Skip to content

Commit

Permalink
drivers/net/ksz9477: Handle Silicon Erratas
Browse files Browse the repository at this point in the history
Improve PHY receive performance
Improve transmit waveform amplitude
Disable EEE for ports 1-5
Fix supply current values

Signed-off-by: Jani Paalijarvi <[email protected]>
  • Loading branch information
jpaali committed Aug 30, 2024
1 parent a31689c commit d44762f
Show file tree
Hide file tree
Showing 2 changed files with 281 additions and 2 deletions.
265 changes: 263 additions & 2 deletions drivers/net/ksz9477.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
* Pre-processor Definitions
****************************************************************************/

#define ERRATA_MOD1_REGS 7
#define ERRATA_MOD9_REGS 13

/****************************************************************************
* Private Data
****************************************************************************/
Expand All @@ -56,6 +59,13 @@ static uint8_t g_port_mirror_config[7] =

#endif

struct errata
{
uint8_t dev;
uint16_t reg;
uint16_t value;
};

/****************************************************************************
* Private Functions
****************************************************************************/
Expand Down Expand Up @@ -124,7 +134,6 @@ static int ksz9477_reg_write32(uint16_t reg, uint32_t data)
return ksz9477_write(&write_msg);
}

#if 0 /* Enable when needed */
static int ksz9477_reg_write16(uint16_t reg, uint16_t data)
{
int ret;
Expand Down Expand Up @@ -175,7 +184,6 @@ static int ksz9477_reg_write16(uint16_t reg, uint16_t data)

return ksz9477_write(&write_msg);
}
#endif

static int ksz9477_sgmii_read_indirect(uint32_t address, uint16_t *value,
unsigned len)
Expand Down Expand Up @@ -211,6 +219,231 @@ static int ksz9477_sgmii_write_indirect(uint32_t address, uint16_t *value,
return ret;
}

static int ksz9477_mmd_read_indirect(ksz9477_port_t port, uint16_t dev,
uint16_t reg, uint16_t *value,
uint16_t len)
{
int ret;

/* Set up MMD device address */

ret = ksz9477_reg_write16(KSZ9477_PHY_MMD_SETUP(port),
KSZ9477_MMD_OP_MODE_REGISTER | dev);
if (ret != OK)
{
goto out;
}

/* Select register */

ret = ksz9477_reg_write16(KSZ9477_PHY_MMD_DATA(port), reg);
if (ret != OK)
{
goto out;
}

/* Set MMD operation mode */

if (len <= 1)
{
/* no post increment */

ret = ksz9477_reg_write16(KSZ9477_PHY_MMD_SETUP(port),
KSZ9477_MMD_OP_MODE_NO_INCREMENT | dev);
if (ret != OK)
{
goto out;
}
}
else
{
/* post increment on reads and writes */

ret = ksz9477_reg_write16(KSZ9477_PHY_MMD_SETUP(port),
KSZ9477_MMD_OP_MODE_RW_INCREMENT | dev);
if (ret != OK)
{
goto out;
}
}

/* Read value */

while (len-- && ret == OK)
{
ret = ksz9477_reg_read16(KSZ9477_PHY_MMD_DATA(port), value);
value++;
}

out:

return ret;
}

static int ksz9477_mmd_write_indirect(ksz9477_port_t port, uint8_t dev,
uint16_t reg, uint16_t *value,
uint16_t len)
{
int ret;

/* Set up MMD device address */

ret = ksz9477_reg_write16(KSZ9477_PHY_MMD_SETUP(port),
KSZ9477_MMD_OP_MODE_REGISTER | dev);
if (ret != OK)
{
goto out;
}

/* Select register */

ret = ksz9477_reg_write16(KSZ9477_PHY_MMD_DATA(port), reg);
if (ret != OK)
{
goto out;
}

/* Set MMD operation mode */

if (len <= 1)
{
/* no post increment */

ret = ksz9477_reg_write16(KSZ9477_PHY_MMD_SETUP(port),
KSZ9477_MMD_OP_MODE_NO_INCREMENT | dev);
if (ret != OK)
{
goto out;
}
}
else
{
/* post increment on reads and writes */

ret = ksz9477_reg_write16(KSZ9477_PHY_MMD_SETUP(port),
KSZ9477_MMD_OP_MODE_RW_INCREMENT | dev);
if (ret != OK)
{
goto out;
}
}

/* Write value */

while (len-- && ret == OK)
{
ret = ksz9477_reg_write16(KSZ9477_PHY_MMD_DATA(port), *value);
value++;
}

out:

return ret;
}

static int ksz9477_handle_erratas(ksz9477_port_t port)
{
int ret;
uint16_t regval16;
int j;
struct errata mod1[ERRATA_MOD1_REGS];
struct errata mod9[ERRATA_MOD9_REGS];

/* First turn off autoneg */

ret = ksz9477_reg_write16(KSZ9477_PHY_CONTROL(port), 0x2100);

if (ret != OK)
{
nerr("PHY Control register write failure, ret %d\n", ret);
return ret ? ret : -EINVAL;
}

/* Module 1: Improve PHY receive performance */

mod1[0].dev = KSZ9477_MMD_DEV_SIGNAL_QUALITY;
mod1[0].reg = 0x6f;
mod1[0].value = 0xdd0b;
mod1[1].dev = KSZ9477_MMD_DEV_SIGNAL_QUALITY;
mod1[1].reg = 0x8f;
mod1[1].value = 0x6032;
mod1[2].dev = KSZ9477_MMD_DEV_SIGNAL_QUALITY;
mod1[2].reg = 0x9d;
mod1[2].value = 0x248c;
mod1[3].dev = KSZ9477_MMD_DEV_SIGNAL_QUALITY;
mod1[3].reg = 0x75;
mod1[3].value = 0x0060;
mod1[4].dev = KSZ9477_MMD_DEV_SIGNAL_QUALITY;
mod1[4].reg = 0xd3;
mod1[4].value = 0x7777;
mod1[5].dev = KSZ9477_MMD_DEV_QUIET_WIRE;
mod1[5].reg = 0x06;
mod1[5].value = 0x3008;
mod1[6].dev = KSZ9477_MMD_DEV_QUIET_WIRE;
mod1[6].reg = 0x08;
mod1[6].value = 0x2001;

for (j = 0; ret == OK && j < ERRATA_MOD1_REGS; j++)
{
ret = ksz9477_mmd_write_indirect(port, mod1[j].dev, mod1[j].reg,
&(mod1[j].value), 1);
}

/* Module 2: Improve transmit waveform amplitude */

regval16 = 0x00d0;
ret = ksz9477_mmd_write_indirect(port, KSZ9477_MMD_DEV_QUIET_WIRE,
0x4, &regval16, 1);

/* Module 9: Set various registers to get correct supply current values */

mod9[0].reg = 0x13;
mod9[0].value = 0x6eff;
mod9[1].reg = 0x14;
mod9[1].value = 0xe6ff;
mod9[2].reg = 0x15;
mod9[2].value = 0x6eff;
mod9[3].reg = 0x16;
mod9[3].value = 0xe6ff;
mod9[4].reg = 0x17;
mod9[4].value = 0x00ff;
mod9[5].reg = 0x18;
mod9[5].value = 0x43ff;
mod9[6].reg = 0x19;
mod9[6].value = 0xC3ff;
mod9[7].reg = 0x1a;
mod9[7].value = 0x6fff;
mod9[8].reg = 0x1b;
mod9[8].value = 0x07ff;
mod9[9].reg = 0x1c;
mod9[9].value = 0x0fff;
mod9[10].reg = 0x1d;
mod9[10].value = 0xe7ff;
mod9[11].reg = 0x1e;
mod9[11].value = 0xefff;
mod9[12].reg = 0x20;
mod9[12].value = 0xeeee;

for (j = 0; ret == OK && j < ERRATA_MOD9_REGS; j++)
{
ret = ksz9477_mmd_write_indirect(port, KSZ9477_MMD_DEV_QUIET_WIRE,
mod9[j].reg, &(mod9[j].value), 1);
}

/* Turn on autoneg */

ret = ksz9477_reg_write16(KSZ9477_PHY_CONTROL(port), 0x1140);

if (ret != OK)
{
nerr("PHY Control register write failure, ret %d\n", ret);
return ret ? ret : -EINVAL;
}

return ret;
}


/****************************************************************************
* Public Functions
****************************************************************************/
Expand Down Expand Up @@ -375,6 +608,34 @@ int ksz9477_init(ksz9477_port_t master_port)
return ret ? ret : -EINVAL;
}

/* Check that indirect access to PHY MMD works.
* Default value of MMD EEE ADVERTISEMENT REGISTER is 0x6
*/

ret = ksz9477_mmd_read_indirect(KSZ9477_PORT_PHY1,
KSZ9477_MMD_DEV_EEE_ADVERTISEMENT,
0x3c, &regval16, 1);
if (ret != OK || regval16 != 0x6)
{
nerr("MMD access failure, ret %d\n", ret);
return ret ? ret : -EINVAL;
}

/* Handle KSZ9477S Silicon Erratas */

for (i = KSZ9477_PORT_PHY1; i <= KSZ9477_PORT_PHY5; i++)
{
ret = ksz9477_handle_erratas(i);
}

if (ret != OK)
{
nerr("Errata handling failure, ret %d\n", ret);
return ret ? ret : -EINVAL;
}

/* Set up SGMII port */

if (master_port == KSZ9477_PORT_SGMII)
{
/* Set the switch's SGMII port into "PHY" mode and enable link */
Expand Down
18 changes: 18 additions & 0 deletions drivers/net/ksz9477_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
#define KSZ9477_PHY_CONTROL(p) KSZ9477_PORT_REG(p, 0x100)
#define KSZ9477_PHY_STATUS(p) KSZ9477_PORT_REG(p, 0x102)

#define KSZ9477_PHY_MMD_SETUP(p) KSZ9477_PORT_REG(p, 0x11A)
#define KSZ9477_PHY_MMD_DATA(p) KSZ9477_PORT_REG(p, 0x11C)

/* Note! Unlike in data sheet, the indirect data register reads and
* writes must be done with 32-bit accesses and the address is
* 0x204
Expand Down Expand Up @@ -118,6 +121,21 @@
#define SGMII_AUTONEG_CONTROL_TC_MASTER (1 << 3)
#define SGMII_AUTONEG_CONTROL_LINK_STATUS (1 << 4)

/* MMD device addresses */

#define KSZ9477_MMD_DEV_SIGNAL_QUALITY 0x1
#define KSZ9477_MMD_DEV_LED_MODE 0x2
#define KSZ9477_MMD_DEV_EEE_ADVERTISEMENT 0x7
#define KSZ9477_MMD_DEV_QUIET_WIRE 0x1C

/* MMD operation modes */

#define KSZ9477_MMD_OP_MODE_SHIFT 14
#define KSZ9477_MMD_OP_MODE_REGISTER (0 << KSZ9477_MMD_OP_MODE_SHIFT)
#define KSZ9477_MMD_OP_MODE_NO_INCREMENT (1 << KSZ9477_MMD_OP_MODE_SHIFT)
#define KSZ9477_MMD_OP_MODE_RW_INCREMENT (2 << KSZ9477_MMD_OP_MODE_SHIFT)
#define KSZ9477_MMD_OP_MODE_W_INCREMENT (3 << KSZ9477_MMD_OP_MODE_SHIFT)

/* Port Mirroring Control Register */

#define KSZ9477_PORT_MIRROR_CONTROL(p) KSZ9477_PORT_REG(p, 0x800)
Expand Down

0 comments on commit d44762f

Please sign in to comment.