Commit 0ca6d8b7 authored by David S. Miller's avatar David S. Miller

Merge branch 'net-next-dsa-mt7530-add-support-for-MT7531'

Landen Chao says:

====================
net-next: dsa: mt7530: add support for MT7531

This patch series adds support for MT7531.

MT7531 is the next generation of MT7530 which could be found on Mediatek
router platforms such as MT7622 or MT7629.

It is also a 7-ports switch with 5 giga embedded phys, 2 cpu ports, and
the same MAC logic of MT7530. Cpu port 6 only supports SGMII interface.
Cpu port 5 supports either RGMII or SGMII in different HW SKU, but cannot
be muxed to PHY of port 0/4 like mt7530. Due to support for SGMII
interface, pll, and pad setting are different from MT7530.

MT7531 SGMII interface can be configured in following mode:
- 'SGMII AN mode' with in-band negotiation capability
    which is compatible with PHY_INTERFACE_MODE_SGMII.
- 'SGMII force mode' without in-band negotiation
    which is compatible with 10B/8B encoding of
    PHY_INTERFACE_MODE_1000BASEX with fixed full-duplex and fixed pause.
- 2.5 times faster clocked 'SGMII force mode' without in-band negotiation
    which is compatible with 10B/8B encoding of
    PHY_INTERFACE_MODE_2500BASEX with fixed full-duplex and fixed pause.

v4 -> v5
- Add fixed-link node to dsa cpu port in dts file by suggestion of
  Vladimir Oltean.

v3 -> v4
- Adjust the coding style by suggestion of Jakub Kicinski.
  Remove unnecessary jumping label, merge continuous numeric 'switch
  cases' into one line, and keep the variables longest to shortest
  (reverse xmas tree).

v2 -> v3
- Keep the same setup logic of mt7530/mt7621 because these series of
  patches is for adding mt7531 hardware.
- Do not adjust rgmii delay when vendor phy driver presents in order to
  prevent double adjustment by suggestion of Andrew Lunn.
- Remove redundant 'Example 4' from dt-bindings by suggestion of
  Rob Herring.
- Fix typo.

v1 -> v2
- change phylink_validate callback function to support full-duplex
  gigabit only to match hardware capability.
- add description of SGMII interface.
- configure mt7531 cpu port in fastest speed by default.
- parse SGMII control word for in-band negotiation mode.
- configure RGMII delay based on phy.rst.
- Rename the definition in the header file to avoid potential conflicts.
- Add wrapper function for mdio read/write to support both C22 and C45.
- correct fixed-link speed of 2500base-x in dts.
- add MT7531 port mirror setting.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4b468385 79a675e6
......@@ -5,6 +5,7 @@ Required properties:
- compatible: may be compatible = "mediatek,mt7530"
or compatible = "mediatek,mt7621"
or compatible = "mediatek,mt7531"
- #address-cells: Must be 1.
- #size-cells: Must be 0.
- mediatek,mcm: Boolean; if defined, indicates that either MT7530 is the part
......@@ -32,10 +33,14 @@ Required properties for the child nodes within ports container:
- reg: Port address described must be 6 for CPU port and from 0 to 5 for
user ports.
- phy-mode: String, must be either "trgmii" or "rgmii" for port labeled
"cpu".
Port 5 of the switch is muxed between:
- phy-mode: String, the following values are acceptable for port labeled
"cpu":
If compatible mediatek,mt7530 or mediatek,mt7621 is set,
must be either "trgmii" or "rgmii"
If compatible mediatek,mt7531 is set,
must be either "sgmii", "1000base-x" or "2500base-x"
Port 5 of mt7530 and mt7621 switch is muxed between:
1. GMAC5: GMAC5 can interface with another external MAC or PHY.
2. PHY of port 0 or port 4: PHY interfaces with an external MAC like 2nd GMAC
of the SOC. Used in many setups where port 0/4 becomes the WAN port.
......
......@@ -143,6 +143,56 @@ fixed-link {
mdio: mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
switch@0 {
compatible = "mediatek,mt7531";
reg = <0>;
reset-gpios = <&pio 54 0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "wan";
};
port@1 {
reg = <1>;
label = "lan0";
};
port@2 {
reg = <2>;
label = "lan1";
};
port@3 {
reg = <3>;
label = "lan2";
};
port@4 {
reg = <4>;
label = "lan3";
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&gmac0>;
phy-mode = "2500base-x";
fixed-link {
speed = <2500>;
full-duplex;
pause;
};
};
};
};
};
};
......
......@@ -105,20 +105,71 @@ &eth {
pinctrl-0 = <&eth_pins>;
status = "okay";
gmac1: mac@1 {
gmac0: mac@0 {
compatible = "mediatek,eth-mac";
reg = <1>;
phy-handle = <&phy5>;
reg = <0>;
phy-mode = "2500base-x";
fixed-link {
speed = <2500>;
full-duplex;
pause;
};
};
mdio-bus {
#address-cells = <1>;
#size-cells = <0>;
phy5: ethernet-phy@5 {
reg = <5>;
phy-mode = "sgmii";
switch@0 {
compatible = "mediatek,mt7531";
reg = <0>;
reset-gpios = <&pio 54 0>;
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
label = "lan0";
};
port@1 {
reg = <1>;
label = "lan1";
};
port@2 {
reg = <2>;
label = "lan2";
};
port@3 {
reg = <3>;
label = "lan3";
};
port@4 {
reg = <4>;
label = "wan";
};
port@6 {
reg = <6>;
label = "cpu";
ethernet = <&gmac0>;
phy-mode = "2500base-x";
fixed-link {
speed = <2500>;
full-duplex;
pause;
};
};
};
};
};
};
......
......@@ -33,12 +33,12 @@ config NET_DSA_LANTIQ_GSWIP
the xrx200 / VR9 SoC.
config NET_DSA_MT7530
tristate "Mediatek MT7530 Ethernet switch support"
tristate "MediaTek MT753x and MT7621 Ethernet switch support"
depends on NET_DSA
select NET_DSA_TAG_MTK
help
This enables support for the Mediatek MT7530 Ethernet switch
chip.
This enables support for the MediaTek MT7530, MT7531, and MT7621
Ethernet switch chips.
config NET_DSA_MV88E6060
tristate "Marvell 88E6060 ethernet switch chip support"
......
......@@ -233,6 +233,12 @@ mt7530_write(struct mt7530_priv *priv, u32 reg, u32 val)
mutex_unlock(&bus->mdio_lock);
}
static u32
_mt7530_unlocked_read(struct mt7530_dummy_poll *p)
{
return mt7530_mii_read(p->priv, p->reg);
}
static u32
_mt7530_read(struct mt7530_dummy_poll *p)
{
......@@ -372,8 +378,9 @@ mt7530_fdb_write(struct mt7530_priv *priv, u16 vid,
mt7530_write(priv, MT7530_ATA1 + (i * 4), reg[i]);
}
/* Setup TX circuit including relevant PAD and driving */
static int
mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
mt7530_pad_clk_setup(struct dsa_switch *ds, phy_interface_t interface)
{
struct mt7530_priv *priv = ds->priv;
u32 ncpo1, ssc_delta, trgint, i, xtal;
......@@ -387,7 +394,7 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
return -EINVAL;
}
switch (mode) {
switch (interface) {
case PHY_INTERFACE_MODE_RGMII:
trgint = 0;
/* PLL frequency: 125MHz */
......@@ -409,7 +416,8 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
}
break;
default:
dev_err(priv->dev, "xMII mode %d not supported\n", mode);
dev_err(priv->dev, "xMII interface %d not supported\n",
interface);
return -EINVAL;
}
......@@ -481,6 +489,108 @@ mt7530_pad_clk_setup(struct dsa_switch *ds, int mode)
return 0;
}
static bool mt7531_dual_sgmii_supported(struct mt7530_priv *priv)
{
u32 val;
val = mt7530_read(priv, MT7531_TOP_SIG_SR);
return (val & PAD_DUAL_SGMII_EN) != 0;
}
static int
mt7531_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
{
struct mt7530_priv *priv = ds->priv;
u32 top_sig;
u32 hwstrap;
u32 xtal;
u32 val;
if (mt7531_dual_sgmii_supported(priv))
return 0;
val = mt7530_read(priv, MT7531_CREV);
top_sig = mt7530_read(priv, MT7531_TOP_SIG_SR);
hwstrap = mt7530_read(priv, MT7531_HWTRAP);
if ((val & CHIP_REV_M) > 0)
xtal = (top_sig & PAD_MCM_SMI_EN) ? HWTRAP_XTAL_FSEL_40MHZ :
HWTRAP_XTAL_FSEL_25MHZ;
else
xtal = hwstrap & HWTRAP_XTAL_FSEL_MASK;
/* Step 1 : Disable MT7531 COREPLL */
val = mt7530_read(priv, MT7531_PLLGP_EN);
val &= ~EN_COREPLL;
mt7530_write(priv, MT7531_PLLGP_EN, val);
/* Step 2: switch to XTAL output */
val = mt7530_read(priv, MT7531_PLLGP_EN);
val |= SW_CLKSW;
mt7530_write(priv, MT7531_PLLGP_EN, val);
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_EN;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
/* Step 3: disable PLLGP and enable program PLLGP */
val = mt7530_read(priv, MT7531_PLLGP_EN);
val |= SW_PLLGP;
mt7530_write(priv, MT7531_PLLGP_EN, val);
/* Step 4: program COREPLL output frequency to 500MHz */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_POSDIV_M;
val |= 2 << RG_COREPLL_POSDIV_S;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
usleep_range(25, 35);
switch (xtal) {
case HWTRAP_XTAL_FSEL_25MHZ:
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_SDM_PCW_M;
val |= 0x140000 << RG_COREPLL_SDM_PCW_S;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
break;
case HWTRAP_XTAL_FSEL_40MHZ:
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_SDM_PCW_M;
val |= 0x190000 << RG_COREPLL_SDM_PCW_S;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
break;
};
/* Set feedback divide ratio update signal to high */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val |= RG_COREPLL_SDM_PCW_CHG;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
/* Wait for at least 16 XTAL clocks */
usleep_range(10, 20);
/* Step 5: set feedback divide ratio update signal to low */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val &= ~RG_COREPLL_SDM_PCW_CHG;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
/* Enable 325M clock for SGMII */
mt7530_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
/* Enable 250SSC clock for RGMII */
mt7530_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
/* Step 6: Enable MT7531 PLL */
val = mt7530_read(priv, MT7531_PLLGP_CR0);
val |= RG_COREPLL_EN;
mt7530_write(priv, MT7531_PLLGP_CR0, val);
val = mt7530_read(priv, MT7531_PLLGP_EN);
val |= EN_COREPLL;
mt7530_write(priv, MT7531_PLLGP_EN, val);
usleep_range(25, 35);
return 0;
}
static void
mt7530_mib_reset(struct dsa_switch *ds)
{
......@@ -505,6 +615,217 @@ static int mt7530_phy_write(struct dsa_switch *ds, int port, int regnum,
return mdiobus_write_nested(priv->bus, port, regnum, val);
}
static int
mt7531_ind_c45_phy_read(struct mt7530_priv *priv, int port, int devad,
int regnum)
{
struct mii_bus *bus = priv->bus;
struct mt7530_dummy_poll p;
u32 reg, val;
int ret;
INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | regnum;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
reg = MT7531_MDIO_CL45_READ | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad);
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
ret = val & MT7531_MDIO_RW_DATA_MASK;
out:
mutex_unlock(&bus->mdio_lock);
return ret;
}
static int
mt7531_ind_c45_phy_write(struct mt7530_priv *priv, int port, int devad,
int regnum, u32 data)
{
struct mii_bus *bus = priv->bus;
struct mt7530_dummy_poll p;
u32 val, reg;
int ret;
INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
reg = MT7531_MDIO_CL45_ADDR | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | regnum;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
reg = MT7531_MDIO_CL45_WRITE | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_DEV_ADDR(devad) | data;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
out:
mutex_unlock(&bus->mdio_lock);
return ret;
}
static int
mt7531_ind_c22_phy_read(struct mt7530_priv *priv, int port, int regnum)
{
struct mii_bus *bus = priv->bus;
struct mt7530_dummy_poll p;
int ret;
u32 val;
INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
val = MT7531_MDIO_CL22_READ | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_REG_ADDR(regnum);
mt7530_mii_write(priv, MT7531_PHY_IAC, val | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, val,
!(val & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
ret = val & MT7531_MDIO_RW_DATA_MASK;
out:
mutex_unlock(&bus->mdio_lock);
return ret;
}
static int
mt7531_ind_c22_phy_write(struct mt7530_priv *priv, int port, int regnum,
u16 data)
{
struct mii_bus *bus = priv->bus;
struct mt7530_dummy_poll p;
int ret;
u32 reg;
INIT_MT7530_DUMMY_POLL(&p, priv, MT7531_PHY_IAC);
mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
!(reg & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
reg = MT7531_MDIO_CL22_WRITE | MT7531_MDIO_PHY_ADDR(port) |
MT7531_MDIO_REG_ADDR(regnum) | data;
mt7530_mii_write(priv, MT7531_PHY_IAC, reg | MT7531_PHY_ACS_ST);
ret = readx_poll_timeout(_mt7530_unlocked_read, &p, reg,
!(reg & MT7531_PHY_ACS_ST), 20, 100000);
if (ret < 0) {
dev_err(priv->dev, "poll timeout\n");
goto out;
}
out:
mutex_unlock(&bus->mdio_lock);
return ret;
}
static int
mt7531_ind_phy_read(struct dsa_switch *ds, int port, int regnum)
{
struct mt7530_priv *priv = ds->priv;
int devad;
int ret;
if (regnum & MII_ADDR_C45) {
devad = (regnum >> MII_DEVADDR_C45_SHIFT) & 0x1f;
ret = mt7531_ind_c45_phy_read(priv, port, devad,
regnum & MII_REGADDR_C45_MASK);
} else {
ret = mt7531_ind_c22_phy_read(priv, port, regnum);
}
return ret;
}
static int
mt7531_ind_phy_write(struct dsa_switch *ds, int port, int regnum,
u16 data)
{
struct mt7530_priv *priv = ds->priv;
int devad;
int ret;
if (regnum & MII_ADDR_C45) {
devad = (regnum >> MII_DEVADDR_C45_SHIFT) & 0x1f;
ret = mt7531_ind_c45_phy_write(priv, port, devad,
regnum & MII_REGADDR_C45_MASK,
data);
} else {
ret = mt7531_ind_c22_phy_write(priv, port, regnum, data);
}
return ret;
}
static void
mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
uint8_t *data)
......@@ -621,9 +942,14 @@ static void mt7530_setup_port5(struct dsa_switch *ds, phy_interface_t interface)
}
static int
mt7530_cpu_port_enable(struct mt7530_priv *priv,
int port)
mt753x_cpu_port_enable(struct dsa_switch *ds, int port)
{
struct mt7530_priv *priv = ds->priv;
/* Setup max capability of CPU port at first */
if (priv->info->cpu_port_config)
priv->info->cpu_port_config(ds, port);
/* Enable Mediatek header mode on the cpu port */
mt7530_write(priv, MT7530_PVC_P(port),
PORT_SPEC_TAG);
......@@ -636,7 +962,7 @@ mt7530_cpu_port_enable(struct mt7530_priv *priv,
mt7530_rmw(priv, MT7530_MFC, CPU_MASK, CPU_EN | CPU_PORT(port));
/* CPU port gets connected to all user ports of
* the switch
* the switch.
*/
mt7530_write(priv, MT7530_PCR_P(port),
PCR_MATRIX(dsa_user_ports(priv->ds)));
......@@ -1130,27 +1456,42 @@ mt7530_port_vlan_del(struct dsa_switch *ds, int port,
return 0;
}
static int mt7530_port_mirror_add(struct dsa_switch *ds, int port,
static int mt753x_mirror_port_get(unsigned int id, u32 val)
{
return (id == ID_MT7531) ? MT7531_MIRROR_PORT_GET(val) :
MIRROR_PORT(val);
}
static int mt753x_mirror_port_set(unsigned int id, u32 val)
{
return (id == ID_MT7531) ? MT7531_MIRROR_PORT_SET(val) :
MIRROR_PORT(val);
}
static int mt753x_port_mirror_add(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror,
bool ingress)
{
struct mt7530_priv *priv = ds->priv;
int monitor_port;
u32 val;
/* Check for existent entry */
if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
return -EEXIST;
val = mt7530_read(priv, MT7530_MFC);
val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
/* MT7530 only supports one monitor port */
if (val & MIRROR_EN && MIRROR_PORT(val) != mirror->to_local_port)
monitor_port = mt753x_mirror_port_get(priv->id, val);
if (val & MT753X_MIRROR_EN(priv->id) &&
monitor_port != mirror->to_local_port)
return -EEXIST;
val |= MIRROR_EN;
val &= ~MIRROR_MASK;
val |= mirror->to_local_port;
mt7530_write(priv, MT7530_MFC, val);
val |= MT753X_MIRROR_EN(priv->id);
val &= ~MT753X_MIRROR_MASK(priv->id);
val |= mt753x_mirror_port_set(priv->id, mirror->to_local_port);
mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
val = mt7530_read(priv, MT7530_PCR_P(port));
if (ingress) {
......@@ -1165,7 +1506,7 @@ static int mt7530_port_mirror_add(struct dsa_switch *ds, int port,
return 0;
}
static void mt7530_port_mirror_del(struct dsa_switch *ds, int port,
static void mt753x_port_mirror_del(struct dsa_switch *ds, int port,
struct dsa_mall_mirror_tc_entry *mirror)
{
struct mt7530_priv *priv = ds->priv;
......@@ -1182,9 +1523,9 @@ static void mt7530_port_mirror_del(struct dsa_switch *ds, int port,
mt7530_write(priv, MT7530_PCR_P(port), val);
if (!priv->mirror_rx && !priv->mirror_tx) {
val = mt7530_read(priv, MT7530_MFC);
val &= ~MIRROR_EN;
mt7530_write(priv, MT7530_MFC, val);
val = mt7530_read(priv, MT753X_MIRROR_REG(priv->id));
val &= ~MT753X_MIRROR_EN(priv->id);
mt7530_write(priv, MT753X_MIRROR_REG(priv->id), val);
}
}
......@@ -1291,7 +1632,7 @@ mt7530_setup(struct dsa_switch *ds)
PCR_MATRIX_CLR);
if (dsa_is_cpu_port(ds, i))
mt7530_cpu_port_enable(priv, i);
mt753x_cpu_port_enable(ds, i);
else
mt7530_port_disable(ds, i);
......@@ -1352,81 +1693,543 @@ mt7530_setup(struct dsa_switch *ds)
return 0;
}
static void mt7530_phylink_mac_config(struct dsa_switch *ds, int port,
unsigned int mode,
const struct phylink_link_state *state)
static int
mt7531_setup(struct dsa_switch *ds)
{
struct mt7530_priv *priv = ds->priv;
u32 mcr_cur, mcr_new;
switch (port) {
case 0: /* Internal phy */
case 1:
case 2:
case 3:
case 4:
if (state->interface != PHY_INTERFACE_MODE_GMII)
return;
break;
case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
if (priv->p5_interface == state->interface)
break;
if (!phy_interface_mode_is_rgmii(state->interface) &&
state->interface != PHY_INTERFACE_MODE_MII &&
state->interface != PHY_INTERFACE_MODE_GMII)
return;
struct mt7530_dummy_poll p;
u32 val, id;
int ret, i;
mt7530_setup_port5(ds, state->interface);
break;
case 6: /* 1st cpu port */
if (priv->p6_interface == state->interface)
break;
/* Reset whole chip through gpio pin or memory-mapped registers for
* different type of hardware
*/
if (priv->mcm) {
reset_control_assert(priv->rstc);
usleep_range(1000, 1100);
reset_control_deassert(priv->rstc);
} else {
gpiod_set_value_cansleep(priv->reset, 0);
usleep_range(1000, 1100);
gpiod_set_value_cansleep(priv->reset, 1);
}
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_TRGMII)
return;
/* Waiting for MT7530 got to stable */
INIT_MT7530_DUMMY_POLL(&p, priv, MT7530_HWTRAP);
ret = readx_poll_timeout(_mt7530_read, &p, val, val != 0,
20, 1000000);
if (ret < 0) {
dev_err(priv->dev, "reset timeout\n");
return ret;
}
/* Setup TX circuit incluing relevant PAD and driving */
mt7530_pad_clk_setup(ds, state->interface);
id = mt7530_read(priv, MT7531_CREV);
id >>= CHIP_NAME_SHIFT;
priv->p6_interface = state->interface;
break;
default:
dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
return;
if (id != MT7531_ID) {
dev_err(priv->dev, "chip %x can't be supported\n", id);
return -ENODEV;
}
if (phylink_autoneg_inband(mode)) {
dev_err(ds->dev, "%s: in-band negotiation unsupported\n",
__func__);
return;
/* Reset the switch through internal reset */
mt7530_write(priv, MT7530_SYS_CTRL,
SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST |
SYS_CTRL_REG_RST);
if (mt7531_dual_sgmii_supported(priv)) {
priv->p5_intf_sel = P5_INTF_SEL_GMAC5_SGMII;
/* Let ds->slave_mii_bus be able to access external phy. */
mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO11_RG_RXD2_MASK,
MT7531_EXT_P_MDC_11);
mt7530_rmw(priv, MT7531_GPIO_MODE1, MT7531_GPIO12_RG_RXD3_MASK,
MT7531_EXT_P_MDIO_12);
} else {
priv->p5_intf_sel = P5_INTF_SEL_GMAC5;
}
dev_dbg(ds->dev, "P5 support %s interface\n",
p5_intf_modes(priv->p5_intf_sel));
mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
mcr_new = mcr_cur;
mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
PMCR_BACKPR_EN | PMCR_FORCE_MODE;
mt7530_rmw(priv, MT7531_GPIO_MODE0, MT7531_GPIO0_MASK,
MT7531_GPIO0_INTERRUPT);
/* Are we connected to external phy */
if (port == 5 && dsa_is_user_port(ds, 5))
mcr_new |= PMCR_EXT_PHY;
/* Let phylink decide the interface later. */
priv->p5_interface = PHY_INTERFACE_MODE_NA;
priv->p6_interface = PHY_INTERFACE_MODE_NA;
if (mcr_new != mcr_cur)
mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
}
/* Enable PHY core PLL, since phy_device has not yet been created
* provided for phy_[read,write]_mmd_indirect is called, we provide
* our own mt7531_ind_mmd_phy_[read,write] to complete this
* function.
*/
val = mt7531_ind_c45_phy_read(priv, MT753X_CTRL_PHY_ADDR,
MDIO_MMD_VEND2, CORE_PLL_GROUP4);
val |= MT7531_PHY_PLL_BYPASS_MODE;
val &= ~MT7531_PHY_PLL_OFF;
mt7531_ind_c45_phy_write(priv, MT753X_CTRL_PHY_ADDR, MDIO_MMD_VEND2,
CORE_PLL_GROUP4, val);
/* BPDU to CPU port */
mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
BIT(MT7530_CPU_PORT));
mt7530_rmw(priv, MT753X_BPC, MT753X_BPDU_PORT_FW_MASK,
MT753X_BPDU_CPU_ONLY);
static void mt7530_phylink_mac_link_down(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface)
{
struct mt7530_priv *priv = ds->priv;
/* Enable and reset MIB counters */
mt7530_mib_reset(ds);
mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
}
for (i = 0; i < MT7530_NUM_PORTS; i++) {
/* Disable forwarding by default on all ports */
mt7530_rmw(priv, MT7530_PCR_P(i), PCR_MATRIX_MASK,
PCR_MATRIX_CLR);
static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
mt7530_set(priv, MT7531_DBG_CNT(i), MT7531_DIS_CLR);
if (dsa_is_cpu_port(ds, i))
mt753x_cpu_port_enable(ds, i);
else
mt7530_port_disable(ds, i);
/* Enable consistent egress tag */
mt7530_rmw(priv, MT7530_PVC_P(i), PVC_EG_TAG_MASK,
PVC_EG_TAG(MT7530_VLAN_EG_CONSISTENT));
}
ds->configure_vlan_while_not_filtering = true;
/* Flush the FDB table */
ret = mt7530_fdb_cmd(priv, MT7530_FDB_FLUSH, NULL);
if (ret < 0)
return ret;
return 0;
}
static bool
mt7530_phy_mode_supported(struct dsa_switch *ds, int port,
const struct phylink_link_state *state)
{
struct mt7530_priv *priv = ds->priv;
switch (port) {
case 0 ... 4: /* Internal phy */
if (state->interface != PHY_INTERFACE_MODE_GMII)
return false;
break;
case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
if (!phy_interface_mode_is_rgmii(state->interface) &&
state->interface != PHY_INTERFACE_MODE_MII &&
state->interface != PHY_INTERFACE_MODE_GMII)
return false;
break;
case 6: /* 1st cpu port */
if (state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_TRGMII)
return false;
break;
default:
dev_err(priv->dev, "%s: unsupported port: %i\n", __func__,
port);
return false;
}
return true;
}
static bool mt7531_is_rgmii_port(struct mt7530_priv *priv, u32 port)
{
return (port == 5) && (priv->p5_intf_sel != P5_INTF_SEL_GMAC5_SGMII);
}
static bool
mt7531_phy_mode_supported(struct dsa_switch *ds, int port,
const struct phylink_link_state *state)
{
struct mt7530_priv *priv = ds->priv;
switch (port) {
case 0 ... 4: /* Internal phy */
if (state->interface != PHY_INTERFACE_MODE_GMII)
return false;
break;
case 5: /* 2nd cpu port supports either rgmii or sgmii/8023z */
if (mt7531_is_rgmii_port(priv, port))
return phy_interface_mode_is_rgmii(state->interface);
fallthrough;
case 6: /* 1st cpu port supports sgmii/8023z only */
if (state->interface != PHY_INTERFACE_MODE_SGMII &&
!phy_interface_mode_is_8023z(state->interface))
return false;
break;
default:
dev_err(priv->dev, "%s: unsupported port: %i\n", __func__,
port);
return false;
}
return true;
}
static bool
mt753x_phy_mode_supported(struct dsa_switch *ds, int port,
const struct phylink_link_state *state)
{
struct mt7530_priv *priv = ds->priv;
return priv->info->phy_mode_supported(ds, port, state);
}
static int
mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
{
struct mt7530_priv *priv = ds->priv;
return priv->info->pad_setup(ds, state->interface);
}
static int
mt7530_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
phy_interface_t interface)
{
struct mt7530_priv *priv = ds->priv;
/* Only need to setup port5. */
if (port != 5)
return 0;
mt7530_setup_port5(priv->ds, interface);
return 0;
}
static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
phy_interface_t interface,
struct phy_device *phydev)
{
u32 val;
if (!mt7531_is_rgmii_port(priv, port)) {
dev_err(priv->dev, "RGMII mode is not available for port %d\n",
port);
return -EINVAL;
}
val = mt7530_read(priv, MT7531_CLKGEN_CTRL);
val |= GP_CLK_EN;
val &= ~GP_MODE_MASK;
val |= GP_MODE(MT7531_GP_MODE_RGMII);
val &= ~CLK_SKEW_IN_MASK;
val |= CLK_SKEW_IN(MT7531_CLK_SKEW_NO_CHG);
val &= ~CLK_SKEW_OUT_MASK;
val |= CLK_SKEW_OUT(MT7531_CLK_SKEW_NO_CHG);
val |= TXCLK_NO_REVERSE | RXCLK_NO_DELAY;
/* Do not adjust rgmii delay when vendor phy driver presents. */
if (!phydev || phy_driver_is_genphy(phydev)) {
val &= ~(TXCLK_NO_REVERSE | RXCLK_NO_DELAY);
switch (interface) {
case PHY_INTERFACE_MODE_RGMII:
val |= TXCLK_NO_REVERSE;
val |= RXCLK_NO_DELAY;
break;
case PHY_INTERFACE_MODE_RGMII_RXID:
val |= TXCLK_NO_REVERSE;
break;
case PHY_INTERFACE_MODE_RGMII_TXID:
val |= RXCLK_NO_DELAY;
break;
case PHY_INTERFACE_MODE_RGMII_ID:
break;
default:
return -EINVAL;
}
}
mt7530_write(priv, MT7531_CLKGEN_CTRL, val);
return 0;
}
static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port,
unsigned long *supported)
{
/* Port5 supports ethier RGMII or SGMII.
* Port6 supports SGMII only.
*/
switch (port) {
case 5:
if (mt7531_is_rgmii_port(priv, port))
break;
fallthrough;
case 6:
phylink_set(supported, 1000baseX_Full);
phylink_set(supported, 2500baseX_Full);
phylink_set(supported, 2500baseT_Full);
}
}
static void
mt7531_sgmii_link_up_force(struct dsa_switch *ds, int port,
unsigned int mode, phy_interface_t interface,
int speed, int duplex)
{
struct mt7530_priv *priv = ds->priv;
unsigned int val;
/* For adjusting speed and duplex of SGMII force mode. */
if (interface != PHY_INTERFACE_MODE_SGMII ||
phylink_autoneg_inband(mode))
return;
/* SGMII force mode setting */
val = mt7530_read(priv, MT7531_SGMII_MODE(port));
val &= ~MT7531_SGMII_IF_MODE_MASK;
switch (speed) {
case SPEED_10:
val |= MT7531_SGMII_FORCE_SPEED_10;
break;
case SPEED_100:
val |= MT7531_SGMII_FORCE_SPEED_100;
break;
case SPEED_1000:
val |= MT7531_SGMII_FORCE_SPEED_1000;
break;
}
/* MT7531 SGMII 1G force mode can only work in full duplex mode,
* no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
*/
if ((speed == SPEED_10 || speed == SPEED_100) &&
duplex != DUPLEX_FULL)
val |= MT7531_SGMII_FORCE_HALF_DUPLEX;
mt7530_write(priv, MT7531_SGMII_MODE(port), val);
}
static bool mt753x_is_mac_port(u32 port)
{
return (port == 5 || port == 6);
}
static int mt7531_sgmii_setup_mode_force(struct mt7530_priv *priv, u32 port,
phy_interface_t interface)
{
u32 val;
if (!mt753x_is_mac_port(port))
return -EINVAL;
mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
MT7531_SGMII_PHYA_PWD);
val = mt7530_read(priv, MT7531_PHYA_CTRL_SIGNAL3(port));
val &= ~MT7531_RG_TPHY_SPEED_MASK;
/* Setup 2.5 times faster clock for 2.5Gbps data speeds with 10B/8B
* encoding.
*/
val |= (interface == PHY_INTERFACE_MODE_2500BASEX) ?
MT7531_RG_TPHY_SPEED_3_125G : MT7531_RG_TPHY_SPEED_1_25G;
mt7530_write(priv, MT7531_PHYA_CTRL_SIGNAL3(port), val);
mt7530_clear(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
/* MT7531 SGMII 1G and 2.5G force mode can only work in full duplex
* mode, no matter MT7531_SGMII_FORCE_HALF_DUPLEX is set or not.
*/
mt7530_rmw(priv, MT7531_SGMII_MODE(port),
MT7531_SGMII_IF_MODE_MASK | MT7531_SGMII_REMOTE_FAULT_DIS,
MT7531_SGMII_FORCE_SPEED_1000);
mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
return 0;
}
static int mt7531_sgmii_setup_mode_an(struct mt7530_priv *priv, int port,
phy_interface_t interface)
{
if (!mt753x_is_mac_port(port))
return -EINVAL;
mt7530_set(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
MT7531_SGMII_PHYA_PWD);
mt7530_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port),
MT7531_RG_TPHY_SPEED_MASK, MT7531_RG_TPHY_SPEED_1_25G);
mt7530_set(priv, MT7531_SGMII_MODE(port),
MT7531_SGMII_REMOTE_FAULT_DIS |
MT7531_SGMII_SPEED_DUPLEX_AN);
mt7530_rmw(priv, MT7531_PCS_SPEED_ABILITY(port),
MT7531_SGMII_TX_CONFIG_MASK, 1);
mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_ENABLE);
mt7530_set(priv, MT7531_PCS_CONTROL_1(port), MT7531_SGMII_AN_RESTART);
mt7530_write(priv, MT7531_QPHY_PWR_STATE_CTRL(port), 0);
return 0;
}
static void mt7531_sgmii_restart_an(struct dsa_switch *ds, int port)
{
struct mt7530_priv *priv = ds->priv;
u32 val;
/* Only restart AN when AN is enabled */
val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
if (val & MT7531_SGMII_AN_ENABLE) {
val |= MT7531_SGMII_AN_RESTART;
mt7530_write(priv, MT7531_PCS_CONTROL_1(port), val);
}
}
static int
mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
phy_interface_t interface)
{
struct mt7530_priv *priv = ds->priv;
struct phy_device *phydev;
struct dsa_port *dp;
if (!mt753x_is_mac_port(port)) {
dev_err(priv->dev, "port %d is not a MAC port\n", port);
return -EINVAL;
}
switch (interface) {
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_ID:
case PHY_INTERFACE_MODE_RGMII_RXID:
case PHY_INTERFACE_MODE_RGMII_TXID:
dp = dsa_to_port(ds, port);
phydev = dp->slave->phydev;
return mt7531_rgmii_setup(priv, port, interface, phydev);
case PHY_INTERFACE_MODE_SGMII:
return mt7531_sgmii_setup_mode_an(priv, port, interface);
case PHY_INTERFACE_MODE_NA:
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
if (phylink_autoneg_inband(mode))
return -EINVAL;
return mt7531_sgmii_setup_mode_force(priv, port, interface);
default:
return -EINVAL;
}
return -EINVAL;
}
static int
mt753x_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
const struct phylink_link_state *state)
{
struct mt7530_priv *priv = ds->priv;
return priv->info->mac_port_config(ds, port, mode, state->interface);
}
static void
mt753x_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
const struct phylink_link_state *state)
{
struct mt7530_priv *priv = ds->priv;
u32 mcr_cur, mcr_new;
if (!mt753x_phy_mode_supported(ds, port, state))
goto unsupported;
switch (port) {
case 0 ... 4: /* Internal phy */
if (state->interface != PHY_INTERFACE_MODE_GMII)
goto unsupported;
break;
case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
if (priv->p5_interface == state->interface)
break;
if (mt753x_mac_config(ds, port, mode, state) < 0)
goto unsupported;
if (priv->p5_intf_sel != P5_DISABLED)
priv->p5_interface = state->interface;
break;
case 6: /* 1st cpu port */
if (priv->p6_interface == state->interface)
break;
mt753x_pad_setup(ds, state);
if (mt753x_mac_config(ds, port, mode, state) < 0)
goto unsupported;
priv->p6_interface = state->interface;
break;
default:
unsupported:
dev_err(ds->dev, "%s: unsupported %s port: %i\n",
__func__, phy_modes(state->interface), port);
return;
}
if (phylink_autoneg_inband(mode) &&
state->interface != PHY_INTERFACE_MODE_SGMII) {
dev_err(ds->dev, "%s: in-band negotiation unsupported\n",
__func__);
return;
}
mcr_cur = mt7530_read(priv, MT7530_PMCR_P(port));
mcr_new = mcr_cur;
mcr_new &= ~PMCR_LINK_SETTINGS_MASK;
mcr_new |= PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | PMCR_BACKOFF_EN |
PMCR_BACKPR_EN | PMCR_FORCE_MODE_ID(priv->id);
/* Are we connected to external phy */
if (port == 5 && dsa_is_user_port(ds, 5))
mcr_new |= PMCR_EXT_PHY;
if (mcr_new != mcr_cur)
mt7530_write(priv, MT7530_PMCR_P(port), mcr_new);
}
static void
mt753x_phylink_mac_an_restart(struct dsa_switch *ds, int port)
{
struct mt7530_priv *priv = ds->priv;
if (!priv->info->mac_pcs_an_restart)
return;
priv->info->mac_pcs_an_restart(ds, port);
}
static void mt753x_phylink_mac_link_down(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface)
{
struct mt7530_priv *priv = ds->priv;
mt7530_clear(priv, MT7530_PMCR_P(port), PMCR_LINK_SETTINGS_MASK);
}
static void mt753x_mac_pcs_link_up(struct dsa_switch *ds, int port,
unsigned int mode, phy_interface_t interface,
int speed, int duplex)
{
struct mt7530_priv *priv = ds->priv;
if (!priv->info->mac_pcs_link_up)
return;
priv->info->mac_pcs_link_up(ds, port, mode, interface, speed, duplex);
}
static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
struct phy_device *phydev,
int speed, int duplex,
......@@ -1435,8 +2238,19 @@ static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
struct mt7530_priv *priv = ds->priv;
u32 mcr;
mt753x_mac_pcs_link_up(ds, port, mode, interface, speed, duplex);
mcr = PMCR_RX_EN | PMCR_TX_EN | PMCR_FORCE_LNK;
/* MT753x MAC works in 1G full duplex mode for all up-clocked
* variants.
*/
if (interface == PHY_INTERFACE_MODE_TRGMII ||
(phy_interface_mode_is_8023z(interface))) {
speed = SPEED_1000;
duplex = DUPLEX_FULL;
}
switch (speed) {
case SPEED_1000:
mcr |= PMCR_FORCE_SPEED_1000;
......@@ -1456,66 +2270,102 @@ static void mt7530_phylink_mac_link_up(struct dsa_switch *ds, int port,
mt7530_set(priv, MT7530_PMCR_P(port), mcr);
}
static void mt7530_phylink_validate(struct dsa_switch *ds, int port,
unsigned long *supported,
struct phylink_link_state *state)
static int
mt7531_cpu_port_config(struct dsa_switch *ds, int port)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
struct mt7530_priv *priv = ds->priv;
phy_interface_t interface;
int speed;
switch (port) {
case 0: /* Internal phy */
case 1:
case 2:
case 3:
case 4:
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != PHY_INTERFACE_MODE_GMII)
goto unsupported;
case 5:
if (mt7531_is_rgmii_port(priv, port))
interface = PHY_INTERFACE_MODE_RGMII;
else
interface = PHY_INTERFACE_MODE_2500BASEX;
priv->p5_interface = interface;
break;
case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
if (state->interface != PHY_INTERFACE_MODE_NA &&
!phy_interface_mode_is_rgmii(state->interface) &&
state->interface != PHY_INTERFACE_MODE_MII &&
state->interface != PHY_INTERFACE_MODE_GMII)
goto unsupported;
case 6:
interface = PHY_INTERFACE_MODE_2500BASEX;
mt7531_pad_setup(ds, interface);
priv->p6_interface = interface;
break;
case 6: /* 1st cpu port */
}
if (interface == PHY_INTERFACE_MODE_2500BASEX)
speed = SPEED_2500;
else
speed = SPEED_1000;
mt7531_mac_config(ds, port, MLO_AN_FIXED, interface);
mt7530_write(priv, MT7530_PMCR_P(port),
PMCR_CPU_PORT_SETTING(priv->id));
mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED, interface, NULL,
speed, DUPLEX_FULL, true, true);
return 0;
}
static void
mt7530_mac_port_validate(struct dsa_switch *ds, int port,
unsigned long *supported)
{
if (port == 5)
phylink_set(supported, 1000baseX_Full);
}
static void mt7531_mac_port_validate(struct dsa_switch *ds, int port,
unsigned long *supported)
{
struct mt7530_priv *priv = ds->priv;
mt7531_sgmii_validate(priv, port, supported);
}
static void
mt753x_phylink_validate(struct dsa_switch *ds, int port,
unsigned long *supported,
struct phylink_link_state *state)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
struct mt7530_priv *priv = ds->priv;
if (state->interface != PHY_INTERFACE_MODE_NA &&
state->interface != PHY_INTERFACE_MODE_RGMII &&
state->interface != PHY_INTERFACE_MODE_TRGMII)
goto unsupported;
break;
default:
dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
unsupported:
!mt753x_phy_mode_supported(ds, port, state)) {
linkmode_zero(supported);
return;
}
phylink_set_port_modes(mask);
phylink_set(mask, Autoneg);
if (state->interface == PHY_INTERFACE_MODE_TRGMII) {
phylink_set(mask, 1000baseT_Full);
} else {
if (state->interface != PHY_INTERFACE_MODE_TRGMII ||
!phy_interface_mode_is_8023z(state->interface)) {
phylink_set(mask, 10baseT_Half);
phylink_set(mask, 10baseT_Full);
phylink_set(mask, 100baseT_Half);
phylink_set(mask, 100baseT_Full);
phylink_set(mask, Autoneg);
}
if (state->interface != PHY_INTERFACE_MODE_MII) {
/* This switch only supports 1G full-duplex. */
if (state->interface != PHY_INTERFACE_MODE_MII)
phylink_set(mask, 1000baseT_Full);
if (port == 5)
phylink_set(mask, 1000baseX_Full);
}
}
priv->info->mac_port_validate(ds, port, mask);
phylink_set(mask, Pause);
phylink_set(mask, Asym_Pause);
linkmode_and(supported, supported, mask);
linkmode_and(state->advertising, state->advertising, mask);
/* We can only operate at 2500BaseX or 1000BaseX. If requested
* to advertise both, only report advertising at 2500BaseX.
*/
phylink_helper_basex_speed(state);
}
static int
......@@ -1558,12 +2408,96 @@ mt7530_phylink_mac_link_state(struct dsa_switch *ds, int port,
return 1;
}
static int
mt7531_sgmii_pcs_get_state_an(struct mt7530_priv *priv, int port,
struct phylink_link_state *state)
{
u32 status, val;
u16 config_reg;
status = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
state->link = !!(status & MT7531_SGMII_LINK_STATUS);
if (state->interface == PHY_INTERFACE_MODE_SGMII &&
(status & MT7531_SGMII_AN_ENABLE)) {
val = mt7530_read(priv, MT7531_PCS_SPEED_ABILITY(port));
config_reg = val >> 16;
switch (config_reg & LPA_SGMII_SPD_MASK) {
case LPA_SGMII_1000:
state->speed = SPEED_1000;
break;
case LPA_SGMII_100:
state->speed = SPEED_100;
break;
case LPA_SGMII_10:
state->speed = SPEED_10;
break;
default:
dev_err(priv->dev, "invalid sgmii PHY speed\n");
state->link = false;
return -EINVAL;
}
if (config_reg & LPA_SGMII_FULL_DUPLEX)
state->duplex = DUPLEX_FULL;
else
state->duplex = DUPLEX_HALF;
}
return 0;
}
static int
mt7531_phylink_mac_link_state(struct dsa_switch *ds, int port,
struct phylink_link_state *state)
{
struct mt7530_priv *priv = ds->priv;
if (state->interface == PHY_INTERFACE_MODE_SGMII)
return mt7531_sgmii_pcs_get_state_an(priv, port, state);
return -EOPNOTSUPP;
}
static int
mt753x_phylink_mac_link_state(struct dsa_switch *ds, int port,
struct phylink_link_state *state)
{
struct mt7530_priv *priv = ds->priv;
return priv->info->mac_port_get_state(ds, port, state);
}
static int
mt753x_setup(struct dsa_switch *ds)
{
struct mt7530_priv *priv = ds->priv;
return priv->info->sw_setup(ds);
}
static int
mt753x_phy_read(struct dsa_switch *ds, int port, int regnum)
{
struct mt7530_priv *priv = ds->priv;
return priv->info->phy_read(ds, port, regnum);
}
static int
mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
{
struct mt7530_priv *priv = ds->priv;
return priv->info->phy_write(ds, port, regnum, val);
}
static const struct dsa_switch_ops mt7530_switch_ops = {
.get_tag_protocol = mtk_get_tag_protocol,
.setup = mt7530_setup,
.setup = mt753x_setup,
.get_strings = mt7530_get_strings,
.phy_read = mt7530_phy_read,
.phy_write = mt7530_phy_write,
.phy_read = mt753x_phy_read,
.phy_write = mt753x_phy_write,
.get_ethtool_stats = mt7530_get_ethtool_stats,
.get_sset_count = mt7530_get_sset_count,
.port_enable = mt7530_port_enable,
......@@ -1578,18 +2512,59 @@ static const struct dsa_switch_ops mt7530_switch_ops = {
.port_vlan_prepare = mt7530_port_vlan_prepare,
.port_vlan_add = mt7530_port_vlan_add,
.port_vlan_del = mt7530_port_vlan_del,
.port_mirror_add = mt7530_port_mirror_add,
.port_mirror_del = mt7530_port_mirror_del,
.phylink_validate = mt7530_phylink_validate,
.phylink_mac_link_state = mt7530_phylink_mac_link_state,
.phylink_mac_config = mt7530_phylink_mac_config,
.phylink_mac_link_down = mt7530_phylink_mac_link_down,
.phylink_mac_link_up = mt7530_phylink_mac_link_up,
.port_mirror_add = mt753x_port_mirror_add,
.port_mirror_del = mt753x_port_mirror_del,
.phylink_validate = mt753x_phylink_validate,
.phylink_mac_link_state = mt753x_phylink_mac_link_state,
.phylink_mac_config = mt753x_phylink_mac_config,
.phylink_mac_an_restart = mt753x_phylink_mac_an_restart,
.phylink_mac_link_down = mt753x_phylink_mac_link_down,
.phylink_mac_link_up = mt753x_phylink_mac_link_up,
};
static const struct mt753x_info mt753x_table[] = {
[ID_MT7621] = {
.id = ID_MT7621,
.sw_setup = mt7530_setup,
.phy_read = mt7530_phy_read,
.phy_write = mt7530_phy_write,
.pad_setup = mt7530_pad_clk_setup,
.phy_mode_supported = mt7530_phy_mode_supported,
.mac_port_validate = mt7530_mac_port_validate,
.mac_port_get_state = mt7530_phylink_mac_link_state,
.mac_port_config = mt7530_mac_config,
},
[ID_MT7530] = {
.id = ID_MT7530,
.sw_setup = mt7530_setup,
.phy_read = mt7530_phy_read,
.phy_write = mt7530_phy_write,
.pad_setup = mt7530_pad_clk_setup,
.phy_mode_supported = mt7530_phy_mode_supported,
.mac_port_validate = mt7530_mac_port_validate,
.mac_port_get_state = mt7530_phylink_mac_link_state,
.mac_port_config = mt7530_mac_config,
},
[ID_MT7531] = {
.id = ID_MT7531,
.sw_setup = mt7531_setup,
.phy_read = mt7531_ind_phy_read,
.phy_write = mt7531_ind_phy_write,
.pad_setup = mt7531_pad_setup,
.cpu_port_config = mt7531_cpu_port_config,
.phy_mode_supported = mt7531_phy_mode_supported,
.mac_port_validate = mt7531_mac_port_validate,
.mac_port_get_state = mt7531_phylink_mac_link_state,
.mac_port_config = mt7531_mac_config,
.mac_pcs_an_restart = mt7531_sgmii_restart_an,
.mac_pcs_link_up = mt7531_sgmii_link_up_force,
},
};
static const struct of_device_id mt7530_of_match[] = {
{ .compatible = "mediatek,mt7621", .data = (void *)ID_MT7621, },
{ .compatible = "mediatek,mt7530", .data = (void *)ID_MT7530, },
{ .compatible = "mediatek,mt7621", .data = &mt753x_table[ID_MT7621], },
{ .compatible = "mediatek,mt7530", .data = &mt753x_table[ID_MT7530], },
{ .compatible = "mediatek,mt7531", .data = &mt753x_table[ID_MT7531], },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mt7530_of_match);
......@@ -1630,8 +2605,21 @@ mt7530_probe(struct mdio_device *mdiodev)
/* Get the hardware identifier from the devicetree node.
* We will need it for some of the clock and regulator setup.
*/
priv->id = (unsigned int)(unsigned long)
of_device_get_match_data(&mdiodev->dev);
priv->info = of_device_get_match_data(&mdiodev->dev);
if (!priv->info)
return -EINVAL;
/* Sanity check if these required device operations are filled
* properly.
*/
if (!priv->info->sw_setup || !priv->info->pad_setup ||
!priv->info->phy_read || !priv->info->phy_write ||
!priv->info->phy_mode_supported ||
!priv->info->mac_port_validate ||
!priv->info->mac_port_get_state || !priv->info->mac_port_config)
return -EINVAL;
priv->id = priv->info->id;
if (priv->id == ID_MT7530) {
priv->core_pwr = devm_regulator_get(&mdiodev->dev, "core");
......
......@@ -11,9 +11,10 @@
#define MT7530_NUM_FDB_RECORDS 2048
#define MT7530_ALL_MEMBERS 0xff
enum {
enum mt753x_id {
ID_MT7530 = 0,
ID_MT7621 = 1,
ID_MT7531 = 2,
};
#define NUM_TRGMII_CTRL 5
......@@ -41,6 +42,33 @@ enum {
#define MIRROR_PORT(x) ((x) & 0x7)
#define MIRROR_MASK 0x7
/* Registers for CPU forward control */
#define MT7531_CFC 0x4
#define MT7531_MIRROR_EN BIT(19)
#define MT7531_MIRROR_MASK (MIRROR_MASK << 16)
#define MT7531_MIRROR_PORT_GET(x) (((x) >> 16) & MIRROR_MASK)
#define MT7531_MIRROR_PORT_SET(x) (((x) & MIRROR_MASK) << 16)
#define MT7531_CPU_PMAP_MASK GENMASK(7, 0)
#define MT753X_MIRROR_REG(id) (((id) == ID_MT7531) ? \
MT7531_CFC : MT7530_MFC)
#define MT753X_MIRROR_EN(id) (((id) == ID_MT7531) ? \
MT7531_MIRROR_EN : MIRROR_EN)
#define MT753X_MIRROR_MASK(id) (((id) == ID_MT7531) ? \
MT7531_MIRROR_MASK : MIRROR_MASK)
/* Registers for BPDU and PAE frame control*/
#define MT753X_BPC 0x24
#define MT753X_BPDU_PORT_FW_MASK GENMASK(2, 0)
enum mt753x_bpdu_port_fw {
MT753X_BPDU_FOLLOW_MFC,
MT753X_BPDU_CPU_EXCLUDE = 4,
MT753X_BPDU_CPU_INCLUDE = 5,
MT753X_BPDU_CPU_ONLY = 6,
MT753X_BPDU_DROP = 7,
};
/* Registers for address table access */
#define MT7530_ATA1 0x74
#define STATIC_EMP 0
......@@ -220,10 +248,30 @@ enum mt7530_vlan_port_attr {
#define PMCR_FORCE_LNK BIT(0)
#define PMCR_SPEED_MASK (PMCR_FORCE_SPEED_100 | \
PMCR_FORCE_SPEED_1000)
#define MT7531_FORCE_LNK BIT(31)
#define MT7531_FORCE_SPD BIT(30)
#define MT7531_FORCE_DPX BIT(29)
#define MT7531_FORCE_RX_FC BIT(28)
#define MT7531_FORCE_TX_FC BIT(27)
#define MT7531_FORCE_MODE (MT7531_FORCE_LNK | \
MT7531_FORCE_SPD | \
MT7531_FORCE_DPX | \
MT7531_FORCE_RX_FC | \
MT7531_FORCE_TX_FC)
#define PMCR_FORCE_MODE_ID(id) (((id) == ID_MT7531) ? \
MT7531_FORCE_MODE : \
PMCR_FORCE_MODE)
#define PMCR_LINK_SETTINGS_MASK (PMCR_TX_EN | PMCR_FORCE_SPEED_1000 | \
PMCR_RX_EN | PMCR_FORCE_SPEED_100 | \
PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
PMCR_FORCE_FDX | PMCR_FORCE_LNK)
#define PMCR_CPU_PORT_SETTING(id) (PMCR_FORCE_MODE_ID((id)) | \
PMCR_IFG_XMIT(1) | PMCR_MAC_MODE | \
PMCR_BACKOFF_EN | PMCR_BACKPR_EN | \
PMCR_TX_EN | PMCR_RX_EN | \
PMCR_TX_FC_EN | PMCR_RX_FC_EN | \
PMCR_FORCE_SPEED_1000 | \
PMCR_FORCE_FDX | PMCR_FORCE_LNK)
#define MT7530_PMSR_P(x) (0x3008 + (x) * 0x100)
#define PMSR_EEE1G BIT(7)
......@@ -237,6 +285,10 @@ enum mt7530_vlan_port_attr {
#define PMSR_DPX BIT(1)
#define PMSR_LINK BIT(0)
/* Register for port debug count */
#define MT7531_DBG_CNT(x) (0x3018 + (x) * 0x100)
#define MT7531_DIS_CLR BIT(31)
/* Register for MIB */
#define MT7530_PORT_MIB_COUNTER(x) (0x4000 + (x) * 0x100)
#define MT7530_MIB_CCR 0x4fe0
......@@ -254,12 +306,118 @@ enum mt7530_vlan_port_attr {
CCR_RX_OCT_CNT_BAD | \
CCR_TX_OCT_CNT_GOOD | \
CCR_TX_OCT_CNT_BAD)
/* MT7531 SGMII register group */
#define MT7531_SGMII_REG_BASE 0x5000
#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \
((p) - 5) * 0x1000 + (r))
/* Register forSGMII PCS_CONTROL_1 */
#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(p, 0x00)
#define MT7531_SGMII_LINK_STATUS BIT(18)
#define MT7531_SGMII_AN_ENABLE BIT(12)
#define MT7531_SGMII_AN_RESTART BIT(9)
/* Register for SGMII PCS_SPPED_ABILITY */
#define MT7531_PCS_SPEED_ABILITY(p) MT7531_SGMII_REG(p, 0x08)
#define MT7531_SGMII_TX_CONFIG_MASK GENMASK(15, 0)
#define MT7531_SGMII_TX_CONFIG BIT(0)
/* Register for SGMII_MODE */
#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(p, 0x20)
#define MT7531_SGMII_REMOTE_FAULT_DIS BIT(8)
#define MT7531_SGMII_IF_MODE_MASK GENMASK(5, 1)
#define MT7531_SGMII_FORCE_DUPLEX BIT(4)
#define MT7531_SGMII_FORCE_SPEED_MASK GENMASK(3, 2)
#define MT7531_SGMII_FORCE_SPEED_1000 BIT(3)
#define MT7531_SGMII_FORCE_SPEED_100 BIT(2)
#define MT7531_SGMII_FORCE_SPEED_10 0
#define MT7531_SGMII_SPEED_DUPLEX_AN BIT(1)
enum mt7531_sgmii_force_duplex {
MT7531_SGMII_FORCE_FULL_DUPLEX = 0,
MT7531_SGMII_FORCE_HALF_DUPLEX = 0x10,
};
/* Fields of QPHY_PWR_STATE_CTRL */
#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(p, 0xe8)
#define MT7531_SGMII_PHYA_PWD BIT(4)
/* Values of SGMII SPEED */
#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(p, 0x128)
#define MT7531_RG_TPHY_SPEED_MASK (BIT(2) | BIT(3))
#define MT7531_RG_TPHY_SPEED_1_25G 0x0
#define MT7531_RG_TPHY_SPEED_3_125G BIT(2)
/* Register for system reset */
#define MT7530_SYS_CTRL 0x7000
#define SYS_CTRL_PHY_RST BIT(2)
#define SYS_CTRL_SW_RST BIT(1)
#define SYS_CTRL_REG_RST BIT(0)
/* Register for PHY Indirect Access Control */
#define MT7531_PHY_IAC 0x701C
#define MT7531_PHY_ACS_ST BIT(31)
#define MT7531_MDIO_REG_ADDR_MASK (0x1f << 25)
#define MT7531_MDIO_PHY_ADDR_MASK (0x1f << 20)
#define MT7531_MDIO_CMD_MASK (0x3 << 18)
#define MT7531_MDIO_ST_MASK (0x3 << 16)
#define MT7531_MDIO_RW_DATA_MASK (0xffff)
#define MT7531_MDIO_REG_ADDR(x) (((x) & 0x1f) << 25)
#define MT7531_MDIO_DEV_ADDR(x) (((x) & 0x1f) << 25)
#define MT7531_MDIO_PHY_ADDR(x) (((x) & 0x1f) << 20)
#define MT7531_MDIO_CMD(x) (((x) & 0x3) << 18)
#define MT7531_MDIO_ST(x) (((x) & 0x3) << 16)
enum mt7531_phy_iac_cmd {
MT7531_MDIO_ADDR = 0,
MT7531_MDIO_WRITE = 1,
MT7531_MDIO_READ = 2,
MT7531_MDIO_READ_CL45 = 3,
};
/* MDIO_ST: MDIO start field */
enum mt7531_mdio_st {
MT7531_MDIO_ST_CL45 = 0,
MT7531_MDIO_ST_CL22 = 1,
};
#define MT7531_MDIO_CL22_READ (MT7531_MDIO_ST(MT7531_MDIO_ST_CL22) | \
MT7531_MDIO_CMD(MT7531_MDIO_READ))
#define MT7531_MDIO_CL22_WRITE (MT7531_MDIO_ST(MT7531_MDIO_ST_CL22) | \
MT7531_MDIO_CMD(MT7531_MDIO_WRITE))
#define MT7531_MDIO_CL45_ADDR (MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \
MT7531_MDIO_CMD(MT7531_MDIO_ADDR))
#define MT7531_MDIO_CL45_READ (MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \
MT7531_MDIO_CMD(MT7531_MDIO_READ))
#define MT7531_MDIO_CL45_WRITE (MT7531_MDIO_ST(MT7531_MDIO_ST_CL45) | \
MT7531_MDIO_CMD(MT7531_MDIO_WRITE))
/* Register for RGMII clock phase */
#define MT7531_CLKGEN_CTRL 0x7500
#define CLK_SKEW_OUT(x) (((x) & 0x3) << 8)
#define CLK_SKEW_OUT_MASK GENMASK(9, 8)
#define CLK_SKEW_IN(x) (((x) & 0x3) << 6)
#define CLK_SKEW_IN_MASK GENMASK(7, 6)
#define RXCLK_NO_DELAY BIT(5)
#define TXCLK_NO_REVERSE BIT(4)
#define GP_MODE(x) (((x) & 0x3) << 1)
#define GP_MODE_MASK GENMASK(2, 1)
#define GP_CLK_EN BIT(0)
enum mt7531_gp_mode {
MT7531_GP_MODE_RGMII = 0,
MT7531_GP_MODE_MII = 1,
MT7531_GP_MODE_REV_MII = 2
};
enum mt7531_clk_skew {
MT7531_CLK_SKEW_NO_CHG = 0,
MT7531_CLK_SKEW_DLY_100PPS = 1,
MT7531_CLK_SKEW_DLY_200PPS = 2,
MT7531_CLK_SKEW_REVERSE = 3,
};
/* Register for hw trap status */
#define MT7530_HWTRAP 0x7800
#define HWTRAP_XTAL_MASK (BIT(10) | BIT(9))
......@@ -267,6 +425,16 @@ enum mt7530_vlan_port_attr {
#define HWTRAP_XTAL_40MHZ (BIT(10))
#define HWTRAP_XTAL_20MHZ (BIT(9))
#define MT7531_HWTRAP 0x7800
#define HWTRAP_XTAL_FSEL_MASK BIT(7)
#define HWTRAP_XTAL_FSEL_25MHZ BIT(7)
#define HWTRAP_XTAL_FSEL_40MHZ 0
/* Unique fields of (M)HWSTRAP for MT7531 */
#define XTAL_FSEL_S 7
#define XTAL_FSEL_M BIT(7)
#define PHY_EN BIT(6)
#define CHG_STRAP BIT(8)
/* Register for hw trap modification */
#define MT7530_MHWTRAP 0x7804
#define MHWTRAP_PHY0_SEL BIT(20)
......@@ -281,14 +449,37 @@ enum mt7530_vlan_port_attr {
#define MT7530_TOP_SIG_CTRL 0x7808
#define TOP_SIG_CTRL_NORMAL (BIT(17) | BIT(16))
#define MT7531_TOP_SIG_SR 0x780c
#define PAD_DUAL_SGMII_EN BIT(1)
#define PAD_MCM_SMI_EN BIT(0)
#define MT7530_IO_DRV_CR 0x7810
#define P5_IO_CLK_DRV(x) ((x) & 0x3)
#define P5_IO_DATA_DRV(x) (((x) & 0x3) << 4)
#define MT7531_CHIP_REV 0x781C
#define MT7531_PLLGP_EN 0x7820
#define EN_COREPLL BIT(2)
#define SW_CLKSW BIT(1)
#define SW_PLLGP BIT(0)
#define MT7530_P6ECR 0x7830
#define P6_INTF_MODE_MASK 0x3
#define P6_INTF_MODE(x) ((x) & 0x3)
#define MT7531_PLLGP_CR0 0x78a8
#define RG_COREPLL_EN BIT(22)
#define RG_COREPLL_POSDIV_S 23
#define RG_COREPLL_POSDIV_M 0x3800000
#define RG_COREPLL_SDM_PCW_S 1
#define RG_COREPLL_SDM_PCW_M 0x3ffffe
#define RG_COREPLL_SDM_PCW_CHG BIT(0)
/* Registers for RGMII and SGMII PLL clock */
#define MT7531_ANA_PLLGP_CR2 0x78b0
#define MT7531_ANA_PLLGP_CR5 0x78bc
/* Registers for TRGMII on the both side */
#define MT7530_TRGMII_RCK_CTRL 0x7a00
#define RX_RST BIT(31)
......@@ -327,10 +518,25 @@ enum mt7530_vlan_port_attr {
#define MT7530_P5RGMIITXCR 0x7b04
#define CSR_RGMII_TXC_CFG(x) ((x) & 0x1f)
/* Registers for GPIO mode */
#define MT7531_GPIO_MODE0 0x7c0c
#define MT7531_GPIO0_MASK GENMASK(3, 0)
#define MT7531_GPIO0_INTERRUPT 1
#define MT7531_GPIO_MODE1 0x7c10
#define MT7531_GPIO11_RG_RXD2_MASK GENMASK(15, 12)
#define MT7531_EXT_P_MDC_11 (2 << 12)
#define MT7531_GPIO12_RG_RXD3_MASK GENMASK(19, 16)
#define MT7531_EXT_P_MDIO_12 (2 << 16)
#define MT7530_CREV 0x7ffc
#define CHIP_NAME_SHIFT 16
#define MT7530_ID 0x7530
#define MT7531_CREV 0x781C
#define CHIP_REV_M 0x0f
#define MT7531_ID 0x7531
/* Registers for core PLL access through mmd indirect */
#define CORE_PLL_GROUP2 0x401
#define RG_SYSPLL_EN_NORMAL BIT(15)
......@@ -347,6 +553,10 @@ enum mt7530_vlan_port_attr {
#define RG_SYSPLL_DDSFBK_EN BIT(12)
#define RG_SYSPLL_BIAS_EN BIT(11)
#define RG_SYSPLL_BIAS_LPF_EN BIT(10)
#define MT7531_PHY_PLL_OFF BIT(5)
#define MT7531_PHY_PLL_BYPASS_MODE BIT(4)
#define MT753X_CTRL_PHY_ADDR 0
#define CORE_PLL_GROUP5 0x404
#define RG_LCDDS_PCW_NCPO1(x) ((x) & 0xffff)
......@@ -425,6 +635,7 @@ enum p5_interface_select {
P5_INTF_SEL_PHY_P0,
P5_INTF_SEL_PHY_P4,
P5_INTF_SEL_GMAC5,
P5_INTF_SEL_GMAC5_SGMII,
};
static const char *p5_intf_modes(unsigned int p5_interface)
......@@ -438,11 +649,56 @@ static const char *p5_intf_modes(unsigned int p5_interface)
return "PHY P4";
case P5_INTF_SEL_GMAC5:
return "GMAC5";
case P5_INTF_SEL_GMAC5_SGMII:
return "GMAC5_SGMII";
default:
return "unknown";
}
}
/* struct mt753x_info - This is the main data structure for holding the specific
* part for each supported device
* @sw_setup: Holding the handler to a device initialization
* @phy_read: Holding the way reading PHY port
* @phy_write: Holding the way writing PHY port
* @pad_setup: Holding the way setting up the bus pad for a certain
* MAC port
* @phy_mode_supported: Check if the PHY type is being supported on a certain
* port
* @mac_port_validate: Holding the way to set addition validate type for a
* certan MAC port
* @mac_port_get_state: Holding the way getting the MAC/PCS state for a certain
* MAC port
* @mac_port_config: Holding the way setting up the PHY attribute to a
* certain MAC port
* @mac_pcs_an_restart Holding the way restarting PCS autonegotiation for a
* certain MAC port
* @mac_pcs_link_up: Holding the way setting up the PHY attribute to the pcs
* of the certain MAC port
*/
struct mt753x_info {
enum mt753x_id id;
int (*sw_setup)(struct dsa_switch *ds);
int (*phy_read)(struct dsa_switch *ds, int port, int regnum);
int (*phy_write)(struct dsa_switch *ds, int port, int regnum, u16 val);
int (*pad_setup)(struct dsa_switch *ds, phy_interface_t interface);
int (*cpu_port_config)(struct dsa_switch *ds, int port);
bool (*phy_mode_supported)(struct dsa_switch *ds, int port,
const struct phylink_link_state *state);
void (*mac_port_validate)(struct dsa_switch *ds, int port,
unsigned long *supported);
int (*mac_port_get_state)(struct dsa_switch *ds, int port,
struct phylink_link_state *state);
int (*mac_port_config)(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface);
void (*mac_pcs_an_restart)(struct dsa_switch *ds, int port);
void (*mac_pcs_link_up)(struct dsa_switch *ds, int port,
unsigned int mode, phy_interface_t interface,
int speed, int duplex);
};
/* struct mt7530_priv - This is the main data structure for holding the state
* of the driver
* @dev: The device pointer
......@@ -468,6 +724,7 @@ struct mt7530_priv {
struct regulator *core_pwr;
struct regulator *io_pwr;
struct gpio_desc *reset;
const struct mt753x_info *info;
unsigned int id;
bool mcm;
phy_interface_t p6_interface;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment