1 /*
2 * Copyright (c) 2016-2019, Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <stdint.h>
34 #include <stdbool.h>
35 /*
36 * By default disable both asserts and log for this module.
37 * This must be done before DebugP.h is included.
38 */
39 #ifndef DebugP_ASSERT_ENABLED
40 #define DebugP_ASSERT_ENABLED 0
41 #endif
42 #ifndef DebugP_LOG_ENABLED
43 #define DebugP_LOG_ENABLED 0
44 #endif
45
46 #include <ti/drivers/dpl/DebugP.h>
47 #include <ti/drivers/dpl/HwiP.h>
48 #include <ti/drivers/dpl/SemaphoreP.h>
49 #include <ti/drivers/Power.h>
50 #include <ti/drivers/power/PowerCC32XX.h>
51 #include <ti/drivers/sd/SDHostCC32XX.h>
52 #include <ti/drivers/dma/UDMACC32XX.h>
53
54 /* Driverlib header files */
55 #include <ti/devices/cc32xx/inc/hw_common_reg.h>
56 #include <ti/devices/cc32xx/inc/hw_types.h>
57 #include <ti/devices/cc32xx/inc/hw_memmap.h>
58 #include <ti/devices/cc32xx/inc/hw_ocp_shared.h>
59 #include <ti/devices/cc32xx/inc/hw_ints.h>
60 #include <ti/devices/cc32xx/inc/hw_mmchs.h>
61 #include <ti/devices/cc32xx/inc/hw_udma.h>
62 #include <ti/devices/cc32xx/driverlib/rom.h>
63 #include <ti/devices/cc32xx/driverlib/rom_map.h>
64 #include <ti/devices/cc32xx/driverlib/pin.h>
65 #include <ti/devices/cc32xx/driverlib/prcm.h>
66 #include <ti/devices/cc32xx/driverlib/sdhost.h>
67 #include <ti/devices/cc32xx/driverlib/udma.h>
68
69 #define PinConfigPinMode(config) (((config) >> 8) & 0xF)
70 #define PinConfigPin(config) (((config) >> 0) & 0x3F)
71
72 #define PAD_CONFIG_BASE (OCP_SHARED_BASE + OCP_SHARED_O_GPIO_PAD_CONFIG_0)
73 #define PAD_RESET_STATE 0xC61
74
75 /* Definitions for SDC driverlib commands */
76 #define CMD_GO_IDLE_STATE (SDHOST_CMD_0)
77 #define CMD_SEND_OP_COND (SDHOST_CMD_1 | SDHOST_RESP_LEN_48)
78 #define CMD_ALL_SEND_CID (SDHOST_CMD_2 | SDHOST_RESP_LEN_136)
79 #define CMD_SEND_REL_ADDR (SDHOST_CMD_3 | SDHOST_RESP_LEN_48)
80 #define CMD_SELECT_CARD (SDHOST_CMD_7 | SDHOST_RESP_LEN_48B)
81 #define CMD_DESELECT_CARD (SDHOST_CMD_7)
82 #define CMD_SEND_IF_COND (SDHOST_CMD_8 | SDHOST_RESP_LEN_48)
83 #define CMD_SEND_CSD (SDHOST_CMD_9 | SDHOST_RESP_LEN_136)
84 #define CMD_STOP_TRANS (SDHOST_CMD_12 | SDHOST_RESP_LEN_48B)
85 #define CMD_READ_SINGLE_BLK (SDHOST_CMD_17 | SDHOST_RD_CMD | SDHOST_RESP_LEN_48)
86 #define CMD_READ_MULTI_BLK (SDHOST_CMD_18 | SDHOST_RD_CMD | \
87 SDHOST_RESP_LEN_48 | SDHOST_MULTI_BLK)
88 #define CMD_SET_BLK_CNT (SDHOST_CMD_23 | SDHOST_RESP_LEN_48)
89 #define CMD_WRITE_SINGLE_BLK (SDHOST_CMD_24 | SDHOST_WR_CMD | SDHOST_RESP_LEN_48)
90 #define CMD_WRITE_MULTI_BLK (SDHOST_CMD_25 | SDHOST_WR_CMD | \
91 SDHOST_RESP_LEN_48 | SDHOST_MULTI_BLK)
92 #define CMD_SD_SEND_OP_COND (SDHOST_CMD_41 | SDHOST_RESP_LEN_48)
93 #define CMD_APP_CMD (SDHOST_CMD_55 | SDHOST_RESP_LEN_48)
94
95 /* Group of all possible SD command and data error flags */
96 #define CMDERROR (SDHOST_INT_CTO | SDHOST_INT_CEB)
97
98 #define DATAERROR (SDHOST_INT_DTO | SDHOST_INT_DCRC | \
99 SDHOST_INT_DEB | SDHOST_INT_CERR | \
100 SDHOST_INT_BADA)
101
102 #define SECTORSIZE (512)
103
104 /* Voltage window (VDD) used on this device (3.3-3.6 V) */
105 #define VOLTAGEWINDOW (0x00E00000)
106
107 /* Bit set to indicate the host controller has high capacity support */
108 #define HIGHCAPSUPPORT (0x40000000)
109
110 /* Voltage supplied 2.7-3.6V */
111 #define SUPPLYVOLTAGE (0x00000100)
112
113 /* Checksum to validate SD command responses */
114 #define CHECKSUM (0xA5)
115
116 /* Setup the UDMA controller to either read or write to the SDHost buffer */
117 #define UDMAWRITE (0x01)
118
119 #define UDMAREAD (0x00)
120
121 /* Define used for commands that do not require an argument */
122 #define NULLARG (0x00)
123
124 /* SDHostCC32XX configuration - initialized in the board file */
125 extern const SD_Config SD_config[];
126
127 /* SDHostCC32XX functions */
128 void SDHostCC32XX_close(SD_Handle handle);
129 int_fast16_t SDHostCC32XX_control(SD_Handle handle, uint_fast16_t cmd,
130 void *arg);
131 uint_fast32_t SDHostCC32XX_getNumSectors(SD_Handle handle);
132 uint_fast32_t SDHostCC32XX_getSectorSize(SD_Handle handle);
133 int_fast16_t SDHostCC32XX_initialize(SD_Handle handle);
134 void SDHostCC32XX_init(SD_Handle handle);
135 SD_Handle SDHostCC32XX_open(SD_Handle handle, SD_Params *params);
136 int_fast16_t SDHostCC32XX_read(SD_Handle handle, void *buf,
137 int_fast32_t sector, uint_fast32_t secCount);
138 int_fast16_t SDHostCC32XX_write(SD_Handle handle, const void *buf,
139 int_fast32_t sector, uint_fast32_t secCount);
140
141 /* Local Functions */
142 static inline void configDMAChannel(SD_Handle handle, uint_fast32_t channelSel,
143 uint_fast32_t operation);
144 static int_fast32_t deSelectCard(SD_Handle handle);
145 static uint_fast32_t getPowerMgrId(uint_fast32_t baseAddr);
146 static void hwiIntFxn(uintptr_t handle);
147 static void initHw(SD_Handle handle);
148 static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
149 uintptr_t clientArg);
150 static int_fast32_t send_cmd(SD_Handle handle, uint_fast32_t cmd,
151 uint_fast32_t arg);
152 static int_fast32_t selectCard(SD_Handle handle);
153
154 /* SDHostCC32XX function table for SDSPICC32XX implementation */
155 const SD_FxnTable sdHostCC32XX_fxnTable = {
156 SDHostCC32XX_close,
157 SDHostCC32XX_control,
158 SDHostCC32XX_getNumSectors,
159 SDHostCC32XX_getSectorSize,
160 SDHostCC32XX_init,
161 SDHostCC32XX_initialize,
162 SDHostCC32XX_open,
163 SDHostCC32XX_read,
164 SDHostCC32XX_write
165 };
166
167 /*
168 * ======== SDHostCC32XX_close ========
169 */
SDHostCC32XX_close(SD_Handle handle)170 void SDHostCC32XX_close(SD_Handle handle)
171 {
172 SDHostCC32XX_Object *object = handle->object;
173 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
174 uint32_t padRegister;
175
176 if (object->cardType != SD_NOCARD) {
177 /* De-select the SD Card, move back to standby state */
178 if (deSelectCard(handle) != SD_STATUS_SUCCESS) {
179 DebugP_log1("SDHost:(%p) Failed to de-select SD Card",
180 hwAttrs->baseAddr);
181 }
182 }
183
184 /* Disable SD Host interrupts */
185 MAP_SDHostIntDisable(hwAttrs->baseAddr, DATAERROR | CMDERROR);
186
187 if (object->dmaHandle) {
188 UDMACC32XX_close(object->dmaHandle);
189 }
190 if (object->cmdSem) {
191 SemaphoreP_delete(object->cmdSem);
192 }
193 if (object->hwiHandle) {
194 HwiP_delete(object->hwiHandle);
195 }
196
197 /* Remove Power driver settings */
198 if (object->clkPin != (uint16_t)-1) {
199 PowerCC32XX_restoreParkState((PowerCC32XX_Pin)object->clkPin,
200 object->prevParkCLK);
201 object->clkPin = (uint16_t)-1;
202 }
203 Power_unregisterNotify(&object->postNotify);
204 Power_releaseDependency(object->powerMgrId);
205
206 /* Restore pin pads to their reset states */
207 padRegister = (PinToPadGet((hwAttrs->dataPin) & 0x3f)<<2) + PAD_CONFIG_BASE;
208 HWREG(padRegister) = PAD_RESET_STATE;
209 padRegister = (PinToPadGet((hwAttrs->cmdPin) & 0x3f)<<2) + PAD_CONFIG_BASE;
210 HWREG(padRegister) = PAD_RESET_STATE;
211 padRegister = (PinToPadGet((hwAttrs->clkPin) & 0x3f)<<2) + PAD_CONFIG_BASE;
212 HWREG(padRegister) = PAD_RESET_STATE;
213
214 object->isOpen = false;
215
216 DebugP_log1("SDHost:(%p) closed and released power dependency",
217 hwAttrs->baseAddr);
218 }
219
220 /*
221 * ======== SDHostCC32XX_control ========
222 * @pre Function assumes that the handle is not NULL.
223 */
SDHostCC32XX_control(SD_Handle handle,uint_fast32_t cmd,void * arg)224 int_fast16_t SDHostCC32XX_control(SD_Handle handle, uint_fast32_t cmd,
225 void *arg)
226 {
227 /* No implementation yet */
228 return (SD_STATUS_UNDEFINEDCMD);
229 }
230
231 /*
232 * ======== SDHostCC32XX_getNumSectors ========
233 * Function to read the CSD register of the SD card on the drive specified
234 * by the SD_Handle and calculate the total card capacity in sectors.
235 */
SDHostCC32XX_getNumSectors(SD_Handle handle)236 uint_fast32_t SDHostCC32XX_getNumSectors(SD_Handle handle)
237 {
238 uint_fast32_t sectors = 0;
239 uint_fast32_t cSize; /* Device size */
240 uint_fast32_t blockSize; /* Read block length */
241 uint_fast32_t sizeMult;
242 uint_fast32_t resp[4];
243 SDHostCC32XX_Object *object = handle->object;
244 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
245
246 Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
247 DebugP_log1("SDHost:(%p) SDHostCC32XX_getNumSectors set command"
248 " power constraint", hwAttrs->baseAddr);
249
250 /* De-Select the card on the input drive(Stand-by state) */
251 if (deSelectCard(handle) != SD_STATUS_SUCCESS) {
252 Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
253 DebugP_log1("SDHost:(%p) SDHostCC32XX_getNumSectors released command"
254 " power constraint", hwAttrs->baseAddr);
255 return (0);
256 }
257
258 if (send_cmd(handle, CMD_SEND_CSD, (object->rca << 16)) ==
259 SD_STATUS_SUCCESS) {
260
261 MAP_SDHostRespGet(hwAttrs->baseAddr, (unsigned long *)resp);
262
263 /*
264 * 136 bit CSD register is read into an array of 4 words
265 * Note: Does not include 8 bit CRC
266 * resp[0] = CSD[31:0]
267 * resp[1] = CSD[63:32]
268 * resp[2] = CSD[95:64]
269 * resp[3] = CSD[127:96]
270 */
271 if(((resp[3] >> 30) & 0x01) == 1) {
272 sectors = (resp[1] >> 16 | ((resp[2] & 0x3F) << 16)) + 1;
273 sectors *= 1024;
274 }
275 else {
276 blockSize = 1 << ((resp[2] >> 16) & 0x0F);
277 sizeMult = ((resp[1] >> 15) & 0x07);
278 cSize = ((resp[1] >> 30) | (resp[2] & 0x3FF) << 2);
279 sectors = (cSize + 1) * (1 << (sizeMult + 2));
280 sectors = (sectors * blockSize) / SECTORSIZE;
281
282 }
283 }
284
285 /* Select the card on the input drive(Transfer state) */
286 if (selectCard(handle) != SD_STATUS_SUCCESS) {
287 sectors = 0;
288 }
289
290 Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
291 DebugP_log1("SDHost:(%p) SDHostCC32XX_getNumSectors released command"
292 " power constraint", hwAttrs->baseAddr);
293
294 return (sectors);
295 }
296
297 /*
298 * ======== SDHostCC32XX_getSectorSize ========
299 * Function to perform a disk read from the SD Card on the specifed drive.
300 */
SDHostCC32XX_getSectorSize(SD_Handle handle)301 uint_fast32_t SDHostCC32XX_getSectorSize(SD_Handle handle)
302 {
303 return (SECTORSIZE);
304 }
305
306 /*
307 * ======== SDHostCC32XX_initialize ========
308 * Function to initialize the SD Card.
309 */
SDHostCC32XX_initialize(SD_Handle handle)310 int_fast16_t SDHostCC32XX_initialize(SD_Handle handle)
311 {
312 int_fast32_t result;
313 uint_fast32_t resp[4];
314 SDHostCC32XX_Object *object = handle->object;
315 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
316
317 Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
318 DebugP_log1("SDHost:(%p) SDHostCC32XX_initialize set read/write"
319 " power constraint", hwAttrs->baseAddr);
320
321 /* Send go to IDLE command */
322 result = send_cmd(handle, CMD_GO_IDLE_STATE, NULLARG);
323
324 if (result == SD_STATUS_SUCCESS) {
325 /* Get interface operating condition for the card */
326 result = send_cmd(handle, CMD_SEND_IF_COND,
327 SUPPLYVOLTAGE | CHECKSUM);
328 /* Verify response will be valid */
329 if (result == SD_STATUS_SUCCESS) {
330 MAP_SDHostRespGet(hwAttrs->baseAddr, (unsigned long *)resp);
331 }
332 }
333
334 /* SD ver 2.0 or higher card */
335 if ((result == SD_STATUS_SUCCESS) && ((resp[0] & 0xFF) ==
336 CHECKSUM)) {
337 object->cardType = SD_SDSC;
338
339 /* Wait for card to be ready */
340 do {
341 /* Send ACMD41 */
342 result = send_cmd(handle, CMD_APP_CMD, NULLARG);
343
344 if (result == SD_STATUS_SUCCESS) {
345 result = send_cmd(handle, CMD_SD_SEND_OP_COND,
346 HIGHCAPSUPPORT | VOLTAGEWINDOW);
347 /* Response contains 32-bit OCR register */
348 MAP_SDHostRespGet(hwAttrs->baseAddr, (unsigned long *)resp);
349 }
350
351 /* Wait until card is ready, spool on busy bit */
352 } while((result == SD_STATUS_SUCCESS) && ((resp[0] >> 31) == 0));
353
354 /* Card capacity status bit */
355 if ((result == SD_STATUS_SUCCESS) && (resp[0] & (1UL << 30))) {
356 object->cardType = SD_SDHC;
357 }
358 }
359 /* It's a MMC or SD 1.x card */
360 else {
361 /* Wait for card to be ready */
362 do {
363 /* Send ACMD41 */
364 result = send_cmd(handle, CMD_APP_CMD, NULLARG);
365
366 if (result == SD_STATUS_SUCCESS) {
367 result = send_cmd(handle, CMD_SD_SEND_OP_COND, VOLTAGEWINDOW);
368 }
369
370 if (result == SD_STATUS_SUCCESS) {
371 /* Response contains 32-bit OCR register */
372 MAP_SDHostRespGet(hwAttrs->baseAddr, (unsigned long *)resp);
373 }
374
375 /* Wait until card is ready, spool on busy bit */
376 } while((result == SD_STATUS_SUCCESS) && ((resp[0] >> 31) == 0));
377
378 if (result == SD_STATUS_SUCCESS) {
379 object->cardType = SD_SDSC;
380 }
381 else if (send_cmd(handle, CMD_SEND_OP_COND, NULLARG) ==
382 SD_STATUS_SUCCESS) {
383 object->cardType = SD_MMC;
384 }
385 /* No command responses */
386 else {
387 object->cardType = SD_NOCARD;
388 }
389 }
390
391 /* Get the relative card address (RCA) of the attached card */
392 if (object->cardType != SD_NOCARD) {
393 result = send_cmd(handle, CMD_ALL_SEND_CID, NULLARG);
394
395 if (result == SD_STATUS_SUCCESS) {
396 result = send_cmd(handle, CMD_SEND_REL_ADDR, NULLARG);
397 }
398
399 if (result == SD_STATUS_SUCCESS) {
400 /* Fill in the RCA */
401 MAP_SDHostRespGet(hwAttrs->baseAddr, (unsigned long *)resp);
402
403 object->rca = resp[0] >> 16;
404
405 /* Select the card on the input drive(Transfer state) */
406 result = selectCard(handle);
407 if (result == SD_STATUS_SUCCESS) {
408 /* Set card read/write block length */
409 MAP_SDHostBlockSizeSet(hwAttrs->baseAddr, SECTORSIZE);
410
411 /* Initialization succeeded */
412 result = SD_STATUS_SUCCESS;
413 }
414 }
415 }
416 else {
417 DebugP_log1("SDHost:(%p) Could not select card",
418 hwAttrs->baseAddr);
419 result = SD_STATUS_ERROR;
420 }
421
422 Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
423 DebugP_log1("SDHost:(%p) SDHostCC32XX_initialize released read/write"
424 " power constraint", hwAttrs->baseAddr);
425
426 return (result);
427 }
428
429 /*
430 * ======== SDHostCC32XX_init ========
431 * Function to initialize the SDHost module
432 */
SDHostCC32XX_init(SD_Handle handle)433 void SDHostCC32XX_init(SD_Handle handle)
434 {
435 SDHostCC32XX_Object *object = handle->object;
436
437 object->buffer = NULL;
438 object->sectorCount = 0;
439 object->cardType = SD_NOCARD;
440 object->isOpen = false;
441
442 UDMACC32XX_init();
443 }
444
445 /*
446 * ======== SDHostCC32XX_open ========
447 */
SDHostCC32XX_open(SD_Handle handle,SD_Params * params)448 SD_Handle SDHostCC32XX_open(SD_Handle handle, SD_Params *params)
449 {
450 uintptr_t key;
451 SemaphoreP_Params semParams;
452 HwiP_Params hwiParams;
453 SDHostCC32XX_Object *object = handle->object;
454 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
455 uint16_t pin;
456
457 key = HwiP_disable();
458
459 if (object->isOpen) {
460 HwiP_restore(key);
461
462 DebugP_log1("SDHost:(%p) already in use.", hwAttrs->baseAddr);
463 return (NULL);
464 }
465 object->isOpen = true;
466
467 HwiP_restore(key);
468
469 /* Initialize the SDCARD_CLK pin ID to undefined */
470 object->clkPin = (uint16_t)-1;
471
472 /* Get the Power resource Id from the base address */
473 object->powerMgrId = getPowerMgrId(hwAttrs->baseAddr);
474 if (object->powerMgrId == (unsigned int)-1) {
475 DebugP_log1("SDHost:(%p) Failed to determine Power resource id",
476 hwAttrs->baseAddr);
477 return (NULL);
478 }
479
480 /*
481 * Register power dependency. Keeps the clock running in SLP
482 * and DSLP modes.
483 */
484 Power_setDependency(object->powerMgrId);
485
486 Power_registerNotify(&object->postNotify, PowerCC32XX_AWAKE_LPDS,
487 postNotifyFxn, (uintptr_t)handle);
488
489 object->dmaHandle = UDMACC32XX_open();
490 if (object->dmaHandle == NULL) {
491 DebugP_log1("SDHost:(%p) UDMACC32XX_open() failed.",
492 hwAttrs->baseAddr);
493 SDHostCC32XX_close(handle);
494 return (NULL);
495 }
496
497 SemaphoreP_Params_init(&semParams);
498 semParams.mode = SemaphoreP_Mode_COUNTING;
499 object->cmdSem = SemaphoreP_create(0, &semParams);
500
501 if (object->cmdSem == NULL) {
502 DebugP_log1("SDHost:(%p) SemaphoreP_create() failed.",
503 hwAttrs->baseAddr);
504 SDHostCC32XX_close(handle);
505 return (NULL);
506 }
507
508 HwiP_Params_init(&hwiParams);
509 hwiParams.arg = (uintptr_t)handle;
510 hwiParams.priority = hwAttrs->intPriority;
511 object->hwiHandle = HwiP_create(INT_MMCHS, hwiIntFxn,
512 &hwiParams);
513 if (object->hwiHandle == NULL) {
514 DebugP_log1("SDHostT:(%p) HwiP_create() failed", hwAttrs->baseAddr);
515 SDHostCC32XX_close(handle);
516 return (NULL);
517 }
518
519 /* Initialize the hardware */
520 initHw(handle);
521
522 /* Save clkPin park state; set to logic '0' during LPDS */
523 pin = PinConfigPin(hwAttrs->clkPin);
524 object->prevParkCLK =
525 (PowerCC32XX_ParkState) PowerCC32XX_getParkState((PowerCC32XX_Pin)pin);
526 PowerCC32XX_setParkState((PowerCC32XX_Pin)pin, 0);
527 object->clkPin = pin;
528
529 DebugP_log1("SDHost:(%p) opened", hwAttrs->baseAddr);
530
531 return (handle);
532 }
533
534 /*
535 * ======== SDHostCC32XX_read ========
536 */
SDHostCC32XX_read(SD_Handle handle,void * buf,int_fast32_t sector,uint_fast32_t secCount)537 int_fast16_t SDHostCC32XX_read(SD_Handle handle, void *buf,
538 int_fast32_t sector, uint_fast32_t secCount)
539 {
540 int_fast32_t result;
541 uint_fast32_t ret;
542 uint_fast32_t size;
543 SDHostCC32XX_Object *object = handle->object;
544 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
545
546 object->stat = SD_STATUS_SUCCESS;
547
548 /* Check for valid sector count */
549 if (secCount == 0) {
550 return (SD_STATUS_ERROR);
551 }
552
553 /* SDSC uses linear address, SDHC uses block address */
554 if (object->cardType == SD_SDSC) {
555 sector = sector * SECTORSIZE;
556 }
557
558 Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
559
560 /* Set the block count */
561 MAP_SDHostBlockCountSet(hwAttrs->baseAddr, secCount);
562
563 /* If input buffer is word aligned use DMA */
564 if (!(((uint32_t)buf) & 0x03)) {
565 object->buffer = (uint32_t *)buf;
566 object->sectorCount = secCount;
567
568 /* Configure ping */
569 configDMAChannel(handle, UDMA_PRI_SELECT , UDMAREAD);
570
571 /* Add offset to input buffer */
572 object->buffer = object->buffer + (SECTORSIZE / 4);
573
574 /* Configure pong */
575 if (secCount > 1) {
576 configDMAChannel(handle, UDMA_ALT_SELECT , UDMAREAD);
577 }
578
579 /*
580 * Enable DMA and transmit complete interrupts, reset ping and
581 * dmaPosted flags.
582 */
583 object->dmaPosted = false;
584 object->ping = false;
585 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_DMARD | SDHOST_INT_TC);
586
587 /* Send multi block read command to the SD card */
588 result = send_cmd(handle, CMD_READ_MULTI_BLK | SDHOST_DMA_EN, sector);
589
590 /* Wait for DMA read(s) to complete */
591 if (result == SD_STATUS_SUCCESS) {
592 /* Any remaining DMA transfers are completed in the hwiFxn */
593 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
594 }
595 }
596 /* Poll buffer for new data */
597 else {
598 /* Compute the number of words to read */
599 size = (SECTORSIZE * secCount) / 4;
600
601 /* Send multi block read command */
602 result = send_cmd(handle, CMD_READ_MULTI_BLK, sector);
603
604 if (result == SD_STATUS_SUCCESS) {
605 /* Read single word of data */
606 while (size > 0) {
607 ret = MAP_SDHostDataNonBlockingRead(hwAttrs->baseAddr,
608 (unsigned long *)buf);
609 /* Block until buffer is ready */
610 if (ret == 0) {
611 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_BRR);
612
613 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
614
615 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_BRR);
616 }
617 else {
618 buf = (uint_least8_t *)buf + 4;
619 size--;
620 }
621 }
622 }
623 }
624
625 /* Verify host controller errors didn't occur */
626 if (object->stat == SD_STATUS_SUCCESS) {
627
628 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_TC);
629
630 /* Wait for full data transfer to complete */
631 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
632
633 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_TC);
634 }
635
636 /* Verify host controller errors didn't occur */
637 if (object->stat == SD_STATUS_SUCCESS) {
638
639 /* Wait for command transfer stop acknowledgement */
640 result = send_cmd(handle, CMD_STOP_TRANS, NULLARG);
641
642 if (result == SD_STATUS_SUCCESS) {
643 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_TC);
644
645 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
646
647 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_TC);
648 }
649 }
650
651 if (object->stat != SD_STATUS_SUCCESS) {
652 result = SD_STATUS_ERROR;
653 }
654
655 Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
656 DebugP_log1("SDHost:(%p) SDHostCC32XX_read released read power"
657 " constraint", hwAttrs->baseAddr);
658
659 return (result);
660 }
661
662 /*
663 * ======== SDHostCC32XX_write ========
664 */
SDHostCC32XX_write(SD_Handle handle,const void * buf,int_fast32_t sector,uint_fast32_t secCount)665 int_fast16_t SDHostCC32XX_write(SD_Handle handle, const void *buf,
666 int_fast32_t sector, uint_fast32_t secCount)
667 {
668 int_fast32_t result;
669 uint_fast32_t ret;
670 uint_fast32_t size;
671 SDHostCC32XX_Object *object = handle->object;
672 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
673
674 object->stat = SD_STATUS_SUCCESS;
675
676 /* Check for valid sector count */
677 if (secCount == 0) {
678 return (SD_STATUS_ERROR);
679 }
680
681 /* SDSC uses linear address, SDHC uses block address */
682 if(object->cardType == SD_SDSC) {
683 sector = sector * SECTORSIZE;
684 }
685
686 Power_setConstraint(PowerCC32XX_DISALLOW_LPDS);
687
688 /* Set the block count */
689 MAP_SDHostBlockCountSet(hwAttrs->baseAddr, secCount);
690
691 /* Set card write block erase count */
692 result = send_cmd(handle, CMD_APP_CMD, object->rca << 16);
693 if (result != SD_STATUS_SUCCESS) {
694 return (SD_STATUS_ERROR);
695 }
696 result = send_cmd(handle, CMD_SET_BLK_CNT, secCount);
697 if (result != SD_STATUS_SUCCESS) {
698 return (SD_STATUS_ERROR);
699 }
700
701 /* If the write buffer is word aligned use the DMA */
702 if (!(((uint_fast32_t)buf) & 0x03)) {
703 object->buffer = (uint32_t *)buf;
704 object->sectorCount = secCount;
705
706 /* Configure ping */
707 configDMAChannel(handle, UDMA_PRI_SELECT, UDMAWRITE);
708
709 /* Add offset to input buffer */
710 object->buffer = object->buffer + (SECTORSIZE / 4);
711
712 /* Configure pong */
713 if (secCount > 1) {
714 configDMAChannel(handle, UDMA_ALT_SELECT, UDMAWRITE);
715 }
716
717 /*
718 * Enable DMA and transmit complete interrupts, reset ping and
719 * dmaPosted flags.
720 */
721 object->dmaPosted = false;
722 object->ping = false;
723 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_DMAWR | SDHOST_INT_TC);
724
725 /* Send write multi block command to the SD card */
726 result = send_cmd(handle, CMD_WRITE_MULTI_BLK | SDHOST_DMA_EN, sector);
727
728 /* Wait for the DMA to finish */
729 if (result == SD_STATUS_SUCCESS) {
730 /* Any remaining DMA transfers are completed in the hwiFxn */
731 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
732 }
733 }
734 else {
735 /* Compute the number of words to write */
736 size = (SECTORSIZE * secCount) / 4;
737
738 /* Verify that the block count had been previous set */
739 if (result == SD_STATUS_SUCCESS) {
740 result = send_cmd(handle, CMD_WRITE_MULTI_BLK, sector);
741 }
742
743 if (result == SD_STATUS_SUCCESS) {
744 /* Write single word of data */
745 while (size > 0) {
746 ret = MAP_SDHostDataNonBlockingWrite(hwAttrs->baseAddr,
747 (*(unsigned long *)buf));
748
749 /* Block until buffer is ready */
750 if (ret == 0) {
751 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_BWR);
752
753 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
754
755 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_BWR);
756
757 }
758 else {
759 buf = (uint_least8_t *)buf + 4;
760 size--;
761 }
762 }
763 }
764 }
765
766 /* Verify host controller errors didn't occur */
767 if (object->stat == SD_STATUS_SUCCESS) {
768 /* Wait for the full data transfer to complete */
769 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_TC);
770
771 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
772
773 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_TC);
774 }
775
776 /* Verify host controller errors didn't occur */
777 if (object->stat == SD_STATUS_SUCCESS) {
778 /* Wait for command transfer stop acknowledgment */
779 result = send_cmd(handle, CMD_STOP_TRANS, NULLARG);
780
781 if (result == SD_STATUS_SUCCESS) {
782 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_TC);
783
784 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
785
786 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_TC);
787 }
788 }
789
790 if (object->stat != SD_STATUS_SUCCESS) {
791 result = SD_STATUS_ERROR;
792 }
793
794 Power_releaseConstraint(PowerCC32XX_DISALLOW_LPDS);
795 DebugP_log1("SDHost:(%p) SDHostCC32XX_write released write power"
796 " constraint", hwAttrs->baseAddr);
797
798 return (result);
799 }
800
801 /*
802 * ======== configDMAChannel ========
803 * Configures either the primary or alternate DMA control structures in
804 * ping-pong mode.
805 * channelSel is the PRI or ALT channel select flag
806 */
configDMAChannel(SD_Handle handle,uint_fast32_t channelSel,uint_fast32_t operation)807 static inline void configDMAChannel(SD_Handle handle, uint_fast32_t channelSel,
808 uint_fast32_t operation)
809 {
810 unsigned long channelControlOptions;
811 SDHostCC32XX_Object *object = handle->object;
812 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
813
814 if (operation == UDMAWRITE) {
815 channelControlOptions = UDMA_SIZE_32 | UDMA_SRC_INC_32 |
816 UDMA_DST_INC_NONE | UDMA_ARB_512;
817
818 /* Primary control structure set-up */
819 MAP_uDMAChannelControlSet(hwAttrs->txChIdx |
820 channelSel, channelControlOptions);
821
822 /* Transfer size is the sector size in words */
823 MAP_uDMAChannelTransferSet(hwAttrs->txChIdx | channelSel,
824 UDMA_MODE_PINGPONG, (void *)object->buffer,
825 (void *)(hwAttrs->baseAddr + MMCHS_O_DATA), SECTORSIZE / 4);
826 }
827 else {
828 channelControlOptions = UDMA_SIZE_32 | UDMA_SRC_INC_NONE |
829 UDMA_DST_INC_32 | UDMA_ARB_512;
830
831 /* Primary control structure set-up */
832 MAP_uDMAChannelControlSet(hwAttrs->rxChIdx |
833 channelSel, channelControlOptions);
834
835 /* Transfer size is the sector size in words */
836 MAP_uDMAChannelTransferSet(hwAttrs->rxChIdx | channelSel,
837 UDMA_MODE_PINGPONG, (void *)(hwAttrs->baseAddr + MMCHS_O_DATA),
838 (void *)object->buffer, SECTORSIZE / 4);
839 }
840 }
841
842 /*
843 * ======== deSelectCard ========
844 * Function to de-select a card on the drive specified by the handle.
845 */
deSelectCard(SD_Handle handle)846 static int_fast32_t deSelectCard(SD_Handle handle)
847 {
848 int_fast32_t result;
849
850 /* De-select the card */
851 result = send_cmd(handle, CMD_DESELECT_CARD, NULLARG);
852
853 return (result);
854 }
855
856 /*
857 * ======== getPowerMgrId ========
858 */
getPowerMgrId(uint_fast32_t baseAddr)859 static uint_fast32_t getPowerMgrId(uint_fast32_t baseAddr)
860 {
861 if (baseAddr == SDHOST_BASE) {
862 return (PowerCC32XX_PERIPH_SDHOST);
863 }
864 else {
865 return ((uint_fast32_t)-1);
866 }
867 }
868
869 /*
870 * ======== hwiIntFxn ========
871 * ISR to service pending SD or DMA commands.
872 */
hwiIntFxn(uintptr_t handle)873 static void hwiIntFxn(uintptr_t handle)
874 {
875 uint_fast32_t ret;
876 SDHostCC32XX_Object *object = ((SD_Handle)handle)->object;
877 SDHostCC32XX_HWAttrsV1 const *hwAttrs = ((SD_Handle)handle)->hwAttrs;
878
879 /* Get interrupt and clear all interrupt flags */
880 ret = MAP_SDHostIntStatus(hwAttrs->baseAddr);
881 MAP_SDHostIntClear(hwAttrs->baseAddr, ret);
882
883 /* Error or unsupported interrupt occurred */
884 if (ret & SDHOST_INT_ERRI) {
885 object->stat = SD_STATUS_ERROR;
886 SemaphoreP_post(object->cmdSem);
887 return;
888 }
889
890 /* Command complete flag */
891 if (ret & SDHOST_INT_CC) {
892 if (object->stat != SD_STATUS_ERROR) {
893 object->stat = SD_STATUS_SUCCESS;
894 }
895 SemaphoreP_post(object->cmdSem);
896 }
897
898 /*
899 * DMA read and write interrupt flags. This interrupt is
900 * generated when a DMA channel finishes a transfer AND when
901 * the SD peripheral empties it's TX or RX buffer. Both events
902 * use the DMA WRITE or DMA READ interrupt flags respectively.
903 */
904 if (ret & (SDHOST_INT_DMARD | SDHOST_INT_DMAWR)) {
905 uint_fast32_t priChannelMode;
906 uint_fast32_t altChannelMode;
907 uint32_t channel = hwAttrs->txChIdx;
908 uint32_t operation = UDMAWRITE;
909
910 if (ret & SDHOST_INT_DMARD) {
911 channel = hwAttrs->rxChIdx;
912 operation = UDMAREAD;
913 }
914
915 priChannelMode = MAP_uDMAChannelModeGet(channel | UDMA_PRI_SELECT);
916 altChannelMode = MAP_uDMAChannelModeGet(channel | UDMA_ALT_SELECT);
917
918 /*
919 * Differentiate between the SD peripheral emptying a buffer
920 * and a DMA channel completing a transfer. If neither DMA
921 * channel is stopped, then we wait for the next interrupt.
922 */
923 if (priChannelMode == UDMA_MODE_STOP ||
924 altChannelMode == UDMA_MODE_STOP) {
925
926 object->ping = !object->ping;
927 if (object->sectorCount != 0) {
928 object->sectorCount--;
929 }
930
931 /*
932 * Check DMA transfers are complete,
933 * otherwise wait for the next interrupt
934 */
935 if (priChannelMode == UDMA_MODE_STOP &&
936 altChannelMode == UDMA_MODE_STOP &&
937 object->sectorCount != 0) {
938
939 /* Determine if multiple DMA transfers completed */
940 if (object->ping) {
941 object->sectorCount--;
942 object->ping = false;
943 }
944
945 /*
946 * If sectorCount is 0, then we do not need to configure
947 * any more DMA transfers.
948 */
949 if(object->sectorCount != 0) {
950 /* Configure the primary DMA channel */
951 object->buffer = object->buffer + (SECTORSIZE / 4);
952 configDMAChannel((SD_Handle) handle, UDMA_PRI_SELECT, operation);
953
954 /* If more than 1 sector is left, configure pong */
955 if (object->sectorCount > 1) {
956 /* Configure the alternate DMA channel */
957 object->buffer = object->buffer + (SECTORSIZE / 4);
958 configDMAChannel((SD_Handle) handle, UDMA_ALT_SELECT, operation);
959 }
960 }
961 }
962
963 /* If the DMA has transfered all sectors to the SD peripheral */
964 if (object->sectorCount == 0 && object->dmaPosted == false &&
965 priChannelMode == UDMA_MODE_STOP &&
966 altChannelMode == UDMA_MODE_STOP) {
967
968 if (object->stat != SD_STATUS_ERROR) {
969 object->stat = SD_STATUS_SUCCESS;
970 }
971
972 /* Reset to primary channel and disable all DMA interrupts */
973 MAP_uDMAChannelAttributeDisable(channel, UDMA_ATTR_ALTSELECT);
974 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_DMAWR | SDHOST_INT_DMARD);
975 MAP_SDHostIntClear(hwAttrs->baseAddr, SDHOST_INT_DMAWR | SDHOST_INT_DMARD);
976 object->dmaPosted = true;
977 SemaphoreP_post(object->cmdSem);
978 }
979 }
980 }
981
982 /* Transfer complete flag */
983 if (ret & SDHOST_INT_TC) {
984 if (object->stat != SD_STATUS_ERROR) {
985 object->stat = SD_STATUS_SUCCESS;
986 }
987 SemaphoreP_post(object->cmdSem);
988 }
989
990 /* Data buffer read ready flag */
991 if (ret & SDHOST_INT_BRR) {
992 if (object->stat != SD_STATUS_ERROR) {
993 object->stat = SD_STATUS_SUCCESS;
994 }
995 SemaphoreP_post(object->cmdSem);
996 }
997
998 /* Data buffer write ready flag */
999 if (ret & SDHOST_INT_BWR) {
1000 if (object->stat != SD_STATUS_ERROR) {
1001 object->stat = SD_STATUS_SUCCESS;
1002 }
1003 SemaphoreP_post(object->cmdSem);
1004 }
1005 }
1006
1007 /*
1008 * ======== initHw ========
1009 */
initHw(SD_Handle handle)1010 static void initHw(SD_Handle handle)
1011 {
1012 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
1013 uint32_t pin;
1014 uint32_t mode;
1015
1016 /* Configure for SDHost Data */
1017 pin = PinConfigPin(hwAttrs->dataPin);
1018 mode = PinConfigPinMode(hwAttrs->dataPin);
1019 MAP_PinTypeSDHost(pin, mode);
1020 MAP_PinConfigSet(pin, PIN_STRENGTH_4MA, PIN_TYPE_STD_PU);
1021
1022 /* Configure for SDHost Command */
1023 pin = PinConfigPin(hwAttrs->cmdPin);
1024 mode = PinConfigPinMode(hwAttrs->cmdPin);
1025 MAP_PinTypeSDHost(pin, mode);
1026 MAP_PinConfigSet(pin, PIN_STRENGTH_4MA, PIN_TYPE_STD_PU);
1027
1028 /* Configure for SDHost clock output */
1029 pin = PinConfigPin(hwAttrs->clkPin);
1030 mode = PinConfigPinMode(hwAttrs->clkPin);
1031 MAP_PinTypeSDHost(pin, mode);
1032 MAP_PinDirModeSet(pin, PIN_DIR_MODE_OUT);
1033
1034 MAP_PRCMPeripheralReset(PRCM_SDHOST);
1035 MAP_SDHostInit(hwAttrs->baseAddr);
1036
1037 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_CC | SDHOST_INT_TC |
1038 SDHOST_INT_DMAWR | SDHOST_INT_DMARD | SDHOST_INT_BRR | SDHOST_INT_BWR);
1039
1040 /* Configure card clock */
1041 MAP_SDHostSetExpClk(hwAttrs->baseAddr,
1042 MAP_PRCMPeripheralClockGet(PRCM_SDHOST), hwAttrs->clkRate);
1043
1044 MAP_SDHostIntClear(hwAttrs->baseAddr, SDHOST_INT_CC | SDHOST_INT_TC |
1045 DATAERROR | CMDERROR | SDHOST_INT_DMAWR | SDHOST_INT_DMARD |
1046 SDHOST_INT_BRR | SDHOST_INT_BWR);
1047
1048 /*
1049 * DMA channels 23 and 24 are connected to the SD peripheral by default.
1050 * If someone hasn't remapped them to something else already, we remap
1051 * them to SW.
1052 */
1053 if (!(HWREG(UDMA_BASE + UDMA_O_CHMAP2) & UDMA_CHMAP2_CH23SEL_M)) {
1054 MAP_uDMAChannelAssign(UDMA_CH23_SW);
1055 }
1056 if (!(HWREG(UDMA_BASE + UDMA_O_CHMAP3) & UDMA_CHMAP3_CH24SEL_M)) {
1057 MAP_uDMAChannelAssign(UDMA_CH24_SW);
1058 }
1059
1060 /* Configure DMA for TX and RX */
1061 MAP_uDMAChannelAssign(hwAttrs->txChIdx);
1062 MAP_uDMAChannelAssign(hwAttrs->rxChIdx);
1063
1064 MAP_uDMAChannelEnable(hwAttrs->txChIdx);
1065 MAP_uDMAChannelEnable(hwAttrs->rxChIdx);
1066
1067 /* Enable SDHost Error Interrupts */
1068 MAP_SDHostIntEnable(hwAttrs->baseAddr, DATAERROR | CMDERROR);
1069 }
1070
1071
1072 /*
1073 * ======== postNotifyFxn ========
1074 * Called by Power module when waking up from LPDS.
1075 */
postNotifyFxn(unsigned int eventType,uintptr_t eventArg,uintptr_t clientArg)1076 static int postNotifyFxn(unsigned int eventType, uintptr_t eventArg,
1077 uintptr_t clientArg)
1078 {
1079 initHw((SD_Handle)clientArg);
1080
1081 return (Power_NOTIFYDONE);
1082 }
1083
1084 /*
1085 * ======== send_cmd ========
1086 * Function to send a command to the SD Card
1087 */
send_cmd(SD_Handle handle,uint_fast32_t cmd,uint_fast32_t arg)1088 static int_fast32_t send_cmd(SD_Handle handle, uint_fast32_t cmd,
1089 uint_fast32_t arg)
1090 {
1091 int_fast32_t result = SD_STATUS_SUCCESS;
1092 SDHostCC32XX_Object *object = handle->object;
1093 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
1094
1095 /* Enable command complete interrupts */
1096 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_CC);
1097
1098 /* Send the command */
1099 MAP_SDHostCmdSend(hwAttrs->baseAddr, cmd, arg);
1100
1101 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
1102
1103 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_CC);
1104
1105 /* SD Card Error, reset the command line */
1106 if (object->stat == SD_STATUS_ERROR) {
1107 MAP_SDHostCmdReset(hwAttrs->baseAddr);
1108 result = SD_STATUS_ERROR;
1109 }
1110
1111 return (result);
1112 }
1113
1114 /*
1115 * ======== selectCard ========
1116 * Function to select a card on the specified drive.
1117 */
selectCard(SD_Handle handle)1118 static int_fast32_t selectCard(SD_Handle handle)
1119 {
1120 int_fast32_t result;
1121 SDHostCC32XX_Object *object = handle->object;
1122 SDHostCC32XX_HWAttrsV1 const *hwAttrs = handle->hwAttrs;
1123
1124 /* Select the card */
1125 result = send_cmd(handle, CMD_SELECT_CARD, object->rca << 16);
1126
1127 if (result == SD_STATUS_SUCCESS) {
1128 /* Wait for transfer compelte interrupt */
1129 MAP_SDHostIntEnable(hwAttrs->baseAddr, SDHOST_INT_TC);
1130
1131 SemaphoreP_pend(object->cmdSem, SemaphoreP_WAIT_FOREVER);
1132
1133 MAP_SDHostIntDisable(hwAttrs->baseAddr, SDHOST_INT_TC);
1134
1135 /* Host controller error occurred */
1136 if (object->stat != SD_STATUS_SUCCESS) {
1137 result = SD_STATUS_ERROR;
1138 }
1139 }
1140 return (result);
1141 }
1142