net: dsa: sja1105: Add RGMII delay support for P/Q/R/S chips
authorVladimir Oltean <olteanv@gmail.com>
Sat, 8 Jun 2019 16:12:28 +0000 (19:12 +0300)
committerDavid S. Miller <davem@davemloft.net>
Mon, 10 Jun 2019 03:06:54 +0000 (20:06 -0700)
As per the DT phy-mode specification, RGMII delays are applied by the
MAC when there is no PHY present on the link.

Signed-off-by: Vladimir Oltean <olteanv@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/sja1105/sja1105.h
drivers/net/dsa/sja1105/sja1105_clocking.c
drivers/net/dsa/sja1105/sja1105_spi.c

index 3e0f685a144cd979828401980ad44ce3d92044d6..78094db3262243a0d58de0485679ff1c31f0eaef 100644 (file)
@@ -161,6 +161,7 @@ typedef enum {
        SJA1105_SPEED_AUTO      = 0,
 } sja1105_speed_t;
 
+int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
 int sja1105_clocking_setup_port(struct sja1105_private *priv, int port);
 int sja1105_clocking_setup(struct sja1105_private *priv);
 
index 5c7cea22b64736ee978317309a27417191308c2c..608126a15d726bda62f062e839cede52a669b9d3 100644 (file)
@@ -19,6 +19,17 @@ struct sja1105_cfg_pad_mii_tx {
        u64 clk_ipud;
 };
 
+struct sja1105_cfg_pad_mii_id {
+       u64 rxc_stable_ovr;
+       u64 rxc_delay;
+       u64 rxc_bypass;
+       u64 rxc_pd;
+       u64 txc_stable_ovr;
+       u64 txc_delay;
+       u64 txc_bypass;
+       u64 txc_pd;
+};
+
 /* UM10944 Table 82.
  * IDIV_0_C to IDIV_4_C control registers
  * (addr. 10000Bh to 10000Fh)
@@ -377,7 +388,84 @@ static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
                                           packed_buf, SJA1105_SIZE_CGU_CMD);
 }
 
-static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port)
+static void
+sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
+                              enum packing_op op)
+{
+       const int size = SJA1105_SIZE_CGU_CMD;
+
+       sja1105_packing(buf, &cmd->rxc_stable_ovr, 15, 15, size, op);
+       sja1105_packing(buf, &cmd->rxc_delay,      14, 10, size, op);
+       sja1105_packing(buf, &cmd->rxc_bypass,      9,  9, size, op);
+       sja1105_packing(buf, &cmd->rxc_pd,          8,  8, size, op);
+       sja1105_packing(buf, &cmd->txc_stable_ovr,  7,  7, size, op);
+       sja1105_packing(buf, &cmd->txc_delay,       6,  2, size, op);
+       sja1105_packing(buf, &cmd->txc_bypass,      1,  1, size, op);
+       sja1105_packing(buf, &cmd->txc_pd,          0,  0, size, op);
+}
+
+/* Valid range in degrees is an integer between 73.8 and 101.7 */
+static inline u64 sja1105_rgmii_delay(u64 phase)
+{
+       /* UM11040.pdf: The delay in degree phase is 73.8 + delay_tune * 0.9.
+        * To avoid floating point operations we'll multiply by 10
+        * and get 1 decimal point precision.
+        */
+       phase *= 10;
+       return (phase - 738) / 9;
+}
+
+/* The RGMII delay setup procedure is 2-step and gets called upon each
+ * .phylink_mac_config. Both are strategic.
+ * The reason is that the RX Tunable Delay Line of the SJA1105 MAC has issues
+ * with recovering from a frequency change of the link partner's RGMII clock.
+ * The easiest way to recover from this is to temporarily power down the TDL,
+ * as it will re-lock at the new frequency afterwards.
+ */
+int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port)
+{
+       const struct sja1105_private *priv = ctx;
+       const struct sja1105_regs *regs = priv->info->regs;
+       struct sja1105_cfg_pad_mii_id pad_mii_id = {0};
+       u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+       int rc;
+
+       if (priv->rgmii_rx_delay[port])
+               pad_mii_id.rxc_delay = sja1105_rgmii_delay(90);
+       if (priv->rgmii_tx_delay[port])
+               pad_mii_id.txc_delay = sja1105_rgmii_delay(90);
+
+       /* Stage 1: Turn the RGMII delay lines off. */
+       pad_mii_id.rxc_bypass = 1;
+       pad_mii_id.rxc_pd = 1;
+       pad_mii_id.txc_bypass = 1;
+       pad_mii_id.txc_pd = 1;
+       sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+       rc = sja1105_spi_send_packed_buf(priv, SPI_WRITE,
+                                        regs->pad_mii_id[port],
+                                        packed_buf, SJA1105_SIZE_CGU_CMD);
+       if (rc < 0)
+               return rc;
+
+       /* Stage 2: Turn the RGMII delay lines on. */
+       if (priv->rgmii_rx_delay[port]) {
+               pad_mii_id.rxc_bypass = 0;
+               pad_mii_id.rxc_pd = 0;
+       }
+       if (priv->rgmii_tx_delay[port]) {
+               pad_mii_id.txc_bypass = 0;
+               pad_mii_id.txc_pd = 0;
+       }
+       sja1105_cfg_pad_mii_id_packing(packed_buf, &pad_mii_id, PACK);
+
+       return sja1105_spi_send_packed_buf(priv, SPI_WRITE,
+                                          regs->pad_mii_id[port],
+                                          packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
+static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port,
+                                       sja1105_mii_role_t role)
 {
        struct device *dev = priv->ds->dev;
        struct sja1105_mac_config_entry *mac;
@@ -429,6 +517,12 @@ static int sja1105_rgmii_clocking_setup(struct sja1105_private *priv, int port)
        }
        if (!priv->info->setup_rgmii_delay)
                return 0;
+       /* The role has no hardware effect for RGMII. However we use it as
+        * a proxy for this interface being a MAC-to-MAC connection, with
+        * the RGMII internal delays needing to be applied by us.
+        */
+       if (role == XMII_MAC)
+               return 0;
 
        return priv->info->setup_rgmii_delay(priv, port);
 }
@@ -575,7 +669,7 @@ int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
                rc = sja1105_rmii_clocking_setup(priv, port, role);
                break;
        case XMII_MODE_RGMII:
-               rc = sja1105_rgmii_clocking_setup(priv, port);
+               rc = sja1105_rgmii_clocking_setup(priv, port, role);
                break;
        default:
                dev_err(dev, "Invalid interface mode specified: %d\n",
index feb9e0422a683e5b7de5fa4d00f41dabffd262a1..f7e51debb9302290b0955b47696c71b3e67f111d 100644 (file)
@@ -531,6 +531,7 @@ static struct sja1105_regs sja1105pqrs_regs = {
        .rgu = 0x100440,
        /* UM10944.pdf, Table 86, ACU Register overview */
        .pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
+       .pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
        .rmii_pll1 = 0x10000A,
        .cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
        .mac = {0x200, 0x202, 0x204, 0x206, 0x208},
@@ -587,6 +588,7 @@ struct sja1105_info sja1105p_info = {
        .dyn_ops                = sja1105pqrs_dyn_ops,
        .ptp_ts_bits            = 32,
        .ptpegr_ts_bytes        = 8,
+       .setup_rgmii_delay      = sja1105pqrs_setup_rgmii_delay,
        .reset_cmd              = sja1105pqrs_reset_cmd,
        .fdb_add_cmd            = sja1105pqrs_fdb_add,
        .fdb_del_cmd            = sja1105pqrs_fdb_del,
@@ -601,6 +603,7 @@ struct sja1105_info sja1105q_info = {
        .dyn_ops                = sja1105pqrs_dyn_ops,
        .ptp_ts_bits            = 32,
        .ptpegr_ts_bytes        = 8,
+       .setup_rgmii_delay      = sja1105pqrs_setup_rgmii_delay,
        .reset_cmd              = sja1105pqrs_reset_cmd,
        .fdb_add_cmd            = sja1105pqrs_fdb_add,
        .fdb_del_cmd            = sja1105pqrs_fdb_del,
@@ -615,6 +618,7 @@ struct sja1105_info sja1105r_info = {
        .dyn_ops                = sja1105pqrs_dyn_ops,
        .ptp_ts_bits            = 32,
        .ptpegr_ts_bytes        = 8,
+       .setup_rgmii_delay      = sja1105pqrs_setup_rgmii_delay,
        .reset_cmd              = sja1105pqrs_reset_cmd,
        .fdb_add_cmd            = sja1105pqrs_fdb_add,
        .fdb_del_cmd            = sja1105pqrs_fdb_del,
@@ -630,6 +634,7 @@ struct sja1105_info sja1105s_info = {
        .regs                   = &sja1105pqrs_regs,
        .ptp_ts_bits            = 32,
        .ptpegr_ts_bytes        = 8,
+       .setup_rgmii_delay      = sja1105pqrs_setup_rgmii_delay,
        .reset_cmd              = sja1105pqrs_reset_cmd,
        .fdb_add_cmd            = sja1105pqrs_fdb_add,
        .fdb_del_cmd            = sja1105pqrs_fdb_del,