Commit | Line | Data |
---|---|---|
0b523ced RM |
1 | /* |
2 | * Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved. | |
3 | * Copyright (c) 2015 The Linux Foundation. All rights reserved. | |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | #include <linux/module.h> | |
704dc4e3 RM |
18 | #include <linux/of.h> |
19 | #include <linux/of_device.h> | |
8beff219 | 20 | #include <linux/clk.h> |
14854bfd | 21 | #include <linux/reset.h> |
0b523ced RM |
22 | #include "core.h" |
23 | #include "debug.h" | |
7f8e79cd | 24 | #include "pci.h" |
0b523ced RM |
25 | #include "ahb.h" |
26 | ||
27 | static const struct of_device_id ath10k_ahb_of_match[] = { | |
280e762e RM |
28 | { .compatible = "qcom,ipq4019-wifi", |
29 | .data = (void *)ATH10K_HW_QCA4019 | |
30 | }, | |
0b523ced RM |
31 | { } |
32 | }; | |
33 | ||
34 | MODULE_DEVICE_TABLE(of, ath10k_ahb_of_match); | |
35 | ||
7f8e79cd RM |
36 | static inline struct ath10k_ahb *ath10k_ahb_priv(struct ath10k *ar) |
37 | { | |
38 | return &((struct ath10k_pci *)ar->drv_priv)->ahb[0]; | |
39 | } | |
40 | ||
41 | static void ath10k_ahb_write32(struct ath10k *ar, u32 offset, u32 value) | |
42 | { | |
43 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
44 | ||
45 | iowrite32(value, ar_ahb->mem + offset); | |
46 | } | |
47 | ||
48 | static u32 ath10k_ahb_read32(struct ath10k *ar, u32 offset) | |
49 | { | |
50 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
51 | ||
52 | return ioread32(ar_ahb->mem + offset); | |
53 | } | |
54 | ||
55 | static u32 ath10k_ahb_gcc_read32(struct ath10k *ar, u32 offset) | |
56 | { | |
57 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
58 | ||
59 | return ioread32(ar_ahb->gcc_mem + offset); | |
60 | } | |
61 | ||
62 | static void ath10k_ahb_tcsr_write32(struct ath10k *ar, u32 offset, u32 value) | |
63 | { | |
64 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
65 | ||
66 | iowrite32(value, ar_ahb->tcsr_mem + offset); | |
67 | } | |
68 | ||
69 | static u32 ath10k_ahb_tcsr_read32(struct ath10k *ar, u32 offset) | |
70 | { | |
71 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
72 | ||
73 | return ioread32(ar_ahb->tcsr_mem + offset); | |
74 | } | |
75 | ||
76 | static u32 ath10k_ahb_soc_read32(struct ath10k *ar, u32 addr) | |
77 | { | |
78 | return ath10k_ahb_read32(ar, RTC_SOC_BASE_ADDRESS + addr); | |
79 | } | |
80 | ||
81 | static int ath10k_ahb_get_num_banks(struct ath10k *ar) | |
82 | { | |
83 | if (ar->hw_rev == ATH10K_HW_QCA4019) | |
84 | return 1; | |
85 | ||
86 | ath10k_warn(ar, "unknown number of banks, assuming 1\n"); | |
87 | return 1; | |
88 | } | |
89 | ||
8beff219 RM |
90 | static int ath10k_ahb_clock_init(struct ath10k *ar) |
91 | { | |
92 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
93 | struct device *dev; | |
94 | int ret; | |
95 | ||
96 | dev = &ar_ahb->pdev->dev; | |
97 | ||
98 | ar_ahb->cmd_clk = clk_get(dev, "wifi_wcss_cmd"); | |
99 | if (IS_ERR_OR_NULL(ar_ahb->cmd_clk)) { | |
100 | ath10k_err(ar, "failed to get cmd clk: %ld\n", | |
101 | PTR_ERR(ar_ahb->cmd_clk)); | |
102 | ret = ar_ahb->cmd_clk ? PTR_ERR(ar_ahb->cmd_clk) : -ENODEV; | |
103 | goto out; | |
104 | } | |
105 | ||
106 | ar_ahb->ref_clk = clk_get(dev, "wifi_wcss_ref"); | |
107 | if (IS_ERR_OR_NULL(ar_ahb->ref_clk)) { | |
108 | ath10k_err(ar, "failed to get ref clk: %ld\n", | |
109 | PTR_ERR(ar_ahb->ref_clk)); | |
110 | ret = ar_ahb->ref_clk ? PTR_ERR(ar_ahb->ref_clk) : -ENODEV; | |
111 | goto err_cmd_clk_put; | |
112 | } | |
113 | ||
114 | ar_ahb->rtc_clk = clk_get(dev, "wifi_wcss_rtc"); | |
115 | if (IS_ERR_OR_NULL(ar_ahb->rtc_clk)) { | |
116 | ath10k_err(ar, "failed to get rtc clk: %ld\n", | |
117 | PTR_ERR(ar_ahb->rtc_clk)); | |
118 | ret = ar_ahb->rtc_clk ? PTR_ERR(ar_ahb->rtc_clk) : -ENODEV; | |
119 | goto err_ref_clk_put; | |
120 | } | |
121 | ||
122 | return 0; | |
123 | ||
124 | err_ref_clk_put: | |
125 | clk_put(ar_ahb->ref_clk); | |
126 | ||
127 | err_cmd_clk_put: | |
128 | clk_put(ar_ahb->cmd_clk); | |
129 | ||
130 | out: | |
131 | return ret; | |
132 | } | |
133 | ||
134 | static void ath10k_ahb_clock_deinit(struct ath10k *ar) | |
135 | { | |
136 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
137 | ||
138 | if (!IS_ERR_OR_NULL(ar_ahb->cmd_clk)) | |
139 | clk_put(ar_ahb->cmd_clk); | |
140 | ||
141 | if (!IS_ERR_OR_NULL(ar_ahb->ref_clk)) | |
142 | clk_put(ar_ahb->ref_clk); | |
143 | ||
144 | if (!IS_ERR_OR_NULL(ar_ahb->rtc_clk)) | |
145 | clk_put(ar_ahb->rtc_clk); | |
146 | ||
147 | ar_ahb->cmd_clk = NULL; | |
148 | ar_ahb->ref_clk = NULL; | |
149 | ar_ahb->rtc_clk = NULL; | |
150 | } | |
151 | ||
152 | static int ath10k_ahb_clock_enable(struct ath10k *ar) | |
153 | { | |
154 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
155 | struct device *dev; | |
156 | int ret; | |
157 | ||
158 | dev = &ar_ahb->pdev->dev; | |
159 | ||
160 | if (IS_ERR_OR_NULL(ar_ahb->cmd_clk) || | |
161 | IS_ERR_OR_NULL(ar_ahb->ref_clk) || | |
162 | IS_ERR_OR_NULL(ar_ahb->rtc_clk)) { | |
163 | ath10k_err(ar, "clock(s) is/are not initialized\n"); | |
164 | ret = -EIO; | |
165 | goto out; | |
166 | } | |
167 | ||
168 | ret = clk_prepare_enable(ar_ahb->cmd_clk); | |
169 | if (ret) { | |
170 | ath10k_err(ar, "failed to enable cmd clk: %d\n", ret); | |
171 | goto out; | |
172 | } | |
173 | ||
174 | ret = clk_prepare_enable(ar_ahb->ref_clk); | |
175 | if (ret) { | |
176 | ath10k_err(ar, "failed to enable ref clk: %d\n", ret); | |
177 | goto err_cmd_clk_disable; | |
178 | } | |
179 | ||
180 | ret = clk_prepare_enable(ar_ahb->rtc_clk); | |
181 | if (ret) { | |
182 | ath10k_err(ar, "failed to enable rtc clk: %d\n", ret); | |
183 | goto err_ref_clk_disable; | |
184 | } | |
185 | ||
186 | return 0; | |
187 | ||
188 | err_ref_clk_disable: | |
189 | clk_disable_unprepare(ar_ahb->ref_clk); | |
190 | ||
191 | err_cmd_clk_disable: | |
192 | clk_disable_unprepare(ar_ahb->cmd_clk); | |
193 | ||
194 | out: | |
195 | return ret; | |
196 | } | |
197 | ||
198 | static void ath10k_ahb_clock_disable(struct ath10k *ar) | |
199 | { | |
200 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
201 | ||
202 | if (!IS_ERR_OR_NULL(ar_ahb->cmd_clk)) | |
203 | clk_disable_unprepare(ar_ahb->cmd_clk); | |
204 | ||
205 | if (!IS_ERR_OR_NULL(ar_ahb->ref_clk)) | |
206 | clk_disable_unprepare(ar_ahb->ref_clk); | |
207 | ||
208 | if (!IS_ERR_OR_NULL(ar_ahb->rtc_clk)) | |
209 | clk_disable_unprepare(ar_ahb->rtc_clk); | |
210 | } | |
211 | ||
14854bfd RM |
212 | static int ath10k_ahb_rst_ctrl_init(struct ath10k *ar) |
213 | { | |
214 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
215 | struct device *dev; | |
216 | int ret; | |
217 | ||
218 | dev = &ar_ahb->pdev->dev; | |
219 | ||
220 | ar_ahb->core_cold_rst = reset_control_get(dev, "wifi_core_cold"); | |
221 | if (IS_ERR_OR_NULL(ar_ahb->core_cold_rst)) { | |
222 | ath10k_err(ar, "failed to get core cold rst ctrl: %ld\n", | |
223 | PTR_ERR(ar_ahb->core_cold_rst)); | |
224 | ret = ar_ahb->core_cold_rst ? | |
225 | PTR_ERR(ar_ahb->core_cold_rst) : -ENODEV; | |
226 | goto out; | |
227 | } | |
228 | ||
229 | ar_ahb->radio_cold_rst = reset_control_get(dev, "wifi_radio_cold"); | |
230 | if (IS_ERR_OR_NULL(ar_ahb->radio_cold_rst)) { | |
231 | ath10k_err(ar, "failed to get radio cold rst ctrl: %ld\n", | |
232 | PTR_ERR(ar_ahb->radio_cold_rst)); | |
233 | ret = ar_ahb->radio_cold_rst ? | |
234 | PTR_ERR(ar_ahb->radio_cold_rst) : -ENODEV; | |
235 | goto err_core_cold_rst_put; | |
236 | } | |
237 | ||
238 | ar_ahb->radio_warm_rst = reset_control_get(dev, "wifi_radio_warm"); | |
239 | if (IS_ERR_OR_NULL(ar_ahb->radio_warm_rst)) { | |
240 | ath10k_err(ar, "failed to get radio warm rst ctrl: %ld\n", | |
241 | PTR_ERR(ar_ahb->radio_warm_rst)); | |
242 | ret = ar_ahb->radio_warm_rst ? | |
243 | PTR_ERR(ar_ahb->radio_warm_rst) : -ENODEV; | |
244 | goto err_radio_cold_rst_put; | |
245 | } | |
246 | ||
247 | ar_ahb->radio_srif_rst = reset_control_get(dev, "wifi_radio_srif"); | |
248 | if (IS_ERR_OR_NULL(ar_ahb->radio_srif_rst)) { | |
249 | ath10k_err(ar, "failed to get radio srif rst ctrl: %ld\n", | |
250 | PTR_ERR(ar_ahb->radio_srif_rst)); | |
251 | ret = ar_ahb->radio_srif_rst ? | |
252 | PTR_ERR(ar_ahb->radio_srif_rst) : -ENODEV; | |
253 | goto err_radio_warm_rst_put; | |
254 | } | |
255 | ||
256 | ar_ahb->cpu_init_rst = reset_control_get(dev, "wifi_cpu_init"); | |
257 | if (IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) { | |
258 | ath10k_err(ar, "failed to get cpu init rst ctrl: %ld\n", | |
259 | PTR_ERR(ar_ahb->cpu_init_rst)); | |
260 | ret = ar_ahb->cpu_init_rst ? | |
261 | PTR_ERR(ar_ahb->cpu_init_rst) : -ENODEV; | |
262 | goto err_radio_srif_rst_put; | |
263 | } | |
264 | ||
265 | return 0; | |
266 | ||
267 | err_radio_srif_rst_put: | |
268 | reset_control_put(ar_ahb->radio_srif_rst); | |
269 | ||
270 | err_radio_warm_rst_put: | |
271 | reset_control_put(ar_ahb->radio_warm_rst); | |
272 | ||
273 | err_radio_cold_rst_put: | |
274 | reset_control_put(ar_ahb->radio_cold_rst); | |
275 | ||
276 | err_core_cold_rst_put: | |
277 | reset_control_put(ar_ahb->core_cold_rst); | |
278 | ||
279 | out: | |
280 | return ret; | |
281 | } | |
282 | ||
283 | static void ath10k_ahb_rst_ctrl_deinit(struct ath10k *ar) | |
284 | { | |
285 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
286 | ||
287 | if (!IS_ERR_OR_NULL(ar_ahb->core_cold_rst)) | |
288 | reset_control_put(ar_ahb->core_cold_rst); | |
289 | ||
290 | if (!IS_ERR_OR_NULL(ar_ahb->radio_cold_rst)) | |
291 | reset_control_put(ar_ahb->radio_cold_rst); | |
292 | ||
293 | if (!IS_ERR_OR_NULL(ar_ahb->radio_warm_rst)) | |
294 | reset_control_put(ar_ahb->radio_warm_rst); | |
295 | ||
296 | if (!IS_ERR_OR_NULL(ar_ahb->radio_srif_rst)) | |
297 | reset_control_put(ar_ahb->radio_srif_rst); | |
298 | ||
299 | if (!IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) | |
300 | reset_control_put(ar_ahb->cpu_init_rst); | |
301 | ||
302 | ar_ahb->core_cold_rst = NULL; | |
303 | ar_ahb->radio_cold_rst = NULL; | |
304 | ar_ahb->radio_warm_rst = NULL; | |
305 | ar_ahb->radio_srif_rst = NULL; | |
306 | ar_ahb->cpu_init_rst = NULL; | |
307 | } | |
308 | ||
309 | static int ath10k_ahb_release_reset(struct ath10k *ar) | |
310 | { | |
311 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
312 | int ret; | |
313 | ||
314 | if (IS_ERR_OR_NULL(ar_ahb->radio_cold_rst) || | |
315 | IS_ERR_OR_NULL(ar_ahb->radio_warm_rst) || | |
316 | IS_ERR_OR_NULL(ar_ahb->radio_srif_rst) || | |
317 | IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) { | |
318 | ath10k_err(ar, "rst ctrl(s) is/are not initialized\n"); | |
319 | return -EINVAL; | |
320 | } | |
321 | ||
322 | ret = reset_control_deassert(ar_ahb->radio_cold_rst); | |
323 | if (ret) { | |
324 | ath10k_err(ar, "failed to deassert radio cold rst: %d\n", ret); | |
325 | return ret; | |
326 | } | |
327 | ||
328 | ret = reset_control_deassert(ar_ahb->radio_warm_rst); | |
329 | if (ret) { | |
330 | ath10k_err(ar, "failed to deassert radio warm rst: %d\n", ret); | |
331 | return ret; | |
332 | } | |
333 | ||
334 | ret = reset_control_deassert(ar_ahb->radio_srif_rst); | |
335 | if (ret) { | |
336 | ath10k_err(ar, "failed to deassert radio srif rst: %d\n", ret); | |
337 | return ret; | |
338 | } | |
339 | ||
340 | ret = reset_control_deassert(ar_ahb->cpu_init_rst); | |
341 | if (ret) { | |
342 | ath10k_err(ar, "failed to deassert cpu init rst: %d\n", ret); | |
343 | return ret; | |
344 | } | |
345 | ||
346 | return 0; | |
347 | } | |
348 | ||
133df0f8 RM |
349 | static void ath10k_ahb_halt_axi_bus(struct ath10k *ar, u32 haltreq_reg, |
350 | u32 haltack_reg) | |
351 | { | |
352 | unsigned long timeout; | |
353 | u32 val; | |
354 | ||
355 | /* Issue halt axi bus request */ | |
356 | val = ath10k_ahb_tcsr_read32(ar, haltreq_reg); | |
357 | val |= AHB_AXI_BUS_HALT_REQ; | |
358 | ath10k_ahb_tcsr_write32(ar, haltreq_reg, val); | |
359 | ||
360 | /* Wait for axi bus halted ack */ | |
361 | timeout = jiffies + msecs_to_jiffies(ATH10K_AHB_AXI_BUS_HALT_TIMEOUT); | |
362 | do { | |
363 | val = ath10k_ahb_tcsr_read32(ar, haltack_reg); | |
364 | if (val & AHB_AXI_BUS_HALT_ACK) | |
365 | break; | |
366 | ||
367 | mdelay(1); | |
368 | } while (time_before(jiffies, timeout)); | |
369 | ||
370 | if (!(val & AHB_AXI_BUS_HALT_ACK)) { | |
371 | ath10k_err(ar, "failed to halt axi bus: %d\n", val); | |
372 | return; | |
373 | } | |
374 | ||
375 | ath10k_dbg(ar, ATH10K_DBG_AHB, "axi bus halted\n"); | |
376 | } | |
377 | ||
378 | static void ath10k_ahb_halt_chip(struct ath10k *ar) | |
379 | { | |
380 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
381 | u32 core_id, glb_cfg_reg, haltreq_reg, haltack_reg; | |
382 | u32 val; | |
383 | int ret; | |
384 | ||
385 | if (IS_ERR_OR_NULL(ar_ahb->core_cold_rst) || | |
386 | IS_ERR_OR_NULL(ar_ahb->radio_cold_rst) || | |
387 | IS_ERR_OR_NULL(ar_ahb->radio_warm_rst) || | |
388 | IS_ERR_OR_NULL(ar_ahb->radio_srif_rst) || | |
389 | IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) { | |
390 | ath10k_err(ar, "rst ctrl(s) is/are not initialized\n"); | |
391 | return; | |
392 | } | |
393 | ||
394 | core_id = ath10k_ahb_read32(ar, ATH10K_AHB_WLAN_CORE_ID_REG); | |
395 | ||
396 | switch (core_id) { | |
397 | case 0: | |
398 | glb_cfg_reg = ATH10K_AHB_TCSR_WIFI0_GLB_CFG; | |
399 | haltreq_reg = ATH10K_AHB_TCSR_WCSS0_HALTREQ; | |
400 | haltack_reg = ATH10K_AHB_TCSR_WCSS0_HALTACK; | |
401 | break; | |
402 | case 1: | |
403 | glb_cfg_reg = ATH10K_AHB_TCSR_WIFI1_GLB_CFG; | |
404 | haltreq_reg = ATH10K_AHB_TCSR_WCSS1_HALTREQ; | |
405 | haltack_reg = ATH10K_AHB_TCSR_WCSS1_HALTACK; | |
406 | break; | |
407 | default: | |
408 | ath10k_err(ar, "invalid core id %d found, skipping reset sequence\n", | |
409 | core_id); | |
410 | return; | |
411 | } | |
412 | ||
413 | ath10k_ahb_halt_axi_bus(ar, haltreq_reg, haltack_reg); | |
414 | ||
415 | val = ath10k_ahb_tcsr_read32(ar, glb_cfg_reg); | |
416 | val |= TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK; | |
417 | ath10k_ahb_tcsr_write32(ar, glb_cfg_reg, val); | |
418 | ||
419 | ret = reset_control_assert(ar_ahb->core_cold_rst); | |
420 | if (ret) | |
421 | ath10k_err(ar, "failed to assert core cold rst: %d\n", ret); | |
422 | msleep(1); | |
423 | ||
424 | ret = reset_control_assert(ar_ahb->radio_cold_rst); | |
425 | if (ret) | |
426 | ath10k_err(ar, "failed to assert radio cold rst: %d\n", ret); | |
427 | msleep(1); | |
428 | ||
429 | ret = reset_control_assert(ar_ahb->radio_warm_rst); | |
430 | if (ret) | |
431 | ath10k_err(ar, "failed to assert radio warm rst: %d\n", ret); | |
432 | msleep(1); | |
433 | ||
434 | ret = reset_control_assert(ar_ahb->radio_srif_rst); | |
435 | if (ret) | |
436 | ath10k_err(ar, "failed to assert radio srif rst: %d\n", ret); | |
437 | msleep(1); | |
438 | ||
439 | ret = reset_control_assert(ar_ahb->cpu_init_rst); | |
440 | if (ret) | |
441 | ath10k_err(ar, "failed to assert cpu init rst: %d\n", ret); | |
442 | msleep(10); | |
443 | ||
444 | /* Clear halt req and core clock disable req before | |
445 | * deasserting wifi core reset. | |
446 | */ | |
447 | val = ath10k_ahb_tcsr_read32(ar, haltreq_reg); | |
448 | val &= ~AHB_AXI_BUS_HALT_REQ; | |
449 | ath10k_ahb_tcsr_write32(ar, haltreq_reg, val); | |
450 | ||
451 | val = ath10k_ahb_tcsr_read32(ar, glb_cfg_reg); | |
452 | val &= ~TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK; | |
453 | ath10k_ahb_tcsr_write32(ar, glb_cfg_reg, val); | |
454 | ||
455 | ret = reset_control_deassert(ar_ahb->core_cold_rst); | |
456 | if (ret) | |
457 | ath10k_err(ar, "failed to deassert core cold rst: %d\n", ret); | |
458 | ||
459 | ath10k_dbg(ar, ATH10K_DBG_AHB, "core %d reset done\n", core_id); | |
460 | } | |
461 | ||
1c44fcb9 RM |
462 | static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg) |
463 | { | |
464 | struct ath10k *ar = arg; | |
465 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); | |
466 | ||
467 | if (!ath10k_pci_irq_pending(ar)) | |
468 | return IRQ_NONE; | |
469 | ||
470 | ath10k_pci_disable_and_clear_legacy_irq(ar); | |
471 | tasklet_schedule(&ar_pci->intr_tq); | |
472 | ||
473 | return IRQ_HANDLED; | |
474 | } | |
475 | ||
476 | static int ath10k_ahb_request_irq_legacy(struct ath10k *ar) | |
477 | { | |
2e550b6d | 478 | struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); |
1c44fcb9 RM |
479 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); |
480 | int ret; | |
481 | ||
482 | ret = request_irq(ar_ahb->irq, | |
483 | ath10k_ahb_interrupt_handler, | |
484 | IRQF_SHARED, "ath10k_ahb", ar); | |
485 | if (ret) { | |
486 | ath10k_warn(ar, "failed to request legacy irq %d: %d\n", | |
487 | ar_ahb->irq, ret); | |
488 | return ret; | |
489 | } | |
2e550b6d | 490 | ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY; |
1c44fcb9 RM |
491 | |
492 | return 0; | |
493 | } | |
494 | ||
495 | static void ath10k_ahb_release_irq_legacy(struct ath10k *ar) | |
496 | { | |
497 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
498 | ||
499 | free_irq(ar_ahb->irq, ar); | |
500 | } | |
501 | ||
502 | static void ath10k_ahb_irq_disable(struct ath10k *ar) | |
503 | { | |
504 | ath10k_ce_disable_interrupts(ar); | |
505 | ath10k_pci_disable_and_clear_legacy_irq(ar); | |
506 | } | |
507 | ||
704dc4e3 RM |
508 | static int ath10k_ahb_resource_init(struct ath10k *ar) |
509 | { | |
510 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
511 | struct platform_device *pdev; | |
512 | struct device *dev; | |
513 | struct resource *res; | |
514 | int ret; | |
515 | ||
516 | pdev = ar_ahb->pdev; | |
517 | dev = &pdev->dev; | |
518 | ||
519 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
520 | if (!res) { | |
521 | ath10k_err(ar, "failed to get memory resource\n"); | |
522 | ret = -ENXIO; | |
523 | goto out; | |
524 | } | |
525 | ||
526 | ar_ahb->mem = devm_ioremap_resource(&pdev->dev, res); | |
527 | if (IS_ERR(ar_ahb->mem)) { | |
528 | ath10k_err(ar, "mem ioremap error\n"); | |
529 | ret = PTR_ERR(ar_ahb->mem); | |
530 | goto out; | |
531 | } | |
532 | ||
533 | ar_ahb->mem_len = resource_size(res); | |
534 | ||
535 | ar_ahb->gcc_mem = ioremap_nocache(ATH10K_GCC_REG_BASE, | |
536 | ATH10K_GCC_REG_SIZE); | |
537 | if (!ar_ahb->gcc_mem) { | |
538 | ath10k_err(ar, "gcc mem ioremap error\n"); | |
539 | ret = -ENOMEM; | |
540 | goto err_mem_unmap; | |
541 | } | |
542 | ||
543 | ar_ahb->tcsr_mem = ioremap_nocache(ATH10K_TCSR_REG_BASE, | |
544 | ATH10K_TCSR_REG_SIZE); | |
545 | if (!ar_ahb->tcsr_mem) { | |
546 | ath10k_err(ar, "tcsr mem ioremap error\n"); | |
547 | ret = -ENOMEM; | |
548 | goto err_gcc_mem_unmap; | |
549 | } | |
550 | ||
551 | ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); | |
552 | if (ret) { | |
553 | ath10k_err(ar, "failed to set 32-bit dma mask: %d\n", ret); | |
554 | goto err_tcsr_mem_unmap; | |
555 | } | |
556 | ||
557 | ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); | |
558 | if (ret) { | |
559 | ath10k_err(ar, "failed to set 32-bit consistent dma: %d\n", | |
560 | ret); | |
561 | goto err_tcsr_mem_unmap; | |
562 | } | |
563 | ||
564 | ret = ath10k_ahb_clock_init(ar); | |
565 | if (ret) | |
566 | goto err_tcsr_mem_unmap; | |
567 | ||
568 | ret = ath10k_ahb_rst_ctrl_init(ar); | |
569 | if (ret) | |
570 | goto err_clock_deinit; | |
571 | ||
572 | ar_ahb->irq = platform_get_irq_byname(pdev, "legacy"); | |
573 | if (ar_ahb->irq < 0) { | |
574 | ath10k_err(ar, "failed to get irq number: %d\n", ar_ahb->irq); | |
575 | goto err_clock_deinit; | |
576 | } | |
577 | ||
578 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "irq: %d\n", ar_ahb->irq); | |
579 | ||
580 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "mem: 0x%p mem_len: %lu gcc mem: 0x%p tcsr_mem: 0x%p\n", | |
581 | ar_ahb->mem, ar_ahb->mem_len, | |
582 | ar_ahb->gcc_mem, ar_ahb->tcsr_mem); | |
583 | return 0; | |
584 | ||
585 | err_clock_deinit: | |
586 | ath10k_ahb_clock_deinit(ar); | |
587 | ||
588 | err_tcsr_mem_unmap: | |
589 | iounmap(ar_ahb->tcsr_mem); | |
590 | ||
591 | err_gcc_mem_unmap: | |
592 | ar_ahb->tcsr_mem = NULL; | |
593 | iounmap(ar_ahb->gcc_mem); | |
594 | ||
595 | err_mem_unmap: | |
596 | ar_ahb->gcc_mem = NULL; | |
597 | devm_iounmap(&pdev->dev, ar_ahb->mem); | |
598 | ||
599 | out: | |
600 | ar_ahb->mem = NULL; | |
601 | return ret; | |
602 | } | |
603 | ||
604 | static void ath10k_ahb_resource_deinit(struct ath10k *ar) | |
605 | { | |
606 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
607 | struct device *dev; | |
608 | ||
609 | dev = &ar_ahb->pdev->dev; | |
610 | ||
611 | if (ar_ahb->mem) | |
612 | devm_iounmap(dev, ar_ahb->mem); | |
613 | ||
614 | if (ar_ahb->gcc_mem) | |
615 | iounmap(ar_ahb->gcc_mem); | |
616 | ||
617 | if (ar_ahb->tcsr_mem) | |
618 | iounmap(ar_ahb->tcsr_mem); | |
619 | ||
620 | ar_ahb->mem = NULL; | |
621 | ar_ahb->gcc_mem = NULL; | |
622 | ar_ahb->tcsr_mem = NULL; | |
623 | ||
624 | ath10k_ahb_clock_deinit(ar); | |
625 | ath10k_ahb_rst_ctrl_deinit(ar); | |
626 | } | |
627 | ||
0d87c920 RM |
628 | static int ath10k_ahb_prepare_device(struct ath10k *ar) |
629 | { | |
630 | u32 val; | |
631 | int ret; | |
632 | ||
633 | ret = ath10k_ahb_clock_enable(ar); | |
634 | if (ret) { | |
635 | ath10k_err(ar, "failed to enable clocks\n"); | |
636 | return ret; | |
637 | } | |
638 | ||
639 | /* Clock for the target is supplied from outside of target (ie, | |
640 | * external clock module controlled by the host). Target needs | |
641 | * to know what frequency target cpu is configured which is needed | |
642 | * for target internal use. Read target cpu frequency info from | |
643 | * gcc register and write into target's scratch register where | |
644 | * target expects this information. | |
645 | */ | |
646 | val = ath10k_ahb_gcc_read32(ar, ATH10K_AHB_GCC_FEPLL_PLL_DIV); | |
647 | ath10k_ahb_write32(ar, ATH10K_AHB_WIFI_SCRATCH_5_REG, val); | |
648 | ||
649 | ret = ath10k_ahb_release_reset(ar); | |
650 | if (ret) | |
651 | goto err_clk_disable; | |
652 | ||
653 | ath10k_ahb_irq_disable(ar); | |
654 | ||
655 | ath10k_ahb_write32(ar, FW_INDICATOR_ADDRESS, FW_IND_HOST_READY); | |
656 | ||
657 | ret = ath10k_pci_wait_for_target_init(ar); | |
658 | if (ret) | |
659 | goto err_halt_chip; | |
660 | ||
661 | return 0; | |
662 | ||
663 | err_halt_chip: | |
664 | ath10k_ahb_halt_chip(ar); | |
665 | ||
666 | err_clk_disable: | |
667 | ath10k_ahb_clock_disable(ar); | |
668 | ||
669 | return ret; | |
670 | } | |
671 | ||
672 | static int ath10k_ahb_chip_reset(struct ath10k *ar) | |
673 | { | |
674 | int ret; | |
675 | ||
676 | ath10k_ahb_halt_chip(ar); | |
677 | ath10k_ahb_clock_disable(ar); | |
678 | ||
679 | ret = ath10k_ahb_prepare_device(ar); | |
680 | if (ret) | |
681 | return ret; | |
682 | ||
683 | return 0; | |
684 | } | |
685 | ||
686 | static int ath10k_ahb_wake_target_cpu(struct ath10k *ar) | |
687 | { | |
688 | u32 addr, val; | |
689 | ||
690 | addr = SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS; | |
691 | val = ath10k_ahb_read32(ar, addr); | |
692 | val |= ATH10K_AHB_CORE_CTRL_CPU_INTR_MASK; | |
693 | ath10k_ahb_write32(ar, addr, val); | |
694 | ||
695 | return 0; | |
696 | } | |
697 | ||
698 | static int ath10k_ahb_hif_start(struct ath10k *ar) | |
699 | { | |
700 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif start\n"); | |
701 | ||
702 | ath10k_ce_enable_interrupts(ar); | |
703 | ath10k_pci_enable_legacy_irq(ar); | |
704 | ||
705 | ath10k_pci_rx_post(ar); | |
706 | ||
707 | return 0; | |
708 | } | |
709 | ||
710 | static void ath10k_ahb_hif_stop(struct ath10k *ar) | |
711 | { | |
712 | struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar); | |
713 | ||
714 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif stop\n"); | |
715 | ||
716 | ath10k_ahb_irq_disable(ar); | |
717 | synchronize_irq(ar_ahb->irq); | |
718 | ||
719 | ath10k_pci_flush(ar); | |
720 | } | |
721 | ||
722 | static int ath10k_ahb_hif_power_up(struct ath10k *ar) | |
723 | { | |
724 | int ret; | |
725 | ||
726 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif power up\n"); | |
727 | ||
728 | ret = ath10k_ahb_chip_reset(ar); | |
729 | if (ret) { | |
730 | ath10k_err(ar, "failed to reset chip: %d\n", ret); | |
731 | goto out; | |
732 | } | |
733 | ||
734 | ret = ath10k_pci_init_pipes(ar); | |
735 | if (ret) { | |
736 | ath10k_err(ar, "failed to initialize CE: %d\n", ret); | |
737 | goto out; | |
738 | } | |
739 | ||
740 | ret = ath10k_pci_init_config(ar); | |
741 | if (ret) { | |
742 | ath10k_err(ar, "failed to setup init config: %d\n", ret); | |
743 | goto err_ce_deinit; | |
744 | } | |
745 | ||
746 | ret = ath10k_ahb_wake_target_cpu(ar); | |
747 | if (ret) { | |
748 | ath10k_err(ar, "could not wake up target CPU: %d\n", ret); | |
749 | goto err_ce_deinit; | |
750 | } | |
751 | ||
752 | return 0; | |
753 | ||
754 | err_ce_deinit: | |
755 | ath10k_pci_ce_deinit(ar); | |
756 | out: | |
757 | return ret; | |
758 | } | |
759 | ||
760 | static const struct ath10k_hif_ops ath10k_ahb_hif_ops = { | |
761 | .tx_sg = ath10k_pci_hif_tx_sg, | |
762 | .diag_read = ath10k_pci_hif_diag_read, | |
763 | .diag_write = ath10k_pci_diag_write_mem, | |
764 | .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, | |
765 | .start = ath10k_ahb_hif_start, | |
766 | .stop = ath10k_ahb_hif_stop, | |
767 | .map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe, | |
768 | .get_default_pipe = ath10k_pci_hif_get_default_pipe, | |
769 | .send_complete_check = ath10k_pci_hif_send_complete_check, | |
770 | .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, | |
771 | .power_up = ath10k_ahb_hif_power_up, | |
772 | .power_down = ath10k_pci_hif_power_down, | |
773 | .read32 = ath10k_ahb_read32, | |
774 | .write32 = ath10k_ahb_write32, | |
775 | }; | |
776 | ||
777 | static const struct ath10k_bus_ops ath10k_ahb_bus_ops = { | |
778 | .read32 = ath10k_ahb_read32, | |
779 | .write32 = ath10k_ahb_write32, | |
780 | .get_num_banks = ath10k_ahb_get_num_banks, | |
781 | }; | |
782 | ||
0b523ced RM |
783 | static int ath10k_ahb_probe(struct platform_device *pdev) |
784 | { | |
0d87c920 RM |
785 | struct ath10k *ar; |
786 | struct ath10k_ahb *ar_ahb; | |
787 | struct ath10k_pci *ar_pci; | |
788 | const struct of_device_id *of_id; | |
789 | enum ath10k_hw_rev hw_rev; | |
790 | size_t size; | |
791 | int ret; | |
792 | u32 chip_id; | |
793 | ||
794 | of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev); | |
795 | if (!of_id) { | |
796 | dev_err(&pdev->dev, "failed to find matching device tree id\n"); | |
797 | return -EINVAL; | |
798 | } | |
799 | ||
800 | hw_rev = (enum ath10k_hw_rev)of_id->data; | |
801 | ||
802 | size = sizeof(*ar_pci) + sizeof(*ar_ahb); | |
803 | ar = ath10k_core_create(size, &pdev->dev, ATH10K_BUS_AHB, | |
804 | hw_rev, &ath10k_ahb_hif_ops); | |
805 | if (!ar) { | |
806 | dev_err(&pdev->dev, "failed to allocate core\n"); | |
807 | return -ENOMEM; | |
808 | } | |
809 | ||
810 | ath10k_dbg(ar, ATH10K_DBG_BOOT, "ahb probe\n"); | |
811 | ||
812 | ar_pci = ath10k_pci_priv(ar); | |
813 | ar_ahb = ath10k_ahb_priv(ar); | |
814 | ||
815 | ar_ahb->pdev = pdev; | |
816 | platform_set_drvdata(pdev, ar); | |
817 | ||
818 | ret = ath10k_ahb_resource_init(ar); | |
819 | if (ret) | |
820 | goto err_core_destroy; | |
821 | ||
822 | ar->dev_id = 0; | |
823 | ar_pci->mem = ar_ahb->mem; | |
824 | ar_pci->mem_len = ar_ahb->mem_len; | |
825 | ar_pci->ar = ar; | |
826 | ar_pci->bus_ops = &ath10k_ahb_bus_ops; | |
827 | ||
828 | ret = ath10k_pci_setup_resource(ar); | |
829 | if (ret) { | |
830 | ath10k_err(ar, "failed to setup resource: %d\n", ret); | |
831 | goto err_resource_deinit; | |
832 | } | |
833 | ||
834 | ath10k_pci_init_irq_tasklets(ar); | |
835 | ||
836 | ret = ath10k_ahb_request_irq_legacy(ar); | |
837 | if (ret) | |
838 | goto err_free_pipes; | |
839 | ||
840 | ret = ath10k_ahb_prepare_device(ar); | |
841 | if (ret) | |
842 | goto err_free_irq; | |
843 | ||
844 | ath10k_pci_ce_deinit(ar); | |
845 | ||
846 | chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS); | |
847 | if (chip_id == 0xffffffff) { | |
848 | ath10k_err(ar, "failed to get chip id\n"); | |
849 | goto err_halt_device; | |
850 | } | |
851 | ||
852 | ret = ath10k_core_register(ar, chip_id); | |
853 | if (ret) { | |
854 | ath10k_err(ar, "failed to register driver core: %d\n", ret); | |
855 | goto err_halt_device; | |
856 | } | |
857 | ||
0b523ced | 858 | return 0; |
0d87c920 RM |
859 | |
860 | err_halt_device: | |
861 | ath10k_ahb_halt_chip(ar); | |
862 | ath10k_ahb_clock_disable(ar); | |
863 | ||
864 | err_free_irq: | |
865 | ath10k_ahb_release_irq_legacy(ar); | |
866 | ||
867 | err_free_pipes: | |
868 | ath10k_pci_free_pipes(ar); | |
869 | ||
870 | err_resource_deinit: | |
871 | ath10k_ahb_resource_deinit(ar); | |
872 | ||
873 | err_core_destroy: | |
874 | ath10k_core_destroy(ar); | |
875 | platform_set_drvdata(pdev, NULL); | |
876 | ||
877 | return ret; | |
0b523ced RM |
878 | } |
879 | ||
880 | static int ath10k_ahb_remove(struct platform_device *pdev) | |
881 | { | |
0d87c920 RM |
882 | struct ath10k *ar = platform_get_drvdata(pdev); |
883 | struct ath10k_ahb *ar_ahb; | |
884 | ||
885 | if (!ar) | |
886 | return -EINVAL; | |
887 | ||
888 | ar_ahb = ath10k_ahb_priv(ar); | |
889 | ||
890 | if (!ar_ahb) | |
891 | return -EINVAL; | |
892 | ||
893 | ath10k_dbg(ar, ATH10K_DBG_AHB, "ahb remove\n"); | |
894 | ||
895 | ath10k_core_unregister(ar); | |
896 | ath10k_ahb_irq_disable(ar); | |
897 | ath10k_ahb_release_irq_legacy(ar); | |
898 | ath10k_pci_release_resource(ar); | |
899 | ath10k_ahb_halt_chip(ar); | |
900 | ath10k_ahb_clock_disable(ar); | |
901 | ath10k_ahb_resource_deinit(ar); | |
902 | ath10k_core_destroy(ar); | |
903 | ||
904 | platform_set_drvdata(pdev, NULL); | |
905 | ||
0b523ced RM |
906 | return 0; |
907 | } | |
908 | ||
909 | static struct platform_driver ath10k_ahb_driver = { | |
910 | .driver = { | |
911 | .name = "ath10k_ahb", | |
912 | .of_match_table = ath10k_ahb_of_match, | |
913 | }, | |
914 | .probe = ath10k_ahb_probe, | |
915 | .remove = ath10k_ahb_remove, | |
916 | }; | |
917 | ||
918 | int ath10k_ahb_init(void) | |
919 | { | |
920 | int ret; | |
921 | ||
0b523ced RM |
922 | ret = platform_driver_register(&ath10k_ahb_driver); |
923 | if (ret) | |
924 | printk(KERN_ERR "failed to register ath10k ahb driver: %d\n", | |
925 | ret); | |
926 | return ret; | |
927 | } | |
928 | ||
929 | void ath10k_ahb_exit(void) | |
930 | { | |
931 | platform_driver_unregister(&ath10k_ahb_driver); | |
932 | } |