]>
Commit | Line | Data |
---|---|---|
3c910ecb | 1 | // SPDX-License-Identifier: GPL-2.0-only |
5ed74140 NA |
2 | /* |
3 | * Oxford Semiconductor OXNAS DWMAC glue layer | |
4 | * | |
5 | * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com> | |
6 | * Copyright (C) 2014 Daniel Golle <daniel@makrotopia.org> | |
7 | * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com> | |
8 | * Copyright (C) 2012 John Crispin <blogic@openwrt.org> | |
5ed74140 NA |
9 | */ |
10 | ||
11 | #include <linux/device.h> | |
12 | #include <linux/io.h> | |
13 | #include <linux/module.h> | |
14 | #include <linux/of.h> | |
15 | #include <linux/platform_device.h> | |
16 | #include <linux/regmap.h> | |
17 | #include <linux/mfd/syscon.h> | |
18 | #include <linux/stmmac.h> | |
19 | ||
20 | #include "stmmac_platform.h" | |
21 | ||
22 | /* System Control regmap offsets */ | |
23 | #define OXNAS_DWMAC_CTRL_REGOFFSET 0x78 | |
24 | #define OXNAS_DWMAC_DELAY_REGOFFSET 0x100 | |
25 | ||
26 | /* Control Register */ | |
27 | #define DWMAC_CKEN_RX_IN 14 | |
28 | #define DWMAC_CKEN_RXN_OUT 13 | |
29 | #define DWMAC_CKEN_RX_OUT 12 | |
30 | #define DWMAC_CKEN_TX_IN 10 | |
31 | #define DWMAC_CKEN_TXN_OUT 9 | |
32 | #define DWMAC_CKEN_TX_OUT 8 | |
33 | #define DWMAC_RX_SOURCE 7 | |
34 | #define DWMAC_TX_SOURCE 6 | |
35 | #define DWMAC_LOW_TX_SOURCE 4 | |
36 | #define DWMAC_AUTO_TX_SOURCE 3 | |
37 | #define DWMAC_RGMII 2 | |
38 | #define DWMAC_SIMPLE_MUX 1 | |
39 | #define DWMAC_CKEN_GTX 0 | |
40 | ||
41 | /* Delay register */ | |
42 | #define DWMAC_TX_VARDELAY_SHIFT 0 | |
43 | #define DWMAC_TXN_VARDELAY_SHIFT 8 | |
44 | #define DWMAC_RX_VARDELAY_SHIFT 16 | |
45 | #define DWMAC_RXN_VARDELAY_SHIFT 24 | |
46 | #define DWMAC_TX_VARDELAY(d) ((d) << DWMAC_TX_VARDELAY_SHIFT) | |
47 | #define DWMAC_TXN_VARDELAY(d) ((d) << DWMAC_TXN_VARDELAY_SHIFT) | |
48 | #define DWMAC_RX_VARDELAY(d) ((d) << DWMAC_RX_VARDELAY_SHIFT) | |
49 | #define DWMAC_RXN_VARDELAY(d) ((d) << DWMAC_RXN_VARDELAY_SHIFT) | |
50 | ||
51 | struct oxnas_dwmac { | |
52 | struct device *dev; | |
53 | struct clk *clk; | |
54 | struct regmap *regmap; | |
55 | }; | |
56 | ||
a8de4d71 | 57 | static int oxnas_dwmac_init(struct platform_device *pdev, void *priv) |
5ed74140 | 58 | { |
a8de4d71 | 59 | struct oxnas_dwmac *dwmac = priv; |
5ed74140 NA |
60 | unsigned int value; |
61 | int ret; | |
62 | ||
63 | /* Reset HW here before changing the glue configuration */ | |
64 | ret = device_reset(dwmac->dev); | |
65 | if (ret) | |
66 | return ret; | |
67 | ||
68 | ret = clk_prepare_enable(dwmac->clk); | |
69 | if (ret) | |
70 | return ret; | |
71 | ||
72 | ret = regmap_read(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, &value); | |
73 | if (ret < 0) { | |
74 | clk_disable_unprepare(dwmac->clk); | |
75 | return ret; | |
76 | } | |
77 | ||
78 | /* Enable GMII_GTXCLK to follow GMII_REFCLK, required for gigabit PHY */ | |
79 | value |= BIT(DWMAC_CKEN_GTX) | | |
80 | /* Use simple mux for 25/125 Mhz clock switching */ | |
81 | BIT(DWMAC_SIMPLE_MUX) | | |
82 | /* set auto switch tx clock source */ | |
83 | BIT(DWMAC_AUTO_TX_SOURCE) | | |
84 | /* enable tx & rx vardelay */ | |
85 | BIT(DWMAC_CKEN_TX_OUT) | | |
86 | BIT(DWMAC_CKEN_TXN_OUT) | | |
87 | BIT(DWMAC_CKEN_TX_IN) | | |
88 | BIT(DWMAC_CKEN_RX_OUT) | | |
89 | BIT(DWMAC_CKEN_RXN_OUT) | | |
90 | BIT(DWMAC_CKEN_RX_IN); | |
91 | regmap_write(dwmac->regmap, OXNAS_DWMAC_CTRL_REGOFFSET, value); | |
92 | ||
93 | /* set tx & rx vardelay */ | |
94 | value = DWMAC_TX_VARDELAY(4) | | |
95 | DWMAC_TXN_VARDELAY(2) | | |
96 | DWMAC_RX_VARDELAY(10) | | |
97 | DWMAC_RXN_VARDELAY(8); | |
98 | regmap_write(dwmac->regmap, OXNAS_DWMAC_DELAY_REGOFFSET, value); | |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
6b4c212b JH |
103 | static void oxnas_dwmac_exit(struct platform_device *pdev, void *priv) |
104 | { | |
105 | struct oxnas_dwmac *dwmac = priv; | |
106 | ||
107 | clk_disable_unprepare(dwmac->clk); | |
108 | } | |
109 | ||
5ed74140 NA |
110 | static int oxnas_dwmac_probe(struct platform_device *pdev) |
111 | { | |
112 | struct plat_stmmacenet_data *plat_dat; | |
113 | struct stmmac_resources stmmac_res; | |
5ed74140 NA |
114 | struct oxnas_dwmac *dwmac; |
115 | int ret; | |
116 | ||
5ed74140 NA |
117 | ret = stmmac_get_platform_resources(pdev, &stmmac_res); |
118 | if (ret) | |
119 | return ret; | |
120 | ||
121 | plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); | |
122 | if (IS_ERR(plat_dat)) | |
123 | return PTR_ERR(plat_dat); | |
124 | ||
125 | dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); | |
6b4c212b JH |
126 | if (!dwmac) { |
127 | ret = -ENOMEM; | |
128 | goto err_remove_config_dt; | |
129 | } | |
5ed74140 NA |
130 | |
131 | dwmac->dev = &pdev->dev; | |
132 | plat_dat->bsp_priv = dwmac; | |
a8de4d71 | 133 | plat_dat->init = oxnas_dwmac_init; |
6b4c212b | 134 | plat_dat->exit = oxnas_dwmac_exit; |
5ed74140 | 135 | |
8f87e626 JH |
136 | dwmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, |
137 | "oxsemi,sys-ctrl"); | |
5ed74140 NA |
138 | if (IS_ERR(dwmac->regmap)) { |
139 | dev_err(&pdev->dev, "failed to have sysctrl regmap\n"); | |
6b4c212b JH |
140 | ret = PTR_ERR(dwmac->regmap); |
141 | goto err_remove_config_dt; | |
5ed74140 NA |
142 | } |
143 | ||
144 | dwmac->clk = devm_clk_get(&pdev->dev, "gmac"); | |
6b4c212b JH |
145 | if (IS_ERR(dwmac->clk)) { |
146 | ret = PTR_ERR(dwmac->clk); | |
147 | goto err_remove_config_dt; | |
148 | } | |
5ed74140 | 149 | |
a8de4d71 | 150 | ret = oxnas_dwmac_init(pdev, plat_dat->bsp_priv); |
5ed74140 | 151 | if (ret) |
6b4c212b | 152 | goto err_remove_config_dt; |
5ed74140 NA |
153 | |
154 | ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
155 | if (ret) | |
6b4c212b | 156 | goto err_dwmac_exit; |
5ed74140 | 157 | |
5ed74140 | 158 | |
6b4c212b | 159 | return 0; |
5ed74140 | 160 | |
6b4c212b JH |
161 | err_dwmac_exit: |
162 | oxnas_dwmac_exit(pdev, plat_dat->bsp_priv); | |
163 | err_remove_config_dt: | |
164 | stmmac_remove_config_dt(pdev, plat_dat); | |
5ed74140 NA |
165 | |
166 | return ret; | |
167 | } | |
168 | ||
5ed74140 NA |
169 | static const struct of_device_id oxnas_dwmac_match[] = { |
170 | { .compatible = "oxsemi,ox820-dwmac" }, | |
171 | { } | |
172 | }; | |
173 | MODULE_DEVICE_TABLE(of, oxnas_dwmac_match); | |
174 | ||
175 | static struct platform_driver oxnas_dwmac_driver = { | |
176 | .probe = oxnas_dwmac_probe, | |
6b4c212b | 177 | .remove = stmmac_pltfr_remove, |
5ed74140 NA |
178 | .driver = { |
179 | .name = "oxnas-dwmac", | |
a8de4d71 | 180 | .pm = &stmmac_pltfr_pm_ops, |
5ed74140 NA |
181 | .of_match_table = oxnas_dwmac_match, |
182 | }, | |
183 | }; | |
184 | module_platform_driver(oxnas_dwmac_driver); | |
185 | ||
186 | MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); | |
187 | MODULE_DESCRIPTION("Oxford Semiconductor OXNAS DWMAC glue layer"); | |
188 | MODULE_LICENSE("GPL v2"); |