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