1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2014 4 * Dirk Eibach, Guntermann & Drunck GmbH, dirk.eibach@gdsys.cc 5 */ 6 7 #include <common.h> 8 9 #include <miiphy.h> 10 11 enum { 12 MIICMD_SET, 13 MIICMD_MODIFY, 14 MIICMD_VERIFY_VALUE, 15 MIICMD_WAIT_FOR_VALUE, 16 }; 17 18 struct mii_setupcmd { 19 u8 token; 20 u8 reg; 21 u16 data; 22 u16 mask; 23 u32 timeout; 24 }; 25 26 /* 27 * verify we are talking to a 88e1518 28 */ 29 struct mii_setupcmd verify_88e1518[] = { 30 { MIICMD_SET, 22, 0x0000 }, 31 { MIICMD_VERIFY_VALUE, 2, 0x0141, 0xffff }, 32 { MIICMD_VERIFY_VALUE, 3, 0x0dd0, 0xfff0 }, 33 }; 34 35 /* 36 * workaround for erratum mentioned in 88E1518 release notes 37 */ 38 struct mii_setupcmd fixup_88e1518[] = { 39 { MIICMD_SET, 22, 0x00ff }, 40 { MIICMD_SET, 17, 0x214b }, 41 { MIICMD_SET, 16, 0x2144 }, 42 { MIICMD_SET, 17, 0x0c28 }, 43 { MIICMD_SET, 16, 0x2146 }, 44 { MIICMD_SET, 17, 0xb233 }, 45 { MIICMD_SET, 16, 0x214d }, 46 { MIICMD_SET, 17, 0xcc0c }, 47 { MIICMD_SET, 16, 0x2159 }, 48 { MIICMD_SET, 22, 0x00fb }, 49 { MIICMD_SET, 7, 0xc00d }, 50 { MIICMD_SET, 22, 0x0000 }, 51 }; 52 53 /* 54 * default initialization: 55 * - set RGMII receive timing to "receive clock transition when data stable" 56 * - set RGMII transmit timing to "transmit clock internally delayed" 57 * - set RGMII output impedance target to 78,8 Ohm 58 * - run output impedance calibration 59 * - set autonegotiation advertise to 1000FD only 60 */ 61 struct mii_setupcmd default_88e1518[] = { 62 { MIICMD_SET, 22, 0x0002 }, 63 { MIICMD_MODIFY, 21, 0x0030, 0x0030 }, 64 { MIICMD_MODIFY, 25, 0x0000, 0x0003 }, 65 { MIICMD_MODIFY, 24, 0x8000, 0x8000 }, 66 { MIICMD_WAIT_FOR_VALUE, 24, 0x4000, 0x4000, 2000 }, 67 { MIICMD_SET, 22, 0x0000 }, 68 { MIICMD_MODIFY, 4, 0x0000, 0x01e0 }, 69 { MIICMD_MODIFY, 9, 0x0200, 0x0300 }, 70 }; 71 72 /* 73 * turn off CLK125 for PHY daughterboard 74 */ 75 struct mii_setupcmd ch1fix_88e1518[] = { 76 { MIICMD_SET, 22, 0x0002 }, 77 { MIICMD_MODIFY, 16, 0x0006, 0x0006 }, 78 { MIICMD_SET, 22, 0x0000 }, 79 }; 80 81 /* 82 * perform copper software reset 83 */ 84 struct mii_setupcmd swreset_88e1518[] = { 85 { MIICMD_SET, 22, 0x0000 }, 86 { MIICMD_MODIFY, 0, 0x8000, 0x8000 }, 87 { MIICMD_WAIT_FOR_VALUE, 0, 0x0000, 0x8000, 2000 }, 88 }; 89 90 /* 91 * special one for 88E1514: 92 * Force SGMII to Copper mode 93 */ 94 struct mii_setupcmd mii_to_copper_88e1514[] = { 95 { MIICMD_SET, 22, 0x0012 }, 96 { MIICMD_MODIFY, 20, 0x0001, 0x0007 }, 97 { MIICMD_MODIFY, 20, 0x8000, 0x8000 }, 98 { MIICMD_SET, 22, 0x0000 }, 99 }; 100 101 /* 102 * turn off SGMII auto-negotiation 103 */ 104 struct mii_setupcmd sgmii_autoneg_off_88e1518[] = { 105 { MIICMD_SET, 22, 0x0001 }, 106 { MIICMD_MODIFY, 0, 0x0000, 0x1000 }, 107 { MIICMD_MODIFY, 0, 0x8000, 0x8000 }, 108 { MIICMD_SET, 22, 0x0000 }, 109 }; 110 111 /* 112 * invert LED2 polarity 113 */ 114 struct mii_setupcmd invert_led2_88e1514[] = { 115 { MIICMD_SET, 22, 0x0003 }, 116 { MIICMD_MODIFY, 17, 0x0030, 0x0010 }, 117 { MIICMD_SET, 22, 0x0000 }, 118 }; 119 120 static int process_setupcmd(const char *bus, unsigned char addr, 121 struct mii_setupcmd *setupcmd) 122 { 123 int res; 124 u8 reg = setupcmd->reg; 125 u16 data = setupcmd->data; 126 u16 mask = setupcmd->mask; 127 u32 timeout = setupcmd->timeout; 128 u16 orig_data; 129 unsigned long start; 130 131 debug("mii %s:%u reg %2u ", bus, addr, reg); 132 133 switch (setupcmd->token) { 134 case MIICMD_MODIFY: 135 res = miiphy_read(bus, addr, reg, &orig_data); 136 if (res) 137 break; 138 debug("is %04x. (value %04x mask %04x) ", orig_data, data, 139 mask); 140 data = (orig_data & ~mask) | (data & mask); 141 /* fallthrough */ 142 case MIICMD_SET: 143 debug("=> %04x\n", data); 144 res = miiphy_write(bus, addr, reg, data); 145 break; 146 case MIICMD_VERIFY_VALUE: 147 res = miiphy_read(bus, addr, reg, &orig_data); 148 if (res) 149 break; 150 if ((orig_data & mask) != (data & mask)) 151 res = -1; 152 debug("(value %04x mask %04x) == %04x? %s\n", data, mask, 153 orig_data, res ? "FAIL" : "PASS"); 154 break; 155 case MIICMD_WAIT_FOR_VALUE: 156 res = -1; 157 start = get_timer(0); 158 while ((res != 0) && (get_timer(start) < timeout)) { 159 res = miiphy_read(bus, addr, reg, &orig_data); 160 if (res) 161 continue; 162 if ((orig_data & mask) != (data & mask)) 163 res = -1; 164 } 165 debug("(value %04x mask %04x) == %04x? %s after %lu ms\n", data, 166 mask, orig_data, res ? "FAIL" : "PASS", 167 get_timer(start)); 168 break; 169 default: 170 res = -1; 171 break; 172 } 173 174 return res; 175 } 176 177 static int process_setup(const char *bus, unsigned char addr, 178 struct mii_setupcmd *setupcmd, unsigned int count) 179 { 180 int res = 0; 181 unsigned int k; 182 183 for (k = 0; k < count; ++k) { 184 res = process_setupcmd(bus, addr, &setupcmd[k]); 185 if (res) { 186 printf("mii cmd %u on bus %s addr %u failed, aborting setup\n", 187 setupcmd[k].token, bus, addr); 188 break; 189 } 190 } 191 192 return res; 193 } 194 195 int setup_88e1518(const char *bus, unsigned char addr) 196 { 197 int res; 198 199 res = process_setup(bus, addr, 200 verify_88e1518, ARRAY_SIZE(verify_88e1518)); 201 if (res) 202 return res; 203 204 res = process_setup(bus, addr, 205 fixup_88e1518, ARRAY_SIZE(fixup_88e1518)); 206 if (res) 207 return res; 208 209 res = process_setup(bus, addr, 210 default_88e1518, ARRAY_SIZE(default_88e1518)); 211 if (res) 212 return res; 213 214 if (addr) { 215 res = process_setup(bus, addr, 216 ch1fix_88e1518, ARRAY_SIZE(ch1fix_88e1518)); 217 if (res) 218 return res; 219 } 220 221 res = process_setup(bus, addr, 222 swreset_88e1518, ARRAY_SIZE(swreset_88e1518)); 223 if (res) 224 return res; 225 226 return 0; 227 } 228 229 int setup_88e1514(const char *bus, unsigned char addr) 230 { 231 int res; 232 233 res = process_setup(bus, addr, 234 verify_88e1518, ARRAY_SIZE(verify_88e1518)); 235 if (res) 236 return res; 237 238 res = process_setup(bus, addr, 239 fixup_88e1518, ARRAY_SIZE(fixup_88e1518)); 240 if (res) 241 return res; 242 243 res = process_setup(bus, addr, 244 mii_to_copper_88e1514, 245 ARRAY_SIZE(mii_to_copper_88e1514)); 246 if (res) 247 return res; 248 249 res = process_setup(bus, addr, 250 sgmii_autoneg_off_88e1518, 251 ARRAY_SIZE(sgmii_autoneg_off_88e1518)); 252 if (res) 253 return res; 254 255 res = process_setup(bus, addr, 256 invert_led2_88e1514, 257 ARRAY_SIZE(invert_led2_88e1514)); 258 if (res) 259 return res; 260 261 res = process_setup(bus, addr, 262 default_88e1518, ARRAY_SIZE(default_88e1518)); 263 if (res) 264 return res; 265 266 if (addr) { 267 res = process_setup(bus, addr, 268 ch1fix_88e1518, ARRAY_SIZE(ch1fix_88e1518)); 269 if (res) 270 return res; 271 } 272 273 res = process_setup(bus, addr, 274 swreset_88e1518, ARRAY_SIZE(swreset_88e1518)); 275 if (res) 276 return res; 277 278 return 0; 279 } 280