Commit 5b89aeae authored by Daniel Golle's avatar Daniel Golle Committed by Jakub Kicinski

net: dsa: mt7530: use external PCS driver

Implement regmap access wrappers, for now only to be used by the
pcs-mtk-lynxi driver.
Make use of this external PCS driver and drop the now reduntant
implementation in mt7530.c.
As a nice side effect the SGMII registers can now also more easily be
inspected for debugging via /sys/kernel/debug/regmap.
Tested-by: default avatarBjørn Mork <bjorn@mork.no>
Signed-off-by: default avatarDaniel Golle <daniel@makrotopia.org>
Tested-by: default avatarFrank Wunderlich <frank-w@public-files.de>
Reviewed-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 2a3ec7ae
......@@ -38,6 +38,7 @@ config NET_DSA_MT7530
tristate "MediaTek MT7530 and MT7531 Ethernet switch support"
select NET_DSA_TAG_MTK
select MEDIATEK_GE_PHY
select PCS_MTK_LYNXI
help
This enables support for the MediaTek MT7530 and MT7531 Ethernet
switch chips. Multi-chip module MT7530 in MT7621AT, MT7621DAT,
......
......@@ -14,6 +14,7 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/of_platform.h>
#include <linux/pcs/pcs-mtk-lynxi.h>
#include <linux/phylink.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
......@@ -2572,128 +2573,11 @@ static int mt7531_rgmii_setup(struct mt7530_priv *priv, u32 port,
return 0;
}
static void mt7531_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
phy_interface_t interface, int speed, int duplex)
{
struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
int port = pcs_to_mt753x_pcs(pcs)->port;
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.
*
* The speed check is unnecessary as the MAC capabilities apply
* this restriction. --rmk
*/
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_pcs_an_restart(struct phylink_pcs *pcs)
{
struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
int port = pcs_to_mt753x_pcs(pcs)->port;
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)
......@@ -2716,11 +2600,11 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
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:
return mt7531_sgmii_setup_mode_force(priv, port, interface);
/* handled in SGMII PCS driver */
return 0;
default:
return -EINVAL;
}
......@@ -2745,11 +2629,11 @@ mt753x_phylink_mac_select_pcs(struct dsa_switch *ds, int port,
switch (interface) {
case PHY_INTERFACE_MODE_TRGMII:
return &priv->pcs[port].pcs;
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
return &priv->pcs[port].pcs;
return priv->ports[port].sgmii_pcs;
default:
return NULL;
}
......@@ -2987,86 +2871,6 @@ static void mt7530_pcs_get_state(struct phylink_pcs *pcs,
state->pause |= MLO_PAUSE_TX;
}
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);
state->an_complete = !!(status & MT7531_SGMII_AN_COMPLETE);
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 void
mt7531_sgmii_pcs_get_state_inband(struct mt7530_priv *priv, int port,
struct phylink_link_state *state)
{
unsigned int val;
val = mt7530_read(priv, MT7531_PCS_CONTROL_1(port));
state->link = !!(val & MT7531_SGMII_LINK_STATUS);
if (!state->link)
return;
state->an_complete = state->link;
if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
state->speed = SPEED_2500;
else
state->speed = SPEED_1000;
state->duplex = DUPLEX_FULL;
state->pause = MLO_PAUSE_NONE;
}
static void mt7531_pcs_get_state(struct phylink_pcs *pcs,
struct phylink_link_state *state)
{
struct mt7530_priv *priv = pcs_to_mt753x_pcs(pcs)->priv;
int port = pcs_to_mt753x_pcs(pcs)->port;
if (state->interface == PHY_INTERFACE_MODE_SGMII) {
mt7531_sgmii_pcs_get_state_an(priv, port, state);
return;
} else if ((state->interface == PHY_INTERFACE_MODE_1000BASEX) ||
(state->interface == PHY_INTERFACE_MODE_2500BASEX)) {
mt7531_sgmii_pcs_get_state_inband(priv, port, state);
return;
}
state->link = false;
}
static int mt753x_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
phy_interface_t interface,
const unsigned long *advertising,
......@@ -3086,18 +2890,57 @@ static const struct phylink_pcs_ops mt7530_pcs_ops = {
.pcs_an_restart = mt7530_pcs_an_restart,
};
static const struct phylink_pcs_ops mt7531_pcs_ops = {
.pcs_validate = mt753x_pcs_validate,
.pcs_get_state = mt7531_pcs_get_state,
.pcs_config = mt753x_pcs_config,
.pcs_an_restart = mt7531_pcs_an_restart,
.pcs_link_up = mt7531_pcs_link_up,
static int mt7530_regmap_read(void *context, unsigned int reg, unsigned int *val)
{
struct mt7530_priv *priv = context;
*val = mt7530_read(priv, reg);
return 0;
};
static int mt7530_regmap_write(void *context, unsigned int reg, unsigned int val)
{
struct mt7530_priv *priv = context;
mt7530_write(priv, reg, val);
return 0;
};
static int mt7530_regmap_update_bits(void *context, unsigned int reg,
unsigned int mask, unsigned int val)
{
struct mt7530_priv *priv = context;
mt7530_rmw(priv, reg, mask, val);
return 0;
};
static const struct regmap_bus mt7531_regmap_bus = {
.reg_write = mt7530_regmap_write,
.reg_read = mt7530_regmap_read,
.reg_update_bits = mt7530_regmap_update_bits,
};
#define MT7531_PCS_REGMAP_CONFIG(_name, _reg_base) \
{ \
.name = _name, \
.reg_bits = 16, \
.val_bits = 32, \
.reg_stride = 4, \
.reg_base = _reg_base, \
.max_register = 0x17c, \
}
static const struct regmap_config mt7531_pcs_config[] = {
MT7531_PCS_REGMAP_CONFIG("port5", MT7531_SGMII_REG_BASE(5)),
MT7531_PCS_REGMAP_CONFIG("port6", MT7531_SGMII_REG_BASE(6)),
};
static int
mt753x_setup(struct dsa_switch *ds)
{
struct mt7530_priv *priv = ds->priv;
struct regmap *regmap;
int i, ret;
/* Initialise the PCS devices */
......@@ -3105,8 +2948,6 @@ mt753x_setup(struct dsa_switch *ds)
priv->pcs[i].pcs.ops = priv->info->pcs_ops;
priv->pcs[i].priv = priv;
priv->pcs[i].port = i;
if (mt753x_is_mac_port(i))
priv->pcs[i].pcs.poll = 1;
}
ret = priv->info->sw_setup(ds);
......@@ -3121,6 +2962,16 @@ mt753x_setup(struct dsa_switch *ds)
if (ret && priv->irq)
mt7530_free_irq_common(priv);
if (priv->id == ID_MT7531)
for (i = 0; i < 2; i++) {
regmap = devm_regmap_init(ds->dev,
&mt7531_regmap_bus, priv,
&mt7531_pcs_config[i]);
priv->ports[5 + i].sgmii_pcs =
mtk_pcs_lynxi_create(ds->dev, regmap,
MT7531_PHYA_CTRL_SIGNAL3, 0);
}
return ret;
}
......@@ -3216,7 +3067,7 @@ static const struct mt753x_info mt753x_table[] = {
},
[ID_MT7531] = {
.id = ID_MT7531,
.pcs_ops = &mt7531_pcs_ops,
.pcs_ops = &mt7530_pcs_ops,
.sw_setup = mt7531_setup,
.phy_read_c22 = mt7531_ind_c22_phy_read,
.phy_write_c22 = mt7531_ind_c22_phy_write,
......@@ -3326,7 +3177,7 @@ static void
mt7530_remove(struct mdio_device *mdiodev)
{
struct mt7530_priv *priv = dev_get_drvdata(&mdiodev->dev);
int ret = 0;
int ret = 0, i;
if (!priv)
return;
......@@ -3345,6 +3196,10 @@ mt7530_remove(struct mdio_device *mdiodev)
mt7530_free_irq(priv);
dsa_unregister_switch(priv->ds);
for (i = 0; i < 2; ++i)
mtk_pcs_lynxi_destroy(priv->ports[5 + i].sgmii_pcs);
mutex_destroy(&priv->reg_mutex);
}
......
......@@ -364,47 +364,8 @@ enum mt7530_vlan_port_acc_frm {
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)
#define MT7531_SGMII_AN_COMPLETE BIT(21)
/* 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)
#define MT7531_SGMII_REG_BASE(p) (0x5000 + ((p) - 5) * 0x1000)
#define MT7531_PHYA_CTRL_SIGNAL3 0x128
/* Register for system reset */
#define MT7530_SYS_CTRL 0x7000
......@@ -703,13 +664,13 @@ struct mt7530_fdb {
* @pm: The matrix used to show all connections with the port.
* @pvid: The VLAN specified is to be considered a PVID at ingress. Any
* untagged frames will be assigned to the related VLAN.
* @vlan_filtering: The flags indicating whether the port that can recognize
* VLAN-tagged frames.
* @sgmii_pcs: Pointer to PCS instance for SerDes ports
*/
struct mt7530_port {
bool enable;
u32 pm;
u16 pvid;
struct phylink_pcs *sgmii_pcs;
};
/* Port 5 interface select definitions */
......
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