xref: /wlan-driver/qca-wifi-host-cmn/hif/src/sdio/if_sdio.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2022-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 #ifndef EXPORT_SYMTAB
21*5113495bSYour Name #define EXPORT_SYMTAB
22*5113495bSYour Name #endif
23*5113495bSYour Name 
24*5113495bSYour Name #include <osdep.h>
25*5113495bSYour Name #include <linux/slab.h>
26*5113495bSYour Name #include <linux/interrupt.h>
27*5113495bSYour Name #include <linux/if_arp.h>
28*5113495bSYour Name #include <linux/mmc/card.h>
29*5113495bSYour Name #include <linux/mmc/mmc.h>
30*5113495bSYour Name #include <linux/mmc/host.h>
31*5113495bSYour Name #include <linux/mmc/sdio_func.h>
32*5113495bSYour Name #include <linux/mmc/sdio_ids.h>
33*5113495bSYour Name #include <linux/mmc/sdio.h>
34*5113495bSYour Name #include <linux/mmc/sd.h>
35*5113495bSYour Name #include <linux/wait.h>
36*5113495bSYour Name #include <qdf_mem.h>
37*5113495bSYour Name #include "if_sdio.h"
38*5113495bSYour Name #include <qdf_trace.h>
39*5113495bSYour Name #include <cds_api.h>
40*5113495bSYour Name #include "regtable_sdio.h"
41*5113495bSYour Name #include <hif_debug.h>
42*5113495bSYour Name #include "target_type.h"
43*5113495bSYour Name #include "epping_main.h"
44*5113495bSYour Name #include "targaddrs.h"
45*5113495bSYour Name #include "sdio_api.h"
46*5113495bSYour Name #include <hif_sdio_dev.h>
47*5113495bSYour Name #ifndef REMOVE_PKT_LOG
48*5113495bSYour Name #include "ol_txrx_types.h"
49*5113495bSYour Name #include "pktlog_ac_api.h"
50*5113495bSYour Name #include "pktlog_ac.h"
51*5113495bSYour Name #endif
52*5113495bSYour Name #ifndef ATH_BUS_PM
53*5113495bSYour Name #ifdef CONFIG_PM
54*5113495bSYour Name #define ATH_BUS_PM
55*5113495bSYour Name #endif /* CONFIG_PM */
56*5113495bSYour Name #endif /* ATH_BUS_PM */
57*5113495bSYour Name 
58*5113495bSYour Name #ifndef REMOVE_PKT_LOG
59*5113495bSYour Name struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs;
60*5113495bSYour Name #endif
61*5113495bSYour Name #define HIF_SDIO_LOAD_TIMEOUT 1000
62*5113495bSYour Name 
63*5113495bSYour Name /**
64*5113495bSYour Name  * hif_sdio_bus_suspend() - suspend the bus
65*5113495bSYour Name  * @hif_ctx: hif context
66*5113495bSYour Name  *
67*5113495bSYour Name  * This function suspends the bus, but sdio doesn't need to suspend.
68*5113495bSYour Name  * Therefore do nothing.
69*5113495bSYour Name  *
70*5113495bSYour Name  * Return: 0 for success and non-zero for failure
71*5113495bSYour Name  */
hif_sdio_bus_suspend(struct hif_softc * hif_ctx)72*5113495bSYour Name int hif_sdio_bus_suspend(struct hif_softc *hif_ctx)
73*5113495bSYour Name {
74*5113495bSYour Name 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx);
75*5113495bSYour Name 	struct hif_sdio_dev *hif_device = scn->hif_handle;
76*5113495bSYour Name 	struct device *dev = &hif_device->func->dev;
77*5113495bSYour Name 
78*5113495bSYour Name 	return hif_device_suspend(hif_ctx, dev);
79*5113495bSYour Name }
80*5113495bSYour Name 
81*5113495bSYour Name 
82*5113495bSYour Name /**
83*5113495bSYour Name  * hif_sdio_bus_resume() - hif resume API
84*5113495bSYour Name  * @hif_ctx: hif context
85*5113495bSYour Name  *
86*5113495bSYour Name  * This function resumes the bus. but sdio doesn't need to resume.
87*5113495bSYour Name  * Therefore do nothing.
88*5113495bSYour Name  *
89*5113495bSYour Name  * Return: 0 for success and non-zero for failure
90*5113495bSYour Name  */
hif_sdio_bus_resume(struct hif_softc * hif_ctx)91*5113495bSYour Name int hif_sdio_bus_resume(struct hif_softc *hif_ctx)
92*5113495bSYour Name {
93*5113495bSYour Name 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx);
94*5113495bSYour Name 	struct hif_sdio_dev *hif_device = scn->hif_handle;
95*5113495bSYour Name 	struct device *dev = &hif_device->func->dev;
96*5113495bSYour Name 
97*5113495bSYour Name 	hif_device_resume(hif_ctx, dev);
98*5113495bSYour Name 	return 0;
99*5113495bSYour Name }
100*5113495bSYour Name 
101*5113495bSYour Name /**
102*5113495bSYour Name  * hif_enable_power_gating() - enable HW power gating
103*5113495bSYour Name  * @hif_ctx: hif context
104*5113495bSYour Name  *
105*5113495bSYour Name  * Return: n/a
106*5113495bSYour Name  */
hif_enable_power_gating(void * hif_ctx)107*5113495bSYour Name void hif_enable_power_gating(void *hif_ctx)
108*5113495bSYour Name {
109*5113495bSYour Name }
110*5113495bSYour Name 
111*5113495bSYour Name /**
112*5113495bSYour Name  * hif_sdio_close() - hif_bus_close
113*5113495bSYour Name  * @hif_sc: hif context
114*5113495bSYour Name  *
115*5113495bSYour Name  * Return: None
116*5113495bSYour Name  */
hif_sdio_close(struct hif_softc * hif_sc)117*5113495bSYour Name void hif_sdio_close(struct hif_softc *hif_sc)
118*5113495bSYour Name {
119*5113495bSYour Name }
120*5113495bSYour Name 
121*5113495bSYour Name /**
122*5113495bSYour Name  * hif_sdio_open() - hif_bus_open
123*5113495bSYour Name  * @hif_sc: hif context
124*5113495bSYour Name  * @bus_type: bus type
125*5113495bSYour Name  *
126*5113495bSYour Name  * Return: QDF status
127*5113495bSYour Name  */
hif_sdio_open(struct hif_softc * hif_sc,enum qdf_bus_type bus_type)128*5113495bSYour Name QDF_STATUS hif_sdio_open(struct hif_softc *hif_sc,
129*5113495bSYour Name 				   enum qdf_bus_type bus_type)
130*5113495bSYour Name {
131*5113495bSYour Name 	hif_sc->bus_type = bus_type;
132*5113495bSYour Name 
133*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
134*5113495bSYour Name }
135*5113495bSYour Name 
hif_get_target_revision(struct hif_softc * ol_sc)136*5113495bSYour Name void hif_get_target_revision(struct hif_softc *ol_sc)
137*5113495bSYour Name {
138*5113495bSYour Name 	struct hif_softc *ol_sc_local = (struct hif_softc *)ol_sc;
139*5113495bSYour Name 	struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc_local);
140*5113495bSYour Name 	uint32_t chip_id = 0;
141*5113495bSYour Name 	QDF_STATUS rv;
142*5113495bSYour Name 
143*5113495bSYour Name 	rv = hif_diag_read_access(hif_hdl,
144*5113495bSYour Name 			(CHIP_ID_ADDRESS | RTC_SOC_BASE_ADDRESS), &chip_id);
145*5113495bSYour Name 	if (rv != QDF_STATUS_SUCCESS) {
146*5113495bSYour Name 		hif_err("get chip id fail");
147*5113495bSYour Name 	} else {
148*5113495bSYour Name 		ol_sc_local->target_info.target_revision =
149*5113495bSYour Name 			CHIP_ID_REVISION_GET(chip_id);
150*5113495bSYour Name 	}
151*5113495bSYour Name }
152*5113495bSYour Name 
153*5113495bSYour Name /**
154*5113495bSYour Name  * hif_sdio_enable_bus() - hif_enable_bus
155*5113495bSYour Name  * @ol_sc: hif context
156*5113495bSYour Name  * @dev: dev
157*5113495bSYour Name  * @bdev: bus dev
158*5113495bSYour Name  * @bid: bus id
159*5113495bSYour Name  * @type: bus type
160*5113495bSYour Name  *
161*5113495bSYour Name  * Return: QDF_STATUS
162*5113495bSYour Name  */
hif_sdio_enable_bus(struct hif_softc * ol_sc,struct device * dev,void * bdev,const struct hif_bus_id * bid,enum hif_enable_type type)163*5113495bSYour Name QDF_STATUS hif_sdio_enable_bus(struct hif_softc *ol_sc, struct device *dev,
164*5113495bSYour Name 			       void *bdev, const struct hif_bus_id *bid,
165*5113495bSYour Name 			       enum hif_enable_type type)
166*5113495bSYour Name {
167*5113495bSYour Name 	const struct sdio_device_id *id = (const struct sdio_device_id *)bid;
168*5113495bSYour Name 
169*5113495bSYour Name 	if (hif_sdio_device_inserted(ol_sc, dev, id)) {
170*5113495bSYour Name 		hif_err("hif_sdio_device_inserted failed");
171*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
172*5113495bSYour Name 	}
173*5113495bSYour Name 
174*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
175*5113495bSYour Name }
176*5113495bSYour Name 
177*5113495bSYour Name 
178*5113495bSYour Name /**
179*5113495bSYour Name  * hif_sdio_disable_bus() - sdio disable bus
180*5113495bSYour Name  * @hif_sc: hif softc pointer
181*5113495bSYour Name  *
182*5113495bSYour Name  * Return: none
183*5113495bSYour Name  */
hif_sdio_disable_bus(struct hif_softc * hif_sc)184*5113495bSYour Name void hif_sdio_disable_bus(struct hif_softc *hif_sc)
185*5113495bSYour Name {
186*5113495bSYour Name 	struct sdio_func *func = dev_to_sdio_func(hif_sc->qdf_dev->dev);
187*5113495bSYour Name 
188*5113495bSYour Name 	hif_sdio_device_removed(hif_sc, func);
189*5113495bSYour Name }
190*5113495bSYour Name 
191*5113495bSYour Name /**
192*5113495bSYour Name  * hif_sdio_get_config_item - sdio configure bus
193*5113495bSYour Name  * @hif_sc: hif context
194*5113495bSYour Name  * @opcode: configuration type
195*5113495bSYour Name  * @config: configuration value to set
196*5113495bSYour Name  * @config_len: configuration length
197*5113495bSYour Name  *
198*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS for success
199*5113495bSYour Name  */
hif_sdio_get_config_item(struct hif_softc * hif_sc,int opcode,void * config,uint32_t config_len)200*5113495bSYour Name QDF_STATUS hif_sdio_get_config_item(struct hif_softc *hif_sc,
201*5113495bSYour Name 		     int opcode, void *config, uint32_t config_len)
202*5113495bSYour Name {
203*5113495bSYour Name 	struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc);
204*5113495bSYour Name 	struct hif_sdio_dev *hif_device = sc->hif_handle;
205*5113495bSYour Name 
206*5113495bSYour Name 	return hif_configure_device(hif_sc, hif_device, opcode,
207*5113495bSYour Name 				    config, config_len);
208*5113495bSYour Name }
209*5113495bSYour Name 
210*5113495bSYour Name /**
211*5113495bSYour Name  * hif_sdio_set_mailbox_swap - set mailbox swap
212*5113495bSYour Name  * @hif_sc: hif context
213*5113495bSYour Name  *
214*5113495bSYour Name  * Return: None
215*5113495bSYour Name  */
hif_sdio_set_mailbox_swap(struct hif_softc * hif_sc)216*5113495bSYour Name void hif_sdio_set_mailbox_swap(struct hif_softc *hif_sc)
217*5113495bSYour Name {
218*5113495bSYour Name 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc);
219*5113495bSYour Name 	struct hif_sdio_dev *hif_device = scn->hif_handle;
220*5113495bSYour Name 
221*5113495bSYour Name 	hif_dev_set_mailbox_swap(hif_device);
222*5113495bSYour Name }
223*5113495bSYour Name 
224*5113495bSYour Name /**
225*5113495bSYour Name  * hif_sdio_claim_device - set mailbox swap
226*5113495bSYour Name  * @hif_sc: hif context
227*5113495bSYour Name  *
228*5113495bSYour Name  * Return: None
229*5113495bSYour Name  */
hif_sdio_claim_device(struct hif_softc * hif_sc)230*5113495bSYour Name void hif_sdio_claim_device(struct hif_softc *hif_sc)
231*5113495bSYour Name {
232*5113495bSYour Name 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc);
233*5113495bSYour Name 	struct hif_sdio_dev *hif_device = scn->hif_handle;
234*5113495bSYour Name 
235*5113495bSYour Name 	hif_device->claimed_ctx = hif_sc;
236*5113495bSYour Name }
237*5113495bSYour Name 
238*5113495bSYour Name /**
239*5113495bSYour Name  * hif_sdio_mask_interrupt_call() - disable hif device irq
240*5113495bSYour Name  * @scn: pointr to softc structure
241*5113495bSYour Name  *
242*5113495bSYour Name  * Return: None
243*5113495bSYour Name  */
hif_sdio_mask_interrupt_call(struct hif_softc * scn)244*5113495bSYour Name void hif_sdio_mask_interrupt_call(struct hif_softc *scn)
245*5113495bSYour Name {
246*5113495bSYour Name 	struct hif_sdio_softc *hif_ctx = HIF_GET_SDIO_SOFTC(scn);
247*5113495bSYour Name 	struct hif_sdio_dev *hif_device = hif_ctx->hif_handle;
248*5113495bSYour Name 
249*5113495bSYour Name 	hif_mask_interrupt(hif_device);
250*5113495bSYour Name }
251*5113495bSYour Name 
252*5113495bSYour Name /**
253*5113495bSYour Name  * hif_trigger_dump() - trigger various dump cmd
254*5113495bSYour Name  * @scn: struct hif_opaque_softc
255*5113495bSYour Name  * @cmd_id: dump command id
256*5113495bSYour Name  * @start: start/stop dump
257*5113495bSYour Name  *
258*5113495bSYour Name  * Return: None
259*5113495bSYour Name  */
hif_trigger_dump(struct hif_opaque_softc * scn,uint8_t cmd_id,bool start)260*5113495bSYour Name void hif_trigger_dump(struct hif_opaque_softc *scn, uint8_t cmd_id, bool start)
261*5113495bSYour Name {
262*5113495bSYour Name }
263*5113495bSYour Name 
264*5113495bSYour Name /**
265*5113495bSYour Name  * hif_check_fw_reg() - check fw selfrecovery indication
266*5113495bSYour Name  * @hif_ctx: hif_opaque_softc
267*5113495bSYour Name  *
268*5113495bSYour Name  * Return: int
269*5113495bSYour Name  */
hif_check_fw_reg(struct hif_opaque_softc * hif_ctx)270*5113495bSYour Name int hif_check_fw_reg(struct hif_opaque_softc *hif_ctx)
271*5113495bSYour Name {
272*5113495bSYour Name 	int ret = 1;
273*5113495bSYour Name 	uint32_t fw_indication = 0;
274*5113495bSYour Name 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx);
275*5113495bSYour Name 
276*5113495bSYour Name 	if (hif_diag_read_access(hif_ctx, FW_INDICATOR_ADDRESS,
277*5113495bSYour Name 				 &fw_indication) != QDF_STATUS_SUCCESS) {
278*5113495bSYour Name 		hif_err("Get fw indication failed");
279*5113495bSYour Name 		return 1;
280*5113495bSYour Name 	}
281*5113495bSYour Name 	hif_info("fw indication is 0x%x def 0x%x",
282*5113495bSYour Name 		fw_indication, FW_IND_HELPER);
283*5113495bSYour Name 	if (fw_indication & FW_IND_HELPER)
284*5113495bSYour Name 		ret = 0;
285*5113495bSYour Name 
286*5113495bSYour Name 	return ret;
287*5113495bSYour Name }
288*5113495bSYour Name 
289*5113495bSYour Name /**
290*5113495bSYour Name  * hif_wlan_disable() - call the platform driver to disable wlan
291*5113495bSYour Name  * @scn: scn
292*5113495bSYour Name  *
293*5113495bSYour Name  * Return: void
294*5113495bSYour Name  */
hif_wlan_disable(struct hif_softc * scn)295*5113495bSYour Name void hif_wlan_disable(struct hif_softc *scn)
296*5113495bSYour Name {
297*5113495bSYour Name }
298*5113495bSYour Name 
299*5113495bSYour Name /**
300*5113495bSYour Name  * hif_sdio_needs_bmi() - return true if the soc needs bmi through the driver
301*5113495bSYour Name  * @scn: hif context
302*5113495bSYour Name  *
303*5113495bSYour Name  * Return: true if soc needs driver bmi otherwise false
304*5113495bSYour Name  */
hif_sdio_needs_bmi(struct hif_softc * scn)305*5113495bSYour Name bool hif_sdio_needs_bmi(struct hif_softc *scn)
306*5113495bSYour Name {
307*5113495bSYour Name 	return true;
308*5113495bSYour Name }
309