blob: 5c2f51205a7f386a521a761abeb74b875e74abf0 [file] [log] [blame]
Yuanyuan Liud9f7a362016-01-22 14:27:12 -08001/*
Jingxiang Ge19042f62020-01-16 20:36:53 +08002 * Copyright (c) 2016-2020 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);
Tiger Yudb568a82019-12-20 19:10:30 +080094
Nirav Shah942cdf62019-09-25 00:02:54 +053095 osif_psoc_sync_wait_for_ops(psoc_sync);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -080096
97 pld_context = pld_get_global_context();
98
99 if (!pld_context)
Nirav Shah942cdf62019-09-25 00:02:54 +0530100 goto out;
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800101
Yuanyuan Liu960fa212016-05-24 17:15:43 -0700102 pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE);
103
Yuanyuan Liu5e25f532016-05-25 16:26:40 -0700104 pld_del_dev(pld_context, &pdev->dev);
Nirav Shah942cdf62019-09-25 00:02:54 +0530105
106out:
107 osif_psoc_sync_trans_stop(psoc_sync);
108 osif_psoc_sync_destroy(psoc_sync);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800109}
110
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700111#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800112/**
Rajeev Kumar588a2542019-04-08 10:57:19 -0700113 * pld_pcie_idle_restart_cb() - Perform idle restart
114 * @pdev: PCIE device
115 * @id: PCIE device ID
116 *
117 * This function will be called if there is an idle restart request
118 *
119 * Return: int
120 */
121static int pld_pcie_idle_restart_cb(struct pci_dev *pdev,
122 const struct pci_device_id *id)
123{
124 struct pld_context *pld_context;
125
126 pld_context = pld_get_global_context();
127 if (pld_context->ops->idle_restart)
128 return pld_context->ops->idle_restart(&pdev->dev,
129 PLD_BUS_TYPE_PCIE);
130
131 return -ENODEV;
132}
133
134/**
135 * pld_pcie_idle_shutdown_cb() - Perform idle shutdown
136 * @pdev: PCIE device
137 * @id: PCIE device ID
138 *
139 * This function will be called if there is an idle shutdown request
140 *
141 * Return: int
142 */
143static int pld_pcie_idle_shutdown_cb(struct pci_dev *pdev)
144{
145 struct pld_context *pld_context;
146
147 pld_context = pld_get_global_context();
148 if (pld_context->ops->shutdown)
149 return pld_context->ops->idle_shutdown(&pdev->dev,
150 PLD_BUS_TYPE_PCIE);
151
152 return -ENODEV;
153}
154
155/**
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800156 * pld_pcie_reinit() - SSR re-initialize function for PCIE device
157 * @pdev: PCIE device
158 * @id: PCIE device ID
159 *
160 * During subsystem restart(SSR), this function will be called to
161 * re-initialize PCIE device.
162 *
163 * Return: int
164 */
165static int pld_pcie_reinit(struct pci_dev *pdev,
166 const struct pci_device_id *id)
167{
168 struct pld_context *pld_context;
169
170 pld_context = pld_get_global_context();
171 if (pld_context->ops->reinit)
172 return pld_context->ops->reinit(&pdev->dev,
173 PLD_BUS_TYPE_PCIE, pdev, (void *)id);
174
175 return -ENODEV;
176}
177
178/**
179 * pld_pcie_shutdown() - SSR shutdown function for PCIE device
180 * @pdev: PCIE device
181 *
182 * During SSR, this function will be called to shutdown PCIE device.
183 *
184 * Return: void
185 */
186static void pld_pcie_shutdown(struct pci_dev *pdev)
187{
188 struct pld_context *pld_context;
189
190 pld_context = pld_get_global_context();
191 if (pld_context->ops->shutdown)
192 pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
193}
194
195/**
196 * pld_pcie_crash_shutdown() - Crash shutdown function for PCIE device
197 * @pdev: PCIE device
198 *
199 * This function will be called when a crash is detected, it will shutdown
200 * the PCIE device.
201 *
202 * Return: void
203 */
204static void pld_pcie_crash_shutdown(struct pci_dev *pdev)
205{
206 struct pld_context *pld_context;
207
208 pld_context = pld_get_global_context();
209 if (pld_context->ops->crash_shutdown)
210 pld_context->ops->crash_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE);
211}
212
213/**
214 * pld_pcie_notify_handler() - Modem state notification callback function
215 * @pdev: PCIE device
216 * @state: modem power state
217 *
218 * This function will be called when there's a modem power state change.
219 *
220 * Return: void
221 */
222static void pld_pcie_notify_handler(struct pci_dev *pdev, int state)
223{
224 struct pld_context *pld_context;
225
226 pld_context = pld_get_global_context();
227 if (pld_context->ops->modem_status)
228 pld_context->ops->modem_status(&pdev->dev,
229 PLD_BUS_TYPE_PCIE, state);
230}
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700231
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800232/**
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530233 * pld_pcie_uevent() - update wlan driver status callback function
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800234 * @pdev: PCIE device
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530235 * @status driver uevent status
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800236 *
237 * This function will be called when platform driver wants to update wlan
238 * driver's status.
239 *
240 * Return: void
241 */
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530242static void pld_pcie_uevent(struct pci_dev *pdev, uint32_t status)
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800243{
244 struct pld_context *pld_context;
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530245 struct pld_uevent_data data;
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800246
247 pld_context = pld_get_global_context();
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530248 if (!pld_context)
249 return;
250
Yue Ma096189d2017-09-13 11:14:59 -0700251 switch (status) {
252 case CNSS_RECOVERY:
Dustin Brown8f05f652018-10-25 15:17:30 -0700253 data.uevent = PLD_FW_RECOVERY_START;
Yue Ma096189d2017-09-13 11:14:59 -0700254 break;
Arunk Khandavallif9957c02018-10-24 16:51:14 +0530255 case CNSS_FW_DOWN:
256 data.uevent = PLD_FW_DOWN;
257 break;
Yue Ma096189d2017-09-13 11:14:59 -0700258 default:
259 goto out;
260 }
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530261
Will Huangbdd28712017-06-21 11:02:39 +0800262 if (pld_context->ops->uevent)
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530263 pld_context->ops->uevent(&pdev->dev, &data);
264
Yue Ma096189d2017-09-13 11:14:59 -0700265out:
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530266 return;
Yuanyuan Liu06a342f2017-01-12 16:48:19 -0800267}
268
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700269#ifdef FEATURE_RUNTIME_PM
270/**
271 * pld_pcie_runtime_suspend() - PM runtime suspend
272 * @pdev: PCIE device
273 *
274 * PM runtime suspend callback function.
275 *
276 * Return: int
277 */
278static int pld_pcie_runtime_suspend(struct pci_dev *pdev)
279{
280 struct pld_context *pld_context;
281
282 pld_context = pld_get_global_context();
283 if (pld_context->ops->runtime_suspend)
284 return pld_context->ops->runtime_suspend(&pdev->dev,
285 PLD_BUS_TYPE_PCIE);
286
287 return -ENODEV;
288}
289
290/**
291 * pld_pcie_runtime_resume() - PM runtime resume
292 * @pdev: PCIE device
293 *
294 * PM runtime resume callback function.
295 *
296 * Return: int
297 */
298static int pld_pcie_runtime_resume(struct pci_dev *pdev)
299{
300 struct pld_context *pld_context;
301
302 pld_context = pld_get_global_context();
303 if (pld_context->ops->runtime_resume)
304 return pld_context->ops->runtime_resume(&pdev->dev,
305 PLD_BUS_TYPE_PCIE);
306
307 return -ENODEV;
308}
309#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800310#endif
311
Yuanyuan Liu25c66e12016-05-13 10:17:46 -0700312#ifdef CONFIG_PM
Yue Ma52d355c2017-01-25 14:49:23 -0800313#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800314/**
315 * pld_pcie_suspend() - Suspend callback function for power management
316 * @pdev: PCIE device
317 * @state: power state
318 *
319 * This function is to suspend the PCIE device when power management is
320 * enabled.
321 *
322 * Return: void
323 */
324static int pld_pcie_suspend(struct pci_dev *pdev, pm_message_t state)
325{
326 struct pld_context *pld_context;
327
328 pld_context = pld_get_global_context();
329 return pld_context->ops->suspend(&pdev->dev,
330 PLD_BUS_TYPE_PCIE, state);
331}
332
333/**
334 * pld_pcie_resume() - Resume callback function for power management
335 * @pdev: PCIE device
336 *
337 * This function is to resume the PCIE device when power management is
338 * enabled.
339 *
340 * Return: void
341 */
342static int pld_pcie_resume(struct pci_dev *pdev)
343{
344 struct pld_context *pld_context;
345
346 pld_context = pld_get_global_context();
347 return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_PCIE);
348}
Yue Mae42c8452017-01-06 17:28:28 -0800349
350/**
351 * pld_pcie_suspend_noirq() - Complete the actions started by suspend()
352 * @pdev: PCI device
353 *
354 * Complete the actions started by suspend(). Carry out any additional
355 * operations required for suspending the device that might be racing
356 * with its driver's interrupt handler, which is guaranteed not to run
357 * while suspend_noirq() is being executed.
358 *
359 * Return: 0 for success
360 * Non zero failure code for errors
361 */
362static int pld_pcie_suspend_noirq(struct pci_dev *pdev)
363{
364 struct pld_context *pld_context;
365
366 pld_context = pld_get_global_context();
367 if (!pld_context)
368 return -EINVAL;
369
370 if (pld_context->ops->suspend_noirq)
371 return pld_context->ops->
372 suspend_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
373 return 0;
374}
375
376/**
377 * pld_pcie_resume_noirq() - Prepare for the execution of resume()
378 * @pdev: PCI device
379 *
380 * Prepare for the execution of resume() by carrying out any additional
381 * operations required for resuming the device that might be racing with
382 * its driver's interrupt handler, which is guaranteed not to run while
383 * resume_noirq() is being executed.
384 *
385 * Return: 0 for success
386 * Non zero failure code for errors
387 */
388static int pld_pcie_resume_noirq(struct pci_dev *pdev)
389{
390 struct pld_context *pld_context;
391
392 pld_context = pld_get_global_context();
393 if (!pld_context)
394 return -EINVAL;
395
396 if (pld_context->ops->resume_noirq)
397 return pld_context->ops->
398 resume_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE);
399 return 0;
400}
Yue Ma52d355c2017-01-25 14:49:23 -0800401#else
402/**
403 * pld_pcie_pm_suspend() - Suspend callback function for power management
404 * @dev: device
405 *
406 * This function is to suspend the PCIE device when power management is
407 * enabled.
408 *
409 * Return: 0 for success
410 * Non zero failure code for errors
411 */
412static int pld_pcie_pm_suspend(struct device *dev)
413{
414 struct pld_context *pld_context;
415
416 pm_message_t state = { .event = PM_EVENT_SUSPEND };
417
418 pld_context = pld_get_global_context();
419 return pld_context->ops->suspend(dev, PLD_BUS_TYPE_PCIE, state);
420}
421
422/**
423 * pld_pcie_pm_resume() - Resume callback function for power management
424 * @dev: device
425 *
426 * This function is to resume the PCIE device when power management is
427 * enabled.
428 *
429 * Return: 0 for success
430 * Non zero failure code for errors
431 */
432static int pld_pcie_pm_resume(struct device *dev)
433{
434 struct pld_context *pld_context;
435
436 pld_context = pld_get_global_context();
437 return pld_context->ops->resume(dev, PLD_BUS_TYPE_PCIE);
438}
439
440/**
441 * pld_pcie_pm_suspend_noirq() - Complete the actions started by suspend()
442 * @dev: device
443 *
444 * Complete the actions started by suspend(). Carry out any additional
445 * operations required for suspending the device that might be racing
446 * with its driver's interrupt handler, which is guaranteed not to run
447 * while suspend_noirq() is being executed.
448 *
449 * Return: 0 for success
450 * Non zero failure code for errors
451 */
452static int pld_pcie_pm_suspend_noirq(struct device *dev)
453{
454 struct pld_context *pld_context;
455
456 pld_context = pld_get_global_context();
457 if (!pld_context)
458 return -EINVAL;
459
460 if (pld_context->ops->suspend_noirq)
461 return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_PCIE);
462 return 0;
463}
464
465/**
466 * pld_pcie_pm_resume_noirq() - Prepare for the execution of resume()
467 * @dev: device
468 *
469 * Prepare for the execution of resume() by carrying out any additional
470 * operations required for resuming the device that might be racing with
471 * its driver's interrupt handler, which is guaranteed not to run while
472 * resume_noirq() is being executed.
473 *
474 * Return: 0 for success
475 * Non zero failure code for errors
476 */
477static int pld_pcie_pm_resume_noirq(struct device *dev)
478{
479 struct pld_context *pld_context;
480
481 pld_context = pld_get_global_context();
482 if (!pld_context)
483 return -EINVAL;
484
485 if (pld_context->ops->resume_noirq)
486 return pld_context->ops->
487 resume_noirq(dev, PLD_BUS_TYPE_PCIE);
488 return 0;
489}
490#endif
Yuanyuan Liu25c66e12016-05-13 10:17:46 -0700491#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800492
493static struct pci_device_id pld_pcie_id_table[] = {
Kai Liu0ef480d2020-03-22 18:50:03 +0800494#ifdef CONFIG_AR6320_SUPPORT
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800495 { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID },
Kai Liu0ef480d2020-03-22 18:50:03 +0800496#elif defined(QCA_WIFI_QCA6290)
497 { 0x17cb, 0x1100, PCI_ANY_ID, PCI_ANY_ID },
498#elif defined(QCA_WIFI_QCA6390)
499 { 0x17cb, 0x1101, PCI_ANY_ID, PCI_ANY_ID },
500#elif defined(QCA_WIFI_QCA6490)
501 { 0x17cb, 0x1103, PCI_ANY_ID, PCI_ANY_ID },
502#elif defined(QCN7605_SUPPORT)
503 { 0x17cb, 0x1102, PCI_ANY_ID, PCI_ANY_ID },
504#else
505 { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID },
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800506 { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID },
507 { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID },
508 { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID },
Kai Liu0ef480d2020-03-22 18:50:03 +0800509#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800510 { 0 }
511};
512
Manikandan Mohan04459b92018-02-23 16:32:48 -0800513#ifdef MULTI_IF_NAME
514#define PLD_PCIE_OPS_NAME "pld_pcie_" MULTI_IF_NAME
515#else
516#define PLD_PCIE_OPS_NAME "pld_pcie"
517#endif
518
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700519#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700520#ifdef FEATURE_RUNTIME_PM
521struct cnss_wlan_runtime_ops runtime_pm_ops = {
522 .runtime_suspend = pld_pcie_runtime_suspend,
523 .runtime_resume = pld_pcie_runtime_resume,
524};
525#endif
526
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800527struct cnss_wlan_driver pld_pcie_ops = {
Manikandan Mohan04459b92018-02-23 16:32:48 -0800528 .name = PLD_PCIE_OPS_NAME,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800529 .id_table = pld_pcie_id_table,
530 .probe = pld_pcie_probe,
531 .remove = pld_pcie_remove,
Rajeev Kumar588a2542019-04-08 10:57:19 -0700532 .idle_restart = pld_pcie_idle_restart_cb,
533 .idle_shutdown = pld_pcie_idle_shutdown_cb,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800534 .reinit = pld_pcie_reinit,
535 .shutdown = pld_pcie_shutdown,
536 .crash_shutdown = pld_pcie_crash_shutdown,
537 .modem_status = pld_pcie_notify_handler,
Anurag Chouhan1ddb9b32017-04-13 13:57:09 +0530538 .update_status = pld_pcie_uevent,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800539#ifdef CONFIG_PM
540 .suspend = pld_pcie_suspend,
541 .resume = pld_pcie_resume,
Yue Mae42c8452017-01-06 17:28:28 -0800542 .suspend_noirq = pld_pcie_suspend_noirq,
543 .resume_noirq = pld_pcie_resume_noirq,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800544#endif
Yuanyuan Liud698eb62016-04-11 11:43:30 -0700545#ifdef FEATURE_RUNTIME_PM
546 .runtime_ops = &runtime_pm_ops,
547#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800548};
549
550/**
551 * pld_pcie_register_driver() - Register PCIE device callback functions
552 *
553 * Return: int
554 */
555int pld_pcie_register_driver(void)
556{
557 return cnss_wlan_register_driver(&pld_pcie_ops);
558}
559
560/**
561 * pld_pcie_unregister_driver() - Unregister PCIE device callback functions
562 *
563 * Return: void
564 */
565void pld_pcie_unregister_driver(void)
566{
567 cnss_wlan_unregister_driver(&pld_pcie_ops);
568}
569#else
Yue Ma52d355c2017-01-25 14:49:23 -0800570#ifdef CONFIG_PM
571static const struct dev_pm_ops pld_pm_ops = {
572 SET_SYSTEM_SLEEP_PM_OPS(pld_pcie_pm_suspend, pld_pcie_pm_resume)
573 .suspend_noirq = pld_pcie_pm_suspend_noirq,
574 .resume_noirq = pld_pcie_pm_resume_noirq,
575};
576#endif
577
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800578struct pci_driver pld_pcie_ops = {
Manikandan Mohan04459b92018-02-23 16:32:48 -0800579 .name = PLD_PCIE_OPS_NAME,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800580 .id_table = pld_pcie_id_table,
581 .probe = pld_pcie_probe,
582 .remove = pld_pcie_remove,
Yue Ma52d355c2017-01-25 14:49:23 -0800583 .driver = {
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800584#ifdef CONFIG_PM
Yue Ma52d355c2017-01-25 14:49:23 -0800585 .pm = &pld_pm_ops,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800586#endif
Yue Ma52d355c2017-01-25 14:49:23 -0800587 },
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800588};
589
590int pld_pcie_register_driver(void)
591{
592 return pci_register_driver(&pld_pcie_ops);
593}
594
595void pld_pcie_unregister_driver(void)
596{
597 pci_unregister_driver(&pld_pcie_ops);
598}
599#endif
600
601/**
602 * pld_pcie_get_ce_id() - Get CE number for the provided IRQ
Yue Ma85761e62017-10-30 11:13:45 -0700603 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800604 * @irq: IRQ number
605 *
606 * Return: CE number
607 */
Yue Ma85761e62017-10-30 11:13:45 -0700608int pld_pcie_get_ce_id(struct device *dev, int irq)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800609{
610 int ce_id = irq - 100;
Manikandan Mohan8cf50612017-04-10 13:23:32 -0700611
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800612 if (ce_id < CE_COUNT_MAX && ce_id >= 0)
613 return ce_id;
614
615 return -EINVAL;
616}
617
Yuanyuan Liu11f526a2016-05-18 10:22:07 -0700618#ifdef CONFIG_PLD_PCIE_CNSS
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800619/**
620 * pld_pcie_wlan_enable() - Enable WLAN
Yue Ma85761e62017-10-30 11:13:45 -0700621 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800622 * @config: WLAN configuration data
623 * @mode: WLAN mode
624 * @host_version: host software version
625 *
626 * This function enables WLAN FW. It passed WLAN configuration data,
627 * WLAN mode and host software version to FW.
628 *
629 * Return: 0 for success
630 * Non zero failure code for errors
631 */
Yue Ma08047522016-11-08 18:53:26 -0800632int pld_pcie_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800633 enum pld_driver_mode mode, const char *host_version)
634{
635 struct cnss_wlan_enable_cfg cfg;
636 enum cnss_driver_mode cnss_mode;
637
638 cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
639 cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *)
640 config->ce_tgt_cfg;
641 cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
642 cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *)
643 config->ce_svc_cfg;
644 cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
645 cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *)
646 config->shadow_reg_cfg;
Yue Ma502a28f2017-01-03 16:38:44 -0800647 cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg;
648 cfg.shadow_reg_v2_cfg = (struct cnss_shadow_reg_v2_cfg *)
649 config->shadow_reg_v2_cfg;
Nirav Shaha6c6dc92018-07-09 16:26:02 +0530650 cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid;
651 if (config->rri_over_ddr_cfg_valid) {
652 cfg.rri_over_ddr_cfg.base_addr_low =
653 config->rri_over_ddr_cfg.base_addr_low;
654 cfg.rri_over_ddr_cfg.base_addr_high =
655 config->rri_over_ddr_cfg.base_addr_high;
656 }
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800657
658 switch (mode) {
659 case PLD_FTM:
660 cnss_mode = CNSS_FTM;
661 break;
662 case PLD_EPPING:
663 cnss_mode = CNSS_EPPING;
664 break;
665 default:
666 cnss_mode = CNSS_MISSION;
667 break;
668 }
Yue Ma08047522016-11-08 18:53:26 -0800669 return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800670}
671
672/**
673 * pld_pcie_wlan_disable() - Disable WLAN
Yue Ma85761e62017-10-30 11:13:45 -0700674 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800675 * @mode: WLAN mode
676 *
677 * This function disables WLAN FW. It passes WLAN mode to FW.
678 *
679 * Return: 0 for success
680 * Non zero failure code for errors
681 */
Yue Ma08047522016-11-08 18:53:26 -0800682int pld_pcie_wlan_disable(struct device *dev, enum pld_driver_mode mode)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800683{
Yue Ma08047522016-11-08 18:53:26 -0800684 return cnss_wlan_disable(dev, CNSS_OFF);
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800685}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800686
687/**
688 * pld_pcie_get_fw_files_for_target() - Get FW file names
Yue Ma85761e62017-10-30 11:13:45 -0700689 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800690 * @pfw_files: buffer for FW file names
691 * @target_type: target type
692 * @target_version: target version
693 *
694 * Return target specific FW file names to the buffer.
695 *
696 * Return: 0 for success
697 * Non zero failure code for errors
698 */
Yue Ma85761e62017-10-30 11:13:45 -0700699int pld_pcie_get_fw_files_for_target(struct device *dev,
700 struct pld_fw_files *pfw_files,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800701 u32 target_type, u32 target_version)
702{
703 int ret = 0;
704 struct cnss_fw_files cnss_fw_files;
705
Jeff Johnson753f9d72019-03-18 13:41:04 -0700706 if (!pfw_files)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800707 return -ENODEV;
708
Yuanyuan Liu6a313dc2016-05-10 14:19:10 -0700709 memset(pfw_files, 0, sizeof(*pfw_files));
710
Yue Ma85761e62017-10-30 11:13:45 -0700711 ret = cnss_get_fw_files_for_target(dev, &cnss_fw_files,
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800712 target_type, target_version);
Yue Ma85761e62017-10-30 11:13:45 -0700713 if (ret)
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800714 return ret;
715
Qun Zhang4a83a462018-09-11 16:28:51 +0800716 scnprintf(pfw_files->image_file, PLD_MAX_FILE_NAME, PREFIX "%s",
717 cnss_fw_files.image_file);
718 scnprintf(pfw_files->board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
719 cnss_fw_files.board_data);
720 scnprintf(pfw_files->otp_data, PLD_MAX_FILE_NAME, PREFIX "%s",
721 cnss_fw_files.otp_data);
722 scnprintf(pfw_files->utf_file, PLD_MAX_FILE_NAME, PREFIX "%s",
723 cnss_fw_files.utf_file);
724 scnprintf(pfw_files->utf_board_data, PLD_MAX_FILE_NAME, PREFIX "%s",
725 cnss_fw_files.utf_board_data);
726 scnprintf(pfw_files->epping_file, PLD_MAX_FILE_NAME, PREFIX "%s",
727 cnss_fw_files.epping_file);
728 scnprintf(pfw_files->evicted_data, PLD_MAX_FILE_NAME, PREFIX "%s",
729 cnss_fw_files.evicted_data);
Yuanyuan Liu6a313dc2016-05-10 14:19:10 -0700730
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800731 return 0;
732}
733
734/**
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800735 * pld_pcie_get_platform_cap() - Get platform capabilities
Yue Ma85761e62017-10-30 11:13:45 -0700736 * @dev: device
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800737 * @cap: buffer to the capabilities
738 *
739 * Return capabilities to the buffer.
740 *
741 * Return: 0 for success
742 * Non zero failure code for errors
743 */
Yue Ma85761e62017-10-30 11:13:45 -0700744int pld_pcie_get_platform_cap(struct device *dev, struct pld_platform_cap *cap)
745{
746 int ret = 0;
747 struct cnss_platform_cap cnss_cap;
748
Jeff Johnson753f9d72019-03-18 13:41:04 -0700749 if (!cap)
Yue Ma85761e62017-10-30 11:13:45 -0700750 return -ENODEV;
751
752 ret = cnss_get_platform_cap(dev, &cnss_cap);
753 if (ret)
754 return ret;
755
756 memcpy(cap, &cnss_cap, sizeof(*cap));
757 return 0;
758}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800759
760/**
Yue Macd243862016-11-04 19:21:16 -0700761 * pld_pcie_get_soc_info() - Get SOC information
Yue Ma85761e62017-10-30 11:13:45 -0700762 * @dev: device
Yue Macd243862016-11-04 19:21:16 -0700763 * @info: buffer to SOC information
764 *
765 * Return SOC info to the buffer.
766 *
767 * Return: 0 for success
768 * Non zero failure code for errors
769 */
770int pld_pcie_get_soc_info(struct device *dev, struct pld_soc_info *info)
771{
772 int ret = 0;
lihual8b9daf22018-04-02 15:18:54 +0800773 struct cnss_soc_info cnss_info = {0};
Yue Macd243862016-11-04 19:21:16 -0700774
Jeff Johnson753f9d72019-03-18 13:41:04 -0700775 if (!info)
Yue Macd243862016-11-04 19:21:16 -0700776 return -ENODEV;
777
778 ret = cnss_get_soc_info(dev, &cnss_info);
779 if (ret)
780 return ret;
781
Frank Liu0e7ac562018-06-15 15:29:49 +0800782 info->v_addr = cnss_info.va;
783 info->p_addr = cnss_info.pa;
784 info->chip_id = cnss_info.chip_id;
785 info->chip_family = cnss_info.chip_family;
786 info->board_id = cnss_info.board_id;
787 info->soc_id = cnss_info.soc_id;
788 info->fw_version = cnss_info.fw_version;
789 strlcpy(info->fw_build_timestamp, cnss_info.fw_build_timestamp,
790 sizeof(info->fw_build_timestamp));
Yue Mab4ebd872019-04-17 14:55:59 -0700791 info->device_version.family_number =
792 cnss_info.device_version.family_number;
793 info->device_version.device_number =
794 cnss_info.device_version.device_number;
795 info->device_version.major_version =
796 cnss_info.device_version.major_version;
797 info->device_version.minor_version =
798 cnss_info.device_version.minor_version;
Yue Macd243862016-11-04 19:21:16 -0700799
800 return 0;
801}
802
803/**
Yuanyuan Liu10fc3d32017-01-12 15:32:06 -0800804 * pld_pcie_schedule_recovery_work() - schedule recovery work
805 * @dev: device
806 * @reason: recovery reason
807 *
808 * Return: void
809 */
810void pld_pcie_schedule_recovery_work(struct device *dev,
811 enum pld_recovery_reason reason)
812{
813 enum cnss_recovery_reason cnss_reason;
814
815 switch (reason) {
816 case PLD_REASON_LINK_DOWN:
817 cnss_reason = CNSS_REASON_LINK_DOWN;
818 break;
819 default:
820 cnss_reason = CNSS_REASON_DEFAULT;
821 break;
822 }
823 cnss_schedule_recovery(dev, cnss_reason);
824}
825
826/**
827 * pld_pcie_device_self_recovery() - device self recovery
828 * @dev: device
829 * @reason: recovery reason
830 *
831 * Return: void
832 */
833void pld_pcie_device_self_recovery(struct device *dev,
834 enum pld_recovery_reason reason)
835{
836 enum cnss_recovery_reason cnss_reason;
837
838 switch (reason) {
839 case PLD_REASON_LINK_DOWN:
840 cnss_reason = CNSS_REASON_LINK_DOWN;
841 break;
842 default:
843 cnss_reason = CNSS_REASON_DEFAULT;
844 break;
845 }
846 cnss_self_recovery(dev, cnss_reason);
847}
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800848#endif
Yuanyuan Liud9f7a362016-01-22 14:27:12 -0800849#endif