1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 2 /* Copyright 2019 NXP */ 3 4 #include <linux/fsl/enetc_mdio.h> 5 #include <linux/mdio.h> 6 #include <linux/of_mdio.h> 7 #include <linux/iopoll.h> 8 #include <linux/of.h> 9 10 #include "enetc_pf.h" 11 12 #define ENETC_MDIO_CFG 0x0 /* MDIO configuration and status */ 13 #define ENETC_MDIO_CTL 0x4 /* MDIO control */ 14 #define ENETC_MDIO_DATA 0x8 /* MDIO data */ 15 #define ENETC_MDIO_ADDR 0xc /* MDIO address */ 16 17 #define MDIO_CFG_CLKDIV(x) ((((x) >> 1) & 0xff) << 8) 18 #define MDIO_CFG_BSY BIT(0) 19 #define MDIO_CFG_RD_ER BIT(1) 20 #define MDIO_CFG_HOLD(x) (((x) << 2) & GENMASK(4, 2)) 21 #define MDIO_CFG_ENC45 BIT(6) 22 /* external MDIO only - driven on neg MDC edge */ 23 #define MDIO_CFG_NEG BIT(23) 24 25 #define ENETC_EMDIO_CFG \ 26 (MDIO_CFG_HOLD(2) | \ 27 MDIO_CFG_CLKDIV(258) | \ 28 MDIO_CFG_NEG) 29 30 #define MDIO_CTL_DEV_ADDR(x) ((x) & 0x1f) 31 #define MDIO_CTL_PORT_ADDR(x) (((x) & 0x1f) << 5) 32 #define MDIO_CTL_READ BIT(15) 33 34 static inline u32 enetc_mdio_rd(struct enetc_mdio_priv *mdio_priv, int off) 35 { 36 return enetc_port_rd_mdio(mdio_priv->hw, mdio_priv->mdio_base + off); 37 } 38 39 static inline void enetc_mdio_wr(struct enetc_mdio_priv *mdio_priv, int off, 40 u32 val) 41 { 42 enetc_port_wr_mdio(mdio_priv->hw, mdio_priv->mdio_base + off, val); 43 } 44 45 static bool enetc_mdio_is_busy(struct enetc_mdio_priv *mdio_priv) 46 { 47 return enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_BSY; 48 } 49 50 static int enetc_mdio_wait_complete(struct enetc_mdio_priv *mdio_priv) 51 { 52 bool is_busy; 53 54 return readx_poll_timeout(enetc_mdio_is_busy, mdio_priv, 55 is_busy, !is_busy, 10, 10 * 1000); 56 } 57 58 int enetc_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value) 59 { 60 struct enetc_mdio_priv *mdio_priv = bus->priv; 61 u32 mdio_ctl, mdio_cfg; 62 u16 dev_addr; 63 int ret; 64 65 mdio_cfg = ENETC_EMDIO_CFG; 66 if (regnum & MII_ADDR_C45) { 67 dev_addr = (regnum >> 16) & 0x1f; 68 mdio_cfg |= MDIO_CFG_ENC45; 69 } else { 70 /* clause 22 (ie 1G) */ 71 dev_addr = regnum & 0x1f; 72 mdio_cfg &= ~MDIO_CFG_ENC45; 73 } 74 75 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 76 77 ret = enetc_mdio_wait_complete(mdio_priv); 78 if (ret) 79 return ret; 80 81 /* set port and dev addr */ 82 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 83 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 84 85 /* set the register address */ 86 if (regnum & MII_ADDR_C45) { 87 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); 88 89 ret = enetc_mdio_wait_complete(mdio_priv); 90 if (ret) 91 return ret; 92 } 93 94 /* write the value */ 95 enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value); 96 97 ret = enetc_mdio_wait_complete(mdio_priv); 98 if (ret) 99 return ret; 100 101 return 0; 102 } 103 EXPORT_SYMBOL_GPL(enetc_mdio_write); 104 105 int enetc_mdio_read(struct mii_bus *bus, int phy_id, int regnum) 106 { 107 struct enetc_mdio_priv *mdio_priv = bus->priv; 108 u32 mdio_ctl, mdio_cfg; 109 u16 dev_addr, value; 110 int ret; 111 112 mdio_cfg = ENETC_EMDIO_CFG; 113 if (regnum & MII_ADDR_C45) { 114 dev_addr = (regnum >> 16) & 0x1f; 115 mdio_cfg |= MDIO_CFG_ENC45; 116 } else { 117 dev_addr = regnum & 0x1f; 118 mdio_cfg &= ~MDIO_CFG_ENC45; 119 } 120 121 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 122 123 ret = enetc_mdio_wait_complete(mdio_priv); 124 if (ret) 125 return ret; 126 127 /* set port and device addr */ 128 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 129 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 130 131 /* set the register address */ 132 if (regnum & MII_ADDR_C45) { 133 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); 134 135 ret = enetc_mdio_wait_complete(mdio_priv); 136 if (ret) 137 return ret; 138 } 139 140 /* initiate the read */ 141 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ); 142 143 ret = enetc_mdio_wait_complete(mdio_priv); 144 if (ret) 145 return ret; 146 147 /* return all Fs if nothing was there */ 148 if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) { 149 dev_dbg(&bus->dev, 150 "Error while reading PHY%d reg at %d.%hhu\n", 151 phy_id, dev_addr, regnum); 152 return 0xffff; 153 } 154 155 value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff; 156 157 return value; 158 } 159 EXPORT_SYMBOL_GPL(enetc_mdio_read); 160 161 struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) 162 { 163 struct enetc_hw *hw; 164 165 hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 166 if (!hw) 167 return ERR_PTR(-ENOMEM); 168 169 hw->port = port_regs; 170 171 return hw; 172 } 173 EXPORT_SYMBOL_GPL(enetc_hw_alloc); 174 175 /* Lock for MDIO access errata on LS1028A */ 176 DEFINE_RWLOCK(enetc_mdio_lock); 177 EXPORT_SYMBOL_GPL(enetc_mdio_lock); 178