2 * dwmac-stm32.c - DWMAC Specific Glue layer for STM32 MCU
4 * Copyright (C) STMicroelectronics SA 2017
5 * Author: Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
10 #include <linux/clk.h>
11 #include <linux/kernel.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/module.h>
15 #include <linux/of_device.h>
16 #include <linux/of_net.h>
17 #include <linux/phy.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm_wakeirq.h>
20 #include <linux/regmap.h>
21 #include <linux/slab.h>
22 #include <linux/stmmac.h>
24 #include "stmmac_platform.h"
26 #define SYSCFG_MCU_ETH_MASK BIT(23)
27 #define SYSCFG_MP1_ETH_MASK GENMASK(23, 16)
29 #define SYSCFG_PMCR_ETH_CLK_SEL BIT(16)
30 #define SYSCFG_PMCR_ETH_REF_CLK_SEL BIT(17)
31 #define SYSCFG_PMCR_ETH_SEL_MII BIT(20)
32 #define SYSCFG_PMCR_ETH_SEL_RGMII BIT(21)
33 #define SYSCFG_PMCR_ETH_SEL_RMII BIT(23)
34 #define SYSCFG_PMCR_ETH_SEL_GMII 0
35 #define SYSCFG_MCU_ETH_SEL_MII 0
36 #define SYSCFG_MCU_ETH_SEL_RMII 1
41 struct clk
*clk_eth_ck
;
42 struct clk
*clk_ethstp
;
43 struct clk
*syscfg_clk
;
44 bool int_phyclk
; /* Clock from RCC to drive PHY */
45 u32 mode_reg
; /* MAC glue-logic mode register */
46 struct regmap
*regmap
;
48 const struct stm32_ops
*ops
;
53 int (*set_mode
)(struct plat_stmmacenet_data
*plat_dat
);
54 int (*clk_prepare
)(struct stm32_dwmac
*dwmac
, bool prepare
);
55 int (*suspend
)(struct stm32_dwmac
*dwmac
);
56 void (*resume
)(struct stm32_dwmac
*dwmac
);
57 int (*parse_data
)(struct stm32_dwmac
*dwmac
,
62 static int stm32_dwmac_init(struct plat_stmmacenet_data
*plat_dat
)
64 struct stm32_dwmac
*dwmac
= plat_dat
->bsp_priv
;
67 if (dwmac
->ops
->set_mode
) {
68 ret
= dwmac
->ops
->set_mode(plat_dat
);
73 ret
= clk_prepare_enable(dwmac
->clk_tx
);
77 if (!dwmac
->dev
->power
.is_suspended
) {
78 ret
= clk_prepare_enable(dwmac
->clk_rx
);
80 clk_disable_unprepare(dwmac
->clk_tx
);
85 if (dwmac
->ops
->clk_prepare
) {
86 ret
= dwmac
->ops
->clk_prepare(dwmac
, true);
88 clk_disable_unprepare(dwmac
->clk_rx
);
89 clk_disable_unprepare(dwmac
->clk_tx
);
96 static int stm32mp1_clk_prepare(struct stm32_dwmac
*dwmac
, bool prepare
)
101 ret
= clk_prepare_enable(dwmac
->syscfg_clk
);
105 if (dwmac
->int_phyclk
) {
106 ret
= clk_prepare_enable(dwmac
->clk_eth_ck
);
108 clk_disable_unprepare(dwmac
->syscfg_clk
);
113 clk_disable_unprepare(dwmac
->syscfg_clk
);
114 if (dwmac
->int_phyclk
)
115 clk_disable_unprepare(dwmac
->clk_eth_ck
);
120 static int stm32mp1_set_mode(struct plat_stmmacenet_data
*plat_dat
)
122 struct stm32_dwmac
*dwmac
= plat_dat
->bsp_priv
;
123 u32 reg
= dwmac
->mode_reg
;
126 switch (plat_dat
->interface
) {
127 case PHY_INTERFACE_MODE_MII
:
128 val
= SYSCFG_PMCR_ETH_SEL_MII
;
129 pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
131 case PHY_INTERFACE_MODE_GMII
:
132 val
= SYSCFG_PMCR_ETH_SEL_GMII
;
133 if (dwmac
->int_phyclk
)
134 val
|= SYSCFG_PMCR_ETH_CLK_SEL
;
135 pr_debug("SYSCFG init : PHY_INTERFACE_MODE_GMII\n");
137 case PHY_INTERFACE_MODE_RMII
:
138 val
= SYSCFG_PMCR_ETH_SEL_RMII
;
139 if (dwmac
->int_phyclk
)
140 val
|= SYSCFG_PMCR_ETH_REF_CLK_SEL
;
141 pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
143 case PHY_INTERFACE_MODE_RGMII
:
144 val
= SYSCFG_PMCR_ETH_SEL_RGMII
;
145 if (dwmac
->int_phyclk
)
146 val
|= SYSCFG_PMCR_ETH_CLK_SEL
;
147 pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RGMII\n");
150 pr_debug("SYSCFG init : Do not manage %d interface\n",
151 plat_dat
->interface
);
152 /* Do not manage others interfaces */
156 return regmap_update_bits(dwmac
->regmap
, reg
,
157 dwmac
->ops
->syscfg_eth_mask
, val
);
160 static int stm32mcu_set_mode(struct plat_stmmacenet_data
*plat_dat
)
162 struct stm32_dwmac
*dwmac
= plat_dat
->bsp_priv
;
163 u32 reg
= dwmac
->mode_reg
;
166 switch (plat_dat
->interface
) {
167 case PHY_INTERFACE_MODE_MII
:
168 val
= SYSCFG_MCU_ETH_SEL_MII
;
169 pr_debug("SYSCFG init : PHY_INTERFACE_MODE_MII\n");
171 case PHY_INTERFACE_MODE_RMII
:
172 val
= SYSCFG_MCU_ETH_SEL_RMII
;
173 pr_debug("SYSCFG init : PHY_INTERFACE_MODE_RMII\n");
176 pr_debug("SYSCFG init : Do not manage %d interface\n",
177 plat_dat
->interface
);
178 /* Do not manage others interfaces */
182 return regmap_update_bits(dwmac
->regmap
, reg
,
183 dwmac
->ops
->syscfg_eth_mask
, val
);
186 static void stm32_dwmac_clk_disable(struct stm32_dwmac
*dwmac
)
188 clk_disable_unprepare(dwmac
->clk_tx
);
189 clk_disable_unprepare(dwmac
->clk_rx
);
191 if (dwmac
->ops
->clk_prepare
)
192 dwmac
->ops
->clk_prepare(dwmac
, false);
195 static int stm32_dwmac_parse_data(struct stm32_dwmac
*dwmac
,
198 struct device_node
*np
= dev
->of_node
;
201 /* Get TX/RX clocks */
202 dwmac
->clk_tx
= devm_clk_get(dev
, "mac-clk-tx");
203 if (IS_ERR(dwmac
->clk_tx
)) {
204 dev_err(dev
, "No ETH Tx clock provided...\n");
205 return PTR_ERR(dwmac
->clk_tx
);
208 dwmac
->clk_rx
= devm_clk_get(dev
, "mac-clk-rx");
209 if (IS_ERR(dwmac
->clk_rx
)) {
210 dev_err(dev
, "No ETH Rx clock provided...\n");
211 return PTR_ERR(dwmac
->clk_rx
);
214 if (dwmac
->ops
->parse_data
) {
215 err
= dwmac
->ops
->parse_data(dwmac
, dev
);
220 /* Get mode register */
221 dwmac
->regmap
= syscon_regmap_lookup_by_phandle(np
, "st,syscon");
222 if (IS_ERR(dwmac
->regmap
))
223 return PTR_ERR(dwmac
->regmap
);
225 err
= of_property_read_u32_index(np
, "st,syscon", 1, &dwmac
->mode_reg
);
227 dev_err(dev
, "Can't get sysconfig mode offset (%d)\n", err
);
232 static int stm32mp1_parse_data(struct stm32_dwmac
*dwmac
,
235 struct device_node
*np
= dev
->of_node
;
237 dwmac
->int_phyclk
= of_property_read_bool(np
, "st,int-phyclk");
239 /* Check if internal clk from RCC selected */
240 if (dwmac
->int_phyclk
) {
241 /* Get ETH_CLK clocks */
242 dwmac
->clk_eth_ck
= devm_clk_get(dev
, "eth-ck");
243 if (IS_ERR(dwmac
->clk_eth_ck
)) {
244 dev_err(dev
, "No ETH CK clock provided...\n");
245 return PTR_ERR(dwmac
->clk_eth_ck
);
249 /* Clock used for low power mode */
250 dwmac
->clk_ethstp
= devm_clk_get(dev
, "ethstp");
251 if (IS_ERR(dwmac
->clk_ethstp
)) {
252 dev_err(dev
, "No ETH peripheral clock provided for CStop mode ...\n");
253 return PTR_ERR(dwmac
->clk_ethstp
);
256 /* Clock for sysconfig */
257 dwmac
->syscfg_clk
= devm_clk_get(dev
, "syscfg-clk");
258 if (IS_ERR(dwmac
->syscfg_clk
)) {
259 dev_err(dev
, "No syscfg clock provided...\n");
260 return PTR_ERR(dwmac
->syscfg_clk
);
266 static int stm32_dwmac_probe(struct platform_device
*pdev
)
268 struct plat_stmmacenet_data
*plat_dat
;
269 struct stmmac_resources stmmac_res
;
270 struct stm32_dwmac
*dwmac
;
271 const struct stm32_ops
*data
;
274 ret
= stmmac_get_platform_resources(pdev
, &stmmac_res
);
278 plat_dat
= stmmac_probe_config_dt(pdev
, &stmmac_res
.mac
);
279 if (IS_ERR(plat_dat
))
280 return PTR_ERR(plat_dat
);
282 dwmac
= devm_kzalloc(&pdev
->dev
, sizeof(*dwmac
), GFP_KERNEL
);
285 goto err_remove_config_dt
;
288 data
= of_device_get_match_data(&pdev
->dev
);
290 dev_err(&pdev
->dev
, "no of match data provided\n");
292 goto err_remove_config_dt
;
296 dwmac
->dev
= &pdev
->dev
;
298 ret
= stm32_dwmac_parse_data(dwmac
, &pdev
->dev
);
300 dev_err(&pdev
->dev
, "Unable to parse OF data\n");
301 goto err_remove_config_dt
;
304 plat_dat
->bsp_priv
= dwmac
;
306 ret
= stm32_dwmac_init(plat_dat
);
308 goto err_remove_config_dt
;
310 ret
= stmmac_dvr_probe(&pdev
->dev
, plat_dat
, &stmmac_res
);
312 goto err_clk_disable
;
317 stm32_dwmac_clk_disable(dwmac
);
318 err_remove_config_dt
:
319 stmmac_remove_config_dt(pdev
, plat_dat
);
324 static int stm32_dwmac_remove(struct platform_device
*pdev
)
326 struct net_device
*ndev
= platform_get_drvdata(pdev
);
327 struct stmmac_priv
*priv
= netdev_priv(ndev
);
328 int ret
= stmmac_dvr_remove(&pdev
->dev
);
330 stm32_dwmac_clk_disable(priv
->plat
->bsp_priv
);
335 static int stm32mp1_suspend(struct stm32_dwmac
*dwmac
)
339 ret
= clk_prepare_enable(dwmac
->clk_ethstp
);
343 clk_disable_unprepare(dwmac
->clk_tx
);
344 clk_disable_unprepare(dwmac
->syscfg_clk
);
345 if (dwmac
->int_phyclk
)
346 clk_disable_unprepare(dwmac
->clk_eth_ck
);
351 static void stm32mp1_resume(struct stm32_dwmac
*dwmac
)
353 clk_disable_unprepare(dwmac
->clk_ethstp
);
356 static int stm32mcu_suspend(struct stm32_dwmac
*dwmac
)
358 clk_disable_unprepare(dwmac
->clk_tx
);
359 clk_disable_unprepare(dwmac
->clk_rx
);
364 #ifdef CONFIG_PM_SLEEP
365 static int stm32_dwmac_suspend(struct device
*dev
)
367 struct net_device
*ndev
= dev_get_drvdata(dev
);
368 struct stmmac_priv
*priv
= netdev_priv(ndev
);
369 struct stm32_dwmac
*dwmac
= priv
->plat
->bsp_priv
;
373 ret
= stmmac_suspend(dev
);
375 if (dwmac
->ops
->suspend
)
376 ret
= dwmac
->ops
->suspend(dwmac
);
381 static int stm32_dwmac_resume(struct device
*dev
)
383 struct net_device
*ndev
= dev_get_drvdata(dev
);
384 struct stmmac_priv
*priv
= netdev_priv(ndev
);
385 struct stm32_dwmac
*dwmac
= priv
->plat
->bsp_priv
;
388 if (dwmac
->ops
->resume
)
389 dwmac
->ops
->resume(dwmac
);
391 ret
= stm32_dwmac_init(priv
->plat
);
395 ret
= stmmac_resume(dev
);
399 #endif /* CONFIG_PM_SLEEP */
401 static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops
,
402 stm32_dwmac_suspend
, stm32_dwmac_resume
);
404 static struct stm32_ops stm32mcu_dwmac_data
= {
405 .set_mode
= stm32mcu_set_mode
,
406 .suspend
= stm32mcu_suspend
,
407 .syscfg_eth_mask
= SYSCFG_MCU_ETH_MASK
410 static struct stm32_ops stm32mp1_dwmac_data
= {
411 .set_mode
= stm32mp1_set_mode
,
412 .clk_prepare
= stm32mp1_clk_prepare
,
413 .suspend
= stm32mp1_suspend
,
414 .resume
= stm32mp1_resume
,
415 .parse_data
= stm32mp1_parse_data
,
416 .syscfg_eth_mask
= SYSCFG_MP1_ETH_MASK
419 static const struct of_device_id stm32_dwmac_match
[] = {
420 { .compatible
= "st,stm32-dwmac", .data
= &stm32mcu_dwmac_data
},
421 { .compatible
= "st,stm32mp1-dwmac", .data
= &stm32mp1_dwmac_data
},
424 MODULE_DEVICE_TABLE(of
, stm32_dwmac_match
);
426 static struct platform_driver stm32_dwmac_driver
= {
427 .probe
= stm32_dwmac_probe
,
428 .remove
= stm32_dwmac_remove
,
430 .name
= "stm32-dwmac",
431 .pm
= &stm32_dwmac_pm_ops
,
432 .of_match_table
= stm32_dwmac_match
,
435 module_platform_driver(stm32_dwmac_driver
);
437 MODULE_AUTHOR("Alexandre Torgue <alexandre.torgue@gmail.com>");
438 MODULE_AUTHOR("Christophe Roullier <christophe.roullier@st.com>");
439 MODULE_DESCRIPTION("STMicroelectronics STM32 DWMAC Specific Glue layer");
440 MODULE_LICENSE("GPL v2");