ar71xx: remove linux 3.18 support
[openwrt/staging/chunkeey.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 +};