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