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