1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2009-2012 Cavium, Inc. 7 */ 8 9#include <linux/platform_device.h> 10#include <linux/of_mdio.h> 11#include <linux/delay.h> 12#include <linux/module.h> 13#include <linux/gfp.h> 14#include <linux/phy.h> 15#include <linux/io.h> 16 17#include <asm/octeon/octeon.h> 18#include <asm/octeon/cvmx-smix-defs.h> 19 20#define DRV_VERSION "1.0" 21#define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver" 22 23#define SMI_CMD 0x0 24#define SMI_WR_DAT 0x8 25#define SMI_RD_DAT 0x10 26#define SMI_CLK 0x18 27#define SMI_EN 0x20 28 29enum octeon_mdiobus_mode { 30 UNINIT = 0, 31 C22, 32 C45 33}; 34 35struct octeon_mdiobus { 36 struct mii_bus *mii_bus; 37 u64 register_base; 38 resource_size_t mdio_phys; 39 resource_size_t regsize; 40 enum octeon_mdiobus_mode mode; 41 int phy_irq[PHY_MAX_ADDR]; 42}; 43 44static void octeon_mdiobus_set_mode(struct octeon_mdiobus *p, 45 enum octeon_mdiobus_mode m) 46{ 47 union cvmx_smix_clk smi_clk; 48 49 if (m == p->mode) 50 return; 51 52 smi_clk.u64 = cvmx_read_csr(p->register_base + SMI_CLK); 53 smi_clk.s.mode = (m == C45) ? 1 : 0; 54 smi_clk.s.preamble = 1; 55 cvmx_write_csr(p->register_base + SMI_CLK, smi_clk.u64); 56 p->mode = m; 57} 58 59static int octeon_mdiobus_c45_addr(struct octeon_mdiobus *p, 60 int phy_id, int regnum) 61{ 62 union cvmx_smix_cmd smi_cmd; 63 union cvmx_smix_wr_dat smi_wr; 64 int timeout = 1000; 65 66 octeon_mdiobus_set_mode(p, C45); 67 68 smi_wr.u64 = 0; 69 smi_wr.s.dat = regnum & 0xffff; 70 cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64); 71 72 regnum = (regnum >> 16) & 0x1f; 73 74 smi_cmd.u64 = 0; 75 smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */ 76 smi_cmd.s.phy_adr = phy_id; 77 smi_cmd.s.reg_adr = regnum; 78 cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); 79 80 do { 81 /* Wait 1000 clocks so we don't saturate the RSL bus 82 * doing reads. 83 */ 84 __delay(1000); 85 smi_wr.u64 = cvmx_read_csr(p->register_base + SMI_WR_DAT); 86 } while (smi_wr.s.pending && --timeout); 87 88 if (timeout <= 0) 89 return -EIO; 90 return 0; 91} 92 93static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) 94{ 95 struct octeon_mdiobus *p = bus->priv; 96 union cvmx_smix_cmd smi_cmd; 97 union cvmx_smix_rd_dat smi_rd; 98 unsigned int op = 1; /* MDIO_CLAUSE_22_READ */ 99 int timeout = 1000; 100 101 if (regnum & MII_ADDR_C45) { 102 int r = octeon_mdiobus_c45_addr(p, phy_id, regnum); 103 if (r < 0) 104 return r; 105 106 regnum = (regnum >> 16) & 0x1f; 107 op = 3; /* MDIO_CLAUSE_45_READ */ 108 } else { 109 octeon_mdiobus_set_mode(p, C22); 110 } 111 112 113 smi_cmd.u64 = 0; 114 smi_cmd.s.phy_op = op; 115 smi_cmd.s.phy_adr = phy_id; 116 smi_cmd.s.reg_adr = regnum; 117 cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); 118 119 do { 120 /* Wait 1000 clocks so we don't saturate the RSL bus 121 * doing reads. 122 */ 123 __delay(1000); 124 smi_rd.u64 = cvmx_read_csr(p->register_base + SMI_RD_DAT); 125 } while (smi_rd.s.pending && --timeout); 126 127 if (smi_rd.s.val) 128 return smi_rd.s.dat; 129 else 130 return -EIO; 131} 132 133static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id, 134 int regnum, u16 val) 135{ 136 struct octeon_mdiobus *p = bus->priv; 137 union cvmx_smix_cmd smi_cmd; 138 union cvmx_smix_wr_dat smi_wr; 139 unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */ 140 int timeout = 1000; 141 142 143 if (regnum & MII_ADDR_C45) { 144 int r = octeon_mdiobus_c45_addr(p, phy_id, regnum); 145 if (r < 0) 146 return r; 147 148 regnum = (regnum >> 16) & 0x1f; 149 op = 1; /* MDIO_CLAUSE_45_WRITE */ 150 } else { 151 octeon_mdiobus_set_mode(p, C22); 152 } 153 154 smi_wr.u64 = 0; 155 smi_wr.s.dat = val; 156 cvmx_write_csr(p->register_base + SMI_WR_DAT, smi_wr.u64); 157 158 smi_cmd.u64 = 0; 159 smi_cmd.s.phy_op = op; 160 smi_cmd.s.phy_adr = phy_id; 161 smi_cmd.s.reg_adr = regnum; 162 cvmx_write_csr(p->register_base + SMI_CMD, smi_cmd.u64); 163 164 do { 165 /* Wait 1000 clocks so we don't saturate the RSL bus 166 * doing reads. 167 */ 168 __delay(1000); 169 smi_wr.u64 = cvmx_read_csr(p->register_base + SMI_WR_DAT); 170 } while (smi_wr.s.pending && --timeout); 171 172 if (timeout <= 0) 173 return -EIO; 174 175 return 0; 176} 177 178static int octeon_mdiobus_probe(struct platform_device *pdev) 179{ 180 struct octeon_mdiobus *bus; 181 struct resource *res_mem; 182 union cvmx_smix_en smi_en; 183 int err = -ENOENT; 184 185 bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL); 186 if (!bus) 187 return -ENOMEM; 188 189 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 190 191 if (res_mem == NULL) { 192 dev_err(&pdev->dev, "found no memory resource\n"); 193 err = -ENXIO; 194 goto fail; 195 } 196 bus->mdio_phys = res_mem->start; 197 bus->regsize = resource_size(res_mem); 198 if (!devm_request_mem_region(&pdev->dev, bus->mdio_phys, bus->regsize, 199 res_mem->name)) { 200 dev_err(&pdev->dev, "request_mem_region failed\n"); 201 goto fail; 202 } 203 bus->register_base = 204 (u64)devm_ioremap(&pdev->dev, bus->mdio_phys, bus->regsize); 205 206 bus->mii_bus = mdiobus_alloc(); 207 208 if (!bus->mii_bus) 209 goto fail; 210 211 smi_en.u64 = 0; 212 smi_en.s.en = 1; 213 cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64); 214 215 bus->mii_bus->priv = bus; 216 bus->mii_bus->irq = bus->phy_irq; 217 bus->mii_bus->name = "mdio-octeon"; 218 snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base); 219 bus->mii_bus->parent = &pdev->dev; 220 221 bus->mii_bus->read = octeon_mdiobus_read; 222 bus->mii_bus->write = octeon_mdiobus_write; 223 224 platform_set_drvdata(pdev, bus); 225 226 err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node); 227 if (err) 228 goto fail_register; 229 230 dev_info(&pdev->dev, "Version " DRV_VERSION "\n"); 231 232 return 0; 233fail_register: 234 mdiobus_free(bus->mii_bus); 235fail: 236 smi_en.u64 = 0; 237 cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64); 238 return err; 239} 240 241static int octeon_mdiobus_remove(struct platform_device *pdev) 242{ 243 struct octeon_mdiobus *bus; 244 union cvmx_smix_en smi_en; 245 246 bus = platform_get_drvdata(pdev); 247 248 mdiobus_unregister(bus->mii_bus); 249 mdiobus_free(bus->mii_bus); 250 smi_en.u64 = 0; 251 cvmx_write_csr(bus->register_base + SMI_EN, smi_en.u64); 252 return 0; 253} 254 255static const struct of_device_id octeon_mdiobus_match[] = { 256 { 257 .compatible = "cavium,octeon-3860-mdio", 258 }, 259 {}, 260}; 261MODULE_DEVICE_TABLE(of, octeon_mdiobus_match); 262 263static struct platform_driver octeon_mdiobus_driver = { 264 .driver = { 265 .name = "mdio-octeon", 266 .of_match_table = octeon_mdiobus_match, 267 }, 268 .probe = octeon_mdiobus_probe, 269 .remove = octeon_mdiobus_remove, 270}; 271 272void octeon_mdiobus_force_mod_depencency(void) 273{ 274 /* Let ethernet drivers force us to be loaded. */ 275} 276EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency); 277 278module_platform_driver(octeon_mdiobus_driver); 279 280MODULE_DESCRIPTION(DRV_DESCRIPTION); 281MODULE_VERSION(DRV_VERSION); 282MODULE_AUTHOR("David Daney"); 283MODULE_LICENSE("GPL"); 284