1004 lines
30 KiB
Diff
1004 lines
30 KiB
Diff
Index: drivers/net/dsa/mv88e6xxx/chip.c
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/chip.c
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/chip.c
|
|
@@ -39,6 +39,7 @@
|
|
#include "phy.h"
|
|
#include "port.h"
|
|
#include "serdes.h"
|
|
+#include "smi.h"
|
|
|
|
static void assert_reg_lock(struct mv88e6xxx_chip *chip)
|
|
{
|
|
@@ -48,149 +49,6 @@ static void assert_reg_lock(struct mv88e
|
|
}
|
|
}
|
|
|
|
-/* The switch ADDR[4:1] configuration pins define the chip SMI device address
|
|
- * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
|
|
- *
|
|
- * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
|
|
- * is the only device connected to the SMI master. In this mode it responds to
|
|
- * all 32 possible SMI addresses, and thus maps directly the internal devices.
|
|
- *
|
|
- * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
|
|
- * multiple devices to share the SMI interface. In this mode it responds to only
|
|
- * 2 registers, used to indirectly access the internal SMI devices.
|
|
- */
|
|
-
|
|
-static int mv88e6xxx_smi_read(struct mv88e6xxx_chip *chip,
|
|
- int addr, int reg, u16 *val)
|
|
-{
|
|
- if (!chip->smi_ops)
|
|
- return -EOPNOTSUPP;
|
|
-
|
|
- return chip->smi_ops->read(chip, addr, reg, val);
|
|
-}
|
|
-
|
|
-static int mv88e6xxx_smi_write(struct mv88e6xxx_chip *chip,
|
|
- int addr, int reg, u16 val)
|
|
-{
|
|
- if (!chip->smi_ops)
|
|
- return -EOPNOTSUPP;
|
|
-
|
|
- return chip->smi_ops->write(chip, addr, reg, val);
|
|
-}
|
|
-
|
|
-static int mv88e6xxx_smi_single_chip_read(struct mv88e6xxx_chip *chip,
|
|
- int addr, int reg, u16 *val)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- ret = mdiobus_read_nested(chip->bus, addr, reg);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- *val = ret & 0xffff;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mv88e6xxx_smi_single_chip_write(struct mv88e6xxx_chip *chip,
|
|
- int addr, int reg, u16 val)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- ret = mdiobus_write_nested(chip->bus, addr, reg, val);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_single_chip_ops = {
|
|
- .read = mv88e6xxx_smi_single_chip_read,
|
|
- .write = mv88e6xxx_smi_single_chip_write,
|
|
-};
|
|
-
|
|
-static int mv88e6xxx_smi_multi_chip_wait(struct mv88e6xxx_chip *chip)
|
|
-{
|
|
- int ret;
|
|
- int i;
|
|
-
|
|
- for (i = 0; i < 16; i++) {
|
|
- ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_CMD);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- if ((ret & SMI_CMD_BUSY) == 0)
|
|
- return 0;
|
|
- }
|
|
-
|
|
- return -ETIMEDOUT;
|
|
-}
|
|
-
|
|
-static int mv88e6xxx_smi_multi_chip_read(struct mv88e6xxx_chip *chip,
|
|
- int addr, int reg, u16 *val)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- /* Wait for the bus to become free. */
|
|
- ret = mv88e6xxx_smi_multi_chip_wait(chip);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- /* Transmit the read command. */
|
|
- ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
|
|
- SMI_CMD_OP_22_READ | (addr << 5) | reg);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- /* Wait for the read command to complete. */
|
|
- ret = mv88e6xxx_smi_multi_chip_wait(chip);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- /* Read the data. */
|
|
- ret = mdiobus_read_nested(chip->bus, chip->sw_addr, SMI_DATA);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- *val = ret & 0xffff;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mv88e6xxx_smi_multi_chip_write(struct mv88e6xxx_chip *chip,
|
|
- int addr, int reg, u16 val)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- /* Wait for the bus to become free. */
|
|
- ret = mv88e6xxx_smi_multi_chip_wait(chip);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- /* Transmit the data to write. */
|
|
- ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_DATA, val);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- /* Transmit the write command. */
|
|
- ret = mdiobus_write_nested(chip->bus, chip->sw_addr, SMI_CMD,
|
|
- SMI_CMD_OP_22_WRITE | (addr << 5) | reg);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- /* Wait for the write command to complete. */
|
|
- ret = mv88e6xxx_smi_multi_chip_wait(chip);
|
|
- if (ret < 0)
|
|
- return ret;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_multi_chip_ops = {
|
|
- .read = mv88e6xxx_smi_multi_chip_read,
|
|
- .write = mv88e6xxx_smi_multi_chip_write,
|
|
-};
|
|
-
|
|
int mv88e6xxx_read(struct mv88e6xxx_chip *chip, int addr, int reg, u16 *val)
|
|
{
|
|
int err;
|
|
@@ -650,6 +508,12 @@ static void mv88e6095_stats_get_strings(
|
|
STATS_TYPE_BANK0 | STATS_TYPE_PORT);
|
|
}
|
|
|
|
+static void mv88e6250_stats_get_strings(struct mv88e6xxx_chip *chip,
|
|
+ uint8_t *data)
|
|
+{
|
|
+ mv88e6xxx_stats_get_strings(chip, data, STATS_TYPE_BANK0);
|
|
+}
|
|
+
|
|
static void mv88e6320_stats_get_strings(struct mv88e6xxx_chip *chip,
|
|
uint8_t *data)
|
|
{
|
|
@@ -686,6 +550,11 @@ static int mv88e6095_stats_get_sset_coun
|
|
STATS_TYPE_PORT);
|
|
}
|
|
|
|
+static int mv88e6250_stats_get_sset_count(struct mv88e6xxx_chip *chip)
|
|
+{
|
|
+ return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0);
|
|
+}
|
|
+
|
|
static int mv88e6320_stats_get_sset_count(struct mv88e6xxx_chip *chip)
|
|
{
|
|
return mv88e6xxx_stats_get_sset_count(chip, STATS_TYPE_BANK0 |
|
|
@@ -728,6 +597,13 @@ static void mv88e6095_stats_get_stats(st
|
|
0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
|
|
}
|
|
|
|
+static void mv88e6250_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
|
|
+ uint64_t *data)
|
|
+{
|
|
+ mv88e6xxx_stats_get_stats(chip, port, data, STATS_TYPE_BANK0,
|
|
+ 0, MV88E6XXX_G1_STATS_OP_HIST_RX_TX);
|
|
+}
|
|
+
|
|
static void mv88e6320_stats_get_stats(struct mv88e6xxx_chip *chip, int port,
|
|
uint64_t *data)
|
|
{
|
|
@@ -2901,6 +2777,40 @@ static const struct mv88e6xxx_ops mv88e6
|
|
.serdes_power = mv88e6352_serdes_power,
|
|
};
|
|
|
|
+static const struct mv88e6xxx_ops mv88e6250_ops = {
|
|
+ /* MV88E6XXX_FAMILY_6250 */
|
|
+ .irl_init_all = mv88e6352_g2_irl_init_all,
|
|
+ .get_eeprom = mv88e6xxx_g2_get_eeprom16,
|
|
+ .set_eeprom = mv88e6xxx_g2_set_eeprom16,
|
|
+ .set_switch_mac = mv88e6xxx_g2_set_switch_mac,
|
|
+ .phy_read = mv88e6xxx_g2_smi_phy_read,
|
|
+ .phy_write = mv88e6xxx_g2_smi_phy_write,
|
|
+ .port_set_link = mv88e6xxx_port_set_link,
|
|
+ .port_set_duplex = mv88e6xxx_port_set_duplex,
|
|
+ .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay,
|
|
+ .port_set_speed = mv88e6250_port_set_speed,
|
|
+ .port_tag_remap = mv88e6095_port_tag_remap,
|
|
+ .port_set_frame_mode = mv88e6351_port_set_frame_mode,
|
|
+ .port_set_egress_floods = mv88e6352_port_set_egress_floods,
|
|
+ .port_set_ether_type = mv88e6351_port_set_ether_type,
|
|
+ .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting,
|
|
+ .port_pause_limit = mv88e6097_port_pause_limit,
|
|
+ .port_disable_pri_override = mv88e6xxx_port_disable_pri_override,
|
|
+ .stats_snapshot = mv88e6320_g1_stats_snapshot,
|
|
+ .stats_set_histogram = mv88e6095_g1_stats_set_histogram,
|
|
+ .stats_get_sset_count = mv88e6250_stats_get_sset_count,
|
|
+ .stats_get_strings = mv88e6250_stats_get_strings,
|
|
+ .stats_get_stats = mv88e6250_stats_get_stats,
|
|
+ .set_cpu_port = mv88e6095_g1_set_cpu_port,
|
|
+ .set_egress_port = mv88e6095_g1_set_egress_port,
|
|
+ .watchdog_ops = &mv88e6250_watchdog_ops,
|
|
+ .mgmt_rsvd2cpu = mv88e6352_g2_mgmt_rsvd2cpu,
|
|
+ .pot_clear = mv88e6xxx_g2_pot_clear,
|
|
+ .reset = mv88e6250_g1_reset,
|
|
+ .vtu_getnext = mv88e6250_g1_vtu_getnext,
|
|
+ .vtu_loadpurge = mv88e6250_g1_vtu_loadpurge,
|
|
+};
|
|
+
|
|
static const struct mv88e6xxx_ops mv88e6290_ops = {
|
|
/* MV88E6XXX_FAMILY_6390 */
|
|
.setup_errata = mv88e6390_setup_errata,
|
|
@@ -3218,6 +3128,25 @@ static const struct mv88e6xxx_ops mv88e6
|
|
};
|
|
|
|
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
|
|
+ [MV88E6071] = {
|
|
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6071,
|
|
+ .family = MV88E6XXX_FAMILY_6250,
|
|
+ .name = "Marvell 88E6071",
|
|
+ .num_databases = 64,
|
|
+ .num_ports = 7,
|
|
+ .max_vid = 4095,
|
|
+ .port_base_addr = 0x08,
|
|
+ .global1_addr = 0x0f,
|
|
+ .global2_addr = 0x07,
|
|
+ .age_time_coeff = 15000,
|
|
+ .g1_irqs = 9,
|
|
+ .g2_irqs = 10,
|
|
+ .atu_move_port_mask = 0xf,
|
|
+ .dual_chip = true,
|
|
+ .tag_protocol = DSA_TAG_PROTO_DSA,
|
|
+ .ops = &mv88e6250_ops,
|
|
+ },
|
|
+
|
|
[MV88E6085] = {
|
|
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085,
|
|
.family = MV88E6XXX_FAMILY_6097,
|
|
@@ -3551,6 +3480,25 @@ static const struct mv88e6xxx_info mv88e
|
|
.ops = &mv88e6240_ops,
|
|
},
|
|
|
|
+ [MV88E6250] = {
|
|
+ .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6250,
|
|
+ .family = MV88E6XXX_FAMILY_6250,
|
|
+ .name = "Marvell 88E6250",
|
|
+ .num_databases = 64,
|
|
+ .num_ports = 7,
|
|
+ .max_vid = 4095,
|
|
+ .port_base_addr = 0x08,
|
|
+ .global1_addr = 0x0f,
|
|
+ .global2_addr = 0x07,
|
|
+ .age_time_coeff = 15000,
|
|
+ .g1_irqs = 9,
|
|
+ .g2_irqs = 10,
|
|
+ .atu_move_port_mask = 0xf,
|
|
+ .dual_chip = true,
|
|
+ .tag_protocol = DSA_TAG_PROTO_DSA,
|
|
+ .ops = &mv88e6250_ops,
|
|
+ },
|
|
+
|
|
[MV88E6290] = {
|
|
.prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6290,
|
|
.family = MV88E6XXX_FAMILY_6390,
|
|
@@ -3786,22 +3734,6 @@ static struct mv88e6xxx_chip *mv88e6xxx_
|
|
return chip;
|
|
}
|
|
|
|
-static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
|
|
- struct mii_bus *bus, int sw_addr)
|
|
-{
|
|
- if (sw_addr == 0)
|
|
- chip->smi_ops = &mv88e6xxx_smi_single_chip_ops;
|
|
- else if (chip->info->multi_chip)
|
|
- chip->smi_ops = &mv88e6xxx_smi_multi_chip_ops;
|
|
- else
|
|
- return -EINVAL;
|
|
-
|
|
- chip->bus = bus;
|
|
- chip->sw_addr = sw_addr;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
static enum dsa_tag_protocol mv88e6xxx_get_tag_protocol(struct dsa_switch *ds)
|
|
{
|
|
struct mv88e6xxx_chip *chip = ds->priv;
|
|
@@ -3832,6 +3764,7 @@ static const char *mv88e6xxx_drv_probe(s
|
|
if (err)
|
|
goto free;
|
|
|
|
+ mv88e6xxx_hardware_reset(chip);
|
|
err = mv88e6xxx_detect(chip);
|
|
if (err)
|
|
goto free;
|
|
@@ -3988,6 +3921,7 @@ static int mv88e6xxx_probe(struct mdio_d
|
|
if (IS_ERR(chip->reset))
|
|
return PTR_ERR(chip->reset);
|
|
|
|
+ mv88e6xxx_hardware_reset(chip);
|
|
err = mv88e6xxx_detect(chip);
|
|
if (err)
|
|
return err;
|
|
@@ -4081,6 +4015,10 @@ static const struct of_device_id mv88e6x
|
|
.compatible = "marvell,mv88e6190",
|
|
.data = &mv88e6xxx_table[MV88E6190],
|
|
},
|
|
+ {
|
|
+ .compatible = "marvell,mv88e6250",
|
|
+ .data = &mv88e6xxx_table[MV88E6250],
|
|
+ },
|
|
{ /* sentinel */ },
|
|
};
|
|
|
|
Index: drivers/net/dsa/mv88e6xxx/chip.h
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/chip.h
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/chip.h
|
|
@@ -22,17 +22,6 @@
|
|
#define UINT64_MAX (u64)(~((u64)0))
|
|
#endif
|
|
|
|
-#define SMI_CMD 0x00
|
|
-#define SMI_CMD_BUSY BIT(15)
|
|
-#define SMI_CMD_CLAUSE_22 BIT(12)
|
|
-#define SMI_CMD_OP_22_WRITE ((1 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22)
|
|
-#define SMI_CMD_OP_22_READ ((2 << 10) | SMI_CMD_BUSY | SMI_CMD_CLAUSE_22)
|
|
-#define SMI_CMD_OP_45_WRITE_ADDR ((0 << 10) | SMI_CMD_BUSY)
|
|
-#define SMI_CMD_OP_45_WRITE_DATA ((1 << 10) | SMI_CMD_BUSY)
|
|
-#define SMI_CMD_OP_45_READ_DATA ((2 << 10) | SMI_CMD_BUSY)
|
|
-#define SMI_CMD_OP_45_READ_DATA_INC ((3 << 10) | SMI_CMD_BUSY)
|
|
-#define SMI_DATA 0x01
|
|
-
|
|
#define MV88E6XXX_N_FID 4096
|
|
|
|
/* PVT limits for 4-bit port and 5-bit switch */
|
|
@@ -55,6 +44,7 @@ enum mv88e6xxx_frame_mode {
|
|
|
|
/* List of supported models */
|
|
enum mv88e6xxx_model {
|
|
+ MV88E6071,
|
|
MV88E6085,
|
|
MV88E6095,
|
|
MV88E6097,
|
|
@@ -72,6 +62,7 @@ enum mv88e6xxx_model {
|
|
MV88E6190X,
|
|
MV88E6191,
|
|
MV88E6240,
|
|
+ MV88E6250,
|
|
MV88E6290,
|
|
MV88E6320,
|
|
MV88E6321,
|
|
@@ -90,6 +81,7 @@ enum mv88e6xxx_family {
|
|
MV88E6XXX_FAMILY_6097, /* 6046 6085 6096 6097 */
|
|
MV88E6XXX_FAMILY_6165, /* 6123 6161 6165 */
|
|
MV88E6XXX_FAMILY_6185, /* 6108 6121 6122 6131 6152 6155 6182 6185 */
|
|
+ MV88E6XXX_FAMILY_6250, /* 6071 6250 */
|
|
MV88E6XXX_FAMILY_6320, /* 6320 6321 */
|
|
MV88E6XXX_FAMILY_6341, /* 6141 6341 */
|
|
MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */
|
|
@@ -119,6 +111,11 @@ struct mv88e6xxx_info {
|
|
* when it is non-zero, and use indirect access to internal registers.
|
|
*/
|
|
bool multi_chip;
|
|
+ /* Dual-chip Addressing Mode
|
|
+ * Some chips respond to only half of the 32 SMI addresses,
|
|
+ * allowing two to coexist on the same SMI interface.
|
|
+ */
|
|
+ bool dual_chip;
|
|
enum dsa_tag_protocol tag_protocol;
|
|
|
|
/* Mask for FromPort and ToPort value of PortVec used in ATU Move
|
|
Index: drivers/net/dsa/mv88e6xxx/global1.c
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/global1.c
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/global1.c
|
|
@@ -31,6 +31,12 @@ int mv88e6xxx_g1_write(struct mv88e6xxx_
|
|
return mv88e6xxx_write(chip, addr, reg, val);
|
|
}
|
|
|
|
+int mv88e6250_g1_ieee_pri_map(struct mv88e6xxx_chip *chip)
|
|
+{
|
|
+ /* Reset the IEEE Tag priorities to defaults */
|
|
+ return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_IEEE_PRI, 0xfa50);
|
|
+}
|
|
+
|
|
int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
|
|
{
|
|
return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
|
|
@@ -182,6 +188,25 @@ int mv88e6185_g1_reset(struct mv88e6xxx_
|
|
return mv88e6185_g1_wait_ppu_polling(chip);
|
|
}
|
|
|
|
+int mv88e6250_g1_reset(struct mv88e6xxx_chip *chip)
|
|
+{
|
|
+ u16 val;
|
|
+ int err;
|
|
+
|
|
+ /* Set the SWReset bit 15 */
|
|
+ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ val |= MV88E6XXX_G1_CTL1_SW_RESET;
|
|
+
|
|
+ err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ return mv88e6xxx_g1_wait_init_ready(chip);
|
|
+}
|
|
+
|
|
int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip)
|
|
{
|
|
u16 val;
|
|
@@ -374,6 +399,22 @@ int mv88e6xxx_g1_stats_wait(struct mv88e
|
|
MV88E6XXX_G1_STATS_OP_BUSY);
|
|
}
|
|
|
|
+int mv88e6095_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
|
|
+{
|
|
+ u16 val;
|
|
+ int err;
|
|
+
|
|
+ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_OP, &val);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ val |= MV88E6XXX_G1_STATS_OP_HIST_RX_TX;
|
|
+
|
|
+ err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, val);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
|
|
{
|
|
int err;
|
|
Index: drivers/net/dsa/mv88e6xxx/global1.h
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/global1.h
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/global1.h
|
|
@@ -227,6 +227,7 @@ int mv88e6xxx_g1_set_switch_mac(struct m
|
|
|
|
int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip);
|
|
int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip);
|
|
+int mv88e6250_g1_reset(struct mv88e6xxx_chip *chip);
|
|
|
|
int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip);
|
|
int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip);
|
|
@@ -236,6 +237,7 @@ int mv88e6xxx_g1_stats_snapshot(struct m
|
|
int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
|
|
int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port);
|
|
int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip);
|
|
+int mv88e6095_g1_stats_set_histogram(struct mv88e6xxx_chip *chip);
|
|
void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val);
|
|
int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port);
|
|
int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port);
|
|
@@ -258,6 +260,12 @@ int mv88e6185_g1_vtu_getnext(struct mv88
|
|
struct mv88e6xxx_vtu_entry *entry);
|
|
int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
|
|
struct mv88e6xxx_vtu_entry *entry);
|
|
+int mv88e6250_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
|
|
+ struct mv88e6xxx_vtu_entry *entry);
|
|
+int mv88e6250_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
|
|
+ struct mv88e6xxx_vtu_entry *entry);
|
|
+int mv88e6250_g1_ieee_pri_map(struct mv88e6xxx_chip *chip);
|
|
+
|
|
int mv88e6352_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
|
|
struct mv88e6xxx_vtu_entry *entry);
|
|
int mv88e6352_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
|
|
Index: drivers/net/dsa/mv88e6xxx/port.h
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/port.h
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/port.h
|
|
@@ -23,6 +23,16 @@
|
|
#define MV88E6XXX_PORT_STS_MY_PAUSE 0x4000
|
|
#define MV88E6XXX_PORT_STS_HD_FLOW 0x2000
|
|
#define MV88E6XXX_PORT_STS_PHY_DETECT 0x1000
|
|
+#define MV88E6250_PORT_STS_LINK 0x1000
|
|
+#define MV88E6250_PORT_STS_PORTMODE_MASK 0x0f00
|
|
+#define MV88E6250_PORT_STS_PORTMODE_PHY_10_HALF 0x0800
|
|
+#define MV88E6250_PORT_STS_PORTMODE_PHY_100_HALF 0x0900
|
|
+#define MV88E6250_PORT_STS_PORTMODE_PHY_10_FULL 0x0a00
|
|
+#define MV88E6250_PORT_STS_PORTMODE_PHY_100_FULL 0x0b00
|
|
+#define MV88E6250_PORT_STS_PORTMODE_MII_10_HALF 0x0c00
|
|
+#define MV88E6250_PORT_STS_PORTMODE_MII_100_HALF 0x0d00
|
|
+#define MV88E6250_PORT_STS_PORTMODE_MII_10_FULL 0x0e00
|
|
+#define MV88E6250_PORT_STS_PORTMODE_MII_100_FULL 0x0f00
|
|
#define MV88E6XXX_PORT_STS_LINK 0x0800
|
|
#define MV88E6XXX_PORT_STS_DUPLEX 0x0400
|
|
#define MV88E6XXX_PORT_STS_SPEED_MASK 0x0300
|
|
@@ -79,6 +89,7 @@
|
|
/* Offset 0x03: Switch Identifier Register */
|
|
#define MV88E6XXX_PORT_SWITCH_ID 0x03
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_MASK 0xfff0
|
|
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6071 0x0710
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6085 0x04a0
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6095 0x0950
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6097 0x0990
|
|
@@ -97,6 +108,7 @@
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6191 0x1910
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6185 0x1a70
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6240 0x2400
|
|
+#define MV88E6XXX_PORT_SWITCH_ID_PROD_6250 0x2500
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6290 0x2900
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6321 0x3100
|
|
#define MV88E6XXX_PORT_SWITCH_ID_PROD_6141 0x3400
|
|
@@ -262,6 +274,7 @@ int mv88e6xxx_port_set_duplex(struct mv8
|
|
|
|
int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
|
|
int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
|
|
+int mv88e6250_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
|
|
int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
|
|
int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
|
|
int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed);
|
|
Index: drivers/net/dsa/mv88e6xxx/port.c
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/port.c
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/port.c
|
|
@@ -266,6 +266,18 @@ int mv88e6185_port_set_speed(struct mv88
|
|
return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
|
|
}
|
|
|
|
+/* Support 10, 100 Mbps (e.g. 88E6250 family) */
|
|
+int mv88e6250_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
|
|
+{
|
|
+ if (speed == SPEED_MAX)
|
|
+ speed = 100;
|
|
+
|
|
+ if (speed > 100)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ return mv88e6xxx_port_set_speed(chip, port, speed, false, false);
|
|
+}
|
|
+
|
|
/* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
|
|
int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed)
|
|
{
|
|
Index: drivers/net/dsa/mv88e6xxx/global1_atu.c
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/global1_atu.c
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/global1_atu.c
|
|
@@ -92,7 +92,7 @@ static int mv88e6xxx_g1_atu_op(struct mv
|
|
if (err)
|
|
return err;
|
|
} else {
|
|
- if (mv88e6xxx_num_databases(chip) > 16) {
|
|
+ if (mv88e6xxx_num_databases(chip) > 64) {
|
|
/* ATU DBNum[7:4] are located in ATU Control 15:12 */
|
|
err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL,
|
|
&val);
|
|
@@ -104,6 +104,9 @@ static int mv88e6xxx_g1_atu_op(struct mv
|
|
val);
|
|
if (err)
|
|
return err;
|
|
+ } else if (mv88e6xxx_num_databases(chip) > 16) {
|
|
+ /* ATU DBNum[5:4] are located in ATU Operation 9:8 */
|
|
+ op |= (fid & 0x30) << 4;
|
|
}
|
|
|
|
/* ATU DBNum[3:0] are located in ATU Operation 3:0 */
|
|
Index: drivers/net/dsa/mv88e6xxx/global1_vtu.c
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/global1_vtu.c
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/global1_vtu.c
|
|
@@ -304,6 +304,35 @@ static int mv88e6xxx_g1_vtu_getnext(stru
|
|
return mv88e6xxx_g1_vtu_vid_read(chip, entry);
|
|
}
|
|
|
|
+int mv88e6250_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
|
|
+ struct mv88e6xxx_vtu_entry *entry)
|
|
+{
|
|
+ u16 val;
|
|
+ int err;
|
|
+
|
|
+ err = mv88e6xxx_g1_vtu_getnext(chip, entry);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (entry->valid) {
|
|
+ err = mv88e6185_g1_vtu_data_read(chip, entry);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ /* VTU DBNum[3:0] are located in VTU Operation 3:0
|
|
+ * VTU DBNum[5:4] are located in VTU Operation 9:8
|
|
+ */
|
|
+ err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP, &val);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ entry->fid = val & 0x000f;
|
|
+ entry->fid |= (val & 0x0300) >> 4;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
int mv88e6185_g1_vtu_getnext(struct mv88e6xxx_chip *chip,
|
|
struct mv88e6xxx_vtu_entry *entry)
|
|
{
|
|
@@ -393,6 +422,35 @@ int mv88e6390_g1_vtu_getnext(struct mv88
|
|
return 0;
|
|
}
|
|
|
|
+int mv88e6250_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
|
|
+ struct mv88e6xxx_vtu_entry *entry)
|
|
+{
|
|
+ u16 op = MV88E6XXX_G1_VTU_OP_VTU_LOAD_PURGE;
|
|
+ int err;
|
|
+
|
|
+ err = mv88e6xxx_g1_vtu_op_wait(chip);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ err = mv88e6xxx_g1_vtu_vid_write(chip, entry);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (entry->valid) {
|
|
+ err = mv88e6185_g1_vtu_data_write(chip, entry);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ /* VTU DBNum[3:0] are located in VTU Operation 3:0
|
|
+ * VTU DBNum[5:4] are located in VTU Operation 9:8
|
|
+ */
|
|
+ op |= entry->fid & 0x000f;
|
|
+ op |= (entry->fid & 0x0030) << 4;
|
|
+ }
|
|
+
|
|
+ return mv88e6xxx_g1_vtu_op(chip, op);
|
|
+}
|
|
+
|
|
int mv88e6185_g1_vtu_loadpurge(struct mv88e6xxx_chip *chip,
|
|
struct mv88e6xxx_vtu_entry *entry)
|
|
{
|
|
Index: drivers/net/dsa/mv88e6xxx/global2.c
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/global2.c
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/global2.c
|
|
@@ -835,6 +835,32 @@ const struct mv88e6xxx_irq_ops mv88e6097
|
|
.irq_free = mv88e6097_watchdog_free,
|
|
};
|
|
|
|
+static void mv88e6250_watchdog_free(struct mv88e6xxx_chip *chip)
|
|
+{
|
|
+ u16 reg;
|
|
+
|
|
+ mv88e6xxx_g2_read(chip, MV88E6250_G2_WDOG_CTL, ®);
|
|
+
|
|
+ reg &= ~(MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
|
|
+ MV88E6250_G2_WDOG_CTL_QC_ENABLE);
|
|
+
|
|
+ mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL, reg);
|
|
+}
|
|
+
|
|
+static int mv88e6250_watchdog_setup(struct mv88e6xxx_chip *chip)
|
|
+{
|
|
+ return mv88e6xxx_g2_write(chip, MV88E6250_G2_WDOG_CTL,
|
|
+ MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE |
|
|
+ MV88E6250_G2_WDOG_CTL_QC_ENABLE |
|
|
+ MV88E6250_G2_WDOG_CTL_SWRESET);
|
|
+}
|
|
+
|
|
+const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops = {
|
|
+ .irq_action = mv88e6097_watchdog_action,
|
|
+ .irq_setup = mv88e6250_watchdog_setup,
|
|
+ .irq_free = mv88e6250_watchdog_free,
|
|
+};
|
|
+
|
|
static int mv88e6390_watchdog_setup(struct mv88e6xxx_chip *chip)
|
|
{
|
|
return mv88e6xxx_g2_update(chip, MV88E6390_G2_WDOG_CTL,
|
|
Index: drivers/net/dsa/mv88e6xxx/global2.h
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/global2.h
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/global2.h
|
|
@@ -185,6 +185,18 @@
|
|
#define MV88E6XXX_G2_SCRATCH_MISC_DATA_MASK 0x00ff
|
|
|
|
/* Offset 0x1B: Watch Dog Control Register */
|
|
+#define MV88E6250_G2_WDOG_CTL 0x1b
|
|
+#define MV88E6250_G2_WDOG_CTL_QC_HISTORY 0x0100
|
|
+#define MV88E6250_G2_WDOG_CTL_QC_EVENT 0x0080
|
|
+#define MV88E6250_G2_WDOG_CTL_QC_ENABLE 0x0040
|
|
+#define MV88E6250_G2_WDOG_CTL_EGRESS_HISTORY 0x0020
|
|
+#define MV88E6250_G2_WDOG_CTL_EGRESS_EVENT 0x0010
|
|
+#define MV88E6250_G2_WDOG_CTL_EGRESS_ENABLE 0x0008
|
|
+#define MV88E6250_G2_WDOG_CTL_FORCE_IRQ 0x0004
|
|
+#define MV88E6250_G2_WDOG_CTL_HISTORY 0x0002
|
|
+#define MV88E6250_G2_WDOG_CTL_SWRESET 0x0001
|
|
+
|
|
+/* Offset 0x1B: Watch Dog Control Register */
|
|
#define MV88E6352_G2_WDOG_CTL 0x1b
|
|
#define MV88E6352_G2_WDOG_CTL_EGRESS_EVENT 0x0080
|
|
#define MV88E6352_G2_WDOG_CTL_RMU_TIMEOUT 0x0040
|
|
@@ -265,6 +277,7 @@ int mv88e6352_g2_mgmt_rsvd2cpu(struct mv
|
|
int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip);
|
|
|
|
extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
|
|
+extern const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops;
|
|
extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops;
|
|
|
|
#else /* !CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */
|
|
@@ -380,6 +393,7 @@ static inline int mv88e6xxx_g2_pot_clear
|
|
}
|
|
|
|
static const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {};
|
|
+static const struct mv88e6xxx_irq_ops mv88e6250_watchdog_ops = {};
|
|
static const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {};
|
|
|
|
#endif /* CONFIG_NET_DSA_MV88E6XXX_GLOBAL2 */
|
|
Index: drivers/net/dsa/mv88e6xxx/Makefile
|
|
===================================================================
|
|
--- drivers/net/dsa/mv88e6xxx/Makefile
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/Makefile
|
|
@@ -8,3 +8,4 @@ mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLO
|
|
mv88e6xxx-objs += phy.o
|
|
mv88e6xxx-objs += port.o
|
|
mv88e6xxx-objs += serdes.o
|
|
+mv88e6xxx-objs += smi.o
|
|
Index: drivers/net/dsa/mv88e6xxx/smi.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/smi.c
|
|
@@ -0,0 +1,181 @@
|
|
+/*
|
|
+ * Marvell 88E6xxx System Management Interface (SMI) support
|
|
+ *
|
|
+ * Copyright (c) 2008 Marvell Semiconductor
|
|
+ *
|
|
+ * Copyright (c) 2019 Vivien Didelot <vivien.didelot@gmail.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#include "chip.h"
|
|
+#include "smi.h"
|
|
+
|
|
+/* The switch ADDR[4:1] configuration pins define the chip SMI device address
|
|
+ * (ADDR[0] is always zero, thus only even SMI addresses can be strapped).
|
|
+ *
|
|
+ * When ADDR is all zero, the chip uses Single-chip Addressing Mode, assuming it
|
|
+ * is the only device connected to the SMI master. In this mode it responds to
|
|
+ * all 32 possible SMI addresses, and thus maps directly the internal devices.
|
|
+ *
|
|
+ * When ADDR is non-zero, the chip uses Multi-chip Addressing Mode, allowing
|
|
+ * multiple devices to share the SMI interface. In this mode it responds to only
|
|
+ * 2 registers, used to indirectly access the internal SMI devices.
|
|
+ *
|
|
+ * Some chips use a different scheme: Only the ADDR4 pin is used for
|
|
+ * configuration, and the device responds to 16 of the 32 SMI
|
|
+ * addresses, allowing two to coexist on the same SMI interface.
|
|
+ */
|
|
+
|
|
+static int mv88e6xxx_smi_direct_read(struct mv88e6xxx_chip *chip,
|
|
+ int dev, int reg, u16 *data)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = mdiobus_read_nested(chip->bus, dev, reg);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ *data = ret & 0xffff;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mv88e6xxx_smi_direct_write(struct mv88e6xxx_chip *chip,
|
|
+ int dev, int reg, u16 data)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = mdiobus_write_nested(chip->bus, dev, reg, data);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mv88e6xxx_smi_direct_wait(struct mv88e6xxx_chip *chip,
|
|
+ int dev, int reg, int bit, int val)
|
|
+{
|
|
+ u16 data;
|
|
+ int err;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < 16; i++) {
|
|
+ err = mv88e6xxx_smi_direct_read(chip, dev, reg, &data);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (!!(data >> bit) == !!val)
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return -ETIMEDOUT;
|
|
+}
|
|
+
|
|
+static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_direct_ops = {
|
|
+ .read = mv88e6xxx_smi_direct_read,
|
|
+ .write = mv88e6xxx_smi_direct_write,
|
|
+};
|
|
+
|
|
+static int mv88e6xxx_smi_dual_direct_read(struct mv88e6xxx_chip *chip,
|
|
+ int dev, int reg, u16 *data)
|
|
+{
|
|
+ return mv88e6xxx_smi_direct_read(chip, chip->sw_addr + dev, reg, data);
|
|
+}
|
|
+
|
|
+static int mv88e6xxx_smi_dual_direct_write(struct mv88e6xxx_chip *chip,
|
|
+ int dev, int reg, u16 data)
|
|
+{
|
|
+ return mv88e6xxx_smi_direct_write(chip, chip->sw_addr + dev, reg, data);
|
|
+}
|
|
+
|
|
+static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_dual_direct_ops = {
|
|
+ .read = mv88e6xxx_smi_dual_direct_read,
|
|
+ .write = mv88e6xxx_smi_dual_direct_write,
|
|
+};
|
|
+
|
|
+/* Offset 0x00: SMI Command Register
|
|
+ * Offset 0x01: SMI Data Register
|
|
+ */
|
|
+
|
|
+static int mv88e6xxx_smi_indirect_read(struct mv88e6xxx_chip *chip,
|
|
+ int dev, int reg, u16 *data)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
|
|
+ MV88E6XXX_SMI_CMD, 15, 0);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
|
|
+ MV88E6XXX_SMI_CMD,
|
|
+ MV88E6XXX_SMI_CMD_BUSY |
|
|
+ MV88E6XXX_SMI_CMD_MODE_22 |
|
|
+ MV88E6XXX_SMI_CMD_OP_22_READ |
|
|
+ (dev << 5) | reg);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
|
|
+ MV88E6XXX_SMI_CMD, 15, 0);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ return mv88e6xxx_smi_direct_read(chip, chip->sw_addr,
|
|
+ MV88E6XXX_SMI_DATA, data);
|
|
+}
|
|
+
|
|
+static int mv88e6xxx_smi_indirect_write(struct mv88e6xxx_chip *chip,
|
|
+ int dev, int reg, u16 data)
|
|
+{
|
|
+ int err;
|
|
+
|
|
+ err = mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
|
|
+ MV88E6XXX_SMI_CMD, 15, 0);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
|
|
+ MV88E6XXX_SMI_DATA, data);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ err = mv88e6xxx_smi_direct_write(chip, chip->sw_addr,
|
|
+ MV88E6XXX_SMI_CMD,
|
|
+ MV88E6XXX_SMI_CMD_BUSY |
|
|
+ MV88E6XXX_SMI_CMD_MODE_22 |
|
|
+ MV88E6XXX_SMI_CMD_OP_22_WRITE |
|
|
+ (dev << 5) | reg);
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ return mv88e6xxx_smi_direct_wait(chip, chip->sw_addr,
|
|
+ MV88E6XXX_SMI_CMD, 15, 0);
|
|
+}
|
|
+
|
|
+static const struct mv88e6xxx_bus_ops mv88e6xxx_smi_indirect_ops = {
|
|
+ .read = mv88e6xxx_smi_indirect_read,
|
|
+ .write = mv88e6xxx_smi_indirect_write,
|
|
+};
|
|
+
|
|
+int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
|
|
+ struct mii_bus *bus, int sw_addr)
|
|
+{
|
|
+ if (chip->info->dual_chip)
|
|
+ chip->smi_ops = &mv88e6xxx_smi_dual_direct_ops;
|
|
+ else if (sw_addr == 0)
|
|
+ chip->smi_ops = &mv88e6xxx_smi_direct_ops;
|
|
+ else if (chip->info->multi_chip)
|
|
+ chip->smi_ops = &mv88e6xxx_smi_indirect_ops;
|
|
+ else
|
|
+ return -EINVAL;
|
|
+
|
|
+ chip->bus = bus;
|
|
+ chip->sw_addr = sw_addr;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
Index: drivers/net/dsa/mv88e6xxx/smi.h
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ linux-imx/drivers/net/dsa/mv88e6xxx/smi.h
|
|
@@ -0,0 +1,59 @@
|
|
+/*
|
|
+ * Marvell 88E6xxx System Management Interface (SMI) support
|
|
+ *
|
|
+ * Copyright (c) 2008 Marvell Semiconductor
|
|
+ *
|
|
+ * Copyright (c) 2019 Vivien Didelot <vivien.didelot@gmail.com>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ */
|
|
+
|
|
+#ifndef _MV88E6XXX_SMI_H
|
|
+#define _MV88E6XXX_SMI_H
|
|
+
|
|
+#include "chip.h"
|
|
+
|
|
+/* Offset 0x00: SMI Command Register */
|
|
+#define MV88E6XXX_SMI_CMD 0x00
|
|
+#define MV88E6XXX_SMI_CMD_BUSY 0x8000
|
|
+#define MV88E6XXX_SMI_CMD_MODE_MASK 0x1000
|
|
+#define MV88E6XXX_SMI_CMD_MODE_45 0x0000
|
|
+#define MV88E6XXX_SMI_CMD_MODE_22 0x1000
|
|
+#define MV88E6XXX_SMI_CMD_OP_MASK 0x0c00
|
|
+#define MV88E6XXX_SMI_CMD_OP_22_WRITE 0x0400
|
|
+#define MV88E6XXX_SMI_CMD_OP_22_READ 0x0800
|
|
+#define MV88E6XXX_SMI_CMD_OP_45_WRITE_ADDR 0x0000
|
|
+#define MV88E6XXX_SMI_CMD_OP_45_WRITE_DATA 0x0400
|
|
+#define MV88E6XXX_SMI_CMD_OP_45_READ_DATA 0x0800
|
|
+#define MV88E6XXX_SMI_CMD_OP_45_READ_DATA_INC 0x0c00
|
|
+#define MV88E6XXX_SMI_CMD_DEV_ADDR_MASK 0x003e
|
|
+#define MV88E6XXX_SMI_CMD_REG_ADDR_MASK 0x001f
|
|
+
|
|
+/* Offset 0x01: SMI Data Register */
|
|
+#define MV88E6XXX_SMI_DATA 0x01
|
|
+
|
|
+int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
|
|
+ struct mii_bus *bus, int sw_addr);
|
|
+
|
|
+static inline int mv88e6xxx_smi_read(struct mv88e6xxx_chip *chip,
|
|
+ int dev, int reg, u16 *data)
|
|
+{
|
|
+ if (chip->smi_ops && chip->smi_ops->read)
|
|
+ return chip->smi_ops->read(chip, dev, reg, data);
|
|
+
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static inline int mv88e6xxx_smi_write(struct mv88e6xxx_chip *chip,
|
|
+ int dev, int reg, u16 data)
|
|
+{
|
|
+ if (chip->smi_ops && chip->smi_ops->write)
|
|
+ return chip->smi_ops->write(chip, dev, reg, data);
|
|
+
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+#endif /* _MV88E6XXX_SMI_H */
|