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        strncpy(mdiodev->name,
 114                name,
 115                MDIO_NAME_LEN);
 116        mdiodev->read = bb_miiphy_read;
 117        mdiodev->write = bb_miiphy_write;
 118
 119        retval = mdio_register(mdiodev);
 120        if (retval < 0)
 121                return retval;
 122        *bus = miiphy_get_dev_by_name(name);
 123
 124        return 0;
 125}
 126
 127struct porttype *get_porttype(uint octo_phy_mask, uint k)
 128{
 129        uint octo_index = k * 4;
 130
 131        if (!k) {
 132                if (octo_phy_mask & 0x01)
 133                        return &porttypes[PORTTYPE_MAIN_CAT];
 134                else if (!(octo_phy_mask & 0x03))
 135                        return &porttypes[PORTTYPE_16C_16F];
 136        } else {
 137                if (octo_phy_mask & (1 << octo_index))
 138                        return &porttypes[PORTTYPE_TOP_CAT];
 139        }
 140
 141        return NULL;
 142}
 143
 144int init_single_phy(struct porttype *porttype, struct mii_dev *bus,
 145                    uint bus_idx, uint m, uint phy_idx)
 146{
 147        struct phy_device *phydev = phy_find_by_mask(
 148                bus, 1 << (m * 8 + phy_idx),
 149                PHY_INTERFACE_MODE_MII);
 150
 151        printf(" %u", bus_idx * 32 + m * 8 + phy_idx);
 152
 153        if (!phydev)
 154                puts("!");
 155        else
 156                ihs_phy_config(phydev, porttype->phy_invert_in_pol,
 157                               porttype->phy_invert_out_pol);
 158
 159        return 0;
 160}
 161
 162int init_octo_phys(uint octo_phy_mask)
 163{
 164        uint bus_idx;
 165
 166        /* there are up to four octo-phys on each mdio bus */
 167        for (bus_idx = 0; bus_idx < bb_miiphy_buses_num; ++bus_idx) {
 168                uint m;
 169                uint octo_index = bus_idx * 4;
 170                struct mii_dev *bus = NULL;
 171                struct porttype *porttype = NULL;
 172                int ret;
 173
 174                porttype = get_porttype(octo_phy_mask, bus_idx);
 175
 176                if (!porttype)
 177                        continue;
 178
 179                for (m = 0; m < 4; ++m) {
 180                        uint phy_idx;
 181
 182                        /**
 183                         * Register a bus device if there is at least one phy
 184                         * on the current bus
 185                         */
 186                        if (!m && octo_phy_mask & (0xf << octo_index)) {
 187                                ret = register_miiphy_bus(bus_idx, &bus);
 188                                if (ret)
 189                                        return ret;
 190                        }
 191
 192                        if (!(octo_phy_mask & BIT(octo_index + m)))
 193                                continue;
 194
 195                        for (phy_idx = 0; phy_idx < 8; ++phy_idx)
 196                                init_single_phy(porttype, bus, bus_idx, m,
 197                                                phy_idx);
 198                }
 199        }
 200
 201        return 0;
 202}
 203
 204/*
 205 * MII GPIO bitbang implementation
 206 * MDC MDIO bus
 207 * 13  14   PHY1-4
 208 * 25  45   PHY5-8
 209 * 46  24   PHY9-10
 210 */
 211
 212struct gpio_mii {
 213        int index;
 214        struct gpio_desc mdc_gpio;
 215        struct gpio_desc mdio_gpio;
 216        int mdc_num;
 217        int mdio_num;
 218        int mdio_value;
 219} gpio_mii_set[] = {
 220        { 0, {}, {}, 13, 14, 1 },
 221        { 1, {}, {}, 25, 45, 1 },
 222        { 2, {}, {}, 46, 24, 1 },
 223};
 224
 225static int mii_mdio_init(struct bb_miiphy_bus *bus)
 226{
 227        struct gpio_mii *gpio_mii = bus->priv;
 228        char name[32] = {};
 229        struct udevice *gpio_dev1 = NULL;
 230        struct udevice *gpio_dev2 = NULL;
 231
 232        if (uclass_get_device_by_name(UCLASS_GPIO, "gpio@18100", &gpio_dev1) ||
 233            uclass_get_device_by_name(UCLASS_GPIO, "gpio@18140", &gpio_dev2)) {
 234                printf("Could not get GPIO device.\n");
 235                return 1;
 236        }
 237
 238        if (gpio_mii->mdc_num > 31) {
 239                gpio_mii->mdc_gpio.dev = gpio_dev2;
 240                gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num - 32;
 241        } else {
 242                gpio_mii->mdc_gpio.dev = gpio_dev1;
 243                gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num;
 244        }
 245        gpio_mii->mdc_gpio.flags = 0;
 246        snprintf(name, 32, "bb_miiphy_bus-%d-mdc", gpio_mii->index);
 247        dm_gpio_request(&gpio_mii->mdc_gpio, name);
 248
 249        if (gpio_mii->mdio_num > 31) {
 250                gpio_mii->mdio_gpio.dev = gpio_dev2;
 251                gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num - 32;
 252        } else {
 253                gpio_mii->mdio_gpio.dev = gpio_dev1;
 254                gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num;
 255        }
 256        gpio_mii->mdio_gpio.flags = 0;
 257        snprintf(name, 32, "bb_miiphy_bus-%d-mdio", gpio_mii->index);
 258        dm_gpio_request(&gpio_mii->mdio_gpio, name);
 259
 260        dm_gpio_set_dir_flags(&gpio_mii->mdc_gpio, GPIOD_IS_OUT);
 261        dm_gpio_set_value(&gpio_mii->mdc_gpio, 1);
 262
 263        return 0;
 264}
 265
 266static int mii_mdio_active(struct bb_miiphy_bus *bus)
 267{
 268        struct gpio_mii *gpio_mii = bus->priv;
 269
 270        dm_gpio_set_value(&gpio_mii->mdc_gpio, gpio_mii->mdio_value);
 271
 272        return 0;
 273}
 274
 275static int mii_mdio_tristate(struct bb_miiphy_bus *bus)
 276{
 277        struct gpio_mii *gpio_mii = bus->priv;
 278
 279        dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
 280
 281        return 0;
 282}
 283
 284static int mii_set_mdio(struct bb_miiphy_bus *bus, int v)
 285{
 286        struct gpio_mii *gpio_mii = bus->priv;
 287
 288        dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_OUT);
 289        dm_gpio_set_value(&gpio_mii->mdio_gpio, v);
 290        gpio_mii->mdio_value = v;
 291
 292        return 0;
 293}
 294
 295static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v)
 296{
 297        struct gpio_mii *gpio_mii = bus->priv;
 298
 299        dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
 300        *v = (dm_gpio_get_value(&gpio_mii->mdio_gpio));
 301
 302        return 0;
 303}
 304
 305static int mii_set_mdc(struct bb_miiphy_bus *bus, int v)
 306{
 307        struct gpio_mii *gpio_mii = bus->priv;
 308
 309        dm_gpio_set_value(&gpio_mii->mdc_gpio, v);
 310
 311        return 0;
 312}
 313
 314static int mii_delay(struct bb_miiphy_bus *bus)
 315{
 316        udelay(1);
 317
 318        return 0;
 319}
 320
 321struct bb_miiphy_bus bb_miiphy_buses[] = {
 322        {
 323                .name = "ihs0",
 324                .init = mii_mdio_init,
 325                .mdio_active = mii_mdio_active,
 326                .mdio_tristate = mii_mdio_tristate,
 327                .set_mdio = mii_set_mdio,
 328                .get_mdio = mii_get_mdio,
 329                .set_mdc = mii_set_mdc,
 330                .delay = mii_delay,
 331                .priv = &gpio_mii_set[0],
 332        },
 333        {
 334                .name = "ihs1",
 335                .init = mii_mdio_init,
 336                .mdio_active = mii_mdio_active,
 337                .mdio_tristate = mii_mdio_tristate,
 338                .set_mdio = mii_set_mdio,
 339                .get_mdio = mii_get_mdio,
 340                .set_mdc = mii_set_mdc,
 341                .delay = mii_delay,
 342                .priv = &gpio_mii_set[1],
 343        },
 344        {
 345                .name = "ihs2",
 346                .init = mii_mdio_init,
 347                .mdio_active = mii_mdio_active,
 348                .mdio_tristate = mii_mdio_tristate,
 349                .set_mdio = mii_set_mdio,
 350                .get_mdio = mii_get_mdio,
 351                .set_mdc = mii_set_mdc,
 352                .delay = mii_delay,
 353                .priv = &gpio_mii_set[2],
 354        },
 355};
 356
 357int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);
 358