blob: 52e4e45b1c5decd70259d2e8074078ebc6f87d1a [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"
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080031
32#ifdef CONFIG_PCI
33
34#ifdef QCA_WIFI_3_0_ADRASTEA
35#define CE_COUNT_MAX 12
36#else
37#define CE_COUNT_MAX 8
38#endif
39
40/**
41 * pld_pcie_probe() - Probe function for PCIE platform driver
42 * @pdev: PCIE device
43 * @id: PCIE device ID table
44 *
45 * The probe function will be called when PCIE device provided
46 * in the ID table is detected.
47 *
48 * Return: int
49 */
50static int pld_pcie_probe(struct pci_dev *pdev,
51 const struct pci_device_id *id)
52{
53 struct pld_context *pld_context;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080054 int ret = 0;
55
56 pld_context = pld_get_global_context();
57 if (!pld_context) {
58 ret = -ENODEV;
59 goto out;
60 }
61
Ajit Pal Singh5e618aa2018-12-20 17:47:36 +053062 ret = pld_add_dev(pld_context, &pdev->dev, NULL, PLD_BUS_TYPE_PCIE);
Yuanyuan Liu5e25f532016-05-25 16:26:40 -070063 if (ret)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080064 goto out;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080065
66 return pld_context->ops->probe(&pdev->dev,
67 PLD_BUS_TYPE_PCIE, pdev, (void *)id);
68
69out:
70 return ret;
71}
72
73
74/**
75 * pld_pcie_remove() - Remove function for PCIE device
76 * @pdev: PCIE device
77 *
78 * The remove function will be called when PCIE device is disconnected
79 *
80 * Return: void
81 */
82static void pld_pcie_remove(struct pci_dev *pdev)
83{
84 struct pld_context *pld_context;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080085
86 pld_context = pld_get_global_context();
87
88 if (!pld_context)
89 return;
90
Yuanyuan Liu960fa212016-05-24 17:15:43 -070091 pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE);
92
Yuanyuan Liu5e25f532016-05-25 16:26:40 -070093 pld_del_dev(pld_context, &pdev->dev);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080094}
95
Yuanyuan Liu11f526a2016-05-18 10:22:07 -070096#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080097/**
Rajeev Kumar588a2542019-04-08 10:57:19 -070098 * pld_pcie_idle_restart_cb() - Perform idle restart
99 * @pdev: PCIE device
100 * @id: PCIE device ID
101 *
102 * This function will be called if there is an idle restart request
103 *
104 * Return: int
105 */
106static int pld_pcie_idle_restart_cb(struct pci_dev *pdev,
107 const struct pci_device_id *id)
108{
109 struct pld_context *pld_context;
110
111 pld_context = pld_get_global_context();
112 if (pld_context->ops->idle_restart)
113 return pld_context->ops->idle_restart(&pdev->dev,
114 PLD_BUS_TYPE_PCIE);
115
116 return -ENODEV;
117}
118
119/**
120 * pld_pcie_idle_shutdown_cb() - Perform idle shutdown
121 * @pdev: PCIE device
122 * @id: PCIE device ID
123 *
124 * This function will be called if there is an idle shutdown request
125 *
126 * Return: int
127 */
128static int pld_pcie_idle_shutdown_cb(struct pci_dev *pdev)
129{
130 struct pld_context *pld_context;
131
132 pld_context = pld_get_global_context();
133 if (pld_context->ops->shutdown)
134 return pld_context->ops->idle_shutdown(&pdev->dev,
135 PLD_BUS_TYPE_PCIE);
136
137 return -ENODEV;
138}
139
140/**
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800141 * pld_pcie_reinit() - SSR re-initialize function for PCIE device
142 * @pdev: PCIE device
143 * @id: PCIE device ID
144 *
145 * During subsystem restart(SSR), this function will be called to
146 * re-initialize PCIE device.
147 *
148 * Return: int
149 */
150static int pld_pcie_reinit(struct pci_dev *pdev,
151 const struct pci_device_id *id)
152{
153 struct pld_context *pld_context;
154
155 pld_context = pld_get_global_context();
156 if (pld_context->ops->reinit)
157 return pld_context->ops->reinit(&pdev->dev,
158 PLD_BUS_TYPE_PCIE, pdev, (void *)id);
159
160 return -ENODEV;
161}
162
163/**
164 * pld_pcie_shutdown() - SSR shutdown function for PCIE device
165 * @pdev: PCIE device
166 *
167 * During SSR, this function will be called to shutdown PCIE device.
168 *
169 * Return: void
170 */
171static void pld_pcie_shutdown(struct pci_dev *pdev)
172{
173 struct pld_context *pld_context;
174
175 pld_context = pld_get_global_context();
176 if (pld_context->ops->shutdown)
177 pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
178}
179
180/**
181 * pld_pcie_crash_shutdown() - Crash shutdown function for PCIE device
182 * @pdev: PCIE device
183 *
184 * This function will be called when a crash is detected, it will shutdown
185 * the PCIE device.
186 *
187 * Return: void
188 */
189static void pld_pcie_crash_shutdown(struct pci_dev *pdev)
190{
191 struct pld_context *pld_context;
192
193 pld_context = pld_get_global_context();
194 if (pld_context->ops->crash_shutdown)
195 pld_context->ops->crash_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
196}
197
198/**
199 * pld_pcie_notify_handler() - Modem state notification callback function
200 * @pdev: PCIE device
201 * @state: modem power state
202 *
203 * This function will be called when there's a modem power state change.
204 *
205 * Return: void
206 */
207static void pld_pcie_notify_handler(struct pci_dev *pdev, int state)
208{
209 struct pld_context *pld_context;
210
211 pld_context = pld_get_global_context();
212 if (pld_context->ops->modem_status)
213 pld_context->ops->modem_status(&pdev->dev,
214 PLD_BUS_TYPE_PCIE, state);
215}
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700216
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800217/**
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530218 * pld_pcie_uevent() - update wlan driver status callback function
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800219 * @pdev: PCIE device
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530220 * @status driver uevent status
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800221 *
222 * This function will be called when platform driver wants to update wlan
223 * driver's status.
224 *
225 * Return: void
226 */
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530227static void pld_pcie_uevent(struct pci_dev *pdev, uint32_t status)
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800228{
229 struct pld_context *pld_context;
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530230 struct pld_uevent_data data;
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800231
232 pld_context = pld_get_global_context();
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530233 if (!pld_context)
234 return;
235
Yue Ma096189d2017-09-13 11:14:59 -0700236 switch (status) {
237 case CNSS_RECOVERY:
Dustin Brown8f05f652018-10-25 15:17:30 -0700238 data.uevent = PLD_FW_RECOVERY_START;
Yue Ma096189d2017-09-13 11:14:59 -0700239 break;
Arunk Khandavallif9957c02018-10-24 16:51:14 +0530240 case CNSS_FW_DOWN:
241 data.uevent = PLD_FW_DOWN;
242 break;
Yue Ma096189d2017-09-13 11:14:59 -0700243 default:
244 goto out;
245 }
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530246
Will Huangbdd28712017-06-21 11:02:39 +0800247 if (pld_context->ops->uevent)
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530248 pld_context->ops->uevent(&pdev->dev, &data);
249
Yue Ma096189d2017-09-13 11:14:59 -0700250out:
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530251 return;
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800252}
253
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700254#ifdef FEATURE_RUNTIME_PM
255/**
256 * pld_pcie_runtime_suspend() - PM runtime suspend
257 * @pdev: PCIE device
258 *
259 * PM runtime suspend callback function.
260 *
261 * Return: int
262 */
263static int pld_pcie_runtime_suspend(struct pci_dev *pdev)
264{
265 struct pld_context *pld_context;
266
267 pld_context = pld_get_global_context();
268 if (pld_context->ops->runtime_suspend)
269 return pld_context->ops->runtime_suspend(&pdev->dev,
270 PLD_BUS_TYPE_PCIE);
271
272 return -ENODEV;
273}
274
275/**
276 * pld_pcie_runtime_resume() - PM runtime resume
277 * @pdev: PCIE device
278 *
279 * PM runtime resume callback function.
280 *
281 * Return: int
282 */
283static int pld_pcie_runtime_resume(struct pci_dev *pdev)
284{
285 struct pld_context *pld_context;
286
287 pld_context = pld_get_global_context();
288 if (pld_context->ops->runtime_resume)
289 return pld_context->ops->runtime_resume(&pdev->dev,
290 PLD_BUS_TYPE_PCIE);
291
292 return -ENODEV;
293}
294#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800295#endif
296
Yuanyuan Liu25c66e12016-05-13 10:17:46 -0700297#ifdef CONFIG_PM
Yue Ma52d355c2017-01-25 14:49:23 -0800298#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800299/**
300 * pld_pcie_suspend() - Suspend callback function for power management
301 * @pdev: PCIE device
302 * @state: power state
303 *
304 * This function is to suspend the PCIE device when power management is
305 * enabled.
306 *
307 * Return: void
308 */
309static int pld_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
310{
311 struct pld_context *pld_context;
312
313 pld_context = pld_get_global_context();
314 return pld_context->ops->suspend(&pdev->dev,
315 PLD_BUS_TYPE_PCIE, state);
316}
317
318/**
319 * pld_pcie_resume() - Resume callback function for power management
320 * @pdev: PCIE device
321 *
322 * This function is to resume the PCIE device when power management is
323 * enabled.
324 *
325 * Return: void
326 */
327static int pld_pcie_resume(struct pci_dev *pdev)
328{
329 struct pld_context *pld_context;
330
331 pld_context = pld_get_global_context();
332 return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_PCIE);
333}
Yue Mae42c8452017-01-06 17:28:28 -0800334
335/**
336 * pld_pcie_suspend_noirq() - Complete the actions started by suspend()
337 * @pdev: PCI device
338 *
339 * Complete the actions started by suspend(). Carry out any additional
340 * operations required for suspending the device that might be racing
341 * with its driver's interrupt handler, which is guaranteed not to run
342 * while suspend_noirq() is being executed.
343 *
344 * Return: 0 for success
345 * Non zero failure code for errors
346 */
347static int pld_pcie_suspend_noirq(struct pci_dev *pdev)
348{
349 struct pld_context *pld_context;
350
351 pld_context = pld_get_global_context();
352 if (!pld_context)
353 return -EINVAL;
354
355 if (pld_context->ops->suspend_noirq)
356 return pld_context->ops->
357 suspend_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
358 return 0;
359}
360
361/**
362 * pld_pcie_resume_noirq() - Prepare for the execution of resume()
363 * @pdev: PCI device
364 *
365 * Prepare for the execution of resume() by carrying out any additional
366 * operations required for resuming the device that might be racing with
367 * its driver's interrupt handler, which is guaranteed not to run while
368 * resume_noirq() is being executed.
369 *
370 * Return: 0 for success
371 * Non zero failure code for errors
372 */
373static int pld_pcie_resume_noirq(struct pci_dev *pdev)
374{
375 struct pld_context *pld_context;
376
377 pld_context = pld_get_global_context();
378 if (!pld_context)
379 return -EINVAL;
380
381 if (pld_context->ops->resume_noirq)
382 return pld_context->ops->
383 resume_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
384 return 0;
385}
Yue Ma52d355c2017-01-25 14:49:23 -0800386#else
387/**
388 * pld_pcie_pm_suspend() - Suspend callback function for power management
389 * @dev: device
390 *
391 * This function is to suspend the PCIE device when power management is
392 * enabled.
393 *
394 * Return: 0 for success
395 * Non zero failure code for errors
396 */
397static int pld_pcie_pm_suspend(struct device *dev)
398{
399 struct pld_context *pld_context;
400
401 pm_message_t state = { .event = PM_EVENT_SUSPEND };
402
403 pld_context = pld_get_global_context();
404 return pld_context->ops->suspend(dev, PLD_BUS_TYPE_PCIE, state);
405}
406
407/**
408 * pld_pcie_pm_resume() - Resume callback function for power management
409 * @dev: device
410 *
411 * This function is to resume the PCIE device when power management is
412 * enabled.
413 *
414 * Return: 0 for success
415 * Non zero failure code for errors
416 */
417static int pld_pcie_pm_resume(struct device *dev)
418{
419 struct pld_context *pld_context;
420
421 pld_context = pld_get_global_context();
422 return pld_context->ops->resume(dev, PLD_BUS_TYPE_PCIE);
423}
424
425/**
426 * pld_pcie_pm_suspend_noirq() - Complete the actions started by suspend()
427 * @dev: device
428 *
429 * Complete the actions started by suspend(). Carry out any additional
430 * operations required for suspending the device that might be racing
431 * with its driver's interrupt handler, which is guaranteed not to run
432 * while suspend_noirq() is being executed.
433 *
434 * Return: 0 for success
435 * Non zero failure code for errors
436 */
437static int pld_pcie_pm_suspend_noirq(struct device *dev)
438{
439 struct pld_context *pld_context;
440
441 pld_context = pld_get_global_context();
442 if (!pld_context)
443 return -EINVAL;
444
445 if (pld_context->ops->suspend_noirq)
446 return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_PCIE);
447 return 0;
448}
449
450/**
451 * pld_pcie_pm_resume_noirq() - Prepare for the execution of resume()
452 * @dev: device
453 *
454 * Prepare for the execution of resume() by carrying out any additional
455 * operations required for resuming the device that might be racing with
456 * its driver's interrupt handler, which is guaranteed not to run while
457 * resume_noirq() is being executed.
458 *
459 * Return: 0 for success
460 * Non zero failure code for errors
461 */
462static int pld_pcie_pm_resume_noirq(struct device *dev)
463{
464 struct pld_context *pld_context;
465
466 pld_context = pld_get_global_context();
467 if (!pld_context)
468 return -EINVAL;
469
470 if (pld_context->ops->resume_noirq)
471 return pld_context->ops->
472 resume_noirq(dev, PLD_BUS_TYPE_PCIE);
473 return 0;
474}
475#endif
Yuanyuan Liu25c66e12016-05-13 10:17:46 -0700476#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800477
478static struct pci_device_id pld_pcie_id_table[] = {
479 { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID },
480 { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID },
481 { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID },
482 { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID },
483 { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID },
484 { 0 }
485};
486
Manikandan Mohan04459b92018-02-23 16:32:48 -0800487#ifdef MULTI_IF_NAME
488#define PLD_PCIE_OPS_NAME "pld_pcie_" MULTI_IF_NAME
489#else
490#define PLD_PCIE_OPS_NAME "pld_pcie"
491#endif
492
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700493#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700494#ifdef FEATURE_RUNTIME_PM
495struct cnss_wlan_runtime_ops runtime_pm_ops = {
496 .runtime_suspend = pld_pcie_runtime_suspend,
497 .runtime_resume = pld_pcie_runtime_resume,
498};
499#endif
500
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800501struct cnss_wlan_driver pld_pcie_ops = {
Manikandan Mohan04459b92018-02-23 16:32:48 -0800502 .name = PLD_PCIE_OPS_NAME,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800503 .id_table = pld_pcie_id_table,
504 .probe = pld_pcie_probe,
505 .remove = pld_pcie_remove,
Rajeev Kumar588a2542019-04-08 10:57:19 -0700506 .idle_restart = pld_pcie_idle_restart_cb,
507 .idle_shutdown = pld_pcie_idle_shutdown_cb,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800508 .reinit = pld_pcie_reinit,
509 .shutdown = pld_pcie_shutdown,
510 .crash_shutdown = pld_pcie_crash_shutdown,
511 .modem_status = pld_pcie_notify_handler,
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530512 .update_status = pld_pcie_uevent,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800513#ifdef CONFIG_PM
514 .suspend = pld_pcie_suspend,
515 .resume = pld_pcie_resume,
Yue Mae42c8452017-01-06 17:28:28 -0800516 .suspend_noirq = pld_pcie_suspend_noirq,
517 .resume_noirq = pld_pcie_resume_noirq,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800518#endif
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700519#ifdef FEATURE_RUNTIME_PM
520 .runtime_ops = &runtime_pm_ops,
521#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800522};
523
524/**
525 * pld_pcie_register_driver() - Register PCIE device callback functions
526 *
527 * Return: int
528 */
529int pld_pcie_register_driver(void)
530{
531 return cnss_wlan_register_driver(&pld_pcie_ops);
532}
533
534/**
535 * pld_pcie_unregister_driver() - Unregister PCIE device callback functions
536 *
537 * Return: void
538 */
539void pld_pcie_unregister_driver(void)
540{
541 cnss_wlan_unregister_driver(&pld_pcie_ops);
542}
543#else
Yue Ma52d355c2017-01-25 14:49:23 -0800544#ifdef CONFIG_PM
545static const struct dev_pm_ops pld_pm_ops = {
546 SET_SYSTEM_SLEEP_PM_OPS(pld_pcie_pm_suspend, pld_pcie_pm_resume)
547 .suspend_noirq = pld_pcie_pm_suspend_noirq,
548 .resume_noirq = pld_pcie_pm_resume_noirq,
549};
550#endif
551
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800552struct pci_driver pld_pcie_ops = {
Manikandan Mohan04459b92018-02-23 16:32:48 -0800553 .name = PLD_PCIE_OPS_NAME,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800554 .id_table = pld_pcie_id_table,
555 .probe = pld_pcie_probe,
556 .remove = pld_pcie_remove,
Yue Ma52d355c2017-01-25 14:49:23 -0800557 .driver = {
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800558#ifdef CONFIG_PM
Yue Ma52d355c2017-01-25 14:49:23 -0800559 .pm = &pld_pm_ops,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800560#endif
Yue Ma52d355c2017-01-25 14:49:23 -0800561 },
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800562};
563
564int pld_pcie_register_driver(void)
565{
566 return pci_register_driver(&pld_pcie_ops);
567}
568
569void pld_pcie_unregister_driver(void)
570{
571 pci_unregister_driver(&pld_pcie_ops);
572}
573#endif
574
575/**
576 * pld_pcie_get_ce_id() - Get CE number for the provided IRQ
Yue Ma85761e62017-10-30 11:13:45 -0700577 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800578 * @irq: IRQ number
579 *
580 * Return: CE number
581 */
Yue Ma85761e62017-10-30 11:13:45 -0700582int pld_pcie_get_ce_id(struct device *dev, int irq)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800583{
584 int ce_id = irq - 100;
Manikandan Mohan8cf50612017-04-10 13:23:32 -0700585
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800586 if (ce_id < CE_COUNT_MAX && ce_id >= 0)
587 return ce_id;
588
589 return -EINVAL;
590}
591
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700592#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800593/**
594 * pld_pcie_wlan_enable() - Enable WLAN
Yue Ma85761e62017-10-30 11:13:45 -0700595 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800596 * @config: WLAN configuration data
597 * @mode: WLAN mode
598 * @host_version: host software version
599 *
600 * This function enables WLAN FW. It passed WLAN configuration data,
601 * WLAN mode and host software version to FW.
602 *
603 * Return: 0 for success
604 * Non zero failure code for errors
605 */
Yue Ma08047522016-11-08 18:53:26 -0800606int pld_pcie_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800607 enum pld_driver_mode mode, const char *host_version)
608{
609 struct cnss_wlan_enable_cfg cfg;
610 enum cnss_driver_mode cnss_mode;
611
612 cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
613 cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *)
614 config->ce_tgt_cfg;
615 cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
616 cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *)
617 config->ce_svc_cfg;
618 cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
619 cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *)
620 config->shadow_reg_cfg;
Yue Ma502a28f2017-01-03 16:38:44 -0800621 cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg;
622 cfg.shadow_reg_v2_cfg = (struct cnss_shadow_reg_v2_cfg *)
623 config->shadow_reg_v2_cfg;
Nirav Shaha6c6dc92018-07-09 16:26:02 +0530624 cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid;
625 if (config->rri_over_ddr_cfg_valid) {
626 cfg.rri_over_ddr_cfg.base_addr_low =
627 config->rri_over_ddr_cfg.base_addr_low;
628 cfg.rri_over_ddr_cfg.base_addr_high =
629 config->rri_over_ddr_cfg.base_addr_high;
630 }
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800631
632 switch (mode) {
633 case PLD_FTM:
634 cnss_mode = CNSS_FTM;
635 break;
636 case PLD_EPPING:
637 cnss_mode = CNSS_EPPING;
638 break;
639 default:
640 cnss_mode = CNSS_MISSION;
641 break;
642 }
Yue Ma08047522016-11-08 18:53:26 -0800643 return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800644}
645
646/**
647 * pld_pcie_wlan_disable() - Disable WLAN
Yue Ma85761e62017-10-30 11:13:45 -0700648 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800649 * @mode: WLAN mode
650 *
651 * This function disables WLAN FW. It passes WLAN mode to FW.
652 *
653 * Return: 0 for success
654 * Non zero failure code for errors
655 */
Yue Ma08047522016-11-08 18:53:26 -0800656int pld_pcie_wlan_disable(struct device *dev, enum pld_driver_mode mode)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800657{
Yue Ma08047522016-11-08 18:53:26 -0800658 return cnss_wlan_disable(dev, CNSS_OFF);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800659}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800660
661/**
662 * pld_pcie_get_fw_files_for_target() - Get FW file names
Yue Ma85761e62017-10-30 11:13:45 -0700663 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800664 * @pfw_files: buffer for FW file names
665 * @target_type: target type
666 * @target_version: target version
667 *
668 * Return target specific FW file names to the buffer.
669 *
670 * Return: 0 for success
671 * Non zero failure code for errors
672 */
Yue Ma85761e62017-10-30 11:13:45 -0700673int pld_pcie_get_fw_files_for_target(struct device *dev,
674 struct pld_fw_files *pfw_files,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800675 u32 target_type, u32 target_version)
676{
677 int ret = 0;
678 struct cnss_fw_files cnss_fw_files;
679
Jeff Johnson753f9d72019-03-18 13:41:04 -0700680 if (!pfw_files)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800681 return -ENODEV;
682
Yuanyuan Liu6a313dc2016-05-10 14:19:10 -0700683 memset(pfw_files, 0, sizeof(*pfw_files));
684
Yue Ma85761e62017-10-30 11:13:45 -0700685 ret = cnss_get_fw_files_for_target(dev, &cnss_fw_files,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800686 target_type, target_version);
Yue Ma85761e62017-10-30 11:13:45 -0700687 if (ret)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800688 return ret;
689
Qun Zhang4a83a462018-09-11 16:28:51 +0800690 scnprintf(pfw_files->image_file, PLD_MAX_FILE_NAME, PREFIX "%s",
691 cnss_fw_files.image_file);
692 scnprintf(pfw_files->board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
693 cnss_fw_files.board_data);
694 scnprintf(pfw_files->otp_data, PLD_MAX_FILE_NAME, PREFIX "%s",
695 cnss_fw_files.otp_data);
696 scnprintf(pfw_files->utf_file, PLD_MAX_FILE_NAME, PREFIX "%s",
697 cnss_fw_files.utf_file);
698 scnprintf(pfw_files->utf_board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
699 cnss_fw_files.utf_board_data);
700 scnprintf(pfw_files->epping_file, PLD_MAX_FILE_NAME, PREFIX "%s",
701 cnss_fw_files.epping_file);
702 scnprintf(pfw_files->evicted_data, PLD_MAX_FILE_NAME, PREFIX "%s",
703 cnss_fw_files.evicted_data);
Yuanyuan Liu6a313dc2016-05-10 14:19:10 -0700704
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800705 return 0;
706}
707
708/**
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800709 * pld_pcie_get_platform_cap() - Get platform capabilities
Yue Ma85761e62017-10-30 11:13:45 -0700710 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800711 * @cap: buffer to the capabilities
712 *
713 * Return capabilities to the buffer.
714 *
715 * Return: 0 for success
716 * Non zero failure code for errors
717 */
Yue Ma85761e62017-10-30 11:13:45 -0700718int pld_pcie_get_platform_cap(struct device *dev, struct pld_platform_cap *cap)
719{
720 int ret = 0;
721 struct cnss_platform_cap cnss_cap;
722
Jeff Johnson753f9d72019-03-18 13:41:04 -0700723 if (!cap)
Yue Ma85761e62017-10-30 11:13:45 -0700724 return -ENODEV;
725
726 ret = cnss_get_platform_cap(dev, &cnss_cap);
727 if (ret)
728 return ret;
729
730 memcpy(cap, &cnss_cap, sizeof(*cap));
731 return 0;
732}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800733
734/**
Yue Macd243862016-11-04 19:21:16 -0700735 * pld_pcie_get_soc_info() - Get SOC information
Yue Ma85761e62017-10-30 11:13:45 -0700736 * @dev: device
Yue Macd243862016-11-04 19:21:16 -0700737 * @info: buffer to SOC information
738 *
739 * Return SOC info to the buffer.
740 *
741 * Return: 0 for success
742 * Non zero failure code for errors
743 */
744int pld_pcie_get_soc_info(struct device *dev, struct pld_soc_info *info)
745{
746 int ret = 0;
lihual8b9daf22018-04-02 15:18:54 +0800747 struct cnss_soc_info cnss_info = {0};
Yue Macd243862016-11-04 19:21:16 -0700748
Jeff Johnson753f9d72019-03-18 13:41:04 -0700749 if (!info)
Yue Macd243862016-11-04 19:21:16 -0700750 return -ENODEV;
751
752 ret = cnss_get_soc_info(dev, &cnss_info);
753 if (ret)
754 return ret;
755
Frank Liu0e7ac562018-06-15 15:29:49 +0800756 info->v_addr = cnss_info.va;
757 info->p_addr = cnss_info.pa;
758 info->chip_id = cnss_info.chip_id;
759 info->chip_family = cnss_info.chip_family;
760 info->board_id = cnss_info.board_id;
761 info->soc_id = cnss_info.soc_id;
762 info->fw_version = cnss_info.fw_version;
763 strlcpy(info->fw_build_timestamp, cnss_info.fw_build_timestamp,
764 sizeof(info->fw_build_timestamp));
Yue Mab4ebd872019-04-17 14:55:59 -0700765 info->device_version.family_number =
766 cnss_info.device_version.family_number;
767 info->device_version.device_number =
768 cnss_info.device_version.device_number;
769 info->device_version.major_version =
770 cnss_info.device_version.major_version;
771 info->device_version.minor_version =
772 cnss_info.device_version.minor_version;
Yue Macd243862016-11-04 19:21:16 -0700773
774 return 0;
775}
776
777/**
Yuanyuan Liu10fc3d32017-01-12 15:32:06 -0800778 * pld_pcie_schedule_recovery_work() - schedule recovery work
779 * @dev: device
780 * @reason: recovery reason
781 *
782 * Return: void
783 */
784void pld_pcie_schedule_recovery_work(struct device *dev,
785 enum pld_recovery_reason reason)
786{
787 enum cnss_recovery_reason cnss_reason;
788
789 switch (reason) {
790 case PLD_REASON_LINK_DOWN:
791 cnss_reason = CNSS_REASON_LINK_DOWN;
792 break;
793 default:
794 cnss_reason = CNSS_REASON_DEFAULT;
795 break;
796 }
797 cnss_schedule_recovery(dev, cnss_reason);
798}
799
800/**
801 * pld_pcie_device_self_recovery() - device self recovery
802 * @dev: device
803 * @reason: recovery reason
804 *
805 * Return: void
806 */
807void pld_pcie_device_self_recovery(struct device *dev,
808 enum pld_recovery_reason reason)
809{
810 enum cnss_recovery_reason cnss_reason;
811
812 switch (reason) {
813 case PLD_REASON_LINK_DOWN:
814 cnss_reason = CNSS_REASON_LINK_DOWN;
815 break;
816 default:
817 cnss_reason = CNSS_REASON_DEFAULT;
818 break;
819 }
820 cnss_self_recovery(dev, cnss_reason);
821}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800822#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800823#endif