From 206112fa65790221ca3ebbc43092911bb8836a19 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Mon, 16 Dec 2024 12:19:53 +0500 Subject: [PATCH 1/5] net: renesas: rswitch: do not write to MPSM register at init time MPSM register is used to execute mdio bus transactions. There is no need to initialize it early. Signed-off-by: Nikita Yushchenko Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://patch.msgid.link/20241216071957.2587354-2-nikita.yoush@cogentembedded.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/renesas/rswitch.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 5fc8c94d1e4b..12efee9f75d8 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1166,7 +1166,6 @@ static void rswitch_etha_enable_mii(struct rswitch_etha *etha) { rswitch_modify(etha->addr, MPIC, MPIC_PSMCS_MASK | MPIC_PSMHT_MASK, MPIC_PSMCS(etha->psmcs) | MPIC_PSMHT(0x06)); - rswitch_modify(etha->addr, MPSM, 0, MPSM_MFF_C45); } static int rswitch_etha_hw_init(struct rswitch_etha *etha, const u8 *mac) From da75ba93e3383fc10af71e5029b5a57378a57576 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Mon, 16 Dec 2024 12:19:54 +0500 Subject: [PATCH 2/5] net: renesas: rswitch: use FIELD_PREP for remaining MPIC register fields Commit fb9e6039c325 ("net: renesas: rswitch: fix initial MPIC register setting") converted setting some MPIC fields to FIELD_PREP. To keep common style, do the same with mii bus related fields of the same register. Signed-off-by: Nikita Yushchenko Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://patch.msgid.link/20241216071957.2587354-3-nikita.yoush@cogentembedded.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/renesas/rswitch.c | 5 +++-- drivers/net/ethernet/renesas/rswitch.h | 10 ++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 12efee9f75d8..e1541a206687 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1164,8 +1164,9 @@ static void rswitch_rmac_setting(struct rswitch_etha *etha, const u8 *mac) static void rswitch_etha_enable_mii(struct rswitch_etha *etha) { - rswitch_modify(etha->addr, MPIC, MPIC_PSMCS_MASK | MPIC_PSMHT_MASK, - MPIC_PSMCS(etha->psmcs) | MPIC_PSMHT(0x06)); + rswitch_modify(etha->addr, MPIC, MPIC_PSMCS | MPIC_PSMHT, + FIELD_PREP(MPIC_PSMCS, etha->psmcs) | + FIELD_PREP(MPIC_PSMHT, 0x06)); } static int rswitch_etha_hw_init(struct rswitch_etha *etha, const u8 *mac) diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index 4b1489100330..78c0325cdf30 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -732,6 +732,8 @@ enum rswitch_etha_mode { #define MPIC_LSC_100M 1 #define MPIC_LSC_1G 2 #define MPIC_LSC_2_5G 3 +#define MPIC_PSMCS GENMASK(22, 16) +#define MPIC_PSMHT GENMASK(26, 24) #define MDIO_READ_C45 0x03 #define MDIO_WRITE_C45 0x01 @@ -747,14 +749,6 @@ enum rswitch_etha_mode { #define MMIS1_PRACS BIT(0) /* Read */ #define MMIS1_CLEAR_FLAGS 0xf -#define MPIC_PSMCS_SHIFT 16 -#define MPIC_PSMCS_MASK GENMASK(22, MPIC_PSMCS_SHIFT) -#define MPIC_PSMCS(val) ((val) << MPIC_PSMCS_SHIFT) - -#define MPIC_PSMHT_SHIFT 24 -#define MPIC_PSMHT_MASK GENMASK(26, MPIC_PSMHT_SHIFT) -#define MPIC_PSMHT(val) ((val) << MPIC_PSMHT_SHIFT) - #define MLVC_PLV BIT(16) /* GWCA */ From 1ced1b8cacf396d6ff979f594ba40ace42087797 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Mon, 16 Dec 2024 12:19:55 +0500 Subject: [PATCH 3/5] net: renesas: rswitch: align mdio C45 operations with datasheet Per rswitch datasheet, software can know that mdio operation completed either by polling MPSM.PSME bit, or via interrupt. Instead, the driver currently polls for interrupt status bit. Although this still provides correct result, it requires additional register operations to clean the interrupt status bits, and generally looks wrong. Fix it to poll MPSM.PSME bit, as the datasheet suggests. Signed-off-by: Nikita Yushchenko Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://patch.msgid.link/20241216071957.2587354-4-nikita.yoush@cogentembedded.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/renesas/rswitch.c | 12 +++--------- drivers/net/ethernet/renesas/rswitch.h | 6 ------ 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index e1541a206687..6e3f162ae3b3 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1205,32 +1205,26 @@ static int rswitch_etha_set_access(struct rswitch_etha *etha, bool read, if (devad == 0xffffffff) return -ENODEV; - writel(MMIS1_CLEAR_FLAGS, etha->addr + MMIS1); - val = MPSM_PSME | MPSM_MFF_C45; iowrite32((regad << 16) | (devad << 8) | (phyad << 3) | val, etha->addr + MPSM); - ret = rswitch_reg_wait(etha->addr, MMIS1, MMIS1_PAACS, MMIS1_PAACS); + ret = rswitch_reg_wait(etha->addr, MPSM, MPSM_PSME, 0); if (ret) return ret; - rswitch_modify(etha->addr, MMIS1, MMIS1_PAACS, MMIS1_PAACS); - if (read) { writel((pop << 13) | (devad << 8) | (phyad << 3) | val, etha->addr + MPSM); - ret = rswitch_reg_wait(etha->addr, MMIS1, MMIS1_PRACS, MMIS1_PRACS); + ret = rswitch_reg_wait(etha->addr, MPSM, MPSM_PSME, 0); if (ret) return ret; ret = (ioread32(etha->addr + MPSM) & MPSM_PRD_MASK) >> 16; - - rswitch_modify(etha->addr, MMIS1, MMIS1_PRACS, MMIS1_PRACS); } else { iowrite32((data << 16) | (pop << 13) | (devad << 8) | (phyad << 3) | val, etha->addr + MPSM); - ret = rswitch_reg_wait(etha->addr, MMIS1, MMIS1_PWACS, MMIS1_PWACS); + ret = rswitch_reg_wait(etha->addr, MPSM, MPSM_PSME, 0); } return ret; diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index 78c0325cdf30..2cb66f3f4716 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -743,12 +743,6 @@ enum rswitch_etha_mode { #define MPSM_PRD_SHIFT 16 #define MPSM_PRD_MASK GENMASK(31, MPSM_PRD_SHIFT) -/* Completion flags */ -#define MMIS1_PAACS BIT(2) /* Address */ -#define MMIS1_PWACS BIT(1) /* Write */ -#define MMIS1_PRACS BIT(0) /* Read */ -#define MMIS1_CLEAR_FLAGS 0xf - #define MLVC_PLV BIT(16) /* GWCA */ From 2aa722b6d81c3118d33dcb8eea9aac49f56af790 Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Mon, 16 Dec 2024 12:19:56 +0500 Subject: [PATCH 4/5] net: renesas: rswitch: use generic MPSM operation for mdio C45 Introduce rswitch_etha_mpsm_op() that accepts values for MPSM register fields and executes the transaction. This avoids some code duptication, and can be used both for C45 and C22. Convert C45 read and write operations to use that. Signed-off-by: Nikita Yushchenko Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://patch.msgid.link/20241216071957.2587354-5-nikita.yoush@cogentembedded.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/renesas/rswitch.c | 51 +++++++++++++++----------- drivers/net/ethernet/renesas/rswitch.h | 17 ++++++--- 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 6e3f162ae3b3..a3ba2a91c0ab 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1195,36 +1195,29 @@ static int rswitch_etha_hw_init(struct rswitch_etha *etha, const u8 *mac) return rswitch_etha_change_mode(etha, EAMC_OPC_OPERATION); } -static int rswitch_etha_set_access(struct rswitch_etha *etha, bool read, - int phyad, int devad, int regad, int data) +static int rswitch_etha_mpsm_op(struct rswitch_etha *etha, bool read, + unsigned int mmf, unsigned int pda, + unsigned int pra, unsigned int pop, + unsigned int prd) { - int pop = read ? MDIO_READ_C45 : MDIO_WRITE_C45; u32 val; int ret; - if (devad == 0xffffffff) - return -ENODEV; - - val = MPSM_PSME | MPSM_MFF_C45; - iowrite32((regad << 16) | (devad << 8) | (phyad << 3) | val, etha->addr + MPSM); + val = MPSM_PSME | + FIELD_PREP(MPSM_MFF, mmf) | + FIELD_PREP(MPSM_PDA, pda) | + FIELD_PREP(MPSM_PRA, pra) | + FIELD_PREP(MPSM_POP, pop) | + FIELD_PREP(MPSM_PRD, prd); + iowrite32(val, etha->addr + MPSM); ret = rswitch_reg_wait(etha->addr, MPSM, MPSM_PSME, 0); if (ret) return ret; if (read) { - writel((pop << 13) | (devad << 8) | (phyad << 3) | val, etha->addr + MPSM); - - ret = rswitch_reg_wait(etha->addr, MPSM, MPSM_PSME, 0); - if (ret) - return ret; - - ret = (ioread32(etha->addr + MPSM) & MPSM_PRD_MASK) >> 16; - } else { - iowrite32((data << 16) | (pop << 13) | (devad << 8) | (phyad << 3) | val, - etha->addr + MPSM); - - ret = rswitch_reg_wait(etha->addr, MPSM, MPSM_PSME, 0); + val = ioread32(etha->addr + MPSM); + ret = FIELD_GET(MPSM_PRD, val); } return ret; @@ -1234,16 +1227,30 @@ static int rswitch_etha_mii_read_c45(struct mii_bus *bus, int addr, int devad, int regad) { struct rswitch_etha *etha = bus->priv; + int ret; - return rswitch_etha_set_access(etha, true, addr, devad, regad, 0); + ret = rswitch_etha_mpsm_op(etha, false, MPSM_MMF_C45, addr, devad, + MPSM_POP_ADDRESS, regad); + if (ret) + return ret; + + return rswitch_etha_mpsm_op(etha, true, MPSM_MMF_C45, addr, devad, + MPSM_POP_READ_C45, 0); } static int rswitch_etha_mii_write_c45(struct mii_bus *bus, int addr, int devad, int regad, u16 val) { struct rswitch_etha *etha = bus->priv; + int ret; - return rswitch_etha_set_access(etha, false, addr, devad, regad, val); + ret = rswitch_etha_mpsm_op(etha, false, MPSM_MMF_C45, addr, devad, + MPSM_POP_ADDRESS, regad); + if (ret) + return ret; + + return rswitch_etha_mpsm_op(etha, false, MPSM_MMF_C45, addr, devad, + MPSM_POP_WRITE, val); } /* Call of_node_put(port) after done */ diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index 2cb66f3f4716..35ee73766396 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -735,13 +735,18 @@ enum rswitch_etha_mode { #define MPIC_PSMCS GENMASK(22, 16) #define MPIC_PSMHT GENMASK(26, 24) -#define MDIO_READ_C45 0x03 -#define MDIO_WRITE_C45 0x01 - #define MPSM_PSME BIT(0) -#define MPSM_MFF_C45 BIT(2) -#define MPSM_PRD_SHIFT 16 -#define MPSM_PRD_MASK GENMASK(31, MPSM_PRD_SHIFT) +#define MPSM_MFF BIT(2) +#define MPSM_MMF_C22 0 +#define MPSM_MMF_C45 1 +#define MPSM_PDA GENMASK(7, 3) +#define MPSM_PRA GENMASK(12, 8) +#define MPSM_POP GENMASK(14, 13) +#define MPSM_POP_ADDRESS 0 +#define MPSM_POP_WRITE 1 +#define MPSM_POP_READ_C22 2 +#define MPSM_POP_READ_C45 3 +#define MPSM_PRD GENMASK(31, 16) #define MLVC_PLV BIT(16) From db48fe905d8ae90d0c35238ddd90e816d543316c Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Mon, 16 Dec 2024 12:19:57 +0500 Subject: [PATCH 5/5] net: renesas: rswitch: add mdio C22 support The generic MPSM operation added by the previous patch can be used both for C45 and C22. Add handlers for C22 operations. Signed-off-by: Nikita Yushchenko Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda Link: https://patch.msgid.link/20241216071957.2587354-6-nikita.yoush@cogentembedded.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/renesas/rswitch.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index a3ba2a91c0ab..aae26098bc0c 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -1253,6 +1253,23 @@ static int rswitch_etha_mii_write_c45(struct mii_bus *bus, int addr, int devad, MPSM_POP_WRITE, val); } +static int rswitch_etha_mii_read_c22(struct mii_bus *bus, int phyad, int regad) +{ + struct rswitch_etha *etha = bus->priv; + + return rswitch_etha_mpsm_op(etha, true, MPSM_MMF_C22, phyad, regad, + MPSM_POP_READ_C22, 0); +} + +static int rswitch_etha_mii_write_c22(struct mii_bus *bus, int phyad, + int regad, u16 val) +{ + struct rswitch_etha *etha = bus->priv; + + return rswitch_etha_mpsm_op(etha, false, MPSM_MMF_C22, phyad, regad, + MPSM_POP_WRITE, val); +} + /* Call of_node_put(port) after done */ static struct device_node *rswitch_get_port_node(struct rswitch_device *rdev) { @@ -1335,6 +1352,8 @@ static int rswitch_mii_register(struct rswitch_device *rdev) mii_bus->priv = rdev->etha; mii_bus->read_c45 = rswitch_etha_mii_read_c45; mii_bus->write_c45 = rswitch_etha_mii_write_c45; + mii_bus->read = rswitch_etha_mii_read_c22; + mii_bus->write = rswitch_etha_mii_write_c22; mii_bus->parent = &rdev->priv->pdev->dev; mdio_np = of_get_child_by_name(rdev->np_port, "mdio");