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