1 // ==========================================================================
6 // MMC card driver for MXC platform
8 // ==========================================================================
9 //####ECOSGPLCOPYRIGHTBEGIN####
10 // -------------------------------------------
11 // This file is part of eCos, the Embedded Configurable Operating System.
12 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
44 // Author(s): Lewis Liu <weizhi.liu@freescale.com>
45 // Contributors: Lewis Liu <weizhi.liu@freescale.com>
46 // Date: 2008-05-13 Initial version
50 //####DESCRIPTIONEND####
52 //==========================================================================
54 #include <cyg/io/mxcmci_host.h>
55 #include <cyg/io/mxcmci_core.h>
56 #include <cyg/io/mxcmci_mmc.h>
57 #include <cyg/io/mxc_mmc.h>
59 extern int HighCapacityCard;
61 static cyg_uint32 mmc_set_rca(void);
62 static cyg_uint32 mmc_set_bus_width(cyg_uint32 bus_width);
63 static cyg_uint32 mmc_set_high_speed_mode(void);
65 cyg_uint32 address_mode; /* Global variable for addressing mode */
67 cyg_uint32 mmc_init(cyg_uint32 bus_width)
69 cyg_uint32 status = FAIL;
70 cyg_uint32 spec_version;
71 /* Get CID number of MMC Card */
72 if (!mxcmci_get_cid()) {
73 /* Set RCA of the MMC Card */
75 flash_dprintf(FLASH_DEBUG_MAX, "%s: mmc_set_rca OK!",
77 /* Get Spec version supported by the card */
78 spec_version = mmc_get_spec_ver();
79 //diag_printf("SPEC Version: %d\n", spec_version);
81 /*Enable operating frequency */
82 host_cfg_clock(OPERATING_FREQ);
84 /*Put MMC in Transfer State */
85 if (!mxcmci_trans_prepare()) {
87 if (mmc_set_high_speed_mode()) {
92 /* Set block length for transfer */
93 //diag_printf("Send CMD to Set Block Length.\n");
94 if (sdmmc_set_blklen(BLK_LEN))
97 flash_dprintf(FLASH_DEBUG_MAX, "%s: mxcmci_trans_prepare OK!",
100 if (!mmc_set_bus_width(bus_width)) {
101 esdhc_base_pointer->protocol_control &= ~(0x3 << 1);
102 esdhc_base_pointer->protocol_control |= (bus_width >> 2) << 1;
104 diag_printf("Bus Width: %d\n",
116 cyg_uint32 mmc_data_read(cyg_uint32 * dest_ptr, cyg_uint32 length,
121 cyg_uint32 read_block_status = 0;
122 cyg_uint32 blk_len = BLK_LEN;
123 unsigned int SectorNum = 0;
125 /* Assing length of data to be read */
126 SectorNum = length / blk_len;
127 if ((length % blk_len) != 0)
129 /* hight capacity card uses sector mode */
133 /* wait until in transfer mode */
134 while (mxcmci_trans_status()) {
139 /* Configure interface block and number of blocks */
140 host_cfg_block(BLK_LEN, SectorNum);
142 if (SectorNum == 1) {
143 //diag_printf("Send CMD17...\n");
144 /* Comfigure command CMD17 for single block read */
145 mxcmci_cmd_config(&cmd, CMD17, offset, READ, RESPONSE_48,
146 DATA_PRESENT, ENABLE, ENABLE);
148 if (host_send_cmd(&cmd) == FAIL) {
149 diag_printf("%s: Can't send CMD17!\n", __FUNCTION__);
150 esdhc_softreset(ESDHC_RESET_CMD_MSK |
151 ESDHC_RESET_DAT_MSK);
152 read_block_status = FAIL;
155 //diag_printf("host_data_read! dest_ptr: 0%x \n", dest_ptr);
156 /* Call interface Data read function */
157 read_block_status = host_data_read(dest_ptr, BLK_LEN);
159 if (read_block_status) { /* fail */
160 //diag_printf("%s: Failed, read_block_status =%d\n", __FUNCTION__, read_block_status);
161 /* re-transfer if data transfer error occurs */
165 } else { /* read multi-blocks */
167 /* Comfigure command CMD18 for multiple block read */
168 mxcmci_cmd_config(&cmd, CMD18, offset, READ, RESPONSE_48,
169 DATA_PRESENT, ENABLE, ENABLE);
171 if (host_send_cmd(&cmd) == FAIL) {
172 diag_printf("%s: Can't send CMD18!\n", __FUNCTION__);
173 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
174 read_block_status = FAIL;
176 /* Call interface Data read function */
178 host_data_read(dest_ptr, BLK_LEN * SectorNum);
180 /* Comfigure command CMD12 for multi-block read stop */
181 mxcmci_cmd_config(&cmd, CMD12, 0, READ, RESPONSE_48,
182 DATA_PRESENT_NONE, ENABLE, ENABLE);
184 if (host_send_cmd(&cmd) == FAIL) {
185 diag_printf("%s: Can't send CMD12!\n",
187 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
188 //read_block_status = FAIL;
191 if (read_block_status) { /* fail */
192 //diag_printf("%s: Failed, read_block_status =%d\n", __FUNCTION__, read_block_status);
193 /* re-transfer if data transfer error occurs */
200 return read_block_status;
203 cyg_uint32 mmc_data_write(cyg_uint32 * src_ptr, cyg_uint32 length,
209 cyg_uint32 blk_len = BLK_LEN;
210 cyg_uint32 write_block_status = SUCCESS;
211 unsigned int SectorNum;
213 //diag_printf("%s: src: 0x%x, offset: 0x%x, length: 0x%x\n", __FUNCTION__, (unsigned int)src_ptr, offset, length);
214 /* Write data size aligned with block size */
215 SectorNum = length / blk_len;
216 if ((length % blk_len) != 0)
219 /* hight capacity card uses sector mode */
223 //need waiting until CARD out of Prg status, or will cause CMD25 timeout
228 while (mxcmci_trans_status()) {
232 //counter = StopCounter();
233 //diag_printf("counter: 0x%x\n",counter);
236 /* Configure interface block and number of blocks , SctorNum will decrease to zero after transfer */
237 host_cfg_block(BLK_LEN, SectorNum);
239 if (SectorNum == 1) {
240 //diag_printf("Send CMD24...\n");
241 /* Comfigure command CMD24 for single block write */
242 mxcmci_cmd_config(&cmd, CMD24, offset, WRITE, RESPONSE_48,
243 DATA_PRESENT, ENABLE, ENABLE);
245 if (host_send_cmd(&cmd) == FAIL) {
246 diag_printf("%s: Failed in configuring CMD24\n",
248 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
249 write_block_status = FAIL;
251 //hal_delay_us(1000);
255 //diag_printf("Start host_data_write:\n");
256 /* Call interface write read function */
257 write_block_status = host_data_write(src_ptr, BLK_LEN);
258 //diag_printf("0x%x\n", esdhc_base_pointer->present_state);
260 if (write_block_status) { /* fail */
261 //diag_printf("transfer failed.(0x%x)\n", esdhc_base_pointer->block_attributes);
262 while (mxcmci_trans_status()) ;
263 //diag_printf("%s: Failed, write_block_status=%d\n", __FUNCTION__, write_block_status);
269 } else { /* multi-block write */
271 //diag_printf("Send CMD25...\n");
272 /* Comfigure command CMD25 for single block write */
273 mxcmci_cmd_config(&cmd, CMD25, offset, WRITE, RESPONSE_48,
274 DATA_PRESENT, ENABLE, ENABLE);
276 if (host_send_cmd(&cmd) == FAIL) {
277 //diag_printf("%s: Failed in configuring CMD25\n",
279 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
280 write_block_status = FAIL;
283 /* Call interface write read function */
285 host_data_write(src_ptr, SectorNum * BLK_LEN);
287 /* Comfigure command CMD12 for multi-block read stop */
288 mxcmci_cmd_config(&cmd, CMD12, 0, READ, RESPONSE_48,
289 DATA_PRESENT_NONE, ENABLE, ENABLE);
291 if (host_send_cmd(&cmd) == FAIL) {
292 diag_printf("%s: Can't send CMD12!\n",
294 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
295 //write_block_status = FAIL;
298 if (write_block_status) { /* fail */
299 //diag_printf("%s: Failed, write_block_status=%d\n", __FUNCTION__, write_block_status);
300 while (mxcmci_trans_status());
307 return write_block_status;
311 cyg_uint32 mmc_data_erase(cyg_uint32 offset, cyg_uint32 size)
314 extern int Card_Mode;
315 cyg_uint8 startEraseBlockCmd = CMD35;
316 cyg_uint8 endEraseBlockCmd = CMD36;
318 cyg_uint32 startBlock = offset / BLK_LEN;
319 cyg_uint32 endBlock = (offset + size - 1) / BLK_LEN;
321 // diag_printf("card_data_erase\n");
322 if (Card_Mode == 0) {
323 startBlock *= BLK_LEN;
325 startEraseBlockCmd = CMD35;
326 endEraseBlockCmd = CMD36;
329 else if (Card_Mode == 1) {
330 startBlock *= BLK_LEN;
332 startEraseBlockCmd = CMD32;
333 endEraseBlockCmd = CMD33;
336 /* hight capacity card uses sector mode */
338 startBlock /= BLK_LEN;
341 // diag_printf("0x%x - 0x%x, size: 0x%x\n", startBlock, endBlock, size);
342 /* Configure start erase command to set first block */
343 mxcmci_cmd_config(&cmd, startEraseBlockCmd, startBlock, READ,
344 RESPONSE_48, DATA_PRESENT_NONE, ENABLE, ENABLE);
346 if ((ret = host_send_cmd(&cmd)) == SUCCESS) {
347 flash_dprintf(FLASH_DEBUG_MAX,
348 "%s: successful for host_send_cmd\n",
350 /* Configure end erase command to set end block */
351 mxcmci_cmd_config(&cmd, endEraseBlockCmd, endBlock, READ,
352 RESPONSE_48, DATA_PRESENT_NONE, ENABLE, ENABLE);
353 if ((ret = host_send_cmd(&cmd)) == SUCCESS) {
354 flash_dprintf(FLASH_DEBUG_MAX,
355 "%s: successful for host_send_cmd:2\n",
357 /* Comfigure command to start erase */
358 mxcmci_cmd_config(&cmd, CMD38, 0, READ, RESPONSE_48,
359 DATA_PRESENT_NONE, ENABLE, ENABLE);
360 if ((ret = host_send_cmd(&cmd)) == SUCCESS) {
361 flash_dprintf(FLASH_DEBUG_MAX,
362 "%s: successful for host_send_cmd:3\n",
364 //wait for completion
370 flash_dprintf(FLASH_DEBUG_MAX, "%s: Error return (%d)\n", __FUNCTION__,
375 cyg_uint32 mmc_voltage_validation(void)
378 command_response_t response;
379 cyg_uint32 voltage_validation_command = 0;
380 cyg_uint32 ocr_val = 0;
381 cyg_uint32 voltage_validation = FAIL;
383 ocr_val = (cyg_uint32) ((MMC_OCR_VALUE) & 0xFFFFFFFF);
385 while ((voltage_validation_command < MMCSD_READY_TIMEOUT)
386 && (voltage_validation != SUCCESS)) {
387 /* Configure CMD1 for MMC card */
388 mxcmci_cmd_config(&cmd, CMD1, ocr_val, READ, RESPONSE_48,
389 DATA_PRESENT_NONE, DISABLE, DISABLE);
391 /* Issue CMD1 to MMC card to determine OCR value */
392 if (host_send_cmd(&cmd) == FAIL) {
393 voltage_validation = FAIL;
396 /* Read Response from CMDRSP0 Register */
397 response.format = RESPONSE_48;
398 host_read_response(&response);
400 /* Check if card busy bit is cleared or not */
401 if (!(response.cmd_rsp0 & CARD_BUSY_BIT)) {
402 /* Iterate One more time */
403 voltage_validation_command++;
405 if ((response.cmd_rsp0 & MMC_OCR_HC_RES) ==
407 address_mode = SECT_MODE;
408 voltage_validation = SUCCESS;
409 } else if ((response.cmd_rsp0 & MMC_OCR_LC_RES)
411 address_mode = BYTE_MODE;
412 voltage_validation = SUCCESS;
419 return voltage_validation;
422 static cyg_uint32 mmc_set_rca(void)
425 cyg_uint32 card_state = 0;
426 cyg_uint32 rca_request = 0;
427 command_response_t response;
428 cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
430 /* Configure CMD3 for MMC card */
431 /* 32bit card address is expected as Argument */
432 mxcmci_cmd_config(&cmd, CMD3, card_address, READ, RESPONSE_48,
433 DATA_PRESENT_NONE, ENABLE, ENABLE);
435 /* Assigns relative address to the card
438 if (host_send_cmd(&cmd) == FAIL) {
443 /* Read Command response */
444 response.format = RESPONSE_48;
445 host_read_response(&response);
446 card_state = CURR_CARD_STATE(response.cmd_rsp0);
447 if (card_state == IDENT) {
448 rca_request = SUCCESS;
458 cyg_uint32 mmc_get_spec_ver(void)
461 cyg_uint32 mmc_spec_version;
463 if (card_get_csd() == FAIL) {
464 mmc_spec_version = 0;
466 mmc_spec_version = ((csd.csd3 && MMC_SPEC_VER) >> MMC_SPEC_VER_SHIFT);
469 return mmc_spec_version;
473 cyg_uint32 card_flash_query(void *data)
476 cyg_uint32 cid_request = FAIL;
477 command_response_t response;
479 /* Configure CMD2 for card */
480 mxcmci_cmd_config(&cmd, CMD2, NO_ARG, READ, RESPONSE_136,
481 DATA_PRESENT_NONE, ENABLE, DISABLE);
482 /* Issue CMD2 to card to determine CID contents */
483 if (host_send_cmd(&cmd) == FAIL) {
485 flash_dprintf(FLASH_DEBUG_MAX, "%s: can't send query command\n",
488 cyg_uint32 *d = (cyg_uint32 *) data;
489 /* Read Command response */
490 response.format = RESPONSE_136;
491 host_read_response(&response);
492 /* Assign CID values to mmc_cid structures */
493 *d++ = response.cmd_rsp0;
494 *d++ = response.cmd_rsp1;
495 *d++ = response.cmd_rsp2;
496 *d = response.cmd_rsp3;
498 /* Assign cid_request as SUCCESS */
499 cid_request = SUCCESS;
501 flash_dprintf(FLASH_DEBUG_MAX,
502 "%s(Success?=%d):(ID=0x%x: 0x%x, 0x%x, 0x%x)\n",
503 __FUNCTION__, cid_request, *(cyg_uint32 *) (data),
504 *(cyg_uint32 *) ((cyg_uint32) data + 4),
505 *(cyg_uint8 *) ((cyg_uint32) data + 8),
506 *(cyg_uint8 *) ((cyg_uint32) data + 12));
510 static cyg_uint32 mmc_set_bus_width(cyg_uint32 bus_width)
513 cyg_uint32 set_bus_width_status = FAIL;
514 command_response_t response;
515 cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
517 if ((bus_width == FOUR) || (bus_width == EIGHT) || (bus_width == ONE)) {
519 /* Configure CMD6 to write to EXT_CSD register for BUS_WIDTH */
520 mxcmci_cmd_config(&cmd, CMD6, 0x03b70001 | ((bus_width >> 2) << 8), READ,
521 RESPONSE_48, DATA_PRESENT_NONE, ENABLE, ENABLE);
523 if (host_send_cmd(&cmd) == SUCCESS) {
524 set_bus_width_status = SUCCESS;
526 diag_printf("Setting MMC bus width failed.\n");
530 return set_bus_width_status;
533 static cyg_uint32 mmc_set_high_speed_mode(void)
536 command_response_t response;
537 cyg_uint32 status = FAIL;
539 //diag_printf("Send CMD6 to Set High Speed Mode.\n");
540 /* Configure CMD6 to write to EXT_CSD register for BUS_WIDTH */
541 mxcmci_cmd_config(&cmd, CMD6, 0x03b90100, READ, RESPONSE_48,
542 DATA_PRESENT_NONE, ENABLE, ENABLE);
544 if (host_send_cmd(&cmd) == SUCCESS) {
545 /* wait until in transfer mode */
546 while (mxcmci_trans_status()) {
552 diag_printf("Setting MMC High Speed Mode FAILED.\n");
558 int sdmmc_set_blklen(int len)
562 command_response_t response;
564 /* Configure CMD16 to set block length as 512 bytes. */
565 mxcmci_cmd_config(&cmd, CMD16, len, READ, RESPONSE_48,
566 DATA_PRESENT_NONE, ENABLE, ENABLE);
568 /* Issue command CMD16 to set block length as 512 bytes */
569 if (host_send_cmd(&cmd) == FAIL) {
570 diag_printf("%s: Can't set block length!(CMD16)\n",
572 esdhc_softreset(ESDHC_RESET_CMD_MSK);
581 int sdmmc_stop_transmission(void)
585 command_response_t response;
587 /* Comfigure command CMD12 for read stop */
588 mxcmci_cmd_config(&cmd, CMD12, 0, READ, RESPONSE_48,
589 DATA_PRESENT_NONE, ENABLE, ENABLE);
591 if (host_send_cmd(&cmd) == FAIL) {
592 //diag_printf("%s: Can't send CMD12!\n", __FUNCTION__);
593 //esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
594 //read_block_status = FAIL;
600 static unsigned int mmc_set_extendCSD(unsigned int ECSD_index, unsigned int value, unsigned int access_mode)
602 unsigned int argument = 0;
605 /* access mode: 0b01 set bits/ 0b10 clear bits/ 0b11 write bytes */
606 argument = (access_mode << 24) | (ECSD_index << 16) | (value << 8);
607 //argument = 0x1b30000;
609 mxcmci_cmd_config(&cmd, CMD6, argument, READ, RESPONSE_48,
610 DATA_PRESENT_NONE, ENABLE, ENABLE);
612 if(host_send_cmd(&cmd) == SUCCESS) {
615 //diag_printf("%s: Setting MMC boot Failed.\n", __FUNCTION__);
620 static void mmc_set_boot_partition_size(unsigned int value)
623 command_response_t response;
624 cyg_uint32 card_state = 0;
625 cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
627 mxcmci_cmd_config(&cmd, CMD62, 0XEFAC62EC, READ, RESPONSE_48,
628 DATA_PRESENT_NONE, ENABLE, ENABLE);
631 mxcmci_cmd_config(&cmd, CMD62, 0X00CBAEA7, READ, RESPONSE_48,
632 DATA_PRESENT_NONE, ENABLE, ENABLE);
635 mxcmci_cmd_config(&cmd, CMD62, value, READ, RESPONSE_48,
636 DATA_PRESENT, ENABLE, ENABLE);
640 cyg_uint32 emmc_set_boot_partition (cyg_uint32 *src_ptr, cyg_uint32 length)
642 cyg_uint32 status=FAIL;
644 unsigned int eMMCBootDataSize = (length / (128 * 1024)) + 1;
646 if (MMC_Spec_vers < 4)
649 /* read back 1KB data as we are programming to user are and want to aviod erasing MBR
650 * will be removed once we program Redboot to boot partition of the card
652 mmc_data_read(src_ptr, 0x400, 0);
654 /* Set boot partition */
655 /* 1. Configure CMD6 to write to EXT_CSD register for eMMC boot partition, Byte 179*/
656 /* boot partition: user area enable and r/w enable */
657 value = (0x7 << 3) | (0x7);
658 //value = (0x1 << 3) | (0x1);
659 status = mmc_set_extendCSD(179, value, 0x3);
661 return 1; /* failed */
664 /* 2. Set boot partition size: n*128KB */
665 value = eMMCBootDataSize;
666 //status = mmc_set_extendCSD(226, value, 0x3);
668 // return 1; /* failed */
670 //mmc_set_boot_partition_size(value);
672 //diag_printf("Boot partition size: 0x%xKB\n", eMMCBootDataSize * 128);
674 /* 3. Program to boot partition, default address is alway 0x0 */
675 status = mmc_data_write (src_ptr, eMMCBootDataSize*128*1024, 0);
677 return 1; /* failed */
680 while (mxcmci_trans_status());
682 /* 4. Clear boot partition access bits, to protect w/r of boot partition */
683 /* bit 6: send boot ack signal, boot partition: user area enable and r/w access disable */
684 //value = (0x1 << 6) | (0x1 << 3) | (0x0);
685 value = (0x1 << 6) | (0x7 << 3) | (0x0);
686 status = mmc_set_extendCSD(179, value, 0x3);
688 return 1; /* failed */
694 /* end of mxcmci_mmc.c */