mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 15:32:33 +00:00
296 lines
8.6 KiB
Diff
296 lines
8.6 KiB
Diff
|
From 5654ec78dd7e64b1e04777b24007344329e6a63b Mon Sep 17 00:00:00 2001
|
||
|
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||
|
Date: Thu, 14 Oct 2021 00:39:11 +0200
|
||
|
Subject: net: dsa: qca8k: rework rgmii delay logic and scan for cpu port 6
|
||
|
|
||
|
Future proof commit. This switch have 2 CPU ports and one valid
|
||
|
configuration is first CPU port set to sgmii and second CPU port set to
|
||
|
rgmii-id. The current implementation detects delay only for CPU port
|
||
|
zero set to rgmii and doesn't count any delay set in a secondary CPU
|
||
|
port. Drop the current delay scan function and move it to the sgmii
|
||
|
parser function to generalize and implicitly add support for secondary
|
||
|
CPU port set to rgmii-id. Introduce new logic where delay is enabled
|
||
|
also with internal delay binding declared and rgmii set as PHY mode.
|
||
|
|
||
|
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||
|
---
|
||
|
drivers/net/dsa/qca8k.c | 165 ++++++++++++++++++++++++------------------------
|
||
|
drivers/net/dsa/qca8k.h | 10 ++-
|
||
|
2 files changed, 89 insertions(+), 86 deletions(-)
|
||
|
|
||
|
--- a/drivers/net/dsa/qca8k.c
|
||
|
+++ b/drivers/net/dsa/qca8k.c
|
||
|
@@ -889,68 +889,6 @@ qca8k_setup_mdio_bus(struct qca8k_priv *
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-qca8k_setup_of_rgmii_delay(struct qca8k_priv *priv)
|
||
|
-{
|
||
|
- struct device_node *port_dn;
|
||
|
- phy_interface_t mode;
|
||
|
- struct dsa_port *dp;
|
||
|
- u32 val;
|
||
|
-
|
||
|
- /* CPU port is already checked */
|
||
|
- dp = dsa_to_port(priv->ds, 0);
|
||
|
-
|
||
|
- port_dn = dp->dn;
|
||
|
-
|
||
|
- /* Check if port 0 is set to the correct type */
|
||
|
- of_get_phy_mode(port_dn, &mode);
|
||
|
- if (mode != PHY_INTERFACE_MODE_RGMII_ID &&
|
||
|
- mode != PHY_INTERFACE_MODE_RGMII_RXID &&
|
||
|
- mode != PHY_INTERFACE_MODE_RGMII_TXID) {
|
||
|
- return 0;
|
||
|
- }
|
||
|
-
|
||
|
- switch (mode) {
|
||
|
- case PHY_INTERFACE_MODE_RGMII_ID:
|
||
|
- case PHY_INTERFACE_MODE_RGMII_RXID:
|
||
|
- if (of_property_read_u32(port_dn, "rx-internal-delay-ps", &val))
|
||
|
- val = 2;
|
||
|
- else
|
||
|
- /* Switch regs accept value in ns, convert ps to ns */
|
||
|
- val = val / 1000;
|
||
|
-
|
||
|
- if (val > QCA8K_MAX_DELAY) {
|
||
|
- dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
|
||
|
- val = 3;
|
||
|
- }
|
||
|
-
|
||
|
- priv->rgmii_rx_delay = val;
|
||
|
- /* Stop here if we need to check only for rx delay */
|
||
|
- if (mode != PHY_INTERFACE_MODE_RGMII_ID)
|
||
|
- break;
|
||
|
-
|
||
|
- fallthrough;
|
||
|
- case PHY_INTERFACE_MODE_RGMII_TXID:
|
||
|
- if (of_property_read_u32(port_dn, "tx-internal-delay-ps", &val))
|
||
|
- val = 1;
|
||
|
- else
|
||
|
- /* Switch regs accept value in ns, convert ps to ns */
|
||
|
- val = val / 1000;
|
||
|
-
|
||
|
- if (val > QCA8K_MAX_DELAY) {
|
||
|
- dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
|
||
|
- val = 3;
|
||
|
- }
|
||
|
-
|
||
|
- priv->rgmii_tx_delay = val;
|
||
|
- break;
|
||
|
- default:
|
||
|
- return 0;
|
||
|
- }
|
||
|
-
|
||
|
- return 0;
|
||
|
-}
|
||
|
-
|
||
|
-static int
|
||
|
qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv)
|
||
|
{
|
||
|
u32 mask = 0;
|
||
|
@@ -996,19 +934,21 @@ static int qca8k_find_cpu_port(struct ds
|
||
|
static int
|
||
|
qca8k_parse_port_config(struct qca8k_priv *priv)
|
||
|
{
|
||
|
+ int port, cpu_port_index = 0, ret;
|
||
|
struct device_node *port_dn;
|
||
|
phy_interface_t mode;
|
||
|
struct dsa_port *dp;
|
||
|
- int port, ret;
|
||
|
+ u32 delay;
|
||
|
|
||
|
/* We have 2 CPU port. Check them */
|
||
|
- for (port = 0; port < QCA8K_NUM_PORTS; port++) {
|
||
|
+ for (port = 0; port < QCA8K_NUM_PORTS && cpu_port_index < QCA8K_NUM_CPU_PORTS; port++) {
|
||
|
/* Skip every other port */
|
||
|
if (port != 0 && port != 6)
|
||
|
continue;
|
||
|
|
||
|
dp = dsa_to_port(priv->ds, port);
|
||
|
port_dn = dp->dn;
|
||
|
+ cpu_port_index++;
|
||
|
|
||
|
if (!of_device_is_available(port_dn))
|
||
|
continue;
|
||
|
@@ -1017,12 +957,54 @@ qca8k_parse_port_config(struct qca8k_pri
|
||
|
if (ret)
|
||
|
continue;
|
||
|
|
||
|
- if (mode == PHY_INTERFACE_MODE_SGMII) {
|
||
|
+ switch (mode) {
|
||
|
+ case PHY_INTERFACE_MODE_RGMII:
|
||
|
+ case PHY_INTERFACE_MODE_RGMII_ID:
|
||
|
+ case PHY_INTERFACE_MODE_RGMII_TXID:
|
||
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
||
|
+ delay = 0;
|
||
|
+
|
||
|
+ if (!of_property_read_u32(port_dn, "tx-internal-delay-ps", &delay))
|
||
|
+ /* Switch regs accept value in ns, convert ps to ns */
|
||
|
+ delay = delay / 1000;
|
||
|
+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID ||
|
||
|
+ mode == PHY_INTERFACE_MODE_RGMII_TXID)
|
||
|
+ delay = 1;
|
||
|
+
|
||
|
+ if (delay > QCA8K_MAX_DELAY) {
|
||
|
+ dev_err(priv->dev, "rgmii tx delay is limited to a max value of 3ns, setting to the max value");
|
||
|
+ delay = 3;
|
||
|
+ }
|
||
|
+
|
||
|
+ priv->rgmii_tx_delay[cpu_port_index] = delay;
|
||
|
+
|
||
|
+ delay = 0;
|
||
|
+
|
||
|
+ if (!of_property_read_u32(port_dn, "rx-internal-delay-ps", &delay))
|
||
|
+ /* Switch regs accept value in ns, convert ps to ns */
|
||
|
+ delay = delay / 1000;
|
||
|
+ else if (mode == PHY_INTERFACE_MODE_RGMII_ID ||
|
||
|
+ mode == PHY_INTERFACE_MODE_RGMII_RXID)
|
||
|
+ delay = 2;
|
||
|
+
|
||
|
+ if (delay > QCA8K_MAX_DELAY) {
|
||
|
+ dev_err(priv->dev, "rgmii rx delay is limited to a max value of 3ns, setting to the max value");
|
||
|
+ delay = 3;
|
||
|
+ }
|
||
|
+
|
||
|
+ priv->rgmii_rx_delay[cpu_port_index] = delay;
|
||
|
+
|
||
|
+ break;
|
||
|
+ case PHY_INTERFACE_MODE_SGMII:
|
||
|
if (of_property_read_bool(port_dn, "qca,sgmii-txclk-falling-edge"))
|
||
|
priv->sgmii_tx_clk_falling_edge = true;
|
||
|
|
||
|
if (of_property_read_bool(port_dn, "qca,sgmii-rxclk-falling-edge"))
|
||
|
priv->sgmii_rx_clk_falling_edge = true;
|
||
|
+
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -1059,10 +1041,6 @@ qca8k_setup(struct dsa_switch *ds)
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
|
||
|
- ret = qca8k_setup_of_rgmii_delay(priv);
|
||
|
- if (ret)
|
||
|
- return ret;
|
||
|
-
|
||
|
ret = qca8k_setup_mac_pwr_sel(priv);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
@@ -1229,8 +1207,8 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||
|
const struct phylink_link_state *state)
|
||
|
{
|
||
|
struct qca8k_priv *priv = ds->priv;
|
||
|
- u32 reg, val;
|
||
|
- int ret;
|
||
|
+ int cpu_port_index, ret;
|
||
|
+ u32 reg, val, delay;
|
||
|
|
||
|
switch (port) {
|
||
|
case 0: /* 1st CPU port */
|
||
|
@@ -1242,6 +1220,7 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||
|
return;
|
||
|
|
||
|
reg = QCA8K_REG_PORT0_PAD_CTRL;
|
||
|
+ cpu_port_index = QCA8K_CPU_PORT0;
|
||
|
break;
|
||
|
case 1:
|
||
|
case 2:
|
||
|
@@ -1260,6 +1239,7 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||
|
return;
|
||
|
|
||
|
reg = QCA8K_REG_PORT6_PAD_CTRL;
|
||
|
+ cpu_port_index = QCA8K_CPU_PORT6;
|
||
|
break;
|
||
|
default:
|
||
|
dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
|
||
|
@@ -1274,23 +1254,40 @@ qca8k_phylink_mac_config(struct dsa_swit
|
||
|
|
||
|
switch (state->interface) {
|
||
|
case PHY_INTERFACE_MODE_RGMII:
|
||
|
- /* RGMII mode means no delay so don't enable the delay */
|
||
|
- qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
|
||
|
- break;
|
||
|
case PHY_INTERFACE_MODE_RGMII_ID:
|
||
|
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||
|
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||
|
- /* RGMII_ID needs internal delay. This is enabled through
|
||
|
- * PORT5_PAD_CTRL for all ports, rather than individual port
|
||
|
- * registers
|
||
|
+ val = QCA8K_PORT_PAD_RGMII_EN;
|
||
|
+
|
||
|
+ /* Delay can be declared in 3 different way.
|
||
|
+ * Mode to rgmii and internal-delay standard binding defined
|
||
|
+ * rgmii-id or rgmii-tx/rx phy mode set.
|
||
|
+ * The parse logic set a delay different than 0 only when one
|
||
|
+ * of the 3 different way is used. In all other case delay is
|
||
|
+ * not enabled. With ID or TX/RXID delay is enabled and set
|
||
|
+ * to the default and recommended value.
|
||
|
+ */
|
||
|
+ if (priv->rgmii_tx_delay[cpu_port_index]) {
|
||
|
+ delay = priv->rgmii_tx_delay[cpu_port_index];
|
||
|
+
|
||
|
+ val |= QCA8K_PORT_PAD_RGMII_TX_DELAY(delay) |
|
||
|
+ QCA8K_PORT_PAD_RGMII_TX_DELAY_EN;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (priv->rgmii_rx_delay[cpu_port_index]) {
|
||
|
+ delay = priv->rgmii_rx_delay[cpu_port_index];
|
||
|
+
|
||
|
+ val |= QCA8K_PORT_PAD_RGMII_RX_DELAY(delay) |
|
||
|
+ QCA8K_PORT_PAD_RGMII_RX_DELAY_EN;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Set RGMII delay based on the selected values */
|
||
|
+ qca8k_write(priv, reg, val);
|
||
|
+
|
||
|
+ /* QCA8337 requires to set rgmii rx delay for all ports.
|
||
|
+ * This is enabled through PORT5_PAD_CTRL for all ports,
|
||
|
+ * rather than individual port registers.
|
||
|
*/
|
||
|
- qca8k_write(priv, reg,
|
||
|
- QCA8K_PORT_PAD_RGMII_EN |
|
||
|
- QCA8K_PORT_PAD_RGMII_TX_DELAY(priv->rgmii_tx_delay) |
|
||
|
- QCA8K_PORT_PAD_RGMII_RX_DELAY(priv->rgmii_rx_delay) |
|
||
|
- QCA8K_PORT_PAD_RGMII_TX_DELAY_EN |
|
||
|
- QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
|
||
|
- /* QCA8337 requires to set rgmii rx delay */
|
||
|
if (priv->switch_id == QCA8K_ID_QCA8337)
|
||
|
qca8k_write(priv, QCA8K_REG_PORT5_PAD_CTRL,
|
||
|
QCA8K_PORT_PAD_RGMII_RX_DELAY_EN);
|
||
|
--- a/drivers/net/dsa/qca8k.h
|
||
|
+++ b/drivers/net/dsa/qca8k.h
|
||
|
@@ -13,6 +13,7 @@
|
||
|
#include <linux/gpio.h>
|
||
|
|
||
|
#define QCA8K_NUM_PORTS 7
|
||
|
+#define QCA8K_NUM_CPU_PORTS 2
|
||
|
#define QCA8K_MAX_MTU 9000
|
||
|
|
||
|
#define PHY_ID_QCA8327 0x004dd034
|
||
|
@@ -255,13 +256,18 @@ struct qca8k_match_data {
|
||
|
u8 id;
|
||
|
};
|
||
|
|
||
|
+enum {
|
||
|
+ QCA8K_CPU_PORT0,
|
||
|
+ QCA8K_CPU_PORT6,
|
||
|
+};
|
||
|
+
|
||
|
struct qca8k_priv {
|
||
|
u8 switch_id;
|
||
|
u8 switch_revision;
|
||
|
- u8 rgmii_tx_delay;
|
||
|
- u8 rgmii_rx_delay;
|
||
|
bool sgmii_rx_clk_falling_edge;
|
||
|
bool sgmii_tx_clk_falling_edge;
|
||
|
+ u8 rgmii_rx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
|
||
|
+ u8 rgmii_tx_delay[QCA8K_NUM_CPU_PORTS]; /* 0: CPU port0, 1: CPU port6 */
|
||
|
bool legacy_phy_port_mapping;
|
||
|
struct regmap *regmap;
|
||
|
struct mii_bus *bus;
|