brcm47xx: add support for ipv6 in default network config
[librecmc/librecmc.git] / target / linux / kirkwood / patches-3.10 / 0023-net-mv643xx_eth-add-DT-parsing-support.patch
1 From dd6cae3b60ee88b301f9325db144e70b5e12482e Mon Sep 17 00:00:00 2001
2 From: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
3 Date: Wed, 29 May 2013 21:32:48 +0200
4 Subject: [PATCH 23/29] net: mv643xx_eth: add DT parsing support
5
6 This adds device tree parsing support for the shared driver of mv643xx_eth.
7 As the bindings are slightly different from current PPC bindings new binding
8 documentation is also added. Following PPC-style device setup, the shared
9 driver now also adds port platform_devices and sets up port platform_data.
10
11 Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
12 ---
13  .../devicetree/bindings/net/marvell-orion-net.txt  |  85 ++++++++++++
14  drivers/net/ethernet/marvell/mv643xx_eth.c         | 153 ++++++++++++++++++++-
15  2 files changed, 234 insertions(+), 4 deletions(-)
16  create mode 100644 Documentation/devicetree/bindings/net/marvell-orion-net.txt
17
18 diff --git a/Documentation/devicetree/bindings/net/marvell-orion-net.txt b/Documentation/devicetree/bindings/net/marvell-orion-net.txt
19 new file mode 100644
20 index 0000000..a73b79f
21 --- /dev/null
22 +++ b/Documentation/devicetree/bindings/net/marvell-orion-net.txt
23 @@ -0,0 +1,85 @@
24 +Marvell Orion/Discovery ethernet controller
25 +=============================================
26 +
27 +The Marvell Discovery ethernet controller can be found on Marvell Orion SoCs
28 +(Kirkwood, Dove, Orion5x, and Discovery Innovation) and as part of Marvell
29 +Discovery system controller chips (mv64[345]60).
30 +
31 +The Discovery ethernet controller is described with two levels of nodes. The
32 +first level describes the ethernet controller itself and the second level
33 +describes up to 3 ethernet port nodes within that controller. The reason for
34 +the multiple levels is that the port registers are interleaved within a single
35 +set of controller registers. Each port node describes port-specific properties.
36 +
37 +Note: The above separation is only true for Discovery system controllers.
38 +For Orion SoCs we stick to the separation, although there each controller has
39 +only one port associated. Multiple ports are implemented as multiple single-port
40 +controllers. As Kirkwood has some issues with proper initialization after reset,
41 +an extra compatible string is added for it.
42 +
43 +* Ethernet controller node
44 +
45 +Required controller properties:
46 + - #address-cells: shall be 1.
47 + - #size-cells: shall be 0.
48 + - compatible: shall be one of "marvell,orion-eth", "marvell,kirkwood-eth".
49 + - reg: address and length of the controller registers.
50 +
51 +Optional controller properties:
52 + - clocks: phandle reference to the controller clock.
53 + - marvell,tx-checksum-limit: max tx packet size for hardware checksum.
54 +
55 +* Ethernet port node
56 +
57 +Required port properties:
58 + - device_type: shall be "network".
59 + - compatible: shall be one of "marvell,orion-eth-port",
60 +      "marvell,kirkwood-eth-port".
61 + - reg: port number relative to ethernet controller, shall be 0, 1, or 2.
62 + - interrupts: port interrupt.
63 + - local-mac-address: 6 bytes MAC address.
64 +
65 +Optional port properties:
66 + - marvell,tx-queue-size: size of the transmit ring buffer.
67 + - marvell,tx-sram-addr: address of transmit descriptor buffer located in SRAM.
68 + - marvell,tx-sram-size: size of transmit descriptor buffer located in SRAM.
69 + - marvell,rx-queue-size: size of the receive ring buffer.
70 + - marvell,rx-sram-addr: address of receive descriptor buffer located in SRAM.
71 + - marvell,rx-sram-size: size of receive descriptor buffer located in SRAM.
72 +
73 +and
74 +
75 + - phy-handle: phandle reference to ethernet PHY.
76 +
77 +or
78 +
79 + - speed: port speed if no PHY connected.
80 + - duplex: port mode if no PHY connected.
81 +
82 +* Node example:
83 +
84 +mdio-bus {
85 +       ...
86 +       ethphy: ethernet-phy@8 {
87 +               device_type = "ethernet-phy";
88 +               ...
89 +       };
90 +};
91 +
92 +eth: ethernet-controller@72000 {
93 +       compatible = "marvell,orion-eth";
94 +       #address-cells = <1>;
95 +       #size-cells = <0>;
96 +       reg = <0x72000 0x2000>;
97 +       clocks = <&gate_clk 2>;
98 +       marvell,tx-checksum-limit = <1600>;
99 +
100 +       ethernet@0 {
101 +               device_type = "network";
102 +               compatible = "marvell,orion-eth-port";
103 +               reg = <0>;
104 +               interrupts = <29>;
105 +               phy-handle = <&ethphy>;
106 +               local-mac-address = [00 00 00 00 00 00];
107 +       };
108 +};
109 diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c
110 index af6bdcc..004a250 100644
111 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c
112 +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c
113 @@ -60,6 +60,9 @@
114  #include <linux/types.h>
115  #include <linux/slab.h>
116  #include <linux/clk.h>
117 +#include <linux/of.h>
118 +#include <linux/of_irq.h>
119 +#include <linux/of_net.h>
120  #include <linux/of_mdio.h>
121  
122  static char mv643xx_eth_driver_name[] = "mv643xx_eth";
123 @@ -2453,13 +2456,148 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp)
124         }
125  }
126  
127 +#if defined(CONFIG_OF)
128 +static const struct of_device_id mv643xx_eth_shared_ids[] = {
129 +       { .compatible = "marvell,orion-eth", },
130 +       { .compatible = "marvell,kirkwood-eth", },
131 +       { }
132 +};
133 +MODULE_DEVICE_TABLE(of, mv643xx_eth_shared_ids);
134 +#endif
135 +
136 +#if defined(CONFIG_OF) && !defined(CONFIG_MV64X60)
137 +#define mv643xx_eth_property(_np, _name, _v)                           \
138 +       do {                                                            \
139 +               u32 tmp;                                                \
140 +               if (!of_property_read_u32(_np, "marvell," _name, &tmp)) \
141 +                       _v = tmp;                                       \
142 +       } while (0)
143 +
144 +static struct platform_device *port_platdev[3];
145 +
146 +static int mv643xx_eth_shared_of_add_port(struct platform_device *pdev,
147 +                                         struct device_node *pnp)
148 +{
149 +       struct platform_device *ppdev;
150 +       struct mv643xx_eth_platform_data ppd;
151 +       struct resource res;
152 +       const char *mac_addr;
153 +       int ret;
154 +
155 +       memset(&ppd, 0, sizeof(ppd));
156 +       ppd.shared = pdev;
157 +
158 +       memset(&res, 0, sizeof(res));
159 +       if (!of_irq_to_resource(pnp, 0, &res)) {
160 +               dev_err(&pdev->dev, "missing interrupt on %s\n", pnp->name);
161 +               return -EINVAL;
162 +       }
163 +
164 +       if (of_property_read_u32(pnp, "reg", &ppd.port_number)) {
165 +               dev_err(&pdev->dev, "missing reg property on %s\n", pnp->name);
166 +               return -EINVAL;
167 +       }
168 +
169 +       if (ppd.port_number >= 3) {
170 +               dev_err(&pdev->dev, "invalid reg property on %s\n", pnp->name);
171 +               return -EINVAL;
172 +       }
173 +
174 +       mac_addr = of_get_mac_address(pnp);
175 +       if (mac_addr)
176 +               memcpy(ppd.mac_addr, mac_addr, 6);
177 +
178 +       mv643xx_eth_property(pnp, "tx-queue-size", ppd.tx_queue_size);
179 +       mv643xx_eth_property(pnp, "tx-sram-addr", ppd.tx_sram_addr);
180 +       mv643xx_eth_property(pnp, "tx-sram-size", ppd.tx_sram_size);
181 +       mv643xx_eth_property(pnp, "rx-queue-size", ppd.rx_queue_size);
182 +       mv643xx_eth_property(pnp, "rx-sram-addr", ppd.rx_sram_addr);
183 +       mv643xx_eth_property(pnp, "rx-sram-size", ppd.rx_sram_size);
184 +
185 +       ppd.phy_node = of_parse_phandle(pnp, "phy-handle", 0);
186 +       if (!ppd.phy_node) {
187 +               ppd.phy_addr = MV643XX_ETH_PHY_NONE;
188 +               of_property_read_u32(pnp, "speed", &ppd.speed);
189 +               of_property_read_u32(pnp, "duplex", &ppd.duplex);
190 +       }
191 +
192 +       ppdev = platform_device_alloc(MV643XX_ETH_NAME, ppd.port_number);
193 +       if (!ppdev)
194 +               return -ENOMEM;
195 +       ppdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
196 +
197 +       ret = platform_device_add_resources(ppdev, &res, 1);
198 +       if (ret)
199 +               goto port_err;
200 +
201 +       ret = platform_device_add_data(ppdev, &ppd, sizeof(ppd));
202 +       if (ret)
203 +               goto port_err;
204 +
205 +       ret = platform_device_add(ppdev);
206 +       if (ret)
207 +               goto port_err;
208 +
209 +       port_platdev[ppd.port_number] = ppdev;
210 +
211 +       return 0;
212 +
213 +port_err:
214 +       platform_device_put(ppdev);
215 +       return ret;
216 +}
217 +
218 +static int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
219 +{
220 +       struct mv643xx_eth_shared_platform_data *pd;
221 +       struct device_node *pnp, *np = pdev->dev.of_node;
222 +       int ret;
223 +
224 +       /* bail out if not registered from DT */
225 +       if (!np)
226 +               return 0;
227 +
228 +       pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
229 +       if (!pd)
230 +               return -ENOMEM;
231 +       pdev->dev.platform_data = pd;
232 +
233 +       mv643xx_eth_property(np, "tx-checksum-limit", pd->tx_csum_limit);
234 +
235 +       for_each_available_child_of_node(np, pnp) {
236 +               ret = mv643xx_eth_shared_of_add_port(pdev, pnp);
237 +               if (ret)
238 +                       return ret;
239 +       }
240 +       return 0;
241 +}
242 +
243 +static void mv643xx_eth_shared_of_remove(void)
244 +{
245 +       int n;
246 +
247 +       for (n = 0; n < 3; n++) {
248 +               platform_device_del(port_platdev[n]);
249 +               port_platdev[n] = NULL;
250 +       }
251 +}
252 +#else
253 +static int mv643xx_eth_shared_of_probe(struct platform_device *pdev)
254 +{
255 +       return 0
256 +}
257 +
258 +#define mv643xx_eth_shared_of_remove()
259 +#endif
260 +
261  static int mv643xx_eth_shared_probe(struct platform_device *pdev)
262  {
263         static int mv643xx_eth_version_printed;
264 -       struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data;
265 +       struct mv643xx_eth_shared_platform_data *pd;
266         struct mv643xx_eth_shared_private *msp;
267         const struct mbus_dram_target_info *dram;
268         struct resource *res;
269 +       int ret;
270  
271         if (!mv643xx_eth_version_printed++)
272                 pr_notice("MV-643xx 10/100/1000 ethernet driver version %s\n",
273 @@ -2472,6 +2610,7 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
274         msp = devm_kzalloc(&pdev->dev, sizeof(*msp), GFP_KERNEL);
275         if (msp == NULL)
276                 return -ENOMEM;
277 +       platform_set_drvdata(pdev, msp);
278  
279         msp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
280         if (msp->base == NULL)
281 @@ -2488,12 +2627,15 @@ static int mv643xx_eth_shared_probe(struct platform_device *pdev)
282         if (dram)
283                 mv643xx_eth_conf_mbus_windows(msp, dram);
284  
285 +       ret = mv643xx_eth_shared_of_probe(pdev);
286 +       if (ret)
287 +               return ret;
288 +       pd = pdev->dev.platform_data;
289 +
290         msp->tx_csum_limit = (pd != NULL && pd->tx_csum_limit) ?
291                                         pd->tx_csum_limit : 9 * 1024;
292         infer_hw_params(msp);
293  
294 -       platform_set_drvdata(pdev, msp);
295 -
296         return 0;
297  }
298  
299 @@ -2501,9 +2643,9 @@ static int mv643xx_eth_shared_remove(struct platform_device *pdev)
300  {
301         struct mv643xx_eth_shared_private *msp = platform_get_drvdata(pdev);
302  
303 +       mv643xx_eth_shared_of_remove();
304         if (!IS_ERR(msp->clk))
305                 clk_disable_unprepare(msp->clk);
306 -
307         return 0;
308  }
309  
310 @@ -2513,6 +2655,7 @@ static struct platform_driver mv643xx_eth_shared_driver = {
311         .driver = {
312                 .name   = MV643XX_ETH_SHARED_NAME,
313                 .owner  = THIS_MODULE,
314 +               .of_match_table = of_match_ptr(mv643xx_eth_shared_ids),
315         },
316  };
317  
318 @@ -2721,6 +2864,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
319         if (!IS_ERR(mp->clk)) {
320                 clk_prepare_enable(mp->clk);
321                 mp->t_clk = clk_get_rate(mp->clk);
322 +       } else if (!IS_ERR(mp->shared->clk)) {
323 +               mp->t_clk = clk_get_rate(mp->shared->clk);
324         }
325  
326         set_params(mp, pd);
327 -- 
328 1.8.4.rc1
329