X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmvpp2.c;h=ebe67e45ab3f38fdd727bf2e5d1b4099f9728970;hb=c05ed00afb95fa5237f16962fccf5810437317bf;hp=e3d31a560d54af4697cf8d48d678e878b4dd3fae;hpb=ab21ecef7a38dd211fe6db35c6e60800445eb6a2;p=oweals%2Fu-boot.git diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index e3d31a560d..ebe67e45ab 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -14,14 +14,21 @@ */ #include +#include #include +#include #include +#include +#include #include #include #include #include #include #include +#include +#include +#include #include #include #include @@ -29,24 +36,14 @@ #include #include #include +#include #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; -/* Some linux -> U-Boot compatibility stuff */ -#define netdev_err(dev, fmt, args...) \ - printf(fmt, ##args) -#define netdev_warn(dev, fmt, args...) \ - printf(fmt, ##args) -#define netdev_info(dev, fmt, args...) \ - printf(fmt, ##args) -#define netdev_dbg(dev, fmt, args...) \ - printf(fmt, ##args) - -#define ETH_ALEN 6 /* Octets in one ethernet addr */ - #define __verify_pcpu_ptr(ptr) \ do { \ const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL; \ @@ -68,15 +65,12 @@ do { \ #define NET_SKB_PAD max(32, MVPP2_CPU_D_CACHE_LINE_SIZE) #define CONFIG_NR_CPUS 1 -#define ETH_HLEN ETHER_HDR_SIZE /* Total octets in header */ /* 2(HW hdr) 14(MAC hdr) 4(CRC) 32(extra for cache prefetch) */ #define WRAP (2 + ETH_HLEN + 4 + 32) #define MTU 1500 #define RX_BUFFER_SIZE (ALIGN(MTU + WRAP, ARCH_DMA_MINALIGN)) -#define MVPP2_SMI_TIMEOUT 10000 - /* RX Fifo Registers */ #define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port)) #define MVPP2_RX_ATTR_FIFO_SIZE_REG(port) (0x20 + 4 * (port)) @@ -503,23 +497,8 @@ do { \ #define MVPP2_QUEUE_NEXT_DESC(q, index) \ (((index) < (q)->last_desc) ? ((index) + 1) : 0) -/* SMI: 0xc0054 -> offset 0x54 to lms_base */ -#define MVPP21_SMI 0x0054 /* PP2.2: SMI: 0x12a200 -> offset 0x1200 to iface_base */ #define MVPP22_SMI 0x1200 -#define MVPP2_PHY_REG_MASK 0x1f -/* SMI register fields */ -#define MVPP2_SMI_DATA_OFFS 0 /* Data */ -#define MVPP2_SMI_DATA_MASK (0xffff << MVPP2_SMI_DATA_OFFS) -#define MVPP2_SMI_DEV_ADDR_OFFS 16 /* PHY device address */ -#define MVPP2_SMI_REG_ADDR_OFFS 21 /* PHY device reg addr*/ -#define MVPP2_SMI_OPCODE_OFFS 26 /* Write/Read opcode */ -#define MVPP2_SMI_OPCODE_READ (1 << MVPP2_SMI_OPCODE_OFFS) -#define MVPP2_SMI_READ_VALID (1 << 27) /* Read Valid */ -#define MVPP2_SMI_BUSY (1 << 28) /* Busy */ - -#define MVPP2_PHY_ADDR_MASK 0x1f -#define MVPP2_PHY_REG_MASK 0x1f /* Additional PPv2.2 offsets */ #define MVPP22_MPCS 0x007000 @@ -608,7 +587,7 @@ enum mv_netc_lanes { /* Default number of TXQs in use */ #define MVPP2_DEFAULT_TXQ 1 -/* Dfault number of RXQs in use */ +/* Default number of RXQs in use */ #define MVPP2_DEFAULT_RXQ 1 #define CONFIG_MV_ETH_RXQ 8 /* increment by 8 */ @@ -910,7 +889,6 @@ struct mvpp2 { void __iomem *base; void __iomem *lms_base; void __iomem *iface_base; - void __iomem *mdio_base; void __iomem *mpcs_base; void __iomem *xpcs_base; @@ -941,8 +919,6 @@ struct mvpp2 { /* Maximum number of RXQs per port */ unsigned int max_port_rxqs; - struct mii_dev *bus; - int probe_done; u8 num_ports; }; @@ -988,9 +964,10 @@ struct mvpp2_port { struct phy_device *phy_dev; phy_interface_t phy_interface; - int phy_node; int phyaddr; -#ifdef CONFIG_DM_GPIO + struct udevice *mdio_dev; + struct mii_dev *bus; +#if CONFIG_IS_ENABLED(DM_GPIO) struct gpio_desc phy_reset_gpio; struct gpio_desc phy_tx_disable_gpio; #endif @@ -4508,17 +4485,40 @@ static void mvpp2_stop_dev(struct mvpp2_port *port) gop_port_enable(port, 0); } -static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) +static void mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) { struct phy_device *phy_dev; if (!port->init || port->link == 0) { - phy_dev = phy_connect(port->priv->bus, port->phyaddr, dev, - port->phy_interface); + phy_dev = dm_mdio_phy_connect(port->mdio_dev, port->phyaddr, + dev, port->phy_interface); + + /* + * If the phy doesn't match with any existing u-boot drivers the + * phy framework will connect it to generic one which + * uid == 0xffffffff. In this case act as if the phy wouldn't be + * declared in dts. Otherwise in case of 3310 (for which the + * driver doesn't exist) the link will not be correctly + * detected. Removing phy entry from dts in case of 3310 is not + * an option because it is required for the phy_fw_down + * procedure. + */ + if (phy_dev && + phy_dev->drv->uid == 0xffffffff) {/* Generic phy */ + netdev_warn(port->dev, + "Marking phy as invalid, link will not be checked\n"); + /* set phy_addr to invalid value */ + port->phyaddr = PHY_MAX_ADDR; + mvpp2_egress_enable(port); + mvpp2_ingress_enable(port); + + return; + } + port->phy_dev = phy_dev; if (!phy_dev) { netdev_err(port->dev, "cannot connect to phy\n"); - return -ENODEV; + return; } phy_dev->supported &= PHY_GBIT_FEATURES; phy_dev->advertising = phy_dev->supported; @@ -4530,18 +4530,14 @@ static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) phy_config(phy_dev); phy_startup(phy_dev); - if (!phy_dev->link) { + if (!phy_dev->link) printf("%s: No link\n", phy_dev->dev->name); - return -1; - } - - port->init = 1; + else + port->init = 1; } else { mvpp2_egress_enable(port); mvpp2_ingress_enable(port); } - - return 0; } static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port) @@ -4580,11 +4576,8 @@ static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port) return err; } - if (port->phy_node) { - err = mvpp2_phy_connect(dev, port); - if (err < 0) - return err; - + if (port->phyaddr < PHY_MAX_ADDR) { + mvpp2_phy_connect(dev, port); mvpp2_link_event(port); } else { mvpp2_egress_enable(port); @@ -4718,44 +4711,29 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) { int port_node = dev_of_offset(dev); const char *phy_mode_str; - int phy_node, mdio_off, cp_node; + int phy_node; u32 id; u32 phyaddr = 0; int phy_mode = -1; - phys_addr_t mdio_addr; + int ret; phy_node = fdtdec_lookup_phandle(gd->fdt_blob, port_node, "phy"); if (phy_node > 0) { + int parent; phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0); if (phyaddr < 0) { dev_err(&pdev->dev, "could not find phy address\n"); return -1; } - mdio_off = fdt_parent_offset(gd->fdt_blob, phy_node); - - /* TODO: This WA for mdio issue. U-boot 2017 don't have - * mdio driver and on MACHIATOBin board ports from CP1 - * connected to mdio on CP0. - * WA is to get mdio address from phy handler parent - * base address. WA should be removed after - * mdio driver implementation. - */ - mdio_addr = fdtdec_get_uint(gd->fdt_blob, - mdio_off, "reg", 0); - - cp_node = fdt_parent_offset(gd->fdt_blob, mdio_off); - mdio_addr |= fdt_get_base_address((void *)gd->fdt_blob, - cp_node); - - port->priv->mdio_base = (void *)mdio_addr; - - if (port->priv->mdio_base < 0) { - dev_err(&pdev->dev, "could not find mdio base address\n"); - return -1; - } + parent = fdt_parent_offset(gd->fdt_blob, phy_node); + ret = uclass_get_device_by_of_offset(UCLASS_MDIO, parent, + &port->mdio_dev); + if (ret) + return ret; } else { - phy_node = 0; + /* phy_addr is set to invalid value */ + phyaddr = PHY_MAX_ADDR; } phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, "phy-mode", NULL); @@ -4772,7 +4750,7 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) return -EINVAL; } -#ifdef CONFIG_DM_GPIO +#if CONFIG_IS_ENABLED(DM_GPIO) gpio_request_by_name(dev, "phy-reset-gpios", 0, &port->phy_reset_gpio, GPIOD_IS_OUT); gpio_request_by_name(dev, "marvell,sfp-tx-disable-gpio", 0, @@ -4793,21 +4771,20 @@ static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) port->first_rxq = port->id * rxq_number; else port->first_rxq = port->id * port->priv->max_port_rxqs; - port->phy_node = phy_node; port->phy_interface = phy_mode; port->phyaddr = phyaddr; return 0; } -#ifdef CONFIG_DM_GPIO +#if CONFIG_IS_ENABLED(DM_GPIO) /* Port GPIO initialization */ static void mvpp2_gpio_init(struct mvpp2_port *port) { if (dm_gpio_is_valid(&port->phy_reset_gpio)) { - dm_gpio_set_value(&port->phy_reset_gpio, 0); - udelay(1000); dm_gpio_set_value(&port->phy_reset_gpio, 1); + mdelay(10); + dm_gpio_set_value(&port->phy_reset_gpio, 0); } if (dm_gpio_is_valid(&port->phy_tx_disable_gpio)) @@ -4833,7 +4810,7 @@ static int mvpp2_port_probe(struct udevice *dev, } mvpp2_port_power_up(port); -#ifdef CONFIG_DM_GPIO +#if CONFIG_IS_ENABLED(DM_GPIO) mvpp2_gpio_init(port); #endif @@ -5070,118 +5047,6 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv) return 0; } -/* SMI / MDIO functions */ - -static int smi_wait_ready(struct mvpp2 *priv) -{ - u32 timeout = MVPP2_SMI_TIMEOUT; - u32 smi_reg; - - /* wait till the SMI is not busy */ - do { - /* read smi register */ - smi_reg = readl(priv->mdio_base); - if (timeout-- == 0) { - printf("Error: SMI busy timeout\n"); - return -EFAULT; - } - } while (smi_reg & MVPP2_SMI_BUSY); - - return 0; -} - -/* - * mpp2_mdio_read - miiphy_read callback function. - * - * Returns 16bit phy register value, or 0xffff on error - */ -static int mpp2_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - struct mvpp2 *priv = bus->priv; - u32 smi_reg; - u32 timeout; - - /* check parameters */ - if (addr > MVPP2_PHY_ADDR_MASK) { - printf("Error: Invalid PHY address %d\n", addr); - return -EFAULT; - } - - if (reg > MVPP2_PHY_REG_MASK) { - printf("Err: Invalid register offset %d\n", reg); - return -EFAULT; - } - - /* wait till the SMI is not busy */ - if (smi_wait_ready(priv) < 0) - return -EFAULT; - - /* fill the phy address and regiser offset and read opcode */ - smi_reg = (addr << MVPP2_SMI_DEV_ADDR_OFFS) - | (reg << MVPP2_SMI_REG_ADDR_OFFS) - | MVPP2_SMI_OPCODE_READ; - - /* write the smi register */ - writel(smi_reg, priv->mdio_base); - - /* wait till read value is ready */ - timeout = MVPP2_SMI_TIMEOUT; - - do { - /* read smi register */ - smi_reg = readl(priv->mdio_base); - if (timeout-- == 0) { - printf("Err: SMI read ready timeout\n"); - return -EFAULT; - } - } while (!(smi_reg & MVPP2_SMI_READ_VALID)); - - /* Wait for the data to update in the SMI register */ - for (timeout = 0; timeout < MVPP2_SMI_TIMEOUT; timeout++) - ; - - return readl(priv->mdio_base) & MVPP2_SMI_DATA_MASK; -} - -/* - * mpp2_mdio_write - miiphy_write callback function. - * - * Returns 0 if write succeed, -EINVAL on bad parameters - * -ETIME on timeout - */ -static int mpp2_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, - u16 value) -{ - struct mvpp2 *priv = bus->priv; - u32 smi_reg; - - /* check parameters */ - if (addr > MVPP2_PHY_ADDR_MASK) { - printf("Error: Invalid PHY address %d\n", addr); - return -EFAULT; - } - - if (reg > MVPP2_PHY_REG_MASK) { - printf("Err: Invalid register offset %d\n", reg); - return -EFAULT; - } - - /* wait till the SMI is not busy */ - if (smi_wait_ready(priv) < 0) - return -EFAULT; - - /* fill the phy addr and reg offset and write opcode and data */ - smi_reg = value << MVPP2_SMI_DATA_OFFS; - smi_reg |= (addr << MVPP2_SMI_DEV_ADDR_OFFS) - | (reg << MVPP2_SMI_REG_ADDR_OFFS); - smi_reg &= ~MVPP2_SMI_OPCODE_READ; - - /* write the smi register */ - writel(smi_reg, priv->mdio_base); - - return 0; -} - static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp) { struct mvpp2_port *port = dev_get_priv(dev); @@ -5194,6 +5059,10 @@ static int mvpp2_recv(struct udevice *dev, int flags, uchar **packetp) struct mvpp2_rx_queue *rxq; u8 *data; + if (port->phyaddr < PHY_MAX_ADDR) + if (!port->phy_dev->link) + return 0; + /* Process RX packets */ rxq = port->rxqs[0]; @@ -5259,6 +5128,10 @@ static int mvpp2_send(struct udevice *dev, void *packet, int length) int tx_done; int timeout; + if (port->phyaddr < PHY_MAX_ADDR) + if (!port->phy_dev->link) + return 0; + txq = port->txqs[0]; aggr_txq = &port->priv->aggr_txqs[smp_processor_id()]; @@ -5340,6 +5213,13 @@ static void mvpp2_stop(struct udevice *dev) mvpp2_cleanup_txqs(port); } +static int mvpp2_write_hwaddr(struct udevice *dev) +{ + struct mvpp2_port *port = dev_get_priv(dev); + + return mvpp2_prs_update_mac_da(port, port->dev_addr); +} + static int mvpp22_smi_phy_addr_cfg(struct mvpp2_port *port) { writel(port->phyaddr, port->priv->iface_base + @@ -5351,7 +5231,6 @@ static int mvpp22_smi_phy_addr_cfg(struct mvpp2_port *port) static int mvpp2_base_probe(struct udevice *dev) { struct mvpp2 *priv = dev_get_priv(dev); - struct mii_dev *bus; void *bd_space; u32 size = 0; int i; @@ -5410,15 +5289,11 @@ static int mvpp2_base_probe(struct udevice *dev) priv->lms_base = (void *)devfdt_get_addr_index(dev, 1); if (IS_ERR(priv->lms_base)) return PTR_ERR(priv->lms_base); - - priv->mdio_base = priv->lms_base + MVPP21_SMI; } else { priv->iface_base = (void *)devfdt_get_addr_index(dev, 1); if (IS_ERR(priv->iface_base)) return PTR_ERR(priv->iface_base); - priv->mdio_base = priv->iface_base + MVPP22_SMI; - /* Store common base addresses for all ports */ priv->mpcs_base = priv->iface_base + MVPP22_MPCS; priv->xpcs_base = priv->iface_base + MVPP22_XPCS; @@ -5430,20 +5305,7 @@ static int mvpp2_base_probe(struct udevice *dev) else priv->max_port_rxqs = 32; - /* Finally create and register the MDIO bus driver */ - bus = mdio_alloc(); - if (!bus) { - printf("Failed to allocate MDIO bus\n"); - return -ENOMEM; - } - - bus->read = mpp2_mdio_read; - bus->write = mpp2_mdio_write; - snprintf(bus->name, sizeof(bus->name), dev->name); - bus->priv = (void *)priv; - priv->bus = bus; - - return mdio_register(bus); + return 0; } static int mvpp2_probe(struct udevice *dev) @@ -5456,7 +5318,7 @@ static int mvpp2_probe(struct udevice *dev) if (!priv->probe_done) err = mvpp2_base_probe(dev->parent); - port->priv = dev_get_priv(dev->parent); + port->priv = priv; err = phy_info_parse(dev, port); if (err) @@ -5485,7 +5347,7 @@ static int mvpp2_probe(struct udevice *dev) port->gop_id * MVPP22_PORT_OFFSET; /* Set phy address of the port */ - if(port->phy_node) + if (port->phyaddr < PHY_MAX_ADDR) mvpp22_smi_phy_addr_cfg(port); /* GoP Init */ @@ -5544,6 +5406,7 @@ static const struct eth_ops mvpp2_ops = { .send = mvpp2_send, .recv = mvpp2_recv, .stop = mvpp2_stop, + .write_hwaddr = mvpp2_write_hwaddr }; static struct driver mvpp2_driver = { @@ -5598,6 +5461,10 @@ static int mvpp2_base_bind(struct udevice *parent) id += base_id_add; name = calloc(1, 16); + if (!name) { + free(plat); + return -ENOMEM; + } sprintf(name, "mvpp2-%d", id); /* Create child device UCLASS_ETH and bind it */