aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFranky Lin <frankyl@broadcom.com>2011-04-25 18:45:08 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-04-25 19:40:17 -0400
commitcb63e4c967541402b79a92a31c841744ca17d1aa (patch)
tree44f8ec68eea237e7dcc8ec904e97883be23930d5
parentddd0b091dbb0cd6891f13c6157679076467aa146 (diff)
staging: brcm80211: Add dhdsdio_chip_attach in dhd_sdio.c
dhdsdio_chip_attach and it sub functions are added for si/sb utils removal. It will replace si_attach in following patches. Signed-off-by: Franky Lin <frankyl@broadcom.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_sdio.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
index 40d6de3b162b..14f470358182 100644
--- a/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
+++ b/drivers/staging/brcm80211/brcmfmac/dhd_sdio.c
@@ -53,6 +53,7 @@
53#include <dhdioctl.h> 53#include <dhdioctl.h>
54#include <sdiovar.h> 54#include <sdiovar.h>
55#include <siutils_priv.h> 55#include <siutils_priv.h>
56#include <bcmchip.h>
56 57
57#ifndef DHDSDIO_MEM_DUMP_FNAME 58#ifndef DHDSDIO_MEM_DUMP_FNAME
58#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" 59#define DHDSDIO_MEM_DUMP_FNAME "mem_dump"
@@ -166,12 +167,28 @@ typedef struct dhd_console {
166} dhd_console_t; 167} dhd_console_t;
167#endif /* DHD_DEBUG */ 168#endif /* DHD_DEBUG */
168 169
170/* misc chip info needed by some of the routines */
171struct chip_info {
172 u32 chip;
173 u32 chiprev;
174 u32 cccorebase;
175 u32 ccrev;
176 u32 cccaps;
177 u32 buscorebase;
178 u32 buscorerev;
179 u32 buscoretype;
180 u32 ramcorebase;
181 u32 armcorebase;
182 u32 pmurev;
183};
184
169/* Private data for SDIO bus interaction */ 185/* Private data for SDIO bus interaction */
170typedef struct dhd_bus { 186typedef struct dhd_bus {
171 dhd_pub_t *dhd; 187 dhd_pub_t *dhd;
172 188
173 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ 189 bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */
174 si_t *sih; /* Handle for SI calls */ 190 si_t *sih; /* Handle for SI calls */
191 struct chip_info *ci; /* Chip info struct */
175 char *vars; /* Variables (from CIS and/or other) */ 192 char *vars; /* Variables (from CIS and/or other) */
176 uint varsz; /* Size of variables buffer */ 193 uint varsz; /* Size of variables buffer */
177 u32 sbaddr; /* Current SB window pointer (-1, invalid) */ 194 u32 sbaddr; /* Current SB window pointer (-1, invalid) */
@@ -465,6 +482,7 @@ static int dhdsdio_download_nvram(struct dhd_bus *bus);
465#ifdef BCMEMBEDIMAGE 482#ifdef BCMEMBEDIMAGE
466static int dhdsdio_download_code_array(struct dhd_bus *bus); 483static int dhdsdio_download_code_array(struct dhd_bus *bus);
467#endif 484#endif
485static int dhdsdio_chip_attach(struct dhd_bus *bus, void *regs);
468 486
469static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) 487static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size)
470{ 488{
@@ -5289,6 +5307,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, void *sdh, void *regsva, u16 devid)
5289 DHD_ERROR(("%s: si_attach failed!\n", __func__)); 5307 DHD_ERROR(("%s: si_attach failed!\n", __func__));
5290 goto fail; 5308 goto fail;
5291 } 5309 }
5310 if (dhdsdio_chip_attach(bus, regsva)) {
5311 DHD_ERROR(("%s: dhdsdio_chip_attach failed!\n", __func__));
5312 goto fail;
5313 }
5292 5314
5293 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); 5315 bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev);
5294 5316
@@ -6071,3 +6093,234 @@ int dhd_bus_devreset(dhd_pub_t *dhdp, u8 flag)
6071 } 6093 }
6072 return bcmerror; 6094 return bcmerror;
6073} 6095}
6096
6097static int
6098dhdsdio_chip_recognition(bcmsdh_info_t *sdh, struct chip_info *ci, void *regs)
6099{
6100 u32 regdata;
6101
6102 /*
6103 * Get CC core rev
6104 * Chipid is assume to be at offset 0 from regs arg
6105 * For different chiptypes or old sdio hosts w/o chipcommon,
6106 * other ways of recognition should be added here.
6107 */
6108 ci->cccorebase = (u32)regs;
6109 regdata = bcmsdh_reg_read(sdh, CORE_CC_REG(ci->cccorebase, chipid), 4);
6110 ci->chip = regdata & CID_ID_MASK;
6111 ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
6112
6113 DHD_INFO(("%s: chipid=0x%x chiprev=%d\n",
6114 __func__, ci->chip, ci->chiprev));
6115
6116 /* Address of cores for new chips should be added here */
6117 switch (ci->chip) {
6118 case BCM4329_CHIP_ID:
6119 ci->buscorebase = BCM4329_CORE_BUS_BASE;
6120 ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE;
6121 ci->armcorebase = BCM4329_CORE_ARM_BASE;
6122 break;
6123 default:
6124 DHD_ERROR(("%s: chipid 0x%x is not supported\n",
6125 __func__, ci->chip));
6126 return -ENODEV;
6127 }
6128
6129 regdata = bcmsdh_reg_read(sdh,
6130 CORE_SB(ci->cccorebase, sbidhigh), 4);
6131 ci->ccrev = SBCOREREV(regdata);
6132
6133 regdata = bcmsdh_reg_read(sdh,
6134 CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
6135 ci->pmurev = regdata & PCAP_REV_MASK;
6136
6137 regdata = bcmsdh_reg_read(sdh, CORE_SB(ci->buscorebase, sbidhigh), 4);
6138 ci->buscorerev = SBCOREREV(regdata);
6139 ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
6140
6141 DHD_INFO(("%s: ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
6142 __func__, ci->ccrev, ci->pmurev,
6143 ci->buscorerev, ci->buscoretype));
6144
6145 /* get chipcommon capabilites */
6146 ci->cccaps = bcmsdh_reg_read(sdh,
6147 CORE_CC_REG(ci->cccorebase, capabilities), 4);
6148
6149 return 0;
6150}
6151
6152static void
6153dhdsdio_chip_disablecore(bcmsdh_info_t *sdh, u32 corebase)
6154{
6155 u32 regdata;
6156
6157 regdata = bcmsdh_reg_read(sdh,
6158 CORE_SB(corebase, sbtmstatelow), 4);
6159 if (regdata & SBTML_RESET)
6160 return;
6161
6162 regdata = bcmsdh_reg_read(sdh,
6163 CORE_SB(corebase, sbtmstatelow), 4);
6164 if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
6165 /*
6166 * set target reject and spin until busy is clear
6167 * (preserve core-specific bits)
6168 */
6169 regdata = bcmsdh_reg_read(sdh,
6170 CORE_SB(corebase, sbtmstatelow), 4);
6171 bcmsdh_reg_write(sdh, CORE_SB(corebase, sbtmstatelow), 4,
6172 regdata | SBTML_REJ);
6173
6174 regdata = bcmsdh_reg_read(sdh,
6175 CORE_SB(corebase, sbtmstatelow), 4);
6176 udelay(1);
6177 SPINWAIT((bcmsdh_reg_read(sdh,
6178 CORE_SB(corebase, sbtmstatehigh), 4) &
6179 SBTMH_BUSY), 100000);
6180
6181 regdata = bcmsdh_reg_read(sdh,
6182 CORE_SB(corebase, sbtmstatehigh), 4);
6183 if (regdata & SBTMH_BUSY)
6184 DHD_ERROR(("%s: ARM core still busy\n", __func__));
6185
6186 regdata = bcmsdh_reg_read(sdh,
6187 CORE_SB(corebase, sbidlow), 4);
6188 if (regdata & SBIDL_INIT) {
6189 regdata = bcmsdh_reg_read(sdh,
6190 CORE_SB(corebase, sbimstate), 4) |
6191 SBIM_RJ;
6192 bcmsdh_reg_write(sdh,
6193 CORE_SB(corebase, sbimstate), 4,
6194 regdata);
6195 regdata = bcmsdh_reg_read(sdh,
6196 CORE_SB(corebase, sbimstate), 4);
6197 udelay(1);
6198 SPINWAIT((bcmsdh_reg_read(sdh,
6199 CORE_SB(corebase, sbimstate), 4) &
6200 SBIM_BY), 100000);
6201 }
6202
6203 /* set reset and reject while enabling the clocks */
6204 bcmsdh_reg_write(sdh,
6205 CORE_SB(corebase, sbtmstatelow), 4,
6206 (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
6207 SBTML_REJ | SBTML_RESET));
6208 regdata = bcmsdh_reg_read(sdh,
6209 CORE_SB(corebase, sbtmstatelow), 4);
6210 udelay(10);
6211
6212 /* clear the initiator reject bit */
6213 regdata = bcmsdh_reg_read(sdh,
6214 CORE_SB(corebase, sbidlow), 4);
6215 if (regdata & SBIDL_INIT) {
6216 regdata = bcmsdh_reg_read(sdh,
6217 CORE_SB(corebase, sbimstate), 4) &
6218 ~SBIM_RJ;
6219 bcmsdh_reg_write(sdh,
6220 CORE_SB(corebase, sbimstate), 4,
6221 regdata);
6222 }
6223 }
6224
6225 /* leave reset and reject asserted */
6226 bcmsdh_reg_write(sdh, CORE_SB(corebase, sbtmstatelow), 4,
6227 (SBTML_REJ | SBTML_RESET));
6228 udelay(1);
6229}
6230
6231static int
6232dhdsdio_chip_attach(struct dhd_bus *bus, void *regs)
6233{
6234 struct chip_info *ci;
6235 int err;
6236 u8 clkval, clkset;
6237
6238 DHD_TRACE(("%s: Enter\n", __func__));
6239
6240 /* alloc chip_info_t */
6241 ci = kmalloc(sizeof(struct chip_info), GFP_ATOMIC);
6242 if (NULL == ci) {
6243 DHD_ERROR(("%s: malloc failed!\n", __func__));
6244 return -ENOMEM;
6245 }
6246
6247 memset((unsigned char *)ci, 0, sizeof(struct chip_info));
6248
6249 /* bus/core/clk setup for register access */
6250 /* Try forcing SDIO core to do ALPAvail request only */
6251 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
6252 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR,
6253 clkset, &err);
6254 if (err) {
6255 DHD_ERROR(("%s: error writing for HT off\n", __func__));
6256 goto fail;
6257 }
6258
6259 /* If register supported, wait for ALPAvail and then force ALP */
6260 /* This may take up to 15 milliseconds */
6261 clkval = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
6262 SBSDIO_FUNC1_CHIPCLKCSR, NULL);
6263 if ((clkval & ~SBSDIO_AVBITS) == clkset) {
6264 SPINWAIT(((clkval =
6265 bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
6266 SBSDIO_FUNC1_CHIPCLKCSR,
6267 NULL)),
6268 !SBSDIO_ALPAV(clkval)),
6269 PMU_MAX_TRANSITION_DLY);
6270 if (!SBSDIO_ALPAV(clkval)) {
6271 DHD_ERROR(("%s: timeout on ALPAV wait, clkval 0x%02x\n",
6272 __func__, clkval));
6273 err = -EBUSY;
6274 goto fail;
6275 }
6276 clkset = SBSDIO_FORCE_HW_CLKREQ_OFF |
6277 SBSDIO_FORCE_ALP;
6278 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1,
6279 SBSDIO_FUNC1_CHIPCLKCSR,
6280 clkset, &err);
6281 udelay(65);
6282 } else {
6283 DHD_ERROR(("%s: ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
6284 __func__, clkset, clkval));
6285 err = -EACCES;
6286 goto fail;
6287 }
6288
6289 /* Also, disable the extra SDIO pull-ups */
6290 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SDIOPULLUP, 0,
6291 NULL);
6292
6293 err = dhdsdio_chip_recognition(bus->sdh, ci, regs);
6294 if (err)
6295 goto fail;
6296
6297 /*
6298 * Make sure any on-chip ARM is off (in case strapping is wrong),
6299 * or downloaded code was already running.
6300 */
6301 dhdsdio_chip_disablecore(bus->sdh, ci->armcorebase);
6302
6303 bcmsdh_reg_write(bus->sdh,
6304 CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0);
6305 bcmsdh_reg_write(bus->sdh,
6306 CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0);
6307
6308 /* Disable F2 to clear any intermediate frame state on the dongle */
6309 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN,
6310 SDIO_FUNC_ENABLE_1, NULL);
6311
6312 /* WAR: cmd52 backplane read so core HW will drop ALPReq */
6313 clkval = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1,
6314 0, NULL);
6315
6316 /* Done with backplane-dependent accesses, can drop clock... */
6317 bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0,
6318 NULL);
6319
6320 bus->ci = ci;
6321 return 0;
6322fail:
6323 bus->ci = NULL;
6324 kfree(ci);
6325 return err;
6326}