123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- #include <common.h>
- #include <dm.h>
- #include <miiphy.h>
- #include <asm-generic/gpio.h>
- #include "ihs_phys.h"
- #include "dt_helpers.h"
- enum {
- PORTTYPE_MAIN_CAT,
- PORTTYPE_TOP_CAT,
- PORTTYPE_16C_16F,
- PORTTYPE_UNKNOWN
- };
- static struct porttype {
- bool phy_invert_in_pol;
- bool phy_invert_out_pol;
- } porttypes[] = {
- { true, false },
- { false, true },
- { false, false },
- };
- static void ihs_phy_config(struct phy_device *phydev, bool qinpn, bool qoutpn)
- {
- u16 reg;
- phy_config(phydev);
- /* enable QSGMII autonegotiation with flow control */
- phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0004);
- reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
- reg |= (3 << 6);
- phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
- /*
- * invert QSGMII Q_INP/N and Q_OUTP/N if required
- * and perform global reset
- */
- reg = phy_read(phydev, MDIO_DEVAD_NONE, 26);
- if (qinpn)
- reg |= (1 << 13);
- if (qoutpn)
- reg |= (1 << 12);
- reg |= (1 << 15);
- phy_write(phydev, MDIO_DEVAD_NONE, 26, reg);
- /* advertise 1000BASE-T full-duplex only */
- phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000);
- reg = phy_read(phydev, MDIO_DEVAD_NONE, 4);
- reg &= ~0x1e0;
- phy_write(phydev, MDIO_DEVAD_NONE, 4, reg);
- reg = phy_read(phydev, MDIO_DEVAD_NONE, 9);
- reg = (reg & ~0x300) | 0x200;
- phy_write(phydev, MDIO_DEVAD_NONE, 9, reg);
- /* copper power up */
- reg = phy_read(phydev, MDIO_DEVAD_NONE, 16);
- reg &= ~0x0004;
- phy_write(phydev, MDIO_DEVAD_NONE, 16, reg);
- }
- uint calculate_octo_phy_mask(void)
- {
- uint k;
- uint octo_phy_mask = 0;
- struct gpio_desc gpio = {};
- char gpio_name[64];
- static const char * const dev_name[] = {"pca9698@23", "pca9698@21",
- "pca9698@24", "pca9698@25",
- "pca9698@26"};
- /* mark all octo phys that should be present */
- for (k = 0; k < 5; ++k) {
- snprintf(gpio_name, 64, "cat-gpio-%u", k);
- if (request_gpio_by_name(&gpio, dev_name[k], 0x20, gpio_name))
- continue;
- /* check CAT flag */
- if (dm_gpio_get_value(&gpio))
- octo_phy_mask |= (1 << (k * 2));
- else
- /* If CAT == 0, there's no second octo phy -> skip */
- continue;
- snprintf(gpio_name, 64, "second-octo-gpio-%u", k);
- if (request_gpio_by_name(&gpio, dev_name[k], 0x27, gpio_name)) {
- /* default: second octo phy is present */
- octo_phy_mask |= (1 << (k * 2 + 1));
- continue;
- }
- if (dm_gpio_get_value(&gpio) == 0)
- octo_phy_mask |= (1 << (k * 2 + 1));
- }
- return octo_phy_mask;
- }
- int register_miiphy_bus(uint k, struct mii_dev **bus)
- {
- int retval;
- struct mii_dev *mdiodev = mdio_alloc();
- char *name = bb_miiphy_buses[k].name;
- if (!mdiodev)
- return -ENOMEM;
- strncpy(mdiodev->name,
- name,
- MDIO_NAME_LEN);
- mdiodev->read = bb_miiphy_read;
- mdiodev->write = bb_miiphy_write;
- retval = mdio_register(mdiodev);
- if (retval < 0)
- return retval;
- *bus = miiphy_get_dev_by_name(name);
- return 0;
- }
- struct porttype *get_porttype(uint octo_phy_mask, uint k)
- {
- uint octo_index = k * 4;
- if (!k) {
- if (octo_phy_mask & 0x01)
- return &porttypes[PORTTYPE_MAIN_CAT];
- else if (!(octo_phy_mask & 0x03))
- return &porttypes[PORTTYPE_16C_16F];
- } else {
- if (octo_phy_mask & (1 << octo_index))
- return &porttypes[PORTTYPE_TOP_CAT];
- }
- return NULL;
- }
- int init_single_phy(struct porttype *porttype, struct mii_dev *bus,
- uint bus_idx, uint m, uint phy_idx)
- {
- struct phy_device *phydev = phy_find_by_mask(
- bus, 1 << (m * 8 + phy_idx),
- PHY_INTERFACE_MODE_MII);
- printf(" %u", bus_idx * 32 + m * 8 + phy_idx);
- if (!phydev)
- puts("!");
- else
- ihs_phy_config(phydev, porttype->phy_invert_in_pol,
- porttype->phy_invert_out_pol);
- return 0;
- }
- int init_octo_phys(uint octo_phy_mask)
- {
- uint bus_idx;
- /* there are up to four octo-phys on each mdio bus */
- for (bus_idx = 0; bus_idx < bb_miiphy_buses_num; ++bus_idx) {
- uint m;
- uint octo_index = bus_idx * 4;
- struct mii_dev *bus = NULL;
- struct porttype *porttype = NULL;
- int ret;
- porttype = get_porttype(octo_phy_mask, bus_idx);
- if (!porttype)
- continue;
- for (m = 0; m < 4; ++m) {
- uint phy_idx;
- /**
- * Register a bus device if there is at least one phy
- * on the current bus
- */
- if (!m && octo_phy_mask & (0xf << octo_index)) {
- ret = register_miiphy_bus(bus_idx, &bus);
- if (ret)
- return ret;
- }
- if (!(octo_phy_mask & BIT(octo_index + m)))
- continue;
- for (phy_idx = 0; phy_idx < 8; ++phy_idx)
- init_single_phy(porttype, bus, bus_idx, m,
- phy_idx);
- }
- }
- return 0;
- }
- /*
- * MII GPIO bitbang implementation
- * MDC MDIO bus
- * 13 14 PHY1-4
- * 25 45 PHY5-8
- * 46 24 PHY9-10
- */
- struct gpio_mii {
- int index;
- struct gpio_desc mdc_gpio;
- struct gpio_desc mdio_gpio;
- int mdc_num;
- int mdio_num;
- int mdio_value;
- } gpio_mii_set[] = {
- { 0, {}, {}, 13, 14, 1 },
- { 1, {}, {}, 25, 45, 1 },
- { 2, {}, {}, 46, 24, 1 },
- };
- static int mii_mdio_init(struct bb_miiphy_bus *bus)
- {
- struct gpio_mii *gpio_mii = bus->priv;
- char name[32] = {};
- struct udevice *gpio_dev1 = NULL;
- struct udevice *gpio_dev2 = NULL;
- if (uclass_get_device_by_name(UCLASS_GPIO, "gpio@18100", &gpio_dev1) ||
- uclass_get_device_by_name(UCLASS_GPIO, "gpio@18140", &gpio_dev2)) {
- printf("Could not get GPIO device.\n");
- return 1;
- }
- if (gpio_mii->mdc_num > 31) {
- gpio_mii->mdc_gpio.dev = gpio_dev2;
- gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num - 32;
- } else {
- gpio_mii->mdc_gpio.dev = gpio_dev1;
- gpio_mii->mdc_gpio.offset = gpio_mii->mdc_num;
- }
- gpio_mii->mdc_gpio.flags = 0;
- snprintf(name, 32, "bb_miiphy_bus-%d-mdc", gpio_mii->index);
- dm_gpio_request(&gpio_mii->mdc_gpio, name);
- if (gpio_mii->mdio_num > 31) {
- gpio_mii->mdio_gpio.dev = gpio_dev2;
- gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num - 32;
- } else {
- gpio_mii->mdio_gpio.dev = gpio_dev1;
- gpio_mii->mdio_gpio.offset = gpio_mii->mdio_num;
- }
- gpio_mii->mdio_gpio.flags = 0;
- snprintf(name, 32, "bb_miiphy_bus-%d-mdio", gpio_mii->index);
- dm_gpio_request(&gpio_mii->mdio_gpio, name);
- dm_gpio_set_dir_flags(&gpio_mii->mdc_gpio, GPIOD_IS_OUT);
- dm_gpio_set_value(&gpio_mii->mdc_gpio, 1);
- return 0;
- }
- static int mii_mdio_active(struct bb_miiphy_bus *bus)
- {
- struct gpio_mii *gpio_mii = bus->priv;
- dm_gpio_set_value(&gpio_mii->mdc_gpio, gpio_mii->mdio_value);
- return 0;
- }
- static int mii_mdio_tristate(struct bb_miiphy_bus *bus)
- {
- struct gpio_mii *gpio_mii = bus->priv;
- dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
- return 0;
- }
- static int mii_set_mdio(struct bb_miiphy_bus *bus, int v)
- {
- struct gpio_mii *gpio_mii = bus->priv;
- dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_OUT);
- dm_gpio_set_value(&gpio_mii->mdio_gpio, v);
- gpio_mii->mdio_value = v;
- return 0;
- }
- static int mii_get_mdio(struct bb_miiphy_bus *bus, int *v)
- {
- struct gpio_mii *gpio_mii = bus->priv;
- dm_gpio_set_dir_flags(&gpio_mii->mdio_gpio, GPIOD_IS_IN);
- *v = (dm_gpio_get_value(&gpio_mii->mdio_gpio));
- return 0;
- }
- static int mii_set_mdc(struct bb_miiphy_bus *bus, int v)
- {
- struct gpio_mii *gpio_mii = bus->priv;
- dm_gpio_set_value(&gpio_mii->mdc_gpio, v);
- return 0;
- }
- static int mii_delay(struct bb_miiphy_bus *bus)
- {
- udelay(1);
- return 0;
- }
- struct bb_miiphy_bus bb_miiphy_buses[] = {
- {
- .name = "ihs0",
- .init = mii_mdio_init,
- .mdio_active = mii_mdio_active,
- .mdio_tristate = mii_mdio_tristate,
- .set_mdio = mii_set_mdio,
- .get_mdio = mii_get_mdio,
- .set_mdc = mii_set_mdc,
- .delay = mii_delay,
- .priv = &gpio_mii_set[0],
- },
- {
- .name = "ihs1",
- .init = mii_mdio_init,
- .mdio_active = mii_mdio_active,
- .mdio_tristate = mii_mdio_tristate,
- .set_mdio = mii_set_mdio,
- .get_mdio = mii_get_mdio,
- .set_mdc = mii_set_mdc,
- .delay = mii_delay,
- .priv = &gpio_mii_set[1],
- },
- {
- .name = "ihs2",
- .init = mii_mdio_init,
- .mdio_active = mii_mdio_active,
- .mdio_tristate = mii_mdio_tristate,
- .set_mdio = mii_set_mdio,
- .get_mdio = mii_get_mdio,
- .set_mdc = mii_set_mdc,
- .delay = mii_delay,
- .priv = &gpio_mii_set[2],
- },
- };
- int bb_miiphy_buses_num = ARRAY_SIZE(bb_miiphy_buses);
|