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