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 MAX_MDIO_FREQ 2500000 /* 2.5 MHz */ 21 #define DEFAULT_HOST_CLOCK 150000000 /* 150 MHz */ 22 23 /* Wait till MDIO interface is ready to accept a new transaction.*/ 24 static int axienet_mdio_wait_until_ready(struct axienet_local *lp) 25 { 26 u32 val; 27 28 return readx_poll_timeout(axinet_ior_read_mcr, lp, 29 val, val & XAE_MDIO_MCR_READY_MASK, 30 1, 20000); 31 } 32 33 /** 34 * axienet_mdio_read - MDIO interface read function 35 * @bus: Pointer to mii bus structure 36 * @phy_id: Address of the PHY device 37 * @reg: PHY register to read 38 * 39 * Return: The register contents on success, -ETIMEDOUT on a timeout 40 * 41 * Reads the contents of the requested register from the requested PHY 42 * address by first writing the details into MCR register. After a while 43 * the register MRD is read to obtain the PHY register content. 44 */ 45 static int axienet_mdio_read(struct mii_bus *bus, int phy_id, int reg) 46 { 47 u32 rc; 48 int ret; 49 struct axienet_local *lp = bus->priv; 50 51 ret = axienet_mdio_wait_until_ready(lp); 52 if (ret < 0) 53 return ret; 54 55 axienet_iow(lp, XAE_MDIO_MCR_OFFSET, 56 (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) & 57 XAE_MDIO_MCR_PHYAD_MASK) | 58 ((reg << XAE_MDIO_MCR_REGAD_SHIFT) & 59 XAE_MDIO_MCR_REGAD_MASK) | 60 XAE_MDIO_MCR_INITIATE_MASK | 61 XAE_MDIO_MCR_OP_READ_MASK)); 62 63 ret = axienet_mdio_wait_until_ready(lp); 64 if (ret < 0) 65 return ret; 66 67 rc = axienet_ior(lp, XAE_MDIO_MRD_OFFSET) & 0x0000FFFF; 68 69 dev_dbg(lp->dev, "axienet_mdio_read(phy_id=%i, reg=%x) == %x\n", 70 phy_id, reg, rc); 71 72 return rc; 73 } 74 75 /** 76 * axienet_mdio_write - MDIO interface write function 77 * @bus: Pointer to mii bus structure 78 * @phy_id: Address of the PHY device 79 * @reg: PHY register to write to 80 * @val: Value to be written into the register 81 * 82 * Return: 0 on success, -ETIMEDOUT on a timeout 83 * 84 * Writes the value to the requested register by first writing the value 85 * into MWD register. The the MCR register is then appropriately setup 86 * to finish the write operation. 87 */ 88 static int axienet_mdio_write(struct mii_bus *bus, int phy_id, int reg, 89 u16 val) 90 { 91 int ret; 92 struct axienet_local *lp = bus->priv; 93 94 dev_dbg(lp->dev, "axienet_mdio_write(phy_id=%i, reg=%x, val=%x)\n", 95 phy_id, reg, val); 96 97 ret = axienet_mdio_wait_until_ready(lp); 98 if (ret < 0) 99 return ret; 100 101 axienet_iow(lp, XAE_MDIO_MWD_OFFSET, (u32) val); 102 axienet_iow(lp, XAE_MDIO_MCR_OFFSET, 103 (((phy_id << XAE_MDIO_MCR_PHYAD_SHIFT) & 104 XAE_MDIO_MCR_PHYAD_MASK) | 105 ((reg << XAE_MDIO_MCR_REGAD_SHIFT) & 106 XAE_MDIO_MCR_REGAD_MASK) | 107 XAE_MDIO_MCR_INITIATE_MASK | 108 XAE_MDIO_MCR_OP_WRITE_MASK)); 109 110 ret = axienet_mdio_wait_until_ready(lp); 111 if (ret < 0) 112 return ret; 113 return 0; 114 } 115 116 /** 117 * axienet_mdio_enable - MDIO hardware setup function 118 * @lp: Pointer to axienet local data structure. 119 * 120 * Return: 0 on success, -ETIMEDOUT on a timeout. 121 * 122 * Sets up the MDIO interface by initializing the MDIO clock and enabling the 123 * MDIO interface in hardware. 124 **/ 125 int axienet_mdio_enable(struct axienet_local *lp) 126 { 127 u32 clk_div, host_clock; 128 129 if (lp->clk) { 130 host_clock = clk_get_rate(lp->clk); 131 } else { 132 struct device_node *np1; 133 134 /* Legacy fallback: detect CPU clock frequency and use as AXI 135 * bus clock frequency. This only works on certain platforms. 136 */ 137 np1 = of_find_node_by_name(NULL, "cpu"); 138 if (!np1) { 139 netdev_warn(lp->ndev, "Could not find CPU device node.\n"); 140 host_clock = DEFAULT_HOST_CLOCK; 141 } else { 142 int ret = of_property_read_u32(np1, "clock-frequency", 143 &host_clock); 144 if (ret) { 145 netdev_warn(lp->ndev, "CPU clock-frequency property not found.\n"); 146 host_clock = DEFAULT_HOST_CLOCK; 147 } 148 of_node_put(np1); 149 } 150 netdev_info(lp->ndev, "Setting assumed host clock to %u\n", 151 host_clock); 152 } 153 154 /* clk_div can be calculated by deriving it from the equation: 155 * fMDIO = fHOST / ((1 + clk_div) * 2) 156 * 157 * Where fMDIO <= 2500000, so we get: 158 * fHOST / ((1 + clk_div) * 2) <= 2500000 159 * 160 * Then we get: 161 * 1 / ((1 + clk_div) * 2) <= (2500000 / fHOST) 162 * 163 * Then we get: 164 * 1 / (1 + clk_div) <= ((2500000 * 2) / fHOST) 165 * 166 * Then we get: 167 * 1 / (1 + clk_div) <= (5000000 / fHOST) 168 * 169 * So: 170 * (1 + clk_div) >= (fHOST / 5000000) 171 * 172 * And finally: 173 * clk_div >= (fHOST / 5000000) - 1 174 * 175 * fHOST can be read from the flattened device tree as property 176 * "clock-frequency" from the CPU 177 */ 178 179 clk_div = (host_clock / (MAX_MDIO_FREQ * 2)) - 1; 180 /* If there is any remainder from the division of 181 * fHOST / (MAX_MDIO_FREQ * 2), then we need to add 182 * 1 to the clock divisor or we will surely be above 2.5 MHz 183 */ 184 if (host_clock % (MAX_MDIO_FREQ * 2)) 185 clk_div++; 186 187 netdev_dbg(lp->ndev, 188 "Setting MDIO clock divisor to %u/%u Hz host clock.\n", 189 clk_div, host_clock); 190 191 axienet_iow(lp, XAE_MDIO_MC_OFFSET, clk_div | XAE_MDIO_MC_MDIOEN_MASK); 192 193 return axienet_mdio_wait_until_ready(lp); 194 } 195 196 /** 197 * axienet_mdio_disable - MDIO hardware disable function 198 * @lp: Pointer to axienet local data structure. 199 * 200 * Disable the MDIO interface in hardware. 201 **/ 202 void axienet_mdio_disable(struct axienet_local *lp) 203 { 204 axienet_iow(lp, XAE_MDIO_MC_OFFSET, 0); 205 } 206 207 /** 208 * axienet_mdio_setup - MDIO setup function 209 * @lp: Pointer to axienet local data structure. 210 * 211 * Return: 0 on success, -ETIMEDOUT on a timeout, -ENOMEM when 212 * mdiobus_alloc (to allocate memory for mii bus structure) fails. 213 * 214 * Sets up the MDIO interface by initializing the MDIO clock and enabling the 215 * MDIO interface in hardware. Register the MDIO interface. 216 **/ 217 int axienet_mdio_setup(struct axienet_local *lp) 218 { 219 struct device_node *mdio_node; 220 struct mii_bus *bus; 221 int ret; 222 223 ret = axienet_mdio_enable(lp); 224 if (ret < 0) 225 return ret; 226 227 bus = mdiobus_alloc(); 228 if (!bus) 229 return -ENOMEM; 230 231 snprintf(bus->id, MII_BUS_ID_SIZE, "axienet-%.8llx", 232 (unsigned long long)lp->regs_start); 233 234 bus->priv = lp; 235 bus->name = "Xilinx Axi Ethernet MDIO"; 236 bus->read = axienet_mdio_read; 237 bus->write = axienet_mdio_write; 238 bus->parent = lp->dev; 239 lp->mii_bus = bus; 240 241 mdio_node = of_get_child_by_name(lp->dev->of_node, "mdio"); 242 ret = of_mdiobus_register(bus, mdio_node); 243 of_node_put(mdio_node); 244 if (ret) { 245 mdiobus_free(bus); 246 lp->mii_bus = NULL; 247 return ret; 248 } 249 return 0; 250 } 251 252 /** 253 * axienet_mdio_teardown - MDIO remove function 254 * @lp: Pointer to axienet local data structure. 255 * 256 * Unregisters the MDIO and frees any associate memory for mii bus. 257 */ 258 void axienet_mdio_teardown(struct axienet_local *lp) 259 { 260 mdiobus_unregister(lp->mii_bus); 261 mdiobus_free(lp->mii_bus); 262 lp->mii_bus = NULL; 263 } 264