blob: c6b272c52ca3761dc43b3737de80a3e2ea426536 [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"
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080032
33#ifdef CONFIG_PCI
34
35#ifdef QCA_WIFI_3_0_ADRASTEA
36#define CE_COUNT_MAX 12
37#else
38#define CE_COUNT_MAX 8
39#endif
40
41/**
42 * pld_pcie_probe() - Probe function for PCIE platform driver
43 * @pdev: PCIE device
44 * @id: PCIE device ID table
45 *
46 * The probe function will be called when PCIE device provided
47 * in the ID table is detected.
48 *
49 * Return: int
50 */
51static int pld_pcie_probe(struct pci_dev *pdev,
52 const struct pci_device_id *id)
53{
54 struct pld_context *pld_context;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080055 int ret = 0;
56
57 pld_context = pld_get_global_context();
58 if (!pld_context) {
59 ret = -ENODEV;
60 goto out;
61 }
62
Ajit Pal Singh5e618aa2018-12-20 17:47:36 +053063 ret = pld_add_dev(pld_context, &pdev->dev, NULL, PLD_BUS_TYPE_PCIE);
Yuanyuan Liu5e25f532016-05-25 16:26:40 -070064 if (ret)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080065 goto out;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080066
67 return pld_context->ops->probe(&pdev->dev,
68 PLD_BUS_TYPE_PCIE, pdev, (void *)id);
69
70out:
71 return ret;
72}
73
74
75/**
76 * pld_pcie_remove() - Remove function for PCIE device
77 * @pdev: PCIE device
78 *
79 * The remove function will be called when PCIE device is disconnected
80 *
81 * Return: void
82 */
83static void pld_pcie_remove(struct pci_dev *pdev)
84{
85 struct pld_context *pld_context;
Nirav Shah942cdf62019-09-25 00:02:54 +053086 int errno;
87 struct osif_psoc_sync *psoc_sync;
88
89 errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync);
90 if (errno)
91 return;
92
93 osif_psoc_sync_unregister(&pdev->dev);
94 osif_psoc_sync_wait_for_ops(psoc_sync);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080095
96 pld_context = pld_get_global_context();
97
98 if (!pld_context)
Nirav Shah942cdf62019-09-25 00:02:54 +053099 goto out;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800100
Yuanyuan Liu960fa212016-05-24 17:15:43 -0700101 pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE);
102
Yuanyuan Liu5e25f532016-05-25 16:26:40 -0700103 pld_del_dev(pld_context, &pdev->dev);
Nirav Shah942cdf62019-09-25 00:02:54 +0530104
105out:
106 osif_psoc_sync_trans_stop(psoc_sync);
107 osif_psoc_sync_destroy(psoc_sync);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800108}
109
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700110#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800111/**
Rajeev Kumar588a2542019-04-08 10:57:19 -0700112 * pld_pcie_idle_restart_cb() - Perform idle restart
113 * @pdev: PCIE device
114 * @id: PCIE device ID
115 *
116 * This function will be called if there is an idle restart request
117 *
118 * Return: int
119 */
120static int pld_pcie_idle_restart_cb(struct pci_dev *pdev,
121 const struct pci_device_id *id)
122{
123 struct pld_context *pld_context;
124
125 pld_context = pld_get_global_context();
126 if (pld_context->ops->idle_restart)
127 return pld_context->ops->idle_restart(&pdev->dev,
128 PLD_BUS_TYPE_PCIE);
129
130 return -ENODEV;
131}
132
133/**
134 * pld_pcie_idle_shutdown_cb() - Perform idle shutdown
135 * @pdev: PCIE device
136 * @id: PCIE device ID
137 *
138 * This function will be called if there is an idle shutdown request
139 *
140 * Return: int
141 */
142static int pld_pcie_idle_shutdown_cb(struct pci_dev *pdev)
143{
144 struct pld_context *pld_context;
145
146 pld_context = pld_get_global_context();
147 if (pld_context->ops->shutdown)
148 return pld_context->ops->idle_shutdown(&pdev->dev,
149 PLD_BUS_TYPE_PCIE);
150
151 return -ENODEV;
152}
153
154/**
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800155 * pld_pcie_reinit() - SSR re-initialize function for PCIE device
156 * @pdev: PCIE device
157 * @id: PCIE device ID
158 *
159 * During subsystem restart(SSR), this function will be called to
160 * re-initialize PCIE device.
161 *
162 * Return: int
163 */
164static int pld_pcie_reinit(struct pci_dev *pdev,
165 const struct pci_device_id *id)
166{
167 struct pld_context *pld_context;
168
169 pld_context = pld_get_global_context();
170 if (pld_context->ops->reinit)
171 return pld_context->ops->reinit(&pdev->dev,
172 PLD_BUS_TYPE_PCIE, pdev, (void *)id);
173
174 return -ENODEV;
175}
176
177/**
178 * pld_pcie_shutdown() - SSR shutdown function for PCIE device
179 * @pdev: PCIE device
180 *
181 * During SSR, this function will be called to shutdown PCIE device.
182 *
183 * Return: void
184 */
185static void pld_pcie_shutdown(struct pci_dev *pdev)
186{
187 struct pld_context *pld_context;
188
189 pld_context = pld_get_global_context();
190 if (pld_context->ops->shutdown)
191 pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
192}
193
194/**
195 * pld_pcie_crash_shutdown() - Crash shutdown function for PCIE device
196 * @pdev: PCIE device
197 *
198 * This function will be called when a crash is detected, it will shutdown
199 * the PCIE device.
200 *
201 * Return: void
202 */
203static void pld_pcie_crash_shutdown(struct pci_dev *pdev)
204{
205 struct pld_context *pld_context;
206
207 pld_context = pld_get_global_context();
208 if (pld_context->ops->crash_shutdown)
209 pld_context->ops->crash_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
210}
211
212/**
213 * pld_pcie_notify_handler() - Modem state notification callback function
214 * @pdev: PCIE device
215 * @state: modem power state
216 *
217 * This function will be called when there's a modem power state change.
218 *
219 * Return: void
220 */
221static void pld_pcie_notify_handler(struct pci_dev *pdev, int state)
222{
223 struct pld_context *pld_context;
224
225 pld_context = pld_get_global_context();
226 if (pld_context->ops->modem_status)
227 pld_context->ops->modem_status(&pdev->dev,
228 PLD_BUS_TYPE_PCIE, state);
229}
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700230
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800231/**
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530232 * pld_pcie_uevent() - update wlan driver status callback function
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800233 * @pdev: PCIE device
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530234 * @status driver uevent status
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800235 *
236 * This function will be called when platform driver wants to update wlan
237 * driver's status.
238 *
239 * Return: void
240 */
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530241static void pld_pcie_uevent(struct pci_dev *pdev, uint32_t status)
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800242{
243 struct pld_context *pld_context;
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530244 struct pld_uevent_data data;
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800245
246 pld_context = pld_get_global_context();
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530247 if (!pld_context)
248 return;
249
Yue Ma096189d2017-09-13 11:14:59 -0700250 switch (status) {
251 case CNSS_RECOVERY:
Dustin Brown8f05f652018-10-25 15:17:30 -0700252 data.uevent = PLD_FW_RECOVERY_START;
Yue Ma096189d2017-09-13 11:14:59 -0700253 break;
Arunk Khandavallif9957c02018-10-24 16:51:14 +0530254 case CNSS_FW_DOWN:
255 data.uevent = PLD_FW_DOWN;
256 break;
Yue Ma096189d2017-09-13 11:14:59 -0700257 default:
258 goto out;
259 }
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530260
Will Huangbdd28712017-06-21 11:02:39 +0800261 if (pld_context->ops->uevent)
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530262 pld_context->ops->uevent(&pdev->dev, &data);
263
Yue Ma096189d2017-09-13 11:14:59 -0700264out:
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530265 return;
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800266}
267
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700268#ifdef FEATURE_RUNTIME_PM
269/**
270 * pld_pcie_runtime_suspend() - PM runtime suspend
271 * @pdev: PCIE device
272 *
273 * PM runtime suspend callback function.
274 *
275 * Return: int
276 */
277static int pld_pcie_runtime_suspend(struct pci_dev *pdev)
278{
279 struct pld_context *pld_context;
280
281 pld_context = pld_get_global_context();
282 if (pld_context->ops->runtime_suspend)
283 return pld_context->ops->runtime_suspend(&pdev->dev,
284 PLD_BUS_TYPE_PCIE);
285
286 return -ENODEV;
287}
288
289/**
290 * pld_pcie_runtime_resume() - PM runtime resume
291 * @pdev: PCIE device
292 *
293 * PM runtime resume callback function.
294 *
295 * Return: int
296 */
297static int pld_pcie_runtime_resume(struct pci_dev *pdev)
298{
299 struct pld_context *pld_context;
300
301 pld_context = pld_get_global_context();
302 if (pld_context->ops->runtime_resume)
303 return pld_context->ops->runtime_resume(&pdev->dev,
304 PLD_BUS_TYPE_PCIE);
305
306 return -ENODEV;
307}
308#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800309#endif
310
Yuanyuan Liu25c66e12016-05-13 10:17:46 -0700311#ifdef CONFIG_PM
Yue Ma52d355c2017-01-25 14:49:23 -0800312#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800313/**
314 * pld_pcie_suspend() - Suspend callback function for power management
315 * @pdev: PCIE device
316 * @state: power state
317 *
318 * This function is to suspend the PCIE device when power management is
319 * enabled.
320 *
321 * Return: void
322 */
323static int pld_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
324{
325 struct pld_context *pld_context;
326
327 pld_context = pld_get_global_context();
328 return pld_context->ops->suspend(&pdev->dev,
329 PLD_BUS_TYPE_PCIE, state);
330}
331
332/**
333 * pld_pcie_resume() - Resume callback function for power management
334 * @pdev: PCIE device
335 *
336 * This function is to resume the PCIE device when power management is
337 * enabled.
338 *
339 * Return: void
340 */
341static int pld_pcie_resume(struct pci_dev *pdev)
342{
343 struct pld_context *pld_context;
344
345 pld_context = pld_get_global_context();
346 return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_PCIE);
347}
Yue Mae42c8452017-01-06 17:28:28 -0800348
349/**
350 * pld_pcie_suspend_noirq() - Complete the actions started by suspend()
351 * @pdev: PCI device
352 *
353 * Complete the actions started by suspend(). Carry out any additional
354 * operations required for suspending the device that might be racing
355 * with its driver's interrupt handler, which is guaranteed not to run
356 * while suspend_noirq() is being executed.
357 *
358 * Return: 0 for success
359 * Non zero failure code for errors
360 */
361static int pld_pcie_suspend_noirq(struct pci_dev *pdev)
362{
363 struct pld_context *pld_context;
364
365 pld_context = pld_get_global_context();
366 if (!pld_context)
367 return -EINVAL;
368
369 if (pld_context->ops->suspend_noirq)
370 return pld_context->ops->
371 suspend_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
372 return 0;
373}
374
375/**
376 * pld_pcie_resume_noirq() - Prepare for the execution of resume()
377 * @pdev: PCI device
378 *
379 * Prepare for the execution of resume() by carrying out any additional
380 * operations required for resuming the device that might be racing with
381 * its driver's interrupt handler, which is guaranteed not to run while
382 * resume_noirq() is being executed.
383 *
384 * Return: 0 for success
385 * Non zero failure code for errors
386 */
387static int pld_pcie_resume_noirq(struct pci_dev *pdev)
388{
389 struct pld_context *pld_context;
390
391 pld_context = pld_get_global_context();
392 if (!pld_context)
393 return -EINVAL;
394
395 if (pld_context->ops->resume_noirq)
396 return pld_context->ops->
397 resume_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
398 return 0;
399}
Yue Ma52d355c2017-01-25 14:49:23 -0800400#else
401/**
402 * pld_pcie_pm_suspend() - Suspend callback function for power management
403 * @dev: device
404 *
405 * This function is to suspend the PCIE device when power management is
406 * enabled.
407 *
408 * Return: 0 for success
409 * Non zero failure code for errors
410 */
411static int pld_pcie_pm_suspend(struct device *dev)
412{
413 struct pld_context *pld_context;
414
415 pm_message_t state = { .event = PM_EVENT_SUSPEND };
416
417 pld_context = pld_get_global_context();
418 return pld_context->ops->suspend(dev, PLD_BUS_TYPE_PCIE, state);
419}
420
421/**
422 * pld_pcie_pm_resume() - Resume callback function for power management
423 * @dev: device
424 *
425 * This function is to resume the PCIE device when power management is
426 * enabled.
427 *
428 * Return: 0 for success
429 * Non zero failure code for errors
430 */
431static int pld_pcie_pm_resume(struct device *dev)
432{
433 struct pld_context *pld_context;
434
435 pld_context = pld_get_global_context();
436 return pld_context->ops->resume(dev, PLD_BUS_TYPE_PCIE);
437}
438
439/**
440 * pld_pcie_pm_suspend_noirq() - Complete the actions started by suspend()
441 * @dev: device
442 *
443 * Complete the actions started by suspend(). Carry out any additional
444 * operations required for suspending the device that might be racing
445 * with its driver's interrupt handler, which is guaranteed not to run
446 * while suspend_noirq() is being executed.
447 *
448 * Return: 0 for success
449 * Non zero failure code for errors
450 */
451static int pld_pcie_pm_suspend_noirq(struct device *dev)
452{
453 struct pld_context *pld_context;
454
455 pld_context = pld_get_global_context();
456 if (!pld_context)
457 return -EINVAL;
458
459 if (pld_context->ops->suspend_noirq)
460 return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_PCIE);
461 return 0;
462}
463
464/**
465 * pld_pcie_pm_resume_noirq() - Prepare for the execution of resume()
466 * @dev: device
467 *
468 * Prepare for the execution of resume() by carrying out any additional
469 * operations required for resuming the device that might be racing with
470 * its driver's interrupt handler, which is guaranteed not to run while
471 * resume_noirq() is being executed.
472 *
473 * Return: 0 for success
474 * Non zero failure code for errors
475 */
476static int pld_pcie_pm_resume_noirq(struct device *dev)
477{
478 struct pld_context *pld_context;
479
480 pld_context = pld_get_global_context();
481 if (!pld_context)
482 return -EINVAL;
483
484 if (pld_context->ops->resume_noirq)
485 return pld_context->ops->
486 resume_noirq(dev, PLD_BUS_TYPE_PCIE);
487 return 0;
488}
489#endif
Yuanyuan Liu25c66e12016-05-13 10:17:46 -0700490#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800491
492static struct pci_device_id pld_pcie_id_table[] = {
493 { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID },
494 { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID },
495 { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID },
496 { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID },
497 { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID },
498 { 0 }
499};
500
Manikandan Mohan04459b92018-02-23 16:32:48 -0800501#ifdef MULTI_IF_NAME
502#define PLD_PCIE_OPS_NAME "pld_pcie_" MULTI_IF_NAME
503#else
504#define PLD_PCIE_OPS_NAME "pld_pcie"
505#endif
506
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700507#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700508#ifdef FEATURE_RUNTIME_PM
509struct cnss_wlan_runtime_ops runtime_pm_ops = {
510 .runtime_suspend = pld_pcie_runtime_suspend,
511 .runtime_resume = pld_pcie_runtime_resume,
512};
513#endif
514
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800515struct cnss_wlan_driver pld_pcie_ops = {
Manikandan Mohan04459b92018-02-23 16:32:48 -0800516 .name = PLD_PCIE_OPS_NAME,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800517 .id_table = pld_pcie_id_table,
518 .probe = pld_pcie_probe,
519 .remove = pld_pcie_remove,
Rajeev Kumar588a2542019-04-08 10:57:19 -0700520 .idle_restart = pld_pcie_idle_restart_cb,
521 .idle_shutdown = pld_pcie_idle_shutdown_cb,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800522 .reinit = pld_pcie_reinit,
523 .shutdown = pld_pcie_shutdown,
524 .crash_shutdown = pld_pcie_crash_shutdown,
525 .modem_status = pld_pcie_notify_handler,
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530526 .update_status = pld_pcie_uevent,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800527#ifdef CONFIG_PM
528 .suspend = pld_pcie_suspend,
529 .resume = pld_pcie_resume,
Yue Mae42c8452017-01-06 17:28:28 -0800530 .suspend_noirq = pld_pcie_suspend_noirq,
531 .resume_noirq = pld_pcie_resume_noirq,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800532#endif
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700533#ifdef FEATURE_RUNTIME_PM
534 .runtime_ops = &runtime_pm_ops,
535#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800536};
537
538/**
539 * pld_pcie_register_driver() - Register PCIE device callback functions
540 *
541 * Return: int
542 */
543int pld_pcie_register_driver(void)
544{
545 return cnss_wlan_register_driver(&pld_pcie_ops);
546}
547
548/**
549 * pld_pcie_unregister_driver() - Unregister PCIE device callback functions
550 *
551 * Return: void
552 */
553void pld_pcie_unregister_driver(void)
554{
555 cnss_wlan_unregister_driver(&pld_pcie_ops);
556}
557#else
Yue Ma52d355c2017-01-25 14:49:23 -0800558#ifdef CONFIG_PM
559static const struct dev_pm_ops pld_pm_ops = {
560 SET_SYSTEM_SLEEP_PM_OPS(pld_pcie_pm_suspend, pld_pcie_pm_resume)
561 .suspend_noirq = pld_pcie_pm_suspend_noirq,
562 .resume_noirq = pld_pcie_pm_resume_noirq,
563};
564#endif
565
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800566struct pci_driver pld_pcie_ops = {
Manikandan Mohan04459b92018-02-23 16:32:48 -0800567 .name = PLD_PCIE_OPS_NAME,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800568 .id_table = pld_pcie_id_table,
569 .probe = pld_pcie_probe,
570 .remove = pld_pcie_remove,
Yue Ma52d355c2017-01-25 14:49:23 -0800571 .driver = {
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800572#ifdef CONFIG_PM
Yue Ma52d355c2017-01-25 14:49:23 -0800573 .pm = &pld_pm_ops,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800574#endif
Yue Ma52d355c2017-01-25 14:49:23 -0800575 },
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800576};
577
578int pld_pcie_register_driver(void)
579{
580 return pci_register_driver(&pld_pcie_ops);
581}
582
583void pld_pcie_unregister_driver(void)
584{
585 pci_unregister_driver(&pld_pcie_ops);
586}
587#endif
588
589/**
590 * pld_pcie_get_ce_id() - Get CE number for the provided IRQ
Yue Ma85761e62017-10-30 11:13:45 -0700591 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800592 * @irq: IRQ number
593 *
594 * Return: CE number
595 */
Yue Ma85761e62017-10-30 11:13:45 -0700596int pld_pcie_get_ce_id(struct device *dev, int irq)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800597{
598 int ce_id = irq - 100;
Manikandan Mohan8cf50612017-04-10 13:23:32 -0700599
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800600 if (ce_id < CE_COUNT_MAX && ce_id >= 0)
601 return ce_id;
602
603 return -EINVAL;
604}
605
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700606#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800607/**
608 * pld_pcie_wlan_enable() - Enable WLAN
Yue Ma85761e62017-10-30 11:13:45 -0700609 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800610 * @config: WLAN configuration data
611 * @mode: WLAN mode
612 * @host_version: host software version
613 *
614 * This function enables WLAN FW. It passed WLAN configuration data,
615 * WLAN mode and host software version to FW.
616 *
617 * Return: 0 for success
618 * Non zero failure code for errors
619 */
Yue Ma08047522016-11-08 18:53:26 -0800620int pld_pcie_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800621 enum pld_driver_mode mode, const char *host_version)
622{
623 struct cnss_wlan_enable_cfg cfg;
624 enum cnss_driver_mode cnss_mode;
625
626 cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
627 cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *)
628 config->ce_tgt_cfg;
629 cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
630 cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *)
631 config->ce_svc_cfg;
632 cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
633 cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *)
634 config->shadow_reg_cfg;
Yue Ma502a28f2017-01-03 16:38:44 -0800635 cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg;
636 cfg.shadow_reg_v2_cfg = (struct cnss_shadow_reg_v2_cfg *)
637 config->shadow_reg_v2_cfg;
Nirav Shaha6c6dc92018-07-09 16:26:02 +0530638 cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid;
639 if (config->rri_over_ddr_cfg_valid) {
640 cfg.rri_over_ddr_cfg.base_addr_low =
641 config->rri_over_ddr_cfg.base_addr_low;
642 cfg.rri_over_ddr_cfg.base_addr_high =
643 config->rri_over_ddr_cfg.base_addr_high;
644 }
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800645
646 switch (mode) {
647 case PLD_FTM:
648 cnss_mode = CNSS_FTM;
649 break;
650 case PLD_EPPING:
651 cnss_mode = CNSS_EPPING;
652 break;
653 default:
654 cnss_mode = CNSS_MISSION;
655 break;
656 }
Yue Ma08047522016-11-08 18:53:26 -0800657 return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800658}
659
660/**
661 * pld_pcie_wlan_disable() - Disable WLAN
Yue Ma85761e62017-10-30 11:13:45 -0700662 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800663 * @mode: WLAN mode
664 *
665 * This function disables WLAN FW. It passes WLAN mode to FW.
666 *
667 * Return: 0 for success
668 * Non zero failure code for errors
669 */
Yue Ma08047522016-11-08 18:53:26 -0800670int pld_pcie_wlan_disable(struct device *dev, enum pld_driver_mode mode)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800671{
Yue Ma08047522016-11-08 18:53:26 -0800672 return cnss_wlan_disable(dev, CNSS_OFF);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800673}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800674
675/**
676 * pld_pcie_get_fw_files_for_target() - Get FW file names
Yue Ma85761e62017-10-30 11:13:45 -0700677 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800678 * @pfw_files: buffer for FW file names
679 * @target_type: target type
680 * @target_version: target version
681 *
682 * Return target specific FW file names to the buffer.
683 *
684 * Return: 0 for success
685 * Non zero failure code for errors
686 */
Yue Ma85761e62017-10-30 11:13:45 -0700687int pld_pcie_get_fw_files_for_target(struct device *dev,
688 struct pld_fw_files *pfw_files,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800689 u32 target_type, u32 target_version)
690{
691 int ret = 0;
692 struct cnss_fw_files cnss_fw_files;
693
Jeff Johnson753f9d72019-03-18 13:41:04 -0700694 if (!pfw_files)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800695 return -ENODEV;
696
Yuanyuan Liu6a313dc2016-05-10 14:19:10 -0700697 memset(pfw_files, 0, sizeof(*pfw_files));
698
Yue Ma85761e62017-10-30 11:13:45 -0700699 ret = cnss_get_fw_files_for_target(dev, &cnss_fw_files,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800700 target_type, target_version);
Yue Ma85761e62017-10-30 11:13:45 -0700701 if (ret)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800702 return ret;
703
Qun Zhang4a83a462018-09-11 16:28:51 +0800704 scnprintf(pfw_files->image_file, PLD_MAX_FILE_NAME, PREFIX "%s",
705 cnss_fw_files.image_file);
706 scnprintf(pfw_files->board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
707 cnss_fw_files.board_data);
708 scnprintf(pfw_files->otp_data, PLD_MAX_FILE_NAME, PREFIX "%s",
709 cnss_fw_files.otp_data);
710 scnprintf(pfw_files->utf_file, PLD_MAX_FILE_NAME, PREFIX "%s",
711 cnss_fw_files.utf_file);
712 scnprintf(pfw_files->utf_board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
713 cnss_fw_files.utf_board_data);
714 scnprintf(pfw_files->epping_file, PLD_MAX_FILE_NAME, PREFIX "%s",
715 cnss_fw_files.epping_file);
716 scnprintf(pfw_files->evicted_data, PLD_MAX_FILE_NAME, PREFIX "%s",
717 cnss_fw_files.evicted_data);
Yuanyuan Liu6a313dc2016-05-10 14:19:10 -0700718
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800719 return 0;
720}
721
722/**
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800723 * pld_pcie_get_platform_cap() - Get platform capabilities
Yue Ma85761e62017-10-30 11:13:45 -0700724 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800725 * @cap: buffer to the capabilities
726 *
727 * Return capabilities to the buffer.
728 *
729 * Return: 0 for success
730 * Non zero failure code for errors
731 */
Yue Ma85761e62017-10-30 11:13:45 -0700732int pld_pcie_get_platform_cap(struct device *dev, struct pld_platform_cap *cap)
733{
734 int ret = 0;
735 struct cnss_platform_cap cnss_cap;
736
Jeff Johnson753f9d72019-03-18 13:41:04 -0700737 if (!cap)
Yue Ma85761e62017-10-30 11:13:45 -0700738 return -ENODEV;
739
740 ret = cnss_get_platform_cap(dev, &cnss_cap);
741 if (ret)
742 return ret;
743
744 memcpy(cap, &cnss_cap, sizeof(*cap));
745 return 0;
746}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800747
748/**
Yue Macd243862016-11-04 19:21:16 -0700749 * pld_pcie_get_soc_info() - Get SOC information
Yue Ma85761e62017-10-30 11:13:45 -0700750 * @dev: device
Yue Macd243862016-11-04 19:21:16 -0700751 * @info: buffer to SOC information
752 *
753 * Return SOC info to the buffer.
754 *
755 * Return: 0 for success
756 * Non zero failure code for errors
757 */
758int pld_pcie_get_soc_info(struct device *dev, struct pld_soc_info *info)
759{
760 int ret = 0;
lihual8b9daf22018-04-02 15:18:54 +0800761 struct cnss_soc_info cnss_info = {0};
Yue Macd243862016-11-04 19:21:16 -0700762
Jeff Johnson753f9d72019-03-18 13:41:04 -0700763 if (!info)
Yue Macd243862016-11-04 19:21:16 -0700764 return -ENODEV;
765
766 ret = cnss_get_soc_info(dev, &cnss_info);
767 if (ret)
768 return ret;
769
Frank Liu0e7ac562018-06-15 15:29:49 +0800770 info->v_addr = cnss_info.va;
771 info->p_addr = cnss_info.pa;
772 info->chip_id = cnss_info.chip_id;
773 info->chip_family = cnss_info.chip_family;
774 info->board_id = cnss_info.board_id;
775 info->soc_id = cnss_info.soc_id;
776 info->fw_version = cnss_info.fw_version;
777 strlcpy(info->fw_build_timestamp, cnss_info.fw_build_timestamp,
778 sizeof(info->fw_build_timestamp));
Yue Mab4ebd872019-04-17 14:55:59 -0700779 info->device_version.family_number =
780 cnss_info.device_version.family_number;
781 info->device_version.device_number =
782 cnss_info.device_version.device_number;
783 info->device_version.major_version =
784 cnss_info.device_version.major_version;
785 info->device_version.minor_version =
786 cnss_info.device_version.minor_version;
Yue Macd243862016-11-04 19:21:16 -0700787
788 return 0;
789}
790
791/**
Yuanyuan Liu10fc3d32017-01-12 15:32:06 -0800792 * pld_pcie_schedule_recovery_work() - schedule recovery work
793 * @dev: device
794 * @reason: recovery reason
795 *
796 * Return: void
797 */
798void pld_pcie_schedule_recovery_work(struct device *dev,
799 enum pld_recovery_reason reason)
800{
801 enum cnss_recovery_reason cnss_reason;
802
803 switch (reason) {
804 case PLD_REASON_LINK_DOWN:
805 cnss_reason = CNSS_REASON_LINK_DOWN;
806 break;
807 default:
808 cnss_reason = CNSS_REASON_DEFAULT;
809 break;
810 }
811 cnss_schedule_recovery(dev, cnss_reason);
812}
813
814/**
815 * pld_pcie_device_self_recovery() - device self recovery
816 * @dev: device
817 * @reason: recovery reason
818 *
819 * Return: void
820 */
821void pld_pcie_device_self_recovery(struct device *dev,
822 enum pld_recovery_reason reason)
823{
824 enum cnss_recovery_reason cnss_reason;
825
826 switch (reason) {
827 case PLD_REASON_LINK_DOWN:
828 cnss_reason = CNSS_REASON_LINK_DOWN;
829 break;
830 default:
831 cnss_reason = CNSS_REASON_DEFAULT;
832 break;
833 }
834 cnss_self_recovery(dev, cnss_reason);
835}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800836#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800837#endif