1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * MDIO bus driver for the Xilinx Axi Ethernet device 4 * 5 * Copyright (c) 2009 Secret Lab Technologies, Ltd. 6 * Copyright (c) 2010 - 2011 Michal Simek <monstr@monstr.eu> 7 * Copyright (c) 2010 - 2011 PetaLogix 8 * Copyright (c) 2019 SED Systems, a division of Calian Ltd. 9 * Copyright (c) 2010 - 2012 Xilinx, Inc. All rights reserved. 10 */ 11 12 #include <linux/clk.h> 13 #include <linux/of_address.h> 14 #include <linux/of_mdio.h> 15 #include <linux/jiffies.h> 16 #include <linux/iopoll.h> 17 18 #include "xilinx_axienet.h" 19 20 #define DEFAULT_MDIO_FREQ 2500000 /* 2.5 MHz */ 21 #define DEFAULT_HOST_CLOCK 150000000 /* 150 MHz */ 22 23 /** 24 * axienet_mdio_wait_until_ready - MDIO wait function 25 * @lp: Pointer to axienet local data structure. 26 * 27 * Return : 0 on success, Negative value on errors 28 * 29 * Wait till MDIO interface is ready to accept a new transaction. 30 */ 31 static int axienet_mdio_wait_until_ready(struct axienet_local *lp) 32 { 33 u32 val; 34 35 return readx_poll_timeout(axinet_ior_read_mcr, lp, 36 val, val & XAE_MDIO_MCR_READY_MASK, 37 1, 20000); 38 } 39 40 /** 41 * axienet_mdio_mdc_enable - MDIO MDC enable function 42 * @lp: Pointer to axienet local data structure. 43 * 44 * Enable the MDIO MDC. Called prior to a read/write operation 45 */ 46 static void axienet_mdio_mdc_enable(struct axienet_local *lp) 47 { 48 axienet_iow(lp, XAE_MDIO_MC_OFFSET, 49 ((u32)lp->mii_clk_div | XAE_MDIO_MC_MDIOEN_MASK)); 50 } 51 52 /** 53 * axienet_mdio_mdc_disable - MDIO MDC disable function 54 * @lp: Pointer to axienet local data structure. 55 * 56 * Disable the MDIO MDC. Called after a read/write operation 57 */ 58 static void axienet_mdio_mdc_disable(struct axienet_local *lp) 59 { 60 u32 mc_reg; 61 62 mc_reg = axienet_ior(lp, XAE_MDIO_MC_OFFSET); 63 axienet_iow(lp, XAE_MDIO_MC_OFFSET, 64 (mc_reg & ~XAE_MDIO_MC_MDIOEN_MASK)); 65 } 66 67 /** 68 * axienet_mdio_read - MDIO interface read function 69 * @bus: Pointer to mii bus structure 70 * @phy_id: Address of the PHY device 71 * @reg: PHY register to read 72 * 73 * Return: The register contents on success, -ETIMEDOUT on a timeout 74 * 75 * Reads the contents of the requested register from the requested PHY 76 * address by first writing the details into MCR register. After a while 77 * the register MRD is read to obtain the PHY register content. 78 */ 79 static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg) 80 { 81 u32 rc; 82 int ret; 83 struct axienet_local *lp = bus->priv; 84 85 axienet_mdio_mdc_enable(lp); 86 87 ret = axienet_mdio_wait_until_ready(lp); 88 if (ret < 0) { 89 axienet_mdio_mdc_disable(lp); 90 return ret; 91 } 92 93 axienet_iow(lp, XAE_MDIO_MCR_OFFSET, 94 (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) & 95 XAE_MDIO_MCR_PHYAD_MASK) | 96 ((reg << XAE_MDIO_MCR_REGAD_SHIFT) & 97 XAE_MDIO_MCR_REGAD_MASK) | 98 XAE_MDIO_MCR_INITIATE_MASK | 99 XAE_MDIO_MCR_OP_READ_MASK)); 100 101 ret = axienet_mdio_wait_until_ready(lp); 102 if (ret < 0) { 103 axienet_mdio_mdc_disable(lp); 104 return ret; 105 } 106 107 rc = axienet_ior(lp, XAE_MDIO_MRD_OFFSET) & 0x0000FFFF; 108 109 dev_dbg(lp->dev, "axienet_mdio_read(phy_id=%i, reg=%x) == %x\n", 110 phy_id, reg, rc); 111 112 axienet_mdio_mdc_disable(lp); 113 return rc; 114 } 115 116 /** 117 * axienet_mdio_write - MDIO interface write function 118 * @bus: Pointer to mii bus structure 119 * @phy_id: Address of the PHY device 120 * @reg: PHY register to write to 121 * @val: Value to be written into the register 122 * 123 * Return: 0 on success, -ETIMEDOUT on a timeout 124 * 125 * Writes the value to the requested register by first writing the value 126 * into MWD register. The MCR register is then appropriately setup 127 * to finish the write operation. 128 */ 129 static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg, 130 u16 val) 131 { 132 int ret; 133 struct axienet_local *lp = bus->priv; 134 135 dev_dbg(lp->dev, "axienet_mdio_write(phy_id=%i, reg=%x, val=%x)\n", 136 phy_id, reg, val); 137 138 axienet_mdio_mdc_enable(lp); 139 140 ret = axienet_mdio_wait_until_ready(lp); 141 if (ret < 0) { 142 axienet_mdio_mdc_disable(lp); 143 return ret; 144 } 145 146 axienet_iow(lp, XAE_MDIO_MWD_OFFSET, (u32)val); 147 axienet_iow(lp, XAE_MDIO_MCR_OFFSET, 148 (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) & 149 XAE_MDIO_MCR_PHYAD_MASK) | 150 ((reg << XAE_MDIO_MCR_REGAD_SHIFT) & 151 XAE_MDIO_MCR_REGAD_MASK) | 152 XAE_MDIO_MCR_INITIATE_MASK | 153 XAE_MDIO_MCR_OP_WRITE_MASK)); 154 155 ret = axienet_mdio_wait_until_ready(lp); 156 if (ret < 0) { 157 axienet_mdio_mdc_disable(lp); 158 return ret; 159 } 160 axienet_mdio_mdc_disable(lp); 161 return 0; 162 } 163 164 /** 165 * axienet_mdio_enable - MDIO hardware setup function 166 * @lp: Pointer to axienet local data structure. 167 * @np: Pointer to mdio device tree node. 168 * 169 * Return: 0 on success, -ETIMEDOUT on a timeout, -EOVERFLOW on a clock 170 * divisor overflow. 171 * 172 * Sets up the MDIO interface by initializing the MDIO clock and enabling the 173 * MDIO interface in hardware. 174 **/ 175 static int axienet_mdio_enable(struct axienet_local *lp, struct device_node *np) 176 { 177 u32 mdio_freq = DEFAULT_MDIO_FREQ; 178 u32 host_clock; 179 u32 clk_div; 180 int ret; 181 182 lp->mii_clk_div = 0; 183 184 if (lp->axi_clk) { 185 host_clock = clk_get_rate(lp->axi_clk); 186 } else { 187 struct device_node *np1; 188 189 /* Legacy fallback: detect CPU clock frequency and use as AXI 190 * bus clock frequency. This only works on certain platforms. 191 */ 192 np1 = of_find_node_by_name(NULL, "cpu"); 193 if (!np1) { 194 netdev_warn(lp->ndev, "Could not find CPU device node.\n"); 195 host_clock = DEFAULT_HOST_CLOCK; 196 } else { 197 int ret = of_property_read_u32(np1, "clock-frequency", 198 &host_clock); 199 if (ret) { 200 netdev_warn(lp->ndev, "CPU clock-frequency property not found.\n"); 201 host_clock = DEFAULT_HOST_CLOCK; 202 } 203 of_node_put(np1); 204 } 205 netdev_info(lp->ndev, "Setting assumed host clock to %u\n", 206 host_clock); 207 } 208 209 if (np) 210 of_property_read_u32(np, "clock-frequency", &mdio_freq); 211 if (mdio_freq != DEFAULT_MDIO_FREQ) 212 netdev_info(lp->ndev, "Setting non-standard mdio bus frequency to %u Hz\n", 213 mdio_freq); 214 215 /* clk_div can be calculated by deriving it from the equation: 216 * fMDIO = fHOST / ((1 + clk_div) * 2) 217 * 218 * Where fMDIO <= 2500000, so we get: 219 * fHOST / ((1 + clk_div) * 2) <= 2500000 220 * 221 * Then we get: 222 * 1 / ((1 + clk_div) * 2) <= (2500000 / fHOST) 223 * 224 * Then we get: 225 * 1 / (1 + clk_div) <= ((2500000 * 2) / fHOST) 226 * 227 * Then we get: 228 * 1 / (1 + clk_div) <= (5000000 / fHOST) 229 * 230 * So: 231 * (1 + clk_div) >= (fHOST / 5000000) 232 * 233 * And finally: 234 * clk_div >= (fHOST / 5000000) - 1 235 * 236 * fHOST can be read from the flattened device tree as property 237 * "clock-frequency" from the CPU 238 */ 239 240 clk_div = (host_clock / (mdio_freq * 2)) - 1; 241 /* If there is any remainder from the division of 242 * fHOST / (mdio_freq * 2), then we need to add 243 * 1 to the clock divisor or we will surely be 244 * above the requested frequency 245 */ 246 if (host_clock % (mdio_freq * 2)) 247 clk_div++; 248 249 /* Check for overflow of mii_clk_div */ 250 if (clk_div & ~XAE_MDIO_MC_CLOCK_DIVIDE_MAX) { 251 netdev_warn(lp->ndev, "MDIO clock divisor overflow\n"); 252 return -EOVERFLOW; 253 } 254 lp->mii_clk_div = (u8)clk_div; 255 256 netdev_dbg(lp->ndev, 257 "Setting MDIO clock divisor to %u/%u Hz host clock.\n", 258 lp->mii_clk_div, host_clock); 259 260 axienet_mdio_mdc_enable(lp); 261 262 ret = axienet_mdio_wait_until_ready(lp); 263 if (ret) 264 axienet_mdio_mdc_disable(lp); 265 266 return ret; 267 } 268 269 /** 270 * axienet_mdio_setup - MDIO setup function 271 * @lp: Pointer to axienet local data structure. 272 * 273 * Return: 0 on success, -ETIMEDOUT on a timeout, -EOVERFLOW on a clock 274 * divisor overflow, -ENOMEM when mdiobus_alloc (to allocate 275 * memory for mii bus structure) fails. 276 * 277 * Sets up the MDIO interface by initializing the MDIO clock. 278 * Register the MDIO interface. 279 **/ 280 int axienet_mdio_setup(struct axienet_local *lp) 281 { 282 struct device_node *mdio_node; 283 struct mii_bus *bus; 284 int ret; 285 286 bus = mdiobus_alloc(); 287 if (!bus) 288 return -ENOMEM; 289 290 snprintf(bus->id, MII_BUS_ID_SIZE, "axienet-%.8llx", 291 (unsigned long long)lp->regs_start); 292 293 bus->priv = lp; 294 bus->name = "Xilinx Axi Ethernet MDIO"; 295 bus->read = axienet_mdio_read; 296 bus->write = axienet_mdio_write; 297 bus->parent = lp->dev; 298 lp->mii_bus = bus; 299 300 mdio_node = of_get_child_by_name(lp->dev->of_node, "mdio"); 301 ret = axienet_mdio_enable(lp, mdio_node); 302 if (ret < 0) 303 goto unregister; 304 ret = of_mdiobus_register(bus, mdio_node); 305 if (ret) 306 goto unregister_mdio_enabled; 307 of_node_put(mdio_node); 308 axienet_mdio_mdc_disable(lp); 309 return 0; 310 311 unregister_mdio_enabled: 312 axienet_mdio_mdc_disable(lp); 313 unregister: 314 of_node_put(mdio_node); 315 mdiobus_free(bus); 316 lp->mii_bus = NULL; 317 return ret; 318 } 319 320 /** 321 * axienet_mdio_teardown - MDIO remove function 322 * @lp: Pointer to axienet local data structure. 323 * 324 * Unregisters the MDIO and frees any associate memory for mii bus. 325 */ 326 void axienet_mdio_teardown(struct axienet_local *lp) 327 { 328 mdiobus_unregister(lp->mii_bus); 329 mdiobus_free(lp->mii_bus); 330 lp->mii_bus = NULL; 331 } 332