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