summaryrefslogtreecommitdiff
path: root/drivers/phy/freescale
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-02-17 11:40:04 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2026-02-17 11:40:04 -0800
commit9b725d5959a1d9bb670ccdb23add45f0eaafefb5 (patch)
treee55a94fe0836bcebb1528d2c5bb8a9360a2b5edc /drivers/phy/freescale
parent4e15e819710e3518ec28735a12e0f45b7550290d (diff)
parentdbeea86fecef7cf2b93aded4525d74f6277376ef (diff)
downloadlinux-next-9b725d5959a1d9bb670ccdb23add45f0eaafefb5.tar.gz
linux-next-9b725d5959a1d9bb670ccdb23add45f0eaafefb5.zip
Merge tag 'phy-for-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy
Pull phy updates from Vinod Koul: "Core: - Add suuport for "rx-polarity" and "tx-polarity" device tree properties and phy common properties to manage this New Support: - Qualcomm Glymur PCIe Gen4 2-lanes PCIe phy, DP and edp phy, USB UNI PHY and SMB2370 eUSB2 repeater. SC8280xp QMP UFS PHY, Kaanapali PCIe phy and QMP PHY, QCS615 QMP USB3+DP PHY and driver support for that. - SpacemiT PCIe/combo PHY and K1 USB2 PHY driver. - HDMI 2.1 FRL configuration support and driver enabling for rockchip samsung-hdptx driver - TI TCAN1046 phy - Renesas RZ/V2H(P) and RZ/V2N usb3 - Mediatek MT8188 hdmi-phy - Google Tensor SoC USB PHY driver - Apple Type-C PHY Updates: - Subsystem conversion for clock round_rate() to determine_rate() - TI USB3 DT schema conversion - Samsung ExynosAutov920 usb3, combo hsphy and ssphy support" * tag 'phy-for-7.0' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (143 commits) phy: ti: phy-j721e-wiz: convert from divider_round_rate() to divider_determine_rate() dt-bindings: phy: ti,control-phy-otghs: convert to DT schema dt-bindings: phy: ti,phy-usb3: convert to DT schema phy: tegra: xusb: Remove unused powered_on variable phy: renesas: rcar-gen3-usb2: add regulator dependency phy: GOOGLE_USB: add TYPEC dependency phy: enter drivers/phy/Makefile even without CONFIG_GENERIC_PHY phy: renesas: rcar-gen3-usb2: Use mux-state for phyrst management phy: renesas: rcar-gen3-usb2: Add regulator for OTG VBUS control phy: renesas: rcar-gen3-usb2: Use devm_pm_runtime_enable() phy: renesas: rcar-gen3-usb2: Factor out VBUS control logic dt-bindings: phy: renesas,usb2-phy: Document RZ/G3E SoC dt-bindings: phy: renesas,usb2-phy: Document mux-states property dt-bindings: phy: renesas,usb2-phy: Document USB VBUS regulator phy: rockchip: samsung-hdptx: Add HDMI 2.1 FRL support phy: rockchip: samsung-hdptx: Extend rk_hdptx_phy_verify_hdmi_config() helper phy: rockchip: samsung-hdptx: Switch to driver specific HDMI config phy: rockchip: samsung-hdptx: Drop hw_rate driver data phy: rockchip: samsung-hdptx: Compute clk rate from PLL config phy: rockchip: samsung-hdptx: Cleanup *_cmn_init_seq lists ...
Diffstat (limited to 'drivers/phy/freescale')
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8mq-usb.c25
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8qm-hsio.c2
-rw-r--r--drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c6
-rw-r--r--drivers/phy/freescale/phy-fsl-lynx-28g.c1156
-rw-r--r--drivers/phy/freescale/phy-fsl-samsung-hdmi.c13
5 files changed, 910 insertions, 292 deletions
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
index 91b3e62743d3..b05d80e849a1 100644
--- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
+++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c
@@ -17,6 +17,10 @@
#define PHY_CTRL0_FSEL_MASK GENMASK(10, 5)
#define PHY_CTRL0_FSEL_24M 0x2a
#define PHY_CTRL0_FSEL_100M 0x27
+#define PHY_CTRL0_SSC_RANGE_MASK GENMASK(23, 21)
+#define PHY_CTRL0_SSC_RANGE_4003PPM 0x2
+#define PHY_CTRL0_SSC_RANGE_4492PPM 0x1
+#define PHY_CTRL0_SSC_RANGE_4980PPM 0x0
#define PHY_CTRL1 0x4
#define PHY_CTRL1_RESET BIT(0)
@@ -47,6 +51,7 @@
#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
#define PHY_CTRL6 0x18
+#define PHY_CTRL6_RXTERM_OVERRIDE_SEL BIT(29)
#define PHY_CTRL6_ALT_CLK_EN BIT(1)
#define PHY_CTRL6_ALT_CLK_SEL BIT(0)
@@ -587,6 +592,9 @@ static int imx8mp_usb_phy_init(struct phy *phy)
value = readl(imx_phy->base + PHY_CTRL0);
value |= PHY_CTRL0_REF_SSP_EN;
+ value &= ~PHY_CTRL0_SSC_RANGE_MASK;
+ value |= FIELD_PREP(PHY_CTRL0_SSC_RANGE_MASK,
+ PHY_CTRL0_SSC_RANGE_4003PPM);
writel(value, imx_phy->base + PHY_CTRL0);
value = readl(imx_phy->base + PHY_CTRL2);
@@ -610,6 +618,7 @@ static int imx8mp_usb_phy_init(struct phy *phy)
static int imx8mq_phy_power_on(struct phy *phy)
{
struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+ u32 value;
int ret;
ret = regulator_enable(imx_phy->vbus);
@@ -626,12 +635,23 @@ static int imx8mq_phy_power_on(struct phy *phy)
return ret;
}
- return ret;
+ /* Disable rx term override */
+ value = readl(imx_phy->base + PHY_CTRL6);
+ value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+ writel(value, imx_phy->base + PHY_CTRL6);
+
+ return 0;
}
static int imx8mq_phy_power_off(struct phy *phy)
{
struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
+ u32 value;
+
+ /* Override rx term to be 0 */
+ value = readl(imx_phy->base + PHY_CTRL6);
+ value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
+ writel(value, imx_phy->base + PHY_CTRL6);
clk_disable_unprepare(imx_phy->alt_clk);
clk_disable_unprepare(imx_phy->clk);
@@ -676,6 +696,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
if (!imx_phy)
return -ENOMEM;
+ platform_set_drvdata(pdev, imx_phy);
+
imx_phy->clk = devm_clk_get(dev, "phy");
if (IS_ERR(imx_phy->clk)) {
dev_err(dev, "failed to get imx8mq usb phy clock\n");
@@ -730,6 +752,7 @@ static struct platform_driver imx8mq_usb_phy_driver = {
.driver = {
.name = "imx8mq-usb-phy",
.of_match_table = imx8mq_usb_phy_of_match,
+ .suppress_bind_attrs = true,
}
};
module_platform_driver(imx8mq_usb_phy_driver);
diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c
index 977d21d753a5..279b8ac7822d 100644
--- a/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c
+++ b/drivers/phy/freescale/phy-fsl-imx8qm-hsio.c
@@ -251,7 +251,7 @@ static void imx_hsio_configure_clk_pad(struct phy *phy)
struct imx_hsio_lane *lane = phy_get_drvdata(phy);
struct imx_hsio_priv *priv = lane->priv;
- if (strncmp(priv->refclk_pad, "output", 6) == 0) {
+ if (priv->refclk_pad && 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,
diff --git a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
index 7aef2f59e8eb..ece357443521 100644
--- a/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
+++ b/drivers/phy/freescale/phy-fsl-imx8qm-lvds-phy.c
@@ -286,11 +286,9 @@ static int mixel_lvds_phy_reset(struct device *dev)
regmap_write(priv->regmap, PHY_CTRL, CTRL_RESET_VAL);
- ret = pm_runtime_put(dev);
- if (ret < 0)
- dev_err(dev, "failed to put PM runtime: %d\n", ret);
+ pm_runtime_put(dev);
- return ret;
+ return 0;
}
static struct phy *mixel_lvds_phy_xlate(struct device *dev,
diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c
index c20d2636c5e9..2b0fd95ba62f 100644
--- a/drivers/phy/freescale/phy-fsl-lynx-28g.c
+++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2021-2022 NXP. */
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy.h>
@@ -11,100 +12,408 @@
#define LYNX_28G_NUM_LANE 8
#define LYNX_28G_NUM_PLL 2
-/* General registers per SerDes block */
-#define LYNX_28G_PCC8 0x10a0
-#define LYNX_28G_PCC8_SGMII 0x1
-#define LYNX_28G_PCC8_SGMII_DIS 0x0
-
-#define LYNX_28G_PCCC 0x10b0
-#define LYNX_28G_PCCC_10GBASER 0x9
-#define LYNX_28G_PCCC_USXGMII 0x1
-#define LYNX_28G_PCCC_SXGMII_DIS 0x0
-
-#define LYNX_28G_LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
+/* SoC IP wrapper for protocol converters */
+#define PCC8 0x10a0
+#define PCC8_SGMIIa_KX BIT(3)
+#define PCC8_SGMIIa_CFG BIT(0)
+
+#define PCCC 0x10b0
+#define PCCC_SXGMIIn_XFI BIT(3)
+#define PCCC_SXGMIIn_CFG BIT(0)
+
+#define PCCD 0x10b4
+#define PCCD_E25Gn_CFG BIT(0)
+
+#define PCCE 0x10b8
+#define PCCE_E40Gn_LRV BIT(3)
+#define PCCE_E40Gn_CFG BIT(0)
+#define PCCE_E50Gn_LRV BIT(3)
+#define PCCE_E50GnCFG BIT(0)
+#define PCCE_E100Gn_LRV BIT(3)
+#define PCCE_E100Gn_CFG BIT(0)
+
+#define SGMII_CFG(id) (28 - (id) * 4) /* Offset into PCC8 */
+#define SXGMII_CFG(id) (28 - (id) * 4) /* Offset into PCCC */
+#define E25G_CFG(id) (28 - (id) * 4) /* Offset into PCCD */
+#define E40G_CFG(id) (28 - (id) * 4) /* Offset into PCCE */
+#define E50G_CFG(id) (20 - (id) * 4) /* Offset into PCCE */
+#define E100G_CFG(id) (12 - (id) * 4) /* Offset into PCCE */
/* Per PLL registers */
-#define LYNX_28G_PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
-#define LYNX_28G_PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
-#define LYNX_28G_PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
-
-#define LYNX_28G_PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
-#define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16)))
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ 0x0
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ 0x10000
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ 0x20000
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ 0x30000
-#define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ 0x40000
-
-#define LYNX_28G_PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)
-#define LYNX_28G_PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24)))
-#define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO 0x0
-#define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO 0x10000000
-#define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO 0x6000000
+#define PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
+#define PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
+#define PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
+
+#define PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
+#define PLLnCR0_REFCLK_SEL GENMASK(20, 16)
+#define PLLnCR0_REFCLK_SEL_100MHZ 0x0
+#define PLLnCR0_REFCLK_SEL_125MHZ 0x1
+#define PLLnCR0_REFCLK_SEL_156MHZ 0x2
+#define PLLnCR0_REFCLK_SEL_150MHZ 0x3
+#define PLLnCR0_REFCLK_SEL_161MHZ 0x4
+
+#define PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)
+#define PLLnCR1_FRATE_SEL GENMASK(28, 24)
+#define PLLnCR1_FRATE_5G_10GVCO 0x0
+#define PLLnCR1_FRATE_5G_25GVCO 0x10
+#define PLLnCR1_FRATE_10G_20GVCO 0x6
/* Per SerDes lane registers */
/* Lane a General Control Register */
-#define LYNX_28G_LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)
-#define LYNX_28G_LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3)
-#define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII 0x8
-#define LYNX_28G_LNaGCR0_PROTO_SEL_XFI 0x50
-#define LYNX_28G_LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0)
-#define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT 0x0
-#define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT 0x2
+#define LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)
+#define LNaGCR0_PROTO_SEL GENMASK(7, 3)
+#define LNaGCR0_PROTO_SEL_SGMII 0x1
+#define LNaGCR0_PROTO_SEL_XFI 0xa
+#define LNaGCR0_IF_WIDTH GENMASK(2, 0)
+#define LNaGCR0_IF_WIDTH_10_BIT 0x0
+#define LNaGCR0_IF_WIDTH_20_BIT 0x2
/* Lane a Tx Reset Control Register */
-#define LYNX_28G_LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
-#define LYNX_28G_LNaTRSTCTL_HLT_REQ BIT(27)
-#define LYNX_28G_LNaTRSTCTL_RST_DONE BIT(30)
-#define LYNX_28G_LNaTRSTCTL_RST_REQ BIT(31)
+#define LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
+#define LNaTRSTCTL_HLT_REQ BIT(27)
+#define LNaTRSTCTL_RST_DONE BIT(30)
+#define LNaTRSTCTL_RST_REQ BIT(31)
/* Lane a Tx General Control Register */
-#define LYNX_28G_LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
-#define LYNX_28G_LNaTGCR0_USE_PLLF 0x0
-#define LYNX_28G_LNaTGCR0_USE_PLLS BIT(28)
-#define LYNX_28G_LNaTGCR0_USE_PLL_MSK BIT(28)
-#define LYNX_28G_LNaTGCR0_N_RATE_FULL 0x0
-#define LYNX_28G_LNaTGCR0_N_RATE_HALF 0x1000000
-#define LYNX_28G_LNaTGCR0_N_RATE_QUARTER 0x2000000
-#define LYNX_28G_LNaTGCR0_N_RATE_MSK GENMASK(26, 24)
-
-#define LYNX_28G_LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
+#define LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
+#define LNaTGCR0_USE_PLL BIT(28)
+#define LNaTGCR0_USE_PLLF 0x0
+#define LNaTGCR0_USE_PLLS 0x1
+#define LNaTGCR0_N_RATE GENMASK(26, 24)
+#define LNaTGCR0_N_RATE_FULL 0x0
+#define LNaTGCR0_N_RATE_HALF 0x1
+#define LNaTGCR0_N_RATE_QUARTER 0x2
+
+#define LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
+#define LNaTECR0_EQ_TYPE GENMASK(30, 28)
+#define LNaTECR0_EQ_SGN_PREQ BIT(23)
+#define LNaTECR0_EQ_PREQ GENMASK(19, 16)
+#define LNaTECR0_EQ_SGN_POST1Q BIT(15)
+#define LNaTECR0_EQ_POST1Q GENMASK(12, 8)
+#define LNaTECR0_EQ_AMP_RED GENMASK(5, 0)
+
+#define LNaTECR1(lane) (0x800 + (lane) * 0x100 + 0x34)
+#define LNaTECR1_EQ_ADPT_EQ_DRVR_DIS BIT(31)
+#define LNaTECR1_EQ_ADPT_EQ GENMASK(29, 24)
/* Lane a Rx Reset Control Register */
-#define LYNX_28G_LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
-#define LYNX_28G_LNaRRSTCTL_HLT_REQ BIT(27)
-#define LYNX_28G_LNaRRSTCTL_RST_DONE BIT(30)
-#define LYNX_28G_LNaRRSTCTL_RST_REQ BIT(31)
-#define LYNX_28G_LNaRRSTCTL_CDR_LOCK BIT(12)
+#define LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
+#define LNaRRSTCTL_HLT_REQ BIT(27)
+#define LNaRRSTCTL_RST_DONE BIT(30)
+#define LNaRRSTCTL_RST_REQ BIT(31)
+#define LNaRRSTCTL_CDR_LOCK BIT(12)
/* Lane a Rx General Control Register */
-#define LYNX_28G_LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)
-#define LYNX_28G_LNaRGCR0_USE_PLLF 0x0
-#define LYNX_28G_LNaRGCR0_USE_PLLS BIT(28)
-#define LYNX_28G_LNaRGCR0_USE_PLL_MSK BIT(28)
-#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
-#define LYNX_28G_LNaRGCR0_N_RATE_FULL 0x0
-#define LYNX_28G_LNaRGCR0_N_RATE_HALF 0x1000000
-#define LYNX_28G_LNaRGCR0_N_RATE_QUARTER 0x2000000
-#define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
-
-#define LYNX_28G_LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
-
-#define LYNX_28G_LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)
-#define LYNX_28G_LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)
-#define LYNX_28G_LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)
-
-#define LYNX_28G_LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
-
-#define LYNX_28G_LNaPSS(lane) (0x1000 + (lane) * 0x4)
-#define LYNX_28G_LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24)
-#define LYNX_28G_LNaPSS_TYPE_SGMII 0x4
-#define LYNX_28G_LNaPSS_TYPE_XFI 0x28
-
-#define LYNX_28G_SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
-#define LYNX_28G_SGMIIaCR1_SGPCS_EN BIT(11)
-#define LYNX_28G_SGMIIaCR1_SGPCS_DIS 0x0
-#define LYNX_28G_SGMIIaCR1_SGPCS_MSK BIT(11)
+#define LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)
+#define LNaRGCR0_USE_PLL BIT(28)
+#define LNaRGCR0_USE_PLLF 0x0
+#define LNaRGCR0_USE_PLLS 0x1
+#define LNaRGCR0_N_RATE GENMASK(26, 24)
+#define LNaRGCR0_N_RATE_FULL 0x0
+#define LNaRGCR0_N_RATE_HALF 0x1
+#define LNaRGCR0_N_RATE_QUARTER 0x2
+
+#define LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
+#define LNaRGCR1_RX_ORD_ELECIDLE BIT(31)
+#define LNaRGCR1_DATA_LOST_FLT BIT(30)
+#define LNaRGCR1_DATA_LOST BIT(29)
+#define LNaRGCR1_IDLE_CONFIG BIT(28)
+#define LNaRGCR1_ENTER_IDLE_FLT_SEL GENMASK(26, 24)
+#define LNaRGCR1_EXIT_IDLE_FLT_SEL GENMASK(22, 20)
+#define LNaRGCR1_DATA_LOST_TH_SEL GENMASK(18, 16)
+#define LNaRGCR1_EXT_REC_CLK_SEL GENMASK(10, 8)
+#define LNaRGCR1_WAKE_TX_DIS BIT(5)
+#define LNaRGCR1_PHY_RDY BIT(4)
+#define LNaRGCR1_CHANGE_RX_CLK BIT(3)
+#define LNaRGCR1_PWR_MGT GENMASK(2, 0)
+
+#define LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)
+#define LNaRECR0_EQ_GAINK2_HF_OV_EN BIT(31)
+#define LNaRECR0_EQ_GAINK2_HF_OV GENMASK(28, 24)
+#define LNaRECR0_EQ_GAINK3_MF_OV_EN BIT(23)
+#define LNaRECR0_EQ_GAINK3_MF_OV GENMASK(20, 16)
+#define LNaRECR0_EQ_GAINK4_LF_OV_EN BIT(7)
+#define LNaRECR0_EQ_GAINK4_LF_DIS BIT(6)
+#define LNaRECR0_EQ_GAINK4_LF_OV GENMASK(4, 0)
+
+#define LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)
+#define LNaRECR1_EQ_BLW_OV_EN BIT(31)
+#define LNaRECR1_EQ_BLW_OV GENMASK(28, 24)
+#define LNaRECR1_EQ_OFFSET_OV_EN BIT(23)
+#define LNaRECR1_EQ_OFFSET_OV GENMASK(21, 16)
+
+#define LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)
+#define LNaRECR2_EQ_OFFSET_RNG_DBL BIT(31)
+#define LNaRECR2_EQ_BOOST GENMASK(29, 28)
+#define LNaRECR2_EQ_BLW_SEL GENMASK(25, 24)
+#define LNaRECR2_EQ_ZERO GENMASK(17, 16)
+#define LNaRECR2_EQ_IND GENMASK(13, 12)
+#define LNaRECR2_EQ_BIN_DATA_AVG_TC GENMASK(5, 4)
+#define LNaRECR2_SPARE_IN GENMASK(1, 0)
+
+#define LNaRECR3(lane) (0x800 + (lane) * 0x100 + 0x5c)
+#define LNaRECR3_EQ_SNAP_START BIT(31)
+#define LNaRECR3_EQ_SNAP_DONE BIT(30)
+#define LNaRECR3_EQ_GAINK2_HF_STAT GENMASK(28, 24)
+#define LNaRECR3_EQ_GAINK3_MF_STAT GENMASK(20, 16)
+#define LNaRECR3_SPARE_OUT GENMASK(13, 12)
+#define LNaRECR3_EQ_GAINK4_LF_STAT GENMASK(4, 0)
+
+#define LNaRECR4(lane) (0x800 + (lane) * 0x100 + 0x60)
+#define LNaRECR4_BLW_STAT GENMASK(28, 24)
+#define LNaRECR4_EQ_OFFSET_STAT GENMASK(21, 16)
+#define LNaRECR4_EQ_BIN_DATA_SEL GENMASK(15, 12)
+#define LNaRECR4_EQ_BIN_DATA GENMASK(8, 0) /* bit 9 is reserved */
+#define LNaRECR4_EQ_BIN_DATA_SGN BIT(8)
+
+#define LNaRCCR0(lane) (0x800 + (lane) * 0x100 + 0x68)
+#define LNaRCCR0_CAL_EN BIT(31)
+#define LNaRCCR0_MEAS_EN BIT(30)
+#define LNaRCCR0_CAL_BIN_SEL BIT(28)
+#define LNaRCCR0_CAL_DC3_DIS BIT(27)
+#define LNaRCCR0_CAL_DC2_DIS BIT(26)
+#define LNaRCCR0_CAL_DC1_DIS BIT(25)
+#define LNaRCCR0_CAL_DC0_DIS BIT(24)
+#define LNaRCCR0_CAL_AC3_OV_EN BIT(15)
+#define LNaRCCR0_CAL_AC3_OV GENMASK(11, 8)
+#define LNaRCCR0_CAL_AC2_OV_EN BIT(7)
+
+#define LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
+#define LNaRSCCR0_SMP_OFF_EN BIT(31)
+#define LNaRSCCR0_SMP_OFF_OV_EN BIT(30)
+#define LNaRSCCR0_SMP_MAN_OFF_EN BIT(29)
+#define LNaRSCCR0_SMP_OFF_RNG_OV_EN BIT(27)
+#define LNaRSCCR0_SMP_OFF_RNG_4X_OV BIT(25)
+#define LNaRSCCR0_SMP_OFF_RNG_2X_OV BIT(24)
+#define LNaRSCCR0_SMP_AUTOZ_PD BIT(23)
+#define LNaRSCCR0_SMP_AUTOZ_CTRL GENMASK(19, 16)
+#define LNaRSCCR0_SMP_AUTOZ_D1R GENMASK(13, 12)
+#define LNaRSCCR0_SMP_AUTOZ_D1F GENMASK(9, 8)
+#define LNaRSCCR0_SMP_AUTOZ_EG1R GENMASK(5, 4)
+#define LNaRSCCR0_SMP_AUTOZ_EG1F GENMASK(1, 0)
+
+#define LNaTTLCR0(lane) (0x800 + (lane) * 0x100 + 0x80)
+#define LNaTTLCR0_TTL_FLT_SEL GENMASK(29, 24)
+#define LNaTTLCR0_TTL_SLO_PM_BYP BIT(22)
+#define LNaTTLCR0_STALL_DET_DIS BIT(21)
+#define LNaTTLCR0_INACT_MON_DIS BIT(20)
+#define LNaTTLCR0_CDR_OV GENMASK(18, 16)
+#define LNaTTLCR0_DATA_IN_SSC BIT(15)
+#define LNaTTLCR0_CDR_MIN_SMP_ON GENMASK(1, 0)
+
+#define LNaTCSR0(lane) (0x800 + (lane) * 0x100 + 0xa0)
+#define LNaTCSR0_SD_STAT_OBS_EN BIT(31)
+#define LNaTCSR0_SD_LPBK_SEL GENMASK(29, 28)
+
+#define LNaPSS(lane) (0x1000 + (lane) * 0x4)
+#define LNaPSS_TYPE GENMASK(30, 24)
+#define LNaPSS_TYPE_SGMII (PROTO_SEL_SGMII_BASEX_KX << 2)
+#define LNaPSS_TYPE_XFI (PROTO_SEL_XFI_10GBASER_KR_SXGMII << 2)
+#define LNaPSS_TYPE_40G ((PROTO_SEL_XFI_10GBASER_KR_SXGMII << 2) | 3)
+#define LNaPSS_TYPE_25G (PROTO_SEL_25G_50G_100G << 2)
+#define LNaPSS_TYPE_100G ((PROTO_SEL_25G_50G_100G << 2) | 2)
+
+/* MDEV_PORT is at the same bitfield address for all protocol converters */
+#define MDEV_PORT GENMASK(31, 27)
+
+#define SGMIIaCR0(lane) (0x1800 + (lane) * 0x10)
+#define SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
+#define SGMIIaCR1_SGPCS_EN BIT(11)
+
+#define ANLTaCR0(lane) (0x1a00 + (lane) * 0x10)
+#define ANLTaCR1(lane) (0x1a04 + (lane) * 0x10)
+
+#define SXGMIIaCR0(lane) (0x1a80 + (lane) * 0x10)
+#define SXGMIIaCR0_RST BIT(31)
+#define SXGMIIaCR0_PD BIT(30)
+
+#define SXGMIIaCR1(lane) (0x1a84 + (lane) * 0x10)
+
+#define E25GaCR0(lane) (0x1b00 + (lane) * 0x10)
+#define E25GaCR0_RST BIT(31)
+#define E25GaCR0_PD BIT(30)
+
+#define E25GaCR1(lane) (0x1b04 + (lane) * 0x10)
+
+#define E25GaCR2(lane) (0x1b08 + (lane) * 0x10)
+#define E25GaCR2_FEC_ENA BIT(23)
+#define E25GaCR2_FEC_ERR_ENA BIT(22)
+#define E25GaCR2_FEC91_ENA BIT(20)
+
+#define E40GaCR0(pcvt) (0x1b40 + (pcvt) * 0x20)
+#define E40GaCR1(pcvt) (0x1b44 + (pcvt) * 0x20)
+
+#define E50GaCR1(pcvt) (0x1b84 + (pcvt) * 0x10)
+
+#define E100GaCR1(pcvt) (0x1c04 + (pcvt) * 0x20)
+
+#define CR(x) ((x) * 4)
+
+enum lynx_28g_eq_type {
+ EQ_TYPE_NO_EQ = 0,
+ EQ_TYPE_2TAP = 1,
+ EQ_TYPE_3TAP = 2,
+};
+
+enum lynx_28g_proto_sel {
+ PROTO_SEL_PCIE = 0,
+ PROTO_SEL_SGMII_BASEX_KX = 1,
+ PROTO_SEL_SATA = 2,
+ PROTO_SEL_XAUI = 4,
+ PROTO_SEL_XFI_10GBASER_KR_SXGMII = 0xa,
+ PROTO_SEL_25G_50G_100G = 0x1a,
+};
+
+enum lynx_lane_mode {
+ LANE_MODE_UNKNOWN,
+ LANE_MODE_1000BASEX_SGMII,
+ LANE_MODE_10GBASER,
+ LANE_MODE_USXGMII,
+ LANE_MODE_MAX,
+};
+
+struct lynx_28g_proto_conf {
+ /* LNaGCR0 */
+ int proto_sel;
+ int if_width;
+ /* LNaTECR0 */
+ int teq_type;
+ int sgn_preq;
+ int ratio_preq;
+ int sgn_post1q;
+ int ratio_post1q;
+ int amp_red;
+ /* LNaTECR1 */
+ int adpt_eq;
+ /* LNaRGCR1 */
+ int enter_idle_flt_sel;
+ int exit_idle_flt_sel;
+ int data_lost_th_sel;
+ /* LNaRECR0 */
+ int gk2ovd;
+ int gk3ovd;
+ int gk4ovd;
+ int gk2ovd_en;
+ int gk3ovd_en;
+ int gk4ovd_en;
+ /* LNaRECR1 ? */
+ int eq_offset_ovd;
+ int eq_offset_ovd_en;
+ /* LNaRECR2 */
+ int eq_offset_rng_dbl;
+ int eq_blw_sel;
+ int eq_boost;
+ int spare_in;
+ /* LNaRSCCR0 */
+ int smp_autoz_d1r;
+ int smp_autoz_eg1r;
+ /* LNaRCCR0 */
+ int rccr0;
+ /* LNaTTLCR0 */
+ int ttlcr0;
+};
+
+static const struct lynx_28g_proto_conf lynx_28g_proto_conf[LANE_MODE_MAX] = {
+ [LANE_MODE_1000BASEX_SGMII] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_SGMII,
+ .if_width = LNaGCR0_IF_WIDTH_10_BIT,
+ .teq_type = EQ_TYPE_NO_EQ,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 0,
+ .amp_red = 6,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 4,
+ .exit_idle_flt_sel = 3,
+ .data_lost_th_sel = 1,
+ .gk2ovd = 0x1f,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 1,
+ .gk3ovd_en = 1,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 0,
+ .eq_blw_sel = 0,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 0,
+ .smp_autoz_eg1r = 0,
+ .rccr0 = LNaRCCR0_CAL_EN,
+ .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
+ LNaTTLCR0_DATA_IN_SSC,
+ },
+ [LANE_MODE_USXGMII] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_XFI,
+ .if_width = LNaGCR0_IF_WIDTH_20_BIT,
+ .teq_type = EQ_TYPE_2TAP,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 3,
+ .amp_red = 7,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 0,
+ .exit_idle_flt_sel = 0,
+ .data_lost_th_sel = 0,
+ .gk2ovd = 0,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 0,
+ .gk3ovd_en = 0,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 1,
+ .eq_blw_sel = 1,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 2,
+ .smp_autoz_eg1r = 0,
+ .rccr0 = LNaRCCR0_CAL_EN,
+ .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
+ LNaTTLCR0_DATA_IN_SSC,
+ },
+ [LANE_MODE_10GBASER] = {
+ .proto_sel = LNaGCR0_PROTO_SEL_XFI,
+ .if_width = LNaGCR0_IF_WIDTH_20_BIT,
+ .teq_type = EQ_TYPE_2TAP,
+ .sgn_preq = 1,
+ .ratio_preq = 0,
+ .sgn_post1q = 1,
+ .ratio_post1q = 3,
+ .amp_red = 7,
+ .adpt_eq = 48,
+ .enter_idle_flt_sel = 0,
+ .exit_idle_flt_sel = 0,
+ .data_lost_th_sel = 0,
+ .gk2ovd = 0,
+ .gk3ovd = 0,
+ .gk4ovd = 0,
+ .gk2ovd_en = 0,
+ .gk3ovd_en = 0,
+ .gk4ovd_en = 0,
+ .eq_offset_ovd = 0x1f,
+ .eq_offset_ovd_en = 0,
+ .eq_offset_rng_dbl = 1,
+ .eq_blw_sel = 1,
+ .eq_boost = 0,
+ .spare_in = 0,
+ .smp_autoz_d1r = 2,
+ .smp_autoz_eg1r = 0,
+ .rccr0 = LNaRCCR0_CAL_EN,
+ .ttlcr0 = LNaTTLCR0_TTL_SLO_PM_BYP |
+ LNaTTLCR0_DATA_IN_SSC,
+ },
+};
+
+struct lynx_pccr {
+ int offset;
+ int width;
+ int shift;
+};
struct lynx_28g_priv;
@@ -112,7 +421,7 @@ struct lynx_28g_pll {
struct lynx_28g_priv *priv;
u32 rstctl, cr0, cr1;
int id;
- DECLARE_PHY_INTERFACE_MASK(supported);
+ DECLARE_BITMAP(supported, LANE_MODE_MAX);
};
struct lynx_28g_lane {
@@ -121,7 +430,7 @@ struct lynx_28g_lane {
bool powered_up;
bool init;
unsigned int id;
- phy_interface_t interface;
+ enum lynx_lane_mode mode;
};
struct lynx_28g_priv {
@@ -149,23 +458,58 @@ static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
iowrite32(tmp, reg);
}
+#define lynx_28g_read(priv, off) \
+ ioread32((priv)->base + (off))
+#define lynx_28g_write(priv, off, val) \
+ iowrite32(val, (priv)->base + (off))
#define lynx_28g_lane_rmw(lane, reg, val, mask) \
- lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \
- LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask)
+ lynx_28g_rmw((lane)->priv, reg(lane->id), val, mask)
#define lynx_28g_lane_read(lane, reg) \
- ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id))
+ ioread32((lane)->priv->base + reg((lane)->id))
+#define lynx_28g_lane_write(lane, reg, val) \
+ iowrite32(val, (lane)->priv->base + reg((lane)->id))
#define lynx_28g_pll_read(pll, reg) \
- ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id))
+ ioread32((pll)->priv->base + reg((pll)->id))
-static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
+static const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return "1000Base-X/SGMII";
+ case LANE_MODE_10GBASER:
+ return "10GBase-R";
+ case LANE_MODE_USXGMII:
+ return "USXGMII";
+ default:
+ return "unknown";
+ }
+}
+
+static enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf)
+{
+ switch (intf) {
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ return LANE_MODE_1000BASEX_SGMII;
+ case PHY_INTERFACE_MODE_10GBASER:
+ return LANE_MODE_10GBASER;
+ case PHY_INTERFACE_MODE_USXGMII:
+ return LANE_MODE_USXGMII;
+ default:
+ return LANE_MODE_UNKNOWN;
+ }
+}
+
+static bool lynx_28g_supports_lane_mode(struct lynx_28g_priv *priv,
+ enum lynx_lane_mode mode)
{
int i;
for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
- if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl))
+ if (PLLnRSTCTL_DIS(priv->pll[i].rstctl))
continue;
- if (test_bit(intf, priv->pll[i].supported))
+ if (test_bit(mode, priv->pll[i].supported))
return true;
}
@@ -173,7 +517,7 @@ static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
}
static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
- phy_interface_t intf)
+ enum lynx_lane_mode mode)
{
struct lynx_28g_pll *pll;
int i;
@@ -181,43 +525,51 @@ static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
pll = &priv->pll[i];
- if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
+ if (PLLnRSTCTL_DIS(pll->rstctl))
continue;
- if (test_bit(intf, pll->supported))
+ if (test_bit(mode, pll->supported))
return pll;
}
/* no pll supports requested mode, either caller forgot to check
* lynx_28g_supports_lane_mode, or this is a bug.
*/
- dev_WARN_ONCE(priv->dev, 1, "no pll for interface %s\n", phy_modes(intf));
+ dev_WARN_ONCE(priv->dev, 1, "no pll for lane mode %s\n",
+ lynx_lane_mode_str(mode));
return NULL;
}
static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll,
- phy_interface_t intf)
+ enum lynx_lane_mode lane_mode)
{
- switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
- case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
- case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
- switch (intf) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK);
+ switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
+ case PLLnCR1_FRATE_5G_10GVCO:
+ case PLLnCR1_FRATE_5G_25GVCO:
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_QUARTER),
+ LNaTGCR0_N_RATE);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_QUARTER),
+ LNaRGCR0_N_RATE);
break;
default:
break;
}
break;
- case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
- switch (intf) {
- case PHY_INTERFACE_MODE_10GBASER:
- case PHY_INTERFACE_MODE_USXGMII:
- lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK);
+ case PLLnCR1_FRATE_10G_20GVCO:
+ switch (lane_mode) {
+ case LANE_MODE_10GBASER:
+ case LANE_MODE_USXGMII:
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_N_RATE, LNaTGCR0_N_RATE_FULL),
+ LNaTGCR0_N_RATE);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_N_RATE, LNaRGCR0_N_RATE_FULL),
+ LNaRGCR0_N_RATE);
break;
default:
break;
@@ -232,163 +584,356 @@ static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
struct lynx_28g_pll *pll)
{
if (pll->id == 0) {
- lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_USE_PLL, LNaTGCR0_USE_PLLF),
+ LNaTGCR0_USE_PLL);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_USE_PLL, LNaRGCR0_USE_PLLF),
+ LNaRGCR0_USE_PLL);
} else {
- lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK);
- lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK);
+ lynx_28g_lane_rmw(lane, LNaTGCR0,
+ FIELD_PREP(LNaTGCR0_USE_PLL, LNaTGCR0_USE_PLLS),
+ LNaTGCR0_USE_PLL);
+ lynx_28g_lane_rmw(lane, LNaRGCR0,
+ FIELD_PREP(LNaRGCR0_USE_PLL, LNaRGCR0_USE_PLLS),
+ LNaRGCR0_USE_PLL);
}
}
-static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
+static int lynx_28g_power_off(struct phy *phy)
{
- u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
- struct lynx_28g_priv *priv = lane->priv;
+ struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+ u32 trstctl, rrstctl;
- /* Cleanup the protocol configuration registers of the current protocol */
- switch (lane->interface) {
- case PHY_INTERFACE_MODE_10GBASER:
- lynx_28g_rmw(priv, LYNX_28G_PCCC,
- LYNX_28G_PCCC_SXGMII_DIS << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ if (!lane->powered_up)
+ return 0;
+
+ /* Issue a halt request */
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_HLT_REQ,
+ LNaTRSTCTL_HLT_REQ);
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_HLT_REQ,
+ LNaRRSTCTL_HLT_REQ);
+
+ /* Wait until the halting process is complete */
+ do {
+ trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
+ rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
+ } while ((trstctl & LNaTRSTCTL_HLT_REQ) ||
+ (rrstctl & LNaRRSTCTL_HLT_REQ));
+
+ lane->powered_up = false;
+
+ return 0;
+}
+
+static int lynx_28g_power_on(struct phy *phy)
+{
+ struct lynx_28g_lane *lane = phy_get_drvdata(phy);
+ u32 trstctl, rrstctl;
+
+ if (lane->powered_up)
+ return 0;
+
+ /* Issue a reset request on the lane */
+ lynx_28g_lane_rmw(lane, LNaTRSTCTL, LNaTRSTCTL_RST_REQ,
+ LNaTRSTCTL_RST_REQ);
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ,
+ LNaRRSTCTL_RST_REQ);
+
+ /* Wait until the reset sequence is completed */
+ do {
+ trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
+ rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
+ } while (!(trstctl & LNaTRSTCTL_RST_DONE) ||
+ !(rrstctl & LNaRRSTCTL_RST_DONE));
+
+ lane->powered_up = true;
+
+ return 0;
+}
+
+static int lynx_28g_get_pccr(enum lynx_lane_mode lane_mode, int lane,
+ struct lynx_pccr *pccr)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ pccr->offset = PCC8;
+ pccr->width = 4;
+ pccr->shift = SGMII_CFG(lane);
break;
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_rmw(priv, LYNX_28G_PCC8,
- LYNX_28G_PCC8_SGMII_DIS << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
+ pccr->offset = PCCC;
+ pccr->width = 4;
+ pccr->shift = SXGMII_CFG(lane);
break;
default:
- break;
+ return -EOPNOTSUPP;
}
+
+ return 0;
}
-static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
+static int lynx_28g_get_pcvt_offset(int lane, enum lynx_lane_mode lane_mode)
+{
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ return SGMIIaCR0(lane);
+ case LANE_MODE_USXGMII:
+ case LANE_MODE_10GBASER:
+ return SXGMIIaCR0(lane);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int lynx_pccr_read(struct lynx_28g_lane *lane, enum lynx_lane_mode mode,
+ u32 *val)
{
- u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
struct lynx_28g_priv *priv = lane->priv;
- struct lynx_28g_pll *pll;
+ struct lynx_pccr pccr;
+ u32 tmp;
+ int err;
- lynx_28g_cleanup_lane(lane);
+ err = lynx_28g_get_pccr(mode, lane->id, &pccr);
+ if (err)
+ return err;
- /* Setup the lane to run in SGMII */
- lynx_28g_rmw(priv, LYNX_28G_PCC8,
- LYNX_28G_PCC8_SGMII << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ tmp = lynx_28g_read(priv, pccr.offset);
+ *val = (tmp >> pccr.shift) & GENMASK(pccr.width - 1, 0);
- /* Setup the protocol select and SerDes parallel interface width */
- lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK);
- lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK);
+ return 0;
+}
- /* Find the PLL that works with this interface type */
- pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
- if (unlikely(pll == NULL))
- return;
+static int lynx_pccr_write(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode, u32 val)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ struct lynx_pccr pccr;
+ u32 old, tmp, mask;
+ int err;
- /* Switch to the PLL that works with this interface type */
- lynx_28g_lane_set_pll(lane, pll);
+ err = lynx_28g_get_pccr(lane_mode, lane->id, &pccr);
+ if (err)
+ return err;
- /* Choose the portion of clock net to be used on this lane */
- lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);
-
- /* Enable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);
-
- /* Configure the appropriate equalization parameters for the protocol */
- iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id));
- iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
- iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id));
- iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
- iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id));
- iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
+ old = lynx_28g_read(priv, pccr.offset);
+ mask = GENMASK(pccr.width - 1, 0) << pccr.shift;
+ tmp = (old & ~mask) | (val << pccr.shift);
+ lynx_28g_write(priv, pccr.offset, tmp);
+
+ dev_dbg(&lane->phy->dev, "PCCR@0x%x: 0x%x -> 0x%x\n",
+ pccr.offset, old, tmp);
+
+ return 0;
}
-static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
+static int lynx_pcvt_read(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode, int cr, u32 *val)
{
- u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
struct lynx_28g_priv *priv = lane->priv;
- struct lynx_28g_pll *pll;
+ int offset;
+
+ offset = lynx_28g_get_pcvt_offset(lane->id, lane_mode);
+ if (offset < 0)
+ return offset;
+
+ *val = lynx_28g_read(priv, offset + cr);
+
+ return 0;
+}
+
+static int lynx_pcvt_write(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode, int cr, u32 val)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ int offset;
+
+ offset = lynx_28g_get_pcvt_offset(lane->id, lane_mode);
+ if (offset < 0)
+ return offset;
- lynx_28g_cleanup_lane(lane);
+ lynx_28g_write(priv, offset + cr, val);
- /* Enable the SXGMII lane */
- lynx_28g_rmw(priv, LYNX_28G_PCCC,
- LYNX_28G_PCCC_10GBASER << lane_offset,
- GENMASK(3, 0) << lane_offset);
+ return 0;
+}
+
+static int lynx_pcvt_rmw(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode,
+ int cr, u32 val, u32 mask)
+{
+ int err;
+ u32 tmp;
+
+ err = lynx_pcvt_read(lane, lane_mode, cr, &tmp);
+ if (err)
+ return err;
+
+ tmp &= ~mask;
+ tmp |= val;
- /* Setup the protocol select and SerDes parallel interface width */
- lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK);
- lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK);
+ return lynx_pcvt_write(lane, lane_mode, cr, tmp);
+}
- /* Find the PLL that works with this interface type */
- pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
+static void lynx_28g_lane_remap_pll(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ struct lynx_28g_pll *pll;
+
+ /* Switch to the PLL that works with this interface type */
+ pll = lynx_28g_pll_get(priv, lane_mode);
if (unlikely(pll == NULL))
return;
- /* Switch to the PLL that works with this interface type */
lynx_28g_lane_set_pll(lane, pll);
/* Choose the portion of clock net to be used on this lane */
- lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
-
- /* Disable the SGMII PCS */
- lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);
-
- /* Configure the appropriate equalization parameters for the protocol */
- iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id));
- iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
- iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id));
- iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
- iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id));
- iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
+ lynx_28g_lane_set_nrate(lane, pll, lane_mode);
}
-static int lynx_28g_power_off(struct phy *phy)
+static void lynx_28g_lane_change_proto_conf(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode)
{
- struct lynx_28g_lane *lane = phy_get_drvdata(phy);
- u32 trstctl, rrstctl;
+ const struct lynx_28g_proto_conf *conf = &lynx_28g_proto_conf[lane_mode];
+
+ lynx_28g_lane_rmw(lane, LNaGCR0,
+ FIELD_PREP(LNaGCR0_PROTO_SEL, conf->proto_sel) |
+ FIELD_PREP(LNaGCR0_IF_WIDTH, conf->if_width),
+ LNaGCR0_PROTO_SEL | LNaGCR0_IF_WIDTH);
+
+ lynx_28g_lane_rmw(lane, LNaTECR0,
+ FIELD_PREP(LNaTECR0_EQ_TYPE, conf->teq_type) |
+ FIELD_PREP(LNaTECR0_EQ_SGN_PREQ, conf->sgn_preq) |
+ FIELD_PREP(LNaTECR0_EQ_PREQ, conf->ratio_preq) |
+ FIELD_PREP(LNaTECR0_EQ_SGN_POST1Q, conf->sgn_post1q) |
+ FIELD_PREP(LNaTECR0_EQ_POST1Q, conf->ratio_post1q) |
+ FIELD_PREP(LNaTECR0_EQ_AMP_RED, conf->amp_red),
+ LNaTECR0_EQ_TYPE |
+ LNaTECR0_EQ_SGN_PREQ |
+ LNaTECR0_EQ_PREQ |
+ LNaTECR0_EQ_SGN_POST1Q |
+ LNaTECR0_EQ_POST1Q |
+ LNaTECR0_EQ_AMP_RED);
+
+ lynx_28g_lane_rmw(lane, LNaTECR1,
+ FIELD_PREP(LNaTECR1_EQ_ADPT_EQ, conf->adpt_eq),
+ LNaTECR1_EQ_ADPT_EQ);
+
+ lynx_28g_lane_rmw(lane, LNaRGCR1,
+ FIELD_PREP(LNaRGCR1_ENTER_IDLE_FLT_SEL, conf->enter_idle_flt_sel) |
+ FIELD_PREP(LNaRGCR1_EXIT_IDLE_FLT_SEL, conf->exit_idle_flt_sel) |
+ FIELD_PREP(LNaRGCR1_DATA_LOST_TH_SEL, conf->data_lost_th_sel),
+ LNaRGCR1_ENTER_IDLE_FLT_SEL |
+ LNaRGCR1_EXIT_IDLE_FLT_SEL |
+ LNaRGCR1_DATA_LOST_TH_SEL);
+
+ lynx_28g_lane_rmw(lane, LNaRECR0,
+ FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV_EN, conf->gk2ovd_en) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV_EN, conf->gk3ovd_en) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK4_LF_OV_EN, conf->gk4ovd_en) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK2_HF_OV, conf->gk2ovd) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK3_MF_OV, conf->gk3ovd) |
+ FIELD_PREP(LNaRECR0_EQ_GAINK4_LF_OV, conf->gk4ovd),
+ LNaRECR0_EQ_GAINK2_HF_OV |
+ LNaRECR0_EQ_GAINK3_MF_OV |
+ LNaRECR0_EQ_GAINK4_LF_OV |
+ LNaRECR0_EQ_GAINK2_HF_OV_EN |
+ LNaRECR0_EQ_GAINK3_MF_OV_EN |
+ LNaRECR0_EQ_GAINK4_LF_OV_EN);
+
+ lynx_28g_lane_rmw(lane, LNaRECR1,
+ FIELD_PREP(LNaRECR1_EQ_OFFSET_OV, conf->eq_offset_ovd) |
+ FIELD_PREP(LNaRECR1_EQ_OFFSET_OV_EN, conf->eq_offset_ovd_en),
+ LNaRECR1_EQ_OFFSET_OV |
+ LNaRECR1_EQ_OFFSET_OV_EN);
+
+ lynx_28g_lane_rmw(lane, LNaRECR2,
+ FIELD_PREP(LNaRECR2_EQ_OFFSET_RNG_DBL, conf->eq_offset_rng_dbl) |
+ FIELD_PREP(LNaRECR2_EQ_BLW_SEL, conf->eq_blw_sel) |
+ FIELD_PREP(LNaRECR2_EQ_BOOST, conf->eq_boost) |
+ FIELD_PREP(LNaRECR2_SPARE_IN, conf->spare_in),
+ LNaRECR2_EQ_OFFSET_RNG_DBL |
+ LNaRECR2_EQ_BLW_SEL |
+ LNaRECR2_EQ_BOOST |
+ LNaRECR2_SPARE_IN);
+
+ lynx_28g_lane_rmw(lane, LNaRSCCR0,
+ FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_D1R, conf->smp_autoz_d1r) |
+ FIELD_PREP(LNaRSCCR0_SMP_AUTOZ_EG1R, conf->smp_autoz_eg1r),
+ LNaRSCCR0_SMP_AUTOZ_D1R |
+ LNaRSCCR0_SMP_AUTOZ_EG1R);
+
+ lynx_28g_lane_write(lane, LNaRCCR0, conf->rccr0);
+ lynx_28g_lane_write(lane, LNaTTLCR0, conf->ttlcr0);
+}
- if (!lane->powered_up)
- return 0;
+static int lynx_28g_lane_disable_pcvt(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode)
+{
+ struct lynx_28g_priv *priv = lane->priv;
+ int err;
- /* Issue a halt request */
- lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ);
- lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ);
+ spin_lock(&priv->pcc_lock);
- /* Wait until the halting process is complete */
- do {
- trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
- rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- } while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) ||
- (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ));
+ err = lynx_pccr_write(lane, lane_mode, 0);
+ if (err)
+ goto out;
- lane->powered_up = false;
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ err = lynx_pcvt_rmw(lane, lane_mode, CR(1), 0,
+ SGMIIaCR1_SGPCS_EN);
+ break;
+ default:
+ err = 0;
+ }
- return 0;
+out:
+ spin_unlock(&priv->pcc_lock);
+
+ return err;
}
-static int lynx_28g_power_on(struct phy *phy)
+static int lynx_28g_lane_enable_pcvt(struct lynx_28g_lane *lane,
+ enum lynx_lane_mode lane_mode)
{
- struct lynx_28g_lane *lane = phy_get_drvdata(phy);
- u32 trstctl, rrstctl;
+ struct lynx_28g_priv *priv = lane->priv;
+ u32 val;
+ int err;
- if (lane->powered_up)
- return 0;
+ spin_lock(&priv->pcc_lock);
- /* Issue a reset request on the lane */
- lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ);
- lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ err = lynx_pcvt_rmw(lane, lane_mode, CR(1), SGMIIaCR1_SGPCS_EN,
+ SGMIIaCR1_SGPCS_EN);
+ break;
+ default:
+ err = 0;
+ }
- /* Wait until the reset sequence is completed */
- do {
- trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
- rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- } while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) ||
- !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
+ val = 0;
- lane->powered_up = true;
+ switch (lane_mode) {
+ case LANE_MODE_1000BASEX_SGMII:
+ val |= PCC8_SGMIIa_CFG;
+ break;
+ case LANE_MODE_10GBASER:
+ val |= PCCC_SXGMIIn_XFI;
+ fallthrough;
+ case LANE_MODE_USXGMII:
+ val |= PCCC_SXGMIIn_CFG;
+ break;
+ default:
+ break;
+ }
- return 0;
+ err = lynx_pccr_write(lane, lane_mode, val);
+
+ spin_unlock(&priv->pcc_lock);
+
+ return err;
}
static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
@@ -396,44 +941,39 @@ static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
struct lynx_28g_priv *priv = lane->priv;
int powered_up = lane->powered_up;
+ enum lynx_lane_mode lane_mode;
int err = 0;
if (mode != PHY_MODE_ETHERNET)
return -EOPNOTSUPP;
- if (lane->interface == PHY_INTERFACE_MODE_NA)
+ if (lane->mode == LANE_MODE_UNKNOWN)
return -EOPNOTSUPP;
- if (!lynx_28g_supports_interface(priv, submode))
+ lane_mode = phy_interface_to_lane_mode(submode);
+ if (!lynx_28g_supports_lane_mode(priv, lane_mode))
return -EOPNOTSUPP;
+ if (lane_mode == lane->mode)
+ return 0;
+
/* If the lane is powered up, put the lane into the halt state while
* the reconfiguration is being done.
*/
if (powered_up)
lynx_28g_power_off(phy);
- spin_lock(&priv->pcc_lock);
-
- switch (submode) {
- case PHY_INTERFACE_MODE_SGMII:
- case PHY_INTERFACE_MODE_1000BASEX:
- lynx_28g_lane_set_sgmii(lane);
- break;
- case PHY_INTERFACE_MODE_10GBASER:
- lynx_28g_lane_set_10gbaser(lane);
- break;
- default:
- err = -EOPNOTSUPP;
+ err = lynx_28g_lane_disable_pcvt(lane, lane->mode);
+ if (err)
goto out;
- }
- lane->interface = submode;
+ lynx_28g_lane_change_proto_conf(lane, lane_mode);
+ lynx_28g_lane_remap_pll(lane, lane_mode);
+ WARN_ON(lynx_28g_lane_enable_pcvt(lane, lane_mode));
-out:
- spin_unlock(&priv->pcc_lock);
+ lane->mode = lane_mode;
- /* Power up the lane if necessary */
+out:
if (powered_up)
lynx_28g_power_on(phy);
@@ -445,11 +985,13 @@ static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
{
struct lynx_28g_lane *lane = phy_get_drvdata(phy);
struct lynx_28g_priv *priv = lane->priv;
+ enum lynx_lane_mode lane_mode;
if (mode != PHY_MODE_ETHERNET)
return -EOPNOTSUPP;
- if (!lynx_28g_supports_interface(priv, submode))
+ lane_mode = phy_interface_to_lane_mode(submode);
+ if (!lynx_28g_supports_lane_mode(priv, lane_mode))
return -EOPNOTSUPP;
return 0;
@@ -495,19 +1037,19 @@ static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
- if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
+ if (PLLnRSTCTL_DIS(pll->rstctl))
continue;
- switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
- case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
- case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
+ switch (FIELD_GET(PLLnCR1_FRATE_SEL, pll->cr1)) {
+ case PLLnCR1_FRATE_5G_10GVCO:
+ case PLLnCR1_FRATE_5G_25GVCO:
/* 5GHz clock net */
- __set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);
- __set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);
+ __set_bit(LANE_MODE_1000BASEX_SGMII, pll->supported);
break;
- case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
+ case PLLnCR1_FRATE_10G_20GVCO:
/* 10.3125GHz clock net */
- __set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);
+ __set_bit(LANE_MODE_10GBASER, pll->supported);
+ __set_bit(LANE_MODE_USXGMII, pll->supported);
break;
default:
/* 6GHz, 12.890625GHz, 8GHz */
@@ -536,11 +1078,12 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
}
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {
- lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
+ if (!(rrstctl & LNaRRSTCTL_CDR_LOCK)) {
+ lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ,
+ LNaRRSTCTL_RST_REQ);
do {
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
- } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
+ } while (!(rrstctl & LNaRRSTCTL_RST_DONE));
}
mutex_unlock(&lane->phy->mutex);
@@ -551,19 +1094,23 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work)
static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
{
- u32 pss, protocol;
+ u32 pccr, pss, protocol;
pss = lynx_28g_lane_read(lane, LNaPSS);
- protocol = LYNX_28G_LNaPSS_TYPE(pss);
+ protocol = FIELD_GET(LNaPSS_TYPE, pss);
switch (protocol) {
- case LYNX_28G_LNaPSS_TYPE_SGMII:
- lane->interface = PHY_INTERFACE_MODE_SGMII;
+ case LNaPSS_TYPE_SGMII:
+ lane->mode = LANE_MODE_1000BASEX_SGMII;
break;
- case LYNX_28G_LNaPSS_TYPE_XFI:
- lane->interface = PHY_INTERFACE_MODE_10GBASER;
+ case LNaPSS_TYPE_XFI:
+ lynx_pccr_read(lane, LANE_MODE_10GBASER, &pccr);
+ if (pccr & PCCC_SXGMIIn_XFI)
+ lane->mode = LANE_MODE_10GBASER;
+ else
+ lane->mode = LANE_MODE_USXGMII;
break;
default:
- lane->interface = PHY_INTERFACE_MODE_NA;
+ lane->mode = LANE_MODE_UNKNOWN;
}
}
@@ -571,7 +1118,14 @@ static struct phy *lynx_28g_xlate(struct device *dev,
const struct of_phandle_args *args)
{
struct lynx_28g_priv *priv = dev_get_drvdata(dev);
- int idx = args->args[0];
+ int idx;
+
+ if (args->args_count == 0)
+ return of_phy_simple_xlate(dev, args);
+ else if (args->args_count != 1)
+ return ERR_PTR(-ENODEV);
+
+ idx = args->args[0];
if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
return ERR_PTR(-EINVAL);
@@ -579,17 +1133,41 @@ static struct phy *lynx_28g_xlate(struct device *dev,
return priv->lane[idx].phy;
}
+static int lynx_28g_probe_lane(struct lynx_28g_priv *priv, int id,
+ struct device_node *dn)
+{
+ struct lynx_28g_lane *lane = &priv->lane[id];
+ struct phy *phy;
+
+ phy = devm_phy_create(priv->dev, dn, &lynx_28g_ops);
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
+
+ lane->priv = priv;
+ lane->phy = phy;
+ lane->id = id;
+ phy_set_drvdata(phy, lane);
+ lynx_28g_lane_read_configuration(lane);
+
+ return 0;
+}
+
static int lynx_28g_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct phy_provider *provider;
struct lynx_28g_priv *priv;
- int i;
+ struct device_node *dn;
+ int err;
- priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->dev = &pdev->dev;
+
+ priv->dev = dev;
+ dev_set_drvdata(dev, priv);
+ spin_lock_init(&priv->pcc_lock);
+ INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base))
@@ -597,35 +1175,51 @@ static int lynx_28g_probe(struct platform_device *pdev)
lynx_28g_pll_read_configuration(priv);
- for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
- struct lynx_28g_lane *lane = &priv->lane[i];
- struct phy *phy;
-
- memset(lane, 0, sizeof(*lane));
-
- phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops);
- if (IS_ERR(phy))
- return PTR_ERR(phy);
-
- lane->priv = priv;
- lane->phy = phy;
- lane->id = i;
- phy_set_drvdata(phy, lane);
- lynx_28g_lane_read_configuration(lane);
+ dn = dev_of_node(dev);
+ if (of_get_child_count(dn)) {
+ struct device_node *child;
+
+ for_each_available_child_of_node(dn, child) {
+ u32 reg;
+
+ /* PHY subnode name must be 'phy'. */
+ if (!(of_node_name_eq(child, "phy")))
+ continue;
+
+ if (of_property_read_u32(child, "reg", &reg)) {
+ dev_err(dev, "No \"reg\" property for %pOF\n", child);
+ of_node_put(child);
+ return -EINVAL;
+ }
+
+ if (reg >= LYNX_28G_NUM_LANE) {
+ dev_err(dev, "\"reg\" property out of range for %pOF\n", child);
+ of_node_put(child);
+ return -EINVAL;
+ }
+
+ err = lynx_28g_probe_lane(priv, reg, child);
+ if (err) {
+ of_node_put(child);
+ return err;
+ }
+ }
+ } else {
+ for (int i = 0; i < LYNX_28G_NUM_LANE; i++) {
+ err = lynx_28g_probe_lane(priv, i, NULL);
+ if (err)
+ return err;
+ }
}
- dev_set_drvdata(dev, priv);
-
- spin_lock_init(&priv->pcc_lock);
- INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
+ provider = devm_of_phy_provider_register(dev, lynx_28g_xlate);
+ if (IS_ERR(provider))
+ return PTR_ERR(provider);
queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
msecs_to_jiffies(1000));
- dev_set_drvdata(&pdev->dev, priv);
- provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate);
-
- return PTR_ERR_OR_ZERO(provider);
+ return 0;
}
static void lynx_28g_remove(struct platform_device *pdev)
diff --git a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
index 191c282246d9..d010fec15671 100644
--- a/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
+++ b/drivers/phy/freescale/phy-fsl-samsung-hdmi.c
@@ -570,17 +570,20 @@ const struct phy_config *fsl_samsung_hdmi_phy_find_settings(struct fsl_samsung_h
return fract_div_phy;
}
-static long fsl_samsung_hdmi_phy_clk_round_rate(struct clk_hw *hw,
- unsigned long rate, unsigned long *parent_rate)
+static int fsl_samsung_hdmi_phy_clk_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
{
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);
+ const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy,
+ req->rate);
if (target_settings == NULL)
return -EINVAL;
dev_dbg(phy->dev, "round_rate, closest rate = %u\n", target_settings->pixclk);
- return target_settings->pixclk;
+ req->rate = target_settings->pixclk;
+
+ return 0;
}
static int fsl_samsung_hdmi_phy_clk_set_rate(struct clk_hw *hw,
@@ -599,7 +602,7 @@ static int fsl_samsung_hdmi_phy_clk_set_rate(struct clk_hw *hw,
static const struct clk_ops phy_clk_ops = {
.recalc_rate = phy_clk_recalc_rate,
- .round_rate = fsl_samsung_hdmi_phy_clk_round_rate,
+ .determine_rate = fsl_samsung_hdmi_phy_clk_determine_rate,
.set_rate = fsl_samsung_hdmi_phy_clk_set_rate,
};