Commit | Line | Data |
---|---|---|
b9b17deb TT |
1 | /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. |
2 | * | |
3 | * This program is free software; you can redistribute it and/or modify | |
4 | * it under the terms of the GNU General Public License version 2 and | |
5 | * only version 2 as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * GNU General Public License for more details. | |
11 | */ | |
12 | ||
13 | /* Qualcomm Technologies, Inc. EMAC SGMII Controller driver. | |
14 | */ | |
15 | ||
282ccf6e | 16 | #include <linux/interrupt.h> |
b9b17deb | 17 | #include <linux/iopoll.h> |
5f3d3807 | 18 | #include <linux/acpi.h> |
b9b17deb TT |
19 | #include <linux/of_device.h> |
20 | #include "emac.h" | |
21 | #include "emac-mac.h" | |
22 | #include "emac-sgmii.h" | |
23 | ||
b9b17deb | 24 | /* EMAC_SGMII register offsets */ |
1e88ab6f TT |
25 | #define EMAC_SGMII_PHY_AUTONEG_CFG2 0x0048 |
26 | #define EMAC_SGMII_PHY_SPEED_CFG1 0x0074 | |
27 | #define EMAC_SGMII_PHY_IRQ_CMD 0x00ac | |
28 | #define EMAC_SGMII_PHY_INTERRUPT_CLEAR 0x00b0 | |
fd0e97b8 | 29 | #define EMAC_SGMII_PHY_INTERRUPT_MASK 0x00b4 |
1e88ab6f | 30 | #define EMAC_SGMII_PHY_INTERRUPT_STATUS 0x00b8 |
fd0e97b8 | 31 | #define EMAC_SGMII_PHY_RX_CHK_STATUS 0x00d4 |
1e88ab6f | 32 | |
b9b17deb TT |
33 | #define FORCE_AN_TX_CFG BIT(5) |
34 | #define FORCE_AN_RX_CFG BIT(4) | |
35 | #define AN_ENABLE BIT(0) | |
36 | ||
b9b17deb TT |
37 | #define DUPLEX_MODE BIT(4) |
38 | #define SPDMODE_1000 BIT(1) | |
39 | #define SPDMODE_100 BIT(0) | |
40 | #define SPDMODE_10 0 | |
b9b17deb | 41 | |
fd0e97b8 TT |
42 | #define CDR_ALIGN_DET BIT(6) |
43 | ||
b9b17deb TT |
44 | #define IRQ_GLOBAL_CLEAR BIT(0) |
45 | ||
b9b17deb TT |
46 | #define DECODE_CODE_ERR BIT(7) |
47 | #define DECODE_DISP_ERR BIT(6) | |
b9b17deb TT |
48 | |
49 | #define SGMII_PHY_IRQ_CLR_WAIT_TIME 10 | |
50 | ||
1e88ab6f | 51 | #define SGMII_PHY_INTERRUPT_ERR (DECODE_CODE_ERR | DECODE_DISP_ERR) |
fd0e97b8 | 52 | #define SGMII_ISR_MASK (SGMII_PHY_INTERRUPT_ERR) |
b9b17deb TT |
53 | |
54 | #define SERDES_START_WAIT_TIMES 100 | |
55 | ||
3db5d555 TT |
56 | /* Initialize the SGMII link between the internal and external PHYs. */ |
57 | static void emac_sgmii_link_init(struct emac_adapter *adpt) | |
b9b17deb | 58 | { |
41c1093f | 59 | struct emac_sgmii *phy = &adpt->phy; |
b9b17deb TT |
60 | u32 val; |
61 | ||
3db5d555 TT |
62 | /* Always use autonegotiation. It works no matter how the external |
63 | * PHY is configured. | |
64 | */ | |
b9b17deb | 65 | val = readl(phy->base + EMAC_SGMII_PHY_AUTONEG_CFG2); |
3db5d555 TT |
66 | val &= ~(FORCE_AN_RX_CFG | FORCE_AN_TX_CFG); |
67 | val |= AN_ENABLE; | |
68 | writel(val, phy->base + EMAC_SGMII_PHY_AUTONEG_CFG2); | |
b9b17deb TT |
69 | } |
70 | ||
71 | static int emac_sgmii_irq_clear(struct emac_adapter *adpt, u32 irq_bits) | |
72 | { | |
41c1093f | 73 | struct emac_sgmii *phy = &adpt->phy; |
b9b17deb TT |
74 | u32 status; |
75 | ||
76 | writel_relaxed(irq_bits, phy->base + EMAC_SGMII_PHY_INTERRUPT_CLEAR); | |
77 | writel_relaxed(IRQ_GLOBAL_CLEAR, phy->base + EMAC_SGMII_PHY_IRQ_CMD); | |
78 | /* Ensure interrupt clear command is written to HW */ | |
79 | wmb(); | |
80 | ||
81 | /* After set the IRQ_GLOBAL_CLEAR bit, the status clearing must | |
82 | * be confirmed before clearing the bits in other registers. | |
83 | * It takes a few cycles for hw to clear the interrupt status. | |
84 | */ | |
85 | if (readl_poll_timeout_atomic(phy->base + | |
86 | EMAC_SGMII_PHY_INTERRUPT_STATUS, | |
87 | status, !(status & irq_bits), 1, | |
88 | SGMII_PHY_IRQ_CLR_WAIT_TIME)) { | |
89 | netdev_err(adpt->netdev, | |
90 | "error: failed clear SGMII irq: status:0x%x bits:0x%x\n", | |
91 | status, irq_bits); | |
92 | return -EIO; | |
93 | } | |
94 | ||
95 | /* Finalize clearing procedure */ | |
96 | writel_relaxed(0, phy->base + EMAC_SGMII_PHY_IRQ_CMD); | |
97 | writel_relaxed(0, phy->base + EMAC_SGMII_PHY_INTERRUPT_CLEAR); | |
98 | ||
99 | /* Ensure that clearing procedure finalization is written to HW */ | |
100 | wmb(); | |
101 | ||
102 | return 0; | |
103 | } | |
104 | ||
fd0e97b8 TT |
105 | /* The number of decode errors that triggers a reset */ |
106 | #define DECODE_ERROR_LIMIT 2 | |
107 | ||
108 | static irqreturn_t emac_sgmii_interrupt(int irq, void *data) | |
109 | { | |
110 | struct emac_adapter *adpt = data; | |
111 | struct emac_sgmii *phy = &adpt->phy; | |
112 | u32 status; | |
113 | ||
114 | status = readl(phy->base + EMAC_SGMII_PHY_INTERRUPT_STATUS); | |
115 | status &= SGMII_ISR_MASK; | |
116 | if (!status) | |
117 | return IRQ_HANDLED; | |
118 | ||
119 | /* If we get a decoding error and CDR is not locked, then try | |
120 | * resetting the internal PHY. The internal PHY uses an embedded | |
121 | * clock with Clock and Data Recovery (CDR) to recover the | |
122 | * clock and data. | |
123 | */ | |
124 | if (status & SGMII_PHY_INTERRUPT_ERR) { | |
125 | int count; | |
126 | ||
127 | /* The SGMII is capable of recovering from some decode | |
128 | * errors automatically. However, if we get multiple | |
129 | * decode errors in a row, then assume that something | |
130 | * is wrong and reset the interface. | |
131 | */ | |
132 | count = atomic_inc_return(&phy->decode_error_count); | |
133 | if (count == DECODE_ERROR_LIMIT) { | |
134 | schedule_work(&adpt->work_thread); | |
135 | atomic_set(&phy->decode_error_count, 0); | |
136 | } | |
137 | } else { | |
138 | /* We only care about consecutive decode errors. */ | |
139 | atomic_set(&phy->decode_error_count, 0); | |
140 | } | |
141 | ||
142 | if (emac_sgmii_irq_clear(adpt, status)) { | |
143 | netdev_warn(adpt->netdev, "failed to clear SGMII interrupt\n"); | |
144 | schedule_work(&adpt->work_thread); | |
145 | } | |
146 | ||
147 | return IRQ_HANDLED; | |
148 | } | |
149 | ||
b9b17deb TT |
150 | static void emac_sgmii_reset_prepare(struct emac_adapter *adpt) |
151 | { | |
41c1093f | 152 | struct emac_sgmii *phy = &adpt->phy; |
b9b17deb TT |
153 | u32 val; |
154 | ||
155 | /* Reset PHY */ | |
156 | val = readl(phy->base + EMAC_EMAC_WRAPPER_CSR2); | |
157 | writel(((val & ~PHY_RESET) | PHY_RESET), phy->base + | |
158 | EMAC_EMAC_WRAPPER_CSR2); | |
159 | /* Ensure phy-reset command is written to HW before the release cmd */ | |
160 | msleep(50); | |
161 | val = readl(phy->base + EMAC_EMAC_WRAPPER_CSR2); | |
162 | writel((val & ~PHY_RESET), phy->base + EMAC_EMAC_WRAPPER_CSR2); | |
163 | /* Ensure phy-reset release command is written to HW before initializing | |
164 | * SGMII | |
165 | */ | |
166 | msleep(50); | |
167 | } | |
168 | ||
169 | void emac_sgmii_reset(struct emac_adapter *adpt) | |
170 | { | |
171 | int ret; | |
172 | ||
b9b17deb | 173 | emac_sgmii_reset_prepare(adpt); |
3db5d555 | 174 | emac_sgmii_link_init(adpt); |
1e88ab6f | 175 | |
b9b17deb TT |
176 | ret = adpt->phy.initialize(adpt); |
177 | if (ret) | |
178 | netdev_err(adpt->netdev, | |
179 | "could not reinitialize internal PHY (error=%i)\n", | |
180 | ret); | |
b9b17deb TT |
181 | } |
182 | ||
fd0e97b8 TT |
183 | static int emac_sgmii_open(struct emac_adapter *adpt) |
184 | { | |
185 | struct emac_sgmii *sgmii = &adpt->phy; | |
186 | int ret; | |
187 | ||
188 | if (sgmii->irq) { | |
189 | /* Make sure interrupts are cleared and disabled first */ | |
190 | ret = emac_sgmii_irq_clear(adpt, 0xff); | |
191 | if (ret) | |
192 | return ret; | |
193 | writel(0, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK); | |
194 | ||
195 | ret = request_irq(sgmii->irq, emac_sgmii_interrupt, 0, | |
196 | "emac-sgmii", adpt); | |
197 | if (ret) { | |
198 | netdev_err(adpt->netdev, | |
199 | "could not register handler for internal PHY\n"); | |
200 | return ret; | |
201 | } | |
202 | } | |
203 | ||
204 | return 0; | |
205 | } | |
206 | ||
207 | static int emac_sgmii_close(struct emac_adapter *adpt) | |
208 | { | |
209 | struct emac_sgmii *sgmii = &adpt->phy; | |
210 | ||
211 | /* Make sure interrupts are disabled */ | |
212 | writel(0, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK); | |
213 | free_irq(sgmii->irq, adpt); | |
214 | ||
215 | return 0; | |
216 | } | |
217 | ||
218 | /* The error interrupts are only valid after the link is up */ | |
219 | static int emac_sgmii_link_up(struct emac_adapter *adpt) | |
220 | { | |
221 | struct emac_sgmii *sgmii = &adpt->phy; | |
222 | int ret; | |
223 | ||
224 | /* Clear and enable interrupts */ | |
225 | ret = emac_sgmii_irq_clear(adpt, 0xff); | |
226 | if (ret) | |
227 | return ret; | |
228 | ||
229 | writel(SGMII_ISR_MASK, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK); | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | static int emac_sgmii_link_down(struct emac_adapter *adpt) | |
235 | { | |
236 | struct emac_sgmii *sgmii = &adpt->phy; | |
237 | ||
238 | /* Disable interrupts */ | |
239 | writel(0, sgmii->base + EMAC_SGMII_PHY_INTERRUPT_MASK); | |
240 | synchronize_irq(sgmii->irq); | |
241 | ||
242 | return 0; | |
243 | } | |
244 | ||
5f3d3807 TT |
245 | static int emac_sgmii_acpi_match(struct device *dev, void *data) |
246 | { | |
a51f4047 | 247 | #ifdef CONFIG_ACPI |
5f3d3807 TT |
248 | static const struct acpi_device_id match_table[] = { |
249 | { | |
250 | .id = "QCOM8071", | |
5f3d3807 TT |
251 | }, |
252 | {} | |
253 | }; | |
254 | const struct acpi_device_id *id = acpi_match_device(match_table, dev); | |
fd0e97b8 | 255 | emac_sgmii_function *initialize = data; |
5f3d3807 | 256 | |
a51f4047 TT |
257 | if (id) { |
258 | acpi_handle handle = ACPI_HANDLE(dev); | |
259 | unsigned long long hrv; | |
260 | acpi_status status; | |
261 | ||
262 | status = acpi_evaluate_integer(handle, "_HRV", NULL, &hrv); | |
263 | if (status) { | |
264 | if (status == AE_NOT_FOUND) | |
265 | /* Older versions of the QDF2432 ACPI tables do | |
266 | * not have an _HRV property. | |
267 | */ | |
268 | hrv = 1; | |
269 | else | |
270 | /* Something is wrong with the tables */ | |
271 | return 0; | |
272 | } | |
5f3d3807 | 273 | |
a51f4047 TT |
274 | switch (hrv) { |
275 | case 1: | |
276 | *initialize = emac_sgmii_init_qdf2432; | |
277 | return 1; | |
278 | case 2: | |
279 | *initialize = emac_sgmii_init_qdf2400; | |
280 | return 1; | |
281 | } | |
282 | } | |
283 | #endif | |
284 | ||
285 | return 0; | |
5f3d3807 TT |
286 | } |
287 | ||
b9b17deb TT |
288 | static const struct of_device_id emac_sgmii_dt_match[] = { |
289 | { | |
290 | .compatible = "qcom,fsm9900-emac-sgmii", | |
1e88ab6f | 291 | .data = emac_sgmii_init_fsm9900, |
b9b17deb TT |
292 | }, |
293 | { | |
294 | .compatible = "qcom,qdf2432-emac-sgmii", | |
1e88ab6f | 295 | .data = emac_sgmii_init_qdf2432, |
b9b17deb TT |
296 | }, |
297 | {} | |
298 | }; | |
299 | ||
ceef551f TT |
300 | /* Dummy function for systems without an internal PHY. This avoids having |
301 | * to check for NULL pointers before calling the functions. | |
302 | */ | |
303 | static int emac_sgmii_dummy(struct emac_adapter *adpt) | |
304 | { | |
305 | return 0; | |
306 | } | |
307 | ||
b9b17deb TT |
308 | int emac_sgmii_config(struct platform_device *pdev, struct emac_adapter *adpt) |
309 | { | |
310 | struct platform_device *sgmii_pdev = NULL; | |
41c1093f | 311 | struct emac_sgmii *phy = &adpt->phy; |
b9b17deb | 312 | struct resource *res; |
54e19bc7 | 313 | int ret; |
b9b17deb | 314 | |
5f3d3807 TT |
315 | if (has_acpi_companion(&pdev->dev)) { |
316 | struct device *dev; | |
b9b17deb | 317 | |
5f3d3807 TT |
318 | dev = device_find_child(&pdev->dev, &phy->initialize, |
319 | emac_sgmii_acpi_match); | |
b9b17deb | 320 | |
5f3d3807 | 321 | if (!dev) { |
ceef551f TT |
322 | dev_warn(&pdev->dev, "cannot find internal phy node\n"); |
323 | /* There is typically no internal PHY on emulation | |
324 | * systems, so if we can't find the node, assume | |
325 | * we are on an emulation system and stub-out | |
326 | * support for the internal PHY. These systems only | |
327 | * use ACPI. | |
328 | */ | |
329 | phy->open = emac_sgmii_dummy; | |
330 | phy->close = emac_sgmii_dummy; | |
331 | phy->link_up = emac_sgmii_dummy; | |
332 | phy->link_down = emac_sgmii_dummy; | |
333 | ||
334 | return 0; | |
5f3d3807 | 335 | } |
b9b17deb | 336 | |
5f3d3807 TT |
337 | sgmii_pdev = to_platform_device(dev); |
338 | } else { | |
339 | const struct of_device_id *match; | |
340 | struct device_node *np; | |
341 | ||
342 | np = of_parse_phandle(pdev->dev.of_node, "internal-phy", 0); | |
343 | if (!np) { | |
344 | dev_err(&pdev->dev, "missing internal-phy property\n"); | |
345 | return -ENODEV; | |
346 | } | |
347 | ||
348 | sgmii_pdev = of_find_device_by_node(np); | |
349 | if (!sgmii_pdev) { | |
350 | dev_err(&pdev->dev, "invalid internal-phy property\n"); | |
351 | return -ENODEV; | |
352 | } | |
353 | ||
354 | match = of_match_device(emac_sgmii_dt_match, &sgmii_pdev->dev); | |
355 | if (!match) { | |
356 | dev_err(&pdev->dev, "unrecognized internal phy node\n"); | |
357 | ret = -ENODEV; | |
358 | goto error_put_device; | |
359 | } | |
360 | ||
fd0e97b8 | 361 | phy->initialize = (emac_sgmii_function)match->data; |
5f3d3807 | 362 | } |
b9b17deb | 363 | |
fd0e97b8 TT |
364 | phy->open = emac_sgmii_open; |
365 | phy->close = emac_sgmii_close; | |
366 | phy->link_up = emac_sgmii_link_up; | |
367 | phy->link_down = emac_sgmii_link_down; | |
368 | ||
b9b17deb TT |
369 | /* Base address is the first address */ |
370 | res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 0); | |
0fd7d43f WY |
371 | if (!res) { |
372 | ret = -EINVAL; | |
373 | goto error_put_device; | |
374 | } | |
375 | ||
54e19bc7 | 376 | phy->base = ioremap(res->start, resource_size(res)); |
0fd7d43f WY |
377 | if (!phy->base) { |
378 | ret = -ENOMEM; | |
54e19bc7 TT |
379 | goto error_put_device; |
380 | } | |
b9b17deb TT |
381 | |
382 | /* v2 SGMII has a per-lane digital digital, so parse it if it exists */ | |
383 | res = platform_get_resource(sgmii_pdev, IORESOURCE_MEM, 1); | |
384 | if (res) { | |
54e19bc7 | 385 | phy->digital = ioremap(res->start, resource_size(res)); |
0fd7d43f WY |
386 | if (!phy->digital) { |
387 | ret = -ENOMEM; | |
54e19bc7 TT |
388 | goto error_unmap_base; |
389 | } | |
b9b17deb TT |
390 | } |
391 | ||
54e19bc7 TT |
392 | ret = phy->initialize(adpt); |
393 | if (ret) | |
394 | goto error; | |
395 | ||
3db5d555 | 396 | emac_sgmii_link_init(adpt); |
1e88ab6f | 397 | |
fd0e97b8 TT |
398 | ret = platform_get_irq(sgmii_pdev, 0); |
399 | if (ret > 0) | |
400 | phy->irq = ret; | |
401 | ||
54e19bc7 TT |
402 | /* We've remapped the addresses, so we don't need the device any |
403 | * more. of_find_device_by_node() says we should release it. | |
404 | */ | |
405 | put_device(&sgmii_pdev->dev); | |
406 | ||
407 | return 0; | |
408 | ||
409 | error: | |
410 | if (phy->digital) | |
411 | iounmap(phy->digital); | |
412 | error_unmap_base: | |
413 | iounmap(phy->base); | |
414 | error_put_device: | |
415 | put_device(&sgmii_pdev->dev); | |
416 | ||
417 | return ret; | |
b9b17deb | 418 | } |