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