drivers: net: ethernet: cpsw: Add device tree support to CPSW
This patch adds device tree support for cpsw driver Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
f07454fe2d
Коммит
2eb32b0a6f
|
@ -0,0 +1,104 @@
|
|||
TI SoC Ethernet Switch Controller Device Tree Bindings
|
||||
------------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be "ti,cpsw"
|
||||
- reg : physical base address and size of the cpsw
|
||||
registers map
|
||||
- interrupts : property with a value describing the interrupt
|
||||
number
|
||||
- interrupt-parent : The parent interrupt controller
|
||||
- cpdma_channels : Specifies number of channels in CPDMA
|
||||
- host_port_no : Specifies host port shift
|
||||
- cpdma_reg_ofs : Specifies CPDMA submodule register offset
|
||||
- ale_reg_ofs : Specifies ALE submodule register offset
|
||||
- ale_entries : Specifies No of entries ALE can hold
|
||||
- host_port_reg_ofs : Specifies host port register offset
|
||||
- hw_stats_reg_ofs : Specifies hardware statistics register offset
|
||||
- bd_ram_ofs : Specifies internal desciptor RAM offset
|
||||
- bd_ram_size : Specifies internal descriptor RAM size
|
||||
- rx_descs : Specifies number of Rx descriptors
|
||||
- mac_control : Specifies Default MAC control register content
|
||||
for the specific platform
|
||||
- slaves : Specifies number for slaves
|
||||
- slave_reg_ofs : Specifies slave register offset
|
||||
- sliver_reg_ofs : Specifies slave sliver register offset
|
||||
- phy_id : Specifies slave phy id
|
||||
- mac-address : Specifies slave MAC address
|
||||
|
||||
Optional properties:
|
||||
- ti,hwmods : Must be "cpgmac0"
|
||||
- no_bd_ram : Must be 0 or 1
|
||||
|
||||
Note: "ti,hwmods" field is used to fetch the base address and irq
|
||||
resources from TI, omap hwmod data base during device registration.
|
||||
Future plan is to migrate hwmod data base contents into device tree
|
||||
blob so that, all the required data will be used from device tree dts
|
||||
file.
|
||||
|
||||
Examples:
|
||||
|
||||
mac: ethernet@4A100000 {
|
||||
compatible = "ti,cpsw";
|
||||
reg = <0x4A100000 0x1000>;
|
||||
interrupts = <55 0x4>;
|
||||
interrupt-parent = <&intc>;
|
||||
cpdma_channels = 8;
|
||||
host_port_no = 0;
|
||||
cpdma_reg_ofs = 0x800;
|
||||
ale_reg_ofs = 0xd00;
|
||||
ale_entries = 1024;
|
||||
host_port_reg_ofs = 0x108;
|
||||
hw_stats_reg_ofs = 0x900;
|
||||
bd_ram_ofs = 0x2000;
|
||||
bd_ram_size = 0x2000;
|
||||
no_bd_ram = 0;
|
||||
rx_descs = 64;
|
||||
mac_control = 0x20;
|
||||
slaves = 2;
|
||||
slave@0 {
|
||||
slave_reg_ofs = 0x208;
|
||||
sliver_reg_ofs = 0xd80;
|
||||
phy_id = "davinci_mdio-0:00"
|
||||
mac-address = [00 04 9F 01 1B B8];
|
||||
};
|
||||
slave@1 {
|
||||
slave_reg_ofs = 0x208;
|
||||
sliver_reg_ofs = 0xd80;
|
||||
phy_id = "davinci_mdio-0:01"
|
||||
mac-address = [00 04 9F 01 1B B9];
|
||||
};
|
||||
};
|
||||
|
||||
(or)
|
||||
|
||||
mac: ethernet@4A100000 {
|
||||
compatible = "ti,cpsw";
|
||||
ti,hwmods = "cpgmac0";
|
||||
cpdma_channels = 8;
|
||||
host_port_no = 0;
|
||||
cpdma_reg_ofs = 0x800;
|
||||
ale_reg_ofs = 0xd00;
|
||||
ale_entries = 1024;
|
||||
host_port_reg_ofs = 0x108;
|
||||
hw_stats_reg_ofs = 0x900;
|
||||
bd_ram_ofs = 0x2000;
|
||||
bd_ram_size = 0x2000;
|
||||
no_bd_ram = 0;
|
||||
rx_descs = 64;
|
||||
mac_control = 0x20;
|
||||
slaves = 2;
|
||||
slave@0 {
|
||||
slave_reg_ofs = 0x208;
|
||||
sliver_reg_ofs = 0xd80;
|
||||
phy_id = "davinci_mdio-0:00"
|
||||
mac-address = [00 04 9F 01 1B B8];
|
||||
};
|
||||
slave@1 {
|
||||
slave_reg_ofs = 0x208;
|
||||
sliver_reg_ofs = 0xd80;
|
||||
phy_id = "davinci_mdio-0:01"
|
||||
mac-address = [00 04 9F 01 1B B9];
|
||||
};
|
||||
|
||||
};
|
|
@ -28,6 +28,9 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <linux/platform_data/cpsw.h>
|
||||
|
||||
|
@ -709,6 +712,158 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
|
|||
slave->sliver = regs + data->sliver_reg_ofs;
|
||||
}
|
||||
|
||||
static int cpsw_probe_dt(struct cpsw_platform_data *data,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct device_node *slave_node;
|
||||
int i = 0, ret;
|
||||
u32 prop;
|
||||
|
||||
if (!node)
|
||||
return -EINVAL;
|
||||
|
||||
if (of_property_read_u32(node, "slaves", &prop)) {
|
||||
pr_err("Missing slaves property in the DT.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
data->slaves = prop;
|
||||
|
||||
data->slave_data = kzalloc(sizeof(struct cpsw_slave_data) *
|
||||
data->slaves, GFP_KERNEL);
|
||||
if (!data->slave_data) {
|
||||
pr_err("Could not allocate slave memory.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
data->no_bd_ram = of_property_read_bool(node, "no_bd_ram");
|
||||
|
||||
if (of_property_read_u32(node, "cpdma_channels", &prop)) {
|
||||
pr_err("Missing cpdma_channels property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->channels = prop;
|
||||
|
||||
if (of_property_read_u32(node, "host_port_no", &prop)) {
|
||||
pr_err("Missing host_port_no property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->host_port_num = prop;
|
||||
|
||||
if (of_property_read_u32(node, "cpdma_reg_ofs", &prop)) {
|
||||
pr_err("Missing cpdma_reg_ofs property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->cpdma_reg_ofs = prop;
|
||||
|
||||
if (of_property_read_u32(node, "cpdma_sram_ofs", &prop)) {
|
||||
pr_err("Missing cpdma_sram_ofs property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->cpdma_sram_ofs = prop;
|
||||
|
||||
if (of_property_read_u32(node, "ale_reg_ofs", &prop)) {
|
||||
pr_err("Missing ale_reg_ofs property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->ale_reg_ofs = prop;
|
||||
|
||||
if (of_property_read_u32(node, "ale_entries", &prop)) {
|
||||
pr_err("Missing ale_entries property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->ale_entries = prop;
|
||||
|
||||
if (of_property_read_u32(node, "host_port_reg_ofs", &prop)) {
|
||||
pr_err("Missing host_port_reg_ofs property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->host_port_reg_ofs = prop;
|
||||
|
||||
if (of_property_read_u32(node, "hw_stats_reg_ofs", &prop)) {
|
||||
pr_err("Missing hw_stats_reg_ofs property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->hw_stats_reg_ofs = prop;
|
||||
|
||||
if (of_property_read_u32(node, "bd_ram_ofs", &prop)) {
|
||||
pr_err("Missing bd_ram_ofs property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->bd_ram_ofs = prop;
|
||||
|
||||
if (of_property_read_u32(node, "bd_ram_size", &prop)) {
|
||||
pr_err("Missing bd_ram_size property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->bd_ram_size = prop;
|
||||
|
||||
if (of_property_read_u32(node, "rx_descs", &prop)) {
|
||||
pr_err("Missing rx_descs property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->rx_descs = prop;
|
||||
|
||||
if (of_property_read_u32(node, "mac_control", &prop)) {
|
||||
pr_err("Missing mac_control property in the DT.\n");
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
data->mac_control = prop;
|
||||
|
||||
for_each_child_of_node(node, slave_node) {
|
||||
struct cpsw_slave_data *slave_data = data->slave_data + i;
|
||||
const char *phy_id = NULL;
|
||||
const void *mac_addr = NULL;
|
||||
|
||||
if (of_property_read_string(slave_node, "phy_id", &phy_id)) {
|
||||
pr_err("Missing slave[%d] phy_id property\n", i);
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
slave_data->phy_id = phy_id;
|
||||
|
||||
if (of_property_read_u32(slave_node, "slave_reg_ofs", &prop)) {
|
||||
pr_err("Missing slave[%d] slave_reg_ofs property\n", i);
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
slave_data->slave_reg_ofs = prop;
|
||||
|
||||
if (of_property_read_u32(slave_node, "sliver_reg_ofs",
|
||||
&prop)) {
|
||||
pr_err("Missing slave[%d] sliver_reg_ofs property\n",
|
||||
i);
|
||||
ret = -EINVAL;
|
||||
goto error_ret;
|
||||
}
|
||||
slave_data->sliver_reg_ofs = prop;
|
||||
|
||||
mac_addr = of_get_mac_address(slave_node);
|
||||
if (mac_addr)
|
||||
memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_ret:
|
||||
kfree(data->slave_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit cpsw_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cpsw_platform_data *data = pdev->dev.platform_data;
|
||||
|
@ -720,11 +875,6 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
int ret = 0, i, k = 0;
|
||||
|
||||
if (!data) {
|
||||
pr_err("platform data missing\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ndev = alloc_etherdev(sizeof(struct cpsw_priv));
|
||||
if (!ndev) {
|
||||
pr_err("error allocating net_device\n");
|
||||
|
@ -734,13 +884,19 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, ndev);
|
||||
priv = netdev_priv(ndev);
|
||||
spin_lock_init(&priv->lock);
|
||||
priv->data = *data;
|
||||
priv->pdev = pdev;
|
||||
priv->ndev = ndev;
|
||||
priv->dev = &ndev->dev;
|
||||
priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
|
||||
priv->rx_packet_max = max(rx_packet_max, 128);
|
||||
|
||||
if (cpsw_probe_dt(&priv->data, pdev)) {
|
||||
pr_err("cpsw: platform data missing\n");
|
||||
ret = -ENODEV;
|
||||
goto clean_ndev_ret;
|
||||
}
|
||||
data = &priv->data;
|
||||
|
||||
if (is_valid_ether_addr(data->slave_data[0].mac_addr)) {
|
||||
memcpy(priv->mac_addr, data->slave_data[0].mac_addr, ETH_ALEN);
|
||||
pr_info("Detected MACID = %pM", priv->mac_addr);
|
||||
|
@ -996,11 +1152,17 @@ static const struct dev_pm_ops cpsw_pm_ops = {
|
|||
.resume = cpsw_resume,
|
||||
};
|
||||
|
||||
static const struct of_device_id cpsw_of_mtable[] = {
|
||||
{ .compatible = "ti,cpsw", },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver cpsw_driver = {
|
||||
.driver = {
|
||||
.name = "cpsw",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &cpsw_pm_ops,
|
||||
.of_match_table = of_match_ptr(cpsw_of_mtable),
|
||||
},
|
||||
.probe = cpsw_probe,
|
||||
.remove = __devexit_p(cpsw_remove),
|
||||
|
|
Загрузка…
Ссылка в новой задаче