1 /* 2 * Driver for the MDIO interface of Marvell network interfaces. 3 * 4 * Since the MDIO interface of Marvell network interfaces is shared 5 * between all network interfaces, having a single driver allows to 6 * handle concurrent accesses properly (you may have four Ethernet 7 * ports, but they in fact share the same SMI interface to access the 8 * MDIO bus). Moreover, this MDIO interface code is similar between 9 * the mv643xx_eth driver and the mvneta driver. For now, it is only 10 * used by the mvneta driver, but it could later be used by the 11 * mv643xx_eth driver as well. 12 * 13 * Copyright (C) 2012 Marvell 14 * 15 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 16 * 17 * This file is licensed under the terms of the GNU General Public 18 * License version 2. This program is licensed "as is" without any 19 * warranty of any kind, whether express or implied. 20 */ 21 22 #include <linux/init.h> 23 #include <linux/kernel.h> 24 #include <linux/module.h> 25 #include <linux/mutex.h> 26 #include <linux/phy.h> 27 #include <linux/of_address.h> 28 #include <linux/of_mdio.h> 29 #include <linux/platform_device.h> 30 #include <linux/delay.h> 31 32 #define MVMDIO_SMI_DATA_SHIFT 0 33 #define MVMDIO_SMI_PHY_ADDR_SHIFT 16 34 #define MVMDIO_SMI_PHY_REG_SHIFT 21 35 #define MVMDIO_SMI_READ_OPERATION BIT(26) 36 #define MVMDIO_SMI_WRITE_OPERATION 0 37 #define MVMDIO_SMI_READ_VALID BIT(27) 38 #define MVMDIO_SMI_BUSY BIT(28) 39 40 struct orion_mdio_dev { 41 struct mutex lock; 42 void __iomem *smireg; 43 }; 44 45 /* Wait for the SMI unit to be ready for another operation 46 */ 47 static int orion_mdio_wait_ready(struct mii_bus *bus) 48 { 49 struct orion_mdio_dev *dev = bus->priv; 50 int count; 51 u32 val; 52 53 count = 0; 54 while (1) { 55 val = readl(dev->smireg); 56 if (!(val & MVMDIO_SMI_BUSY)) 57 break; 58 59 if (count > 100) { 60 dev_err(bus->parent, "Timeout: SMI busy for too long\n"); 61 return -ETIMEDOUT; 62 } 63 64 udelay(10); 65 count++; 66 } 67 68 return 0; 69 } 70 71 static int orion_mdio_read(struct mii_bus *bus, int mii_id, 72 int regnum) 73 { 74 struct orion_mdio_dev *dev = bus->priv; 75 int count; 76 u32 val; 77 int ret; 78 79 mutex_lock(&dev->lock); 80 81 ret = orion_mdio_wait_ready(bus); 82 if (ret < 0) { 83 mutex_unlock(&dev->lock); 84 return ret; 85 } 86 87 writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) | 88 (regnum << MVMDIO_SMI_PHY_REG_SHIFT) | 89 MVMDIO_SMI_READ_OPERATION), 90 dev->smireg); 91 92 /* Wait for the value to become available */ 93 count = 0; 94 while (1) { 95 val = readl(dev->smireg); 96 if (val & MVMDIO_SMI_READ_VALID) 97 break; 98 99 if (count > 100) { 100 dev_err(bus->parent, "Timeout when reading PHY\n"); 101 mutex_unlock(&dev->lock); 102 return -ETIMEDOUT; 103 } 104 105 udelay(10); 106 count++; 107 } 108 109 mutex_unlock(&dev->lock); 110 111 return val & 0xFFFF; 112 } 113 114 static int orion_mdio_write(struct mii_bus *bus, int mii_id, 115 int regnum, u16 value) 116 { 117 struct orion_mdio_dev *dev = bus->priv; 118 int ret; 119 120 mutex_lock(&dev->lock); 121 122 ret = orion_mdio_wait_ready(bus); 123 if (ret < 0) { 124 mutex_unlock(&dev->lock); 125 return ret; 126 } 127 128 writel(((mii_id << MVMDIO_SMI_PHY_ADDR_SHIFT) | 129 (regnum << MVMDIO_SMI_PHY_REG_SHIFT) | 130 MVMDIO_SMI_WRITE_OPERATION | 131 (value << MVMDIO_SMI_DATA_SHIFT)), 132 dev->smireg); 133 134 mutex_unlock(&dev->lock); 135 136 return 0; 137 } 138 139 static int orion_mdio_reset(struct mii_bus *bus) 140 { 141 return 0; 142 } 143 144 static int orion_mdio_probe(struct platform_device *pdev) 145 { 146 struct device_node *np = pdev->dev.of_node; 147 struct mii_bus *bus; 148 struct orion_mdio_dev *dev; 149 int i, ret; 150 151 bus = mdiobus_alloc_size(sizeof(struct orion_mdio_dev)); 152 if (!bus) { 153 dev_err(&pdev->dev, "Cannot allocate MDIO bus\n"); 154 return -ENOMEM; 155 } 156 157 bus->name = "orion_mdio_bus"; 158 bus->read = orion_mdio_read; 159 bus->write = orion_mdio_write; 160 bus->reset = orion_mdio_reset; 161 snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", 162 dev_name(&pdev->dev)); 163 bus->parent = &pdev->dev; 164 165 bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 166 if (!bus->irq) { 167 mdiobus_free(bus); 168 return -ENOMEM; 169 } 170 171 for (i = 0; i < PHY_MAX_ADDR; i++) 172 bus->irq[i] = PHY_POLL; 173 174 dev = bus->priv; 175 dev->smireg = of_iomap(pdev->dev.of_node, 0); 176 if (!dev->smireg) { 177 dev_err(&pdev->dev, "No SMI register address given in DT\n"); 178 kfree(bus->irq); 179 mdiobus_free(bus); 180 return -ENODEV; 181 } 182 183 mutex_init(&dev->lock); 184 185 ret = of_mdiobus_register(bus, np); 186 if (ret < 0) { 187 dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret); 188 iounmap(dev->smireg); 189 kfree(bus->irq); 190 mdiobus_free(bus); 191 return ret; 192 } 193 194 platform_set_drvdata(pdev, bus); 195 196 return 0; 197 } 198 199 static int orion_mdio_remove(struct platform_device *pdev) 200 { 201 struct mii_bus *bus = platform_get_drvdata(pdev); 202 mdiobus_unregister(bus); 203 kfree(bus->irq); 204 mdiobus_free(bus); 205 return 0; 206 } 207 208 static const struct of_device_id orion_mdio_match[] = { 209 { .compatible = "marvell,orion-mdio" }, 210 { } 211 }; 212 MODULE_DEVICE_TABLE(of, orion_mdio_match); 213 214 static struct platform_driver orion_mdio_driver = { 215 .probe = orion_mdio_probe, 216 .remove = orion_mdio_remove, 217 .driver = { 218 .name = "orion-mdio", 219 .of_match_table = orion_mdio_match, 220 }, 221 }; 222 223 module_platform_driver(orion_mdio_driver); 224 225 MODULE_DESCRIPTION("Marvell MDIO interface driver"); 226 MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>"); 227 MODULE_LICENSE("GPL"); 228