Vj[,o
Vt$ /*
%O>_$
4q * Broadcom BCMSDH to SPI Protocol Conversion Layer
)N&95\u *
m .^WSy * Copyright (C) 1999-2010, Broadcom Corporation
.?r}3Ch *
{%X[Snv * Unless you and Broadcom execute a separate written software license
Oq95zo * agreement governing use of this software, this software is licensed to you
a!;K+wL
> * under the terms of the GNU General Public License version 2 (the "GPL"),
I&5cUj{GX- * available at
http://www.broadcom.com/licenses/GPLv2.php, with the
IZxr;\dq6
* following added to such license:
~JOC8dO *
$XFFNE`% * As a special exception, the copyright holders of this software give you
M+L0 X$}NZ * permission to link this software with independent modules, and to copy and
zBqNE` * distribute the resulting executable under terms of your choice, provided that
Z'c9xvy5 * you also meet, for each linked independent module, the terms and conditions of
?lIh&C8]X * the license of that module. An independent module is a module which is not
4o( Q+6m * derived from this software. The special exception does not apply to any
H(Ad"1~.# * modifications of the software.
=#vU$~a *
fyv S1_ * Notwithstanding the above, under no circumstances may you combine this
p1,.f&(f * software in any way with any other Broadcom software provided under a license
Oi~.z@@ * other than the GPL, without Broadcom's express prior written consent.
Qy) -gax:, *
0Y*Ag,S * $Id: bcmsdspi.c,v 1.14.4.2.4.4.6.5 2010/03/10 03:09:48 Exp $
}9L;|ul6 */
49 1 1 #M:Vwn
JX #include <typedefs.h>
!]#;' (vbI4&r #include <bcmdevs.h>
)'`@rq! #include <bcmendian.h>
MNKY J #include <bcmutils.h>
e]smnf #include <osl.h>
iMp_1EXe #include <siutils.h>
}/F9(m #include <sdio.h> /* SDIO Device and Protocol Specs */
}yM!o`90 #include <sdioh.h> /* SDIO Host Controller Specification */
+\MGlsMK@. #include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */
=|q@Q`DB #include <sdiovar.h> /* ioctl/iovars */
Oa7jLz'i c nV2}U/\ #include <pcicfg.h>
(APGz,^9# Y!_e,]GW E)(Rhvij #include <bcmsdspi.h>
k)S'@>n{u #include <bcmspi.h>
A,%NdM;t=5 ngH_p> #include <proto/sdspi.h>
-2y>X`1Y A)D1
#,0 #define SD_PAGE 4096
`qj24ehc fMRMQR=6B /* Globals */
\v([,tiW% 7 gT^ZL uint sd_msglevel = SDH_ERROR_VAL;
:Pi=" uint sd_hiok = FALSE; /* Use hi-speed mode if available? */
bH_zWk uint sd_sdmode = SDIOH_MODE_SPI; /* Use SD4 mode by default */
+rOd0? uint sd_f2_blocksize = 512; /* Default blocksize */
n7'X.=o7 ,+E"s3NW uint sd_divisor = 2; /* Default 33MHz/2 = 16MHz for dongle */
oF(|NS^ uint sd_power = 1; /* Default to SD Slot powered ON */
|&rxDf}W uint sd_clock = 1; /* Default to SD Clock turned ON */
6zW3!_tz uint sd_crc = 0; /* Default to SPI CRC Check turned OFF */
R"[U<^ uint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */
u/X1v-2 hN.{H:skL) uint sd_toctl = 7;
R8fB
8 ) O.OSLezTQ /* Prototypes */
66Xo3o static bool sdspi_start_power(sdioh_info_t *sd);
0uf)6(f static int sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode);
xX{gm'3UYa static int sdspi_card_enablefuncs(sdioh_info_t *sd);
^es/xt static void sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count);
)zq sn static int sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg,
FFID<Lf/2 uint32 *data, uint32 datalen);
C2W&*W* static int sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
hdx"/.s int regsize, uint32 *data);
C(5B/W6 static int sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr,
r7n-Xe int regsize, uint32 data);
vrvOPLiQ static int sdspi_driver_init(sdioh_info_t *sd);
>^%TY^7n static bool sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset);
[V.#w|n static int sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
l*<RKY8 uint32 addr, int nbytes, uint32 *data);
;TG<$4N static int sdspi_abort(sdioh_info_t *sd, uint func);
0^&-j.9 OG}m+K&< static int set_client_block_size(sdioh_info_t *sd, int func, int blocksize);
WY" `wM `'M}.q,k~ static uint8 sdspi_crc7(unsigned char* p, uint32 len);
t5jZ8&M5] static uint16 sdspi_crc16(unsigned char* p, uint32 len);
e khx?rz static int sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc);
e2$k
%c~ \v[?4[ /*
(uskVK>L * Public entry points & extern's
p1(<F_Kta */
e-e*% extern sdioh_info_t *
eU.HS78 sdioh_attach(osl_t *osh, void *bar0, uint irq)
}o MY {
P|4qbm4%O, sdioh_info_t *sd;
w-9fskd6e 8.4+4Vxh sd_trace(("%s\n", __FUNCTION__));
[DO UIR9 if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
&Ew{ {t;" sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
0*}%v:uN9 return NULL;
!L_\6;aP,x }
%vFoTu)2 bzero((char *)sd, sizeof(sdioh_info_t));
.l(t\BfE~ sd->osh = osh;
ZF6?N?t}h8 o$+"{3svw? if (spi_osinit(sd) != 0) {
WaYT7 : sd_err(("%s: spi_osinit() failed\n", __FUNCTION__));
XhEd9># MFREE(sd->osh, sd, sizeof(sdioh_info_t));
j^'op|l return NULL;
Pf?y!dK< }
vTY+J$N__ j=~c(
B sd->bar0 = (uintptr)bar0;
_MC\\u/C/ sd->irq = irq;
s j{i sd->intr_handler = NULL;
?go+oS^ sd->intr_handler_arg = NULL;
WN%KATA sd->intr_handler_valid = FALSE;
[exIK bI?YNt, /* Set defaults */
J}UG{RttI sd->sd_blockmode = FALSE;
bhWH sd->use_client_ints = TRUE;
`$odxo+ sd->sd_use_dma = FALSE; /* DMA Not supported */
{@8TGHKv %d/Pc4gfc /* Haven't figured out how to make bytemode work with dma */
4#^?-6 if (!sd->sd_blockmode)
1hn4YcHb sd->sd_use_dma = 0;
s9'lw' u!VAAX if (!spi_hw_attach(sd)) {
kxp, ZP sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__));
:L!O/Bd8V spi_osfree(sd);
#- hYjE5 MFREE(sd->osh, sd, sizeof(sdioh_info_t));
xVn"xk return NULL;
-$js5Gx1 }
$<(FZb= U,w J8 if (sdspi_driver_init(sd) != SUCCESS) {
v2uyn if (sdspi_driver_init(sd) != SUCCESS) {
^ A`@g4! sd_err(("%s:sdspi_driver_init() failed()\n", __FUNCTION__));
DlWnz- spi_hw_detach(sd);
tuF
hPqe { spi_osfree(sd);
vS{zLXg MFREE(sd->osh, sd, sizeof(sdioh_info_t));
[spJ%AhV return (NULL);
~\^h;A'3 }
xF4>D!T%8 }
:"4Pr/}rT |_^A$Hv if (spi_register_irq(sd, irq) != SUCCESS) {
6eNo}Tos9 sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq));
;Xw'WMb*= spi_hw_detach(sd);
Qwm#6{5 spi_osfree(sd);
SXW8p>1Jw MFREE(sd->osh, sd, sizeof(sdioh_info_t));
x!08FL) return (NULL);
VdZmrq;?/ }
1k
*gbXb l12_&o"C~ sd_trace(("%s: Done\n", __FUNCTION__));
[?vn>
return sd;
Gx]J6Z8 }
cJnAwIs_e` &Q85B q extern SDIOH_API_RC
B4 cm_YGE sdioh_detach(osl_t *osh, sdioh_info_t *sd)
QKAo}1Pq {
61W
ms@D% sd_trace(("%s\n", __FUNCTION__));
T7!"gJ vIi#M0@N if (sd) {
Gqz<;y if (sd->card_init_done)
;;2Yfn'`9 sdspi_reset(sd, 1, 1);
.9< i $H9+>Z0( sd_info(("%s: detaching from hardware\n", __FUNCTION__));
KfO$bmwmx spi_free_irq(sd->irq, sd);
%$)[qa3 spi_hw_detach(sd);
d3$&I==;: spi_osfree(sd);
/NH9$u.g MFREE(sd->osh, sd, sizeof(sdioh_info_t));
/"Bm1 }
sMq*X^z
)? }T}9AQ}| return SDIOH_API_RC_SUCCESS;
/=5YHq> }
e*7nq~ B5 yH'vhtop /* Configure callback to client when we recieve client interrupt */
nnV(MB4z1 extern SDIOH_API_RC
|-W7n'n sdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
L@"1d.k_ {
ZZ<uiN$ sd_trace(("%s: Entering\n", __FUNCTION__));
1@j0kTJ~m :3z`+5Y* sd->intr_handler = fn;
1kG{z;9 sd->intr_handler_arg = argh;
"pDwN$c sd->intr_handler_valid = TRUE;
kIb)I(n #+vIq? return SDIOH_API_RC_SUCCESS;
r+}5;fQJ }
dPdodjSu,! C6=P(%y extern SDIOH_API_RC
I.f)rMl+h
sdioh_interrupt_deregister(sdioh_info_t *sd)
1^*M*>&d< {
;\F3~rl sd_trace(("%s: Entering\n", __FUNCTION__));
p97}HT} hP=^JH sd->intr_handler_valid = FALSE;
:|s!_G < sd->intr_handler = NULL;
Ag3[Nu1 sd->intr_handler_arg = NULL;
D;pfogK @ ^^u{W|'CaH return SDIOH_API_RC_SUCCESS;
pZS0;T]W, }
~w&P]L\dB R. sRH/6 extern SDIOH_API_RC
p7UdZOi2 sdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
u~|D;e {
@WV}VKm sd_trace(("%s: Entering\n", __FUNCTION__));
gEVN;G'B<= Hh_Yd) *onoff = sd->client_intr_enabled;
wj-=#gyAoo qUH02"z@9 return SDIOH_API_RC_SUCCESS;
0w0\TWz* }
xz-z"
8d #1INOR9 #if defined(DHD_DEBUG)
r#ISIgJXG extern bool
Zc_%hQf2A sdioh_interrupt_pending(sdioh_info_t *sd)
5'JONw'\ {
7oPLO(0L return 0;
BO#XQ, }
.AIlv^:|U #endif
y4%u<