Re: [PATCH v18 6/8] phy: freescale: Add DisplayPort/HDMI Combo-PHY driver for i.MX8MQ
Dmitry Baryshkov
dmitry.baryshkov at linaro.org
Wed Nov 6 01:29:01 PST 2024
On 5 November 2024 14:05:51 GMT, Sandor Yu <sandor.yu at nxp.com> wrote:
>>
>> On Tue, Oct 29, 2024 at 02:02:14PM +0800, Sandor Yu wrote:
>> > Add Cadence HDP-TX DisplayPort and HDMI PHY driver for i.MX8MQ.
>> >
>> > Cadence HDP-TX PHY could be put in either DP mode or
>> > HDMI mode base on the configuration chosen.
>> > DisplayPort or HDMI PHY mode is configured in the driver.
>> >
>> > Signed-off-by: Sandor Yu <Sandor.yu at nxp.com>
>> > Signed-off-by: Alexander Stein <alexander.stein at ew.tq-group.com>
>> > ---
>> > v17->v18:
>> > - fix build error as code rebase to latest kernel version.
>> >
>> > drivers/phy/freescale/Kconfig | 10 +
>> > drivers/phy/freescale/Makefile | 1 +
>> > drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c | 1337
>> ++++++++++++++++++
>> > 3 files changed, 1348 insertions(+)
>> > create mode 100644 drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c
>> >
>> > diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
>> > index dcd9acff6d01a..2b1210367b31c 100644
>> > --- a/drivers/phy/freescale/Kconfig
>> > +++ b/drivers/phy/freescale/Kconfig
>> > @@ -35,6 +35,16 @@ config PHY_FSL_IMX8M_PCIE
>> > Enable this to add support for the PCIE PHY as found on
>> > i.MX8M family of SOCs.
>> >
>> > +config PHY_FSL_IMX8MQ_HDPTX
>> > + tristate "Freescale i.MX8MQ DP/HDMI PHY support"
>> > + depends on OF && HAS_IOMEM
>> > + depends on COMMON_CLK
>> > + select GENERIC_PHY
>> > + select CDNS_MHDP_HELPER
>>
>> This can have problems with being satisfied on randconfig builds,
>> because CDNS_MHDP_HELPER is deep inside the DRM tree.
>
>Yes, it should be. Change it to "depend on CDNS_MHDP_HELPER" will eliminate this problem.
No, depending on a non-user-selectable symbol is a bad idea. You should either depend/select all necessary symbols or, better in my opinion, move your helpers out of the DRM tree.
>
>>
>> > + help
>> > + Enable this to support the Cadence HDPTX DP/HDMI PHY driver
>> > + on i.MX8MQ SOC.
>> > +
>> > config PHY_FSL_IMX8QM_HSIO
>> > tristate "Freescale i.MX8QM HSIO PHY"
>> > depends on OF && HAS_IOMEM
>> > diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile
>> > index 658eac7d0a622..a946b87905498 100644
>> > --- a/drivers/phy/freescale/Makefile
>> > +++ b/drivers/phy/freescale/Makefile
>> > @@ -1,4 +1,5 @@
>> > # SPDX-License-Identifier: GPL-2.0-only
>> > +obj-$(CONFIG_PHY_FSL_IMX8MQ_HDPTX) += phy-fsl-imx8mq-hdptx.o
>> > obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o
>> > obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) +=
>> phy-fsl-imx8qm-lvds-phy.o
>> > obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o
>> > diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c
>> b/drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c
>> > new file mode 100644
>> > index 0000000000000..7aac39df0ab02
>> > --- /dev/null
>> > +++ b/drivers/phy/freescale/phy-fsl-imx8mq-hdptx.c
>> > @@ -0,0 +1,1337 @@
>> > +// SPDX-License-Identifier: GPL-2.0-only
>> > +/*
>> > + * Cadence DP/HDMI PHY driver
>> > + *
>> > + * Copyright (C) 2022-2024 NXP Semiconductor, Inc.
>> > + */
>> > +#include <drm/bridge/cdns-mhdp-helper.h>
>> > +#include <linux/clk.h>
>> > +#include <linux/kernel.h>
>> > +#include <linux/phy/phy.h>
>> > +#include <linux/platform_device.h>
>> > +#include <linux/io.h>
>> > +#include <linux/unaligned.h>
>> > +
>> > +#define ADDR_PHY_AFE 0x80000
>> > +
>> > +/* PHY registers */
>> > +#define CMN_SSM_BIAS_TMR 0x0022
>> > +#define CMN_PLLSM0_PLLEN_TMR 0x0029
>> > +#define CMN_PLLSM0_PLLPRE_TMR 0x002a
>> > +#define CMN_PLLSM0_PLLVREF_TMR 0x002b
>> > +#define CMN_PLLSM0_PLLLOCK_TMR 0x002c
>> > +#define CMN_PLLSM0_USER_DEF_CTRL 0x002f
>> > +#define CMN_PSM_CLK_CTRL 0x0061
>> > +#define CMN_CDIAG_REFCLK_CTRL 0x0062
>> > +#define CMN_PLL0_VCOCAL_START 0x0081
>> > +#define CMN_PLL0_VCOCAL_INIT_TMR 0x0084
>> > +#define CMN_PLL0_VCOCAL_ITER_TMR 0x0085
>> > +#define CMN_PLL0_INTDIV 0x0094
>> > +#define CMN_PLL0_FRACDIV 0x0095
>> > +#define CMN_PLL0_HIGH_THR 0x0096
>> > +#define CMN_PLL0_DSM_DIAG 0x0097
>> > +#define CMN_PLL0_SS_CTRL2 0x0099
>> > +#define CMN_ICAL_INIT_TMR 0x00c4
>> > +#define CMN_ICAL_ITER_TMR 0x00c5
>> > +#define CMN_RXCAL_INIT_TMR 0x00d4
>> > +#define CMN_RXCAL_ITER_TMR 0x00d5
>> > +#define CMN_TXPUCAL_CTRL 0x00e0
>> > +#define CMN_TXPUCAL_INIT_TMR 0x00e4
>> > +#define CMN_TXPUCAL_ITER_TMR 0x00e5
>> > +#define CMN_TXPDCAL_CTRL 0x00f0
>> > +#define CMN_TXPDCAL_INIT_TMR 0x00f4
>> > +#define CMN_TXPDCAL_ITER_TMR 0x00f5
>> > +#define CMN_ICAL_ADJ_INIT_TMR 0x0102
>> > +#define CMN_ICAL_ADJ_ITER_TMR 0x0103
>> > +#define CMN_RX_ADJ_INIT_TMR 0x0106
>> > +#define CMN_RX_ADJ_ITER_TMR 0x0107
>> > +#define CMN_TXPU_ADJ_CTRL 0x0108
>> > +#define CMN_TXPU_ADJ_INIT_TMR 0x010a
>> > +#define CMN_TXPU_ADJ_ITER_TMR 0x010b
>> > +#define CMN_TXPD_ADJ_CTRL 0x010c
>> > +#define CMN_TXPD_ADJ_INIT_TMR 0x010e
>> > +#define CMN_TXPD_ADJ_ITER_TMR 0x010f
>> > +#define CMN_DIAG_PLL0_FBH_OVRD 0x01c0
>> > +#define CMN_DIAG_PLL0_FBL_OVRD 0x01c1
>> > +#define CMN_DIAG_PLL0_OVRD 0x01c2
>> > +#define CMN_DIAG_PLL0_TEST_MODE 0x01c4
>> > +#define CMN_DIAG_PLL0_V2I_TUNE 0x01c5
>> > +#define CMN_DIAG_PLL0_CP_TUNE 0x01c6
>> > +#define CMN_DIAG_PLL0_LF_PROG 0x01c7
>> > +#define CMN_DIAG_PLL0_PTATIS_TUNE1 0x01c8
>> > +#define CMN_DIAG_PLL0_PTATIS_TUNE2 0x01c9
>> > +#define CMN_DIAG_PLL0_INCLK_CTRL 0x01ca
>> > +#define CMN_DIAG_PLL0_PXL_DIVH 0x01cb
>> > +#define CMN_DIAG_PLL0_PXL_DIVL 0x01cc
>> > +#define CMN_DIAG_HSCLK_SEL 0x01e0
>> > +#define CMN_DIAG_PER_CAL_ADJ 0x01ec
>> > +#define CMN_DIAG_CAL_CTRL 0x01ed
>> > +#define CMN_DIAG_ACYA 0x01ff
>> > +#define XCVR_PSM_RCTRL 0x4001
>> > +#define XCVR_PSM_CAL_TMR 0x4002
>> > +#define XCVR_PSM_A0IN_TMR 0x4003
>> > +#define TX_TXCC_CAL_SCLR_MULT_0 0x4047
>> > +#define TX_TXCC_CPOST_MULT_00_0 0x404c
>> > +#define XCVR_DIAG_PLLDRC_CTRL 0x40e0
>> > +#define XCVR_DIAG_HSCLK_SEL 0x40e1
>> > +#define XCVR_DIAG_BIDI_CTRL 0x40e8
>> > +#define XCVR_DIAG_LANE_FCM_EN_MGN_TMR
>> 0x40f2
>> > +#define TX_PSC_A0 0x4100
>> > +#define TX_PSC_A1 0x4101
>> > +#define TX_PSC_A2 0x4102
>> > +#define TX_PSC_A3 0x4103
>> > +#define TX_RCVDET_EN_TMR 0x4122
>> > +#define TX_RCVDET_ST_TMR 0x4123
>> > +#define TX_DIAG_TX_CTRL 0x41e0
>> > +#define TX_DIAG_TX_DRV 0x41e1
>> > +#define TX_DIAG_BGREF_PREDRV_DELAY 0x41e7
>> > +#define TX_DIAG_ACYA_0 0x41ff
>> > +#define TX_DIAG_ACYA_1 0x43ff
>> > +#define TX_DIAG_ACYA_2 0x45ff
>> > +#define TX_DIAG_ACYA_3 0x47ff
>> > +#define TX_ANA_CTRL_REG_1 0x5020
>> > +#define TX_ANA_CTRL_REG_2 0x5021
>> > +#define TX_DIG_CTRL_REG_1 0x5023
>> > +#define TX_DIG_CTRL_REG_2 0x5024
>> > +#define TXDA_CYA_AUXDA_CYA 0x5025
>> > +#define TX_ANA_CTRL_REG_3 0x5026
>> > +#define TX_ANA_CTRL_REG_4 0x5027
>> > +#define TX_ANA_CTRL_REG_5 0x5029
>> > +#define RX_PSC_A0 0x8000
>> > +#define RX_PSC_CAL 0x8006
>> > +#define PHY_HDP_MODE_CTRL 0xc008
>> > +#define PHY_HDP_CLK_CTL 0xc009
>> > +#define PHY_ISO_CMN_CTRL 0xc010
>> > +#define PHY_PMA_CMN_CTRL1 0xc800
>> > +#define PHY_PMA_ISO_CMN_CTRL 0xc810
>> > +#define PHY_PMA_ISO_PLL_CTRL1 0xc812
>> > +#define PHY_PMA_ISOLATION_CTRL 0xc81f
>> > +
>> > +/* PHY_HDP_CLK_CTL */
>> > +#define PLL_DATA_RATE_CLK_DIV_MASK GENMASK(15, 8)
>> > +#define PLL_DATA_RATE_CLK_DIV_HBR 0x24
>> > +#define PLL_DATA_RATE_CLK_DIV_HBR2 0x12
>> > +#define PLL_CLK_EN_ACK BIT(3)
>> > +#define PLL_CLK_EN BIT(2)
>> > +#define PLL_READY BIT(1)
>> > +#define PLL_EN BIT(0)
>> > +
>> > +/* PHY_PMA_CMN_CTRL1 */
>> > +#define CMA_REF_CLK_DIG_DIV_MASK GENMASK(13, 12)
>> > +#define CMA_REF_CLK_SEL_MASK GENMASK(6, 4)
>> > +#define CMA_REF_CLK_RCV_EN_MASK BIT(3)
>> > +#define CMA_REF_CLK_RCV_EN 1
>> > +#define CMN_READY BIT(0)
>> > +
>> > +/* PHY_PMA_ISO_PLL_CTRL1 */
>> > +#define CMN_PLL0_CLK_DATART_DIV_MASK GENMASK(7, 0)
>> > +
>> > +/* TX_DIAG_TX_DRV */
>> > +#define TX_DRIVER_PROG_BOOST_ENABLE BIT(10)
>> > +#define TX_DRIVER_PROG_BOOST_LEVEL_MASK
>> GENMASK(9, 8)
>> > +#define TX_DRIVER_LDO_BG_DEPENDENT_REF_ENABLE BIT(7)
>> > +#define TX_DRIVER_LDO_BANDGAP_REF_ENABLE BIT(6)
>> > +
>> > +/* TX_TXCC_CAL_SCLR_MULT_0 */
>> > +#define SCALED_RESISTOR_CALIBRATION_CODE_ADD BIT(8)
>> > +#define RESISTOR_CAL_MULT_VAL_32_128 BIT(5)
>> > +
>> > +/* CMN_CDIAG_REFCLK_CTRL */
>> > +#define DIG_REF_CLK_DIV_SCALER_MASK GENMASK(14, 12)
>> > +#define REFCLK_TERMINATION_EN_OVERRIDE_EN BIT(7)
>> > +#define REFCLK_TERMINATION_EN_OVERRIDE BIT(6)
>> > +
>> > +/* CMN_DIAG_HSCLK_SEL */
>> > +#define HSCLK1_SEL_MASK
>> GENMASK(5, 4)
>> > +#define HSCLK0_SEL_MASK
>> GENMASK(1, 0)
>> > +#define HSCLK_PLL0_DIV2 1
>> > +
>> > +/* XCVR_DIAG_HSCLK_SEL */
>> > +#define HSCLK_SEL_MODE3_MASK GENMASK(13, 12)
>> > +#define HSCLK_SEL_MODE3_HSCLK1 1
>> > +
>> > +/* CMN_PLL0_VCOCAL_START */
>> > +#define VCO_CALIB_CODE_START_POINT_VAL_MASK GENMASK(8, 0)
>> > +
>> > +/* CMN_DIAG_PLL0_FBH_OVRD */
>> > +#define PLL_FEEDBACK_DIV_HI_OVERRIDE_EN BIT(15)
>> > +
>> > +/* CMN_DIAG_PLL0_FBL_OVRD */
>> > +#define PLL_FEEDBACK_DIV_LO_OVERRIDE_EN BIT(15)
>> > +
>> > +/* CMN_DIAG_PLL0_PXL_DIVH */
>> > +#define PLL_PCLK_DIV_EN BIT(15)
>> > +
>> > +/* XCVR_DIAG_PLLDRC_CTRL */
>> > +#define DPLL_CLK_SEL_MODE3 BIT(14)
>> > +#define DPLL_DATA_RATE_DIV_MODE3_MASK
>> GENMASK(13, 12)
>> > +
>> > +/* TX_DIAG_TX_CTRL */
>> > +#define TX_IF_SUBRATE_MODE3_MASK GENMASK(7, 6)
>> > +
>> > +/* PHY_HDP_MODE_CTRL */
>> > +#define POWER_STATE_A3_ACK BIT(7)
>> > +#define POWER_STATE_A2_ACK BIT(6)
>> > +#define POWER_STATE_A1_ACK BIT(5)
>> > +#define POWER_STATE_A0_ACK BIT(4)
>> > +#define POWER_STATE_A3 BIT(3)
>> > +#define POWER_STATE_A2 BIT(2)
>> > +#define POWER_STATE_A1 BIT(1)
>> > +#define POWER_STATE_A0 BIT(0)
>> > +
>> > +/* PHY_PMA_ISO_CMN_CTRL */
>> > +#define CMN_MACRO_PWR_EN_ACK BIT(5)
>> > +
>> > +#define KEEP_ALIVE 0x18
>> > +
>> > +#define REF_CLK_27MHZ 27000000
>> > +
>> > +/* HDMI TX clock control settings */
>> > +struct hdptx_hdmi_ctrl {
>> > + u32 pixel_clk_freq_min;
>> > + u32 pixel_clk_freq_max;
>> > + u32 feedback_factor;
>> > + u32 data_range_kbps_min;
>> > + u32 data_range_kbps_max;
>> > + u32 cmnda_pll0_ip_div;
>> > + u32 cmn_ref_clk_dig_div;
>> > + u32 ref_clk_divider_scaler;
>> > + u32 pll_fb_div_total;
>> > + u32 cmnda_pll0_fb_div_low;
>> > + u32 cmnda_pll0_fb_div_high;
>> > + u32 pixel_div_total;
>> > + u32 cmnda_pll0_pxdiv_low;
>> > + u32 cmnda_pll0_pxdiv_high;
>> > + u32 vco_freq_min;
>> > + u32 vco_freq_max;
>> > + u32 vco_ring_select;
>> > + u32 cmnda_hs_clk_0_sel;
>> > + u32 cmnda_hs_clk_1_sel;
>> > + u32 hsclk_div_at_xcvr;
>> > + u32 hsclk_div_tx_sub_rate;
>> > + u32 cmnda_pll0_hs_sym_div_sel;
>> > + u32 cmnda_pll0_clk_freq_min;
>> > + u32 cmnda_pll0_clk_freq_max;
>> > +};
>> > +
>> > +struct cdns_hdptx_phy {
>> > + struct cdns_mhdp_base base;
>> > +
>> > + void __iomem *regs; /* DPTX registers base */
>> > + struct device *dev;
>> > + struct phy *phy;
>> > + struct clk *ref_clk, *apb_clk;
>> > + u32 ref_clk_rate;
>> > + bool power_up;
>> > + union {
>> > + struct phy_configure_opts_hdmi hdmi;
>> > + struct phy_configure_opts_dp dp;
>> > + };
>> > +};
>> > +
>> > +/* HDMI TX clock control settings, pixel clock is output */
>> > +static const struct hdptx_hdmi_ctrl pixel_clk_output_ctrl_table[] = {
>> > +/*Minclk Maxclk Fdbak DR_min DR_max ip_d dig DS Totl
>> */
>> > +{ 27000, 27000, 1000, 270000, 270000, 0x03, 0x1, 0x1, 240, 0x0bc,
>> 0x030, 80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x3, 27000,
>> 27000},
>> > +{ 27000, 27000, 1250, 337500, 337500, 0x03, 0x1, 0x1, 300, 0x0ec,
>> 0x03c, 100, 0x030, 0x030, 2700000, 2700000, 0, 2, 2, 2, 4, 0x3, 33750,
>> 33750},
>> > +{ 27000, 27000, 1500, 405000, 405000, 0x03, 0x1, 0x1, 360, 0x11c,
>> 0x048, 120, 0x03a, 0x03a, 3240000, 3240000, 0, 2, 2, 2, 4, 0x3, 40500,
>> 40500},
>> > +{ 27000, 27000, 2000, 540000, 540000, 0x03, 0x1, 0x1, 240, 0x0bc,
>> 0x030, 80, 0x026, 0x026, 2160000, 2160000, 0, 2, 2, 2, 4, 0x2, 54000,
>> 54000},
>> > +{ 54000, 54000, 1000, 540000, 540000, 0x03, 0x1, 0x1, 480, 0x17c,
>> 0x060, 80, 0x026, 0x026, 4320000, 4320000, 1, 2, 2, 2, 4, 0x3, 54000,
>> 54000},
>> > +{ 54000, 54000, 1250, 675000, 675000, 0x04, 0x1, 0x1, 400, 0x13c,
>> 0x050, 50, 0x017, 0x017, 2700000, 2700000, 0, 1, 1, 2, 4, 0x2, 67500,
>> 67500},
>> > +{ 54000, 54000, 1500, 810000, 810000, 0x04, 0x1, 0x1, 480, 0x17c,
>> 0x060, 60, 0x01c, 0x01c, 3240000, 3240000, 0, 2, 2, 2, 2, 0x2, 81000,
>> 81000},
>> > +{ 54000, 54000, 2000, 1080000, 1080000, 0x03, 0x1, 0x1, 240, 0x0bc,
>> 0x030, 40, 0x012, 0x012, 2160000, 2160000, 0, 2, 2, 2, 1, 0x1, 108000,
>> 108000},
>> > +{ 74250, 74250, 1000, 742500, 742500, 0x03, 0x1, 0x1, 660, 0x20c,
>> 0x084, 80, 0x026, 0x026, 5940000, 5940000, 1, 2, 2, 2, 4, 0x3, 74250,
>> 74250},
>> > +{ 74250, 74250, 1250, 928125, 928125, 0x04, 0x1, 0x1, 550, 0x1b4,
>> 0x06e, 50, 0x017, 0x017, 3712500, 3712500, 1, 1, 1, 2, 4, 0x2, 92812,
>> 92812},
>> > +{ 74250, 74250, 1500, 1113750, 1113750, 0x04, 0x1, 0x1, 660, 0x20c,
>> 0x084, 60, 0x01c, 0x01c, 4455000, 4455000, 1, 2, 2, 2, 2, 0x2, 111375,
>> 111375},
>> > +{ 74250, 74250, 2000, 1485000, 1485000, 0x03, 0x1, 0x1, 330, 0x104,
>> 0x042, 40, 0x012, 0x012, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500,
>> 148500},
>> > +{ 99000, 99000, 1000, 990000, 990000, 0x03, 0x1, 0x1, 440, 0x15c,
>> 0x058, 40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 2, 0x2, 99000,
>> 99000},
>> > +{ 99000, 99000, 1250, 1237500, 1237500, 0x03, 0x1, 0x1, 275, 0x0d8,
>> 0x037, 25, 0x00b, 0x00a, 2475000, 2475000, 0, 1, 1, 2, 2, 0x1, 123750,
>> 123750},
>> > +{ 99000, 99000, 1500, 1485000, 1485000, 0x03, 0x1, 0x1, 330, 0x104,
>> 0x042, 30, 0x00d, 0x00d, 2970000, 2970000, 0, 2, 2, 2, 1, 0x1, 148500,
>> 148500},
>> > +{ 99000, 99000, 2000, 1980000, 1980000, 0x03, 0x1, 0x1, 440, 0x15c,
>> 0x058, 40, 0x012, 0x012, 3960000, 3960000, 1, 2, 2, 2, 1, 0x1, 198000,
>> 198000},
>> > +{148500, 148500, 1000, 1485000, 1485000, 0x03, 0x1, 0x1, 660, 0x20c,
>> 0x084, 40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 2, 0x2, 148500,
>> 148500},
>> > +{148500, 148500, 1250, 1856250, 1856250, 0x04, 0x1, 0x1, 550, 0x1b4,
>> 0x06e, 25, 0x00b, 0x00a, 3712500, 3712500, 1, 1, 1, 2, 2, 0x1, 185625,
>> 185625},
>> > +{148500, 148500, 1500, 2227500, 2227500, 0x03, 0x1, 0x1, 495, 0x188,
>> 0x063, 30, 0x00d, 0x00d, 4455000, 4455000, 1, 1, 1, 2, 2, 0x1, 222750,
>> 222750},
>> > +{148500, 148500, 2000, 2970000, 2970000, 0x03, 0x1, 0x1, 660, 0x20c,
>> 0x084, 40, 0x012, 0x012, 5940000, 5940000, 1, 2, 2, 2, 1, 0x1, 297000,
>> 297000},
>> > +{198000, 198000, 1000, 1980000, 1980000, 0x03, 0x1, 0x1, 220, 0x0ac,
>> 0x02c, 10, 0x003, 0x003, 1980000, 1980000, 0, 1, 1, 2, 1, 0x0, 198000,
>> 198000},
>> > +{198000, 198000, 1250, 2475000, 2475000, 0x03, 0x1, 0x1, 550, 0x1b4,
>> 0x06e, 25, 0x00b, 0x00a, 4950000, 4950000, 1, 1, 1, 2, 2, 0x1, 247500,
>> 247500},
>> > +{198000, 198000, 1500, 2970000, 2970000, 0x03, 0x1, 0x1, 330, 0x104,
>> 0x042, 15, 0x006, 0x005, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000,
>> 297000},
>> > +{198000, 198000, 2000, 3960000, 3960000, 0x03, 0x1, 0x1, 440, 0x15c,
>> 0x058, 20, 0x008, 0x008, 3960000, 3960000, 1, 1, 1, 2, 1, 0x0, 396000,
>> 396000},
>> > +{297000, 297000, 1000, 2970000, 2970000, 0x03, 0x1, 0x1, 330, 0x104,
>> 0x042, 10, 0x003, 0x003, 2970000, 2970000, 0, 1, 1, 2, 1, 0x0, 297000,
>> 297000},
>> > +{297000, 297000, 1500, 4455000, 4455000, 0x03, 0x1, 0x1, 495, 0x188,
>> 0x063, 15, 0x006, 0x005, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500,
>> 445500},
>> > +{297000, 297000, 2000, 5940000, 5940000, 0x03, 0x1, 0x1, 660, 0x20c,
>> 0x084, 20, 0x008, 0x008, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000,
>> 594000},
>> > +{594000, 594000, 1000, 5940000, 5940000, 0x03, 0x1, 0x1, 660, 0x20c,
>> 0x084, 10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 1, 0x0, 594000,
>> 594000},
>> > +{594000, 594000, 750, 4455000, 4455000, 0x03, 0x1, 0x1, 495, 0x188,
>> 0x063, 10, 0x003, 0x003, 4455000, 4455000, 1, 1, 1, 2, 1, 0x0, 445500,
>> 445500},
>> > +{594000, 594000, 625, 3712500, 3712500, 0x04, 0x1, 0x1, 550, 0x1b4,
>> 0x06e, 10, 0x003, 0x003, 3712500, 3712500, 1, 1, 1, 2, 1, 0x0, 371250,
>> 371250},
>> > +{594000, 594000, 500, 2970000, 2970000, 0x03, 0x1, 0x1, 660, 0x20c,
>> 0x084, 10, 0x003, 0x003, 5940000, 5940000, 1, 1, 1, 2, 2, 0x1, 297000,
>> 297000},
>>
>> Is there a chance that this table or a part of it can be simplified or
>> calculated at runtime? For example, I think in all the cases minclk =
>> maxclk and DR_min = DR_max, dig and DS are always 0x1, etc.
>
>The calculation method used to generate this table is not publicly disclosed by the vendor.
I just pointed out how to simplify the table. If the exact method is not known, please apply some common sense to reduce duplication.
>
>This PHY operates in two modes: one where the pixel clock is generated internally by the PHY,
>and another where the pixel clock is input externally.
>The table above shows the configuration where the pixel clock is generated internally,
>It is the PHY work mode for i.MX8MQ HDMI PHY.
>When the pixel clock is input externally, the values for minclk, maxclk, DR_min, DR_max, dig, and DS are different.
>This operating mode is used in other SOCs.
Make use of it when there is a need for that. You might have different tables or platform-specific code instead.
>
>>
>> > +};
>> > +
>> > +/* HDMI TX PLL tuning settings */
>> > +struct hdptx_hdmi_pll_tuning {
>> > + u32 vco_freq_bin;
>> > + u32 vco_freq_min;
>> > + u32 vco_freq_max;
>> > + u32 volt_to_current_coarse;
>> > + u32 volt_to_current;
>> > + u32 ndac_ctrl;
>> > + u32 pmos_ctrl;
>> > + u32 ptat_ndac_ctrl;
>> > + u32 feedback_div_total;
>> > + u32 charge_pump_gain;
>> > + u32 coarse_code;
>> > + u32 v2i_code;
>> > + u32 vco_cal_code;
>> > +};
>> > +
>> > +/* HDMI TX PLL tuning settings, pixel clock is output */
>> > +static const struct hdptx_hdmi_pll_tuning pixel_clk_output_pll_table[] = {
>> > +/*bin VCO_freq min/max coar cod NDAC PMOS PTAT div-T P-Gain
>> Coa V2I CAL */
>> > +{ 1, 1980000, 1980000, 0x4, 0x3, 0x0, 0x09, 0x09, 220, 0x42, 160, 5,
>> 183 },
>> > +{ 2, 2160000, 2160000, 0x4, 0x3, 0x0, 0x09, 0x09, 240, 0x42, 166, 6,
>> 208 },
>> > +{ 3, 2475000, 2475000, 0x5, 0x3, 0x1, 0x00, 0x07, 275, 0x42, 167, 6,
>> 209 },
>> > +{ 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 300, 0x42, 188, 6,
>> 230 },
>> > +{ 4, 2700000, 2700000, 0x5, 0x3, 0x1, 0x00, 0x07, 400, 0x4c, 188, 6,
>> 230 },
>> > +{ 5, 2970000, 2970000, 0x6, 0x3, 0x1, 0x00, 0x07, 330, 0x42, 183, 6,
>> 225 },
>> > +{ 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 360, 0x42, 203, 7,
>> 256 },
>> > +{ 6, 3240000, 3240000, 0x6, 0x3, 0x1, 0x00, 0x07, 480, 0x4c, 203, 7,
>> 256 },
>> > +{ 7, 3712500, 3712500, 0x4, 0x3, 0x0, 0x07, 0x0F, 550, 0x4c, 212, 7, 257 },
>> > +{ 8, 3960000, 3960000, 0x5, 0x3, 0x0, 0x07, 0x0F, 440, 0x42, 184, 6, 226 },
>> > +{ 9, 4320000, 4320000, 0x5, 0x3, 0x1, 0x07, 0x0F, 480, 0x42, 205, 7, 258 },
>> > +{ 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 495, 0x42, 219, 7, 272 },
>> > +{ 10, 4455000, 4455000, 0x5, 0x3, 0x0, 0x07, 0x0F, 660, 0x4c, 219, 7, 272 },
>> > +{ 11, 4950000, 4950000, 0x6, 0x3, 0x1, 0x00, 0x07, 550, 0x42, 213, 7, 258 },
>> > +{ 12, 5940000, 5940000, 0x7, 0x3, 0x1, 0x00, 0x07, 660, 0x42, 244, 8, 292 },
>> > +};
>> > +
>> > +enum dp_link_rate {
>> > + RATE_1_6 = 162000,
>> > + RATE_2_1 = 216000,
>> > + RATE_2_4 = 243000,
>> > + RATE_2_7 = 270000,
>> > + RATE_3_2 = 324000,
>> > + RATE_4_3 = 432000,
>> > + RATE_5_4 = 540000,
>> > +};
>> > +
>> > +#define MAX_LINK_RATE RATE_5_4
>> > +
>> > +struct phy_pll_reg {
>> > + u16 val[7];
>> > + u32 addr;
>> > +};
>> > +
>> > +static const struct phy_pll_reg phy_pll_27m_cfg[] = {
>> > + /* 1.62 2.16 2.43 2.7 3.24 4.32 5.4
>> register address */
>> > + {{ 0x010e, 0x010e, 0x010e, 0x010e, 0x010e, 0x010e, 0x010e },
>> CMN_PLL0_VCOCAL_INIT_TMR },
>> > + {{ 0x001b, 0x001b, 0x001b, 0x001b, 0x001b, 0x001b, 0x001b },
>> CMN_PLL0_VCOCAL_ITER_TMR },
>> > + {{ 0x30b9, 0x3087, 0x3096, 0x30b4, 0x30b9, 0x3087, 0x30b4 },
>> CMN_PLL0_VCOCAL_START },
>> > + {{ 0x0077, 0x009f, 0x00b3, 0x00c7, 0x0077, 0x009f, 0x00c7 },
>> CMN_PLL0_INTDIV },
>> > + {{ 0xf9da, 0xf7cd, 0xf6c7, 0xf5c1, 0xf9da, 0xf7cd, 0xf5c1 },
>> CMN_PLL0_FRACDIV },
>> > + {{ 0x001e, 0x0028, 0x002d, 0x0032, 0x001e, 0x0028, 0x0032 },
>> CMN_PLL0_HIGH_THR },
>> > + {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 },
>> CMN_PLL0_DSM_DIAG },
>> > + {{ 0x0000, 0x1000, 0x1000, 0x1000, 0x0000, 0x1000, 0x1000 },
>> CMN_PLLSM0_USER_DEF_CTRL },
>> > + {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
>> CMN_DIAG_PLL0_OVRD },
>> > + {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
>> CMN_DIAG_PLL0_FBH_OVRD },
>> > + {{ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
>> CMN_DIAG_PLL0_FBL_OVRD },
>> > + {{ 0x0006, 0x0007, 0x0007, 0x0007, 0x0006, 0x0007, 0x0007 },
>> CMN_DIAG_PLL0_V2I_TUNE },
>> > + {{ 0x0043, 0x0043, 0x0043, 0x0042, 0x0043, 0x0043, 0x0042 },
>> CMN_DIAG_PLL0_CP_TUNE },
>> > + {{ 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008 },
>> CMN_DIAG_PLL0_LF_PROG },
>> > + {{ 0x0100, 0x0001, 0x0001, 0x0001, 0x0100, 0x0001, 0x0001 },
>> CMN_DIAG_PLL0_PTATIS_TUNE1 },
>> > + {{ 0x0007, 0x0001, 0x0001, 0x0001, 0x0007, 0x0001, 0x0001 },
>> CMN_DIAG_PLL0_PTATIS_TUNE2 },
>> > + {{ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020 },
>> CMN_DIAG_PLL0_TEST_MODE},
>> > + {{ 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016, 0x0016 },
>> CMN_PSM_CLK_CTRL }
>> > +};
>> > +
>> > +static int dp_link_rate_index(u32 rate)
>> > +{
>> > + switch (rate) {
>> > + case RATE_1_6:
>> > + return 0;
>> > + case RATE_2_1:
>> > + return 1;
>> > + case RATE_2_4:
>> > + return 2;
>> > + case RATE_2_7:
>> > + return 3;
>> > + case RATE_3_2:
>> > + return 4;
>> > + case RATE_4_3:
>> > + return 5;
>> > + case RATE_5_4:
>>
>> If this is the only usage, please drop the enum.
>
>OK.
>
>>
>> > + default:
>> > + return 6;
>>
>> default should be -EINVAL
>>
>
>OK.
>
>>
>> > + }
>> > +}
>> > +
>> > +static int cdns_phy_reg_write(struct cdns_hdptx_phy *cdns_phy, u32 addr,
>> u32 val)
>> > +{
>> > + return cdns_mhdp_reg_write(&cdns_phy->base, ADDR_PHY_AFE +
>> (addr << 2), val);
>> > +}
>> > +
>> > +static u32 cdns_phy_reg_read(struct cdns_hdptx_phy *cdns_phy, u32
>> addr)
>> > +{
>> > + u32 reg32;
>> > +
>> > + cdns_mhdp_reg_read(&cdns_phy->base, ADDR_PHY_AFE + (addr <<
>> 2), ®32);
>> > +
>> > + return reg32;
>> > +}
>> > +
>> > +static void hdptx_dp_aux_cfg(struct cdns_hdptx_phy *cdns_phy)
>> > +{
>> > + /* Power up Aux */
>> > + cdns_phy_reg_write(cdns_phy, TXDA_CYA_AUXDA_CYA, 1);
>> > +
>> > + cdns_phy_reg_write(cdns_phy, TX_DIG_CTRL_REG_1, 0x3);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_DIG_CTRL_REG_2, 36);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x0100);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x0300);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_3, 0x0000);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2008);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0x2018);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0xa018);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030c);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_5, 0x0000);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_4, 0x1001);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0xa098);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_1, 0xa198);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030d);
>> > + ndelay(150);
>> > + cdns_phy_reg_write(cdns_phy, TX_ANA_CTRL_REG_2, 0x030f);
>> > +}
>> > +
>> > +/* PMA common configuration for 27MHz */
>> > +static void hdptx_dp_phy_pma_cmn_cfg_27mhz(struct cdns_hdptx_phy
>> *cdns_phy)
>> > +{
>> > + u32 num_lanes = cdns_phy->dp.lanes;
>> > + u16 val;
>> > + int k;
>> > +
>> > + /* Enable PMA input ref clk(CMN_REF_CLK_RCV_EN) */
>> > + val = cdns_phy_reg_read(cdns_phy, PHY_PMA_CMN_CTRL1);
>> > + val &= ~CMA_REF_CLK_RCV_EN_MASK;
>> > + val |= FIELD_PREP(CMA_REF_CLK_RCV_EN_MASK,
>> CMA_REF_CLK_RCV_EN);
>> > + cdns_phy_reg_write(cdns_phy, PHY_PMA_CMN_CTRL1, val);
>> > +
>> > + /* Startup state machine registers */
>> > + cdns_phy_reg_write(cdns_phy, CMN_SSM_BIAS_TMR, 0x0087);
>> > + cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLEN_TMR,
>> 0x001b);
>> > + cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLPRE_TMR,
>> 0x0036);
>> > + cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLVREF_TMR,
>> 0x001b);
>> > + cdns_phy_reg_write(cdns_phy, CMN_PLLSM0_PLLLOCK_TMR,
>> 0x006c);
>> > +
>> > + /* Current calibration registers */
>> > + cdns_phy_reg_write(cdns_phy, CMN_ICAL_INIT_TMR, 0x0044);
>> > + cdns_phy_reg_write(cdns_phy, CMN_ICAL_ITER_TMR, 0x0006);
>> > + cdns_phy_reg_write(cdns_phy, CMN_ICAL_ADJ_INIT_TMR,
>> 0x0022);
>> > + cdns_phy_reg_write(cdns_phy, CMN_ICAL_ADJ_ITER_TMR,
>> 0x0006);
>> > +
>> > + /* Resistor calibration registers */
>> > + cdns_phy_reg_write(cdns_phy, CMN_TXPUCAL_INIT_TMR, 0x0022);
>> > + cdns_phy_reg_write(cdns_phy, CMN_TXPUCAL_ITER_TMR,
>> 0x0006);
>> > + cdns_phy_reg_write(cdns_phy, CMN_TXPU_ADJ_INIT_TMR,
>> 0x0022);
>> > + cdns_phy_reg_write(cdns_phy, CMN_TXPU_ADJ_ITER_TMR,
>> 0x0006);
>> > + cdns_phy_reg_write(cdns_phy, CMN_TXPDCAL_INIT_TMR, 0x0022);
>> > + cdns_phy_reg_write(cdns_phy, CMN_TXPDCAL_ITER_TMR,
>> 0x0006);
>> > + cdns_phy_reg_write(cdns_phy, CMN_TXPD_ADJ_INIT_TMR,
>> 0x0022);
>> > + cdns_phy_reg_write(cdns_phy, CMN_TXPD_ADJ_ITER_TMR,
>> 0x0006);
>> > + cdns_phy_reg_write(cdns_phy, CMN_RXCAL_INIT_TMR, 0x0022);
>> > + cdns_phy_reg_write(cdns_phy, CMN_RXCAL_ITER_TMR, 0x0006);
>> > + cdns_phy_reg_write(cdns_phy, CMN_RX_ADJ_INIT_TMR, 0x0022);
>> > + cdns_phy_reg_write(cdns_phy, CMN_RX_ADJ_ITER_TMR, 0x0006);
>> > +
>> > + for (k = 0; k < num_lanes; k = k + 1) {
>> > + /* Power state machine registers */
>> > + cdns_phy_reg_write(cdns_phy, XCVR_PSM_CAL_TMR |
>> (k << 9), 0x016d);
>> > + cdns_phy_reg_write(cdns_phy, XCVR_PSM_A0IN_TMR |
>> (k << 9), 0x016d);
>> > + /* Transceiver control and diagnostic registers */
>> > + cdns_phy_reg_write(cdns_phy,
>> XCVR_DIAG_LANE_FCM_EN_MGN_TMR | (k << 9), 0x00a2);
>> > + cdns_phy_reg_write(cdns_phy,
>> TX_DIAG_BGREF_PREDRV_DELAY | (k << 9), 0x0097);
>> > + /* Transmitter receiver detect registers */
>> > + cdns_phy_reg_write(cdns_phy, TX_RCVDET_EN_TMR | (k
>> << 9), 0x0a8c);
>> > + cdns_phy_reg_write(cdns_phy, TX_RCVDET_ST_TMR | (k
>> << 9), 0x0036);
>> > + }
>> > +
>> > + cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_0, 1);
>> > + cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_1, 1);
>> > + cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_2, 1);
>> > + cdns_phy_reg_write(cdns_phy, TX_DIAG_ACYA_3, 1);
>> > +}
>> > +
>> > +static void hdptx_dp_phy_pma_cmn_pll0_27mhz(struct cdns_hdptx_phy
>> *cdns_phy)
>> > +{
>> > + u32 num_lanes = cdns_phy->dp.lanes;
>> > + u32 link_rate = cdns_phy->dp.link_rate;
>> > + u16 val;
>> > + int index, i, k;
>> > +
>> > + /* DP PLL data rate 0/1 clock divider value */
>> > + val = cdns_phy_reg_read(cdns_phy, PHY_HDP_CLK_CTL);
>> > + val &= ~PLL_DATA_RATE_CLK_DIV_MASK;
>> > + if (link_rate <= RATE_2_7)
>> > + val |= FIELD_PREP(PLL_DATA_RATE_CLK_DIV_MASK,
>> > + PLL_DATA_RATE_CLK_DIV_HBR);
>> > + else
>> > + val |= FIELD_PREP(PLL_DATA_RATE_CLK_DIV_MASK,
>> > + PLL_DATA_RATE_CLK_DIV_HBR2);
>> > + cdns_phy_reg_write(cdns_phy, PHY_HDP_CLK_CTL, val);
>> > +
>> > + /* High speed clock 0/1 div */
>> > + val = cdns_phy_reg_read(cdns_phy, CMN_DIAG_HSCLK_SEL);
>> > + val &= ~(HSCLK1_SEL_MASK | HSCLK0_SEL_MASK);
>> > + if (link_rate <= RATE_2_7) {
>> > + val |= FIELD_PREP(HSCLK1_SEL_MASK,
>> HSCLK_PLL0_DIV2);
>> > + val |= FIELD_PREP(HSCLK0_SEL_MASK,
>> HSCLK_PLL0_DIV2);
>> > + }
>> > + cdns_phy_reg_write(cdns_phy, CMN_DIAG_HSCLK_SEL, val);
>> > +
>> > + for (k = 0; k < num_lanes; k++) {
>> > + val = cdns_phy_reg_read(cdns_phy,
>> (XCVR_DIAG_HSCLK_SEL | (k << 9)));
>> > + val &= ~HSCLK_SEL_MODE3_MASK;
>> > + if (link_rate <= RATE_2_7)
>> > + val |= FIELD_PREP(HSCLK_SEL_MODE3_MASK,
>> HSCLK_SEL_MODE3_HSCLK1);
>> > + cdns_phy_reg_write(cdns_phy, (XCVR_DIAG_HSCLK_SEL |
>> (k << 9)), val);
>> > + }
>> > +
>> > + /* DP PHY PLL 27MHz configuration */
>> > + index = dp_link_rate_index(link_rate);
>> > + for (i = 0; i < ARRAY_SIZE(phy_pll_27m_cfg); i++)
>> > + cdns_phy_reg_write(cdns_phy, phy_pll_27m_cfg[i].addr,
>> > + phy_pll_27m_cfg[i].val[index]);
>> > +
>> > + /* Transceiver control and diagnostic registers */
>> > + for (k = 0; k < num_lanes; k++) {
>> > + val = cdns_phy_reg_read(cdns_phy,
>> (XCVR_DIAG_PLLDRC_CTRL | (k << 9)));
>> > + val &= ~(DPLL_DATA_RATE_DIV_MODE3_MASK |
>> DPLL_CLK_SEL_MODE3);
>> > + if (link_rate <= RATE_2_7)
>> > + val |=
>> FIELD_PREP(DPLL_DATA_RATE_DIV_MODE3_MASK, 2);
>> > + else
>> > + val |=
>> FIELD_PREP(DPLL_DATA_RATE_DIV_MODE3_MASK, 1);
>> > + cdns_phy_reg_write(cdns_phy,
>> (XCVR_DIAG_PLLDRC_CTRL | (k << 9)), val);
>> > + }
>> > +
>> > + for (k = 0; k < num_lanes; k = k + 1) {
>> > +
More information about the linux-phy
mailing list