2 #include <minix/blockdriver.h>
20 /* header imported from netbsd */
25 /* omap /hardware related */
29 * Define a structure to be used for logging
31 static struct mmclog log
= {
32 .name
= "mmc_host_mmchs",
33 .log_level
= LEVEL_INFO
,
34 .log_func
= default_log
37 #define REG(x)(*((volatile uint32_t *)(x)))
38 #define BIT(x)(0x1 << x)
40 /* Write a uint32_t value to a memory address. */
42 write32(uint32_t address
, uint32_t value
)
47 /* Read an uint32_t from a memory address */
49 read32(uint32_t address
)
55 /* Set a 32 bits value depending on a mask */
57 set32(uint32_t address
, uint32_t mask
, uint32_t value
)
60 val
= read32(address
);
63 /* apply the value using the mask */
64 val
|= (value
& mask
);
65 write32(address
, val
);
68 static uint32_t base_address
;
71 * Initialize the MMC controller given a certain
72 * instance. this driver only handles a single
73 * mmchs controller at a given time.
76 mmchs_init(uint32_t instance
)
84 struct minix_mem_range mr
;
86 mr
.mr_base
= MMCHS1_REG_BASE
;
87 mr
.mr_limit
= MMCHS1_REG_BASE
+ 0x400;
89 if (sys_privctl(SELF
, SYS_PRIV_ADD_MEM
, &mr
) != 0) {
90 panic("Unable to request permission to map memory");
93 /* Set the base address to use */
95 (uint32_t) vm_map_phys(SELF
, (void *) MMCHS1_REG_BASE
, 0x400);
96 if (base_address
== (uint32_t) MAP_FAILED
)
97 panic("Unable to map MMC memory");
99 base_address
= (unsigned long) base_address
- 0x100;
101 /* Soft reset of the controller. This section is documented in the TRM
104 /* Write 1 to sysconfig[0] to trigger a reset */
105 set32(base_address
+ MMCHS_SD_SYSCONFIG
, MMCHS_SD_SYSCONFIG_SOFTRESET
,
106 MMCHS_SD_SYSCONFIG_SOFTRESET
);
108 /* Read sysstatus to know when it's done */
109 while (!(read32(base_address
+ MMCHS_SD_SYSSTATUS
)
110 & MMCHS_SD_SYSSTATUS_RESETDONE
)) {
111 /* TODO:Add proper delay and escape route */
116 /* Set SD default capabilities */
117 set32(base_address
+ MMCHS_SD_CAPA
, MMCHS_SD_CAPA_VS_MASK
,
118 MMCHS_SD_CAPA_VS18
| MMCHS_SD_CAPA_VS30
);
120 /* TRM mentions MMCHS_SD_CUR_CAPA but does not describe how to limit
124 MMCHS_SD_SYSCONFIG_AUTOIDLE
| MMCHS_SD_SYSCONFIG_ENAWAKEUP
|
125 MMCHS_SD_SYSCONFIG_STANDBYMODE
| MMCHS_SD_SYSCONFIG_CLOCKACTIVITY
|
126 MMCHS_SD_SYSCONFIG_SIDLEMODE
;
128 /* Automatic clock gating strategy */
129 value
= MMCHS_SD_SYSCONFIG_AUTOIDLE_EN
;
130 /* Enable wake-up capability */
131 value
|= MMCHS_SD_SYSCONFIG_ENAWAKEUP_EN
;
133 value
|= MMCHS_SD_SYSCONFIG_SIDLEMODE_IDLE
;
134 /* Booth the interface and functional can be switched off */
135 value
|= MMCHS_SD_SYSCONFIG_CLOCKACTIVITY_OFF
;
136 /* Go into wake-up mode when possible */
137 value
|= MMCHS_SD_SYSCONFIG_STANDBYMODE_WAKEUP_INTERNAL
;
140 * wake-up configuration
142 set32(base_address
+ MMCHS_SD_SYSCONFIG
, mask
, value
);
144 /* Wake-up on sd interrupt for SDIO */
145 set32(base_address
+ MMCHS_SD_HCTL
, MMCHS_SD_HCTL_IWE
,
146 MMCHS_SD_HCTL_IWE_EN
);
149 * MMC host and bus configuration
152 /* Configure data and command transfer (1 bit mode) */
153 set32(base_address
+ MMCHS_SD_CON
, MMCHS_SD_CON_DW8
,
154 MMCHS_SD_CON_DW8_1BIT
);
155 set32(base_address
+ MMCHS_SD_HCTL
, MMCHS_SD_HCTL_DTW
,
156 MMCHS_SD_HCTL_DTW_1BIT
);
158 /* Configure card voltage to 3.0 volt */
159 set32(base_address
+ MMCHS_SD_HCTL
, MMCHS_SD_HCTL_SDVS
,
160 MMCHS_SD_HCTL_SDVS_VS30
);
162 /* Power on the host controller and wait for the
163 * MMCHS_SD_HCTL_SDBP_POWER_ON to be set */
164 set32(base_address
+ MMCHS_SD_HCTL
, MMCHS_SD_HCTL_SDBP
,
165 MMCHS_SD_HCTL_SDBP_ON
);
167 /* TODO: Add padconf stuff here as documented in the TRM */
169 while ((read32(base_address
+ MMCHS_SD_HCTL
) & MMCHS_SD_HCTL_SDBP
)
170 != MMCHS_SD_HCTL_SDBP_ON
) {
171 /* TODO:Add proper delay and escape route */
175 /* Enable internal clock and clock to the card */
176 set32(base_address
+ MMCHS_SD_SYSCTL
, MMCHS_SD_SYSCTL_ICE
,
177 MMCHS_SD_SYSCTL_ICE_EN
);
179 // @TODO Fix external clock enable , this one is very slow
180 set32(base_address
+ MMCHS_SD_SYSCTL
, MMCHS_SD_SYSCTL_CLKD
,
182 set32(base_address
+ MMCHS_SD_SYSCTL
, MMCHS_SD_SYSCTL_CEN
,
183 MMCHS_SD_SYSCTL_CEN_EN
);
186 while ((read32(base_address
+ MMCHS_SD_SYSCTL
) & MMCHS_SD_SYSCTL_ICS
)
187 != MMCHS_SD_SYSCTL_ICS_STABLE
) {
188 /* TODO:Add proper delay and escape route */
193 * See spruh73e page 3576 Card Detection, Identification, and Selection
196 /* Enable command interrupt */
197 set32(base_address
+ MMCHS_SD_IE
, MMCHS_SD_IE_CC_ENABLE
,
198 MMCHS_SD_IE_CC_ENABLE_ENABLE
);
199 /* Enable transfer complete interrupt */
200 set32(base_address
+ MMCHS_SD_IE
, MMCHS_SD_IE_TC_ENABLE
,
201 MMCHS_SD_IE_TC_ENABLE_ENABLE
);
203 /* enable error interrupts */
204 /* NOTE: We are currently skipping the BADA interrupt it does get
205 * raised for unknown reasons */
206 set32(base_address
+ MMCHS_SD_IE
, MMCHS_SD_IE_ERROR_MASK
, 0x0fffffffu
);
208 /* clean the error interrupts */
209 set32(base_address
+ MMCHS_SD_STAT
, MMCHS_SD_STAT_ERROR_MASK
,
212 /* send a init signal to the host controller. This does not actually
213 * send a command to a card manner */
214 set32(base_address
+ MMCHS_SD_CON
, MMCHS_SD_CON_INIT
,
215 MMCHS_SD_CON_INIT_INIT
);
216 /* command 0 , type other commands not response etc) */
217 write32(base_address
+ MMCHS_SD_CMD
, 0x00);
220 while ((read32(base_address
+ MMCHS_SD_STAT
) & MMCHS_SD_STAT_CC
)
221 != MMCHS_SD_STAT_CC_RAISED
) {
222 if (read32(base_address
+ MMCHS_SD_STAT
) & 0x8000) {
223 mmc_log_warn(&log
, "%s, error stat %x\n",
225 read32(base_address
+ MMCHS_SD_STAT
));
231 /* clear the cc interrupt status */
232 set32(base_address
+ MMCHS_SD_STAT
, MMCHS_SD_IE_CC_ENABLE
,
233 MMCHS_SD_IE_CC_ENABLE_ENABLE
);
236 * Set Set SD_CON[1] INIT bit to 0x0 to end the initialization sequence
238 set32(base_address
+ MMCHS_SD_CON
, MMCHS_SD_CON_INIT
,
239 MMCHS_SD_CON_INIT_NOINIT
);
241 /* Clean the MMCHS_SD_STAT register */
242 write32(base_address
+ MMCHS_SD_STAT
, 0xffffffffu
);
247 mmchs_send_cmd(uint32_t command
, uint32_t arg
)
251 /* Read current interrupt status and fail it an interrupt is already
253 if ((read32(base_address
+ MMCHS_SD_STAT
) & 0xffffu
)) {
254 mmc_log_warn(&log
, "%s, interrupt already raised stat %08x\n",
255 __FUNCTION__
, read32(base_address
+ MMCHS_SD_STAT
));
256 write32(base_address
+ MMCHS_SD_STAT
,
257 MMCHS_SD_IE_CC_ENABLE_CLEAR
);
262 write32(base_address
+ MMCHS_SD_ARG
, arg
);
264 set32(base_address
+ MMCHS_SD_CMD
, MMCHS_SD_CMD_MASK
, command
);
266 /* Wait for completion */
267 while ((read32(base_address
+ MMCHS_SD_STAT
) & 0xffffu
) == 0x0) {
271 if (read32(base_address
+ MMCHS_SD_STAT
) & 0x8000) {
272 mmc_log_warn(&log
, "%s, error stat %08x\n", __FUNCTION__
,
273 read32(base_address
+ MMCHS_SD_STAT
));
274 set32(base_address
+ MMCHS_SD_STAT
, MMCHS_SD_STAT_ERROR_MASK
,
279 if ((command
& MMCHS_SD_CMD_RSP_TYPE
) ==
280 MMCHS_SD_CMD_RSP_TYPE_48B_BUSY
) {
282 * Command with busy response *CAN* also set the TC bit if they exit busy
284 while ((read32(base_address
+ MMCHS_SD_STAT
)
285 & MMCHS_SD_IE_TC_ENABLE_ENABLE
) == 0) {
288 write32(base_address
+ MMCHS_SD_STAT
,
289 MMCHS_SD_IE_TC_ENABLE_CLEAR
);
292 /* clear the cc status */
293 write32(base_address
+ MMCHS_SD_STAT
, MMCHS_SD_IE_CC_ENABLE_CLEAR
);
298 mmc_send_cmd(struct mmc_command
*c
)
301 /* convert the command to a hsmmc command */
304 cmd
= MMCHS_SD_CMD_INDX_CMD(c
->cmd
);
307 switch (c
->resp_type
) {
308 case RESP_LEN_48_CHK_BUSY
:
309 cmd
|= MMCHS_SD_CMD_RSP_TYPE_48B_BUSY
;
312 cmd
|= MMCHS_SD_CMD_RSP_TYPE_48B
;
315 cmd
|= MMCHS_SD_CMD_RSP_TYPE_136B
;
318 cmd
|= MMCHS_SD_CMD_RSP_TYPE_NO_RESP
;
324 ret
= mmchs_send_cmd(cmd
, arg
);
326 /* copy response into cmd->resp */
327 switch (c
->resp_type
) {
328 case RESP_LEN_48_CHK_BUSY
:
330 c
->resp
[0] = read32(base_address
+ MMCHS_SD_RSP10
);
333 c
->resp
[0] = read32(base_address
+ MMCHS_SD_RSP10
);
334 c
->resp
[1] = read32(base_address
+ MMCHS_SD_RSP32
);
335 c
->resp
[2] = read32(base_address
+ MMCHS_SD_RSP54
);
336 c
->resp
[3] = read32(base_address
+ MMCHS_SD_RSP76
);
347 static struct mmc_command command
;
350 card_goto_idle_state()
352 command
.cmd
= MMC_GO_IDLE_STATE
;
353 command
.resp_type
= NO_RESPONSE
;
355 if (mmc_send_cmd(&command
)) {
363 card_identification()
365 command
.cmd
= MMC_SEND_EXT_CSD
;
366 command
.resp_type
= RESP_LEN_48
;
367 command
.args
= MMCHS_SD_ARG_CMD8_VHS
| MMCHS_SD_ARG_CMD8_CHECK_PATTERN
;
369 if (mmc_send_cmd(&command
)) {
370 // We currently only support 2.0,
374 if (!(command
.resp
[0]
375 == (MMCHS_SD_ARG_CMD8_VHS
| MMCHS_SD_ARG_CMD8_CHECK_PATTERN
))) {
376 mmc_log_warn(&log
, "%s, check pattern check failed %08x\n",
377 __FUNCTION__
, command
.resp
[0]);
384 card_query_voltage_and_type(struct sd_card_regs
*card
)
387 command
.cmd
= MMC_APP_CMD
;
388 command
.resp_type
= RESP_LEN_48
;
389 command
.args
= MMC_ARG_RCA(0x0); /* RCA=0000 */
390 if (mmc_send_cmd(&command
)) {
394 command
.cmd
= SD_APP_OP_COND
;
395 command
.resp_type
= RESP_LEN_48
;
397 /* 0x1 << 30 == send HCS (Host capacity support) and get OCR register */
399 MMC_OCR_3_3V_3_4V
| MMC_OCR_3_2V_3_3V
| MMC_OCR_3_1V_3_2V
|
400 MMC_OCR_3_0V_3_1V
| MMC_OCR_2_9V_3_0V
| MMC_OCR_2_8V_2_9V
|
402 command
.args
|= MMC_OCR_HCS
; /* RCA=0000 */
404 if (mmc_send_cmd(&command
)) {
407 /* @todo wait for max 1 ms */
408 while (!(command
.resp
[0] & MMC_OCR_MEM_READY
)) {
409 command
.cmd
= MMC_APP_CMD
;
410 command
.resp_type
= RESP_LEN_48
;
411 command
.args
= MMC_ARG_RCA(0x0); /* RCA=0000 */
412 if (mmc_send_cmd(&command
)) {
417 /* 0x1 << 30 == send HCS (Host capacity support) and get OCR
419 command
.cmd
= SD_APP_OP_COND
;
420 command
.resp_type
= RESP_LEN_48
;
421 /* 0x1 << 30 == send HCS (Host capacity support) */
422 command
.args
= MMC_OCR_3_3V_3_4V
| MMC_OCR_3_2V_3_3V
423 | MMC_OCR_3_1V_3_2V
| MMC_OCR_3_0V_3_1V
| MMC_OCR_2_9V_3_0V
424 | MMC_OCR_2_8V_2_9V
| MMC_OCR_2_7V_2_8V
;
425 command
.args
|= MMC_OCR_HCS
; /* RCA=0000 */
427 if (mmc_send_cmd(&command
)) {
431 /* if bit 31 is set the response is valid */
432 if ((command
.resp
[0] & MMC_OCR_MEM_READY
)) {
437 card
->ocr
= command
.resp
[3];
442 card_identify(struct sd_card_regs
*card
)
445 /* Send cmd 2 (all_send_cid) and expect 136 bits response */
446 command
.cmd
= MMC_ALL_SEND_CID
;
447 command
.resp_type
= RESP_LEN_136
;
448 command
.args
= MMC_ARG_RCA(0x0); /* RCA=0000 */
450 if (mmc_send_cmd(&command
)) {
454 card
->cid
[0] = command
.resp
[0];
455 card
->cid
[1] = command
.resp
[1];
456 card
->cid
[2] = command
.resp
[2];
457 card
->cid
[3] = command
.resp
[3];
459 command
.cmd
= MMC_SET_RELATIVE_ADDR
;
460 command
.resp_type
= RESP_LEN_48
;
461 command
.args
= 0x0; /* RCA=0000 */
464 if (mmc_send_cmd(&command
)) {
468 card
->rca
= SD_R6_RCA(command
.resp
);
469 /* MMHCS only supports a single card so sending MMCHS_SD_CMD_CMD2 is
470 * useless Still we should make it possible in the API to support
477 card_csd(struct sd_card_regs
*card
)
479 /* send_csd -> r2 response */
480 command
.cmd
= MMC_SEND_CSD
;
481 command
.resp_type
= RESP_LEN_136
;
482 command
.args
= MMC_ARG_RCA(card
->rca
); /* card rca */
484 if (mmc_send_cmd(&command
)) {
488 card
->csd
[0] = command
.resp
[0];
489 card
->csd
[1] = command
.resp
[1];
490 card
->csd
[2] = command
.resp
[2];
491 card
->csd
[3] = command
.resp
[3];
493 if (SD_CSD_CSDVER(card
->csd
) != SD_CSD_CSDVER_2_0
) {
494 mmc_log_warn(&log
, "Version 2.0 of CSD register expected\n");
499 // mmc_log_warn(&log,"size = %llu bytes\n", (long long
500 // unsigned)SD_CSD_V2_CAPACITY( card->csd) * 512);
505 select_card(struct sd_card_regs
*card
)
508 command
.cmd
= MMC_SELECT_CARD
;
509 command
.resp_type
= RESP_LEN_48_CHK_BUSY
;
510 command
.args
= MMC_ARG_RCA(card
->rca
); /* card rca */
512 if (mmc_send_cmd(&command
)) {
519 read_single_block(struct sd_card_regs
*card
,
520 uint32_t blknr
, unsigned char *buf
)
527 set32(base_address
+ MMCHS_SD_IE
, MMCHS_SD_IE_BRR_ENABLE
,
528 MMCHS_SD_IE_BRR_ENABLE_ENABLE
);
530 set32(base_address
+ MMCHS_SD_BLK
, MMCHS_SD_BLK_BLEN
, 512);
532 /* read single block */
533 if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_READ_BLOCK_SINGLE
)
534 | MMCHS_SD_CMD_DP_DATA
/* Command with data transfer */
535 | MMCHS_SD_CMD_RSP_TYPE_48B
/* type (R1) */
536 | MMCHS_SD_CMD_MSBS_SINGLE
/* single block */
537 | MMCHS_SD_CMD_DDIR_READ
/* read data from card */
542 while ((read32(base_address
+ MMCHS_SD_STAT
)
543 & MMCHS_SD_IE_BRR_ENABLE_ENABLE
) == 0) {
547 if (!(read32(base_address
+ MMCHS_SD_PSTATE
) & MMCHS_SD_PSTATE_BRE_EN
)) {
548 return 1; /* We are not allowed to read data from the
552 for (count
= 0; count
< 512; count
+= 4) {
553 value
= read32(base_address
+ MMCHS_SD_DATA
);
554 buf
[count
] = *((char *) &value
);
555 buf
[count
+ 1] = *((char *) &value
+ 1);
556 buf
[count
+ 2] = *((char *) &value
+ 2);
557 buf
[count
+ 3] = *((char *) &value
+ 3);
561 while ((read32(base_address
+
562 MMCHS_SD_STAT
) & MMCHS_SD_IE_TC_ENABLE_ENABLE
)
566 write32(base_address
+ MMCHS_SD_STAT
, MMCHS_SD_IE_TC_ENABLE_CLEAR
);
568 /* clear and disable the bbr interrupt */
569 write32(base_address
+ MMCHS_SD_STAT
, MMCHS_SD_IE_BRR_ENABLE_CLEAR
);
570 set32(base_address
+ MMCHS_SD_IE
, MMCHS_SD_IE_BRR_ENABLE
,
571 MMCHS_SD_IE_BRR_ENABLE_DISABLE
);
576 write_single_block(struct sd_card_regs
*card
,
577 uint32_t blknr
, unsigned char *buf
)
584 set32(base_address
+ MMCHS_SD_IE
, MMCHS_SD_IE_BWR_ENABLE
,
585 MMCHS_SD_IE_BWR_ENABLE_ENABLE
);
586 // set32(base_address + MMCHS_SD_IE, 0xfff , 0xfff);
587 set32(base_address
+ MMCHS_SD_BLK
, MMCHS_SD_BLK_BLEN
, 512);
590 set32(base_address
+ MMCHS_SD_SYSCTL
, MMCHS_SD_SYSCTL_DTO
,
591 MMCHS_SD_SYSCTL_DTO_2POW27
);
593 /* write single block */
594 if (mmchs_send_cmd(MMCHS_SD_CMD_INDX_CMD(MMC_WRITE_BLOCK_SINGLE
)
595 | MMCHS_SD_CMD_DP_DATA
/* Command with data transfer */
596 | MMCHS_SD_CMD_RSP_TYPE_48B
/* type (R1b) */
597 | MMCHS_SD_CMD_MSBS_SINGLE
/* single block */
598 | MMCHS_SD_CMD_DDIR_WRITE
/* write to the card */
603 /* Wait for the MMCHS_SD_IE_BWR_ENABLE interrupt */
604 while ((read32(base_address
+
605 MMCHS_SD_STAT
) & MMCHS_SD_IE_BWR_ENABLE
) == 0) {
609 if (!(read32(base_address
+ MMCHS_SD_PSTATE
) & MMCHS_SD_PSTATE_BWE_EN
)) {
610 return 1; /* not ready to write data */
612 for (count
= 0; count
< 512; count
+= 4) {
613 *((char *) &value
) = buf
[count
];
614 *((char *) &value
+ 1) = buf
[count
+ 1];
615 *((char *) &value
+ 2) = buf
[count
+ 2];
616 *((char *) &value
+ 3) = buf
[count
+ 3];
617 write32(base_address
+ MMCHS_SD_DATA
, value
);
621 while ((read32(base_address
+
622 MMCHS_SD_STAT
) & MMCHS_SD_IE_TC_ENABLE_ENABLE
)
626 write32(base_address
+ MMCHS_SD_STAT
, MMCHS_SD_IE_TC_ENABLE_CLEAR
);
627 write32(base_address
+ MMCHS_SD_STAT
, MMCHS_SD_IE_CC_ENABLE_CLEAR
); /* finished.
629 /* clear the bwr interrupt FIXME is this right when writing? */
630 write32(base_address
+ MMCHS_SD_STAT
, MMCHS_SD_IE_BWR_ENABLE_CLEAR
);
631 set32(base_address
+ MMCHS_SD_IE
, MMCHS_SD_IE_BWR_ENABLE
,
632 MMCHS_SD_IE_BWR_ENABLE_DISABLE
);
637 mmchs_host_init(struct mmc_host
*host
)
644 mmchs_set_log_level(int level
)
646 if (level
>= 0 && level
<= 4) {
647 log
.log_level
= level
;
652 mmchs_host_set_instance(struct mmc_host
*host
, int instance
)
654 mmc_log_info(&log
, "Using instance number %d\n", instance
);
662 mmchs_host_reset(struct mmc_host
*host
)
669 mmchs_card_detect(struct sd_slot
*slot
)
671 /* @TODO implement proper card detect */
676 mmchs_card_initialize(struct sd_slot
*slot
)
680 struct sd_card
*card
;
682 memset(card
, 0, sizeof(struct sd_card
));
685 if (card_goto_idle_state()) {
686 mmc_log_warn(&log
, "Failed to go idle state\n");
690 if (card_identification()) {
691 mmc_log_warn(&log
, "Failed to do card_identification\n");
695 if (card_query_voltage_and_type(&slot
->card
.regs
)) {
697 "Failed to do card_query_voltage_and_type\n");
700 if (card_identify(&slot
->card
.regs
)) {
701 mmc_log_warn(&log
, "Failed to identify card\n");
704 /* We have now initialized the hardware identified the card */
705 if (card_csd(&slot
->card
.regs
)) {
707 "failed to read csd (card specific data)\n");
711 if (select_card(&slot
->card
.regs
)) {
712 mmc_log_warn(&log
, "Failed to select card\n");
716 if (SD_CSD_READ_BL_LEN(slot
->card
.regs
.csd
) != 0x09) {
717 /* for CSD version 2.0 the value is fixed to 0x09 and means a
718 * block size of 512 */
719 mmc_log_warn(&log
, "Block size expect to be 512\n");
723 slot
->card
.blk_size
= 512; /* HARDCODED value */
724 slot
->card
.blk_count
= SD_CSD_V2_CAPACITY(slot
->card
.regs
.csd
);
725 slot
->card
.state
= SD_MODE_DATA_TRANSFER_MODE
;
727 memset(slot
->card
.part
, 0, sizeof(slot
->card
.part
));
728 memset(slot
->card
.subpart
, 0, sizeof(slot
->card
.subpart
));
729 slot
->card
.part
[0].dv_base
= 0;
730 slot
->card
.part
[0].dv_size
=
731 (unsigned long long) SD_CSD_V2_CAPACITY(slot
->card
.regs
.csd
) * 512;
735 /* read count blocks into existing buf */
737 mmchs_host_read(struct sd_card
*card
,
738 uint32_t blknr
, uint32_t count
, unsigned char *buf
)
742 for (i
= 0; i
< count
; i
++) {
743 read_single_block(&card
->regs
, blknr
+ i
,
744 buf
+ (i
* card
->blk_size
));
749 /* write count blocks */
751 mmchs_host_write(struct sd_card
*card
,
752 uint32_t blknr
, uint32_t count
, unsigned char *buf
)
757 for (i
= 0; i
< count
; i
++) {
758 write_single_block(&card
->regs
, blknr
+ i
,
759 buf
+ (i
* card
->blk_size
));
766 mmchs_card_release(struct sd_card
*card
)
768 assert(card
->open_ct
== 1);
770 card
->state
= SD_MODE_UNINITIALIZED
;
771 /* TODO:Set card state */
776 host_initialize_host_structure_mmchs(struct mmc_host
*host
)
778 /* Initialize the basic data structures host slots and cards */
781 host
->host_set_instance
= mmchs_host_set_instance
;
782 host
->host_init
= mmchs_host_init
;
783 host
->set_log_level
= mmchs_set_log_level
;
784 host
->host_reset
= mmchs_host_reset
;
785 host
->card_detect
= mmchs_card_detect
;
786 host
->card_initialize
= mmchs_card_initialize
;
787 host
->card_release
= mmchs_card_release
;
788 host
->read
= mmchs_host_read
;
789 host
->write
= mmchs_host_write
;
791 /* initialize data structures */
792 for (i
= 0; i
< sizeof(host
->slot
) / sizeof(host
->slot
[0]); i
++) {
793 // @TODO set initial card and slot state
794 host
->slot
[i
].host
= host
;
795 host
->slot
[i
].card
.slot
= &host
->slot
[i
];