summaryrefslogtreecommitdiff
path: root/drivers/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/allwinner/phy-sun4i-usb.c1
-rw-r--r--drivers/phy/freescale/Kconfig1
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8m-pcie.c23
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8mq-usb.c250
-rw-r--r--drivers/phy/freescale/phy-fsl-samsung-hdmi.c72
-rw-r--r--drivers/phy/hisilicon/phy-hi3670-pcie.c11
-rw-r--r--drivers/phy/marvell/phy-mvebu-cp110-comphy.c2
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c44
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h3
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi.c28
-rw-r--r--drivers/phy/mediatek/phy-mtk-hdmi.h4
-rw-r--r--drivers/phy/mediatek/phy-mtk-tphy.c44
-rw-r--r--drivers/phy/microchip/Kconfig1
-rw-r--r--drivers/phy/motorola/phy-mapphone-mdm6600.c4
-rw-r--r--drivers/phy/phy-can-transceiver.c23
-rw-r--r--drivers/phy/phy-core.c54
-rw-r--r--drivers/phy/qualcomm/Kconfig13
-rw-r--r--drivers/phy/qualcomm/Makefile1
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-combo.c100
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcie.c385
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h5
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h5
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h3
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h1
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6.h2
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h7
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v7.h67
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h1
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-ufs.c179
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usb.c9
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qmp-usbc.c3
-rw-r--r--drivers/phy/qualcomm/phy-qcom-qusb2.c30
-rw-r--r--drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c286
-rw-r--r--drivers/phy/renesas/phy-rcar-gen3-usb2.c135
-rw-r--r--drivers/phy/rockchip/Kconfig12
-rw-r--r--drivers/phy/rockchip/Makefile1
-rw-r--r--drivers/phy/rockchip/phy-rockchip-inno-usb2.c4
-rw-r--r--drivers/phy/rockchip/phy-rockchip-naneng-combphy.c431
-rw-r--r--drivers/phy/rockchip/phy-rockchip-pcie.c148
-rw-r--r--drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c1719
-rw-r--r--drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c1061
-rw-r--r--drivers/phy/rockchip/phy-rockchip-typec.c2
-rw-r--r--drivers/phy/rockchip/phy-rockchip-usbdp.c90
-rw-r--r--drivers/phy/samsung/Kconfig2
-rw-r--r--drivers/phy/samsung/Makefile1
-rw-r--r--drivers/phy/samsung/phy-exynos5-usbdrd.c202
-rw-r--r--drivers/phy/samsung/phy-exynosautov920-ufs.c168
-rw-r--r--drivers/phy/samsung/phy-samsung-ufs.c15
-rw-r--r--drivers/phy/samsung/phy-samsung-ufs.h4
-rw-r--r--drivers/phy/st/phy-stih407-usb.c24
-rw-r--r--drivers/phy/starfive/phy-jh7110-usb.c7
-rw-r--r--drivers/phy/tegra/Kconfig5
-rw-r--r--drivers/phy/tegra/xusb-tegra186.c46
-rw-r--r--drivers/phy/tegra/xusb.c8
-rw-r--r--drivers/phy/ti/phy-gmii-sel.c15
55 files changed, 5238 insertions, 524 deletions
diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c
index cd159a71b23c..29b8fd4b9351 100644
--- a/drivers/phy/allwinner/phy-sun4i-usb.c
+++ b/drivers/phy/allwinner/phy-sun4i-usb.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
#include <linux/phy/phy.h>
#include <linux/phy/phy-sun4i-usb.h>
#include <linux/platform_device.h>
diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig
index dcd9acff6d01..81f53564ee15 100644
--- a/drivers/phy/freescale/Kconfig
+++ b/drivers/phy/freescale/Kconfig
@@ -5,6 +5,7 @@ if (ARCH_MXC && ARM64) || COMPILE_TEST
config PHY_FSL_IMX8MQ_USB
tristate "Freescale i.MX8M USB3 PHY"
depends on OF && HAS_IOMEM
+ depends on TYPEC || TYPEC=n
select GENERIC_PHY
default ARCH_MXC && ARM64
diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
index e98361dcdead..7355d9921b64 100644
--- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
+++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c
@@ -141,15 +141,9 @@ static int imx8_pcie_phy_power_on(struct phy *phy)
IMX8MM_GPR_PCIE_REF_CLK_PLL);
usleep_range(100, 200);
- switch (imx8_phy->drvdata->variant) {
- case IMX8MP:
- reset_control_deassert(imx8_phy->perst);
- fallthrough;
- case IMX8MM:
- reset_control_deassert(imx8_phy->reset);
- usleep_range(200, 500);
- break;
- }
+ reset_control_deassert(imx8_phy->perst);
+ reset_control_deassert(imx8_phy->reset);
+ usleep_range(200, 500);
/* Do the PHY common block reset */
regmap_update_bits(imx8_phy->iomuxc_gpr, IOMUXC_GPR14,
@@ -162,6 +156,16 @@ static int imx8_pcie_phy_power_on(struct phy *phy)
return ret;
}
+static int imx8_pcie_phy_power_off(struct phy *phy)
+{
+ struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
+
+ reset_control_assert(imx8_phy->reset);
+ reset_control_assert(imx8_phy->perst);
+
+ return 0;
+}
+
static int imx8_pcie_phy_init(struct phy *phy)
{
struct imx8_pcie_phy *imx8_phy = phy_get_drvdata(phy);
@@ -182,6 +186,7 @@ static const struct phy_ops imx8_pcie_phy_ops = {
.init = imx8_pcie_phy_init,
.exit = imx8_pcie_phy_exit,
.power_on = imx8_pcie_phy_power_on,
+ .power_off = imx8_pcie_phy_power_off,
.owner = THIS_MODULE,
};
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index adc6394626ce..9598a8073991 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -10,6 +10,7 @@
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/usb/typec_mux.h>
#define PHY_CTRL0 0x0
#define PHY_CTRL0_REF_SSP_EN BIT(2)
@@ -50,11 +51,66 @@
#define PHY_TUNE_DEFAULT 0xffffffff
+#define TCA_CLK_RST 0x00
+#define TCA_CLK_RST_SW BIT(9)
+#define TCA_CLK_RST_REF_CLK_EN BIT(1)
+#define TCA_CLK_RST_SUSPEND_CLK_EN BIT(0)
+
+#define TCA_INTR_EN 0x04
+#define TCA_INTR_STS 0x08
+
+#define TCA_GCFG 0x10
+#define TCA_GCFG_ROLE_HSTDEV BIT(4)
+#define TCA_GCFG_OP_MODE GENMASK(1, 0)
+#define TCA_GCFG_OP_MODE_SYSMODE 0
+#define TCA_GCFG_OP_MODE_SYNCMODE 1
+
+#define TCA_TCPC 0x14
+#define TCA_TCPC_VALID BIT(4)
+#define TCA_TCPC_LOW_POWER_EN BIT(3)
+#define TCA_TCPC_ORIENTATION_NORMAL BIT(2)
+#define TCA_TCPC_MUX_CONTRL GENMASK(1, 0)
+#define TCA_TCPC_MUX_CONTRL_NO_CONN 0
+#define TCA_TCPC_MUX_CONTRL_USB_CONN 1
+
+#define TCA_SYSMODE_CFG 0x18
+#define TCA_SYSMODE_TCPC_DISABLE BIT(3)
+#define TCA_SYSMODE_TCPC_FLIP BIT(2)
+
+#define TCA_CTRLSYNCMODE_CFG0 0x20
+#define TCA_CTRLSYNCMODE_CFG1 0x20
+
+#define TCA_PSTATE 0x30
+#define TCA_PSTATE_CM_STS BIT(4)
+#define TCA_PSTATE_TX_STS BIT(3)
+#define TCA_PSTATE_RX_PLL_STS BIT(2)
+#define TCA_PSTATE_PIPE0_POWER_DOWN GENMASK(1, 0)
+
+#define TCA_GEN_STATUS 0x34
+#define TCA_GEN_DEV_POR BIT(12)
+#define TCA_GEN_REF_CLK_SEL BIT(8)
+#define TCA_GEN_TYPEC_FLIP_INVERT BIT(4)
+#define TCA_GEN_PHY_TYPEC_DISABLE BIT(3)
+#define TCA_GEN_PHY_TYPEC_FLIP BIT(2)
+
+#define TCA_VBUS_CTRL 0x40
+#define TCA_VBUS_STATUS 0x44
+
+#define TCA_INFO 0xfc
+
+struct tca_blk {
+ struct typec_switch_dev *sw;
+ void __iomem *base;
+ struct mutex mutex;
+ enum typec_orientation orientation;
+};
+
struct imx8mq_usb_phy {
struct phy *phy;
struct clk *clk;
void __iomem *base;
struct regulator *vbus;
+ struct tca_blk *tca;
u32 pcs_tx_swing_full;
u32 pcs_tx_deemph_3p5db;
u32 tx_vref_tune;
@@ -64,6 +120,172 @@ struct imx8mq_usb_phy {
u32 comp_dis_tune;
};
+
+static void tca_blk_orientation_set(struct tca_blk *tca,
+ enum typec_orientation orientation);
+
+#ifdef CONFIG_TYPEC
+
+static int tca_blk_typec_switch_set(struct typec_switch_dev *sw,
+ enum typec_orientation orientation)
+{
+ struct imx8mq_usb_phy *imx_phy = typec_switch_get_drvdata(sw);
+ struct tca_blk *tca = imx_phy->tca;
+ int ret;
+
+ if (tca->orientation == orientation)
+ return 0;
+
+ ret = clk_prepare_enable(imx_phy->clk);
+ if (ret)
+ return ret;
+
+ tca_blk_orientation_set(tca, orientation);
+ clk_disable_unprepare(imx_phy->clk);
+
+ return 0;
+}
+
+static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev,
+ struct imx8mq_usb_phy *imx_phy)
+{
+ struct device *dev = &pdev->dev;
+ struct typec_switch_dev *sw;
+ struct typec_switch_desc sw_desc = { };
+
+ sw_desc.drvdata = imx_phy;
+ sw_desc.fwnode = dev->fwnode;
+ sw_desc.set = tca_blk_typec_switch_set;
+ sw_desc.name = NULL;
+
+ sw = typec_switch_register(dev, &sw_desc);
+ if (IS_ERR(sw)) {
+ dev_err(dev, "Error register tca orientation switch: %ld",
+ PTR_ERR(sw));
+ return NULL;
+ }
+
+ return sw;
+}
+
+static void tca_blk_put_typec_switch(struct typec_switch_dev *sw)
+{
+ typec_switch_unregister(sw);
+}
+
+#else
+
+static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev,
+ struct imx8mq_usb_phy *imx_phy)
+{
+ return NULL;
+}
+
+static void tca_blk_put_typec_switch(struct typec_switch_dev *sw) {}
+
+#endif /* CONFIG_TYPEC */
+
+static void tca_blk_orientation_set(struct tca_blk *tca,
+ enum typec_orientation orientation)
+{
+ u32 val;
+
+ mutex_lock(&tca->mutex);
+
+ if (orientation == TYPEC_ORIENTATION_NONE) {
+ /*
+ * use Controller Synced Mode for TCA low power enable and
+ * put PHY to USB safe state.
+ */
+ val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYNCMODE);
+ writel(val, tca->base + TCA_GCFG);
+
+ val = TCA_TCPC_VALID | TCA_TCPC_LOW_POWER_EN;
+ writel(val, tca->base + TCA_TCPC);
+
+ goto out;
+ }
+
+ /* use System Configuration Mode for TCA mux control. */
+ val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYSMODE);
+ writel(val, tca->base + TCA_GCFG);
+
+ /* Disable TCA module */
+ val = readl(tca->base + TCA_SYSMODE_CFG);
+ val |= TCA_SYSMODE_TCPC_DISABLE;
+ writel(val, tca->base + TCA_SYSMODE_CFG);
+
+ if (orientation == TYPEC_ORIENTATION_REVERSE)
+ val |= TCA_SYSMODE_TCPC_FLIP;
+ else if (orientation == TYPEC_ORIENTATION_NORMAL)
+ val &= ~TCA_SYSMODE_TCPC_FLIP;
+
+ writel(val, tca->base + TCA_SYSMODE_CFG);
+
+ /* Enable TCA module */
+ val &= ~TCA_SYSMODE_TCPC_DISABLE;
+ writel(val, tca->base + TCA_SYSMODE_CFG);
+
+out:
+ tca->orientation = orientation;
+ mutex_unlock(&tca->mutex);
+}
+
+static void tca_blk_init(struct tca_blk *tca)
+{
+ u32 val;
+
+ /* reset XBar block */
+ val = readl(tca->base + TCA_CLK_RST);
+ val &= ~TCA_CLK_RST_SW;
+ writel(val, tca->base + TCA_CLK_RST);
+
+ udelay(100);
+
+ /* clear reset */
+ val |= TCA_CLK_RST_SW;
+ writel(val, tca->base + TCA_CLK_RST);
+
+ tca_blk_orientation_set(tca, tca->orientation);
+}
+
+static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
+ struct imx8mq_usb_phy *imx_phy)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct tca_blk *tca;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return NULL;
+
+ tca = devm_kzalloc(dev, sizeof(*tca), GFP_KERNEL);
+ if (!tca)
+ return ERR_PTR(-ENOMEM);
+
+ tca->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tca->base))
+ return ERR_CAST(tca->base);
+
+ mutex_init(&tca->mutex);
+
+ tca->orientation = TYPEC_ORIENTATION_NORMAL;
+ tca->sw = tca_blk_get_typec_switch(pdev, imx_phy);
+
+ return tca;
+}
+
+static void imx95_usb_phy_put_tca(struct imx8mq_usb_phy *imx_phy)
+{
+ struct tca_blk *tca = imx_phy->tca;
+
+ if (!tca)
+ return;
+
+ tca_blk_put_typec_switch(tca->sw);
+}
+
static u32 phy_tx_vref_tune_from_property(u32 percent)
{
percent = clamp(percent, 94U, 124U);
@@ -95,12 +317,12 @@ static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp)
static u32 phy_tx_vboost_level_from_property(u32 microvolt)
{
switch (microvolt) {
- case 0 ... 960:
- return 0;
- case 961 ... 1160:
- return 2;
- default:
+ case 1156:
+ return 5;
+ case 844:
return 3;
+ default:
+ return 4;
}
}
@@ -315,6 +537,9 @@ static int imx8mp_usb_phy_init(struct phy *phy)
imx8m_phy_tune(imx_phy);
+ if (imx_phy->tca)
+ tca_blk_init(imx_phy->tca);
+
return 0;
}
@@ -359,6 +584,8 @@ static const struct of_device_id imx8mq_usb_phy_of_match[] = {
.data = &imx8mq_usb_phy_ops,},
{.compatible = "fsl,imx8mp-usb-phy",
.data = &imx8mp_usb_phy_ops,},
+ {.compatible = "fsl,imx95-usb-phy",
+ .data = &imx8mp_usb_phy_ops,},
{ }
};
MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
@@ -398,6 +625,11 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
phy_set_drvdata(imx_phy->phy, imx_phy);
+ imx_phy->tca = imx95_usb_phy_get_tca(pdev, imx_phy);
+ if (IS_ERR(imx_phy->tca))
+ return dev_err_probe(dev, PTR_ERR(imx_phy->tca),
+ "failed to get tca\n");
+
imx8m_get_phy_tuning_data(imx_phy);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
@@ -405,8 +637,16 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
+static void imx8mq_usb_phy_remove(struct platform_device *pdev)
+{
+ struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev);
+
+ imx95_usb_phy_put_tca(imx_phy);
+}
+
static struct platform_driver imx8mq_usb_phy_driver = {
.probe = imx8mq_usb_phy_probe,
+ .remove = imx8mq_usb_phy_remove,
.driver = {
.name = "imx8mq-usb-phy",
.of_match_table = imx8mq_usb_phy_of_match,
diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
index d3ccf547ba1c..10fbe8dee116 100644
--- a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
+++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
@@ -325,31 +325,26 @@ to_fsl_samsung_hdmi_phy(struct clk_hw *hw)
return container_of(hw, struct fsl_samsung_hdmi_phy, hw);
}
-static void
+static int
fsl_samsung_hdmi_phy_configure_pll_lock_det(struct fsl_samsung_hdmi_phy *phy,
const struct phy_config *cfg)
{
u32 pclk = cfg->pixclk;
u32 fld_tg_code;
- u32 pclk_khz;
- u8 div = 1;
-
- switch (cfg->pixclk) {
- case 22250000 ... 47500000:
- div = 1;
- break;
- case 50349650 ... 99000000:
- div = 2;
- break;
- case 100699300 ... 198000000:
- div = 4;
- break;
- case 205000000 ... 297000000:
- div = 8;
- break;
+ u32 int_pllclk;
+ u8 div;
+
+ /* Find int_pllclk speed */
+ for (div = 0; div < 4; div++) {
+ int_pllclk = pclk / (1 << div);
+ if (int_pllclk < (50 * MHZ))
+ break;
}
- writeb(FIELD_PREP(REG12_CK_DIV_MASK, ilog2(div)), phy->regs + PHY_REG(12));
+ if (unlikely(div == 4))
+ return -EINVAL;
+
+ writeb(FIELD_PREP(REG12_CK_DIV_MASK, div), phy->regs + PHY_REG(12));
/*
* Calculation for the frequency lock detector target code (fld_tg_code)
@@ -362,10 +357,8 @@ fsl_samsung_hdmi_phy_configure_pll_lock_det(struct fsl_samsung_hdmi_phy *phy,
* settings rounding up always too. TODO: Check if that is
* correct.
*/
- pclk /= div;
- pclk_khz = pclk / 1000;
- fld_tg_code = 256 * 1000 * 1000 / pclk_khz * 24;
- fld_tg_code = DIV_ROUND_UP(fld_tg_code, 1000);
+
+ fld_tg_code = DIV_ROUND_UP(24 * MHZ * 256, int_pllclk);
/* FLD_TOL and FLD_RP_CODE taken from downstream driver */
writeb(FIELD_PREP(REG13_TG_CODE_LOW_MASK, fld_tg_code),
@@ -374,6 +367,8 @@ fsl_samsung_hdmi_phy_configure_pll_lock_det(struct fsl_samsung_hdmi_phy *phy,
FIELD_PREP(REG14_RP_CODE_MASK, 2) |
FIELD_PREP(REG14_TG_CODE_HIGH_MASK, fld_tg_code >> 8),
phy->regs + PHY_REG(14));
+
+ return 0;
}
static unsigned long fsl_samsung_hdmi_phy_find_pms(unsigned long fout, u8 *p, u16 *m, u8 *s)
@@ -406,16 +401,15 @@ static unsigned long fsl_samsung_hdmi_phy_find_pms(unsigned long fout, u8 *p, u1
continue;
/*
- * TODO: Ref Manual doesn't state the range of _m
- * so this should be further refined if possible.
- * This range was set based on the original values
- * in the lookup table
+ * The Ref manual doesn't explicitly state the range of M,
+ * but it does show it as an 8-bit value, so reject
+ * any value above 255.
*/
tmp = (u64)fout * (_p * _s);
do_div(tmp, 24 * MHZ);
- _m = tmp;
- if (_m < 0x30 || _m > 0x7b)
+ if (tmp > 255)
continue;
+ _m = tmp;
/*
* Rev 2 of the Ref Manual states the
@@ -440,9 +434,13 @@ static unsigned long fsl_samsung_hdmi_phy_find_pms(unsigned long fout, u8 *p, u1
min_delta = delta;
best_freq = tmp;
}
+
+ /* If we have an exact match, stop looking for a better value */
+ if (!delta)
+ goto done;
}
}
-
+done:
if (best_freq) {
*p = best_p;
*m = best_m;
@@ -473,7 +471,11 @@ static int fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy,
writeb(REG21_SEL_TX_CK_INV | FIELD_PREP(REG21_PMS_S_MASK,
cfg->pll_div_regs[2] >> 4), phy->regs + PHY_REG(21));
- fsl_samsung_hdmi_phy_configure_pll_lock_det(phy, cfg);
+ ret = fsl_samsung_hdmi_phy_configure_pll_lock_det(phy, cfg);
+ if (ret) {
+ dev_err(phy->dev, "pixclock too large\n");
+ return ret;
+ }
writeb(REG33_FIX_DA | REG33_MODE_SET_DONE, phy->regs + PHY_REG(33));
@@ -666,7 +668,7 @@ static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev)
if (IS_ERR(phy->regs))
return PTR_ERR(phy->regs);
- phy->apbclk = devm_clk_get(phy->dev, "apb");
+ phy->apbclk = devm_clk_get_enabled(phy->dev, "apb");
if (IS_ERR(phy->apbclk))
return dev_err_probe(phy->dev, PTR_ERR(phy->apbclk),
"failed to get apb clk\n");
@@ -676,12 +678,6 @@ static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev)
return dev_err_probe(phy->dev, PTR_ERR(phy->refclk),
"failed to get ref clk\n");
- ret = clk_prepare_enable(phy->apbclk);
- if (ret) {
- dev_err(phy->dev, "failed to enable apbclk\n");
- return ret;
- }
-
pm_runtime_get_noresume(phy->dev);
pm_runtime_set_active(phy->dev);
pm_runtime_enable(phy->dev);
@@ -697,8 +693,6 @@ static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev)
return 0;
register_clk_failed:
- clk_disable_unprepare(phy->apbclk);
-
return ret;
}
diff --git a/drivers/phy/hisilicon/phy-hi3670-pcie.c b/drivers/phy/hisilicon/phy-hi3670-pcie.c
index 0ac9634b398d..dbc7dcce682b 100644
--- a/drivers/phy/hisilicon/phy-hi3670-pcie.c
+++ b/drivers/phy/hisilicon/phy-hi3670-pcie.c
@@ -16,15 +16,20 @@
*/
#include <linux/bitfield.h>
+#include <linux/bits.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
-#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
#include <linux/mfd/syscon.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of_gpio.h>
+#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
+#include <linux/types.h>
#define AXI_CLK_FREQ 207500000
#define REF_CLK_FREQ 100000000
diff --git a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c
index fefc02d921e6..71f9c14fb50d 100644
--- a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c
+++ b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c
@@ -422,7 +422,7 @@ static int mvebu_comphy_ethernet_init_reset(struct mvebu_comphy_lane *lane)
/* wait until clocks are ready */
mdelay(1);
- /* exlicitly disable 40B, the bits isn't clear on reset */
+ /* explicitly disable 40B, the bits isn't clear on reset */
regmap_read(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), &val);
val &= ~MVEBU_COMPHY_CONF6_40B;
regmap_write(priv->regmap, MVEBU_COMPHY_CONF6(lane->id), val);
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
index bbfe11d6a69d..b38f3ae26b3f 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.c
@@ -9,6 +9,8 @@
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/of_regulator.h>
#include <linux/types.h>
#include <linux/units.h>
#include <linux/nvmem-consumer.h>
@@ -478,8 +480,50 @@ static int mtk_hdmi_phy_configure(struct phy *phy, union phy_configure_opts *opt
return ret;
}
+static int mtk_hdmi_phy_pwr5v_enable(struct regulator_dev *rdev)
+{
+ struct mtk_hdmi_phy *hdmi_phy = rdev_get_drvdata(rdev);
+
+ mtk_phy_set_bits(hdmi_phy->regs + HDMI_CTL_1, RG_HDMITX_PWR5V_O);
+
+ return 0;
+}
+
+static int mtk_hdmi_phy_pwr5v_disable(struct regulator_dev *rdev)
+{
+ struct mtk_hdmi_phy *hdmi_phy = rdev_get_drvdata(rdev);
+
+ mtk_phy_clear_bits(hdmi_phy->regs + HDMI_CTL_1, RG_HDMITX_PWR5V_O);
+
+ return 0;
+}
+
+static int mtk_hdmi_phy_pwr5v_is_enabled(struct regulator_dev *rdev)
+{
+ struct mtk_hdmi_phy *hdmi_phy = rdev_get_drvdata(rdev);
+
+ return !!(readl(hdmi_phy->regs + HDMI_CTL_1) & RG_HDMITX_PWR5V_O);
+}
+
+static const struct regulator_ops mtk_hdmi_pwr5v_regulator_ops = {
+ .enable = mtk_hdmi_phy_pwr5v_enable,
+ .disable = mtk_hdmi_phy_pwr5v_disable,
+ .is_enabled = mtk_hdmi_phy_pwr5v_is_enabled
+};
+
+static const struct regulator_desc mtk_hdmi_phy_pwr5v_desc = {
+ .name = "hdmi-pwr5v",
+ .id = -1,
+ .n_voltages = 1,
+ .fixed_uV = 5000000,
+ .ops = &mtk_hdmi_pwr5v_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+};
+
struct mtk_hdmi_phy_conf mtk_hdmi_phy_8195_conf = {
.flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
+ .hdmi_phy_regulator_desc = &mtk_hdmi_phy_pwr5v_desc,
.hdmi_phy_clk_ops = &mtk_hdmi_pll_ops,
.hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds,
.hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds,
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h
index 22a68dc9550c..e26caaf4d104 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h
+++ b/drivers/phy/mediatek/phy-mtk-hdmi-mt8195.h
@@ -103,6 +103,9 @@
#define HDMI_ANA_CTL 0x7c
#define REG_ANA_HDMI20_FIFO_EN BIT(16)
+#define HDMI_CTL_1 0xc4
+#define RG_HDMITX_PWR5V_O BIT(9)
+
#define HDMI_CTL_3 0xcc
#define REG_HDMITXPLL_DIV GENMASK(4, 0)
#define REG_HDMITX_REF_XTAL_SEL BIT(7)
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.c b/drivers/phy/mediatek/phy-mtk-hdmi.c
index d2e824771f9d..52a7d525ff9b 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi.c
+++ b/drivers/phy/mediatek/phy-mtk-hdmi.c
@@ -75,6 +75,28 @@ static void mtk_hdmi_phy_clk_get_data(struct mtk_hdmi_phy *hdmi_phy,
clk_init->ops = hdmi_phy->conf->hdmi_phy_clk_ops;
}
+static int mtk_hdmi_phy_register_regulators(struct mtk_hdmi_phy *hdmi_phy)
+{
+ const struct regulator_desc *vreg_desc = hdmi_phy->conf->hdmi_phy_regulator_desc;
+ const struct regulator_init_data vreg_init_data = {
+ .constraints = {
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ }
+ };
+ struct regulator_config vreg_config = {
+ .dev = hdmi_phy->dev,
+ .driver_data = hdmi_phy,
+ .init_data = &vreg_init_data,
+ .of_node = hdmi_phy->dev->of_node
+ };
+
+ hdmi_phy->rdev = devm_regulator_register(hdmi_phy->dev, vreg_desc, &vreg_config);
+ if (IS_ERR(hdmi_phy->rdev))
+ return PTR_ERR(hdmi_phy->rdev);
+
+ return 0;
+}
+
static int mtk_hdmi_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -150,6 +172,12 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev)
if (hdmi_phy->conf->pll_default_off)
hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy);
+ if (hdmi_phy->conf->hdmi_phy_regulator_desc) {
+ ret = mtk_hdmi_phy_register_regulators(hdmi_phy);
+ if (ret)
+ return ret;
+ }
+
return of_clk_add_provider(dev->of_node, of_clk_src_simple_get,
hdmi_phy->pll);
}
diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.h b/drivers/phy/mediatek/phy-mtk-hdmi.h
index 71c02d043485..99d917e0036a 100644
--- a/drivers/phy/mediatek/phy-mtk-hdmi.h
+++ b/drivers/phy/mediatek/phy-mtk-hdmi.h
@@ -13,6 +13,8 @@
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
#include <linux/types.h>
struct mtk_hdmi_phy;
@@ -20,6 +22,7 @@ struct mtk_hdmi_phy;
struct mtk_hdmi_phy_conf {
unsigned long flags;
bool pll_default_off;
+ const struct regulator_desc *hdmi_phy_regulator_desc;
const struct clk_ops *hdmi_phy_clk_ops;
void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy);
void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy);
@@ -32,6 +35,7 @@ struct mtk_hdmi_phy {
struct mtk_hdmi_phy_conf *conf;
struct clk *pll;
struct clk_hw pll_hw;
+ struct regulator_dev *rdev;
unsigned long pll_rate;
unsigned char drv_imp_clk;
unsigned char drv_imp_d2;
diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c
index 3f7095ec5978..644a34bd2b0b 100644
--- a/drivers/phy/mediatek/phy-mtk-tphy.c
+++ b/drivers/phy/mediatek/phy-mtk-tphy.c
@@ -381,17 +381,12 @@ static const char *const u3_phy_files[] = {
static int u2_phy_params_show(struct seq_file *sf, void *unused)
{
struct mtk_phy_instance *inst = sf->private;
- const char *fname = file_dentry(sf->file)->d_iname;
struct u2phy_banks *u2_banks = &inst->u2_banks;
void __iomem *com = u2_banks->com;
u32 max = 0;
u32 tmp = 0;
u32 val = 0;
- int ret;
-
- ret = match_string(u2_phy_files, ARRAY_SIZE(u2_phy_files), fname);
- if (ret < 0)
- return ret;
+ int ret = debugfs_get_aux_num(sf->file);
switch (ret) {
case U2P_EYE_VRT:
@@ -438,7 +433,7 @@ static int u2_phy_params_show(struct seq_file *sf, void *unused)
break;
}
- seq_printf(sf, "%s : %d [0, %d]\n", fname, val, max);
+ seq_printf(sf, "%s : %d [0, %d]\n", u2_phy_files[ret], val, max);
return 0;
}
@@ -451,23 +446,18 @@ static int u2_phy_params_open(struct inode *inode, struct file *file)
static ssize_t u2_phy_params_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
- const char *fname = file_dentry(file)->d_iname;
struct seq_file *sf = file->private_data;
struct mtk_phy_instance *inst = sf->private;
struct u2phy_banks *u2_banks = &inst->u2_banks;
void __iomem *com = u2_banks->com;
ssize_t rc;
u32 val;
- int ret;
+ int ret = debugfs_get_aux_num(file);
rc = kstrtouint_from_user(ubuf, USER_BUF_LEN(count), 0, &val);
if (rc)
return rc;
- ret = match_string(u2_phy_files, ARRAY_SIZE(u2_phy_files), fname);
- if (ret < 0)
- return (ssize_t)ret;
-
switch (ret) {
case U2P_EYE_VRT:
mtk_phy_update_field(com + U3P_USBPHYACR1, PA1_RG_VRT_SEL, val);
@@ -516,23 +506,18 @@ static void u2_phy_dbgfs_files_create(struct mtk_phy_instance *inst)
int i;
for (i = 0; i < count; i++)
- debugfs_create_file(u2_phy_files[i], 0644, inst->phy->debugfs,
- inst, &u2_phy_fops);
+ debugfs_create_file_aux_num(u2_phy_files[i], 0644, inst->phy->debugfs,
+ inst, i, &u2_phy_fops);
}
static int u3_phy_params_show(struct seq_file *sf, void *unused)
{
struct mtk_phy_instance *inst = sf->private;
- const char *fname = file_dentry(sf->file)->d_iname;
struct u3phy_banks *u3_banks = &inst->u3_banks;
u32 val = 0;
u32 max = 0;
u32 tmp;
- int ret;
-
- ret = match_string(u3_phy_files, ARRAY_SIZE(u3_phy_files), fname);
- if (ret < 0)
- return ret;
+ int ret = debugfs_get_aux_num(sf->file);
switch (ret) {
case U3P_EFUSE_EN:
@@ -564,7 +549,7 @@ static int u3_phy_params_show(struct seq_file *sf, void *unused)
break;
}
- seq_printf(sf, "%s : %d [0, %d]\n", fname, val, max);
+ seq_printf(sf, "%s : %d [0, %d]\n", u3_phy_files[ret], val, max);
return 0;
}
@@ -577,23 +562,18 @@ static int u3_phy_params_open(struct inode *inode, struct file *file)
static ssize_t u3_phy_params_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
- const char *fname = file_dentry(file)->d_iname;
struct seq_file *sf = file->private_data;
struct mtk_phy_instance *inst = sf->private;
struct u3phy_banks *u3_banks = &inst->u3_banks;
void __iomem *phyd = u3_banks->phyd;
ssize_t rc;
u32 val;
- int ret;
+ int ret = debugfs_get_aux_num(sf->file);
rc = kstrtouint_from_user(ubuf, USER_BUF_LEN(count), 0, &val);
if (rc)
return rc;
- ret = match_string(u3_phy_files, ARRAY_SIZE(u3_phy_files), fname);
- if (ret < 0)
- return (ssize_t)ret;
-
switch (ret) {
case U3P_EFUSE_EN:
mtk_phy_update_field(phyd + U3P_U3_PHYD_RSV,
@@ -636,8 +616,8 @@ static void u3_phy_dbgfs_files_create(struct mtk_phy_instance *inst)
int i;
for (i = 0; i < count; i++)
- debugfs_create_file(u3_phy_files[i], 0644, inst->phy->debugfs,
- inst, &u3_phy_fops);
+ debugfs_create_file_aux_num(u3_phy_files[i], 0644, inst->phy->debugfs,
+ inst, i, &u3_phy_fops);
}
static int phy_type_show(struct seq_file *sf, void *unused)
@@ -1215,7 +1195,7 @@ static int phy_type_syscon_get(struct mtk_phy_instance *instance,
int ret;
/* type switch function is optional */
- if (!of_property_read_bool(dn, "mediatek,syscon-type"))
+ if (!of_property_present(dn, "mediatek,syscon-type"))
return 0;
ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type",
@@ -1278,7 +1258,7 @@ static int phy_efuse_get(struct mtk_tphy *tphy, struct mtk_phy_instance *instanc
}
/* software efuse is optional */
- instance->efuse_sw_en = device_property_read_bool(dev, "nvmem-cells");
+ instance->efuse_sw_en = device_property_present(dev, "nvmem-cells");
if (!instance->efuse_sw_en)
return 0;
diff --git a/drivers/phy/microchip/Kconfig b/drivers/phy/microchip/Kconfig
index 38039ed0754c..2f0045e874ac 100644
--- a/drivers/phy/microchip/Kconfig
+++ b/drivers/phy/microchip/Kconfig
@@ -15,6 +15,7 @@ config PHY_SPARX5_SERDES
config PHY_LAN966X_SERDES
tristate "SerDes PHY driver for Microchip LAN966X"
select GENERIC_PHY
+ depends on SOC_LAN966 || MCHP_LAN966X_PCI || COMPILE_TEST
depends on OF
depends on MFD_SYSCON
help
diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c
index 152344e4f7e4..fd0e0cd1c1cf 100644
--- a/drivers/phy/motorola/phy-mapphone-mdm6600.c
+++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c
@@ -177,9 +177,7 @@ static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val)
values[0] = val;
- gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES,
- ddata->cmd_gpios->desc,
- ddata->cmd_gpios->info, values);
+ gpiod_multi_set_value_cansleep(ddata->cmd_gpios, values);
}
/**
diff --git a/drivers/phy/phy-can-transceiver.c b/drivers/phy/phy-can-transceiver.c
index ee4ce4249698..f59caff4b3d4 100644
--- a/drivers/phy/phy-can-transceiver.c
+++ b/drivers/phy/phy-can-transceiver.c
@@ -93,6 +93,16 @@ static const struct of_device_id can_transceiver_phy_ids[] = {
};
MODULE_DEVICE_TABLE(of, can_transceiver_phy_ids);
+/* Temporary wrapper until the multiplexer subsystem supports optional muxes */
+static inline struct mux_state *
+devm_mux_state_get_optional(struct device *dev, const char *mux_name)
+{
+ if (!of_property_present(dev->of_node, "mux-states"))
+ return NULL;
+
+ return devm_mux_state_get(dev, mux_name);
+}
+
static int can_transceiver_phy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
@@ -103,6 +113,7 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
struct phy *phy;
struct gpio_desc *standby_gpio;
struct gpio_desc *enable_gpio;
+ struct mux_state *mux_state;
u32 max_bitrate = 0;
int err;
@@ -113,15 +124,11 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)
match = of_match_node(can_transceiver_phy_ids, pdev->dev.of_node);
drvdata = match->data;
- if (of_property_read_bool(dev->of_node, "mux-states")) {
- struct mux_state *mux_state;
+ mux_state = devm_mux_state_get_optional(dev, NULL);
+ if (IS_ERR(mux_state))
+ return PTR_ERR(mux_state);
- mux_state = devm_mux_state_get(dev, NULL);
- if (IS_ERR(mux_state))
- return dev_err_probe(&pdev->dev, PTR_ERR(mux_state),
- "failed to get mux\n");
- can_transceiver_phy->mux_state = mux_state;
- }
+ can_transceiver_phy->mux_state = mux_state;
phy = devm_phy_create(dev, dev->of_node,
&can_transceiver_phy_ops);
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 413f76e2d174..8e2daea81666 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -214,30 +214,6 @@ int phy_pm_runtime_put_sync(struct phy *phy)
}
EXPORT_SYMBOL_GPL(phy_pm_runtime_put_sync);
-void phy_pm_runtime_allow(struct phy *phy)
-{
- if (!phy)
- return;
-
- if (!pm_runtime_enabled(&phy->dev))
- return;
-
- pm_runtime_allow(&phy->dev);
-}
-EXPORT_SYMBOL_GPL(phy_pm_runtime_allow);
-
-void phy_pm_runtime_forbid(struct phy *phy)
-{
- if (!phy)
- return;
-
- if (!pm_runtime_enabled(&phy->dev))
- return;
-
- pm_runtime_forbid(&phy->dev);
-}
-EXPORT_SYMBOL_GPL(phy_pm_runtime_forbid);
-
/**
* phy_init - phy internal initialization before phy operation
* @phy: the phy returned by phy_get()
@@ -405,13 +381,14 @@ EXPORT_SYMBOL_GPL(phy_power_off);
int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode)
{
- int ret;
+ int ret = 0;
- if (!phy || !phy->ops->set_mode)
+ if (!phy)
return 0;
mutex_lock(&phy->mutex);
- ret = phy->ops->set_mode(phy, mode, submode);
+ if (phy->ops->set_mode)
+ ret = phy->ops->set_mode(phy, mode, submode);
if (!ret)
phy->attrs.mode = mode;
mutex_unlock(&phy->mutex);
@@ -749,8 +726,8 @@ EXPORT_SYMBOL_GPL(devm_phy_put);
/**
* of_phy_simple_xlate() - returns the phy instance from phy provider
- * @dev: the PHY provider device
- * @args: of_phandle_args (not used here)
+ * @dev: the PHY provider device (not used here)
+ * @args: of_phandle_args
*
* Intended to be used by phy provider for the common case where #phy-cells is
* 0. For other cases where #phy-cells is greater than '0', the phy provider
@@ -760,21 +737,14 @@ EXPORT_SYMBOL_GPL(devm_phy_put);
struct phy *of_phy_simple_xlate(struct device *dev,
const struct of_phandle_args *args)
{
- struct phy *phy;
- struct class_dev_iter iter;
-
- class_dev_iter_init(&iter, &phy_class, NULL, NULL);
- while ((dev = class_dev_iter_next(&iter))) {
- phy = to_phy(dev);
- if (args->np != phy->dev.of_node)
- continue;
+ struct device *target_dev;
- class_dev_iter_exit(&iter);
- return phy;
- }
+ target_dev = class_find_device_by_of_node(&phy_class, args->np);
+ if (!target_dev)
+ return ERR_PTR(-ENODEV);
- class_dev_iter_exit(&iter);
- return ERR_PTR(-ENODEV);
+ put_device(target_dev);
+ return to_phy(target_dev);
}
EXPORT_SYMBOL_GPL(of_phy_simple_xlate);
diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
index 846f8c99547f..c1e0a11ddd76 100644
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -154,6 +154,19 @@ config PHY_QCOM_M31_USB
management. This driver is required even for peripheral only or
host only mode configurations.
+config PHY_QCOM_UNIPHY_PCIE_28LP
+ bool "PCIE UNIPHY 28LP PHY driver"
+ depends on ARCH_QCOM
+ depends on COMMON_CLK
+ depends on HAS_IOMEM
+ depends on OF
+ select GENERIC_PHY
+ help
+ Enable this to support the PCIe UNIPHY 28LP phy transceiver that
+ is used with PCIe controllers on Qualcomm IPQ5332 chips. It
+ handles PHY initialization, clock management required after
+ resetting the hardware and power management.
+
config PHY_QCOM_USB_HS
tristate "Qualcomm USB HS PHY module"
depends on USB_ULPI_BUS
diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile
index eb60e950ad53..42038bc30974 100644
--- a/drivers/phy/qualcomm/Makefile
+++ b/drivers/phy/qualcomm/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_PHY_QCOM_QMP_USB_LEGACY) += phy-qcom-qmp-usb-legacy.o
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
obj-$(CONFIG_PHY_QCOM_SNPS_EUSB2) += phy-qcom-snps-eusb2.o
obj-$(CONFIG_PHY_QCOM_EUSB2_REPEATER) += phy-qcom-eusb2-repeater.o
+obj-$(CONFIG_PHY_QCOM_UNIPHY_PCIE_28LP) += phy-qcom-uniphy-pcie-28lp.o
obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o
obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o
obj-$(CONFIG_PHY_QCOM_USB_HS_28NM) += phy-qcom-usb-hs-28nm.o
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index 3bae39381fd0..b09fa00e9fe7 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -400,6 +400,57 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_pcs_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
};
+static const struct qmp_phy_init_tbl sar2130p_usb3_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x2e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MSB_MODE1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE1, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE1, 0xd5),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE1, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE1_MODE1, 0x25),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE2_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xb7),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xb7),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MSB_MODE0, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xd5),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE1_MODE0, 0x25),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE2_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x31),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_BUF_ENABLE, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_1, 0xb6),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_2, 0x4b),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_AUTO_GAIN_ADJ_CTRL_3, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_ADDITIONAL_MISC, 0x0c),
+};
+
static const struct qmp_phy_init_tbl sm6350_usb3_rx_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
@@ -1730,6 +1781,51 @@ static const struct qmp_combo_offsets qmp_combo_offsets_v5 = {
.dp_dp_phy = 0x2200,
};
+static const struct qmp_phy_cfg sar2130p_usb3dpphy_cfg = {
+ .offsets = &qmp_combo_offsets_v3,
+
+ .serdes_tbl = sar2130p_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(sar2130p_usb3_serdes_tbl),
+ .tx_tbl = sm8550_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(sm8550_usb3_tx_tbl),
+ .rx_tbl = sm8550_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(sm8550_usb3_rx_tbl),
+ .pcs_tbl = sm8550_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(sm8550_usb3_pcs_tbl),
+ .pcs_usb_tbl = sm8550_usb3_pcs_usb_tbl,
+ .pcs_usb_tbl_num = ARRAY_SIZE(sm8550_usb3_pcs_usb_tbl),
+
+ .dp_serdes_tbl = qmp_v6_dp_serdes_tbl,
+ .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl),
+ .dp_tx_tbl = qmp_v6_dp_tx_tbl,
+ .dp_tx_tbl_num = ARRAY_SIZE(qmp_v6_dp_tx_tbl),
+
+ .serdes_tbl_rbr = qmp_v6_dp_serdes_tbl_rbr,
+ .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_rbr),
+ .serdes_tbl_hbr = qmp_v6_dp_serdes_tbl_hbr,
+ .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_hbr),
+ .serdes_tbl_hbr2 = qmp_v6_dp_serdes_tbl_hbr2,
+ .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_hbr2),
+ .serdes_tbl_hbr3 = qmp_v6_dp_serdes_tbl_hbr3,
+ .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v6_dp_serdes_tbl_hbr3),
+
+ .swing_hbr_rbr = &qmp_dp_v5_voltage_swing_hbr_rbr,
+ .pre_emphasis_hbr_rbr = &qmp_dp_v6_pre_emphasis_hbr_rbr,
+ .swing_hbr3_hbr2 = &qmp_dp_v5_voltage_swing_hbr3_hbr2,
+ .pre_emphasis_hbr3_hbr2 = &qmp_dp_v5_pre_emphasis_hbr3_hbr2,
+
+ .dp_aux_init = qmp_v4_dp_aux_init,
+ .configure_dp_tx = qmp_v4_configure_dp_tx,
+ .configure_dp_phy = qmp_v4_configure_dp_phy,
+ .calibrate_dp_phy = qmp_v4_calibrate_dp_phy,
+
+ .regs = qmp_v6_usb3phy_regs_layout,
+ .reset_list = msm8996_usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+};
+
static const struct qmp_phy_cfg sc7180_usb3dpphy_cfg = {
.offsets = &qmp_combo_offsets_v3,
@@ -3768,6 +3864,10 @@ err_node_put:
static const struct of_device_id qmp_combo_of_match_table[] = {
{
+ .compatible = "qcom,sar2130p-qmp-usb3-dp-phy",
+ .data = &sar2130p_usb3dpphy_cfg,
+ },
+ {
.compatible = "qcom,sc7180-qmp-usb3-dp-phy",
.data = &sc7180_usb3dpphy_cfg,
},
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
index 873f2f9844c6..c232b8fe9846 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
@@ -728,6 +728,135 @@ static const struct qmp_phy_init_tbl ipq9574_gen3x2_pcie_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1),
};
+static const struct qmp_phy_init_tbl qcs615_pcie_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0xf),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x1),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x0),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x6),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0xf),
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x0),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x1),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0xa),
+ QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x9),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x4),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x3),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x0),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0xd),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x35),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x2),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x4),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x0),
+ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x1),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0xa),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x1),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x1),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x2),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x0),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x2f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x19),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_EP_DIV, 0x19),
+};
+
+static const struct qmp_phy_init_tbl qcs615_pcie_rx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_ENABLES, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x1),
+ QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x0),
+ QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb),
+ QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b),
+ QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x4),
+ QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN_HALF, 0x4),
+};
+
+static const struct qmp_phy_init_tbl qcs615_pcie_tx_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45),
+ QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x6),
+ QMP_PHY_INIT_CFG(QSERDES_TX_RES_CODE_LANE_OFFSET, 0x2),
+ QMP_PHY_INIT_CFG(QSERDES_TX_RCV_DETECT_LVL_2, 0x12),
+};
+
+static const struct qmp_phy_init_tbl qcs615_pcie_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_ENDPOINT_REFCLK_DRIVE, 0x4),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_OSC_DTCT_ACTIONS, 0x0),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x0),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB, 0x0),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_LP_WAKEUP_DLY_TIME_AUXCLK, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_PLL_LOCK_CHK_DLY_TIME, 0x73),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_SIGDET_CNTRL, 0x7),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_RX_SIGDET_LVL, 0x99),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_TXDEEMPH_M6DB_V0, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V2_PCS_TXDEEMPH_M3P5DB_V0, 0xe),
+};
+
+static const struct qmp_phy_init_tbl qcs8300_qmp_gen4x2_pcie_rx_alt_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_PI_CONTROLS, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B0, 0x9b),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B1, 0xb0),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B2, 0xd2),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B3, 0xf0),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B4, 0x42),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B5, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE_0_1_B6, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B0, 0x9b),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B1, 0xfb),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B2, 0xd2),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B3, 0xec),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B4, 0x43),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B5, 0xdd),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE2_B6, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B0, 0xf3),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B1, 0xf8),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B2, 0xec),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B3, 0xd6),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B4, 0x83),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B5, 0xf5),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MODE_RATE3_B6, 0x5e),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_PHPRE_CTRL, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_0_1, 0x3f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_AUX_DATA_THRESH_BIN_RATE_2_3, 0x37),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_3, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH4_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH5_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH6_RATE3, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH1_RATE210, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH2_RATE210, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_MARG_COARSE_THRESH3_RATE210, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_FO_GAIN_RATE3, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_UCDR_SO_GAIN_RATE3, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_CNTRL1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_VGA_CAL_MAN_VAL, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x7c),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_RX_IDAC_SAOFFSET, 0x10),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_DFE_DAC_ENABLE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_GM_CAL, 0x05),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V5_20_RX_TX_ADAPT_POST_THRESH2, 0x1f),
+};
+
static const struct qmp_phy_init_tbl sdm845_qmp_pcie_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14),
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
@@ -1773,7 +1902,7 @@ static const struct qmp_phy_init_tbl sdx55_qmp_pcie_rc_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00),
};
-static const struct qmp_phy_init_tbl sdx55_qmp_pcie_ep_pcs_misc_tbl[] = {
+static const struct qmp_phy_init_tbl sdx55_qmp_pcie_ep_pcs_lane1_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_SW_CTRL2, 0x00),
QMP_PHY_INIT_CFG(QPHY_V4_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00),
};
@@ -1907,6 +2036,9 @@ static const struct qmp_phy_init_tbl sdx65_qmp_pcie_pcs_misc_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG2, 0x0d),
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG5, 0x02),
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN, 0x2e),
+};
+
+static const struct qmp_phy_init_tbl sdx65_qmp_pcie_pcs_lane1_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_SW_CTRL2, 0x00),
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00),
};
@@ -2582,8 +2714,6 @@ static const struct qmp_phy_init_tbl sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl[] = {
static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x2_pcie_pcs_alt_tbl[] = {
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG4, 0x16),
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_EQ_CONFIG5, 0x22),
- QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_SW_CTRL2, 0x00),
- QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_LANE1_INSIG_MX_CTRL2, 0x00),
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_G3S2_PRE_GAIN, 0x2e),
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_RX_SIGDET_LVL, 0x66),
};
@@ -2724,10 +2854,106 @@ static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x2_pcie_ep_pcs_alt_tbl[] =
QMP_PHY_INIT_CFG(QPHY_V5_20_PCS_INSIG_SW_CTRL7, 0x00),
};
+static const struct qmp_phy_init_tbl sar2130p_qmp_gen3x2_pcie_rc_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x31),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0x4c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_ENABLE1, 0x90),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYS_CLK_CTRL, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x36),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x42),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x82),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x68),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xea),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE1, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE1, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE1, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_SELECT, 0x34),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_ADDITIONAL_MISC_3, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0xa0),
+};
+
+static const struct qmp_phy_init_tbl sar2130p_qmp_gen3x2_pcie_pcs_lane1_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_LANE1_INSIG_SW_CTRL2, 0x01),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_LANE1_INSIG_MX_CTRL2, 0x01),
+};
+
+static const struct qmp_phy_init_tbl sar2130p_qmp_gen3x2_pcie_rc_tx_tbl[] = {
+ QMP_PHY_INIT_CFG_LANE(QSERDES_V6_TX_BIST_MODE_LANENO, 0x00, 2),
+};
+
+static const struct qmp_phy_init_tbl sar2130p_qmp_gen3x2_pcie_rc_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_G12S1_TXDEEMPH_M6DB, 0x17),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_G3S2_PRE_GAIN, 0x2e),
+};
+
+static const struct qmp_phy_init_tbl sar2130p_qmp_gen3x2_pcie_ep_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYS_CLK_CTRL, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x0d),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x42),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0xff),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x19),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE0, 0xfb),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE0, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE1, 0xfb),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE1, 0x03),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORECLK_DIV_MODE1, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MODE, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0xa0),
+};
+
+static const struct qmp_phy_init_tbl sar2130p_qmp_gen3x2_pcie_ep_pcs_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_G12S1_TXDEEMPH_M6DB, 0x17),
+};
+
+static const struct qmp_phy_init_tbl sar2130p_qmp_gen3x2_pcie_ep_pcs_misc_tbl[] = {
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_EQ_CONFIG1, 0x1e),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2, 0x14),
+ QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4, 0x07),
+};
+
struct qmp_pcie_offsets {
u16 serdes;
u16 pcs;
u16 pcs_misc;
+ u16 pcs_lane1;
u16 tx;
u16 rx;
u16 tx2;
@@ -2752,6 +2978,8 @@ struct qmp_phy_cfg_tbls {
int pcs_num;
const struct qmp_phy_init_tbl *pcs_misc;
int pcs_misc_num;
+ const struct qmp_phy_init_tbl *pcs_lane1;
+ int pcs_lane1_num;
const struct qmp_phy_init_tbl *ln_shrd;
int ln_shrd_num;
};
@@ -2811,6 +3039,7 @@ struct qmp_pcie {
void __iomem *serdes;
void __iomem *pcs;
void __iomem *pcs_misc;
+ void __iomem *pcs_lane1;
void __iomem *tx;
void __iomem *rx;
void __iomem *tx2;
@@ -2927,6 +3156,7 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v4_20 = {
.serdes = 0x1000,
.pcs = 0x1200,
.pcs_misc = 0x1600,
+ .pcs_lane1 = 0x1e00,
.tx = 0x0000,
.rx = 0x0200,
.tx2 = 0x0800,
@@ -2957,6 +3187,7 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v5_20 = {
.serdes = 0x1000,
.pcs = 0x1200,
.pcs_misc = 0x1400,
+ .pcs_lane1 = 0x1e00,
.tx = 0x0000,
.rx = 0x0200,
.tx2 = 0x0800,
@@ -3132,6 +3363,65 @@ static const struct qmp_phy_cfg ipq9574_gen3x2_pciephy_cfg = {
.pipe_clock_rate = 250000000,
};
+static const struct qmp_phy_cfg qcs615_pciephy_cfg = {
+ .lanes = 1,
+
+ .offsets = &qmp_pcie_offsets_v2,
+
+ .tbls = {
+ .serdes = qcs615_pcie_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(qcs615_pcie_serdes_tbl),
+ .tx = qcs615_pcie_tx_tbl,
+ .tx_num = ARRAY_SIZE(qcs615_pcie_tx_tbl),
+ .rx = qcs615_pcie_rx_tbl,
+ .rx_num = ARRAY_SIZE(qcs615_pcie_rx_tbl),
+ .pcs = qcs615_pcie_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(qcs615_pcie_pcs_tbl),
+ },
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = pciephy_v2_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
+};
+
+static const struct qmp_phy_cfg qcs8300_qmp_gen4x2_pciephy_cfg = {
+ .lanes = 2,
+ .offsets = &qmp_pcie_offsets_v5_20,
+
+ .tbls = {
+ .serdes = sa8775p_qmp_gen4x2_pcie_serdes_alt_tbl,
+ .serdes_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_serdes_alt_tbl),
+ .tx = sa8775p_qmp_gen4_pcie_tx_tbl,
+ .tx_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_tx_tbl),
+ .rx = qcs8300_qmp_gen4x2_pcie_rx_alt_tbl,
+ .rx_num = ARRAY_SIZE(qcs8300_qmp_gen4x2_pcie_rx_alt_tbl),
+ .pcs = sa8775p_qmp_gen4x2_pcie_pcs_alt_tbl,
+ .pcs_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_pcs_alt_tbl),
+ .pcs_misc = sa8775p_qmp_gen4_pcie_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_pcs_misc_tbl),
+ },
+
+ .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+ .serdes = sa8775p_qmp_gen4x2_pcie_rc_serdes_alt_tbl,
+ .serdes_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_rc_serdes_alt_tbl),
+ .pcs_misc = sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl),
+ },
+
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = pciephy_v5_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS_4_20,
+};
+
static const struct qmp_phy_cfg sdm845_qmp_pciephy_cfg = {
.lanes = 1,
@@ -3283,6 +3573,49 @@ static const struct qmp_phy_cfg msm8998_pciephy_cfg = {
.skip_start_delay = true,
};
+static const struct qmp_phy_cfg sar2130p_qmp_gen3x2_pciephy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_pcie_offsets_v5,
+
+ .tbls = {
+ .tx = sm8550_qmp_gen3x2_pcie_tx_tbl,
+ .tx_num = ARRAY_SIZE(sm8550_qmp_gen3x2_pcie_tx_tbl),
+ .rx = sm8550_qmp_gen3x2_pcie_rx_tbl,
+ .rx_num = ARRAY_SIZE(sm8550_qmp_gen3x2_pcie_rx_tbl),
+ .pcs = sm8550_qmp_gen3x2_pcie_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sm8550_qmp_gen3x2_pcie_pcs_tbl),
+ .pcs_lane1 = sar2130p_qmp_gen3x2_pcie_pcs_lane1_tbl,
+ .pcs_lane1_num = ARRAY_SIZE(sar2130p_qmp_gen3x2_pcie_pcs_lane1_tbl),
+ },
+ .tbls_rc = &(const struct qmp_phy_cfg_tbls) {
+ .serdes = sar2130p_qmp_gen3x2_pcie_rc_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sar2130p_qmp_gen3x2_pcie_rc_serdes_tbl),
+ .tx = sar2130p_qmp_gen3x2_pcie_rc_tx_tbl,
+ .tx_num = ARRAY_SIZE(sar2130p_qmp_gen3x2_pcie_rc_tx_tbl),
+ .pcs = sar2130p_qmp_gen3x2_pcie_rc_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sar2130p_qmp_gen3x2_pcie_rc_pcs_tbl),
+ .pcs_misc = sm8550_qmp_gen3x2_pcie_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sm8550_qmp_gen3x2_pcie_pcs_misc_tbl),
+ },
+ .tbls_ep = &(const struct qmp_phy_cfg_tbls) {
+ .serdes = sar2130p_qmp_gen3x2_pcie_ep_serdes_tbl,
+ .serdes_num = ARRAY_SIZE(sar2130p_qmp_gen3x2_pcie_ep_serdes_tbl),
+ .pcs = sar2130p_qmp_gen3x2_pcie_ep_pcs_tbl,
+ .pcs_num = ARRAY_SIZE(sar2130p_qmp_gen3x2_pcie_ep_pcs_tbl),
+ .pcs_misc = sar2130p_qmp_gen3x2_pcie_ep_pcs_misc_tbl,
+ .pcs_misc_num = ARRAY_SIZE(sar2130p_qmp_gen3x2_pcie_ep_pcs_misc_tbl),
+ },
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = pciephy_v5_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS,
+};
+
static const struct qmp_phy_cfg sc8180x_pciephy_cfg = {
.lanes = 2,
@@ -3440,8 +3773,8 @@ static const struct qmp_phy_cfg sdx55_qmp_pciephy_cfg = {
.tbls_ep = &(const struct qmp_phy_cfg_tbls) {
.serdes = sdx55_qmp_pcie_ep_serdes_tbl,
.serdes_num = ARRAY_SIZE(sdx55_qmp_pcie_ep_serdes_tbl),
- .pcs_misc = sdx55_qmp_pcie_ep_pcs_misc_tbl,
- .pcs_misc_num = ARRAY_SIZE(sdx55_qmp_pcie_ep_pcs_misc_tbl),
+ .pcs_lane1 = sdx55_qmp_pcie_ep_pcs_lane1_tbl,
+ .pcs_lane1_num = ARRAY_SIZE(sdx55_qmp_pcie_ep_pcs_lane1_tbl),
},
.reset_list = sdm845_pciephy_reset_l,
@@ -3540,6 +3873,8 @@ static const struct qmp_phy_cfg sdx65_qmp_pciephy_cfg = {
.pcs_num = ARRAY_SIZE(sdx65_qmp_pcie_pcs_tbl),
.pcs_misc = sdx65_qmp_pcie_pcs_misc_tbl,
.pcs_misc_num = ARRAY_SIZE(sdx65_qmp_pcie_pcs_misc_tbl),
+ .pcs_lane1 = sdx65_qmp_pcie_pcs_lane1_tbl,
+ .pcs_lane1_num = ARRAY_SIZE(sdx65_qmp_pcie_pcs_lane1_tbl),
},
.reset_list = sdm845_pciephy_reset_l,
.num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
@@ -3739,6 +4074,8 @@ static const struct qmp_phy_cfg sa8775p_qmp_gen4x2_pciephy_cfg = {
.pcs_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_pcs_alt_tbl),
.pcs_misc = sa8775p_qmp_gen4_pcie_pcs_misc_tbl,
.pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_pcs_misc_tbl),
+ .pcs_lane1 = sdx65_qmp_pcie_pcs_lane1_tbl,
+ .pcs_lane1_num = ARRAY_SIZE(sdx65_qmp_pcie_pcs_lane1_tbl),
},
.tbls_rc = &(const struct qmp_phy_cfg_tbls) {
@@ -3905,6 +4242,21 @@ static const struct qmp_phy_cfg x1e80100_qmp_gen4x8_pciephy_cfg = {
.has_nocsr_reset = true,
};
+static const struct qmp_phy_cfg qmp_v6_gen4x4_pciephy_cfg = {
+ .lanes = 4,
+
+ .offsets = &qmp_pcie_offsets_v6_20,
+
+ .reset_list = sdm845_pciephy_reset_l,
+ .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = pciephy_v6_regs_layout,
+
+ .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL,
+ .phy_status = PHYSTATUS_4_20,
+};
+
static void qmp_pcie_init_port_b(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
@@ -3945,6 +4297,7 @@ static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_c
void __iomem *rx2 = qmp->rx2;
void __iomem *pcs = qmp->pcs;
void __iomem *pcs_misc = qmp->pcs_misc;
+ void __iomem *pcs_lane1 = qmp->pcs_lane1;
void __iomem *ln_shrd = qmp->ln_shrd;
if (!tbls)
@@ -3969,6 +4322,7 @@ static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_c
qmp_configure(qmp->dev, pcs, tbls->pcs, tbls->pcs_num);
qmp_configure(qmp->dev, pcs_misc, tbls->pcs_misc, tbls->pcs_misc_num);
+ qmp_configure(qmp->dev, pcs_lane1, tbls->pcs_lane1, tbls->pcs_lane1_num);
if (cfg->lanes >= 4 && qmp->tcsr_4ln_config) {
qmp_configure(qmp->dev, serdes, cfg->serdes_4ln_tbl,
@@ -4420,6 +4774,14 @@ static int qmp_pcie_parse_dt_legacy(struct qmp_pcie *qmp, struct device_node *np
}
}
+ /*
+ * For all platforms where legacy bindings existed, PCS_LANE1 was
+ * mapped as a part of the PCS_MISC region.
+ */
+ if (!IS_ERR(qmp->pcs_misc) && cfg->offsets->pcs_lane1 != 0)
+ qmp->pcs_lane1 = qmp->pcs_misc +
+ (cfg->offsets->pcs_lane1 - cfg->offsets->pcs_misc);
+
clk = devm_get_clk_from_child(dev, np, NULL);
if (IS_ERR(clk)) {
return dev_err_probe(dev, PTR_ERR(clk),
@@ -4487,6 +4849,7 @@ static int qmp_pcie_parse_dt(struct qmp_pcie *qmp)
qmp->serdes = base + offs->serdes;
qmp->pcs = base + offs->pcs;
qmp->pcs_misc = base + offs->pcs_misc;
+ qmp->pcs_lane1 = base + offs->pcs_lane1;
qmp->tx = base + offs->tx;
qmp->rx = base + offs->rx;
@@ -4612,12 +4975,21 @@ static const struct of_device_id qmp_pcie_of_match_table[] = {
.compatible = "qcom,msm8998-qmp-pcie-phy",
.data = &msm8998_pciephy_cfg,
}, {
+ .compatible = "qcom,qcs615-qmp-gen3x1-pcie-phy",
+ .data = &qcs615_pciephy_cfg,
+ }, {
+ .compatible = "qcom,qcs8300-qmp-gen4x2-pcie-phy",
+ .data = &qcs8300_qmp_gen4x2_pciephy_cfg,
+ }, {
.compatible = "qcom,sa8775p-qmp-gen4x2-pcie-phy",
.data = &sa8775p_qmp_gen4x2_pciephy_cfg,
}, {
.compatible = "qcom,sa8775p-qmp-gen4x4-pcie-phy",
.data = &sa8775p_qmp_gen4x4_pciephy_cfg,
}, {
+ .compatible = "qcom,sar2130p-qmp-gen3x2-pcie-phy",
+ .data = &sar2130p_qmp_gen3x2_pciephy_cfg,
+ }, {
.compatible = "qcom,sc8180x-qmp-pcie-phy",
.data = &sc8180x_pciephy_cfg,
}, {
@@ -4692,6 +5064,9 @@ static const struct of_device_id qmp_pcie_of_match_table[] = {
}, {
.compatible = "qcom,x1e80100-qmp-gen4x8-pcie-phy",
.data = &x1e80100_qmp_gen4x8_pciephy_cfg,
+ }, {
+ .compatible = "qcom,x1p42100-qmp-gen4x4-pcie-phy",
+ .data = &qmp_v6_gen4x4_pciephy_cfg,
},
{ },
};
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h
index ac872a9eff9a..ab892d1067c2 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v4_20.h
@@ -13,7 +13,8 @@
#define QPHY_V4_20_PCS_PCIE_G4_RXEQEVAL_TIME 0x0f4
#define QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG2 0x0fc
#define QPHY_V4_20_PCS_PCIE_G4_EQ_CONFIG5 0x108
-#define QPHY_V4_20_PCS_LANE1_INSIG_SW_CTRL2 0x824
-#define QPHY_V4_20_PCS_LANE1_INSIG_MX_CTRL2 0x828
+
+#define QPHY_V4_20_PCS_LANE1_INSIG_SW_CTRL2 0x024
+#define QPHY_V4_20_PCS_LANE1_INSIG_MX_CTRL2 0x028
#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h
index cdf8c04ea078..283d63c81593 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5_20.h
@@ -17,7 +17,8 @@
#define QPHY_V5_20_PCS_PCIE_G4_EQ_CONFIG5 0x108
#define QPHY_V5_20_PCS_PCIE_G4_PRE_GAIN 0x15c
#define QPHY_V5_20_PCS_PCIE_RX_MARGINING_CONFIG3 0x184
-#define QPHY_V5_20_PCS_LANE1_INSIG_SW_CTRL2 0xa24
-#define QPHY_V5_20_PCS_LANE1_INSIG_MX_CTRL2 0xa28
+
+#define QPHY_V5_20_PCS_LANE1_INSIG_SW_CTRL2 0x024
+#define QPHY_V5_20_PCS_LANE1_INSIG_MX_CTRL2 0x028
#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h
index 0ca79333d942..45397cb3c0c6 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h
@@ -14,4 +14,7 @@
#define QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x20
#define QPHY_PCIE_V6_PCS_PCIE_OSC_DTCT_ACTIONS 0x94
+#define QPHY_PCIE_V6_PCS_LANE1_INSIG_SW_CTRL2 0x024
+#define QPHY_PCIE_V6_PCS_LANE1_INSIG_MX_CTRL2 0x028
+
#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h
index bf36399d0057..1ecf4b5beba6 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v2.h
@@ -34,6 +34,7 @@
#define QPHY_V2_PCS_USB_PCS_STATUS 0x17c /* USB */
#define QPHY_V2_PCS_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB 0x1a8
#define QPHY_V2_PCS_OSC_DTCT_ACTIONS 0x1ac
+#define QPHY_V2_PCS_SIGDET_CNTRL 0x1b0
#define QPHY_V2_PCS_RX_SIGDET_LVL 0x1d8
#define QPHY_V2_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1dc
#define QPHY_V2_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1e0
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6.h
index 08299d2b78f0..aa5afb921f12 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6.h
@@ -17,6 +17,8 @@
#define QPHY_V6_PCS_LOCK_DETECT_CONFIG3 0x0cc
#define QPHY_V6_PCS_LOCK_DETECT_CONFIG6 0x0d8
#define QPHY_V6_PCS_REFGEN_REQ_CONFIG1 0x0dc
+#define QPHY_V6_PCS_G12S1_TXDEEMPH_M6DB 0x168
+#define QPHY_V6_PCS_G3S2_PRE_GAIN 0x170
#define QPHY_V6_PCS_RX_SIGDET_LVL 0x188
#define QPHY_V6_PCS_RCVR_DTCT_DLY_P1U2_L 0x190
#define QPHY_V6_PCS_RCVR_DTCT_DLY_P1U2_H 0x194
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
index 328c6c0b0b09..258f3d30742e 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h
@@ -86,4 +86,11 @@
#define QSERDES_V6_COM_CMN_STATUS 0x1d0
#define QSERDES_V6_COM_C_READY_STATUS 0x1f8
+#define QSERDES_V6_COM_ADAPTIVE_ANALOG_CONFIG 0x268
+#define QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE0 0x26c
+#define QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE0 0x270
+#define QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE0 0x274
+#define QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE1 0x278
+#define QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE1 0x27c
+#define QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE1 0x280
#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v7.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v7.h
new file mode 100644
index 000000000000..3f0522492f85
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v7.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024, Linaro Limited
+ */
+
+#ifndef QCOM_PHY_QMP_QSERDES_TXRX_UFS_V7_H_
+#define QCOM_PHY_QMP_QSERDES_TXRX_UFS_V7_H_
+
+#define QSERDES_UFS_V7_TX_RES_CODE_LANE_TX 0x28
+#define QSERDES_UFS_V7_TX_RES_CODE_LANE_RX 0x2c
+#define QSERDES_UFS_V7_TX_RES_CODE_LANE_OFFSET_TX 0x30
+#define QSERDES_UFS_V7_TX_RES_CODE_LANE_OFFSET_RX 0x34
+#define QSERDES_UFS_V7_TX_LANE_MODE_1 0x7c
+#define QSERDES_UFS_V7_TX_FR_DCC_CTRL 0x108
+
+#define QSERDES_UFS_V7_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10
+#define QSERDES_UFS_V7_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24
+#define QSERDES_UFS_V7_RX_UCDR_SO_SATURATION 0x28
+#define QSERDES_UFS_V7_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54
+#define QSERDES_UFS_V7_RX_UCDR_PI_CTRL1 0x58
+#define QSERDES_UFS_V7_RX_TERM_BW_CTRL0 0xc4
+#define QSERDES_UFS_V7_RX_UCDR_FO_GAIN_RATE2 0xd4
+#define QSERDES_UFS_V7_RX_UCDR_FO_GAIN_RATE4 0xdc
+#define QSERDES_UFS_V7_RX_UCDR_SO_GAIN_RATE4 0xf0
+#define QSERDES_UFS_V7_RX_UCDR_PI_CONTROLS 0xf4
+#define QSERDES_UFS_V7_RX_VGA_CAL_MAN_VAL 0x178
+#define QSERDES_UFS_V7_RX_EQU_ADAPTOR_CNTRL4 0x1b4
+#define QSERDES_UFS_V7_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1cc
+#define QSERDES_UFS_V7_RX_OFFSET_ADAPTOR_CNTRL3 0x1d4
+#define QSERDES_UFS_V7_RX_INTERFACE_MODE 0x1f0
+#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B0 0x218
+#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B1 0x21C
+#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B2 0x220
+#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B3 0x224
+#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B4 0x228
+#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B6 0x230
+#define QSERDES_UFS_V7_RX_MODE_RATE_0_1_B7 0x234
+#define QSERDES_UFS_V7_RX_MODE_RATE2_B3 0x248
+#define QSERDES_UFS_V7_RX_MODE_RATE2_B6 0x254
+#define QSERDES_UFS_V7_RX_MODE_RATE2_B7 0x258
+#define QSERDES_UFS_V7_RX_MODE_RATE3_B0 0x260
+#define QSERDES_UFS_V7_RX_MODE_RATE3_B1 0x264
+#define QSERDES_UFS_V7_RX_MODE_RATE3_B2 0x268
+#define QSERDES_UFS_V7_RX_MODE_RATE3_B3 0x26c
+#define QSERDES_UFS_V7_RX_MODE_RATE3_B4 0x270
+#define QSERDES_UFS_V7_RX_MODE_RATE3_B5 0x274
+#define QSERDES_UFS_V7_RX_MODE_RATE3_B7 0x27c
+#define QSERDES_UFS_V7_RX_MODE_RATE3_B8 0x280
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B0 0x284
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B1 0x288
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B2 0x28c
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B3 0x290
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B4 0x294
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B5 0x298
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B6 0x29c
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SA_B7 0x2a0
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B0 0x2a8
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B1 0x2ac
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B2 0x2b0
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B3 0x2b4
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B4 0x2b8
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B5 0x2bc
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B6 0x2c0
+#define QSERDES_UFS_V7_RX_MODE_RATE4_SB_B7 0x2c4
+#define QSERDES_UFS_V7_RX_DLL0_FTUNE_CTRL 0x348
+#define QSERDES_UFS_V7_RX_SIGDET_CAL_TRIM 0x380
+#endif
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h
index 23ffcfae9efa..f47fdc9cecda 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6.h
@@ -6,6 +6,7 @@
#ifndef QCOM_PHY_QMP_QSERDES_TXRX_USB_V6_H_
#define QCOM_PHY_QMP_QSERDES_TXRX_USB_V6_H_
+#define QSERDES_V6_TX_BIST_MODE_LANENO 0x00
#define QSERDES_V6_TX_CLKBUF_ENABLE 0x08
#define QSERDES_V6_TX_TX_EMP_POST1_LVL 0x0c
#define QSERDES_V6_TX_TX_DRV_LVL 0x14
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
index d964bdfe8700..b33e2e2b5014 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -31,6 +31,7 @@
#include "phy-qcom-qmp-pcs-ufs-v6.h"
#include "phy-qcom-qmp-qserdes-txrx-ufs-v6.h"
+#include "phy-qcom-qmp-qserdes-txrx-ufs-v7.h"
/* QPHY_PCS_READY_STATUS bit */
#define PCS_READY BIT(0)
@@ -949,6 +950,124 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_g5_pcs[] = {
QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e),
};
+static const struct qmp_phy_init_tbl sm8750_ufsphy_serdes[] = {
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0xd9),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x11),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO_MODE1, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x20),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_CTRL, 0x40),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_ADAPTIVE_ANALOG_CONFIG, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE0, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE0, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x7f),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x92),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_ADAPTIVE_MODE1, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCCTRL_ADAPTIVE_MODE1, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_ADAPTIVE_MODE1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xbe),
+ QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x23),
+};
+
+static const struct qmp_phy_init_tbl sm8750_ufsphy_tx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_TX_LANE_MODE_1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_TX_RES_CODE_LANE_OFFSET_TX, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_TX_RES_CODE_LANE_OFFSET_RX, 0x17),
+};
+
+static const struct qmp_phy_init_tbl sm8750_ufsphy_rx[] = {
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FO_GAIN_RATE2, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FO_GAIN_RATE4, 0x0c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_SO_GAIN_RATE4, 0x04),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_PI_CONTROLS, 0x07),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_VGA_CAL_MAN_VAL, 0x8e),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_EQU_ADAPTOR_CNTRL4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B0, 0xce),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B1, 0xce),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B2, 0x18),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B3, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B4, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B6, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE_0_1_B7, 0x62),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE2_B3, 0x9a),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE2_B6, 0xe2),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE2_B7, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B0, 0x1b),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B1, 0x1b),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B2, 0x98),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B3, 0x9b),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B4, 0x2a),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B5, 0x12),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B7, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE3_B8, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B0, 0x93),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B1, 0x93),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B2, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B3, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B4, 0x5f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B5, 0x92),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B6, 0xe3),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SA_B7, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B0, 0x9b),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B1, 0x9b),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B2, 0x60),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B3, 0x99),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B4, 0x5f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B5, 0x92),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B6, 0xfb),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_MODE_RATE4_SB_B7, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_SO_SATURATION, 0x1f),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_UCDR_PI_CTRL1, 0x94),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_TERM_BW_CTRL0, 0xfa),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_DLL0_FTUNE_CTRL, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_UFS_V7_RX_SIGDET_CAL_TRIM, 0x77),
+};
+
+static const struct qmp_phy_init_tbl sm8750_ufsphy_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0x40),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4, 0x0e),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S5, 0x12),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S6, 0x15),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S7, 0x19),
+};
+
+static const struct qmp_phy_init_tbl sm8750_ufsphy_g4_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04),
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04),
+};
+
+static const struct qmp_phy_init_tbl sm8750_ufsphy_hs_b_pcs[] = {
+ QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0x41),
+};
+
struct qmp_ufs_offsets {
u16 serdes;
u16 pcs;
@@ -1523,6 +1642,45 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = {
.regs = ufsphy_v6_regs_layout,
};
+static const struct qmp_phy_cfg sm8750_ufsphy_cfg = {
+ .lanes = 2,
+
+ .offsets = &qmp_ufs_offsets_v6,
+ .max_supported_gear = UFS_HS_G5,
+
+ .tbls = {
+ .serdes = sm8750_ufsphy_serdes,
+ .serdes_num = ARRAY_SIZE(sm8750_ufsphy_serdes),
+ .tx = sm8750_ufsphy_tx,
+ .tx_num = ARRAY_SIZE(sm8750_ufsphy_tx),
+ .rx = sm8750_ufsphy_rx,
+ .rx_num = ARRAY_SIZE(sm8750_ufsphy_rx),
+ .pcs = sm8750_ufsphy_pcs,
+ .pcs_num = ARRAY_SIZE(sm8750_ufsphy_pcs),
+ },
+
+ .tbls_hs_b = {
+ .pcs = sm8750_ufsphy_hs_b_pcs,
+ .pcs_num = ARRAY_SIZE(sm8750_ufsphy_hs_b_pcs),
+ },
+
+ .tbls_hs_overlay[0] = {
+ .pcs = sm8750_ufsphy_g4_pcs,
+ .pcs_num = ARRAY_SIZE(sm8750_ufsphy_g4_pcs),
+ .max_gear = UFS_HS_G4,
+ },
+ .tbls_hs_overlay[1] = {
+ .pcs = sm8650_ufsphy_g5_pcs,
+ .pcs_num = ARRAY_SIZE(sm8650_ufsphy_g5_pcs),
+ .max_gear = UFS_HS_G5,
+ },
+
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = ufsphy_v6_regs_layout,
+
+};
+
static void qmp_ufs_serdes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
{
void __iomem *serdes = qmp->serdes;
@@ -1578,23 +1736,26 @@ static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cf
return ret;
}
+static void qmp_ufs_init_all(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls)
+{
+ qmp_ufs_serdes_init(qmp, tbls);
+ qmp_ufs_lanes_init(qmp, tbls);
+ qmp_ufs_pcs_init(qmp, tbls);
+}
+
static void qmp_ufs_init_registers(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg)
{
int i;
- qmp_ufs_serdes_init(qmp, &cfg->tbls);
- qmp_ufs_lanes_init(qmp, &cfg->tbls);
- qmp_ufs_pcs_init(qmp, &cfg->tbls);
+ qmp_ufs_init_all(qmp, &cfg->tbls);
i = qmp_ufs_get_gear_overlay(qmp, cfg);
if (i >= 0) {
- qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_overlay[i]);
- qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_overlay[i]);
- qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_overlay[i]);
+ qmp_ufs_init_all(qmp, &cfg->tbls_hs_overlay[i]);
}
if (qmp->mode == PHY_MODE_UFS_HS_B)
- qmp_ufs_serdes_init(qmp, &cfg->tbls_hs_b);
+ qmp_ufs_init_all(qmp, &cfg->tbls_hs_b);
}
static int qmp_ufs_com_init(struct qmp_ufs *qmp)
@@ -2061,7 +2222,11 @@ static const struct of_device_id qmp_ufs_of_match_table[] = {
}, {
.compatible = "qcom,sm8650-qmp-ufs-phy",
.data = &sm8650_ufsphy_cfg,
+ }, {
+ .compatible = "qcom,sm8750-qmp-ufs-phy",
+ .data = &sm8750_ufsphy_cfg,
},
+
{ },
};
MODULE_DEVICE_TABLE(of, qmp_ufs_of_match_table);
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
index c9c337840715..ed646a7e705b 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
@@ -2106,12 +2106,16 @@ static void __iomem *qmp_usb_iomap(struct device *dev, struct device_node *np,
int index, bool exclusive)
{
struct resource res;
+ void __iomem *mem;
if (!exclusive) {
if (of_address_to_resource(np, index, &res))
return IOMEM_ERR_PTR(-EINVAL);
- return devm_ioremap(dev, res.start, resource_size(&res));
+ mem = devm_ioremap(dev, res.start, resource_size(&res));
+ if (!mem)
+ return IOMEM_ERR_PTR(-ENOMEM);
+ return mem;
}
return devm_of_iomap(dev, np, index, NULL);
@@ -2298,6 +2302,9 @@ err_node_put:
static const struct of_device_id qmp_usb_of_match_table[] = {
{
+ .compatible = "qcom,ipq5424-qmp-usb3-phy",
+ .data = &ipq9574_usb3phy_cfg,
+ }, {
.compatible = "qcom,ipq6018-qmp-usb3-phy",
.data = &ipq6018_usb3phy_cfg,
}, {
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index cf12a6f12134..5e7fcb26744a 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -1125,6 +1125,9 @@ static const struct of_device_id qmp_usbc_of_match_table[] = {
.compatible = "qcom,qcm2290-qmp-usb3-phy",
.data = &qcm2290_usb3phy_cfg,
}, {
+ .compatible = "qcom,qcs615-qmp-usb3-phy",
+ .data = &qcm2290_usb3phy_cfg,
+ }, {
.compatible = "qcom,sdm660-qmp-usb3-phy",
.data = &sdm660_usb3phy_cfg,
}, {
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c
index c52655a383ce..49c37c53b38e 100644
--- a/drivers/phy/qualcomm/phy-qcom-qusb2.c
+++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c
@@ -151,6 +151,19 @@ static const struct qusb2_phy_init_tbl ipq6018_init_tbl[] = {
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9F),
};
+static const struct qusb2_phy_init_tbl qcs615_init_tbl[] = {
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xc8),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0xb3),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE3, 0x83),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE4, 0xc0),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
+ QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TEST2, 0x14),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
+ QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
+};
+
static const unsigned int ipq6018_regs_layout[] = {
[QUSB2PHY_PLL_STATUS] = 0x38,
[QUSB2PHY_PORT_TUNE1] = 0x80,
@@ -331,6 +344,17 @@ static const struct qusb2_phy_cfg ipq6018_phy_cfg = {
.autoresume_en = BIT(0),
};
+static const struct qusb2_phy_cfg qcs615_phy_cfg = {
+ .tbl = qcs615_init_tbl,
+ .tbl_num = ARRAY_SIZE(qcs615_init_tbl),
+ .regs = ipq6018_regs_layout,
+
+ .disable_ctrl = (CLAMP_N_EN | FREEZIO_N | POWER_DOWN),
+ .mask_core_ready = PLL_LOCKED,
+ /* autoresume not used */
+ .autoresume_en = BIT(0),
+};
+
static const struct qusb2_phy_cfg qusb2_v2_phy_cfg = {
.tbl = qusb2_v2_init_tbl,
.tbl_num = ARRAY_SIZE(qusb2_v2_init_tbl),
@@ -905,6 +929,9 @@ static const struct phy_ops qusb2_phy_gen_ops = {
static const struct of_device_id qusb2_phy_of_match_table[] = {
{
+ .compatible = "qcom,ipq5424-qusb2-phy",
+ .data = &ipq6018_phy_cfg,
+ }, {
.compatible = "qcom,ipq6018-qusb2-phy",
.data = &ipq6018_phy_cfg,
}, {
@@ -923,6 +950,9 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
.compatible = "qcom,msm8998-qusb2-phy",
.data = &msm8998_phy_cfg,
}, {
+ .compatible = "qcom,qcs615-qusb2-phy",
+ .data = &qcs615_phy_cfg,
+ }, {
.compatible = "qcom,qcm2290-qusb2-phy",
.data = &sm6115_phy_cfg,
}, {
diff --git a/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
new file mode 100644
index 000000000000..c8b2a3818880
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2025, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/units.h>
+
+#define RST_ASSERT_DELAY_MIN_US 100
+#define RST_ASSERT_DELAY_MAX_US 150
+#define PIPE_CLK_DELAY_MIN_US 5000
+#define PIPE_CLK_DELAY_MAX_US 5100
+#define CLK_EN_DELAY_MIN_US 30
+#define CLK_EN_DELAY_MAX_US 50
+#define CDR_CTRL_REG_1 0x80
+#define CDR_CTRL_REG_2 0x84
+#define CDR_CTRL_REG_3 0x88
+#define CDR_CTRL_REG_4 0x8c
+#define CDR_CTRL_REG_5 0x90
+#define CDR_CTRL_REG_6 0x94
+#define CDR_CTRL_REG_7 0x98
+#define SSCG_CTRL_REG_1 0x9c
+#define SSCG_CTRL_REG_2 0xa0
+#define SSCG_CTRL_REG_3 0xa4
+#define SSCG_CTRL_REG_4 0xa8
+#define SSCG_CTRL_REG_5 0xac
+#define SSCG_CTRL_REG_6 0xb0
+#define PCS_INTERNAL_CONTROL_2 0x2d8
+
+#define PHY_CFG_PLLCFG 0x220
+#define PHY_CFG_EIOS_DTCT_REG 0x3e4
+#define PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME 0x3e8
+
+enum qcom_uniphy_pcie_type {
+ PHY_TYPE_PCIE = 1,
+ PHY_TYPE_PCIE_GEN2,
+ PHY_TYPE_PCIE_GEN3,
+};
+
+struct qcom_uniphy_pcie_regs {
+ u32 offset;
+ u32 val;
+};
+
+struct qcom_uniphy_pcie_data {
+ int lane_offset; /* offset between the lane register bases */
+ u32 phy_type;
+ const struct qcom_uniphy_pcie_regs *init_seq;
+ u32 init_seq_num;
+ u32 pipe_clk_rate;
+};
+
+struct qcom_uniphy_pcie {
+ struct phy phy;
+ struct device *dev;
+ const struct qcom_uniphy_pcie_data *data;
+ struct clk_bulk_data *clks;
+ int num_clks;
+ struct reset_control *resets;
+ void __iomem *base;
+ int lanes;
+};
+
+#define phy_to_dw_phy(x) container_of((x), struct qca_uni_pcie_phy, phy)
+
+static const struct qcom_uniphy_pcie_regs ipq5332_regs[] = {
+ {
+ .offset = PHY_CFG_PLLCFG,
+ .val = 0x30,
+ }, {
+ .offset = PHY_CFG_EIOS_DTCT_REG,
+ .val = 0x53ef,
+ }, {
+ .offset = PHY_CFG_GEN3_ALIGN_HOLDOFF_TIME,
+ .val = 0xcf,
+ },
+};
+
+static const struct qcom_uniphy_pcie_data ipq5332_data = {
+ .lane_offset = 0x800,
+ .phy_type = PHY_TYPE_PCIE_GEN3,
+ .init_seq = ipq5332_regs,
+ .init_seq_num = ARRAY_SIZE(ipq5332_regs),
+ .pipe_clk_rate = 250 * MEGA,
+};
+
+static void qcom_uniphy_pcie_init(struct qcom_uniphy_pcie *phy)
+{
+ const struct qcom_uniphy_pcie_data *data = phy->data;
+ const struct qcom_uniphy_pcie_regs *init_seq;
+ void __iomem *base = phy->base;
+ int lane, i;
+
+ for (lane = 0; lane < phy->lanes; lane++) {
+ init_seq = data->init_seq;
+
+ for (i = 0; i < data->init_seq_num; i++)
+ writel(init_seq[i].val, base + init_seq[i].offset);
+
+ base += data->lane_offset;
+ }
+}
+
+static int qcom_uniphy_pcie_power_off(struct phy *x)
+{
+ struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
+
+ clk_bulk_disable_unprepare(phy->num_clks, phy->clks);
+
+ return reset_control_assert(phy->resets);
+}
+
+static int qcom_uniphy_pcie_power_on(struct phy *x)
+{
+ struct qcom_uniphy_pcie *phy = phy_get_drvdata(x);
+ int ret;
+
+ ret = reset_control_assert(phy->resets);
+ if (ret) {
+ dev_err(phy->dev, "reset assert failed (%d)\n", ret);
+ return ret;
+ }
+
+ usleep_range(RST_ASSERT_DELAY_MIN_US, RST_ASSERT_DELAY_MAX_US);
+
+ ret = reset_control_deassert(phy->resets);
+ if (ret) {
+ dev_err(phy->dev, "reset deassert failed (%d)\n", ret);
+ return ret;
+ }
+
+ usleep_range(PIPE_CLK_DELAY_MIN_US, PIPE_CLK_DELAY_MAX_US);
+
+ ret = clk_bulk_prepare_enable(phy->num_clks, phy->clks);
+ if (ret) {
+ dev_err(phy->dev, "clk prepare and enable failed %d\n", ret);
+ return ret;
+ }
+
+ usleep_range(CLK_EN_DELAY_MIN_US, CLK_EN_DELAY_MAX_US);
+
+ qcom_uniphy_pcie_init(phy);
+
+ return 0;
+}
+
+static inline int qcom_uniphy_pcie_get_resources(struct platform_device *pdev,
+ struct qcom_uniphy_pcie *phy)
+{
+ struct resource *res;
+
+ phy->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+ if (IS_ERR(phy->base))
+ return PTR_ERR(phy->base);
+
+ phy->num_clks = devm_clk_bulk_get_all(phy->dev, &phy->clks);
+ if (phy->num_clks < 0)
+ return phy->num_clks;
+
+ phy->resets = devm_reset_control_array_get_exclusive(phy->dev);
+ if (IS_ERR(phy->resets))
+ return PTR_ERR(phy->resets);
+
+ return 0;
+}
+
+/*
+ * Register a fixed rate pipe clock.
+ *
+ * The <s>_pipe_clksrc generated by PHY goes to the GCC that gate
+ * controls it. The <s>_pipe_clk coming out of the GCC is requested
+ * by the PHY driver for its operations.
+ * We register the <s>_pipe_clksrc here. The gcc driver takes care
+ * of assigning this <s>_pipe_clksrc as parent to <s>_pipe_clk.
+ * Below picture shows this relationship.
+ *
+ * +---------------+
+ * | PHY block |<<---------------------------------------+
+ * | | |
+ * | +-------+ | +-----+ |
+ * I/P---^-->| PLL |---^--->pipe_clksrc--->| GCC |--->pipe_clk---+
+ * clk | +-------+ | +-----+
+ * +---------------+
+ */
+static inline int phy_pipe_clk_register(struct qcom_uniphy_pcie *phy, int id)
+{
+ const struct qcom_uniphy_pcie_data *data = phy->data;
+ struct clk_hw *hw;
+ char name[64];
+
+ snprintf(name, sizeof(name), "phy%d_pipe_clk_src", id);
+ hw = devm_clk_hw_register_fixed_rate(phy->dev, name, NULL, 0,
+ data->pipe_clk_rate);
+ if (IS_ERR(hw))
+ return dev_err_probe(phy->dev, PTR_ERR(hw),
+ "Unable to register %s\n", name);
+
+ return devm_of_clk_add_hw_provider(phy->dev, of_clk_hw_simple_get, hw);
+}
+
+static const struct of_device_id qcom_uniphy_pcie_id_table[] = {
+ {
+ .compatible = "qcom,ipq5332-uniphy-pcie-phy",
+ .data = &ipq5332_data,
+ }, {
+ /* Sentinel */
+ },
+};
+MODULE_DEVICE_TABLE(of, qcom_uniphy_pcie_id_table);
+
+static const struct phy_ops pcie_ops = {
+ .power_on = qcom_uniphy_pcie_power_on,
+ .power_off = qcom_uniphy_pcie_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int qcom_uniphy_pcie_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct device *dev = &pdev->dev;
+ struct qcom_uniphy_pcie *phy;
+ struct phy *generic_phy;
+ int ret;
+
+ phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, phy);
+ phy->dev = &pdev->dev;
+
+ phy->data = of_device_get_match_data(dev);
+ if (!phy->data)
+ return -EINVAL;
+
+ ret = of_property_read_u32(dev_of_node(dev), "num-lanes", &phy->lanes);
+ if (ret)
+ return dev_err_probe(dev, ret, "Couldn't read num-lanes\n");
+
+ ret = qcom_uniphy_pcie_get_resources(pdev, phy);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to get resources: %d\n", ret);
+
+ generic_phy = devm_phy_create(phy->dev, NULL, &pcie_ops);
+ if (IS_ERR(generic_phy))
+ return PTR_ERR(generic_phy);
+
+ phy_set_drvdata(generic_phy, phy);
+
+ ret = phy_pipe_clk_register(phy, generic_phy->id);
+ if (ret)
+ dev_err(&pdev->dev, "failed to register phy pipe clk\n");
+
+ phy_provider = devm_of_phy_provider_register(phy->dev,
+ of_phy_simple_xlate);
+ if (IS_ERR(phy_provider))
+ return PTR_ERR(phy_provider);
+
+ return 0;
+}
+
+static struct platform_driver qcom_uniphy_pcie_driver = {
+ .probe = qcom_uniphy_pcie_probe,
+ .driver = {
+ .name = "qcom-uniphy-pcie",
+ .of_match_table = qcom_uniphy_pcie_id_table,
+ },
+};
+
+module_platform_driver(qcom_uniphy_pcie_driver);
+
+MODULE_DESCRIPTION("PCIE QCOM UNIPHY driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
index 775f4f973a6c..9fdf17e0848a 100644
--- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c
@@ -9,6 +9,7 @@
* Copyright (C) 2014 Cogent Embedded, Inc.
*/
+#include <linux/cleanup.h>
#include <linux/extcon-provider.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@@ -107,7 +108,6 @@ struct rcar_gen3_phy {
struct rcar_gen3_chan *ch;
u32 int_enable_bits;
bool initialized;
- bool otg_initialized;
bool powered;
};
@@ -119,9 +119,8 @@ struct rcar_gen3_chan {
struct regulator *vbus;
struct reset_control *rstc;
struct work_struct work;
- struct mutex lock; /* protects rphys[...].powered */
+ spinlock_t lock; /* protects access to hardware and driver data structure. */
enum usb_dr_mode dr_mode;
- int irq;
u32 obint_enable_bits;
bool extcon_host;
bool is_otg_channel;
@@ -320,16 +319,15 @@ static bool rcar_gen3_is_any_rphy_initialized(struct rcar_gen3_chan *ch)
return false;
}
-static bool rcar_gen3_needs_init_otg(struct rcar_gen3_chan *ch)
+static bool rcar_gen3_is_any_otg_rphy_initialized(struct rcar_gen3_chan *ch)
{
- int i;
-
- for (i = 0; i < NUM_OF_PHYS; i++) {
- if (ch->rphys[i].otg_initialized)
- return false;
+ for (enum rcar_gen3_phy_index i = PHY_INDEX_BOTH_HC; i <= PHY_INDEX_EHCI;
+ i++) {
+ if (ch->rphys[i].initialized)
+ return true;
}
- return true;
+ return false;
}
static bool rcar_gen3_are_all_rphys_power_off(struct rcar_gen3_chan *ch)
@@ -351,7 +349,9 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,
bool is_b_device;
enum phy_mode cur_mode, new_mode;
- if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch))
+ guard(spinlock_irqsave)(&ch->lock);
+
+ if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch))
return -EIO;
if (sysfs_streq(buf, "host"))
@@ -389,7 +389,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,
{
struct rcar_gen3_chan *ch = dev_get_drvdata(dev);
- if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch))
+ if (!ch->is_otg_channel || !rcar_gen3_is_any_otg_rphy_initialized(ch))
return -EIO;
return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" :
@@ -402,6 +402,9 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
void __iomem *usb2_base = ch->base;
u32 val;
+ if (!ch->is_otg_channel || rcar_gen3_is_any_otg_rphy_initialized(ch))
+ return;
+
/* Should not use functions of read-modify-write a register */
val = readl(usb2_base + USB2_LINECTRL1);
val = (val & ~USB2_LINECTRL1_DP_RPD) | USB2_LINECTRL1_DPRPD_EN |
@@ -415,7 +418,7 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch)
val = readl(usb2_base + USB2_ADPCTRL);
writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL);
}
- msleep(20);
+ mdelay(20);
writel(0xffffffff, usb2_base + USB2_OBINTSTA);
writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN);
@@ -427,16 +430,27 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch)
{
struct rcar_gen3_chan *ch = _ch;
void __iomem *usb2_base = ch->base;
- u32 status = readl(usb2_base + USB2_OBINTSTA);
+ struct device *dev = ch->dev;
irqreturn_t ret = IRQ_NONE;
+ u32 status;
+
+ pm_runtime_get_noresume(dev);
+
+ if (pm_runtime_suspended(dev))
+ goto rpm_put;
- if (status & ch->obint_enable_bits) {
- dev_vdbg(ch->dev, "%s: %08x\n", __func__, status);
- writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA);
- rcar_gen3_device_recognition(ch);
- ret = IRQ_HANDLED;
+ scoped_guard(spinlock, &ch->lock) {
+ status = readl(usb2_base + USB2_OBINTSTA);
+ if (status & ch->obint_enable_bits) {
+ dev_vdbg(dev, "%s: %08x\n", __func__, status);
+ writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA);
+ rcar_gen3_device_recognition(ch);
+ ret = IRQ_HANDLED;
+ }
}
+rpm_put:
+ pm_runtime_put_noidle(dev);
return ret;
}
@@ -446,32 +460,23 @@ static int rcar_gen3_phy_usb2_init(struct phy *p)
struct rcar_gen3_chan *channel = rphy->ch;
void __iomem *usb2_base = channel->base;
u32 val;
- int ret;
- if (!rcar_gen3_is_any_rphy_initialized(channel) && channel->irq >= 0) {
- INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
- ret = request_irq(channel->irq, rcar_gen3_phy_usb2_irq,
- IRQF_SHARED, dev_name(channel->dev), channel);
- if (ret < 0) {
- dev_err(channel->dev, "No irq handler (%d)\n", channel->irq);
- return ret;
- }
- }
+ guard(spinlock_irqsave)(&channel->lock);
/* Initialize USB2 part */
val = readl(usb2_base + USB2_INT_ENABLE);
val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits;
writel(val, usb2_base + USB2_INT_ENABLE);
- writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
- writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
-
- /* Initialize otg part */
- if (channel->is_otg_channel) {
- if (rcar_gen3_needs_init_otg(channel))
- rcar_gen3_init_otg(channel);
- rphy->otg_initialized = true;
+
+ if (!rcar_gen3_is_any_rphy_initialized(channel)) {
+ writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET);
+ writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET);
}
+ /* Initialize otg part (only if we initialize a PHY with IRQs). */
+ if (rphy->int_enable_bits)
+ rcar_gen3_init_otg(channel);
+
rphy->initialized = true;
return 0;
@@ -484,10 +489,9 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
void __iomem *usb2_base = channel->base;
u32 val;
- rphy->initialized = false;
+ guard(spinlock_irqsave)(&channel->lock);
- if (channel->is_otg_channel)
- rphy->otg_initialized = false;
+ rphy->initialized = false;
val = readl(usb2_base + USB2_INT_ENABLE);
val &= ~rphy->int_enable_bits;
@@ -495,9 +499,6 @@ static int rcar_gen3_phy_usb2_exit(struct phy *p)
val &= ~USB2_INT_ENABLE_UCOM_INTEN;
writel(val, usb2_base + USB2_INT_ENABLE);
- if (channel->irq >= 0 && !rcar_gen3_is_any_rphy_initialized(channel))
- free_irq(channel->irq, channel);
-
return 0;
}
@@ -509,16 +510,17 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
u32 val;
int ret = 0;
- mutex_lock(&channel->lock);
- if (!rcar_gen3_are_all_rphys_power_off(channel))
- goto out;
-
if (channel->vbus) {
ret = regulator_enable(channel->vbus);
if (ret)
- goto out;
+ return ret;
}
+ guard(spinlock_irqsave)(&channel->lock);
+
+ if (!rcar_gen3_are_all_rphys_power_off(channel))
+ goto out;
+
val = readl(usb2_base + USB2_USBCTR);
val |= USB2_USBCTR_PLL_RST;
writel(val, usb2_base + USB2_USBCTR);
@@ -528,7 +530,6 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p)
out:
/* The powered flag should be set for any other phys anyway */
rphy->powered = true;
- mutex_unlock(&channel->lock);
return 0;
}
@@ -539,18 +540,20 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
struct rcar_gen3_chan *channel = rphy->ch;
int ret = 0;
- mutex_lock(&channel->lock);
- rphy->powered = false;
+ scoped_guard(spinlock_irqsave, &channel->lock) {
+ rphy->powered = false;
- if (!rcar_gen3_are_all_rphys_power_off(channel))
- goto out;
+ if (rcar_gen3_are_all_rphys_power_off(channel)) {
+ u32 val = readl(channel->base + USB2_USBCTR);
+
+ val |= USB2_USBCTR_PLL_RST;
+ writel(val, channel->base + USB2_USBCTR);
+ }
+ }
if (channel->vbus)
ret = regulator_disable(channel->vbus);
-out:
- mutex_unlock(&channel->lock);
-
return ret;
}
@@ -703,7 +706,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rcar_gen3_chan *channel;
struct phy_provider *provider;
- int ret = 0, i;
+ int ret = 0, i, irq;
if (!dev->of_node) {
dev_err(dev, "This driver needs device tree\n");
@@ -719,8 +722,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
return PTR_ERR(channel->base);
channel->obint_enable_bits = USB2_OBINT_BITS;
- /* get irq number here and request_irq for OTG in phy_init */
- channel->irq = platform_get_irq_optional(pdev, 0);
channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node);
if (channel->dr_mode != USB_DR_MODE_UNKNOWN) {
channel->is_otg_channel = true;
@@ -763,7 +764,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
if (phy_data->no_adp_ctrl)
channel->obint_enable_bits = USB2_OBINT_IDCHG_EN;
- mutex_init(&channel->lock);
+ spin_lock_init(&channel->lock);
for (i = 0; i < NUM_OF_PHYS; i++) {
channel->rphys[i].phy = devm_phy_create(dev, NULL,
phy_data->phy_usb2_ops);
@@ -789,6 +790,20 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
channel->vbus = NULL;
}
+ irq = platform_get_irq_optional(pdev, 0);
+ if (irq < 0 && irq != -ENXIO) {
+ ret = irq;
+ goto error;
+ } else if (irq > 0) {
+ INIT_WORK(&channel->work, rcar_gen3_phy_usb2_work);
+ ret = devm_request_irq(dev, irq, rcar_gen3_phy_usb2_irq,
+ IRQF_SHARED, dev_name(dev), channel);
+ if (ret < 0) {
+ dev_err(dev, "Failed to request irq (%d)\n", irq);
+ goto error;
+ }
+ }
+
provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate);
if (IS_ERR(provider)) {
dev_err(dev, "Failed to register PHY provider\n");
diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig
index dcb8e1628632..14698571b607 100644
--- a/drivers/phy/rockchip/Kconfig
+++ b/drivers/phy/rockchip/Kconfig
@@ -83,6 +83,18 @@ config PHY_ROCKCHIP_PCIE
help
Enable this to support the Rockchip PCIe PHY.
+config PHY_ROCKCHIP_SAMSUNG_DCPHY
+ tristate "Rockchip Samsung MIPI DCPHY driver"
+ depends on (ARCH_ROCKCHIP || COMPILE_TEST)
+ select GENERIC_PHY
+ select GENERIC_PHY_MIPI_DPHY
+ help
+ Enable this to support the Rockchip MIPI DCPHY with
+ Samsung IP block.
+
+ To compile this driver as a module, choose M here: the module
+ will be called phy-rockchip-samsung-dcphy
+
config PHY_ROCKCHIP_SAMSUNG_HDPTX
tristate "Rockchip Samsung HDMI/eDP Combo PHY driver"
depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF
diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile
index 010a824e32ce..117aaffd037d 100644
--- a/drivers/phy/rockchip/Makefile
+++ b/drivers/phy/rockchip/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
obj-$(CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY) += phy-rockchip-naneng-combphy.o
obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
+obj-$(CONFIG_PHY_ROCKCHIP_SAMSUNG_DCPHY) += phy-rockchip-samsung-dcphy.o
obj-$(CONFIG_PHY_ROCKCHIP_SAMSUNG_HDPTX) += phy-rockchip-samsung-hdptx.o
obj-$(CONFIG_PHY_ROCKCHIP_SNPS_PCIE3) += phy-rockchip-snps-pcie3.o
obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index 96f3d868a526..b5e6a864deeb 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -440,7 +440,7 @@ static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy)
struct extcon_dev *edev;
int ret;
- if (of_property_read_bool(node, "extcon")) {
+ if (of_property_present(node, "extcon")) {
edev = extcon_get_edev_by_phandle(rphy->dev, 0);
if (IS_ERR(edev))
return dev_err_probe(rphy->dev, PTR_ERR(edev),
@@ -1323,7 +1323,7 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
goto out;
}
- if (!of_property_read_bool(rphy->dev->of_node, "extcon")) {
+ if (!of_property_present(rphy->dev->of_node, "extcon")) {
/* do initial sync of usb state */
id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id);
extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id);
diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
index 1ef6d9630f7e..ce91fb1d5167 100644
--- a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
+++ b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
@@ -37,6 +37,10 @@
#define PHYREG8 0x1C
#define PHYREG8_SSC_EN BIT(4)
+#define PHYREG10 0x24
+#define PHYREG10_SSC_PCM_MASK GENMASK(3, 0)
+#define PHYREG10_SSC_PCM_3500PPM 7
+
#define PHYREG11 0x28
#define PHYREG11_SU_TRIM_0_7 0xF0
@@ -61,17 +65,26 @@
#define PHYREG16 0x3C
#define PHYREG16_SSC_CNT_VALUE 0x5f
+#define PHYREG17 0x40
+
#define PHYREG18 0x44
#define PHYREG18_PLL_LOOP 0x32
+#define PHYREG21 0x50
+#define PHYREG21_RX_SQUELCH_VAL 0x0D
+
#define PHYREG27 0x6C
#define PHYREG27_RX_TRIM_RK3588 0x4C
+#define PHYREG30 0x74
+
#define PHYREG32 0x7C
#define PHYREG32_SSC_MASK GENMASK(7, 4)
+#define PHYREG32_SSC_DIR_MASK GENMASK(5, 4)
#define PHYREG32_SSC_DIR_SHIFT 4
#define PHYREG32_SSC_UPWARD 0
#define PHYREG32_SSC_DOWNWARD 1
+#define PHYREG32_SSC_OFFSET_MASK GENMASK(7, 6)
#define PHYREG32_SSC_OFFSET_SHIFT 6
#define PHYREG32_SSC_OFFSET_500PPM 1
@@ -79,6 +92,7 @@
#define PHYREG33_PLL_KVCO_MASK GENMASK(4, 2)
#define PHYREG33_PLL_KVCO_SHIFT 2
#define PHYREG33_PLL_KVCO_VALUE 2
+#define PHYREG33_PLL_KVCO_VALUE_RK3576 4
struct rockchip_combphy_priv;
@@ -98,6 +112,7 @@ struct rockchip_combphy_grfcfg {
struct combphy_reg pipe_rxterm_set;
struct combphy_reg pipe_txelec_set;
struct combphy_reg pipe_txcomp_set;
+ struct combphy_reg pipe_clk_24m;
struct combphy_reg pipe_clk_25m;
struct combphy_reg pipe_clk_100m;
struct combphy_reg pipe_phymode_sel;
@@ -381,6 +396,154 @@ static int rockchip_combphy_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(phy_provider);
}
+static int rk3562_combphy_cfg(struct rockchip_combphy_priv *priv)
+{
+ const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
+ unsigned long rate;
+ u32 val;
+
+ switch (priv->type) {
+ case PHY_TYPE_PCIE:
+ /* Set SSC downward spread spectrum */
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK,
+ PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT,
+ PHYREG32);
+
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
+ break;
+ case PHY_TYPE_USB3:
+ /* Set SSC downward spread spectrum */
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK,
+ PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT,
+ PHYREG32);
+
+ /* Enable adaptive CTLE for USB3.0 Rx */
+ rockchip_combphy_updatel(priv, PHYREG15_CTLE_EN,
+ PHYREG15_CTLE_EN, PHYREG15);
+
+ /* Set PLL KVCO fine tuning signals */
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, BIT(3), PHYREG33);
+
+ /* Set PLL LPF R1 to su_trim[10:7]=1001 */
+ writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12);
+
+ /* Set PLL input clock divider 1/2 */
+ val = FIELD_PREP(PHYREG6_PLL_DIV_MASK, PHYREG6_PLL_DIV_2);
+ rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, val, PHYREG6);
+
+ /* Set PLL loop divider */
+ writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18);
+
+ /* Set PLL KVCO to min and set PLL charge pump current to max */
+ writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11);
+
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_usb, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true);
+ break;
+ default:
+ dev_err(priv->dev, "incompatible PHY type\n");
+ return -EINVAL;
+ }
+
+ rate = clk_get_rate(priv->refclk);
+
+ switch (rate) {
+ case REF_CLOCK_24MHz:
+ if (priv->type == PHY_TYPE_USB3) {
+ /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */
+ val = FIELD_PREP(PHYREG15_SSC_CNT_MASK, PHYREG15_SSC_CNT_VALUE);
+ rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK,
+ val, PHYREG15);
+
+ writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
+ }
+ break;
+ case REF_CLOCK_25MHz:
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_25m, true);
+ break;
+ case REF_CLOCK_100MHz:
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
+ if (priv->type == PHY_TYPE_PCIE) {
+ /* PLL KVCO tuning fine */
+ val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE);
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
+ val, PHYREG33);
+
+ /* Enable controlling random jitter, aka RMJ */
+ writel(0x4, priv->mmio + PHYREG12);
+
+ val = PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT;
+ rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK,
+ val, PHYREG6);
+
+ writel(0x32, priv->mmio + PHYREG18);
+ writel(0xf0, priv->mmio + PHYREG11);
+ }
+ break;
+ default:
+ dev_err(priv->dev, "Unsupported rate: %lu\n", rate);
+ return -EINVAL;
+ }
+
+ if (priv->ext_refclk) {
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true);
+ if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) {
+ val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT;
+ val |= PHYREG13_CKRCV_AMP0;
+ rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13);
+
+ val = readl(priv->mmio + PHYREG14);
+ val |= PHYREG14_CKRCV_AMP1;
+ writel(val, priv->mmio + PHYREG14);
+ }
+ }
+
+ if (priv->enable_ssc) {
+ val = readl(priv->mmio + PHYREG8);
+ val |= PHYREG8_SSC_EN;
+ writel(val, priv->mmio + PHYREG8);
+ }
+
+ return 0;
+}
+
+static const struct rockchip_combphy_grfcfg rk3562_combphy_grfcfgs = {
+ /* pipe-phy-grf */
+ .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 },
+ .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 },
+ .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 },
+ .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 },
+ .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 },
+ .pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x01 },
+ .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 },
+ .pipe_phymode_sel = { 0x0008, 1, 1, 0x00, 0x01 },
+ .pipe_rate_sel = { 0x0008, 2, 2, 0x00, 0x01 },
+ .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 },
+ .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 },
+ .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 },
+ .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 },
+ .pipe_sel_usb = { 0x000c, 14, 13, 0x00, 0x01 },
+ .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 },
+ .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 },
+ .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 },
+ .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 },
+ .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
+};
+
+static const struct rockchip_combphy_cfg rk3562_combphy_cfgs = {
+ .num_phys = 1,
+ .phy_ids = {
+ 0xff750000
+ },
+ .grfcfg = &rk3562_combphy_grfcfgs,
+ .combphy_cfg = rk3562_combphy_cfg,
+};
+
static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv)
{
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
@@ -587,6 +750,266 @@ static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = {
.combphy_cfg = rk3568_combphy_cfg,
};
+static int rk3576_combphy_cfg(struct rockchip_combphy_priv *priv)
+{
+ const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
+ unsigned long rate;
+ u32 val;
+
+ switch (priv->type) {
+ case PHY_TYPE_PCIE:
+ /* Set SSC downward spread spectrum */
+ val = FIELD_PREP(PHYREG32_SSC_MASK, PHYREG32_SSC_DOWNWARD);
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32);
+
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
+ break;
+
+ case PHY_TYPE_USB3:
+ /* Set SSC downward spread spectrum */
+ val = FIELD_PREP(PHYREG32_SSC_MASK, PHYREG32_SSC_DOWNWARD);
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32);
+
+ /* Enable adaptive CTLE for USB3.0 Rx */
+ val = readl(priv->mmio + PHYREG15);
+ val |= PHYREG15_CTLE_EN;
+ writel(val, priv->mmio + PHYREG15);
+
+ /* Set PLL KVCO fine tuning signals */
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK, BIT(3), PHYREG33);
+
+ /* Set PLL LPF R1 to su_trim[10:7]=1001 */
+ writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12);
+
+ /* Set PLL input clock divider 1/2 */
+ val = FIELD_PREP(PHYREG6_PLL_DIV_MASK, PHYREG6_PLL_DIV_2);
+ rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK, val, PHYREG6);
+
+ /* Set PLL loop divider */
+ writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18);
+
+ /* Set PLL KVCO to min and set PLL charge pump current to max */
+ writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11);
+
+ /* Set Rx squelch input filler bandwidth */
+ writel(PHYREG21_RX_SQUELCH_VAL, priv->mmio + PHYREG21);
+
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true);
+ break;
+
+ case PHY_TYPE_SATA:
+ /* Enable adaptive CTLE for SATA Rx */
+ val = readl(priv->mmio + PHYREG15);
+ val |= PHYREG15_CTLE_EN;
+ writel(val, priv->mmio + PHYREG15);
+
+ /* Set tx_rterm = 50 ohm and rx_rterm = 43.5 ohm */
+ val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT;
+ val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT;
+ writel(val, priv->mmio + PHYREG7);
+
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_sata, true);
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_sata, true);
+ rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_con0_for_sata, true);
+ rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_con1_for_sata, true);
+ break;
+
+ default:
+ dev_err(priv->dev, "incompatible PHY type\n");
+ return -EINVAL;
+ }
+
+ rate = clk_get_rate(priv->refclk);
+
+ switch (rate) {
+ case REF_CLOCK_24MHz:
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_24m, true);
+ if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) {
+ /* Set ssc_cnt[9:0]=0101111101 & 31.5KHz */
+ val = FIELD_PREP(PHYREG15_SSC_CNT_MASK, PHYREG15_SSC_CNT_VALUE);
+ rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK,
+ val, PHYREG15);
+
+ writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
+ } else if (priv->type == PHY_TYPE_PCIE) {
+ /* PLL KVCO tuning fine */
+ val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576);
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
+ val, PHYREG33);
+
+ /* Set up rx_pck invert and rx msb to disable */
+ writel(0x00, priv->mmio + PHYREG27);
+
+ /*
+ * Set up SU adjust signal:
+ * su_trim[7:0], PLL KVCO adjust bits[2:0] to min
+ * su_trim[15:8], PLL LPF R1 adujst bits[9:7]=3'b011
+ * su_trim[31:24], CKDRV adjust
+ */
+ writel(0x90, priv->mmio + PHYREG11);
+ writel(0x02, priv->mmio + PHYREG12);
+ writel(0x57, priv->mmio + PHYREG14);
+
+ writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
+ }
+ break;
+
+ case REF_CLOCK_25MHz:
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_25m, true);
+ break;
+
+ case REF_CLOCK_100MHz:
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
+ if (priv->type == PHY_TYPE_PCIE) {
+ /* gate_tx_pck_sel length select work for L1SS */
+ writel(0xc0, priv->mmio + PHYREG30);
+
+ /* PLL KVCO tuning fine */
+ val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576);
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
+ val, PHYREG33);
+
+ /* Set up rx_trim: PLL LPF C1 85pf R1 1.25kohm */
+ writel(0x4c, priv->mmio + PHYREG27);
+
+ /*
+ * Set up SU adjust signal:
+ * su_trim[7:0], PLL KVCO adjust bits[2:0] to min
+ * su_trim[15:8], bypass PLL loop divider code, and
+ * PLL LPF R1 adujst bits[9:7]=3'b101
+ * su_trim[23:16], CKRCV adjust
+ * su_trim[31:24], CKDRV adjust
+ */
+ writel(0x90, priv->mmio + PHYREG11);
+ writel(0x43, priv->mmio + PHYREG12);
+ writel(0x88, priv->mmio + PHYREG13);
+ writel(0x56, priv->mmio + PHYREG14);
+ } else if (priv->type == PHY_TYPE_SATA) {
+ /* downward spread spectrum +500ppm */
+ val = FIELD_PREP(PHYREG32_SSC_DIR_MASK, PHYREG32_SSC_DOWNWARD);
+ val |= FIELD_PREP(PHYREG32_SSC_OFFSET_MASK, PHYREG32_SSC_OFFSET_500PPM);
+ rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32);
+
+ /* ssc ppm adjust to 3500ppm */
+ rockchip_combphy_updatel(priv, PHYREG10_SSC_PCM_MASK,
+ PHYREG10_SSC_PCM_3500PPM,
+ PHYREG10);
+ }
+ break;
+
+ default:
+ dev_err(priv->dev, "Unsupported rate: %lu\n", rate);
+ return -EINVAL;
+ }
+
+ if (priv->ext_refclk) {
+ rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true);
+ if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) {
+ val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576);
+ rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
+ val, PHYREG33);
+
+ /* Set up rx_trim: PLL LPF C1 85pf R1 2.5kohm */
+ writel(0x0c, priv->mmio + PHYREG27);
+
+ /*
+ * Set up SU adjust signal:
+ * su_trim[7:0], PLL KVCO adjust bits[2:0] to min
+ * su_trim[15:8], bypass PLL loop divider code, and
+ * PLL LPF R1 adujst bits[9:7]=3'b101.
+ * su_trim[23:16], CKRCV adjust
+ * su_trim[31:24], CKDRV adjust
+ */
+ writel(0x90, priv->mmio + PHYREG11);
+ writel(0x43, priv->mmio + PHYREG12);
+ writel(0x88, priv->mmio + PHYREG13);
+ writel(0x56, priv->mmio + PHYREG14);
+ }
+ }
+
+ if (priv->enable_ssc) {
+ val = readl(priv->mmio + PHYREG8);
+ val |= PHYREG8_SSC_EN;
+ writel(val, priv->mmio + PHYREG8);
+
+ if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_24MHz) {
+ /* Set PLL loop divider */
+ writel(0x00, priv->mmio + PHYREG17);
+ writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18);
+
+ /* Set up rx_pck invert and rx msb to disable */
+ writel(0x00, priv->mmio + PHYREG27);
+
+ /*
+ * Set up SU adjust signal:
+ * su_trim[7:0], PLL KVCO adjust bits[2:0] to min
+ * su_trim[15:8], PLL LPF R1 adujst bits[9:7]=3'b101
+ * su_trim[23:16], CKRCV adjust
+ * su_trim[31:24], CKDRV adjust
+ */
+ writel(0x90, priv->mmio + PHYREG11);
+ writel(0x02, priv->mmio + PHYREG12);
+ writel(0x08, priv->mmio + PHYREG13);
+ writel(0x57, priv->mmio + PHYREG14);
+ writel(0x40, priv->mmio + PHYREG15);
+
+ writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
+
+ val = FIELD_PREP(PHYREG33_PLL_KVCO_MASK, PHYREG33_PLL_KVCO_VALUE_RK3576);
+ writel(val, priv->mmio + PHYREG33);
+ }
+ }
+
+ return 0;
+}
+
+static const struct rockchip_combphy_grfcfg rk3576_combphy_grfcfgs = {
+ /* pipe-phy-grf */
+ .pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 },
+ .usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 },
+ .pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 },
+ .pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 },
+ .pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 },
+ .pipe_clk_24m = { 0x0004, 14, 13, 0x00, 0x00 },
+ .pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x01 },
+ .pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 },
+ .pipe_phymode_sel = { 0x0008, 1, 1, 0x00, 0x01 },
+ .pipe_rate_sel = { 0x0008, 2, 2, 0x00, 0x01 },
+ .pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 },
+ .pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 },
+ .pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 },
+ .pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 },
+ .pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 },
+ .con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 },
+ .con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 },
+ .con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 },
+ .con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
+ .con0_for_sata = { 0x0000, 15, 0, 0x00, 0x0129 },
+ .con1_for_sata = { 0x0004, 15, 0, 0x00, 0x0000 },
+ .con2_for_sata = { 0x0008, 15, 0, 0x00, 0x80c1 },
+ .con3_for_sata = { 0x000c, 15, 0, 0x00, 0x0407 },
+ /* php-grf */
+ .pipe_con0_for_sata = { 0x001C, 2, 0, 0x00, 0x2 },
+ .pipe_con1_for_sata = { 0x0020, 2, 0, 0x00, 0x2 },
+};
+
+static const struct rockchip_combphy_cfg rk3576_combphy_cfgs = {
+ .num_phys = 2,
+ .phy_ids = {
+ 0x2b050000,
+ 0x2b060000
+ },
+ .grfcfg = &rk3576_combphy_grfcfgs,
+ .combphy_cfg = rk3576_combphy_cfg,
+};
+
static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv)
{
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
@@ -775,10 +1198,18 @@ static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = {
static const struct of_device_id rockchip_combphy_of_match[] = {
{
+ .compatible = "rockchip,rk3562-naneng-combphy",
+ .data = &rk3562_combphy_cfgs,
+ },
+ {
.compatible = "rockchip,rk3568-naneng-combphy",
.data = &rk3568_combphy_cfgs,
},
{
+ .compatible = "rockchip,rk3576-naneng-combphy",
+ .data = &rk3576_combphy_cfgs,
+ },
+ {
.compatible = "rockchip,rk3588-naneng-combphy",
.data = &rk3588_combphy_cfgs,
},
diff --git a/drivers/phy/rockchip/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c
index 51cc5ece0e63..bd44af36c67a 100644
--- a/drivers/phy/rockchip/phy-rockchip-pcie.c
+++ b/drivers/phy/rockchip/phy-rockchip-pcie.c
@@ -124,7 +124,7 @@ static int rockchip_pcie_phy_power_off(struct phy *phy)
struct rockchip_pcie_phy *rk_phy = to_pcie_phy(inst);
int err = 0;
- mutex_lock(&rk_phy->pcie_mutex);
+ guard(mutex)(&rk_phy->pcie_mutex);
regmap_write(rk_phy->reg_base,
rk_phy->phy_data->pcie_laneoff,
@@ -132,27 +132,22 @@ static int rockchip_pcie_phy_power_off(struct phy *phy)
PHY_LANE_IDLE_MASK,
PHY_LANE_IDLE_A_SHIFT + inst->index));
- if (--rk_phy->pwr_cnt)
- goto err_out;
+ if (--rk_phy->pwr_cnt) {
+ return 0;
+ }
err = reset_control_assert(rk_phy->phy_rst);
if (err) {
dev_err(&phy->dev, "assert phy_rst err %d\n", err);
- goto err_restore;
+ rk_phy->pwr_cnt++;
+ regmap_write(rk_phy->reg_base,
+ rk_phy->phy_data->pcie_laneoff,
+ HIWORD_UPDATE(!PHY_LANE_IDLE_OFF,
+ PHY_LANE_IDLE_MASK,
+ PHY_LANE_IDLE_A_SHIFT + inst->index));
+ return err;
}
-err_out:
- mutex_unlock(&rk_phy->pcie_mutex);
- return 0;
-
-err_restore:
- rk_phy->pwr_cnt++;
- regmap_write(rk_phy->reg_base,
- rk_phy->phy_data->pcie_laneoff,
- HIWORD_UPDATE(!PHY_LANE_IDLE_OFF,
- PHY_LANE_IDLE_MASK,
- PHY_LANE_IDLE_A_SHIFT + inst->index));
- mutex_unlock(&rk_phy->pcie_mutex);
return err;
}
@@ -162,17 +157,18 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
struct rockchip_pcie_phy *rk_phy = to_pcie_phy(inst);
int err = 0;
u32 status;
- unsigned long timeout;
- mutex_lock(&rk_phy->pcie_mutex);
+ guard(mutex)(&rk_phy->pcie_mutex);
- if (rk_phy->pwr_cnt++)
- goto err_out;
+ if (rk_phy->pwr_cnt++) {
+ return 0;
+ }
err = reset_control_deassert(rk_phy->phy_rst);
if (err) {
dev_err(&phy->dev, "deassert phy_rst err %d\n", err);
- goto err_pwr_cnt;
+ rk_phy->pwr_cnt--;
+ return err;
}
regmap_write(rk_phy->reg_base, rk_phy->phy_data->pcie_conf,
@@ -191,21 +187,11 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
* so we make it large enough here. And we use loop-break
* method which should not be harmful.
*/
- timeout = jiffies + msecs_to_jiffies(1000);
-
- err = -EINVAL;
- while (time_before(jiffies, timeout)) {
- regmap_read(rk_phy->reg_base,
- rk_phy->phy_data->pcie_status,
- &status);
- if (status & PHY_PLL_LOCKED) {
- dev_dbg(&phy->dev, "pll locked!\n");
- err = 0;
- break;
- }
- msleep(20);
- }
-
+ err = regmap_read_poll_timeout(rk_phy->reg_base,
+ rk_phy->phy_data->pcie_status,
+ status,
+ status & PHY_PLL_LOCKED,
+ 200, 100000);
if (err) {
dev_err(&phy->dev, "pll lock timeout!\n");
goto err_pll_lock;
@@ -214,19 +200,11 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
phy_wr_cfg(rk_phy, PHY_CFG_CLK_TEST, PHY_CFG_SEPE_RATE);
phy_wr_cfg(rk_phy, PHY_CFG_CLK_SCC, PHY_CFG_PLL_100M);
- err = -ETIMEDOUT;
- while (time_before(jiffies, timeout)) {
- regmap_read(rk_phy->reg_base,
- rk_phy->phy_data->pcie_status,
- &status);
- if (!(status & PHY_PLL_OUTPUT)) {
- dev_dbg(&phy->dev, "pll output enable done!\n");
- err = 0;
- break;
- }
- msleep(20);
- }
-
+ err = regmap_read_poll_timeout(rk_phy->reg_base,
+ rk_phy->phy_data->pcie_status,
+ status,
+ !(status & PHY_PLL_OUTPUT),
+ 200, 100000);
if (err) {
dev_err(&phy->dev, "pll output enable timeout!\n");
goto err_pll_lock;
@@ -236,33 +214,22 @@ static int rockchip_pcie_phy_power_on(struct phy *phy)
HIWORD_UPDATE(PHY_CFG_PLL_LOCK,
PHY_CFG_ADDR_MASK,
PHY_CFG_ADDR_SHIFT));
- err = -EINVAL;
- while (time_before(jiffies, timeout)) {
- regmap_read(rk_phy->reg_base,
- rk_phy->phy_data->pcie_status,
- &status);
- if (status & PHY_PLL_LOCKED) {
- dev_dbg(&phy->dev, "pll relocked!\n");
- err = 0;
- break;
- }
- msleep(20);
- }
+ err = regmap_read_poll_timeout(rk_phy->reg_base,
+ rk_phy->phy_data->pcie_status,
+ status,
+ status & PHY_PLL_LOCKED,
+ 200, 100000);
if (err) {
dev_err(&phy->dev, "pll relock timeout!\n");
goto err_pll_lock;
}
-err_out:
- mutex_unlock(&rk_phy->pcie_mutex);
- return 0;
+ return err;
err_pll_lock:
reset_control_assert(rk_phy->phy_rst);
-err_pwr_cnt:
rk_phy->pwr_cnt--;
- mutex_unlock(&rk_phy->pcie_mutex);
return err;
}
@@ -272,33 +239,19 @@ static int rockchip_pcie_phy_init(struct phy *phy)
struct rockchip_pcie_phy *rk_phy = to_pcie_phy(inst);
int err = 0;
- mutex_lock(&rk_phy->pcie_mutex);
-
- if (rk_phy->init_cnt++)
- goto err_out;
+ guard(mutex)(&rk_phy->pcie_mutex);
- err = clk_prepare_enable(rk_phy->clk_pciephy_ref);
- if (err) {
- dev_err(&phy->dev, "Fail to enable pcie ref clock.\n");
- goto err_refclk;
+ if (rk_phy->init_cnt++) {
+ return 0;
}
err = reset_control_assert(rk_phy->phy_rst);
if (err) {
dev_err(&phy->dev, "assert phy_rst err %d\n", err);
- goto err_reset;
+ rk_phy->init_cnt--;
+ return err;
}
-err_out:
- mutex_unlock(&rk_phy->pcie_mutex);
- return 0;
-
-err_reset:
-
- clk_disable_unprepare(rk_phy->clk_pciephy_ref);
-err_refclk:
- rk_phy->init_cnt--;
- mutex_unlock(&rk_phy->pcie_mutex);
return err;
}
@@ -307,15 +260,12 @@ static int rockchip_pcie_phy_exit(struct phy *phy)
struct phy_pcie_instance *inst = phy_get_drvdata(phy);
struct rockchip_pcie_phy *rk_phy = to_pcie_phy(inst);
- mutex_lock(&rk_phy->pcie_mutex);
+ guard(mutex)(&rk_phy->pcie_mutex);
if (--rk_phy->init_cnt)
goto err_init_cnt;
- clk_disable_unprepare(rk_phy->clk_pciephy_ref);
-
err_init_cnt:
- mutex_unlock(&rk_phy->pcie_mutex);
return 0;
}
@@ -371,18 +321,14 @@ static int rockchip_pcie_phy_probe(struct platform_device *pdev)
mutex_init(&rk_phy->pcie_mutex);
rk_phy->phy_rst = devm_reset_control_get(dev, "phy");
- if (IS_ERR(rk_phy->phy_rst)) {
- if (PTR_ERR(rk_phy->phy_rst) != -EPROBE_DEFER)
- dev_err(dev,
- "missing phy property for reset controller\n");
- return PTR_ERR(rk_phy->phy_rst);
- }
-
- rk_phy->clk_pciephy_ref = devm_clk_get(dev, "refclk");
- if (IS_ERR(rk_phy->clk_pciephy_ref)) {
- dev_err(dev, "refclk not found.\n");
- return PTR_ERR(rk_phy->clk_pciephy_ref);
- }
+ if (IS_ERR(rk_phy->phy_rst))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rk_phy->phy_rst),
+ "missing phy property for reset controller\n");
+
+ rk_phy->clk_pciephy_ref = devm_clk_get_enabled(dev, "refclk");
+ if (IS_ERR(rk_phy->clk_pciephy_ref))
+ return dev_err_probe(&pdev->dev, PTR_ERR(rk_phy->clk_pciephy_ref),
+ "failed to get phyclk\n");
/* parse #phy-cells to see if it's legacy PHY model */
if (of_property_read_u32(dev->of_node, "#phy-cells", &phy_num))
diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
new file mode 100644
index 000000000000..28a052e17366
--- /dev/null
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-dcphy.c
@@ -0,0 +1,1719 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2025 Rockchip Electronics Co.Ltd
+ * Author:
+ * Guochun Huang <hero.huang@rock-chips.com>
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#define FIELD_PREP_HIWORD(_mask, _val) \
+ ( \
+ FIELD_PREP((_mask), (_val)) | \
+ ((_mask) << 16) \
+ )
+
+#define BIAS_CON0 0x0000
+#define I_RES_CNTL_MASK GENMASK(6, 4)
+#define I_RES_CNTL(x) FIELD_PREP(I_RES_CNTL_MASK, x)
+#define I_RES_059_2UA I_RES_CNTL(0)
+#define I_RES_100_2UA I_RES_CNTL(1)
+#define I_RES_094_2UA I_RES_CNTL(2)
+#define I_RES_113_8UA I_RES_CNTL(3)
+#define I_RES_089_7UA I_RES_CNTL(4)
+#define I_RES_111_8UA I_RES_CNTL(5)
+#define I_RES_108_2UA I_RES_CNTL(6)
+#define I_RES_120_8UA I_RES_CNTL(7)
+#define I_DEV_SEL_MASK GENMASK(1, 0)
+#define I_DEV_SEL(x) FIELD_PREP(I_DEV_SEL_MASK, x)
+#define I_DEV_DIV_6 I_DEV_SEL(0)
+#define I_DEV_DIV_12 I_DEV_SEL(1)
+#define I_DEV_DIV_20 I_DEV_SEL(2)
+#define I_DEV_DIV_40 I_DEV_SEL(3)
+
+#define BIAS_CON1 0x0004
+#define I_VBG_SEL_MASK GENMASK(9, 8)
+#define I_VBG_SEL(x) FIELD_PREP(I_VBG_SEL_MASK, x)
+#define I_VBG_SEL_780MV I_VBG_SEL(0)
+#define I_VBG_SEL_820MV I_VBG_SEL(1)
+#define I_VBG_SEL_860MV I_VBG_SEL(2)
+#define I_VBG_SEL_900MV I_VBG_SEL(3)
+#define I_BGR_VREF_SEL_MASK GENMASK(5, 4)
+#define I_BGR_VREF_SEL(x) FIELD_PREP(I_BGR_VREF_SEL_MASK, x)
+#define I_BGR_VREF_810MV I_BGR_VREF_SEL(0)
+#define I_BGR_VREF_820MV I_BGR_VREF_SEL(1)
+#define I_BGR_VREF_830MV I_BGR_VREF_SEL(2)
+#define I_BGR_VREF_840MV I_BGR_VREF_SEL(3)
+#define I_LADDER_SEL_MASK GENMASK(2, 0)
+#define I_LADDER_SEL(x) FIELD_PREP(I_LADDER_SEL_MASK, x)
+#define I_LADDER_1_00V I_LADDER_SEL(0)
+#define I_LADDER_0_96V I_LADDER_SEL(1)
+#define I_LADDER_0_92V I_LADDER_SEL(2)
+#define I_LADDER_0_88V I_LADDER_SEL(3)
+#define I_LADDER_0_84V I_LADDER_SEL(4)
+#define I_LADDER_0_80V I_LADDER_SEL(5)
+#define I_LADDER_0_76V I_LADDER_SEL(6)
+#define I_LADDER_0_72V I_LADDER_SEL(7)
+
+/*
+ * Voltage corrections around reference voltages
+ * The selection between the 400-based or 200-based values for REG_400M
+ * is done by the hw depending on I_MUX below being 400MV or 200MV.
+ */
+#define BIAS_CON2 0x0008
+#define REG_325M_MASK GENMASK(14, 12)
+#define REG_325M(x) FIELD_PREP(REG_325M_MASK, x)
+#define REG_325M_295MV REG_325M(0)
+#define REG_325M_305MV REG_325M(1)
+#define REG_325M_315MV REG_325M(2)
+#define REG_325M_325MV REG_325M(3)
+#define REG_325M_335MV REG_325M(4)
+#define REG_325M_345MV REG_325M(5)
+#define REG_325M_355MV REG_325M(6)
+#define REG_325M_365MV REG_325M(7)
+#define REG_LP_400M_MASK GENMASK(10, 8)
+#define REG_LP_400M(x) FIELD_PREP(REG_LP_400M_MASK, x)
+#define REG_LP_400M_380MV REG_LP_400M(0)
+#define REG_LP_400M_390MV REG_LP_400M(1)
+#define REG_LP_400M_400MV REG_LP_400M(2)
+#define REG_LP_400M_410MV REG_LP_400M(3)
+#define REG_LP_400M_420MV REG_LP_400M(4)
+#define REG_LP_400M_430MV REG_LP_400M(5)
+#define REG_LP_400M_440MV REG_LP_400M(6)
+#define REG_LP_400M_450MV REG_LP_400M(7)
+#define REG_400M_MASK GENMASK(6, 4)
+#define REG_400M(x) FIELD_PREP(REG_400M_MASK, x)
+#define REG_400M_380MV REG_400M(0)
+#define REG_400M_390MV REG_400M(1)
+#define REG_400M_400MV REG_400M(2)
+#define REG_400M_410MV REG_400M(3)
+#define REG_400M_420MV REG_400M(4)
+#define REG_400M_430MV REG_400M(5)
+#define REG_400M_440MV REG_400M(6)
+#define REG_400M_450MV REG_400M(7)
+#define REG_400M_230MV REG_400M(0)
+#define REG_400M_220MV REG_400M(1)
+#define REG_400M_210MV REG_400M(2)
+#define REG_400M_200MV REG_400M(3)
+#define REG_400M_190MV REG_400M(4)
+#define REG_400M_180MV REG_400M(5)
+#define REG_400M_170MV REG_400M(6)
+#define REG_400M_160MV REG_400M(7)
+#define REG_645M_MASK GENMASK(2, 0)
+#define REG_645M(x) FIELD_PREP(REG_645M_MASK, x)
+#define REG_645M_605MV REG_645M(0)
+#define REG_645M_625MV REG_645M(1)
+#define REG_645M_635MV REG_645M(2)
+#define REG_645M_645MV REG_645M(3)
+#define REG_645M_655MV REG_645M(4)
+#define REG_645M_665MV REG_645M(5)
+#define REG_645M_685MV REG_645M(6)
+#define REG_645M_725MV REG_645M(7)
+
+#define BIAS_CON4 0x0010
+#define I_MUX_SEL_MASK GENMASK(6, 5)
+#define I_MUX_SEL(x) FIELD_PREP(I_MUX_SEL_MASK, x)
+#define I_MUX_400MV I_MUX_SEL(0)
+#define I_MUX_200MV I_MUX_SEL(1)
+#define I_MUX_530MV I_MUX_SEL(2)
+
+#define PLL_CON0 0x0100
+#define PLL_EN BIT(12)
+#define S_MASK GENMASK(10, 8)
+#define S(x) FIELD_PREP(S_MASK, x)
+#define P_MASK GENMASK(5, 0)
+#define P(x) FIELD_PREP(P_MASK, x)
+#define PLL_CON1 0x0104
+#define PLL_CON2 0x0108
+#define M_MASK GENMASK(9, 0)
+#define M(x) FIELD_PREP(M_MASK, x)
+#define PLL_CON3 0x010c
+#define MRR_MASK GENMASK(13, 8)
+#define MRR(x) FIELD_PREP(MRR_MASK, x)
+#define MFR_MASK GENMASK(7, 0)
+#define MFR(x) FIELD_PREP(MFR_MASK, x)
+#define PLL_CON4 0x0110
+#define SSCG_EN BIT(11)
+#define PLL_CON5 0x0114
+#define RESET_N_SEL BIT(10)
+#define PLL_ENABLE_SEL BIT(8)
+#define PLL_CON6 0x0118
+#define PLL_CON7 0x011c
+#define PLL_LOCK_CNT(x) FIELD_PREP(GENMASK(15, 0), x)
+#define PLL_CON8 0x0120
+#define PLL_STB_CNT(x) FIELD_PREP(GENMASK(15, 0), x)
+#define PLL_STAT0 0x0140
+#define PLL_LOCK BIT(0)
+
+#define DPHY_MC_GNR_CON0 0x0300
+#define PHY_READY BIT(1)
+#define PHY_ENABLE BIT(0)
+#define DPHY_MC_GNR_CON1 0x0304
+#define T_PHY_READY(x) FIELD_PREP(GENMASK(15, 0), x)
+#define DPHY_MC_ANA_CON0 0x0308
+#define EDGE_CON(x) FIELD_PREP(GENMASK(14, 12), x)
+#define EDGE_CON_DIR(x) FIELD_PREP(BIT(9), x)
+#define EDGE_CON_EN BIT(8)
+#define RES_UP(x) FIELD_PREP(GENMASK(7, 4), x)
+#define RES_DN(x) FIELD_PREP(GENMASK(3, 0), x)
+#define DPHY_MC_ANA_CON1 0x030c
+#define DPHY_MC_ANA_CON2 0x0310
+#define HS_VREG_AMP_ICON(x) FIELD_PREP(GENMASK(1, 0), x)
+#define DPHY_MC_TIME_CON0 0x0330
+#define HSTX_CLK_SEL BIT(12)
+#define T_LPX(x) FIELD_PREP(GENMASK(11, 4), x)
+#define DPHY_MC_TIME_CON1 0x0334
+#define T_CLK_ZERO(x) FIELD_PREP(GENMASK(15, 8), x)
+#define T_CLK_PREPARE(x) FIELD_PREP(GENMASK(7, 0), x)
+#define DPHY_MC_TIME_CON2 0x0338
+#define T_HS_EXIT(x) FIELD_PREP(GENMASK(15, 8), x)
+#define T_CLK_TRAIL(x) FIELD_PREP(GENMASK(7, 0), x)
+#define DPHY_MC_TIME_CON3 0x033c
+#define T_CLK_POST(x) FIELD_PREP(GENMASK(7, 0), x)
+#define DPHY_MC_TIME_CON4 0x0340
+#define T_ULPS_EXIT(x) FIELD_PREP(GENMASK(9, 0), x)
+#define DPHY_MC_DESKEW_CON0 0x0350
+#define SKEW_CAL_RUN_TIME(x) FIELD_PREP(GENMASK(15, 12), x)
+
+#define SKEW_CAL_INIT_RUN_TIME(x) FIELD_PREP(GENMASK(11, 8), x)
+#define SKEW_CAL_INIT_WAIT_TIME(x) FIELD_PREP(GENMASK(7, 4), x)
+#define SKEW_CAL_EN BIT(0)
+
+#define COMBO_MD0_GNR_CON0 0x0400
+#define COMBO_MD0_GNR_CON1 0x0404
+#define COMBO_MD0_ANA_CON0 0x0408
+#define COMBO_MD0_ANA_CON1 0x040c
+#define COMBO_MD0_ANA_CON2 0x0410
+
+#define COMBO_MD0_TIME_CON0 0x0430
+#define COMBO_MD0_TIME_CON1 0x0434
+#define COMBO_MD0_TIME_CON2 0x0438
+#define COMBO_MD0_TIME_CON3 0x043c
+#define COMBO_MD0_TIME_CON4 0x0440
+#define COMBO_MD0_DATA_CON0 0x0444
+
+#define COMBO_MD1_GNR_CON0 0x0500
+#define COMBO_MD1_GNR_CON1 0x0504
+#define COMBO_MD1_ANA_CON0 0x0508
+#define COMBO_MD1_ANA_CON1 0x050c
+#define COMBO_MD1_ANA_CON2 0x0510
+#define COMBO_MD1_TIME_CON0 0x0530
+#define COMBO_MD1_TIME_CON1 0x0534
+#define COMBO_MD1_TIME_CON2 0x0538
+#define COMBO_MD1_TIME_CON3 0x053c
+#define COMBO_MD1_TIME_CON4 0x0540
+#define COMBO_MD1_DATA_CON0 0x0544
+
+#define COMBO_MD2_GNR_CON0 0x0600
+#define COMBO_MD2_GNR_CON1 0x0604
+#define COMBO_MD2_ANA_CON0 0X0608
+#define COMBO_MD2_ANA_CON1 0X060c
+#define COMBO_MD2_ANA_CON2 0X0610
+#define COMBO_MD2_TIME_CON0 0x0630
+#define COMBO_MD2_TIME_CON1 0x0634
+#define COMBO_MD2_TIME_CON2 0x0638
+#define COMBO_MD2_TIME_CON3 0x063c
+#define COMBO_MD2_TIME_CON4 0x0640
+#define COMBO_MD2_DATA_CON0 0x0644
+
+#define DPHY_MD3_GNR_CON0 0x0700
+#define DPHY_MD3_GNR_CON1 0x0704
+#define DPHY_MD3_ANA_CON0 0X0708
+#define DPHY_MD3_ANA_CON1 0X070c
+#define DPHY_MD3_ANA_CON2 0X0710
+#define DPHY_MD3_TIME_CON0 0x0730
+#define DPHY_MD3_TIME_CON1 0x0734
+#define DPHY_MD3_TIME_CON2 0x0738
+#define DPHY_MD3_TIME_CON3 0x073c
+#define DPHY_MD3_TIME_CON4 0x0740
+#define DPHY_MD3_DATA_CON0 0x0744
+
+#define T_LP_EXIT_SKEW(x) FIELD_PREP(GENMASK(3, 2), x)
+#define T_LP_ENTRY_SKEW(x) FIELD_PREP(GENMASK(1, 0), x)
+#define T_HS_ZERO(x) FIELD_PREP(GENMASK(15, 8), x)
+#define T_HS_PREPARE(x) FIELD_PREP(GENMASK(7, 0), x)
+#define T_HS_EXIT(x) FIELD_PREP(GENMASK(15, 8), x)
+#define T_HS_TRAIL(x) FIELD_PREP(GENMASK(7, 0), x)
+#define T_TA_GET(x) FIELD_PREP(GENMASK(7, 4), x)
+#define T_TA_GO(x) FIELD_PREP(GENMASK(3, 0), x)
+
+/* MIPI_CDPHY_GRF registers */
+#define MIPI_DCPHY_GRF_CON0 0x0000
+#define S_CPHY_MODE FIELD_PREP_HIWORD(BIT(3), 1)
+#define M_CPHY_MODE FIELD_PREP_HIWORD(BIT(0), 1)
+
+enum hs_drv_res_ohm {
+ STRENGTH_30_OHM = 0x8,
+ STRENGTH_31_2_OHM,
+ STRENGTH_32_5_OHM,
+ STRENGTH_34_OHM,
+ STRENGTH_35_5_OHM,
+ STRENGTH_37_OHM,
+ STRENGTH_39_OHM,
+ STRENGTH_41_OHM,
+ STRENGTH_43_OHM = 0x0,
+ STRENGTH_46_OHM,
+ STRENGTH_49_OHM,
+ STRENGTH_52_OHM,
+ STRENGTH_56_OHM,
+ STRENGTH_60_OHM,
+ STRENGTH_66_OHM,
+ STRENGTH_73_OHM,
+};
+
+struct hs_drv_res_cfg {
+ enum hs_drv_res_ohm clk_hs_drv_up_ohm;
+ enum hs_drv_res_ohm clk_hs_drv_down_ohm;
+ enum hs_drv_res_ohm data_hs_drv_up_ohm;
+ enum hs_drv_res_ohm data_hs_drv_down_ohm;
+};
+
+struct samsung_mipi_dcphy_plat_data {
+ const struct hs_drv_res_cfg *dphy_hs_drv_res_cfg;
+ u32 dphy_tx_max_lane_kbps;
+};
+
+struct samsung_mipi_dcphy {
+ struct device *dev;
+ struct clk *ref_clk;
+ struct clk *pclk;
+ struct regmap *regmap;
+ struct regmap *grf_regmap;
+ struct reset_control *m_phy_rst;
+ struct reset_control *s_phy_rst;
+ struct reset_control *apb_rst;
+ struct reset_control *grf_apb_rst;
+ unsigned int lanes;
+ struct phy *phy;
+ u8 type;
+
+ const struct samsung_mipi_dcphy_plat_data *pdata;
+ struct {
+ unsigned long long rate;
+ u8 prediv;
+ u16 fbdiv;
+ long dsm;
+ u8 scaler;
+
+ bool ssc_en;
+ u8 mfr;
+ u8 mrr;
+ } pll;
+};
+
+struct samsung_mipi_dphy_timing {
+ unsigned int max_lane_mbps;
+ u8 clk_prepare;
+ u8 clk_zero;
+ u8 clk_post;
+ u8 clk_trail_eot;
+ u8 hs_prepare;
+ u8 hs_zero;
+ u8 hs_trail_eot;
+ u8 lpx;
+ u8 hs_exit;
+ u8 hs_settle;
+};
+
+/*
+ * Timing values taken from rk3588 vendor kernel.
+ * Not documented in hw documentation.
+ */
+static const
+struct samsung_mipi_dphy_timing samsung_mipi_dphy_timing_table[] = {
+ {6500, 32, 117, 31, 28, 30, 56, 27, 24, 44, 37},
+ {6490, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37},
+ {6480, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37},
+ {6470, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37},
+ {6460, 32, 116, 31, 28, 30, 56, 27, 24, 44, 37},
+ {6450, 32, 115, 31, 28, 30, 56, 27, 24, 44, 37},
+ {6440, 32, 115, 31, 28, 30, 56, 27, 24, 44, 37},
+ {6430, 31, 116, 31, 28, 30, 55, 27, 24, 44, 37},
+ {6420, 31, 116, 31, 28, 30, 55, 27, 24, 44, 37},
+ {6410, 31, 116, 31, 27, 30, 55, 27, 24, 44, 37},
+ {6400, 31, 115, 30, 27, 30, 55, 27, 23, 43, 36},
+ {6390, 31, 115, 30, 27, 30, 55, 27, 23, 43, 36},
+ {6380, 31, 115, 30, 27, 30, 55, 27, 23, 43, 36},
+ {6370, 31, 115, 30, 27, 30, 55, 26, 23, 43, 36},
+ {6360, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36},
+ {6350, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36},
+ {6340, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36},
+ {6330, 31, 114, 30, 27, 30, 54, 26, 23, 43, 36},
+ {6320, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36},
+ {6310, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36},
+ {6300, 31, 113, 30, 27, 30, 54, 26, 23, 43, 36},
+ {6290, 31, 113, 30, 27, 29, 54, 26, 23, 43, 36},
+ {6280, 31, 112, 30, 27, 29, 54, 26, 23, 43, 36},
+ {6270, 31, 112, 30, 27, 29, 54, 26, 23, 43, 36},
+ {6260, 31, 112, 30, 27, 29, 54, 26, 23, 43, 36},
+ {6250, 31, 112, 30, 27, 29, 54, 26, 23, 42, 36},
+ {6240, 30, 113, 30, 27, 29, 54, 26, 23, 42, 36},
+ {6230, 30, 112, 30, 27, 29, 54, 26, 23, 42, 35},
+ {6220, 30, 112, 30, 27, 29, 53, 26, 23, 42, 35},
+ {6210, 30, 112, 30, 27, 29, 53, 26, 23, 42, 35},
+ {6200, 30, 112, 29, 27, 29, 53, 26, 23, 42, 35},
+ {6190, 30, 111, 29, 27, 29, 53, 26, 23, 42, 35},
+ {6180, 30, 111, 29, 27, 29, 53, 26, 23, 42, 35},
+ {6170, 30, 111, 29, 26, 29, 53, 26, 23, 42, 35},
+ {6160, 30, 111, 29, 26, 29, 53, 26, 23, 42, 35},
+ {6150, 30, 110, 29, 26, 29, 53, 26, 23, 42, 35},
+ {6140, 30, 110, 29, 26, 29, 52, 26, 23, 42, 35},
+ {6130, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35},
+ {6120, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35},
+ {6110, 30, 110, 29, 26, 29, 52, 25, 22, 42, 35},
+ {6100, 30, 109, 29, 26, 29, 52, 25, 22, 41, 35},
+ {6090, 30, 109, 29, 26, 29, 52, 25, 22, 41, 35},
+ {6080, 30, 109, 29, 26, 28, 53, 25, 22, 41, 35},
+ {6070, 30, 109, 29, 26, 28, 52, 25, 22, 41, 34},
+ {6060, 30, 108, 29, 26, 28, 52, 25, 22, 41, 34},
+ {6050, 30, 108, 29, 26, 28, 52, 25, 22, 41, 34},
+ {6040, 29, 109, 29, 26, 28, 52, 25, 22, 41, 34},
+ {6030, 29, 109, 29, 26, 28, 52, 25, 22, 41, 34},
+ {6020, 29, 108, 29, 26, 28, 52, 25, 22, 41, 34},
+ {6010, 29, 108, 29, 26, 28, 52, 25, 22, 41, 34},
+ {6000, 29, 108, 28, 26, 28, 51, 25, 22, 41, 34},
+ {5990, 29, 108, 28, 26, 28, 51, 25, 22, 41, 34},
+ {5980, 29, 107, 28, 26, 28, 51, 25, 22, 41, 34},
+ {5970, 29, 107, 28, 26, 28, 51, 25, 22, 41, 34},
+ {5960, 29, 107, 28, 26, 28, 51, 25, 22, 40, 34},
+ {5950, 29, 107, 28, 26, 28, 51, 25, 22, 40, 34},
+ {5940, 29, 107, 28, 25, 28, 51, 25, 22, 40, 34},
+ {5930, 29, 106, 28, 25, 28, 50, 25, 22, 40, 34},
+ {5920, 29, 106, 28, 25, 28, 50, 25, 22, 40, 34},
+ {5910, 29, 106, 28, 25, 28, 50, 25, 22, 40, 34},
+ {5900, 29, 106, 28, 25, 28, 50, 24, 22, 40, 33},
+ {5890, 29, 105, 28, 25, 28, 50, 24, 22, 40, 33},
+ {5880, 29, 105, 28, 25, 28, 50, 24, 22, 40, 33},
+ {5870, 29, 105, 28, 25, 27, 51, 24, 22, 40, 33},
+ {5860, 29, 105, 28, 25, 27, 51, 24, 21, 40, 33},
+ {5850, 29, 104, 28, 25, 27, 50, 24, 21, 40, 33},
+ {5840, 28, 105, 28, 25, 27, 50, 24, 21, 40, 33},
+ {5830, 28, 105, 28, 25, 27, 50, 24, 21, 40, 33},
+ {5820, 28, 105, 28, 25, 27, 50, 24, 21, 40, 33},
+ {5810, 28, 104, 28, 25, 27, 50, 24, 21, 39, 33},
+ {5800, 28, 104, 27, 25, 27, 50, 24, 21, 39, 33},
+ {5790, 28, 104, 27, 25, 27, 50, 24, 21, 39, 33},
+ {5780, 28, 104, 27, 25, 27, 49, 24, 21, 39, 33},
+ {5770, 28, 104, 27, 25, 27, 49, 24, 21, 39, 33},
+ {5760, 28, 103, 27, 25, 27, 49, 24, 21, 39, 33},
+ {5750, 28, 103, 27, 25, 27, 49, 24, 21, 39, 33},
+ {5740, 28, 103, 27, 25, 27, 49, 24, 21, 39, 33},
+ {5730, 28, 103, 27, 25, 27, 49, 24, 21, 39, 32},
+ {5720, 28, 102, 27, 25, 27, 49, 24, 21, 39, 32},
+ {5710, 28, 102, 27, 25, 27, 48, 24, 21, 39, 32},
+ {5700, 28, 102, 27, 24, 27, 48, 24, 21, 39, 32},
+ {5690, 28, 102, 27, 24, 27, 48, 24, 21, 39, 32},
+ {5680, 28, 101, 27, 24, 27, 48, 24, 21, 39, 32},
+ {5670, 28, 101, 27, 24, 27, 48, 23, 21, 38, 32},
+ {5660, 28, 101, 27, 24, 26, 49, 23, 21, 38, 32},
+ {5650, 28, 101, 27, 24, 26, 49, 23, 21, 38, 32},
+ {5640, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32},
+ {5630, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32},
+ {5620, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32},
+ {5610, 27, 101, 27, 24, 26, 48, 23, 21, 38, 32},
+ {5600, 27, 101, 26, 24, 26, 48, 23, 20, 38, 32},
+ {5590, 27, 100, 26, 24, 26, 48, 23, 20, 38, 32},
+ {5580, 27, 100, 26, 24, 26, 48, 23, 20, 38, 32},
+ {5570, 27, 100, 26, 24, 26, 48, 23, 20, 38, 31},
+ {5560, 27, 100, 26, 24, 26, 47, 23, 20, 38, 31},
+ {5550, 27, 99, 26, 24, 26, 47, 23, 20, 38, 31},
+ {5540, 27, 99, 26, 24, 26, 47, 23, 20, 38, 31},
+ {5530, 27, 99, 26, 24, 26, 47, 23, 20, 38, 31},
+ {5520, 27, 99, 26, 24, 26, 47, 23, 20, 37, 31},
+ {5510, 27, 98, 26, 24, 26, 47, 23, 20, 37, 31},
+ {5500, 27, 98, 26, 24, 26, 47, 23, 20, 37, 31},
+ {5490, 27, 98, 26, 24, 26, 46, 23, 20, 37, 31},
+ {5480, 27, 98, 26, 24, 26, 46, 23, 20, 37, 31},
+ {5470, 27, 97, 26, 23, 26, 46, 23, 20, 37, 31},
+ {5460, 27, 97, 26, 23, 26, 46, 23, 20, 37, 31},
+ {5450, 27, 97, 26, 23, 25, 47, 23, 20, 37, 31},
+ {5440, 26, 98, 26, 23, 25, 47, 23, 20, 37, 31},
+ {5430, 26, 98, 26, 23, 25, 47, 22, 20, 37, 31},
+ {5420, 26, 97, 26, 23, 25, 46, 22, 20, 37, 31},
+ {5410, 26, 97, 26, 23, 25, 46, 22, 20, 37, 31},
+ {5400, 26, 97, 25, 23, 25, 46, 22, 20, 37, 30},
+ {5390, 26, 97, 25, 23, 25, 46, 22, 20, 37, 30},
+ {5380, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30},
+ {5370, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30},
+ {5360, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30},
+ {5350, 26, 96, 25, 23, 25, 46, 22, 20, 36, 30},
+ {5340, 26, 95, 25, 23, 25, 45, 22, 20, 36, 30},
+ {5330, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30},
+ {5320, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30},
+ {5310, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30},
+ {5300, 26, 95, 25, 23, 25, 45, 22, 19, 36, 30},
+ {5290, 26, 94, 25, 23, 25, 45, 22, 19, 36, 30},
+ {5280, 26, 94, 25, 23, 25, 45, 22, 19, 36, 30},
+ {5270, 26, 94, 25, 23, 25, 44, 22, 19, 36, 30},
+ {5260, 26, 94, 25, 23, 25, 44, 22, 19, 36, 30},
+ {5250, 25, 94, 25, 23, 24, 45, 22, 19, 36, 30},
+ {5240, 25, 94, 25, 23, 24, 45, 22, 19, 36, 29},
+ {5230, 25, 94, 25, 22, 24, 45, 22, 19, 35, 29},
+ {5220, 25, 94, 25, 22, 24, 45, 22, 19, 35, 29},
+ {5210, 25, 93, 25, 22, 24, 45, 22, 19, 35, 29},
+ {5200, 25, 93, 24, 22, 24, 44, 21, 19, 35, 29},
+ {5190, 25, 93, 24, 22, 24, 44, 21, 19, 35, 29},
+ {5180, 25, 93, 24, 22, 24, 44, 21, 19, 35, 29},
+ {5170, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29},
+ {5160, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29},
+ {5150, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29},
+ {5140, 25, 92, 24, 22, 24, 44, 21, 19, 35, 29},
+ {5130, 25, 92, 24, 22, 24, 43, 21, 19, 35, 29},
+ {5120, 25, 91, 24, 22, 24, 43, 21, 19, 35, 29},
+ {5110, 25, 91, 24, 22, 24, 43, 21, 19, 35, 29},
+ {5100, 25, 91, 24, 22, 24, 43, 21, 19, 35, 29},
+ {5090, 25, 91, 24, 22, 24, 43, 21, 19, 34, 29},
+ {5080, 25, 90, 24, 22, 24, 43, 21, 19, 34, 29},
+ {5070, 25, 90, 24, 22, 24, 43, 21, 19, 34, 28},
+ {5060, 25, 90, 24, 22, 24, 43, 21, 18, 34, 28},
+ {5050, 24, 91, 24, 22, 24, 42, 21, 18, 34, 28},
+ {5040, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28},
+ {5030, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28},
+ {5020, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28},
+ {5010, 24, 90, 24, 22, 23, 43, 21, 18, 34, 28},
+ {5000, 24, 89, 23, 21, 23, 43, 21, 18, 34, 28},
+ {4990, 24, 89, 23, 21, 23, 43, 21, 18, 34, 28},
+ {4980, 24, 89, 23, 21, 23, 42, 21, 18, 34, 28},
+ {4970, 24, 89, 23, 21, 23, 42, 21, 18, 34, 28},
+ {4960, 24, 89, 23, 21, 23, 42, 20, 18, 34, 28},
+ {4950, 24, 88, 23, 21, 23, 42, 20, 18, 34, 28},
+ {4940, 24, 88, 23, 21, 23, 42, 20, 18, 33, 28},
+ {4930, 24, 88, 23, 21, 23, 42, 20, 18, 33, 28},
+ {4920, 24, 88, 23, 21, 23, 42, 20, 18, 33, 28},
+ {4910, 24, 87, 23, 21, 23, 41, 20, 18, 33, 28},
+ {4900, 24, 87, 23, 21, 23, 41, 20, 18, 33, 27},
+ {4890, 24, 87, 23, 21, 23, 41, 20, 18, 33, 27},
+ {4880, 24, 87, 23, 21, 23, 41, 20, 18, 33, 27},
+ {4870, 24, 86, 23, 21, 23, 41, 20, 18, 33, 27},
+ {4860, 24, 86, 23, 21, 23, 41, 20, 18, 33, 27},
+ {4850, 23, 87, 23, 21, 23, 41, 20, 18, 33, 27},
+ {4840, 23, 87, 23, 21, 23, 40, 20, 18, 33, 27},
+ {4830, 23, 86, 23, 21, 22, 41, 20, 18, 33, 27},
+ {4820, 23, 86, 23, 21, 22, 41, 20, 18, 33, 27},
+ {4810, 23, 86, 23, 21, 22, 41, 20, 18, 33, 27},
+ {4800, 23, 86, 22, 21, 22, 41, 20, 17, 32, 27},
+ {4790, 23, 86, 22, 21, 22, 41, 20, 17, 32, 27},
+ {4780, 23, 85, 22, 21, 22, 41, 20, 17, 32, 27},
+ {4770, 23, 85, 22, 21, 22, 41, 20, 17, 32, 27},
+ {4760, 23, 85, 22, 20, 22, 40, 20, 17, 32, 27},
+ {4750, 23, 85, 22, 20, 22, 40, 20, 17, 32, 27},
+ {4740, 23, 84, 22, 20, 22, 40, 20, 17, 32, 26},
+ {4730, 23, 84, 22, 20, 22, 40, 19, 17, 32, 26},
+ {4720, 23, 84, 22, 20, 22, 40, 19, 17, 32, 26},
+ {4710, 23, 84, 22, 20, 22, 40, 19, 17, 32, 26},
+ {4700, 23, 83, 22, 20, 22, 40, 19, 17, 32, 26},
+ {4690, 23, 83, 22, 20, 22, 39, 19, 17, 32, 26},
+ {4680, 23, 83, 22, 20, 22, 39, 19, 17, 32, 26},
+ {4670, 23, 83, 22, 20, 22, 39, 19, 17, 32, 26},
+ {4660, 23, 82, 22, 20, 22, 39, 19, 17, 32, 26},
+ {4650, 22, 83, 22, 20, 22, 39, 19, 17, 31, 26},
+ {4640, 22, 83, 22, 20, 22, 39, 19, 17, 31, 26},
+ {4630, 22, 83, 22, 20, 22, 39, 19, 17, 31, 26},
+ {4620, 22, 83, 22, 20, 21, 39, 19, 17, 31, 26},
+ {4610, 22, 82, 22, 20, 21, 39, 19, 17, 31, 26},
+ {4600, 22, 82, 21, 20, 21, 39, 19, 17, 31, 26},
+ {4590, 22, 82, 21, 20, 21, 39, 19, 17, 31, 26},
+ {4580, 22, 82, 21, 20, 21, 39, 19, 17, 31, 26},
+ {4570, 22, 81, 21, 20, 21, 39, 19, 17, 31, 25},
+ {4560, 22, 81, 21, 20, 21, 39, 19, 17, 31, 25},
+ {4550, 22, 81, 21, 20, 21, 38, 19, 17, 31, 25},
+ {4540, 22, 81, 21, 20, 21, 38, 19, 17, 31, 25},
+ {4530, 22, 80, 21, 19, 21, 38, 19, 16, 31, 25},
+ {4520, 22, 80, 21, 19, 21, 38, 19, 16, 31, 25},
+ {4510, 22, 80, 21, 19, 21, 38, 19, 16, 31, 25},
+ {4500, 22, 80, 21, 19, 21, 38, 19, 16, 30, 25},
+ {4490, 22, 80, 21, 19, 21, 38, 18, 16, 30, 25},
+ {4480, 22, 79, 21, 19, 21, 38, 18, 16, 30, 25},
+ {4470, 22, 79, 21, 19, 21, 37, 18, 16, 30, 25},
+ {4460, 22, 79, 21, 19, 21, 37, 18, 16, 30, 25},
+ {4450, 21, 80, 21, 19, 21, 37, 18, 16, 30, 25},
+ {4440, 21, 79, 21, 19, 21, 37, 18, 16, 30, 25},
+ {4430, 21, 79, 21, 19, 21, 37, 18, 16, 30, 25},
+ {4420, 21, 79, 21, 19, 21, 37, 18, 16, 30, 25},
+ {4410, 21, 79, 21, 19, 20, 38, 18, 16, 30, 25},
+ {4400, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24},
+ {4390, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24},
+ {4380, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24},
+ {4370, 21, 78, 20, 19, 20, 37, 18, 16, 30, 24},
+ {4360, 21, 77, 20, 19, 20, 37, 18, 16, 29, 24},
+ {4350, 21, 77, 20, 19, 20, 37, 18, 16, 29, 24},
+ {4340, 21, 77, 20, 19, 20, 37, 18, 16, 29, 24},
+ {4330, 21, 77, 20, 19, 20, 36, 18, 16, 29, 24},
+ {4320, 21, 77, 20, 19, 20, 36, 18, 16, 29, 24},
+ {4310, 21, 76, 20, 19, 20, 36, 18, 16, 29, 24},
+ {4300, 21, 76, 20, 18, 20, 36, 18, 16, 29, 24},
+ {4290, 21, 76, 20, 18, 20, 36, 18, 16, 29, 24},
+ {4280, 21, 76, 20, 18, 20, 36, 18, 16, 29, 24},
+ {4270, 21, 75, 20, 18, 20, 36, 18, 16, 29, 24},
+ {4260, 21, 75, 20, 18, 20, 35, 17, 15, 29, 24},
+ {4250, 20, 76, 20, 18, 20, 35, 17, 15, 29, 24},
+ {4240, 20, 76, 20, 18, 20, 35, 17, 15, 29, 23},
+ {4230, 20, 75, 20, 18, 20, 35, 17, 15, 29, 23},
+ {4220, 20, 75, 20, 18, 20, 35, 17, 15, 29, 23},
+ {4210, 20, 75, 20, 18, 20, 35, 17, 15, 28, 23},
+ {4200, 20, 75, 19, 18, 19, 36, 17, 15, 28, 23},
+ {4190, 20, 74, 19, 18, 19, 36, 17, 15, 28, 23},
+ {4180, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23},
+ {4170, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23},
+ {4160, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23},
+ {4150, 20, 74, 19, 18, 19, 35, 17, 15, 28, 23},
+ {4140, 20, 73, 19, 18, 19, 35, 17, 15, 28, 23},
+ {4130, 20, 73, 19, 18, 19, 35, 17, 15, 28, 23},
+ {4120, 20, 73, 19, 18, 19, 35, 17, 15, 28, 23},
+ {4110, 20, 73, 19, 18, 19, 34, 17, 15, 28, 23},
+ {4100, 20, 72, 19, 18, 19, 34, 17, 15, 28, 23},
+ {4090, 20, 72, 19, 18, 19, 34, 17, 15, 28, 23},
+ {4080, 20, 72, 19, 18, 19, 34, 17, 15, 28, 23},
+ {4070, 20, 72, 19, 18, 19, 34, 17, 15, 27, 22},
+ {4060, 19, 72, 19, 17, 19, 34, 17, 15, 27, 22},
+ {4050, 19, 72, 19, 17, 19, 34, 17, 15, 27, 22},
+ {4040, 19, 72, 19, 17, 19, 33, 17, 15, 27, 22},
+ {4030, 19, 72, 19, 17, 19, 33, 17, 15, 27, 22},
+ {4020, 19, 71, 19, 17, 19, 33, 16, 15, 27, 22},
+ {4010, 19, 71, 19, 17, 19, 33, 16, 15, 27, 22},
+ {4000, 19, 71, 18, 17, 19, 33, 16, 14, 27, 22},
+ {3990, 19, 71, 18, 17, 18, 34, 16, 14, 27, 22},
+ {3980, 19, 71, 18, 17, 18, 34, 16, 14, 27, 22},
+ {3970, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22},
+ {3960, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22},
+ {3950, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22},
+ {3940, 19, 70, 18, 17, 18, 33, 16, 14, 27, 22},
+ {3930, 19, 69, 18, 17, 18, 33, 16, 14, 27, 22},
+ {3920, 19, 69, 18, 17, 18, 33, 16, 14, 26, 22},
+ {3910, 19, 69, 18, 17, 18, 33, 16, 14, 26, 22},
+ {3900, 19, 69, 18, 17, 18, 33, 16, 14, 26, 21},
+ {3890, 19, 68, 18, 17, 18, 32, 16, 14, 26, 21},
+ {3880, 19, 68, 18, 17, 18, 32, 16, 14, 26, 21},
+ {3870, 19, 68, 18, 17, 18, 32, 16, 14, 26, 21},
+ {3860, 18, 69, 18, 17, 18, 32, 16, 14, 26, 21},
+ {3850, 18, 68, 18, 17, 18, 32, 16, 14, 26, 21},
+ {3840, 18, 68, 18, 17, 18, 32, 16, 14, 26, 21},
+ {3830, 18, 68, 18, 16, 18, 32, 16, 14, 26, 21},
+ {3820, 18, 68, 18, 16, 18, 31, 16, 14, 26, 21},
+ {3810, 18, 68, 18, 16, 18, 31, 16, 14, 26, 21},
+ {3800, 18, 67, 17, 16, 18, 31, 16, 14, 26, 21},
+ {3790, 18, 67, 17, 16, 17, 32, 15, 14, 26, 21},
+ {3780, 18, 67, 17, 16, 17, 32, 15, 14, 25, 21},
+ {3770, 18, 67, 17, 16, 17, 32, 15, 14, 25, 21},
+ {3760, 18, 66, 17, 16, 17, 32, 15, 14, 25, 21},
+ {3750, 18, 66, 17, 16, 17, 31, 15, 14, 25, 21},
+ {3740, 18, 66, 17, 16, 17, 31, 15, 14, 25, 20},
+ {3730, 18, 66, 17, 16, 17, 31, 15, 13, 25, 20},
+ {3720, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20},
+ {3710, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20},
+ {3700, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20},
+ {3690, 18, 65, 17, 16, 17, 31, 15, 13, 25, 20},
+ {3680, 18, 64, 17, 16, 17, 31, 15, 13, 25, 20},
+ {3670, 18, 64, 17, 16, 17, 30, 15, 13, 25, 20},
+ {3660, 17, 65, 17, 16, 17, 30, 15, 13, 25, 20},
+ {3650, 17, 65, 17, 16, 17, 30, 15, 13, 25, 20},
+ {3640, 17, 65, 17, 16, 17, 30, 15, 13, 25, 20},
+ {3630, 17, 64, 17, 16, 17, 30, 15, 13, 24, 20},
+ {3620, 17, 64, 17, 16, 17, 30, 15, 13, 24, 20},
+ {3610, 17, 64, 17, 16, 17, 30, 15, 13, 24, 20},
+ {3600, 17, 64, 16, 16, 17, 29, 15, 13, 24, 20},
+ {3590, 17, 63, 16, 15, 17, 29, 15, 13, 24, 20},
+ {3580, 17, 63, 16, 15, 16, 30, 15, 13, 24, 20},
+ {3570, 17, 63, 16, 15, 16, 30, 15, 13, 24, 19},
+ {3560, 17, 63, 16, 15, 16, 30, 14, 13, 24, 19},
+ {3550, 17, 62, 16, 15, 16, 30, 14, 13, 24, 19},
+ {3540, 17, 62, 16, 15, 16, 30, 14, 13, 24, 19},
+ {3530, 17, 62, 16, 15, 16, 29, 14, 13, 24, 19},
+ {3520, 17, 62, 16, 15, 16, 29, 14, 13, 24, 19},
+ {3510, 17, 62, 16, 15, 16, 29, 14, 13, 24, 19},
+ {3500, 17, 61, 16, 15, 16, 29, 14, 13, 24, 19},
+ {3490, 17, 61, 16, 15, 16, 29, 14, 13, 23, 19},
+ {3480, 17, 61, 16, 15, 16, 29, 14, 13, 23, 19},
+ {3470, 17, 61, 16, 15, 16, 29, 14, 13, 23, 19},
+ {3460, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19},
+ {3450, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19},
+ {3440, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19},
+ {3430, 16, 61, 16, 15, 16, 28, 14, 12, 23, 19},
+ {3420, 16, 60, 16, 15, 16, 28, 14, 12, 23, 19},
+ {3410, 16, 60, 16, 15, 16, 28, 14, 12, 23, 18},
+ {3400, 16, 60, 15, 15, 16, 28, 14, 12, 23, 18},
+ {3390, 16, 60, 15, 15, 16, 28, 14, 12, 23, 18},
+ {3380, 16, 59, 15, 15, 16, 27, 14, 12, 23, 18},
+ {3370, 16, 59, 15, 15, 15, 28, 14, 12, 23, 18},
+ {3360, 16, 59, 15, 14, 15, 28, 14, 12, 23, 18},
+ {3350, 16, 59, 15, 14, 15, 28, 14, 12, 23, 18},
+ {3340, 16, 59, 15, 14, 15, 28, 14, 12, 22, 18},
+ {3330, 16, 58, 15, 14, 15, 28, 14, 12, 22, 18},
+ {3320, 16, 58, 15, 14, 15, 28, 13, 12, 22, 18},
+ {3310, 16, 58, 15, 14, 15, 27, 13, 12, 22, 18},
+ {3300, 16, 58, 15, 14, 15, 27, 13, 12, 22, 18},
+ {3290, 16, 57, 15, 14, 15, 27, 13, 12, 22, 18},
+ {3280, 16, 57, 15, 14, 15, 27, 13, 12, 22, 18},
+ {3270, 16, 57, 15, 14, 15, 27, 13, 12, 22, 18},
+ {3260, 15, 58, 15, 14, 15, 27, 13, 12, 22, 18},
+ {3250, 15, 57, 15, 14, 15, 27, 13, 12, 22, 18},
+ {3240, 15, 57, 15, 14, 15, 26, 13, 12, 22, 17},
+ {3230, 15, 57, 15, 14, 15, 26, 13, 12, 22, 17},
+ {3220, 15, 57, 15, 14, 15, 26, 13, 12, 22, 17},
+ {3210, 15, 56, 15, 14, 15, 26, 13, 12, 22, 17},
+ {3200, 15, 56, 14, 14, 15, 26, 13, 11, 21, 17},
+ {3190, 15, 56, 14, 14, 15, 26, 13, 11, 21, 17},
+ {3180, 15, 56, 14, 14, 15, 26, 13, 11, 21, 17},
+ {3170, 15, 56, 14, 14, 15, 25, 13, 11, 21, 17},
+ {3160, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17},
+ {3150, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17},
+ {3140, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17},
+ {3130, 15, 55, 14, 14, 14, 26, 13, 11, 21, 17},
+ {3120, 15, 54, 14, 13, 14, 26, 13, 11, 21, 17},
+ {3110, 15, 54, 14, 13, 14, 26, 13, 11, 21, 17},
+ {3100, 15, 54, 14, 13, 14, 26, 13, 11, 21, 17},
+ {3090, 15, 54, 14, 13, 14, 25, 12, 11, 21, 17},
+ {3080, 15, 53, 14, 13, 14, 25, 12, 11, 21, 17},
+ {3070, 14, 54, 14, 13, 14, 25, 12, 11, 21, 16},
+ {3060, 14, 54, 14, 13, 14, 25, 12, 11, 21, 16},
+ {3050, 14, 54, 14, 13, 14, 25, 12, 11, 20, 16},
+ {3040, 14, 53, 14, 13, 14, 25, 12, 11, 20, 16},
+ {3030, 14, 53, 14, 13, 14, 25, 12, 11, 20, 16},
+ {3020, 14, 53, 14, 13, 14, 24, 12, 11, 20, 16},
+ {3010, 14, 53, 14, 13, 14, 24, 12, 11, 20, 16},
+ {3000, 14, 53, 13, 13, 14, 24, 12, 11, 20, 16},
+ {2990, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16},
+ {2980, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16},
+ {2970, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16},
+ {2960, 14, 52, 13, 13, 14, 24, 12, 11, 20, 16},
+ {2950, 14, 51, 13, 13, 13, 24, 12, 11, 20, 16},
+ {2940, 14, 51, 13, 13, 13, 24, 12, 11, 20, 16},
+ {2930, 14, 51, 13, 13, 13, 24, 12, 10, 20, 16},
+ {2920, 14, 51, 13, 13, 13, 24, 12, 10, 20, 16},
+ {2910, 14, 50, 13, 13, 13, 24, 12, 10, 20, 15},
+ {2900, 14, 50, 13, 13, 13, 24, 12, 10, 19, 15},
+ {2890, 14, 50, 13, 12, 13, 24, 12, 10, 19, 15},
+ {2880, 14, 50, 13, 12, 13, 23, 12, 10, 19, 15},
+ {2870, 13, 50, 13, 12, 13, 23, 12, 10, 19, 15},
+ {2860, 13, 50, 13, 12, 13, 23, 12, 10, 19, 15},
+ {2850, 13, 50, 13, 12, 13, 23, 11, 10, 19, 15},
+ {2840, 13, 50, 13, 12, 13, 23, 11, 10, 19, 15},
+ {2830, 13, 50, 13, 12, 13, 23, 11, 10, 19, 15},
+ {2820, 13, 49, 13, 12, 13, 23, 11, 10, 19, 15},
+ {2810, 13, 49, 13, 12, 13, 23, 11, 10, 19, 15},
+ {2800, 13, 49, 12, 12, 13, 22, 11, 10, 19, 15},
+ {2790, 13, 49, 12, 12, 13, 22, 11, 10, 19, 15},
+ {2780, 13, 48, 12, 12, 13, 22, 11, 10, 19, 15},
+ {2770, 13, 48, 12, 12, 13, 22, 11, 10, 19, 15},
+ {2760, 13, 48, 12, 12, 13, 22, 11, 10, 18, 15},
+ {2750, 13, 48, 12, 12, 13, 22, 11, 10, 18, 15},
+ {2740, 13, 47, 12, 12, 12, 23, 11, 10, 18, 14},
+ {2730, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14},
+ {2720, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14},
+ {2710, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14},
+ {2700, 13, 47, 12, 12, 12, 22, 11, 10, 18, 14},
+ {2690, 13, 46, 12, 12, 12, 22, 11, 10, 18, 14},
+ {2680, 13, 46, 12, 12, 12, 22, 11, 10, 18, 14},
+ {2670, 12, 47, 12, 12, 12, 22, 11, 10, 18, 14},
+ {2660, 12, 47, 12, 12, 12, 21, 11, 9, 18, 14},
+ {2650, 12, 46, 12, 11, 12, 21, 11, 9, 18, 14},
+ {2640, 12, 46, 12, 11, 12, 21, 11, 9, 18, 14},
+ {2630, 12, 46, 12, 11, 12, 21, 11, 9, 18, 14},
+ {2620, 12, 46, 12, 11, 12, 21, 10, 9, 18, 14},
+ {2610, 12, 45, 12, 11, 12, 21, 10, 9, 17, 14},
+ {2600, 12, 45, 11, 11, 12, 21, 10, 9, 17, 14},
+ {2590, 12, 45, 11, 11, 12, 20, 10, 9, 17, 14},
+ {2580, 12, 45, 11, 11, 12, 20, 10, 9, 17, 14},
+ {2570, 12, 44, 11, 11, 12, 20, 10, 9, 17, 13},
+ {2560, 12, 44, 11, 11, 12, 20, 10, 9, 17, 13},
+ {2550, 12, 44, 11, 11, 12, 20, 10, 9, 17, 13},
+ {2540, 12, 44, 11, 11, 11, 21, 10, 9, 17, 13},
+ {2530, 12, 44, 11, 11, 11, 21, 10, 9, 17, 13},
+ {2520, 12, 43, 11, 11, 11, 21, 10, 9, 17, 13},
+ {2510, 12, 43, 11, 11, 11, 20, 10, 9, 17, 13},
+ {2500, 12, 43, 11, 11, 11, 20, 10, 9, 17, 13},
+ {2490, 12, 43, 11, 11, 11, 20, 10, 9, 17, 13},
+ {2480, 12, 42, 11, 11, 11, 20, 10, 9, 17, 13},
+ {2470, 11, 43, 11, 11, 11, 20, 10, 9, 16, 13},
+ {2460, 11, 43, 11, 11, 11, 20, 10, 9, 16, 13},
+ {2450, 11, 43, 11, 11, 11, 20, 10, 9, 16, 13},
+ {2440, 11, 42, 11, 11, 11, 19, 10, 9, 16, 13},
+ {2430, 11, 42, 11, 11, 11, 19, 10, 9, 16, 13},
+ {2420, 11, 42, 11, 10, 11, 19, 10, 9, 16, 13},
+ {2410, 11, 42, 11, 10, 11, 19, 10, 9, 16, 12},
+ {2400, 11, 41, 10, 10, 11, 19, 10, 8, 16, 12},
+ {2390, 11, 41, 10, 10, 11, 19, 10, 8, 16, 12},
+ {2380, 11, 41, 10, 10, 11, 19, 9, 8, 16, 12},
+ {2370, 11, 41, 10, 10, 11, 18, 9, 8, 16, 12},
+ {2360, 11, 41, 10, 10, 11, 18, 9, 8, 16, 12},
+ {2350, 11, 40, 10, 10, 11, 18, 9, 8, 16, 12},
+ {2340, 11, 40, 10, 10, 11, 18, 9, 8, 16, 12},
+ {2330, 11, 40, 10, 10, 10, 19, 9, 8, 16, 12},
+ {2320, 11, 40, 10, 10, 10, 19, 9, 8, 15, 12},
+ {2310, 11, 39, 10, 10, 10, 19, 9, 8, 15, 12},
+ {2300, 11, 39, 10, 10, 10, 18, 9, 8, 15, 12},
+ {2290, 11, 39, 10, 10, 10, 18, 9, 8, 15, 12},
+ {2280, 11, 39, 10, 10, 10, 18, 9, 8, 15, 12},
+ {2270, 10, 39, 10, 10, 10, 18, 9, 8, 15, 12},
+ {2260, 10, 39, 10, 10, 10, 18, 9, 8, 15, 12},
+ {2250, 10, 39, 10, 10, 10, 18, 9, 8, 15, 12},
+ {2240, 10, 39, 10, 10, 10, 18, 9, 8, 15, 11},
+ {2230, 10, 38, 10, 10, 10, 18, 9, 8, 15, 11},
+ {2220, 10, 38, 10, 10, 10, 17, 9, 8, 15, 11},
+ {2210, 10, 38, 10, 10, 10, 17, 9, 8, 15, 11},
+ {2200, 10, 38, 9, 10, 10, 17, 9, 8, 15, 11},
+ {2190, 10, 38, 9, 9, 10, 17, 9, 8, 15, 11},
+ {2180, 10, 37, 9, 9, 10, 17, 9, 8, 14, 11},
+ {2170, 10, 37, 9, 9, 10, 17, 9, 8, 14, 11},
+ {2160, 10, 37, 9, 9, 10, 17, 9, 8, 14, 11},
+ {2150, 10, 37, 9, 9, 10, 16, 8, 8, 14, 11},
+ {2140, 10, 36, 9, 9, 10, 16, 8, 8, 14, 11},
+ {2130, 10, 36, 9, 9, 10, 16, 8, 7, 14, 11},
+ {2120, 10, 36, 9, 9, 9, 17, 8, 7, 14, 11},
+ {2110, 10, 36, 9, 9, 9, 17, 8, 7, 14, 11},
+ {2100, 10, 35, 9, 9, 9, 17, 8, 7, 14, 11},
+ {2090, 10, 35, 9, 9, 9, 17, 8, 7, 14, 11},
+ {2080, 9, 36, 9, 9, 9, 16, 8, 7, 14, 11},
+ {2070, 9, 36, 9, 9, 9, 16, 8, 7, 14, 10},
+ {2060, 9, 35, 9, 9, 9, 16, 8, 7, 14, 10},
+ {2050, 9, 35, 9, 9, 9, 16, 8, 7, 14, 10},
+ {2040, 9, 35, 9, 9, 9, 16, 8, 7, 14, 10},
+ {2030, 9, 35, 9, 9, 9, 16, 8, 7, 13, 10},
+ {2020, 9, 35, 9, 9, 9, 16, 8, 7, 13, 10},
+ {2010, 9, 34, 9, 9, 9, 15, 8, 7, 13, 10},
+ {2000, 9, 34, 8, 9, 9, 15, 8, 7, 13, 10},
+ {1990, 9, 34, 8, 9, 9, 15, 8, 7, 13, 10},
+ {1980, 9, 34, 8, 9, 9, 15, 8, 7, 13, 10},
+ {1970, 9, 33, 8, 9, 9, 15, 8, 7, 13, 10},
+ {1960, 9, 33, 8, 9, 9, 15, 8, 7, 13, 10},
+ {1950, 9, 33, 8, 8, 9, 15, 8, 7, 13, 10},
+ {1940, 9, 33, 8, 8, 9, 15, 8, 7, 13, 10},
+ {1930, 9, 32, 8, 8, 9, 14, 8, 7, 13, 10},
+ {1920, 9, 32, 8, 8, 9, 14, 8, 7, 13, 10},
+ {1910, 9, 32, 8, 8, 8, 15, 7, 7, 13, 9},
+ {1900, 9, 32, 8, 8, 8, 15, 7, 7, 13, 9},
+ {1890, 9, 31, 8, 8, 8, 15, 7, 7, 12, 9},
+ {1880, 8, 32, 8, 8, 8, 15, 7, 7, 12, 9},
+ {1870, 8, 32, 8, 8, 8, 15, 7, 7, 12, 9},
+ {1860, 8, 32, 8, 8, 8, 14, 7, 6, 12, 9},
+ {1850, 8, 32, 8, 8, 8, 14, 7, 6, 12, 9},
+ {1840, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9},
+ {1830, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9},
+ {1820, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9},
+ {1810, 8, 31, 8, 8, 8, 14, 7, 6, 12, 9},
+ {1800, 8, 30, 7, 8, 8, 14, 7, 6, 12, 9},
+ {1790, 8, 30, 7, 8, 8, 13, 7, 6, 12, 9},
+ {1780, 8, 30, 7, 8, 8, 13, 7, 6, 12, 9},
+ {1770, 8, 30, 7, 8, 8, 13, 7, 6, 12, 9},
+ {1760, 8, 29, 7, 8, 8, 13, 7, 6, 12, 9},
+ {1750, 8, 29, 7, 8, 8, 13, 7, 6, 12, 9},
+ {1740, 8, 29, 7, 8, 8, 13, 7, 6, 11, 8},
+ {1730, 8, 29, 7, 8, 8, 13, 7, 6, 11, 8},
+ {1720, 8, 29, 7, 7, 8, 13, 7, 6, 11, 8},
+ {1710, 8, 28, 7, 7, 8, 12, 7, 6, 11, 8},
+ {1700, 8, 28, 7, 7, 7, 13, 7, 6, 11, 8},
+ {1690, 8, 28, 7, 7, 7, 13, 7, 6, 11, 8},
+ {1680, 7, 29, 7, 7, 7, 13, 6, 6, 11, 8},
+ {1670, 7, 28, 7, 7, 7, 13, 6, 6, 11, 8},
+ {1660, 7, 28, 7, 7, 7, 13, 6, 6, 11, 8},
+ {1650, 7, 28, 7, 7, 7, 13, 6, 6, 11, 8},
+ {1640, 7, 28, 7, 7, 7, 12, 6, 6, 11, 8},
+ {1630, 7, 27, 7, 7, 7, 12, 6, 6, 11, 8},
+ {1620, 7, 27, 7, 7, 7, 12, 6, 6, 11, 8},
+ {1610, 7, 27, 7, 7, 7, 12, 6, 6, 11, 8},
+ {1600, 7, 27, 6, 7, 7, 12, 6, 5, 10, 8},
+ {1590, 7, 26, 6, 7, 7, 12, 6, 5, 10, 8},
+ {1580, 7, 26, 6, 7, 7, 12, 6, 5, 10, 7},
+ {1570, 7, 26, 6, 7, 7, 11, 6, 5, 10, 7},
+ {1560, 7, 26, 6, 7, 7, 11, 6, 5, 10, 7},
+ {1550, 7, 26, 6, 7, 7, 11, 6, 5, 10, 7},
+ {1540, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7},
+ {1530, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7},
+ {1520, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7},
+ {1510, 7, 25, 6, 7, 7, 11, 6, 5, 10, 7},
+ {1500, 7, 24, 6, 7, 7, 10, 6, 5, 10, 7},
+ {1490, 59, 25, 6, 77, 59, 10, 70, 44, 9, 73},
+ {1480, 59, 24, 6, 76, 58, 10, 70, 44, 9, 73},
+ {1470, 58, 24, 6, 76, 58, 10, 69, 44, 9, 72},
+ {1460, 58, 24, 6, 76, 58, 10, 69, 43, 9, 72},
+ {1450, 58, 24, 6, 75, 57, 10, 68, 43, 9, 71},
+ {1440, 57, 24, 6, 75, 57, 10, 68, 43, 9, 71},
+ {1430, 57, 23, 6, 75, 57, 10, 68, 43, 8, 70},
+ {1420, 56, 23, 6, 74, 57, 9, 67, 43, 8, 70},
+ {1410, 56, 23, 6, 74, 57, 9, 67, 43, 8, 69},
+ {1400, 56, 23, 5, 74, 55, 9, 67, 41, 8, 69},
+ {1390, 55, 23, 5, 73, 55, 9, 66, 41, 8, 68},
+ {1380, 55, 23, 5, 73, 54, 9, 66, 41, 8, 68},
+ {1370, 54, 22, 5, 72, 54, 9, 66, 41, 8, 67},
+ {1360, 54, 22, 5, 72, 54, 9, 65, 40, 8, 67},
+ {1350, 54, 22, 5, 72, 53, 9, 65, 40, 8, 66},
+ {1340, 53, 22, 5, 71, 53, 9, 65, 40, 8, 66},
+ {1330, 53, 22, 5, 71, 53, 9, 64, 39, 8, 65},
+ {1320, 52, 22, 5, 71, 53, 8, 64, 40, 8, 65},
+ {1310, 52, 21, 5, 70, 53, 8, 64, 40, 8, 64},
+ {1300, 51, 21, 5, 70, 51, 8, 63, 38, 8, 64},
+ {1290, 51, 21, 5, 70, 51, 8, 63, 38, 7, 64},
+ {1280, 51, 21, 5, 69, 51, 8, 63, 38, 7, 63},
+ {1270, 50, 21, 5, 69, 50, 8, 62, 38, 7, 63},
+ {1260, 50, 20, 5, 69, 50, 8, 62, 37, 7, 62},
+ {1250, 49, 20, 5, 68, 49, 8, 62, 37, 7, 62},
+ {1240, 49, 20, 5, 68, 49, 8, 61, 37, 7, 61},
+ {1230, 49, 20, 5, 68, 49, 8, 61, 36, 7, 61},
+ {1220, 48, 20, 5, 67, 48, 8, 61, 36, 7, 60},
+ {1210, 48, 19, 5, 67, 48, 7, 60, 36, 7, 60},
+ {1200, 49, 19, 4, 67, 49, 7, 60, 36, 7, 59},
+ {1190, 48, 19, 4, 66, 48, 7, 60, 36, 7, 59},
+ {1180, 48, 19, 4, 66, 48, 7, 59, 36, 7, 58},
+ {1170, 46, 19, 4, 66, 46, 7, 59, 35, 7, 58},
+ {1160, 46, 18, 4, 65, 46, 7, 59, 34, 7, 57},
+ {1150, 45, 18, 4, 65, 46, 7, 58, 34, 7, 57},
+ {1140, 45, 18, 4, 65, 45, 7, 58, 34, 6, 56},
+ {1130, 45, 18, 4, 64, 45, 7, 58, 33, 6, 56},
+ {1120, 44, 18, 4, 64, 44, 7, 57, 33, 6, 55},
+ {1110, 44, 18, 4, 64, 44, 7, 57, 33, 6, 55},
+ {1100, 43, 17, 4, 63, 44, 6, 57, 32, 6, 54},
+ {1090, 43, 17, 4, 63, 44, 6, 56, 33, 6, 54},
+ {1080, 43, 17, 4, 63, 44, 6, 56, 33, 6, 53},
+ {1070, 42, 17, 4, 62, 44, 6, 56, 33, 6, 53},
+ {1060, 42, 17, 4, 62, 42, 6, 55, 31, 6, 52},
+ {1050, 41, 17, 4, 62, 42, 6, 55, 31, 6, 52},
+ {1040, 41, 16, 4, 61, 41, 6, 54, 31, 6, 52},
+ {1030, 41, 16, 4, 61, 41, 6, 54, 30, 6, 51},
+ {1020, 40, 16, 4, 61, 41, 6, 54, 30, 6, 51},
+ {1010, 40, 16, 4, 60, 40, 6, 53, 30, 6, 50},
+ {1000, 39, 16, 3, 60, 40, 6, 53, 29, 5, 50},
+ { 990, 39, 15, 3, 60, 39, 6, 53, 29, 5, 49},
+ { 980, 39, 15, 3, 59, 39, 5, 52, 29, 5, 49},
+ { 970, 38, 15, 3, 59, 39, 5, 52, 29, 5, 48},
+ { 960, 38, 15, 3, 59, 39, 5, 52, 29, 5, 48},
+ { 950, 37, 15, 3, 58, 39, 5, 51, 29, 5, 47},
+ { 940, 37, 14, 3, 58, 39, 5, 51, 29, 5, 47},
+ { 930, 37, 14, 3, 57, 37, 5, 51, 27, 5, 46},
+ { 920, 36, 14, 3, 57, 37, 5, 50, 27, 5, 46},
+ { 910, 36, 14, 3, 57, 36, 5, 50, 27, 5, 45},
+ { 900, 35, 14, 3, 56, 36, 5, 50, 26, 5, 45},
+ { 890, 35, 14, 3, 56, 36, 5, 49, 26, 5, 44},
+ { 880, 35, 13, 3, 56, 35, 5, 49, 26, 5, 44},
+ { 870, 34, 13, 3, 55, 35, 4, 49, 26, 5, 43},
+ { 860, 34, 13, 3, 55, 35, 4, 48, 25, 5, 43},
+ { 850, 33, 13, 3, 55, 35, 4, 48, 26, 4, 42},
+ { 840, 33, 13, 3, 54, 35, 4, 48, 26, 4, 42},
+ { 830, 33, 12, 3, 54, 33, 4, 47, 24, 4, 41},
+ { 820, 32, 12, 3, 54, 33, 4, 47, 24, 4, 41},
+ { 810, 32, 12, 3, 53, 33, 4, 47, 24, 4, 40},
+ { 800, 31, 12, 2, 53, 32, 4, 46, 23, 4, 40},
+ { 790, 31, 12, 2, 53, 32, 4, 46, 23, 4, 39},
+ { 780, 30, 12, 2, 52, 31, 4, 46, 23, 4, 39},
+ { 770, 30, 11, 2, 52, 31, 4, 45, 23, 4, 39},
+ { 760, 30, 11, 2, 52, 31, 3, 45, 22, 4, 38},
+ { 750, 29, 11, 2, 51, 30, 3, 45, 22, 4, 38},
+ { 740, 29, 11, 2, 51, 30, 3, 44, 22, 4, 37},
+ { 730, 28, 11, 2, 51, 31, 3, 44, 22, 4, 37},
+ { 720, 28, 10, 2, 50, 30, 3, 44, 22, 4, 36},
+ { 710, 28, 10, 2, 50, 30, 3, 43, 22, 4, 36},
+ { 700, 27, 10, 2, 50, 28, 3, 43, 20, 3, 35},
+ { 690, 27, 10, 2, 49, 28, 3, 43, 20, 3, 35},
+ { 680, 26, 10, 2, 49, 28, 3, 42, 20, 3, 34},
+ { 670, 26, 10, 2, 49, 27, 3, 42, 20, 3, 34},
+ { 660, 26, 9, 2, 48, 27, 3, 42, 19, 3, 33},
+ { 650, 25, 9, 2, 48, 26, 3, 41, 19, 3, 33},
+ { 640, 25, 9, 2, 48, 26, 2, 41, 19, 3, 32},
+ { 630, 24, 9, 2, 47, 26, 2, 40, 18, 3, 32},
+ { 620, 24, 9, 2, 47, 26, 2, 40, 19, 3, 31},
+ { 610, 24, 8, 2, 47, 26, 2, 40, 19, 3, 31},
+ { 600, 23, 8, 1, 46, 26, 2, 39, 18, 3, 30},
+ { 590, 23, 8, 1, 46, 24, 2, 39, 17, 3, 30},
+ { 580, 22, 8, 1, 46, 24, 2, 39, 17, 3, 29},
+ { 570, 22, 8, 1, 45, 23, 2, 38, 17, 3, 29},
+ { 560, 22, 7, 1, 45, 23, 2, 38, 16, 2, 28},
+ { 550, 21, 7, 1, 45, 23, 2, 38, 16, 2, 28},
+ { 540, 21, 7, 1, 44, 22, 2, 37, 16, 2, 27},
+ { 530, 20, 7, 1, 44, 22, 1, 37, 15, 2, 27},
+ { 520, 20, 7, 1, 43, 21, 1, 37, 15, 2, 27},
+ { 510, 20, 6, 1, 43, 21, 1, 36, 15, 2, 26},
+ { 500, 19, 6, 1, 43, 22, 1, 36, 15, 2, 26},
+ { 490, 19, 6, 1, 42, 21, 1, 36, 15, 2, 25},
+ { 480, 18, 6, 1, 42, 21, 1, 35, 15, 2, 25},
+ { 470, 18, 6, 1, 42, 21, 1, 35, 15, 2, 24},
+ { 460, 18, 6, 1, 41, 19, 1, 35, 13, 2, 24},
+ { 450, 17, 5, 1, 41, 19, 1, 34, 13, 2, 23},
+ { 440, 17, 5, 1, 41, 18, 1, 34, 13, 2, 23},
+ { 430, 16, 5, 1, 40, 18, 0, 34, 12, 2, 22},
+ { 420, 16, 5, 1, 40, 18, 0, 33, 12, 2, 22},
+ { 410, 16, 5, 1, 40, 17, 0, 33, 12, 1, 21},
+ { 400, 15, 5, 0, 39, 17, 0, 33, 11, 1, 21},
+ { 390, 15, 4, 0, 39, 17, 0, 32, 12, 1, 20},
+ { 380, 14, 4, 0, 39, 17, 0, 32, 12, 1, 20},
+ { 370, 14, 4, 0, 38, 17, 0, 32, 12, 1, 19},
+ { 360, 14, 4, 0, 38, 15, 0, 31, 10, 1, 19},
+ { 350, 13, 4, 0, 38, 15, 0, 31, 10, 1, 18},
+ { 340, 13, 3, 0, 37, 15, 0, 31, 10, 1, 18},
+ { 330, 12, 3, 0, 37, 14, 0, 30, 9, 1, 17},
+ { 320, 12, 3, 0, 37, 14, 0, 30, 9, 1, 17},
+ { 310, 12, 3, 0, 36, 13, 0, 30, 9, 1, 16},
+ { 300, 11, 3, 0, 36, 13, 0, 29, 8, 1, 16},
+ { 290, 11, 2, 0, 36, 13, 0, 29, 8, 1, 15},
+ { 280, 10, 2, 0, 35, 12, 0, 29, 8, 1, 15},
+ { 270, 10, 2, 0, 35, 12, 0, 28, 8, 0, 14},
+ { 260, 9, 2, 0, 35, 12, 0, 28, 8, 0, 14},
+ { 250, 9, 2, 0, 34, 12, 0, 28, 8, 0, 14},
+ { 240, 9, 2, 0, 34, 12, 0, 27, 8, 0, 13},
+ { 230, 8, 1, 0, 34, 10, 0, 27, 6, 0, 13},
+ { 220, 8, 1, 0, 33, 10, 0, 27, 6, 0, 12},
+ { 210, 7, 1, 0, 33, 10, 0, 26, 6, 0, 12},
+ { 200, 7, 1, 0, 33, 9, 0, 26, 5, 0, 11},
+ { 190, 7, 1, 0, 32, 9, 0, 25, 5, 0, 11},
+ { 180, 6, 1, 0, 32, 8, 0, 25, 5, 0, 10},
+ { 170, 6, 0, 0, 32, 8, 0, 25, 5, 0, 10},
+ { 160, 5, 0, 0, 31, 8, 0, 24, 4, 0, 9},
+ { 150, 5, 0, 0, 31, 8, 0, 24, 5, 0, 9},
+ { 140, 5, 0, 0, 31, 8, 0, 24, 5, 0, 8},
+ { 130, 4, 0, 0, 30, 6, 0, 23, 3, 0, 8},
+ { 120, 4, 0, 0, 30, 6, 0, 23, 3, 0, 7},
+ { 110, 3, 0, 0, 30, 6, 0, 23, 3, 0, 7},
+ { 100, 3, 0, 0, 29, 5, 0, 22, 2, 0, 6},
+ { 90, 3, 0, 0, 29, 5, 0, 22, 2, 0, 6},
+ { 80, 2, 0, 0, 28, 5, 0, 22, 2, 0, 5},
+};
+
+static void samsung_mipi_dcphy_bias_block_enable(struct samsung_mipi_dcphy *samsung)
+{
+ regmap_write(samsung->regmap, BIAS_CON0, I_DEV_DIV_6 | I_RES_100_2UA);
+ regmap_write(samsung->regmap, BIAS_CON1, I_VBG_SEL_820MV | I_BGR_VREF_820MV |
+ I_LADDER_1_00V);
+ regmap_write(samsung->regmap, BIAS_CON2, REG_325M_325MV | REG_LP_400M_400MV |
+ REG_400M_400MV | REG_645M_645MV);
+
+ /* default output voltage select:
+ * dphy: 400mv
+ * cphy: 530mv
+ */
+ regmap_update_bits(samsung->regmap, BIAS_CON4,
+ I_MUX_SEL_MASK, I_MUX_400MV);
+}
+
+static void samsung_mipi_dphy_lane_enable(struct samsung_mipi_dcphy *samsung)
+{
+ regmap_write(samsung->regmap, DPHY_MC_GNR_CON1, T_PHY_READY(0x2000));
+ regmap_update_bits(samsung->regmap, DPHY_MC_GNR_CON0,
+ PHY_ENABLE, PHY_ENABLE);
+
+ switch (samsung->lanes) {
+ case 4:
+ regmap_write(samsung->regmap, DPHY_MD3_GNR_CON1,
+ T_PHY_READY(0x2000));
+ regmap_update_bits(samsung->regmap, DPHY_MD3_GNR_CON0,
+ PHY_ENABLE, PHY_ENABLE);
+ fallthrough;
+ case 3:
+ regmap_write(samsung->regmap, COMBO_MD2_GNR_CON1,
+ T_PHY_READY(0x2000));
+ regmap_update_bits(samsung->regmap, COMBO_MD2_GNR_CON0,
+ PHY_ENABLE, PHY_ENABLE);
+ fallthrough;
+ case 2:
+ regmap_write(samsung->regmap, COMBO_MD1_GNR_CON1,
+ T_PHY_READY(0x2000));
+ regmap_update_bits(samsung->regmap, COMBO_MD1_GNR_CON0,
+ PHY_ENABLE, PHY_ENABLE);
+ fallthrough;
+ case 1:
+ default:
+ regmap_write(samsung->regmap, COMBO_MD0_GNR_CON1,
+ T_PHY_READY(0x2000));
+ regmap_update_bits(samsung->regmap, COMBO_MD0_GNR_CON0,
+ PHY_ENABLE, PHY_ENABLE);
+ break;
+ }
+}
+
+static void samsung_mipi_dphy_lane_disable(struct samsung_mipi_dcphy *samsung)
+{
+ switch (samsung->lanes) {
+ case 4:
+ regmap_update_bits(samsung->regmap, DPHY_MD3_GNR_CON0,
+ PHY_ENABLE, 0);
+ fallthrough;
+ case 3:
+ regmap_update_bits(samsung->regmap, COMBO_MD2_GNR_CON0,
+ PHY_ENABLE, 0);
+ fallthrough;
+ case 2:
+ regmap_update_bits(samsung->regmap, COMBO_MD1_GNR_CON0,
+ PHY_ENABLE, 0);
+ fallthrough;
+ case 1:
+ default:
+ regmap_update_bits(samsung->regmap, COMBO_MD0_GNR_CON0,
+ PHY_ENABLE, 0);
+ break;
+ }
+
+ regmap_update_bits(samsung->regmap, DPHY_MC_GNR_CON0, PHY_ENABLE, 0);
+}
+
+static void samsung_mipi_dcphy_pll_configure(struct samsung_mipi_dcphy *samsung)
+{
+ regmap_update_bits(samsung->regmap, PLL_CON0, S_MASK | P_MASK,
+ S(samsung->pll.scaler) | P(samsung->pll.prediv));
+
+ if (samsung->pll.dsm < 0) {
+ u16 dsm_tmp;
+
+ /* Using opposite number subtraction to find complement */
+ dsm_tmp = abs(samsung->pll.dsm);
+ dsm_tmp = dsm_tmp - 1;
+ dsm_tmp ^= 0xffff;
+ regmap_write(samsung->regmap, PLL_CON1, dsm_tmp);
+ } else {
+ regmap_write(samsung->regmap, PLL_CON1, samsung->pll.dsm);
+ }
+
+ regmap_update_bits(samsung->regmap, PLL_CON2,
+ M_MASK, M(samsung->pll.fbdiv));
+
+ if (samsung->pll.ssc_en) {
+ regmap_write(samsung->regmap, PLL_CON3,
+ MRR(samsung->pll.mrr) | MFR(samsung->pll.mfr));
+ regmap_update_bits(samsung->regmap, PLL_CON4, SSCG_EN, SSCG_EN);
+ }
+
+ regmap_write(samsung->regmap, PLL_CON5, RESET_N_SEL | PLL_ENABLE_SEL);
+ regmap_write(samsung->regmap, PLL_CON7, PLL_LOCK_CNT(0xf000));
+ regmap_write(samsung->regmap, PLL_CON8, PLL_STB_CNT(0xf000));
+}
+
+static int samsung_mipi_dcphy_pll_enable(struct samsung_mipi_dcphy *samsung)
+{
+ u32 sts;
+ int ret;
+
+ regmap_update_bits(samsung->regmap, PLL_CON0, PLL_EN, PLL_EN);
+
+ ret = regmap_read_poll_timeout(samsung->regmap, PLL_STAT0,
+ sts, (sts & PLL_LOCK), 1000, 20000);
+ if (ret < 0)
+ dev_err(samsung->dev, "DC-PHY pll failed to lock\n");
+
+ return ret;
+}
+
+static void samsung_mipi_dcphy_pll_disable(struct samsung_mipi_dcphy *samsung)
+{
+ regmap_update_bits(samsung->regmap, PLL_CON0, PLL_EN, 0);
+}
+
+static const struct samsung_mipi_dphy_timing *
+samsung_mipi_dphy_get_timing(struct samsung_mipi_dcphy *samsung)
+{
+ const struct samsung_mipi_dphy_timing *timings;
+ unsigned int num_timings;
+ unsigned int lane_mbps = div64_ul(samsung->pll.rate, USEC_PER_SEC);
+ unsigned int i;
+
+ timings = samsung_mipi_dphy_timing_table;
+ num_timings = ARRAY_SIZE(samsung_mipi_dphy_timing_table);
+
+ for (i = num_timings; i > 1; i--)
+ if (lane_mbps <= timings[i - 1].max_lane_mbps)
+ break;
+
+ return &timings[i - 1];
+}
+
+static unsigned long
+samsung_mipi_dcphy_pll_round_rate(struct samsung_mipi_dcphy *samsung,
+ unsigned long prate, unsigned long rate,
+ u8 *prediv, u16 *fbdiv, int *dsm, u8 *scaler)
+{
+ u32 max_fout = samsung->pdata->dphy_tx_max_lane_kbps;
+ u64 best_freq = 0;
+ u64 fin, fvco, fout;
+ u8 min_prediv, max_prediv;
+ u8 _prediv, best_prediv = 1;
+ u16 _fbdiv, best_fbdiv = 1;
+ u8 _scaler, best_scaler = 0;
+ u32 min_delta = UINT_MAX;
+ long _dsm, best_dsm = 0;
+
+ if (!prate) {
+ dev_err(samsung->dev, "parent rate of PLL can not be zero\n");
+ return 0;
+ }
+
+ /*
+ * The PLL output frequency can be calculated using a simple formula:
+ * Fvco = ((m+k/65536) x 2 x Fin) / p
+ * Fout = ((m+k/65536) x 2 x Fin) / (p x 2^s)
+ */
+ fin = div64_ul(prate, MSEC_PER_SEC);
+
+ while (!best_freq) {
+ fout = div64_ul(rate, MSEC_PER_SEC);
+ if (fout > max_fout)
+ fout = max_fout;
+
+ /* 0 ≤ S[2:0] ≤ 6 */
+ for (_scaler = 0; _scaler < 7; _scaler++) {
+ fvco = fout << _scaler;
+
+ /*
+ * 2600MHz ≤ FVCO ≤ 6600MHz
+ */
+ if (fvco < 2600 * MSEC_PER_SEC || fvco > 6600 * MSEC_PER_SEC)
+ continue;
+
+ /* 6MHz ≤ Fref(Fin / p) ≤ 30MHz */
+ min_prediv = DIV_ROUND_UP_ULL(fin, 30 * MSEC_PER_SEC);
+ max_prediv = DIV_ROUND_CLOSEST_ULL(fin, 6 * MSEC_PER_SEC);
+
+ for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
+ u64 delta, tmp;
+
+ _fbdiv = DIV_ROUND_CLOSEST_ULL(fvco * _prediv, 2 * fin);
+
+ /* 64 ≤ M[9:0] ≤ 1023 */
+ if (_fbdiv < 64 || _fbdiv > 1023)
+ continue;
+
+ /* -32767 ≤ K[15:0] ≤ 32767 */
+ _dsm = ((_prediv * fvco) - (2 * _fbdiv * fin));
+ _dsm = DIV_ROUND_UP_ULL(_dsm << 15, fin);
+ if (abs(_dsm) > 32767)
+ continue;
+
+ tmp = DIV_ROUND_CLOSEST_ULL((_fbdiv * fin * 2 * 1000), _prediv);
+ tmp += DIV_ROUND_CLOSEST_ULL((_dsm * fin * 1000), _prediv << 15);
+
+ delta = abs(fvco * MSEC_PER_SEC - tmp);
+ if (delta < min_delta) {
+ best_prediv = _prediv;
+ best_fbdiv = _fbdiv;
+ best_dsm = _dsm;
+ best_scaler = _scaler;
+ min_delta = delta;
+ best_freq = DIV_ROUND_CLOSEST_ULL(tmp, 1000) * MSEC_PER_SEC;
+ }
+ }
+ }
+
+ rate += 100 * MSEC_PER_SEC;
+ }
+
+ *prediv = best_prediv;
+ *fbdiv = best_fbdiv;
+ *dsm = (int)best_dsm & 0xffff;
+ *scaler = best_scaler;
+ dev_dbg(samsung->dev, "p: %d, m: %d, dsm:%ld, scaler: %d\n",
+ best_prediv, best_fbdiv, best_dsm, best_scaler);
+
+ return best_freq >> best_scaler;
+}
+
+static void
+samsung_mipi_dphy_clk_lane_timing_init(struct samsung_mipi_dcphy *samsung)
+{
+ const struct samsung_mipi_dphy_timing *timing;
+ unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC);
+ u32 val, res_up, res_down;
+
+ timing = samsung_mipi_dphy_get_timing(samsung);
+ regmap_write(samsung->regmap, DPHY_MC_GNR_CON0, 0xf000);
+
+ /*
+ * The Drive-Strength / Voltage-Amplitude is adjusted by setting
+ * the Driver-Up Resistor and Driver-Down Resistor.
+ */
+ res_up = samsung->pdata->dphy_hs_drv_res_cfg->clk_hs_drv_up_ohm;
+ res_down = samsung->pdata->dphy_hs_drv_res_cfg->clk_hs_drv_down_ohm;
+ val = EDGE_CON(7) | EDGE_CON_DIR(0) | EDGE_CON_EN |
+ RES_UP(res_up) | RES_DN(res_down);
+ regmap_write(samsung->regmap, DPHY_MC_ANA_CON0, val);
+
+ if (lane_hs_rate >= 4500)
+ regmap_write(samsung->regmap, DPHY_MC_ANA_CON1, 0x0001);
+
+ val = 0;
+ /*
+ * Divide-by-2 Clock from Serial Clock. Use this when data rate is under
+ * 1500Mbps, otherwise divide-by-16 Clock from Serial Clock
+ */
+ if (lane_hs_rate < 1500)
+ val = HSTX_CLK_SEL;
+
+ val |= T_LPX(timing->lpx);
+ /* T_LP_EXIT_SKEW/T_LP_ENTRY_SKEW unconfig */
+ regmap_write(samsung->regmap, DPHY_MC_TIME_CON0, val);
+
+ val = T_CLK_ZERO(timing->clk_zero) | T_CLK_PREPARE(timing->clk_prepare);
+ regmap_write(samsung->regmap, DPHY_MC_TIME_CON1, val);
+
+ val = T_HS_EXIT(timing->hs_exit) | T_CLK_TRAIL(timing->clk_trail_eot);
+ regmap_write(samsung->regmap, DPHY_MC_TIME_CON2, val);
+
+ val = T_CLK_POST(timing->clk_post);
+ regmap_write(samsung->regmap, DPHY_MC_TIME_CON3, val);
+
+ /* Escape Clock is 20.00MHz */
+ regmap_write(samsung->regmap, DPHY_MC_TIME_CON4, 0x1f4);
+
+ /*
+ * skew calibration should be off, if the operation data rate is
+ * under 1.5Gbps or equal to 1.5Gbps.
+ */
+ if (lane_hs_rate > 1500)
+ regmap_write(samsung->regmap, DPHY_MC_DESKEW_CON0, 0x9cb1);
+}
+
+static void
+samsung_mipi_dphy_data_lane_timing_init(struct samsung_mipi_dcphy *samsung)
+{
+ const struct samsung_mipi_dphy_timing *timing;
+ unsigned int lane_hs_rate = div64_ul(samsung->pll.rate, USEC_PER_SEC);
+ u32 val, res_up, res_down;
+
+ timing = samsung_mipi_dphy_get_timing(samsung);
+
+ /*
+ * The Drive-Strength / Voltage-Amplitude is adjusted by adjusting the
+ * Driver-Up Resistor and Driver-Down Resistor.
+ */
+ res_up = samsung->pdata->dphy_hs_drv_res_cfg->data_hs_drv_up_ohm;
+ res_down = samsung->pdata->dphy_hs_drv_res_cfg->data_hs_drv_down_ohm;
+ val = EDGE_CON(7) | EDGE_CON_DIR(0) | EDGE_CON_EN |
+ RES_UP(res_up) | RES_DN(res_down);
+ regmap_write(samsung->regmap, COMBO_MD0_ANA_CON0, val);
+ regmap_write(samsung->regmap, COMBO_MD1_ANA_CON0, val);
+ regmap_write(samsung->regmap, COMBO_MD2_ANA_CON0, val);
+ regmap_write(samsung->regmap, DPHY_MD3_ANA_CON0, val);
+
+ if (lane_hs_rate >= 4500) {
+ regmap_write(samsung->regmap, COMBO_MD0_ANA_CON1, 0x0001);
+ regmap_write(samsung->regmap, COMBO_MD1_ANA_CON1, 0x0001);
+ regmap_write(samsung->regmap, COMBO_MD2_ANA_CON1, 0x0001);
+ regmap_write(samsung->regmap, DPHY_MD3_ANA_CON1, 0x0001);
+ }
+
+ val = 0;
+ /*
+ * Divide-by-2 Clock from Serial Clock. Use this when data rate is under
+ * 1500Mbps, otherwise divide-by-16 Clock from Serial Clock
+ */
+ if (lane_hs_rate < 1500)
+ val = HSTX_CLK_SEL;
+
+ val |= T_LPX(timing->lpx);
+ /* T_LP_EXIT_SKEW/T_LP_ENTRY_SKEW unconfig */
+ regmap_write(samsung->regmap, COMBO_MD0_TIME_CON0, val);
+ regmap_write(samsung->regmap, COMBO_MD1_TIME_CON0, val);
+ regmap_write(samsung->regmap, COMBO_MD2_TIME_CON0, val);
+ regmap_write(samsung->regmap, DPHY_MD3_TIME_CON0, val);
+
+ val = T_HS_ZERO(timing->hs_zero) | T_HS_PREPARE(timing->hs_prepare);
+ regmap_write(samsung->regmap, COMBO_MD0_TIME_CON1, val);
+ regmap_write(samsung->regmap, COMBO_MD1_TIME_CON1, val);
+ regmap_write(samsung->regmap, COMBO_MD2_TIME_CON1, val);
+ regmap_write(samsung->regmap, DPHY_MD3_TIME_CON1, val);
+
+ val = T_HS_EXIT(timing->hs_exit) | T_HS_TRAIL(timing->hs_trail_eot);
+ regmap_write(samsung->regmap, COMBO_MD0_TIME_CON2, val);
+ regmap_write(samsung->regmap, COMBO_MD1_TIME_CON2, val);
+ regmap_write(samsung->regmap, COMBO_MD2_TIME_CON2, val);
+ regmap_write(samsung->regmap, DPHY_MD3_TIME_CON2, val);
+
+ /* TTA-GET/TTA-GO Timing Counter register use default value */
+ val = T_TA_GET(0x3) | T_TA_GO(0x0);
+ regmap_write(samsung->regmap, COMBO_MD0_TIME_CON3, val);
+ regmap_write(samsung->regmap, COMBO_MD1_TIME_CON3, val);
+ regmap_write(samsung->regmap, COMBO_MD2_TIME_CON3, val);
+ regmap_write(samsung->regmap, DPHY_MD3_TIME_CON3, val);
+
+ /* Escape Clock is 20.00MHz */
+ regmap_write(samsung->regmap, COMBO_MD0_TIME_CON4, 0x1f4);
+ regmap_write(samsung->regmap, COMBO_MD1_TIME_CON4, 0x1f4);
+ regmap_write(samsung->regmap, COMBO_MD2_TIME_CON4, 0x1f4);
+ regmap_write(samsung->regmap, DPHY_MD3_TIME_CON4, 0x1f4);
+}
+
+static int samsung_mipi_dphy_power_on(struct samsung_mipi_dcphy *samsung)
+{
+ int ret;
+
+ reset_control_assert(samsung->m_phy_rst);
+
+ samsung_mipi_dcphy_bias_block_enable(samsung);
+ samsung_mipi_dcphy_pll_configure(samsung);
+ samsung_mipi_dphy_clk_lane_timing_init(samsung);
+ samsung_mipi_dphy_data_lane_timing_init(samsung);
+ ret = samsung_mipi_dcphy_pll_enable(samsung);
+ if (ret < 0)
+ return ret;
+
+ samsung_mipi_dphy_lane_enable(samsung);
+
+ reset_control_deassert(samsung->m_phy_rst);
+
+ /* The TSKEWCAL maximum is 100 µsec
+ * at initial calibration.
+ */
+ usleep_range(100, 110);
+
+ return 0;
+}
+
+static int samsung_mipi_dcphy_power_on(struct phy *phy)
+{
+ struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy);
+
+ reset_control_assert(samsung->apb_rst);
+ udelay(1);
+ reset_control_deassert(samsung->apb_rst);
+
+ switch (samsung->type) {
+ case PHY_TYPE_DPHY:
+ return samsung_mipi_dphy_power_on(samsung);
+ default:
+ /* CPHY part to be implemented later */
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static int samsung_mipi_dcphy_power_off(struct phy *phy)
+{
+ struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy);
+
+ switch (samsung->type) {
+ case PHY_TYPE_DPHY:
+ samsung_mipi_dphy_lane_disable(samsung);
+ break;
+ default:
+ /* CPHY part to be implemented later */
+ return -EOPNOTSUPP;
+ }
+
+ samsung_mipi_dcphy_pll_disable(samsung);
+
+ return 0;
+}
+
+static int
+samsung_mipi_dcphy_pll_ssc_modulation_calc(struct samsung_mipi_dcphy *samsung,
+ u8 *mfr, u8 *mrr)
+{
+ unsigned long fin = div64_ul(clk_get_rate(samsung->ref_clk), MSEC_PER_SEC);
+ u16 prediv = samsung->pll.prediv;
+ u16 fbdiv = samsung->pll.fbdiv;
+ u16 min_mfr, max_mfr;
+ u16 _mfr, best_mfr = 0;
+ u16 mr, _mrr, best_mrr = 0;
+
+ /* 20KHz ≤ MF ≤ 150KHz */
+ max_mfr = DIV_ROUND_UP(fin, (20 * prediv) << 5);
+ min_mfr = div64_ul(fin, ((150 * prediv) << 5));
+ /*0 ≤ mfr ≤ 255 */
+ if (max_mfr > 256)
+ max_mfr = 256;
+
+ for (_mfr = min_mfr; _mfr < max_mfr; _mfr++) {
+ /* 1 ≤ mrr ≤ 31 */
+ for (_mrr = 1; _mrr < 32; _mrr++) {
+ mr = DIV_ROUND_UP(_mfr * _mrr * 100, fbdiv << 6);
+ /* 0 ≤ MR ≤ 5% */
+ if (mr > 5)
+ continue;
+
+ if (_mfr * _mrr < 513) {
+ best_mfr = _mfr;
+ best_mrr = _mrr;
+ break;
+ }
+ }
+ }
+
+ if (best_mrr) {
+ *mfr = best_mfr & 0xff;
+ *mrr = best_mrr & 0x3f;
+ } else {
+ dev_err(samsung->dev, "failed to calc ssc parameter mfr and mrr\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void
+samsung_mipi_dcphy_pll_calc_rate(struct samsung_mipi_dcphy *samsung,
+ unsigned long long rate)
+{
+ unsigned long prate = clk_get_rate(samsung->ref_clk);
+ unsigned long fout;
+ u8 scaler = 0, mfr = 0, mrr = 0;
+ u16 fbdiv = 0;
+ u8 prediv = 1;
+ int dsm = 0;
+ int ret;
+
+ fout = samsung_mipi_dcphy_pll_round_rate(samsung, prate, rate,
+ &prediv, &fbdiv, &dsm,
+ &scaler);
+
+ dev_dbg(samsung->dev, "%s: fin=%lu, req_rate=%llu\n",
+ __func__, prate, rate);
+ dev_dbg(samsung->dev, "%s: fout=%lu, prediv=%u, fbdiv=%u\n",
+ __func__, fout, prediv, fbdiv);
+
+ samsung->pll.prediv = prediv;
+ samsung->pll.fbdiv = fbdiv;
+ samsung->pll.dsm = dsm;
+ samsung->pll.scaler = scaler;
+ samsung->pll.rate = fout;
+
+ /*
+ * All DPHY 2.0 compliant Transmitters shall support SSC operating above
+ * 2.5 Gbps
+ */
+ if (fout > 2500000000LL) {
+ ret = samsung_mipi_dcphy_pll_ssc_modulation_calc(samsung,
+ &mfr, &mrr);
+ if (!ret) {
+ samsung->pll.ssc_en = true;
+ samsung->pll.mfr = mfr;
+ samsung->pll.mrr = mrr;
+ }
+ }
+}
+
+static int samsung_mipi_dcphy_configure(struct phy *phy,
+ union phy_configure_opts *opts)
+{
+ struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy);
+ unsigned long long target_rate = opts->mipi_dphy.hs_clk_rate;
+
+ samsung->lanes = opts->mipi_dphy.lanes > 4 ? 4 : opts->mipi_dphy.lanes;
+
+ samsung_mipi_dcphy_pll_calc_rate(samsung, target_rate);
+ opts->mipi_dphy.hs_clk_rate = samsung->pll.rate;
+
+ return 0;
+}
+
+static int samsung_mipi_dcphy_init(struct phy *phy)
+{
+ struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy);
+
+ return pm_runtime_resume_and_get(samsung->dev);
+}
+
+static int samsung_mipi_dcphy_exit(struct phy *phy)
+{
+ struct samsung_mipi_dcphy *samsung = phy_get_drvdata(phy);
+
+ return pm_runtime_put(samsung->dev);
+}
+
+static const struct phy_ops samsung_mipi_dcphy_ops = {
+ .configure = samsung_mipi_dcphy_configure,
+ .power_on = samsung_mipi_dcphy_power_on,
+ .power_off = samsung_mipi_dcphy_power_off,
+ .init = samsung_mipi_dcphy_init,
+ .exit = samsung_mipi_dcphy_exit,
+ .owner = THIS_MODULE,
+};
+
+static const struct regmap_config samsung_mipi_dcphy_regmap_config = {
+ .name = "dcphy",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x10000,
+};
+
+static struct phy *samsung_mipi_dcphy_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct samsung_mipi_dcphy *samsung = dev_get_drvdata(dev);
+
+ if (args->args_count != 1) {
+ dev_err(dev, "invalid number of arguments\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (samsung->type != PHY_NONE && samsung->type != args->args[0])
+ dev_warn(dev, "phy type select %d overwriting type %d\n",
+ args->args[0], samsung->type);
+
+ samsung->type = args->args[0];
+
+ return samsung->phy;
+}
+
+static int samsung_mipi_dcphy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct samsung_mipi_dcphy *samsung;
+ struct phy_provider *phy_provider;
+ struct resource *res;
+ void __iomem *regs;
+ int ret;
+
+ samsung = devm_kzalloc(dev, sizeof(*samsung), GFP_KERNEL);
+ if (!samsung)
+ return -ENOMEM;
+
+ samsung->dev = dev;
+ samsung->pdata = device_get_match_data(dev);
+ platform_set_drvdata(pdev, samsung);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ samsung->regmap = devm_regmap_init_mmio(dev, regs,
+ &samsung_mipi_dcphy_regmap_config);
+ if (IS_ERR(samsung->regmap))
+ return dev_err_probe(dev, PTR_ERR(samsung->regmap), "Failed to init regmap\n");
+
+ samsung->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(samsung->grf_regmap))
+ return dev_err_probe(dev, PTR_ERR(samsung->grf_regmap),
+ "Unable to get rockchip,grf\n");
+
+ samsung->ref_clk = devm_clk_get(dev, "ref");
+ if (IS_ERR(samsung->ref_clk))
+ return dev_err_probe(dev, PTR_ERR(samsung->ref_clk),
+ "Failed to get reference clock\n");
+
+ samsung->pclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(samsung->pclk))
+ return dev_err_probe(dev, PTR_ERR(samsung->pclk), "Failed to get pclk\n");
+
+ samsung->m_phy_rst = devm_reset_control_get(dev, "m_phy");
+ if (IS_ERR(samsung->m_phy_rst))
+ return dev_err_probe(dev, PTR_ERR(samsung->m_phy_rst),
+ "Failed to get system m_phy_rst control\n");
+
+ samsung->s_phy_rst = devm_reset_control_get(dev, "s_phy");
+ if (IS_ERR(samsung->s_phy_rst))
+ return dev_err_probe(dev, PTR_ERR(samsung->s_phy_rst),
+ "Failed to get system s_phy_rst control\n");
+
+ samsung->apb_rst = devm_reset_control_get(dev, "apb");
+ if (IS_ERR(samsung->apb_rst))
+ return dev_err_probe(dev, PTR_ERR(samsung->apb_rst),
+ "Failed to get system apb_rst control\n");
+
+ samsung->grf_apb_rst = devm_reset_control_get(dev, "grf");
+ if (IS_ERR(samsung->grf_apb_rst))
+ return dev_err_probe(dev, PTR_ERR(samsung->grf_apb_rst),
+ "Failed to get system grf_apb_rst control\n");
+
+ samsung->phy = devm_phy_create(dev, NULL, &samsung_mipi_dcphy_ops);
+ if (IS_ERR(samsung->phy))
+ return dev_err_probe(dev, PTR_ERR(samsung->phy), "Failed to create MIPI DC-PHY\n");
+
+ phy_set_drvdata(samsung->phy, samsung);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable runtime PM\n");
+
+ phy_provider = devm_of_phy_provider_register(dev, samsung_mipi_dcphy_xlate);
+ if (IS_ERR(phy_provider))
+ return dev_err_probe(dev, PTR_ERR(phy_provider),
+ "Failed to register phy provider\n");
+
+ return 0;
+}
+
+static __maybe_unused int samsung_mipi_dcphy_runtime_suspend(struct device *dev)
+{
+ struct samsung_mipi_dcphy *samsung = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(samsung->ref_clk);
+ clk_disable_unprepare(samsung->pclk);
+
+ return 0;
+}
+
+static __maybe_unused int samsung_mipi_dcphy_runtime_resume(struct device *dev)
+{
+ struct samsung_mipi_dcphy *samsung = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(samsung->pclk);
+ if (ret) {
+ dev_err(samsung->dev, "Failed to enable pclk, %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(samsung->ref_clk);
+ if (ret) {
+ dev_err(samsung->dev, "Failed to enable reference clock, %d\n", ret);
+ clk_disable_unprepare(samsung->pclk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops samsung_mipi_dcphy_pm_ops = {
+ SET_RUNTIME_PM_OPS(samsung_mipi_dcphy_runtime_suspend,
+ samsung_mipi_dcphy_runtime_resume, NULL)
+};
+
+static const struct hs_drv_res_cfg rk3576_dphy_hs_drv_res_cfg = {
+ .clk_hs_drv_up_ohm = STRENGTH_52_OHM,
+ .clk_hs_drv_down_ohm = STRENGTH_52_OHM,
+ .data_hs_drv_up_ohm = STRENGTH_39_OHM,
+ .data_hs_drv_down_ohm = STRENGTH_39_OHM,
+};
+
+static const struct hs_drv_res_cfg rk3588_dphy_hs_drv_res_cfg = {
+ .clk_hs_drv_up_ohm = STRENGTH_34_OHM,
+ .clk_hs_drv_down_ohm = STRENGTH_34_OHM,
+ .data_hs_drv_up_ohm = STRENGTH_43_OHM,
+ .data_hs_drv_down_ohm = STRENGTH_43_OHM,
+};
+
+static const struct samsung_mipi_dcphy_plat_data rk3576_samsung_mipi_dcphy_plat_data = {
+ .dphy_hs_drv_res_cfg = &rk3576_dphy_hs_drv_res_cfg,
+ .dphy_tx_max_lane_kbps = 2500000L,
+};
+
+static const struct samsung_mipi_dcphy_plat_data rk3588_samsung_mipi_dcphy_plat_data = {
+ .dphy_hs_drv_res_cfg = &rk3588_dphy_hs_drv_res_cfg,
+ .dphy_tx_max_lane_kbps = 4500000L,
+};
+
+static const struct of_device_id samsung_mipi_dcphy_of_match[] = {
+ {
+ .compatible = "rockchip,rk3576-mipi-dcphy",
+ .data = &rk3576_samsung_mipi_dcphy_plat_data,
+ }, {
+ .compatible = "rockchip,rk3588-mipi-dcphy",
+ .data = &rk3588_samsung_mipi_dcphy_plat_data,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, samsung_mipi_dcphy_of_match);
+
+static struct platform_driver samsung_mipi_dcphy_driver = {
+ .driver = {
+ .name = "samsung-mipi-dcphy",
+ .of_match_table = samsung_mipi_dcphy_of_match,
+ .pm = &samsung_mipi_dcphy_pm_ops,
+ },
+ .probe = samsung_mipi_dcphy_probe,
+};
+module_platform_driver(samsung_mipi_dcphy_driver);
+
+MODULE_AUTHOR("Guochun Huang <hero.huang@rock-chips.com>");
+MODULE_DESCRIPTION("Samsung MIPI DCPHY Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
index 0965b9d4f9cf..61db514ce5cf 100644
--- a/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
+++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c
@@ -25,6 +25,7 @@
#define HDPTX_I_PLL_EN BIT(7)
#define HDPTX_I_BIAS_EN BIT(6)
#define HDPTX_I_BGR_EN BIT(5)
+#define HDPTX_MODE_SEL BIT(0)
#define GRF_HDPTX_STATUS 0x80
#define HDPTX_O_PLL_LOCK_DONE BIT(3)
#define HDPTX_O_PHY_CLK_RDY BIT(2)
@@ -44,66 +45,130 @@
#define LANE_REG(n) HDTPX_REG(n, 0300, 062d)
/* CMN_REG(0008) */
+#define OVRD_LCPLL_EN_MASK BIT(7)
#define LCPLL_EN_MASK BIT(6)
#define LCPLL_LCVCO_MODE_EN_MASK BIT(4)
/* CMN_REG(001e) */
#define LCPLL_PI_EN_MASK BIT(5)
#define LCPLL_100M_CLK_EN_MASK BIT(0)
/* CMN_REG(0025) */
-#define LCPLL_PMS_IQDIV_RSTN BIT(4)
+#define LCPLL_PMS_IQDIV_RSTN_MASK BIT(4)
/* CMN_REG(0028) */
-#define LCPLL_SDC_FRAC_EN BIT(2)
-#define LCPLL_SDC_FRAC_RSTN BIT(0)
+#define LCPLL_SDC_FRAC_EN_MASK BIT(2)
+#define LCPLL_SDC_FRAC_RSTN_MASK BIT(0)
/* CMN_REG(002d) */
#define LCPLL_SDC_N_MASK GENMASK(3, 1)
/* CMN_REG(002e) */
#define LCPLL_SDC_NUMBERATOR_MASK GENMASK(5, 0)
/* CMN_REG(002f) */
#define LCPLL_SDC_DENOMINATOR_MASK GENMASK(7, 2)
-#define LCPLL_SDC_NDIV_RSTN BIT(0)
+#define LCPLL_SDC_NDIV_RSTN_MASK BIT(0)
+/* CMN_REG(003c) */
+#define ANA_LCPLL_RESERVED7_MASK BIT(7)
/* CMN_REG(003d) */
-#define ROPLL_LCVCO_EN BIT(4)
+#define OVRD_ROPLL_EN_MASK BIT(7)
+#define ROPLL_EN_MASK BIT(6)
+#define ROPLL_LCVCO_EN_MASK BIT(4)
+/* CMN_REG(0046) */
+#define ROPLL_ANA_CPP_CTRL_COARSE_MASK GENMASK(7, 4)
+#define ROPLL_ANA_CPP_CTRL_FINE_MASK GENMASK(3, 0)
+/* CMN_REG(0047) */
+#define ROPLL_ANA_LPF_C_SEL_COARSE_MASK GENMASK(5, 3)
+#define ROPLL_ANA_LPF_C_SEL_FINE_MASK GENMASK(2, 0)
/* CMN_REG(004e) */
-#define ROPLL_PI_EN BIT(5)
+#define ROPLL_PI_EN_MASK BIT(5)
+/* CMN_REG(0051) */
+#define ROPLL_PMS_MDIV_MASK GENMASK(7, 0)
+/* CMN_REG(0055) */
+#define ROPLL_PMS_MDIV_AFC_MASK GENMASK(7, 0)
+/* CMN_REG(0059) */
+#define ANA_ROPLL_PMS_PDIV_MASK GENMASK(7, 4)
+#define ANA_ROPLL_PMS_REFDIV_MASK GENMASK(3, 0)
+/* CMN_REG(005a) */
+#define ROPLL_PMS_SDIV_RBR_MASK GENMASK(7, 4)
+#define ROPLL_PMS_SDIV_HBR_MASK GENMASK(3, 0)
+/* CMN_REG(005b) */
+#define ROPLL_PMS_SDIV_HBR2_MASK GENMASK(7, 4)
/* CMN_REG(005c) */
-#define ROPLL_PMS_IQDIV_RSTN BIT(5)
+#define ROPLL_PMS_IQDIV_RSTN_MASK BIT(5)
/* CMN_REG(005e) */
#define ROPLL_SDM_EN_MASK BIT(6)
-#define ROPLL_SDM_FRAC_EN_RBR BIT(3)
-#define ROPLL_SDM_FRAC_EN_HBR BIT(2)
-#define ROPLL_SDM_FRAC_EN_HBR2 BIT(1)
-#define ROPLL_SDM_FRAC_EN_HBR3 BIT(0)
+#define OVRD_ROPLL_SDM_RSTN_MASK BIT(5)
+#define ROPLL_SDM_RSTN_MASK BIT(4)
+#define ROPLL_SDC_FRAC_EN_RBR_MASK BIT(3)
+#define ROPLL_SDC_FRAC_EN_HBR_MASK BIT(2)
+#define ROPLL_SDC_FRAC_EN_HBR2_MASK BIT(1)
+#define ROPLL_SDM_FRAC_EN_HBR3_MASK BIT(0)
+/* CMN_REG(005f) */
+#define OVRD_ROPLL_SDC_RSTN_MASK BIT(5)
+#define ROPLL_SDC_RSTN_MASK BIT(4)
+/* CMN_REG(0060) */
+#define ROPLL_SDM_DENOMINATOR_MASK GENMASK(7, 0)
/* CMN_REG(0064) */
#define ROPLL_SDM_NUM_SIGN_RBR_MASK BIT(3)
+#define ROPLL_SDM_NUM_SIGN_HBR_MASK BIT(2)
+#define ROPLL_SDM_NUM_SIGN_HBR2_MASK BIT(1)
+/* CMN_REG(0065) */
+#define ROPLL_SDM_NUM_MASK GENMASK(7, 0)
/* CMN_REG(0069) */
#define ROPLL_SDC_N_RBR_MASK GENMASK(2, 0)
+/* CMN_REG(006a) */
+#define ROPLL_SDC_N_HBR_MASK GENMASK(5, 3)
+#define ROPLL_SDC_N_HBR2_MASK GENMASK(2, 0)
+/* CMN_REG(006b) */
+#define ROPLL_SDC_N_HBR3_MASK GENMASK(3, 1)
+/* CMN_REG(006c) */
+#define ROPLL_SDC_NUM_MASK GENMASK(5, 0)
+/* cmn_reg0070 */
+#define ROPLL_SDC_DENO_MASK GENMASK(5, 0)
/* CMN_REG(0074) */
-#define ROPLL_SDC_NDIV_RSTN BIT(2)
-#define ROPLL_SSC_EN BIT(0)
+#define OVRD_ROPLL_SDC_NDIV_RSTN_MASK BIT(3)
+#define ROPLL_SDC_NDIV_RSTN_MASK BIT(2)
+#define OVRD_ROPLL_SSC_EN_MASK BIT(1)
+#define ROPLL_SSC_EN_MASK BIT(0)
+/* CMN_REG(0075) */
+#define ANA_ROPLL_SSC_FM_DEVIATION_MASK GENMASK(5, 0)
+/* CMN_REG(0076) */
+#define ANA_ROPLL_SSC_FM_FREQ_MASK GENMASK(6, 2)
+/* CMN_REG(0077) */
+#define ANA_ROPLL_SSC_CLK_DIV_SEL_MASK GENMASK(6, 3)
/* CMN_REG(0081) */
-#define OVRD_PLL_CD_CLK_EN BIT(8)
-#define PLL_CD_HSCLK_EAST_EN BIT(0)
+#define OVRD_PLL_CD_CLK_EN_MASK BIT(8)
+#define ANA_PLL_CD_TX_SER_RATE_SEL_MASK BIT(3)
+#define ANA_PLL_CD_HSCLK_WEST_EN_MASK BIT(1)
+#define ANA_PLL_CD_HSCLK_EAST_EN_MASK BIT(0)
+/* CMN_REG(0082) */
+#define ANA_PLL_CD_VREG_GAIN_CTRL_MASK GENMASK(3, 0)
+/* CMN_REG(0083) */
+#define ANA_PLL_CD_VREG_ICTRL_MASK GENMASK(6, 5)
+/* CMN_REG(0084) */
+#define PLL_LCRO_CLK_SEL_MASK BIT(5)
+/* CMN_REG(0085) */
+#define ANA_PLL_SYNC_LOSS_DET_MODE_MASK GENMASK(1, 0)
/* CMN_REG(0086) */
#define PLL_PCG_POSTDIV_SEL_MASK GENMASK(7, 4)
#define PLL_PCG_CLK_SEL_MASK GENMASK(3, 1)
-#define PLL_PCG_CLK_EN BIT(0)
+#define PLL_PCG_CLK_EN_MASK BIT(0)
/* CMN_REG(0087) */
-#define PLL_FRL_MODE_EN BIT(3)
-#define PLL_TX_HS_CLK_EN BIT(2)
+#define ANA_PLL_FRL_MODE_EN_MASK BIT(3)
+#define ANA_PLL_TX_HS_CLK_EN_MASK BIT(2)
/* CMN_REG(0089) */
-#define LCPLL_ALONE_MODE BIT(1)
+#define LCPLL_ALONE_MODE_MASK BIT(1)
+/* CMN_REG(0095) */
+#define DP_TX_LINK_BW_MASK GENMASK(1, 0)
/* CMN_REG(0097) */
-#define DIG_CLK_SEL BIT(1)
-#define ROPLL_REF BIT(1)
-#define LCPLL_REF 0
+#define DIG_CLK_SEL_MASK BIT(1)
+#define LCPLL_REF BIT(1)
+#define ROPLL_REF 0
/* CMN_REG(0099) */
-#define CMN_ROPLL_ALONE_MODE BIT(2)
+#define SSC_EN_MASK GENMASK(7, 6)
+#define CMN_ROPLL_ALONE_MODE_MASK BIT(2)
#define ROPLL_ALONE_MODE BIT(2)
/* CMN_REG(009a) */
-#define HS_SPEED_SEL BIT(0)
+#define HS_SPEED_SEL_MASK BIT(0)
#define DIV_10_CLOCK BIT(0)
/* CMN_REG(009b) */
-#define IS_SPEED_SEL BIT(4)
+#define LS_SPEED_SEL_MASK BIT(4)
#define LINK_SYMBOL_CLOCK BIT(4)
#define LINK_SYMBOL_CLOCK1_2 0
@@ -118,6 +183,8 @@
/* SB_REG(0104) */
#define OVRD_SB_EN_MASK BIT(5)
#define SB_EN_MASK BIT(4)
+#define OVRD_SB_AUX_EN_MASK BIT(1)
+#define SB_AUX_EN_MASK BIT(0)
/* SB_REG(0105) */
#define OVRD_SB_EARC_CMDC_EN_MASK BIT(6)
#define SB_EARC_CMDC_EN_MASK BIT(5)
@@ -126,6 +193,8 @@
#define ANA_SB_TX_LLVL_PROG_MASK GENMASK(6, 4)
/* SB_REG(0109) */
#define ANA_SB_DMRX_AFC_DIV_RATIO_MASK GENMASK(2, 0)
+/* SB_REG(010d) */
+#define ANA_SB_DMRX_LPBK_DATA_MASK BIT(4)
/* SB_REG(010f) */
#define OVRD_SB_VREG_EN_MASK BIT(7)
#define SB_VREG_EN_MASK BIT(6)
@@ -133,6 +202,7 @@
#define SB_VREG_LPF_BYPASS_MASK BIT(4)
#define ANA_SB_VREG_GAIN_CTRL_MASK GENMASK(3, 0)
/* SB_REG(0110) */
+#define ANA_SB_VREG_OUT_SEL_MASK BIT(1)
#define ANA_SB_VREG_REF_SEL_MASK BIT(0)
/* SB_REG(0113) */
#define SB_RX_RCAL_OPT_CODE_MASK GENMASK(5, 4)
@@ -147,13 +217,24 @@
#define AFC_RSTN_DELAY_TIME_MASK GENMASK(6, 4)
/* SB_REG(0117) */
#define FAST_PULSE_TIME_MASK GENMASK(3, 0)
+/* SB_REG(0118) */
+#define SB_TG_EARC_DMRX_RECVRD_CLK_CNT_MASK GENMASK(7, 0)
+/* SB_REG(011a) */
+#define SB_TG_CNT_RUN_NO_7_0_MASK GENMASK(7, 0)
/* SB_REG(011b) */
#define SB_EARC_SIG_DET_BYPASS_MASK BIT(4)
#define SB_AFC_TOL_MASK GENMASK(3, 0)
+/* SB_REG(011c) */
+#define SB_AFC_STB_NUM_MASK GENMASK(3, 0)
+/* SB_REG(011d) */
+#define SB_TG_OSC_CNT_MIN_MASK GENMASK(7, 0)
+/* SB_REG(011e) */
+#define SB_TG_OSC_CNT_MAX_MASK GENMASK(7, 0)
/* SB_REG(011f) */
#define SB_PWM_AFC_CTRL_MASK GENMASK(7, 2)
#define SB_RCAL_RSTN_MASK BIT(1)
/* SB_REG(0120) */
+#define SB_AUX_EN_IN_MASK BIT(7)
#define SB_EARC_EN_MASK BIT(1)
#define SB_EARC_AFC_EN_MASK BIT(2)
/* SB_REG(0123) */
@@ -161,39 +242,93 @@
#define SB_READY_MASK BIT(4)
/* LNTOP_REG(0200) */
-#define PROTOCOL_SEL BIT(2)
+#define PROTOCOL_SEL_MASK BIT(2)
#define HDMI_MODE BIT(2)
#define HDMI_TMDS_FRL_SEL BIT(1)
/* LNTOP_REG(0206) */
-#define DATA_BUS_SEL BIT(0)
+#define DATA_BUS_WIDTH_MASK GENMASK(2, 1)
+#define DATA_BUS_WIDTH_SEL_MASK BIT(0)
#define DATA_BUS_36_40 BIT(0)
/* LNTOP_REG(0207) */
-#define LANE_EN 0xf
+#define LANE_EN_MASK 0xf
#define ALL_LANE_EN 0xf
+/* LANE_REG(0301) */
+#define OVRD_LN_TX_DRV_EI_EN_MASK BIT(7)
+#define LN_TX_DRV_EI_EN_MASK BIT(6)
+/* LANE_REG(0303) */
+#define OVRD_LN_TX_DRV_LVL_CTRL_MASK BIT(5)
+#define LN_TX_DRV_LVL_CTRL_MASK GENMASK(4, 0)
+/* LANE_REG(0304) */
+#define OVRD_LN_TX_DRV_POST_LVL_CTRL_MASK BIT(4)
+#define LN_TX_DRV_POST_LVL_CTRL_MASK GENMASK(3, 0)
+/* LANE_REG(0305) */
+#define OVRD_LN_TX_DRV_PRE_LVL_CTRL_MASK BIT(6)
+#define LN_TX_DRV_PRE_LVL_CTRL_MASK GENMASK(5, 2)
+/* LANE_REG(0306) */
+#define LN_ANA_TX_DRV_IDRV_IDN_CTRL_MASK GENMASK(7, 5)
+#define LN_ANA_TX_DRV_IDRV_IUP_CTRL_MASK GENMASK(4, 2)
+#define LN_ANA_TX_DRV_ACCDRV_EN_MASK BIT(0)
+/* LANE_REG(0307) */
+#define LN_ANA_TX_DRV_ACCDRV_POL_SEL_MASK BIT(6)
+#define LN_ANA_TX_DRV_ACCDRV_CTRL_MASK GENMASK(5, 3)
+/* LANE_REG(030a) */
+#define LN_ANA_TX_JEQ_EN_MASK BIT(4)
+#define LN_TX_JEQ_EVEN_CTRL_RBR_MASK GENMASK(3, 0)
+/* LANE_REG(030b) */
+#define LN_TX_JEQ_EVEN_CTRL_HBR_MASK GENMASK(7, 4)
+#define LN_TX_JEQ_EVEN_CTRL_HBR2_MASK GENMASK(3, 0)
+/* LANE_REG(030c) */
+#define LN_TX_JEQ_ODD_CTRL_RBR_MASK GENMASK(3, 0)
+/* LANE_REG(030d) */
+#define LN_TX_JEQ_ODD_CTRL_HBR_MASK GENMASK(7, 4)
+#define LN_TX_JEQ_ODD_CTRL_HBR2_MASK GENMASK(3, 0)
+/* LANE_REG(0310) */
+#define LN_ANA_TX_SYNC_LOSS_DET_MODE_MASK GENMASK(1, 0)
+/* LANE_REG(0311) */
+#define LN_TX_SER_40BIT_EN_RBR_MASK BIT(3)
+#define LN_TX_SER_40BIT_EN_HBR_MASK BIT(2)
+#define LN_TX_SER_40BIT_EN_HBR2_MASK BIT(1)
/* LANE_REG(0312) */
-#define LN0_TX_SER_RATE_SEL_RBR BIT(5)
-#define LN0_TX_SER_RATE_SEL_HBR BIT(4)
-#define LN0_TX_SER_RATE_SEL_HBR2 BIT(3)
-#define LN0_TX_SER_RATE_SEL_HBR3 BIT(2)
+#define LN0_TX_SER_RATE_SEL_RBR_MASK BIT(5)
+#define LN0_TX_SER_RATE_SEL_HBR_MASK BIT(4)
+#define LN0_TX_SER_RATE_SEL_HBR2_MASK BIT(3)
+#define LN0_TX_SER_RATE_SEL_HBR3_MASK BIT(2)
+/* LANE_REG(0316) */
+#define LN_ANA_TX_SER_VREG_GAIN_CTRL_MASK GENMASK(3, 0)
+/* LANE_REG(031B) */
+#define LN_ANA_TX_RESERVED_MASK GENMASK(7, 0)
+/* LANE_REG(031e) */
+#define LN_POLARITY_INV_MASK BIT(2)
+#define LN_LANE_MODE_MASK BIT(1)
+
/* LANE_REG(0412) */
-#define LN1_TX_SER_RATE_SEL_RBR BIT(5)
-#define LN1_TX_SER_RATE_SEL_HBR BIT(4)
-#define LN1_TX_SER_RATE_SEL_HBR2 BIT(3)
-#define LN1_TX_SER_RATE_SEL_HBR3 BIT(2)
+#define LN1_TX_SER_RATE_SEL_RBR_MASK BIT(5)
+#define LN1_TX_SER_RATE_SEL_HBR_MASK BIT(4)
+#define LN1_TX_SER_RATE_SEL_HBR2_MASK BIT(3)
+#define LN1_TX_SER_RATE_SEL_HBR3_MASK BIT(2)
+
/* LANE_REG(0512) */
-#define LN2_TX_SER_RATE_SEL_RBR BIT(5)
-#define LN2_TX_SER_RATE_SEL_HBR BIT(4)
-#define LN2_TX_SER_RATE_SEL_HBR2 BIT(3)
-#define LN2_TX_SER_RATE_SEL_HBR3 BIT(2)
+#define LN2_TX_SER_RATE_SEL_RBR_MASK BIT(5)
+#define LN2_TX_SER_RATE_SEL_HBR_MASK BIT(4)
+#define LN2_TX_SER_RATE_SEL_HBR2_MASK BIT(3)
+#define LN2_TX_SER_RATE_SEL_HBR3_MASK BIT(2)
+
/* LANE_REG(0612) */
-#define LN3_TX_SER_RATE_SEL_RBR BIT(5)
-#define LN3_TX_SER_RATE_SEL_HBR BIT(4)
-#define LN3_TX_SER_RATE_SEL_HBR2 BIT(3)
-#define LN3_TX_SER_RATE_SEL_HBR3 BIT(2)
+#define LN3_TX_SER_RATE_SEL_RBR_MASK BIT(5)
+#define LN3_TX_SER_RATE_SEL_HBR_MASK BIT(4)
+#define LN3_TX_SER_RATE_SEL_HBR2_MASK BIT(3)
+#define LN3_TX_SER_RATE_SEL_HBR3_MASK BIT(2)
+#define HDMI14_MAX_RATE 340000000
#define HDMI20_MAX_RATE 600000000
+enum dp_link_rate {
+ DP_BW_RBR,
+ DP_BW_HBR,
+ DP_BW_HBR2,
+};
+
struct lcpll_config {
u32 bit_rate;
u8 lcvco_mode_en;
@@ -255,6 +390,19 @@ struct ropll_config {
u8 cd_tx_ser_rate_sel;
};
+struct tx_drv_ctrl {
+ u8 tx_drv_lvl_ctrl;
+ u8 tx_drv_post_lvl_ctrl;
+ u8 ana_tx_drv_idrv_idn_ctrl;
+ u8 ana_tx_drv_idrv_iup_ctrl;
+ u8 ana_tx_drv_accdrv_en;
+ u8 ana_tx_drv_accdrv_ctrl;
+ u8 tx_drv_pre_lvl_ctrl;
+ u8 ana_tx_jeq_en;
+ u8 tx_jeq_even_ctrl;
+ u8 tx_jeq_odd_ctrl;
+};
+
enum rk_hdptx_reset {
RST_APB = 0,
RST_INIT,
@@ -263,11 +411,22 @@ enum rk_hdptx_reset {
RST_MAX
};
+#define MAX_HDPTX_PHY_NUM 2
+
+struct rk_hdptx_phy_cfg {
+ unsigned int num_phys;
+ unsigned int phy_ids[MAX_HDPTX_PHY_NUM];
+};
+
struct rk_hdptx_phy {
struct device *dev;
struct regmap *regmap;
struct regmap *grf;
+ /* PHY const config */
+ const struct rk_hdptx_phy_cfg *cfgs;
+ int phy_id;
+
struct phy *phy;
struct phy_config *phy_cfg;
struct clk_bulk_data *clks;
@@ -279,6 +438,10 @@ struct rk_hdptx_phy {
unsigned long rate;
atomic_t usage_count;
+
+ /* used for dp mode */
+ unsigned int link_rate;
+ unsigned int lanes;
};
static const struct ropll_config ropll_tmds_cfg[] = {
@@ -314,6 +477,8 @@ static const struct ropll_config ropll_tmds_cfg[] = {
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
{ 650000, 162, 162, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 54, 0, 16, 4, 1,
1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
+ { 502500, 84, 84, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 11, 1, 4, 5,
+ 4, 11, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
{ 337500, 0x70, 0x70, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 0x2, 0, 0x01, 5,
1, 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, },
{ 400000, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0,
@@ -557,16 +722,100 @@ static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = {
REG_SEQ0(LANE_REG(0606), 0x1c),
};
+static struct tx_drv_ctrl tx_drv_ctrl_rbr[4][4] = {
+ /* voltage swing 0, pre-emphasis 0->3 */
+ {
+ { 0x2, 0x0, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ { 0x4, 0x3, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0x7, 0x6, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0xd, 0xc, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 },
+ },
+
+ /* voltage swing 1, pre-emphasis 0->2 */
+ {
+ { 0x4, 0x0, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ { 0x9, 0x5, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0xc, 0x8, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 },
+ },
+
+ /* voltage swing 2, pre-emphasis 0->1 */
+ {
+ { 0x8, 0x0, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ { 0xc, 0x5, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 },
+ },
+
+ /* voltage swing 3, pre-emphasis 0 */
+ {
+ { 0xb, 0x0, 0x7, 0x7, 0x1, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ }
+};
+
+static struct tx_drv_ctrl tx_drv_ctrl_hbr[4][4] = {
+ /* voltage swing 0, pre-emphasis 0->3 */
+ {
+ { 0x2, 0x0, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ { 0x5, 0x4, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0x9, 0x8, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0xd, 0xc, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 },
+ },
+
+ /* voltage swing 1, pre-emphasis 0->2 */
+ {
+ { 0x6, 0x1, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ { 0xa, 0x6, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0xc, 0x8, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 },
+ },
+
+ /* voltage swing 2, pre-emphasis 0->1 */
+ {
+ { 0x9, 0x1, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ { 0xd, 0x6, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 },
+ },
+
+ /* voltage swing 3, pre-emphasis 0 */
+ {
+ { 0xc, 0x1, 0x7, 0x7, 0x1, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ }
+};
+
+static struct tx_drv_ctrl tx_drv_ctrl_hbr2[4][4] = {
+ /* voltage swing 0, pre-emphasis 0->3 */
+ {
+ { 0x2, 0x1, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0x5, 0x4, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0x9, 0x8, 0x4, 0x6, 0x1, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0xd, 0xc, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 },
+ },
+
+ /* voltage swing 1, pre-emphasis 0->2 */
+ {
+ { 0x6, 0x1, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ { 0xb, 0x7, 0x4, 0x6, 0x0, 0x4, 0x0, 0x1, 0x7, 0x7 },
+ { 0xd, 0x9, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 },
+ },
+
+ /* voltage swing 2, pre-emphasis 0->1 */
+ {
+ { 0x8, 0x1, 0x4, 0x6, 0x0, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ { 0xc, 0x6, 0x7, 0x7, 0x1, 0x7, 0x0, 0x1, 0x7, 0x7 },
+ },
+
+ /* voltage swing 3, pre-emphasis 0 */
+ {
+ { 0xb, 0x0, 0x7, 0x7, 0x1, 0x4, 0x1, 0x1, 0x7, 0x7 },
+ }
+};
+
static bool rk_hdptx_phy_is_rw_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
- case 0x0000 ... 0x029c:
- case 0x0400 ... 0x04a4:
- case 0x0800 ... 0x08a4:
- case 0x0c00 ... 0x0cb4:
- case 0x1000 ... 0x10b4:
- case 0x1400 ... 0x14b4:
- case 0x1800 ... 0x18b4:
+ case 0x0000 ... 0x029c: /* CMN Register */
+ case 0x0400 ... 0x04a4: /* Sideband Register */
+ case 0x0800 ... 0x08a4: /* Lane Top Register */
+ case 0x0c00 ... 0x0cb4: /* Lane 0 Register */
+ case 0x1000 ... 0x10b4: /* Lane 1 Register */
+ case 0x1400 ... 0x14b4: /* Lane 2 Register */
+ case 0x1800 ... 0x18b4: /* Lane 3 Register */
return true;
}
@@ -759,9 +1008,7 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx,
{
const struct ropll_config *cfg = NULL;
struct ropll_config rc = {0};
- int i;
-
- hdptx->rate = rate * 100;
+ int ret, i;
for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++)
if (rate == ropll_tmds_cfg[i].bit_rate) {
@@ -813,10 +1060,14 @@ static int rk_hdptx_ropll_tmds_cmn_config(struct rk_hdptx_phy *hdptx,
regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_POSTDIV_SEL_MASK,
FIELD_PREP(PLL_PCG_POSTDIV_SEL_MASK, cfg->pms_sdiv));
- regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN,
- PLL_PCG_CLK_EN);
+ regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN_MASK,
+ FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1));
- return rk_hdptx_post_enable_pll(hdptx);
+ ret = rk_hdptx_post_enable_pll(hdptx);
+ if (!ret)
+ hdptx->rate = rate * 100;
+
+ return ret;
}
static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx,
@@ -826,7 +1077,7 @@ static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx,
regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06);
- if (rate >= 3400000) {
+ if (rate > HDMI14_MAX_RATE / 100) {
/* For 1/40 bitrate clk */
rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq);
} else {
@@ -843,9 +1094,45 @@ static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx,
return rk_hdptx_post_enable_lane(hdptx);
}
+static void rk_hdptx_dp_reset(struct rk_hdptx_phy *hdptx)
+{
+ reset_control_assert(hdptx->rsts[RST_LANE].rstc);
+ reset_control_assert(hdptx->rsts[RST_CMN].rstc);
+ reset_control_assert(hdptx->rsts[RST_INIT].rstc);
+
+ reset_control_assert(hdptx->rsts[RST_APB].rstc);
+ udelay(10);
+ reset_control_deassert(hdptx->rsts[RST_APB].rstc);
+
+ regmap_update_bits(hdptx->regmap, LANE_REG(0301),
+ OVRD_LN_TX_DRV_EI_EN_MASK | LN_TX_DRV_EI_EN_MASK,
+ FIELD_PREP(OVRD_LN_TX_DRV_EI_EN_MASK, 1) |
+ FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0401),
+ OVRD_LN_TX_DRV_EI_EN_MASK | LN_TX_DRV_EI_EN_MASK,
+ FIELD_PREP(OVRD_LN_TX_DRV_EI_EN_MASK, 1) |
+ FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0501),
+ OVRD_LN_TX_DRV_EI_EN_MASK | LN_TX_DRV_EI_EN_MASK,
+ FIELD_PREP(OVRD_LN_TX_DRV_EI_EN_MASK, 1) |
+ FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0601),
+ OVRD_LN_TX_DRV_EI_EN_MASK | LN_TX_DRV_EI_EN_MASK,
+ FIELD_PREP(OVRD_LN_TX_DRV_EI_EN_MASK, 1) |
+ FIELD_PREP(LN_TX_DRV_EI_EN_MASK, 0));
+
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x0));
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ HDPTX_I_BIAS_EN << 16 | FIELD_PREP(HDPTX_I_BIAS_EN, 0x0));
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x0));
+}
+
static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx,
unsigned int rate)
{
+ enum phy_mode mode = phy_get_mode(hdptx->phy);
u32 status;
int ret;
@@ -859,10 +1146,14 @@ static int rk_hdptx_phy_consumer_get(struct rk_hdptx_phy *hdptx,
if (status & HDPTX_O_PLL_LOCK_DONE)
dev_warn(hdptx->dev, "PLL locked by unknown consumer!\n");
- if (rate) {
- ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
- if (ret)
- goto dec_usage;
+ if (mode == PHY_MODE_DP) {
+ rk_hdptx_dp_reset(hdptx);
+ } else {
+ if (rate) {
+ ret = rk_hdptx_ropll_tmds_cmn_config(hdptx, rate);
+ if (ret)
+ goto dec_usage;
+ }
}
return 0;
@@ -874,6 +1165,7 @@ dec_usage:
static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force)
{
+ enum phy_mode mode = phy_get_mode(hdptx->phy);
u32 status;
int ret;
@@ -887,8 +1179,12 @@ static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force)
} else {
ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status);
if (!ret) {
- if (status & HDPTX_O_PLL_LOCK_DONE)
- rk_hdptx_phy_disable(hdptx);
+ if (status & HDPTX_O_PLL_LOCK_DONE) {
+ if (mode == PHY_MODE_DP)
+ rk_hdptx_dp_reset(hdptx);
+ else
+ rk_hdptx_phy_disable(hdptx);
+ }
return 0;
} else if (force) {
return 0;
@@ -899,11 +1195,262 @@ static int rk_hdptx_phy_consumer_put(struct rk_hdptx_phy *hdptx, bool force)
return ret;
}
+static void rk_hdptx_dp_pll_init(struct rk_hdptx_phy *hdptx)
+{
+ regmap_update_bits(hdptx->regmap, CMN_REG(003c), ANA_LCPLL_RESERVED7_MASK,
+ FIELD_PREP(ANA_LCPLL_RESERVED7_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0046),
+ ROPLL_ANA_CPP_CTRL_COARSE_MASK | ROPLL_ANA_CPP_CTRL_FINE_MASK,
+ FIELD_PREP(ROPLL_ANA_CPP_CTRL_COARSE_MASK, 0xe) |
+ FIELD_PREP(ROPLL_ANA_CPP_CTRL_FINE_MASK, 0xe));
+ regmap_update_bits(hdptx->regmap, CMN_REG(0047),
+ ROPLL_ANA_LPF_C_SEL_COARSE_MASK |
+ ROPLL_ANA_LPF_C_SEL_FINE_MASK,
+ FIELD_PREP(ROPLL_ANA_LPF_C_SEL_COARSE_MASK, 0x4) |
+ FIELD_PREP(ROPLL_ANA_LPF_C_SEL_FINE_MASK, 0x4));
+
+ regmap_write(hdptx->regmap, CMN_REG(0051), FIELD_PREP(ROPLL_PMS_MDIV_MASK, 0x87));
+ regmap_write(hdptx->regmap, CMN_REG(0052), FIELD_PREP(ROPLL_PMS_MDIV_MASK, 0x71));
+ regmap_write(hdptx->regmap, CMN_REG(0053), FIELD_PREP(ROPLL_PMS_MDIV_MASK, 0x71));
+
+ regmap_write(hdptx->regmap, CMN_REG(0055),
+ FIELD_PREP(ROPLL_PMS_MDIV_AFC_MASK, 0x87));
+ regmap_write(hdptx->regmap, CMN_REG(0056),
+ FIELD_PREP(ROPLL_PMS_MDIV_AFC_MASK, 0x71));
+ regmap_write(hdptx->regmap, CMN_REG(0057),
+ FIELD_PREP(ROPLL_PMS_MDIV_AFC_MASK, 0x71));
+
+ regmap_write(hdptx->regmap, CMN_REG(0059),
+ FIELD_PREP(ANA_ROPLL_PMS_PDIV_MASK, 0x1) |
+ FIELD_PREP(ANA_ROPLL_PMS_REFDIV_MASK, 0x1));
+ regmap_write(hdptx->regmap, CMN_REG(005a),
+ FIELD_PREP(ROPLL_PMS_SDIV_RBR_MASK, 0x3) |
+ FIELD_PREP(ROPLL_PMS_SDIV_HBR_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, CMN_REG(005b), ROPLL_PMS_SDIV_HBR2_MASK,
+ FIELD_PREP(ROPLL_PMS_SDIV_HBR2_MASK, 0x0));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDM_EN_MASK,
+ FIELD_PREP(ROPLL_SDM_EN_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, CMN_REG(005e),
+ OVRD_ROPLL_SDM_RSTN_MASK | ROPLL_SDM_RSTN_MASK,
+ FIELD_PREP(OVRD_ROPLL_SDM_RSTN_MASK, 0x1) |
+ FIELD_PREP(ROPLL_SDM_RSTN_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDC_FRAC_EN_RBR_MASK,
+ FIELD_PREP(ROPLL_SDC_FRAC_EN_RBR_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDC_FRAC_EN_HBR_MASK,
+ FIELD_PREP(ROPLL_SDC_FRAC_EN_HBR_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDC_FRAC_EN_HBR2_MASK,
+ FIELD_PREP(ROPLL_SDC_FRAC_EN_HBR2_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(005f),
+ OVRD_ROPLL_SDC_RSTN_MASK | ROPLL_SDC_RSTN_MASK,
+ FIELD_PREP(OVRD_ROPLL_SDC_RSTN_MASK, 0x1) |
+ FIELD_PREP(ROPLL_SDC_RSTN_MASK, 0x1));
+ regmap_write(hdptx->regmap, CMN_REG(0060),
+ FIELD_PREP(ROPLL_SDM_DENOMINATOR_MASK, 0x21));
+ regmap_write(hdptx->regmap, CMN_REG(0061),
+ FIELD_PREP(ROPLL_SDM_DENOMINATOR_MASK, 0x27));
+ regmap_write(hdptx->regmap, CMN_REG(0062),
+ FIELD_PREP(ROPLL_SDM_DENOMINATOR_MASK, 0x27));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0064),
+ ROPLL_SDM_NUM_SIGN_RBR_MASK |
+ ROPLL_SDM_NUM_SIGN_HBR_MASK |
+ ROPLL_SDM_NUM_SIGN_HBR2_MASK,
+ FIELD_PREP(ROPLL_SDM_NUM_SIGN_RBR_MASK, 0x0) |
+ FIELD_PREP(ROPLL_SDM_NUM_SIGN_HBR_MASK, 0x1) |
+ FIELD_PREP(ROPLL_SDM_NUM_SIGN_HBR2_MASK, 0x1));
+ regmap_write(hdptx->regmap, CMN_REG(0065),
+ FIELD_PREP(ROPLL_SDM_NUM_MASK, 0x0));
+ regmap_write(hdptx->regmap, CMN_REG(0066),
+ FIELD_PREP(ROPLL_SDM_NUM_MASK, 0xd));
+ regmap_write(hdptx->regmap, CMN_REG(0067),
+ FIELD_PREP(ROPLL_SDM_NUM_MASK, 0xd));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0069), ROPLL_SDC_N_RBR_MASK,
+ FIELD_PREP(ROPLL_SDC_N_RBR_MASK, 0x2));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(006a),
+ ROPLL_SDC_N_HBR_MASK | ROPLL_SDC_N_HBR2_MASK,
+ FIELD_PREP(ROPLL_SDC_N_HBR_MASK, 0x1) |
+ FIELD_PREP(ROPLL_SDC_N_HBR2_MASK, 0x1));
+
+ regmap_write(hdptx->regmap, CMN_REG(006c),
+ FIELD_PREP(ROPLL_SDC_NUM_MASK, 0x3));
+ regmap_write(hdptx->regmap, CMN_REG(006d),
+ FIELD_PREP(ROPLL_SDC_NUM_MASK, 0x7));
+ regmap_write(hdptx->regmap, CMN_REG(006e),
+ FIELD_PREP(ROPLL_SDC_NUM_MASK, 0x7));
+
+ regmap_write(hdptx->regmap, CMN_REG(0070),
+ FIELD_PREP(ROPLL_SDC_DENO_MASK, 0x8));
+ regmap_write(hdptx->regmap, CMN_REG(0071),
+ FIELD_PREP(ROPLL_SDC_DENO_MASK, 0x18));
+ regmap_write(hdptx->regmap, CMN_REG(0072),
+ FIELD_PREP(ROPLL_SDC_DENO_MASK, 0x18));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0074),
+ OVRD_ROPLL_SDC_NDIV_RSTN_MASK | ROPLL_SDC_NDIV_RSTN_MASK,
+ FIELD_PREP(OVRD_ROPLL_SDC_NDIV_RSTN_MASK, 0x1) |
+ FIELD_PREP(ROPLL_SDC_NDIV_RSTN_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0077), ANA_ROPLL_SSC_CLK_DIV_SEL_MASK,
+ FIELD_PREP(ANA_ROPLL_SSC_CLK_DIV_SEL_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0081), ANA_PLL_CD_TX_SER_RATE_SEL_MASK,
+ FIELD_PREP(ANA_PLL_CD_TX_SER_RATE_SEL_MASK, 0x0));
+ regmap_update_bits(hdptx->regmap, CMN_REG(0081),
+ ANA_PLL_CD_HSCLK_EAST_EN_MASK | ANA_PLL_CD_HSCLK_WEST_EN_MASK,
+ FIELD_PREP(ANA_PLL_CD_HSCLK_EAST_EN_MASK, 0x1) |
+ FIELD_PREP(ANA_PLL_CD_HSCLK_WEST_EN_MASK, 0x0));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0082), ANA_PLL_CD_VREG_GAIN_CTRL_MASK,
+ FIELD_PREP(ANA_PLL_CD_VREG_GAIN_CTRL_MASK, 0x4));
+ regmap_update_bits(hdptx->regmap, CMN_REG(0083), ANA_PLL_CD_VREG_ICTRL_MASK,
+ FIELD_PREP(ANA_PLL_CD_VREG_ICTRL_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, CMN_REG(0084), PLL_LCRO_CLK_SEL_MASK,
+ FIELD_PREP(PLL_LCRO_CLK_SEL_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, CMN_REG(0085), ANA_PLL_SYNC_LOSS_DET_MODE_MASK,
+ FIELD_PREP(ANA_PLL_SYNC_LOSS_DET_MODE_MASK, 0x3));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0087), ANA_PLL_TX_HS_CLK_EN_MASK,
+ FIELD_PREP(ANA_PLL_TX_HS_CLK_EN_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0097), DIG_CLK_SEL_MASK,
+ FIELD_PREP(DIG_CLK_SEL_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0099), CMN_ROPLL_ALONE_MODE_MASK,
+ FIELD_PREP(CMN_ROPLL_ALONE_MODE_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, CMN_REG(009a), HS_SPEED_SEL_MASK,
+ FIELD_PREP(HS_SPEED_SEL_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, CMN_REG(009b), LS_SPEED_SEL_MASK,
+ FIELD_PREP(LS_SPEED_SEL_MASK, 0x1));
+}
+
+static int rk_hdptx_dp_aux_init(struct rk_hdptx_phy *hdptx)
+{
+ u32 status;
+ int ret;
+
+ regmap_update_bits(hdptx->regmap, SB_REG(0102), ANA_SB_RXTERM_OFFSP_MASK,
+ FIELD_PREP(ANA_SB_RXTERM_OFFSP_MASK, 0x3));
+ regmap_update_bits(hdptx->regmap, SB_REG(0103), ANA_SB_RXTERM_OFFSN_MASK,
+ FIELD_PREP(ANA_SB_RXTERM_OFFSN_MASK, 0x3));
+ regmap_update_bits(hdptx->regmap, SB_REG(0104), SB_AUX_EN_MASK,
+ FIELD_PREP(SB_AUX_EN_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, SB_REG(0105), ANA_SB_TX_HLVL_PROG_MASK,
+ FIELD_PREP(ANA_SB_TX_HLVL_PROG_MASK, 0x7));
+ regmap_update_bits(hdptx->regmap, SB_REG(0106), ANA_SB_TX_LLVL_PROG_MASK,
+ FIELD_PREP(ANA_SB_TX_LLVL_PROG_MASK, 0x7));
+
+ regmap_update_bits(hdptx->regmap, SB_REG(010d), ANA_SB_DMRX_LPBK_DATA_MASK,
+ FIELD_PREP(ANA_SB_DMRX_LPBK_DATA_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, SB_REG(010f), ANA_SB_VREG_GAIN_CTRL_MASK,
+ FIELD_PREP(ANA_SB_VREG_GAIN_CTRL_MASK, 0x0));
+ regmap_update_bits(hdptx->regmap, SB_REG(0110),
+ ANA_SB_VREG_OUT_SEL_MASK | ANA_SB_VREG_REF_SEL_MASK,
+ FIELD_PREP(ANA_SB_VREG_OUT_SEL_MASK, 0x1) |
+ FIELD_PREP(ANA_SB_VREG_REF_SEL_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, SB_REG(0113),
+ SB_RX_RCAL_OPT_CODE_MASK | SB_RX_RTERM_CTRL_MASK,
+ FIELD_PREP(SB_RX_RCAL_OPT_CODE_MASK, 0x1) |
+ FIELD_PREP(SB_RX_RTERM_CTRL_MASK, 0x3));
+ regmap_update_bits(hdptx->regmap, SB_REG(0114),
+ SB_TG_SB_EN_DELAY_TIME_MASK | SB_TG_RXTERM_EN_DELAY_TIME_MASK,
+ FIELD_PREP(SB_TG_SB_EN_DELAY_TIME_MASK, 0x2) |
+ FIELD_PREP(SB_TG_RXTERM_EN_DELAY_TIME_MASK, 0x2));
+ regmap_update_bits(hdptx->regmap, SB_REG(0115),
+ SB_READY_DELAY_TIME_MASK | SB_TG_OSC_EN_DELAY_TIME_MASK,
+ FIELD_PREP(SB_READY_DELAY_TIME_MASK, 0x2) |
+ FIELD_PREP(SB_TG_OSC_EN_DELAY_TIME_MASK, 0x2));
+ regmap_update_bits(hdptx->regmap, SB_REG(0116),
+ AFC_RSTN_DELAY_TIME_MASK,
+ FIELD_PREP(AFC_RSTN_DELAY_TIME_MASK, 0x2));
+ regmap_update_bits(hdptx->regmap, SB_REG(0117),
+ FAST_PULSE_TIME_MASK,
+ FIELD_PREP(FAST_PULSE_TIME_MASK, 0x4));
+ regmap_update_bits(hdptx->regmap, SB_REG(0118),
+ SB_TG_EARC_DMRX_RECVRD_CLK_CNT_MASK,
+ FIELD_PREP(SB_TG_EARC_DMRX_RECVRD_CLK_CNT_MASK, 0xa));
+
+ regmap_update_bits(hdptx->regmap, SB_REG(011a), SB_TG_CNT_RUN_NO_7_0_MASK,
+ FIELD_PREP(SB_TG_CNT_RUN_NO_7_0_MASK, 0x3));
+ regmap_update_bits(hdptx->regmap, SB_REG(011b),
+ SB_EARC_SIG_DET_BYPASS_MASK | SB_AFC_TOL_MASK,
+ FIELD_PREP(SB_EARC_SIG_DET_BYPASS_MASK, 0x1) |
+ FIELD_PREP(SB_AFC_TOL_MASK, 0x3));
+ regmap_update_bits(hdptx->regmap, SB_REG(011c), SB_AFC_STB_NUM_MASK,
+ FIELD_PREP(SB_AFC_STB_NUM_MASK, 0x4));
+ regmap_update_bits(hdptx->regmap, SB_REG(011d), SB_TG_OSC_CNT_MIN_MASK,
+ FIELD_PREP(SB_TG_OSC_CNT_MIN_MASK, 0x67));
+ regmap_update_bits(hdptx->regmap, SB_REG(011e), SB_TG_OSC_CNT_MAX_MASK,
+ FIELD_PREP(SB_TG_OSC_CNT_MAX_MASK, 0x6a));
+ regmap_update_bits(hdptx->regmap, SB_REG(011f), SB_PWM_AFC_CTRL_MASK,
+ FIELD_PREP(SB_PWM_AFC_CTRL_MASK, 0x5));
+ regmap_update_bits(hdptx->regmap, SB_REG(011f), SB_RCAL_RSTN_MASK,
+ FIELD_PREP(SB_RCAL_RSTN_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, SB_REG(0120), SB_AUX_EN_IN_MASK,
+ FIELD_PREP(SB_AUX_EN_IN_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, SB_REG(0102), OVRD_SB_RXTERM_EN_MASK,
+ FIELD_PREP(OVRD_SB_RXTERM_EN_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, SB_REG(0103), OVRD_SB_RX_RESCAL_DONE_MASK,
+ FIELD_PREP(OVRD_SB_RX_RESCAL_DONE_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, SB_REG(0104), OVRD_SB_EN_MASK,
+ FIELD_PREP(OVRD_SB_EN_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, SB_REG(0104), OVRD_SB_AUX_EN_MASK,
+ FIELD_PREP(OVRD_SB_AUX_EN_MASK, 0x1));
+
+ regmap_update_bits(hdptx->regmap, SB_REG(010f), OVRD_SB_VREG_EN_MASK,
+ FIELD_PREP(OVRD_SB_VREG_EN_MASK, 0x1));
+
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ HDPTX_I_BGR_EN << 16 | FIELD_PREP(HDPTX_I_BGR_EN, 0x1));
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ HDPTX_I_BIAS_EN << 16 | FIELD_PREP(HDPTX_I_BIAS_EN, 0x1));
+ usleep_range(20, 25);
+
+ reset_control_deassert(hdptx->rsts[RST_INIT].rstc);
+ usleep_range(20, 25);
+ reset_control_deassert(hdptx->rsts[RST_CMN].rstc);
+ usleep_range(20, 25);
+
+ regmap_update_bits(hdptx->regmap, SB_REG(0103), OVRD_SB_RX_RESCAL_DONE_MASK,
+ FIELD_PREP(OVRD_SB_RX_RESCAL_DONE_MASK, 0x1));
+ usleep_range(100, 110);
+ regmap_update_bits(hdptx->regmap, SB_REG(0104), SB_EN_MASK,
+ FIELD_PREP(SB_EN_MASK, 0x1));
+ usleep_range(100, 110);
+ regmap_update_bits(hdptx->regmap, SB_REG(0102), SB_RXTERM_EN_MASK,
+ FIELD_PREP(SB_RXTERM_EN_MASK, 0x1));
+ usleep_range(20, 25);
+ regmap_update_bits(hdptx->regmap, SB_REG(010f), SB_VREG_EN_MASK,
+ FIELD_PREP(SB_VREG_EN_MASK, 0x1));
+ usleep_range(20, 25);
+ regmap_update_bits(hdptx->regmap, SB_REG(0104), SB_AUX_EN_MASK,
+ FIELD_PREP(SB_AUX_EN_MASK, 0x1));
+ usleep_range(100, 110);
+
+ ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS,
+ status, FIELD_GET(HDPTX_O_SB_RDY, status),
+ 50, 1000);
+ if (ret) {
+ dev_err(hdptx->dev, "Failed to get phy sb ready: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int rk_hdptx_phy_power_on(struct phy *phy)
{
struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
int bus_width = phy_get_bus_width(hdptx->phy);
- int ret;
+ enum phy_mode mode = phy_get_mode(phy);
+ int ret, lane;
/*
* FIXME: Temporary workaround to pass pixel_clk_rate
@@ -919,9 +1466,37 @@ static int rk_hdptx_phy_power_on(struct phy *phy)
if (ret)
return ret;
- ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate);
- if (ret)
- rk_hdptx_phy_consumer_put(hdptx, true);
+ if (mode == PHY_MODE_DP) {
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x1));
+
+ for (lane = 0; lane < 4; lane++) {
+ regmap_update_bits(hdptx->regmap, LANE_REG(031e) + 0x400 * lane,
+ LN_POLARITY_INV_MASK | LN_LANE_MODE_MASK,
+ FIELD_PREP(LN_POLARITY_INV_MASK, 0) |
+ FIELD_PREP(LN_LANE_MODE_MASK, 1));
+ }
+
+ regmap_update_bits(hdptx->regmap, LNTOP_REG(0200), PROTOCOL_SEL_MASK,
+ FIELD_PREP(PROTOCOL_SEL_MASK, 0x0));
+ regmap_update_bits(hdptx->regmap, LNTOP_REG(0206), DATA_BUS_WIDTH_MASK,
+ FIELD_PREP(DATA_BUS_WIDTH_MASK, 0x1));
+ regmap_update_bits(hdptx->regmap, LNTOP_REG(0206), DATA_BUS_WIDTH_SEL_MASK,
+ FIELD_PREP(DATA_BUS_WIDTH_SEL_MASK, 0x0));
+
+ rk_hdptx_dp_pll_init(hdptx);
+
+ ret = rk_hdptx_dp_aux_init(hdptx);
+ if (ret)
+ rk_hdptx_phy_consumer_put(hdptx, true);
+ } else {
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ HDPTX_MODE_SEL << 16 | FIELD_PREP(HDPTX_MODE_SEL, 0x0));
+
+ ret = rk_hdptx_ropll_tmds_mode_config(hdptx, rate);
+ if (ret)
+ rk_hdptx_phy_consumer_put(hdptx, true);
+ }
return ret;
}
@@ -933,9 +1508,308 @@ static int rk_hdptx_phy_power_off(struct phy *phy)
return rk_hdptx_phy_consumer_put(hdptx, false);
}
+static int rk_hdptx_phy_verify_config(struct rk_hdptx_phy *hdptx,
+ struct phy_configure_opts_dp *dp)
+{
+ int i;
+
+ if (dp->set_rate) {
+ switch (dp->link_rate) {
+ case 1620:
+ case 2700:
+ case 5400:
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (dp->set_lanes) {
+ switch (dp->lanes) {
+ case 1:
+ case 2:
+ case 4:
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (dp->set_voltages) {
+ for (i = 0; i < hdptx->lanes; i++) {
+ if (dp->voltage[i] > 3 || dp->pre[i] > 3)
+ return -EINVAL;
+
+ if (dp->voltage[i] + dp->pre[i] > 3)
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int rk_hdptx_phy_set_rate(struct rk_hdptx_phy *hdptx,
+ struct phy_configure_opts_dp *dp)
+{
+ u32 bw, status;
+ int ret;
+
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x0));
+
+ switch (dp->link_rate) {
+ case 1620:
+ bw = DP_BW_RBR;
+ break;
+ case 2700:
+ bw = DP_BW_HBR;
+ break;
+ case 5400:
+ bw = DP_BW_HBR2;
+ break;
+ default:
+ return -EINVAL;
+ }
+ hdptx->link_rate = dp->link_rate;
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0008), OVRD_LCPLL_EN_MASK | LCPLL_EN_MASK,
+ FIELD_PREP(OVRD_LCPLL_EN_MASK, 0x1) |
+ FIELD_PREP(LCPLL_EN_MASK, 0x0));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(003d), OVRD_ROPLL_EN_MASK | ROPLL_EN_MASK,
+ FIELD_PREP(OVRD_ROPLL_EN_MASK, 0x1) |
+ FIELD_PREP(ROPLL_EN_MASK, 0x1));
+
+ if (dp->ssc) {
+ regmap_update_bits(hdptx->regmap, CMN_REG(0074),
+ OVRD_ROPLL_SSC_EN_MASK | ROPLL_SSC_EN_MASK,
+ FIELD_PREP(OVRD_ROPLL_SSC_EN_MASK, 0x1) |
+ FIELD_PREP(ROPLL_SSC_EN_MASK, 0x1));
+ regmap_write(hdptx->regmap, CMN_REG(0075),
+ FIELD_PREP(ANA_ROPLL_SSC_FM_DEVIATION_MASK, 0xc));
+ regmap_update_bits(hdptx->regmap, CMN_REG(0076),
+ ANA_ROPLL_SSC_FM_FREQ_MASK,
+ FIELD_PREP(ANA_ROPLL_SSC_FM_FREQ_MASK, 0x1f));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0099), SSC_EN_MASK,
+ FIELD_PREP(SSC_EN_MASK, 0x2));
+ } else {
+ regmap_update_bits(hdptx->regmap, CMN_REG(0074),
+ OVRD_ROPLL_SSC_EN_MASK | ROPLL_SSC_EN_MASK,
+ FIELD_PREP(OVRD_ROPLL_SSC_EN_MASK, 0x1) |
+ FIELD_PREP(ROPLL_SSC_EN_MASK, 0x0));
+ regmap_write(hdptx->regmap, CMN_REG(0075),
+ FIELD_PREP(ANA_ROPLL_SSC_FM_DEVIATION_MASK, 0x20));
+ regmap_update_bits(hdptx->regmap, CMN_REG(0076),
+ ANA_ROPLL_SSC_FM_FREQ_MASK,
+ FIELD_PREP(ANA_ROPLL_SSC_FM_FREQ_MASK, 0xc));
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0099), SSC_EN_MASK,
+ FIELD_PREP(SSC_EN_MASK, 0x0));
+ }
+
+ regmap_update_bits(hdptx->regmap, CMN_REG(0095), DP_TX_LINK_BW_MASK,
+ FIELD_PREP(DP_TX_LINK_BW_MASK, bw));
+
+ regmap_write(hdptx->grf, GRF_HDPTX_CON0,
+ HDPTX_I_PLL_EN << 16 | FIELD_PREP(HDPTX_I_PLL_EN, 0x1));
+
+ ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS,
+ status, FIELD_GET(HDPTX_O_PLL_LOCK_DONE, status),
+ 50, 1000);
+ if (ret) {
+ dev_err(hdptx->dev, "Failed to get phy pll lock: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rk_hdptx_phy_set_lanes(struct rk_hdptx_phy *hdptx,
+ struct phy_configure_opts_dp *dp)
+{
+ hdptx->lanes = dp->lanes;
+
+ regmap_update_bits(hdptx->regmap, LNTOP_REG(0207), LANE_EN_MASK,
+ FIELD_PREP(LANE_EN_MASK, GENMASK(hdptx->lanes - 1, 0)));
+
+ return 0;
+}
+
+static void rk_hdptx_phy_set_voltage(struct rk_hdptx_phy *hdptx,
+ struct phy_configure_opts_dp *dp,
+ u8 lane)
+{
+ const struct tx_drv_ctrl *ctrl;
+ u32 offset = lane * 0x400;
+
+ switch (hdptx->link_rate) {
+ case 1620:
+ ctrl = &tx_drv_ctrl_rbr[dp->voltage[lane]][dp->pre[lane]];
+ regmap_update_bits(hdptx->regmap, LANE_REG(030a) + offset,
+ LN_TX_JEQ_EVEN_CTRL_RBR_MASK,
+ FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_RBR_MASK,
+ ctrl->tx_jeq_even_ctrl));
+ regmap_update_bits(hdptx->regmap, LANE_REG(030c) + offset,
+ LN_TX_JEQ_ODD_CTRL_RBR_MASK,
+ FIELD_PREP(LN_TX_JEQ_ODD_CTRL_RBR_MASK,
+ ctrl->tx_jeq_odd_ctrl));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset,
+ LN_TX_SER_40BIT_EN_RBR_MASK,
+ FIELD_PREP(LN_TX_SER_40BIT_EN_RBR_MASK, 0x1));
+ break;
+ case 2700:
+ ctrl = &tx_drv_ctrl_hbr[dp->voltage[lane]][dp->pre[lane]];
+ regmap_update_bits(hdptx->regmap, LANE_REG(030b) + offset,
+ LN_TX_JEQ_EVEN_CTRL_HBR_MASK,
+ FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_HBR_MASK,
+ ctrl->tx_jeq_even_ctrl));
+ regmap_update_bits(hdptx->regmap, LANE_REG(030d) + offset,
+ LN_TX_JEQ_ODD_CTRL_HBR_MASK,
+ FIELD_PREP(LN_TX_JEQ_ODD_CTRL_HBR_MASK,
+ ctrl->tx_jeq_odd_ctrl));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset,
+ LN_TX_SER_40BIT_EN_HBR_MASK,
+ FIELD_PREP(LN_TX_SER_40BIT_EN_HBR_MASK, 0x1));
+ break;
+ case 5400:
+ default:
+ ctrl = &tx_drv_ctrl_hbr2[dp->voltage[lane]][dp->pre[lane]];
+ regmap_update_bits(hdptx->regmap, LANE_REG(030b) + offset,
+ LN_TX_JEQ_EVEN_CTRL_HBR2_MASK,
+ FIELD_PREP(LN_TX_JEQ_EVEN_CTRL_HBR2_MASK,
+ ctrl->tx_jeq_even_ctrl));
+ regmap_update_bits(hdptx->regmap, LANE_REG(030d) + offset,
+ LN_TX_JEQ_ODD_CTRL_HBR2_MASK,
+ FIELD_PREP(LN_TX_JEQ_ODD_CTRL_HBR2_MASK,
+ ctrl->tx_jeq_odd_ctrl));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0311) + offset,
+ LN_TX_SER_40BIT_EN_HBR2_MASK,
+ FIELD_PREP(LN_TX_SER_40BIT_EN_HBR2_MASK, 0x1));
+ break;
+ }
+
+ regmap_update_bits(hdptx->regmap, LANE_REG(0303) + offset,
+ OVRD_LN_TX_DRV_LVL_CTRL_MASK | LN_TX_DRV_LVL_CTRL_MASK,
+ FIELD_PREP(OVRD_LN_TX_DRV_LVL_CTRL_MASK, 0x1) |
+ FIELD_PREP(LN_TX_DRV_LVL_CTRL_MASK,
+ ctrl->tx_drv_lvl_ctrl));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0304) + offset,
+ OVRD_LN_TX_DRV_POST_LVL_CTRL_MASK |
+ LN_TX_DRV_POST_LVL_CTRL_MASK,
+ FIELD_PREP(OVRD_LN_TX_DRV_POST_LVL_CTRL_MASK, 0x1) |
+ FIELD_PREP(LN_TX_DRV_POST_LVL_CTRL_MASK,
+ ctrl->tx_drv_post_lvl_ctrl));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0305) + offset,
+ OVRD_LN_TX_DRV_PRE_LVL_CTRL_MASK |
+ LN_TX_DRV_PRE_LVL_CTRL_MASK,
+ FIELD_PREP(OVRD_LN_TX_DRV_PRE_LVL_CTRL_MASK, 0x1) |
+ FIELD_PREP(LN_TX_DRV_PRE_LVL_CTRL_MASK,
+ ctrl->tx_drv_pre_lvl_ctrl));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0306) + offset,
+ LN_ANA_TX_DRV_IDRV_IDN_CTRL_MASK |
+ LN_ANA_TX_DRV_IDRV_IUP_CTRL_MASK |
+ LN_ANA_TX_DRV_ACCDRV_EN_MASK,
+ FIELD_PREP(LN_ANA_TX_DRV_IDRV_IDN_CTRL_MASK,
+ ctrl->ana_tx_drv_idrv_idn_ctrl) |
+ FIELD_PREP(LN_ANA_TX_DRV_IDRV_IUP_CTRL_MASK,
+ ctrl->ana_tx_drv_idrv_iup_ctrl) |
+ FIELD_PREP(LN_ANA_TX_DRV_ACCDRV_EN_MASK,
+ ctrl->ana_tx_drv_accdrv_en));
+ regmap_update_bits(hdptx->regmap, LANE_REG(0307) + offset,
+ LN_ANA_TX_DRV_ACCDRV_POL_SEL_MASK |
+ LN_ANA_TX_DRV_ACCDRV_CTRL_MASK,
+ FIELD_PREP(LN_ANA_TX_DRV_ACCDRV_POL_SEL_MASK, 0x1) |
+ FIELD_PREP(LN_ANA_TX_DRV_ACCDRV_CTRL_MASK,
+ ctrl->ana_tx_drv_accdrv_ctrl));
+
+ regmap_update_bits(hdptx->regmap, LANE_REG(030a) + offset,
+ LN_ANA_TX_JEQ_EN_MASK,
+ FIELD_PREP(LN_ANA_TX_JEQ_EN_MASK, ctrl->ana_tx_jeq_en));
+
+ regmap_update_bits(hdptx->regmap, LANE_REG(0310) + offset,
+ LN_ANA_TX_SYNC_LOSS_DET_MODE_MASK,
+ FIELD_PREP(LN_ANA_TX_SYNC_LOSS_DET_MODE_MASK, 0x3));
+
+ regmap_update_bits(hdptx->regmap, LANE_REG(0316) + offset,
+ LN_ANA_TX_SER_VREG_GAIN_CTRL_MASK,
+ FIELD_PREP(LN_ANA_TX_SER_VREG_GAIN_CTRL_MASK, 0x2));
+
+ regmap_update_bits(hdptx->regmap, LANE_REG(031b) + offset,
+ LN_ANA_TX_RESERVED_MASK,
+ FIELD_PREP(LN_ANA_TX_RESERVED_MASK, 0x1));
+}
+
+static int rk_hdptx_phy_set_voltages(struct rk_hdptx_phy *hdptx,
+ struct phy_configure_opts_dp *dp)
+{
+ u8 lane;
+ u32 status;
+ int ret;
+
+ for (lane = 0; lane < hdptx->lanes; lane++)
+ rk_hdptx_phy_set_voltage(hdptx, dp, lane);
+
+ reset_control_deassert(hdptx->rsts[RST_LANE].rstc);
+
+ ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS,
+ status, FIELD_GET(HDPTX_O_PHY_RDY, status),
+ 50, 5000);
+ if (ret) {
+ dev_err(hdptx->dev, "Failed to get phy ready: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rk_hdptx_phy_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+ struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy);
+ enum phy_mode mode = phy_get_mode(phy);
+ int ret;
+
+ if (mode != PHY_MODE_DP)
+ return 0;
+
+ ret = rk_hdptx_phy_verify_config(hdptx, &opts->dp);
+ if (ret) {
+ dev_err(hdptx->dev, "invalid params for phy configure\n");
+ return ret;
+ }
+
+ if (opts->dp.set_rate) {
+ ret = rk_hdptx_phy_set_rate(hdptx, &opts->dp);
+ if (ret) {
+ dev_err(hdptx->dev, "failed to set rate: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (opts->dp.set_lanes) {
+ ret = rk_hdptx_phy_set_lanes(hdptx, &opts->dp);
+ if (ret) {
+ dev_err(hdptx->dev, "failed to set lanes: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (opts->dp.set_voltages) {
+ ret = rk_hdptx_phy_set_voltages(hdptx, &opts->dp);
+ if (ret) {
+ dev_err(hdptx->dev, "failed to set voltages: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static const struct phy_ops rk_hdptx_phy_ops = {
.power_on = rk_hdptx_phy_power_on,
.power_off = rk_hdptx_phy_power_off,
+ .configure = rk_hdptx_phy_configure,
.owner = THIS_MODULE,
};
@@ -1007,15 +1881,14 @@ static int rk_hdptx_phy_clk_register(struct rk_hdptx_phy *hdptx)
struct device *dev = hdptx->dev;
const char *name, *pname;
struct clk *refclk;
- int ret, id;
+ int ret;
refclk = devm_clk_get(dev, "ref");
if (IS_ERR(refclk))
return dev_err_probe(dev, PTR_ERR(refclk),
"Failed to get ref clock\n");
- id = of_alias_get_id(dev->of_node, "hdptxphy");
- name = id > 0 ? "clk_hdmiphy_pixel1" : "clk_hdmiphy_pixel0";
+ name = hdptx->phy_id > 0 ? "clk_hdmiphy_pixel1" : "clk_hdmiphy_pixel0";
pname = __clk_get_name(refclk);
hdptx->hw.init = CLK_HW_INIT(name, pname, &hdptx_phy_clk_ops,
@@ -1058,8 +1931,9 @@ static int rk_hdptx_phy_probe(struct platform_device *pdev)
struct phy_provider *phy_provider;
struct device *dev = &pdev->dev;
struct rk_hdptx_phy *hdptx;
+ struct resource *res;
void __iomem *regs;
- int ret;
+ int ret, id;
hdptx = devm_kzalloc(dev, sizeof(*hdptx), GFP_KERNEL);
if (!hdptx)
@@ -1067,11 +1941,27 @@ static int rk_hdptx_phy_probe(struct platform_device *pdev)
hdptx->dev = dev;
- regs = devm_platform_ioremap_resource(pdev, 0);
+ regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(regs))
return dev_err_probe(dev, PTR_ERR(regs),
"Failed to ioremap resource\n");
+ hdptx->cfgs = device_get_match_data(dev);
+ if (!hdptx->cfgs)
+ return dev_err_probe(dev, -EINVAL, "missing match data\n");
+
+ /* find the phy-id from the io address */
+ hdptx->phy_id = -ENODEV;
+ for (id = 0; id < hdptx->cfgs->num_phys; id++) {
+ if (res->start == hdptx->cfgs->phy_ids[id]) {
+ hdptx->phy_id = id;
+ break;
+ }
+ }
+
+ if (hdptx->phy_id < 0)
+ return dev_err_probe(dev, -ENODEV, "no matching device found\n");
+
ret = devm_clk_bulk_get_all(dev, &hdptx->clks);
if (ret < 0)
return dev_err_probe(dev, ret, "Failed to get clocks\n");
@@ -1132,8 +2022,30 @@ static const struct dev_pm_ops rk_hdptx_phy_pm_ops = {
rk_hdptx_phy_runtime_resume, NULL)
};
+static const struct rk_hdptx_phy_cfg rk3576_hdptx_phy_cfgs = {
+ .num_phys = 1,
+ .phy_ids = {
+ 0x2b000000,
+ },
+};
+
+static const struct rk_hdptx_phy_cfg rk3588_hdptx_phy_cfgs = {
+ .num_phys = 2,
+ .phy_ids = {
+ 0xfed60000,
+ 0xfed70000,
+ },
+};
+
static const struct of_device_id rk_hdptx_phy_of_match[] = {
- { .compatible = "rockchip,rk3588-hdptx-phy", },
+ {
+ .compatible = "rockchip,rk3576-hdptx-phy",
+ .data = &rk3576_hdptx_phy_cfgs
+ },
+ {
+ .compatible = "rockchip,rk3588-hdptx-phy",
+ .data = &rk3588_hdptx_phy_cfgs
+ },
{}
};
MODULE_DEVICE_TABLE(of, rk_hdptx_phy_of_match);
@@ -1150,5 +2062,6 @@ module_platform_driver(rk_hdptx_phy_driver);
MODULE_AUTHOR("Algea Cao <algea.cao@rock-chips.com>");
MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@collabora.com>");
+MODULE_AUTHOR("Damon Ding <damon.ding@rock-chips.com>");
MODULE_DESCRIPTION("Samsung HDMI/eDP Transmitter Combo PHY Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c
index 122ae0fdc785..d9701b6106d5 100644
--- a/drivers/phy/rockchip/phy-rockchip-typec.c
+++ b/drivers/phy/rockchip/phy-rockchip-typec.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
+ * Copyright (C) Rockchip Electronics Co., Ltd.
* Author: Chris Zhong <zyw@rock-chips.com>
* Kever Yang <kever.yang@rock-chips.com>
*
diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c
index 5b1e8a3806ed..c066cc0a7b4f 100644
--- a/drivers/phy/rockchip/phy-rockchip-usbdp.c
+++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c
@@ -187,6 +187,8 @@ struct rk_udphy {
u32 dp_aux_din_sel;
bool dp_sink_hpd_sel;
bool dp_sink_hpd_cfg;
+ unsigned int link_rate;
+ unsigned int lanes;
u8 bw;
int id;
@@ -978,7 +980,7 @@ static int rk_udphy_parse_dt(struct rk_udphy *udphy)
if (device_property_present(dev, "maximum-speed")) {
maximum_speed = usb_get_maximum_speed(dev);
- udphy->hs = maximum_speed <= USB_SPEED_HIGH ? true : false;
+ udphy->hs = maximum_speed <= USB_SPEED_HIGH;
}
ret = rk_udphy_clk_init(udphy, dev);
@@ -1045,7 +1047,6 @@ static int rk_udphy_dp_phy_init(struct phy *phy)
mutex_lock(&udphy->mutex);
udphy->dp_in_use = true;
- rk_udphy_dp_hpd_event_trigger(udphy, udphy->dp_sink_hpd_cfg);
mutex_unlock(&udphy->mutex);
@@ -1103,15 +1104,19 @@ static int rk_udphy_dp_phy_power_off(struct phy *phy)
return 0;
}
-static int rk_udphy_dp_phy_verify_link_rate(unsigned int link_rate)
+/*
+ * Verify link rate
+ */
+static int rk_udphy_dp_phy_verify_link_rate(struct rk_udphy *udphy,
+ struct phy_configure_opts_dp *dp)
{
- switch (link_rate) {
+ switch (dp->link_rate) {
case 1620:
case 2700:
case 5400:
case 8100:
+ udphy->link_rate = dp->link_rate;
break;
-
default:
return -EINVAL;
}
@@ -1119,45 +1124,44 @@ static int rk_udphy_dp_phy_verify_link_rate(unsigned int link_rate)
return 0;
}
-static int rk_udphy_dp_phy_verify_config(struct rk_udphy *udphy,
- struct phy_configure_opts_dp *dp)
+static int rk_udphy_dp_phy_verify_lanes(struct rk_udphy *udphy,
+ struct phy_configure_opts_dp *dp)
{
- int i, ret;
-
- /* If changing link rate was required, verify it's supported. */
- ret = rk_udphy_dp_phy_verify_link_rate(dp->link_rate);
- if (ret)
- return ret;
-
- /* Verify lane count. */
switch (dp->lanes) {
case 1:
case 2:
case 4:
/* valid lane count. */
+ udphy->lanes = dp->lanes;
break;
default:
return -EINVAL;
}
- /*
- * If changing voltages is required, check swing and pre-emphasis
- * levels, per-lane.
- */
- if (dp->set_voltages) {
- /* Lane count verified previously. */
- for (i = 0; i < dp->lanes; i++) {
- if (dp->voltage[i] > 3 || dp->pre[i] > 3)
- return -EINVAL;
+ return 0;
+}
- /*
- * Sum of voltage swing and pre-emphasis levels cannot
- * exceed 3.
- */
- if (dp->voltage[i] + dp->pre[i] > 3)
- return -EINVAL;
- }
+/*
+ * If changing voltages is required, check swing and pre-emphasis
+ * levels, per-lane.
+ */
+static int rk_udphy_dp_phy_verify_voltages(struct rk_udphy *udphy,
+ struct phy_configure_opts_dp *dp)
+{
+ int i;
+
+ /* Lane count verified previously. */
+ for (i = 0; i < udphy->lanes; i++) {
+ if (dp->voltage[i] > 3 || dp->pre[i] > 3)
+ return -EINVAL;
+
+ /*
+ * Sum of voltage swing and pre-emphasis levels cannot
+ * exceed 3.
+ */
+ if (dp->voltage[i] + dp->pre[i] > 3)
+ return -EINVAL;
}
return 0;
@@ -1197,9 +1201,23 @@ static int rk_udphy_dp_phy_configure(struct phy *phy,
u32 i, val, lane;
int ret;
- ret = rk_udphy_dp_phy_verify_config(udphy, dp);
- if (ret)
- return ret;
+ if (dp->set_rate) {
+ ret = rk_udphy_dp_phy_verify_link_rate(udphy, dp);
+ if (ret)
+ return ret;
+ }
+
+ if (dp->set_lanes) {
+ ret = rk_udphy_dp_phy_verify_lanes(udphy, dp);
+ if (ret)
+ return ret;
+ }
+
+ if (dp->set_voltages) {
+ ret = rk_udphy_dp_phy_verify_voltages(udphy, dp);
+ if (ret)
+ return ret;
+ }
if (dp->set_rate) {
regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET,
@@ -1244,9 +1262,9 @@ static int rk_udphy_dp_phy_configure(struct phy *phy,
}
if (dp->set_voltages) {
- for (i = 0; i < dp->lanes; i++) {
+ for (i = 0; i < udphy->lanes; i++) {
lane = udphy->dp_lane_sel[i];
- switch (dp->link_rate) {
+ switch (udphy->link_rate) {
case 1620:
case 2700:
regmap_update_bits(udphy->pma_regmap,
diff --git a/drivers/phy/samsung/Kconfig b/drivers/phy/samsung/Kconfig
index f10afa3d7ff5..6566100441d6 100644
--- a/drivers/phy/samsung/Kconfig
+++ b/drivers/phy/samsung/Kconfig
@@ -33,6 +33,7 @@ config PHY_SAMSUNG_UFS
tristate "Exynos SoC series UFS PHY driver"
depends on OF && (ARCH_EXYNOS || COMPILE_TEST)
select GENERIC_PHY
+ select MFD_SYSCON
help
Enable this to support the Samsung Exynos SoC UFS PHY driver for
Samsung Exynos SoCs. This driver provides the interface for UFS host
@@ -80,6 +81,7 @@ config PHY_EXYNOS5_USBDRD
tristate "Exynos5 SoC series USB DRD PHY driver"
depends on (ARCH_EXYNOS && OF) || COMPILE_TEST
depends on HAS_IOMEM
+ depends on TYPEC || !TYPEC
depends on USB_DWC3_EXYNOS
select GENERIC_PHY
select MFD_SYSCON
diff --git a/drivers/phy/samsung/Makefile b/drivers/phy/samsung/Makefile
index fea1f96d0e43..342682638a87 100644
--- a/drivers/phy/samsung/Makefile
+++ b/drivers/phy/samsung/Makefile
@@ -7,6 +7,7 @@ phy-exynos-ufs-y += phy-gs101-ufs.o
phy-exynos-ufs-y += phy-samsung-ufs.o
phy-exynos-ufs-y += phy-exynos7-ufs.o
phy-exynos-ufs-y += phy-exynosautov9-ufs.o
+phy-exynos-ufs-y += phy-exynosautov920-ufs.o
phy-exynos-ufs-y += phy-fsd-ufs.o
obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o
phy-exynos-usb2-y += phy-samsung-usb2.o
diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c
index 46b8f6987c62..817fddee0392 100644
--- a/drivers/phy/samsung/phy-exynos5-usbdrd.c
+++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c
@@ -23,6 +23,8 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/soc/samsung/exynos-regs-pmu.h>
+#include <linux/usb/typec.h>
+#include <linux/usb/typec_mux.h>
/* Exynos USB PHY registers */
#define EXYNOS5_FSEL_9MHZ6 0x0
@@ -209,6 +211,10 @@
#define EXYNOS9_PMA_USBDP_CMN_REG00B8 0x02e0
#define CMN_REG00B8_LANE_MUX_SEL_DP GENMASK(3, 0)
+#define CMN_REG00B8_LANE_MUX_SEL_DP_LANE3 BIT(3)
+#define CMN_REG00B8_LANE_MUX_SEL_DP_LANE2 BIT(2)
+#define CMN_REG00B8_LANE_MUX_SEL_DP_LANE1 BIT(1)
+#define CMN_REG00B8_LANE_MUX_SEL_DP_LANE0 BIT(0)
#define EXYNOS9_PMA_USBDP_CMN_REG01C0 0x0700
#define CMN_REG01C0_ANA_LCPLL_LOCK_DONE BIT(7)
@@ -383,11 +389,14 @@ struct exynos5_usbdrd_phy_drvdata {
* @clks: clocks for register access
* @core_clks: core clocks for phy (ref, pipe3, utmi+, ITP, etc. as required)
* @drv_data: pointer to SoC level driver data structure
+ * @phy_mutex: mutex protecting phy_init/exit & TCPC callbacks
* @phys: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
* instances each with its 'phy' and 'phy_cfg'.
* @extrefclk: frequency select settings when using 'separate
* reference clocks' for SS and HS operations
* @regulators: regulators for phy
+ * @sw: TypeC orientation switch handle
+ * @orientation: TypeC connector orientation - normal or flipped
*/
struct exynos5_usbdrd_phy {
struct device *dev;
@@ -397,6 +406,7 @@ struct exynos5_usbdrd_phy {
struct clk_bulk_data *clks;
struct clk_bulk_data *core_clks;
const struct exynos5_usbdrd_phy_drvdata *drv_data;
+ struct mutex phy_mutex;
struct phy_usb_instance {
struct phy *phy;
u32 index;
@@ -406,6 +416,9 @@ struct exynos5_usbdrd_phy {
} phys[EXYNOS5_DRDPHYS_NUM];
u32 extrefclk;
struct regulator_bulk_data *regulators;
+
+ struct typec_switch_dev *sw;
+ enum typec_orientation orientation;
};
static inline
@@ -647,22 +660,38 @@ exynos5_usbdrd_usbdp_g2_v4_pma_lane_mux_sel(struct exynos5_usbdrd_phy *phy_drd)
/* lane configuration: USB on all lanes */
reg = readl(regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8);
reg &= ~CMN_REG00B8_LANE_MUX_SEL_DP;
- writel(reg, regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8);
-
/*
- * FIXME: below code supports one connector orientation only. It needs
- * updating once we can receive connector events.
+ * USB on lanes 0 & 1 in normal mode, or 2 & 3 if reversed, DP on the
+ * other ones.
*/
+ reg |= FIELD_PREP(CMN_REG00B8_LANE_MUX_SEL_DP,
+ ((phy_drd->orientation == TYPEC_ORIENTATION_NORMAL)
+ ? (CMN_REG00B8_LANE_MUX_SEL_DP_LANE3
+ | CMN_REG00B8_LANE_MUX_SEL_DP_LANE2)
+ : (CMN_REG00B8_LANE_MUX_SEL_DP_LANE1
+ | CMN_REG00B8_LANE_MUX_SEL_DP_LANE0)));
+ writel(reg, regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8);
+
/* override of TX receiver detector and comparator: lane 1 */
reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413);
- reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN;
- reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_EN;
+ if (phy_drd->orientation == TYPEC_ORIENTATION_NORMAL) {
+ reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN;
+ reg &= ~TRSV_REG0413_OVRD_LN1_TX_RXD_EN;
+ } else {
+ reg |= TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN;
+ reg |= TRSV_REG0413_OVRD_LN1_TX_RXD_EN;
+ }
writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0413);
/* lane 3 */
reg = readl(regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813);
- reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN;
- reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_EN;
+ if (phy_drd->orientation == TYPEC_ORIENTATION_NORMAL) {
+ reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN;
+ reg |= TRSV_REG0813_OVRD_LN3_TX_RXD_EN;
+ } else {
+ reg &= ~TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN;
+ reg &= ~TRSV_REG0813_OVRD_LN3_TX_RXD_EN;
+ }
writel(reg, regs_base + EXYNOS9_PMA_USBDP_TRSV_REG0813);
}
@@ -700,21 +729,18 @@ exynos5_usbdrd_usbdp_g2_v4_pma_check_cdr_lock(struct exynos5_usbdrd_phy *phy_drd
int err;
err = readl_poll_timeout(
- phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG03C3,
- reg, (reg & locked) == locked, sleep_us, timeout_us);
- if (!err)
- return;
-
- dev_err(phy_drd->dev,
- "timed out waiting for CDR lock (l0): %#.8x, retrying\n", reg);
-
- /* based on cable orientation, this might be on the other phy port */
- err = readl_poll_timeout(
- phy_drd->reg_pma + EXYNOS9_PMA_USBDP_TRSV_REG07C3,
+ /* lane depends on cable orientation */
+ (phy_drd->reg_pma
+ + ((phy_drd->orientation == TYPEC_ORIENTATION_NORMAL)
+ ? EXYNOS9_PMA_USBDP_TRSV_REG03C3
+ : EXYNOS9_PMA_USBDP_TRSV_REG07C3)),
reg, (reg & locked) == locked, sleep_us, timeout_us);
if (err)
dev_err(phy_drd->dev,
- "timed out waiting for CDR lock (l2): %#.8x\n", reg);
+ "timed out waiting for CDR(l%d) lock: %#.8x\n",
+ ((phy_drd->orientation == TYPEC_ORIENTATION_NORMAL)
+ ? 0
+ : 2), reg);
}
static void exynos5_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
@@ -1111,13 +1137,15 @@ static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd)
reg |= LINKCTRL_BUS_FILTER_BYPASS(0xf);
writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL);
- reg = readl(regs_base + EXYNOS850_DRD_UTMI);
- reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID;
- writel(reg, regs_base + EXYNOS850_DRD_UTMI);
+ if (!phy_drd->sw) {
+ reg = readl(regs_base + EXYNOS850_DRD_UTMI);
+ reg |= UTMI_FORCE_BVALID | UTMI_FORCE_VBUSVALID;
+ writel(reg, regs_base + EXYNOS850_DRD_UTMI);
- reg = readl(regs_base + EXYNOS850_DRD_HSP);
- reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL;
- writel(reg, regs_base + EXYNOS850_DRD_HSP);
+ reg = readl(regs_base + EXYNOS850_DRD_HSP);
+ reg |= HSP_VBUSVLDEXT | HSP_VBUSVLDEXTSEL;
+ writel(reg, regs_base + EXYNOS850_DRD_HSP);
+ }
reg = readl(regs_base + EXYNOS850_DRD_SSPPLLCTL);
reg &= ~SSPPLLCTL_FSEL;
@@ -1184,7 +1212,8 @@ static int exynos850_usbdrd_phy_init(struct phy *phy)
return ret;
/* UTMI or PIPE3 specific init */
- inst->phy_cfg->phy_init(phy_drd);
+ scoped_guard(mutex, &phy_drd->phy_mutex)
+ inst->phy_cfg->phy_init(phy_drd);
clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks);
@@ -1203,6 +1232,8 @@ static int exynos850_usbdrd_phy_exit(struct phy *phy)
if (ret)
return ret;
+ guard(mutex)(&phy_drd->phy_mutex);
+
/* Set PHY clock and control HS PHY */
reg = readl(regs_base + EXYNOS850_DRD_UTMI);
reg &= ~(UTMI_DP_PULLDOWN | UTMI_DM_PULLDOWN);
@@ -1374,6 +1405,87 @@ static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
return 0;
}
+static int exynos5_usbdrd_orien_sw_set(struct typec_switch_dev *sw,
+ enum typec_orientation orientation)
+{
+ struct exynos5_usbdrd_phy *phy_drd = typec_switch_get_drvdata(sw);
+ int ret;
+
+ ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks);
+ if (ret) {
+ dev_err(phy_drd->dev, "Failed to enable PHY clocks(s)\n");
+ return ret;
+ }
+
+ scoped_guard(mutex, &phy_drd->phy_mutex) {
+ void __iomem * const regs_base = phy_drd->reg_phy;
+ unsigned int reg;
+
+ if (orientation == TYPEC_ORIENTATION_NONE) {
+ reg = readl(regs_base + EXYNOS850_DRD_UTMI);
+ reg &= ~(UTMI_FORCE_VBUSVALID | UTMI_FORCE_BVALID);
+ writel(reg, regs_base + EXYNOS850_DRD_UTMI);
+
+ reg = readl(regs_base + EXYNOS850_DRD_HSP);
+ reg |= HSP_VBUSVLDEXTSEL;
+ reg &= ~HSP_VBUSVLDEXT;
+ writel(reg, regs_base + EXYNOS850_DRD_HSP);
+ } else {
+ reg = readl(regs_base + EXYNOS850_DRD_UTMI);
+ reg |= UTMI_FORCE_VBUSVALID | UTMI_FORCE_BVALID;
+ writel(reg, regs_base + EXYNOS850_DRD_UTMI);
+
+ reg = readl(regs_base + EXYNOS850_DRD_HSP);
+ reg |= HSP_VBUSVLDEXTSEL | HSP_VBUSVLDEXT;
+ writel(reg, regs_base + EXYNOS850_DRD_HSP);
+ }
+
+ phy_drd->orientation = orientation;
+ }
+
+ clk_bulk_disable(phy_drd->drv_data->n_clks, phy_drd->clks);
+
+ return 0;
+}
+
+static void exynos5_usbdrd_orien_switch_unregister(void *data)
+{
+ struct exynos5_usbdrd_phy *phy_drd = data;
+
+ typec_switch_unregister(phy_drd->sw);
+}
+
+static int exynos5_usbdrd_setup_notifiers(struct exynos5_usbdrd_phy *phy_drd)
+{
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_TYPEC))
+ return 0;
+
+ if (device_property_present(phy_drd->dev, "orientation-switch")) {
+ struct typec_switch_desc sw_desc = { };
+
+ sw_desc.drvdata = phy_drd;
+ sw_desc.fwnode = dev_fwnode(phy_drd->dev);
+ sw_desc.set = exynos5_usbdrd_orien_sw_set;
+
+ phy_drd->sw = typec_switch_register(phy_drd->dev, &sw_desc);
+ if (IS_ERR(phy_drd->sw))
+ return dev_err_probe(phy_drd->dev,
+ PTR_ERR(phy_drd->sw),
+ "Failed to register TypeC orientation switch\n");
+
+ ret = devm_add_action_or_reset(phy_drd->dev,
+ exynos5_usbdrd_orien_switch_unregister,
+ phy_drd);
+ if (ret)
+ return dev_err_probe(phy_drd->dev, ret,
+ "Failed to register TypeC orientation devm action\n");
+ }
+
+ return 0;
+}
+
static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = {
{
.id = EXYNOS5_DRDPHY_UTMI,
@@ -1513,8 +1625,11 @@ static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_preinit[] = {
PHY_TUNING_ENTRY_PMA(0x09e0, -1, 0x00),
PHY_TUNING_ENTRY_PMA(0x09e4, -1, 0x36),
PHY_TUNING_ENTRY_PMA(0x1e7c, -1, 0x06),
- PHY_TUNING_ENTRY_PMA(0x1e90, -1, 0x00),
- PHY_TUNING_ENTRY_PMA(0x1e94, -1, 0x36),
+ PHY_TUNING_ENTRY_PMA(0x19e0, -1, 0x00),
+ PHY_TUNING_ENTRY_PMA(0x19e4, -1, 0x36),
+ /* fix bootloader bug */
+ PHY_TUNING_ENTRY_PMA(0x1e90, -1, 0x02),
+ PHY_TUNING_ENTRY_PMA(0x1e94, -1, 0x0b),
/* improve LVCC */
PHY_TUNING_ENTRY_PMA(0x08f0, -1, 0x30),
PHY_TUNING_ENTRY_PMA(0x18f0, -1, 0x30),
@@ -1698,6 +1813,10 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
return -EINVAL;
phy_drd->drv_data = drv_data;
+ ret = devm_mutex_init(dev, &phy_drd->phy_mutex);
+ if (ret)
+ return ret;
+
if (of_property_present(dev->of_node, "reg-names")) {
void __iomem *reg;
@@ -1728,10 +1847,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,pmu-syscon");
- if (IS_ERR(reg_pmu)) {
- dev_err(dev, "Failed to lookup PMU regmap\n");
- return PTR_ERR(reg_pmu);
- }
+ if (IS_ERR(reg_pmu))
+ return dev_err_probe(dev, PTR_ERR(reg_pmu),
+ "Failed to lookup PMU regmap\n");
/*
* Exynos5420 SoC has multiple channels for USB 3.0 PHY, with
@@ -1757,15 +1875,18 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(dev, ret, "failed to get regulators\n");
+ ret = exynos5_usbdrd_setup_notifiers(phy_drd);
+ if (ret)
+ return ret;
+
dev_vdbg(dev, "Creating usbdrd_phy phy\n");
for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL, drv_data->phy_ops);
- if (IS_ERR(phy)) {
- dev_err(dev, "Failed to create usbdrd_phy phy\n");
- return PTR_ERR(phy);
- }
+ if (IS_ERR(phy))
+ return dev_err_probe(dev, PTR_ERR(phy),
+ "Failed to create usbdrd_phy phy\n");
phy_drd->phys[i].phy = phy;
phy_drd->phys[i].index = i;
@@ -1789,10 +1910,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
phy_provider = devm_of_phy_provider_register(dev,
exynos5_usbdrd_phy_xlate);
- if (IS_ERR(phy_provider)) {
- dev_err(phy_drd->dev, "Failed to register phy provider\n");
- return PTR_ERR(phy_provider);
- }
+ if (IS_ERR(phy_provider))
+ return dev_err_probe(phy_drd->dev, PTR_ERR(phy_provider),
+ "Failed to register phy provider\n");
return 0;
}
diff --git a/drivers/phy/samsung/phy-exynosautov920-ufs.c b/drivers/phy/samsung/phy-exynosautov920-ufs.c
new file mode 100644
index 000000000000..21ef79c42f95
--- /dev/null
+++ b/drivers/phy/samsung/phy-exynosautov920-ufs.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UFS PHY driver data for Samsung ExynosAuto v920 SoC
+ *
+ * Copyright (C) 2024 Samsung Electronics Co., Ltd.
+ */
+
+#include "phy-samsung-ufs.h"
+
+#define EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL 0x708
+#define EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL_MASK 0x1
+#define EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL_EN BIT(0)
+#define EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS 0x5e
+
+#define EXYNOSAUTOV920_CDR_LOCK_OFFSET 0xce4
+
+#define PHY_EXYNOSAUTOV920_LANE_OFFSET 0x200
+#define PHY_TRSV_REG_CFG_AUTOV920(o, v, d) \
+ PHY_TRSV_REG_CFG_OFFSET(o, v, d, PHY_EXYNOSAUTOV920_LANE_OFFSET)
+
+/* Calibration for phy initialization */
+static const struct samsung_ufs_phy_cfg exynosautov920_pre_init_cfg[] = {
+ PHY_COMN_REG_CFG(0x29, 0x22, PWR_MODE_ANY),
+ PHY_COMN_REG_CFG(0x43, 0x10, PWR_MODE_ANY),
+ PHY_COMN_REG_CFG(0x3c, 0x14, PWR_MODE_ANY),
+ PHY_COMN_REG_CFG(0x46, 0x48, PWR_MODE_ANY),
+ PHY_COMN_REG_CFG(0x04, 0x95, PWR_MODE_ANY),
+ PHY_COMN_REG_CFG(0x06, 0x30, PWR_MODE_ANY),
+
+ PHY_TRSV_REG_CFG_AUTOV920(0x200, 0x00, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x201, 0x06, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x202, 0x06, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x203, 0x0a, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x204, 0x00, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x205, 0x10, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x207, 0x0c, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2e1, 0xc0, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x22d, 0xf8, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x234, 0x60, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x238, 0x13, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x239, 0x48, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x23a, 0x01, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x23b, 0x29, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x23c, 0x2a, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x23d, 0x01, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x23e, 0x14, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x23f, 0x13, PWR_MODE_ANY),
+
+ PHY_TRSV_REG_CFG_AUTOV920(0x240, 0x4a, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x243, 0x40, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x244, 0x02, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x25d, 0x00, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x25e, 0x3f, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x25f, 0xff, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x26f, 0xf0, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x273, 0x33, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x274, 0x50, PWR_MODE_ANY),
+
+ PHY_TRSV_REG_CFG_AUTOV920(0x284, 0x02, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x285, 0x02, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2a2, 0x04, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x27d, 0x01, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2fa, 0x01, PWR_MODE_ANY),
+
+ PHY_TRSV_REG_CFG_AUTOV920(0x286, 0x03, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x287, 0x03, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x288, 0x03, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x289, 0x03, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2b3, 0x04, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2b6, 0x0b, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2b7, 0x0b, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2b8, 0x0b, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2b9, 0x0b, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2ba, 0x0b, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2bb, 0x06, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2bc, 0x06, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2bd, 0x06, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x2be, 0x06, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x34b, 0x01, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x34c, 0x24, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x34d, 0x23, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x34e, 0x45, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x34f, 0x00, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x350, 0x31, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x351, 0x00, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x352, 0x02, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x353, 0x00, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x354, 0x01, PWR_MODE_ANY),
+
+ PHY_COMN_REG_CFG(0x43, 0x18, PWR_MODE_ANY),
+ PHY_COMN_REG_CFG(0x43, 0x00, PWR_MODE_ANY),
+
+ END_UFS_PHY_CFG,
+};
+
+/* Calibration for HS mode series A/B */
+static const struct samsung_ufs_phy_cfg exynosautov920_pre_pwr_hs_cfg[] = {
+ PHY_TRSV_REG_CFG_AUTOV920(0x369, 0x11, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x246, 0x03, PWR_MODE_ANY),
+
+ END_UFS_PHY_CFG,
+};
+
+static const struct samsung_ufs_phy_cfg exynosautov920_post_pwr_hs_cfg[] = {
+ END_UFS_PHY_CFG,
+};
+
+#define DELAY_IN_US 40
+#define RETRY_CNT 100
+#define EXYNOSAUTOV920_CDR_LOCK_MASK 0x8
+
+int exynosautov920_ufs_phy_wait_cdr_lock(struct phy *phy, u8 lane)
+{
+ struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy);
+ u32 reg, i;
+
+ struct samsung_ufs_phy_cfg cfg[4] = {
+ PHY_TRSV_REG_CFG_AUTOV920(0x222, 0x10, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x222, 0x18, PWR_MODE_ANY),
+ PHY_TRSV_REG_CFG_AUTOV920(0x246, 0x01, PWR_MODE_ANY),
+ END_UFS_PHY_CFG,
+ };
+
+ for (i = 0; i < RETRY_CNT; i++) {
+ udelay(DELAY_IN_US);
+
+ reg = readl(ufs_phy->reg_pma + EXYNOSAUTOV920_CDR_LOCK_OFFSET +
+ (PHY_APB_ADDR(PHY_EXYNOSAUTOV920_LANE_OFFSET) * lane));
+
+ if ((reg & EXYNOSAUTOV920_CDR_LOCK_MASK)
+ == EXYNOSAUTOV920_CDR_LOCK_MASK) {
+ samsung_ufs_phy_config(ufs_phy, &cfg[2], lane);
+ return 0;
+ }
+
+ udelay(DELAY_IN_US);
+
+ /* Disable and enable CDR */
+ samsung_ufs_phy_config(ufs_phy, &cfg[0], lane);
+ samsung_ufs_phy_config(ufs_phy, &cfg[1], lane);
+ }
+
+ dev_err(ufs_phy->dev, "failed to get phy cdr lock\n");
+ return -ETIMEDOUT;
+}
+
+static const struct samsung_ufs_phy_cfg *exynosautov920_ufs_phy_cfgs[CFG_TAG_MAX] = {
+ [CFG_PRE_INIT] = exynosautov920_pre_init_cfg,
+ [CFG_PRE_PWR_HS] = exynosautov920_pre_pwr_hs_cfg,
+ [CFG_POST_PWR_HS] = exynosautov920_post_pwr_hs_cfg,
+};
+
+static const char * const exynosautov920_ufs_phy_clks[] = {
+ "ref_clk",
+};
+
+const struct samsung_ufs_phy_drvdata exynosautov920_ufs_phy = {
+ .cfgs = exynosautov920_ufs_phy_cfgs,
+ .isol = {
+ .offset = EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL,
+ .mask = EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL_MASK,
+ .en = EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CTRL_EN,
+ },
+ .clk_list = exynosautov920_ufs_phy_clks,
+ .num_clks = ARRAY_SIZE(exynosautov920_ufs_phy_clks),
+ .cdr_lock_status_offset = EXYNOSAUTOV920_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS,
+ .wait_for_cdr = exynosautov920_ufs_phy_wait_cdr_lock,
+};
diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c
index 6c5d41552649..f3cbe6b17b23 100644
--- a/drivers/phy/samsung/phy-samsung-ufs.c
+++ b/drivers/phy/samsung/phy-samsung-ufs.c
@@ -13,11 +13,11 @@
#include <linux/of.h>
#include <linux/io.h>
#include <linux/iopoll.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#include <linux/soc/samsung/exynos-pmu.h>
#include "phy-samsung-ufs.h"
@@ -28,9 +28,9 @@
#define PHY_DEF_LANE_CNT 1
-static void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
- const struct samsung_ufs_phy_cfg *cfg,
- u8 lane)
+void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
+ const struct samsung_ufs_phy_cfg *cfg,
+ u8 lane)
{
enum {LANE_0, LANE_1}; /* lane index */
@@ -268,8 +268,8 @@ static int samsung_ufs_phy_probe(struct platform_device *pdev)
goto out;
}
- phy->reg_pmu = exynos_get_pmu_regmap_by_phandle(dev->of_node,
- "samsung,pmu-syscon");
+ phy->reg_pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "samsung,pmu-syscon");
if (IS_ERR(phy->reg_pmu)) {
err = PTR_ERR(phy->reg_pmu);
dev_err(dev, "failed syscon remap for pmu\n");
@@ -324,6 +324,9 @@ static const struct of_device_id samsung_ufs_phy_match[] = {
.compatible = "samsung,exynosautov9-ufs-phy",
.data = &exynosautov9_ufs_phy,
}, {
+ .compatible = "samsung,exynosautov920-ufs-phy",
+ .data = &exynosautov920_ufs_phy,
+ }, {
.compatible = "tesla,fsd-ufs-phy",
.data = &fsd_ufs_phy,
},
diff --git a/drivers/phy/samsung/phy-samsung-ufs.h b/drivers/phy/samsung/phy-samsung-ufs.h
index 9b7deef6e10f..a28f148081d1 100644
--- a/drivers/phy/samsung/phy-samsung-ufs.h
+++ b/drivers/phy/samsung/phy-samsung-ufs.h
@@ -143,9 +143,13 @@ static inline void samsung_ufs_phy_ctrl_isol(
}
int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy, u8 lane);
+int exynosautov920_ufs_phy_wait_cdr_lock(struct phy *phy, u8 lane);
+void samsung_ufs_phy_config(struct samsung_ufs_phy *phy,
+ const struct samsung_ufs_phy_cfg *cfg, u8 lane);
extern const struct samsung_ufs_phy_drvdata exynos7_ufs_phy;
extern const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy;
+extern const struct samsung_ufs_phy_drvdata exynosautov920_ufs_phy;
extern const struct samsung_ufs_phy_drvdata fsd_ufs_phy;
extern const struct samsung_ufs_phy_drvdata tensor_gs101_ufs_phy;
diff --git a/drivers/phy/st/phy-stih407-usb.c b/drivers/phy/st/phy-stih407-usb.c
index a4ae2cca7f63..ebb1d0858aa3 100644
--- a/drivers/phy/st/phy-stih407-usb.c
+++ b/drivers/phy/st/phy-stih407-usb.c
@@ -18,8 +18,8 @@
#include <linux/mfd/syscon.h>
#include <linux/phy/phy.h>
-#define PHYPARAM_REG 1
-#define PHYCTRL_REG 2
+#define PHYPARAM_REG 0
+#define PHYCTRL_REG 1
/* Default PHY_SEL and REFCLKSEL configuration */
#define STIH407_USB_PICOPHY_CTRL_PORT_CONF 0x6
@@ -91,8 +91,8 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct phy_provider *phy_provider;
+ unsigned int syscon_args[2];
struct phy *phy;
- int ret;
phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL);
if (!phy_dev)
@@ -116,25 +116,15 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
/* Reset port by default: only deassert it in phy init */
reset_control_assert(phy_dev->rstport);
- phy_dev->regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+ phy_dev->regmap = syscon_regmap_lookup_by_phandle_args(np, "st,syscfg",
+ 2, syscon_args);
if (IS_ERR(phy_dev->regmap)) {
dev_err(dev, "No syscfg phandle specified\n");
return PTR_ERR(phy_dev->regmap);
}
- ret = of_property_read_u32_index(np, "st,syscfg", PHYPARAM_REG,
- &phy_dev->param);
- if (ret) {
- dev_err(dev, "can't get phyparam offset (%d)\n", ret);
- return ret;
- }
-
- ret = of_property_read_u32_index(np, "st,syscfg", PHYCTRL_REG,
- &phy_dev->ctrl);
- if (ret) {
- dev_err(dev, "can't get phyctrl offset (%d)\n", ret);
- return ret;
- }
+ phy_dev->param = syscon_args[PHYPARAM_REG];
+ phy_dev->ctrl = syscon_args[PHYCTRL_REG];
phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data);
if (IS_ERR(phy)) {
diff --git a/drivers/phy/starfive/phy-jh7110-usb.c b/drivers/phy/starfive/phy-jh7110-usb.c
index cb5454fbe2c8..b505d89860b4 100644
--- a/drivers/phy/starfive/phy-jh7110-usb.c
+++ b/drivers/phy/starfive/phy-jh7110-usb.c
@@ -18,6 +18,8 @@
#include <linux/usb/of.h>
#define USB_125M_CLK_RATE 125000000
+#define USB_CLK_MODE_OFF 0x0
+#define USB_CLK_MODE_RX_NORMAL_PWR BIT(1)
#define USB_LS_KEEPALIVE_OFF 0x4
#define USB_LS_KEEPALIVE_ENABLE BIT(4)
@@ -78,6 +80,7 @@ static int jh7110_usb2_phy_init(struct phy *_phy)
{
struct jh7110_usb2_phy *phy = phy_get_drvdata(_phy);
int ret;
+ unsigned int val;
ret = clk_set_rate(phy->usb_125m_clk, USB_125M_CLK_RATE);
if (ret)
@@ -87,6 +90,10 @@ static int jh7110_usb2_phy_init(struct phy *_phy)
if (ret)
return ret;
+ val = readl(phy->regs + USB_CLK_MODE_OFF);
+ val |= USB_CLK_MODE_RX_NORMAL_PWR;
+ writel(val, phy->regs + USB_CLK_MODE_OFF);
+
return 0;
}
diff --git a/drivers/phy/tegra/Kconfig b/drivers/phy/tegra/Kconfig
index c591c958f1eb..f30cfb42b210 100644
--- a/drivers/phy/tegra/Kconfig
+++ b/drivers/phy/tegra/Kconfig
@@ -13,7 +13,8 @@ config PHY_TEGRA_XUSB
config PHY_TEGRA194_P2U
tristate "NVIDIA Tegra194 PIPE2UPHY PHY driver"
- depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
+ depends on ARCH_TEGRA_194_SOC || ARCH_TEGRA_234_SOC || COMPILE_TEST
select GENERIC_PHY
help
- Enable this to support the P2U (PIPE to UPHY) that is part of Tegra 19x SOCs.
+ Enable this to support the P2U (PIPE to UPHY) that is part of Tegra 19x
+ and 234 SOCs.
diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c
index fae6242aa730..23a23f2d64e5 100644
--- a/drivers/phy/tegra/xusb-tegra186.c
+++ b/drivers/phy/tegra/xusb-tegra186.c
@@ -237,6 +237,8 @@
#define DATA0_VAL_PD BIT(1)
#define USE_XUSB_AO BIT(4)
+#define TEGRA_UTMI_PAD_MAX 4
+
#define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \
{ \
.name = _name, \
@@ -269,7 +271,7 @@ struct tegra186_xusb_padctl {
/* UTMI bias and tracking */
struct clk *usb2_trk_clk;
- unsigned int bias_pad_enable;
+ DECLARE_BITMAP(utmi_pad_enabled, TEGRA_UTMI_PAD_MAX);
/* padctl context */
struct tegra186_xusb_padctl_context context;
@@ -603,12 +605,8 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl)
u32 value;
int err;
- mutex_lock(&padctl->lock);
-
- if (priv->bias_pad_enable++ > 0) {
- mutex_unlock(&padctl->lock);
+ if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX))
return;
- }
err = clk_prepare_enable(priv->usb2_trk_clk);
if (err < 0)
@@ -658,8 +656,6 @@ static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl)
} else {
clk_disable_unprepare(priv->usb2_trk_clk);
}
-
- mutex_unlock(&padctl->lock);
}
static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
@@ -667,17 +663,8 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
u32 value;
- mutex_lock(&padctl->lock);
-
- if (WARN_ON(priv->bias_pad_enable == 0)) {
- mutex_unlock(&padctl->lock);
- return;
- }
-
- if (--priv->bias_pad_enable > 0) {
- mutex_unlock(&padctl->lock);
+ if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX))
return;
- }
value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1);
value |= USB2_PD_TRK;
@@ -690,13 +677,13 @@ static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl)
clk_disable_unprepare(priv->usb2_trk_clk);
}
- mutex_unlock(&padctl->lock);
}
static void tegra186_utmi_pad_power_on(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
struct tegra_xusb_usb2_port *port;
struct device *dev = padctl->dev;
unsigned int index = lane->index;
@@ -705,9 +692,16 @@ static void tegra186_utmi_pad_power_on(struct phy *phy)
if (!phy)
return;
+ mutex_lock(&padctl->lock);
+ if (test_bit(index, priv->utmi_pad_enabled)) {
+ mutex_unlock(&padctl->lock);
+ return;
+ }
+
port = tegra_xusb_find_usb2_port(padctl, index);
if (!port) {
dev_err(dev, "no port found for USB2 lane %u\n", index);
+ mutex_unlock(&padctl->lock);
return;
}
@@ -724,18 +718,28 @@ static void tegra186_utmi_pad_power_on(struct phy *phy)
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
value &= ~USB2_OTG_PD_DR;
padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index));
+
+ set_bit(index, priv->utmi_pad_enabled);
+ mutex_unlock(&padctl->lock);
}
static void tegra186_utmi_pad_power_down(struct phy *phy)
{
struct tegra_xusb_lane *lane = phy_get_drvdata(phy);
struct tegra_xusb_padctl *padctl = lane->pad->padctl;
+ struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl);
unsigned int index = lane->index;
u32 value;
if (!phy)
return;
+ mutex_lock(&padctl->lock);
+ if (!test_bit(index, priv->utmi_pad_enabled)) {
+ mutex_unlock(&padctl->lock);
+ return;
+ }
+
dev_dbg(padctl->dev, "power down UTMI pad %u\n", index);
value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
@@ -748,7 +752,11 @@ static void tegra186_utmi_pad_power_down(struct phy *phy)
udelay(2);
+ clear_bit(index, priv->utmi_pad_enabled);
+
tegra186_utmi_bias_pad_power_off(padctl);
+
+ mutex_unlock(&padctl->lock);
}
static int tegra186_xusb_padctl_vbus_override(struct tegra_xusb_padctl *padctl,
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index 79d4814d758d..c89df95aa6ca 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -548,16 +548,16 @@ static int tegra_xusb_port_init(struct tegra_xusb_port *port,
err = dev_set_name(&port->dev, "%s-%u", name, index);
if (err < 0)
- goto unregister;
+ goto put_device;
err = device_add(&port->dev);
if (err < 0)
- goto unregister;
+ goto put_device;
return 0;
-unregister:
- device_unregister(&port->dev);
+put_device:
+ put_device(&port->dev);
return err;
}
diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
index e0ca59ae3153..ff5d5e29629f 100644
--- a/drivers/phy/ti/phy-gmii-sel.c
+++ b/drivers/phy/ti/phy-gmii-sel.c
@@ -424,6 +424,12 @@ static int phy_gmii_sel_init_ports(struct phy_gmii_sel_priv *priv)
return 0;
}
+static const struct regmap_config phy_gmii_sel_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
static int phy_gmii_sel_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -468,7 +474,14 @@ static int phy_gmii_sel_probe(struct platform_device *pdev)
priv->regmap = syscon_node_to_regmap(node->parent);
if (IS_ERR(priv->regmap)) {
- priv->regmap = device_node_to_regmap(node);
+ void __iomem *base;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return dev_err_probe(dev, PTR_ERR(base),
+ "failed to get base memory resource\n");
+
+ priv->regmap = regmap_init_mmio(dev, base, &phy_gmii_sel_regmap_cfg);
if (IS_ERR(priv->regmap))
return dev_err_probe(dev, PTR_ERR(priv->regmap),
"Failed to get syscon\n");