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.c352
1 files changed, 269 insertions, 83 deletions
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index b9a6575009..3aafebaad4 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
@@ -52,6 +51,12 @@
#define CPDMA_DESC_EOP BIT(30)
#define CPDMA_DESC_OWNER BIT(29)
#define CPDMA_DESC_EOQ BIT(28)
+#define CPDMA_DESC_PASS_CRC BIT(26)
+#define CPDMA_DESC_TO_PORT_EN BIT(20)
+#define CPDMA_FROM_TO_PORT_SHIFT 16
+#define CPDMA_RX_SOURCE_PORT(__status__) \
+ (((__status__) >> CPDMA_FROM_TO_PORT_SHIFT) & 0x7)
+#define CPDMA_DESC_CRC_LEN 4
#define SLIVER_SIZE 0x40
@@ -161,16 +166,18 @@ enum cpsw_ale_port_state {
/* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */
#define ALE_SECURE 1
#define ALE_BLOCKED 2
+#define ALE_VLAN 4
struct cpsw_slave {
struct cpsw_slave_regs *regs;
struct cpsw_sliver_regs *sliver;
+ int port_vlan;
int slave_num;
int phy_id;
phy_interface_t phy_if;
struct eth_device edev;
struct cpsw_priv *cpsw;
- struct device_d dev;
+ struct device dev;
};
struct cpdma_desc {
@@ -190,7 +197,7 @@ struct cpdma_chan {
};
struct cpsw_priv {
- struct device_d *dev;
+ struct device *dev;
u32 version;
struct cpsw_platform_data data;
@@ -210,6 +217,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;
@@ -218,7 +227,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;
};
@@ -258,6 +267,7 @@ static inline void cpsw_ale_set_##name(u32 *ale_entry, u32 value) \
}
DEFINE_ALE_FIELD(entry_type, 60, 2)
+DEFINE_ALE_FIELD(vlan_id, 48, 12)
DEFINE_ALE_FIELD(mcast_state, 62, 2)
DEFINE_ALE_FIELD(port_mask, 66, 3)
DEFINE_ALE_FIELD(ucast_type, 62, 2)
@@ -265,6 +275,10 @@ DEFINE_ALE_FIELD(port_num, 66, 2)
DEFINE_ALE_FIELD(blocked, 65, 1)
DEFINE_ALE_FIELD(secure, 64, 1)
DEFINE_ALE_FIELD(mcast, 40, 1)
+DEFINE_ALE_FIELD(vlan_untag, 24, 3)
+DEFINE_ALE_FIELD(vlan_reg_mcast, 16, 3)
+DEFINE_ALE_FIELD(vlan_unreg_mcast, 8, 3)
+DEFINE_ALE_FIELD(vlan_member_list, 0, 3)
static char ethbdaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@@ -309,6 +323,23 @@ static int cpsw_ale_write(struct cpsw_priv *priv, int idx, u32 *ale_entry)
return idx;
}
+static int cpsw_ale_match_vlan(struct cpsw_priv *priv, u16 vid)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS];
+ int type, idx;
+
+ for (idx = 0; idx < priv->ale_entries; idx++) {
+ cpsw_ale_read(priv, idx, ale_entry);
+ type = cpsw_ale_get_entry_type(ale_entry);
+ if (type != ALE_TYPE_VLAN)
+ continue;
+ if (cpsw_ale_get_vlan_id(ale_entry) == vid)
+ return idx;
+ }
+
+ return -ENOENT;
+}
+
static int cpsw_ale_match_addr(struct cpsw_priv *priv, u8* addr)
{
u32 ale_entry[ALE_ENTRY_WORDS];
@@ -373,13 +404,47 @@ static int cpsw_ale_find_ageable(struct cpsw_priv *priv)
return -ENOENT;
}
+static int cpsw_ale_add_vlan(struct cpsw_priv *priv, u16 vid, int port_mask,
+ int untag, int reg_mcast, int unreg_mcast)
+{
+ u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
+ int idx;
+
+ idx = cpsw_ale_match_vlan(priv, vid);
+ if (idx >= 0)
+ cpsw_ale_read(priv, idx, ale_entry);
+
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN);
+ cpsw_ale_set_vlan_id(ale_entry, vid);
+ cpsw_ale_set_vlan_untag(ale_entry, untag);
+ cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast);
+ cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
+ cpsw_ale_set_vlan_member_list(ale_entry, port_mask);
+
+ if (idx < 0)
+ idx = cpsw_ale_match_free(priv);
+ if (idx < 0)
+ idx = cpsw_ale_find_ageable(priv);
+ if (idx < 0)
+ return -ENOMEM;
+
+ cpsw_ale_write(priv, idx, ale_entry);
+ return 0;
+}
+
static int cpsw_ale_add_ucast(struct cpsw_priv *priv, u8 *addr,
- int port, int flags)
+ int port, int flags, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx;
- cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+ if (flags & ALE_VLAN) {
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+ cpsw_ale_set_vlan_id(ale_entry, vid);
+ } else {
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+ }
+
cpsw_ale_set_addr(ale_entry, addr);
cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT);
cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0);
@@ -398,7 +463,8 @@ static int cpsw_ale_add_ucast(struct cpsw_priv *priv, u8 *addr,
return 0;
}
-static int cpsw_ale_add_mcast(struct cpsw_priv *priv, u8 *addr, int port_mask)
+static int cpsw_ale_add_mcast(struct cpsw_priv *priv, u8 *addr, int port_mask,
+ int flags, u16 vid, int mcast_state)
{
u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0};
int idx, mask;
@@ -407,9 +473,14 @@ static int cpsw_ale_add_mcast(struct cpsw_priv *priv, u8 *addr, int port_mask)
if (idx >= 0)
cpsw_ale_read(priv, idx, ale_entry);
- cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+ if (flags & ALE_VLAN) {
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR);
+ cpsw_ale_set_vlan_id(ale_entry, vid);
+ } else {
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR);
+ }
cpsw_ale_set_addr(ale_entry, addr);
- cpsw_ale_set_mcast_state(ale_entry, ALE_MCAST_FWD_2);
+ cpsw_ale_set_mcast_state(ale_entry, mcast_state);
mask = cpsw_ale_get_port_mask(ale_entry);
port_mask |= mask;
@@ -514,7 +585,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;
@@ -524,7 +595,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);
@@ -548,7 +624,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) {
@@ -581,8 +657,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),
@@ -673,6 +750,7 @@ static inline u32 cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
{
u32 slave_port;
+ u32 port_mask;
dev_dbg(&slave->dev, "* %s\n", __func__);
@@ -689,8 +767,22 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
slave_port = cpsw_get_slave_port(priv, slave->slave_num);
cpsw_ale_port_state(priv, slave_port, ALE_PORT_STATE_FORWARD);
+ port_mask = BIT(slave_port) | BIT(priv->host_port);
+
+ /* set port_vlan to host_vlan */
+ writel(BIT(slave->slave_num), &slave->regs->port_vlan);
+ slave->port_vlan = readl(&slave->regs->port_vlan);
+ slave->port_vlan &= 0xfff;
+
+ /* add dual emac default entries */
+ cpsw_ale_add_vlan(priv, slave->port_vlan, port_mask,
+ port_mask, port_mask, 0);
/* add broadcast address */
- cpsw_ale_add_mcast(priv, ethbdaddr, 1 << slave_port);
+ cpsw_ale_add_mcast(priv, ethbdaddr, BIT(priv->host_port), ALE_VLAN,
+ slave->port_vlan, 0);
+ cpsw_ale_add_ucast(priv, priv->mac_addr, priv->host_port,
+ ALE_SECURE | ALE_VLAN,
+ slave->port_vlan);
}
static struct cpdma_desc *cpdma_desc_alloc(struct cpsw_priv *priv)
@@ -714,7 +806,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)
+ void *sw_buffer, dma_addr_t hw_buffer,
+ int len, int port)
{
struct cpdma_desc *desc, *prev;
u32 mode;
@@ -728,11 +821,15 @@ static int cpdma_submit(struct cpsw_priv *priv, struct cpdma_chan *chan,
mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP;
+ if (port)
+ mode |= CPDMA_DESC_TO_PORT_EN |
+ (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) {
@@ -758,10 +855,11 @@ done:
return 0;
}
-static int cpdma_process(struct cpsw_priv *priv, struct cpdma_chan *chan,
- void **buffer, int *len)
+static int cpdma_process(struct cpsw_slave *slave, struct cpdma_chan *chan,
+ void **buffer, dma_addr_t *dma, int *len)
{
struct cpdma_desc *desc = chan->head;
+ struct cpsw_priv *priv = slave->cpsw;
u32 status;
if (!desc)
@@ -769,9 +867,14 @@ static int cpdma_process(struct cpsw_priv *priv, struct cpdma_chan *chan,
status = readl(&desc->hw_mode);
- if (len)
+ if (len) {
*len = status & 0x7ff;
+ if (status & CPDMA_DESC_PASS_CRC)
+ *len -= CPDMA_DESC_CRC_LEN;
+ }
+ if (dma)
+ *dma = readl(&desc->hw_buffer);
if (buffer)
*buffer = (void *)readl(&desc->sw_buffer);
@@ -783,6 +886,14 @@ static int cpdma_process(struct cpsw_priv *priv, struct cpdma_chan *chan,
return -EBUSY;
}
+ /* cpsw_send is cleaning finished descriptors on next send
+ * so we only have to check for rx channel here
+ */
+ if (CPDMA_RX_SOURCE_PORT(status) != BIT(slave->slave_num) &&
+ chan == &priv->rx_chan) {
+ return -ENOMSG;
+ }
+
chan->head = (void *)readl(&desc->hw_next);
writel((u32)desc, chan->cp);
@@ -801,15 +912,25 @@ static int cpsw_open(struct eth_device *edev)
{
struct cpsw_slave *slave = edev->priv;
struct cpsw_priv *priv = slave->cpsw;
- int i, ret;
+ int ret;
dev_dbg(&slave->dev, "* %s\n", __func__);
+ cpsw_slave_init(slave, priv);
+
ret = phy_device_connect(edev, NULL, slave->phy_id,
cpsw_adjust_link, 0, slave->phy_if);
if (ret)
return ret;
+ return 0;
+}
+
+static int cpsw_setup(struct device *dev)
+{
+ struct cpsw_priv *priv = dev->priv;
+ int i, ret;
+
/* soft reset the controller and initialize priv */
soft_reset(priv, &priv->regs->soft_reset);
@@ -817,7 +938,10 @@ static int cpsw_open(struct eth_device *edev)
cpsw_ale_enable(priv, 1);
cpsw_ale_clear(priv, 1);
cpsw_ale_bypass(priv, 0);
- cpsw_ale_vlan_aware(priv, 0); /* vlan unaware mode */
+ cpsw_ale_vlan_aware(priv, 1); /* vlan aware mode */
+
+ /* dual mac mode in fifo */
+ writel(BIT(16), &priv->host_port_regs->flow_thresh);
/* setup host port priority mapping */
writel(0x76543210, &priv->host_port_regs->cpdma_tx_pri_map);
@@ -831,12 +955,6 @@ static int cpsw_open(struct eth_device *edev)
cpsw_ale_port_state(priv, priv->host_port, ALE_PORT_STATE_FORWARD);
- cpsw_ale_add_ucast(priv, priv->mac_addr, priv->host_port,
- ALE_SECURE);
- cpsw_ale_add_mcast(priv, ethbdaddr, 1 << priv->host_port);
-
- cpsw_slave_init(slave, priv);
-
/* init descriptor pool */
for (i = 0; i < NUM_DESCS; i++) {
u32 val = (i == (NUM_DESCS - 1)) ? 0 : (u32)&priv->descs[i + 1];
@@ -872,10 +990,17 @@ static int cpsw_open(struct eth_device *edev)
/* submit rx descs */
for (i = 0; i < PKTBUFSRX - 2; i++) {
- ret = cpdma_submit(priv, &priv->rx_chan, NetRxPackets[i],
- PKTSIZE);
+ 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(&slave->dev, "error %d submitting rx desc\n", ret);
+ dev_err(dev, "error %d submitting rx desc\n", ret);
break;
}
}
@@ -904,19 +1029,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(priv, &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, length);
- dma_sync_single_for_cpu((unsigned long)packet, length, DMA_TO_DEVICE);
+ 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_unmap_single(priv->dev, dma, length, DMA_TO_DEVICE);
return ret;
}
@@ -925,16 +1052,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(priv, &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);
+ dma_sync_single_for_device(priv->dev, dma, len, DMA_FROM_DEVICE);
+ cpdma_submit(priv, &priv->rx_chan, buffer, dma, PKTSIZE, 0);
}
return 0;
@@ -954,7 +1080,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;
@@ -1015,7 +1141,7 @@ static struct cpsw_data cpsw1_data = {
.cpdma_reg_ofs = 0x100,
.state_ram_ofs = 0x200,
.ale_reg_ofs = 0x600,
- .slave_ofs = 0x050,
+ .slave_ofs = 0x058,
.slave_size = 0x040,
.sliver_ofs = 0x700,
/* FIXME: mdio_reg_ofs and cppi_ram_ofs missing */
@@ -1026,7 +1152,7 @@ static struct cpsw_data cpsw2_data = {
.cpdma_reg_ofs = 0x800,
.state_ram_ofs = 0xa00,
.ale_reg_ofs = 0xd00,
- .slave_ofs = 0x200,
+ .slave_ofs = 0x208,
.slave_size = 0x100,
.sliver_ofs = 0xd80,
.mdio_reg_ofs = 0x1000,
@@ -1110,11 +1236,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);
@@ -1123,15 +1265,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);
@@ -1140,34 +1273,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;
- cpsw_gmii_sel_am335x(slave);
+ 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++;
}
return 0;
}
-static int cpsw_probe(struct device_d *dev)
+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 *dev)
{
struct resource *iores;
struct cpsw_platform_data *data = (struct cpsw_platform_data *)dev->platform_data;
@@ -1178,19 +1355,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;
@@ -1241,6 +1422,8 @@ static int cpsw_probe(struct device_d *dev)
dev->priv = priv;
+ cpsw_setup(dev);
+
return 0;
out:
free(priv->slaves);
@@ -1249,7 +1432,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;
@@ -1265,13 +1448,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,