uboot/board/gdsys/a38x/ihs_phys.c
<<
>>
Prefs
   1#include <common.h>
   2#include <dm.h>
   3#include <miiphy.h>
   4#include <asm-generic/gpio.h>
   5#include <linux/bitops.h>
   6#include <linux/delay.h>
   7
   8#include "ihs_phys.h"
   9#include "dt_helpers.h"
  10
  11enum {
  12        PORTTYPE_MAIN_CAT,
  13        PORTTYPE_TOP_CAT,
  14        PORTTYPE_16C_16F,
  15        PORTTYPE_UNKNOWN
  16};
  17
  18static struct porttype {
  19        bool phy_invert_in_pol;
  20        bool phy_invert_out_pol;
  21} porttypes[] = {
  22        { true, false },
  23        { false, true },
  24        { false, false },
  25};
  26
  27static void ihs_phy_config(struct phy_device *phydev, bool qinpn, bool qoutpn)
  28{
  29        u16 reg;
  30
  31        phy_config(phydev);
  32
  33        /* enable QSGMII autonegotiation with flow control */
  34        phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0004);
  35        reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
  36        reg |= (3 << 6);
  37        phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
  38
  39        /*
  40         * invert QSGMII Q_INP/N and Q_OUTP/N if required
  41         * and perform global reset
  42         */
  43        reg = phy_read(phydev, MDIO_DEVAD_NONE, 26);
  44        if (qinpn)
  45                reg |= (1 << 13);
  46        if (qoutpn)
  47                reg |= (1 << 12);
  48        reg |= (1 << 15);
  49        phy_write(phydev, MDIO_DEVAD_NONE, 26, reg);
  50
  51        /* advertise 1000BASE-T full-duplex only  */
  52        phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000);
  53        reg = phy_read(phydev, MDIO_DEVAD_NONE, 4);
  54        reg &= ~0x1e0;
  55        phy_write(phydev, MDIO_DEVAD_NONE, 4, reg);
  56        reg = phy_read(phydev, MDIO_DEVAD_NONE, 9);
  57        reg = (reg & ~0x300) | 0x200;
  58        phy_write(phydev, MDIO_DEVAD_NONE, 9, reg);
  59
  60        /* copper power up */
  61        reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
  62        reg &= ~0x0004;
  63        phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
  64}
  65
  66uint calculate_octo_phy_mask(void)
  67{
  68        uint k;
  69        uint octo_phy_mask = 0;
  70        struct gpio_desc gpio = {};
  71        char gpio_name[64];
  72        static const char * const dev_name[] = {"pca9698@23", "pca9698@21",
  73                                                "pca9698@24", "pca9698@25",
  74                                                "pca9698@26"};
  75
  76        /* mark all octo phys that should be present */
  77        for (k = 0; k < 5; ++k) {
  78                snprintf(gpio_name, 64, "cat-gpio-%u", k);
  79
  80                if (request_gpio_by_name(&gpio, dev_name[k], 0x20, gpio_name))
  81                        continue;
  82
  83                /* check CAT flag */
  84                if (dm_gpio_get_value(&gpio))
  85                        octo_phy_mask |= (1 << (k * 2));
  86                else
  87                        /* If CAT == 0, there's no second octo phy -> skip */
  88                        continue;
  89
  90                snprintf(gpio_name, 64, "second-octo-gpio-%u", k);
  91
  92                if (request_gpio_by_name(&gpio, dev_name[k], 0x27, gpio_name)) {
  93                        /* default: second octo phy is present */
  94                        octo_phy_mask |= (1 << (k * 2 + 1));
  95                        continue;
  96                }
  97
  98                if (dm_gpio_get_value(&gpio) == 0)
  99                        octo_phy_mask |= (1 << (k * 2 + 1));
 100        }
 101
 102        return octo_phy_mask;
 103}
 104
 105int register_miiphy_bus(uint k, struct mii_dev **bus)
 106{
 107        int retval;
 108        struct mii_dev *mdiodev = mdio_alloc();
 109        char *name = bb_miiphy_buses[k].name;
 110
 111        if (!mdiodev)
 112                return -ENOMEM;
 113        strlcpy(mdiodev->name, name, MDIO_NAME_LEN);
 114        mdiodev->read = bb_miiphy_read;
 115        mdiodev->write = bb_miiphy_write;
 116
 117        retval = mdio_register(mdiodev);
 118        if (retval < 0)
 119                return retval;
 120        *bus = miiphy_get_dev_by_name(name);
 121
 122        return 0;
 123}
 124
 125struct porttype *get_porttype(uint octo_phy_mask, uint k)
 126{
 127        uint octo_index = k * 4;
 128
 129        if (!k) {
 130                if (octo_phy_mask & 0x01)
 131                        return &porttypes[PORTTYPE_MAIN_CAT];
 132                else if (!(octo_phy_mask & 0x03))
 133                        return &porttypes[PORTTYPE_16C_16F];
 134        } else {
 135                if (octo_phy_mask & (1 << octo_index))
 136                        return &porttypes[PORTTYPE_TOP_CAT];
 137        }
 138
 139        return NULL;
 140}
 141
 142int init_single_phy(struct porttype *porttype, struct mii_dev *bus,
 143                    uint bus_idx, uint m, uint phy_idx)
 144{
 145        struct phy_device *phydev = phy_find_by_mask(
 146                bus, 1 << (m * 8 + phy_idx),
 147                PHY_INTERFACE_MODE_MII);
 148
 149        printf(" %u", bus_idx * 32 + m * 8 + phy_idx);
 150
 151        if (!phydev)
 152                puts("!");
 153        else
 154                ihs_phy_config(phydev, porttype->phy_invert_in_pol,
 155                               porttype->phy_invert_out_pol);
 156
 157        return 0;
 158}
 159
 160int init_octo_phys(uint octo_phy_mask)
 161{
 162        uint bus_idx;
 163
 164        /* there are up to four octo-phys on each mdio bus */
 165        for (bus_idx = 0; bus_idx < bb_miiphy_buses_num; ++bus_idx) {
 166                uint m;
 167                uint octo_index = bus_idx * 4;
 168                struct mii_dev *bus = NULL;
 169                struct porttype *porttype = NULL;
 170                int ret;
 171
 172                porttype = get_porttype(octo_phy_mask, bus_idx);
 173
 174                if (!porttype)
 175                        continue;
 176
 177                for (m = 0; m < 4; ++m) {
 178                        uint phy_idx;
 179
 180                        /**
 181                         * Register a bus device if there is at least one phy
 182                         * on the current bus
 183                         */
 184                        if (!m && octo_phy_mask & (0xf << octo_index)) {
 185                                ret = register_miiphy_bus(bus_idx, &bus);
 186                                if (ret)
 187                                        return ret;
 188                        }
 189
 190                        if (!(octo_phy_mask & BIT(octo_index + m)))
 191                                continue;
 192
 193                        for (phy_idx = 0; phy_idx < 8; ++phy_idx)
 194                                init_single_phy(porttype, bus, bus_idx, m,
 195                                                phy_idx);
 196                }
 197        }
 198
 199        return 0;
 200}
 201
 202/*
 203 * MII GPIO bitbang implementation
 204 * MDC MDIO bus
 205 * 13  14   PHY1-4
 206 * 25  45   PHY5-8
 207 * 46  24   PHY9-10
 208 */
 209
 210struct gpio_mii {
 211        int index;
 212        struct gpio_desc mdc_gpio;
 213        struct gpio_desc mdio_gpio;
 214        int mdc_num;
 215        int mdio_num;
 216        int mdio_value;
 217} gpio_mii_set[] = {
 218        { 0, {}, {}, 13, 14, 1 },
 219        { 1, {}, {}, 25, 45, 1 },
 220        { 2, {}, {}, 46, 24, 1 },
 221};
 222
 223static int mii_mdio_init(struct bb_miiphy_bus *bus)
 224{
 225        struct gpio_mii *gpio_mii = bus->priv;
 226        char name[32] = {};
 227        struct udevice *gpio_dev1 = NULL;
 228        struct udevice *gpio_dev2 = NULL;
 229
 230        if (uclass_get_device_by_name(UCLASS_GPIO, "gpio@18100", &gpio_dev1) ||
 231            uclass_get_device_by_name(UCLASS_GPIO, "gpio@18140", &gpio_dev2)) {
 232                printf("Could not get GPIO device.\n");
 233                return 1;
 234        }
 235
 236        if (gpio_mii->mdc_num > 31) {
 237                gpio_mii->mdc_gpio.dev = gpio_dev2;
 238                gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num - 32;
 239        } else {
 240                gpio_mii->mdc_gpio.dev = gpio_dev1;
 241                gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num;
 242        }
 243        gpio_mii->mdc_gpio.flags = 0;
 244        snprintf(name, 32, "bb_miiphy_bus-%d-mdc", gpio_mii->index);
 245        dm_gpio_request(&gpio_mii->mdc_gpio, name);
 246
 247        if (gpio_mii->mdio_num > 31) {
 248                gpio_mii->mdio_gpio.dev = gpio_dev2;
 249                gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num - 32;
 250        } else {
 251                gpio_mii->mdio_gpio.dev = gpio_dev1;
 252                gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num;
 253        }
 254        gpio_mii->mdio_gpio.flags = 0;
 255        snprintf(name, 32, "bb_miiphy_bus-%d-mdio", gpio_mii->index);
 256        dm_gpio_request(&gpio_mii->mdio_gpio, name);
 257
 258        dm_gpio_set_dir_flags(&gpio_mii->mdc_gpio, GPIOD_IS_OUT);
 259        dm_gpio_set_value(&gpio_mii->mdc_gpio, 1);
 260
 261        return 0;
 262}
 263
 264static int mii_mdio_active(struct bb_miiphy_bus *bus)
 265{
 266        struct gpio_mii *gpio_mii = bus->priv;
 267
 268        dm_gpio_set_value(&gpio_mii->mdc_gpio, gpio_mii->mdio_value);
 269
 270        return 0;
 271}
 272
 273static int mii_mdio_tristate(struct bb_miiphy_bus *bus)
 274{
 275        struct gpio_mii *gpio_mii = bus->priv;
 276
 277        dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
 278
 279        return 0;
 280}
 281
 282static int mii_set_mdio(struct bb_miiphy_bus *bus, int v)
 283{
 284        struct gpio_mii *gpio_mii = bus->priv;
 285
 286        dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_OUT);
 287        dm_gpio_set_value(&gpio_mii->mdio_gpio, v);
 288        gpio_mii->mdio_value = v;
 289
 290        return 0;
 291}
 292
 293static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v)
 294{
 295        struct gpio_mii *gpio_mii = bus->priv;
 296
 297        dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
 298        *v = (dm_gpio_get_value(&gpio_mii->mdio_gpio));
 299
 300        return 0;
 301}
 302
 303static int mii_set_mdc(struct bb_miiphy_bus *bus, int v)
 304{
 305        struct gpio_mii *gpio_mii = bus->priv;
 306
 307        dm_gpio_set_value(&gpio_mii->mdc_gpio, v);
 308
 309        return 0;
 310}
 311
 312static int mii_delay(struct bb_miiphy_bus *bus)
 313{
 314        udelay(1);
 315
 316        return 0;
 317}
 318
 319struct bb_miiphy_bus bb_miiphy_buses[] = {
 320        {
 321                .name = "ihs0",
 322                .init = mii_mdio_init,
 323                .mdio_active = mii_mdio_active,
 324                .mdio_tristate = mii_mdio_tristate,
 325                .set_mdio = mii_set_mdio,
 326                .get_mdio = mii_get_mdio,
 327                .set_mdc = mii_set_mdc,
 328                .delay = mii_delay,
 329                .priv = &gpio_mii_set[0],
 330        },
 331        {
 332                .name = "ihs1",
 333                .init = mii_mdio_init,
 334                .mdio_active = mii_mdio_active,
 335                .mdio_tristate = mii_mdio_tristate,
 336                .set_mdio = mii_set_mdio,
 337                .get_mdio = mii_get_mdio,
 338                .set_mdc = mii_set_mdc,
 339                .delay = mii_delay,
 340                .priv = &gpio_mii_set[1],
 341        },
 342        {
 343                .name = "ihs2",
 344                .init = mii_mdio_init,
 345                .mdio_active = mii_mdio_active,
 346                .mdio_tristate = mii_mdio_tristate,
 347                .set_mdio = mii_set_mdio,
 348                .get_mdio = mii_get_mdio,
 349                .set_mdc = mii_set_mdc,
 350                .delay = mii_delay,
 351                .priv = &gpio_mii_set[2],
 352        },
 353};
 354
 355int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);
 356