OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / hardware / broadcom / wlan / bcm4329 / src / bcmsdio / sys / bcmpcispi.c
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, &regs->spih_ctrl, 0x00000010);
189         SPIPCI_WREG(osh, &regs->spih_gpio_ctrl, 0x00000000);    /* Disable GPIO for CS# */
190         SPIPCI_WREG(osh, &regs->spih_int_mask, 0x00000000);     /* Clear Intmask */
191         SPIPCI_WREG(osh, &regs->spih_hex_disp, 0x0000DEAF);
192         SPIPCI_WREG(osh, &regs->spih_int_edge, 0x00000000);
193         SPIPCI_WREG(osh, &regs->spih_int_pol, 0x00000000);
194         SPIPCI_WREG(osh, &regs->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, &regs->spih_pll_ctrl, ext_clk ? SPIH_EXT_CLK : 0);
221
222         SPINWAIT(((SPIPCI_RREG(osh, &regs->spih_pll_status) & SPIH_PLL_LOCKED)
223                   != SPIH_PLL_LOCKED), 1000);
224         if ((SPIPCI_RREG(osh, &regs->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, &regs->spih_clk_count);
272                 if (clk_tick == SPIPCI_RREG(osh, &regs->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, &regs->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, &regs->spih_ctrl);
352         t &= ~3;
353         t |= espr & 3;
354         SPIPCI_WREG(osh, &regs->spih_ctrl, t);
355
356         t = SPIPCI_RREG(osh, &regs->spih_ext);
357         t &= ~3;
358         t |= (espr >> 2) & 3;
359         SPIPCI_WREG(osh, &regs->spih_ext, t);
360
361         SPIPCI_WREG(osh, &regs->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, &regs->spih_ctrl),
376                  SPIPCI_RREG(osh, &regs->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, &regs->spih_ext, 0x10);
392                 } else {
393                         SPIPCI_ANDREG(osh, &regs->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, &regs->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, &regs->spih_ctrl) & 0x02) {
427                         /* Ack in case one was pending but is no longer... */
428                         SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_DEV_INTR);
429                 }
430                 sd->intmask |= SPIH_DEV_INTR;
431                 /* Set device intr in Intmask */
432                 SPIPCI_WREG(osh, &regs->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, &regs->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, &regs->spih_int_status, SPIH_DEV_INTR);
465                 SPIPCI_RREG(osh, &regs->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, &regs->spih_stat, 0x00000080);
474
475                 /* Ack the interrupt in the interrupt controller */
476                 SPIPCI_WREG(osh, &regs->spih_int_status, SPIH_CTLR_INTR);
477                 SPIPCI_RREG(osh, &regs->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, &regs->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, &regs->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, &regs->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, &regs->spih_int_status, SPIH_WFIFO_INTR);
565                 SPIPCI_RREG(osh, &regs->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, &regs->spih_int_mask, sd->intmask);
571
572         }
573 #endif /* BCMSDYIELD */
574
575         /* Wait for write fifo to empty... */
576         SPIPCI_ANDREG(osh, &regs->spih_gpio_data, ~0x00000020); /* Set GPIO 5 Low */
577
578         if (yield) {
579                 ASSERT((SPIPCI_RREG(sd->osh, &regs->spih_stat) & SPIH_WFEMPTY) == 0);
580         }
581
582         spi_waitbits(sd, yield);
583         SPIPCI_ORREG(osh, &regs->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, &regs->spih_data);
587                 ((uint32 *)msg_in)[count] = spi_data_in;
588         }
589
590         /* Set GPIO CS# High (de-asserted) */
591         SPIPCI_ORREG(osh, &regs->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, &regs->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, &regs->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 }