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/hal/hal_soc.h>
59 #include <cyg/io/mxc_mmc.h>
61 host_register_ptr esdhc_base_pointer;
62 extern void mxc_mmc_init(unsigned int module_base);
64 static void esdhc_cmd_config(command_t *);
65 static int esdhc_wait_end_cmd_resp_intr(void);
66 static cyg_uint32 esdhc_check_response(void);
67 static void esdhc_wait_buf_rdy_intr(cyg_uint32, multi_single_block_select);
68 static void esdhc_wait_op_done_intr(cyg_uint32);
69 static cyg_uint32 esdhc_check_data(cyg_uint32, cyg_uint32, cyg_uint32);
70 static void esdhc_set_data_transfer_width(cyg_uint32 data_transfer_width);
71 static void esdhc_set_endianness(cyg_uint32 endian_mode);
72 static int esdhc_check_for_send_cmd(int data_present);
74 void host_reset(cyg_uint32 data_transfer_width, cyg_uint32 endian_mode)
78 /* Reset the entire host controller by writing 1 to RSTA bit of SYSCTRL Register */
79 esdhc_base_pointer->system_control |= ESDHC_SOFTWARE_RESET;
81 //use WDOG timer: 3 ms delay
82 hal_delay_us(3 * 1000);
84 /* Wait for clearance of CIHB and CDIHB Bits */
85 while (esdhc_base_pointer->present_state & ESDHC_CMD_INHIBIT) {
86 if (counter++ > 200) {
88 ("%s: something goes wrong with the DSDHC and int is not received!\n",
95 /* send 80 clock ticks for card to power up */
96 esdhc_base_pointer->system_control |= ESDHC_SOFTWARE_INIT;
98 /* Set data bus width of ESDCH */
99 esdhc_set_data_transfer_width(data_transfer_width);
101 /* Set Endianness of ESDHC */
102 esdhc_set_endianness(endian_mode);
106 void esdhc_softreset(cyg_uint32 mask)
108 //wait max timeout 100ms
109 cyg_uint32 timeout = 100;
111 esdhc_base_pointer->system_control |= mask;
113 /* hw clears the bit when it's done */
114 while (esdhc_base_pointer->system_control & mask) {
116 flash_dprintf(FLASH_DEBUG_MAX, "%s: Reset did not complete\n",
125 void host_init(cyg_uint32 base_address)
127 esdhc_base_pointer = (host_register_ptr) base_address;
129 flash_dprintf(FLASH_DEBUG_MAX, "%s: interface_esdc=%d\n", __FUNCTION__,
132 mxc_mmc_init(base_address);
135 void host_cfg_clock(sdhc_freq_t frequency)
137 unsigned int timeout = 9000;
138 /* Enable ipg_perclk, HCLK enable, IPG Clock enable. */
139 esdhc_base_pointer->system_control |= ESDHC_CLOCK_ENABLE;
141 esdhc_base_pointer->system_control |= 0xe0000; //set timeout counter
143 /* Clear DTOCV SDCLKFS bits, clear SD clk enable bit to change frequency */
144 esdhc_base_pointer->system_control &= ESDHC_FREQ_MASK;
146 /* Disable SD clock */
147 esdhc_base_pointer->system_control &= ~ESDHC_ENABLE;
149 if (frequency == IDENTIFICATION_FREQ) {
150 /* Input frequecy to eSDHC is 36 MHZ */
151 /* PLL3 is the source of input frequency */
152 /*Set DTOCV and SDCLKFS bit to get SD_CLK of frequency below 400 KHZ (70.31 KHZ) */
153 esdhc_base_pointer->system_control |= ESDHC_IDENT_FREQ;
154 } else if (frequency == OPERATING_FREQ) {
155 /*Set DTOCV and SDCLKFS bit to get SD_CLK of frequency around 25 MHz.(18 MHz) */
156 esdhc_base_pointer->system_control |= ESDHC_OPERT_FREQ;
159 /* Wait for clock to be steady */
160 while (((esdhc_base_pointer->present_state & 0x8) == 0) && (timeout != 0)) {
165 /* Enable SD clock */
166 esdhc_base_pointer->system_control |= ESDHC_ENABLE;
169 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;
176 static void esdhc_set_endianness(cyg_uint32 endian_mode)
178 /* Set DWT bit of protocol control register according to bus_width */
179 esdhc_base_pointer->protocol_control |= endian_mode;
182 cyg_uint32 host_send_cmd(command_t * cmd)
185 /* Clear Interrupt status register */
186 esdhc_base_pointer->interrupt_status = ESDHC_CLEAR_INTERRUPT;
187 //esdhc_base_pointer->interrupt_status = 0x117f01ff;
189 /* Enable Interrupt */
190 esdhc_base_pointer->interrupt_status_enable |= ESDHC_INTERRUPT_ENABLE;
191 //esdhc_base_pointer->interrupt_status_enable |= 0x007f0123;
194 if (esdhc_check_for_send_cmd(cmd->data_present)) {
195 diag_printf("Data/Cmd Line Busy.\n");
200 /* Configure Command */
201 esdhc_cmd_config(cmd);
203 /* Wait interrupt (END COMMAND RESPONSE) */
204 //diag_printf("Wait for CMD Response.\n");
205 if (esdhc_wait_end_cmd_resp_intr()) {
206 diag_printf("Wait CMD (%d) RESPONSE TIMEOUT.\n", cmd->command);
209 //Just test for Erase functionality:Lewis-20080505:
210 if (cmd->command == CMD38) {
211 flash_dprintf(FLASH_DEBUG_MAX, "%s:Check DAT0 status:\n",
213 //while(((esdhc_base_pointer->present_state) & 0x01000004)){
214 // flash_dprintf(FLASH_DEBUG_MAX,".");
215 // hal_delay_us(1000);
217 /* I'm not sure the minimum value of delay */
218 hal_delay_us(100000);
219 hal_delay_us(100000);
220 hal_delay_us(100000);
221 flash_dprintf(FLASH_DEBUG_MAX,
222 "\nCheck DAT0 status DONE: present_state=%x\n",
223 (cyg_uint32) (esdhc_base_pointer->present_state));
226 /* Mask all interrupts */
227 //esdhc_base_pointer->interrupt_signal_enable =0;
229 /* Check if an error occured */
230 return esdhc_check_response();
233 static void esdhc_cmd_config(command_t * cmd)
235 unsigned int transfer_type;
237 /* Write Command Argument in Command Argument Register */
238 esdhc_base_pointer->command_argument = cmd->arg;
240 /* *Configure e-SDHC Register value according to Command */
241 transfer_type = (((cmd->data_transfer) << DATA_TRANSFER_SHIFT) |
242 ((cmd->response_format) << RESPONSE_FORMAT_SHIFT) |
243 ((cmd->data_present) << DATA_PRESENT_SHIFT) |
244 ((cmd->crc_check) << CRC_CHECK_SHIFT) |
245 ((cmd->cmdindex_check) << CMD_INDEX_CHECK_SHIFT) |
246 ((cmd->command) << CMD_INDEX_SHIFT) |
248 block_count_enable_check) <<
249 BLOCK_COUNT_ENABLE_SHIFT) | ((cmd->
250 multi_single_block) <<
251 MULTI_SINGLE_BLOCK_SELECT_SHIFT));
253 esdhc_base_pointer->command_transfer_type = transfer_type;
255 //diag_printf("arg: 0x%x | tp: 0x%x\n", esdhc_base_pointer->command_argument, esdhc_base_pointer->command_transfer_type);
258 static int esdhc_wait_end_cmd_resp_intr(void)
260 /* Wait interrupt (END COMMAND RESPONSE) */
261 cyg_uint32 i = 50000;
263 ((esdhc_base_pointer->
264 interrupt_status) & ESDHC_STATUS_END_CMD_RESP_TIME_MSK) && i) {
267 //diag_printf("0x%x\n", esdhc_base_pointer->interrupt_status);
271 ((esdhc_base_pointer->
272 interrupt_status) & ESDHC_STATUS_END_CMD_RESP_TIME_MSK)) {
273 //diag_printf("%s: can't get END COMMAND RESPONSE! Tried %d times\n", __FUNCTION__, (5000000-i));
280 static cyg_uint32 esdhc_check_response(void)
282 cyg_uint32 status = FAIL;
284 /* Check whether the interrupt is an END_CMD_RESP
285 * or a response time out or a CRC error
287 if ((esdhc_base_pointer->
288 interrupt_status & ESDHC_STATUS_END_CMD_RESP_MSK)
289 && !(esdhc_base_pointer->
290 interrupt_status & ESDHC_STATUS_TIME_OUT_RESP_MSK)
291 && !(esdhc_base_pointer->
292 interrupt_status & ESDHC_STATUS_RESP_CRC_ERR_MSK)
293 && !(esdhc_base_pointer->
294 interrupt_status & ESDHC_STATUS_RESP_INDEX_ERR_MSK)) {
298 //diag_printf("Warning: Check CMD response, Intr Status: 0x%x\n", esdhc_base_pointer->interrupt_status);
305 void host_read_response(command_response_t * cmd_resp)
307 /* get response values from e-SDHC CMDRSP registers. */
308 cmd_resp->cmd_rsp0 = (cyg_uint32) esdhc_base_pointer->command_response0;
309 cmd_resp->cmd_rsp1 = (cyg_uint32) esdhc_base_pointer->command_response1;
310 cmd_resp->cmd_rsp2 = (cyg_uint32) esdhc_base_pointer->command_response2;
311 cmd_resp->cmd_rsp3 = (cyg_uint32) esdhc_base_pointer->command_response3;
314 static void __attribute__((unused)) esdhc_wait_buf_rdy_intr(cyg_uint32 mask,
315 multi_single_block_select
319 /* Wait interrupt (BUF_READ_RDY) */
322 for (i = 3000; i > 0; i--) {
323 if (esdhc_base_pointer->interrupt_status & mask) {
329 if (multi_single_block == MULTIPLE
330 && esdhc_base_pointer->interrupt_status & mask)
331 esdhc_base_pointer->interrupt_status |= mask;
333 flash_dprintf(FLASH_DEBUG_MAX, "%s:Debug: tried %d times\n",
334 __FUNCTION__, (3000 - i));
338 static void esdhc_wait_op_done_intr(cyg_uint32 transfer_mask)
340 /* Wait interrupt (Transfer Complete) */
342 while (!(esdhc_base_pointer->interrupt_status & transfer_mask)) ;
344 //diag_printf("Wait OP Done Failed.\n");
345 //flash_dprintf(FLASH_DEBUG_MAX,"%s:Debug: tried %d times\n", __FUNCTION__, (3001-i));
348 static cyg_uint32 esdhc_check_data(cyg_uint32 op_done_mask,
349 cyg_uint32 read_time_out_mask,
350 cyg_uint32 read_crc_err_mask)
353 cyg_uint32 status = FAIL;
355 /* Check whether the interrupt is an OP_DONE
356 * or a data time out or a CRC error */
357 if ((esdhc_base_pointer->interrupt_status & op_done_mask) &&
358 !(esdhc_base_pointer->interrupt_status & read_time_out_mask) &&
359 !(esdhc_base_pointer->interrupt_status & read_crc_err_mask)) {
363 //diag_printf("Warning: Check data, interrupt_status=%X\n", (esdhc_base_pointer->interrupt_status));
369 void host_cfg_block(cyg_uint32 blk_len, cyg_uint32 nob)
371 /* Configre block Attributes register */
372 esdhc_base_pointer->block_attributes =
373 ((nob << 16) | (blk_len & 0xffff));
375 //diag_printf("nob: 0x%x, block_attributes: 0x%x\n", nob, esdhc_base_pointer->block_attributes);
377 /* Set Read Water Mark Level register */
378 esdhc_base_pointer->watermark_level = WRITE_READ_WATER_MARK_LEVEL;
381 cyg_uint32 host_data_read(cyg_uint32 * dest_ptr, cyg_uint32 read_len)
384 cyg_uint32 status = FAIL;
385 unsigned int len = WRITE_READ_WATER_MARK_LEVEL & 0xff;
388 /* Enable Interrupt */
389 esdhc_base_pointer->interrupt_status_enable |= ESDHC_INTERRUPT_ENABLE;
391 for (j = 0; j < read_len / (len * 4); j++) {
393 /* wait for read fifo full (equal or beyond the watermark) */
394 while (!(esdhc_base_pointer->present_state & (1 << 11))) ;
396 //counter = StopCounter();
397 //diag_printf("counter: 0x%x\n", counter);
399 for (k = 0; k < len; k++) {
400 *dest_ptr++ = esdhc_base_pointer->data_buffer_access;
404 /* Wait for transfer complete operation interrupt */
405 esdhc_wait_op_done_intr(ESDHC_STATUS_TRANSFER_COMPLETE_MSK);
407 /* Check for status errors */
409 esdhc_check_data(ESDHC_STATUS_TRANSFER_COMPLETE_MSK,
410 ESDHC_STATUS_TIME_OUT_READ, ESDHC_STATUS_READ_CRC_ERR_MSK);
416 cyg_uint32 host_data_write(cyg_uint32 * src_ptr, cyg_uint32 write_len)
419 cyg_uint32 status = FAIL;
420 unsigned int len = (WRITE_READ_WATER_MARK_LEVEL >> 16) & 0xff;
421 //cyg_uint32 counter = 0;
423 /* Enable Interrupt */
424 esdhc_base_pointer->interrupt_status_enable |= ESDHC_INTERRUPT_ENABLE;
427 for (i = 0; i < (write_len) / (len * 4); i++) {
428 /* wait for write fifo empty (equal or less than the watermark), BWEN */
429 while (!(esdhc_base_pointer->present_state & (1 << 10))) ;
431 for (k = 0; k < len; k++) {
432 esdhc_base_pointer->data_buffer_access = *src_ptr++;
437 /* Wait for transfer complete operation interrupt */
438 esdhc_wait_op_done_intr(ESDHC_STATUS_TRANSFER_COMPLETE_MSK);
440 //counter = StopCounter();
441 //diag_printf("0x%x\n", counter);
443 /* Check for status errors */
445 esdhc_check_data(ESDHC_STATUS_TRANSFER_COMPLETE_MSK,
446 ESDHC_STATUS_TIME_OUT_READ, ESDHC_STATUS_READ_CRC_ERR_MSK);
452 static int __attribute__((unused)) esdhc_check_for_send_cmd(int data_present)
455 int status = SUCCESS;
458 /* Wait for the command line to be free (poll the CIHB bit of
459 * the present state register.
462 while (((esdhc_base_pointer->present_state & 0x1) == 0x1) && counter--) {
469 /* Wait for the data line to be free (poll the CDIHB bit of
470 * the present state register.
473 if (data_present == DATA_PRESENT) {
474 while (((esdhc_base_pointer->present_state & 0x2) == 0x2) && counter--) {