diff options
Diffstat (limited to 'drivers/phy')
184 files changed, 25156 insertions, 4088 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 4cef568231bf..58c911e1b2d2 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -43,6 +43,14 @@ config PHY_PISTACHIO_USB help Enable this to support the USB2.0 PHY on the IMG Pistachio SoC. +config PHY_SNPS_EUSB2 + tristate "SNPS eUSB2 PHY Driver" + depends on OF && (ARCH_EXYNOS || ARCH_QCOM || COMPILE_TEST) + select GENERIC_PHY + help + Enable support for the USB high-speed SNPS eUSB2 phy on select + SoCs. The PHY is usually paired with a Synopsys DWC3 USB controller. + config PHY_XGENE tristate "APM X-Gene 15Gbps PHY support" depends on HAS_IOMEM && OF && (ARCH_XGENE || COMPILE_TEST) @@ -72,6 +80,27 @@ config PHY_CAN_TRANSCEIVER functional modes using gpios and sets the attribute max link rate, for CAN drivers. +config PHY_AIROHA_PCIE + tristate "Airoha PCIe-PHY Driver" + depends on ARCH_AIROHA || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Say Y here to add support for Airoha PCIe PHY driver. + This driver create the basic PHY instance and provides initialize + callback for PCIe GEN3 port. + +config PHY_NXP_PTN3222 + tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver" + depends on I2C + depends on OF + select GENERIC_PHY + help + Enable this to support NXP PTN3222 1-port eUSB2 to USB2 Redriver. + This redriver performs translation between eUSB2 and USB2 signalling + schemes. It supports all three USB 2.0 data rates: Low Speed, Full + Speed and High Speed. + source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/broadcom/Kconfig" @@ -85,8 +114,10 @@ source "drivers/phy/mediatek/Kconfig" source "drivers/phy/microchip/Kconfig" source "drivers/phy/motorola/Kconfig" source "drivers/phy/mscc/Kconfig" +source "drivers/phy/nuvoton/Kconfig" source "drivers/phy/qualcomm/Kconfig" source "drivers/phy/ralink/Kconfig" +source "drivers/phy/realtek/Kconfig" source "drivers/phy/renesas/Kconfig" source "drivers/phy/rockchip/Kconfig" source "drivers/phy/samsung/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index fb3dc9de6111..c670a8dac468 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -9,7 +9,10 @@ obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o +obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o +obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o +obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o obj-y += allwinner/ \ amlogic/ \ broadcom/ \ @@ -24,8 +27,10 @@ obj-y += allwinner/ \ microchip/ \ motorola/ \ mscc/ \ + nuvoton/ \ qualcomm/ \ ralink/ \ + realtek/ \ renesas/ \ rockchip/ \ samsung/ \ diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index e53a9a9317bc..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> @@ -683,7 +682,7 @@ static int sun4i_usb_phy0_vbus_notify(struct notifier_block *nb, } static struct phy *sun4i_usb_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct sun4i_usb_phy_data *data = dev_get_drvdata(dev); @@ -1049,11 +1048,11 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match); static struct platform_driver sun4i_usb_phy_driver = { - .probe = sun4i_usb_phy_probe, - .remove_new = sun4i_usb_phy_remove, + .probe = sun4i_usb_phy_probe, + .remove = sun4i_usb_phy_remove, .driver = { - .of_match_table = sun4i_usb_phy_of_match, - .name = "sun4i-usb-phy", + .of_match_table= sun4i_usb_phy_of_match, + .name = "sun4i-usb-phy", } }; module_platform_driver(sun4i_usb_phy_driver); diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c index 08a86962d949..c4a56b9d3289 100644 --- a/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-dphy.c @@ -377,13 +377,9 @@ static int phy_meson_axg_mipi_dphy_probe(struct platform_device *pdev) return ret; phy = devm_phy_create(dev, NULL, &phy_meson_axg_mipi_dphy_ops); - if (IS_ERR(phy)) { - ret = PTR_ERR(phy); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to create PHY\n"); - - return ret; - } + if (IS_ERR(phy)) + return dev_err_probe(dev, PTR_ERR(phy), + "failed to create PHY\n"); phy_set_drvdata(phy, priv); diff --git a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c index ae898f93f97b..c0ba2852dbb8 100644 --- a/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c +++ b/drivers/phy/amlogic/phy-meson-axg-mipi-pcie-analog.c @@ -200,7 +200,6 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev) struct phy_axg_mipi_pcie_analog_priv *priv; struct device_node *np = dev->of_node, *parent_np; struct regmap *map; - int ret; priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -219,12 +218,9 @@ static int phy_axg_mipi_pcie_analog_probe(struct platform_device *pdev) priv->regmap = map; priv->phy = devm_phy_create(dev, np, &phy_axg_mipi_pcie_analog_ops); - if (IS_ERR(priv->phy)) { - ret = PTR_ERR(priv->phy); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to create PHY\n"); - return ret; - } + if (IS_ERR(priv->phy)) + return dev_err_probe(dev, PTR_ERR(priv->phy), + "failed to create PHY\n"); phy_set_drvdata(priv->phy, priv); dev_set_drvdata(dev, priv); diff --git a/drivers/phy/amlogic/phy-meson-axg-pcie.c b/drivers/phy/amlogic/phy-meson-axg-pcie.c index 60be5cdc600b..14dee73f9cb5 100644 --- a/drivers/phy/amlogic/phy-meson-axg-pcie.c +++ b/drivers/phy/amlogic/phy-meson-axg-pcie.c @@ -131,20 +131,11 @@ static int phy_axg_pcie_probe(struct platform_device *pdev) struct phy_axg_pcie_priv *priv; struct device_node *np = dev->of_node; void __iomem *base; - int ret; priv = devm_kmalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops); - if (IS_ERR(priv->phy)) { - ret = PTR_ERR(priv->phy); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to create PHY\n"); - return ret; - } - base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); @@ -162,6 +153,11 @@ static int phy_axg_pcie_probe(struct platform_device *pdev) if (IS_ERR(priv->analog)) return PTR_ERR(priv->analog); + priv->phy = devm_phy_create(dev, np, &phy_axg_pcie_ops); + if (IS_ERR(priv->phy)) + return dev_err_probe(dev, PTR_ERR(priv->phy), + "failed to create PHY\n"); + phy_set_drvdata(priv->phy, priv); dev_set_drvdata(dev, priv); pphy = devm_of_phy_provider_register(dev, of_phy_simple_xlate); diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb2.c b/drivers/phy/amlogic/phy-meson-g12a-usb2.c index 0e0b5c00b676..66bf0b7ef8ed 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-usb2.c +++ b/drivers/phy/amlogic/phy-meson-g12a-usb2.c @@ -339,13 +339,9 @@ static int phy_meson_g12a_usb2_probe(struct platform_device *pdev) return ret; phy = devm_phy_create(dev, NULL, &phy_meson_g12a_usb2_ops); - if (IS_ERR(phy)) { - ret = PTR_ERR(phy); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to create PHY\n"); - - return ret; - } + if (IS_ERR(phy)) + return dev_err_probe(dev, PTR_ERR(phy), + "failed to create PHY\n"); phy_set_bus_width(phy, 8); phy_set_drvdata(phy, priv); diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c index 2712c4bd549d..5468831d6ab9 100644 --- a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c +++ b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c @@ -350,7 +350,7 @@ static int phy_g12a_usb3_pcie_exit(struct phy *phy) } static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct phy_g12a_usb3_pcie_priv *priv = dev_get_drvdata(dev); unsigned int mode; diff --git a/drivers/phy/amlogic/phy-meson-gxl-usb2.c b/drivers/phy/amlogic/phy-meson-gxl-usb2.c index 14ea89927ab1..6b390304f723 100644 --- a/drivers/phy/amlogic/phy-meson-gxl-usb2.c +++ b/drivers/phy/amlogic/phy-meson-gxl-usb2.c @@ -237,7 +237,6 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev) struct phy_meson_gxl_usb2_priv *priv; struct phy *phy; void __iomem *base; - int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -266,13 +265,9 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev) return PTR_ERR(priv->reset); phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops); - if (IS_ERR(phy)) { - ret = PTR_ERR(phy); - if (ret != -EPROBE_DEFER) - dev_err(dev, "failed to create PHY\n"); - - return ret; - } + if (IS_ERR(phy)) + return dev_err_probe(dev, PTR_ERR(phy), + "failed to create PHY\n"); phy_set_drvdata(phy, priv); diff --git a/drivers/phy/amlogic/phy-meson8b-usb2.c b/drivers/phy/amlogic/phy-meson8b-usb2.c index d63147c41b8c..a553231a9f7c 100644 --- a/drivers/phy/amlogic/phy-meson8b-usb2.c +++ b/drivers/phy/amlogic/phy-meson8b-usb2.c @@ -5,6 +5,7 @@ * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com> */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/io.h> @@ -39,9 +40,7 @@ #define REG_CTRL_TX_BITSTUFF_ENN BIT(18) #define REG_CTRL_COMMON_ON BIT(19) #define REG_CTRL_REF_CLK_SEL_MASK GENMASK(21, 20) - #define REG_CTRL_REF_CLK_SEL_SHIFT 20 #define REG_CTRL_FSEL_MASK GENMASK(24, 22) - #define REG_CTRL_FSEL_SHIFT 22 #define REG_CTRL_PORT_RESET BIT(25) #define REG_CTRL_THREAD_ID_MASK GENMASK(31, 26) @@ -166,33 +165,29 @@ static int phy_meson8b_usb2_power_on(struct phy *phy) return ret; } - regmap_update_bits(priv->regmap, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL, - REG_CONFIG_CLK_32k_ALTSEL); + regmap_set_bits(priv->regmap, REG_CONFIG, REG_CONFIG_CLK_32k_ALTSEL); regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_REF_CLK_SEL_MASK, - 0x2 << REG_CTRL_REF_CLK_SEL_SHIFT); + FIELD_PREP(REG_CTRL_REF_CLK_SEL_MASK, 0x2)); regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_FSEL_MASK, - 0x5 << REG_CTRL_FSEL_SHIFT); + FIELD_PREP(REG_CTRL_FSEL_MASK, 0x5)); /* reset the PHY */ - regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET, - REG_CTRL_POWER_ON_RESET); + regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET); udelay(RESET_COMPLETE_TIME); - regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET, 0); + regmap_clear_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET); udelay(RESET_COMPLETE_TIME); - regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT, - REG_CTRL_SOF_TOGGLE_OUT); + regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_SOF_TOGGLE_OUT); if (priv->dr_mode == USB_DR_MODE_HOST) { - regmap_update_bits(priv->regmap, REG_DBG_UART, - REG_DBG_UART_SET_IDDQ, 0); + regmap_clear_bits(priv->regmap, REG_DBG_UART, + REG_DBG_UART_SET_IDDQ); if (priv->match->host_enable_aca) { - regmap_update_bits(priv->regmap, REG_ADP_BC, - REG_ADP_BC_ACA_ENABLE, - REG_ADP_BC_ACA_ENABLE); + regmap_set_bits(priv->regmap, REG_ADP_BC, + REG_ADP_BC_ACA_ENABLE); udelay(ACA_ENABLE_COMPLETE_TIME); @@ -215,17 +210,15 @@ static int phy_meson8b_usb2_power_off(struct phy *phy) struct phy_meson8b_usb2_priv *priv = phy_get_drvdata(phy); if (priv->dr_mode == USB_DR_MODE_HOST) - regmap_update_bits(priv->regmap, REG_DBG_UART, - REG_DBG_UART_SET_IDDQ, - REG_DBG_UART_SET_IDDQ); + regmap_set_bits(priv->regmap, REG_DBG_UART, + REG_DBG_UART_SET_IDDQ); clk_disable_unprepare(priv->clk_usb); clk_disable_unprepare(priv->clk_usb_general); reset_control_rearm(priv->reset); /* power off the PHY by putting it into reset mode */ - regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET, - REG_CTRL_POWER_ON_RESET); + regmap_set_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET); return 0; } diff --git a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c index cc29b08e49eb..462c61a24ec5 100644 --- a/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c @@ -113,11 +113,10 @@ static const struct phy_ops cygnus_pcie_phy_ops = { static int cygnus_pcie_phy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node, *child; + struct device_node *node = dev->of_node; struct cygnus_pcie_phy_core *core; struct phy_provider *provider; unsigned cnt = 0; - int ret; if (of_get_child_count(node) == 0) { dev_err(dev, "PHY no child node\n"); @@ -136,35 +135,31 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev) mutex_init(&core->lock); - for_each_available_child_of_node(node, child) { + for_each_available_child_of_node_scoped(node, child) { unsigned int id; struct cygnus_pcie_phy *p; if (of_property_read_u32(child, "reg", &id)) { dev_err(dev, "missing reg property for %pOFn\n", child); - ret = -EINVAL; - goto put_child; + return -EINVAL; } if (id >= MAX_NUM_PHYS) { dev_err(dev, "invalid PHY id: %u\n", id); - ret = -EINVAL; - goto put_child; + return -EINVAL; } if (core->phys[id].phy) { dev_err(dev, "duplicated PHY id: %u\n", id); - ret = -EINVAL; - goto put_child; + return -EINVAL; } p = &core->phys[id]; p->phy = devm_phy_create(dev, child, &cygnus_pcie_phy_ops); if (IS_ERR(p->phy)) { dev_err(dev, "failed to create PHY\n"); - ret = PTR_ERR(p->phy); - goto put_child; + return PTR_ERR(p->phy); } p->core = core; @@ -184,9 +179,6 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev) dev_dbg(dev, "registered %u PCIe PHY(s)\n", cnt); return 0; -put_child: - of_node_put(child); - return ret; } static const struct of_device_id cygnus_pcie_phy_match_table[] = { diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb2.c b/drivers/phy/broadcom/phy-bcm-ns-usb2.c index 269564bdf687..c5d35031b398 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb2.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb2.c @@ -24,9 +24,6 @@ struct bcm_ns_usb2 { struct phy *phy; struct regmap *clkset; void __iomem *base; - - /* Deprecated binding */ - void __iomem *dmu; }; static int bcm_ns_usb2_phy_init(struct phy *phy) @@ -49,10 +46,7 @@ static int bcm_ns_usb2_phy_init(struct phy *phy) goto err_clk_off; } - if (usb2->base) - usb2ctl = readl(usb2->base); - else - usb2ctl = readl(usb2->dmu + BCMA_DMU_CRU_USB2_CONTROL); + usb2ctl = readl(usb2->base); if (usb2ctl & BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_PDIV_MASK) { usb_pll_pdiv = usb2ctl; @@ -66,24 +60,16 @@ static int bcm_ns_usb2_phy_init(struct phy *phy) usb_pll_ndiv = (1920000000 * usb_pll_pdiv) / ref_clk_rate; /* Unlock DMU PLL settings with some magic value */ - if (usb2->clkset) - regmap_write(usb2->clkset, 0, 0x0000ea68); - else - writel(0x0000ea68, usb2->dmu + BCMA_DMU_CRU_CLKSET_KEY); + regmap_write(usb2->clkset, 0, 0x0000ea68); /* Write USB 2.0 PLL control setting */ usb2ctl &= ~BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_MASK; usb2ctl |= usb_pll_ndiv << BCMA_DMU_CRU_USB2_CONTROL_USB_PLL_NDIV_SHIFT; - if (usb2->base) - writel(usb2ctl, usb2->base); - else - writel(usb2ctl, usb2->dmu + BCMA_DMU_CRU_USB2_CONTROL); + + writel(usb2ctl, usb2->base); /* Lock DMU PLL settings */ - if (usb2->clkset) - regmap_write(usb2->clkset, 0, 0x00000000); - else - writel(0x00000000, usb2->dmu + BCMA_DMU_CRU_CLKSET_KEY); + regmap_write(usb2->clkset, 0, 0x00000000); err_clk_off: clk_disable_unprepare(usb2->ref_clk); @@ -107,27 +93,17 @@ static int bcm_ns_usb2_probe(struct platform_device *pdev) return -ENOMEM; usb2->dev = dev; - if (of_property_present(dev->of_node, "brcm,syscon-clkset")) { - usb2->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(usb2->base)) { - dev_err(dev, "Failed to map control reg\n"); - return PTR_ERR(usb2->base); - } - - usb2->clkset = syscon_regmap_lookup_by_phandle(dev->of_node, - "brcm,syscon-clkset"); - if (IS_ERR(usb2->clkset)) { - dev_err(dev, "Failed to lookup clkset regmap\n"); - return PTR_ERR(usb2->clkset); - } - } else { - usb2->dmu = devm_platform_ioremap_resource_byname(pdev, "dmu"); - if (IS_ERR(usb2->dmu)) { - dev_err(dev, "Failed to map DMU regs\n"); - return PTR_ERR(usb2->dmu); - } + usb2->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(usb2->base)) { + dev_err(dev, "Failed to map control reg\n"); + return PTR_ERR(usb2->base); + } - dev_warn(dev, "using deprecated DT binding\n"); + usb2->clkset = syscon_regmap_lookup_by_phandle(dev->of_node, + "brcm,syscon-clkset"); + if (IS_ERR(usb2->clkset)) { + dev_err(dev, "Failed to lookup clkset regmap\n"); + return PTR_ERR(usb2->clkset); } usb2->ref_clk = devm_clk_get(dev, "phy-ref-clk"); @@ -162,4 +138,5 @@ static struct platform_driver bcm_ns_usb2_driver = { }; module_platform_driver(bcm_ns_usb2_driver); +MODULE_DESCRIPTION("Broadcom Northstar USB 2.0 PHY Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/broadcom/phy-bcm-ns-usb3.c b/drivers/phy/broadcom/phy-bcm-ns-usb3.c index 2c8b1b7dda5b..9f995e156f75 100644 --- a/drivers/phy/broadcom/phy-bcm-ns-usb3.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb3.c @@ -240,5 +240,6 @@ static struct mdio_driver bcm_ns_usb3_mdio_driver = { mdio_module_driver(bcm_ns_usb3_mdio_driver); +MODULE_DESCRIPTION("Broadcom Northstar USB 3.0 PHY Driver"); MODULE_LICENSE("GPL v2"); MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table); diff --git a/drivers/phy/broadcom/phy-bcm-sr-pcie.c b/drivers/phy/broadcom/phy-bcm-sr-pcie.c index 8a4aadf166cf..ff9b3862bf7a 100644 --- a/drivers/phy/broadcom/phy-bcm-sr-pcie.c +++ b/drivers/phy/broadcom/phy-bcm-sr-pcie.c @@ -195,7 +195,7 @@ static const struct phy_ops sr_paxc_phy_ops = { }; static struct phy *sr_pcie_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct sr_pcie_phy_core *core; int phy_idx; diff --git a/drivers/phy/broadcom/phy-bcm-sr-usb.c b/drivers/phy/broadcom/phy-bcm-sr-usb.c index b0bd18a5df87..6bcfe83609c8 100644 --- a/drivers/phy/broadcom/phy-bcm-sr-usb.c +++ b/drivers/phy/broadcom/phy-bcm-sr-usb.c @@ -209,7 +209,7 @@ static const struct phy_ops sr_phy_ops = { }; static struct phy *bcm_usb_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct bcm_usb_phy_cfg *phy_cfg; int phy_idx; diff --git a/drivers/phy/broadcom/phy-bcm63xx-usbh.c b/drivers/phy/broadcom/phy-bcm63xx-usbh.c index f8183dea774b..647644de041b 100644 --- a/drivers/phy/broadcom/phy-bcm63xx-usbh.c +++ b/drivers/phy/broadcom/phy-bcm63xx-usbh.c @@ -366,7 +366,7 @@ static const struct phy_ops bcm63xx_usbh_phy_ops = { }; static struct phy *bcm63xx_usbh_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct bcm63xx_usbh_phy *usbh = dev_get_drvdata(dev); diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c index ed9e18791ec9..228100357054 100644 --- a/drivers/phy/broadcom/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c @@ -751,11 +751,11 @@ static int brcm_sata_phy_probe(struct platform_device *pdev) { const char *rxaeq_mode; struct device *dev = &pdev->dev; - struct device_node *dn = dev->of_node, *child; + struct device_node *dn = dev->of_node; const struct of_device_id *of_id; struct brcm_sata_phy *priv; struct phy_provider *provider; - int ret, count = 0; + int count = 0; if (of_get_child_count(dn) == 0) return -ENODEV; @@ -782,26 +782,23 @@ static int brcm_sata_phy_probe(struct platform_device *pdev) return PTR_ERR(priv->ctrl_base); } - for_each_available_child_of_node(dn, child) { + for_each_available_child_of_node_scoped(dn, child) { unsigned int id; struct brcm_sata_port *port; if (of_property_read_u32(child, "reg", &id)) { dev_err(dev, "missing reg property in node %pOFn\n", child); - ret = -EINVAL; - goto put_child; + return -EINVAL; } if (id >= MAX_PORTS) { dev_err(dev, "invalid reg: %u\n", id); - ret = -EINVAL; - goto put_child; + return -EINVAL; } if (priv->phys[id].phy) { dev_err(dev, "already registered port %u\n", id); - ret = -EINVAL; - goto put_child; + return -EINVAL; } port = &priv->phys[id]; @@ -822,8 +819,7 @@ static int brcm_sata_phy_probe(struct platform_device *pdev) port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc"); if (IS_ERR(port->phy)) { dev_err(dev, "failed to create PHY\n"); - ret = PTR_ERR(port->phy); - goto put_child; + return PTR_ERR(port->phy); } phy_set_drvdata(port->phy, port); @@ -839,9 +835,6 @@ static int brcm_sata_phy_probe(struct platform_device *pdev) dev_info(dev, "registered %d port(s)\n", count); return 0; -put_child: - of_node_put(child); - return ret; } static struct platform_driver brcm_sata_phy_driver = { diff --git a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c index 4c10cafded4e..8a5ed50f2da0 100644 --- a/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c +++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c @@ -43,6 +43,8 @@ #define USB_CTRL_SETUP_tca_drv_sel_MASK BIT(24) #define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK BIT(25) #define USB_CTRL_USB_PM 0x04 +#define USB_CTRL_USB_PM_REF_S2_CLK_SWITCH_EN_MASK BIT(1) +#define USB_CTRL_USB_PM_UTMI_S2_CLK_SWITCH_EN_MASK BIT(2) #define USB_CTRL_USB_PM_XHC_S2_CLK_SWITCH_EN_MASK BIT(3) #define USB_CTRL_USB_PM_XHC_PME_EN_MASK BIT(4) #define USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK BIT(22) @@ -61,6 +63,13 @@ #define USB_CTRL_CTLR_CSHCR_ctl_pme_en_MASK BIT(18) #define USB_CTRL_P0_U2PHY_CFG1 0x68 #define USB_CTRL_P0_U2PHY_CFG1_COMMONONN_MASK BIT(10) +#define USB_CTRL_P0_U2PHY_CFG2 0x6c +#define USB_CTRL_P0_U2PHY_CFG2_TXVREFTUNE0_MASK GENMASK(20, 17) +#define USB_CTRL_P0_U2PHY_CFG2_TXVREFTUNE0_SHIFT 17 +#define USB_CTRL_P0_U2PHY_CFG2_TXRESTUNE0_MASK GENMASK(24, 23) +#define USB_CTRL_P0_U2PHY_CFG2_TXRESTUNE0_SHIFT 23 +#define USB_CTRL_P0_U2PHY_CFG2_TXPREEMPAMPTUNE0_MASK GENMASK(26, 25) +#define USB_CTRL_P0_U2PHY_CFG2_TXPREEMPAMPTUNE0_SHIFT 25 /* Register definitions for the USB_PHY block in 7211b0 */ #define USB_PHY_PLL_CTL 0x00 @@ -153,7 +162,9 @@ static void xhci_soft_reset(struct brcm_usb_init_params *params, } else { USB_CTRL_SET(ctrl, USB_PM, XHC_SOFT_RESETB); /* Required for COMMONONN to be set */ - USB_XHCI_GBL_UNSET(xhci_gbl, GUSB2PHYCFG, U2_FREECLK_EXISTS); + if (params->supported_port_modes != USB_CTLR_MODE_DRD) + USB_XHCI_GBL_UNSET(xhci_gbl, GUSB2PHYCFG, + U2_FREECLK_EXISTS); } } @@ -323,13 +334,23 @@ static void usb_init_common_7216(struct brcm_usb_init_params *params) void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; USB_CTRL_UNSET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN); + + /* + * The PHY might be in a bad state if it is already powered + * up. Toggle the power just in case. + */ + USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN); USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN); /* 1 millisecond - for USB clocks to settle down */ usleep_range(1000, 2000); - /* Disable PHY when port is suspended */ - USB_CTRL_SET(ctrl, P0_U2PHY_CFG1, COMMONONN); + /* + * Disable PHY when port is suspended + * Does not work in DRD mode + */ + if (params->supported_port_modes != USB_CTLR_MODE_DRD) + USB_CTRL_SET(ctrl, P0_U2PHY_CFG1, COMMONONN); usb_wake_enable_7216(params, false); usb_init_common(params); @@ -357,6 +378,42 @@ static void usb_uninit_common_7216(struct brcm_usb_init_params *params) } } +static void usb_init_common_74110(struct brcm_usb_init_params *params) +{ + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; + u32 reg; + + reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_PM)); + reg &= ~(USB_CTRL_MASK(USB_PM, REF_S2_CLK_SWITCH_EN) | + USB_CTRL_MASK(USB_PM, UTMI_S2_CLK_SWITCH_EN)); + brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_PM)); + + usb_init_common_7216(params); + + reg = brcm_usb_readl(USB_CTRL_REG(ctrl, P0_U2PHY_CFG2)); + reg &= ~(USB_CTRL_P0_U2PHY_CFG2_TXVREFTUNE0_MASK | + USB_CTRL_P0_U2PHY_CFG2_TXRESTUNE0_MASK | + USB_CTRL_P0_U2PHY_CFG2_TXPREEMPAMPTUNE0_MASK); + reg |= (0x6 << USB_CTRL_P0_U2PHY_CFG2_TXVREFTUNE0_SHIFT) | + (0x3 << USB_CTRL_P0_U2PHY_CFG2_TXRESTUNE0_SHIFT) | + (0x2 << USB_CTRL_P0_U2PHY_CFG2_TXPREEMPAMPTUNE0_SHIFT); + brcm_usb_writel(reg, USB_CTRL_REG(ctrl, P0_U2PHY_CFG2)); +} + +static void usb_uninit_common_74110(struct brcm_usb_init_params *params) +{ + void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; + u32 reg; + + if (params->wake_enabled) { + reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_PM)); + reg |= (USB_CTRL_MASK(USB_PM, REF_S2_CLK_SWITCH_EN) | + USB_CTRL_MASK(USB_PM, UTMI_S2_CLK_SWITCH_EN)); + brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_PM)); + } + usb_uninit_common_7216(params); +} + static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params) { void __iomem *ctrl = params->regs[BRCM_REGS_CTRL]; @@ -414,6 +471,16 @@ static void usb_set_dual_select(struct brcm_usb_init_params *params) brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1)); } +static const struct brcm_usb_init_ops bcm74110_ops = { + .init_ipp = usb_init_ipp, + .init_common = usb_init_common_74110, + .init_xhci = usb_init_xhci, + .uninit_common = usb_uninit_common_74110, + .uninit_xhci = usb_uninit_xhci, + .get_dual_select = usb_get_dual_select, + .set_dual_select = usb_set_dual_select, +}; + static const struct brcm_usb_init_ops bcm7216_ops = { .init_ipp = usb_init_ipp, .init_common = usb_init_common_7216, @@ -434,6 +501,12 @@ static const struct brcm_usb_init_ops bcm7211b0_ops = { .set_dual_select = usb_set_dual_select, }; +void brcm_usb_dvr_init_74110(struct brcm_usb_init_params *params) +{ + params->family_name = "74110"; + params->ops = &bcm74110_ops; +} + void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params) { diff --git a/drivers/phy/broadcom/phy-brcm-usb-init.c b/drivers/phy/broadcom/phy-brcm-usb-init.c index 39536b6d96a9..da23078878a9 100644 --- a/drivers/phy/broadcom/phy-brcm-usb-init.c +++ b/drivers/phy/broadcom/phy-brcm-usb-init.c @@ -193,254 +193,251 @@ static const u32 usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = { /* 3390B0 */ [BRCM_FAMILY_3390A0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 4908 */ [BRCM_FAMILY_4908] = { - 0, /* USB_CTRL_SETUP_SCB1_EN_MASK */ - 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ - 0, /* USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */ - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - 0, /* USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK */ - 0, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, }, /* 7250b0 */ [BRCM_FAMILY_7250B0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, - 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR] = + USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7271a0 */ [BRCM_FAMILY_7271A0] = { - 0, /* USB_CTRL_SETUP_SCB1_EN_MASK */ - 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - USB_CTRL_USB_PM_SOFT_RESET_MASK, - USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK, - USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK, - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_SOFT_RESET_SELECTOR] = + USB_CTRL_USB_PM_SOFT_RESET_MASK, + [USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_SELECTOR] = + USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK, + [USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7364a0 */ [BRCM_FAMILY_7364A0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, - 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR] = + USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7366c0 */ [BRCM_FAMILY_7366C0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_VAR_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 74371A0 */ [BRCM_FAMILY_74371A0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK */ - 0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */ - USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ - USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB30_CTL1_USB3_IOC_MASK, - USB_CTRL_USB30_CTL1_USB3_IPP_MASK, - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - 0, /* USB_CTRL_USB_PM_USB20_HC_RESETB_MASK */ - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, + [USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR] = + USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, + [USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB30_CTL1_USB3_IOC_SELECTOR] = + USB_CTRL_USB30_CTL1_USB3_IOC_MASK, + [USB_CTRL_USB30_CTL1_USB3_IPP_SELECTOR] = + USB_CTRL_USB30_CTL1_USB3_IPP_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7439B0 */ [BRCM_FAMILY_7439B0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7445d0 */ [BRCM_FAMILY_7445D0] = { - USB_CTRL_SETUP_SCB1_EN_MASK, - USB_CTRL_SETUP_SCB2_EN_MASK, - USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, - 0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */ - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, - 0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB_PM_USB_PWRDN_MASK */ - USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK, - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - 0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */ - 0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */ - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SCB1_EN_SELECTOR] = + USB_CTRL_SETUP_SCB1_EN_MASK, + [USB_CTRL_SETUP_SCB2_EN_SELECTOR] = + USB_CTRL_SETUP_SCB2_EN_MASK, + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_VAR_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_SELECTOR] = + USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK, + [USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7260a0 */ [BRCM_FAMILY_7260A0] = { - 0, /* USB_CTRL_SETUP_SCB1_EN_MASK */ - 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ - USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - USB_CTRL_USB_PM_SOFT_RESET_MASK, - USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK, - USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK, - USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, - ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_SS_EHCI64BIT_EN_SELECTOR] = + USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK, + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_SOFT_RESET_SELECTOR] = + USB_CTRL_USB_PM_SOFT_RESET_MASK, + [USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_SELECTOR] = + USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK, + [USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK, + [USB_CTRL_USB_PM_USB20_HC_RESETB_SELECTOR] = + USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK, + [USB_CTRL_SETUP_ENDIAN_SELECTOR] = ENDIAN_SETTINGS, }, /* 7278a0 */ [BRCM_FAMILY_7278A0] = { - 0, /* USB_CTRL_SETUP_SCB1_EN_MASK */ - 0, /* USB_CTRL_SETUP_SCB2_EN_MASK */ - 0, /*USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */ - USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, - USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, - USB_CTRL_SETUP_OC3_DISABLE_MASK, - 0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */ - USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, - USB_CTRL_USB_PM_USB_PWRDN_MASK, - 0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */ - 0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */ - USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, - USB_CTRL_USB_PM_SOFT_RESET_MASK, - 0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */ - 0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */ - 0, /* USB_CTRL_USB_PM_USB20_HC_RESETB_MASK */ - 0, /* USB_CTRL_SETUP ENDIAN bits */ + [USB_CTRL_SETUP_STRAP_IPP_SEL_SELECTOR] = + USB_CTRL_SETUP_STRAP_IPP_SEL_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT0_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT0_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_PORT1_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_PORT1_MASK, + [USB_CTRL_SETUP_OC3_DISABLE_SELECTOR] = + USB_CTRL_SETUP_OC3_DISABLE_MASK, + [USB_CTRL_USB_PM_BDC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_XHC_SOFT_RESETB_SELECTOR] = + USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK, + [USB_CTRL_USB_PM_USB_PWRDN_SELECTOR] = + USB_CTRL_USB_PM_USB_PWRDN_MASK, + [USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_SELECTOR] = + USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK, + [USB_CTRL_USB_PM_SOFT_RESET_SELECTOR] = + USB_CTRL_USB_PM_SOFT_RESET_MASK, }, }; diff --git a/drivers/phy/broadcom/phy-brcm-usb-init.h b/drivers/phy/broadcom/phy-brcm-usb-init.h index c1a88f5cd4cd..4c7be78d0b14 100644 --- a/drivers/phy/broadcom/phy-brcm-usb-init.h +++ b/drivers/phy/broadcom/phy-brcm-usb-init.h @@ -72,6 +72,7 @@ struct brcm_usb_init_params { bool wake_enabled; }; +void brcm_usb_dvr_init_74110(struct brcm_usb_init_params *params); void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params); void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params); void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params); diff --git a/drivers/phy/broadcom/phy-brcm-usb.c b/drivers/phy/broadcom/phy-brcm-usb.c index a16f0b58eb74..0666864c2f77 100644 --- a/drivers/phy/broadcom/phy-brcm-usb.c +++ b/drivers/phy/broadcom/phy-brcm-usb.c @@ -175,7 +175,7 @@ static const struct phy_ops brcm_usb_phy_ops = { }; static struct phy *brcm_usb_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct brcm_usb_phy_data *data = dev_get_drvdata(dev); @@ -283,6 +283,16 @@ static const struct attribute_group brcm_usb_phy_group = { .attrs = brcm_usb_phy_attrs, }; +static const struct match_chip_info chip_info_74110 = { + .init_func = &brcm_usb_dvr_init_74110, + .required_regs = { + BRCM_REGS_CTRL, + BRCM_REGS_XHCI_EC, + BRCM_REGS_XHCI_GBL, + -1, + }, +}; + static const struct match_chip_info chip_info_4908 = { .init_func = &brcm_usb_dvr_init_4908, .required_regs = { @@ -326,6 +336,10 @@ static const struct match_chip_info chip_info_7445 = { static const struct of_device_id brcm_usb_dt_ids[] = { { + .compatible = "brcm,bcm74110-usb-phy", + .data = &chip_info_74110, + }, + { .compatible = "brcm,bcm4908-usb-phy", .data = &chip_info_4908, }, @@ -667,7 +681,7 @@ MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids); static struct platform_driver brcm_usb_driver = { .probe = brcm_usb_phy_probe, - .remove_new = brcm_usb_phy_remove, + .remove = brcm_usb_phy_remove, .driver = { .name = "brcmstb-usb-phy", .pm = &brcm_usb_phy_pm_ops, diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c index dddb66de6dba..ed87a3970f83 100644 --- a/drivers/phy/cadence/cdns-dphy.c +++ b/drivers/phy/cadence/cdns-dphy.c @@ -472,7 +472,7 @@ MODULE_DEVICE_TABLE(of, cdns_dphy_of_match); static struct platform_driver cdns_dphy_platform_driver = { .probe = cdns_dphy_probe, - .remove_new = cdns_dphy_remove, + .remove = cdns_dphy_remove, .driver = { .name = "cdns-mipi-dphy", .of_match_table = cdns_dphy_of_match, diff --git a/drivers/phy/cadence/phy-cadence-sierra.c b/drivers/phy/cadence/phy-cadence-sierra.c index d4eb93ce8232..45a5c00843bf 100644 --- a/drivers/phy/cadence/phy-cadence-sierra.c +++ b/drivers/phy/cadence/phy-cadence-sierra.c @@ -174,8 +174,9 @@ #define SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG 0x150 #define SIERRA_DEQ_TAU_CTRL2_PREG 0x151 #define SIERRA_DEQ_TAU_CTRL3_PREG 0x152 -#define SIERRA_DEQ_OPENEYE_CTRL_PREG 0x158 +#define SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG 0x158 #define SIERRA_DEQ_CONCUR_EPIOFFSET_MODE_PREG 0x159 +#define SIERRA_DEQ_OPENEYE_CTRL_PREG 0x15C #define SIERRA_DEQ_PICTRL_PREG 0x161 #define SIERRA_CPICAL_TMRVAL_MODE1_PREG 0x170 #define SIERRA_CPICAL_TMRVAL_MODE0_PREG 0x171 @@ -310,7 +311,7 @@ static const struct clk_parent_data pll_mux_parent_data[][SIERRA_NUM_CMN_PLLC_PA }, }; -static u32 cdns_sierra_pll_mux_table[][SIERRA_NUM_CMN_PLLC_PARENTS] = { +static const u32 cdns_sierra_pll_mux_table[][SIERRA_NUM_CMN_PLLC_PARENTS] = { [CMN_PLLLC] = { 0, 1 }, [CMN_PLLLC1] = { 1, 0 }, }; @@ -362,14 +363,14 @@ struct cdns_sierra_data { u32 id_value; u8 block_offset_shift; u8 reg_offset_shift; - struct cdns_sierra_vals *pcs_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; - struct cdns_sierra_vals *phy_pma_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; - struct cdns_sierra_vals *pma_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; - struct cdns_sierra_vals *pma_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; + const struct cdns_sierra_vals *pcs_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] + [NUM_SSC_MODE]; + const struct cdns_sierra_vals *phy_pma_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] + [NUM_SSC_MODE]; + const struct cdns_sierra_vals *pma_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] + [NUM_SSC_MODE]; + const struct cdns_sierra_vals *pma_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] + [NUM_SSC_MODE]; }; struct cdns_regmap_cdb_context { @@ -539,12 +540,12 @@ static int cdns_sierra_phy_init(struct phy *gphy) struct cdns_sierra_inst *ins = phy_get_drvdata(gphy); struct cdns_sierra_phy *phy = dev_get_drvdata(gphy->dev.parent); const struct cdns_sierra_data *init_data = phy->init_data; - struct cdns_sierra_vals *pma_cmn_vals, *pma_ln_vals; + const struct cdns_sierra_vals *pma_cmn_vals, *pma_ln_vals; enum cdns_sierra_phy_type phy_type = ins->phy_type; + const struct cdns_sierra_vals *phy_pma_ln_vals; enum cdns_sierra_ssc_mode ssc = ins->ssc_mode; - struct cdns_sierra_vals *phy_pma_ln_vals; + const struct cdns_sierra_vals *pcs_cmn_vals; const struct cdns_reg_pairs *reg_pairs; - struct cdns_sierra_vals *pcs_cmn_vals; struct regmap *regmap; u32 num_regs; int i, j; @@ -1244,12 +1245,12 @@ static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp, static int cdns_sierra_phy_configure_multilink(struct cdns_sierra_phy *sp) { + const struct cdns_sierra_vals *pma_cmn_vals, *pma_ln_vals; const struct cdns_sierra_data *init_data = sp->init_data; - struct cdns_sierra_vals *pma_cmn_vals, *pma_ln_vals; + const struct cdns_sierra_vals *phy_pma_ln_vals; + const struct cdns_sierra_vals *pcs_cmn_vals; enum cdns_sierra_phy_type phy_t1, phy_t2; - struct cdns_sierra_vals *phy_pma_ln_vals; const struct cdns_reg_pairs *reg_pairs; - struct cdns_sierra_vals *pcs_cmn_vals; int i, j, node, mlane, num_lanes, ret; enum cdns_sierra_ssc_mode ssc; struct regmap *regmap; @@ -1366,7 +1367,7 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) unsigned int id_value; int ret, node = 0; void __iomem *base; - struct device_node *dn = dev->of_node, *child; + struct device_node *dn = dev->of_node; if (of_get_child_count(dn) == 0) return -ENODEV; @@ -1438,7 +1439,7 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) sp->autoconf = of_property_read_bool(dn, "cdns,autoconf"); - for_each_available_child_of_node(dn, child) { + for_each_available_child_of_node_scoped(dn, child) { struct phy *gphy; if (!(of_node_name_eq(child, "phy") || @@ -1452,7 +1453,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) dev_err(dev, "failed to get reset %s\n", child->full_name); ret = PTR_ERR(sp->phys[node].lnk_rst); - of_node_put(child); goto put_control; } @@ -1461,7 +1461,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) if (ret) { dev_err(dev, "missing property in node %s\n", child->name); - of_node_put(child); reset_control_put(sp->phys[node].lnk_rst); goto put_control; } @@ -1475,7 +1474,6 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev) gphy = devm_phy_create(dev, child, &noop_ops); if (IS_ERR(gphy)) { ret = PTR_ERR(gphy); - of_node_put(child); reset_control_put(sp->phys[node].lnk_rst); goto put_control; } @@ -1544,11 +1542,11 @@ static void cdns_sierra_phy_remove(struct platform_device *pdev) } /* SGMII PHY PMA lane configuration */ -static struct cdns_reg_pairs sgmii_phy_pma_ln_regs[] = { +static const struct cdns_reg_pairs sgmii_phy_pma_ln_regs[] = { {0x9010, SIERRA_PHY_PMA_XCVR_CTRL} }; -static struct cdns_sierra_vals sgmii_phy_pma_ln_vals = { +static const struct cdns_sierra_vals sgmii_phy_pma_ln_vals = { .reg_pairs = sgmii_phy_pma_ln_regs, .num_regs = ARRAY_SIZE(sgmii_phy_pma_ln_regs), }; @@ -1598,22 +1596,22 @@ static const struct cdns_reg_pairs sgmii_100_no_ssc_plllc1_opt3_ln_regs[] = { {0x0002, SIERRA_RXBUFFER_RCDFECTRL_PREG} }; -static struct cdns_sierra_vals sgmii_100_no_ssc_plllc1_opt3_cmn_vals = { +static const struct cdns_sierra_vals sgmii_100_no_ssc_plllc1_opt3_cmn_vals = { .reg_pairs = sgmii_100_no_ssc_plllc1_opt3_cmn_regs, .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_plllc1_opt3_cmn_regs), }; -static struct cdns_sierra_vals sgmii_100_no_ssc_plllc1_opt3_ln_vals = { +static const struct cdns_sierra_vals sgmii_100_no_ssc_plllc1_opt3_ln_vals = { .reg_pairs = sgmii_100_no_ssc_plllc1_opt3_ln_regs, .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_plllc1_opt3_ln_regs), }; /* QSGMII PHY PMA lane configuration */ -static struct cdns_reg_pairs qsgmii_phy_pma_ln_regs[] = { +static const struct cdns_reg_pairs qsgmii_phy_pma_ln_regs[] = { {0x9010, SIERRA_PHY_PMA_XCVR_CTRL} }; -static struct cdns_sierra_vals qsgmii_phy_pma_ln_vals = { +static const struct cdns_sierra_vals qsgmii_phy_pma_ln_vals = { .reg_pairs = qsgmii_phy_pma_ln_regs, .num_regs = ARRAY_SIZE(qsgmii_phy_pma_ln_regs), }; @@ -1664,22 +1662,22 @@ static const struct cdns_reg_pairs qsgmii_100_no_ssc_plllc1_ln_regs[] = { {0x0002, SIERRA_RXBUFFER_RCDFECTRL_PREG} }; -static struct cdns_sierra_vals qsgmii_100_no_ssc_plllc1_cmn_vals = { +static const struct cdns_sierra_vals qsgmii_100_no_ssc_plllc1_cmn_vals = { .reg_pairs = qsgmii_100_no_ssc_plllc1_cmn_regs, .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_plllc1_cmn_regs), }; -static struct cdns_sierra_vals qsgmii_100_no_ssc_plllc1_ln_vals = { +static const struct cdns_sierra_vals qsgmii_100_no_ssc_plllc1_ln_vals = { .reg_pairs = qsgmii_100_no_ssc_plllc1_ln_regs, .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_plllc1_ln_regs), }; /* PCIE PHY PCS common configuration */ -static struct cdns_reg_pairs pcie_phy_pcs_cmn_regs[] = { +static const struct cdns_reg_pairs pcie_phy_pcs_cmn_regs[] = { {0x0430, SIERRA_PHY_PIPE_CMN_CTRL1} }; -static struct cdns_sierra_vals pcie_phy_pcs_cmn_vals = { +static const struct cdns_sierra_vals pcie_phy_pcs_cmn_vals = { .reg_pairs = pcie_phy_pcs_cmn_regs, .num_regs = ARRAY_SIZE(pcie_phy_pcs_cmn_regs), }; @@ -1736,7 +1734,7 @@ static const struct cdns_reg_pairs ml_pcie_100_no_ssc_ln_regs[] = { {0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, {0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG}, {0x0100, SIERRA_DEQ_TAU_CTRL3_PREG}, - {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG}, {0x002B, SIERRA_CPI_TRIM_PREG}, {0x0003, SIERRA_EPI_CTRL_PREG}, {0x803F, SIERRA_SDFILT_H2L_A_PREG}, @@ -1745,12 +1743,12 @@ static const struct cdns_reg_pairs ml_pcie_100_no_ssc_ln_regs[] = { {0x4432, SIERRA_RXBUFFER_DFECTRL_PREG} }; -static struct cdns_sierra_vals pcie_100_no_ssc_plllc_cmn_vals = { +static const struct cdns_sierra_vals pcie_100_no_ssc_plllc_cmn_vals = { .reg_pairs = pcie_100_no_ssc_plllc_cmn_regs, .num_regs = ARRAY_SIZE(pcie_100_no_ssc_plllc_cmn_regs), }; -static struct cdns_sierra_vals ml_pcie_100_no_ssc_ln_vals = { +static const struct cdns_sierra_vals ml_pcie_100_no_ssc_ln_vals = { .reg_pairs = ml_pcie_100_no_ssc_ln_regs, .num_regs = ARRAY_SIZE(ml_pcie_100_no_ssc_ln_regs), }; @@ -1800,7 +1798,7 @@ static const struct cdns_reg_pairs ti_ml_pcie_100_no_ssc_ln_regs[] = { {0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, {0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG}, {0x0100, SIERRA_DEQ_TAU_CTRL3_PREG}, - {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG}, {0x002B, SIERRA_CPI_TRIM_PREG}, {0x0003, SIERRA_EPI_CTRL_PREG}, {0x803F, SIERRA_SDFILT_H2L_A_PREG}, @@ -1810,7 +1808,7 @@ static const struct cdns_reg_pairs ti_ml_pcie_100_no_ssc_ln_regs[] = { {0x0002, SIERRA_TX_RCVDET_OVRD_PREG} }; -static struct cdns_sierra_vals ti_ml_pcie_100_no_ssc_ln_vals = { +static const struct cdns_sierra_vals ti_ml_pcie_100_no_ssc_ln_vals = { .reg_pairs = ti_ml_pcie_100_no_ssc_ln_regs, .num_regs = ARRAY_SIZE(ti_ml_pcie_100_no_ssc_ln_regs), }; @@ -1877,7 +1875,7 @@ static const struct cdns_reg_pairs ml_pcie_100_int_ssc_ln_regs[] = { {0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, {0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG}, {0x0100, SIERRA_DEQ_TAU_CTRL3_PREG}, - {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG}, {0x002B, SIERRA_CPI_TRIM_PREG}, {0x0003, SIERRA_EPI_CTRL_PREG}, {0x803F, SIERRA_SDFILT_H2L_A_PREG}, @@ -1886,12 +1884,12 @@ static const struct cdns_reg_pairs ml_pcie_100_int_ssc_ln_regs[] = { {0x4432, SIERRA_RXBUFFER_DFECTRL_PREG} }; -static struct cdns_sierra_vals pcie_100_int_ssc_plllc_cmn_vals = { +static const struct cdns_sierra_vals pcie_100_int_ssc_plllc_cmn_vals = { .reg_pairs = pcie_100_int_ssc_plllc_cmn_regs, .num_regs = ARRAY_SIZE(pcie_100_int_ssc_plllc_cmn_regs), }; -static struct cdns_sierra_vals ml_pcie_100_int_ssc_ln_vals = { +static const struct cdns_sierra_vals ml_pcie_100_int_ssc_ln_vals = { .reg_pairs = ml_pcie_100_int_ssc_ln_regs, .num_regs = ARRAY_SIZE(ml_pcie_100_int_ssc_ln_regs), }; @@ -1944,7 +1942,7 @@ static const struct cdns_reg_pairs ti_ml_pcie_100_int_ssc_ln_regs[] = { {0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, {0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG}, {0x0100, SIERRA_DEQ_TAU_CTRL3_PREG}, - {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG}, {0x002B, SIERRA_CPI_TRIM_PREG}, {0x0003, SIERRA_EPI_CTRL_PREG}, {0x803F, SIERRA_SDFILT_H2L_A_PREG}, @@ -1954,7 +1952,7 @@ static const struct cdns_reg_pairs ti_ml_pcie_100_int_ssc_ln_regs[] = { {0x0002, SIERRA_TX_RCVDET_OVRD_PREG} }; -static struct cdns_sierra_vals ti_ml_pcie_100_int_ssc_ln_vals = { +static const struct cdns_sierra_vals ti_ml_pcie_100_int_ssc_ln_vals = { .reg_pairs = ti_ml_pcie_100_int_ssc_ln_regs, .num_regs = ARRAY_SIZE(ti_ml_pcie_100_int_ssc_ln_regs), }; @@ -2015,7 +2013,7 @@ static const struct cdns_reg_pairs ml_pcie_100_ext_ssc_ln_regs[] = { {0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, {0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG}, {0x0100, SIERRA_DEQ_TAU_CTRL3_PREG}, - {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG}, {0x002B, SIERRA_CPI_TRIM_PREG}, {0x0003, SIERRA_EPI_CTRL_PREG}, {0x803F, SIERRA_SDFILT_H2L_A_PREG}, @@ -2024,12 +2022,12 @@ static const struct cdns_reg_pairs ml_pcie_100_ext_ssc_ln_regs[] = { {0x4432, SIERRA_RXBUFFER_DFECTRL_PREG} }; -static struct cdns_sierra_vals pcie_100_ext_ssc_plllc_cmn_vals = { +static const struct cdns_sierra_vals pcie_100_ext_ssc_plllc_cmn_vals = { .reg_pairs = pcie_100_ext_ssc_plllc_cmn_regs, .num_regs = ARRAY_SIZE(pcie_100_ext_ssc_plllc_cmn_regs), }; -static struct cdns_sierra_vals ml_pcie_100_ext_ssc_ln_vals = { +static const struct cdns_sierra_vals ml_pcie_100_ext_ssc_ln_vals = { .reg_pairs = ml_pcie_100_ext_ssc_ln_regs, .num_regs = ARRAY_SIZE(ml_pcie_100_ext_ssc_ln_regs), }; @@ -2082,7 +2080,7 @@ static const struct cdns_reg_pairs ti_ml_pcie_100_ext_ssc_ln_regs[] = { {0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, {0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG}, {0x0100, SIERRA_DEQ_TAU_CTRL3_PREG}, - {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG}, {0x002B, SIERRA_CPI_TRIM_PREG}, {0x0003, SIERRA_EPI_CTRL_PREG}, {0x803F, SIERRA_SDFILT_H2L_A_PREG}, @@ -2092,7 +2090,7 @@ static const struct cdns_reg_pairs ti_ml_pcie_100_ext_ssc_ln_regs[] = { {0x0002, SIERRA_TX_RCVDET_OVRD_PREG} }; -static struct cdns_sierra_vals ti_ml_pcie_100_ext_ssc_ln_vals = { +static const struct cdns_sierra_vals ti_ml_pcie_100_ext_ssc_ln_vals = { .reg_pairs = ti_ml_pcie_100_ext_ssc_ln_regs, .num_regs = ARRAY_SIZE(ti_ml_pcie_100_ext_ssc_ln_regs), }; @@ -2143,7 +2141,7 @@ static const struct cdns_reg_pairs cdns_pcie_ln_regs_no_ssc[] = { {0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, {0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG}, {0x0100, SIERRA_DEQ_TAU_CTRL3_PREG}, - {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG}, {0x002B, SIERRA_CPI_TRIM_PREG}, {0x0003, SIERRA_EPI_CTRL_PREG}, {0x803F, SIERRA_SDFILT_H2L_A_PREG}, @@ -2152,12 +2150,12 @@ static const struct cdns_reg_pairs cdns_pcie_ln_regs_no_ssc[] = { {0x4432, SIERRA_RXBUFFER_DFECTRL_PREG} }; -static struct cdns_sierra_vals pcie_100_no_ssc_cmn_vals = { +static const struct cdns_sierra_vals pcie_100_no_ssc_cmn_vals = { .reg_pairs = cdns_pcie_cmn_regs_no_ssc, .num_regs = ARRAY_SIZE(cdns_pcie_cmn_regs_no_ssc), }; -static struct cdns_sierra_vals pcie_100_no_ssc_ln_vals = { +static const struct cdns_sierra_vals pcie_100_no_ssc_ln_vals = { .reg_pairs = cdns_pcie_ln_regs_no_ssc, .num_regs = ARRAY_SIZE(cdns_pcie_ln_regs_no_ssc), }; @@ -2218,7 +2216,7 @@ static const struct cdns_reg_pairs cdns_pcie_ln_regs_int_ssc[] = { {0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, {0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG}, {0x0100, SIERRA_DEQ_TAU_CTRL3_PREG}, - {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG}, {0x002B, SIERRA_CPI_TRIM_PREG}, {0x0003, SIERRA_EPI_CTRL_PREG}, {0x803F, SIERRA_SDFILT_H2L_A_PREG}, @@ -2227,12 +2225,12 @@ static const struct cdns_reg_pairs cdns_pcie_ln_regs_int_ssc[] = { {0x4432, SIERRA_RXBUFFER_DFECTRL_PREG} }; -static struct cdns_sierra_vals pcie_100_int_ssc_cmn_vals = { +static const struct cdns_sierra_vals pcie_100_int_ssc_cmn_vals = { .reg_pairs = cdns_pcie_cmn_regs_int_ssc, .num_regs = ARRAY_SIZE(cdns_pcie_cmn_regs_int_ssc), }; -static struct cdns_sierra_vals pcie_100_int_ssc_ln_vals = { +static const struct cdns_sierra_vals pcie_100_int_ssc_ln_vals = { .reg_pairs = cdns_pcie_ln_regs_int_ssc, .num_regs = ARRAY_SIZE(cdns_pcie_ln_regs_int_ssc), }; @@ -2287,7 +2285,7 @@ static const struct cdns_reg_pairs cdns_pcie_ln_regs_ext_ssc[] = { {0x3C0F, SIERRA_DEQ_TAU_CTRL1_SLOW_MAINT_PREG}, {0x1C0C, SIERRA_DEQ_TAU_CTRL2_PREG}, {0x0100, SIERRA_DEQ_TAU_CTRL3_PREG}, - {0x5E82, SIERRA_DEQ_OPENEYE_CTRL_PREG}, + {0x5E82, SIERRA_DEQ_TAU_EPIOFFSET_MODE_PREG}, {0x002B, SIERRA_CPI_TRIM_PREG}, {0x0003, SIERRA_EPI_CTRL_PREG}, {0x803F, SIERRA_SDFILT_H2L_A_PREG}, @@ -2296,12 +2294,12 @@ static const struct cdns_reg_pairs cdns_pcie_ln_regs_ext_ssc[] = { {0x4432, SIERRA_RXBUFFER_DFECTRL_PREG} }; -static struct cdns_sierra_vals pcie_100_ext_ssc_cmn_vals = { +static const struct cdns_sierra_vals pcie_100_ext_ssc_cmn_vals = { .reg_pairs = cdns_pcie_cmn_regs_ext_ssc, .num_regs = ARRAY_SIZE(cdns_pcie_cmn_regs_ext_ssc), }; -static struct cdns_sierra_vals pcie_100_ext_ssc_ln_vals = { +static const struct cdns_sierra_vals pcie_100_ext_ssc_ln_vals = { .reg_pairs = cdns_pcie_ln_regs_ext_ssc, .num_regs = ARRAY_SIZE(cdns_pcie_ln_regs_ext_ssc), }; @@ -2413,12 +2411,12 @@ static const struct cdns_reg_pairs cdns_usb_ln_regs_ext_ssc[] = { {0x4243, SIERRA_RXBUFFER_DFECTRL_PREG} }; -static struct cdns_sierra_vals usb_100_ext_ssc_cmn_vals = { +static const struct cdns_sierra_vals usb_100_ext_ssc_cmn_vals = { .reg_pairs = cdns_usb_cmn_regs_ext_ssc, .num_regs = ARRAY_SIZE(cdns_usb_cmn_regs_ext_ssc), }; -static struct cdns_sierra_vals usb_100_ext_ssc_ln_vals = { +static const struct cdns_sierra_vals usb_100_ext_ssc_ln_vals = { .reg_pairs = cdns_usb_ln_regs_ext_ssc, .num_regs = ARRAY_SIZE(cdns_usb_ln_regs_ext_ssc), }; @@ -2443,7 +2441,7 @@ static const struct cdns_reg_pairs sgmii_pma_cmn_vals[] = { {0x0013, SIERRA_CMN_PLLLC1_DCOCAL_CTRL_PREG}, }; -static struct cdns_sierra_vals sgmii_cmn_vals = { +static const struct cdns_sierra_vals sgmii_cmn_vals = { .reg_pairs = sgmii_pma_cmn_vals, .num_regs = ARRAY_SIZE(sgmii_pma_cmn_vals), }; @@ -2489,7 +2487,7 @@ static const struct cdns_reg_pairs sgmii_ln_regs[] = { {0x321F, SIERRA_CPICAL_RES_STARTCODE_MODE01_PREG}, }; -static struct cdns_sierra_vals sgmii_pma_ln_vals = { +static const struct cdns_sierra_vals sgmii_pma_ln_vals = { .reg_pairs = sgmii_ln_regs, .num_regs = ARRAY_SIZE(sgmii_ln_regs), }; @@ -2733,7 +2731,7 @@ MODULE_DEVICE_TABLE(of, cdns_sierra_id_table); static struct platform_driver cdns_sierra_driver = { .probe = cdns_sierra_phy_probe, - .remove_new = cdns_sierra_phy_remove, + .remove = cdns_sierra_phy_remove, .driver = { .name = "cdns-sierra-phy", .of_match_table = cdns_sierra_id_table, diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index a75c96385c57..a281c0dfae97 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -285,7 +285,7 @@ static const int refclk_driver_parent_index[] = { CDNS_TORRENT_RECEIVED_REFCLK }; -static u32 cdns_torrent_refclk_driver_mux_table[] = { 1, 0 }; +static const u32 cdns_torrent_refclk_driver_mux_table[] = { 1, 0 }; enum cdns_torrent_phy_type { TYPE_NONE, @@ -351,13 +351,17 @@ struct cdns_torrent_phy { void __iomem *sd_base; /* SD0801 registers base */ u32 max_bit_rate; /* Maximum link bit rate to use (in Mbps) */ u32 dp_pll; + u32 protocol_bitmask; struct reset_control *phy_rst; struct reset_control *apb_rst; struct device *dev; struct clk *clk; + struct clk *clk1; enum cdns_torrent_ref_clk ref_clk_rate; + enum cdns_torrent_ref_clk ref_clk1_rate; struct cdns_torrent_inst phys[MAX_NUM_LANES]; int nsubnodes; + int already_configured; const struct cdns_torrent_data *init_data; struct regmap *regmap_common_cdb; struct regmap *regmap_phy_pcs_common_cdb; @@ -419,17 +423,17 @@ struct cdns_reg_pairs { }; struct cdns_torrent_vals { - struct cdns_reg_pairs *reg_pairs; + const struct cdns_reg_pairs *reg_pairs; u32 num_regs; }; struct cdns_torrent_vals_entry { u32 key; - struct cdns_torrent_vals *vals; + const struct cdns_torrent_vals *vals; }; struct cdns_torrent_vals_table { - struct cdns_torrent_vals_entry *entries; + const struct cdns_torrent_vals_entry *entries; u32 num_entries; }; @@ -451,12 +455,12 @@ struct cdns_regmap_cdb_context { u8 reg_offset_shift; }; -static struct cdns_torrent_vals *cdns_torrent_get_tbl_vals(const struct cdns_torrent_vals_table *tbl, - enum cdns_torrent_ref_clk refclk0, - enum cdns_torrent_ref_clk refclk1, - enum cdns_torrent_phy_type link0, - enum cdns_torrent_phy_type link1, - enum cdns_torrent_ssc_mode ssc) +static const struct cdns_torrent_vals *cdns_torrent_get_tbl_vals(const struct cdns_torrent_vals_table *tbl, + enum cdns_torrent_ref_clk refclk0, + enum cdns_torrent_ref_clk refclk1, + enum cdns_torrent_phy_type link0, + enum cdns_torrent_phy_type link1, + enum cdns_torrent_ssc_mode ssc) { int i; u32 key = CDNS_TORRENT_KEY(refclk0, refclk1, link0, link1, ssc); @@ -1154,6 +1158,9 @@ static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy, ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_POWER_STATE_ACK, read_val, (read_val & mask) == value, 0, POLL_TIMEOUT_US); + if (ret) + return ret; + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, 0x00000000); ndelay(100); @@ -1592,6 +1599,9 @@ static int cdns_torrent_dp_configure(struct phy *phy, struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); int ret; + if (cdns_phy->already_configured) + return 0; + ret = cdns_torrent_dp_verify_config(inst, &opts->dp); if (ret) { dev_err(&phy->dev, "invalid params for phy configure\n"); @@ -1627,6 +1637,12 @@ static int cdns_torrent_phy_on(struct phy *phy) u32 read_val; int ret; + if (cdns_phy->already_configured) { + /* Give 5ms to 10ms delay for the PIPE clock to be stable */ + usleep_range(5000, 10000); + return 0; + } + if (cdns_phy->nsubnodes == 1) { /* Take the PHY lane group out of reset */ reset_control_deassert(inst->lnk_rst); @@ -2291,20 +2307,23 @@ static int cdns_torrent_regmap_init(struct cdns_torrent_phy *cdns_phy) static int cdns_torrent_phy_init(struct phy *phy) { struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + const struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals; const struct cdns_torrent_data *init_data = cdns_phy->init_data; - struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals; + const struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals; enum cdns_torrent_ref_clk ref_clk = cdns_phy->ref_clk_rate; - struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals; struct cdns_torrent_inst *inst = phy_get_drvdata(phy); enum cdns_torrent_phy_type phy_type = inst->phy_type; + const struct cdns_torrent_vals *phy_pma_cmn_vals; enum cdns_torrent_ssc_mode ssc = inst->ssc_mode; - struct cdns_torrent_vals *phy_pma_cmn_vals; - struct cdns_torrent_vals *pcs_cmn_vals; - struct cdns_reg_pairs *reg_pairs; + const struct cdns_torrent_vals *pcs_cmn_vals; + const struct cdns_reg_pairs *reg_pairs; struct regmap *regmap; u32 num_regs; int i, j; + if (cdns_phy->already_configured) + return 0; + if (cdns_phy->nsubnodes > 1) { if (phy_type == TYPE_DP) return cdns_torrent_dp_multilink_init(cdns_phy, inst, phy); @@ -2442,166 +2461,219 @@ static const struct phy_ops cdns_torrent_phy_ops = { .owner = THIS_MODULE, }; -static int cdns_torrent_noop_phy_on(struct phy *phy) -{ - /* Give 5ms to 10ms delay for the PIPE clock to be stable */ - usleep_range(5000, 10000); - - return 0; -} - -static const struct phy_ops noop_ops = { - .power_on = cdns_torrent_noop_phy_on, - .owner = THIS_MODULE, -}; - static int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) { + const struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals; const struct cdns_torrent_data *init_data = cdns_phy->init_data; - struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals; + const struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals; + enum cdns_torrent_ref_clk ref_clk1 = cdns_phy->ref_clk1_rate; enum cdns_torrent_ref_clk ref_clk = cdns_phy->ref_clk_rate; - struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals; + const struct cdns_torrent_vals *phy_pma_cmn_vals; + const struct cdns_torrent_vals *pcs_cmn_vals; enum cdns_torrent_phy_type phy_t1, phy_t2; - struct cdns_torrent_vals *pcs_cmn_vals; + const struct cdns_reg_pairs *reg_pairs; int i, j, node, mlane, num_lanes, ret; - struct cdns_reg_pairs *reg_pairs; + struct device *dev = cdns_phy->dev; enum cdns_torrent_ssc_mode ssc; struct regmap *regmap; - u32 num_regs; + u32 num_regs, num_protocols, protocol; - /* Maximum 2 links (subnodes) are supported */ - if (cdns_phy->nsubnodes != 2) + num_protocols = hweight32(cdns_phy->protocol_bitmask); + /* Maximum 2 protocols are supported */ + if (num_protocols > 2) { + dev_err(dev, "at most 2 protocols are supported\n"); return -EINVAL; + } - phy_t1 = cdns_phy->phys[0].phy_type; - phy_t2 = cdns_phy->phys[1].phy_type; /** - * First configure the PHY for first link with phy_t1. Get the array - * values as [phy_t1][phy_t2][ssc]. + * Get PHY types directly from subnodes if only 2 subnodes exist. + * It is possible for phy_t1 to be the same as phy_t2 for special + * configurations such as PCIe Multilink. */ - for (node = 0; node < cdns_phy->nsubnodes; node++) { - if (node == 1) { + if (cdns_phy->nsubnodes == 2) { + phy_t1 = cdns_phy->phys[0].phy_type; + phy_t2 = cdns_phy->phys[1].phy_type; + } else { + /** + * Both PHY types / protocols should be unique. + * If they are the same, it should be expressed with either + * a) Single-Link (1 Sub-node) - handled via PHY APIs + * OR + * b) Double-Link (2 Sub-nodes) - handled above + */ + if (num_protocols != 2) { + dev_err(dev, "incorrect representation of link\n"); + return -EINVAL; + } + + phy_t1 = fns(cdns_phy->protocol_bitmask, 0); + phy_t2 = fns(cdns_phy->protocol_bitmask, 1); + } + + /** + * Configure all links with the protocol phy_t1 first followed by + * configuring all links with the protocol phy_t2. + * + * When phy_t1 = phy_t2, it is a single protocol and configuration + * is performed with a single iteration of the protocol and multiple + * iterations over the sub-nodes (links). + * + * When phy_t1 != phy_t2, there are two protocols and configuration + * is performed by iterating over all sub-nodes matching the first + * protocol and configuring them first, followed by iterating over + * all sub-nodes matching the second protocol and configuring them + * next. + */ + for (protocol = 0; protocol < num_protocols; protocol++) { + /** + * For the case where num_protocols is 1, + * phy_t1 = phy_t2 and the swap is unnecessary. + * + * Swapping phy_t1 and phy_t2 is only required when the + * number of protocols is 2 and there are 2 or more links. + */ + if (protocol == 1) { /** - * If first link with phy_t1 is configured, then - * configure the PHY for second link with phy_t2. + * If first protocol with phy_t1 is configured, then + * configure the PHY for second protocol with phy_t2. * Get the array values as [phy_t2][phy_t1][ssc]. */ swap(phy_t1, phy_t2); + swap(ref_clk, ref_clk1); } - mlane = cdns_phy->phys[node].mlane; - ssc = cdns_phy->phys[node].ssc_mode; - num_lanes = cdns_phy->phys[node].num_lanes; + for (node = 0; node < cdns_phy->nsubnodes; node++) { + if (cdns_phy->phys[node].phy_type != phy_t1) + continue; - /** - * PHY configuration specific registers: - * link_cmn_vals depend on combination of PHY types being - * configured and are common for both PHY types, so array - * values should be same for [phy_t1][phy_t2][ssc] and - * [phy_t2][phy_t1][ssc]. - * xcvr_diag_vals also depend on combination of PHY types - * being configured, but these can be different for particular - * PHY type and are per lane. - */ - link_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_tbl, - CLK_ANY, CLK_ANY, - phy_t1, phy_t2, ANY_SSC); - if (link_cmn_vals) { - reg_pairs = link_cmn_vals->reg_pairs; - num_regs = link_cmn_vals->num_regs; - regmap = cdns_phy->regmap_common_cdb; + mlane = cdns_phy->phys[node].mlane; + ssc = cdns_phy->phys[node].ssc_mode; + num_lanes = cdns_phy->phys[node].num_lanes; /** - * First array value in link_cmn_vals must be of - * PHY_PLL_CFG register + * PHY configuration specific registers: + * link_cmn_vals depend on combination of PHY types being + * configured and are common for both PHY types, so array + * values should be same for [phy_t1][phy_t2][ssc] and + * [phy_t2][phy_t1][ssc]. + * xcvr_diag_vals also depend on combination of PHY types + * being configured, but these can be different for particular + * PHY type and are per lane. */ - regmap_field_write(cdns_phy->phy_pll_cfg, - reg_pairs[0].val); + link_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->link_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); + if (link_cmn_vals) { + reg_pairs = link_cmn_vals->reg_pairs; + num_regs = link_cmn_vals->num_regs; + regmap = cdns_phy->regmap_common_cdb; + + /** + * First array value in link_cmn_vals must be of + * PHY_PLL_CFG register + */ + regmap_field_write(cdns_phy->phy_pll_cfg, + reg_pairs[0].val); + + for (i = 1; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } - for (i = 1; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + xcvr_diag_vals = cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals_tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); + if (xcvr_diag_vals) { + reg_pairs = xcvr_diag_vals->reg_pairs; + num_regs = xcvr_diag_vals->num_regs; + for (i = 0; i < num_lanes; i++) { + regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; + for (j = 0; j < num_regs; j++) + regmap_write(regmap, reg_pairs[j].off, + reg_pairs[j].val); + } + } - xcvr_diag_vals = cdns_torrent_get_tbl_vals(&init_data->xcvr_diag_vals_tbl, - CLK_ANY, CLK_ANY, - phy_t1, phy_t2, ANY_SSC); - if (xcvr_diag_vals) { - reg_pairs = xcvr_diag_vals->reg_pairs; - num_regs = xcvr_diag_vals->num_regs; - for (i = 0; i < num_lanes; i++) { - regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; - for (j = 0; j < num_regs; j++) - regmap_write(regmap, reg_pairs[j].off, - reg_pairs[j].val); + /* PHY PCS common registers configurations */ + pcs_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl, + CLK_ANY, CLK_ANY, + phy_t1, phy_t2, ANY_SSC); + if (pcs_cmn_vals) { + reg_pairs = pcs_cmn_vals->reg_pairs; + num_regs = pcs_cmn_vals->num_regs; + regmap = cdns_phy->regmap_phy_pcs_common_cdb; + for (i = 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); } - } - /* PHY PCS common registers configurations */ - pcs_cmn_vals = cdns_torrent_get_tbl_vals(&init_data->pcs_cmn_vals_tbl, - CLK_ANY, CLK_ANY, - phy_t1, phy_t2, ANY_SSC); - if (pcs_cmn_vals) { - reg_pairs = pcs_cmn_vals->reg_pairs; - num_regs = pcs_cmn_vals->num_regs; - regmap = cdns_phy->regmap_phy_pcs_common_cdb; - for (i = 0; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + /* PHY PMA common registers configurations */ + phy_pma_cmn_vals = + cdns_torrent_get_tbl_vals(&init_data->phy_pma_cmn_vals_tbl, + CLK_ANY, CLK_ANY, phy_t1, phy_t2, + ANY_SSC); + if (phy_pma_cmn_vals) { + reg_pairs = phy_pma_cmn_vals->reg_pairs; + num_regs = phy_pma_cmn_vals->num_regs; + regmap = cdns_phy->regmap_phy_pma_common_cdb; + for (i = 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } - /* PMA common registers configurations */ - cmn_vals = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, - ref_clk, ref_clk, - phy_t1, phy_t2, ssc); - if (cmn_vals) { - reg_pairs = cmn_vals->reg_pairs; - num_regs = cmn_vals->num_regs; - regmap = cdns_phy->regmap_common_cdb; - for (i = 0; i < num_regs; i++) - regmap_write(regmap, reg_pairs[i].off, - reg_pairs[i].val); - } + /* PMA common registers configurations */ + cmn_vals = cdns_torrent_get_tbl_vals(&init_data->cmn_vals_tbl, + ref_clk, ref_clk1, + phy_t1, phy_t2, ssc); + if (cmn_vals) { + reg_pairs = cmn_vals->reg_pairs; + num_regs = cmn_vals->num_regs; + regmap = cdns_phy->regmap_common_cdb; + for (i = 0; i < num_regs; i++) + regmap_write(regmap, reg_pairs[i].off, + reg_pairs[i].val); + } - /* PMA TX lane registers configurations */ - tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, - ref_clk, ref_clk, - phy_t1, phy_t2, ssc); - if (tx_ln_vals) { - reg_pairs = tx_ln_vals->reg_pairs; - num_regs = tx_ln_vals->num_regs; - for (i = 0; i < num_lanes; i++) { - regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; - for (j = 0; j < num_regs; j++) - regmap_write(regmap, reg_pairs[j].off, - reg_pairs[j].val); + /* PMA TX lane registers configurations */ + tx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->tx_ln_vals_tbl, + ref_clk, ref_clk1, + phy_t1, phy_t2, ssc); + if (tx_ln_vals) { + reg_pairs = tx_ln_vals->reg_pairs; + num_regs = tx_ln_vals->num_regs; + for (i = 0; i < num_lanes; i++) { + regmap = cdns_phy->regmap_tx_lane_cdb[i + mlane]; + for (j = 0; j < num_regs; j++) + regmap_write(regmap, reg_pairs[j].off, + reg_pairs[j].val); + } } - } - /* PMA RX lane registers configurations */ - rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, - ref_clk, ref_clk, - phy_t1, phy_t2, ssc); - if (rx_ln_vals) { - reg_pairs = rx_ln_vals->reg_pairs; - num_regs = rx_ln_vals->num_regs; - for (i = 0; i < num_lanes; i++) { - regmap = cdns_phy->regmap_rx_lane_cdb[i + mlane]; - for (j = 0; j < num_regs; j++) - regmap_write(regmap, reg_pairs[j].off, - reg_pairs[j].val); + /* PMA RX lane registers configurations */ + rx_ln_vals = cdns_torrent_get_tbl_vals(&init_data->rx_ln_vals_tbl, + ref_clk, ref_clk1, + phy_t1, phy_t2, ssc); + if (rx_ln_vals) { + reg_pairs = rx_ln_vals->reg_pairs; + num_regs = rx_ln_vals->num_regs; + for (i = 0; i < num_lanes; i++) { + regmap = cdns_phy->regmap_rx_lane_cdb[i + mlane]; + for (j = 0; j < num_regs; j++) + regmap_write(regmap, reg_pairs[j].off, + reg_pairs[j].val); + } } - } - if (phy_t1 == TYPE_DP) { - ret = cdns_torrent_dp_get_pll(cdns_phy, phy_t2); - if (ret) - return ret; - } + if (phy_t1 == TYPE_DP) { + ret = cdns_torrent_dp_get_pll(cdns_phy, phy_t2); + if (ret) + return ret; + } - reset_control_deassert(cdns_phy->phys[node].lnk_rst); + reset_control_deassert(cdns_phy->phys[node].lnk_rst); + } } /* Take the PHY out of reset */ @@ -2660,7 +2732,7 @@ static int cdns_torrent_clk_register(struct cdns_torrent_phy *cdns_phy) return 0; } -static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy) +static int cdns_torrent_of_get_reset(struct cdns_torrent_phy *cdns_phy) { struct device *dev = cdns_phy->dev; @@ -2681,29 +2753,40 @@ static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy) return 0; } +static int cdns_torrent_of_get_clk(struct cdns_torrent_phy *cdns_phy) +{ + /* refclk: Input reference clock for PLL0 */ + cdns_phy->clk = devm_clk_get(cdns_phy->dev, "refclk"); + if (IS_ERR(cdns_phy->clk)) + return dev_err_probe(cdns_phy->dev, PTR_ERR(cdns_phy->clk), + "phy ref clock not found\n"); + + /* refclk1: Input reference clock for PLL1 */ + cdns_phy->clk1 = devm_clk_get_optional(cdns_phy->dev, "pll1_refclk"); + if (IS_ERR(cdns_phy->clk1)) + return dev_err_probe(cdns_phy->dev, PTR_ERR(cdns_phy->clk1), + "phy PLL1 ref clock not found\n"); + + return 0; +} + static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) { - struct device *dev = cdns_phy->dev; + unsigned long ref_clk1_rate; unsigned long ref_clk_rate; int ret; - cdns_phy->clk = devm_clk_get(dev, "refclk"); - if (IS_ERR(cdns_phy->clk)) { - dev_err(dev, "phy ref clock not found\n"); - return PTR_ERR(cdns_phy->clk); - } - ret = clk_prepare_enable(cdns_phy->clk); if (ret) { - dev_err(cdns_phy->dev, "Failed to prepare ref clock\n"); + dev_err(cdns_phy->dev, "Failed to prepare ref clock: %d\n", ret); return ret; } ref_clk_rate = clk_get_rate(cdns_phy->clk); if (!ref_clk_rate) { dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); - clk_disable_unprepare(cdns_phy->clk); - return -EINVAL; + ret = -EINVAL; + goto disable_clk; } switch (ref_clk_rate) { @@ -2720,12 +2803,54 @@ static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) cdns_phy->ref_clk_rate = CLK_156_25_MHZ; break; default: - dev_err(cdns_phy->dev, "Invalid Ref Clock Rate\n"); - clk_disable_unprepare(cdns_phy->clk); - return -EINVAL; + dev_err(cdns_phy->dev, "Invalid ref clock rate\n"); + ret = -EINVAL; + goto disable_clk; + } + + if (cdns_phy->clk1) { + ret = clk_prepare_enable(cdns_phy->clk1); + if (ret) { + dev_err(cdns_phy->dev, "Failed to prepare PLL1 ref clock: %d\n", ret); + goto disable_clk; + } + + ref_clk1_rate = clk_get_rate(cdns_phy->clk1); + if (!ref_clk1_rate) { + dev_err(cdns_phy->dev, "Failed to get PLL1 ref clock rate\n"); + ret = -EINVAL; + goto disable_clk1; + } + + switch (ref_clk1_rate) { + case REF_CLK_19_2MHZ: + cdns_phy->ref_clk1_rate = CLK_19_2_MHZ; + break; + case REF_CLK_25MHZ: + cdns_phy->ref_clk1_rate = CLK_25_MHZ; + break; + case REF_CLK_100MHZ: + cdns_phy->ref_clk1_rate = CLK_100_MHZ; + break; + case REF_CLK_156_25MHZ: + cdns_phy->ref_clk1_rate = CLK_156_25_MHZ; + break; + default: + dev_err(cdns_phy->dev, "Invalid PLL1 ref clock rate\n"); + ret = -EINVAL; + goto disable_clk1; + } + } else { + cdns_phy->ref_clk1_rate = cdns_phy->ref_clk_rate; } return 0; + +disable_clk1: + clk_disable_unprepare(cdns_phy->clk1); +disable_clk: + clk_disable_unprepare(cdns_phy->clk); + return ret; } static int cdns_torrent_phy_probe(struct platform_device *pdev) @@ -2737,7 +2862,6 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) struct device_node *child; int ret, subnodes, node = 0, i; u32 total_num_lanes = 0; - int already_configured; u8 init_dp_regmap = 0; u32 phy_type; @@ -2753,6 +2877,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) dev_set_drvdata(dev, cdns_phy); cdns_phy->dev = dev; cdns_phy->init_data = data; + cdns_phy->protocol_bitmask = 0; cdns_phy->sd_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cdns_phy->sd_base)) @@ -2776,13 +2901,17 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) if (ret) return ret; - regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &already_configured); + ret = cdns_torrent_of_get_reset(cdns_phy); + if (ret) + goto clk_cleanup; - if (!already_configured) { - ret = cdns_torrent_reset(cdns_phy); - if (ret) - goto clk_cleanup; + ret = cdns_torrent_of_get_clk(cdns_phy); + if (ret) + goto clk_cleanup; + + regmap_field_read(cdns_phy->phy_pma_cmn_ctrl_1, &cdns_phy->already_configured); + if (!cdns_phy->already_configured) { ret = cdns_torrent_clk(cdns_phy); if (ret) goto clk_cleanup; @@ -2862,10 +2991,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) of_property_read_u32(child, "cdns,ssc-mode", &cdns_phy->phys[node].ssc_mode); - if (!already_configured) - gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops); - else - gphy = devm_phy_create(dev, child, &noop_ops); + gphy = devm_phy_create(dev, child, &cdns_torrent_phy_ops); if (IS_ERR(gphy)) { ret = PTR_ERR(gphy); goto put_child; @@ -2936,6 +3062,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) } cdns_phy->phys[node].phy = gphy; + cdns_phy->protocol_bitmask |= BIT(cdns_phy->phys[node].phy_type); phy_set_drvdata(gphy, &cdns_phy->phys[node]); node++; @@ -2948,7 +3075,7 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) goto put_lnk_rst; } - if (cdns_phy->nsubnodes > 1 && !already_configured) { + if (cdns_phy->nsubnodes > 1 && !cdns_phy->already_configured) { ret = cdns_torrent_phy_configure_multilink(cdns_phy); if (ret) goto put_lnk_rst; @@ -2980,6 +3107,7 @@ put_lnk_rst: reset_control_put(cdns_phy->phys[i].lnk_rst); of_node_put(child); reset_control_assert(cdns_phy->apb_rst); + clk_disable_unprepare(cdns_phy->clk1); clk_disable_unprepare(cdns_phy->clk); clk_cleanup: cdns_torrent_clk_cleanup(cdns_phy); @@ -2998,76 +3126,363 @@ static void cdns_torrent_phy_remove(struct platform_device *pdev) reset_control_put(cdns_phy->phys[i].lnk_rst); } + clk_disable_unprepare(cdns_phy->clk1); clk_disable_unprepare(cdns_phy->clk); cdns_torrent_clk_cleanup(cdns_phy); } +/* SGMII and QSGMII link configuration */ +static const struct cdns_reg_pairs sgmii_qsgmii_link_cmn_regs[] = { + {0x0002, PHY_PLL_CFG} +}; + +static const struct cdns_reg_pairs sgmii_qsgmii_xcvr_diag_ln_regs[] = { + {0x0003, XCVR_DIAG_HSCLK_DIV}, + {0x0113, XCVR_DIAG_PLLDRC_CTRL} +}; + +static const struct cdns_torrent_vals sgmii_qsgmii_link_cmn_vals = { + .reg_pairs = sgmii_qsgmii_link_cmn_regs, + .num_regs = ARRAY_SIZE(sgmii_qsgmii_link_cmn_regs), +}; + +static const struct cdns_torrent_vals sgmii_qsgmii_xcvr_diag_ln_vals = { + .reg_pairs = sgmii_qsgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(sgmii_qsgmii_xcvr_diag_ln_regs), +}; + +static int cdns_torrent_phy_suspend_noirq(struct device *dev) +{ + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(dev); + int i; + + reset_control_assert(cdns_phy->phy_rst); + reset_control_assert(cdns_phy->apb_rst); + for (i = 0; i < cdns_phy->nsubnodes; i++) + reset_control_assert(cdns_phy->phys[i].lnk_rst); + + if (cdns_phy->already_configured) + cdns_phy->already_configured = 0; + else { + clk_disable_unprepare(cdns_phy->clk1); + clk_disable_unprepare(cdns_phy->clk); + } + + return 0; +} + +static int cdns_torrent_phy_resume_noirq(struct device *dev) +{ + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(dev); + int node = cdns_phy->nsubnodes; + int ret, i; + + ret = cdns_torrent_clk(cdns_phy); + if (ret) + return ret; + + /* Enable APB */ + reset_control_deassert(cdns_phy->apb_rst); + + if (cdns_phy->nsubnodes > 1) { + ret = cdns_torrent_phy_configure_multilink(cdns_phy); + if (ret) + goto put_lnk_rst; + } + + return 0; + +put_lnk_rst: + for (i = 0; i < node; i++) + reset_control_assert(cdns_phy->phys[i].lnk_rst); + reset_control_assert(cdns_phy->apb_rst); + + clk_disable_unprepare(cdns_phy->clk1); + clk_disable_unprepare(cdns_phy->clk); + + return ret; +} + +static DEFINE_NOIRQ_DEV_PM_OPS(cdns_torrent_phy_pm_ops, + cdns_torrent_phy_suspend_noirq, + cdns_torrent_phy_resume_noirq); + /* USB and DP link configuration */ -static struct cdns_reg_pairs usb_dp_link_cmn_regs[] = { +static const struct cdns_reg_pairs usb_dp_link_cmn_regs[] = { {0x0002, PHY_PLL_CFG}, {0x8600, CMN_PDIAG_PLL0_CLK_SEL_M0} }; -static struct cdns_reg_pairs usb_dp_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs usb_dp_xcvr_diag_ln_regs[] = { {0x0000, XCVR_DIAG_HSCLK_SEL}, {0x0001, XCVR_DIAG_HSCLK_DIV}, {0x0041, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_reg_pairs dp_usb_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs dp_usb_xcvr_diag_ln_regs[] = { {0x0001, XCVR_DIAG_HSCLK_SEL}, {0x0009, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_torrent_vals usb_dp_link_cmn_vals = { +static const struct cdns_torrent_vals usb_dp_link_cmn_vals = { .reg_pairs = usb_dp_link_cmn_regs, .num_regs = ARRAY_SIZE(usb_dp_link_cmn_regs), }; -static struct cdns_torrent_vals usb_dp_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals usb_dp_xcvr_diag_ln_vals = { .reg_pairs = usb_dp_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(usb_dp_xcvr_diag_ln_regs), }; -static struct cdns_torrent_vals dp_usb_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals dp_usb_xcvr_diag_ln_vals = { .reg_pairs = dp_usb_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(dp_usb_xcvr_diag_ln_regs), }; +/* USXGMII and SGMII/QSGMII link configuration */ +static const struct cdns_reg_pairs usxgmii_sgmii_link_cmn_regs[] = { + {0x0002, PHY_PLL_CFG}, + {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M0}, + {0x0601, CMN_PDIAG_PLL1_CLK_SEL_M0} +}; + +static const struct cdns_reg_pairs usxgmii_sgmii_xcvr_diag_ln_regs[] = { + {0x0000, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0001, XCVR_DIAG_PLLDRC_CTRL} +}; + +static const struct cdns_reg_pairs sgmii_usxgmii_xcvr_diag_ln_regs[] = { + {0x0111, XCVR_DIAG_HSCLK_SEL}, + {0x0103, XCVR_DIAG_HSCLK_DIV}, + {0x0A9B, XCVR_DIAG_PLLDRC_CTRL} +}; + +static const struct cdns_torrent_vals usxgmii_sgmii_link_cmn_vals = { + .reg_pairs = usxgmii_sgmii_link_cmn_regs, + .num_regs = ARRAY_SIZE(usxgmii_sgmii_link_cmn_regs), +}; + +static const struct cdns_torrent_vals usxgmii_sgmii_xcvr_diag_ln_vals = { + .reg_pairs = usxgmii_sgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(usxgmii_sgmii_xcvr_diag_ln_regs), +}; + +static const struct cdns_torrent_vals sgmii_usxgmii_xcvr_diag_ln_vals = { + .reg_pairs = sgmii_usxgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(sgmii_usxgmii_xcvr_diag_ln_regs), +}; + +/* Multilink USXGMII, using PLL0, 156.25 MHz Ref clk, no SSC */ +static const struct cdns_reg_pairs ml_usxgmii_pll0_156_25_no_ssc_cmn_regs[] = { + {0x0014, CMN_PLL0_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL0_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL0_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL0_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL0_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0138, CMN_PLL0_LOCK_REFCNT_START}, + {0x0138, CMN_PLL0_LOCK_PLLCNT_START} +}; + +static const struct cdns_torrent_vals ml_usxgmii_pll0_156_25_no_ssc_cmn_vals = { + .reg_pairs = ml_usxgmii_pll0_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_pll0_156_25_no_ssc_cmn_regs), +}; + +/* Multilink SGMII/QSGMII, using PLL1, 100 MHz Ref clk, no SSC */ +static const struct cdns_reg_pairs ml_sgmii_pll1_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + +static const struct cdns_torrent_vals ml_sgmii_pll1_100_no_ssc_cmn_vals = { + .reg_pairs = ml_sgmii_pll1_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_sgmii_pll1_100_no_ssc_cmn_regs), +}; + +/* TI J7200, Multilink USXGMII, using PLL0, 156.25 MHz Ref clk, no SSC */ +static const struct cdns_reg_pairs j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_regs[] = { + {0x0014, CMN_SSM_BIAS_TMR}, + {0x0028, CMN_PLLSM0_PLLPRE_TMR}, + {0x00A4, CMN_PLLSM0_PLLLOCK_TMR}, + {0x0062, CMN_BGCAL_INIT_TMR}, + {0x0062, CMN_BGCAL_ITER_TMR}, + {0x0014, CMN_IBCAL_INIT_TMR}, + {0x0018, CMN_TXPUCAL_INIT_TMR}, + {0x0005, CMN_TXPUCAL_ITER_TMR}, + {0x0018, CMN_TXPDCAL_INIT_TMR}, + {0x0005, CMN_TXPDCAL_ITER_TMR}, + {0x024A, CMN_RXCAL_INIT_TMR}, + {0x0005, CMN_RXCAL_ITER_TMR}, + {0x000B, CMN_SD_CAL_REFTIM_START}, + {0x0132, CMN_SD_CAL_PLLCNT_START}, + {0x0014, CMN_PLL0_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL0_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL0_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL0_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL0_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0138, CMN_PLL0_LOCK_REFCNT_START}, + {0x0138, CMN_PLL0_LOCK_PLLCNT_START} +}; + +static const struct cdns_torrent_vals j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_vals = { + .reg_pairs = j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_regs), +}; + +/* TI J7200, Multilink SGMII/QSGMII, using PLL1, 100 MHz Ref clk, no SSC */ +static const struct cdns_reg_pairs j7200_ml_sgmii_pll1_100_no_ssc_cmn_regs[] = { + {0x0028, CMN_PLLSM1_PLLPRE_TMR}, + {0x00A4, CMN_PLLSM1_PLLLOCK_TMR}, + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + +static const struct cdns_torrent_vals j7200_ml_sgmii_pll1_100_no_ssc_cmn_vals = { + .reg_pairs = j7200_ml_sgmii_pll1_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(j7200_ml_sgmii_pll1_100_no_ssc_cmn_regs), +}; + +/* PCIe and USXGMII link configuration */ +static const struct cdns_reg_pairs pcie_usxgmii_link_cmn_regs[] = { + {0x0003, PHY_PLL_CFG}, + {0x0601, CMN_PDIAG_PLL0_CLK_SEL_M0}, + {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M1}, + {0x0400, CMN_PDIAG_PLL1_CLK_SEL_M0} +}; + +static const struct cdns_reg_pairs pcie_usxgmii_xcvr_diag_ln_regs[] = { + {0x0000, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0012, XCVR_DIAG_PLLDRC_CTRL} +}; + +static const struct cdns_reg_pairs usxgmii_pcie_xcvr_diag_ln_regs[] = { + {0x0011, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_HSCLK_DIV}, + {0x0089, XCVR_DIAG_PLLDRC_CTRL} +}; + +static const struct cdns_torrent_vals pcie_usxgmii_link_cmn_vals = { + .reg_pairs = pcie_usxgmii_link_cmn_regs, + .num_regs = ARRAY_SIZE(pcie_usxgmii_link_cmn_regs), +}; + +static const struct cdns_torrent_vals pcie_usxgmii_xcvr_diag_ln_vals = { + .reg_pairs = pcie_usxgmii_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(pcie_usxgmii_xcvr_diag_ln_regs), +}; + +static const struct cdns_torrent_vals usxgmii_pcie_xcvr_diag_ln_vals = { + .reg_pairs = usxgmii_pcie_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(usxgmii_pcie_xcvr_diag_ln_regs), +}; + +/* + * Multilink USXGMII, using PLL1, 156.25 MHz Ref clk, no SSC + */ +static const struct cdns_reg_pairs ml_usxgmii_pll1_156_25_no_ssc_cmn_regs[] = { + {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x0014, CMN_PLL1_DSM_FBH_OVRD_M0}, + {0x0005, CMN_PLL1_DSM_FBL_OVRD_M0}, + {0x061B, CMN_PLL1_VCOCAL_INIT_TMR}, + {0x0019, CMN_PLL1_VCOCAL_ITER_TMR}, + {0x1354, CMN_PLL1_VCOCAL_REFTIM_START}, + {0x1354, CMN_PLL1_VCOCAL_PLLCNT_START}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL}, + {0x0138, CMN_PLL1_LOCK_REFCNT_START}, + {0x0138, CMN_PLL1_LOCK_PLLCNT_START}, + {0x007F, CMN_TXPUCAL_TUNE}, + {0x007F, CMN_TXPDCAL_TUNE} +}; + +static const struct cdns_reg_pairs ml_usxgmii_156_25_no_ssc_tx_ln_regs[] = { + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3 }, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x0000, XCVR_DIAG_PSC_OVRD} +}; + +static const struct cdns_reg_pairs ml_usxgmii_156_25_no_ssc_rx_ln_regs[] = { + {0x091D, RX_PSC_A0}, + {0x0900, RX_PSC_A2}, + {0x0100, RX_PSC_A3}, + {0x0030, RX_REE_SMGM_CTRL1}, + {0x03C7, RX_REE_GCSM1_EQENM_PH1}, + {0x01C7, RX_REE_GCSM1_EQENM_PH2}, + {0x0000, RX_DIAG_DFE_CTRL}, + {0x0019, RX_REE_TAP1_CLIP}, + {0x0019, RX_REE_TAP2TON_CLIP}, + {0x00B9, RX_DIAG_NQST_CTRL}, + {0x0C21, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0002, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0033, RX_DIAG_PI_RATE}, + {0x0001, RX_DIAG_ACYA}, + {0x018C, RX_CDRLF_CNFG} +}; + +static const struct cdns_torrent_vals ml_usxgmii_pll1_156_25_no_ssc_cmn_vals = { + .reg_pairs = ml_usxgmii_pll1_156_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_pll1_156_25_no_ssc_cmn_regs), +}; + +static const struct cdns_torrent_vals ml_usxgmii_156_25_no_ssc_tx_ln_vals = { + .reg_pairs = ml_usxgmii_156_25_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_156_25_no_ssc_tx_ln_regs), +}; + +static const struct cdns_torrent_vals ml_usxgmii_156_25_no_ssc_rx_ln_vals = { + .reg_pairs = ml_usxgmii_156_25_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(ml_usxgmii_156_25_no_ssc_rx_ln_regs), +}; + /* TI USXGMII configuration: Enable cmn_refclk_rcv_out_en */ -static struct cdns_reg_pairs ti_usxgmii_phy_pma_cmn_regs[] = { +static const struct cdns_reg_pairs ti_usxgmii_phy_pma_cmn_regs[] = { {0x0040, PHY_PMA_CMN_CTRL1}, }; -static struct cdns_torrent_vals ti_usxgmii_phy_pma_cmn_vals = { +static const struct cdns_torrent_vals ti_usxgmii_phy_pma_cmn_vals = { .reg_pairs = ti_usxgmii_phy_pma_cmn_regs, .num_regs = ARRAY_SIZE(ti_usxgmii_phy_pma_cmn_regs), }; /* Single USXGMII link configuration */ -static struct cdns_reg_pairs sl_usxgmii_link_cmn_regs[] = { +static const struct cdns_reg_pairs sl_usxgmii_link_cmn_regs[] = { {0x0000, PHY_PLL_CFG}, {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M0} }; -static struct cdns_reg_pairs sl_usxgmii_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs sl_usxgmii_xcvr_diag_ln_regs[] = { {0x0000, XCVR_DIAG_HSCLK_SEL}, {0x0001, XCVR_DIAG_HSCLK_DIV}, {0x0001, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_torrent_vals sl_usxgmii_link_cmn_vals = { +static const struct cdns_torrent_vals sl_usxgmii_link_cmn_vals = { .reg_pairs = sl_usxgmii_link_cmn_regs, .num_regs = ARRAY_SIZE(sl_usxgmii_link_cmn_regs), }; -static struct cdns_torrent_vals sl_usxgmii_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals sl_usxgmii_xcvr_diag_ln_vals = { .reg_pairs = sl_usxgmii_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(sl_usxgmii_xcvr_diag_ln_regs), }; /* Single link USXGMII, 156.25 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs sl_usxgmii_156_25_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sl_usxgmii_156_25_no_ssc_cmn_regs[] = { {0x0014, CMN_SSM_BIAS_TMR}, {0x0028, CMN_PLLSM0_PLLPRE_TMR}, {0x00A4, CMN_PLLSM0_PLLLOCK_TMR}, @@ -3105,7 +3520,7 @@ static struct cdns_reg_pairs sl_usxgmii_156_25_no_ssc_cmn_regs[] = { {0x0138, CMN_PLL1_LOCK_PLLCNT_START} }; -static struct cdns_reg_pairs usxgmii_156_25_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs usxgmii_156_25_no_ssc_tx_ln_regs[] = { {0x07A2, TX_RCVDET_ST_TMR}, {0x00F3, TX_PSC_A0}, {0x04A2, TX_PSC_A2}, @@ -3114,7 +3529,7 @@ static struct cdns_reg_pairs usxgmii_156_25_no_ssc_tx_ln_regs[] = { {0x0000, XCVR_DIAG_PSC_OVRD} }; -static struct cdns_reg_pairs usxgmii_156_25_no_ssc_rx_ln_regs[] = { +static const struct cdns_reg_pairs usxgmii_156_25_no_ssc_rx_ln_regs[] = { {0x0014, RX_SDCAL0_INIT_TMR}, {0x0062, RX_SDCAL0_ITER_TMR}, {0x0014, RX_SDCAL1_INIT_TMR}, @@ -3136,68 +3551,68 @@ static struct cdns_reg_pairs usxgmii_156_25_no_ssc_rx_ln_regs[] = { {0x018C, RX_CDRLF_CNFG} }; -static struct cdns_torrent_vals sl_usxgmii_156_25_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals sl_usxgmii_156_25_no_ssc_cmn_vals = { .reg_pairs = sl_usxgmii_156_25_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sl_usxgmii_156_25_no_ssc_cmn_regs), }; -static struct cdns_torrent_vals usxgmii_156_25_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals usxgmii_156_25_no_ssc_tx_ln_vals = { .reg_pairs = usxgmii_156_25_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(usxgmii_156_25_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals usxgmii_156_25_no_ssc_rx_ln_vals = { +static const struct cdns_torrent_vals usxgmii_156_25_no_ssc_rx_ln_vals = { .reg_pairs = usxgmii_156_25_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(usxgmii_156_25_no_ssc_rx_ln_regs), }; /* PCIe and DP link configuration */ -static struct cdns_reg_pairs pcie_dp_link_cmn_regs[] = { +static const struct cdns_reg_pairs pcie_dp_link_cmn_regs[] = { {0x0003, PHY_PLL_CFG}, {0x0601, CMN_PDIAG_PLL0_CLK_SEL_M0}, {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M1} }; -static struct cdns_reg_pairs pcie_dp_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs pcie_dp_xcvr_diag_ln_regs[] = { {0x0000, XCVR_DIAG_HSCLK_SEL}, {0x0001, XCVR_DIAG_HSCLK_DIV}, {0x0012, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_reg_pairs dp_pcie_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs dp_pcie_xcvr_diag_ln_regs[] = { {0x0001, XCVR_DIAG_HSCLK_SEL}, {0x0009, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_torrent_vals pcie_dp_link_cmn_vals = { +static const struct cdns_torrent_vals pcie_dp_link_cmn_vals = { .reg_pairs = pcie_dp_link_cmn_regs, .num_regs = ARRAY_SIZE(pcie_dp_link_cmn_regs), }; -static struct cdns_torrent_vals pcie_dp_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals pcie_dp_xcvr_diag_ln_vals = { .reg_pairs = pcie_dp_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(pcie_dp_xcvr_diag_ln_regs), }; -static struct cdns_torrent_vals dp_pcie_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals dp_pcie_xcvr_diag_ln_vals = { .reg_pairs = dp_pcie_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(dp_pcie_xcvr_diag_ln_regs), }; /* DP Multilink, 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs dp_100_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs dp_100_no_ssc_cmn_regs[] = { {0x007F, CMN_TXPUCAL_TUNE}, {0x007F, CMN_TXPDCAL_TUNE} }; -static struct cdns_reg_pairs dp_100_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs dp_100_no_ssc_tx_ln_regs[] = { {0x00FB, TX_PSC_A0}, {0x04AA, TX_PSC_A2}, {0x04AA, TX_PSC_A3}, {0x000F, XCVR_DIAG_BIDI_CTRL} }; -static struct cdns_reg_pairs dp_100_no_ssc_rx_ln_regs[] = { +static const struct cdns_reg_pairs dp_100_no_ssc_rx_ln_regs[] = { {0x0000, RX_PSC_A0}, {0x0000, RX_PSC_A2}, {0x0000, RX_PSC_A3}, @@ -3207,43 +3622,43 @@ static struct cdns_reg_pairs dp_100_no_ssc_rx_ln_regs[] = { {0x0000, RX_REE_PERGCSM_CTRL} }; -static struct cdns_torrent_vals dp_100_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals dp_100_no_ssc_cmn_vals = { .reg_pairs = dp_100_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(dp_100_no_ssc_cmn_regs), }; -static struct cdns_torrent_vals dp_100_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals dp_100_no_ssc_tx_ln_vals = { .reg_pairs = dp_100_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(dp_100_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals dp_100_no_ssc_rx_ln_vals = { +static const struct cdns_torrent_vals dp_100_no_ssc_rx_ln_vals = { .reg_pairs = dp_100_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(dp_100_no_ssc_rx_ln_regs), }; /* Single DisplayPort(DP) link configuration */ -static struct cdns_reg_pairs sl_dp_link_cmn_regs[] = { +static const struct cdns_reg_pairs sl_dp_link_cmn_regs[] = { {0x0000, PHY_PLL_CFG}, }; -static struct cdns_reg_pairs sl_dp_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs sl_dp_xcvr_diag_ln_regs[] = { {0x0000, XCVR_DIAG_HSCLK_SEL}, {0x0001, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_torrent_vals sl_dp_link_cmn_vals = { +static const struct cdns_torrent_vals sl_dp_link_cmn_vals = { .reg_pairs = sl_dp_link_cmn_regs, .num_regs = ARRAY_SIZE(sl_dp_link_cmn_regs), }; -static struct cdns_torrent_vals sl_dp_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals sl_dp_xcvr_diag_ln_vals = { .reg_pairs = sl_dp_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(sl_dp_xcvr_diag_ln_regs), }; /* Single DP, 19.2 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs sl_dp_19_2_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sl_dp_19_2_no_ssc_cmn_regs[] = { {0x0014, CMN_SSM_BIAS_TMR}, {0x0027, CMN_PLLSM0_PLLPRE_TMR}, {0x00A1, CMN_PLLSM0_PLLLOCK_TMR}, @@ -3280,7 +3695,7 @@ static struct cdns_reg_pairs sl_dp_19_2_no_ssc_cmn_regs[] = { {0x0003, CMN_PLL1_VCOCAL_TCTRL} }; -static struct cdns_reg_pairs sl_dp_19_2_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs sl_dp_19_2_no_ssc_tx_ln_regs[] = { {0x0780, TX_RCVDET_ST_TMR}, {0x00FB, TX_PSC_A0}, {0x04AA, TX_PSC_A2}, @@ -3288,7 +3703,7 @@ static struct cdns_reg_pairs sl_dp_19_2_no_ssc_tx_ln_regs[] = { {0x000F, XCVR_DIAG_BIDI_CTRL} }; -static struct cdns_reg_pairs sl_dp_19_2_no_ssc_rx_ln_regs[] = { +static const struct cdns_reg_pairs sl_dp_19_2_no_ssc_rx_ln_regs[] = { {0x0000, RX_PSC_A0}, {0x0000, RX_PSC_A2}, {0x0000, RX_PSC_A3}, @@ -3298,23 +3713,23 @@ static struct cdns_reg_pairs sl_dp_19_2_no_ssc_rx_ln_regs[] = { {0x0000, RX_REE_PERGCSM_CTRL} }; -static struct cdns_torrent_vals sl_dp_19_2_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals sl_dp_19_2_no_ssc_cmn_vals = { .reg_pairs = sl_dp_19_2_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sl_dp_19_2_no_ssc_cmn_regs), }; -static struct cdns_torrent_vals sl_dp_19_2_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals sl_dp_19_2_no_ssc_tx_ln_vals = { .reg_pairs = sl_dp_19_2_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(sl_dp_19_2_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals sl_dp_19_2_no_ssc_rx_ln_vals = { +static const struct cdns_torrent_vals sl_dp_19_2_no_ssc_rx_ln_vals = { .reg_pairs = sl_dp_19_2_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(sl_dp_19_2_no_ssc_rx_ln_regs), }; /* Single DP, 25 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs sl_dp_25_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sl_dp_25_no_ssc_cmn_regs[] = { {0x0019, CMN_SSM_BIAS_TMR}, {0x0032, CMN_PLLSM0_PLLPRE_TMR}, {0x00D1, CMN_PLLSM0_PLLLOCK_TMR}, @@ -3351,7 +3766,7 @@ static struct cdns_reg_pairs sl_dp_25_no_ssc_cmn_regs[] = { {0x0003, CMN_PLL1_VCOCAL_TCTRL} }; -static struct cdns_reg_pairs sl_dp_25_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs sl_dp_25_no_ssc_tx_ln_regs[] = { {0x09C4, TX_RCVDET_ST_TMR}, {0x00FB, TX_PSC_A0}, {0x04AA, TX_PSC_A2}, @@ -3359,7 +3774,7 @@ static struct cdns_reg_pairs sl_dp_25_no_ssc_tx_ln_regs[] = { {0x000F, XCVR_DIAG_BIDI_CTRL} }; -static struct cdns_reg_pairs sl_dp_25_no_ssc_rx_ln_regs[] = { +static const struct cdns_reg_pairs sl_dp_25_no_ssc_rx_ln_regs[] = { {0x0000, RX_PSC_A0}, {0x0000, RX_PSC_A2}, {0x0000, RX_PSC_A3}, @@ -3369,35 +3784,35 @@ static struct cdns_reg_pairs sl_dp_25_no_ssc_rx_ln_regs[] = { {0x0000, RX_REE_PERGCSM_CTRL} }; -static struct cdns_torrent_vals sl_dp_25_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals sl_dp_25_no_ssc_cmn_vals = { .reg_pairs = sl_dp_25_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_cmn_regs), }; -static struct cdns_torrent_vals sl_dp_25_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals sl_dp_25_no_ssc_tx_ln_vals = { .reg_pairs = sl_dp_25_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals sl_dp_25_no_ssc_rx_ln_vals = { +static const struct cdns_torrent_vals sl_dp_25_no_ssc_rx_ln_vals = { .reg_pairs = sl_dp_25_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_rx_ln_regs), }; /* Single DP, 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs sl_dp_100_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sl_dp_100_no_ssc_cmn_regs[] = { {0x0003, CMN_PLL0_VCOCAL_TCTRL}, {0x0003, CMN_PLL1_VCOCAL_TCTRL} }; -static struct cdns_reg_pairs sl_dp_100_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs sl_dp_100_no_ssc_tx_ln_regs[] = { {0x00FB, TX_PSC_A0}, {0x04AA, TX_PSC_A2}, {0x04AA, TX_PSC_A3}, {0x000F, XCVR_DIAG_BIDI_CTRL} }; -static struct cdns_reg_pairs sl_dp_100_no_ssc_rx_ln_regs[] = { +static const struct cdns_reg_pairs sl_dp_100_no_ssc_rx_ln_regs[] = { {0x0000, RX_PSC_A0}, {0x0000, RX_PSC_A2}, {0x0000, RX_PSC_A3}, @@ -3407,92 +3822,92 @@ static struct cdns_reg_pairs sl_dp_100_no_ssc_rx_ln_regs[] = { {0x0000, RX_REE_PERGCSM_CTRL} }; -static struct cdns_torrent_vals sl_dp_100_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals sl_dp_100_no_ssc_cmn_vals = { .reg_pairs = sl_dp_100_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sl_dp_100_no_ssc_cmn_regs), }; -static struct cdns_torrent_vals sl_dp_100_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals sl_dp_100_no_ssc_tx_ln_vals = { .reg_pairs = sl_dp_100_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(sl_dp_100_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals sl_dp_100_no_ssc_rx_ln_vals = { +static const struct cdns_torrent_vals sl_dp_100_no_ssc_rx_ln_vals = { .reg_pairs = sl_dp_100_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(sl_dp_100_no_ssc_rx_ln_regs), }; /* USB and SGMII/QSGMII link configuration */ -static struct cdns_reg_pairs usb_sgmii_link_cmn_regs[] = { +static const struct cdns_reg_pairs usb_sgmii_link_cmn_regs[] = { {0x0002, PHY_PLL_CFG}, {0x8600, CMN_PDIAG_PLL0_CLK_SEL_M0}, {0x0601, CMN_PDIAG_PLL1_CLK_SEL_M0} }; -static struct cdns_reg_pairs usb_sgmii_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs usb_sgmii_xcvr_diag_ln_regs[] = { {0x0000, XCVR_DIAG_HSCLK_SEL}, {0x0001, XCVR_DIAG_HSCLK_DIV}, {0x0041, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_reg_pairs sgmii_usb_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs sgmii_usb_xcvr_diag_ln_regs[] = { {0x0011, XCVR_DIAG_HSCLK_SEL}, {0x0003, XCVR_DIAG_HSCLK_DIV}, {0x009B, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_torrent_vals usb_sgmii_link_cmn_vals = { +static const struct cdns_torrent_vals usb_sgmii_link_cmn_vals = { .reg_pairs = usb_sgmii_link_cmn_regs, .num_regs = ARRAY_SIZE(usb_sgmii_link_cmn_regs), }; -static struct cdns_torrent_vals usb_sgmii_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals usb_sgmii_xcvr_diag_ln_vals = { .reg_pairs = usb_sgmii_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(usb_sgmii_xcvr_diag_ln_regs), }; -static struct cdns_torrent_vals sgmii_usb_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals sgmii_usb_xcvr_diag_ln_vals = { .reg_pairs = sgmii_usb_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(sgmii_usb_xcvr_diag_ln_regs), }; /* PCIe and USB Unique SSC link configuration */ -static struct cdns_reg_pairs pcie_usb_link_cmn_regs[] = { +static const struct cdns_reg_pairs pcie_usb_link_cmn_regs[] = { {0x0003, PHY_PLL_CFG}, {0x0601, CMN_PDIAG_PLL0_CLK_SEL_M0}, {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M1}, {0x8600, CMN_PDIAG_PLL1_CLK_SEL_M0} }; -static struct cdns_reg_pairs pcie_usb_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs pcie_usb_xcvr_diag_ln_regs[] = { {0x0000, XCVR_DIAG_HSCLK_SEL}, {0x0001, XCVR_DIAG_HSCLK_DIV}, {0x0012, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_reg_pairs usb_pcie_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs usb_pcie_xcvr_diag_ln_regs[] = { {0x0011, XCVR_DIAG_HSCLK_SEL}, {0x0001, XCVR_DIAG_HSCLK_DIV}, {0x00C9, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_torrent_vals pcie_usb_link_cmn_vals = { +static const struct cdns_torrent_vals pcie_usb_link_cmn_vals = { .reg_pairs = pcie_usb_link_cmn_regs, .num_regs = ARRAY_SIZE(pcie_usb_link_cmn_regs), }; -static struct cdns_torrent_vals pcie_usb_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals pcie_usb_xcvr_diag_ln_vals = { .reg_pairs = pcie_usb_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(pcie_usb_xcvr_diag_ln_regs), }; -static struct cdns_torrent_vals usb_pcie_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals usb_pcie_xcvr_diag_ln_vals = { .reg_pairs = usb_pcie_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(usb_pcie_xcvr_diag_ln_regs), }; /* USB 100 MHz Ref clk, internal SSC */ -static struct cdns_reg_pairs usb_100_int_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs usb_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, {0x0004, CMN_PLL0_DSM_DIAG_M1}, {0x0004, CMN_PLL1_DSM_DIAG_M0}, @@ -3545,47 +3960,47 @@ static struct cdns_reg_pairs usb_100_int_ssc_cmn_regs[] = { {0x007F, CMN_TXPDCAL_TUNE} }; -static struct cdns_torrent_vals usb_100_int_ssc_cmn_vals = { +static const struct cdns_torrent_vals usb_100_int_ssc_cmn_vals = { .reg_pairs = usb_100_int_ssc_cmn_regs, .num_regs = ARRAY_SIZE(usb_100_int_ssc_cmn_regs), }; /* Single USB link configuration */ -static struct cdns_reg_pairs sl_usb_link_cmn_regs[] = { +static const struct cdns_reg_pairs sl_usb_link_cmn_regs[] = { {0x0000, PHY_PLL_CFG}, {0x8600, CMN_PDIAG_PLL0_CLK_SEL_M0} }; -static struct cdns_reg_pairs sl_usb_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs sl_usb_xcvr_diag_ln_regs[] = { {0x0000, XCVR_DIAG_HSCLK_SEL}, {0x0001, XCVR_DIAG_HSCLK_DIV}, {0x0041, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_torrent_vals sl_usb_link_cmn_vals = { +static const struct cdns_torrent_vals sl_usb_link_cmn_vals = { .reg_pairs = sl_usb_link_cmn_regs, .num_regs = ARRAY_SIZE(sl_usb_link_cmn_regs), }; -static struct cdns_torrent_vals sl_usb_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals sl_usb_xcvr_diag_ln_vals = { .reg_pairs = sl_usb_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(sl_usb_xcvr_diag_ln_regs), }; /* USB PHY PCS common configuration */ -static struct cdns_reg_pairs usb_phy_pcs_cmn_regs[] = { +static const struct cdns_reg_pairs usb_phy_pcs_cmn_regs[] = { {0x0A0A, PHY_PIPE_USB3_GEN2_PRE_CFG0}, {0x1000, PHY_PIPE_USB3_GEN2_POST_CFG0}, {0x0010, PHY_PIPE_USB3_GEN2_POST_CFG1} }; -static struct cdns_torrent_vals usb_phy_pcs_cmn_vals = { +static const struct cdns_torrent_vals usb_phy_pcs_cmn_vals = { .reg_pairs = usb_phy_pcs_cmn_regs, .num_regs = ARRAY_SIZE(usb_phy_pcs_cmn_regs), }; /* USB 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs sl_usb_100_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sl_usb_100_no_ssc_cmn_regs[] = { {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, @@ -3595,19 +4010,19 @@ static struct cdns_reg_pairs sl_usb_100_no_ssc_cmn_regs[] = { {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD} }; -static struct cdns_torrent_vals sl_usb_100_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals sl_usb_100_no_ssc_cmn_vals = { .reg_pairs = sl_usb_100_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sl_usb_100_no_ssc_cmn_regs), }; -static struct cdns_reg_pairs usb_100_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs usb_100_no_ssc_cmn_regs[] = { {0x8200, CMN_CDIAG_CDB_PWRI_OVRD}, {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD}, {0x007F, CMN_TXPUCAL_TUNE}, {0x007F, CMN_TXPDCAL_TUNE} }; -static struct cdns_reg_pairs usb_100_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs usb_100_no_ssc_tx_ln_regs[] = { {0x02FF, TX_PSC_A0}, {0x06AF, TX_PSC_A1}, {0x06AE, TX_PSC_A2}, @@ -3617,7 +4032,7 @@ static struct cdns_reg_pairs usb_100_no_ssc_tx_ln_regs[] = { {0x0003, XCVR_DIAG_PSC_OVRD} }; -static struct cdns_reg_pairs usb_100_no_ssc_rx_ln_regs[] = { +static const struct cdns_reg_pairs usb_100_no_ssc_rx_ln_regs[] = { {0x0D1D, RX_PSC_A0}, {0x0D1D, RX_PSC_A1}, {0x0D00, RX_PSC_A2}, @@ -3640,23 +4055,23 @@ static struct cdns_reg_pairs usb_100_no_ssc_rx_ln_regs[] = { {0x0003, RX_CDRLF_CNFG3} }; -static struct cdns_torrent_vals usb_100_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals usb_100_no_ssc_cmn_vals = { .reg_pairs = usb_100_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(usb_100_no_ssc_cmn_regs), }; -static struct cdns_torrent_vals usb_100_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals usb_100_no_ssc_tx_ln_vals = { .reg_pairs = usb_100_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(usb_100_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals usb_100_no_ssc_rx_ln_vals = { +static const struct cdns_torrent_vals usb_100_no_ssc_rx_ln_vals = { .reg_pairs = usb_100_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(usb_100_no_ssc_rx_ln_regs), }; /* Single link USB, 100 MHz Ref clk, internal SSC */ -static struct cdns_reg_pairs sl_usb_100_int_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sl_usb_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, {0x0004, CMN_PLL1_DSM_DIAG_M0}, {0x0509, CMN_PDIAG_PLL0_CP_PADJ_M0}, @@ -3697,48 +4112,48 @@ static struct cdns_reg_pairs sl_usb_100_int_ssc_cmn_regs[] = { {0x8200, CMN_CDIAG_XCVRC_PWRI_OVRD} }; -static struct cdns_torrent_vals sl_usb_100_int_ssc_cmn_vals = { +static const struct cdns_torrent_vals sl_usb_100_int_ssc_cmn_vals = { .reg_pairs = sl_usb_100_int_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sl_usb_100_int_ssc_cmn_regs), }; /* PCIe and SGMII/QSGMII Unique SSC link configuration */ -static struct cdns_reg_pairs pcie_sgmii_link_cmn_regs[] = { +static const struct cdns_reg_pairs pcie_sgmii_link_cmn_regs[] = { {0x0003, PHY_PLL_CFG}, {0x0601, CMN_PDIAG_PLL0_CLK_SEL_M0}, {0x0400, CMN_PDIAG_PLL0_CLK_SEL_M1}, {0x0601, CMN_PDIAG_PLL1_CLK_SEL_M0} }; -static struct cdns_reg_pairs pcie_sgmii_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs pcie_sgmii_xcvr_diag_ln_regs[] = { {0x0000, XCVR_DIAG_HSCLK_SEL}, {0x0001, XCVR_DIAG_HSCLK_DIV}, {0x0012, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_reg_pairs sgmii_pcie_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs sgmii_pcie_xcvr_diag_ln_regs[] = { {0x0011, XCVR_DIAG_HSCLK_SEL}, {0x0003, XCVR_DIAG_HSCLK_DIV}, {0x009B, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_torrent_vals pcie_sgmii_link_cmn_vals = { +static const struct cdns_torrent_vals pcie_sgmii_link_cmn_vals = { .reg_pairs = pcie_sgmii_link_cmn_regs, .num_regs = ARRAY_SIZE(pcie_sgmii_link_cmn_regs), }; -static struct cdns_torrent_vals pcie_sgmii_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals pcie_sgmii_xcvr_diag_ln_vals = { .reg_pairs = pcie_sgmii_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(pcie_sgmii_xcvr_diag_ln_regs), }; -static struct cdns_torrent_vals sgmii_pcie_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals sgmii_pcie_xcvr_diag_ln_vals = { .reg_pairs = sgmii_pcie_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(sgmii_pcie_xcvr_diag_ln_regs), }; /* SGMII 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs sl_sgmii_100_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sl_sgmii_100_no_ssc_cmn_regs[] = { {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, @@ -3746,34 +4161,36 @@ static struct cdns_reg_pairs sl_sgmii_100_no_ssc_cmn_regs[] = { {0x0003, CMN_PLL1_VCOCAL_TCTRL} }; -static struct cdns_torrent_vals sl_sgmii_100_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals sl_sgmii_100_no_ssc_cmn_vals = { .reg_pairs = sl_sgmii_100_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sl_sgmii_100_no_ssc_cmn_regs), }; -static struct cdns_reg_pairs sgmii_100_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sgmii_100_no_ssc_cmn_regs[] = { {0x007F, CMN_TXPUCAL_TUNE}, {0x007F, CMN_TXPDCAL_TUNE} }; -static struct cdns_reg_pairs sgmii_100_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs sgmii_100_no_ssc_tx_ln_regs[] = { {0x00F3, TX_PSC_A0}, {0x04A2, TX_PSC_A2}, {0x04A2, TX_PSC_A3}, {0x0000, TX_TXCC_CPOST_MULT_00}, - {0x00B3, DRV_DIAG_TX_DRV} + {0x00B3, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD} }; -static struct cdns_reg_pairs ti_sgmii_100_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs ti_sgmii_100_no_ssc_tx_ln_regs[] = { {0x00F3, TX_PSC_A0}, {0x04A2, TX_PSC_A2}, {0x04A2, TX_PSC_A3}, {0x0000, TX_TXCC_CPOST_MULT_00}, {0x00B3, DRV_DIAG_TX_DRV}, - {0x4000, XCVR_DIAG_RXCLK_CTRL}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} }; -static struct cdns_reg_pairs sgmii_100_no_ssc_rx_ln_regs[] = { +static const struct cdns_reg_pairs sgmii_100_no_ssc_rx_ln_regs[] = { {0x091D, RX_PSC_A0}, {0x0900, RX_PSC_A2}, {0x0100, RX_PSC_A3}, @@ -3791,28 +4208,72 @@ static struct cdns_reg_pairs sgmii_100_no_ssc_rx_ln_regs[] = { {0x018C, RX_CDRLF_CNFG}, }; -static struct cdns_torrent_vals sgmii_100_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals sgmii_100_no_ssc_cmn_vals = { .reg_pairs = sgmii_100_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_cmn_regs), }; -static struct cdns_torrent_vals sgmii_100_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals sgmii_100_no_ssc_tx_ln_vals = { .reg_pairs = sgmii_100_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals ti_sgmii_100_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals ti_sgmii_100_no_ssc_tx_ln_vals = { .reg_pairs = ti_sgmii_100_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(ti_sgmii_100_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals sgmii_100_no_ssc_rx_ln_vals = { +static const struct cdns_torrent_vals sgmii_100_no_ssc_rx_ln_vals = { .reg_pairs = sgmii_100_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(sgmii_100_no_ssc_rx_ln_regs), }; +/* TI J7200, multilink SGMII */ +static const struct cdns_reg_pairs j7200_sgmii_100_no_ssc_tx_ln_regs[] = { + {0x07A2, TX_RCVDET_ST_TMR}, + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3 }, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x00B3, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} +}; + +static const struct cdns_torrent_vals j7200_sgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = j7200_sgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_sgmii_100_no_ssc_tx_ln_regs), +}; + +static const struct cdns_reg_pairs j7200_sgmii_100_no_ssc_rx_ln_regs[] = { + {0x0014, RX_SDCAL0_INIT_TMR}, + {0x0062, RX_SDCAL0_ITER_TMR}, + {0x0014, RX_SDCAL1_INIT_TMR}, + {0x0062, RX_SDCAL1_ITER_TMR}, + {0x091D, RX_PSC_A0}, + {0x0900, RX_PSC_A2}, + {0x0100, RX_PSC_A3}, + {0x03C7, RX_REE_GCSM1_EQENM_PH1}, + {0x01C7, RX_REE_GCSM1_EQENM_PH2}, + {0x0000, RX_DIAG_DFE_CTRL}, + {0x0019, RX_REE_TAP1_CLIP}, + {0x0019, RX_REE_TAP2TON_CLIP}, + {0x0098, RX_DIAG_NQST_CTRL}, + {0x0C01, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0000, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0000, RX_DIAG_PI_CAP}, + {0x0010, RX_DIAG_PI_RATE}, + {0x0001, RX_DIAG_ACYA}, + {0x018C, RX_CDRLF_CNFG} +}; + +static const struct cdns_torrent_vals j7200_sgmii_100_no_ssc_rx_ln_vals = { + .reg_pairs = j7200_sgmii_100_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_sgmii_100_no_ssc_rx_ln_regs), +}; + /* SGMII 100 MHz Ref clk, internal SSC */ -static struct cdns_reg_pairs sgmii_100_int_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sgmii_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, {0x0004, CMN_PLL0_DSM_DIAG_M1}, {0x0004, CMN_PLL1_DSM_DIAG_M0}, @@ -3863,13 +4324,13 @@ static struct cdns_reg_pairs sgmii_100_int_ssc_cmn_regs[] = { {0x007F, CMN_TXPDCAL_TUNE} }; -static struct cdns_torrent_vals sgmii_100_int_ssc_cmn_vals = { +static const struct cdns_torrent_vals sgmii_100_int_ssc_cmn_vals = { .reg_pairs = sgmii_100_int_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sgmii_100_int_ssc_cmn_regs), }; /* QSGMII 100 MHz Ref clk, no SSC */ -static struct cdns_reg_pairs sl_qsgmii_100_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sl_qsgmii_100_no_ssc_cmn_regs[] = { {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0}, @@ -3877,36 +4338,38 @@ static struct cdns_reg_pairs sl_qsgmii_100_no_ssc_cmn_regs[] = { {0x0003, CMN_PLL1_VCOCAL_TCTRL} }; -static struct cdns_torrent_vals sl_qsgmii_100_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals sl_qsgmii_100_no_ssc_cmn_vals = { .reg_pairs = sl_qsgmii_100_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sl_qsgmii_100_no_ssc_cmn_regs), }; -static struct cdns_reg_pairs qsgmii_100_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs qsgmii_100_no_ssc_cmn_regs[] = { {0x007F, CMN_TXPUCAL_TUNE}, {0x007F, CMN_TXPDCAL_TUNE} }; -static struct cdns_reg_pairs qsgmii_100_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs qsgmii_100_no_ssc_tx_ln_regs[] = { {0x00F3, TX_PSC_A0}, {0x04A2, TX_PSC_A2}, {0x04A2, TX_PSC_A3}, {0x0000, TX_TXCC_CPOST_MULT_00}, {0x0011, TX_TXCC_MGNFS_MULT_100}, - {0x0003, DRV_DIAG_TX_DRV} + {0x0003, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD} }; -static struct cdns_reg_pairs ti_qsgmii_100_no_ssc_tx_ln_regs[] = { +static const struct cdns_reg_pairs ti_qsgmii_100_no_ssc_tx_ln_regs[] = { {0x00F3, TX_PSC_A0}, {0x04A2, TX_PSC_A2}, {0x04A2, TX_PSC_A3}, {0x0000, TX_TXCC_CPOST_MULT_00}, {0x0011, TX_TXCC_MGNFS_MULT_100}, {0x0003, DRV_DIAG_TX_DRV}, - {0x4000, XCVR_DIAG_RXCLK_CTRL}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} }; -static struct cdns_reg_pairs qsgmii_100_no_ssc_rx_ln_regs[] = { +static const struct cdns_reg_pairs qsgmii_100_no_ssc_rx_ln_regs[] = { {0x091D, RX_PSC_A0}, {0x0900, RX_PSC_A2}, {0x0100, RX_PSC_A3}, @@ -3924,28 +4387,73 @@ static struct cdns_reg_pairs qsgmii_100_no_ssc_rx_ln_regs[] = { {0x018C, RX_CDRLF_CNFG}, }; -static struct cdns_torrent_vals qsgmii_100_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals qsgmii_100_no_ssc_cmn_vals = { .reg_pairs = qsgmii_100_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_cmn_regs), }; -static struct cdns_torrent_vals qsgmii_100_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals qsgmii_100_no_ssc_tx_ln_vals = { .reg_pairs = qsgmii_100_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals ti_qsgmii_100_no_ssc_tx_ln_vals = { +static const struct cdns_torrent_vals ti_qsgmii_100_no_ssc_tx_ln_vals = { .reg_pairs = ti_qsgmii_100_no_ssc_tx_ln_regs, .num_regs = ARRAY_SIZE(ti_qsgmii_100_no_ssc_tx_ln_regs), }; -static struct cdns_torrent_vals qsgmii_100_no_ssc_rx_ln_vals = { +static const struct cdns_torrent_vals qsgmii_100_no_ssc_rx_ln_vals = { .reg_pairs = qsgmii_100_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(qsgmii_100_no_ssc_rx_ln_regs), }; +/* TI J7200, multilink QSGMII */ +static const struct cdns_reg_pairs j7200_qsgmii_100_no_ssc_tx_ln_regs[] = { + {0x07A2, TX_RCVDET_ST_TMR}, + {0x00F3, TX_PSC_A0}, + {0x04A2, TX_PSC_A2}, + {0x04A2, TX_PSC_A3 }, + {0x0000, TX_TXCC_CPOST_MULT_00}, + {0x0011, TX_TXCC_MGNFS_MULT_100}, + {0x0003, DRV_DIAG_TX_DRV}, + {0x0002, XCVR_DIAG_PSC_OVRD}, + {0x4000, XCVR_DIAG_RXCLK_CTRL} +}; + +static const struct cdns_torrent_vals j7200_qsgmii_100_no_ssc_tx_ln_vals = { + .reg_pairs = j7200_qsgmii_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_qsgmii_100_no_ssc_tx_ln_regs), +}; + +static const struct cdns_reg_pairs j7200_qsgmii_100_no_ssc_rx_ln_regs[] = { + {0x0014, RX_SDCAL0_INIT_TMR}, + {0x0062, RX_SDCAL0_ITER_TMR}, + {0x0014, RX_SDCAL1_INIT_TMR}, + {0x0062, RX_SDCAL1_ITER_TMR}, + {0x091D, RX_PSC_A0}, + {0x0900, RX_PSC_A2}, + {0x0100, RX_PSC_A3}, + {0x03C7, RX_REE_GCSM1_EQENM_PH1}, + {0x01C7, RX_REE_GCSM1_EQENM_PH2}, + {0x0000, RX_DIAG_DFE_CTRL}, + {0x0019, RX_REE_TAP1_CLIP}, + {0x0019, RX_REE_TAP2TON_CLIP}, + {0x0098, RX_DIAG_NQST_CTRL}, + {0x0C01, RX_DIAG_DFE_AMP_TUNE_2}, + {0x0000, RX_DIAG_DFE_AMP_TUNE_3}, + {0x0000, RX_DIAG_PI_CAP}, + {0x0010, RX_DIAG_PI_RATE}, + {0x0001, RX_DIAG_ACYA}, + {0x018C, RX_CDRLF_CNFG} +}; + +static const struct cdns_torrent_vals j7200_qsgmii_100_no_ssc_rx_ln_vals = { + .reg_pairs = j7200_qsgmii_100_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(j7200_qsgmii_100_no_ssc_rx_ln_regs), +}; + /* QSGMII 100 MHz Ref clk, internal SSC */ -static struct cdns_reg_pairs qsgmii_100_int_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs qsgmii_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, {0x0004, CMN_PLL0_DSM_DIAG_M1}, {0x0004, CMN_PLL1_DSM_DIAG_M0}, @@ -3996,35 +4504,35 @@ static struct cdns_reg_pairs qsgmii_100_int_ssc_cmn_regs[] = { {0x007F, CMN_TXPDCAL_TUNE} }; -static struct cdns_torrent_vals qsgmii_100_int_ssc_cmn_vals = { +static const struct cdns_torrent_vals qsgmii_100_int_ssc_cmn_vals = { .reg_pairs = qsgmii_100_int_ssc_cmn_regs, .num_regs = ARRAY_SIZE(qsgmii_100_int_ssc_cmn_regs), }; /* Single SGMII/QSGMII link configuration */ -static struct cdns_reg_pairs sl_sgmii_link_cmn_regs[] = { +static const struct cdns_reg_pairs sl_sgmii_link_cmn_regs[] = { {0x0000, PHY_PLL_CFG}, {0x0601, CMN_PDIAG_PLL0_CLK_SEL_M0} }; -static struct cdns_reg_pairs sl_sgmii_xcvr_diag_ln_regs[] = { +static const struct cdns_reg_pairs sl_sgmii_xcvr_diag_ln_regs[] = { {0x0000, XCVR_DIAG_HSCLK_SEL}, {0x0003, XCVR_DIAG_HSCLK_DIV}, {0x0013, XCVR_DIAG_PLLDRC_CTRL} }; -static struct cdns_torrent_vals sl_sgmii_link_cmn_vals = { +static const struct cdns_torrent_vals sl_sgmii_link_cmn_vals = { .reg_pairs = sl_sgmii_link_cmn_regs, .num_regs = ARRAY_SIZE(sl_sgmii_link_cmn_regs), }; -static struct cdns_torrent_vals sl_sgmii_xcvr_diag_ln_vals = { +static const struct cdns_torrent_vals sl_sgmii_xcvr_diag_ln_vals = { .reg_pairs = sl_sgmii_xcvr_diag_ln_regs, .num_regs = ARRAY_SIZE(sl_sgmii_xcvr_diag_ln_regs), }; /* Multi link PCIe, 100 MHz Ref clk, internal SSC */ -static struct cdns_reg_pairs pcie_100_int_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs pcie_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, {0x0004, CMN_PLL0_DSM_DIAG_M1}, {0x0004, CMN_PLL1_DSM_DIAG_M0}, @@ -4073,13 +4581,13 @@ static struct cdns_reg_pairs pcie_100_int_ssc_cmn_regs[] = { {0x0005, CMN_PLL1_LOCK_PLLCNT_THR} }; -static struct cdns_torrent_vals pcie_100_int_ssc_cmn_vals = { +static const struct cdns_torrent_vals pcie_100_int_ssc_cmn_vals = { .reg_pairs = pcie_100_int_ssc_cmn_regs, .num_regs = ARRAY_SIZE(pcie_100_int_ssc_cmn_regs), }; /* Single link PCIe, 100 MHz Ref clk, internal SSC */ -static struct cdns_reg_pairs sl_pcie_100_int_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs sl_pcie_100_int_ssc_cmn_regs[] = { {0x0004, CMN_PLL0_DSM_DIAG_M0}, {0x0004, CMN_PLL0_DSM_DIAG_M1}, {0x0004, CMN_PLL1_DSM_DIAG_M0}, @@ -4128,35 +4636,35 @@ static struct cdns_reg_pairs sl_pcie_100_int_ssc_cmn_regs[] = { {0x0005, CMN_PLL1_LOCK_PLLCNT_THR} }; -static struct cdns_torrent_vals sl_pcie_100_int_ssc_cmn_vals = { +static const struct cdns_torrent_vals sl_pcie_100_int_ssc_cmn_vals = { .reg_pairs = sl_pcie_100_int_ssc_cmn_regs, .num_regs = ARRAY_SIZE(sl_pcie_100_int_ssc_cmn_regs), }; /* PCIe, 100 MHz Ref clk, no SSC & external SSC */ -static struct cdns_reg_pairs pcie_100_ext_no_ssc_cmn_regs[] = { +static const struct cdns_reg_pairs pcie_100_ext_no_ssc_cmn_regs[] = { {0x0028, CMN_PDIAG_PLL1_CP_PADJ_M0}, {0x001E, CMN_PLL1_DSM_FBH_OVRD_M0}, {0x000C, CMN_PLL1_DSM_FBL_OVRD_M0} }; -static struct cdns_reg_pairs pcie_100_ext_no_ssc_rx_ln_regs[] = { +static const struct cdns_reg_pairs pcie_100_ext_no_ssc_rx_ln_regs[] = { {0x0019, RX_REE_TAP1_CLIP}, {0x0019, RX_REE_TAP2TON_CLIP}, {0x0001, RX_DIAG_ACYA} }; -static struct cdns_torrent_vals pcie_100_no_ssc_cmn_vals = { +static const struct cdns_torrent_vals pcie_100_no_ssc_cmn_vals = { .reg_pairs = pcie_100_ext_no_ssc_cmn_regs, .num_regs = ARRAY_SIZE(pcie_100_ext_no_ssc_cmn_regs), }; -static struct cdns_torrent_vals pcie_100_no_ssc_rx_ln_vals = { +static const struct cdns_torrent_vals pcie_100_no_ssc_rx_ln_vals = { .reg_pairs = pcie_100_ext_no_ssc_rx_ln_regs, .num_regs = ARRAY_SIZE(pcie_100_ext_no_ssc_rx_ln_regs), }; -static struct cdns_torrent_vals_entry link_cmn_vals_entries[] = { +static const struct cdns_torrent_vals_entry link_cmn_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_NONE), &sl_dp_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_PCIE), &pcie_dp_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_USB), &usb_dp_link_cmn_vals}, @@ -4166,14 +4674,19 @@ static struct cdns_torrent_vals_entry link_cmn_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_QSGMII), &pcie_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USXGMII), &pcie_usxgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_NONE), &sl_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_PCIE), &pcie_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_QSGMII), &sgmii_qsgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USB), &usb_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USXGMII), &usxgmii_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_NONE), &sl_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_PCIE), &pcie_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_SGMII), &sgmii_qsgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USB), &usb_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USXGMII), &usxgmii_sgmii_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_NONE), &sl_usb_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE), &pcie_usb_link_cmn_vals}, @@ -4182,9 +4695,12 @@ static struct cdns_torrent_vals_entry link_cmn_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_DP), &usb_dp_link_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &sl_usxgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &pcie_usxgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_link_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_link_cmn_vals}, }; -static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { +static const struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_NONE), &sl_dp_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_PCIE), &dp_pcie_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_DP, TYPE_USB), &dp_usb_xcvr_diag_ln_vals}, @@ -4194,14 +4710,19 @@ static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_QSGMII), &pcie_sgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USB), &pcie_usb_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_DP), &pcie_dp_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_PCIE, TYPE_USXGMII), &pcie_usxgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_NONE), &sl_sgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_PCIE), &sgmii_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_QSGMII), &sgmii_qsgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USB), &sgmii_usb_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_SGMII, TYPE_USXGMII), &sgmii_usxgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_NONE), &sl_sgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_PCIE), &sgmii_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_SGMII), &sgmii_qsgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USB), &sgmii_usb_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_QSGMII, TYPE_USXGMII), &sgmii_usxgmii_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_NONE), &sl_usb_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE), &usb_pcie_xcvr_diag_ln_vals}, @@ -4210,9 +4731,12 @@ static struct cdns_torrent_vals_entry xcvr_diag_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_DP), &usb_dp_xcvr_diag_ln_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &sl_usxgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &usxgmii_pcie_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &usxgmii_sgmii_xcvr_diag_ln_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &usxgmii_sgmii_xcvr_diag_ln_vals}, }; -static struct cdns_torrent_vals_entry pcs_cmn_vals_entries[] = { +static const struct cdns_torrent_vals_entry pcs_cmn_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_NONE), &usb_phy_pcs_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_PCIE), &usb_phy_pcs_cmn_vals}, {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_SGMII), &usb_phy_pcs_cmn_vals}, @@ -4220,7 +4744,7 @@ static struct cdns_torrent_vals_entry pcs_cmn_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_USB, TYPE_DP), &usb_phy_pcs_cmn_vals}, }; -static struct cdns_torrent_vals_entry cmn_vals_entries[] = { +static const struct cdns_torrent_vals_entry cmn_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_cmn_vals}, @@ -4252,6 +4776,8 @@ static struct cdns_torrent_vals_entry cmn_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_int_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, @@ -4262,6 +4788,8 @@ static struct cdns_torrent_vals_entry cmn_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_int_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &sl_qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, @@ -4285,9 +4813,20 @@ static struct cdns_torrent_vals_entry cmn_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_cmn_vals}, {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &sl_usxgmii_156_25_no_ssc_cmn_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_pll1_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, }; -static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { +static const struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_tx_ln_vals}, @@ -4319,6 +4858,8 @@ static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_tx_ln_vals}, @@ -4329,6 +4870,8 @@ static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, @@ -4352,9 +4895,20 @@ static struct cdns_torrent_vals_entry cdns_tx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, }; -static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { +static const struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_rx_ln_vals}, @@ -4386,6 +4940,8 @@ static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, @@ -4396,6 +4952,8 @@ static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, @@ -4419,6 +4977,17 @@ static struct cdns_torrent_vals_entry cdns_rx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, }; static const struct cdns_torrent_data cdns_map_torrent = { @@ -4450,11 +5019,14 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }; -static struct cdns_torrent_vals_entry j721e_phy_pma_cmn_vals_entries[] = { +static const struct cdns_torrent_vals_entry j721e_phy_pma_cmn_vals_entries[] = { {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_NONE), &ti_usxgmii_phy_pma_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_PCIE), &ti_usxgmii_phy_pma_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_SGMII), &ti_usxgmii_phy_pma_cmn_vals}, + {CDNS_TORRENT_KEY_ANYCLK(TYPE_USXGMII, TYPE_QSGMII), &ti_usxgmii_phy_pma_cmn_vals}, }; -static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { +static const struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_tx_ln_vals}, @@ -4486,6 +5058,8 @@ static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, @@ -4496,6 +5070,8 @@ static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, @@ -4519,6 +5095,17 @@ static struct cdns_torrent_vals_entry ti_tx_ln_vals_entries[] = { {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, }; static const struct cdns_torrent_data ti_j721e_map_torrent = { @@ -4554,6 +5141,286 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }; +/* TI J7200 (Torrent SD0805) */ +static const struct cdns_torrent_vals_entry ti_j7200_cmn_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &sl_dp_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), &sl_pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), &pcie_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), &pcie_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sl_sgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &sl_qsgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &sl_qsgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &sl_usb_100_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &sl_usb_100_int_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &sl_usxgmii_156_25_no_ssc_cmn_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &j7200_ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &j7200_ml_sgmii_pll1_100_no_ssc_cmn_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_pll1_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &j7200_ml_usxgmii_pll0_156_25_no_ssc_cmn_vals}, +}; + +static const struct cdns_torrent_vals_entry ti_j7200_tx_ln_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &dp_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), NULL}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &ti_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &ti_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), NULL}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &j7200_sgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &j7200_qsgmii_100_no_ssc_tx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &usxgmii_156_25_no_ssc_tx_ln_vals}, +}; + +static const struct cdns_torrent_vals_entry ti_j7200_rx_ln_vals_entries[] = { + {CDNS_TORRENT_KEY(CLK_19_2_MHZ, CLK_19_2_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_19_2_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_25_MHZ, CLK_25_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_25_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_NONE, NO_SSC), &sl_dp_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_PCIE, NO_SSC), &dp_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_DP, TYPE_USB, NO_SSC), &dp_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_NONE, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_SGMII, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_QSGMII, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, EXTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_USB, INTERNAL_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_PCIE, TYPE_DP, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_NONE, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_PCIE, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_QSGMII, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, NO_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, EXTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_SGMII, TYPE_USB, INTERNAL_SSC), &sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_NONE, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_PCIE, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_SGMII, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, NO_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, EXTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_QSGMII, TYPE_USB, INTERNAL_SSC), &qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_NONE, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_PCIE, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_SGMII, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, EXTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_QSGMII, INTERNAL_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_100_MHZ, TYPE_USB, TYPE_DP, NO_SSC), &usb_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_156_25_MHZ, TYPE_USXGMII, TYPE_NONE, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, + + /* Dual refclk */ + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_PCIE, TYPE_USXGMII, NO_SSC), &pcie_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_SGMII, TYPE_USXGMII, NO_SSC), &j7200_sgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_100_MHZ, CLK_156_25_MHZ, TYPE_QSGMII, TYPE_USXGMII, NO_SSC), &j7200_qsgmii_100_no_ssc_rx_ln_vals}, + + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_PCIE, NO_SSC), &ml_usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_SGMII, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, + {CDNS_TORRENT_KEY(CLK_156_25_MHZ, CLK_100_MHZ, TYPE_USXGMII, TYPE_QSGMII, NO_SSC), &usxgmii_156_25_no_ssc_rx_ln_vals}, +}; + +static const struct cdns_torrent_data ti_j7200_map_torrent = { + .block_offset_shift = 0x0, + .reg_offset_shift = 0x1, + .link_cmn_vals_tbl = { + .entries = link_cmn_vals_entries, + .num_entries = ARRAY_SIZE(link_cmn_vals_entries), + }, + .xcvr_diag_vals_tbl = { + .entries = xcvr_diag_vals_entries, + .num_entries = ARRAY_SIZE(xcvr_diag_vals_entries), + }, + .pcs_cmn_vals_tbl = { + .entries = pcs_cmn_vals_entries, + .num_entries = ARRAY_SIZE(pcs_cmn_vals_entries), + }, + .phy_pma_cmn_vals_tbl = { + .entries = j721e_phy_pma_cmn_vals_entries, + .num_entries = ARRAY_SIZE(j721e_phy_pma_cmn_vals_entries), + }, + .cmn_vals_tbl = { + .entries = ti_j7200_cmn_vals_entries, + .num_entries = ARRAY_SIZE(ti_j7200_cmn_vals_entries), + }, + .tx_ln_vals_tbl = { + .entries = ti_j7200_tx_ln_vals_entries, + .num_entries = ARRAY_SIZE(ti_j7200_tx_ln_vals_entries), + }, + .rx_ln_vals_tbl = { + .entries = ti_j7200_rx_ln_vals_entries, + .num_entries = ARRAY_SIZE(ti_j7200_rx_ln_vals_entries), + }, +}; + static const struct of_device_id cdns_torrent_phy_of_match[] = { { .compatible = "cdns,torrent-phy", @@ -4563,16 +5430,21 @@ static const struct of_device_id cdns_torrent_phy_of_match[] = { .compatible = "ti,j721e-serdes-10g", .data = &ti_j721e_map_torrent, }, + { + .compatible = "ti,j7200-serdes-10g", + .data = &ti_j7200_map_torrent, + }, {} }; MODULE_DEVICE_TABLE(of, cdns_torrent_phy_of_match); static struct platform_driver cdns_torrent_phy_driver = { .probe = cdns_torrent_phy_probe, - .remove_new = cdns_torrent_phy_remove, - .driver = { + .remove = cdns_torrent_phy_remove, + .driver = { .name = "cdns-torrent-phy", .of_match_table = cdns_torrent_phy_of_match, + .pm = pm_sleep_ptr(&cdns_torrent_phy_pm_ops), } }; module_platform_driver(cdns_torrent_phy_driver); diff --git a/drivers/phy/freescale/Kconfig b/drivers/phy/freescale/Kconfig index 853958fb2c06..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 @@ -35,6 +36,19 @@ config PHY_FSL_IMX8M_PCIE Enable this to add support for the PCIE PHY as found on i.MX8M family of SOCs. +config PHY_FSL_IMX8QM_HSIO + tristate "Freescale i.MX8QM HSIO PHY" + depends on OF && HAS_IOMEM + select GENERIC_PHY + help + Enable this to add support for the HSIO PHY as found on + i.MX8QM family of SOCs. + +config PHY_FSL_SAMSUNG_HDMI_PHY + tristate "Samsung HDMI PHY support" + depends on OF && HAS_IOMEM && COMMON_CLK + help + Enable this to add support for the Samsung HDMI PHY in i.MX8MP. endif config PHY_FSL_LYNX_28G diff --git a/drivers/phy/freescale/Makefile b/drivers/phy/freescale/Makefile index cedb328bc4d2..658eac7d0a62 100644 --- a/drivers/phy/freescale/Makefile +++ b/drivers/phy/freescale/Makefile @@ -3,4 +3,6 @@ obj-$(CONFIG_PHY_FSL_IMX8MQ_USB) += phy-fsl-imx8mq-usb.o obj-$(CONFIG_PHY_MIXEL_LVDS_PHY) += phy-fsl-imx8qm-lvds-phy.o obj-$(CONFIG_PHY_MIXEL_MIPI_DPHY) += phy-fsl-imx8-mipi-dphy.o obj-$(CONFIG_PHY_FSL_IMX8M_PCIE) += phy-fsl-imx8m-pcie.o +obj-$(CONFIG_PHY_FSL_IMX8QM_HSIO) += phy-fsl-imx8qm-hsio.o obj-$(CONFIG_PHY_FSL_LYNX_28G) += phy-fsl-lynx-28g.o +obj-$(CONFIG_PHY_FSL_SAMSUNG_HDMI_PHY) += phy-fsl-samsung-hdmi.o diff --git a/drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c b/drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c index e625b32889bf..0928a526e2ab 100644 --- a/drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c +++ b/drivers/phy/freescale/phy-fsl-imx8-mipi-dphy.c @@ -706,7 +706,7 @@ static int mixel_dphy_probe(struct platform_device *pdev) return ret; } - priv->id = of_alias_get_id(np, "mipi_dphy"); + priv->id = of_alias_get_id(np, "mipi-dphy"); if (priv->id < 0) { dev_err(dev, "Failed to get phy node alias id: %d\n", priv->id); diff --git a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c index b700f52b7b67..68fcc8114d75 100644 --- a/drivers/phy/freescale/phy-fsl-imx8m-pcie.c +++ b/drivers/phy/freescale/phy-fsl-imx8m-pcie.c @@ -110,8 +110,10 @@ static int imx8_pcie_phy_power_on(struct phy *phy) /* Source clock from SoC internal PLL */ writel(ANA_PLL_CLK_OUT_TO_EXT_IO_SEL, imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG062); - writel(AUX_PLL_REFCLK_SEL_SYS_PLL, - imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG063); + if (imx8_phy->drvdata->variant != IMX8MM) { + writel(AUX_PLL_REFCLK_SEL_SYS_PLL, + imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG063); + } val = ANA_AUX_RX_TX_SEL_TX | ANA_AUX_TX_TERM; writel(val | ANA_AUX_RX_TERM_GND_EN, imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG064); @@ -139,27 +141,31 @@ static int imx8_pcie_phy_power_on(struct phy *phy) IMX8MM_GPR_PCIE_REF_CLK_PLL); usleep_range(100, 200); + 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, IMX8MM_GPR_PCIE_CMN_RST, IMX8MM_GPR_PCIE_CMN_RST); - 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; - } - /* Polling to check the phy is ready or not. */ ret = readl_poll_timeout(imx8_phy->base + IMX8MM_PCIE_PHY_CMN_REG075, val, val == ANA_PLL_DONE, 10, 20000); 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); @@ -180,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, }; @@ -231,24 +238,21 @@ static int imx8_pcie_phy_probe(struct platform_device *pdev) imx8_phy->clkreq_unused = false; imx8_phy->clk = devm_clk_get(dev, "ref"); - if (IS_ERR(imx8_phy->clk)) { - dev_err(dev, "failed to get imx pcie phy clock\n"); - return PTR_ERR(imx8_phy->clk); - } + if (IS_ERR(imx8_phy->clk)) + return dev_err_probe(dev, PTR_ERR(imx8_phy->clk), + "failed to get imx pcie phy clock\n"); /* Grab GPR config register range */ imx8_phy->iomuxc_gpr = syscon_regmap_lookup_by_compatible(imx8_phy->drvdata->gpr); - if (IS_ERR(imx8_phy->iomuxc_gpr)) { - dev_err(dev, "unable to find iomuxc registers\n"); - return PTR_ERR(imx8_phy->iomuxc_gpr); - } + if (IS_ERR(imx8_phy->iomuxc_gpr)) + return dev_err_probe(dev, PTR_ERR(imx8_phy->iomuxc_gpr), + "unable to find iomuxc registers\n"); imx8_phy->reset = devm_reset_control_get_exclusive(dev, "pciephy"); - if (IS_ERR(imx8_phy->reset)) { - dev_err(dev, "Failed to get PCIEPHY reset control\n"); - return PTR_ERR(imx8_phy->reset); - } + if (IS_ERR(imx8_phy->reset)) + return dev_err_probe(dev, PTR_ERR(imx8_phy->reset), + "Failed to get PCIEPHY reset control\n"); if (imx8_phy->drvdata->variant == IMX8MP) { imx8_phy->perst = diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c index 0b9a59d5b8f0..b94f242420fc 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); @@ -71,6 +293,28 @@ static u32 phy_tx_vref_tune_from_property(u32 percent) return DIV_ROUND_CLOSEST(percent - 94U, 2); } +static u32 imx95_phy_tx_vref_tune_from_property(u32 percent) +{ + percent = clamp(percent, 90U, 108U); + + switch (percent) { + case 90 ... 91: + percent = 0; + break; + case 92 ... 96: + percent -= 91; + break; + case 97 ... 104: + percent -= 92; + break; + case 105 ... 108: + percent -= 93; + break; + } + + return percent; +} + static u32 phy_tx_rise_tune_from_property(u32 percent) { switch (percent) { @@ -85,6 +329,22 @@ static u32 phy_tx_rise_tune_from_property(u32 percent) } } +static u32 imx95_phy_tx_rise_tune_from_property(u32 percent) +{ + percent = clamp(percent, 90U, 120U); + + switch (percent) { + case 90 ... 99: + return 3; + case 101 ... 115: + return 1; + case 116 ... 120: + return 0; + default: + return 2; + } +} + static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp) { microamp = min(microamp, 1800U); @@ -95,12 +355,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; } } @@ -130,6 +390,29 @@ static u32 phy_comp_dis_tune_from_property(u32 percent) return 7; } } + +static u32 imx95_phy_comp_dis_tune_from_property(u32 percent) +{ + percent = clamp(percent, 94, 104); + + switch (percent) { + case 94 ... 95: + percent = 0; + break; + case 96 ... 98: + percent -= 95; + break; + case 99 ... 102: + percent -= 96; + break; + case 103 ... 104: + percent -= 97; + break; + } + + return percent; +} + static u32 phy_pcs_tx_swing_full_from_property(u32 percent) { percent = min(percent, 100U); @@ -140,10 +423,17 @@ static u32 phy_pcs_tx_swing_full_from_property(u32 percent) static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy) { struct device *dev = imx_phy->phy->dev.parent; + bool is_imx95 = false; + + if (device_is_compatible(dev, "fsl,imx95-usb-phy")) + is_imx95 = true; if (device_property_read_u32(dev, "fsl,phy-tx-vref-tune-percent", &imx_phy->tx_vref_tune)) imx_phy->tx_vref_tune = PHY_TUNE_DEFAULT; + else if (is_imx95) + imx_phy->tx_vref_tune = + imx95_phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune); else imx_phy->tx_vref_tune = phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune); @@ -151,6 +441,9 @@ static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy) if (device_property_read_u32(dev, "fsl,phy-tx-rise-tune-percent", &imx_phy->tx_rise_tune)) imx_phy->tx_rise_tune = PHY_TUNE_DEFAULT; + else if (is_imx95) + imx_phy->tx_rise_tune = + imx95_phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune); else imx_phy->tx_rise_tune = phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune); @@ -172,11 +465,14 @@ static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy) if (device_property_read_u32(dev, "fsl,phy-comp-dis-tune-percent", &imx_phy->comp_dis_tune)) imx_phy->comp_dis_tune = PHY_TUNE_DEFAULT; + else if (is_imx95) + imx_phy->comp_dis_tune = + imx95_phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune); else imx_phy->comp_dis_tune = phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune); - if (device_property_read_u32(dev, "fsl,pcs-tx-deemph-3p5db-attenuation-db", + if (device_property_read_u32(dev, "fsl,phy-pcs-tx-deemph-3p5db-attenuation-db", &imx_phy->pcs_tx_deemph_3p5db)) imx_phy->pcs_tx_deemph_3p5db = PHY_TUNE_DEFAULT; else @@ -315,6 +611,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 +658,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 +699,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 +711,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-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c new file mode 100644 index 000000000000..5dca93cd325c --- /dev/null +++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c @@ -0,0 +1,611 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2024 NXP + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pci_regs.h> +#include <linux/phy/phy.h> +#include <linux/phy/pcie.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <dt-bindings/phy/phy.h> +#include <dt-bindings/phy/phy-imx8-pcie.h> + +#define MAX_NUM_LANE 3 +#define LANE_NUM_CLKS 5 + +/* Parameters for the waiting for PCIe PHY PLL to lock */ +#define PHY_INIT_WAIT_USLEEP_MAX 10 +#define PHY_INIT_WAIT_TIMEOUT (1000 * PHY_INIT_WAIT_USLEEP_MAX) + +/* i.MX8Q HSIO registers */ +#define HSIO_CTRL0 0x0 +#define HSIO_APB_RSTN_0 BIT(0) +#define HSIO_APB_RSTN_1 BIT(1) +#define HSIO_PIPE_RSTN_0_MASK GENMASK(25, 24) +#define HSIO_PIPE_RSTN_1_MASK GENMASK(27, 26) +#define HSIO_MODE_MASK GENMASK(20, 17) +#define HSIO_MODE_PCIE 0x0 +#define HSIO_MODE_SATA 0x4 +#define HSIO_DEVICE_TYPE_MASK GENMASK(27, 24) +#define HSIO_EPCS_TXDEEMP BIT(5) +#define HSIO_EPCS_TXDEEMP_SEL BIT(6) +#define HSIO_EPCS_PHYRESET_N BIT(7) +#define HSIO_RESET_N BIT(12) + +#define HSIO_IOB_RXENA BIT(0) +#define HSIO_IOB_TXENA BIT(1) +#define HSIO_IOB_A_0_TXOE BIT(2) +#define HSIO_IOB_A_0_M1M0_2 BIT(4) +#define HSIO_IOB_A_0_M1M0_MASK GENMASK(4, 3) +#define HSIO_PHYX1_EPCS_SEL BIT(12) +#define HSIO_PCIE_AB_SELECT BIT(13) + +#define HSIO_PHY_STS0 0x4 +#define HSIO_LANE0_TX_PLL_LOCK BIT(4) +#define HSIO_LANE1_TX_PLL_LOCK BIT(12) + +#define HSIO_CTRL2 0x8 +#define HSIO_LTSSM_ENABLE BIT(4) +#define HSIO_BUTTON_RST_N BIT(21) +#define HSIO_PERST_N BIT(22) +#define HSIO_POWER_UP_RST_N BIT(23) + +#define HSIO_PCIE_STS0 0xc +#define HSIO_PM_REQ_CORE_RST BIT(19) + +#define HSIO_REG48_PMA_STATUS 0x30 +#define HSIO_REG48_PMA_RDY BIT(7) + +struct imx_hsio_drvdata { + int lane_num; +}; + +struct imx_hsio_lane { + u32 ctrl_index; + u32 ctrl_off; + u32 idx; + u32 phy_off; + u32 phy_type; + const char * const *clk_names; + struct clk_bulk_data clks[LANE_NUM_CLKS]; + struct imx_hsio_priv *priv; + struct phy *phy; + enum phy_mode phy_mode; +}; + +struct imx_hsio_priv { + void __iomem *base; + struct device *dev; + struct mutex lock; + const char *hsio_cfg; + const char *refclk_pad; + u32 open_cnt; + struct regmap *phy; + struct regmap *ctrl; + struct regmap *misc; + const struct imx_hsio_drvdata *drvdata; + struct imx_hsio_lane lane[MAX_NUM_LANE]; +}; + +static const char * const lan0_pcie_clks[] = {"apb_pclk0", "pclk0", "ctl0_crr", + "phy0_crr", "misc_crr"}; +static const char * const lan1_pciea_clks[] = {"apb_pclk1", "pclk1", "ctl0_crr", + "phy0_crr", "misc_crr"}; +static const char * const lan1_pcieb_clks[] = {"apb_pclk1", "pclk1", "ctl1_crr", + "phy0_crr", "misc_crr"}; +static const char * const lan2_pcieb_clks[] = {"apb_pclk2", "pclk2", "ctl1_crr", + "phy1_crr", "misc_crr"}; +static const char * const lan2_sata_clks[] = {"pclk2", "epcs_tx", "epcs_rx", + "phy1_crr", "misc_crr"}; + +static const struct regmap_config regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int imx_hsio_init(struct phy *phy) +{ + int ret, i; + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + struct device *dev = priv->dev; + + /* Assign clocks refer to different modes */ + switch (lane->phy_type) { + case PHY_TYPE_PCIE: + lane->phy_mode = PHY_MODE_PCIE; + if (lane->ctrl_index == 0) { /* PCIEA */ + lane->ctrl_off = 0; + lane->phy_off = 0; + + for (i = 0; i < LANE_NUM_CLKS; i++) { + if (lane->idx == 0) + lane->clks[i].id = lan0_pcie_clks[i]; + else + lane->clks[i].id = lan1_pciea_clks[i]; + } + } else { /* PCIEB */ + if (lane->idx == 0) { /* i.MX8QXP */ + lane->ctrl_off = 0; + lane->phy_off = 0; + } else { + /* + * On i.MX8QM, only second or third lane can be + * bound to PCIEB. + */ + lane->ctrl_off = SZ_64K; + if (lane->idx == 1) + lane->phy_off = 0; + else /* the third lane is bound to PCIEB */ + lane->phy_off = SZ_64K; + } + + for (i = 0; i < LANE_NUM_CLKS; i++) { + if (lane->idx == 1) + lane->clks[i].id = lan1_pcieb_clks[i]; + else if (lane->idx == 2) + lane->clks[i].id = lan2_pcieb_clks[i]; + else /* i.MX8QXP only has PCIEB, idx is 0 */ + lane->clks[i].id = lan0_pcie_clks[i]; + } + } + break; + case PHY_TYPE_SATA: + /* On i.MX8QM, only the third lane can be bound to SATA */ + lane->phy_mode = PHY_MODE_SATA; + lane->ctrl_off = SZ_128K; + lane->phy_off = SZ_64K; + + for (i = 0; i < LANE_NUM_CLKS; i++) + lane->clks[i].id = lan2_sata_clks[i]; + break; + default: + return -EINVAL; + } + + /* Fetch clocks and enable them */ + ret = devm_clk_bulk_get(dev, LANE_NUM_CLKS, lane->clks); + if (ret) + return ret; + ret = clk_bulk_prepare_enable(LANE_NUM_CLKS, lane->clks); + if (ret) + return ret; + + /* allow the clocks to stabilize */ + usleep_range(200, 500); + return 0; +} + +static int imx_hsio_exit(struct phy *phy) +{ + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + + clk_bulk_disable_unprepare(LANE_NUM_CLKS, lane->clks); + + return 0; +} + +static void imx_hsio_pcie_phy_resets(struct phy *phy) +{ + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2, + HSIO_BUTTON_RST_N); + regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2, + HSIO_PERST_N); + regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2, + HSIO_POWER_UP_RST_N); + regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2, + HSIO_BUTTON_RST_N); + regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2, + HSIO_PERST_N); + regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2, + HSIO_POWER_UP_RST_N); + + if (lane->idx == 1) { + regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0, + HSIO_APB_RSTN_1); + regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0, + HSIO_PIPE_RSTN_1_MASK); + } else { + regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0, + HSIO_APB_RSTN_0); + regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0, + HSIO_PIPE_RSTN_0_MASK); + } +} + +static void imx_hsio_sata_phy_resets(struct phy *phy) +{ + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + /* clear PHY RST, then set it */ + regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, + HSIO_EPCS_PHYRESET_N); + regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, + HSIO_EPCS_PHYRESET_N); + + /* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */ + regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, HSIO_RESET_N); + udelay(1); + regmap_clear_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, + HSIO_RESET_N); + regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, HSIO_RESET_N); +} + +static void imx_hsio_configure_clk_pad(struct phy *phy) +{ + bool pll = false; + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + if (strncmp(priv->refclk_pad, "output", 6) == 0) { + pll = true; + regmap_update_bits(priv->misc, HSIO_CTRL0, + HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_MASK, + HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_2); + } else { + regmap_update_bits(priv->misc, HSIO_CTRL0, + HSIO_IOB_A_0_TXOE | HSIO_IOB_A_0_M1M0_MASK, + 0); + } + + regmap_update_bits(priv->misc, HSIO_CTRL0, HSIO_IOB_RXENA, + pll ? 0 : HSIO_IOB_RXENA); + regmap_update_bits(priv->misc, HSIO_CTRL0, HSIO_IOB_TXENA, + pll ? HSIO_IOB_TXENA : 0); +} + +static void imx_hsio_pre_set(struct phy *phy) +{ + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + if (strncmp(priv->hsio_cfg, "pciea-x2-pcieb", 14) == 0) { + regmap_set_bits(priv->misc, HSIO_CTRL0, HSIO_PCIE_AB_SELECT); + } else if (strncmp(priv->hsio_cfg, "pciea-x2-sata", 13) == 0) { + regmap_set_bits(priv->misc, HSIO_CTRL0, HSIO_PHYX1_EPCS_SEL); + } else if (strncmp(priv->hsio_cfg, "pciea-pcieb-sata", 16) == 0) { + regmap_set_bits(priv->misc, HSIO_CTRL0, HSIO_PCIE_AB_SELECT); + regmap_set_bits(priv->misc, HSIO_CTRL0, HSIO_PHYX1_EPCS_SEL); + } + + imx_hsio_configure_clk_pad(phy); +} + +static int imx_hsio_pcie_power_on(struct phy *phy) +{ + int ret; + u32 val, addr, cond; + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + imx_hsio_pcie_phy_resets(phy); + + /* Toggle apb_pclk to make sure PM_REQ_CORE_RST is cleared. */ + clk_disable_unprepare(lane->clks[0].clk); + mdelay(1); + ret = clk_prepare_enable(lane->clks[0].clk); + if (ret) { + dev_err(priv->dev, "unable to enable phy apb_pclk\n"); + return ret; + } + + addr = lane->ctrl_off + HSIO_PCIE_STS0; + cond = HSIO_PM_REQ_CORE_RST; + ret = regmap_read_poll_timeout(priv->ctrl, addr, val, + (val & cond) == 0, + PHY_INIT_WAIT_USLEEP_MAX, + PHY_INIT_WAIT_TIMEOUT); + if (ret) + dev_err(priv->dev, "HSIO_PM_REQ_CORE_RST is set\n"); + return ret; +} + +static int imx_hsio_sata_power_on(struct phy *phy) +{ + int ret; + u32 val, cond; + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + regmap_set_bits(priv->phy, lane->phy_off + HSIO_CTRL0, HSIO_APB_RSTN_0); + regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, + HSIO_EPCS_TXDEEMP); + regmap_set_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, + HSIO_EPCS_TXDEEMP_SEL); + + imx_hsio_sata_phy_resets(phy); + + cond = HSIO_REG48_PMA_RDY; + ret = read_poll_timeout(readb, val, ((val & cond) == cond), + PHY_INIT_WAIT_USLEEP_MAX, + PHY_INIT_WAIT_TIMEOUT, false, + priv->base + HSIO_REG48_PMA_STATUS); + if (ret) + dev_err(priv->dev, "PHY calibration is timeout\n"); + else + dev_dbg(priv->dev, "PHY calibration is done\n"); + + return ret; +} + +static int imx_hsio_power_on(struct phy *phy) +{ + int ret; + u32 val, cond; + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + scoped_guard(mutex, &priv->lock) { + if (!priv->open_cnt) + imx_hsio_pre_set(phy); + priv->open_cnt++; + } + + if (lane->phy_mode == PHY_MODE_PCIE) + ret = imx_hsio_pcie_power_on(phy); + else /* SATA */ + ret = imx_hsio_sata_power_on(phy); + if (ret) + return ret; + + /* Polling to check the PHY is ready or not. */ + if (lane->idx == 1) + cond = HSIO_LANE1_TX_PLL_LOCK; + else + /* + * Except the phy_off, the bit-offset of lane2 is same to lane0. + * Merge the lane0 and lane2 bit-operations together. + */ + cond = HSIO_LANE0_TX_PLL_LOCK; + + ret = regmap_read_poll_timeout(priv->phy, lane->phy_off + HSIO_PHY_STS0, + val, ((val & cond) == cond), + PHY_INIT_WAIT_USLEEP_MAX, + PHY_INIT_WAIT_TIMEOUT); + if (ret) { + dev_err(priv->dev, "IMX8Q PHY%d PLL lock timeout\n", lane->idx); + return ret; + } + dev_dbg(priv->dev, "IMX8Q PHY%d PLL is locked\n", lane->idx); + + return ret; +} + +static int imx_hsio_power_off(struct phy *phy) +{ + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + scoped_guard(mutex, &priv->lock) { + priv->open_cnt--; + if (priv->open_cnt == 0) { + regmap_clear_bits(priv->misc, HSIO_CTRL0, + HSIO_PCIE_AB_SELECT); + regmap_clear_bits(priv->misc, HSIO_CTRL0, + HSIO_PHYX1_EPCS_SEL); + + if (lane->phy_mode == PHY_MODE_PCIE) { + regmap_clear_bits(priv->ctrl, + lane->ctrl_off + HSIO_CTRL2, + HSIO_BUTTON_RST_N); + regmap_clear_bits(priv->ctrl, + lane->ctrl_off + HSIO_CTRL2, + HSIO_PERST_N); + regmap_clear_bits(priv->ctrl, + lane->ctrl_off + HSIO_CTRL2, + HSIO_POWER_UP_RST_N); + } else { + regmap_clear_bits(priv->ctrl, + lane->ctrl_off + HSIO_CTRL0, + HSIO_EPCS_TXDEEMP); + regmap_clear_bits(priv->ctrl, + lane->ctrl_off + HSIO_CTRL0, + HSIO_EPCS_TXDEEMP_SEL); + regmap_clear_bits(priv->ctrl, + lane->ctrl_off + HSIO_CTRL0, + HSIO_RESET_N); + } + + if (lane->idx == 1) { + regmap_clear_bits(priv->phy, + lane->phy_off + HSIO_CTRL0, + HSIO_APB_RSTN_1); + regmap_clear_bits(priv->phy, + lane->phy_off + HSIO_CTRL0, + HSIO_PIPE_RSTN_1_MASK); + } else { + /* + * Except the phy_off, the bit-offset of lane2 is same + * to lane0. Merge the lane0 and lane2 bit-operations + * together. + */ + regmap_clear_bits(priv->phy, + lane->phy_off + HSIO_CTRL0, + HSIO_APB_RSTN_0); + regmap_clear_bits(priv->phy, + lane->phy_off + HSIO_CTRL0, + HSIO_PIPE_RSTN_0_MASK); + } + } + } + + return 0; +} + +static int imx_hsio_set_mode(struct phy *phy, enum phy_mode mode, + int submode) +{ + u32 val; + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + if (lane->phy_mode != mode) + return -EINVAL; + + val = (mode == PHY_MODE_PCIE) ? HSIO_MODE_PCIE : HSIO_MODE_SATA; + val = FIELD_PREP(HSIO_MODE_MASK, val); + regmap_update_bits(priv->phy, lane->phy_off + HSIO_CTRL0, + HSIO_MODE_MASK, val); + + switch (submode) { + case PHY_MODE_PCIE_RC: + val = FIELD_PREP(HSIO_DEVICE_TYPE_MASK, PCI_EXP_TYPE_ROOT_PORT); + break; + case PHY_MODE_PCIE_EP: + val = FIELD_PREP(HSIO_DEVICE_TYPE_MASK, PCI_EXP_TYPE_ENDPOINT); + break; + default: /* Support only PCIe EP and RC now. */ + return 0; + } + if (submode) + regmap_update_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL0, + HSIO_DEVICE_TYPE_MASK, val); + + return 0; +} + +static int imx_hsio_set_speed(struct phy *phy, int speed) +{ + struct imx_hsio_lane *lane = phy_get_drvdata(phy); + struct imx_hsio_priv *priv = lane->priv; + + regmap_update_bits(priv->ctrl, lane->ctrl_off + HSIO_CTRL2, + HSIO_LTSSM_ENABLE, + speed ? HSIO_LTSSM_ENABLE : 0); + return 0; +} + +static const struct phy_ops imx_hsio_ops = { + .init = imx_hsio_init, + .exit = imx_hsio_exit, + .power_on = imx_hsio_power_on, + .power_off = imx_hsio_power_off, + .set_mode = imx_hsio_set_mode, + .set_speed = imx_hsio_set_speed, + .owner = THIS_MODULE, +}; + +static const struct imx_hsio_drvdata imx8qxp_hsio_drvdata = { + .lane_num = 0x1, +}; + +static const struct imx_hsio_drvdata imx8qm_hsio_drvdata = { + .lane_num = 0x3, +}; + +static const struct of_device_id imx_hsio_of_match[] = { + {.compatible = "fsl,imx8qm-hsio", .data = &imx8qm_hsio_drvdata}, + {.compatible = "fsl,imx8qxp-hsio", .data = &imx8qxp_hsio_drvdata}, + { }, +}; +MODULE_DEVICE_TABLE(of, imx_hsio_of_match); + +static struct phy *imx_hsio_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct imx_hsio_priv *priv = dev_get_drvdata(dev); + int idx = args->args[0]; + int phy_type = args->args[1]; + int ctrl_index = args->args[2]; + + if (idx < 0 || idx >= priv->drvdata->lane_num) + return ERR_PTR(-EINVAL); + priv->lane[idx].idx = idx; + priv->lane[idx].phy_type = phy_type; + priv->lane[idx].ctrl_index = ctrl_index; + + return priv->lane[idx].phy; +} + +static int imx_hsio_probe(struct platform_device *pdev) +{ + int i; + void __iomem *off; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct imx_hsio_priv *priv; + struct phy_provider *provider; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dev = &pdev->dev; + priv->drvdata = of_device_get_match_data(dev); + + /* Get HSIO configuration mode */ + if (of_property_read_string(np, "fsl,hsio-cfg", &priv->hsio_cfg)) + priv->hsio_cfg = "pciea-pcieb-sata"; + /* Get PHY refclk pad mode */ + if (of_property_read_string(np, "fsl,refclk-pad-mode", + &priv->refclk_pad)) + priv->refclk_pad = NULL; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + off = devm_platform_ioremap_resource_byname(pdev, "phy"); + priv->phy = devm_regmap_init_mmio(dev, off, ®map_config); + if (IS_ERR(priv->phy)) + return dev_err_probe(dev, PTR_ERR(priv->phy), + "unable to find phy csr registers\n"); + + off = devm_platform_ioremap_resource_byname(pdev, "ctrl"); + priv->ctrl = devm_regmap_init_mmio(dev, off, ®map_config); + if (IS_ERR(priv->ctrl)) + return dev_err_probe(dev, PTR_ERR(priv->ctrl), + "unable to find ctrl csr registers\n"); + + off = devm_platform_ioremap_resource_byname(pdev, "misc"); + priv->misc = devm_regmap_init_mmio(dev, off, ®map_config); + if (IS_ERR(priv->misc)) + return dev_err_probe(dev, PTR_ERR(priv->misc), + "unable to find misc csr registers\n"); + + for (i = 0; i < priv->drvdata->lane_num; i++) { + struct imx_hsio_lane *lane = &priv->lane[i]; + struct phy *phy; + + phy = devm_phy_create(&pdev->dev, NULL, &imx_hsio_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + lane->priv = priv; + lane->phy = phy; + lane->idx = i; + phy_set_drvdata(phy, lane); + } + + dev_set_drvdata(dev, priv); + dev_set_drvdata(&pdev->dev, priv); + + provider = devm_of_phy_provider_register(&pdev->dev, imx_hsio_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static struct platform_driver imx_hsio_driver = { + .probe = imx_hsio_probe, + .driver = { + .name = "imx8qm-hsio-phy", + .of_match_table = imx_hsio_of_match, + } +}; +module_platform_driver(imx_hsio_driver); + +MODULE_DESCRIPTION("FSL IMX8QM HSIO SERDES PHY driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c index 0ae052df3765..7aef2f59e8eb 100644 --- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c +++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c @@ -294,7 +294,7 @@ static int mixel_lvds_phy_reset(struct device *dev) } static struct phy *mixel_lvds_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mixel_lvds_phy_priv *priv = dev_get_drvdata(dev); unsigned int phy_id; @@ -433,12 +433,12 @@ static const struct of_device_id mixel_lvds_phy_of_match[] = { MODULE_DEVICE_TABLE(of, mixel_lvds_phy_of_match); static struct platform_driver mixel_lvds_phy_driver = { - .probe = mixel_lvds_phy_probe, - .remove_new = mixel_lvds_phy_remove, + .probe = mixel_lvds_phy_probe, + .remove = mixel_lvds_phy_remove, .driver = { .pm = &mixel_lvds_phy_pm_ops, .name = "mixel-lvds-phy", - .of_match_table = mixel_lvds_phy_of_match, + .of_match_table = mixel_lvds_phy_of_match, } }; module_platform_driver(mixel_lvds_phy_driver); diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index e2187767ce00..f7994e8983c8 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -556,7 +556,7 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane) } static struct phy *lynx_28g_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct lynx_28g_priv *priv = dev_get_drvdata(dev); int idx = args->args[0]; @@ -631,9 +631,9 @@ static const struct of_device_id lynx_28g_of_match_table[] = { MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table); static struct platform_driver lynx_28g_driver = { - .probe = lynx_28g_probe, - .remove_new = lynx_28g_remove, - .driver = { + .probe = lynx_28g_probe, + .remove = lynx_28g_remove, + .driver = { .name = "lynx-28g", .of_match_table = lynx_28g_of_match_table, }, diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c new file mode 100644 index 000000000000..191c282246d9 --- /dev/null +++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c @@ -0,0 +1,740 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + * Copyright 2022 Pengutronix, Lucas Stach <kernel@pengutronix.de> + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#define PHY_REG(reg) (reg * 4) + +#define REG01_PMS_P_MASK GENMASK(3, 0) +#define REG03_PMS_S_MASK GENMASK(7, 4) +#define REG12_CK_DIV_MASK GENMASK(5, 4) + +#define REG13_TG_CODE_LOW_MASK GENMASK(7, 0) + +#define REG14_TOL_MASK GENMASK(7, 4) +#define REG14_RP_CODE_MASK GENMASK(3, 1) +#define REG14_TG_CODE_HIGH_MASK GENMASK(0, 0) + +#define REG21_SEL_TX_CK_INV BIT(7) +#define REG21_PMS_S_MASK GENMASK(3, 0) +/* + * REG33 does not match the ref manual. According to Sandor Yu from NXP, + * "There is a doc issue on the i.MX8MP latest RM" + * REG33 is being used per guidance from Sandor + */ +#define REG33_MODE_SET_DONE BIT(7) +#define REG33_FIX_DA BIT(1) + +#define REG34_PHY_READY BIT(7) +#define REG34_PLL_LOCK BIT(6) +#define REG34_PHY_CLK_READY BIT(5) + +#ifndef MHZ +#define MHZ (1000UL * 1000UL) +#endif + +#define PHY_PLL_DIV_REGS_NUM 7 + +struct phy_config { + u32 pixclk; + u8 pll_div_regs[PHY_PLL_DIV_REGS_NUM]; +}; + +/* + * The calculated_phy_pll_cfg only handles integer divider for PMS, + * meaning the last four entries will be fixed, but the first three will + * be calculated by the PMS calculator. + */ +static struct phy_config calculated_phy_pll_cfg = { + .pixclk = 0, + .pll_div_regs = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }, +}; + +/* The lookup table contains values for which the fractional divder is used */ +static const struct phy_config phy_pll_cfg[] = { + { + .pixclk = 22250000, + .pll_div_regs = { 0xd1, 0x4b, 0xf1, 0x89, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 23750000, + .pll_div_regs = { 0xd1, 0x50, 0xf1, 0x86, 0x85, 0x80, 0x40 }, + }, { + .pixclk = 24024000, + .pll_div_regs = { 0xd1, 0x50, 0xf1, 0x99, 0x02, 0x80, 0x40 }, + }, { + .pixclk = 25175000, + .pll_div_regs = { 0xd1, 0x54, 0xfc, 0xcc, 0x91, 0x80, 0x40 }, + }, { + .pixclk = 26750000, + .pll_div_regs = { 0xd1, 0x5a, 0xf2, 0x89, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 27027000, + .pll_div_regs = { 0xd1, 0x5a, 0xf2, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 29500000, + .pll_div_regs = { 0xd1, 0x62, 0xf4, 0x95, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 30750000, + .pll_div_regs = { 0xd1, 0x66, 0xf4, 0x82, 0x01, 0x88, 0x45 }, + }, { + .pixclk = 30888000, + .pll_div_regs = { 0xd1, 0x66, 0xf4, 0x99, 0x18, 0x88, 0x45 }, + }, { + .pixclk = 33750000, + .pll_div_regs = { 0xd1, 0x70, 0xf4, 0x82, 0x01, 0x80, 0x40 }, + }, { + .pixclk = 35000000, + .pll_div_regs = { 0xd1, 0x58, 0xb8, 0x8b, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 36036000, + .pll_div_regs = { 0xd1, 0x5a, 0xb2, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 43243200, + .pll_div_regs = { 0xd1, 0x5a, 0x92, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 44500000, + .pll_div_regs = { 0xd1, 0x5c, 0x92, 0x98, 0x11, 0x84, 0x41 }, + }, { + .pixclk = 47000000, + .pll_div_regs = { 0xd1, 0x62, 0x94, 0x95, 0x82, 0x80, 0x40 }, + }, { + .pixclk = 47500000, + .pll_div_regs = { 0xd1, 0x63, 0x96, 0xa1, 0x82, 0x80, 0x40 }, + }, { + .pixclk = 50349650, + .pll_div_regs = { 0xd1, 0x54, 0x7c, 0xc3, 0x8f, 0x80, 0x40 }, + }, { + .pixclk = 53250000, + .pll_div_regs = { 0xd1, 0x58, 0x72, 0x84, 0x03, 0x82, 0x41 }, + }, { + .pixclk = 53500000, + .pll_div_regs = { 0xd1, 0x5a, 0x72, 0x89, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 54054000, + .pll_div_regs = { 0xd1, 0x5a, 0x72, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 59000000, + .pll_div_regs = { 0xd1, 0x62, 0x74, 0x95, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 59340659, + .pll_div_regs = { 0xd1, 0x62, 0x74, 0xdb, 0x52, 0x88, 0x47 }, + }, { + .pixclk = 61500000, + .pll_div_regs = { 0xd1, 0x66, 0x74, 0x82, 0x01, 0x88, 0x45 }, + }, { + .pixclk = 63500000, + .pll_div_regs = { 0xd1, 0x69, 0x74, 0x89, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 67500000, + .pll_div_regs = { 0xd1, 0x54, 0x52, 0x87, 0x03, 0x80, 0x40 }, + }, { + .pixclk = 70000000, + .pll_div_regs = { 0xd1, 0x58, 0x58, 0x8b, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 72072000, + .pll_div_regs = { 0xd1, 0x5a, 0x52, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 74176000, + .pll_div_regs = { 0xd1, 0x5d, 0x58, 0xdb, 0xA2, 0x88, 0x41 }, + }, { + .pixclk = 74250000, + .pll_div_regs = { 0xd1, 0x5c, 0x52, 0x90, 0x0d, 0x84, 0x41 }, + }, { + .pixclk = 78500000, + .pll_div_regs = { 0xd1, 0x62, 0x54, 0x87, 0x01, 0x80, 0x40 }, + }, { + .pixclk = 82000000, + .pll_div_regs = { 0xd1, 0x66, 0x54, 0x82, 0x01, 0x88, 0x45 }, + }, { + .pixclk = 82500000, + .pll_div_regs = { 0xd1, 0x67, 0x54, 0x88, 0x01, 0x90, 0x49 }, + }, { + .pixclk = 89000000, + .pll_div_regs = { 0xd1, 0x70, 0x54, 0x84, 0x83, 0x80, 0x40 }, + }, { + .pixclk = 90000000, + .pll_div_regs = { 0xd1, 0x70, 0x54, 0x82, 0x01, 0x80, 0x40 }, + }, { + .pixclk = 94000000, + .pll_div_regs = { 0xd1, 0x4e, 0x32, 0xa7, 0x10, 0x80, 0x40 }, + }, { + .pixclk = 95000000, + .pll_div_regs = { 0xd1, 0x50, 0x31, 0x86, 0x85, 0x80, 0x40 }, + }, { + .pixclk = 98901099, + .pll_div_regs = { 0xd1, 0x52, 0x3a, 0xdb, 0x4c, 0x88, 0x47 }, + }, { + .pixclk = 99000000, + .pll_div_regs = { 0xd1, 0x52, 0x32, 0x82, 0x01, 0x88, 0x47 }, + }, { + .pixclk = 100699300, + .pll_div_regs = { 0xd1, 0x54, 0x3c, 0xc3, 0x8f, 0x80, 0x40 }, + }, { + .pixclk = 102500000, + .pll_div_regs = { 0xd1, 0x55, 0x32, 0x8c, 0x05, 0x90, 0x4b }, + }, { + .pixclk = 104750000, + .pll_div_regs = { 0xd1, 0x57, 0x32, 0x98, 0x07, 0x90, 0x49 }, + }, { + .pixclk = 106500000, + .pll_div_regs = { 0xd1, 0x58, 0x32, 0x84, 0x03, 0x82, 0x41 }, + }, { + .pixclk = 107000000, + .pll_div_regs = { 0xd1, 0x5a, 0x32, 0x89, 0x88, 0x80, 0x40 }, + }, { + .pixclk = 108108000, + .pll_div_regs = { 0xd1, 0x5a, 0x32, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 118000000, + .pll_div_regs = { 0xd1, 0x62, 0x34, 0x95, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 123000000, + .pll_div_regs = { 0xd1, 0x66, 0x34, 0x82, 0x01, 0x88, 0x45 }, + }, { + .pixclk = 127000000, + .pll_div_regs = { 0xd1, 0x69, 0x34, 0x89, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 135000000, + .pll_div_regs = { 0xd1, 0x70, 0x34, 0x82, 0x01, 0x80, 0x40 }, + }, { + .pixclk = 135580000, + .pll_div_regs = { 0xd1, 0x71, 0x39, 0xe9, 0x82, 0x9c, 0x5b }, + }, { + .pixclk = 137520000, + .pll_div_regs = { 0xd1, 0x72, 0x38, 0x99, 0x10, 0x85, 0x41 }, + }, { + .pixclk = 138750000, + .pll_div_regs = { 0xd1, 0x73, 0x35, 0x88, 0x05, 0x90, 0x4d }, + }, { + .pixclk = 140000000, + .pll_div_regs = { 0xd1, 0x75, 0x36, 0xa7, 0x90, 0x80, 0x40 }, + }, { + .pixclk = 148352000, + .pll_div_regs = { 0xd1, 0x7b, 0x35, 0xdb, 0x39, 0x90, 0x45 }, + }, { + .pixclk = 148500000, + .pll_div_regs = { 0xd1, 0x7b, 0x35, 0x84, 0x03, 0x90, 0x45 }, + }, { + .pixclk = 154000000, + .pll_div_regs = { 0xd1, 0x40, 0x18, 0x83, 0x01, 0x00, 0x40 }, + }, { + .pixclk = 157000000, + .pll_div_regs = { 0xd1, 0x41, 0x11, 0xa7, 0x14, 0x80, 0x40 }, + }, { + .pixclk = 160000000, + .pll_div_regs = { 0xd1, 0x42, 0x12, 0xa1, 0x20, 0x80, 0x40 }, + }, { + .pixclk = 162000000, + .pll_div_regs = { 0xd1, 0x43, 0x18, 0x8b, 0x08, 0x96, 0x55 }, + }, { + .pixclk = 164000000, + .pll_div_regs = { 0xd1, 0x45, 0x11, 0x83, 0x82, 0x90, 0x4b }, + }, { + .pixclk = 165000000, + .pll_div_regs = { 0xd1, 0x45, 0x11, 0x84, 0x81, 0x90, 0x4b }, + }, { + .pixclk = 185625000, + .pll_div_regs = { 0xd1, 0x4e, 0x12, 0x9a, 0x95, 0x80, 0x40 }, + }, { + .pixclk = 188000000, + .pll_div_regs = { 0xd1, 0x4e, 0x12, 0xa7, 0x10, 0x80, 0x40 }, + }, { + .pixclk = 198000000, + .pll_div_regs = { 0xd1, 0x52, 0x12, 0x82, 0x01, 0x88, 0x47 }, + }, { + .pixclk = 205000000, + .pll_div_regs = { 0xd1, 0x55, 0x12, 0x8c, 0x05, 0x90, 0x4b }, + }, { + .pixclk = 209500000, + .pll_div_regs = { 0xd1, 0x57, 0x12, 0x98, 0x07, 0x90, 0x49 }, + }, { + .pixclk = 213000000, + .pll_div_regs = { 0xd1, 0x58, 0x12, 0x84, 0x03, 0x82, 0x41 }, + }, { + .pixclk = 216216000, + .pll_div_regs = { 0xd1, 0x5a, 0x12, 0xfd, 0x0c, 0x80, 0x40 }, + }, { + .pixclk = 254000000, + .pll_div_regs = { 0xd1, 0x69, 0x14, 0x89, 0x08, 0x80, 0x40 }, + }, { + .pixclk = 277500000, + .pll_div_regs = { 0xd1, 0x73, 0x15, 0x88, 0x05, 0x90, 0x4d }, + }, { + .pixclk = 297000000, + .pll_div_regs = { 0xd1, 0x7b, 0x15, 0x84, 0x03, 0x90, 0x45 }, + }, +}; + +struct reg_settings { + u8 reg; + u8 val; +}; + +static const struct reg_settings common_phy_cfg[] = { + { PHY_REG(0), 0x00 }, + /* PHY_REG(1-7) pix clk specific */ + { PHY_REG(8), 0x4f }, { PHY_REG(9), 0x30 }, + { PHY_REG(10), 0x33 }, { PHY_REG(11), 0x65 }, + /* REG12 pixclk specific */ + /* REG13 pixclk specific */ + /* REG14 pixclk specific */ + { PHY_REG(15), 0x80 }, { PHY_REG(16), 0x6c }, + { PHY_REG(17), 0xf2 }, { PHY_REG(18), 0x67 }, + { PHY_REG(19), 0x00 }, { PHY_REG(20), 0x10 }, + /* REG21 pixclk specific */ + { PHY_REG(22), 0x30 }, { PHY_REG(23), 0x32 }, + { PHY_REG(24), 0x60 }, { PHY_REG(25), 0x8f }, + { PHY_REG(26), 0x00 }, { PHY_REG(27), 0x00 }, + { PHY_REG(28), 0x08 }, { PHY_REG(29), 0x00 }, + { PHY_REG(30), 0x00 }, { PHY_REG(31), 0x00 }, + { PHY_REG(32), 0x00 }, { PHY_REG(33), 0x80 }, + { PHY_REG(34), 0x00 }, { PHY_REG(35), 0x00 }, + { PHY_REG(36), 0x00 }, { PHY_REG(37), 0x00 }, + { PHY_REG(38), 0x00 }, { PHY_REG(39), 0x00 }, + { PHY_REG(40), 0x00 }, { PHY_REG(41), 0xe0 }, + { PHY_REG(42), 0x83 }, { PHY_REG(43), 0x0f }, + { PHY_REG(44), 0x3E }, { PHY_REG(45), 0xf8 }, + { PHY_REG(46), 0x00 }, { PHY_REG(47), 0x00 } +}; + +struct fsl_samsung_hdmi_phy { + struct device *dev; + void __iomem *regs; + struct clk *apbclk; + struct clk *refclk; + + /* clk provider */ + struct clk_hw hw; + const struct phy_config *cur_cfg; +}; + +static inline struct fsl_samsung_hdmi_phy * +to_fsl_samsung_hdmi_phy(struct clk_hw *hw) +{ + return container_of(hw, struct fsl_samsung_hdmi_phy, hw); +} + +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 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; + } + + 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) + * is based on reference manual register description of PHY_REG13 + * (13.10.3.1.14.2): + * 1st) Calculate int_pllclk which is determinded by FLD_CK_DIV + * 2nd) Increase resolution to avoid rounding issues + * 3th) Do the div (256 / Freq. of int_pllclk) * 24 + * 4th) Reduce the resolution and always round up since the NXP + * settings rounding up always too. TODO: Check if that is + * correct. + */ + + 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), + phy->regs + PHY_REG(13)); + writeb(FIELD_PREP(REG14_TOL_MASK, 2) | + 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) +{ + unsigned long best_freq = 0; + u32 min_delta = 0xffffffff; + u8 _p, best_p; + u16 _m, best_m; + u8 _s, best_s; + + /* + * Figure 13-78 of the reference manual states the PLL should be TMDS x 5 + * while the TMDS_CLKO should be the PLL / 5. So to calculate the PLL, + * take the pix clock x 5, then return the value of the PLL / 5. + */ + fout *= 5; + + /* The ref manual states the values of 'P' range from 1 to 11 */ + for (_p = 1; _p <= 11; ++_p) { + for (_s = 1; _s <= 16; ++_s) { + u64 tmp; + u32 delta; + + /* s must be one or even */ + if (_s > 1 && (_s & 0x01) == 1) + _s++; + + /* _s cannot be 14 per the TRM */ + if (_s == 14) + continue; + + /* + * 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); + if (tmp > 255) + continue; + _m = tmp; + + /* + * Rev 2 of the Ref Manual states the + * VCO can range between 750MHz and + * 3GHz. The VCO is assumed to be + * Fvco = (M * f_ref) / P, + * where f_ref is 24MHz. + */ + tmp = div64_ul((u64)_m * 24 * MHZ, _p); + if (tmp < 750 * MHZ || + tmp > 3000 * MHZ) + continue; + + /* Final frequency after post-divider */ + do_div(tmp, _s); + + delta = abs(fout - tmp); + if (delta < min_delta) { + best_p = _p; + best_s = _s; + best_m = _m; + 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; + *s = best_s; + } + + return best_freq / 5; +} + +static int fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy, + const struct phy_config *cfg) +{ + int i, ret; + u8 val; + + phy->cur_cfg = cfg; + + /* HDMI PHY init */ + writeb(REG33_FIX_DA, phy->regs + PHY_REG(33)); + + /* common PHY registers */ + for (i = 0; i < ARRAY_SIZE(common_phy_cfg); i++) + writeb(common_phy_cfg[i].val, phy->regs + common_phy_cfg[i].reg); + + /* set individual PLL registers PHY_REG1 ... PHY_REG7 */ + for (i = 0; i < PHY_PLL_DIV_REGS_NUM; i++) + writeb(cfg->pll_div_regs[i], phy->regs + PHY_REG(1) + i * 4); + + /* High nibble of PHY_REG3 and low nibble of PHY_REG21 both contain 'S' */ + writeb(REG21_SEL_TX_CK_INV | FIELD_PREP(REG21_PMS_S_MASK, + cfg->pll_div_regs[2] >> 4), phy->regs + PHY_REG(21)); + + 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)); + + ret = readb_poll_timeout(phy->regs + PHY_REG(34), val, + val & REG34_PLL_LOCK, 50, 20000); + if (ret) + dev_err(phy->dev, "PLL failed to lock\n"); + + return ret; +} + +static unsigned long phy_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); + + if (!phy->cur_cfg) + return 74250000; + + return phy->cur_cfg->pixclk; +} + +/* Helper function to lookup the available fractional-divider rate */ +static const struct phy_config *fsl_samsung_hdmi_phy_lookup_rate(unsigned long rate) +{ + int i; + + /* Search the lookup table */ + for (i = ARRAY_SIZE(phy_pll_cfg) - 1; i >= 0; i--) + if (phy_pll_cfg[i].pixclk <= rate) + break; + + /* If there is an exact match, or the array has been searched, return the value*/ + if (phy_pll_cfg[i].pixclk == rate || i + 1 > ARRAY_SIZE(phy_pll_cfg) - 1) + return &phy_pll_cfg[i]; + + /* See if the next entry is closer to nominal than this one */ + return (abs((long) rate - (long) phy_pll_cfg[i].pixclk) < + abs((long) rate - (long) phy_pll_cfg[i+1].pixclk) ? + &phy_pll_cfg[i] : &phy_pll_cfg[i+1]); +} + +static void fsl_samsung_hdmi_calculate_phy(struct phy_config *cal_phy, unsigned long rate, + u8 p, u16 m, u8 s) +{ + cal_phy->pixclk = rate; + cal_phy->pll_div_regs[0] = FIELD_PREP(REG01_PMS_P_MASK, p); + cal_phy->pll_div_regs[1] = m; + cal_phy->pll_div_regs[2] = FIELD_PREP(REG03_PMS_S_MASK, s-1); + /* pll_div_regs 3-6 are fixed and pre-defined already */ +} + +static +const struct phy_config *fsl_samsung_hdmi_phy_find_settings(struct fsl_samsung_hdmi_phy *phy, + unsigned long rate) +{ + const struct phy_config *fract_div_phy; + u32 int_div_clk; + u16 m; + u8 p, s; + + /* If the clock is out of range return error instead of searching */ + if (rate > 297000000 || rate < 22250000) + return NULL; + + /* Search the fractional divider lookup table */ + fract_div_phy = fsl_samsung_hdmi_phy_lookup_rate(rate); + if (fract_div_phy->pixclk == rate) { + dev_dbg(phy->dev, "fractional divider match = %u\n", fract_div_phy->pixclk); + return fract_div_phy; + } + + /* Calculate the integer divider */ + int_div_clk = fsl_samsung_hdmi_phy_find_pms(rate, &p, &m, &s); + fsl_samsung_hdmi_calculate_phy(&calculated_phy_pll_cfg, int_div_clk, p, m, s); + if (int_div_clk == rate) { + dev_dbg(phy->dev, "integer divider match = %u\n", calculated_phy_pll_cfg.pixclk); + return &calculated_phy_pll_cfg; + } + + /* Calculate the absolute value of the differences and return whichever is closest */ + if (abs((long)rate - (long)int_div_clk) < + abs((long)rate - (long)fract_div_phy->pixclk)) { + dev_dbg(phy->dev, "integer divider = %u\n", calculated_phy_pll_cfg.pixclk); + return &calculated_phy_pll_cfg; + } + + dev_dbg(phy->dev, "fractional divider = %u\n", phy->cur_cfg->pixclk); + + return fract_div_phy; +} + +static long fsl_samsung_hdmi_phy_clk_round_rate(struct clk_hw *hw, + unsigned long rate, unsigned long *parent_rate) +{ + struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); + const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy, rate); + + if (target_settings == NULL) + return -EINVAL; + + dev_dbg(phy->dev, "round_rate, closest rate = %u\n", target_settings->pixclk); + return target_settings->pixclk; +} + +static int fsl_samsung_hdmi_phy_clk_set_rate(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate) +{ + struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); + const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy, rate); + + if (target_settings == NULL) + return -EINVAL; + + dev_dbg(phy->dev, "set_rate, closest rate = %u\n", target_settings->pixclk); + + return fsl_samsung_hdmi_phy_configure(phy, target_settings); +} + +static const struct clk_ops phy_clk_ops = { + .recalc_rate = phy_clk_recalc_rate, + .round_rate = fsl_samsung_hdmi_phy_clk_round_rate, + .set_rate = fsl_samsung_hdmi_phy_clk_set_rate, +}; + +static int phy_clk_register(struct fsl_samsung_hdmi_phy *phy) +{ + struct device *dev = phy->dev; + struct device_node *np = dev->of_node; + struct clk_init_data init; + const char *parent_name; + struct clk *phyclk; + int ret; + + parent_name = __clk_get_name(phy->refclk); + + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = 0; + init.name = "hdmi_pclk"; + init.ops = &phy_clk_ops; + + phy->hw.init = &init; + + phyclk = devm_clk_register(dev, &phy->hw); + if (IS_ERR(phyclk)) + return dev_err_probe(dev, PTR_ERR(phyclk), + "failed to register clock\n"); + + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, phyclk); + if (ret) + return dev_err_probe(dev, ret, + "failed to register clock provider\n"); + + return 0; +} + +static int fsl_samsung_hdmi_phy_probe(struct platform_device *pdev) +{ + struct fsl_samsung_hdmi_phy *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->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->regs)) + return PTR_ERR(phy->regs); + + 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"); + + phy->refclk = devm_clk_get(phy->dev, "ref"); + if (IS_ERR(phy->refclk)) + return dev_err_probe(phy->dev, PTR_ERR(phy->refclk), + "failed to get ref clk\n"); + + pm_runtime_get_noresume(phy->dev); + pm_runtime_set_active(phy->dev); + pm_runtime_enable(phy->dev); + + ret = phy_clk_register(phy); + if (ret) { + dev_err(&pdev->dev, "register clk failed\n"); + goto register_clk_failed; + } + + pm_runtime_put(phy->dev); + + return 0; + +register_clk_failed: + return ret; +} + +static void fsl_samsung_hdmi_phy_remove(struct platform_device *pdev) +{ + of_clk_del_provider(pdev->dev.of_node); +} + +static int __maybe_unused fsl_samsung_hdmi_phy_suspend(struct device *dev) +{ + struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev); + + clk_disable_unprepare(phy->apbclk); + + return 0; +} + +static int __maybe_unused fsl_samsung_hdmi_phy_resume(struct device *dev) +{ + struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev); + int ret = 0; + + ret = clk_prepare_enable(phy->apbclk); + if (ret) { + dev_err(phy->dev, "failed to enable apbclk\n"); + return ret; + } + + if (phy->cur_cfg) + ret = fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); + + return ret; + +} + +static DEFINE_RUNTIME_DEV_PM_OPS(fsl_samsung_hdmi_phy_pm_ops, + fsl_samsung_hdmi_phy_suspend, + fsl_samsung_hdmi_phy_resume, NULL); + +static const struct of_device_id fsl_samsung_hdmi_phy_of_match[] = { + { + .compatible = "fsl,imx8mp-hdmi-phy", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, fsl_samsung_hdmi_phy_of_match); + +static struct platform_driver fsl_samsung_hdmi_phy_driver = { + .probe = fsl_samsung_hdmi_phy_probe, + .remove = fsl_samsung_hdmi_phy_remove, + .driver = { + .name = "fsl-samsung-hdmi-phy", + .of_match_table = fsl_samsung_hdmi_phy_of_match, + .pm = pm_ptr(&fsl_samsung_hdmi_phy_pm_ops), + }, +}; +module_platform_driver(fsl_samsung_hdmi_phy_driver); + +MODULE_AUTHOR("Sandor Yu <Sandor.yu@nxp.com>"); +MODULE_DESCRIPTION("SAMSUNG HDMI 2.0 Transmitter PHY Driver"); +MODULE_LICENSE("GPL"); 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/hisilicon/phy-hisi-inno-usb2.c b/drivers/phy/hisilicon/phy-hisi-inno-usb2.c index c138cd4807d6..c843923252aa 100644 --- a/drivers/phy/hisilicon/phy-hisi-inno-usb2.c +++ b/drivers/phy/hisilicon/phy-hisi-inno-usb2.c @@ -138,7 +138,6 @@ static int hisi_inno_phy_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct hisi_inno_phy_priv *priv; struct phy_provider *provider; - struct device_node *child; int i = 0; int ret; @@ -162,24 +161,20 @@ static int hisi_inno_phy_probe(struct platform_device *pdev) priv->type = (uintptr_t) of_device_get_match_data(dev); - for_each_child_of_node(np, child) { + for_each_child_of_node_scoped(np, child) { struct reset_control *rst; struct phy *phy; rst = of_reset_control_get_exclusive(child, NULL); - if (IS_ERR(rst)) { - of_node_put(child); + if (IS_ERR(rst)) return PTR_ERR(rst); - } priv->ports[i].utmi_rst = rst; priv->ports[i].priv = priv; phy = devm_phy_create(dev, child, &hisi_inno_phy_ops); - if (IS_ERR(phy)) { - of_node_put(child); + if (IS_ERR(phy)) return PTR_ERR(phy); - } phy_set_bus_width(phy, 8); phy_set_drvdata(phy, &priv->ports[i]); @@ -187,7 +182,6 @@ static int hisi_inno_phy_probe(struct platform_device *pdev) if (i >= INNO_PHY_PORT_NUM) { dev_warn(dev, "Support %d ports in maximum\n", i); - of_node_put(child); break; } } diff --git a/drivers/phy/hisilicon/phy-histb-combphy.c b/drivers/phy/hisilicon/phy-histb-combphy.c index c44588fd5a53..7436dcae3981 100644 --- a/drivers/phy/hisilicon/phy-histb-combphy.c +++ b/drivers/phy/hisilicon/phy-histb-combphy.c @@ -163,7 +163,7 @@ static const struct phy_ops histb_combphy_ops = { }; static struct phy *histb_combphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct histb_combphy_priv *priv = dev_get_drvdata(dev); struct histb_combphy_mode *mode = &priv->mode; diff --git a/drivers/phy/intel/phy-intel-lgm-combo.c b/drivers/phy/intel/phy-intel-lgm-combo.c index d32e267c0001..9ee3cf61cdd0 100644 --- a/drivers/phy/intel/phy-intel-lgm-combo.c +++ b/drivers/phy/intel/phy-intel-lgm-combo.c @@ -508,7 +508,7 @@ static const struct phy_ops intel_cbphy_ops = { }; static struct phy *intel_cbphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct intel_combo_phy *cbphy = dev_get_drvdata(dev); u32 iphy_id; @@ -605,7 +605,7 @@ static const struct of_device_id of_intel_cbphy_match[] = { static struct platform_driver intel_cbphy_driver = { .probe = intel_cbphy_probe, - .remove_new = intel_cbphy_remove, + .remove = intel_cbphy_remove, .driver = { .name = "intel-combo-phy", .of_match_table = of_intel_cbphy_match, diff --git a/drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c b/drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c index ef93bf2cba10..406a87c8b759 100644 --- a/drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c +++ b/drivers/phy/lantiq/phy-lantiq-vrx200-pcie.c @@ -358,7 +358,7 @@ static const struct phy_ops ltq_vrx200_pcie_phy_ops = { }; static struct phy *ltq_vrx200_pcie_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct ltq_vrx200_pcie_phy_priv *priv = dev_get_drvdata(dev); unsigned int mode; diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig index bdb87c976243..bccd72dccb77 100644 --- a/drivers/phy/marvell/Kconfig +++ b/drivers/phy/marvell/Kconfig @@ -29,7 +29,7 @@ config PHY_MVEBU_A3700_COMPHY depends on ARCH_MVEBU || COMPILE_TEST depends on OF depends on HAVE_ARM_SMCCC - default y + default ARCH_MVEBU select GENERIC_PHY help This driver allows to control the comphy, a hardware block providing @@ -40,7 +40,7 @@ config PHY_MVEBU_A3700_UTMI tristate "Marvell A3700 UTMI driver" depends on ARCH_MVEBU || COMPILE_TEST depends on OF - default y + default ARCH_MVEBU select GENERIC_PHY help Enable this to support Marvell A3700 UTMI PHY driver. diff --git a/drivers/phy/marvell/phy-armada375-usb2.c b/drivers/phy/marvell/phy-armada375-usb2.c index b141e3cd8a94..3731f9b25655 100644 --- a/drivers/phy/marvell/phy-armada375-usb2.c +++ b/drivers/phy/marvell/phy-armada375-usb2.c @@ -61,7 +61,7 @@ static const struct phy_ops armada375_usb_phy_ops = { * USB3 case it still optional and we use ENODEV. */ static struct phy *armada375_usb_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct armada375_cluster_phy *cluster_phy = dev_get_drvdata(dev); diff --git a/drivers/phy/marvell/phy-armada38x-comphy.c b/drivers/phy/marvell/phy-armada38x-comphy.c index b7d99861526a..5063361b0120 100644 --- a/drivers/phy/marvell/phy-armada38x-comphy.c +++ b/drivers/phy/marvell/phy-armada38x-comphy.c @@ -47,8 +47,13 @@ struct a38x_comphy { struct a38x_comphy_lane lane[MAX_A38X_COMPHY]; }; +/* + * Map serdes lanes and gbe ports to serdes mux configuration values: + * row index = serdes lane, + * column index = gbe port number. + */ static const u8 gbe_mux[MAX_A38X_COMPHY][MAX_A38X_PORTS] = { - { 0, 0, 0 }, + { 3, 0, 0 }, { 4, 5, 0 }, { 0, 4, 0 }, { 0, 0, 4 }, @@ -155,7 +160,7 @@ static const struct phy_ops a38x_comphy_ops = { }; static struct phy *a38x_comphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct a38x_comphy_lane *lane; struct phy *phy; diff --git a/drivers/phy/marvell/phy-berlin-sata.c b/drivers/phy/marvell/phy-berlin-sata.c index f972d78372ea..c90e2867900c 100644 --- a/drivers/phy/marvell/phy-berlin-sata.c +++ b/drivers/phy/marvell/phy-berlin-sata.c @@ -155,7 +155,7 @@ static int phy_berlin_sata_power_off(struct phy *phy) } static struct phy *phy_berlin_sata_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct phy_berlin_priv *priv = dev_get_drvdata(dev); int i; diff --git a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c index 24c3371e2bb2..1d1db1737422 100644 --- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c +++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c @@ -603,7 +603,7 @@ static void comphy_gbe_phy_init(struct mvebu_a3700_comphy_lane *lane, u16 val; fix_idx = 0; - for (addr = 0; addr < 512; addr++) { + for (addr = 0; addr < ARRAY_SIZE(gbe_phy_init); addr++) { /* * All PHY register values are defined in full for 3.125Gbps * SERDES speed. The values required for 1.25 Gbps are almost @@ -611,11 +611,12 @@ static void comphy_gbe_phy_init(struct mvebu_a3700_comphy_lane *lane, * comparison to 3.125 Gbps values. These register values are * stored in "gbe_phy_init_fix" array. */ - if (!is_1gbps && gbe_phy_init_fix[fix_idx].addr == addr) { + if (!is_1gbps && + fix_idx < ARRAY_SIZE(gbe_phy_init_fix) && + gbe_phy_init_fix[fix_idx].addr == addr) { /* Use new value */ val = gbe_phy_init_fix[fix_idx].value; - if (fix_idx < ARRAY_SIZE(gbe_phy_init_fix)) - fix_idx++; + fix_idx++; } else { val = gbe_phy_init[addr]; } @@ -1213,7 +1214,7 @@ static const struct phy_ops mvebu_a3700_comphy_ops = { }; static struct phy *mvebu_a3700_comphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mvebu_a3700_comphy_lane *lane; unsigned int port; diff --git a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c index b0dd13366598..71f9c14fb50d 100644 --- a/drivers/phy/marvell/phy-mvebu-cp110-comphy.c +++ b/drivers/phy/marvell/phy-mvebu-cp110-comphy.c @@ -244,8 +244,8 @@ static const struct mvebu_comphy_conf mvebu_comphy_cp110_modes[] = { GEN_CONF(4, 1, PHY_MODE_USB_HOST_SS, COMPHY_FW_MODE_USB3H), GEN_CONF(4, 1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE), ETH_CONF(4, 1, PHY_INTERFACE_MODE_SGMII, 0x1, COMPHY_FW_MODE_SGMII), - ETH_CONF(4, 1, PHY_INTERFACE_MODE_2500BASEX, -1, COMPHY_FW_MODE_2500BASEX), - ETH_CONF(4, 1, PHY_INTERFACE_MODE_5GBASER, -1, COMPHY_FW_MODE_XFI), + ETH_CONF(4, 1, PHY_INTERFACE_MODE_2500BASEX, 0x1, COMPHY_FW_MODE_2500BASEX), + ETH_CONF(4, 1, PHY_INTERFACE_MODE_5GBASER, 0x1, COMPHY_FW_MODE_XFI), ETH_CONF(4, 1, PHY_INTERFACE_MODE_10GBASER, -1, COMPHY_FW_MODE_XFI), /* lane 5 */ ETH_CONF(5, 1, PHY_INTERFACE_MODE_RXAUI, 0x2, COMPHY_FW_MODE_RXAUI), @@ -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); @@ -917,7 +917,7 @@ static const struct phy_ops mvebu_comphy_ops = { }; static struct phy *mvebu_comphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mvebu_comphy_lane *lane; struct phy *phy; diff --git a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c index 4922a5f3327d..59903f86b13f 100644 --- a/drivers/phy/marvell/phy-mvebu-cp110-utmi.c +++ b/drivers/phy/marvell/phy-mvebu-cp110-utmi.c @@ -62,6 +62,8 @@ #define SQ_AMP_CAL_MASK GENMASK(2, 0) #define SQ_AMP_CAL_VAL 1 #define SQ_AMP_CAL_EN BIT(3) +#define UTMI_DIG_CTRL1_REG 0x20 +#define SWAP_DPDM BIT(15) #define UTMI_CTRL_STATUS0_REG 0x24 #define SUSPENDM BIT(22) #define TEST_SEL BIT(25) @@ -99,11 +101,13 @@ struct mvebu_cp110_utmi { * @priv: PHY driver data * @id: PHY port ID * @dr_mode: PHY connection: USB_DR_MODE_HOST or USB_DR_MODE_PERIPHERAL + * @swap_dx: whether to swap d+/d- signals */ struct mvebu_cp110_utmi_port { struct mvebu_cp110_utmi *priv; u32 id; enum usb_dr_mode dr_mode; + bool swap_dx; }; static void mvebu_cp110_utmi_port_setup(struct mvebu_cp110_utmi_port *port) @@ -159,6 +163,13 @@ static void mvebu_cp110_utmi_port_setup(struct mvebu_cp110_utmi_port *port) reg &= ~(VDAT_MASK | VSRC_MASK); reg |= (VDAT_VAL << VDAT_OFFSET) | (VSRC_VAL << VSRC_OFFSET); writel(reg, PORT_REGS(port) + UTMI_CHGDTC_CTRL_REG); + + /* Swap D+/D- */ + reg = readl(PORT_REGS(port) + UTMI_DIG_CTRL1_REG); + reg &= ~(SWAP_DPDM); + if (port->swap_dx) + reg |= SWAP_DPDM; + writel(reg, PORT_REGS(port) + UTMI_DIG_CTRL1_REG); } static int mvebu_cp110_utmi_phy_power_off(struct phy *phy) @@ -286,6 +297,7 @@ static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev) struct phy_provider *provider; struct device_node *child; u32 usb_devices = 0; + u32 swap_dx = 0; utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL); if (!utmi) @@ -345,6 +357,10 @@ static int mvebu_cp110_utmi_phy_probe(struct platform_device *pdev) } } + of_property_for_each_u32(dev->of_node, "swap-dx-lanes", swap_dx) + if (swap_dx == port_id) + port->swap_dx = 1; + /* Retrieve PHY capabilities */ utmi->ops = &mvebu_cp110_utmi_phy_ops; diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig index 3125ecb5d119..ba6461350951 100644 --- a/drivers/phy/mediatek/Kconfig +++ b/drivers/phy/mediatek/Kconfig @@ -13,6 +13,17 @@ config PHY_MTK_PCIE callback for PCIe GEN3 port, it supports software efuse initialization. +config PHY_MTK_XFI_TPHY + tristate "MediaTek 10GE SerDes XFI T-PHY driver" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Say 'Y' here to add support for MediaTek XFI T-PHY driver. + The driver provides access to the Ethernet SerDes T-PHY supporting + 1GE and 2.5GE modes via the LynxI PCS, and 5GE and 10GE modes + via the USXGMII PCS found in MediaTek SoCs with 10G Ethernet. + config PHY_MTK_TPHY tristate "MediaTek T-PHY Driver" depends on ARCH_MEDIATEK || COMPILE_TEST @@ -54,10 +65,23 @@ config PHY_MTK_HDMI depends on ARCH_MEDIATEK || COMPILE_TEST depends on COMMON_CLK depends on OF + depends on REGULATOR select GENERIC_PHY help Support HDMI PHY for Mediatek SoCs. +config PHY_MTK_MIPI_CSI_0_5 + tristate "MediaTek MIPI CSI CD-PHY v0.5 Driver" + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Enable this to support the MIPI CSI CD-PHY receiver version 0.5. + The driver supports multiple CSI cdphy ports simultaneously. + + To compile this driver as a module, choose M here: the + module will be called phy-mtk-mipi-csi-0-5. + config PHY_MTK_MIPI_DSI tristate "MediaTek MIPI-DSI Driver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile index c9a50395533e..1b8088df71e8 100644 --- a/drivers/phy/mediatek/Makefile +++ b/drivers/phy/mediatek/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_MTK_PCIE) += phy-mtk-pcie.o obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o +obj-$(CONFIG_PHY_MTK_XFI_TPHY) += phy-mtk-xfi-tphy.o phy-mtk-hdmi-drv-y := phy-mtk-hdmi.o phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt2701.o @@ -15,6 +16,8 @@ phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt8173.o phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt8195.o obj-$(CONFIG_PHY_MTK_HDMI) += phy-mtk-hdmi-drv.o +obj-$(CONFIG_PHY_MTK_MIPI_CSI_0_5) += phy-mtk-mipi-csi-0-5.o + phy-mtk-mipi-dsi-drv-y := phy-mtk-mipi-dsi.o phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8173.o phy-mtk-mipi-dsi-drv-y += phy-mtk-mipi-dsi-mt8183.o 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-mipi-csi-0-5-rx-reg.h b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5-rx-reg.h new file mode 100644 index 000000000000..97b4c27a1699 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5-rx-reg.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023, MediaTek Inc. + * Copyright (c) 2023, BayLibre Inc. + */ + +#ifndef __PHY_MTK_MIPI_CSI_V_0_5_RX_REG_H__ +#define __PHY_MTK_MIPI_CSI_V_0_5_RX_REG_H__ + +/* + * CSI1 and CSI2 are identical, and similar to CSI0. All CSIX macros are + * applicable to the three PHYs. Where differences exist, they are denoted by + * macro names using CSI0 and CSI1, the latter being applicable to CSI1 and + * CSI2 alike. + */ + +#define MIPI_RX_ANA00_CSIXA 0x0000 +#define RG_CSI0A_CPHY_EN BIT(0) +#define RG_CSIXA_EQ_PROTECT_EN BIT(1) +#define RG_CSIXA_BG_LPF_EN BIT(2) +#define RG_CSIXA_BG_CORE_EN BIT(3) +#define RG_CSIXA_DPHY_L0_CKMODE_EN BIT(5) +#define RG_CSIXA_DPHY_L0_CKSEL BIT(6) +#define RG_CSIXA_DPHY_L1_CKMODE_EN BIT(8) +#define RG_CSIXA_DPHY_L1_CKSEL BIT(9) +#define RG_CSIXA_DPHY_L2_CKMODE_EN BIT(11) +#define RG_CSIXA_DPHY_L2_CKSEL BIT(12) + +#define MIPI_RX_ANA18_CSIXA 0x0018 +#define RG_CSI0A_L0_T0AB_EQ_IS GENMASK(5, 4) +#define RG_CSI0A_L0_T0AB_EQ_BW GENMASK(7, 6) +#define RG_CSI0A_L1_T1AB_EQ_IS GENMASK(21, 20) +#define RG_CSI0A_L1_T1AB_EQ_BW GENMASK(23, 22) +#define RG_CSI0A_L2_T1BC_EQ_IS GENMASK(21, 20) +#define RG_CSI0A_L2_T1BC_EQ_BW GENMASK(23, 22) +#define RG_CSI1A_L0_EQ_IS GENMASK(5, 4) +#define RG_CSI1A_L0_EQ_BW GENMASK(7, 6) +#define RG_CSI1A_L1_EQ_IS GENMASK(21, 20) +#define RG_CSI1A_L1_EQ_BW GENMASK(23, 22) +#define RG_CSI1A_L2_EQ_IS GENMASK(5, 4) +#define RG_CSI1A_L2_EQ_BW GENMASK(7, 6) + +#define MIPI_RX_ANA1C_CSIXA 0x001c +#define MIPI_RX_ANA20_CSI0A 0x0020 + +#define MIPI_RX_ANA24_CSIXA 0x0024 +#define RG_CSIXA_RESERVE GENMASK(31, 24) + +#define MIPI_RX_ANA40_CSIXA 0x0040 +#define RG_CSIXA_CPHY_FMCK_SEL GENMASK(1, 0) +#define RG_CSIXA_ASYNC_OPTION GENMASK(7, 4) +#define RG_CSIXA_CPHY_SPARE GENMASK(31, 16) + +#define MIPI_RX_WRAPPER80_CSIXA 0x0080 +#define CSR_CSI_RST_MODE GENMASK(17, 16) + +#define MIPI_RX_ANAA8_CSIXA 0x00a8 +#define RG_CSIXA_CDPHY_L0_T0_BYTECK_INVERT BIT(0) +#define RG_CSIXA_DPHY_L1_BYTECK_INVERT BIT(1) +#define RG_CSIXA_CDPHY_L2_T1_BYTECK_INVERT BIT(2) + +#endif diff --git a/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c new file mode 100644 index 000000000000..058e1d926630 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-mipi-csi-0-5.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek MIPI CSI v0.5 driver + * + * Copyright (c) 2023, MediaTek Inc. + * Copyright (c) 2023, BayLibre Inc. + */ + +#include <dt-bindings/phy/phy.h> +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "phy-mtk-io.h" +#include "phy-mtk-mipi-csi-0-5-rx-reg.h" + +#define CSIXB_OFFSET 0x1000 + +struct mtk_mipi_cdphy_port { + struct device *dev; + void __iomem *base; + struct phy *phy; + u32 type; + u32 mode; + u32 num_lanes; +}; + +enum PHY_TYPE { + DPHY = 0, + CPHY, + CDPHY, +}; + +static void mtk_phy_csi_cdphy_ana_eq_tune(void __iomem *base) +{ + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_BW, 1); + mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_BW, 1); + mtk_phy_update_field(base + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_BW, 1); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI0A_L0_T0AB_EQ_BW, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI0A_L1_T1AB_EQ_BW, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA20_CSI0A, RG_CSI0A_L2_T1BC_EQ_BW, 1); +} + +static void mtk_phy_csi_dphy_ana_eq_tune(void __iomem *base) +{ + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_BW, 1); + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_BW, 1); + mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_IS, 1); + mtk_phy_update_field(base + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_BW, 1); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L0_EQ_BW, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA18_CSIXA, RG_CSI1A_L1_EQ_BW, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_IS, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA1C_CSIXA, RG_CSI1A_L2_EQ_BW, 1); +} + +static int mtk_mipi_phy_power_on(struct phy *phy) +{ + struct mtk_mipi_cdphy_port *port = phy_get_drvdata(phy); + void __iomem *base = port->base; + + /* + * The driver currently supports DPHY and CD-PHY phys, + * but the only mode supported is DPHY, + * so CD-PHY capable phys must be configured in DPHY mode + */ + if (port->type == CDPHY) { + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSI0A_CPHY_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, + RG_CSI0A_CPHY_EN, 0); + } + + /* + * Lane configuration: + * + * Only 4 data + 1 clock is supported for now with the following mapping: + * + * CSIXA_LNR0 --> D2 + * CSIXA_LNR1 --> D0 + * CSIXA_LNR2 --> C + * CSIXB_LNR0 --> D1 + * CSIXB_LNR1 --> D3 + */ + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L0_CKMODE_EN, 0); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L0_CKSEL, 1); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L1_CKMODE_EN, 0); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L1_CKSEL, 1); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L2_CKMODE_EN, 1); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L2_CKSEL, 1); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, + RG_CSIXA_DPHY_L0_CKMODE_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L0_CKSEL, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, + RG_CSIXA_DPHY_L1_CKMODE_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L1_CKSEL, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, + RG_CSIXA_DPHY_L2_CKMODE_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_DPHY_L2_CKSEL, 1); + + /* Byte clock invert */ + mtk_phy_update_field(base + MIPI_RX_ANAA8_CSIXA, RG_CSIXA_CDPHY_L0_T0_BYTECK_INVERT, 1); + mtk_phy_update_field(base + MIPI_RX_ANAA8_CSIXA, RG_CSIXA_DPHY_L1_BYTECK_INVERT, 1); + mtk_phy_update_field(base + MIPI_RX_ANAA8_CSIXA, RG_CSIXA_CDPHY_L2_T1_BYTECK_INVERT, 1); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANAA8_CSIXA, + RG_CSIXA_CDPHY_L0_T0_BYTECK_INVERT, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANAA8_CSIXA, + RG_CSIXA_DPHY_L1_BYTECK_INVERT, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANAA8_CSIXA, + RG_CSIXA_CDPHY_L2_T1_BYTECK_INVERT, 1); + + /* Start ANA EQ tuning */ + if (port->type == CDPHY) + mtk_phy_csi_cdphy_ana_eq_tune(base); + else + mtk_phy_csi_dphy_ana_eq_tune(base); + + /* End ANA EQ tuning */ + mtk_phy_set_bits(base + MIPI_RX_ANA40_CSIXA, 0x90); + + mtk_phy_update_field(base + MIPI_RX_ANA24_CSIXA, RG_CSIXA_RESERVE, 0x40); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA24_CSIXA, RG_CSIXA_RESERVE, 0x40); + mtk_phy_update_field(base + MIPI_RX_WRAPPER80_CSIXA, CSR_CSI_RST_MODE, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_WRAPPER80_CSIXA, CSR_CSI_RST_MODE, 0); + /* ANA power on */ + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 1); + usleep_range(20, 40); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 1); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 1); + + return 0; +} + +static int mtk_mipi_phy_power_off(struct phy *phy) +{ + struct mtk_mipi_cdphy_port *port = phy_get_drvdata(phy); + void __iomem *base = port->base; + + /* Disable MIPI BG. */ + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 0); + mtk_phy_update_field(base + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 0); + + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_CORE_EN, 0); + mtk_phy_update_field(base + CSIXB_OFFSET + MIPI_RX_ANA00_CSIXA, RG_CSIXA_BG_LPF_EN, 0); + + return 0; +} + +static struct phy *mtk_mipi_cdphy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct mtk_mipi_cdphy_port *priv = dev_get_drvdata(dev); + + /* + * If PHY is CD-PHY then we need to get the operating mode + * For now only D-PHY mode is supported + */ + if (priv->type == CDPHY) { + if (args->args_count != 1) { + dev_err(dev, "invalid number of arguments\n"); + return ERR_PTR(-EINVAL); + } + switch (args->args[0]) { + case PHY_TYPE_DPHY: + priv->mode = DPHY; + if (priv->num_lanes != 4) { + dev_err(dev, "Only 4D1C mode is supported for now!\n"); + return ERR_PTR(-EINVAL); + } + break; + default: + dev_err(dev, "Unsupported PHY type: %i\n", args->args[0]); + return ERR_PTR(-EINVAL); + } + } else { + if (args->args_count) { + dev_err(dev, "invalid number of arguments\n"); + return ERR_PTR(-EINVAL); + } + priv->mode = DPHY; + } + + return priv->phy; +} + +static const struct phy_ops mtk_cdphy_ops = { + .power_on = mtk_mipi_phy_power_on, + .power_off = mtk_mipi_phy_power_off, + .owner = THIS_MODULE, +}; + +static int mtk_mipi_cdphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + struct mtk_mipi_cdphy_port *port; + struct phy *phy; + int ret; + u32 phy_type; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + dev_set_drvdata(dev, port); + + port->dev = dev; + + port->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(port->base)) + return PTR_ERR(port->base); + + ret = of_property_read_u32(dev->of_node, "num-lanes", &port->num_lanes); + if (ret) { + dev_err(dev, "Failed to read num-lanes property: %i\n", ret); + return ret; + } + + /* + * phy-type is optional, if not present, PHY is considered to be CD-PHY + */ + if (device_property_present(dev, "phy-type")) { + ret = of_property_read_u32(dev->of_node, "phy-type", &phy_type); + if (ret) { + dev_err(dev, "Failed to read phy-type property: %i\n", ret); + return ret; + } + switch (phy_type) { + case PHY_TYPE_DPHY: + port->type = DPHY; + break; + default: + dev_err(dev, "Unsupported PHY type: %i\n", phy_type); + return -EINVAL; + } + } else { + port->type = CDPHY; + } + + phy = devm_phy_create(dev, NULL, &mtk_cdphy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "Failed to create PHY: %ld\n", PTR_ERR(phy)); + return PTR_ERR(phy); + } + + port->phy = phy; + phy_set_drvdata(phy, port); + + phy_provider = devm_of_phy_provider_register(dev, mtk_mipi_cdphy_xlate); + if (IS_ERR(phy_provider)) { + dev_err(dev, "Failed to register PHY provider: %ld\n", + PTR_ERR(phy_provider)); + return PTR_ERR(phy_provider); + } + + return 0; +} + +static const struct of_device_id mtk_mipi_cdphy_of_match[] = { + { .compatible = "mediatek,mt8365-csi-rx" }, + { /* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, mtk_mipi_cdphy_of_match); + +static struct platform_driver mipi_cdphy_pdrv = { + .probe = mtk_mipi_cdphy_probe, + .driver = { + .name = "mtk-mipi-csi-0-5", + .of_match_table = mtk_mipi_cdphy_of_match, + }, +}; +module_platform_driver(mipi_cdphy_pdrv); + +MODULE_DESCRIPTION("MediaTek MIPI CSI CD-PHY v0.5 Driver"); +MODULE_AUTHOR("Louis Kuo <louis.kuo@mediatek.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index a4746f6cb8a1..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; @@ -1467,7 +1447,7 @@ static int mtk_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) } static struct phy *mtk_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mtk_tphy *tphy = dev_get_drvdata(dev); struct mtk_phy_instance *instance = NULL; @@ -1577,12 +1557,11 @@ static int mtk_tphy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *child_np; struct phy_provider *provider; struct resource *sif_res; struct mtk_tphy *tphy; struct resource res; - int port, retval; + int port; tphy = devm_kzalloc(dev, sizeof(*tphy), GFP_KERNEL); if (!tphy) @@ -1623,25 +1602,23 @@ static int mtk_tphy_probe(struct platform_device *pdev) } port = 0; - for_each_child_of_node(np, child_np) { + for_each_child_of_node_scoped(np, child_np) { struct mtk_phy_instance *instance; struct clk_bulk_data *clks; struct device *subdev; struct phy *phy; + int retval; instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL); - if (!instance) { - retval = -ENOMEM; - goto put_child; - } + if (!instance) + return -ENOMEM; tphy->phys[port] = instance; phy = devm_phy_create(dev, child_np, &mtk_tphy_ops); if (IS_ERR(phy)) { dev_err(dev, "failed to create phy\n"); - retval = PTR_ERR(phy); - goto put_child; + return PTR_ERR(phy); } subdev = &phy->dev; @@ -1649,14 +1626,12 @@ static int mtk_tphy_probe(struct platform_device *pdev) if (retval) { dev_err(subdev, "failed to get address resource(id-%d)\n", port); - goto put_child; + return retval; } instance->port_base = devm_ioremap_resource(subdev, &res); - if (IS_ERR(instance->port_base)) { - retval = PTR_ERR(instance->port_base); - goto put_child; - } + if (IS_ERR(instance->port_base)) + return PTR_ERR(instance->port_base); instance->phy = phy; instance->index = port; @@ -1668,19 +1643,16 @@ static int mtk_tphy_probe(struct platform_device *pdev) clks[1].id = "da_ref"; /* analog clock */ retval = devm_clk_bulk_get_optional(subdev, TPHY_CLKS_CNT, clks); if (retval) - goto put_child; + return retval; retval = phy_type_syscon_get(instance, child_np); if (retval) - goto put_child; + return retval; } provider = devm_of_phy_provider_register(dev, mtk_phy_xlate); return PTR_ERR_OR_ZERO(provider); -put_child: - of_node_put(child_np); - return retval; } static struct platform_driver mtk_tphy_driver = { diff --git a/drivers/phy/mediatek/phy-mtk-xfi-tphy.c b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c new file mode 100644 index 000000000000..1a0b7484f525 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c @@ -0,0 +1,451 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MediaTek 10GE SerDes XFI T-PHY driver + * + * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org> + * Bc-bocun Chen <bc-bocun.chen@mediatek.com> + * based on mtk_usxgmii.c and mtk_sgmii.c found in MediaTek's SDK (GPL-2.0) + * Copyright (c) 2022 MediaTek Inc. + * Author: Henry Yen <henry.yen@mediatek.com> + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/reset.h> +#include <linux/phy.h> +#include <linux/phy/phy.h> + +#include "phy-mtk-io.h" + +#define MTK_XFI_TPHY_NUM_CLOCKS 2 + +#define REG_DIG_GLB_70 0x0070 +#define XTP_PCS_RX_EQ_IN_PROGRESS(x) FIELD_PREP(GENMASK(25, 24), (x)) +#define XTP_PCS_MODE_MASK GENMASK(17, 16) +#define XTP_PCS_MODE(x) FIELD_PREP(GENMASK(17, 16), (x)) +#define XTP_PCS_RST_B BIT(15) +#define XTP_FRC_PCS_RST_B BIT(14) +#define XTP_PCS_PWD_SYNC_MASK GENMASK(13, 12) +#define XTP_PCS_PWD_SYNC(x) FIELD_PREP(XTP_PCS_PWD_SYNC_MASK, (x)) +#define XTP_PCS_PWD_ASYNC_MASK GENMASK(11, 10) +#define XTP_PCS_PWD_ASYNC(x) FIELD_PREP(XTP_PCS_PWD_ASYNC_MASK, (x)) +#define XTP_FRC_PCS_PWD_ASYNC BIT(8) +#define XTP_PCS_UPDT BIT(4) +#define XTP_PCS_IN_FR_RG BIT(0) + +#define REG_DIG_GLB_F4 0x00f4 +#define XFI_DPHY_PCS_SEL BIT(0) +#define XFI_DPHY_PCS_SEL_SGMII FIELD_PREP(XFI_DPHY_PCS_SEL, 1) +#define XFI_DPHY_PCS_SEL_USXGMII FIELD_PREP(XFI_DPHY_PCS_SEL, 0) +#define XFI_DPHY_AD_SGDT_FRC_EN BIT(5) + +#define REG_DIG_LN_TRX_40 0x3040 +#define XTP_LN_FRC_TX_DATA_EN BIT(29) +#define XTP_LN_TX_DATA_EN BIT(28) + +#define REG_DIG_LN_TRX_B0 0x30b0 +#define XTP_LN_FRC_TX_MACCK_EN BIT(5) +#define XTP_LN_TX_MACCK_EN BIT(4) + +#define REG_ANA_GLB_D0 0x90d0 +#define XTP_GLB_USXGMII_SEL_MASK GENMASK(3, 1) +#define XTP_GLB_USXGMII_SEL(x) FIELD_PREP(GENMASK(3, 1), (x)) +#define XTP_GLB_USXGMII_EN BIT(0) + +/** + * struct mtk_xfi_tphy - run-time data of the XFI phy instance + * @base: IO memory area to access phy registers. + * @dev: Kernel device used to output prefixed debug info. + * @reset: Reset control corresponding to the phy instance. + * @clocks: All clocks required for the phy to operate. + * @da_war: Enables work-around for 10GBase-R mode. + */ +struct mtk_xfi_tphy { + void __iomem *base; + struct device *dev; + struct reset_control *reset; + struct clk_bulk_data clocks[MTK_XFI_TPHY_NUM_CLOCKS]; + bool da_war; +}; + +/** + * mtk_xfi_tphy_setup() - Setup phy for specified interface mode. + * @xfi_tphy: XFI phy instance. + * @interface: Ethernet interface mode + * + * The setup function is the condensed result of combining the 5 functions which + * setup the phy in MediaTek's GPL licensed public SDK sources. They can be found + * in mtk_sgmii.c[1] as well as mtk_usxgmii.c[2]. + * + * Many magic values have been replaced by register and bit definitions, however, + * that has not been possible in all cases. While the vendor driver uses a + * sequence of 32-bit writes, here we try to only modify the actually required + * bits. + * + * [1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/b72d6cba92bf9e29fb035c03052fa1e86664a25b/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_sgmii.c + * + * [2]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/dec96a1d9b82cdcda4a56453fd0b453d4cab4b85/21.02/files/target/linux/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c + */ +static void mtk_xfi_tphy_setup(struct mtk_xfi_tphy *xfi_tphy, + phy_interface_t interface) +{ + bool is_1g, is_2p5g, is_5g, is_10g, da_war, use_lynxi_pcs; + + /* shorthands for specific clock speeds depending on interface mode */ + is_1g = interface == PHY_INTERFACE_MODE_1000BASEX || + interface == PHY_INTERFACE_MODE_SGMII; + is_2p5g = interface == PHY_INTERFACE_MODE_2500BASEX; + is_5g = interface == PHY_INTERFACE_MODE_5GBASER; + is_10g = interface == PHY_INTERFACE_MODE_10GBASER || + interface == PHY_INTERFACE_MODE_USXGMII; + + /* Is overriding 10GBase-R tuning value required? */ + da_war = xfi_tphy->da_war && (interface == PHY_INTERFACE_MODE_10GBASER); + + /* configure input mux to either + * - USXGMII PCS (64b/66b coding) for 5G/10G + * - LynxI PCS (8b/10b coding) for 1G/2.5G + */ + use_lynxi_pcs = is_1g || is_2p5g; + + dev_dbg(xfi_tphy->dev, "setting up for mode %s\n", phy_modes(interface)); + + /* Setup PLL setting */ + mtk_phy_update_bits(xfi_tphy->base + 0x9024, 0x100000, is_10g ? 0x0 : 0x100000); + mtk_phy_update_bits(xfi_tphy->base + 0x2020, 0x202000, is_5g ? 0x202000 : 0x0); + mtk_phy_update_bits(xfi_tphy->base + 0x2030, 0x500, is_1g ? 0x0 : 0x500); + mtk_phy_update_bits(xfi_tphy->base + 0x2034, 0xa00, is_1g ? 0x0 : 0xa00); + mtk_phy_update_bits(xfi_tphy->base + 0x2040, 0x340000, is_1g ? 0x200000 : 0x140000); + + /* Setup RXFE BW setting */ + mtk_phy_update_bits(xfi_tphy->base + 0x50f0, 0xc10, is_1g ? 0x410 : is_5g ? 0x800 : 0x400); + mtk_phy_update_bits(xfi_tphy->base + 0x50e0, 0x4000, is_5g ? 0x0 : 0x4000); + + /* Setup RX CDR setting */ + mtk_phy_update_bits(xfi_tphy->base + 0x506c, 0x30000, is_5g ? 0x0 : 0x30000); + mtk_phy_update_bits(xfi_tphy->base + 0x5070, 0x670000, is_5g ? 0x620000 : 0x50000); + mtk_phy_update_bits(xfi_tphy->base + 0x5074, 0x180000, is_5g ? 0x180000 : 0x0); + mtk_phy_update_bits(xfi_tphy->base + 0x5078, 0xf000400, is_5g ? 0x8000000 : + 0x7000400); + mtk_phy_update_bits(xfi_tphy->base + 0x507c, 0x5000500, is_5g ? 0x4000400 : + 0x1000100); + mtk_phy_update_bits(xfi_tphy->base + 0x5080, 0x1410, is_1g ? 0x400 : is_5g ? 0x1010 : 0x0); + mtk_phy_update_bits(xfi_tphy->base + 0x5084, 0x30300, is_1g ? 0x30300 : + is_5g ? 0x30100 : + 0x100); + mtk_phy_update_bits(xfi_tphy->base + 0x5088, 0x60200, is_1g ? 0x20200 : + is_5g ? 0x40000 : + 0x20000); + + /* Setting RXFE adaptation range setting */ + mtk_phy_update_bits(xfi_tphy->base + 0x50e4, 0xc0000, is_5g ? 0x0 : 0xc0000); + mtk_phy_update_bits(xfi_tphy->base + 0x50e8, 0x40000, is_5g ? 0x0 : 0x40000); + mtk_phy_update_bits(xfi_tphy->base + 0x50ec, 0xa00, is_1g ? 0x200 : 0x800); + mtk_phy_update_bits(xfi_tphy->base + 0x50a8, 0xee0000, is_5g ? 0x800000 : + 0x6e0000); + mtk_phy_update_bits(xfi_tphy->base + 0x6004, 0x190000, is_5g ? 0x0 : 0x190000); + + if (is_10g) + writel(0x01423342, xfi_tphy->base + 0x00f8); + else if (is_5g) + writel(0x00a132a1, xfi_tphy->base + 0x00f8); + else if (is_2p5g) + writel(0x009c329c, xfi_tphy->base + 0x00f8); + else + writel(0x00fa32fa, xfi_tphy->base + 0x00f8); + + /* Force SGDT_OUT off and select PCS */ + mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_F4, + XFI_DPHY_AD_SGDT_FRC_EN | XFI_DPHY_PCS_SEL, + XFI_DPHY_AD_SGDT_FRC_EN | + (use_lynxi_pcs ? XFI_DPHY_PCS_SEL_SGMII : + XFI_DPHY_PCS_SEL_USXGMII)); + + /* Force GLB_CKDET_OUT */ + mtk_phy_set_bits(xfi_tphy->base + 0x0030, 0xc00); + + /* Force AEQ on */ + writel(XTP_PCS_RX_EQ_IN_PROGRESS(2) | XTP_PCS_PWD_SYNC(2) | XTP_PCS_PWD_ASYNC(2), + xfi_tphy->base + REG_DIG_GLB_70); + + usleep_range(1, 5); + writel(XTP_LN_FRC_TX_DATA_EN, xfi_tphy->base + REG_DIG_LN_TRX_40); + + /* Setup TX DA default value */ + mtk_phy_update_bits(xfi_tphy->base + 0x30b0, 0x30, 0x20); + writel(0x00008a01, xfi_tphy->base + 0x3028); + writel(0x0000a884, xfi_tphy->base + 0x302c); + writel(0x00083002, xfi_tphy->base + 0x3024); + + /* Setup RG default value */ + if (use_lynxi_pcs) { + writel(0x00011110, xfi_tphy->base + 0x3010); + writel(0x40704000, xfi_tphy->base + 0x3048); + } else { + writel(0x00022220, xfi_tphy->base + 0x3010); + writel(0x0f020a01, xfi_tphy->base + 0x5064); + writel(0x06100600, xfi_tphy->base + 0x50b4); + if (interface == PHY_INTERFACE_MODE_USXGMII) + writel(0x40704000, xfi_tphy->base + 0x3048); + else + writel(0x47684100, xfi_tphy->base + 0x3048); + } + + if (is_1g) + writel(0x0000c000, xfi_tphy->base + 0x3064); + + /* Setup RX EQ initial value */ + mtk_phy_update_bits(xfi_tphy->base + 0x3050, 0xa8000000, + (interface != PHY_INTERFACE_MODE_10GBASER) ? 0xa8000000 : 0x0); + mtk_phy_update_bits(xfi_tphy->base + 0x3054, 0xaa, + (interface != PHY_INTERFACE_MODE_10GBASER) ? 0xaa : 0x0); + + if (!use_lynxi_pcs) + writel(0x00000f00, xfi_tphy->base + 0x306c); + else if (is_2p5g) + writel(0x22000f00, xfi_tphy->base + 0x306c); + else + writel(0x20200f00, xfi_tphy->base + 0x306c); + + mtk_phy_update_bits(xfi_tphy->base + 0xa008, 0x10000, da_war ? 0x10000 : 0x0); + + mtk_phy_update_bits(xfi_tphy->base + 0xa060, 0x50000, use_lynxi_pcs ? 0x50000 : 0x40000); + + /* Setup PHYA speed */ + mtk_phy_update_bits(xfi_tphy->base + REG_ANA_GLB_D0, + XTP_GLB_USXGMII_SEL_MASK | XTP_GLB_USXGMII_EN, + is_10g ? XTP_GLB_USXGMII_SEL(0) : + is_5g ? XTP_GLB_USXGMII_SEL(1) : + is_2p5g ? XTP_GLB_USXGMII_SEL(2) : + XTP_GLB_USXGMII_SEL(3)); + mtk_phy_set_bits(xfi_tphy->base + REG_ANA_GLB_D0, XTP_GLB_USXGMII_EN); + + /* Release reset */ + mtk_phy_set_bits(xfi_tphy->base + REG_DIG_GLB_70, + XTP_PCS_RST_B | XTP_FRC_PCS_RST_B); + usleep_range(150, 500); + + /* Switch to P0 */ + mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_70, + XTP_PCS_IN_FR_RG | + XTP_FRC_PCS_PWD_ASYNC | + XTP_PCS_PWD_ASYNC_MASK | + XTP_PCS_PWD_SYNC_MASK | + XTP_PCS_UPDT, + XTP_PCS_IN_FR_RG | + XTP_FRC_PCS_PWD_ASYNC | + XTP_PCS_UPDT); + usleep_range(1, 5); + + mtk_phy_clear_bits(xfi_tphy->base + REG_DIG_GLB_70, XTP_PCS_UPDT); + usleep_range(15, 50); + + if (use_lynxi_pcs) { + /* Switch to Gen2 */ + mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_70, + XTP_PCS_MODE_MASK | XTP_PCS_UPDT, + XTP_PCS_MODE(1) | XTP_PCS_UPDT); + } else { + /* Switch to Gen3 */ + mtk_phy_update_bits(xfi_tphy->base + REG_DIG_GLB_70, + XTP_PCS_MODE_MASK | XTP_PCS_UPDT, + XTP_PCS_MODE(2) | XTP_PCS_UPDT); + } + usleep_range(1, 5); + + mtk_phy_clear_bits(xfi_tphy->base + REG_DIG_GLB_70, XTP_PCS_UPDT); + + usleep_range(100, 500); + + /* Enable MAC CK */ + mtk_phy_set_bits(xfi_tphy->base + REG_DIG_LN_TRX_B0, XTP_LN_TX_MACCK_EN); + mtk_phy_clear_bits(xfi_tphy->base + REG_DIG_GLB_F4, XFI_DPHY_AD_SGDT_FRC_EN); + + /* Enable TX data */ + mtk_phy_set_bits(xfi_tphy->base + REG_DIG_LN_TRX_40, + XTP_LN_FRC_TX_DATA_EN | XTP_LN_TX_DATA_EN); + usleep_range(400, 1000); +} + +/** + * mtk_xfi_tphy_set_mode() - Setup phy for specified interface mode. + * + * @phy: Phy instance. + * @mode: Only PHY_MODE_ETHERNET is supported. + * @submode: An Ethernet interface mode. + * + * Validate selected mode and call function mtk_xfi_tphy_setup(). + * + * Return: + * * %0 - OK + * * %-EINVAL - invalid mode + */ +static int mtk_xfi_tphy_set_mode(struct phy *phy, enum phy_mode mode, int + submode) +{ + struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy); + + if (mode != PHY_MODE_ETHERNET) + return -EINVAL; + + switch (submode) { + case PHY_INTERFACE_MODE_1000BASEX: + case PHY_INTERFACE_MODE_2500BASEX: + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_5GBASER: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_USXGMII: + mtk_xfi_tphy_setup(xfi_tphy, submode); + return 0; + default: + return -EINVAL; + } +} + +/** + * mtk_xfi_tphy_reset() - Reset the phy. + * + * @phy: Phy instance. + * + * Reset the phy using the external reset controller. + * + * Return: + * %0 - OK + */ +static int mtk_xfi_tphy_reset(struct phy *phy) +{ + struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy); + + reset_control_assert(xfi_tphy->reset); + usleep_range(100, 500); + reset_control_deassert(xfi_tphy->reset); + usleep_range(1, 10); + + return 0; +} + +/** + * mtk_xfi_tphy_power_on() - Power-on the phy. + * + * @phy: Phy instance. + * + * Prepare and enable all clocks required for the phy to operate. + * + * Return: + * See clk_bulk_prepare_enable(). + */ +static int mtk_xfi_tphy_power_on(struct phy *phy) +{ + struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy); + + return clk_bulk_prepare_enable(MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks); +} + +/** + * mtk_xfi_tphy_power_off() - Power-off the phy. + * + * @phy: Phy instance. + * + * Disable and unprepare all clocks previously enabled. + * + * Return: + * See clk_bulk_prepare_disable(). + */ +static int mtk_xfi_tphy_power_off(struct phy *phy) +{ + struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy); + + clk_bulk_disable_unprepare(MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks); + + return 0; +} + +static const struct phy_ops mtk_xfi_tphy_ops = { + .power_on = mtk_xfi_tphy_power_on, + .power_off = mtk_xfi_tphy_power_off, + .set_mode = mtk_xfi_tphy_set_mode, + .reset = mtk_xfi_tphy_reset, + .owner = THIS_MODULE, +}; + +/** + * mtk_xfi_tphy_probe() - Probe phy instance from Device Tree. + * @pdev: Matching platform device. + * + * The probe function gets IO resource, clocks, reset controller and + * whether the DA work-around for 10GBase-R is required from Device Tree and + * allocates memory for holding that information in a struct mtk_xfi_tphy. + * + * Return: + * * %0 - OK + * * %-ENODEV - Missing associated Device Tree node (should never happen). + * * %-ENOMEM - Out of memory. + * * Any error value which devm_platform_ioremap_resource(), + * devm_clk_bulk_get(), devm_reset_control_get_exclusive(), + * devm_phy_create() or devm_of_phy_provider_register() may return. + */ +static int mtk_xfi_tphy_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct phy_provider *phy_provider; + struct mtk_xfi_tphy *xfi_tphy; + struct phy *phy; + int ret; + + if (!np) + return -ENODEV; + + xfi_tphy = devm_kzalloc(&pdev->dev, sizeof(*xfi_tphy), GFP_KERNEL); + if (!xfi_tphy) + return -ENOMEM; + + xfi_tphy->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(xfi_tphy->base)) + return PTR_ERR(xfi_tphy->base); + + xfi_tphy->dev = &pdev->dev; + xfi_tphy->clocks[0].id = "topxtal"; + xfi_tphy->clocks[1].id = "xfipll"; + ret = devm_clk_bulk_get(&pdev->dev, MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks); + if (ret) + return ret; + + xfi_tphy->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(xfi_tphy->reset)) + return PTR_ERR(xfi_tphy->reset); + + xfi_tphy->da_war = of_property_read_bool(np, "mediatek,usxgmii-performance-errata"); + + phy = devm_phy_create(&pdev->dev, NULL, &mtk_xfi_tphy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy_set_drvdata(phy, xfi_tphy); + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id mtk_xfi_tphy_match[] = { + { .compatible = "mediatek,mt7988-xfi-tphy", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mtk_xfi_tphy_match); + +static struct platform_driver mtk_xfi_tphy_driver = { + .probe = mtk_xfi_tphy_probe, + .driver = { + .name = "mtk-xfi-tphy", + .of_match_table = mtk_xfi_tphy_match, + }, +}; +module_platform_driver(mtk_xfi_tphy_driver); + +MODULE_DESCRIPTION("MediaTek 10GE SerDes XFI T-PHY driver"); +MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>"); +MODULE_AUTHOR("Bc-bocun Chen <bc-bocun.chen@mediatek.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/mediatek/phy-mtk-xsphy.c b/drivers/phy/mediatek/phy-mtk-xsphy.c index b222fbbd71d1..c0ddb9273cc3 100644 --- a/drivers/phy/mediatek/phy-mtk-xsphy.c +++ b/drivers/phy/mediatek/phy-mtk-xsphy.c @@ -11,10 +11,12 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/iopoll.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of_address.h> #include <linux/phy/phy.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include "phy-mtk-io.h" @@ -81,12 +83,22 @@ #define XSP_SR_COEF_DIVISOR 1000 #define XSP_FM_DET_CYCLE_CNT 1024 +/* PHY switch between pcie/usb3/sgmii */ +#define USB_PHY_SWITCH_CTRL 0x0 +#define RG_PHY_SW_TYPE GENMASK(3, 0) +#define RG_PHY_SW_PCIE 0x0 +#define RG_PHY_SW_USB3 0x1 +#define RG_PHY_SW_SGMII 0x2 + struct xsphy_instance { struct phy *phy; void __iomem *port_base; struct clk *ref_clk; /* reference clock of anolog phy */ u32 index; u32 type; + struct regmap *type_sw; + u32 type_sw_reg; + u32 type_sw_index; /* only for HQA test */ int efuse_intr; int efuse_tx_imp; @@ -259,6 +271,10 @@ static void phy_parse_property(struct mtk_xsphy *xsphy, inst->efuse_intr, inst->efuse_tx_imp, inst->efuse_rx_imp); break; + case PHY_TYPE_PCIE: + case PHY_TYPE_SGMII: + /* nothing to do */ + break; default: dev_err(xsphy->dev, "incompatible phy type\n"); return; @@ -305,6 +321,62 @@ static void u3_phy_props_set(struct mtk_xsphy *xsphy, RG_XTP_LN0_RX_IMPSEL, inst->efuse_rx_imp); } +/* type switch for usb3/pcie/sgmii */ +static int phy_type_syscon_get(struct xsphy_instance *instance, + struct device_node *dn) +{ + struct of_phandle_args args; + int ret; + + /* type switch function is optional */ + if (!of_property_present(dn, "mediatek,syscon-type")) + return 0; + + ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type", + 2, 0, &args); + if (ret) + return ret; + + instance->type_sw_reg = args.args[0]; + instance->type_sw_index = args.args[1] & 0x3; /* <=3 */ + instance->type_sw = syscon_node_to_regmap(args.np); + of_node_put(args.np); + dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n", + instance->type_sw_reg, instance->type_sw_index); + + return PTR_ERR_OR_ZERO(instance->type_sw); +} + +static int phy_type_set(struct xsphy_instance *instance) +{ + int type; + u32 offset; + + if (!instance->type_sw) + return 0; + + switch (instance->type) { + case PHY_TYPE_USB3: + type = RG_PHY_SW_USB3; + break; + case PHY_TYPE_PCIE: + type = RG_PHY_SW_PCIE; + break; + case PHY_TYPE_SGMII: + type = RG_PHY_SW_SGMII; + break; + case PHY_TYPE_USB2: + default: + return 0; + } + + offset = instance->type_sw_index * BITS_PER_BYTE; + regmap_update_bits(instance->type_sw, instance->type_sw_reg, + RG_PHY_SW_TYPE << offset, type << offset); + + return 0; +} + static int mtk_phy_init(struct phy *phy) { struct xsphy_instance *inst = phy_get_drvdata(phy); @@ -325,6 +397,10 @@ static int mtk_phy_init(struct phy *phy) case PHY_TYPE_USB3: u3_phy_props_set(xsphy, inst); break; + case PHY_TYPE_PCIE: + case PHY_TYPE_SGMII: + /* nothing to do, only used to set type */ + break; default: dev_err(xsphy->dev, "incompatible phy type\n"); clk_disable_unprepare(inst->ref_clk); @@ -378,7 +454,7 @@ static int mtk_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) } static struct phy *mtk_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mtk_xsphy *xsphy = dev_get_drvdata(dev); struct xsphy_instance *inst = NULL; @@ -403,12 +479,15 @@ static struct phy *mtk_phy_xlate(struct device *dev, inst->type = args->args[0]; if (!(inst->type == PHY_TYPE_USB2 || - inst->type == PHY_TYPE_USB3)) { + inst->type == PHY_TYPE_USB3 || + inst->type == PHY_TYPE_PCIE || + inst->type == PHY_TYPE_SGMII)) { dev_err(dev, "unsupported phy type: %d\n", inst->type); return ERR_PTR(-EINVAL); } phy_parse_property(xsphy, inst); + phy_type_set(inst); return inst->phy; } @@ -432,12 +511,11 @@ static int mtk_xsphy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; - struct device_node *child_np; struct phy_provider *provider; struct resource *glb_res; struct mtk_xsphy *xsphy; struct resource res; - int port, retval; + int port; xsphy = devm_kzalloc(dev, sizeof(*xsphy), GFP_KERNEL); if (!xsphy) @@ -471,37 +549,34 @@ static int mtk_xsphy_probe(struct platform_device *pdev) device_property_read_u32(dev, "mediatek,src-coef", &xsphy->src_coef); port = 0; - for_each_child_of_node(np, child_np) { + for_each_child_of_node_scoped(np, child_np) { struct xsphy_instance *inst; struct phy *phy; + int retval; inst = devm_kzalloc(dev, sizeof(*inst), GFP_KERNEL); - if (!inst) { - retval = -ENOMEM; - goto put_child; - } + if (!inst) + return -ENOMEM; xsphy->phys[port] = inst; phy = devm_phy_create(dev, child_np, &mtk_xsphy_ops); if (IS_ERR(phy)) { dev_err(dev, "failed to create phy\n"); - retval = PTR_ERR(phy); - goto put_child; + return PTR_ERR(phy); } retval = of_address_to_resource(child_np, 0, &res); if (retval) { dev_err(dev, "failed to get address resource(id-%d)\n", port); - goto put_child; + return retval; } inst->port_base = devm_ioremap_resource(&phy->dev, &res); if (IS_ERR(inst->port_base)) { dev_err(dev, "failed to remap phy regs\n"); - retval = PTR_ERR(inst->port_base); - goto put_child; + return PTR_ERR(inst->port_base); } inst->phy = phy; @@ -512,17 +587,16 @@ static int mtk_xsphy_probe(struct platform_device *pdev) inst->ref_clk = devm_clk_get(&phy->dev, "ref"); if (IS_ERR(inst->ref_clk)) { dev_err(dev, "failed to get ref_clk(id-%d)\n", port); - retval = PTR_ERR(inst->ref_clk); - goto put_child; + return PTR_ERR(inst->ref_clk); } + + retval = phy_type_syscon_get(inst, child_np); + if (retval) + return retval; } provider = devm_of_phy_provider_register(dev, mtk_phy_xlate); return PTR_ERR_OR_ZERO(provider); - -put_child: - of_node_put(child_np); - return retval; } static struct platform_driver mtk_xsphy_driver = { 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/microchip/lan966x_serdes.c b/drivers/phy/microchip/lan966x_serdes.c index c1a41b6cd29b..835e369cdfc5 100644 --- a/drivers/phy/microchip/lan966x_serdes.c +++ b/drivers/phy/microchip/lan966x_serdes.c @@ -96,6 +96,8 @@ static const struct serdes_mux lan966x_serdes_muxes[] = { SERDES_MUX_SGMII(SERDES6G(1), 3, HSIO_HW_CFG_SD6G_1_CFG, HSIO_HW_CFG_SD6G_1_CFG_SET(1)), + SERDES_MUX_SGMII(SERDES6G(2), 4, 0, 0), + SERDES_MUX_RGMII(RGMII(0), 2, HSIO_HW_CFG_RGMII_0_CFG | HSIO_HW_CFG_RGMII_ENA | HSIO_HW_CFG_GMII_ENA, @@ -516,7 +518,7 @@ static const struct phy_ops serdes_ops = { }; static struct phy *serdes_simple_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct serdes_ctrl *ctrl = dev_get_drvdata(dev); unsigned int port, idx, i; diff --git a/drivers/phy/microchip/sparx5_serdes.c b/drivers/phy/microchip/sparx5_serdes.c index 01bd5ea620c5..320cf5b50a8c 100644 --- a/drivers/phy/microchip/sparx5_serdes.c +++ b/drivers/phy/microchip/sparx5_serdes.c @@ -21,23 +21,33 @@ #include "sparx5_serdes.h" -#define SPX5_CMU_MAX 14 - #define SPX5_SERDES_10G_START 13 #define SPX5_SERDES_25G_START 25 #define SPX5_SERDES_6G10G_CNT SPX5_SERDES_25G_START +#define LAN969X_SERDES_10G_CNT 10 + /* Optimal power settings from GUC */ #define SPX5_SERDES_QUIET_MODE_VAL 0x01ef4e0c -enum sparx5_10g28cmu_mode { - SPX5_SD10G28_CMU_MAIN = 0, - SPX5_SD10G28_CMU_AUX1 = 1, - SPX5_SD10G28_CMU_AUX2 = 3, - SPX5_SD10G28_CMU_NONE = 4, - SPX5_SD10G28_CMU_MAX, +/* Register target sizes */ +const unsigned int sparx5_serdes_tsize[TSIZE_LAST] = { + [TC_SD10G_LANE] = 12, + [TC_SD_CMU] = 14, + [TC_SD_CMU_CFG] = 14, + [TC_SD_LANE] = 25, +}; + +const unsigned int lan969x_serdes_tsize[TSIZE_LAST] = { + [TC_SD10G_LANE] = 10, + [TC_SD_CMU] = 6, + [TC_SD_CMU_CFG] = 6, + [TC_SD_LANE] = 10, }; +/* Pointer to the register target size table */ +const unsigned int *tsize; + enum sparx5_sd25g28_mode_preset_type { SPX5_SD25G28_MODE_PRESET_25000, SPX5_SD25G28_MODE_PRESET_10000, @@ -1095,13 +1105,31 @@ static int sparx5_serdes_cmu_get(enum sparx5_10g28cmu_mode mode, int sd_index) return sparx5_serdes_cmu_map[mode][sd_index]; } +/* Map of 6G/10G serdes mode and index to CMU index. */ +static const int +lan969x_serdes_cmu_map[SPX5_SD10G28_CMU_MAX][LAN969X_SERDES_10G_CNT] = { + [SPX5_SD10G28_CMU_MAIN] = { 2, 2, 2, 2, 2, + 2, 2, 2, 5, 5 }, + [SPX5_SD10G28_CMU_AUX1] = { 0, 0, 3, 3, 3, + 3, 3, 3, 3, 3 }, + [SPX5_SD10G28_CMU_AUX2] = { 1, 1, 1, 1, 4, + 4, 4, 4, 4, 4 }, + [SPX5_SD10G28_CMU_NONE] = { 1, 1, 1, 1, 4, + 4, 4, 4, 4, 4 }, +}; + +static int lan969x_serdes_cmu_get(enum sparx5_10g28cmu_mode mode, int sd_index) +{ + return lan969x_serdes_cmu_map[mode][sd_index]; +} + static void sparx5_serdes_cmu_power_off(struct sparx5_serdes_private *priv) { void __iomem *cmu_inst, *cmu_cfg_inst; int i; /* Power down each CMU */ - for (i = 0; i < SPX5_CMU_MAX; i++) { + for (i = 0; i < priv->data->consts.cmu_max; i++) { cmu_inst = sdx5_inst_get(priv, TARGET_SD_CMU, i); cmu_cfg_inst = sdx5_inst_get(priv, TARGET_SD_CMU_CFG, i); @@ -1650,7 +1678,7 @@ static int sparx5_sd10g28_apply_params(struct sparx5_serdes_macro *macro, if (params->skip_cmu_cfg) return 0; - cmu_idx = sparx5_serdes_cmu_get(params->cmu_sel, lane_index); + cmu_idx = priv->data->ops.serdes_cmu_get(params->cmu_sel, macro->sidx); err = sparx5_cmu_cfg(priv, cmu_idx); if (err) return err; @@ -2183,6 +2211,10 @@ static int sparx5_serdes_clock_config(struct sparx5_serdes_macro *macro) { struct sparx5_serdes_private *priv = macro->priv; + /* Clock is auto-detected in 100Base-FX mode on lan969x */ + if (priv->data->type == SPX5_TARGET_LAN969X) + return 0; + if (macro->serdesmode == SPX5_SD_MODE_100FX) { u32 freq = priv->coreclock == 250000000 ? 2 : priv->coreclock == 500000000 ? 1 : 0; @@ -2297,10 +2329,12 @@ static int sparx5_serdes_set_speed(struct phy *phy, int speed) { struct sparx5_serdes_macro *macro = phy_get_drvdata(phy); - if (macro->sidx < SPX5_SERDES_10G_START && speed > SPEED_5000) - return -EINVAL; - if (macro->sidx < SPX5_SERDES_25G_START && speed > SPEED_10000) - return -EINVAL; + if (macro->priv->data->type == SPX5_TARGET_SPARX5) { + if (macro->sidx < SPX5_SERDES_10G_START && speed > SPEED_5000) + return -EINVAL; + if (macro->sidx < SPX5_SERDES_25G_START && speed > SPEED_10000) + return -EINVAL; + } if (speed != macro->speed) { macro->speed = speed; if (macro->serdesmode != SPX5_SD_MODE_NONE) @@ -2337,11 +2371,14 @@ static int sparx5_serdes_validate(struct phy *phy, enum phy_mode mode, if (macro->speed == 0) return -EINVAL; - if (macro->sidx < SPX5_SERDES_10G_START && macro->speed > SPEED_5000) - return -EINVAL; - if (macro->sidx < SPX5_SERDES_25G_START && macro->speed > SPEED_10000) - return -EINVAL; - + if (macro->priv->data->type == SPX5_TARGET_SPARX5) { + if (macro->sidx < SPX5_SERDES_10G_START && + macro->speed > SPEED_5000) + return -EINVAL; + if (macro->sidx < SPX5_SERDES_25G_START && + macro->speed > SPEED_10000) + return -EINVAL; + } switch (submode) { case PHY_INTERFACE_MODE_1000BASEX: if (macro->speed != SPEED_100 && /* This is for 100BASE-FX */ @@ -2375,6 +2412,26 @@ static const struct phy_ops sparx5_serdes_ops = { .owner = THIS_MODULE, }; +static void sparx5_serdes_type_set(struct sparx5_serdes_macro *macro, int sidx) +{ + if (sidx < SPX5_SERDES_10G_START) { + macro->serdestype = SPX5_SDT_6G; + macro->stpidx = macro->sidx; + } else if (sidx < SPX5_SERDES_25G_START) { + macro->serdestype = SPX5_SDT_10G; + macro->stpidx = macro->sidx - SPX5_SERDES_10G_START; + } else { + macro->serdestype = SPX5_SDT_25G; + macro->stpidx = macro->sidx - SPX5_SERDES_25G_START; + } +} + +static void lan969x_serdes_type_set(struct sparx5_serdes_macro *macro, int sidx) +{ + macro->serdestype = SPX5_SDT_10G; + macro->stpidx = macro->sidx; +} + static int sparx5_phy_create(struct sparx5_serdes_private *priv, int idx, struct phy **phy) { @@ -2391,16 +2448,8 @@ static int sparx5_phy_create(struct sparx5_serdes_private *priv, macro->sidx = idx; macro->priv = priv; macro->speed = SPEED_UNKNOWN; - if (idx < SPX5_SERDES_10G_START) { - macro->serdestype = SPX5_SDT_6G; - macro->stpidx = macro->sidx; - } else if (idx < SPX5_SERDES_25G_START) { - macro->serdestype = SPX5_SDT_10G; - macro->stpidx = macro->sidx - SPX5_SERDES_10G_START; - } else { - macro->serdestype = SPX5_SDT_25G; - macro->stpidx = macro->sidx - SPX5_SERDES_25G_START; - } + + priv->data->ops.serdes_type_set(macro, idx); phy_set_drvdata(*phy, macro); @@ -2507,9 +2556,74 @@ static struct sparx5_serdes_io_resource sparx5_serdes_iomap[] = { { TARGET_SD_LANE_25G + 7, 0x5c8000 }, /* 0x610dd0000: sd_lane_25g_32 */ }; +static const struct sparx5_serdes_io_resource lan969x_serdes_iomap[] = { + { TARGET_SD_CMU, 0x0 }, /* 0xe3410000 */ + { TARGET_SD_CMU + 1, 0x8000 }, /* 0xe3418000 */ + { TARGET_SD_CMU + 2, 0x10000 }, /* 0xe3420000 */ + { TARGET_SD_CMU + 3, 0x18000 }, /* 0xe3428000 */ + { TARGET_SD_CMU + 4, 0x20000 }, /* 0xe3430000 */ + { TARGET_SD_CMU + 5, 0x28000 }, /* 0xe3438000 */ + { TARGET_SD_CMU_CFG, 0x30000 }, /* 0xe3440000 */ + { TARGET_SD_CMU_CFG + 1, 0x38000 }, /* 0xe3448000 */ + { TARGET_SD_CMU_CFG + 2, 0x40000 }, /* 0xe3450000 */ + { TARGET_SD_CMU_CFG + 3, 0x48000 }, /* 0xe3458000 */ + { TARGET_SD_CMU_CFG + 4, 0x50000 }, /* 0xe3460000 */ + { TARGET_SD_CMU_CFG + 5, 0x58000 }, /* 0xe3468000 */ + { TARGET_SD10G_LANE, 0x60000 }, /* 0xe3470000 */ + { TARGET_SD10G_LANE + 1, 0x68000 }, /* 0xe3478000 */ + { TARGET_SD10G_LANE + 2, 0x70000 }, /* 0xe3480000 */ + { TARGET_SD10G_LANE + 3, 0x78000 }, /* 0xe3488000 */ + { TARGET_SD10G_LANE + 4, 0x80000 }, /* 0xe3490000 */ + { TARGET_SD10G_LANE + 5, 0x88000 }, /* 0xe3498000 */ + { TARGET_SD10G_LANE + 6, 0x90000 }, /* 0xe34a0000 */ + { TARGET_SD10G_LANE + 7, 0x98000 }, /* 0xe34a8000 */ + { TARGET_SD10G_LANE + 8, 0xa0000 }, /* 0xe34b0000 */ + { TARGET_SD10G_LANE + 9, 0xa8000 }, /* 0xe34b8000 */ + { TARGET_SD_LANE, 0x100000 }, /* 0xe3510000 */ + { TARGET_SD_LANE + 1, 0x108000 }, /* 0xe3518000 */ + { TARGET_SD_LANE + 2, 0x110000 }, /* 0xe3520000 */ + { TARGET_SD_LANE + 3, 0x118000 }, /* 0xe3528000 */ + { TARGET_SD_LANE + 4, 0x120000 }, /* 0xe3530000 */ + { TARGET_SD_LANE + 5, 0x128000 }, /* 0xe3538000 */ + { TARGET_SD_LANE + 6, 0x130000 }, /* 0xe3540000 */ + { TARGET_SD_LANE + 7, 0x138000 }, /* 0xe3548000 */ + { TARGET_SD_LANE + 8, 0x140000 }, /* 0xe3550000 */ + { TARGET_SD_LANE + 9, 0x148000 }, /* 0xe3558000 */ +}; + +static const struct sparx5_serdes_match_data sparx5_desc = { + .type = SPX5_TARGET_SPARX5, + .iomap = sparx5_serdes_iomap, + .iomap_size = ARRAY_SIZE(sparx5_serdes_iomap), + .tsize = sparx5_serdes_tsize, + .consts = { + .sd_max = 33, + .cmu_max = 14, + }, + .ops = { + .serdes_type_set = &sparx5_serdes_type_set, + .serdes_cmu_get = &sparx5_serdes_cmu_get, + }, +}; + +static const struct sparx5_serdes_match_data lan969x_desc = { + .type = SPX5_TARGET_LAN969X, + .iomap = lan969x_serdes_iomap, + .iomap_size = ARRAY_SIZE(lan969x_serdes_iomap), + .tsize = lan969x_serdes_tsize, + .consts = { + .sd_max = 10, + .cmu_max = 6, + }, + .ops = { + .serdes_type_set = &lan969x_serdes_type_set, + .serdes_cmu_get = &lan969x_serdes_cmu_get, + } +}; + /* Client lookup function, uses serdes index */ static struct phy *sparx5_serdes_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct sparx5_serdes_private *priv = dev_get_drvdata(dev); int idx; @@ -2521,7 +2635,7 @@ static struct phy *sparx5_serdes_xlate(struct device *dev, sidx = args->args[0]; /* Check validity: ERR_PTR(-ENODEV) if not valid */ - for (idx = 0; idx < SPX5_SERDES_MAX; idx++) { + for (idx = 0; idx < priv->data->consts.sd_max; idx++) { struct sparx5_serdes_macro *macro = phy_get_drvdata(priv->phys[idx]); @@ -2555,6 +2669,12 @@ static int sparx5_serdes_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); priv->dev = &pdev->dev; + priv->data = device_get_match_data(priv->dev); + if (!priv->data) + return -EINVAL; + + tsize = priv->data->tsize; + /* Get coreclock */ clk = devm_clk_get(priv->dev, NULL); if (IS_ERR(clk)) { @@ -2579,19 +2699,21 @@ static int sparx5_serdes_probe(struct platform_device *pdev) iores->name); return -ENOMEM; } - for (idx = 0; idx < ARRAY_SIZE(sparx5_serdes_iomap); idx++) { - struct sparx5_serdes_io_resource *iomap = &sparx5_serdes_iomap[idx]; + for (idx = 0; idx < priv->data->iomap_size; idx++) { + const struct sparx5_serdes_io_resource *iomap = + &priv->data->iomap[idx]; priv->regs[iomap->id] = iomem + iomap->offset; } - for (idx = 0; idx < SPX5_SERDES_MAX; idx++) { + for (idx = 0; idx < priv->data->consts.sd_max; idx++) { err = sparx5_phy_create(priv, idx, &priv->phys[idx]); if (err) return err; } - /* Power down all CMUs by default */ - sparx5_serdes_cmu_power_off(priv); + /* Power down all CMU's by default */ + if (priv->data->type == SPX5_TARGET_SPARX5) + sparx5_serdes_cmu_power_off(priv); provider = devm_of_phy_provider_register(priv->dev, sparx5_serdes_xlate); @@ -2599,7 +2721,8 @@ static int sparx5_serdes_probe(struct platform_device *pdev) } static const struct of_device_id sparx5_serdes_match[] = { - { .compatible = "microchip,sparx5-serdes" }, + { .compatible = "microchip,sparx5-serdes", .data = &sparx5_desc }, + { .compatible = "microchip,lan9691-serdes", .data = &lan969x_desc }, { } }; MODULE_DEVICE_TABLE(of, sparx5_serdes_match); diff --git a/drivers/phy/microchip/sparx5_serdes.h b/drivers/phy/microchip/sparx5_serdes.h index 13f94a29225a..d7093d0b09c0 100644 --- a/drivers/phy/microchip/sparx5_serdes.h +++ b/drivers/phy/microchip/sparx5_serdes.h @@ -26,11 +26,18 @@ enum sparx5_serdes_mode { SPX5_SD_MODE_SFI, }; -struct sparx5_serdes_private { - struct device *dev; - void __iomem *regs[NUM_TARGETS]; - struct phy *phys[SPX5_SERDES_MAX]; - unsigned long coreclock; +enum sparx5_10g28cmu_mode { + SPX5_SD10G28_CMU_MAIN = 0, + SPX5_SD10G28_CMU_AUX1 = 1, + SPX5_SD10G28_CMU_AUX2 = 3, + SPX5_SD10G28_CMU_NONE = 4, + SPX5_SD10G28_CMU_MAX, +}; + +enum sparx5_target { + SPX5_TARGET_SPARX5, + SPX5_TARGET_LAN969X, + }; struct sparx5_serdes_macro { @@ -44,6 +51,33 @@ struct sparx5_serdes_macro { enum phy_media media; }; +struct sparx5_serdes_consts { + int sd_max; + int cmu_max; +}; + +struct sparx5_serdes_ops { + void (*serdes_type_set)(struct sparx5_serdes_macro *macro, int sidx); + int (*serdes_cmu_get)(enum sparx5_10g28cmu_mode mode, int sd_index); +}; + +struct sparx5_serdes_match_data { + enum sparx5_target type; + const struct sparx5_serdes_consts consts; + const struct sparx5_serdes_ops ops; + const struct sparx5_serdes_io_resource *iomap; + int iomap_size; + const unsigned int *tsize; +}; + +struct sparx5_serdes_private { + struct device *dev; + void __iomem *regs[NUM_TARGETS]; + struct phy *phys[SPX5_SERDES_MAX]; + unsigned long coreclock; + const struct sparx5_serdes_match_data *data; +}; + /* Read, Write and modify registers content. * The register definition macros start at the id */ diff --git a/drivers/phy/microchip/sparx5_serdes_regs.h b/drivers/phy/microchip/sparx5_serdes_regs.h index d0543fd3dc94..11c4fdc593fa 100644 --- a/drivers/phy/microchip/sparx5_serdes_regs.h +++ b/drivers/phy/microchip/sparx5_serdes_regs.h @@ -1,11 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0+ * Microchip Sparx5 SerDes driver * - * Copyright (c) 2020 Microchip Technology Inc. + * Copyright (c) 2024 Microchip Technology Inc. */ -/* This file is autogenerated by cml-utils 2020-11-16 13:11:27 +0100. - * Commit ID: 13bdf073131d8bf40c54901df6988ae4e9c8f29f +/* This file is autogenerated by cml-utils 2023-04-13 15:02:00 +0200. + * Commit ID: 5ac560288d46048f872ecdb8add53717f1efc0e1 */ #ifndef _SPARX5_SERDES_REGS_H_ @@ -26,10 +26,25 @@ enum sparx5_serdes_target { NUM_TARGETS = 332 }; +enum sparx5_serdes_tsize_enum { + TC_SD10G_LANE, + TC_SD_CMU, + TC_SD_CMU_CFG, + TC_SD_LANE, + TSIZE_LAST, +}; + +/* sparx5_serdes.c */ +extern const unsigned int *tsize; + +#define TSIZE(o) tsize[o] + #define __REG(...) __VA_ARGS__ -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_01 */ -#define SD10G_LANE_LANE_01(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 4, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_01 */ +#define SD10G_LANE_LANE_01(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 4, 0, \ + 1, 4) #define SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_01_CFG_PMA_TX_CK_BITWIDTH_2_0_SET(x)\ @@ -49,8 +64,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_01_CFG_RXDET_STR_GET(x)\ FIELD_GET(SD10G_LANE_LANE_01_CFG_RXDET_STR, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_02 */ -#define SD10G_LANE_LANE_02(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 8, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_02 */ +#define SD10G_LANE_LANE_02(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 8, 0, \ + 1, 4) #define SD10G_LANE_LANE_02_CFG_EN_ADV BIT(0) #define SD10G_LANE_LANE_02_CFG_EN_ADV_SET(x)\ @@ -82,8 +99,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_02_CFG_TAP_ADV_3_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_03 */ -#define SD10G_LANE_LANE_03(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 12, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_03 */ +#define SD10G_LANE_LANE_03(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 12, 0, \ + 1, 4) #define SD10G_LANE_LANE_03_CFG_TAP_MAIN BIT(0) #define SD10G_LANE_LANE_03_CFG_TAP_MAIN_SET(x)\ @@ -91,8 +110,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_03_CFG_TAP_MAIN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_03_CFG_TAP_MAIN, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_04 */ -#define SD10G_LANE_LANE_04(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 16, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_04 */ +#define SD10G_LANE_LANE_04(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 16, 0, \ + 1, 4) #define SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0 GENMASK(4, 0) #define SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_SET(x)\ @@ -100,8 +121,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_04_CFG_TAP_DLY_4_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_06 */ -#define SD10G_LANE_LANE_06(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 24, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_06 */ +#define SD10G_LANE_LANE_06(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 24, 0, \ + 1, 4) #define SD10G_LANE_LANE_06_CFG_PD_DRIVER BIT(0) #define SD10G_LANE_LANE_06_CFG_PD_DRIVER_SET(x)\ @@ -139,8 +162,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_06_CFG_EN_PREEMPH_GET(x)\ FIELD_GET(SD10G_LANE_LANE_06_CFG_EN_PREEMPH, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0B */ -#define SD10G_LANE_LANE_0B(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 44, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0B */ +#define SD10G_LANE_LANE_0B(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 44, 0, \ + 1, 4) #define SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_0B_CFG_EQ_RES_3_0_SET(x)\ @@ -172,8 +197,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0B_CFG_RESETB_OSCAL_SQ, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0C */ -#define SD10G_LANE_LANE_0C(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 48, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0C */ +#define SD10G_LANE_LANE_0C(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 48, 0, \ + 1, 4) #define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE BIT(0) #define SD10G_LANE_LANE_0C_CFG_OSCAL_AFE_SET(x)\ @@ -223,8 +250,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0C_CFG_RX_PCIE_GEN12, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0D */ -#define SD10G_LANE_LANE_0D(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 52, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0D */ +#define SD10G_LANE_LANE_0D(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 52, 0, \ + 1, 4) #define SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_0D_CFG_CTLE_M_THR_1_0_SET(x)\ @@ -238,8 +267,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0D_CFG_EQR_BYP_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0D_CFG_EQR_BYP, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0E */ -#define SD10G_LANE_LANE_0E(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 56, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0E */ +#define SD10G_LANE_LANE_0E(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 56, 0, \ + 1, 4) #define SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_0E_CFG_EQC_FORCE_3_0_SET(x)\ @@ -265,8 +296,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0E_CFG_SUM_SETCM_EN, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0F */ -#define SD10G_LANE_LANE_0F(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 60, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_0F */ +#define SD10G_LANE_LANE_0F(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 60, 0, \ + 1, 4) #define SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0 GENMASK(7, 0) #define SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_SET(x)\ @@ -274,8 +307,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_0F_R_CDR_M_GEN1_7_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_13 */ -#define SD10G_LANE_LANE_13(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 76, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_13 */ +#define SD10G_LANE_LANE_13(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 76, 0, \ + 1, 4) #define SD10G_LANE_LANE_13_CFG_DCDR_PD BIT(0) #define SD10G_LANE_LANE_13_CFG_DCDR_PD_SET(x)\ @@ -295,8 +330,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_13_CFG_CDRCK_EN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_13_CFG_CDRCK_EN, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_14 */ -#define SD10G_LANE_LANE_14(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 80, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_14 */ +#define SD10G_LANE_LANE_14(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 80, 0, \ + 1, 4) #define SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0 GENMASK(7, 0) #define SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_SET(x)\ @@ -304,8 +341,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_14_CFG_PI_EXT_DAC_7_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_15 */ -#define SD10G_LANE_LANE_15(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 84, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_15 */ +#define SD10G_LANE_LANE_15(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 84, 0, \ + 1, 4) #define SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8 GENMASK(7, 0) #define SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_SET(x)\ @@ -313,8 +352,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8_GET(x)\ FIELD_GET(SD10G_LANE_LANE_15_CFG_PI_EXT_DAC_15_8, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_16 */ -#define SD10G_LANE_LANE_16(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 88, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_16 */ +#define SD10G_LANE_LANE_16(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 88, 0, \ + 1, 4) #define SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16 GENMASK(7, 0) #define SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_SET(x)\ @@ -322,8 +363,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16_GET(x)\ FIELD_GET(SD10G_LANE_LANE_16_CFG_PI_EXT_DAC_23_16, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_1A */ -#define SD10G_LANE_LANE_1A(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 104, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_1A */ +#define SD10G_LANE_LANE_1A(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 104, 0,\ + 1, 4) #define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN BIT(0) #define SD10G_LANE_LANE_1A_CFG_PI_R_SCAN_EN_SET(x)\ @@ -355,8 +398,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_1A_CFG_PI_FLOOP_STEPS_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_22 */ -#define SD10G_LANE_LANE_22(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 136, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_22 */ +#define SD10G_LANE_LANE_22(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 136, 0,\ + 1, 4) #define SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1 GENMASK(4, 0) #define SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_SET(x)\ @@ -364,8 +409,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1_GET(x)\ FIELD_GET(SD10G_LANE_LANE_22_CFG_DFETAP_EN_5_1, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_23 */ -#define SD10G_LANE_LANE_23(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 140, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_23 */ +#define SD10G_LANE_LANE_23(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 140, 0,\ + 1, 4) #define SD10G_LANE_LANE_23_CFG_DFE_PD BIT(0) #define SD10G_LANE_LANE_23_CFG_DFE_PD_SET(x)\ @@ -397,8 +444,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_23_CFG_DFEDIG_M_2_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_24 */ -#define SD10G_LANE_LANE_24(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 144, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_24 */ +#define SD10G_LANE_LANE_24(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 144, 0,\ + 1, 4) #define SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_24_CFG_PI_BW_GEN1_3_0_SET(x)\ @@ -412,8 +461,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_24_CFG_PI_BW_GEN2_3_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_26 */ -#define SD10G_LANE_LANE_26(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 152, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_26 */ +#define SD10G_LANE_LANE_26(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 152, 0,\ + 1, 4) #define SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0 GENMASK(7, 0) #define SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_SET(x)\ @@ -421,8 +472,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_26_CFG_ISCAN_EXT_DAC_7_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_2F */ -#define SD10G_LANE_LANE_2F(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 188, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_2F */ +#define SD10G_LANE_LANE_2F(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 188, 0,\ + 1, 4) #define SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_2F_CFG_VGA_CP_2_0_SET(x)\ @@ -436,8 +489,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_2F_CFG_VGA_CTRL_3_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_30 */ -#define SD10G_LANE_LANE_30(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 192, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_30 */ +#define SD10G_LANE_LANE_30(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 192, 0,\ + 1, 4) #define SD10G_LANE_LANE_30_CFG_SUMMER_EN BIT(0) #define SD10G_LANE_LANE_30_CFG_SUMMER_EN_SET(x)\ @@ -451,8 +506,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_30_CFG_RXDIV_SEL_2_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_31 */ -#define SD10G_LANE_LANE_31(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 196, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_31 */ +#define SD10G_LANE_LANE_31(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 196, 0,\ + 1, 4) #define SD10G_LANE_LANE_31_CFG_PI_RSTN BIT(0) #define SD10G_LANE_LANE_31_CFG_PI_RSTN_SET(x)\ @@ -490,8 +547,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_31_CFG_R50_EN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_31_CFG_R50_EN, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_32 */ -#define SD10G_LANE_LANE_32(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 200, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_32 */ +#define SD10G_LANE_LANE_32(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 200, 0,\ + 1, 4) #define SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_32_CFG_ITX_IPCLK_BASE_1_0_SET(x)\ @@ -505,8 +564,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_32_CFG_ITX_IPCML_BASE_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_33 */ -#define SD10G_LANE_LANE_33(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 204, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_33 */ +#define SD10G_LANE_LANE_33(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 204, 0,\ + 1, 4) #define SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_33_CFG_ITX_IPDRIVER_BASE_2_0_SET(x)\ @@ -520,8 +581,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_33_CFG_ITX_IPPREEMP_BASE_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_35 */ -#define SD10G_LANE_LANE_35(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 212, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_35 */ +#define SD10G_LANE_LANE_35(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 212, 0,\ + 1, 4) #define SD10G_LANE_LANE_35_CFG_TXRATE_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_35_CFG_TXRATE_1_0_SET(x)\ @@ -535,8 +598,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_35_CFG_RXRATE_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_35_CFG_RXRATE_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_36 */ -#define SD10G_LANE_LANE_36(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 216, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_36 */ +#define SD10G_LANE_LANE_36(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 216, 0,\ + 1, 4) #define SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_36_CFG_PREDRV_SLEWRATE_1_0_SET(x)\ @@ -568,8 +633,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_36_CFG_PRBS_SETB_GET(x)\ FIELD_GET(SD10G_LANE_LANE_36_CFG_PRBS_SETB, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_37 */ -#define SD10G_LANE_LANE_37(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 220, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_37 */ +#define SD10G_LANE_LANE_37(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 220, 0,\ + 1, 4) #define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD BIT(0) #define SD10G_LANE_LANE_37_CFG_RXDET_COMP_PD_SET(x)\ @@ -595,8 +662,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_37_CFG_IP_PRE_BASE_1_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_39 */ -#define SD10G_LANE_LANE_39(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 228, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_39 */ +#define SD10G_LANE_LANE_39(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 228, 0,\ + 1, 4) #define SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_39_CFG_RXFILT_Y_2_0_SET(x)\ @@ -610,8 +679,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_39_CFG_RX_SSC_LH_GET(x)\ FIELD_GET(SD10G_LANE_LANE_39_CFG_RX_SSC_LH, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3A */ -#define SD10G_LANE_LANE_3A(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 232, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3A */ +#define SD10G_LANE_LANE_3A(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 232, 0,\ + 1, 4) #define SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_3A_CFG_MP_MIN_3_0_SET(x)\ @@ -625,8 +696,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_3A_CFG_MP_MAX_3_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3C */ -#define SD10G_LANE_LANE_3C(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 240, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_3C */ +#define SD10G_LANE_LANE_3C(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 240, 0,\ + 1, 4) #define SD10G_LANE_LANE_3C_CFG_DIS_ACC BIT(0) #define SD10G_LANE_LANE_3C_CFG_DIS_ACC_SET(x)\ @@ -640,8 +713,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER_GET(x)\ FIELD_GET(SD10G_LANE_LANE_3C_CFG_DIS_2NDORDER, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_40 */ -#define SD10G_LANE_LANE_40(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 256, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_40 */ +#define SD10G_LANE_LANE_40(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 256, 0,\ + 1, 4) #define SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0 GENMASK(7, 0) #define SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_SET(x)\ @@ -649,8 +724,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_40_CFG_LANE_RESERVE_7_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_41 */ -#define SD10G_LANE_LANE_41(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 260, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_41 */ +#define SD10G_LANE_LANE_41(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 260, 0,\ + 1, 4) #define SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8 GENMASK(7, 0) #define SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_SET(x)\ @@ -658,8 +735,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8_GET(x)\ FIELD_GET(SD10G_LANE_LANE_41_CFG_LANE_RESERVE_15_8, x) -/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_42 */ -#define SD10G_LANE_LANE_42(t) __REG(TARGET_SD10G_LANE, t, 12, 0, 0, 1, 288, 264, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_0:LANE_42 */ +#define SD10G_LANE_LANE_42(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 0, 0, 1, 288, 264, 0,\ + 1, 4) #define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN1_2_0_SET(x)\ @@ -673,8 +752,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_42_CFG_CDR_KF_GEN2_2_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_48 */ -#define SD10G_LANE_LANE_48(t) __REG(TARGET_SD10G_LANE, t, 12, 288, 0, 1, 40, 0, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_48 */ +#define SD10G_LANE_LANE_48(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 288, 0, 1, 40, 0, 0, \ + 1, 4) #define SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0 GENMASK(3, 0) #define SD10G_LANE_LANE_48_CFG_ALOS_THR_3_0_SET(x)\ @@ -694,8 +775,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_48_CFG_CLK_ENQ_GET(x)\ FIELD_GET(SD10G_LANE_LANE_48_CFG_CLK_ENQ, x) -/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_50 */ -#define SD10G_LANE_LANE_50(t) __REG(TARGET_SD10G_LANE, t, 12, 288, 0, 1, 40, 32, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_1:LANE_50 */ +#define SD10G_LANE_LANE_50(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 288, 0, 1, 40, 32, 0,\ + 1, 4) #define SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_50_CFG_SSC_PI_STEP_1_0_SET(x)\ @@ -727,8 +810,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_50_CFG_JT_EN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_50_CFG_JT_EN, x) -/* SD10G_LANE_TARGET:LANE_GRP_2:LANE_52 */ -#define SD10G_LANE_LANE_52(t) __REG(TARGET_SD10G_LANE, t, 12, 328, 0, 1, 24, 0, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_2:LANE_52 */ +#define SD10G_LANE_LANE_52(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 328, 0, 1, 24, 0, 0, \ + 1, 4) #define SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0 GENMASK(5, 0) #define SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_SET(x)\ @@ -736,8 +821,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_52_CFG_IBIAS_TUNE_RESERVE_5_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_4:LANE_83 */ -#define SD10G_LANE_LANE_83(t) __REG(TARGET_SD10G_LANE, t, 12, 464, 0, 1, 112, 60, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_4:LANE_83 */ +#define SD10G_LANE_LANE_83(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 464, 0, 1, 112, 60, \ + 0, 1, 4) #define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE BIT(0) #define SD10G_LANE_LANE_83_R_TX_BIT_REVERSE_SET(x)\ @@ -781,8 +868,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_83_R_CTLE_RSTN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_83_R_CTLE_RSTN, x) -/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_93 */ -#define SD10G_LANE_LANE_93(t) __REG(TARGET_SD10G_LANE, t, 12, 576, 0, 1, 64, 12, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_93 */ +#define SD10G_LANE_LANE_93(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 576, 0, 1, 64, 12, 0,\ + 1, 4) #define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN BIT(0) #define SD10G_LANE_LANE_93_R_RXEI_FIFO_RST_EN_SET(x)\ @@ -832,8 +921,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT_GET(x)\ FIELD_GET(SD10G_LANE_LANE_93_R_RX_PCIE_GEN12_FROM_HWT, x) -/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_94 */ -#define SD10G_LANE_LANE_94(t) __REG(TARGET_SD10G_LANE, t, 12, 576, 0, 1, 64, 16, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_94 */ +#define SD10G_LANE_LANE_94(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 576, 0, 1, 64, 16, 0,\ + 1, 4) #define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0 GENMASK(2, 0) #define SD10G_LANE_LANE_94_R_DWIDTHCTRL_2_0_SET(x)\ @@ -865,8 +956,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_94_R_SWING_REG_GET(x)\ FIELD_GET(SD10G_LANE_LANE_94_R_SWING_REG, x) -/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_9E */ -#define SD10G_LANE_LANE_9E(t) __REG(TARGET_SD10G_LANE, t, 12, 576, 0, 1, 64, 56, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_5:LANE_9E */ +#define SD10G_LANE_LANE_9E(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 576, 0, 1, 64, 56, 0,\ + 1, 4) #define SD10G_LANE_LANE_9E_R_RXEQ_REG BIT(0) #define SD10G_LANE_LANE_9E_R_RXEQ_REG_SET(x)\ @@ -886,8 +979,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN_GET(x)\ FIELD_GET(SD10G_LANE_LANE_9E_R_EN_AUTO_CDR_RSTN, x) -/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A1 */ -#define SD10G_LANE_LANE_A1(t) __REG(TARGET_SD10G_LANE, t, 12, 640, 0, 1, 128, 4, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A1 */ +#define SD10G_LANE_LANE_A1(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 640, 0, 1, 128, 4, 0,\ + 1, 4) #define SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0 GENMASK(1, 0) #define SD10G_LANE_LANE_A1_R_PMA_TXCK_DIV_SEL_1_0_SET(x)\ @@ -919,8 +1014,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_A1_R_PCLK_GATING_GET(x)\ FIELD_GET(SD10G_LANE_LANE_A1_R_PCLK_GATING, x) -/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A2 */ -#define SD10G_LANE_LANE_A2(t) __REG(TARGET_SD10G_LANE, t, 12, 640, 0, 1, 128, 8, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_6:LANE_A2 */ +#define SD10G_LANE_LANE_A2(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 640, 0, 1, 128, 8, 0,\ + 1, 4) #define SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0 GENMASK(4, 0) #define SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_SET(x)\ @@ -928,8 +1025,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0_GET(x)\ FIELD_GET(SD10G_LANE_LANE_A2_R_PCS2PMA_PHYMODE_4_0, x) -/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ -#define SD10G_LANE_LANE_DF(t) __REG(TARGET_SD10G_LANE, t, 12, 832, 0, 1, 84, 60, 0, 1, 4) +/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ +#define SD10G_LANE_LANE_DF(t) \ + __REG(TARGET_SD10G_LANE, t, TSIZE(TC_SD10G_LANE), 832, 0, 1, 84, 60, 0,\ + 1, 4) #define SD10G_LANE_LANE_DF_LOL_UDL BIT(0) #define SD10G_LANE_LANE_DF_LOL_UDL_SET(x)\ @@ -955,8 +1054,10 @@ enum sparx5_serdes_target { #define SD10G_LANE_LANE_DF_SQUELCH_GET(x)\ FIELD_GET(SD10G_LANE_LANE_DF_SQUELCH, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_09 */ -#define SD25G_LANE_CMU_09(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 36, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_09 */ +#define SD25G_LANE_CMU_09(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 36, 0, 1, 4) #define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN BIT(0) #define SD25G_LANE_CMU_09_CFG_REFCK_TERM_EN_SET(x)\ @@ -988,8 +1089,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_09_CFG_PLL_TP_SEL_1_0, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_0B */ -#define SD25G_LANE_CMU_0B(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 44, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_0B */ +#define SD25G_LANE_CMU_0B(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 44, 0, 1, 4) #define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT BIT(0) #define SD25G_LANE_CMU_0B_CFG_FORCE_RX_FILT_SET(x)\ @@ -1039,8 +1142,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN_GET(x)\ FIELD_GET(SD25G_LANE_CMU_0B_CFG_RST_TREE_PD_MAN, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_0C */ -#define SD25G_LANE_CMU_0C(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 48, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_0C */ +#define SD25G_LANE_CMU_0C(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 48, 0, 1, 4) #define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET BIT(0) #define SD25G_LANE_CMU_0C_CFG_PLL_LOL_SET_SET(x)\ @@ -1072,8 +1177,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_0C_CFG_VCO_DIV_MODE_1_0, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_0D */ -#define SD25G_LANE_CMU_0D(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 52, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_0D */ +#define SD25G_LANE_CMU_0D(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 52, 0, 1, 4) #define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD BIT(0) #define SD25G_LANE_CMU_0D_CFG_CK_TREE_PD_SET(x)\ @@ -1105,8 +1212,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_0D_CFG_PRE_DIVSEL_1_0, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_0E */ -#define SD25G_LANE_CMU_0E(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 56, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_0E */ +#define SD25G_LANE_CMU_0E(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 56, 0, 1, 4) #define SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0 GENMASK(3, 0) #define SD25G_LANE_CMU_0E_CFG_SEL_DIV_3_0_SET(x)\ @@ -1120,8 +1229,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD_GET(x)\ FIELD_GET(SD25G_LANE_CMU_0E_CFG_PMAA_CENTR_CK_PD, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_13 */ -#define SD25G_LANE_CMU_13(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 76, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_13 */ +#define SD25G_LANE_CMU_13(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 76, 0, 1, 4) #define SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0 GENMASK(3, 0) #define SD25G_LANE_CMU_13_CFG_PLL_RESERVE_3_0_SET(x)\ @@ -1135,8 +1246,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_13_CFG_JT_EN_GET(x)\ FIELD_GET(SD25G_LANE_CMU_13_CFG_JT_EN, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_18 */ -#define SD25G_LANE_CMU_18(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 96, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_18 */ +#define SD25G_LANE_CMU_18(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 96, 0, 1, 4) #define SD25G_LANE_CMU_18_R_PLL_RSTN BIT(0) #define SD25G_LANE_CMU_18_R_PLL_RSTN_SET(x)\ @@ -1162,8 +1275,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_18_R_PLL_TP_SEL_1_0, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_19 */ -#define SD25G_LANE_CMU_19(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 100, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_19 */ +#define SD25G_LANE_CMU_19(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 100, 0, 1, 4) #define SD25G_LANE_CMU_19_R_CK_RESETB BIT(0) #define SD25G_LANE_CMU_19_R_CK_RESETB_SET(x)\ @@ -1177,8 +1292,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_19_R_PLL_DLOL_EN_GET(x)\ FIELD_GET(SD25G_LANE_CMU_19_R_PLL_DLOL_EN, x) -/* SD25G_TARGET:CMU_GRP_0:CMU_1A */ -#define SD25G_LANE_CMU_1A(t) __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 104, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_0:CMU_1A */ +#define SD25G_LANE_CMU_1A(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 0, 0, 1, 132, 104, 0, 1, 4) #define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0 GENMASK(2, 0) #define SD25G_LANE_CMU_1A_R_DWIDTHCTRL_2_0_SET(x)\ @@ -1204,8 +1321,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_1A_R_REG_MANUAL_GET(x)\ FIELD_GET(SD25G_LANE_CMU_1A_R_REG_MANUAL, x) -/* SD25G_TARGET:CMU_GRP_1:CMU_2A */ -#define SD25G_LANE_CMU_2A(t) __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 36, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_1:CMU_2A */ +#define SD25G_LANE_CMU_2A(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 36, 0, 1, 4) #define SD25G_LANE_CMU_2A_R_DBG_SEL_1_0 GENMASK(1, 0) #define SD25G_LANE_CMU_2A_R_DBG_SEL_1_0_SET(x)\ @@ -1225,8 +1344,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS_GET(x)\ FIELD_GET(SD25G_LANE_CMU_2A_R_DBG_LOL_STATUS, x) -/* SD25G_TARGET:CMU_GRP_1:CMU_30 */ -#define SD25G_LANE_CMU_30(t) __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 60, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_1:CMU_30 */ +#define SD25G_LANE_CMU_30(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 60, 0, 1, 4) #define SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0 GENMASK(2, 0) #define SD25G_LANE_CMU_30_R_TXFIFO_CK_DIV_PMAD_2_0_SET(x)\ @@ -1240,8 +1361,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_30_R_RXFIFO_CK_DIV_PMAD_2_0, x) -/* SD25G_TARGET:CMU_GRP_1:CMU_31 */ -#define SD25G_LANE_CMU_31(t) __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 64, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_1:CMU_31 */ +#define SD25G_LANE_CMU_31(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 132, 0, 1, 124, 64, 0, 1, 4) #define SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0 GENMASK(7, 0) #define SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_SET(x)\ @@ -1249,8 +1372,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_31_CFG_COMMON_RESERVE_7_0, x) -/* SD25G_TARGET:CMU_GRP_2:CMU_40 */ -#define SD25G_LANE_CMU_40(t) __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_2:CMU_40 */ +#define SD25G_LANE_CMU_40(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 0, 0, 1, 4) #define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL BIT(0) #define SD25G_LANE_CMU_40_L0_CFG_CKSKEW_CTRL_SET(x)\ @@ -1288,8 +1413,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST_GET(x)\ FIELD_GET(SD25G_LANE_CMU_40_L0_CFG_TXCAL_RST, x) -/* SD25G_TARGET:CMU_GRP_2:CMU_45 */ -#define SD25G_LANE_CMU_45(t) __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 20, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_2:CMU_45 */ +#define SD25G_LANE_CMU_45(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 20, 0, 1, 4) #define SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0 GENMASK(7, 0) #define SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_SET(x)\ @@ -1297,8 +1424,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0_GET(x)\ FIELD_GET(SD25G_LANE_CMU_45_L0_CFG_TX_RESERVE_7_0, x) -/* SD25G_TARGET:CMU_GRP_2:CMU_46 */ -#define SD25G_LANE_CMU_46(t) __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 24, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_2:CMU_46 */ +#define SD25G_LANE_CMU_46(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 256, 0, 1, 512, 24, 0, 1, 4) #define SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8 GENMASK(7, 0) #define SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_SET(x)\ @@ -1306,8 +1435,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8_GET(x)\ FIELD_GET(SD25G_LANE_CMU_46_L0_CFG_TX_RESERVE_15_8, x) -/* SD25G_TARGET:CMU_GRP_3:CMU_C0 */ -#define SD25G_LANE_CMU_C0(t) __REG(TARGET_SD25G_LANE, t, 8, 768, 0, 1, 252, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_3:CMU_C0 */ +#define SD25G_LANE_CMU_C0(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 768, 0, 1, 252, 0, 0, 1, 4) #define SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0 GENMASK(3, 0) #define SD25G_LANE_CMU_C0_READ_VCO_CTUNE_3_0_SET(x)\ @@ -1321,8 +1452,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_C0_PLL_LOL_UDL_GET(x)\ FIELD_GET(SD25G_LANE_CMU_C0_PLL_LOL_UDL, x) -/* SD25G_TARGET:CMU_GRP_4:CMU_FF */ -#define SD25G_LANE_CMU_FF(t) __REG(TARGET_SD25G_LANE, t, 8, 1020, 0, 1, 4, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:CMU_GRP_4:CMU_FF */ +#define SD25G_LANE_CMU_FF(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1020, 0, 1, 4, 0, 0, 1, 4) #define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX GENMASK(7, 0) #define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_SET(x)\ @@ -1330,8 +1463,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX_GET(x)\ FIELD_GET(SD25G_LANE_CMU_FF_REGISTER_TABLE_INDEX, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_00 */ -#define SD25G_LANE_LANE_00(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_00 */ +#define SD25G_LANE_LANE_00(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 0, 0, 1, 4) #define SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_00_LN_CFG_ITX_VC_DRIVER_3_0_SET(x)\ @@ -1345,8 +1480,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_00_LN_CFG_ITX_IPCML_BASE_1_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_01 */ -#define SD25G_LANE_LANE_01(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_01 */ +#define SD25G_LANE_LANE_01(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 4, 0, 1, 4) #define SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_01_LN_CFG_ITX_IPDRIVER_BASE_2_0_SET(x)\ @@ -1360,8 +1497,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_01_LN_CFG_TX_PREDIV_1_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_03 */ -#define SD25G_LANE_LANE_03(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 12, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_03 */ +#define SD25G_LANE_LANE_03(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 12, 0, 1, 4) #define SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0 GENMASK(4, 0) #define SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_SET(x)\ @@ -1369,8 +1508,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_03_LN_CFG_TAP_DLY_4_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_04 */ -#define SD25G_LANE_LANE_04(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 16, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_04 */ +#define SD25G_LANE_LANE_04(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 16, 0, 1, 4) #define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN BIT(0) #define SD25G_LANE_LANE_04_LN_CFG_TX2RX_LP_EN_SET(x)\ @@ -1408,8 +1549,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN_GET(x)\ FIELD_GET(SD25G_LANE_LANE_04_LN_CFG_TAP_MAIN, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_05 */ -#define SD25G_LANE_LANE_05(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 20, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_05 */ +#define SD25G_LANE_LANE_05(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 20, 0, 1, 4) #define SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_05_LN_CFG_TAP_DLY2_3_0_SET(x)\ @@ -1423,8 +1566,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_05_LN_CFG_BW_1_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_05_LN_CFG_BW_1_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_06 */ -#define SD25G_LANE_LANE_06(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 24, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_06 */ +#define SD25G_LANE_LANE_06(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 24, 0, 1, 4) #define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN BIT(0) #define SD25G_LANE_LANE_06_LN_CFG_EN_MAIN_SET(x)\ @@ -1438,8 +1583,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_06_LN_CFG_TAP_ADV_3_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_07 */ -#define SD25G_LANE_LANE_07(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 28, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_07 */ +#define SD25G_LANE_LANE_07(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 28, 0, 1, 4) #define SD25G_LANE_LANE_07_LN_CFG_EN_ADV BIT(0) #define SD25G_LANE_LANE_07_LN_CFG_EN_ADV_SET(x)\ @@ -1459,8 +1606,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_07_LN_CFG_EN_DLY_GET(x)\ FIELD_GET(SD25G_LANE_LANE_07_LN_CFG_EN_DLY, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_09 */ -#define SD25G_LANE_LANE_09(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 36, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_09 */ +#define SD25G_LANE_LANE_09(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 36, 0, 1, 4) #define SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_SET(x)\ @@ -1468,8 +1617,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_09_LN_CFG_TXCAL_VALID_SEL_3_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0A */ -#define SD25G_LANE_LANE_0A(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 40, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0A */ +#define SD25G_LANE_LANE_0A(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 40, 0, 1, 4) #define SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0 GENMASK(5, 0) #define SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_SET(x)\ @@ -1477,8 +1628,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0A_LN_CFG_TXCAL_SHIFT_CODE_5_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0B */ -#define SD25G_LANE_LANE_0B(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 44, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0B */ +#define SD25G_LANE_LANE_0B(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 44, 0, 1, 4) #define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN BIT(0) #define SD25G_LANE_LANE_0B_LN_CFG_TXCAL_MAN_EN_SET(x)\ @@ -1498,8 +1651,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0B_LN_CFG_QUAD_MAN_1_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0C */ -#define SD25G_LANE_LANE_0C(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 48, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0C */ +#define SD25G_LANE_LANE_0C(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 48, 0, 1, 4) #define SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_0C_LN_CFG_PMA_TX_CK_BITWIDTH_2_0_SET(x)\ @@ -1519,8 +1674,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0C_LN_CFG_RXTERM_PD, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0D */ -#define SD25G_LANE_LANE_0D(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 52, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0D */ +#define SD25G_LANE_LANE_0D(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 52, 0, 1, 4) #define SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_0D_LN_CFG_RXTERM_2_0_SET(x)\ @@ -1552,8 +1709,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0D_LN_CFG_DFECK_EN, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0E */ -#define SD25G_LANE_LANE_0E(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 56, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0E */ +#define SD25G_LANE_LANE_0E(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 56, 0, 1, 4) #define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN BIT(0) #define SD25G_LANE_LANE_0E_LN_CFG_ISCAN_EN_SET(x)\ @@ -1579,8 +1738,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0E_LN_CFG_DFEDIG_M_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_0F */ -#define SD25G_LANE_LANE_0F(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 60, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_0F */ +#define SD25G_LANE_LANE_0F(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 60, 0, 1, 4) #define SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1 GENMASK(4, 0) #define SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_SET(x)\ @@ -1588,8 +1749,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1_GET(x)\ FIELD_GET(SD25G_LANE_LANE_0F_LN_CFG_DFETAP_EN_5_1, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_18 */ -#define SD25G_LANE_LANE_18(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 96, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_18 */ +#define SD25G_LANE_LANE_18(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 96, 0, 1, 4) #define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN BIT(0) #define SD25G_LANE_LANE_18_LN_CFG_CDRCK_EN_SET(x)\ @@ -1621,8 +1784,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_18_LN_CFG_RXDIV_SEL_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_19 */ -#define SD25G_LANE_LANE_19(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 100, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_19 */ +#define SD25G_LANE_LANE_19(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 100, 0, 1, 4) #define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD BIT(0) #define SD25G_LANE_LANE_19_LN_CFG_DCDR_PD_SET(x)\ @@ -1672,8 +1837,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_19_LN_CFG_PD_CTLE_GET(x)\ FIELD_GET(SD25G_LANE_LANE_19_LN_CFG_PD_CTLE, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1A */ -#define SD25G_LANE_LANE_1A(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 104, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1A */ +#define SD25G_LANE_LANE_1A(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 104, 0, 1, 4) #define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN BIT(0) #define SD25G_LANE_LANE_1A_LN_CFG_CTLE_TP_EN_SET(x)\ @@ -1687,8 +1854,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1A_LN_CFG_CDR_KF_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1B */ -#define SD25G_LANE_LANE_1B(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 108, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1B */ +#define SD25G_LANE_LANE_1B(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 108, 0, 1, 4) #define SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0 GENMASK(7, 0) #define SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_SET(x)\ @@ -1696,8 +1865,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1B_LN_CFG_CDR_M_7_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1C */ -#define SD25G_LANE_LANE_1C(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 112, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1C */ +#define SD25G_LANE_LANE_1C(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 112, 0, 1, 4) #define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN BIT(0) #define SD25G_LANE_LANE_1C_LN_CFG_CDR_RSTN_SET(x)\ @@ -1723,8 +1894,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1C_LN_CFG_EQC_FORCE_3_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1D */ -#define SD25G_LANE_LANE_1D(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 116, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1D */ +#define SD25G_LANE_LANE_1D(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 116, 0, 1, 4) #define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR BIT(0) #define SD25G_LANE_LANE_1D_LN_CFG_ISCAN_EXT_OVR_SET(x)\ @@ -1774,8 +1947,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1D_LN_CFG_PI_HOLD, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_1E */ -#define SD25G_LANE_LANE_1E(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 120, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_1E */ +#define SD25G_LANE_LANE_1E(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 120, 0, 1, 4) #define SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0 GENMASK(1, 0) #define SD25G_LANE_LANE_1E_LN_CFG_PI_STEPS_1_0_SET(x)\ @@ -1807,8 +1982,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD_GET(x)\ FIELD_GET(SD25G_LANE_LANE_1E_LN_CFG_PMAD_CK_PD, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_21 */ -#define SD25G_LANE_LANE_21(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 132, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_21 */ +#define SD25G_LANE_LANE_21(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 132, 0, 1, 4) #define SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0 GENMASK(4, 0) #define SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_SET(x)\ @@ -1816,8 +1993,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_21_LN_CFG_VGA_CTRL_BYP_4_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_22 */ -#define SD25G_LANE_LANE_22(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 136, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_22 */ +#define SD25G_LANE_LANE_22(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 136, 0, 1, 4) #define SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_SET(x)\ @@ -1825,8 +2004,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_22_LN_CFG_EQR_FORCE_3_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_25 */ -#define SD25G_LANE_LANE_25(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 148, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_25 */ +#define SD25G_LANE_LANE_25(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 148, 0, 1, 4) #define SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0 GENMASK(6, 0) #define SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_SET(x)\ @@ -1834,8 +2015,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_25_LN_CFG_INIT_POS_ISCAN_6_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_26 */ -#define SD25G_LANE_LANE_26(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 152, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_26 */ +#define SD25G_LANE_LANE_26(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 152, 0, 1, 4) #define SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0 GENMASK(6, 0) #define SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_SET(x)\ @@ -1843,8 +2026,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_26_LN_CFG_INIT_POS_IPI_6_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_28 */ -#define SD25G_LANE_LANE_28(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 160, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_28 */ +#define SD25G_LANE_LANE_28(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 160, 0, 1, 4) #define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN BIT(0) #define SD25G_LANE_LANE_28_LN_CFG_ISCAN_MODE_EN_SET(x)\ @@ -1870,8 +2055,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_28_LN_CFG_RX_SUBRATE_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_2B */ -#define SD25G_LANE_LANE_2B(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 172, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_2B */ +#define SD25G_LANE_LANE_2B(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 172, 0, 1, 4) #define SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0 GENMASK(3, 0) #define SD25G_LANE_LANE_2B_LN_CFG_PI_BW_3_0_SET(x)\ @@ -1891,8 +2078,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU_GET(x)\ FIELD_GET(SD25G_LANE_LANE_2B_LN_CFG_RSTN_TXDUPU, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_2C */ -#define SD25G_LANE_LANE_2C(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 176, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_2C */ +#define SD25G_LANE_LANE_2C(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 176, 0, 1, 4) #define SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_2C_LN_CFG_TX_SUBRATE_2_0_SET(x)\ @@ -1906,8 +2095,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER_GET(x)\ FIELD_GET(SD25G_LANE_LANE_2C_LN_CFG_DIS_2NDORDER, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_2D */ -#define SD25G_LANE_LANE_2D(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 180, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_2D */ +#define SD25G_LANE_LANE_2D(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 180, 0, 1, 4) #define SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0 GENMASK(2, 0) #define SD25G_LANE_LANE_2D_LN_CFG_ALOS_THR_2_0_SET(x)\ @@ -1921,8 +2112,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_2D_LN_CFG_SAT_CNTSEL_2_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_2E */ -#define SD25G_LANE_LANE_2E(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 184, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_2E */ +#define SD25G_LANE_LANE_2E(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 184, 0, 1, 4) #define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN BIT(0) #define SD25G_LANE_LANE_2E_LN_CFG_EN_FAST_ISCAN_SET(x)\ @@ -1972,8 +2165,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN_GET(x)\ FIELD_GET(SD25G_LANE_LANE_2E_LN_CFG_CTLE_RSTN, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_40 */ -#define SD25G_LANE_LANE_40(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 256, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_40 */ +#define SD25G_LANE_LANE_40(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 256, 0, 1, 4) #define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE BIT(0) #define SD25G_LANE_LANE_40_LN_R_TX_BIT_REVERSE_SET(x)\ @@ -2017,8 +2212,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_40_LN_R_CTLE_RSTN_GET(x)\ FIELD_GET(SD25G_LANE_LANE_40_LN_R_CTLE_RSTN, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_42 */ -#define SD25G_LANE_LANE_42(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 264, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_42 */ +#define SD25G_LANE_LANE_42(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 264, 0, 1, 4) #define SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0 GENMASK(7, 0) #define SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_SET(x)\ @@ -2026,8 +2223,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_42_LN_CFG_TX_RESERVE_7_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_43 */ -#define SD25G_LANE_LANE_43(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 268, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_43 */ +#define SD25G_LANE_LANE_43(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 268, 0, 1, 4) #define SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8 GENMASK(7, 0) #define SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_SET(x)\ @@ -2035,8 +2234,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8_GET(x)\ FIELD_GET(SD25G_LANE_LANE_43_LN_CFG_TX_RESERVE_15_8, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_44 */ -#define SD25G_LANE_LANE_44(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 272, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_44 */ +#define SD25G_LANE_LANE_44(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 272, 0, 1, 4) #define SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0 GENMASK(7, 0) #define SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_SET(x)\ @@ -2044,8 +2245,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0_GET(x)\ FIELD_GET(SD25G_LANE_LANE_44_LN_CFG_RX_RESERVE_7_0, x) -/* SD25G_TARGET:LANE_GRP_0:LANE_45 */ -#define SD25G_LANE_LANE_45(t) __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 276, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_0:LANE_45 */ +#define SD25G_LANE_LANE_45(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1024, 0, 1, 768, 276, 0, 1, 4) #define SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8 GENMASK(7, 0) #define SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_SET(x)\ @@ -2053,8 +2256,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8_GET(x)\ FIELD_GET(SD25G_LANE_LANE_45_LN_CFG_RX_RESERVE_15_8, x) -/* SD25G_TARGET:LANE_GRP_1:LANE_DE */ -#define SD25G_LANE_LANE_DE(t) __REG(TARGET_SD25G_LANE, t, 8, 1792, 0, 1, 128, 120, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_TARGET:LANE_GRP_1:LANE_DE */ +#define SD25G_LANE_LANE_DE(t) \ + __REG(TARGET_SD25G_LANE, t, 8, 1792, 0, 1, 128, 120, 0, 1, 4) #define SD25G_LANE_LANE_DE_LN_LOL_UDL BIT(0) #define SD25G_LANE_LANE_DE_LN_LOL_UDL_SET(x)\ @@ -2080,8 +2285,10 @@ enum sparx5_serdes_target { #define SD25G_LANE_LANE_DE_LN_PMA_RXEI_GET(x)\ FIELD_GET(SD25G_LANE_LANE_DE_LN_PMA_RXEI, x) -/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ -#define SD6G_LANE_LANE_DF(t) __REG(TARGET_SD6G_LANE, t, 13, 832, 0, 1, 84, 60, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD10G_LANE_TARGET:LANE_GRP_8:LANE_DF */ +#define SD6G_LANE_LANE_DF(t) \ + __REG(TARGET_SD6G_LANE, t, 13, 832, 0, 1, 84, 60, 0, 1, 4) #define SD6G_LANE_LANE_DF_LOL_UDL BIT(0) #define SD6G_LANE_LANE_DF_LOL_UDL_SET(x)\ @@ -2107,8 +2314,9 @@ enum sparx5_serdes_target { #define SD6G_LANE_LANE_DF_SQUELCH_GET(x)\ FIELD_GET(SD6G_LANE_LANE_DF_SQUELCH, x) -/* SD10G_CMU_TARGET:CMU_GRP_0:CMU_00 */ -#define SD_CMU_CMU_00(t) __REG(TARGET_SD_CMU, t, 14, 0, 0, 1, 20, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_0:CMU_00 */ +#define SD_CMU_CMU_00(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 0, 0, 1, 20, 0, 0, 1, 4) #define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE BIT(0) #define SD_CMU_CMU_00_R_HWT_SIMULATION_MODE_SET(x)\ @@ -2134,8 +2342,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0_GET(x)\ FIELD_GET(SD_CMU_CMU_00_CFG_PLL_TP_SEL_1_0, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_05 */ -#define SD_CMU_CMU_05(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_05 */ +#define SD_CMU_CMU_05(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 0, 0, 1, 4) #define SD_CMU_CMU_05_CFG_REFCK_TERM_EN BIT(0) #define SD_CMU_CMU_05_CFG_REFCK_TERM_EN_SET(x)\ @@ -2149,9 +2358,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0_GET(x)\ FIELD_GET(SD_CMU_CMU_05_CFG_BIAS_TP_SEL_1_0, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_06 */ -#define SD_CMU_CMU_06(t) \ - __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 4, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_06 */ +#define SD_CMU_CMU_06(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 4, 0, 1, 4) #define SD_CMU_CMU_06_CFG_DISLOS BIT(0) #define SD_CMU_CMU_06_CFG_DISLOS_SET(x)\ @@ -2201,9 +2410,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_06_CFG_VCO_CAL_BYP_GET(x)\ FIELD_GET(SD_CMU_CMU_06_CFG_VCO_CAL_BYP, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_08 */ -#define SD_CMU_CMU_08(t) \ - __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 12, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_08 */ +#define SD_CMU_CMU_08(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 12, 0, 1, 4) #define SD_CMU_CMU_08_CFG_VFILT2PAD BIT(0) #define SD_CMU_CMU_08_CFG_VFILT2PAD_SET(x)\ @@ -2235,8 +2444,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_EN_GET(x)\ FIELD_GET(SD_CMU_CMU_08_CFG_RST_TREE_PD_MAN_EN, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_09 */ -#define SD_CMU_CMU_09(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 16, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_09 */ +#define SD_CMU_CMU_09(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 16, 0, 1, 4) #define SD_CMU_CMU_09_CFG_EN_TX_CK_UP BIT(0) #define SD_CMU_CMU_09_CFG_EN_TX_CK_UP_SET(x)\ @@ -2262,8 +2472,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_09_CFG_SW_10G_GET(x)\ FIELD_GET(SD_CMU_CMU_09_CFG_SW_10G, x) -/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_0D */ -#define SD_CMU_CMU_0D(t) __REG(TARGET_SD_CMU, t, 14, 20, 0, 1, 72, 32, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_1:CMU_0D */ +#define SD_CMU_CMU_0D(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 20, 0, 1, 72, 32, 0, 1, 4) #define SD_CMU_CMU_0D_CFG_PD_DIV64 BIT(0) #define SD_CMU_CMU_0D_CFG_PD_DIV64_SET(x)\ @@ -2295,8 +2506,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_0D_CFG_REFCK_PD_GET(x)\ FIELD_GET(SD_CMU_CMU_0D_CFG_REFCK_PD, x) -/* SD10G_CMU_TARGET:CMU_GRP_3:CMU_1B */ -#define SD_CMU_CMU_1B(t) __REG(TARGET_SD_CMU, t, 14, 104, 0, 1, 20, 4, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_3:CMU_1B */ +#define SD_CMU_CMU_1B(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 104, 0, 1, 20, 4, 0, 1, 4) #define SD_CMU_CMU_1B_CFG_RESERVE_7_0 GENMASK(7, 0) #define SD_CMU_CMU_1B_CFG_RESERVE_7_0_SET(x)\ @@ -2304,8 +2516,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_1B_CFG_RESERVE_7_0_GET(x)\ FIELD_GET(SD_CMU_CMU_1B_CFG_RESERVE_7_0, x) -/* SD10G_CMU_TARGET:CMU_GRP_4:CMU_1F */ -#define SD_CMU_CMU_1F(t) __REG(TARGET_SD_CMU, t, 14, 124, 0, 1, 68, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_4:CMU_1F */ +#define SD_CMU_CMU_1F(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 124, 0, 1, 68, 0, 0, 1, 4) #define SD_CMU_CMU_1F_CFG_BIAS_DN_EN BIT(0) #define SD_CMU_CMU_1F_CFG_BIAS_DN_EN_SET(x)\ @@ -2331,8 +2544,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_1F_CFG_VTUNE_SEL_GET(x)\ FIELD_GET(SD_CMU_CMU_1F_CFG_VTUNE_SEL, x) -/* SD10G_CMU_TARGET:CMU_GRP_5:CMU_30 */ -#define SD_CMU_CMU_30(t) __REG(TARGET_SD_CMU, t, 14, 192, 0, 1, 72, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_5:CMU_30 */ +#define SD_CMU_CMU_30(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 192, 0, 1, 72, 0, 0, 1, 4) #define SD_CMU_CMU_30_R_PLL_DLOL_EN BIT(0) #define SD_CMU_CMU_30_R_PLL_DLOL_EN_SET(x)\ @@ -2340,8 +2554,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_30_R_PLL_DLOL_EN_GET(x)\ FIELD_GET(SD_CMU_CMU_30_R_PLL_DLOL_EN, x) -/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_44 */ -#define SD_CMU_CMU_44(t) __REG(TARGET_SD_CMU, t, 14, 264, 0, 1, 632, 8, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_44 */ +#define SD_CMU_CMU_44(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 264, 0, 1, 632, 8, 0, 1, 4) #define SD_CMU_CMU_44_R_PLL_RSTN BIT(0) #define SD_CMU_CMU_44_R_PLL_RSTN_SET(x)\ @@ -2355,8 +2570,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_44_R_CK_RESETB_GET(x)\ FIELD_GET(SD_CMU_CMU_44_R_CK_RESETB, x) -/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_45 */ -#define SD_CMU_CMU_45(t) __REG(TARGET_SD_CMU, t, 14, 264, 0, 1, 632, 12, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_45 */ +#define SD_CMU_CMU_45(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 264, 0, 1, 632, 12, 0, 1, 4) #define SD_CMU_CMU_45_R_EN_RATECHG_CTRL BIT(0) #define SD_CMU_CMU_45_R_EN_RATECHG_CTRL_SET(x)\ @@ -2406,8 +2622,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN_GET(x)\ FIELD_GET(SD_CMU_CMU_45_R_AUTO_RST_TREE_PD_MAN, x) -/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_47 */ -#define SD_CMU_CMU_47(t) __REG(TARGET_SD_CMU, t, 14, 264, 0, 1, 632, 20, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_6:CMU_47 */ +#define SD_CMU_CMU_47(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 264, 0, 1, 632, 20, 0, 1, 4) #define SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0 GENMASK(4, 0) #define SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_SET(x)\ @@ -2415,8 +2632,9 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0_GET(x)\ FIELD_GET(SD_CMU_CMU_47_R_PCS2PMA_PHYMODE_4_0, x) -/* SD10G_CMU_TARGET:CMU_GRP_7:CMU_E0 */ -#define SD_CMU_CMU_E0(t) __REG(TARGET_SD_CMU, t, 14, 896, 0, 1, 8, 0, 0, 1, 4) +/* SD10G_CMU_TARGET:CMU_GRP_7:CMU_E0 */ +#define SD_CMU_CMU_E0(t) \ + __REG(TARGET_SD_CMU, t, TSIZE(TC_SD_CMU), 896, 0, 1, 8, 0, 0, 1, 4) #define SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0 GENMASK(3, 0) #define SD_CMU_CMU_E0_READ_VCO_CTUNE_3_0_SET(x)\ @@ -2430,8 +2648,10 @@ enum sparx5_serdes_target { #define SD_CMU_CMU_E0_PLL_LOL_UDL_GET(x)\ FIELD_GET(SD_CMU_CMU_E0_PLL_LOL_UDL, x) -/* SD_CMU_TARGET:SD_CMU_CFG:SD_CMU_CFG */ -#define SD_CMU_CFG_SD_CMU_CFG(t) __REG(TARGET_SD_CMU_CFG, t, 14, 0, 0, 1, 8, 0, 0, 1, 4) +/* SD_CMU_TARGET:SD_CMU_CFG:SD_CMU_CFG */ +#define SD_CMU_CFG_SD_CMU_CFG(t) \ + __REG(TARGET_SD_CMU_CFG, t, TSIZE(TC_SD_CMU_CFG), 0, 0, 1, 8, 0, 0, 1, \ + 4) #define SD_CMU_CFG_SD_CMU_CFG_CMU_RST BIT(0) #define SD_CMU_CFG_SD_CMU_CFG_CMU_RST_SET(x)\ @@ -2445,8 +2665,9 @@ enum sparx5_serdes_target { #define SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST_GET(x)\ FIELD_GET(SD_CMU_CFG_SD_CMU_CFG_EXT_CFG_RST, x) -/* SD_LANE_TARGET:SD_RESET:SD_SER_RST */ -#define SD_LANE_SD_SER_RST(t) __REG(TARGET_SD_LANE, t, 25, 0, 0, 1, 8, 0, 0, 1, 4) +/* SD_LANE_TARGET:SD_RESET:SD_SER_RST */ +#define SD_LANE_SD_SER_RST(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 0, 0, 1, 8, 0, 0, 1, 4) #define SD_LANE_SD_SER_RST_SER_RST BIT(0) #define SD_LANE_SD_SER_RST_SER_RST_SET(x)\ @@ -2454,8 +2675,9 @@ enum sparx5_serdes_target { #define SD_LANE_SD_SER_RST_SER_RST_GET(x)\ FIELD_GET(SD_LANE_SD_SER_RST_SER_RST, x) -/* SD_LANE_TARGET:SD_RESET:SD_DES_RST */ -#define SD_LANE_SD_DES_RST(t) __REG(TARGET_SD_LANE, t, 25, 0, 0, 1, 8, 4, 0, 1, 4) +/* SD_LANE_TARGET:SD_RESET:SD_DES_RST */ +#define SD_LANE_SD_DES_RST(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 0, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_SD_DES_RST_DES_RST BIT(0) #define SD_LANE_SD_DES_RST_DES_RST_SET(x)\ @@ -2463,8 +2685,9 @@ enum sparx5_serdes_target { #define SD_LANE_SD_DES_RST_DES_RST_GET(x)\ FIELD_GET(SD_LANE_SD_DES_RST_DES_RST, x) -/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ -#define SD_LANE_SD_LANE_CFG(t) __REG(TARGET_SD_LANE, t, 25, 8, 0, 1, 8, 0, 0, 1, 4) +/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ +#define SD_LANE_SD_LANE_CFG(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 8, 0, 1, 8, 0, 0, 1, 4) #define SD_LANE_SD_LANE_CFG_MACRO_RST BIT(0) #define SD_LANE_SD_LANE_CFG_MACRO_RST_SET(x)\ @@ -2508,8 +2731,9 @@ enum sparx5_serdes_target { #define SD_LANE_SD_LANE_CFG_LANE_RX_RST_GET(x)\ FIELD_GET(SD_LANE_SD_LANE_CFG_LANE_RX_RST, x) -/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ -#define SD_LANE_SD_LANE_STAT(t) __REG(TARGET_SD_LANE, t, 25, 8, 0, 1, 8, 4, 0, 1, 4) +/* SD_LANE_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ +#define SD_LANE_SD_LANE_STAT(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 8, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_SD_LANE_STAT_PMA_RST_DONE BIT(0) #define SD_LANE_SD_LANE_STAT_PMA_RST_DONE_SET(x)\ @@ -2529,9 +2753,9 @@ enum sparx5_serdes_target { #define SD_LANE_SD_LANE_STAT_DBG_OBS_GET(x)\ FIELD_GET(SD_LANE_SD_LANE_STAT_DBG_OBS, x) -/* SD_LANE_TARGET:SD_PWR_CFG:QUIET_MODE_6G */ -#define SD_LANE_QUIET_MODE_6G(t) \ - __REG(TARGET_SD_LANE, t, 25, 24, 0, 1, 8, 4, 0, 1, 4) +/* SD_LANE_TARGET:SD_PWR_CFG:QUIET_MODE_6G */ +#define SD_LANE_QUIET_MODE_6G(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 24, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_QUIET_MODE_6G_QUIET_MODE GENMASK(24, 0) #define SD_LANE_QUIET_MODE_6G_QUIET_MODE_SET(x)\ @@ -2539,8 +2763,9 @@ enum sparx5_serdes_target { #define SD_LANE_QUIET_MODE_6G_QUIET_MODE_GET(x)\ FIELD_GET(SD_LANE_QUIET_MODE_6G_QUIET_MODE, x) -/* SD_LANE_TARGET:CFG_STAT_FX100:MISC */ -#define SD_LANE_MISC(t) __REG(TARGET_SD_LANE, t, 25, 56, 0, 1, 56, 0, 0, 1, 4) +/* SD_LANE_TARGET:CFG_STAT_FX100:MISC */ +#define SD_LANE_MISC(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 56, 0, 1, 56, 0, 0, 1, 4) #define SD_LANE_MISC_SD_125_RST_DIS BIT(0) #define SD_LANE_MISC_SD_125_RST_DIS_SET(x)\ @@ -2560,14 +2785,16 @@ enum sparx5_serdes_target { #define SD_LANE_MISC_MUX_ENA_GET(x)\ FIELD_GET(SD_LANE_MISC_MUX_ENA, x) +/* SPARX5 ONLY */ #define SD_LANE_MISC_CORE_CLK_FREQ GENMASK(5, 4) #define SD_LANE_MISC_CORE_CLK_FREQ_SET(x)\ FIELD_PREP(SD_LANE_MISC_CORE_CLK_FREQ, x) #define SD_LANE_MISC_CORE_CLK_FREQ_GET(x)\ FIELD_GET(SD_LANE_MISC_CORE_CLK_FREQ, x) -/* SD_LANE_TARGET:CFG_STAT_FX100:M_STAT_MISC */ -#define SD_LANE_M_STAT_MISC(t) __REG(TARGET_SD_LANE, t, 25, 56, 0, 1, 56, 36, 0, 1, 4) +/* SD_LANE_TARGET:CFG_STAT_FX100:M_STAT_MISC */ +#define SD_LANE_M_STAT_MISC(t) \ + __REG(TARGET_SD_LANE, t, TSIZE(TC_SD_LANE), 56, 0, 1, 56, 36, 0, 1, 4) #define SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM GENMASK(21, 0) #define SD_LANE_M_STAT_MISC_M_RIS_EDGE_PTR_ADJ_SUM_SET(x)\ @@ -2581,8 +2808,10 @@ enum sparx5_serdes_target { #define SD_LANE_M_STAT_MISC_M_LOCK_CNT_GET(x)\ FIELD_GET(SD_LANE_M_STAT_MISC_M_LOCK_CNT, x) -/* SD25G_CFG_TARGET:SD_RESET:SD_SER_RST */ -#define SD_LANE_25G_SD_SER_RST(t) __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_RESET:SD_SER_RST */ +#define SD_LANE_25G_SD_SER_RST(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 0, 0, 1, 4) #define SD_LANE_25G_SD_SER_RST_SER_RST BIT(0) #define SD_LANE_25G_SD_SER_RST_SER_RST_SET(x)\ @@ -2590,8 +2819,10 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_SER_RST_SER_RST_GET(x)\ FIELD_GET(SD_LANE_25G_SD_SER_RST_SER_RST, x) -/* SD25G_CFG_TARGET:SD_RESET:SD_DES_RST */ -#define SD_LANE_25G_SD_DES_RST(t) __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_RESET:SD_DES_RST */ +#define SD_LANE_25G_SD_DES_RST(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 0, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_25G_SD_DES_RST_DES_RST BIT(0) #define SD_LANE_25G_SD_DES_RST_DES_RST_SET(x)\ @@ -2599,8 +2830,10 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_DES_RST_DES_RST_GET(x)\ FIELD_GET(SD_LANE_25G_SD_DES_RST_DES_RST, x) -/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ -#define SD_LANE_25G_SD_LANE_CFG(t) __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 0, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG */ +#define SD_LANE_25G_SD_LANE_CFG(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 0, 0, 1, 4) #define SD_LANE_25G_SD_LANE_CFG_MACRO_RST BIT(0) #define SD_LANE_25G_SD_LANE_CFG_MACRO_RST_SET(x)\ @@ -2698,8 +2931,10 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN_GET(x)\ FIELD_GET(SD_LANE_25G_SD_LANE_CFG_PCS2PMA_TXMARGIN, x) -/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG2 */ -#define SD_LANE_25G_SD_LANE_CFG2(t) __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 4, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_CFG2 */ +#define SD_LANE_25G_SD_LANE_CFG2(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 4, 0, 1, 4) #define SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL GENMASK(2, 0) #define SD_LANE_25G_SD_LANE_CFG2_DATA_WIDTH_SEL_SET(x)\ @@ -2767,8 +3002,10 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL_GET(x)\ FIELD_GET(SD_LANE_25G_SD_LANE_CFG2_RXRATE_SEL, x) -/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ -#define SD_LANE_25G_SD_LANE_STAT(t) __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 8, 0, 1, 4) +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_LANE_CFG_STAT:SD_LANE_STAT */ +#define SD_LANE_25G_SD_LANE_STAT(t) \ + __REG(TARGET_SD_LANE_25G, t, 8, 8, 0, 1, 12, 8, 0, 1, 4) #define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE BIT(0) #define SD_LANE_25G_SD_LANE_STAT_PMA_RST_DONE_SET(x)\ @@ -2788,8 +3025,9 @@ enum sparx5_serdes_target { #define SD_LANE_25G_SD_LANE_STAT_DBG_OBS_GET(x)\ FIELD_GET(SD_LANE_25G_SD_LANE_STAT_DBG_OBS, x) -/* SD25G_CFG_TARGET:SD_PWR_CFG:QUIET_MODE_6G */ -#define SD_LANE_25G_QUIET_MODE_6G(t) \ +/* SPARX5 ONLY */ +/* SD25G_CFG_TARGET:SD_PWR_CFG:QUIET_MODE_6G */ +#define SD_LANE_25G_QUIET_MODE_6G(t) \ __REG(TARGET_SD_LANE_25G, t, 8, 28, 0, 1, 8, 4, 0, 1, 4) #define SD_LANE_25G_QUIET_MODE_6G_QUIET_MODE GENMASK(24, 0) diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 7bbf729a7c90..7cb020dd3423 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -704,7 +704,7 @@ static void cpcap_usb_phy_remove(struct platform_device *pdev) static struct platform_driver cpcap_usb_phy_driver = { .probe = cpcap_usb_phy_probe, - .remove_new = cpcap_usb_phy_remove, + .remove = cpcap_usb_phy_remove, .driver = { .name = "cpcap-usb-phy", .of_match_table = of_match_ptr(cpcap_usb_phy_id_table), diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c index 376d023a0aa9..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); } /** @@ -655,7 +653,7 @@ static void phy_mdm6600_remove(struct platform_device *pdev) static struct platform_driver phy_mdm6600_driver = { .probe = phy_mdm6600_probe, - .remove_new = phy_mdm6600_remove, + .remove = phy_mdm6600_remove, .driver = { .name = "phy-mapphone-mdm6600", .pm = &phy_mdm6600_pm_ops, diff --git a/drivers/phy/mscc/phy-ocelot-serdes.c b/drivers/phy/mscc/phy-ocelot-serdes.c index d9443e865a78..1cd1b5db2ad7 100644 --- a/drivers/phy/mscc/phy-ocelot-serdes.c +++ b/drivers/phy/mscc/phy-ocelot-serdes.c @@ -441,7 +441,7 @@ static const struct phy_ops serdes_ops = { }; static struct phy *serdes_simple_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct serdes_ctrl *ctrl = dev_get_drvdata(dev); unsigned int port, idx, i; diff --git a/drivers/phy/nuvoton/Kconfig b/drivers/phy/nuvoton/Kconfig new file mode 100644 index 000000000000..d02cae2db315 --- /dev/null +++ b/drivers/phy/nuvoton/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# PHY drivers for Nuvoton MA35 platforms +# +config PHY_MA35_USB + tristate "Nuvoton MA35 USB2.0 PHY driver" + depends on ARCH_MA35 || COMPILE_TEST + depends on OF + select GENERIC_PHY + help + Enable this to support the USB2.0 PHY on the Nuvoton MA35 + series SoCs. diff --git a/drivers/phy/nuvoton/Makefile b/drivers/phy/nuvoton/Makefile new file mode 100644 index 000000000000..2937e3921898 --- /dev/null +++ b/drivers/phy/nuvoton/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_PHY_MA35_USB) += phy-ma35d1-usb2.o diff --git a/drivers/phy/nuvoton/phy-ma35d1-usb2.c b/drivers/phy/nuvoton/phy-ma35d1-usb2.c new file mode 100644 index 000000000000..9a459b700ed4 --- /dev/null +++ b/drivers/phy/nuvoton/phy-ma35d1-usb2.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Nuvoton Technology Corp. + */ +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +/* USB PHY Miscellaneous Control Register */ +#define MA35_SYS_REG_USBPMISCR 0x60 +#define PHY0POR BIT(0) /* PHY Power-On Reset Control Bit */ +#define PHY0SUSPEND BIT(1) /* PHY Suspend; 0: suspend, 1: operaion */ +#define PHY0COMN BIT(2) /* PHY Common Block Power-Down Control */ +#define PHY0DEVCKSTB BIT(10) /* PHY 60 MHz UTMI clock stable bit */ + +struct ma35_usb_phy { + struct clk *clk; + struct device *dev; + struct regmap *sysreg; +}; + +static int ma35_usb_phy_power_on(struct phy *phy) +{ + struct ma35_usb_phy *p_phy = phy_get_drvdata(phy); + unsigned int val; + int ret; + + ret = clk_prepare_enable(p_phy->clk); + if (ret < 0) { + dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret); + return ret; + } + + regmap_read(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, &val); + if (val & PHY0SUSPEND) { + /* + * USB PHY0 is in operation mode already + * make sure USB PHY 60 MHz UTMI Interface Clock ready + */ + ret = regmap_read_poll_timeout(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, val, + val & PHY0DEVCKSTB, 10, 1000); + if (ret == 0) + return 0; + } + + /* + * reset USB PHY0. + * wait until USB PHY0 60 MHz UTMI Interface Clock ready + */ + regmap_update_bits(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, 0x7, (PHY0POR | PHY0SUSPEND)); + udelay(20); + + /* make USB PHY0 enter operation mode */ + regmap_update_bits(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, 0x7, PHY0SUSPEND); + + /* make sure USB PHY 60 MHz UTMI Interface Clock ready */ + ret = regmap_read_poll_timeout(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, val, + val & PHY0DEVCKSTB, 10, 1000); + if (ret == -ETIMEDOUT) { + dev_err(p_phy->dev, "Check PHY clock, Timeout: %d\n", ret); + clk_disable_unprepare(p_phy->clk); + return ret; + } + + return 0; +} + +static int ma35_usb_phy_power_off(struct phy *phy) +{ + struct ma35_usb_phy *p_phy = phy_get_drvdata(phy); + + clk_disable_unprepare(p_phy->clk); + return 0; +} + +static const struct phy_ops ma35_usb_phy_ops = { + .power_on = ma35_usb_phy_power_on, + .power_off = ma35_usb_phy_power_off, + .owner = THIS_MODULE, +}; + +static int ma35_usb_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *provider; + struct ma35_usb_phy *p_phy; + struct phy *phy; + + p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL); + if (!p_phy) + return -ENOMEM; + + p_phy->dev = &pdev->dev; + platform_set_drvdata(pdev, p_phy); + + p_phy->sysreg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "nuvoton,sys"); + if (IS_ERR(p_phy->sysreg)) + return dev_err_probe(&pdev->dev, PTR_ERR(p_phy->sysreg), + "Failed to get SYS registers\n"); + + p_phy->clk = of_clk_get(pdev->dev.of_node, 0); + if (IS_ERR(p_phy->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(p_phy->clk), + "failed to find usb_phy clock\n"); + + phy = devm_phy_create(&pdev->dev, NULL, &ma35_usb_phy_ops); + if (IS_ERR(phy)) + return dev_err_probe(&pdev->dev, PTR_ERR(phy), "Failed to create PHY\n"); + + phy_set_drvdata(phy, p_phy); + + provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); + if (IS_ERR(provider)) + return dev_err_probe(&pdev->dev, PTR_ERR(provider), + "Failed to register PHY provider\n"); + return 0; +} + +static const struct of_device_id ma35_usb_phy_of_match[] = { + { .compatible = "nuvoton,ma35d1-usb2-phy", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ma35_usb_phy_of_match); + +static struct platform_driver ma35_usb_phy_driver = { + .probe = ma35_usb_phy_probe, + .driver = { + .name = "ma35d1-usb2-phy", + .of_match_table = ma35_usb_phy_of_match, + }, +}; +module_platform_driver(ma35_usb_phy_driver); + +MODULE_DESCRIPTION("Nuvoton ma35d1 USB2.0 PHY driver"); +MODULE_AUTHOR("Hui-Ping Chen <hpchen0nvt@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/phy-airoha-pcie-regs.h b/drivers/phy/phy-airoha-pcie-regs.h new file mode 100644 index 000000000000..b938a7b468fe --- /dev/null +++ b/drivers/phy/phy-airoha-pcie-regs.h @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 AIROHA Inc + * Author: Lorenzo Bianconi <lorenzo@kernel.org> + */ + +#ifndef _PHY_AIROHA_PCIE_H +#define _PHY_AIROHA_PCIE_H + +/* CSR_2L */ +#define REG_CSR_2L_CMN 0x0000 +#define CSR_2L_PXP_CMN_LANE_EN BIT(0) +#define CSR_2L_PXP_CMN_TRIM_MASK GENMASK(28, 24) + +#define REG_CSR_2L_JCPLL_IB_EXT 0x0004 +#define REG_CSR_2L_JCPLL_LPF_SHCK_EN BIT(8) +#define CSR_2L_PXP_JCPLL_CHP_IBIAS GENMASK(21, 16) +#define CSR_2L_PXP_JCPLL_CHP_IOFST GENMASK(29, 24) + +#define REG_CSR_2L_JCPLL_LPF_BR 0x0008 +#define CSR_2L_PXP_JCPLL_LPF_BR GENMASK(4, 0) +#define CSR_2L_PXP_JCPLL_LPF_BC GENMASK(12, 8) +#define CSR_2L_PXP_JCPLL_LPF_BP GENMASK(20, 16) +#define CSR_2L_PXP_JCPLL_LPF_BWR GENMASK(28, 24) + +#define REG_CSR_2L_JCPLL_LPF_BWC 0x000c +#define CSR_2L_PXP_JCPLL_LPF_BWC GENMASK(4, 0) +#define CSR_2L_PXP_JCPLL_KBAND_CODE GENMASK(23, 16) +#define CSR_2L_PXP_JCPLL_KBAND_DIV GENMASK(26, 24) + +#define REG_CSR_2L_JCPLL_KBAND_KFC 0x0010 +#define CSR_2L_PXP_JCPLL_KBAND_KFC GENMASK(1, 0) +#define CSR_2L_PXP_JCPLL_KBAND_KF GENMASK(9, 8) +#define CSR_2L_PXP_JCPLL_KBAND_KS GENMASK(17, 16) +#define CSR_2L_PXP_JCPLL_POSTDIV_EN BIT(24) + +#define REG_CSR_2L_JCPLL_MMD_PREDIV_MODE 0x0014 +#define CSR_2L_PXP_JCPLL_MMD_PREDIV_MODE GENMASK(1, 0) +#define CSR_2L_PXP_JCPLL_POSTDIV_D2 BIT(16) +#define CSR_2L_PXP_JCPLL_POSTDIV_D5 BIT(24) + +#define CSR_2L_PXP_JCPLL_MONCK 0x0018 +#define CSR_2L_PXP_JCPLL_REFIN_DIV GENMASK(25, 24) + +#define REG_CSR_2L_JCPLL_RST_DLY 0x001c +#define CSR_2L_PXP_JCPLL_RST_DLY GENMASK(2, 0) +#define CSR_2L_PXP_JCPLL_RST BIT(8) +#define CSR_2L_PXP_JCPLL_SDM_DI_EN BIT(16) +#define CSR_2L_PXP_JCPLL_SDM_DI_LS GENMASK(25, 24) + +#define REG_CSR_2L_JCPLL_SDM_IFM 0x0020 +#define CSR_2L_PXP_JCPLL_SDM_IFM BIT(0) + +#define REG_CSR_2L_JCPLL_SDM_HREN 0x0024 +#define CSR_2L_PXP_JCPLL_SDM_HREN BIT(0) +#define CSR_2L_PXP_JCPLL_TCL_AMP_EN BIT(8) +#define CSR_2L_PXP_JCPLL_TCL_AMP_GAIN GENMASK(18, 16) +#define CSR_2L_PXP_JCPLL_TCL_AMP_VREF GENMASK(28, 24) + +#define REG_CSR_2L_JCPLL_TCL_CMP 0x0028 +#define CSR_2L_PXP_JCPLL_TCL_LPF_EN BIT(16) +#define CSR_2L_PXP_JCPLL_TCL_LPF_BW GENMASK(26, 24) + +#define REG_CSR_2L_JCPLL_VCODIV 0x002c +#define CSR_2L_PXP_JCPLL_VCO_CFIX GENMASK(9, 8) +#define CSR_2L_PXP_JCPLL_VCO_HALFLSB_EN BIT(16) +#define CSR_2L_PXP_JCPLL_VCO_SCAPWR GENMASK(26, 24) + +#define REG_CSR_2L_JCPLL_VCO_TCLVAR 0x0030 +#define CSR_2L_PXP_JCPLL_VCO_TCLVAR GENMASK(2, 0) + +#define REG_CSR_2L_JCPLL_SSC 0x0038 +#define CSR_2L_PXP_JCPLL_SSC_EN BIT(0) +#define CSR_2L_PXP_JCPLL_SSC_PHASE_INI BIT(8) +#define CSR_2L_PXP_JCPLL_SSC_TRI_EN BIT(16) + +#define REG_CSR_2L_JCPLL_SSC_DELTA1 0x003c +#define CSR_2L_PXP_JCPLL_SSC_DELTA1 GENMASK(15, 0) +#define CSR_2L_PXP_JCPLL_SSC_DELTA GENMASK(31, 16) + +#define REG_CSR_2L_JCPLL_SSC_PERIOD 0x0040 +#define CSR_2L_PXP_JCPLL_SSC_PERIOD GENMASK(15, 0) + +#define REG_CSR_2L_JCPLL_TCL_VTP_EN 0x004c +#define CSR_2L_PXP_JCPLL_SPARE_LOW GENMASK(31, 24) + +#define REG_CSR_2L_JCPLL_TCL_KBAND_VREF 0x0050 +#define CSR_2L_PXP_JCPLL_TCL_KBAND_VREF GENMASK(4, 0) +#define CSR_2L_PXP_JCPLL_VCO_KBAND_MEAS_EN BIT(24) + +#define REG_CSR_2L_750M_SYS_CK 0x0054 +#define CSR_2L_PXP_TXPLL_LPF_SHCK_EN BIT(16) +#define CSR_2L_PXP_TXPLL_CHP_IBIAS GENMASK(29, 24) + +#define REG_CSR_2L_TXPLL_CHP_IOFST 0x0058 +#define CSR_2L_PXP_TXPLL_CHP_IOFST GENMASK(5, 0) +#define CSR_2L_PXP_TXPLL_LPF_BR GENMASK(12, 8) +#define CSR_2L_PXP_TXPLL_LPF_BC GENMASK(20, 16) +#define CSR_2L_PXP_TXPLL_LPF_BP GENMASK(28, 24) + +#define REG_CSR_2L_TXPLL_LPF_BWR 0x005c +#define CSR_2L_PXP_TXPLL_LPF_BWR GENMASK(4, 0) +#define CSR_2L_PXP_TXPLL_LPF_BWC GENMASK(12, 8) +#define CSR_2L_PXP_TXPLL_KBAND_CODE GENMASK(31, 24) + +#define REG_CSR_2L_TXPLL_KBAND_DIV 0x0060 +#define CSR_2L_PXP_TXPLL_KBAND_DIV GENMASK(2, 0) +#define CSR_2L_PXP_TXPLL_KBAND_KFC GENMASK(9, 8) +#define CSR_2L_PXP_TXPLL_KBAND_KF GENMASK(17, 16) +#define CSR_2L_PXP_txpll_KBAND_KS GENMASK(25, 24) + +#define REG_CSR_2L_TXPLL_POSTDIV 0x0064 +#define CSR_2L_PXP_TXPLL_POSTDIV_EN BIT(0) +#define CSR_2L_PXP_TXPLL_MMD_PREDIV_MODE GENMASK(9, 8) +#define CSR_2L_PXP_TXPLL_PHY_CK1_EN BIT(24) + +#define REG_CSR_2L_TXPLL_PHY_CK2 0x0068 +#define CSR_2L_PXP_TXPLL_REFIN_INTERNAL BIT(24) + +#define REG_CSR_2L_TXPLL_REFIN_DIV 0x006c +#define CSR_2L_PXP_TXPLL_REFIN_DIV GENMASK(1, 0) +#define CSR_2L_PXP_TXPLL_RST_DLY GENMASK(10, 8) +#define CSR_2L_PXP_TXPLL_PLL_RSTB BIT(16) + +#define REG_CSR_2L_TXPLL_SDM_DI_LS 0x0070 +#define CSR_2L_PXP_TXPLL_SDM_DI_LS GENMASK(1, 0) +#define CSR_2L_PXP_TXPLL_SDM_IFM BIT(8) +#define CSR_2L_PXP_TXPLL_SDM_ORD GENMASK(25, 24) + +#define REG_CSR_2L_TXPLL_SDM_OUT 0x0074 +#define CSR_2L_PXP_TXPLL_TCL_AMP_EN BIT(16) +#define CSR_2L_PXP_TXPLL_TCL_AMP_GAIN GENMASK(26, 24) + +#define REG_CSR_2L_TXPLL_TCL_AMP_VREF 0x0078 +#define CSR_2L_PXP_TXPLL_TCL_AMP_VREF GENMASK(4, 0) +#define CSR_2L_PXP_TXPLL_TCL_LPF_EN BIT(24) + +#define REG_CSR_2L_TXPLL_TCL_LPF_BW 0x007c +#define CSR_2L_PXP_TXPLL_TCL_LPF_BW GENMASK(2, 0) +#define CSR_2L_PXP_TXPLL_VCO_CFIX GENMASK(17, 16) +#define CSR_2L_PXP_TXPLL_VCO_HALFLSB_EN BIT(24) + +#define REG_CSR_2L_TXPLL_VCO_SCAPWR 0x0080 +#define CSR_2L_PXP_TXPLL_VCO_SCAPWR GENMASK(2, 0) + +#define REG_CSR_2L_TXPLL_SSC 0x0084 +#define CSR_2L_PXP_TXPLL_SSC_EN BIT(0) +#define CSR_2L_PXP_TXPLL_SSC_PHASE_INI BIT(8) + +#define REG_CSR_2L_TXPLL_SSC_DELTA1 0x0088 +#define CSR_2L_PXP_TXPLL_SSC_DELTA1 GENMASK(15, 0) +#define CSR_2L_PXP_TXPLL_SSC_DELTA GENMASK(31, 16) + +#define REG_CSR_2L_TXPLL_SSC_PERIOD 0x008c +#define CSR_2L_PXP_txpll_SSC_PERIOD GENMASK(15, 0) + +#define REG_CSR_2L_TXPLL_VTP 0x0090 +#define CSR_2L_PXP_TXPLL_VTP_EN BIT(0) + +#define REG_CSR_2L_TXPLL_TCL_VTP 0x0098 +#define CSR_2L_PXP_TXPLL_SPARE_L GENMASK(31, 24) + +#define REG_CSR_2L_TXPLL_TCL_KBAND_VREF 0x009c +#define CSR_2L_PXP_TXPLL_TCL_KBAND_VREF GENMASK(4, 0) +#define CSR_2L_PXP_TXPLL_VCO_KBAND_MEAS_EN BIT(24) + +#define REG_CSR_2L_TXPLL_POSTDIV_D256 0x00a0 +#define CSR_2L_PXP_CLKTX0_AMP GENMASK(10, 8) +#define CSR_2L_PXP_CLKTX0_OFFSET GENMASK(17, 16) +#define CSR_2L_PXP_CLKTX0_SR GENMASK(25, 24) + +#define REG_CSR_2L_CLKTX0_FORCE_OUT1 0x00a4 +#define CSR_2L_PXP_CLKTX0_HZ BIT(8) +#define CSR_2L_PXP_CLKTX0_IMP_SEL GENMASK(20, 16) +#define CSR_2L_PXP_CLKTX1_AMP GENMASK(26, 24) + +#define REG_CSR_2L_CLKTX1_OFFSET 0x00a8 +#define CSR_2L_PXP_CLKTX1_OFFSET GENMASK(1, 0) +#define CSR_2L_PXP_CLKTX1_SR GENMASK(9, 8) +#define CSR_2L_PXP_CLKTX1_HZ BIT(24) + +#define REG_CSR_2L_CLKTX1_IMP_SEL 0x00ac +#define CSR_2L_PXP_CLKTX1_IMP_SEL GENMASK(4, 0) + +#define REG_CSR_2L_PLL_CMN_RESERVE0 0x00b0 +#define CSR_2L_PXP_PLL_RESERVE_MASK GENMASK(15, 0) + +#define REG_CSR_2L_TX0_CKLDO 0x00cc +#define CSR_2L_PXP_TX0_CKLDO_EN BIT(0) +#define CSR_2L_PXP_TX0_DMEDGEGEN_EN BIT(24) + +#define REG_CSR_2L_TX1_CKLDO 0x00e8 +#define CSR_2L_PXP_TX1_CKLDO_EN BIT(0) +#define CSR_2L_PXP_TX1_DMEDGEGEN_EN BIT(24) + +#define REG_CSR_2L_TX1_MULTLANE 0x00ec +#define CSR_2L_PXP_TX1_MULTLANE_EN BIT(0) + +#define REG_CSR_2L_RX0_REV0 0x00fc +#define CSR_2L_PXP_VOS_PNINV GENMASK(19, 18) +#define CSR_2L_PXP_FE_GAIN_NORMAL_MODE GENMASK(22, 20) +#define CSR_2L_PXP_FE_GAIN_TRAIN_MODE GENMASK(26, 24) + +#define REG_CSR_2L_RX0_PHYCK_DIV 0x0100 +#define CSR_2L_PXP_RX0_PHYCK_SEL GENMASK(9, 8) +#define CSR_2L_PXP_RX0_PHYCK_RSTB BIT(16) +#define CSR_2L_PXP_RX0_TDC_CK_SEL BIT(24) + +#define REG_CSR_2L_CDR0_PD_PICAL_CKD8_INV 0x0104 +#define CSR_2L_PXP_CDR0_PD_EDGE_DISABLE BIT(8) + +#define REG_CSR_2L_CDR0_LPF_RATIO 0x0110 +#define CSR_2L_PXP_CDR0_LPF_TOP_LIM GENMASK(26, 8) + +#define REG_CSR_2L_CDR0_PR_INJ_MODE 0x011c +#define CSR_2L_PXP_CDR0_INJ_FORCE_OFF BIT(24) + +#define REG_CSR_2L_CDR0_PR_BETA_DAC 0x0120 +#define CSR_2L_PXP_CDR0_PR_BETA_SEL GENMASK(19, 16) +#define CSR_2L_PXP_CDR0_PR_KBAND_DIV GENMASK(26, 24) + +#define REG_CSR_2L_CDR0_PR_VREG_IBAND 0x0124 +#define CSR_2L_PXP_CDR0_PR_VREG_IBAND GENMASK(2, 0) +#define CSR_2L_PXP_CDR0_PR_VREG_CKBUF GENMASK(10, 8) + +#define REG_CSR_2L_CDR0_PR_CKREF_DIV 0x0128 +#define CSR_2L_PXP_CDR0_PR_CKREF_DIV GENMASK(1, 0) + +#define REG_CSR_2L_CDR0_PR_MONCK 0x012c +#define CSR_2L_PXP_CDR0_PR_MONCK_ENABLE BIT(0) +#define CSR_2L_PXP_CDR0_PR_RESERVE0 GENMASK(19, 16) + +#define REG_CSR_2L_CDR0_PR_COR_HBW 0x0130 +#define CSR_2L_PXP_CDR0_PR_LDO_FORCE_ON BIT(8) +#define CSR_2L_PXP_CDR0_PR_CKREF_DIV1 GENMASK(17, 16) + +#define REG_CSR_2L_CDR0_PR_MONPI 0x0134 +#define CSR_2L_PXP_CDR0_PR_XFICK_EN BIT(8) + +#define REG_CSR_2L_RX0_SIGDET_DCTEST 0x0140 +#define CSR_2L_PXP_RX0_SIGDET_LPF_CTRL GENMASK(9, 8) +#define CSR_2L_PXP_RX0_SIGDET_PEAK GENMASK(25, 24) + +#define REG_CSR_2L_RX0_SIGDET_VTH_SEL 0x0144 +#define CSR_2L_PXP_RX0_SIGDET_VTH_SEL GENMASK(4, 0) +#define CSR_2L_PXP_RX0_FE_VB_EQ1_EN BIT(24) + +#define REG_CSR_2L_PXP_RX0_FE_VB_EQ2 0x0148 +#define CSR_2L_PXP_RX0_FE_VB_EQ2_EN BIT(0) +#define CSR_2L_PXP_RX0_FE_VB_EQ3_EN BIT(8) +#define CSR_2L_PXP_RX0_FE_VCM_GEN_PWDB BIT(16) + +#define REG_CSR_2L_PXP_RX0_OSCAL_CTLE1IOS 0x0158 +#define CSR_2L_PXP_RX0_PR_OSCAL_VGA1IOS GENMASK(29, 24) + +#define REG_CSR_2L_PXP_RX0_OSCA_VGA1VOS 0x015c +#define CSR_2L_PXP_RX0_PR_OSCAL_VGA1VOS GENMASK(5, 0) +#define CSR_2L_PXP_RX0_PR_OSCAL_VGA2IOS GENMASK(13, 8) + +#define REG_CSR_2L_RX1_REV0 0x01b4 + +#define REG_CSR_2L_RX1_PHYCK_DIV 0x01b8 +#define CSR_2L_PXP_RX1_PHYCK_SEL GENMASK(9, 8) +#define CSR_2L_PXP_RX1_PHYCK_RSTB BIT(16) +#define CSR_2L_PXP_RX1_TDC_CK_SEL BIT(24) + +#define REG_CSR_2L_CDR1_PD_PICAL_CKD8_INV 0x01bc +#define CSR_2L_PXP_CDR1_PD_EDGE_DISABLE BIT(8) + +#define REG_CSR_2L_CDR1_PR_BETA_DAC 0x01d8 +#define CSR_2L_PXP_CDR1_PR_BETA_SEL GENMASK(19, 16) +#define CSR_2L_PXP_CDR1_PR_KBAND_DIV GENMASK(26, 24) + +#define REG_CSR_2L_CDR1_PR_MONCK 0x01e4 +#define CSR_2L_PXP_CDR1_PR_MONCK_ENABLE BIT(0) +#define CSR_2L_PXP_CDR1_PR_RESERVE0 GENMASK(19, 16) + +#define REG_CSR_2L_CDR1_LPF_RATIO 0x01c8 +#define CSR_2L_PXP_CDR1_LPF_TOP_LIM GENMASK(26, 8) + +#define REG_CSR_2L_CDR1_PR_INJ_MODE 0x01d4 +#define CSR_2L_PXP_CDR1_INJ_FORCE_OFF BIT(24) + +#define REG_CSR_2L_CDR1_PR_VREG_IBAND_VAL 0x01dc +#define CSR_2L_PXP_CDR1_PR_VREG_IBAND GENMASK(2, 0) +#define CSR_2L_PXP_CDR1_PR_VREG_CKBUF GENMASK(10, 8) + +#define REG_CSR_2L_CDR1_PR_CKREF_DIV 0x01e0 +#define CSR_2L_PXP_CDR1_PR_CKREF_DIV GENMASK(1, 0) + +#define REG_CSR_2L_CDR1_PR_COR_HBW 0x01e8 +#define CSR_2L_PXP_CDR1_PR_LDO_FORCE_ON BIT(8) +#define CSR_2L_PXP_CDR1_PR_CKREF_DIV1 GENMASK(17, 16) + +#define REG_CSR_2L_CDR1_PR_MONPI 0x01ec +#define CSR_2L_PXP_CDR1_PR_XFICK_EN BIT(8) + +#define REG_CSR_2L_RX1_DAC_RANGE_EYE 0x01f4 +#define CSR_2L_PXP_RX1_SIGDET_LPF_CTRL GENMASK(25, 24) + +#define REG_CSR_2L_RX1_SIGDET_NOVTH 0x01f8 +#define CSR_2L_PXP_RX1_SIGDET_PEAK GENMASK(9, 8) +#define CSR_2L_PXP_RX1_SIGDET_VTH_SEL GENMASK(20, 16) + +#define REG_CSR_2L_RX1_FE_VB_EQ1 0x0200 +#define CSR_2L_PXP_RX1_FE_VB_EQ1_EN BIT(0) +#define CSR_2L_PXP_RX1_FE_VB_EQ2_EN BIT(8) +#define CSR_2L_PXP_RX1_FE_VB_EQ3_EN BIT(16) +#define CSR_2L_PXP_RX1_FE_VCM_GEN_PWDB BIT(24) + +#define REG_CSR_2L_RX1_OSCAL_VGA1IOS 0x0214 +#define CSR_2L_PXP_RX1_PR_OSCAL_VGA1IOS GENMASK(5, 0) +#define CSR_2L_PXP_RX1_PR_OSCAL_VGA1VOS GENMASK(13, 8) +#define CSR_2L_PXP_RX1_PR_OSCAL_VGA2IOS GENMASK(21, 16) + +/* PMA */ +#define REG_PCIE_PMA_SS_LCPLL_PWCTL_SETTING_1 0x0004 +#define PCIE_LCPLL_MAN_PWDB BIT(0) + +#define REG_PCIE_PMA_SEQUENCE_DISB_CTRL1 0x010c +#define PCIE_DISB_RX_SDCAL_EN BIT(0) + +#define REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1 0x0114 +#define PCIE_FORCE_RX_SDCAL_EN BIT(0) + +#define REG_PCIE_PMA_SS_RX_FREQ_DET1 0x014c +#define PCIE_PLL_FT_LOCK_CYCLECNT GENMASK(15, 0) +#define PCIE_PLL_FT_UNLOCK_CYCLECNT GENMASK(31, 16) + +#define REG_PCIE_PMA_SS_RX_FREQ_DET2 0x0150 +#define PCIE_LOCK_TARGET_BEG GENMASK(15, 0) +#define PCIE_LOCK_TARGET_END GENMASK(31, 16) + +#define REG_PCIE_PMA_SS_RX_FREQ_DET3 0x0154 +#define PCIE_UNLOCK_TARGET_BEG GENMASK(15, 0) +#define PCIE_UNLOCK_TARGET_END GENMASK(31, 16) + +#define REG_PCIE_PMA_SS_RX_FREQ_DET4 0x0158 +#define PCIE_FREQLOCK_DET_EN GENMASK(2, 0) +#define PCIE_LOCK_LOCKTH GENMASK(11, 8) +#define PCIE_UNLOCK_LOCKTH GENMASK(15, 12) + +#define REG_PCIE_PMA_SS_RX_CAL1 0x0160 +#define REG_PCIE_PMA_SS_RX_CAL2 0x0164 +#define PCIE_CAL_OUT_OS GENMASK(11, 8) + +#define REG_PCIE_PMA_SS_RX_SIGDET0 0x0168 +#define PCIE_SIGDET_WIN_NONVLD_TIMES GENMASK(28, 24) + +#define REG_PCIE_PMA_TX_RESET 0x0260 +#define PCIE_TX_TOP_RST BIT(0) +#define PCIE_TX_CAL_RST BIT(8) + +#define REG_PCIE_PMA_RX_FORCE_MODE0 0x0294 +#define PCIE_FORCE_DA_XPON_RX_FE_GAIN_CTRL GENMASK(1, 0) + +#define REG_PCIE_PMA_SS_DA_XPON_PWDB0 0x034c +#define PCIE_DA_XPON_CDR_PR_PWDB BIT(8) + +#define REG_PCIE_PMA_SW_RESET 0x0460 +#define PCIE_SW_RX_FIFO_RST BIT(0) +#define PCIE_SW_RX_RST BIT(1) +#define PCIE_SW_TX_RST BIT(2) +#define PCIE_SW_PMA_RST BIT(3) +#define PCIE_SW_ALLPCS_RST BIT(4) +#define PCIE_SW_REF_RST BIT(5) +#define PCIE_SW_TX_FIFO_RST BIT(6) +#define PCIE_SW_XFI_TXPCS_RST BIT(7) +#define PCIE_SW_XFI_RXPCS_RST BIT(8) +#define PCIE_SW_XFI_RXPCS_BIST_RST BIT(9) +#define PCIE_SW_HSG_TXPCS_RST BIT(10) +#define PCIE_SW_HSG_RXPCS_RST BIT(11) +#define PCIE_PMA_SW_RST (PCIE_SW_RX_FIFO_RST | \ + PCIE_SW_RX_RST | \ + PCIE_SW_TX_RST | \ + PCIE_SW_PMA_RST | \ + PCIE_SW_ALLPCS_RST | \ + PCIE_SW_REF_RST | \ + PCIE_SW_TX_FIFO_RST | \ + PCIE_SW_XFI_TXPCS_RST | \ + PCIE_SW_XFI_RXPCS_RST | \ + PCIE_SW_XFI_RXPCS_BIST_RST | \ + PCIE_SW_HSG_TXPCS_RST | \ + PCIE_SW_HSG_RXPCS_RST) + +#define REG_PCIE_PMA_RO_RX_FREQDET 0x0530 +#define PCIE_RO_FBCK_LOCK BIT(0) +#define PCIE_RO_FL_OUT GENMASK(31, 16) + +#define REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC 0x0794 +#define PCIE_FORCE_DA_PXP_CDR_PR_IDAC GENMASK(10, 0) +#define PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC BIT(16) +#define PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW BIT(24) + +#define REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_SDM_PCW 0x0798 +#define PCIE_FORCE_DA_PXP_TXPLL_SDM_PCW GENMASK(30, 0) + +#define REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_VOS 0x079c +#define PCIE_FORCE_SEL_DA_PXP_JCPLL_SDM_PCW BIT(16) + +#define REG_PCIE_PMA_FORCE_DA_PXP_JCPLL_SDM_PCW 0x0800 +#define PCIE_FORCE_DA_PXP_JCPLL_SDM_PCW GENMASK(30, 0) + +#define REG_PCIE_PMA_FORCE_DA_PXP_CDR_PD_PWDB 0x081c +#define PCIE_FORCE_DA_PXP_CDR_PD_PWDB BIT(0) +#define PCIE_FORCE_SEL_DA_PXP_CDR_PD_PWDB BIT(8) + +#define REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C 0x0820 +#define PCIE_FORCE_DA_PXP_CDR_PR_LPF_C_EN BIT(0) +#define PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN BIT(8) +#define PCIE_FORCE_DA_PXP_CDR_PR_LPF_R_EN BIT(16) +#define PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN BIT(24) + +#define REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB 0x0824 +#define PCIE_FORCE_DA_PXP_CDR_PR_PWDB BIT(16) +#define PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB BIT(24) + +#define REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT 0x0828 +#define PCIE_FORCE_DA_PXP_JCPLL_CKOUT_EN BIT(0) +#define PCIE_FORCE_SEL_DA_PXP_JCPLL_CKOUT_EN BIT(8) +#define PCIE_FORCE_DA_PXP_JCPLL_EN BIT(16) +#define PCIE_FORCE_SEL_DA_PXP_JCPLL_EN BIT(24) + +#define REG_PCIE_PMA_FORCE_DA_PXP_RX_SCAN_RST 0x0084c +#define PCIE_FORCE_DA_PXP_RX_SIGDET_PWDB BIT(16) +#define PCIE_FORCE_SEL_DA_PXP_RX_SIGDET_PWDB BIT(24) + +#define REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT 0x0854 +#define PCIE_FORCE_DA_PXP_TXPLL_CKOUT_EN BIT(0) +#define PCIE_FORCE_SEL_DA_PXP_TXPLL_CKOUT_EN BIT(8) +#define PCIE_FORCE_DA_PXP_TXPLL_EN BIT(16) +#define PCIE_FORCE_SEL_DA_PXP_TXPLL_EN BIT(24) + +#define REG_PCIE_PMA_SCAN_MODE 0x0884 +#define PCIE_FORCE_DA_PXP_JCPLL_KBAND_LOAD_EN BIT(0) +#define PCIE_FORCE_SEL_DA_PXP_JCPLL_KBAND_LOAD_EN BIT(8) + +#define REG_PCIE_PMA_DIG_RESERVE_13 0x08bc +#define PCIE_FLL_IDAC_PCIEG1 GENMASK(10, 0) +#define PCIE_FLL_IDAC_PCIEG2 GENMASK(26, 16) + +#define REG_PCIE_PMA_DIG_RESERVE_14 0x08c0 +#define PCIE_FLL_IDAC_PCIEG3 GENMASK(10, 0) +#define PCIE_FLL_LOAD_EN BIT(16) + +#define REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL 0x088c +#define PCIE_FORCE_DA_PXP_RX_FE_GAIN_CTRL GENMASK(1, 0) +#define PCIE_FORCE_SEL_DA_PXP_RX_FE_GAIN_CTRL BIT(8) + +#define REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_PWDB 0x0894 +#define PCIE_FORCE_DA_PXP_RX_FE_PWDB BIT(0) +#define PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB BIT(8) + +#define REG_PCIE_PMA_DIG_RESERVE_12 0x08b8 +#define PCIE_FORCE_PMA_RX_SPEED GENMASK(7, 4) +#define PCIE_FORCE_SEL_PMA_RX_SPEED BIT(7) + +#define REG_PCIE_PMA_DIG_RESERVE_17 0x08e0 + +#define REG_PCIE_PMA_DIG_RESERVE_18 0x08e4 +#define PCIE_PXP_RX_VTH_SEL_PCIE_G1 GENMASK(4, 0) +#define PCIE_PXP_RX_VTH_SEL_PCIE_G2 GENMASK(12, 8) +#define PCIE_PXP_RX_VTH_SEL_PCIE_G3 GENMASK(20, 16) + +#define REG_PCIE_PMA_DIG_RESERVE_19 0x08e8 +#define PCIE_PCP_RX_REV0_PCIE_GEN1 GENMASK(31, 16) + +#define REG_PCIE_PMA_DIG_RESERVE_20 0x08ec +#define PCIE_PCP_RX_REV0_PCIE_GEN2 GENMASK(15, 0) +#define PCIE_PCP_RX_REV0_PCIE_GEN3 GENMASK(31, 16) + +#define REG_PCIE_PMA_DIG_RESERVE_21 0x08f0 +#define REG_PCIE_PMA_DIG_RESERVE_22 0x08f4 +#define REG_PCIE_PMA_DIG_RESERVE_27 0x0908 +#define REG_PCIE_PMA_DIG_RESERVE_30 0x0914 + +/* DTIME */ +#define REG_PCIE_PEXTP_DIG_GLB44 0x00 +#define PCIE_XTP_RXDET_VCM_OFF_STB_T_SEL GENMASK(7, 0) +#define PCIE_XTP_RXDET_EN_STB_T_SEL GENMASK(15, 8) +#define PCIE_XTP_RXDET_FINISH_STB_T_SEL GENMASK(23, 16) +#define PCIE_XTP_TXPD_TX_DATA_EN_DLY GENMASK(27, 24) +#define PCIE_XTP_TXPD_RXDET_DONE_CDT BIT(28) +#define PCIE_XTP_RXDET_LATCH_STB_T_SEL GENMASK(31, 29) + +/* RX AEQ */ +#define REG_PCIE_PEXTP_DIG_LN_RX30_P0 0x0000 +#define PCIE_XTP_LN_RX_PDOWN_L1P2_EXIT_WAIT GENMASK(7, 0) +#define PCIE_XTP_LN_RX_PDOWN_T2RLB_DIG_EN BIT(8) +#define PCIE_XTP_LN_RX_PDOWN_E0_AEQEN_WAIT GENMASK(31, 16) + +#define REG_PCIE_PEXTP_DIG_LN_RX30_P1 0x0100 + +#endif /* _PHY_AIROHA_PCIE_H */ diff --git a/drivers/phy/phy-airoha-pcie.c b/drivers/phy/phy-airoha-pcie.c new file mode 100644 index 000000000000..56e9ade8a9fd --- /dev/null +++ b/drivers/phy/phy-airoha-pcie.c @@ -0,0 +1,1290 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2024 AIROHA Inc + * Author: Lorenzo Bianconi <lorenzo@kernel.org> + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "phy-airoha-pcie-regs.h" + +#define LEQ_LEN_CTRL_MAX_VAL 7 +#define FREQ_LOCK_MAX_ATTEMPT 10 + +/* PCIe-PHY initialization time in ms needed by the hw to complete */ +#define PHY_HW_INIT_TIME_MS 30 + +enum airoha_pcie_port_gen { + PCIE_PORT_GEN1 = 1, + PCIE_PORT_GEN2, + PCIE_PORT_GEN3, +}; + +/** + * struct airoha_pcie_phy - PCIe phy driver main structure + * @dev: pointer to device + * @phy: pointer to generic phy + * @csr_2l: Analogic lane IO mapped register base address + * @pma0: IO mapped register base address of PMA0-PCIe + * @pma1: IO mapped register base address of PMA1-PCIe + * @p0_xr_dtime: IO mapped register base address of port0 Tx-Rx detection time + * @p1_xr_dtime: IO mapped register base address of port1 Tx-Rx detection time + * @rx_aeq: IO mapped register base address of Rx AEQ training + */ +struct airoha_pcie_phy { + struct device *dev; + struct phy *phy; + void __iomem *csr_2l; + void __iomem *pma0; + void __iomem *pma1; + void __iomem *p0_xr_dtime; + void __iomem *p1_xr_dtime; + void __iomem *rx_aeq; +}; + +static void airoha_phy_clear_bits(void __iomem *reg, u32 mask) +{ + u32 val = readl(reg) & ~mask; + + writel(val, reg); +} + +static void airoha_phy_set_bits(void __iomem *reg, u32 mask) +{ + u32 val = readl(reg) | mask; + + writel(val, reg); +} + +static void airoha_phy_update_bits(void __iomem *reg, u32 mask, u32 val) +{ + u32 tmp = readl(reg); + + tmp &= ~mask; + tmp |= val & mask; + writel(tmp, reg); +} + +#define airoha_phy_update_field(reg, mask, val) \ + do { \ + BUILD_BUG_ON_MSG(!__builtin_constant_p((mask)), \ + "mask is not constant"); \ + airoha_phy_update_bits((reg), (mask), \ + FIELD_PREP((mask), (val))); \ + } while (0) + +#define airoha_phy_csr_2l_clear_bits(pcie_phy, reg, mask) \ + airoha_phy_clear_bits((pcie_phy)->csr_2l + (reg), (mask)) +#define airoha_phy_csr_2l_set_bits(pcie_phy, reg, mask) \ + airoha_phy_set_bits((pcie_phy)->csr_2l + (reg), (mask)) +#define airoha_phy_csr_2l_update_field(pcie_phy, reg, mask, val) \ + airoha_phy_update_field((pcie_phy)->csr_2l + (reg), (mask), (val)) +#define airoha_phy_pma0_clear_bits(pcie_phy, reg, mask) \ + airoha_phy_clear_bits((pcie_phy)->pma0 + (reg), (mask)) +#define airoha_phy_pma1_clear_bits(pcie_phy, reg, mask) \ + airoha_phy_clear_bits((pcie_phy)->pma1 + (reg), (mask)) +#define airoha_phy_pma0_set_bits(pcie_phy, reg, mask) \ + airoha_phy_set_bits((pcie_phy)->pma0 + (reg), (mask)) +#define airoha_phy_pma1_set_bits(pcie_phy, reg, mask) \ + airoha_phy_set_bits((pcie_phy)->pma1 + (reg), (mask)) +#define airoha_phy_pma0_update_field(pcie_phy, reg, mask, val) \ + airoha_phy_update_field((pcie_phy)->pma0 + (reg), (mask), (val)) +#define airoha_phy_pma1_update_field(pcie_phy, reg, mask, val) \ + airoha_phy_update_field((pcie_phy)->pma1 + (reg), (mask), (val)) + +static void +airoha_phy_init_lane0_rx_fw_pre_calib(struct airoha_pcie_phy *pcie_phy, + enum airoha_pcie_port_gen gen) +{ + u32 fl_out_target = gen == PCIE_PORT_GEN3 ? 41600 : 41941; + u32 lock_cyclecnt = gen == PCIE_PORT_GEN3 ? 26000 : 32767; + u32 pr_idac, val, cdr_pr_idac_tmp = 0; + int i; + + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_SS_LCPLL_PWCTL_SETTING_1, + PCIE_LCPLL_MAN_PWDB); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET2, + PCIE_LOCK_TARGET_BEG, + fl_out_target - 100); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET2, + PCIE_LOCK_TARGET_END, + fl_out_target + 100); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET1, + PCIE_PLL_FT_LOCK_CYCLECNT, lock_cyclecnt); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_LOCK_LOCKTH, 0x3); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET3, + PCIE_UNLOCK_TARGET_BEG, + fl_out_target - 100); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET3, + PCIE_UNLOCK_TARGET_END, + fl_out_target + 100); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET1, + PCIE_PLL_FT_UNLOCK_CYCLECNT, + lock_cyclecnt); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_UNLOCK_LOCKTH, 0x3); + + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR0_PR_INJ_MODE, + CSR_2L_PXP_CDR0_INJ_FORCE_OFF); + + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN); + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_DA_PXP_CDR_PR_LPF_R_EN); + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_DA_PXP_CDR_PR_LPF_C_EN); + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC); + + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB, + PCIE_FORCE_DA_PXP_CDR_PR_PWDB); + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB, + PCIE_FORCE_DA_PXP_CDR_PR_PWDB); + + for (i = 0; i < LEQ_LEN_CTRL_MAX_VAL; i++) { + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_DA_PXP_CDR_PR_IDAC, i << 8); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN); + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN, 0x3); + + usleep_range(10000, 15000); + + val = FIELD_GET(PCIE_RO_FL_OUT, + readl(pcie_phy->pma0 + + REG_PCIE_PMA_RO_RX_FREQDET)); + if (val > fl_out_target) + cdr_pr_idac_tmp = i << 8; + } + + for (i = LEQ_LEN_CTRL_MAX_VAL; i >= 0; i--) { + pr_idac = cdr_pr_idac_tmp | (0x1 << i); + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_DA_PXP_CDR_PR_IDAC, pr_idac); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN); + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN, 0x3); + + usleep_range(10000, 15000); + + val = FIELD_GET(PCIE_RO_FL_OUT, + readl(pcie_phy->pma0 + + REG_PCIE_PMA_RO_RX_FREQDET)); + if (val < fl_out_target) + pr_idac &= ~(0x1 << i); + + cdr_pr_idac_tmp = pr_idac; + } + + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_DA_PXP_CDR_PR_IDAC, + cdr_pr_idac_tmp); + + for (i = 0; i < FREQ_LOCK_MAX_ATTEMPT; i++) { + u32 val; + + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN); + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN, 0x3); + + usleep_range(10000, 15000); + + val = readl(pcie_phy->pma0 + REG_PCIE_PMA_RO_RX_FREQDET); + if (val & PCIE_RO_FBCK_LOCK) + break; + } + + /* turn off force mode and update band values */ + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR0_PR_INJ_MODE, + CSR_2L_PXP_CDR0_INJ_FORCE_OFF); + + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC); + if (gen == PCIE_PORT_GEN3) { + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_DIG_RESERVE_14, + PCIE_FLL_IDAC_PCIEG3, + cdr_pr_idac_tmp); + } else { + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_DIG_RESERVE_13, + PCIE_FLL_IDAC_PCIEG1, + cdr_pr_idac_tmp); + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_DIG_RESERVE_13, + PCIE_FLL_IDAC_PCIEG2, + cdr_pr_idac_tmp); + } +} + +static void +airoha_phy_init_lane1_rx_fw_pre_calib(struct airoha_pcie_phy *pcie_phy, + enum airoha_pcie_port_gen gen) +{ + u32 fl_out_target = gen == PCIE_PORT_GEN3 ? 41600 : 41941; + u32 lock_cyclecnt = gen == PCIE_PORT_GEN3 ? 26000 : 32767; + u32 pr_idac, val, cdr_pr_idac_tmp = 0; + int i; + + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_SS_LCPLL_PWCTL_SETTING_1, + PCIE_LCPLL_MAN_PWDB); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET2, + PCIE_LOCK_TARGET_BEG, + fl_out_target - 100); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET2, + PCIE_LOCK_TARGET_END, + fl_out_target + 100); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET1, + PCIE_PLL_FT_LOCK_CYCLECNT, lock_cyclecnt); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_LOCK_LOCKTH, 0x3); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET3, + PCIE_UNLOCK_TARGET_BEG, + fl_out_target - 100); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET3, + PCIE_UNLOCK_TARGET_END, + fl_out_target + 100); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET1, + PCIE_PLL_FT_UNLOCK_CYCLECNT, + lock_cyclecnt); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_UNLOCK_LOCKTH, 0x3); + + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR1_PR_INJ_MODE, + CSR_2L_PXP_CDR1_INJ_FORCE_OFF); + + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_DA_PXP_CDR_PR_LPF_R_EN); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_DA_PXP_CDR_PR_LPF_C_EN); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB, + PCIE_FORCE_DA_PXP_CDR_PR_PWDB); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB, + PCIE_FORCE_DA_PXP_CDR_PR_PWDB); + + for (i = 0; i < LEQ_LEN_CTRL_MAX_VAL; i++) { + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_DA_PXP_CDR_PR_IDAC, i << 8); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN); + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN, 0x3); + + usleep_range(10000, 15000); + + val = FIELD_GET(PCIE_RO_FL_OUT, + readl(pcie_phy->pma1 + + REG_PCIE_PMA_RO_RX_FREQDET)); + if (val > fl_out_target) + cdr_pr_idac_tmp = i << 8; + } + + for (i = LEQ_LEN_CTRL_MAX_VAL; i >= 0; i--) { + pr_idac = cdr_pr_idac_tmp | (0x1 << i); + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_DA_PXP_CDR_PR_IDAC, pr_idac); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN); + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN, 0x3); + + usleep_range(10000, 15000); + + val = FIELD_GET(PCIE_RO_FL_OUT, + readl(pcie_phy->pma1 + + REG_PCIE_PMA_RO_RX_FREQDET)); + if (val < fl_out_target) + pr_idac &= ~(0x1 << i); + + cdr_pr_idac_tmp = pr_idac; + } + + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_DA_PXP_CDR_PR_IDAC, + cdr_pr_idac_tmp); + + for (i = 0; i < FREQ_LOCK_MAX_ATTEMPT; i++) { + u32 val; + + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN); + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_SS_RX_FREQ_DET4, + PCIE_FREQLOCK_DET_EN, 0x3); + + usleep_range(10000, 15000); + + val = readl(pcie_phy->pma1 + REG_PCIE_PMA_RO_RX_FREQDET); + if (val & PCIE_RO_FBCK_LOCK) + break; + } + + /* turn off force mode and update band values */ + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR1_PR_INJ_MODE, + CSR_2L_PXP_CDR1_INJ_FORCE_OFF); + + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_R_EN); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_LPF_C, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_LPF_C_EN); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_PIEYE_PWDB, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_PWDB); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_SEL_DA_PXP_CDR_PR_IDAC); + if (gen == PCIE_PORT_GEN3) { + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_DIG_RESERVE_14, + PCIE_FLL_IDAC_PCIEG3, + cdr_pr_idac_tmp); + } else { + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_DIG_RESERVE_13, + PCIE_FLL_IDAC_PCIEG1, + cdr_pr_idac_tmp); + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_DIG_RESERVE_13, + PCIE_FLL_IDAC_PCIEG2, + cdr_pr_idac_tmp); + } +} + +static void airoha_pcie_phy_init_default(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CMN, + CSR_2L_PXP_CMN_TRIM_MASK, 0x10); + writel(0xcccbcccb, pcie_phy->pma0 + REG_PCIE_PMA_DIG_RESERVE_21); + writel(0xcccb, pcie_phy->pma0 + REG_PCIE_PMA_DIG_RESERVE_22); + writel(0xcccbcccb, pcie_phy->pma1 + REG_PCIE_PMA_DIG_RESERVE_21); + writel(0xcccb, pcie_phy->pma1 + REG_PCIE_PMA_DIG_RESERVE_22); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CMN, + CSR_2L_PXP_CMN_LANE_EN); +} + +static void airoha_pcie_phy_init_clk_out(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_TXPLL_POSTDIV_D256, + CSR_2L_PXP_CLKTX0_AMP, 0x5); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_CLKTX0_FORCE_OUT1, + CSR_2L_PXP_CLKTX1_AMP, 0x5); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_TXPLL_POSTDIV_D256, + CSR_2L_PXP_CLKTX0_OFFSET, 0x2); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CLKTX1_OFFSET, + CSR_2L_PXP_CLKTX1_OFFSET, 0x2); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CLKTX0_FORCE_OUT1, + CSR_2L_PXP_CLKTX0_HZ); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CLKTX1_OFFSET, + CSR_2L_PXP_CLKTX1_HZ); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_CLKTX0_FORCE_OUT1, + CSR_2L_PXP_CLKTX0_IMP_SEL, 0x12); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CLKTX1_IMP_SEL, + CSR_2L_PXP_CLKTX1_IMP_SEL, 0x12); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_POSTDIV_D256, + CSR_2L_PXP_CLKTX0_SR); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CLKTX1_OFFSET, + CSR_2L_PXP_CLKTX1_SR); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_PLL_CMN_RESERVE0, + CSR_2L_PXP_PLL_RESERVE_MASK, 0xd0d); +} + +static void airoha_pcie_phy_init_csr_2l(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_SW_RESET, + PCIE_SW_XFI_RXPCS_RST | PCIE_SW_REF_RST | + PCIE_SW_RX_RST); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_SW_RESET, + PCIE_SW_XFI_RXPCS_RST | PCIE_SW_REF_RST | + PCIE_SW_RX_RST); + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_TX_RESET, + PCIE_TX_TOP_RST | PCIE_TX_CAL_RST); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_TX_RESET, + PCIE_TX_TOP_RST | PCIE_TX_CAL_RST); +} + +static void airoha_pcie_phy_init_rx(struct airoha_pcie_phy *pcie_phy) +{ + writel(0x2a00090b, pcie_phy->pma0 + REG_PCIE_PMA_DIG_RESERVE_17); + writel(0x2a00090b, pcie_phy->pma1 + REG_PCIE_PMA_DIG_RESERVE_17); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR0_PR_MONPI, + CSR_2L_PXP_CDR0_PR_XFICK_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR1_PR_MONPI, + CSR_2L_PXP_CDR1_PR_XFICK_EN); + airoha_phy_csr_2l_clear_bits(pcie_phy, + REG_CSR_2L_CDR0_PD_PICAL_CKD8_INV, + CSR_2L_PXP_CDR0_PD_EDGE_DISABLE); + airoha_phy_csr_2l_clear_bits(pcie_phy, + REG_CSR_2L_CDR1_PD_PICAL_CKD8_INV, + CSR_2L_PXP_CDR1_PD_EDGE_DISABLE); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_PHYCK_DIV, + CSR_2L_PXP_RX0_PHYCK_SEL, 0x1); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_PHYCK_DIV, + CSR_2L_PXP_RX1_PHYCK_SEL, 0x1); +} + +static void airoha_pcie_phy_init_jcpll(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_JCPLL_EN); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_DA_PXP_JCPLL_EN); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_JCPLL_EN); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_DA_PXP_JCPLL_EN); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_TCL_VTP_EN, + CSR_2L_PXP_JCPLL_SPARE_LOW, 0x20); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY, + CSR_2L_PXP_JCPLL_RST); + writel(0x0, pcie_phy->csr_2l + REG_CSR_2L_JCPLL_SSC_DELTA1); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC_PERIOD, + CSR_2L_PXP_JCPLL_SSC_PERIOD); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC, + CSR_2L_PXP_JCPLL_SSC_PHASE_INI); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC, + CSR_2L_PXP_JCPLL_SSC_TRI_EN); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BR, + CSR_2L_PXP_JCPLL_LPF_BR, 0xa); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BR, + CSR_2L_PXP_JCPLL_LPF_BP, 0xc); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BR, + CSR_2L_PXP_JCPLL_LPF_BC, 0x1f); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BWC, + CSR_2L_PXP_JCPLL_LPF_BWC, 0x1e); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BR, + CSR_2L_PXP_JCPLL_LPF_BWR, 0xa); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_JCPLL_MMD_PREDIV_MODE, + CSR_2L_PXP_JCPLL_MMD_PREDIV_MODE, + 0x1); + airoha_phy_csr_2l_clear_bits(pcie_phy, CSR_2L_PXP_JCPLL_MONCK, + CSR_2L_PXP_JCPLL_REFIN_DIV); + + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_VOS, + PCIE_FORCE_SEL_DA_PXP_JCPLL_SDM_PCW); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_VOS, + PCIE_FORCE_SEL_DA_PXP_JCPLL_SDM_PCW); + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_JCPLL_SDM_PCW, + PCIE_FORCE_DA_PXP_JCPLL_SDM_PCW, + 0x50000000); + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_JCPLL_SDM_PCW, + PCIE_FORCE_DA_PXP_JCPLL_SDM_PCW, + 0x50000000); + + airoha_phy_csr_2l_set_bits(pcie_phy, + REG_CSR_2L_JCPLL_MMD_PREDIV_MODE, + CSR_2L_PXP_JCPLL_POSTDIV_D5); + airoha_phy_csr_2l_set_bits(pcie_phy, + REG_CSR_2L_JCPLL_MMD_PREDIV_MODE, + CSR_2L_PXP_JCPLL_POSTDIV_D2); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY, + CSR_2L_PXP_JCPLL_RST_DLY, 0x4); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY, + CSR_2L_PXP_JCPLL_SDM_DI_LS); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_TCL_KBAND_VREF, + CSR_2L_PXP_JCPLL_VCO_KBAND_MEAS_EN); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_IB_EXT, + CSR_2L_PXP_JCPLL_CHP_IOFST); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_IB_EXT, + CSR_2L_PXP_JCPLL_CHP_IBIAS, 0xc); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_JCPLL_MMD_PREDIV_MODE, + CSR_2L_PXP_JCPLL_MMD_PREDIV_MODE, + 0x1); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_VCODIV, + CSR_2L_PXP_JCPLL_VCO_HALFLSB_EN); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_VCODIV, + CSR_2L_PXP_JCPLL_VCO_CFIX, 0x1); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_VCODIV, + CSR_2L_PXP_JCPLL_VCO_SCAPWR, 0x4); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_IB_EXT, + REG_CSR_2L_JCPLL_LPF_SHCK_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_KBAND_KFC, + CSR_2L_PXP_JCPLL_POSTDIV_EN); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_KBAND_KFC, + CSR_2L_PXP_JCPLL_KBAND_KFC); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_KBAND_KFC, + CSR_2L_PXP_JCPLL_KBAND_KF, 0x3); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_KBAND_KFC, + CSR_2L_PXP_JCPLL_KBAND_KS); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BWC, + CSR_2L_PXP_JCPLL_KBAND_DIV, 0x1); + + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_SCAN_MODE, + PCIE_FORCE_SEL_DA_PXP_JCPLL_KBAND_LOAD_EN); + airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_SCAN_MODE, + PCIE_FORCE_DA_PXP_JCPLL_KBAND_LOAD_EN); + + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_LPF_BWC, + CSR_2L_PXP_JCPLL_KBAND_CODE, 0xe4); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN, + CSR_2L_PXP_JCPLL_TCL_AMP_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_TCL_CMP, + CSR_2L_PXP_JCPLL_TCL_LPF_EN); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_JCPLL_TCL_KBAND_VREF, + CSR_2L_PXP_JCPLL_TCL_KBAND_VREF, 0xf); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN, + CSR_2L_PXP_JCPLL_TCL_AMP_GAIN, 0x1); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN, + CSR_2L_PXP_JCPLL_TCL_AMP_VREF, 0x5); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_TCL_CMP, + CSR_2L_PXP_JCPLL_TCL_LPF_BW, 0x1); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_VCO_TCLVAR, + CSR_2L_PXP_JCPLL_VCO_TCLVAR, 0x3); + + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_JCPLL_CKOUT_EN); + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_DA_PXP_JCPLL_CKOUT_EN); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_JCPLL_CKOUT_EN); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_DA_PXP_JCPLL_CKOUT_EN); + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_JCPLL_EN); + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_DA_PXP_JCPLL_EN); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_JCPLL_EN); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_PXP_JCPLL_CKOUT, + PCIE_FORCE_DA_PXP_JCPLL_EN); +} + +static void airoha_pcie_phy_txpll(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_TXPLL_EN); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_DA_PXP_TXPLL_EN); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_TXPLL_EN); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_DA_PXP_TXPLL_EN); + + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_REFIN_DIV, + CSR_2L_PXP_TXPLL_PLL_RSTB); + writel(0x0, pcie_phy->csr_2l + REG_CSR_2L_TXPLL_SSC_DELTA1); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SSC_PERIOD, + CSR_2L_PXP_txpll_SSC_PERIOD); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST, + CSR_2L_PXP_TXPLL_CHP_IOFST, 0x1); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_750M_SYS_CK, + CSR_2L_PXP_TXPLL_CHP_IBIAS, 0x2d); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_REFIN_DIV, + CSR_2L_PXP_TXPLL_REFIN_DIV); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_TCL_LPF_BW, + CSR_2L_PXP_TXPLL_VCO_CFIX, 0x3); + + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW); + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_SDM_PCW, + PCIE_FORCE_DA_PXP_TXPLL_SDM_PCW, + 0xc800000); + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_SDM_PCW, + PCIE_FORCE_DA_PXP_TXPLL_SDM_PCW, + 0xc800000); + + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SDM_DI_LS, + CSR_2L_PXP_TXPLL_SDM_IFM); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SSC, + CSR_2L_PXP_TXPLL_SSC_PHASE_INI); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_REFIN_DIV, + CSR_2L_PXP_TXPLL_RST_DLY, 0x4); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SDM_DI_LS, + CSR_2L_PXP_TXPLL_SDM_DI_LS); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_SDM_DI_LS, + CSR_2L_PXP_TXPLL_SDM_ORD, 0x3); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_TCL_KBAND_VREF, + CSR_2L_PXP_TXPLL_VCO_KBAND_MEAS_EN); + writel(0x0, pcie_phy->csr_2l + REG_CSR_2L_TXPLL_SSC_DELTA1); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST, + CSR_2L_PXP_TXPLL_LPF_BP, 0x1); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST, + CSR_2L_PXP_TXPLL_LPF_BC, 0x18); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST, + CSR_2L_PXP_TXPLL_LPF_BR, 0x5); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_CHP_IOFST, + CSR_2L_PXP_TXPLL_CHP_IOFST, 0x1); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_750M_SYS_CK, + CSR_2L_PXP_TXPLL_CHP_IBIAS, 0x2d); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_TCL_VTP, + CSR_2L_PXP_TXPLL_SPARE_L, 0x1); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_LPF_BWR, + CSR_2L_PXP_TXPLL_LPF_BWC); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_POSTDIV, + CSR_2L_PXP_TXPLL_MMD_PREDIV_MODE); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_REFIN_DIV, + CSR_2L_PXP_TXPLL_REFIN_DIV); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_TCL_LPF_BW, + CSR_2L_PXP_TXPLL_VCO_HALFLSB_EN); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_VCO_SCAPWR, + CSR_2L_PXP_TXPLL_VCO_SCAPWR, 0x7); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_TCL_LPF_BW, + CSR_2L_PXP_TXPLL_VCO_CFIX, 0x3); + + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PR_IDAC, + PCIE_FORCE_SEL_DA_PXP_TXPLL_SDM_PCW); + + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SSC, + CSR_2L_PXP_TXPLL_SSC_PHASE_INI); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_LPF_BWR, + CSR_2L_PXP_TXPLL_LPF_BWR); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_PHY_CK2, + CSR_2L_PXP_TXPLL_REFIN_INTERNAL); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_TCL_KBAND_VREF, + CSR_2L_PXP_TXPLL_VCO_KBAND_MEAS_EN); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_VTP, + CSR_2L_PXP_TXPLL_VTP_EN); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_POSTDIV, + CSR_2L_PXP_TXPLL_PHY_CK1_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_PHY_CK2, + CSR_2L_PXP_TXPLL_REFIN_INTERNAL); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_SSC, + CSR_2L_PXP_TXPLL_SSC_EN); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_750M_SYS_CK, + CSR_2L_PXP_TXPLL_LPF_SHCK_EN); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_POSTDIV, + CSR_2L_PXP_TXPLL_POSTDIV_EN); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TXPLL_KBAND_DIV, + CSR_2L_PXP_TXPLL_KBAND_KFC); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_KBAND_DIV, + CSR_2L_PXP_TXPLL_KBAND_KF, 0x3); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_KBAND_DIV, + CSR_2L_PXP_txpll_KBAND_KS, 0x1); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_KBAND_DIV, + CSR_2L_PXP_TXPLL_KBAND_DIV, 0x4); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_LPF_BWR, + CSR_2L_PXP_TXPLL_KBAND_CODE, 0xe4); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_SDM_OUT, + CSR_2L_PXP_TXPLL_TCL_AMP_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TXPLL_TCL_AMP_VREF, + CSR_2L_PXP_TXPLL_TCL_LPF_EN); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_TXPLL_TCL_KBAND_VREF, + CSR_2L_PXP_TXPLL_TCL_KBAND_VREF, 0xf); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_SDM_OUT, + CSR_2L_PXP_TXPLL_TCL_AMP_GAIN, 0x3); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_TXPLL_TCL_AMP_VREF, + CSR_2L_PXP_TXPLL_TCL_AMP_VREF, 0xb); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_TXPLL_TCL_LPF_BW, + CSR_2L_PXP_TXPLL_TCL_LPF_BW, 0x3); + + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_TXPLL_CKOUT_EN); + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_DA_PXP_TXPLL_CKOUT_EN); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_TXPLL_CKOUT_EN); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_DA_PXP_TXPLL_CKOUT_EN); + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_TXPLL_EN); + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_DA_PXP_TXPLL_EN); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_SEL_DA_PXP_TXPLL_EN); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_TXPLL_CKOUT, + PCIE_FORCE_DA_PXP_TXPLL_EN); +} + +static void airoha_pcie_phy_init_ssc_jcpll(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SSC_DELTA1, + CSR_2L_PXP_JCPLL_SSC_DELTA1, 0x106); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SSC_DELTA1, + CSR_2L_PXP_JCPLL_SSC_DELTA, 0x106); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_JCPLL_SSC_PERIOD, + CSR_2L_PXP_JCPLL_SSC_PERIOD, 0x31b); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC, + CSR_2L_PXP_JCPLL_SSC_PHASE_INI); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC, + CSR_2L_PXP_JCPLL_SSC_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_IFM, + CSR_2L_PXP_JCPLL_SDM_IFM); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SDM_HREN, + CSR_2L_PXP_JCPLL_SDM_HREN); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_RST_DLY, + CSR_2L_PXP_JCPLL_SDM_DI_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC, + CSR_2L_PXP_JCPLL_SSC_TRI_EN); +} + +static void +airoha_pcie_phy_set_rxlan0_signal_detect(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR0_PR_COR_HBW, + CSR_2L_PXP_CDR0_PR_LDO_FORCE_ON); + + usleep_range(100, 200); + + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_19, + PCIE_PCP_RX_REV0_PCIE_GEN1, 0x18b0); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_20, + PCIE_PCP_RX_REV0_PCIE_GEN2, 0x18b0); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_20, + PCIE_PCP_RX_REV0_PCIE_GEN3, 0x1030); + + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_SIGDET_DCTEST, + CSR_2L_PXP_RX0_SIGDET_PEAK, 0x2); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_SIGDET_VTH_SEL, + CSR_2L_PXP_RX0_SIGDET_VTH_SEL, 0x5); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_REV0, + CSR_2L_PXP_VOS_PNINV, 0x2); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_SIGDET_DCTEST, + CSR_2L_PXP_RX0_SIGDET_LPF_CTRL, 0x1); + + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_CAL2, + PCIE_CAL_OUT_OS, 0x0); + + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_PXP_RX0_FE_VB_EQ2, + CSR_2L_PXP_RX0_FE_VCM_GEN_PWDB); + + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL, + PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB); + airoha_phy_pma0_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL, + PCIE_FORCE_DA_PXP_RX_FE_GAIN_CTRL, 0x3); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_RX_FORCE_MODE0, + PCIE_FORCE_DA_XPON_RX_FE_GAIN_CTRL, 0x1); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_SIGDET0, + PCIE_SIGDET_WIN_NONVLD_TIMES, 0x3); + airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_SEQUENCE_DISB_CTRL1, + PCIE_DISB_RX_SDCAL_EN); + + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1, + PCIE_FORCE_RX_SDCAL_EN); + usleep_range(150, 200); + airoha_phy_pma0_clear_bits(pcie_phy, + REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1, + PCIE_FORCE_RX_SDCAL_EN); +} + +static void +airoha_pcie_phy_set_rxlan1_signal_detect(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_CDR1_PR_COR_HBW, + CSR_2L_PXP_CDR1_PR_LDO_FORCE_ON); + + usleep_range(100, 200); + + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_19, + PCIE_PCP_RX_REV0_PCIE_GEN1, 0x18b0); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_20, + PCIE_PCP_RX_REV0_PCIE_GEN2, 0x18b0); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_20, + PCIE_PCP_RX_REV0_PCIE_GEN3, 0x1030); + + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_SIGDET_NOVTH, + CSR_2L_PXP_RX1_SIGDET_PEAK, 0x2); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_SIGDET_NOVTH, + CSR_2L_PXP_RX1_SIGDET_VTH_SEL, 0x5); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_REV0, + CSR_2L_PXP_VOS_PNINV, 0x2); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_DAC_RANGE_EYE, + CSR_2L_PXP_RX1_SIGDET_LPF_CTRL, 0x1); + + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_CAL2, + PCIE_CAL_OUT_OS, 0x0); + + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX1_FE_VB_EQ1, + CSR_2L_PXP_RX1_FE_VCM_GEN_PWDB); + + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL, + PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB); + airoha_phy_pma1_update_field(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_GAIN_CTRL, + PCIE_FORCE_DA_PXP_RX_FE_GAIN_CTRL, 0x3); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_RX_FORCE_MODE0, + PCIE_FORCE_DA_XPON_RX_FE_GAIN_CTRL, 0x1); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_SS_RX_SIGDET0, + PCIE_SIGDET_WIN_NONVLD_TIMES, 0x3); + airoha_phy_pma1_clear_bits(pcie_phy, REG_PCIE_PMA_SEQUENCE_DISB_CTRL1, + PCIE_DISB_RX_SDCAL_EN); + + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1, + PCIE_FORCE_RX_SDCAL_EN); + usleep_range(150, 200); + airoha_phy_pma1_clear_bits(pcie_phy, + REG_PCIE_PMA_CTRL_SEQUENCE_FORCE_CTRL1, + PCIE_FORCE_RX_SDCAL_EN); +} + +static void airoha_pcie_phy_set_rxflow(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_RX_SCAN_RST, + PCIE_FORCE_DA_PXP_RX_SIGDET_PWDB | + PCIE_FORCE_SEL_DA_PXP_RX_SIGDET_PWDB); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_RX_SCAN_RST, + PCIE_FORCE_DA_PXP_RX_SIGDET_PWDB | + PCIE_FORCE_SEL_DA_PXP_RX_SIGDET_PWDB); + + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PD_PWDB, + PCIE_FORCE_DA_PXP_CDR_PD_PWDB | + PCIE_FORCE_SEL_DA_PXP_CDR_PD_PWDB); + airoha_phy_pma0_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_PWDB, + PCIE_FORCE_DA_PXP_RX_FE_PWDB | + PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_CDR_PD_PWDB, + PCIE_FORCE_DA_PXP_CDR_PD_PWDB | + PCIE_FORCE_SEL_DA_PXP_CDR_PD_PWDB); + airoha_phy_pma1_set_bits(pcie_phy, + REG_PCIE_PMA_FORCE_DA_PXP_RX_FE_PWDB, + PCIE_FORCE_DA_PXP_RX_FE_PWDB | + PCIE_FORCE_SEL_DA_PXP_RX_FE_PWDB); + + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX0_PHYCK_DIV, + CSR_2L_PXP_RX0_PHYCK_RSTB | + CSR_2L_PXP_RX0_TDC_CK_SEL); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX1_PHYCK_DIV, + CSR_2L_PXP_RX1_PHYCK_RSTB | + CSR_2L_PXP_RX1_TDC_CK_SEL); + + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_SW_RESET, + PCIE_SW_RX_FIFO_RST | PCIE_SW_TX_RST | + PCIE_SW_PMA_RST | PCIE_SW_ALLPCS_RST | + PCIE_SW_TX_FIFO_RST); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_SW_RESET, + PCIE_SW_RX_FIFO_RST | PCIE_SW_TX_RST | + PCIE_SW_PMA_RST | PCIE_SW_ALLPCS_RST | + PCIE_SW_TX_FIFO_RST); + + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_PXP_RX0_FE_VB_EQ2, + CSR_2L_PXP_RX0_FE_VB_EQ2_EN | + CSR_2L_PXP_RX0_FE_VB_EQ3_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX0_SIGDET_VTH_SEL, + CSR_2L_PXP_RX0_FE_VB_EQ1_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_RX1_FE_VB_EQ1, + CSR_2L_PXP_RX1_FE_VB_EQ1_EN | + CSR_2L_PXP_RX1_FE_VB_EQ2_EN | + CSR_2L_PXP_RX1_FE_VB_EQ3_EN); + + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_REV0, + CSR_2L_PXP_FE_GAIN_NORMAL_MODE, 0x4); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX0_REV0, + CSR_2L_PXP_FE_GAIN_TRAIN_MODE, 0x4); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_REV0, + CSR_2L_PXP_FE_GAIN_NORMAL_MODE, 0x4); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_REV0, + CSR_2L_PXP_FE_GAIN_TRAIN_MODE, 0x4); +} + +static void airoha_pcie_phy_set_pr(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_VREG_IBAND, + CSR_2L_PXP_CDR0_PR_VREG_IBAND, 0x5); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_VREG_IBAND, + CSR_2L_PXP_CDR0_PR_VREG_CKBUF, 0x5); + + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR0_PR_CKREF_DIV, + CSR_2L_PXP_CDR0_PR_CKREF_DIV); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR0_PR_COR_HBW, + CSR_2L_PXP_CDR0_PR_CKREF_DIV1); + + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_CDR1_PR_VREG_IBAND_VAL, + CSR_2L_PXP_CDR1_PR_VREG_IBAND, 0x5); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_CDR1_PR_VREG_IBAND_VAL, + CSR_2L_PXP_CDR1_PR_VREG_CKBUF, 0x5); + + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR1_PR_CKREF_DIV, + CSR_2L_PXP_CDR1_PR_CKREF_DIV); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR1_PR_COR_HBW, + CSR_2L_PXP_CDR1_PR_CKREF_DIV1); + + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_LPF_RATIO, + CSR_2L_PXP_CDR0_LPF_TOP_LIM, 0x20000); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR1_LPF_RATIO, + CSR_2L_PXP_CDR1_LPF_TOP_LIM, 0x20000); + + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_BETA_DAC, + CSR_2L_PXP_CDR0_PR_BETA_SEL, 0x2); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR1_PR_BETA_DAC, + CSR_2L_PXP_CDR1_PR_BETA_SEL, 0x2); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_BETA_DAC, + CSR_2L_PXP_CDR0_PR_KBAND_DIV, 0x4); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR1_PR_BETA_DAC, + CSR_2L_PXP_CDR1_PR_KBAND_DIV, 0x4); +} + +static void airoha_pcie_phy_set_txflow(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TX0_CKLDO, + CSR_2L_PXP_TX0_CKLDO_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TX1_CKLDO, + CSR_2L_PXP_TX1_CKLDO_EN); + + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TX0_CKLDO, + CSR_2L_PXP_TX0_DMEDGEGEN_EN); + airoha_phy_csr_2l_set_bits(pcie_phy, REG_CSR_2L_TX1_CKLDO, + CSR_2L_PXP_TX1_DMEDGEGEN_EN); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_TX1_MULTLANE, + CSR_2L_PXP_TX1_MULTLANE_EN); +} + +static void airoha_pcie_phy_set_rx_mode(struct airoha_pcie_phy *pcie_phy) +{ + writel(0x804000, pcie_phy->pma0 + REG_PCIE_PMA_DIG_RESERVE_27); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18, + PCIE_PXP_RX_VTH_SEL_PCIE_G1, 0x5); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18, + PCIE_PXP_RX_VTH_SEL_PCIE_G2, 0x5); + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18, + PCIE_PXP_RX_VTH_SEL_PCIE_G3, 0x5); + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_30, + 0x77700); + + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR0_PR_MONCK, + CSR_2L_PXP_CDR0_PR_MONCK_ENABLE); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR0_PR_MONCK, + CSR_2L_PXP_CDR0_PR_RESERVE0, 0x2); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_PXP_RX0_OSCAL_CTLE1IOS, + CSR_2L_PXP_RX0_PR_OSCAL_VGA1IOS, 0x19); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_PXP_RX0_OSCA_VGA1VOS, + CSR_2L_PXP_RX0_PR_OSCAL_VGA1VOS, 0x19); + airoha_phy_csr_2l_update_field(pcie_phy, + REG_CSR_2L_PXP_RX0_OSCA_VGA1VOS, + CSR_2L_PXP_RX0_PR_OSCAL_VGA2IOS, 0x14); + + writel(0x804000, pcie_phy->pma1 + REG_PCIE_PMA_DIG_RESERVE_27); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18, + PCIE_PXP_RX_VTH_SEL_PCIE_G1, 0x5); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18, + PCIE_PXP_RX_VTH_SEL_PCIE_G2, 0x5); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_18, + PCIE_PXP_RX_VTH_SEL_PCIE_G3, 0x5); + + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_30, + 0x77700); + + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_CDR1_PR_MONCK, + CSR_2L_PXP_CDR1_PR_MONCK_ENABLE); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_CDR1_PR_MONCK, + CSR_2L_PXP_CDR1_PR_RESERVE0, 0x2); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_OSCAL_VGA1IOS, + CSR_2L_PXP_RX1_PR_OSCAL_VGA1IOS, 0x19); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_OSCAL_VGA1IOS, + CSR_2L_PXP_RX1_PR_OSCAL_VGA1VOS, 0x19); + airoha_phy_csr_2l_update_field(pcie_phy, REG_CSR_2L_RX1_OSCAL_VGA1IOS, + CSR_2L_PXP_RX1_PR_OSCAL_VGA2IOS, 0x14); +} + +static void airoha_pcie_phy_load_kflow(struct airoha_pcie_phy *pcie_phy) +{ + airoha_phy_pma0_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_12, + PCIE_FORCE_PMA_RX_SPEED, 0xa); + airoha_phy_pma1_update_field(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_12, + PCIE_FORCE_PMA_RX_SPEED, 0xa); + airoha_phy_init_lane0_rx_fw_pre_calib(pcie_phy, PCIE_PORT_GEN3); + airoha_phy_init_lane1_rx_fw_pre_calib(pcie_phy, PCIE_PORT_GEN3); + + airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_12, + PCIE_FORCE_PMA_RX_SPEED); + airoha_phy_pma1_clear_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_12, + PCIE_FORCE_PMA_RX_SPEED); + usleep_range(100, 200); + + airoha_phy_init_lane0_rx_fw_pre_calib(pcie_phy, PCIE_PORT_GEN2); + airoha_phy_init_lane1_rx_fw_pre_calib(pcie_phy, PCIE_PORT_GEN2); +} + +/** + * airoha_pcie_phy_init() - Initialize the phy + * @phy: the phy to be initialized + * + * Initialize the phy registers. + * The hardware settings will be reset during suspend, it should be + * reinitialized when the consumer calls phy_init() again on resume. + */ +static int airoha_pcie_phy_init(struct phy *phy) +{ + struct airoha_pcie_phy *pcie_phy = phy_get_drvdata(phy); + u32 val; + + /* Setup Tx-Rx detection time */ + val = FIELD_PREP(PCIE_XTP_RXDET_VCM_OFF_STB_T_SEL, 0x33) | + FIELD_PREP(PCIE_XTP_RXDET_EN_STB_T_SEL, 0x1) | + FIELD_PREP(PCIE_XTP_RXDET_FINISH_STB_T_SEL, 0x2) | + FIELD_PREP(PCIE_XTP_TXPD_TX_DATA_EN_DLY, 0x3) | + FIELD_PREP(PCIE_XTP_RXDET_LATCH_STB_T_SEL, 0x1); + writel(val, pcie_phy->p0_xr_dtime + REG_PCIE_PEXTP_DIG_GLB44); + writel(val, pcie_phy->p1_xr_dtime + REG_PCIE_PEXTP_DIG_GLB44); + /* Setup Rx AEQ training time */ + val = FIELD_PREP(PCIE_XTP_LN_RX_PDOWN_L1P2_EXIT_WAIT, 0x32) | + FIELD_PREP(PCIE_XTP_LN_RX_PDOWN_E0_AEQEN_WAIT, 0x5050); + writel(val, pcie_phy->rx_aeq + REG_PCIE_PEXTP_DIG_LN_RX30_P0); + writel(val, pcie_phy->rx_aeq + REG_PCIE_PEXTP_DIG_LN_RX30_P1); + + /* enable load FLL-K flow */ + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_14, + PCIE_FLL_LOAD_EN); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_DIG_RESERVE_14, + PCIE_FLL_LOAD_EN); + + airoha_pcie_phy_init_default(pcie_phy); + airoha_pcie_phy_init_clk_out(pcie_phy); + airoha_pcie_phy_init_csr_2l(pcie_phy); + + usleep_range(100, 200); + + airoha_pcie_phy_init_rx(pcie_phy); + /* phase 1, no ssc for K TXPLL */ + airoha_pcie_phy_init_jcpll(pcie_phy); + + usleep_range(500, 600); + + /* TX PLL settings */ + airoha_pcie_phy_txpll(pcie_phy); + + usleep_range(200, 300); + + /* SSC JCPLL setting */ + airoha_pcie_phy_init_ssc_jcpll(pcie_phy); + + usleep_range(100, 200); + + /* Rx lan0 signal detect */ + airoha_pcie_phy_set_rxlan0_signal_detect(pcie_phy); + /* Rx lan1 signal detect */ + airoha_pcie_phy_set_rxlan1_signal_detect(pcie_phy); + /* RX FLOW */ + airoha_pcie_phy_set_rxflow(pcie_phy); + + usleep_range(100, 200); + + airoha_pcie_phy_set_pr(pcie_phy); + /* TX FLOW */ + airoha_pcie_phy_set_txflow(pcie_phy); + + usleep_range(100, 200); + /* RX mode setting */ + airoha_pcie_phy_set_rx_mode(pcie_phy); + /* Load K-Flow */ + airoha_pcie_phy_load_kflow(pcie_phy); + airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_SS_DA_XPON_PWDB0, + PCIE_DA_XPON_CDR_PR_PWDB); + airoha_phy_pma1_clear_bits(pcie_phy, REG_PCIE_PMA_SS_DA_XPON_PWDB0, + PCIE_DA_XPON_CDR_PR_PWDB); + + usleep_range(100, 200); + + airoha_phy_pma0_set_bits(pcie_phy, REG_PCIE_PMA_SS_DA_XPON_PWDB0, + PCIE_DA_XPON_CDR_PR_PWDB); + airoha_phy_pma1_set_bits(pcie_phy, REG_PCIE_PMA_SS_DA_XPON_PWDB0, + PCIE_DA_XPON_CDR_PR_PWDB); + + /* Wait for the PCIe PHY to complete initialization before returning */ + msleep(PHY_HW_INIT_TIME_MS); + + return 0; +} + +static int airoha_pcie_phy_exit(struct phy *phy) +{ + struct airoha_pcie_phy *pcie_phy = phy_get_drvdata(phy); + + airoha_phy_pma0_clear_bits(pcie_phy, REG_PCIE_PMA_SW_RESET, + PCIE_PMA_SW_RST); + airoha_phy_pma1_clear_bits(pcie_phy, REG_PCIE_PMA_SW_RESET, + PCIE_PMA_SW_RST); + airoha_phy_csr_2l_clear_bits(pcie_phy, REG_CSR_2L_JCPLL_SSC, + CSR_2L_PXP_JCPLL_SSC_PHASE_INI | + CSR_2L_PXP_JCPLL_SSC_TRI_EN | + CSR_2L_PXP_JCPLL_SSC_EN); + + return 0; +} + +static const struct phy_ops airoha_pcie_phy_ops = { + .init = airoha_pcie_phy_init, + .exit = airoha_pcie_phy_exit, + .owner = THIS_MODULE, +}; + +static int airoha_pcie_phy_probe(struct platform_device *pdev) +{ + struct airoha_pcie_phy *pcie_phy; + struct device *dev = &pdev->dev; + struct phy_provider *provider; + + pcie_phy = devm_kzalloc(dev, sizeof(*pcie_phy), GFP_KERNEL); + if (!pcie_phy) + return -ENOMEM; + + pcie_phy->csr_2l = devm_platform_ioremap_resource_byname(pdev, "csr-2l"); + if (IS_ERR(pcie_phy->csr_2l)) + return dev_err_probe(dev, PTR_ERR(pcie_phy->csr_2l), + "Failed to map phy-csr-2l base\n"); + + pcie_phy->pma0 = devm_platform_ioremap_resource_byname(pdev, "pma0"); + if (IS_ERR(pcie_phy->pma0)) + return dev_err_probe(dev, PTR_ERR(pcie_phy->pma0), + "Failed to map phy-pma0 base\n"); + + pcie_phy->pma1 = devm_platform_ioremap_resource_byname(pdev, "pma1"); + if (IS_ERR(pcie_phy->pma1)) + return dev_err_probe(dev, PTR_ERR(pcie_phy->pma1), + "Failed to map phy-pma1 base\n"); + + pcie_phy->phy = devm_phy_create(dev, dev->of_node, &airoha_pcie_phy_ops); + if (IS_ERR(pcie_phy->phy)) + return dev_err_probe(dev, PTR_ERR(pcie_phy->phy), + "Failed to create PCIe phy\n"); + + pcie_phy->p0_xr_dtime = + devm_platform_ioremap_resource_byname(pdev, "p0-xr-dtime"); + if (IS_ERR(pcie_phy->p0_xr_dtime)) + return dev_err_probe(dev, PTR_ERR(pcie_phy->p0_xr_dtime), + "Failed to map P0 Tx-Rx dtime base\n"); + + pcie_phy->p1_xr_dtime = + devm_platform_ioremap_resource_byname(pdev, "p1-xr-dtime"); + if (IS_ERR(pcie_phy->p1_xr_dtime)) + return dev_err_probe(dev, PTR_ERR(pcie_phy->p1_xr_dtime), + "Failed to map P1 Tx-Rx dtime base\n"); + + pcie_phy->rx_aeq = devm_platform_ioremap_resource_byname(pdev, "rx-aeq"); + if (IS_ERR(pcie_phy->rx_aeq)) + return dev_err_probe(dev, PTR_ERR(pcie_phy->rx_aeq), + "Failed to map Rx AEQ base\n"); + + pcie_phy->dev = dev; + phy_set_drvdata(pcie_phy->phy, pcie_phy); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) + return dev_err_probe(dev, PTR_ERR(provider), + "PCIe phy probe failed\n"); + + return 0; +} + +static const struct of_device_id airoha_pcie_phy_of_match[] = { + { .compatible = "airoha,en7581-pcie-phy" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, airoha_pcie_phy_of_match); + +static struct platform_driver airoha_pcie_phy_driver = { + .probe = airoha_pcie_phy_probe, + .driver = { + .name = "airoha-pcie-phy", + .of_match_table = airoha_pcie_phy_of_match, + }, +}; +module_platform_driver(airoha_pcie_phy_driver); + +MODULE_DESCRIPTION("Airoha PCIe PHY driver"); +MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>"); +MODULE_LICENSE("GPL"); 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 d9be6a4d5383..8e2daea81666 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -20,7 +20,12 @@ #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> -static struct class *phy_class; +static void phy_release(struct device *dev); +static const struct class phy_class = { + .name = "phy", + .dev_release = phy_release, +}; + static struct dentry *phy_debugfs_root; static DEFINE_MUTEX(phy_provider_mutex); static LIST_HEAD(phy_provider_list); @@ -140,8 +145,10 @@ static struct phy_provider *of_phy_provider_lookup(struct device_node *node) return phy_provider; for_each_child_of_node(phy_provider->children, child) - if (child == node) + if (child == node) { + of_node_put(child); return phy_provider; + } } return ERR_PTR(-EPROBE_DEFER); @@ -207,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() @@ -398,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); @@ -490,6 +474,53 @@ int phy_calibrate(struct phy *phy) EXPORT_SYMBOL_GPL(phy_calibrate); /** + * phy_notify_connect() - phy connect notification + * @phy: the phy returned by phy_get() + * @port: the port index for connect + * + * If the phy needs to get connection status, the callback can be used. + * Returns: %0 if successful, a negative error code otherwise + */ +int phy_notify_connect(struct phy *phy, int port) +{ + int ret; + + if (!phy || !phy->ops->connect) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->connect(phy, port); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_notify_connect); + +/** + * phy_notify_disconnect() - phy disconnect notification + * @phy: the phy returned by phy_get() + * @port: the port index for disconnect + * + * If the phy needs to get connection status, the callback can be used. + * + * Returns: %0 if successful, a negative error code otherwise + */ +int phy_notify_disconnect(struct phy *phy, int port) +{ + int ret; + + if (!phy || !phy->ops->disconnect) + return 0; + + mutex_lock(&phy->mutex); + ret = phy->ops->disconnect(phy, port); + mutex_unlock(&phy->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(phy_notify_disconnect); + +/** * phy_configure() - Changes the phy parameters * @phy: the phy returned by phy_get() * @opts: New configuration to apply @@ -577,8 +608,10 @@ static struct phy *_of_phy_get(struct device_node *np, int index) return ERR_PTR(-ENODEV); /* This phy type handled by the usb-phy subsystem for now */ - if (of_device_is_compatible(args.np, "usb-nop-xceiv")) - return ERR_PTR(-ENODEV); + if (of_device_is_compatible(args.np, "usb-nop-xceiv")) { + phy = ERR_PTR(-ENODEV); + goto out_put_node; + } mutex_lock(&phy_provider_mutex); phy_provider = of_phy_provider_lookup(args.np); @@ -600,6 +633,7 @@ out_put_module: out_unlock: mutex_unlock(&phy_provider_mutex); +out_put_node: of_node_put(args.np); return phy; @@ -612,7 +646,7 @@ out_unlock: * * Returns the phy driver, after getting a refcount to it; or * -ENODEV if there is no such phy. The caller is responsible for - * calling phy_put() to release that count. + * calling of_phy_put() to release that count. */ struct phy *of_phy_get(struct device_node *np, const char *con_id) { @@ -685,39 +719,32 @@ void devm_phy_put(struct device *dev, struct phy *phy) if (!phy) return; - r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy); + r = devres_release(dev, devm_phy_release, devm_phy_match, phy); dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n"); } 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 * should provide a custom of_xlate function that reads the *args* and returns * the appropriate phy. */ -struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args - *args) +struct phy *of_phy_simple_xlate(struct device *dev, + const struct of_phandle_args *args) { - struct phy *phy; - struct class_dev_iter iter; + struct device *target_dev; - 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; - - 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); @@ -969,7 +996,7 @@ struct phy *phy_create(struct device *dev, struct device_node *node, device_initialize(&phy->dev); mutex_init(&phy->mutex); - phy->dev.class = phy_class; + phy->dev.class = &phy_class; phy->dev.parent = dev; phy->dev.of_node = node ?: dev->of_node; phy->id = id; @@ -1069,7 +1096,7 @@ void devm_phy_destroy(struct device *dev, struct phy *phy) { int r; - r = devres_destroy(dev, devm_phy_consume, devm_phy_match, phy); + r = devres_release(dev, devm_phy_consume, devm_phy_match, phy); dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n"); } EXPORT_SYMBOL_GPL(devm_phy_destroy); @@ -1095,7 +1122,7 @@ EXPORT_SYMBOL_GPL(devm_phy_destroy); struct phy_provider *__of_phy_provider_register(struct device *dev, struct device_node *children, struct module *owner, struct phy * (*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { struct phy_provider *phy_provider; @@ -1158,7 +1185,7 @@ EXPORT_SYMBOL_GPL(__of_phy_provider_register); struct phy_provider *__devm_of_phy_provider_register(struct device *dev, struct device_node *children, struct module *owner, struct phy * (*of_xlate)(struct device *dev, - struct of_phandle_args *args)) + const struct of_phandle_args *args)) { struct phy_provider **ptr, *phy_provider; @@ -1207,12 +1234,12 @@ EXPORT_SYMBOL_GPL(of_phy_provider_unregister); * of_phy_provider_unregister to unregister the phy provider. */ void devm_of_phy_provider_unregister(struct device *dev, - struct phy_provider *phy_provider) + struct phy_provider *phy_provider) { int r; - r = devres_destroy(dev, devm_phy_provider_release, devm_phy_match, - phy_provider); + r = devres_release(dev, devm_phy_provider_release, devm_phy_match, + phy_provider); dev_WARN_ONCE(dev, r, "couldn't find PHY provider device resource\n"); } EXPORT_SYMBOL_GPL(devm_of_phy_provider_unregister); @@ -1238,14 +1265,13 @@ static void phy_release(struct device *dev) static int __init phy_core_init(void) { - phy_class = class_create("phy"); - if (IS_ERR(phy_class)) { - pr_err("failed to create phy class --> %ld\n", - PTR_ERR(phy_class)); - return PTR_ERR(phy_class); - } + int err; - phy_class->dev_release = phy_release; + err = class_register(&phy_class); + if (err) { + pr_err("failed to register phy class"); + return err; + } phy_debugfs_root = debugfs_create_dir("phy", NULL); @@ -1256,6 +1282,6 @@ device_initcall(phy_core_init); static void __exit phy_core_exit(void) { debugfs_remove_recursive(phy_debugfs_root); - class_destroy(phy_class); + class_unregister(&phy_class); } module_exit(phy_core_exit); diff --git a/drivers/phy/phy-lgm-usb.c b/drivers/phy/phy-lgm-usb.c index 410729c7f513..eb7c6fed20d3 100644 --- a/drivers/phy/phy-lgm-usb.c +++ b/drivers/phy/phy-lgm-usb.c @@ -271,7 +271,7 @@ static struct platform_driver lgm_phy_driver = { .of_match_table = intel_usb_phy_dt_ids, }, .probe = phy_probe, - .remove_new = phy_remove, + .remove = phy_remove, }; module_platform_driver(lgm_phy_driver); diff --git a/drivers/phy/phy-nxp-ptn3222.c b/drivers/phy/phy-nxp-ptn3222.c new file mode 100644 index 000000000000..c6179d8701e6 --- /dev/null +++ b/drivers/phy/phy-nxp-ptn3222.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Linaro Limited + */ + +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/phy/phy.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#define NUM_SUPPLIES 2 + +struct ptn3222 { + struct i2c_client *client; + struct phy *phy; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data *supplies; +}; + +static int ptn3222_init(struct phy *phy) +{ + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); + int ret; + + ret = regulator_bulk_enable(NUM_SUPPLIES, ptn3222->supplies); + if (ret) + return ret; + + gpiod_set_value_cansleep(ptn3222->reset_gpio, 0); + + return 0; +} + +static int ptn3222_exit(struct phy *phy) +{ + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); + + gpiod_set_value_cansleep(ptn3222->reset_gpio, 1); + + return regulator_bulk_disable(NUM_SUPPLIES, ptn3222->supplies); +} + +static const struct phy_ops ptn3222_ops = { + .init = ptn3222_init, + .exit = ptn3222_exit, + .owner = THIS_MODULE, +}; + +static const struct regulator_bulk_data ptn3222_supplies[NUM_SUPPLIES] = { + { + .supply = "vdd3v3", + .init_load_uA = 11000, + }, { + .supply = "vdd1v8", + .init_load_uA = 55000, + } +}; + +static int ptn3222_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct phy_provider *phy_provider; + struct ptn3222 *ptn3222; + int ret; + + ptn3222 = devm_kzalloc(dev, sizeof(*ptn3222), GFP_KERNEL); + if (!ptn3222) + return -ENOMEM; + + ptn3222->client = client; + + ptn3222->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ptn3222->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ptn3222->reset_gpio), + "unable to acquire reset gpio\n"); + + ret = devm_regulator_bulk_get_const(dev, NUM_SUPPLIES, ptn3222_supplies, + &ptn3222->supplies); + if (ret) + return ret; + + ptn3222->phy = devm_phy_create(dev, dev->of_node, &ptn3222_ops); + if (IS_ERR(ptn3222->phy)) { + dev_err(dev, "failed to create PHY: %d\n", ret); + return PTR_ERR(ptn3222->phy); + } + + phy_set_drvdata(ptn3222->phy, ptn3222); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct i2c_device_id ptn3222_table[] = { + { "ptn3222" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ptn3222_table); + +static const struct of_device_id ptn3222_of_table[] = { + { .compatible = "nxp,ptn3222" }, + { } +}; +MODULE_DEVICE_TABLE(of, ptn3222_of_table); + +static struct i2c_driver ptn3222_driver = { + .driver = { + .name = "ptn3222", + .of_match_table = ptn3222_of_table, + }, + .probe = ptn3222_probe, + .id_table = ptn3222_table, +}; + +module_i2c_driver(ptn3222_driver); + +MODULE_DESCRIPTION("NXP PTN3222 eUSB2 Redriver driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/phy-snps-eusb2.c b/drivers/phy/phy-snps-eusb2.c new file mode 100644 index 000000000000..b73a1d7e57b3 --- /dev/null +++ b/drivers/phy/phy-snps-eusb2.c @@ -0,0 +1,627 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023, Linaro Limited + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/iopoll.h> +#include <linux/mod_devicetable.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> + +#define EXYNOS_USB_PHY_HS_PHY_CTRL_RST (0x0) +#define USB_PHY_RST_MASK GENMASK(1, 0) +#define UTMI_PORT_RST_MASK GENMASK(5, 4) + +#define EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON (0x4) +#define RPTR_MODE BIT(10) +#define FSEL_20_MHZ_VAL (0x1) +#define FSEL_24_MHZ_VAL (0x2) +#define FSEL_26_MHZ_VAL (0x3) +#define FSEL_48_MHZ_VAL (0x2) + +#define EXYNOS_USB_PHY_CFG_PLLCFG0 (0x8) +#define PHY_CFG_PLL_FB_DIV_19_8_MASK GENMASK(19, 8) +#define DIV_19_8_19_2_MHZ_VAL (0x170) +#define DIV_19_8_20_MHZ_VAL (0x160) +#define DIV_19_8_24_MHZ_VAL (0x120) +#define DIV_19_8_26_MHZ_VAL (0x107) +#define DIV_19_8_48_MHZ_VAL (0x120) + +#define EXYNOS_USB_PHY_CFG_PLLCFG1 (0xc) +#define EXYNOS_PHY_CFG_PLL_FB_DIV_11_8_MASK GENMASK(11, 8) +#define EXYNOS_DIV_11_8_19_2_MHZ_VAL (0x0) +#define EXYNOS_DIV_11_8_20_MHZ_VAL (0x0) +#define EXYNOS_DIV_11_8_24_MHZ_VAL (0x0) +#define EXYNOS_DIV_11_8_26_MHZ_VAL (0x0) +#define EXYNOS_DIV_11_8_48_MHZ_VAL (0x1) + +#define EXYNOS_PHY_CFG_TX (0x14) +#define EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK GENMASK(2, 1) + +#define EXYNOS_USB_PHY_UTMI_TESTSE (0x20) +#define TEST_IDDQ BIT(6) + +#define QCOM_USB_PHY_UTMI_CTRL0 (0x3c) +#define SLEEPM BIT(0) +#define OPMODE_MASK GENMASK(4, 3) +#define OPMODE_NONDRIVING BIT(3) + +#define QCOM_USB_PHY_UTMI_CTRL5 (0x50) +#define POR BIT(1) + +#define QCOM_USB_PHY_HS_PHY_CTRL_COMMON0 (0x54) +#define PHY_ENABLE BIT(0) +#define SIDDQ_SEL BIT(1) +#define SIDDQ BIT(2) +#define RETENABLEN BIT(3) +#define FSEL_MASK GENMASK(6, 4) +#define FSEL_19_2_MHZ_VAL (0x0) +#define FSEL_38_4_MHZ_VAL (0x4) + +#define QCOM_USB_PHY_CFG_CTRL_1 (0x58) +#define PHY_CFG_PLL_CPBIAS_CNTRL_MASK GENMASK(7, 1) + +#define QCOM_USB_PHY_CFG_CTRL_2 (0x5c) +#define PHY_CFG_PLL_FB_DIV_7_0_MASK GENMASK(7, 0) +#define DIV_7_0_19_2_MHZ_VAL (0x90) +#define DIV_7_0_38_4_MHZ_VAL (0xc8) + +#define QCOM_USB_PHY_CFG_CTRL_3 (0x60) +#define PHY_CFG_PLL_FB_DIV_11_8_MASK GENMASK(3, 0) +#define DIV_11_8_19_2_MHZ_VAL (0x1) +#define DIV_11_8_38_4_MHZ_VAL (0x0) + +#define PHY_CFG_PLL_REF_DIV GENMASK(7, 4) +#define PLL_REF_DIV_VAL (0x0) + +#define QCOM_USB_PHY_HS_PHY_CTRL2 (0x64) +#define VBUSVLDEXT0 BIT(0) +#define USB2_SUSPEND_N BIT(2) +#define USB2_SUSPEND_N_SEL BIT(3) +#define VBUS_DET_EXT_SEL BIT(4) + +#define QCOM_USB_PHY_CFG_CTRL_4 (0x68) +#define PHY_CFG_PLL_GMP_CNTRL_MASK GENMASK(1, 0) +#define PHY_CFG_PLL_INT_CNTRL_MASK GENMASK(7, 2) + +#define QCOM_USB_PHY_CFG_CTRL_5 (0x6c) +#define PHY_CFG_PLL_PROP_CNTRL_MASK GENMASK(4, 0) +#define PHY_CFG_PLL_VREF_TUNE_MASK GENMASK(7, 6) + +#define QCOM_USB_PHY_CFG_CTRL_6 (0x70) +#define PHY_CFG_PLL_VCO_CNTRL_MASK GENMASK(2, 0) + +#define QCOM_USB_PHY_CFG_CTRL_7 (0x74) + +#define QCOM_USB_PHY_CFG_CTRL_8 (0x78) +#define PHY_CFG_TX_FSLS_VREF_TUNE_MASK GENMASK(1, 0) +#define PHY_CFG_TX_FSLS_VREG_BYPASS BIT(2) +#define PHY_CFG_TX_HS_VREF_TUNE_MASK GENMASK(5, 3) +#define PHY_CFG_TX_HS_XV_TUNE_MASK GENMASK(7, 6) + +#define QCOM_USB_PHY_CFG_CTRL_9 (0x7c) +#define PHY_CFG_TX_PREEMP_TUNE_MASK GENMASK(2, 0) +#define PHY_CFG_TX_RES_TUNE_MASK GENMASK(4, 3) +#define PHY_CFG_TX_RISE_TUNE_MASK GENMASK(6, 5) +#define PHY_CFG_RCAL_BYPASS BIT(7) + +#define QCOM_USB_PHY_CFG_CTRL_10 (0x80) + +#define QCOM_USB_PHY_CFG0 (0x94) +#define DATAPATH_CTRL_OVERRIDE_EN BIT(0) +#define CMN_CTRL_OVERRIDE_EN BIT(1) + +#define QCOM_UTMI_PHY_CMN_CTRL0 (0x98) +#define TESTBURNIN BIT(6) + +#define QCOM_USB_PHY_FSEL_SEL (0xb8) +#define FSEL_SEL BIT(0) + +#define QCOM_USB_PHY_APB_ACCESS_CMD (0x130) +#define RW_ACCESS BIT(0) +#define APB_START_CMD BIT(1) +#define APB_LOGIC_RESET BIT(2) + +#define QCOM_USB_PHY_APB_ACCESS_STATUS (0x134) +#define ACCESS_DONE BIT(0) +#define TIMED_OUT BIT(1) +#define ACCESS_ERROR BIT(2) +#define ACCESS_IN_PROGRESS BIT(3) + +#define QCOM_USB_PHY_APB_ADDRESS (0x138) +#define APB_REG_ADDR_MASK GENMASK(7, 0) + +#define QCOM_USB_PHY_APB_WRDATA_LSB (0x13c) +#define APB_REG_WRDATA_7_0_MASK GENMASK(3, 0) + +#define QCOM_USB_PHY_APB_WRDATA_MSB (0x140) +#define APB_REG_WRDATA_15_8_MASK GENMASK(7, 4) + +#define QCOM_USB_PHY_APB_RDDATA_LSB (0x144) +#define APB_REG_RDDATA_7_0_MASK GENMASK(3, 0) + +#define QCOM_USB_PHY_APB_RDDATA_MSB (0x148) +#define APB_REG_RDDATA_15_8_MASK GENMASK(7, 4) + +static const char * const eusb2_hsphy_vreg_names[] = { + "vdd", "vdda12", +}; + +#define EUSB2_NUM_VREGS ARRAY_SIZE(eusb2_hsphy_vreg_names) + +struct snps_eusb2_phy_drvdata { + int (*phy_init)(struct phy *p); + const char * const *clk_names; + int num_clks; +}; + +struct snps_eusb2_hsphy { + struct phy *phy; + void __iomem *base; + + struct clk *ref_clk; + struct clk_bulk_data *clks; + struct reset_control *phy_reset; + + struct regulator_bulk_data vregs[EUSB2_NUM_VREGS]; + + enum phy_mode mode; + + struct phy *repeater; + + const struct snps_eusb2_phy_drvdata *data; +}; + +static int snps_eusb2_hsphy_set_mode(struct phy *p, enum phy_mode mode, int submode) +{ + struct snps_eusb2_hsphy *phy = phy_get_drvdata(p); + + phy->mode = mode; + + return phy_set_mode_ext(phy->repeater, mode, submode); +} + +static void snps_eusb2_hsphy_write_mask(void __iomem *base, u32 offset, + u32 mask, u32 val) +{ + u32 reg; + + reg = readl_relaxed(base + offset); + reg &= ~mask; + reg |= val & mask; + writel_relaxed(reg, base + offset); + + /* Ensure above write is completed */ + readl_relaxed(base + offset); +} + +static void qcom_eusb2_default_parameters(struct snps_eusb2_hsphy *phy) +{ + /* default parameters: tx pre-emphasis */ + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_9, + PHY_CFG_TX_PREEMP_TUNE_MASK, + FIELD_PREP(PHY_CFG_TX_PREEMP_TUNE_MASK, 0)); + + /* tx rise/fall time */ + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_9, + PHY_CFG_TX_RISE_TUNE_MASK, + FIELD_PREP(PHY_CFG_TX_RISE_TUNE_MASK, 0x2)); + + /* source impedance adjustment */ + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_9, + PHY_CFG_TX_RES_TUNE_MASK, + FIELD_PREP(PHY_CFG_TX_RES_TUNE_MASK, 0x1)); + + /* dc voltage level adjustement */ + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_8, + PHY_CFG_TX_HS_VREF_TUNE_MASK, + FIELD_PREP(PHY_CFG_TX_HS_VREF_TUNE_MASK, 0x3)); + + /* transmitter HS crossover adjustement */ + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_8, + PHY_CFG_TX_HS_XV_TUNE_MASK, + FIELD_PREP(PHY_CFG_TX_HS_XV_TUNE_MASK, 0x0)); +} + +struct snps_eusb2_ref_clk { + unsigned long freq; + u32 fsel_val; + u32 div_7_0_val; + u32 div_11_8_val; +}; + +static const struct snps_eusb2_ref_clk exynos_eusb2_ref_clk[] = { + { 19200000, FSEL_19_2_MHZ_VAL, DIV_19_8_19_2_MHZ_VAL, EXYNOS_DIV_11_8_19_2_MHZ_VAL }, + { 20000000, FSEL_20_MHZ_VAL, DIV_19_8_20_MHZ_VAL, EXYNOS_DIV_11_8_20_MHZ_VAL }, + { 24000000, FSEL_24_MHZ_VAL, DIV_19_8_24_MHZ_VAL, EXYNOS_DIV_11_8_24_MHZ_VAL }, + { 26000000, FSEL_26_MHZ_VAL, DIV_19_8_26_MHZ_VAL, EXYNOS_DIV_11_8_26_MHZ_VAL }, + { 48000000, FSEL_48_MHZ_VAL, DIV_19_8_48_MHZ_VAL, EXYNOS_DIV_11_8_48_MHZ_VAL }, +}; + +static int exynos_eusb2_ref_clk_init(struct snps_eusb2_hsphy *phy) +{ + const struct snps_eusb2_ref_clk *config = NULL; + unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk); + + for (int i = 0; i < ARRAY_SIZE(exynos_eusb2_ref_clk); i++) { + if (exynos_eusb2_ref_clk[i].freq == ref_clk_freq) { + config = &exynos_eusb2_ref_clk[i]; + break; + } + } + + if (!config) { + dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq); + return -EINVAL; + } + + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON, + FSEL_MASK, + FIELD_PREP(FSEL_MASK, config->fsel_val)); + + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_CFG_PLLCFG0, + PHY_CFG_PLL_FB_DIV_19_8_MASK, + FIELD_PREP(PHY_CFG_PLL_FB_DIV_19_8_MASK, + config->div_7_0_val)); + + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_CFG_PLLCFG1, + EXYNOS_PHY_CFG_PLL_FB_DIV_11_8_MASK, + config->div_11_8_val); + return 0; +} + +static const struct snps_eusb2_ref_clk qcom_eusb2_ref_clk[] = { + { 19200000, FSEL_19_2_MHZ_VAL, DIV_7_0_19_2_MHZ_VAL, DIV_11_8_19_2_MHZ_VAL }, + { 38400000, FSEL_38_4_MHZ_VAL, DIV_7_0_38_4_MHZ_VAL, DIV_11_8_38_4_MHZ_VAL }, +}; + +static int qcom_eusb2_ref_clk_init(struct snps_eusb2_hsphy *phy) +{ + const struct snps_eusb2_ref_clk *config = NULL; + unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk); + + for (int i = 0; i < ARRAY_SIZE(qcom_eusb2_ref_clk); i++) { + if (qcom_eusb2_ref_clk[i].freq == ref_clk_freq) { + config = &qcom_eusb2_ref_clk[i]; + break; + } + } + + if (!config) { + dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq); + return -EINVAL; + } + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0, + FSEL_MASK, + FIELD_PREP(FSEL_MASK, config->fsel_val)); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_2, + PHY_CFG_PLL_FB_DIV_7_0_MASK, + config->div_7_0_val); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_3, + PHY_CFG_PLL_FB_DIV_11_8_MASK, + config->div_11_8_val); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_3, + PHY_CFG_PLL_REF_DIV, PLL_REF_DIV_VAL); + + return 0; +} + +static int exynos_snps_eusb2_hsphy_init(struct phy *p) +{ + struct snps_eusb2_hsphy *phy = phy_get_drvdata(p); + int ret; + + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST, + USB_PHY_RST_MASK | UTMI_PORT_RST_MASK, + USB_PHY_RST_MASK | UTMI_PORT_RST_MASK); + fsleep(50); /* required after holding phy in reset */ + + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON, + RPTR_MODE, RPTR_MODE); + + /* update ref_clk related registers */ + ret = exynos_eusb2_ref_clk_init(phy); + if (ret) + return ret; + + /* default parameter: tx fsls-vref */ + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_PHY_CFG_TX, + EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK, + FIELD_PREP(EXYNOS_PHY_CFG_TX_FSLS_VREF_TUNE_MASK, 0x0)); + + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_UTMI_TESTSE, + TEST_IDDQ, 0); + fsleep(10); /* required after releasing test_iddq */ + + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST, + USB_PHY_RST_MASK, 0); + + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_COMMON, + PHY_ENABLE, PHY_ENABLE); + + snps_eusb2_hsphy_write_mask(phy->base, EXYNOS_USB_PHY_HS_PHY_CTRL_RST, + UTMI_PORT_RST_MASK, 0); + + return 0; +} + +static const char * const exynos_eusb2_hsphy_clock_names[] = { + "ref", "bus", "ctrl", +}; + +static const struct snps_eusb2_phy_drvdata exynos2200_snps_eusb2_phy = { + .phy_init = exynos_snps_eusb2_hsphy_init, + .clk_names = exynos_eusb2_hsphy_clock_names, + .num_clks = ARRAY_SIZE(exynos_eusb2_hsphy_clock_names), +}; + +static int qcom_snps_eusb2_hsphy_init(struct phy *p) +{ + struct snps_eusb2_hsphy *phy = phy_get_drvdata(p); + int ret; + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG0, + CMN_CTRL_OVERRIDE_EN, CMN_CTRL_OVERRIDE_EN); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_UTMI_CTRL5, POR, POR); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0, + PHY_ENABLE | RETENABLEN, PHY_ENABLE | RETENABLEN); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_APB_ACCESS_CMD, + APB_LOGIC_RESET, APB_LOGIC_RESET); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_UTMI_PHY_CMN_CTRL0, TESTBURNIN, 0); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_FSEL_SEL, + FSEL_SEL, FSEL_SEL); + + /* update ref_clk related registers */ + ret = qcom_eusb2_ref_clk_init(phy); + if (ret) + return ret; + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_1, + PHY_CFG_PLL_CPBIAS_CNTRL_MASK, + FIELD_PREP(PHY_CFG_PLL_CPBIAS_CNTRL_MASK, 0x1)); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_4, + PHY_CFG_PLL_INT_CNTRL_MASK, + FIELD_PREP(PHY_CFG_PLL_INT_CNTRL_MASK, 0x8)); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_4, + PHY_CFG_PLL_GMP_CNTRL_MASK, + FIELD_PREP(PHY_CFG_PLL_GMP_CNTRL_MASK, 0x1)); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_5, + PHY_CFG_PLL_PROP_CNTRL_MASK, + FIELD_PREP(PHY_CFG_PLL_PROP_CNTRL_MASK, 0x10)); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_6, + PHY_CFG_PLL_VCO_CNTRL_MASK, + FIELD_PREP(PHY_CFG_PLL_VCO_CNTRL_MASK, 0x0)); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_CFG_CTRL_5, + PHY_CFG_PLL_VREF_TUNE_MASK, + FIELD_PREP(PHY_CFG_PLL_VREF_TUNE_MASK, 0x1)); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL2, + VBUS_DET_EXT_SEL, VBUS_DET_EXT_SEL); + + /* set default parameters */ + qcom_eusb2_default_parameters(phy); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL2, + USB2_SUSPEND_N_SEL | USB2_SUSPEND_N, + USB2_SUSPEND_N_SEL | USB2_SUSPEND_N); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_UTMI_CTRL0, SLEEPM, SLEEPM); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0, + SIDDQ_SEL, SIDDQ_SEL); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL_COMMON0, + SIDDQ, 0); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_UTMI_CTRL5, POR, 0); + + snps_eusb2_hsphy_write_mask(phy->base, QCOM_USB_PHY_HS_PHY_CTRL2, + USB2_SUSPEND_N_SEL, 0); + + return 0; +} + +static const char * const qcom_eusb2_hsphy_clock_names[] = { + "ref", +}; + +static const struct snps_eusb2_phy_drvdata sm8550_snps_eusb2_phy = { + .phy_init = qcom_snps_eusb2_hsphy_init, + .clk_names = qcom_eusb2_hsphy_clock_names, + .num_clks = ARRAY_SIZE(qcom_eusb2_hsphy_clock_names), +}; + +static int snps_eusb2_hsphy_init(struct phy *p) +{ + struct snps_eusb2_hsphy *phy = phy_get_drvdata(p); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(phy->vregs), phy->vregs); + if (ret) + return ret; + + ret = phy_init(phy->repeater); + if (ret) { + dev_err(&p->dev, "repeater init failed. %d\n", ret); + goto disable_vreg; + } + + ret = clk_bulk_prepare_enable(phy->data->num_clks, phy->clks); + if (ret) { + dev_err(&p->dev, "failed to enable ref clock, %d\n", ret); + goto disable_vreg; + } + + ret = reset_control_assert(phy->phy_reset); + if (ret) { + dev_err(&p->dev, "failed to assert phy_reset, %d\n", ret); + goto disable_ref_clk; + } + + usleep_range(100, 150); + + ret = reset_control_deassert(phy->phy_reset); + if (ret) { + dev_err(&p->dev, "failed to de-assert phy_reset, %d\n", ret); + goto disable_ref_clk; + } + + ret = phy->data->phy_init(p); + if (ret) + goto disable_ref_clk; + + return 0; + +disable_ref_clk: + clk_bulk_disable_unprepare(phy->data->num_clks, phy->clks); + +disable_vreg: + regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs); + + return ret; +} + +static int snps_eusb2_hsphy_exit(struct phy *p) +{ + struct snps_eusb2_hsphy *phy = phy_get_drvdata(p); + + clk_disable_unprepare(phy->ref_clk); + + regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs); + + phy_exit(phy->repeater); + + return 0; +} + +static const struct phy_ops snps_eusb2_hsphy_ops = { + .init = snps_eusb2_hsphy_init, + .exit = snps_eusb2_hsphy_exit, + .set_mode = snps_eusb2_hsphy_set_mode, + .owner = THIS_MODULE, +}; + +static int snps_eusb2_hsphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct snps_eusb2_hsphy *phy; + struct phy_provider *phy_provider; + struct phy *generic_phy; + int ret, i; + int num; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + phy->data = device_get_match_data(dev); + if (!phy->data) + return -EINVAL; + + phy->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->base)) + return PTR_ERR(phy->base); + + phy->phy_reset = devm_reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(phy->phy_reset)) + return PTR_ERR(phy->phy_reset); + + phy->clks = devm_kcalloc(dev, phy->data->num_clks, sizeof(*phy->clks), + GFP_KERNEL); + if (!phy->clks) + return -ENOMEM; + + for (int i = 0; i < phy->data->num_clks; ++i) + phy->clks[i].id = phy->data->clk_names[i]; + + ret = devm_clk_bulk_get(dev, phy->data->num_clks, phy->clks); + if (ret) + return dev_err_probe(dev, ret, + "failed to get phy clock(s)\n"); + + phy->ref_clk = NULL; + for (int i = 0; i < phy->data->num_clks; ++i) { + if (!strcmp(phy->clks[i].id, "ref")) { + phy->ref_clk = phy->clks[i].clk; + break; + } + } + + if (IS_ERR_OR_NULL(phy->ref_clk)) + return dev_err_probe(dev, PTR_ERR(phy->ref_clk), + "failed to get ref clk\n"); + + num = ARRAY_SIZE(phy->vregs); + for (i = 0; i < num; i++) + phy->vregs[i].supply = eusb2_hsphy_vreg_names[i]; + + ret = devm_regulator_bulk_get(dev, num, phy->vregs); + if (ret) + return dev_err_probe(dev, ret, + "failed to get regulator supplies\n"); + + phy->repeater = devm_of_phy_optional_get(dev, np, 0); + if (IS_ERR(phy->repeater)) + return dev_err_probe(dev, PTR_ERR(phy->repeater), + "failed to get repeater\n"); + + generic_phy = devm_phy_create(dev, NULL, &snps_eusb2_hsphy_ops); + if (IS_ERR(generic_phy)) { + dev_err(dev, "failed to create phy %d\n", ret); + return PTR_ERR(generic_phy); + } + + dev_set_drvdata(dev, phy); + phy_set_drvdata(generic_phy, phy); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + dev_info(dev, "Registered Snps-eUSB2 phy\n"); + + return 0; +} + +static const struct of_device_id snps_eusb2_hsphy_of_match_table[] = { + { + .compatible = "qcom,sm8550-snps-eusb2-phy", + .data = &sm8550_snps_eusb2_phy, + }, { + .compatible = "samsung,exynos2200-eusb2-phy", + .data = &exynos2200_snps_eusb2_phy, + }, { }, +}; +MODULE_DEVICE_TABLE(of, snps_eusb2_hsphy_of_match_table); + +static struct platform_driver snps_eusb2_hsphy_driver = { + .probe = snps_eusb2_hsphy_probe, + .driver = { + .name = "snps-eusb2-hsphy", + .of_match_table = snps_eusb2_hsphy_of_match_table, + }, +}; + +module_platform_driver(snps_eusb2_hsphy_driver); +MODULE_DESCRIPTION("Synopsys eUSB2 HS PHY driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/phy-xgene.c b/drivers/phy/phy-xgene.c index 1f0f908323f0..5007dc7a357c 100644 --- a/drivers/phy/phy-xgene.c +++ b/drivers/phy/phy-xgene.c @@ -1611,7 +1611,7 @@ static const struct phy_ops xgene_phy_ops = { }; static struct phy *xgene_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct xgene_phy_ctx *ctx = dev_get_drvdata(dev); diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig index 846f8c99547f..ef14f4e33973 100644 --- a/drivers/phy/qualcomm/Kconfig +++ b/drivers/phy/qualcomm/Kconfig @@ -125,15 +125,6 @@ config PHY_QCOM_QUSB2 PHY which is usually paired with either the ChipIdea or Synopsys DWC3 USB IPs on MSM SOCs. -config PHY_QCOM_SNPS_EUSB2 - tristate "Qualcomm SNPS eUSB2 PHY Driver" - depends on OF && (ARCH_QCOM || COMPILE_TEST) - select GENERIC_PHY - help - Enable support for the USB high-speed SNPS eUSB2 phy on Qualcomm - chipsets. The PHY is paired with a Synopsys DWC3 USB controller - on Qualcomm SOCs. - config PHY_QCOM_EUSB2_REPEATER tristate "Qualcomm SNPS eUSB2 Repeater Driver" depends on OF && (ARCH_QCOM || COMPILE_TEST) @@ -154,6 +145,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 ffd609ac6233..3851e28a212d 100644 --- a/drivers/phy/qualcomm/Makefile +++ b/drivers/phy/qualcomm/Makefile @@ -7,7 +7,7 @@ obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o obj-$(CONFIG_PHY_QCOM_M31_USB) += phy-qcom-m31.o obj-$(CONFIG_PHY_QCOM_PCIE2) += phy-qcom-pcie2.o -obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o +obj-$(CONFIG_PHY_QCOM_QMP_COMBO) += phy-qcom-qmp-combo.o phy-qcom-qmp-usbc.o obj-$(CONFIG_PHY_QCOM_QMP_PCIE) += phy-qcom-qmp-pcie.o obj-$(CONFIG_PHY_QCOM_QMP_PCIE_8996) += phy-qcom-qmp-pcie-msm8996.o obj-$(CONFIG_PHY_QCOM_QMP_UFS) += phy-qcom-qmp-ufs.o @@ -15,8 +15,8 @@ obj-$(CONFIG_PHY_QCOM_QMP_USB) += phy-qcom-qmp-usb.o 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-apq8064-sata.c b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c index 3642a5d4f2f3..cae290a6e19f 100644 --- a/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c +++ b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c @@ -257,12 +257,12 @@ static const struct of_device_id qcom_apq8064_sata_phy_of_match[] = { MODULE_DEVICE_TABLE(of, qcom_apq8064_sata_phy_of_match); static struct platform_driver qcom_apq8064_sata_phy_driver = { - .probe = qcom_apq8064_sata_phy_probe, - .remove_new = qcom_apq8064_sata_phy_remove, + .probe = qcom_apq8064_sata_phy_probe, + .remove = qcom_apq8064_sata_phy_remove, .driver = { - .name = "qcom-apq8064-sata-phy", - .of_match_table = qcom_apq8064_sata_phy_of_match, - } + .name = "qcom-apq8064-sata-phy", + .of_match_table = qcom_apq8064_sata_phy_of_match, + }, }; module_platform_driver(qcom_apq8064_sata_phy_driver); diff --git a/drivers/phy/qualcomm/phy-qcom-edp.c b/drivers/phy/qualcomm/phy-qcom-edp.c index 8e5078304646..f1b51018683d 100644 --- a/drivers/phy/qualcomm/phy-qcom-edp.c +++ b/drivers/phy/qualcomm/phy-qcom-edp.c @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/phy/phy.h> +#include <linux/phy/phy-dp.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/reset.h> @@ -21,7 +22,9 @@ #include <dt-bindings/phy/phy.h> -#include "phy-qcom-qmp.h" +#include "phy-qcom-qmp-dp-phy.h" +#include "phy-qcom-qmp-qserdes-com-v4.h" +#include "phy-qcom-qmp-qserdes-com-v6.h" /* EDP_PHY registers */ #define DP_PHY_CFG 0x0010 @@ -29,16 +32,8 @@ #define DP_PHY_PD_CTL 0x001c #define DP_PHY_MODE 0x0020 -#define DP_PHY_AUX_CFG0 0x0024 -#define DP_PHY_AUX_CFG1 0x0028 -#define DP_PHY_AUX_CFG2 0x002C -#define DP_PHY_AUX_CFG3 0x0030 -#define DP_PHY_AUX_CFG4 0x0034 -#define DP_PHY_AUX_CFG5 0x0038 -#define DP_PHY_AUX_CFG6 0x003C -#define DP_PHY_AUX_CFG7 0x0040 -#define DP_PHY_AUX_CFG8 0x0044 -#define DP_PHY_AUX_CFG9 0x0048 +#define DP_AUX_CFG_SIZE 10 +#define DP_PHY_AUX_CFG(n) (0x24 + (0x04 * (n))) #define DP_PHY_AUX_INTERRUPT_MASK 0x0058 @@ -68,19 +63,33 @@ #define TXn_TRAN_DRVR_EMP_EN 0x0078 -struct qcom_edp_cfg { - bool is_dp; - - /* DP PHY swing and pre_emphasis tables */ +struct qcom_edp_swing_pre_emph_cfg { const u8 (*swing_hbr_rbr)[4][4]; const u8 (*swing_hbr3_hbr2)[4][4]; const u8 (*pre_emphasis_hbr_rbr)[4][4]; const u8 (*pre_emphasis_hbr3_hbr2)[4][4]; }; +struct qcom_edp; + +struct phy_ver_ops { + int (*com_power_on)(const struct qcom_edp *edp); + int (*com_resetsm_cntrl)(const struct qcom_edp *edp); + int (*com_bias_en_clkbuflr)(const struct qcom_edp *edp); + int (*com_configure_pll)(const struct qcom_edp *edp); + int (*com_configure_ssc)(const struct qcom_edp *edp); +}; + +struct qcom_edp_phy_cfg { + bool is_edp; + const u8 *aux_cfg; + const struct qcom_edp_swing_pre_emph_cfg *swing_pre_emph_cfg; + const struct phy_ver_ops *ver_ops; +}; + struct qcom_edp { struct device *dev; - const struct qcom_edp_cfg *cfg; + const struct qcom_edp_phy_cfg *cfg; struct phy *phy; @@ -96,6 +105,8 @@ struct qcom_edp { struct clk_bulk_data clks[2]; struct regulator_bulk_data supplies[2]; + + bool is_edp; }; static const u8 dp_swing_hbr_rbr[4][4] = { @@ -126,8 +137,7 @@ static const u8 dp_pre_emp_hbr2_hbr3[4][4] = { { 0x04, 0xff, 0xff, 0xff } }; -static const struct qcom_edp_cfg dp_phy_cfg = { - .is_dp = true, +static const struct qcom_edp_swing_pre_emph_cfg dp_phy_swing_pre_emph_cfg = { .swing_hbr_rbr = &dp_swing_hbr_rbr, .swing_hbr3_hbr2 = &dp_swing_hbr2_hbr3, .pre_emphasis_hbr_rbr = &dp_pre_emp_hbr_rbr, @@ -162,20 +172,47 @@ static const u8 edp_pre_emp_hbr2_hbr3[4][4] = { { 0x00, 0xff, 0xff, 0xff } }; -static const struct qcom_edp_cfg edp_phy_cfg = { - .is_dp = false, +static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg = { .swing_hbr_rbr = &edp_swing_hbr_rbr, .swing_hbr3_hbr2 = &edp_swing_hbr2_hbr3, .pre_emphasis_hbr_rbr = &edp_pre_emp_hbr_rbr, .pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3, }; +static const u8 edp_phy_aux_cfg_v4[10] = { + 0x00, 0x13, 0x24, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03 +}; + +static const u8 edp_pre_emp_hbr_rbr_v5[4][4] = { + { 0x05, 0x11, 0x17, 0x1d }, + { 0x05, 0x11, 0x18, 0xff }, + { 0x06, 0x11, 0xff, 0xff }, + { 0x00, 0xff, 0xff, 0xff } +}; + +static const u8 edp_pre_emp_hbr2_hbr3_v5[4][4] = { + { 0x0c, 0x15, 0x19, 0x1e }, + { 0x0b, 0x15, 0x19, 0xff }, + { 0x0e, 0x14, 0xff, 0xff }, + { 0x0d, 0xff, 0xff, 0xff } +}; + +static const struct qcom_edp_swing_pre_emph_cfg edp_phy_swing_pre_emph_cfg_v5 = { + .swing_hbr_rbr = &edp_swing_hbr_rbr, + .swing_hbr3_hbr2 = &edp_swing_hbr2_hbr3, + .pre_emphasis_hbr_rbr = &edp_pre_emp_hbr_rbr_v5, + .pre_emphasis_hbr3_hbr2 = &edp_pre_emp_hbr2_hbr3_v5, +}; + +static const u8 edp_phy_aux_cfg_v5[10] = { + 0x00, 0x13, 0xa4, 0x00, 0x0a, 0x26, 0x0a, 0x03, 0x37, 0x03 +}; + static int qcom_edp_phy_init(struct phy *phy) { struct qcom_edp *edp = phy_get_drvdata(phy); - const struct qcom_edp_cfg *cfg = edp->cfg; + u8 aux_cfg[DP_AUX_CFG_SIZE]; int ret; - u8 cfg8; ret = regulator_bulk_enable(ARRAY_SIZE(edp->supplies), edp->supplies); if (ret) @@ -185,12 +222,15 @@ static int qcom_edp_phy_init(struct phy *phy) if (ret) goto out_disable_supplies; + memcpy(aux_cfg, edp->cfg->aux_cfg, sizeof(aux_cfg)); + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, edp->edp + DP_PHY_PD_CTL); - /* Turn on BIAS current for PHY/PLL */ - writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN); + ret = edp->cfg->ver_ops->com_bias_en_clkbuflr(edp); + if (ret) + return ret; writel(DP_PHY_PD_CTL_PSR_PWRDN, edp->edp + DP_PHY_PD_CTL); msleep(20); @@ -200,23 +240,18 @@ static int qcom_edp_phy_init(struct phy *phy) DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, edp->edp + DP_PHY_PD_CTL); - if (cfg && cfg->is_dp) - cfg8 = 0xb7; - else - cfg8 = 0x37; + /* + * TODO: Re-work the conditions around setting the cfg8 value + * when more information becomes available about why this is + * even needed. + */ + if (edp->cfg->swing_pre_emph_cfg && !edp->is_edp) + aux_cfg[8] = 0xb7; writel(0xfc, edp->edp + DP_PHY_MODE); - writel(0x00, edp->edp + DP_PHY_AUX_CFG0); - writel(0x13, edp->edp + DP_PHY_AUX_CFG1); - writel(0x24, edp->edp + DP_PHY_AUX_CFG2); - writel(0x00, edp->edp + DP_PHY_AUX_CFG3); - writel(0x0a, edp->edp + DP_PHY_AUX_CFG4); - writel(0x26, edp->edp + DP_PHY_AUX_CFG5); - writel(0x0a, edp->edp + DP_PHY_AUX_CFG6); - writel(0x03, edp->edp + DP_PHY_AUX_CFG7); - writel(cfg8, edp->edp + DP_PHY_AUX_CFG8); - writel(0x03, edp->edp + DP_PHY_AUX_CFG9); + for (int i = 0; i < DP_AUX_CFG_SIZE; i++) + writel(aux_cfg[i], edp->edp + DP_PHY_AUX_CFG(i)); writel(PHY_AUX_STOP_ERR_MASK | PHY_AUX_DEC_ERR_MASK | PHY_AUX_SYNC_ERR_MASK | PHY_AUX_ALIGN_ERR_MASK | @@ -234,7 +269,7 @@ out_disable_supplies: static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configure_opts_dp *dp_opts) { - const struct qcom_edp_cfg *cfg = edp->cfg; + const struct qcom_edp_swing_pre_emph_cfg *cfg = edp->cfg->swing_pre_emph_cfg; unsigned int v_level = 0; unsigned int p_level = 0; u8 ldo_config; @@ -245,6 +280,9 @@ static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configur if (!cfg) return 0; + if (edp->is_edp) + cfg = &edp_phy_swing_pre_emph_cfg; + for (i = 0; i < dp_opts->lanes; i++) { v_level = max(v_level, dp_opts->voltage[i]); p_level = max(p_level, dp_opts->pre[i]); @@ -261,7 +299,7 @@ static int qcom_edp_set_voltages(struct qcom_edp *edp, const struct phy_configur if (swing == 0xff || emph == 0xff) return -EINVAL; - ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0; + ldo_config = edp->is_edp ? 0x0 : 0x1; writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG); writel(swing, edp->tx0 + TXn_TX_DRV_LVL); @@ -290,6 +328,84 @@ static int qcom_edp_phy_configure(struct phy *phy, union phy_configure_opts *opt static int qcom_edp_configure_ssc(const struct qcom_edp *edp) { + return edp->cfg->ver_ops->com_configure_ssc(edp); +} + +static int qcom_edp_configure_pll(const struct qcom_edp *edp) +{ + return edp->cfg->ver_ops->com_configure_pll(edp); +} + +static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel_freq) +{ + const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; + u32 vco_div; + + switch (dp_opts->link_rate) { + case 1620: + vco_div = 0x1; + *pixel_freq = 1620000000UL / 2; + break; + + case 2700: + vco_div = 0x1; + *pixel_freq = 2700000000UL / 2; + break; + + case 5400: + vco_div = 0x2; + *pixel_freq = 5400000000UL / 4; + break; + + case 8100: + vco_div = 0x0; + *pixel_freq = 8100000000UL / 6; + break; + + default: + /* Other link rates aren't supported */ + return -EINVAL; + } + + writel(vco_div, edp->edp + DP_PHY_VCO_DIV); + + return 0; +} + +static int qcom_edp_phy_power_on_v4(const struct qcom_edp *edp) +{ + u32 val; + + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, + edp->edp + DP_PHY_PD_CTL); + writel(0xfc, edp->edp + DP_PHY_MODE); + + return readl_poll_timeout(edp->pll + QSERDES_V4_COM_CMN_STATUS, + val, val & BIT(7), 5, 200); +} + +static int qcom_edp_phy_com_resetsm_cntrl_v4(const struct qcom_edp *edp) +{ + u32 val; + + writel(0x20, edp->pll + QSERDES_V4_COM_RESETSM_CNTRL); + + return readl_poll_timeout(edp->pll + QSERDES_V4_COM_C_READY_STATUS, + val, val & BIT(0), 500, 10000); +} + +static int qcom_edp_com_bias_en_clkbuflr_v4(const struct qcom_edp *edp) +{ + /* Turn on BIAS current for PHY/PLL */ + writel(0x17, edp->pll + QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN); + + return 0; +} + +static int qcom_edp_com_configure_ssc_v4(const struct qcom_edp *edp) +{ const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; u32 step1; u32 step2; @@ -322,7 +438,7 @@ static int qcom_edp_configure_ssc(const struct qcom_edp *edp) return 0; } -static int qcom_edp_configure_pll(const struct qcom_edp *edp) +static int qcom_edp_com_configure_pll_v4(const struct qcom_edp *edp) { const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; u32 div_frac_start2_mode0; @@ -408,30 +524,160 @@ static int qcom_edp_configure_pll(const struct qcom_edp *edp) return 0; } -static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel_freq) +static const struct phy_ver_ops qcom_edp_phy_ops_v4 = { + .com_power_on = qcom_edp_phy_power_on_v4, + .com_resetsm_cntrl = qcom_edp_phy_com_resetsm_cntrl_v4, + .com_bias_en_clkbuflr = qcom_edp_com_bias_en_clkbuflr_v4, + .com_configure_pll = qcom_edp_com_configure_pll_v4, + .com_configure_ssc = qcom_edp_com_configure_ssc_v4, +}; + +static const struct qcom_edp_phy_cfg sa8775p_dp_phy_cfg = { + .is_edp = false, + .aux_cfg = edp_phy_aux_cfg_v5, + .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg_v5, + .ver_ops = &qcom_edp_phy_ops_v4, +}; + +static const struct qcom_edp_phy_cfg sc7280_dp_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v4, + .ver_ops = &qcom_edp_phy_ops_v4, +}; + +static const struct qcom_edp_phy_cfg sc8280xp_dp_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v4, + .swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v4, +}; + +static const struct qcom_edp_phy_cfg sc8280xp_edp_phy_cfg = { + .is_edp = true, + .aux_cfg = edp_phy_aux_cfg_v4, + .swing_pre_emph_cfg = &edp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v4, +}; + +static int qcom_edp_phy_power_on_v6(const struct qcom_edp *edp) +{ + u32 val; + + writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | + DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | + DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, + edp->edp + DP_PHY_PD_CTL); + writel(0xfc, edp->edp + DP_PHY_MODE); + + return readl_poll_timeout(edp->pll + QSERDES_V6_COM_CMN_STATUS, + val, val & BIT(7), 5, 200); +} + +static int qcom_edp_phy_com_resetsm_cntrl_v6(const struct qcom_edp *edp) +{ + u32 val; + + writel(0x20, edp->pll + QSERDES_V6_COM_RESETSM_CNTRL); + + return readl_poll_timeout(edp->pll + QSERDES_V6_COM_C_READY_STATUS, + val, val & BIT(0), 500, 10000); +} + +static int qcom_edp_com_bias_en_clkbuflr_v6(const struct qcom_edp *edp) +{ + /* Turn on BIAS current for PHY/PLL */ + writel(0x1f, edp->pll + QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN); + + return 0; +} + +static int qcom_edp_com_configure_ssc_v6(const struct qcom_edp *edp) { const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; - u32 vco_div; + u32 step1; + u32 step2; switch (dp_opts->link_rate) { case 1620: - vco_div = 0x1; - *pixel_freq = 1620000000UL / 2; + case 2700: + case 8100: + step1 = 0x92; + step2 = 0x01; + break; + + case 5400: + step1 = 0x18; + step2 = 0x02; + break; + + default: + /* Other link rates aren't supported */ + return -EINVAL; + } + + writel(0x01, edp->pll + QSERDES_V6_COM_SSC_EN_CENTER); + writel(0x00, edp->pll + QSERDES_V6_COM_SSC_ADJ_PER1); + writel(0x36, edp->pll + QSERDES_V6_COM_SSC_PER1); + writel(0x01, edp->pll + QSERDES_V6_COM_SSC_PER2); + writel(step1, edp->pll + QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0); + writel(step2, edp->pll + QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0); + + return 0; +} + +static int qcom_edp_com_configure_pll_v6(const struct qcom_edp *edp) +{ + const struct phy_configure_opts_dp *dp_opts = &edp->dp_opts; + u32 div_frac_start2_mode0; + u32 div_frac_start3_mode0; + u32 dec_start_mode0; + u32 lock_cmp1_mode0; + u32 lock_cmp2_mode0; + u32 code1_mode0; + u32 code2_mode0; + u32 hsclk_sel; + + switch (dp_opts->link_rate) { + case 1620: + hsclk_sel = 0x5; + dec_start_mode0 = 0x34; + div_frac_start2_mode0 = 0xc0; + div_frac_start3_mode0 = 0x0b; + lock_cmp1_mode0 = 0x37; + lock_cmp2_mode0 = 0x04; + code1_mode0 = 0x71; + code2_mode0 = 0x0c; break; case 2700: - vco_div = 0x1; - *pixel_freq = 2700000000UL / 2; + hsclk_sel = 0x3; + dec_start_mode0 = 0x34; + div_frac_start2_mode0 = 0xc0; + div_frac_start3_mode0 = 0x0b; + lock_cmp1_mode0 = 0x07; + lock_cmp2_mode0 = 0x07; + code1_mode0 = 0x71; + code2_mode0 = 0x0c; break; case 5400: - vco_div = 0x2; - *pixel_freq = 5400000000UL / 4; + hsclk_sel = 0x1; + dec_start_mode0 = 0x46; + div_frac_start2_mode0 = 0x00; + div_frac_start3_mode0 = 0x05; + lock_cmp1_mode0 = 0x0f; + lock_cmp2_mode0 = 0x0e; + code1_mode0 = 0x97; + code2_mode0 = 0x10; break; case 8100: - vco_div = 0x0; - *pixel_freq = 8100000000UL / 6; + hsclk_sel = 0x0; + dec_start_mode0 = 0x34; + div_frac_start2_mode0 = 0xc0; + div_frac_start3_mode0 = 0x0b; + lock_cmp1_mode0 = 0x17; + lock_cmp2_mode0 = 0x15; + code1_mode0 = 0x71; + code2_mode0 = 0x0c; break; default: @@ -439,36 +685,73 @@ static int qcom_edp_set_vco_div(const struct qcom_edp *edp, unsigned long *pixel return -EINVAL; } - writel(vco_div, edp->edp + DP_PHY_VCO_DIV); + writel(0x01, edp->pll + QSERDES_V6_COM_SVS_MODE_CLK_SEL); + writel(0x0b, edp->pll + QSERDES_V6_COM_SYSCLK_EN_SEL); + writel(0x02, edp->pll + QSERDES_V6_COM_SYS_CLK_CTRL); + writel(0x0c, edp->pll + QSERDES_V6_COM_CLK_ENABLE1); + writel(0x06, edp->pll + QSERDES_V6_COM_SYSCLK_BUF_ENABLE); + writel(0x30, edp->pll + QSERDES_V6_COM_CLK_SELECT); + writel(hsclk_sel, edp->pll + QSERDES_V6_COM_HSCLK_SEL_1); + writel(0x07, edp->pll + QSERDES_V6_COM_PLL_IVCO); + writel(0x08, edp->pll + QSERDES_V6_COM_LOCK_CMP_EN); + writel(0x36, edp->pll + QSERDES_V6_COM_PLL_CCTRL_MODE0); + writel(0x16, edp->pll + QSERDES_V6_COM_PLL_RCTRL_MODE0); + writel(0x06, edp->pll + QSERDES_V6_COM_CP_CTRL_MODE0); + writel(dec_start_mode0, edp->pll + QSERDES_V6_COM_DEC_START_MODE0); + writel(0x00, edp->pll + QSERDES_V6_COM_DIV_FRAC_START1_MODE0); + writel(div_frac_start2_mode0, edp->pll + QSERDES_V6_COM_DIV_FRAC_START2_MODE0); + writel(div_frac_start3_mode0, edp->pll + QSERDES_V6_COM_DIV_FRAC_START3_MODE0); + writel(0x12, edp->pll + QSERDES_V6_COM_CMN_CONFIG_1); + writel(0x3f, edp->pll + QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE0); + writel(0x00, edp->pll + QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE0); + writel(0x00, edp->pll + QSERDES_V6_COM_VCO_TUNE_MAP); + writel(lock_cmp1_mode0, edp->pll + QSERDES_V6_COM_LOCK_CMP1_MODE0); + writel(lock_cmp2_mode0, edp->pll + QSERDES_V6_COM_LOCK_CMP2_MODE0); + + writel(0x0a, edp->pll + QSERDES_V6_COM_BG_TIMER); + writel(0x14, edp->pll + QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0); + writel(0x00, edp->pll + QSERDES_V6_COM_VCO_TUNE_CTRL); + writel(0x1f, edp->pll + QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN); + writel(0x0f, edp->pll + QSERDES_V6_COM_CORE_CLK_EN); + writel(0xa0, edp->pll + QSERDES_V6_COM_VCO_TUNE1_MODE0); + writel(0x03, edp->pll + QSERDES_V6_COM_VCO_TUNE2_MODE0); + + writel(code1_mode0, edp->pll + QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0); + writel(code2_mode0, edp->pll + QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0); return 0; } +static const struct phy_ver_ops qcom_edp_phy_ops_v6 = { + .com_power_on = qcom_edp_phy_power_on_v6, + .com_resetsm_cntrl = qcom_edp_phy_com_resetsm_cntrl_v6, + .com_bias_en_clkbuflr = qcom_edp_com_bias_en_clkbuflr_v6, + .com_configure_pll = qcom_edp_com_configure_pll_v6, + .com_configure_ssc = qcom_edp_com_configure_ssc_v6, +}; + +static struct qcom_edp_phy_cfg x1e80100_phy_cfg = { + .aux_cfg = edp_phy_aux_cfg_v4, + .swing_pre_emph_cfg = &dp_phy_swing_pre_emph_cfg, + .ver_ops = &qcom_edp_phy_ops_v6, +}; + static int qcom_edp_phy_power_on(struct phy *phy) { const struct qcom_edp *edp = phy_get_drvdata(phy); - const struct qcom_edp_cfg *cfg = edp->cfg; u32 bias0_en, drvr0_en, bias1_en, drvr1_en; unsigned long pixel_freq; - u8 ldo_config; - int timeout; + u8 ldo_config = 0x0; int ret; u32 val; u8 cfg1; - writel(DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN | - DP_PHY_PD_CTL_LANE_0_1_PWRDN | DP_PHY_PD_CTL_LANE_2_3_PWRDN | - DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN, - edp->edp + DP_PHY_PD_CTL); - writel(0xfc, edp->edp + DP_PHY_MODE); - - timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_CMN_STATUS, - val, val & BIT(7), 5, 200); - if (timeout) - return timeout; - + ret = edp->cfg->ver_ops->com_power_on(edp); + if (ret) + return ret; - ldo_config = (cfg && cfg->is_dp) ? 0x1 : 0x0; + if (edp->cfg->swing_pre_emph_cfg && !edp->is_edp) + ldo_config = 0x1; writel(ldo_config, edp->tx0 + TXn_LDO_CONFIG); writel(ldo_config, edp->tx1 + TXn_LDO_CONFIG); @@ -512,12 +795,9 @@ static int qcom_edp_phy_power_on(struct phy *phy) writel(0x01, edp->edp + DP_PHY_CFG); writel(0x09, edp->edp + DP_PHY_CFG); - writel(0x20, edp->pll + QSERDES_V4_COM_RESETSM_CNTRL); - - timeout = readl_poll_timeout(edp->pll + QSERDES_V4_COM_C_READY_STATUS, - val, val & BIT(0), 500, 10000); - if (timeout) - return timeout; + ret = edp->cfg->ver_ops->com_resetsm_cntrl(edp); + if (ret) + return ret; writel(0x19, edp->edp + DP_PHY_CFG); writel(0x1f, edp->tx0 + TXn_HIGHZ_DRVR_EN); @@ -589,6 +869,18 @@ static int qcom_edp_phy_power_off(struct phy *phy) return 0; } +static int qcom_edp_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct qcom_edp *edp = phy_get_drvdata(phy); + + if (mode != PHY_MODE_DP) + return -EINVAL; + + edp->is_edp = submode == PHY_SUBMODE_EDP; + + return 0; +} + static int qcom_edp_phy_exit(struct phy *phy) { struct qcom_edp *edp = phy_get_drvdata(phy); @@ -604,6 +896,7 @@ static const struct phy_ops qcom_edp_ops = { .configure = qcom_edp_phy_configure, .power_on = qcom_edp_phy_power_on, .power_off = qcom_edp_phy_power_off, + .set_mode = qcom_edp_phy_set_mode, .exit = qcom_edp_phy_exit, .owner = THIS_MODULE, }; @@ -781,6 +1074,7 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) edp->dev = dev; edp->cfg = of_device_get_match_data(&pdev->dev); + edp->is_edp = edp->cfg->is_edp; edp->edp = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(edp->edp)) @@ -839,10 +1133,12 @@ static int qcom_edp_phy_probe(struct platform_device *pdev) } static const struct of_device_id qcom_edp_phy_match_table[] = { - { .compatible = "qcom,sc7280-edp-phy" }, - { .compatible = "qcom,sc8180x-edp-phy" }, - { .compatible = "qcom,sc8280xp-dp-phy", .data = &dp_phy_cfg }, - { .compatible = "qcom,sc8280xp-edp-phy", .data = &edp_phy_cfg }, + { .compatible = "qcom,sa8775p-edp-phy", .data = &sa8775p_dp_phy_cfg, }, + { .compatible = "qcom,sc7280-edp-phy", .data = &sc7280_dp_phy_cfg, }, + { .compatible = "qcom,sc8180x-edp-phy", .data = &sc7280_dp_phy_cfg, }, + { .compatible = "qcom,sc8280xp-dp-phy", .data = &sc8280xp_dp_phy_cfg, }, + { .compatible = "qcom,sc8280xp-edp-phy", .data = &sc8280xp_edp_phy_cfg, }, + { .compatible = "qcom,x1e80100-dp-phy", .data = &x1e80100_phy_cfg, }, { } }; MODULE_DEVICE_TABLE(of, qcom_edp_phy_match_table); diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c index a623f092b11f..6bd1b3c75c77 100644 --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c @@ -37,56 +37,28 @@ #define EUSB2_TUNE_EUSB_EQU 0x5A #define EUSB2_TUNE_EUSB_HS_COMP_CUR 0x5B -#define QCOM_EUSB2_REPEATER_INIT_CFG(r, v) \ - { \ - .reg = r, \ - .val = v, \ - } - -enum reg_fields { - F_TUNE_EUSB_HS_COMP_CUR, - F_TUNE_EUSB_EQU, - F_TUNE_EUSB_SLEW, - F_TUNE_USB2_HS_COMP_CUR, - F_TUNE_USB2_PREEM, - F_TUNE_USB2_EQU, - F_TUNE_USB2_SLEW, - F_TUNE_SQUELCH_U, - F_TUNE_HSDISC, - F_TUNE_RES_FSDIF, - F_TUNE_IUSB2, - F_TUNE_USB2_CROSSOVER, - F_NUM_TUNE_FIELDS, - - F_FORCE_VAL_5 = F_NUM_TUNE_FIELDS, - F_FORCE_EN_5, - - F_EN_CTL1, - - F_RPTR_STATUS, - F_NUM_FIELDS, -}; - -static struct reg_field eusb2_repeater_tune_reg_fields[F_NUM_FIELDS] = { - [F_TUNE_EUSB_HS_COMP_CUR] = REG_FIELD(EUSB2_TUNE_EUSB_HS_COMP_CUR, 0, 1), - [F_TUNE_EUSB_EQU] = REG_FIELD(EUSB2_TUNE_EUSB_EQU, 0, 1), - [F_TUNE_EUSB_SLEW] = REG_FIELD(EUSB2_TUNE_EUSB_SLEW, 0, 1), - [F_TUNE_USB2_HS_COMP_CUR] = REG_FIELD(EUSB2_TUNE_USB2_HS_COMP_CUR, 0, 1), - [F_TUNE_USB2_PREEM] = REG_FIELD(EUSB2_TUNE_USB2_PREEM, 0, 2), - [F_TUNE_USB2_EQU] = REG_FIELD(EUSB2_TUNE_USB2_EQU, 0, 1), - [F_TUNE_USB2_SLEW] = REG_FIELD(EUSB2_TUNE_USB2_SLEW, 0, 1), - [F_TUNE_SQUELCH_U] = REG_FIELD(EUSB2_TUNE_SQUELCH_U, 0, 2), - [F_TUNE_HSDISC] = REG_FIELD(EUSB2_TUNE_HSDISC, 0, 2), - [F_TUNE_RES_FSDIF] = REG_FIELD(EUSB2_TUNE_RES_FSDIF, 0, 2), - [F_TUNE_IUSB2] = REG_FIELD(EUSB2_TUNE_IUSB2, 0, 3), - [F_TUNE_USB2_CROSSOVER] = REG_FIELD(EUSB2_TUNE_USB2_CROSSOVER, 0, 2), - - [F_FORCE_VAL_5] = REG_FIELD(EUSB2_FORCE_VAL_5, 0, 7), - [F_FORCE_EN_5] = REG_FIELD(EUSB2_FORCE_EN_5, 0, 7), - - [F_EN_CTL1] = REG_FIELD(EUSB2_EN_CTL1, 0, 7), - - [F_RPTR_STATUS] = REG_FIELD(EUSB2_RPTR_STATUS, 0, 7), +enum eusb2_reg_layout { + TUNE_EUSB_HS_COMP_CUR, + TUNE_EUSB_EQU, + TUNE_EUSB_SLEW, + TUNE_USB2_HS_COMP_CUR, + TUNE_USB2_PREEM, + TUNE_USB2_EQU, + TUNE_USB2_SLEW, + TUNE_SQUELCH_U, + TUNE_HSDISC, + TUNE_RES_FSDIF, + TUNE_IUSB2, + TUNE_USB2_CROSSOVER, + NUM_TUNE_FIELDS, + + FORCE_VAL_5 = NUM_TUNE_FIELDS, + FORCE_EN_5, + + EN_CTL1, + + RPTR_STATUS, + LAYOUT_SIZE, }; struct eusb2_repeater_cfg { @@ -98,10 +70,11 @@ struct eusb2_repeater_cfg { struct eusb2_repeater { struct device *dev; - struct regmap_field *regs[F_NUM_FIELDS]; + struct regmap *regmap; struct phy *phy; struct regulator_bulk_data *vregs; const struct eusb2_repeater_cfg *cfg; + u32 base; enum phy_mode mode; }; @@ -109,10 +82,16 @@ static const char * const pm8550b_vreg_l[] = { "vdd18", "vdd3", }; -static const u32 pm8550b_init_tbl[F_NUM_TUNE_FIELDS] = { - [F_TUNE_IUSB2] = 0x8, - [F_TUNE_SQUELCH_U] = 0x3, - [F_TUNE_USB2_PREEM] = 0x5, +static const u32 pm8550b_init_tbl[NUM_TUNE_FIELDS] = { + [TUNE_IUSB2] = 0x8, + [TUNE_SQUELCH_U] = 0x3, + [TUNE_USB2_PREEM] = 0x5, +}; + +static const u32 smb2360_init_tbl[NUM_TUNE_FIELDS] = { + [TUNE_IUSB2] = 0x5, + [TUNE_SQUELCH_U] = 0x3, + [TUNE_USB2_PREEM] = 0x2, }; static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = { @@ -122,6 +101,13 @@ static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = { .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), }; +static const struct eusb2_repeater_cfg smb2360_eusb2_cfg = { + .init_tbl = smb2360_init_tbl, + .init_tbl_num = ARRAY_SIZE(smb2360_init_tbl), + .vreg_list = pm8550b_vreg_l, + .num_vregs = ARRAY_SIZE(pm8550b_vreg_l), +}; + static int eusb2_repeater_init_vregs(struct eusb2_repeater *rptr) { int num = rptr->cfg->num_vregs; @@ -140,47 +126,42 @@ static int eusb2_repeater_init_vregs(struct eusb2_repeater *rptr) static int eusb2_repeater_init(struct phy *phy) { - struct reg_field *regfields = eusb2_repeater_tune_reg_fields; struct eusb2_repeater *rptr = phy_get_drvdata(phy); struct device_node *np = rptr->dev->of_node; - u32 init_tbl[F_NUM_TUNE_FIELDS] = { 0 }; - u8 override; + struct regmap *regmap = rptr->regmap; + const u32 *init_tbl = rptr->cfg->init_tbl; + u8 tune_usb2_preem = init_tbl[TUNE_USB2_PREEM]; + u8 tune_hsdisc = init_tbl[TUNE_HSDISC]; + u8 tune_iusb2 = init_tbl[TUNE_IUSB2]; + u32 base = rptr->base; u32 val; int ret; - int i; + + of_property_read_u8(np, "qcom,tune-usb2-amplitude", &tune_iusb2); + of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &tune_hsdisc); + of_property_read_u8(np, "qcom,tune-usb2-preem", &tune_usb2_preem); ret = regulator_bulk_enable(rptr->cfg->num_vregs, rptr->vregs); if (ret) return ret; - regmap_field_update_bits(rptr->regs[F_EN_CTL1], EUSB2_RPTR_EN, EUSB2_RPTR_EN); + regmap_write(regmap, base + EUSB2_EN_CTL1, EUSB2_RPTR_EN); - for (i = 0; i < F_NUM_TUNE_FIELDS; i++) { - if (init_tbl[i]) { - regmap_field_update_bits(rptr->regs[i], init_tbl[i], init_tbl[i]); - } else { - /* Write 0 if there's no value set */ - u32 mask = GENMASK(regfields[i].msb, regfields[i].lsb); + regmap_write(regmap, base + EUSB2_TUNE_EUSB_HS_COMP_CUR, init_tbl[TUNE_EUSB_HS_COMP_CUR]); + regmap_write(regmap, base + EUSB2_TUNE_EUSB_EQU, init_tbl[TUNE_EUSB_EQU]); + regmap_write(regmap, base + EUSB2_TUNE_EUSB_SLEW, init_tbl[TUNE_EUSB_SLEW]); + regmap_write(regmap, base + EUSB2_TUNE_USB2_HS_COMP_CUR, init_tbl[TUNE_USB2_HS_COMP_CUR]); + regmap_write(regmap, base + EUSB2_TUNE_USB2_EQU, init_tbl[TUNE_USB2_EQU]); + regmap_write(regmap, base + EUSB2_TUNE_USB2_SLEW, init_tbl[TUNE_USB2_SLEW]); + regmap_write(regmap, base + EUSB2_TUNE_SQUELCH_U, init_tbl[TUNE_SQUELCH_U]); + regmap_write(regmap, base + EUSB2_TUNE_RES_FSDIF, init_tbl[TUNE_RES_FSDIF]); + regmap_write(regmap, base + EUSB2_TUNE_USB2_CROSSOVER, init_tbl[TUNE_USB2_CROSSOVER]); - regmap_field_update_bits(rptr->regs[i], mask, 0); - } - } - memcpy(init_tbl, rptr->cfg->init_tbl, sizeof(init_tbl)); - - if (!of_property_read_u8(np, "qcom,tune-usb2-amplitude", &override)) - init_tbl[F_TUNE_IUSB2] = override; - - if (!of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &override)) - init_tbl[F_TUNE_HSDISC] = override; + regmap_write(regmap, base + EUSB2_TUNE_USB2_PREEM, tune_usb2_preem); + regmap_write(regmap, base + EUSB2_TUNE_HSDISC, tune_hsdisc); + regmap_write(regmap, base + EUSB2_TUNE_IUSB2, tune_iusb2); - if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &override)) - init_tbl[F_TUNE_USB2_PREEM] = override; - - for (i = 0; i < F_NUM_TUNE_FIELDS; i++) - regmap_field_update_bits(rptr->regs[i], init_tbl[i], init_tbl[i]); - - ret = regmap_field_read_poll_timeout(rptr->regs[F_RPTR_STATUS], - val, val & RPTR_OK, 10, 5); + ret = regmap_read_poll_timeout(regmap, base + EUSB2_RPTR_STATUS, val, val & RPTR_OK, 10, 5); if (ret) dev_err(rptr->dev, "initialization timed-out\n"); @@ -191,6 +172,8 @@ static int eusb2_repeater_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct eusb2_repeater *rptr = phy_get_drvdata(phy); + struct regmap *regmap = rptr->regmap; + u32 base = rptr->base; switch (mode) { case PHY_MODE_USB_HOST: @@ -199,10 +182,8 @@ static int eusb2_repeater_set_mode(struct phy *phy, * per eUSB 1.2 Spec. Below implement software workaround until * PHY and controller is fixing seen observation. */ - regmap_field_update_bits(rptr->regs[F_FORCE_EN_5], - F_CLK_19P2M_EN, F_CLK_19P2M_EN); - regmap_field_update_bits(rptr->regs[F_FORCE_VAL_5], - V_CLK_19P2M_EN, V_CLK_19P2M_EN); + regmap_write(regmap, base + EUSB2_FORCE_EN_5, F_CLK_19P2M_EN); + regmap_write(regmap, base + EUSB2_FORCE_VAL_5, V_CLK_19P2M_EN); break; case PHY_MODE_USB_DEVICE: /* @@ -211,10 +192,8 @@ static int eusb2_repeater_set_mode(struct phy *phy, * repeater doesn't clear previous value due to shared * regulators (say host <-> device mode switch). */ - regmap_field_update_bits(rptr->regs[F_FORCE_EN_5], - F_CLK_19P2M_EN, 0); - regmap_field_update_bits(rptr->regs[F_FORCE_VAL_5], - V_CLK_19P2M_EN, 0); + regmap_write(regmap, base + EUSB2_FORCE_EN_5, 0); + regmap_write(regmap, base + EUSB2_FORCE_VAL_5, 0); break; default: return -EINVAL; @@ -243,9 +222,8 @@ static int eusb2_repeater_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct phy_provider *phy_provider; struct device_node *np = dev->of_node; - struct regmap *regmap; - int i, ret; u32 res; + int ret; rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL); if (!rptr) @@ -258,22 +236,15 @@ static int eusb2_repeater_probe(struct platform_device *pdev) if (!rptr->cfg) return -EINVAL; - regmap = dev_get_regmap(dev->parent, NULL); - if (!regmap) + rptr->regmap = dev_get_regmap(dev->parent, NULL); + if (!rptr->regmap) return -ENODEV; ret = of_property_read_u32(np, "reg", &res); if (ret < 0) return ret; - for (i = 0; i < F_NUM_FIELDS; i++) - eusb2_repeater_tune_reg_fields[i].reg += res; - - ret = devm_regmap_field_bulk_alloc(dev, regmap, rptr->regs, - eusb2_repeater_tune_reg_fields, - F_NUM_FIELDS); - if (ret) - return ret; + rptr->base = res; ret = eusb2_repeater_init_vregs(rptr); if (ret < 0) { @@ -313,13 +284,17 @@ static const struct of_device_id eusb2_repeater_of_match_table[] = { .compatible = "qcom,pm8550b-eusb2-repeater", .data = &pm8550b_eusb2_cfg, }, + { + .compatible = "qcom,smb2360-eusb2-repeater", + .data = &smb2360_eusb2_cfg, + }, { }, }; MODULE_DEVICE_TABLE(of, eusb2_repeater_of_match_table); static struct platform_driver eusb2_repeater_driver = { .probe = eusb2_repeater_probe, - .remove_new = eusb2_repeater_remove, + .remove = eusb2_repeater_remove, .driver = { .name = "qcom-eusb2-repeater", .of_match_table = eusb2_repeater_of_match_table, diff --git a/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c index f0a72b82c770..f5eb0bdac418 100644 --- a/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c +++ b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c @@ -184,11 +184,11 @@ static const struct of_device_id qcom_ipq806x_sata_phy_of_match[] = { MODULE_DEVICE_TABLE(of, qcom_ipq806x_sata_phy_of_match); static struct platform_driver qcom_ipq806x_sata_phy_driver = { - .probe = qcom_ipq806x_sata_phy_probe, - .remove_new = qcom_ipq806x_sata_phy_remove, + .probe = qcom_ipq806x_sata_phy_probe, + .remove = qcom_ipq806x_sata_phy_remove, .driver = { - .name = "qcom-ipq806x-sata-phy", - .of_match_table = qcom_ipq806x_sata_phy_of_match, + .name = "qcom-ipq806x-sata-phy", + .of_match_table = qcom_ipq806x_sata_phy_of_match, } }; module_platform_driver(qcom_ipq806x_sata_phy_driver); diff --git a/drivers/phy/qualcomm/phy-qcom-m31.c b/drivers/phy/qualcomm/phy-qcom-m31.c index c2590579190a..20d4c020a83c 100644 --- a/drivers/phy/qualcomm/phy-qcom-m31.c +++ b/drivers/phy/qualcomm/phy-qcom-m31.c @@ -297,9 +297,9 @@ static int m31usb_phy_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(qphy->phy), "failed to create phy\n"); - qphy->vreg = devm_regulator_get(dev, "vdda-phy"); + qphy->vreg = devm_regulator_get(dev, "vdd"); if (IS_ERR(qphy->vreg)) - return dev_err_probe(dev, PTR_ERR(qphy->phy), + return dev_err_probe(dev, PTR_ERR(qphy->vreg), "failed to get vreg\n"); phy_set_drvdata(qphy->phy, qphy); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c index 1ad10110dd25..b09fa00e9fe7 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c @@ -25,21 +25,21 @@ #include <dt-bindings/phy/phy-qcom-qmp.h> +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" #include "phy-qcom-qmp-pcs-usb-v4.h" #include "phy-qcom-qmp-pcs-usb-v5.h" #include "phy-qcom-qmp-pcs-usb-v6.h" -/* QPHY_SW_RESET bit */ -#define SW_RESET BIT(0) -/* QPHY_POWER_DOWN_CONTROL */ -#define SW_PWRDN BIT(0) -/* QPHY_START_CONTROL bits */ -#define SERDES_START BIT(0) -#define PCS_START BIT(1) -/* QPHY_PCS_STATUS bit */ -#define PHYSTATUS BIT(6) +#include "phy-qcom-qmp-dp-com-v3.h" + +#include "phy-qcom-qmp-dp-phy.h" +#include "phy-qcom-qmp-dp-phy-v3.h" +#include "phy-qcom-qmp-dp-phy-v4.h" +#include "phy-qcom-qmp-dp-phy-v5.h" +#include "phy-qcom-qmp-dp-phy-v6.h" /* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ /* DP PHY soft reset */ @@ -55,47 +55,12 @@ #define USB3_MODE BIT(0) /* enables USB3 mode */ #define DP_MODE BIT(1) /* enables DP mode */ -/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */ -#define ARCVR_DTCT_EN BIT(0) -#define ALFPS_DTCT_EN BIT(1) -#define ARCVR_DTCT_EVENT_SEL BIT(4) - -/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */ -#define IRQ_CLEAR BIT(0) - -/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */ -#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ - /* QPHY_V3_DP_COM_TYPEC_CTRL register bits */ #define SW_PORTSELECT_VAL BIT(0) #define SW_PORTSELECT_MUX BIT(1) #define PHY_INIT_COMPLETE_TIMEOUT 10000 -struct qmp_phy_init_tbl { - unsigned int offset; - unsigned int val; - /* - * mask of lanes for which this register is written - * for cases when second lane needs different values - */ - u8 lane_mask; -}; - -#define QMP_PHY_INIT_CFG(o, v) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = 0xff, \ - } - -#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = l, \ - } - /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { /* PCS registers */ @@ -112,6 +77,7 @@ enum qphy_reg_layout { QPHY_COM_BIAS_EN_CLKBUFLR_EN, QPHY_DP_PHY_STATUS, + QPHY_DP_PHY_VCO_DIV, QPHY_TX_TX_POL_INV, QPHY_TX_TX_DRV_LVL, @@ -137,6 +103,7 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, [QPHY_DP_PHY_STATUS] = QSERDES_V3_DP_PHY_STATUS, + [QPHY_DP_PHY_VCO_DIV] = QSERDES_V3_DP_PHY_VCO_DIV, [QPHY_TX_TX_POL_INV] = QSERDES_V3_TX_TX_POL_INV, [QPHY_TX_TX_DRV_LVL] = QSERDES_V3_TX_TX_DRV_LVL, @@ -161,6 +128,7 @@ static const unsigned int qmp_v45_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V4_COM_BIAS_EN_CLKBUFLR_EN, [QPHY_DP_PHY_STATUS] = QSERDES_V4_DP_PHY_STATUS, + [QPHY_DP_PHY_VCO_DIV] = QSERDES_V4_DP_PHY_VCO_DIV, [QPHY_TX_TX_POL_INV] = QSERDES_V4_TX_TX_POL_INV, [QPHY_TX_TX_DRV_LVL] = QSERDES_V4_TX_TX_DRV_LVL, @@ -185,6 +153,7 @@ static const unsigned int qmp_v5_5nm_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, [QPHY_DP_PHY_STATUS] = QSERDES_V5_DP_PHY_STATUS, + [QPHY_DP_PHY_VCO_DIV] = QSERDES_V5_DP_PHY_VCO_DIV, [QPHY_TX_TX_POL_INV] = QSERDES_V5_5NM_TX_TX_POL_INV, [QPHY_TX_TX_DRV_LVL] = QSERDES_V5_5NM_TX_TX_DRV_LVL, @@ -209,6 +178,7 @@ static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, [QPHY_DP_PHY_STATUS] = QSERDES_V6_DP_PHY_STATUS, + [QPHY_DP_PHY_VCO_DIV] = QSERDES_V6_DP_PHY_VCO_DIV, [QPHY_TX_TX_POL_INV] = QSERDES_V6_TX_TX_POL_INV, [QPHY_TX_TX_DRV_LVL] = QSERDES_V6_TX_TX_DRV_LVL, @@ -217,6 +187,31 @@ static const unsigned int qmp_v6_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V6_TX_TRANSCEIVER_BIAS_EN, }; +static const unsigned int qmp_v6_n4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V6_N4_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V6_N4_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V6_N4_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_N4_PCS_POWER_DOWN_CONTROL, + + /* In PCS_USB */ + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V6_PCS_USB3_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V6_PCS_USB3_LFPS_RXTERM_IRQ_CLEAR, + + [QPHY_COM_RESETSM_CNTRL] = QSERDES_V6_COM_RESETSM_CNTRL, + [QPHY_COM_C_READY_STATUS] = QSERDES_V6_COM_C_READY_STATUS, + [QPHY_COM_CMN_STATUS] = QSERDES_V6_COM_CMN_STATUS, + [QPHY_COM_BIAS_EN_CLKBUFLR_EN] = QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, + + [QPHY_DP_PHY_STATUS] = QSERDES_V6_DP_PHY_STATUS, + [QPHY_DP_PHY_VCO_DIV] = QSERDES_V6_DP_PHY_VCO_DIV, + + [QPHY_TX_TX_POL_INV] = QSERDES_V6_N4_TX_TX_POL_INV, + [QPHY_TX_TX_DRV_LVL] = QSERDES_V6_N4_TX_TX_DRV_LVL, + [QPHY_TX_TX_EMP_POST1_LVL] = QSERDES_V6_N4_TX_TX_EMP_POST1_LVL, + [QPHY_TX_HIGHZ_DRVR_EN] = QSERDES_V6_N4_TX_HIGHZ_DRVR_EN, + [QPHY_TX_TRANSCEIVER_BIAS_EN] = QSERDES_V6_N4_TX_TRANSCEIVER_BIAS_EN, +}; + static const struct qmp_phy_init_tbl qmp_v3_usb3_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), @@ -405,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), @@ -1027,6 +1073,31 @@ static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0x0f), }; +static const struct qmp_phy_init_tbl qmp_v6_n4_dp_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SVS_MODE_CLK_SEL, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x3b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_ENABLE1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_BUF_ENABLE, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xc0), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CORE_CLK_DIV_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CORE_CLK_EN, 0x0f), +}; + static const struct qmp_phy_init_tbl qmp_v6_dp_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_TX_VMODE_CTRL1, 0x40), QMP_PHY_INIT_CFG(QSERDES_V6_TX_PRE_STALL_LDO_BOOST_EN, 0x30), @@ -1041,6 +1112,19 @@ static const struct qmp_phy_init_tbl qmp_v6_dp_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_TX_TX_BAND, 0x4), }; +static const struct qmp_phy_init_tbl qmp_v6_n4_dp_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_VMODE_CTRL1, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_PRE_STALL_LDO_BOOST_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_INTERFACE_SELECT, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_CLKBUF_ENABLE, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_RESET_TSYNC_EN, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_TRAN_DRVR_EMP_EN, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_PARRATE_REC_DETECT_IDLE_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_RES_CODE_LANE_OFFSET_TX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_RES_CODE_LANE_OFFSET_RX, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V6_N4_TX_TX_BAND, 0x1), +}; + static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl_rbr[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x05), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x34), @@ -1089,6 +1173,74 @@ static const struct qmp_phy_init_tbl qmp_v6_dp_serdes_tbl_hbr3[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0c), }; +static const struct qmp_phy_init_tbl qmp_v6_n4_dp_serdes_tbl_rbr[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x37), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x71), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x6b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0x92), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01), +}; + +static const struct qmp_phy_init_tbl qmp_v6_n4_dp_serdes_tbl_hbr[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x71), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x6b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0x92), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01), +}; + +static const struct qmp_phy_init_tbl qmp_v6_n4_dp_serdes_tbl_hbr2[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x46), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x97), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x6b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x02), +}; + +static const struct qmp_phy_init_tbl qmp_v6_n4_dp_serdes_tbl_hbr3[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_SEL_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0x71), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x6b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0x92), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01), +}; + static const struct qmp_phy_init_tbl sc8280xp_usb43dp_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_EN_CENTER, 0x01), QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_PER1, 0x31), @@ -1303,20 +1455,20 @@ static const struct qmp_phy_init_tbl x1e80100_usb43dp_rx_tbl[] = { }; static const struct qmp_phy_init_tbl x1e80100_usb43dp_pcs_tbl[] = { - QMP_PHY_INIT_CFG(QPHY_V6_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_LOCK_DETECT_CONFIG1, 0xc4), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_LOCK_DETECT_CONFIG2, 0x89), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_LOCK_DETECT_CONFIG3, 0x20), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_LOCK_DETECT_CONFIG6, 0x13), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_REFGEN_REQ_CONFIG1, 0x21), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_RX_SIGDET_LVL, 0x55), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_CDR_RESET_TIME, 0x0a), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_ALIGN_DETECT_CONFIG1, 0xd4), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_ALIGN_DETECT_CONFIG2, 0x30), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_PCS_TX_RX_CONFIG, 0x0c), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_EQ_CONFIG1, 0x4b), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_EQ_CONFIG5, 0x10), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_LOCK_DETECT_CONFIG1, 0xc4), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_LOCK_DETECT_CONFIG2, 0x89), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_LOCK_DETECT_CONFIG3, 0x20), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_LOCK_DETECT_CONFIG6, 0x13), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_REFGEN_REQ_CONFIG1, 0x21), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_RX_SIGDET_LVL, 0x55), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_RX_CONFIG, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_ALIGN_DETECT_CONFIG1, 0xd4), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_ALIGN_DETECT_CONFIG2, 0x30), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_PCS_TX_RX_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_EQ_CONFIG1, 0x4b), + QMP_PHY_INIT_CFG(QPHY_V6_N4_PCS_EQ_CONFIG5, 0x10), }; static const struct qmp_phy_init_tbl x1e80100_usb43dp_pcs_usb_tbl[] = { @@ -1412,6 +1564,13 @@ static const u8 qmp_dp_v5_voltage_swing_hbr_rbr[4][4] = { { 0x3f, 0xff, 0xff, 0xff } }; +static const u8 qmp_dp_v6_voltage_swing_hbr_rbr[4][4] = { + { 0x27, 0x2f, 0x36, 0x3f }, + { 0x31, 0x3e, 0x3f, 0xff }, + { 0x36, 0x3f, 0xff, 0xff }, + { 0x3f, 0xff, 0xff, 0xff } +}; + static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = { { 0x20, 0x2d, 0x34, 0x3a }, { 0x20, 0x2e, 0x35, 0xff }, @@ -1622,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, @@ -1817,22 +2021,22 @@ static const struct qmp_phy_cfg x1e80100_usb3dpphy_cfg = { .pcs_usb_tbl = x1e80100_usb43dp_pcs_usb_tbl, .pcs_usb_tbl_num = ARRAY_SIZE(x1e80100_usb43dp_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_v5_pre_emphasis_hbr_rbr, + .dp_serdes_tbl = qmp_v6_n4_dp_serdes_tbl, + .dp_serdes_tbl_num = ARRAY_SIZE(qmp_v6_n4_dp_serdes_tbl), + .dp_tx_tbl = qmp_v6_n4_dp_tx_tbl, + .dp_tx_tbl_num = ARRAY_SIZE(qmp_v6_n4_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v6_n4_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v6_n4_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v6_n4_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v6_n4_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v6_n4_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v6_n4_dp_serdes_tbl_hbr2), + .serdes_tbl_hbr3 = qmp_v6_n4_dp_serdes_tbl_hbr3, + .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v6_n4_dp_serdes_tbl_hbr3), + + .swing_hbr_rbr = &qmp_dp_v6_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, @@ -1845,7 +2049,7 @@ static const struct qmp_phy_cfg x1e80100_usb3dpphy_cfg = { .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v45_usb3phy_regs_layout, + .regs = qmp_v6_n4_usb3phy_regs_layout, }; static const struct qmp_phy_cfg sm6350_usb3dpphy_cfg = { @@ -2031,31 +2235,50 @@ static const struct qmp_phy_cfg sm8550_usb3dpphy_cfg = { .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), }; -static void qmp_combo_configure_lane(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num, - u8 lane_mask) -{ - int i; - const struct qmp_phy_init_tbl *t = tbl; +static const struct qmp_phy_cfg sm8650_usb3dpphy_cfg = { + .offsets = &qmp_combo_offsets_v3, - if (!t) - return; + .serdes_tbl = sm8550_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sm8550_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), - for (i = 0; i < num; i++, t++) { - if (!(t->lane_mask & lane_mask)) - continue; + .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), - writel(t->val, base + t->offset); - } -} + .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), -static void qmp_combo_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_combo_configure_lane(base, tbl, num, 0xff); -} + .swing_hbr_rbr = &qmp_dp_v6_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 int qmp_combo_dp_serdes_init(struct qmp_combo *qmp) { @@ -2063,24 +2286,25 @@ static int qmp_combo_dp_serdes_init(struct qmp_combo *qmp) void __iomem *serdes = qmp->dp_serdes; const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; - qmp_combo_configure(serdes, cfg->dp_serdes_tbl, cfg->dp_serdes_tbl_num); + qmp_configure(qmp->dev, serdes, cfg->dp_serdes_tbl, + cfg->dp_serdes_tbl_num); switch (dp_opts->link_rate) { case 1620: - qmp_combo_configure(serdes, cfg->serdes_tbl_rbr, - cfg->serdes_tbl_rbr_num); + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_rbr, + cfg->serdes_tbl_rbr_num); break; case 2700: - qmp_combo_configure(serdes, cfg->serdes_tbl_hbr, - cfg->serdes_tbl_hbr_num); + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr, + cfg->serdes_tbl_hbr_num); break; case 5400: - qmp_combo_configure(serdes, cfg->serdes_tbl_hbr2, - cfg->serdes_tbl_hbr2_num); + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr2, + cfg->serdes_tbl_hbr2_num); break; case 8100: - qmp_combo_configure(serdes, cfg->serdes_tbl_hbr3, - cfg->serdes_tbl_hbr3_num); + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr3, + cfg->serdes_tbl_hbr3_num); break; default: /* Other link rates aren't supported */ @@ -2211,9 +2435,9 @@ static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp) writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); if (reverse) - writel(0x4c, qmp->pcs + QSERDES_DP_PHY_MODE); + writel(0x4c, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE); else - writel(0x5c, qmp->pcs + QSERDES_DP_PHY_MODE); + writel(0x5c, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE); return reverse; } @@ -2223,6 +2447,7 @@ static int qmp_combo_configure_dp_clocks(struct qmp_combo *qmp) const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; u32 phy_vco_div; unsigned long pixel_freq; + const struct qmp_phy_cfg *cfg = qmp->cfg; switch (dp_opts->link_rate) { case 1620: @@ -2245,7 +2470,7 @@ static int qmp_combo_configure_dp_clocks(struct qmp_combo *qmp) /* Other link rates aren't supported */ return -EINVAL; } - writel(phy_vco_div, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_VCO_DIV); + writel(phy_vco_div, qmp->dp_dp_phy + cfg->regs[QPHY_DP_PHY_VCO_DIV]); clk_set_rate(qmp->dp_link_hw.clk, dp_opts->link_rate * 100000); clk_set_rate(qmp->dp_pixel_hw.clk, pixel_freq); @@ -2370,7 +2595,7 @@ static int qmp_v456_configure_dp_phy(struct qmp_combo *qmp) u32 status; int ret; - writel(0x0f, qmp->dp_dp_phy + QSERDES_V4_DP_PHY_CFG_1); + writel(0x0f, qmp->dp_dp_phy + QSERDES_DP_PHY_CFG_1); qmp_combo_configure_dp_mode(qmp); @@ -2492,8 +2717,6 @@ static int qmp_v4_configure_dp_phy(struct qmp_combo *qmp) writel(0x20, qmp->dp_tx2 + cfg->regs[QPHY_TX_TX_EMP_POST1_LVL]); return 0; - - return 0; } /* @@ -2681,8 +2904,8 @@ static int qmp_combo_dp_power_on(struct phy *phy) qmp_combo_dp_serdes_init(qmp); - qmp_combo_configure_lane(tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1); - qmp_combo_configure_lane(tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2); + qmp_configure_lane(qmp->dev, tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1); + qmp_configure_lane(qmp->dev, tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2); /* Configure special DP tx tunings */ cfg->configure_dp_tx(qmp); @@ -2724,7 +2947,7 @@ static int qmp_combo_usb_power_on(struct phy *phy) unsigned int val; int ret; - qmp_combo_configure(serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl, cfg->serdes_tbl_num); ret = clk_prepare_enable(qmp->pipe_clk); if (ret) { @@ -2733,16 +2956,17 @@ static int qmp_combo_usb_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qmp_combo_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); - qmp_combo_configure_lane(tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); + qmp_configure_lane(qmp->dev, tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_configure_lane(qmp->dev, tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); - qmp_combo_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - qmp_combo_configure_lane(rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); + qmp_configure_lane(qmp->dev, rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_configure_lane(qmp->dev, rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); - qmp_combo_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_configure(qmp->dev, pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); if (pcs_usb) - qmp_combo_configure(pcs_usb, cfg->pcs_usb_tbl, cfg->pcs_usb_tbl_num); + qmp_configure(qmp->dev, pcs_usb, cfg->pcs_usb_tbl, + cfg->pcs_usb_tbl_num); if (cfg->has_pwrdn_delay) usleep_range(10, 20); @@ -3355,7 +3579,7 @@ static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) } #endif -static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_node *np) +static int qmp_combo_parse_dt_legacy_dp(struct qmp_combo *qmp, struct device_node *np) { struct device *dev = qmp->dev; @@ -3382,7 +3606,7 @@ static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_nod return 0; } -static int qmp_combo_parse_dt_lecacy_usb(struct qmp_combo *qmp, struct device_node *np) +static int qmp_combo_parse_dt_legacy_usb(struct qmp_combo *qmp, struct device_node *np) { const struct qmp_phy_cfg *cfg = qmp->cfg; struct device *dev = qmp->dev; @@ -3448,11 +3672,11 @@ static int qmp_combo_parse_dt_legacy(struct qmp_combo *qmp, struct device_node * if (IS_ERR(qmp->dp_serdes)) return PTR_ERR(qmp->dp_serdes); - ret = qmp_combo_parse_dt_lecacy_usb(qmp, usb_np); + ret = qmp_combo_parse_dt_legacy_usb(qmp, usb_np); if (ret) return ret; - ret = qmp_combo_parse_dt_lecacy_dp(qmp, dp_np); + ret = qmp_combo_parse_dt_legacy_dp(qmp, dp_np); if (ret) return ret; @@ -3515,7 +3739,7 @@ static int qmp_combo_parse_dt(struct qmp_combo *qmp) return 0; } -static struct phy *qmp_combo_phy_xlate(struct device *dev, struct of_phandle_args *args) +static struct phy *qmp_combo_phy_xlate(struct device *dev, const struct of_phandle_args *args) { struct qmp_combo *qmp = dev_get_drvdata(dev); @@ -3545,6 +3769,7 @@ static int qmp_combo_probe(struct platform_device *pdev) return -ENOMEM; qmp->dev = dev; + dev_set_drvdata(dev, qmp); qmp->orientation = TYPEC_ORIENTATION_NORMAL; @@ -3562,14 +3787,6 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) return ret; - ret = qmp_combo_typec_switch_register(qmp); - if (ret) - return ret; - - ret = drm_aux_bridge_register(dev); - if (ret) - return ret; - /* Check for legacy binding with child nodes. */ usb_np = of_get_child_by_name(dev->of_node, "usb3-phy"); if (usb_np) { @@ -3589,6 +3806,14 @@ static int qmp_combo_probe(struct platform_device *pdev) if (ret) goto err_node_put; + ret = qmp_combo_typec_switch_register(qmp); + if (ret) + goto err_node_put; + + ret = drm_aux_bridge_register(dev); + if (ret) + goto err_node_put; + pm_runtime_set_active(dev); ret = devm_pm_runtime_enable(dev); if (ret) @@ -3621,8 +3846,6 @@ static int qmp_combo_probe(struct platform_device *pdev) phy_set_drvdata(qmp->dp_phy, qmp); - dev_set_drvdata(dev, qmp); - if (usb_np == dev->of_node) phy_provider = devm_of_phy_provider_register(dev, qmp_combo_phy_xlate); else @@ -3641,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, }, @@ -3686,7 +3913,7 @@ static const struct of_device_id qmp_combo_of_match_table[] = { }, { .compatible = "qcom,sm8650-qmp-usb3-dp-phy", - .data = &sm8550_usb3dpphy_cfg, + .data = &sm8650_usb3dpphy_cfg, }, { .compatible = "qcom,x1e80100-qmp-usb3-dp-phy", diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-common.h b/drivers/phy/qualcomm/phy-qcom-qmp-common.h new file mode 100644 index 000000000000..b945fc14cece --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-common.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_COMMON_H_ +#define QCOM_PHY_QMP_COMMON_H_ + +struct qmp_phy_init_tbl { + unsigned int offset; + unsigned int val; + char *name; + /* + * mask of lanes for which this register is written + * for cases when second lane needs different values + */ + u8 lane_mask; +}; + +#define QMP_PHY_INIT_CFG(o, v) \ + { \ + .offset = o, \ + .val = v, \ + .name = #o, \ + .lane_mask = 0xff, \ + } + +#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ + { \ + .offset = o, \ + .val = v, \ + .name = #o, \ + .lane_mask = l, \ + } + +static inline void qmp_configure_lane(struct device *dev, void __iomem *base, + const struct qmp_phy_init_tbl tbl[], + int num, u8 lane_mask) +{ + int i; + const struct qmp_phy_init_tbl *t = tbl; + + if (!t) + return; + + for (i = 0; i < num; i++, t++) { + if (!(t->lane_mask & lane_mask)) + continue; + + dev_dbg(dev, "Writing Reg: %s Offset: 0x%04x Val: 0x%02x\n", + t->name, t->offset, t->val); + writel(t->val, base + t->offset); + } +} + +static inline void qmp_configure(struct device *dev, void __iomem *base, + const struct qmp_phy_init_tbl tbl[], int num) +{ + qmp_configure_lane(dev, base, tbl, num, 0xff); +} + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-com-v3.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-com-v3.h new file mode 100644 index 000000000000..396179ef38b0 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-com-v3.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_COM_V3_H_ +#define QCOM_PHY_QMP_DP_COM_V3_H_ + +/* Only for QMP V3 & V4 PHY - DP COM registers */ +#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00 +#define QPHY_V3_DP_COM_SW_RESET 0x04 +#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08 +#define QPHY_V3_DP_COM_SWI_CTRL 0x0c +#define QPHY_V3_DP_COM_TYPEC_CTRL 0x10 +#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL 0x14 +#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v3.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v3.h new file mode 100644 index 000000000000..00a9702abccd --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v3.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V3_H_ +#define QCOM_PHY_QMP_DP_PHY_V3_H_ + +/* Only for QMP V3 PHY - DP PHY registers */ +#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK 0x048 +#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_CLEAR 0x04c +#define QSERDES_V3_DP_PHY_AUX_BIST_CFG 0x050 + +#define QSERDES_V3_DP_PHY_VCO_DIV 0x064 +#define QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL 0x06c +#define QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL 0x088 + +#define QSERDES_V3_DP_PHY_SPARE0 0x0ac +#define QSERDES_V3_DP_PHY_STATUS 0x0c0 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v4.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v4.h new file mode 100644 index 000000000000..ed6795e1257c --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v4.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V4_H_ +#define QCOM_PHY_QMP_DP_PHY_V4_H_ + +/* Only for QMP V4 PHY - DP PHY registers */ +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK 0x054 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_CLEAR 0x058 +#define QSERDES_V4_DP_PHY_VCO_DIV 0x070 +#define QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL 0x078 +#define QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL 0x09c +#define QSERDES_V4_DP_PHY_SPARE0 0x0c8 +#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8 +#define QSERDES_V4_DP_PHY_STATUS 0x0dc + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v5.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v5.h new file mode 100644 index 000000000000..181057421c11 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v5.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V5_H_ +#define QCOM_PHY_QMP_DP_PHY_V5_H_ + +/* Only for QMP V5 PHY - DP PHY registers */ +#define QSERDES_V5_DP_PHY_VCO_DIV 0x070 +#define QSERDES_V5_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8 +#define QSERDES_V5_DP_PHY_STATUS 0x0dc + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v6.h new file mode 100644 index 000000000000..fa967a1af058 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy-v6.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_V6_H_ +#define QCOM_PHY_QMP_DP_PHY_V6_H_ + +/* Only for QMP V6 PHY - DP PHY registers */ +#define QSERDES_V6_DP_PHY_VCO_DIV 0x070 +#define QSERDES_V6_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0 +#define QSERDES_V6_DP_PHY_STATUS 0x0e4 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h new file mode 100644 index 000000000000..0ebd405bcaf0 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-dp-phy.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_DP_PHY_H_ +#define QCOM_PHY_QMP_DP_PHY_H_ + +/* QMP PHY - DP PHY registers */ +#define QSERDES_DP_PHY_REVISION_ID0 0x000 +#define QSERDES_DP_PHY_REVISION_ID1 0x004 +#define QSERDES_DP_PHY_REVISION_ID2 0x008 +#define QSERDES_DP_PHY_REVISION_ID3 0x00c +#define QSERDES_DP_PHY_CFG 0x010 +#define QSERDES_DP_PHY_CFG_1 0x014 +#define QSERDES_DP_PHY_PD_CTL 0x018 +#define QSERDES_DP_PHY_MODE 0x01c +#define QSERDES_DP_PHY_AUX_CFG0 0x020 +#define QSERDES_DP_PHY_AUX_CFG1 0x024 +#define QSERDES_DP_PHY_AUX_CFG2 0x028 +#define QSERDES_DP_PHY_AUX_CFG3 0x02c +#define QSERDES_DP_PHY_AUX_CFG4 0x030 +#define QSERDES_DP_PHY_AUX_CFG5 0x034 +#define QSERDES_DP_PHY_AUX_CFG6 0x038 +#define QSERDES_DP_PHY_AUX_CFG7 0x03c +#define QSERDES_DP_PHY_AUX_CFG8 0x040 +#define QSERDES_DP_PHY_AUX_CFG9 0x044 + +/* QSERDES COM_BIAS_EN_CLKBUFLR_EN bits */ +# define QSERDES_V3_COM_BIAS_EN 0x0001 +# define QSERDES_V3_COM_BIAS_EN_MUX 0x0002 +# define QSERDES_V3_COM_CLKBUF_R_EN 0x0004 +# define QSERDES_V3_COM_CLKBUF_L_EN 0x0008 +# define QSERDES_V3_COM_EN_SYSCLK_TX_SEL 0x0010 +# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_L 0x0020 +# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_R 0x0040 + +/* QPHY_TX_TX_EMP_POST1_LVL bits */ +# define DP_PHY_TXn_TX_EMP_POST1_LVL_MASK 0x001f +# define DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN 0x0020 + +/* QPHY_TX_TX_DRV_LVL bits */ +# define DP_PHY_TXn_TX_DRV_LVL_MASK 0x001f +# define DP_PHY_TXn_TX_DRV_LVL_MUX_EN 0x0020 + +/* QSERDES_DP_PHY_PD_CTL bits */ +# define DP_PHY_PD_CTL_PWRDN 0x001 +# define DP_PHY_PD_CTL_PSR_PWRDN 0x002 +# define DP_PHY_PD_CTL_AUX_PWRDN 0x004 +# define DP_PHY_PD_CTL_LANE_0_1_PWRDN 0x008 +# define DP_PHY_PD_CTL_LANE_2_3_PWRDN 0x010 +# define DP_PHY_PD_CTL_PLL_PWRDN 0x020 +# define DP_PHY_PD_CTL_DP_CLAMP_EN 0x040 + +/* QPHY_DP_PHY_AUX_INTERRUPT_STATUS bits */ +# define PHY_AUX_STOP_ERR_MASK 0x01 +# define PHY_AUX_DEC_ERR_MASK 0x02 +# define PHY_AUX_SYNC_ERR_MASK 0x04 +# define PHY_AUX_ALIGN_ERR_MASK 0x08 +# define PHY_AUX_REQ_ERR_MASK 0x10 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c index ab61a9c73b18..a7c65cfe31df 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie-msm8996.c @@ -19,19 +19,13 @@ #include <linux/reset.h> #include <linux/slab.h> +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" -/* QPHY_SW_RESET bit */ -#define SW_RESET BIT(0) -/* QPHY_POWER_DOWN_CONTROL */ -#define SW_PWRDN BIT(0) -#define REFCLK_DRV_DSBL BIT(1) /* QPHY_START_CONTROL bits */ -#define SERDES_START BIT(0) -#define PCS_START BIT(1) #define PLL_READY_GATE_EN BIT(3) -/* QPHY_PCS_STATUS bit */ -#define PHYSTATUS BIT(6) + /* QPHY_COM_PCS_READY_STATUS bit */ #define PCS_READY BIT(0) @@ -39,30 +33,6 @@ #define POWER_DOWN_DELAY_US_MIN 10 #define POWER_DOWN_DELAY_US_MAX 20 -struct qmp_phy_init_tbl { - unsigned int offset; - unsigned int val; - /* - * mask of lanes for which this register is written - * for cases when second lane needs different values - */ - u8 lane_mask; -}; - -#define QMP_PHY_INIT_CFG(o, v) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = 0xff, \ - } - -#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = l, \ - } - /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { /* Common block control registers */ @@ -307,32 +277,6 @@ static const struct qmp_phy_cfg msm8996_pciephy_cfg = { .regs = pciephy_regs_layout, }; -static void qmp_pcie_msm8996_configure_lane(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num, - u8 lane_mask) -{ - int i; - const struct qmp_phy_init_tbl *t = tbl; - - if (!t) - return; - - for (i = 0; i < num; i++, t++) { - if (!(t->lane_mask & lane_mask)) - continue; - - writel(t->val, base + t->offset); - } -} - -static void qmp_pcie_msm8996_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_pcie_msm8996_configure_lane(base, tbl, num, 0xff); -} - static int qmp_pcie_msm8996_serdes_init(struct qmp_phy *qphy) { struct qcom_qmp *qmp = qphy->qmp; @@ -344,7 +288,7 @@ static int qmp_pcie_msm8996_serdes_init(struct qmp_phy *qphy) unsigned int val; int ret; - qmp_pcie_msm8996_configure(serdes, serdes_tbl, serdes_tbl_num); + qmp_configure(qmp->dev, serdes, serdes_tbl, serdes_tbl_num); qphy_clrbits(serdes, cfg->regs[QPHY_COM_SW_RESET], SW_RESET); qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL], @@ -487,9 +431,9 @@ static int qmp_pcie_msm8996_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qmp_pcie_msm8996_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); - qmp_pcie_msm8996_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - qmp_pcie_msm8996_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_configure_lane(qmp->dev, tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_configure_lane(qmp->dev, rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + qmp_configure(qmp->dev, pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); /* * Pull out PHY from POWER DOWN state. @@ -781,7 +725,6 @@ static int qmp_pcie_msm8996_probe(struct platform_device *pdev) { struct qcom_qmp *qmp; struct device *dev = &pdev->dev; - struct device_node *child; struct phy_provider *phy_provider; void __iomem *serdes; const struct qmp_phy_cfg *cfg = NULL; @@ -829,13 +772,13 @@ static int qmp_pcie_msm8996_probe(struct platform_device *pdev) return -ENOMEM; id = 0; - for_each_available_child_of_node(dev->of_node, child) { + for_each_available_child_of_node_scoped(dev->of_node, child) { /* Create per-lane phy */ ret = qmp_pcie_msm8996_create(dev, child, id, serdes, cfg); if (ret) { dev_err(dev, "failed to create lane%d phy, %d\n", id, ret); - goto err_node_put; + return ret; } /* @@ -846,7 +789,7 @@ static int qmp_pcie_msm8996_probe(struct platform_device *pdev) if (ret) { dev_err(qmp->dev, "failed to register pipe clock source\n"); - goto err_node_put; + return ret; } id++; @@ -855,10 +798,6 @@ static int qmp_pcie_msm8996_probe(struct platform_device *pdev) phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); return PTR_ERR_OR_ZERO(phy_provider); - -err_node_put: - of_node_put(child); - return ret; } static struct platform_driver qmp_pcie_msm8996_driver = { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c index 2af7115ef968..461b9e0af610 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c @@ -22,6 +22,10 @@ #include <linux/reset.h> #include <linux/slab.h> +#include <dt-bindings/phy/phy-qcom-qmp.h> + +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" #include "phy-qcom-qmp-pcs-pcie-v4.h" @@ -30,46 +34,12 @@ #include "phy-qcom-qmp-pcs-pcie-v5_20.h" #include "phy-qcom-qmp-pcs-pcie-v6.h" #include "phy-qcom-qmp-pcs-pcie-v6_20.h" +#include "phy-qcom-qmp-pcs-pcie-v6_30.h" +#include "phy-qcom-qmp-pcs-v6_30.h" #include "phy-qcom-qmp-pcie-qhp.h" -/* QPHY_SW_RESET bit */ -#define SW_RESET BIT(0) -/* QPHY_POWER_DOWN_CONTROL */ -#define SW_PWRDN BIT(0) -#define REFCLK_DRV_DSBL BIT(1) -/* QPHY_START_CONTROL bits */ -#define SERDES_START BIT(0) -#define PCS_START BIT(1) -/* QPHY_PCS_STATUS bit */ -#define PHYSTATUS BIT(6) -#define PHYSTATUS_4_20 BIT(7) - #define PHY_INIT_COMPLETE_TIMEOUT 10000 -struct qmp_phy_init_tbl { - unsigned int offset; - unsigned int val; - /* - * mask of lanes for which this register is written - * for cases when second lane needs different values - */ - u8 lane_mask; -}; - -#define QMP_PHY_INIT_CFG(o, v) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = 0xff, \ - } - -#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = l, \ - } - /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { /* PCS registers */ @@ -116,6 +86,13 @@ static const unsigned int pciephy_v5_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V5_PCS_POWER_DOWN_CONTROL, }; +static const unsigned int pciephy_v6_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V6_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V6_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V6_PCS_PCS_STATUS1, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V6_PCS_POWER_DOWN_CONTROL, +}; + static const struct qmp_phy_init_tbl msm8998_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), @@ -514,6 +491,372 @@ static const struct qmp_phy_init_tbl ipq8074_pcie_gen3_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1), }; +static const struct qmp_phy_init_tbl ipq9574_gen3x1_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CLKBUFLR_EN, 0x18), + QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CTRL_BY_PSM, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_SELECT, 0x31), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_PLL_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP_EN, 0x42), + QMP_PHY_INIT_CFG(QSERDES_PLL_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_TIMER2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x30), + QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x21), + QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE0, 0x68), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE0, 0xd4), + QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE0, 0x09), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE0, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x20), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_SELECT, 0x32), + QMP_PHY_INIT_CFG(QSERDES_PLL_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_BUF_ENABLE, 0x07), + QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE1, 0x53), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE1, 0x29), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE1, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE1, 0x09), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE1, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE1, 0xb4), + QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV_MODE1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER1, 0x7d), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE0, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_EP_DIV_MODE0, 0x19), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_EP_DIV_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x89), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x10), +}; + +static const struct qmp_phy_init_tbl ipq9574_gen3x2_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CLKBUFLR_EN, 0x18), + QMP_PHY_INIT_CFG(QSERDES_PLL_BIAS_EN_CTRL_BY_PSM, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_SELECT, 0x31), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_PLL_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP_EN, 0x42), + QMP_PHY_INIT_CFG(QSERDES_PLL_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE_TIMER2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x30), + QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x21), + QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE0, 0x68), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE0, 0xd4), + QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE0, 0x09), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE0, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_SELECT, 0x32), + QMP_PHY_INIT_CFG(QSERDES_PLL_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_BUF_ENABLE, 0x07), + QMP_PHY_INIT_CFG(QSERDES_PLL_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_PLL_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_DEC_START_MODE1, 0x53), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START3_MODE1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START2_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_PLL_DIV_FRAC_START1_MODE1, 0x55), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP2_MODE1, 0x29), + QMP_PHY_INIT_CFG(QSERDES_PLL_LOCK_CMP1_MODE1, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_PLL_CP_CTRL_MODE1, 0x09), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_PLL_PLL_CCTRL_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_INTEGLOOP_GAIN0_MODE1, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE2_MODE1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_PLL_VCO_TUNE1_MODE1, 0xb4), + QMP_PHY_INIT_CFG(QSERDES_PLL_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_CORECLK_DIV_MODE1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER1, 0x7d), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE0, 0x05), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE1_MODE1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_PLL_SSC_STEP_SIZE2_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_EP_DIV_MODE0, 0x19), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_EP_DIV_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x90), + QMP_PHY_INIT_CFG(QSERDES_PLL_HSCLK_SEL, 0x89), + QMP_PHY_INIT_CFG(QSERDES_PLL_CLK_ENABLE1, 0x10), +}; + +static const struct qmp_phy_init_tbl ipq9574_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x61), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FO_GAIN, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x70), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL1, 0x73), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_LOW, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH2, 0xc8), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH3, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH4, 0xb1), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0xc8), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0xb1), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0xf0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0xd3), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0), +}; + +static const struct qmp_phy_init_tbl ipq9574_gen3x1_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 0x01), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_DCC_CAL_CONFIG, 0x01), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB, 0x10), +}; + +static const struct qmp_phy_init_tbl ipq9574_gen3x1_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_POWER_STATE_CONFIG2, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L, 0x01), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L, 0x01), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_EQ_CONFIG1, 0x14), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_EQ_CONFIG1, 0x10), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_EQ_CONFIG2, 0x0b), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_PRE, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_POST, 0x58), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_POWER_STATE_CONFIG4, 0x07), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_CONFIG2, 0x52), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_INT_AUX_CLK_CONFIG1, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2, 0x50), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4, 0x1a), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5, 0x06), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_MODE2_CONFIG6, 0x03), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1), +}; + +static const struct qmp_phy_init_tbl ipq9574_gen3x2_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_G12S1_TXDEEMPH_M3P5DB, 0x10), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 0x01), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_DCC_CAL_CONFIG, 0x01), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa), +}; + +static const struct qmp_phy_init_tbl ipq9574_gen3x2_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG2, 0x1d), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L, 0x01), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L, 0x01), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_EQ_CONFIG1, 0x14), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_EQ_CONFIG1, 0x10), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_EQ_CONFIG2, 0x0b), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_PRESET_P10_PRE, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_PRESET_P10_POST, 0x58), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG4, 0x07), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG1, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG2, 0x52), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG4, 0x19), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_INT_AUX_CLK_CONFIG1, 0x00), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2, 0x49), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4, 0x2a), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5, 0x02), + QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG6, 0x03), + 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), @@ -982,6 +1325,304 @@ static const struct qmp_phy_init_tbl sc8280xp_qmp_gen3x2_pcie_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V5_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), }; +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0x26), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06), + 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, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x68), + 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_HSCLK_SEL_1, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0xf8), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), + 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_PLL_CORE_CLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x62), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_POST_DIV_MUX, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, 0x14), + 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, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x46), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x04), + 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_CORE_CLK_EN, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MISC_1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MODE, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_VCO_DC_LEVEL_CTRL, 0x0f), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x4_pcie_serdes_4ln_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, 0x1c), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_ln_shrd_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RXCLK_DIV2_CTRL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_DFE_DAC_ENABLE1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B0, 0xd4), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B1, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B2, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B3, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B4, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B5, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B6, 0x64), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH4_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH5_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH6_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_SUMMER_CAL_SPD_MODE, 0x5b), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_TX, 0x1d), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_RX, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_2, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_3, 0x51), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_TRAN_DRVR_EMP_EN, 0x34), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_GAIN_RATE_2, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_3, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_PI_CONTROLS, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE3, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_CAL_CTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_POSTCAL_OFFSET, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_BKUP_CTRL1, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_3, 0x45), + QMP_PHY_INIT_CFG_LANE(QSERDES_V6_20_RX_VGA_CAL_MAN_VAL, 0x0a, 1), + QMP_PHY_INIT_CFG_LANE(QSERDES_V6_20_RX_VGA_CAL_MAN_VAL, 0x0b, 2), + QMP_PHY_INIT_CFG(QSERDES_V6_20_VGA_CAL_CNTRL1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_GM_CAL, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_PHPRE_CTRL, 0x20), + QMP_PHY_INIT_CFG_LANE(QSERDES_V6_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x3a, 1), + QMP_PHY_INIT_CFG_LANE(QSERDES_V6_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38, 2), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x39), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B1, 0xb3), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B2, 0x58), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B3, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B4, 0x26), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B5, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B6, 0xee), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B0, 0xe4), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B1, 0xa4), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B2, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B3, 0xdf), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B4, 0x4b), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B5, 0x76), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_TX_ADPT_CTRL, 0x10), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_G3S2_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_RX_SIGDET_LVL, 0xcc), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG4, 0x00), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG5, 0x22), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_TX_RX_CONFIG1, 0x04), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_TX_RX_CONFIG2, 0x02), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x2_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_ENDPOINT_REFCLK_DRIVE, 0xc1), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_OSC_DTCT_ATCIONS, 0x00), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG1, 0x16), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG5, 0x02), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG1, 0x03), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG3, 0x28), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G3_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_TX_RX_CONFIG, 0xc0), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_POWER_STATE_CONFIG2, 0x1d), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG5, 0x18), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G3_FOM_EQ_CONFIG5, 0x7a), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_FOM_EQ_CONFIG5, 0x8a), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE1, 0x26), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x06), + 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, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x68), + 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_HSCLK_SEL_1, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE1_MODE0, 0xf8), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_STEP_SIZE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), + 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_PLL_CORE_CLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START2_MODE0, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DIV_FRAC_START3_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_HSCLK_HS_SWITCH_SEL_1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER1, 0x62), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SSC_PER2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_POST_DIV_MUX, 0x40), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_BIAS_EN_CLK_BUFLR_EN, 0x1c), + 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, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_EN, 0x46), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP_CFG, 0x04), + 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_CORE_CLK_EN, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_CONFIG_1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MISC_1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_MODE, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_VCO_DC_LEVEL_CTRL, 0x0f), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_ln_shrd_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RXCLK_DIV2_CTRL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_SUMMER_CAL_SPD_MODE, 0x5b), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_DFE_DAC_ENABLE1, 0x88), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B0, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B1, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B2, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B3, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B4, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B5, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B6, 0x64), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH1_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH2_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE210, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH3_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH4_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH5_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH6_RATE3, 0x1f), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_txz_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_TX, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_RES_CODE_LANE_OFFSET_RX, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_1, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_2, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_LANE_MODE_3, 0x51), + QMP_PHY_INIT_CFG(QSERDES_V6_20_TX_TRAN_DRVR_EMP_EN, 0x34), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_rxz_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_GAIN_RATE_2, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_3, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_PI_CONTROLS, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE3, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_CAL_CTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_POSTCAL_OFFSET, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_BKUP_CTRL1, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_3, 0x45), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_VGA_CAL_MAN_VAL, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_VGA_CAL_CNTRL1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_GM_CAL, 0x0d), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_PHPRE_CTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_Q_PI_INTRINSIC_BIAS_RATE32, 0x39), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B0, 0xd4), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B1, 0x23), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B2, 0x58), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B3, 0x9a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B4, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B5, 0xb6), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE2_B6, 0xee), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B0, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B1, 0xe4), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B2, 0x60), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B3, 0xdf), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B4, 0x69), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B5, 0x76), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_TX_ADPT_CTRL, 0x10), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG_LANE(QSERDES_V6_20_RX_DFE_CTLE_POST_CAL_OFFSET, 0x3a, BIT(0)), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_LOCK_DETECT_CONFIG2, 0x00), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_G3S2_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_RX_SIGDET_LVL, 0x99), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_ALIGN_DETECT_CONFIG7, 0x00), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_EQ_CONFIG4, 0x00), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_EQ_CONFIG5, 0x22), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_TX_RX_CONFIG, 0x04), + QMP_PHY_INIT_CFG(QPHY_V6_30_PCS_TX_RX_CONFIG2, 0x02), +}; + +static const struct qmp_phy_init_tbl x1e80100_qmp_gen4x8_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_ENDPOINT_REFCLK_DRIVE, 0xc1), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_OSC_DTCT_ACTIONS, 0x00), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_EQ_CONFIG1, 0x16), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G4_EQ_CONFIG5, 0x02), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G4_PRE_GAIN, 0x2e), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG1, 0x03), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG3, 0x28), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG5, 0x18), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G3_FOM_EQ_CONFIG5, 0x7a), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G4_FOM_EQ_CONFIG5, 0x8a), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G3_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_G4_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_TX_RX_CONFIG, 0xc0), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_30_PCS_POWER_STATE_CONFIG2, 0x1d), +}; + static const struct qmp_phy_init_tbl sm8250_qmp_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08), QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34), @@ -1261,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), }; @@ -1395,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), }; @@ -1747,7 +2391,7 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH2, 0x5b), QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH3, 0x1a), QMP_PHY_INIT_CFG(QSERDES_V6_RX_RX_MODE_10_HIGH4, 0x89), - QMP_PHY_INIT_CFG(QSERDES_V6_RX_TX_ADAPT_POST_THRESH, 0xf0), + QMP_PHY_INIT_CFG(QSERDES_V6_RX_TX_ADAPT_POST_THRESH, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_FO_GAIN, 0x09), QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SO_GAIN, 0x05), QMP_PHY_INIT_CFG(QSERDES_V6_RX_UCDR_SB2_THRESH1, 0x08), @@ -1767,6 +2411,8 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_pcs_tbl[] = { }; static const struct qmp_phy_init_tbl sm8550_qmp_gen3x2_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_EQ_CONFIG1, 0x1e), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_RXEQEVAL_TIME, 0x27), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2, 0x1d), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4, 0x07), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1), @@ -1823,10 +2469,9 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_serdes_tbl[] = { static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_ln_shrd_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RXCLK_DIV2_CTRL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_Q_EN_RATES, 0xe), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_DFE_DAC_ENABLE1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_TX_ADAPT_POST_THRESH2, 0x0d), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B0, 0x12), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B1, 0x12), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MODE_RATE_0_1_B2, 0xdb), @@ -1843,6 +2488,7 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_ln_shrd_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH4_RATE3, 0x1f), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH5_RATE3, 0x1f), QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_MARG_COARSE_THRESH6_RATE3, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_LN_SHRD_RX_SUMMER_CAL_SPD_MODE, 0x5b), }; static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_tx_tbl[] = { @@ -1855,13 +2501,15 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_tx_tbl[] = { }; static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_2, 0x0c), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_FO_GAIN_RATE_3, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_GAIN_RATE_2, 0x04), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_PI_CONTROLS, 0x16), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_UCDR_SO_ACC_DEFAULT_VAL_RATE3, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_CAL_CTRL2, 0x80), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_IVCM_POSTCAL_OFFSET, 0x7c), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_DFE_3, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_TX_ADPT_CTRL, 0x10), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_VGA_CAL_MAN_VAL, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_GM_CAL, 0x0d), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4, 0x0b), @@ -1883,11 +2531,13 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B4, 0x78), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B5, 0x76), QMP_PHY_INIT_CFG(QSERDES_V6_20_RX_MODE_RATE3_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V6_20_VGA_CAL_CNTRL1, 0x00), }; static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_G12S1_TXDEEMPH_M6DB, 0x17), QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_G3S2_PRE_GAIN, 0x2e), - QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_COM_ELECIDLE_DLY_SEL, 0x25), + QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_RX_SIGDET_LVL, 0xcc), QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG4, 0x00), QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_EQ_CONFIG5, 0x22), QMP_PHY_INIT_CFG(QPHY_V6_20_PCS_TX_RX_CONFIG1, 0x04), @@ -1898,6 +2548,8 @@ static const struct qmp_phy_init_tbl sm8550_qmp_gen4x2_pcie_pcs_misc_tbl[] = { QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_ENDPOINT_REFCLK_DRIVE, 0xc1), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_OSC_DTCT_ATCIONS, 0x00), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG1, 0x16), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G3_RXEQEVAL_TIME, 0x27), + QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_RXEQEVAL_TIME, 0x27), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_EQ_CONFIG5, 0x02), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_G4_PRE_GAIN, 0x2e), QMP_PHY_INIT_CFG(QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG1, 0x03), @@ -2062,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), }; @@ -2128,6 +2778,7 @@ static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x4_pcie_pcs_alt_tbl[] = { }; static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x4_pcie_serdes_alt_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x1c), QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_IVCO, 0x0f), QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36), QMP_PHY_INIT_CFG(QSERDES_V5_COM_PLL_CCTRL_MODE1, 0x36), @@ -2154,7 +2805,6 @@ static const struct qmp_phy_init_tbl sa8775p_qmp_gen4x4_pcie_rc_serdes_alt_tbl[] QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE0, 0x07), QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE1_MODE1, 0x97), QMP_PHY_INIT_CFG(QSERDES_V5_COM_SSC_STEP_SIZE2_MODE1, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIAS_EN_CLKBUFLR_EN, 0x1c), QMP_PHY_INIT_CFG(QSERDES_V5_COM_CLK_ENABLE1, 0x90), QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE0, 0x06), QMP_PHY_INIT_CFG(QSERDES_V5_COM_CP_CTRL_MODE1, 0x06), @@ -2204,14 +2854,112 @@ 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; u16 rx2; + u16 txz; + u16 rxz; u16 ln_shrd; }; @@ -2222,10 +2970,16 @@ struct qmp_phy_cfg_tbls { int tx_num; const struct qmp_phy_init_tbl *rx; int rx_num; + const struct qmp_phy_init_tbl *txz; + int txz_num; + const struct qmp_phy_init_tbl *rxz; + int rxz_num; const struct qmp_phy_init_tbl *pcs; 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; }; @@ -2267,10 +3021,11 @@ struct qmp_phy_cfg { bool skip_start_delay; - bool has_nocsr_reset; - /* QMP PHY pipe clock interface rate */ unsigned long pipe_clock_rate; + + /* QMP PHY AUX clock interface rate */ + unsigned long aux_clock_rate; }; struct qmp_pcie { @@ -2278,14 +3033,18 @@ struct qmp_pcie { const struct qmp_phy_cfg *cfg; bool tcsr_4ln_config; + bool skip_init; void __iomem *serdes; void __iomem *pcs; void __iomem *pcs_misc; + void __iomem *pcs_lane1; void __iomem *tx; void __iomem *rx; void __iomem *tx2; void __iomem *rx2; + void __iomem *txz; + void __iomem *rxz; void __iomem *ln_shrd; void __iomem *port_b; @@ -2302,6 +3061,7 @@ struct qmp_pcie { int mode; struct clk_fixed_rate pipe_clk_fixed; + struct clk_fixed_rate aux_clk_fixed; }; static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) @@ -2395,6 +3155,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, @@ -2411,10 +3172,21 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v5 = { .rx2 = 0x1800, }; +static const struct qmp_pcie_offsets qmp_pcie_offsets_ipq9574 = { + .serdes = 0, + .pcs = 0x1000, + .pcs_misc = 0x1400, + .tx = 0x0200, + .rx = 0x0400, + .tx2 = 0x0600, + .rx2 = 0x0800, +}; + 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, @@ -2442,6 +3214,17 @@ static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_20 = { .ln_shrd = 0x0e00, }; +static const struct qmp_pcie_offsets qmp_pcie_offsets_v6_30 = { + .serdes = 0x8800, + .pcs = 0x9000, + .pcs_misc = 0x9800, + .tx = 0x0000, + .rx = 0x0200, + .txz = 0xe000, + .rxz = 0xe200, + .ln_shrd = 0x8000, +}; + static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { .lanes = 1, @@ -2523,6 +3306,121 @@ static const struct qmp_phy_cfg ipq6018_pciephy_cfg = { .phy_status = PHYSTATUS, }; +static const struct qmp_phy_cfg ipq9574_gen3x1_pciephy_cfg = { + .lanes = 1, + + .offsets = &qmp_pcie_offsets_v4x1, + + .tbls = { + .serdes = ipq9574_gen3x1_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(ipq9574_gen3x1_pcie_serdes_tbl), + .tx = ipq8074_pcie_gen3_tx_tbl, + .tx_num = ARRAY_SIZE(ipq8074_pcie_gen3_tx_tbl), + .rx = ipq9574_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(ipq9574_pcie_rx_tbl), + .pcs = ipq9574_gen3x1_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(ipq9574_gen3x1_pcie_pcs_tbl), + .pcs_misc = ipq9574_gen3x1_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(ipq9574_gen3x1_pcie_pcs_misc_tbl), + }, + .reset_list = ipq8074_pciephy_reset_l, + .num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l), + .vreg_list = NULL, + .num_vregs = 0, + .regs = pciephy_v4_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS, + .pipe_clock_rate = 250000000, +}; + +static const struct qmp_phy_cfg ipq9574_gen3x2_pciephy_cfg = { + .lanes = 2, + + .offsets = &qmp_pcie_offsets_ipq9574, + + .tbls = { + .serdes = ipq9574_gen3x2_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(ipq9574_gen3x2_pcie_serdes_tbl), + .tx = ipq8074_pcie_gen3_tx_tbl, + .tx_num = ARRAY_SIZE(ipq8074_pcie_gen3_tx_tbl), + .rx = ipq9574_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(ipq9574_pcie_rx_tbl), + .pcs = ipq9574_gen3x2_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(ipq9574_gen3x2_pcie_pcs_tbl), + .pcs_misc = ipq9574_gen3x2_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(ipq9574_gen3x2_pcie_pcs_misc_tbl), + }, + .reset_list = ipq8074_pciephy_reset_l, + .num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l), + .vreg_list = NULL, + .num_vregs = 0, + .regs = pciephy_v5_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS, + .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, @@ -2674,6 +3572,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, @@ -2831,8 +3772,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, @@ -2931,12 +3872,14 @@ 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), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = pciephy_v5_regs_layout, + .regs = pciephy_v6_regs_layout, .pwrdn_ctrl = SW_PWRDN, .phy_status = PHYSTATUS_4_20, @@ -3017,6 +3960,9 @@ static const struct qmp_phy_cfg sm8450_qmp_gen4x2_pciephy_cfg = { .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, + + /* 20MHz PHY AUX Clock */ + .aux_clock_rate = 20000000, }; static const struct qmp_phy_cfg sm8550_qmp_gen3x2_pciephy_cfg = { @@ -3069,11 +4015,13 @@ static const struct qmp_phy_cfg sm8550_qmp_gen4x2_pciephy_cfg = { .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), .vreg_list = sm8550_qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l), - .regs = pciephy_v5_regs_layout, + .regs = pciephy_v6_regs_layout, .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, - .has_nocsr_reset = true, + + /* 20MHz PHY AUX Clock */ + .aux_clock_rate = 20000000, }; static const struct qmp_phy_cfg sm8650_qmp_gen4x2_pciephy_cfg = { @@ -3099,11 +4047,13 @@ static const struct qmp_phy_cfg sm8650_qmp_gen4x2_pciephy_cfg = { .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), .vreg_list = sm8550_qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(sm8550_qmp_phy_vreg_l), - .regs = pciephy_v5_regs_layout, + .regs = pciephy_v6_regs_layout, .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, .phy_status = PHYSTATUS_4_20, - .has_nocsr_reset = true, + + /* 20MHz PHY AUX Clock */ + .aux_clock_rate = 20000000, }; static const struct qmp_phy_cfg sa8775p_qmp_gen4x2_pciephy_cfg = { @@ -3121,6 +4071,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) { @@ -3173,6 +4125,13 @@ static const struct qmp_phy_cfg sa8775p_qmp_gen4x4_pciephy_cfg = { .pcs_misc_num = ARRAY_SIZE(sa8775p_qmp_gen4_pcie_rc_pcs_misc_tbl), }, + .tbls_ep = &(const struct qmp_phy_cfg_tbls) { + .serdes = sa8775p_qmp_gen4x2_pcie_ep_serdes_alt_tbl, + .serdes_num = ARRAY_SIZE(sa8775p_qmp_gen4x2_pcie_ep_serdes_alt_tbl), + .pcs_misc = sm8450_qmp_gen4x2_pcie_ep_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(sm8450_qmp_gen4x2_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, @@ -3183,48 +4142,143 @@ static const struct qmp_phy_cfg sa8775p_qmp_gen4x4_pciephy_cfg = { .phy_status = PHYSTATUS_4_20, }; -static void qmp_pcie_configure_lane(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num, - u8 lane_mask) -{ - int i; - const struct qmp_phy_init_tbl *t = tbl; +static const struct qmp_phy_cfg x1e80100_qmp_gen4x2_pciephy_cfg = { + .lanes = 2, - if (!t) - return; + .offsets = &qmp_pcie_offsets_v6_20, - for (i = 0; i < num; i++, t++) { - if (!(t->lane_mask & lane_mask)) - continue; + .tbls = { + .serdes = x1e80100_qmp_gen4x2_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_serdes_tbl), + .tx = x1e80100_qmp_gen4x2_pcie_tx_tbl, + .tx_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_tx_tbl), + .rx = x1e80100_qmp_gen4x2_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_rx_tbl), + .pcs = x1e80100_qmp_gen4x2_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_pcs_tbl), + .pcs_misc = x1e80100_qmp_gen4x2_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_pcs_misc_tbl), + .ln_shrd = x1e80100_qmp_gen4x2_pcie_ln_shrd_tbl, + .ln_shrd_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_ln_shrd_tbl), + }, - writel(t->val, base + t->offset); - } -} + .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, -static void qmp_pcie_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_pcie_configure_lane(base, tbl, num, 0xff); -} + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, +}; + +static const struct qmp_phy_cfg x1e80100_qmp_gen4x4_pciephy_cfg = { + .lanes = 4, + + .offsets = &qmp_pcie_offsets_v6_20, + + .tbls = { + .serdes = x1e80100_qmp_gen4x2_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_serdes_tbl), + .tx = x1e80100_qmp_gen4x2_pcie_tx_tbl, + .tx_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_tx_tbl), + .rx = x1e80100_qmp_gen4x2_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_rx_tbl), + .pcs = x1e80100_qmp_gen4x2_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_pcs_tbl), + .pcs_misc = x1e80100_qmp_gen4x2_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_pcs_misc_tbl), + .ln_shrd = x1e80100_qmp_gen4x2_pcie_ln_shrd_tbl, + .ln_shrd_num = ARRAY_SIZE(x1e80100_qmp_gen4x2_pcie_ln_shrd_tbl), + }, + + .serdes_4ln_tbl = x1e80100_qmp_gen4x4_pcie_serdes_4ln_tbl, + .serdes_4ln_num = ARRAY_SIZE(x1e80100_qmp_gen4x4_pcie_serdes_4ln_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_v6_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, +}; + +static const struct qmp_phy_cfg x1e80100_qmp_gen4x8_pciephy_cfg = { + .lanes = 8, + + .offsets = &qmp_pcie_offsets_v6_30, + .tbls = { + .serdes = x1e80100_qmp_gen4x8_pcie_serdes_tbl, + .serdes_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_serdes_tbl), + .rx = x1e80100_qmp_gen4x8_pcie_rx_tbl, + .rx_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_rx_tbl), + .txz = x1e80100_qmp_gen4x8_pcie_txz_tbl, + .txz_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_txz_tbl), + .rxz = x1e80100_qmp_gen4x8_pcie_rxz_tbl, + .rxz_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_rxz_tbl), + .pcs = x1e80100_qmp_gen4x8_pcie_pcs_tbl, + .pcs_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_pcs_tbl), + .pcs_misc = x1e80100_qmp_gen4x8_pcie_pcs_misc_tbl, + .pcs_misc_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_pcs_misc_tbl), + .ln_shrd = x1e80100_qmp_gen4x8_pcie_ln_shrd_tbl, + .ln_shrd_num = ARRAY_SIZE(x1e80100_qmp_gen4x8_pcie_ln_shrd_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_v6_regs_layout, + + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + .phy_status = PHYSTATUS_4_20, +}; + +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; const struct qmp_pcie_offsets *offs = cfg->offsets; - void __iomem *tx3, *rx3, *tx4, *rx4; + void __iomem *serdes, *tx3, *rx3, *tx4, *rx4, *pcs, *pcs_misc, *ln_shrd; + serdes = qmp->port_b + offs->serdes; tx3 = qmp->port_b + offs->tx; rx3 = qmp->port_b + offs->rx; tx4 = qmp->port_b + offs->tx2; rx4 = qmp->port_b + offs->rx2; + pcs = qmp->port_b + offs->pcs; + pcs_misc = qmp->port_b + offs->pcs_misc; + ln_shrd = qmp->port_b + offs->ln_shrd; + + qmp_configure(qmp->dev, serdes, tbls->serdes, tbls->serdes_num); + qmp_configure(qmp->dev, serdes, cfg->serdes_4ln_tbl, cfg->serdes_4ln_num); - qmp_pcie_configure_lane(tx3, tbls->tx, tbls->tx_num, 1); - qmp_pcie_configure_lane(rx3, tbls->rx, tbls->rx_num, 1); + qmp_configure_lane(qmp->dev, tx3, tbls->tx, tbls->tx_num, 1); + qmp_configure_lane(qmp->dev, rx3, tbls->rx, tbls->rx_num, 1); - qmp_pcie_configure_lane(tx4, tbls->tx, tbls->tx_num, 2); - qmp_pcie_configure_lane(rx4, tbls->rx, tbls->rx_num, 2); + qmp_configure_lane(qmp->dev, tx4, tbls->tx, tbls->tx_num, 2); + qmp_configure_lane(qmp->dev, rx4, tbls->rx, tbls->rx_num, 2); + + 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, ln_shrd, tbls->ln_shrd, tbls->ln_shrd_num); } static void qmp_pcie_init_registers(struct qmp_pcie *qmp, const struct qmp_phy_cfg_tbls *tbls) @@ -3237,48 +4291,78 @@ 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) return; - qmp_pcie_configure(serdes, tbls->serdes, tbls->serdes_num); + qmp_configure(qmp->dev, serdes, tbls->serdes, tbls->serdes_num); - qmp_pcie_configure_lane(tx, tbls->tx, tbls->tx_num, 1); - qmp_pcie_configure_lane(rx, tbls->rx, tbls->rx_num, 1); + /* + * Tx/Rx registers that require different settings than + * txz/rxz must be programmed after txz/rxz. + */ + qmp_configure(qmp->dev, qmp->txz, tbls->txz, tbls->txz_num); + qmp_configure(qmp->dev, qmp->rxz, tbls->rxz, tbls->rxz_num); + + qmp_configure_lane(qmp->dev, tx, tbls->tx, tbls->tx_num, 1); + qmp_configure_lane(qmp->dev, rx, tbls->rx, tbls->rx_num, 1); if (cfg->lanes >= 2) { - qmp_pcie_configure_lane(tx2, tbls->tx, tbls->tx_num, 2); - qmp_pcie_configure_lane(rx2, tbls->rx, tbls->rx_num, 2); + qmp_configure_lane(qmp->dev, tx2, tbls->tx, tbls->tx_num, 2); + qmp_configure_lane(qmp->dev, rx2, tbls->rx, tbls->rx_num, 2); } - qmp_pcie_configure(pcs, tbls->pcs, tbls->pcs_num); - qmp_pcie_configure(pcs_misc, tbls->pcs_misc, tbls->pcs_misc_num); + 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_pcie_configure(serdes, cfg->serdes_4ln_tbl, cfg->serdes_4ln_num); + qmp_configure(qmp->dev, serdes, cfg->serdes_4ln_tbl, + cfg->serdes_4ln_num); qmp_pcie_init_port_b(qmp, tbls); } - qmp_pcie_configure(ln_shrd, tbls->ln_shrd, tbls->ln_shrd_num); + qmp_configure(qmp->dev, ln_shrd, tbls->ln_shrd, tbls->ln_shrd_num); } static int qmp_pcie_init(struct phy *phy) { struct qmp_pcie *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = qmp->pcs; + bool phy_initialized = !!(readl(pcs + cfg->regs[QPHY_START_CTRL])); int ret; + qmp->skip_init = qmp->nocsr_reset && phy_initialized; + /* + * We need to check the existence of init sequences in two cases: + * 1. The PHY doesn't support no_csr reset. + * 2. The PHY supports no_csr reset but isn't initialized by bootloader. + * As we can't skip init in these two cases. + */ + if (!qmp->skip_init && !cfg->tbls.serdes_num) { + dev_err(qmp->dev, "Init sequence not available\n"); + return -ENODATA; + } + ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); if (ret) { dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); return ret; } - ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets); - if (ret) { - dev_err(qmp->dev, "reset assert failed\n"); - goto err_disable_regulators; + /* + * Toggle BCR reset for PHY that doesn't support no_csr reset or has not + * been initialized. + */ + if (!qmp->skip_init) { + ret = reset_control_bulk_assert(cfg->num_resets, qmp->resets); + if (ret) { + dev_err(qmp->dev, "reset assert failed\n"); + goto err_disable_regulators; + } } ret = reset_control_assert(qmp->nocsr_reset); @@ -3289,10 +4373,12 @@ static int qmp_pcie_init(struct phy *phy) usleep_range(200, 300); - ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets); - if (ret) { - dev_err(qmp->dev, "reset deassert failed\n"); - goto err_assert_reset; + if (!qmp->skip_init) { + ret = reset_control_bulk_deassert(cfg->num_resets, qmp->resets); + if (ret) { + dev_err(qmp->dev, "reset deassert failed\n"); + goto err_assert_reset; + } } ret = clk_bulk_prepare_enable(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks); @@ -3302,7 +4388,8 @@ static int qmp_pcie_init(struct phy *phy) return 0; err_assert_reset: - reset_control_bulk_assert(cfg->num_resets, qmp->resets); + if (!qmp->skip_init) + reset_control_bulk_assert(cfg->num_resets, qmp->resets); err_disable_regulators: regulator_bulk_disable(cfg->num_vregs, qmp->vregs); @@ -3314,7 +4401,10 @@ static int qmp_pcie_exit(struct phy *phy) struct qmp_pcie *qmp = phy_get_drvdata(phy); const struct qmp_phy_cfg *cfg = qmp->cfg; - reset_control_bulk_assert(cfg->num_resets, qmp->resets); + if (qmp->nocsr_reset) + reset_control_assert(qmp->nocsr_reset); + else + reset_control_bulk_assert(cfg->num_resets, qmp->resets); clk_bulk_disable_unprepare(ARRAY_SIZE(qmp_pciephy_clk_l), qmp->clks); @@ -3333,6 +4423,13 @@ static int qmp_pcie_power_on(struct phy *phy) unsigned int mask, val; int ret; + /* + * Write CSR register for PHY that doesn't support no_csr reset or has not + * been initialized. + */ + if (qmp->skip_init) + goto skip_tbls_init; + qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], cfg->pwrdn_ctrl); @@ -3344,6 +4441,7 @@ static int qmp_pcie_power_on(struct phy *phy) qmp_pcie_init_registers(qmp, &cfg->tbls); qmp_pcie_init_registers(qmp, mode_tbls); +skip_tbls_init: ret = clk_bulk_prepare_enable(qmp->num_pipe_clks, qmp->pipe_clks); if (ret) return ret; @@ -3354,6 +4452,9 @@ static int qmp_pcie_power_on(struct phy *phy) goto err_disable_pipe_clk; } + if (qmp->skip_init) + goto skip_serdes_start; + /* Pull PHY out of reset state */ qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); @@ -3363,6 +4464,7 @@ static int qmp_pcie_power_on(struct phy *phy) if (!cfg->skip_start_delay) usleep_range(1000, 1200); +skip_serdes_start: status = pcs + cfg->regs[QPHY_PCS_STATUS]; mask = cfg->phy_status; ret = readl_poll_timeout(status, val, !(val & mask), 200, @@ -3387,6 +4489,15 @@ static int qmp_pcie_power_off(struct phy *phy) clk_bulk_disable_unprepare(qmp->num_pipe_clks, qmp->pipe_clks); + /* + * While powering off the PHY, only qmp->nocsr_reset needs to be checked. In + * this way, no matter whether the PHY settings were initially programmed by + * bootloader or PHY driver itself, we can reuse them when PHY is powered on + * next time. + */ + if (qmp->nocsr_reset) + goto skip_phy_deinit; + /* PHY reset */ qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); @@ -3398,6 +4509,7 @@ static int qmp_pcie_power_off(struct phy *phy) qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], cfg->pwrdn_ctrl); +skip_phy_deinit: return 0; } @@ -3487,12 +4599,10 @@ static int qmp_pcie_reset_init(struct qmp_pcie *qmp) if (ret) return dev_err_probe(dev, ret, "failed to get resets\n"); - if (cfg->has_nocsr_reset) { - qmp->nocsr_reset = devm_reset_control_get_exclusive(dev, "phy_nocsr"); - if (IS_ERR(qmp->nocsr_reset)) - return dev_err_probe(dev, PTR_ERR(qmp->nocsr_reset), - "failed to get no-csr reset\n"); - } + qmp->nocsr_reset = devm_reset_control_get_optional_exclusive(dev, "phy_nocsr"); + if (IS_ERR(qmp->nocsr_reset)) + return dev_err_probe(dev, PTR_ERR(qmp->nocsr_reset), + "failed to get no-csr reset\n"); return 0; } @@ -3542,7 +4652,7 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np) struct clk_init_data init = { }; int ret; - ret = of_property_read_string(np, "clock-output-names", &init.name); + ret = of_property_read_string_index(np, "clock-output-names", 0, &init.name); if (ret) { dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); return ret; @@ -3561,14 +4671,84 @@ static int phy_pipe_clk_register(struct qmp_pcie *qmp, struct device_node *np) fixed->hw.init = &init; - ret = devm_clk_hw_register(qmp->dev, &fixed->hw); - if (ret) - return ret; + return devm_clk_hw_register(qmp->dev, &fixed->hw); +} + +/* + * Register a fixed rate PHY aux clock. + * + * The <s>_phy_aux_clksrc generated by PHY goes to the GCC that gate + * controls it. The <s>_phy_aux_clk coming out of the GCC is requested + * by the PHY driver for its operations. + * We register the <s>_phy_aux_clksrc here. The gcc driver takes care + * of assigning this <s>_phy_aux_clksrc as parent to <s>_phy_aux_clk. + * Below picture shows this relationship. + * + * +---------------+ + * | PHY block |<<---------------------------------------------+ + * | | | + * | +-------+ | +-----+ | + * I/P---^-->| PLL |---^--->phy_aux_clksrc--->| GCC |--->phy_aux_clk---+ + * clk | +-------+ | +-----+ + * +---------------+ + */ +static int phy_aux_clk_register(struct qmp_pcie *qmp, struct device_node *np) +{ + struct clk_fixed_rate *fixed = &qmp->aux_clk_fixed; + struct clk_init_data init = { }; + char name[64]; + + snprintf(name, sizeof(name), "%s::phy_aux_clk", dev_name(qmp->dev)); + + init.name = name; + init.ops = &clk_fixed_rate_ops; + + fixed->fixed_rate = qmp->cfg->aux_clock_rate; + fixed->hw.init = &init; + + return devm_clk_hw_register(qmp->dev, &fixed->hw); +} + +static struct clk_hw *qmp_pcie_clk_hw_get(struct of_phandle_args *clkspec, void *data) +{ + struct qmp_pcie *qmp = data; + + /* Support legacy bindings */ + if (!clkspec->args_count) + return &qmp->pipe_clk_fixed.hw; + + switch (clkspec->args[0]) { + case QMP_PCIE_PIPE_CLK: + return &qmp->pipe_clk_fixed.hw; + case QMP_PCIE_PHY_AUX_CLK: + return &qmp->aux_clk_fixed.hw; + } - ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw); + return ERR_PTR(-EINVAL); +} + +static int qmp_pcie_register_clocks(struct qmp_pcie *qmp, struct device_node *np) +{ + int ret; + + ret = phy_pipe_clk_register(qmp, np); if (ret) return ret; + if (qmp->cfg->aux_clock_rate) { + ret = phy_aux_clk_register(qmp, np); + if (ret) + return ret; + + ret = of_clk_add_hw_provider(np, qmp_pcie_clk_hw_get, qmp); + if (ret) + return ret; + } else { + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &qmp->pipe_clk_fixed.hw); + if (ret) + return ret; + } + /* * Roll a devm action because the clock provider is the child node, but * the child node is not actually a device. @@ -3634,6 +4814,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), @@ -3701,6 +4889,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; @@ -3715,6 +4904,9 @@ static int qmp_pcie_parse_dt(struct qmp_pcie *qmp) return PTR_ERR(qmp->port_b); } + qmp->txz = base + offs->txz; + qmp->rxz = base + offs->rxz; + if (cfg->tbls.ln_shrd) qmp->ln_shrd = base + offs->ln_shrd; @@ -3777,7 +4969,7 @@ static int qmp_pcie_probe(struct platform_device *pdev) if (ret) goto err_node_put; - ret = phy_pipe_clk_register(qmp, np); + ret = qmp_pcie_register_clocks(qmp, np); if (ret) goto err_node_put; @@ -3814,15 +5006,30 @@ static const struct of_device_id qmp_pcie_of_match_table[] = { .compatible = "qcom,ipq8074-qmp-pcie-phy", .data = &ipq8074_pciephy_cfg, }, { + .compatible = "qcom,ipq9574-qmp-gen3x1-pcie-phy", + .data = &ipq9574_gen3x1_pciephy_cfg, + }, { + .compatible = "qcom,ipq9574-qmp-gen3x2-pcie-phy", + .data = &ipq9574_gen3x2_pciephy_cfg, + }, { .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, }, { @@ -3885,6 +5092,21 @@ static const struct of_device_id qmp_pcie_of_match_table[] = { }, { .compatible = "qcom,sm8650-qmp-gen4x2-pcie-phy", .data = &sm8650_qmp_gen4x2_pciephy_cfg, + }, { + .compatible = "qcom,x1e80100-qmp-gen3x2-pcie-phy", + .data = &sm8550_qmp_gen3x2_pciephy_cfg, + }, { + .compatible = "qcom,x1e80100-qmp-gen4x2-pcie-phy", + .data = &x1e80100_qmp_gen4x2_pciephy_cfg, + }, { + .compatible = "qcom,x1e80100-qmp-gen4x4-pcie-phy", + .data = &x1e80100_qmp_gen4x4_pciephy_cfg, + }, { + .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.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5.h index a469ae2a10a1..fa15a03055de 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v5.h @@ -11,8 +11,22 @@ #define QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG2 0x0c #define QPHY_V5_PCS_PCIE_POWER_STATE_CONFIG4 0x14 #define QPHY_V5_PCS_PCIE_ENDPOINT_REFCLK_DRIVE 0x20 +#define QPHY_V5_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L 0x44 +#define QPHY_V5_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_H 0x48 +#define QPHY_V5_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L 0x4c +#define QPHY_V5_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_H 0x50 #define QPHY_V5_PCS_PCIE_INT_AUX_CLK_CONFIG1 0x54 +#define QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG1 0x5c +#define QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG2 0x60 +#define QPHY_V5_PCS_PCIE_OSC_DTCT_CONFIG4 0x68 +#define QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG2 0x7c +#define QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG4 0x84 +#define QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG5 0x88 +#define QPHY_V5_PCS_PCIE_OSC_DTCT_MODE2_CONFIG6 0x8c #define QPHY_V5_PCS_PCIE_OSC_DTCT_ACTIONS 0x94 +#define QPHY_V5_PCS_PCIE_EQ_CONFIG1 0xa4 #define QPHY_V5_PCS_PCIE_EQ_CONFIG2 0xa8 +#define QPHY_V5_PCS_PCIE_PRESET_P10_PRE 0xc0 +#define QPHY_V5_PCS_PCIE_PRESET_P10_POST 0xe4 #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 91e70002eb47..45397cb3c0c6 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6.h @@ -7,9 +7,14 @@ #define QCOM_PHY_QMP_PCS_PCIE_V6_H_ /* Only for QMP V6 PHY - PCIE have different offsets than V5 */ +#define QPHY_PCIE_V6_PCS_PCIE_EQ_CONFIG1 0xa4 +#define QPHY_PCIE_V6_PCS_PCIE_RXEQEVAL_TIME 0xf4 #define QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG2 0x0c #define QPHY_PCIE_V6_PCS_PCIE_POWER_STATE_CONFIG4 0x14 #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-pcie-v6_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h index e3eb08776339..dfcecf31a606 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_20.h @@ -12,6 +12,8 @@ #define QPHY_PCIE_V6_20_PCS_ENDPOINT_REFCLK_DRIVE 0x01c #define QPHY_PCIE_V6_20_PCS_OSC_DTCT_ATCIONS 0x090 #define QPHY_PCIE_V6_20_PCS_EQ_CONFIG1 0x0a0 +#define QPHY_PCIE_V6_20_PCS_G3_RXEQEVAL_TIME 0x0f0 +#define QPHY_PCIE_V6_20_PCS_G4_RXEQEVAL_TIME 0x0f4 #define QPHY_PCIE_V6_20_PCS_EQ_CONFIG5 0x108 #define QPHY_PCIE_V6_20_PCS_G4_PRE_GAIN 0x15c #define QPHY_PCIE_V6_20_PCS_RX_MARGINING_CONFIG1 0x17c diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_30.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_30.h new file mode 100644 index 000000000000..5a58ff197e6e --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-pcie-v6_30.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_PCIE_V6_30_H_ +#define QCOM_PHY_QMP_PCS_PCIE_V6_30_H_ + +/* Only for QMP V6_30 PHY - PCIE have different offsets than V6 */ +#define QPHY_PCIE_V6_30_PCS_POWER_STATE_CONFIG2 0x014 +#define QPHY_PCIE_V6_30_PCS_TX_RX_CONFIG 0x020 +#define QPHY_PCIE_V6_30_PCS_ENDPOINT_REFCLK_DRIVE 0x024 +#define QPHY_PCIE_V6_30_PCS_OSC_DTCT_ACTIONS 0x098 +#define QPHY_PCIE_V6_30_PCS_EQ_CONFIG1 0x0a8 +#define QPHY_PCIE_V6_30_PCS_G3_RXEQEVAL_TIME 0x0f8 +#define QPHY_PCIE_V6_30_PCS_G4_RXEQEVAL_TIME 0x0fc +#define QPHY_PCIE_V6_30_PCS_G4_EQ_CONFIG5 0x110 +#define QPHY_PCIE_V6_30_PCS_G4_PRE_GAIN 0x164 +#define QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG1 0x184 +#define QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG3 0x18c +#define QPHY_PCIE_V6_30_PCS_RX_MARGINING_CONFIG5 0x194 +#define QPHY_PCIE_V6_30_PCS_G3_FOM_EQ_CONFIG5 0x1b4 +#define QPHY_PCIE_V6_30_PCS_G4_FOM_EQ_CONFIG5 0x1c8 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-sgmii.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-sgmii.h new file mode 100644 index 000000000000..4d8c962f5e0f --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-sgmii.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef QCOM_PHY_QMP_PCS_SGMII_H_ +#define QCOM_PHY_QMP_PCS_SGMII_H_ + +#define QPHY_PCS_PHY_START 0x000 +#define QPHY_PCS_POWER_DOWN_CONTROL 0x004 +#define QPHY_PCS_SW_RESET 0x008 +#define QPHY_PCS_LINE_RESET_TIME 0x00c +#define QPHY_PCS_TX_LARGE_AMP_DRV_LVL 0x020 +#define QPHY_PCS_TX_SMALL_AMP_DRV_LVL 0x028 +#define QPHY_PCS_PCS_READY_STATUS 0x094 +#define QPHY_PCS_TX_MID_TERM_CTRL1 0x0d8 +#define QPHY_PCS_TX_MID_TERM_CTRL2 0x0dc +#define QPHY_PCS_SGMII_MISC_CTRL8 0x118 + +#endif diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h index fe6c450f6123..f19f9892ed7b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-ufs-v6.h @@ -19,6 +19,7 @@ #define QPHY_V6_PCS_UFS_BIST_FIXED_PAT_CTRL 0x060 #define QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY 0x074 #define QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY 0x0bc +#define QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY 0x12c #define QPHY_V6_PCS_UFS_DEBUG_BUS_CLKSEL 0x158 #define QPHY_V6_PCS_UFS_LINECFG_DISABLE 0x17c #define QPHY_V6_PCS_UFS_RX_MIN_HIBERN8_TIME 0x184 @@ -28,5 +29,10 @@ #define QPHY_V6_PCS_UFS_READY_STATUS 0x1a8 #define QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1 0x1f4 #define QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1 0x1fc +#define QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME 0x220 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4 0x240 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S5 0x244 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S6 0x248 +#define QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S7 0x24c #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-n4.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6-n4.h new file mode 100644 index 000000000000..b3024714dab4 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6-n4.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023, Linaro Limited + */ + +#ifndef QCOM_PHY_QMP_PCS_V6_N4_H_ +#define QCOM_PHY_QMP_PCS_V6_N4_H_ + +/* Only for QMP V6 N4 PHY - USB/PCIe PCS registers */ +#define QPHY_V6_N4_PCS_SW_RESET 0x000 +#define QPHY_V6_N4_PCS_PCS_STATUS1 0x014 +#define QPHY_V6_N4_PCS_POWER_DOWN_CONTROL 0x040 +#define QPHY_V6_N4_PCS_START_CONTROL 0x044 +#define QPHY_V6_N4_PCS_POWER_STATE_CONFIG1 0x090 +#define QPHY_V6_N4_PCS_LOCK_DETECT_CONFIG1 0x0c4 +#define QPHY_V6_N4_PCS_LOCK_DETECT_CONFIG2 0x0c8 +#define QPHY_V6_N4_PCS_LOCK_DETECT_CONFIG3 0x0cc +#define QPHY_V6_N4_PCS_LOCK_DETECT_CONFIG6 0x0d8 +#define QPHY_V6_N4_PCS_REFGEN_REQ_CONFIG1 0x0dc +#define QPHY_V6_N4_PCS_RX_SIGDET_LVL 0x188 +#define QPHY_V6_N4_PCS_RCVR_DTCT_DLY_P1U2_L 0x190 +#define QPHY_V6_N4_PCS_RCVR_DTCT_DLY_P1U2_H 0x194 +#define QPHY_V6_N4_PCS_RATE_SLEW_CNTRL1 0x198 +#define QPHY_V6_N4_PCS_RX_CONFIG 0x1b0 +#define QPHY_V6_N4_PCS_ALIGN_DETECT_CONFIG1 0x1c0 +#define QPHY_V6_N4_PCS_ALIGN_DETECT_CONFIG2 0x1c4 +#define QPHY_V6_N4_PCS_PCS_TX_RX_CONFIG 0x1d0 +#define QPHY_V6_N4_PCS_EQ_CONFIG1 0x1dc +#define QPHY_V6_N4_PCS_EQ_CONFIG2 0x1e0 +#define QPHY_V6_N4_PCS_EQ_CONFIG5 0x1ec + +#endif 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-pcs-v6_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h index 9c3f1e4950e6..4d9615cc0383 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_20.h @@ -7,6 +7,7 @@ #define QCOM_PHY_QMP_PCS_V6_20_H_ /* Only for QMP V6_20 PHY - USB/PCIe PCS registers */ +#define QPHY_V6_20_PCS_G12S1_TXDEEMPH_M6DB 0x170 #define QPHY_V6_20_PCS_G3S2_PRE_GAIN 0x178 #define QPHY_V6_20_PCS_RX_SIGDET_LVL 0x190 #define QPHY_V6_20_PCS_COM_ELECIDLE_DLY_SEL 0x1b8 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_30.h b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_30.h new file mode 100644 index 000000000000..369120d88bc2 --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcs-v6_30.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center. All rights reserved. + */ + +#ifndef QCOM_PHY_QMP_PCS_V6_30_H_ +#define QCOM_PHY_QMP_PCS_V6_30_H_ + +/* Only for QMP V6_30 PHY - PCIe PCS registers */ +#define QPHY_V6_30_PCS_LOCK_DETECT_CONFIG2 0x0cc +#define QPHY_V6_30_PCS_G3S2_PRE_GAIN 0x17c +#define QPHY_V6_30_PCS_RX_SIGDET_LVL 0x194 +#define QPHY_V6_30_PCS_ALIGN_DETECT_CONFIG7 0x1dc +#define QPHY_V6_30_PCS_TX_RX_CONFIG 0x1e0 +#define QPHY_V6_30_PCS_TX_RX_CONFIG2 0x1e4 +#define QPHY_V6_30_PCS_EQ_CONFIG4 0x1fc +#define QPHY_V6_30_PCS_EQ_CONFIG5 0x200 + +#endif 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 ec7291424dd1..258f3d30742e 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-com-v6.h @@ -60,6 +60,8 @@ #define QSERDES_V6_COM_SYSCLK_BUF_ENABLE 0xe8 #define QSERDES_V6_COM_PLL_IVCO 0xf4 #define QSERDES_V6_COM_PLL_IVCO_MODE1 0xf8 +#define QSERDES_V6_COM_CMN_IETRIM 0xfc +#define QSERDES_V6_COM_CMN_IPTRIM 0x100 #define QSERDES_V6_COM_SYSCLK_EN_SEL 0x110 #define QSERDES_V6_COM_RESETSM_CNTRL 0x118 #define QSERDES_V6_COM_LOCK_CMP_EN 0x120 @@ -84,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-pll.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-pll.h index ad326e301a3a..231e59364e31 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-pll.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-pll.h @@ -8,6 +8,9 @@ /* QMP V2 PHY for PCIE gen3 ports - QSERDES PLL registers */ #define QSERDES_PLL_BG_TIMER 0x00c +#define QSERDES_PLL_SSC_EN_CENTER 0x010 +#define QSERDES_PLL_SSC_ADJ_PER1 0x014 +#define QSERDES_PLL_SSC_ADJ_PER2 0x018 #define QSERDES_PLL_SSC_PER1 0x01c #define QSERDES_PLL_SSC_PER2 0x020 #define QSERDES_PLL_SSC_STEP_SIZE1_MODE0 0x024 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h index 35d497fd9f9a..d17a52357965 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-ufs-v6.h @@ -15,16 +15,25 @@ #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE2 0x08 #define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4 0x10 +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4 0x24 #define QSERDES_UFS_V6_RX_UCDR_SO_SATURATION 0x28 +#define QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4 0x54 #define QSERDES_UFS_V6_RX_UCDR_PI_CTRL1 0x58 #define QSERDES_UFS_V6_RX_RX_TERM_BW_CTRL0 0xc4 #define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2 0xd4 #define QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4 0xdc +#define QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4 0xf0 +#define QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS 0xf4 #define QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL 0x178 +#define QSERDES_UFS_V6_RX_RX_EQU_ADAPTOR_CNTRL4 0x1ac +#define QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1 0x1bc #define QSERDES_UFS_V6_RX_INTERFACE_MODE 0x1e0 +#define QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3 0x1c4 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0 0x208 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1 0x20c +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B2 0x210 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3 0x214 +#define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B4 0x218 #define QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6 0x220 #define QSERDES_UFS_V6_RX_MODE_RATE2_B3 0x238 #define QSERDES_UFS_V6_RX_MODE_RATE2_B6 0x244 @@ -32,7 +41,12 @@ #define QSERDES_UFS_V6_RX_MODE_RATE3_B4 0x260 #define QSERDES_UFS_V6_RX_MODE_RATE3_B5 0x264 #define QSERDES_UFS_V6_RX_MODE_RATE3_B8 0x270 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B0 0x274 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B1 0x278 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B2 0x27c #define QSERDES_UFS_V6_RX_MODE_RATE4_B3 0x280 +#define QSERDES_UFS_V6_RX_MODE_RATE4_B4 0x284 #define QSERDES_UFS_V6_RX_MODE_RATE4_B6 0x28c +#define QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL 0x2f8 #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-qserdes-txrx-v6_20.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h index 6ed5339fd2ea..7bac5d5c6c34 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_20.h @@ -23,6 +23,8 @@ #define QSERDES_V6_20_RX_DFE_1 0xac #define QSERDES_V6_20_RX_DFE_2 0xb0 #define QSERDES_V6_20_RX_DFE_3 0xb4 +#define QSERDES_V6_20_RX_TX_ADPT_CTRL 0xd4 +#define QSERDES_V6_20_VGA_CAL_CNTRL1 0xe0 #define QSERDES_V6_20_RX_VGA_CAL_MAN_VAL 0xe8 #define QSERDES_V6_20_RX_GM_CAL 0x10c #define QSERDES_V6_20_RX_EQU_ADAPTOR_CNTRL4 0x120 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_n4.h b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_n4.h index a814ad11af07..d37cc0d4fd36 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_n4.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp-qserdes-txrx-v6_n4.h @@ -6,11 +6,24 @@ #ifndef QCOM_PHY_QMP_QSERDES_TXRX_V6_N4_H_ #define QCOM_PHY_QMP_QSERDES_TXRX_V6_N4_H_ +#define QSERDES_V6_N4_TX_CLKBUF_ENABLE 0x08 +#define QSERDES_V6_N4_TX_TX_EMP_POST1_LVL 0x0c +#define QSERDES_V6_N4_TX_TX_DRV_LVL 0x14 +#define QSERDES_V6_N4_TX_RESET_TSYNC_EN 0x1c +#define QSERDES_V6_N4_TX_PRE_STALL_LDO_BOOST_EN 0x20 #define QSERDES_V6_N4_TX_RES_CODE_LANE_OFFSET_TX 0x30 #define QSERDES_V6_N4_TX_RES_CODE_LANE_OFFSET_RX 0x34 +#define QSERDES_V6_N4_TX_TRANSCEIVER_BIAS_EN 0x48 +#define QSERDES_V6_N4_TX_HIGHZ_DRVR_EN 0x4c +#define QSERDES_V6_N4_TX_TX_POL_INV 0x50 +#define QSERDES_V6_N4_TX_PARRATE_REC_DETECT_IDLE_EN 0x54 #define QSERDES_V6_N4_TX_LANE_MODE_1 0x78 #define QSERDES_V6_N4_TX_LANE_MODE_2 0x7c #define QSERDES_V6_N4_TX_LANE_MODE_3 0x80 +#define QSERDES_V6_N4_TX_TRAN_DRVR_EMP_EN 0xac +#define QSERDES_V6_N4_TX_TX_BAND 0xd8 +#define QSERDES_V6_N4_TX_INTERFACE_SELECT 0xe4 +#define QSERDES_V6_N4_TX_VMODE_CTRL1 0xb0 #define QSERDES_V6_N4_RX_UCDR_FO_GAIN_RATE2 0x8 #define QSERDES_V6_N4_RX_UCDR_SO_GAIN_RATE2 0x18 diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index 3c2e6255e26f..b33e2e2b5014 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -20,6 +20,9 @@ #include <linux/slab.h> #include <ufs/unipro.h> + +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-ufs-v2.h" #include "phy-qcom-qmp-pcs-ufs-v3.h" @@ -28,42 +31,14 @@ #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_SW_RESET bit */ -#define SW_RESET BIT(0) -/* QPHY_POWER_DOWN_CONTROL */ -#define SW_PWRDN BIT(0) -/* QPHY_START_CONTROL bits */ -#define SERDES_START BIT(0) -#define PCS_START BIT(1) /* QPHY_PCS_READY_STATUS bit */ #define PCS_READY BIT(0) #define PHY_INIT_COMPLETE_TIMEOUT 10000 -struct qmp_phy_init_tbl { - unsigned int offset; - unsigned int val; - /* - * mask of lanes for which this register is written - * for cases when second lane needs different values - */ - u8 lane_mask; -}; - -#define QMP_PHY_INIT_CFG(o, v) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = 0xff, \ - } - -#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = l, \ - } +#define NUM_OVERLAY 2 /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { @@ -748,21 +723,60 @@ static const struct qmp_phy_init_tbl sm8350_ufsphy_g4_pcs[] = { QMP_PHY_INIT_CFG(QPHY_V5_PCS_UFS_BIST_FIXED_PAT_CTRL, 0x0a), }; -static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = { +static const struct qmp_phy_init_tbl sm8475_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_VCO_TUNE_INITVAL2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE0, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE0, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x0c), +}; + +static const struct qmp_phy_init_tbl sm8475_ufsphy_g4_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_CCTRL_MODE1, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x0f), +}; + +static const struct qmp_phy_init_tbl sm8475_ufsphy_g4_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x0b), + 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 sm8550_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_VCO_TUNE_INITVAL2, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a), 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_LOCK_CMP1_MODE0, 0x7f), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c), QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_RCTRL_MODE1, 0x18), @@ -771,19 +785,24 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_serdes[] = { QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE1, 0x07), }; -static const struct qmp_phy_init_tbl sm8550_ufsphy_hs_b_serdes[] = { - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44), +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_serdes[] = { + QMP_PHY_INIT_CFG(QSERDES_V6_COM_PLL_IVCO, 0x1f), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IETRIM, 0x1b), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x06), }; static const struct qmp_phy_init_tbl sm8550_ufsphy_tx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_tx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_FR_DCC_CTRL, 0x4c), }; static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2), @@ -799,33 +818,65 @@ static const struct qmp_phy_init_tbl sm8550_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02), }; +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g5_rx[] = { + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30), +}; + static const struct qmp_phy_init_tbl sm8550_ufsphy_pcs[] = { QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x69), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), +}; + +static const struct qmp_phy_init_tbl sm8550_ufsphy_g4_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x2b), 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 sm8550_ufsphy_g5_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4f), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSG5_SYNC_WAIT_TIME, 0x9e), +}; + static const struct qmp_phy_init_tbl sm8650_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_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x44), + 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, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_CMN_IPTRIM, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_MAP, 0x04), QMP_PHY_INIT_CFG(QSERDES_V6_COM_VCO_TUNE_INITVAL2, 0x00), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE0, 0x41), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE0, 0x0a), + 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_LOCK_CMP1_MODE0, 0x7f), QMP_PHY_INIT_CFG(QSERDES_V6_COM_LOCK_CMP2_MODE0, 0x06), QMP_PHY_INIT_CFG(QSERDES_V6_COM_DEC_START_MODE1, 0x4c), - QMP_PHY_INIT_CFG(QSERDES_V6_COM_CP_CTRL_MODE1, 0x0a), + 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_LOCK_CMP1_MODE1, 0x99), @@ -833,17 +884,28 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_serdes[] = { }; static const struct qmp_phy_init_tbl sm8650_ufsphy_tx[] = { - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x05), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_LANE_MODE_1, 0x01), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_TX, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), }; static const struct qmp_phy_init_tbl sm8650_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE2, 0x0c), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x0e), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xc2), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xc2), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FO_GAIN_RATE4, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_GAIN_RATE4, 0x04), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CONTROLS, 0x07), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_OFFSET_ADAPTOR_CNTRL3, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_COUNT_HIGH_RATE4, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_FO_GAIN_RATE4, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_FASTLOCK_SO_GAIN_RATE4, 0x06), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_VGA_CAL_MAN_VAL, 0x3e), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B0, 0xce), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B1, 0xce), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B2, 0x18), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B3, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B4, 0x0f), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE_0_1_B6, 0x60), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B3, 0x9e), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE2_B6, 0x60), @@ -851,23 +913,159 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_rx[] = { QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B4, 0x0e), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B5, 0x36), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE3_B8, 0x02), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B1, 0x24), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B2, 0x20), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B3, 0xb9), - QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B6, 0xff), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_MODE_RATE4_B4, 0x4f), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_SO_SATURATION, 0x1f), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_UCDR_PI_CTRL1, 0x94), QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_RX_TERM_BW_CTRL0, 0xfa), + QMP_PHY_INIT_CFG(QSERDES_UFS_V6_RX_DLL0_FTUNE_CTRL, 0x30), }; static const struct qmp_phy_init_tbl sm8650_ufsphy_pcs[] = { - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x00), + 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, 0xc1), - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + 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 sm8650_ufsphy_g4_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x13), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04), - 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, 0x69), +}; + +static const struct qmp_phy_init_tbl sm8650_ufsphy_g5_pcs[] = { + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x05), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x05), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4d), + 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 { @@ -889,6 +1087,8 @@ struct qmp_phy_cfg_tbls { int rx_num; const struct qmp_phy_init_tbl *pcs; int pcs_num; + /* Maximum supported Gear of this tbls */ + u32 max_gear; }; /* struct qmp_phy_cfg - per-PHY initialization config */ @@ -896,17 +1096,16 @@ struct qmp_phy_cfg { int lanes; const struct qmp_ufs_offsets *offsets; + /* Maximum supported Gear of this config */ + u32 max_supported_gear; /* Main init sequence for PHY blocks - serdes, tx, rx, pcs */ const struct qmp_phy_cfg_tbls tbls; /* Additional sequence for HS Series B */ const struct qmp_phy_cfg_tbls tbls_hs_b; - /* Additional sequence for HS G4 */ - const struct qmp_phy_cfg_tbls tbls_hs_g4; + /* Additional sequence for different HS Gears */ + const struct qmp_phy_cfg_tbls tbls_hs_overlay[NUM_OVERLAY]; - /* clock ids to be requested */ - const char * const *clk_list; - int num_clks; /* regulators to be requested */ const char * const *vreg_list; int num_vregs; @@ -932,6 +1131,7 @@ struct qmp_ufs { void __iomem *rx2; struct clk_bulk_data *clks; + int num_clks; struct regulator_bulk_data *vregs; struct reset_control *ufs_reset; @@ -964,20 +1164,6 @@ static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) readl(base + offset); } -/* list of clocks required by phy */ -static const char * const msm8996_ufs_phy_clk_l[] = { - "ref", -}; - -/* the primary usb3 phy on sm8250 doesn't have a ref clock */ -static const char * const sm8450_ufs_phy_clk_l[] = { - "qref", "ref", "ref_aux", -}; - -static const char * const sdm845_ufs_phy_clk_l[] = { - "ref", "ref_aux", -}; - /* list of regulators */ static const char * const qmp_phy_vreg_l[] = { "vdda-phy", "vdda-pll", @@ -1005,6 +1191,7 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .lanes = 1, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = msm8996_ufsphy_serdes, @@ -1015,9 +1202,6 @@ static const struct qmp_phy_cfg msm8996_ufsphy_cfg = { .rx_num = ARRAY_SIZE(msm8996_ufsphy_rx), }, - .clk_list = msm8996_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(msm8996_ufs_phy_clk_l), - .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), @@ -1030,6 +1214,7 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1045,16 +1230,15 @@ static const struct qmp_phy_cfg sa8775p_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sm8450_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1064,6 +1248,7 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8150_ufsphy_serdes, @@ -1079,16 +1264,15 @@ static const struct qmp_phy_cfg sc7280_ufsphy_cfg = { .serdes = sm8150_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8250_ufsphy_hs_g4_tx, .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx), .rx = sc7280_ufsphy_hs_g4_rx, .rx_num = ARRAY_SIZE(sc7280_ufsphy_hs_g4_rx), .pcs = sm8150_ufsphy_hs_g4_pcs, .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sm8450_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v4_regs_layout, @@ -1098,6 +1282,7 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1113,16 +1298,15 @@ static const struct qmp_phy_cfg sc8280xp_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1132,6 +1316,7 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = sdm845_ufsphy_serdes, @@ -1147,8 +1332,6 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v3_regs_layout, @@ -1160,6 +1343,7 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { .lanes = 1, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = sm6115_ufsphy_serdes, @@ -1175,8 +1359,6 @@ static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { .serdes = sm6115_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm6115_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v2_regs_layout, @@ -1188,6 +1370,7 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { .lanes = 1, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G3, .tbls = { .serdes = sdm845_ufsphy_serdes, @@ -1203,8 +1386,6 @@ static const struct qmp_phy_cfg sm7150_ufsphy_cfg = { .serdes = sdm845_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sdm845_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v3_regs_layout, @@ -1216,6 +1397,7 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8150_ufsphy_serdes, @@ -1231,16 +1413,15 @@ static const struct qmp_phy_cfg sm8150_ufsphy_cfg = { .serdes = sm8150_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8150_ufsphy_hs_g4_tx, .tx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_tx), .rx = sm8150_ufsphy_hs_g4_rx, .rx_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_rx), .pcs = sm8150_ufsphy_hs_g4_pcs, .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v4_regs_layout, @@ -1250,6 +1431,7 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8150_ufsphy_serdes, @@ -1265,16 +1447,15 @@ static const struct qmp_phy_cfg sm8250_ufsphy_cfg = { .serdes = sm8150_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8150_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8250_ufsphy_hs_g4_tx, .tx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_tx), .rx = sm8250_ufsphy_hs_g4_rx, .rx_num = ARRAY_SIZE(sm8250_ufsphy_hs_g4_rx), .pcs = sm8150_ufsphy_hs_g4_pcs, .pcs_num = ARRAY_SIZE(sm8150_ufsphy_hs_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v4_regs_layout, @@ -1284,6 +1465,7 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1299,16 +1481,15 @@ static const struct qmp_phy_cfg sm8350_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, @@ -1318,6 +1499,7 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets, + .max_supported_gear = UFS_HS_G4, .tbls = { .serdes = sm8350_ufsphy_serdes, @@ -1333,25 +1515,61 @@ static const struct qmp_phy_cfg sm8450_ufsphy_cfg = { .serdes = sm8350_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8350_ufsphy_hs_b_serdes), }, - .tbls_hs_g4 = { + .tbls_hs_overlay[0] = { .tx = sm8350_ufsphy_g4_tx, .tx_num = ARRAY_SIZE(sm8350_ufsphy_g4_tx), .rx = sm8350_ufsphy_g4_rx, .rx_num = ARRAY_SIZE(sm8350_ufsphy_g4_rx), .pcs = sm8350_ufsphy_g4_pcs, .pcs_num = ARRAY_SIZE(sm8350_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, }, - .clk_list = sm8450_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sm8450_ufs_phy_clk_l), .vreg_list = qmp_phy_vreg_l, .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), .regs = ufsphy_v5_regs_layout, }; +static const struct qmp_phy_cfg sm8475_ufsphy_cfg = { + .lanes = 2, + + .offsets = &qmp_ufs_offsets_v6, + .max_supported_gear = UFS_HS_G4, + + .tbls = { + .serdes = sm8475_ufsphy_serdes, + .serdes_num = ARRAY_SIZE(sm8475_ufsphy_serdes), + .tx = sm8550_ufsphy_tx, + .tx_num = ARRAY_SIZE(sm8550_ufsphy_tx), + .rx = sm8550_ufsphy_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_rx), + .pcs = sm8550_ufsphy_pcs, + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_pcs), + }, + .tbls_hs_b = { + .serdes = sm8550_ufsphy_hs_b_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes), + }, + .tbls_hs_overlay[0] = { + .serdes = sm8475_ufsphy_g4_serdes, + .serdes_num = ARRAY_SIZE(sm8475_ufsphy_g4_serdes), + .tx = sm8550_ufsphy_g4_tx, + .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx), + .rx = sm8550_ufsphy_g4_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx), + .pcs = sm8475_ufsphy_g4_pcs, + .pcs_num = ARRAY_SIZE(sm8475_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, + }, + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = ufsphy_v6_regs_layout, +}; + static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets_v6, + .max_supported_gear = UFS_HS_G5, .tbls = { .serdes = sm8550_ufsphy_serdes, @@ -1367,8 +1585,26 @@ static const struct qmp_phy_cfg sm8550_ufsphy_cfg = { .serdes = sm8550_ufsphy_hs_b_serdes, .serdes_num = ARRAY_SIZE(sm8550_ufsphy_hs_b_serdes), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .tbls_hs_overlay[0] = { + .serdes = sm8550_ufsphy_g4_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g4_serdes), + .tx = sm8550_ufsphy_g4_tx, + .tx_num = ARRAY_SIZE(sm8550_ufsphy_g4_tx), + .rx = sm8550_ufsphy_g4_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g4_rx), + .pcs = sm8550_ufsphy_g4_pcs, + .pcs_num = ARRAY_SIZE(sm8550_ufsphy_g4_pcs), + .max_gear = UFS_HS_G4, + }, + .tbls_hs_overlay[1] = { + .serdes = sm8550_ufsphy_g5_serdes, + .serdes_num = ARRAY_SIZE(sm8550_ufsphy_g5_serdes), + .rx = sm8550_ufsphy_g5_rx, + .rx_num = ARRAY_SIZE(sm8550_ufsphy_g5_rx), + .pcs = sm8550_ufsphy_g5_pcs, + .pcs_num = ARRAY_SIZE(sm8550_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, @@ -1378,6 +1614,7 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .lanes = 2, .offsets = &qmp_ufs_offsets_v6, + .max_supported_gear = UFS_HS_G5, .tbls = { .serdes = sm8650_ufsphy_serdes, @@ -1389,44 +1626,66 @@ static const struct qmp_phy_cfg sm8650_ufsphy_cfg = { .pcs = sm8650_ufsphy_pcs, .pcs_num = ARRAY_SIZE(sm8650_ufsphy_pcs), }, - .clk_list = sdm845_ufs_phy_clk_l, - .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .tbls_hs_overlay[0] = { + .pcs = sm8650_ufsphy_g4_pcs, + .pcs_num = ARRAY_SIZE(sm8650_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_configure_lane(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num, - u8 lane_mask) -{ - int i; - const struct qmp_phy_init_tbl *t = tbl; +static const struct qmp_phy_cfg sm8750_ufsphy_cfg = { + .lanes = 2, - if (!t) - return; + .offsets = &qmp_ufs_offsets_v6, + .max_supported_gear = UFS_HS_G5, - for (i = 0; i < num; i++, t++) { - if (!(t->lane_mask & lane_mask)) - continue; + .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), + }, - writel(t->val, base + t->offset); - } -} + .tbls_hs_b = { + .pcs = sm8750_ufsphy_hs_b_pcs, + .pcs_num = ARRAY_SIZE(sm8750_ufsphy_hs_b_pcs), + }, -static void qmp_ufs_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_ufs_configure_lane(base, tbl, num, 0xff); -} + .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; - qmp_ufs_configure(serdes, tbls->serdes, tbls->serdes_num); + qmp_configure(qmp->dev, serdes, tbls->serdes, tbls->serdes_num); } static void qmp_ufs_lanes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls *tbls) @@ -1435,12 +1694,12 @@ static void qmp_ufs_lanes_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbl void __iomem *tx = qmp->tx; void __iomem *rx = qmp->rx; - qmp_ufs_configure_lane(tx, tbls->tx, tbls->tx_num, 1); - qmp_ufs_configure_lane(rx, tbls->rx, tbls->rx_num, 1); + qmp_configure_lane(qmp->dev, tx, tbls->tx, tbls->tx_num, 1); + qmp_configure_lane(qmp->dev, rx, tbls->rx, tbls->rx_num, 1); if (cfg->lanes >= 2) { - qmp_ufs_configure_lane(qmp->tx2, tbls->tx, tbls->tx_num, 2); - qmp_ufs_configure_lane(qmp->rx2, tbls->rx, tbls->rx_num, 2); + qmp_configure_lane(qmp->dev, qmp->tx2, tbls->tx, tbls->tx_num, 2); + qmp_configure_lane(qmp->dev, qmp->rx2, tbls->rx, tbls->rx_num, 2); } } @@ -1448,20 +1707,55 @@ static void qmp_ufs_pcs_init(struct qmp_ufs *qmp, const struct qmp_phy_cfg_tbls { void __iomem *pcs = qmp->pcs; - qmp_ufs_configure(pcs, tbls->pcs, tbls->pcs_num); + qmp_configure(qmp->dev, pcs, tbls->pcs, tbls->pcs_num); +} + +static int qmp_ufs_get_gear_overlay(struct qmp_ufs *qmp, const struct qmp_phy_cfg *cfg) +{ + u32 max_gear, floor_max_gear = cfg->max_supported_gear; + int idx, ret = -EINVAL; + + for (idx = NUM_OVERLAY - 1; idx >= 0; idx--) { + max_gear = cfg->tbls_hs_overlay[idx].max_gear; + + /* Skip if the table is not available */ + if (max_gear == 0) + continue; + + /* Direct matching, bail */ + if (qmp->submode == max_gear) + return idx; + + /* If no direct matching, the lowest gear is the best matching */ + if (max_gear < floor_max_gear) { + ret = idx; + floor_max_gear = max_gear; + } + } + + 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) { - qmp_ufs_serdes_init(qmp, &cfg->tbls); + int i; + + qmp_ufs_init_all(qmp, &cfg->tbls); + + i = qmp_ufs_get_gear_overlay(qmp, cfg); + if (i >= 0) { + 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_lanes_init(qmp, &cfg->tbls); - if (qmp->submode == UFS_HS_G4) - qmp_ufs_lanes_init(qmp, &cfg->tbls_hs_g4); - qmp_ufs_pcs_init(qmp, &cfg->tbls); - if (qmp->submode == UFS_HS_G4) - qmp_ufs_pcs_init(qmp, &cfg->tbls_hs_g4); + qmp_ufs_init_all(qmp, &cfg->tbls_hs_b); } static int qmp_ufs_com_init(struct qmp_ufs *qmp) @@ -1476,7 +1770,7 @@ static int qmp_ufs_com_init(struct qmp_ufs *qmp) return ret; } - ret = clk_bulk_prepare_enable(cfg->num_clks, qmp->clks); + ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); if (ret) goto err_disable_regulators; @@ -1496,7 +1790,7 @@ static int qmp_ufs_com_exit(struct qmp_ufs *qmp) reset_control_assert(qmp->ufs_reset); - clk_bulk_disable_unprepare(cfg->num_clks, qmp->clks); + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); regulator_bulk_disable(cfg->num_vregs, qmp->vregs); @@ -1633,6 +1927,12 @@ static int qmp_ufs_disable(struct phy *phy) static int qmp_ufs_set_mode(struct phy *phy, enum phy_mode mode, int submode) { struct qmp_ufs *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + if (submode > cfg->max_supported_gear || submode == 0) { + dev_err(qmp->dev, "Invalid PHY submode %d\n", submode); + return -EINVAL; + } qmp->mode = mode; qmp->submode = submode; @@ -1666,19 +1966,13 @@ static int qmp_ufs_vreg_init(struct qmp_ufs *qmp) static int qmp_ufs_clk_init(struct qmp_ufs *qmp) { - const struct qmp_phy_cfg *cfg = qmp->cfg; struct device *dev = qmp->dev; - int num = cfg->num_clks; - int i; - qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); - if (!qmp->clks) - return -ENOMEM; - - for (i = 0; i < num; i++) - qmp->clks[i].id = cfg->clk_list[i]; + qmp->num_clks = devm_clk_bulk_get_all(dev, &qmp->clks); + if (qmp->num_clks < 0) + return qmp->num_clks; - return devm_clk_bulk_get(dev, num, qmp->clks); + return 0; } static void qmp_ufs_clk_release_provider(void *res) @@ -1881,6 +2175,9 @@ static const struct of_device_id qmp_ufs_of_match_table[] = { .compatible = "qcom,sa8775p-qmp-ufs-phy", .data = &sa8775p_ufsphy_cfg, }, { + .compatible = "qcom,sc7180-qmp-ufs-phy", + .data = &sm7150_ufsphy_cfg, + }, { .compatible = "qcom,sc7280-qmp-ufs-phy", .data = &sc7280_ufsphy_cfg, }, { @@ -1917,12 +2214,19 @@ static const struct of_device_id qmp_ufs_of_match_table[] = { .compatible = "qcom,sm8450-qmp-ufs-phy", .data = &sm8450_ufsphy_cfg, }, { + .compatible = "qcom,sm8475-qmp-ufs-phy", + .data = &sm8475_ufsphy_cfg, + }, { .compatible = "qcom,sm8550-qmp-ufs-phy", .data = &sm8550_ufsphy_cfg, }, { .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-legacy.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c index cf466f6df94d..8bf951b0490c 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb-legacy.c @@ -25,15 +25,7 @@ #include "phy-qcom-qmp-pcs-usb-v4.h" #include "phy-qcom-qmp-pcs-usb-v5.h" -/* QPHY_SW_RESET bit */ -#define SW_RESET BIT(0) -/* QPHY_POWER_DOWN_CONTROL */ -#define SW_PWRDN BIT(0) -/* QPHY_START_CONTROL bits */ -#define SERDES_START BIT(0) -#define PCS_START BIT(1) -/* QPHY_PCS_STATUS bit */ -#define PHYSTATUS BIT(6) +#include "phy-qcom-qmp-dp-com-v3.h" /* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ /* DP PHY soft reset */ @@ -49,17 +41,6 @@ #define USB3_MODE BIT(0) /* enables USB3 mode */ #define DP_MODE BIT(1) /* enables DP mode */ -/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */ -#define ARCVR_DTCT_EN BIT(0) -#define ALFPS_DTCT_EN BIT(1) -#define ARCVR_DTCT_EVENT_SEL BIT(4) - -/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */ -#define IRQ_CLEAR BIT(0) - -/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */ -#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ - #define PHY_INIT_COMPLETE_TIMEOUT 10000 struct qmp_phy_init_tbl { @@ -507,8 +488,6 @@ struct qmp_usb_legacy_offsets { /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { - int lanes; - const struct qmp_usb_legacy_offsets *offsets; /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ @@ -621,8 +600,6 @@ static const char * const qmp_phy_vreg_l[] = { }; static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { - .lanes = 2, - .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), .tx_tbl = qmp_v3_usb3_tx_tbl, @@ -641,8 +618,6 @@ static const struct qmp_phy_cfg qmp_v3_usb3phy_cfg = { }; static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { - .lanes = 2, - .serdes_tbl = qmp_v3_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(qmp_v3_usb3_serdes_tbl), .tx_tbl = qmp_v3_usb3_tx_tbl, @@ -661,8 +636,6 @@ static const struct qmp_phy_cfg sc7180_usb3phy_cfg = { }; static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { - .lanes = 2, - .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), .tx_tbl = sm8150_usb3_tx_tbl, @@ -684,8 +657,6 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { }; static const struct qmp_phy_cfg sm8250_usb3phy_cfg = { - .lanes = 2, - .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), .tx_tbl = sm8250_usb3_tx_tbl, @@ -707,8 +678,6 @@ static const struct qmp_phy_cfg sm8250_usb3phy_cfg = { }; static const struct qmp_phy_cfg sm8350_usb3phy_cfg = { - .lanes = 2, - .serdes_tbl = sm8150_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_serdes_tbl), .tx_tbl = sm8350_usb3_tx_tbl, @@ -874,10 +843,8 @@ static int qmp_usb_legacy_power_on(struct phy *phy) qmp_usb_legacy_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); qmp_usb_legacy_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - if (cfg->lanes >= 2) { - qmp_usb_legacy_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); - qmp_usb_legacy_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); - } + qmp_usb_legacy_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); + qmp_usb_legacy_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); qmp_usb_legacy_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); @@ -1180,27 +1147,11 @@ static int phy_pipe_clk_register(struct qmp_usb *qmp, struct device_node *np) return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); } -static void __iomem *qmp_usb_legacy_iomap(struct device *dev, struct device_node *np, - int index, bool exclusive) -{ - struct resource res; - - if (!exclusive) { - if (of_address_to_resource(np, index, &res)) - return IOMEM_ERR_PTR(-EINVAL); - - return devm_ioremap(dev, res.start, resource_size(&res)); - } - - return devm_of_iomap(dev, np, index, NULL); -} - static int qmp_usb_legacy_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np) { struct platform_device *pdev = to_platform_device(qmp->dev); const struct qmp_phy_cfg *cfg = qmp->cfg; struct device *dev = qmp->dev; - bool exclusive = true; qmp->serdes = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(qmp->serdes)) @@ -1224,27 +1175,22 @@ static int qmp_usb_legacy_parse_dt_legacy(struct qmp_usb *qmp, struct device_nod if (IS_ERR(qmp->rx)) return PTR_ERR(qmp->rx); - qmp->pcs = qmp_usb_legacy_iomap(dev, np, 2, exclusive); + qmp->pcs = devm_of_iomap(dev, np, 2, NULL); if (IS_ERR(qmp->pcs)) return PTR_ERR(qmp->pcs); if (cfg->pcs_usb_offset) qmp->pcs_usb = qmp->pcs + cfg->pcs_usb_offset; - if (cfg->lanes >= 2) { - qmp->tx2 = devm_of_iomap(dev, np, 3, NULL); - if (IS_ERR(qmp->tx2)) - return PTR_ERR(qmp->tx2); - - qmp->rx2 = devm_of_iomap(dev, np, 4, NULL); - if (IS_ERR(qmp->rx2)) - return PTR_ERR(qmp->rx2); + qmp->tx2 = devm_of_iomap(dev, np, 3, NULL); + if (IS_ERR(qmp->tx2)) + return PTR_ERR(qmp->tx2); - qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL); - } else { - qmp->pcs_misc = devm_of_iomap(dev, np, 3, NULL); - } + qmp->rx2 = devm_of_iomap(dev, np, 4, NULL); + if (IS_ERR(qmp->rx2)) + return PTR_ERR(qmp->rx2); + qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL); if (IS_ERR(qmp->pcs_misc)) { dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); qmp->pcs_misc = NULL; @@ -1302,6 +1248,7 @@ static int qmp_usb_legacy_probe(struct platform_device *pdev) return -ENOMEM; qmp->dev = dev; + dev_set_drvdata(dev, qmp); qmp->cfg = of_device_get_match_data(dev); if (!qmp->cfg) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c index 243cc2b9a0fb..ed646a7e705b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c @@ -19,6 +19,8 @@ #include <linux/reset.h> #include <linux/slab.h> +#include "phy-qcom-qmp-common.h" + #include "phy-qcom-qmp.h" #include "phy-qcom-qmp-pcs-misc-v3.h" #include "phy-qcom-qmp-pcs-misc-v4.h" @@ -27,67 +29,8 @@ #include "phy-qcom-qmp-pcs-usb-v6.h" #include "phy-qcom-qmp-pcs-usb-v7.h" -/* QPHY_SW_RESET bit */ -#define SW_RESET BIT(0) -/* QPHY_POWER_DOWN_CONTROL */ -#define SW_PWRDN BIT(0) -/* QPHY_START_CONTROL bits */ -#define SERDES_START BIT(0) -#define PCS_START BIT(1) -/* QPHY_PCS_STATUS bit */ -#define PHYSTATUS BIT(6) - -/* QPHY_V3_DP_COM_RESET_OVRD_CTRL register bits */ -/* DP PHY soft reset */ -#define SW_DPPHY_RESET BIT(0) -/* mux to select DP PHY reset control, 0:HW control, 1: software reset */ -#define SW_DPPHY_RESET_MUX BIT(1) -/* USB3 PHY soft reset */ -#define SW_USB3PHY_RESET BIT(2) -/* mux to select USB3 PHY reset control, 0:HW control, 1: software reset */ -#define SW_USB3PHY_RESET_MUX BIT(3) - -/* QPHY_V3_DP_COM_PHY_MODE_CTRL register bits */ -#define USB3_MODE BIT(0) /* enables USB3 mode */ -#define DP_MODE BIT(1) /* enables DP mode */ - -/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */ -#define ARCVR_DTCT_EN BIT(0) -#define ALFPS_DTCT_EN BIT(1) -#define ARCVR_DTCT_EVENT_SEL BIT(4) - -/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */ -#define IRQ_CLEAR BIT(0) - -/* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */ -#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ - #define PHY_INIT_COMPLETE_TIMEOUT 10000 -struct qmp_phy_init_tbl { - unsigned int offset; - unsigned int val; - /* - * mask of lanes for which this register is written - * for cases when second lane needs different values - */ - u8 lane_mask; -}; - -#define QMP_PHY_INIT_CFG(o, v) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = 0xff, \ - } - -#define QMP_PHY_INIT_CFG_LANE(o, v, l) \ - { \ - .offset = o, \ - .val = v, \ - .lane_mask = l, \ - } - /* set of registers with offsets different per-PHY */ enum qphy_reg_layout { /* PCS registers */ @@ -121,15 +64,6 @@ static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_MISC_CLAMP_ENABLE] = QPHY_V3_PCS_MISC_CLAMP_ENABLE, }; -static const unsigned int qmp_v3_usb3phy_regs_layout_qcm2290[QPHY_LAYOUT_SIZE] = { - [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET, - [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL, - [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS, - [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, - [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, - [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL, -}; - static const unsigned int qmp_v4_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_SW_RESET] = QPHY_V4_PCS_SW_RESET, [QPHY_START_CTRL] = QPHY_V4_PCS_START_CONTROL, @@ -403,6 +337,29 @@ static const struct qmp_phy_init_tbl msm8996_usb3_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V2_PCS_POWER_STATE_CONFIG2, 0x08), }; +static const struct qmp_phy_init_tbl qdu1000_usb3_uniphy_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG1, 0xc4), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG2, 0x89), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG3, 0x20), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_LOCK_DETECT_CONFIG6, 0x13), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCS_TX_RX_CONFIG, 0x0c), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_CDR_RESET_TIME, 0x0a), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG1, 0x88), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_ALIGN_DETECT_CONFIG2, 0x13), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG1, 0x4b), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x10), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x21), +}; + +static const struct qmp_phy_init_tbl qdu1000_usb3_uniphy_pcs_usb_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_RXEQTRAINING_DFE_TIME_S2, 0x07), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_USB3_POWER_STATE_CONFIG1, 0x6f), +}; + static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), @@ -514,115 +471,6 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60), }; -static const struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85), - QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07), -}; - -static const struct qmp_phy_init_tbl msm8998_usb3_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), -}; - -static const struct qmp_phy_init_tbl msm8998_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), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x07), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05), -}; - -static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x8a), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), -}; - static const struct qmp_phy_init_tbl sm8150_usb3_uniphy_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x1a), QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), @@ -1023,6 +871,16 @@ static const struct qmp_phy_init_tbl sdx75_usb3_uniphy_pcs_usb_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V6_PCS_USB3_RCVR_DTCT_DLY_U3_H, 0x00), }; +static const struct qmp_phy_init_tbl qcs8300_usb3_uniphy_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xa5), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_2, 0xf2), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_3, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_4, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_PI_QEC_CTRL, 0x21), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), +}; + static const struct qmp_phy_init_tbl sm8350_usb3_uniphy_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_1, 0xa5), QMP_PHY_INIT_CFG(QSERDES_V5_TX_LANE_MODE_2, 0x82), @@ -1089,99 +947,6 @@ static const struct qmp_phy_init_tbl sm8350_usb3_uniphy_pcs_usb_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V5_PCS_USB3_LFPS_DET_HIGH_COUNT_VAL, 0xf8), }; -static const struct qmp_phy_init_tbl qcm2290_usb3_serdes_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), - QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL2, 0x08), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), - QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), - QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde), - QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07), - QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), - QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_INITVAL, 0x80), - QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x01), -}; - -static const struct qmp_phy_init_tbl qcm2290_usb3_tx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0xc6), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x00), -}; - -static const struct qmp_phy_init_tbl qcm2290_usb3_rx_tbl[] = { - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0a), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), - QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00), -}; - -static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x17), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x85), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), - QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88), -}; - static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1a), QMP_PHY_INIT_CFG(QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), @@ -1234,6 +999,40 @@ static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x0e), }; +static const struct qmp_phy_init_tbl qcs8300_usb3_uniphy_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xec), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0xbd), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH2, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_LOW, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xa9), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x7b), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xe4), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_HIGH, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_01_LOW, 0x64), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x99), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_THRESH2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SB2_GAIN2, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FO_GAIN, 0x09), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL1, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x47), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_CNTRL, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_DFE_CTLE_POST_CAL_OFFSET, 0x38), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_GM_CAL, 0x19), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_SIGDET_ENABLES, 0x00), +}; + static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xdc), QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_MODE_00_HIGH3, 0xbd), @@ -1253,7 +1052,7 @@ static const struct qmp_phy_init_tbl sc8280xp_usb3_uniphy_rx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x2f), QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0xff), QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x0f), - QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_SO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V5_RX_UCDR_FO_GAIN, 0x0a), QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL1, 0x54), QMP_PHY_INIT_CFG(QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x0f), QMP_PHY_INIT_CFG(QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f), @@ -1448,15 +1247,10 @@ struct qmp_usb_offsets { u16 pcs_usb; u16 tx; u16 rx; - /* for PHYs with >= 2 lanes */ - u16 tx2; - u16 rx2; }; /* struct qmp_phy_cfg - per-PHY initialization config */ struct qmp_phy_cfg { - int lanes; - const struct qmp_usb_offsets *offsets; /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ @@ -1496,8 +1290,6 @@ struct qmp_usb { void __iomem *pcs_usb; void __iomem *tx; void __iomem *rx; - void __iomem *tx2; - void __iomem *rx2; struct clk *pipe_clk; struct clk_bulk_data *clks; @@ -1556,29 +1348,27 @@ static const char * const qmp_phy_vreg_l[] = { "vdda-phy", "vdda-pll", }; -static const struct qmp_usb_offsets qmp_usb_offsets_ipq9574 = { +static const struct qmp_usb_offsets qmp_usb_offsets_v3 = { .serdes = 0, .pcs = 0x800, - .pcs_usb = 0x800, + .pcs_misc = 0x600, .tx = 0x200, .rx = 0x400, }; -static const struct qmp_usb_offsets qmp_usb_offsets_v3 = { +static const struct qmp_usb_offsets qmp_usb_offsets_ipq9574 = { .serdes = 0, - .pcs = 0x600, + .pcs = 0x800, + .pcs_usb = 0x800, .tx = 0x200, .rx = 0x400, }; -static const struct qmp_usb_offsets qmp_usb_offsets_v3_qcm2290 = { - .serdes = 0x0, - .pcs = 0xc00, - .pcs_misc = 0xa00, +static const struct qmp_usb_offsets qmp_usb_offsets_v3_msm8996 = { + .serdes = 0, + .pcs = 0x600, .tx = 0x200, .rx = 0x400, - .tx2 = 0x600, - .rx2 = 0x800, }; static const struct qmp_usb_offsets qmp_usb_offsets_v4 = { @@ -1613,9 +1403,23 @@ static const struct qmp_usb_offsets qmp_usb_offsets_v7 = { .rx = 0x1000, }; -static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = { - .lanes = 1, +static const struct qmp_phy_cfg ipq6018_usb3phy_cfg = { + .offsets = &qmp_usb_offsets_v3, + .serdes_tbl = ipq9574_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(ipq9574_usb3_serdes_tbl), + .tx_tbl = msm8996_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(msm8996_usb3_tx_tbl), + .rx_tbl = ipq8074_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(ipq8074_usb3_rx_tbl), + .pcs_tbl = ipq8074_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(ipq8074_usb3_pcs_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout, +}; + +static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = { .offsets = &qmp_usb_offsets_v3, .serdes_tbl = ipq8074_usb3_serdes_tbl, @@ -1632,8 +1436,6 @@ static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = { }; static const struct qmp_phy_cfg ipq9574_usb3phy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_ipq9574, .serdes_tbl = ipq9574_usb3_serdes_tbl, @@ -1650,9 +1452,7 @@ static const struct qmp_phy_cfg ipq9574_usb3phy_cfg = { }; static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { - .lanes = 1, - - .offsets = &qmp_usb_offsets_v3, + .offsets = &qmp_usb_offsets_v3_msm8996, .serdes_tbl = msm8996_usb3_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(msm8996_usb3_serdes_tbl), @@ -1667,9 +1467,28 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = { .regs = qmp_v2_usb3phy_regs_layout, }; -static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = { - .lanes = 1, +static const struct qmp_phy_cfg qdu1000_usb3_uniphy_cfg = { + .offsets = &qmp_usb_offsets_v5, + + .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sm8150_usb3_uniphy_serdes_tbl), + .tx_tbl = sm8350_usb3_uniphy_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sm8350_usb3_uniphy_tx_tbl), + .rx_tbl = sm8350_usb3_uniphy_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sm8350_usb3_uniphy_rx_tbl), + .pcs_tbl = qdu1000_usb3_uniphy_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qdu1000_usb3_uniphy_pcs_tbl), + .pcs_usb_tbl = qdu1000_usb3_uniphy_pcs_usb_tbl, + .pcs_usb_tbl_num = ARRAY_SIZE(qdu1000_usb3_uniphy_pcs_usb_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v4_usb3phy_regs_layout, + .pcs_usb_offset = 0x1000, + .has_pwrdn_delay = true, +}; + +static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = { .offsets = &qmp_usb_offsets_v5, .serdes_tbl = sc8280xp_usb3_uniphy_serdes_tbl, @@ -1687,9 +1506,25 @@ static const struct qmp_phy_cfg sa8775p_usb3_uniphy_cfg = { .regs = qmp_v5_usb3phy_regs_layout, }; -static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = { - .lanes = 1, +static const struct qmp_phy_cfg qcs8300_usb3_uniphy_cfg = { + .offsets = &qmp_usb_offsets_v5, + + .serdes_tbl = sc8280xp_usb3_uniphy_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sc8280xp_usb3_uniphy_serdes_tbl), + .tx_tbl = qcs8300_usb3_uniphy_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcs8300_usb3_uniphy_tx_tbl), + .rx_tbl = qcs8300_usb3_uniphy_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qcs8300_usb3_uniphy_rx_tbl), + .pcs_tbl = sa8775p_usb3_uniphy_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sa8775p_usb3_uniphy_pcs_tbl), + .pcs_usb_tbl = sa8775p_usb3_uniphy_pcs_usb_tbl, + .pcs_usb_tbl_num = ARRAY_SIZE(sa8775p_usb3_uniphy_pcs_usb_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v5_usb3phy_regs_layout, +}; +static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = { .offsets = &qmp_usb_offsets_v5, .serdes_tbl = sc8280xp_usb3_uniphy_serdes_tbl, @@ -1708,8 +1543,6 @@ static const struct qmp_phy_cfg sc8280xp_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v3, .serdes_tbl = qmp_v3_usb3_uniphy_serdes_tbl, @@ -1727,27 +1560,7 @@ static const struct qmp_phy_cfg qmp_v3_usb3_uniphy_cfg = { .has_pwrdn_delay = true, }; -static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { - .lanes = 2, - - .offsets = &qmp_usb_offsets_v3_qcm2290, - - .serdes_tbl = msm8998_usb3_serdes_tbl, - .serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl), - .tx_tbl = msm8998_usb3_tx_tbl, - .tx_tbl_num = ARRAY_SIZE(msm8998_usb3_tx_tbl), - .rx_tbl = msm8998_usb3_rx_tbl, - .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), - .pcs_tbl = msm8998_usb3_pcs_tbl, - .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v3_usb3phy_regs_layout, -}; - static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v4, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1769,8 +1582,6 @@ static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v4, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1792,8 +1603,6 @@ static const struct qmp_phy_cfg sm8250_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v4, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1815,8 +1624,6 @@ static const struct qmp_phy_cfg sdx55_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v5, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1838,7 +1645,6 @@ static const struct qmp_phy_cfg sdx65_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sdx75_usb3_uniphy_cfg = { - .lanes = 1, .offsets = &qmp_usb_offsets_v6, .serdes_tbl = sdx75_usb3_uniphy_serdes_tbl, @@ -1860,8 +1666,6 @@ static const struct qmp_phy_cfg sdx75_usb3_uniphy_cfg = { }; static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v5, .serdes_tbl = sm8150_usb3_uniphy_serdes_tbl, @@ -1882,27 +1686,7 @@ static const struct qmp_phy_cfg sm8350_usb3_uniphy_cfg = { .has_pwrdn_delay = true, }; -static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { - .lanes = 2, - - .offsets = &qmp_usb_offsets_v3_qcm2290, - - .serdes_tbl = qcm2290_usb3_serdes_tbl, - .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), - .tx_tbl = qcm2290_usb3_tx_tbl, - .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), - .rx_tbl = qcm2290_usb3_rx_tbl, - .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), - .pcs_tbl = qcm2290_usb3_pcs_tbl, - .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), - .vreg_list = qmp_phy_vreg_l, - .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), - .regs = qmp_v3_usb3phy_regs_layout_qcm2290, -}; - static const struct qmp_phy_cfg x1e80100_usb3_uniphy_cfg = { - .lanes = 1, - .offsets = &qmp_usb_offsets_v7, .serdes_tbl = x1e80100_usb3_uniphy_serdes_tbl, @@ -1920,32 +1704,6 @@ static const struct qmp_phy_cfg x1e80100_usb3_uniphy_cfg = { .regs = qmp_v7_usb3phy_regs_layout, }; -static void qmp_usb_configure_lane(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num, - u8 lane_mask) -{ - int i; - const struct qmp_phy_init_tbl *t = tbl; - - if (!t) - return; - - for (i = 0; i < num; i++, t++) { - if (!(t->lane_mask & lane_mask)) - continue; - - writel(t->val, base + t->offset); - } -} - -static void qmp_usb_configure(void __iomem *base, - const struct qmp_phy_init_tbl tbl[], - int num) -{ - qmp_usb_configure_lane(base, tbl, num, 0xff); -} - static int qmp_usb_serdes_init(struct qmp_usb *qmp) { const struct qmp_phy_cfg *cfg = qmp->cfg; @@ -1953,7 +1711,7 @@ static int qmp_usb_serdes_init(struct qmp_usb *qmp) const struct qmp_phy_init_tbl *serdes_tbl = cfg->serdes_tbl; int serdes_tbl_num = cfg->serdes_tbl_num; - qmp_usb_configure(serdes, serdes_tbl, serdes_tbl_num); + qmp_configure(qmp->dev, serdes, serdes_tbl, serdes_tbl_num); return 0; } @@ -2034,18 +1792,13 @@ static int qmp_usb_power_on(struct phy *phy) } /* Tx, Rx, and PCS configurations */ - qmp_usb_configure_lane(tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); - qmp_usb_configure_lane(rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - - if (cfg->lanes >= 2) { - qmp_usb_configure_lane(qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); - qmp_usb_configure_lane(qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); - } + qmp_configure_lane(qmp->dev, tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_configure_lane(qmp->dev, rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); - qmp_usb_configure(pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + qmp_configure(qmp->dev, pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); if (pcs_usb) - qmp_usb_configure(pcs_usb, cfg->pcs_usb_tbl, cfg->pcs_usb_tbl_num); + qmp_configure(qmp->dev, pcs_usb, cfg->pcs_usb_tbl, cfg->pcs_usb_tbl_num); if (cfg->has_pwrdn_delay) usleep_range(10, 20); @@ -2353,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); @@ -2388,7 +2145,6 @@ static int qmp_usb_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np) /* * Get memory resources for the PHY: * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2. - * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 * For single lane PHYs: pcs_misc (optional) -> 3. */ qmp->tx = devm_of_iomap(dev, np, 0, NULL); @@ -2406,19 +2162,7 @@ static int qmp_usb_parse_dt_legacy(struct qmp_usb *qmp, struct device_node *np) if (cfg->pcs_usb_offset) qmp->pcs_usb = qmp->pcs + cfg->pcs_usb_offset; - if (cfg->lanes >= 2) { - qmp->tx2 = devm_of_iomap(dev, np, 3, NULL); - if (IS_ERR(qmp->tx2)) - return PTR_ERR(qmp->tx2); - - qmp->rx2 = devm_of_iomap(dev, np, 4, NULL); - if (IS_ERR(qmp->rx2)) - return PTR_ERR(qmp->rx2); - - qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL); - } else { - qmp->pcs_misc = devm_of_iomap(dev, np, 3, NULL); - } + qmp->pcs_misc = devm_of_iomap(dev, np, 3, NULL); if (IS_ERR(qmp->pcs_misc)) { dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); @@ -2470,11 +2214,6 @@ static int qmp_usb_parse_dt(struct qmp_usb *qmp) qmp->tx = base + offs->tx; qmp->rx = base + offs->rx; - if (cfg->lanes >= 2) { - qmp->tx2 = base + offs->tx2; - qmp->rx2 = base + offs->rx2; - } - ret = qmp_usb_clk_init(qmp); if (ret) return ret; @@ -2506,6 +2245,7 @@ static int qmp_usb_probe(struct platform_device *pdev) return -ENOMEM; qmp->dev = dev; + dev_set_drvdata(dev, qmp); qmp->cfg = of_device_get_match_data(dev); if (!qmp->cfg) @@ -2562,8 +2302,11 @@ 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 = &ipq8074_usb3phy_cfg, + .data = &ipq6018_usb3phy_cfg, }, { .compatible = "qcom,ipq8074-qmp-usb3-phy", .data = &ipq8074_usb3phy_cfg, @@ -2574,15 +2317,18 @@ static const struct of_device_id qmp_usb_of_match_table[] = { .compatible = "qcom,msm8996-qmp-usb3-phy", .data = &msm8996_usb3phy_cfg, }, { - .compatible = "qcom,msm8998-qmp-usb3-phy", - .data = &msm8998_usb3phy_cfg, + .compatible = "qcom,qcs8300-qmp-usb3-uni-phy", + .data = &qcs8300_usb3_uniphy_cfg, }, { - .compatible = "qcom,qcm2290-qmp-usb3-phy", - .data = &qcm2290_usb3phy_cfg, + .compatible = "qcom,qdu1000-qmp-usb3-uni-phy", + .data = &qdu1000_usb3_uniphy_cfg, }, { .compatible = "qcom,sa8775p-qmp-usb3-uni-phy", .data = &sa8775p_usb3_uniphy_cfg, }, { + .compatible = "qcom,sc8180x-qmp-usb3-uni-phy", + .data = &sm8150_usb3_uniphy_cfg, + }, { .compatible = "qcom,sc8280xp-qmp-usb3-uni-phy", .data = &sc8280xp_usb3_uniphy_cfg, }, { @@ -2598,9 +2344,6 @@ static const struct of_device_id qmp_usb_of_match_table[] = { .compatible = "qcom,sdx75-qmp-usb3-uni-phy", .data = &sdx75_usb3_uniphy_cfg, }, { - .compatible = "qcom,sm6115-qmp-usb3-phy", - .data = &qcm2290_usb3phy_cfg, - }, { .compatible = "qcom,sm8150-qmp-usb3-uni-phy", .data = &sm8150_usb3_uniphy_cfg, }, { diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c new file mode 100644 index 000000000000..5e7fcb26744a --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c @@ -0,0 +1,1154 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, 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/iopoll.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> +#include <linux/slab.h> +#include <linux/usb/typec.h> +#include <linux/usb/typec_mux.h> + +#include "phy-qcom-qmp-common.h" + +#include "phy-qcom-qmp.h" +#include "phy-qcom-qmp-pcs-misc-v3.h" + +#define PHY_INIT_COMPLETE_TIMEOUT 10000 + +/* set of registers with offsets different per-PHY */ +enum qphy_reg_layout { + /* PCS registers */ + QPHY_SW_RESET, + QPHY_START_CTRL, + QPHY_PCS_STATUS, + QPHY_PCS_AUTONOMOUS_MODE_CTRL, + QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR, + QPHY_PCS_POWER_DOWN_CONTROL, + /* Keep last to ensure regs_layout arrays are properly initialized */ + QPHY_LAYOUT_SIZE +}; + +static const unsigned int qmp_v3_usb3phy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS, + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL, +}; + +static const unsigned int qmp_v3_usb3phy_regs_layout_qcm2290[QPHY_LAYOUT_SIZE] = { + [QPHY_SW_RESET] = QPHY_V3_PCS_SW_RESET, + [QPHY_START_CTRL] = QPHY_V3_PCS_START_CONTROL, + [QPHY_PCS_STATUS] = QPHY_V3_PCS_PCS_STATUS, + [QPHY_PCS_AUTONOMOUS_MODE_CTRL] = QPHY_V3_PCS_AUTONOMOUS_MODE_CTRL, + [QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR] = QPHY_V3_PCS_LFPS_RXTERM_IRQ_CLEAR, + [QPHY_PCS_POWER_DOWN_CONTROL] = QPHY_V3_PCS_POWER_DOWN_CONTROL, +}; + +static const struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85), + QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07), +}; + +static const struct qmp_phy_init_tbl msm8998_usb3_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), +}; + +static const struct qmp_phy_init_tbl msm8998_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), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05), +}; + +static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V1, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x8a), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), +}; + +static const struct qmp_phy_init_tbl qcm2290_usb3_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06), + QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL2, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0x15), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x34), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0xde), + QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x07), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_INITVAL, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x01), +}; + +static const struct qmp_phy_init_tbl qcm2290_usb3_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0xc6), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_RX, 0x00), +}; + +static const struct qmp_phy_init_tbl qcm2290_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00), +}; + +/* the only difference is QSERDES_V3_RX_UCDR_PI_CONTROLS */ +static const struct qmp_phy_init_tbl sdm660_usb3_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x77), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x00), +}; + +static const struct qmp_phy_init_tbl qcm2290_usb3_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x17), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x85), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00), + QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x88), +}; + +struct qmp_usbc_offsets { + u16 serdes; + u16 pcs; + u16 pcs_misc; + u16 tx; + u16 rx; + /* for PHYs with >= 2 lanes */ + u16 tx2; + u16 rx2; +}; + +/* struct qmp_phy_cfg - per-PHY initialization config */ +struct qmp_phy_cfg { + const struct qmp_usbc_offsets *offsets; + + /* Init sequence for PHY blocks - serdes, tx, rx, pcs */ + const struct qmp_phy_init_tbl *serdes_tbl; + int serdes_tbl_num; + const struct qmp_phy_init_tbl *tx_tbl; + int tx_tbl_num; + const struct qmp_phy_init_tbl *rx_tbl; + int rx_tbl_num; + const struct qmp_phy_init_tbl *pcs_tbl; + int pcs_tbl_num; + + /* regulators to be requested */ + const char * const *vreg_list; + int num_vregs; + + /* array of registers with different offsets */ + const unsigned int *regs; +}; + +struct qmp_usbc { + struct device *dev; + + const struct qmp_phy_cfg *cfg; + + void __iomem *serdes; + void __iomem *pcs; + void __iomem *pcs_misc; + void __iomem *tx; + void __iomem *rx; + void __iomem *tx2; + void __iomem *rx2; + + struct regmap *tcsr_map; + u32 vls_clamp_reg; + + struct clk *pipe_clk; + struct clk_bulk_data *clks; + int num_clks; + int num_resets; + struct reset_control_bulk_data *resets; + struct regulator_bulk_data *vregs; + + struct mutex phy_mutex; + + enum phy_mode mode; + unsigned int usb_init_count; + + struct phy *phy; + + struct clk_fixed_rate pipe_clk_fixed; + + struct typec_switch_dev *sw; + enum typec_orientation orientation; +}; + +static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg |= val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +static inline void qphy_clrbits(void __iomem *base, u32 offset, u32 val) +{ + u32 reg; + + reg = readl(base + offset); + reg &= ~val; + writel(reg, base + offset); + + /* ensure that above write is through */ + readl(base + offset); +} + +/* list of clocks required by phy */ +static const char * const qmp_usbc_phy_clk_l[] = { + "aux", "cfg_ahb", "ref", "com_aux", +}; + +/* list of resets */ +static const char * const usb3phy_legacy_reset_l[] = { + "phy", "common", +}; + +static const char * const usb3phy_reset_l[] = { + "phy_phy", "phy", +}; + +/* list of regulators */ +static const char * const qmp_phy_vreg_l[] = { + "vdda-phy", "vdda-pll", +}; + +static const struct qmp_usbc_offsets qmp_usbc_offsets_v3_qcm2290 = { + .serdes = 0x0, + .pcs = 0xc00, + .pcs_misc = 0xa00, + .tx = 0x200, + .rx = 0x400, + .tx2 = 0x600, + .rx2 = 0x800, +}; + +static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { + .offsets = &qmp_usbc_offsets_v3_qcm2290, + + .serdes_tbl = msm8998_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl), + .tx_tbl = msm8998_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(msm8998_usb3_tx_tbl), + .rx_tbl = msm8998_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl), + .pcs_tbl = msm8998_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout, +}; + +static const struct qmp_phy_cfg qcm2290_usb3phy_cfg = { + .offsets = &qmp_usbc_offsets_v3_qcm2290, + + .serdes_tbl = qcm2290_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), + .tx_tbl = qcm2290_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), + .rx_tbl = qcm2290_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(qcm2290_usb3_rx_tbl), + .pcs_tbl = qcm2290_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout_qcm2290, +}; + +static const struct qmp_phy_cfg sdm660_usb3phy_cfg = { + .offsets = &qmp_usbc_offsets_v3_qcm2290, + + .serdes_tbl = qcm2290_usb3_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qcm2290_usb3_serdes_tbl), + .tx_tbl = qcm2290_usb3_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qcm2290_usb3_tx_tbl), + .rx_tbl = sdm660_usb3_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sdm660_usb3_rx_tbl), + .pcs_tbl = qcm2290_usb3_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(qcm2290_usb3_pcs_tbl), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout_qcm2290, +}; + +static int qmp_usbc_init(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = qmp->pcs; + u32 val = 0; + int ret; + + ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs); + if (ret) { + dev_err(qmp->dev, "failed to enable regulators, err=%d\n", ret); + return ret; + } + + ret = reset_control_bulk_assert(qmp->num_resets, qmp->resets); + if (ret) { + dev_err(qmp->dev, "reset assert failed\n"); + goto err_disable_regulators; + } + + ret = reset_control_bulk_deassert(qmp->num_resets, qmp->resets); + if (ret) { + dev_err(qmp->dev, "reset deassert failed\n"); + goto err_disable_regulators; + } + + ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); + if (ret) + goto err_assert_reset; + + qphy_setbits(pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], SW_PWRDN); + +#define SW_PORTSELECT_VAL BIT(0) +#define SW_PORTSELECT_MUX BIT(1) + /* Use software based port select and switch on typec orientation */ + val = SW_PORTSELECT_MUX; + if (qmp->orientation == TYPEC_ORIENTATION_REVERSE) + val |= SW_PORTSELECT_VAL; + writel(val, qmp->pcs_misc); + + return 0; + +err_assert_reset: + reset_control_bulk_assert(qmp->num_resets, qmp->resets); +err_disable_regulators: + regulator_bulk_disable(cfg->num_vregs, qmp->vregs); + + return ret; +} + +static int qmp_usbc_exit(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + reset_control_bulk_assert(qmp->num_resets, qmp->resets); + + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); + + regulator_bulk_disable(cfg->num_vregs, qmp->vregs); + + return 0; +} + +static int qmp_usbc_power_on(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *status; + unsigned int val; + int ret; + + qmp_configure(qmp->dev, qmp->serdes, cfg->serdes_tbl, + cfg->serdes_tbl_num); + + ret = clk_prepare_enable(qmp->pipe_clk); + if (ret) { + dev_err(qmp->dev, "pipe_clk enable failed err=%d\n", ret); + return ret; + } + + /* Tx, Rx, and PCS configurations */ + qmp_configure_lane(qmp->dev, qmp->tx, cfg->tx_tbl, cfg->tx_tbl_num, 1); + qmp_configure_lane(qmp->dev, qmp->rx, cfg->rx_tbl, cfg->rx_tbl_num, 1); + + qmp_configure_lane(qmp->dev, qmp->tx2, cfg->tx_tbl, cfg->tx_tbl_num, 2); + qmp_configure_lane(qmp->dev, qmp->rx2, cfg->rx_tbl, cfg->rx_tbl_num, 2); + + qmp_configure(qmp->dev, qmp->pcs, cfg->pcs_tbl, cfg->pcs_tbl_num); + + /* Pull PHY out of reset state */ + qphy_clrbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); + + /* start SerDes and Phy-Coding-Sublayer */ + qphy_setbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], SERDES_START | PCS_START); + + status = qmp->pcs + cfg->regs[QPHY_PCS_STATUS]; + ret = readl_poll_timeout(status, val, !(val & PHYSTATUS), 200, + PHY_INIT_COMPLETE_TIMEOUT); + if (ret) { + dev_err(qmp->dev, "phy initialization timed-out\n"); + goto err_disable_pipe_clk; + } + + return 0; + +err_disable_pipe_clk: + clk_disable_unprepare(qmp->pipe_clk); + + return ret; +} + +static int qmp_usbc_power_off(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + const struct qmp_phy_cfg *cfg = qmp->cfg; + + clk_disable_unprepare(qmp->pipe_clk); + + /* PHY reset */ + qphy_setbits(qmp->pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); + + /* stop SerDes and Phy-Coding-Sublayer */ + qphy_clrbits(qmp->pcs, cfg->regs[QPHY_START_CTRL], + SERDES_START | PCS_START); + + /* Put PHY into POWER DOWN state: active low */ + qphy_clrbits(qmp->pcs, cfg->regs[QPHY_PCS_POWER_DOWN_CONTROL], + SW_PWRDN); + + return 0; +} + +static int qmp_usbc_enable(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + int ret; + + mutex_lock(&qmp->phy_mutex); + + ret = qmp_usbc_init(phy); + if (ret) + goto out_unlock; + + ret = qmp_usbc_power_on(phy); + if (ret) { + qmp_usbc_exit(phy); + goto out_unlock; + } + + qmp->usb_init_count++; +out_unlock: + mutex_unlock(&qmp->phy_mutex); + + return ret; +} + +static int qmp_usbc_disable(struct phy *phy) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + int ret; + + qmp->usb_init_count--; + ret = qmp_usbc_power_off(phy); + if (ret) + return ret; + return qmp_usbc_exit(phy); +} + +static int qmp_usbc_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct qmp_usbc *qmp = phy_get_drvdata(phy); + + qmp->mode = mode; + + return 0; +} + +static const struct phy_ops qmp_usbc_phy_ops = { + .init = qmp_usbc_enable, + .exit = qmp_usbc_disable, + .set_mode = qmp_usbc_set_mode, + .owner = THIS_MODULE, +}; + +static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = qmp->pcs; + u32 intr_mask; + + if (qmp->mode == PHY_MODE_USB_HOST_SS || + qmp->mode == PHY_MODE_USB_DEVICE_SS) + intr_mask = ARCVR_DTCT_EN | ALFPS_DTCT_EN; + else + intr_mask = ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL; + + /* Clear any pending interrupts status */ + qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); + /* Writing 1 followed by 0 clears the interrupt */ + qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); + + qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], + ARCVR_DTCT_EN | ALFPS_DTCT_EN | ARCVR_DTCT_EVENT_SEL); + + /* Enable required PHY autonomous mode interrupts */ + qphy_setbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], intr_mask); + + /* Enable i/o clamp_n for autonomous mode */ + if (qmp->tcsr_map && qmp->vls_clamp_reg) + regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 1); +} + +static void qmp_usbc_disable_autonomous_mode(struct qmp_usbc *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + void __iomem *pcs = qmp->pcs; + + /* Disable i/o clamp_n on resume for normal mode */ + if (qmp->tcsr_map && qmp->vls_clamp_reg) + regmap_write(qmp->tcsr_map, qmp->vls_clamp_reg, 0); + + qphy_clrbits(pcs, cfg->regs[QPHY_PCS_AUTONOMOUS_MODE_CTRL], + ARCVR_DTCT_EN | ARCVR_DTCT_EVENT_SEL | ALFPS_DTCT_EN); + + qphy_setbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); + /* Writing 1 followed by 0 clears the interrupt */ + qphy_clrbits(pcs, cfg->regs[QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR], IRQ_CLEAR); +} + +static int __maybe_unused qmp_usbc_runtime_suspend(struct device *dev) +{ + struct qmp_usbc *qmp = dev_get_drvdata(dev); + + dev_vdbg(dev, "Suspending QMP phy, mode:%d\n", qmp->mode); + + if (!qmp->phy->init_count) { + dev_vdbg(dev, "PHY not initialized, bailing out\n"); + return 0; + } + + qmp_usbc_enable_autonomous_mode(qmp); + + clk_disable_unprepare(qmp->pipe_clk); + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); + + return 0; +} + +static int __maybe_unused qmp_usbc_runtime_resume(struct device *dev) +{ + struct qmp_usbc *qmp = dev_get_drvdata(dev); + int ret = 0; + + dev_vdbg(dev, "Resuming QMP phy, mode:%d\n", qmp->mode); + + if (!qmp->phy->init_count) { + dev_vdbg(dev, "PHY not initialized, bailing out\n"); + return 0; + } + + ret = clk_bulk_prepare_enable(qmp->num_clks, qmp->clks); + if (ret) + return ret; + + ret = clk_prepare_enable(qmp->pipe_clk); + if (ret) { + dev_err(dev, "pipe_clk enable failed, err=%d\n", ret); + clk_bulk_disable_unprepare(qmp->num_clks, qmp->clks); + return ret; + } + + qmp_usbc_disable_autonomous_mode(qmp); + + return 0; +} + +static const struct dev_pm_ops qmp_usbc_pm_ops = { + SET_RUNTIME_PM_OPS(qmp_usbc_runtime_suspend, + qmp_usbc_runtime_resume, NULL) +}; + +static int qmp_usbc_vreg_init(struct qmp_usbc *qmp) +{ + const struct qmp_phy_cfg *cfg = qmp->cfg; + struct device *dev = qmp->dev; + int num = cfg->num_vregs; + int i; + + qmp->vregs = devm_kcalloc(dev, num, sizeof(*qmp->vregs), GFP_KERNEL); + if (!qmp->vregs) + return -ENOMEM; + + for (i = 0; i < num; i++) + qmp->vregs[i].supply = cfg->vreg_list[i]; + + return devm_regulator_bulk_get(dev, num, qmp->vregs); +} + +static int qmp_usbc_reset_init(struct qmp_usbc *qmp, + const char *const *reset_list, + int num_resets) +{ + struct device *dev = qmp->dev; + int i; + int ret; + + qmp->resets = devm_kcalloc(dev, num_resets, + sizeof(*qmp->resets), GFP_KERNEL); + if (!qmp->resets) + return -ENOMEM; + + for (i = 0; i < num_resets; i++) + qmp->resets[i].id = reset_list[i]; + + qmp->num_resets = num_resets; + + ret = devm_reset_control_bulk_get_exclusive(dev, num_resets, qmp->resets); + if (ret) + return dev_err_probe(dev, ret, "failed to get resets\n"); + + return 0; +} + +static int qmp_usbc_clk_init(struct qmp_usbc *qmp) +{ + struct device *dev = qmp->dev; + int num = ARRAY_SIZE(qmp_usbc_phy_clk_l); + int i; + + qmp->clks = devm_kcalloc(dev, num, sizeof(*qmp->clks), GFP_KERNEL); + if (!qmp->clks) + return -ENOMEM; + + for (i = 0; i < num; i++) + qmp->clks[i].id = qmp_usbc_phy_clk_l[i]; + + qmp->num_clks = num; + + return devm_clk_bulk_get_optional(dev, num, qmp->clks); +} + +static void phy_clk_release_provider(void *res) +{ + of_clk_del_provider(res); +} + +/* + * 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 int phy_pipe_clk_register(struct qmp_usbc *qmp, struct device_node *np) +{ + struct clk_fixed_rate *fixed = &qmp->pipe_clk_fixed; + struct clk_init_data init = { }; + int ret; + + ret = of_property_read_string(np, "clock-output-names", &init.name); + if (ret) { + dev_err(qmp->dev, "%pOFn: No clock-output-names\n", np); + return ret; + } + + init.ops = &clk_fixed_rate_ops; + + /* controllers using QMP phys use 125MHz pipe clock interface */ + fixed->fixed_rate = 125000000; + fixed->hw.init = &init; + + ret = devm_clk_hw_register(qmp->dev, &fixed->hw); + if (ret) + return ret; + + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &fixed->hw); + if (ret) + return ret; + + /* + * Roll a devm action because the clock provider is the child node, but + * the child node is not actually a device. + */ + return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, np); +} + +#if IS_ENABLED(CONFIG_TYPEC) +static int qmp_usbc_typec_switch_set(struct typec_switch_dev *sw, + enum typec_orientation orientation) +{ + struct qmp_usbc *qmp = typec_switch_get_drvdata(sw); + + if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE) + return 0; + + mutex_lock(&qmp->phy_mutex); + qmp->orientation = orientation; + + if (qmp->usb_init_count) { + qmp_usbc_power_off(qmp->phy); + qmp_usbc_exit(qmp->phy); + + qmp_usbc_init(qmp->phy); + qmp_usbc_power_on(qmp->phy); + } + + mutex_unlock(&qmp->phy_mutex); + + return 0; +} + +static void qmp_usbc_typec_unregister(void *data) +{ + struct qmp_usbc *qmp = data; + + typec_switch_unregister(qmp->sw); +} + +static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) +{ + struct typec_switch_desc sw_desc = {}; + struct device *dev = qmp->dev; + + sw_desc.drvdata = qmp; + sw_desc.fwnode = dev->fwnode; + sw_desc.set = qmp_usbc_typec_switch_set; + qmp->sw = typec_switch_register(dev, &sw_desc); + if (IS_ERR(qmp->sw)) { + dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw); + return PTR_ERR(qmp->sw); + } + + return devm_add_action_or_reset(dev, qmp_usbc_typec_unregister, qmp); +} +#else +static int qmp_usbc_typec_switch_register(struct qmp_usbc *qmp) +{ + return 0; +} +#endif + +static int qmp_usbc_parse_dt_legacy(struct qmp_usbc *qmp, struct device_node *np) +{ + struct platform_device *pdev = to_platform_device(qmp->dev); + struct device *dev = qmp->dev; + int ret; + + qmp->serdes = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(qmp->serdes)) + return PTR_ERR(qmp->serdes); + + /* + * Get memory resources for the PHY: + * Resources are indexed as: tx -> 0; rx -> 1; pcs -> 2. + * For dual lane PHYs: tx2 -> 3, rx2 -> 4, pcs_misc (optional) -> 5 + * For single lane PHYs: pcs_misc (optional) -> 3. + */ + qmp->tx = devm_of_iomap(dev, np, 0, NULL); + if (IS_ERR(qmp->tx)) + return PTR_ERR(qmp->tx); + + qmp->rx = devm_of_iomap(dev, np, 1, NULL); + if (IS_ERR(qmp->rx)) + return PTR_ERR(qmp->rx); + + qmp->pcs = devm_of_iomap(dev, np, 2, NULL); + if (IS_ERR(qmp->pcs)) + return PTR_ERR(qmp->pcs); + + qmp->tx2 = devm_of_iomap(dev, np, 3, NULL); + if (IS_ERR(qmp->tx2)) + return PTR_ERR(qmp->tx2); + + qmp->rx2 = devm_of_iomap(dev, np, 4, NULL); + if (IS_ERR(qmp->rx2)) + return PTR_ERR(qmp->rx2); + + qmp->pcs_misc = devm_of_iomap(dev, np, 5, NULL); + if (IS_ERR(qmp->pcs_misc)) { + dev_vdbg(dev, "PHY pcs_misc-reg not used\n"); + qmp->pcs_misc = NULL; + } + + qmp->pipe_clk = devm_get_clk_from_child(dev, np, NULL); + if (IS_ERR(qmp->pipe_clk)) { + return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), + "failed to get pipe clock\n"); + } + + ret = devm_clk_bulk_get_all(qmp->dev, &qmp->clks); + if (ret < 0) + return ret; + + qmp->num_clks = ret; + + ret = qmp_usbc_reset_init(qmp, usb3phy_legacy_reset_l, + ARRAY_SIZE(usb3phy_legacy_reset_l)); + if (ret) + return ret; + + return 0; +} + +static int qmp_usbc_parse_dt(struct qmp_usbc *qmp) +{ + struct platform_device *pdev = to_platform_device(qmp->dev); + const struct qmp_phy_cfg *cfg = qmp->cfg; + const struct qmp_usbc_offsets *offs = cfg->offsets; + struct device *dev = qmp->dev; + void __iomem *base; + int ret; + + if (!offs) + return -EINVAL; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + qmp->serdes = base + offs->serdes; + qmp->pcs = base + offs->pcs; + if (offs->pcs_misc) + qmp->pcs_misc = base + offs->pcs_misc; + qmp->tx = base + offs->tx; + qmp->rx = base + offs->rx; + + qmp->tx2 = base + offs->tx2; + qmp->rx2 = base + offs->rx2; + + ret = qmp_usbc_clk_init(qmp); + if (ret) + return ret; + + qmp->pipe_clk = devm_clk_get(dev, "pipe"); + if (IS_ERR(qmp->pipe_clk)) { + return dev_err_probe(dev, PTR_ERR(qmp->pipe_clk), + "failed to get pipe clock\n"); + } + + ret = qmp_usbc_reset_init(qmp, usb3phy_reset_l, + ARRAY_SIZE(usb3phy_reset_l)); + if (ret) + return ret; + + return 0; +} + +static int qmp_usbc_parse_vls_clamp(struct qmp_usbc *qmp) +{ + struct of_phandle_args tcsr_args; + struct device *dev = qmp->dev; + int ret; + + /* for backwards compatibility ignore if there is no property */ + ret = of_parse_phandle_with_fixed_args(dev->of_node, "qcom,tcsr-reg", 1, 0, + &tcsr_args); + if (ret == -ENOENT) + return 0; + else if (ret < 0) + return dev_err_probe(dev, ret, "Failed to parse qcom,tcsr-reg\n"); + + qmp->tcsr_map = syscon_node_to_regmap(tcsr_args.np); + of_node_put(tcsr_args.np); + if (IS_ERR(qmp->tcsr_map)) + return PTR_ERR(qmp->tcsr_map); + + qmp->vls_clamp_reg = tcsr_args.args[0]; + + return 0; +} + +static int qmp_usbc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + struct device_node *np; + struct qmp_usbc *qmp; + int ret; + + qmp = devm_kzalloc(dev, sizeof(*qmp), GFP_KERNEL); + if (!qmp) + return -ENOMEM; + + qmp->dev = dev; + dev_set_drvdata(dev, qmp); + + qmp->orientation = TYPEC_ORIENTATION_NORMAL; + + qmp->cfg = of_device_get_match_data(dev); + if (!qmp->cfg) + return -EINVAL; + + mutex_init(&qmp->phy_mutex); + + ret = qmp_usbc_vreg_init(qmp); + if (ret) + return ret; + + ret = qmp_usbc_typec_switch_register(qmp); + if (ret) + return ret; + + ret = qmp_usbc_parse_vls_clamp(qmp); + if (ret) + return ret; + + /* Check for legacy binding with child node. */ + np = of_get_child_by_name(dev->of_node, "phy"); + if (np) { + ret = qmp_usbc_parse_dt_legacy(qmp, np); + } else { + np = of_node_get(dev->of_node); + ret = qmp_usbc_parse_dt(qmp); + } + if (ret) + goto err_node_put; + + pm_runtime_set_active(dev); + ret = devm_pm_runtime_enable(dev); + if (ret) + goto err_node_put; + /* + * Prevent runtime pm from being ON by default. Users can enable + * it using power/control in sysfs. + */ + pm_runtime_forbid(dev); + + ret = phy_pipe_clk_register(qmp, np); + if (ret) + goto err_node_put; + + qmp->phy = devm_phy_create(dev, np, &qmp_usbc_phy_ops); + if (IS_ERR(qmp->phy)) { + ret = PTR_ERR(qmp->phy); + dev_err(dev, "failed to create PHY: %d\n", ret); + goto err_node_put; + } + + phy_set_drvdata(qmp->phy, qmp); + + of_node_put(np); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); + +err_node_put: + of_node_put(np); + return ret; +} + +static const struct of_device_id qmp_usbc_of_match_table[] = { + { + .compatible = "qcom,msm8998-qmp-usb3-phy", + .data = &msm8998_usb3phy_cfg, + }, { + .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, + }, { + .compatible = "qcom,sm6115-qmp-usb3-phy", + .data = &qcm2290_usb3phy_cfg, + }, + { }, +}; +MODULE_DEVICE_TABLE(of, qmp_usbc_of_match_table); + +static struct platform_driver qmp_usbc_driver = { + .probe = qmp_usbc_probe, + .driver = { + .name = "qcom-qmp-usbc-phy", + .pm = &qmp_usbc_pm_ops, + .of_match_table = qmp_usbc_of_match_table, + }, +}; + +module_platform_driver(qmp_usbc_driver); + +MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>"); +MODULE_DESCRIPTION("Qualcomm QMP USB-C PHY driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 6923496cbfee..d0f41e4aaa85 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -46,96 +46,35 @@ #include "phy-qcom-qmp-pcs-v6.h" +#include "phy-qcom-qmp-pcs-v6-n4.h" + #include "phy-qcom-qmp-pcs-v6_20.h" #include "phy-qcom-qmp-pcs-v7.h" -/* Only for QMP V3 & V4 PHY - DP COM registers */ -#define QPHY_V3_DP_COM_PHY_MODE_CTRL 0x00 -#define QPHY_V3_DP_COM_SW_RESET 0x04 -#define QPHY_V3_DP_COM_POWER_DOWN_CTRL 0x08 -#define QPHY_V3_DP_COM_SWI_CTRL 0x0c -#define QPHY_V3_DP_COM_TYPEC_CTRL 0x10 -#define QPHY_V3_DP_COM_TYPEC_PWRDN_CTRL 0x14 -#define QPHY_V3_DP_COM_RESET_OVRD_CTRL 0x1c - -/* QSERDES V3 COM bits */ -# define QSERDES_V3_COM_BIAS_EN 0x0001 -# define QSERDES_V3_COM_BIAS_EN_MUX 0x0002 -# define QSERDES_V3_COM_CLKBUF_R_EN 0x0004 -# define QSERDES_V3_COM_CLKBUF_L_EN 0x0008 -# define QSERDES_V3_COM_EN_SYSCLK_TX_SEL 0x0010 -# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_L 0x0020 -# define QSERDES_V3_COM_CLKBUF_RX_DRIVE_R 0x0040 - -/* QSERDES V3 TX bits */ -# define DP_PHY_TXn_TX_EMP_POST1_LVL_MASK 0x001f -# define DP_PHY_TXn_TX_EMP_POST1_LVL_MUX_EN 0x0020 -# define DP_PHY_TXn_TX_DRV_LVL_MASK 0x001f -# define DP_PHY_TXn_TX_DRV_LVL_MUX_EN 0x0020 - -/* QMP PHY - DP PHY registers */ -#define QSERDES_DP_PHY_REVISION_ID0 0x000 -#define QSERDES_DP_PHY_REVISION_ID1 0x004 -#define QSERDES_DP_PHY_REVISION_ID2 0x008 -#define QSERDES_DP_PHY_REVISION_ID3 0x00c -#define QSERDES_DP_PHY_CFG 0x010 -#define QSERDES_DP_PHY_PD_CTL 0x018 -# define DP_PHY_PD_CTL_PWRDN 0x001 -# define DP_PHY_PD_CTL_PSR_PWRDN 0x002 -# define DP_PHY_PD_CTL_AUX_PWRDN 0x004 -# define DP_PHY_PD_CTL_LANE_0_1_PWRDN 0x008 -# define DP_PHY_PD_CTL_LANE_2_3_PWRDN 0x010 -# define DP_PHY_PD_CTL_PLL_PWRDN 0x020 -# define DP_PHY_PD_CTL_DP_CLAMP_EN 0x040 -#define QSERDES_DP_PHY_MODE 0x01c -#define QSERDES_DP_PHY_AUX_CFG0 0x020 -#define QSERDES_DP_PHY_AUX_CFG1 0x024 -#define QSERDES_DP_PHY_AUX_CFG2 0x028 -#define QSERDES_DP_PHY_AUX_CFG3 0x02c -#define QSERDES_DP_PHY_AUX_CFG4 0x030 -#define QSERDES_DP_PHY_AUX_CFG5 0x034 -#define QSERDES_DP_PHY_AUX_CFG6 0x038 -#define QSERDES_DP_PHY_AUX_CFG7 0x03c -#define QSERDES_DP_PHY_AUX_CFG8 0x040 -#define QSERDES_DP_PHY_AUX_CFG9 0x044 - -/* Only for QMP V3 PHY - DP PHY registers */ -#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_MASK 0x048 -# define PHY_AUX_STOP_ERR_MASK 0x01 -# define PHY_AUX_DEC_ERR_MASK 0x02 -# define PHY_AUX_SYNC_ERR_MASK 0x04 -# define PHY_AUX_ALIGN_ERR_MASK 0x08 -# define PHY_AUX_REQ_ERR_MASK 0x10 - -#define QSERDES_V3_DP_PHY_AUX_INTERRUPT_CLEAR 0x04c -#define QSERDES_V3_DP_PHY_AUX_BIST_CFG 0x050 - -#define QSERDES_V3_DP_PHY_VCO_DIV 0x064 -#define QSERDES_V3_DP_PHY_TX0_TX1_LANE_CTL 0x06c -#define QSERDES_V3_DP_PHY_TX2_TX3_LANE_CTL 0x088 - -#define QSERDES_V3_DP_PHY_SPARE0 0x0ac -#define DP_PHY_SPARE0_MASK 0x0f -#define DP_PHY_SPARE0_ORIENTATION_INFO_SHIFT 0x04(0x0004) - -#define QSERDES_V3_DP_PHY_STATUS 0x0c0 - -/* Only for QMP V4 PHY - DP PHY registers */ -#define QSERDES_V4_DP_PHY_CFG_1 0x014 -#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_MASK 0x054 -#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_CLEAR 0x058 -#define QSERDES_V4_DP_PHY_VCO_DIV 0x070 -#define QSERDES_V4_DP_PHY_TX0_TX1_LANE_CTL 0x078 -#define QSERDES_V4_DP_PHY_TX2_TX3_LANE_CTL 0x09c -#define QSERDES_V4_DP_PHY_SPARE0 0x0c8 -#define QSERDES_V4_DP_PHY_AUX_INTERRUPT_STATUS 0x0d8 -#define QSERDES_V4_DP_PHY_STATUS 0x0dc - -#define QSERDES_V5_DP_PHY_STATUS 0x0dc - -/* Only for QMP V6 PHY - DP PHY registers */ -#define QSERDES_V6_DP_PHY_AUX_INTERRUPT_STATUS 0x0e0 -#define QSERDES_V6_DP_PHY_STATUS 0x0e4 +/* QPHY_SW_RESET bit */ +#define SW_RESET BIT(0) +/* QPHY_POWER_DOWN_CONTROL */ +#define SW_PWRDN BIT(0) +#define REFCLK_DRV_DSBL BIT(1) /* PCIe */ + +/* QPHY_START_CONTROL bits */ +#define SERDES_START BIT(0) +#define PCS_START BIT(1) + +/* QPHY_PCS_STATUS bit */ +#define PHYSTATUS BIT(6) +#define PHYSTATUS_4_20 BIT(7) + +/* QPHY_PCS_AUTONOMOUS_MODE_CTRL register bits */ +#define ARCVR_DTCT_EN BIT(0) +#define ALFPS_DTCT_EN BIT(1) +#define ARCVR_DTCT_EVENT_SEL BIT(4) + +/* QPHY_PCS_LFPS_RXTERM_IRQ_CLEAR register bits */ +#define IRQ_CLEAR BIT(0) + +/* QPHY_PCS_MISC_CLAMP_ENABLE register bits */ +#define CLAMP_EN BIT(0) /* enables i/o clamp_n */ #endif 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-sgmii-eth.c b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c index 03dc753f0de1..5b1c82459c12 100644 --- a/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c +++ b/drivers/phy/qualcomm/phy-qcom-sgmii-eth.c @@ -11,93 +11,14 @@ #include <linux/platform_device.h> #include <linux/regmap.h> -#define QSERDES_QMP_PLL 0x0 -#define QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0 (QSERDES_QMP_PLL + 0x1ac) -#define QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0 (QSERDES_QMP_PLL + 0x1b0) -#define QSERDES_COM_BIN_VCOCAL_HSCLK_SEL (QSERDES_QMP_PLL + 0x1bc) -#define QSERDES_COM_CORE_CLK_EN (QSERDES_QMP_PLL + 0x174) -#define QSERDES_COM_CORECLK_DIV_MODE0 (QSERDES_QMP_PLL + 0x168) -#define QSERDES_COM_CP_CTRL_MODE0 (QSERDES_QMP_PLL + 0x74) -#define QSERDES_COM_DEC_START_MODE0 (QSERDES_QMP_PLL + 0xbc) -#define QSERDES_COM_DIV_FRAC_START1_MODE0 (QSERDES_QMP_PLL + 0xcc) -#define QSERDES_COM_DIV_FRAC_START2_MODE0 (QSERDES_QMP_PLL + 0xd0) -#define QSERDES_COM_DIV_FRAC_START3_MODE0 (QSERDES_QMP_PLL + 0xd4) -#define QSERDES_COM_HSCLK_HS_SWITCH_SEL (QSERDES_QMP_PLL + 0x15c) -#define QSERDES_COM_HSCLK_SEL (QSERDES_QMP_PLL + 0x158) -#define QSERDES_COM_LOCK_CMP1_MODE0 (QSERDES_QMP_PLL + 0xac) -#define QSERDES_COM_LOCK_CMP2_MODE0 (QSERDES_QMP_PLL + 0xb0) -#define QSERDES_COM_PLL_CCTRL_MODE0 (QSERDES_QMP_PLL + 0x84) -#define QSERDES_COM_PLL_IVCO (QSERDES_QMP_PLL + 0x58) -#define QSERDES_COM_PLL_RCTRL_MODE0 (QSERDES_QMP_PLL + 0x7c) -#define QSERDES_COM_SYSCLK_EN_SEL (QSERDES_QMP_PLL + 0x94) -#define QSERDES_COM_VCO_TUNE1_MODE0 (QSERDES_QMP_PLL + 0x110) -#define QSERDES_COM_VCO_TUNE2_MODE0 (QSERDES_QMP_PLL + 0x114) -#define QSERDES_COM_VCO_TUNE_INITVAL2 (QSERDES_QMP_PLL + 0x124) -#define QSERDES_COM_C_READY_STATUS (QSERDES_QMP_PLL + 0x178) -#define QSERDES_COM_CMN_STATUS (QSERDES_QMP_PLL + 0x140) +#include "phy-qcom-qmp-pcs-sgmii.h" +#include "phy-qcom-qmp-qserdes-com-v5.h" +#include "phy-qcom-qmp-qserdes-txrx-v5.h" +#define QSERDES_QMP_PLL 0x0 #define QSERDES_RX 0x600 -#define QSERDES_RX_UCDR_FO_GAIN (QSERDES_RX + 0x8) -#define QSERDES_RX_UCDR_SO_GAIN (QSERDES_RX + 0x14) -#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN (QSERDES_RX + 0x30) -#define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE (QSERDES_RX + 0x34) -#define QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW (QSERDES_RX + 0x3c) -#define QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH (QSERDES_RX + 0x40) -#define QSERDES_RX_UCDR_PI_CONTROLS (QSERDES_RX + 0x44) -#define QSERDES_RX_UCDR_PI_CTRL2 (QSERDES_RX + 0x48) -#define QSERDES_RX_RX_TERM_BW (QSERDES_RX + 0x80) -#define QSERDES_RX_VGA_CAL_CNTRL2 (QSERDES_RX + 0xd8) -#define QSERDES_RX_GM_CAL (QSERDES_RX + 0xdc) -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1 (QSERDES_RX + 0xe8) -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 (QSERDES_RX + 0xec) -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 (QSERDES_RX + 0xf0) -#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 (QSERDES_RX + 0xf4) -#define QSERDES_RX_RX_IDAC_TSETTLE_LOW (QSERDES_RX + 0xf8) -#define QSERDES_RX_RX_IDAC_TSETTLE_HIGH (QSERDES_RX + 0xfc) -#define QSERDES_RX_RX_IDAC_MEASURE_TIME (QSERDES_RX + 0x100) -#define QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 (QSERDES_RX + 0x110) -#define QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2 (QSERDES_RX + 0x114) -#define QSERDES_RX_SIGDET_CNTRL (QSERDES_RX + 0x11c) -#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL (QSERDES_RX + 0x124) -#define QSERDES_RX_RX_BAND (QSERDES_RX + 0x128) -#define QSERDES_RX_RX_MODE_00_LOW (QSERDES_RX + 0x15c) -#define QSERDES_RX_RX_MODE_00_HIGH (QSERDES_RX + 0x160) -#define QSERDES_RX_RX_MODE_00_HIGH2 (QSERDES_RX + 0x164) -#define QSERDES_RX_RX_MODE_00_HIGH3 (QSERDES_RX + 0x168) -#define QSERDES_RX_RX_MODE_00_HIGH4 (QSERDES_RX + 0x16c) -#define QSERDES_RX_RX_MODE_01_LOW (QSERDES_RX + 0x170) -#define QSERDES_RX_RX_MODE_01_HIGH (QSERDES_RX + 0x174) -#define QSERDES_RX_RX_MODE_01_HIGH2 (QSERDES_RX + 0x178) -#define QSERDES_RX_RX_MODE_01_HIGH3 (QSERDES_RX + 0x17c) -#define QSERDES_RX_RX_MODE_01_HIGH4 (QSERDES_RX + 0x180) -#define QSERDES_RX_RX_MODE_10_LOW (QSERDES_RX + 0x184) -#define QSERDES_RX_RX_MODE_10_HIGH (QSERDES_RX + 0x188) -#define QSERDES_RX_RX_MODE_10_HIGH2 (QSERDES_RX + 0x18c) -#define QSERDES_RX_RX_MODE_10_HIGH3 (QSERDES_RX + 0x190) -#define QSERDES_RX_RX_MODE_10_HIGH4 (QSERDES_RX + 0x194) -#define QSERDES_RX_DCC_CTRL1 (QSERDES_RX + 0x1a8) - #define QSERDES_TX 0x400 -#define QSERDES_TX_TX_BAND (QSERDES_TX + 0x24) -#define QSERDES_TX_SLEW_CNTL (QSERDES_TX + 0x28) -#define QSERDES_TX_RES_CODE_LANE_OFFSET_TX (QSERDES_TX + 0x3c) -#define QSERDES_TX_RES_CODE_LANE_OFFSET_RX (QSERDES_TX + 0x40) -#define QSERDES_TX_LANE_MODE_1 (QSERDES_TX + 0x84) -#define QSERDES_TX_LANE_MODE_3 (QSERDES_TX + 0x8c) -#define QSERDES_TX_RCV_DETECT_LVL_2 (QSERDES_TX + 0xa4) -#define QSERDES_TX_TRAN_DRVR_EMP_EN (QSERDES_TX + 0xc0) - -#define QSERDES_PCS 0xC00 -#define QSERDES_PCS_PHY_START (QSERDES_PCS + 0x0) -#define QSERDES_PCS_POWER_DOWN_CONTROL (QSERDES_PCS + 0x4) -#define QSERDES_PCS_SW_RESET (QSERDES_PCS + 0x8) -#define QSERDES_PCS_LINE_RESET_TIME (QSERDES_PCS + 0xc) -#define QSERDES_PCS_TX_LARGE_AMP_DRV_LVL (QSERDES_PCS + 0x20) -#define QSERDES_PCS_TX_SMALL_AMP_DRV_LVL (QSERDES_PCS + 0x28) -#define QSERDES_PCS_TX_MID_TERM_CTRL1 (QSERDES_PCS + 0xd8) -#define QSERDES_PCS_TX_MID_TERM_CTRL2 (QSERDES_PCS + 0xdc) -#define QSERDES_PCS_SGMII_MISC_CTRL8 (QSERDES_PCS + 0x118) -#define QSERDES_PCS_PCS_READY_STATUS (QSERDES_PCS + 0x94) +#define QSERDES_PCS 0xc00 #define QSERDES_COM_C_READY BIT(0) #define QSERDES_PCS_READY BIT(0) @@ -112,178 +33,178 @@ struct qcom_dwmac_sgmii_phy_data { static void qcom_dwmac_sgmii_phy_init_1g(struct regmap *regmap) { - regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x01); - regmap_write(regmap, QSERDES_PCS_POWER_DOWN_CONTROL, 0x01); - - regmap_write(regmap, QSERDES_COM_PLL_IVCO, 0x0F); - regmap_write(regmap, QSERDES_COM_CP_CTRL_MODE0, 0x06); - regmap_write(regmap, QSERDES_COM_PLL_RCTRL_MODE0, 0x16); - regmap_write(regmap, QSERDES_COM_PLL_CCTRL_MODE0, 0x36); - regmap_write(regmap, QSERDES_COM_SYSCLK_EN_SEL, 0x1A); - regmap_write(regmap, QSERDES_COM_LOCK_CMP1_MODE0, 0x0A); - regmap_write(regmap, QSERDES_COM_LOCK_CMP2_MODE0, 0x1A); - regmap_write(regmap, QSERDES_COM_DEC_START_MODE0, 0x82); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START3_MODE0, 0x03); - regmap_write(regmap, QSERDES_COM_VCO_TUNE1_MODE0, 0x24); - - regmap_write(regmap, QSERDES_COM_VCO_TUNE2_MODE0, 0x02); - regmap_write(regmap, QSERDES_COM_VCO_TUNE_INITVAL2, 0x00); - regmap_write(regmap, QSERDES_COM_HSCLK_SEL, 0x04); - regmap_write(regmap, QSERDES_COM_HSCLK_HS_SWITCH_SEL, 0x00); - regmap_write(regmap, QSERDES_COM_CORECLK_DIV_MODE0, 0x0A); - regmap_write(regmap, QSERDES_COM_CORE_CLK_EN, 0x00); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xB9); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1E); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_HSCLK_SEL, 0x11); - - regmap_write(regmap, QSERDES_TX_TX_BAND, 0x05); - regmap_write(regmap, QSERDES_TX_SLEW_CNTL, 0x0A); - regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_TX, 0x09); - regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_RX, 0x09); - regmap_write(regmap, QSERDES_TX_LANE_MODE_1, 0x05); - regmap_write(regmap, QSERDES_TX_LANE_MODE_3, 0x00); - regmap_write(regmap, QSERDES_TX_RCV_DETECT_LVL_2, 0x12); - regmap_write(regmap, QSERDES_TX_TRAN_DRVR_EMP_EN, 0x0C); - - regmap_write(regmap, QSERDES_RX_UCDR_FO_GAIN, 0x0A); - regmap_write(regmap, QSERDES_RX_UCDR_SO_GAIN, 0x06); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A); - regmap_write(regmap, QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01); - regmap_write(regmap, QSERDES_RX_UCDR_PI_CONTROLS, 0x81); - regmap_write(regmap, QSERDES_RX_UCDR_PI_CTRL2, 0x80); - regmap_write(regmap, QSERDES_RX_RX_TERM_BW, 0x04); - regmap_write(regmap, QSERDES_RX_VGA_CAL_CNTRL2, 0x08); - regmap_write(regmap, QSERDES_RX_GM_CAL, 0x0F); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A); - regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_LOW, 0x80); - regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_HIGH, 0x01); - regmap_write(regmap, QSERDES_RX_RX_IDAC_MEASURE_TIME, 0x20); - regmap_write(regmap, QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17); - regmap_write(regmap, QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00); - regmap_write(regmap, QSERDES_RX_SIGDET_CNTRL, 0x0F); - regmap_write(regmap, QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E); - regmap_write(regmap, QSERDES_RX_RX_BAND, 0x05); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH3, 0x09); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH4, 0xB1); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH3, 0x09); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH4, 0xB1); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH3, 0x3B); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH4, 0xB7); - regmap_write(regmap, QSERDES_RX_DCC_CTRL1, 0x0C); - - regmap_write(regmap, QSERDES_PCS_LINE_RESET_TIME, 0x0C); - regmap_write(regmap, QSERDES_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); - regmap_write(regmap, QSERDES_PCS_TX_SMALL_AMP_DRV_LVL, 0x03); - regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL1, 0x83); - regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL2, 0x08); - regmap_write(regmap, QSERDES_PCS_SGMII_MISC_CTRL8, 0x0C); - regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x00); - - regmap_write(regmap, QSERDES_PCS_PHY_START, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_POWER_DOWN_CONTROL, 0x01); + + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, 0x0F); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, 0x06); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x0A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x1A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DEC_START_MODE0, 0x82); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x55); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0x55); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x03); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE1_MODE0, 0x24); + + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE2_MODE0, 0x02); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE_INITVAL2, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_SEL, 0x04); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x0A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORE_CLK_EN, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xB9); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1E); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11); + + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TX_BAND, 0x05); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_SLEW_CNTL, 0x0A); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x09); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x09); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_1, 0x05); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_3, 0x00); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RCV_DETECT_LVL_2, 0x12); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TRAN_DRVR_EMP_EN, 0x0C); + + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FO_GAIN, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_GAIN, 0x06); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x81); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CTRL2, 0x80); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_TERM_BW, 0x04); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x08); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_GM_CAL, 0x0F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0x80); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x01); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_MEASURE_TIME, 0x20); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_CNTRL, 0x0F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x1E); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_BAND, 0x05); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x09); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xB1); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x09); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xB1); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH3, 0x3B); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, 0xB7); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, 0x0C); + + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_LINE_RESET_TIME, 0x0C); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_SMALL_AMP_DRV_LVL, 0x03); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL1, 0x83); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, 0x08); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SGMII_MISC_CTRL8, 0x0C); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x00); + + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_PHY_START, 0x01); } static void qcom_dwmac_sgmii_phy_init_2p5g(struct regmap *regmap) { - regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x01); - regmap_write(regmap, QSERDES_PCS_POWER_DOWN_CONTROL, 0x01); - - regmap_write(regmap, QSERDES_COM_PLL_IVCO, 0x0F); - regmap_write(regmap, QSERDES_COM_CP_CTRL_MODE0, 0x06); - regmap_write(regmap, QSERDES_COM_PLL_RCTRL_MODE0, 0x16); - regmap_write(regmap, QSERDES_COM_PLL_CCTRL_MODE0, 0x36); - regmap_write(regmap, QSERDES_COM_SYSCLK_EN_SEL, 0x1A); - regmap_write(regmap, QSERDES_COM_LOCK_CMP1_MODE0, 0x1A); - regmap_write(regmap, QSERDES_COM_LOCK_CMP2_MODE0, 0x41); - regmap_write(regmap, QSERDES_COM_DEC_START_MODE0, 0x7A); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START2_MODE0, 0x20); - regmap_write(regmap, QSERDES_COM_DIV_FRAC_START3_MODE0, 0x01); - regmap_write(regmap, QSERDES_COM_VCO_TUNE1_MODE0, 0xA1); - - regmap_write(regmap, QSERDES_COM_VCO_TUNE2_MODE0, 0x02); - regmap_write(regmap, QSERDES_COM_VCO_TUNE_INITVAL2, 0x00); - regmap_write(regmap, QSERDES_COM_HSCLK_SEL, 0x03); - regmap_write(regmap, QSERDES_COM_HSCLK_HS_SWITCH_SEL, 0x00); - regmap_write(regmap, QSERDES_COM_CORECLK_DIV_MODE0, 0x05); - regmap_write(regmap, QSERDES_COM_CORE_CLK_EN, 0x00); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xCD); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1C); - regmap_write(regmap, QSERDES_COM_BIN_VCOCAL_HSCLK_SEL, 0x11); - - regmap_write(regmap, QSERDES_TX_TX_BAND, 0x04); - regmap_write(regmap, QSERDES_TX_SLEW_CNTL, 0x0A); - regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_TX, 0x09); - regmap_write(regmap, QSERDES_TX_RES_CODE_LANE_OFFSET_RX, 0x02); - regmap_write(regmap, QSERDES_TX_LANE_MODE_1, 0x05); - regmap_write(regmap, QSERDES_TX_LANE_MODE_3, 0x00); - regmap_write(regmap, QSERDES_TX_RCV_DETECT_LVL_2, 0x12); - regmap_write(regmap, QSERDES_TX_TRAN_DRVR_EMP_EN, 0x0C); - - regmap_write(regmap, QSERDES_RX_UCDR_FO_GAIN, 0x0A); - regmap_write(regmap, QSERDES_RX_UCDR_SO_GAIN, 0x06); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A); - regmap_write(regmap, QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00); - regmap_write(regmap, QSERDES_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01); - regmap_write(regmap, QSERDES_RX_UCDR_PI_CONTROLS, 0x81); - regmap_write(regmap, QSERDES_RX_UCDR_PI_CTRL2, 0x80); - regmap_write(regmap, QSERDES_RX_RX_TERM_BW, 0x00); - regmap_write(regmap, QSERDES_RX_VGA_CAL_CNTRL2, 0x08); - regmap_write(regmap, QSERDES_RX_GM_CAL, 0x0F); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A); - regmap_write(regmap, QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A); - regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_LOW, 0x80); - regmap_write(regmap, QSERDES_RX_RX_IDAC_TSETTLE_HIGH, 0x01); - regmap_write(regmap, QSERDES_RX_RX_IDAC_MEASURE_TIME, 0x20); - regmap_write(regmap, QSERDES_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17); - regmap_write(regmap, QSERDES_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00); - regmap_write(regmap, QSERDES_RX_SIGDET_CNTRL, 0x0F); - regmap_write(regmap, QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E); - regmap_write(regmap, QSERDES_RX_RX_BAND, 0x18); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_LOW, 0x18); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH3, 0x0C); - regmap_write(regmap, QSERDES_RX_RX_MODE_00_HIGH4, 0xB8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH3, 0x09); - regmap_write(regmap, QSERDES_RX_RX_MODE_01_HIGH4, 0xB1); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_LOW, 0xE0); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH2, 0xC8); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH3, 0x3B); - regmap_write(regmap, QSERDES_RX_RX_MODE_10_HIGH4, 0xB7); - regmap_write(regmap, QSERDES_RX_DCC_CTRL1, 0x0C); - - regmap_write(regmap, QSERDES_PCS_LINE_RESET_TIME, 0x0C); - regmap_write(regmap, QSERDES_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); - regmap_write(regmap, QSERDES_PCS_TX_SMALL_AMP_DRV_LVL, 0x03); - regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL1, 0x83); - regmap_write(regmap, QSERDES_PCS_TX_MID_TERM_CTRL2, 0x08); - regmap_write(regmap, QSERDES_PCS_SGMII_MISC_CTRL8, 0x8C); - regmap_write(regmap, QSERDES_PCS_SW_RESET, 0x00); - - regmap_write(regmap, QSERDES_PCS_PHY_START, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x01); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_POWER_DOWN_CONTROL, 0x01); + + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_IVCO, 0x0F); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CP_CTRL_MODE0, 0x06); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_RCTRL_MODE0, 0x16); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_PLL_CCTRL_MODE0, 0x36); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_SYSCLK_EN_SEL, 0x1A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP1_MODE0, 0x1A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_LOCK_CMP2_MODE0, 0x41); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DEC_START_MODE0, 0x7A); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START1_MODE0, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START2_MODE0, 0x20); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_DIV_FRAC_START3_MODE0, 0x01); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE1_MODE0, 0xA1); + + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE2_MODE0, 0x02); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_VCO_TUNE_INITVAL2, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_SEL, 0x03); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_HSCLK_HS_SWITCH_SEL, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORECLK_DIV_MODE0, 0x05); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_CORE_CLK_EN, 0x00); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xCD); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1C); + regmap_write(regmap, QSERDES_QMP_PLL + QSERDES_V5_COM_BIN_VCOCAL_HSCLK_SEL, 0x11); + + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TX_BAND, 0x04); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_SLEW_CNTL, 0x0A); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_TX, 0x09); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RES_CODE_LANE_OFFSET_RX, 0x02); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_1, 0x05); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_LANE_MODE_3, 0x00); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_RCV_DETECT_LVL_2, 0x12); + regmap_write(regmap, QSERDES_TX + QSERDES_V5_TX_TRAN_DRVR_EMP_EN, 0x0C); + + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FO_GAIN, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_GAIN, 0x06); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_FO_GAIN, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x01); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CONTROLS, 0x81); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_UCDR_PI_CTRL2, 0x80); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_TERM_BW, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_VGA_CAL_CNTRL2, 0x08); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_GM_CAL, 0x0F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL1, 0x04); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL2, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQU_ADAPTOR_CNTRL4, 0x0A); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_LOW, 0x80); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_TSETTLE_HIGH, 0x01); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_IDAC_MEASURE_TIME, 0x20); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x00); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_CNTRL, 0x0F); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_SIGDET_DEGLITCH_CNTRL, 0x1E); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_BAND, 0x18); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_LOW, 0x18); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH3, 0x0C); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_00_HIGH4, 0xB8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH3, 0x09); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_01_HIGH4, 0xB1); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_LOW, 0xE0); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH2, 0xC8); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH3, 0x3B); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_RX_MODE_10_HIGH4, 0xB7); + regmap_write(regmap, QSERDES_RX + QSERDES_V5_RX_DCC_CTRL1, 0x0C); + + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_LINE_RESET_TIME, 0x0C); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_LARGE_AMP_DRV_LVL, 0x1F); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_SMALL_AMP_DRV_LVL, 0x03); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL1, 0x83); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, 0x08); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SGMII_MISC_CTRL8, 0x8C); + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x00); + + regmap_write(regmap, QSERDES_PCS + QPHY_PCS_PHY_START, 0x01); } static inline int @@ -313,28 +234,28 @@ static int qcom_dwmac_sgmii_phy_calibrate(struct phy *phy) } if (qcom_dwmac_sgmii_phy_poll_status(data->regmap, - QSERDES_COM_C_READY_STATUS, + QSERDES_QMP_PLL + QSERDES_V5_COM_C_READY_STATUS, QSERDES_COM_C_READY)) { dev_err(dev, "QSERDES_COM_C_READY_STATUS timed-out"); return -ETIMEDOUT; } if (qcom_dwmac_sgmii_phy_poll_status(data->regmap, - QSERDES_PCS_PCS_READY_STATUS, + QSERDES_PCS + QPHY_PCS_PCS_READY_STATUS, QSERDES_PCS_READY)) { dev_err(dev, "PCS_READY timed-out"); return -ETIMEDOUT; } if (qcom_dwmac_sgmii_phy_poll_status(data->regmap, - QSERDES_PCS_PCS_READY_STATUS, + QSERDES_PCS + QPHY_PCS_PCS_READY_STATUS, QSERDES_PCS_SGMIIPHY_READY)) { dev_err(dev, "SGMIIPHY_READY timed-out"); return -ETIMEDOUT; } if (qcom_dwmac_sgmii_phy_poll_status(data->regmap, - QSERDES_COM_CMN_STATUS, + QSERDES_QMP_PLL + QSERDES_V5_COM_CMN_STATUS, QSERDES_COM_C_PLL_LOCKED)) { dev_err(dev, "PLL Lock Status timed-out"); return -ETIMEDOUT; @@ -354,11 +275,11 @@ static int qcom_dwmac_sgmii_phy_power_off(struct phy *phy) { struct qcom_dwmac_sgmii_phy_data *data = phy_get_drvdata(phy); - regmap_write(data->regmap, QSERDES_PCS_TX_MID_TERM_CTRL2, 0x08); - regmap_write(data->regmap, QSERDES_PCS_SW_RESET, 0x01); + regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_TX_MID_TERM_CTRL2, 0x08); + regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x01); udelay(100); - regmap_write(data->regmap, QSERDES_PCS_SW_RESET, 0x00); - regmap_write(data->regmap, QSERDES_PCS_PHY_START, 0x01); + regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_SW_RESET, 0x00); + regmap_write(data->regmap, QSERDES_PCS + QPHY_PCS_PHY_START, 0x01); clk_disable_unprepare(data->refclk); diff --git a/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c b/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c deleted file mode 100644 index 1484691a41d5..000000000000 --- a/drivers/phy/qualcomm/phy-qcom-snps-eusb2.c +++ /dev/null @@ -1,442 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2023, Linaro Limited - */ - -#include <linux/bitfield.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/iopoll.h> -#include <linux/mod_devicetable.h> -#include <linux/phy/phy.h> -#include <linux/platform_device.h> -#include <linux/regulator/consumer.h> -#include <linux/reset.h> - -#define USB_PHY_UTMI_CTRL0 (0x3c) -#define SLEEPM BIT(0) -#define OPMODE_MASK GENMASK(4, 3) -#define OPMODE_NONDRIVING BIT(3) - -#define USB_PHY_UTMI_CTRL5 (0x50) -#define POR BIT(1) - -#define USB_PHY_HS_PHY_CTRL_COMMON0 (0x54) -#define PHY_ENABLE BIT(0) -#define SIDDQ_SEL BIT(1) -#define SIDDQ BIT(2) -#define RETENABLEN BIT(3) -#define FSEL_MASK GENMASK(6, 4) -#define FSEL_19_2_MHZ_VAL (0x0) -#define FSEL_38_4_MHZ_VAL (0x4) - -#define USB_PHY_CFG_CTRL_1 (0x58) -#define PHY_CFG_PLL_CPBIAS_CNTRL_MASK GENMASK(7, 1) - -#define USB_PHY_CFG_CTRL_2 (0x5c) -#define PHY_CFG_PLL_FB_DIV_7_0_MASK GENMASK(7, 0) -#define DIV_7_0_19_2_MHZ_VAL (0x90) -#define DIV_7_0_38_4_MHZ_VAL (0xc8) - -#define USB_PHY_CFG_CTRL_3 (0x60) -#define PHY_CFG_PLL_FB_DIV_11_8_MASK GENMASK(3, 0) -#define DIV_11_8_19_2_MHZ_VAL (0x1) -#define DIV_11_8_38_4_MHZ_VAL (0x0) - -#define PHY_CFG_PLL_REF_DIV GENMASK(7, 4) -#define PLL_REF_DIV_VAL (0x0) - -#define USB_PHY_HS_PHY_CTRL2 (0x64) -#define VBUSVLDEXT0 BIT(0) -#define USB2_SUSPEND_N BIT(2) -#define USB2_SUSPEND_N_SEL BIT(3) -#define VBUS_DET_EXT_SEL BIT(4) - -#define USB_PHY_CFG_CTRL_4 (0x68) -#define PHY_CFG_PLL_GMP_CNTRL_MASK GENMASK(1, 0) -#define PHY_CFG_PLL_INT_CNTRL_MASK GENMASK(7, 2) - -#define USB_PHY_CFG_CTRL_5 (0x6c) -#define PHY_CFG_PLL_PROP_CNTRL_MASK GENMASK(4, 0) -#define PHY_CFG_PLL_VREF_TUNE_MASK GENMASK(7, 6) - -#define USB_PHY_CFG_CTRL_6 (0x70) -#define PHY_CFG_PLL_VCO_CNTRL_MASK GENMASK(2, 0) - -#define USB_PHY_CFG_CTRL_7 (0x74) - -#define USB_PHY_CFG_CTRL_8 (0x78) -#define PHY_CFG_TX_FSLS_VREF_TUNE_MASK GENMASK(1, 0) -#define PHY_CFG_TX_FSLS_VREG_BYPASS BIT(2) -#define PHY_CFG_TX_HS_VREF_TUNE_MASK GENMASK(5, 3) -#define PHY_CFG_TX_HS_XV_TUNE_MASK GENMASK(7, 6) - -#define USB_PHY_CFG_CTRL_9 (0x7c) -#define PHY_CFG_TX_PREEMP_TUNE_MASK GENMASK(2, 0) -#define PHY_CFG_TX_RES_TUNE_MASK GENMASK(4, 3) -#define PHY_CFG_TX_RISE_TUNE_MASK GENMASK(6, 5) -#define PHY_CFG_RCAL_BYPASS BIT(7) - -#define USB_PHY_CFG_CTRL_10 (0x80) - -#define USB_PHY_CFG0 (0x94) -#define DATAPATH_CTRL_OVERRIDE_EN BIT(0) -#define CMN_CTRL_OVERRIDE_EN BIT(1) - -#define UTMI_PHY_CMN_CTRL0 (0x98) -#define TESTBURNIN BIT(6) - -#define USB_PHY_FSEL_SEL (0xb8) -#define FSEL_SEL BIT(0) - -#define USB_PHY_APB_ACCESS_CMD (0x130) -#define RW_ACCESS BIT(0) -#define APB_START_CMD BIT(1) -#define APB_LOGIC_RESET BIT(2) - -#define USB_PHY_APB_ACCESS_STATUS (0x134) -#define ACCESS_DONE BIT(0) -#define TIMED_OUT BIT(1) -#define ACCESS_ERROR BIT(2) -#define ACCESS_IN_PROGRESS BIT(3) - -#define USB_PHY_APB_ADDRESS (0x138) -#define APB_REG_ADDR_MASK GENMASK(7, 0) - -#define USB_PHY_APB_WRDATA_LSB (0x13c) -#define APB_REG_WRDATA_7_0_MASK GENMASK(3, 0) - -#define USB_PHY_APB_WRDATA_MSB (0x140) -#define APB_REG_WRDATA_15_8_MASK GENMASK(7, 4) - -#define USB_PHY_APB_RDDATA_LSB (0x144) -#define APB_REG_RDDATA_7_0_MASK GENMASK(3, 0) - -#define USB_PHY_APB_RDDATA_MSB (0x148) -#define APB_REG_RDDATA_15_8_MASK GENMASK(7, 4) - -static const char * const eusb2_hsphy_vreg_names[] = { - "vdd", "vdda12", -}; - -#define EUSB2_NUM_VREGS ARRAY_SIZE(eusb2_hsphy_vreg_names) - -struct qcom_snps_eusb2_hsphy { - struct phy *phy; - void __iomem *base; - - struct clk *ref_clk; - struct reset_control *phy_reset; - - struct regulator_bulk_data vregs[EUSB2_NUM_VREGS]; - - enum phy_mode mode; - - struct phy *repeater; -}; - -static int qcom_snps_eusb2_hsphy_set_mode(struct phy *p, enum phy_mode mode, int submode) -{ - struct qcom_snps_eusb2_hsphy *phy = phy_get_drvdata(p); - - phy->mode = mode; - - return phy_set_mode_ext(phy->repeater, mode, submode); -} - -static void qcom_snps_eusb2_hsphy_write_mask(void __iomem *base, u32 offset, - u32 mask, u32 val) -{ - u32 reg; - - reg = readl_relaxed(base + offset); - reg &= ~mask; - reg |= val & mask; - writel_relaxed(reg, base + offset); - - /* Ensure above write is completed */ - readl_relaxed(base + offset); -} - -static void qcom_eusb2_default_parameters(struct qcom_snps_eusb2_hsphy *phy) -{ - /* default parameters: tx pre-emphasis */ - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_9, - PHY_CFG_TX_PREEMP_TUNE_MASK, - FIELD_PREP(PHY_CFG_TX_PREEMP_TUNE_MASK, 0)); - - /* tx rise/fall time */ - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_9, - PHY_CFG_TX_RISE_TUNE_MASK, - FIELD_PREP(PHY_CFG_TX_RISE_TUNE_MASK, 0x2)); - - /* source impedance adjustment */ - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_9, - PHY_CFG_TX_RES_TUNE_MASK, - FIELD_PREP(PHY_CFG_TX_RES_TUNE_MASK, 0x1)); - - /* dc voltage level adjustement */ - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_8, - PHY_CFG_TX_HS_VREF_TUNE_MASK, - FIELD_PREP(PHY_CFG_TX_HS_VREF_TUNE_MASK, 0x3)); - - /* transmitter HS crossover adjustement */ - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_8, - PHY_CFG_TX_HS_XV_TUNE_MASK, - FIELD_PREP(PHY_CFG_TX_HS_XV_TUNE_MASK, 0x0)); -} - -static int qcom_eusb2_ref_clk_init(struct qcom_snps_eusb2_hsphy *phy) -{ - unsigned long ref_clk_freq = clk_get_rate(phy->ref_clk); - - switch (ref_clk_freq) { - case 19200000: - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0, - FSEL_MASK, - FIELD_PREP(FSEL_MASK, FSEL_19_2_MHZ_VAL)); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_2, - PHY_CFG_PLL_FB_DIV_7_0_MASK, - DIV_7_0_19_2_MHZ_VAL); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_3, - PHY_CFG_PLL_FB_DIV_11_8_MASK, - DIV_11_8_19_2_MHZ_VAL); - break; - - case 38400000: - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0, - FSEL_MASK, - FIELD_PREP(FSEL_MASK, FSEL_38_4_MHZ_VAL)); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_2, - PHY_CFG_PLL_FB_DIV_7_0_MASK, - DIV_7_0_38_4_MHZ_VAL); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_3, - PHY_CFG_PLL_FB_DIV_11_8_MASK, - DIV_11_8_38_4_MHZ_VAL); - break; - - default: - dev_err(&phy->phy->dev, "unsupported ref_clk_freq:%lu\n", ref_clk_freq); - return -EINVAL; - } - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_3, - PHY_CFG_PLL_REF_DIV, PLL_REF_DIV_VAL); - - return 0; -} - -static int qcom_snps_eusb2_hsphy_init(struct phy *p) -{ - struct qcom_snps_eusb2_hsphy *phy = phy_get_drvdata(p); - int ret; - - ret = regulator_bulk_enable(ARRAY_SIZE(phy->vregs), phy->vregs); - if (ret) - return ret; - - ret = phy_init(phy->repeater); - if (ret) { - dev_err(&p->dev, "repeater init failed. %d\n", ret); - goto disable_vreg; - } - - ret = clk_prepare_enable(phy->ref_clk); - if (ret) { - dev_err(&p->dev, "failed to enable ref clock, %d\n", ret); - goto disable_vreg; - } - - ret = reset_control_assert(phy->phy_reset); - if (ret) { - dev_err(&p->dev, "failed to assert phy_reset, %d\n", ret); - goto disable_ref_clk; - } - - usleep_range(100, 150); - - ret = reset_control_deassert(phy->phy_reset); - if (ret) { - dev_err(&p->dev, "failed to de-assert phy_reset, %d\n", ret); - goto disable_ref_clk; - } - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG0, - CMN_CTRL_OVERRIDE_EN, CMN_CTRL_OVERRIDE_EN); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_UTMI_CTRL5, POR, POR); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0, - PHY_ENABLE | RETENABLEN, PHY_ENABLE | RETENABLEN); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_APB_ACCESS_CMD, - APB_LOGIC_RESET, APB_LOGIC_RESET); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, UTMI_PHY_CMN_CTRL0, TESTBURNIN, 0); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_FSEL_SEL, - FSEL_SEL, FSEL_SEL); - - /* update ref_clk related registers */ - ret = qcom_eusb2_ref_clk_init(phy); - if (ret) - goto disable_ref_clk; - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_1, - PHY_CFG_PLL_CPBIAS_CNTRL_MASK, - FIELD_PREP(PHY_CFG_PLL_CPBIAS_CNTRL_MASK, 0x1)); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_4, - PHY_CFG_PLL_INT_CNTRL_MASK, - FIELD_PREP(PHY_CFG_PLL_INT_CNTRL_MASK, 0x8)); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_4, - PHY_CFG_PLL_GMP_CNTRL_MASK, - FIELD_PREP(PHY_CFG_PLL_GMP_CNTRL_MASK, 0x1)); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_5, - PHY_CFG_PLL_PROP_CNTRL_MASK, - FIELD_PREP(PHY_CFG_PLL_PROP_CNTRL_MASK, 0x10)); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_6, - PHY_CFG_PLL_VCO_CNTRL_MASK, - FIELD_PREP(PHY_CFG_PLL_VCO_CNTRL_MASK, 0x0)); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_CFG_CTRL_5, - PHY_CFG_PLL_VREF_TUNE_MASK, - FIELD_PREP(PHY_CFG_PLL_VREF_TUNE_MASK, 0x1)); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL2, - VBUS_DET_EXT_SEL, VBUS_DET_EXT_SEL); - - /* set default parameters */ - qcom_eusb2_default_parameters(phy); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL2, - USB2_SUSPEND_N_SEL | USB2_SUSPEND_N, - USB2_SUSPEND_N_SEL | USB2_SUSPEND_N); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_UTMI_CTRL0, SLEEPM, SLEEPM); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0, - SIDDQ_SEL, SIDDQ_SEL); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL_COMMON0, - SIDDQ, 0); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_UTMI_CTRL5, POR, 0); - - qcom_snps_eusb2_hsphy_write_mask(phy->base, USB_PHY_HS_PHY_CTRL2, - USB2_SUSPEND_N_SEL, 0); - - return 0; - -disable_ref_clk: - clk_disable_unprepare(phy->ref_clk); - -disable_vreg: - regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs); - - return ret; -} - -static int qcom_snps_eusb2_hsphy_exit(struct phy *p) -{ - struct qcom_snps_eusb2_hsphy *phy = phy_get_drvdata(p); - - clk_disable_unprepare(phy->ref_clk); - - regulator_bulk_disable(ARRAY_SIZE(phy->vregs), phy->vregs); - - phy_exit(phy->repeater); - - return 0; -} - -static const struct phy_ops qcom_snps_eusb2_hsphy_ops = { - .init = qcom_snps_eusb2_hsphy_init, - .exit = qcom_snps_eusb2_hsphy_exit, - .set_mode = qcom_snps_eusb2_hsphy_set_mode, - .owner = THIS_MODULE, -}; - -static int qcom_snps_eusb2_hsphy_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - struct qcom_snps_eusb2_hsphy *phy; - struct phy_provider *phy_provider; - struct phy *generic_phy; - int ret, i; - int num; - - phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); - if (!phy) - return -ENOMEM; - - phy->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(phy->base)) - return PTR_ERR(phy->base); - - phy->phy_reset = devm_reset_control_get_exclusive(dev, NULL); - if (IS_ERR(phy->phy_reset)) - return PTR_ERR(phy->phy_reset); - - phy->ref_clk = devm_clk_get(dev, "ref"); - if (IS_ERR(phy->ref_clk)) - return dev_err_probe(dev, PTR_ERR(phy->ref_clk), - "failed to get ref clk\n"); - - num = ARRAY_SIZE(phy->vregs); - for (i = 0; i < num; i++) - phy->vregs[i].supply = eusb2_hsphy_vreg_names[i]; - - ret = devm_regulator_bulk_get(dev, num, phy->vregs); - if (ret) - return dev_err_probe(dev, ret, - "failed to get regulator supplies\n"); - - phy->repeater = devm_of_phy_get_by_index(dev, np, 0); - if (IS_ERR(phy->repeater)) - return dev_err_probe(dev, PTR_ERR(phy->repeater), - "failed to get repeater\n"); - - generic_phy = devm_phy_create(dev, NULL, &qcom_snps_eusb2_hsphy_ops); - if (IS_ERR(generic_phy)) { - dev_err(dev, "failed to create phy %d\n", ret); - return PTR_ERR(generic_phy); - } - - dev_set_drvdata(dev, phy); - phy_set_drvdata(generic_phy, phy); - - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - - dev_info(dev, "Registered Qcom-eUSB2 phy\n"); - - return 0; -} - -static const struct of_device_id qcom_snps_eusb2_hsphy_of_match_table[] = { - { .compatible = "qcom,sm8550-snps-eusb2-phy", }, - { }, -}; -MODULE_DEVICE_TABLE(of, qcom_snps_eusb2_hsphy_of_match_table); - -static struct platform_driver qcom_snps_eusb2_hsphy_driver = { - .probe = qcom_snps_eusb2_hsphy_probe, - .driver = { - .name = "qcom-snps-eusb2-hsphy", - .of_match_table = qcom_snps_eusb2_hsphy_of_match_table, - }, -}; - -module_platform_driver(qcom_snps_eusb2_hsphy_driver); -MODULE_DESCRIPTION("Qualcomm SNPS eUSB2 HS PHY driver"); -MODULE_LICENSE("GPL"); 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..324c0a5d658e --- /dev/null +++ b/drivers/phy/qualcomm/phy-qcom-uniphy-pcie-28lp.c @@ -0,0 +1,331 @@ +// 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 ipq5018_regs[] = { + { + .offset = SSCG_CTRL_REG_4, + .val = 0x1cb9, + }, { + .offset = SSCG_CTRL_REG_5, + .val = 0x023a, + }, { + .offset = SSCG_CTRL_REG_3, + .val = 0xd360, + }, { + .offset = SSCG_CTRL_REG_1, + .val = 0x1, + }, { + .offset = SSCG_CTRL_REG_2, + .val = 0xeb, + }, { + .offset = CDR_CTRL_REG_4, + .val = 0x3f9, + }, { + .offset = CDR_CTRL_REG_5, + .val = 0x1c9, + }, { + .offset = CDR_CTRL_REG_2, + .val = 0x419, + }, { + .offset = CDR_CTRL_REG_1, + .val = 0x200, + }, { + .offset = PCS_INTERNAL_CONTROL_2, + .val = 0xf101, + }, +}; + +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 ipq5018_data = { + .lane_offset = 0x800, + .phy_type = PHY_TYPE_PCIE_GEN2, + .init_seq = ipq5018_regs, + .init_seq_num = ARRAY_SIZE(ipq5018_regs), + .pipe_clk_rate = 125 * MEGA, +}; + +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,ipq5018-uniphy-pcie-phy", + .data = &ipq5018_data, + }, { + .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/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c index 2f876f158e1d..a591ad95347c 100644 --- a/drivers/phy/ralink/phy-mt7621-pci.c +++ b/drivers/phy/ralink/phy-mt7621-pci.c @@ -263,7 +263,7 @@ static const struct phy_ops mt7621_pci_phy_ops = { }; static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev); diff --git a/drivers/phy/realtek/Kconfig b/drivers/phy/realtek/Kconfig new file mode 100644 index 000000000000..75ac7e7c31ae --- /dev/null +++ b/drivers/phy/realtek/Kconfig @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Phy drivers for Realtek platforms +# + +if ARCH_REALTEK || COMPILE_TEST + +config PHY_RTK_RTD_USB2PHY + tristate "Realtek RTD USB2 PHY Transceiver Driver" + depends on USB_SUPPORT + select GENERIC_PHY + select USB_PHY + select USB_COMMON + help + Enable this to support Realtek SoC USB2 phy transceiver. + The DHC (digital home center) RTD series SoCs used the Synopsys + DWC3 USB IP. This driver will do the PHY initialization + of the parameters. + +config PHY_RTK_RTD_USB3PHY + tristate "Realtek RTD USB3 PHY Transceiver Driver" + depends on USB_SUPPORT + select GENERIC_PHY + select USB_PHY + select USB_COMMON + help + Enable this to support Realtek SoC USB3 phy transceiver. + The DHC (digital home center) RTD series SoCs used the Synopsys + DWC3 USB IP. This driver will do the PHY initialization + of the parameters. + +endif # ARCH_REALTEK || COMPILE_TEST diff --git a/drivers/phy/realtek/Makefile b/drivers/phy/realtek/Makefile new file mode 100644 index 000000000000..ed7b47ff8a26 --- /dev/null +++ b/drivers/phy/realtek/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_PHY_RTK_RTD_USB2PHY) += phy-rtk-usb2.o +obj-$(CONFIG_PHY_RTK_RTD_USB3PHY) += phy-rtk-usb3.o diff --git a/drivers/phy/realtek/phy-rtk-usb2.c b/drivers/phy/realtek/phy-rtk-usb2.c new file mode 100644 index 000000000000..248550ef98ca --- /dev/null +++ b/drivers/phy/realtek/phy-rtk-usb2.c @@ -0,0 +1,1314 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-rtk-usb2.c RTK usb2.0 PHY driver + * + * Copyright (C) 2023 Realtek Semiconductor Corporation + * + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <linux/nvmem-consumer.h> +#include <linux/regmap.h> +#include <linux/sys_soc.h> +#include <linux/mfd/syscon.h> +#include <linux/phy/phy.h> +#include <linux/usb.h> + +/* GUSB2PHYACCn register */ +#define PHY_NEW_REG_REQ BIT(25) +#define PHY_VSTS_BUSY BIT(23) +#define PHY_VCTRL_SHIFT 8 +#define PHY_REG_DATA_MASK 0xff + +#define GET_LOW_NIBBLE(addr) ((addr) & 0x0f) +#define GET_HIGH_NIBBLE(addr) (((addr) & 0xf0) >> 4) + +#define EFUS_USB_DC_CAL_RATE 2 +#define EFUS_USB_DC_CAL_MAX 7 + +#define EFUS_USB_DC_DIS_RATE 1 +#define EFUS_USB_DC_DIS_MAX 7 + +#define MAX_PHY_DATA_SIZE 20 +#define OFFEST_PHY_READ 0x20 + +#define MAX_USB_PHY_NUM 4 +#define MAX_USB_PHY_PAGE0_DATA_SIZE 16 +#define MAX_USB_PHY_PAGE1_DATA_SIZE 16 +#define MAX_USB_PHY_PAGE2_DATA_SIZE 8 + +#define SET_PAGE_OFFSET 0xf4 +#define SET_PAGE_0 0x9b +#define SET_PAGE_1 0xbb +#define SET_PAGE_2 0xdb + +#define PAGE_START 0xe0 +#define PAGE0_0XE4 0xe4 +#define PAGE0_0XE6 0xe6 +#define PAGE0_0XE7 0xe7 +#define PAGE1_0XE0 0xe0 +#define PAGE1_0XE2 0xe2 + +#define SENSITIVITY_CTRL (BIT(4) | BIT(5) | BIT(6)) +#define ENABLE_AUTO_SENSITIVITY_CALIBRATION BIT(2) +#define DEFAULT_DC_DRIVING_VALUE (0x8) +#define DEFAULT_DC_DISCONNECTION_VALUE (0x6) +#define HS_CLK_SELECT BIT(6) + +struct phy_reg { + void __iomem *reg_wrap_vstatus; + void __iomem *reg_gusb2phyacc0; + int vstatus_index; +}; + +struct phy_data { + u8 addr; + u8 data; +}; + +struct phy_cfg { + int page0_size; + struct phy_data page0[MAX_USB_PHY_PAGE0_DATA_SIZE]; + int page1_size; + struct phy_data page1[MAX_USB_PHY_PAGE1_DATA_SIZE]; + int page2_size; + struct phy_data page2[MAX_USB_PHY_PAGE2_DATA_SIZE]; + + int num_phy; + + bool check_efuse; + int check_efuse_version; +#define CHECK_EFUSE_V1 1 +#define CHECK_EFUSE_V2 2 + int efuse_dc_driving_rate; + int efuse_dc_disconnect_rate; + int dc_driving_mask; + int dc_disconnect_mask; + bool usb_dc_disconnect_at_page0; + int driving_updated_for_dev_dis; + + bool do_toggle; + bool do_toggle_driving; + bool use_default_parameter; + bool is_double_sensitivity_mode; +}; + +struct phy_parameter { + struct phy_reg phy_reg; + + /* Get from efuse */ + s8 efuse_usb_dc_cal; + s8 efuse_usb_dc_dis; + + /* Get from dts */ + bool inverse_hstx_sync_clock; + u32 driving_level; + s32 driving_level_compensate; + s32 disconnection_compensate; +}; + +struct rtk_phy { + struct device *dev; + + struct phy_cfg *phy_cfg; + int num_phy; + struct phy_parameter *phy_parameter; + + struct dentry *debug_dir; +}; + +/* mapping 0xE0 to 0 ... 0xE7 to 7, 0xF0 to 8 ,,, 0xF7 to 15 */ +static inline int page_addr_to_array_index(u8 addr) +{ + return (int)((((addr) - PAGE_START) & 0x7) + + ((((addr) - PAGE_START) & 0x10) >> 1)); +} + +static inline u8 array_index_to_page_addr(int index) +{ + return ((((index) + PAGE_START) & 0x7) + + ((((index) & 0x8) << 1) + PAGE_START)); +} + +#define PHY_IO_TIMEOUT_USEC (50000) +#define PHY_IO_DELAY_US (100) + +static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) +{ + int ret; + unsigned int val; + + ret = read_poll_timeout(readl, val, ((val & mask) == result), + PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg); + if (ret) { + pr_err("%s can't program USB phy\n", __func__); + return -ETIMEDOUT; + } + + return 0; +} + +static char rtk_phy_read(struct phy_reg *phy_reg, char addr) +{ + void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0; + unsigned int val; + int ret = 0; + + addr -= OFFEST_PHY_READ; + + /* polling until VBusy == 0 */ + ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); + if (ret) + return (char)ret; + + /* VCtrl = low nibble of addr, and set PHY_NEW_REG_REQ */ + val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT); + writel(val, reg_gusb2phyacc0); + ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); + if (ret) + return (char)ret; + + /* VCtrl = high nibble of addr, and set PHY_NEW_REG_REQ */ + val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT); + writel(val, reg_gusb2phyacc0); + ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); + if (ret) + return (char)ret; + + val = readl(reg_gusb2phyacc0); + + return (char)(val & PHY_REG_DATA_MASK); +} + +static int rtk_phy_write(struct phy_reg *phy_reg, char addr, char data) +{ + unsigned int val; + void __iomem *reg_wrap_vstatus = phy_reg->reg_wrap_vstatus; + void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0; + int shift_bits = phy_reg->vstatus_index * 8; + int ret = 0; + + /* write data to VStatusOut2 (data output to phy) */ + writel((u32)data << shift_bits, reg_wrap_vstatus); + + ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); + if (ret) + return ret; + + /* VCtrl = low nibble of addr, set PHY_NEW_REG_REQ */ + val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT); + + writel(val, reg_gusb2phyacc0); + ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); + if (ret) + return ret; + + /* VCtrl = high nibble of addr, set PHY_NEW_REG_REQ */ + val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT); + + writel(val, reg_gusb2phyacc0); + ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0); + if (ret) + return ret; + + return 0; +} + +static int rtk_phy_set_page(struct phy_reg *phy_reg, int page) +{ + switch (page) { + case 0: + return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_0); + case 1: + return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_1); + case 2: + return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_2); + default: + pr_err("%s error page=%d\n", __func__, page); + } + + return -EINVAL; +} + +static u8 __updated_dc_disconnect_level_page0_0xe4(struct phy_cfg *phy_cfg, + struct phy_parameter *phy_parameter, u8 data) +{ + u8 ret; + s32 val; + s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask; + int offset = 4; + + val = (s32)((data >> offset) & dc_disconnect_mask) + + phy_parameter->efuse_usb_dc_dis + + phy_parameter->disconnection_compensate; + + if (val > dc_disconnect_mask) + val = dc_disconnect_mask; + else if (val < 0) + val = 0; + + ret = (data & (~(dc_disconnect_mask << offset))) | + (val & dc_disconnect_mask) << offset; + + return ret; +} + +/* updated disconnect level at page0 */ +static void update_dc_disconnect_level_at_page0(struct rtk_phy *rtk_phy, + struct phy_parameter *phy_parameter, bool update) +{ + struct phy_cfg *phy_cfg; + struct phy_reg *phy_reg; + struct phy_data *phy_data_page; + struct phy_data *phy_data; + u8 addr, data; + int offset = 4; + s32 dc_disconnect_mask; + int i; + + phy_cfg = rtk_phy->phy_cfg; + phy_reg = &phy_parameter->phy_reg; + + /* Set page 0 */ + phy_data_page = phy_cfg->page0; + rtk_phy_set_page(phy_reg, 0); + + i = page_addr_to_array_index(PAGE0_0XE4); + phy_data = phy_data_page + i; + if (!phy_data->addr) { + phy_data->addr = PAGE0_0XE4; + phy_data->data = rtk_phy_read(phy_reg, PAGE0_0XE4); + } + + addr = phy_data->addr; + data = phy_data->data; + dc_disconnect_mask = phy_cfg->dc_disconnect_mask; + + if (update) + data = __updated_dc_disconnect_level_page0_0xe4(phy_cfg, phy_parameter, data); + else + data = (data & ~(dc_disconnect_mask << offset)) | + (DEFAULT_DC_DISCONNECTION_VALUE << offset); + + if (rtk_phy_write(phy_reg, addr, data)) + dev_err(rtk_phy->dev, + "%s: Error to set page1 parameter addr=0x%x value=0x%x\n", + __func__, addr, data); +} + +static u8 __updated_dc_disconnect_level_page1_0xe2(struct phy_cfg *phy_cfg, + struct phy_parameter *phy_parameter, u8 data) +{ + u8 ret; + s32 val; + s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask; + + if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) { + val = (s32)(data & dc_disconnect_mask) + + phy_parameter->efuse_usb_dc_dis + + phy_parameter->disconnection_compensate; + } else { /* for CHECK_EFUSE_V2 or no efuse */ + if (phy_parameter->efuse_usb_dc_dis) + val = (s32)(phy_parameter->efuse_usb_dc_dis + + phy_parameter->disconnection_compensate); + else + val = (s32)((data & dc_disconnect_mask) + + phy_parameter->disconnection_compensate); + } + + if (val > dc_disconnect_mask) + val = dc_disconnect_mask; + else if (val < 0) + val = 0; + + ret = (data & (~dc_disconnect_mask)) | (val & dc_disconnect_mask); + + return ret; +} + +/* updated disconnect level at page1 */ +static void update_dc_disconnect_level_at_page1(struct rtk_phy *rtk_phy, + struct phy_parameter *phy_parameter, bool update) +{ + struct phy_cfg *phy_cfg; + struct phy_data *phy_data_page; + struct phy_data *phy_data; + struct phy_reg *phy_reg; + u8 addr, data; + s32 dc_disconnect_mask; + int i; + + phy_cfg = rtk_phy->phy_cfg; + phy_reg = &phy_parameter->phy_reg; + + /* Set page 1 */ + phy_data_page = phy_cfg->page1; + rtk_phy_set_page(phy_reg, 1); + + i = page_addr_to_array_index(PAGE1_0XE2); + phy_data = phy_data_page + i; + if (!phy_data->addr) { + phy_data->addr = PAGE1_0XE2; + phy_data->data = rtk_phy_read(phy_reg, PAGE1_0XE2); + } + + addr = phy_data->addr; + data = phy_data->data; + dc_disconnect_mask = phy_cfg->dc_disconnect_mask; + + if (update) + data = __updated_dc_disconnect_level_page1_0xe2(phy_cfg, phy_parameter, data); + else + data = (data & ~dc_disconnect_mask) | DEFAULT_DC_DISCONNECTION_VALUE; + + if (rtk_phy_write(phy_reg, addr, data)) + dev_err(rtk_phy->dev, + "%s: Error to set page1 parameter addr=0x%x value=0x%x\n", + __func__, addr, data); +} + +static void update_dc_disconnect_level(struct rtk_phy *rtk_phy, + struct phy_parameter *phy_parameter, bool update) +{ + struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; + + if (phy_cfg->usb_dc_disconnect_at_page0) + update_dc_disconnect_level_at_page0(rtk_phy, phy_parameter, update); + else + update_dc_disconnect_level_at_page1(rtk_phy, phy_parameter, update); +} + +static u8 __update_dc_driving_page0_0xe4(struct phy_cfg *phy_cfg, + struct phy_parameter *phy_parameter, u8 data) +{ + s32 driving_level_compensate = phy_parameter->driving_level_compensate; + s32 dc_driving_mask = phy_cfg->dc_driving_mask; + s32 val; + u8 ret; + + if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) { + val = (s32)(data & dc_driving_mask) + driving_level_compensate + + phy_parameter->efuse_usb_dc_cal; + } else { /* for CHECK_EFUSE_V2 or no efuse */ + if (phy_parameter->efuse_usb_dc_cal) + val = (s32)((phy_parameter->efuse_usb_dc_cal & dc_driving_mask) + + driving_level_compensate); + else + val = (s32)(data & dc_driving_mask); + } + + if (val > dc_driving_mask) + val = dc_driving_mask; + else if (val < 0) + val = 0; + + ret = (data & (~dc_driving_mask)) | (val & dc_driving_mask); + + return ret; +} + +static void update_dc_driving_level(struct rtk_phy *rtk_phy, + struct phy_parameter *phy_parameter) +{ + struct phy_cfg *phy_cfg; + struct phy_reg *phy_reg; + + phy_reg = &phy_parameter->phy_reg; + phy_cfg = rtk_phy->phy_cfg; + if (!phy_cfg->page0[4].addr) { + rtk_phy_set_page(phy_reg, 0); + phy_cfg->page0[4].addr = PAGE0_0XE4; + phy_cfg->page0[4].data = rtk_phy_read(phy_reg, PAGE0_0XE4); + } + + if (phy_parameter->driving_level != DEFAULT_DC_DRIVING_VALUE) { + u32 dc_driving_mask; + u8 driving_level; + u8 data; + + data = phy_cfg->page0[4].data; + dc_driving_mask = phy_cfg->dc_driving_mask; + driving_level = data & dc_driving_mask; + + dev_dbg(rtk_phy->dev, "%s driving_level=%d => dts driving_level=%d\n", + __func__, driving_level, phy_parameter->driving_level); + + phy_cfg->page0[4].data = (data & (~dc_driving_mask)) | + (phy_parameter->driving_level & dc_driving_mask); + } + + phy_cfg->page0[4].data = __update_dc_driving_page0_0xe4(phy_cfg, + phy_parameter, + phy_cfg->page0[4].data); +} + +static void update_hs_clk_select(struct rtk_phy *rtk_phy, + struct phy_parameter *phy_parameter) +{ + struct phy_cfg *phy_cfg; + struct phy_reg *phy_reg; + + phy_cfg = rtk_phy->phy_cfg; + phy_reg = &phy_parameter->phy_reg; + + if (phy_parameter->inverse_hstx_sync_clock) { + if (!phy_cfg->page0[6].addr) { + rtk_phy_set_page(phy_reg, 0); + phy_cfg->page0[6].addr = PAGE0_0XE6; + phy_cfg->page0[6].data = rtk_phy_read(phy_reg, PAGE0_0XE6); + } + + phy_cfg->page0[6].data = phy_cfg->page0[6].data | HS_CLK_SELECT; + } +} + +static void do_rtk_phy_toggle(struct rtk_phy *rtk_phy, + int index, bool connect) +{ + struct phy_parameter *phy_parameter; + struct phy_cfg *phy_cfg; + struct phy_reg *phy_reg; + struct phy_data *phy_data_page; + u8 addr, data; + int i; + + phy_cfg = rtk_phy->phy_cfg; + phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; + phy_reg = &phy_parameter->phy_reg; + + if (!phy_cfg->do_toggle) + goto out; + + if (phy_cfg->is_double_sensitivity_mode) + goto do_toggle_driving; + + /* Set page 0 */ + rtk_phy_set_page(phy_reg, 0); + + addr = PAGE0_0XE7; + data = rtk_phy_read(phy_reg, addr); + + if (connect) + rtk_phy_write(phy_reg, addr, data & (~SENSITIVITY_CTRL)); + else + rtk_phy_write(phy_reg, addr, data | (SENSITIVITY_CTRL)); + +do_toggle_driving: + + if (!phy_cfg->do_toggle_driving) + goto do_toggle; + + /* Page 0 addr 0xE4 driving capability */ + + /* Set page 0 */ + phy_data_page = phy_cfg->page0; + rtk_phy_set_page(phy_reg, 0); + + i = page_addr_to_array_index(PAGE0_0XE4); + addr = phy_data_page[i].addr; + data = phy_data_page[i].data; + + if (connect) { + rtk_phy_write(phy_reg, addr, data); + } else { + u8 value; + s32 tmp; + s32 driving_updated = + phy_cfg->driving_updated_for_dev_dis; + s32 dc_driving_mask = phy_cfg->dc_driving_mask; + + tmp = (s32)(data & dc_driving_mask) + driving_updated; + + if (tmp > dc_driving_mask) + tmp = dc_driving_mask; + else if (tmp < 0) + tmp = 0; + + value = (data & (~dc_driving_mask)) | (tmp & dc_driving_mask); + + rtk_phy_write(phy_reg, addr, value); + } + +do_toggle: + /* restore dc disconnect level before toggle */ + update_dc_disconnect_level(rtk_phy, phy_parameter, false); + + /* Set page 1 */ + rtk_phy_set_page(phy_reg, 1); + + addr = PAGE1_0XE0; + data = rtk_phy_read(phy_reg, addr); + + rtk_phy_write(phy_reg, addr, data & + (~ENABLE_AUTO_SENSITIVITY_CALIBRATION)); + mdelay(1); + rtk_phy_write(phy_reg, addr, data | + (ENABLE_AUTO_SENSITIVITY_CALIBRATION)); + + /* update dc disconnect level after toggle */ + update_dc_disconnect_level(rtk_phy, phy_parameter, true); + +out: + return; +} + +static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index) +{ + struct phy_parameter *phy_parameter; + struct phy_cfg *phy_cfg; + struct phy_data *phy_data_page; + struct phy_reg *phy_reg; + int i; + + phy_cfg = rtk_phy->phy_cfg; + phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; + phy_reg = &phy_parameter->phy_reg; + + if (phy_cfg->use_default_parameter) { + dev_dbg(rtk_phy->dev, "%s phy#%d use default parameter\n", + __func__, index); + goto do_toggle; + } + + /* Set page 0 */ + phy_data_page = phy_cfg->page0; + rtk_phy_set_page(phy_reg, 0); + + for (i = 0; i < phy_cfg->page0_size; i++) { + struct phy_data *phy_data = phy_data_page + i; + u8 addr = phy_data->addr; + u8 data = phy_data->data; + + if (!addr) + continue; + + if (rtk_phy_write(phy_reg, addr, data)) { + dev_err(rtk_phy->dev, + "%s: Error to set page0 parameter addr=0x%x value=0x%x\n", + __func__, addr, data); + return -EINVAL; + } + } + + /* Set page 1 */ + phy_data_page = phy_cfg->page1; + rtk_phy_set_page(phy_reg, 1); + + for (i = 0; i < phy_cfg->page1_size; i++) { + struct phy_data *phy_data = phy_data_page + i; + u8 addr = phy_data->addr; + u8 data = phy_data->data; + + if (!addr) + continue; + + if (rtk_phy_write(phy_reg, addr, data)) { + dev_err(rtk_phy->dev, + "%s: Error to set page1 parameter addr=0x%x value=0x%x\n", + __func__, addr, data); + return -EINVAL; + } + } + + if (phy_cfg->page2_size == 0) + goto do_toggle; + + /* Set page 2 */ + phy_data_page = phy_cfg->page2; + rtk_phy_set_page(phy_reg, 2); + + for (i = 0; i < phy_cfg->page2_size; i++) { + struct phy_data *phy_data = phy_data_page + i; + u8 addr = phy_data->addr; + u8 data = phy_data->data; + + if (!addr) + continue; + + if (rtk_phy_write(phy_reg, addr, data)) { + dev_err(rtk_phy->dev, + "%s: Error to set page2 parameter addr=0x%x value=0x%x\n", + __func__, addr, data); + return -EINVAL; + } + } + +do_toggle: + do_rtk_phy_toggle(rtk_phy, index, false); + + return 0; +} + +static int rtk_phy_init(struct phy *phy) +{ + struct rtk_phy *rtk_phy = phy_get_drvdata(phy); + unsigned long phy_init_time = jiffies; + int i, ret = 0; + + if (!rtk_phy) + return -EINVAL; + + for (i = 0; i < rtk_phy->num_phy; i++) + ret = do_rtk_phy_init(rtk_phy, i); + + dev_dbg(rtk_phy->dev, "Initialized RTK USB 2.0 PHY (take %dms)\n", + jiffies_to_msecs(jiffies - phy_init_time)); + return ret; +} + +static int rtk_phy_exit(struct phy *phy) +{ + return 0; +} + +static void rtk_phy_toggle(struct rtk_phy *rtk_phy, bool connect, int port) +{ + int index = port; + + if (index > rtk_phy->num_phy) { + dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n", + __func__, index, rtk_phy->num_phy); + return; + } + + do_rtk_phy_toggle(rtk_phy, index, connect); +} + +static int rtk_phy_connect(struct phy *phy, int port) +{ + struct rtk_phy *rtk_phy = phy_get_drvdata(phy); + + dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port); + rtk_phy_toggle(rtk_phy, true, port); + + return 0; +} + +static int rtk_phy_disconnect(struct phy *phy, int port) +{ + struct rtk_phy *rtk_phy = phy_get_drvdata(phy); + + dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port); + rtk_phy_toggle(rtk_phy, false, port); + + return 0; +} + +static const struct phy_ops ops = { + .init = rtk_phy_init, + .exit = rtk_phy_exit, + .connect = rtk_phy_connect, + .disconnect = rtk_phy_disconnect, + .owner = THIS_MODULE, +}; + +#ifdef CONFIG_DEBUG_FS +static struct dentry *create_phy_debug_root(void) +{ + struct dentry *phy_debug_root; + + phy_debug_root = debugfs_lookup("phy", usb_debug_root); + if (!phy_debug_root) + phy_debug_root = debugfs_create_dir("phy", usb_debug_root); + + return phy_debug_root; +} + +static int rtk_usb2_parameter_show(struct seq_file *s, void *unused) +{ + struct rtk_phy *rtk_phy = s->private; + struct phy_cfg *phy_cfg; + int i, index; + + phy_cfg = rtk_phy->phy_cfg; + + seq_puts(s, "Property:\n"); + seq_printf(s, " check_efuse: %s\n", + phy_cfg->check_efuse ? "Enable" : "Disable"); + seq_printf(s, " check_efuse_version: %d\n", + phy_cfg->check_efuse_version); + seq_printf(s, " efuse_dc_driving_rate: %d\n", + phy_cfg->efuse_dc_driving_rate); + seq_printf(s, " dc_driving_mask: 0x%x\n", + phy_cfg->dc_driving_mask); + seq_printf(s, " efuse_dc_disconnect_rate: %d\n", + phy_cfg->efuse_dc_disconnect_rate); + seq_printf(s, " dc_disconnect_mask: 0x%x\n", + phy_cfg->dc_disconnect_mask); + seq_printf(s, " usb_dc_disconnect_at_page0: %s\n", + phy_cfg->usb_dc_disconnect_at_page0 ? "true" : "false"); + seq_printf(s, " do_toggle: %s\n", + phy_cfg->do_toggle ? "Enable" : "Disable"); + seq_printf(s, " do_toggle_driving: %s\n", + phy_cfg->do_toggle_driving ? "Enable" : "Disable"); + seq_printf(s, " driving_updated_for_dev_dis: 0x%x\n", + phy_cfg->driving_updated_for_dev_dis); + seq_printf(s, " use_default_parameter: %s\n", + phy_cfg->use_default_parameter ? "Enable" : "Disable"); + seq_printf(s, " is_double_sensitivity_mode: %s\n", + phy_cfg->is_double_sensitivity_mode ? "Enable" : "Disable"); + + for (index = 0; index < rtk_phy->num_phy; index++) { + struct phy_parameter *phy_parameter; + struct phy_reg *phy_reg; + struct phy_data *phy_data_page; + + phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; + phy_reg = &phy_parameter->phy_reg; + + seq_printf(s, "PHY %d:\n", index); + + seq_puts(s, "Page 0:\n"); + /* Set page 0 */ + phy_data_page = phy_cfg->page0; + rtk_phy_set_page(phy_reg, 0); + + for (i = 0; i < phy_cfg->page0_size; i++) { + struct phy_data *phy_data = phy_data_page + i; + u8 addr = array_index_to_page_addr(i); + u8 data = phy_data->data; + u8 value = rtk_phy_read(phy_reg, addr); + + if (phy_data->addr) + seq_printf(s, " Page 0: addr=0x%x data=0x%02x ==> read value=0x%02x\n", + addr, data, value); + else + seq_printf(s, " Page 0: addr=0x%x data=none ==> read value=0x%02x\n", + addr, value); + } + + seq_puts(s, "Page 1:\n"); + /* Set page 1 */ + phy_data_page = phy_cfg->page1; + rtk_phy_set_page(phy_reg, 1); + + for (i = 0; i < phy_cfg->page1_size; i++) { + struct phy_data *phy_data = phy_data_page + i; + u8 addr = array_index_to_page_addr(i); + u8 data = phy_data->data; + u8 value = rtk_phy_read(phy_reg, addr); + + if (phy_data->addr) + seq_printf(s, " Page 1: addr=0x%x data=0x%02x ==> read value=0x%02x\n", + addr, data, value); + else + seq_printf(s, " Page 1: addr=0x%x data=none ==> read value=0x%02x\n", + addr, value); + } + + if (phy_cfg->page2_size == 0) + goto out; + + seq_puts(s, "Page 2:\n"); + /* Set page 2 */ + phy_data_page = phy_cfg->page2; + rtk_phy_set_page(phy_reg, 2); + + for (i = 0; i < phy_cfg->page2_size; i++) { + struct phy_data *phy_data = phy_data_page + i; + u8 addr = array_index_to_page_addr(i); + u8 data = phy_data->data; + u8 value = rtk_phy_read(phy_reg, addr); + + if (phy_data->addr) + seq_printf(s, " Page 2: addr=0x%x data=0x%02x ==> read value=0x%02x\n", + addr, data, value); + else + seq_printf(s, " Page 2: addr=0x%x data=none ==> read value=0x%02x\n", + addr, value); + } + +out: + seq_puts(s, "PHY Property:\n"); + seq_printf(s, " efuse_usb_dc_cal: %d\n", + (int)phy_parameter->efuse_usb_dc_cal); + seq_printf(s, " efuse_usb_dc_dis: %d\n", + (int)phy_parameter->efuse_usb_dc_dis); + seq_printf(s, " inverse_hstx_sync_clock: %s\n", + phy_parameter->inverse_hstx_sync_clock ? "Enable" : "Disable"); + seq_printf(s, " driving_level: %d\n", + phy_parameter->driving_level); + seq_printf(s, " driving_level_compensate: %d\n", + phy_parameter->driving_level_compensate); + seq_printf(s, " disconnection_compensate: %d\n", + phy_parameter->disconnection_compensate); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(rtk_usb2_parameter); + +static inline void create_debug_files(struct rtk_phy *rtk_phy) +{ + struct dentry *phy_debug_root = NULL; + + phy_debug_root = create_phy_debug_root(); + if (!phy_debug_root) + return; + + rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), + phy_debug_root); + + debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy, + &rtk_usb2_parameter_fops); +} + +static inline void remove_debug_files(struct rtk_phy *rtk_phy) +{ + debugfs_remove_recursive(rtk_phy->debug_dir); +} +#else +static inline void create_debug_files(struct rtk_phy *rtk_phy) { } +static inline void remove_debug_files(struct rtk_phy *rtk_phy) { } +#endif /* CONFIG_DEBUG_FS */ + +static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy, + struct phy_parameter *phy_parameter, int index) +{ + struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; + u8 value = 0; + struct nvmem_cell *cell; + struct soc_device_attribute rtk_soc_groot[] = { + { .family = "Realtek Groot",}, + { /* empty */ } }; + + if (!phy_cfg->check_efuse) + goto out; + + /* Read efuse for usb dc cal */ + cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-cal"); + if (IS_ERR(cell)) { + dev_dbg(rtk_phy->dev, "%s no usb-dc-cal: %ld\n", + __func__, PTR_ERR(cell)); + } else { + unsigned char *buf; + size_t buf_size; + + buf = nvmem_cell_read(cell, &buf_size); + if (!IS_ERR(buf)) { + value = buf[0] & phy_cfg->dc_driving_mask; + kfree(buf); + } + nvmem_cell_put(cell); + } + + if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) { + int rate = phy_cfg->efuse_dc_driving_rate; + + if (value <= EFUS_USB_DC_CAL_MAX) + phy_parameter->efuse_usb_dc_cal = (int8_t)(value * rate); + else + phy_parameter->efuse_usb_dc_cal = -(int8_t) + ((EFUS_USB_DC_CAL_MAX & value) * rate); + + if (soc_device_match(rtk_soc_groot)) { + dev_dbg(rtk_phy->dev, "For groot IC we need a workaround to adjust efuse_usb_dc_cal\n"); + + /* We don't multiple dc_cal_rate=2 for positive dc cal compensate */ + if (value <= EFUS_USB_DC_CAL_MAX) + phy_parameter->efuse_usb_dc_cal = (int8_t)(value); + + /* We set max dc cal compensate is 0x8 if otp is 0x7 */ + if (value == 0x7) + phy_parameter->efuse_usb_dc_cal = (int8_t)(value + 1); + } + } else { /* for CHECK_EFUSE_V2 */ + phy_parameter->efuse_usb_dc_cal = value & phy_cfg->dc_driving_mask; + } + + /* Read efuse for usb dc disconnect level */ + value = 0; + cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-dis"); + if (IS_ERR(cell)) { + dev_dbg(rtk_phy->dev, "%s no usb-dc-dis: %ld\n", + __func__, PTR_ERR(cell)); + } else { + unsigned char *buf; + size_t buf_size; + + buf = nvmem_cell_read(cell, &buf_size); + if (!IS_ERR(buf)) { + value = buf[0] & phy_cfg->dc_disconnect_mask; + kfree(buf); + } + nvmem_cell_put(cell); + } + + if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) { + int rate = phy_cfg->efuse_dc_disconnect_rate; + + if (value <= EFUS_USB_DC_DIS_MAX) + phy_parameter->efuse_usb_dc_dis = (int8_t)(value * rate); + else + phy_parameter->efuse_usb_dc_dis = -(int8_t) + ((EFUS_USB_DC_DIS_MAX & value) * rate); + } else { /* for CHECK_EFUSE_V2 */ + phy_parameter->efuse_usb_dc_dis = value & phy_cfg->dc_disconnect_mask; + } + +out: + return 0; +} + +static int parse_phy_data(struct rtk_phy *rtk_phy) +{ + struct device *dev = rtk_phy->dev; + struct device_node *np = dev->of_node; + struct phy_parameter *phy_parameter; + int ret = 0; + int index; + + rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) * + rtk_phy->num_phy, GFP_KERNEL); + if (!rtk_phy->phy_parameter) + return -ENOMEM; + + for (index = 0; index < rtk_phy->num_phy; index++) { + phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; + + phy_parameter->phy_reg.reg_wrap_vstatus = of_iomap(np, 0); + phy_parameter->phy_reg.reg_gusb2phyacc0 = of_iomap(np, 1) + index; + phy_parameter->phy_reg.vstatus_index = index; + + if (of_property_read_bool(np, "realtek,inverse-hstx-sync-clock")) + phy_parameter->inverse_hstx_sync_clock = true; + else + phy_parameter->inverse_hstx_sync_clock = false; + + if (of_property_read_u32_index(np, "realtek,driving-level", + index, &phy_parameter->driving_level)) + phy_parameter->driving_level = DEFAULT_DC_DRIVING_VALUE; + + if (of_property_read_u32_index(np, "realtek,driving-level-compensate", + index, &phy_parameter->driving_level_compensate)) + phy_parameter->driving_level_compensate = 0; + + if (of_property_read_u32_index(np, "realtek,disconnection-compensate", + index, &phy_parameter->disconnection_compensate)) + phy_parameter->disconnection_compensate = 0; + + get_phy_data_by_efuse(rtk_phy, phy_parameter, index); + + update_dc_driving_level(rtk_phy, phy_parameter); + + update_hs_clk_select(rtk_phy, phy_parameter); + } + + return ret; +} + +static int rtk_usb2phy_probe(struct platform_device *pdev) +{ + struct rtk_phy *rtk_phy; + struct device *dev = &pdev->dev; + struct phy *generic_phy; + struct phy_provider *phy_provider; + const struct phy_cfg *phy_cfg; + int ret = 0; + + phy_cfg = of_device_get_match_data(dev); + if (!phy_cfg) { + dev_err(dev, "phy config are not assigned!\n"); + return -EINVAL; + } + + rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL); + if (!rtk_phy) + return -ENOMEM; + + rtk_phy->dev = &pdev->dev; + rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL); + if (!rtk_phy->phy_cfg) + return -ENOMEM; + + memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg)); + + rtk_phy->num_phy = phy_cfg->num_phy; + + ret = parse_phy_data(rtk_phy); + if (ret) + goto err; + + platform_set_drvdata(pdev, rtk_phy); + + generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops); + if (IS_ERR(generic_phy)) + return PTR_ERR(generic_phy); + + phy_set_drvdata(generic_phy, rtk_phy); + + phy_provider = devm_of_phy_provider_register(rtk_phy->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + create_debug_files(rtk_phy); + +err: + return ret; +} + +static void rtk_usb2phy_remove(struct platform_device *pdev) +{ + struct rtk_phy *rtk_phy = platform_get_drvdata(pdev); + + remove_debug_files(rtk_phy); +} + +static const struct phy_cfg rtd1295_phy_cfg = { + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, + .page0 = { [0] = {0xe0, 0x90}, + [3] = {0xe3, 0x3a}, + [4] = {0xe4, 0x68}, + [6] = {0xe6, 0x91}, + [13] = {0xf5, 0x81}, + [15] = {0xf7, 0x02}, }, + .page1_size = 8, + .page1 = { /* default parameter */ }, + .page2_size = 0, + .page2 = { /* no parameter */ }, + .num_phy = 1, + .check_efuse = false, + .check_efuse_version = CHECK_EFUSE_V1, + .efuse_dc_driving_rate = 1, + .dc_driving_mask = 0xf, + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, + .dc_disconnect_mask = 0xf, + .usb_dc_disconnect_at_page0 = true, + .do_toggle = true, + .do_toggle_driving = false, + .driving_updated_for_dev_dis = 0xf, + .use_default_parameter = false, + .is_double_sensitivity_mode = false, +}; + +static const struct phy_cfg rtd1395_phy_cfg = { + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, + .page0 = { [4] = {0xe4, 0xac}, + [13] = {0xf5, 0x00}, + [15] = {0xf7, 0x02}, }, + .page1_size = 8, + .page1 = { /* default parameter */ }, + .page2_size = 0, + .page2 = { /* no parameter */ }, + .num_phy = 1, + .check_efuse = false, + .check_efuse_version = CHECK_EFUSE_V1, + .efuse_dc_driving_rate = 1, + .dc_driving_mask = 0xf, + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, + .dc_disconnect_mask = 0xf, + .usb_dc_disconnect_at_page0 = true, + .do_toggle = true, + .do_toggle_driving = false, + .driving_updated_for_dev_dis = 0xf, + .use_default_parameter = false, + .is_double_sensitivity_mode = false, +}; + +static const struct phy_cfg rtd1395_phy_cfg_2port = { + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, + .page0 = { [4] = {0xe4, 0xac}, + [13] = {0xf5, 0x00}, + [15] = {0xf7, 0x02}, }, + .page1_size = 8, + .page1 = { /* default parameter */ }, + .page2_size = 0, + .page2 = { /* no parameter */ }, + .num_phy = 2, + .check_efuse = false, + .check_efuse_version = CHECK_EFUSE_V1, + .efuse_dc_driving_rate = 1, + .dc_driving_mask = 0xf, + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, + .dc_disconnect_mask = 0xf, + .usb_dc_disconnect_at_page0 = true, + .do_toggle = true, + .do_toggle_driving = false, + .driving_updated_for_dev_dis = 0xf, + .use_default_parameter = false, + .is_double_sensitivity_mode = false, +}; + +static const struct phy_cfg rtd1619_phy_cfg = { + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, + .page0 = { [4] = {0xe4, 0x68}, }, + .page1_size = 8, + .page1 = { /* default parameter */ }, + .page2_size = 0, + .page2 = { /* no parameter */ }, + .num_phy = 1, + .check_efuse = true, + .check_efuse_version = CHECK_EFUSE_V1, + .efuse_dc_driving_rate = 1, + .dc_driving_mask = 0xf, + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, + .dc_disconnect_mask = 0xf, + .usb_dc_disconnect_at_page0 = true, + .do_toggle = true, + .do_toggle_driving = false, + .driving_updated_for_dev_dis = 0xf, + .use_default_parameter = false, + .is_double_sensitivity_mode = false, +}; + +static const struct phy_cfg rtd1319_phy_cfg = { + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, + .page0 = { [0] = {0xe0, 0x18}, + [4] = {0xe4, 0x6a}, + [7] = {0xe7, 0x71}, + [13] = {0xf5, 0x15}, + [15] = {0xf7, 0x32}, }, + .page1_size = 8, + .page1 = { [3] = {0xe3, 0x44}, }, + .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, + .page2 = { [0] = {0xe0, 0x01}, }, + .num_phy = 1, + .check_efuse = true, + .check_efuse_version = CHECK_EFUSE_V1, + .efuse_dc_driving_rate = 1, + .dc_driving_mask = 0xf, + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, + .dc_disconnect_mask = 0xf, + .usb_dc_disconnect_at_page0 = true, + .do_toggle = true, + .do_toggle_driving = true, + .driving_updated_for_dev_dis = 0xf, + .use_default_parameter = false, + .is_double_sensitivity_mode = true, +}; + +static const struct phy_cfg rtd1312c_phy_cfg = { + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, + .page0 = { [0] = {0xe0, 0x14}, + [4] = {0xe4, 0x67}, + [5] = {0xe5, 0x55}, }, + .page1_size = 8, + .page1 = { [3] = {0xe3, 0x23}, + [6] = {0xe6, 0x58}, }, + .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, + .page2 = { /* default parameter */ }, + .num_phy = 1, + .check_efuse = true, + .check_efuse_version = CHECK_EFUSE_V1, + .efuse_dc_driving_rate = 1, + .dc_driving_mask = 0xf, + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, + .dc_disconnect_mask = 0xf, + .usb_dc_disconnect_at_page0 = true, + .do_toggle = true, + .do_toggle_driving = true, + .driving_updated_for_dev_dis = 0xf, + .use_default_parameter = false, + .is_double_sensitivity_mode = true, +}; + +static const struct phy_cfg rtd1619b_phy_cfg = { + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, + .page0 = { [0] = {0xe0, 0xa3}, + [4] = {0xe4, 0xa8}, + [5] = {0xe5, 0x4f}, + [6] = {0xe6, 0x02}, }, + .page1_size = 8, + .page1 = { [3] = {0xe3, 0x64}, }, + .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, + .page2 = { [7] = {0xe7, 0x45}, }, + .num_phy = 1, + .check_efuse = true, + .check_efuse_version = CHECK_EFUSE_V1, + .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE, + .dc_driving_mask = 0x1f, + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, + .dc_disconnect_mask = 0xf, + .usb_dc_disconnect_at_page0 = false, + .do_toggle = true, + .do_toggle_driving = true, + .driving_updated_for_dev_dis = 0x8, + .use_default_parameter = false, + .is_double_sensitivity_mode = true, +}; + +static const struct phy_cfg rtd1319d_phy_cfg = { + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, + .page0 = { [0] = {0xe0, 0xa3}, + [4] = {0xe4, 0x8e}, + [5] = {0xe5, 0x4f}, + [6] = {0xe6, 0x02}, }, + .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE, + .page1 = { [14] = {0xf5, 0x1}, }, + .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, + .page2 = { [7] = {0xe7, 0x44}, }, + .check_efuse = true, + .num_phy = 1, + .check_efuse_version = CHECK_EFUSE_V1, + .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE, + .dc_driving_mask = 0x1f, + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, + .dc_disconnect_mask = 0xf, + .usb_dc_disconnect_at_page0 = false, + .do_toggle = true, + .do_toggle_driving = false, + .driving_updated_for_dev_dis = 0x8, + .use_default_parameter = false, + .is_double_sensitivity_mode = true, +}; + +static const struct phy_cfg rtd1315e_phy_cfg = { + .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE, + .page0 = { [0] = {0xe0, 0xa3}, + [4] = {0xe4, 0x8c}, + [5] = {0xe5, 0x4f}, + [6] = {0xe6, 0x02}, }, + .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE, + .page1 = { [3] = {0xe3, 0x7f}, + [14] = {0xf5, 0x01}, }, + .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE, + .page2 = { [7] = {0xe7, 0x44}, }, + .num_phy = 1, + .check_efuse = true, + .check_efuse_version = CHECK_EFUSE_V2, + .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE, + .dc_driving_mask = 0x1f, + .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE, + .dc_disconnect_mask = 0xf, + .usb_dc_disconnect_at_page0 = false, + .do_toggle = true, + .do_toggle_driving = false, + .driving_updated_for_dev_dis = 0x8, + .use_default_parameter = false, + .is_double_sensitivity_mode = true, +}; + +static const struct of_device_id usbphy_rtk_dt_match[] = { + { .compatible = "realtek,rtd1295-usb2phy", .data = &rtd1295_phy_cfg }, + { .compatible = "realtek,rtd1312c-usb2phy", .data = &rtd1312c_phy_cfg }, + { .compatible = "realtek,rtd1315e-usb2phy", .data = &rtd1315e_phy_cfg }, + { .compatible = "realtek,rtd1319-usb2phy", .data = &rtd1319_phy_cfg }, + { .compatible = "realtek,rtd1319d-usb2phy", .data = &rtd1319d_phy_cfg }, + { .compatible = "realtek,rtd1395-usb2phy", .data = &rtd1395_phy_cfg }, + { .compatible = "realtek,rtd1395-usb2phy-2port", .data = &rtd1395_phy_cfg_2port }, + { .compatible = "realtek,rtd1619-usb2phy", .data = &rtd1619_phy_cfg }, + { .compatible = "realtek,rtd1619b-usb2phy", .data = &rtd1619b_phy_cfg }, + {}, +}; +MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match); + +static struct platform_driver rtk_usb2phy_driver = { + .probe = rtk_usb2phy_probe, + .remove = rtk_usb2phy_remove, + .driver = { + .name = "rtk-usb2phy", + .of_match_table = usbphy_rtk_dt_match, + }, +}; + +module_platform_driver(rtk_usb2phy_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>"); +MODULE_DESCRIPTION("Realtek usb 2.0 phy driver"); diff --git a/drivers/phy/realtek/phy-rtk-usb3.c b/drivers/phy/realtek/phy-rtk-usb3.c new file mode 100644 index 000000000000..cce453686db2 --- /dev/null +++ b/drivers/phy/realtek/phy-rtk-usb3.c @@ -0,0 +1,750 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * phy-rtk-usb3.c RTK usb3.0 phy driver + * + * copyright (c) 2023 realtek semiconductor corporation + * + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> +#include <linux/uaccess.h> +#include <linux/debugfs.h> +#include <linux/nvmem-consumer.h> +#include <linux/regmap.h> +#include <linux/sys_soc.h> +#include <linux/mfd/syscon.h> +#include <linux/phy/phy.h> +#include <linux/usb.h> + +#define USB_MDIO_CTRL_PHY_BUSY BIT(7) +#define USB_MDIO_CTRL_PHY_WRITE BIT(0) +#define USB_MDIO_CTRL_PHY_ADDR_SHIFT 8 +#define USB_MDIO_CTRL_PHY_DATA_SHIFT 16 + +#define MAX_USB_PHY_DATA_SIZE 0x30 +#define PHY_ADDR_0X09 0x09 +#define PHY_ADDR_0X0B 0x0b +#define PHY_ADDR_0X0D 0x0d +#define PHY_ADDR_0X10 0x10 +#define PHY_ADDR_0X1F 0x1f +#define PHY_ADDR_0X20 0x20 +#define PHY_ADDR_0X21 0x21 +#define PHY_ADDR_0X30 0x30 + +#define REG_0X09_FORCE_CALIBRATION BIT(9) +#define REG_0X0B_RX_OFFSET_RANGE_MASK 0xc +#define REG_0X0D_RX_DEBUG_TEST_EN BIT(6) +#define REG_0X10_DEBUG_MODE_SETTING 0x3c0 +#define REG_0X10_DEBUG_MODE_SETTING_MASK 0x3f8 +#define REG_0X1F_RX_OFFSET_CODE_MASK 0x1e + +#define USB_U3_TX_LFPS_SWING_TRIM_SHIFT 4 +#define USB_U3_TX_LFPS_SWING_TRIM_MASK 0xf +#define AMPLITUDE_CONTROL_COARSE_MASK 0xff +#define AMPLITUDE_CONTROL_FINE_MASK 0xffff +#define AMPLITUDE_CONTROL_COARSE_DEFAULT 0xff +#define AMPLITUDE_CONTROL_FINE_DEFAULT 0xffff + +#define PHY_ADDR_MAP_ARRAY_INDEX(addr) (addr) +#define ARRAY_INDEX_MAP_PHY_ADDR(index) (index) + +struct phy_reg { + void __iomem *reg_mdio_ctl; +}; + +struct phy_data { + u8 addr; + u16 data; +}; + +struct phy_cfg { + int param_size; + struct phy_data param[MAX_USB_PHY_DATA_SIZE]; + + bool check_efuse; + bool do_toggle; + bool do_toggle_once; + bool use_default_parameter; + bool check_rx_front_end_offset; +}; + +struct phy_parameter { + struct phy_reg phy_reg; + + /* Get from efuse */ + u8 efuse_usb_u3_tx_lfps_swing_trim; + + /* Get from dts */ + u32 amplitude_control_coarse; + u32 amplitude_control_fine; +}; + +struct rtk_phy { + struct device *dev; + + struct phy_cfg *phy_cfg; + int num_phy; + struct phy_parameter *phy_parameter; + + struct dentry *debug_dir; +}; + +#define PHY_IO_TIMEOUT_USEC (50000) +#define PHY_IO_DELAY_US (100) + +static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result) +{ + int ret; + unsigned int val; + + ret = read_poll_timeout(readl, val, ((val & mask) == result), + PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg); + if (ret) { + pr_err("%s can't program USB phy\n", __func__); + return -ETIMEDOUT; + } + + return 0; +} + +static int rtk_phy3_wait_vbusy(struct phy_reg *phy_reg) +{ + return utmi_wait_register(phy_reg->reg_mdio_ctl, USB_MDIO_CTRL_PHY_BUSY, 0); +} + +static u16 rtk_phy_read(struct phy_reg *phy_reg, char addr) +{ + unsigned int tmp; + u32 value; + + tmp = (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT); + + writel(tmp, phy_reg->reg_mdio_ctl); + + rtk_phy3_wait_vbusy(phy_reg); + + value = readl(phy_reg->reg_mdio_ctl); + value = value >> USB_MDIO_CTRL_PHY_DATA_SHIFT; + + return (u16)value; +} + +static int rtk_phy_write(struct phy_reg *phy_reg, char addr, u16 data) +{ + unsigned int val; + + val = USB_MDIO_CTRL_PHY_WRITE | + (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT) | + (data << USB_MDIO_CTRL_PHY_DATA_SHIFT); + + writel(val, phy_reg->reg_mdio_ctl); + + rtk_phy3_wait_vbusy(phy_reg); + + return 0; +} + +static void do_rtk_usb3_phy_toggle(struct rtk_phy *rtk_phy, int index, bool connect) +{ + struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; + struct phy_reg *phy_reg; + struct phy_parameter *phy_parameter; + struct phy_data *phy_data; + u8 addr; + u16 data; + int i; + + phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; + phy_reg = &phy_parameter->phy_reg; + + if (!phy_cfg->do_toggle) + return; + + i = PHY_ADDR_MAP_ARRAY_INDEX(PHY_ADDR_0X09); + phy_data = phy_cfg->param + i; + addr = phy_data->addr; + data = phy_data->data; + + if (!addr && !data) { + addr = PHY_ADDR_0X09; + data = rtk_phy_read(phy_reg, addr); + phy_data->addr = addr; + phy_data->data = data; + } + + rtk_phy_write(phy_reg, addr, data & (~REG_0X09_FORCE_CALIBRATION)); + mdelay(1); + rtk_phy_write(phy_reg, addr, data | REG_0X09_FORCE_CALIBRATION); +} + +static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index) +{ + struct phy_cfg *phy_cfg; + struct phy_reg *phy_reg; + struct phy_parameter *phy_parameter; + int i = 0; + + phy_cfg = rtk_phy->phy_cfg; + phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; + phy_reg = &phy_parameter->phy_reg; + + if (phy_cfg->use_default_parameter) + goto do_toggle; + + for (i = 0; i < phy_cfg->param_size; i++) { + struct phy_data *phy_data = phy_cfg->param + i; + u8 addr = phy_data->addr; + u16 data = phy_data->data; + + if (!addr && !data) + continue; + + rtk_phy_write(phy_reg, addr, data); + } + +do_toggle: + if (phy_cfg->do_toggle_once) + phy_cfg->do_toggle = true; + + do_rtk_usb3_phy_toggle(rtk_phy, index, false); + + if (phy_cfg->do_toggle_once) { + u16 check_value = 0; + int count = 10; + u16 value_0x0d, value_0x10; + + /* Enable Debug mode by set 0x0D and 0x10 */ + value_0x0d = rtk_phy_read(phy_reg, PHY_ADDR_0X0D); + value_0x10 = rtk_phy_read(phy_reg, PHY_ADDR_0X10); + + rtk_phy_write(phy_reg, PHY_ADDR_0X0D, + value_0x0d | REG_0X0D_RX_DEBUG_TEST_EN); + rtk_phy_write(phy_reg, PHY_ADDR_0X10, + (value_0x10 & ~REG_0X10_DEBUG_MODE_SETTING_MASK) | + REG_0X10_DEBUG_MODE_SETTING); + + check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30); + + while (!(check_value & BIT(15))) { + check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30); + mdelay(1); + if (count-- < 0) + break; + } + + if (!(check_value & BIT(15))) + dev_info(rtk_phy->dev, "toggle fail addr=0x%02x, data=0x%04x\n", + PHY_ADDR_0X30, check_value); + + /* Disable Debug mode by set 0x0D and 0x10 to default*/ + rtk_phy_write(phy_reg, PHY_ADDR_0X0D, value_0x0d); + rtk_phy_write(phy_reg, PHY_ADDR_0X10, value_0x10); + + phy_cfg->do_toggle = false; + } + + if (phy_cfg->check_rx_front_end_offset) { + u16 rx_offset_code, rx_offset_range; + u16 code_mask = REG_0X1F_RX_OFFSET_CODE_MASK; + u16 range_mask = REG_0X0B_RX_OFFSET_RANGE_MASK; + bool do_update = false; + + rx_offset_code = rtk_phy_read(phy_reg, PHY_ADDR_0X1F); + if (((rx_offset_code & code_mask) == 0x0) || + ((rx_offset_code & code_mask) == code_mask)) + do_update = true; + + rx_offset_range = rtk_phy_read(phy_reg, PHY_ADDR_0X0B); + if (((rx_offset_range & range_mask) == range_mask) && do_update) { + dev_warn(rtk_phy->dev, "Don't update rx_offset_range (rx_offset_code=0x%x, rx_offset_range=0x%x)\n", + rx_offset_code, rx_offset_range); + do_update = false; + } + + if (do_update) { + u16 tmp1, tmp2; + + tmp1 = rx_offset_range & (~range_mask); + tmp2 = rx_offset_range & range_mask; + tmp2 += (1 << 2); + rx_offset_range = tmp1 | (tmp2 & range_mask); + rtk_phy_write(phy_reg, PHY_ADDR_0X0B, rx_offset_range); + goto do_toggle; + } + } + + return 0; +} + +static int rtk_phy_init(struct phy *phy) +{ + struct rtk_phy *rtk_phy = phy_get_drvdata(phy); + int ret = 0; + int i; + unsigned long phy_init_time = jiffies; + + for (i = 0; i < rtk_phy->num_phy; i++) + ret = do_rtk_phy_init(rtk_phy, i); + + dev_dbg(rtk_phy->dev, "Initialized RTK USB 3.0 PHY (take %dms)\n", + jiffies_to_msecs(jiffies - phy_init_time)); + + return ret; +} + +static int rtk_phy_exit(struct phy *phy) +{ + return 0; +} + +static void rtk_phy_toggle(struct rtk_phy *rtk_phy, bool connect, int port) +{ + int index = port; + + if (index > rtk_phy->num_phy) { + dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n", + __func__, index, rtk_phy->num_phy); + return; + } + + do_rtk_usb3_phy_toggle(rtk_phy, index, connect); +} + +static int rtk_phy_connect(struct phy *phy, int port) +{ + struct rtk_phy *rtk_phy = phy_get_drvdata(phy); + + dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port); + rtk_phy_toggle(rtk_phy, true, port); + + return 0; +} + +static int rtk_phy_disconnect(struct phy *phy, int port) +{ + struct rtk_phy *rtk_phy = phy_get_drvdata(phy); + + dev_dbg(rtk_phy->dev, "%s port=%d\n", __func__, port); + rtk_phy_toggle(rtk_phy, false, port); + + return 0; +} + +static const struct phy_ops ops = { + .init = rtk_phy_init, + .exit = rtk_phy_exit, + .connect = rtk_phy_connect, + .disconnect = rtk_phy_disconnect, + .owner = THIS_MODULE, +}; + +#ifdef CONFIG_DEBUG_FS +static struct dentry *create_phy_debug_root(void) +{ + struct dentry *phy_debug_root; + + phy_debug_root = debugfs_lookup("phy", usb_debug_root); + if (!phy_debug_root) + phy_debug_root = debugfs_create_dir("phy", usb_debug_root); + + return phy_debug_root; +} + +static int rtk_usb3_parameter_show(struct seq_file *s, void *unused) +{ + struct rtk_phy *rtk_phy = s->private; + struct phy_cfg *phy_cfg; + int i, index; + + phy_cfg = rtk_phy->phy_cfg; + + seq_puts(s, "Property:\n"); + seq_printf(s, " check_efuse: %s\n", + phy_cfg->check_efuse ? "Enable" : "Disable"); + seq_printf(s, " do_toggle: %s\n", + phy_cfg->do_toggle ? "Enable" : "Disable"); + seq_printf(s, " do_toggle_once: %s\n", + phy_cfg->do_toggle_once ? "Enable" : "Disable"); + seq_printf(s, " use_default_parameter: %s\n", + phy_cfg->use_default_parameter ? "Enable" : "Disable"); + + for (index = 0; index < rtk_phy->num_phy; index++) { + struct phy_reg *phy_reg; + struct phy_parameter *phy_parameter; + + phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; + phy_reg = &phy_parameter->phy_reg; + + seq_printf(s, "PHY %d:\n", index); + + for (i = 0; i < phy_cfg->param_size; i++) { + struct phy_data *phy_data = phy_cfg->param + i; + u8 addr = ARRAY_INDEX_MAP_PHY_ADDR(i); + u16 data = phy_data->data; + + if (!phy_data->addr && !data) + seq_printf(s, " addr = 0x%02x, data = none ==> read value = 0x%04x\n", + addr, rtk_phy_read(phy_reg, addr)); + else + seq_printf(s, " addr = 0x%02x, data = 0x%04x ==> read value = 0x%04x\n", + addr, data, rtk_phy_read(phy_reg, addr)); + } + + seq_puts(s, "PHY Property:\n"); + seq_printf(s, " efuse_usb_u3_tx_lfps_swing_trim: 0x%x\n", + (int)phy_parameter->efuse_usb_u3_tx_lfps_swing_trim); + seq_printf(s, " amplitude_control_coarse: 0x%x\n", + (int)phy_parameter->amplitude_control_coarse); + seq_printf(s, " amplitude_control_fine: 0x%x\n", + (int)phy_parameter->amplitude_control_fine); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(rtk_usb3_parameter); + +static inline void create_debug_files(struct rtk_phy *rtk_phy) +{ + struct dentry *phy_debug_root = NULL; + + phy_debug_root = create_phy_debug_root(); + + if (!phy_debug_root) + return; + + rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), phy_debug_root); + + debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy, + &rtk_usb3_parameter_fops); +} + +static inline void remove_debug_files(struct rtk_phy *rtk_phy) +{ + debugfs_remove_recursive(rtk_phy->debug_dir); +} +#else +static inline void create_debug_files(struct rtk_phy *rtk_phy) { } +static inline void remove_debug_files(struct rtk_phy *rtk_phy) { } +#endif /* CONFIG_DEBUG_FS */ + +static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy, + struct phy_parameter *phy_parameter, int index) +{ + struct phy_cfg *phy_cfg = rtk_phy->phy_cfg; + u8 value = 0; + struct nvmem_cell *cell; + + if (!phy_cfg->check_efuse) + goto out; + + cell = nvmem_cell_get(rtk_phy->dev, "usb_u3_tx_lfps_swing_trim"); + if (IS_ERR(cell)) { + dev_dbg(rtk_phy->dev, "%s no usb_u3_tx_lfps_swing_trim: %ld\n", + __func__, PTR_ERR(cell)); + } else { + unsigned char *buf; + size_t buf_size; + + buf = nvmem_cell_read(cell, &buf_size); + if (!IS_ERR(buf)) { + value = buf[0] & USB_U3_TX_LFPS_SWING_TRIM_MASK; + kfree(buf); + } + nvmem_cell_put(cell); + } + + if (value > 0 && value < 0x8) + phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = 0x8; + else + phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = (u8)value; + +out: + return 0; +} + +static void update_amplitude_control_value(struct rtk_phy *rtk_phy, + struct phy_parameter *phy_parameter) +{ + struct phy_cfg *phy_cfg; + struct phy_reg *phy_reg; + + phy_reg = &phy_parameter->phy_reg; + phy_cfg = rtk_phy->phy_cfg; + + if (phy_parameter->amplitude_control_coarse != AMPLITUDE_CONTROL_COARSE_DEFAULT) { + u16 val_mask = AMPLITUDE_CONTROL_COARSE_MASK; + u16 data; + + if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) { + phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20; + data = rtk_phy_read(phy_reg, PHY_ADDR_0X20); + } else { + data = phy_cfg->param[PHY_ADDR_0X20].data; + } + + data &= (~val_mask); + data |= (phy_parameter->amplitude_control_coarse & val_mask); + + phy_cfg->param[PHY_ADDR_0X20].data = data; + } + + if (phy_parameter->efuse_usb_u3_tx_lfps_swing_trim) { + u8 efuse_val = phy_parameter->efuse_usb_u3_tx_lfps_swing_trim; + u16 val_mask = USB_U3_TX_LFPS_SWING_TRIM_MASK; + int val_shift = USB_U3_TX_LFPS_SWING_TRIM_SHIFT; + u16 data; + + if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) { + phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20; + data = rtk_phy_read(phy_reg, PHY_ADDR_0X20); + } else { + data = phy_cfg->param[PHY_ADDR_0X20].data; + } + + data &= ~(val_mask << val_shift); + data |= ((efuse_val & val_mask) << val_shift); + + phy_cfg->param[PHY_ADDR_0X20].data = data; + } + + if (phy_parameter->amplitude_control_fine != AMPLITUDE_CONTROL_FINE_DEFAULT) { + u16 val_mask = AMPLITUDE_CONTROL_FINE_MASK; + + if (!phy_cfg->param[PHY_ADDR_0X21].addr && !phy_cfg->param[PHY_ADDR_0X21].data) + phy_cfg->param[PHY_ADDR_0X21].addr = PHY_ADDR_0X21; + + phy_cfg->param[PHY_ADDR_0X21].data = + phy_parameter->amplitude_control_fine & val_mask; + } +} + +static int parse_phy_data(struct rtk_phy *rtk_phy) +{ + struct device *dev = rtk_phy->dev; + struct phy_parameter *phy_parameter; + int ret = 0; + int index; + + rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) * + rtk_phy->num_phy, GFP_KERNEL); + if (!rtk_phy->phy_parameter) + return -ENOMEM; + + for (index = 0; index < rtk_phy->num_phy; index++) { + phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index]; + + phy_parameter->phy_reg.reg_mdio_ctl = of_iomap(dev->of_node, 0) + index; + + /* Amplitude control address 0x20 bit 0 to bit 7 */ + if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-coarse-tuning", + &phy_parameter->amplitude_control_coarse)) + phy_parameter->amplitude_control_coarse = AMPLITUDE_CONTROL_COARSE_DEFAULT; + + /* Amplitude control address 0x21 bit 0 to bit 16 */ + if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-fine-tuning", + &phy_parameter->amplitude_control_fine)) + phy_parameter->amplitude_control_fine = AMPLITUDE_CONTROL_FINE_DEFAULT; + + get_phy_data_by_efuse(rtk_phy, phy_parameter, index); + + update_amplitude_control_value(rtk_phy, phy_parameter); + } + + return ret; +} + +static int rtk_usb3phy_probe(struct platform_device *pdev) +{ + struct rtk_phy *rtk_phy; + struct device *dev = &pdev->dev; + struct phy *generic_phy; + struct phy_provider *phy_provider; + const struct phy_cfg *phy_cfg; + int ret; + + phy_cfg = of_device_get_match_data(dev); + if (!phy_cfg) { + dev_err(dev, "phy config are not assigned!\n"); + return -EINVAL; + } + + rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL); + if (!rtk_phy) + return -ENOMEM; + + rtk_phy->dev = &pdev->dev; + rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL); + if (!rtk_phy->phy_cfg) + return -ENOMEM; + + memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg)); + + rtk_phy->num_phy = 1; + + ret = parse_phy_data(rtk_phy); + if (ret) + goto err; + + platform_set_drvdata(pdev, rtk_phy); + + generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops); + if (IS_ERR(generic_phy)) + return PTR_ERR(generic_phy); + + phy_set_drvdata(generic_phy, rtk_phy); + + phy_provider = devm_of_phy_provider_register(rtk_phy->dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + create_debug_files(rtk_phy); + +err: + return ret; +} + +static void rtk_usb3phy_remove(struct platform_device *pdev) +{ + struct rtk_phy *rtk_phy = platform_get_drvdata(pdev); + + remove_debug_files(rtk_phy); +} + +static const struct phy_cfg rtd1295_phy_cfg = { + .param_size = MAX_USB_PHY_DATA_SIZE, + .param = { [0] = {0x01, 0x4008}, [1] = {0x01, 0xe046}, + [2] = {0x02, 0x6046}, [3] = {0x03, 0x2779}, + [4] = {0x04, 0x72f5}, [5] = {0x05, 0x2ad3}, + [6] = {0x06, 0x000e}, [7] = {0x07, 0x2e00}, + [8] = {0x08, 0x3591}, [9] = {0x09, 0x525c}, + [10] = {0x0a, 0xa600}, [11] = {0x0b, 0xa904}, + [12] = {0x0c, 0xc000}, [13] = {0x0d, 0xef1c}, + [14] = {0x0e, 0x2000}, [15] = {0x0f, 0x0000}, + [16] = {0x10, 0x000c}, [17] = {0x11, 0x4c00}, + [18] = {0x12, 0xfc00}, [19] = {0x13, 0x0c81}, + [20] = {0x14, 0xde01}, [21] = {0x15, 0x0000}, + [22] = {0x16, 0x0000}, [23] = {0x17, 0x0000}, + [24] = {0x18, 0x0000}, [25] = {0x19, 0x4004}, + [26] = {0x1a, 0x1260}, [27] = {0x1b, 0xff00}, + [28] = {0x1c, 0xcb00}, [29] = {0x1d, 0xa03f}, + [30] = {0x1e, 0xc2e0}, [31] = {0x1f, 0x2807}, + [32] = {0x20, 0x947a}, [33] = {0x21, 0x88aa}, + [34] = {0x22, 0x0057}, [35] = {0x23, 0xab66}, + [36] = {0x24, 0x0800}, [37] = {0x25, 0x0000}, + [38] = {0x26, 0x040a}, [39] = {0x27, 0x01d6}, + [40] = {0x28, 0xf8c2}, [41] = {0x29, 0x3080}, + [42] = {0x2a, 0x3082}, [43] = {0x2b, 0x2078}, + [44] = {0x2c, 0xffff}, [45] = {0x2d, 0xffff}, + [46] = {0x2e, 0x0000}, [47] = {0x2f, 0x0040}, }, + .check_efuse = false, + .do_toggle = true, + .do_toggle_once = false, + .use_default_parameter = false, + .check_rx_front_end_offset = false, +}; + +static const struct phy_cfg rtd1619_phy_cfg = { + .param_size = MAX_USB_PHY_DATA_SIZE, + .param = { [8] = {0x08, 0x3591}, + [38] = {0x26, 0x840b}, + [40] = {0x28, 0xf842}, }, + .check_efuse = false, + .do_toggle = true, + .do_toggle_once = false, + .use_default_parameter = false, + .check_rx_front_end_offset = false, +}; + +static const struct phy_cfg rtd1319_phy_cfg = { + .param_size = MAX_USB_PHY_DATA_SIZE, + .param = { [1] = {0x01, 0xac86}, + [6] = {0x06, 0x0003}, + [9] = {0x09, 0x924c}, + [10] = {0x0a, 0xa608}, + [11] = {0x0b, 0xb905}, + [14] = {0x0e, 0x2010}, + [32] = {0x20, 0x705a}, + [33] = {0x21, 0xf645}, + [34] = {0x22, 0x0013}, + [35] = {0x23, 0xcb66}, + [41] = {0x29, 0xff00}, }, + .check_efuse = true, + .do_toggle = true, + .do_toggle_once = false, + .use_default_parameter = false, + .check_rx_front_end_offset = false, +}; + +static const struct phy_cfg rtd1619b_phy_cfg = { + .param_size = MAX_USB_PHY_DATA_SIZE, + .param = { [1] = {0x01, 0xac8c}, + [6] = {0x06, 0x0017}, + [9] = {0x09, 0x724c}, + [10] = {0x0a, 0xb610}, + [11] = {0x0b, 0xb90d}, + [13] = {0x0d, 0xef2a}, + [15] = {0x0f, 0x9050}, + [16] = {0x10, 0x000c}, + [32] = {0x20, 0x70ff}, + [34] = {0x22, 0x0013}, + [35] = {0x23, 0xdb66}, + [38] = {0x26, 0x8609}, + [41] = {0x29, 0xff13}, + [42] = {0x2a, 0x3070}, }, + .check_efuse = true, + .do_toggle = false, + .do_toggle_once = true, + .use_default_parameter = false, + .check_rx_front_end_offset = false, +}; + +static const struct phy_cfg rtd1319d_phy_cfg = { + .param_size = MAX_USB_PHY_DATA_SIZE, + .param = { [1] = {0x01, 0xac89}, + [4] = {0x04, 0xf2f5}, + [6] = {0x06, 0x0017}, + [9] = {0x09, 0x424c}, + [10] = {0x0a, 0x9610}, + [11] = {0x0b, 0x9901}, + [12] = {0x0c, 0xf000}, + [13] = {0x0d, 0xef2a}, + [14] = {0x0e, 0x1000}, + [15] = {0x0f, 0x9050}, + [32] = {0x20, 0x7077}, + [35] = {0x23, 0x0b62}, + [37] = {0x25, 0x10ec}, + [42] = {0x2a, 0x3070}, }, + .check_efuse = true, + .do_toggle = false, + .do_toggle_once = true, + .use_default_parameter = false, + .check_rx_front_end_offset = true, +}; + +static const struct of_device_id usbphy_rtk_dt_match[] = { + { .compatible = "realtek,rtd1295-usb3phy", .data = &rtd1295_phy_cfg }, + { .compatible = "realtek,rtd1319-usb3phy", .data = &rtd1319_phy_cfg }, + { .compatible = "realtek,rtd1319d-usb3phy", .data = &rtd1319d_phy_cfg }, + { .compatible = "realtek,rtd1619-usb3phy", .data = &rtd1619_phy_cfg }, + { .compatible = "realtek,rtd1619b-usb3phy", .data = &rtd1619b_phy_cfg }, + {}, +}; +MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match); + +static struct platform_driver rtk_usb3phy_driver = { + .probe = rtk_usb3phy_probe, + .remove = rtk_usb3phy_remove, + .driver = { + .name = "rtk-usb3phy", + .of_match_table = usbphy_rtk_dt_match, + }, +}; + +module_platform_driver(rtk_usb3phy_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>"); +MODULE_DESCRIPTION("Realtek usb 3.0 phy driver"); diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c index 507435af2656..c0221e7258c0 100644 --- a/drivers/phy/renesas/phy-rcar-gen2.c +++ b/drivers/phy/renesas/phy-rcar-gen2.c @@ -306,7 +306,7 @@ static const struct of_device_id rcar_gen2_phy_match_table[] = { MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table); static struct phy *rcar_gen2_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct rcar_gen2_phy_driver *drv; struct device_node *np = args->np; diff --git a/drivers/phy/renesas/phy-rcar-gen3-pcie.c b/drivers/phy/renesas/phy-rcar-gen3-pcie.c index 0ce7e9c94444..feca4cb2ff4d 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-pcie.c +++ b/drivers/phy/renesas/phy-rcar-gen3-pcie.c @@ -132,11 +132,11 @@ static void rcar_gen3_phy_pcie_remove(struct platform_device *pdev) static struct platform_driver rcar_gen3_phy_driver = { .driver = { - .name = "phy_rcar_gen3_pcie", - .of_match_table = rcar_gen3_phy_pcie_match_table, + .name = "phy_rcar_gen3_pcie", + .of_match_table = rcar_gen3_phy_pcie_match_table, }, - .probe = rcar_gen3_phy_pcie_probe, - .remove_new = rcar_gen3_phy_pcie_remove, + .probe = rcar_gen3_phy_pcie_probe, + .remove = rcar_gen3_phy_pcie_remove, }; module_platform_driver(rcar_gen3_phy_driver); diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index e53eace7c91e..47beb94cd424 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> @@ -19,15 +20,19 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> #include <linux/string.h> #include <linux/usb/of.h> #include <linux/workqueue.h> /******* USB2.0 Host registers (original offset is +0x200) *******/ #define USB2_INT_ENABLE 0x000 +#define USB2_AHB_BUS_CTR 0x008 #define USB2_USBCTR 0x00c +#define USB2_REGEN_CG_CTRL 0x104 /* RZ/V2H(P) only */ #define USB2_SPD_RSM_TIMSET 0x10c #define USB2_OC_TIMSET 0x110 +#define USB2_UTMI_CTRL 0x118 /* RZ/V2H(P) only */ #define USB2_COMMCTRL 0x600 #define USB2_OBINTSTA 0x604 #define USB2_OBINTEN 0x608 @@ -40,16 +45,26 @@ #define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) /* For EHCI */ #define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) /* For OHCI */ +/* AHB_BUS_CTR */ +#define USB2_AHB_BUS_CTR_MBL_MASK GENMASK(1, 0) +#define USB2_AHB_BUS_CTR_MBL_INCR4 2 + /* USBCTR */ #define USB2_USBCTR_DIRPD BIT(2) #define USB2_USBCTR_PLL_RST BIT(1) +/* REGEN_CG_CTRL*/ +#define USB2_REGEN_CG_CTRL_UPHY_WEN BIT(0) + /* SPD_RSM_TIMSET */ #define USB2_SPD_RSM_TIMSET_INIT 0x014e029b /* OC_TIMSET */ #define USB2_OC_TIMSET_INIT 0x000209ab +/* UTMI_CTRL */ +#define USB2_UTMI_CTRL_INIT 0x8000018f + /* COMMCTRL */ #define USB2_COMMCTRL_OTG_PERI BIT(31) /* 1 = Peripheral mode */ @@ -101,7 +116,6 @@ struct rcar_gen3_phy { struct rcar_gen3_chan *ch; u32 int_enable_bits; bool initialized; - bool otg_initialized; bool powered; }; @@ -111,20 +125,23 @@ struct rcar_gen3_chan { struct extcon_dev *extcon; struct rcar_gen3_phy rphys[NUM_OF_PHYS]; 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; bool uses_otg_pins; bool soc_no_adp_ctrl; + bool utmi_ctrl; }; struct rcar_gen3_phy_drv_data { const struct phy_ops *phy_usb2_ops; bool no_adp_ctrl; + bool init_bus; + bool utmi_ctrl; }; /* @@ -188,6 +205,9 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); if (ch->soc_no_adp_ctrl) { + if (ch->vbus) + regulator_hardware_enable(ch->vbus, vbus); + vbus_ctrl_reg = USB2_VBCTRL; vbus_ctrl_val = USB2_VBCTRL_VBOUT; } @@ -309,16 +329,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) @@ -340,7 +359,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")) @@ -378,7 +399,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" : @@ -391,6 +412,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 | @@ -404,7 +428,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); @@ -416,16 +440,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 (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; + if (pm_runtime_suspended(dev)) + goto rpm_put; + + 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; } @@ -435,30 +470,29 @@ 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); + + if (channel->utmi_ctrl) { + val = readl(usb2_base + USB2_REGEN_CG_CTRL) | USB2_REGEN_CG_CTRL_UPHY_WEN; + writel(val, usb2_base + USB2_REGEN_CG_CTRL); + + writel(USB2_UTMI_CTRL_INIT, usb2_base + USB2_UTMI_CTRL); + writel(val & ~USB2_REGEN_CG_CTRL_UPHY_WEN, usb2_base + USB2_REGEN_CG_CTRL); } rphy->initialized = true; @@ -473,10 +507,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; @@ -484,9 +517,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; } @@ -498,16 +528,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); @@ -517,7 +548,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; } @@ -528,18 +558,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; } @@ -572,6 +604,18 @@ static const struct rcar_gen3_phy_drv_data rz_g2l_phy_usb2_data = { .no_adp_ctrl = true, }; +static const struct rcar_gen3_phy_drv_data rz_g3s_phy_usb2_data = { + .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, + .no_adp_ctrl = true, + .init_bus = true, +}; + +static const struct rcar_gen3_phy_drv_data rz_v2h_phy_usb2_data = { + .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, + .no_adp_ctrl = true, + .utmi_ctrl = true, +}; + static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { { .compatible = "renesas,usb2-phy-r8a77470", @@ -590,6 +634,14 @@ static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { .data = &rcar_gen3_phy_usb2_data, }, { + .compatible = "renesas,usb2-phy-r9a08g045", + .data = &rz_g3s_phy_usb2_data, + }, + { + .compatible = "renesas,usb2-phy-r9a09g057", + .data = &rz_v2h_phy_usb2_data, + }, + { .compatible = "renesas,rzg2l-usb2-phy", .data = &rz_g2l_phy_usb2_data, }, @@ -608,7 +660,7 @@ static const unsigned int rcar_gen3_phy_cable[] = { }; static struct phy *rcar_gen3_phy_usb2_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct rcar_gen3_chan *ch = dev_get_drvdata(dev); @@ -647,13 +699,42 @@ static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np) return candidate; } +static int rcar_gen3_phy_usb2_init_bus(struct rcar_gen3_chan *channel) +{ + struct device *dev = channel->dev; + int ret; + u32 val; + + channel->rstc = devm_reset_control_array_get_shared(dev); + if (IS_ERR(channel->rstc)) + return PTR_ERR(channel->rstc); + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + ret = reset_control_deassert(channel->rstc); + if (ret) + goto rpm_put; + + val = readl(channel->base + USB2_AHB_BUS_CTR); + val &= ~USB2_AHB_BUS_CTR_MBL_MASK; + val |= USB2_AHB_BUS_CTR_MBL_INCR4; + writel(val, channel->base + USB2_AHB_BUS_CTR); + +rpm_put: + pm_runtime_put(dev); + + return ret; +} + static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { const struct rcar_gen3_phy_drv_data *phy_data; 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"); @@ -669,12 +750,8 @@ 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) { - int ret; - channel->is_otg_channel = true; channel->uses_otg_pins = !of_property_read_bool(dev->of_node, "renesas,no-otg-pins"); @@ -702,11 +779,22 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) goto error; } + platform_set_drvdata(pdev, channel); + channel->dev = dev; + + if (phy_data->init_bus) { + ret = rcar_gen3_phy_usb2_init_bus(channel); + if (ret) + goto error; + } + channel->soc_no_adp_ctrl = phy_data->no_adp_ctrl; if (phy_data->no_adp_ctrl) channel->obint_enable_bits = USB2_OBINT_IDCHG_EN; - mutex_init(&channel->lock); + channel->utmi_ctrl = phy_data->utmi_ctrl; + + 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); @@ -720,7 +808,10 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) phy_set_drvdata(channel->rphys[i].phy, &channel->rphys[i]); } - channel->vbus = devm_regulator_get_optional(dev, "vbus"); + if (channel->soc_no_adp_ctrl && channel->is_otg_channel) + channel->vbus = devm_regulator_get_exclusive(dev, "vbus"); + else + channel->vbus = devm_regulator_get_optional(dev, "vbus"); if (IS_ERR(channel->vbus)) { if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) { ret = PTR_ERR(channel->vbus); @@ -729,8 +820,19 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) channel->vbus = NULL; } - platform_set_drvdata(pdev, channel); - channel->dev = dev; + 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)) { @@ -738,8 +840,6 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) ret = PTR_ERR(provider); goto error; } else if (channel->is_otg_channel) { - int ret; - ret = device_create_file(dev, &dev_attr_role); if (ret < 0) goto error; @@ -760,6 +860,7 @@ static void rcar_gen3_phy_usb2_remove(struct platform_device *pdev) if (channel->is_otg_channel) device_remove_file(&pdev->dev, &dev_attr_role); + reset_control_assert(channel->rstc); pm_runtime_disable(&pdev->dev); }; @@ -769,7 +870,7 @@ static struct platform_driver rcar_gen3_phy_usb2_driver = { .of_match_table = rcar_gen3_phy_usb2_match_table, }, .probe = rcar_gen3_phy_usb2_probe, - .remove_new = rcar_gen3_phy_usb2_remove, + .remove = rcar_gen3_phy_usb2_remove, }; module_platform_driver(rcar_gen3_phy_usb2_driver); diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb3.c b/drivers/phy/renesas/phy-rcar-gen3-usb3.c index e2d630edd992..5c267d148c90 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb3.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c @@ -206,11 +206,11 @@ static void rcar_gen3_phy_usb3_remove(struct platform_device *pdev) static struct platform_driver rcar_gen3_phy_usb3_driver = { .driver = { - .name = "phy_rcar_gen3_usb3", - .of_match_table = rcar_gen3_phy_usb3_match_table, + .name = "phy_rcar_gen3_usb3", + .of_match_table = rcar_gen3_phy_usb3_match_table, }, - .probe = rcar_gen3_phy_usb3_probe, - .remove_new = rcar_gen3_phy_usb3_remove, + .probe = rcar_gen3_phy_usb3_probe, + .remove = rcar_gen3_phy_usb3_remove, }; module_platform_driver(rcar_gen3_phy_usb3_driver); diff --git a/drivers/phy/renesas/r8a779f0-ether-serdes.c b/drivers/phy/renesas/r8a779f0-ether-serdes.c index fc6e398fa3bf..3b2d8cef75e5 100644 --- a/drivers/phy/renesas/r8a779f0-ether-serdes.c +++ b/drivers/phy/renesas/r8a779f0-ether-serdes.c @@ -334,7 +334,7 @@ static const struct phy_ops r8a779f0_eth_serdes_ops = { }; static struct phy *r8a779f0_eth_serdes_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct r8a779f0_eth_serdes_drv_data *dd = dev_get_drvdata(dev); @@ -404,7 +404,7 @@ static void r8a779f0_eth_serdes_remove(struct platform_device *pdev) static struct platform_driver r8a779f0_eth_serdes_driver_platform = { .probe = r8a779f0_eth_serdes_probe, - .remove_new = r8a779f0_eth_serdes_remove, + .remove = r8a779f0_eth_serdes_remove, .driver = { .name = "r8a779f0_eth_serdes", .of_match_table = r8a779f0_eth_serdes_of_table, diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index 94360fc96a6f..14698571b607 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -83,6 +83,30 @@ 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 + depends on COMMON_CLK + depends on HAS_IOMEM + select GENERIC_PHY + select MFD_SYSCON + select RATIONAL + help + Enable this to support the Rockchip HDMI/eDP Combo PHY + with Samsung IP block. + config PHY_ROCKCHIP_SNPS_PCIE3 tristate "Rockchip Snps PCIe3 PHY Driver" depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST @@ -107,3 +131,16 @@ config PHY_ROCKCHIP_USB select GENERIC_PHY help Enable this to support the Rockchip USB 2.0 PHY. + +config PHY_ROCKCHIP_USBDP + tristate "Rockchip USBDP COMBO PHY Driver" + depends on ARCH_ROCKCHIP && OF + depends on TYPEC + select GENERIC_PHY + select USB_COMMON + help + Enable this to support the Rockchip USB3.0/DP combo PHY with + Samsung IP block. This is required for USB3 support on RK3588. + + To compile this driver as a module, choose M here: the module + will be called phy-rockchip-usbdp diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile index 7eab129230d1..117aaffd037d 100644 --- a/drivers/phy/rockchip/Makefile +++ b/drivers/phy/rockchip/Makefile @@ -8,6 +8,9 @@ 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 obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o +obj-$(CONFIG_PHY_ROCKCHIP_USBDP) += phy-rockchip-usbdp.o diff --git a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c index 98c92d6c482f..2ab99e1d47eb 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-csidphy.c @@ -472,7 +472,7 @@ static struct platform_driver rockchip_inno_csidphy_driver = { .of_match_table = rockchip_inno_csidphy_match_id, }, .probe = rockchip_inno_csidphy_probe, - .remove_new = rockchip_inno_csidphy_remove, + .remove = rockchip_inno_csidphy_remove, }; module_platform_driver(rockchip_inno_csidphy_driver); diff --git a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c index 6405943a2676..d5b1a4e2f7d3 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-dsidphy.c @@ -784,7 +784,7 @@ static struct platform_driver inno_dsidphy_driver = { .of_match_table = of_match_ptr(inno_dsidphy_of_match), }, .probe = inno_dsidphy_probe, - .remove_new = inno_dsidphy_remove, + .remove = inno_dsidphy_remove, }; module_platform_driver(inno_dsidphy_driver); diff --git a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c index 053bd62e31ba..8dcc2bb777b5 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-hdmi.c @@ -1424,8 +1424,8 @@ static const struct of_device_id inno_hdmi_phy_of_match[] = { MODULE_DEVICE_TABLE(of, inno_hdmi_phy_of_match); static struct platform_driver inno_hdmi_phy_driver = { - .probe = inno_hdmi_phy_probe, - .remove_new = inno_hdmi_phy_remove, + .probe = inno_hdmi_phy_probe, + .remove = inno_hdmi_phy_remove, .driver = { .name = "inno-hdmi-phy", .of_match_table = inno_hdmi_phy_of_match, diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 4f71373ae6e1..b0f23690ec30 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -229,9 +229,10 @@ struct rockchip_usb2phy_port { * @dev: pointer to device. * @grf: General Register Files regmap. * @usbgrf: USB General Register Files regmap. - * @clk: clock struct of phy input clk. + * @clks: array of phy input clocks. * @clk480m: clock struct of phy output clk. * @clk480m_hw: clock struct of phy output clk management. + * @num_clks: number of phy input clocks. * @phy_reset: phy reset control. * @chg_state: states involved in USB charger detection. * @chg_type: USB charger types. @@ -246,9 +247,10 @@ struct rockchip_usb2phy { struct device *dev; struct regmap *grf; struct regmap *usbgrf; - struct clk *clk; + struct clk_bulk_data *clks; struct clk *clk480m; struct clk_hw clk480m_hw; + int num_clks; struct reset_control *phy_reset; enum usb_chg_state chg_state; enum power_supply_type chg_type; @@ -310,6 +312,13 @@ static int rockchip_usb2phy_reset(struct rockchip_usb2phy *rphy) return 0; } +static void rockchip_usb2phy_clk_bulk_disable(void *data) +{ + struct rockchip_usb2phy *rphy = data; + + clk_bulk_disable_unprepare(rphy->num_clks, rphy->clks); +} + static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw) { struct rockchip_usb2phy *rphy = @@ -376,7 +385,9 @@ rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) { struct device_node *node = rphy->dev->of_node; struct clk_init_data init; + struct clk *refclk = NULL; const char *clk_name; + int i; int ret = 0; init.flags = 0; @@ -386,8 +397,15 @@ rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) /* optional override of the clockname */ of_property_read_string(node, "clock-output-names", &init.name); - if (rphy->clk) { - clk_name = __clk_get_name(rphy->clk); + for (i = 0; i < rphy->num_clks; i++) { + if (!strncmp(rphy->clks[i].id, "phyclk", 6)) { + refclk = rphy->clks[i].clk; + break; + } + } + + if (!IS_ERR(refclk)) { + clk_name = __clk_get_name(refclk); init.parent_names = &clk_name; init.num_parents = 1; } else { @@ -418,30 +436,28 @@ err_ret: static int rockchip_usb2phy_extcon_register(struct rockchip_usb2phy *rphy) { - int ret; struct device_node *node = rphy->dev->of_node; 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)) { - if (PTR_ERR(edev) != -EPROBE_DEFER) - dev_err(rphy->dev, "Invalid or missing extcon\n"); - return PTR_ERR(edev); - } + if (IS_ERR(edev)) + return dev_err_probe(rphy->dev, PTR_ERR(edev), + "invalid or missing extcon\n"); } else { /* Initialize extcon device */ edev = devm_extcon_dev_allocate(rphy->dev, rockchip_usb2phy_extcon_cable); if (IS_ERR(edev)) - return -ENOMEM; + return dev_err_probe(rphy->dev, PTR_ERR(edev), + "failed to allocate extcon device\n"); ret = devm_extcon_dev_register(rphy->dev, edev); - if (ret) { - dev_err(rphy->dev, "failed to register extcon device\n"); - return ret; - } + if (ret) + return dev_err_probe(rphy->dev, ret, + "failed to register extcon device\n"); } rphy->edev = edev; @@ -1307,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); @@ -1327,7 +1343,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) struct rockchip_usb2phy *rphy; const struct rockchip_usb2phy_cfg *phy_cfgs; unsigned int reg; - int index, ret; + int index = 0, ret; rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL); if (!rphy) @@ -1339,9 +1355,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) dev_err(dev, "failed to locate usbgrf\n"); return PTR_ERR(rphy->grf); } - } - - else { + } else { rphy->grf = syscon_node_to_regmap(dev->parent->of_node); if (IS_ERR(rphy->grf)) return PTR_ERR(rphy->grf); @@ -1358,16 +1372,14 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) } if (of_property_read_u32_index(np, "reg", 0, ®)) { - dev_err(dev, "the reg property is not assigned in %pOFn node\n", - np); + dev_err(dev, "the reg property is not assigned in %pOFn node\n", np); return -EINVAL; } /* support address_cells=2 */ if (of_property_count_u32_elems(np, "reg") > 2 && reg == 0) { if (of_property_read_u32_index(np, "reg", 1, ®)) { - dev_err(dev, "the reg property is not assigned in %pOFn node\n", - np); + dev_err(dev, "the reg property is not assigned in %pOFn node\n", np); return -EINVAL; } } @@ -1386,8 +1398,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) if (ret) return ret; - /* find out a proper config which can be matched with dt. */ - index = 0; + /* find a proper config that can be matched with the DT */ do { if (phy_cfgs[index].reg == reg) { rphy->phy_cfg = &phy_cfgs[index]; @@ -1406,17 +1417,25 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) if (IS_ERR(rphy->phy_reset)) return PTR_ERR(rphy->phy_reset); - rphy->clk = devm_clk_get_optional_enabled(dev, "phyclk"); - if (IS_ERR(rphy->clk)) { - return dev_err_probe(&pdev->dev, PTR_ERR(rphy->clk), - "failed to get phyclk\n"); - } + ret = devm_clk_bulk_get_all(dev, &rphy->clks); + if (ret == -EPROBE_DEFER) + return dev_err_probe(&pdev->dev, -EPROBE_DEFER, + "failed to get phy clock\n"); + + /* Clocks are optional */ + rphy->num_clks = ret < 0 ? 0 : ret; ret = rockchip_usb2phy_clk480m_register(rphy); - if (ret) { - dev_err(dev, "failed to register 480m output clock\n"); + if (ret) + return dev_err_probe(dev, ret, "failed to register 480m output clock\n"); + + ret = clk_bulk_prepare_enable(rphy->num_clks, rphy->clks); + if (ret) + return dev_err_probe(dev, ret, "failed to enable phy clock\n"); + + ret = devm_add_action_or_reset(dev, rockchip_usb2phy_clk_bulk_disable, rphy); + if (ret) return ret; - } if (rphy->phy_cfg->phy_tuning) { ret = rphy->phy_cfg->phy_tuning(rphy); @@ -1436,8 +1455,7 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops); if (IS_ERR(phy)) { - dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n"); - ret = PTR_ERR(phy); + ret = dev_err_probe(dev, PTR_ERR(phy), "failed to create phy\n"); goto put_child; } @@ -1446,13 +1464,11 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) /* initialize otg/host port separately */ if (of_node_name_eq(child_np, "host-port")) { - ret = rockchip_usb2phy_host_port_init(rphy, rport, - child_np); + ret = rockchip_usb2phy_host_port_init(rphy, rport, child_np); if (ret) goto put_child; } else { - ret = rockchip_usb2phy_otg_port_init(rphy, rport, - child_np); + ret = rockchip_usb2phy_otg_port_init(rphy, rport, child_np); if (ret) goto put_child; } @@ -1474,8 +1490,7 @@ next_child: "rockchip_usb2phy", rphy); if (ret) { - dev_err(rphy->dev, - "failed to request usb2phy irq handle\n"); + dev_err_probe(rphy->dev, ret, "failed to request usb2phy irq handle\n"); goto put_child; } } @@ -1495,6 +1510,30 @@ static int rk3128_usb2phy_tuning(struct rockchip_usb2phy *rphy) BIT(2) << BIT_WRITEABLE_SHIFT | 0); } +static int rk3576_usb2phy_tuning(struct rockchip_usb2phy *rphy) +{ + int ret; + u32 reg = rphy->phy_cfg->reg; + + /* Deassert SIDDQ to power on analog block */ + ret = regmap_write(rphy->grf, reg + 0x0010, GENMASK(29, 29) | 0x0000); + if (ret) + return ret; + + /* Do reset after exit IDDQ mode */ + ret = rockchip_usb2phy_reset(rphy); + if (ret) + return ret; + + /* HS DC Voltage Level Adjustment 4'b1001 : +5.89% */ + ret |= regmap_write(rphy->grf, reg + 0x000c, GENMASK(27, 24) | 0x0900); + + /* HS Transmitter Pre-Emphasis Current Control 2'b10 : 2x */ + ret |= regmap_write(rphy->grf, reg + 0x0010, GENMASK(20, 19) | 0x0010); + + return ret; +} + static int rk3588_usb2phy_tuning(struct rockchip_usb2phy *rphy) { int ret; @@ -1544,6 +1583,37 @@ static int rk3588_usb2phy_tuning(struct rockchip_usb2phy *rphy) return ret; } +static const struct rockchip_usb2phy_cfg rk3036_phy_cfgs[] = { + { + .reg = 0x17c, + .num_ports = 2, + .phy_tuning = rk3128_usb2phy_tuning, + .clkout_ctl = { 0x017c, 11, 11, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x017c, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x017c, 14, 14, 0, 1 }, + .bvalid_det_st = { 0x017c, 15, 15, 0, 1 }, + .bvalid_det_clr = { 0x017c, 15, 15, 0, 1 }, + .ls_det_en = { 0x017c, 12, 12, 0, 1 }, + .ls_det_st = { 0x017c, 13, 13, 0, 1 }, + .ls_det_clr = { 0x017c, 13, 13, 0, 1 }, + .utmi_bvalid = { 0x014c, 8, 8, 0, 1 }, + .utmi_id = { 0x014c, 11, 11, 0, 1 }, + .utmi_ls = { 0x014c, 10, 9, 0, 1 }, + + }, + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x0194, 8, 0, 0, 0x1d1 }, + .ls_det_en = { 0x0194, 14, 14, 0, 1 }, + .ls_det_st = { 0x0194, 15, 15, 0, 1 }, + .ls_det_clr = { 0x0194, 15, 15, 0, 1 } + } + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rk3128_phy_cfgs[] = { { .reg = 0x17c, @@ -1853,6 +1923,54 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { { /* sentinel */ } }; +static const struct rockchip_usb2phy_cfg rk3562_phy_cfgs[] = { + { + .reg = 0xff740000, + .num_ports = 2, + .clkout_ctl = { 0x0108, 4, 4, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x0100, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x0110, 2, 2, 0, 1 }, + .bvalid_det_st = { 0x0114, 2, 2, 0, 1 }, + .bvalid_det_clr = { 0x0118, 2, 2, 0, 1 }, + .idfall_det_en = { 0x0110, 5, 5, 0, 1 }, + .idfall_det_st = { 0x0114, 5, 5, 0, 1 }, + .idfall_det_clr = { 0x0118, 5, 5, 0, 1 }, + .idrise_det_en = { 0x0110, 4, 4, 0, 1 }, + .idrise_det_st = { 0x0114, 4, 4, 0, 1 }, + .idrise_det_clr = { 0x0118, 4, 4, 0, 1 }, + .ls_det_en = { 0x0110, 0, 0, 0, 1 }, + .ls_det_st = { 0x0114, 0, 0, 0, 1 }, + .ls_det_clr = { 0x0118, 0, 0, 0, 1 }, + .utmi_avalid = { 0x0120, 10, 10, 0, 1 }, + .utmi_bvalid = { 0x0120, 9, 9, 0, 1 }, + .utmi_ls = { 0x0120, 5, 4, 0, 1 }, + }, + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x0104, 8, 0, 0x1d2, 0x1d1 }, + .ls_det_en = { 0x0110, 1, 1, 0, 1 }, + .ls_det_st = { 0x0114, 1, 1, 0, 1 }, + .ls_det_clr = { 0x0118, 1, 1, 0, 1 }, + .utmi_ls = { 0x0120, 17, 16, 0, 1 }, + .utmi_hstdet = { 0x0120, 19, 19, 0, 1 } + } + }, + .chg_det = { + .cp_det = { 0x0120, 24, 24, 0, 1 }, + .dcp_det = { 0x0120, 23, 23, 0, 1 }, + .dp_det = { 0x0120, 25, 25, 0, 1 }, + .idm_sink_en = { 0x0108, 8, 8, 0, 1 }, + .idp_sink_en = { 0x0108, 7, 7, 0, 1 }, + .idp_src_en = { 0x0108, 9, 9, 0, 1 }, + .rdm_pdwn_en = { 0x0108, 10, 10, 0, 1 }, + .vdm_src_en = { 0x0108, 12, 12, 0, 1 }, + .vdp_src_en = { 0x0108, 11, 11, 0, 1 }, + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { { .reg = 0xfe8a0000, @@ -1923,6 +2041,84 @@ static const struct rockchip_usb2phy_cfg rk3568_phy_cfgs[] = { { /* sentinel */ } }; +static const struct rockchip_usb2phy_cfg rk3576_phy_cfgs[] = { + { + .reg = 0x0, + .num_ports = 1, + .phy_tuning = rk3576_usb2phy_tuning, + .clkout_ctl = { 0x0008, 0, 0, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x0000, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x00c0, 1, 1, 0, 1 }, + .bvalid_det_st = { 0x00c4, 1, 1, 0, 1 }, + .bvalid_det_clr = { 0x00c8, 1, 1, 0, 1 }, + .ls_det_en = { 0x00c0, 0, 0, 0, 1 }, + .ls_det_st = { 0x00c4, 0, 0, 0, 1 }, + .ls_det_clr = { 0x00c8, 0, 0, 0, 1 }, + .disfall_en = { 0x00c0, 6, 6, 0, 1 }, + .disfall_st = { 0x00c4, 6, 6, 0, 1 }, + .disfall_clr = { 0x00c8, 6, 6, 0, 1 }, + .disrise_en = { 0x00c0, 5, 5, 0, 1 }, + .disrise_st = { 0x00c4, 5, 5, 0, 1 }, + .disrise_clr = { 0x00c8, 5, 5, 0, 1 }, + .utmi_avalid = { 0x0080, 1, 1, 0, 1 }, + .utmi_bvalid = { 0x0080, 0, 0, 0, 1 }, + .utmi_ls = { 0x0080, 5, 4, 0, 1 }, + } + }, + .chg_det = { + .cp_det = { 0x0080, 8, 8, 0, 1 }, + .dcp_det = { 0x0080, 8, 8, 0, 1 }, + .dp_det = { 0x0080, 9, 9, 1, 0 }, + .idm_sink_en = { 0x0010, 5, 5, 1, 0 }, + .idp_sink_en = { 0x0010, 5, 5, 0, 1 }, + .idp_src_en = { 0x0010, 14, 14, 0, 1 }, + .rdm_pdwn_en = { 0x0010, 14, 14, 0, 1 }, + .vdm_src_en = { 0x0010, 7, 6, 0, 3 }, + .vdp_src_en = { 0x0010, 7, 6, 0, 3 }, + }, + }, + { + .reg = 0x2000, + .num_ports = 1, + .phy_tuning = rk3576_usb2phy_tuning, + .clkout_ctl = { 0x2008, 0, 0, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x2000, 8, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x20c0, 1, 1, 0, 1 }, + .bvalid_det_st = { 0x20c4, 1, 1, 0, 1 }, + .bvalid_det_clr = { 0x20c8, 1, 1, 0, 1 }, + .ls_det_en = { 0x20c0, 0, 0, 0, 1 }, + .ls_det_st = { 0x20c4, 0, 0, 0, 1 }, + .ls_det_clr = { 0x20c8, 0, 0, 0, 1 }, + .disfall_en = { 0x20c0, 6, 6, 0, 1 }, + .disfall_st = { 0x20c4, 6, 6, 0, 1 }, + .disfall_clr = { 0x20c8, 6, 6, 0, 1 }, + .disrise_en = { 0x20c0, 5, 5, 0, 1 }, + .disrise_st = { 0x20c4, 5, 5, 0, 1 }, + .disrise_clr = { 0x20c8, 5, 5, 0, 1 }, + .utmi_avalid = { 0x2080, 1, 1, 0, 1 }, + .utmi_bvalid = { 0x2080, 0, 0, 0, 1 }, + .utmi_ls = { 0x2080, 5, 4, 0, 1 }, + } + }, + .chg_det = { + .cp_det = { 0x2080, 8, 8, 0, 1 }, + .dcp_det = { 0x2080, 8, 8, 0, 1 }, + .dp_det = { 0x2080, 9, 9, 1, 0 }, + .idm_sink_en = { 0x2010, 5, 5, 1, 0 }, + .idp_sink_en = { 0x2010, 5, 5, 0, 1 }, + .idp_src_en = { 0x2010, 14, 14, 0, 1 }, + .rdm_pdwn_en = { 0x2010, 14, 14, 0, 1 }, + .vdm_src_en = { 0x2010, 7, 6, 0, 3 }, + .vdp_src_en = { 0x2010, 7, 6, 0, 3 }, + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rk3588_phy_cfgs[] = { { .reg = 0x0000, @@ -2087,13 +2283,16 @@ static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = { static const struct of_device_id rockchip_usb2phy_dt_match[] = { { .compatible = "rockchip,px30-usb2phy", .data = &rk3328_phy_cfgs }, + { .compatible = "rockchip,rk3036-usb2phy", .data = &rk3036_phy_cfgs }, { .compatible = "rockchip,rk3128-usb2phy", .data = &rk3128_phy_cfgs }, { .compatible = "rockchip,rk3228-usb2phy", .data = &rk3228_phy_cfgs }, { .compatible = "rockchip,rk3308-usb2phy", .data = &rk3308_phy_cfgs }, { .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs }, { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, + { .compatible = "rockchip,rk3562-usb2phy", .data = &rk3562_phy_cfgs }, { .compatible = "rockchip,rk3568-usb2phy", .data = &rk3568_phy_cfgs }, + { .compatible = "rockchip,rk3576-usb2phy", .data = &rk3576_phy_cfgs }, { .compatible = "rockchip,rk3588-usb2phy", .data = &rk3588_phy_cfgs }, { .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs }, {} diff --git a/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c b/drivers/phy/rockchip/phy-rockchip-naneng-combphy.c index 5de5e2e97ffa..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; @@ -125,12 +140,15 @@ struct rockchip_combphy_grfcfg { }; struct rockchip_combphy_cfg { + unsigned int num_phys; + unsigned int phy_ids[3]; const struct rockchip_combphy_grfcfg *grfcfg; int (*combphy_cfg)(struct rockchip_combphy_priv *priv); }; struct rockchip_combphy_priv { u8 type; + int id; void __iomem *mmio; int num_clks; struct clk_bulk_data *clks; @@ -245,13 +263,13 @@ static int rockchip_combphy_exit(struct phy *phy) return 0; } -static const struct phy_ops rochchip_combphy_ops = { +static const struct phy_ops rockchip_combphy_ops = { .init = rockchip_combphy_init, .exit = rockchip_combphy_exit, .owner = THIS_MODULE, }; -static struct phy *rockchip_combphy_xlate(struct device *dev, struct of_phandle_args *args) +static struct phy *rockchip_combphy_xlate(struct device *dev, const struct of_phandle_args *args) { struct rockchip_combphy_priv *priv = dev_get_drvdata(dev); @@ -306,7 +324,10 @@ static int rockchip_combphy_parse_dt(struct device *dev, struct rockchip_combphy priv->ext_refclk = device_property_present(dev, "rockchip,ext-refclk"); - priv->phy_rst = devm_reset_control_array_get_exclusive(dev); + priv->phy_rst = devm_reset_control_get_exclusive(dev, "phy"); + /* fallback to old behaviour */ + if (PTR_ERR(priv->phy_rst) == -ENOENT) + priv->phy_rst = devm_reset_control_array_get_exclusive(dev); if (IS_ERR(priv->phy_rst)) return dev_err_probe(dev, PTR_ERR(priv->phy_rst), "failed to get phy reset\n"); @@ -320,7 +341,7 @@ static int rockchip_combphy_probe(struct platform_device *pdev) struct rockchip_combphy_priv *priv; const struct rockchip_combphy_cfg *phy_cfg; struct resource *res; - int ret; + int ret, id; phy_cfg = of_device_get_match_data(dev); if (!phy_cfg) { @@ -338,6 +359,15 @@ static int rockchip_combphy_probe(struct platform_device *pdev) return ret; } + /* find the phy-id from the io address */ + priv->id = -ENODEV; + for (id = 0; id < phy_cfg->num_phys; id++) { + if (res->start == phy_cfg->phy_ids[id]) { + priv->id = id; + break; + } + } + priv->dev = dev; priv->type = PHY_NONE; priv->cfg = phy_cfg; @@ -352,7 +382,7 @@ static int rockchip_combphy_probe(struct platform_device *pdev) return ret; } - priv->phy = devm_phy_create(dev, NULL, &rochchip_combphy_ops); + priv->phy = devm_phy_create(dev, NULL, &rockchip_combphy_ops); if (IS_ERR(priv->phy)) { dev_err(dev, "failed to create combphy\n"); return PTR_ERR(priv->phy); @@ -366,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; @@ -562,10 +740,276 @@ static const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = { }; static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = { + .num_phys = 3, + .phy_ids = { + 0xfe820000, + 0xfe830000, + 0xfe840000, + }, .grfcfg = &rk3568_combphy_grfcfgs, .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; @@ -578,8 +1022,14 @@ static int rk3588_combphy_cfg(struct rockchip_combphy_priv *priv) 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); - rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_pcie1l0_sel, true); - rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_pcie1l1_sel, true); + switch (priv->id) { + case 1: + rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_pcie1l0_sel, true); + break; + case 2: + rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_pcie1l1_sel, true); + break; + } break; case PHY_TYPE_USB3: /* Set SSC downward spread spectrum */ @@ -736,16 +1186,30 @@ static const struct rockchip_combphy_grfcfg rk3588_combphy_grfcfgs = { }; static const struct rockchip_combphy_cfg rk3588_combphy_cfgs = { + .num_phys = 3, + .phy_ids = { + 0xfee00000, + 0xfee10000, + 0xfee20000, + }, .grfcfg = &rk3588_combphy_grfcfgs, .combphy_cfg = rk3588_combphy_cfg, }; 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 1bbd6be2a584..bd44af36c67a 100644 --- a/drivers/phy/rockchip/phy-rockchip-pcie.c +++ b/drivers/phy/rockchip/phy-rockchip-pcie.c @@ -82,7 +82,7 @@ static struct rockchip_pcie_phy *to_pcie_phy(struct phy_pcie_instance *inst) } static struct phy *rockchip_pcie_phy_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct rockchip_pcie_phy *rk_phy = dev_get_drvdata(dev); @@ -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 new file mode 100644 index 000000000000..79db57ee90d1 --- /dev/null +++ b/drivers/phy/rockchip/phy-rockchip-samsung-hdptx.c @@ -0,0 +1,2122 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021-2022 Rockchip Electronics Co., Ltd. + * Copyright (c) 2024 Collabora Ltd. + * + * Author: Algea Cao <algea.cao@rock-chips.com> + * Author: Cristian Ciocaltea <cristian.ciocaltea@collabora.com> + */ +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/rational.h> +#include <linux/regmap.h> +#include <linux/reset.h> + +#define GRF_HDPTX_CON0 0x00 +#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) +#define HDPTX_O_PHY_RDY BIT(1) +#define HDPTX_O_SB_RDY BIT(0) + +#define HDTPX_REG(_n, _min, _max) \ + ( \ + BUILD_BUG_ON_ZERO((0x##_n) < (0x##_min)) + \ + BUILD_BUG_ON_ZERO((0x##_n) > (0x##_max)) + \ + ((0x##_n) * 4) \ + ) + +#define CMN_REG(n) HDTPX_REG(n, 0000, 00a7) +#define SB_REG(n) HDTPX_REG(n, 0100, 0129) +#define LNTOP_REG(n) HDTPX_REG(n, 0200, 0229) +#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_MASK BIT(4) +/* CMN_REG(0028) */ +#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_MASK BIT(0) +/* CMN_REG(003c) */ +#define ANA_LCPLL_RESERVED7_MASK BIT(7) +/* CMN_REG(003d) */ +#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_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_MASK BIT(5) +/* CMN_REG(005e) */ +#define ROPLL_SDM_EN_MASK BIT(6) +#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 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_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_MASK BIT(0) +/* CMN_REG(0087) */ +#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_MASK BIT(1) +/* CMN_REG(0095) */ +#define DP_TX_LINK_BW_MASK GENMASK(1, 0) +/* CMN_REG(0097) */ +#define DIG_CLK_SEL_MASK BIT(1) +#define LCPLL_REF BIT(1) +#define ROPLL_REF 0 +/* CMN_REG(0099) */ +#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_MASK BIT(0) +#define DIV_10_CLOCK BIT(0) +/* CMN_REG(009b) */ +#define LS_SPEED_SEL_MASK BIT(4) +#define LINK_SYMBOL_CLOCK BIT(4) +#define LINK_SYMBOL_CLOCK1_2 0 + +/* SB_REG(0102) */ +#define OVRD_SB_RXTERM_EN_MASK BIT(5) +#define SB_RXTERM_EN_MASK BIT(4) +#define ANA_SB_RXTERM_OFFSP_MASK GENMASK(3, 0) +/* SB_REG(0103) */ +#define ANA_SB_RXTERM_OFFSN_MASK GENMASK(6, 3) +#define OVRD_SB_RX_RESCAL_DONE_MASK BIT(1) +#define SB_RX_RESCAL_DONE_MASK BIT(0) +/* 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) +#define ANA_SB_TX_HLVL_PROG_MASK GENMASK(2, 0) +/* SB_REG(0106) */ +#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) +#define OVRD_SB_VREG_LPF_BYPASS_MASK BIT(5) +#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) +#define SB_RX_RTERM_CTRL_MASK GENMASK(3, 0) +/* SB_REG(0114) */ +#define SB_TG_SB_EN_DELAY_TIME_MASK GENMASK(5, 3) +#define SB_TG_RXTERM_EN_DELAY_TIME_MASK GENMASK(2, 0) +/* SB_REG(0115) */ +#define SB_READY_DELAY_TIME_MASK GENMASK(5, 3) +#define SB_TG_OSC_EN_DELAY_TIME_MASK GENMASK(2, 0) +/* SB_REG(0116) */ +#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) */ +#define OVRD_SB_READY_MASK BIT(5) +#define SB_READY_MASK BIT(4) + +/* LNTOP_REG(0200) */ +#define PROTOCOL_SEL_MASK BIT(2) +#define HDMI_MODE BIT(2) +#define HDMI_TMDS_FRL_SEL BIT(1) +/* LNTOP_REG(0206) */ +#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_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_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_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_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_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 ropll_config { + unsigned long long rate; + u8 pms_mdiv; + u8 pms_mdiv_afc; + u8 pms_pdiv; + u8 pms_refdiv; + u8 pms_sdiv; + u8 pms_iqdiv_rstn; + u8 ref_clk_sel; + u8 sdm_en; + u8 sdm_rstn; + u8 sdc_frac_en; + u8 sdc_rstn; + u8 sdm_clk_div; + u8 sdm_deno; + u8 sdm_num_sign; + u8 sdm_num; + u8 sdc_n; + u8 sdc_num; + u8 sdc_deno; + u8 sdc_ndiv_rstn; + u8 ssc_en; + u8 ssc_fm_dev; + u8 ssc_fm_freq; + u8 ssc_clk_div_sel; + u8 ana_cpp_ctrl; + u8 ana_lpf_c_sel; + 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, + RST_CMN, + RST_LANE, + 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; + + int phy_id; + struct phy *phy; + struct phy_configure_opts_hdmi hdmi_cfg; + struct clk_bulk_data *clks; + int nr_clks; + struct reset_control_bulk_data rsts[RST_MAX]; + + /* clk provider */ + struct clk_hw hw; + unsigned long hw_rate; + bool restrict_rate_change; + + atomic_t usage_count; + + /* used for dp mode */ + unsigned int link_rate; + unsigned int lanes; +}; + +static const struct ropll_config ropll_tmds_cfg[] = { + { 594000000ULL, 124, 124, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 371250000ULL, 155, 155, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 297000000ULL, 124, 124, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 162000000ULL, 135, 135, 1, 1, 3, 1, 1, 0, 1, 1, 1, 1, 4, 0, 3, 5, 5, 0x10, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 185625000ULL, 155, 155, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 154000000ULL, 193, 193, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 193, 1, 32, 2, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 148500000ULL, 0x7b, 0x7b, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 4, 0, 3, 5, 5, + 0x10, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 146250000ULL, 122, 122, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 244, 1, 16, 2, 1, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 119000000ULL, 149, 149, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 149, 1, 16, 2, 1, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 106500000ULL, 89, 89, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 89, 1, 16, 1, 0, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 108000000ULL, 135, 135, 1, 1, 5, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, + 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 85500000ULL, 214, 214, 1, 1, 11, 1, 1, 1, 1, 1, 1, 1, 214, 1, 16, 2, 1, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 83500000ULL, 105, 105, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 42, 1, 16, 1, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 92812500ULL, 155, 155, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 74250000ULL, 124, 124, 1, 1, 7, 1, 1, 1, 1, 1, 1, 1, 62, 1, 16, 5, 0, + 1, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 65000000ULL, 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, }, + { 50250000ULL, 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, }, + { 33750000ULL, 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, }, + { 40000000ULL, 100, 100, 1, 1, 11, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, + 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 27000000ULL, 0x5a, 0x5a, 1, 1, 0xf, 1, 1, 0, 1, 0, 1, 1, 0x9, 0, 0x05, 0, + 0x14, 0x18, 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, + { 25175000ULL, 84, 84, 1, 1, 0xf, 1, 1, 1, 1, 1, 1, 1, 168, 1, 16, 4, 1, 1, + 1, 0, 0x20, 0x0c, 1, 0x0e, 0, 0, }, +}; + +static const struct reg_sequence rk_hdtpx_common_cmn_init_seq[] = { + REG_SEQ0(CMN_REG(0009), 0x0c), + REG_SEQ0(CMN_REG(000a), 0x83), + REG_SEQ0(CMN_REG(000b), 0x06), + REG_SEQ0(CMN_REG(000c), 0x20), + REG_SEQ0(CMN_REG(000d), 0xb8), + REG_SEQ0(CMN_REG(000e), 0x0f), + REG_SEQ0(CMN_REG(000f), 0x0f), + REG_SEQ0(CMN_REG(0010), 0x04), + REG_SEQ0(CMN_REG(0011), 0x00), + REG_SEQ0(CMN_REG(0012), 0x26), + REG_SEQ0(CMN_REG(0013), 0x22), + REG_SEQ0(CMN_REG(0014), 0x24), + REG_SEQ0(CMN_REG(0015), 0x77), + REG_SEQ0(CMN_REG(0016), 0x08), + REG_SEQ0(CMN_REG(0017), 0x00), + REG_SEQ0(CMN_REG(0018), 0x04), + REG_SEQ0(CMN_REG(0019), 0x48), + REG_SEQ0(CMN_REG(001a), 0x01), + REG_SEQ0(CMN_REG(001b), 0x00), + REG_SEQ0(CMN_REG(001c), 0x01), + REG_SEQ0(CMN_REG(001d), 0x64), + REG_SEQ0(CMN_REG(001f), 0x00), + REG_SEQ0(CMN_REG(0026), 0x53), + REG_SEQ0(CMN_REG(0029), 0x01), + REG_SEQ0(CMN_REG(0030), 0x00), + REG_SEQ0(CMN_REG(0031), 0x20), + REG_SEQ0(CMN_REG(0032), 0x30), + REG_SEQ0(CMN_REG(0033), 0x0b), + REG_SEQ0(CMN_REG(0034), 0x23), + REG_SEQ0(CMN_REG(0035), 0x00), + REG_SEQ0(CMN_REG(0038), 0x00), + REG_SEQ0(CMN_REG(0039), 0x00), + REG_SEQ0(CMN_REG(003a), 0x00), + REG_SEQ0(CMN_REG(003b), 0x00), + REG_SEQ0(CMN_REG(003c), 0x80), + REG_SEQ0(CMN_REG(003e), 0x0c), + REG_SEQ0(CMN_REG(003f), 0x83), + REG_SEQ0(CMN_REG(0040), 0x06), + REG_SEQ0(CMN_REG(0041), 0x20), + REG_SEQ0(CMN_REG(0042), 0xb8), + REG_SEQ0(CMN_REG(0043), 0x00), + REG_SEQ0(CMN_REG(0044), 0x46), + REG_SEQ0(CMN_REG(0045), 0x24), + REG_SEQ0(CMN_REG(0046), 0xff), + REG_SEQ0(CMN_REG(0047), 0x00), + REG_SEQ0(CMN_REG(0048), 0x44), + REG_SEQ0(CMN_REG(0049), 0xfa), + REG_SEQ0(CMN_REG(004a), 0x08), + REG_SEQ0(CMN_REG(004b), 0x00), + REG_SEQ0(CMN_REG(004c), 0x01), + REG_SEQ0(CMN_REG(004d), 0x64), + REG_SEQ0(CMN_REG(004e), 0x14), + REG_SEQ0(CMN_REG(004f), 0x00), + REG_SEQ0(CMN_REG(0050), 0x00), + REG_SEQ0(CMN_REG(005d), 0x0c), + REG_SEQ0(CMN_REG(005f), 0x01), + REG_SEQ0(CMN_REG(006b), 0x04), + REG_SEQ0(CMN_REG(0073), 0x30), + REG_SEQ0(CMN_REG(0074), 0x00), + REG_SEQ0(CMN_REG(0075), 0x20), + REG_SEQ0(CMN_REG(0076), 0x30), + REG_SEQ0(CMN_REG(0077), 0x08), + REG_SEQ0(CMN_REG(0078), 0x0c), + REG_SEQ0(CMN_REG(0079), 0x00), + REG_SEQ0(CMN_REG(007b), 0x00), + REG_SEQ0(CMN_REG(007c), 0x00), + REG_SEQ0(CMN_REG(007d), 0x00), + REG_SEQ0(CMN_REG(007e), 0x00), + REG_SEQ0(CMN_REG(007f), 0x00), + REG_SEQ0(CMN_REG(0080), 0x00), + REG_SEQ0(CMN_REG(0081), 0x09), + REG_SEQ0(CMN_REG(0082), 0x04), + REG_SEQ0(CMN_REG(0083), 0x24), + REG_SEQ0(CMN_REG(0084), 0x20), + REG_SEQ0(CMN_REG(0085), 0x03), + REG_SEQ0(CMN_REG(0086), 0x01), + REG_SEQ0(CMN_REG(0087), 0x0c), + REG_SEQ0(CMN_REG(008a), 0x55), + REG_SEQ0(CMN_REG(008b), 0x25), + REG_SEQ0(CMN_REG(008c), 0x2c), + REG_SEQ0(CMN_REG(008d), 0x22), + REG_SEQ0(CMN_REG(008e), 0x14), + REG_SEQ0(CMN_REG(008f), 0x20), + REG_SEQ0(CMN_REG(0090), 0x00), + REG_SEQ0(CMN_REG(0091), 0x00), + REG_SEQ0(CMN_REG(0092), 0x00), + REG_SEQ0(CMN_REG(0093), 0x00), + REG_SEQ0(CMN_REG(009a), 0x11), + REG_SEQ0(CMN_REG(009b), 0x10), +}; + +static const struct reg_sequence rk_hdtpx_tmds_cmn_init_seq[] = { + REG_SEQ0(CMN_REG(0008), 0x00), + REG_SEQ0(CMN_REG(0011), 0x01), + REG_SEQ0(CMN_REG(0017), 0x20), + REG_SEQ0(CMN_REG(001e), 0x14), + REG_SEQ0(CMN_REG(0020), 0x00), + REG_SEQ0(CMN_REG(0021), 0x00), + REG_SEQ0(CMN_REG(0022), 0x11), + REG_SEQ0(CMN_REG(0023), 0x00), + REG_SEQ0(CMN_REG(0024), 0x00), + REG_SEQ0(CMN_REG(0025), 0x53), + REG_SEQ0(CMN_REG(0026), 0x00), + REG_SEQ0(CMN_REG(0027), 0x00), + REG_SEQ0(CMN_REG(0028), 0x01), + REG_SEQ0(CMN_REG(002a), 0x00), + REG_SEQ0(CMN_REG(002b), 0x00), + REG_SEQ0(CMN_REG(002c), 0x00), + REG_SEQ0(CMN_REG(002d), 0x00), + REG_SEQ0(CMN_REG(002e), 0x04), + REG_SEQ0(CMN_REG(002f), 0x00), + REG_SEQ0(CMN_REG(0030), 0x20), + REG_SEQ0(CMN_REG(0031), 0x30), + REG_SEQ0(CMN_REG(0032), 0x0b), + REG_SEQ0(CMN_REG(0033), 0x23), + REG_SEQ0(CMN_REG(0034), 0x00), + REG_SEQ0(CMN_REG(003d), 0x40), + REG_SEQ0(CMN_REG(0042), 0x78), + REG_SEQ0(CMN_REG(004e), 0x34), + REG_SEQ0(CMN_REG(005c), 0x25), + REG_SEQ0(CMN_REG(005e), 0x4f), + REG_SEQ0(CMN_REG(0074), 0x04), + REG_SEQ0(CMN_REG(0081), 0x01), + REG_SEQ0(CMN_REG(0087), 0x04), + REG_SEQ0(CMN_REG(0089), 0x00), + REG_SEQ0(CMN_REG(0095), 0x00), + REG_SEQ0(CMN_REG(0097), 0x02), + REG_SEQ0(CMN_REG(0099), 0x04), + REG_SEQ0(CMN_REG(009b), 0x00), +}; + +static const struct reg_sequence rk_hdtpx_common_sb_init_seq[] = { + REG_SEQ0(SB_REG(0114), 0x00), + REG_SEQ0(SB_REG(0115), 0x00), + REG_SEQ0(SB_REG(0116), 0x00), + REG_SEQ0(SB_REG(0117), 0x00), +}; + +static const struct reg_sequence rk_hdtpx_tmds_lntop_highbr_seq[] = { + REG_SEQ0(LNTOP_REG(0201), 0x00), + REG_SEQ0(LNTOP_REG(0202), 0x00), + REG_SEQ0(LNTOP_REG(0203), 0x0f), + REG_SEQ0(LNTOP_REG(0204), 0xff), + REG_SEQ0(LNTOP_REG(0205), 0xff), +}; + +static const struct reg_sequence rk_hdtpx_tmds_lntop_lowbr_seq[] = { + REG_SEQ0(LNTOP_REG(0201), 0x07), + REG_SEQ0(LNTOP_REG(0202), 0xc1), + REG_SEQ0(LNTOP_REG(0203), 0xf0), + REG_SEQ0(LNTOP_REG(0204), 0x7c), + REG_SEQ0(LNTOP_REG(0205), 0x1f), +}; + +static const struct reg_sequence rk_hdtpx_common_lane_init_seq[] = { + REG_SEQ0(LANE_REG(0303), 0x0c), + REG_SEQ0(LANE_REG(0307), 0x20), + REG_SEQ0(LANE_REG(030a), 0x17), + REG_SEQ0(LANE_REG(030b), 0x77), + REG_SEQ0(LANE_REG(030c), 0x77), + REG_SEQ0(LANE_REG(030d), 0x77), + REG_SEQ0(LANE_REG(030e), 0x38), + REG_SEQ0(LANE_REG(0310), 0x03), + REG_SEQ0(LANE_REG(0311), 0x0f), + REG_SEQ0(LANE_REG(0316), 0x02), + REG_SEQ0(LANE_REG(031b), 0x01), + REG_SEQ0(LANE_REG(031f), 0x15), + REG_SEQ0(LANE_REG(0320), 0xa0), + REG_SEQ0(LANE_REG(0403), 0x0c), + REG_SEQ0(LANE_REG(0407), 0x20), + REG_SEQ0(LANE_REG(040a), 0x17), + REG_SEQ0(LANE_REG(040b), 0x77), + REG_SEQ0(LANE_REG(040c), 0x77), + REG_SEQ0(LANE_REG(040d), 0x77), + REG_SEQ0(LANE_REG(040e), 0x38), + REG_SEQ0(LANE_REG(0410), 0x03), + REG_SEQ0(LANE_REG(0411), 0x0f), + REG_SEQ0(LANE_REG(0416), 0x02), + REG_SEQ0(LANE_REG(041b), 0x01), + REG_SEQ0(LANE_REG(041f), 0x15), + REG_SEQ0(LANE_REG(0420), 0xa0), + REG_SEQ0(LANE_REG(0503), 0x0c), + REG_SEQ0(LANE_REG(0507), 0x20), + REG_SEQ0(LANE_REG(050a), 0x17), + REG_SEQ0(LANE_REG(050b), 0x77), + REG_SEQ0(LANE_REG(050c), 0x77), + REG_SEQ0(LANE_REG(050d), 0x77), + REG_SEQ0(LANE_REG(050e), 0x38), + REG_SEQ0(LANE_REG(0510), 0x03), + REG_SEQ0(LANE_REG(0511), 0x0f), + REG_SEQ0(LANE_REG(0516), 0x02), + REG_SEQ0(LANE_REG(051b), 0x01), + REG_SEQ0(LANE_REG(051f), 0x15), + REG_SEQ0(LANE_REG(0520), 0xa0), + REG_SEQ0(LANE_REG(0603), 0x0c), + REG_SEQ0(LANE_REG(0607), 0x20), + REG_SEQ0(LANE_REG(060a), 0x17), + REG_SEQ0(LANE_REG(060b), 0x77), + REG_SEQ0(LANE_REG(060c), 0x77), + REG_SEQ0(LANE_REG(060d), 0x77), + REG_SEQ0(LANE_REG(060e), 0x38), + REG_SEQ0(LANE_REG(0610), 0x03), + REG_SEQ0(LANE_REG(0611), 0x0f), + REG_SEQ0(LANE_REG(0616), 0x02), + REG_SEQ0(LANE_REG(061b), 0x01), + REG_SEQ0(LANE_REG(061f), 0x15), + REG_SEQ0(LANE_REG(0620), 0xa0), +}; + +static const struct reg_sequence rk_hdtpx_tmds_lane_init_seq[] = { + REG_SEQ0(LANE_REG(0312), 0x00), + REG_SEQ0(LANE_REG(031e), 0x00), + REG_SEQ0(LANE_REG(0412), 0x00), + REG_SEQ0(LANE_REG(041e), 0x00), + REG_SEQ0(LANE_REG(0512), 0x00), + REG_SEQ0(LANE_REG(051e), 0x00), + REG_SEQ0(LANE_REG(0612), 0x00), + REG_SEQ0(LANE_REG(061e), 0x08), + REG_SEQ0(LANE_REG(0303), 0x2f), + REG_SEQ0(LANE_REG(0403), 0x2f), + REG_SEQ0(LANE_REG(0503), 0x2f), + REG_SEQ0(LANE_REG(0603), 0x2f), + REG_SEQ0(LANE_REG(0305), 0x03), + REG_SEQ0(LANE_REG(0405), 0x03), + REG_SEQ0(LANE_REG(0505), 0x03), + REG_SEQ0(LANE_REG(0605), 0x03), + REG_SEQ0(LANE_REG(0306), 0x1c), + REG_SEQ0(LANE_REG(0406), 0x1c), + REG_SEQ0(LANE_REG(0506), 0x1c), + 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: /* 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; + } + + return false; +} + +static const struct regmap_config rk_hdptx_phy_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .writeable_reg = rk_hdptx_phy_is_rw_reg, + .readable_reg = rk_hdptx_phy_is_rw_reg, + .fast_io = true, + .max_register = 0x18b4, +}; + +#define rk_hdptx_multi_reg_write(hdptx, seq) \ + regmap_multi_reg_write((hdptx)->regmap, seq, ARRAY_SIZE(seq)) + +static void rk_hdptx_pre_power_up(struct rk_hdptx_phy *hdptx) +{ + u32 val; + + reset_control_assert(hdptx->rsts[RST_APB].rstc); + usleep_range(20, 25); + reset_control_deassert(hdptx->rsts[RST_APB].rstc); + + reset_control_assert(hdptx->rsts[RST_LANE].rstc); + reset_control_assert(hdptx->rsts[RST_CMN].rstc); + reset_control_assert(hdptx->rsts[RST_INIT].rstc); + + val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); +} + +static int rk_hdptx_post_enable_lane(struct rk_hdptx_phy *hdptx) +{ + u32 val; + int ret; + + reset_control_deassert(hdptx->rsts[RST_LANE].rstc); + + val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 | + HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); + + ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val, + (val & HDPTX_O_PHY_RDY) && + (val & HDPTX_O_PLL_LOCK_DONE), + 100, 5000); + if (ret) { + dev_err(hdptx->dev, "Failed to get PHY lane lock: %d\n", ret); + return ret; + } + + dev_dbg(hdptx->dev, "PHY lane locked\n"); + + return 0; +} + +static int rk_hdptx_post_enable_pll(struct rk_hdptx_phy *hdptx) +{ + u32 val; + int ret; + + val = (HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16 | + HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); + + usleep_range(10, 15); + reset_control_deassert(hdptx->rsts[RST_INIT].rstc); + + usleep_range(10, 15); + val = HDPTX_I_PLL_EN << 16 | HDPTX_I_PLL_EN; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); + + usleep_range(10, 15); + reset_control_deassert(hdptx->rsts[RST_CMN].rstc); + + ret = regmap_read_poll_timeout(hdptx->grf, GRF_HDPTX_STATUS, val, + val & HDPTX_O_PHY_CLK_RDY, 20, 400); + if (ret) { + dev_err(hdptx->dev, "Failed to get PHY clk ready: %d\n", ret); + return ret; + } + + dev_dbg(hdptx->dev, "PHY clk ready\n"); + + return 0; +} + +static void rk_hdptx_phy_disable(struct rk_hdptx_phy *hdptx) +{ + u32 val; + + reset_control_assert(hdptx->rsts[RST_APB].rstc); + usleep_range(20, 30); + reset_control_deassert(hdptx->rsts[RST_APB].rstc); + + regmap_write(hdptx->regmap, LANE_REG(0300), 0x82); + regmap_write(hdptx->regmap, SB_REG(010f), 0xc1); + regmap_write(hdptx->regmap, SB_REG(0110), 0x1); + regmap_write(hdptx->regmap, LANE_REG(0301), 0x80); + regmap_write(hdptx->regmap, LANE_REG(0401), 0x80); + regmap_write(hdptx->regmap, LANE_REG(0501), 0x80); + regmap_write(hdptx->regmap, LANE_REG(0601), 0x80); + + reset_control_assert(hdptx->rsts[RST_LANE].rstc); + reset_control_assert(hdptx->rsts[RST_CMN].rstc); + reset_control_assert(hdptx->rsts[RST_INIT].rstc); + + val = (HDPTX_I_PLL_EN | HDPTX_I_BIAS_EN | HDPTX_I_BGR_EN) << 16; + regmap_write(hdptx->grf, GRF_HDPTX_CON0, val); +} + +static bool rk_hdptx_phy_clk_pll_calc(unsigned long long rate, + struct ropll_config *cfg) +{ + const unsigned int fout = div_u64(rate, 200), fref = 24000; + unsigned long k = 0, lc, k_sub, lc_sub; + unsigned int fvco, sdc; + u32 mdiv, sdiv, n = 8; + + if (fout > 0xfffffff) + return false; + + for (sdiv = 16; sdiv >= 1; sdiv--) { + if (sdiv % 2 && sdiv != 1) + continue; + + fvco = fout * sdiv; + + if (fvco < 2000000 || fvco > 4000000) + continue; + + mdiv = DIV_ROUND_UP(fvco, fref); + if (mdiv < 20 || mdiv > 255) + continue; + + if (fref * mdiv - fvco) { + for (sdc = 264000; sdc <= 750000; sdc += fref) + if (sdc * n > fref * mdiv) + break; + + if (sdc > 750000) + continue; + + rational_best_approximation(fref * mdiv - fvco, + sdc / 16, + GENMASK(6, 0), + GENMASK(7, 0), + &k, &lc); + + rational_best_approximation(sdc * n - fref * mdiv, + sdc, + GENMASK(6, 0), + GENMASK(7, 0), + &k_sub, &lc_sub); + } + + break; + } + + if (sdiv < 1) + return false; + + if (cfg) { + cfg->pms_mdiv = mdiv; + cfg->pms_mdiv_afc = mdiv; + cfg->pms_pdiv = 1; + cfg->pms_refdiv = 1; + cfg->pms_sdiv = sdiv - 1; + + cfg->sdm_en = k > 0 ? 1 : 0; + if (cfg->sdm_en) { + cfg->sdm_deno = lc; + cfg->sdm_num_sign = 1; + cfg->sdm_num = k; + cfg->sdc_n = n - 3; + cfg->sdc_num = k_sub; + cfg->sdc_deno = lc_sub; + } + } + + return true; +} + +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 ret, i; + + if (!hdptx->hdmi_cfg.tmds_char_rate) + return 0; + + for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) + if (hdptx->hdmi_cfg.tmds_char_rate == ropll_tmds_cfg[i].rate) { + cfg = &ropll_tmds_cfg[i]; + break; + } + + if (!cfg) { + if (!rk_hdptx_phy_clk_pll_calc(hdptx->hdmi_cfg.tmds_char_rate, &rc)) { + dev_err(hdptx->dev, "%s cannot find pll cfg for rate=%llu\n", + __func__, hdptx->hdmi_cfg.tmds_char_rate); + return -EINVAL; + } + + cfg = &rc; + } + + dev_dbg(hdptx->dev, "%s rate=%llu mdiv=%u sdiv=%u sdm_en=%u k_sign=%u k=%u lc=%u\n", + __func__, hdptx->hdmi_cfg.tmds_char_rate, cfg->pms_mdiv, cfg->pms_sdiv + 1, + cfg->sdm_en, cfg->sdm_num_sign, cfg->sdm_num, cfg->sdm_deno); + + rk_hdptx_pre_power_up(hdptx); + + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_cmn_init_seq); + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_cmn_init_seq); + + regmap_write(hdptx->regmap, CMN_REG(0051), cfg->pms_mdiv); + regmap_write(hdptx->regmap, CMN_REG(0055), cfg->pms_mdiv_afc); + regmap_write(hdptx->regmap, CMN_REG(0059), + (cfg->pms_pdiv << 4) | cfg->pms_refdiv); + regmap_write(hdptx->regmap, CMN_REG(005a), cfg->pms_sdiv << 4); + + regmap_update_bits(hdptx->regmap, CMN_REG(005e), ROPLL_SDM_EN_MASK, + FIELD_PREP(ROPLL_SDM_EN_MASK, cfg->sdm_en)); + if (!cfg->sdm_en) + regmap_update_bits(hdptx->regmap, CMN_REG(005e), 0xf, 0); + + regmap_update_bits(hdptx->regmap, CMN_REG(0064), ROPLL_SDM_NUM_SIGN_RBR_MASK, + FIELD_PREP(ROPLL_SDM_NUM_SIGN_RBR_MASK, cfg->sdm_num_sign)); + + regmap_write(hdptx->regmap, CMN_REG(0060), cfg->sdm_deno); + regmap_write(hdptx->regmap, CMN_REG(0065), cfg->sdm_num); + + regmap_update_bits(hdptx->regmap, CMN_REG(0069), ROPLL_SDC_N_RBR_MASK, + FIELD_PREP(ROPLL_SDC_N_RBR_MASK, cfg->sdc_n)); + + regmap_write(hdptx->regmap, CMN_REG(006c), cfg->sdc_num); + regmap_write(hdptx->regmap, CMN_REG(0070), cfg->sdc_deno); + + 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_SEL_MASK, + FIELD_PREP(PLL_PCG_CLK_SEL_MASK, (hdptx->hdmi_cfg.bpc - 8) >> 1)); + + regmap_update_bits(hdptx->regmap, CMN_REG(0086), PLL_PCG_CLK_EN_MASK, + FIELD_PREP(PLL_PCG_CLK_EN_MASK, 0x1)); + + ret = rk_hdptx_post_enable_pll(hdptx); + if (!ret) + hdptx->hw_rate = hdptx->hdmi_cfg.tmds_char_rate; + + return ret; +} + +static int rk_hdptx_ropll_tmds_mode_config(struct rk_hdptx_phy *hdptx) +{ + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_sb_init_seq); + + regmap_write(hdptx->regmap, LNTOP_REG(0200), 0x06); + + if (hdptx->hdmi_cfg.tmds_char_rate > HDMI14_MAX_RATE) { + /* For 1/40 bitrate clk */ + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_highbr_seq); + } else { + /* For 1/10 bitrate clk */ + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lntop_lowbr_seq); + } + + regmap_write(hdptx->regmap, LNTOP_REG(0206), 0x07); + regmap_write(hdptx->regmap, LNTOP_REG(0207), 0x0f); + + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_common_lane_init_seq); + rk_hdptx_multi_reg_write(hdptx, rk_hdtpx_tmds_lane_init_seq); + + 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) +{ + enum phy_mode mode = phy_get_mode(hdptx->phy); + u32 status; + int ret; + + if (atomic_inc_return(&hdptx->usage_count) > 1) + return 0; + + ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status); + if (ret) + goto dec_usage; + + if (status & HDPTX_O_PLL_LOCK_DONE) + dev_warn(hdptx->dev, "PLL locked by unknown consumer!\n"); + + if (mode == PHY_MODE_DP) { + rk_hdptx_dp_reset(hdptx); + } else { + ret = rk_hdptx_ropll_tmds_cmn_config(hdptx); + if (ret) + goto dec_usage; + } + + return 0; + +dec_usage: + atomic_dec(&hdptx->usage_count); + return ret; +} + +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; + + ret = atomic_dec_return(&hdptx->usage_count); + if (ret > 0) + return 0; + + if (ret < 0) { + dev_warn(hdptx->dev, "Usage count underflow!\n"); + ret = -EINVAL; + } else { + ret = regmap_read(hdptx->grf, GRF_HDPTX_STATUS, &status); + if (!ret) { + 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; + } + } + + atomic_inc(&hdptx->usage_count); + 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); + enum phy_mode mode = phy_get_mode(phy); + int ret, lane; + + if (mode != PHY_MODE_DP) { + if (!hdptx->hdmi_cfg.tmds_char_rate) { + /* + * FIXME: Temporary workaround to setup TMDS char rate + * from the RK DW HDMI QP bridge driver. + * Will be removed as soon the switch to the HDMI PHY + * configuration API has been completed on both ends. + */ + hdptx->hdmi_cfg.tmds_char_rate = phy_get_bus_width(hdptx->phy) & 0xfffffff; + hdptx->hdmi_cfg.tmds_char_rate *= 100; + } + + dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__, + hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc); + } + + ret = rk_hdptx_phy_consumer_get(hdptx); + if (ret) + return ret; + + 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); + if (ret) + rk_hdptx_phy_consumer_put(hdptx, true); + } + + return ret; +} + +static int rk_hdptx_phy_power_off(struct phy *phy) +{ + struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); + + return rk_hdptx_phy_consumer_put(hdptx, false); +} + +static int rk_hdptx_phy_verify_hdmi_config(struct rk_hdptx_phy *hdptx, + struct phy_configure_opts_hdmi *hdmi) +{ + int i; + + if (!hdmi->tmds_char_rate || hdmi->tmds_char_rate > HDMI20_MAX_RATE) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(ropll_tmds_cfg); i++) + if (hdmi->tmds_char_rate == ropll_tmds_cfg[i].rate) + break; + + if (i == ARRAY_SIZE(ropll_tmds_cfg) && + !rk_hdptx_phy_clk_pll_calc(hdmi->tmds_char_rate, NULL)) + return -EINVAL; + + if (!hdmi->bpc) + hdmi->bpc = 8; + + switch (hdmi->bpc) { + case 8: + case 10: + case 12: + case 16: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rk_hdptx_phy_verify_dp_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) { + ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi); + if (ret) { + dev_err(hdptx->dev, "invalid hdmi params for phy configure\n"); + } else { + hdptx->hdmi_cfg = opts->hdmi; + hdptx->restrict_rate_change = true; + } + + dev_dbg(hdptx->dev, "%s rate=%llu bpc=%u\n", __func__, + hdptx->hdmi_cfg.tmds_char_rate, hdptx->hdmi_cfg.bpc); + return ret; + } + + ret = rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp); + if (ret) { + dev_err(hdptx->dev, "invalid dp 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 int rk_hdptx_phy_validate(struct phy *phy, enum phy_mode mode, + int submode, union phy_configure_opts *opts) +{ + struct rk_hdptx_phy *hdptx = phy_get_drvdata(phy); + + if (mode != PHY_MODE_DP) + return rk_hdptx_phy_verify_hdmi_config(hdptx, &opts->hdmi); + + return rk_hdptx_phy_verify_dp_config(hdptx, &opts->dp); +} + +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, + .validate = rk_hdptx_phy_validate, + .owner = THIS_MODULE, +}; + +static struct rk_hdptx_phy *to_rk_hdptx_phy(struct clk_hw *hw) +{ + return container_of(hw, struct rk_hdptx_phy, hw); +} + +static int rk_hdptx_phy_clk_prepare(struct clk_hw *hw) +{ + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + + return rk_hdptx_phy_consumer_get(hdptx); +} + +static void rk_hdptx_phy_clk_unprepare(struct clk_hw *hw) +{ + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + + rk_hdptx_phy_consumer_put(hdptx, true); +} + +static unsigned long rk_hdptx_phy_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + + return hdptx->hw_rate; +} + +static long rk_hdptx_phy_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + + /* + * FIXME: Temporarily allow altering TMDS char rate via CCF. + * To be dropped as soon as the RK DW HDMI QP bridge driver + * switches to make use of phy_configure(). + */ + if (!hdptx->restrict_rate_change && rate != hdptx->hdmi_cfg.tmds_char_rate) { + struct phy_configure_opts_hdmi hdmi = { + .tmds_char_rate = rate, + }; + int ret = rk_hdptx_phy_verify_hdmi_config(hdptx, &hdmi); + + if (ret) + return ret; + + hdptx->hdmi_cfg = hdmi; + } + + /* + * The TMDS char rate shall be adjusted via phy_configure() only, + * hence ensure rk_hdptx_phy_clk_set_rate() won't be invoked with + * a different rate argument. + */ + return hdptx->hdmi_cfg.tmds_char_rate; +} + +static int rk_hdptx_phy_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct rk_hdptx_phy *hdptx = to_rk_hdptx_phy(hw); + + /* Revert any unlikely TMDS char rate change since round_rate() */ + if (hdptx->hdmi_cfg.tmds_char_rate != rate) { + dev_warn(hdptx->dev, "Reverting unexpected rate change from %lu to %llu\n", + rate, hdptx->hdmi_cfg.tmds_char_rate); + hdptx->hdmi_cfg.tmds_char_rate = rate; + } + + /* + * The TMDS char rate would be normally programmed in HW during + * phy_ops.power_on() or clk_ops.prepare() callbacks, but it might + * happen that the former gets fired too late, i.e. after this call, + * while the latter being executed only once, i.e. when clock remains + * in the prepared state during rate changes. + */ + return rk_hdptx_ropll_tmds_cmn_config(hdptx); +} + +static const struct clk_ops hdptx_phy_clk_ops = { + .prepare = rk_hdptx_phy_clk_prepare, + .unprepare = rk_hdptx_phy_clk_unprepare, + .recalc_rate = rk_hdptx_phy_clk_recalc_rate, + .round_rate = rk_hdptx_phy_clk_round_rate, + .set_rate = rk_hdptx_phy_clk_set_rate, +}; + +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; + + refclk = devm_clk_get(dev, "ref"); + if (IS_ERR(refclk)) + return dev_err_probe(dev, PTR_ERR(refclk), + "Failed to get ref clock\n"); + + 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, + CLK_GET_RATE_NOCACHE); + + ret = devm_clk_hw_register(dev, &hdptx->hw); + if (ret) + return dev_err_probe(dev, ret, "Failed to register clock\n"); + + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, &hdptx->hw); + if (ret) + return dev_err_probe(dev, ret, + "Failed to register clk provider\n"); + return 0; +} + +static int rk_hdptx_phy_runtime_suspend(struct device *dev) +{ + struct rk_hdptx_phy *hdptx = dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(hdptx->nr_clks, hdptx->clks); + + return 0; +} + +static int rk_hdptx_phy_runtime_resume(struct device *dev) +{ + struct rk_hdptx_phy *hdptx = dev_get_drvdata(dev); + int ret; + + ret = clk_bulk_prepare_enable(hdptx->nr_clks, hdptx->clks); + if (ret) + dev_err(hdptx->dev, "Failed to enable clocks: %d\n", ret); + + return ret; +} + +static int rk_hdptx_phy_probe(struct platform_device *pdev) +{ + const struct rk_hdptx_phy_cfg *cfgs; + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct rk_hdptx_phy *hdptx; + struct resource *res; + void __iomem *regs; + int ret, id; + + hdptx = devm_kzalloc(dev, sizeof(*hdptx), GFP_KERNEL); + if (!hdptx) + return -ENOMEM; + + hdptx->dev = dev; + hdptx->hdmi_cfg.bpc = 8; + + 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"); + + cfgs = device_get_match_data(dev); + if (!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 < cfgs->num_phys; id++) { + if (res->start == 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"); + if (ret == 0) + return dev_err_probe(dev, -EINVAL, "Missing clocks\n"); + + hdptx->nr_clks = ret; + + hdptx->regmap = devm_regmap_init_mmio(dev, regs, + &rk_hdptx_phy_regmap_config); + if (IS_ERR(hdptx->regmap)) + return dev_err_probe(dev, PTR_ERR(hdptx->regmap), + "Failed to init regmap\n"); + + hdptx->rsts[RST_APB].id = "apb"; + hdptx->rsts[RST_INIT].id = "init"; + hdptx->rsts[RST_CMN].id = "cmn"; + hdptx->rsts[RST_LANE].id = "lane"; + + ret = devm_reset_control_bulk_get_exclusive(dev, RST_MAX, hdptx->rsts); + if (ret) + return dev_err_probe(dev, ret, "Failed to get resets\n"); + + hdptx->grf = syscon_regmap_lookup_by_phandle(dev->of_node, + "rockchip,grf"); + if (IS_ERR(hdptx->grf)) + return dev_err_probe(dev, PTR_ERR(hdptx->grf), + "Could not get GRF syscon\n"); + + platform_set_drvdata(pdev, hdptx); + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable runtime PM\n"); + + hdptx->phy = devm_phy_create(dev, NULL, &rk_hdptx_phy_ops); + if (IS_ERR(hdptx->phy)) + return dev_err_probe(dev, PTR_ERR(hdptx->phy), + "Failed to create HDMI PHY\n"); + + phy_set_drvdata(hdptx->phy, hdptx); + phy_set_bus_width(hdptx->phy, 8); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return dev_err_probe(dev, PTR_ERR(phy_provider), + "Failed to register PHY provider\n"); + + reset_control_deassert(hdptx->rsts[RST_APB].rstc); + reset_control_deassert(hdptx->rsts[RST_CMN].rstc); + reset_control_deassert(hdptx->rsts[RST_INIT].rstc); + + return rk_hdptx_phy_clk_register(hdptx); +} + +static const struct dev_pm_ops rk_hdptx_phy_pm_ops = { + RUNTIME_PM_OPS(rk_hdptx_phy_runtime_suspend, + 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,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); + +static struct platform_driver rk_hdptx_phy_driver = { + .probe = rk_hdptx_phy_probe, + .driver = { + .name = "rockchip-hdptx-phy", + .pm = &rk_hdptx_phy_pm_ops, + .of_match_table = rk_hdptx_phy_of_match, + }, +}; +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-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index 121e5961ce11..4e8ffd173096 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -35,11 +35,19 @@ #define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 #define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 #define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 +#define RK3588_PCIE3PHY_GRF_PHY0_LN0_CON1 0x1004 +#define RK3588_PCIE3PHY_GRF_PHY0_LN1_CON1 0x1104 +#define RK3588_PCIE3PHY_GRF_PHY1_LN0_CON1 0x2004 +#define RK3588_PCIE3PHY_GRF_PHY1_LN1_CON1 0x2104 #define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0)) #define RK3588_BIFURCATION_LANE_0_1 BIT(0) #define RK3588_BIFURCATION_LANE_2_3 BIT(1) #define RK3588_LANE_AGGREGATION BIT(2) +#define RK3588_RX_CMN_REFCLK_MODE_EN ((BIT(7) << 16) | BIT(7)) +#define RK3588_RX_CMN_REFCLK_MODE_DIS (BIT(7) << 16) +#define RK3588_PCIE1LN_SEL_EN (GENMASK(1, 0) << 16) +#define RK3588_PCIE30_PHY_MODE_EN (GENMASK(2, 0) << 16) struct rockchip_p3phy_ops; @@ -58,6 +66,7 @@ struct rockchip_p3phy_priv { int num_clks; int num_lanes; u32 lanes[4]; + u32 rx_cmn_refclk_mode[4]; }; struct rockchip_p3phy_ops { @@ -132,39 +141,45 @@ static const struct rockchip_p3phy_ops rk3568_ops = { static int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) { u32 reg = 0; - u8 mode = 0; + u8 mode = RK3588_LANE_AGGREGATION; /* default */ int ret; + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY0_LN0_CON1, + priv->rx_cmn_refclk_mode[0] ? RK3588_RX_CMN_REFCLK_MODE_EN : + RK3588_RX_CMN_REFCLK_MODE_DIS); + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY0_LN1_CON1, + priv->rx_cmn_refclk_mode[1] ? RK3588_RX_CMN_REFCLK_MODE_EN : + RK3588_RX_CMN_REFCLK_MODE_DIS); + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY1_LN0_CON1, + priv->rx_cmn_refclk_mode[2] ? RK3588_RX_CMN_REFCLK_MODE_EN : + RK3588_RX_CMN_REFCLK_MODE_DIS); + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY1_LN1_CON1, + priv->rx_cmn_refclk_mode[3] ? RK3588_RX_CMN_REFCLK_MODE_EN : + RK3588_RX_CMN_REFCLK_MODE_DIS); + /* Deassert PCIe PMA output clamp mode */ regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, BIT(8) | BIT(24)); /* Set bifurcation if needed */ for (int i = 0; i < priv->num_lanes; i++) { - if (!priv->lanes[i]) - mode |= (BIT(i) << 3); - if (priv->lanes[i] > 1) - mode |= (BIT(i) >> 1); - } - - if (!mode) - reg = RK3588_LANE_AGGREGATION; - else { - if (mode & (BIT(0) | BIT(1))) - reg |= RK3588_BIFURCATION_LANE_0_1; - - if (mode & (BIT(2) | BIT(3))) - reg |= RK3588_BIFURCATION_LANE_2_3; + mode &= ~RK3588_LANE_AGGREGATION; + if (priv->lanes[i] == 3) + mode |= RK3588_BIFURCATION_LANE_0_1; + if (priv->lanes[i] == 4) + mode |= RK3588_BIFURCATION_LANE_2_3; } - regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, (0x7<<16) | reg); + reg = mode; + regmap_write(priv->phy_grf, RK3588_PCIE3PHY_GRF_CMN_CON0, + RK3588_PCIE30_PHY_MODE_EN | reg); /* Set pcie1ln_sel in PHP_GRF_PCIESEL_CON */ if (!IS_ERR(priv->pipe_grf)) { - reg = (mode & (BIT(6) | BIT(7))) >> 6; + reg = mode & (RK3588_BIFURCATION_LANE_0_1 | RK3588_BIFURCATION_LANE_2_3); if (reg) regmap_write(priv->pipe_grf, PHP_GRF_PCIESEL_CON, - (reg << 16) | reg); + RK3588_PCIE1LN_SEL_EN | reg); } reset_control_deassert(priv->p30phy); @@ -187,7 +202,7 @@ static const struct rockchip_p3phy_ops rk3588_ops = { .phy_init = rockchip_p3phy_rk3588_init, }; -static int rochchip_p3phy_init(struct phy *phy) +static int rockchip_p3phy_init(struct phy *phy) { struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); int ret; @@ -210,7 +225,7 @@ static int rochchip_p3phy_init(struct phy *phy) return ret; } -static int rochchip_p3phy_exit(struct phy *phy) +static int rockchip_p3phy_exit(struct phy *phy) { struct rockchip_p3phy_priv *priv = phy_get_drvdata(phy); @@ -219,9 +234,9 @@ static int rochchip_p3phy_exit(struct phy *phy) return 0; } -static const struct phy_ops rochchip_p3phy_ops = { - .init = rochchip_p3phy_init, - .exit = rochchip_p3phy_exit, +static const struct phy_ops rockchip_p3phy_ops = { + .init = rockchip_p3phy_init, + .exit = rockchip_p3phy_exit, .set_mode = rockchip_p3phy_set_mode, .owner = THIS_MODULE, }; @@ -280,7 +295,24 @@ static int rockchip_p3phy_probe(struct platform_device *pdev) return priv->num_lanes; } - priv->phy = devm_phy_create(dev, NULL, &rochchip_p3phy_ops); + ret = of_property_read_variable_u32_array(dev->of_node, + "rockchip,rx-common-refclk-mode", + priv->rx_cmn_refclk_mode, 1, + ARRAY_SIZE(priv->rx_cmn_refclk_mode)); + /* + * if no rockchip,rx-common-refclk-mode, assume enabled for all lanes in + * order to be DT backwards compatible. (Since HW reset val is enabled.) + */ + if (ret == -EINVAL) { + for (int i = 0; i < ARRAY_SIZE(priv->rx_cmn_refclk_mode); i++) + priv->rx_cmn_refclk_mode[i] = 1; + } else if (ret < 0) { + dev_err(dev, "failed to read rockchip,rx-common-refclk-mode property %d\n", + ret); + return ret; + } + + priv->phy = devm_phy_create(dev, NULL, &rockchip_p3phy_ops); if (IS_ERR(priv->phy)) { dev_err(dev, "failed to create combphy\n"); return PTR_ERR(priv->phy); diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 4efcb78b0ab1..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> * @@ -1210,7 +1210,7 @@ MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids); static struct platform_driver rockchip_typec_phy_driver = { .probe = rockchip_typec_phy_probe, - .remove_new = rockchip_typec_phy_remove, + .remove = rockchip_typec_phy_remove, .driver = { .name = "rockchip-typec-phy", .of_match_table = rockchip_typec_phy_dt_ids, diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c new file mode 100644 index 000000000000..c066cc0a7b4f --- /dev/null +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -0,0 +1,1667 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Rockchip USBDP Combo PHY with Samsung IP block driver + * + * Copyright (C) 2021-2024 Rockchip Electronics Co., Ltd + * Copyright (C) 2024 Collabora Ltd + */ + +#include <dt-bindings/phy/phy.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/mfd/syscon.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <linux/usb/ch9.h> +#include <linux/usb/typec_dp.h> +#include <linux/usb/typec_mux.h> + +/* USBDP PHY Register Definitions */ +#define UDPHY_PCS 0x4000 +#define UDPHY_PMA 0x8000 + +/* VO0 GRF Registers */ +#define DP_SINK_HPD_CFG BIT(11) +#define DP_SINK_HPD_SEL BIT(10) +#define DP_AUX_DIN_SEL BIT(9) +#define DP_AUX_DOUT_SEL BIT(8) +#define DP_LANE_SEL_N(n) GENMASK(2 * (n) + 1, 2 * (n)) +#define DP_LANE_SEL_ALL GENMASK(7, 0) + +/* PMA CMN Registers */ +#define CMN_LANE_MUX_AND_EN_OFFSET 0x0288 /* cmn_reg00A2 */ +#define CMN_DP_LANE_MUX_N(n) BIT((n) + 4) +#define CMN_DP_LANE_EN_N(n) BIT(n) +#define CMN_DP_LANE_MUX_ALL GENMASK(7, 4) +#define CMN_DP_LANE_EN_ALL GENMASK(3, 0) + +#define CMN_DP_LINK_OFFSET 0x28c /* cmn_reg00A3 */ +#define CMN_DP_TX_LINK_BW GENMASK(6, 5) +#define CMN_DP_TX_LANE_SWAP_EN BIT(2) + +#define CMN_SSC_EN_OFFSET 0x2d0 /* cmn_reg00B4 */ +#define CMN_ROPLL_SSC_EN BIT(1) +#define CMN_LCPLL_SSC_EN BIT(0) + +#define CMN_ANA_LCPLL_DONE_OFFSET 0x0350 /* cmn_reg00D4 */ +#define CMN_ANA_LCPLL_LOCK_DONE BIT(7) +#define CMN_ANA_LCPLL_AFC_DONE BIT(6) + +#define CMN_ANA_ROPLL_DONE_OFFSET 0x0354 /* cmn_reg00D5 */ +#define CMN_ANA_ROPLL_LOCK_DONE BIT(1) +#define CMN_ANA_ROPLL_AFC_DONE BIT(0) + +#define CMN_DP_RSTN_OFFSET 0x038c /* cmn_reg00E3 */ +#define CMN_DP_INIT_RSTN BIT(3) +#define CMN_DP_CMN_RSTN BIT(2) +#define CMN_CDR_WTCHDG_EN BIT(1) +#define CMN_CDR_WTCHDG_MSK_CDR_EN BIT(0) + +#define TRSV_ANA_TX_CLK_OFFSET_N(n) (0x854 + (n) * 0x800) /* trsv_reg0215 */ +#define LN_ANA_TX_SER_TXCLK_INV BIT(1) + +#define TRSV_LN0_MON_RX_CDR_DONE_OFFSET 0x0b84 /* trsv_reg02E1 */ +#define TRSV_LN0_MON_RX_CDR_LOCK_DONE BIT(0) + +#define TRSV_LN2_MON_RX_CDR_DONE_OFFSET 0x1b84 /* trsv_reg06E1 */ +#define TRSV_LN2_MON_RX_CDR_LOCK_DONE BIT(0) + +#define BIT_WRITEABLE_SHIFT 16 +#define PHY_AUX_DP_DATA_POL_NORMAL 0 +#define PHY_AUX_DP_DATA_POL_INVERT 1 +#define PHY_LANE_MUX_USB 0 +#define PHY_LANE_MUX_DP 1 + +enum { + DP_BW_RBR, + DP_BW_HBR, + DP_BW_HBR2, + DP_BW_HBR3, +}; + +enum { + UDPHY_MODE_NONE = 0, + UDPHY_MODE_USB = BIT(0), + UDPHY_MODE_DP = BIT(1), + UDPHY_MODE_DP_USB = BIT(1) | BIT(0), +}; + +struct rk_udphy_grf_reg { + unsigned int offset; + unsigned int disable; + unsigned int enable; +}; + +#define _RK_UDPHY_GEN_GRF_REG(offset, mask, disable, enable) \ +{\ + offset, \ + FIELD_PREP_CONST(mask, disable) | (mask << BIT_WRITEABLE_SHIFT), \ + FIELD_PREP_CONST(mask, enable) | (mask << BIT_WRITEABLE_SHIFT), \ +} + +#define RK_UDPHY_GEN_GRF_REG(offset, bitend, bitstart, disable, enable) \ + _RK_UDPHY_GEN_GRF_REG(offset, GENMASK(bitend, bitstart), disable, enable) + +struct rk_udphy_grf_cfg { + /* u2phy-grf */ + struct rk_udphy_grf_reg bvalid_phy_con; + struct rk_udphy_grf_reg bvalid_grf_con; + + /* usb-grf */ + struct rk_udphy_grf_reg usb3otg0_cfg; + struct rk_udphy_grf_reg usb3otg1_cfg; + + /* usbdpphy-grf */ + struct rk_udphy_grf_reg low_pwrn; + struct rk_udphy_grf_reg rx_lfps; +}; + +struct rk_udphy_vogrf_cfg { + /* vo-grf */ + struct rk_udphy_grf_reg hpd_trigger; + u32 dp_lane_reg; +}; + +struct rk_udphy_dp_tx_drv_ctrl { + u32 trsv_reg0204; + u32 trsv_reg0205; + u32 trsv_reg0206; + u32 trsv_reg0207; +}; + +struct rk_udphy_cfg { + unsigned int num_phys; + unsigned int phy_ids[2]; + /* resets to be requested */ + const char * const *rst_list; + int num_rsts; + + struct rk_udphy_grf_cfg grfcfg; + struct rk_udphy_vogrf_cfg vogrfcfg[2]; + const struct rk_udphy_dp_tx_drv_ctrl (*dp_tx_ctrl_cfg[4])[4]; + const struct rk_udphy_dp_tx_drv_ctrl (*dp_tx_ctrl_cfg_typec[4])[4]; +}; + +struct rk_udphy { + struct device *dev; + struct regmap *pma_regmap; + struct regmap *u2phygrf; + struct regmap *udphygrf; + struct regmap *usbgrf; + struct regmap *vogrf; + struct typec_switch_dev *sw; + struct typec_mux_dev *mux; + struct mutex mutex; /* mutex to protect access to individual PHYs */ + + /* clocks and rests */ + int num_clks; + struct clk_bulk_data *clks; + struct clk *refclk; + int num_rsts; + struct reset_control_bulk_data *rsts; + + /* PHY status management */ + bool flip; + bool mode_change; + u8 mode; + u8 status; + + /* utilized for USB */ + bool hs; /* flag for high-speed */ + + /* utilized for DP */ + struct gpio_desc *sbu1_dc_gpio; + struct gpio_desc *sbu2_dc_gpio; + u32 lane_mux_sel[4]; + u32 dp_lane_sel[4]; + u32 dp_aux_dout_sel; + 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; + + bool dp_in_use; + + /* PHY const config */ + const struct rk_udphy_cfg *cfgs; + + /* PHY devices */ + struct phy *phy_dp; + struct phy *phy_u3; +}; + +static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x20, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x29, 0x18, 0x42, 0xe5 }, + { 0x2b, 0x1c, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x23, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x17, 0x43, 0xe7 }, + { 0x2b, 0x1a, 0x43, 0xe7 }, + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x27, 0x10, 0x42, 0xe7 }, + { 0x2b, 0x17, 0x43, 0xe7 }, + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x29, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_rbr_hbr_typec[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x20, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x29, 0x18, 0x42, 0xe5 }, + { 0x2b, 0x1c, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x23, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x17, 0x43, 0xe7 }, + { 0x2b, 0x1a, 0x43, 0xe7 }, + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x27, 0x10, 0x43, 0x67 }, + { 0x2b, 0x17, 0x43, 0xe7 }, + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x29, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr2[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x21, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x26, 0x16, 0x43, 0xe5 }, + { 0x2a, 0x19, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x24, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x17, 0x43, 0xe7 }, + { 0x2b, 0x1a, 0x43, 0xe7 }, + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x28, 0x10, 0x42, 0xe7 }, + { 0x2b, 0x17, 0x43, 0xe7 }, + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x28, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct rk_udphy_dp_tx_drv_ctrl rk3588_dp_tx_drv_ctrl_hbr3[4][4] = { + /* voltage swing 0, pre-emphasis 0->3 */ + { + { 0x21, 0x10, 0x42, 0xe5 }, + { 0x26, 0x14, 0x42, 0xe5 }, + { 0x26, 0x16, 0x43, 0xe5 }, + { 0x29, 0x18, 0x43, 0xe7 }, + }, + + /* voltage swing 1, pre-emphasis 0->2 */ + { + { 0x24, 0x10, 0x42, 0xe7 }, + { 0x2a, 0x18, 0x43, 0xe7 }, + { 0x2b, 0x1b, 0x43, 0xe7 } + }, + + /* voltage swing 2, pre-emphasis 0->1 */ + { + { 0x27, 0x10, 0x42, 0xe7 }, + { 0x2b, 0x18, 0x43, 0xe7 } + }, + + /* voltage swing 3, pre-emphasis 0 */ + { + { 0x28, 0x10, 0x43, 0xe7 }, + }, +}; + +static const struct reg_sequence rk_udphy_24m_refclk_cfg[] = { + {0x0090, 0x68}, {0x0094, 0x68}, + {0x0128, 0x24}, {0x012c, 0x44}, + {0x0130, 0x3f}, {0x0134, 0x44}, + {0x015c, 0xa9}, {0x0160, 0x71}, + {0x0164, 0x71}, {0x0168, 0xa9}, + {0x0174, 0xa9}, {0x0178, 0x71}, + {0x017c, 0x71}, {0x0180, 0xa9}, + {0x018c, 0x41}, {0x0190, 0x00}, + {0x0194, 0x05}, {0x01ac, 0x2a}, + {0x01b0, 0x17}, {0x01b4, 0x17}, + {0x01b8, 0x2a}, {0x01c8, 0x04}, + {0x01cc, 0x08}, {0x01d0, 0x08}, + {0x01d4, 0x04}, {0x01d8, 0x20}, + {0x01dc, 0x01}, {0x01e0, 0x09}, + {0x01e4, 0x03}, {0x01f0, 0x29}, + {0x01f4, 0x02}, {0x01f8, 0x02}, + {0x01fc, 0x29}, {0x0208, 0x2a}, + {0x020c, 0x17}, {0x0210, 0x17}, + {0x0214, 0x2a}, {0x0224, 0x20}, + {0x03f0, 0x0a}, {0x03f4, 0x07}, + {0x03f8, 0x07}, {0x03fc, 0x0c}, + {0x0404, 0x12}, {0x0408, 0x1a}, + {0x040c, 0x1a}, {0x0410, 0x3f}, + {0x0ce0, 0x68}, {0x0ce8, 0xd0}, + {0x0cf0, 0x87}, {0x0cf8, 0x70}, + {0x0d00, 0x70}, {0x0d08, 0xa9}, + {0x1ce0, 0x68}, {0x1ce8, 0xd0}, + {0x1cf0, 0x87}, {0x1cf8, 0x70}, + {0x1d00, 0x70}, {0x1d08, 0xa9}, + {0x0a3c, 0xd0}, {0x0a44, 0xd0}, + {0x0a48, 0x01}, {0x0a4c, 0x0d}, + {0x0a54, 0xe0}, {0x0a5c, 0xe0}, + {0x0a64, 0xa8}, {0x1a3c, 0xd0}, + {0x1a44, 0xd0}, {0x1a48, 0x01}, + {0x1a4c, 0x0d}, {0x1a54, 0xe0}, + {0x1a5c, 0xe0}, {0x1a64, 0xa8} +}; + +static const struct reg_sequence rk_udphy_26m_refclk_cfg[] = { + {0x0830, 0x07}, {0x085c, 0x80}, + {0x1030, 0x07}, {0x105c, 0x80}, + {0x1830, 0x07}, {0x185c, 0x80}, + {0x2030, 0x07}, {0x205c, 0x80}, + {0x0228, 0x38}, {0x0104, 0x44}, + {0x0248, 0x44}, {0x038c, 0x02}, + {0x0878, 0x04}, {0x1878, 0x04}, + {0x0898, 0x77}, {0x1898, 0x77}, + {0x0054, 0x01}, {0x00e0, 0x38}, + {0x0060, 0x24}, {0x0064, 0x77}, + {0x0070, 0x76}, {0x0234, 0xe8}, + {0x0af4, 0x15}, {0x1af4, 0x15}, + {0x081c, 0xe5}, {0x181c, 0xe5}, + {0x099c, 0x48}, {0x199c, 0x48}, + {0x09a4, 0x07}, {0x09a8, 0x22}, + {0x19a4, 0x07}, {0x19a8, 0x22}, + {0x09b8, 0x3e}, {0x19b8, 0x3e}, + {0x09e4, 0x02}, {0x19e4, 0x02}, + {0x0a34, 0x1e}, {0x1a34, 0x1e}, + {0x0a98, 0x2f}, {0x1a98, 0x2f}, + {0x0c30, 0x0e}, {0x0c48, 0x06}, + {0x1c30, 0x0e}, {0x1c48, 0x06}, + {0x028c, 0x18}, {0x0af0, 0x00}, + {0x1af0, 0x00} +}; + +static const struct reg_sequence rk_udphy_init_sequence[] = { + {0x0104, 0x44}, {0x0234, 0xe8}, + {0x0248, 0x44}, {0x028c, 0x18}, + {0x081c, 0xe5}, {0x0878, 0x00}, + {0x0994, 0x1c}, {0x0af0, 0x00}, + {0x181c, 0xe5}, {0x1878, 0x00}, + {0x1994, 0x1c}, {0x1af0, 0x00}, + {0x0428, 0x60}, {0x0d58, 0x33}, + {0x1d58, 0x33}, {0x0990, 0x74}, + {0x0d64, 0x17}, {0x08c8, 0x13}, + {0x1990, 0x74}, {0x1d64, 0x17}, + {0x18c8, 0x13}, {0x0d90, 0x40}, + {0x0da8, 0x40}, {0x0dc0, 0x40}, + {0x0dd8, 0x40}, {0x1d90, 0x40}, + {0x1da8, 0x40}, {0x1dc0, 0x40}, + {0x1dd8, 0x40}, {0x03c0, 0x30}, + {0x03c4, 0x06}, {0x0e10, 0x00}, + {0x1e10, 0x00}, {0x043c, 0x0f}, + {0x0d2c, 0xff}, {0x1d2c, 0xff}, + {0x0d34, 0x0f}, {0x1d34, 0x0f}, + {0x08fc, 0x2a}, {0x0914, 0x28}, + {0x0a30, 0x03}, {0x0e38, 0x03}, + {0x0ecc, 0x27}, {0x0ed0, 0x22}, + {0x0ed4, 0x26}, {0x18fc, 0x2a}, + {0x1914, 0x28}, {0x1a30, 0x03}, + {0x1e38, 0x03}, {0x1ecc, 0x27}, + {0x1ed0, 0x22}, {0x1ed4, 0x26}, + {0x0048, 0x0f}, {0x0060, 0x3c}, + {0x0064, 0xf7}, {0x006c, 0x20}, + {0x0070, 0x7d}, {0x0074, 0x68}, + {0x0af4, 0x1a}, {0x1af4, 0x1a}, + {0x0440, 0x3f}, {0x10d4, 0x08}, + {0x20d4, 0x08}, {0x00d4, 0x30}, + {0x0024, 0x6e}, +}; + +static inline int rk_udphy_grfreg_write(struct regmap *base, + const struct rk_udphy_grf_reg *reg, bool en) +{ + return regmap_write(base, reg->offset, en ? reg->enable : reg->disable); +} + +static int rk_udphy_clk_init(struct rk_udphy *udphy, struct device *dev) +{ + int i; + + udphy->num_clks = devm_clk_bulk_get_all(dev, &udphy->clks); + if (udphy->num_clks < 1) + return -ENODEV; + + /* used for configure phy reference clock frequency */ + for (i = 0; i < udphy->num_clks; i++) { + if (!strncmp(udphy->clks[i].id, "refclk", 6)) { + udphy->refclk = udphy->clks[i].clk; + break; + } + } + + if (!udphy->refclk) + return dev_err_probe(udphy->dev, -EINVAL, "no refclk found\n"); + + return 0; +} + +static int rk_udphy_reset_assert_all(struct rk_udphy *udphy) +{ + return reset_control_bulk_assert(udphy->num_rsts, udphy->rsts); +} + +static int rk_udphy_reset_deassert_all(struct rk_udphy *udphy) +{ + return reset_control_bulk_deassert(udphy->num_rsts, udphy->rsts); +} + +static int rk_udphy_reset_deassert(struct rk_udphy *udphy, char *name) +{ + struct reset_control_bulk_data *list = udphy->rsts; + int idx; + + for (idx = 0; idx < udphy->num_rsts; idx++) { + if (!strcmp(list[idx].id, name)) + return reset_control_deassert(list[idx].rstc); + } + + return -EINVAL; +} + +static int rk_udphy_reset_init(struct rk_udphy *udphy, struct device *dev) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + int idx; + + udphy->num_rsts = cfg->num_rsts; + udphy->rsts = devm_kcalloc(dev, udphy->num_rsts, + sizeof(*udphy->rsts), GFP_KERNEL); + if (!udphy->rsts) + return -ENOMEM; + + for (idx = 0; idx < cfg->num_rsts; idx++) + udphy->rsts[idx].id = cfg->rst_list[idx]; + + return devm_reset_control_bulk_get_exclusive(dev, cfg->num_rsts, + udphy->rsts); +} + +static void rk_udphy_u3_port_disable(struct rk_udphy *udphy, u8 disable) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + const struct rk_udphy_grf_reg *preg; + + preg = udphy->id ? &cfg->grfcfg.usb3otg1_cfg : &cfg->grfcfg.usb3otg0_cfg; + rk_udphy_grfreg_write(udphy->usbgrf, preg, disable); +} + +static void rk_udphy_usb_bvalid_enable(struct rk_udphy *udphy, u8 enable) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + + rk_udphy_grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_phy_con, enable); + rk_udphy_grfreg_write(udphy->u2phygrf, &cfg->grfcfg.bvalid_grf_con, enable); +} + +/* + * In usb/dp combo phy driver, here are 2 ways to mapping lanes. + * + * 1 Type-C Mapping table (DP_Alt_Mode V1.0b remove ABF pin mapping) + * --------------------------------------------------------------------------- + * Type-C Pin B11-B10 A2-A3 A11-A10 B2-B3 + * PHY Pad ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) + * C/E(Normal) dpln3 dpln2 dpln0 dpln1 + * C/E(Flip ) dpln0 dpln1 dpln3 dpln2 + * D/F(Normal) usbrx usbtx dpln0 dpln1 + * D/F(Flip ) dpln0 dpln1 usbrx usbtx + * A(Normal ) dpln3 dpln1 dpln2 dpln0 + * A(Flip ) dpln2 dpln0 dpln3 dpln1 + * B(Normal ) usbrx usbtx dpln1 dpln0 + * B(Flip ) dpln1 dpln0 usbrx usbtx + * --------------------------------------------------------------------------- + * + * 2 Mapping the lanes in dtsi + * if all 4 lane assignment for dp function, define rockchip,dp-lane-mux = <x x x x>; + * sample as follow: + * --------------------------------------------------------------------------- + * B11-B10 A2-A3 A11-A10 B2-B3 + * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) + * <0 1 2 3> dpln0 dpln1 dpln2 dpln3 + * <2 3 0 1> dpln2 dpln3 dpln0 dpln1 + * --------------------------------------------------------------------------- + * if 2 lane for dp function, 2 lane for usb function, define rockchip,dp-lane-mux = <x x>; + * sample as follow: + * --------------------------------------------------------------------------- + * B11-B10 A2-A3 A11-A10 B2-B3 + * rockchip,dp-lane-mux ln0(tx/rx) ln1(tx) ln2(tx/rx) ln3(tx) + * <0 1> dpln0 dpln1 usbrx usbtx + * <2 3> usbrx usbtx dpln0 dpln1 + * --------------------------------------------------------------------------- + */ + +static void rk_udphy_dplane_select(struct rk_udphy *udphy) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + u32 value = 0; + + switch (udphy->mode) { + case UDPHY_MODE_DP: + value |= 2 << udphy->dp_lane_sel[2] * 2; + value |= 3 << udphy->dp_lane_sel[3] * 2; + fallthrough; + + case UDPHY_MODE_DP_USB: + value |= 0 << udphy->dp_lane_sel[0] * 2; + value |= 1 << udphy->dp_lane_sel[1] * 2; + break; + + case UDPHY_MODE_USB: + break; + + default: + break; + } + + regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg, + ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) | + FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) | + FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value); +} + +static int rk_udphy_dplane_get(struct rk_udphy *udphy) +{ + int dp_lanes; + + switch (udphy->mode) { + case UDPHY_MODE_DP: + dp_lanes = 4; + break; + + case UDPHY_MODE_DP_USB: + dp_lanes = 2; + break; + + case UDPHY_MODE_USB: + default: + dp_lanes = 0; + break; + } + + return dp_lanes; +} + +static void rk_udphy_dplane_enable(struct rk_udphy *udphy, int dp_lanes) +{ + u32 val = 0; + int i; + + for (i = 0; i < dp_lanes; i++) + val |= BIT(udphy->dp_lane_sel[i]); + + regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, CMN_DP_LANE_EN_ALL, + FIELD_PREP(CMN_DP_LANE_EN_ALL, val)); + + if (!dp_lanes) + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, + CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); +} + +static void rk_udphy_dp_hpd_event_trigger(struct rk_udphy *udphy, bool hpd) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + + udphy->dp_sink_hpd_sel = true; + udphy->dp_sink_hpd_cfg = hpd; + + if (!udphy->dp_in_use) + return; + + rk_udphy_grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd); +} + +static void rk_udphy_set_typec_default_mapping(struct rk_udphy *udphy) +{ + if (udphy->flip) { + udphy->dp_lane_sel[0] = 0; + udphy->dp_lane_sel[1] = 1; + udphy->dp_lane_sel[2] = 3; + udphy->dp_lane_sel[3] = 2; + udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; + udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_INVERT; + udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_INVERT; + gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 1); + gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0); + } else { + udphy->dp_lane_sel[0] = 2; + udphy->dp_lane_sel[1] = 3; + udphy->dp_lane_sel[2] = 1; + udphy->dp_lane_sel[3] = 0; + udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; + udphy->dp_aux_dout_sel = PHY_AUX_DP_DATA_POL_NORMAL; + udphy->dp_aux_din_sel = PHY_AUX_DP_DATA_POL_NORMAL; + gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0); + gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 1); + } + + udphy->mode = UDPHY_MODE_DP_USB; +} + +static int rk_udphy_orien_sw_set(struct typec_switch_dev *sw, + enum typec_orientation orien) +{ + struct rk_udphy *udphy = typec_switch_get_drvdata(sw); + + mutex_lock(&udphy->mutex); + + if (orien == TYPEC_ORIENTATION_NONE) { + gpiod_set_value_cansleep(udphy->sbu1_dc_gpio, 0); + gpiod_set_value_cansleep(udphy->sbu2_dc_gpio, 0); + /* unattached */ + rk_udphy_usb_bvalid_enable(udphy, false); + goto unlock_ret; + } + + udphy->flip = (orien == TYPEC_ORIENTATION_REVERSE) ? true : false; + rk_udphy_set_typec_default_mapping(udphy); + rk_udphy_usb_bvalid_enable(udphy, true); + +unlock_ret: + mutex_unlock(&udphy->mutex); + return 0; +} + +static void rk_udphy_orien_switch_unregister(void *data) +{ + struct rk_udphy *udphy = data; + + typec_switch_unregister(udphy->sw); +} + +static int rk_udphy_setup_orien_switch(struct rk_udphy *udphy) +{ + struct typec_switch_desc sw_desc = { }; + + sw_desc.drvdata = udphy; + sw_desc.fwnode = dev_fwnode(udphy->dev); + sw_desc.set = rk_udphy_orien_sw_set; + + udphy->sw = typec_switch_register(udphy->dev, &sw_desc); + if (IS_ERR(udphy->sw)) { + dev_err(udphy->dev, "Error register typec orientation switch: %ld\n", + PTR_ERR(udphy->sw)); + return PTR_ERR(udphy->sw); + } + + return devm_add_action_or_reset(udphy->dev, + rk_udphy_orien_switch_unregister, udphy); +} + +static int rk_udphy_refclk_set(struct rk_udphy *udphy) +{ + unsigned long rate; + int ret; + + /* configure phy reference clock */ + rate = clk_get_rate(udphy->refclk); + dev_dbg(udphy->dev, "refclk freq %ld\n", rate); + + switch (rate) { + case 24000000: + ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_24m_refclk_cfg, + ARRAY_SIZE(rk_udphy_24m_refclk_cfg)); + if (ret) + return ret; + break; + + case 26000000: + /* register default is 26MHz */ + ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_26m_refclk_cfg, + ARRAY_SIZE(rk_udphy_26m_refclk_cfg)); + if (ret) + return ret; + break; + + default: + dev_err(udphy->dev, "unsupported refclk freq %ld\n", rate); + return -EINVAL; + } + + return 0; +} + +static int rk_udphy_status_check(struct rk_udphy *udphy) +{ + unsigned int val; + int ret; + + /* LCPLL check */ + if (udphy->mode & UDPHY_MODE_USB) { + ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_LCPLL_DONE_OFFSET, + val, (val & CMN_ANA_LCPLL_AFC_DONE) && + (val & CMN_ANA_LCPLL_LOCK_DONE), 200, 100000); + if (ret) { + dev_err(udphy->dev, "cmn ana lcpll lock timeout\n"); + /* + * If earlier software (U-Boot) enabled USB once already + * the PLL may have problems locking on the first try. + * It will be successful on the second try, so for the + * time being a -EPROBE_DEFER will solve the issue. + * + * This requires further investigation to understand the + * root cause, especially considering that the driver is + * asserting all reset lines at probe time. + */ + return -EPROBE_DEFER; + } + + if (!udphy->flip) { + ret = regmap_read_poll_timeout(udphy->pma_regmap, + TRSV_LN0_MON_RX_CDR_DONE_OFFSET, val, + val & TRSV_LN0_MON_RX_CDR_LOCK_DONE, + 200, 100000); + if (ret) + dev_err(udphy->dev, "trsv ln0 mon rx cdr lock timeout\n"); + } else { + ret = regmap_read_poll_timeout(udphy->pma_regmap, + TRSV_LN2_MON_RX_CDR_DONE_OFFSET, val, + val & TRSV_LN2_MON_RX_CDR_LOCK_DONE, + 200, 100000); + if (ret) + dev_err(udphy->dev, "trsv ln2 mon rx cdr lock timeout\n"); + } + } + + return 0; +} + +static int rk_udphy_init(struct rk_udphy *udphy) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + int ret; + + rk_udphy_reset_assert_all(udphy); + usleep_range(10000, 11000); + + /* enable rx lfps for usb */ + if (udphy->mode & UDPHY_MODE_USB) + rk_udphy_grfreg_write(udphy->udphygrf, &cfg->grfcfg.rx_lfps, true); + + /* Step 1: power on pma and deassert apb rstn */ + rk_udphy_grfreg_write(udphy->udphygrf, &cfg->grfcfg.low_pwrn, true); + + rk_udphy_reset_deassert(udphy, "pma_apb"); + rk_udphy_reset_deassert(udphy, "pcs_apb"); + + /* Step 2: set init sequence and phy refclk */ + ret = regmap_multi_reg_write(udphy->pma_regmap, rk_udphy_init_sequence, + ARRAY_SIZE(rk_udphy_init_sequence)); + if (ret) { + dev_err(udphy->dev, "init sequence set error %d\n", ret); + goto assert_resets; + } + + ret = rk_udphy_refclk_set(udphy); + if (ret) { + dev_err(udphy->dev, "refclk set error %d\n", ret); + goto assert_resets; + } + + /* Step 3: configure lane mux */ + regmap_update_bits(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, + CMN_DP_LANE_MUX_ALL | CMN_DP_LANE_EN_ALL, + FIELD_PREP(CMN_DP_LANE_MUX_N(3), udphy->lane_mux_sel[3]) | + FIELD_PREP(CMN_DP_LANE_MUX_N(2), udphy->lane_mux_sel[2]) | + FIELD_PREP(CMN_DP_LANE_MUX_N(1), udphy->lane_mux_sel[1]) | + FIELD_PREP(CMN_DP_LANE_MUX_N(0), udphy->lane_mux_sel[0]) | + FIELD_PREP(CMN_DP_LANE_EN_ALL, 0)); + + /* Step 4: deassert init rstn and wait for 200ns from datasheet */ + if (udphy->mode & UDPHY_MODE_USB) + rk_udphy_reset_deassert(udphy, "init"); + + if (udphy->mode & UDPHY_MODE_DP) { + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, + CMN_DP_INIT_RSTN, + FIELD_PREP(CMN_DP_INIT_RSTN, 0x1)); + } + + udelay(1); + + /* Step 5: deassert cmn/lane rstn */ + if (udphy->mode & UDPHY_MODE_USB) { + rk_udphy_reset_deassert(udphy, "cmn"); + rk_udphy_reset_deassert(udphy, "lane"); + } + + /* Step 6: wait for lock done of pll */ + ret = rk_udphy_status_check(udphy); + if (ret) + goto assert_resets; + + return 0; + +assert_resets: + rk_udphy_reset_assert_all(udphy); + return ret; +} + +static int rk_udphy_setup(struct rk_udphy *udphy) +{ + int ret; + + ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks); + if (ret) { + dev_err(udphy->dev, "failed to enable clk\n"); + return ret; + } + + ret = rk_udphy_init(udphy); + if (ret) { + dev_err(udphy->dev, "failed to init combophy\n"); + clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks); + return ret; + } + + return 0; +} + +static void rk_udphy_disable(struct rk_udphy *udphy) +{ + clk_bulk_disable_unprepare(udphy->num_clks, udphy->clks); + rk_udphy_reset_assert_all(udphy); +} + +static int rk_udphy_parse_lane_mux_data(struct rk_udphy *udphy) +{ + int ret, i, num_lanes; + + num_lanes = device_property_count_u32(udphy->dev, "rockchip,dp-lane-mux"); + if (num_lanes < 0) { + dev_dbg(udphy->dev, "no dp-lane-mux, following dp alt mode\n"); + udphy->mode = UDPHY_MODE_USB; + return 0; + } + + if (num_lanes != 2 && num_lanes != 4) + return dev_err_probe(udphy->dev, -EINVAL, + "invalid number of lane mux\n"); + + ret = device_property_read_u32_array(udphy->dev, "rockchip,dp-lane-mux", + udphy->dp_lane_sel, num_lanes); + if (ret) + return dev_err_probe(udphy->dev, ret, "get dp lane mux failed\n"); + + for (i = 0; i < num_lanes; i++) { + int j; + + if (udphy->dp_lane_sel[i] > 3) + return dev_err_probe(udphy->dev, -EINVAL, + "lane mux between 0 and 3, exceeding the range\n"); + + udphy->lane_mux_sel[udphy->dp_lane_sel[i]] = PHY_LANE_MUX_DP; + + for (j = i + 1; j < num_lanes; j++) { + if (udphy->dp_lane_sel[i] == udphy->dp_lane_sel[j]) + return dev_err_probe(udphy->dev, -EINVAL, + "set repeat lane mux value\n"); + } + } + + udphy->mode = UDPHY_MODE_DP; + if (num_lanes == 2) { + udphy->mode |= UDPHY_MODE_USB; + udphy->flip = (udphy->lane_mux_sel[0] == PHY_LANE_MUX_DP); + } + + return 0; +} + +static int rk_udphy_get_initial_status(struct rk_udphy *udphy) +{ + int ret; + u32 value; + + ret = clk_bulk_prepare_enable(udphy->num_clks, udphy->clks); + if (ret) { + dev_err(udphy->dev, "failed to enable clk\n"); + return ret; + } + + rk_udphy_reset_deassert_all(udphy); + + regmap_read(udphy->pma_regmap, CMN_LANE_MUX_AND_EN_OFFSET, &value); + if (FIELD_GET(CMN_DP_LANE_MUX_ALL, value) && FIELD_GET(CMN_DP_LANE_EN_ALL, value)) + udphy->status = UDPHY_MODE_DP; + else + rk_udphy_disable(udphy); + + return 0; +} + +static int rk_udphy_parse_dt(struct rk_udphy *udphy) +{ + struct device *dev = udphy->dev; + struct device_node *np = dev_of_node(dev); + enum usb_device_speed maximum_speed; + int ret; + + udphy->u2phygrf = syscon_regmap_lookup_by_phandle(np, "rockchip,u2phy-grf"); + if (IS_ERR(udphy->u2phygrf)) + return dev_err_probe(dev, PTR_ERR(udphy->u2phygrf), "failed to get u2phy-grf\n"); + + udphy->udphygrf = syscon_regmap_lookup_by_phandle(np, "rockchip,usbdpphy-grf"); + if (IS_ERR(udphy->udphygrf)) + return dev_err_probe(dev, PTR_ERR(udphy->udphygrf), "failed to get usbdpphy-grf\n"); + + udphy->usbgrf = syscon_regmap_lookup_by_phandle(np, "rockchip,usb-grf"); + if (IS_ERR(udphy->usbgrf)) + return dev_err_probe(dev, PTR_ERR(udphy->usbgrf), "failed to get usb-grf\n"); + + udphy->vogrf = syscon_regmap_lookup_by_phandle(np, "rockchip,vo-grf"); + if (IS_ERR(udphy->vogrf)) + return dev_err_probe(dev, PTR_ERR(udphy->vogrf), "failed to get vo-grf\n"); + + ret = rk_udphy_parse_lane_mux_data(udphy); + if (ret) + return ret; + + udphy->sbu1_dc_gpio = devm_gpiod_get_optional(dev, "sbu1-dc", GPIOD_OUT_LOW); + if (IS_ERR(udphy->sbu1_dc_gpio)) + return PTR_ERR(udphy->sbu1_dc_gpio); + + udphy->sbu2_dc_gpio = devm_gpiod_get_optional(dev, "sbu2-dc", GPIOD_OUT_LOW); + if (IS_ERR(udphy->sbu2_dc_gpio)) + return PTR_ERR(udphy->sbu2_dc_gpio); + + if (device_property_present(dev, "maximum-speed")) { + maximum_speed = usb_get_maximum_speed(dev); + udphy->hs = maximum_speed <= USB_SPEED_HIGH; + } + + ret = rk_udphy_clk_init(udphy, dev); + if (ret) + return ret; + + return rk_udphy_reset_init(udphy, dev); +} + +static int rk_udphy_power_on(struct rk_udphy *udphy, u8 mode) +{ + int ret; + + if (!(udphy->mode & mode)) { + dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); + return 0; + } + + if (udphy->status == UDPHY_MODE_NONE) { + udphy->mode_change = false; + ret = rk_udphy_setup(udphy); + if (ret) + return ret; + + if (udphy->mode & UDPHY_MODE_USB) + rk_udphy_u3_port_disable(udphy, false); + } else if (udphy->mode_change) { + udphy->mode_change = false; + udphy->status = UDPHY_MODE_NONE; + if (udphy->mode == UDPHY_MODE_DP) + rk_udphy_u3_port_disable(udphy, true); + + rk_udphy_disable(udphy); + ret = rk_udphy_setup(udphy); + if (ret) + return ret; + } + + udphy->status |= mode; + + return 0; +} + +static void rk_udphy_power_off(struct rk_udphy *udphy, u8 mode) +{ + if (!(udphy->mode & mode)) { + dev_info(udphy->dev, "mode 0x%02x is not support\n", mode); + return; + } + + if (!udphy->status) + return; + + udphy->status &= ~mode; + + if (udphy->status == UDPHY_MODE_NONE) + rk_udphy_disable(udphy); +} + +static int rk_udphy_dp_phy_init(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + + mutex_lock(&udphy->mutex); + + udphy->dp_in_use = true; + + mutex_unlock(&udphy->mutex); + + return 0; +} + +static int rk_udphy_dp_phy_exit(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + + mutex_lock(&udphy->mutex); + udphy->dp_in_use = false; + mutex_unlock(&udphy->mutex); + return 0; +} + +static int rk_udphy_dp_phy_power_on(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + int ret, dp_lanes; + + mutex_lock(&udphy->mutex); + + dp_lanes = rk_udphy_dplane_get(udphy); + phy_set_bus_width(phy, dp_lanes); + + ret = rk_udphy_power_on(udphy, UDPHY_MODE_DP); + if (ret) + goto unlock; + + rk_udphy_dplane_enable(udphy, dp_lanes); + + rk_udphy_dplane_select(udphy); + +unlock: + mutex_unlock(&udphy->mutex); + /* + * If data send by aux channel too fast after phy power on, + * the aux may be not ready which will cause aux error. Adding + * delay to avoid this issue. + */ + usleep_range(10000, 11000); + return ret; +} + +static int rk_udphy_dp_phy_power_off(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + + mutex_lock(&udphy->mutex); + rk_udphy_dplane_enable(udphy, 0); + rk_udphy_power_off(udphy, UDPHY_MODE_DP); + mutex_unlock(&udphy->mutex); + + return 0; +} + +/* + * Verify link rate + */ +static int rk_udphy_dp_phy_verify_link_rate(struct rk_udphy *udphy, + struct phy_configure_opts_dp *dp) +{ + switch (dp->link_rate) { + case 1620: + case 2700: + case 5400: + case 8100: + udphy->link_rate = dp->link_rate; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int rk_udphy_dp_phy_verify_lanes(struct rk_udphy *udphy, + struct phy_configure_opts_dp *dp) +{ + switch (dp->lanes) { + case 1: + case 2: + case 4: + /* valid lane count. */ + udphy->lanes = dp->lanes; + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* + * 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; +} + +static void rk_udphy_dp_set_voltage(struct rk_udphy *udphy, u8 bw, + u32 voltage, u32 pre, u32 lane) +{ + const struct rk_udphy_cfg *cfg = udphy->cfgs; + const struct rk_udphy_dp_tx_drv_ctrl (*dp_ctrl)[4]; + u32 offset = 0x800 * lane; + u32 val; + + if (udphy->mux) + dp_ctrl = cfg->dp_tx_ctrl_cfg_typec[bw]; + else + dp_ctrl = cfg->dp_tx_ctrl_cfg[bw]; + + val = dp_ctrl[voltage][pre].trsv_reg0204; + regmap_write(udphy->pma_regmap, 0x0810 + offset, val); + + val = dp_ctrl[voltage][pre].trsv_reg0205; + regmap_write(udphy->pma_regmap, 0x0814 + offset, val); + + val = dp_ctrl[voltage][pre].trsv_reg0206; + regmap_write(udphy->pma_regmap, 0x0818 + offset, val); + + val = dp_ctrl[voltage][pre].trsv_reg0207; + regmap_write(udphy->pma_regmap, 0x081c + offset, val); +} + +static int rk_udphy_dp_phy_configure(struct phy *phy, + union phy_configure_opts *opts) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + struct phy_configure_opts_dp *dp = &opts->dp; + u32 i, val, lane; + int 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, + CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); + + switch (dp->link_rate) { + case 1620: + udphy->bw = DP_BW_RBR; + break; + + case 2700: + udphy->bw = DP_BW_HBR; + break; + + case 5400: + udphy->bw = DP_BW_HBR2; + break; + + case 8100: + udphy->bw = DP_BW_HBR3; + break; + + default: + return -EINVAL; + } + + regmap_update_bits(udphy->pma_regmap, CMN_DP_LINK_OFFSET, CMN_DP_TX_LINK_BW, + FIELD_PREP(CMN_DP_TX_LINK_BW, udphy->bw)); + regmap_update_bits(udphy->pma_regmap, CMN_SSC_EN_OFFSET, CMN_ROPLL_SSC_EN, + FIELD_PREP(CMN_ROPLL_SSC_EN, dp->ssc)); + regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, CMN_DP_CMN_RSTN, + FIELD_PREP(CMN_DP_CMN_RSTN, 0x1)); + + ret = regmap_read_poll_timeout(udphy->pma_regmap, CMN_ANA_ROPLL_DONE_OFFSET, val, + FIELD_GET(CMN_ANA_ROPLL_LOCK_DONE, val) && + FIELD_GET(CMN_ANA_ROPLL_AFC_DONE, val), + 0, 1000); + if (ret) { + dev_err(udphy->dev, "ROPLL is not lock, set_rate failed\n"); + return ret; + } + } + + if (dp->set_voltages) { + for (i = 0; i < udphy->lanes; i++) { + lane = udphy->dp_lane_sel[i]; + switch (udphy->link_rate) { + case 1620: + case 2700: + regmap_update_bits(udphy->pma_regmap, + TRSV_ANA_TX_CLK_OFFSET_N(lane), + LN_ANA_TX_SER_TXCLK_INV, + FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, + udphy->lane_mux_sel[lane])); + break; + + case 5400: + case 8100: + regmap_update_bits(udphy->pma_regmap, + TRSV_ANA_TX_CLK_OFFSET_N(lane), + LN_ANA_TX_SER_TXCLK_INV, + FIELD_PREP(LN_ANA_TX_SER_TXCLK_INV, 0x0)); + break; + } + + rk_udphy_dp_set_voltage(udphy, udphy->bw, dp->voltage[i], + dp->pre[i], lane); + } + } + + return 0; +} + +static const struct phy_ops rk_udphy_dp_phy_ops = { + .init = rk_udphy_dp_phy_init, + .exit = rk_udphy_dp_phy_exit, + .power_on = rk_udphy_dp_phy_power_on, + .power_off = rk_udphy_dp_phy_power_off, + .configure = rk_udphy_dp_phy_configure, + .owner = THIS_MODULE, +}; + +static int rk_udphy_usb3_phy_init(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + int ret = 0; + + mutex_lock(&udphy->mutex); + /* DP only or high-speed, disable U3 port */ + if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) { + rk_udphy_u3_port_disable(udphy, true); + goto unlock; + } + + ret = rk_udphy_power_on(udphy, UDPHY_MODE_USB); + +unlock: + mutex_unlock(&udphy->mutex); + return ret; +} + +static int rk_udphy_usb3_phy_exit(struct phy *phy) +{ + struct rk_udphy *udphy = phy_get_drvdata(phy); + + mutex_lock(&udphy->mutex); + /* DP only or high-speed */ + if (!(udphy->mode & UDPHY_MODE_USB) || udphy->hs) + goto unlock; + + rk_udphy_power_off(udphy, UDPHY_MODE_USB); + +unlock: + mutex_unlock(&udphy->mutex); + return 0; +} + +static const struct phy_ops rk_udphy_usb3_phy_ops = { + .init = rk_udphy_usb3_phy_init, + .exit = rk_udphy_usb3_phy_exit, + .owner = THIS_MODULE, +}; + +static int rk_udphy_typec_mux_set(struct typec_mux_dev *mux, + struct typec_mux_state *state) +{ + struct rk_udphy *udphy = typec_mux_get_drvdata(mux); + u8 mode; + + mutex_lock(&udphy->mutex); + + switch (state->mode) { + case TYPEC_DP_STATE_C: + case TYPEC_DP_STATE_E: + udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; + mode = UDPHY_MODE_DP; + break; + + case TYPEC_DP_STATE_D: + default: + if (udphy->flip) { + udphy->lane_mux_sel[0] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_USB; + } else { + udphy->lane_mux_sel[0] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[1] = PHY_LANE_MUX_USB; + udphy->lane_mux_sel[2] = PHY_LANE_MUX_DP; + udphy->lane_mux_sel[3] = PHY_LANE_MUX_DP; + } + mode = UDPHY_MODE_DP_USB; + break; + } + + if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) { + struct typec_displayport_data *data = state->data; + + if (!data) { + rk_udphy_dp_hpd_event_trigger(udphy, false); + } else if (data->status & DP_STATUS_IRQ_HPD) { + rk_udphy_dp_hpd_event_trigger(udphy, false); + usleep_range(750, 800); + rk_udphy_dp_hpd_event_trigger(udphy, true); + } else if (data->status & DP_STATUS_HPD_STATE) { + if (udphy->mode != mode) { + udphy->mode = mode; + udphy->mode_change = true; + } + rk_udphy_dp_hpd_event_trigger(udphy, true); + } else { + rk_udphy_dp_hpd_event_trigger(udphy, false); + } + } + + mutex_unlock(&udphy->mutex); + return 0; +} + +static void rk_udphy_typec_mux_unregister(void *data) +{ + struct rk_udphy *udphy = data; + + typec_mux_unregister(udphy->mux); +} + +static int rk_udphy_setup_typec_mux(struct rk_udphy *udphy) +{ + struct typec_mux_desc mux_desc = {}; + + mux_desc.drvdata = udphy; + mux_desc.fwnode = dev_fwnode(udphy->dev); + mux_desc.set = rk_udphy_typec_mux_set; + + udphy->mux = typec_mux_register(udphy->dev, &mux_desc); + if (IS_ERR(udphy->mux)) { + dev_err(udphy->dev, "Error register typec mux: %ld\n", + PTR_ERR(udphy->mux)); + return PTR_ERR(udphy->mux); + } + + return devm_add_action_or_reset(udphy->dev, rk_udphy_typec_mux_unregister, + udphy); +} + +static const struct regmap_config rk_udphy_pma_regmap_cfg = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .fast_io = true, + .max_register = 0x20dc, +}; + +static struct phy *rk_udphy_phy_xlate(struct device *dev, const struct of_phandle_args *args) +{ + struct rk_udphy *udphy = dev_get_drvdata(dev); + + if (args->args_count == 0) + return ERR_PTR(-EINVAL); + + switch (args->args[0]) { + case PHY_TYPE_USB3: + return udphy->phy_u3; + case PHY_TYPE_DP: + return udphy->phy_dp; + } + + return ERR_PTR(-EINVAL); +} + +static int rk_udphy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + struct resource *res; + struct rk_udphy *udphy; + void __iomem *base; + int id, ret; + + udphy = devm_kzalloc(dev, sizeof(*udphy), GFP_KERNEL); + if (!udphy) + return -ENOMEM; + + udphy->cfgs = device_get_match_data(dev); + if (!udphy->cfgs) + return dev_err_probe(dev, -EINVAL, "missing match data\n"); + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* find the phy-id from the io address */ + udphy->id = -ENODEV; + for (id = 0; id < udphy->cfgs->num_phys; id++) { + if (res->start == udphy->cfgs->phy_ids[id]) { + udphy->id = id; + break; + } + } + + if (udphy->id < 0) + return dev_err_probe(dev, -ENODEV, "no matching device found\n"); + + udphy->pma_regmap = devm_regmap_init_mmio(dev, base + UDPHY_PMA, + &rk_udphy_pma_regmap_cfg); + if (IS_ERR(udphy->pma_regmap)) + return PTR_ERR(udphy->pma_regmap); + + udphy->dev = dev; + ret = rk_udphy_parse_dt(udphy); + if (ret) + return ret; + + ret = rk_udphy_get_initial_status(udphy); + if (ret) + return ret; + + mutex_init(&udphy->mutex); + platform_set_drvdata(pdev, udphy); + + if (device_property_present(dev, "orientation-switch")) { + ret = rk_udphy_setup_orien_switch(udphy); + if (ret) + return ret; + } + + if (device_property_present(dev, "mode-switch")) { + ret = rk_udphy_setup_typec_mux(udphy); + if (ret) + return ret; + } + + udphy->phy_u3 = devm_phy_create(dev, dev->of_node, &rk_udphy_usb3_phy_ops); + if (IS_ERR(udphy->phy_u3)) { + ret = PTR_ERR(udphy->phy_u3); + return dev_err_probe(dev, ret, "failed to create USB3 phy\n"); + } + phy_set_drvdata(udphy->phy_u3, udphy); + + udphy->phy_dp = devm_phy_create(dev, dev->of_node, &rk_udphy_dp_phy_ops); + if (IS_ERR(udphy->phy_dp)) { + ret = PTR_ERR(udphy->phy_dp); + return dev_err_probe(dev, ret, "failed to create DP phy\n"); + } + phy_set_bus_width(udphy->phy_dp, rk_udphy_dplane_get(udphy)); + udphy->phy_dp->attrs.max_link_rate = 8100; + phy_set_drvdata(udphy->phy_dp, udphy); + + phy_provider = devm_of_phy_provider_register(dev, rk_udphy_phy_xlate); + if (IS_ERR(phy_provider)) { + ret = PTR_ERR(phy_provider); + return dev_err_probe(dev, ret, "failed to register phy provider\n"); + } + + return 0; +} + +static int __maybe_unused rk_udphy_resume(struct device *dev) +{ + struct rk_udphy *udphy = dev_get_drvdata(dev); + + if (udphy->dp_sink_hpd_sel) + rk_udphy_dp_hpd_event_trigger(udphy, udphy->dp_sink_hpd_cfg); + + return 0; +} + +static const struct dev_pm_ops rk_udphy_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, rk_udphy_resume) +}; + +static const char * const rk_udphy_rst_list[] = { + "init", "cmn", "lane", "pcs_apb", "pma_apb" +}; + +static const struct rk_udphy_cfg rk3576_udphy_cfgs = { + .num_phys = 1, + .phy_ids = { 0x2b010000 }, + .num_rsts = ARRAY_SIZE(rk_udphy_rst_list), + .rst_list = rk_udphy_rst_list, + .grfcfg = { + /* u2phy-grf */ + .bvalid_phy_con = RK_UDPHY_GEN_GRF_REG(0x0010, 1, 0, 0x2, 0x3), + .bvalid_grf_con = RK_UDPHY_GEN_GRF_REG(0x0000, 15, 14, 0x1, 0x3), + + /* usb-grf */ + .usb3otg0_cfg = RK_UDPHY_GEN_GRF_REG(0x0030, 15, 0, 0x1100, 0x0188), + + /* usbdpphy-grf */ + .low_pwrn = RK_UDPHY_GEN_GRF_REG(0x0004, 13, 13, 0, 1), + .rx_lfps = RK_UDPHY_GEN_GRF_REG(0x0004, 14, 14, 0, 1), + }, + .vogrfcfg = { + { + .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3), + .dp_lane_reg = 0x0000, + }, + }, + .dp_tx_ctrl_cfg = { + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_hbr2, + rk3588_dp_tx_drv_ctrl_hbr3, + }, + .dp_tx_ctrl_cfg_typec = { + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_hbr2, + rk3588_dp_tx_drv_ctrl_hbr3, + }, +}; + +static const struct rk_udphy_cfg rk3588_udphy_cfgs = { + .num_phys = 2, + .phy_ids = { + 0xfed80000, + 0xfed90000, + }, + .num_rsts = ARRAY_SIZE(rk_udphy_rst_list), + .rst_list = rk_udphy_rst_list, + .grfcfg = { + /* u2phy-grf */ + .bvalid_phy_con = RK_UDPHY_GEN_GRF_REG(0x0008, 1, 0, 0x2, 0x3), + .bvalid_grf_con = RK_UDPHY_GEN_GRF_REG(0x0010, 3, 2, 0x2, 0x3), + + /* usb-grf */ + .usb3otg0_cfg = RK_UDPHY_GEN_GRF_REG(0x001c, 15, 0, 0x1100, 0x0188), + .usb3otg1_cfg = RK_UDPHY_GEN_GRF_REG(0x0034, 15, 0, 0x1100, 0x0188), + + /* usbdpphy-grf */ + .low_pwrn = RK_UDPHY_GEN_GRF_REG(0x0004, 13, 13, 0, 1), + .rx_lfps = RK_UDPHY_GEN_GRF_REG(0x0004, 14, 14, 0, 1), + }, + .vogrfcfg = { + { + .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0000, 11, 10, 1, 3), + .dp_lane_reg = 0x0000, + }, + { + .hpd_trigger = RK_UDPHY_GEN_GRF_REG(0x0008, 11, 10, 1, 3), + .dp_lane_reg = 0x0008, + }, + }, + .dp_tx_ctrl_cfg = { + rk3588_dp_tx_drv_ctrl_rbr_hbr, + rk3588_dp_tx_drv_ctrl_rbr_hbr, + rk3588_dp_tx_drv_ctrl_hbr2, + rk3588_dp_tx_drv_ctrl_hbr3, + }, + .dp_tx_ctrl_cfg_typec = { + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_rbr_hbr_typec, + rk3588_dp_tx_drv_ctrl_hbr2, + rk3588_dp_tx_drv_ctrl_hbr3, + }, +}; + +static const struct of_device_id rk_udphy_dt_match[] = { + { + .compatible = "rockchip,rk3576-usbdp-phy", + .data = &rk3576_udphy_cfgs + }, + { + .compatible = "rockchip,rk3588-usbdp-phy", + .data = &rk3588_udphy_cfgs + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rk_udphy_dt_match); + +static struct platform_driver rk_udphy_driver = { + .probe = rk_udphy_probe, + .driver = { + .name = "rockchip-usbdp-phy", + .of_match_table = rk_udphy_dt_match, + .pm = &rk_udphy_pm_ops, + }, +}; +module_platform_driver(rk_udphy_driver); + +MODULE_AUTHOR("Frank Wang <frank.wang@rock-chips.com>"); +MODULE_AUTHOR("Zhang Yubing <yubing.zhang@rock-chips.com>"); +MODULE_DESCRIPTION("Rockchip USBDP Combo PHY driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/samsung/Kconfig b/drivers/phy/samsung/Kconfig index f10afa3d7ff5..b7ab402909a8 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,10 +81,11 @@ 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 - default y + default ARCH_EXYNOS help Enable USB DRD PHY support for Exynos 5 SoC series. This driver provides PHY interface for USB 3.0 DRD controller diff --git a/drivers/phy/samsung/Makefile b/drivers/phy/samsung/Makefile index afb34a153e34..342682638a87 100644 --- a/drivers/phy/samsung/Makefile +++ b/drivers/phy/samsung/Makefile @@ -3,9 +3,11 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o obj-$(CONFIG_PHY_SAMSUNG_UFS) += phy-exynos-ufs.o +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-exynos-mipi-video.c b/drivers/phy/samsung/phy-exynos-mipi-video.c index 592d8067e848..f6756a609a9a 100644 --- a/drivers/phy/samsung/phy-exynos-mipi-video.c +++ b/drivers/phy/samsung/phy-exynos-mipi-video.c @@ -274,7 +274,7 @@ static int exynos_mipi_video_phy_power_off(struct phy *phy) } static struct phy *exynos_mipi_video_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct exynos_mipi_video_phy *state = dev_get_drvdata(dev); diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index 3f310b28bfff..917a76d584f0 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -8,6 +8,7 @@ * Author: Vivek Gautam <gautam.vivek@samsung.com> */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/io.h> @@ -22,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 @@ -30,59 +33,71 @@ #define EXYNOS5_FSEL_19MHZ2 0x3 #define EXYNOS5_FSEL_20MHZ 0x4 #define EXYNOS5_FSEL_24MHZ 0x5 -#define EXYNOS5_FSEL_26MHZ 0x82 +#define EXYNOS5_FSEL_26MHZ 0x6 #define EXYNOS5_FSEL_50MHZ 0x7 +/* USB 3.2 DRD 4nm PHY link controller registers */ +#define EXYNOS2200_DRD_CLKRST 0x0c +#define EXYNOS2200_CLKRST_LINK_PCLK_SEL BIT(1) + +#define EXYNOS2200_DRD_UTMI 0x10 +#define EXYNOS2200_UTMI_FORCE_VBUSVALID BIT(1) +#define EXYNOS2200_UTMI_FORCE_BVALID BIT(0) + +#define EXYNOS2200_DRD_HSP_MISC 0x114 +#define HSP_MISC_SET_REQ_IN2 BIT(4) +#define HSP_MISC_RES_TUNE GENMASK(1, 0) +#define RES_TUNE_PHY1_PHY2 0x1 +#define RES_TUNE_PHY1 0x2 +#define RES_TUNE_PHY2 0x3 + /* Exynos5: USB 3.0 DRD PHY registers */ #define EXYNOS5_DRD_LINKSYSTEM 0x04 - -#define LINKSYSTEM_FLADJ_MASK (0x3f << 1) -#define LINKSYSTEM_FLADJ(_x) ((_x) << 1) #define LINKSYSTEM_XHCI_VERSION_CONTROL BIT(27) +#define LINKSYSTEM_FORCE_VBUSVALID BIT(8) +#define LINKSYSTEM_FORCE_BVALID BIT(7) +#define LINKSYSTEM_FLADJ GENMASK(6, 1) #define EXYNOS5_DRD_PHYUTMI 0x08 - +#define PHYUTMI_UTMI_SUSPEND_COM_N BIT(12) +#define PHYUTMI_UTMI_L1_SUSPEND_COM_N BIT(11) +#define PHYUTMI_VBUSVLDEXTSEL BIT(10) +#define PHYUTMI_VBUSVLDEXT BIT(9) +#define PHYUTMI_TXBITSTUFFENH BIT(8) +#define PHYUTMI_TXBITSTUFFEN BIT(7) #define PHYUTMI_OTGDISABLE BIT(6) +#define PHYUTMI_IDPULLUP BIT(5) +#define PHYUTMI_DRVVBUS BIT(4) +#define PHYUTMI_DPPULLDOWN BIT(3) +#define PHYUTMI_DMPULLDOWN BIT(2) #define PHYUTMI_FORCESUSPEND BIT(1) #define PHYUTMI_FORCESLEEP BIT(0) #define EXYNOS5_DRD_PHYPIPE 0x0c #define EXYNOS5_DRD_PHYCLKRST 0x10 - #define PHYCLKRST_EN_UTMISUSPEND BIT(31) - -#define PHYCLKRST_SSC_REFCLKSEL_MASK (0xff << 23) -#define PHYCLKRST_SSC_REFCLKSEL(_x) ((_x) << 23) - -#define PHYCLKRST_SSC_RANGE_MASK (0x03 << 21) -#define PHYCLKRST_SSC_RANGE(_x) ((_x) << 21) - +#define PHYCLKRST_SSC_REFCLKSEL GENMASK(30, 23) +#define PHYCLKRST_SSC_RANGE GENMASK(22, 21) #define PHYCLKRST_SSC_EN BIT(20) #define PHYCLKRST_REF_SSP_EN BIT(19) #define PHYCLKRST_REF_CLKDIV2 BIT(18) - -#define PHYCLKRST_MPLL_MULTIPLIER_MASK (0x7f << 11) -#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF (0x19 << 11) -#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF (0x32 << 11) -#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF (0x68 << 11) -#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF (0x7d << 11) -#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF (0x02 << 11) - -#define PHYCLKRST_FSEL_UTMI_MASK (0x7 << 5) -#define PHYCLKRST_FSEL_PIPE_MASK (0x7 << 8) -#define PHYCLKRST_FSEL(_x) ((_x) << 5) -#define PHYCLKRST_FSEL_PAD_100MHZ (0x27 << 5) -#define PHYCLKRST_FSEL_PAD_24MHZ (0x2a << 5) -#define PHYCLKRST_FSEL_PAD_20MHZ (0x31 << 5) -#define PHYCLKRST_FSEL_PAD_19_2MHZ (0x38 << 5) - +#define PHYCLKRST_MPLL_MULTIPLIER GENMASK(17, 11) +#define PHYCLKRST_MPLL_MULTIPLIER_100MHZ_REF 0x19 +#define PHYCLKRST_MPLL_MULTIPLIER_50M_REF 0x32 +#define PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF 0x68 +#define PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF 0x7d +#define PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF 0x02 +#define PHYCLKRST_FSEL_PIPE GENMASK(10, 8) +#define PHYCLKRST_FSEL_UTMI GENMASK(7, 5) +#define PHYCLKRST_FSEL_PAD_100MHZ 0x27 +#define PHYCLKRST_FSEL_PAD_24MHZ 0x2a +#define PHYCLKRST_FSEL_PAD_20MHZ 0x31 +#define PHYCLKRST_FSEL_PAD_19_2MHZ 0x38 #define PHYCLKRST_RETENABLEN BIT(4) - -#define PHYCLKRST_REFCLKSEL_MASK (0x03 << 2) -#define PHYCLKRST_REFCLKSEL_PAD_REFCLK (0x2 << 2) -#define PHYCLKRST_REFCLKSEL_EXT_REFCLK (0x3 << 2) - +#define PHYCLKRST_REFCLKSEL GENMASK(3, 2) +#define PHYCLKRST_REFCLKSEL_PAD_REFCLK 0x2 +#define PHYCLKRST_REFCLKSEL_EXT_REFCLK 0x3 #define PHYCLKRST_PORTRESET BIT(1) #define PHYCLKRST_COMMONONN BIT(0) @@ -91,40 +106,53 @@ #define PHYREG0_SSC_RANGE BIT(20) #define PHYREG0_CR_WRITE BIT(19) #define PHYREG0_CR_READ BIT(18) -#define PHYREG0_CR_DATA_IN(_x) ((_x) << 2) +#define PHYREG0_CR_DATA_IN GENMASK(17, 2) #define PHYREG0_CR_CAP_DATA BIT(1) #define PHYREG0_CR_CAP_ADDR BIT(0) #define EXYNOS5_DRD_PHYREG1 0x18 -#define PHYREG1_CR_DATA_OUT(_x) ((_x) << 1) +#define PHYREG0_CR_DATA_OUT GENMASK(16, 1) #define PHYREG1_CR_ACK BIT(0) #define EXYNOS5_DRD_PHYPARAM0 0x1c - #define PHYPARAM0_REF_USE_PAD BIT(31) -#define PHYPARAM0_REF_LOSLEVEL_MASK (0x1f << 26) -#define PHYPARAM0_REF_LOSLEVEL (0x9 << 26) +#define PHYPARAM0_REF_LOSLEVEL GENMASK(30, 26) +#define PHYPARAM0_REF_LOSLEVEL_VAL 0x9 +#define PHYPARAM0_TXVREFTUNE GENMASK(25, 22) +#define PHYPARAM0_TXRISETUNE GENMASK(21, 20) +#define PHYPARAM0_TXRESTUNE GENMASK(19, 18) +#define PHYPARAM0_TXPREEMPPULSETUNE BIT(17) +#define PHYPARAM0_TXPREEMPAMPTUNE GENMASK(16, 15) +#define PHYPARAM0_TXHSXVTUNE GENMASK(14, 13) +#define PHYPARAM0_TXFSLSTUNE GENMASK(12, 9) +#define PHYPARAM0_SQRXTUNE GENMASK(8, 6) +#define PHYPARAM0_OTGTUNE GENMASK(5, 3) +#define PHYPARAM0_COMPDISTUNE GENMASK(2, 0) #define EXYNOS5_DRD_PHYPARAM1 0x20 - -#define PHYPARAM1_PCS_TXDEEMPH_MASK (0x1f << 0) -#define PHYPARAM1_PCS_TXDEEMPH (0x1c) +#define PHYPARAM1_PCS_TXDEEMPH GENMASK(4, 0) +#define PHYPARAM1_PCS_TXDEEMPH_VAL 0x1c #define EXYNOS5_DRD_PHYTERM 0x24 #define EXYNOS5_DRD_PHYTEST 0x28 - #define PHYTEST_POWERDOWN_SSP BIT(3) #define PHYTEST_POWERDOWN_HSP BIT(2) #define EXYNOS5_DRD_PHYADP 0x2c #define EXYNOS5_DRD_PHYUTMICLKSEL 0x30 - #define PHYUTMICLKSEL_UTMI_CLKSEL BIT(2) #define EXYNOS5_DRD_PHYRESUME 0x34 + #define EXYNOS5_DRD_LINKPORT 0x44 +#define LINKPORT_HOST_U3_PORT_DISABLE BIT(8) +#define LINKPORT_HOST_U2_PORT_DISABLE BIT(7) +#define LINKPORT_HOST_PORT_OVCR_U3 BIT(5) +#define LINKPORT_HOST_PORT_OVCR_U2 BIT(4) +#define LINKPORT_HOST_PORT_OVCR_U3_SEL BIT(3) +#define LINKPORT_HOST_PORT_OVCR_U2_SEL BIT(2) /* USB 3.0 DRD PHY SS Function Control Reg; accessed by CR_PORT */ #define EXYNOS5_DRD_PHYSS_LOSLEVEL_OVRD_IN (0x15) @@ -145,37 +173,239 @@ #define LANE0_TX_DEBUG_RXDET_MEAS_TIME_62M5 (0x20 << 4) #define LANE0_TX_DEBUG_RXDET_MEAS_TIME_96M_100M (0x40 << 4) +/* Exynos7870: USB DRD PHY registers */ +#define EXYNOS7870_DRD_PHYPCSVAL 0x3C +#define PHYPCSVAL_PCS_RX_LOS_MASK GENMASK(9, 0) + +#define EXYNOS7870_DRD_PHYPARAM2 0x50 +#define PHYPARAM2_TX_VBOOST_LVL GENMASK(6, 4) +#define PHYPARAM2_LOS_BIAS GENMASK(2, 0) + +#define EXYNOS7870_DRD_HSPHYCTRL 0x54 +#define HSPHYCTRL_PHYSWRSTALL BIT(31) +#define HSPHYCTRL_SIDDQ BIT(6) +#define HSPHYCTRL_PHYSWRST BIT(0) + +#define EXYNOS7870_DRD_HSPHYPLLTUNE 0x70 +#define HSPHYPLLTUNE_PLL_B_TUNE BIT(6) +#define HSPHYPLLTUNE_PLL_I_TUNE GENMASK(5, 4) +#define HSPHYPLLTUNE_PLL_P_TUNE GENMASK(3, 0) + /* Exynos850: USB DRD PHY registers */ #define EXYNOS850_DRD_LINKCTRL 0x04 -#define LINKCTRL_BUS_FILTER_BYPASS(_x) ((_x) << 4) +#define LINKCTRL_FORCE_RXELECIDLE BIT(18) +#define LINKCTRL_FORCE_PHYSTATUS BIT(17) +#define LINKCTRL_FORCE_PIPE_EN BIT(16) #define LINKCTRL_FORCE_QACT BIT(8) +#define LINKCTRL_BUS_FILTER_BYPASS GENMASK(7, 4) + +#define EXYNOS850_DRD_LINKPORT 0x08 +#define LINKPORT_HOST_NUM_U3 GENMASK(19, 16) +#define LINKPORT_HOST_NUM_U2 GENMASK(15, 12) #define EXYNOS850_DRD_CLKRST 0x20 -#define CLKRST_LINK_SW_RST BIT(0) -#define CLKRST_PORT_RST BIT(1) +/* + * On versions without SS ports (like E850), bit 3 is for the 2.0 phy (HS), + * while on versions with (like gs101), bits 2 and 3 are for the 3.0 phy (SS) + * and bits 12 & 13 for the 2.0 phy. + */ +#define CLKRST_PHY20_SW_POR BIT(13) +#define CLKRST_PHY20_SW_POR_SEL BIT(12) +#define CLKRST_LINK_PCLK_SEL BIT(7) #define CLKRST_PHY_SW_RST BIT(3) +#define CLKRST_PHY_RESET_SEL BIT(2) +#define CLKRST_PORT_RST BIT(1) +#define CLKRST_LINK_SW_RST BIT(0) + +#define EXYNOS850_DRD_SSPPLLCTL 0x30 +#define SSPPLLCTL_FSEL GENMASK(2, 0) #define EXYNOS850_DRD_UTMI 0x50 -#define UTMI_FORCE_SLEEP BIT(0) -#define UTMI_FORCE_SUSPEND BIT(1) -#define UTMI_DM_PULLDOWN BIT(2) -#define UTMI_DP_PULLDOWN BIT(3) -#define UTMI_FORCE_BVALID BIT(4) #define UTMI_FORCE_VBUSVALID BIT(5) +#define UTMI_FORCE_BVALID BIT(4) +#define UTMI_DP_PULLDOWN BIT(3) +#define UTMI_DM_PULLDOWN BIT(2) +#define UTMI_FORCE_SUSPEND BIT(1) +#define UTMI_FORCE_SLEEP BIT(0) #define EXYNOS850_DRD_HSP 0x54 -#define HSP_COMMONONN BIT(8) -#define HSP_EN_UTMISUSPEND BIT(9) -#define HSP_VBUSVLDEXT BIT(12) -#define HSP_VBUSVLDEXTSEL BIT(13) #define HSP_FSV_OUT_EN BIT(24) +#define HSP_VBUSVLDEXTSEL BIT(13) +#define HSP_VBUSVLDEXT BIT(12) +#define HSP_EN_UTMISUSPEND BIT(9) +#define HSP_COMMONONN BIT(8) + +#define EXYNOS850_DRD_HSPPARACON 0x58 +#define HSPPARACON_TXVREF GENMASK(31, 28) +#define HSPPARACON_TXRISE GENMASK(25, 24) +#define HSPPARACON_TXRES GENMASK(22, 21) +#define HSPPARACON_TXPREEMPPULSE BIT(20) +#define HSPPARACON_TXPREEMPAMP GENMASK(19, 18) +#define HSPPARACON_TXHSXV GENMASK(17, 16) +#define HSPPARACON_TXFSLS GENMASK(15, 12) +#define HSPPARACON_SQRX GENMASK(10, 8) +#define HSPPARACON_OTG GENMASK(6, 4) +#define HSPPARACON_COMPDIS GENMASK(2, 0) #define EXYNOS850_DRD_HSP_TEST 0x5c #define HSP_TEST_SIDDQ BIT(24) +/* Exynos9 - GS101 */ +#define EXYNOS850_DRD_SECPMACTL 0x48 +#define SECPMACTL_PMA_ROPLL_REF_CLK_SEL GENMASK(13, 12) +#define SECPMACTL_PMA_LCPLL_REF_CLK_SEL GENMASK(11, 10) +#define SECPMACTL_PMA_REF_FREQ_SEL GENMASK(9, 8) +#define SECPMACTL_PMA_LOW_PWR BIT(4) +#define SECPMACTL_PMA_TRSV_SW_RST BIT(3) +#define SECPMACTL_PMA_CMN_SW_RST BIT(2) +#define SECPMACTL_PMA_INIT_SW_RST BIT(1) +#define SECPMACTL_PMA_APB_SW_RST BIT(0) + +/* PMA registers */ +#define EXYNOS9_PMA_USBDP_CMN_REG0008 0x0020 +#define CMN_REG0008_OVRD_AUX_EN BIT(3) +#define CMN_REG0008_AUX_EN BIT(2) + +#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) +#define CMN_REG01C0_ANA_LCPLL_AFC_DONE BIT(6) + +/* these have similar register layout, for lanes 0 and 2 */ +#define EXYNOS9_PMA_USBDP_TRSV_REG03C3 0x0f0c +#define EXYNOS9_PMA_USBDP_TRSV_REG07C3 0x1f0c +#define TRSV_REG03C3_LN0_MON_RX_CDR_AFC_DONE BIT(3) +#define TRSV_REG03C3_LN0_MON_RX_CDR_CAL_DONE BIT(2) +#define TRSV_REG03C3_LN0_MON_RX_CDR_FLD_PLL_MODE_DONE BIT(1) +#define TRSV_REG03C3_LN0_MON_RX_CDR_LOCK_DONE BIT(0) + +/* TRSV_REG0413 and TRSV_REG0813 have similar register layout */ +#define EXYNOS9_PMA_USBDP_TRSV_REG0413 0x104c +#define TRSV_REG0413_OVRD_LN1_TX_RXD_COMP_EN BIT(7) +#define TRSV_REG0413_OVRD_LN1_TX_RXD_EN BIT(5) + +#define EXYNOS9_PMA_USBDP_TRSV_REG0813 0x204c +#define TRSV_REG0813_OVRD_LN3_TX_RXD_COMP_EN BIT(7) +#define TRSV_REG0813_OVRD_LN3_TX_RXD_EN BIT(5) + +/* PCS registers */ +#define EXYNOS9_PCS_NS_VEC_PS1_N1 0x010c +#define EXYNOS9_PCS_NS_VEC_PS2_N0 0x0110 +#define EXYNOS9_PCS_NS_VEC_PS3_N0 0x0118 +#define NS_VEC_NS_REQ GENMASK(31, 24) +#define NS_VEC_ENABLE_TIMER BIT(22) +#define NS_VEC_SEL_TIMEOUT GENMASK(21, 20) +#define NS_VEC_INV_MASK GENMASK(19, 16) +#define NS_VEC_COND_MASK GENMASK(11, 8) +#define NS_VEC_EXP_COND GENMASK(3, 0) + +#define EXYNOS9_PCS_OUT_VEC_2 0x014c +#define EXYNOS9_PCS_OUT_VEC_3 0x0150 +#define PCS_OUT_VEC_B9_DYNAMIC BIT(19) +#define PCS_OUT_VEC_B9_SEL_OUT BIT(18) +#define PCS_OUT_VEC_B8_DYNAMIC BIT(17) +#define PCS_OUT_VEC_B8_SEL_OUT BIT(16) +#define PCS_OUT_VEC_B7_DYNAMIC BIT(15) +#define PCS_OUT_VEC_B7_SEL_OUT BIT(14) +#define PCS_OUT_VEC_B6_DYNAMIC BIT(13) +#define PCS_OUT_VEC_B6_SEL_OUT BIT(12) +#define PCS_OUT_VEC_B5_DYNAMIC BIT(11) +#define PCS_OUT_VEC_B5_SEL_OUT BIT(10) +#define PCS_OUT_VEC_B4_DYNAMIC BIT(9) +#define PCS_OUT_VEC_B4_SEL_OUT BIT(8) +#define PCS_OUT_VEC_B3_DYNAMIC BIT(7) +#define PCS_OUT_VEC_B3_SEL_OUT BIT(6) +#define PCS_OUT_VEC_B2_DYNAMIC BIT(5) +#define PCS_OUT_VEC_B2_SEL_OUT BIT(4) +#define PCS_OUT_VEC_B1_DYNAMIC BIT(3) +#define PCS_OUT_VEC_B1_SEL_OUT BIT(2) +#define PCS_OUT_VEC_B0_DYNAMIC BIT(1) +#define PCS_OUT_VEC_B0_SEL_OUT BIT(0) + +#define EXYNOS9_PCS_TIMEOUT_0 0x0170 + +#define EXYNOS9_PCS_TIMEOUT_3 0x017c + +#define EXYNOS9_PCS_EBUF_PARAM 0x0304 +#define EBUF_PARAM_SKP_REMOVE_TH_EMPTY_MODE GENMASK(29, 24) + +#define EXYNOS9_PCS_BACK_END_MODE_VEC 0x030c +#define BACK_END_MODE_VEC_FORCE_EBUF_EMPTY_MODE BIT(1) +#define BACK_END_MODE_VEC_DISABLE_DATA_MASK BIT(0) + +#define EXYNOS9_PCS_RX_CONTROL 0x03f0 +#define RX_CONTROL_EN_BLOCK_ALIGNER_TYPE_B BIT(22) + +#define EXYNOS9_PCS_RX_CONTROL_DEBUG 0x03f4 +#define RX_CONTROL_DEBUG_EN_TS_CHECK BIT(5) +#define RX_CONTROL_DEBUG_NUM_COM_FOUND GENMASK(3, 0) + +#define EXYNOS9_PCS_LOCAL_COEF 0x040c +#define LOCAL_COEF_PMA_CENTER_COEF GENMASK(21, 16) +#define LOCAL_COEF_LF GENMASK(13, 8) +#define LOCAL_COEF_FS GENMASK(5, 0) + +#define EXYNOS9_PCS_HS_TX_COEF_MAP_0 0x0410 +#define HS_TX_COEF_MAP_0_SSTX_DEEMP GENMASK(17, 12) +#define HS_TX_COEF_MAP_0_SSTX_LEVEL GENMASK(11, 6) +#define HS_TX_COEF_MAP_0_SSTX_PRE_SHOOT GENMASK(5, 0) + + #define KHZ 1000 #define MHZ (KHZ * KHZ) +#define PHY_TUNING_ENTRY_PHY(o, m, v) { \ + .off = (o), \ + .mask = (m), \ + .val = (v), \ + .region = PTR_PHY \ + } + +#define PHY_TUNING_ENTRY_PCS(o, m, v) { \ + .off = (o), \ + .mask = (m), \ + .val = (v), \ + .region = PTR_PCS \ + } + +#define PHY_TUNING_ENTRY_PMA(o, m, v) { \ + .off = (o), \ + .mask = (m), \ + .val = (v), \ + .region = PTR_PMA, \ + } + +#define PHY_TUNING_ENTRY_LAST { .region = PTR_INVALID } + +#define for_each_phy_tune(tune) \ + for (; (tune)->region != PTR_INVALID; ++(tune)) + +struct exynos5_usbdrd_phy_tuning { + u32 off; + u32 mask; + u32 val; + char region; +#define PTR_INVALID 0 +#define PTR_PHY 1 +#define PTR_PCS 2 +#define PTR_PMA 3 +}; + +enum exynos5_usbdrd_phy_tuning_state { + PTS_UTMI_POSTINIT, + PTS_PIPE3_PREINIT, + PTS_PIPE3_INIT, + PTS_PIPE3_POSTINIT, + PTS_PIPE3_POSTLOCK, + PTS_MAX, +}; + enum exynos5_usbdrd_phy_id { EXYNOS5_DRDPHY_UTMI, EXYNOS5_DRDPHY_PIPE3, @@ -187,45 +417,55 @@ struct exynos5_usbdrd_phy; struct exynos5_usbdrd_phy_config { u32 id; - void (*phy_isol)(struct phy_usb_instance *inst, u32 on); + void (*phy_isol)(struct phy_usb_instance *inst, bool isolate); void (*phy_init)(struct exynos5_usbdrd_phy *phy_drd); unsigned int (*set_refclk)(struct phy_usb_instance *inst); }; struct exynos5_usbdrd_phy_drvdata { const struct exynos5_usbdrd_phy_config *phy_cfg; + const struct exynos5_usbdrd_phy_tuning **phy_tunes; const struct phy_ops *phy_ops; + const char * const *clk_names; + int n_clks; + const char * const *core_clk_names; + int n_core_clks; + const char * const *regulator_names; + int n_regulators; u32 pmu_offset_usbdrd0_phy; + u32 pmu_offset_usbdrd0_phy_ss; u32 pmu_offset_usbdrd1_phy; - bool has_common_clk_gate; }; /** * struct exynos5_usbdrd_phy - driver data for USB 3.0 PHY * @dev: pointer to device instance of this platform device * @reg_phy: usb phy controller register memory base - * @clk: phy clock for register access - * @pipeclk: clock for pipe3 phy - * @utmiclk: clock for utmi+ phy - * @itpclk: clock for ITP generation + * @reg_pcs: usb phy physical coding sublayer register memory base + * @reg_pma: usb phy physical media attachment register memory base + * @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 + * @hs_phy: pointer to non-Samsung IP high-speed phy controller + * @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 - * @ref_clk: reference clock to PHY block from which PHY's - * operational clocks are derived - * @vbus: VBUS regulator for phy - * @vbus_boost: Boost regulator for VBUS present on few Exynos boards + * @regulators: regulators for phy + * @sw: TypeC orientation switch handle + * @orientation: TypeC connector orientation - normal or flipped */ struct exynos5_usbdrd_phy { struct device *dev; void __iomem *reg_phy; - struct clk *clk; - struct clk *pipeclk; - struct clk *utmiclk; - struct clk *itpclk; + void __iomem *reg_pcs; + void __iomem *reg_pma; + struct clk_bulk_data *clks; + struct clk_bulk_data *core_clks; const struct exynos5_usbdrd_phy_drvdata *drv_data; + struct phy *hs_phy; + struct mutex phy_mutex; struct phy_usb_instance { struct phy *phy; u32 index; @@ -234,9 +474,10 @@ struct exynos5_usbdrd_phy { const struct exynos5_usbdrd_phy_config *phy_cfg; } phys[EXYNOS5_DRDPHYS_NUM]; u32 extrefclk; - struct clk *ref_clk; - struct regulator *vbus; - struct regulator *vbus_boost; + struct regulator_bulk_data *regulators; + + struct typec_switch_dev *sw; + enum typec_orientation orientation; }; static inline @@ -287,14 +528,14 @@ static unsigned int exynos5_rate_to_clk(unsigned long rate, u32 *reg) } static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst, - unsigned int on) + bool isolate) { unsigned int val; if (!inst->reg_pmu) return; - val = on ? 0 : EXYNOS4_PHY_ENABLE; + val = isolate ? 0 : EXYNOS4_PHY_ENABLE; regmap_update_bits(inst->reg_pmu, inst->pmu_offset, EXYNOS4_PHY_ENABLE, val); @@ -315,29 +556,33 @@ exynos5_usbdrd_pipe3_set_refclk(struct phy_usb_instance *inst) reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); /* Use EXTREFCLK as ref clock */ - reg &= ~PHYCLKRST_REFCLKSEL_MASK; - reg |= PHYCLKRST_REFCLKSEL_EXT_REFCLK; + reg &= ~PHYCLKRST_REFCLKSEL; + reg |= FIELD_PREP(PHYCLKRST_REFCLKSEL, PHYCLKRST_REFCLKSEL_EXT_REFCLK); /* FSEL settings corresponding to reference clock */ - reg &= ~PHYCLKRST_FSEL_PIPE_MASK | - PHYCLKRST_MPLL_MULTIPLIER_MASK | - PHYCLKRST_SSC_REFCLKSEL_MASK; + reg &= ~(PHYCLKRST_FSEL_PIPE | + PHYCLKRST_MPLL_MULTIPLIER | + PHYCLKRST_SSC_REFCLKSEL); switch (phy_drd->extrefclk) { case EXYNOS5_FSEL_50MHZ: - reg |= (PHYCLKRST_MPLL_MULTIPLIER_50M_REF | - PHYCLKRST_SSC_REFCLKSEL(0x00)); + reg |= (FIELD_PREP(PHYCLKRST_SSC_REFCLKSEL, 0x00) | + FIELD_PREP(PHYCLKRST_MPLL_MULTIPLIER, + PHYCLKRST_MPLL_MULTIPLIER_50M_REF)); break; case EXYNOS5_FSEL_24MHZ: - reg |= (PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF | - PHYCLKRST_SSC_REFCLKSEL(0x88)); + reg |= (FIELD_PREP(PHYCLKRST_SSC_REFCLKSEL, 0x88) | + FIELD_PREP(PHYCLKRST_MPLL_MULTIPLIER, + PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF)); break; case EXYNOS5_FSEL_20MHZ: - reg |= (PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF | - PHYCLKRST_SSC_REFCLKSEL(0x00)); + reg |= (FIELD_PREP(PHYCLKRST_SSC_REFCLKSEL, 0x00) | + FIELD_PREP(PHYCLKRST_MPLL_MULTIPLIER, + PHYCLKRST_MPLL_MULTIPLIER_20MHZ_REF)); break; case EXYNOS5_FSEL_19MHZ2: - reg |= (PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF | - PHYCLKRST_SSC_REFCLKSEL(0x88)); + reg |= (FIELD_PREP(PHYCLKRST_SSC_REFCLKSEL, 0x88) | + FIELD_PREP(PHYCLKRST_MPLL_MULTIPLIER, + PHYCLKRST_MPLL_MULTIPLIER_19200KHZ_REF)); break; default: dev_dbg(phy_drd->dev, "unsupported ref clk\n"); @@ -360,25 +605,64 @@ exynos5_usbdrd_utmi_set_refclk(struct phy_usb_instance *inst) /* restore any previous reference clock settings */ reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); - reg &= ~PHYCLKRST_REFCLKSEL_MASK; - reg |= PHYCLKRST_REFCLKSEL_EXT_REFCLK; + reg &= ~PHYCLKRST_REFCLKSEL; + reg |= FIELD_PREP(PHYCLKRST_REFCLKSEL, PHYCLKRST_REFCLKSEL_EXT_REFCLK); - reg &= ~PHYCLKRST_FSEL_UTMI_MASK | - PHYCLKRST_MPLL_MULTIPLIER_MASK | - PHYCLKRST_SSC_REFCLKSEL_MASK; - reg |= PHYCLKRST_FSEL(phy_drd->extrefclk); + reg &= ~(PHYCLKRST_FSEL_UTMI | + PHYCLKRST_MPLL_MULTIPLIER | + PHYCLKRST_SSC_REFCLKSEL); + reg |= FIELD_PREP(PHYCLKRST_FSEL_UTMI, phy_drd->extrefclk); return reg; } +static void +exynos5_usbdrd_apply_phy_tunes(struct exynos5_usbdrd_phy *phy_drd, + enum exynos5_usbdrd_phy_tuning_state state) +{ + const struct exynos5_usbdrd_phy_tuning *tune; + + tune = phy_drd->drv_data->phy_tunes[state]; + if (!tune) + return; + + for_each_phy_tune(tune) { + void __iomem *reg_base; + u32 reg = 0; + + switch (tune->region) { + case PTR_PHY: + reg_base = phy_drd->reg_phy; + break; + case PTR_PCS: + reg_base = phy_drd->reg_pcs; + break; + case PTR_PMA: + reg_base = phy_drd->reg_pma; + break; + default: + dev_warn_once(phy_drd->dev, + "unknown phy region %d\n", tune->region); + continue; + } + + if (~tune->mask) { + reg = readl(reg_base + tune->off); + reg &= ~tune->mask; + } + reg |= tune->val; + writel(reg, reg_base + tune->off); + } +} + static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd) { u32 reg; reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); /* Set Tx De-Emphasis level */ - reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK; - reg |= PHYPARAM1_PCS_TXDEEMPH; + reg &= ~PHYPARAM1_PCS_TXDEEMPH; + reg |= FIELD_PREP(PHYPARAM1_PCS_TXDEEMPH, PHYPARAM1_PCS_TXDEEMPH_VAL); writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); @@ -386,20 +670,156 @@ static void exynos5_usbdrd_pipe3_init(struct exynos5_usbdrd_phy *phy_drd) writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); } +static void +exynos5_usbdrd_usbdp_g2_v4_ctrl_pma_ready(struct exynos5_usbdrd_phy *phy_drd) +{ + void __iomem *regs_base = phy_drd->reg_phy; + u32 reg; + + /* link pipe_clock selection to pclk of PMA */ + reg = readl(regs_base + EXYNOS850_DRD_CLKRST); + reg |= CLKRST_LINK_PCLK_SEL; + writel(reg, regs_base + EXYNOS850_DRD_CLKRST); + + reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL); + reg &= ~SECPMACTL_PMA_REF_FREQ_SEL; + reg |= FIELD_PREP(SECPMACTL_PMA_REF_FREQ_SEL, 1); + /* SFR reset */ + reg |= (SECPMACTL_PMA_LOW_PWR | SECPMACTL_PMA_APB_SW_RST); + reg &= ~(SECPMACTL_PMA_ROPLL_REF_CLK_SEL | + SECPMACTL_PMA_LCPLL_REF_CLK_SEL); + /* PMA power off */ + reg |= (SECPMACTL_PMA_TRSV_SW_RST | SECPMACTL_PMA_CMN_SW_RST | + SECPMACTL_PMA_INIT_SW_RST); + writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL); + + udelay(1); + + reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL); + reg &= ~SECPMACTL_PMA_LOW_PWR; + writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL); + + udelay(1); + + /* release override */ + reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL); + reg &= ~LINKCTRL_FORCE_PIPE_EN; + writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); + + udelay(1); + + /* APB enable */ + reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL); + reg &= ~SECPMACTL_PMA_APB_SW_RST; + writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL); +} + +static void +exynos5_usbdrd_usbdp_g2_v4_pma_lane_mux_sel(struct exynos5_usbdrd_phy *phy_drd) +{ + void __iomem *regs_base = phy_drd->reg_pma; + u32 reg; + + /* lane configuration: USB on all lanes */ + reg = readl(regs_base + EXYNOS9_PMA_USBDP_CMN_REG00B8); + reg &= ~CMN_REG00B8_LANE_MUX_SEL_DP; + /* + * 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); + 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); + 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); +} + +static int +exynos5_usbdrd_usbdp_g2_v4_pma_check_pll_lock(struct exynos5_usbdrd_phy *phy_drd) +{ + static const unsigned int timeout_us = 40000; + static const unsigned int sleep_us = 40; + static const u32 locked = (CMN_REG01C0_ANA_LCPLL_LOCK_DONE | + CMN_REG01C0_ANA_LCPLL_AFC_DONE); + u32 reg; + int err; + + err = readl_poll_timeout( + phy_drd->reg_pma + EXYNOS9_PMA_USBDP_CMN_REG01C0, + reg, (reg & locked) == locked, sleep_us, timeout_us); + if (err) + dev_err(phy_drd->dev, + "timed out waiting for PLL lock: %#.8x\n", reg); + + return err; +} + +static void +exynos5_usbdrd_usbdp_g2_v4_pma_check_cdr_lock(struct exynos5_usbdrd_phy *phy_drd) +{ + static const unsigned int timeout_us = 40000; + static const unsigned int sleep_us = 40; + static const u32 locked = + (TRSV_REG03C3_LN0_MON_RX_CDR_AFC_DONE + | TRSV_REG03C3_LN0_MON_RX_CDR_CAL_DONE + | TRSV_REG03C3_LN0_MON_RX_CDR_FLD_PLL_MODE_DONE + | TRSV_REG03C3_LN0_MON_RX_CDR_LOCK_DONE); + u32 reg; + int err; + + err = readl_poll_timeout( + /* 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(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) { u32 reg; reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); /* Set Loss-of-Signal Detector sensitivity */ - reg &= ~PHYPARAM0_REF_LOSLEVEL_MASK; - reg |= PHYPARAM0_REF_LOSLEVEL; + reg &= ~PHYPARAM0_REF_LOSLEVEL; + reg |= FIELD_PREP(PHYPARAM0_REF_LOSLEVEL, PHYPARAM0_REF_LOSLEVEL_VAL); writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); /* Set Tx De-Emphasis level */ - reg &= ~PHYPARAM1_PCS_TXDEEMPH_MASK; - reg |= PHYPARAM1_PCS_TXDEEMPH; + reg &= ~PHYPARAM1_PCS_TXDEEMPH; + reg |= FIELD_PREP(PHYPARAM1_PCS_TXDEEMPH, PHYPARAM1_PCS_TXDEEMPH_VAL); writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM1); /* UTMI Power Control */ @@ -417,7 +837,7 @@ static int exynos5_usbdrd_phy_init(struct phy *phy) struct phy_usb_instance *inst = phy_get_drvdata(phy); struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); - ret = clk_prepare_enable(phy_drd->clk); + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); if (ret) return ret; @@ -430,7 +850,7 @@ static int exynos5_usbdrd_phy_init(struct phy *phy) * See xHCI 1.0 spec, 5.2.4 */ reg = LINKSYSTEM_XHCI_VERSION_CONTROL | - LINKSYSTEM_FLADJ(0x20); + FIELD_PREP(LINKSYSTEM_FLADJ, 0x20); writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM); reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYPARAM0); @@ -462,12 +882,12 @@ static int exynos5_usbdrd_phy_init(struct phy *phy) writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); - udelay(10); + fsleep(10); reg &= ~PHYCLKRST_PORTRESET; writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); - clk_disable_unprepare(phy_drd->clk); + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); return 0; } @@ -479,7 +899,7 @@ static int exynos5_usbdrd_phy_exit(struct phy *phy) struct phy_usb_instance *inst = phy_get_drvdata(phy); struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); - ret = clk_prepare_enable(phy_drd->clk); + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); if (ret) return ret; @@ -501,7 +921,7 @@ static int exynos5_usbdrd_phy_exit(struct phy *phy) PHYTEST_POWERDOWN_HSP; writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYTEST); - clk_disable_unprepare(phy_drd->clk); + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); return 0; } @@ -514,47 +934,27 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy) dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n"); - clk_prepare_enable(phy_drd->ref_clk); - if (!phy_drd->drv_data->has_common_clk_gate) { - clk_prepare_enable(phy_drd->pipeclk); - clk_prepare_enable(phy_drd->utmiclk); - clk_prepare_enable(phy_drd->itpclk); - } + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_core_clks, + phy_drd->core_clks); + if (ret) + return ret; /* Enable VBUS supply */ - if (phy_drd->vbus_boost) { - ret = regulator_enable(phy_drd->vbus_boost); - if (ret) { - dev_err(phy_drd->dev, - "Failed to enable VBUS boost supply\n"); - goto fail_vbus; - } - } - - if (phy_drd->vbus) { - ret = regulator_enable(phy_drd->vbus); - if (ret) { - dev_err(phy_drd->dev, "Failed to enable VBUS supply\n"); - goto fail_vbus_boost; - } + ret = regulator_bulk_enable(phy_drd->drv_data->n_regulators, + phy_drd->regulators); + if (ret) { + dev_err(phy_drd->dev, "Failed to enable PHY regulator(s)\n"); + goto fail_vbus; } - /* Power-on PHY*/ - inst->phy_cfg->phy_isol(inst, 0); + /* Power-on PHY */ + inst->phy_cfg->phy_isol(inst, false); return 0; -fail_vbus_boost: - if (phy_drd->vbus_boost) - regulator_disable(phy_drd->vbus_boost); - fail_vbus: - clk_disable_unprepare(phy_drd->ref_clk); - if (!phy_drd->drv_data->has_common_clk_gate) { - clk_disable_unprepare(phy_drd->itpclk); - clk_disable_unprepare(phy_drd->utmiclk); - clk_disable_unprepare(phy_drd->pipeclk); - } + clk_bulk_disable_unprepare(phy_drd->drv_data->n_core_clks, + phy_drd->core_clks); return ret; } @@ -567,20 +967,14 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy) dev_dbg(phy_drd->dev, "Request to power_off usbdrd_phy phy\n"); /* Power-off the PHY */ - inst->phy_cfg->phy_isol(inst, 1); + inst->phy_cfg->phy_isol(inst, true); /* Disable VBUS supply */ - if (phy_drd->vbus) - regulator_disable(phy_drd->vbus); - if (phy_drd->vbus_boost) - regulator_disable(phy_drd->vbus_boost); - - clk_disable_unprepare(phy_drd->ref_clk); - if (!phy_drd->drv_data->has_common_clk_gate) { - clk_disable_unprepare(phy_drd->itpclk); - clk_disable_unprepare(phy_drd->pipeclk); - clk_disable_unprepare(phy_drd->utmiclk); - } + regulator_bulk_disable(phy_drd->drv_data->n_regulators, + phy_drd->regulators); + + clk_bulk_disable_unprepare(phy_drd->drv_data->n_core_clks, + phy_drd->core_clks); return 0; } @@ -615,26 +1009,24 @@ static int crport_handshake(struct exynos5_usbdrd_phy *phy_drd, static int crport_ctrl_write(struct exynos5_usbdrd_phy *phy_drd, u32 addr, u32 data) { + u32 val; int ret; /* Write Address */ - writel(PHYREG0_CR_DATA_IN(addr), - phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); - ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(addr), - PHYREG0_CR_CAP_ADDR); + val = FIELD_PREP(PHYREG0_CR_DATA_IN, addr); + writel(val, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); + ret = crport_handshake(phy_drd, val, PHYREG0_CR_CAP_ADDR); if (ret) return ret; /* Write Data */ - writel(PHYREG0_CR_DATA_IN(data), - phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); - ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data), - PHYREG0_CR_CAP_DATA); + val = FIELD_PREP(PHYREG0_CR_DATA_IN, data); + writel(val, phy_drd->reg_phy + EXYNOS5_DRD_PHYREG0); + ret = crport_handshake(phy_drd, val, PHYREG0_CR_CAP_DATA); if (ret) return ret; - ret = crport_handshake(phy_drd, PHYREG0_CR_DATA_IN(data), - PHYREG0_CR_WRITE); + ret = crport_handshake(phy_drd, val, PHYREG0_CR_WRITE); return ret; } @@ -715,7 +1107,7 @@ static int exynos5420_usbdrd_phy_calibrate(struct exynos5_usbdrd_phy *phy_drd) } static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct exynos5_usbdrd_phy *phy_drd = dev_get_drvdata(dev); @@ -744,10 +1136,338 @@ static const struct phy_ops exynos5_usbdrd_phy_ops = { .owner = THIS_MODULE, }; +static void exynos7870_usbdrd_phy_isol(struct phy_usb_instance *inst, + bool isolate) +{ + unsigned int val; + + if (!inst->reg_pmu) + return; + + val = isolate ? 0 : EXYNOS7870_USB2PHY_ENABLE; + + regmap_update_bits(inst->reg_pmu, inst->pmu_offset, + EXYNOS7870_USB2PHY_ENABLE, val); +} + +static void exynos7870_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) +{ + u32 reg; + + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); + /* Use PADREFCLK as ref clock */ + reg &= ~PHYCLKRST_REFCLKSEL; + reg |= FIELD_PREP(PHYCLKRST_REFCLKSEL, PHYCLKRST_REFCLKSEL_PAD_REFCLK); + /* Select ref clock rate */ + reg &= ~PHYCLKRST_FSEL_UTMI; + reg &= ~PHYCLKRST_FSEL_PIPE; + reg |= FIELD_PREP(PHYCLKRST_FSEL_UTMI, phy_drd->extrefclk); + /* Enable suspend and reset the port */ + reg |= PHYCLKRST_EN_UTMISUSPEND; + reg |= PHYCLKRST_COMMONONN; + reg |= PHYCLKRST_PORTRESET; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); + udelay(10); + + /* Clear the port reset bit */ + reg &= ~PHYCLKRST_PORTRESET; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYCLKRST); + + /* Change PHY PLL tune value */ + reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYPLLTUNE); + if (phy_drd->extrefclk == EXYNOS5_FSEL_24MHZ) + reg |= HSPHYPLLTUNE_PLL_B_TUNE; + else + reg &= ~HSPHYPLLTUNE_PLL_B_TUNE; + reg &= ~HSPHYPLLTUNE_PLL_P_TUNE; + reg |= FIELD_PREP(HSPHYPLLTUNE_PLL_P_TUNE, 14); + writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYPLLTUNE); + + /* High-Speed PHY control */ + reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL); + reg &= ~HSPHYCTRL_SIDDQ; + reg &= ~HSPHYCTRL_PHYSWRST; + reg &= ~HSPHYCTRL_PHYSWRSTALL; + writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL); + udelay(500); + + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM); + /* + * Setting the Frame length Adj value[6:1] to default 0x20 + * See xHCI 1.0 spec, 5.2.4 + */ + reg |= LINKSYSTEM_XHCI_VERSION_CONTROL; + reg &= ~LINKSYSTEM_FLADJ; + reg |= FIELD_PREP(LINKSYSTEM_FLADJ, 0x20); + /* Set VBUSVALID signal as the VBUS pad is not used */ + reg |= LINKSYSTEM_FORCE_BVALID; + reg |= LINKSYSTEM_FORCE_VBUSVALID; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM); + + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI); + /* Release force_sleep & force_suspend */ + reg &= ~PHYUTMI_FORCESLEEP; + reg &= ~PHYUTMI_FORCESUSPEND; + /* DP/DM pull down control */ + reg &= ~PHYUTMI_DMPULLDOWN; + reg &= ~PHYUTMI_DPPULLDOWN; + reg &= ~PHYUTMI_DRVVBUS; + /* Set DP-pull up as the VBUS pad is not used */ + reg |= PHYUTMI_VBUSVLDEXTSEL; + reg |= PHYUTMI_VBUSVLDEXT; + /* Disable OTG block and VBUS valid comparator */ + reg |= PHYUTMI_OTGDISABLE; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI); + + /* Configure OVC IO usage */ + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_LINKPORT); + reg |= LINKPORT_HOST_PORT_OVCR_U3_SEL | LINKPORT_HOST_PORT_OVCR_U2_SEL; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKPORT); + + /* High-Speed PHY swrst */ + reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL); + reg |= HSPHYCTRL_PHYSWRST; + writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL); + udelay(20); + + /* Clear the PHY swrst bit */ + reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL); + reg &= ~HSPHYCTRL_PHYSWRST; + writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL); + + if (phy_drd->drv_data->phy_tunes) + exynos5_usbdrd_apply_phy_tunes(phy_drd, + PTS_UTMI_POSTINIT); +} + +static int exynos7870_usbdrd_phy_init(struct phy *phy) +{ + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + int ret; + + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); + if (ret) + return ret; + + /* UTMI or PIPE3 specific init */ + inst->phy_cfg->phy_init(phy_drd); + + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); + + return 0; +} + +static int exynos7870_usbdrd_phy_exit(struct phy *phy) +{ + int ret; + u32 reg; + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); + if (ret) + return ret; + + /* + * Disable the VBUS signal and the ID pull-up resistor. + * Enable force-suspend and force-sleep modes. + */ + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI); + reg &= ~(PHYUTMI_DRVVBUS | PHYUTMI_VBUSVLDEXT | PHYUTMI_VBUSVLDEXTSEL); + reg &= ~PHYUTMI_IDPULLUP; + reg |= PHYUTMI_FORCESUSPEND | PHYUTMI_FORCESLEEP; + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_PHYUTMI); + + /* Power down PHY analog blocks */ + reg = readl(phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL); + reg |= HSPHYCTRL_SIDDQ; + writel(reg, phy_drd->reg_phy + EXYNOS7870_DRD_HSPHYCTRL); + + /* Clear VBUSVALID signal as the VBUS pad is not used */ + reg = readl(phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM); + reg &= ~(LINKSYSTEM_FORCE_BVALID | LINKSYSTEM_FORCE_VBUSVALID); + writel(reg, phy_drd->reg_phy + EXYNOS5_DRD_LINKSYSTEM); + + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); + + return 0; +} + +static const struct phy_ops exynos7870_usbdrd_phy_ops = { + .init = exynos7870_usbdrd_phy_init, + .exit = exynos7870_usbdrd_phy_exit, + .power_on = exynos5_usbdrd_phy_power_on, + .power_off = exynos5_usbdrd_phy_power_off, + .owner = THIS_MODULE, +}; + +static void exynos2200_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) +{ + /* Configure non-Samsung IP PHY, responsible for UTMI */ + phy_init(phy_drd->hs_phy); +} + +static void exynos2200_usbdrd_link_init(struct exynos5_usbdrd_phy *phy_drd) +{ + void __iomem *regs_base = phy_drd->reg_phy; + u32 reg; + + /* + * Disable HWACG (hardware auto clock gating control). This will force + * QACTIVE signal in Q-Channel interface to HIGH level, to make sure + * the PHY clock is not gated by the hardware. + */ + reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL); + reg |= LINKCTRL_FORCE_QACT; + writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); + + /* De-assert link reset */ + reg = readl(regs_base + EXYNOS2200_DRD_CLKRST); + reg &= ~CLKRST_LINK_SW_RST; + writel(reg, regs_base + EXYNOS2200_DRD_CLKRST); + + /* Set link VBUS Valid */ + reg = readl(regs_base + EXYNOS2200_DRD_UTMI); + reg |= EXYNOS2200_UTMI_FORCE_BVALID | EXYNOS2200_UTMI_FORCE_VBUSVALID; + writel(reg, regs_base + EXYNOS2200_DRD_UTMI); +} + +static void +exynos2200_usbdrd_link_attach_detach_pipe3_phy(struct phy_usb_instance *inst) +{ + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + void __iomem *regs_base = phy_drd->reg_phy; + u32 reg; + + reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL); + if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) { + /* force pipe3 signal for link */ + reg &= ~LINKCTRL_FORCE_PHYSTATUS; + reg |= LINKCTRL_FORCE_PIPE_EN | LINKCTRL_FORCE_RXELECIDLE; + } else { + /* disable forcing pipe interface */ + reg &= ~LINKCTRL_FORCE_PIPE_EN; + } + writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); + + reg = readl(regs_base + EXYNOS2200_DRD_HSP_MISC); + if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) { + /* calibrate only eUSB phy */ + reg |= FIELD_PREP(HSP_MISC_RES_TUNE, RES_TUNE_PHY1); + reg |= HSP_MISC_SET_REQ_IN2; + } else { + /* calibrate for dual phy */ + reg |= FIELD_PREP(HSP_MISC_RES_TUNE, RES_TUNE_PHY1_PHY2); + reg &= ~HSP_MISC_SET_REQ_IN2; + } + writel(reg, regs_base + EXYNOS2200_DRD_HSP_MISC); + + reg = readl(regs_base + EXYNOS2200_DRD_CLKRST); + if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) + reg &= ~EXYNOS2200_CLKRST_LINK_PCLK_SEL; + else + reg |= EXYNOS2200_CLKRST_LINK_PCLK_SEL; + + writel(reg, regs_base + EXYNOS2200_DRD_CLKRST); +} + +static int exynos2200_usbdrd_phy_init(struct phy *phy) +{ + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + int ret; + + if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) { + /* Power-on PHY ... */ + ret = regulator_bulk_enable(phy_drd->drv_data->n_regulators, + phy_drd->regulators); + if (ret) { + dev_err(phy_drd->dev, + "Failed to enable PHY regulator(s)\n"); + return ret; + } + } + /* + * ... and ungate power via PMU. Without this here, we get an SError + * trying to access PMA registers + */ + exynos5_usbdrd_phy_isol(inst, false); + + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); + if (ret) + return ret; + + /* Set up the link controller */ + exynos2200_usbdrd_link_init(phy_drd); + + /* UTMI or PIPE3 link preparation */ + exynos2200_usbdrd_link_attach_detach_pipe3_phy(inst); + + /* UTMI or PIPE3 specific init */ + inst->phy_cfg->phy_init(phy_drd); + + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); + + return 0; +} + +static int exynos2200_usbdrd_phy_exit(struct phy *phy) +{ + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + void __iomem *regs_base = phy_drd->reg_phy; + u32 reg; + int ret; + + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); + if (ret) + return ret; + + reg = readl(regs_base + EXYNOS2200_DRD_UTMI); + reg &= ~(EXYNOS2200_UTMI_FORCE_BVALID | EXYNOS2200_UTMI_FORCE_VBUSVALID); + writel(reg, regs_base + EXYNOS2200_DRD_UTMI); + + reg = readl(regs_base + EXYNOS2200_DRD_CLKRST); + reg |= CLKRST_LINK_SW_RST; + writel(reg, regs_base + EXYNOS2200_DRD_CLKRST); + + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); + + exynos5_usbdrd_phy_isol(inst, true); + return regulator_bulk_disable(phy_drd->drv_data->n_regulators, + phy_drd->regulators); +} + +static const struct phy_ops exynos2200_usbdrd_phy_ops = { + .init = exynos2200_usbdrd_phy_init, + .exit = exynos2200_usbdrd_phy_exit, + .owner = THIS_MODULE, +}; + +static void +exynos5_usbdrd_usb_v3p1_pipe_override(struct exynos5_usbdrd_phy *phy_drd) +{ + void __iomem *regs_base = phy_drd->reg_phy; + u32 reg; + + /* force pipe3 signal for link */ + reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL); + reg &= ~LINKCTRL_FORCE_PHYSTATUS; + reg |= LINKCTRL_FORCE_PIPE_EN | LINKCTRL_FORCE_RXELECIDLE; + writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); + + /* PMA disable */ + reg = readl(regs_base + EXYNOS850_DRD_SECPMACTL); + reg |= SECPMACTL_PMA_LOW_PWR; + writel(reg, regs_base + EXYNOS850_DRD_SECPMACTL); +} + static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) { void __iomem *regs_base = phy_drd->reg_phy; u32 reg; + u32 ss_ports; /* * Disable HWACG (hardware auto clock gating control). This will force @@ -758,8 +1478,16 @@ static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) reg |= LINKCTRL_FORCE_QACT; writel(reg, regs_base + EXYNOS850_DRD_LINKCTRL); + reg = readl(regs_base + EXYNOS850_DRD_LINKPORT); + ss_ports = FIELD_GET(LINKPORT_HOST_NUM_U3, reg); + /* Start PHY Reset (POR=high) */ reg = readl(regs_base + EXYNOS850_DRD_CLKRST); + if (ss_ports) { + reg |= CLKRST_PHY20_SW_POR; + reg |= CLKRST_PHY20_SW_POR_SEL; + reg |= CLKRST_PHY_RESET_SEL; + } reg |= CLKRST_PHY_SW_RST; writel(reg, regs_base + EXYNOS850_DRD_CLKRST); @@ -776,16 +1504,47 @@ static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) /* Set VBUS Valid and D+ pull-up control by VBUS pad usage */ reg = readl(regs_base + EXYNOS850_DRD_LINKCTRL); - reg |= LINKCTRL_BUS_FILTER_BYPASS(0xf); + reg |= FIELD_PREP(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; + switch (phy_drd->extrefclk) { + case EXYNOS5_FSEL_50MHZ: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 7); + break; + case EXYNOS5_FSEL_26MHZ: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 6); + break; + case EXYNOS5_FSEL_24MHZ: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 2); + break; + case EXYNOS5_FSEL_20MHZ: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 1); + break; + case EXYNOS5_FSEL_19MHZ2: + reg |= FIELD_PREP(SSPPLLCTL_FSEL, 0); + break; + default: + dev_warn(phy_drd->dev, "unsupported ref clk: %#.2x\n", + phy_drd->extrefclk); + break; + } + writel(reg, regs_base + EXYNOS850_DRD_SSPPLLCTL); + + if (phy_drd->drv_data->phy_tunes) + exynos5_usbdrd_apply_phy_tunes(phy_drd, + PTS_UTMI_POSTINIT); /* Power up PHY analog blocks */ reg = readl(regs_base + EXYNOS850_DRD_HSP_TEST); @@ -793,16 +1552,23 @@ static void exynos850_usbdrd_utmi_init(struct exynos5_usbdrd_phy *phy_drd) writel(reg, regs_base + EXYNOS850_DRD_HSP_TEST); /* Finish PHY reset (POR=low) */ - udelay(10); /* required before doing POR=low */ + fsleep(10); /* required before doing POR=low */ reg = readl(regs_base + EXYNOS850_DRD_CLKRST); + if (ss_ports) { + reg |= CLKRST_PHY20_SW_POR_SEL; + reg &= ~CLKRST_PHY20_SW_POR; + } reg &= ~(CLKRST_PHY_SW_RST | CLKRST_PORT_RST); writel(reg, regs_base + EXYNOS850_DRD_CLKRST); - udelay(75); /* required after POR=low for guaranteed PHY clock */ + fsleep(75); /* required after POR=low for guaranteed PHY clock */ /* Disable single ended signal out */ reg = readl(regs_base + EXYNOS850_DRD_HSP); reg &= ~HSP_FSV_OUT_EN; writel(reg, regs_base + EXYNOS850_DRD_HSP); + + if (ss_ports) + exynos5_usbdrd_usb_v3p1_pipe_override(phy_drd); } static int exynos850_usbdrd_phy_init(struct phy *phy) @@ -811,14 +1577,15 @@ static int exynos850_usbdrd_phy_init(struct phy *phy) struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); int ret; - ret = clk_prepare_enable(phy_drd->clk); + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); if (ret) 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_disable_unprepare(phy_drd->clk); + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); return 0; } @@ -831,10 +1598,12 @@ static int exynos850_usbdrd_phy_exit(struct phy *phy) u32 reg; int ret; - ret = clk_prepare_enable(phy_drd->clk); + ret = clk_bulk_prepare_enable(phy_drd->drv_data->n_clks, phy_drd->clks); 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); @@ -850,11 +1619,11 @@ static int exynos850_usbdrd_phy_exit(struct phy *phy) reg = readl(regs_base + EXYNOS850_DRD_CLKRST); reg |= CLKRST_LINK_SW_RST; writel(reg, regs_base + EXYNOS850_DRD_CLKRST); - udelay(10); /* required before doing POR=low */ + fsleep(10); /* required before doing POR=low */ reg &= ~CLKRST_LINK_SW_RST; writel(reg, regs_base + EXYNOS850_DRD_CLKRST); - clk_disable_unprepare(phy_drd->clk); + clk_bulk_disable_unprepare(phy_drd->drv_data->n_clks, phy_drd->clks); return 0; } @@ -867,52 +1636,231 @@ static const struct phy_ops exynos850_usbdrd_phy_ops = { .owner = THIS_MODULE, }; -static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd) +static void exynos5_usbdrd_gs101_pipe3_init(struct exynos5_usbdrd_phy *phy_drd) { - unsigned long ref_rate; + void __iomem *regs_pma = phy_drd->reg_pma; + void __iomem *regs_phy = phy_drd->reg_phy; + u32 reg; + + exynos5_usbdrd_usbdp_g2_v4_ctrl_pma_ready(phy_drd); + + /* force aux off */ + reg = readl(regs_pma + EXYNOS9_PMA_USBDP_CMN_REG0008); + reg &= ~CMN_REG0008_AUX_EN; + reg |= CMN_REG0008_OVRD_AUX_EN; + writel(reg, regs_pma + EXYNOS9_PMA_USBDP_CMN_REG0008); + + exynos5_usbdrd_apply_phy_tunes(phy_drd, PTS_PIPE3_PREINIT); + exynos5_usbdrd_apply_phy_tunes(phy_drd, PTS_PIPE3_INIT); + exynos5_usbdrd_apply_phy_tunes(phy_drd, PTS_PIPE3_POSTINIT); + + exynos5_usbdrd_usbdp_g2_v4_pma_lane_mux_sel(phy_drd); + + /* reset release from port */ + reg = readl(regs_phy + EXYNOS850_DRD_SECPMACTL); + reg &= ~(SECPMACTL_PMA_TRSV_SW_RST | SECPMACTL_PMA_CMN_SW_RST | + SECPMACTL_PMA_INIT_SW_RST); + writel(reg, regs_phy + EXYNOS850_DRD_SECPMACTL); + + if (!exynos5_usbdrd_usbdp_g2_v4_pma_check_pll_lock(phy_drd)) + exynos5_usbdrd_usbdp_g2_v4_pma_check_cdr_lock(phy_drd); +} + +static int exynos5_usbdrd_gs101_phy_init(struct phy *phy) +{ + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); int ret; - phy_drd->clk = devm_clk_get(phy_drd->dev, "phy"); - if (IS_ERR(phy_drd->clk)) { - dev_err(phy_drd->dev, "Failed to get phy clock\n"); - return PTR_ERR(phy_drd->clk); + if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) { + /* Power-on PHY ... */ + ret = regulator_bulk_enable(phy_drd->drv_data->n_regulators, + phy_drd->regulators); + if (ret) { + dev_err(phy_drd->dev, + "Failed to enable PHY regulator(s)\n"); + return ret; + } } + /* + * ... and ungate power via PMU. Without this here, we get an SError + * trying to access PMA registers + */ + exynos5_usbdrd_phy_isol(inst, false); + + return exynos850_usbdrd_phy_init(phy); +} - phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref"); - if (IS_ERR(phy_drd->ref_clk)) { - dev_err(phy_drd->dev, "Failed to get phy reference clock\n"); - return PTR_ERR(phy_drd->ref_clk); +static int exynos5_usbdrd_gs101_phy_exit(struct phy *phy) +{ + struct phy_usb_instance *inst = phy_get_drvdata(phy); + struct exynos5_usbdrd_phy *phy_drd = to_usbdrd_phy(inst); + int ret; + + if (inst->phy_cfg->id == EXYNOS5_DRDPHY_UTMI) { + ret = exynos850_usbdrd_phy_exit(phy); + if (ret) + return ret; } - ref_rate = clk_get_rate(phy_drd->ref_clk); - ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); + exynos5_usbdrd_phy_isol(inst, true); + + if (inst->phy_cfg->id != EXYNOS5_DRDPHY_UTMI) + return 0; + + return regulator_bulk_disable(phy_drd->drv_data->n_regulators, + phy_drd->regulators); +} + +static const struct phy_ops gs101_usbdrd_phy_ops = { + .init = exynos5_usbdrd_gs101_phy_init, + .exit = exynos5_usbdrd_gs101_phy_exit, + .owner = THIS_MODULE, +}; + +static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd) +{ + int ret; + struct clk *ref_clk; + unsigned long ref_rate; + + phy_drd->clks = devm_kcalloc(phy_drd->dev, phy_drd->drv_data->n_clks, + sizeof(*phy_drd->clks), GFP_KERNEL); + if (!phy_drd->clks) + return -ENOMEM; + + for (int i = 0; i < phy_drd->drv_data->n_clks; ++i) + phy_drd->clks[i].id = phy_drd->drv_data->clk_names[i]; + + ret = devm_clk_bulk_get(phy_drd->dev, phy_drd->drv_data->n_clks, + phy_drd->clks); + if (ret) + return dev_err_probe(phy_drd->dev, ret, + "failed to get phy clock(s)\n"); + + phy_drd->core_clks = devm_kcalloc(phy_drd->dev, + phy_drd->drv_data->n_core_clks, + sizeof(*phy_drd->core_clks), + GFP_KERNEL); + if (!phy_drd->core_clks) + return -ENOMEM; + + for (int i = 0; i < phy_drd->drv_data->n_core_clks; ++i) + phy_drd->core_clks[i].id = phy_drd->drv_data->core_clk_names[i]; + + ret = devm_clk_bulk_get(phy_drd->dev, phy_drd->drv_data->n_core_clks, + phy_drd->core_clks); + if (ret) + return dev_err_probe(phy_drd->dev, ret, + "failed to get phy core clock(s)\n"); + + if (phy_drd->drv_data->n_core_clks) { + ref_clk = NULL; + for (int i = 0; i < phy_drd->drv_data->n_core_clks; ++i) { + if (!strcmp(phy_drd->core_clks[i].id, "ref")) { + ref_clk = phy_drd->core_clks[i].clk; + break; + } + } + if (!ref_clk) + return dev_err_probe(phy_drd->dev, -ENODEV, + "failed to find phy reference clock\n"); + + ref_rate = clk_get_rate(ref_clk); + ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk); + if (ret) + return dev_err_probe(phy_drd->dev, ret, + "clock rate (%ld) not supported\n", + ref_rate); + } + + return 0; +} + +static const struct exynos5_usbdrd_phy_config phy_cfg_exynos2200[] = { + { + .id = EXYNOS5_DRDPHY_UTMI, + .phy_isol = exynos5_usbdrd_phy_isol, + .phy_init = exynos2200_usbdrd_utmi_init, + }, +}; + +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, "Clock rate (%ld) not supported\n", - ref_rate); + dev_err(phy_drd->dev, "Failed to enable PHY clocks(s)\n"); return ret; } - if (!phy_drd->drv_data->has_common_clk_gate) { - phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe"); - if (IS_ERR(phy_drd->pipeclk)) { - dev_info(phy_drd->dev, - "PIPE3 phy operational clock not specified\n"); - phy_drd->pipeclk = NULL; + 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->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi"); - if (IS_ERR(phy_drd->utmiclk)) { - dev_info(phy_drd->dev, - "UTMI phy operational clock not specified\n"); - phy_drd->utmiclk = NULL; - } + phy_drd->orientation = orientation; + } - phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp"); - if (IS_ERR(phy_drd->itpclk)) { - dev_info(phy_drd->dev, - "ITP clock from main OSC not specified\n"); - phy_drd->itpclk = NULL; - } + 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; @@ -933,6 +1881,14 @@ static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = { }, }; +static const struct exynos5_usbdrd_phy_config phy_cfg_exynos7870[] = { + { + .id = EXYNOS5_DRDPHY_UTMI, + .phy_isol = exynos7870_usbdrd_phy_isol, + .phy_init = exynos7870_usbdrd_utmi_init, + }, +}; + static const struct exynos5_usbdrd_phy_config phy_cfg_exynos850[] = { { .id = EXYNOS5_DRDPHY_UTMI, @@ -941,19 +1897,82 @@ static const struct exynos5_usbdrd_phy_config phy_cfg_exynos850[] = { }, }; +static +const struct exynos5_usbdrd_phy_tuning exynos7870_tunes_utmi_postinit[] = { + PHY_TUNING_ENTRY_PHY(EXYNOS5_DRD_PHYPARAM0, + (PHYPARAM0_TXVREFTUNE | PHYPARAM0_TXRISETUNE | + PHYPARAM0_TXRESTUNE | PHYPARAM0_TXPREEMPPULSETUNE | + PHYPARAM0_TXPREEMPAMPTUNE | PHYPARAM0_TXHSXVTUNE | + PHYPARAM0_TXFSLSTUNE | PHYPARAM0_SQRXTUNE | + PHYPARAM0_OTGTUNE | PHYPARAM0_COMPDISTUNE), + (FIELD_PREP_CONST(PHYPARAM0_TXVREFTUNE, 14) | + FIELD_PREP_CONST(PHYPARAM0_TXRISETUNE, 1) | + FIELD_PREP_CONST(PHYPARAM0_TXRESTUNE, 3) | + FIELD_PREP_CONST(PHYPARAM0_TXPREEMPAMPTUNE, 0) | + FIELD_PREP_CONST(PHYPARAM0_TXHSXVTUNE, 0) | + FIELD_PREP_CONST(PHYPARAM0_TXFSLSTUNE, 3) | + FIELD_PREP_CONST(PHYPARAM0_SQRXTUNE, 6) | + FIELD_PREP_CONST(PHYPARAM0_OTGTUNE, 2) | + FIELD_PREP_CONST(PHYPARAM0_COMPDISTUNE, 3))), + PHY_TUNING_ENTRY_LAST +}; + +static const struct exynos5_usbdrd_phy_tuning *exynos7870_tunes[PTS_MAX] = { + [PTS_UTMI_POSTINIT] = exynos7870_tunes_utmi_postinit, +}; + +static const char * const exynos5_clk_names[] = { + "phy", +}; + +static const char * const exynos5_core_clk_names[] = { + "ref", +}; + +static const char * const exynos5433_core_clk_names[] = { + "ref", "phy_pipe", "phy_utmi", "itp", +}; + +static const char * const exynos5_regulator_names[] = { + "vbus", "vbus-boost", +}; + +static const struct exynos5_usbdrd_phy_drvdata exynos2200_usb32drd_phy = { + .phy_cfg = phy_cfg_exynos2200, + .phy_ops = &exynos2200_usbdrd_phy_ops, + .pmu_offset_usbdrd0_phy = EXYNOS2200_PHY_CTRL_USB20, + .clk_names = exynos5_clk_names, + .n_clks = ARRAY_SIZE(exynos5_clk_names), + /* clocks and regulators are specific to the underlying PHY blocks */ + .core_clk_names = NULL, + .n_core_clks = 0, + .regulator_names = NULL, + .n_regulators = 0, +}; + static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .phy_ops = &exynos5_usbdrd_phy_ops, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, .pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL, - .has_common_clk_gate = true, + .clk_names = exynos5_clk_names, + .n_clks = ARRAY_SIZE(exynos5_clk_names), + .core_clk_names = exynos5_core_clk_names, + .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names), + .regulator_names = exynos5_regulator_names, + .n_regulators = ARRAY_SIZE(exynos5_regulator_names), }; static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .phy_ops = &exynos5_usbdrd_phy_ops, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, - .has_common_clk_gate = true, + .clk_names = exynos5_clk_names, + .n_clks = ARRAY_SIZE(exynos5_clk_names), + .core_clk_names = exynos5_core_clk_names, + .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names), + .regulator_names = exynos5_regulator_names, + .n_regulators = ARRAY_SIZE(exynos5_regulator_names), }; static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = { @@ -961,25 +1980,237 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5433_usbdrd_phy = { .phy_ops = &exynos5_usbdrd_phy_ops, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, .pmu_offset_usbdrd1_phy = EXYNOS5433_USBHOST30_PHY_CONTROL, - .has_common_clk_gate = false, + .clk_names = exynos5_clk_names, + .n_clks = ARRAY_SIZE(exynos5_clk_names), + .core_clk_names = exynos5433_core_clk_names, + .n_core_clks = ARRAY_SIZE(exynos5433_core_clk_names), + .regulator_names = exynos5_regulator_names, + .n_regulators = ARRAY_SIZE(exynos5_regulator_names), }; static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = { .phy_cfg = phy_cfg_exynos5, .phy_ops = &exynos5_usbdrd_phy_ops, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, - .has_common_clk_gate = false, + .clk_names = exynos5_clk_names, + .n_clks = ARRAY_SIZE(exynos5_clk_names), + .core_clk_names = exynos5433_core_clk_names, + .n_core_clks = ARRAY_SIZE(exynos5433_core_clk_names), + .regulator_names = exynos5_regulator_names, + .n_regulators = ARRAY_SIZE(exynos5_regulator_names), +}; + +static const struct exynos5_usbdrd_phy_drvdata exynos7870_usbdrd_phy = { + .phy_cfg = phy_cfg_exynos7870, + .phy_tunes = exynos7870_tunes, + .phy_ops = &exynos7870_usbdrd_phy_ops, + .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, + .clk_names = exynos5_clk_names, + .n_clks = ARRAY_SIZE(exynos5_clk_names), + .core_clk_names = exynos5_core_clk_names, + .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names), + .regulator_names = exynos5_regulator_names, + .n_regulators = ARRAY_SIZE(exynos5_regulator_names), }; static const struct exynos5_usbdrd_phy_drvdata exynos850_usbdrd_phy = { .phy_cfg = phy_cfg_exynos850, .phy_ops = &exynos850_usbdrd_phy_ops, .pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL, - .has_common_clk_gate = true, + .clk_names = exynos5_clk_names, + .n_clks = ARRAY_SIZE(exynos5_clk_names), + .core_clk_names = exynos5_core_clk_names, + .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names), + .regulator_names = exynos5_regulator_names, + .n_regulators = ARRAY_SIZE(exynos5_regulator_names), +}; + +static const struct exynos5_usbdrd_phy_config phy_cfg_gs101[] = { + { + .id = EXYNOS5_DRDPHY_UTMI, + .phy_isol = exynos5_usbdrd_phy_isol, + .phy_init = exynos850_usbdrd_utmi_init, + }, + { + .id = EXYNOS5_DRDPHY_PIPE3, + .phy_isol = exynos5_usbdrd_phy_isol, + .phy_init = exynos5_usbdrd_gs101_pipe3_init, + }, +}; + +static const struct exynos5_usbdrd_phy_tuning gs101_tunes_utmi_postinit[] = { + PHY_TUNING_ENTRY_PHY(EXYNOS850_DRD_HSPPARACON, + (HSPPARACON_TXVREF | HSPPARACON_TXRES | + HSPPARACON_TXPREEMPAMP | HSPPARACON_SQRX | + HSPPARACON_COMPDIS), + (FIELD_PREP_CONST(HSPPARACON_TXVREF, 6) | + FIELD_PREP_CONST(HSPPARACON_TXRES, 1) | + FIELD_PREP_CONST(HSPPARACON_TXPREEMPAMP, 3) | + FIELD_PREP_CONST(HSPPARACON_SQRX, 5) | + FIELD_PREP_CONST(HSPPARACON_COMPDIS, 7))), + PHY_TUNING_ENTRY_LAST +}; + +static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_preinit[] = { + /* preinit */ + /* CDR data mode exit GEN1 ON / GEN2 OFF */ + PHY_TUNING_ENTRY_PMA(0x0c8c, -1, 0xff), + PHY_TUNING_ENTRY_PMA(0x1c8c, -1, 0xff), + PHY_TUNING_ENTRY_PMA(0x0c9c, -1, 0x7d), + PHY_TUNING_ENTRY_PMA(0x1c9c, -1, 0x7d), + /* improve EDS distribution */ + PHY_TUNING_ENTRY_PMA(0x0e7c, -1, 0x06), + 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(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), + /* LFPS RX VIH shmoo hole */ + PHY_TUNING_ENTRY_PMA(0x0a08, -1, 0x0c), + PHY_TUNING_ENTRY_PMA(0x1a08, -1, 0x0c), + /* remove unrelated option for v4 phy */ + PHY_TUNING_ENTRY_PMA(0x0a0c, -1, 0x05), + PHY_TUNING_ENTRY_PMA(0x1a0c, -1, 0x05), + /* improve Gen2 LVCC */ + PHY_TUNING_ENTRY_PMA(0x00f8, -1, 0x1c), + PHY_TUNING_ENTRY_PMA(0x00fc, -1, 0x54), + /* Change Vth of RCV_DET because of TD 7.40 Polling Retry Test */ + PHY_TUNING_ENTRY_PMA(0x104c, -1, 0x07), + PHY_TUNING_ENTRY_PMA(0x204c, -1, 0x07), + /* reduce Ux Exit time, assuming 26MHz clock */ + /* Gen1 */ + PHY_TUNING_ENTRY_PMA(0x0ca8, -1, 0x00), + PHY_TUNING_ENTRY_PMA(0x0cac, -1, 0x04), + PHY_TUNING_ENTRY_PMA(0x1ca8, -1, 0x00), + PHY_TUNING_ENTRY_PMA(0x1cac, -1, 0x04), + /* Gen2 */ + PHY_TUNING_ENTRY_PMA(0x0cb8, -1, 0x00), + PHY_TUNING_ENTRY_PMA(0x0cbc, -1, 0x04), + PHY_TUNING_ENTRY_PMA(0x1cb8, -1, 0x00), + PHY_TUNING_ENTRY_PMA(0x1cbc, -1, 0x04), + /* RX impedance setting */ + PHY_TUNING_ENTRY_PMA(0x0bb0, 0x03, 0x01), + PHY_TUNING_ENTRY_PMA(0x0bb4, 0xf0, 0xa0), + PHY_TUNING_ENTRY_PMA(0x1bb0, 0x03, 0x01), + PHY_TUNING_ENTRY_PMA(0x1bb4, 0xf0, 0xa0), + + PHY_TUNING_ENTRY_LAST +}; + +static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_init[] = { + /* init */ + /* abnormal common pattern mask */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_BACK_END_MODE_VEC, + BACK_END_MODE_VEC_DISABLE_DATA_MASK, 0), + /* de-serializer enabled when U2 */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_OUT_VEC_2, PCS_OUT_VEC_B4_DYNAMIC, + PCS_OUT_VEC_B4_SEL_OUT), + /* TX Keeper Disable, Squelch on when U3 */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_OUT_VEC_3, PCS_OUT_VEC_B7_DYNAMIC, + PCS_OUT_VEC_B7_SEL_OUT | PCS_OUT_VEC_B2_SEL_OUT), + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_NS_VEC_PS1_N1, -1, + (FIELD_PREP_CONST(NS_VEC_NS_REQ, 5) | + NS_VEC_ENABLE_TIMER | + FIELD_PREP_CONST(NS_VEC_SEL_TIMEOUT, 3))), + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_NS_VEC_PS2_N0, -1, + (FIELD_PREP_CONST(NS_VEC_NS_REQ, 1) | + NS_VEC_ENABLE_TIMER | + FIELD_PREP_CONST(NS_VEC_SEL_TIMEOUT, 3) | + FIELD_PREP_CONST(NS_VEC_COND_MASK, 2) | + FIELD_PREP_CONST(NS_VEC_EXP_COND, 2))), + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_NS_VEC_PS3_N0, -1, + (FIELD_PREP_CONST(NS_VEC_NS_REQ, 1) | + NS_VEC_ENABLE_TIMER | + FIELD_PREP_CONST(NS_VEC_SEL_TIMEOUT, 3) | + FIELD_PREP_CONST(NS_VEC_COND_MASK, 7) | + FIELD_PREP_CONST(NS_VEC_EXP_COND, 7))), + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_TIMEOUT_0, -1, 112), + /* Block Aligner Type B */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_RX_CONTROL, 0, + RX_CONTROL_EN_BLOCK_ALIGNER_TYPE_B), + /* Block align at TS1/TS2 for Gen2 stability (Gen2 only) */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_RX_CONTROL_DEBUG, + RX_CONTROL_DEBUG_NUM_COM_FOUND, + (RX_CONTROL_DEBUG_EN_TS_CHECK | + /* + * increase pcs ts1 adding packet-cnt 1 --> 4 + * lnx_rx_valid_rstn_delay_rise_sp/ssp : + * 19.6us(0x200) -> 15.3us(0x4) + */ + FIELD_PREP_CONST(RX_CONTROL_DEBUG_NUM_COM_FOUND, 4))), + /* Gen1 Tx DRIVER pre-shoot, de-emphasis, level ctrl */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_HS_TX_COEF_MAP_0, + (HS_TX_COEF_MAP_0_SSTX_DEEMP | HS_TX_COEF_MAP_0_SSTX_LEVEL | + HS_TX_COEF_MAP_0_SSTX_PRE_SHOOT), + (FIELD_PREP_CONST(HS_TX_COEF_MAP_0_SSTX_DEEMP, 8) | + FIELD_PREP_CONST(HS_TX_COEF_MAP_0_SSTX_LEVEL, 0xb) | + FIELD_PREP_CONST(HS_TX_COEF_MAP_0_SSTX_PRE_SHOOT, 0))), + /* Gen2 Tx DRIVER level ctrl */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_LOCAL_COEF, + LOCAL_COEF_PMA_CENTER_COEF, + FIELD_PREP_CONST(LOCAL_COEF_PMA_CENTER_COEF, 0xb)), + /* Gen2 U1 exit LFPS duration : 900ns ~ 1.2us */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_TIMEOUT_3, -1, 4096), + /* set skp_remove_th 0x2 -> 0x7 for avoiding retry problem. */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_EBUF_PARAM, + EBUF_PARAM_SKP_REMOVE_TH_EMPTY_MODE, + FIELD_PREP_CONST(EBUF_PARAM_SKP_REMOVE_TH_EMPTY_MODE, 0x7)), + + PHY_TUNING_ENTRY_LAST +}; + +static const struct exynos5_usbdrd_phy_tuning gs101_tunes_pipe3_postlock[] = { + /* Squelch off when U3 */ + PHY_TUNING_ENTRY_PCS(EXYNOS9_PCS_OUT_VEC_3, PCS_OUT_VEC_B2_SEL_OUT, 0), + + PHY_TUNING_ENTRY_LAST +}; + +static const struct exynos5_usbdrd_phy_tuning *gs101_tunes[PTS_MAX] = { + [PTS_UTMI_POSTINIT] = gs101_tunes_utmi_postinit, + [PTS_PIPE3_PREINIT] = gs101_tunes_pipe3_preinit, + [PTS_PIPE3_INIT] = gs101_tunes_pipe3_init, + [PTS_PIPE3_POSTLOCK] = gs101_tunes_pipe3_postlock, +}; + +static const char * const gs101_clk_names[] = { + "phy", "ctrl_aclk", "ctrl_pclk", "scl_pclk", +}; + +static const char * const gs101_regulator_names[] = { + "pll", + "dvdd-usb20", "vddh-usb20", "vdd33-usb20", + "vdda-usbdp", "vddh-usbdp", +}; + +static const struct exynos5_usbdrd_phy_drvdata gs101_usbd31rd_phy = { + .phy_cfg = phy_cfg_gs101, + .phy_tunes = gs101_tunes, + .phy_ops = &gs101_usbdrd_phy_ops, + .pmu_offset_usbdrd0_phy = GS101_PHY_CTRL_USB20, + .pmu_offset_usbdrd0_phy_ss = GS101_PHY_CTRL_USBDP, + .clk_names = gs101_clk_names, + .n_clks = ARRAY_SIZE(gs101_clk_names), + .core_clk_names = exynos5_core_clk_names, + .n_core_clks = ARRAY_SIZE(exynos5_core_clk_names), + .regulator_names = gs101_regulator_names, + .n_regulators = ARRAY_SIZE(gs101_regulator_names), }; static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { { + .compatible = "google,gs101-usb31drd-phy", + .data = &gs101_usbd31rd_phy + }, { + .compatible = "samsung,exynos2200-usb32drd-phy", + .data = &exynos2200_usb32drd_phy, + }, { .compatible = "samsung,exynos5250-usbdrd-phy", .data = &exynos5250_usbdrd_phy }, { @@ -992,6 +2223,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = { .compatible = "samsung,exynos7-usbdrd-phy", .data = &exynos7_usbdrd_phy }, { + .compatible = "samsung,exynos7870-usbdrd-phy", + .data = &exynos7870_usbdrd_phy + }, { .compatible = "samsung,exynos850-usbdrd-phy", .data = &exynos850_usbdrd_phy }, @@ -1018,28 +2252,59 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) dev_set_drvdata(dev, phy_drd); phy_drd->dev = dev; - phy_drd->reg_phy = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(phy_drd->reg_phy)) - return PTR_ERR(phy_drd->reg_phy); - drv_data = of_device_get_match_data(dev); if (!drv_data) return -EINVAL; - phy_drd->drv_data = drv_data; - ret = exynos5_usbdrd_phy_clk_handle(phy_drd); - if (ret) { - dev_err(dev, "Failed to initialize clocks\n"); + 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; + + reg = devm_platform_ioremap_resource_byname(pdev, "phy"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + phy_drd->reg_phy = reg; + + reg = devm_platform_ioremap_resource_byname(pdev, "pcs"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + phy_drd->reg_pcs = reg; + + reg = devm_platform_ioremap_resource_byname(pdev, "pma"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + phy_drd->reg_pma = reg; + } else { + /* DTB with just a single region */ + phy_drd->reg_phy = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy_drd->reg_phy)) + return PTR_ERR(phy_drd->reg_phy); + } + + /* + * USB32DRD 4nm controller implements Synopsys eUSB2.0 PHY + * and Synopsys SS/USBDP COMBOPHY, managed by external code. + */ + if (of_property_present(dev->of_node, "phy-names")) { + phy_drd->hs_phy = devm_of_phy_get(dev, dev->of_node, "hs"); + if (IS_ERR(phy_drd->hs_phy)) + return dev_err_probe(dev, PTR_ERR(phy_drd->hs_phy), + "failed to get hs_phy\n"); } + ret = exynos5_usbdrd_phy_clk_handle(phy_drd); + if (ret) + return ret; + 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 @@ -1050,50 +2315,49 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev) if (channel < 0) dev_dbg(dev, "Not a multi-controller usbdrd phy\n"); - switch (channel) { - case 1: - pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd1_phy; - break; - case 0: - default: - pmu_offset = phy_drd->drv_data->pmu_offset_usbdrd0_phy; - break; - } - - /* Get Vbus regulators */ - phy_drd->vbus = devm_regulator_get(dev, "vbus"); - if (IS_ERR(phy_drd->vbus)) { - ret = PTR_ERR(phy_drd->vbus); - if (ret == -EPROBE_DEFER) - return ret; - - dev_warn(dev, "Failed to get VBUS supply regulator\n"); - phy_drd->vbus = NULL; - } - - phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost"); - if (IS_ERR(phy_drd->vbus_boost)) { - ret = PTR_ERR(phy_drd->vbus_boost); - if (ret == -EPROBE_DEFER) - return ret; + /* Get regulators */ + phy_drd->regulators = devm_kcalloc(dev, + drv_data->n_regulators, + sizeof(*phy_drd->regulators), + GFP_KERNEL); + if (!phy_drd->regulators) + return -ENOMEM; + regulator_bulk_set_supply_names(phy_drd->regulators, + drv_data->regulator_names, + drv_data->n_regulators); + ret = devm_regulator_bulk_get(dev, drv_data->n_regulators, + phy_drd->regulators); + if (ret) + return dev_err_probe(dev, ret, "failed to get regulators\n"); - dev_warn(dev, "Failed to get VBUS boost supply regulator\n"); - phy_drd->vbus_boost = NULL; - } + 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; phy_drd->phys[i].reg_pmu = reg_pmu; + switch (channel) { + case 1: + pmu_offset = drv_data->pmu_offset_usbdrd1_phy; + break; + case 0: + default: + pmu_offset = drv_data->pmu_offset_usbdrd0_phy; + if (i == EXYNOS5_DRDPHY_PIPE3 && drv_data + ->pmu_offset_usbdrd0_phy_ss) + pmu_offset = drv_data->pmu_offset_usbdrd0_phy_ss; + break; + } phy_drd->phys[i].pmu_offset = pmu_offset; phy_drd->phys[i].phy_cfg = &drv_data->phy_cfg[i]; phy_set_drvdata(phy, &phy_drd->phys[i]); @@ -1101,10 +2365,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-exynos5250-usb2.c b/drivers/phy/samsung/phy-exynos5250-usb2.c index e198010e1bfd..21b06072f866 100644 --- a/drivers/phy/samsung/phy-exynos5250-usb2.c +++ b/drivers/phy/samsung/phy-exynos5250-usb2.c @@ -121,7 +121,7 @@ #define EXYNOS_5420_USB_ISOL_HOST_OFFSET 0x70C #define EXYNOS_5250_USB_ISOL_ENABLE BIT(0) -/* Mode swtich register */ +/* Mode switch register */ #define EXYNOS_5250_MODE_SWITCH_OFFSET 0x230 #define EXYNOS_5250_MODE_SWITCH_MASK 1 #define EXYNOS_5250_MODE_SWITCH_DEVICE 0 diff --git a/drivers/phy/samsung/phy-exynos7-ufs.c b/drivers/phy/samsung/phy-exynos7-ufs.c index a982e7c128c5..15eec1d9e0e0 100644 --- a/drivers/phy/samsung/phy-exynos7-ufs.c +++ b/drivers/phy/samsung/phy-exynos7-ufs.c @@ -82,4 +82,5 @@ const struct samsung_ufs_phy_drvdata exynos7_ufs_phy = { .clk_list = exynos7_ufs_phy_clks, .num_clks = ARRAY_SIZE(exynos7_ufs_phy_clks), .cdr_lock_status_offset = EXYNOS7_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS, + .wait_for_cdr = samsung_ufs_phy_wait_for_lock_acq, }; diff --git a/drivers/phy/samsung/phy-exynosautov9-ufs.c b/drivers/phy/samsung/phy-exynosautov9-ufs.c index 49e2bcbef0b4..9c3e030f07ba 100644 --- a/drivers/phy/samsung/phy-exynosautov9-ufs.c +++ b/drivers/phy/samsung/phy-exynosautov9-ufs.c @@ -71,4 +71,5 @@ const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy = { .clk_list = exynosautov9_ufs_phy_clks, .num_clks = ARRAY_SIZE(exynosautov9_ufs_phy_clks), .cdr_lock_status_offset = EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS, + .wait_for_cdr = samsung_ufs_phy_wait_for_lock_acq, }; 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-fsd-ufs.c b/drivers/phy/samsung/phy-fsd-ufs.c index d36cabd53434..f2361746db0e 100644 --- a/drivers/phy/samsung/phy-fsd-ufs.c +++ b/drivers/phy/samsung/phy-fsd-ufs.c @@ -60,4 +60,5 @@ const struct samsung_ufs_phy_drvdata fsd_ufs_phy = { .clk_list = fsd_ufs_phy_clks, .num_clks = ARRAY_SIZE(fsd_ufs_phy_clks), .cdr_lock_status_offset = FSD_EMBEDDED_COMBO_PHY_CDR_LOCK_STATUS, + .wait_for_cdr = samsung_ufs_phy_wait_for_lock_acq, }; diff --git a/drivers/phy/samsung/phy-gs101-ufs.c b/drivers/phy/samsung/phy-gs101-ufs.c new file mode 100644 index 000000000000..17b798da5b57 --- /dev/null +++ b/drivers/phy/samsung/phy-gs101-ufs.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UFS PHY driver data for Google Tensor gs101 SoC + * + * Copyright (C) 2024 Linaro Ltd + * Author: Peter Griffin <peter.griffin@linaro.org> + */ + +#include "phy-samsung-ufs.h" + +#define TENSOR_GS101_PHY_CTRL 0x3ec8 +#define TENSOR_GS101_PHY_CTRL_MASK 0x1 +#define TENSOR_GS101_PHY_CTRL_EN BIT(0) +#define PHY_GS101_LANE_OFFSET 0x200 +#define TRSV_REG338 0x338 +#define LN0_MON_RX_CAL_DONE BIT(3) +#define TRSV_REG339 0x339 +#define LN0_MON_RX_CDR_FLD_CK_MODE_DONE BIT(3) +#define TRSV_REG222 0x222 +#define LN0_OVRD_RX_CDR_EN BIT(4) +#define LN0_RX_CDR_EN BIT(3) + +#define PHY_PMA_TRSV_ADDR(reg, lane) (PHY_APB_ADDR((reg) + \ + ((lane) * PHY_GS101_LANE_OFFSET))) + +#define PHY_TRSV_REG_CFG_GS101(o, v, d) \ + PHY_TRSV_REG_CFG_OFFSET(o, v, d, PHY_GS101_LANE_OFFSET) + +/* Calibration for phy initialization */ +static const struct samsung_ufs_phy_cfg tensor_gs101_pre_init_cfg[] = { + 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_TRSV_REG_CFG_GS101(0x200, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x201, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x202, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x203, 0x0a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x204, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x205, 0x11, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x207, 0x0c, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2E1, 0xc0, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x22D, 0xb8, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x234, 0x60, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x238, 0x13, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x239, 0x48, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23A, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23B, 0x25, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23C, 0x2a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23D, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23E, 0x13, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x23F, 0x13, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x240, 0x4a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x243, 0x40, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x244, 0x02, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x25D, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x25E, 0x3f, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x25F, 0xff, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x273, 0x33, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x274, 0x50, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x284, 0x02, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x285, 0x02, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2A2, 0x04, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x25D, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2FA, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x286, 0x03, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x287, 0x03, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x288, 0x03, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x289, 0x03, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B3, 0x04, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B6, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B7, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B8, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2B9, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2BA, 0x0b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2BB, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2BC, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2BD, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x29E, 0x06, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2E4, 0x1a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2ED, 0x25, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x269, 0x1a, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x2F4, 0x2f, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34B, 0x01, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34C, 0x23, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34D, 0x23, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34E, 0x45, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x34F, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x350, 0x31, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x351, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x352, 0x02, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x353, 0x00, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(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, +}; + +static const struct samsung_ufs_phy_cfg tensor_gs101_pre_pwr_hs_config[] = { + PHY_TRSV_REG_CFG_GS101(0x369, 0x11, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_GS101(0x246, 0x03, PWR_MODE_ANY), +}; + +/* Calibration for HS mode series A/B */ +static const struct samsung_ufs_phy_cfg tensor_gs101_post_pwr_hs_config[] = { + PHY_COMN_REG_CFG(0x8, 0x60, PWR_MODE_PWM_ANY), + PHY_TRSV_REG_CFG_GS101(0x222, 0x08, PWR_MODE_PWM_ANY), + PHY_TRSV_REG_CFG_GS101(0x246, 0x01, PWR_MODE_ANY), + END_UFS_PHY_CFG, +}; + +static const struct samsung_ufs_phy_cfg *tensor_gs101_ufs_phy_cfgs[CFG_TAG_MAX] = { + [CFG_PRE_INIT] = tensor_gs101_pre_init_cfg, + [CFG_PRE_PWR_HS] = tensor_gs101_pre_pwr_hs_config, + [CFG_POST_PWR_HS] = tensor_gs101_post_pwr_hs_config, +}; + +static const char * const tensor_gs101_ufs_phy_clks[] = { + "ref_clk", +}; + +static int gs101_phy_wait_for_calibration(struct phy *phy, u8 lane) +{ + struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy); + const unsigned int timeout_us = 40000; + const unsigned int sleep_us = 40; + u32 val; + u32 off; + int err; + + off = PHY_PMA_TRSV_ADDR(TRSV_REG338, lane); + + err = readl_poll_timeout(ufs_phy->reg_pma + off, + val, (val & LN0_MON_RX_CAL_DONE), + sleep_us, timeout_us); + + if (err) { + dev_err(ufs_phy->dev, + "failed to get phy cal done %d\n", err); + } + + return err; +} + +#define DELAY_IN_US 40 +#define RETRY_CNT 100 +static int gs101_phy_wait_for_cdr_lock(struct phy *phy, u8 lane) +{ + struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy); + u32 val; + int i; + + for (i = 0; i < RETRY_CNT; i++) { + udelay(DELAY_IN_US); + val = readl(ufs_phy->reg_pma + + PHY_PMA_TRSV_ADDR(TRSV_REG339, lane)); + + if (val & LN0_MON_RX_CDR_FLD_CK_MODE_DONE) + return 0; + + udelay(DELAY_IN_US); + /* Override and enable clock data recovery */ + writel(LN0_OVRD_RX_CDR_EN, ufs_phy->reg_pma + + PHY_PMA_TRSV_ADDR(TRSV_REG222, lane)); + writel(LN0_OVRD_RX_CDR_EN | LN0_RX_CDR_EN, + ufs_phy->reg_pma + PHY_PMA_TRSV_ADDR(TRSV_REG222, lane)); + } + dev_err(ufs_phy->dev, "failed to get cdr lock\n"); + return -ETIMEDOUT; +} + +const struct samsung_ufs_phy_drvdata tensor_gs101_ufs_phy = { + .cfgs = tensor_gs101_ufs_phy_cfgs, + .isol = { + .offset = TENSOR_GS101_PHY_CTRL, + .mask = TENSOR_GS101_PHY_CTRL_MASK, + .en = TENSOR_GS101_PHY_CTRL_EN, + }, + .clk_list = tensor_gs101_ufs_phy_clks, + .num_clks = ARRAY_SIZE(tensor_gs101_ufs_phy_clks), + .wait_for_cal = gs101_phy_wait_for_calibration, + .wait_for_cdr = gs101_phy_wait_for_cdr_lock, +}; diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c index 183c88e3d1ec..f3cbe6b17b23 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.c +++ b/drivers/phy/samsung/phy-samsung-ufs.c @@ -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 */ @@ -45,7 +45,7 @@ static void samsung_ufs_phy_config(struct samsung_ufs_phy *phy, } } -static int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy) +int samsung_ufs_phy_wait_for_lock_acq(struct phy *phy, u8 lane) { struct samsung_ufs_phy *ufs_phy = get_samsung_ufs_phy(phy); const unsigned int timeout_us = 100000; @@ -97,8 +97,21 @@ static int samsung_ufs_phy_calibrate(struct phy *phy) } } - if (ufs_phy->ufs_phy_state == CFG_POST_PWR_HS) - err = samsung_ufs_phy_wait_for_lock_acq(phy); + for_each_phy_lane(ufs_phy, i) { + if (ufs_phy->ufs_phy_state == CFG_PRE_INIT && + ufs_phy->drvdata->wait_for_cal) { + err = ufs_phy->drvdata->wait_for_cal(phy, i); + if (err) + goto out; + } + + if (ufs_phy->ufs_phy_state == CFG_POST_PWR_HS && + ufs_phy->drvdata->wait_for_cdr) { + err = ufs_phy->drvdata->wait_for_cdr(phy, i); + if (err) + goto out; + } + } /** * In Samsung ufshci, PHY need to be calibrated at different @@ -255,8 +268,8 @@ static int samsung_ufs_phy_probe(struct platform_device *pdev) goto out; } - phy->reg_pmu = syscon_regmap_lookup_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"); @@ -302,12 +315,18 @@ out: static const struct of_device_id samsung_ufs_phy_match[] = { { + .compatible = "google,gs101-ufs-phy", + .data = &tensor_gs101_ufs_phy, + }, { .compatible = "samsung,exynos7-ufs-phy", .data = &exynos7_ufs_phy, }, { .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 e122960cfee8..a28f148081d1 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.h +++ b/drivers/phy/samsung/phy-samsung-ufs.h @@ -112,6 +112,9 @@ struct samsung_ufs_phy_drvdata { const char * const *clk_list; int num_clks; u32 cdr_lock_status_offset; + /* SoC's specific operations */ + int (*wait_for_cal)(struct phy *phy, u8 lane); + int (*wait_for_cdr)(struct phy *phy, u8 lane); }; struct samsung_ufs_phy { @@ -139,8 +142,15 @@ static inline void samsung_ufs_phy_ctrl_isol( phy->isol.mask, isol ? 0 : phy->isol.en); } +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; #endif /* _PHY_SAMSUNG_UFS_ */ diff --git a/drivers/phy/samsung/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c index 68a174eca0ba..9de744cd6f39 100644 --- a/drivers/phy/samsung/phy-samsung-usb2.c +++ b/drivers/phy/samsung/phy-samsung-usb2.c @@ -87,7 +87,7 @@ static const struct phy_ops samsung_usb2_phy_ops = { }; static struct phy *samsung_usb2_phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct samsung_usb2_phy_driver *drv; diff --git a/drivers/phy/socionext/phy-uniphier-usb2.c b/drivers/phy/socionext/phy-uniphier-usb2.c index 3f2086ed4fe4..21c201717d95 100644 --- a/drivers/phy/socionext/phy-uniphier-usb2.c +++ b/drivers/phy/socionext/phy-uniphier-usb2.c @@ -81,7 +81,7 @@ static int uniphier_u2phy_init(struct phy *phy) } static struct phy *uniphier_u2phy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct uniphier_u2phy_priv *priv = dev_get_drvdata(dev); diff --git a/drivers/phy/st/Kconfig b/drivers/phy/st/Kconfig index 3fc3d0781fb8..304614b6dabf 100644 --- a/drivers/phy/st/Kconfig +++ b/drivers/phy/st/Kconfig @@ -33,6 +33,17 @@ config PHY_STIH407_USB Enable this support to enable the picoPHY device used by USB2 and USB3 controllers on STMicroelectronics STiH407 SoC families. +config PHY_STM32_COMBOPHY + tristate "STMicroelectronics COMBOPHY driver for STM32MP25" + depends on ARCH_STM32 || COMPILE_TEST + select GENERIC_PHY + help + Enable this to support the COMBOPHY device used by USB3 or PCIe + controllers on STMicroelectronics STM32MP25 SoC. + This driver controls the COMBOPHY block to generate the PCIe 100Mhz + reference clock from either the external clock generator or HSE + internal SoC clock source. + config PHY_STM32_USBPHYC tristate "STMicroelectronics STM32 USB HS PHY Controller driver" depends on ARCH_STM32 || COMPILE_TEST diff --git a/drivers/phy/st/Makefile b/drivers/phy/st/Makefile index c862dd937b64..cb80e954ea9f 100644 --- a/drivers/phy/st/Makefile +++ b/drivers/phy/st/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o +obj-$(CONFIG_PHY_STM32_COMBOPHY) += phy-stm32-combophy.o obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o diff --git a/drivers/phy/st/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c index e30305b77f0d..43cef89af55e 100644 --- a/drivers/phy/st/phy-miphy28lp.c +++ b/drivers/phy/st/phy-miphy28lp.c @@ -228,11 +228,6 @@ struct miphy28lp_dev { int nphys; }; -struct miphy_initval { - u16 reg; - u16 val; -}; - enum miphy_sata_gen { SATA_GEN1, SATA_GEN2, SATA_GEN3 }; static char *PHY_TYPE_name[] = { "sata-up", "pcie-up", "", "usb3-up" }; @@ -1074,7 +1069,7 @@ static int miphy28lp_get_addr(struct miphy28lp_phy *miphy_phy) } static struct phy *miphy28lp_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct miphy28lp_dev *miphy_dev = dev_get_drvdata(dev); struct miphy28lp_phy *miphy_phy = NULL; diff --git a/drivers/phy/st/phy-spear1310-miphy.c b/drivers/phy/st/phy-spear1310-miphy.c index 35a9831b5161..c661ab63505f 100644 --- a/drivers/phy/st/phy-spear1310-miphy.c +++ b/drivers/phy/st/phy-spear1310-miphy.c @@ -183,7 +183,7 @@ static const struct phy_ops spear1310_miphy_ops = { }; static struct phy *spear1310_miphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct spear1310_miphy_priv *priv = dev_get_drvdata(dev); diff --git a/drivers/phy/st/phy-spear1340-miphy.c b/drivers/phy/st/phy-spear1340-miphy.c index 34a1cf21015f..85a60d64ebb7 100644 --- a/drivers/phy/st/phy-spear1340-miphy.c +++ b/drivers/phy/st/phy-spear1340-miphy.c @@ -220,7 +220,7 @@ static SIMPLE_DEV_PM_OPS(spear1340_miphy_pm_ops, spear1340_miphy_suspend, spear1340_miphy_resume); static struct phy *spear1340_miphy_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct spear1340_miphy_priv *priv = dev_get_drvdata(dev); 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/st/phy-stm32-combophy.c b/drivers/phy/st/phy-stm32-combophy.c new file mode 100644 index 000000000000..607b4d607eb5 --- /dev/null +++ b/drivers/phy/st/phy-stm32-combophy.c @@ -0,0 +1,605 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * STMicroelectronics COMBOPHY STM32MP25 Controller driver. + * + * Copyright (C) 2024 STMicroelectronics + * Author: Christian Bruel <christian.bruel@foss.st.com> + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/mfd/syscon.h> +#include <linux/platform_device.h> +#include <linux/phy/phy.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/reset.h> +#include <dt-bindings/phy/phy.h> + +#define SYSCFG_COMBOPHY_CR1 0x4c00 +#define SYSCFG_COMBOPHY_CR2 0x4c04 +#define SYSCFG_COMBOPHY_CR4 0x4c0c +#define SYSCFG_COMBOPHY_CR5 0x4c10 +#define SYSCFG_COMBOPHY_SR 0x4c14 +#define SYSCFG_PCIEPRGCR 0x6080 + +/* SYSCFG PCIEPRGCR */ +#define STM32MP25_PCIEPRGCR_EN BIT(0) +#define STM32MP25_PCIEPRG_IMPCTRL_OHM GENMASK(3, 1) +#define STM32MP25_PCIEPRG_IMPCTRL_VSWING GENMASK(5, 4) + +/* SYSCFG SYSCFG_COMBOPHY_SR */ +#define STM32MP25_PIPE0_PHYSTATUS BIT(1) + +/* SYSCFG CR1 */ +#define SYSCFG_COMBOPHY_CR1_REFUSEPAD BIT(0) +#define SYSCFG_COMBOPHY_CR1_MPLLMULT GENMASK(7, 1) +#define SYSCFG_COMBOPHY_CR1_REFCLKSEL GENMASK(16, 8) +#define SYSCFG_COMBOPHY_CR1_REFCLKDIV2 BIT(17) +#define SYSCFG_COMBOPHY_CR1_REFSSPEN BIT(18) +#define SYSCFG_COMBOPHY_CR1_SSCEN BIT(19) + +/* SYSCFG CR4 */ +#define SYSCFG_COMBOPHY_CR4_RX0_EQ GENMASK(2, 0) + +#define MPLLMULT_19_2 (0x02u << 1) +#define MPLLMULT_20 (0x7du << 1) +#define MPLLMULT_24 (0x68u << 1) +#define MPLLMULT_25 (0x64u << 1) +#define MPLLMULT_26 (0x60u << 1) +#define MPLLMULT_38_4 (0x41u << 1) +#define MPLLMULT_48 (0x6cu << 1) +#define MPLLMULT_50 (0x32u << 1) +#define MPLLMULT_52 (0x30u << 1) +#define MPLLMULT_100 (0x19u << 1) + +#define REFCLKSEL_0 0 +#define REFCLKSEL_1 (0x108u << 8) + +#define REFCLDIV_0 0 + +/* SYSCFG CR2 */ +#define SYSCFG_COMBOPHY_CR2_MODESEL GENMASK(1, 0) +#define SYSCFG_COMBOPHY_CR2_ISO_DIS BIT(15) + +#define COMBOPHY_MODESEL_PCIE 0 +#define COMBOPHY_MODESEL_USB 3 + +/* SYSCFG CR5 */ +#define SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS BIT(12) + +#define COMBOPHY_SUP_ANA_MPLL_LOOP_CTL 0xc0 +#define COMBOPHY_PROP_CNTRL GENMASK(7, 4) + +/* Required apb/ker clocks first, optional pad last. */ +static const char * const combophy_clks[] = {"apb", "ker", "pad"}; +#define APB_CLK 0 +#define KER_CLK 1 +#define PAD_CLK 2 + +struct stm32_combophy { + struct phy *phy; + struct regmap *regmap; + struct device *dev; + void __iomem *base; + struct reset_control *phy_reset; + struct clk_bulk_data clks[ARRAY_SIZE(combophy_clks)]; + int num_clks; + bool have_pad_clk; + unsigned int type; + bool is_init; + int irq_wakeup; +}; + +struct clk_impedance { + u32 microohm; + u32 vswing[4]; +}; + +/* + * lookup table to hold the settings needed for a ref clock frequency + * impedance, the offset is used to set the IMP_CTL and DE_EMP bit of the + * PRG_IMP_CTRL register. Use ordered discrete values in the table + */ +static const struct clk_impedance imp_lookup[] = { + { 6090000, { 442000, 564000, 684000, 802000 } }, + { 5662000, { 528000, 621000, 712000, 803000 } }, + { 5292000, { 491000, 596000, 700000, 802000 } }, + { 4968000, { 558000, 640000, 722000, 803000 } }, + { 4684000, { 468000, 581000, 692000, 802000 } }, + { 4429000, { 554000, 613000, 717000, 803000 } }, + { 4204000, { 511000, 609000, 706000, 802000 } }, + { 3999000, { 571000, 648000, 726000, 803000 } } +}; +#define DEFAULT_IMP_INDEX 3 /* Default impedance is 50 Ohm */ + +static int stm32_impedance_tune(struct stm32_combophy *combophy) +{ + u8 imp_size = ARRAY_SIZE(imp_lookup); + u8 vswing_size = ARRAY_SIZE(imp_lookup[0].vswing); + u8 imp_of, vswing_of; + u32 max_imp = imp_lookup[0].microohm; + u32 min_imp = imp_lookup[imp_size - 1].microohm; + u32 max_vswing; + u32 min_vswing = imp_lookup[0].vswing[0]; + u32 val; + + if (!of_property_read_u32(combophy->dev->of_node, "st,output-micro-ohms", &val)) { + if (val < min_imp || val > max_imp) { + dev_err(combophy->dev, "Invalid value %u for output ohm\n", val); + return -EINVAL; + } + + for (imp_of = 0; imp_of < ARRAY_SIZE(imp_lookup); imp_of++) + if (imp_lookup[imp_of].microohm <= val) + break; + + if (WARN_ON(imp_of == ARRAY_SIZE(imp_lookup))) + return -EINVAL; + + dev_dbg(combophy->dev, "Set %u micro-ohms output impedance\n", + imp_lookup[imp_of].microohm); + + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRG_IMPCTRL_OHM, + FIELD_PREP(STM32MP25_PCIEPRG_IMPCTRL_OHM, imp_of)); + } else + imp_of = DEFAULT_IMP_INDEX; + + if (!of_property_read_u32(combophy->dev->of_node, "st,output-vswing-microvolt", &val)) { + max_vswing = imp_lookup[imp_of].vswing[vswing_size - 1]; + + if (val < min_vswing || val > max_vswing) { + dev_err(combophy->dev, "Invalid value %u for output vswing\n", val); + return -EINVAL; + } + + for (vswing_of = 0; vswing_of < ARRAY_SIZE(imp_lookup[imp_of].vswing); vswing_of++) + if (imp_lookup[imp_of].vswing[vswing_of] >= val) + break; + + if (WARN_ON(vswing_of == ARRAY_SIZE(imp_lookup[imp_of].vswing))) + return -EINVAL; + + dev_dbg(combophy->dev, "Set %u microvolt swing\n", + imp_lookup[imp_of].vswing[vswing_of]); + + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRG_IMPCTRL_VSWING, + FIELD_PREP(STM32MP25_PCIEPRG_IMPCTRL_VSWING, vswing_of)); + } + + return 0; +} + +static int stm32_combophy_pll_init(struct stm32_combophy *combophy) +{ + int ret; + u32 refclksel, pllmult, propcntrl, val; + u32 clk_rate; + struct clk *clk; + u32 cr1_val = 0, cr1_mask = 0; + + if (combophy->have_pad_clk) + clk = combophy->clks[PAD_CLK].clk; + else + clk = combophy->clks[KER_CLK].clk; + + clk_rate = clk_get_rate(clk); + + dev_dbg(combophy->dev, "%s pll init rate %d\n", + combophy->have_pad_clk ? "External" : "Ker", clk_rate); + + if (combophy->type != PHY_TYPE_PCIE) { + cr1_mask |= SYSCFG_COMBOPHY_CR1_REFSSPEN; + cr1_val |= SYSCFG_COMBOPHY_CR1_REFSSPEN; + } + + if (of_property_present(combophy->dev->of_node, "st,ssc-on")) { + dev_dbg(combophy->dev, "Enabling clock with SSC\n"); + cr1_mask |= SYSCFG_COMBOPHY_CR1_SSCEN; + cr1_val |= SYSCFG_COMBOPHY_CR1_SSCEN; + } + + switch (clk_rate) { + case 100000000: + pllmult = MPLLMULT_100; + refclksel = REFCLKSEL_0; + propcntrl = 0x8u << 4; + break; + case 19200000: + pllmult = MPLLMULT_19_2; + refclksel = REFCLKSEL_1; + propcntrl = 0x8u << 4; + break; + case 25000000: + pllmult = MPLLMULT_25; + refclksel = REFCLKSEL_0; + propcntrl = 0xeu << 4; + break; + case 24000000: + pllmult = MPLLMULT_24; + refclksel = REFCLKSEL_1; + propcntrl = 0xeu << 4; + break; + case 20000000: + pllmult = MPLLMULT_20; + refclksel = REFCLKSEL_0; + propcntrl = 0xeu << 4; + break; + default: + dev_err(combophy->dev, "Invalid rate 0x%x\n", clk_rate); + return -EINVAL; + } + + cr1_mask |= SYSCFG_COMBOPHY_CR1_REFCLKDIV2; + cr1_val |= REFCLDIV_0; + + cr1_mask |= SYSCFG_COMBOPHY_CR1_REFCLKSEL; + cr1_val |= refclksel; + + cr1_mask |= SYSCFG_COMBOPHY_CR1_MPLLMULT; + cr1_val |= pllmult; + + /* + * vddcombophy is interconnected with vddcore. Isolation bit should be unset + * before using the ComboPHY. + */ + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, + SYSCFG_COMBOPHY_CR2_ISO_DIS, SYSCFG_COMBOPHY_CR2_ISO_DIS); + + reset_control_assert(combophy->phy_reset); + + if (combophy->type == PHY_TYPE_PCIE) { + ret = stm32_impedance_tune(combophy); + if (ret) + goto out_iso; + + cr1_mask |= SYSCFG_COMBOPHY_CR1_REFUSEPAD; + cr1_val |= combophy->have_pad_clk ? SYSCFG_COMBOPHY_CR1_REFUSEPAD : 0; + } + + if (!of_property_read_u32(combophy->dev->of_node, "st,rx-equalizer", &val)) { + dev_dbg(combophy->dev, "Set RX equalizer %u\n", val); + if (val > SYSCFG_COMBOPHY_CR4_RX0_EQ) { + dev_err(combophy->dev, "Invalid value %u for rx0 equalizer\n", val); + ret = -EINVAL; + goto out_iso; + } + + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR4, + SYSCFG_COMBOPHY_CR4_RX0_EQ, val); + } + + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR1, cr1_mask, cr1_val); + + /* + * Force elasticity buffer to be tuned for the reference clock as + * the separated clock model is not supported + */ + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR5, + SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS, SYSCFG_COMBOPHY_CR5_COMMON_CLOCKS); + + reset_control_deassert(combophy->phy_reset); + + ret = regmap_read_poll_timeout(combophy->regmap, SYSCFG_COMBOPHY_SR, val, + !(val & STM32MP25_PIPE0_PHYSTATUS), + 10, 1000); + if (ret) { + dev_err(combophy->dev, "timeout, cannot lock PLL\n"); + if (combophy->type == PHY_TYPE_PCIE && !combophy->have_pad_clk) + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRGCR_EN, 0); + + if (combophy->type != PHY_TYPE_PCIE) + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR1, + SYSCFG_COMBOPHY_CR1_REFSSPEN, 0); + + goto out; + } + + + if (combophy->type == PHY_TYPE_PCIE) { + if (!combophy->have_pad_clk) + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRGCR_EN, STM32MP25_PCIEPRGCR_EN); + + val = readl_relaxed(combophy->base + COMBOPHY_SUP_ANA_MPLL_LOOP_CTL); + val &= ~COMBOPHY_PROP_CNTRL; + val |= propcntrl; + writel_relaxed(val, combophy->base + COMBOPHY_SUP_ANA_MPLL_LOOP_CTL); + } + + return 0; + +out_iso: + reset_control_deassert(combophy->phy_reset); + +out: + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, + SYSCFG_COMBOPHY_CR2_ISO_DIS, 0); + + return ret; +} + +static struct phy *stm32_combophy_xlate(struct device *dev, + const struct of_phandle_args *args) +{ + struct stm32_combophy *combophy = dev_get_drvdata(dev); + unsigned int type; + + if (args->args_count != 1) { + dev_err(dev, "invalid number of cells in 'phy' property\n"); + return ERR_PTR(-EINVAL); + } + + type = args->args[0]; + if (type != PHY_TYPE_USB3 && type != PHY_TYPE_PCIE) { + dev_err(dev, "unsupported device type: %d\n", type); + return ERR_PTR(-EINVAL); + } + + if (combophy->have_pad_clk && type != PHY_TYPE_PCIE) { + dev_err(dev, "Invalid use of clk_pad for USB3 mode\n"); + return ERR_PTR(-EINVAL); + } + + combophy->type = type; + + return combophy->phy; +} + +static int stm32_combophy_set_mode(struct stm32_combophy *combophy) +{ + int type = combophy->type; + u32 val; + + switch (type) { + case PHY_TYPE_PCIE: + dev_dbg(combophy->dev, "setting PCIe ComboPHY\n"); + val = COMBOPHY_MODESEL_PCIE; + break; + case PHY_TYPE_USB3: + dev_dbg(combophy->dev, "setting USB3 ComboPHY\n"); + val = COMBOPHY_MODESEL_USB; + break; + default: + dev_err(combophy->dev, "Invalid PHY mode %d\n", type); + return -EINVAL; + } + + return regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, + SYSCFG_COMBOPHY_CR2_MODESEL, val); +} + +static int stm32_combophy_suspend_noirq(struct device *dev) +{ + struct stm32_combophy *combophy = dev_get_drvdata(dev); + + /* + * Clocks should be turned off since it is not needed for + * wakeup capability. In case usb-remote wakeup is not enabled, + * combo-phy is already turned off by HCD driver using exit callback + */ + if (combophy->is_init) { + clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); + + /* since wakeup is enabled for ctrl */ + enable_irq_wake(combophy->irq_wakeup); + } + + return 0; +} + +static int stm32_combophy_resume_noirq(struct device *dev) +{ + struct stm32_combophy *combophy = dev_get_drvdata(dev); + int ret; + + /* + * If clocks was turned off by suspend call for wakeup then needs + * to be turned back ON in resume. In case usb-remote wakeup is not + * enabled, clocks already turned ON by HCD driver using init callback + */ + if (combophy->is_init) { + /* since wakeup was enabled for ctrl */ + disable_irq_wake(combophy->irq_wakeup); + + ret = clk_bulk_prepare_enable(combophy->num_clks, combophy->clks); + if (ret) { + dev_err(dev, "can't enable clocks (%d)\n", ret); + return ret; + } + } + + return 0; +} + +static int stm32_combophy_exit(struct phy *phy) +{ + struct stm32_combophy *combophy = phy_get_drvdata(phy); + struct device *dev = combophy->dev; + + combophy->is_init = false; + + if (combophy->type == PHY_TYPE_PCIE && !combophy->have_pad_clk) + regmap_update_bits(combophy->regmap, SYSCFG_PCIEPRGCR, + STM32MP25_PCIEPRGCR_EN, 0); + + if (combophy->type != PHY_TYPE_PCIE) + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR1, + SYSCFG_COMBOPHY_CR1_REFSSPEN, 0); + + regmap_update_bits(combophy->regmap, SYSCFG_COMBOPHY_CR2, + SYSCFG_COMBOPHY_CR2_ISO_DIS, 0); + + clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); + + pm_runtime_put_noidle(dev); + + return 0; +} + +static int stm32_combophy_init(struct phy *phy) +{ + struct stm32_combophy *combophy = phy_get_drvdata(phy); + struct device *dev = combophy->dev; + int ret; + + pm_runtime_get_noresume(dev); + + ret = clk_bulk_prepare_enable(combophy->num_clks, combophy->clks); + if (ret) { + dev_err(dev, "can't enable clocks (%d)\n", ret); + pm_runtime_put_noidle(dev); + return ret; + } + + ret = stm32_combophy_set_mode(combophy); + if (ret) { + dev_err(dev, "combophy mode not set\n"); + clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); + pm_runtime_put_noidle(dev); + return ret; + } + + ret = stm32_combophy_pll_init(combophy); + if (ret) { + clk_bulk_disable_unprepare(combophy->num_clks, combophy->clks); + pm_runtime_put_noidle(dev); + return ret; + } + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + combophy->is_init = true; + + return ret; +} + +static const struct phy_ops stm32_combophy_phy_data = { + .init = stm32_combophy_init, + .exit = stm32_combophy_exit, + .owner = THIS_MODULE +}; + +static irqreturn_t stm32_combophy_irq_wakeup_handler(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +static int stm32_combophy_get_clocks(struct stm32_combophy *combophy) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(combophy_clks); i++) + combophy->clks[i].id = combophy_clks[i]; + + combophy->num_clks = ARRAY_SIZE(combophy_clks) - 1; + + ret = devm_clk_bulk_get(combophy->dev, combophy->num_clks, combophy->clks); + if (ret) + return ret; + + ret = devm_clk_bulk_get_optional(combophy->dev, 1, combophy->clks + combophy->num_clks); + if (ret) + return ret; + + if (combophy->clks[combophy->num_clks].clk != NULL) { + combophy->have_pad_clk = true; + combophy->num_clks++; + } + + return 0; +} + +static int stm32_combophy_probe(struct platform_device *pdev) +{ + struct stm32_combophy *combophy; + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + int ret, irq; + + combophy = devm_kzalloc(dev, sizeof(*combophy), GFP_KERNEL); + if (!combophy) + return -ENOMEM; + + combophy->dev = dev; + + dev_set_drvdata(dev, combophy); + + combophy->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(combophy->base)) + return PTR_ERR(combophy->base); + + ret = stm32_combophy_get_clocks(combophy); + if (ret) + return ret; + + combophy->phy_reset = devm_reset_control_get_exclusive(dev, "phy"); + if (IS_ERR(combophy->phy_reset)) + return dev_err_probe(dev, PTR_ERR(combophy->phy_reset), + "Failed to get PHY reset\n"); + + combophy->regmap = syscon_regmap_lookup_by_compatible("st,stm32mp25-syscfg"); + if (IS_ERR(combophy->regmap)) + return dev_err_probe(dev, PTR_ERR(combophy->regmap), + "No syscfg specified\n"); + + combophy->phy = devm_phy_create(dev, NULL, &stm32_combophy_phy_data); + if (IS_ERR(combophy->phy)) + return dev_err_probe(dev, PTR_ERR(combophy->phy), + "failed to create PCIe/USB3 ComboPHY\n"); + + if (device_property_read_bool(dev, "wakeup-source")) { + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(dev, irq, "failed to get IRQ\n"); + combophy->irq_wakeup = irq; + + ret = devm_request_threaded_irq(dev, combophy->irq_wakeup, NULL, + stm32_combophy_irq_wakeup_handler, IRQF_ONESHOT, + NULL, NULL); + if (ret) + return dev_err_probe(dev, ret, "unable to request wake IRQ %d\n", + combophy->irq_wakeup); + } + + ret = devm_pm_runtime_enable(dev); + if (ret) + return dev_err_probe(dev, ret, "Failed to enable pm runtime\n"); + + phy_set_drvdata(combophy->phy, combophy); + + phy_provider = devm_of_phy_provider_register(dev, stm32_combophy_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct dev_pm_ops stm32_combophy_pm_ops = { + NOIRQ_SYSTEM_SLEEP_PM_OPS(stm32_combophy_suspend_noirq, + stm32_combophy_resume_noirq) +}; + +static const struct of_device_id stm32_combophy_of_match[] = { + { .compatible = "st,stm32mp25-combophy", }, + { }, +}; +MODULE_DEVICE_TABLE(of, stm32_combophy_of_match); + +static struct platform_driver stm32_combophy_driver = { + .probe = stm32_combophy_probe, + .driver = { + .name = "stm32-combophy", + .of_match_table = stm32_combophy_of_match, + .pm = pm_sleep_ptr(&stm32_combophy_pm_ops) + } +}; + +module_platform_driver(stm32_combophy_driver); + +MODULE_AUTHOR("Christian Bruel <christian.bruel@foss.st.com>"); +MODULE_DESCRIPTION("STM32MP25 Combophy USB3/PCIe controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c index d5e7e44000b5..b917cd413de7 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -574,7 +574,7 @@ static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, } static struct phy *stm32_usbphyc_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev); struct stm32_usbphyc_phy *usbphyc_phy = NULL; @@ -812,7 +812,7 @@ MODULE_DEVICE_TABLE(of, stm32_usbphyc_of_match); static struct platform_driver stm32_usbphyc_driver = { .probe = stm32_usbphyc_probe, - .remove_new = stm32_usbphyc_remove, + .remove = stm32_usbphyc_remove, .driver = { .of_match_table = stm32_usbphyc_of_match, .name = "stm32-usbphyc", diff --git a/drivers/phy/starfive/Kconfig b/drivers/phy/starfive/Kconfig index 9508e2143011..d0cdd7cb4a13 100644 --- a/drivers/phy/starfive/Kconfig +++ b/drivers/phy/starfive/Kconfig @@ -15,6 +15,16 @@ config PHY_STARFIVE_JH7110_DPHY_RX system. If M is selected, the module will be called phy-jh7110-dphy-rx.ko. +config PHY_STARFIVE_JH7110_DPHY_TX + tristate "StarFive JH7110 D-PHY TX Support" + depends on HAS_IOMEM + select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + help + Choose this option if you have a StarFive D-PHY TX in your + system. If M is selected, the module will be called + phy-jh7110-dphy-tx.ko. + config PHY_STARFIVE_JH7110_PCIE tristate "Starfive JH7110 PCIE 2.0/USB 3.0 PHY support" depends on HAS_IOMEM diff --git a/drivers/phy/starfive/Makefile b/drivers/phy/starfive/Makefile index b391018b7c47..eedc4a6fec15 100644 --- a/drivers/phy/starfive/Makefile +++ b/drivers/phy/starfive/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_PHY_STARFIVE_JH7110_DPHY_RX) += phy-jh7110-dphy-rx.o +obj-$(CONFIG_PHY_STARFIVE_JH7110_DPHY_TX) += phy-jh7110-dphy-tx.o obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o obj-$(CONFIG_PHY_STARFIVE_JH7110_USB) += phy-jh7110-usb.o diff --git a/drivers/phy/starfive/phy-jh7110-dphy-rx.c b/drivers/phy/starfive/phy-jh7110-dphy-rx.c index 037a9e0263cd..0b039e1f71c5 100644 --- a/drivers/phy/starfive/phy-jh7110-dphy-rx.c +++ b/drivers/phy/starfive/phy-jh7110-dphy-rx.c @@ -46,11 +46,6 @@ #define STF_MAP_LANES_NUM 6 -struct regval { - u32 addr; - u32 val; -}; - struct stf_dphy_info { /** * @maps: diff --git a/drivers/phy/starfive/phy-jh7110-dphy-tx.c b/drivers/phy/starfive/phy-jh7110-dphy-tx.c new file mode 100644 index 000000000000..c64d1c91b130 --- /dev/null +++ b/drivers/phy/starfive/phy-jh7110-dphy-tx.c @@ -0,0 +1,461 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * DPHY TX driver for the StarFive JH7110 SoC + * + * Copyright (C) 2023 StarFive Technology Co., Ltd. + * Author: Keith Zhao <keith.zhao@starfivetech.com> + * Author: Shengyang Chen <shengyang.chen@starfivetech.com> + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/phy/phy.h> +#include <linux/phy/phy-mipi-dphy.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#define STF_DPHY_APBIFSAIF_SYSCFG(x) (x) + +#define STF_DPHY_AON_POWER_READY_N_ACTIVE 0 +#define STF_DPHY_AON_POWER_READY_N BIT(0) +#define STF_DPHY_CFG_L0_SWAP_SEL GENMASK(14, 12) +#define STF_DPHY_CFG_L1_SWAP_SEL GENMASK(17, 15) +#define STF_DPHY_CFG_L2_SWAP_SEL GENMASK(20, 18) +#define STF_DPHY_CFG_L3_SWAP_SEL GENMASK(23, 21) +#define STF_DPHY_CFG_L4_SWAP_SEL GENMASK(26, 24) +#define STF_DPHY_RGS_CDTX_PLL_UNLOCK BIT(18) +#define STF_DPHY_RG_CDTX_L0N_HSTX_RES GENMASK(23, 19) +#define STF_DPHY_RG_CDTX_L0P_HSTX_RES GENMASK(28, 24) + +#define STF_DPHY_RG_CDTX_L1P_HSTX_RES GENMASK(9, 5) +#define STF_DPHY_RG_CDTX_L2N_HSTX_RES GENMASK(14, 10) +#define STF_DPHY_RG_CDTX_L2P_HSTX_RES GENMASK(19, 15) +#define STF_DPHY_RG_CDTX_L3N_HSTX_RES GENMASK(24, 20) +#define STF_DPHY_RG_CDTX_L3P_HSTX_RES GENMASK(29, 25) + +#define STF_DPHY_RG_CDTX_L4N_HSTX_RES GENMASK(4, 0) +#define STF_DPHY_RG_CDTX_L4P_HSTX_RES GENMASK(9, 5) +#define STF_DPHY_RG_CDTX_PLL_FBK_FRA GENMASK(23, 0) + +#define STF_DPHY_RG_CDTX_PLL_FBK_INT GENMASK(8, 0) +#define STF_DPHY_RG_CDTX_PLL_FM_EN BIT(9) +#define STF_DPHY_RG_CDTX_PLL_LDO_STB_X2_EN BIT(10) +#define STF_DPHY_RG_CDTX_PLL_PRE_DIV GENMASK(12, 11) + +#define STF_DPHY_RG_CDTX_PLL_SSC_EN BIT(18) + +#define STF_DPHY_RG_CLANE_HS_CLK_POST_TIME GENMASK(7, 0) +#define STF_DPHY_RG_CLANE_HS_CLK_PRE_TIME GENMASK(15, 8) +#define STF_DPHY_RG_CLANE_HS_PRE_TIME GENMASK(23, 16) +#define STF_DPHY_RG_CLANE_HS_TRAIL_TIME GENMASK(31, 24) + +#define STF_DPHY_RG_CLANE_HS_ZERO_TIME GENMASK(7, 0) +#define STF_DPHY_RG_DLANE_HS_PRE_TIME GENMASK(15, 8) +#define STF_DPHY_RG_DLANE_HS_TRAIL_TIME GENMASK(23, 16) +#define STF_DPHY_RG_DLANE_HS_ZERO_TIME GENMASK(31, 24) + +#define STF_DPHY_RG_EXTD_CYCLE_SEL GENMASK(2, 0) +#define STF_DPHY_SCFG_C_HS_PRE_ZERO_TIME GENMASK(31, 0) + +#define STF_DPHY_SCFG_DSI_TXREADY_ESC_SEL GENMASK(2, 1) +#define STF_DPHY_SCFG_PPI_C_READY_SEL GENMASK(4, 3) + +#define STF_DPHY_REFCLK_IN_SEL GENMASK(28, 26) +#define STF_DPHY_RESETB BIT(29) + +#define STF_DPHY_REFCLK_12M 1 +#define STF_DPHY_BITRATE_ALIGN 10000000 + +#define STF_MAP_LANES_NUM 5 + +#define STF_DPHY_LSHIFT_16(x) (FIELD_PREP(GENMASK(23, 16), (x))) +#define STF_DPHY_LSHIFT_8(x) (FIELD_PREP(GENMASK(15, 8), (x))) + +#define STF_DPHY_HW_DELAY_US 200 +#define STF_DPHY_HW_TIMEOUT_US 5000 + +struct stf_dphy_config { + unsigned long bitrate; + u32 pll_fbk_int; + u32 pll_fbk_fra_val; + u32 extd_cycle_sel; + u32 dlane_hs_pre_time; + u32 dlane_hs_zero_time; + u32 dlane_hs_trail_time; + u32 clane_hs_pre_time; + u32 clane_hs_zero_time; + u32 clane_hs_trail_time; + u32 clane_hs_clk_pre_time; + u32 clane_hs_clk_post_time; +}; + +static const struct stf_dphy_config reg_configs[] = { + {160000000, 0x6a, 0xaa, 0x3, 0xa, 0x17, 0x11, 0x5, 0x2b, 0xd, 0x7, 0x3d}, + {170000000, 0x71, 0x55, 0x3, 0xb, 0x18, 0x11, 0x5, 0x2e, 0xd, 0x7, 0x3d}, + {180000000, 0x78, 0x0, 0x3, 0xb, 0x19, 0x12, 0x6, 0x30, 0xe, 0x7, 0x3e}, + {190000000, 0x7e, 0xaa, 0x3, 0xc, 0x1a, 0x12, 0x6, 0x33, 0xe, 0x7, 0x3e}, + {200000000, 0x85, 0x55, 0x3, 0xc, 0x1b, 0x13, 0x7, 0x35, 0xf, 0x7, 0x3f}, + {320000000, 0x6a, 0xaa, 0x2, 0x8, 0x14, 0xf, 0x5, 0x2b, 0xd, 0x3, 0x23}, + {330000000, 0x6e, 0x0, 0x2, 0x8, 0x15, 0xf, 0x5, 0x2d, 0xd, 0x3, 0x23}, + {340000000, 0x71, 0x55, 0x2, 0x9, 0x15, 0xf, 0x5, 0x2e, 0xd, 0x3, 0x23}, + {350000000, 0x74, 0xaa, 0x2, 0x9, 0x15, 0x10, 0x6, 0x2f, 0xe, 0x3, 0x24}, + {360000000, 0x78, 0x0, 0x2, 0x9, 0x16, 0x10, 0x6, 0x30, 0xe, 0x3, 0x24}, + {370000000, 0x7b, 0x55, 0x2, 0x9, 0x17, 0x10, 0x6, 0x32, 0xe, 0x3, 0x24}, + {380000000, 0x7e, 0xaa, 0x2, 0xa, 0x17, 0x10, 0x6, 0x33, 0xe, 0x3, 0x24}, + {390000000, 0x82, 0x0, 0x2, 0xa, 0x17, 0x11, 0x6, 0x35, 0xf, 0x3, 0x25}, + {400000000, 0x85, 0x55, 0x2, 0xa, 0x18, 0x11, 0x7, 0x35, 0xf, 0x3, 0x25}, + {410000000, 0x88, 0xaa, 0x2, 0xa, 0x19, 0x11, 0x7, 0x37, 0xf, 0x3, 0x25}, + {420000000, 0x8c, 0x0, 0x2, 0xa, 0x19, 0x12, 0x7, 0x38, 0x10, 0x3, 0x26}, + {430000000, 0x8f, 0x55, 0x2, 0xb, 0x19, 0x12, 0x7, 0x39, 0x10, 0x3, 0x26}, + {440000000, 0x92, 0xaa, 0x2, 0xb, 0x1a, 0x12, 0x7, 0x3b, 0x10, 0x3, 0x26}, + {450000000, 0x96, 0x0, 0x2, 0xb, 0x1b, 0x12, 0x8, 0x3c, 0x10, 0x3, 0x26}, + {460000000, 0x99, 0x55, 0x2, 0xb, 0x1b, 0x13, 0x8, 0x3d, 0x11, 0x3, 0x27}, + {470000000, 0x9c, 0xaa, 0x2, 0xc, 0x1b, 0x13, 0x8, 0x3e, 0x11, 0x3, 0x27}, + {480000000, 0xa0, 0x27, 0x2, 0xc, 0x1c, 0x13, 0x8, 0x40, 0x11, 0x3, 0x27}, + {490000000, 0xa3, 0x55, 0x2, 0xc, 0x1d, 0x14, 0x8, 0x42, 0x12, 0x3, 0x28}, + {500000000, 0xa6, 0xaa, 0x2, 0xc, 0x1d, 0x14, 0x9, 0x42, 0x12, 0x3, 0x28}, + {510000000, 0xaa, 0x0, 0x2, 0xc, 0x1e, 0x14, 0x9, 0x44, 0x12, 0x3, 0x28}, + {520000000, 0xad, 0x55, 0x2, 0xd, 0x1e, 0x15, 0x9, 0x45, 0x13, 0x3, 0x29}, + {530000000, 0xb0, 0xaa, 0x2, 0xd, 0x1e, 0x15, 0x9, 0x47, 0x13, 0x3, 0x29}, + {540000000, 0xb4, 0x0, 0x2, 0xd, 0x1f, 0x15, 0x9, 0x48, 0x13, 0x3, 0x29}, + {550000000, 0xb7, 0x55, 0x2, 0xd, 0x20, 0x16, 0x9, 0x4a, 0x14, 0x3, 0x2a}, + {560000000, 0xba, 0xaa, 0x2, 0xe, 0x20, 0x16, 0xa, 0x4a, 0x14, 0x3, 0x2a}, + {570000000, 0xbe, 0x0, 0x2, 0xe, 0x20, 0x16, 0xa, 0x4c, 0x14, 0x3, 0x2a}, + {580000000, 0xc1, 0x55, 0x2, 0xe, 0x21, 0x16, 0xa, 0x4d, 0x14, 0x3, 0x2a}, + {590000000, 0xc4, 0xaa, 0x2, 0xe, 0x22, 0x17, 0xa, 0x4f, 0x15, 0x3, 0x2b}, + {600000000, 0xc8, 0x0, 0x2, 0xe, 0x23, 0x17, 0xa, 0x50, 0x15, 0x3, 0x2b}, + {610000000, 0xcb, 0x55, 0x2, 0xf, 0x22, 0x17, 0xb, 0x50, 0x15, 0x3, 0x2b}, + {620000000, 0xce, 0xaa, 0x2, 0xf, 0x23, 0x18, 0xb, 0x52, 0x16, 0x3, 0x2c}, + {630000000, 0x69, 0x0, 0x1, 0x7, 0x12, 0xd, 0x5, 0x2a, 0xc, 0x1, 0x15}, + {640000000, 0x6a, 0xaa, 0x1, 0x7, 0x13, 0xe, 0x5, 0x2b, 0xd, 0x1, 0x16}, + {650000000, 0x6c, 0x55, 0x1, 0x7, 0x13, 0xe, 0x5, 0x2c, 0xd, 0x1, 0x16}, + {660000000, 0x6e, 0x0, 0x1, 0x7, 0x13, 0xe, 0x5, 0x2d, 0xd, 0x1, 0x16}, + {670000000, 0x6f, 0xaa, 0x1, 0x8, 0x13, 0xe, 0x5, 0x2d, 0xd, 0x1, 0x16}, + {680000000, 0x71, 0x55, 0x1, 0x8, 0x13, 0xe, 0x5, 0x2e, 0xd, 0x1, 0x16}, + {690000000, 0x73, 0x0, 0x1, 0x8, 0x14, 0xe, 0x6, 0x2e, 0xd, 0x1, 0x16}, + {700000000, 0x74, 0xaa, 0x1, 0x8, 0x14, 0xf, 0x6, 0x2f, 0xe, 0x1, 0x16}, + {710000000, 0x76, 0x55, 0x1, 0x8, 0x14, 0xf, 0x6, 0x2f, 0xe, 0x1, 0x17}, + {720000000, 0x78, 0x0, 0x1, 0x8, 0x15, 0xf, 0x6, 0x30, 0xe, 0x1, 0x17}, + {730000000, 0x79, 0xaa, 0x1, 0x8, 0x15, 0xf, 0x6, 0x31, 0xe, 0x1, 0x17}, + {740000000, 0x7b, 0x55, 0x1, 0x8, 0x15, 0xf, 0x6, 0x32, 0xe, 0x1, 0x17}, + {750000000, 0x7d, 0x0, 0x1, 0x8, 0x16, 0xf, 0x6, 0x32, 0xe, 0x1, 0x17}, + {760000000, 0x7e, 0xaa, 0x1, 0x9, 0x15, 0xf, 0x6, 0x33, 0xe, 0x1, 0x17}, + {770000000, 0x80, 0x55, 0x1, 0x9, 0x15, 0x10, 0x6, 0x34, 0xf, 0x1, 0x18}, + {780000000, 0x82, 0x0, 0x1, 0x9, 0x16, 0x10, 0x6, 0x35, 0xf, 0x1, 0x18,}, + {790000000, 0x83, 0xaa, 0x1, 0x9, 0x16, 0x10, 0x7, 0x34, 0xf, 0x1, 0x18}, + {800000000, 0x85, 0x55, 0x1, 0x9, 0x17, 0x10, 0x7, 0x35, 0xf, 0x1, 0x18}, + {810000000, 0x87, 0x0, 0x1, 0x9, 0x17, 0x10, 0x7, 0x36, 0xf, 0x1, 0x18}, + {820000000, 0x88, 0xaa, 0x1, 0x9, 0x17, 0x10, 0x7, 0x37, 0xf, 0x1, 0x18}, + {830000000, 0x8a, 0x55, 0x1, 0x9, 0x18, 0x10, 0x7, 0x37, 0xf, 0x1, 0x18}, + {840000000, 0x8c, 0x0, 0x1, 0x9, 0x18, 0x11, 0x7, 0x38, 0x10, 0x1, 0x19}, + {850000000, 0x8d, 0xaa, 0x1, 0xa, 0x17, 0x11, 0x7, 0x39, 0x10, 0x1, 0x19}, + {860000000, 0x8f, 0x55, 0x1, 0xa, 0x18, 0x11, 0x7, 0x39, 0x10, 0x1, 0x19}, + {870000000, 0x91, 0x0, 0x1, 0xa, 0x18, 0x11, 0x7, 0x3a, 0x10, 0x1, 0x19}, + {880000000, 0x92, 0xaa, 0x1, 0xa, 0x18, 0x11, 0x7, 0x3b, 0x10, 0x1, 0x19}, + {890000000, 0x94, 0x55, 0x1, 0xa, 0x19, 0x11, 0x7, 0x3c, 0x10, 0x1, 0x19}, + {900000000, 0x96, 0x0, 0x1, 0xa, 0x19, 0x12, 0x8, 0x3c, 0x10, 0x1, 0x19}, + {910000000, 0x97, 0xaa, 0x1, 0xa, 0x19, 0x12, 0x8, 0x3c, 0x11, 0x1, 0x1a}, + {920000000, 0x99, 0x55, 0x1, 0xa, 0x1a, 0x12, 0x8, 0x3d, 0x11, 0x1, 0x1a}, + {930000000, 0x9b, 0x0, 0x1, 0xa, 0x1a, 0x12, 0x8, 0x3e, 0x11, 0x1, 0x1a}, + {940000000, 0x9c, 0xaa, 0x1, 0xb, 0x1a, 0x12, 0x8, 0x3e, 0x11, 0x1, 0x1a}, + {950000000, 0x9e, 0x55, 0x1, 0xb, 0x1a, 0x12, 0x8, 0x3f, 0x11, 0x1, 0x1a}, + {960000000, 0xa0, 0x0, 0x1, 0xb, 0x1a, 0x12, 0x8, 0x40, 0x11, 0x1, 0x1a}, + {970000000, 0xa1, 0xaa, 0x1, 0xb, 0x1b, 0x13, 0x8, 0x41, 0x12, 0x1, 0x1b}, + {980000000, 0xa3, 0x55, 0x1, 0xb, 0x1b, 0x13, 0x8, 0x42, 0x12, 0x1, 0x1b}, + {990000000, 0xa5, 0x0, 0x1, 0xb, 0x1b, 0x13, 0x8, 0x42, 0x12, 0x1, 0x1b}, + {1000000000, 0xa6, 0xaa, 0x1, 0xb, 0x1c, 0x13, 0x9, 0x42, 0x12, 0x1, 0x1b}, +}; + +struct stf_dphy_info { + /** + * @maps: + * + * Physical lanes and logic lanes mapping table. + * + * The default order is: + * [data lane 0, data lane 1, data lane 2, date lane 3, clk lane] + */ + u8 maps[STF_MAP_LANES_NUM]; +}; + +struct stf_dphy { + struct device *dev; + void __iomem *topsys; + struct clk *txesc_clk; + struct reset_control *sys_rst; + + struct phy_configure_opts_mipi_dphy config; + + struct phy *phy; + const struct stf_dphy_info *info; +}; + +static u32 stf_dphy_get_config_index(u32 bitrate) +{ + u32 i; + + for (i = 0; i < ARRAY_SIZE(reg_configs); i++) { + if (reg_configs[i].bitrate == bitrate) + return i; + } + + return 0; +} + +static void stf_dphy_hw_reset(struct stf_dphy *dphy, int assert) +{ + int rc; + u32 status = 0; + + writel(FIELD_PREP(STF_DPHY_RESETB, assert), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(100)); + + if (assert) { + rc = readl_poll_timeout_atomic(dphy->topsys + + STF_DPHY_APBIFSAIF_SYSCFG(8), + status, + !(FIELD_GET(STF_DPHY_RGS_CDTX_PLL_UNLOCK, status)), + STF_DPHY_HW_DELAY_US, STF_DPHY_HW_TIMEOUT_US); + if (rc) + dev_err(dphy->dev, "MIPI dphy-tx # PLL Locked\n"); + } +} + +static int stf_dphy_configure(struct phy *phy, union phy_configure_opts *opts) +{ + struct stf_dphy *dphy = phy_get_drvdata(phy); + const struct stf_dphy_info *info = dphy->info; + const struct stf_dphy_config *p = reg_configs; + unsigned long alignment = STF_DPHY_BITRATE_ALIGN; + u32 bitrate = opts->mipi_dphy.hs_clk_rate; + u32 tmp; + u32 i; + + if (bitrate % alignment) + bitrate += alignment - (bitrate % alignment); + + i = stf_dphy_get_config_index(bitrate); + + tmp = readl(dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(100)); + tmp &= ~STF_DPHY_REFCLK_IN_SEL; + tmp |= FIELD_PREP(STF_DPHY_REFCLK_IN_SEL, STF_DPHY_REFCLK_12M); + writel(tmp, dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(100)); + + writel(FIELD_PREP(STF_DPHY_RG_CDTX_L0N_HSTX_RES, 0x10) | + FIELD_PREP(STF_DPHY_RG_CDTX_L0P_HSTX_RES, 0x10), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(8)); + + writel(FIELD_PREP(STF_DPHY_RG_CDTX_L0N_HSTX_RES, 0x10) | + FIELD_PREP(STF_DPHY_RG_CDTX_L2N_HSTX_RES, 0x10) | + FIELD_PREP(STF_DPHY_RG_CDTX_L3N_HSTX_RES, 0x10) | + FIELD_PREP(STF_DPHY_RG_CDTX_L1P_HSTX_RES, 0x10) | + FIELD_PREP(STF_DPHY_RG_CDTX_L2P_HSTX_RES, 0x10) | + FIELD_PREP(STF_DPHY_RG_CDTX_L3P_HSTX_RES, 0x10), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(12)); + + writel(FIELD_PREP(STF_DPHY_RG_CDTX_L4N_HSTX_RES, 0x10) | + FIELD_PREP(STF_DPHY_RG_CDTX_L4P_HSTX_RES, 0x10), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(16)); + + /* Lane setting */ + writel(FIELD_PREP(STF_DPHY_AON_POWER_READY_N, + STF_DPHY_AON_POWER_READY_N_ACTIVE) | + FIELD_PREP(STF_DPHY_CFG_L0_SWAP_SEL, info->maps[0]) | + FIELD_PREP(STF_DPHY_CFG_L1_SWAP_SEL, info->maps[1]) | + FIELD_PREP(STF_DPHY_CFG_L2_SWAP_SEL, info->maps[2]) | + FIELD_PREP(STF_DPHY_CFG_L3_SWAP_SEL, info->maps[3]) | + FIELD_PREP(STF_DPHY_CFG_L4_SWAP_SEL, info->maps[4]), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(0)); + + /* PLL setting */ + writel(FIELD_PREP(STF_DPHY_RG_CDTX_PLL_SSC_EN, 0x0), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(28)); + + writel(FIELD_PREP(STF_DPHY_RG_CDTX_PLL_LDO_STB_X2_EN, 0x1) | + FIELD_PREP(STF_DPHY_RG_CDTX_PLL_FM_EN, 0x1) | + FIELD_PREP(STF_DPHY_RG_CDTX_PLL_PRE_DIV, 0x0) | + FIELD_PREP(STF_DPHY_RG_CDTX_PLL_FBK_INT, p[i].pll_fbk_int), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(24)); + + writel(FIELD_PREP(STF_DPHY_RG_CDTX_PLL_FBK_FRA, + STF_DPHY_LSHIFT_16(p[i].pll_fbk_fra_val) | + STF_DPHY_LSHIFT_8(p[i].pll_fbk_fra_val) | + p[i].pll_fbk_fra_val), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(20)); + + writel(FIELD_PREP(STF_DPHY_RG_EXTD_CYCLE_SEL, p[i].extd_cycle_sel), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(40)); + + writel(FIELD_PREP(STF_DPHY_RG_DLANE_HS_PRE_TIME, p[i].dlane_hs_pre_time) | + FIELD_PREP(STF_DPHY_RG_DLANE_HS_ZERO_TIME, p[i].dlane_hs_zero_time) | + FIELD_PREP(STF_DPHY_RG_DLANE_HS_TRAIL_TIME, p[i].dlane_hs_trail_time) | + FIELD_PREP(STF_DPHY_RG_CLANE_HS_ZERO_TIME, p[i].clane_hs_zero_time), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(36)); + + writel(FIELD_PREP(STF_DPHY_RG_CLANE_HS_PRE_TIME, p[i].clane_hs_pre_time) | + FIELD_PREP(STF_DPHY_RG_CLANE_HS_TRAIL_TIME, p[i].clane_hs_trail_time) | + FIELD_PREP(STF_DPHY_RG_CLANE_HS_CLK_PRE_TIME, p[i].clane_hs_clk_pre_time) | + FIELD_PREP(STF_DPHY_RG_CLANE_HS_CLK_POST_TIME, p[i].clane_hs_clk_post_time), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(32)); + + return 0; +} + +static int stf_dphy_init(struct phy *phy) +{ + struct stf_dphy *dphy = phy_get_drvdata(phy); + int ret; + + stf_dphy_hw_reset(dphy, 1); + + writel(FIELD_PREP(STF_DPHY_SCFG_PPI_C_READY_SEL, 0) | + FIELD_PREP(STF_DPHY_SCFG_DSI_TXREADY_ESC_SEL, 0), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(48)); + + writel(FIELD_PREP(STF_DPHY_SCFG_C_HS_PRE_ZERO_TIME, 0x30), + dphy->topsys + STF_DPHY_APBIFSAIF_SYSCFG(44)); + + ret = clk_prepare_enable(dphy->txesc_clk); + if (ret) { + dev_err(dphy->dev, "Failed to prepare/enable txesc_clk\n"); + return ret; + } + + ret = reset_control_deassert(dphy->sys_rst); + if (ret) { + dev_err(dphy->dev, "Failed to deassert sys_rst\n"); + return ret; + } + + return 0; +} + +static int stf_dphy_exit(struct phy *phy) +{ + struct stf_dphy *dphy = phy_get_drvdata(phy); + int ret; + + ret = reset_control_assert(dphy->sys_rst); + if (ret) { + dev_err(dphy->dev, "Failed to assert sys_rst\n"); + return ret; + } + + clk_disable_unprepare(dphy->txesc_clk); + + stf_dphy_hw_reset(dphy, 0); + + return 0; +} + +static int stf_dphy_power_on(struct phy *phy) +{ + struct stf_dphy *dphy = phy_get_drvdata(phy); + + return pm_runtime_resume_and_get(dphy->dev); +} + +static int stf_dphy_validate(struct phy *phy, enum phy_mode mode, int submode, + union phy_configure_opts *opts) +{ + if (mode != PHY_MODE_MIPI_DPHY) + return -EINVAL; + + return 0; +} + +static int stf_dphy_power_off(struct phy *phy) +{ + struct stf_dphy *dphy = phy_get_drvdata(phy); + + return pm_runtime_put_sync(dphy->dev); +} + +static const struct phy_ops stf_dphy_ops = { + .power_on = stf_dphy_power_on, + .power_off = stf_dphy_power_off, + .init = stf_dphy_init, + .exit = stf_dphy_exit, + .configure = stf_dphy_configure, + .validate = stf_dphy_validate, + .owner = THIS_MODULE, +}; + +static int stf_dphy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct stf_dphy *dphy; + + dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL); + if (!dphy) + return -ENOMEM; + + dphy->info = of_device_get_match_data(&pdev->dev); + + dphy->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, dphy); + + dphy->topsys = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dphy->topsys)) + return PTR_ERR(dphy->topsys); + + pm_runtime_enable(&pdev->dev); + + dphy->txesc_clk = devm_clk_get(&pdev->dev, "txesc"); + if (IS_ERR(dphy->txesc_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(dphy->txesc_clk), + "Failed to get txesc clock\n"); + + dphy->sys_rst = devm_reset_control_get_exclusive(&pdev->dev, "sys"); + if (IS_ERR(dphy->sys_rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(dphy->sys_rst), + "Failed to get sys reset\n"); + + dphy->phy = devm_phy_create(&pdev->dev, NULL, &stf_dphy_ops); + if (IS_ERR(dphy->phy)) + return dev_err_probe(&pdev->dev, PTR_ERR(dphy->phy), + "Failed to create phy\n"); + + phy_set_drvdata(dphy->phy, dphy); + + phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return dev_err_probe(&pdev->dev, PTR_ERR(phy_provider), + "Failed to register phy\n"); + + return 0; +} + +static const struct stf_dphy_info starfive_dphy_info = { + .maps = {0, 1, 2, 3, 4}, +}; + +static const struct of_device_id stf_dphy_dt_ids[] = { + { + .compatible = "starfive,jh7110-dphy-tx", + .data = &starfive_dphy_info, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, stf_dphy_dt_ids); + +static struct platform_driver stf_dphy_driver = { + .driver = { + .name = "starfive-dphy-tx", + .of_match_table = stf_dphy_dt_ids, + }, + .probe = stf_dphy_probe, +}; +module_platform_driver(stf_dphy_driver); + +MODULE_AUTHOR("Keith Zhao <keith.zhao@starfivetech.com>"); +MODULE_AUTHOR("Shengyang Chen <shengyang.chen@starfivetech.com>"); +MODULE_DESCRIPTION("StarFive JH7110 DPHY TX driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/phy/starfive/phy-jh7110-usb.c b/drivers/phy/starfive/phy-jh7110-usb.c index 633912f8a05d..b505d89860b4 100644 --- a/drivers/phy/starfive/phy-jh7110-usb.c +++ b/drivers/phy/starfive/phy-jh7110-usb.c @@ -10,18 +10,26 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/io.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/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) +#define USB_PDRSTN_SPLIT BIT(17) +#define SYSCON_USB_SPLIT_OFFSET 0x18 + struct jh7110_usb2_phy { struct phy *phy; void __iomem *regs; + struct regmap *sys_syscon; struct clk *usb_125m_clk; struct clk *app_125m; enum phy_mode mode; @@ -61,6 +69,10 @@ static int usb2_phy_set_mode(struct phy *_phy, usb2_set_ls_keepalive(phy, (mode != PHY_MODE_USB_DEVICE)); } + /* Connect usb 2.0 phy mode */ + regmap_update_bits(phy->sys_syscon, SYSCON_USB_SPLIT_OFFSET, + USB_PDRSTN_SPLIT, USB_PDRSTN_SPLIT); + return 0; } @@ -68,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) @@ -77,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; } @@ -129,6 +146,12 @@ static int jh7110_usb_phy_probe(struct platform_device *pdev) phy_set_drvdata(phy->phy, phy); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + phy->sys_syscon = + syscon_regmap_lookup_by_compatible("starfive,jh7110-sys-syscon"); + if (IS_ERR(phy->sys_syscon)) + return dev_err_probe(dev, PTR_ERR(phy->sys_syscon), + "Failed to get sys-syscon\n"); + return PTR_ERR_OR_ZERO(phy_provider); } diff --git a/drivers/phy/tegra/Kconfig b/drivers/phy/tegra/Kconfig index c591c958f1eb..342fb736da4b 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 || 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 0f60d5d1c167..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); + if (!bitmap_empty(priv->utmi_pad_enabled, TEGRA_UTMI_PAD_MAX)) return; - } - - if (--priv->bias_pad_enable > 0) { - mutex_unlock(&padctl->lock); - 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, @@ -928,6 +936,7 @@ static int tegra186_utmi_phy_init(struct phy *phy) unsigned int index = lane->index; struct device *dev = padctl->dev; int err; + u32 reg; port = tegra_xusb_find_usb2_port(padctl, index); if (!port) { @@ -935,6 +944,16 @@ static int tegra186_utmi_phy_init(struct phy *phy) return -ENODEV; } + if (port->mode == USB_DR_MODE_OTG || + port->mode == USB_DR_MODE_PERIPHERAL) { + /* reset VBUS&ID OVERRIDE */ + reg = padctl_readl(padctl, USB2_VBUS_ID); + reg &= ~VBUS_OVERRIDE; + reg &= ~ID_OVERRIDE(~0); + reg |= ID_OVERRIDE_FLOATING; + padctl_writel(padctl, reg, USB2_VBUS_ID); + } + if (port->supply && port->mode == USB_DR_MODE_HOST) { err = regulator_enable(port->supply); if (err) { diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index 142ebe0247cc..c89df95aa6ca 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -22,7 +22,7 @@ #include "xusb.h" static struct phy *tegra_xusb_pad_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct tegra_xusb_pad *pad = dev_get_drvdata(dev); struct phy *phy = NULL; @@ -543,21 +543,21 @@ static int tegra_xusb_port_init(struct tegra_xusb_port *port, device_initialize(&port->dev); port->dev.type = &tegra_xusb_port_type; - port->dev.of_node = of_node_get(np); + device_set_node(&port->dev, of_fwnode_handle(of_node_get(np))); port->dev.parent = padctl->dev; 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; } @@ -699,6 +699,8 @@ static int tegra_xusb_setup_usb_role_switch(struct tegra_xusb_port *port) return -ENOMEM; lane = tegra_xusb_find_lane(port->padctl, "usb2", port->index); + if (IS_ERR(lane)) + return PTR_ERR(lane); /* * Assign phy dev to usb-phy dev. Host/device drivers can use phy @@ -1325,7 +1327,7 @@ static struct platform_driver tegra_xusb_padctl_driver = { .pm = &tegra_xusb_padctl_pm_ops, }, .probe = tegra_xusb_padctl_probe, - .remove_new = tegra_xusb_padctl_remove, + .remove = tegra_xusb_padctl_remove, }; module_platform_driver(tegra_xusb_padctl_driver); @@ -1531,6 +1533,19 @@ int tegra_xusb_padctl_get_usb3_companion(struct tegra_xusb_padctl *padctl, } EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_usb3_companion); +int tegra_xusb_padctl_get_port_number(struct phy *phy) +{ + struct tegra_xusb_lane *lane; + + if (!phy) + return -ENODEV; + + lane = phy_get_drvdata(phy); + + return lane->index; +} +EXPORT_SYMBOL_GPL(tegra_xusb_padctl_get_port_number); + MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>"); MODULE_DESCRIPTION("Tegra XUSB Pad Controller driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c index 3f1d43e8b7ad..431b223996e0 100644 --- a/drivers/phy/ti/phy-am654-serdes.c +++ b/drivers/phy/ti/phy-am654-serdes.c @@ -7,6 +7,7 @@ */ #include <dt-bindings/phy/phy.h> +#include <linux/cleanup.h> #include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/delay.h> @@ -30,7 +31,6 @@ #define LANE_R058 0x258 #define LANE_R06c 0x26c #define LANE_R070 0x270 -#define LANE_R070 0x270 #define LANE_R19C 0x39c #define COMLANE_R004 0xa04 @@ -495,7 +495,7 @@ static void serdes_am654_release(struct phy *x) } static struct phy *serdes_am654_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct serdes_am654 *am654_phy; struct phy *phy; @@ -645,7 +645,6 @@ static int serdes_am654_clk_register(struct serdes_am654 *am654_phy, struct device_node *node = am654_phy->of_node; struct device *dev = am654_phy->dev; struct serdes_am654_clk_mux *mux; - struct device_node *regmap_node; const char **parent_names; struct clk_init_data *init; unsigned int num_parents; @@ -653,7 +652,6 @@ static int serdes_am654_clk_register(struct serdes_am654 *am654_phy, const __be32 *addr; unsigned int reg; struct clk *clk; - int ret = 0; mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); if (!mux) @@ -661,41 +659,30 @@ static int serdes_am654_clk_register(struct serdes_am654 *am654_phy, init = &mux->clk_data; - regmap_node = of_parse_phandle(node, "ti,serdes-clk", 0); - if (!regmap_node) { - dev_err(dev, "Fail to get serdes-clk node\n"); - ret = -ENODEV; - goto out_put_node; - } + struct device_node *regmap_node __free(device_node) = + of_parse_phandle(node, "ti,serdes-clk", 0); + if (!regmap_node) + return dev_err_probe(dev, -ENODEV, "Fail to get serdes-clk node\n"); regmap = syscon_node_to_regmap(regmap_node->parent); - if (IS_ERR(regmap)) { - dev_err(dev, "Fail to get Syscon regmap\n"); - ret = PTR_ERR(regmap); - goto out_put_node; - } + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "Fail to get Syscon regmap\n"); num_parents = of_clk_get_parent_count(node); - if (num_parents < 2) { - dev_err(dev, "SERDES clock must have parents\n"); - ret = -EINVAL; - goto out_put_node; - } + if (num_parents < 2) + return dev_err_probe(dev, -EINVAL, "SERDES clock must have parents\n"); parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), GFP_KERNEL); - if (!parent_names) { - ret = -ENOMEM; - goto out_put_node; - } + if (!parent_names) + return -ENOMEM; of_clk_parent_fill(node, parent_names, num_parents); addr = of_get_address(regmap_node, 0, NULL, NULL); - if (!addr) { - ret = -EINVAL; - goto out_put_node; - } + if (!addr) + return -EINVAL; reg = be32_to_cpu(*addr); @@ -711,16 +698,12 @@ static int serdes_am654_clk_register(struct serdes_am654 *am654_phy, mux->hw.init = init; clk = devm_clk_register(dev, &mux->hw); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - goto out_put_node; - } + if (IS_ERR(clk)) + return PTR_ERR(clk); am654_phy->clks[clock_num] = clk; -out_put_node: - of_node_put(regmap_node); - return ret; + return 0; } static const struct of_device_id serdes_am654_id_table[] = { @@ -854,7 +837,7 @@ static void serdes_am654_remove(struct platform_device *pdev) static struct platform_driver serdes_am654_driver = { .probe = serdes_am654_probe, - .remove_new = serdes_am654_remove, + .remove = serdes_am654_remove, .driver = { .name = "phy-am654", .of_match_table = serdes_am654_id_table, diff --git a/drivers/phy/ti/phy-da8xx-usb.c b/drivers/phy/ti/phy-da8xx-usb.c index b7a9ef3f4654..1d81a1e6ec6b 100644 --- a/drivers/phy/ti/phy-da8xx-usb.c +++ b/drivers/phy/ti/phy-da8xx-usb.c @@ -14,11 +14,13 @@ #include <linux/phy/phy.h> #include <linux/platform_data/phy-da8xx-usb.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #define PHY_INIT_BITS (CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN) struct da8xx_usb_phy { + struct device *dev; struct phy_provider *phy_provider; struct phy *usb11_phy; struct phy *usb20_phy; @@ -39,6 +41,12 @@ static int da8xx_usb11_phy_power_on(struct phy *phy) regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, CFGCHIP2_USB1SUSPENDM); + /* + * USB1.1 can used USB2.0 output clock as reference clock so this is here to prevent USB2.0 + * from shutting PHY's power when USB1.1 might use it + */ + pm_runtime_get_sync(d_phy->dev); + return 0; } @@ -49,6 +57,7 @@ static int da8xx_usb11_phy_power_off(struct phy *phy) regmap_write_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_USB1SUSPENDM, 0); clk_disable_unprepare(d_phy->usb11_clk); + pm_runtime_put_sync(d_phy->dev); return 0; } @@ -118,8 +127,37 @@ static const struct phy_ops da8xx_usb20_phy_ops = { .owner = THIS_MODULE, }; +static int __maybe_unused da8xx_runtime_suspend(struct device *dev) +{ + struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev); + + dev_dbg(dev, "Suspending ...\n"); + + regmap_set_bits(d_phy->regmap, CFGCHIP(2), CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN); + + return 0; +} + +static int __maybe_unused da8xx_runtime_resume(struct device *dev) +{ + u32 mask = CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN | CFGCHIP2_PHY_PLLON; + struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev); + u32 pll_status; + + regmap_update_bits(d_phy->regmap, CFGCHIP(2), mask, CFGCHIP2_PHY_PLLON); + + dev_dbg(dev, "Resuming ...\n"); + + return regmap_read_poll_timeout(d_phy->regmap, CFGCHIP(2), pll_status, + pll_status & CFGCHIP2_PHYCLKGD, 1000, 500000); +} + +static const struct dev_pm_ops da8xx_usb_phy_pm_ops = { + SET_RUNTIME_PM_OPS(da8xx_runtime_suspend, da8xx_runtime_resume, NULL) +}; + static struct phy *da8xx_usb_phy_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct da8xx_usb_phy *d_phy = dev_get_drvdata(dev); @@ -147,6 +185,8 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) if (!d_phy) return -ENOMEM; + d_phy->dev = dev; + if (pdata) d_phy->regmap = pdata->cfgchip; else @@ -208,6 +248,14 @@ static int da8xx_usb_phy_probe(struct platform_device *pdev) regmap_write_bits(d_phy->regmap, CFGCHIP(2), PHY_INIT_BITS, PHY_INIT_BITS); + pm_runtime_set_active(dev); + devm_pm_runtime_enable(dev); + /* + * Prevent runtime pm from being ON by default. Users can enable + * it using power/control in sysfs. + */ + pm_runtime_forbid(dev); + return 0; } @@ -229,10 +277,11 @@ MODULE_DEVICE_TABLE(of, da8xx_usb_phy_ids); static struct platform_driver da8xx_usb_phy_driver = { .probe = da8xx_usb_phy_probe, - .remove_new = da8xx_usb_phy_remove, + .remove = da8xx_usb_phy_remove, .driver = { .name = "da8xx-usb-phy", - .of_match_table = da8xx_usb_phy_ids, + .pm = &da8xx_usb_phy_pm_ops, + .of_match_table = da8xx_usb_phy_ids, }, }; diff --git a/drivers/phy/ti/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c index d5ae972a31fb..e8f842d4e841 100644 --- a/drivers/phy/ti/phy-dm816x-usb.c +++ b/drivers/phy/ti/phy-dm816x-usb.c @@ -259,7 +259,7 @@ static void dm816x_usb_phy_remove(struct platform_device *pdev) static struct platform_driver dm816x_usb_phy_driver = { .probe = dm816x_usb_phy_probe, - .remove_new = dm816x_usb_phy_remove, + .remove = dm816x_usb_phy_remove, .driver = { .name = "dm816x-usb-phy", .pm = &dm816x_usb_phy_pm_ops, diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c index 0f4818adb440..ff5d5e29629f 100644 --- a/drivers/phy/ti/phy-gmii-sel.c +++ b/drivers/phy/ti/phy-gmii-sel.c @@ -230,7 +230,8 @@ static const struct phy_gmii_sel_soc_data phy_gmii_sel_cpsw5g_soc_j7200 = { .use_of_data = true, .regfields = phy_gmii_sel_fields_am654, - .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII), + .extra_modes = BIT(PHY_INTERFACE_MODE_QSGMII) | BIT(PHY_INTERFACE_MODE_SGMII) | + BIT(PHY_INTERFACE_MODE_USXGMII), .num_ports = 4, .num_qsgmii_main_ports = 1, }; @@ -297,7 +298,7 @@ static const struct phy_ops phy_gmii_sel_ops = { }; static struct phy *phy_gmii_sel_of_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev); int phy_id = args->args[0]; @@ -423,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; @@ -467,12 +474,17 @@ 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); - if (IS_ERR(priv->regmap)) { - ret = PTR_ERR(priv->regmap); - dev_err(dev, "Failed to get syscon %d\n", ret); - return ret; - } + 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"); priv->no_offset = true; } @@ -485,20 +497,42 @@ static int phy_gmii_sel_probe(struct platform_device *pdev) priv->phy_provider = devm_of_phy_provider_register(dev, phy_gmii_sel_of_xlate); - if (IS_ERR(priv->phy_provider)) { - ret = PTR_ERR(priv->phy_provider); - dev_err(dev, "Failed to create phy provider %d\n", ret); - return ret; + if (IS_ERR(priv->phy_provider)) + return dev_err_probe(dev, PTR_ERR(priv->phy_provider), + "Failed to create phy provider\n"); + + return 0; +} + +static int phy_gmii_sel_resume_noirq(struct device *dev) +{ + struct phy_gmii_sel_priv *priv = dev_get_drvdata(dev); + struct phy_gmii_sel_phy_priv *if_phys = priv->if_phys; + int ret, i; + + for (i = 0; i < priv->num_ports; i++) { + if (if_phys[i].phy_if_mode) { + ret = phy_gmii_sel_mode(if_phys[i].if_phy, + PHY_MODE_ETHERNET, if_phys[i].phy_if_mode); + if (ret) { + dev_err(dev, "port%u: restore mode fail %d\n", + if_phys[i].if_phy->id, ret); + return ret; + } + } } return 0; } +static DEFINE_NOIRQ_DEV_PM_OPS(phy_gmii_sel_pm_ops, NULL, phy_gmii_sel_resume_noirq); + static struct platform_driver phy_gmii_sel_driver = { .probe = phy_gmii_sel_probe, .driver = { .name = "phy-gmii-sel", .of_match_table = phy_gmii_sel_id_table, + .pm = pm_sleep_ptr(&phy_gmii_sel_pm_ops), }, }; module_platform_driver(phy_gmii_sel_driver); diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 00d7e6a6de03..ab2a4f2c0a5b 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -450,8 +450,8 @@ static int wiz_mode_select(struct wiz *wiz) } else if (wiz->lane_phy_type[i] == PHY_TYPE_USXGMII) { ret = regmap_field_write(wiz->p0_mac_src_sel[i], 0x3); ret = regmap_field_write(wiz->p0_rxfclk_sel[i], 0x3); - ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x3); - mode = LANE_MODE_GEN1; + ret = regmap_field_write(wiz->p0_refclk_sel[i], 0x2); + mode = LANE_MODE_GEN2; } else { continue; } @@ -1076,27 +1076,12 @@ static int wiz_clock_register(struct wiz *wiz) return ret; } -static int wiz_clock_init(struct wiz *wiz, struct device_node *node) +static void wiz_clock_init(struct wiz *wiz) { - const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; - struct device *dev = wiz->dev; - struct device_node *clk_node; - const char *node_name; unsigned long rate; - struct clk *clk; - int ret; - int i; - - clk = devm_clk_get(dev, "core_ref_clk"); - if (IS_ERR(clk)) { - dev_err(dev, "core_ref_clk clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - wiz->input_clks[WIZ_CORE_REFCLK] = clk; - rate = clk_get_rate(clk); - if (rate >= 100000000) + rate = clk_get_rate(wiz->input_clks[WIZ_CORE_REFCLK]); + if (rate >= REF_CLK_100MHZ) regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x1); else regmap_field_write(wiz->pma_cmn_refclk_int_mode, 0x3); @@ -1120,35 +1105,55 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) break; } - if (wiz->data->pma_cmn_refclk1_int_mode) { - clk = devm_clk_get(dev, "core_ref1_clk"); - if (IS_ERR(clk)) { - dev_err(dev, "core_ref1_clk clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - wiz->input_clks[WIZ_CORE_REFCLK1] = clk; - - rate = clk_get_rate(clk); - if (rate >= 100000000) + if (wiz->input_clks[WIZ_CORE_REFCLK1]) { + rate = clk_get_rate(wiz->input_clks[WIZ_CORE_REFCLK1]); + if (rate >= REF_CLK_100MHZ) regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x1); else regmap_field_write(wiz->pma_cmn_refclk1_int_mode, 0x3); } - clk = devm_clk_get(dev, "ext_ref_clk"); - if (IS_ERR(clk)) { - dev_err(dev, "ext_ref_clk clock not found\n"); - ret = PTR_ERR(clk); - return ret; - } - wiz->input_clks[WIZ_EXT_REFCLK] = clk; - - rate = clk_get_rate(clk); - if (rate >= 100000000) + rate = clk_get_rate(wiz->input_clks[WIZ_EXT_REFCLK]); + if (rate >= REF_CLK_100MHZ) regmap_field_write(wiz->pma_cmn_refclk_mode, 0x0); else regmap_field_write(wiz->pma_cmn_refclk_mode, 0x2); +} + +static int wiz_clock_probe(struct wiz *wiz, struct device_node *node) +{ + const struct wiz_clk_mux_sel *clk_mux_sel = wiz->clk_mux_sel; + struct device *dev = wiz->dev; + struct device_node *clk_node; + const char *node_name; + struct clk *clk; + int ret; + int i; + + clk = devm_clk_get(dev, "core_ref_clk"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "core_ref_clk clock not found\n"); + + wiz->input_clks[WIZ_CORE_REFCLK] = clk; + + if (wiz->data->pma_cmn_refclk1_int_mode) { + clk = devm_clk_get(dev, "core_ref1_clk"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "core_ref1_clk clock not found\n"); + + wiz->input_clks[WIZ_CORE_REFCLK1] = clk; + } + + clk = devm_clk_get(dev, "ext_ref_clk"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "ext_ref_clk clock not found\n"); + + wiz->input_clks[WIZ_EXT_REFCLK] = clk; + + wiz_clock_init(wiz); switch (wiz->type) { case AM64_WIZ_10G: @@ -1157,8 +1162,9 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) case J721S2_WIZ_10G: ret = wiz_clock_register(wiz); if (ret) - dev_err(dev, "Failed to register wiz clocks\n"); - return ret; + return dev_err_probe(dev, ret, "Failed to register wiz clocks\n"); + + return 0; default: break; } @@ -1167,42 +1173,37 @@ static int wiz_clock_init(struct wiz *wiz, struct device_node *node) node_name = clk_mux_sel[i].node_name; clk_node = of_get_child_by_name(node, node_name); if (!clk_node) { - dev_err(dev, "Unable to get %s node\n", node_name); - ret = -EINVAL; + ret = dev_err_probe(dev, -EINVAL, "Unable to get %s node\n", node_name); goto err; } ret = wiz_mux_of_clk_register(wiz, clk_node, wiz->mux_sel_field[i], clk_mux_sel[i].table); + of_node_put(clk_node); if (ret) { - dev_err(dev, "Failed to register %s clock\n", - node_name); - of_node_put(clk_node); + dev_err_probe(dev, ret, "Failed to register %s clock\n", + node_name); goto err; } - of_node_put(clk_node); } for (i = 0; i < wiz->clk_div_sel_num; i++) { node_name = clk_div_sel[i].node_name; clk_node = of_get_child_by_name(node, node_name); if (!clk_node) { - dev_err(dev, "Unable to get %s node\n", node_name); - ret = -EINVAL; + ret = dev_err_probe(dev, -EINVAL, "Unable to get %s node\n", node_name); goto err; } ret = wiz_div_clk_register(wiz, clk_node, wiz->div_sel_field[i], clk_div_sel[i].table); + of_node_put(clk_node); if (ret) { - dev_err(dev, "Failed to register %s clock\n", - node_name); - of_node_put(clk_node); + dev_err_probe(dev, ret, "Failed to register %s clock\n", + node_name); goto err; } - - of_node_put(clk_node); } return 0; @@ -1403,7 +1404,7 @@ MODULE_DEVICE_TABLE(of, wiz_id_table); static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) { - struct device_node *serdes, *subnode; + struct device_node *serdes; serdes = of_get_child_by_name(dev->of_node, "serdes"); if (!serdes) { @@ -1411,7 +1412,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) return -EINVAL; } - for_each_child_of_node(serdes, subnode) { + for_each_child_of_node_scoped(serdes, subnode) { u32 reg, num_lanes = 1, phy_type = PHY_NONE; int ret, i; @@ -1421,7 +1422,6 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) ret = of_property_read_u32(subnode, "reg", ®); if (ret) { - of_node_put(subnode); dev_err(dev, "%s: Reading \"reg\" from \"%s\" failed: %d\n", __func__, subnode->name, ret); @@ -1574,8 +1574,8 @@ static int wiz_probe(struct platform_device *pdev) phy_reset_dev = &wiz->wiz_phy_reset_dev; phy_reset_dev->dev = dev; - phy_reset_dev->ops = &wiz_phy_reset_ops, - phy_reset_dev->owner = THIS_MODULE, + phy_reset_dev->ops = &wiz_phy_reset_ops; + phy_reset_dev->owner = THIS_MODULE; phy_reset_dev->of_node = node; /* Reset for each of the lane and one for the entire SERDES */ phy_reset_dev->nr_resets = num_lanes + 1; @@ -1593,7 +1593,7 @@ static int wiz_probe(struct platform_device *pdev) goto err_get_sync; } - ret = wiz_clock_init(wiz, node); + ret = wiz_clock_probe(wiz, node); if (ret < 0) { dev_warn(dev, "Failed to initialize clocks\n"); goto err_get_sync; @@ -1655,12 +1655,41 @@ static void wiz_remove(struct platform_device *pdev) pm_runtime_disable(dev); } +static int wiz_resume_noirq(struct device *dev) +{ + struct device_node *node = dev->of_node; + struct wiz *wiz = dev_get_drvdata(dev); + int ret; + + /* Enable supplemental Control override if available */ + if (wiz->sup_legacy_clk_override) + regmap_field_write(wiz->sup_legacy_clk_override, 1); + + wiz_clock_init(wiz); + + ret = wiz_init(wiz); + if (ret) { + dev_err(dev, "WIZ initialization failed\n"); + goto err_wiz_init; + } + + return 0; + +err_wiz_init: + wiz_clock_cleanup(wiz, node); + + return ret; +} + +static DEFINE_NOIRQ_DEV_PM_OPS(wiz_pm_ops, NULL, wiz_resume_noirq); + static struct platform_driver wiz_driver = { .probe = wiz_probe, - .remove_new = wiz_remove, + .remove = wiz_remove, .driver = { .name = "wiz", .of_match_table = wiz_id_table, + .pm = pm_sleep_ptr(&wiz_pm_ops), }, }; module_platform_driver(wiz_driver); diff --git a/drivers/phy/ti/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c index dd2913ac0fa2..c1a0ef979142 100644 --- a/drivers/phy/ti/phy-omap-usb2.c +++ b/drivers/phy/ti/phy-omap-usb2.c @@ -117,7 +117,7 @@ static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) { struct omap_usb *phy = phy_to_omapusb(otg->usb_phy); - if (!phy->comparator) + if (!phy->comparator || !phy->comparator->set_vbus) return -ENODEV; return phy->comparator->set_vbus(phy->comparator, enabled); @@ -127,7 +127,7 @@ static int omap_usb_start_srp(struct usb_otg *otg) { struct omap_usb *phy = phy_to_omapusb(otg->usb_phy); - if (!phy->comparator) + if (!phy->comparator || !phy->comparator->start_srp) return -ENODEV; return phy->comparator->start_srp(phy->comparator); @@ -511,7 +511,7 @@ static void omap_usb2_remove(struct platform_device *pdev) static struct platform_driver omap_usb2_driver = { .probe = omap_usb2_probe, - .remove_new = omap_usb2_remove, + .remove = omap_usb2_remove, .driver = { .name = "omap-usb2", .of_match_table = omap_usb2_id_table, diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c index 874c1a25ce36..da2cbacb982c 100644 --- a/drivers/phy/ti/phy-ti-pipe3.c +++ b/drivers/phy/ti/phy-ti-pipe3.c @@ -920,7 +920,7 @@ MODULE_DEVICE_TABLE(of, ti_pipe3_id_table); static struct platform_driver ti_pipe3_driver = { .probe = ti_pipe3_probe, - .remove_new = ti_pipe3_remove, + .remove = ti_pipe3_remove, .driver = { .name = "ti-pipe3", .of_match_table = ti_pipe3_id_table, diff --git a/drivers/phy/ti/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c index b4881cb34475..c3ae9d7948d7 100644 --- a/drivers/phy/ti/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -17,6 +17,10 @@ #include <linux/property.h> #include <linux/workqueue.h> +#define TI_VENDOR_ID 0x0451 +#define TI_DEVICE_TUSB1210 0x1507 +#define TI_DEVICE_TUSB1211 0x1508 + #define TUSB1211_POWER_CONTROL 0x3d #define TUSB1211_POWER_CONTROL_SET 0x3e #define TUSB1211_POWER_CONTROL_CLEAR 0x3f @@ -52,7 +56,7 @@ enum tusb1210_chg_det_state { }; struct tusb1210 { - struct ulpi *ulpi; + struct device *dev; struct phy *phy; struct gpio_desc *gpio_reset; struct gpio_desc *gpio_cs; @@ -65,32 +69,32 @@ struct tusb1210 { struct delayed_work chg_det_work; struct notifier_block psy_nb; struct power_supply *psy; - struct power_supply *charger; #endif }; static int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val) { + struct device *dev = tusb->dev; int ret; - ret = ulpi_write(tusb->ulpi, reg, val); + ret = ulpi_write(to_ulpi_dev(dev), reg, val); if (ret) - dev_err(&tusb->ulpi->dev, "error %d writing val 0x%02x to reg 0x%02x\n", - ret, val, reg); + dev_err(dev, "error %d writing val 0x%02x to reg 0x%02x\n", ret, val, reg); return ret; } static int tusb1210_ulpi_read(struct tusb1210 *tusb, u8 reg, u8 *val) { + struct device *dev = tusb->dev; int ret; - ret = ulpi_read(tusb->ulpi, reg); + ret = ulpi_read(to_ulpi_dev(dev), reg); if (ret >= 0) { *val = ret; ret = 0; } else { - dev_err(&tusb->ulpi->dev, "error %d reading reg 0x%02x\n", ret, reg); + dev_err(dev, "error %d reading reg 0x%02x\n", ret, reg); } return ret; @@ -178,7 +182,7 @@ static void tusb1210_reset(struct tusb1210 *tusb) static void tusb1210_chg_det_set_type(struct tusb1210 *tusb, enum power_supply_usb_type type) { - dev_dbg(&tusb->ulpi->dev, "charger type: %d\n", type); + dev_dbg(tusb->dev, "charger type: %d\n", type); tusb->chg_type = type; tusb->chg_det_retries = 0; power_supply_changed(tusb->psy); @@ -189,7 +193,7 @@ static void tusb1210_chg_det_set_state(struct tusb1210 *tusb, int delay_ms) { if (delay_ms) - dev_dbg(&tusb->ulpi->dev, "chg_det new state %s in %d ms\n", + dev_dbg(tusb->dev, "chg_det new state %s in %d ms\n", tusb1210_chg_det_states[new_state], delay_ms); tusb->chg_det_state = new_state; @@ -231,19 +235,24 @@ static const char * const tusb1210_chargers[] = { static bool tusb1210_get_online(struct tusb1210 *tusb) { + struct power_supply *charger = NULL; union power_supply_propval val; - int i; + bool online = false; + int i, ret; - for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !tusb->charger; i++) - tusb->charger = power_supply_get_by_name(tusb1210_chargers[i]); + for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !charger; i++) + charger = power_supply_get_by_name(tusb1210_chargers[i]); - if (!tusb->charger) + if (!charger) return false; - if (power_supply_get_property(tusb->charger, POWER_SUPPLY_PROP_ONLINE, &val)) - return false; + ret = power_supply_get_property(charger, POWER_SUPPLY_PROP_ONLINE, &val); + if (ret == 0) + online = val.intval; - return val.intval; + power_supply_put(charger); + + return online; } static void tusb1210_chg_det_work(struct work_struct *work) @@ -253,7 +262,7 @@ static void tusb1210_chg_det_work(struct work_struct *work) int ret; u8 val; - dev_dbg(&tusb->ulpi->dev, "chg_det state %s vbus_present %d\n", + dev_dbg(tusb->dev, "chg_det state %s vbus_present %d\n", tusb1210_chg_det_states[tusb->chg_det_state], vbus_present); switch (tusb->chg_det_state) { @@ -261,9 +270,9 @@ static void tusb1210_chg_det_work(struct work_struct *work) tusb->chg_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; tusb->chg_det_retries = 0; /* Power on USB controller for ulpi_read()/_write() */ - ret = pm_runtime_resume_and_get(tusb->ulpi->dev.parent); + ret = pm_runtime_resume_and_get(tusb->dev->parent); if (ret < 0) { - dev_err(&tusb->ulpi->dev, "error %d runtime-resuming\n", ret); + dev_err(tusb->dev, "error %d runtime-resuming\n", ret); /* Should never happen, skip charger detection */ tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0); return; @@ -332,7 +341,7 @@ static void tusb1210_chg_det_work(struct work_struct *work) mutex_unlock(&tusb->phy->mutex); - pm_runtime_put(tusb->ulpi->dev.parent); + pm_runtime_put(tusb->dev->parent); tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0); break; case TUSB1210_CHG_DET_CONNECTED: @@ -402,12 +411,6 @@ static int tusb1210_psy_get_prop(struct power_supply *psy, return 0; } -static const enum power_supply_usb_type tusb1210_psy_usb_types[] = { - POWER_SUPPLY_USB_TYPE_SDP, - POWER_SUPPLY_USB_TYPE_DCP, - POWER_SUPPLY_USB_TYPE_UNKNOWN, -}; - static const enum power_supply_property tusb1210_psy_props[] = { POWER_SUPPLY_PROP_ONLINE, POWER_SUPPLY_PROP_USB_TYPE, @@ -417,8 +420,9 @@ static const enum power_supply_property tusb1210_psy_props[] = { static const struct power_supply_desc tusb1210_psy_desc = { .name = "tusb1211-charger-detect", .type = POWER_SUPPLY_TYPE_USB, - .usb_types = tusb1210_psy_usb_types, - .num_usb_types = ARRAY_SIZE(tusb1210_psy_usb_types), + .usb_types = BIT(POWER_SUPPLY_USB_TYPE_SDP) | + BIT(POWER_SUPPLY_USB_TYPE_DCP) | + BIT(POWER_SUPPLY_USB_TYPE_UNKNOWN), .properties = tusb1210_psy_props, .num_properties = ARRAY_SIZE(tusb1210_psy_props), .get_property = tusb1210_psy_get_prop, @@ -428,13 +432,14 @@ static const struct power_supply_desc tusb1210_psy_desc = { static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { struct power_supply_config psy_cfg = { .drv_data = tusb }; - struct device *dev = &tusb->ulpi->dev; + struct device *dev = tusb->dev; + struct ulpi *ulpi = to_ulpi_dev(dev); int ret; if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect")) return; - if (tusb->ulpi->id.product != 0x1508) { + if (ulpi->id.product != TI_DEVICE_TUSB1211) { dev_err(dev, "error charger detection is only supported on the TUSB1211\n"); return; } @@ -467,9 +472,6 @@ static void tusb1210_remove_charger_detect(struct tusb1210 *tusb) cancel_delayed_work_sync(&tusb->chg_det_work); power_supply_unregister(tusb->psy); } - - if (tusb->charger) - power_supply_put(tusb->charger); } #else static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { } @@ -485,25 +487,24 @@ static const struct phy_ops phy_ops = { static int tusb1210_probe(struct ulpi *ulpi) { + struct device *dev = &ulpi->dev; struct tusb1210 *tusb; u8 val, reg; int ret; - tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL); + tusb = devm_kzalloc(dev, sizeof(*tusb), GFP_KERNEL); if (!tusb) return -ENOMEM; - tusb->ulpi = ulpi; + tusb->dev = dev; - tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset", - GPIOD_OUT_LOW); + tusb->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(tusb->gpio_reset)) return PTR_ERR(tusb->gpio_reset); gpiod_set_value_cansleep(tusb->gpio_reset, 1); - tusb->gpio_cs = devm_gpiod_get_optional(&ulpi->dev, "cs", - GPIOD_OUT_LOW); + tusb->gpio_cs = devm_gpiod_get_optional(dev, "cs", GPIOD_OUT_LOW); if (IS_ERR(tusb->gpio_cs)) return PTR_ERR(tusb->gpio_cs); @@ -519,15 +520,15 @@ static int tusb1210_probe(struct ulpi *ulpi) return ret; /* High speed output drive strength configuration */ - if (!device_property_read_u8(&ulpi->dev, "ihstx", &val)) + if (!device_property_read_u8(dev, "ihstx", &val)) u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK); /* High speed output impedance configuration */ - if (!device_property_read_u8(&ulpi->dev, "zhsdrv", &val)) + if (!device_property_read_u8(dev, "zhsdrv", &val)) u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK); /* DP/DM swap control */ - if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val)) + if (!device_property_read_u8(dev, "datapolarity", &val)) u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK); ret = tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, reg); @@ -561,11 +562,9 @@ static void tusb1210_remove(struct ulpi *ulpi) tusb1210_remove_charger_detect(tusb); } -#define TI_VENDOR_ID 0x0451 - static const struct ulpi_device_id tusb1210_ulpi_id[] = { - { TI_VENDOR_ID, 0x1507, }, /* TUSB1210 */ - { TI_VENDOR_ID, 0x1508, }, /* TUSB1211 */ + { TI_VENDOR_ID, TI_DEVICE_TUSB1210 }, + { TI_VENDOR_ID, TI_DEVICE_TUSB1211 }, { }, }; MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id); diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index 6b265992d988..6f12b38cd894 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -834,7 +834,7 @@ MODULE_DEVICE_TABLE(of, twl4030_usb_id_table); static struct platform_driver twl4030_usb_driver = { .probe = twl4030_usb_probe, - .remove_new = twl4030_usb_remove, + .remove = twl4030_usb_remove, .driver = { .name = "twl4030_usb", .pm = &twl4030_usb_pm_ops, diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index 2559c6594cea..fe6b4925d166 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -13,6 +13,7 @@ */ #include <linux/clk.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/kernel.h> @@ -80,7 +81,8 @@ /* Reference clock selection parameters */ #define L0_Ln_REF_CLK_SEL(n) (0x2860 + (n) * 4) -#define L0_REF_CLK_SEL_MASK 0x8f +#define L0_REF_CLK_LCL_SEL BIT(7) +#define L0_REF_CLK_SEL_MASK 0x9f /* Calibration digital logic parameters */ #define L3_TM_CALIB_DIG19 0xec4c @@ -122,6 +124,15 @@ #define ICM_PROTOCOL_DP 0x4 #define ICM_PROTOCOL_SGMII 0x5 +static const char *const xpsgtr_icm_str[] = { + [ICM_PROTOCOL_PD] = "none", + [ICM_PROTOCOL_PCIE] = "PCIe", + [ICM_PROTOCOL_SATA] = "SATA", + [ICM_PROTOCOL_USB] = "USB", + [ICM_PROTOCOL_DP] = "DisplayPort", + [ICM_PROTOCOL_SGMII] = "SGMII", +}; + /* Test Mode common reset control parameters */ #define TM_CMN_RST 0x10018 #define TM_CMN_RST_EN 0x1 @@ -146,25 +157,27 @@ /* Total number of controllers */ #define CONTROLLERS_PER_LANE 5 -/* Protocol Type parameters */ -#define XPSGTR_TYPE_USB0 0 /* USB controller 0 */ -#define XPSGTR_TYPE_USB1 1 /* USB controller 1 */ -#define XPSGTR_TYPE_SATA_0 2 /* SATA controller lane 0 */ -#define XPSGTR_TYPE_SATA_1 3 /* SATA controller lane 1 */ -#define XPSGTR_TYPE_PCIE_0 4 /* PCIe controller lane 0 */ -#define XPSGTR_TYPE_PCIE_1 5 /* PCIe controller lane 1 */ -#define XPSGTR_TYPE_PCIE_2 6 /* PCIe controller lane 2 */ -#define XPSGTR_TYPE_PCIE_3 7 /* PCIe controller lane 3 */ -#define XPSGTR_TYPE_DP_0 8 /* Display Port controller lane 0 */ -#define XPSGTR_TYPE_DP_1 9 /* Display Port controller lane 1 */ -#define XPSGTR_TYPE_SGMII0 10 /* Ethernet SGMII controller 0 */ -#define XPSGTR_TYPE_SGMII1 11 /* Ethernet SGMII controller 1 */ -#define XPSGTR_TYPE_SGMII2 12 /* Ethernet SGMII controller 2 */ -#define XPSGTR_TYPE_SGMII3 13 /* Ethernet SGMII controller 3 */ - /* Timeout values */ #define TIMEOUT_US 1000 +/* Lane 0/1/2/3 offset */ +#define DIG_8(n) ((0x4000 * (n)) + 0x1074) +#define ILL13(n) ((0x4000 * (n)) + 0x1994) +#define DIG_10(n) ((0x4000 * (n)) + 0x107c) +#define RST_DLY(n) ((0x4000 * (n)) + 0x19a4) +#define BYP_15(n) ((0x4000 * (n)) + 0x1038) +#define BYP_12(n) ((0x4000 * (n)) + 0x102c) +#define MISC3(n) ((0x4000 * (n)) + 0x19ac) +#define EQ11(n) ((0x4000 * (n)) + 0x1978) + +static u32 save_reg_address[] = { + /* Lane 0/1/2/3 Register */ + DIG_8(0), ILL13(0), DIG_10(0), RST_DLY(0), BYP_15(0), BYP_12(0), MISC3(0), EQ11(0), + DIG_8(1), ILL13(1), DIG_10(1), RST_DLY(1), BYP_15(1), BYP_12(1), MISC3(1), EQ11(1), + DIG_8(2), ILL13(2), DIG_10(2), RST_DLY(2), BYP_15(2), BYP_12(2), MISC3(2), EQ11(2), + DIG_8(3), ILL13(3), DIG_10(3), RST_DLY(3), BYP_15(3), BYP_12(3), MISC3(3), EQ11(3), +}; + struct xpsgtr_dev; /** @@ -184,7 +197,8 @@ struct xpsgtr_ssc { /** * struct xpsgtr_phy - representation of a lane * @phy: pointer to the kernel PHY device - * @type: controller which uses this lane + * @instance: instance of the protocol type (such as the lane within a + * protocol, or the USB/Ethernet controller) * @lane: lane number * @protocol: protocol in which the lane operates * @skip_phy_init: skip phy_init() if true @@ -193,7 +207,7 @@ struct xpsgtr_ssc { */ struct xpsgtr_phy { struct phy *phy; - u8 type; + u8 instance; u8 lane; u8 protocol; bool skip_phy_init; @@ -208,11 +222,11 @@ struct xpsgtr_phy { * @siou: siou base address * @gtr_mutex: mutex for locking * @phys: PHY lanes - * @refclk_sscs: spread spectrum settings for the reference clocks * @clk: reference clocks * @tx_term_fix: fix for GT issue * @saved_icm_cfg0: stored value of ICM CFG0 register * @saved_icm_cfg1: stored value of ICM CFG1 register + * @saved_regs: registers to be saved/restored during suspend/resume */ struct xpsgtr_dev { struct device *dev; @@ -220,11 +234,11 @@ struct xpsgtr_dev { void __iomem *siou; struct mutex gtr_mutex; /* mutex for locking */ struct xpsgtr_phy phys[NUM_LANES]; - const struct xpsgtr_ssc *refclk_sscs[NUM_LANES]; struct clk *clk[NUM_LANES]; bool tx_term_fix; unsigned int saved_icm_cfg0; unsigned int saved_icm_cfg1; + u32 *saved_regs; }; /* @@ -298,6 +312,32 @@ static inline void xpsgtr_clr_set_phy(struct xpsgtr_phy *gtr_phy, writel((readl(addr) & ~clr) | set, addr); } +/** + * xpsgtr_save_lane_regs - Saves registers on suspend + * @gtr_dev: pointer to phy controller context structure + */ +static void xpsgtr_save_lane_regs(struct xpsgtr_dev *gtr_dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(save_reg_address); i++) + gtr_dev->saved_regs[i] = xpsgtr_read(gtr_dev, + save_reg_address[i]); +} + +/** + * xpsgtr_restore_lane_regs - Restores registers on resume + * @gtr_dev: pointer to phy controller context structure + */ +static void xpsgtr_restore_lane_regs(struct xpsgtr_dev *gtr_dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(save_reg_address); i++) + xpsgtr_write(gtr_dev, save_reg_address[i], + gtr_dev->saved_regs[i]); +} + /* * Hardware Configuration */ @@ -308,10 +348,30 @@ static int xpsgtr_wait_pll_lock(struct phy *phy) struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy); struct xpsgtr_dev *gtr_dev = gtr_phy->dev; unsigned int timeout = TIMEOUT_US; + u8 protocol = gtr_phy->protocol; int ret; dev_dbg(gtr_dev->dev, "Waiting for PLL lock\n"); + /* + * For DP and PCIe, only the instance 0 PLL is used. Switch to that phy + * so we wait on the right PLL. + */ + if ((protocol == ICM_PROTOCOL_DP || protocol == ICM_PROTOCOL_PCIE) && + gtr_phy->instance) { + int i; + + for (i = 0; i < NUM_LANES; i++) { + gtr_phy = >r_dev->phys[i]; + + if (gtr_phy->protocol == protocol && !gtr_phy->instance) + goto got_phy; + } + + return -EBUSY; + } + +got_phy: while (1) { u32 reg = xpsgtr_read_phy(gtr_phy, L0_PLL_STATUS_READ_1); @@ -330,30 +390,58 @@ static int xpsgtr_wait_pll_lock(struct phy *phy) if (ret == -ETIMEDOUT) dev_err(gtr_dev->dev, - "lane %u (type %u, protocol %u): PLL lock timeout\n", - gtr_phy->lane, gtr_phy->type, gtr_phy->protocol); + "lane %u (protocol %u, instance %u): PLL lock timeout\n", + gtr_phy->lane, gtr_phy->protocol, gtr_phy->instance); return ret; } +/* Get the spread spectrum (SSC) settings for the reference clock rate */ +static const struct xpsgtr_ssc *xpsgtr_find_sscs(struct xpsgtr_phy *gtr_phy) +{ + unsigned long rate; + struct clk *clk; + unsigned int i; + + clk = gtr_phy->dev->clk[gtr_phy->refclk]; + rate = clk_get_rate(clk); + + for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) { + /* Allow an error of 100 ppm */ + unsigned long error = ssc_lookup[i].refclk_rate / 10000; + + if (abs(rate - ssc_lookup[i].refclk_rate) < error) + return &ssc_lookup[i]; + } + + dev_err(gtr_phy->dev->dev, "Invalid rate %lu for reference clock %u\n", + rate, gtr_phy->refclk); + + return NULL; +} + /* Configure PLL and spread-sprectrum clock. */ -static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy) +static int xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy) { const struct xpsgtr_ssc *ssc; u32 step_size; - ssc = gtr_phy->dev->refclk_sscs[gtr_phy->refclk]; + ssc = xpsgtr_find_sscs(gtr_phy); + if (!ssc) + return -EINVAL; + step_size = ssc->step_size; xpsgtr_clr_set(gtr_phy->dev, PLL_REF_SEL(gtr_phy->lane), PLL_FREQ_MASK, ssc->pll_ref_clk); /* Enable lane clock sharing, if required */ - if (gtr_phy->refclk != gtr_phy->lane) { - /* Lane3 Ref Clock Selection Register */ + if (gtr_phy->refclk == gtr_phy->lane) + xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane), + L0_REF_CLK_SEL_MASK, L0_REF_CLK_LCL_SEL); + else xpsgtr_clr_set(gtr_phy->dev, L0_Ln_REF_CLK_SEL(gtr_phy->lane), L0_REF_CLK_SEL_MASK, 1 << gtr_phy->refclk); - } /* SSC step size [7:0] */ xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_0_LSB, @@ -383,6 +471,8 @@ static void xpsgtr_configure_pll(struct xpsgtr_phy *gtr_phy) xpsgtr_clr_set_phy(gtr_phy, L0_PLL_SS_STEP_SIZE_3_MSB, STEP_SIZE_3_MASK, (step_size & STEP_SIZE_3_MASK) | FORCE_STEP_SIZE | FORCE_STEPS); + + return 0; } /* Configure the lane protocol. */ @@ -573,7 +663,7 @@ static int xpsgtr_phy_init(struct phy *phy) mutex_lock(>r_dev->gtr_mutex); /* Configure and enable the clock when peripheral phy_init call */ - if (clk_prepare_enable(gtr_dev->clk[gtr_phy->lane])) + if (clk_prepare_enable(gtr_dev->clk[gtr_phy->refclk])) goto out; /* Skip initialization if not required. */ @@ -595,7 +685,10 @@ static int xpsgtr_phy_init(struct phy *phy) * Configure the PLL, the lane protocol, and perform protocol-specific * initialization. */ - xpsgtr_configure_pll(gtr_phy); + ret = xpsgtr_configure_pll(gtr_phy); + if (ret) + goto out; + xpsgtr_lane_set_protocol(gtr_phy); switch (gtr_phy->protocol) { @@ -625,7 +718,7 @@ static int xpsgtr_phy_exit(struct phy *phy) gtr_phy->skip_phy_init = false; /* Ensure that disable clock only, which configure for lane */ - clk_disable_unprepare(gtr_dev->clk[gtr_phy->lane]); + clk_disable_unprepare(gtr_dev->clk[gtr_phy->refclk]); return 0; } @@ -638,16 +731,7 @@ static int xpsgtr_phy_power_on(struct phy *phy) /* Skip initialization if not required. */ if (!xpsgtr_phy_init_required(gtr_phy)) return ret; - /* - * Wait for the PLL to lock. For DP, only wait on DP0 to avoid - * cumulating waits for both lanes. The user is expected to initialize - * lane 0 last. - */ - if (gtr_phy->protocol != ICM_PROTOCOL_DP || - gtr_phy->type == XPSGTR_TYPE_DP_0) - ret = xpsgtr_wait_pll_lock(phy); - - return ret; + return xpsgtr_wait_pll_lock(phy); } static int xpsgtr_phy_configure(struct phy *phy, union phy_configure_opts *opts) @@ -674,73 +758,33 @@ static const struct phy_ops xpsgtr_phyops = { * OF Xlate Support */ -/* Set the lane type and protocol based on the PHY type and instance number. */ +/* Set the lane protocol and instance based on the PHY type and instance number. */ static int xpsgtr_set_lane_type(struct xpsgtr_phy *gtr_phy, u8 phy_type, unsigned int phy_instance) { unsigned int num_phy_types; - const int *phy_types; switch (phy_type) { - case PHY_TYPE_SATA: { - static const int types[] = { - XPSGTR_TYPE_SATA_0, - XPSGTR_TYPE_SATA_1, - }; - - phy_types = types; - num_phy_types = ARRAY_SIZE(types); + case PHY_TYPE_SATA: + num_phy_types = 2; gtr_phy->protocol = ICM_PROTOCOL_SATA; break; - } - case PHY_TYPE_USB3: { - static const int types[] = { - XPSGTR_TYPE_USB0, - XPSGTR_TYPE_USB1, - }; - - phy_types = types; - num_phy_types = ARRAY_SIZE(types); + case PHY_TYPE_USB3: + num_phy_types = 2; gtr_phy->protocol = ICM_PROTOCOL_USB; break; - } - case PHY_TYPE_DP: { - static const int types[] = { - XPSGTR_TYPE_DP_0, - XPSGTR_TYPE_DP_1, - }; - - phy_types = types; - num_phy_types = ARRAY_SIZE(types); + case PHY_TYPE_DP: + num_phy_types = 2; gtr_phy->protocol = ICM_PROTOCOL_DP; break; - } - case PHY_TYPE_PCIE: { - static const int types[] = { - XPSGTR_TYPE_PCIE_0, - XPSGTR_TYPE_PCIE_1, - XPSGTR_TYPE_PCIE_2, - XPSGTR_TYPE_PCIE_3, - }; - - phy_types = types; - num_phy_types = ARRAY_SIZE(types); + case PHY_TYPE_PCIE: + num_phy_types = 4; gtr_phy->protocol = ICM_PROTOCOL_PCIE; break; - } - case PHY_TYPE_SGMII: { - static const int types[] = { - XPSGTR_TYPE_SGMII0, - XPSGTR_TYPE_SGMII1, - XPSGTR_TYPE_SGMII2, - XPSGTR_TYPE_SGMII3, - }; - - phy_types = types; - num_phy_types = ARRAY_SIZE(types); + case PHY_TYPE_SGMII: + num_phy_types = 4; gtr_phy->protocol = ICM_PROTOCOL_SGMII; break; - } default: return -EINVAL; } @@ -748,27 +792,30 @@ static int xpsgtr_set_lane_type(struct xpsgtr_phy *gtr_phy, u8 phy_type, if (phy_instance >= num_phy_types) return -EINVAL; - gtr_phy->type = phy_types[phy_instance]; + gtr_phy->instance = phy_instance; return 0; } /* - * Valid combinations of controllers and lanes (Interconnect Matrix). + * Valid combinations of controllers and lanes (Interconnect Matrix). Each + * "instance" represents one controller for a lane. For PCIe and DP, the + * "instance" is the logical lane in the link. For SATA, USB, and SGMII, + * the instance is the index of the controller. + * + * This information is only used to validate the devicetree reference, and is + * not used when programming the hardware. */ static const unsigned int icm_matrix[NUM_LANES][CONTROLLERS_PER_LANE] = { - { XPSGTR_TYPE_PCIE_0, XPSGTR_TYPE_SATA_0, XPSGTR_TYPE_USB0, - XPSGTR_TYPE_DP_1, XPSGTR_TYPE_SGMII0 }, - { XPSGTR_TYPE_PCIE_1, XPSGTR_TYPE_SATA_1, XPSGTR_TYPE_USB0, - XPSGTR_TYPE_DP_0, XPSGTR_TYPE_SGMII1 }, - { XPSGTR_TYPE_PCIE_2, XPSGTR_TYPE_SATA_0, XPSGTR_TYPE_USB0, - XPSGTR_TYPE_DP_1, XPSGTR_TYPE_SGMII2 }, - { XPSGTR_TYPE_PCIE_3, XPSGTR_TYPE_SATA_1, XPSGTR_TYPE_USB1, - XPSGTR_TYPE_DP_0, XPSGTR_TYPE_SGMII3 } + /* PCIe, SATA, USB, DP, SGMII */ + { 0, 0, 0, 1, 0 }, /* Lane 0 */ + { 1, 1, 0, 0, 1 }, /* Lane 1 */ + { 2, 0, 0, 1, 2 }, /* Lane 2 */ + { 3, 1, 1, 0, 3 }, /* Lane 3 */ }; /* Translate OF phandle and args to PHY instance. */ static struct phy *xpsgtr_xlate(struct device *dev, - struct of_phandle_args *args) + const struct of_phandle_args *args) { struct xpsgtr_dev *gtr_dev = dev_get_drvdata(dev); struct xpsgtr_phy *gtr_phy; @@ -798,6 +845,7 @@ static struct phy *xpsgtr_xlate(struct device *dev, phy_type = args->args[1]; phy_instance = args->args[2]; + guard(mutex)(>r_phy->phy->mutex); ret = xpsgtr_set_lane_type(gtr_phy, phy_type, phy_instance); if (ret < 0) { dev_err(gtr_dev->dev, "Invalid PHY type and/or instance\n"); @@ -805,8 +853,7 @@ static struct phy *xpsgtr_xlate(struct device *dev, } refclk = args->args[3]; - if (refclk >= ARRAY_SIZE(gtr_dev->refclk_sscs) || - !gtr_dev->refclk_sscs[refclk]) { + if (refclk >= ARRAY_SIZE(gtr_dev->clk)) { dev_err(dev, "Invalid reference clock number %u\n", refclk); return ERR_PTR(-EINVAL); } @@ -818,7 +865,7 @@ static struct phy *xpsgtr_xlate(struct device *dev, * is allowed to operate on the lane. */ for (i = 0; i < CONTROLLERS_PER_LANE; i++) { - if (icm_matrix[phy_lane][i] == gtr_phy->type) + if (icm_matrix[phy_lane][i] == gtr_phy->instance) return gtr_phy->phy; } @@ -826,6 +873,34 @@ static struct phy *xpsgtr_xlate(struct device *dev, } /* + * DebugFS + */ + +static int xpsgtr_status_read(struct seq_file *seq, void *data) +{ + struct device *dev = seq->private; + struct xpsgtr_phy *gtr_phy = dev_get_drvdata(dev); + struct clk *clk; + u32 pll_status; + + mutex_lock(>r_phy->phy->mutex); + pll_status = xpsgtr_read_phy(gtr_phy, L0_PLL_STATUS_READ_1); + clk = gtr_phy->dev->clk[gtr_phy->refclk]; + + seq_printf(seq, "Lane: %u\n", gtr_phy->lane); + seq_printf(seq, "Protocol: %s\n", + xpsgtr_icm_str[gtr_phy->protocol]); + seq_printf(seq, "Instance: %u\n", gtr_phy->instance); + seq_printf(seq, "Reference clock: %u (%pC)\n", gtr_phy->refclk, clk); + seq_printf(seq, "Reference rate: %lu\n", clk_get_rate(clk)); + seq_printf(seq, "PLL locked: %s\n", + pll_status & PLL_STATUS_LOCKED ? "yes" : "no"); + + mutex_unlock(>r_phy->phy->mutex); + return 0; +} + +/* * Power Management */ @@ -837,6 +912,8 @@ static int xpsgtr_runtime_suspend(struct device *dev) gtr_dev->saved_icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); gtr_dev->saved_icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); + xpsgtr_save_lane_regs(gtr_dev); + return 0; } @@ -847,6 +924,8 @@ static int xpsgtr_runtime_resume(struct device *dev) unsigned int i; bool skip_phy_init; + xpsgtr_restore_lane_regs(gtr_dev); + icm_cfg0 = xpsgtr_read(gtr_dev, ICM_CFG0); icm_cfg1 = xpsgtr_read(gtr_dev, ICM_CFG1); @@ -878,9 +957,7 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) { unsigned int refclk; - for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->refclk_sscs); ++refclk) { - unsigned long rate; - unsigned int i; + for (refclk = 0; refclk < ARRAY_SIZE(gtr_dev->clk); ++refclk) { struct clk *clk; char name[8]; @@ -896,29 +973,6 @@ static int xpsgtr_get_ref_clocks(struct xpsgtr_dev *gtr_dev) continue; gtr_dev->clk[refclk] = clk; - - /* - * Get the spread spectrum (SSC) settings for the reference - * clock rate. - */ - rate = clk_get_rate(clk); - - for (i = 0 ; i < ARRAY_SIZE(ssc_lookup); i++) { - /* Allow an error of 100 ppm */ - unsigned long error = ssc_lookup[i].refclk_rate / 10000; - - if (abs(rate - ssc_lookup[i].refclk_rate) < error) { - gtr_dev->refclk_sscs[refclk] = &ssc_lookup[i]; - break; - } - } - - if (i == ARRAY_SIZE(ssc_lookup)) { - dev_err(gtr_dev->dev, - "Invalid rate %lu for reference clock %u\n", - rate, refclk); - return -EINVAL; - } } return 0; @@ -974,6 +1028,8 @@ static int xpsgtr_probe(struct platform_device *pdev) gtr_phy->phy = phy; phy_set_drvdata(phy, gtr_phy); + debugfs_create_devm_seqfile(&phy->dev, "status", phy->debugfs, + xpsgtr_status_read); } /* Register the PHY provider. */ @@ -992,18 +1048,22 @@ static int xpsgtr_probe(struct platform_device *pdev) return ret; } + gtr_dev->saved_regs = devm_kmalloc(gtr_dev->dev, + sizeof(save_reg_address), + GFP_KERNEL); + if (!gtr_dev->saved_regs) + return -ENOMEM; + return 0; } -static int xpsgtr_remove(struct platform_device *pdev) +static void xpsgtr_remove(struct platform_device *pdev) { struct xpsgtr_dev *gtr_dev = platform_get_drvdata(pdev); pm_runtime_disable(gtr_dev->dev); pm_runtime_put_noidle(gtr_dev->dev); pm_runtime_set_suspended(gtr_dev->dev); - - return 0; } static const struct of_device_id xpsgtr_of_match[] = { @@ -1015,7 +1075,7 @@ MODULE_DEVICE_TABLE(of, xpsgtr_of_match); static struct platform_driver xpsgtr_driver = { .probe = xpsgtr_probe, - .remove = xpsgtr_remove, + .remove = xpsgtr_remove, .driver = { .name = "xilinx-psgtr", .of_match_table = xpsgtr_of_match, |