mdio-cavium.c (3479B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2009-2016 Cavium, Inc. 4 */ 5 6#include <linux/delay.h> 7#include <linux/io.h> 8#include <linux/module.h> 9#include <linux/phy.h> 10 11#include "mdio-cavium.h" 12 13static void cavium_mdiobus_set_mode(struct cavium_mdiobus *p, 14 enum cavium_mdiobus_mode m) 15{ 16 union cvmx_smix_clk smi_clk; 17 18 if (m == p->mode) 19 return; 20 21 smi_clk.u64 = oct_mdio_readq(p->register_base + SMI_CLK); 22 smi_clk.s.mode = (m == C45) ? 1 : 0; 23 smi_clk.s.preamble = 1; 24 oct_mdio_writeq(smi_clk.u64, p->register_base + SMI_CLK); 25 p->mode = m; 26} 27 28static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p, 29 int phy_id, int regnum) 30{ 31 union cvmx_smix_cmd smi_cmd; 32 union cvmx_smix_wr_dat smi_wr; 33 int timeout = 1000; 34 35 cavium_mdiobus_set_mode(p, C45); 36 37 smi_wr.u64 = 0; 38 smi_wr.s.dat = regnum & 0xffff; 39 oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); 40 41 regnum = (regnum >> 16) & 0x1f; 42 43 smi_cmd.u64 = 0; 44 smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */ 45 smi_cmd.s.phy_adr = phy_id; 46 smi_cmd.s.reg_adr = regnum; 47 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); 48 49 do { 50 /* Wait 1000 clocks so we don't saturate the RSL bus 51 * doing reads. 52 */ 53 __delay(1000); 54 smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); 55 } while (smi_wr.s.pending && --timeout); 56 57 if (timeout <= 0) 58 return -EIO; 59 return 0; 60} 61 62int cavium_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum) 63{ 64 struct cavium_mdiobus *p = bus->priv; 65 union cvmx_smix_cmd smi_cmd; 66 union cvmx_smix_rd_dat smi_rd; 67 unsigned int op = 1; /* MDIO_CLAUSE_22_READ */ 68 int timeout = 1000; 69 70 if (regnum & MII_ADDR_C45) { 71 int r = cavium_mdiobus_c45_addr(p, phy_id, regnum); 72 73 if (r < 0) 74 return r; 75 76 regnum = (regnum >> 16) & 0x1f; 77 op = 3; /* MDIO_CLAUSE_45_READ */ 78 } else { 79 cavium_mdiobus_set_mode(p, C22); 80 } 81 82 smi_cmd.u64 = 0; 83 smi_cmd.s.phy_op = op; 84 smi_cmd.s.phy_adr = phy_id; 85 smi_cmd.s.reg_adr = regnum; 86 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); 87 88 do { 89 /* Wait 1000 clocks so we don't saturate the RSL bus 90 * doing reads. 91 */ 92 __delay(1000); 93 smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT); 94 } while (smi_rd.s.pending && --timeout); 95 96 if (smi_rd.s.val) 97 return smi_rd.s.dat; 98 else 99 return -EIO; 100} 101EXPORT_SYMBOL(cavium_mdiobus_read); 102 103int cavium_mdiobus_write(struct mii_bus *bus, int phy_id, int regnum, u16 val) 104{ 105 struct cavium_mdiobus *p = bus->priv; 106 union cvmx_smix_cmd smi_cmd; 107 union cvmx_smix_wr_dat smi_wr; 108 unsigned int op = 0; /* MDIO_CLAUSE_22_WRITE */ 109 int timeout = 1000; 110 111 if (regnum & MII_ADDR_C45) { 112 int r = cavium_mdiobus_c45_addr(p, phy_id, regnum); 113 114 if (r < 0) 115 return r; 116 117 regnum = (regnum >> 16) & 0x1f; 118 op = 1; /* MDIO_CLAUSE_45_WRITE */ 119 } else { 120 cavium_mdiobus_set_mode(p, C22); 121 } 122 123 smi_wr.u64 = 0; 124 smi_wr.s.dat = val; 125 oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); 126 127 smi_cmd.u64 = 0; 128 smi_cmd.s.phy_op = op; 129 smi_cmd.s.phy_adr = phy_id; 130 smi_cmd.s.reg_adr = regnum; 131 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); 132 133 do { 134 /* Wait 1000 clocks so we don't saturate the RSL bus 135 * doing reads. 136 */ 137 __delay(1000); 138 smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); 139 } while (smi_wr.s.pending && --timeout); 140 141 if (timeout <= 0) 142 return -EIO; 143 144 return 0; 145} 146EXPORT_SYMBOL(cavium_mdiobus_write); 147 148MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers"); 149MODULE_AUTHOR("David Daney"); 150MODULE_LICENSE("GPL v2");