summaryrefslogtreecommitdiffstats
path: root/drivers/net/cpsw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/cpsw.c')
-rw-r--r--drivers/net/cpsw.c205
1 files changed, 140 insertions, 65 deletions
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index 4a8f9e67d6..31ca61a230 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -9,7 +9,6 @@
#include <command.h>
#include <dma.h>
-#include <net.h>
#include <malloc.h>
#include <net.h>
#include <linux/phy.h>
@@ -23,7 +22,7 @@
#include <asm/system.h>
#include <linux/err.h>
-#include <mach/cpsw.h>
+#include <mach/omap/cpsw.h>
#define CPSW_VERSION_1 0x19010a
#define CPSW_VERSION_2 0x19010c
@@ -176,7 +175,7 @@ struct cpsw_slave {
phy_interface_t phy_if;
struct eth_device edev;
struct cpsw_priv *cpsw;
- struct device_d dev;
+ struct device dev;
};
struct cpdma_desc {
@@ -196,7 +195,7 @@ struct cpdma_chan {
};
struct cpsw_priv {
- struct device_d *dev;
+ struct device *dev;
u32 version;
struct cpsw_platform_data data;
@@ -216,6 +215,8 @@ struct cpsw_priv {
unsigned int slave_size;
unsigned int sliver_ofs;
+ void *rx_buffer[PKTBUFSRX - 2];
+
struct cpdma_desc *descs;
struct cpdma_desc *desc_free;
struct cpdma_chan rx_chan, tx_chan;
@@ -224,7 +225,7 @@ struct cpsw_priv {
};
struct cpsw_mdio_priv {
- struct device_d *dev;
+ struct device *dev;
struct mii_bus miibus;
struct cpsw_mdio_regs *mdio_regs;
};
@@ -582,7 +583,7 @@ static int cpsw_mdio_write(struct mii_bus *bus, int phy_id, int phy_reg, u16 val
return 0;
}
-static int cpsw_mdio_probe(struct device_d *dev)
+static int cpsw_mdio_probe(struct device *dev)
{
struct resource *iores;
struct cpsw_mdio_priv *priv;
@@ -592,7 +593,12 @@ static int cpsw_mdio_probe(struct device_d *dev)
priv = xzalloc(sizeof(*priv));
+ /* If we can't request I/O memory region, we'll assume parent did
+ * it for us
+ */
iores = dev_request_mem_resource(dev, 0);
+ if (IS_ERR(iores) && PTR_ERR(iores) == -EBUSY)
+ iores = dev_get_resource(dev, IORESOURCE_MEM, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
priv->mdio_regs = IOMEM(iores->start);
@@ -616,7 +622,7 @@ static int cpsw_mdio_probe(struct device_d *dev)
* silicon. Since the effect of (b) was found to be largely
* negligible, we keep things simple here.
*/
- udelay(1000);
+ udelay(2000);
start = get_time_ns();
while (1) {
@@ -649,8 +655,9 @@ static __maybe_unused struct of_device_id cpsw_mdio_dt_ids[] = {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, cpsw_mdio_dt_ids);
-static struct driver_d cpsw_mdio_driver = {
+static struct driver cpsw_mdio_driver = {
.name = "cpsw-mdio",
.probe = cpsw_mdio_probe,
.of_compatible = DRV_OF_COMPAT(cpsw_mdio_dt_ids),
@@ -797,7 +804,8 @@ static void cpdma_desc_free(struct cpsw_priv *priv, struct cpdma_desc *desc)
}
static int cpdma_submit(struct cpsw_priv *priv, struct cpdma_chan *chan,
- void *buffer, int len, int port)
+ void *sw_buffer, dma_addr_t hw_buffer,
+ int len, int port)
{
struct cpdma_desc *desc, *prev;
u32 mode;
@@ -816,10 +824,10 @@ static int cpdma_submit(struct cpsw_priv *priv, struct cpdma_chan *chan,
(port << CPDMA_FROM_TO_PORT_SHIFT);
writel(0, &desc->hw_next);
- writel((u32)buffer, &desc->hw_buffer);
+ writel(hw_buffer, &desc->hw_buffer);
writel(len, &desc->hw_len);
writel(mode | len, &desc->hw_mode);
- writel((u32)buffer, &desc->sw_buffer);
+ writel((u32)sw_buffer, &desc->sw_buffer);
writel((u32)len, &desc->sw_len);
if (!chan->head) {
@@ -846,7 +854,7 @@ done:
}
static int cpdma_process(struct cpsw_slave *slave, struct cpdma_chan *chan,
- void **buffer, int *len)
+ void **buffer, dma_addr_t *dma, int *len)
{
struct cpdma_desc *desc = chan->head;
struct cpsw_priv *priv = slave->cpsw;
@@ -860,6 +868,8 @@ static int cpdma_process(struct cpsw_slave *slave, struct cpdma_chan *chan,
if (len)
*len = status & 0x7ff;
+ if (dma)
+ *dma = readl(&desc->hw_buffer);
if (buffer)
*buffer = (void *)readl(&desc->sw_buffer);
@@ -911,7 +921,7 @@ static int cpsw_open(struct eth_device *edev)
return 0;
}
-static int cpsw_setup(struct device_d *dev)
+static int cpsw_setup(struct device *dev)
{
struct cpsw_priv *priv = dev->priv;
int i, ret;
@@ -975,8 +985,15 @@ static int cpsw_setup(struct device_d *dev)
/* submit rx descs */
for (i = 0; i < PKTBUFSRX - 2; i++) {
- ret = cpdma_submit(priv, &priv->rx_chan, NetRxPackets[i],
- PKTSIZE, 0);
+ void *buffer = priv->rx_buffer[i];
+ unsigned len = PKTSIZE;
+ dma_addr_t dma;
+
+ dma = dma_map_single(priv->dev, buffer, len, DMA_FROM_DEVICE);
+ if (dma_mapping_error(priv->dev, dma))
+ return -EFAULT;
+
+ ret = cpdma_submit(priv, &priv->rx_chan, buffer, dma, len, 0);
if (ret < 0) {
dev_err(dev, "error %d submitting rx desc\n", ret);
break;
@@ -1007,20 +1024,21 @@ static int cpsw_send(struct eth_device *edev, void *packet, int length)
{
struct cpsw_slave *slave = edev->priv;
struct cpsw_priv *priv = slave->cpsw;
- void *buffer;
- int ret, len;
+ dma_addr_t dma;
+ int ret;
dev_dbg(&slave->dev, "* %s slave %d\n", __func__, slave->slave_num);
/* first reap completed packets */
- while (cpdma_process(slave, &priv->tx_chan, &buffer, &len) >= 0);
+ while (cpdma_process(slave, &priv->tx_chan, NULL, NULL, NULL) >= 0)
+ ;
dev_dbg(&slave->dev, "%s: %i bytes @ 0x%p\n", __func__, length, packet);
- dma_sync_single_for_device((unsigned long)packet, length, DMA_TO_DEVICE);
- ret = cpdma_submit(priv, &priv->tx_chan, packet,
+ dma = dma_map_single(priv->dev, packet, length, DMA_TO_DEVICE);
+ ret = cpdma_submit(priv, &priv->tx_chan, packet, dma,
length, BIT(slave->slave_num));
- dma_sync_single_for_cpu((unsigned long)packet, length, DMA_TO_DEVICE);
+ dma_unmap_single(priv->dev, dma, length, DMA_TO_DEVICE);
return ret;
}
@@ -1029,16 +1047,15 @@ static int cpsw_recv(struct eth_device *edev)
{
struct cpsw_slave *slave = edev->priv;
struct cpsw_priv *priv = slave->cpsw;
+ dma_addr_t dma;
void *buffer;
int len;
- while (cpdma_process(slave, &priv->rx_chan, &buffer, &len) >= 0) {
- dma_sync_single_for_cpu((unsigned long)buffer, len,
- DMA_FROM_DEVICE);
+ while (cpdma_process(slave, &priv->rx_chan, &buffer, &dma, &len) >= 0) {
+ dma_sync_single_for_cpu(priv->dev, dma, len, DMA_FROM_DEVICE);
net_receive(edev, buffer, len);
- dma_sync_single_for_device((unsigned long)buffer, len,
- DMA_FROM_DEVICE);
- cpdma_submit(priv, &priv->rx_chan, buffer, PKTSIZE, 0);
+ dma_sync_single_for_device(priv->dev, dma, len, DMA_FROM_DEVICE);
+ cpdma_submit(priv, &priv->rx_chan, buffer, dma, PKTSIZE, 0);
}
return 0;
@@ -1058,7 +1075,7 @@ static int cpsw_slave_setup(struct cpsw_slave *slave, int slave_num,
{
void *regs = priv->regs;
struct eth_device *edev = &slave->edev;
- struct device_d *dev = &slave->dev;
+ struct device *dev = &slave->dev;
int ret;
edev->parent = dev;
@@ -1214,11 +1231,27 @@ static void cpsw_gmii_sel_am335x(struct cpsw_slave *slave)
writel(reg, phy_sel_addr);
}
-static int cpsw_probe_dt(struct cpsw_priv *priv)
+static void cpsw_add_slave(struct cpsw_slave *slave, struct device_node *child, int i)
{
- struct device_d *dev = priv->dev;
- struct device_node *np = dev->device_node, *child;
- struct device_node *physel;
+ uint32_t phy_id[2] = {-1, -1};
+ int ret;
+
+ if (!of_find_node_by_name_address(child, "fixed-link")) {
+ ret = of_property_read_u32_array(child, "phy_id", phy_id, 2);
+ if (!ret)
+ dev_warn(slave->cpsw->dev, "phy_id is deprecated, use phy-handle\n");
+ }
+
+ slave->dev.of_node = child;
+ slave->phy_id = phy_id[1];
+ slave->phy_if = of_get_phy_mode(child);
+ slave->slave_num = i;
+}
+
+static int cpsw_legacy_probe_dt(struct cpsw_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct device_node *np = dev->of_node, *child;
int ret, i = 0;
ret = of_property_read_u32(np, "slaves", &priv->num_slaves);
@@ -1227,15 +1260,6 @@ static int cpsw_probe_dt(struct cpsw_priv *priv)
priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves);
- physel = of_find_compatible_node(NULL, NULL, "ti,am3352-phy-gmii-sel");
- if (!physel) {
- dev_err(dev, "Cannot find ti,am3352-phy-gmii-sel node\n");
- return -EINVAL;
- }
- ret = cpsw_phy_sel_init(priv, physel);
- if (ret)
- return ret;
-
for_each_child_of_node(np, child) {
if (of_device_is_compatible(child, "ti,davinci_mdio")) {
ret = of_pinctrl_select_state_default(child);
@@ -1244,34 +1268,78 @@ static int cpsw_probe_dt(struct cpsw_priv *priv)
}
if (i < priv->num_slaves && !strncmp(child->name, "slave", 5)) {
- struct cpsw_slave *slave = &priv->slaves[i];
- uint32_t phy_id[2] = {-1, -1};
+ cpsw_add_slave(&priv->slaves[i], child, i);
+ i++;
+ }
+ }
- if (!of_find_node_by_name(child, "fixed-link")) {
- ret = of_property_read_u32_array(child, "phy_id", phy_id, 2);
- if (!ret)
- dev_warn(dev, "phy_id is deprecated, use phy-handle\n");
- }
+ return 0;
+}
- slave->dev.device_node = child;
- slave->phy_id = phy_id[1];
- slave->phy_if = of_get_phy_mode(child);
- slave->slave_num = i;
+static int cpsw_switch_probe_dt(struct cpsw_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct device_node *np = dev->of_node, *child;
+ struct device_node *ports = NULL;
+ int ret, i = 0;
- i++;
+ for_each_child_of_node(np, child) {
+ if (of_device_is_compatible(child, "ti,davinci_mdio")) {
+ ret = of_pinctrl_select_state_default(child);
+ if (ret)
+ return ret;
+ }
+
+ if (!strcmp(child->name, "ethernet-ports")) {
+ ports = child;
+ priv->num_slaves = of_get_available_child_count(ports);
}
}
- for (i = 0; i < priv->num_slaves; i++) {
- struct cpsw_slave *slave = &priv->slaves[i];
+ if (!ports)
+ return -EINVAL;
+
+ priv->slaves = xzalloc(sizeof(struct cpsw_slave) * priv->num_slaves);
+
+ for_each_available_child_of_node(ports, child) {
+ cpsw_add_slave(&priv->slaves[i], child, i);
+ i++;
+ }
- cpsw_gmii_sel_am335x(slave);
+ return 0;
+}
+
+static int cpsw_probe_dt(struct cpsw_priv *priv)
+{
+ struct device *dev = priv->dev;
+ struct device_node *physel;
+ int (*probe_slaves_dt)(struct cpsw_priv *priv);
+ int ret, i = 0;
+
+ physel = of_find_compatible_node(NULL, NULL, "ti,am3352-phy-gmii-sel");
+ if (!physel) {
+ dev_err(dev, "Cannot find ti,am3352-phy-gmii-sel node\n");
+ return -EINVAL;
}
+ ret = cpsw_phy_sel_init(priv, physel);
+ if (ret)
+ return ret;
+
+ probe_slaves_dt = device_get_match_data(dev);
+ if (!probe_slaves_dt)
+ return -EINVAL;
+
+ ret = probe_slaves_dt(priv);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < priv->num_slaves; i++)
+ cpsw_gmii_sel_am335x(&priv->slaves[i]);
return 0;
}
-static int cpsw_probe(struct device_d *dev)
+static int cpsw_probe(struct device *dev)
{
struct resource *iores;
struct cpsw_platform_data *data = (struct cpsw_platform_data *)dev->platform_data;
@@ -1282,19 +1350,23 @@ static int cpsw_probe(struct device_d *dev)
dev_dbg(dev, "* %s\n", __func__);
- ret = of_platform_populate(dev->device_node, NULL, dev);
- if (ret)
- return ret;
-
iores = dev_request_mem_resource(dev, 0);
if (IS_ERR(iores))
return PTR_ERR(iores);
regs = IOMEM(iores->start);
+ ret = of_platform_populate(dev->of_node, NULL, dev);
+ if (ret)
+ return ret;
+
priv = xzalloc(sizeof(*priv));
priv->dev = dev;
- if (dev->device_node) {
+ ret = net_alloc_packets(priv->rx_buffer, ARRAY_SIZE(priv->rx_buffer));
+ if (ret)
+ goto out;
+
+ if (dev->of_node) {
ret = cpsw_probe_dt(priv);
if (ret)
goto out;
@@ -1355,7 +1427,7 @@ out:
return ret;
}
-static void cpsw_remove(struct device_d *dev)
+static void cpsw_remove(struct device *dev)
{
struct cpsw_priv *priv = dev->priv;
int i;
@@ -1371,13 +1443,16 @@ static void cpsw_remove(struct device_d *dev)
static __maybe_unused struct of_device_id cpsw_dt_ids[] = {
{
- .compatible = "ti,cpsw",
+ .compatible = "ti,cpsw", .data = cpsw_legacy_probe_dt
+ }, {
+ .compatible = "ti,cpsw-switch", .data = cpsw_switch_probe_dt
}, {
/* sentinel */
}
};
+MODULE_DEVICE_TABLE(of, cpsw_dt_ids);
-static struct driver_d cpsw_driver = {
+static struct driver cpsw_driver = {
.name = "cpsw",
.probe = cpsw_probe,
.remove = cpsw_remove,