uboot/board/gdsys/common/phy.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2014
   3 * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.de
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9
  10#include <miiphy.h>
  11
  12enum {
  13        MIICMD_SET,
  14        MIICMD_MODIFY,
  15        MIICMD_VERIFY_VALUE,
  16        MIICMD_WAIT_FOR_VALUE,
  17};
  18
  19struct mii_setupcmd {
  20        u8 token;
  21        u8 reg;
  22        u16 data;
  23        u16 mask;
  24        u32 timeout;
  25};
  26
  27/*
  28 * verify we are talking to a 88e1518
  29 */
  30struct mii_setupcmd verify_88e1518[] = {
  31        { MIICMD_SET, 22, 0x0000 },
  32        { MIICMD_VERIFY_VALUE, 2, 0x0141, 0xffff },
  33        { MIICMD_VERIFY_VALUE, 3, 0x0dd0, 0xfff0 },
  34};
  35
  36/*
  37 * workaround for erratum mentioned in 88E1518 release notes
  38 */
  39struct mii_setupcmd fixup_88e1518[] = {
  40        { MIICMD_SET, 22, 0x00ff },
  41        { MIICMD_SET, 17, 0x214b },
  42        { MIICMD_SET, 16, 0x2144 },
  43        { MIICMD_SET, 17, 0x0c28 },
  44        { MIICMD_SET, 16, 0x2146 },
  45        { MIICMD_SET, 17, 0xb233 },
  46        { MIICMD_SET, 16, 0x214d },
  47        { MIICMD_SET, 17, 0xcc0c },
  48        { MIICMD_SET, 16, 0x2159 },
  49        { MIICMD_SET, 22, 0x00fb },
  50        { MIICMD_SET,  7, 0xc00d },
  51        { MIICMD_SET, 22, 0x0000 },
  52};
  53
  54/*
  55 * default initialization:
  56 * - set RGMII receive timing to "receive clock transition when data stable"
  57 * - set RGMII transmit timing to "transmit clock internally delayed"
  58 * - set RGMII output impedance target to 78,8 Ohm
  59 * - run output impedance calibration
  60 * - set autonegotiation advertise to 1000FD only
  61 */
  62struct mii_setupcmd default_88e1518[] = {
  63        { MIICMD_SET, 22, 0x0002 },
  64        { MIICMD_MODIFY, 21, 0x0030, 0x0030 },
  65        { MIICMD_MODIFY, 25, 0x0000, 0x0003 },
  66        { MIICMD_MODIFY, 24, 0x8000, 0x8000 },
  67        { MIICMD_WAIT_FOR_VALUE, 24, 0x4000, 0x4000, 2000 },
  68        { MIICMD_SET, 22, 0x0000 },
  69        { MIICMD_MODIFY, 4, 0x0000, 0x01e0 },
  70        { MIICMD_MODIFY, 9, 0x0200, 0x0300 },
  71};
  72
  73/*
  74 * turn off CLK125 for PHY daughterboard
  75 */
  76struct mii_setupcmd ch1fix_88e1518[] = {
  77        { MIICMD_SET, 22, 0x0002 },
  78        { MIICMD_MODIFY, 16, 0x0006, 0x0006 },
  79        { MIICMD_SET, 22, 0x0000 },
  80};
  81
  82/*
  83 * perform copper software reset
  84 */
  85struct mii_setupcmd swreset_88e1518[] = {
  86        { MIICMD_SET, 22, 0x0000 },
  87        { MIICMD_MODIFY, 0, 0x8000, 0x8000 },
  88        { MIICMD_WAIT_FOR_VALUE, 0, 0x0000, 0x8000, 2000 },
  89};
  90
  91/*
  92 * special one for 88E1514:
  93 * Force SGMII to Copper mode
  94 */
  95struct mii_setupcmd mii_to_copper_88e1514[] = {
  96        { MIICMD_SET, 22, 0x0012 },
  97        { MIICMD_MODIFY, 20, 0x0001, 0x0007 },
  98        { MIICMD_MODIFY, 20, 0x8000, 0x8000 },
  99        { MIICMD_SET, 22, 0x0000 },
 100};
 101
 102/*
 103 * turn off SGMII auto-negotiation
 104 */
 105struct mii_setupcmd sgmii_autoneg_off_88e1518[] = {
 106        { MIICMD_SET, 22, 0x0001 },
 107        { MIICMD_MODIFY, 0, 0x0000, 0x1000 },
 108        { MIICMD_MODIFY, 0, 0x8000, 0x8000 },
 109        { MIICMD_SET, 22, 0x0000 },
 110};
 111
 112/*
 113 * invert LED2 polarity
 114 */
 115struct mii_setupcmd invert_led2_88e1514[] = {
 116        { MIICMD_SET, 22, 0x0003 },
 117        { MIICMD_MODIFY, 17, 0x0030, 0x0010 },
 118        { MIICMD_SET, 22, 0x0000 },
 119};
 120
 121static int process_setupcmd(const char *bus, unsigned char addr,
 122                            struct mii_setupcmd *setupcmd)
 123{
 124        int res;
 125        u8 reg = setupcmd->reg;
 126        u16 data = setupcmd->data;
 127        u16 mask = setupcmd->mask;
 128        u32 timeout = setupcmd->timeout;
 129        u16 orig_data;
 130        unsigned long start;
 131
 132        debug("mii %s:%u reg %2u ", bus, addr, reg);
 133
 134        switch (setupcmd->token) {
 135        case MIICMD_MODIFY:
 136                res = miiphy_read(bus, addr, reg, &orig_data);
 137                if (res)
 138                        break;
 139                debug("is %04x. (value %04x mask %04x) ", orig_data, data,
 140                      mask);
 141                data = (orig_data & ~mask) | (data & mask);
 142                /* fallthrough */
 143        case MIICMD_SET:
 144                debug("=> %04x\n", data);
 145                res = miiphy_write(bus, addr, reg, data);
 146                break;
 147        case MIICMD_VERIFY_VALUE:
 148                res = miiphy_read(bus, addr, reg, &orig_data);
 149                if (res)
 150                        break;
 151                if ((orig_data & mask) != (data & mask))
 152                        res = -1;
 153                debug("(value %04x mask %04x) == %04x? %s\n", data, mask,
 154                      orig_data, res ? "FAIL" : "PASS");
 155                break;
 156        case MIICMD_WAIT_FOR_VALUE:
 157                res = -1;
 158                start = get_timer(0);
 159                while ((res != 0) && (get_timer(start) < timeout)) {
 160                        res = miiphy_read(bus, addr, reg, &orig_data);
 161                        if (res)
 162                                continue;
 163                        if ((orig_data & mask) != (data & mask))
 164                                res = -1;
 165                }
 166                debug("(value %04x mask %04x) == %04x? %s after %lu ms\n", data,
 167                      mask, orig_data, res ? "FAIL" : "PASS",
 168                      get_timer(start));
 169                break;
 170        default:
 171                res = -1;
 172                break;
 173        }
 174
 175        return res;
 176}
 177
 178static int process_setup(const char *bus, unsigned char addr,
 179                            struct mii_setupcmd *setupcmd, unsigned int count)
 180{
 181        int res = 0;
 182        unsigned int k;
 183
 184        for (k = 0; k < count; ++k) {
 185                res = process_setupcmd(bus, addr, &setupcmd[k]);
 186                if (res) {
 187                        printf("mii cmd %u on bus %s addr %u failed, aborting setup\n",
 188                               setupcmd[k].token, bus, addr);
 189                        break;
 190                }
 191        }
 192
 193        return res;
 194}
 195
 196int setup_88e1518(const char *bus, unsigned char addr)
 197{
 198        int res;
 199
 200        res = process_setup(bus, addr,
 201                            verify_88e1518, ARRAY_SIZE(verify_88e1518));
 202        if (res)
 203                return res;
 204
 205        res = process_setup(bus, addr,
 206                            fixup_88e1518, ARRAY_SIZE(fixup_88e1518));
 207        if (res)
 208                return res;
 209
 210        res = process_setup(bus, addr,
 211                            default_88e1518, ARRAY_SIZE(default_88e1518));
 212        if (res)
 213                return res;
 214
 215        if (addr) {
 216                res = process_setup(bus, addr,
 217                                    ch1fix_88e1518, ARRAY_SIZE(ch1fix_88e1518));
 218                if (res)
 219                        return res;
 220        }
 221
 222        res = process_setup(bus, addr,
 223                            swreset_88e1518, ARRAY_SIZE(swreset_88e1518));
 224        if (res)
 225                return res;
 226
 227        return 0;
 228}
 229
 230int setup_88e1514(const char *bus, unsigned char addr)
 231{
 232        int res;
 233
 234        res = process_setup(bus, addr,
 235                            verify_88e1518, ARRAY_SIZE(verify_88e1518));
 236        if (res)
 237                return res;
 238
 239        res = process_setup(bus, addr,
 240                            fixup_88e1518, ARRAY_SIZE(fixup_88e1518));
 241        if (res)
 242                return res;
 243
 244        res = process_setup(bus, addr,
 245                            mii_to_copper_88e1514,
 246                            ARRAY_SIZE(mii_to_copper_88e1514));
 247        if (res)
 248                return res;
 249
 250        res = process_setup(bus, addr,
 251                            sgmii_autoneg_off_88e1518,
 252                            ARRAY_SIZE(sgmii_autoneg_off_88e1518));
 253        if (res)
 254                return res;
 255
 256        res = process_setup(bus, addr,
 257                            invert_led2_88e1514,
 258                            ARRAY_SIZE(invert_led2_88e1514));
 259        if (res)
 260                return res;
 261
 262        res = process_setup(bus, addr,
 263                            default_88e1518, ARRAY_SIZE(default_88e1518));
 264        if (res)
 265                return res;
 266
 267        if (addr) {
 268                res = process_setup(bus, addr,
 269                                    ch1fix_88e1518, ARRAY_SIZE(ch1fix_88e1518));
 270                if (res)
 271                        return res;
 272        }
 273
 274        res = process_setup(bus, addr,
 275                            swreset_88e1518, ARRAY_SIZE(swreset_88e1518));
 276        if (res)
 277                return res;
 278
 279        return 0;
 280}
 281