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 34static 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 39static 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 45static 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 50static 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 58int enetc_mdio_write_c22(struct mii_bus *bus, int phy_id, int regnum, 59 u16 value) 60{ 61 struct enetc_mdio_priv *mdio_priv = bus->priv; 62 u32 mdio_ctl, mdio_cfg; 63 u16 dev_addr; 64 int ret; 65 66 mdio_cfg = ENETC_EMDIO_CFG; 67 dev_addr = regnum & 0x1f; 68 mdio_cfg &= ~MDIO_CFG_ENC45; 69 70 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 71 72 ret = enetc_mdio_wait_complete(mdio_priv); 73 if (ret) 74 return ret; 75 76 /* set port and dev addr */ 77 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 78 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 79 80 /* write the value */ 81 enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value); 82 83 ret = enetc_mdio_wait_complete(mdio_priv); 84 if (ret) 85 return ret; 86 87 return 0; 88} 89EXPORT_SYMBOL_GPL(enetc_mdio_write_c22); 90 91int enetc_mdio_write_c45(struct mii_bus *bus, int phy_id, int dev_addr, 92 int regnum, u16 value) 93{ 94 struct enetc_mdio_priv *mdio_priv = bus->priv; 95 u32 mdio_ctl, mdio_cfg; 96 int ret; 97 98 mdio_cfg = ENETC_EMDIO_CFG; 99 mdio_cfg |= MDIO_CFG_ENC45; 100 101 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 102 103 ret = enetc_mdio_wait_complete(mdio_priv); 104 if (ret) 105 return ret; 106 107 /* set port and dev addr */ 108 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 109 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 110 111 /* set the register address */ 112 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); 113 114 ret = enetc_mdio_wait_complete(mdio_priv); 115 if (ret) 116 return ret; 117 118 /* write the value */ 119 enetc_mdio_wr(mdio_priv, ENETC_MDIO_DATA, value); 120 121 ret = enetc_mdio_wait_complete(mdio_priv); 122 if (ret) 123 return ret; 124 125 return 0; 126} 127EXPORT_SYMBOL_GPL(enetc_mdio_write_c45); 128 129int enetc_mdio_read_c22(struct mii_bus *bus, int phy_id, int regnum) 130{ 131 struct enetc_mdio_priv *mdio_priv = bus->priv; 132 u32 mdio_ctl, mdio_cfg; 133 u16 dev_addr, value; 134 int ret; 135 136 mdio_cfg = ENETC_EMDIO_CFG; 137 dev_addr = regnum & 0x1f; 138 mdio_cfg &= ~MDIO_CFG_ENC45; 139 140 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 141 142 ret = enetc_mdio_wait_complete(mdio_priv); 143 if (ret) 144 return ret; 145 146 /* set port and device addr */ 147 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 148 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 149 150 /* initiate the read */ 151 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ); 152 153 ret = enetc_mdio_wait_complete(mdio_priv); 154 if (ret) 155 return ret; 156 157 /* return all Fs if nothing was there */ 158 if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) { 159 dev_dbg(&bus->dev, 160 "Error while reading PHY%d reg at %d.%d\n", 161 phy_id, dev_addr, regnum); 162 return 0xffff; 163 } 164 165 value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff; 166 167 return value; 168} 169EXPORT_SYMBOL_GPL(enetc_mdio_read_c22); 170 171int enetc_mdio_read_c45(struct mii_bus *bus, int phy_id, int dev_addr, 172 int regnum) 173{ 174 struct enetc_mdio_priv *mdio_priv = bus->priv; 175 u32 mdio_ctl, mdio_cfg; 176 u16 value; 177 int ret; 178 179 mdio_cfg = ENETC_EMDIO_CFG; 180 mdio_cfg |= MDIO_CFG_ENC45; 181 182 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CFG, mdio_cfg); 183 184 ret = enetc_mdio_wait_complete(mdio_priv); 185 if (ret) 186 return ret; 187 188 /* set port and device addr */ 189 mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr); 190 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl); 191 192 /* set the register address */ 193 enetc_mdio_wr(mdio_priv, ENETC_MDIO_ADDR, regnum & 0xffff); 194 195 ret = enetc_mdio_wait_complete(mdio_priv); 196 if (ret) 197 return ret; 198 199 /* initiate the read */ 200 enetc_mdio_wr(mdio_priv, ENETC_MDIO_CTL, mdio_ctl | MDIO_CTL_READ); 201 202 ret = enetc_mdio_wait_complete(mdio_priv); 203 if (ret) 204 return ret; 205 206 /* return all Fs if nothing was there */ 207 if (enetc_mdio_rd(mdio_priv, ENETC_MDIO_CFG) & MDIO_CFG_RD_ER) { 208 dev_dbg(&bus->dev, 209 "Error while reading PHY%d reg at %d.%d\n", 210 phy_id, dev_addr, regnum); 211 return 0xffff; 212 } 213 214 value = enetc_mdio_rd(mdio_priv, ENETC_MDIO_DATA) & 0xffff; 215 216 return value; 217} 218EXPORT_SYMBOL_GPL(enetc_mdio_read_c45); 219 220struct enetc_hw *enetc_hw_alloc(struct device *dev, void __iomem *port_regs) 221{ 222 struct enetc_hw *hw; 223 224 hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL); 225 if (!hw) 226 return ERR_PTR(-ENOMEM); 227 228 hw->port = port_regs; 229 230 return hw; 231} 232EXPORT_SYMBOL_GPL(enetc_hw_alloc); 233 234/* Lock for MDIO access errata on LS1028A */ 235DEFINE_RWLOCK(enetc_mdio_lock); 236EXPORT_SYMBOL_GPL(enetc_mdio_lock); 237