Skip to content

Commit

Permalink
net: dsa: qca8k: rework rgmii delay logic and scan for cpu port 6
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ansuel Smith authored and David S. Miller committed Oct 15, 2021
1 parent 3fcf734 commit 5654ec7
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 86 deletions.
165 changes: 81 additions & 84 deletions drivers/net/dsa/qca8k.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,68 +888,6 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
return 0;
}

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)
{
Expand Down Expand Up @@ -996,19 +934,21 @@ static int qca8k_find_cpu_port(struct dsa_switch *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;
Expand All @@ -1017,12 +957,54 @@ qca8k_parse_port_config(struct qca8k_priv *priv)
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;
}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1229,8 +1207,8 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
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 */
Expand All @@ -1242,6 +1220,7 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
return;

reg = QCA8K_REG_PORT0_PAD_CTRL;
cpu_port_index = QCA8K_CPU_PORT0;
break;
case 1:
case 2:
Expand All @@ -1260,6 +1239,7 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
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);
Expand All @@ -1274,23 +1254,40 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,

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);
Expand Down
10 changes: 8 additions & 2 deletions drivers/net/dsa/qca8k.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 5654ec7

Please sign in to comment.