1 /* 2 * (C) Copyright 2009 Industrie Dial Face S.p.A. 3 * Luigi 'Comio' Mantellini <luigi.mantellini@idf-hit.com> 4 * 5 * (C) Copyright 2001 6 * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com. 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 /* 12 * This provides a bit-banged interface to the ethernet MII management 13 * channel. 14 */ 15 16 #include <common.h> 17 #include <ioports.h> 18 #include <ppc_asm.tmpl> 19 #include <miiphy.h> 20 21 #define BB_MII_RELOCATE(v,off) (v += (v?off:0)) 22 23 DECLARE_GLOBAL_DATA_PTR; 24 25 #ifndef CONFIG_BITBANGMII_MULTI 26 27 /* 28 * If CONFIG_BITBANGMII_MULTI is not defined we use a 29 * compatibility layer with the previous miiphybb implementation 30 * based on macros usage. 31 * 32 */ 33 static int bb_mii_init_wrap(struct bb_miiphy_bus *bus) 34 { 35 #ifdef MII_INIT 36 MII_INIT; 37 #endif 38 return 0; 39 } 40 41 static int bb_mdio_active_wrap(struct bb_miiphy_bus *bus) 42 { 43 #ifdef MDIO_DECLARE 44 MDIO_DECLARE; 45 #endif 46 MDIO_ACTIVE; 47 return 0; 48 } 49 50 static int bb_mdio_tristate_wrap(struct bb_miiphy_bus *bus) 51 { 52 #ifdef MDIO_DECLARE 53 MDIO_DECLARE; 54 #endif 55 MDIO_TRISTATE; 56 return 0; 57 } 58 59 static int bb_set_mdio_wrap(struct bb_miiphy_bus *bus, int v) 60 { 61 #ifdef MDIO_DECLARE 62 MDIO_DECLARE; 63 #endif 64 MDIO(v); 65 return 0; 66 } 67 68 static int bb_get_mdio_wrap(struct bb_miiphy_bus *bus, int *v) 69 { 70 #ifdef MDIO_DECLARE 71 MDIO_DECLARE; 72 #endif 73 *v = MDIO_READ; 74 return 0; 75 } 76 77 static int bb_set_mdc_wrap(struct bb_miiphy_bus *bus, int v) 78 { 79 #ifdef MDC_DECLARE 80 MDC_DECLARE; 81 #endif 82 MDC(v); 83 return 0; 84 } 85 86 static int bb_delay_wrap(struct bb_miiphy_bus *bus) 87 { 88 MIIDELAY; 89 return 0; 90 } 91 92 struct bb_miiphy_bus bb_miiphy_buses[] = { 93 { 94 .name = BB_MII_DEVNAME, 95 .init = bb_mii_init_wrap, 96 .mdio_active = bb_mdio_active_wrap, 97 .mdio_tristate = bb_mdio_tristate_wrap, 98 .set_mdio = bb_set_mdio_wrap, 99 .get_mdio = bb_get_mdio_wrap, 100 .set_mdc = bb_set_mdc_wrap, 101 .delay = bb_delay_wrap, 102 } 103 }; 104 105 int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) / 106 sizeof(bb_miiphy_buses[0]); 107 #endif 108 109 void bb_miiphy_init(void) 110 { 111 int i; 112 113 for (i = 0; i < bb_miiphy_buses_num; i++) { 114 #if defined(CONFIG_NEEDS_MANUAL_RELOC) 115 /* Relocate the hook pointers*/ 116 BB_MII_RELOCATE(bb_miiphy_buses[i].init, gd->reloc_off); 117 BB_MII_RELOCATE(bb_miiphy_buses[i].mdio_active, gd->reloc_off); 118 BB_MII_RELOCATE(bb_miiphy_buses[i].mdio_tristate, gd->reloc_off); 119 BB_MII_RELOCATE(bb_miiphy_buses[i].set_mdio, gd->reloc_off); 120 BB_MII_RELOCATE(bb_miiphy_buses[i].get_mdio, gd->reloc_off); 121 BB_MII_RELOCATE(bb_miiphy_buses[i].set_mdc, gd->reloc_off); 122 BB_MII_RELOCATE(bb_miiphy_buses[i].delay, gd->reloc_off); 123 #endif 124 if (bb_miiphy_buses[i].init != NULL) { 125 bb_miiphy_buses[i].init(&bb_miiphy_buses[i]); 126 } 127 } 128 } 129 130 static inline struct bb_miiphy_bus *bb_miiphy_getbus(const char *devname) 131 { 132 #ifdef CONFIG_BITBANGMII_MULTI 133 int i; 134 135 /* Search the correct bus */ 136 for (i = 0; i < bb_miiphy_buses_num; i++) { 137 if (!strcmp(bb_miiphy_buses[i].name, devname)) { 138 return &bb_miiphy_buses[i]; 139 } 140 } 141 return NULL; 142 #else 143 /* We have just one bitbanging bus */ 144 return &bb_miiphy_buses[0]; 145 #endif 146 } 147 148 /***************************************************************************** 149 * 150 * Utility to send the preamble, address, and register (common to read 151 * and write). 152 */ 153 static void miiphy_pre(struct bb_miiphy_bus *bus, char read, 154 unsigned char addr, unsigned char reg) 155 { 156 int j; 157 158 /* 159 * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. 160 * The IEEE spec says this is a PHY optional requirement. The AMD 161 * 79C874 requires one after power up and one after a MII communications 162 * error. This means that we are doing more preambles than we need, 163 * but it is safer and will be much more robust. 164 */ 165 166 bus->mdio_active(bus); 167 bus->set_mdio(bus, 1); 168 for (j = 0; j < 32; j++) { 169 bus->set_mdc(bus, 0); 170 bus->delay(bus); 171 bus->set_mdc(bus, 1); 172 bus->delay(bus); 173 } 174 175 /* send the start bit (01) and the read opcode (10) or write (10) */ 176 bus->set_mdc(bus, 0); 177 bus->set_mdio(bus, 0); 178 bus->delay(bus); 179 bus->set_mdc(bus, 1); 180 bus->delay(bus); 181 bus->set_mdc(bus, 0); 182 bus->set_mdio(bus, 1); 183 bus->delay(bus); 184 bus->set_mdc(bus, 1); 185 bus->delay(bus); 186 bus->set_mdc(bus, 0); 187 bus->set_mdio(bus, read); 188 bus->delay(bus); 189 bus->set_mdc(bus, 1); 190 bus->delay(bus); 191 bus->set_mdc(bus, 0); 192 bus->set_mdio(bus, !read); 193 bus->delay(bus); 194 bus->set_mdc(bus, 1); 195 bus->delay(bus); 196 197 /* send the PHY address */ 198 for (j = 0; j < 5; j++) { 199 bus->set_mdc(bus, 0); 200 if ((addr & 0x10) == 0) { 201 bus->set_mdio(bus, 0); 202 } else { 203 bus->set_mdio(bus, 1); 204 } 205 bus->delay(bus); 206 bus->set_mdc(bus, 1); 207 bus->delay(bus); 208 addr <<= 1; 209 } 210 211 /* send the register address */ 212 for (j = 0; j < 5; j++) { 213 bus->set_mdc(bus, 0); 214 if ((reg & 0x10) == 0) { 215 bus->set_mdio(bus, 0); 216 } else { 217 bus->set_mdio(bus, 1); 218 } 219 bus->delay(bus); 220 bus->set_mdc(bus, 1); 221 bus->delay(bus); 222 reg <<= 1; 223 } 224 } 225 226 /***************************************************************************** 227 * 228 * Read a MII PHY register. 229 * 230 * Returns: 231 * 0 on success 232 */ 233 int bb_miiphy_read(struct mii_dev *miidev, int addr, int devad, int reg) 234 { 235 short rdreg; /* register working value */ 236 int v; 237 int j; /* counter */ 238 struct bb_miiphy_bus *bus; 239 240 bus = bb_miiphy_getbus(miidev->name); 241 if (bus == NULL) { 242 return -1; 243 } 244 245 miiphy_pre (bus, 1, addr, reg); 246 247 /* tri-state our MDIO I/O pin so we can read */ 248 bus->set_mdc(bus, 0); 249 bus->mdio_tristate(bus); 250 bus->delay(bus); 251 bus->set_mdc(bus, 1); 252 bus->delay(bus); 253 254 /* check the turnaround bit: the PHY should be driving it to zero */ 255 bus->get_mdio(bus, &v); 256 if (v != 0) { 257 /* puts ("PHY didn't drive TA low\n"); */ 258 for (j = 0; j < 32; j++) { 259 bus->set_mdc(bus, 0); 260 bus->delay(bus); 261 bus->set_mdc(bus, 1); 262 bus->delay(bus); 263 } 264 /* There is no PHY, return */ 265 return -1; 266 } 267 268 bus->set_mdc(bus, 0); 269 bus->delay(bus); 270 271 /* read 16 bits of register data, MSB first */ 272 rdreg = 0; 273 for (j = 0; j < 16; j++) { 274 bus->set_mdc(bus, 1); 275 bus->delay(bus); 276 rdreg <<= 1; 277 bus->get_mdio(bus, &v); 278 rdreg |= (v & 0x1); 279 bus->set_mdc(bus, 0); 280 bus->delay(bus); 281 } 282 283 bus->set_mdc(bus, 1); 284 bus->delay(bus); 285 bus->set_mdc(bus, 0); 286 bus->delay(bus); 287 bus->set_mdc(bus, 1); 288 bus->delay(bus); 289 290 #ifdef DEBUG 291 printf("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, rdreg); 292 #endif 293 294 return rdreg; 295 } 296 297 298 /***************************************************************************** 299 * 300 * Write a MII PHY register. 301 * 302 * Returns: 303 * 0 on success 304 */ 305 int bb_miiphy_write(struct mii_dev *miidev, int addr, int devad, int reg, 306 u16 value) 307 { 308 struct bb_miiphy_bus *bus; 309 int j; /* counter */ 310 311 bus = bb_miiphy_getbus(miidev->name); 312 if (bus == NULL) { 313 /* Bus not found! */ 314 return -1; 315 } 316 317 miiphy_pre (bus, 0, addr, reg); 318 319 /* send the turnaround (10) */ 320 bus->set_mdc(bus, 0); 321 bus->set_mdio(bus, 1); 322 bus->delay(bus); 323 bus->set_mdc(bus, 1); 324 bus->delay(bus); 325 bus->set_mdc(bus, 0); 326 bus->set_mdio(bus, 0); 327 bus->delay(bus); 328 bus->set_mdc(bus, 1); 329 bus->delay(bus); 330 331 /* write 16 bits of register data, MSB first */ 332 for (j = 0; j < 16; j++) { 333 bus->set_mdc(bus, 0); 334 if ((value & 0x00008000) == 0) { 335 bus->set_mdio(bus, 0); 336 } else { 337 bus->set_mdio(bus, 1); 338 } 339 bus->delay(bus); 340 bus->set_mdc(bus, 1); 341 bus->delay(bus); 342 value <<= 1; 343 } 344 345 /* 346 * Tri-state the MDIO line. 347 */ 348 bus->mdio_tristate(bus); 349 bus->set_mdc(bus, 0); 350 bus->delay(bus); 351 bus->set_mdc(bus, 1); 352 bus->delay(bus); 353 354 return 0; 355 } 356