summaryrefslogtreecommitdiff
path: root/drivers/net/dsa/sja1105
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/dsa/sja1105')
-rw-r--r--drivers/net/dsa/sja1105/Kconfig1
-rw-r--r--drivers/net/dsa/sja1105/sja1105.h1
-rw-r--r--drivers/net/dsa/sja1105/sja1105_clocking.c58
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ethtool.c144
-rw-r--r--drivers/net/dsa/sja1105/sja1105_ptp.c26
-rw-r--r--drivers/net/dsa/sja1105/sja1105_spi.c2
6 files changed, 147 insertions, 85 deletions
diff --git a/drivers/net/dsa/sja1105/Kconfig b/drivers/net/dsa/sja1105/Kconfig
index 0fe1ae173aa1..68c3086af9af 100644
--- a/drivers/net/dsa/sja1105/Kconfig
+++ b/drivers/net/dsa/sja1105/Kconfig
@@ -20,6 +20,7 @@ tristate "NXP SJA1105 Ethernet switch family support"
config NET_DSA_SJA1105_PTP
bool "Support for the PTP clock on the NXP SJA1105 Ethernet switch"
depends on NET_DSA_SJA1105
+ depends on PTP_1588_CLOCK
help
This enables support for timestamping and PTP clock manipulations in
the SJA1105 DSA driver.
diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h
index 8b60dbd567f2..2f62942692ec 100644
--- a/drivers/net/dsa/sja1105/sja1105.h
+++ b/drivers/net/dsa/sja1105/sja1105.h
@@ -49,6 +49,7 @@ struct sja1105_regs {
u64 ptpschtm;
u64 ptpegr_ts[SJA1105_NUM_PORTS];
u64 pad_mii_tx[SJA1105_NUM_PORTS];
+ u64 pad_mii_rx[SJA1105_NUM_PORTS];
u64 pad_mii_id[SJA1105_NUM_PORTS];
u64 cgu_idiv[SJA1105_NUM_PORTS];
u64 mii_tx_clk[SJA1105_NUM_PORTS];
diff --git a/drivers/net/dsa/sja1105/sja1105_clocking.c b/drivers/net/dsa/sja1105/sja1105_clocking.c
index 0fdc2d55fff6..2a9b8a6a5306 100644
--- a/drivers/net/dsa/sja1105/sja1105_clocking.c
+++ b/drivers/net/dsa/sja1105/sja1105_clocking.c
@@ -7,12 +7,16 @@
#define SJA1105_SIZE_CGU_CMD 4
-struct sja1105_cfg_pad_mii_tx {
+/* Common structure for CFG_PAD_MIIx_RX and CFG_PAD_MIIx_TX */
+struct sja1105_cfg_pad_mii {
u64 d32_os;
+ u64 d32_ih;
u64 d32_ipud;
+ u64 d10_ih;
u64 d10_os;
u64 d10_ipud;
u64 ctrl_os;
+ u64 ctrl_ih;
u64 ctrl_ipud;
u64 clk_os;
u64 clk_ih;
@@ -338,16 +342,19 @@ static int sja1105_cgu_rgmii_tx_clk_config(struct sja1105_private *priv,
/* AGU */
static void
-sja1105_cfg_pad_mii_tx_packing(void *buf, struct sja1105_cfg_pad_mii_tx *cmd,
- enum packing_op op)
+sja1105_cfg_pad_mii_packing(void *buf, struct sja1105_cfg_pad_mii *cmd,
+ enum packing_op op)
{
const int size = 4;
sja1105_packing(buf, &cmd->d32_os, 28, 27, size, op);
+ sja1105_packing(buf, &cmd->d32_ih, 26, 26, size, op);
sja1105_packing(buf, &cmd->d32_ipud, 25, 24, size, op);
sja1105_packing(buf, &cmd->d10_os, 20, 19, size, op);
+ sja1105_packing(buf, &cmd->d10_ih, 18, 18, size, op);
sja1105_packing(buf, &cmd->d10_ipud, 17, 16, size, op);
sja1105_packing(buf, &cmd->ctrl_os, 12, 11, size, op);
+ sja1105_packing(buf, &cmd->ctrl_ih, 10, 10, size, op);
sja1105_packing(buf, &cmd->ctrl_ipud, 9, 8, size, op);
sja1105_packing(buf, &cmd->clk_os, 4, 3, size, op);
sja1105_packing(buf, &cmd->clk_ih, 2, 2, size, op);
@@ -358,7 +365,7 @@ static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
int port)
{
const struct sja1105_regs *regs = priv->info->regs;
- struct sja1105_cfg_pad_mii_tx pad_mii_tx;
+ struct sja1105_cfg_pad_mii pad_mii_tx = {0};
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
/* Payload */
@@ -375,12 +382,45 @@ static int sja1105_rgmii_cfg_pad_tx_config(struct sja1105_private *priv,
pad_mii_tx.clk_os = 3; /* TX_CLK output stage */
pad_mii_tx.clk_ih = 0; /* TX_CLK input hysteresis (default) */
pad_mii_tx.clk_ipud = 2; /* TX_CLK input stage (default) */
- sja1105_cfg_pad_mii_tx_packing(packed_buf, &pad_mii_tx, PACK);
+ sja1105_cfg_pad_mii_packing(packed_buf, &pad_mii_tx, PACK);
return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_tx[port],
packed_buf, SJA1105_SIZE_CGU_CMD);
}
+static int sja1105_cfg_pad_rx_config(struct sja1105_private *priv, int port)
+{
+ const struct sja1105_regs *regs = priv->info->regs;
+ struct sja1105_cfg_pad_mii pad_mii_rx = {0};
+ u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+
+ /* Payload */
+ pad_mii_rx.d32_ih = 0; /* RXD[3:2] input stage hysteresis: */
+ /* non-Schmitt (default) */
+ pad_mii_rx.d32_ipud = 2; /* RXD[3:2] input weak pull-up/down */
+ /* plain input (default) */
+ pad_mii_rx.d10_ih = 0; /* RXD[1:0] input stage hysteresis: */
+ /* non-Schmitt (default) */
+ pad_mii_rx.d10_ipud = 2; /* RXD[1:0] input weak pull-up/down */
+ /* plain input (default) */
+ pad_mii_rx.ctrl_ih = 0; /* RX_DV/CRS_DV/RX_CTL and RX_ER */
+ /* input stage hysteresis: */
+ /* non-Schmitt (default) */
+ pad_mii_rx.ctrl_ipud = 3; /* RX_DV/CRS_DV/RX_CTL and RX_ER */
+ /* input stage weak pull-up/down: */
+ /* pull-down */
+ pad_mii_rx.clk_os = 2; /* RX_CLK/RXC output stage: */
+ /* medium noise/fast speed (default) */
+ pad_mii_rx.clk_ih = 0; /* RX_CLK/RXC input hysteresis: */
+ /* non-Schmitt (default) */
+ pad_mii_rx.clk_ipud = 2; /* RX_CLK/RXC input pull-up/down: */
+ /* plain input (default) */
+ sja1105_cfg_pad_mii_packing(packed_buf, &pad_mii_rx, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, regs->pad_mii_rx[port],
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+}
+
static void
sja1105_cfg_pad_mii_id_packing(void *buf, struct sja1105_cfg_pad_mii_id *cmd,
enum packing_op op)
@@ -669,10 +709,14 @@ int sja1105_clocking_setup_port(struct sja1105_private *priv, int port)
phy_mode);
return -EINVAL;
}
- if (rc)
+ if (rc) {
dev_err(dev, "Clocking setup for port %d failed: %d\n",
port, rc);
- return rc;
+ return rc;
+ }
+
+ /* Internally pull down the RX_DV/CRS_DV/RX_CTL and RX_ER inputs */
+ return sja1105_cfg_pad_rx_config(priv, port);
}
int sja1105_clocking_setup(struct sja1105_private *priv)
diff --git a/drivers/net/dsa/sja1105/sja1105_ethtool.c b/drivers/net/dsa/sja1105/sja1105_ethtool.c
index d742ffcbfce9..709f035055c5 100644
--- a/drivers/net/dsa/sja1105/sja1105_ethtool.c
+++ b/drivers/net/dsa/sja1105/sja1105_ethtool.c
@@ -421,92 +421,96 @@ static char sja1105pqrs_extra_port_stats[][ETH_GSTRING_LEN] = {
void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data)
{
struct sja1105_private *priv = ds->priv;
- struct sja1105_port_status status;
+ struct sja1105_port_status *status;
int rc, i, k = 0;
- memset(&status, 0, sizeof(status));
+ status = kzalloc(sizeof(*status), GFP_KERNEL);
+ if (!status)
+ goto out;
- rc = sja1105_port_status_get(priv, &status, port);
+ rc = sja1105_port_status_get(priv, status, port);
if (rc < 0) {
dev_err(ds->dev, "Failed to read port %d counters: %d\n",
port, rc);
- return;
+ goto out;
}
memset(data, 0, ARRAY_SIZE(sja1105_port_stats) * sizeof(u64));
- data[k++] = status.mac.n_runt;
- data[k++] = status.mac.n_soferr;
- data[k++] = status.mac.n_alignerr;
- data[k++] = status.mac.n_miierr;
- data[k++] = status.mac.typeerr;
- data[k++] = status.mac.sizeerr;
- data[k++] = status.mac.tctimeout;
- data[k++] = status.mac.priorerr;
- data[k++] = status.mac.nomaster;
- data[k++] = status.mac.memov;
- data[k++] = status.mac.memerr;
- data[k++] = status.mac.invtyp;
- data[k++] = status.mac.intcyov;
- data[k++] = status.mac.domerr;
- data[k++] = status.mac.pcfbagdrop;
- data[k++] = status.mac.spcprior;
- data[k++] = status.mac.ageprior;
- data[k++] = status.mac.portdrop;
- data[k++] = status.mac.lendrop;
- data[k++] = status.mac.bagdrop;
- data[k++] = status.mac.policeerr;
- data[k++] = status.mac.drpnona664err;
- data[k++] = status.mac.spcerr;
- data[k++] = status.mac.agedrp;
- data[k++] = status.hl1.n_n664err;
- data[k++] = status.hl1.n_vlanerr;
- data[k++] = status.hl1.n_unreleased;
- data[k++] = status.hl1.n_sizeerr;
- data[k++] = status.hl1.n_crcerr;
- data[k++] = status.hl1.n_vlnotfound;
- data[k++] = status.hl1.n_ctpolerr;
- data[k++] = status.hl1.n_polerr;
- data[k++] = status.hl1.n_rxfrm;
- data[k++] = status.hl1.n_rxbyte;
- data[k++] = status.hl1.n_txfrm;
- data[k++] = status.hl1.n_txbyte;
- data[k++] = status.hl2.n_qfull;
- data[k++] = status.hl2.n_part_drop;
- data[k++] = status.hl2.n_egr_disabled;
- data[k++] = status.hl2.n_not_reach;
+ data[k++] = status->mac.n_runt;
+ data[k++] = status->mac.n_soferr;
+ data[k++] = status->mac.n_alignerr;
+ data[k++] = status->mac.n_miierr;
+ data[k++] = status->mac.typeerr;
+ data[k++] = status->mac.sizeerr;
+ data[k++] = status->mac.tctimeout;
+ data[k++] = status->mac.priorerr;
+ data[k++] = status->mac.nomaster;
+ data[k++] = status->mac.memov;
+ data[k++] = status->mac.memerr;
+ data[k++] = status->mac.invtyp;
+ data[k++] = status->mac.intcyov;
+ data[k++] = status->mac.domerr;
+ data[k++] = status->mac.pcfbagdrop;
+ data[k++] = status->mac.spcprior;
+ data[k++] = status->mac.ageprior;
+ data[k++] = status->mac.portdrop;
+ data[k++] = status->mac.lendrop;
+ data[k++] = status->mac.bagdrop;
+ data[k++] = status->mac.policeerr;
+ data[k++] = status->mac.drpnona664err;
+ data[k++] = status->mac.spcerr;
+ data[k++] = status->mac.agedrp;
+ data[k++] = status->hl1.n_n664err;
+ data[k++] = status->hl1.n_vlanerr;
+ data[k++] = status->hl1.n_unreleased;
+ data[k++] = status->hl1.n_sizeerr;
+ data[k++] = status->hl1.n_crcerr;
+ data[k++] = status->hl1.n_vlnotfound;
+ data[k++] = status->hl1.n_ctpolerr;
+ data[k++] = status->hl1.n_polerr;
+ data[k++] = status->hl1.n_rxfrm;
+ data[k++] = status->hl1.n_rxbyte;
+ data[k++] = status->hl1.n_txfrm;
+ data[k++] = status->hl1.n_txbyte;
+ data[k++] = status->hl2.n_qfull;
+ data[k++] = status->hl2.n_part_drop;
+ data[k++] = status->hl2.n_egr_disabled;
+ data[k++] = status->hl2.n_not_reach;
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
priv->info->device_id == SJA1105T_DEVICE_ID)
- return;
+ goto out;;
memset(data + k, 0, ARRAY_SIZE(sja1105pqrs_extra_port_stats) *
sizeof(u64));
for (i = 0; i < 8; i++) {
- data[k++] = status.hl2.qlevel_hwm[i];
- data[k++] = status.hl2.qlevel[i];
+ data[k++] = status->hl2.qlevel_hwm[i];
+ data[k++] = status->hl2.qlevel[i];
}
- data[k++] = status.ether.n_drops_nolearn;
- data[k++] = status.ether.n_drops_noroute;
- data[k++] = status.ether.n_drops_ill_dtag;
- data[k++] = status.ether.n_drops_dtag;
- data[k++] = status.ether.n_drops_sotag;
- data[k++] = status.ether.n_drops_sitag;
- data[k++] = status.ether.n_drops_utag;
- data[k++] = status.ether.n_tx_bytes_1024_2047;
- data[k++] = status.ether.n_tx_bytes_512_1023;
- data[k++] = status.ether.n_tx_bytes_256_511;
- data[k++] = status.ether.n_tx_bytes_128_255;
- data[k++] = status.ether.n_tx_bytes_65_127;
- data[k++] = status.ether.n_tx_bytes_64;
- data[k++] = status.ether.n_tx_mcast;
- data[k++] = status.ether.n_tx_bcast;
- data[k++] = status.ether.n_rx_bytes_1024_2047;
- data[k++] = status.ether.n_rx_bytes_512_1023;
- data[k++] = status.ether.n_rx_bytes_256_511;
- data[k++] = status.ether.n_rx_bytes_128_255;
- data[k++] = status.ether.n_rx_bytes_65_127;
- data[k++] = status.ether.n_rx_bytes_64;
- data[k++] = status.ether.n_rx_mcast;
- data[k++] = status.ether.n_rx_bcast;
+ data[k++] = status->ether.n_drops_nolearn;
+ data[k++] = status->ether.n_drops_noroute;
+ data[k++] = status->ether.n_drops_ill_dtag;
+ data[k++] = status->ether.n_drops_dtag;
+ data[k++] = status->ether.n_drops_sotag;
+ data[k++] = status->ether.n_drops_sitag;
+ data[k++] = status->ether.n_drops_utag;
+ data[k++] = status->ether.n_tx_bytes_1024_2047;
+ data[k++] = status->ether.n_tx_bytes_512_1023;
+ data[k++] = status->ether.n_tx_bytes_256_511;
+ data[k++] = status->ether.n_tx_bytes_128_255;
+ data[k++] = status->ether.n_tx_bytes_65_127;
+ data[k++] = status->ether.n_tx_bytes_64;
+ data[k++] = status->ether.n_tx_mcast;
+ data[k++] = status->ether.n_tx_bcast;
+ data[k++] = status->ether.n_rx_bytes_1024_2047;
+ data[k++] = status->ether.n_rx_bytes_512_1023;
+ data[k++] = status->ether.n_rx_bytes_256_511;
+ data[k++] = status->ether.n_rx_bytes_128_255;
+ data[k++] = status->ether.n_rx_bytes_65_127;
+ data[k++] = status->ether.n_rx_bytes_64;
+ data[k++] = status->ether.n_rx_mcast;
+ data[k++] = status->ether.n_rx_bcast;
+out:
+ kfree(status);
}
void sja1105_get_strings(struct dsa_switch *ds, int port,
diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c
index a22f8e3fc06b..bc0e47c1dbb9 100644
--- a/drivers/net/dsa/sja1105/sja1105_ptp.c
+++ b/drivers/net/dsa/sja1105/sja1105_ptp.c
@@ -16,14 +16,15 @@
/* PTPSYNCTS has no interrupt or update mechanism, because the intended
* hardware use case is for the timestamp to be collected synchronously,
- * immediately after the CAS_MASTER SJA1105 switch has triggered a CASSYNC
- * pulse on the PTP_CLK pin. When used as a generic extts source, it needs
- * polling and a comparison with the old value. The polling interval is just
- * the Nyquist rate of a canonical PPS input (e.g. from a GPS module).
- * Anything of higher frequency than 1 Hz will be lost, since there is no
- * timestamp FIFO.
+ * immediately after the CAS_MASTER SJA1105 switch has performed a CASSYNC
+ * one-shot toggle (no return to level) on the PTP_CLK pin. When used as a
+ * generic extts source, the PTPSYNCTS register needs polling and a comparison
+ * with the old value. The polling interval is configured as the Nyquist rate
+ * of a signal with 50% duty cycle and 1Hz frequency, which is sadly all that
+ * this hardware can do (but may be enough for some setups). Anything of higher
+ * frequency than 1 Hz will be lost, since there is no timestamp FIFO.
*/
-#define SJA1105_EXTTS_INTERVAL (HZ / 2)
+#define SJA1105_EXTTS_INTERVAL (HZ / 4)
/* This range is actually +/- SJA1105_MAX_ADJ_PPB
* divided by 1000 (ppb -> ppm) and with a 16-bit
@@ -754,7 +755,16 @@ static int sja1105_extts_enable(struct sja1105_private *priv,
return -EOPNOTSUPP;
/* Reject requests with unsupported flags */
- if (extts->flags)
+ if (extts->flags & ~(PTP_ENABLE_FEATURE |
+ PTP_RISING_EDGE |
+ PTP_FALLING_EDGE |
+ PTP_STRICT_FLAGS))
+ return -EOPNOTSUPP;
+
+ /* We can only enable time stamping on both edges, sadly. */
+ if ((extts->flags & PTP_STRICT_FLAGS) &&
+ (extts->flags & PTP_ENABLE_FEATURE) &&
+ (extts->flags & PTP_EXTTS_EDGES) != PTP_EXTTS_EDGES)
return -EOPNOTSUPP;
rc = sja1105_change_ptp_clk_pin_func(priv, PTP_PF_EXTTS);
diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c
index 04bdb72ae6b6..43f14a5c2718 100644
--- a/drivers/net/dsa/sja1105/sja1105_spi.c
+++ b/drivers/net/dsa/sja1105/sja1105_spi.c
@@ -443,6 +443,7 @@ static struct sja1105_regs sja1105et_regs = {
.rgu = 0x100440,
/* UM10944.pdf, Table 86, ACU Register overview */
.pad_mii_tx = {0x100800, 0x100802, 0x100804, 0x100806, 0x100808},
+ .pad_mii_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
.rmii_pll1 = 0x10000A,
.cgu_idiv = {0x10000B, 0x10000C, 0x10000D, 0x10000E, 0x10000F},
.mac = {0x200, 0x202, 0x204, 0x206, 0x208},
@@ -475,6 +476,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_rx = {0x100801, 0x100803, 0x100805, 0x100807, 0x100809},
.pad_mii_id = {0x100810, 0x100811, 0x100812, 0x100813, 0x100814},
.sgmii = 0x1F0000,
.rmii_pll1 = 0x10000A,