论坛风格切换切换到宽版
发帖 回复
返回列表  提醒:不能用迅雷等P2P下载,否则下载失败标(二级)的板块,需二级才能下载,没二级不要购买,下载不了
  • 5714阅读
  • 1回复

RK3288  WIFI BCM驱动 [复制链接]

上一主题 下一主题
离线mark83136
 

性别:
帅哥
发帖
1210
金币
360
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看楼主 倒序阅读 使用道具 0楼 发表于: 2015-07-07
V j[,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 Oq 95zo  
* 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%  
7gT^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 */ 66Xo3 o  
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<L f/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); ekhx?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!d K<  
    } 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%KA TA  
    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; -$js5 Gx1  
    } $<(FZb=  
U ,wJ8  
    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`  
&Q85Bq  
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  
#+v Iq?  
    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< /  
pvCf4pf~  
uint Md~% e'  
sdioh_query_iofnum(sdioh_info_t *sd) pzX684  
{ hJr cy!P<a  
    return sd->num_funcs; F/MzrK\':m  
} g_kR5Wxpt  
::k>V\;  
/* IOVar table */ \7W4)>At-  
enum { (=hXt=hZ  
    IOV_MSGLEVEL = 1, ^hG Y,\K9  
    IOV_BLOCKMODE, &d"c6il[  
    IOV_BLOCKSIZE, _|VWf8?\  
    IOV_DMA, IO,ddVO  
    IOV_USEINTS, svt%UE|_:$  
    IOV_NUMINTS, s:_M+_7_  
    IOV_NUMLOCALINTS, K4]42#  
    IOV_HOSTREG, LaI(  
    IOV_DEVREG, qH3<,s*  
    IOV_DIVISOR, H3$~S '  
    IOV_SDMODE, ]2^tV.^S^  
    IOV_HISPEED, OQ[E-%v1 R  
    IOV_HCIREGS, t<_Jx<{2  
    IOV_POWER, wv.FL$f[@  
    IOV_CLOCK, x$Gu)S  
    IOV_CRC 9}~WwmC|x  
}; c,cc avv{I  
N|Cx";,|FZ  
const bcm_iovar_t sdioh_iovars[] = { m!{}Y]FZn  
    {"sd_msglevel",    IOV_MSGLEVEL,     0,    IOVT_UINT32,    0 }, 64qm  
    {"sd_blockmode", IOV_BLOCKMODE,    0,    IOVT_BOOL,    0 }, <ej Wl%4  
    {"sd_blocksize", IOV_BLOCKSIZE, 0,    IOVT_UINT32,    0 }, /* ((fn << 16) | size) */ l[KFK%?  
    {"sd_dma",    IOV_DMA,    0,    IOVT_BOOL,    0 }, 4>q^W$  
    {"sd_ints",    IOV_USEINTS,    0,    IOVT_BOOL,    0 }, KmuE#Ia  
    {"sd_numints",    IOV_NUMINTS,    0,    IOVT_UINT32,    0 }, 8vzjPWu  
    {"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32,    0 }, 7@[3]c<=  
    {"sd_hostreg",    IOV_HOSTREG,    0,    IOVT_BUFFER,    sizeof(sdreg_t) }, kOv2E]  
    {"sd_devreg",    IOV_DEVREG,    0,    IOVT_BUFFER,    sizeof(sdreg_t)    }, R|7yhsJq,  
    {"sd_divisor",    IOV_DIVISOR,    0,    IOVT_UINT32,    0 }, kbqG)  
    {"sd_power",    IOV_POWER,    0,    IOVT_UINT32,    0 }, (C< ~:Y?%  
    {"sd_clock",    IOV_CLOCK,    0,    IOVT_UINT32,    0 }, .C]V==z`[4  
    {"sd_crc",    IOV_CRC,    0,    IOVT_UINT32,    0 }, jy=dB-&  
    {"sd_mode",    IOV_SDMODE,    0,    IOVT_UINT32,    100}, JNQiCK,)}M  
    {"sd_highspeed",    IOV_HISPEED,    0,    IOVT_UINT32,    0}, w]Q0}Z  
    {NULL, 0, 0, 0, 0 } \ (y6o}aW  
}; h, |49~^@"  
6pkZ8Vp:  
int U) tqo_  
sdioh_iovar_op(sdioh_info_t *si, const char *name, zdDn. vG  
               void *params, int plen, void *arg, int len, bool set) E)eRi"a46  
{ ;DMv?-H  
    const bcm_iovar_t *vi = NULL; )@-v6;7b0  
    int bcmerror = 0; @"M%ZnFu  
    int val_size; d/Q}I[J.u  
    int32 int_val = 0; ]+1?T)<!  
    bool bool_val; :D-xa!7  
    uint32 actionid; ]LFY2w<  
^i3~i?\,P  
    ASSERT(name); # 2As-9  
    ASSERT(len >= 0); kcy?;b;z  
/*5t@_0fe  
    /* Get must have return space; Set does not take qualifiers */ g~ tG  
    ASSERT(set || (arg && len)); GA19=gow  
    ASSERT(!set || (!params && !plen)); -4P2 2  
E?c)WA2iH  
    sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name)); Vp =  
OrX x0Hn  
    if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) { VGbuEC[Y  
        bcmerror = BCME_UNSUPPORTED; 7aH E:Dnwp  
        goto exit; TH_Vw,)  
    } j M%qv  
pfj%AP:  
    if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0) v#iKa+tx  
        goto exit; L8<Yk`jx  
F...>%N$  
    /* Set up params so get and set can share the convenience variables */ Dp:u!tdbeg  
    if (params == NULL) { /0(2PVf y  
        params = arg;  3nfw:.  
        plen = len; b6Jv|1w'  
    } 4:$?u}9[:[  
5t6!K?}  
    if (vi->type == IOVT_VOID) #J AU5d  
        val_size = 0; Ndj9B|s_  
    else if (vi->type == IOVT_BUFFER) ],ow@}  
        val_size = len; QcyYTg4i  
    else S>~QuCMY  
        val_size = sizeof(int); ]?P9M<0PM  
bP;cDQ(g  
    if (plen >= (int)sizeof(int_val)) ZN)a}\]  
        bcopy(params, &int_val, sizeof(int_val)); *uYnu|UQH  
Vq`i.>%5  
    bool_val = (int_val != 0) ? TRUE : FALSE; Hu$]V*rAG  
n7~!klF-  
    actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); }8E//$J  
    switch (actionid) { 27b7~!  
    case IOV_GVAL(IOV_MSGLEVEL): Wc4K?3 ZM  
        int_val = (int32)sd_msglevel; 5MJ`B: He+  
        bcopy(&int_val, arg, val_size); !ndc <],  
        break; jd;=5(2  
-a`EL]NX  
    case IOV_SVAL(IOV_MSGLEVEL): A8JEig 3Ix  
        sd_msglevel = int_val; &&e{9{R  
        break; ]JQk,<l5E  
7&G[mOx0  
    case IOV_GVAL(IOV_BLOCKMODE): {Y{*(5YV  
        int_val = (int32)si->sd_blockmode; HjTK/x'_'L  
        bcopy(&int_val, arg, val_size); \m!swYy  
        break; mq$mB1$3u  
D$k40Mz  
    case IOV_SVAL(IOV_BLOCKMODE): zGFo -C  
        si->sd_blockmode = (bool)int_val; v'`9^3(-  
        /* Haven't figured out how to make non-block mode with DMA */  /kGRN @  
        if (!si->sd_blockmode) A3%s5`vNvH  
            si->sd_use_dma = 0; 9WQC\/w  
        break; >j1\]uo  
|xaJv:96%  
    case IOV_GVAL(IOV_BLOCKSIZE): fRo_rj _  
        if ((uint32)int_val > si->num_funcs) { X&._<2  
            bcmerror = BCME_BADARG; ['pk/h  
            break; ocwRU0+j  
        } pfW0)V1t  
        int_val = (int32)si->client_block_size[int_val]; 620y[iiK$  
        bcopy(&int_val, arg, val_size); )%8oE3O#  
        break; F,#)8>O  
11}fPWK  
    case IOV_SVAL(IOV_BLOCKSIZE): M-KjRl  
    { =LJc8@<:f  
        uint func = ((uint32)int_val >> 16); T{M~*5$  
        uint blksize = (uint16)int_val; 6L~@jg~0A[  
        uint maxsize; v%3mhk#  
)5P*O5kQ -  
        if (func > si->num_funcs) { uAT01ZEm  
            bcmerror = BCME_BADARG; 'UO,DFq[Fl  
            break; iZ+\vO?|  
        } 1E!0N`E  
XJnDx 09h  
        switch (func) { :bMCmY  
        case 0: maxsize = 32; break; #=R)s0j"  
        case 1: maxsize = BLOCK_SIZE_4318; break; }*l V  
        case 2: maxsize = BLOCK_SIZE_4328; break; =tl[?6  
        default: maxsize = 0; %7BVJJp2  
        } \s Fdp!M}2  
        if (blksize > maxsize) { Y?hC/ 6$7  
            bcmerror = BCME_BADARG; D1bS=> ;,"  
            break; ?}%Gr,tj2  
        } [w l:"rm  
        if (!blksize) { Lys4l$J]  
            blksize = maxsize; pmXx2T#=  
        } ay#cW.,  
$DC*&hqpt  
        /* Now set it */ 1QM*oj:  
        spi_lock(si); YMP:T?vMVh  
        bcmerror = set_client_block_size(si, func, blksize); Oy[1_qfP  
        spi_unlock(si); 0B)l"$W[)/  
        break; f&t]O$  
    } O!='U!X@P  
WMBntB   
    case IOV_GVAL(IOV_DMA): \/4ipU.  
        int_val = (int32)si->sd_use_dma; Fa^5.p  
        bcopy(&int_val, arg, val_size); wJh|$Vn  
        break; O z%K*  
u8 14ZN}  
    case IOV_SVAL(IOV_DMA): 94%gg0azp  
        si->sd_use_dma = (bool)int_val; o7VNw8Bp  
        break; a8aEZ724  
=nOV!!  
    case IOV_GVAL(IOV_USEINTS): `(1em%}  
        int_val = (int32)si->use_client_ints; ~c[} %Ir>  
        bcopy(&int_val, arg, val_size); PEZElB ;  
        break; I.tJ4  
4vTO  #F  
    case IOV_SVAL(IOV_USEINTS): joDnjz=  
        break; 2;%DE<Z  
Z$0r+phQk=  
    case IOV_GVAL(IOV_DIVISOR): rq9{m(  
        int_val = (uint32)sd_divisor; ?GU/Rf!H#  
        bcopy(&int_val, arg, val_size); i0,{*LD%^  
        break; I"@X~Y7}  
bv0B  
    case IOV_SVAL(IOV_DIVISOR): m_~ p G  
        sd_divisor = int_val; l.1)%q&@^  
        if (!spi_start_clock(si, (uint16)sd_divisor)) { &'Qz  
            sd_err(("set clock failed!\n")); y4) M,+O5  
            bcmerror = BCME_ERROR; MQE=8\  
        } JU:!lyd  
        break; zB\g'F/  
KgVit+4u/  
    case IOV_GVAL(IOV_POWER): $-"AMZ899  
        int_val = (uint32)sd_power; (.P;VH9R\  
        bcopy(&int_val, arg, val_size); 7CUu:6%  
        break; B Hn`e~  
VP\HPSp  
    case IOV_SVAL(IOV_POWER): }p}i _'%  
        sd_power = int_val; xPb;_~  
        break; >h<eEv/  
Rp A76ug  
    case IOV_GVAL(IOV_CLOCK): jd l1Q<Z  
        int_val = (uint32)sd_clock; l7aGo1TcIh  
        bcopy(&int_val, arg, val_size); B+);y  
        break; n0U^gsD4J  
Y_>z"T  
    case IOV_SVAL(IOV_CLOCK): xj{X#[q):  
        sd_clock = int_val; dJ?VN!B0  
        break; l}335;(  
D[ 7K2G+  
    case IOV_GVAL(IOV_CRC): t2p/NIn  
        int_val = (uint32)sd_crc; Q6,rY(b6  
        bcopy(&int_val, arg, val_size); qh0)~JL4   
        break; Yc=y  Vh  
p1v:X?  
    case IOV_SVAL(IOV_CRC): !W^2?pqN  
        /* Apply new setting, but don't change sd_crc until yr&oJYM  
         * after the CRC-mode is selected in the device.  This b-]E -$Uz  
         * is required because the software must generate a yZK1bnYG|I  
         * correct CRC for the CMD59 in order to be able to 2P$lXGjh  
         * turn OFF the CRC. tA#X@HIE  
         */ fj0+a0h  
        sdspi_crc_onoff(si, int_val ? 1 : 0); qt/syF&s  
        sd_crc = int_val; 'e3y|  
        break; D\(,:_ge  
90sMS]a  
    case IOV_GVAL(IOV_SDMODE): Mn>dI@/gM  
        int_val = (uint32)sd_sdmode; T_Z@uZom.  
        bcopy(&int_val, arg, val_size); <tf4j3lwH  
        break; eno*JK  
Lj*F KP\{  
    case IOV_SVAL(IOV_SDMODE): KyXgw  
        sd_sdmode = int_val; kSU5  }  
        break; GOJi/R.{  
}S*6+4  
    case IOV_GVAL(IOV_HISPEED):  3mWo`l  
        int_val = (uint32)sd_hiok; :1_hQeq  
        bcopy(&int_val, arg, val_size); qqw6p j  
        break; Q)#<T]~=  
*Q!b%DIa$  
    case IOV_SVAL(IOV_HISPEED): (n"  )  
        sd_hiok = int_val; t vk^L3=<  
8S]Mf*~S'  
        if (!sdspi_set_highspeed_mode(si, (bool)sd_hiok)) { Da-F(^E  
            sd_err(("Failed changing highspeed mode to %d.\n", sd_hiok)); QIi*'21a+  
            bcmerror = BCME_ERROR; ~pzaX8!  
            return ERROR; :U)e 8  
        } pal))e! B  
        break; ~e{2Y%  
Y D.3FTNGC  
    case IOV_GVAL(IOV_NUMINTS): ujz %0Mq;  
        int_val = (int32)si->intrcount; 4c2P%X( C  
        bcopy(&int_val, arg, val_size); rA` zuYo  
        break; V]q{N-Iq  
=v:_N.Fh-c  
    case IOV_GVAL(IOV_NUMLOCALINTS): rFx2 S  
        int_val = (int32)si->local_intrcount; {)b`fq  
        bcopy(&int_val, arg, val_size); 6\5U%~78  
        break; <ya'L&  
.Z_U]_(  
    case IOV_GVAL(IOV_HOSTREG): iS=T/<|?  
    { C{!Czz.N  
        break; GGJ_,S*  
    } v/m`rc]e  
7]nPWz1%*  
    case IOV_SVAL(IOV_HOSTREG): M<ad>M  
    { 'Fonn  
        sd_err(("IOV_HOSTREG unsupported\n")); {_q2kk  
        break; T{)!>)  
    } ` 4k;`a  
a@8knJ|  
    case IOV_GVAL(IOV_DEVREG): 1Rczf(,aT  
    { W/\7m\ B  
        sdreg_t *sd_ptr = (sdreg_t *)params; Qb(CH  
        uint8 data; Fn[~5/  
qh2.N}lW  
        if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) { il#rdJ1@t  
            bcmerror = BCME_SDIO_ERROR; [")0{LSA=  
            break; I?fE=2}9  
        } Ce0I8B2y  
2sU"p5 j  
        int_val = (int)data; ko5\*!|:lj  
        bcopy(&int_val, arg, sizeof(int_val)); #e|eWi>  
        break; vaQ,l6z .h  
    } Q1jyetk~I  
5vpf;  
    case IOV_SVAL(IOV_DEVREG): v,M2|x\r}  
    { }2\"(_  
        sdreg_t *sd_ptr = (sdreg_t *)params; Y4{`?UM&h  
        uint8 data = (uint8)sd_ptr->value; JfVay I=  
[ =9R5.)c  
        if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) { :EO}uP2  
            bcmerror = BCME_SDIO_ERROR; |SxEJ  
            break; }!d}febk_  
        } ALw uw^+  
        break; \O0fo^+U,,  
    } mi-\PD>X  
4/h2_  
5sE^MS1  
    default: Kz<xuulr  
        bcmerror = BCME_UNSUPPORTED; )a}5\V  
        break; 9.@(&  
    } gRFC n6Q  
exit: 1z`,*eD7  
(8*lLZ  
    return bcmerror; ^s?wnEo;j  
} JxvwquI  
uVk8KMYU  
extern SDIOH_API_RC 869`jA &7"  
sdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) srSTQ\l4  
{ m!2Dk#t  
    SDIOH_API_RC status; lvN{R{7 >  
    /* No lock needed since sdioh_request_byte does locking */ y H'\<bT  
    status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data); |`okIqp  
    return status; Wp]EaYt2D  
} C=]3NB>Jc  
OP&[5X+Y  
extern SDIOH_API_RC ,qfa,O  
sdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data) [D,:=p`  
{ \%C[l  
    /* No lock needed since sdioh_request_byte does locking */ .( J /*H  
    SDIOH_API_RC status; j~8+,:  
    status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data); NV gLq@F  
    return status; 9=o b:  
} esHiWHAC  
H|Nw)*.  
extern SDIOH_API_RC C:K\-P9  
sdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length) }ot _k-  
{ <2 Q@^  
    uint32 count; Ocb2XEF  
    int offset; G<z)Ydh_  
    uint32 foo; 4W?<hv+k7*  
    uint8 *cis = cisd;  n=&c5!  
S3_4i;K\  
    sd_trace(("%s: Func = %d\n", __FUNCTION__, func)); gfYB|VyWo  
n,F00Y R  
    if (!sd->func_cis_ptr[func]) { K$.zO4  
        bzero(cis, length); A1q^E(}O  
        return SDIOH_API_RC_FAIL; A!D:Kc3  
    } QdTe!f|  
caP  
    spi_lock(sd); *p3P\ H^5  
    *cis = 0; 6ZR0_v;TD  
    for (count = 0; count < length; count++) { [z~Nw#  
        offset =  sd->func_cis_ptr[func] + count; r83~o/T@  
        if (sdspi_card_regread (sd, 0, offset, 1, &foo) < 0) { [!le 9aNg  
            sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__)); [FL I+;gY  
            spi_unlock(sd); <C77_t  
            return SDIOH_API_RC_FAIL; MT`gr  
        } Ic}ofBK  
        *cis = (uint8)(foo & 0xff); b8>9mKs  
        cis++; :/NN =3e  
    } bw\=F_>L  
    spi_unlock(sd); w#T,g9  
    return SDIOH_API_RC_SUCCESS; X2[cR;;'  
} :#}`uR,D/  
}#8uXA  
extern SDIOH_API_RC F4Uk+|]Bu  
sdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte) Elp!,(+&6  
{ 6\;1<Sw*  
    int status; \zU5G#LQ  
    uint32 cmd_arg; 6W=:`14  
    uint32 rsp5; Bs?F*,zDJ  
md"%S-a_dT  
    spi_lock(sd); [QbXj0en$  
)^H9C"7T  
    cmd_arg = 0; a1SOC=.M;  
    cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func); MPbPq3an  
    cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr); !h!9SE  
    cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, rw == SDIOH_READ ? 0 : 1); YZRB4T9  
    cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0); qJU)d  
    cmd_arg = SFIELD(cmd_arg, CMD52_DATA, rw == SDIOH_READ ? 0 : *byte); GiXde}bm  
ap^=CEf   
    sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x\n", __FUNCTION__, rw, func, regaddr)); 3 \r@f_p  
Zk UuniO  
    if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, Qiw4'xQm  
                                  SDIOH_CMD_52, cmd_arg, NULL, 0)) != SUCCESS) { |nN/x<v  
        spi_unlock(sd); ,,@`l\Pgd  
        return status; i@5%d!J  
    } ':D&c  
-5 /v`  
    sdspi_cmd_getrsp(sd, &rsp5, 1); i8_x1=A  
    if (rsp5 != 0x00) { VtiqAh}4  
        sd_err(("%s: rsp5 flags is 0x%x func=%d\n", MuV0;K \  
                __FUNCTION__, rsp5, func)); V2{#<d-T!  
        /* ASSERT(0); */ $af}+:'  
        spi_unlock(sd); DXW?;|8)O  
        return SDIOH_API_RC_FAIL; > x ghq  
    } WWW#s gM%  
,'CWt]OS'  
    if (rw == SDIOH_READ) F9P0cGDs  
        *byte = sd->card_rsp_data >> 24; nFnF_  
DhNo +"!z  
    spi_unlock(sd); !u4Z0!Ll  
    return SDIOH_API_RC_SUCCESS; 07Q[L'}y@  
} _SC  
A}bHfn|  
extern SDIOH_API_RC |4. o$*0Y  
sdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr, <nTmZ-;  
                   uint32 *word, uint nbytes) c4>sE[]  
{ *rcuhw"^b#  
    int status; Of7) A  
%}MA5 t]o  
    spi_lock(sd); ]~00=nXFM/  
xSDE6]  
    if (rw == SDIOH_READ) Eqmv`Z [_  
        status = sdspi_card_regread(sd, func, addr, nbytes, word); {IPn\Bka  
    else O%K?l}e  
        status = sdspi_card_regwrite(sd, func, addr, nbytes, *word); %Mng8r  
R #3Q$   
    spi_unlock(sd); G:c8`*5Q  
    return (status == SUCCESS ?  SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); M&djw`B  
} &O6;nJEI  
)yNw2+ ~5  
extern SDIOH_API_RC I0w@S7  
sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func, KtU GI.X  
                     uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt) AIl$qPKj&  
{ 5<O61Lgx  
    int len; ))IgB).3M  
    int buflen = (int)buflen_u; >[XOMKgQ](  
    bool fifo = (fix_inc == SDIOH_DATA_FIX); B}q  
 9VUm=Z#`  
    spi_lock(sd); 5&HT$"H :  
I,<>%Z|'  
    ASSERT(reg_width == 4); Jn<e"  
    ASSERT(buflen_u < (1 << 30)); #OD@q;  
    ASSERT(sd->client_block_size[func]); zh^jWu  
iVKbGgA  
    sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n", fs rg2:kQ  
             __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W', fmnRUN=  
             buflen_u, sd->r_cnt, sd->t_cnt, pkt)); p&OJa$N$[  
i_0 ,BV C  
    /* Break buffer down into blocksize chunks: sm2p$3v  
     * Bytemode: 1 block at a time. /m Q2;*|  
     */ X40la_[.  
    while (buflen > 0) { V5yxQb  
        if (sd->sd_blockmode) { Q"OV>klk  
            /* Max xfer is Page size */ ayH%  qp  
            len = MIN(SD_PAGE, buflen); mo|PrLV  
of+phMev  
            /* Round down to a block boundry */ })zB".  
            if (buflen > sd->client_block_size[func]) `rz`3:ZH  
                len = (len/sd->client_block_size[func]) * { OxAY_  
                        sd->client_block_size[func]; ^<>Jw%H  
        } else { !bZhj3.  
            /* Byte mode: One block at a time */ vLnq%@x  
            len = MIN(sd->client_block_size[func], buflen); .*EOVo9S  
        } {+ C%D'  
vbRrk($`  
        if (sdspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) { SRt$4EL21  
            spi_unlock(sd); @ate49W  
            return SDIOH_API_RC_FAIL; 2vqmsl ?  
        } [+;FV!M6  
        buffer += len; FXOT+9bg  
        buflen -= len; CJMaltPp&  
        if (!fifo) {?EEIfg  
            addr += len; Y!Uu173  
    } Gd30Be2gd  
    spi_unlock(sd); ><;l:RGK|  
    return SDIOH_API_RC_SUCCESS; A*7Io4e!  
} di3 B=A>3  
|D;_:x9  
static int 1z})mfsh  
sdspi_abort(sdioh_info_t *sd, uint func) O+G~Qp0b>  
{ s{(ehP.Dd  
    uint8 spi_databuf[] = { 0x74, 0x80, 0x00, 0x0C, 0xFF, 0x95, 0xFF, 0xFF, n!0${QVnS  
                            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; ~vW)1XnK  
    uint8 spi_rspbuf[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, nB cp7e  
                           0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; n0rerI[R  
    int err = 0; G 2%  
Tjnt(5g  
    sd_err(("Sending SPI Abort to F%d\n", func)); T&9`?QD  
    spi_databuf[4] = func & 0x7; YPF&U4CN  
    /* write to function 0, addr 6 (IOABORT) func # in 3 LSBs. */ hl AR[]  
    spi_sendrecv(sd, spi_databuf, spi_rspbuf, sizeof(spi_databuf)); E$]a?uA:  
`pP9z;/Xq  
    return err; -W|*fKN`3  
} PHQ{-b?4t  
Xtci0eS#V  
extern int {E!$ xY8  
sdioh_abort(sdioh_info_t *sd, uint fnum) xGKfej9  
{ >Hdjsu5{N  
    int ret; 9 '2=  
tO?21?AD D  
    spi_lock(sd); a`7%A H)  
    ret = sdspi_abort(sd, fnum); 25xcD1*  
    spi_unlock(sd); )-0[ra]  
r#LnDseW  
    return ret; S 3R|8?|  
} B }6Kd  
f"Ost;7zg  
int |WB"=PE  
sdioh_start(sdioh_info_t *sd, int stage) C= >B_EO  
{ J1.qhy>  
    return SUCCESS; ?V#Gx>\  
} ( FM4 ^#6  
riID,aut  
int )yHJ[  
sdioh_stop(sdioh_info_t *sd) ?sV[MsOsC  
{ S*4f%!  
    return SUCCESS; ;!'qtw"CB  
} :FnOS<_B  
g<f P:/  
R"NGJu9  
/* ft{W/ * +_  
* Private/Static work routines !d\t:0;  
*/ Q`N18I3  
static bool Was'A+GZ  
sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset) Zotz?j VVr  
{ /v5qyR7an  
    if (!sd) [1NaH  
        return TRUE; ; vMn/  
W3^.5I  
    spi_lock(sd); pP3U,n   
    /* Reset client card */ KL "Y!PN:  
    if (client_reset && (sd->adapter_slot != -1)) { :#WEx_]  
        if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOABORT, 1, 0x8) != SUCCESS) .%_)*NUZ  
            sd_err(("%s: Cannot write to card reg 0x%x\n", m)r]F#@/  
                    __FUNCTION__, SDIOD_CCCR_IOABORT)); ]5N zK=2{  
        else +i+tp8T+7  
            sd->card_rca = 0; PCtkjd  
    } CQ<8P86gt  
^b=XV&{q  
    /* The host reset is a NOP in the sd-spi case. */ d^tVD`Fm  
    if (host_reset) { N3Z iGD  
        sd->sd_mode = SDIOH_MODE_SPI; q'.;W@m  
    } .vK.XFZ8R  
    spi_unlock(sd); Rxx>{+f4M  
    return TRUE; )Lb72;!?  
} uMHRUi  
L7m`HVCt&  
static int @YCv  
sdspi_host_init(sdioh_info_t *sd) i(0hvV>'  
{ 0vDg8i\  
    sdspi_reset(sd, 1, 0); @m?{80;uQ  
x:qr\Rz  
    /* Default power on mode is SD1 */ %bXsGPB  
    sd->sd_mode = SDIOH_MODE_SPI; +5-]iKh  
    sd->polled_mode = TRUE; b{BaQ>.(`  
    sd->host_init_done = TRUE; /tP7uVL R  
    sd->card_init_done = FALSE; Y[ ?`\c|  
    sd->adapter_slot = 1; ~Zmi(Ra  
Mm.Ql  
    return (SUCCESS); Q&gPa]z]}  
} p'80d:  
%[XY67A3I  
#define CMD0_RETRIES 3 z>|)ieL  
#define CMD5_RETRIES 10 -?5$ PH  
OTE<x"=h  
static int 9k}<Fz"^.  
get_ocr(sdioh_info_t *sd, uint32 *cmd_arg, uint32 *cmd_rsp) \e|U9;Mf  
{ ;b1wk^,Hw~  
    uint32 rsp5; 7 W{~f?Sh  
    int retries, status; a1|c2kT  
8)Zk24:])_  
    /* First issue a CMD0 to get the card into SPI mode. */ odpUM@OAW  
    for (retries = 0; retries <= CMD0_RETRIES; retries++) { 6b<+8w  
        if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, b_l3+'#ofM  
                                      SDIOH_CMD_0, *cmd_arg, NULL, 0)) != SUCCESS) { ]H+{eJB7O  
            sd_err(("%s: No response to CMD0\n", __FUNCTION__)); xg} ug[  
            continue; ]26mB  
        } (f~gEKcB2u  
GmbIFOT~  
        sdspi_cmd_getrsp(sd, &rsp5, 1); 5%P[^}  
TP{Gt.e  
        if (GFIELD(rsp5, SPI_RSP_ILL_CMD)) { -w~(3(  
            printf("%s: Card already initialized (continuing)\n", __FUNCTION__); H_Os4}  
            break; KmL$M  
        } # k9 <  
h@@d{{IqT  
        if (GFIELD(rsp5, SPI_RSP_IDLE)) { 5B{k\H;  
            printf("%s: Card in SPI mode\n", __FUNCTION__); q@kOTkHv)  
            break; W' ep6O  
        } 13a(FG  
    } VgMP^&/gZ  
> :Ze4}(  
    if (retries > CMD0_RETRIES) { l E^*t`+  
        sd_err(("%s: Too many retries for CMD0\n", __FUNCTION__)); 8*s7m   
        return ERROR; Qn.[{rw  
    } e:OyjG5_  
W2eAhz&  
    /* Get the Card's Operation Condition. */ ]'k[u  
    /* Occasionally the board takes a while to become ready. */ C(o.Cy6  
    for (retries = 0; retries <= CMD5_RETRIES; retries++) {  rN"Xz  
        if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, x2k*| =$  
                                      SDIOH_CMD_5, *cmd_arg, NULL, 0)) != SUCCESS) { G52Z)^  
            sd_err(("%s: No response to CMD5\n", __FUNCTION__)); K%gP5>y*9>  
            continue; @Tr&`Hi  
        } O R #7"  
^PqMi:htc  
        printf("CMD5 response data was: 0x%08x\n", sd->card_rsp_data); C),7- ?  
@o#+5P  
        if (GFIELD(sd->card_rsp_data, RSP4_CARD_READY)) { w<t,j~ Pr#  
            printf("%s: Card ready\n", __FUNCTION__); 0^#DNq*NQ  
            break; q (>c`5  
        } O@jqdJu  
    } "- eZZEl(  
S0LszW)e  
    if (retries > CMD5_RETRIES) { Z^# ]#f  
        sd_err(("%s: Too many retries for CMD5\n", __FUNCTION__)); :wipE]~4t  
        return ERROR; eOnT W4  
    } wqy ^8N[K]  
~HmxEk9  
    *cmd_rsp = sd->card_rsp_data; OCnFEX"  
PLdn#S}.  
    sdspi_crc_onoff(sd, sd_crc ? 1 : 0); jPk c3dG +  
~Ltr.ci  
    return (SUCCESS); +xj "hX>3  
} G{b:i8}l  
 &?+WXL>  
static int |^GyH$.  
sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc) >F3.c%VU]w  
{ l6 7KJ  
    uint32 args; m^I,}1H4  
    int status; B:9.e?t  
\[#t<dD  
    args = use_crc ? 1 : 0; o| D^`Z  
    if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, 6t}XJB$+7  
                                  SDIOH_CMD_59, args, NULL, 0)) != SUCCESS) { Qhy#r  
        sd_err(("%s: No response to CMD59\n", __FUNCTION__)); ^$Krub{|  
    } wsnK3tM7-  
QCpM|,drS  
    sd_info(("CMD59 response data was: 0x%08x\n", sd->card_rsp_data)); V1<`%=%_W  
6D/'`  
    sd_err(("SD-SPI CRC turned %s\n", use_crc ? "ON" : "OFF")); JsQ6l%9  
    return (SUCCESS); #w>~u2W  
} ;7rv  
&q>zR6jne  
static int @`|)Ia<  
sdspi_client_init(sdioh_info_t *sd) G7-!`-Nk  
{ <1@ (ioPH  
    uint8 fn_ints; B8V,)rn  
`.^ |]|u  
    sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot)); s-?fUqA  
@Zm J z  
    /* Start at ~400KHz clock rate for initialization */ *YvRNHP  
    if (!spi_start_clock(sd, 128)) { n29(!10Px  
        sd_err(("spi_start_clock failed\n")); G/{ ~_&t  
        return ERROR; OW`STp!  
    } Gvx[ 8I  
nPA@h  
    if (!sdspi_start_power(sd)) { lf$Ve  
        sd_err(("sdspi_start_power failed\n")); =u|~ <zQw  
        return ERROR; 8_Z/o5s  
    } R^8{bP  
y=H@6$2EQ  
    if (sd->num_funcs == 0) { '*!L!VJ  
        sd_err(("%s: No IO funcs!\n", __FUNCTION__)); D7Zm2Kj  
        return ERROR; (E!!pz  
    } ctJ&URCi#  
*<9$D  
    sdspi_card_enablefuncs(sd); S>f&6ZDNY(  
PW)aLycPK  
    set_client_block_size(sd, 1, BLOCK_SIZE_4318); \ =nrt?  
    fn_ints = INTR_CTL_FUNC1_EN; SY _='9U  
/Ox)|) l  
    if (sd->num_funcs >= 2) { !ALZBB.r(  
        set_client_block_size(sd, 2, sd_f2_blocksize /* BLOCK_SIZE_4328 */); bQQVj?8jp  
        fn_ints |= INTR_CTL_FUNC2_EN; U5+vN[ K  
    } {a "RXa  
L`3n2DEBf  
    /* Enable/Disable Client interrupts */ bd \=h1  
    /* Turn on here but disable at host controller */ '^}+Fv<O  
    if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_INTEN, 1, NQLiWz-q  
                            (fn_ints | INTR_CTL_MASTER_EN)) != SUCCESS) { -[]';f4]M  
        sd_err(("%s: Could not enable ints in CCCR\n", __FUNCTION__)); MCYl{uH!  
        return ERROR; u#jC#u^M  
    } w*~Tm>U  
)#[|hb=o  
    /* Switch to High-speed clocking mode if both host and device support it */ )bD nbO$s_  
    sdspi_set_highspeed_mode(sd, (bool)sd_hiok); QK <\kVZ8  
tZ8e`r*  
    /* After configuring for High-Speed mode, set the desired clock rate. */ A 's-'8m  
    if (!spi_start_clock(sd, (uint16)sd_divisor)) { 3 ^}A %-bS  
        sd_err(("spi_start_clock failed\n")); !%S4 n  
        return ERROR; )=_ycf^MC  
    } &/WAZs$2n  
HL8eD^  
    sd->card_init_done = TRUE; J^zi2 jtV  
"J19*<~  
    return SUCCESS; _\zQ"y|G  
} [1( FgyE  
<P4 FzK  
static int YfDWM7x7,  
sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode) 0k[2jh  
{ OO-k|\{ |  
    uint32 regdata; "wM1qX  
    int status; n=!uNu7  
    bool hsmode; qX6D1X1_  
\}dyS8  
    if (HSMode == TRUE) { q7Es$zjX  
v1+U;Th>g  
        sd_err(("Attempting to enable High-Speed mode.\n")); wCb(>pL0  
=G${[V \  
        if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL, !I8f#'p  
                                         1, &regdata)) != SUCCESS) { |>1hu1  
            return status; vg\/DbI'  
        } wAF,H8 -DK  
        if (regdata & SDIO_SPEED_SHS) { HW6.O|3  
            sd_err(("Device supports High-Speed mode.\n")); |b.z*G  
$8 =@R'  
            regdata |= SDIO_SPEED_EHS; J;QUPpH Z  
5Ec/(-F  
            sd_err(("Writing %08x to Card at %08x\n", jRj=Awy  
                     regdata, SDIOD_CCCR_SPEED_CONTROL)); l]!B#{  
            if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL, iHBB,x  
                                              1, regdata)) != BCME_OK) { ?<%=: Yh  
                return status; AEg(m<t  
            } g8pO Lr'  
S4A q'  
            hsmode = 1; T *>`,}J  
^[q /Mw  
            sd_err(("High-speed clocking mode enabled.\n")); B3 zk(RNZ  
        } ejePDgi_[  
        else { f =s&n}  
            sd_err(("Device does not support High-Speed Mode.\n")); Zi ESlf$  
            hsmode = 0; |g&ym Fc  
        } q]c5MlJXF  
    } else { 9F##F-%x  
        if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL, ]z ==   
                                         1, &regdata)) != SUCCESS) { 4IsG=7   
            return status; W!la-n  
        } ?6N3tk-2  
_D;@v?n6!O  
        regdata = ~SDIO_SPEED_EHS; d8x%SQ!V  
E4oz|2!m  
        sd_err(("Writing %08x to Card at %08x\n", WxUxc75  
                 regdata, SDIOD_CCCR_SPEED_CONTROL)); "@ E3MTW  
        if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL, +t!S'|C  
                                          1, regdata)) != BCME_OK) { ocQWQ   
            return status; 3S~(:#|  
        } Y`ihi,s`H  
D$r Uid  
        sd_err(("Low-speed clocking mode enabled.\n")); vNDu9ovs-  
        hsmode = 0; T0QvnIaP  
    } Te-Amu  
TkRP3_b  
    spi_controller_highspeed_mode(sd, hsmode); I9 64  
OI/@3"L{  
    return TRUE; cDkV;$  
} -"TR\/  
LBlN2)\@  
bool IApT'QNM  
sdspi_start_power(sdioh_info_t *sd) ^ 4>k%d  
{ `dkV_ O0  
    uint32 cmd_arg; c z'5iK  
    uint32 cmd_rsp; O l@_(U  
On_@HQ/FI  
    sd_trace(("%s\n", __FUNCTION__)); MZ4c{@Tg  
DtxE@,  
    /* Get the Card's Operation Condition.  Occasionally the board q!lP"J  
     * takes a while to become ready U.oksD9 v  
     */ CXaWgxlK:a  
X` r* ob  
    cmd_arg = 0; V%ii3  
    if (get_ocr(sd, &cmd_arg, &cmd_rsp) != SUCCESS) { J%rP$O$  
        sd_err(("%s: Failed to get OCR; bailing\n", __FUNCTION__)); zqySm) o]  
        return FALSE; '-PC7"o  
    } x~DLW1I  
2.I^Xf2  
    sd_err(("mem_present = %d\n", GFIELD(cmd_rsp, RSP4_MEM_PRESENT))); MmoR~~*  
    sd_err(("num_funcs = %d\n", GFIELD(cmd_rsp, RSP4_NUM_FUNCS))); fb]S-z(  
    sd_err(("card_ready = %d\n", GFIELD(cmd_rsp, RSP4_CARD_READY))); 1T|$BK@)  
    sd_err(("OCR = 0x%x\n", GFIELD(cmd_rsp, RSP4_IO_OCR))); S;\R!%t_  
]ya; v '  
    /* Verify that the card supports I/O mode */ wxQ>ifi9Z  
    if (GFIELD(cmd_rsp, RSP4_NUM_FUNCS) == 0) { 3{7T4p.G  
        sd_err(("%s: Card does not support I/O\n", __FUNCTION__)); J5p8nmb  
        return ERROR; X]j)+DX>  
    } hvV_xD8|  
Qs 2.ef?  
    sd->num_funcs = GFIELD(cmd_rsp, RSP4_NUM_FUNCS); N3A<:%s  
NTs7KSgZ  
    /* Examine voltage: Arasan only supports 3.3 volts, ]7GlO9  
     * so look for 3.2-3.3 Volts and also 3.3-3.4 volts. vDj;>VE2b  
     */ ^_5|BT@  
ii|? ;  
    if ((GFIELD(cmd_rsp, RSP4_IO_OCR) & (0x3 << 20)) == 0) { 9q[;u[A8^  
        sd_err(("This client does not support 3.3 volts!\n")); ]/2T\w.<  
        return ERROR; ~f>2U]F>5  
    } epD?K  
#=c`of6  
m\u26`M  
    return TRUE; B{6<;u)[  
} o+O}Te  
8G^<[`.@j  
static int ;@mRo`D`  
sdspi_driver_init(sdioh_info_t *sd) t;qP']2  
{ hlJpElYf  
    sd_trace(("%s\n", __FUNCTION__)); ]wn/BG)  
- xm{&0e)  
    if ((sdspi_host_init(sd)) != SUCCESS) { q3e8#R)l  
        return ERROR; o @Z#  
    } *s4\\Wb=  
TV59(bG.2  
    if (sdspi_client_init(sd) != SUCCESS) { X* eW#|$\  
        return ERROR; %ati7{2!  
    } A&5:ATQ/|  
/#LW"4;*  
    return SUCCESS; JgRYljQi2  
} MHj,<|8Q  
C|-pD  
static int PA;6$vqX  
sdspi_card_enablefuncs(sdioh_info_t *sd) ;^){|9@  
{ "h"NW[R  
    int status; I s57F4[}  
    uint32 regdata; d3Di/Iej   
    uint32 regaddr, fbraddr; d=*x#In  
    uint8 func; ?knYY>Kzh1  
    uint8 *ptr; AasZuO_I  
G5.nPsuM   
    sd_trace(("%s\n", __FUNCTION__)); 4$6T+i2E   
    /* Get the Card's common CIS address */ B~o-l*  
    ptr = (uint8 *) &sd->com_cis_ptr; myFAKRc  
    for (regaddr = SDIOD_CCCR_CISPTR_0; regaddr <= SDIOD_CCCR_CISPTR_2; regaddr++) { yzsab ^]  
        if ((status = sdspi_card_regread (sd, 0, regaddr, 1, &regdata)) != SUCCESS) e( X|3h|  
            return status; ? zDa=7 J  
->{d`-}m'  
        *ptr++ = (uint8) regdata; -Sv"gLB  
    } Q%S9fq,q  
U/{6% Qy  
    /* Only the lower 17-bits are valid */ }YhtUWz].  
    sd->com_cis_ptr &= 0x0001FFFF; CO+/.^s7}S  
    sd->func_cis_ptr[0] = sd->com_cis_ptr; L5YnG_M&  
    sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr)); e 8\;t"D  
G[Lpe  
    /* Get the Card's function CIS (for each function) */ tB7}|jC  
    for (fbraddr = SDIOD_FBR_STARTADDR, func = 1; [V8fu qE>  
         func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) { ecJ6  
        ptr = (uint8 *) &sd->func_cis_ptr[func]; lK7m=[ j  
        for (regaddr = SDIOD_FBR_CISPTR_0; regaddr <= SDIOD_FBR_CISPTR_2; regaddr++) { uGN^!NG-0  
            if ((status = sdspi_card_regread (sd, 0, regaddr + fbraddr, 1, &regdata)) &[mZD,  
                != SUCCESS) fnKY1y]2+  
                return status; p,g1eb|E  
y3u+_KY-  
            *ptr++ = (uint8) regdata; q% >'4_  
        } g| <wyt[  
_6@hTen`  
        /* Only the lower 17-bits are valid */ ^D^JzEy'?C  
        sd->func_cis_ptr[func] &= 0x0001FFFF; %(/!ljh_  
        sd_info(("%s: Function %d CIS Ptr = 0x%x\n", \G@wp5  
                 __FUNCTION__, func, sd->func_cis_ptr[func])); I751 t  
    } J8a*s`ik  
Ck =;1sGh  
    sd_info(("%s: write ESCI bit\n", __FUNCTION__)); oEz%={f  
    /* Enable continuous SPI interrupt (ESCI bit) */ BQ</g* $;  
    sdspi_card_regwrite(sd, 0, SDIOD_CCCR_BICTRL, 1, 0x60); TJ8E"t*)  
vl E z9/H  
    sd_info(("%s: enable f1\n", __FUNCTION__)); SlLw{Yb7\.  
    /* Enable function 1 on the card */ `Pn[tuIO  
    regdata = SDIO_FUNC_ENABLE_1; #EGA#SKoq  
    if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOEN, 1, regdata)) != SUCCESS) <bck~E  
        return status; zLw{ {|  
QYb33pN|  
    sd_info(("%s: done\n", __FUNCTION__)); )jrT6x^IB  
    return SUCCESS; ikBYd }5  
} ~I}9;XT  
~tFqb<n  
/* Read client card reg */ qm*}U3K  
static int P>Euq'ajX  
sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data) bAk&~4Y_"  
{ 9i5,2~  
    int status; A=zPL q{Sb  
    uint32 cmd_arg; W=B"Q qL  
    uint32 rsp5; lS^(&<{  
?rX]x8iP  
    cmd_arg = 0; gwd (N  
nR>r2wMk@  
    if ((func == 0) || (regsize == 1)) { 5v\!]?(O;  
        cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func); VQI(Vp|  
        cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr); s^OO^%b  
        cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_READ); hJz):d>Im  
        cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0); 5l-mW0,MK  
        cmd_arg = SFIELD(cmd_arg, CMD52_DATA, 0); )py{\r9X  
GV6K/T :  
        if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0)) Dq@2-Cv  
            != SUCCESS) 'uDjFQX  
            return status; $/1c= Y@  
spofLu.  
        sdspi_cmd_getrsp(sd, &rsp5, 1); 1{Mcs%W;w5  
F(#rQ_z]  
        if (rsp5 != 0x00) q*![AzFh  
            sd_err(("%s: rsp5 flags is 0x%x\t %d\n", Nr<`Z  
                    __FUNCTION__, rsp5, func)); Si 9Z>MR  
8.=\GV  
        *data = sd->card_rsp_data >> 24; dUznxZB  
    } else { "P@>M)-9Z  
        cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize); t2" (2  
        cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1); *Oc.9 F88"  
        cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0); + 1IQYa|  
        cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func); (R~]|?:wt  
        cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr); 9mc!bj^811  
        cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ); mV73 \P6K  
wv QMnE8\  
        sd->data_xfer_count = regsize; 9z;HsUv  
r,goRK.  
        /* sdspi_cmd_issue() returns with the command complete bit g[>\4B9t  
         * in the ISR already cleared (KZHX5T=  
         */ b*fgv9Kh'  
        if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0)) 0n~Zz  
            != SUCCESS) I|-p3g8\  
            return status; (C] SH\  
"1q>At  
        sdspi_cmd_getrsp(sd, &rsp5, 1); x6afI<dm  
plu$h-$d  
        if (rsp5 != 0x00) Q(d9n8  
            sd_err(("%s: rsp5 flags is 0x%x\t %d\n", e7fiGl  
                    __FUNCTION__, rsp5, func)); cH-@V<  
dUgrKDNyA  
        *data = sd->card_rsp_data; MaBYk?TR~  
        if (regsize == 2) { R8L_J6Kpa  
            *data &= 0xffff; aKUS5jDu  
        } jJ4qR:]  
X1[CX&Am  
        sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n", iz(u=/*\  
                 __FUNCTION__, func, regaddr, regsize, *data)); /<CSVJ_r  
3lLMu B+  
&AuF]VT  
    } }),w1/#5u8  
bk<\ujH  
    return SUCCESS; >StO.Q99  
} =z?%;4'|  
SYeadsvF  
/* write a client register */ yq_LW>|Z  
static int .,~(%#Wl$  
sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data) dt[k\ !-v  
{ p_ Fy >j  
    int status; IC{eE  
    uint32 cmd_arg, rsp5, flags; V>64/  
+5.t. d  
    cmd_arg = 0; Uw-p758dD  
cH<q:OYi  
    if ((func == 0) || (regsize == 1)) { 58%'UwKn  
        cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func); '6$*YN&5  
        cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr); 2 nb:)  
        cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_WRITE); sC00un%  
        cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0); T,fI BD:  
        cmd_arg = SFIELD(cmd_arg, CMD52_DATA, data & 0xff); H$ftGwS8  
        if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0)) wdzOFDA  
            != SUCCESS) ]fnnZ  
            return status; )CI1;  
KtS)'jf  
        sdspi_cmd_getrsp(sd, &rsp5, 1); VN4yn| f/  
        flags = GFIELD(rsp5, RSP5_FLAGS); o!E v;' D  
        if (flags && (flags != 0x10)) PqNFyQkl  
            sd_err(("%s: rsp5.rsp5.flags = 0x%x, expecting 0x10\n", Z'^U ad6  
                    __FUNCTION__,  flags)); y5= `ap  
    } 'B83m#HR#  
    else { Sz{O2 l Y  
        cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize); 9p$V)qdX  
        cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1); 6m.k;'  
        cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0); e@@?AB$n(  
        cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func); m6eZ_ &+u  
        cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr); M >:]lpRK  
        cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE); 5ep/h5*/  
c4e_6=Iv  
        sd->data_xfer_count = regsize; VZ>On$hp  
        sd->cmd53_wr_data = data; *?QE2&S:  
&"_u}I&\  
        sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n", ?^' 7+8C*J  
                 __FUNCTION__, func, regaddr, regsize, data)); cN! uV-e  
}MR1^  
        /* sdspi_cmd_issue() returns with the command complete bit ~mV"i7VX  
         * in the ISR already cleared >}~#>Ru  
         */ 53QfTP  
        if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0)) @L84>3O  
            != SUCCESS) NT%W;)6m9  
            return status; < `qRA]  
r8xyd"Axy  
        sdspi_cmd_getrsp(sd, &rsp5, 1); c~A4gtB=  
)PkNWj6%y  
        if (rsp5 != 0x00) qLncn}oNM  
            sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n", "O+5R(XT  
                    __FUNCTION__,  rsp5));  "SN4*  
|eoid?=  
    } STfyCtS  
    return SUCCESS; bLz*A-  
} 89{HJ9}  
1ju#9i`.Wg  
void 8T;IZ(s  
sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count /* num 32 bit words */) !.7udYmB  
{ |( (zTf  
    *rsp_buffer = sd->card_response; 6nDV1O5  
} C8@TZ[w  
DPe]daF  
int max_errors = 0; <0|9Tn2O  
LL!.c  
#define SPI_MAX_PKT_LEN        768 Y9SGRV(  
uint8    spi_databuf[SPI_MAX_PKT_LEN]; ?&WYjTU]H  
uint8    spi_rspbuf[SPI_MAX_PKT_LEN]; < (RC|?  
jD) {I  
/* datalen is used for CMD53 length only (0 for sd->data_xfer_count) */ +y[@T6_  
static int 0?7XtC P<  
sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg, M"=n>;*X  
                uint32 *data, uint32 datalen) oC*ees g_  
{ Kj=gm .  
    uint32 cmd_reg; W!$zXwY}(  
    uint32 cmd_arg = arg; [~5p>'  
    uint8 cmd_crc = 0x95;        /* correct CRC for CMD0 and don't care for others. */ {hSGv   
    uint16 dat_crc; Mro4`GL  
    uint8 cmd52data = 0; v=Y K8fNi  
    uint32 i, j; h>S[^ -,  
    uint32 spi_datalen = 0; 3 K/Df#  
    uint32 spi_pre_cmd_pad    = 0; v|Jlf$>  
    uint32 spi_max_response_pad = 128; {B$2"q/~  
n_[i0x7#  
    cmd_reg = 0; +%J\y^09kr  
    cmd_reg = SFIELD(cmd_reg, SPI_DIR, 1); }6RT,O g  
    cmd_reg = SFIELD(cmd_reg, SPI_CMD_INDEX, cmd); .r|*Ch#;P  
KV!<Oq  
    if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) {    /* Same for CMD52 and CMD53 */ _cJ[ FP1  
        cmd_reg = SFIELD(cmd_reg, SPI_RW, 1); D  _X8-  
    } 3EFD%9n  
qX:B4,|ck  
    switch (cmd) { :LJ7ru2  
    case SDIOH_CMD_59:    /* CRC_ON_OFF (SPI Mode Only) - Response R1 */ yFIy`9R  
        cmd52data = arg & 0x1; U0B2WmT~Q  
    case SDIOH_CMD_0:    /* Set Card to Idle State - No Response */ -H(vL=  
    case SDIOH_CMD_5:    /* Send Operation condition - Response R4 */ -Q e~)7  
        sd_trace(("%s: CMD%d\n", __FUNCTION__, cmd)); ;uI~BV*3  
        spi_datalen = 44; ?v]-^X=&  
        spi_pre_cmd_pad = 12; 'E;W  
        spi_max_response_pad = 28; s}x>J8hK  
        break; bPD)D'Hs  
cH`^D?#se  
    case SDIOH_CMD_3:    /* Ask card to send RCA - Response R6 */ >X}{BDMb.  
    case SDIOH_CMD_7:    /* Select card - Response R1 */ Rz <OF^Iy  
    case SDIOH_CMD_15:    /* Set card to inactive state - Response None */ V}8$p8#<@  
        sd_err(("%s: CMD%d is invalid for SPI Mode.\n", __FUNCTION__, cmd)); X'sEE  
        return ERROR; `{<frB@  
        break; vL_zvX A  
+`en{$%%  
    case SDIOH_CMD_52:    /* IO R/W Direct (single byte) - Response R5 */ 0Vv9BL{  
        cmd52data = GFIELD(cmd_arg, CMD52_DATA); _"f  :`  
        cmd_arg = arg; ,krS-.  
        cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD52_FUNCTION)); uF(k[[qaiN  
        cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD52_REG_ADDR)); O;XG^s@5  
        /* Display trace for byte write */ 9V!-ZG  
        if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) { S0w> hr  
            sd_trace(("%s: CMD52: Wr F:%d @0x%04x=%02x\n", e29y7:)c=  
                      __FUNCTION__, wvc>0?t'  
                      GFIELD(cmd_arg, CMD52_FUNCTION), ,\ldz(D?+  
                      GFIELD(cmd_arg, CMD52_REG_ADDR), 9w ~cvlv[  
                      cmd52data)); zok D:c  
        } _+QwREP  
QEJGnl676  
        spi_datalen = 32; ?T*";_o,B  
        spi_max_response_pad = 28; Q |hm1q  
I lG:X)V%  
        break; 0Oxz3r%}r  
    case SDIOH_CMD_53:    /* IO R/W Extended (multiple bytes/blocks) */ :X>DkRP  
        cmd_arg = arg; sOC&Q&eg  
        cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD53_FUNCTION)); U{1z;lJ  
        cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD53_REG_ADDR)); 3{J.xWB@:  
        cmd_reg = SFIELD(cmd_reg, SPI_BLKMODE, 0);  WR.x&m>  
        cmd_reg = SFIELD(cmd_reg, SPI_OPCODE, GFIELD(cmd_arg, CMD53_OP_CODE)); qc8Ta"  
        cmd_reg = SFIELD(cmd_reg, SPI_STUFF0, (sd->data_xfer_count>>8)); pG yRX_;  
        cmd52data = (uint8)sd->data_xfer_count; (Pi-uL<[a  
8OAg~mQ15(  
        /* Set upper bit in byte count if necessary, but don't set it for 512 bytes. */ Wc'Ehyi;  
        if ((sd->data_xfer_count > 255) && (sd->data_xfer_count < 512)) { 2R@%Y/  
            cmd_reg |= 1; H^(L90  
        } oh\,OW  
'Ji+c  
        if (GFIELD(cmd_reg, SPI_RW) == 1) { /* Write */ [8]m8=n  
            spi_max_response_pad = 32; [%8@D C'  
            spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC; zXre~b03ZS  
        } else { /* Read */ &4kM8Qh  
f'{>AKi=C  
            spi_max_response_pad = 32; 'U)8rR  
            spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC; K5flit4-  
        } :,F=w0O  
        sd_trace(("%s: CMD53: %s F:%d @0x%04x len=0x%02x\n", FBY ODw  
                  __FUNCTION__, )!-S|s'  
                  (GFIELD(cmd_reg, SPI_RW) == 1 ? "Wr" : "Rd"), $L{7%]7QC  
                  GFIELD(cmd_arg, CMD53_FUNCTION), 0n5UKtB  
                  GFIELD(cmd_arg, CMD53_REG_ADDR), b=LF%P  
                  cmd52data)); vjTwv+B"  
        break; a!t V6H  
 KOS yh<&  
    default: h~ha  
        sd_err(("%s: Unknown command %d\n", __FUNCTION__, cmd)); z\}!RBOq  
        return ERROR; :kp0EiJ  
    } S}gD,7@  
L>nO:`>h  
    /* Set up and issue the SDIO command */ i$O#%12l  
    memset(spi_databuf, SDSPI_IDLE_PAD, spi_datalen); QkX@QQ T?  
    spi_databuf[spi_pre_cmd_pad + 0] = (cmd_reg & 0xFF000000) >> 24; 1q!sKoJ<  
    spi_databuf[spi_pre_cmd_pad + 1] = (cmd_reg & 0x00FF0000) >> 16; `^%GN8d}nm  
    spi_databuf[spi_pre_cmd_pad + 2] = (cmd_reg & 0x0000FF00) >> 8; 6FjVmje  
    spi_databuf[spi_pre_cmd_pad + 3] = (cmd_reg & 0x000000FF); wo(j}O-  
    spi_databuf[spi_pre_cmd_pad + 4] = cmd52data; w-: D  
k+\7B}7F  
    /* Generate CRC7 for command, if CRC is enabled, otherwise, a v MWC(m  
     * default CRC7 of 0x95, which is correct for CMD0, is used. M[,^KJ!  
     */ f[@#7,2~M  
    if (sd_crc) { {HuLuP 0t  
        cmd_crc = sdspi_crc7(&spi_databuf[spi_pre_cmd_pad], 5); >B~?dTm  
    } &7F&}7*c  
    spi_databuf[spi_pre_cmd_pad + 5] = cmd_crc; LXxl?D  
#define SPI_STOP_TRAN        0xFD >sV Bj(f  
r5)f82pQ  
    /* for CMD53 Write, put the data into the output buffer  */ ~ 7BX@?  
    if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD53_RW_FLAG) == 1)) { rk|a'&  
        if (datalen != 0) { y''V"Be  
            spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD; rqC1  
            spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK; WguV{#=H  
w:R]!e_6\9  
            for (i = 0; i < sd->data_xfer_count; i++) { 6QptKXu7  
                spi_databuf[i + 11 + spi_pre_cmd_pad] = ((uint8 *)data); m){&:Hs  
            } `q1}6U/k  
            if (sd_crc) { 2o}8W7y  
                dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], i); ]}_,U!`8  
            } else { =0Y'f](2eW  
                dat_crc = 0xAAAA; dh,7iQ s  
            } nP)-Y#`~7  
            spi_databuf[i + 11 + spi_pre_cmd_pad] = (dat_crc >> 8) & 0xFF; 8)`5P\  
            spi_databuf[i + 12 + spi_pre_cmd_pad] = dat_crc & 0xFF; g[<uwknf  
        } else if (sd->data_xfer_count == 2) { KqY>4tb  
            spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD; 4+,*sn  
            spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK; EM~7#Y  
            spi_databuf[spi_pre_cmd_pad + 11]  = sd->cmd53_wr_data & 0xFF; h=mv9=x  
            spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8; Oi#k:vq4  
            if (sd_crc) { %J3lK]bv(  
                dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 2); 2c*2\93>  
            } else { "U{mMd!9L  
                dat_crc = 0x22AA; pb= HVjW<  
            } L%4tw5*N  
            spi_databuf[spi_pre_cmd_pad + 13] = (dat_crc >> 8) & 0xFF; N>T=L0`  
            spi_databuf[spi_pre_cmd_pad + 14] = (dat_crc & 0xFF); #|D:f~"d3  
        } else if (sd->data_xfer_count == 4) { /^WE@r[:  
            spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD; W.sD2f  
            spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK; _4S7wOq5  
            spi_databuf[spi_pre_cmd_pad + 11]  = sd->cmd53_wr_data & 0xFF; ix+x3OCip  
            spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8; s-o~@(r6  
            spi_databuf[spi_pre_cmd_pad + 13] = (sd->cmd53_wr_data & 0x00FF0000) >> 16; _"`/^L`Q?  
            spi_databuf[spi_pre_cmd_pad + 14] = (sd->cmd53_wr_data & 0xFF000000) >> 24; CTh1;U20  
            if (sd_crc) { n/:Z{  
                dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 4); 8^NE=)cb7w  
            } else { yl|R:/2V  
                dat_crc = 0x44AA; QTJrJD  
            } Xek E#?.  
            spi_databuf[spi_pre_cmd_pad + 15] = (dat_crc >> 8) & 0xFF; [kQ"6wh8  
            spi_databuf[spi_pre_cmd_pad + 16] = (dat_crc & 0xFF); y& Gw.N}<r  
        } else { ;vZ*,q6  
            printf("CMD53 Write: size %d unsupported\n", sd->data_xfer_count); Zr~"\llk  
        } cbY3mSfn*  
    } <4SF~i  
iNMLYYq]l  
    spi_sendrecv(sd, spi_databuf, spi_rspbuf, spi_datalen); W'8J<VBD  
J78Qj[v  
    for (i = spi_pre_cmd_pad + SDSPI_COMMAND_LEN; i < spi_max_response_pad; i++) { "otr+.{`*  
        if ((spi_rspbuf & SDSPI_START_BIT_MASK) == 0) { yzODF>KJ  
            break; (u$!\fE-et  
        } </~1p~=hAt  
    } %,h!: Ec^c  
A89Y;_4y  
    if (i == spi_max_response_pad) { t/_\U =i$  
        sd_err(("%s: Did not get a response for CMD%d\n", __FUNCTION__, cmd)); UX+?0K  
        return ERROR; vQE` c@^{  
    } lb=2*dFJ1  
4ZSfz#<[z  
    /* Extract the response. */ U Ek |8yq  
    sd->card_response = spi_rspbuf; $=X!nQ& Z|  
S;G"L$&\  
    /* for CMD53 Read, find the start of the response data... */ nau~i1  
    if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) { &*h`b{]  
        for (; i < spi_max_response_pad; i++) {  ||bA  
            if (spi_rspbuf == SDSPI_START_BLOCK) { Iht mD@H}  
                break; %!1@aL]pQ  
            } K7YT0cG  
        } n C\(+K1%  
\r)_-  
        if (i == spi_max_response_pad) { .CB"@.7  
            printf("Did not get a start of data phase for CMD%d\n", cmd); S8rW'}XJ=H  
            max_errors++; zSX'  
            sdspi_abort(sd, GFIELD(cmd_arg, CMD53_FUNCTION)); Jc9@VxWY  
        } ^*j[&:d  
        sd->card_rsp_data = spi_rspbuf[i+1]; F=P+;%.  
        sd->card_rsp_data |= spi_rspbuf[i+2] << 8; ~QQEHx\4zZ  
        sd->card_rsp_data |= spi_rspbuf[i+3] << 16; @8T Vr2uy  
        sd->card_rsp_data |= spi_rspbuf[i+4] << 24; pb$ An<P  
c9>8IW  
        if (datalen != 0) { 7cJO)cm0'  
            i++; bUEt0wRR  
            for (j = 0; j < sd->data_xfer_count; j++) { Phk`=:xh  
                ((uint8 *)data)[j] = spi_rspbuf[i+j]; woC FN1W  
            } U/ v"?pg[  
            if (sd_crc) { Z &ua,:5  
                uint16 recv_crc; t\E-6u  
T/X?ZK(T  
                recv_crc = spi_rspbuf[i+j] << 8 | spi_rspbuf[i+j+1]; F5om-tzy  
                dat_crc = sdspi_crc16((uint8 *)data, datalen); t/EMBfLc  
                if (dat_crc != recv_crc) { &z 1|  
                    sd_err(("%s: Incorrect data CRC: expected 0x%04x, " H-PW(  
                            "received 0x%04x\n", kM}ic(K  
                            __FUNCTION__, dat_crc, recv_crc)); Q*oA{eZY  
                } o>QFd x  
            } [7ek;d;'t  
        } iLI.e rm  
        return SUCCESS; .T N`p*  
    } uH~ TugQ~  
~ Iu21Q(*  
    sd->card_rsp_data = spi_rspbuf[i+4]; ?3KR(6D  
    sd->card_rsp_data |= spi_rspbuf[i+3] << 8; %s&E-*X  
    sd->card_rsp_data |= spi_rspbuf[i+2] << 16; Q:Nwy(,I  
    sd->card_rsp_data |= spi_rspbuf[i+1] << 24; 0|*UeM  
6>P  
    /* Display trace for byte read */ `eA&C4oFOO  
    if ((cmd == SDIOH_CMD_52) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) { OGD8QD  
        sd_trace(("%s: CMD52: Rd F:%d @0x%04x=%02x\n", GwU>o:g"  
                  __FUNCTION__, Ra15d^  
                  GFIELD(cmd_arg, CMD53_FUNCTION), bo?3E +B  
                  GFIELD(cmd_arg, CMD53_REG_ADDR), Wtzj;GJj  
                  sd->card_rsp_data >> 24)); 0'`8HP  
    } J7 zVi  
IJb1) ZuR  
    return SUCCESS; Ke;X3j ]`  
} t,r&SrC  
N4JqW  
/* %I2xK.8=  
* On entry: if single-block or non-block, buffer size <= block size. olQ8s *  
* If multi-block, buffer size is unlimited. _|5FrN  
* Question is how to handle the left-overs in either single- or multi-block. dp%pbn6w  
* I think the caller should break the buffer up so this routine will always 1Ag;s  
* use block size == buffer size to handle the end piece of the buffer <^X'f  
*/ E]U3O>hf  
%NAFU /&  
static int q4#f *]  
sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int nbytes, uint32 *data) "a%ASy>?g  
{ TG%hy"k  
    int status; h1UlLy 8  
    uint32 cmd_arg; (^s&#_w03  
    uint32 rsp5; 0qV*d  
    int num_blocks, blocksize; po](6V  
    bool local_blockmode, local_dma; uJ!s%s2g  
    bool read = rw == SDIOH_READ ? 1 : 0; &s}@7htE  
"}~i7NBB  
    ASSERT(nbytes); =='{[[J  
p9] 7g%  
    cmd_arg = 0; A%czhF  
    sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", .0*CT:1=0  
             __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR", :`"T Eif  
             addr, nbytes, sd->r_cnt, sd->t_cnt)); 6+f>XL#w  
+K?N:w  
    if (read) sd->r_cnt++; else sd->t_cnt++; _*?"[TYfX  
p31rhe   
    local_blockmode = sd->sd_blockmode; gBiQIhz  
    local_dma = sd->sd_use_dma; `J7Lecgo  
He_(JXTP  
    /* Don't bother with block mode on small xfers */ 'V9aB5O&  
    if (nbytes < sd->client_block_size[func]) { -$MC  
        sd_info(("setting local blockmode to false: nbytes (%d) != block_size (%d)\n", gW pT:tX-  
                 nbytes, sd->client_block_size[func])); en#g<on  
        local_blockmode = FALSE; P)j9\ muc  
        local_dma = FALSE; SUi1*S  
    } C.e|VzQa  
D>#v 6XI  
    if (local_blockmode) { f;XsShxr  
        blocksize = MIN(sd->client_block_size[func], nbytes); W;}u 2GH  
        num_blocks = nbytes/blocksize; 1*, ~1!>  
        cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, num_blocks); ?;#3U5$v  
        cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 1); {F9Qy0.*u  
    } else { {S: 3 FI  
        num_blocks =  1; 4Z p5o`*g2  
        blocksize = nbytes; ~aR='\<  
        cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, nbytes); T]Td4T!  
        cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0); BNoCE!  
    } C`T5d  
=28H^rK{  
    if (fifo) |3lAye,t)a  
        cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 0); f(MHU   
    else -/7=\kao%  
        cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1); :a!a  
V5@[7ncVf  
    cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func); MdboWE5i  
    cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, addr); 1YD.jU^;HD  
    if (read) KXbYv62  
        cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ); e`2R{H  
    else sU_4+Mk  
        cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE); #YYvc`9  
.lj!~_  
    sd->data_xfer_count = nbytes; } fMFQA)  
    if ((func == 2) && (fifo == 1)) { >s?;2T2"yx  
        sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n", $ 5-2 cL  
                 __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR", T:~W.3  
                 addr, nbytes, sd->r_cnt, sd->t_cnt)); G`lhvpifG  
    } ^^Q32XC,  
w8#>xV^~  
    /* sdspi_cmd_issue() returns with the command complete bit )w?$~q  
     * in the ISR already cleared kQ'xs%Fw  
     */ kJpHhAn4  
    if ((status = sdspi_cmd_issue(sd, local_dma, VRP.tD  
                                  SDIOH_CMD_53, cmd_arg, Wq&c,H  
                                  data, nbytes)) != SUCCESS) { !4cdP2^P  
        sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, (read ? "read" : "write"))); QN a3S*  
        return status; Kf<_A{s  
    } ~{$'sp0  
92_H!m/  
    sdspi_cmd_getrsp(sd, &rsp5, 1); e[&3K<  
vjRD?kF  
    if (rsp5 != 0x00) { $=SYssg7La  
        sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n", ^52R`{  
                __FUNCTION__,  rsp5)); <l/Qf[V  
        return ERROR; l8lR5<  
    } cDyC&}:f  
#@"rp]1xv  
    return SUCCESS; x&b-Na3Xi  
} &: 8&;vk  
?+tZP3'  
static int uQ+$HzxX  
set_client_block_size(sdioh_info_t *sd, int func, int block_size) 9TS=>  
{ LbI])M  
    int base; !7*/lG  
    int err = 0; 0DT2qM[,  
I T2sS6&R  
    sd_err(("%s: Setting block size %d, func %d\n", __FUNCTION__, block_size, func));  o*1`,n  
    sd->client_block_size[func] = block_size; zb)SlR  
.JKaC>oX  
    /* Set the block size in the SDIO Card register */ IH:Cm5MV  
    base = func * SDIOD_FBR_SIZE; 1/J*ki+?  
    err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_0, 1, block_size & 0xff); . L%@/(r  
    if (!err) { #T`+~tW'|  
        err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_1, 1, A8Y~^wn  
                                  (block_size >> 8) & 0xff); O~]G(TMs8W  
    } L(S.  
D+PUi!  
    /* hG3Lj7)UH  
     * Do not set the block size in the SDIO Host register; that ee` =B  
     * is func dependent and will get done on an individual %=eD)p7l-  
     * transaction basis. >maz t=,  
     */ o-Arfc3Q  
"evV/Fg (  
    return (err ? BCME_SDIO_ERROR : 0); `sC8ro@Fm  
}  Vp4]  
+c_CYkHJ/  
/* Reset and re-initialize the device */ C}E ea~  
int <9ph c  
sdioh_sdio_reset(sdioh_info_t *si) Sd11ZC6  
{ B6&Mtm1  
    si->card_init_done = FALSE; " N4]e/.V  
    return sdspi_client_init(si); a8$pc>2E  
} `d#_66TLr  
/omVM u  
#define CRC7_POLYNOM    0x09 IDZn ,^  
#define CRC7_CRCHIGHBIT    0x40 w Vmy`OV/  
[wYQP6Cyy  
static uint8 sdspi_crc7(unsigned char* p, uint32 len) .1}(Bywm5  
{ .p_$]  
    uint8 c, j, bit, crc = 0; U++UG5c  
    uint32 i; ,r4af<  
b7mP~]V  
    for (i = 0; i < len; i++) { n_glYSV!  
        c = *p++; FgaBwd^W  
        for (j = 0x80; j; j >>= 1) { KguFU  
            bit = crc & CRC7_CRCHIGHBIT; ,/9|j*9H  
            crc <<= 1; 4ebGAg?_  
            if (c & j) bit ^= CRC7_CRCHIGHBIT; SBt: `,  
            if (bit) crc ^= CRC7_POLYNOM; d a9 *>+[  
        } z"`?<A&u  
    } P*]g*&*Y +  
_Z&R'`kg  
    /* Convert the CRC7 to an 8-bit SD CRC */ VUy 1?n  
    crc = (crc << 1) | 1; <'33!8 G  
na)ceN2h  
    return (crc); z ZQoY_UI  
} z>~3*a9&  
)G&OX  
#define CRC16_POLYNOM    0x1021 x]T;W&s  
#define CRC16_CRCHIGHBIT    0x8000 _Qas+8NW  
 VVY\W!  
static uint16 sdspi_crc16(unsigned char* p, uint32 len) 0g\&3EvD  
{ Wd# 6Y}:  
    uint32 i; 3WS % H17  
    uint16 j, c, bit; <Jz>e}*)  
    uint16 crc = 0; 0Jr< >7Q1  
nceF4Ty  
    for (i = 0; i < len; i++) { \=~Ap#Mpc4  
        c = *p++; Yg b#U'|  
        for (j = 0x80; j; j >>= 1) { KNhH4K2iP8  
            bit = crc & CRC16_CRCHIGHBIT; OMU#Sx!6  
            crc <<= 1; &\r%&IX/  
            if (c & j) bit ^= CRC16_CRCHIGHBIT; gu!A:Q  
            if (bit) crc ^= CRC16_POLYNOM; N8TO"`wdbs  
        } EC0auB7G  
    } &V L<Rx  
hV)I C9  
    return (crc); 'I2)-=ZL6  
} WjB[e>  


评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

一般

差劲
离线yangjing29

性别:
帅哥
发帖
2327
金币
11907
提示:会员销售的附件,下载积分 = 版块积分 + 销售积分       只看该作者 1楼 发表于: 2015-07-07
      


快速回复
限150 字节
 
上一个 下一个