.. | .. |
---|
55 | 55 | struct completion cmp; |
---|
56 | 56 | }; |
---|
57 | 57 | |
---|
| 58 | +enum inno_hdmi_dev_type { |
---|
| 59 | + RK3036_HDMI, |
---|
| 60 | + RK3128_HDMI, |
---|
| 61 | +}; |
---|
| 62 | + |
---|
| 63 | +struct inno_hdmi_phy_config { |
---|
| 64 | + unsigned long mpixelclock; |
---|
| 65 | + u8 pre_emphasis; /* pre-emphasis value */ |
---|
| 66 | + u8 vlev_ctr; /* voltage level control */ |
---|
| 67 | +}; |
---|
| 68 | + |
---|
| 69 | +struct inno_hdmi_plat_data { |
---|
| 70 | + enum inno_hdmi_dev_type dev_type; |
---|
| 71 | + struct inno_hdmi_phy_config *phy_config; |
---|
| 72 | +}; |
---|
| 73 | + |
---|
58 | 74 | struct inno_hdmi { |
---|
59 | 75 | struct device *dev; |
---|
60 | 76 | struct drm_device *drm_dev; |
---|
61 | 77 | |
---|
62 | 78 | int irq; |
---|
| 79 | + struct clk *aclk; |
---|
63 | 80 | struct clk *pclk; |
---|
64 | 81 | void __iomem *regs; |
---|
65 | 82 | |
---|
.. | .. |
---|
70 | 87 | struct i2c_adapter *ddc; |
---|
71 | 88 | |
---|
72 | 89 | unsigned int tmds_rate; |
---|
| 90 | + const struct inno_hdmi_plat_data *plat_data; |
---|
73 | 91 | |
---|
74 | 92 | struct hdmi_data_info hdmi_data; |
---|
75 | 93 | struct drm_display_mode previous_mode; |
---|
.. | .. |
---|
197 | 215 | |
---|
198 | 216 | static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode) |
---|
199 | 217 | { |
---|
| 218 | + const struct inno_hdmi_phy_config *phy_config = |
---|
| 219 | + hdmi->plat_data->phy_config; |
---|
| 220 | + |
---|
200 | 221 | switch (mode) { |
---|
201 | 222 | case NORMAL: |
---|
202 | 223 | inno_hdmi_sys_power(hdmi, false); |
---|
203 | | - |
---|
204 | | - hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); |
---|
205 | | - hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); |
---|
| 224 | + for (; phy_config->mpixelclock != ~0UL; phy_config++) |
---|
| 225 | + if (hdmi->tmds_rate <= phy_config->mpixelclock) |
---|
| 226 | + break; |
---|
| 227 | + if (!phy_config->mpixelclock) |
---|
| 228 | + return; |
---|
| 229 | + hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, |
---|
| 230 | + phy_config->pre_emphasis); |
---|
| 231 | + hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->vlev_ctr); |
---|
206 | 232 | |
---|
207 | 233 | hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); |
---|
208 | 234 | hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); |
---|
.. | .. |
---|
389 | 415 | { |
---|
390 | 416 | int value; |
---|
391 | 417 | |
---|
| 418 | + if (hdmi->plat_data->dev_type == RK3036_HDMI) { |
---|
| 419 | + value = BIT(20) | BIT(21); |
---|
| 420 | + value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BIT(4) : 0; |
---|
| 421 | + value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BIT(5) : 0; |
---|
| 422 | + hdmi_writeb(hdmi, 0x148, value); |
---|
| 423 | + } |
---|
392 | 424 | /* Set detail external video timing polarity and interlace mode */ |
---|
393 | 425 | value = v_EXTERANL_VIDEO(1); |
---|
394 | 426 | value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? |
---|
.. | .. |
---|
823 | 855 | return adap; |
---|
824 | 856 | } |
---|
825 | 857 | |
---|
| 858 | +static struct inno_hdmi_phy_config rk3036_hdmi_phy_config[] = { |
---|
| 859 | + /* pixelclk pre-emp vlev */ |
---|
| 860 | + { 74250000, 0x3f, 0xbb }, |
---|
| 861 | + { 165000000, 0x6f, 0xbb }, |
---|
| 862 | + { ~0UL, 0x00, 0x00 } |
---|
| 863 | +}; |
---|
| 864 | + |
---|
| 865 | +static struct inno_hdmi_phy_config rk3128_hdmi_phy_config[] = { |
---|
| 866 | + /* pixelclk pre-emp vlev */ |
---|
| 867 | + { 74250000, 0x3f, 0xaa }, |
---|
| 868 | + { 165000000, 0x5f, 0xaa }, |
---|
| 869 | + { ~0UL, 0x00, 0x00 } |
---|
| 870 | +}; |
---|
| 871 | + |
---|
| 872 | +static const struct inno_hdmi_plat_data rk3036_hdmi_drv_data = { |
---|
| 873 | + .dev_type = RK3036_HDMI, |
---|
| 874 | + .phy_config = rk3036_hdmi_phy_config, |
---|
| 875 | +}; |
---|
| 876 | + |
---|
| 877 | +static const struct inno_hdmi_plat_data rk3128_hdmi_drv_data = { |
---|
| 878 | + .dev_type = RK3128_HDMI, |
---|
| 879 | + .phy_config = rk3128_hdmi_phy_config, |
---|
| 880 | +}; |
---|
| 881 | + |
---|
| 882 | +static const struct of_device_id inno_hdmi_dt_ids[] = { |
---|
| 883 | + { .compatible = "rockchip,rk3036-inno-hdmi", |
---|
| 884 | + .data = &rk3036_hdmi_drv_data, |
---|
| 885 | + }, |
---|
| 886 | + { .compatible = "rockchip,rk3128-inno-hdmi", |
---|
| 887 | + .data = &rk3128_hdmi_drv_data, |
---|
| 888 | + }, |
---|
| 889 | + {}, |
---|
| 890 | +}; |
---|
| 891 | +MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); |
---|
| 892 | + |
---|
826 | 893 | static int inno_hdmi_bind(struct device *dev, struct device *master, |
---|
827 | 894 | void *data) |
---|
828 | 895 | { |
---|
.. | .. |
---|
839 | 906 | |
---|
840 | 907 | hdmi->dev = dev; |
---|
841 | 908 | hdmi->drm_dev = drm; |
---|
| 909 | + hdmi->plat_data = device_get_match_data(hdmi->dev); |
---|
842 | 910 | |
---|
843 | 911 | iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
---|
844 | 912 | hdmi->regs = devm_ioremap_resource(dev, iores); |
---|
845 | 913 | if (IS_ERR(hdmi->regs)) |
---|
846 | 914 | return PTR_ERR(hdmi->regs); |
---|
| 915 | + |
---|
| 916 | + irq = platform_get_irq(pdev, 0); |
---|
| 917 | + if (irq < 0) |
---|
| 918 | + return irq; |
---|
| 919 | + |
---|
| 920 | + hdmi->aclk = devm_clk_get(hdmi->dev, "aclk"); |
---|
| 921 | + if (IS_ERR(hdmi->aclk)) { |
---|
| 922 | + dev_err(hdmi->dev, "Unable to get HDMI aclk clk\n"); |
---|
| 923 | + return PTR_ERR(hdmi->aclk); |
---|
| 924 | + } |
---|
847 | 925 | |
---|
848 | 926 | hdmi->pclk = devm_clk_get(hdmi->dev, "pclk"); |
---|
849 | 927 | if (IS_ERR(hdmi->pclk)) { |
---|
.. | .. |
---|
851 | 929 | return PTR_ERR(hdmi->pclk); |
---|
852 | 930 | } |
---|
853 | 931 | |
---|
854 | | - ret = clk_prepare_enable(hdmi->pclk); |
---|
| 932 | + ret = clk_prepare_enable(hdmi->aclk); |
---|
855 | 933 | if (ret) { |
---|
856 | 934 | DRM_DEV_ERROR(hdmi->dev, |
---|
857 | | - "Cannot enable HDMI pclk clock: %d\n", ret); |
---|
| 935 | + "Cannot enable HDMI aclk clock: %d\n", ret); |
---|
858 | 936 | return ret; |
---|
859 | 937 | } |
---|
860 | 938 | |
---|
861 | | - irq = platform_get_irq(pdev, 0); |
---|
862 | | - if (irq < 0) { |
---|
863 | | - ret = irq; |
---|
864 | | - goto err_disable_clk; |
---|
| 939 | + ret = clk_prepare_enable(hdmi->pclk); |
---|
| 940 | + if (ret) { |
---|
| 941 | + dev_err(hdmi->dev, "Cannot enable HDMI pclk clock: %d\n", ret); |
---|
| 942 | + goto err_disable_aclk; |
---|
865 | 943 | } |
---|
866 | 944 | |
---|
867 | 945 | inno_hdmi_reset(hdmi); |
---|
.. | .. |
---|
870 | 948 | if (IS_ERR(hdmi->ddc)) { |
---|
871 | 949 | ret = PTR_ERR(hdmi->ddc); |
---|
872 | 950 | hdmi->ddc = NULL; |
---|
873 | | - goto err_disable_clk; |
---|
| 951 | + goto err_disable_pclk; |
---|
874 | 952 | } |
---|
875 | 953 | |
---|
876 | 954 | /* |
---|
.. | .. |
---|
894 | 972 | ret = devm_request_threaded_irq(dev, irq, inno_hdmi_hardirq, |
---|
895 | 973 | inno_hdmi_irq, IRQF_SHARED, |
---|
896 | 974 | dev_name(dev), hdmi); |
---|
897 | | - if (ret < 0) |
---|
| 975 | + if (ret) { |
---|
| 976 | + dev_err(hdmi->dev, |
---|
| 977 | + "failed to request hdmi irq: %d\n", ret); |
---|
898 | 978 | goto err_cleanup_hdmi; |
---|
| 979 | + } |
---|
899 | 980 | |
---|
900 | 981 | return 0; |
---|
| 982 | + |
---|
901 | 983 | err_cleanup_hdmi: |
---|
902 | 984 | hdmi->connector.funcs->destroy(&hdmi->connector); |
---|
903 | 985 | hdmi->encoder.funcs->destroy(&hdmi->encoder); |
---|
904 | 986 | err_put_adapter: |
---|
905 | 987 | i2c_put_adapter(hdmi->ddc); |
---|
906 | | -err_disable_clk: |
---|
| 988 | +err_disable_pclk: |
---|
907 | 989 | clk_disable_unprepare(hdmi->pclk); |
---|
| 990 | +err_disable_aclk: |
---|
| 991 | + clk_disable_unprepare(hdmi->aclk); |
---|
908 | 992 | return ret; |
---|
909 | 993 | } |
---|
910 | 994 | |
---|
.. | .. |
---|
918 | 1002 | |
---|
919 | 1003 | i2c_put_adapter(hdmi->ddc); |
---|
920 | 1004 | clk_disable_unprepare(hdmi->pclk); |
---|
| 1005 | + clk_disable_unprepare(hdmi->aclk); |
---|
921 | 1006 | } |
---|
922 | 1007 | |
---|
923 | 1008 | static const struct component_ops inno_hdmi_ops = { |
---|
.. | .. |
---|
936 | 1021 | |
---|
937 | 1022 | return 0; |
---|
938 | 1023 | } |
---|
939 | | - |
---|
940 | | -static const struct of_device_id inno_hdmi_dt_ids[] = { |
---|
941 | | - { .compatible = "rockchip,rk3036-inno-hdmi", |
---|
942 | | - }, |
---|
943 | | - {}, |
---|
944 | | -}; |
---|
945 | | -MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids); |
---|
946 | 1024 | |
---|
947 | 1025 | struct platform_driver inno_hdmi_driver = { |
---|
948 | 1026 | .probe = inno_hdmi_probe, |
---|