xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/sdio/if_sdio.c (revision e1d3d092f61a07549ab97f6f1f0c86554e0c642f)
1 /*
2  * Copyright (c) 2013-2017 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 "bmi_msg.h"            /* TARGET_TYPE_ */
46 #include "if_sdio.h"
47 #include <qdf_trace.h>
48 #include <cds_api.h>
49 #include "regtable_sdio.h"
50 #include <hif_debug.h>
51 #ifndef REMOVE_PKT_LOG
52 #include "ol_txrx_types.h"
53 #include "pktlog_ac_api.h"
54 #include "pktlog_ac.h"
55 #endif
56 #include "epping_main.h"
57 
58 #ifndef ATH_BUS_PM
59 #ifdef CONFIG_PM
60 #define ATH_BUS_PM
61 #endif /* CONFIG_PM */
62 #endif /* ATH_BUS_PM */
63 
64 #ifndef REMOVE_PKT_LOG
65 struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs;
66 #endif
67 #define HIF_SDIO_LOAD_TIMEOUT 1000
68 
69 struct hif_sdio_softc *scn;
70 struct hif_softc *ol_sc;
71 static atomic_t hif_sdio_load_state;
72 /* Wait queue for MC thread */
73 wait_queue_head_t sync_wait_queue;
74 
75 /**
76  * hif_sdio_probe() - configure sdio device
77  * @context: sdio device context
78  * @hif_handle: pointer to hif handle
79  *
80  * Return: 0 for success and non-zero for failure
81  */
82 static A_STATUS hif_sdio_probe(void *context, void *hif_handle)
83 {
84 	int ret = 0;
85 	struct HIF_DEVICE_OS_DEVICE_INFO os_dev_info;
86 	struct sdio_func *func = NULL;
87 	const struct sdio_device_id *id;
88 	uint32_t target_type;
89 
90 	HIF_ENTER();
91 	scn = (struct hif_sdio_softc *)qdf_mem_malloc(sizeof(*scn));
92 	if (!scn) {
93 		ret = -ENOMEM;
94 		goto err_alloc;
95 	}
96 
97 	scn->hif_handle = hif_handle;
98 	hif_configure_device(hif_handle, HIF_DEVICE_GET_OS_DEVICE,
99 			     &os_dev_info,
100 			     sizeof(os_dev_info));
101 
102 	scn->aps_osdev.device = os_dev_info.os_dev;
103 	scn->aps_osdev.bc.bc_bustype = QDF_BUS_TYPE_SDIO;
104 	spin_lock_init(&scn->target_lock);
105 	ol_sc = qdf_mem_malloc(sizeof(*ol_sc));
106 	if (!ol_sc) {
107 		ret = -ENOMEM;
108 		goto err_attach;
109 	}
110 	OS_MEMZERO(ol_sc, sizeof(*ol_sc));
111 
112 	{
113 		/*
114 		 * Attach Target register table. This is needed early on
115 		 * even before BMI since PCI and HIF initialization
116 		 * directly access Target registers.
117 		 *
118 		 * TBDXXX: targetdef should not be global -- should be stored
119 		 * in per-device struct so that we can support multiple
120 		 * different Target types with a single Host driver.
121 		 * The whole notion of an "hif type" -- (not as in the hif
122 		 * module, but generic "Host Interface Type") is bizarre.
123 		 * At first, one one expect it to be things like SDIO, USB, PCI.
124 		 * But instead, it's an actual platform type. Inexplicably, the
125 		 * values used for HIF platform types are *different* from the
126 		 * values used for Target Types.
127 		 */
128 
129 #if defined(CONFIG_AR9888_SUPPORT)
130 		hif_register_tbl_attach(ol_sc, HIF_TYPE_AR9888);
131 		target_register_tbl_attach(ol_sc, TARGET_TYPE_AR9888);
132 		target_type = TARGET_TYPE_AR9888;
133 #elif defined(CONFIG_AR6320_SUPPORT)
134 		id = ((struct hif_sdio_dev *) hif_handle)->id;
135 		if (((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) ==
136 				MANUFACTURER_ID_QCA9377_BASE) ||
137 			((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) ==
138 				MANUFACTURER_ID_QCA9379_BASE)) {
139 			hif_register_tbl_attach(ol_sc, HIF_TYPE_AR6320V2);
140 			target_register_tbl_attach(ol_sc, TARGET_TYPE_AR6320V2);
141 		} else if ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) ==
142 				MANUFACTURER_ID_AR6320_BASE) {
143 			int ar6kid = id->device & MANUFACTURER_ID_AR6K_REV_MASK;
144 
145 			if (ar6kid >= 1) {
146 				/* v2 or higher silicon */
147 				hif_register_tbl_attach(ol_sc,
148 					HIF_TYPE_AR6320V2);
149 				target_register_tbl_attach(ol_sc,
150 					  TARGET_TYPE_AR6320V2);
151 			} else {
152 				/* legacy v1 silicon */
153 				hif_register_tbl_attach(ol_sc,
154 					HIF_TYPE_AR6320);
155 				target_register_tbl_attach(ol_sc,
156 					  TARGET_TYPE_AR6320);
157 			}
158 		}
159 		target_type = TARGET_TYPE_AR6320;
160 
161 #endif
162 	}
163 	func = ((struct hif_sdio_dev *) hif_handle)->func;
164 	scn->targetdef =  ol_sc->targetdef;
165 	scn->hostdef =  ol_sc->hostdef;
166 	scn->aps_osdev.bdev = func;
167 	ol_sc->bus_type = scn->aps_osdev.bc.bc_bustype;
168 	scn->ol_sc = *ol_sc;
169 	ol_sc->target_info.target_type = target_type;
170 
171 #ifndef TARGET_DUMP_FOR_NON_QC_PLATFORM
172 	scn->ramdump_base = ioremap(RAMDUMP_ADDR, RAMDUMP_SIZE);
173 	scn->ramdump_size = RAMDUMP_SIZE;
174 	if (scn->ramdump_base == NULL) {
175 		scn->ramdump_base = 0;
176 		scn->ramdump_size = 0;
177 	}
178 #endif
179 
180 	if (athdiag_procfs_init(scn) != 0) {
181 		QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR,
182 			  "%s athdiag_procfs_init failed", __func__);
183 		ret = QDF_STATUS_E_FAILURE;
184 		goto err_attach1;
185 	}
186 
187 	atomic_set(&hif_sdio_load_state, true);
188 	wake_up_interruptible(&sync_wait_queue);
189 
190 	return 0;
191 
192 err_attach1:
193 	qdf_mem_free(ol_sc);
194 err_attach:
195 	qdf_mem_free(scn);
196 	scn = NULL;
197 err_alloc:
198 	return ret;
199 }
200 
201 /**
202  * ol_ath_sdio_configure() - configure sdio device
203  * @hif_sc: pointer to sdio softc structure
204  * @dev: pointer to net device
205  * @hif_handle: pointer to sdio function
206  *
207  * Return: 0 for success and non-zero for failure
208  */
209 int
210 ol_ath_sdio_configure(void *hif_sc, struct net_device *dev,
211 		      hif_handle_t *hif_hdl)
212 {
213 	struct hif_sdio_softc *sc = (struct hif_sdio_softc *)hif_sc;
214 	int ret = 0;
215 
216 	sc->aps_osdev.netdev = dev;
217 	*hif_hdl = sc->hif_handle;
218 
219 	return ret;
220 }
221 
222 /**
223  * hif_sdio_remove() - remove sdio device
224  * @conext: sdio device context
225  * @hif_handle: pointer to sdio function
226  *
227  * Return: 0 for success and non-zero for failure
228  */
229 static A_STATUS hif_sdio_remove(void *context, void *hif_handle)
230 {
231 	HIF_ENTER();
232 
233 	if (!scn) {
234 		QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR,
235 			  "Global SDIO context is NULL");
236 		return A_ERROR;
237 	}
238 
239 	atomic_set(&hif_sdio_load_state, false);
240 	athdiag_procfs_remove();
241 
242 #ifndef TARGET_DUMP_FOR_NON_QC_PLATFORM
243 	iounmap(scn->ramdump_base);
244 #endif
245 
246 	if (scn) {
247 		qdf_mem_free(scn);
248 		scn = NULL;
249 	}
250 
251 	HIF_EXIT();
252 
253 	return 0;
254 }
255 
256 /**
257  * hif_sdio_suspend() - sdio suspend routine
258  * @context: sdio device context
259  *
260  * Return: 0 for success and non-zero for failure
261  */
262 static A_STATUS hif_sdio_suspend(void *context)
263 {
264 	return 0;
265 }
266 
267 /**
268  * hif_sdio_resume() - sdio resume routine
269  * @context: sdio device context
270  *
271  * Return: 0 for success and non-zero for failure
272  */
273 static A_STATUS hif_sdio_resume(void *context)
274 {
275 	return 0;
276 }
277 
278 /**
279  * hif_sdio_power_change() - change power state of sdio bus
280  * @conext: sdio device context
281  * @config: power state configurartion
282  *
283  * Return: 0 for success and non-zero for failure
284  */
285 static A_STATUS hif_sdio_power_change(void *context, uint32_t config)
286 {
287 	return 0;
288 }
289 
290 /*
291  * Module glue.
292  */
293 #include <linux/version.h>
294 static char *version = "HIF (Atheros/multi-bss)";
295 static char *dev_info = "ath_hif_sdio";
296 
297 /**
298  * init_ath_hif_sdio() - initialize hif sdio callbacks
299  * @param: none
300  *
301  * Return: 0 for success and non-zero for failure
302  */
303 static int init_ath_hif_sdio(void)
304 {
305 	static int probed;
306 	QDF_STATUS status;
307 	struct osdrv_callbacks osdrv_callbacks;
308 
309 	HIF_ENTER();
310 	qdf_mem_zero(&osdrv_callbacks, sizeof(osdrv_callbacks));
311 	osdrv_callbacks.device_inserted_handler = hif_sdio_probe;
312 	osdrv_callbacks.device_removed_handler = hif_sdio_remove;
313 	osdrv_callbacks.device_suspend_handler = hif_sdio_suspend;
314 	osdrv_callbacks.device_resume_handler = hif_sdio_resume;
315 	osdrv_callbacks.device_power_change_handler = hif_sdio_power_change;
316 
317 	if (probed)
318 		return -ENODEV;
319 	probed++;
320 
321 	QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, "%s %d", __func__,
322 		  __LINE__);
323 	status = hif_init(&osdrv_callbacks);
324 	if (status != QDF_STATUS_SUCCESS) {
325 		QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
326 			  "%s hif_init failed!", __func__);
327 		return -ENODEV;
328 	}
329 	QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR,
330 		 "%s: %s\n", dev_info, version);
331 
332 	return 0;
333 }
334 
335 /**
336  * hif_targ_is_awake(): check if target is awake
337  *
338  * This function returns true if the target is awake
339  *
340  * @scn: struct hif_softc
341  * @mem: mapped mem base
342  *
343  * Return: bool
344  */
345 bool hif_targ_is_awake(struct hif_softc *scn, void *__iomem *mem)
346 {
347 	return true;
348 }
349 
350 /**
351  * hif_sdio_bus_suspend() - suspend the bus
352  *
353  * This function suspends the bus, but sdio doesn't need to suspend.
354  * Therefore do nothing.
355  *
356  * Return: 0 for success and non-zero for failure
357  */
358 int hif_sdio_bus_suspend(struct hif_softc *hif_ctx)
359 {
360 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx);
361 	struct hif_sdio_dev *hif_device = scn->hif_handle;
362 	struct device *dev = &hif_device->func->dev;
363 
364 	hif_device_suspend(dev);
365 	return 0;
366 }
367 
368 
369 /**
370  * hif_sdio_bus_resume() - hif resume API
371  *
372  * This function resumes the bus. but sdio doesn't need to resume.
373  * Therefore do nothing.
374  *
375  * Return: 0 for success and non-zero for failure
376  */
377 int hif_sdio_bus_resume(struct hif_softc *hif_ctx)
378 {
379 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx);
380 	struct hif_sdio_dev *hif_device = scn->hif_handle;
381 	struct device *dev = &hif_device->func->dev;
382 
383 	hif_device_resume(dev);
384 	return 0;
385 }
386 
387 /**
388  * hif_enable_power_gating() - enable HW power gating
389  *
390  * Return: n/a
391  */
392 void hif_enable_power_gating(void *hif_ctx)
393 {
394 }
395 
396 /**
397  * hif_disable_aspm() - hif_disable_aspm
398  *
399  * Return: n/a
400  */
401 void hif_disable_aspm(void)
402 {
403 }
404 
405 /**
406  * hif_sdio_close() - hif_bus_close
407  *
408  * Return: None
409  */
410 void hif_sdio_close(struct hif_softc *hif_sc)
411 {
412 }
413 
414 /**
415  * hif_sdio_open() - hif_bus_open
416  * @hif_sc: hif context
417  * @bus_type: bus type
418  *
419  * Return: QDF status
420  */
421 QDF_STATUS hif_sdio_open(struct hif_softc *hif_sc,
422 				   enum qdf_bus_type bus_type)
423 {
424 	QDF_STATUS status;
425 
426 	hif_sc->bus_type = bus_type;
427 	status = init_ath_hif_sdio();
428 
429 	return status;
430 }
431 
432 /**
433  * hif_get_target_type() - Get the target type
434  *
435  * This function is used to query the target type.
436  *
437  * @ol_sc: ol_softc struct pointer
438  * @dev: device pointer
439  * @bdev: bus dev pointer
440  * @bid: bus id pointer
441  * @hif_type: HIF type such as HIF_TYPE_QCA6180
442  * @target_type: target type such as TARGET_TYPE_QCA6180
443  *
444  * Return: 0 for success
445  */
446 int hif_get_target_type(struct hif_softc *ol_sc, struct device *dev,
447 	void *bdev, const hif_bus_id *bid, uint32_t *hif_type,
448 	uint32_t *target_type)
449 {
450 
451 	return 0;
452 }
453 
454 void hif_get_target_revision(struct hif_softc *ol_sc)
455 {
456 	struct hif_softc *ol_sc_local = (struct hif_softc *)ol_sc;
457 	struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc_local);
458 	uint32_t chip_id = 0;
459 	QDF_STATUS rv;
460 
461 	rv = hif_diag_read_access(hif_hdl,
462 			(CHIP_ID_ADDRESS | RTC_SOC_BASE_ADDRESS), &chip_id);
463 	if (rv != QDF_STATUS_SUCCESS) {
464 		HIF_ERROR("%s[%d]: get chip id fail\n", __func__, __LINE__);
465 	} else {
466 		ol_sc_local->target_info.target_revision =
467 			CHIP_ID_REVISION_GET(chip_id);
468 	}
469 }
470 
471 /**
472  * hif_sdio_enable_bus() - hif_enable_bus
473  * @hif_sc: hif context
474  * @dev: dev
475  * @bdev: bus dev
476  * @bid: bus id
477  * @type: bus type
478  *
479  * Return: QDF_STATUS
480  */
481 QDF_STATUS hif_sdio_enable_bus(struct hif_softc *hif_sc,
482 			struct device *dev, void *bdev,
483 			const struct hif_bus_id *bid,
484 			enum hif_enable_type type)
485 {
486 	int ret = 0;
487 	const struct sdio_device_id *id = (const struct sdio_device_id *)bid;
488 	struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc);
489 
490 	init_waitqueue_head(&sync_wait_queue);
491 	if (hif_sdio_device_inserted(dev, id)) {
492 		HIF_ERROR("wlan: %s hif_sdio_device_inserted failed", __func__);
493 		return QDF_STATUS_E_NOMEM;
494 	}
495 
496 	wait_event_interruptible_timeout(sync_wait_queue,
497 			  atomic_read(&hif_sdio_load_state) == true,
498 			  HIF_SDIO_LOAD_TIMEOUT);
499 	hif_sc->hostdef = ol_sc->hostdef;
500 	hif_sc->targetdef = ol_sc->targetdef;
501 	hif_sc->bus_type = ol_sc->bus_type;
502 	hif_sc->target_info.target_type = ol_sc->target_info.target_type;
503 
504 	sc->hif_handle = scn->hif_handle;
505 	sc->aps_osdev.device = scn->aps_osdev.device;
506 	sc->aps_osdev.bc.bc_bustype = scn->aps_osdev.bc.bc_bustype;
507 	sc->target_lock = scn->target_lock;
508 	sc->targetdef = scn->targetdef;
509 	sc->hostdef = scn->hostdef;
510 	sc->aps_osdev.bdev = scn->aps_osdev.bdev;
511 	sc->ramdump_size = scn->ramdump_size;
512 	sc->ramdump_base = scn->ramdump_base;
513 
514 	return ret;
515 }
516 
517 
518 /**
519  * hif_sdio_disable_bus() - sdio disable bus
520  * @hif_sc: hif softc pointer
521  *
522  * Return: none
523  */
524 void hif_sdio_disable_bus(struct hif_softc *hif_sc)
525 {
526 	struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc);
527 	struct sdio_func *func = sc->aps_osdev.bdev;
528 
529 	hif_sdio_device_removed(func);
530 }
531 
532 /**
533  * hif_sdio_get_config_item - sdio configure bus
534  * @hif_sc: hif context
535  * @opcode: configuration type
536  * @config: configuration value to set
537  * @config_len: configuration length
538  *
539  * Return: QDF_STATUS_SUCCESS for sucess
540  */
541 QDF_STATUS hif_sdio_get_config_item(struct hif_softc *hif_sc,
542 		     int opcode, void *config, uint32_t config_len)
543 {
544 	struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc);
545 	struct hif_sdio_dev *hif_device = sc->hif_handle;
546 
547 	return hif_configure_device(hif_device,
548 				opcode, config, config_len);
549 }
550 
551 /**
552  * hif_sdio_set_mailbox_swap - set mailbox swap
553  * @hif_sc: hif context
554  *
555  * Return: None
556  */
557 void hif_sdio_set_mailbox_swap(struct hif_softc *hif_sc)
558 {
559 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc);
560 	struct hif_sdio_dev *hif_device = scn->hif_handle;
561 
562 	hif_device->swap_mailbox = true;
563 }
564 
565 /**
566  * hif_sdio_claim_device - set mailbox swap
567  * @hif_sc: hif context
568  *
569  * Return: None
570  */
571 void hif_sdio_claim_device(struct hif_softc *hif_sc)
572 {
573 	struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc);
574 	struct hif_sdio_dev *hif_device = scn->hif_handle;
575 
576 	hif_device->claimed_ctx = hif_sc;
577 }
578 
579 /**
580  * hif_sdio_mask_interrupt_call() - disbale hif device irq
581  * @scn: pointr to softc structure
582  *
583  * Return: None
584  */
585 void hif_sdio_mask_interrupt_call(struct hif_softc *scn)
586 {
587 	struct hif_sdio_softc *hif_ctx = HIF_GET_SDIO_SOFTC(scn);
588 	struct hif_sdio_dev *hif_device = hif_ctx->hif_handle;
589 
590 	hif_mask_interrupt(hif_device);
591 }
592 
593 /**
594  * hif_trigger_dump() - trigger various dump cmd
595  * @scn: struct hif_opaque_softc
596  * @cmd_id: dump command id
597  * @start: start/stop dump
598  *
599  * Return: None
600  */
601 void hif_trigger_dump(struct hif_opaque_softc *scn, uint8_t cmd_id, bool start)
602 {
603 }
604 
605 /**
606  * hif_check_fw_reg() - hif_check_fw_reg
607  * @scn: scn
608  * @state:
609  *
610  * Return: int
611  */
612 int hif_check_fw_reg(struct hif_opaque_softc *scn)
613 {
614 	return 0;
615 }
616 
617 /**
618  * hif_wlan_disable() - call the platform driver to disable wlan
619  * @scn: scn
620  *
621  * Return: void
622  */
623 void hif_wlan_disable(struct hif_softc *scn)
624 {
625 }
626 
627 /**
628  * hif_config_target() - configure hif bus
629  * @hif_hdl: hif handle
630  * @state:
631  *
632  * Return: int
633  */
634 int hif_config_target(void *hif_hdl)
635 {
636 	return 0;
637 }
638