fecc958dc8bec8db973e57b4abc490e03b5cb6ea
[15.05/openwrt.git] / target / linux / ipq806x / patches-4.0 / 704-stmmac-add-ipq806x-glue-layer.patch
1 From 69fb970ad3fe05af7cb99ea78230c69c7ca0d03b Mon Sep 17 00:00:00 2001
2 From: Mathieu Olivari <mathieu@codeaurora.org>
3 Date: Fri, 8 May 2015 16:10:22 -0700
4 Subject: [PATCH 4/8] stmmac: add ipq806x glue layer
5
6 The ethernet controller available in IPQ806x is a Synopsys DesignWare
7 Gigabit MAC IP core, already supported by the stmmac driver.
8
9 This glue layer implements some platform specific settings required to
10 get the controller working on an IPQ806x based platform.
11
12 Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
13 ---
14  drivers/net/ethernet/stmicro/stmmac/Kconfig        |   1 +
15  drivers/net/ethernet/stmicro/stmmac/Makefile       |   2 +-
16  drivers/net/ethernet/stmicro/stmmac/dwmac-ipq.c    | 324 +++++++++++++++++++++
17  .../net/ethernet/stmicro/stmmac/stmmac_platform.c  |   1 +
18  .../net/ethernet/stmicro/stmmac/stmmac_platform.h  |   1 +
19  5 files changed, 328 insertions(+), 1 deletion(-)
20  create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-ipq.c
21
22 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
23 +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
24 @@ -16,6 +16,7 @@ if STMMAC_ETH
25  config STMMAC_PLATFORM
26         tristate "STMMAC Platform bus support"
27         depends on STMMAC_ETH
28 +       select MFD_SYSCON
29         default y
30         ---help---
31           This selects the platform specific bus support for the stmmac driver.
32 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile
33 +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
34 @@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethto
35  
36  obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
37  stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o   \
38 -                      dwmac-sti.o dwmac-socfpga.o dwmac-rk.o
39 +                      dwmac-sti.o dwmac-socfpga.o dwmac-rk.o dwmac-ipq806x.o
40  
41  obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
42  stmmac-pci-objs:= stmmac_pci.o
43 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
44 +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
45 @@ -42,6 +42,7 @@ static const struct of_device_id stmmac_
46         { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data},
47         { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
48         { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
49 +       { .compatible = "qcom,ipq806x-gmac", .data = &ipq806x_gmac_data },
50         { .compatible = "st,spear600-gmac"},
51         { .compatible = "snps,dwmac-3.610"},
52         { .compatible = "snps,dwmac-3.70a"},
53 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
54 +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
55 @@ -25,5 +25,6 @@ extern const struct stmmac_of_data stih4
56  extern const struct stmmac_of_data stid127_dwmac_data;
57  extern const struct stmmac_of_data socfpga_gmac_data;
58  extern const struct stmmac_of_data rk3288_gmac_data;
59 +extern const struct stmmac_of_data ipq806x_gmac_data;
60  
61  #endif /* __STMMAC_PLATFORM_H__ */
62 --- /dev/null
63 +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
64 @@ -0,0 +1,343 @@
65 +/*
66 + * Qualcomm Atheros IPQ806x GMAC glue layer
67 + *
68 + * Copyright (C) 2015 The Linux Foundation
69 + *
70 + * Permission to use, copy, modify, and/or distribute this software for any
71 + * purpose with or without fee is hereby granted, provided that the above
72 + * copyright notice and this permission notice appear in all copies.
73 + *
74 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
75 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
76 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
77 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
78 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
79 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
80 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
81 + */
82 +
83 +#include <linux/device.h>
84 +#include <linux/platform_device.h>
85 +#include <linux/phy.h>
86 +#include <linux/regmap.h>
87 +#include <linux/clk.h>
88 +#include <linux/reset.h>
89 +#include <linux/of_net.h>
90 +#include <linux/mfd/syscon.h>
91 +#include <linux/stmmac.h>
92 +#include <linux/of_mdio.h>
93 +
94 +#include "stmmac_platform.h"
95 +
96 +#define NSS_COMMON_CLK_GATE                    0x8
97 +#define NSS_COMMON_CLK_GATE_PTP_EN(x)          BIT(0x10 + x)
98 +#define NSS_COMMON_CLK_GATE_RGMII_RX_EN(x)     BIT(0x9 + (x * 2))
99 +#define NSS_COMMON_CLK_GATE_RGMII_TX_EN(x)     BIT(0x8 + (x * 2))
100 +#define NSS_COMMON_CLK_GATE_GMII_RX_EN(x)      BIT(0x4 + x)
101 +#define NSS_COMMON_CLK_GATE_GMII_TX_EN(x)      BIT(0x0 + x)
102 +
103 +#define NSS_COMMON_CLK_DIV0                    0xC
104 +#define NSS_COMMON_CLK_DIV_OFFSET(x)           (x * 8)
105 +#define NSS_COMMON_CLK_DIV_MASK                        0x7f
106 +
107 +#define NSS_COMMON_CLK_SRC_CTRL                        0x14
108 +#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x)      (1 << x)
109 +/* Mode is coded on 1 bit but is different depending on the MAC ID:
110 + * MAC0: QSGMII=0 RGMII=1
111 + * MAC1: QSGMII=0 SGMII=0 RGMII=1
112 + * MAC2 & MAC3: QSGMII=0 SGMII=1
113 + */
114 +#define NSS_COMMON_CLK_SRC_CTRL_RGMII(x)       1
115 +#define NSS_COMMON_CLK_SRC_CTRL_SGMII(x)       ((x >= 2) ? 1 : 0)
116 +
117 +#define NSS_COMMON_MACSEC_CTL                  0x28
118 +#define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x) (1 << x)
119 +
120 +#define NSS_COMMON_GMAC_CTL(x)                 (0x30 + (x * 4))
121 +#define NSS_COMMON_GMAC_CTL_CSYS_REQ           BIT(19)
122 +#define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL      BIT(16)
123 +#define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET   8
124 +#define NSS_COMMON_GMAC_CTL_IFG_OFFSET         0
125 +#define NSS_COMMON_GMAC_CTL_IFG_MASK           0x3f
126 +
127 +#define NSS_COMMON_CLK_DIV_RGMII_1000          1
128 +#define NSS_COMMON_CLK_DIV_RGMII_100           9
129 +#define NSS_COMMON_CLK_DIV_RGMII_10            99
130 +#define NSS_COMMON_CLK_DIV_SGMII_1000          0
131 +#define NSS_COMMON_CLK_DIV_SGMII_100           4
132 +#define NSS_COMMON_CLK_DIV_SGMII_10            49
133 +
134 +#define QSGMII_PCS_MODE_CTL                    0x68
135 +#define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x)      BIT((x * 8) + 7)
136 +
137 +#define QSGMII_PCS_CAL_LCKDT_CTL               0x120
138 +#define QSGMII_PCS_CAL_LCKDT_CTL_RST           BIT(19)
139 +
140 +/* Only GMAC1/2/3 support SGMII and their CTL register are not contiguous */
141 +#define QSGMII_PHY_SGMII_CTL(x)                        ((x == 1) ? 0x134 : \
142 +                                                (0x13c + (4 * (x - 2))))
143 +#define QSGMII_PHY_CDR_EN                      BIT(0)
144 +#define QSGMII_PHY_RX_FRONT_EN                 BIT(1)
145 +#define QSGMII_PHY_RX_SIGNAL_DETECT_EN         BIT(2)
146 +#define QSGMII_PHY_TX_DRIVER_EN                        BIT(3)
147 +#define QSGMII_PHY_QSGMII_EN                   BIT(7)
148 +#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET      12
149 +#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK                0x7
150 +#define QSGMII_PHY_RX_DC_BIAS_OFFSET           18
151 +#define QSGMII_PHY_RX_DC_BIAS_MASK             0x3
152 +#define QSGMII_PHY_RX_INPUT_EQU_OFFSET         20
153 +#define QSGMII_PHY_RX_INPUT_EQU_MASK           0x3
154 +#define QSGMII_PHY_CDR_PI_SLEW_OFFSET          22
155 +#define QSGMII_PHY_CDR_PI_SLEW_MASK            0x3
156 +#define QSGMII_PHY_TX_DRV_AMP_OFFSET           28
157 +#define QSGMII_PHY_TX_DRV_AMP_MASK             0xf
158 +
159 +struct ipq806x_gmac {
160 +       struct platform_device *pdev;
161 +       struct regmap *nss_common;
162 +       struct regmap *qsgmii_csr;
163 +       uint32_t id;
164 +       struct clk *core_clk;
165 +       phy_interface_t phy_mode;
166 +};
167 +
168 +static int get_clk_div_sgmii(struct ipq806x_gmac *gmac, unsigned int speed)
169 +{
170 +       struct device *dev = &gmac->pdev->dev;
171 +       int div;
172 +
173 +       switch (speed) {
174 +       case SPEED_1000:
175 +               div = NSS_COMMON_CLK_DIV_SGMII_1000;
176 +               break;
177 +
178 +       case SPEED_100:
179 +               div = NSS_COMMON_CLK_DIV_SGMII_100;
180 +               break;
181 +
182 +       case SPEED_10:
183 +               div = NSS_COMMON_CLK_DIV_SGMII_10;
184 +               break;
185 +
186 +       default:
187 +               dev_err(dev, "Speed %dMbps not supported in SGMII\n", speed);
188 +               return -EINVAL;
189 +       }
190 +
191 +       return div;
192 +}
193 +
194 +static int get_clk_div_rgmii(struct ipq806x_gmac *gmac, unsigned int speed)
195 +{
196 +       struct device *dev = &gmac->pdev->dev;
197 +       int div;
198 +
199 +       switch (speed) {
200 +       case SPEED_1000:
201 +               div = NSS_COMMON_CLK_DIV_RGMII_1000;
202 +               break;
203 +
204 +       case SPEED_100:
205 +               div = NSS_COMMON_CLK_DIV_RGMII_100;
206 +               break;
207 +
208 +       case SPEED_10:
209 +               div = NSS_COMMON_CLK_DIV_RGMII_10;
210 +               break;
211 +
212 +       default:
213 +               dev_err(dev, "Speed %dMbps not supported in RGMII\n", speed);
214 +               return -EINVAL;
215 +       }
216 +
217 +       return div;
218 +}
219 +
220 +static int ipq806x_gmac_set_speed(struct ipq806x_gmac *gmac, unsigned int speed)
221 +{
222 +       uint32_t clk_bits, val;
223 +       int div;
224 +
225 +       switch (gmac->phy_mode) {
226 +       case PHY_INTERFACE_MODE_RGMII:
227 +               div = get_clk_div_rgmii(gmac, speed);
228 +               clk_bits = NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
229 +                          NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
230 +               break;
231 +
232 +       case PHY_INTERFACE_MODE_SGMII:
233 +               div = get_clk_div_sgmii(gmac, speed);
234 +               clk_bits = NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) |
235 +                          NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id);
236 +               break;
237 +
238 +       default:
239 +               dev_err(&gmac->pdev->dev, "Unsupported PHY mode: \"%s\"\n",
240 +                       phy_modes(gmac->phy_mode));
241 +               return -EINVAL;
242 +       }
243 +
244 +       /* Disable the clocks */
245 +       regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
246 +       val &= ~clk_bits;
247 +       regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
248 +
249 +       /* Set the divider */
250 +       regmap_read(gmac->nss_common, NSS_COMMON_CLK_DIV0, &val);
251 +       val &= ~(NSS_COMMON_CLK_DIV_MASK
252 +                << NSS_COMMON_CLK_DIV_OFFSET(gmac->id));
253 +       val |= div << NSS_COMMON_CLK_DIV_OFFSET(gmac->id);
254 +       regmap_write(gmac->nss_common, NSS_COMMON_CLK_DIV0, val);
255 +
256 +       /* Enable the clock back */
257 +       regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
258 +       val |= clk_bits;
259 +       regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
260 +
261 +       return 0;
262 +}
263 +
264 +static void *ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
265 +{
266 +       struct device *dev = &gmac->pdev->dev;
267 +
268 +       gmac->phy_mode = of_get_phy_mode(dev->of_node);
269 +       if (gmac->phy_mode < 0) {
270 +               dev_err(dev, "missing phy mode property\n");
271 +               return ERR_PTR(-EINVAL);
272 +       }
273 +
274 +       if (of_property_read_u32(dev->of_node, "qcom,id", &gmac->id) < 0) {
275 +               dev_err(dev, "missing qcom id property\n");
276 +               return ERR_PTR(-EINVAL);
277 +       }
278 +
279 +       /* The GMACs are called 1 to 4 in the documentation, but to simplify the
280 +        * code and keep it consistent with the Linux convention, we'll number
281 +        * them from 0 to 3 here.
282 +        */
283 +       if (gmac->id < 0 || gmac->id > 3) {
284 +               dev_err(dev, "invalid gmac id\n");
285 +               return ERR_PTR(-EINVAL);
286 +       }
287 +
288 +       gmac->core_clk = devm_clk_get(dev, "stmmaceth");
289 +       if (IS_ERR(gmac->core_clk)) {
290 +               dev_err(dev, "missing stmmaceth clk property\n");
291 +               return gmac->core_clk;
292 +       }
293 +       clk_set_rate(gmac->core_clk, 266000000);
294 +
295 +       /* Setup the register map for the nss common registers */
296 +       gmac->nss_common = syscon_regmap_lookup_by_phandle(dev->of_node,
297 +                                                          "qcom,nss-common");
298 +       if (IS_ERR(gmac->nss_common)) {
299 +               dev_err(dev, "missing nss-common node\n");
300 +               return gmac->nss_common;
301 +       }
302 +
303 +       /* Setup the register map for the qsgmii csr registers */
304 +       gmac->qsgmii_csr = syscon_regmap_lookup_by_phandle(dev->of_node,
305 +                                                          "qcom,qsgmii-csr");
306 +       if (IS_ERR(gmac->qsgmii_csr)) {
307 +               dev_err(dev, "missing qsgmii-csr node\n");
308 +               return gmac->qsgmii_csr;
309 +       }
310 +
311 +       return NULL;
312 +}
313 +
314 +static void *ipq806x_gmac_setup(struct platform_device *pdev)
315 +{
316 +       struct device *dev = &pdev->dev;
317 +       struct ipq806x_gmac *gmac;
318 +       int val;
319 +       void *err;
320 +
321 +       gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
322 +       if (!gmac)
323 +               return ERR_PTR(-ENOMEM);
324 +
325 +       gmac->pdev = pdev;
326 +
327 +       err = ipq806x_gmac_of_parse(gmac);
328 +       if (err) {
329 +               dev_err(dev, "device tree parsing error\n");
330 +               return err;
331 +       }
332 +
333 +       regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL,
334 +                    QSGMII_PCS_CAL_LCKDT_CTL_RST);
335 +
336 +       /* Inter frame gap is set to 12 */
337 +       val = 12 << NSS_COMMON_GMAC_CTL_IFG_OFFSET |
338 +             12 << NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET;
339 +       /* We also initiate an AXI low power exit request */
340 +       val |= NSS_COMMON_GMAC_CTL_CSYS_REQ;
341 +       switch (gmac->phy_mode) {
342 +       case PHY_INTERFACE_MODE_RGMII:
343 +               val |= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
344 +               break;
345 +       case PHY_INTERFACE_MODE_SGMII:
346 +               val &= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
347 +               break;
348 +       default:
349 +               dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
350 +                       phy_modes(gmac->phy_mode));
351 +               return NULL;
352 +       }
353 +       regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val);
354 +
355 +       /* Configure the clock src according to the mode */
356 +       regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val);
357 +       val &= ~NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
358 +       switch (gmac->phy_mode) {
359 +       case PHY_INTERFACE_MODE_RGMII:
360 +               val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
361 +                       NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
362 +               break;
363 +       case PHY_INTERFACE_MODE_SGMII:
364 +               val |= NSS_COMMON_CLK_SRC_CTRL_SGMII(gmac->id) <<
365 +                       NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
366 +               break;
367 +       default:
368 +               dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
369 +                       phy_modes(gmac->phy_mode));
370 +               return NULL;
371 +       }
372 +       regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val);
373 +
374 +       /* Enable PTP clock */
375 +       regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
376 +       val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id);
377 +       regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
378 +
379 +       if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
380 +               regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
381 +                            QSGMII_PHY_CDR_EN |
382 +                            QSGMII_PHY_RX_FRONT_EN |
383 +                            QSGMII_PHY_RX_SIGNAL_DETECT_EN |
384 +                            QSGMII_PHY_TX_DRIVER_EN |
385 +                            QSGMII_PHY_QSGMII_EN |
386 +                            0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
387 +                            0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET |
388 +                            0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
389 +                            0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
390 +                            0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET);
391 +       }
392 +
393 +       return gmac;
394 +}
395 +
396 +static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
397 +{
398 +       struct ipq806x_gmac *gmac = priv;
399 +
400 +       ipq806x_gmac_set_speed(gmac, speed);
401 +}
402 +
403 +const struct stmmac_of_data ipq806x_gmac_data = {
404 +       .has_gmac       = 1,
405 +       .setup          = ipq806x_gmac_setup,
406 +       .fix_mac_speed  = ipq806x_gmac_fix_mac_speed,
407 +};