.. | .. |
---|
17 | 17 | #include <drm/drm_crtc_helper.h> |
---|
18 | 18 | #include <drm/drm_dsc.h> |
---|
19 | 19 | #include <drm/drm_edid.h> |
---|
| 20 | +#include <drm/drm_hdcp.h> |
---|
20 | 21 | #include <drm/bridge/dw_hdmi.h> |
---|
21 | 22 | #include <drm/drm_edid.h> |
---|
22 | 23 | #include <drm/drm_of.h> |
---|
.. | .. |
---|
105 | 106 | #define RK3588_HDMI1_LEVEL_INT BIT(24) |
---|
106 | 107 | #define RK3588_HDMI1_INTR_CHANGE_CNT (0x7 << 21) |
---|
107 | 108 | |
---|
| 109 | +#define RK3588_GRF_VO1_CON1 0x0004 |
---|
| 110 | +#define HDCP1_P1_GPIO_IN BIT(9) |
---|
108 | 111 | #define RK3588_GRF_VO1_CON3 0x000c |
---|
109 | 112 | #define RK3588_COLOR_FORMAT_MASK 0xf |
---|
110 | 113 | #define RK3588_RGB 0 |
---|
.. | .. |
---|
129 | 132 | #define RK3588_HDMI0_GRANT_SW BIT(11) |
---|
130 | 133 | #define RK3588_HDMI1_GRANT_SEL BIT(12) |
---|
131 | 134 | #define RK3588_HDMI1_GRANT_SW BIT(13) |
---|
| 135 | +#define RK3588_GRF_VO1_CON4 0x0010 |
---|
| 136 | +#define RK3588_HDMI_HDCP14_MEM_EN BIT(15) |
---|
132 | 137 | #define RK3588_GRF_VO1_CON6 0x0018 |
---|
133 | 138 | #define RK3588_GRF_VO1_CON7 0x001c |
---|
134 | 139 | |
---|
.. | .. |
---|
197 | 202 | u8 id; |
---|
198 | 203 | bool hpd_stat; |
---|
199 | 204 | bool is_hdmi_qp; |
---|
200 | | - bool user_split_mode; |
---|
201 | 205 | |
---|
202 | 206 | unsigned long bus_format; |
---|
203 | 207 | unsigned long output_bus_format; |
---|
.. | .. |
---|
215 | 219 | struct drm_property *next_hdr_sink_data_property; |
---|
216 | 220 | struct drm_property *output_hdmi_dvi; |
---|
217 | 221 | struct drm_property *output_type_capacity; |
---|
218 | | - struct drm_property *user_split_mode_prop; |
---|
219 | 222 | struct drm_property *allm_capacity; |
---|
220 | 223 | struct drm_property *allm_enable; |
---|
| 224 | + struct drm_property *hdcp_state_property; |
---|
221 | 225 | |
---|
222 | 226 | struct drm_property_blob *hdr_panel_blob_ptr; |
---|
223 | 227 | struct drm_property_blob *next_hdr_data_ptr; |
---|
.. | .. |
---|
234 | 238 | u8 max_lanes; |
---|
235 | 239 | u8 add_func; |
---|
236 | 240 | u8 edid_colorimetry; |
---|
| 241 | + u8 hdcp_status; |
---|
237 | 242 | struct rockchip_drm_dsc_cap dsc_cap; |
---|
238 | 243 | struct next_hdr_sink_data next_hdr_data; |
---|
239 | 244 | struct dw_hdmi_link_config link_cfg; |
---|
.. | .. |
---|
1592 | 1597 | struct drm_crtc *crtc; |
---|
1593 | 1598 | struct rockchip_hdmi *hdmi; |
---|
1594 | 1599 | |
---|
1595 | | - /* |
---|
1596 | | - * Pixel clocks we support are always < 2GHz and so fit in an |
---|
1597 | | - * int. We should make sure source rate does too so we don't get |
---|
1598 | | - * overflow when we multiply by 1000. |
---|
1599 | | - */ |
---|
1600 | | - if (mode->clock > INT_MAX / 1000) |
---|
1601 | | - return MODE_BAD; |
---|
1602 | | - |
---|
1603 | 1600 | if (!encoder) { |
---|
1604 | 1601 | const struct drm_connector_helper_funcs *funcs; |
---|
1605 | 1602 | |
---|
.. | .. |
---|
1615 | 1612 | return MODE_BAD; |
---|
1616 | 1613 | |
---|
1617 | 1614 | hdmi = to_rockchip_hdmi(encoder); |
---|
| 1615 | + |
---|
| 1616 | + if (hdmi->is_hdmi_qp) { |
---|
| 1617 | + if (!hdmi->enable_gpio && mode->clock > 600000) |
---|
| 1618 | + return MODE_BAD; |
---|
| 1619 | + |
---|
| 1620 | + return MODE_OK; |
---|
| 1621 | + } |
---|
| 1622 | + |
---|
| 1623 | + /* |
---|
| 1624 | + * Pixel clocks we support are always < 2GHz and so fit in an |
---|
| 1625 | + * int. We should make sure source rate does too so we don't get |
---|
| 1626 | + * overflow when we multiply by 1000. |
---|
| 1627 | + */ |
---|
| 1628 | + if (mode->clock > INT_MAX / 1000) |
---|
| 1629 | + return MODE_BAD; |
---|
1618 | 1630 | |
---|
1619 | 1631 | /* |
---|
1620 | 1632 | * If sink max TMDS clock < 340MHz, we should check the mode pixel |
---|
.. | .. |
---|
1668 | 1680 | { |
---|
1669 | 1681 | struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder); |
---|
1670 | 1682 | struct drm_crtc *crtc = encoder->crtc; |
---|
1671 | | - struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); |
---|
| 1683 | + struct rockchip_crtc_state *s; |
---|
1672 | 1684 | |
---|
1673 | | - if (WARN_ON(!crtc || !crtc->state)) |
---|
| 1685 | + if (!crtc || !crtc->state) { |
---|
| 1686 | + dev_info(hdmi->dev, "%s old crtc state is null\n", __func__); |
---|
1674 | 1687 | return; |
---|
| 1688 | + } |
---|
| 1689 | + |
---|
| 1690 | + s = to_rockchip_crtc_state(crtc->state); |
---|
1675 | 1691 | |
---|
1676 | 1692 | if (crtc->state->active_changed) { |
---|
1677 | 1693 | if (hdmi->plat_data->split_mode) { |
---|
.. | .. |
---|
1699 | 1715 | int mux; |
---|
1700 | 1716 | int ret; |
---|
1701 | 1717 | |
---|
1702 | | - if (WARN_ON(!crtc || !crtc->state)) |
---|
| 1718 | + if (!crtc || !crtc->state) { |
---|
| 1719 | + dev_info(hdmi->dev, "%s old crtc state is null\n", __func__); |
---|
1703 | 1720 | return; |
---|
| 1721 | + } |
---|
1704 | 1722 | |
---|
1705 | 1723 | if (hdmi->phy) |
---|
1706 | 1724 | phy_set_bus_width(hdmi->phy, hdmi->phy_bus_width); |
---|
.. | .. |
---|
1878 | 1896 | regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON6, val); |
---|
1879 | 1897 | } |
---|
1880 | 1898 | |
---|
| 1899 | +static void rk3588_set_hdcp_status(void *data, u8 status) |
---|
| 1900 | +{ |
---|
| 1901 | + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
---|
| 1902 | + |
---|
| 1903 | + hdmi->hdcp_status = status; |
---|
| 1904 | +} |
---|
| 1905 | + |
---|
| 1906 | +static void rk3588_set_hdcp2_enable(void *data, bool enable) |
---|
| 1907 | +{ |
---|
| 1908 | + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
---|
| 1909 | + u32 val; |
---|
| 1910 | + |
---|
| 1911 | + if (enable) |
---|
| 1912 | + val = HIWORD_UPDATE(HDCP1_P1_GPIO_IN, HDCP1_P1_GPIO_IN); |
---|
| 1913 | + else |
---|
| 1914 | + val = HIWORD_UPDATE(0, HDCP1_P1_GPIO_IN); |
---|
| 1915 | + |
---|
| 1916 | + regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON1, val); |
---|
| 1917 | +} |
---|
| 1918 | + |
---|
1881 | 1919 | static void rk3588_set_grf_cfg(void *data) |
---|
1882 | 1920 | { |
---|
1883 | 1921 | struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
---|
.. | .. |
---|
2027 | 2065 | else |
---|
2028 | 2066 | color_depth = 8; |
---|
2029 | 2067 | |
---|
2030 | | - if (!sink_is_hdmi) { |
---|
2031 | | - *color_format = RK_IF_FORMAT_RGB; |
---|
2032 | | - color_depth = 8; |
---|
2033 | | - } |
---|
2034 | | - |
---|
2035 | 2068 | *eotf = HDMI_EOTF_TRADITIONAL_GAMMA_SDR; |
---|
2036 | 2069 | if (conn_state->hdr_output_metadata) { |
---|
2037 | 2070 | hdr_metadata = (struct hdr_output_metadata *) |
---|
.. | .. |
---|
2080 | 2113 | |
---|
2081 | 2114 | if (hdmi->is_hdmi_qp && mode.clock >= 600000) |
---|
2082 | 2115 | *color_format = RK_IF_FORMAT_YCBCR420; |
---|
| 2116 | + |
---|
| 2117 | + if (!sink_is_hdmi) { |
---|
| 2118 | + *color_format = RK_IF_FORMAT_RGB; |
---|
| 2119 | + color_depth = 8; |
---|
| 2120 | + } |
---|
2083 | 2121 | |
---|
2084 | 2122 | if (*color_format == RK_IF_FORMAT_YCBCR422 || color_depth == 8) |
---|
2085 | 2123 | tmdsclock = pixclock; |
---|
.. | .. |
---|
2551 | 2589 | } |
---|
2552 | 2590 | } |
---|
2553 | 2591 | |
---|
| 2592 | +static void dw_hdmi_rockchip_set_hdcp14_mem(void *data, bool enable) |
---|
| 2593 | +{ |
---|
| 2594 | + struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
---|
| 2595 | + u32 val; |
---|
| 2596 | + |
---|
| 2597 | + val = HIWORD_UPDATE(enable << 15, RK3588_HDMI_HDCP14_MEM_EN); |
---|
| 2598 | + if (!hdmi->id) |
---|
| 2599 | + regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON4, val); |
---|
| 2600 | + else |
---|
| 2601 | + regmap_write(hdmi->vo1_regmap, RK3588_GRF_VO1_CON7, val); |
---|
| 2602 | +} |
---|
| 2603 | + |
---|
2554 | 2604 | static const struct drm_prop_enum_list color_depth_enum_list[] = { |
---|
2555 | 2605 | { 0, "Automatic" }, /* Prefer highest color depth */ |
---|
2556 | 2606 | { 8, "24bit" }, |
---|
.. | .. |
---|
2597 | 2647 | struct rockchip_hdmi *hdmi = (struct rockchip_hdmi *)data; |
---|
2598 | 2648 | struct drm_property *prop; |
---|
2599 | 2649 | struct rockchip_drm_private *private = connector->dev->dev_private; |
---|
| 2650 | + int ret; |
---|
2600 | 2651 | |
---|
2601 | 2652 | switch (color) { |
---|
2602 | 2653 | case MEDIA_BUS_FMT_RGB101010_1X30: |
---|
.. | .. |
---|
2711 | 2762 | drm_object_attach_property(&connector->base, prop, 0); |
---|
2712 | 2763 | } |
---|
2713 | 2764 | |
---|
2714 | | - prop = drm_property_create_bool(connector->dev, DRM_MODE_PROP_IMMUTABLE, |
---|
2715 | | - "USER_SPLIT_MODE"); |
---|
2716 | | - if (prop) { |
---|
2717 | | - hdmi->user_split_mode_prop = prop; |
---|
2718 | | - drm_object_attach_property(&connector->base, prop, |
---|
2719 | | - hdmi->user_split_mode ? 1 : 0); |
---|
2720 | | - } |
---|
| 2765 | + if (hdmi->is_hdmi_qp) { |
---|
| 2766 | + prop = drm_property_create_bool(connector->dev, 0, "allm_capacity"); |
---|
| 2767 | + if (prop) { |
---|
| 2768 | + hdmi->allm_capacity = prop; |
---|
| 2769 | + drm_object_attach_property(&connector->base, prop, |
---|
| 2770 | + !!(hdmi->add_func & SUPPORT_HDMI_ALLM)); |
---|
| 2771 | + } |
---|
2721 | 2772 | |
---|
2722 | | - prop = drm_property_create_bool(connector->dev, 0, "allm_capacity"); |
---|
2723 | | - if (prop) { |
---|
2724 | | - hdmi->allm_capacity = prop; |
---|
2725 | | - drm_object_attach_property(&connector->base, prop, |
---|
2726 | | - !!(hdmi->add_func & SUPPORT_HDMI_ALLM)); |
---|
| 2773 | + prop = drm_property_create_enum(connector->dev, 0, |
---|
| 2774 | + "allm_enable", |
---|
| 2775 | + allm_enable_list, |
---|
| 2776 | + ARRAY_SIZE(allm_enable_list)); |
---|
| 2777 | + if (prop) { |
---|
| 2778 | + hdmi->allm_enable = prop; |
---|
| 2779 | + drm_object_attach_property(&connector->base, prop, 0); |
---|
| 2780 | + } |
---|
| 2781 | + hdmi->enable_allm = allm_en; |
---|
2727 | 2782 | } |
---|
2728 | | - |
---|
2729 | | - prop = drm_property_create_enum(connector->dev, 0, |
---|
2730 | | - "allm_enable", |
---|
2731 | | - allm_enable_list, |
---|
2732 | | - ARRAY_SIZE(allm_enable_list)); |
---|
2733 | | - if (prop) { |
---|
2734 | | - hdmi->allm_enable = prop; |
---|
2735 | | - drm_object_attach_property(&connector->base, prop, 0); |
---|
2736 | | - } |
---|
2737 | | - hdmi->enable_allm = allm_en; |
---|
2738 | 2783 | |
---|
2739 | 2784 | prop = drm_property_create_enum(connector->dev, 0, |
---|
2740 | 2785 | "output_hdmi_dvi", |
---|
.. | .. |
---|
2773 | 2818 | drm_object_attach_property(&connector->base, |
---|
2774 | 2819 | connector->colorspace_property, 0); |
---|
2775 | 2820 | drm_object_attach_property(&connector->base, private->connector_id_prop, hdmi->id); |
---|
| 2821 | + |
---|
| 2822 | + ret = drm_connector_attach_content_protection_property(connector, true); |
---|
| 2823 | + if (ret) { |
---|
| 2824 | + dev_err(hdmi->dev, "failed to attach content protection: %d\n", ret); |
---|
| 2825 | + return; |
---|
| 2826 | + } |
---|
| 2827 | + |
---|
| 2828 | + prop = drm_property_create_range(connector->dev, 0, RK_IF_PROP_ENCRYPTED, |
---|
| 2829 | + RK_IF_HDCP_ENCRYPTED_NONE, RK_IF_HDCP_ENCRYPTED_LEVEL2); |
---|
| 2830 | + if (!prop) { |
---|
| 2831 | + dev_err(hdmi->dev, "create hdcp encrypted prop for hdmi%d failed\n", hdmi->id); |
---|
| 2832 | + return; |
---|
| 2833 | + } |
---|
| 2834 | + hdmi->hdcp_state_property = prop; |
---|
| 2835 | + drm_object_attach_property(&connector->base, prop, RK_IF_HDCP_ENCRYPTED_NONE); |
---|
2776 | 2836 | } |
---|
2777 | 2837 | |
---|
2778 | 2838 | static void |
---|
.. | .. |
---|
2833 | 2893 | drm_property_destroy(connector->dev, |
---|
2834 | 2894 | hdmi->output_type_capacity); |
---|
2835 | 2895 | hdmi->output_type_capacity = NULL; |
---|
2836 | | - } |
---|
2837 | | - |
---|
2838 | | - if (hdmi->user_split_mode_prop) { |
---|
2839 | | - drm_property_destroy(connector->dev, |
---|
2840 | | - hdmi->user_split_mode_prop); |
---|
2841 | | - hdmi->user_split_mode_prop = NULL; |
---|
2842 | 2896 | } |
---|
2843 | 2897 | |
---|
2844 | 2898 | if (hdmi->allm_capacity) { |
---|
.. | .. |
---|
2913 | 2967 | if (allm_enable != hdmi->enable_allm) |
---|
2914 | 2968 | dw_hdmi_qp_set_allm_enable(hdmi->hdmi_qp, hdmi->enable_allm); |
---|
2915 | 2969 | return 0; |
---|
| 2970 | + } else if (property == hdmi->hdcp_state_property) { |
---|
| 2971 | + return 0; |
---|
2916 | 2972 | } |
---|
2917 | 2973 | |
---|
2918 | 2974 | DRM_ERROR("Unknown property [PROP:%d:%s]\n", |
---|
.. | .. |
---|
2982 | 3038 | else |
---|
2983 | 3039 | *val = dw_hdmi_qp_get_output_type_cap(hdmi->hdmi_qp); |
---|
2984 | 3040 | return 0; |
---|
2985 | | - } else if (property == hdmi->user_split_mode_prop) { |
---|
2986 | | - *val = hdmi->user_split_mode; |
---|
2987 | | - return 0; |
---|
2988 | 3041 | } else if (property == hdmi->allm_capacity) { |
---|
2989 | 3042 | *val = !!(hdmi->add_func & SUPPORT_HDMI_ALLM); |
---|
2990 | 3043 | return 0; |
---|
2991 | 3044 | } else if (property == hdmi->allm_enable) { |
---|
2992 | 3045 | *val = hdmi->enable_allm; |
---|
| 3046 | + return 0; |
---|
| 3047 | + } else if (property == hdmi->hdcp_state_property) { |
---|
| 3048 | + if (hdmi->hdcp_status & BIT(1)) |
---|
| 3049 | + *val = RK_IF_HDCP_ENCRYPTED_LEVEL2; |
---|
| 3050 | + else if (hdmi->hdcp_status & BIT(0)) |
---|
| 3051 | + *val = RK_IF_HDCP_ENCRYPTED_LEVEL1; |
---|
| 3052 | + else |
---|
| 3053 | + *val = RK_IF_HDCP_ENCRYPTED_NONE; |
---|
2993 | 3054 | return 0; |
---|
2994 | 3055 | } |
---|
2995 | 3056 | |
---|
.. | .. |
---|
3376 | 3437 | }; |
---|
3377 | 3438 | |
---|
3378 | 3439 | static const struct dw_hdmi_plat_data rk3588_hdmi_drv_data = { |
---|
| 3440 | + .mode_valid = dw_hdmi_rockchip_mode_valid, |
---|
3379 | 3441 | .phy_data = &rk3588_hdmi_chip_data, |
---|
3380 | 3442 | .qp_phy_ops = &rk3588_hdmi_phy_ops, |
---|
3381 | 3443 | .phy_name = "samsung_hdptx_phy", |
---|
.. | .. |
---|
3463 | 3525 | plat_data->get_colorimetry = |
---|
3464 | 3526 | dw_hdmi_rockchip_get_colorimetry; |
---|
3465 | 3527 | plat_data->get_link_cfg = dw_hdmi_rockchip_get_link_cfg; |
---|
| 3528 | + plat_data->set_hdcp2_enable = rk3588_set_hdcp2_enable; |
---|
| 3529 | + plat_data->set_hdcp_status = rk3588_set_hdcp_status; |
---|
3466 | 3530 | plat_data->set_grf_cfg = rk3588_set_grf_cfg; |
---|
3467 | 3531 | plat_data->get_grf_color_fmt = rk3588_get_grf_color_fmt; |
---|
3468 | 3532 | plat_data->convert_to_split_mode = drm_mode_convert_to_split_mode; |
---|
.. | .. |
---|
3478 | 3542 | dw_hdmi_rockchip_set_prev_bus_format; |
---|
3479 | 3543 | plat_data->set_ddc_io = |
---|
3480 | 3544 | dw_hdmi_rockchip_set_ddc_io; |
---|
| 3545 | + plat_data->set_hdcp14_mem = |
---|
| 3546 | + dw_hdmi_rockchip_set_hdcp14_mem; |
---|
3481 | 3547 | plat_data->property_ops = &dw_hdmi_rockchip_property_ops; |
---|
3482 | 3548 | |
---|
3483 | 3549 | secondary = rockchip_hdmi_find_by_id(dev->driver, !hdmi->id); |
---|
.. | .. |
---|
3496 | 3562 | secondary->plat_data->split_mode = true; |
---|
3497 | 3563 | if (!secondary->plat_data->first_screen) |
---|
3498 | 3564 | plat_data->first_screen = true; |
---|
3499 | | - } |
---|
3500 | | - |
---|
3501 | | - if (device_property_read_bool(dev, "user-split-mode") || |
---|
3502 | | - device_property_read_bool(secondary->dev, "user-split-mode")) { |
---|
3503 | | - hdmi->user_split_mode = true; |
---|
3504 | | - secondary->user_split_mode = true; |
---|
3505 | 3565 | } |
---|
3506 | 3566 | } |
---|
3507 | 3567 | |
---|
.. | .. |
---|
3675 | 3735 | drm_encoder_cleanup(&hdmi->encoder); |
---|
3676 | 3736 | } |
---|
3677 | 3737 | |
---|
3678 | | - if (plat_data->connector) { |
---|
| 3738 | + if (plat_data->bridge) { |
---|
| 3739 | + struct drm_connector *connector = NULL; |
---|
| 3740 | + struct list_head *connector_list = |
---|
| 3741 | + &plat_data->bridge->dev->mode_config.connector_list; |
---|
| 3742 | + |
---|
| 3743 | + list_for_each_entry(connector, connector_list, head) |
---|
| 3744 | + if (drm_connector_has_possible_encoder(connector, |
---|
| 3745 | + &hdmi->encoder)) |
---|
| 3746 | + break; |
---|
| 3747 | + |
---|
| 3748 | + hdmi->sub_dev.connector = connector; |
---|
| 3749 | + hdmi->sub_dev.of_node = dev->of_node; |
---|
| 3750 | + rockchip_drm_register_sub_dev(&hdmi->sub_dev); |
---|
| 3751 | + } else if (plat_data->connector) { |
---|
3679 | 3752 | hdmi->sub_dev.connector = plat_data->connector; |
---|
3680 | 3753 | hdmi->sub_dev.loader_protect = dw_hdmi_rockchip_encoder_loader_protect; |
---|
3681 | 3754 | if (secondary && device_property_read_bool(secondary->dev, "split-mode")) |
---|