1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * BCMSDH interface glue
3*4882a593Smuzhiyun * implement bcmsdh API for SDIOH driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2020, Broadcom.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Unless you and Broadcom execute a separate written software license
8*4882a593Smuzhiyun * agreement governing use of this software, this software is licensed to you
9*4882a593Smuzhiyun * under the terms of the GNU General Public License version 2 (the "GPL"),
10*4882a593Smuzhiyun * available at http://www.broadcom.com/licenses/GPLv2.php, with the
11*4882a593Smuzhiyun * following added to such license:
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * As a special exception, the copyright holders of this software give you
14*4882a593Smuzhiyun * permission to link this software with independent modules, and to copy and
15*4882a593Smuzhiyun * distribute the resulting executable under terms of your choice, provided that
16*4882a593Smuzhiyun * you also meet, for each linked independent module, the terms and conditions of
17*4882a593Smuzhiyun * the license of that module. An independent module is a module which is not
18*4882a593Smuzhiyun * derived from this software. The special exception does not apply to any
19*4882a593Smuzhiyun * modifications of the software.
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * <<Broadcom-WL-IPTag/Open:>>
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * $Id$
25*4882a593Smuzhiyun */
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /**
28*4882a593Smuzhiyun * @file bcmsdh.c
29*4882a593Smuzhiyun */
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun /* ****************** BCMSDH Interface Functions *************************** */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #include <typedefs.h>
34*4882a593Smuzhiyun #include <bcmdevs.h>
35*4882a593Smuzhiyun #include <bcmendian.h>
36*4882a593Smuzhiyun #include <bcmutils.h>
37*4882a593Smuzhiyun #include <hndsoc.h>
38*4882a593Smuzhiyun #include <siutils.h>
39*4882a593Smuzhiyun #if !defined(BCMDONGLEHOST)
40*4882a593Smuzhiyun #include <bcmsrom.h>
41*4882a593Smuzhiyun #endif /* !defined(BCMDONGLEHOST) */
42*4882a593Smuzhiyun #include <osl.h>
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #include <bcmsdh.h> /* BRCM API for SDIO clients (such as wl, dhd) */
45*4882a593Smuzhiyun #include <bcmsdbus.h> /* common SDIO/controller interface */
46*4882a593Smuzhiyun #include <sbsdio.h> /* SDIO device core hardware definitions. */
47*4882a593Smuzhiyun #include <sdio.h> /* SDIO Device and Protocol Specs */
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #if defined (BT_OVER_SDIO)
50*4882a593Smuzhiyun #include <dhd_bt_interface.h>
51*4882a593Smuzhiyun #endif /* defined (BT_OVER_SDIO) */
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun #define SDIOH_API_ACCESS_RETRY_LIMIT 2
54*4882a593Smuzhiyun const uint bcmsdh_msglevel = BCMSDH_ERROR_VAL;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /* local copy of bcm sd handler */
57*4882a593Smuzhiyun bcmsdh_info_t * l_bcmsdh = NULL;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun #if defined (BT_OVER_SDIO)
60*4882a593Smuzhiyun struct sdio_func *func_f3 = NULL;
61*4882a593Smuzhiyun static f3intr_handler processf3intr = NULL;
62*4882a593Smuzhiyun static dhd_hang_notification process_dhd_hang_notification = NULL;
63*4882a593Smuzhiyun static dhd_hang_state_t g_dhd_hang_state = NO_HANG_STATE;
64*4882a593Smuzhiyun #endif /* defined (BT_OVER_SDIO) */
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun #if defined(NDIS) && (NDISVER < 0x0630)
67*4882a593Smuzhiyun extern SDIOH_API_RC sdioh_detach(osl_t *osh, sdioh_info_t *sd);
68*4882a593Smuzhiyun #endif
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun #if defined(OOB_INTR_ONLY) && defined(HW_OOB) || defined(FORCE_WOWLAN)
71*4882a593Smuzhiyun extern int
72*4882a593Smuzhiyun sdioh_enable_hw_oob_intr(void *sdioh, bool enable);
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun void
bcmsdh_enable_hw_oob_intr(bcmsdh_info_t * sdh,bool enable)75*4882a593Smuzhiyun bcmsdh_enable_hw_oob_intr(bcmsdh_info_t *sdh, bool enable)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun sdioh_enable_hw_oob_intr(sdh->sdioh, enable);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun #endif
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun #if defined (BT_OVER_SDIO)
bcmsdh_btsdio_process_hang_state(dhd_hang_state_t new_state)82*4882a593Smuzhiyun void bcmsdh_btsdio_process_hang_state(dhd_hang_state_t new_state)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun bool state_change = false;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun BCMSDH_ERROR(("%s: DHD hang state changed - [%d] -> [%d]\n",
87*4882a593Smuzhiyun __FUNCTION__, g_dhd_hang_state, new_state));
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (g_dhd_hang_state == new_state)
90*4882a593Smuzhiyun return;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun switch (g_dhd_hang_state) {
93*4882a593Smuzhiyun case NO_HANG_STATE:
94*4882a593Smuzhiyun if (HANG_START_STATE == new_state)
95*4882a593Smuzhiyun state_change = true;
96*4882a593Smuzhiyun break;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun case HANG_START_STATE:
99*4882a593Smuzhiyun if (HANG_RECOVERY_STATE == new_state ||
100*4882a593Smuzhiyun NO_HANG_STATE == new_state)
101*4882a593Smuzhiyun state_change = true;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun break;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun case HANG_RECOVERY_STATE:
106*4882a593Smuzhiyun if (NO_HANG_STATE == new_state)
107*4882a593Smuzhiyun state_change = true;
108*4882a593Smuzhiyun break;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun default:
111*4882a593Smuzhiyun BCMSDH_ERROR(("%s: Unhandled Hang state\n", __FUNCTION__));
112*4882a593Smuzhiyun break;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun if (!state_change) {
116*4882a593Smuzhiyun BCMSDH_ERROR(("%s: Hang state cannot be changed\n", __FUNCTION__));
117*4882a593Smuzhiyun return;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun g_dhd_hang_state = new_state;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
bcmsdh_btsdio_process_f3_intr(void)123*4882a593Smuzhiyun void bcmsdh_btsdio_process_f3_intr(void)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun if (processf3intr && (g_dhd_hang_state == NO_HANG_STATE))
126*4882a593Smuzhiyun processf3intr(func_f3);
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
bcmsdh_btsdio_process_dhd_hang_notification(bool wifi_recovery_completed)129*4882a593Smuzhiyun void bcmsdh_btsdio_process_dhd_hang_notification(bool wifi_recovery_completed)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun bcmsdh_btsdio_process_hang_state(HANG_START_STATE);
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun if (process_dhd_hang_notification)
134*4882a593Smuzhiyun process_dhd_hang_notification(func_f3, wifi_recovery_completed);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /* WiFi was off, so HANG_RECOVERY_STATE is not needed */
137*4882a593Smuzhiyun if (wifi_recovery_completed)
138*4882a593Smuzhiyun bcmsdh_btsdio_process_hang_state(NO_HANG_STATE);
139*4882a593Smuzhiyun else {
140*4882a593Smuzhiyun bcmsdh_btsdio_process_hang_state(HANG_RECOVERY_STATE);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
bcmsdh_btsdio_interface_init(struct sdio_func * func,f3intr_handler f3intr_fun,dhd_hang_notification hang_notification)144*4882a593Smuzhiyun void bcmsdh_btsdio_interface_init(struct sdio_func *func,
145*4882a593Smuzhiyun f3intr_handler f3intr_fun, dhd_hang_notification hang_notification)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)l_bcmsdh;
148*4882a593Smuzhiyun BCMSDH_INFO(("%s: func %p \n", __FUNCTION__, func));
149*4882a593Smuzhiyun func_f3 = func;
150*4882a593Smuzhiyun processf3intr = f3intr_fun;
151*4882a593Smuzhiyun sdioh_sdmmc_card_enable_func_f3(bcmsdh->sdioh, func);
152*4882a593Smuzhiyun process_dhd_hang_notification = hang_notification;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun } EXPORT_SYMBOL(bcmsdh_btsdio_interface_init);
155*4882a593Smuzhiyun #endif /* defined (BT_OVER_SDIO) */
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* Attach BCMSDH layer to SDIO Host Controller Driver
158*4882a593Smuzhiyun *
159*4882a593Smuzhiyun * @param osh OSL Handle.
160*4882a593Smuzhiyun * @param cfghdl Configuration Handle.
161*4882a593Smuzhiyun * @param regsva Virtual address of controller registers.
162*4882a593Smuzhiyun * @param irq Interrupt number of SDIO controller.
163*4882a593Smuzhiyun *
164*4882a593Smuzhiyun * @return bcmsdh_info_t Handle to BCMSDH context.
165*4882a593Smuzhiyun */
166*4882a593Smuzhiyun bcmsdh_info_t *
bcmsdh_attach(osl_t * osh,void * sdioh,ulong * regsva)167*4882a593Smuzhiyun bcmsdh_attach(osl_t *osh, void *sdioh, ulong *regsva)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun if ((bcmsdh = (bcmsdh_info_t *)MALLOC(osh, sizeof(bcmsdh_info_t))) == NULL) {
172*4882a593Smuzhiyun BCMSDH_ERROR(("bcmsdh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
173*4882a593Smuzhiyun return NULL;
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun bzero((char *)bcmsdh, sizeof(bcmsdh_info_t));
176*4882a593Smuzhiyun bcmsdh->sdioh = sdioh;
177*4882a593Smuzhiyun bcmsdh->osh = osh;
178*4882a593Smuzhiyun bcmsdh->init_success = TRUE;
179*4882a593Smuzhiyun *regsva = si_enum_base(0);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun bcmsdh_force_sbwad_calc(bcmsdh, FALSE);
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /* Report the BAR, to fix if needed */
184*4882a593Smuzhiyun bcmsdh->sbwad = si_enum_base(0);
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun /* save the handler locally */
187*4882a593Smuzhiyun l_bcmsdh = bcmsdh;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return bcmsdh;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun int
bcmsdh_detach(osl_t * osh,void * sdh)193*4882a593Smuzhiyun bcmsdh_detach(osl_t *osh, void *sdh)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun if (bcmsdh != NULL) {
198*4882a593Smuzhiyun #if defined(NDIS) && (NDISVER < 0x0630)
199*4882a593Smuzhiyun if (bcmsdh->sdioh)
200*4882a593Smuzhiyun sdioh_detach(osh, bcmsdh->sdioh);
201*4882a593Smuzhiyun #endif
202*4882a593Smuzhiyun MFREE(osh, bcmsdh, sizeof(bcmsdh_info_t));
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun l_bcmsdh = NULL;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun int
bcmsdh_iovar_op(void * sdh,const char * name,void * params,uint plen,void * arg,uint len,bool set)211*4882a593Smuzhiyun bcmsdh_iovar_op(void *sdh, const char *name,
212*4882a593Smuzhiyun void *params, uint plen, void *arg, uint len, bool set)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
215*4882a593Smuzhiyun return sdioh_iovar_op(bcmsdh->sdioh, name, params, plen, arg, len, set);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun bool
bcmsdh_intr_query(void * sdh)219*4882a593Smuzhiyun bcmsdh_intr_query(void *sdh)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
222*4882a593Smuzhiyun SDIOH_API_RC status;
223*4882a593Smuzhiyun bool on;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun ASSERT(bcmsdh);
226*4882a593Smuzhiyun status = sdioh_interrupt_query(bcmsdh->sdioh, &on);
227*4882a593Smuzhiyun if (SDIOH_API_SUCCESS(status))
228*4882a593Smuzhiyun return FALSE;
229*4882a593Smuzhiyun else
230*4882a593Smuzhiyun return on;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun int
bcmsdh_intr_enable(void * sdh)234*4882a593Smuzhiyun bcmsdh_intr_enable(void *sdh)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
237*4882a593Smuzhiyun SDIOH_API_RC status;
238*4882a593Smuzhiyun #ifdef BCMSPI_ANDROID
239*4882a593Smuzhiyun uint32 data;
240*4882a593Smuzhiyun #endif /* BCMSPI_ANDROID */
241*4882a593Smuzhiyun ASSERT(bcmsdh);
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun status = sdioh_interrupt_set(bcmsdh->sdioh, TRUE);
244*4882a593Smuzhiyun #ifdef BCMSPI_ANDROID
245*4882a593Smuzhiyun data = bcmsdh_cfg_read_word(sdh, 0, 4, NULL);
246*4882a593Smuzhiyun data |= 0xE0E70000;
247*4882a593Smuzhiyun bcmsdh_cfg_write_word(sdh, 0, 4, data, NULL);
248*4882a593Smuzhiyun #endif /* BCMSPI_ANDROID */
249*4882a593Smuzhiyun return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun int
bcmsdh_intr_disable(void * sdh)253*4882a593Smuzhiyun bcmsdh_intr_disable(void *sdh)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
256*4882a593Smuzhiyun SDIOH_API_RC status;
257*4882a593Smuzhiyun #ifdef BCMSPI_ANDROID
258*4882a593Smuzhiyun uint32 data;
259*4882a593Smuzhiyun #endif /* BCMSPI_ANDROID */
260*4882a593Smuzhiyun ASSERT(bcmsdh);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun status = sdioh_interrupt_set(bcmsdh->sdioh, FALSE);
263*4882a593Smuzhiyun #ifdef BCMSPI_ANDROID
264*4882a593Smuzhiyun data = bcmsdh_cfg_read_word(sdh, 0, 4, NULL);
265*4882a593Smuzhiyun data &= ~0xE0E70000;
266*4882a593Smuzhiyun bcmsdh_cfg_write_word(sdh, 0, 4, data, NULL);
267*4882a593Smuzhiyun #endif /* BCMSPI_ANDROID */
268*4882a593Smuzhiyun return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun int
bcmsdh_intr_reg(void * sdh,bcmsdh_cb_fn_t fn,void * argh)272*4882a593Smuzhiyun bcmsdh_intr_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
275*4882a593Smuzhiyun SDIOH_API_RC status;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun if (!bcmsdh)
278*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun ASSERT(bcmsdh);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun status = sdioh_interrupt_register(bcmsdh->sdioh, fn, argh);
283*4882a593Smuzhiyun return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun int
bcmsdh_intr_dereg(void * sdh)287*4882a593Smuzhiyun bcmsdh_intr_dereg(void *sdh)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
290*4882a593Smuzhiyun SDIOH_API_RC status;
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun if (!bcmsdh)
293*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun ASSERT(bcmsdh);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun status = sdioh_interrupt_deregister(bcmsdh->sdioh);
298*4882a593Smuzhiyun return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun #if defined(DHD_DEBUG) || defined(BCMDBG)
302*4882a593Smuzhiyun bool
bcmsdh_intr_pending(void * sdh)303*4882a593Smuzhiyun bcmsdh_intr_pending(void *sdh)
304*4882a593Smuzhiyun {
305*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun ASSERT(sdh);
308*4882a593Smuzhiyun return sdioh_interrupt_pending(bcmsdh->sdioh);
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun #endif
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun int
bcmsdh_devremove_reg(void * sdh,bcmsdh_cb_fn_t fn,void * argh)313*4882a593Smuzhiyun bcmsdh_devremove_reg(void *sdh, bcmsdh_cb_fn_t fn, void *argh)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun ASSERT(sdh);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /* don't support yet */
318*4882a593Smuzhiyun return BCME_UNSUPPORTED;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun /**
322*4882a593Smuzhiyun * Read from SDIO Configuration Space
323*4882a593Smuzhiyun * @param sdh SDIO Host context.
324*4882a593Smuzhiyun * @param func_num Function number to read from.
325*4882a593Smuzhiyun * @param addr Address to read from.
326*4882a593Smuzhiyun * @param err Error return.
327*4882a593Smuzhiyun * @return value read from SDIO configuration space.
328*4882a593Smuzhiyun */
329*4882a593Smuzhiyun uint8
bcmsdh_cfg_read(void * sdh,uint fnc_num,uint32 addr,int * err)330*4882a593Smuzhiyun bcmsdh_cfg_read(void *sdh, uint fnc_num, uint32 addr, int *err)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
333*4882a593Smuzhiyun SDIOH_API_RC status;
334*4882a593Smuzhiyun #ifdef SDIOH_API_ACCESS_RETRY_LIMIT
335*4882a593Smuzhiyun int32 retry = 0;
336*4882a593Smuzhiyun #endif
337*4882a593Smuzhiyun uint8 data = 0;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun if (!bcmsdh)
340*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun #ifdef SDIOH_API_ACCESS_RETRY_LIMIT
345*4882a593Smuzhiyun do {
346*4882a593Smuzhiyun if (retry) /* wait for 1 ms till bus get settled down */
347*4882a593Smuzhiyun OSL_DELAY(1000);
348*4882a593Smuzhiyun #endif
349*4882a593Smuzhiyun status = sdioh_cfg_read(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
350*4882a593Smuzhiyun #ifdef SDIOH_API_ACCESS_RETRY_LIMIT
351*4882a593Smuzhiyun } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
352*4882a593Smuzhiyun #endif
353*4882a593Smuzhiyun if (err)
354*4882a593Smuzhiyun *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
357*4882a593Smuzhiyun fnc_num, addr, data));
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun return data;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun #ifdef BCMSDH_MODULE
362*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_cfg_read);
363*4882a593Smuzhiyun #endif
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun void
bcmsdh_cfg_write(void * sdh,uint fnc_num,uint32 addr,uint8 data,int * err)366*4882a593Smuzhiyun bcmsdh_cfg_write(void *sdh, uint fnc_num, uint32 addr, uint8 data, int *err)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
369*4882a593Smuzhiyun SDIOH_API_RC status;
370*4882a593Smuzhiyun #ifdef SDIOH_API_ACCESS_RETRY_LIMIT
371*4882a593Smuzhiyun int32 retry = 0;
372*4882a593Smuzhiyun #endif
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (!bcmsdh)
375*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun #ifdef SDIOH_API_ACCESS_RETRY_LIMIT
380*4882a593Smuzhiyun do {
381*4882a593Smuzhiyun if (retry) /* wait for 1 ms till bus get settled down */
382*4882a593Smuzhiyun OSL_DELAY(1000);
383*4882a593Smuzhiyun #endif
384*4882a593Smuzhiyun status = sdioh_cfg_write(bcmsdh->sdioh, fnc_num, addr, (uint8 *)&data);
385*4882a593Smuzhiyun #ifdef SDIOH_API_ACCESS_RETRY_LIMIT
386*4882a593Smuzhiyun } while (!SDIOH_API_SUCCESS(status) && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
387*4882a593Smuzhiyun #endif
388*4882a593Smuzhiyun if (err)
389*4882a593Smuzhiyun *err = SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint8data = 0x%x\n", __FUNCTION__,
392*4882a593Smuzhiyun fnc_num, addr, data));
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun #ifdef BCMSDH_MODULE
395*4882a593Smuzhiyun EXPORT_SYMBOL(bcmsdh_cfg_write);
396*4882a593Smuzhiyun #endif
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun uint32
bcmsdh_cfg_read_word(void * sdh,uint fnc_num,uint32 addr,int * err)399*4882a593Smuzhiyun bcmsdh_cfg_read_word(void *sdh, uint fnc_num, uint32 addr, int *err)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
402*4882a593Smuzhiyun SDIOH_API_RC status;
403*4882a593Smuzhiyun uint32 data = 0;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun if (!bcmsdh)
406*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_READ, fnc_num,
411*4882a593Smuzhiyun addr, &data, 4);
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun if (err)
414*4882a593Smuzhiyun *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__,
417*4882a593Smuzhiyun fnc_num, addr, data));
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun return data;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun void
bcmsdh_cfg_write_word(void * sdh,uint fnc_num,uint32 addr,uint32 data,int * err)423*4882a593Smuzhiyun bcmsdh_cfg_write_word(void *sdh, uint fnc_num, uint32 addr, uint32 data, int *err)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
426*4882a593Smuzhiyun SDIOH_API_RC status;
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun if (!bcmsdh)
429*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, fnc_num,
434*4882a593Smuzhiyun addr, &data, 4);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if (err)
437*4882a593Smuzhiyun *err = (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, uint32data = 0x%x\n", __FUNCTION__, fnc_num,
440*4882a593Smuzhiyun addr, data));
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun int
bcmsdh_cis_read(void * sdh,uint func,uint8 * cis,uint length)444*4882a593Smuzhiyun bcmsdh_cis_read(void *sdh, uint func, uint8 *cis, uint length)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
447*4882a593Smuzhiyun SDIOH_API_RC status;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun uint8 *tmp_buf, *tmp_ptr;
450*4882a593Smuzhiyun uint8 *ptr;
451*4882a593Smuzhiyun bool ascii = func & ~0xf;
452*4882a593Smuzhiyun func &= 0x7;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun if (!bcmsdh)
455*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
458*4882a593Smuzhiyun ASSERT(cis);
459*4882a593Smuzhiyun ASSERT(length <= SBSDIO_CIS_SIZE_LIMIT);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun status = sdioh_cis_read(bcmsdh->sdioh, func, cis, length);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun if (ascii) {
464*4882a593Smuzhiyun /* Move binary bits to tmp and format them into the provided buffer. */
465*4882a593Smuzhiyun if ((tmp_buf = (uint8 *)MALLOC(bcmsdh->osh, length)) == NULL) {
466*4882a593Smuzhiyun BCMSDH_ERROR(("%s: out of memory\n", __FUNCTION__));
467*4882a593Smuzhiyun return BCME_NOMEM;
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun bcopy(cis, tmp_buf, length);
470*4882a593Smuzhiyun for (tmp_ptr = tmp_buf, ptr = cis; ptr < (cis + length - 4); tmp_ptr++) {
471*4882a593Smuzhiyun ptr += snprintf((char*)ptr, (cis + length - ptr - 4),
472*4882a593Smuzhiyun "%.2x ", *tmp_ptr & 0xff);
473*4882a593Smuzhiyun if ((((tmp_ptr - tmp_buf) + 1) & 0xf) == 0)
474*4882a593Smuzhiyun ptr += snprintf((char *)ptr, (cis + length - ptr -4), "\n");
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun MFREE(bcmsdh->osh, tmp_buf, length);
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun int
bcmsdh_cisaddr_read(void * sdh,uint func,uint8 * cisd,uint32 offset)483*4882a593Smuzhiyun bcmsdh_cisaddr_read(void *sdh, uint func, uint8 *cisd, uint32 offset)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
486*4882a593Smuzhiyun SDIOH_API_RC status;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun func &= 0x7;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun if (!bcmsdh)
491*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
494*4882a593Smuzhiyun ASSERT(cisd);
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun status = sdioh_cisaddr_read(bcmsdh->sdioh, func, cisd, offset);
497*4882a593Smuzhiyun
498*4882a593Smuzhiyun return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun int
bcmsdhsdio_set_sbaddr_window(void * sdh,uint32 address,bool force_set)503*4882a593Smuzhiyun bcmsdhsdio_set_sbaddr_window(void *sdh, uint32 address, bool force_set)
504*4882a593Smuzhiyun {
505*4882a593Smuzhiyun int err = 0;
506*4882a593Smuzhiyun uint bar0 = address & ~SBSDIO_SB_OFT_ADDR_MASK;
507*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun if (bar0 != bcmsdh->sbwad || force_set) {
510*4882a593Smuzhiyun bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
511*4882a593Smuzhiyun (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
512*4882a593Smuzhiyun if (!err)
513*4882a593Smuzhiyun bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID,
514*4882a593Smuzhiyun (address >> 16) & SBSDIO_SBADDRMID_MASK, &err);
515*4882a593Smuzhiyun if (!err)
516*4882a593Smuzhiyun bcmsdh_cfg_write(bcmsdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH,
517*4882a593Smuzhiyun (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err);
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun if (!err)
520*4882a593Smuzhiyun bcmsdh->sbwad = bar0;
521*4882a593Smuzhiyun else
522*4882a593Smuzhiyun /* invalidate cached window var */
523*4882a593Smuzhiyun bcmsdh->sbwad = 0;
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun #ifdef BCMDBG
526*4882a593Smuzhiyun if (err)
527*4882a593Smuzhiyun BCMSDH_ERROR(("%s: error setting address window %08x\n",
528*4882a593Smuzhiyun __FUNCTION__, address));
529*4882a593Smuzhiyun #endif /* BCMDBG */
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun return err;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun uint32
bcmsdh_reg_read(void * sdh,uintptr addr,uint size)536*4882a593Smuzhiyun bcmsdh_reg_read(void *sdh, uintptr addr, uint size)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
539*4882a593Smuzhiyun SDIOH_API_RC status;
540*4882a593Smuzhiyun uint32 word = 0;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun BCMSDH_INFO(("%s:fun = 1, addr = 0x%x\n", __FUNCTION__, (unsigned int)addr));
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun if (!bcmsdh)
545*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun if (bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, bcmsdh->force_sbwad_calc)) {
550*4882a593Smuzhiyun bcmsdh->regfail = TRUE; // terence 20130621: prevent dhd_dpc in dead lock
551*4882a593Smuzhiyun return 0xFFFFFFFF;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun addr &= SBSDIO_SB_OFT_ADDR_MASK;
555*4882a593Smuzhiyun if (size == 4)
556*4882a593Smuzhiyun addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL,
559*4882a593Smuzhiyun SDIOH_READ, SDIO_FUNC_1, addr, &word, size);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun BCMSDH_INFO(("uint32data = 0x%x\n", word));
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun /* if ok, return appropriately masked word */
566*4882a593Smuzhiyun /* XXX Masking was put in for NDIS port, remove if not needed */
567*4882a593Smuzhiyun if (SDIOH_API_SUCCESS(status)) {
568*4882a593Smuzhiyun switch (size) {
569*4882a593Smuzhiyun case sizeof(uint8):
570*4882a593Smuzhiyun return (word & 0xff);
571*4882a593Smuzhiyun case sizeof(uint16):
572*4882a593Smuzhiyun return (word & 0xffff);
573*4882a593Smuzhiyun case sizeof(uint32):
574*4882a593Smuzhiyun return word;
575*4882a593Smuzhiyun default:
576*4882a593Smuzhiyun bcmsdh->regfail = TRUE;
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun /* otherwise, bad sdio access or invalid size */
582*4882a593Smuzhiyun BCMSDH_ERROR(("%s: error reading addr 0x%x size %d\n",
583*4882a593Smuzhiyun __FUNCTION__, (unsigned int)addr, size));
584*4882a593Smuzhiyun return 0xFFFFFFFF;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun uint32
bcmsdh_reg_write(void * sdh,uintptr addr,uint size,uint32 data)588*4882a593Smuzhiyun bcmsdh_reg_write(void *sdh, uintptr addr, uint size, uint32 data)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
591*4882a593Smuzhiyun SDIOH_API_RC status;
592*4882a593Smuzhiyun int err = 0;
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun BCMSDH_INFO(("%s:fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
595*4882a593Smuzhiyun __FUNCTION__, (unsigned int)addr, size*8, data));
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (!bcmsdh)
598*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
601*4882a593Smuzhiyun
602*4882a593Smuzhiyun if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, bcmsdh->force_sbwad_calc))) {
603*4882a593Smuzhiyun bcmsdh->regfail = TRUE; // terence 20130621:
604*4882a593Smuzhiyun return err;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun addr &= SBSDIO_SB_OFT_ADDR_MASK;
608*4882a593Smuzhiyun if (size == 4)
609*4882a593Smuzhiyun addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
610*4882a593Smuzhiyun status = sdioh_request_word(bcmsdh->sdioh, SDIOH_CMD_TYPE_NORMAL, SDIOH_WRITE, SDIO_FUNC_1,
611*4882a593Smuzhiyun addr, &data, size);
612*4882a593Smuzhiyun bcmsdh->regfail = !(SDIOH_API_SUCCESS(status));
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun if (SDIOH_API_SUCCESS(status))
615*4882a593Smuzhiyun return 0;
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun BCMSDH_ERROR(("%s: error writing 0x%08x to addr 0x%04x size %d\n",
618*4882a593Smuzhiyun __FUNCTION__, data, (unsigned int)addr, size));
619*4882a593Smuzhiyun return 0xFFFFFFFF;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun bool
bcmsdh_regfail(void * sdh)623*4882a593Smuzhiyun bcmsdh_regfail(void *sdh)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun return ((bcmsdh_info_t *)sdh)->regfail;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun int
bcmsdh_recv_buf(void * sdh,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete_fn,void * handle)629*4882a593Smuzhiyun bcmsdh_recv_buf(void *sdh, uint32 addr, uint fn, uint flags,
630*4882a593Smuzhiyun uint8 *buf, uint nbytes, void *pkt,
631*4882a593Smuzhiyun bcmsdh_cmplt_fn_t complete_fn, void *handle)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
634*4882a593Smuzhiyun SDIOH_API_RC status;
635*4882a593Smuzhiyun uint incr_fix;
636*4882a593Smuzhiyun uint width;
637*4882a593Smuzhiyun int err = 0;
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun ASSERT(bcmsdh);
640*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
643*4882a593Smuzhiyun __FUNCTION__, fn, addr, nbytes));
644*4882a593Smuzhiyun
645*4882a593Smuzhiyun /* Async not implemented yet */
646*4882a593Smuzhiyun ASSERT(!(flags & SDIO_REQ_ASYNC));
647*4882a593Smuzhiyun if (flags & SDIO_REQ_ASYNC)
648*4882a593Smuzhiyun return BCME_UNSUPPORTED;
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
651*4882a593Smuzhiyun return err;
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun addr &= SBSDIO_SB_OFT_ADDR_MASK;
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
656*4882a593Smuzhiyun width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
657*4882a593Smuzhiyun if (width == 4)
658*4882a593Smuzhiyun addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
661*4882a593Smuzhiyun SDIOH_READ, fn, addr, width, nbytes, buf, pkt);
662*4882a593Smuzhiyun
663*4882a593Smuzhiyun return (SDIOH_API_SUCCESS(status) ? 0 : BCME_SDIO_ERROR);
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun int
bcmsdh_send_buf(void * sdh,uint32 addr,uint fn,uint flags,uint8 * buf,uint nbytes,void * pkt,bcmsdh_cmplt_fn_t complete_fn,void * handle)667*4882a593Smuzhiyun bcmsdh_send_buf(void *sdh, uint32 addr, uint fn, uint flags,
668*4882a593Smuzhiyun uint8 *buf, uint nbytes, void *pkt,
669*4882a593Smuzhiyun bcmsdh_cmplt_fn_t complete_fn, void *handle)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
672*4882a593Smuzhiyun SDIOH_API_RC status;
673*4882a593Smuzhiyun uint incr_fix;
674*4882a593Smuzhiyun uint width;
675*4882a593Smuzhiyun int err = 0;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun ASSERT(bcmsdh);
678*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun BCMSDH_INFO(("%s:fun = %d, addr = 0x%x, size = %d\n",
681*4882a593Smuzhiyun __FUNCTION__, fn, addr, nbytes));
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun /* Async not implemented yet */
684*4882a593Smuzhiyun ASSERT(!(flags & SDIO_REQ_ASYNC));
685*4882a593Smuzhiyun if (flags & SDIO_REQ_ASYNC)
686*4882a593Smuzhiyun return BCME_UNSUPPORTED;
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun if ((err = bcmsdhsdio_set_sbaddr_window(bcmsdh, addr, FALSE)))
689*4882a593Smuzhiyun return err;
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun addr &= SBSDIO_SB_OFT_ADDR_MASK;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun incr_fix = (flags & SDIO_REQ_FIXED) ? SDIOH_DATA_FIX : SDIOH_DATA_INC;
694*4882a593Smuzhiyun width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
695*4882a593Smuzhiyun if (width == 4)
696*4882a593Smuzhiyun addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, incr_fix,
699*4882a593Smuzhiyun SDIOH_WRITE, fn, addr, width, nbytes, buf, pkt);
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
702*4882a593Smuzhiyun }
703*4882a593Smuzhiyun
704*4882a593Smuzhiyun int
bcmsdh_rwdata(void * sdh,uint rw,uint32 addr,uint8 * buf,uint nbytes)705*4882a593Smuzhiyun bcmsdh_rwdata(void *sdh, uint rw, uint32 addr, uint8 *buf, uint nbytes)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
708*4882a593Smuzhiyun SDIOH_API_RC status;
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun ASSERT(bcmsdh);
711*4882a593Smuzhiyun ASSERT(bcmsdh->init_success);
712*4882a593Smuzhiyun ASSERT((addr & SBSDIO_SBWINDOW_MASK) == 0);
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun addr &= SBSDIO_SB_OFT_ADDR_MASK;
715*4882a593Smuzhiyun addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun status = sdioh_request_buffer(bcmsdh->sdioh, SDIOH_DATA_PIO, SDIOH_DATA_INC,
718*4882a593Smuzhiyun (rw ? SDIOH_WRITE : SDIOH_READ), SDIO_FUNC_1,
719*4882a593Smuzhiyun addr, 4, nbytes, buf, NULL);
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun return (SDIOH_API_SUCCESS(status) ? 0 : BCME_ERROR);
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun int
bcmsdh_abort(void * sdh,uint fn)725*4882a593Smuzhiyun bcmsdh_abort(void *sdh, uint fn)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun return sdioh_abort(bcmsdh->sdioh, fn);
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun
732*4882a593Smuzhiyun int
bcmsdh_start(void * sdh,int stage)733*4882a593Smuzhiyun bcmsdh_start(void *sdh, int stage)
734*4882a593Smuzhiyun {
735*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun return sdioh_start(bcmsdh->sdioh, stage);
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun int
bcmsdh_stop(void * sdh)741*4882a593Smuzhiyun bcmsdh_stop(void *sdh)
742*4882a593Smuzhiyun {
743*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun return sdioh_stop(bcmsdh->sdioh);
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun int
bcmsdh_waitlockfree(void * sdh)749*4882a593Smuzhiyun bcmsdh_waitlockfree(void *sdh)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun #ifdef LINUX
752*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun return sdioh_waitlockfree(bcmsdh->sdioh);
755*4882a593Smuzhiyun #else
756*4882a593Smuzhiyun return 0;
757*4882a593Smuzhiyun #endif
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun int
bcmsdh_query_device(void * sdh)761*4882a593Smuzhiyun bcmsdh_query_device(void *sdh)
762*4882a593Smuzhiyun {
763*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
764*4882a593Smuzhiyun #if defined(BCMDONGLEHOST)
765*4882a593Smuzhiyun bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0;
766*4882a593Smuzhiyun #else
767*4882a593Smuzhiyun uint8 *fn0cis[1];
768*4882a593Smuzhiyun int err;
769*4882a593Smuzhiyun char *vars;
770*4882a593Smuzhiyun uint varsz;
771*4882a593Smuzhiyun osl_t *osh = bcmsdh->osh;
772*4882a593Smuzhiyun
773*4882a593Smuzhiyun bcmsdh->vendevid = ~(0);
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun if (!(fn0cis[0] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) {
776*4882a593Smuzhiyun BCMSDH_ERROR(("%s: CIS malloc failed\n", __FUNCTION__));
777*4882a593Smuzhiyun return (bcmsdh->vendevid);
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun
780*4882a593Smuzhiyun bzero(fn0cis[0], SBSDIO_CIS_SIZE_LIMIT);
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun if ((err = bcmsdh_cis_read(sdh, 0, fn0cis[0], SBSDIO_CIS_SIZE_LIMIT))) {
783*4882a593Smuzhiyun BCMSDH_ERROR(("%s: CIS read err %d, report unknown BRCM device\n",
784*4882a593Smuzhiyun __FUNCTION__, err));
785*4882a593Smuzhiyun bcmsdh->vendevid = (VENDOR_BROADCOM << 16) | 0;
786*4882a593Smuzhiyun MFREE(osh, fn0cis[0], SBSDIO_CIS_SIZE_LIMIT);
787*4882a593Smuzhiyun return (bcmsdh->vendevid);
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun if (!err) {
791*4882a593Smuzhiyun if ((err = srom_parsecis(NULL, osh, fn0cis, 1, &vars, &varsz))) {
792*4882a593Smuzhiyun BCMSDH_ERROR(("%s: Error parsing CIS = %d\n", __FUNCTION__, err));
793*4882a593Smuzhiyun } else {
794*4882a593Smuzhiyun bcmsdh->vendevid = (getintvar(vars, "vendid") << 16) |
795*4882a593Smuzhiyun getintvar(vars, "devid");
796*4882a593Smuzhiyun MFREE(osh, vars, varsz);
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun MFREE(osh, fn0cis[0], SBSDIO_CIS_SIZE_LIMIT);
801*4882a593Smuzhiyun #endif /* BCMDONGLEHOST */
802*4882a593Smuzhiyun return (bcmsdh->vendevid);
803*4882a593Smuzhiyun }
804*4882a593Smuzhiyun
805*4882a593Smuzhiyun uint
bcmsdh_query_iofnum(void * sdh)806*4882a593Smuzhiyun bcmsdh_query_iofnum(void *sdh)
807*4882a593Smuzhiyun {
808*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
809*4882a593Smuzhiyun
810*4882a593Smuzhiyun if (!bcmsdh)
811*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
812*4882a593Smuzhiyun
813*4882a593Smuzhiyun return (sdioh_query_iofnum(bcmsdh->sdioh));
814*4882a593Smuzhiyun }
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun int
bcmsdh_reset(bcmsdh_info_t * sdh)817*4882a593Smuzhiyun bcmsdh_reset(bcmsdh_info_t *sdh)
818*4882a593Smuzhiyun {
819*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun return sdioh_sdio_reset(bcmsdh->sdioh);
822*4882a593Smuzhiyun }
823*4882a593Smuzhiyun
824*4882a593Smuzhiyun /* XXX For use by NDIS port, remove if not needed. */
bcmsdh_get_sdioh(bcmsdh_info_t * sdh)825*4882a593Smuzhiyun void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh)
826*4882a593Smuzhiyun {
827*4882a593Smuzhiyun ASSERT(sdh);
828*4882a593Smuzhiyun return sdh->sdioh;
829*4882a593Smuzhiyun }
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun /* Function to pass device-status bits to DHD. */
832*4882a593Smuzhiyun uint32
bcmsdh_get_dstatus(void * sdh)833*4882a593Smuzhiyun bcmsdh_get_dstatus(void *sdh)
834*4882a593Smuzhiyun {
835*4882a593Smuzhiyun #ifdef BCMSPI
836*4882a593Smuzhiyun bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
837*4882a593Smuzhiyun sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
838*4882a593Smuzhiyun return sdioh_get_dstatus(sd);
839*4882a593Smuzhiyun #else
840*4882a593Smuzhiyun return 0;
841*4882a593Smuzhiyun #endif /* BCMSPI */
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun uint32
bcmsdh_cur_sbwad(void * sdh)844*4882a593Smuzhiyun bcmsdh_cur_sbwad(void *sdh)
845*4882a593Smuzhiyun {
846*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun if (!bcmsdh)
849*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun return (bcmsdh->sbwad);
852*4882a593Smuzhiyun }
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun /* example usage: if force is TRUE, forces the bcmsdhsdio_set_sbaddr_window to
855*4882a593Smuzhiyun * calculate sbwad always instead of caching.
856*4882a593Smuzhiyun */
857*4882a593Smuzhiyun void
bcmsdh_force_sbwad_calc(void * sdh,bool force)858*4882a593Smuzhiyun bcmsdh_force_sbwad_calc(void *sdh, bool force)
859*4882a593Smuzhiyun {
860*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun if (!bcmsdh)
863*4882a593Smuzhiyun bcmsdh = l_bcmsdh;
864*4882a593Smuzhiyun bcmsdh->force_sbwad_calc = force;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun void
bcmsdh_chipinfo(void * sdh,uint32 chip,uint32 chiprev)868*4882a593Smuzhiyun bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev)
869*4882a593Smuzhiyun {
870*4882a593Smuzhiyun #ifdef BCMSPI
871*4882a593Smuzhiyun bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
872*4882a593Smuzhiyun sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
873*4882a593Smuzhiyun sdioh_chipinfo(sd, chip, chiprev);
874*4882a593Smuzhiyun #else
875*4882a593Smuzhiyun return;
876*4882a593Smuzhiyun #endif /* BCMSPI */
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun #ifdef BCMSPI
880*4882a593Smuzhiyun void
bcmsdh_dwordmode(void * sdh,bool set)881*4882a593Smuzhiyun bcmsdh_dwordmode(void *sdh, bool set)
882*4882a593Smuzhiyun {
883*4882a593Smuzhiyun bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
884*4882a593Smuzhiyun sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
885*4882a593Smuzhiyun sdioh_dwordmode(sd, set);
886*4882a593Smuzhiyun return;
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun #endif /* BCMSPI */
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun int
bcmsdh_sleep(void * sdh,bool enab)891*4882a593Smuzhiyun bcmsdh_sleep(void *sdh, bool enab)
892*4882a593Smuzhiyun {
893*4882a593Smuzhiyun #ifdef SDIOH_SLEEP_ENABLED
894*4882a593Smuzhiyun bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
895*4882a593Smuzhiyun sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
896*4882a593Smuzhiyun
897*4882a593Smuzhiyun return sdioh_sleep(sd, enab);
898*4882a593Smuzhiyun #else
899*4882a593Smuzhiyun return BCME_UNSUPPORTED;
900*4882a593Smuzhiyun #endif
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun int
bcmsdh_gpio_init(void * sdh)904*4882a593Smuzhiyun bcmsdh_gpio_init(void *sdh)
905*4882a593Smuzhiyun {
906*4882a593Smuzhiyun bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
907*4882a593Smuzhiyun sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun return sdioh_gpio_init(sd);
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun bool
bcmsdh_gpioin(void * sdh,uint32 gpio)913*4882a593Smuzhiyun bcmsdh_gpioin(void *sdh, uint32 gpio)
914*4882a593Smuzhiyun {
915*4882a593Smuzhiyun bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
916*4882a593Smuzhiyun sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun return sdioh_gpioin(sd, gpio);
919*4882a593Smuzhiyun }
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun int
bcmsdh_gpioouten(void * sdh,uint32 gpio)922*4882a593Smuzhiyun bcmsdh_gpioouten(void *sdh, uint32 gpio)
923*4882a593Smuzhiyun {
924*4882a593Smuzhiyun bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
925*4882a593Smuzhiyun sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun return sdioh_gpioouten(sd, gpio);
928*4882a593Smuzhiyun }
929*4882a593Smuzhiyun
930*4882a593Smuzhiyun int
bcmsdh_gpioout(void * sdh,uint32 gpio,bool enab)931*4882a593Smuzhiyun bcmsdh_gpioout(void *sdh, uint32 gpio, bool enab)
932*4882a593Smuzhiyun {
933*4882a593Smuzhiyun bcmsdh_info_t *p = (bcmsdh_info_t *)sdh;
934*4882a593Smuzhiyun sdioh_info_t *sd = (sdioh_info_t *)(p->sdioh);
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun return sdioh_gpioout(sd, gpio, enab);
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun uint
bcmsdh_set_mode(void * sdh,uint mode)940*4882a593Smuzhiyun bcmsdh_set_mode(void *sdh, uint mode)
941*4882a593Smuzhiyun {
942*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
943*4882a593Smuzhiyun return (sdioh_set_mode(bcmsdh->sdioh, mode));
944*4882a593Smuzhiyun }
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun #ifdef PKT_STATICS
947*4882a593Smuzhiyun uint32
bcmsdh_get_spend_time(void * sdh)948*4882a593Smuzhiyun bcmsdh_get_spend_time(void *sdh)
949*4882a593Smuzhiyun {
950*4882a593Smuzhiyun bcmsdh_info_t *bcmsdh = (bcmsdh_info_t *)sdh;
951*4882a593Smuzhiyun return (sdioh_get_spend_time(bcmsdh->sdioh));
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun #endif
954