xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/sdio/if_sdio.c (revision c8e2987f9325baadee03d0265544a08c4a0217b0)
1 /*
2  * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
3  *
4  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5  *
6  *
7  * Permission to use, copy, modify, and/or distribute this software for
8  * any purpose with or without fee is hereby granted, provided that the
9  * above copyright notice and this permission notice appear in all
10  * copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19  * PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 /*
23  * This file was originally distributed by Qualcomm Atheros, Inc.
24  * under proprietary terms before Copyright ownership was assigned
25  * to the Linux Foundation.
26  */
27 
28 #ifndef EXPORT_SYMTAB
29 #define EXPORT_SYMTAB
30 #endif
31 
32 #include <osdep.h>
33 #include <linux/slab.h>
34 #include <linux/interrupt.h>
35 #include <linux/if_arp.h>
36 #include <linux/mmc/card.h>
37 #include <linux/mmc/mmc.h>
38 #include <linux/mmc/host.h>
39 #include <linux/mmc/sdio_func.h>
40 #include <linux/mmc/sdio_ids.h>
41 #include <linux/mmc/sdio.h>
42 #include <linux/mmc/sd.h>
43 #include <linux/wait.h>
44 #include <qdf_mem.h>
45 #include "if_sdio.h"
46 #include <qdf_trace.h>
47 #include <cds_api.h>
48 #include "regtable_sdio.h"
49 #include <hif_debug.h>
50 #include "target_type.h"
51 #include "epping_main.h"
52 #include "pld_sdio.h"
53 #include "targaddrs.h"
54 #include "sdio_api.h"
55 #ifndef REMOVE_PKT_LOG
56 #include "ol_txrx_types.h"
57 #include "pktlog_ac_api.h"
58 #include "pktlog_ac.h"
59 #endif
60 
61 #ifndef ATH_BUS_PM
62 #ifdef CONFIG_PM
63 #define ATH_BUS_PM
64 #endif /* CONFIG_PM */
65 #endif /* ATH_BUS_PM */
66 
67 #ifndef REMOVE_PKT_LOG
68 struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs;
69 #endif
70 #define HIF_SDIO_LOAD_TIMEOUT 1000
71 
72 struct hif_sdio_softc *scn;
73 struct hif_softc *ol_sc;
74 static atomic_t hif_sdio_load_state;
75 /* Wait queue for MC thread */
76 wait_queue_head_t sync_wait_queue;
77 
78 /**
79  * hif_sdio_probe() - configure sdio device
80  * @context: sdio device context
81  * @hif_handle: pointer to hif handle
82  *
83  * Return: 0 for success and non-zero for failure
84  */
85 static A_STATUS hif_sdio_probe(void *context, void *hif_handle)
86 {
87 	int ret = 0;
88 	struct HIF_DEVICE_OS_DEVICE_INFO os_dev_info;
89 	struct sdio_func *func = NULL;
90 	const struct sdio_device_id *id;
91 	uint32_t target_type;
92 
93 	HIF_ENTER();
94 	scn = (struct hif_sdio_softc *)qdf_mem_malloc(sizeof(*scn));
95 	if (!scn) {
96 		ret = -ENOMEM;
97 		goto err_alloc;
98 	}
99 
100 	scn->hif_handle = hif_handle;
101 	hif_configure_device(hif_handle, HIF_DEVICE_GET_OS_DEVICE,
102 			     &os_dev_info,
103 			     sizeof(os_dev_info));
104 
105 	scn->aps_osdev.device = os_dev_info.os_dev;
106 	scn->aps_osdev.bc.bc_bustype = QDF_BUS_TYPE_SDIO;
107 	spin_lock_init(&scn->target_lock);
108 	ol_sc = qdf_mem_malloc(sizeof(*ol_sc));
109 	if (!ol_sc) {
110 		ret = -ENOMEM;
111 		goto err_attach;
112 	}
113 	OS_MEMZERO(ol_sc, sizeof(*ol_sc));
114 
115 	{
116 		/*
117 		 * Attach Target register table. This is needed early on
118 		 * even before BMI since PCI and HIF initialization
119 		 * directly access Target registers.
120 		 *
121 		 * TBDXXX: targetdef should not be global -- should be stored
122 		 * in per-device struct so that we can support multiple
123 		 * different Target types with a single Host driver.
124 		 * The whole notion of an "hif type" -- (not as in the hif
125 		 * module, but generic "Host Interface Type") is bizarre.
126 		 * At first, one one expect it to be things like SDIO, USB, PCI.
127 		 * But instead, it's an actual platform type. Inexplicably, the
128 		 * values used for HIF platform types are *different* from the
129 		 * values used for Target Types.
130 		 */
131 
132 #if defined(CONFIG_AR9888_SUPPORT)
133 		hif_register_tbl_attach(ol_sc, HIF_TYPE_AR9888);
134 		target_register_tbl_attach(ol_sc, TARGET_TYPE_AR9888);
135 		target_type = TARGET_TYPE_AR9888;
136 #elif defined(CONFIG_AR6320_SUPPORT)
137 		id = ((struct hif_sdio_dev *) hif_handle)->id;
138 		if (((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) ==
139 				MANUFACTURER_ID_QCA9377_BASE) ||
140 			((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) ==
141 				MANUFACTURER_ID_QCA9379_BASE)) {
142 			hif_register_tbl_attach(ol_sc, HIF_TYPE_AR6320V2);
143 			target_register_tbl_attach(ol_sc, TARGET_TYPE_AR6320V2);
144 		} else if ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) ==
145 				MANUFACTURER_ID_AR6320_BASE) {
146 			int ar6kid = id->device & MANUFACTURER_ID_AR6K_REV_MASK;
147 
148 			if (ar6kid >= 1) {
149 				/* v2 or higher silicon */
150 				hif_register_tbl_attach(ol_sc,
151 					HIF_TYPE_AR6320V2);
152 				target_register_tbl_attach(ol_sc,
153 					  TARGET_TYPE_AR6320V2);
154 			} else {
155 				/* legacy v1 silicon */
156 				hif_register_tbl_attach(ol_sc,
157 					HIF_TYPE_AR6320);
158 				target_register_tbl_attach(ol_sc,
159 					  TARGET_TYPE_AR6320);
160 			}
161 		}
162 		target_type = TARGET_TYPE_AR6320;
163 
164 #endif
165 	}
166 	func = ((struct hif_sdio_dev *) hif_handle)->func;
167 	scn->targetdef =  ol_sc->targetdef;
168 	scn->hostdef =  ol_sc->hostdef;
169 	scn->aps_osdev.bdev = func;
170 	ol_sc->bus_type = scn->aps_osdev.bc.bc_bustype;
171 	scn->ol_sc = *ol_sc;
172 	ol_sc->target_info.target_type = target_type;
173 
174 	scn->ramdump_base = pld_hif_sdio_get_virt_ramdump_mem(
175 					scn->aps_osdev.device,
176 					&scn->ramdump_size);
177 	if (scn->ramdump_base == NULL || !scn->ramdump_size) {
178 		QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR,
179 			"%s: Failed to get RAM dump memory address or size!\n",
180 			__func__);
181 	} else {
182 		QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO,
183 			"%s: ramdump base 0x%pK size %d\n", __func__,
184 			scn->ramdump_base, (int)scn->ramdump_size);
185 	}
186 
187 	if (athdiag_procfs_init(scn) != 0) {
188 		QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR,
189 			  "%s athdiag_procfs_init failed", __func__);
190 		ret = QDF_STATUS_E_FAILURE;
191 		goto err_attach1;
192 	}
193 
194 	atomic_set(&hif_sdio_load_state, true);
195 	wake_up_interruptible(&sync_wait_queue);
196 
197 	return 0;
198 
199 err_attach1:
200 	if (scn->ramdump_base)
201 		pld_hif_sdio_release_ramdump_mem(scn->ramdump_base);
202 	qdf_mem_free(ol_sc);
203 err_attach:
204 	qdf_mem_free(scn);
205 	scn = NULL;
206 err_alloc:
207 	return ret;
208 }
209 
210 /**
211  * hif_sdio_remove() - remove sdio device
212  * @conext: sdio device context
213  * @hif_handle: pointer to sdio function
214  *
215  * Return: 0 for success and non-zero for failure
216  */
217 static A_STATUS hif_sdio_remove(void *context, void *hif_handle)
218 {
219 	HIF_ENTER();
220 
221 	if (!scn) {
222 		QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR,
223 			  "Global SDIO context is NULL");
224 		return A_ERROR;
225 	}
226 
227 	atomic_set(&hif_sdio_load_state, false);
228 	athdiag_procfs_remove();
229 
230 #ifndef TARGET_DUMP_FOR_NON_QC_PLATFORM
231 	iounmap(scn->ramdump_base);
232 #endif
233 
234 	if (ol_sc) {
235 		qdf_mem_free(ol_sc);
236 		ol_sc = NULL;
237 	}
238 
239 	if (scn) {
240 		qdf_mem_free(scn);
241 		scn = NULL;
242 	}
243 
244 	HIF_EXIT();
245 
246 	return 0;
247 }
248 
249 /**
250  * hif_sdio_suspend() - sdio suspend routine
251  * @context: sdio device context
252  *
253  * Return: 0 for success and non-zero for failure
254  */
255 static A_STATUS hif_sdio_suspend(void *context)
256 {
257 	return 0;
258 }
259 
260 /**
261  * hif_sdio_resume() - sdio resume routine
262  * @context: sdio device context
263  *
264  * Return: 0 for success and non-zero for failure
265  */
266 static A_STATUS hif_sdio_resume(void *context)
267 {
268 	return 0;
269 }
270 
271 /**
272  * hif_sdio_power_change() - change power state of sdio bus
273  * @conext: sdio device context
274  * @config: power state configurartion
275  *
276  * Return: 0 for success and non-zero for failure
277  */
278 static A_STATUS hif_sdio_power_change(void *context, uint32_t config)
279 {
280 	return 0;
281 }
282 
283 /*
284  * Module glue.
285  */
286 #include <linux/version.h>
287 static char *version = "HIF (Atheros/multi-bss)";
288 static char *dev_info = "ath_hif_sdio";
289 
290 /**
291  * init_ath_hif_sdio() - initialize hif sdio callbacks
292  * @param: none
293  *
294  * Return: 0 for success and non-zero for failure
295  */
296 static int init_ath_hif_sdio(void)
297 {
298 	QDF_STATUS status;
299 	struct osdrv_callbacks osdrv_callbacks;
300 
301 	HIF_ENTER();
302 	qdf_mem_zero(&osdrv_callbacks, sizeof(osdrv_callbacks));
303 	osdrv_callbacks.device_inserted_handler = hif_sdio_probe;
304 	osdrv_callbacks.device_removed_handler = hif_sdio_remove;
305 	osdrv_callbacks.device_suspend_handler = hif_sdio_suspend;
306 	osdrv_callbacks.device_resume_handler = hif_sdio_resume;
307 	osdrv_callbacks.device_power_change_handler = hif_sdio_power_change;
308 
309 	QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, "%s %d", __func__,
310 		  __LINE__);
311 	status = hif_init(&osdrv_callbacks);
312 	if (status != QDF_STATUS_SUCCESS) {
313 		QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
314 			  "%s hif_init failed!", __func__);
315 		return -ENODEV;
316 	}
317 	QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR,
318 		 "%s: %s\n", dev_info, version);
319 
320 	return 0;
321 }
322 
323 /**
324  * hif_sdio_bus_suspend() - suspend the bus
325  *
326  * This function suspends the bus, but sdio doesn't need to suspend.
327  * Therefore do nothing.
328  *
329  * Return: 0 for success and non-zero for failure
330  */
331 int hif_sdio_bus_suspend(struct hif_softc *hif_ctx)
332 {
333 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx);
334 	struct hif_sdio_dev *hif_device = scn->hif_handle;
335 	struct device *dev = &hif_device->func->dev;
336 
337 	hif_device_suspend(dev);
338 	return 0;
339 }
340 
341 
342 /**
343  * hif_sdio_bus_resume() - hif resume API
344  *
345  * This function resumes the bus. but sdio doesn't need to resume.
346  * Therefore do nothing.
347  *
348  * Return: 0 for success and non-zero for failure
349  */
350 int hif_sdio_bus_resume(struct hif_softc *hif_ctx)
351 {
352 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx);
353 	struct hif_sdio_dev *hif_device = scn->hif_handle;
354 	struct device *dev = &hif_device->func->dev;
355 
356 	hif_device_resume(dev);
357 	return 0;
358 }
359 
360 /**
361  * hif_enable_power_gating() - enable HW power gating
362  *
363  * Return: n/a
364  */
365 void hif_enable_power_gating(void *hif_ctx)
366 {
367 }
368 
369 /**
370  * hif_sdio_close() - hif_bus_close
371  *
372  * Return: None
373  */
374 void hif_sdio_close(struct hif_softc *hif_sc)
375 {
376 	if (ol_sc) {
377 		qdf_mem_free(ol_sc);
378 		ol_sc = NULL;
379 	}
380 
381 	if (scn) {
382 		qdf_mem_free(scn);
383 		scn = NULL;
384 	}
385 }
386 
387 /**
388  * hif_sdio_open() - hif_bus_open
389  * @hif_sc: hif context
390  * @bus_type: bus type
391  *
392  * Return: QDF status
393  */
394 QDF_STATUS hif_sdio_open(struct hif_softc *hif_sc,
395 				   enum qdf_bus_type bus_type)
396 {
397 	QDF_STATUS status;
398 
399 	hif_sc->bus_type = bus_type;
400 	status = init_ath_hif_sdio();
401 
402 	return status;
403 }
404 
405 void hif_get_target_revision(struct hif_softc *ol_sc)
406 {
407 	struct hif_softc *ol_sc_local = (struct hif_softc *)ol_sc;
408 	struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc_local);
409 	uint32_t chip_id = 0;
410 	QDF_STATUS rv;
411 
412 	rv = hif_diag_read_access(hif_hdl,
413 			(CHIP_ID_ADDRESS | RTC_SOC_BASE_ADDRESS), &chip_id);
414 	if (rv != QDF_STATUS_SUCCESS) {
415 		HIF_ERROR("%s[%d]: get chip id fail\n", __func__, __LINE__);
416 	} else {
417 		ol_sc_local->target_info.target_revision =
418 			CHIP_ID_REVISION_GET(chip_id);
419 	}
420 }
421 
422 /**
423  * hif_sdio_enable_bus() - hif_enable_bus
424  * @hif_sc: hif context
425  * @dev: dev
426  * @bdev: bus dev
427  * @bid: bus id
428  * @type: bus type
429  *
430  * Return: QDF_STATUS
431  */
432 QDF_STATUS hif_sdio_enable_bus(struct hif_softc *hif_sc,
433 		struct device *dev, void *bdev, const struct hif_bus_id *bid,
434 		enum hif_enable_type type)
435 {
436 	int ret = 0;
437 	const struct sdio_device_id *id = (const struct sdio_device_id *)bid;
438 	struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc);
439 
440 	init_waitqueue_head(&sync_wait_queue);
441 	if (hif_sdio_device_inserted(dev, id)) {
442 		HIF_ERROR("wlan: %s hif_sdio_device_inserted failed", __func__);
443 		return QDF_STATUS_E_NOMEM;
444 	}
445 
446 	wait_event_interruptible_timeout(sync_wait_queue,
447 			  atomic_read(&hif_sdio_load_state) == true,
448 			  HIF_SDIO_LOAD_TIMEOUT);
449 	hif_sc->hostdef = ol_sc->hostdef;
450 	hif_sc->targetdef = ol_sc->targetdef;
451 	hif_sc->bus_type = ol_sc->bus_type;
452 	hif_sc->target_info.target_type = ol_sc->target_info.target_type;
453 
454 	sc->hif_handle = scn->hif_handle;
455 	sc->aps_osdev.device = scn->aps_osdev.device;
456 	sc->aps_osdev.bc.bc_bustype = scn->aps_osdev.bc.bc_bustype;
457 	sc->target_lock = scn->target_lock;
458 	sc->targetdef = scn->targetdef;
459 	sc->hostdef = scn->hostdef;
460 	sc->aps_osdev.bdev = scn->aps_osdev.bdev;
461 	sc->ramdump_size = scn->ramdump_size;
462 	sc->ramdump_base = scn->ramdump_base;
463 
464 	return ret;
465 }
466 
467 
468 /**
469  * hif_sdio_disable_bus() - sdio disable bus
470  * @hif_sc: hif softc pointer
471  *
472  * Return: none
473  */
474 void hif_sdio_disable_bus(struct hif_softc *hif_sc)
475 {
476 	struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc);
477 	struct sdio_func *func = sc->aps_osdev.bdev;
478 
479 	hif_sdio_device_removed(func);
480 }
481 
482 /**
483  * hif_sdio_get_config_item - sdio configure bus
484  * @hif_sc: hif context
485  * @opcode: configuration type
486  * @config: configuration value to set
487  * @config_len: configuration length
488  *
489  * Return: QDF_STATUS_SUCCESS for sucess
490  */
491 QDF_STATUS hif_sdio_get_config_item(struct hif_softc *hif_sc,
492 		     int opcode, void *config, uint32_t config_len)
493 {
494 	struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc);
495 	struct hif_sdio_dev *hif_device = sc->hif_handle;
496 
497 	return hif_configure_device(hif_device,
498 				opcode, config, config_len);
499 }
500 
501 /**
502  * hif_sdio_set_mailbox_swap - set mailbox swap
503  * @hif_sc: hif context
504  *
505  * Return: None
506  */
507 void hif_sdio_set_mailbox_swap(struct hif_softc *hif_sc)
508 {
509 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc);
510 	struct hif_sdio_dev *hif_device = scn->hif_handle;
511 
512 	hif_device->swap_mailbox = true;
513 }
514 
515 /**
516  * hif_sdio_claim_device - set mailbox swap
517  * @hif_sc: hif context
518  *
519  * Return: None
520  */
521 void hif_sdio_claim_device(struct hif_softc *hif_sc)
522 {
523 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc);
524 	struct hif_sdio_dev *hif_device = scn->hif_handle;
525 
526 	hif_device->claimed_ctx = hif_sc;
527 }
528 
529 /**
530  * hif_sdio_mask_interrupt_call() - disbale hif device irq
531  * @scn: pointr to softc structure
532  *
533  * Return: None
534  */
535 void hif_sdio_mask_interrupt_call(struct hif_softc *scn)
536 {
537 	struct hif_sdio_softc *hif_ctx = HIF_GET_SDIO_SOFTC(scn);
538 	struct hif_sdio_dev *hif_device = hif_ctx->hif_handle;
539 
540 	hif_mask_interrupt(hif_device);
541 }
542 
543 /**
544  * hif_trigger_dump() - trigger various dump cmd
545  * @scn: struct hif_opaque_softc
546  * @cmd_id: dump command id
547  * @start: start/stop dump
548  *
549  * Return: None
550  */
551 void hif_trigger_dump(struct hif_opaque_softc *scn, uint8_t cmd_id, bool start)
552 {
553 }
554 
555 /**
556  * hif_check_fw_reg() - check fw selfrecovery indication
557  * @hif_ctx: hif_opaque_softc
558  *
559  * Return: int
560  */
561 int hif_check_fw_reg(struct hif_opaque_softc *hif_ctx)
562 {
563 	int ret = 1;
564 	uint32_t fw_indication = 0;
565 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx);
566 
567 	if (hif_diag_read_access(hif_ctx, FW_INDICATOR_ADDRESS,
568 				 &fw_indication) != QDF_STATUS_SUCCESS) {
569 		HIF_ERROR("%s Get fw indication failed\n", __func__);
570 		return 1;
571 	}
572 	HIF_INFO("%s: fw indication is 0x%x def 0x%x.\n", __func__,
573 		fw_indication, FW_IND_HELPER);
574 	if (fw_indication & FW_IND_HELPER)
575 		ret = 0;
576 
577 	return ret;
578 }
579 
580 /**
581  * hif_wlan_disable() - call the platform driver to disable wlan
582  * @scn: scn
583  *
584  * Return: void
585  */
586 void hif_wlan_disable(struct hif_softc *scn)
587 {
588 }
589 
590 /**
591  * hif_sdio_needs_bmi() - return true if the soc needs bmi through the driver
592  * @scn: hif context
593  *
594  * Return: true if soc needs driver bmi otherwise false
595  */
596 bool hif_sdio_needs_bmi(struct hif_softc *scn)
597 {
598 	return true;
599 }
600