diff options
author | Rasmus Villemoes <linux@rasmusvillemoes.dk> | 2023-06-20 13:38:54 +0200 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2023-06-23 04:48:37 +0200 |
commit | 5c844d57aa7894154e49cf2fc648bfe2f1aefc1c (patch) | |
tree | 83857be9935b39fb3526e2ff6b756307c7054b48 | |
parent | net: dsa: microchip: add ksz_prmw32() helper (diff) | |
download | linux-5c844d57aa7894154e49cf2fc648bfe2f1aefc1c.tar.xz linux-5c844d57aa7894154e49cf2fc648bfe2f1aefc1c.zip |
net: dsa: microchip: fix writes to phy registers >= 0x10
According to the errata sheets for ksz9477 and ksz9567, writes to the
PHY registers 0x10-0x1f (i.e. those located at addresses 0xN120 to
0xN13f) must be done as a 32 bit write to the 4-byte aligned address
containing the register, hence requires a RMW in order not to change
the adjacent PHY register.
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20230620113855.733526-4-linux@rasmusvillemoes.dk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | drivers/net/dsa/microchip/ksz9477.c | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/drivers/net/dsa/microchip/ksz9477.c b/drivers/net/dsa/microchip/ksz9477.c index fc5157a10af5..83b7f2d5c1ea 100644 --- a/drivers/net/dsa/microchip/ksz9477.c +++ b/drivers/net/dsa/microchip/ksz9477.c @@ -329,11 +329,27 @@ int ksz9477_r_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 *data) int ksz9477_w_phy(struct ksz_device *dev, u16 addr, u16 reg, u16 val) { + u32 mask, val32; + /* No real PHY after this. */ if (!dev->info->internal_phy[addr]) return 0; - return ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); + if (reg < 0x10) + return ksz_pwrite16(dev, addr, 0x100 + (reg << 1), val); + + /* Errata: When using SPI, I2C, or in-band register access, + * writes to certain PHY registers should be performed as + * 32-bit writes instead of 16-bit writes. + */ + val32 = val; + mask = 0xffff; + if ((reg & 1) == 0) { + val32 <<= 16; + mask <<= 16; + } + reg &= ~1; + return ksz_prmw32(dev, addr, 0x100 + (reg << 1), mask, val32); } void ksz9477_cfg_port_member(struct ksz_device *dev, int port, u8 member) |