diff options
-rw-r--r-- | Documentation/devicetree/bindings/net/cpsw.txt | 104 | ||||
-rw-r--r-- | drivers/net/ethernet/ti/cpsw.c | 174 |
2 files changed, 272 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt new file mode 100644 index 000000000000..acca48c4246d --- /dev/null +++ b/Documentation/devicetree/bindings/net/cpsw.txt | |||
@@ -0,0 +1,104 @@ | |||
1 | TI SoC Ethernet Switch Controller Device Tree Bindings | ||
2 | ------------------------------------------------------ | ||
3 | |||
4 | Required properties: | ||
5 | - compatible : Should be "ti,cpsw" | ||
6 | - reg : physical base address and size of the cpsw | ||
7 | registers map | ||
8 | - interrupts : property with a value describing the interrupt | ||
9 | number | ||
10 | - interrupt-parent : The parent interrupt controller | ||
11 | - cpdma_channels : Specifies number of channels in CPDMA | ||
12 | - host_port_no : Specifies host port shift | ||
13 | - cpdma_reg_ofs : Specifies CPDMA submodule register offset | ||
14 | - ale_reg_ofs : Specifies ALE submodule register offset | ||
15 | - ale_entries : Specifies No of entries ALE can hold | ||
16 | - host_port_reg_ofs : Specifies host port register offset | ||
17 | - hw_stats_reg_ofs : Specifies hardware statistics register offset | ||
18 | - bd_ram_ofs : Specifies internal desciptor RAM offset | ||
19 | - bd_ram_size : Specifies internal descriptor RAM size | ||
20 | - rx_descs : Specifies number of Rx descriptors | ||
21 | - mac_control : Specifies Default MAC control register content | ||
22 | for the specific platform | ||
23 | - slaves : Specifies number for slaves | ||
24 | - slave_reg_ofs : Specifies slave register offset | ||
25 | - sliver_reg_ofs : Specifies slave sliver register offset | ||
26 | - phy_id : Specifies slave phy id | ||
27 | - mac-address : Specifies slave MAC address | ||
28 | |||
29 | Optional properties: | ||
30 | - ti,hwmods : Must be "cpgmac0" | ||
31 | - no_bd_ram : Must be 0 or 1 | ||
32 | |||
33 | Note: "ti,hwmods" field is used to fetch the base address and irq | ||
34 | resources from TI, omap hwmod data base during device registration. | ||
35 | Future plan is to migrate hwmod data base contents into device tree | ||
36 | blob so that, all the required data will be used from device tree dts | ||
37 | file. | ||
38 | |||
39 | Examples: | ||
40 | |||
41 | mac: ethernet@4A100000 { | ||
42 | compatible = "ti,cpsw"; | ||
43 | reg = <0x4A100000 0x1000>; | ||
44 | interrupts = <55 0x4>; | ||
45 | interrupt-parent = <&intc>; | ||
46 | cpdma_channels = 8; | ||
47 | host_port_no = 0; | ||
48 | cpdma_reg_ofs = 0x800; | ||
49 | ale_reg_ofs = 0xd00; | ||
50 | ale_entries = 1024; | ||
51 | host_port_reg_ofs = 0x108; | ||
52 | hw_stats_reg_ofs = 0x900; | ||
53 | bd_ram_ofs = 0x2000; | ||
54 | bd_ram_size = 0x2000; | ||
55 | no_bd_ram = 0; | ||
56 | rx_descs = 64; | ||
57 | mac_control = 0x20; | ||
58 | slaves = 2; | ||
59 | slave@0 { | ||
60 | slave_reg_ofs = 0x208; | ||
61 | sliver_reg_ofs = 0xd80; | ||
62 | phy_id = "davinci_mdio-0:00" | ||
63 | mac-address = [00 04 9F 01 1B B8]; | ||
64 | }; | ||
65 | slave@1 { | ||
66 | slave_reg_ofs = 0x208; | ||
67 | sliver_reg_ofs = 0xd80; | ||
68 | phy_id = "davinci_mdio-0:01" | ||
69 | mac-address = [00 04 9F 01 1B B9]; | ||
70 | }; | ||
71 | }; | ||
72 | |||
73 | (or) | ||
74 | |||
75 | mac: ethernet@4A100000 { | ||
76 | compatible = "ti,cpsw"; | ||
77 | ti,hwmods = "cpgmac0"; | ||
78 | cpdma_channels = 8; | ||
79 | host_port_no = 0; | ||
80 | cpdma_reg_ofs = 0x800; | ||
81 | ale_reg_ofs = 0xd00; | ||
82 | ale_entries = 1024; | ||
83 | host_port_reg_ofs = 0x108; | ||
84 | hw_stats_reg_ofs = 0x900; | ||
85 | bd_ram_ofs = 0x2000; | ||
86 | bd_ram_size = 0x2000; | ||
87 | no_bd_ram = 0; | ||
88 | rx_descs = 64; | ||
89 | mac_control = 0x20; | ||
90 | slaves = 2; | ||
91 | slave@0 { | ||
92 | slave_reg_ofs = 0x208; | ||
93 | sliver_reg_ofs = 0xd80; | ||
94 | phy_id = "davinci_mdio-0:00" | ||
95 | mac-address = [00 04 9F 01 1B B8]; | ||
96 | }; | ||
97 | slave@1 { | ||
98 | slave_reg_ofs = 0x208; | ||
99 | sliver_reg_ofs = 0xd80; | ||
100 | phy_id = "davinci_mdio-0:01" | ||
101 | mac-address = [00 04 9F 01 1B B9]; | ||
102 | }; | ||
103 | |||
104 | }; | ||
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 1e5d85b06e71..0cbc0e59252c 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/pm_runtime.h> | 30 | #include <linux/pm_runtime.h> |
31 | #include <linux/of.h> | ||
32 | #include <linux/of_net.h> | ||
33 | #include <linux/of_device.h> | ||
31 | 34 | ||
32 | #include <linux/platform_data/cpsw.h> | 35 | #include <linux/platform_data/cpsw.h> |
33 | 36 | ||
@@ -709,6 +712,158 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv) | |||
709 | slave->sliver = regs + data->sliver_reg_ofs; | 712 | slave->sliver = regs + data->sliver_reg_ofs; |
710 | } | 713 | } |
711 | 714 | ||
715 | static int cpsw_probe_dt(struct cpsw_platform_data *data, | ||
716 | struct platform_device *pdev) | ||
717 | { | ||
718 | struct device_node *node = pdev->dev.of_node; | ||
719 | struct device_node *slave_node; | ||
720 | int i = 0, ret; | ||
721 | u32 prop; | ||
722 | |||
723 | if (!node) | ||
724 | return -EINVAL; | ||
725 | |||
726 | if (of_property_read_u32(node, "slaves", &prop)) { | ||
727 | pr_err("Missing slaves property in the DT.\n"); | ||
728 | return -EINVAL; | ||
729 | } | ||
730 | data->slaves = prop; | ||
731 | |||
732 | data->slave_data = kzalloc(sizeof(struct cpsw_slave_data) * | ||
733 | data->slaves, GFP_KERNEL); | ||
734 | if (!data->slave_data) { | ||
735 | pr_err("Could not allocate slave memory.\n"); | ||
736 | return -EINVAL; | ||
737 | } | ||
738 | |||
739 | data->no_bd_ram = of_property_read_bool(node, "no_bd_ram"); | ||
740 | |||
741 | if (of_property_read_u32(node, "cpdma_channels", &prop)) { | ||
742 | pr_err("Missing cpdma_channels property in the DT.\n"); | ||
743 | ret = -EINVAL; | ||
744 | goto error_ret; | ||
745 | } | ||
746 | data->channels = prop; | ||
747 | |||
748 | if (of_property_read_u32(node, "host_port_no", &prop)) { | ||
749 | pr_err("Missing host_port_no property in the DT.\n"); | ||
750 | ret = -EINVAL; | ||
751 | goto error_ret; | ||
752 | } | ||
753 | data->host_port_num = prop; | ||
754 | |||
755 | if (of_property_read_u32(node, "cpdma_reg_ofs", &prop)) { | ||
756 | pr_err("Missing cpdma_reg_ofs property in the DT.\n"); | ||
757 | ret = -EINVAL; | ||
758 | goto error_ret; | ||
759 | } | ||
760 | data->cpdma_reg_ofs = prop; | ||
761 | |||
762 | if (of_property_read_u32(node, "cpdma_sram_ofs", &prop)) { | ||
763 | pr_err("Missing cpdma_sram_ofs property in the DT.\n"); | ||
764 | ret = -EINVAL; | ||
765 | goto error_ret; | ||
766 | } | ||
767 | data->cpdma_sram_ofs = prop; | ||
768 | |||
769 | if (of_property_read_u32(node, "ale_reg_ofs", &prop)) { | ||
770 | pr_err("Missing ale_reg_ofs property in the DT.\n"); | ||
771 | ret = -EINVAL; | ||
772 | goto error_ret; | ||
773 | } | ||
774 | data->ale_reg_ofs = prop; | ||
775 | |||
776 | if (of_property_read_u32(node, "ale_entries", &prop)) { | ||
777 | pr_err("Missing ale_entries property in the DT.\n"); | ||
778 | ret = -EINVAL; | ||
779 | goto error_ret; | ||
780 | } | ||
781 | data->ale_entries = prop; | ||
782 | |||
783 | if (of_property_read_u32(node, "host_port_reg_ofs", &prop)) { | ||
784 | pr_err("Missing host_port_reg_ofs property in the DT.\n"); | ||
785 | ret = -EINVAL; | ||
786 | goto error_ret; | ||
787 | } | ||
788 | data->host_port_reg_ofs = prop; | ||
789 | |||
790 | if (of_property_read_u32(node, "hw_stats_reg_ofs", &prop)) { | ||
791 | pr_err("Missing hw_stats_reg_ofs property in the DT.\n"); | ||
792 | ret = -EINVAL; | ||
793 | goto error_ret; | ||
794 | } | ||
795 | data->hw_stats_reg_ofs = prop; | ||
796 | |||
797 | if (of_property_read_u32(node, "bd_ram_ofs", &prop)) { | ||
798 | pr_err("Missing bd_ram_ofs property in the DT.\n"); | ||
799 | ret = -EINVAL; | ||
800 | goto error_ret; | ||
801 | } | ||
802 | data->bd_ram_ofs = prop; | ||
803 | |||
804 | if (of_property_read_u32(node, "bd_ram_size", &prop)) { | ||
805 | pr_err("Missing bd_ram_size property in the DT.\n"); | ||
806 | ret = -EINVAL; | ||
807 | goto error_ret; | ||
808 | } | ||
809 | data->bd_ram_size = prop; | ||
810 | |||
811 | if (of_property_read_u32(node, "rx_descs", &prop)) { | ||
812 | pr_err("Missing rx_descs property in the DT.\n"); | ||
813 | ret = -EINVAL; | ||
814 | goto error_ret; | ||
815 | } | ||
816 | data->rx_descs = prop; | ||
817 | |||
818 | if (of_property_read_u32(node, "mac_control", &prop)) { | ||
819 | pr_err("Missing mac_control property in the DT.\n"); | ||
820 | ret = -EINVAL; | ||
821 | goto error_ret; | ||
822 | } | ||
823 | data->mac_control = prop; | ||
824 | |||
825 | for_each_child_of_node(node, slave_node) { | ||
826 | struct cpsw_slave_data *slave_data = data->slave_data + i; | ||
827 | const char *phy_id = NULL; | ||
828 | const void *mac_addr = NULL; | ||
829 | |||
830 | if (of_property_read_string(slave_node, "phy_id", &phy_id)) { | ||
831 | pr_err("Missing slave[%d] phy_id property\n", i); | ||
832 | ret = -EINVAL; | ||
833 | goto error_ret; | ||
834 | } | ||
835 | slave_data->phy_id = phy_id; | ||
836 | |||
837 | if (of_property_read_u32(slave_node, "slave_reg_ofs", &prop)) { | ||
838 | pr_err("Missing slave[%d] slave_reg_ofs property\n", i); | ||
839 | ret = -EINVAL; | ||
840 | goto error_ret; | ||
841 | } | ||
842 | slave_data->slave_reg_ofs = prop; | ||
843 | |||
844 | if (of_property_read_u32(slave_node, "sliver_reg_ofs", | ||
845 | &prop)) { | ||
846 | pr_err("Missing slave[%d] sliver_reg_ofs property\n", | ||
847 | i); | ||
848 | ret = -EINVAL; | ||
849 | goto error_ret; | ||
850 | } | ||
851 | slave_data->sliver_reg_ofs = prop; | ||
852 | |||
853 | mac_addr = of_get_mac_address(slave_node); | ||
854 | if (mac_addr) | ||
855 | memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN); | ||
856 | |||
857 | i++; | ||
858 | } | ||
859 | |||
860 | return 0; | ||
861 | |||
862 | error_ret: | ||
863 | kfree(data->slave_data); | ||
864 | return ret; | ||
865 | } | ||
866 | |||
712 | static int __devinit cpsw_probe(struct platform_device *pdev) | 867 | static int __devinit cpsw_probe(struct platform_device *pdev) |
713 | { | 868 | { |
714 | struct cpsw_platform_data *data = pdev->dev.platform_data; | 869 | struct cpsw_platform_data *data = pdev->dev.platform_data; |
@@ -720,11 +875,6 @@ static int __devinit cpsw_probe(struct platform_device *pdev) | |||
720 | struct resource *res; | 875 | struct resource *res; |
721 | int ret = 0, i, k = 0; | 876 | int ret = 0, i, k = 0; |
722 | 877 | ||
723 | if (!data) { | ||
724 | pr_err("platform data missing\n"); | ||
725 | return -ENODEV; | ||
726 | } | ||
727 | |||
728 | ndev = alloc_etherdev(sizeof(struct cpsw_priv)); | 878 | ndev = alloc_etherdev(sizeof(struct cpsw_priv)); |
729 | if (!ndev) { | 879 | if (!ndev) { |
730 | pr_err("error allocating net_device\n"); | 880 | pr_err("error allocating net_device\n"); |
@@ -734,13 +884,19 @@ static int __devinit cpsw_probe(struct platform_device *pdev) | |||
734 | platform_set_drvdata(pdev, ndev); | 884 | platform_set_drvdata(pdev, ndev); |
735 | priv = netdev_priv(ndev); | 885 | priv = netdev_priv(ndev); |
736 | spin_lock_init(&priv->lock); | 886 | spin_lock_init(&priv->lock); |
737 | priv->data = *data; | ||
738 | priv->pdev = pdev; | 887 | priv->pdev = pdev; |
739 | priv->ndev = ndev; | 888 | priv->ndev = ndev; |
740 | priv->dev = &ndev->dev; | 889 | priv->dev = &ndev->dev; |
741 | priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); | 890 | priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); |
742 | priv->rx_packet_max = max(rx_packet_max, 128); | 891 | priv->rx_packet_max = max(rx_packet_max, 128); |
743 | 892 | ||
893 | if (cpsw_probe_dt(&priv->data, pdev)) { | ||
894 | pr_err("cpsw: platform data missing\n"); | ||
895 | ret = -ENODEV; | ||
896 | goto clean_ndev_ret; | ||
897 | } | ||
898 | data = &priv->data; | ||
899 | |||
744 | if (is_valid_ether_addr(data->slave_data[0].mac_addr)) { | 900 | if (is_valid_ether_addr(data->slave_data[0].mac_addr)) { |
745 | memcpy(priv->mac_addr, data->slave_data[0].mac_addr, ETH_ALEN); | 901 | memcpy(priv->mac_addr, data->slave_data[0].mac_addr, ETH_ALEN); |
746 | pr_info("Detected MACID = %pM", priv->mac_addr); | 902 | pr_info("Detected MACID = %pM", priv->mac_addr); |
@@ -996,11 +1152,17 @@ static const struct dev_pm_ops cpsw_pm_ops = { | |||
996 | .resume = cpsw_resume, | 1152 | .resume = cpsw_resume, |
997 | }; | 1153 | }; |
998 | 1154 | ||
1155 | static const struct of_device_id cpsw_of_mtable[] = { | ||
1156 | { .compatible = "ti,cpsw", }, | ||
1157 | { /* sentinel */ }, | ||
1158 | }; | ||
1159 | |||
999 | static struct platform_driver cpsw_driver = { | 1160 | static struct platform_driver cpsw_driver = { |
1000 | .driver = { | 1161 | .driver = { |
1001 | .name = "cpsw", | 1162 | .name = "cpsw", |
1002 | .owner = THIS_MODULE, | 1163 | .owner = THIS_MODULE, |
1003 | .pm = &cpsw_pm_ops, | 1164 | .pm = &cpsw_pm_ops, |
1165 | .of_match_table = of_match_ptr(cpsw_of_mtable), | ||
1004 | }, | 1166 | }, |
1005 | .probe = cpsw_probe, | 1167 | .probe = cpsw_probe, |
1006 | .remove = __devexit_p(cpsw_remove), | 1168 | .remove = __devexit_p(cpsw_remove), |