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
6 Add imx8qm/mq DP/hdmi driver
8 Signed-off-by: Sandor Yu <Sandor.yu@nxp.com>
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
24 --- a/drivers/gpu/drm/imx/Kconfig
25 +++ b/drivers/gpu/drm/imx/Kconfig
26 @@ -39,3 +39,12 @@ config DRM_IMX_HDMI
29 Choose this if you want to use HDMI on i.MX6.
31 +config DRM_IMX_CDNS_MHDP
32 + tristate "NXP i.MX MX8 DRM HDMI/DP"
33 + select DRM_CDNS_MHDP
35 + select DRM_CDNS_HDMI
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
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
47 +++ b/drivers/gpu/drm/imx/cdn-mhdp-dp-phy.c
50 + * Cadence Display Port Interface (DP) PHY driver
52 + * Copyright (C) 2019 NXP Semiconductor, Inc.
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.
60 +#include <linux/clk.h>
61 +#include <linux/kernel.h>
62 +#include <drm/drm_dp_helper.h>
64 +#include <drm/bridge/cdns-mhdp-common.h>
65 +#include "cdn-mhdp-phy.h"
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 }
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 }
127 +static int link_rate_index(u32 rate)
149 +static void dp_aux_cfg(struct cdns_mhdp_device *mhdp)
152 + cdns_phy_reg_write(mhdp, TXDA_CYA_AUXDA_CYA, 1);
154 + cdns_phy_reg_write(mhdp, TX_DIG_CTRL_REG_2, 36);
156 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0100);
158 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x0300);
160 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_3, 0x0000);
162 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2008);
164 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0x2018);
166 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA018);
168 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030C);
170 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_5, 0x0000);
172 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_4, 0x1001);
174 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA098);
176 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_1, 0xA198);
178 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030d);
180 + cdns_phy_reg_write(mhdp, TX_ANA_CTRL_REG_2, 0x030f);
183 +/* PMA common configuration for 24MHz */
184 +static void dp_phy_pma_cmn_cfg_24mhz(struct cdns_mhdp_device *mhdp)
187 + u32 num_lanes = mhdp->dp.link.num_lanes;
190 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
193 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
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);
204 +/* Valid for 24 MHz only */
205 +static void dp_phy_pma_cmn_pll0_24mhz(struct cdns_mhdp_device *mhdp)
207 + u32 num_lanes = mhdp->dp.link.num_lanes;
208 + u32 link_rate = mhdp->dp.link.rate;
213 + * PLL reference clock source select
214 + * for single ended reference clock val |= 0x0030;
215 + * for differential clock val |= 0x0000;
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);
222 + /* DP PLL data rate 0/1 clock divider value */
223 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
225 + if (link_rate <= RATE_2_7)
229 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
231 + /* High speed clock 0/1 div */
232 + val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
234 + if (link_rate <= RATE_2_7)
236 + cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
238 + for (k = 0; k < num_lanes; k = k + 1) {
239 + val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
241 + if (link_rate <= RATE_2_7)
243 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
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]);
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)));
255 + if (link_rate <= RATE_2_7)
259 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
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);
271 +/* PMA common configuration for 27MHz */
272 +static void dp_phy_pma_cmn_cfg_27mhz(struct cdns_mhdp_device *mhdp)
274 + u32 num_lanes = mhdp->dp.link.num_lanes;
278 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
281 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
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);
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);
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);
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);
323 +static void dp_phy_pma_cmn_pll0_27mhz(struct cdns_mhdp_device *mhdp)
325 + u32 num_lanes = mhdp->dp.link.num_lanes;
326 + u32 link_rate = mhdp->dp.link.rate;
331 + * PLL reference clock source select
332 + * for single ended reference clock val |= 0x0030;
333 + * for differential clock val |= 0x0000;
335 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
337 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
339 + /* for differential clock on the refclk_p and refclk_m off chip pins:
340 + * CMN_DIAG_ACYA[8]=1'b1
342 + cdns_phy_reg_write(mhdp, CMN_DIAG_ACYA, 0x0100);
344 + /* DP PLL data rate 0/1 clock divider value */
345 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
347 + if (link_rate <= RATE_2_7)
351 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
353 + /* High speed clock 0/1 div */
354 + val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
356 + if (link_rate <= RATE_2_7)
358 + cdns_phy_reg_write(mhdp, CMN_DIAG_HSCLK_SEL, val);
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)
365 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)), val);
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]);
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)
381 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
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));
394 + cdns_phy_reg_write(mhdp, (RX_PSC_CAL | (k << 9)), val);
395 + val = cdns_phy_reg_read(mhdp, RX_PSC_A0 | (k << 9));
397 + cdns_phy_reg_write(mhdp, (RX_PSC_A0 | (k << 9)), val);
401 +static void dp_phy_power_down(struct cdns_mhdp_device *mhdp)
406 + if (!mhdp->power_up)
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))
419 + dev_err(mhdp->dev, "Wait A3 Ack failed\n");
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);
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)))
435 + dev_err(mhdp->dev, "Wait PLL clock gate Ack failed\n");
439 + /* Disable HDP PLL’s for high speed clocks */
440 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
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)))
451 + dev_err(mhdp->dev, "Wait PLL disable Ack failed\n");
456 +static int dp_phy_power_up(struct cdns_mhdp_device *mhdp)
460 + /* Enable HDP PLL’s for high speed clocks */
461 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
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))
472 + dev_err(mhdp->dev, "Wait PLL Ack failed\n");
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);
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))
488 + dev_err(mhdp->dev, "Wait PLL clock enable ACk failed\n");
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))
502 + dev_err(mhdp->dev, "Wait A2 Ack failed\n");
506 + /* Configure PHY in A0 mode (PHY must be in the A0 power
507 + * state in order to transmit data)
509 + cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101);
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))
519 + dev_err(mhdp->dev, "Wait A0 Ack failed\n");
523 + mhdp->power_up = true;
528 +int cdns_dp_phy_init_imx8mq(struct imx_mhdp_device *hdp)
530 + struct cdns_mhdp_device *mhdp = &hdp->mhdp;
533 + /* Disable phy clock if PHY in power up state */
534 + dp_phy_power_down(mhdp);
536 + dp_phy_pma_cmn_cfg_27mhz(mhdp);
538 + dp_phy_pma_cmn_pll0_27mhz(mhdp);
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);
546 + ret = dp_phy_power_up(mhdp);
556 +int cdns_dp_phy_init_imx8qm(struct imx_mhdp_device *hdp)
558 + struct cdns_mhdp_device *mhdp = &hdp->mhdp;
561 + /* Disable phy clock if PHY in power up state */
562 + dp_phy_power_down(mhdp);
564 + dp_phy_pma_cmn_cfg_24mhz(mhdp);
566 + dp_phy_pma_cmn_pll0_24mhz(mhdp);
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);
574 + ret = dp_phy_power_up(mhdp);
583 +++ b/drivers/gpu/drm/imx/cdn-mhdp-hdmi-phy.c
586 + * Cadence High-Definition Multimedia Interface (HDMI) driver
588 + * Copyright (C) 2019 NXP Semiconductor, Inc.
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.
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>
605 +#include <drm/bridge/cdns-mhdp-common.h>
606 +#include "cdn-mhdp-phy.h"
608 +/* HDMI TX clock control settings */
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;
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;
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},
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},
699 +/* HDMI TX PLL tuning settings */
700 +struct hdmi_pll_tuning {
704 + u32 volt_to_current_coarse;
705 + u32 volt_to_current;
708 + u32 ptat_ndac_ctrl;
709 + u32 feedback_div_total;
710 + u32 charge_pump_gain;
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 },
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 }
779 +static void hdmi_phy_set_vswing(struct cdns_mhdp_device *mhdp)
781 + const u32 num_lanes = 4;
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);
791 +static int hdmi_feedback_factor(struct cdns_mhdp_device *mhdp)
793 + u32 feedback_factor;
795 + switch (mhdp->video_info.color_fmt) {
797 + feedback_factor = 1000;
800 + switch (mhdp->video_info.color_depth) {
802 + feedback_factor = 500;
805 + feedback_factor = 625;
808 + feedback_factor = 750;
811 + feedback_factor = 1000;
814 + DRM_ERROR("Invalid ColorDepth\n");
819 + /* Assume RGB/YUV444 */
820 + switch (mhdp->video_info.color_depth) {
822 + feedback_factor = 1250;
825 + feedback_factor = 1500;
828 + feedback_factor = 2000;
831 + feedback_factor = 1000;
834 + return feedback_factor;
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,
842 + const u32 num_lanes = 4;
845 + /* enable PHY isolation mode only for CMN */
846 + cdns_phy_reg_write(mhdp, PHY_PMA_ISOLATION_CTRL, 0xD000);
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);
852 + cdns_phy_reg_write(mhdp, PHY_PMA_ISO_PLL_CTRL1, val);
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);
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);
863 + /* Describing Task phy_cfg_hdp */
865 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
868 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
870 + /* PHY Registers */
871 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
873 + val |= p_ctrl_table->cmn_ref_clk_dig_div << 12;
874 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
876 + val = cdns_phy_reg_read(mhdp, PHY_HDP_CLK_CTL);
879 + cdns_phy_reg_write(mhdp, PHY_HDP_CLK_CTL, val);
881 + /* Common control module control and diagnostic registers */
882 + val = cdns_phy_reg_read(mhdp, CMN_CDIAG_REFCLK_CTRL);
884 + val |= p_ctrl_table->ref_clk_divider_scaler << 12;
886 + cdns_phy_reg_write(mhdp, CMN_CDIAG_REFCLK_CTRL, val);
888 + /* High speed clock used */
889 + val = cdns_phy_reg_read(mhdp, CMN_DIAG_HSCLK_SEL);
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);
895 + for (k = 0; k < num_lanes; k++) {
896 + val = cdns_phy_reg_read(mhdp, (XCVR_DIAG_HSCLK_SEL | (k << 9)));
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);
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);
906 + if (pclk_in == true)
909 + val = cdns_phy_reg_read(mhdp, CMN_PLL0_VCOCAL_START);
911 + val |= p_pll_table->vco_cal_code;
913 + cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_START, val);
915 + cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_INIT_TMR, 0x0064);
916 + cdns_phy_reg_write(mhdp, CMN_PLL0_VCOCAL_ITER_TMR, 0x000A);
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);
923 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_OVRD, 0x0000);
925 + val = p_ctrl_table->cmnda_pll0_fb_div_high;
927 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBH_OVRD, val);
929 + val = p_ctrl_table->cmnda_pll0_fb_div_low;
931 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_FBL_OVRD, val);
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);
937 + val = p_ctrl_table->cmnda_pll0_pxdiv_high;
939 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PXL_DIVH, val);
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);
946 + val = p_pll_table->charge_pump_gain;
947 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_CP_TUNE, val);
949 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_LF_PROG, 0x0008);
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);
955 + val = p_pll_table->ptat_ndac_ctrl;
956 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_PTATIS_TUNE2, val);
958 + if (pclk_in == true)
959 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0022);
961 + cdns_phy_reg_write(mhdp, CMN_DIAG_PLL0_TEST_MODE, 0x0020);
962 + cdns_phy_reg_write(mhdp, CMN_PSM_CLK_CTRL, 0x0016);
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)));
968 + cdns_phy_reg_write(mhdp, (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
971 + for (k = 0; k < num_lanes; k++) {
972 + val = cdns_phy_reg_read(mhdp, (TX_DIAG_TX_CTRL | (k << 9)));
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);
979 + * for single ended reference clock val |= 0x0030;
980 + * for differential clock val |= 0x0000;
982 + val = cdns_phy_reg_read(mhdp, PHY_PMA_CMN_CTRL1);
984 + if (pclk_in == true)
986 + cdns_phy_reg_write(mhdp, PHY_PMA_CMN_CTRL1, val);
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);
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);
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);
1000 + /* Assert cmn_macro_pwr_en */
1001 + cdns_phy_reg_write(mhdp, PHY_PMA_ISO_CMN_CTRL, 0x0013);
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))
1011 + DRM_ERROR("PMA ouput macro power up failed\n");
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))
1023 + DRM_ERROR("PMA output ready failed\n");
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);
1033 + val = cdns_phy_reg_read(mhdp, RX_PSC_CAL | (k << 9));
1035 + cdns_phy_reg_write(mhdp, RX_PSC_CAL | (k << 9), val);
1037 + val = cdns_phy_reg_read(mhdp, RX_PSC_A0 | (k << 9));
1039 + cdns_phy_reg_write(mhdp, RX_PSC_A0 | (k << 9), val);
1044 +static int hdmi_phy_cfg_t28hpc(struct cdns_mhdp_device *mhdp,
1045 + struct drm_display_mode *mode)
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;
1056 + feedback_factor = hdmi_feedback_factor(mhdp);
1058 + char_freq = pixel_freq * feedback_factor / 1000;
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);
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];
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);
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;
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];
1092 + if (i == ARRAY_SIZE(imx8mq_pll_table)) {
1093 + DRM_WARN("VCO (%d KHz) not supported\n", vco_freq);
1096 + DRM_INFO("VCO frequency is %d KHz\n", vco_freq);
1098 + ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in);
1105 +static int hdmi_phy_cfg_ss28fdsoi(struct cdns_mhdp_device *mhdp,
1106 + struct drm_display_mode *mode)
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;
1116 + feedback_factor = hdmi_feedback_factor(mhdp);
1118 + char_freq = pixel_freq * feedback_factor / 1000;
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);
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];
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);
1140 + div_total = p_ctrl_table->pll_fb_div_total;
1141 + vco_freq = pixel_freq * div_total / p_ctrl_table->cmnda_pll0_ip_div;
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];
1154 + if (i == ARRAY_SIZE(imx8qm_pll_table)) {
1155 + DRM_WARN("VCO (%d KHz) not supported\n", vco_freq);
1158 + DRM_INFO("VCO frequency is %d KHz\n", vco_freq);
1160 + ret = hdmi_phy_config(mhdp, p_ctrl_table, p_pll_table, pclk_in);
1167 +static int hdmi_phy_power_up(struct cdns_mhdp_device *mhdp)
1171 + /* set Power State to A2 */
1172 + cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0004);
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);
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))
1187 + dev_err(mhdp->dev, "Wait A2 Ack failed\n");
1191 + /* Configure PHY in A0 mode (PHY must be in the A0 power
1192 + * state in order to transmit data)
1194 + //cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0101); //imx8mq
1195 + cdns_phy_reg_write(mhdp, PHY_HDP_MODE_CTRL, 0x0001);
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))
1205 + dev_err(mhdp->dev, "Wait A0 Ack failed\n");
1211 +int cdns_hdmi_phy_set_imx8mq(struct imx_mhdp_device *hdp)
1213 + struct cdns_mhdp_device *mhdp = &hdp->mhdp;
1214 + struct drm_display_mode *mode = &mhdp->mode;
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");
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");
1231 + ret = hdmi_phy_power_up(mhdp);
1235 + hdmi_phy_set_vswing(mhdp);
1240 +int cdns_hdmi_phy_set_imx8qm(struct imx_mhdp_device *hdp)
1242 + struct cdns_mhdp_device *mhdp = &hdp->mhdp;
1243 + struct drm_display_mode *mode = &mhdp->mode;
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");
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");
1260 + ret = hdmi_phy_power_up(mhdp);
1264 + hdmi_phy_set_vswing(mhdp);
1270 +++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8mq.c
1273 + * Copyright (C) 2019 NXP Semiconductor, Inc.
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.
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>
1290 +#include <drm/bridge/cdns-mhdp-imx.h>
1291 +#include "cdn-mhdp-phy.h"
1292 +#include "imx-drm.h"
1295 + struct device *dev;
1296 + struct drm_encoder encoder;
1299 +static void cdns_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
1303 +static void cdns_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
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)
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,
1320 +static const struct drm_encoder_funcs cdns_hdmi_imx_encoder_funcs = {
1321 + .destroy = drm_encoder_cleanup,
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,
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,
1336 +static const struct of_device_id cdns_hdmi_imx_dt_ids[] = {
1337 + { .compatible = "cdn,imx8mq-hdmi",
1338 + .data = &imx8mq_hdmi_drv_data
1340 + { .compatible = "cdn,imx8mq-dp",
1341 + .data = &imx8mq_dp_drv_data
1345 +MODULE_DEVICE_TABLE(of, cdns_hdmi_imx_dt_ids);
1347 +static int cdns_hdmi_imx_bind(struct device *dev, struct device *master,
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;
1358 + if (!pdev->dev.of_node)
1361 + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
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;
1370 + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
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.
1377 + if (encoder->possible_crtcs == 0)
1378 + return -EPROBE_DEFER;
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);
1384 + ret = plat_data->bind(pdev, encoder, plat_data);
1387 + * If cdns_hdmi_bind() fails we'll never call cdns_hdmi_unbind(),
1388 + * which would have called the encoder cleanup. Do it manually.
1391 + drm_encoder_cleanup(encoder);
1396 +static void cdns_hdmi_imx_unbind(struct device *dev, struct device *master,
1399 + struct imx_mhdp_device *hdp = dev_get_drvdata(dev);
1401 + hdp->plat_data->unbind(dev);
1404 +static const struct component_ops cdns_hdmi_imx_ops = {
1405 + .bind = cdns_hdmi_imx_bind,
1406 + .unbind = cdns_hdmi_imx_unbind,
1409 +static int cdns_hdmi_imx_probe(struct platform_device *pdev)
1411 + return component_add(&pdev->dev, &cdns_hdmi_imx_ops);
1414 +static int cdns_hdmi_imx_remove(struct platform_device *pdev)
1416 + component_del(&pdev->dev, &cdns_hdmi_imx_ops);
1421 +static struct platform_driver cdns_hdmi_imx_platform_driver = {
1422 + .probe = cdns_hdmi_imx_probe,
1423 + .remove = cdns_hdmi_imx_remove,
1425 + .name = "cdn-hdp-imx8mq",
1426 + .of_match_table = cdns_hdmi_imx_dt_ids,
1430 +module_platform_driver(cdns_hdmi_imx_platform_driver);
1432 +MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
1433 +MODULE_LICENSE("GPL");
1434 +MODULE_ALIAS("platform:cdnhdmi-imx");
1436 +++ b/drivers/gpu/drm/imx/cdn-mhdp-imx8qm.c
1439 + * Copyright (C) 2019 NXP Semiconductor, Inc.
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.
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>
1458 +#include <drm/bridge/cdns-mhdp-imx.h>
1459 +#include "cdn-mhdp-phy.h"
1460 +#include "imx-drm.h"
1462 +#define CSR_PIXEL_LINK_MUX_CTL 0x00
1463 +#define PL_MUX_CTL_VCP_OFFSET 5
1464 +#define PL_MUX_CTL_HCP_OFFSET 4
1466 +#define PLL_800MHZ (800000000)
1469 + struct device *dev;
1470 + struct drm_encoder encoder;
1473 +static void imx8qm_pixel_link_mux(struct imx_mhdp_device *hdp)
1475 + struct drm_display_mode *mode = &hdp->mhdp.mode;
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)
1488 + regmap_write(hdp->regmap_csr, hdp->csr_pxl_mux_reg, val);
1491 +static void imx8qm_pixel_link_valid(u32 dual_mode)
1493 + struct imx_sc_ipc *handle;
1495 + imx_scu_get_handle(&handle);
1497 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 1);
1499 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 1);
1502 +static void imx8qm_pixel_link_invalid(u32 dual_mode)
1504 + struct imx_sc_ipc *handle;
1506 + imx_scu_get_handle(&handle);
1508 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST1_VLD, 0);
1510 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_PXL_LINK_MST2_VLD, 0);
1513 +static void imx8qm_pixel_link_sync_enable(u32 dual_mode)
1515 + struct imx_sc_ipc *handle;
1517 + imx_scu_get_handle(&handle);
1520 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 3);
1522 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 1);
1525 +static void imx8qm_pixel_link_sync_disable(u32 dual_mode)
1527 + struct imx_sc_ipc *handle;
1529 + imx_scu_get_handle(&handle);
1532 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL, 0);
1534 + imx_sc_misc_set_control(handle, IMX_SC_R_DC_0, IMX_SC_C_SYNC_CTRL0, 0);
1537 +static void imx8qm_phy_reset(u8 reset)
1539 + struct imx_sc_ipc *handle;
1541 + imx_scu_get_handle(&handle);
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);
1547 +static void imx8qm_clk_mux(u8 is_dp)
1549 + struct imx_sc_ipc *handle;
1551 + imx_scu_get_handle(&handle);
1554 + /* Enable the 24MHz for HDP PHY */
1555 + imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 1);
1557 + imx_sc_misc_set_control(handle, IMX_SC_R_HDMI, IMX_SC_C_MODE, 0);
1560 +int imx8qm_clocks_init(struct imx_mhdp_device *hdp)
1562 + struct device *dev = hdp->mhdp.dev;
1563 + struct imx_hdp_clks *clks = &hdp->clks;
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1669 +static int imx8qm_pixel_clk_enable(struct imx_mhdp_device *hdp)
1671 + struct imx_hdp_clks *clks = &hdp->clks;
1672 + struct device *dev = hdp->mhdp.dev;
1675 + ret = clk_prepare_enable(clks->av_pll);
1677 + dev_err(dev, "%s, pre av pll error\n", __func__);
1681 + ret = clk_prepare_enable(clks->clk_pxl);
1683 + dev_err(dev, "%s, pre clk pxl error\n", __func__);
1686 + ret = clk_prepare_enable(clks->clk_pxl_mux);
1688 + dev_err(dev, "%s, pre clk pxl mux error\n", __func__);
1692 + ret = clk_prepare_enable(clks->clk_pxl_link);
1694 + dev_err(dev, "%s, pre clk pxl link error\n", __func__);
1697 + ret = clk_prepare_enable(clks->lpcg_vif);
1699 + dev_err(dev, "%s, pre clk vif error\n", __func__);
1702 + ret = clk_prepare_enable(clks->lpcg_pxl);
1704 + dev_err(dev, "%s, pre lpcg pxl error\n", __func__);
1707 + ret = clk_prepare_enable(clks->lpcg_hdp);
1709 + dev_err(dev, "%s, pre lpcg hdp error\n", __func__);
1716 +static void imx8qm_pixel_clk_disable(struct imx_mhdp_device *hdp)
1718 + struct imx_hdp_clks *clks = &hdp->clks;
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);
1729 +static void imx8qm_pixel_clk_set_rate(struct imx_mhdp_device *hdp, u32 pclock)
1731 + struct imx_hdp_clks *clks = &hdp->clks;
1733 + /* pixel clock for HDMI */
1734 + clk_set_rate(clks->av_pll, pclock);
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);
1740 + clk_set_rate(clks->clk_pxl_link, pclock);
1741 + clk_set_rate(clks->clk_pxl, pclock);
1743 + clk_set_rate(clks->clk_pxl_mux, pclock);
1746 +static void imx8qm_pixel_clk_rate_change(struct imx_mhdp_device *hdp)
1748 + /* set pixel clock before video mode setup */
1749 + imx8qm_pixel_clk_disable(hdp);
1751 + imx8qm_pixel_clk_set_rate(hdp, hdp->mhdp.mode.clock * 1000);
1753 + imx8qm_pixel_clk_enable(hdp);
1755 + /* Config pixel link mux */
1756 + imx8qm_pixel_link_mux(hdp);
1759 +static int imx8qm_ipg_clk_enable(struct imx_mhdp_device *hdp)
1762 + struct imx_hdp_clks *clks = &hdp->clks;
1763 + struct device *dev = hdp->mhdp.dev;
1765 + ret = clk_prepare_enable(clks->dig_pll);
1767 + dev_err(dev, "%s, pre dig pll error\n", __func__);
1771 + ret = clk_prepare_enable(clks->clk_ipg);
1773 + dev_err(dev, "%s, pre clk_ipg error\n", __func__);
1777 + ret = clk_prepare_enable(clks->clk_core);
1779 + dev_err(dev, "%s, pre clk core error\n", __func__);
1783 + ret = clk_prepare_enable(clks->lpcg_apb);
1785 + dev_err(dev, "%s, pre clk apb error\n", __func__);
1788 + ret = clk_prepare_enable(clks->lpcg_lis);
1790 + dev_err(dev, "%s, pre clk lis error\n", __func__);
1793 + ret = clk_prepare_enable(clks->lpcg_msi);
1795 + dev_err(dev, "%s, pre clk msierror\n", __func__);
1798 + ret = clk_prepare_enable(clks->lpcg_apb_csr);
1800 + dev_err(dev, "%s, pre clk apb csr error\n", __func__);
1803 + ret = clk_prepare_enable(clks->lpcg_apb_ctrl);
1805 + dev_err(dev, "%s, pre clk apb ctrl error\n", __func__);
1808 + ret = clk_prepare_enable(clks->lpcg_i2s);
1810 + dev_err(dev, "%s, pre clk i2s error\n", __func__);
1813 + ret = clk_prepare_enable(clks->clk_i2s_bypass);
1815 + dev_err(dev, "%s, pre clk i2s bypass error\n", __func__);
1821 +static void imx8qm_ipg_clk_disable(struct imx_mhdp_device *hdp)
1823 + struct imx_hdp_clks *clks = &hdp->clks;
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);
1837 +static void imx8qm_ipg_clk_set_rate(struct imx_mhdp_device *hdp)
1839 + struct imx_hdp_clks *clks = &hdp->clks;
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);
1847 +static void imx8qm_detach_pm_domains(struct imx_mhdp_device *hdp)
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);
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);
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);
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;
1872 +static int imx8qm_attach_pm_domains(struct imx_mhdp_device *hdp)
1874 + struct device *dev = hdp->mhdp.dev;
1875 + u32 flags = DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE;
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);
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",
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);
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",
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);
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",
1920 + imx8qm_detach_pm_domains(hdp);
1924 +static int imx8qm_firmware_init(struct imx_mhdp_device *hdp)
1929 + /* Power on PM Domains */
1930 + imx8qm_attach_pm_domains(hdp);
1932 + /* clock init and rate set */
1933 + imx8qm_clocks_init(hdp);
1935 + imx8qm_ipg_clk_set_rate(hdp);
1937 + /* Init pixel clock with 148.5MHz before FW init */
1938 + imx8qm_pixel_clk_set_rate(hdp, 148500000);
1940 + imx8qm_ipg_clk_enable(hdp);
1942 + imx8qm_clk_mux(hdp->plat_data->is_dp);
1944 + imx8qm_pixel_clk_enable(hdp);
1946 + imx8qm_phy_reset(1);
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);
1954 + /* configure HDMI/DP core clock */
1955 + rate = clk_get_rate(hdp->clks.clk_core);
1956 + cdns_mhdp_set_fw_clk(&hdp->mhdp, rate);
1958 + /* un-reset ucpu */
1959 + writel(0, (APB_CTRL << 2) + hdp->mhdp.regs);
1960 + DRM_INFO("Started firmware!\n");
1962 + ret = cdns_mhdp_check_alive(&hdp->mhdp);
1963 + if (ret == false) {
1964 + DRM_ERROR("NO HDMI FW running\n");
1968 + /* turn on IP activity */
1969 + cdns_mhdp_set_firmware_active(&hdp->mhdp, 1);
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));
1978 +static void cdns_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
1980 + struct imx_mhdp_device *hdp = encoder->bridge->driver_private;
1982 + imx8qm_pixel_link_sync_disable(hdp->dual_mode);
1983 + imx8qm_pixel_link_invalid(hdp->dual_mode);
1986 +static void cdns_hdmi_imx_encoder_enable(struct drm_encoder *encoder)
1988 + struct imx_mhdp_device *hdp = encoder->bridge->driver_private;
1990 + imx8qm_pixel_link_valid(hdp->dual_mode);
1991 + imx8qm_pixel_link_sync_enable(hdp->dual_mode);
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)
1998 + struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
2000 + imx_crtc_state->bus_format = MEDIA_BUS_FMT_RGB101010_1X30;
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,
2010 +static const struct drm_encoder_funcs cdns_hdmi_imx_encoder_funcs = {
2011 + .destroy = drm_encoder_cleanup,
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,
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,
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,
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,
2045 +static const struct of_device_id cdns_hdmi_imx_dt_ids[] = {
2047 + { .compatible = "cdn,imx8mq-hdmi",
2048 + .data = &imx8mq_hdmi_drv_data
2050 + { .compatible = "cdn,imx8mq-dp",
2051 + .data = &imx8mq_dp_drv_data
2054 + { .compatible = "cdn,imx8qm-hdmi",
2055 + .data = &imx8qm_hdmi_drv_data
2057 + { .compatible = "cdn,imx8qm-dp",
2058 + .data = &imx8qm_dp_drv_data
2062 +MODULE_DEVICE_TABLE(of, cdns_hdmi_imx_dt_ids);
2064 +static int cdns_hdmi_imx_bind(struct device *dev, struct device *master,
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;
2075 + if (!pdev->dev.of_node)
2078 + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
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;
2087 + encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
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.
2094 + if (encoder->possible_crtcs == 0)
2095 + return -EPROBE_DEFER;
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);
2101 + ret = plat_data->bind(pdev, encoder, plat_data);
2104 + * If cdns_hdmi_bind() fails we'll never call cdns_hdmi_unbind(),
2105 + * which would have called the encoder cleanup. Do it manually.
2108 + drm_encoder_cleanup(encoder);
2113 +static void cdns_hdmi_imx_unbind(struct device *dev, struct device *master,
2116 + struct imx_mhdp_device *hdp = dev_get_drvdata(dev);
2118 + hdp->plat_data->unbind(dev);
2121 +static const struct component_ops cdns_hdmi_imx8qm_ops = {
2122 + .bind = cdns_hdmi_imx_bind,
2123 + .unbind = cdns_hdmi_imx_unbind,
2126 +static int cdns_hdmi_imx_probe(struct platform_device *pdev)
2128 + return component_add(&pdev->dev, &cdns_hdmi_imx8qm_ops);
2131 +static int cdns_hdmi_imx_remove(struct platform_device *pdev)
2133 + component_del(&pdev->dev, &cdns_hdmi_imx8qm_ops);
2138 +static struct platform_driver cdns_hdmi_imx_platform_driver = {
2139 + .probe = cdns_hdmi_imx_probe,
2140 + .remove = cdns_hdmi_imx_remove,
2142 + .name = "cdn-hdp-imx8qm",
2143 + .of_match_table = cdns_hdmi_imx_dt_ids,
2147 +module_platform_driver(cdns_hdmi_imx_platform_driver);
2149 +MODULE_AUTHOR("Sandor YU <sandor.yu@nxp.com>");
2150 +MODULE_LICENSE("GPL");
2151 +MODULE_ALIAS("platform:cdnhdmi-imx");
2153 +++ b/drivers/gpu/drm/imx/cdn-mhdp-phy.h
2156 + * Copyright (C) 2019 NXP Semiconductor, Inc.
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.
2164 +#ifndef _CDN_DP_PHY_H
2165 +#define _CDN_DP_PHY_H
2167 +#include <drm/bridge/cdns-mhdp-imx.h>
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
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
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 */