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 dev_err(&pdev->dev, "Cannot allocate PHY IRQ array\n"); 168 mdiobus_free(bus); 169 return -ENOMEM; 170 } 171 172 for (i = 0; i < PHY_MAX_ADDR; i++) 173 bus->irq[i] = PHY_POLL; 174 175 dev = bus->priv; 176 dev->smireg = of_iomap(pdev->dev.of_node, 0); 177 if (!dev->smireg) { 178 dev_err(&pdev->dev, "No SMI register address given in DT\n"); 179 kfree(bus->irq); 180 mdiobus_free(bus); 181 return -ENODEV; 182 } 183 184 mutex_init(&dev->lock); 185 186 ret = of_mdiobus_register(bus, np); 187 if (ret < 0) { 188 dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret); 189 iounmap(dev->smireg); 190 kfree(bus->irq); 191 mdiobus_free(bus); 192 return ret; 193 } 194 195 platform_set_drvdata(pdev, bus); 196 197 return 0; 198 } 199 200 static int orion_mdio_remove(struct platform_device *pdev) 201 { 202 struct mii_bus *bus = platform_get_drvdata(pdev); 203 mdiobus_unregister(bus); 204 kfree(bus->irq); 205 mdiobus_free(bus); 206 return 0; 207 } 208 209 static const struct of_device_id orion_mdio_match[] = { 210 { .compatible = "marvell,orion-mdio" }, 211 { } 212 }; 213 MODULE_DEVICE_TABLE(of, orion_mdio_match); 214 215 static struct platform_driver orion_mdio_driver = { 216 .probe = orion_mdio_probe, 217 .remove = orion_mdio_remove, 218 .driver = { 219 .name = "orion-mdio", 220 .of_match_table = orion_mdio_match, 221 }, 222 }; 223 224 module_platform_driver(orion_mdio_driver); 225 226 MODULE_DESCRIPTION("Marvell MDIO interface driver"); 227 MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>"); 228 MODULE_LICENSE("GPL"); 229