uboot/drivers/net/phy/miiphybb.c
<<
>>
Prefs
   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
  22DECLARE_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 */
  32static 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
  40static 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
  49static 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
  58static 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
  67static 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
  76static 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
  85static int bb_delay_wrap(struct bb_miiphy_bus *bus)
  86{
  87        MIIDELAY;
  88        return 0;
  89}
  90
  91struct 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
 104int bb_miiphy_buses_num = sizeof(bb_miiphy_buses) /
 105                          sizeof(bb_miiphy_buses[0]);
 106#endif
 107
 108void 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
 129static 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 */
 152static 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 */
 232int 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 */
 304int 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