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 13 static 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 28 static int cavium_mdiobus_c45_addr(struct cavium_mdiobus *p, 29 int phy_id, int devad, 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 smi_cmd.u64 = 0; 42 smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_45_ADDRESS */ 43 smi_cmd.s.phy_adr = phy_id; 44 smi_cmd.s.reg_adr = devad; 45 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); 46 47 do { 48 /* Wait 1000 clocks so we don't saturate the RSL bus 49 * doing reads. 50 */ 51 __delay(1000); 52 smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); 53 } while (smi_wr.s.pending && --timeout); 54 55 if (timeout <= 0) 56 return -EIO; 57 return 0; 58 } 59 60 int cavium_mdiobus_read_c22(struct mii_bus *bus, int phy_id, int regnum) 61 { 62 struct cavium_mdiobus *p = bus->priv; 63 union cvmx_smix_cmd smi_cmd; 64 union cvmx_smix_rd_dat smi_rd; 65 int timeout = 1000; 66 67 cavium_mdiobus_set_mode(p, C22); 68 69 smi_cmd.u64 = 0; 70 smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */ 71 smi_cmd.s.phy_adr = phy_id; 72 smi_cmd.s.reg_adr = regnum; 73 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); 74 75 do { 76 /* Wait 1000 clocks so we don't saturate the RSL bus 77 * doing reads. 78 */ 79 __delay(1000); 80 smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT); 81 } while (smi_rd.s.pending && --timeout); 82 83 if (smi_rd.s.val) 84 return smi_rd.s.dat; 85 else 86 return -EIO; 87 } 88 EXPORT_SYMBOL(cavium_mdiobus_read_c22); 89 90 int cavium_mdiobus_read_c45(struct mii_bus *bus, int phy_id, int devad, 91 int regnum) 92 { 93 struct cavium_mdiobus *p = bus->priv; 94 union cvmx_smix_cmd smi_cmd; 95 union cvmx_smix_rd_dat smi_rd; 96 int timeout = 1000; 97 int r; 98 99 r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum); 100 if (r < 0) 101 return r; 102 103 smi_cmd.u64 = 0; 104 smi_cmd.s.phy_op = 3; /* MDIO_CLAUSE_45_READ */ 105 smi_cmd.s.phy_adr = phy_id; 106 smi_cmd.s.reg_adr = regnum; 107 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); 108 109 do { 110 /* Wait 1000 clocks so we don't saturate the RSL bus 111 * doing reads. 112 */ 113 __delay(1000); 114 smi_rd.u64 = oct_mdio_readq(p->register_base + SMI_RD_DAT); 115 } while (smi_rd.s.pending && --timeout); 116 117 if (smi_rd.s.val) 118 return smi_rd.s.dat; 119 else 120 return -EIO; 121 } 122 EXPORT_SYMBOL(cavium_mdiobus_read_c45); 123 124 int cavium_mdiobus_write_c22(struct mii_bus *bus, int phy_id, int regnum, 125 u16 val) 126 { 127 struct cavium_mdiobus *p = bus->priv; 128 union cvmx_smix_cmd smi_cmd; 129 union cvmx_smix_wr_dat smi_wr; 130 int timeout = 1000; 131 132 cavium_mdiobus_set_mode(p, C22); 133 134 smi_wr.u64 = 0; 135 smi_wr.s.dat = val; 136 oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); 137 138 smi_cmd.u64 = 0; 139 smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */ 140 smi_cmd.s.phy_adr = phy_id; 141 smi_cmd.s.reg_adr = regnum; 142 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); 143 144 do { 145 /* Wait 1000 clocks so we don't saturate the RSL bus 146 * doing reads. 147 */ 148 __delay(1000); 149 smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); 150 } while (smi_wr.s.pending && --timeout); 151 152 if (timeout <= 0) 153 return -EIO; 154 155 return 0; 156 } 157 EXPORT_SYMBOL(cavium_mdiobus_write_c22); 158 159 int cavium_mdiobus_write_c45(struct mii_bus *bus, int phy_id, int devad, 160 int regnum, u16 val) 161 { 162 struct cavium_mdiobus *p = bus->priv; 163 union cvmx_smix_cmd smi_cmd; 164 union cvmx_smix_wr_dat smi_wr; 165 int timeout = 1000; 166 int r; 167 168 r = cavium_mdiobus_c45_addr(p, phy_id, devad, regnum); 169 if (r < 0) 170 return r; 171 172 smi_wr.u64 = 0; 173 smi_wr.s.dat = val; 174 oct_mdio_writeq(smi_wr.u64, p->register_base + SMI_WR_DAT); 175 176 smi_cmd.u64 = 0; 177 smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_45_WRITE */ 178 smi_cmd.s.phy_adr = phy_id; 179 smi_cmd.s.reg_adr = devad; 180 oct_mdio_writeq(smi_cmd.u64, p->register_base + SMI_CMD); 181 182 do { 183 /* Wait 1000 clocks so we don't saturate the RSL bus 184 * doing reads. 185 */ 186 __delay(1000); 187 smi_wr.u64 = oct_mdio_readq(p->register_base + SMI_WR_DAT); 188 } while (smi_wr.s.pending && --timeout); 189 190 if (timeout <= 0) 191 return -EIO; 192 193 return 0; 194 } 195 EXPORT_SYMBOL(cavium_mdiobus_write_c45); 196 197 MODULE_DESCRIPTION("Common code for OCTEON and Thunder MDIO bus drivers"); 198 MODULE_AUTHOR("David Daney"); 199 MODULE_LICENSE("GPL v2"); 200