.. | .. |
---|
4 | 4 | * Author: |
---|
5 | 5 | * Algea Cao <algea.cao@rock-chips.com> |
---|
6 | 6 | */ |
---|
| 7 | +#include <linux/bitfield.h> |
---|
7 | 8 | #include <linux/clk.h> |
---|
8 | 9 | #include <linux/delay.h> |
---|
9 | 10 | #include <linux/dma-mapping.h> |
---|
.. | .. |
---|
25 | 26 | #include <drm/drm_dsc.h> |
---|
26 | 27 | #include <drm/drm_edid.h> |
---|
27 | 28 | #include <drm/drm_encoder_slave.h> |
---|
| 29 | +#include <drm/drm_hdcp.h> |
---|
28 | 30 | #include <drm/drm_of.h> |
---|
29 | 31 | #include <drm/drm_panel.h> |
---|
30 | 32 | #include <drm/drm_print.h> |
---|
.. | .. |
---|
38 | 40 | #include "dw-hdmi-qp-audio.h" |
---|
39 | 41 | #include "dw-hdmi-qp.h" |
---|
40 | 42 | #include "dw-hdmi-qp-cec.h" |
---|
| 43 | +#include "dw-hdmi-qp-hdcp.h" |
---|
41 | 44 | |
---|
42 | 45 | #include <media/cec-notifier.h> |
---|
43 | 46 | |
---|
.. | .. |
---|
51 | 54 | |
---|
52 | 55 | #define HDMI14_MAX_TMDSCLK 340000000 |
---|
53 | 56 | #define HDMI20_MAX_TMDSCLK_KHZ 600000 |
---|
| 57 | + |
---|
| 58 | +#define HDMI_VH0 0x20 |
---|
| 59 | +#define HDMI_HDCP_ADDR 0x3a |
---|
| 60 | +#define HDMI_BCAPS 0x40 |
---|
| 61 | +#define HDMI_HDCP14_SUPPORT BIT(7) |
---|
| 62 | +#define HDMI_HDCP2_VERSION 0x50 |
---|
| 63 | +#define HDMI_HDCP2_SUPPORT BIT(2) |
---|
| 64 | + |
---|
| 65 | +#define SINK_CAP_HDCP14 BIT(0) |
---|
| 66 | +#define SINK_CAP_HDCP2 BIT(1) |
---|
| 67 | + |
---|
| 68 | +#define HDMI_HDCP2_AUTH BIT(1) |
---|
| 69 | +#define HDMI_HDCP14_AUTH BIT(0) |
---|
54 | 70 | |
---|
55 | 71 | static const unsigned int dw_hdmi_cable[] = { |
---|
56 | 72 | EXTCON_DISP_HDMI, |
---|
.. | .. |
---|
221 | 237 | struct dw_hdmi_qp { |
---|
222 | 238 | struct drm_connector connector; |
---|
223 | 239 | struct drm_bridge bridge; |
---|
| 240 | + struct drm_bridge *next_bridge; |
---|
224 | 241 | struct drm_panel *panel; |
---|
225 | 242 | struct platform_device *hdcp_dev; |
---|
226 | 243 | struct platform_device *audio; |
---|
.. | .. |
---|
230 | 247 | |
---|
231 | 248 | struct hdmi_qp_data_info hdmi_data; |
---|
232 | 249 | const struct dw_hdmi_plat_data *plat_data; |
---|
233 | | - |
---|
| 250 | + struct dw_qp_hdcp *hdcp; |
---|
234 | 251 | int vic; |
---|
235 | 252 | int main_irq; |
---|
236 | 253 | int avp_irq; |
---|
.. | .. |
---|
249 | 266 | |
---|
250 | 267 | struct i2c_adapter *ddc; |
---|
251 | 268 | void __iomem *regs; |
---|
| 269 | + void __iomem *hdcp14_mem; |
---|
252 | 270 | bool sink_is_hdmi; |
---|
253 | 271 | bool sink_has_audio; |
---|
254 | 272 | bool dclk_en; |
---|
.. | .. |
---|
256 | 274 | bool cec_enable; |
---|
257 | 275 | bool allm_enable; |
---|
258 | 276 | bool support_hdmi; |
---|
| 277 | + bool skip_connector; |
---|
259 | 278 | int force_output; |
---|
260 | 279 | int vp_id; |
---|
261 | 280 | int old_vp_id; |
---|
.. | .. |
---|
268 | 287 | bool rxsense; /* rxsense state */ |
---|
269 | 288 | u8 phy_mask; /* desired phy int mask settings */ |
---|
270 | 289 | u8 mc_clkdis; /* clock disable register */ |
---|
| 290 | + u8 hdcp_caps; |
---|
| 291 | + u8 hdcp_status; |
---|
271 | 292 | |
---|
272 | 293 | bool update; |
---|
273 | 294 | bool hdr2sdr; |
---|
.. | .. |
---|
944 | 965 | { |
---|
945 | 966 | /* Software reset */ |
---|
946 | 967 | hdmi_writel(hdmi, 0x01, I2CM_CONTROL0); |
---|
947 | | - |
---|
948 | | - hdmi_writel(hdmi, 0x085c085c, I2CM_FM_SCL_CONFIG0); |
---|
949 | 968 | |
---|
950 | 969 | hdmi_modb(hdmi, 0, I2CM_FM_EN, I2CM_INTERFACE_CONTROL0); |
---|
951 | 970 | |
---|
.. | .. |
---|
1877 | 1896 | return tmdsclock; |
---|
1878 | 1897 | } |
---|
1879 | 1898 | |
---|
| 1899 | +static void dw_hdmi_qp_hdcp_enable(struct dw_hdmi_qp *hdmi, |
---|
| 1900 | + struct drm_connector *connector) |
---|
| 1901 | +{ |
---|
| 1902 | + int ret, val; |
---|
| 1903 | + const struct drm_connector_state *conn_state = connector->state; |
---|
| 1904 | + void *data = hdmi->plat_data->phy_data; |
---|
| 1905 | + |
---|
| 1906 | + if (conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_DESIRED) |
---|
| 1907 | + return; |
---|
| 1908 | + |
---|
| 1909 | + /* sink support hdcp2.x */ |
---|
| 1910 | + if (hdmi->hdcp_caps & SINK_CAP_HDCP2) { |
---|
| 1911 | + hdmi_writel(hdmi, HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ, AVP_3_INT_CLEAR); |
---|
| 1912 | + hdmi_modb(hdmi, HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ, |
---|
| 1913 | + HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ, AVP_3_INT_MASK_N); |
---|
| 1914 | + |
---|
| 1915 | + hdmi_writel(hdmi, 0x35, HDCP2LOGIC_ESM_GPIO_IN); |
---|
| 1916 | + hdmi_modb(hdmi, 0, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); |
---|
| 1917 | + if (hdmi->plat_data->set_hdcp2_enable) |
---|
| 1918 | + hdmi->plat_data->set_hdcp2_enable(data, true); |
---|
| 1919 | + |
---|
| 1920 | + /* wait hdcp2.X auth success */ |
---|
| 1921 | + ret = regmap_read_poll_timeout(hdmi->regm, HDCP2LOGIC_ESM_GPIO_OUT, val, |
---|
| 1922 | + FIELD_GET(HDCP2_AUTHENTICATION_SUCCESS, val), |
---|
| 1923 | + 10000, 2000000); |
---|
| 1924 | + if (ret) { |
---|
| 1925 | + hdmi->hdcp_status &= ~HDMI_HDCP2_AUTH; |
---|
| 1926 | + dev_info(hdmi->dev, "hdcp2 auth failed,start hdcp1.4\n"); |
---|
| 1927 | + |
---|
| 1928 | + hdmi_writel(hdmi, 0, HDCP2LOGIC_ESM_GPIO_IN); |
---|
| 1929 | + hdmi_modb(hdmi, HDCP2_BYPASS, HDCP2_BYPASS, HDCP2LOGIC_CONFIG0); |
---|
| 1930 | + |
---|
| 1931 | + if (hdmi->plat_data->set_hdcp2_enable) |
---|
| 1932 | + hdmi->plat_data->set_hdcp2_enable(data, false); |
---|
| 1933 | + |
---|
| 1934 | + if (hdmi->hdcp && hdmi->hdcp->hdcp_start) |
---|
| 1935 | + hdmi->hdcp->hdcp_start(hdmi->hdcp); |
---|
| 1936 | + goto exit; |
---|
| 1937 | + } |
---|
| 1938 | + |
---|
| 1939 | + hdmi->hdcp_status |= HDMI_HDCP2_AUTH; |
---|
| 1940 | + drm_hdcp_update_content_protection(connector, DRM_MODE_CONTENT_PROTECTION_ENABLED); |
---|
| 1941 | + dev_info(hdmi->dev, "HDCP2 authentication succeed\n"); |
---|
| 1942 | + } else { |
---|
| 1943 | + if (hdmi->hdcp && hdmi->hdcp->hdcp_start) |
---|
| 1944 | + hdmi->hdcp->hdcp_start(hdmi->hdcp); |
---|
| 1945 | + } |
---|
| 1946 | +exit: |
---|
| 1947 | + if (hdmi->plat_data->set_hdcp_status) |
---|
| 1948 | + hdmi->plat_data->set_hdcp_status(data, hdmi->hdcp_status); |
---|
| 1949 | +} |
---|
| 1950 | + |
---|
1880 | 1951 | static int dw_hdmi_qp_setup(struct dw_hdmi_qp *hdmi, |
---|
1881 | 1952 | const struct drm_connector *connector, |
---|
1882 | 1953 | struct drm_display_mode *mode) |
---|
.. | .. |
---|
2038 | 2109 | dev_info(hdmi->dev, "%s DVI mode\n", __func__); |
---|
2039 | 2110 | } |
---|
2040 | 2111 | |
---|
| 2112 | + dw_hdmi_qp_hdcp_enable(hdmi, hdmi->curr_conn); |
---|
2041 | 2113 | hdmi->frl_switch = false; |
---|
2042 | 2114 | return 0; |
---|
2043 | 2115 | } |
---|
.. | .. |
---|
2056 | 2128 | |
---|
2057 | 2129 | if (hdmi->panel) |
---|
2058 | 2130 | return connector_status_connected; |
---|
| 2131 | + |
---|
| 2132 | + if (hdmi->next_bridge && hdmi->next_bridge->ops & DRM_BRIDGE_OP_DETECT) |
---|
| 2133 | + return drm_bridge_detect(hdmi->next_bridge); |
---|
2059 | 2134 | |
---|
2060 | 2135 | if (hdmi->plat_data->left) |
---|
2061 | 2136 | secondary = hdmi->plat_data->left; |
---|
.. | .. |
---|
2124 | 2199 | return false; |
---|
2125 | 2200 | } |
---|
2126 | 2201 | |
---|
| 2202 | +static ssize_t hdcp_ddc_read(struct i2c_adapter *adapter, u8 address, |
---|
| 2203 | + u8 offset, void *buffer) |
---|
| 2204 | +{ |
---|
| 2205 | + int ret; |
---|
| 2206 | + struct i2c_msg msgs[2] = { |
---|
| 2207 | + { |
---|
| 2208 | + .addr = address, |
---|
| 2209 | + .flags = 0, |
---|
| 2210 | + .len = 1, |
---|
| 2211 | + .buf = &offset, |
---|
| 2212 | + }, { |
---|
| 2213 | + .addr = address, |
---|
| 2214 | + .flags = I2C_M_RD, |
---|
| 2215 | + .len = 1, |
---|
| 2216 | + .buf = buffer, |
---|
| 2217 | + } |
---|
| 2218 | + }; |
---|
| 2219 | + |
---|
| 2220 | + ret = i2c_transfer(adapter, msgs, ARRAY_SIZE(msgs)); |
---|
| 2221 | + if (ret < 0) |
---|
| 2222 | + return ret; |
---|
| 2223 | + if (ret != ARRAY_SIZE(msgs)) |
---|
| 2224 | + return -EPROTO; |
---|
| 2225 | + |
---|
| 2226 | + return 0; |
---|
| 2227 | +} |
---|
| 2228 | + |
---|
| 2229 | +static u8 dw_hdmi_qp_hdcp_capable(struct dw_hdmi_qp *hdmi) |
---|
| 2230 | +{ |
---|
| 2231 | + u8 version = 0; |
---|
| 2232 | + u8 bcaps; |
---|
| 2233 | + int ret; |
---|
| 2234 | + |
---|
| 2235 | + ret = hdcp_ddc_read(hdmi->ddc, HDMI_HDCP_ADDR, HDMI_BCAPS, &bcaps); |
---|
| 2236 | + if (ret < 0) { |
---|
| 2237 | + dev_err(hdmi->dev, "get hdcp1.4 capable failed:%d\n", ret); |
---|
| 2238 | + return 0; |
---|
| 2239 | + } |
---|
| 2240 | + if (bcaps & HDMI_HDCP14_SUPPORT) |
---|
| 2241 | + version |= SINK_CAP_HDCP14; |
---|
| 2242 | + |
---|
| 2243 | + ret = hdcp_ddc_read(hdmi->ddc, HDMI_HDCP_ADDR, HDMI_HDCP2_VERSION, &bcaps); |
---|
| 2244 | + if (ret < 0) { |
---|
| 2245 | + dev_err(hdmi->dev, "get hdcp2.x capable failed:%d\n", ret); |
---|
| 2246 | + return 0; |
---|
| 2247 | + } |
---|
| 2248 | + if (bcaps & HDMI_HDCP2_SUPPORT) |
---|
| 2249 | + version |= SINK_CAP_HDCP2; |
---|
| 2250 | + |
---|
| 2251 | + return version; |
---|
| 2252 | +} |
---|
| 2253 | + |
---|
2127 | 2254 | static int dw_hdmi_connector_get_modes(struct drm_connector *connector) |
---|
2128 | 2255 | { |
---|
2129 | 2256 | struct dw_hdmi_qp *hdmi = |
---|
.. | .. |
---|
2134 | 2261 | struct drm_display_mode *mode; |
---|
2135 | 2262 | struct drm_display_info *info = &connector->display_info; |
---|
2136 | 2263 | void *data = hdmi->plat_data->phy_data; |
---|
| 2264 | + struct drm_property_blob *edid_blob_ptr = connector->edid_blob_ptr; |
---|
2137 | 2265 | int i, ret = 0; |
---|
| 2266 | + |
---|
| 2267 | + if (hdmi->plat_data->right && hdmi->plat_data->right->next_bridge) { |
---|
| 2268 | + struct drm_bridge *bridge = hdmi->plat_data->right->next_bridge; |
---|
| 2269 | + |
---|
| 2270 | + if (bridge->ops & DRM_BRIDGE_OP_MODES) { |
---|
| 2271 | + if (!drm_bridge_get_modes(bridge, connector)) |
---|
| 2272 | + return 0; |
---|
| 2273 | + } |
---|
| 2274 | + } |
---|
2138 | 2275 | |
---|
2139 | 2276 | if (hdmi->panel) |
---|
2140 | 2277 | return drm_panel_get_modes(hdmi->panel, connector); |
---|
| 2278 | + |
---|
| 2279 | + if (hdmi->next_bridge && hdmi->next_bridge->ops & DRM_BRIDGE_OP_MODES) |
---|
| 2280 | + return drm_bridge_get_modes(hdmi->next_bridge, connector); |
---|
2141 | 2281 | |
---|
2142 | 2282 | if (!hdmi->ddc) |
---|
2143 | 2283 | return 0; |
---|
2144 | 2284 | |
---|
2145 | 2285 | memset(metedata, 0, sizeof(*metedata)); |
---|
2146 | | - edid = drm_get_edid(connector, hdmi->ddc); |
---|
| 2286 | + |
---|
| 2287 | + if (edid_blob_ptr && edid_blob_ptr->length) { |
---|
| 2288 | + edid = kmalloc(edid_blob_ptr->length, GFP_KERNEL); |
---|
| 2289 | + if (!edid) |
---|
| 2290 | + return -ENOMEM; |
---|
| 2291 | + memcpy(edid, edid_blob_ptr->data, edid_blob_ptr->length); |
---|
| 2292 | + } else { |
---|
| 2293 | + edid = drm_get_edid(connector, hdmi->ddc); |
---|
| 2294 | + hdmi->hdcp_caps = dw_hdmi_qp_hdcp_capable(hdmi); |
---|
| 2295 | + } |
---|
| 2296 | + |
---|
2147 | 2297 | if (edid) { |
---|
2148 | 2298 | dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", |
---|
2149 | 2299 | edid->width_cm, edid->height_cm); |
---|
.. | .. |
---|
2161 | 2311 | if (hdmi->plat_data->get_yuv422_format) |
---|
2162 | 2312 | hdmi->plat_data->get_yuv422_format(connector, edid); |
---|
2163 | 2313 | dw_hdmi_update_hdr_property(connector); |
---|
| 2314 | + hdmi->hdcp_caps = dw_hdmi_qp_hdcp_capable(hdmi); |
---|
2164 | 2315 | if (ret > 0 && hdmi->plat_data->split_mode) { |
---|
2165 | 2316 | struct dw_hdmi_qp *secondary = NULL; |
---|
2166 | 2317 | void *secondary_data; |
---|
.. | .. |
---|
2170 | 2321 | else if (hdmi->plat_data->right) |
---|
2171 | 2322 | secondary = hdmi->plat_data->right; |
---|
2172 | 2323 | |
---|
2173 | | - if (!secondary) |
---|
| 2324 | + if (!secondary) { |
---|
| 2325 | + kfree(edid); |
---|
2174 | 2326 | return -ENOMEM; |
---|
| 2327 | + } |
---|
2175 | 2328 | secondary_data = secondary->plat_data->phy_data; |
---|
2176 | 2329 | |
---|
2177 | 2330 | list_for_each_entry(mode, &connector->probed_modes, head) |
---|
.. | .. |
---|
2224 | 2377 | |
---|
2225 | 2378 | dev_info(hdmi->dev, "failed to get edid\n"); |
---|
2226 | 2379 | } |
---|
2227 | | - dw_hdmi_qp_check_output_type_changed(hdmi); |
---|
2228 | 2380 | |
---|
2229 | 2381 | return ret; |
---|
2230 | 2382 | } |
---|
.. | .. |
---|
2444 | 2596 | return false; |
---|
2445 | 2597 | } |
---|
2446 | 2598 | |
---|
| 2599 | +static bool check_dw_hdcp_state_changed(struct drm_connector *conn, |
---|
| 2600 | + struct drm_atomic_state *state) |
---|
| 2601 | +{ |
---|
| 2602 | + struct drm_connector_state *old_state, *new_state; |
---|
| 2603 | + u64 old_cp, new_cp; |
---|
| 2604 | + |
---|
| 2605 | + old_state = drm_atomic_get_old_connector_state(state, conn); |
---|
| 2606 | + new_state = drm_atomic_get_new_connector_state(state, conn); |
---|
| 2607 | + old_cp = old_state->content_protection; |
---|
| 2608 | + new_cp = new_state->content_protection; |
---|
| 2609 | + |
---|
| 2610 | + if (old_state->hdcp_content_type != new_state->hdcp_content_type && |
---|
| 2611 | + new_cp != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { |
---|
| 2612 | + new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; |
---|
| 2613 | + return true; |
---|
| 2614 | + } |
---|
| 2615 | + |
---|
| 2616 | + if (!new_state->crtc) { |
---|
| 2617 | + if (old_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) |
---|
| 2618 | + new_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED; |
---|
| 2619 | + return false; |
---|
| 2620 | + } |
---|
| 2621 | + |
---|
| 2622 | + if (old_cp == new_cp || |
---|
| 2623 | + (old_cp == DRM_MODE_CONTENT_PROTECTION_DESIRED && |
---|
| 2624 | + new_cp == DRM_MODE_CONTENT_PROTECTION_ENABLED)) |
---|
| 2625 | + return false; |
---|
| 2626 | + |
---|
| 2627 | + return true; |
---|
| 2628 | +} |
---|
| 2629 | + |
---|
2447 | 2630 | static int dw_hdmi_connector_atomic_check(struct drm_connector *connector, |
---|
2448 | 2631 | struct drm_atomic_state *state) |
---|
2449 | 2632 | { |
---|
.. | .. |
---|
2546 | 2729 | } |
---|
2547 | 2730 | |
---|
2548 | 2731 | if (check_hdr_color_change(old_state, new_state, hdmi) || hdmi->logo_plug_out || |
---|
2549 | | - dw_hdmi_color_changed(connector, state)) { |
---|
| 2732 | + dw_hdmi_color_changed(connector, state) || |
---|
| 2733 | + dw_hdmi_qp_check_output_type_changed(hdmi)) { |
---|
2550 | 2734 | u32 mtmdsclk; |
---|
2551 | 2735 | |
---|
2552 | 2736 | crtc_state = drm_atomic_get_crtc_state(state, crtc); |
---|
.. | .. |
---|
2580 | 2764 | hdmi_modb(hdmi, PKTSCHED_GCP_TX_EN, PKTSCHED_GCP_TX_EN, PKTSCHED_PKT_EN); |
---|
2581 | 2765 | mdelay(50); |
---|
2582 | 2766 | } else if (!hdmi->disabled) { |
---|
2583 | | - if (mode.clock > 600000) |
---|
| 2767 | + if (hdmi->previous_mode.clock > 600000 && mode.clock > 600000) |
---|
2584 | 2768 | hdmi->frl_switch = true; |
---|
2585 | 2769 | hdmi->update = false; |
---|
2586 | 2770 | crtc_state->mode_changed = true; |
---|
2587 | 2771 | hdmi->logo_plug_out = false; |
---|
2588 | 2772 | } |
---|
2589 | 2773 | } |
---|
| 2774 | + |
---|
| 2775 | + if (check_dw_hdcp_state_changed(connector, state)) |
---|
| 2776 | + crtc_state->mode_changed = true; |
---|
2590 | 2777 | |
---|
2591 | 2778 | return 0; |
---|
2592 | 2779 | } |
---|
.. | .. |
---|
2608 | 2795 | void dw_hdmi_qp_set_output_type(struct dw_hdmi_qp *hdmi, u64 val) |
---|
2609 | 2796 | { |
---|
2610 | 2797 | hdmi->force_output = val; |
---|
2611 | | - |
---|
2612 | | - if (!dw_hdmi_qp_check_output_type_changed(hdmi)) |
---|
2613 | | - return; |
---|
2614 | | - |
---|
2615 | | - if (hdmi->disabled) |
---|
2616 | | - return; |
---|
2617 | | - |
---|
2618 | | - if (!hdmi->sink_is_hdmi) |
---|
2619 | | - hdmi_modb(hdmi, OPMODE_DVI, OPMODE_DVI, LINK_CONFIG0); |
---|
2620 | | - else |
---|
2621 | | - hdmi_modb(hdmi, 0, OPMODE_DVI, LINK_CONFIG0); |
---|
2622 | 2798 | } |
---|
2623 | 2799 | EXPORT_SYMBOL_GPL(dw_hdmi_qp_set_output_type); |
---|
2624 | 2800 | |
---|
.. | .. |
---|
2682 | 2858 | struct drm_connector *connector = &hdmi->connector; |
---|
2683 | 2859 | struct cec_connector_info conn_info; |
---|
2684 | 2860 | struct cec_notifier *notifier; |
---|
| 2861 | + bool skip_connector = false; |
---|
2685 | 2862 | |
---|
2686 | | - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) |
---|
| 2863 | + if (hdmi->next_bridge) { |
---|
| 2864 | + struct drm_bridge *next_bridge = hdmi->next_bridge; |
---|
| 2865 | + int ret; |
---|
| 2866 | + |
---|
| 2867 | + ret = drm_bridge_attach(bridge->encoder, next_bridge, bridge, |
---|
| 2868 | + next_bridge->ops & DRM_BRIDGE_OP_MODES ? |
---|
| 2869 | + DRM_BRIDGE_ATTACH_NO_CONNECTOR : 0); |
---|
| 2870 | + if (ret) { |
---|
| 2871 | + DRM_ERROR("failed to attach next bridge: %d\n", ret); |
---|
| 2872 | + return ret; |
---|
| 2873 | + } |
---|
| 2874 | + |
---|
| 2875 | + skip_connector = !(next_bridge->ops & DRM_BRIDGE_OP_MODES); |
---|
| 2876 | + } |
---|
| 2877 | + |
---|
| 2878 | + hdmi->skip_connector = skip_connector; |
---|
| 2879 | + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR || skip_connector) |
---|
2687 | 2880 | return 0; |
---|
2688 | 2881 | |
---|
2689 | 2882 | connector->interlace_allowed = 1; |
---|
2690 | 2883 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
---|
2691 | | - |
---|
| 2884 | + if (hdmi->next_bridge && hdmi->next_bridge->ops & DRM_BRIDGE_OP_DETECT) |
---|
| 2885 | + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; |
---|
2692 | 2886 | drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); |
---|
2693 | 2887 | |
---|
2694 | 2888 | drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs, |
---|
.. | .. |
---|
2728 | 2922 | const struct drm_display_info *info, |
---|
2729 | 2923 | const struct drm_display_mode *mode) |
---|
2730 | 2924 | { |
---|
| 2925 | + struct dw_hdmi_qp *hdmi = bridge->driver_private; |
---|
| 2926 | + const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; |
---|
| 2927 | + |
---|
2731 | 2928 | if (mode->clock <= 25000) |
---|
2732 | 2929 | return MODE_CLOCK_RANGE; |
---|
| 2930 | + |
---|
| 2931 | + if (!hdmi->sink_is_hdmi && mode->clock > 340000) |
---|
| 2932 | + return MODE_BAD; |
---|
| 2933 | + |
---|
| 2934 | + if (pdata->mode_valid) |
---|
| 2935 | + return pdata->mode_valid(NULL, pdata->priv_data, info, |
---|
| 2936 | + mode); |
---|
2733 | 2937 | |
---|
2734 | 2938 | return MODE_OK; |
---|
2735 | 2939 | } |
---|
.. | .. |
---|
2757 | 2961 | { |
---|
2758 | 2962 | struct dw_hdmi_qp *hdmi = bridge->driver_private; |
---|
2759 | 2963 | void *data = hdmi->plat_data->phy_data; |
---|
| 2964 | + const struct drm_connector_state *conn_state = hdmi->curr_conn->state; |
---|
2760 | 2965 | |
---|
2761 | 2966 | if (hdmi->panel) |
---|
2762 | 2967 | drm_panel_disable(hdmi->panel); |
---|
.. | .. |
---|
2764 | 2969 | /* set avmute */ |
---|
2765 | 2970 | hdmi_writel(hdmi, 1, PKTSCHED_PKT_CONTROL0); |
---|
2766 | 2971 | mdelay(50); |
---|
| 2972 | + |
---|
| 2973 | + hdmi_modb(hdmi, 0, HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ, |
---|
| 2974 | + AVP_3_INT_MASK_N); |
---|
| 2975 | + if (hdmi->hdcp && hdmi->hdcp->hdcp_stop) |
---|
| 2976 | + hdmi->hdcp->hdcp_stop(hdmi->hdcp); |
---|
| 2977 | + |
---|
| 2978 | + hdmi_writel(hdmi, 0, HDCP2LOGIC_ESM_GPIO_IN); |
---|
| 2979 | + if (conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) |
---|
| 2980 | + drm_hdcp_update_content_protection(hdmi->curr_conn, |
---|
| 2981 | + DRM_MODE_CONTENT_PROTECTION_DESIRED); |
---|
| 2982 | + |
---|
| 2983 | + if (hdmi->plat_data->set_hdcp_status) |
---|
| 2984 | + hdmi->plat_data->set_hdcp_status(data, hdmi->hdcp_status); |
---|
2767 | 2985 | |
---|
2768 | 2986 | extcon_set_state_sync(hdmi->extcon, EXTCON_DISP_HDMI, false); |
---|
2769 | 2987 | handle_plugged_change(hdmi, false); |
---|
.. | .. |
---|
2781 | 2999 | hdmi_writel(hdmi, 0, FLT_CONFIG0); |
---|
2782 | 3000 | hdmi_writel(hdmi, 0, SCRAMB_CONFIG0); |
---|
2783 | 3001 | /* set sink frl mode disable */ |
---|
2784 | | - if (hdmi->curr_conn && dw_hdmi_support_scdc(hdmi, &hdmi->curr_conn->display_info)) |
---|
| 3002 | + if (dw_hdmi_support_scdc(hdmi, &hdmi->curr_conn->display_info)) |
---|
2785 | 3003 | drm_scdc_writeb(hdmi->ddc, 0x31, 0); |
---|
2786 | 3004 | |
---|
2787 | 3005 | hdmi->phy.ops->disable(hdmi, hdmi->phy.data); |
---|
.. | .. |
---|
2913 | 3131 | static irqreturn_t dw_hdmi_qp_avp_hardirq(int irq, void *dev_id) |
---|
2914 | 3132 | { |
---|
2915 | 3133 | struct dw_hdmi_qp *hdmi = dev_id; |
---|
2916 | | - u32 stat; |
---|
| 3134 | + u32 stat1, stat3; |
---|
2917 | 3135 | |
---|
2918 | | - stat = hdmi_readl(hdmi, AVP_1_INT_STATUS); |
---|
2919 | | - if (stat) { |
---|
2920 | | - dev_dbg(hdmi->dev, "HDCP irq %#x\n", stat); |
---|
2921 | | - stat &= ~stat; |
---|
2922 | | - hdmi_writel(hdmi, stat, AVP_1_INT_MASK_N); |
---|
2923 | | - return IRQ_WAKE_THREAD; |
---|
| 3136 | + stat1 = hdmi_readl(hdmi, AVP_1_INT_STATUS); |
---|
| 3137 | + stat3 = hdmi_readl(hdmi, AVP_3_INT_STATUS); |
---|
| 3138 | + |
---|
| 3139 | + if (!stat1 && !stat3) |
---|
| 3140 | + return IRQ_NONE; |
---|
| 3141 | + |
---|
| 3142 | + return IRQ_WAKE_THREAD; |
---|
| 3143 | +} |
---|
| 3144 | + |
---|
| 3145 | +static irqreturn_t dw_hdmi_qp_avp_irq(int irq, void *dev_id) |
---|
| 3146 | +{ |
---|
| 3147 | + struct dw_hdmi_qp *hdmi = dev_id; |
---|
| 3148 | + struct drm_connector_state *conn_state; |
---|
| 3149 | + void *data = hdmi->plat_data->phy_data; |
---|
| 3150 | + u32 stat1, stat3, val; |
---|
| 3151 | + |
---|
| 3152 | + stat1 = hdmi_readl(hdmi, AVP_1_INT_STATUS); |
---|
| 3153 | + stat3 = hdmi_readl(hdmi, AVP_3_INT_STATUS); |
---|
| 3154 | + |
---|
| 3155 | + hdmi_writel(hdmi, stat1, AVP_1_INT_CLEAR); |
---|
| 3156 | + hdmi_writel(hdmi, stat3, AVP_3_INT_CLEAR); |
---|
| 3157 | + |
---|
| 3158 | + if (!hdmi->curr_conn || !hdmi->curr_conn->state) |
---|
| 3159 | + return IRQ_HANDLED; |
---|
| 3160 | + |
---|
| 3161 | + conn_state = hdmi->curr_conn->state; |
---|
| 3162 | + val = conn_state->content_protection; |
---|
| 3163 | + |
---|
| 3164 | + if (hdmi->hdcp && hdmi->hdcp->hdcp_isr) { |
---|
| 3165 | + u32 hdcp_status = hdmi_readl(hdmi, HDCP14_STATUS0); |
---|
| 3166 | + |
---|
| 3167 | + if (stat1 & HDCP14_AUTH_CHG_MASK_N) { |
---|
| 3168 | + /* hdcp14 auth success */ |
---|
| 3169 | + if (hdcp_status & BIT(2)) { |
---|
| 3170 | + hdmi->hdcp_status |= HDMI_HDCP14_AUTH; |
---|
| 3171 | + if (conn_state->content_protection != |
---|
| 3172 | + DRM_MODE_CONTENT_PROTECTION_UNDESIRED) |
---|
| 3173 | + val = DRM_MODE_CONTENT_PROTECTION_ENABLED; |
---|
| 3174 | + } else if (!(hdcp_status & BIT(2))) { |
---|
| 3175 | + hdmi->hdcp_status &= ~HDMI_HDCP14_AUTH; |
---|
| 3176 | + if (conn_state->content_protection != |
---|
| 3177 | + DRM_MODE_CONTENT_PROTECTION_UNDESIRED) |
---|
| 3178 | + val = DRM_MODE_CONTENT_PROTECTION_DESIRED; |
---|
| 3179 | + } |
---|
| 3180 | + conn_state->content_protection = val; |
---|
| 3181 | + } |
---|
| 3182 | + hdmi->hdcp->hdcp_isr(hdmi->hdcp, stat1, hdcp_status); |
---|
2924 | 3183 | } |
---|
2925 | 3184 | |
---|
2926 | | - return IRQ_NONE; |
---|
| 3185 | + if (stat3 & HDCP2_ESM_P0_GPIO_OUT_2_CHG_IRQ) { |
---|
| 3186 | + stat3 = hdmi_readl(hdmi, HDCP2LOGIC_ESM_GPIO_OUT); |
---|
| 3187 | + if (stat3 & HDCP2_AUTHENTICATION_SUCCESS) { |
---|
| 3188 | + hdmi->hdcp_status |= HDMI_HDCP2_AUTH; |
---|
| 3189 | + if (conn_state->content_protection != |
---|
| 3190 | + DRM_MODE_CONTENT_PROTECTION_UNDESIRED) |
---|
| 3191 | + val = DRM_MODE_CONTENT_PROTECTION_ENABLED; |
---|
| 3192 | + } else if (!(stat3 & HDCP2_AUTHENTICATION_SUCCESS)) { |
---|
| 3193 | + hdmi->hdcp_status &= ~HDMI_HDCP2_AUTH; |
---|
| 3194 | + if (conn_state->content_protection != |
---|
| 3195 | + DRM_MODE_CONTENT_PROTECTION_UNDESIRED) |
---|
| 3196 | + val = DRM_MODE_CONTENT_PROTECTION_DESIRED; |
---|
| 3197 | + } |
---|
| 3198 | + conn_state->content_protection = val; |
---|
| 3199 | + } |
---|
| 3200 | + |
---|
| 3201 | + if (hdmi->plat_data->set_hdcp_status) |
---|
| 3202 | + hdmi->plat_data->set_hdcp_status(data, hdmi->hdcp_status); |
---|
| 3203 | + |
---|
| 3204 | + return IRQ_HANDLED; |
---|
2927 | 3205 | } |
---|
2928 | 3206 | |
---|
2929 | 3207 | static irqreturn_t dw_hdmi_qp_earc_hardirq(int irq, void *dev_id) |
---|
.. | .. |
---|
2940 | 3218 | } |
---|
2941 | 3219 | |
---|
2942 | 3220 | return IRQ_NONE; |
---|
2943 | | -} |
---|
2944 | | - |
---|
2945 | | -static irqreturn_t dw_hdmi_qp_avp_irq(int irq, void *dev_id) |
---|
2946 | | -{ |
---|
2947 | | - struct dw_hdmi_qp *hdmi = dev_id; |
---|
2948 | | - u32 stat; |
---|
2949 | | - |
---|
2950 | | - stat = hdmi_readl(hdmi, AVP_1_INT_STATUS); |
---|
2951 | | - |
---|
2952 | | - if (!stat) |
---|
2953 | | - return IRQ_NONE; |
---|
2954 | | - |
---|
2955 | | - hdmi_writel(hdmi, stat, AVP_1_INT_CLEAR); |
---|
2956 | | - |
---|
2957 | | - return IRQ_HANDLED; |
---|
2958 | 3221 | } |
---|
2959 | 3222 | |
---|
2960 | 3223 | static irqreturn_t dw_hdmi_qp_earc_irq(int irq, void *dev_id) |
---|
.. | .. |
---|
3124 | 3387 | struct dw_hdmi_qp *hdmi = s->private; |
---|
3125 | 3388 | u32 i = 0, j = 0, val = 0; |
---|
3126 | 3389 | |
---|
| 3390 | + if (hdmi->disabled) { |
---|
| 3391 | + dev_err(hdmi->dev, "hdmi is disabled\n"); |
---|
| 3392 | + return -EACCES; |
---|
| 3393 | + } |
---|
| 3394 | + |
---|
3127 | 3395 | seq_puts(s, "\n---------------------------------------------------"); |
---|
3128 | 3396 | |
---|
3129 | 3397 | for (i = 0; i < ARRAY_SIZE(hdmi_reg_table); i++) { |
---|
.. | .. |
---|
3154 | 3422 | ((struct seq_file *)file->private_data)->private; |
---|
3155 | 3423 | u32 reg, val; |
---|
3156 | 3424 | char kbuf[25]; |
---|
| 3425 | + |
---|
| 3426 | + if (hdmi->disabled) { |
---|
| 3427 | + dev_err(hdmi->dev, "hdmi is disabled\n"); |
---|
| 3428 | + return -EACCES; |
---|
| 3429 | + } |
---|
3157 | 3430 | |
---|
3158 | 3431 | if (count > 24) { |
---|
3159 | 3432 | dev_err(hdmi->dev, "out of buf range\n"); |
---|
.. | .. |
---|
3339 | 3612 | hdmi, &dw_hdmi_ctrl_fops); |
---|
3340 | 3613 | } |
---|
3341 | 3614 | |
---|
| 3615 | +static void dw_hdmi_qp_hdcp14_get_mem(struct dw_hdmi_qp *hdmi, u8 *data, u32 len) |
---|
| 3616 | +{ |
---|
| 3617 | + u32 ksv_len, i, val; |
---|
| 3618 | + void *hdmi_data = hdmi->plat_data->phy_data; |
---|
| 3619 | + |
---|
| 3620 | + if (hdmi->plat_data->set_hdcp14_mem) |
---|
| 3621 | + hdmi->plat_data->set_hdcp14_mem(hdmi_data, true); |
---|
| 3622 | + |
---|
| 3623 | + ksv_len = len - BSTATUS_LEN - M0_LEN - SHAMAX; |
---|
| 3624 | + for (i = 0; i < len; i++) { |
---|
| 3625 | + /* read ksv list */ |
---|
| 3626 | + if (i < ksv_len) |
---|
| 3627 | + val = readl(hdmi->hdcp14_mem + HDMI_HDCP14_MEM_KSV0 + i * 4); |
---|
| 3628 | + /* read bstatus */ |
---|
| 3629 | + else if (i < len - SHAMAX - M0_LEN) |
---|
| 3630 | + val = readl(hdmi->hdcp14_mem + HDMI_HDCP14_MEM_BSTATUS0 + |
---|
| 3631 | + (i - ksv_len) * 4); |
---|
| 3632 | + /* read M0 */ |
---|
| 3633 | + else if (i < len - SHAMAX) |
---|
| 3634 | + val = readl(hdmi->hdcp14_mem + HDMI_HDCP14_MEM_M0_1 + |
---|
| 3635 | + (i - ksv_len - BSTATUS_LEN) * 4); |
---|
| 3636 | + else |
---|
| 3637 | + /* VH0 save in external memory is error, we need to read VH0 via ddc */ |
---|
| 3638 | + hdcp_ddc_read(hdmi->ddc, HDMI_HDCP_ADDR, HDMI_VH0 + i - (len - SHAMAX), |
---|
| 3639 | + &val); |
---|
| 3640 | + |
---|
| 3641 | + data[i] = val; |
---|
| 3642 | + } |
---|
| 3643 | + |
---|
| 3644 | + if (hdmi->plat_data->set_hdcp14_mem) |
---|
| 3645 | + hdmi->plat_data->set_hdcp14_mem(hdmi_data, false); |
---|
| 3646 | +} |
---|
| 3647 | + |
---|
| 3648 | +static int dw_hdmi_qp_register_hdcp(struct device *dev, |
---|
| 3649 | + struct dw_hdmi_qp *hdmi) |
---|
| 3650 | +{ |
---|
| 3651 | + struct dw_qp_hdcp hdmi_hdcp = { |
---|
| 3652 | + .hdmi = hdmi, |
---|
| 3653 | + .write = hdmi_writel, |
---|
| 3654 | + .read = hdmi_readl, |
---|
| 3655 | + .regs = hdmi->regs, |
---|
| 3656 | + .get_mem = dw_hdmi_qp_hdcp14_get_mem, |
---|
| 3657 | + }; |
---|
| 3658 | + struct platform_device_info hdcp_device_info = { |
---|
| 3659 | + .parent = dev, |
---|
| 3660 | + .id = PLATFORM_DEVID_AUTO, |
---|
| 3661 | + .res = NULL, |
---|
| 3662 | + .num_res = 0, |
---|
| 3663 | + .name = DW_HDCP_QP_DRIVER_NAME, |
---|
| 3664 | + .data = &hdmi_hdcp, |
---|
| 3665 | + .size_data = sizeof(hdmi_hdcp), |
---|
| 3666 | + .dma_mask = DMA_BIT_MASK(32), |
---|
| 3667 | + }; |
---|
| 3668 | + hdmi->hdcp_dev = platform_device_register_full(&hdcp_device_info); |
---|
| 3669 | + if (IS_ERR(hdmi->hdcp_dev)) { |
---|
| 3670 | + dev_err(dev, "failed to register hdcp!\n"); |
---|
| 3671 | + return -ENOMEM; |
---|
| 3672 | + } |
---|
| 3673 | + |
---|
| 3674 | + hdmi->hdcp = hdmi->hdcp_dev->dev.platform_data; |
---|
| 3675 | + |
---|
| 3676 | + return 0; |
---|
| 3677 | +} |
---|
| 3678 | + |
---|
3342 | 3679 | static struct dw_hdmi_qp * |
---|
3343 | 3680 | __dw_hdmi_probe(struct platform_device *pdev, |
---|
3344 | 3681 | const struct dw_hdmi_plat_data *plat_data) |
---|
.. | .. |
---|
3352 | 3689 | struct dw_hdmi_qp_cec_data cec; |
---|
3353 | 3690 | struct resource *iores = NULL; |
---|
3354 | 3691 | struct drm_panel *panel = NULL; |
---|
| 3692 | + struct drm_bridge *bridge = NULL; |
---|
3355 | 3693 | int irq; |
---|
3356 | 3694 | int ret; |
---|
3357 | 3695 | |
---|
3358 | | - ret = drm_of_find_panel_or_bridge(np, 1, -1, &panel, NULL); |
---|
| 3696 | + ret = drm_of_find_panel_or_bridge(np, 1, -1, &panel, &bridge); |
---|
3359 | 3697 | if (ret < 0 && ret != -ENODEV) |
---|
3360 | 3698 | return ERR_PTR(ret); |
---|
3361 | 3699 | |
---|
.. | .. |
---|
3364 | 3702 | return ERR_PTR(-ENOMEM); |
---|
3365 | 3703 | |
---|
3366 | 3704 | hdmi->panel = panel; |
---|
| 3705 | + hdmi->next_bridge = bridge; |
---|
3367 | 3706 | hdmi->connector.stereo_allowed = 1; |
---|
3368 | 3707 | hdmi->plat_data = plat_data; |
---|
3369 | 3708 | hdmi->dev = dev; |
---|
.. | .. |
---|
3512 | 3851 | hdmi->avp_irq = irq; |
---|
3513 | 3852 | ret = devm_request_threaded_irq(dev, hdmi->avp_irq, |
---|
3514 | 3853 | dw_hdmi_qp_avp_hardirq, |
---|
3515 | | - dw_hdmi_qp_avp_irq, IRQF_SHARED, |
---|
| 3854 | + dw_hdmi_qp_avp_irq, IRQF_ONESHOT, |
---|
3516 | 3855 | dev_name(dev), hdmi); |
---|
3517 | 3856 | if (ret) |
---|
3518 | 3857 | goto err_aud; |
---|
.. | .. |
---|
3564 | 3903 | goto err_cec; |
---|
3565 | 3904 | |
---|
3566 | 3905 | dw_hdmi_register_debugfs(dev, hdmi); |
---|
| 3906 | + |
---|
| 3907 | + if (hdmi_readl(hdmi, CONFIG_REG) & CONFIG_HDCP14) { |
---|
| 3908 | + iores = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
---|
| 3909 | + hdmi->hdcp14_mem = devm_ioremap_resource(dev, iores); |
---|
| 3910 | + |
---|
| 3911 | + if (IS_ERR(hdmi->hdcp14_mem)) { |
---|
| 3912 | + ret = PTR_ERR(hdmi->hdcp14_mem); |
---|
| 3913 | + goto err_cec; |
---|
| 3914 | + } |
---|
| 3915 | + |
---|
| 3916 | + ret = dw_hdmi_qp_register_hdcp(dev, hdmi); |
---|
| 3917 | + if (ret) |
---|
| 3918 | + goto err_cec; |
---|
| 3919 | + } |
---|
3567 | 3920 | |
---|
3568 | 3921 | return hdmi; |
---|
3569 | 3922 | |
---|
.. | .. |
---|
3617 | 3970 | hdmi->bridge.encoder->funcs->destroy(hdmi->bridge.encoder); |
---|
3618 | 3971 | if (!IS_ERR(hdmi->cec)) |
---|
3619 | 3972 | platform_device_unregister(hdmi->cec); |
---|
| 3973 | + if (!IS_ERR(hdmi->hdcp_dev)) |
---|
| 3974 | + platform_device_unregister(hdmi->hdcp_dev); |
---|
3620 | 3975 | if (hdmi->i2c) |
---|
3621 | 3976 | i2c_del_adapter(&hdmi->i2c->adap); |
---|
3622 | 3977 | else |
---|
.. | .. |
---|
3646 | 4001 | } |
---|
3647 | 4002 | |
---|
3648 | 4003 | plat_data->connector = &hdmi->connector; |
---|
| 4004 | + if (hdmi->skip_connector && hdmi->next_bridge) |
---|
| 4005 | + plat_data->bridge = hdmi->next_bridge; |
---|
| 4006 | + else |
---|
| 4007 | + plat_data->bridge = NULL; |
---|
3649 | 4008 | } |
---|
3650 | 4009 | |
---|
3651 | 4010 | if (plat_data->split_mode && !hdmi->plat_data->first_screen) { |
---|
.. | .. |
---|
3703 | 4062 | disable_irq(hdmi->earc_irq); |
---|
3704 | 4063 | |
---|
3705 | 4064 | pinctrl_pm_select_sleep_state(dev); |
---|
| 4065 | + drm_connector_update_edid_property(&hdmi->connector, NULL); |
---|
3706 | 4066 | } |
---|
3707 | 4067 | EXPORT_SYMBOL_GPL(dw_hdmi_qp_suspend); |
---|
3708 | 4068 | |
---|