56b7e41ff65c0c517f112555d6ec256820752569
[karo-tx-redboot.git] / packages / devs / flash / arm / mxc / v2_0 / src / mxcmci_core.c
1 // ==========================================================================
2 //
3 //   mxcmci_core.c
4 //   (c) 2008, Freescale
5 //
6 //   MMC card driver for MXC platform
7 //
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.
13 //
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.
17 //
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
21 // for more details.
22 //
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.
26 //
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.
33 //
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.
36 //
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####
43 //
44 // Author(s):    Lewis Liu <weizhi.liu@freescale.com>
45 // Contributors: Lewis Liu <weizhi.liu@freescale.com>
46 // Date:         2008-05-13 Initial version
47 // Purpose:
48 // Description:
49 //
50 //####DESCRIPTIONEND####
51 //
52 //==========================================================================
53
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>
59
60 static cyg_uint32 csd_get_value(cyg_uint32 * pcsd, cyg_uint32 start_bit,
61                 cyg_uint32 end_bit);
62
63 #define MMCSD_INIT_DELAY 64
64
65 cyg_uint32 Card_rca = 0x1;    /* Relative Card Address */
66 card_ident Card_identification;    /* Card Identification Data */
67 card_type Card_type;        /* Card Type */
68 cyg_uint32 MMC_Spec_vers = 0x1;        /* Spec vers used for MMC */
69 card_specific_data csd;        /* Global variable for Card Specific Data */
70 cyg_uint32 Card_capacity_size = 0;    /*Card capacity size */
71 cyg_uint32 CCC = 0;        /* Card Command Class */
72 int Card_Mode = 2;
73 int HighCapacityCard = 0;
74
75 /*==========================================================================
76                                     Global FUNCTIONS
77 ==========================================================================*/
78
79 cyg_uint32 mxcmci_init(cyg_uint32 bus_width, cyg_uint32 base_address)
80 {
81     cyg_uint32 init_status = FAIL;
82
83     flash_dprintf(FLASH_DEBUG_MAX, "%s:try to init base address...\n",
84               __FUNCTION__);
85     /* initialize Interface Controller */
86     host_init(base_address);
87     flash_dprintf(FLASH_DEBUG_MAX, "%s:try to software reset...\n",
88               __FUNCTION__);
89
90     /* Software Reset to Interface Controller */
91     host_reset(ESDHC_ONE_BIT_SUPPORT, ESDHC_LITTLE_ENDIAN_MODE);
92     flash_dprintf(FLASH_DEBUG_MAX, "%s:try to set identification freq...\n",
93               __FUNCTION__);
94
95     /* Enable Identification Frequency */
96     host_cfg_clock(IDENTIFICATION_FREQ);
97
98     /* Add delay of 2 msec, let mmc/sd card to initialize */
99     hal_delay_us(2 * 1000);
100
101     flash_dprintf(FLASH_DEBUG_MAX, "%s:try to software resetto card...\n",
102               __FUNCTION__);
103
104     //diag_printf("SW Reset...\n");
105     /* Issue Software Reset to card */
106     if (mxcmci_software_reset())
107         return FAIL;
108
109     //diag_printf("Check Card...\n");
110
111     /* Check if the card is SD Memory Card */
112     if (!sd_voltage_validation()) {
113         flash_dprintf(FLASH_DEBUG_MAX, "%s:try to verify SD card...\n",
114                   __FUNCTION__);
115         /* Call SD Initialization Function */
116         init_status = sd_init(bus_width);
117         Card_type =
118             ((csd.csd3 & CSD_STRUCT_MSK) ? SD_CSD_2_0 : SD_CSD_1_0);
119         Card_Mode = 1;
120         /* Card Command Class */
121         CCC = csd_get_value(&csd, 84, 95);
122     } else {
123         flash_dprintf(FLASH_DEBUG_MAX, "%s:try to verify MMC card...\n",
124                   __FUNCTION__);
125         /* Check if the card is MMC Memory Card */
126         if (!mmc_voltage_validation()) {
127
128             /* Call MMC Initialization Function */
129             init_status = mmc_init(bus_width);
130             Card_Mode = 0;
131             Card_type = ((csd.csd3 & CSD_STRUCT_MSK) >> CSD_STRUCT_SHIFT) + SD_CSD_2_0;
132             MMC_Spec_vers = (csd.csd3 & MMC_CSD_SPEC_VERS_MASK) >> MMC_CSD_SPEC_VERS_SHIFT;
133             /* Card Command Class */
134             CCC = csd_get_value(&csd, 84, 95);
135         }
136     }
137
138     return init_status;
139 }
140
141 /*==========================================================================
142 FUNCTION: static cyg_uint32 card_get_csd (void)
143 DESCRIPTION:
144    this function will read MMC/SD CSD register and store in the global Variable.
145
146 ARGUMENTS PASSED:
147    None
148
149 RETURN VALUE:
150    cyg_uint32
151
152 PRE-CONDITIONS:
153    None
154
155 POST-CONDITIONS:
156    None
157
158 Detailed Description:
159   1.Send CMD9 to get CSD value of MMC/SD Card.
160   2.Extract CSD value from CMDRSP0,CMDRSP1,CMDRSP2,CMDRSP3 registers.
161 ==============================================================================*/
162 cyg_uint32 card_get_csd(void)
163 {
164
165     command_t cmd;
166     command_response_t response;
167     cyg_uint32 status = FAIL;
168     cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
169
170     /* Configure CMD9 for MMC/SD card */
171     /* 16bit card address is expected as Argument */
172     mxcmci_cmd_config(&cmd, CMD9, card_address, READ, RESPONSE_136,
173               DATA_PRESENT_NONE, ENABLE, DISABLE);
174
175     /* Issue Command CMD9 to Extrace CSD register contents     */
176
177     if (host_send_cmd(&cmd) != FAIL) {
178         /* Read Command response */
179         response.format = RESPONSE_136;
180         host_read_response(&response);
181
182         /* Assign Response to CSD Strcuture */
183         csd.csd0 = response.cmd_rsp0;
184         csd.csd1 = response.cmd_rsp1;
185         csd.csd2 = response.cmd_rsp2;
186         csd.csd3 = response.cmd_rsp3;
187
188         flash_dprintf(FLASH_DEBUG_MAX, "CSD:%x:%x:%x:%x\n", csd.csd0,
189                   csd.csd1, csd.csd2, csd.csd3);
190         status = SUCCESS;
191     } else {
192         diag_printf("Get CSD Failed.\n");
193     }
194
195     return status;
196
197 }
198
199 static cyg_uint32 csd_get_value(cyg_uint32 * pcsd, cyg_uint32 start_bit,
200                 cyg_uint32 end_bit)
201 {
202     cyg_uint32 index = (start_bit / 32);
203     cyg_uint32 end_index = (end_bit / 32);
204     cyg_uint32 offset = (start_bit - 8) % 32;
205     cyg_uint32 end_offset = (end_bit - 8) % 32;
206     cyg_uint32 value;
207     cyg_uint32 temp;
208     //pcsd = &(csd.csd0);
209     flash_dprintf(FLASH_DEBUG_MAX,
210               "start_bit=%d, end_bit=%d, index=%d, end_index=%d, offset=%d\n",
211               start_bit, end_bit, index, end_index, offset);
212
213     if (index == end_index) {
214         flash_dprintf(FLASH_DEBUG_MAX, "onl1y in index register\n");
215         value =
216             (*((cyg_uint32 *) ((cyg_uint32) pcsd + (index << 2)))) &
217             ((1 << (end_offset + 1)) - (1 << offset));
218         value = (value >> offset);
219     } else {
220         flash_dprintf(FLASH_DEBUG_MAX, "index and index+1 registers\n");
221         value =
222             *((cyg_uint32 *) ((cyg_uint32) pcsd +
223                       (index << 2))) & (0xFFFFFFFF -
224                             (1 << offset) + 1);
225         value = (value >> offset);
226         temp = (1 << (offset + end_bit - start_bit - 31)) - 1;
227         temp =
228             (*((cyg_uint32 *) ((cyg_uint32) pcsd + (index + 1) * 4)) &
229              temp);
230         value += temp << (32 - offset);
231     }
232
233     flash_dprintf(FLASH_DEBUG_MAX, "%s:value=%x (CSD:%x:%x:%x:%x)\n",
234               __FUNCTION__, value, *pcsd, *(pcsd + 1), *(pcsd + 2),
235               *(pcsd + 3));
236     return value;
237
238 }
239
240 cyg_uint32 card_get_capacity_size(void)
241 {
242     cyg_uint32 capacity = 0;
243     cyg_uint32 c_size, c_size_mult, blk_len;
244
245     if (!csd.csd0 && !csd.csd1 && !csd.csd2 && !csd.csd3)
246         flash_dprintf(FLASH_DEBUG_MAX,
247                   "WARNINGS:mxcmci_init should be done first!\n");
248
249     switch (Card_type) {
250     case SD_CSD_1_0:
251     case MMC_CSD_1_0:
252     case MMC_CSD_1_1:
253     case MMC_CSD_1_2:
254         c_size = csd_get_value(&csd, 62, 73);
255         c_size_mult = csd_get_value(&csd, 47, 49);
256         blk_len = csd_get_value(&csd, 80, 83);
257         capacity = (c_size + 1) << (c_size_mult + 2 + blk_len - 10);
258         break;
259     case SD_CSD_2_0:
260         //blk_len = csd_get_value(&csd, 80, 83);
261         c_size = csd_get_value(&csd, 48, 69);
262         capacity = (c_size + 1) * 512;    /* block length is fixed to 512B */
263         break;
264     default:
265         capacity = 1;
266         break;
267     }
268
269     /* check whether the card is high capacity card */
270     if(capacity>2*1024*1024)
271         HighCapacityCard = 1;
272     else
273         HighCapacityCard = 0;
274
275     return capacity;
276
277 }
278
279 cyg_uint32 mxcmci_data_read(cyg_uint32 * dest_ptr, cyg_uint32 len,
280                 cyg_uint32 offset)
281 {
282     cyg_uint32 read_status = FAIL;
283
284     read_status = mmc_data_read(dest_ptr, len, offset);
285
286     if (read_status) {
287         len = 0;
288     }
289     return len;
290
291 }
292
293 cyg_uint32 mxcmci_software_reset(void)
294 {
295     command_t cmd;
296     cyg_uint32 response = FAIL;
297
298     /*Configure CMD0 for MMC/SD card */
299     /*CMD0 doesnt expect any response */
300     mxcmci_cmd_config(&cmd, CMD0, NO_ARG, READ, RESPONSE_NONE,
301               DATA_PRESENT_NONE, DISABLE, DISABLE);
302
303     /*Issue CMD0 to MMC/SD card to put in active state */
304     if (host_send_cmd(&cmd) != FAIL) {
305         response = SUCCESS;
306     } else {
307         diag_printf("Card SW Reset Failed.\n");
308     }
309
310     return response;
311 }
312
313 cyg_uint32 mxcmci_get_cid(void)
314 {
315
316     command_t cmd;
317     cyg_uint32 cid_request = FAIL;
318     command_response_t response;
319
320     /* Configure CMD2 for card */
321     /* No Argument is expected for CMD2 */
322     mxcmci_cmd_config(&cmd, CMD2, NO_ARG, READ, RESPONSE_136,
323               DATA_PRESENT_NONE, ENABLE, DISABLE);
324
325     /* Issue CMD2 to card to determine CID contents */
326     if (host_send_cmd(&cmd) == FAIL) {
327         cid_request = FAIL;
328         diag_printf("Send CMD2 Failed.\n");
329     } else {
330         /* Read Command response  */
331         response.format = RESPONSE_136;
332         host_read_response(&response);
333
334         /* Assign CID values to mmc_cid structures */
335         Card_identification.cid0 = response.cmd_rsp0;
336         Card_identification.cid1 = response.cmd_rsp1;
337         Card_identification.cid2 = response.cmd_rsp2;
338         Card_identification.cid3 = response.cmd_rsp3;
339
340         /* Assign cid_request as SUCCESS */
341         cid_request = SUCCESS;
342     }
343
344     flash_dprintf(FLASH_DEBUG_MAX, "%s:CID=%X:%X:%X:%X\n", __FUNCTION__,
345               Card_identification.cid0, Card_identification.cid1,
346               Card_identification.cid2, Card_identification.cid3);
347     return cid_request;
348 }
349
350 cyg_uint32 mxcmci_trans_prepare(void)
351 {
352     command_t cmd;
353     cyg_uint32 card_state = 0;
354     cyg_uint32 transfer_status = 0;
355     command_response_t response;
356     cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
357
358     /* Configure CMD7 for MMC card */
359     /* 16bit card address is expected as Argument */
360     mxcmci_cmd_config(&cmd, CMD7, card_address, READ, RESPONSE_48,
361               DATA_PRESENT_NONE, ENABLE, ENABLE);
362
363     /* Sending the card from stand-by to transfer state    */
364     if (host_send_cmd(&cmd) == FAIL) {
365         transfer_status = FAIL;
366         diag_printf("Send CMD7 Failed.\n");
367     } else {
368
369         /* Configure CMD13 to read status of the card becuase CMD7 has R1b response */
370         mxcmci_cmd_config(&cmd, CMD13, card_address, READ, RESPONSE_48,
371                   DATA_PRESENT_NONE, ENABLE, ENABLE);
372
373         if (host_send_cmd(&cmd) == FAIL) {
374             transfer_status = FAIL;
375             diag_printf("Send CMD13 Failed.\n");
376         } else {
377             /* Read Command response */
378             response.format = RESPONSE_48;
379             host_read_response(&response);
380
381             card_state = CURR_CARD_STATE(response.cmd_rsp0);
382
383             if (card_state == TRAN) {
384                 transfer_status = SUCCESS;
385
386             } else {
387                 diag_printf("card_state: 0x%x\n", card_state);
388                 transfer_status = FAIL;
389             }
390         }
391
392     }
393
394     return transfer_status;
395
396 }
397
398 cyg_uint32 mxcmci_trans_status(void)
399 {
400     command_t cmd;
401     cyg_uint32 card_state = 0;
402     cyg_uint32 transfer_status = 0;
403     command_response_t response;
404     cyg_uint32 card_address = (Card_rca << RCA_SHIFT);
405
406     /* Configure CMD13 to read status of the card becuase CMD7 has R1b response */
407     mxcmci_cmd_config(&cmd, CMD13, card_address, READ, RESPONSE_48,
408               DATA_PRESENT_NONE, ENABLE, ENABLE);
409
410     if (host_send_cmd(&cmd) == FAIL) {
411         diag_printf("Fail, CMD13\n");
412         transfer_status = FAIL;
413     }
414
415     else {
416         /* Read Command response */
417         response.format = RESPONSE_48;
418         host_read_response(&response);
419
420         card_state = CURR_CARD_STATE(response.cmd_rsp0);
421
422         if (card_state == TRAN) {
423             transfer_status = SUCCESS;
424             //diag_printf("card_state: 0x%x\n", card_state);
425         }
426
427         else {
428             //diag_printf("card_state: 0x%x\n", card_state);
429             transfer_status = FAIL;
430         }
431     }
432     return transfer_status;
433
434 }
435
436 void mxcmci_cmd_config(command_t * cmd_config, cyg_uint32 index,
437                cyg_uint32 argument, xfer_type_t transfer,
438                response_format_t format, data_present_select data,
439                crc_check_enable crc, cmdindex_check_enable cmdindex)
440 {
441
442     command_t *cmd;
443
444     /* Assign cmd to cmd_config */
445     cmd = cmd_config;
446
447     /* Configure Command index */
448     cmd->command = index;
449
450     /* Configure Command Argument */
451     cmd->arg = argument;
452
453     /* Configure Data transfer type */
454     cmd->data_transfer = transfer;
455
456     /* Configure Response Format */
457     cmd->response_format = format;
458
459     /* Configure Data Present Select */
460     cmd->data_present = data;
461
462     /* Configiure CRC check Enable */
463     cmd->crc_check = crc;
464
465     /*Configure Command index check enable */
466     cmd->cmdindex_check = cmdindex;
467
468     /* if multi-block is used */
469     if (CMD18 == index || CMD25 == index) {
470         /*Configure Block count enable */
471         cmd->block_count_enable_check = ENABLE;
472         /*Configure Multi single block select */
473         cmd->multi_single_block = MULTIPLE;
474     } else {
475         /*Configure Block count enable */
476         cmd->block_count_enable_check = DISABLE;
477
478         /*Configure Multi single block select */
479         cmd->multi_single_block = SINGLE;
480     }
481 }