123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- From 5654ec78dd7e64b1e04777b24007344329e6a63b Mon Sep 17 00:00:00 2001
- From: Ansuel Smith <[email protected]>
- 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 <[email protected]>
- Signed-off-by: David S. Miller <[email protected]>
- ---
- 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;
|