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/infra/diag.h>
55 #include <cyg/io/mxcmci_host.h>
56 #include <cyg/io/mxcmci_core.h>
57 #include <cyg/io/mxcmci_mmc.h>
58 #include <cyg/io/mxc_mmc.h>
59 #include <cyg/hal/hal_intr.h>
61 static cyg_uint32 mmc_set_rca(void);
62 static cyg_uint32 mmc_set_bus_width(cyg_uint32 bus_width);
64 cyg_uint32 address_mode; /* Global variable for addressing mode */
66 cyg_uint32 mmc_init(cyg_uint32 bus_width)
68 cyg_uint32 status = FAIL;
69 cyg_uint32 spec_version;
70 /* Get CID number of MMC Card */
71 if (!mxcmci_get_cid()) {
72 /* Set RCA of the MMC Card */
74 flash_dprintf(FLASH_DEBUG_MAX, "%s: mmc_set_rca OK!",
76 /* Get Spec version supported by the card */
77 spec_version = mmc_get_spec_ver();
78 //diag_printf("SPEC Version: %d\n", spec_version);
80 /*Enable operating frequency */
81 host_cfg_clock(OPERATING_FREQ);
83 /*Put MMC in Transfer State */
84 if (!mxcmci_trans_prepare()) {
86 if (mmc_set_high_speed_mode()) {
90 /* Set block length for transfer */
91 //diag_printf("Send CMD to Set Block Length.\n");
92 if (sdmmc_set_blklen(BLK_LEN))
95 flash_dprintf(FLASH_DEBUG_MAX, "%s: mxcmci_trans_prepare OK!",
98 if (!mmc_set_bus_width(bus_width)) {
99 esdhc_base_pointer->protocol_control &= ~(0x3 << 1);
100 esdhc_base_pointer->protocol_control |= (bus_width >> 2) << 1;
102 diag_printf("Bus Width: %d\n",
114 cyg_uint32 mmc_data_read(cyg_uint32 *dest_ptr, cyg_uint32 length,
118 cyg_uint32 read_block_status = 0;
119 cyg_uint32 blk_len = BLK_LEN;
120 unsigned int SectorNum = 0;
122 /* Assing length of data to be read */
123 SectorNum = length / blk_len;
124 if ((length % blk_len) != 0)
126 /* hight capacity card uses sector mode */
130 /* wait until in transfer mode */
131 while (mxcmci_trans_status()) {
136 /* Configure interface block and number of blocks */
137 host_cfg_block(BLK_LEN, SectorNum);
139 if (SectorNum == 1) {
140 //diag_printf("Send CMD17...\n");
141 /* Comfigure command CMD17 for single block read */
142 mxcmci_cmd_config(&cmd, CMD17, offset, READ, RESPONSE_48,
143 DATA_PRESENT, ENABLE, ENABLE);
145 if (host_send_cmd(&cmd) == FAIL) {
146 diag_printf("%s: Can't send CMD17!\n", __FUNCTION__);
147 esdhc_softreset(ESDHC_RESET_CMD_MSK |
148 ESDHC_RESET_DAT_MSK);
149 read_block_status = FAIL;
152 //diag_printf("host_data_read! dest_ptr: 0%x \n", dest_ptr);
153 /* Call interface Data read function */
154 read_block_status = host_data_read(dest_ptr, BLK_LEN);
156 if (read_block_status) { /* fail */
157 //diag_printf("%s: Failed, read_block_status =%d\n", __FUNCTION__, read_block_status);
158 /* re-transfer if data transfer error occurs */
162 } else { /* read multi-blocks */
164 /* Comfigure command CMD18 for multiple block read */
165 mxcmci_cmd_config(&cmd, CMD18, offset, READ, RESPONSE_48,
166 DATA_PRESENT, ENABLE, ENABLE);
168 if (host_send_cmd(&cmd) == FAIL) {
169 diag_printf("%s: Can't send CMD18!\n", __FUNCTION__);
170 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
171 read_block_status = FAIL;
173 /* Call interface Data read function */
175 host_data_read(dest_ptr, BLK_LEN * SectorNum);
177 /* Comfigure command CMD12 for multi-block read stop */
178 mxcmci_cmd_config(&cmd, CMD12, 0, READ, RESPONSE_48,
179 DATA_PRESENT_NONE, ENABLE, ENABLE);
181 if (host_send_cmd(&cmd) == FAIL) {
182 diag_printf("%s: Can't send CMD12!\n",
184 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
185 //read_block_status = FAIL;
188 if (read_block_status) { /* fail */
189 //diag_printf("%s: Failed, read_block_status =%d\n", __FUNCTION__, read_block_status);
190 /* re-transfer if data transfer error occurs */
197 return read_block_status;
200 cyg_uint32 mmc_data_write(cyg_uint32 *src_ptr, cyg_uint32 length,
205 cyg_uint32 blk_len = BLK_LEN;
206 cyg_uint32 write_block_status = SUCCESS;
207 unsigned int SectorNum;
209 //diag_printf("%s: src: 0x%x, offset: 0x%x, length: 0x%x\n", __FUNCTION__, (unsigned int)src_ptr, offset, length);
210 /* Write data size aligned with block size */
211 SectorNum = length / blk_len;
212 if ((length % blk_len) != 0)
215 /* hight capacity card uses sector mode */
219 //need waiting until CARD out of Prg status, or will cause CMD25 timeout
224 while (mxcmci_trans_status()) {
228 //counter = StopCounter();
229 //diag_printf("counter: 0x%x\n",counter);
232 /* Configure interface block and number of blocks , SctorNum will decrease to zero after transfer */
233 host_cfg_block(BLK_LEN, SectorNum);
235 if (SectorNum == 1) {
236 //diag_printf("Send CMD24...\n");
237 /* Comfigure command CMD24 for single block write */
238 mxcmci_cmd_config(&cmd, CMD24, offset, WRITE, RESPONSE_48,
239 DATA_PRESENT, ENABLE, ENABLE);
241 if (host_send_cmd(&cmd) == FAIL) {
242 diag_printf("%s: Failed in configuring CMD24\n",
244 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
245 write_block_status = FAIL;
247 //HAL_DELAY_US(1000);
251 //diag_printf("Start host_data_write:\n");
252 /* Call interface write read function */
253 write_block_status = host_data_write(src_ptr, BLK_LEN);
254 //diag_printf("0x%x\n", esdhc_base_pointer->present_state);
256 if (write_block_status) { /* fail */
257 //diag_printf("transfer failed.(0x%x)\n", esdhc_base_pointer->block_attributes);
258 while (mxcmci_trans_status()) ;
259 //diag_printf("%s: Failed, write_block_status=%d\n", __FUNCTION__, write_block_status);
265 } else { /* multi-block write */
267 //diag_printf("Send CMD25...\n");
268 /* Comfigure command CMD25 for single block write */
269 mxcmci_cmd_config(&cmd, CMD25, offset, WRITE, RESPONSE_48,
270 DATA_PRESENT, ENABLE, ENABLE);
272 if (host_send_cmd(&cmd) == FAIL) {
273 //diag_printf("%s: Failed in configuring CMD25\n",
275 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
276 write_block_status = FAIL;
279 /* Call interface write read function */
281 host_data_write(src_ptr, SectorNum * BLK_LEN);
283 /* Comfigure command CMD12 for multi-block read stop */
284 mxcmci_cmd_config(&cmd, CMD12, 0, READ, RESPONSE_48,
285 DATA_PRESENT_NONE, ENABLE, ENABLE);
287 if (host_send_cmd(&cmd) == FAIL) {
288 diag_printf("%s: Can't send CMD12!\n",
290 esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
291 //write_block_status = FAIL;
294 if (write_block_status) { /* fail */
295 //diag_printf("%s: Failed, write_block_status=%d\n", __FUNCTION__, write_block_status);
296 while (mxcmci_trans_status());
303 return write_block_status;
306 cyg_uint32 mmc_data_erase(cyg_uint32 offset, cyg_uint32 size)
309 extern int Card_Mode;
310 cyg_uint8 startEraseBlockCmd = CMD35;
311 cyg_uint8 endEraseBlockCmd = CMD36;
313 cyg_uint32 startBlock = offset / BLK_LEN;
314 cyg_uint32 endBlock = (offset + size - 1) / BLK_LEN;
316 // diag_printf("card_data_erase\n");
317 if (Card_Mode == 0) {
318 startBlock *= BLK_LEN;
320 startEraseBlockCmd = CMD35;
321 endEraseBlockCmd = CMD36;
324 else if (Card_Mode == 1) {
325 startBlock *= BLK_LEN;
327 startEraseBlockCmd = CMD32;
328 endEraseBlockCmd = CMD33;
331 /* hight capacity card uses sector mode */
333 startBlock /= BLK_LEN;
336 // diag_printf("0x%x - 0x%x, size: 0x%x\n", startBlock, endBlock, size);
337 /* Configure start erase command to set first block */
338 mxcmci_cmd_config(&cmd, startEraseBlockCmd, startBlock, READ,
339 RESPONSE_48, DATA_PRESENT_NONE, ENABLE, ENABLE);
341 if ((ret = host_send_cmd(&cmd)) == SUCCESS) {
342 flash_dprintf(FLASH_DEBUG_MAX,
343 "%s: successful for host_send_cmd\n",
345 /* Configure end erase command to set end block */
346 mxcmci_cmd_config(&cmd, endEraseBlockCmd, endBlock, READ,
347 RESPONSE_48, DATA_PRESENT_NONE, ENABLE, ENABLE);
348 if ((ret = host_send_cmd(&cmd)) == SUCCESS) {
349 flash_dprintf(FLASH_DEBUG_MAX,
350 "%s: successful for host_send_cmd:2\n",
352 /* Comfigure command to start erase */
353 mxcmci_cmd_config(&cmd, CMD38, 0, READ, RESPONSE_48,
354 DATA_PRESENT_NONE, ENABLE, ENABLE);
355 if ((ret = host_send_cmd(&cmd)) == SUCCESS) {
356 flash_dprintf(FLASH_DEBUG_MAX,
357 "%s: successful for host_send_cmd:3\n",
359 //wait for completion
365 flash_dprintf(FLASH_DEBUG_MAX, "%s: Error return (%d)\n", __FUNCTION__,
370 cyg_uint32 mmc_voltage_validation(void)
373 command_response_t response;
374 cyg_uint32 voltage_validation_command = 0;
375 cyg_uint32 ocr_val = 0;
376 cyg_uint32 voltage_validation = FAIL;
378 ocr_val = (cyg_uint32) ((MMC_OCR_VALUE) & 0xFFFFFFFF);
380 while ((voltage_validation_command < MMCSD_READY_TIMEOUT)
381 && (voltage_validation != SUCCESS)) {
382 /* Configure CMD1 for MMC card */
383 mxcmci_cmd_config(&cmd, CMD1, ocr_val, READ, RESPONSE_48,
384 DATA_PRESENT_NONE, DISABLE, DISABLE);
386 /* Issue CMD1 to MMC card to determine OCR value */
387 if (host_send_cmd(&cmd) == FAIL) {
388 voltage_validation = FAIL;
391 /* Read Response from CMDRSP0 Register */
392 response.format = RESPONSE_48;
393 host_read_response(&response);
395 /* Check if card busy bit is cleared or not */
396 if (!(response.cmd_rsp0 & CARD_BUSY_BIT)) {
397 /* Iterate One more time */
398 voltage_validation_command++;
400 if ((response.cmd_rsp0 & MMC_OCR_HC_RES) ==
402 address_mode = SECT_MODE;
403 voltage_validation = SUCCESS;
404 } else if ((response.cmd_rsp0 & MMC_OCR_LC_RES)
406 address_mode = BYTE_MODE;
407 voltage_validation = SUCCESS;
414 return voltage_validation;
417 static cyg_uint32 mmc_set_rca(void)
420 cyg_uint32 card_state = 0;
421 cyg_uint32 rca_request = 0;
422 command_response_t response;
423 cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
425 /* Configure CMD3 for MMC card */
426 /* 32bit card address is expected as Argument */
427 mxcmci_cmd_config(&cmd, CMD3, card_address, READ, RESPONSE_48,
428 DATA_PRESENT_NONE, ENABLE, ENABLE);
430 /* Assigns relative address to the card
433 if (host_send_cmd(&cmd) == FAIL) {
438 /* Read Command response */
439 response.format = RESPONSE_48;
440 host_read_response(&response);
441 card_state = CURR_CARD_STATE(response.cmd_rsp0);
442 if (card_state == IDENT) {
443 rca_request = SUCCESS;
453 cyg_uint32 mmc_get_spec_ver(void)
456 cyg_uint32 mmc_spec_version;
458 if (card_get_csd() == FAIL) {
459 mmc_spec_version = 0;
461 mmc_spec_version = ((csd.csd3 && MMC_SPEC_VER) >> MMC_SPEC_VER_SHIFT);
464 return mmc_spec_version;
467 cyg_uint32 card_flash_query(void *data)
470 cyg_uint32 cid_request = FAIL;
471 command_response_t response;
473 /* Configure CMD2 for card */
474 mxcmci_cmd_config(&cmd, CMD2, NO_ARG, READ, RESPONSE_136,
475 DATA_PRESENT_NONE, ENABLE, DISABLE);
476 /* Issue CMD2 to card to determine CID contents */
477 if (host_send_cmd(&cmd) == FAIL) {
479 flash_dprintf(FLASH_DEBUG_MAX, "%s: can't send query command\n",
482 cyg_uint32 *d = (cyg_uint32 *) data;
483 /* Read Command response */
484 response.format = RESPONSE_136;
485 host_read_response(&response);
486 /* Assign CID values to mmc_cid structures */
487 *d++ = response.cmd_rsp0;
488 *d++ = response.cmd_rsp1;
489 *d++ = response.cmd_rsp2;
490 *d = response.cmd_rsp3;
492 /* Assign cid_request as SUCCESS */
493 cid_request = SUCCESS;
495 flash_dprintf(FLASH_DEBUG_MAX,
496 "%s(Success?=%d):(ID=0x%x: 0x%x, 0x%x, 0x%x)\n",
497 __FUNCTION__, cid_request, *(cyg_uint32 *) (data),
498 *(cyg_uint32 *) ((cyg_uint32) data + 4),
499 *(cyg_uint8 *) ((cyg_uint32) data + 8),
500 *(cyg_uint8 *) ((cyg_uint32) data + 12));
504 static cyg_uint32 mmc_set_bus_width(cyg_uint32 bus_width)
507 cyg_uint32 set_bus_width_status = FAIL;
509 if ((bus_width == 4) || (bus_width == 8) || (bus_width == 1)) {
511 /* Configure CMD6 to write to EXT_CSD register for BUS_WIDTH */
512 mxcmci_cmd_config(&cmd, CMD6, 0x03b70001 | ((bus_width >> 2) << 8), READ,
513 RESPONSE_48, DATA_PRESENT_NONE, ENABLE, ENABLE);
515 if (host_send_cmd(&cmd) == SUCCESS) {
516 set_bus_width_status = SUCCESS;
518 diag_printf("Setting MMC bus width failed.\n");
522 return set_bus_width_status;
525 cyg_uint32 mmc_set_high_speed_mode(void)
530 //diag_printf("Send CMD6 to Set High Speed Mode.\n");
531 /* Configure CMD6 to write to EXT_CSD register for BUS_WIDTH */
532 mxcmci_cmd_config(&cmd, CMD6, 0x03b90100, READ, RESPONSE_48,
533 DATA_PRESENT_NONE, ENABLE, ENABLE);
535 status = host_send_cmd(&cmd);
536 if (status == SUCCESS) {
537 /* wait until in transfer mode */
538 while (mxcmci_trans_status()) {
542 diag_printf("Setting MMC High Speed Mode FAILED.\n");
548 int sdmmc_set_blklen(int len)
553 /* Configure CMD16 to set block length as 512 bytes. */
554 mxcmci_cmd_config(&cmd, CMD16, len, READ, RESPONSE_48,
555 DATA_PRESENT_NONE, ENABLE, ENABLE);
557 /* Issue command CMD16 to set block length as 512 bytes */
558 if (host_send_cmd(&cmd) == FAIL) {
559 diag_printf("%s: Can't set block length!(CMD16)\n",
561 esdhc_softreset(ESDHC_RESET_CMD_MSK);
570 int sdmmc_stop_transmission(void)
574 /* Comfigure command CMD12 for read stop */
575 mxcmci_cmd_config(&cmd, CMD12, 0, READ, RESPONSE_48,
576 DATA_PRESENT_NONE, ENABLE, ENABLE);
578 if (host_send_cmd(&cmd) == FAIL) {
579 //diag_printf("%s: Can't send CMD12!\n", __FUNCTION__);
580 //esdhc_softreset(ESDHC_RESET_CMD_MSK | ESDHC_RESET_DAT_MSK);
581 //read_block_status = FAIL;
587 static unsigned int mmc_set_extendCSD(unsigned int ECSD_index, unsigned int value, unsigned int access_mode)
589 unsigned int argument = 0;
592 /* access mode: 0b01 set bits/ 0b10 clear bits/ 0b11 write bytes */
593 argument = (access_mode << 24) | (ECSD_index << 16) | (value << 8);
594 //argument = 0x1b30000;
596 mxcmci_cmd_config(&cmd, CMD6, argument, READ, RESPONSE_48,
597 DATA_PRESENT_NONE, ENABLE, ENABLE);
599 if(host_send_cmd(&cmd) == SUCCESS) {
602 //diag_printf("%s: Setting MMC boot Failed.\n", __FUNCTION__);
607 void mmc_set_boot_partition_size(unsigned int value)
611 mxcmci_cmd_config(&cmd, CMD62, 0XEFAC62EC, READ, RESPONSE_48,
612 DATA_PRESENT_NONE, ENABLE, ENABLE);
615 mxcmci_cmd_config(&cmd, CMD62, 0X00CBAEA7, READ, RESPONSE_48,
616 DATA_PRESENT_NONE, ENABLE, ENABLE);
619 mxcmci_cmd_config(&cmd, CMD62, value, READ, RESPONSE_48,
620 DATA_PRESENT, ENABLE, ENABLE);
624 cyg_uint32 emmc_set_boot_partition (cyg_uint32 *src_ptr, cyg_uint32 length)
626 cyg_uint32 status=FAIL;
628 unsigned int eMMCBootDataSize = (length / (128 * 1024)) + 1;
630 if (MMC_Spec_vers < 4)
633 /* read back 1KB data as we are programming to user are and want to aviod erasing MBR
634 * will be removed once we program Redboot to boot partition of the card
636 mmc_data_read(src_ptr, 0x400, 0);
638 /* Set boot partition */
639 /* 1. Configure CMD6 to write to EXT_CSD register for eMMC boot partition, Byte 179*/
640 /* boot partition: user area enable and r/w enable */
641 value = (0x7 << 3) | (0x7);
642 //value = (0x1 << 3) | (0x1);
643 status = mmc_set_extendCSD(179, value, 0x3);
645 return 1; /* failed */
648 /* 2. Set boot partition size: n*128KB */
649 value = eMMCBootDataSize;
650 //status = mmc_set_extendCSD(226, value, 0x3);
652 // return 1; /* failed */
654 //mmc_set_boot_partition_size(value);
656 //diag_printf("Boot partition size: 0x%xKB\n", eMMCBootDataSize * 128);
658 /* 3. Program to boot partition, default address is alway 0x0 */
659 status = mmc_data_write (src_ptr, eMMCBootDataSize*128*1024, 0);
661 return 1; /* failed */
664 while (mxcmci_trans_status());
666 /* 4. Clear boot partition access bits, to protect w/r of boot partition */
667 /* bit 6: send boot ack signal, boot partition: user area enable and r/w access disable */
668 //value = (0x1 << 6) | (0x1 << 3) | (0x0);
669 value = (0x1 << 6) | (0x7 << 3) | (0x0);
670 status = mmc_set_extendCSD(179, value, 0x3);
672 return 1; /* failed */
678 /* end of mxcmci_mmc.c */