uboot/drivers/net/phy/miiphybb.c
<<
>>
Prefs
   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
  23DECLARE_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 */
  33static 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
  41static 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
  50static 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
  59static 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
  68static 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
  77static 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
  86static int bb_delay_wrap(struct bb_miiphy_bus *bus)
  87{
  88        MIIDELAY;
  89        return 0;
  90}
  91
  92struct 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
 105int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) /
 106                          sizeof(bb_miiphy_buses[0]);
 107#endif
 108
 109void 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
 130static 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 */
 153static 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 */
 233int bb_miiphy_read(const char *devname, unsigned char addr,
 234                   unsigned char reg, unsigned short *value)
 235{
 236        short rdreg; /* register working value */
 237        int v;
 238        int j; /* counter */
 239        struct bb_miiphy_bus *bus;
 240
 241        bus = bb_miiphy_getbus(devname);
 242        if (bus == NULL) {
 243                return -1;
 244        }
 245
 246        if (value == NULL) {
 247                puts("NULL value pointer\n");
 248                return -1;
 249        }
 250
 251        miiphy_pre (bus, 1, addr, reg);
 252
 253        /* tri-state our MDIO I/O pin so we can read */
 254        bus->set_mdc(bus, 0);
 255        bus->mdio_tristate(bus);
 256        bus->delay(bus);
 257        bus->set_mdc(bus, 1);
 258        bus->delay(bus);
 259
 260        /* check the turnaround bit: the PHY should be driving it to zero */
 261        bus->get_mdio(bus, &v);
 262        if (v != 0) {
 263                /* puts ("PHY didn't drive TA low\n"); */
 264                for (j = 0; j < 32; j++) {
 265                        bus->set_mdc(bus, 0);
 266                        bus->delay(bus);
 267                        bus->set_mdc(bus, 1);
 268                        bus->delay(bus);
 269                }
 270                /* There is no PHY, set value to 0xFFFF and return */
 271                *value = 0xFFFF;
 272                return -1;
 273        }
 274
 275        bus->set_mdc(bus, 0);
 276        bus->delay(bus);
 277
 278        /* read 16 bits of register data, MSB first */
 279        rdreg = 0;
 280        for (j = 0; j < 16; j++) {
 281                bus->set_mdc(bus, 1);
 282                bus->delay(bus);
 283                rdreg <<= 1;
 284                bus->get_mdio(bus, &v);
 285                rdreg |= (v & 0x1);
 286                bus->set_mdc(bus, 0);
 287                bus->delay(bus);
 288        }
 289
 290        bus->set_mdc(bus, 1);
 291        bus->delay(bus);
 292        bus->set_mdc(bus, 0);
 293        bus->delay(bus);
 294        bus->set_mdc(bus, 1);
 295        bus->delay(bus);
 296
 297        *value = rdreg;
 298
 299#ifdef DEBUG
 300        printf ("miiphy_read(0x%x) @ 0x%x = 0x%04x\n", reg, addr, *value);
 301#endif
 302
 303        return 0;
 304}
 305
 306
 307/*****************************************************************************
 308 *
 309 * Write a MII PHY register.
 310 *
 311 * Returns:
 312 *   0 on success
 313 */
 314int bb_miiphy_write (const char *devname, unsigned char addr,
 315                     unsigned char reg, unsigned short value)
 316{
 317        struct bb_miiphy_bus *bus;
 318        int j;                  /* counter */
 319
 320        bus = bb_miiphy_getbus(devname);
 321        if (bus == NULL) {
 322                /* Bus not found! */
 323                return -1;
 324        }
 325
 326        miiphy_pre (bus, 0, addr, reg);
 327
 328        /* send the turnaround (10) */
 329        bus->set_mdc(bus, 0);
 330        bus->set_mdio(bus, 1);
 331        bus->delay(bus);
 332        bus->set_mdc(bus, 1);
 333        bus->delay(bus);
 334        bus->set_mdc(bus, 0);
 335        bus->set_mdio(bus, 0);
 336        bus->delay(bus);
 337        bus->set_mdc(bus, 1);
 338        bus->delay(bus);
 339
 340        /* write 16 bits of register data, MSB first */
 341        for (j = 0; j < 16; j++) {
 342                bus->set_mdc(bus, 0);
 343                if ((value & 0x00008000) == 0) {
 344                        bus->set_mdio(bus, 0);
 345                } else {
 346                        bus->set_mdio(bus, 1);
 347                }
 348                bus->delay(bus);
 349                bus->set_mdc(bus, 1);
 350                bus->delay(bus);
 351                value <<= 1;
 352        }
 353
 354        /*
 355         * Tri-state the MDIO line.
 356         */
 357        bus->mdio_tristate(bus);
 358        bus->set_mdc(bus, 0);
 359        bus->delay(bus);
 360        bus->set_mdc(bus, 1);
 361        bus->delay(bus);
 362
 363        return 0;
 364}
 365