Commit 27871359 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller

net: dsa: sja1105: register the PCS MDIO bus for SJA1110

On the SJA1110, the PCS of each SERDES-capable port is accessed through
a different memory window which is 0x100 bytes in size, denoted by
"pcs_base".

In each PCS register access window, the XPCS MMDs are accessed in an
indirect way: in pages/banks of up to 0x100 addresses each. Changing the
page/bank is done by writing to a special register at the end of the
access window.

The MDIO register map accessed indirectly through the indirect banked
method described above is similar to what SJA1105 has: upper 5 bits are
the MMD, lower 16 bits are the MDIO address within that MMD.

Since the PHY ID reported by the XPCS inside SJA1110 is also all zeroes
(like SJA1105), we need to trap those reads and return a fake PHY ID so
that the xpcs driver can apply some specific fixups for our integration.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3ad1d171
......@@ -69,6 +69,7 @@ struct sja1105_regs {
u64 stats[__MAX_SJA1105_STATS_AREA][SJA1105_MAX_NUM_PORTS];
u64 mdio_100base_tx;
u64 mdio_100base_t1;
u64 pcs_base[SJA1105_MAX_NUM_PORTS];
};
struct sja1105_mdio_private {
......@@ -303,6 +304,8 @@ int sja1105_mdiobus_register(struct dsa_switch *ds);
void sja1105_mdiobus_unregister(struct dsa_switch *ds);
int sja1105_pcs_mdio_read(struct mii_bus *bus, int phy, int reg);
int sja1105_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val);
int sja1110_pcs_mdio_read(struct mii_bus *bus, int phy, int reg);
int sja1110_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val);
/* From sja1105_devlink.c */
int sja1105_devlink_setup(struct dsa_switch *ds);
......
......@@ -5,6 +5,8 @@
#include <linux/of_mdio.h>
#include "sja1105.h"
#define SJA1110_PCS_BANK_REG SJA1110_SPI_ADDR(0x3fc)
int sja1105_pcs_mdio_read(struct mii_bus *bus, int phy, int reg)
{
struct sja1105_mdio_private *mdio_priv = bus->priv;
......@@ -56,6 +58,99 @@ int sja1105_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
return sja1105_xfer_u32(priv, SPI_WRITE, addr, &tmp, NULL);
}
int sja1110_pcs_mdio_read(struct mii_bus *bus, int phy, int reg)
{
struct sja1105_mdio_private *mdio_priv = bus->priv;
struct sja1105_private *priv = mdio_priv->priv;
const struct sja1105_regs *regs = priv->info->regs;
int offset, bank;
u64 addr;
u32 tmp;
u16 mmd;
int rc;
if (!(reg & MII_ADDR_C45))
return -EINVAL;
if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
return -ENODEV;
mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
addr = (mmd << 16) | (reg & GENMASK(15, 0));
if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID1)
return NXP_SJA1110_XPCS_ID >> 16;
if (mmd == MDIO_MMD_VEND2 && (reg & GENMASK(15, 0)) == MII_PHYSID2)
return NXP_SJA1110_XPCS_ID & GENMASK(15, 0);
bank = addr >> 8;
offset = addr & GENMASK(7, 0);
/* This addressing scheme reserves register 0xff for the bank address
* register, so that can never be addressed.
*/
if (WARN_ON(offset == 0xff))
return -ENODEV;
tmp = bank;
rc = sja1105_xfer_u32(priv, SPI_WRITE,
regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
&tmp, NULL);
if (rc < 0)
return rc;
rc = sja1105_xfer_u32(priv, SPI_READ, regs->pcs_base[phy] + offset,
&tmp, NULL);
if (rc < 0)
return rc;
return tmp & 0xffff;
}
int sja1110_pcs_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
{
struct sja1105_mdio_private *mdio_priv = bus->priv;
struct sja1105_private *priv = mdio_priv->priv;
const struct sja1105_regs *regs = priv->info->regs;
int offset, bank;
u64 addr;
u32 tmp;
u16 mmd;
int rc;
if (!(reg & MII_ADDR_C45))
return -EINVAL;
if (regs->pcs_base[phy] == SJA1105_RSV_ADDR)
return -ENODEV;
mmd = (reg >> MII_DEVADDR_C45_SHIFT) & 0x1f;
addr = (mmd << 16) | (reg & GENMASK(15, 0));
bank = addr >> 8;
offset = addr & GENMASK(7, 0);
/* This addressing scheme reserves register 0xff for the bank address
* register, so that can never be addressed.
*/
if (WARN_ON(offset == 0xff))
return -ENODEV;
tmp = bank;
rc = sja1105_xfer_u32(priv, SPI_WRITE,
regs->pcs_base[phy] + SJA1110_PCS_BANK_REG,
&tmp, NULL);
if (rc < 0)
return rc;
tmp = val;
return sja1105_xfer_u32(priv, SPI_WRITE, regs->pcs_base[phy] + offset,
&tmp, NULL);
}
enum sja1105_mdio_opcode {
SJA1105_C45_ADDR = 0,
SJA1105_C22 = 1,
......
......@@ -561,6 +561,9 @@ static struct sja1105_regs sja1110_regs = {
.ptpsyncts = SJA1110_SPI_ADDR(0x84),
.mdio_100base_tx = 0x1c2400,
.mdio_100base_t1 = 0x1c1000,
.pcs_base = {SJA1105_RSV_ADDR, 0x1c1400, 0x1c1800, 0x1c1c00, 0x1c2000,
SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR,
SJA1105_RSV_ADDR, SJA1105_RSV_ADDR, SJA1105_RSV_ADDR},
};
const struct sja1105_info sja1105e_info = {
......@@ -794,6 +797,8 @@ const struct sja1105_info sja1110a_info = {
.rxtstamp = sja1110_rxtstamp,
.txtstamp = sja1110_txtstamp,
.clocking_setup = sja1110_clocking_setup,
.pcs_mdio_read = sja1110_pcs_mdio_read,
.pcs_mdio_write = sja1110_pcs_mdio_write,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 4,
......@@ -843,6 +848,8 @@ const struct sja1105_info sja1110b_info = {
.rxtstamp = sja1110_rxtstamp,
.txtstamp = sja1110_txtstamp,
.clocking_setup = sja1110_clocking_setup,
.pcs_mdio_read = sja1110_pcs_mdio_read,
.pcs_mdio_write = sja1110_pcs_mdio_write,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 4,
......@@ -892,6 +899,8 @@ const struct sja1105_info sja1110c_info = {
.rxtstamp = sja1110_rxtstamp,
.txtstamp = sja1110_txtstamp,
.clocking_setup = sja1110_clocking_setup,
.pcs_mdio_read = sja1110_pcs_mdio_read,
.pcs_mdio_write = sja1110_pcs_mdio_write,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 4,
......@@ -941,6 +950,8 @@ const struct sja1105_info sja1110d_info = {
.rxtstamp = sja1110_rxtstamp,
.txtstamp = sja1110_txtstamp,
.clocking_setup = sja1110_clocking_setup,
.pcs_mdio_read = sja1110_pcs_mdio_read,
.pcs_mdio_write = sja1110_pcs_mdio_write,
.port_speed = {
[SJA1105_SPEED_AUTO] = 0,
[SJA1105_SPEED_10MBPS] = 4,
......
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