layerscape: add patches-5.4
[openwrt/staging/stintel.git] / target / linux / layerscape / patches-5.4 / 805-display-0005-gpu-drm-Add-imx8qm-mq-DP-HDMI-driver.patch
1 From 1433ad0f114ec80b524768af8ec96e09a5bba9b2 Mon Sep 17 00:00:00 2001
2 From: Sandor Yu <Sandor.yu@nxp.com>
3 Date: Fri, 23 Aug 2019 14:05:16 +0800
4 Subject: [PATCH] gpu: drm: Add imx8qm/mq DP/HDMI driver
5
6 Add imx8qm/mq DP/hdmi driver
7
8 Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
9 ---
10 drivers/gpu/drm/imx/Kconfig | 9 +
11 drivers/gpu/drm/imx/Makefile | 1 +
12 drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c | 533 ++++++++++++++++++++++++
13 drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c | 684 ++++++++++++++++++++++++++++++
14 drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c | 163 ++++++++
15 drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c | 714 ++++++++++++++++++++++++++++++++
16 drivers/gpu/drm/imx/cdn-mhdp-phy.h | 153 +++++++
17 7 files changed, 2257 insertions(+)
18 create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c
19 create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
20 create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c
21 create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
22 create mode 100644 drivers/gpu/drm/imx/cdn-mhdp-phy.h
23
24 --- a/drivers/gpu/drm/imx/Kconfig
25 +++ b/drivers/gpu/drm/imx/Kconfig
26 @@ -39,3 +39,12 @@ config DRM_IMX_HDMI
27 depends on DRM_IMX
28 help
29 Choose this if you want to use HDMI on i.MX6.
30 +
31 +config DRM_IMX_CDNS_MHDP
32 + tristate "NXP i.MX MX8 DRM HDMI/DP"
33 + select DRM_CDNS_MHDP
34 + select DRM_CDNS_DP
35 + select DRM_CDNS_HDMI
36 + depends on DRM_IMX
37 + help
38 + Choose this if you want to use HDMI on i.MX8.
39 --- a/drivers/gpu/drm/imx/Makefile
40 +++ b/drivers/gpu/drm/imx/Makefile
41 @@ -9,3 +9,4 @@ obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
42 obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
43
44 obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
45 +obj-$(CONFIG_DRM_IMX_CDNS_MHDP) += cdn-mhdp-imx8qm.o cdn-mhdp-imx8mq.o cdn-mhdp-dp-phy.o cdn-mhdp-hdmi-phy.o
46 --- /dev/null
47 +++ b/drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c
48 @@ -0,0 +1,533 @@
49 +/*
50 + * Cadence Display Port Interface (DP) PHY driver
51 + *
52 + * Copyright (C) 2019 NXP Semiconductor, Inc.
53 + *
54 + * This program is free software; you can redistribute it and/or modify
55 + * it under the terms of the GNU General Public License as published by
56 + * the Free Software Foundation; either version 2 of the License, or
57 + * (at your option) any later version.
58 + *
59 + */
60 +#include <linux/clk.h>
61 +#include <linux/kernel.h>
62 +#include <drm/drm_dp_helper.h>
63 +
64 +#include <drm/bridge/cdns-mhdp-common.h>
65 +#include "cdn-mhdp-phy.h"
66 +
67 +enum dp_link_rate {
68 + RATE_1_6 = 162000,
69 + RATE_2_1 = 216000,
70 + RATE_2_4 = 243000,
71 + RATE_2_7 = 270000,
72 + RATE_3_2 = 324000,
73 + RATE_4_3 = 432000,
74 + RATE_5_4 = 540000,
75 + RATE_8_1 = 810000,
76 +};
77 +
78 +struct phy_pll_reg {
79 + u16 val[7];
80 + u32 addr;
81 +};
82 +
83 +static const struct phy_pll_reg phy_pll_27m_cfg[] = {
84 + /* 1.62 2.16 2.43 2.7 3.24 4.32 5.4 register address */
85 + {{ 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E, 0x010E }, CMN_PLL0_VCOCAL_INIT_TMR },
86 + {{ 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B, 0x001B }, CMN_PLL0_VCOCAL_ITER_TMR },
87 + {{ 0x30B9, 0x3087, 0x3096, 0x30B4, 0x30B9, 0x3087, 0x30B4 }, CMN_PLL0_VCOCAL_START },
88 + {{ 0x0077, 0x009F, 0x00B3, 0x00C7, 0x0077, 0x009F, 0x00C7 }, CMN_PLL0_INTDIV },
89 + {{ 0xF9DA, 0xF7CD, 0xF6C7, 0xF5C1, 0xF9DA, 0xF7CD, 0xF5C1 }, CMN_PLL0_FRACDIV },
90 + {{ 0x001E, 0x0028, 0x002D, 0x0032, 0x001E, 0x0028, 0x0032 }, CMN_PLL0_HIGH_THR },
91 + {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG },
92 + {{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL },
93 + {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD },
94 + {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD },
95 + {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD },
96 + {{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE },
97 + {{ 0x0043, 0x0043, 0x0043, 0x0042, 0x0043, 0x0043, 0x0042 }, CMN_DIAG_PLL0_CP_TUNE },
98 + {{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG },
99 + {{ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE1 },
100 + {{ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001 }, CMN_DIAG_PLL0_PTATIS_TUNE2 },
101 + {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_DIAG_PLL0_TEST_MODE},
102 + {{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL }
103 +};
104 +
105 +static const struct phy_pll_reg phy_pll_24m_cfg[] = {
106 + /* 1.62 2.16 2.43 2.7 3.24 4.32 5.4 register address */
107 + {{ 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0 }, CMN_PLL0_VCOCAL_INIT_TMR },
108 + {{ 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018 }, CMN_PLL0_VCOCAL_ITER_TMR },
109 + {{ 0x3061, 0x3092, 0x30B3, 0x30D0, 0x3061, 0x3092, 0x30D0 }, CMN_PLL0_VCOCAL_START },
110 + {{ 0x0086, 0x00B3, 0x00CA, 0x00E0, 0x0086, 0x00B3, 0x00E0 }, CMN_PLL0_INTDIV },
111 + {{ 0xF917, 0xF6C7, 0x75A1, 0xF479, 0xF917, 0xF6C7, 0xF479 }, CMN_PLL0_FRACDIV },
112 + {{ 0x0022, 0x002D, 0x0033, 0x0038, 0x0022, 0x002D, 0x0038 }, CMN_PLL0_HIGH_THR },
113 + {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 }, CMN_PLL0_DSM_DIAG },
114 + {{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 }, CMN_PLLSM0_USER_DEF_CTRL },
115 + {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_OVRD },
116 + {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBH_OVRD },
117 + {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, CMN_DIAG_PLL0_FBL_OVRD },
118 + {{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 }, CMN_DIAG_PLL0_V2I_TUNE },
119 + {{ 0x0026, 0x0029, 0x0029, 0x0029, 0x0026, 0x0029, 0x0029 }, CMN_DIAG_PLL0_CP_TUNE },
120 + {{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 }, CMN_DIAG_PLL0_LF_PROG },
121 + {{ 0x008C, 0x008C, 0x008C, 0x008C, 0x008C, 0x008C, 0x008C }, CMN_DIAG_PLL0_PTATIS_TUNE1 },
122 + {{ 0x002E, 0x002E, 0x002E, 0x002E, 0x002E, 0x002E, 0x002E }, CMN_DIAG_PLL0_PTATIS_TUNE2 },
123 + {{ 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022, 0x0022 }, CMN_DIAG_PLL0_TEST_MODE},
124 + {{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 }, CMN_PSM_CLK_CTRL }
125 +};
126 +
127 +static int link_rate_index(u32 rate)
128 +{
129 + switch (rate) {
130 + case RATE_1_6:
131 + return 0;
132 + case RATE_2_1:
133 + return 1;
134 + case RATE_2_4:
135 + return 2;
136 + case RATE_2_7:
137 + return 3;
138 + case RATE_3_2:
139 + return 4;
140 + case RATE_4_3:
141 + return 5;
142 + case RATE_5_4:
143 + return 6;
144 + default:
145 + return -1;
146 + }
147 +}
148 +
149 +static void dp_aux_cfg(struct cdns_mhdp_device *mhdp)
150 +{
151 + /* Power up Aux */
152 + cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 1);
153 +
154 + cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, 36);
155 + ndelay(150);
156 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100);
157 + ndelay(150);
158 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300);
159 + ndelay(150);
160 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000);
161 + ndelay(150);
162 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008);
163 + ndelay(150);
164 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018);
165 + ndelay(150);
166 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA018);
167 + ndelay(150);
168 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C);
169 + ndelay(150);
170 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0000);
171 + ndelay(150);
172 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x1001);
173 + ndelay(150);
174 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA098);
175 + ndelay(150);
176 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA198);
177 + ndelay(150);
178 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030d);
179 + ndelay(150);
180 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030f);
181 +}
182 +
183 +/* PMA common configuration for 24MHz */
184 +static void dp_phy_pma_cmn_cfg_24mhz(struct cdns_mhdp_device *mhdp)
185 +{
186 + int k;
187 + u32 num_lanes = mhdp->dp.link.num_lanes;
188 + u16 val;
189 +
190 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
191 + val &= 0xFFF7;
192 + val |= 0x0008;
193 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
194 +
195 + for (k = 0; k < num_lanes; k++) {
196 + /* Transceiver control and diagnostic registers */
197 + cdns_phy_reg_write(mhdp, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x0090);
198 + /* Transmitter receiver detect registers */
199 + cdns_phy_reg_write(mhdp, TX_RCVDET_EN_TMR | (k << 9), 0x0960);
200 + cdns_phy_reg_write(mhdp, TX_RCVDET_ST_TMR | (k << 9), 0x0030);
201 + }
202 +}
203 +
204 +/* Valid for 24 MHz only */
205 +static void dp_phy_pma_cmn_pll0_24mhz(struct cdns_mhdp_device *mhdp)
206 +{
207 + u32 num_lanes = mhdp->dp.link.num_lanes;
208 + u32 link_rate = mhdp->dp.link.rate;
209 + u16 val;
210 + int index, i, k;
211 +
212 + /*
213 + * PLL reference clock source select
214 + * for single ended reference clock val |= 0x0030;
215 + * for differential clock val |= 0x0000;
216 + */
217 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
218 + val = val & 0xFF8F;
219 + val = val | 0x0030;
220 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
221 +
222 + /* DP PLL data rate 0/1 clock divider value */
223 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
224 + val &= 0x00FF;
225 + if (link_rate <= RATE_2_7)
226 + val |= 0x2400;
227 + else
228 + val |= 0x1200;
229 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
230 +
231 + /* High speed clock 0/1 div */
232 + val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
233 + val &= 0xFFCC;
234 + if (link_rate <= RATE_2_7)
235 + val |= 0x0011;
236 + cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
237 +
238 + for (k = 0; k < num_lanes; k = k + 1) {
239 + val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
240 + val &= 0xCFFF;
241 + if (link_rate <= RATE_2_7)
242 + val |= 0x1000;
243 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
244 + }
245 +
246 + /* DP PHY PLL 24MHz configuration */
247 + index = link_rate_index(link_rate);
248 + for (i = 0; i < ARRAY_SIZE(phy_pll_24m_cfg); i++)
249 + cdns_phy_reg_write(mhdp, phy_pll_24m_cfg[i].addr, phy_pll_24m_cfg[i].val[index]);
250 +
251 + /* Transceiver control and diagnostic registers */
252 + for (k = 0; k < num_lanes; k = k + 1) {
253 + val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
254 + val &= 0x8FFF;
255 + if (link_rate <= RATE_2_7)
256 + val |= 0x2000;
257 + else
258 + val |= 0x1000;
259 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
260 + }
261 +
262 + for (k = 0; k < num_lanes; k = k + 1) {
263 + cdns_phy_reg_write(mhdp, (XCVR_PSM_RCTRL | (k << 9)), 0xBEFC);
264 + cdns_phy_reg_write(mhdp, (TX_PSC_A0 | (k << 9)), 0x6799);
265 + cdns_phy_reg_write(mhdp, (TX_PSC_A1 | (k << 9)), 0x6798);
266 + cdns_phy_reg_write(mhdp, (TX_PSC_A2 | (k << 9)), 0x0098);
267 + cdns_phy_reg_write(mhdp, (TX_PSC_A3 | (k << 9)), 0x0098);
268 + }
269 +}
270 +
271 +/* PMA common configuration for 27MHz */
272 +static void dp_phy_pma_cmn_cfg_27mhz(struct cdns_mhdp_device *mhdp)
273 +{
274 + u32 num_lanes = mhdp->dp.link.num_lanes;
275 + u16 val;
276 + int k;
277 +
278 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
279 + val &= 0xFFF7;
280 + val |= 0x0008;
281 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
282 +
283 + /* Startup state machine registers */
284 + cdns_phy_reg_write(mhdp, CMN_SSM_BIAS_TMR, 0x0087);
285 + cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLEN_TMR, 0x001B);
286 + cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLPRE_TMR, 0x0036);
287 + cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLVREF_TMR, 0x001B);
288 + cdns_phy_reg_write(mhdp, CMN_PLLSM0_PLLLOCK_TMR, 0x006C);
289 +
290 + /* Current calibration registers */
291 + cdns_phy_reg_write(mhdp, CMN_ICAL_INIT_TMR, 0x0044);
292 + cdns_phy_reg_write(mhdp, CMN_ICAL_ITER_TMR, 0x0006);
293 + cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_INIT_TMR, 0x0022);
294 + cdns_phy_reg_write(mhdp, CMN_ICAL_ADJ_ITER_TMR, 0x0006);
295 +
296 + /* Resistor calibration registers */
297 + cdns_phy_reg_write(mhdp, CMN_TXPUCAL_INIT_TMR, 0x0022);
298 + cdns_phy_reg_write(mhdp, CMN_TXPUCAL_ITER_TMR, 0x0006);
299 + cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_INIT_TMR, 0x0022);
300 + cdns_phy_reg_write(mhdp, CMN_TXPU_ADJ_ITER_TMR, 0x0006);
301 + cdns_phy_reg_write(mhdp, CMN_TXPDCAL_INIT_TMR, 0x0022);
302 + cdns_phy_reg_write(mhdp, CMN_TXPDCAL_ITER_TMR, 0x0006);
303 + cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_INIT_TMR, 0x0022);
304 + cdns_phy_reg_write(mhdp, CMN_TXPD_ADJ_ITER_TMR, 0x0006);
305 + cdns_phy_reg_write(mhdp, CMN_RXCAL_INIT_TMR, 0x0022);
306 + cdns_phy_reg_write(mhdp, CMN_RXCAL_ITER_TMR, 0x0006);
307 + cdns_phy_reg_write(mhdp, CMN_RX_ADJ_INIT_TMR, 0x0022);
308 + cdns_phy_reg_write(mhdp, CMN_RX_ADJ_ITER_TMR, 0x0006);
309 +
310 + for (k = 0; k < num_lanes; k = k + 1) {
311 + /* Power state machine registers */
312 + cdns_phy_reg_write(mhdp, XCVR_PSM_CAL_TMR | (k << 9), 0x016D);
313 + cdns_phy_reg_write(mhdp, XCVR_PSM_A0IN_TMR | (k << 9), 0x016D);
314 + /* Transceiver control and diagnostic registers */
315 + cdns_phy_reg_write(mhdp, XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x00A2);
316 + cdns_phy_reg_write(mhdp, TX_DIAG_BGREF_PREDRV_DELAY | (k << 9), 0x0097);
317 + /* Transmitter receiver detect registers */
318 + cdns_phy_reg_write(mhdp, TX_RCVDET_EN_TMR | (k << 9), 0x0A8C);
319 + cdns_phy_reg_write(mhdp, TX_RCVDET_ST_TMR | (k << 9), 0x0036);
320 + }
321 +}
322 +
323 +static void dp_phy_pma_cmn_pll0_27mhz(struct cdns_mhdp_device *mhdp)
324 +{
325 + u32 num_lanes = mhdp->dp.link.num_lanes;
326 + u32 link_rate = mhdp->dp.link.rate;
327 + u16 val;
328 + int index, i, k;
329 +
330 + /*
331 + * PLL reference clock source select
332 + * for single ended reference clock val |= 0x0030;
333 + * for differential clock val |= 0x0000;
334 + */
335 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
336 + val &= 0xFF8F;
337 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
338 +
339 + /* for differential clock on the refclk_p and refclk_m off chip pins:
340 + * CMN_DIAG_ACYA[8]=1'b1
341 + */
342 + cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100);
343 +
344 + /* DP PLL data rate 0/1 clock divider value */
345 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
346 + val &= 0x00FF;
347 + if (link_rate <= RATE_2_7)
348 + val |= 0x2400;
349 + else
350 + val |= 0x1200;
351 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
352 +
353 + /* High speed clock 0/1 div */
354 + val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
355 + val &= 0xFFCC;
356 + if (link_rate <= RATE_2_7)
357 + val |= 0x0011;
358 + cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
359 +
360 + for (k = 0; k < num_lanes; k++) {
361 + val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
362 + val = val & 0xCFFF;
363 + if (link_rate <= RATE_2_7)
364 + val |= 0x1000;
365 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
366 + }
367 +
368 + /* DP PHY PLL 27MHz configuration */
369 + index = link_rate_index(link_rate);
370 + for (i = 0; i < ARRAY_SIZE(phy_pll_27m_cfg); i++)
371 + cdns_phy_reg_write(mhdp, phy_pll_27m_cfg[i].addr, phy_pll_27m_cfg[i].val[index]);
372 +
373 + /* Transceiver control and diagnostic registers */
374 + for (k = 0; k < num_lanes; k++) {
375 + val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
376 + val = val & 0x8FFF;
377 + if (link_rate <= RATE_2_7)
378 + val |= 0x2000;
379 + else
380 + val |= 0x1000;
381 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
382 + }
383 +
384 + for (k = 0; k < num_lanes; k = k + 1) {
385 + /* Power state machine registers */
386 + cdns_phy_reg_write(mhdp, (XCVR_PSM_RCTRL | (k << 9)), 0xBEFC);
387 + cdns_phy_reg_write(mhdp, (TX_PSC_A0 | (k << 9)), 0x6799);
388 + cdns_phy_reg_write(mhdp, (TX_PSC_A1 | (k << 9)), 0x6798);
389 + cdns_phy_reg_write(mhdp, (TX_PSC_A2 | (k << 9)), 0x0098);
390 + cdns_phy_reg_write(mhdp, (TX_PSC_A3 | (k << 9)), 0x0098);
391 + /* Receiver calibration power state definition register */
392 + val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9));
393 + val &= 0xFFBB;
394 + cdns_phy_reg_write(mhdp, (RX_PSC_CAL | (k << 9)), val);
395 + val = cdns_phy_reg_read(mhdp, RX_PSC_A0 | (k << 9));
396 + val &= 0xFFBB;
397 + cdns_phy_reg_write(mhdp, (RX_PSC_A0 | (k << 9)), val);
398 + }
399 +}
400 +
401 +static void dp_phy_power_down(struct cdns_mhdp_device *mhdp)
402 +{
403 + u16 val;
404 + int i;
405 +
406 + if (!mhdp->power_up)
407 + return;
408 +
409 + /* Place the PHY lanes in the A3 power state. */
410 + cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x8);
411 + /* Wait for Power State A3 Ack */
412 + for (i = 0; i < 10; i++) {
413 + val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
414 + if (val & (1 << 7))
415 + break;
416 + msleep(20);
417 + }
418 + if (i == 10) {
419 + dev_err(mhdp->dev, "Wait A3 Ack failed\n");
420 + return;
421 + }
422 +
423 + /* Disable HDP PLL’s data rate and full rate clocks out of PMA. */
424 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
425 + val &= ~(1 << 2);
426 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
427 + /* Wait for PLL clock gate ACK */
428 + for (i = 0; i < 10; i++) {
429 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
430 + if (!(val & (1 << 3)))
431 + break;
432 + msleep(20);
433 + }
434 + if (i == 10) {
435 + dev_err(mhdp->dev, "Wait PLL clock gate Ack failed\n");
436 + return;
437 + }
438 +
439 + /* Disable HDP PLL’s for high speed clocks */
440 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
441 + val &= ~(1 << 0);
442 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
443 + /* Wait for PLL disable ACK */
444 + for (i = 0; i < 10; i++) {
445 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
446 + if (!(val & (1 << 1)))
447 + break;
448 + msleep(20);
449 + }
450 + if (i == 10) {
451 + dev_err(mhdp->dev, "Wait PLL disable Ack failed\n");
452 + return;
453 + }
454 +}
455 +
456 +static int dp_phy_power_up(struct cdns_mhdp_device *mhdp)
457 +{
458 + u32 val, i;
459 +
460 + /* Enable HDP PLL’s for high speed clocks */
461 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
462 + val |= (1 << 0);
463 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
464 + /* Wait for PLL ready ACK */
465 + for (i = 0; i < 10; i++) {
466 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
467 + if (val & (1 << 1))
468 + break;
469 + msleep(20);
470 + }
471 + if (i == 10) {
472 + dev_err(mhdp->dev, "Wait PLL Ack failed\n");
473 + return -1;
474 + }
475 +
476 + /* Enable HDP PLL’s data rate and full rate clocks out of PMA. */
477 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
478 + val |= (1 << 2);
479 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
480 + /* Wait for PLL clock enable ACK */
481 + for (i = 0; i < 10; i++) {
482 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
483 + if (val & (1 << 3))
484 + break;
485 + msleep(20);
486 + }
487 + if (i == 10) {
488 + dev_err(mhdp->dev, "Wait PLL clock enable ACk failed\n");
489 + return -1;
490 + }
491 +
492 + /* Configure PHY in A2 Mode */
493 + cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004);
494 + /* Wait for Power State A2 Ack */
495 + for (i = 0; i < 10; i++) {
496 + val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
497 + if (val & (1 << 6))
498 + break;
499 + msleep(20);
500 + }
501 + if (i == 10) {
502 + dev_err(mhdp->dev, "Wait A2 Ack failed\n");
503 + return -1;
504 + }
505 +
506 + /* Configure PHY in A0 mode (PHY must be in the A0 power
507 + * state in order to transmit data)
508 + */
509 + cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101);
510 +
511 + /* Wait for Power State A0 Ack */
512 + for (i = 0; i < 10; i++) {
513 + val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
514 + if (val & (1 << 4))
515 + break;
516 + msleep(20);
517 + }
518 + if (i == 10) {
519 + dev_err(mhdp->dev, "Wait A0 Ack failed\n");
520 + return -1;
521 + }
522 +
523 + mhdp->power_up = true;
524 +
525 + return 0;
526 +}
527 +
528 +int cdns_dp_phy_init_imx8mq(struct imx_mhdp_device *hdp)
529 +{
530 + struct cdns_mhdp_device *mhdp = &hdp->mhdp;
531 + int ret;
532 +
533 + /* Disable phy clock if PHY in power up state */
534 + dp_phy_power_down(mhdp);
535 +
536 + dp_phy_pma_cmn_cfg_27mhz(mhdp);
537 +
538 + dp_phy_pma_cmn_pll0_27mhz(mhdp);
539 +
540 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
541 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
542 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
543 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
544 +
545 + /* PHY power up */
546 + ret = dp_phy_power_up(mhdp);
547 + if (ret < 0)
548 + return ret;
549 +
550 + dp_aux_cfg(mhdp);
551 +
552 + return ret;
553 +}
554 +
555 +
556 +int cdns_dp_phy_init_imx8qm(struct imx_mhdp_device *hdp)
557 +{
558 + struct cdns_mhdp_device *mhdp = &hdp->mhdp;
559 + int ret;
560 +
561 + /* Disable phy clock if PHY in power up state */
562 + dp_phy_power_down(mhdp);
563 +
564 + dp_phy_pma_cmn_cfg_24mhz(mhdp);
565 +
566 + dp_phy_pma_cmn_pll0_24mhz(mhdp);
567 +
568 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
569 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
570 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
571 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
572 +
573 + /* PHY power up */
574 + ret = dp_phy_power_up(mhdp);
575 + if (ret < 0)
576 + return ret;
577 +
578 + dp_aux_cfg(mhdp);
579 +
580 + return true;
581 +}
582 --- /dev/null
583 +++ b/drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
584 @@ -0,0 +1,684 @@
585 +/*
586 + * Cadence High-Definition Multimedia Interface (HDMI) driver
587 + *
588 + * Copyright (C) 2019 NXP Semiconductor, Inc.
589 + *
590 + * This program is free software; you can redistribute it and/or modify
591 + * it under the terms of the GNU General Public License as published by
592 + * the Free Software Foundation; either version 2 of the License, or
593 + * (at your option) any later version.
594 + *
595 + */
596 +#include <drm/drm_of.h>
597 +#include <drm/drmP.h>
598 +#include <drm/drm_crtc_helper.h>
599 +#include <linux/io.h>
600 +#include <drm/drm_edid.h>
601 +#include <drm/drm_encoder_slave.h>
602 +#include <drm/drm_atomic.h>
603 +#include <linux/io.h>
604 +
605 +#include <drm/bridge/cdns-mhdp-common.h>
606 +#include "cdn-mhdp-phy.h"
607 +
608 +/* HDMI TX clock control settings */
609 +struct hdmi_ctrl {
610 + u32 pixel_clk_freq_min;
611 + u32 pixel_clk_freq_max;
612 + u32 feedback_factor;
613 + u32 data_range_kbps_min;
614 + u32 data_range_kbps_max;
615 + u32 cmnda_pll0_ip_div;
616 + u32 cmn_ref_clk_dig_div;
617 + u32 ref_clk_divider_scaler;
618 + u32 pll_fb_div_total;
619 + u32 cmnda_pll0_fb_div_low;
620 + u32 cmnda_pll0_fb_div_high;
621 + u32 pixel_div_total;
622 + u32 cmnda_pll0_pxdiv_low;
623 + u32 cmnda_pll0_pxdiv_high;
624 + u32 vco_freq_min;
625 + u32 vco_freq_max;
626 + u32 vco_ring_select;
627 + u32 cmnda_hs_clk_0_sel;
628 + u32 cmnda_hs_clk_1_sel;
629 + u32 hsclk_div_at_xcvr;
630 + u32 hsclk_div_tx_sub_rate;
631 + u32 cmnda_pll0_hs_sym_div_sel;
632 + u32 cmnda_pll0_clk_freq_min;
633 + u32 cmnda_pll0_clk_freq_max;
634 +};
635 +
636 +/* HDMI TX clock control settings, pixel clock is output */
637 +static const struct hdmi_ctrl imx8mq_ctrl_table[] = {
638 +/*Minclk Maxclk Fdbak DR_min DR_max ip_d dig DS Totl */
639 +{ 27000, 27000, 1000, 270000, 270000, 0x03, 0x1, 0x1, 240, 0x0BC, 0x030, 80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x3, 27000, 27000},
640 +{ 27000, 27000, 1250, 337500, 337500, 0x03, 0x1, 0x1, 300, 0x0EC, 0x03C, 100, 0x030, 0x030, 2700000, 2700000, 0, 2, 2, 2, 4, 0x3, 33750, 33750},
641 +{ 27000, 27000, 1500, 405000, 405000, 0x03, 0x1, 0x1, 360, 0x11C, 0x048, 120, 0x03A, 0x03A, 3240000, 3240000, 0, 2, 2, 2, 4, 0x3, 40500, 40500},
642 +{ 27000, 27000, 2000, 540000, 540000, 0x03, 0x1, 0x1, 240, 0x0BC, 0x030, 80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x2, 54000, 54000},
643 +{ 54000, 54000, 1000, 540000, 540000, 0x03, 0x1, 0x1, 480, 0x17C, 0x060, 80, 0x026, 0x026, 4320000, 4320000, 1, 2, 2, 2, 4, 0x3, 54000, 54000},
644 +{ 54000, 54000, 1250, 675000, 675000, 0x04, 0x1, 0x1, 400, 0x13C, 0x050, 50, 0x017, 0x017, 2700000, 2700000, 0, 1, 1, 2, 4, 0x2, 67500, 67500},
645 +{ 54000, 54000, 1500, 810000, 810000, 0x04, 0x1, 0x1, 480, 0x17C, 0x060, 60, 0x01C, 0x01C, 3240000, 3240000, 0, 2, 2, 2, 2, 0x2, 81000, 81000},
646 +{ 54000, 54000, 2000, 1080000, 1080000, 0x03, 0x1, 0x1, 240, 0x0BC, 0x030, 40, 0x012, 0x012, 2160000, 2160000, 0, 2, 2, 2, 1, 0x1, 108000, 108000},
647 +{ 74250, 74250, 1000, 742500, 742500, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 80, 0x026, 0x026, 5940000, 5940000, 1, 2, 2, 2, 4, 0x3, 74250, 74250},
648 +{ 74250, 74250, 1250, 928125, 928125, 0x04, 0x1, 0x1, 550, 0x1B4, 0x06E, 50, 0x017, 0x017, 3712500, 3712500, 1, 1, 1, 2, 4, 0x2, 92812, 92812},
649 +{ 74250, 74250, 1500, 1113750, 1113750, 0x04, 0x1, 0x1, 660, 0x20C, 0x084, 60, 0x01C, 0x01C, 4455000, 4455000, 1, 2, 2, 2, 2, 0x2, 111375, 111375},
650 +{ 74250, 74250, 2000, 1485000, 1485000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 40, 0x012, 0x012, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500},
651 +{ 99000, 99000, 1000, 990000, 990000, 0x03, 0x1, 0x1, 440, 0x15C, 0x058, 40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 2, 0x2, 99000, 99000},
652 +{ 99000, 99000, 1250, 1237500, 1237500, 0x03, 0x1, 0x1, 275, 0x0D8, 0x037, 25, 0x00B, 0x00A, 2475000, 2475000, 0, 1, 1, 2, 2, 0x1, 123750, 123750},
653 +{ 99000, 99000, 1500, 1485000, 1485000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 30, 0x00D, 0x00D, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500, 148500},
654 +{ 99000, 99000, 2000, 1980000, 1980000, 0x03, 0x1, 0x1, 440, 0x15C, 0x058, 40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 1, 0x1, 198000, 198000},
655 +{148500, 148500, 1000, 1485000, 1485000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 2, 0x2, 148500, 148500},
656 +{148500, 148500, 1250, 1856250, 1856250, 0x04, 0x1, 0x1, 550, 0x1B4, 0x06E, 25, 0x00B, 0x00A, 3712500, 3712500, 1, 1, 1, 2, 2, 0x1, 185625, 185625},
657 +{148500, 148500, 1500, 2227500, 2227500, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 30, 0x00D, 0x00D, 4455000, 4455000, 1, 1, 1, 2, 2, 0x1, 222750, 222750},
658 +{148500, 148500, 2000, 2970000, 2970000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 1, 0x1, 297000, 297000},
659 +{198000, 198000, 1000, 1980000, 1980000, 0x03, 0x1, 0x1, 220, 0x0AC, 0x02C, 10, 0x003, 0x003, 1980000, 1980000, 0, 1, 1, 2, 1, 0x0, 198000, 198000},
660 +{198000, 198000, 1250, 2475000, 2475000, 0x03, 0x1, 0x1, 550, 0x1B4, 0x06E, 25, 0x00B, 0x00A, 4950000, 4950000, 1, 1, 1, 2, 2, 0x1, 247500, 247500},
661 +{198000, 198000, 1500, 2970000, 2970000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 15, 0x006, 0x005, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000},
662 +{198000, 198000, 2000, 3960000, 3960000, 0x03, 0x1, 0x1, 440, 0x15C, 0x058, 20, 0x008, 0x008, 3960000, 3960000, 1, 1, 1, 2, 1, 0x0, 396000, 396000},
663 +{297000, 297000, 1000, 2970000, 2970000, 0x03, 0x1, 0x1, 330, 0x104, 0x042, 10, 0x003, 0x003, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000, 297000},
664 +{297000, 297000, 1500, 4455000, 4455000, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 15, 0x006, 0x005, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500},
665 +{297000, 297000, 2000, 5940000, 5940000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 20, 0x008, 0x008, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000},
666 +{594000, 594000, 1000, 5940000, 5940000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000, 594000},
667 +{594000, 594000, 750, 4455000, 4455000, 0x03, 0x1, 0x1, 495, 0x188, 0x063, 10, 0x003, 0x003, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500, 445500},
668 +{594000, 594000, 625, 3712500, 3712500, 0x04, 0x1, 0x1, 550, 0x1B4, 0x06E, 10, 0x003, 0x003, 3712500, 3712500, 1, 1, 1, 2, 1, 0x0, 371250, 371250},
669 +{594000, 594000, 500, 2970000, 2970000, 0x03, 0x1, 0x1, 660, 0x20C, 0x084, 10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 2, 0x1, 297000, 297000},
670 +};
671 +
672 +/* HDMI TX clock control settings, pixel clock is input */
673 +static const struct hdmi_ctrl imx8qm_ctrl_table[] = {
674 +/*pclk_l pclk_h fd DRR_L DRR_H PLLD */
675 +{ 25000, 42500, 1000, 250000, 425000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2000000, 3400000, 0, 2, 2, 2, 4, 0x03, 25000, 42500},
676 +{ 42500, 85000, 1000, 425000, 850000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02, 42500, 85000},
677 +{ 85000, 170000, 1000, 850000, 1700000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01, 85000, 170000},
678 +{170000, 340000, 1000, 1700000, 3400000, 0x22, 0x01, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000},
679 +{340000, 600000, 1000, 3400000, 6000000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000},
680 +{ 25000, 34000, 1205, 312500, 425000, 0x04, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2500000, 3400000, 0, 2, 2, 2, 4, 0x03, 31250, 42500},
681 +{ 34000, 68000, 1205, 425000, 850000, 0x06, 0x02, 0x01, 300, 0x11E, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 4, 0x02, 42500, 85000},
682 +{ 68000, 136000, 1205, 850000, 1700000, 0x0D, 0x02, 0x02, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01, 85000, 170000},
683 +{136000, 272000, 1205, 1700000, 3400000, 0x1A, 0x02, 0x04, 325, 0x137, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000},
684 +{272000, 480000, 1205, 3400000, 6000000, 0x30, 0x03, 0x05, 600, 0x24A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000},
685 +{ 25000, 28000, 1500, 375000, 420000, 0x03, 0x01, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 3000000, 3360000, 0, 2, 2, 2, 4, 0x03, 37500, 42000},
686 +{ 28000, 56000, 1500, 420000, 840000, 0x06, 0x02, 0x01, 360, 0x15A, 0x00A, 0, 0, 0, 1680000, 3360000, 0, 1, 1, 2, 4, 0x02, 42000, 84000},
687 +{ 56000, 113000, 1500, 840000, 1695000, 0x0B, 0x00, 0x05, 330, 0x13C, 0x00A, 0, 0, 0, 1680000, 3390000, 0, 1, 1, 2, 2, 0x01, 84000, 169500},
688 +{113000, 226000, 1500, 1695000, 3390000, 0x16, 0x01, 0x05, 330, 0x13C, 0x00A, 0, 0, 0, 1695000, 3390000, 0, 1, 1, 2, 1, 0x00, 169500, 339000},
689 +{226000, 400000, 1500, 3390000, 6000000, 0x28, 0x03, 0x04, 600, 0x24A, 0x00A, 0, 0, 0, 3390000, 6000000, 1, 1, 1, 2, 1, 0x00, 339000, 600000},
690 +{ 25000, 42500, 2000, 500000, 850000, 0x05, 0x01, 0x01, 400, 0x182, 0x00A, 0, 0, 0, 2000000, 3400000, 0, 1, 1, 2, 4, 0x02, 50000, 85000},
691 +{ 42500, 85000, 2000, 850000, 1700000, 0x08, 0x03, 0x01, 320, 0x132, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 2, 0x01, 85000, 170000},
692 +{ 85000, 170000, 2000, 1700000, 3400000, 0x11, 0x00, 0x07, 340, 0x146, 0x00A, 0, 0, 0, 1700000, 3400000, 0, 1, 1, 2, 1, 0x00, 170000, 340000},
693 +{170000, 300000, 2000, 3400000, 6000000, 0x22, 0x01, 0x06, 680, 0x29A, 0x00A, 0, 0, 0, 3400000, 6000000, 1, 1, 1, 2, 1, 0x00, 340000, 600000},
694 +{594000, 594000, 5000, 2970000, 2970000, 0x3C, 0x03, 0x06, 600, 0x24A, 0x00A, 0, 0, 0, 5940000, 5940000, 1, 1, 1, 2, 2, 0x01, 297000, 297000},
695 +{594000, 594000, 6250, 3712500, 3712500, 0x3C, 0x03, 0x06, 375, 0x169, 0x00A, 0, 0, 0, 3712500, 3712500, 1, 1, 1, 2, 1, 0x00, 371250, 371250},
696 +{594000, 594000, 7500, 4455000, 4455000, 0x3C, 0x03, 0x06, 450, 0x1B4, 0x00A, 0, 0, 0, 4455000, 4455000, 1, 1, 1, 2, 1, 0x00, 445500, 445500},
697 +};
698 +
699 +/* HDMI TX PLL tuning settings */
700 +struct hdmi_pll_tuning {
701 + u32 vco_freq_bin;
702 + u32 vco_freq_min;
703 + u32 vco_freq_max;
704 + u32 volt_to_current_coarse;
705 + u32 volt_to_current;
706 + u32 ndac_ctrl;
707 + u32 pmos_ctrl;
708 + u32 ptat_ndac_ctrl;
709 + u32 feedback_div_total;
710 + u32 charge_pump_gain;
711 + u32 coarse_code;
712 + u32 v2i_code;
713 + u32 vco_cal_code;
714 +};
715 +
716 +/* HDMI TX PLL tuning settings, pixel clock is output */
717 +static const struct hdmi_pll_tuning imx8mq_pll_table[] = {
718 +/* bin VCO_freq min/max coar cod NDAC PMOS PTAT div-T P-Gain Coa V2I CAL */
719 + { 1, 1980000, 1980000, 0x4, 0x3, 0x0, 0x09, 0x09, 220, 0x42, 160, 5, 183 },
720 + { 2, 2160000, 2160000, 0x4, 0x3, 0x0, 0x09, 0x09, 240, 0x42, 166, 6, 208 },
721 + { 3, 2475000, 2475000, 0x5, 0x3, 0x1, 0x00, 0x07, 275, 0x42, 167, 6, 209 },
722 + { 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 300, 0x42, 188, 6, 230 },
723 + { 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 400, 0x4C, 188, 6, 230 },
724 + { 5, 2970000, 2970000, 0x6, 0x3, 0x1, 0x00, 0x07, 330, 0x42, 183, 6, 225 },
725 + { 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 360, 0x42, 203, 7, 256 },
726 + { 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 480, 0x4C, 203, 7, 256 },
727 + { 7, 3712500, 3712500, 0x4, 0x3, 0x0, 0x07, 0x0F, 550, 0x4C, 212, 7, 257 },
728 + { 8, 3960000, 3960000, 0x5, 0x3, 0x0, 0x07, 0x0F, 440, 0x42, 184, 6, 226 },
729 + { 9, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 480, 0x42, 205, 7, 258 },
730 + { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 495, 0x42, 219, 7, 272 },
731 + { 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 660, 0x4C, 219, 7, 272 },
732 + { 11, 4950000, 4950000, 0x6, 0x3, 0x1, 0x00, 0x07, 550, 0x42, 213, 7, 258 },
733 + { 12, 5940000, 5940000, 0x7, 0x3, 0x1, 0x00, 0x07, 660, 0x42, 244, 8, 292 },
734 +};
735 +
736 +/* HDMI TX PLL tuning settings, pixel clock is input */
737 +static const struct hdmi_pll_tuning imx8qm_pll_table[] = {
738 +/* bin VCO_freq min/max coar cod NDAC PMOS PTAT div-T P-Gain pad only */
739 + { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x08D, 0, 0, 0 },
740 + { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x08E, 0, 0, 0 },
741 + { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x08E, 0, 0, 0 },
742 + { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x08E, 0, 0, 0 },
743 + { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08F, 0, 0, 0 },
744 + { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x0A7, 0, 0, 0 },
745 + { 0, 1700000, 2000000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0C5, 0, 0, 0 },
746 + { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 300, 0x086, 0, 0, 0 },
747 + { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 320, 0x087, 0, 0, 0 },
748 + { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 325, 0x087, 0, 0, 0 },
749 + { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 330, 0x104, 0, 0, 0 },
750 + { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 340, 0x08B, 0, 0, 0 },
751 + { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 360, 0x08D, 0, 0, 0 },
752 + { 1, 2000000, 2400000, 0x3, 0x1, 0x0, 0x8C, 0x2E, 400, 0x0A6, 0, 0, 0 },
753 + { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x04E, 0, 0, 0 },
754 + { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04F, 0, 0, 0 },
755 + { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04F, 0, 0, 0 },
756 + { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x085, 0, 0, 0 },
757 + { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x085, 0, 0, 0 },
758 + { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x086, 0, 0, 0 },
759 + { 2, 2400000, 2800000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x08B, 0, 0, 0 },
760 + { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 300, 0x047, 0, 0, 0 },
761 + { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 320, 0x04B, 0, 0, 0 },
762 + { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 325, 0x04B, 0, 0, 0 },
763 + { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 330, 0x04B, 0, 0, 0 },
764 + { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 340, 0x04D, 0, 0, 0 },
765 + { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 360, 0x04E, 0, 0, 0 },
766 + { 3, 2800000, 3400000, 0x3, 0x1, 0x0, 0x04, 0x0D, 400, 0x085, 0, 0, 0 },
767 + { 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 375, 0x041, 0, 0, 0 },
768 + { 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x08D, 0, 0, 0 },
769 + { 4, 3400000, 3900000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A6, 0, 0, 0 },
770 + { 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 450, 0x041, 0, 0, 0 },
771 + { 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 600, 0x087, 0, 0, 0 },
772 + { 5, 3900000, 4500000, 0x7, 0x1, 0x0, 0x8E, 0x2F, 680, 0x0A4, 0, 0, 0 },
773 + { 6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04F, 0, 0, 0 },
774 + { 6, 4500000, 5200000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x086, 0, 0, 0 },
775 + { 7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 600, 0x04D, 0, 0, 0 },
776 + { 7, 5200000, 6000000, 0x7, 0x1, 0x0, 0x04, 0x0D, 680, 0x04F, 0, 0, 0 }
777 +};
778 +
779 +static void hdmi_phy_set_vswing(struct cdns_mhdp_device *mhdp)
780 +{
781 + const u32 num_lanes = 4;
782 + u32 k;
783 +
784 + for (k = 0; k < num_lanes; k++) {
785 + cdns_phy_reg_write(mhdp, (TX_DIAG_TX_DRV | (k << 9)), 0x7c0);
786 + cdns_phy_reg_write(mhdp, (TX_TXCC_CPOST_MULT_00_0 | (k << 9)), 0x0);
787 + cdns_phy_reg_write(mhdp, (TX_TXCC_CAL_SCLR_MULT_0 | (k << 9)), 0x120);
788 + }
789 +}
790 +
791 +static int hdmi_feedback_factor(struct cdns_mhdp_device *mhdp)
792 +{
793 + u32 feedback_factor;
794 +
795 + switch (mhdp->video_info.color_fmt) {
796 + case YCBCR_4_2_2:
797 + feedback_factor = 1000;
798 + break;
799 + case YCBCR_4_2_0:
800 + switch (mhdp->video_info.color_depth) {
801 + case 8:
802 + feedback_factor = 500;
803 + break;
804 + case 10:
805 + feedback_factor = 625;
806 + break;
807 + case 12:
808 + feedback_factor = 750;
809 + break;
810 + case 16:
811 + feedback_factor = 1000;
812 + break;
813 + default:
814 + DRM_ERROR("Invalid ColorDepth\n");
815 + return 0;
816 + }
817 + break;
818 + default:
819 + /* Assume RGB/YUV444 */
820 + switch (mhdp->video_info.color_depth) {
821 + case 10:
822 + feedback_factor = 1250;
823 + break;
824 + case 12:
825 + feedback_factor = 1500;
826 + break;
827 + case 16:
828 + feedback_factor = 2000;
829 + break;
830 + default:
831 + feedback_factor = 1000;
832 + }
833 + }
834 + return feedback_factor;
835 +}
836 +
837 +static int hdmi_phy_config(struct cdns_mhdp_device *mhdp,
838 + const struct hdmi_ctrl *p_ctrl_table,
839 + const struct hdmi_pll_tuning *p_pll_table,
840 + char pclk_in)
841 +{
842 + const u32 num_lanes = 4;
843 + u32 val, i, k;
844 +
845 + /* enable PHY isolation mode only for CMN */
846 + cdns_phy_reg_write(mhdp, PHY_PMA_ISOLATION_CTRL, 0xD000);
847 +
848 + /* set cmn_pll0_clk_datart1_div/cmn_pll0_clk_datart0_div dividers */
849 + val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_PLL_CTRL1);
850 + val &= 0xFF00;
851 + val |= 0x0012;
852 + cdns_phy_reg_write(mhdp, PHY_PMA_ISO_PLL_CTRL1, val);
853 +
854 + /* assert PHY reset from isolation register */
855 + cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0000);
856 + /* assert PMA CMN reset */
857 + cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0000);
858 +
859 + /* register XCVR_DIAG_BIDI_CTRL */
860 + for (k = 0; k < num_lanes; k++)
861 + cdns_phy_reg_write(mhdp, XCVR_DIAG_BIDI_CTRL | (k << 9), 0x00FF);
862 +
863 + /* Describing Task phy_cfg_hdp */
864 +
865 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
866 + val &= 0xFFF7;
867 + val |= 0x0008;
868 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
869 +
870 + /* PHY Registers */
871 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
872 + val &= 0xCFFF;
873 + val |= p_ctrl_table->cmn_ref_clk_dig_div << 12;
874 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
875 +
876 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
877 + val &= 0x00FF;
878 + val |= 0x1200;
879 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
880 +
881 + /* Common control module control and diagnostic registers */
882 + val = cdns_phy_reg_read(mhdp, CMN_CDIAG_REFCLK_CTRL);
883 + val &= 0x8FFF;
884 + val |= p_ctrl_table->ref_clk_divider_scaler << 12;
885 + val |= 0x00C0;
886 + cdns_phy_reg_write(mhdp, CMN_CDIAG_REFCLK_CTRL, val);
887 +
888 + /* High speed clock used */
889 + val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
890 + val &= 0xFF00;
891 + val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 0;
892 + val |= (p_ctrl_table->cmnda_hs_clk_1_sel >> 1) << 4;
893 + cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
894 +
895 + for (k = 0; k < num_lanes; k++) {
896 + val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
897 + val &= 0xCFFF;
898 + val |= (p_ctrl_table->cmnda_hs_clk_0_sel >> 1) << 12;
899 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
900 + }
901 +
902 + /* PLL 0 control state machine registers */
903 + val = p_ctrl_table->vco_ring_select << 12;
904 + cdns_phy_reg_write(mhdp, CMN_PLLSM0_USER_DEF_CTRL, val);
905 +
906 + if (pclk_in == true)
907 + val = 0x30A0;
908 + else {
909 + val = cdns_phy_reg_read(mhdp, CMN_PLL0_VCOCAL_START);
910 + val &= 0xFE00;
911 + val |= p_pll_table->vco_cal_code;
912 + }
913 + cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_START, val);
914 +
915 + cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_INIT_TMR, 0x0064);
916 + cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_ITER_TMR, 0x000A);
917 +
918 + /* Common functions control and diagnostics registers */
919 + val = p_ctrl_table->cmnda_pll0_hs_sym_div_sel << 8;
920 + val |= p_ctrl_table->cmnda_pll0_ip_div;
921 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_INCLK_CTRL, val);
922 +
923 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_OVRD, 0x0000);
924 +
925 + val = p_ctrl_table->cmnda_pll0_fb_div_high;
926 + val |= (1 << 15);
927 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBH_OVRD, val);
928 +
929 + val = p_ctrl_table->cmnda_pll0_fb_div_low;
930 + val |= (1 << 15);
931 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBL_OVRD, val);
932 +
933 + if (pclk_in == false) {
934 + val = p_ctrl_table->cmnda_pll0_pxdiv_low;
935 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVL, val);
936 +
937 + val = p_ctrl_table->cmnda_pll0_pxdiv_high;
938 + val |= (1 << 15);
939 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVH, val);
940 + }
941 +
942 + val = p_pll_table->volt_to_current_coarse;
943 + val |= (p_pll_table->volt_to_current) << 4;
944 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_V2I_TUNE, val);
945 +
946 + val = p_pll_table->charge_pump_gain;
947 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_CP_TUNE, val);
948 +
949 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_LF_PROG, 0x0008);
950 +
951 + val = p_pll_table->pmos_ctrl;
952 + val |= (p_pll_table->ndac_ctrl) << 8;
953 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE1, val);
954 +
955 + val = p_pll_table->ptat_ndac_ctrl;
956 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE2, val);
957 +
958 + if (pclk_in == true)
959 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0022);
960 + else
961 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0020);
962 + cdns_phy_reg_write(mhdp, CMN_PSM_CLK_CTRL, 0x0016);
963 +
964 + /* Transceiver control and diagnostic registers */
965 + for (k = 0; k < num_lanes; k++) {
966 + val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
967 + val &= 0xBFFF;
968 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
969 + }
970 +
971 + for (k = 0; k < num_lanes; k++) {
972 + val = cdns_phy_reg_read(mhdp, (TX_DIAG_TX_CTRL | (k << 9)));
973 + val &= 0xFF3F;
974 + val |= (p_ctrl_table->hsclk_div_tx_sub_rate >> 1) << 6;
975 + cdns_phy_reg_write(mhdp, (TX_DIAG_TX_CTRL | (k << 9)), val);
976 + }
977 +
978 + /*
979 + * for single ended reference clock val |= 0x0030;
980 + * for differential clock val |= 0x0000;
981 + */
982 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
983 + val &= 0xFF8F;
984 + if (pclk_in == true)
985 + val |= 0x0030;
986 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
987 +
988 + /* for differential clock on the refclk_p and
989 + * refclk_m off chip pins: CMN_DIAG_ACYA[8]=1'b1 */
990 + cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100);
991 +
992 + /* Deassert PHY reset */
993 + cdns_phy_reg_write(mhdp, PHY_ISO_CMN_CTRL, 0x0001);
994 + cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0003);
995 +
996 + /* Power state machine registers */
997 + for (k = 0; k < num_lanes; k++)
998 + cdns_phy_reg_write(mhdp, XCVR_PSM_RCTRL | (k << 9), 0xFEFC);
999 +
1000 + /* Assert cmn_macro_pwr_en */
1001 + cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0013);
1002 +
1003 + /* wait for cmn_macro_pwr_en_ack */
1004 + for (i = 0; i < 10; i++) {
1005 + val = cdns_phy_reg_read(mhdp, PHY_PMA_ISO_CMN_CTRL);
1006 + if (val & (1 << 5))
1007 + break;
1008 + msleep(20);
1009 + }
1010 + if (i == 10) {
1011 + DRM_ERROR("PMA ouput macro power up failed\n");
1012 + return false;
1013 + }
1014 +
1015 + /* wait for cmn_ready */
1016 + for (i = 0; i < 10; i++) {
1017 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
1018 + if (val & (1 << 0))
1019 + break;
1020 + msleep(20);
1021 + }
1022 + if (i == 10) {
1023 + DRM_ERROR("PMA output ready failed\n");
1024 + return false;
1025 + }
1026 +
1027 + for (k = 0; k < num_lanes; k++) {
1028 + cdns_phy_reg_write(mhdp, TX_PSC_A0 | (k << 9), 0x6791);
1029 + cdns_phy_reg_write(mhdp, TX_PSC_A1 | (k << 9), 0x6790);
1030 + cdns_phy_reg_write(mhdp, TX_PSC_A2 | (k << 9), 0x0090);
1031 + cdns_phy_reg_write(mhdp, TX_PSC_A3 | (k << 9), 0x0090);
1032 +
1033 + val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9));
1034 + val &= 0xFFBB;
1035 + cdns_phy_reg_write(mhdp, RX_PSC_CAL | (k << 9), val);
1036 +
1037 + val = cdns_phy_reg_read(mhdp, RX_PSC_A0 | (k << 9));
1038 + val &= 0xFFBB;
1039 + cdns_phy_reg_write(mhdp, RX_PSC_A0 | (k << 9), val);
1040 + }
1041 + return true;
1042 +}
1043 +
1044 +static int hdmi_phy_cfg_t28hpc(struct cdns_mhdp_device *mhdp,
1045 + struct drm_display_mode *mode)
1046 +{
1047 + const struct hdmi_ctrl *p_ctrl_table;
1048 + const struct hdmi_pll_tuning *p_pll_table;
1049 + const u32 refclk_freq_khz = 27000;
1050 + const u8 pclk_in = false;
1051 + u32 pixel_freq = mode->clock;
1052 + u32 vco_freq, char_freq;
1053 + u32 div_total, feedback_factor;
1054 + u32 i, ret;
1055 +
1056 + feedback_factor = hdmi_feedback_factor(mhdp);
1057 +
1058 + char_freq = pixel_freq * feedback_factor / 1000;
1059 +
1060 + DRM_INFO("Pixel clock: %d KHz, character clock: %d, bpc is %0d-bit.\n",
1061 + pixel_freq, char_freq, mhdp->video_info.color_depth);
1062 +
1063 + /* Get right row from the ctrl_table table.
1064 + * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ column.
1065 + * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
1066 + for (i = 0; i < ARRAY_SIZE(imx8mq_ctrl_table); i++) {
1067 + if (feedback_factor == imx8mq_ctrl_table[i].feedback_factor &&
1068 + pixel_freq == imx8mq_ctrl_table[i].pixel_clk_freq_min) {
1069 + p_ctrl_table = &imx8mq_ctrl_table[i];
1070 + break;
1071 + }
1072 + }
1073 + if (i == ARRAY_SIZE(imx8mq_ctrl_table)) {
1074 + DRM_WARN("Pixel clk (%d KHz) not supported, color depth (%0d-bit)\n",
1075 + pixel_freq, mhdp->video_info.color_depth);
1076 + return 0;
1077 + }
1078 +
1079 + div_total = p_ctrl_table->pll_fb_div_total;
1080 + vco_freq = refclk_freq_khz * div_total / p_ctrl_table->cmnda_pll0_ip_div;
1081 +
1082 + /* Get right row from the imx8mq_pll_table table.
1083 + * Check if vco_freq_khz and feedback_div_total
1084 + * column matching with imx8mq_pll_table. */
1085 + for (i = 0; i < ARRAY_SIZE(imx8mq_pll_table); i++) {
1086 + if (vco_freq == imx8mq_pll_table[i].vco_freq_min &&
1087 + div_total == imx8mq_pll_table[i].feedback_div_total) {
1088 + p_pll_table = &imx8mq_pll_table[i];
1089 + break;
1090 + }
1091 + }
1092 + if (i == ARRAY_SIZE(imx8mq_pll_table)) {
1093 + DRM_WARN("VCO (%d KHz) not supported\n", vco_freq);
1094 + return 0;
1095 + }
1096 + DRM_INFO("VCO frequency is %d KHz\n", vco_freq);
1097 +
1098 + ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in);
1099 + if (ret == false)
1100 + return 0;
1101 +
1102 + return char_freq;
1103 +}
1104 +
1105 +static int hdmi_phy_cfg_ss28fdsoi(struct cdns_mhdp_device *mhdp,
1106 + struct drm_display_mode *mode)
1107 +{
1108 + const struct hdmi_ctrl *p_ctrl_table;
1109 + const struct hdmi_pll_tuning *p_pll_table;
1110 + const u8 pclk_in = true;
1111 + u32 pixel_freq = mode->clock;
1112 + u32 vco_freq, char_freq;
1113 + u32 div_total, feedback_factor;
1114 + u32 ret, i;
1115 +
1116 + feedback_factor = hdmi_feedback_factor(mhdp);
1117 +
1118 + char_freq = pixel_freq * feedback_factor / 1000;
1119 +
1120 + DRM_INFO("Pixel clock: %d KHz, character clock: %d, bpc is %0d-bit.\n",
1121 + pixel_freq, char_freq, mhdp->video_info.color_depth);
1122 +
1123 + /* Get right row from the ctrl_table table.
1124 + * Check if 'pixel_freq_khz' value matches the PIXEL_CLK_FREQ column.
1125 + * Consider only the rows with FEEDBACK_FACTOR column matching feedback_factor. */
1126 + for (i = 0; i < ARRAY_SIZE(imx8qm_ctrl_table); i++) {
1127 + if (feedback_factor == imx8qm_ctrl_table[i].feedback_factor &&
1128 + pixel_freq >= imx8qm_ctrl_table[i].pixel_clk_freq_min &&
1129 + pixel_freq <= imx8qm_ctrl_table[i].pixel_clk_freq_max) {
1130 + p_ctrl_table = &imx8qm_ctrl_table[i];
1131 + break;
1132 + }
1133 + }
1134 + if (i == ARRAY_SIZE(imx8qm_ctrl_table)) {
1135 + DRM_WARN("Pixel clk (%d KHz) not supported, color depth (%0d-bit)\n",
1136 + pixel_freq, mhdp->video_info.color_depth);
1137 + return 0;
1138 + }
1139 +
1140 + div_total = p_ctrl_table->pll_fb_div_total;
1141 + vco_freq = pixel_freq * div_total / p_ctrl_table->cmnda_pll0_ip_div;
1142 +
1143 + /* Get right row from the imx8mq_pll_table table.
1144 + * Check if vco_freq_khz and feedback_div_total
1145 + * column matching with imx8mq_pll_table. */
1146 + for (i = 0; i < ARRAY_SIZE(imx8qm_pll_table); i++) {
1147 + if (vco_freq >= imx8qm_pll_table[i].vco_freq_min &&
1148 + vco_freq < imx8qm_pll_table[i].vco_freq_max &&
1149 + div_total == imx8qm_pll_table[i].feedback_div_total) {
1150 + p_pll_table = &imx8qm_pll_table[i];
1151 + break;
1152 + }
1153 + }
1154 + if (i == ARRAY_SIZE(imx8qm_pll_table)) {
1155 + DRM_WARN("VCO (%d KHz) not supported\n", vco_freq);
1156 + return 0;
1157 + }
1158 + DRM_INFO("VCO frequency is %d KHz\n", vco_freq);
1159 +
1160 + ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in);
1161 + if (ret == false)
1162 + return 0;
1163 +
1164 + return char_freq;
1165 +}
1166 +
1167 +static int hdmi_phy_power_up(struct cdns_mhdp_device *mhdp)
1168 +{
1169 + u32 val, i;
1170 +
1171 + /* set Power State to A2 */
1172 + cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004);
1173 +
1174 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_0, 1);
1175 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_1, 1);
1176 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_2, 1);
1177 + cdns_phy_reg_write(mhdp, TX_DIAG_ACYA_3, 1);
1178 +
1179 + /* Wait for Power State A2 Ack */
1180 + for (i = 0; i < 10; i++) {
1181 + val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
1182 + if (val & (1 << 6))
1183 + break;
1184 + msleep(20);
1185 + }
1186 + if (i == 10) {
1187 + dev_err(mhdp->dev, "Wait A2 Ack failed\n");
1188 + return -1;
1189 + }
1190 +
1191 + /* Configure PHY in A0 mode (PHY must be in the A0 power
1192 + * state in order to transmit data)
1193 + */
1194 + //cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101); //imx8mq
1195 + cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0001);
1196 +
1197 + /* Wait for Power State A0 Ack */
1198 + for (i = 0; i < 10; i++) {
1199 + val = cdns_phy_reg_read(mhdp, PHY_HDP_MODE_CTRL);
1200 + if (val & (1 << 4))
1201 + break;
1202 + msleep(20);
1203 + }
1204 + if (i == 10) {
1205 + dev_err(mhdp->dev, "Wait A0 Ack failed\n");
1206 + return -1;
1207 + }
1208 + return 0;
1209 +}
1210 +
1211 +int cdns_hdmi_phy_set_imx8mq(struct imx_mhdp_device *hdp)
1212 +{
1213 + struct cdns_mhdp_device *mhdp = &hdp->mhdp;
1214 + struct drm_display_mode *mode = &mhdp->mode;
1215 + int ret;
1216 +
1217 + /* Check HDMI FW alive before HDMI PHY init */
1218 + ret = cdns_mhdp_check_alive(mhdp);
1219 + if (ret == false) {
1220 + DRM_ERROR("NO HDMI FW running\n");
1221 + return -ENXIO;
1222 + }
1223 +
1224 + /* Configure PHY */
1225 + mhdp->hdmi.char_rate = hdmi_phy_cfg_t28hpc(mhdp, mode);
1226 + if (mhdp->hdmi.char_rate == 0) {
1227 + DRM_ERROR("failed to set phy pclock\n");
1228 + return -EINVAL;
1229 + }
1230 +
1231 + ret = hdmi_phy_power_up(mhdp);
1232 + if (ret < 0)
1233 + return ret;
1234 +
1235 + hdmi_phy_set_vswing(mhdp);
1236 +
1237 + return true;
1238 +}
1239 +
1240 +int cdns_hdmi_phy_set_imx8qm(struct imx_mhdp_device *hdp)
1241 +{
1242 + struct cdns_mhdp_device *mhdp = &hdp->mhdp;
1243 + struct drm_display_mode *mode = &mhdp->mode;
1244 + int ret;
1245 +
1246 + /* Check HDMI FW alive before HDMI PHY init */
1247 + ret = cdns_mhdp_check_alive(mhdp);
1248 + if (ret == false) {
1249 + DRM_ERROR("NO HDMI FW running\n");
1250 + return -ENXIO;
1251 + }
1252 +
1253 + /* Configure PHY */
1254 + mhdp->hdmi.char_rate = hdmi_phy_cfg_ss28fdsoi(mhdp, mode);
1255 + if (mhdp->hdmi.char_rate == 0) {
1256 + DRM_ERROR("failed to set phy pclock\n");
1257 + return -EINVAL;
1258 + }
1259 +
1260 + ret = hdmi_phy_power_up(mhdp);
1261 + if (ret < 0)
1262 + return ret;
1263 +
1264 + hdmi_phy_set_vswing(mhdp);
1265 +
1266 + return true;
1267 +}
1268 +
1269 --- /dev/null
1270 +++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c
1271 @@ -0,0 +1,163 @@
1272 +/*
1273 + * Copyright (C) 2019 NXP Semiconductor, Inc.
1274 + *
1275 + * This program is free software; you can redistribute it and/or modify
1276 + * it under the terms of the GNU General Public License version 2 as
1277 + * published by the Free Software Foundation.
1278 + */
1279 +#include <linux/module.h>
1280 +#include <linux/platform_device.h>
1281 +#include <linux/component.h>
1282 +#include <linux/mfd/syscon.h>
1283 +#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
1284 +#include <drm/drm_of.h>
1285 +#include <drm/drmP.h>
1286 +#include <drm/drm_crtc_helper.h>
1287 +#include <drm/drm_edid.h>
1288 +#include <drm/drm_encoder_slave.h>
1289 +
1290 +#include <drm/bridge/cdns-mhdp-imx.h>
1291 +#include "cdn-mhdp-phy.h"
1292 +#include "imx-drm.h"
1293 +
1294 +struct imx_hdmi {
1295 + struct device *dev;
1296 + struct drm_encoder encoder;
1297 +};
1298 +
1299 +static void cdns_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
1300 +{
1301 +}
1302 +
1303 +static void cdns_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
1304 +{
1305 +}
1306 +
1307 +static int cdns_hdmi_imx_atomic_check(struct drm_encoder *encoder,
1308 + struct drm_crtc_state *crtc_state,
1309 + struct drm_connector_state *conn_state)
1310 +{
1311 + return 0;
1312 +}
1313 +
1314 +static const struct drm_encoder_helper_funcs cdns_hdmi_imx_encoder_helper_funcs = {
1315 + .enable = cdns_hdmi_imx_encoder_enable,
1316 + .disable = cdns_hdmi_imx_encoder_disable,
1317 + .atomic_check = cdns_hdmi_imx_atomic_check,
1318 +};
1319 +
1320 +static const struct drm_encoder_funcs cdns_hdmi_imx_encoder_funcs = {
1321 + .destroy = drm_encoder_cleanup,
1322 +};
1323 +
1324 +static struct cdn_plat_data imx8mq_hdmi_drv_data = {
1325 + .bind = cdns_hdmi_bind,
1326 + .unbind = cdns_hdmi_unbind,
1327 + .phy_init = cdns_hdmi_phy_set_imx8mq,
1328 +};
1329 +
1330 +static struct cdn_plat_data imx8mq_dp_drv_data = {
1331 + .bind = cdns_dp_bind,
1332 + .unbind = cdns_dp_unbind,
1333 + .phy_init = cdns_dp_phy_init_imx8mq,
1334 +};
1335 +
1336 +static const struct of_device_id cdns_hdmi_imx_dt_ids[] = {
1337 + { .compatible = "cdn,imx8mq-hdmi",
1338 + .data = &imx8mq_hdmi_drv_data
1339 + },
1340 + { .compatible = "cdn,imx8mq-dp",
1341 + .data = &imx8mq_dp_drv_data
1342 + },
1343 + {},
1344 +};
1345 +MODULE_DEVICE_TABLE(of, cdns_hdmi_imx_dt_ids);
1346 +
1347 +static int cdns_hdmi_imx_bind(struct device *dev, struct device *master,
1348 + void *data)
1349 +{
1350 + struct platform_device *pdev = to_platform_device(dev);
1351 + const struct cdn_plat_data *plat_data;
1352 + const struct of_device_id *match;
1353 + struct drm_device *drm = data;
1354 + struct drm_encoder *encoder;
1355 + struct imx_hdmi *hdmi;
1356 + int ret;
1357 +
1358 + if (!pdev->dev.of_node)
1359 + return -ENODEV;
1360 +
1361 + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
1362 + if (!hdmi)
1363 + return -ENOMEM;
1364 +
1365 + match = of_match_node(cdns_hdmi_imx_dt_ids, pdev->dev.of_node);
1366 + plat_data = match->data;
1367 + hdmi->dev = &pdev->dev;
1368 + encoder = &hdmi->encoder;
1369 +
1370 + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
1371 + /*
1372 + * If we failed to find the CRTC(s) which this encoder is
1373 + * supposed to be connected to, it's because the CRTC has
1374 + * not been registered yet. Defer probing, and hope that
1375 + * the required CRTC is added later.
1376 + */
1377 + if (encoder->possible_crtcs == 0)
1378 + return -EPROBE_DEFER;
1379 +
1380 + drm_encoder_helper_add(encoder, &cdns_hdmi_imx_encoder_helper_funcs);
1381 + drm_encoder_init(drm, encoder, &cdns_hdmi_imx_encoder_funcs,
1382 + DRM_MODE_ENCODER_TMDS, NULL);
1383 +
1384 + ret = plat_data->bind(pdev, encoder, plat_data);
1385 +
1386 + /*
1387 + * If cdns_hdmi_bind() fails we'll never call cdns_hdmi_unbind(),
1388 + * which would have called the encoder cleanup. Do it manually.
1389 + */
1390 + if (ret)
1391 + drm_encoder_cleanup(encoder);
1392 +
1393 + return ret;
1394 +}
1395 +
1396 +static void cdns_hdmi_imx_unbind(struct device *dev, struct device *master,
1397 + void *data)
1398 +{
1399 + struct imx_mhdp_device *hdp = dev_get_drvdata(dev);
1400 +
1401 + hdp->plat_data->unbind(dev);
1402 +}
1403 +
1404 +static const struct component_ops cdns_hdmi_imx_ops = {
1405 + .bind = cdns_hdmi_imx_bind,
1406 + .unbind = cdns_hdmi_imx_unbind,
1407 +};
1408 +
1409 +static int cdns_hdmi_imx_probe(struct platform_device *pdev)
1410 +{
1411 + return component_add(&pdev->dev, &cdns_hdmi_imx_ops);
1412 +}
1413 +
1414 +static int cdns_hdmi_imx_remove(struct platform_device *pdev)
1415 +{
1416 + component_del(&pdev->dev, &cdns_hdmi_imx_ops);
1417 +
1418 + return 0;
1419 +}
1420 +
1421 +static struct platform_driver cdns_hdmi_imx_platform_driver = {
1422 + .probe = cdns_hdmi_imx_probe,
1423 + .remove = cdns_hdmi_imx_remove,
1424 + .driver = {
1425 + .name = "cdn-hdp-imx8mq",
1426 + .of_match_table = cdns_hdmi_imx_dt_ids,
1427 + },
1428 +};
1429 +
1430 +module_platform_driver(cdns_hdmi_imx_platform_driver);
1431 +
1432 +MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
1433 +MODULE_LICENSE("GPL");
1434 +MODULE_ALIAS("platform:cdnhdmi-imx");
1435 --- /dev/null
1436 +++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
1437 @@ -0,0 +1,714 @@
1438 +/*
1439 + * Copyright (C) 2019 NXP Semiconductor, Inc.
1440 + *
1441 + * This program is free software; you can redistribute it and/or modify
1442 + * it under the terms of the GNU General Public License version 2 as
1443 + * published by the Free Software Foundation.
1444 + */
1445 +#include <dt-bindings/firmware/imx/rsrc.h>
1446 +#include <linux/clk.h>
1447 +#include <linux/module.h>
1448 +#include <linux/platform_device.h>
1449 +#include <linux/component.h>
1450 +#include <drm/drm_of.h>
1451 +#include <drm/drmP.h>
1452 +#include <drm/drm_crtc_helper.h>
1453 +#include <drm/drm_encoder_slave.h>
1454 +#include <linux/firmware/imx/sci.h>
1455 +#include <linux/regmap.h>
1456 +#include <linux/pm_domain.h>
1457 +
1458 +#include <drm/bridge/cdns-mhdp-imx.h>
1459 +#include "cdn-mhdp-phy.h"
1460 +#include "imx-drm.h"
1461 +
1462 +#define CSR_PIXEL_LINK_MUX_CTL 0x00
1463 +#define PL_MUX_CTL_VCP_OFFSET 5
1464 +#define PL_MUX_CTL_HCP_OFFSET 4
1465 +
1466 +#define PLL_800MHZ (800000000)
1467 +
1468 +struct imx_hdmi {
1469 + struct device *dev;
1470 + struct drm_encoder encoder;
1471 +};
1472 +
1473 +static void imx8qm_pixel_link_mux(struct imx_mhdp_device *hdp)
1474 +{
1475 + struct drm_display_mode *mode = &hdp->mhdp.mode;
1476 + u32 val;
1477 +
1478 + val = 0x4; /* RGB */
1479 + if (hdp->dual_mode)
1480 + val |= 0x2; /* pixel link 0 and 1 are active */
1481 + if (mode->flags & DRM_MODE_FLAG_PVSYNC)
1482 + val |= 1 << PL_MUX_CTL_VCP_OFFSET;
1483 + if (mode->flags & DRM_MODE_FLAG_PHSYNC)
1484 + val |= 1 << PL_MUX_CTL_HCP_OFFSET;
1485 + if (mode->flags & DRM_MODE_FLAG_INTERLACE)
1486 + val |= 0x2;
1487 +
1488 + regmap_write(hdp->regmap_csr, hdp->csr_pxl_mux_reg, val);
1489 +}
1490 +
1491 +static void imx8qm_pixel_link_valid(u32 dual_mode)
1492 +{
1493 + struct imx_sc_ipc *handle;
1494 +
1495 + imx_scu_get_handle(&handle);
1496 +
1497 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 1);
1498 + if (dual_mode)
1499 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 1);
1500 +}
1501 +
1502 +static void imx8qm_pixel_link_invalid(u32 dual_mode)
1503 +{
1504 + struct imx_sc_ipc *handle;
1505 +
1506 + imx_scu_get_handle(&handle);
1507 +
1508 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 0);
1509 + if (dual_mode)
1510 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 0);
1511 +}
1512 +
1513 +static void imx8qm_pixel_link_sync_enable(u32 dual_mode)
1514 +{
1515 + struct imx_sc_ipc *handle;
1516 +
1517 + imx_scu_get_handle(&handle);
1518 +
1519 + if (dual_mode)
1520 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 3);
1521 + else
1522 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 1);
1523 +}
1524 +
1525 +static void imx8qm_pixel_link_sync_disable(u32 dual_mode)
1526 +{
1527 + struct imx_sc_ipc *handle;
1528 +
1529 + imx_scu_get_handle(&handle);
1530 +
1531 + if (dual_mode)
1532 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 0);
1533 + else
1534 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 0);
1535 +}
1536 +
1537 +static void imx8qm_phy_reset(u8 reset)
1538 +{
1539 + struct imx_sc_ipc *handle;
1540 +
1541 + imx_scu_get_handle(&handle);
1542 +
1543 + /* set the pixel link mode and pixel type */
1544 + imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_PHY_RESET, reset);
1545 +}
1546 +
1547 +static void imx8qm_clk_mux(u8 is_dp)
1548 +{
1549 + struct imx_sc_ipc *handle;
1550 +
1551 + imx_scu_get_handle(&handle);
1552 +
1553 + if (is_dp)
1554 + /* Enable the 24MHz for HDP PHY */
1555 + imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 1);
1556 + else
1557 + imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 0);
1558 +}
1559 +
1560 +int imx8qm_clocks_init(struct imx_mhdp_device *hdp)
1561 +{
1562 + struct device *dev = hdp->mhdp.dev;
1563 + struct imx_hdp_clks *clks = &hdp->clks;
1564 +
1565 + clks->dig_pll = devm_clk_get(dev, "dig_pll");
1566 + if (IS_ERR(clks->dig_pll)) {
1567 + dev_warn(dev, "failed to get dig pll clk\n");
1568 + return PTR_ERR(clks->dig_pll);
1569 + }
1570 +
1571 + clks->av_pll = devm_clk_get(dev, "av_pll");
1572 + if (IS_ERR(clks->av_pll)) {
1573 + dev_warn(dev, "failed to get av pll clk\n");
1574 + return PTR_ERR(clks->av_pll);
1575 + }
1576 +
1577 + clks->clk_ipg = devm_clk_get(dev, "clk_ipg");
1578 + if (IS_ERR(clks->clk_ipg)) {
1579 + dev_warn(dev, "failed to get dp ipg clk\n");
1580 + return PTR_ERR(clks->clk_ipg);
1581 + }
1582 +
1583 + clks->clk_core = devm_clk_get(dev, "clk_core");
1584 + if (IS_ERR(clks->clk_core)) {
1585 + dev_warn(dev, "failed to get hdp core clk\n");
1586 + return PTR_ERR(clks->clk_core);
1587 + }
1588 +
1589 + clks->clk_pxl = devm_clk_get(dev, "clk_pxl");
1590 + if (IS_ERR(clks->clk_pxl)) {
1591 + dev_warn(dev, "failed to get pxl clk\n");
1592 + return PTR_ERR(clks->clk_pxl);
1593 + }
1594 +
1595 + clks->clk_pxl_mux = devm_clk_get(dev, "clk_pxl_mux");
1596 + if (IS_ERR(clks->clk_pxl_mux)) {
1597 + dev_warn(dev, "failed to get pxl mux clk\n");
1598 + return PTR_ERR(clks->clk_pxl_mux);
1599 + }
1600 +
1601 + clks->clk_pxl_link = devm_clk_get(dev, "clk_pxl_link");
1602 + if (IS_ERR(clks->clk_pxl_mux)) {
1603 + dev_warn(dev, "failed to get pxl link clk\n");
1604 + return PTR_ERR(clks->clk_pxl_link);
1605 + }
1606 +
1607 + clks->lpcg_hdp = devm_clk_get(dev, "lpcg_hdp");
1608 + if (IS_ERR(clks->lpcg_hdp)) {
1609 + dev_warn(dev, "failed to get lpcg hdp clk\n");
1610 + return PTR_ERR(clks->lpcg_hdp);
1611 + }
1612 +
1613 + clks->lpcg_msi = devm_clk_get(dev, "lpcg_msi");
1614 + if (IS_ERR(clks->lpcg_msi)) {
1615 + dev_warn(dev, "failed to get lpcg msi clk\n");
1616 + return PTR_ERR(clks->lpcg_msi);
1617 + }
1618 +
1619 + clks->lpcg_pxl = devm_clk_get(dev, "lpcg_pxl");
1620 + if (IS_ERR(clks->lpcg_pxl)) {
1621 + dev_warn(dev, "failed to get lpcg pxl clk\n");
1622 + return PTR_ERR(clks->lpcg_pxl);
1623 + }
1624 +
1625 + clks->lpcg_vif = devm_clk_get(dev, "lpcg_vif");
1626 + if (IS_ERR(clks->lpcg_vif)) {
1627 + dev_warn(dev, "failed to get lpcg vif clk\n");
1628 + return PTR_ERR(clks->lpcg_vif);
1629 + }
1630 +
1631 + clks->lpcg_lis = devm_clk_get(dev, "lpcg_lis");
1632 + if (IS_ERR(clks->lpcg_lis)) {
1633 + dev_warn(dev, "failed to get lpcg lis clk\n");
1634 + return PTR_ERR(clks->lpcg_lis);
1635 + }
1636 +
1637 + clks->lpcg_apb = devm_clk_get(dev, "lpcg_apb");
1638 + if (IS_ERR(clks->lpcg_apb)) {
1639 + dev_warn(dev, "failed to get lpcg apb clk\n");
1640 + return PTR_ERR(clks->lpcg_apb);
1641 + }
1642 +
1643 + clks->lpcg_apb_csr = devm_clk_get(dev, "lpcg_apb_csr");
1644 + if (IS_ERR(clks->lpcg_apb_csr)) {
1645 + dev_warn(dev, "failed to get apb csr clk\n");
1646 + return PTR_ERR(clks->lpcg_apb_csr);
1647 + }
1648 +
1649 + clks->lpcg_apb_ctrl = devm_clk_get(dev, "lpcg_apb_ctrl");
1650 + if (IS_ERR(clks->lpcg_apb_ctrl)) {
1651 + dev_warn(dev, "failed to get lpcg apb ctrl clk\n");
1652 + return PTR_ERR(clks->lpcg_apb_ctrl);
1653 + }
1654 +
1655 + clks->clk_i2s_bypass = devm_clk_get(dev, "clk_i2s_bypass");
1656 + if (IS_ERR(clks->clk_i2s_bypass)) {
1657 + dev_err(dev, "failed to get i2s bypass clk\n");
1658 + return PTR_ERR(clks->clk_i2s_bypass);
1659 + }
1660 +
1661 + clks->lpcg_i2s = devm_clk_get(dev, "lpcg_i2s");
1662 + if (IS_ERR(clks->lpcg_i2s)) {
1663 + dev_err(dev, "failed to get lpcg i2s clk\n");
1664 + return PTR_ERR(clks->lpcg_i2s);
1665 + }
1666 + return true;
1667 +}
1668 +
1669 +static int imx8qm_pixel_clk_enable(struct imx_mhdp_device *hdp)
1670 +{
1671 + struct imx_hdp_clks *clks = &hdp->clks;
1672 + struct device *dev = hdp->mhdp.dev;
1673 + int ret;
1674 +
1675 + ret = clk_prepare_enable(clks->av_pll);
1676 + if (ret < 0) {
1677 + dev_err(dev, "%s, pre av pll error\n", __func__);
1678 + return ret;
1679 + }
1680 +
1681 + ret = clk_prepare_enable(clks->clk_pxl);
1682 + if (ret < 0) {
1683 + dev_err(dev, "%s, pre clk pxl error\n", __func__);
1684 + return ret;
1685 + }
1686 + ret = clk_prepare_enable(clks->clk_pxl_mux);
1687 + if (ret < 0) {
1688 + dev_err(dev, "%s, pre clk pxl mux error\n", __func__);
1689 + return ret;
1690 + }
1691 +
1692 + ret = clk_prepare_enable(clks->clk_pxl_link);
1693 + if (ret < 0) {
1694 + dev_err(dev, "%s, pre clk pxl link error\n", __func__);
1695 + return ret;
1696 + }
1697 + ret = clk_prepare_enable(clks->lpcg_vif);
1698 + if (ret < 0) {
1699 + dev_err(dev, "%s, pre clk vif error\n", __func__);
1700 + return ret;
1701 + }
1702 + ret = clk_prepare_enable(clks->lpcg_pxl);
1703 + if (ret < 0) {
1704 + dev_err(dev, "%s, pre lpcg pxl error\n", __func__);
1705 + return ret;
1706 + }
1707 + ret = clk_prepare_enable(clks->lpcg_hdp);
1708 + if (ret < 0) {
1709 + dev_err(dev, "%s, pre lpcg hdp error\n", __func__);
1710 + return ret;
1711 + }
1712 + return ret;
1713 +
1714 +}
1715 +
1716 +static void imx8qm_pixel_clk_disable(struct imx_mhdp_device *hdp)
1717 +{
1718 + struct imx_hdp_clks *clks = &hdp->clks;
1719 +
1720 + clk_disable_unprepare(clks->lpcg_pxl);
1721 + clk_disable_unprepare(clks->lpcg_hdp);
1722 + clk_disable_unprepare(clks->lpcg_vif);
1723 + clk_disable_unprepare(clks->clk_pxl);
1724 + clk_disable_unprepare(clks->clk_pxl_link);
1725 + clk_disable_unprepare(clks->clk_pxl_mux);
1726 + clk_disable_unprepare(clks->av_pll);
1727 +}
1728 +
1729 +static void imx8qm_pixel_clk_set_rate(struct imx_mhdp_device *hdp, u32 pclock)
1730 +{
1731 + struct imx_hdp_clks *clks = &hdp->clks;
1732 +
1733 + /* pixel clock for HDMI */
1734 + clk_set_rate(clks->av_pll, pclock);
1735 +
1736 + if (hdp->dual_mode == true) {
1737 + clk_set_rate(clks->clk_pxl, pclock/2);
1738 + clk_set_rate(clks->clk_pxl_link, pclock/2);
1739 + } else {
1740 + clk_set_rate(clks->clk_pxl_link, pclock);
1741 + clk_set_rate(clks->clk_pxl, pclock);
1742 + }
1743 + clk_set_rate(clks->clk_pxl_mux, pclock);
1744 +}
1745 +
1746 +static void imx8qm_pixel_clk_rate_change(struct imx_mhdp_device *hdp)
1747 +{
1748 + /* set pixel clock before video mode setup */
1749 + imx8qm_pixel_clk_disable(hdp);
1750 +
1751 + imx8qm_pixel_clk_set_rate(hdp, hdp->mhdp.mode.clock * 1000);
1752 +
1753 + imx8qm_pixel_clk_enable(hdp);
1754 +
1755 + /* Config pixel link mux */
1756 + imx8qm_pixel_link_mux(hdp);
1757 +}
1758 +
1759 +static int imx8qm_ipg_clk_enable(struct imx_mhdp_device *hdp)
1760 +{
1761 + int ret;
1762 + struct imx_hdp_clks *clks = &hdp->clks;
1763 + struct device *dev = hdp->mhdp.dev;
1764 +
1765 + ret = clk_prepare_enable(clks->dig_pll);
1766 + if (ret < 0) {
1767 + dev_err(dev, "%s, pre dig pll error\n", __func__);
1768 + return ret;
1769 + }
1770 +
1771 + ret = clk_prepare_enable(clks->clk_ipg);
1772 + if (ret < 0) {
1773 + dev_err(dev, "%s, pre clk_ipg error\n", __func__);
1774 + return ret;
1775 + }
1776 +
1777 + ret = clk_prepare_enable(clks->clk_core);
1778 + if (ret < 0) {
1779 + dev_err(dev, "%s, pre clk core error\n", __func__);
1780 + return ret;
1781 + }
1782 +
1783 + ret = clk_prepare_enable(clks->lpcg_apb);
1784 + if (ret < 0) {
1785 + dev_err(dev, "%s, pre clk apb error\n", __func__);
1786 + return ret;
1787 + }
1788 + ret = clk_prepare_enable(clks->lpcg_lis);
1789 + if (ret < 0) {
1790 + dev_err(dev, "%s, pre clk lis error\n", __func__);
1791 + return ret;
1792 + }
1793 + ret = clk_prepare_enable(clks->lpcg_msi);
1794 + if (ret < 0) {
1795 + dev_err(dev, "%s, pre clk msierror\n", __func__);
1796 + return ret;
1797 + }
1798 + ret = clk_prepare_enable(clks->lpcg_apb_csr);
1799 + if (ret < 0) {
1800 + dev_err(dev, "%s, pre clk apb csr error\n", __func__);
1801 + return ret;
1802 + }
1803 + ret = clk_prepare_enable(clks->lpcg_apb_ctrl);
1804 + if (ret < 0) {
1805 + dev_err(dev, "%s, pre clk apb ctrl error\n", __func__);
1806 + return ret;
1807 + }
1808 + ret = clk_prepare_enable(clks->lpcg_i2s);
1809 + if (ret < 0) {
1810 + dev_err(dev, "%s, pre clk i2s error\n", __func__);
1811 + return ret;
1812 + }
1813 + ret = clk_prepare_enable(clks->clk_i2s_bypass);
1814 + if (ret < 0) {
1815 + dev_err(dev, "%s, pre clk i2s bypass error\n", __func__);
1816 + return ret;
1817 + }
1818 + return ret;
1819 +}
1820 +
1821 +static void imx8qm_ipg_clk_disable(struct imx_mhdp_device *hdp)
1822 +{
1823 + struct imx_hdp_clks *clks = &hdp->clks;
1824 +
1825 + clk_disable_unprepare(clks->clk_i2s_bypass);
1826 + clk_disable_unprepare(clks->lpcg_i2s);
1827 + clk_disable_unprepare(clks->lpcg_apb_ctrl);
1828 + clk_disable_unprepare(clks->lpcg_apb_csr);
1829 + clk_disable_unprepare(clks->lpcg_msi);
1830 + clk_disable_unprepare(clks->lpcg_lis);
1831 + clk_disable_unprepare(clks->lpcg_apb);
1832 + clk_disable_unprepare(clks->clk_core);
1833 + clk_disable_unprepare(clks->clk_ipg);
1834 + clk_disable_unprepare(clks->dig_pll);
1835 +}
1836 +
1837 +static void imx8qm_ipg_clk_set_rate(struct imx_mhdp_device *hdp)
1838 +{
1839 + struct imx_hdp_clks *clks = &hdp->clks;
1840 +
1841 + /* ipg/core clock */
1842 + clk_set_rate(clks->dig_pll, PLL_800MHZ);
1843 + clk_set_rate(clks->clk_core, PLL_800MHZ/4);
1844 + clk_set_rate(clks->clk_ipg, PLL_800MHZ/8);
1845 +}
1846 +
1847 +static void imx8qm_detach_pm_domains(struct imx_mhdp_device *hdp)
1848 +{
1849 + if (hdp->pd_pll1_link && !IS_ERR(hdp->pd_pll1_link))
1850 + device_link_del(hdp->pd_pll1_link);
1851 + if (hdp->pd_pll1_dev && !IS_ERR(hdp->pd_pll1_dev))
1852 + dev_pm_domain_detach(hdp->pd_pll1_dev, true);
1853 +
1854 + if (hdp->pd_pll0_link && !IS_ERR(hdp->pd_pll0_link))
1855 + device_link_del(hdp->pd_pll0_link);
1856 + if (hdp->pd_pll0_dev && !IS_ERR(hdp->pd_pll0_dev))
1857 + dev_pm_domain_detach(hdp->pd_pll0_dev, true);
1858 +
1859 + if (hdp->pd_mhdp_link && !IS_ERR(hdp->pd_mhdp_link))
1860 + device_link_del(hdp->pd_mhdp_link);
1861 + if (hdp->pd_mhdp_dev && !IS_ERR(hdp->pd_mhdp_dev))
1862 + dev_pm_domain_detach(hdp->pd_mhdp_dev, true);
1863 +
1864 + hdp->pd_mhdp_dev = NULL;
1865 + hdp->pd_mhdp_link = NULL;
1866 + hdp->pd_pll0_dev = NULL;
1867 + hdp->pd_pll0_link = NULL;
1868 + hdp->pd_pll1_dev = NULL;
1869 + hdp->pd_pll1_link = NULL;
1870 +}
1871 +
1872 +static int imx8qm_attach_pm_domains(struct imx_mhdp_device *hdp)
1873 +{
1874 + struct device *dev = hdp->mhdp.dev;
1875 + u32 flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE;
1876 + int ret = 0;
1877 +
1878 + hdp->pd_mhdp_dev = dev_pm_domain_attach_by_name(dev, "hdmi");
1879 + if (IS_ERR(hdp->pd_mhdp_dev)) {
1880 + ret = PTR_ERR(hdp->pd_mhdp_dev);
1881 + dev_err(dev, "Failed to attach dc pd dev: %d\n", ret);
1882 + goto fail;
1883 + }
1884 + hdp->pd_mhdp_link = device_link_add(dev, hdp->pd_mhdp_dev, flags);
1885 + if (IS_ERR(hdp->pd_mhdp_link)) {
1886 + ret = PTR_ERR(hdp->pd_mhdp_link);
1887 + dev_err(dev, "Failed to add device link to dc pd dev: %d\n",
1888 + ret);
1889 + goto fail;
1890 + }
1891 +
1892 + hdp->pd_pll0_dev = dev_pm_domain_attach_by_name(dev, "pll0");
1893 + if (IS_ERR(hdp->pd_pll0_dev)) {
1894 + ret = PTR_ERR(hdp->pd_pll0_dev);
1895 + dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
1896 + goto fail;
1897 + }
1898 + hdp->pd_pll0_link = device_link_add(dev, hdp->pd_pll0_dev, flags);
1899 + if (IS_ERR(hdp->pd_pll0_link)) {
1900 + ret = PTR_ERR(hdp->pd_pll0_link);
1901 + dev_err(dev, "Failed to add device link to pll0 pd dev: %d\n",
1902 + ret);
1903 + goto fail;
1904 + }
1905 +
1906 + hdp->pd_pll1_dev = dev_pm_domain_attach_by_name(dev, "pll1");
1907 + if (IS_ERR(hdp->pd_pll1_dev)) {
1908 + ret = PTR_ERR(hdp->pd_pll1_dev);
1909 + dev_err(dev, "Failed to attach pll0 pd dev: %d\n", ret);
1910 + goto fail;
1911 + }
1912 + hdp->pd_pll1_link = device_link_add(dev, hdp->pd_pll1_dev, flags);
1913 + if (IS_ERR(hdp->pd_pll1_link)) {
1914 + ret = PTR_ERR(hdp->pd_pll1_link);
1915 + dev_err(dev, "Failed to add device link to pll1 pd dev: %d\n",
1916 + ret);
1917 + goto fail;
1918 + }
1919 +fail:
1920 + imx8qm_detach_pm_domains(hdp);
1921 + return ret;
1922 +}
1923 +
1924 +static int imx8qm_firmware_init(struct imx_mhdp_device *hdp)
1925 +{
1926 + u32 rate;
1927 + int ret;
1928 +
1929 + /* Power on PM Domains */
1930 + imx8qm_attach_pm_domains(hdp);
1931 +
1932 + /* clock init and rate set */
1933 + imx8qm_clocks_init(hdp);
1934 +
1935 + imx8qm_ipg_clk_set_rate(hdp);
1936 +
1937 + /* Init pixel clock with 148.5MHz before FW init */
1938 + imx8qm_pixel_clk_set_rate(hdp, 148500000);
1939 +
1940 + imx8qm_ipg_clk_enable(hdp);
1941 +
1942 + imx8qm_clk_mux(hdp->plat_data->is_dp);
1943 +
1944 + imx8qm_pixel_clk_enable(hdp);
1945 +
1946 + imx8qm_phy_reset(1);
1947 +
1948 + hdp->csr_pxl_mux_reg = 0;
1949 + hdp->csr_ctrl0_reg = 0x8;
1950 + hdp->csr_ctrl0_sec = 0xc;
1951 + /* iMX8QM HDP register, Remap HPD memory address to low 4K */
1952 + regmap_write(hdp->regmap_csr, hdp->csr_ctrl0_reg, 0);
1953 +
1954 + /* configure HDMI/DP core clock */
1955 + rate = clk_get_rate(hdp->clks.clk_core);
1956 + cdns_mhdp_set_fw_clk(&hdp->mhdp, rate);
1957 +
1958 + /* un-reset ucpu */
1959 + writel(0, (APB_CTRL << 2) + hdp->mhdp.regs);
1960 + DRM_INFO("Started firmware!\n");
1961 +
1962 + ret = cdns_mhdp_check_alive(&hdp->mhdp);
1963 + if (ret == false) {
1964 + DRM_ERROR("NO HDMI FW running\n");
1965 + return -ENXIO;
1966 + }
1967 +
1968 + /* turn on IP activity */
1969 + cdns_mhdp_set_firmware_active(&hdp->mhdp, 1);
1970 +
1971 + DRM_INFO("HDP FW Version - ver %d verlib %d\n",
1972 + __raw_readb(VER_L + hdp->mhdp.regs) + (__raw_readb(VER_H + hdp->mhdp.regs) << 8),
1973 + __raw_readb(VER_LIB_L_ADDR + hdp->mhdp.regs) + (__raw_readb(VER_LIB_H_ADDR + hdp->mhdp.regs) << 8));
1974 +
1975 + return 0;
1976 +}
1977 +
1978 +static void cdns_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
1979 +{
1980 + struct imx_mhdp_device *hdp = encoder->bridge->driver_private;
1981 +
1982 + imx8qm_pixel_link_sync_disable(hdp->dual_mode);
1983 + imx8qm_pixel_link_invalid(hdp->dual_mode);
1984 +}
1985 +
1986 +static void cdns_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
1987 +{
1988 + struct imx_mhdp_device *hdp = encoder->bridge->driver_private;
1989 +
1990 + imx8qm_pixel_link_valid(hdp->dual_mode);
1991 + imx8qm_pixel_link_sync_enable(hdp->dual_mode);
1992 +}
1993 +
1994 +static int cdns_hdmi_imx_encoder_atomic_check(struct drm_encoder *encoder,
1995 + struct drm_crtc_state *crtc_state,
1996 + struct drm_connector_state *conn_state)
1997 +{
1998 + struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
1999 +
2000 + imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
2001 + return 0;
2002 +}
2003 +
2004 +static const struct drm_encoder_helper_funcs cdns_hdmi_imx_encoder_helper_funcs = {
2005 + .enable = cdns_hdmi_imx_encoder_enable,
2006 + .disable = cdns_hdmi_imx_encoder_disable,
2007 + .atomic_check = cdns_hdmi_imx_encoder_atomic_check,
2008 +};
2009 +
2010 +static const struct drm_encoder_funcs cdns_hdmi_imx_encoder_funcs = {
2011 + .destroy = drm_encoder_cleanup,
2012 +};
2013 +
2014 +#if 0
2015 +static struct cdn_plat_data imx8mq_hdmi_drv_data = {
2016 + .bind = cdns_hdmi_bind,
2017 + .unbind = cdns_hdmi_unbind,
2018 + .phy_init = cdns_hdmi_phy_set_imx8mq,
2019 +};
2020 +
2021 +static struct cdn_plat_data imx8mq_dp_drv_data = {
2022 + .bind = cdns_dp_bind,
2023 + .unbind = cdns_dp_unbind,
2024 + .phy_init = cdns_dp_phy_init_imx8mq,
2025 +};
2026 +#endif
2027 +
2028 +static struct cdn_plat_data imx8qm_hdmi_drv_data = {
2029 + .bind = cdns_hdmi_bind,
2030 + .unbind = cdns_hdmi_unbind,
2031 + .phy_init = cdns_hdmi_phy_set_imx8qm,
2032 + .fw_init = imx8qm_firmware_init,
2033 + .pclock_change = imx8qm_pixel_clk_rate_change,
2034 +};
2035 +
2036 +static struct cdn_plat_data imx8qm_dp_drv_data = {
2037 + .bind = cdns_dp_bind,
2038 + .unbind = cdns_dp_unbind,
2039 + .phy_init = cdns_dp_phy_init_imx8qm,
2040 + .fw_init = imx8qm_firmware_init,
2041 + .pclock_change = imx8qm_pixel_clk_rate_change,
2042 + .is_dp = true,
2043 +};
2044 +
2045 +static const struct of_device_id cdns_hdmi_imx_dt_ids[] = {
2046 +#if 0
2047 + { .compatible = "cdn,imx8mq-hdmi",
2048 + .data = &imx8mq_hdmi_drv_data
2049 + },
2050 + { .compatible = "cdn,imx8mq-dp",
2051 + .data = &imx8mq_dp_drv_data
2052 + },
2053 +#endif
2054 + { .compatible = "cdn,imx8qm-hdmi",
2055 + .data = &imx8qm_hdmi_drv_data
2056 + },
2057 + { .compatible = "cdn,imx8qm-dp",
2058 + .data = &imx8qm_dp_drv_data
2059 + },
2060 + {},
2061 +};
2062 +MODULE_DEVICE_TABLE(of, cdns_hdmi_imx_dt_ids);
2063 +
2064 +static int cdns_hdmi_imx_bind(struct device *dev, struct device *master,
2065 + void *data)
2066 +{
2067 + struct platform_device *pdev = to_platform_device(dev);
2068 + const struct cdn_plat_data *plat_data;
2069 + const struct of_device_id *match;
2070 + struct drm_device *drm = data;
2071 + struct drm_encoder *encoder;
2072 + struct imx_hdmi *hdmi;
2073 + int ret;
2074 +
2075 + if (!pdev->dev.of_node)
2076 + return -ENODEV;
2077 +
2078 + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
2079 + if (!hdmi)
2080 + return -ENOMEM;
2081 +
2082 + match = of_match_node(cdns_hdmi_imx_dt_ids, pdev->dev.of_node);
2083 + plat_data = match->data;
2084 + hdmi->dev = &pdev->dev;
2085 + encoder = &hdmi->encoder;
2086 +
2087 + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
2088 + /*
2089 + * If we failed to find the CRTC(s) which this encoder is
2090 + * supposed to be connected to, it's because the CRTC has
2091 + * not been registered yet. Defer probing, and hope that
2092 + * the required CRTC is added later.
2093 + */
2094 + if (encoder->possible_crtcs == 0)
2095 + return -EPROBE_DEFER;
2096 +
2097 + drm_encoder_helper_add(encoder, &cdns_hdmi_imx_encoder_helper_funcs);
2098 + drm_encoder_init(drm, encoder, &cdns_hdmi_imx_encoder_funcs,
2099 + DRM_MODE_ENCODER_TMDS, NULL);
2100 +
2101 + ret = plat_data->bind(pdev, encoder, plat_data);
2102 +
2103 + /*
2104 + * If cdns_hdmi_bind() fails we'll never call cdns_hdmi_unbind(),
2105 + * which would have called the encoder cleanup. Do it manually.
2106 + */
2107 + if (ret)
2108 + drm_encoder_cleanup(encoder);
2109 +
2110 + return ret;
2111 +}
2112 +
2113 +static void cdns_hdmi_imx_unbind(struct device *dev, struct device *master,
2114 + void *data)
2115 +{
2116 + struct imx_mhdp_device *hdp = dev_get_drvdata(dev);
2117 +
2118 + hdp->plat_data->unbind(dev);
2119 +}
2120 +
2121 +static const struct component_ops cdns_hdmi_imx8qm_ops = {
2122 + .bind = cdns_hdmi_imx_bind,
2123 + .unbind = cdns_hdmi_imx_unbind,
2124 +};
2125 +
2126 +static int cdns_hdmi_imx_probe(struct platform_device *pdev)
2127 +{
2128 + return component_add(&pdev->dev, &cdns_hdmi_imx8qm_ops);
2129 +}
2130 +
2131 +static int cdns_hdmi_imx_remove(struct platform_device *pdev)
2132 +{
2133 + component_del(&pdev->dev, &cdns_hdmi_imx8qm_ops);
2134 +
2135 + return 0;
2136 +}
2137 +
2138 +static struct platform_driver cdns_hdmi_imx_platform_driver = {
2139 + .probe = cdns_hdmi_imx_probe,
2140 + .remove = cdns_hdmi_imx_remove,
2141 + .driver = {
2142 + .name = "cdn-hdp-imx8qm",
2143 + .of_match_table = cdns_hdmi_imx_dt_ids,
2144 + },
2145 +};
2146 +
2147 +module_platform_driver(cdns_hdmi_imx_platform_driver);
2148 +
2149 +MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
2150 +MODULE_LICENSE("GPL");
2151 +MODULE_ALIAS("platform:cdnhdmi-imx");
2152 --- /dev/null
2153 +++ b/drivers/gpu/drm/imx/cdn-mhdp-phy.h
2154 @@ -0,0 +1,153 @@
2155 +/*
2156 + * Copyright (C) 2019 NXP Semiconductor, Inc.
2157 + *
2158 + * This program is free software; you can redistribute it and/or modify
2159 + * it under the terms of the GNU General Public License as published by
2160 + * the Free Software Foundation; either version 2 of the License, or
2161 + * (at your option) any later version.
2162 + */
2163 +
2164 +#ifndef _CDN_DP_PHY_H
2165 +#define _CDN_DP_PHY_H
2166 +
2167 +#include <drm/bridge/cdns-mhdp-imx.h>
2168 +
2169 +#define CMN_SSM_BIAS_TMR 0x0022
2170 +#define CMN_PLLSM0_PLLEN_TMR 0x0029
2171 +#define CMN_PLLSM0_PLLPRE_TMR 0x002A
2172 +#define CMN_PLLSM0_PLLVREF_TMR 0x002B
2173 +#define CMN_PLLSM0_PLLLOCK_TMR 0x002C
2174 +#define CMN_PLLSM0_USER_DEF_CTRL 0x002F
2175 +#define CMN_PSM_CLK_CTRL 0x0061
2176 +#define CMN_CDIAG_REFCLK_CTRL 0x0062
2177 +#define CMN_PLL0_VCOCAL_START 0x0081
2178 +#define CMN_PLL0_VCOCAL_INIT_TMR 0x0084
2179 +#define CMN_PLL0_VCOCAL_ITER_TMR 0x0085
2180 +#define CMN_PLL0_INTDIV 0x0094
2181 +#define CMN_PLL0_FRACDIV 0x0095
2182 +#define CMN_PLL0_HIGH_THR 0x0096
2183 +#define CMN_PLL0_DSM_DIAG 0x0097
2184 +#define CMN_PLL0_SS_CTRL1 0x0098
2185 +#define CMN_PLL0_SS_CTRL2 0x0099
2186 +#define CMN_ICAL_INIT_TMR 0x00C4
2187 +#define CMN_ICAL_ITER_TMR 0x00C5
2188 +#define CMN_RXCAL_INIT_TMR 0x00D4
2189 +#define CMN_RXCAL_ITER_TMR 0x00D5
2190 +#define CMN_TXPUCAL_CTRL 0x00E0
2191 +#define CMN_TXPUCAL_INIT_TMR 0x00E4
2192 +#define CMN_TXPUCAL_ITER_TMR 0x00E5
2193 +#define CMN_TXPDCAL_CTRL 0x00F0
2194 +#define CMN_TXPDCAL_INIT_TMR 0x00F4
2195 +#define CMN_TXPDCAL_ITER_TMR 0x00F5
2196 +#define CMN_ICAL_ADJ_INIT_TMR 0x0102
2197 +#define CMN_ICAL_ADJ_ITER_TMR 0x0103
2198 +#define CMN_RX_ADJ_INIT_TMR 0x0106
2199 +#define CMN_RX_ADJ_ITER_TMR 0x0107
2200 +#define CMN_TXPU_ADJ_CTRL 0x0108
2201 +#define CMN_TXPU_ADJ_INIT_TMR 0x010A
2202 +#define CMN_TXPU_ADJ_ITER_TMR 0x010B
2203 +#define CMN_TXPD_ADJ_CTRL 0x010c
2204 +#define CMN_TXPD_ADJ_INIT_TMR 0x010E
2205 +#define CMN_TXPD_ADJ_ITER_TMR 0x010F
2206 +#define CMN_DIAG_PLL0_FBH_OVRD 0x01C0
2207 +#define CMN_DIAG_PLL0_FBL_OVRD 0x01C1
2208 +#define CMN_DIAG_PLL0_OVRD 0x01C2
2209 +#define CMN_DIAG_PLL0_TEST_MODE 0x01C4
2210 +#define CMN_DIAG_PLL0_V2I_TUNE 0x01C5
2211 +#define CMN_DIAG_PLL0_CP_TUNE 0x01C6
2212 +#define CMN_DIAG_PLL0_LF_PROG 0x01C7
2213 +#define CMN_DIAG_PLL0_PTATIS_TUNE1 0x01C8
2214 +#define CMN_DIAG_PLL0_PTATIS_TUNE2 0x01C9
2215 +#define CMN_DIAG_PLL0_INCLK_CTRL 0x01CA
2216 +#define CMN_DIAG_PLL0_PXL_DIVH 0x01CB
2217 +#define CMN_DIAG_PLL0_PXL_DIVL 0x01CC
2218 +#define CMN_DIAG_HSCLK_SEL 0x01E0
2219 +#define CMN_DIAG_PER_CAL_ADJ 0x01EC
2220 +#define CMN_DIAG_CAL_CTRL 0x01ED
2221 +#define CMN_DIAG_ACYA 0x01FF
2222 +#define XCVR_PSM_RCTRL 0x4001
2223 +#define XCVR_PSM_CAL_TMR 0x4002
2224 +#define XCVR_PSM_A0IN_TMR 0x4003
2225 +#define TX_TXCC_CAL_SCLR_MULT_0 0x4047
2226 +#define TX_TXCC_CPOST_MULT_00_0 0x404C
2227 +#define TX_TXCC_MGNFS_MULT_000_0 0x4050
2228 +#define XCVR_DIAG_PLLDRC_CTRL 0x40E0
2229 +#define XCVR_DIAG_PLLDRC_CTRL 0x40E0
2230 +#define XCVR_DIAG_HSCLK_SEL 0x40E1
2231 +#define XCVR_DIAG_BIDI_CTRL 0x40E8
2232 +#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR 0x40F2
2233 +#define XCVR_DIAG_LANE_FCM_EN_MGN 0x40F2
2234 +#define TX_PSC_A0 0x4100
2235 +#define TX_PSC_A1 0x4101
2236 +#define TX_PSC_A2 0x4102
2237 +#define TX_PSC_A3 0x4103
2238 +#define TX_RCVDET_CTRL 0x4120
2239 +#define TX_RCVDET_EN_TMR 0x4122
2240 +#define TX_RCVDET_EN_TMR 0x4122
2241 +#define TX_RCVDET_ST_TMR 0x4123
2242 +#define TX_RCVDET_ST_TMR 0x4123
2243 +#define TX_BIST_CTRL 0x4140
2244 +#define TX_BIST_UDDWR 0x4141
2245 +#define TX_DIAG_TX_CTRL 0x41E0
2246 +#define TX_DIAG_TX_DRV 0x41E1
2247 +#define TX_DIAG_BGREF_PREDRV_DELAY 0x41E7
2248 +#define TX_DIAG_BGREF_PREDRV_DELAY 0x41E7
2249 +#define XCVR_PSM_RCTRL_1 0x4201
2250 +#define TX_TXCC_CAL_SCLR_MULT_1 0x4247
2251 +#define TX_TXCC_CPOST_MULT_00_1 0x424C
2252 +#define TX_TXCC_MGNFS_MULT_000_1 0x4250
2253 +#define XCVR_DIAG_PLLDRC_CTRL_1 0x42E0
2254 +#define XCVR_DIAG_HSCLK_SEL_1 0x42E1
2255 +#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR_1 0x42F2
2256 +#define TX_RCVDET_EN_TMR_1 0x4322
2257 +#define TX_RCVDET_ST_TMR_1 0x4323
2258 +#define TX_DIAG_ACYA_0 0x41FF
2259 +#define TX_DIAG_ACYA_1 0x43FF
2260 +#define TX_DIAG_ACYA_2 0x45FF
2261 +#define TX_DIAG_ACYA_3 0x47FF
2262 +#define TX_ANA_CTRL_REG_1 0x5020
2263 +#define TX_ANA_CTRL_REG_2 0x5021
2264 +#define TXDA_COEFF_CALC 0x5022
2265 +#define TX_DIG_CTRL_REG_1 0x5023
2266 +#define TX_DIG_CTRL_REG_2 0x5024
2267 +#define TXDA_CYA_AUXDA_CYA 0x5025
2268 +#define TX_ANA_CTRL_REG_3 0x5026
2269 +#define TX_ANA_CTRL_REG_4 0x5027
2270 +#define TX_ANA_CTRL_REG_5 0x5029
2271 +#define RX_PSC_A0 0x8000
2272 +#define RX_PSC_CAL 0x8006
2273 +#define PMA_LANE_CFG 0xC000
2274 +#define PIPE_CMN_CTRL1 0xC001
2275 +#define PIPE_CMN_CTRL2 0xC002
2276 +#define PIPE_COM_LOCK_CFG1 0xC003
2277 +#define PIPE_COM_LOCK_CFG2 0xC004
2278 +#define PIPE_RCV_DET_INH 0xC005
2279 +#define PHY_HDP_MODE_CTRL 0xC008
2280 +#define PHY_HDP_CLK_CTL 0xC009
2281 +#define STS 0xC00F
2282 +#define PHY_ISO_CMN_CTRL 0xC010
2283 +#define PHY_ISO_CMN_CTRL 0xC010
2284 +#define PHY_HDP_TX_CTL_L0 0xC408
2285 +#define PHY_DP_TX_CTL 0xC408
2286 +#define PHY_HDP_TX_CTL_L1 0xC448
2287 +#define PHY_HDP_TX_CTL_L2 0xC488
2288 +#define PHY_HDP_TX_CTL_L3 0xC4C8
2289 +#define PHY_PMA_CMN_CTRL1 0xC800
2290 +#define PMA_CMN_CTRL1 0xC800
2291 +#define PHY_PMA_ISO_CMN_CTRL 0xC810
2292 +#define PHY_PMA_ISO_PLL_CTRL1 0xC812
2293 +#define PHY_PMA_ISOLATION_CTRL 0xC81F
2294 +#define PHY_ISOLATION_CTRL 0xC81F
2295 +#define PHY_PMA_ISO_XCVR_CTRL 0xCC11
2296 +#define PHY_PMA_ISO_LINK_MODE 0xCC12
2297 +#define PHY_PMA_ISO_PWRST_CTRL 0xCC13
2298 +#define PHY_PMA_ISO_TX_DATA_LO 0xCC14
2299 +#define PHY_PMA_ISO_TX_DATA_HI 0xCC15
2300 +#define PHY_PMA_ISO_RX_DATA_LO 0xCC16
2301 +#define PHY_PMA_ISO_RX_DATA_HI 0xCC17
2302 +
2303 +int cdns_dp_phy_init_imx8mq(struct imx_mhdp_device *hdp);
2304 +int cdns_dp_phy_init_imx8qm(struct imx_mhdp_device *hdp);
2305 +int cdns_hdmi_phy_set_imx8mq(struct imx_mhdp_device *hdp);
2306 +int cdns_hdmi_phy_set_imx8qm(struct imx_mhdp_device *hdp);
2307 +#endif /* _CDN_DP_PHY_H */