2 * Qualcomm Atheros IPQ806x GMAC glue layer
4 * Copyright (C) 2015 The Linux Foundation
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <linux/device.h>
20 #include <linux/platform_device.h>
21 #include <linux/phy.h>
22 #include <linux/regmap.h>
23 #include <linux/clk.h>
24 #include <linux/reset.h>
25 #include <linux/of_net.h>
26 #include <linux/mfd/syscon.h>
27 #include <linux/stmmac.h>
28 #include <linux/of_mdio.h>
29 #include <linux/module.h>
31 #include "stmmac_platform.h"
33 #define NSS_COMMON_CLK_GATE 0x8
34 #define NSS_COMMON_CLK_GATE_PTP_EN(x) BIT(0x10 + x)
35 #define NSS_COMMON_CLK_GATE_RGMII_RX_EN(x) BIT(0x9 + (x * 2))
36 #define NSS_COMMON_CLK_GATE_RGMII_TX_EN(x) BIT(0x8 + (x * 2))
37 #define NSS_COMMON_CLK_GATE_GMII_RX_EN(x) BIT(0x4 + x)
38 #define NSS_COMMON_CLK_GATE_GMII_TX_EN(x) BIT(0x0 + x)
40 #define NSS_COMMON_CLK_DIV0 0xC
41 #define NSS_COMMON_CLK_DIV_OFFSET(x) (x * 8)
42 #define NSS_COMMON_CLK_DIV_MASK 0x7f
44 #define NSS_COMMON_CLK_SRC_CTRL 0x14
45 #define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (1 << x)
46 /* Mode is coded on 1 bit but is different depending on the MAC ID:
47 * MAC0: QSGMII=0 RGMII=1
48 * MAC1: QSGMII=0 SGMII=0 RGMII=1
49 * MAC2 & MAC3: QSGMII=0 SGMII=1
51 #define NSS_COMMON_CLK_SRC_CTRL_RGMII(x) 1
52 #define NSS_COMMON_CLK_SRC_CTRL_SGMII(x) ((x >= 2) ? 1 : 0)
54 #define NSS_COMMON_MACSEC_CTL 0x28
55 #define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x) (1 << x)
57 #define NSS_COMMON_GMAC_CTL(x) (0x30 + (x * 4))
58 #define NSS_COMMON_GMAC_CTL_CSYS_REQ BIT(19)
59 #define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL BIT(16)
60 #define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET 8
61 #define NSS_COMMON_GMAC_CTL_IFG_OFFSET 0
62 #define NSS_COMMON_GMAC_CTL_IFG_MASK 0x3f
64 #define NSS_COMMON_CLK_DIV_RGMII_1000 1
65 #define NSS_COMMON_CLK_DIV_RGMII_100 9
66 #define NSS_COMMON_CLK_DIV_RGMII_10 99
67 #define NSS_COMMON_CLK_DIV_SGMII_1000 0
68 #define NSS_COMMON_CLK_DIV_SGMII_100 4
69 #define NSS_COMMON_CLK_DIV_SGMII_10 49
71 #define QSGMII_PCS_MODE_CTL 0x68
72 #define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x) BIT((x * 8) + 7)
74 #define QSGMII_PCS_CAL_LCKDT_CTL 0x120
75 #define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19)
77 /* Only GMAC1/2/3 support SGMII and their CTL register are not contiguous */
78 #define QSGMII_PHY_SGMII_CTL(x) ((x == 1) ? 0x134 : \
79 (0x13c + (4 * (x - 2))))
80 #define QSGMII_PHY_CDR_EN BIT(0)
81 #define QSGMII_PHY_RX_FRONT_EN BIT(1)
82 #define QSGMII_PHY_RX_SIGNAL_DETECT_EN BIT(2)
83 #define QSGMII_PHY_TX_DRIVER_EN BIT(3)
84 #define QSGMII_PHY_QSGMII_EN BIT(7)
85 #define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12
86 #define QSGMII_PHY_PHASE_LOOP_GAIN_MASK 0x7
87 #define QSGMII_PHY_RX_DC_BIAS_OFFSET 18
88 #define QSGMII_PHY_RX_DC_BIAS_MASK 0x3
89 #define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20
90 #define QSGMII_PHY_RX_INPUT_EQU_MASK 0x3
91 #define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22
92 #define QSGMII_PHY_CDR_PI_SLEW_MASK 0x3
93 #define QSGMII_PHY_TX_DRV_AMP_OFFSET 28
94 #define QSGMII_PHY_TX_DRV_AMP_MASK 0xf
97 struct platform_device
*pdev
;
98 struct regmap
*nss_common
;
99 struct regmap
*qsgmii_csr
;
101 struct clk
*core_clk
;
102 phy_interface_t phy_mode
;
105 static int get_clk_div_sgmii(struct ipq806x_gmac
*gmac
, unsigned int speed
)
107 struct device
*dev
= &gmac
->pdev
->dev
;
112 div
= NSS_COMMON_CLK_DIV_SGMII_1000
;
116 div
= NSS_COMMON_CLK_DIV_SGMII_100
;
120 div
= NSS_COMMON_CLK_DIV_SGMII_10
;
124 dev_err(dev
, "Speed %dMbps not supported in SGMII\n", speed
);
131 static int get_clk_div_rgmii(struct ipq806x_gmac
*gmac
, unsigned int speed
)
133 struct device
*dev
= &gmac
->pdev
->dev
;
138 div
= NSS_COMMON_CLK_DIV_RGMII_1000
;
142 div
= NSS_COMMON_CLK_DIV_RGMII_100
;
146 div
= NSS_COMMON_CLK_DIV_RGMII_10
;
150 dev_err(dev
, "Speed %dMbps not supported in RGMII\n", speed
);
157 static int ipq806x_gmac_set_speed(struct ipq806x_gmac
*gmac
, unsigned int speed
)
159 uint32_t clk_bits
, val
;
162 switch (gmac
->phy_mode
) {
163 case PHY_INTERFACE_MODE_RGMII
:
164 div
= get_clk_div_rgmii(gmac
, speed
);
165 clk_bits
= NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac
->id
) |
166 NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac
->id
);
169 case PHY_INTERFACE_MODE_SGMII
:
170 div
= get_clk_div_sgmii(gmac
, speed
);
171 clk_bits
= NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac
->id
) |
172 NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac
->id
);
176 dev_err(&gmac
->pdev
->dev
, "Unsupported PHY mode: \"%s\"\n",
177 phy_modes(gmac
->phy_mode
));
181 /* Disable the clocks */
182 regmap_read(gmac
->nss_common
, NSS_COMMON_CLK_GATE
, &val
);
184 regmap_write(gmac
->nss_common
, NSS_COMMON_CLK_GATE
, val
);
186 /* Set the divider */
187 regmap_read(gmac
->nss_common
, NSS_COMMON_CLK_DIV0
, &val
);
188 val
&= ~(NSS_COMMON_CLK_DIV_MASK
189 << NSS_COMMON_CLK_DIV_OFFSET(gmac
->id
));
190 val
|= div
<< NSS_COMMON_CLK_DIV_OFFSET(gmac
->id
);
191 regmap_write(gmac
->nss_common
, NSS_COMMON_CLK_DIV0
, val
);
193 /* Enable the clock back */
194 regmap_read(gmac
->nss_common
, NSS_COMMON_CLK_GATE
, &val
);
196 regmap_write(gmac
->nss_common
, NSS_COMMON_CLK_GATE
, val
);
201 static void *ipq806x_gmac_of_parse(struct ipq806x_gmac
*gmac
)
203 struct device
*dev
= &gmac
->pdev
->dev
;
205 gmac
->phy_mode
= of_get_phy_mode(dev
->of_node
);
206 if (gmac
->phy_mode
< 0) {
207 dev_err(dev
, "missing phy mode property\n");
208 return ERR_PTR(-EINVAL
);
211 if (of_property_read_u32(dev
->of_node
, "qcom,id", &gmac
->id
) < 0) {
212 dev_err(dev
, "missing qcom id property\n");
213 return ERR_PTR(-EINVAL
);
216 /* The GMACs are called 1 to 4 in the documentation, but to simplify the
217 * code and keep it consistent with the Linux convention, we'll number
218 * them from 0 to 3 here.
220 if (gmac
->id
< 0 || gmac
->id
> 3) {
221 dev_err(dev
, "invalid gmac id\n");
222 return ERR_PTR(-EINVAL
);
225 gmac
->core_clk
= devm_clk_get(dev
, "stmmaceth");
226 if (IS_ERR(gmac
->core_clk
)) {
227 dev_err(dev
, "missing stmmaceth clk property\n");
228 return gmac
->core_clk
;
230 clk_set_rate(gmac
->core_clk
, 266000000);
232 /* Setup the register map for the nss common registers */
233 gmac
->nss_common
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
235 if (IS_ERR(gmac
->nss_common
)) {
236 dev_err(dev
, "missing nss-common node\n");
237 return gmac
->nss_common
;
240 /* Setup the register map for the qsgmii csr registers */
241 gmac
->qsgmii_csr
= syscon_regmap_lookup_by_phandle(dev
->of_node
,
243 if (IS_ERR(gmac
->qsgmii_csr
)) {
244 dev_err(dev
, "missing qsgmii-csr node\n");
245 return gmac
->qsgmii_csr
;
251 static void *ipq806x_gmac_setup(struct platform_device
*pdev
)
253 struct device
*dev
= &pdev
->dev
;
254 struct ipq806x_gmac
*gmac
;
258 gmac
= devm_kzalloc(dev
, sizeof(*gmac
), GFP_KERNEL
);
260 return ERR_PTR(-ENOMEM
);
264 err
= ipq806x_gmac_of_parse(gmac
);
266 dev_err(dev
, "device tree parsing error\n");
270 regmap_write(gmac
->qsgmii_csr
, QSGMII_PCS_CAL_LCKDT_CTL
,
271 QSGMII_PCS_CAL_LCKDT_CTL_RST
);
273 /* Inter frame gap is set to 12 */
274 val
= 12 << NSS_COMMON_GMAC_CTL_IFG_OFFSET
|
275 12 << NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET
;
276 /* We also initiate an AXI low power exit request */
277 val
|= NSS_COMMON_GMAC_CTL_CSYS_REQ
;
278 switch (gmac
->phy_mode
) {
279 case PHY_INTERFACE_MODE_RGMII
:
280 val
|= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL
;
282 case PHY_INTERFACE_MODE_SGMII
:
283 val
&= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL
;
286 dev_err(&pdev
->dev
, "Unsupported PHY mode: \"%s\"\n",
287 phy_modes(gmac
->phy_mode
));
290 regmap_write(gmac
->nss_common
, NSS_COMMON_GMAC_CTL(gmac
->id
), val
);
292 /* Configure the clock src according to the mode */
293 regmap_read(gmac
->nss_common
, NSS_COMMON_CLK_SRC_CTRL
, &val
);
294 val
&= ~NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac
->id
);
295 switch (gmac
->phy_mode
) {
296 case PHY_INTERFACE_MODE_RGMII
:
297 val
|= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac
->id
) <<
298 NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac
->id
);
300 case PHY_INTERFACE_MODE_SGMII
:
301 val
|= NSS_COMMON_CLK_SRC_CTRL_SGMII(gmac
->id
) <<
302 NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac
->id
);
305 dev_err(&pdev
->dev
, "Unsupported PHY mode: \"%s\"\n",
306 phy_modes(gmac
->phy_mode
));
309 regmap_write(gmac
->nss_common
, NSS_COMMON_CLK_SRC_CTRL
, val
);
311 /* Enable PTP clock */
312 regmap_read(gmac
->nss_common
, NSS_COMMON_CLK_GATE
, &val
);
313 val
|= NSS_COMMON_CLK_GATE_PTP_EN(gmac
->id
);
314 regmap_write(gmac
->nss_common
, NSS_COMMON_CLK_GATE
, val
);
316 if (gmac
->phy_mode
== PHY_INTERFACE_MODE_SGMII
) {
317 regmap_write(gmac
->qsgmii_csr
, QSGMII_PHY_SGMII_CTL(gmac
->id
),
319 QSGMII_PHY_RX_FRONT_EN
|
320 QSGMII_PHY_RX_SIGNAL_DETECT_EN
|
321 QSGMII_PHY_TX_DRIVER_EN
|
322 QSGMII_PHY_QSGMII_EN
|
323 0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET
|
324 0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET
|
325 0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET
|
326 0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET
|
327 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET
);
333 static void ipq806x_gmac_fix_mac_speed(void *priv
, unsigned int speed
)
335 struct ipq806x_gmac
*gmac
= priv
;
337 ipq806x_gmac_set_speed(gmac
, speed
);
340 static const struct stmmac_of_data ipq806x_gmac_data
= {
342 .setup
= ipq806x_gmac_setup
,
343 .fix_mac_speed
= ipq806x_gmac_fix_mac_speed
,
346 static const struct of_device_id ipq806x_gmac_dwmac_match
[] = {
347 { .compatible
= "qcom,ipq806x-gmac", .data
= &ipq806x_gmac_data
},
350 MODULE_DEVICE_TABLE(of
, ipq806x_gmac_dwmac_match
);
352 static struct platform_driver ipq806x_gmac_dwmac_driver
= {
353 .probe
= stmmac_pltfr_probe
,
354 .remove
= stmmac_pltfr_remove
,
356 .name
= "ipq806x-gmac-dwmac",
357 .pm
= &stmmac_pltfr_pm_ops
,
358 .of_match_table
= ipq806x_gmac_dwmac_match
,
361 module_platform_driver(ipq806x_gmac_dwmac_driver
);
363 MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>");
364 MODULE_DESCRIPTION("Qualcomm Atheros IPQ806x DWMAC specific glue layer");
365 MODULE_LICENSE("Dual BSD/GPL");