]>
Commit | Line | Data |
---|---|---|
a7c30e62 VK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2018-19, Linaro Limited | |
3 | ||
4 | #include <linux/module.h> | |
5 | #include <linux/of.h> | |
6 | #include <linux/of_device.h> | |
7 | #include <linux/platform_device.h> | |
8 | #include <linux/phy.h> | |
9 | #include "stmmac.h" | |
10 | #include "stmmac_platform.h" | |
11 | ||
12 | #define RGMII_IO_MACRO_CONFIG 0x0 | |
13 | #define SDCC_HC_REG_DLL_CONFIG 0x4 | |
14 | #define SDCC_HC_REG_DDR_CONFIG 0xC | |
15 | #define SDCC_HC_REG_DLL_CONFIG2 0x10 | |
16 | #define SDC4_STATUS 0x14 | |
17 | #define SDCC_USR_CTL 0x18 | |
18 | #define RGMII_IO_MACRO_CONFIG2 0x1C | |
19 | #define RGMII_IO_MACRO_DEBUG1 0x20 | |
20 | #define EMAC_SYSTEM_LOW_POWER_DEBUG 0x28 | |
21 | ||
22 | /* RGMII_IO_MACRO_CONFIG fields */ | |
23 | #define RGMII_CONFIG_FUNC_CLK_EN BIT(30) | |
24 | #define RGMII_CONFIG_POS_NEG_DATA_SEL BIT(23) | |
25 | #define RGMII_CONFIG_GPIO_CFG_RX_INT GENMASK(21, 20) | |
26 | #define RGMII_CONFIG_GPIO_CFG_TX_INT GENMASK(19, 17) | |
27 | #define RGMII_CONFIG_MAX_SPD_PRG_9 GENMASK(16, 8) | |
28 | #define RGMII_CONFIG_MAX_SPD_PRG_2 GENMASK(7, 6) | |
29 | #define RGMII_CONFIG_INTF_SEL GENMASK(5, 4) | |
30 | #define RGMII_CONFIG_BYPASS_TX_ID_EN BIT(3) | |
31 | #define RGMII_CONFIG_LOOPBACK_EN BIT(2) | |
32 | #define RGMII_CONFIG_PROG_SWAP BIT(1) | |
33 | #define RGMII_CONFIG_DDR_MODE BIT(0) | |
34 | ||
35 | /* SDCC_HC_REG_DLL_CONFIG fields */ | |
36 | #define SDCC_DLL_CONFIG_DLL_RST BIT(30) | |
37 | #define SDCC_DLL_CONFIG_PDN BIT(29) | |
38 | #define SDCC_DLL_CONFIG_MCLK_FREQ GENMASK(26, 24) | |
39 | #define SDCC_DLL_CONFIG_CDR_SELEXT GENMASK(23, 20) | |
40 | #define SDCC_DLL_CONFIG_CDR_EXT_EN BIT(19) | |
41 | #define SDCC_DLL_CONFIG_CK_OUT_EN BIT(18) | |
42 | #define SDCC_DLL_CONFIG_CDR_EN BIT(17) | |
43 | #define SDCC_DLL_CONFIG_DLL_EN BIT(16) | |
44 | #define SDCC_DLL_MCLK_GATING_EN BIT(5) | |
45 | #define SDCC_DLL_CDR_FINE_PHASE GENMASK(3, 2) | |
46 | ||
47 | /* SDCC_HC_REG_DDR_CONFIG fields */ | |
48 | #define SDCC_DDR_CONFIG_PRG_DLY_EN BIT(31) | |
49 | #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY GENMASK(26, 21) | |
50 | #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE GENMASK(29, 27) | |
51 | #define SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN BIT(30) | |
52 | #define SDCC_DDR_CONFIG_PRG_RCLK_DLY GENMASK(8, 0) | |
53 | ||
54 | /* SDCC_HC_REG_DLL_CONFIG2 fields */ | |
55 | #define SDCC_DLL_CONFIG2_DLL_CLOCK_DIS BIT(21) | |
56 | #define SDCC_DLL_CONFIG2_MCLK_FREQ_CALC GENMASK(17, 10) | |
57 | #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL GENMASK(3, 2) | |
58 | #define SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW BIT(1) | |
59 | #define SDCC_DLL_CONFIG2_DDR_CAL_EN BIT(0) | |
60 | ||
61 | /* SDC4_STATUS bits */ | |
62 | #define SDC4_STATUS_DLL_LOCK BIT(7) | |
63 | ||
64 | /* RGMII_IO_MACRO_CONFIG2 fields */ | |
65 | #define RGMII_CONFIG2_RSVD_CONFIG15 GENMASK(31, 17) | |
66 | #define RGMII_CONFIG2_RGMII_CLK_SEL_CFG BIT(16) | |
67 | #define RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN BIT(13) | |
68 | #define RGMII_CONFIG2_CLK_DIVIDE_SEL BIT(12) | |
69 | #define RGMII_CONFIG2_RX_PROG_SWAP BIT(7) | |
70 | #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL BIT(6) | |
71 | #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN BIT(5) | |
72 | ||
73 | struct ethqos_emac_por { | |
74 | unsigned int offset; | |
75 | unsigned int value; | |
76 | }; | |
77 | ||
fd4a5177 VK |
78 | struct ethqos_emac_driver_data { |
79 | const struct ethqos_emac_por *por; | |
80 | unsigned int num_por; | |
81 | }; | |
82 | ||
a7c30e62 VK |
83 | struct qcom_ethqos { |
84 | struct platform_device *pdev; | |
85 | void __iomem *rgmii_base; | |
86 | ||
87 | unsigned int rgmii_clk_rate; | |
88 | struct clk *rgmii_clk; | |
89 | unsigned int speed; | |
90 | ||
91 | const struct ethqos_emac_por *por; | |
92 | unsigned int num_por; | |
93 | }; | |
94 | ||
95 | static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) | |
96 | { | |
97 | return readl(ethqos->rgmii_base + offset); | |
98 | } | |
99 | ||
100 | static void rgmii_writel(struct qcom_ethqos *ethqos, | |
101 | int value, unsigned int offset) | |
102 | { | |
103 | writel(value, ethqos->rgmii_base + offset); | |
104 | } | |
105 | ||
106 | static void rgmii_updatel(struct qcom_ethqos *ethqos, | |
107 | int mask, int val, unsigned int offset) | |
108 | { | |
109 | unsigned int temp; | |
110 | ||
111 | temp = rgmii_readl(ethqos, offset); | |
112 | temp = (temp & ~(mask)) | val; | |
113 | rgmii_writel(ethqos, temp, offset); | |
114 | } | |
115 | ||
116 | static void rgmii_dump(struct qcom_ethqos *ethqos) | |
117 | { | |
118 | dev_dbg(ðqos->pdev->dev, "Rgmii register dump\n"); | |
119 | dev_dbg(ðqos->pdev->dev, "RGMII_IO_MACRO_CONFIG: %x\n", | |
120 | rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG)); | |
121 | dev_dbg(ðqos->pdev->dev, "SDCC_HC_REG_DLL_CONFIG: %x\n", | |
122 | rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG)); | |
123 | dev_dbg(ðqos->pdev->dev, "SDCC_HC_REG_DDR_CONFIG: %x\n", | |
124 | rgmii_readl(ethqos, SDCC_HC_REG_DDR_CONFIG)); | |
125 | dev_dbg(ðqos->pdev->dev, "SDCC_HC_REG_DLL_CONFIG2: %x\n", | |
126 | rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG2)); | |
127 | dev_dbg(ðqos->pdev->dev, "SDC4_STATUS: %x\n", | |
128 | rgmii_readl(ethqos, SDC4_STATUS)); | |
129 | dev_dbg(ðqos->pdev->dev, "SDCC_USR_CTL: %x\n", | |
130 | rgmii_readl(ethqos, SDCC_USR_CTL)); | |
131 | dev_dbg(ðqos->pdev->dev, "RGMII_IO_MACRO_CONFIG2: %x\n", | |
132 | rgmii_readl(ethqos, RGMII_IO_MACRO_CONFIG2)); | |
133 | dev_dbg(ðqos->pdev->dev, "RGMII_IO_MACRO_DEBUG1: %x\n", | |
134 | rgmii_readl(ethqos, RGMII_IO_MACRO_DEBUG1)); | |
135 | dev_dbg(ðqos->pdev->dev, "EMAC_SYSTEM_LOW_POWER_DEBUG: %x\n", | |
136 | rgmii_readl(ethqos, EMAC_SYSTEM_LOW_POWER_DEBUG)); | |
137 | } | |
138 | ||
139 | /* Clock rates */ | |
140 | #define RGMII_1000_NOM_CLK_FREQ (250 * 1000 * 1000UL) | |
141 | #define RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ (50 * 1000 * 1000UL) | |
142 | #define RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ (5 * 1000 * 1000UL) | |
143 | ||
144 | static void | |
145 | ethqos_update_rgmii_clk(struct qcom_ethqos *ethqos, unsigned int speed) | |
146 | { | |
147 | switch (speed) { | |
148 | case SPEED_1000: | |
149 | ethqos->rgmii_clk_rate = RGMII_1000_NOM_CLK_FREQ; | |
150 | break; | |
151 | ||
152 | case SPEED_100: | |
153 | ethqos->rgmii_clk_rate = RGMII_ID_MODE_100_LOW_SVS_CLK_FREQ; | |
154 | break; | |
155 | ||
156 | case SPEED_10: | |
157 | ethqos->rgmii_clk_rate = RGMII_ID_MODE_10_LOW_SVS_CLK_FREQ; | |
158 | break; | |
159 | } | |
160 | ||
161 | clk_set_rate(ethqos->rgmii_clk, ethqos->rgmii_clk_rate); | |
162 | } | |
163 | ||
164 | static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos) | |
165 | { | |
166 | rgmii_updatel(ethqos, RGMII_CONFIG_FUNC_CLK_EN, | |
167 | RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG); | |
168 | } | |
169 | ||
170 | static const struct ethqos_emac_por emac_v2_3_0_por[] = { | |
171 | { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, | |
172 | { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, | |
173 | { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, | |
174 | { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, | |
175 | { .offset = SDCC_USR_CTL, .value = 0x00010800 }, | |
176 | { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, | |
177 | }; | |
178 | ||
fd4a5177 VK |
179 | static const struct ethqos_emac_driver_data emac_v2_3_0_data = { |
180 | .por = emac_v2_3_0_por, | |
181 | .num_por = ARRAY_SIZE(emac_v2_3_0_por), | |
182 | }; | |
183 | ||
a7c30e62 VK |
184 | static int ethqos_dll_configure(struct qcom_ethqos *ethqos) |
185 | { | |
186 | unsigned int val; | |
187 | int retry = 1000; | |
188 | ||
189 | /* Set CDR_EN */ | |
190 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EN, | |
191 | SDCC_DLL_CONFIG_CDR_EN, SDCC_HC_REG_DLL_CONFIG); | |
192 | ||
193 | /* Set CDR_EXT_EN */ | |
194 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EXT_EN, | |
195 | SDCC_DLL_CONFIG_CDR_EXT_EN, SDCC_HC_REG_DLL_CONFIG); | |
196 | ||
197 | /* Clear CK_OUT_EN */ | |
198 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, | |
199 | 0, SDCC_HC_REG_DLL_CONFIG); | |
200 | ||
201 | /* Set DLL_EN */ | |
202 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, | |
203 | SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); | |
204 | ||
205 | rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, | |
206 | 0, SDCC_HC_REG_DLL_CONFIG); | |
207 | ||
208 | rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE, | |
209 | 0, SDCC_HC_REG_DLL_CONFIG); | |
210 | ||
211 | /* Wait for CK_OUT_EN clear */ | |
212 | do { | |
213 | val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); | |
214 | val &= SDCC_DLL_CONFIG_CK_OUT_EN; | |
215 | if (!val) | |
216 | break; | |
217 | mdelay(1); | |
218 | retry--; | |
219 | } while (retry > 0); | |
220 | if (!retry) | |
221 | dev_err(ðqos->pdev->dev, "Clear CK_OUT_EN timedout\n"); | |
222 | ||
223 | /* Set CK_OUT_EN */ | |
224 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, | |
225 | SDCC_DLL_CONFIG_CK_OUT_EN, SDCC_HC_REG_DLL_CONFIG); | |
226 | ||
227 | /* Wait for CK_OUT_EN set */ | |
228 | retry = 1000; | |
229 | do { | |
230 | val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); | |
231 | val &= SDCC_DLL_CONFIG_CK_OUT_EN; | |
232 | if (val) | |
233 | break; | |
234 | mdelay(1); | |
235 | retry--; | |
236 | } while (retry > 0); | |
237 | if (!retry) | |
238 | dev_err(ðqos->pdev->dev, "Set CK_OUT_EN timedout\n"); | |
239 | ||
240 | /* Set DDR_CAL_EN */ | |
241 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, | |
242 | SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2); | |
243 | ||
244 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, | |
245 | 0, SDCC_HC_REG_DLL_CONFIG2); | |
246 | ||
247 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, | |
248 | 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); | |
249 | ||
250 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, | |
251 | BIT(2), SDCC_HC_REG_DLL_CONFIG2); | |
252 | ||
253 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, | |
254 | SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, | |
255 | SDCC_HC_REG_DLL_CONFIG2); | |
256 | ||
257 | return 0; | |
258 | } | |
259 | ||
260 | static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) | |
261 | { | |
262 | /* Disable loopback mode */ | |
263 | rgmii_updatel(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN, | |
264 | 0, RGMII_IO_MACRO_CONFIG2); | |
265 | ||
266 | /* Select RGMII, write 0 to interface select */ | |
267 | rgmii_updatel(ethqos, RGMII_CONFIG_INTF_SEL, | |
268 | 0, RGMII_IO_MACRO_CONFIG); | |
269 | ||
270 | switch (ethqos->speed) { | |
271 | case SPEED_1000: | |
272 | rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, | |
273 | RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); | |
274 | rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, | |
275 | 0, RGMII_IO_MACRO_CONFIG); | |
276 | rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, | |
277 | RGMII_CONFIG_POS_NEG_DATA_SEL, | |
278 | RGMII_IO_MACRO_CONFIG); | |
279 | rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, | |
280 | RGMII_CONFIG_PROG_SWAP, RGMII_IO_MACRO_CONFIG); | |
281 | rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, | |
282 | 0, RGMII_IO_MACRO_CONFIG2); | |
283 | rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, | |
284 | RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, | |
285 | RGMII_IO_MACRO_CONFIG2); | |
286 | rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, | |
287 | 0, RGMII_IO_MACRO_CONFIG2); | |
288 | rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, | |
289 | RGMII_CONFIG2_RX_PROG_SWAP, | |
290 | RGMII_IO_MACRO_CONFIG2); | |
291 | ||
292 | /* Set PRG_RCLK_DLY to 57 for 1.8 ns delay */ | |
293 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, | |
294 | 57, SDCC_HC_REG_DDR_CONFIG); | |
295 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, | |
296 | SDCC_DDR_CONFIG_PRG_DLY_EN, | |
297 | SDCC_HC_REG_DDR_CONFIG); | |
298 | rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, | |
299 | RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG); | |
300 | break; | |
301 | ||
302 | case SPEED_100: | |
303 | rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, | |
304 | RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); | |
305 | rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, | |
306 | RGMII_CONFIG_BYPASS_TX_ID_EN, | |
307 | RGMII_IO_MACRO_CONFIG); | |
308 | rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, | |
309 | 0, RGMII_IO_MACRO_CONFIG); | |
310 | rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, | |
311 | 0, RGMII_IO_MACRO_CONFIG); | |
312 | rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, | |
313 | 0, RGMII_IO_MACRO_CONFIG2); | |
314 | rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, | |
315 | RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, | |
316 | RGMII_IO_MACRO_CONFIG2); | |
317 | rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_2, | |
318 | BIT(6), RGMII_IO_MACRO_CONFIG); | |
319 | rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, | |
320 | 0, RGMII_IO_MACRO_CONFIG2); | |
321 | rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, | |
322 | 0, RGMII_IO_MACRO_CONFIG2); | |
323 | /* Write 0x5 to PRG_RCLK_DLY_CODE */ | |
324 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, | |
325 | (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); | |
326 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, | |
327 | SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, | |
328 | SDCC_HC_REG_DDR_CONFIG); | |
329 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, | |
330 | SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, | |
331 | SDCC_HC_REG_DDR_CONFIG); | |
332 | rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, | |
333 | RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG); | |
334 | break; | |
335 | ||
336 | case SPEED_10: | |
337 | rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, | |
338 | RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); | |
339 | rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, | |
340 | RGMII_CONFIG_BYPASS_TX_ID_EN, | |
341 | RGMII_IO_MACRO_CONFIG); | |
342 | rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, | |
343 | 0, RGMII_IO_MACRO_CONFIG); | |
344 | rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, | |
345 | 0, RGMII_IO_MACRO_CONFIG); | |
346 | rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, | |
347 | 0, RGMII_IO_MACRO_CONFIG2); | |
348 | rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, | |
349 | 0, RGMII_IO_MACRO_CONFIG2); | |
350 | rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_9, | |
351 | BIT(12) | GENMASK(9, 8), | |
352 | RGMII_IO_MACRO_CONFIG); | |
353 | rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, | |
354 | 0, RGMII_IO_MACRO_CONFIG2); | |
355 | rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, | |
356 | 0, RGMII_IO_MACRO_CONFIG2); | |
357 | /* Write 0x5 to PRG_RCLK_DLY_CODE */ | |
358 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, | |
359 | (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); | |
360 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, | |
361 | SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, | |
362 | SDCC_HC_REG_DDR_CONFIG); | |
363 | rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, | |
364 | SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, | |
365 | SDCC_HC_REG_DDR_CONFIG); | |
366 | rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, | |
367 | RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG); | |
368 | break; | |
369 | default: | |
370 | dev_err(ðqos->pdev->dev, | |
371 | "Invalid speed %d\n", ethqos->speed); | |
372 | return -EINVAL; | |
373 | } | |
374 | ||
375 | return 0; | |
376 | } | |
377 | ||
378 | static int ethqos_configure(struct qcom_ethqos *ethqos) | |
379 | { | |
380 | volatile unsigned int dll_lock; | |
381 | unsigned int i, retry = 1000; | |
382 | ||
383 | /* Reset to POR values and enable clk */ | |
384 | for (i = 0; i < ethqos->num_por; i++) | |
385 | rgmii_writel(ethqos, ethqos->por[i].value, | |
386 | ethqos->por[i].offset); | |
387 | ethqos_set_func_clk_en(ethqos); | |
388 | ||
389 | /* Initialize the DLL first */ | |
390 | ||
391 | /* Set DLL_RST */ | |
392 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, | |
393 | SDCC_DLL_CONFIG_DLL_RST, SDCC_HC_REG_DLL_CONFIG); | |
394 | ||
395 | /* Set PDN */ | |
396 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, | |
397 | SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG); | |
398 | ||
399 | /* Clear DLL_RST */ | |
400 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, 0, | |
401 | SDCC_HC_REG_DLL_CONFIG); | |
402 | ||
403 | /* Clear PDN */ | |
404 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, 0, | |
405 | SDCC_HC_REG_DLL_CONFIG); | |
406 | ||
407 | if (ethqos->speed != SPEED_100 && ethqos->speed != SPEED_10) { | |
408 | /* Set DLL_EN */ | |
409 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, | |
410 | SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); | |
411 | ||
412 | /* Set CK_OUT_EN */ | |
413 | rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, | |
414 | SDCC_DLL_CONFIG_CK_OUT_EN, | |
415 | SDCC_HC_REG_DLL_CONFIG); | |
416 | ||
417 | /* Set USR_CTL bit 26 with mask of 3 bits */ | |
418 | rgmii_updatel(ethqos, GENMASK(26, 24), BIT(26), SDCC_USR_CTL); | |
419 | ||
420 | /* wait for DLL LOCK */ | |
421 | do { | |
422 | mdelay(1); | |
423 | dll_lock = rgmii_readl(ethqos, SDC4_STATUS); | |
424 | if (dll_lock & SDC4_STATUS_DLL_LOCK) | |
425 | break; | |
7d10f077 | 426 | retry--; |
a7c30e62 VK |
427 | } while (retry > 0); |
428 | if (!retry) | |
429 | dev_err(ðqos->pdev->dev, | |
430 | "Timeout while waiting for DLL lock\n"); | |
431 | } | |
432 | ||
433 | if (ethqos->speed == SPEED_1000) | |
434 | ethqos_dll_configure(ethqos); | |
435 | ||
436 | ethqos_rgmii_macro_init(ethqos); | |
437 | ||
438 | return 0; | |
439 | } | |
440 | ||
441 | static void ethqos_fix_mac_speed(void *priv, unsigned int speed) | |
442 | { | |
443 | struct qcom_ethqos *ethqos = priv; | |
444 | ||
445 | ethqos->speed = speed; | |
446 | ethqos_update_rgmii_clk(ethqos, speed); | |
447 | ethqos_configure(ethqos); | |
448 | } | |
449 | ||
450 | static int qcom_ethqos_probe(struct platform_device *pdev) | |
451 | { | |
452 | struct device_node *np = pdev->dev.of_node; | |
453 | struct plat_stmmacenet_data *plat_dat; | |
454 | struct stmmac_resources stmmac_res; | |
fd4a5177 | 455 | const struct ethqos_emac_driver_data *data; |
a7c30e62 VK |
456 | struct qcom_ethqos *ethqos; |
457 | struct resource *res; | |
458 | int ret; | |
459 | ||
460 | ret = stmmac_get_platform_resources(pdev, &stmmac_res); | |
461 | if (ret) | |
462 | return ret; | |
463 | ||
464 | plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); | |
465 | if (IS_ERR(plat_dat)) { | |
466 | dev_err(&pdev->dev, "dt configuration failed\n"); | |
467 | return PTR_ERR(plat_dat); | |
468 | } | |
469 | ||
470 | ethqos = devm_kzalloc(&pdev->dev, sizeof(*ethqos), GFP_KERNEL); | |
471 | if (!ethqos) { | |
472 | ret = -ENOMEM; | |
473 | goto err_mem; | |
474 | } | |
475 | ||
476 | ethqos->pdev = pdev; | |
477 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rgmii"); | |
478 | ethqos->rgmii_base = devm_ioremap_resource(&pdev->dev, res); | |
479 | if (IS_ERR(ethqos->rgmii_base)) { | |
480 | dev_err(&pdev->dev, "Can't get rgmii base\n"); | |
481 | ret = PTR_ERR(ethqos->rgmii_base); | |
482 | goto err_mem; | |
483 | } | |
484 | ||
fd4a5177 VK |
485 | data = of_device_get_match_data(&pdev->dev); |
486 | ethqos->por = data->por; | |
487 | ethqos->num_por = data->num_por; | |
a7c30e62 VK |
488 | |
489 | ethqos->rgmii_clk = devm_clk_get(&pdev->dev, "rgmii"); | |
8f4ebaaa WY |
490 | if (IS_ERR(ethqos->rgmii_clk)) { |
491 | ret = PTR_ERR(ethqos->rgmii_clk); | |
a7c30e62 VK |
492 | goto err_mem; |
493 | } | |
494 | ||
495 | ret = clk_prepare_enable(ethqos->rgmii_clk); | |
496 | if (ret) | |
497 | goto err_mem; | |
498 | ||
499 | ethqos->speed = SPEED_1000; | |
500 | ethqos_update_rgmii_clk(ethqos, SPEED_1000); | |
501 | ethqos_set_func_clk_en(ethqos); | |
502 | ||
503 | plat_dat->bsp_priv = ethqos; | |
504 | plat_dat->fix_mac_speed = ethqos_fix_mac_speed; | |
505 | plat_dat->has_gmac4 = 1; | |
506 | plat_dat->pmt = 1; | |
507 | plat_dat->tso_en = of_property_read_bool(np, "snps,tso"); | |
508 | ||
509 | ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); | |
510 | if (ret) | |
511 | goto err_clk; | |
512 | ||
513 | rgmii_dump(ethqos); | |
514 | ||
515 | return ret; | |
516 | ||
517 | err_clk: | |
518 | clk_disable_unprepare(ethqos->rgmii_clk); | |
519 | ||
520 | err_mem: | |
521 | stmmac_remove_config_dt(pdev, plat_dat); | |
522 | ||
523 | return ret; | |
524 | } | |
525 | ||
526 | static int qcom_ethqos_remove(struct platform_device *pdev) | |
527 | { | |
528 | struct qcom_ethqos *ethqos; | |
529 | int ret; | |
530 | ||
531 | ethqos = get_stmmac_bsp_priv(&pdev->dev); | |
532 | if (!ethqos) | |
533 | return -ENODEV; | |
534 | ||
535 | ret = stmmac_pltfr_remove(pdev); | |
536 | clk_disable_unprepare(ethqos->rgmii_clk); | |
537 | ||
538 | return ret; | |
539 | } | |
540 | ||
541 | static const struct of_device_id qcom_ethqos_match[] = { | |
fd4a5177 | 542 | { .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data}, |
a7c30e62 VK |
543 | { } |
544 | }; | |
545 | MODULE_DEVICE_TABLE(of, qcom_ethqos_match); | |
546 | ||
547 | static struct platform_driver qcom_ethqos_driver = { | |
548 | .probe = qcom_ethqos_probe, | |
549 | .remove = qcom_ethqos_remove, | |
550 | .driver = { | |
551 | .name = "qcom-ethqos", | |
552 | .pm = &stmmac_pltfr_pm_ops, | |
553 | .of_match_table = of_match_ptr(qcom_ethqos_match), | |
554 | }, | |
555 | }; | |
556 | module_platform_driver(qcom_ethqos_driver); | |
557 | ||
558 | MODULE_DESCRIPTION("Qualcomm ETHQOS driver"); | |
559 | MODULE_LICENSE("GPL v2"); |