1 /* 2 * Broadcom SPI over PCI-SPI Host Controller, low-level hardware driver 3 * 4 * Copyright (C) 1999-2010, Broadcom Corporation 5 * 6 * Unless you and Broadcom execute a separate written software license 7 * agreement governing use of this software, this software is licensed to you 8 * under the terms of the GNU General Public License version 2 (the "GPL"), 9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the 10 * following added to such license: 11 * 12 * As a special exception, the copyright holders of this software give you 13 * permission to link this software with independent modules, and to copy and 14 * distribute the resulting executable under terms of your choice, provided that 15 * you also meet, for each linked independent module, the terms and conditions of 16 * the license of that module. An independent module is a module which is not 17 * derived from this software. The special exception does not apply to any 18 * modifications of the software. 19 * 20 * Notwithstanding the above, under no circumstances may you combine this 21 * software in any way with any other Broadcom software provided under a license 22 * other than the GPL, without Broadcom's express prior written consent. 23 * 24 * $Id: bcmpcispi.c,v 1.22.2.4.4.5.6.1 2010/08/13 00:26:05 Exp $ 25 */ 26 27 #include <typedefs.h> 28 #include <bcmutils.h> 29 30 #include <sdio.h> /* SDIO Specs */ 31 #include <bcmsdbus.h> /* bcmsdh to/from specific controller APIs */ 32 #include <sdiovar.h> /* to get msglevel bit values */ 33 34 #include <pcicfg.h> 35 #include <bcmsdspi.h> 36 #include <bcmspi.h> 37 #include <bcmpcispi.h> /* BRCM PCI-SPI Host Controller Register definitions */ 38 39 40 /* ndis_osl.h needs to do a runtime check of the osh to map 41 * R_REG/W_REG to bus specific access similar to linux_osl.h. 42 * Until then... 43 */ 44 /* linux */ 45 46 #define SPIPCI_RREG R_REG 47 #define SPIPCI_WREG W_REG 48 49 50 #define SPIPCI_ANDREG(osh, r, v) SPIPCI_WREG(osh, (r), (SPIPCI_RREG(osh, r) & (v))) 51 #define SPIPCI_ORREG(osh, r, v) SPIPCI_WREG(osh, (r), (SPIPCI_RREG(osh, r) | (v))) 52 53 54 int bcmpcispi_dump = 0; /* Set to dump complete trace of all SPI bus transactions */ 55 56 typedef struct spih_info_ { 57 uint bar0; /* BAR0 of PCI Card */ 58 uint bar1; /* BAR1 of PCI Card */ 59 osl_t *osh; /* osh handle */ 60 spih_pciregs_t *pciregs; /* PCI Core Registers */ 61 spih_regs_t *regs; /* SPI Controller Registers */ 62 uint8 rev; /* PCI Card Revision ID */ 63 } spih_info_t; 64 65 66 /* Attach to PCI-SPI Host Controller Hardware */ 67 bool 68 spi_hw_attach(sdioh_info_t *sd) 69 { 70 osl_t *osh; 71 spih_info_t *si; 72 73 sd_trace(("%s: enter\n", __FUNCTION__)); 74 75 osh = sd->osh; 76 77 if ((si = (spih_info_t *)MALLOC(osh, sizeof(spih_info_t))) == NULL) { 78 sd_err(("%s: out of memory, malloced %d bytes\n", __FUNCTION__, MALLOCED(osh))); 79 return FALSE; 80 } 81 82 bzero(si, sizeof(spih_info_t)); 83 84 sd->controller = si; 85 86 si->osh = sd->osh; 87 si->rev = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_REV, 4) & 0xFF; 88 89 if (si->rev < 3) { 90 sd_err(("Host controller %d not supported, please upgrade to rev >= 3\n", si->rev)); 91 MFREE(osh, si, sizeof(spih_info_t)); 92 return (FALSE); 93 } 94 95 sd_err(("Attaching to Generic PCI SPI Host Controller Rev %d\n", si->rev)); 96 97 /* FPGA Revision < 3 not supported by driver anymore. */ 98 ASSERT(si->rev >= 3); 99 100 si->bar0 = sd->bar0; 101 102 /* Rev < 10 PciSpiHost has 2 BARs: 103 * BAR0 = PCI Core Registers 104 * BAR1 = PciSpiHost Registers (all other cores on backplane) 105 * 106 * Rev 10 and up use a different PCI core which only has a single 107 * BAR0 which contains the PciSpiHost Registers. 108 */ 109 if (si->rev < 10) { 110 si->pciregs = (spih_pciregs_t *)spi_reg_map(osh, 111 (uintptr)si->bar0, 112 sizeof(spih_pciregs_t)); 113 sd_err(("Mapped PCI Core regs to BAR0 at %p\n", si->pciregs)); 114 115 si->bar1 = OSL_PCI_READ_CONFIG(sd->osh, PCI_CFG_BAR1, 4); 116 si->regs = (spih_regs_t *)spi_reg_map(osh, 117 (uintptr)si->bar1, 118 sizeof(spih_regs_t)); 119 sd_err(("Mapped SPI Controller regs to BAR1 at %p\n", si->regs)); 120 } else { 121 si->regs = (spih_regs_t *)spi_reg_map(osh, 122 (uintptr)si->bar0, 123 sizeof(spih_regs_t)); 124 sd_err(("Mapped SPI Controller regs to BAR0 at %p\n", si->regs)); 125 si->pciregs = NULL; 126 } 127 /* Enable SPI Controller, 16.67MHz SPI Clock */ 128 SPIPCI_WREG(osh, &si->regs->spih_ctrl, 0x000000d1); 129 130 /* Set extended feature register to defaults */ 131 SPIPCI_WREG(osh, &si->regs->spih_ext, 0x00000000); 132 133 /* Set GPIO CS# High (de-asserted) */ 134 SPIPCI_WREG(osh, &si->regs->spih_gpio_data, SPIH_CS); 135 136 /* set GPIO[0] to output for CS# */ 137 /* set GPIO[1] to output for power control */ 138 /* set GPIO[2] to input for card detect */ 139 SPIPCI_WREG(osh, &si->regs->spih_gpio_ctrl, (SPIH_CS | SPIH_SLOT_POWER)); 140 141 /* Clear out the Read FIFO in case there is any stuff left in there from a previous run. */ 142 while ((SPIPCI_RREG(osh, &si->regs->spih_stat) & SPIH_RFEMPTY) == 0) { 143 SPIPCI_RREG(osh, &si->regs->spih_data); 144 } 145 146 /* Wait for power to stabilize to the SDIO Card (100msec was insufficient) */ 147 OSL_DELAY(250000); 148 149 /* Check card detect on FPGA Revision >= 4 */ 150 if (si->rev >= 4) { 151 if (SPIPCI_RREG(osh, &si->regs->spih_gpio_data) & SPIH_CARD_DETECT) { 152 sd_err(("%s: no card detected in SD slot\n", __FUNCTION__)); 153 spi_reg_unmap(osh, (uintptr)si->regs, sizeof(spih_regs_t)); 154 if (si->pciregs) { 155 spi_reg_unmap(osh, (uintptr)si->pciregs, sizeof(spih_pciregs_t)); 156 } 157 MFREE(osh, si, sizeof(spih_info_t)); 158 return FALSE; 159 } 160 } 161 162 /* Interrupts are level sensitive */ 163 SPIPCI_WREG(osh, &si->regs->spih_int_edge, 0x80000000); 164 165 /* Interrupts are active low. */ 166 SPIPCI_WREG(osh, &si->regs->spih_int_pol, 0x40000004); 167 168 /* Enable interrupts through PCI Core. */ 169 if (si->pciregs) { 170 SPIPCI_WREG(osh, &si->pciregs->ICR, PCI_INT_PROP_EN); 171 } 172 173 sd_trace(("%s: exit\n", __FUNCTION__)); 174 return TRUE; 175 } 176 177 /* Detach and return PCI-SPI Hardware to unconfigured state */ 178 bool 179 spi_hw_detach(sdioh_info_t *sd) 180 { 181 spih_info_t *si = (spih_info_t *)sd->controller; 182 osl_t *osh = si->osh; 183 spih_regs_t *regs = si->regs; 184 spih_pciregs_t *pciregs = si->pciregs; 185 186 sd_trace(("%s: enter\n", __FUNCTION__)); 187 188 SPIPCI_WREG(osh, ®s->spih_ctrl, 0x00000010); 189 SPIPCI_WREG(osh, ®s->spih_gpio_ctrl, 0x00000000); /* Disable GPIO for CS# */ 190 SPIPCI_WREG(osh, ®s->spih_int_mask, 0x00000000); /* Clear Intmask */ 191 SPIPCI_WREG(osh, ®s->spih_hex_disp, 0x0000DEAF); 192 SPIPCI_WREG(osh, ®s->spih_int_edge, 0x00000000); 193 SPIPCI_WREG(osh, ®s->spih_int_pol, 0x00000000); 194 SPIPCI_WREG(osh, ®s->spih_hex_disp, 0x0000DEAD); 195 196 /* Disable interrupts through PCI Core. */ 197 if (si->pciregs) { 198 SPIPCI_WREG(osh, &pciregs->ICR, 0x00000000); 199 spi_reg_unmap(osh, (uintptr)pciregs, sizeof(spih_pciregs_t)); 200 } 201 spi_reg_unmap(osh, (uintptr)regs, sizeof(spih_regs_t)); 202 203 MFREE(osh, si, sizeof(spih_info_t)); 204 205 sd->controller = NULL; 206 207 sd_trace(("%s: exit\n", __FUNCTION__)); 208 return TRUE; 209 } 210 211 /* Switch between internal (PCI) and external clock oscillator */ 212 static bool 213 sdspi_switch_clock(sdioh_info_t *sd, bool ext_clk) 214 { 215 spih_info_t *si = (spih_info_t *)sd->controller; 216 osl_t *osh = si->osh; 217 spih_regs_t *regs = si->regs; 218 219 /* Switch to desired clock, and reset the PLL. */ 220 SPIPCI_WREG(osh, ®s->spih_pll_ctrl, ext_clk ? SPIH_EXT_CLK : 0); 221 222 SPINWAIT(((SPIPCI_RREG(osh, ®s->spih_pll_status) & SPIH_PLL_LOCKED) 223 != SPIH_PLL_LOCKED), 1000); 224 if ((SPIPCI_RREG(osh, ®s->spih_pll_status) & SPIH_PLL_LOCKED) != SPIH_PLL_LOCKED) { 225 sd_err(("%s: timeout waiting for PLL to lock\n", __FUNCTION__)); 226 return (FALSE); 227 } 228 return (TRUE); 229 230 } 231 232 /* Configure PCI-SPI Host Controller's SPI Clock rate as a divisor into the 233 * base clock rate. The base clock is either the PCI Clock (33MHz) or the 234 * external clock oscillator at U17 on the PciSpiHost. 235 */ 236 bool 237 spi_start_clock(sdioh_info_t *sd, uint16 div) 238 { 239 spih_info_t *si = (spih_info_t *)sd->controller; 240 osl_t *osh = si->osh; 241 spih_regs_t *regs = si->regs; 242 uint32 t, espr, disp; 243 uint32 disp_xtal_freq; 244 bool ext_clock = FALSE; 245 char disp_string[5]; 246 247 if (div > 2048) { 248 sd_err(("%s: divisor %d too large; using max of 2048\n", __FUNCTION__, div)); 249 div = 2048; 250 } else if (div & (div - 1)) { /* Not a power of 2? */ 251 /* Round up to a power of 2 */ 252 while ((div + 1) & div) 253 div |= div >> 1; 254 div++; 255 } 256 257 /* For FPGA Rev >= 5, the use of an external clock oscillator is supported. 258 * If the oscillator is populated, use it to provide the SPI base clock, 259 * otherwise, default to the PCI clock as the SPI base clock. 260 */ 261 if (si->rev >= 5) { 262 uint32 clk_tick; 263 /* Enable the External Clock Oscillator as PLL clock source. */ 264 if (!sdspi_switch_clock(sd, TRUE)) { 265 sd_err(("%s: error switching to external clock\n", __FUNCTION__)); 266 } 267 268 /* Check to make sure the external clock is running. If not, then it 269 * is not populated on the card, so we will default to the PCI clock. 270 */ 271 clk_tick = SPIPCI_RREG(osh, ®s->spih_clk_count); 272 if (clk_tick == SPIPCI_RREG(osh, ®s->spih_clk_count)) { 273 274 /* Switch back to the PCI clock as the clock source. */ 275 if (!sdspi_switch_clock(sd, FALSE)) { 276 sd_err(("%s: error switching to external clock\n", __FUNCTION__)); 277 } 278 } else { 279 ext_clock = TRUE; 280 } 281 } 282 283 /* Hack to allow hot-swapping oscillators: 284 * 1. Force PCI clock as clock source, using sd_divisor of 0. 285 * 2. Swap oscillator 286 * 3. Set desired sd_divisor (will switch to external oscillator as clock source. 287 */ 288 if (div == 0) { 289 ext_clock = FALSE; 290 div = 2; 291 292 /* Select PCI clock as the clock source. */ 293 if (!sdspi_switch_clock(sd, FALSE)) { 294 sd_err(("%s: error switching to external clock\n", __FUNCTION__)); 295 } 296 297 sd_err(("%s: Ok to hot-swap oscillators.\n", __FUNCTION__)); 298 } 299 300 /* If using the external oscillator, read the clock frequency from the controller 301 * The value read is in units of 10000Hz, and it's not a nice round number because 302 * it is calculated by the FPGA. So to make up for that, we round it off. 303 */ 304 if (ext_clock == TRUE) { 305 uint32 xtal_freq; 306 307 OSL_DELAY(1000); 308 xtal_freq = SPIPCI_RREG(osh, ®s->spih_xtal_freq) * 10000; 309 310 sd_info(("%s: Oscillator is %dHz\n", __FUNCTION__, xtal_freq)); 311 312 313 disp_xtal_freq = xtal_freq / 10000; 314 315 /* Round it off to a nice number. */ 316 if ((disp_xtal_freq % 100) > 50) { 317 disp_xtal_freq += 100; 318 } 319 320 disp_xtal_freq = (disp_xtal_freq / 100) * 100; 321 } else { 322 sd_err(("%s: no external oscillator installed, using PCI clock.\n", __FUNCTION__)); 323 disp_xtal_freq = 3333; 324 } 325 326 /* Convert the SPI Clock frequency to BCD format. */ 327 sprintf(disp_string, "%04d", disp_xtal_freq / div); 328 329 disp = (disp_string[0] - '0') << 12; 330 disp |= (disp_string[1] - '0') << 8; 331 disp |= (disp_string[2] - '0') << 4; 332 disp |= (disp_string[3] - '0'); 333 334 /* Select the correct ESPR register value based on the divisor. */ 335 switch (div) { 336 case 1: espr = 0x0; break; 337 case 2: espr = 0x1; break; 338 case 4: espr = 0x2; break; 339 case 8: espr = 0x5; break; 340 case 16: espr = 0x3; break; 341 case 32: espr = 0x4; break; 342 case 64: espr = 0x6; break; 343 case 128: espr = 0x7; break; 344 case 256: espr = 0x8; break; 345 case 512: espr = 0x9; break; 346 case 1024: espr = 0xa; break; 347 case 2048: espr = 0xb; break; 348 default: espr = 0x0; ASSERT(0); break; 349 } 350 351 t = SPIPCI_RREG(osh, ®s->spih_ctrl); 352 t &= ~3; 353 t |= espr & 3; 354 SPIPCI_WREG(osh, ®s->spih_ctrl, t); 355 356 t = SPIPCI_RREG(osh, ®s->spih_ext); 357 t &= ~3; 358 t |= (espr >> 2) & 3; 359 SPIPCI_WREG(osh, ®s->spih_ext, t); 360 361 SPIPCI_WREG(osh, ®s->spih_hex_disp, disp); 362 363 /* For Rev 8, writing to the PLL_CTRL register resets 364 * the PLL, and it can re-acquire in 200uS. For 365 * Rev 7 and older, we use a software delay to allow 366 * the PLL to re-acquire, which takes more than 2mS. 367 */ 368 if (si->rev < 8) { 369 /* Wait for clock to settle. */ 370 OSL_DELAY(5000); 371 } 372 373 sd_info(("%s: SPI_CTRL=0x%08x SPI_EXT=0x%08x\n", 374 __FUNCTION__, 375 SPIPCI_RREG(osh, ®s->spih_ctrl), 376 SPIPCI_RREG(osh, ®s->spih_ext))); 377 378 return TRUE; 379 } 380 381 /* Configure PCI-SPI Host Controller High-Speed Clocking mode setting */ 382 bool 383 spi_controller_highspeed_mode(sdioh_info_t *sd, bool hsmode) 384 { 385 spih_info_t *si = (spih_info_t *)sd->controller; 386 osl_t *osh = si->osh; 387 spih_regs_t *regs = si->regs; 388 389 if (si->rev >= 10) { 390 if (hsmode) { 391 SPIPCI_ORREG(osh, ®s->spih_ext, 0x10); 392 } else { 393 SPIPCI_ANDREG(osh, ®s->spih_ext, ~0x10); 394 } 395 } 396 397 return TRUE; 398 } 399 400 /* Disable device interrupt */ 401 void 402 spi_devintr_off(sdioh_info_t *sd) 403 { 404 spih_info_t *si = (spih_info_t *)sd->controller; 405 osl_t *osh = si->osh; 406 spih_regs_t *regs = si->regs; 407 408 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); 409 if (sd->use_client_ints) { 410 sd->intmask &= ~SPIH_DEV_INTR; 411 SPIPCI_WREG(osh, ®s->spih_int_mask, sd->intmask); /* Clear Intmask */ 412 } 413 } 414 415 /* Enable device interrupt */ 416 void 417 spi_devintr_on(sdioh_info_t *sd) 418 { 419 spih_info_t *si = (spih_info_t *)sd->controller; 420 osl_t *osh = si->osh; 421 spih_regs_t *regs = si->regs; 422 423 ASSERT(sd->lockcount == 0); 424 sd_trace(("%s: %d\n", __FUNCTION__, sd->use_client_ints)); 425 if (sd->use_client_ints) { 426 if (SPIPCI_RREG(osh, ®s->spih_ctrl) & 0x02) { 427 /* Ack in case one was pending but is no longer... */ 428 SPIPCI_WREG(osh, ®s->spih_int_status, SPIH_DEV_INTR); 429 } 430 sd->intmask |= SPIH_DEV_INTR; 431 /* Set device intr in Intmask */ 432 SPIPCI_WREG(osh, ®s->spih_int_mask, sd->intmask); 433 } 434 } 435 436 /* Check to see if an interrupt belongs to the PCI-SPI Host or a SPI Device */ 437 bool 438 spi_check_client_intr(sdioh_info_t *sd, int *is_dev_intr) 439 { 440 spih_info_t *si = (spih_info_t *)sd->controller; 441 osl_t *osh = si->osh; 442 spih_regs_t *regs = si->regs; 443 bool ours = FALSE; 444 445 uint32 raw_int, cur_int; 446 ASSERT(sd); 447 448 if (is_dev_intr) 449 *is_dev_intr = FALSE; 450 raw_int = SPIPCI_RREG(osh, ®s->spih_int_status); 451 cur_int = raw_int & sd->intmask; 452 if (cur_int & SPIH_DEV_INTR) { 453 if (sd->client_intr_enabled && sd->use_client_ints) { 454 sd->intrcount++; 455 ASSERT(sd->intr_handler); 456 ASSERT(sd->intr_handler_arg); 457 (sd->intr_handler)(sd->intr_handler_arg); 458 if (is_dev_intr) 459 *is_dev_intr = TRUE; 460 } else { 461 sd_trace(("%s: Not ready for intr: enabled %d, handler 0x%p\n", 462 __FUNCTION__, sd->client_intr_enabled, sd->intr_handler)); 463 } 464 SPIPCI_WREG(osh, ®s->spih_int_status, SPIH_DEV_INTR); 465 SPIPCI_RREG(osh, ®s->spih_int_status); 466 ours = TRUE; 467 } else if (cur_int & SPIH_CTLR_INTR) { 468 /* Interrupt is from SPI FIFO... just clear and ack it... */ 469 sd_trace(("%s: SPI CTLR interrupt: raw_int 0x%08x cur_int 0x%08x\n", 470 __FUNCTION__, raw_int, cur_int)); 471 472 /* Clear the interrupt in the SPI_STAT register */ 473 SPIPCI_WREG(osh, ®s->spih_stat, 0x00000080); 474 475 /* Ack the interrupt in the interrupt controller */ 476 SPIPCI_WREG(osh, ®s->spih_int_status, SPIH_CTLR_INTR); 477 SPIPCI_RREG(osh, ®s->spih_int_status); 478 479 ours = TRUE; 480 } else if (cur_int & SPIH_WFIFO_INTR) { 481 sd_trace(("%s: SPI WR FIFO Empty interrupt: raw_int 0x%08x cur_int 0x%08x\n", 482 __FUNCTION__, raw_int, cur_int)); 483 484 /* Disable the FIFO Empty Interrupt */ 485 sd->intmask &= ~SPIH_WFIFO_INTR; 486 SPIPCI_WREG(osh, ®s->spih_int_mask, sd->intmask); 487 488 sd->local_intrcount++; 489 sd->got_hcint = TRUE; 490 ours = TRUE; 491 } else { 492 /* Not an error: can share interrupts... */ 493 sd_trace(("%s: Not my interrupt: raw_int 0x%08x cur_int 0x%08x\n", 494 __FUNCTION__, raw_int, cur_int)); 495 ours = FALSE; 496 } 497 498 return ours; 499 } 500 501 static void 502 hexdump(char *pfx, unsigned char *msg, int msglen) 503 { 504 int i, col; 505 char buf[80]; 506 507 ASSERT(strlen(pfx) + 49 <= sizeof(buf)); 508 509 col = 0; 510 511 for (i = 0; i < msglen; i++, col++) { 512 if (col % 16 == 0) 513 strcpy(buf, pfx); 514 sprintf(buf + strlen(buf), "%02x", msg[i]); 515 if ((col + 1) % 16 == 0) 516 printf("%s\n", buf); 517 else 518 sprintf(buf + strlen(buf), " "); 519 } 520 521 if (col % 16 != 0) 522 printf("%s\n", buf); 523 } 524 525 /* Send/Receive an SPI Packet */ 526 void 527 spi_sendrecv(sdioh_info_t *sd, uint8 *msg_out, uint8 *msg_in, int msglen) 528 { 529 spih_info_t *si = (spih_info_t *)sd->controller; 530 osl_t *osh = si->osh; 531 spih_regs_t *regs = si->regs; 532 uint32 count; 533 uint32 spi_data_out; 534 uint32 spi_data_in; 535 bool yield; 536 537 sd_trace(("%s: enter\n", __FUNCTION__)); 538 539 if (bcmpcispi_dump) { 540 printf("SENDRECV(len=%d)\n", msglen); 541 hexdump(" OUT: ", msg_out, msglen); 542 } 543 544 #ifdef BCMSDYIELD 545 /* Only yield the CPU and wait for interrupt on Rev 8 and newer FPGA images. */ 546 yield = ((msglen > 500) && (si->rev >= 8)); 547 #else 548 yield = FALSE; 549 #endif /* BCMSDYIELD */ 550 551 ASSERT(msglen % 4 == 0); 552 553 554 SPIPCI_ANDREG(osh, ®s->spih_gpio_data, ~SPIH_CS); /* Set GPIO CS# Low (asserted) */ 555 556 for (count = 0; count < (uint32)msglen/4; count++) { 557 spi_data_out = ((uint32)((uint32 *)msg_out)[count]); 558 SPIPCI_WREG(osh, ®s->spih_data, spi_data_out); 559 } 560 561 #ifdef BCMSDYIELD 562 if (yield) { 563 /* Ack the interrupt in the interrupt controller */ 564 SPIPCI_WREG(osh, ®s->spih_int_status, SPIH_WFIFO_INTR); 565 SPIPCI_RREG(osh, ®s->spih_int_status); 566 567 /* Enable the FIFO Empty Interrupt */ 568 sd->intmask |= SPIH_WFIFO_INTR; 569 sd->got_hcint = FALSE; 570 SPIPCI_WREG(osh, ®s->spih_int_mask, sd->intmask); 571 572 } 573 #endif /* BCMSDYIELD */ 574 575 /* Wait for write fifo to empty... */ 576 SPIPCI_ANDREG(osh, ®s->spih_gpio_data, ~0x00000020); /* Set GPIO 5 Low */ 577 578 if (yield) { 579 ASSERT((SPIPCI_RREG(sd->osh, ®s->spih_stat) & SPIH_WFEMPTY) == 0); 580 } 581 582 spi_waitbits(sd, yield); 583 SPIPCI_ORREG(osh, ®s->spih_gpio_data, 0x00000020); /* Set GPIO 5 High (de-asserted) */ 584 585 for (count = 0; count < (uint32)msglen/4; count++) { 586 spi_data_in = SPIPCI_RREG(osh, ®s->spih_data); 587 ((uint32 *)msg_in)[count] = spi_data_in; 588 } 589 590 /* Set GPIO CS# High (de-asserted) */ 591 SPIPCI_ORREG(osh, ®s->spih_gpio_data, SPIH_CS); 592 593 if (bcmpcispi_dump) { 594 hexdump(" IN : ", msg_in, msglen); 595 } 596 } 597 598 void 599 spi_spinbits(sdioh_info_t *sd) 600 { 601 spih_info_t *si = (spih_info_t *)sd->controller; 602 osl_t *osh = si->osh; 603 spih_regs_t *regs = si->regs; 604 uint spin_count; /* Spin loop bound check */ 605 606 spin_count = 0; 607 while ((SPIPCI_RREG(sd->osh, ®s->spih_stat) & SPIH_WFEMPTY) == 0) { 608 if (spin_count > SPI_SPIN_BOUND) { 609 sd_err(("%s: SPIH_WFEMPTY spin bits out of bound %u times \n", 610 __FUNCTION__, spin_count)); 611 ASSERT(FALSE); 612 } 613 spin_count++; 614 } 615 616 /* Wait for SPI Transfer state machine to return to IDLE state. 617 * The state bits are only implemented in Rev >= 5 FPGA. These 618 * bits are hardwired to 00 for Rev < 5, so this check doesn't cause 619 * any problems. 620 */ 621 spin_count = 0; 622 while ((SPIPCI_RREG(osh, ®s->spih_stat) & SPIH_STATE_MASK) != 0) { 623 if (spin_count > SPI_SPIN_BOUND) { 624 sd_err(("%s: SPIH_STATE_MASK spin bits out of bound %u times \n", 625 __FUNCTION__, spin_count)); 626 ASSERT(FALSE); 627 } 628 spin_count++; 629 } 630 } 631