mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-06-10 14:22:05 +08:00

Refreshed patches for qualcommb/ipq95xx by running make target/linux/refresh after creating a .config containing: CONFIG_TARGET_qualcommbe=y CONFIG_TARGET_qualcommbe_ipq95xx=y CONFIG_TARGET_qualcommbe_ipq95xx_DEVICE_qcom_rdp433=y Signed-off-by: John Audia <therealgraysky@proton.me> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
361 lines
11 KiB
Diff
361 lines
11 KiB
Diff
From d96ec0527b0f5618b3a0757b47606705555ee996 Mon Sep 17 00:00:00 2001
|
|
From: Lei Wei <quic_leiwei@quicinc.com>
|
|
Date: Mon, 15 Apr 2024 11:06:02 +0800
|
|
Subject: [PATCH 15/50] net:pcs: Add 10G_QXGMII interface mode support to IPQ
|
|
UNIPHY PCS driver
|
|
|
|
10G_QXGMII is used when PCS connectes with QCA8084 four ports
|
|
2.5G PHYs.
|
|
|
|
Change-Id: If3dc92a07ac3e51f7c9473fb05fa0668617916fb
|
|
Signed-off-by: Lei Wei <quic_leiwei@quicinc.com>
|
|
---
|
|
drivers/net/pcs/pcs-qcom-ipq-uniphy.c | 174 +++++++++++++++++++++-----
|
|
1 file changed, 142 insertions(+), 32 deletions(-)
|
|
|
|
--- a/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
|
|
+++ b/drivers/net/pcs/pcs-qcom-ipq-uniphy.c
|
|
@@ -50,6 +50,9 @@
|
|
#define PCS_CHANNEL_STS_PAUSE_TX_EN BIT(1)
|
|
#define PCS_CHANNEL_STS_PAUSE_RX_EN BIT(0)
|
|
|
|
+#define PCS_QP_USXG_OPTION 0x584
|
|
+#define PCS_QP_USXG_GMII_SRC_XPCS BIT(0)
|
|
+
|
|
#define PCS_PLL_RESET 0x780
|
|
#define PCS_ANA_SW_RESET BIT(6)
|
|
|
|
@@ -65,10 +68,22 @@
|
|
#define XPCS_10GBASER_LINK_STS BIT(12)
|
|
|
|
#define XPCS_DIG_CTRL 0x38000
|
|
+#define XPCS_SOFT_RESET BIT(15)
|
|
#define XPCS_USXG_ADPT_RESET BIT(10)
|
|
#define XPCS_USXG_EN BIT(9)
|
|
|
|
+#define XPCS_KR_CTRL 0x38007
|
|
+#define XPCS_USXG_MODE_MASK GENMASK(12, 10)
|
|
+#define XPCS_10G_QXGMII_MODE FIELD_PREP(XPCS_USXG_MODE_MASK, 0x5)
|
|
+
|
|
+#define XPCS_DIG_STS 0x3800a
|
|
+#define XPCS_DIG_STS_AM_COUNT GENMASK(14, 0)
|
|
+
|
|
+#define XPCS_CHANNEL_DIG_CTRL(x) (0x1a8000 + 0x10000 * ((x) - 1))
|
|
+#define XPCS_CHANNEL_USXG_ADPT_RESET BIT(5)
|
|
+
|
|
#define XPCS_MII_CTRL 0x1f0000
|
|
+#define XPCS_CHANNEL_MII_CTRL(x) (0x1a0000 + 0x10000 * ((x) - 1))
|
|
#define XPCS_MII_AN_EN BIT(12)
|
|
#define XPCS_DUPLEX_FULL BIT(8)
|
|
#define XPCS_SPEED_MASK (BIT(13) | BIT(6) | BIT(5))
|
|
@@ -80,9 +95,11 @@
|
|
#define XPCS_SPEED_10 0
|
|
|
|
#define XPCS_MII_AN_CTRL 0x1f8001
|
|
+#define XPCS_CHANNEL_MII_AN_CTRL(x) (0x1a8001 + 0x10000 * ((x) - 1))
|
|
#define XPCS_MII_AN_8BIT BIT(8)
|
|
|
|
#define XPCS_MII_AN_INTR_STS 0x1f8002
|
|
+#define XPCS_CHANNEL_MII_AN_INTR_STS(x) (0x1a8002 + 0x10000 * ((x) - 1))
|
|
#define XPCS_USXG_AN_LINK_STS BIT(14)
|
|
#define XPCS_USXG_AN_DUPLEX_FULL BIT(13)
|
|
#define XPCS_USXG_AN_SPEED_MASK GENMASK(12, 10)
|
|
@@ -93,6 +110,10 @@
|
|
#define XPCS_USXG_AN_SPEED_5000 5
|
|
#define XPCS_USXG_AN_SPEED_10000 3
|
|
|
|
+#define XPCS_XAUI_MODE_CTRL 0x1f8004
|
|
+#define XPCS_CHANNEL_XAUI_MODE_CTRL(x) (0x1a8004 + 0x10000 * ((x) - 1))
|
|
+#define XPCS_TX_IPG_CHECK_DIS BIT(0)
|
|
+
|
|
/* UNIPHY PCS RAW clock ID */
|
|
enum {
|
|
PCS_RAW_RX_CLK = 0,
|
|
@@ -153,6 +174,7 @@ struct ipq_uniphy_pcs {
|
|
struct device *dev;
|
|
phy_interface_t interface;
|
|
struct mutex shared_lock; /* Lock to protect shared config */
|
|
+ spinlock_t reg_lock; /* Lock for register access */
|
|
struct clk *clk[PCS_CLK_MAX];
|
|
struct reset_control *reset[PCS_RESET_MAX];
|
|
struct ipq_unipcs_raw_clk raw_clk[PCS_RAW_CLK_MAX];
|
|
@@ -215,39 +237,55 @@ static const struct clk_ops ipq_unipcs_r
|
|
|
|
static u32 ipq_unipcs_reg_read32(struct ipq_uniphy_pcs *qunipcs, u32 reg)
|
|
{
|
|
+ u32 val;
|
|
+
|
|
/* PCS use direct AHB access while XPCS use indirect AHB access */
|
|
if (reg >= XPCS_INDIRECT_ADDR) {
|
|
+ /* For XPCS, althrough the register is different for different
|
|
+ * channels, but they use the same indirect AHB address to
|
|
+ * access, so add protects here.
|
|
+ */
|
|
+ spin_lock(&qunipcs->reg_lock);
|
|
+
|
|
writel(FIELD_GET(XPCS_INDIRECT_ADDR_H, reg),
|
|
qunipcs->base + XPCS_INDIRECT_AHB_ADDR);
|
|
- return readl(qunipcs->base + XPCS_INDIRECT_DATA_ADDR(reg));
|
|
+ val = readl(qunipcs->base + XPCS_INDIRECT_DATA_ADDR(reg));
|
|
+
|
|
+ spin_unlock(&qunipcs->reg_lock);
|
|
+ return val;
|
|
} else {
|
|
return readl(qunipcs->base + reg);
|
|
}
|
|
}
|
|
|
|
-static void ipq_unipcs_reg_write32(struct ipq_uniphy_pcs *qunipcs,
|
|
- u32 reg, u32 val)
|
|
+static void ipq_unipcs_reg_modify32(struct ipq_uniphy_pcs *qunipcs,
|
|
+ u32 reg, u32 mask, u32 set)
|
|
{
|
|
+ u32 val;
|
|
+
|
|
if (reg >= XPCS_INDIRECT_ADDR) {
|
|
+ spin_lock(&qunipcs->reg_lock);
|
|
+
|
|
+ /* XPCS read */
|
|
writel(FIELD_GET(XPCS_INDIRECT_ADDR_H, reg),
|
|
qunipcs->base + XPCS_INDIRECT_AHB_ADDR);
|
|
+ val = readl(qunipcs->base + XPCS_INDIRECT_DATA_ADDR(reg));
|
|
+
|
|
+ val &= ~mask;
|
|
+ val |= set;
|
|
+
|
|
+ /* XPCS write */
|
|
writel(val, qunipcs->base + XPCS_INDIRECT_DATA_ADDR(reg));
|
|
+
|
|
+ spin_unlock(&qunipcs->reg_lock);
|
|
} else {
|
|
+ val = readl(qunipcs->base + reg);
|
|
+ val &= ~mask;
|
|
+ val |= set;
|
|
writel(val, qunipcs->base + reg);
|
|
}
|
|
}
|
|
|
|
-static void ipq_unipcs_reg_modify32(struct ipq_uniphy_pcs *qunipcs,
|
|
- u32 reg, u32 mask, u32 set)
|
|
-{
|
|
- u32 val;
|
|
-
|
|
- val = ipq_unipcs_reg_read32(qunipcs, reg);
|
|
- val &= ~mask;
|
|
- val |= set;
|
|
- ipq_unipcs_reg_write32(qunipcs, reg, val);
|
|
-}
|
|
-
|
|
static void ipq_unipcs_get_state_sgmii(struct ipq_uniphy_pcs *qunipcs,
|
|
int channel,
|
|
struct phylink_link_state *state)
|
|
@@ -305,11 +343,15 @@ static void ipq_unipcs_get_state_2500bas
|
|
}
|
|
|
|
static void ipq_unipcs_get_state_usxgmii(struct ipq_uniphy_pcs *qunipcs,
|
|
+ int channel,
|
|
struct phylink_link_state *state)
|
|
{
|
|
- u32 val;
|
|
+ u32 val, reg;
|
|
+
|
|
+ reg = (channel == 0) ? XPCS_MII_AN_INTR_STS :
|
|
+ XPCS_CHANNEL_MII_AN_INTR_STS(channel);
|
|
|
|
- val = ipq_unipcs_reg_read32(qunipcs, XPCS_MII_AN_INTR_STS);
|
|
+ val = ipq_unipcs_reg_read32(qunipcs, reg);
|
|
|
|
state->link = !!(val & XPCS_USXG_AN_LINK_STS);
|
|
|
|
@@ -415,6 +457,15 @@ static int ipq_unipcs_config_mode(struct
|
|
PCS_MODE_SEL_MASK,
|
|
PCS_MODE_XPCS);
|
|
break;
|
|
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
|
+ rate = 312500000;
|
|
+ ipq_unipcs_reg_modify32(qunipcs, PCS_MODE_CTRL,
|
|
+ PCS_MODE_SEL_MASK,
|
|
+ PCS_MODE_XPCS);
|
|
+ ipq_unipcs_reg_modify32(qunipcs, PCS_QP_USXG_OPTION,
|
|
+ PCS_QP_USXG_GMII_SRC_XPCS,
|
|
+ PCS_QP_USXG_GMII_SRC_XPCS);
|
|
+ break;
|
|
default:
|
|
dev_err(qunipcs->dev,
|
|
"interface %s not supported\n", phy_modes(interface));
|
|
@@ -502,35 +553,82 @@ static int ipq_unipcs_config_2500basex(s
|
|
}
|
|
|
|
static int ipq_unipcs_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
|
|
+ int channel,
|
|
unsigned int neg_mode,
|
|
phy_interface_t interface)
|
|
{
|
|
int ret;
|
|
+ u32 reg;
|
|
+
|
|
+ /* Only in-band autoneg mode is supported currently */
|
|
+ if (neg_mode != PHYLINK_PCS_NEG_INBAND_ENABLED)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ if (interface == PHY_INTERFACE_MODE_10G_QXGMII)
|
|
+ mutex_lock(&qunipcs->shared_lock);
|
|
|
|
if (qunipcs->interface != interface) {
|
|
ret = ipq_unipcs_config_mode(qunipcs, interface);
|
|
if (ret)
|
|
- return ret;
|
|
+ goto err;
|
|
|
|
- /* Deassert XPCS and configure XPCS USXGMII */
|
|
+ /* Deassert XPCS and configure XPCS USXGMII or 10G_QXGMII */
|
|
reset_control_deassert(qunipcs->reset[XPCS_RESET]);
|
|
|
|
ipq_unipcs_reg_modify32(qunipcs, XPCS_DIG_CTRL,
|
|
XPCS_USXG_EN, XPCS_USXG_EN);
|
|
|
|
- if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
|
|
- ipq_unipcs_reg_modify32(qunipcs, XPCS_MII_AN_CTRL,
|
|
- XPCS_MII_AN_8BIT,
|
|
- XPCS_MII_AN_8BIT);
|
|
-
|
|
- ipq_unipcs_reg_modify32(qunipcs, XPCS_MII_CTRL,
|
|
- XPCS_MII_AN_EN, XPCS_MII_AN_EN);
|
|
+ if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
|
|
+ ipq_unipcs_reg_modify32(qunipcs, XPCS_KR_CTRL,
|
|
+ XPCS_USXG_MODE_MASK,
|
|
+ XPCS_10G_QXGMII_MODE);
|
|
+
|
|
+ /* Set Alignment Marker Interval */
|
|
+ ipq_unipcs_reg_modify32(qunipcs, XPCS_DIG_STS,
|
|
+ XPCS_DIG_STS_AM_COUNT,
|
|
+ 0x6018);
|
|
+
|
|
+ ipq_unipcs_reg_modify32(qunipcs, XPCS_DIG_CTRL,
|
|
+ XPCS_SOFT_RESET,
|
|
+ XPCS_SOFT_RESET);
|
|
}
|
|
|
|
qunipcs->interface = interface;
|
|
}
|
|
|
|
+ if (interface == PHY_INTERFACE_MODE_10G_QXGMII)
|
|
+ mutex_unlock(&qunipcs->shared_lock);
|
|
+
|
|
+ /* Disable Tx IPG check for 10G_QXGMII */
|
|
+ if (interface == PHY_INTERFACE_MODE_10G_QXGMII) {
|
|
+ reg = (channel == 0) ? XPCS_XAUI_MODE_CTRL :
|
|
+ XPCS_CHANNEL_XAUI_MODE_CTRL(channel);
|
|
+
|
|
+ ipq_unipcs_reg_modify32(qunipcs, reg,
|
|
+ XPCS_TX_IPG_CHECK_DIS,
|
|
+ XPCS_TX_IPG_CHECK_DIS);
|
|
+ }
|
|
+
|
|
+ /* Enable autoneg */
|
|
+ reg = (channel == 0) ? XPCS_MII_AN_CTRL :
|
|
+ XPCS_CHANNEL_MII_AN_CTRL(channel);
|
|
+
|
|
+ ipq_unipcs_reg_modify32(qunipcs, reg,
|
|
+ XPCS_MII_AN_8BIT, XPCS_MII_AN_8BIT);
|
|
+
|
|
+ reg = (channel == 0) ? XPCS_MII_CTRL :
|
|
+ XPCS_CHANNEL_MII_CTRL(channel);
|
|
+
|
|
+ ipq_unipcs_reg_modify32(qunipcs, reg,
|
|
+ XPCS_MII_AN_EN, XPCS_MII_AN_EN);
|
|
+
|
|
return 0;
|
|
+
|
|
+err:
|
|
+ if (interface == PHY_INTERFACE_MODE_10G_QXGMII)
|
|
+ mutex_unlock(&qunipcs->shared_lock);
|
|
+
|
|
+ return ret;
|
|
}
|
|
|
|
static int ipq_unipcs_config_10gbaser(struct ipq_uniphy_pcs *qunipcs,
|
|
@@ -638,6 +736,7 @@ ipq_unipcs_link_up_clock_rate_set(struct
|
|
break;
|
|
case PHY_INTERFACE_MODE_USXGMII:
|
|
case PHY_INTERFACE_MODE_10GBASER:
|
|
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
|
rate = ipq_unipcs_clock_rate_get_xgmii(speed);
|
|
break;
|
|
default:
|
|
@@ -713,9 +812,10 @@ static void ipq_unipcs_link_up_config_25
|
|
}
|
|
|
|
static void ipq_unipcs_link_up_config_usxgmii(struct ipq_uniphy_pcs *qunipcs,
|
|
+ int channel,
|
|
int speed)
|
|
{
|
|
- u32 val;
|
|
+ u32 val, reg;
|
|
|
|
switch (speed) {
|
|
case SPEED_10000:
|
|
@@ -744,14 +844,20 @@ static void ipq_unipcs_link_up_config_us
|
|
val |= XPCS_DUPLEX_FULL;
|
|
|
|
/* Config XPCS speed */
|
|
- ipq_unipcs_reg_modify32(qunipcs, XPCS_MII_CTRL,
|
|
+ reg = (channel == 0) ? XPCS_MII_CTRL : XPCS_CHANNEL_MII_CTRL(channel);
|
|
+ ipq_unipcs_reg_modify32(qunipcs, reg,
|
|
XPCS_SPEED_MASK | XPCS_DUPLEX_FULL,
|
|
val);
|
|
|
|
/* XPCS adapter reset */
|
|
- ipq_unipcs_reg_modify32(qunipcs, XPCS_DIG_CTRL,
|
|
- XPCS_USXG_ADPT_RESET,
|
|
- XPCS_USXG_ADPT_RESET);
|
|
+ if (channel == 0)
|
|
+ ipq_unipcs_reg_modify32(qunipcs, XPCS_DIG_CTRL,
|
|
+ XPCS_USXG_ADPT_RESET,
|
|
+ XPCS_USXG_ADPT_RESET);
|
|
+ else
|
|
+ ipq_unipcs_reg_modify32(qunipcs, XPCS_CHANNEL_DIG_CTRL(channel),
|
|
+ XPCS_CHANNEL_USXG_ADPT_RESET,
|
|
+ XPCS_CHANNEL_USXG_ADPT_RESET);
|
|
}
|
|
|
|
static int ipq_unipcs_validate(struct phylink_pcs *pcs,
|
|
@@ -786,7 +892,8 @@ static void ipq_unipcs_get_state(struct
|
|
ipq_unipcs_get_state_2500basex(qunipcs, channel, state);
|
|
break;
|
|
case PHY_INTERFACE_MODE_USXGMII:
|
|
- ipq_unipcs_get_state_usxgmii(qunipcs, state);
|
|
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
|
+ ipq_unipcs_get_state_usxgmii(qunipcs, channel, state);
|
|
break;
|
|
case PHY_INTERFACE_MODE_10GBASER:
|
|
ipq_unipcs_get_state_10gbaser(qunipcs, state);
|
|
@@ -823,7 +930,8 @@ static int ipq_unipcs_config(struct phyl
|
|
case PHY_INTERFACE_MODE_2500BASEX:
|
|
return ipq_unipcs_config_2500basex(qunipcs, interface);
|
|
case PHY_INTERFACE_MODE_USXGMII:
|
|
- return ipq_unipcs_config_usxgmii(qunipcs,
|
|
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
|
+ return ipq_unipcs_config_usxgmii(qunipcs, channel,
|
|
neg_mode, interface);
|
|
case PHY_INTERFACE_MODE_10GBASER:
|
|
return ipq_unipcs_config_10gbaser(qunipcs, interface);
|
|
@@ -865,7 +973,8 @@ static void ipq_unipcs_link_up(struct ph
|
|
channel, speed);
|
|
break;
|
|
case PHY_INTERFACE_MODE_USXGMII:
|
|
- ipq_unipcs_link_up_config_usxgmii(qunipcs, speed);
|
|
+ case PHY_INTERFACE_MODE_10G_QXGMII:
|
|
+ ipq_unipcs_link_up_config_usxgmii(qunipcs, channel, speed);
|
|
break;
|
|
case PHY_INTERFACE_MODE_10GBASER:
|
|
break;
|
|
@@ -1082,6 +1191,7 @@ static int ipq_uniphy_probe(struct platf
|
|
return ret;
|
|
|
|
mutex_init(&priv->shared_lock);
|
|
+ spin_lock_init(&priv->reg_lock);
|
|
|
|
platform_set_drvdata(pdev, priv);
|
|
|