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/hal/hal_soc.h>
58 #include <cyg/io/mxc_mmc.h>
60 host_register_ptr esdhc_base_pointer;
61 extern void mxc_mmc_init(unsigned int module_base);
63 static void esdhc_cmd_config(command_t *);
64 static int esdhc_wait_end_cmd_resp_intr(void);
65 static cyg_uint32 esdhc_check_response(void);
66 static void esdhc_wait_buf_rdy_intr(cyg_uint32, multi_single_block_select);
67 static void esdhc_wait_op_done_intr(cyg_uint32);
68 static cyg_uint32 esdhc_check_data(cyg_uint32, cyg_uint32, cyg_uint32);
69 static void esdhc_set_data_transfer_width(cyg_uint32 data_transfer_width);
70 static void esdhc_set_endianness(cyg_uint32 endian_mode);
71 static int esdhc_check_for_send_cmd(int data_present);
73 void host_reset(cyg_uint32 data_transfer_width, cyg_uint32 endian_mode)
77 /* Reset the entire host controller by writing 1 to RSTA bit of SYSCTRL Register */
78 esdhc_base_pointer->system_control |= ESDHC_SOFTWARE_RESET;
80 //use WDOG timer: 3 ms delay
81 hal_delay_us(3 * 1000);
83 /* Wait for clearance of CIHB and CDIHB Bits */
84 while (esdhc_base_pointer->present_state & ESDHC_CMD_INHIBIT) {
85 if (counter++ > 200) {
87 ("%s: something goes wrong with the DSDHC and int is not received!\n",
94 /* send 80 clock ticks for card to power up */
95 esdhc_base_pointer->system_control |= ESDHC_SOFTWARE_INIT;
97 /* Set data bus width of ESDCH */
98 esdhc_set_data_transfer_width(data_transfer_width);
100 /* Set Endianness of ESDHC */
101 esdhc_set_endianness(endian_mode);
105 void esdhc_softreset(cyg_uint32 mask)
107 //wait max timeout 100ms
108 cyg_uint32 timeout = 100;
110 esdhc_base_pointer->system_control |= mask;
112 /* hw clears the bit when it's done */
113 while (esdhc_base_pointer->system_control & mask) {
115 flash_dprintf(FLASH_DEBUG_MAX,
116 "%s:Reset 0x%X never complete!\n");
124 void host_init(cyg_uint32 base_address)
126 esdhc_base_pointer = (host_register_ptr) base_address;
128 flash_dprintf(FLASH_DEBUG_MAX, "%s: interface_esdc=%d\n", __FUNCTION__,
131 mxc_mmc_init(base_address);
134 void host_cfg_clock(sdhc_freq_t frequency)
136 unsigned int timeout = 9000;
137 /* Enable ipg_perclk, HCLK enable, IPG Clock enable. */
138 esdhc_base_pointer->system_control |= ESDHC_CLOCK_ENABLE;
140 esdhc_base_pointer->system_control |= 0xe0000; //set timeout counter
142 /* Clear DTOCV SDCLKFS bits, clear SD clk enable bit to change frequency */
143 esdhc_base_pointer->system_control &= ESDHC_FREQ_MASK;
145 /* Disable SD clock */
146 esdhc_base_pointer->system_control &= ~ESDHC_ENABLE;
148 if (frequency == IDENTIFICATION_FREQ) {
149 /* Input frequecy to eSDHC is 36 MHZ */
150 /* PLL3 is the source of input frequency */
151 /*Set DTOCV and SDCLKFS bit to get SD_CLK of frequency below 400 KHZ (70.31 KHZ) */
152 esdhc_base_pointer->system_control |= ESDHC_IDENT_FREQ;
153 } else if (frequency == OPERATING_FREQ) {
154 /*Set DTOCV and SDCLKFS bit to get SD_CLK of frequency around 25 MHz.(18 MHz) */
155 esdhc_base_pointer->system_control |= ESDHC_OPERT_FREQ;
158 /* Wait for clock to be steady */
159 while (((esdhc_base_pointer->present_state & 0x8) == 0) && (timeout != 0)) {
164 /* Enable SD clock */
165 esdhc_base_pointer->system_control |= ESDHC_ENABLE;
168 static void esdhc_set_data_transfer_width(cyg_uint32 data_transfer_width)
171 /* Set DWT bit of protocol control register according to bus_width */
172 esdhc_base_pointer->protocol_control &= ~0x6;
173 esdhc_base_pointer->protocol_control |= data_transfer_width;
177 static void esdhc_set_endianness(cyg_uint32 endian_mode)
180 /* Set DWT bit of protocol control register according to bus_width */
181 esdhc_base_pointer->protocol_control |= endian_mode;
185 cyg_uint32 host_send_cmd(command_t * cmd)
188 /* Clear Interrupt status register */
189 esdhc_base_pointer->interrupt_status = ESDHC_CLEAR_INTERRUPT;
190 //esdhc_base_pointer->interrupt_status = 0x117f01ff;
192 /* Enable Interrupt */
193 esdhc_base_pointer->interrupt_status_enable |= ESDHC_INTERRUPT_ENABLE;
194 //esdhc_base_pointer->interrupt_status_enable |= 0x007f0123;
197 if (esdhc_check_for_send_cmd(cmd->data_present)) {
198 diag_printf("Data/Cmd Line Busy.\n");
203 /* Configure Command */
204 esdhc_cmd_config(cmd);
206 /* Wait interrupt (END COMMAND RESPONSE) */
207 //diag_printf("Wait for CMD Response.\n");
208 if (esdhc_wait_end_cmd_resp_intr()) {
209 diag_printf("Wait CMD (%d) RESPONSE TIMEOUT.\n", cmd->command);
212 //Just test for Erase functionality:Lewis-20080505:
213 if (cmd->command == CMD38) {
214 flash_dprintf(FLASH_DEBUG_MAX, "%s:Check DAT0 status:\n",
216 //while(((esdhc_base_pointer->present_state) & 0x01000004)){
217 // flash_dprintf(FLASH_DEBUG_MAX,".");
218 // hal_delay_us(1000);
220 /* I'm not sure the minimum value of delay */
221 hal_delay_us(100000);
222 hal_delay_us(100000);
223 hal_delay_us(100000);
224 flash_dprintf(FLASH_DEBUG_MAX,
225 "\nCheck DAT0 status DONE: present_state=%x\n",
226 (cyg_uint32) (esdhc_base_pointer->present_state));
229 /* Mask all interrupts */
230 //esdhc_base_pointer->interrupt_signal_enable =0;
232 /* Check if an error occured */
233 return esdhc_check_response();
236 static void esdhc_cmd_config(command_t * cmd)
238 unsigned int transfer_type;
240 /* Write Command Argument in Command Argument Register */
241 esdhc_base_pointer->command_argument = cmd->arg;
243 /* *Configure e-SDHC Register value according to Command */
244 transfer_type = (((cmd->data_transfer) << DATA_TRANSFER_SHIFT) |
245 ((cmd->response_format) << RESPONSE_FORMAT_SHIFT) |
246 ((cmd->data_present) << DATA_PRESENT_SHIFT) |
247 ((cmd->crc_check) << CRC_CHECK_SHIFT) |
248 ((cmd->cmdindex_check) << CMD_INDEX_CHECK_SHIFT) |
249 ((cmd->command) << CMD_INDEX_SHIFT) |
251 block_count_enable_check) <<
252 BLOCK_COUNT_ENABLE_SHIFT) | ((cmd->
253 multi_single_block) <<
254 MULTI_SINGLE_BLOCK_SELECT_SHIFT));
256 esdhc_base_pointer->command_transfer_type = transfer_type;
258 //diag_printf("arg: 0x%x | tp: 0x%x\n", esdhc_base_pointer->command_argument, esdhc_base_pointer->command_transfer_type);
262 static int esdhc_wait_end_cmd_resp_intr(void)
264 /* Wait interrupt (END COMMAND RESPONSE) */
265 cyg_uint32 i = 50000;
267 ((esdhc_base_pointer->
268 interrupt_status) & ESDHC_STATUS_END_CMD_RESP_TIME_MSK) && i) {
271 //diag_printf("0x%x\n", esdhc_base_pointer->interrupt_status);
275 ((esdhc_base_pointer->
276 interrupt_status) & ESDHC_STATUS_END_CMD_RESP_TIME_MSK)) {
277 //diag_printf("%s: can't get END COMMAND RESPONSE! Tried %d times\n", __FUNCTION__, (5000000-i));
284 static cyg_uint32 esdhc_check_response(void)
286 cyg_uint32 status = FAIL;
288 /* Check whether the interrupt is an END_CMD_RESP
289 * or a response time out or a CRC error
291 if ((esdhc_base_pointer->
292 interrupt_status & ESDHC_STATUS_END_CMD_RESP_MSK)
293 && !(esdhc_base_pointer->
294 interrupt_status & ESDHC_STATUS_TIME_OUT_RESP_MSK)
295 && !(esdhc_base_pointer->
296 interrupt_status & ESDHC_STATUS_RESP_CRC_ERR_MSK)
297 && !(esdhc_base_pointer->
298 interrupt_status & ESDHC_STATUS_RESP_INDEX_ERR_MSK)) {
302 //diag_printf("Warning: Check CMD response, Intr Status: 0x%x\n", esdhc_base_pointer->interrupt_status);
310 void host_read_response(command_response_t * cmd_resp)
312 /* get response values from e-SDHC CMDRSP registers. */
313 cmd_resp->cmd_rsp0 = (cyg_uint32) esdhc_base_pointer->command_response0;
314 cmd_resp->cmd_rsp1 = (cyg_uint32) esdhc_base_pointer->command_response1;
315 cmd_resp->cmd_rsp2 = (cyg_uint32) esdhc_base_pointer->command_response2;
316 cmd_resp->cmd_rsp3 = (cyg_uint32) esdhc_base_pointer->command_response3;
319 static void esdhc_wait_buf_rdy_intr(cyg_uint32 mask,
320 multi_single_block_select
324 /* Wait interrupt (BUF_READ_RDY) */
327 for (i = 3000; i > 0; i--) {
328 if (esdhc_base_pointer->interrupt_status & mask) {
334 if (multi_single_block == MULTIPLE
335 && esdhc_base_pointer->interrupt_status & mask)
336 esdhc_base_pointer->interrupt_status |= mask;
338 flash_dprintf(FLASH_DEBUG_MAX, "%s:Debug: tried %d times\n",
339 __FUNCTION__, (3000 - i));
343 static void esdhc_wait_op_done_intr(cyg_uint32 transfer_mask)
345 /* Wait interrupt (Transfer Complete) */
348 while (!(esdhc_base_pointer->interrupt_status & transfer_mask)) ;
350 //diag_printf("Wait OP Done Failed.\n");
351 //flash_dprintf(FLASH_DEBUG_MAX,"%s:Debug: tried %d times\n", __FUNCTION__, (3001-i));
355 static cyg_uint32 esdhc_check_data(cyg_uint32 op_done_mask,
356 cyg_uint32 read_time_out_mask,
357 cyg_uint32 read_crc_err_mask)
360 cyg_uint32 status = FAIL;
362 /* Check whether the interrupt is an OP_DONE
363 * or a data time out or a CRC error */
364 if ((esdhc_base_pointer->interrupt_status & op_done_mask) &&
365 !(esdhc_base_pointer->interrupt_status & read_time_out_mask) &&
366 !(esdhc_base_pointer->interrupt_status & read_crc_err_mask)) {
370 //diag_printf("Warning: Check data, interrupt_status=%X\n", (esdhc_base_pointer->interrupt_status));
376 void host_cfg_block(cyg_uint32 blk_len, cyg_uint32 nob)
378 /* Configre block Attributes register */
379 esdhc_base_pointer->block_attributes =
380 ((nob << 16) | (blk_len & 0xffff));
382 //diag_printf("nob: 0x%x, block_attributes: 0x%x\n", nob, esdhc_base_pointer->block_attributes);
384 /* Set Read Water Mark Level register */
385 esdhc_base_pointer->watermark_level = WRITE_READ_WATER_MARK_LEVEL;
388 cyg_uint32 host_data_read(cyg_uint32 * dest_ptr, cyg_uint32 read_len)
391 cyg_uint32 status = FAIL;
392 unsigned int len = WRITE_READ_WATER_MARK_LEVEL & 0xff;
395 /* Enable Interrupt */
396 esdhc_base_pointer->interrupt_status_enable |= ESDHC_INTERRUPT_ENABLE;
398 for (j = 0; j < read_len / (len * 4); j++) {
400 /* wait for read fifo full (equal or beyond the watermark) */
401 while (!(esdhc_base_pointer->present_state & (1 << 11))) ;
403 //counter = StopCounter();
404 //diag_printf("counter: 0x%x\n", counter);
406 for (k = 0; k < len; k++) {
407 *dest_ptr++ = esdhc_base_pointer->data_buffer_access;
411 /* Wait for transfer complete operation interrupt */
412 esdhc_wait_op_done_intr(ESDHC_STATUS_TRANSFER_COMPLETE_MSK);
414 /* Check for status errors */
416 esdhc_check_data(ESDHC_STATUS_TRANSFER_COMPLETE_MSK,
417 ESDHC_STATUS_TIME_OUT_READ, ESDHC_STATUS_READ_CRC_ERR_MSK);
423 cyg_uint32 host_data_write(cyg_uint32 * src_ptr, cyg_uint32 write_len)
426 cyg_uint32 status = FAIL;
427 unsigned int len = (WRITE_READ_WATER_MARK_LEVEL >> 16) & 0xff;
428 //cyg_uint32 counter = 0;
430 /* Enable Interrupt */
431 esdhc_base_pointer->interrupt_status_enable |= ESDHC_INTERRUPT_ENABLE;
434 for (i = 0; i < (write_len) / (len * 4); i++) {
435 /* wait for write fifo empty (equal or less than the watermark), BWEN */
436 while (!(esdhc_base_pointer->present_state & (1 << 10))) ;
438 for (k = 0; k < len; k++) {
439 esdhc_base_pointer->data_buffer_access = *src_ptr++;
444 /* Wait for transfer complete operation interrupt */
445 esdhc_wait_op_done_intr(ESDHC_STATUS_TRANSFER_COMPLETE_MSK);
447 //counter = StopCounter();
448 //diag_printf("0x%x\n", counter);
450 /* Check for status errors */
452 esdhc_check_data(ESDHC_STATUS_TRANSFER_COMPLETE_MSK,
453 ESDHC_STATUS_TIME_OUT_READ, ESDHC_STATUS_READ_CRC_ERR_MSK);
459 static int esdhc_check_for_send_cmd(int data_present)
462 int status = SUCCESS;
465 /* Wait for the command line to be free (poll the CIHB bit of
466 * the present state register.
469 while (((esdhc_base_pointer->present_state & 0x1) == 0x1) && counter--) {
476 /* Wait for the data line to be free (poll the CDIHB bit of
477 * the present state register.
480 if (data_present == DATA_PRESENT) {
481 while (((esdhc_base_pointer->present_state & 0x2) == 0x2) && counter--) {