#include <asm/arch/soc.h>
#include <linux/compat.h>
#include <linux/mbus.h>
+#include <asm-generic/gpio.h>
+#include <fdt_support.h>
DECLARE_GLOBAL_DATA_PTR;
#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK 0xff00
#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT 8
#define MVPP22_BM_MC_RLS_REG 0x64d4
+#define MVPP22_BM_POOL_BASE_HIGH_REG 0x6310
+#define MVPP22_BM_POOL_BASE_HIGH_MASK 0xff
/* TX Scheduler registers */
#define MVPP2_TXP_SCHED_PORT_INDEX_REG 0x8000
/* MPCS registers */
#define PCS40G_COMMON_CONTROL 0x14
-#define FORWARD_ERROR_CORRECTION_MASK BIT(1)
+#define FORWARD_ERROR_CORRECTION_MASK BIT(10)
#define PCS_CLOCK_RESET 0x14c
#define TX_SD_CLK_RESET_MASK BIT(0)
#define MVPP2_MAX_TXD 16
/* Amount of Tx descriptors that can be reserved at once by CPU */
-#define MVPP2_CPU_DESC_CHUNK 64
+#define MVPP2_CPU_DESC_CHUNK 16
/* Max number of Tx descriptors in each aggregated queue */
-#define MVPP2_AGGR_TXQ_SIZE 256
+#define MVPP2_AGGR_TXQ_SIZE 16
/* Descriptor aligned size */
#define MVPP2_DESC_ALIGNED_SIZE 32
struct mii_dev *bus;
int probe_done;
+ u8 num_ports;
};
struct mvpp2_pcpu_stats {
phy_interface_t phy_interface;
int phy_node;
int phyaddr;
+#ifdef CONFIG_DM_GPIO
+ struct gpio_desc phy_reset_gpio;
+ struct gpio_desc phy_tx_disable_gpio;
+#endif
int init;
unsigned int link;
unsigned int duplex;
mvpp2_write(priv, MVPP2_BM_POOL_BASE_REG(bm_pool->id),
lower_32_bits(bm_pool->dma_addr));
+ if (priv->hw_version == MVPP22)
+ mvpp2_write(priv, MVPP22_BM_POOL_BASE_HIGH_REG,
+ (upper_32_bits(bm_pool->dma_addr) &
+ MVPP22_BM_POOL_BASE_HIGH_MASK));
mvpp2_write(priv, MVPP2_BM_POOL_SIZE_REG(bm_pool->id), size);
val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id));
static void mvpp2_bm_bufs_free(struct udevice *dev, struct mvpp2 *priv,
struct mvpp2_bm_pool *bm_pool)
{
+ int i;
+
+ for (i = 0; i < bm_pool->buf_num; i++) {
+ /* Allocate buffer back from the buffer manager */
+ mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
+ }
+
bm_pool->buf_num = 0;
}
err = mvpp2_bm_pool_create(dev, priv, bm_pool, size);
if (err)
goto err_unroll_pools;
- mvpp2_bm_pool_bufsize_set(priv, bm_pool, 0);
+ mvpp2_bm_pool_bufsize_set(priv, bm_pool, RX_BUFFER_SIZE);
}
return 0;
}
}
- mvpp2_bm_pool_bufsize_set(port->priv, new_pool,
- MVPP2_RX_BUF_SIZE(new_pool->pkt_size));
-
return new_pool;
}
val |= MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
writel(val, port->base + MVPP2_GMAC_CTRL_4_REG);
- val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
- val |= MVPP2_GMAC_PORT_DIS_PADING_MASK;
- writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
-
val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
/*
* Configure GIG MAC to 1000Base-X mode connected to a fiber
val |= MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK;
writel(val, port->base + MVPP2_GMAC_CTRL_4_REG);
- val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
- val |= MVPP2_GMAC_PORT_DIS_PADING_MASK;
- writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
-
val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
/* configure GIG MAC to SGMII mode */
val &= ~MVPP2_GMAC_PORT_TYPE_MASK;
val |= MVPP2_GMAC_CTRL4_EXT_PIN_GMII_SEL_MASK;
writel(val, port->base + MVPP2_GMAC_CTRL_4_REG);
- val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
- val &= ~MVPP2_GMAC_PORT_DIS_PADING_MASK;
- writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
-
val = readl(port->base + MVPP2_GMAC_CTRL_0_REG);
/* configure GIG MAC to SGMII mode */
val &= ~MVPP2_GMAC_PORT_TYPE_MASK;
/* configure XG MAC mode */
val = readl(port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG);
- val &= ~MVPP22_XPCS_PCSMODE_OFFS;
+ val &= ~MVPP22_XPCS_PCSMODE_MASK;
val &= ~MVPP22_XPCS_LANEACTIVE_MASK;
val |= (2 * lane) << MVPP22_XPCS_LANEACTIVE_OFFS;
writel(val, port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG);
/* Set hw internals when starting port */
static void mvpp2_start_dev(struct mvpp2_port *port)
{
- mvpp2_gmac_max_rx_size_set(port);
+ switch (port->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_SGMII:
+ mvpp2_gmac_max_rx_size_set(port);
+ default:
+ break;
+ }
+
mvpp2_txp_max_tx_size_set(port);
if (port->priv->hw_version == MVPP21)
return err;
}
- err = mvpp2_phy_connect(dev, port);
- if (err < 0)
- return err;
+ if (port->phy_node) {
+ err = mvpp2_phy_connect(dev, port);
+ if (err < 0)
+ return err;
- mvpp2_link_event(port);
+ mvpp2_link_event(port);
+ } else {
+ mvpp2_egress_enable(port);
+ mvpp2_ingress_enable(port);
+ }
mvpp2_start_dev(port);
port->rxqs[queue] = rxq;
}
- /* Configure Rx queue group interrupt for this port */
- if (priv->hw_version == MVPP21) {
- mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id),
- CONFIG_MV_ETH_RXQ);
- } else {
- u32 val;
-
- val = (port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET);
- mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val);
-
- val = (CONFIG_MV_ETH_RXQ <<
- MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET);
- mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val);
- }
/* Create Rx descriptor rings */
for (queue = 0; queue < rxq_number; queue++) {
{
int port_node = dev_of_offset(dev);
const char *phy_mode_str;
- int phy_node;
+ int phy_node, mdio_off, cp_node;
u32 id;
- u32 phyaddr;
+ u32 phyaddr = 0;
int phy_mode = -1;
+ phys_addr_t mdio_addr;
phy_node = fdtdec_lookup_phandle(gd->fdt_blob, port_node, "phy");
- if (phy_node < 0) {
- dev_err(&pdev->dev, "missing phy\n");
- return -ENODEV;
+
+ if (phy_node > 0) {
+ 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;
+ }
+ } else {
+ phy_node = 0;
}
phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, "phy-mode", NULL);
return -EINVAL;
}
+#ifdef CONFIG_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,
+ &port->phy_tx_disable_gpio, GPIOD_IS_OUT);
+#endif
+
/*
* ToDo:
* Not sure if this DT property "phy-speed" will get accepted, so
port->phy_speed = fdtdec_get_int(gd->fdt_blob, port_node,
"phy-speed", 1000);
- phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0);
-
port->id = id;
if (port->priv->hw_version == MVPP21)
port->first_rxq = port->id * rxq_number;
return 0;
}
+#ifdef CONFIG_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);
+ }
+
+ if (dm_gpio_is_valid(&port->phy_tx_disable_gpio))
+ dm_gpio_set_value(&port->phy_tx_disable_gpio, 0);
+}
+#endif
+
/* Ports initialization */
static int mvpp2_port_probe(struct udevice *dev,
struct mvpp2_port *port,
}
mvpp2_port_power_up(port);
+#ifdef CONFIG_DM_GPIO
+ mvpp2_gpio_init(port);
+#endif
+
priv->port_list[port->id] = port;
+ priv->num_ports++;
return 0;
}
return -EINVAL;
}
- /* MBUS windows configuration */
- dram_target_info = mvebu_mbus_dram_info();
- if (dram_target_info)
- mvpp2_conf_mbus_windows(dram_target_info, priv);
-
if (priv->hw_version == MVPP22)
mvpp2_axi_init(priv);
+ else {
+ /* MBUS windows configuration */
+ dram_target_info = mvebu_mbus_dram_info();
+ if (dram_target_info)
+ mvpp2_conf_mbus_windows(dram_target_info, priv);
+ }
if (priv->hw_version == MVPP21) {
/* Disable HW PHY polling */
if (priv->hw_version == MVPP22)
mvpp2_tx_fifo_init(priv);
- /* Reset Rx queue group interrupt configuration */
- for (i = 0; i < MVPP2_MAX_PORTS; i++) {
- if (priv->hw_version == MVPP21) {
- mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(i),
- CONFIG_MV_ETH_RXQ);
- continue;
- } else {
- u32 val;
-
- val = (i << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET);
- mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val);
-
- val = (CONFIG_MV_ETH_RXQ <<
- MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET);
- mvpp2_write(priv,
- MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val);
- }
- }
-
if (priv->hw_version == MVPP21)
writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT,
priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG);
int pool, rx_bytes, err;
int rx_received;
struct mvpp2_rx_queue *rxq;
- u32 cause_rx_tx, cause_rx, cause_misc;
u8 *data;
- cause_rx_tx = mvpp2_read(port->priv,
- MVPP2_ISR_RX_TX_CAUSE_REG(port->id));
- cause_rx_tx &= ~MVPP2_CAUSE_TXQ_OCCUP_DESC_ALL_MASK;
- cause_misc = cause_rx_tx & MVPP2_CAUSE_MISC_SUM_MASK;
- if (!cause_rx_tx && !cause_misc)
- return 0;
-
- cause_rx = cause_rx_tx & MVPP2_CAUSE_RXQ_OCCUP_DESC_ALL_MASK;
-
/* Process RX packets */
- cause_rx |= port->pending_cause_rx;
- rxq = mvpp2_get_rx_queue(port, cause_rx);
+ rxq = port->rxqs[0];
/* Get number of received packets and clamp the to-do */
rx_received = mvpp2_rxq_received(port, rxq->id);
return rx_bytes;
}
-/* Drain Txq */
-static void mvpp2_txq_drain(struct mvpp2_port *port, struct mvpp2_tx_queue *txq,
- int enable)
-{
- u32 val;
-
- mvpp2_write(port->priv, MVPP2_TXQ_NUM_REG, txq->id);
- val = mvpp2_read(port->priv, MVPP2_TXQ_PREF_BUF_REG);
- if (enable)
- val |= MVPP2_TXQ_DRAIN_EN_MASK;
- else
- val &= ~MVPP2_TXQ_DRAIN_EN_MASK;
- mvpp2_write(port->priv, MVPP2_TXQ_PREF_BUF_REG, val);
-}
-
static int mvpp2_send(struct udevice *dev, void *packet, int length)
{
struct mvpp2_port *port = dev_get_priv(dev);
tx_done = mvpp2_txq_pend_desc_num_get(port, txq);
} while (tx_done);
- /* Enable TXQ drain */
- mvpp2_txq_drain(port, txq, 1);
-
timeout = 0;
do {
if (timeout++ > 10000) {
tx_done = mvpp2_txq_sent_desc_proc(port, txq);
} while (!tx_done);
- /* Disable TXQ drain */
- mvpp2_txq_drain(port, txq, 0);
-
return 0;
}
/* Reconfigure parser accept the original MAC address */
mvpp2_prs_update_mac_da(port, port->dev_addr);
- mvpp2_port_power_up(port);
+ switch (port->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ case PHY_INTERFACE_MODE_SGMII:
+ mvpp2_port_power_up(port);
+ default:
+ break;
+ }
mvpp2_open(dev, port);
memset(bd_space, 0, size);
/* Save base addresses for later use */
- priv->base = (void *)dev_get_addr_index(dev, 0);
+ priv->base = (void *)devfdt_get_addr_index(dev, 0);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
if (priv->hw_version == MVPP21) {
- priv->lms_base = (void *)dev_get_addr_index(dev, 1);
+ 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 *)dev_get_addr_index(dev, 1);
+ priv->iface_base = (void *)devfdt_get_addr_index(dev, 1);
if (IS_ERR(priv->iface_base))
return PTR_ERR(priv->iface_base);
int err;
/* Only call the probe function for the parent once */
- if (!priv->probe_done) {
+ if (!priv->probe_done)
err = mvpp2_base_probe(dev->parent);
- priv->probe_done = 1;
- }
port->priv = dev_get_priv(dev->parent);
if (priv->hw_version == MVPP21) {
int priv_common_regs_num = 2;
- port->base = (void __iomem *)dev_get_addr_index(
+ port->base = (void __iomem *)devfdt_get_addr_index(
dev->parent, priv_common_regs_num + port->id);
if (IS_ERR(port->base))
return PTR_ERR(port->base);
port->gop_id * MVPP22_PORT_OFFSET;
/* Set phy address of the port */
- mvpp22_smi_phy_addr_cfg(port);
+ if(port->phy_node)
+ mvpp22_smi_phy_addr_cfg(port);
/* GoP Init */
gop_port_init(port);
}
- /* Initialize network controller */
- err = mvpp2_init(dev, priv);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to initialize controller\n");
- return err;
+ if (!priv->probe_done) {
+ /* Initialize network controller */
+ err = mvpp2_init(dev, priv);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to initialize controller\n");
+ return err;
+ }
+ priv->num_ports = 0;
+ priv->probe_done = 1;
}
err = mvpp2_port_probe(dev, port, dev_of_offset(dev), priv);
return 0;
}
+/*
+ * Empty BM pool and stop its activity before the OS is started
+ */
+static int mvpp2_remove(struct udevice *dev)
+{
+ struct mvpp2_port *port = dev_get_priv(dev);
+ struct mvpp2 *priv = port->priv;
+ int i;
+
+ priv->num_ports--;
+
+ if (priv->num_ports)
+ return 0;
+
+ for (i = 0; i < MVPP2_BM_POOLS_NUM; i++)
+ mvpp2_bm_pool_destroy(dev, priv, &priv->bm_pools[i]);
+
+ return 0;
+}
+
static const struct eth_ops mvpp2_ops = {
.start = mvpp2_start,
.send = mvpp2_send,
.name = "mvpp2",
.id = UCLASS_ETH,
.probe = mvpp2_probe,
+ .remove = mvpp2_remove,
.ops = &mvpp2_ops,
.priv_auto_alloc_size = sizeof(struct mvpp2_port),
.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ACTIVE_DMA,
};
/*
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 */