@@ -136,6 +136,7 @@ struct sja1105_info {
int (*clocking_setup)(struct sja1105_private *priv);
int (*pcs_mdio_read)(struct mii_bus *bus, int phy, int reg);
int (*pcs_mdio_write)(struct mii_bus *bus, int phy, int reg, u16 val);
+ int (*disable_microcontroller)(struct sja1105_private *priv);
const char *name;
bool supports_mii[SJA1105_MAX_NUM_PORTS];
bool supports_rmii[SJA1105_MAX_NUM_PORTS];
@@ -363,7 +364,7 @@ int sja1105pqrs_setup_rgmii_delay(const void *ctx, int port);
int sja1110_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);
-int sja1110_clocking_setup(struct sja1105_private *priv);
+int sja1110_disable_microcontroller(struct sja1105_private *priv);
/* From sja1105_ethtool.c */
void sja1105_get_ethtool_stats(struct dsa_switch *ds, int port, u64 *data);
@@ -6,6 +6,7 @@
#include "sja1105.h"
#define SJA1105_SIZE_CGU_CMD 4
+#define SJA1110_BASE_MCSS_CLK SJA1110_CGU_ADDR(0x70)
#define SJA1110_BASE_TIMER_CLK SJA1110_CGU_ADDR(0x74)
/* Common structure for CFG_PAD_MIIx_RX and CFG_PAD_MIIx_TX */
@@ -832,17 +833,30 @@ sja1110_cgu_outclk_packing(void *buf, struct sja1110_cgu_outclk *outclk,
sja1105_packing(buf, &outclk->pd, 0, 0, size, op);
}
-/* Power down the BASE_TIMER_CLK in order to disable the watchdog */
-int sja1110_clocking_setup(struct sja1105_private *priv)
+int sja1110_disable_microcontroller(struct sja1105_private *priv)
{
u8 packed_buf[SJA1105_SIZE_CGU_CMD] = {0};
+ struct sja1110_cgu_outclk outclk_6_c = {
+ .clksrc = 0x3,
+ .pd = true,
+ };
struct sja1110_cgu_outclk outclk_7_c = {
.clksrc = 0x5,
.pd = true,
};
+ int rc;
+ /* Power down the BASE_TIMER_CLK to disable the watchdog timer */
sja1110_cgu_outclk_packing(packed_buf, &outclk_7_c, PACK);
- return sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_TIMER_CLK,
+ rc = sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_TIMER_CLK,
+ packed_buf, SJA1105_SIZE_CGU_CMD);
+ if (rc)
+ return rc;
+
+ /* Power down the BASE_MCSS_CLOCK to gate the microcontroller off */
+ sja1110_cgu_outclk_packing(packed_buf, &outclk_6_c, PACK);
+
+ return sja1105_xfer_buf(priv, SPI_WRITE, SJA1110_BASE_MCSS_CLK,
packed_buf, SJA1105_SIZE_CGU_CMD);
}
@@ -1922,9 +1922,11 @@ int sja1105_static_config_reload(struct sja1105_private *priv,
* For these interfaces there is no dynamic configuration
* needed, since PLLs have same settings at all speeds.
*/
- rc = priv->info->clocking_setup(priv);
- if (rc < 0)
- goto out;
+ if (priv->info->clocking_setup) {
+ rc = priv->info->clocking_setup(priv);
+ if (rc < 0)
+ goto out;
+ }
for (i = 0; i < ds->num_ports; i++) {
struct dw_xpcs *xpcs = priv->xpcs[i];
@@ -3032,18 +3034,34 @@ static int sja1105_setup(struct dsa_switch *ds)
goto out_ptp_clock_unregister;
}
+ if (priv->info->disable_microcontroller) {
+ rc = priv->info->disable_microcontroller(priv);
+ if (rc < 0) {
+ dev_err(ds->dev,
+ "Failed to disable microcontroller: %pe\n",
+ ERR_PTR(rc));
+ goto out_mdiobus_unregister;
+ }
+ }
+
/* Create and send configuration down to device */
rc = sja1105_static_config_load(priv);
if (rc < 0) {
dev_err(ds->dev, "Failed to load static config: %d\n", rc);
goto out_mdiobus_unregister;
}
+
/* Configure the CGU (PHY link modes and speeds) */
- rc = priv->info->clocking_setup(priv);
- if (rc < 0) {
- dev_err(ds->dev, "Failed to configure MII clocking: %d\n", rc);
- goto out_static_config_free;
+ if (priv->info->clocking_setup) {
+ rc = priv->info->clocking_setup(priv);
+ if (rc < 0) {
+ dev_err(ds->dev,
+ "Failed to configure MII clocking: %pe\n",
+ ERR_PTR(rc));
+ goto out_static_config_free;
+ }
}
+
/* On SJA1105, VLAN filtering per se is always enabled in hardware.
* The only thing we can do to disable it is lie about what the 802.1Q
* EtherType is.
@@ -199,7 +199,11 @@ static int sja1110_reset_cmd(struct dsa_switch *ds)
const struct sja1105_regs *regs = priv->info->regs;
u32 switch_reset = BIT(20);
- /* Switch core reset */
+ /* Only reset the switch core.
+ * A full cold reset would re-enable the BASE_MCSS_CLOCK PLL which
+ * would turn on the microcontroller, potentially letting it execute
+ * code which could interfere with our configuration.
+ */
return sja1105_xfer_u32(priv, SPI_WRITE, regs->rgu, &switch_reset, NULL);
}
@@ -796,7 +800,7 @@ const struct sja1105_info sja1110a_info = {
.ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
.rxtstamp = sja1110_rxtstamp,
.txtstamp = sja1110_txtstamp,
- .clocking_setup = sja1110_clocking_setup,
+ .disable_microcontroller = sja1110_disable_microcontroller,
.pcs_mdio_read = sja1110_pcs_mdio_read,
.pcs_mdio_write = sja1110_pcs_mdio_write,
.port_speed = {
@@ -847,7 +851,7 @@ const struct sja1105_info sja1110b_info = {
.ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
.rxtstamp = sja1110_rxtstamp,
.txtstamp = sja1110_txtstamp,
- .clocking_setup = sja1110_clocking_setup,
+ .disable_microcontroller = sja1110_disable_microcontroller,
.pcs_mdio_read = sja1110_pcs_mdio_read,
.pcs_mdio_write = sja1110_pcs_mdio_write,
.port_speed = {
@@ -898,7 +902,7 @@ const struct sja1105_info sja1110c_info = {
.ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
.rxtstamp = sja1110_rxtstamp,
.txtstamp = sja1110_txtstamp,
- .clocking_setup = sja1110_clocking_setup,
+ .disable_microcontroller = sja1110_disable_microcontroller,
.pcs_mdio_read = sja1110_pcs_mdio_read,
.pcs_mdio_write = sja1110_pcs_mdio_write,
.port_speed = {
@@ -949,7 +953,7 @@ const struct sja1105_info sja1110d_info = {
.ptp_cmd_packing = sja1105pqrs_ptp_cmd_packing,
.rxtstamp = sja1110_rxtstamp,
.txtstamp = sja1110_txtstamp,
- .clocking_setup = sja1110_clocking_setup,
+ .disable_microcontroller = sja1110_disable_microcontroller,
.pcs_mdio_read = sja1110_pcs_mdio_read,
.pcs_mdio_write = sja1110_pcs_mdio_write,
.port_speed = {