xref: /wlan-driver/qcacld-3.0/core/pld/src/pld_ipci.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name #include <linux/platform_device.h>
21*5113495bSYour Name #include <linux/err.h>
22*5113495bSYour Name #include <linux/list.h>
23*5113495bSYour Name #include <linux/slab.h>
24*5113495bSYour Name 
25*5113495bSYour Name #ifdef CONFIG_PLD_IPCI_ICNSS
26*5113495bSYour Name #ifdef CONFIG_CNSS_OUT_OF_TREE
27*5113495bSYour Name #include "icnss2.h"
28*5113495bSYour Name #else
29*5113495bSYour Name #include <soc/qcom/icnss2.h>
30*5113495bSYour Name #endif
31*5113495bSYour Name #endif
32*5113495bSYour Name 
33*5113495bSYour Name #include "pld_internal.h"
34*5113495bSYour Name #include "pld_ipci.h"
35*5113495bSYour Name #include "osif_psoc_sync.h"
36*5113495bSYour Name 
37*5113495bSYour Name #ifdef CONFIG_PLD_IPCI_ICNSS
38*5113495bSYour Name 
39*5113495bSYour Name #define WCN6750_DEVICE_ID 0x6750
40*5113495bSYour Name #define WCN6450_DEVICE_ID 0x6450
41*5113495bSYour Name /**
42*5113495bSYour Name  * pld_ipci_probe() - Probe function for platform driver
43*5113495bSYour Name  * @dev: device
44*5113495bSYour Name  *
45*5113495bSYour Name  * The probe function will be called when platform device
46*5113495bSYour Name  * is detected.
47*5113495bSYour Name  *
48*5113495bSYour Name  * Return: int
49*5113495bSYour Name  */
pld_ipci_probe(struct device * dev)50*5113495bSYour Name static int pld_ipci_probe(struct device *dev)
51*5113495bSYour Name {
52*5113495bSYour Name 	struct pld_context *pld_context;
53*5113495bSYour Name 	int ret = 0;
54*5113495bSYour Name 
55*5113495bSYour Name 	pld_context = pld_get_global_context();
56*5113495bSYour Name 	if (!pld_context) {
57*5113495bSYour Name 		ret = -ENODEV;
58*5113495bSYour Name 		goto out;
59*5113495bSYour Name 	}
60*5113495bSYour Name 
61*5113495bSYour Name 	ret = pld_add_dev(pld_context, dev, NULL, PLD_BUS_TYPE_IPCI);
62*5113495bSYour Name 	if (ret)
63*5113495bSYour Name 		goto out;
64*5113495bSYour Name 
65*5113495bSYour Name 	return pld_context->ops->probe(dev, PLD_BUS_TYPE_IPCI,
66*5113495bSYour Name 				       NULL, NULL);
67*5113495bSYour Name 
68*5113495bSYour Name out:
69*5113495bSYour Name 	return ret;
70*5113495bSYour Name }
71*5113495bSYour Name 
72*5113495bSYour Name /**
73*5113495bSYour Name  * pld_ipci_remove() - Remove function for platform device
74*5113495bSYour Name  * @dev: device
75*5113495bSYour Name  *
76*5113495bSYour Name  * The remove function will be called when platform device
77*5113495bSYour Name  * is disconnected
78*5113495bSYour Name  *
79*5113495bSYour Name  * Return: void
80*5113495bSYour Name  */
pld_ipci_remove(struct device * dev)81*5113495bSYour Name static void pld_ipci_remove(struct device *dev)
82*5113495bSYour Name {
83*5113495bSYour Name 	struct pld_context *pld_context;
84*5113495bSYour Name 	int errno;
85*5113495bSYour Name 	struct osif_psoc_sync *psoc_sync;
86*5113495bSYour Name 
87*5113495bSYour Name 	errno = osif_psoc_sync_trans_start_wait(dev, &psoc_sync);
88*5113495bSYour Name 	if (errno)
89*5113495bSYour Name 		return;
90*5113495bSYour Name 
91*5113495bSYour Name 	osif_psoc_sync_unregister(dev);
92*5113495bSYour Name 	osif_psoc_sync_wait_for_ops(psoc_sync);
93*5113495bSYour Name 
94*5113495bSYour Name 	pld_context = pld_get_global_context();
95*5113495bSYour Name 
96*5113495bSYour Name 	if (!pld_context)
97*5113495bSYour Name 		goto out;
98*5113495bSYour Name 
99*5113495bSYour Name 	pld_context->ops->remove(dev, PLD_BUS_TYPE_SNOC);
100*5113495bSYour Name 
101*5113495bSYour Name 	pld_del_dev(pld_context, dev);
102*5113495bSYour Name 
103*5113495bSYour Name out:
104*5113495bSYour Name 	osif_psoc_sync_trans_stop(psoc_sync);
105*5113495bSYour Name 	osif_psoc_sync_destroy(psoc_sync);
106*5113495bSYour Name }
107*5113495bSYour Name 
108*5113495bSYour Name /**
109*5113495bSYour Name  * pld_ipci_reinit() - SSR re-initialize function for platform device
110*5113495bSYour Name  * @dev: device
111*5113495bSYour Name  *
112*5113495bSYour Name  * During subsystem restart(SSR), this function will be called to
113*5113495bSYour Name  * re-initialize platform device.
114*5113495bSYour Name  *
115*5113495bSYour Name  * Return: int
116*5113495bSYour Name  */
pld_ipci_reinit(struct device * dev)117*5113495bSYour Name static int pld_ipci_reinit(struct device *dev)
118*5113495bSYour Name {
119*5113495bSYour Name 	struct pld_context *pld_context;
120*5113495bSYour Name 
121*5113495bSYour Name 	pld_context = pld_get_global_context();
122*5113495bSYour Name 	if (pld_context->ops->reinit)
123*5113495bSYour Name 		return pld_context->ops->reinit(dev, PLD_BUS_TYPE_IPCI,
124*5113495bSYour Name 						NULL, NULL);
125*5113495bSYour Name 
126*5113495bSYour Name 	return -ENODEV;
127*5113495bSYour Name }
128*5113495bSYour Name 
129*5113495bSYour Name /**
130*5113495bSYour Name  * pld_ipci_shutdown() - SSR shutdown function for platform device
131*5113495bSYour Name  * @dev: device
132*5113495bSYour Name  *
133*5113495bSYour Name  * During SSR, this function will be called to shutdown platform device.
134*5113495bSYour Name  *
135*5113495bSYour Name  * Return: void
136*5113495bSYour Name  */
pld_ipci_shutdown(struct device * dev)137*5113495bSYour Name static void pld_ipci_shutdown(struct device *dev)
138*5113495bSYour Name {
139*5113495bSYour Name 	struct pld_context *pld_context;
140*5113495bSYour Name 
141*5113495bSYour Name 	pld_context = pld_get_global_context();
142*5113495bSYour Name 	if (pld_context->ops->shutdown)
143*5113495bSYour Name 		pld_context->ops->shutdown(dev, PLD_BUS_TYPE_IPCI);
144*5113495bSYour Name }
145*5113495bSYour Name 
146*5113495bSYour Name /**
147*5113495bSYour Name  * pld_ipci_crash_shutdown() - Crash shutdown function for platform device
148*5113495bSYour Name  * @dev: device
149*5113495bSYour Name  *
150*5113495bSYour Name  * This function will be called when a crash is detected, it will shutdown
151*5113495bSYour Name  * platform device.
152*5113495bSYour Name  *
153*5113495bSYour Name  * Return: void
154*5113495bSYour Name  */
pld_ipci_crash_shutdown(void * dev)155*5113495bSYour Name static void pld_ipci_crash_shutdown(void *dev)
156*5113495bSYour Name {
157*5113495bSYour Name 	struct pld_context *pld_context;
158*5113495bSYour Name 
159*5113495bSYour Name 	pld_context = pld_get_global_context();
160*5113495bSYour Name 	if (pld_context->ops->crash_shutdown)
161*5113495bSYour Name 		pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_IPCI);
162*5113495bSYour Name }
163*5113495bSYour Name 
164*5113495bSYour Name /**
165*5113495bSYour Name  * pld_ipci_pm_suspend() - PM suspend callback function for power management
166*5113495bSYour Name  * @dev: device
167*5113495bSYour Name  *
168*5113495bSYour Name  * This function is to suspend the platform device when power management
169*5113495bSYour Name  * is enabled.
170*5113495bSYour Name  *
171*5113495bSYour Name  * Return: void
172*5113495bSYour Name  */
pld_ipci_pm_suspend(struct device * dev)173*5113495bSYour Name static int pld_ipci_pm_suspend(struct device *dev)
174*5113495bSYour Name {
175*5113495bSYour Name 	struct pld_context *pld_context;
176*5113495bSYour Name 	pm_message_t state;
177*5113495bSYour Name 
178*5113495bSYour Name 	state.event = PM_EVENT_SUSPEND;
179*5113495bSYour Name 	pld_context = pld_get_global_context();
180*5113495bSYour Name 	return pld_context->ops->suspend(dev, PLD_BUS_TYPE_IPCI, state);
181*5113495bSYour Name }
182*5113495bSYour Name 
183*5113495bSYour Name /**
184*5113495bSYour Name  * pld_ipci_pm_resume() - PM resume callback function for power management
185*5113495bSYour Name  * @dev: device
186*5113495bSYour Name  *
187*5113495bSYour Name  * This function is to resume the platform device when power management
188*5113495bSYour Name  * is enabled.
189*5113495bSYour Name  *
190*5113495bSYour Name  * Return: void
191*5113495bSYour Name  */
pld_ipci_pm_resume(struct device * dev)192*5113495bSYour Name static int pld_ipci_pm_resume(struct device *dev)
193*5113495bSYour Name {
194*5113495bSYour Name 	struct pld_context *pld_context;
195*5113495bSYour Name 
196*5113495bSYour Name 	pld_context = pld_get_global_context();
197*5113495bSYour Name 	return pld_context->ops->resume(dev, PLD_BUS_TYPE_IPCI);
198*5113495bSYour Name }
199*5113495bSYour Name 
200*5113495bSYour Name /**
201*5113495bSYour Name  * pld_ipci_suspend_noirq() - Complete the actions started by suspend()
202*5113495bSYour Name  * @dev: device
203*5113495bSYour Name  *
204*5113495bSYour Name  * Complete the actions started by suspend().  Carry out any
205*5113495bSYour Name  * additional operations required for suspending the device that might be
206*5113495bSYour Name  * racing with its driver's interrupt handler, which is guaranteed not to
207*5113495bSYour Name  * run while suspend_noirq() is being executed.
208*5113495bSYour Name  *
209*5113495bSYour Name  * Return: 0 for success
210*5113495bSYour Name  *         Non zero failure code for errors
211*5113495bSYour Name  */
pld_ipci_suspend_noirq(struct device * dev)212*5113495bSYour Name static int pld_ipci_suspend_noirq(struct device *dev)
213*5113495bSYour Name {
214*5113495bSYour Name 	struct pld_context *pld_context;
215*5113495bSYour Name 
216*5113495bSYour Name 	pld_context = pld_get_global_context();
217*5113495bSYour Name 	if (!pld_context)
218*5113495bSYour Name 		return -EINVAL;
219*5113495bSYour Name 
220*5113495bSYour Name 	if (pld_context->ops->suspend_noirq)
221*5113495bSYour Name 		return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_IPCI);
222*5113495bSYour Name 	return 0;
223*5113495bSYour Name }
224*5113495bSYour Name 
225*5113495bSYour Name /**
226*5113495bSYour Name  * pld_ipci_resume_noirq() - Prepare for the execution of resume()
227*5113495bSYour Name  * @dev: device
228*5113495bSYour Name  *
229*5113495bSYour Name  * Prepare for the execution of resume() by carrying out any
230*5113495bSYour Name  * operations required for resuming the device that might be racing with
231*5113495bSYour Name  * its driver's interrupt handler, which is guaranteed not to run while
232*5113495bSYour Name  * resume_noirq() is being executed.
233*5113495bSYour Name  *
234*5113495bSYour Name  * Return: 0 for success
235*5113495bSYour Name  *         Non zero failure code for errors
236*5113495bSYour Name  */
pld_ipci_resume_noirq(struct device * dev)237*5113495bSYour Name static int pld_ipci_resume_noirq(struct device *dev)
238*5113495bSYour Name {
239*5113495bSYour Name 	struct pld_context *pld_context;
240*5113495bSYour Name 
241*5113495bSYour Name 	pld_context = pld_get_global_context();
242*5113495bSYour Name 	if (!pld_context)
243*5113495bSYour Name 		return -EINVAL;
244*5113495bSYour Name 
245*5113495bSYour Name 	if (pld_context->ops->resume_noirq)
246*5113495bSYour Name 		return pld_context->ops->resume_noirq(dev, PLD_BUS_TYPE_IPCI);
247*5113495bSYour Name 
248*5113495bSYour Name 	return 0;
249*5113495bSYour Name }
250*5113495bSYour Name 
251*5113495bSYour Name /**
252*5113495bSYour Name  * pld_ipci_runtime_suspend() - Runtime suspend callback for power management
253*5113495bSYour Name  * @dev: device
254*5113495bSYour Name  *
255*5113495bSYour Name  * This function is to runtime suspend the platform device when power management
256*5113495bSYour Name  * is enabled.
257*5113495bSYour Name  *
258*5113495bSYour Name  * Return: status
259*5113495bSYour Name  */
pld_ipci_runtime_suspend(struct device * dev)260*5113495bSYour Name static int pld_ipci_runtime_suspend(struct device *dev)
261*5113495bSYour Name {
262*5113495bSYour Name 	struct pld_context *pld_context;
263*5113495bSYour Name 
264*5113495bSYour Name 	pld_context = pld_get_global_context();
265*5113495bSYour Name 	if (!pld_context)
266*5113495bSYour Name 		return -EINVAL;
267*5113495bSYour Name 
268*5113495bSYour Name 	if (pld_context->ops && pld_context->ops->runtime_suspend)
269*5113495bSYour Name 		return pld_context->ops->runtime_suspend(dev,
270*5113495bSYour Name 							 PLD_BUS_TYPE_IPCI);
271*5113495bSYour Name 
272*5113495bSYour Name 	return 0;
273*5113495bSYour Name }
274*5113495bSYour Name 
275*5113495bSYour Name /**
276*5113495bSYour Name  * pld_ipci_runtime_resume() - Runtime resume callback for power management
277*5113495bSYour Name  * @dev: device
278*5113495bSYour Name  *
279*5113495bSYour Name  * This function is to runtime resume the platform device when power management
280*5113495bSYour Name  * is enabled.
281*5113495bSYour Name  *
282*5113495bSYour Name  * Return: status
283*5113495bSYour Name  */
pld_ipci_runtime_resume(struct device * dev)284*5113495bSYour Name static int pld_ipci_runtime_resume(struct device *dev)
285*5113495bSYour Name {
286*5113495bSYour Name 	struct pld_context *pld_context;
287*5113495bSYour Name 
288*5113495bSYour Name 	pld_context = pld_get_global_context();
289*5113495bSYour Name 	if (!pld_context)
290*5113495bSYour Name 		return -EINVAL;
291*5113495bSYour Name 
292*5113495bSYour Name 	if (pld_context->ops && pld_context->ops->runtime_resume)
293*5113495bSYour Name 		return pld_context->ops->runtime_resume(dev, PLD_BUS_TYPE_IPCI);
294*5113495bSYour Name 
295*5113495bSYour Name 	return 0;
296*5113495bSYour Name }
297*5113495bSYour Name 
298*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))
pld_update_hang_evt_data(struct icnss_uevent_hang_data * evt_data,struct pld_uevent_data * data)299*5113495bSYour Name static int pld_update_hang_evt_data(struct icnss_uevent_hang_data *evt_data,
300*5113495bSYour Name 				    struct pld_uevent_data *data)
301*5113495bSYour Name {
302*5113495bSYour Name 	if (!evt_data || !data)
303*5113495bSYour Name 		return -EINVAL;
304*5113495bSYour Name 
305*5113495bSYour Name 	data->hang_data.hang_event_data = evt_data->hang_event_data;
306*5113495bSYour Name 	data->hang_data.hang_event_data_len = evt_data->hang_event_data_len;
307*5113495bSYour Name 	return 0;
308*5113495bSYour Name }
309*5113495bSYour Name 
pld_ipci_uevent(struct device * dev,struct icnss_uevent_data * uevent)310*5113495bSYour Name static int pld_ipci_uevent(struct device *dev,
311*5113495bSYour Name 			   struct icnss_uevent_data *uevent)
312*5113495bSYour Name {
313*5113495bSYour Name 	struct pld_context *pld_context;
314*5113495bSYour Name 	struct icnss_uevent_fw_down_data *uevent_data = NULL;
315*5113495bSYour Name 	struct pld_uevent_data data = {0};
316*5113495bSYour Name 	struct icnss_uevent_hang_data *hang_data = NULL;
317*5113495bSYour Name 
318*5113495bSYour Name 	pld_context = pld_get_global_context();
319*5113495bSYour Name 	if (!pld_context)
320*5113495bSYour Name 		return -EINVAL;
321*5113495bSYour Name 
322*5113495bSYour Name 	if (!pld_context->ops->uevent)
323*5113495bSYour Name 		goto out;
324*5113495bSYour Name 
325*5113495bSYour Name 	if (!uevent)
326*5113495bSYour Name 		return -EINVAL;
327*5113495bSYour Name 
328*5113495bSYour Name 	switch (uevent->uevent) {
329*5113495bSYour Name 	case ICNSS_UEVENT_FW_CRASHED:
330*5113495bSYour Name 		data.uevent = PLD_FW_CRASHED;
331*5113495bSYour Name 		break;
332*5113495bSYour Name 	case ICNSS_UEVENT_FW_DOWN:
333*5113495bSYour Name 		if (!uevent->data)
334*5113495bSYour Name 			return -EINVAL;
335*5113495bSYour Name 		uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data;
336*5113495bSYour Name 		data.uevent = PLD_FW_DOWN;
337*5113495bSYour Name 		data.fw_down.crashed = uevent_data->crashed;
338*5113495bSYour Name 		break;
339*5113495bSYour Name 	case ICNSS_UEVENT_HANG_DATA:
340*5113495bSYour Name 		if (!uevent->data)
341*5113495bSYour Name 			return -EINVAL;
342*5113495bSYour Name 		hang_data = (struct icnss_uevent_hang_data *)uevent->data;
343*5113495bSYour Name 		data.uevent = PLD_FW_HANG_EVENT;
344*5113495bSYour Name 		pld_update_hang_evt_data(hang_data, &data);
345*5113495bSYour Name 		break;
346*5113495bSYour Name 	case ICNSS_UEVENT_SMMU_FAULT:
347*5113495bSYour Name 		if (!uevent->data)
348*5113495bSYour Name 			return -EINVAL;
349*5113495bSYour Name 		uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data;
350*5113495bSYour Name 		data.uevent = PLD_SMMU_FAULT;
351*5113495bSYour Name 		data.fw_down.crashed = uevent_data->crashed;
352*5113495bSYour Name 		break;
353*5113495bSYour Name 	default:
354*5113495bSYour Name 		goto out;
355*5113495bSYour Name 	}
356*5113495bSYour Name 
357*5113495bSYour Name 	pld_context->ops->uevent(dev, &data);
358*5113495bSYour Name out:
359*5113495bSYour Name 	return 0;
360*5113495bSYour Name }
361*5113495bSYour Name #else
pld_ipci_uevent(struct device * dev,struct icnss_uevent_data * uevent)362*5113495bSYour Name static int pld_ipci_uevent(struct device *dev,
363*5113495bSYour Name 			   struct icnss_uevent_data *uevent)
364*5113495bSYour Name {
365*5113495bSYour Name 	struct pld_context *pld_context;
366*5113495bSYour Name 	struct icnss_uevent_fw_down_data *uevent_data = NULL;
367*5113495bSYour Name 	struct pld_uevent_data data = {0};
368*5113495bSYour Name 
369*5113495bSYour Name 	pld_context = pld_get_global_context();
370*5113495bSYour Name 	if (!pld_context)
371*5113495bSYour Name 		return -EINVAL;
372*5113495bSYour Name 
373*5113495bSYour Name 	if (!pld_context->ops->uevent)
374*5113495bSYour Name 		goto out;
375*5113495bSYour Name 
376*5113495bSYour Name 	if (!uevent)
377*5113495bSYour Name 		return -EINVAL;
378*5113495bSYour Name 
379*5113495bSYour Name 	switch (uevent->uevent) {
380*5113495bSYour Name 	case ICNSS_UEVENT_FW_CRASHED:
381*5113495bSYour Name 		data.uevent = PLD_FW_CRASHED;
382*5113495bSYour Name 		break;
383*5113495bSYour Name 	case ICNSS_UEVENT_FW_DOWN:
384*5113495bSYour Name 		if (!uevent->data)
385*5113495bSYour Name 			return -EINVAL;
386*5113495bSYour Name 		uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data;
387*5113495bSYour Name 		data.uevent = PLD_FW_DOWN;
388*5113495bSYour Name 		data.fw_down.crashed = uevent_data->crashed;
389*5113495bSYour Name 		break;
390*5113495bSYour Name 	default:
391*5113495bSYour Name 		goto out;
392*5113495bSYour Name 	}
393*5113495bSYour Name 
394*5113495bSYour Name 	pld_context->ops->uevent(dev, &data);
395*5113495bSYour Name out:
396*5113495bSYour Name 	return 0;
397*5113495bSYour Name }
398*5113495bSYour Name #endif
399*5113495bSYour Name 
400*5113495bSYour Name /**
401*5113495bSYour Name  * pld_ipci_idle_restart_cb() - Perform idle restart
402*5113495bSYour Name  * @dev: platform device
403*5113495bSYour Name  *
404*5113495bSYour Name  * This function will be called if there is an idle restart request
405*5113495bSYour Name  *
406*5113495bSYour Name  * Return: int
407*5113495bSYour Name  */
pld_ipci_idle_restart_cb(struct device * dev)408*5113495bSYour Name static int pld_ipci_idle_restart_cb(struct device *dev)
409*5113495bSYour Name {
410*5113495bSYour Name 	struct pld_context *pld_context;
411*5113495bSYour Name 
412*5113495bSYour Name 	pld_context = pld_get_global_context();
413*5113495bSYour Name 
414*5113495bSYour Name 	if (!pld_context)
415*5113495bSYour Name 		return -EINVAL;
416*5113495bSYour Name 
417*5113495bSYour Name 	if (pld_context->ops->idle_restart)
418*5113495bSYour Name 		return pld_context->ops->idle_restart(dev,
419*5113495bSYour Name 						      PLD_BUS_TYPE_IPCI);
420*5113495bSYour Name 
421*5113495bSYour Name 	return -ENODEV;
422*5113495bSYour Name }
423*5113495bSYour Name 
424*5113495bSYour Name /**
425*5113495bSYour Name  * pld_ipci_idle_shutdown_cb() - Perform idle shutdown
426*5113495bSYour Name  * @dev: PCIE device
427*5113495bSYour Name  *
428*5113495bSYour Name  * This function will be called if there is an idle shutdown request
429*5113495bSYour Name  *
430*5113495bSYour Name  * Return: int
431*5113495bSYour Name  */
pld_ipci_idle_shutdown_cb(struct device * dev)432*5113495bSYour Name static int pld_ipci_idle_shutdown_cb(struct device *dev)
433*5113495bSYour Name {
434*5113495bSYour Name 	struct pld_context *pld_context;
435*5113495bSYour Name 
436*5113495bSYour Name 	pld_context = pld_get_global_context();
437*5113495bSYour Name 
438*5113495bSYour Name 	if (!pld_context)
439*5113495bSYour Name 		return -EINVAL;
440*5113495bSYour Name 
441*5113495bSYour Name 	if (pld_context->ops->shutdown)
442*5113495bSYour Name 		return pld_context->ops->idle_shutdown(dev,
443*5113495bSYour Name 						       PLD_BUS_TYPE_IPCI);
444*5113495bSYour Name 
445*5113495bSYour Name 	return -ENODEV;
446*5113495bSYour Name }
447*5113495bSYour Name 
448*5113495bSYour Name /**
449*5113495bSYour Name  * pld_ipci_set_thermal_state() - Set thermal state for thermal mitigation
450*5113495bSYour Name  * @dev: device
451*5113495bSYour Name  * @thermal_state: Thermal state set by thermal subsystem
452*5113495bSYour Name  * @mon_id: Thermal cooling device ID
453*5113495bSYour Name  *
454*5113495bSYour Name  * This function will be called when thermal subsystem notifies platform
455*5113495bSYour Name  * driver about change in thermal state.
456*5113495bSYour Name  *
457*5113495bSYour Name  * Return: 0 for success
458*5113495bSYour Name  * Non zero failure code for errors
459*5113495bSYour Name  */
pld_ipci_set_thermal_state(struct device * dev,unsigned long thermal_state,int mon_id)460*5113495bSYour Name static int pld_ipci_set_thermal_state(struct device *dev,
461*5113495bSYour Name 				      unsigned long thermal_state,
462*5113495bSYour Name 				      int mon_id)
463*5113495bSYour Name {
464*5113495bSYour Name 	struct pld_context *pld_context;
465*5113495bSYour Name 
466*5113495bSYour Name 	pld_context = pld_get_global_context();
467*5113495bSYour Name 	if (!pld_context)
468*5113495bSYour Name 		return -EINVAL;
469*5113495bSYour Name 
470*5113495bSYour Name 	if (pld_context->ops->set_curr_therm_cdev_state)
471*5113495bSYour Name 		return pld_context->ops->set_curr_therm_cdev_state(dev,
472*5113495bSYour Name 							      thermal_state,
473*5113495bSYour Name 							      mon_id);
474*5113495bSYour Name 
475*5113495bSYour Name 	return -ENOTSUPP;
476*5113495bSYour Name }
477*5113495bSYour Name 
478*5113495bSYour Name #ifdef MULTI_IF_NAME
479*5113495bSYour Name #define PLD_IPCI_OPS_NAME "pld_ipci_" MULTI_IF_NAME
480*5113495bSYour Name #else
481*5113495bSYour Name #define PLD_IPCI_OPS_NAME "pld_ipci"
482*5113495bSYour Name #endif
483*5113495bSYour Name 
484*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
485*5113495bSYour Name static struct device_info pld_ipci_dev_info[] = {
486*5113495bSYour Name #ifdef QCA_WIFI_QCA6750
487*5113495bSYour Name 	{ "wcn6750", WCN6750_DEVICE_ID },
488*5113495bSYour Name #elif defined(QCA_WIFI_WCN6450)
489*5113495bSYour Name 	{ "wcn6450", WCN6450_DEVICE_ID },
490*5113495bSYour Name #endif
491*5113495bSYour Name 	{ { 0 } }
492*5113495bSYour Name };
493*5113495bSYour Name #endif
494*5113495bSYour Name 
495*5113495bSYour Name struct icnss_driver_ops pld_ipci_ops = {
496*5113495bSYour Name 	.name       = PLD_IPCI_OPS_NAME,
497*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0))
498*5113495bSYour Name 	.dev_info   = pld_ipci_dev_info,
499*5113495bSYour Name #endif
500*5113495bSYour Name 	.probe      = pld_ipci_probe,
501*5113495bSYour Name 	.remove     = pld_ipci_remove,
502*5113495bSYour Name 	.shutdown   = pld_ipci_shutdown,
503*5113495bSYour Name 	.reinit     = pld_ipci_reinit,
504*5113495bSYour Name 	.crash_shutdown = pld_ipci_crash_shutdown,
505*5113495bSYour Name 	.pm_suspend = pld_ipci_pm_suspend,
506*5113495bSYour Name 	.pm_resume  = pld_ipci_pm_resume,
507*5113495bSYour Name 	.suspend_noirq = pld_ipci_suspend_noirq,
508*5113495bSYour Name 	.resume_noirq = pld_ipci_resume_noirq,
509*5113495bSYour Name 	.runtime_suspend = pld_ipci_runtime_suspend,
510*5113495bSYour Name 	.runtime_resume  = pld_ipci_runtime_resume,
511*5113495bSYour Name 	.uevent = pld_ipci_uevent,
512*5113495bSYour Name 	.idle_restart = pld_ipci_idle_restart_cb,
513*5113495bSYour Name 	.idle_shutdown = pld_ipci_idle_shutdown_cb,
514*5113495bSYour Name 	.set_therm_cdev_state = pld_ipci_set_thermal_state,
515*5113495bSYour Name };
516*5113495bSYour Name 
pld_ipci_register_driver(void)517*5113495bSYour Name int pld_ipci_register_driver(void)
518*5113495bSYour Name {
519*5113495bSYour Name 	return icnss_register_driver(&pld_ipci_ops);
520*5113495bSYour Name }
521*5113495bSYour Name 
pld_ipci_unregister_driver(void)522*5113495bSYour Name void pld_ipci_unregister_driver(void)
523*5113495bSYour Name {
524*5113495bSYour Name 	icnss_unregister_driver(&pld_ipci_ops);
525*5113495bSYour Name }
526*5113495bSYour Name 
527*5113495bSYour Name #ifdef CONFIG_SHADOW_V3
528*5113495bSYour Name static inline void
pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg * cfg,struct pld_wlan_enable_cfg * config)529*5113495bSYour Name pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg *cfg,
530*5113495bSYour Name 				struct pld_wlan_enable_cfg *config)
531*5113495bSYour Name {
532*5113495bSYour Name 	cfg->num_shadow_reg_v3_cfg = config->num_shadow_reg_v3_cfg;
533*5113495bSYour Name 	cfg->shadow_reg_v3_cfg = (struct icnss_shadow_reg_v3_cfg *)
534*5113495bSYour Name 				 config->shadow_reg_v3_cfg;
535*5113495bSYour Name }
536*5113495bSYour Name #else
537*5113495bSYour Name static inline void
pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg * cfg,struct pld_wlan_enable_cfg * config)538*5113495bSYour Name pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg *cfg,
539*5113495bSYour Name 				struct pld_wlan_enable_cfg *config)
540*5113495bSYour Name {
541*5113495bSYour Name }
542*5113495bSYour Name #endif
543*5113495bSYour Name 
pld_ipci_wlan_enable(struct device * dev,struct pld_wlan_enable_cfg * config,enum pld_driver_mode mode,const char * host_version)544*5113495bSYour Name int pld_ipci_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config,
545*5113495bSYour Name 			 enum pld_driver_mode mode, const char *host_version)
546*5113495bSYour Name {
547*5113495bSYour Name 	struct icnss_wlan_enable_cfg cfg;
548*5113495bSYour Name 	enum icnss_driver_mode icnss_mode;
549*5113495bSYour Name 
550*5113495bSYour Name 	if (!dev)
551*5113495bSYour Name 		return -ENODEV;
552*5113495bSYour Name 
553*5113495bSYour Name 	cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
554*5113495bSYour Name 	cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *)
555*5113495bSYour Name 		config->ce_tgt_cfg;
556*5113495bSYour Name 	cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
557*5113495bSYour Name 	cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *)
558*5113495bSYour Name 		config->ce_svc_cfg;
559*5113495bSYour Name 	cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
560*5113495bSYour Name 	cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *)
561*5113495bSYour Name 		config->shadow_reg_cfg;
562*5113495bSYour Name 	cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg;
563*5113495bSYour Name 	cfg.shadow_reg_v2_cfg = (struct icnss_shadow_reg_v2_cfg *)
564*5113495bSYour Name 		config->shadow_reg_v2_cfg;
565*5113495bSYour Name 	cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid;
566*5113495bSYour Name 	if (config->rri_over_ddr_cfg_valid) {
567*5113495bSYour Name 		cfg.rri_over_ddr_cfg.base_addr_low =
568*5113495bSYour Name 			 config->rri_over_ddr_cfg.base_addr_low;
569*5113495bSYour Name 		cfg.rri_over_ddr_cfg.base_addr_high =
570*5113495bSYour Name 			 config->rri_over_ddr_cfg.base_addr_high;
571*5113495bSYour Name 	}
572*5113495bSYour Name 
573*5113495bSYour Name 	pld_ipci_populate_shadow_v3_cfg(&cfg, config);
574*5113495bSYour Name 
575*5113495bSYour Name 	switch (mode) {
576*5113495bSYour Name 	case PLD_FTM:
577*5113495bSYour Name 		icnss_mode = ICNSS_FTM;
578*5113495bSYour Name 		break;
579*5113495bSYour Name 	case PLD_EPPING:
580*5113495bSYour Name 		icnss_mode = ICNSS_EPPING;
581*5113495bSYour Name 		break;
582*5113495bSYour Name 	default:
583*5113495bSYour Name 		icnss_mode = ICNSS_MISSION;
584*5113495bSYour Name 		break;
585*5113495bSYour Name 	}
586*5113495bSYour Name 
587*5113495bSYour Name 	return icnss_wlan_enable(dev, &cfg, icnss_mode, host_version);
588*5113495bSYour Name }
589*5113495bSYour Name 
pld_ipci_wlan_disable(struct device * dev,enum pld_driver_mode mode)590*5113495bSYour Name int pld_ipci_wlan_disable(struct device *dev, enum pld_driver_mode mode)
591*5113495bSYour Name {
592*5113495bSYour Name 	if (!dev)
593*5113495bSYour Name 		return -ENODEV;
594*5113495bSYour Name 
595*5113495bSYour Name 	return icnss_wlan_disable(dev, ICNSS_OFF);
596*5113495bSYour Name }
597*5113495bSYour Name 
598*5113495bSYour Name #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0))
pld_ipci_populate_hw_cap_info(struct icnss_soc_info * icnss_info,struct pld_soc_info * info)599*5113495bSYour Name static void pld_ipci_populate_hw_cap_info(struct icnss_soc_info *icnss_info,
600*5113495bSYour Name 					  struct pld_soc_info *info)
601*5113495bSYour Name {
602*5113495bSYour Name 	/*WLAN HW cap info*/
603*5113495bSYour Name 	info->hw_cap_info.nss =
604*5113495bSYour Name 		(enum pld_wlan_hw_nss_info)icnss_info->rd_card_chain_cap;
605*5113495bSYour Name 	info->hw_cap_info.bw =
606*5113495bSYour Name 	(enum pld_wlan_hw_channel_bw_info)icnss_info->phy_he_channel_width_cap;
607*5113495bSYour Name 	info->hw_cap_info.qam =
608*5113495bSYour Name 		(enum pld_wlan_hw_qam_info)icnss_info->phy_qam_cap;
609*5113495bSYour Name }
610*5113495bSYour Name #else
pld_ipci_populate_hw_cap_info(struct icnss_soc_info * icnss_info,struct pld_soc_info * info)611*5113495bSYour Name static void pld_ipci_populate_hw_cap_info(struct icnss_soc_info *icnss_info,
612*5113495bSYour Name 					  struct pld_soc_info *info)
613*5113495bSYour Name {
614*5113495bSYour Name }
615*5113495bSYour Name #endif
616*5113495bSYour Name 
pld_ipci_get_soc_info(struct device * dev,struct pld_soc_info * info)617*5113495bSYour Name int pld_ipci_get_soc_info(struct device *dev, struct pld_soc_info *info)
618*5113495bSYour Name {
619*5113495bSYour Name 	int errno;
620*5113495bSYour Name 	struct icnss_soc_info icnss_info = {0};
621*5113495bSYour Name 
622*5113495bSYour Name 	if (!info || !dev)
623*5113495bSYour Name 		return -ENODEV;
624*5113495bSYour Name 
625*5113495bSYour Name 	errno = icnss_get_soc_info(dev, &icnss_info);
626*5113495bSYour Name 	if (errno)
627*5113495bSYour Name 		return errno;
628*5113495bSYour Name 
629*5113495bSYour Name 	info->v_addr = icnss_info.v_addr;
630*5113495bSYour Name 	info->p_addr = icnss_info.p_addr;
631*5113495bSYour Name 	info->chip_id = icnss_info.chip_id;
632*5113495bSYour Name 	info->chip_family = icnss_info.chip_family;
633*5113495bSYour Name 	info->board_id = icnss_info.board_id;
634*5113495bSYour Name 	info->soc_id = icnss_info.soc_id;
635*5113495bSYour Name 	info->fw_version = icnss_info.fw_version;
636*5113495bSYour Name 	strlcpy(info->fw_build_timestamp, icnss_info.fw_build_timestamp,
637*5113495bSYour Name 		sizeof(info->fw_build_timestamp));
638*5113495bSYour Name 	strlcpy(info->fw_build_id, icnss_info.fw_build_id,
639*5113495bSYour Name 		sizeof(info->fw_build_id));
640*5113495bSYour Name 
641*5113495bSYour Name 	pld_ipci_populate_hw_cap_info(&icnss_info, info);
642*5113495bSYour Name 
643*5113495bSYour Name 	return 0;
644*5113495bSYour Name }
645*5113495bSYour Name 
646*5113495bSYour Name /*
647*5113495bSYour Name  * pld_ipci_get_irq() - Get irq by ce_id
648*5113495bSYour Name  * @dev: device
649*5113495bSYour Name  * @ce_id: CE id for which irq is requested
650*5113495bSYour Name  *
651*5113495bSYour Name  * Return irq number.
652*5113495bSYour Name  *
653*5113495bSYour Name  * Return: irq number for success
654*5113495bSYour Name  *		Non zero failure code for errors
655*5113495bSYour Name  */
pld_ipci_get_irq(struct device * dev,int ce_id)656*5113495bSYour Name int pld_ipci_get_irq(struct device *dev, int ce_id)
657*5113495bSYour Name {
658*5113495bSYour Name 	uint32_t msi_data_start;
659*5113495bSYour Name 	uint32_t msi_data_count;
660*5113495bSYour Name 	uint32_t msi_irq_start;
661*5113495bSYour Name 	uint32_t msi_data;
662*5113495bSYour Name 	int ret;
663*5113495bSYour Name 
664*5113495bSYour Name 	ret = icnss_get_user_msi_assignment(dev, "CE", &msi_data_count,
665*5113495bSYour Name 					    &msi_data_start, &msi_irq_start);
666*5113495bSYour Name 	if (ret)
667*5113495bSYour Name 		return ret;
668*5113495bSYour Name 
669*5113495bSYour Name 	msi_data = (ce_id % msi_data_count) + msi_irq_start;
670*5113495bSYour Name 	ret = icnss_get_msi_irq(dev, msi_data);
671*5113495bSYour Name 
672*5113495bSYour Name 	return ret;
673*5113495bSYour Name }
674*5113495bSYour Name #endif
675