blob: 3139b6026bb7478f0b6aef0802f67d2947cb9d27 [file] [log] [blame]
Yuanyuan Liud9f7a362016-01-22 14:27:12 -08001/*
Ajit Pal Singh5e618aa2018-12-20 17:47:36 +05302 * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
Yuanyuan Liud9f7a362016-01-22 14:27:12 -08003 *
Yuanyuan Liud9f7a362016-01-22 14:27:12 -08004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all
7 * copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16 * PERFORMANCE OF THIS SOFTWARE.
17 */
18
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080019#include <linux/platform_device.h>
20#include <linux/err.h>
21#include <linux/pci.h>
22#include <linux/list.h>
23#include <linux/slab.h>
24
Yuanyuan Liu11f526a2016-05-18 10:22:07 -070025#ifdef CONFIG_PLD_PCIE_CNSS
Yue Mae6a7a322016-08-31 11:09:23 -070026#include <net/cnss2.h>
27#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080028
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080029#include "pld_internal.h"
Jeff Johnsonbbaf4e42016-10-07 12:33:22 -070030#include "pld_pcie.h"
Nirav Shah942cdf62019-09-25 00:02:54 +053031#include "osif_psoc_sync.h"
Tiger Yudb568a82019-12-20 19:10:30 +080032#include <cds_api.h>
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080033
34#ifdef CONFIG_PCI
35
36#ifdef QCA_WIFI_3_0_ADRASTEA
37#define CE_COUNT_MAX 12
38#else
39#define CE_COUNT_MAX 8
40#endif
41
42/**
43 * pld_pcie_probe() - Probe function for PCIE platform driver
44 * @pdev: PCIE device
45 * @id: PCIE device ID table
46 *
47 * The probe function will be called when PCIE device provided
48 * in the ID table is detected.
49 *
50 * Return: int
51 */
52static int pld_pcie_probe(struct pci_dev *pdev,
53 const struct pci_device_id *id)
54{
55 struct pld_context *pld_context;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080056 int ret = 0;
57
58 pld_context = pld_get_global_context();
59 if (!pld_context) {
60 ret = -ENODEV;
61 goto out;
62 }
63
Ajit Pal Singh5e618aa2018-12-20 17:47:36 +053064 ret = pld_add_dev(pld_context, &pdev->dev, NULL, PLD_BUS_TYPE_PCIE);
Yuanyuan Liu5e25f532016-05-25 16:26:40 -070065 if (ret)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080066 goto out;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080067
68 return pld_context->ops->probe(&pdev->dev,
69 PLD_BUS_TYPE_PCIE, pdev, (void *)id);
70
71out:
72 return ret;
73}
74
75
76/**
77 * pld_pcie_remove() - Remove function for PCIE device
78 * @pdev: PCIE device
79 *
80 * The remove function will be called when PCIE device is disconnected
81 *
82 * Return: void
83 */
84static void pld_pcie_remove(struct pci_dev *pdev)
85{
86 struct pld_context *pld_context;
Nirav Shah942cdf62019-09-25 00:02:54 +053087 int errno;
88 struct osif_psoc_sync *psoc_sync;
89
90 errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync);
91 if (errno)
92 return;
93
94 osif_psoc_sync_unregister(&pdev->dev);
Tiger Yudb568a82019-12-20 19:10:30 +080095
96 cds_set_driver_loaded(false);
97 cds_set_unload_in_progress(true);
98
Nirav Shah942cdf62019-09-25 00:02:54 +053099 osif_psoc_sync_wait_for_ops(psoc_sync);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800100
101 pld_context = pld_get_global_context();
102
103 if (!pld_context)
Nirav Shah942cdf62019-09-25 00:02:54 +0530104 goto out;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800105
Yuanyuan Liu960fa212016-05-24 17:15:43 -0700106 pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE);
107
Yuanyuan Liu5e25f532016-05-25 16:26:40 -0700108 pld_del_dev(pld_context, &pdev->dev);
Nirav Shah942cdf62019-09-25 00:02:54 +0530109
110out:
111 osif_psoc_sync_trans_stop(psoc_sync);
112 osif_psoc_sync_destroy(psoc_sync);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800113}
114
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700115#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800116/**
Rajeev Kumar588a2542019-04-08 10:57:19 -0700117 * pld_pcie_idle_restart_cb() - Perform idle restart
118 * @pdev: PCIE device
119 * @id: PCIE device ID
120 *
121 * This function will be called if there is an idle restart request
122 *
123 * Return: int
124 */
125static int pld_pcie_idle_restart_cb(struct pci_dev *pdev,
126 const struct pci_device_id *id)
127{
128 struct pld_context *pld_context;
129
130 pld_context = pld_get_global_context();
131 if (pld_context->ops->idle_restart)
132 return pld_context->ops->idle_restart(&pdev->dev,
133 PLD_BUS_TYPE_PCIE);
134
135 return -ENODEV;
136}
137
138/**
139 * pld_pcie_idle_shutdown_cb() - Perform idle shutdown
140 * @pdev: PCIE device
141 * @id: PCIE device ID
142 *
143 * This function will be called if there is an idle shutdown request
144 *
145 * Return: int
146 */
147static int pld_pcie_idle_shutdown_cb(struct pci_dev *pdev)
148{
149 struct pld_context *pld_context;
150
151 pld_context = pld_get_global_context();
152 if (pld_context->ops->shutdown)
153 return pld_context->ops->idle_shutdown(&pdev->dev,
154 PLD_BUS_TYPE_PCIE);
155
156 return -ENODEV;
157}
158
159/**
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800160 * pld_pcie_reinit() - SSR re-initialize function for PCIE device
161 * @pdev: PCIE device
162 * @id: PCIE device ID
163 *
164 * During subsystem restart(SSR), this function will be called to
165 * re-initialize PCIE device.
166 *
167 * Return: int
168 */
169static int pld_pcie_reinit(struct pci_dev *pdev,
170 const struct pci_device_id *id)
171{
172 struct pld_context *pld_context;
173
174 pld_context = pld_get_global_context();
175 if (pld_context->ops->reinit)
176 return pld_context->ops->reinit(&pdev->dev,
177 PLD_BUS_TYPE_PCIE, pdev, (void *)id);
178
179 return -ENODEV;
180}
181
182/**
183 * pld_pcie_shutdown() - SSR shutdown function for PCIE device
184 * @pdev: PCIE device
185 *
186 * During SSR, this function will be called to shutdown PCIE device.
187 *
188 * Return: void
189 */
190static void pld_pcie_shutdown(struct pci_dev *pdev)
191{
192 struct pld_context *pld_context;
193
194 pld_context = pld_get_global_context();
195 if (pld_context->ops->shutdown)
196 pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
197}
198
199/**
200 * pld_pcie_crash_shutdown() - Crash shutdown function for PCIE device
201 * @pdev: PCIE device
202 *
203 * This function will be called when a crash is detected, it will shutdown
204 * the PCIE device.
205 *
206 * Return: void
207 */
208static void pld_pcie_crash_shutdown(struct pci_dev *pdev)
209{
210 struct pld_context *pld_context;
211
212 pld_context = pld_get_global_context();
213 if (pld_context->ops->crash_shutdown)
214 pld_context->ops->crash_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
215}
216
217/**
218 * pld_pcie_notify_handler() - Modem state notification callback function
219 * @pdev: PCIE device
220 * @state: modem power state
221 *
222 * This function will be called when there's a modem power state change.
223 *
224 * Return: void
225 */
226static void pld_pcie_notify_handler(struct pci_dev *pdev, int state)
227{
228 struct pld_context *pld_context;
229
230 pld_context = pld_get_global_context();
231 if (pld_context->ops->modem_status)
232 pld_context->ops->modem_status(&pdev->dev,
233 PLD_BUS_TYPE_PCIE, state);
234}
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700235
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800236/**
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530237 * pld_pcie_uevent() - update wlan driver status callback function
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800238 * @pdev: PCIE device
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530239 * @status driver uevent status
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800240 *
241 * This function will be called when platform driver wants to update wlan
242 * driver's status.
243 *
244 * Return: void
245 */
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530246static void pld_pcie_uevent(struct pci_dev *pdev, uint32_t status)
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800247{
248 struct pld_context *pld_context;
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530249 struct pld_uevent_data data;
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800250
251 pld_context = pld_get_global_context();
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530252 if (!pld_context)
253 return;
254
Yue Ma096189d2017-09-13 11:14:59 -0700255 switch (status) {
256 case CNSS_RECOVERY:
Dustin Brown8f05f652018-10-25 15:17:30 -0700257 data.uevent = PLD_FW_RECOVERY_START;
Yue Ma096189d2017-09-13 11:14:59 -0700258 break;
Arunk Khandavallif9957c02018-10-24 16:51:14 +0530259 case CNSS_FW_DOWN:
260 data.uevent = PLD_FW_DOWN;
261 break;
Yue Ma096189d2017-09-13 11:14:59 -0700262 default:
263 goto out;
264 }
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530265
Will Huangbdd28712017-06-21 11:02:39 +0800266 if (pld_context->ops->uevent)
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530267 pld_context->ops->uevent(&pdev->dev, &data);
268
Yue Ma096189d2017-09-13 11:14:59 -0700269out:
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530270 return;
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800271}
272
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700273#ifdef FEATURE_RUNTIME_PM
274/**
275 * pld_pcie_runtime_suspend() - PM runtime suspend
276 * @pdev: PCIE device
277 *
278 * PM runtime suspend callback function.
279 *
280 * Return: int
281 */
282static int pld_pcie_runtime_suspend(struct pci_dev *pdev)
283{
284 struct pld_context *pld_context;
285
286 pld_context = pld_get_global_context();
287 if (pld_context->ops->runtime_suspend)
288 return pld_context->ops->runtime_suspend(&pdev->dev,
289 PLD_BUS_TYPE_PCIE);
290
291 return -ENODEV;
292}
293
294/**
295 * pld_pcie_runtime_resume() - PM runtime resume
296 * @pdev: PCIE device
297 *
298 * PM runtime resume callback function.
299 *
300 * Return: int
301 */
302static int pld_pcie_runtime_resume(struct pci_dev *pdev)
303{
304 struct pld_context *pld_context;
305
306 pld_context = pld_get_global_context();
307 if (pld_context->ops->runtime_resume)
308 return pld_context->ops->runtime_resume(&pdev->dev,
309 PLD_BUS_TYPE_PCIE);
310
311 return -ENODEV;
312}
313#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800314#endif
315
Yuanyuan Liu25c66e12016-05-13 10:17:46 -0700316#ifdef CONFIG_PM
Yue Ma52d355c2017-01-25 14:49:23 -0800317#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800318/**
319 * pld_pcie_suspend() - Suspend callback function for power management
320 * @pdev: PCIE device
321 * @state: power state
322 *
323 * This function is to suspend the PCIE device when power management is
324 * enabled.
325 *
326 * Return: void
327 */
328static int pld_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
329{
330 struct pld_context *pld_context;
331
332 pld_context = pld_get_global_context();
333 return pld_context->ops->suspend(&pdev->dev,
334 PLD_BUS_TYPE_PCIE, state);
335}
336
337/**
338 * pld_pcie_resume() - Resume callback function for power management
339 * @pdev: PCIE device
340 *
341 * This function is to resume the PCIE device when power management is
342 * enabled.
343 *
344 * Return: void
345 */
346static int pld_pcie_resume(struct pci_dev *pdev)
347{
348 struct pld_context *pld_context;
349
350 pld_context = pld_get_global_context();
351 return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_PCIE);
352}
Yue Mae42c8452017-01-06 17:28:28 -0800353
354/**
355 * pld_pcie_suspend_noirq() - Complete the actions started by suspend()
356 * @pdev: PCI device
357 *
358 * Complete the actions started by suspend(). Carry out any additional
359 * operations required for suspending the device that might be racing
360 * with its driver's interrupt handler, which is guaranteed not to run
361 * while suspend_noirq() is being executed.
362 *
363 * Return: 0 for success
364 * Non zero failure code for errors
365 */
366static int pld_pcie_suspend_noirq(struct pci_dev *pdev)
367{
368 struct pld_context *pld_context;
369
370 pld_context = pld_get_global_context();
371 if (!pld_context)
372 return -EINVAL;
373
374 if (pld_context->ops->suspend_noirq)
375 return pld_context->ops->
376 suspend_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
377 return 0;
378}
379
380/**
381 * pld_pcie_resume_noirq() - Prepare for the execution of resume()
382 * @pdev: PCI device
383 *
384 * Prepare for the execution of resume() by carrying out any additional
385 * operations required for resuming the device that might be racing with
386 * its driver's interrupt handler, which is guaranteed not to run while
387 * resume_noirq() is being executed.
388 *
389 * Return: 0 for success
390 * Non zero failure code for errors
391 */
392static int pld_pcie_resume_noirq(struct pci_dev *pdev)
393{
394 struct pld_context *pld_context;
395
396 pld_context = pld_get_global_context();
397 if (!pld_context)
398 return -EINVAL;
399
400 if (pld_context->ops->resume_noirq)
401 return pld_context->ops->
402 resume_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
403 return 0;
404}
Yue Ma52d355c2017-01-25 14:49:23 -0800405#else
406/**
407 * pld_pcie_pm_suspend() - Suspend callback function for power management
408 * @dev: device
409 *
410 * This function is to suspend the PCIE device when power management is
411 * enabled.
412 *
413 * Return: 0 for success
414 * Non zero failure code for errors
415 */
416static int pld_pcie_pm_suspend(struct device *dev)
417{
418 struct pld_context *pld_context;
419
420 pm_message_t state = { .event = PM_EVENT_SUSPEND };
421
422 pld_context = pld_get_global_context();
423 return pld_context->ops->suspend(dev, PLD_BUS_TYPE_PCIE, state);
424}
425
426/**
427 * pld_pcie_pm_resume() - Resume callback function for power management
428 * @dev: device
429 *
430 * This function is to resume the PCIE device when power management is
431 * enabled.
432 *
433 * Return: 0 for success
434 * Non zero failure code for errors
435 */
436static int pld_pcie_pm_resume(struct device *dev)
437{
438 struct pld_context *pld_context;
439
440 pld_context = pld_get_global_context();
441 return pld_context->ops->resume(dev, PLD_BUS_TYPE_PCIE);
442}
443
444/**
445 * pld_pcie_pm_suspend_noirq() - Complete the actions started by suspend()
446 * @dev: device
447 *
448 * Complete the actions started by suspend(). Carry out any additional
449 * operations required for suspending the device that might be racing
450 * with its driver's interrupt handler, which is guaranteed not to run
451 * while suspend_noirq() is being executed.
452 *
453 * Return: 0 for success
454 * Non zero failure code for errors
455 */
456static int pld_pcie_pm_suspend_noirq(struct device *dev)
457{
458 struct pld_context *pld_context;
459
460 pld_context = pld_get_global_context();
461 if (!pld_context)
462 return -EINVAL;
463
464 if (pld_context->ops->suspend_noirq)
465 return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_PCIE);
466 return 0;
467}
468
469/**
470 * pld_pcie_pm_resume_noirq() - Prepare for the execution of resume()
471 * @dev: device
472 *
473 * Prepare for the execution of resume() by carrying out any additional
474 * operations required for resuming the device that might be racing with
475 * its driver's interrupt handler, which is guaranteed not to run while
476 * resume_noirq() is being executed.
477 *
478 * Return: 0 for success
479 * Non zero failure code for errors
480 */
481static int pld_pcie_pm_resume_noirq(struct device *dev)
482{
483 struct pld_context *pld_context;
484
485 pld_context = pld_get_global_context();
486 if (!pld_context)
487 return -EINVAL;
488
489 if (pld_context->ops->resume_noirq)
490 return pld_context->ops->
491 resume_noirq(dev, PLD_BUS_TYPE_PCIE);
492 return 0;
493}
494#endif
Yuanyuan Liu25c66e12016-05-13 10:17:46 -0700495#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800496
497static struct pci_device_id pld_pcie_id_table[] = {
498 { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID },
499 { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID },
500 { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID },
501 { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID },
502 { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID },
503 { 0 }
504};
505
Manikandan Mohan04459b92018-02-23 16:32:48 -0800506#ifdef MULTI_IF_NAME
507#define PLD_PCIE_OPS_NAME "pld_pcie_" MULTI_IF_NAME
508#else
509#define PLD_PCIE_OPS_NAME "pld_pcie"
510#endif
511
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700512#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700513#ifdef FEATURE_RUNTIME_PM
514struct cnss_wlan_runtime_ops runtime_pm_ops = {
515 .runtime_suspend = pld_pcie_runtime_suspend,
516 .runtime_resume = pld_pcie_runtime_resume,
517};
518#endif
519
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800520struct cnss_wlan_driver pld_pcie_ops = {
Manikandan Mohan04459b92018-02-23 16:32:48 -0800521 .name = PLD_PCIE_OPS_NAME,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800522 .id_table = pld_pcie_id_table,
523 .probe = pld_pcie_probe,
524 .remove = pld_pcie_remove,
Rajeev Kumar588a2542019-04-08 10:57:19 -0700525 .idle_restart = pld_pcie_idle_restart_cb,
526 .idle_shutdown = pld_pcie_idle_shutdown_cb,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800527 .reinit = pld_pcie_reinit,
528 .shutdown = pld_pcie_shutdown,
529 .crash_shutdown = pld_pcie_crash_shutdown,
530 .modem_status = pld_pcie_notify_handler,
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530531 .update_status = pld_pcie_uevent,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800532#ifdef CONFIG_PM
533 .suspend = pld_pcie_suspend,
534 .resume = pld_pcie_resume,
Yue Mae42c8452017-01-06 17:28:28 -0800535 .suspend_noirq = pld_pcie_suspend_noirq,
536 .resume_noirq = pld_pcie_resume_noirq,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800537#endif
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700538#ifdef FEATURE_RUNTIME_PM
539 .runtime_ops = &runtime_pm_ops,
540#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800541};
542
543/**
544 * pld_pcie_register_driver() - Register PCIE device callback functions
545 *
546 * Return: int
547 */
548int pld_pcie_register_driver(void)
549{
550 return cnss_wlan_register_driver(&pld_pcie_ops);
551}
552
553/**
554 * pld_pcie_unregister_driver() - Unregister PCIE device callback functions
555 *
556 * Return: void
557 */
558void pld_pcie_unregister_driver(void)
559{
560 cnss_wlan_unregister_driver(&pld_pcie_ops);
561}
562#else
Yue Ma52d355c2017-01-25 14:49:23 -0800563#ifdef CONFIG_PM
564static const struct dev_pm_ops pld_pm_ops = {
565 SET_SYSTEM_SLEEP_PM_OPS(pld_pcie_pm_suspend, pld_pcie_pm_resume)
566 .suspend_noirq = pld_pcie_pm_suspend_noirq,
567 .resume_noirq = pld_pcie_pm_resume_noirq,
568};
569#endif
570
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800571struct pci_driver pld_pcie_ops = {
Manikandan Mohan04459b92018-02-23 16:32:48 -0800572 .name = PLD_PCIE_OPS_NAME,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800573 .id_table = pld_pcie_id_table,
574 .probe = pld_pcie_probe,
575 .remove = pld_pcie_remove,
Yue Ma52d355c2017-01-25 14:49:23 -0800576 .driver = {
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800577#ifdef CONFIG_PM
Yue Ma52d355c2017-01-25 14:49:23 -0800578 .pm = &pld_pm_ops,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800579#endif
Yue Ma52d355c2017-01-25 14:49:23 -0800580 },
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800581};
582
583int pld_pcie_register_driver(void)
584{
585 return pci_register_driver(&pld_pcie_ops);
586}
587
588void pld_pcie_unregister_driver(void)
589{
590 pci_unregister_driver(&pld_pcie_ops);
591}
592#endif
593
594/**
595 * pld_pcie_get_ce_id() - Get CE number for the provided IRQ
Yue Ma85761e62017-10-30 11:13:45 -0700596 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800597 * @irq: IRQ number
598 *
599 * Return: CE number
600 */
Yue Ma85761e62017-10-30 11:13:45 -0700601int pld_pcie_get_ce_id(struct device *dev, int irq)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800602{
603 int ce_id = irq - 100;
Manikandan Mohan8cf50612017-04-10 13:23:32 -0700604
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800605 if (ce_id < CE_COUNT_MAX && ce_id >= 0)
606 return ce_id;
607
608 return -EINVAL;
609}
610
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700611#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800612/**
613 * pld_pcie_wlan_enable() - Enable WLAN
Yue Ma85761e62017-10-30 11:13:45 -0700614 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800615 * @config: WLAN configuration data
616 * @mode: WLAN mode
617 * @host_version: host software version
618 *
619 * This function enables WLAN FW. It passed WLAN configuration data,
620 * WLAN mode and host software version to FW.
621 *
622 * Return: 0 for success
623 * Non zero failure code for errors
624 */
Yue Ma08047522016-11-08 18:53:26 -0800625int pld_pcie_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800626 enum pld_driver_mode mode, const char *host_version)
627{
628 struct cnss_wlan_enable_cfg cfg;
629 enum cnss_driver_mode cnss_mode;
630
631 cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
632 cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *)
633 config->ce_tgt_cfg;
634 cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
635 cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *)
636 config->ce_svc_cfg;
637 cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
638 cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *)
639 config->shadow_reg_cfg;
Yue Ma502a28f2017-01-03 16:38:44 -0800640 cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg;
641 cfg.shadow_reg_v2_cfg = (struct cnss_shadow_reg_v2_cfg *)
642 config->shadow_reg_v2_cfg;
Nirav Shaha6c6dc92018-07-09 16:26:02 +0530643 cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid;
644 if (config->rri_over_ddr_cfg_valid) {
645 cfg.rri_over_ddr_cfg.base_addr_low =
646 config->rri_over_ddr_cfg.base_addr_low;
647 cfg.rri_over_ddr_cfg.base_addr_high =
648 config->rri_over_ddr_cfg.base_addr_high;
649 }
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800650
651 switch (mode) {
652 case PLD_FTM:
653 cnss_mode = CNSS_FTM;
654 break;
655 case PLD_EPPING:
656 cnss_mode = CNSS_EPPING;
657 break;
658 default:
659 cnss_mode = CNSS_MISSION;
660 break;
661 }
Yue Ma08047522016-11-08 18:53:26 -0800662 return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800663}
664
665/**
666 * pld_pcie_wlan_disable() - Disable WLAN
Yue Ma85761e62017-10-30 11:13:45 -0700667 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800668 * @mode: WLAN mode
669 *
670 * This function disables WLAN FW. It passes WLAN mode to FW.
671 *
672 * Return: 0 for success
673 * Non zero failure code for errors
674 */
Yue Ma08047522016-11-08 18:53:26 -0800675int pld_pcie_wlan_disable(struct device *dev, enum pld_driver_mode mode)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800676{
Yue Ma08047522016-11-08 18:53:26 -0800677 return cnss_wlan_disable(dev, CNSS_OFF);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800678}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800679
680/**
681 * pld_pcie_get_fw_files_for_target() - Get FW file names
Yue Ma85761e62017-10-30 11:13:45 -0700682 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800683 * @pfw_files: buffer for FW file names
684 * @target_type: target type
685 * @target_version: target version
686 *
687 * Return target specific FW file names to the buffer.
688 *
689 * Return: 0 for success
690 * Non zero failure code for errors
691 */
Yue Ma85761e62017-10-30 11:13:45 -0700692int pld_pcie_get_fw_files_for_target(struct device *dev,
693 struct pld_fw_files *pfw_files,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800694 u32 target_type, u32 target_version)
695{
696 int ret = 0;
697 struct cnss_fw_files cnss_fw_files;
698
Jeff Johnson753f9d72019-03-18 13:41:04 -0700699 if (!pfw_files)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800700 return -ENODEV;
701
Yuanyuan Liu6a313dc2016-05-10 14:19:10 -0700702 memset(pfw_files, 0, sizeof(*pfw_files));
703
Yue Ma85761e62017-10-30 11:13:45 -0700704 ret = cnss_get_fw_files_for_target(dev, &cnss_fw_files,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800705 target_type, target_version);
Yue Ma85761e62017-10-30 11:13:45 -0700706 if (ret)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800707 return ret;
708
Qun Zhang4a83a462018-09-11 16:28:51 +0800709 scnprintf(pfw_files->image_file, PLD_MAX_FILE_NAME, PREFIX "%s",
710 cnss_fw_files.image_file);
711 scnprintf(pfw_files->board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
712 cnss_fw_files.board_data);
713 scnprintf(pfw_files->otp_data, PLD_MAX_FILE_NAME, PREFIX "%s",
714 cnss_fw_files.otp_data);
715 scnprintf(pfw_files->utf_file, PLD_MAX_FILE_NAME, PREFIX "%s",
716 cnss_fw_files.utf_file);
717 scnprintf(pfw_files->utf_board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
718 cnss_fw_files.utf_board_data);
719 scnprintf(pfw_files->epping_file, PLD_MAX_FILE_NAME, PREFIX "%s",
720 cnss_fw_files.epping_file);
721 scnprintf(pfw_files->evicted_data, PLD_MAX_FILE_NAME, PREFIX "%s",
722 cnss_fw_files.evicted_data);
Yuanyuan Liu6a313dc2016-05-10 14:19:10 -0700723
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800724 return 0;
725}
726
727/**
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800728 * pld_pcie_get_platform_cap() - Get platform capabilities
Yue Ma85761e62017-10-30 11:13:45 -0700729 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800730 * @cap: buffer to the capabilities
731 *
732 * Return capabilities to the buffer.
733 *
734 * Return: 0 for success
735 * Non zero failure code for errors
736 */
Yue Ma85761e62017-10-30 11:13:45 -0700737int pld_pcie_get_platform_cap(struct device *dev, struct pld_platform_cap *cap)
738{
739 int ret = 0;
740 struct cnss_platform_cap cnss_cap;
741
Jeff Johnson753f9d72019-03-18 13:41:04 -0700742 if (!cap)
Yue Ma85761e62017-10-30 11:13:45 -0700743 return -ENODEV;
744
745 ret = cnss_get_platform_cap(dev, &cnss_cap);
746 if (ret)
747 return ret;
748
749 memcpy(cap, &cnss_cap, sizeof(*cap));
750 return 0;
751}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800752
753/**
Yue Macd243862016-11-04 19:21:16 -0700754 * pld_pcie_get_soc_info() - Get SOC information
Yue Ma85761e62017-10-30 11:13:45 -0700755 * @dev: device
Yue Macd243862016-11-04 19:21:16 -0700756 * @info: buffer to SOC information
757 *
758 * Return SOC info to the buffer.
759 *
760 * Return: 0 for success
761 * Non zero failure code for errors
762 */
763int pld_pcie_get_soc_info(struct device *dev, struct pld_soc_info *info)
764{
765 int ret = 0;
lihual8b9daf22018-04-02 15:18:54 +0800766 struct cnss_soc_info cnss_info = {0};
Yue Macd243862016-11-04 19:21:16 -0700767
Jeff Johnson753f9d72019-03-18 13:41:04 -0700768 if (!info)
Yue Macd243862016-11-04 19:21:16 -0700769 return -ENODEV;
770
771 ret = cnss_get_soc_info(dev, &cnss_info);
772 if (ret)
773 return ret;
774
Frank Liu0e7ac562018-06-15 15:29:49 +0800775 info->v_addr = cnss_info.va;
776 info->p_addr = cnss_info.pa;
777 info->chip_id = cnss_info.chip_id;
778 info->chip_family = cnss_info.chip_family;
779 info->board_id = cnss_info.board_id;
780 info->soc_id = cnss_info.soc_id;
781 info->fw_version = cnss_info.fw_version;
782 strlcpy(info->fw_build_timestamp, cnss_info.fw_build_timestamp,
783 sizeof(info->fw_build_timestamp));
Yue Mab4ebd872019-04-17 14:55:59 -0700784 info->device_version.family_number =
785 cnss_info.device_version.family_number;
786 info->device_version.device_number =
787 cnss_info.device_version.device_number;
788 info->device_version.major_version =
789 cnss_info.device_version.major_version;
790 info->device_version.minor_version =
791 cnss_info.device_version.minor_version;
Yue Macd243862016-11-04 19:21:16 -0700792
793 return 0;
794}
795
796/**
Yuanyuan Liu10fc3d32017-01-12 15:32:06 -0800797 * pld_pcie_schedule_recovery_work() - schedule recovery work
798 * @dev: device
799 * @reason: recovery reason
800 *
801 * Return: void
802 */
803void pld_pcie_schedule_recovery_work(struct device *dev,
804 enum pld_recovery_reason reason)
805{
806 enum cnss_recovery_reason cnss_reason;
807
808 switch (reason) {
809 case PLD_REASON_LINK_DOWN:
810 cnss_reason = CNSS_REASON_LINK_DOWN;
811 break;
812 default:
813 cnss_reason = CNSS_REASON_DEFAULT;
814 break;
815 }
816 cnss_schedule_recovery(dev, cnss_reason);
817}
818
819/**
820 * pld_pcie_device_self_recovery() - device self recovery
821 * @dev: device
822 * @reason: recovery reason
823 *
824 * Return: void
825 */
826void pld_pcie_device_self_recovery(struct device *dev,
827 enum pld_recovery_reason reason)
828{
829 enum cnss_recovery_reason cnss_reason;
830
831 switch (reason) {
832 case PLD_REASON_LINK_DOWN:
833 cnss_reason = CNSS_REASON_LINK_DOWN;
834 break;
835 default:
836 cnss_reason = CNSS_REASON_DEFAULT;
837 break;
838 }
839 cnss_self_recovery(dev, cnss_reason);
840}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800841#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800842#endif