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