?? sdc.c
字號:
/************************************************** * * sdc.c * * CVS ID: $Id: sdc.c,v 1.17 2007/03/19 17:59:41 belardi Exp $ * Author: Sangwon Bae [swbae] - Optomech * Date: $Date: 2007/03/19 17:59:41 $ * Revision: $Revision: 1.17 $ * * Description: * * *************************************************** * * COPYRIGHT (C) Optomech 2006 * All Rights Reserved * *************************************************** * * STM CVS Log: * * $Log: sdc.c,v $ * Revision 1.17 2007/03/19 17:59:41 belardi * Integration of Optomech SDC driver P150307 * * Revision 1.16 2007/02/27 09:29:35 belardi * Optomech patch 070226 * - MMC is supported by SDC driver * * Revision 1.15 2007/02/08 12:39:48 belardi * Optomech driver stability patch P070131 * * Revision 1.14 2006/12/13 09:24:52 belardi * Optomech stability fix for SDC driver (P061212) * * Revision 1.13 2006/11/28 09:28:45 belardi * bug fix from Optomech * * Revision 1.12 2006/09/18 09:55:24 belardi * Corrected CVS keyword usage * * Revision 1.11 2006/09/18 09:25:23 belardi * Added Log CVS keyword into file header * * ***************************************************/#include "gendef.h"#include "hwreg.h"#include "osal.h"#if (1 == HAVE_SDC)#include "hostif_high.h"#include "xfile.h"#include "sdc.h"#include "sdci.h"tU8 sdc_data[SDP_BUFFERLEN];tU32 sdc_nac;SDC_FLAG_STATUS sdc_status;t_fsm sdc_fsm_xfer;tU8 sdc_kick;t_child_cmd_event local_sdc_cmd_event;t_child_cmd_event sdc_cmd_event_data[EVENT_MAX_STAGES];/****************************************************************** * * SD Card * *****************************************************************//* Init SDC task */void InitSDCTask(void){ sd_init(); sdc_kick = 0; start_timer(SDC_TIMER, SD_ELAPSE_INSERTION);}/* SDC task */void SDCTask(void *unused){ while (TRUE) { OSAL_wait_thread(OSAL_THREAD_SDCTask); event_disable_scheduling(); event_in_shedule(SDC_CMD_EVENT); event_enable_scheduling(); sdc_process_preevents(); sdc_transition_handler(); event_disable_scheduling(); event_in_clear(SDC_CMD_EVENT); event_out_shedule(SDC_STOP_EVENT); event_out_shedule(SDC_DATA_EVENT); event_out_shedule(SDC_MOUNT_EVENT); event_enable_scheduling(); }}void sd_init(void){ PDB |= 0x1000; // CS SD_CLK = SDP_CLOCK_INIT; // 67.74MHz / 170 = 398.5 kHz < 400 kHz SD_CSR1.field.bspe = 0; // BSPI Disable SD_CSR1.field.mstr = 1; // BSPI is a master SD_CSR1.field.rie = 0; SD_CSR1.field.reie = 0; SD_CSR1.field.beie = 0; SD_CSR1.field.cpol = 0; SD_CSR1.field.cpha = 0; SD_CSR1.field.wl = 0; SD_CSR1.field.rfs = 0; // 8 Word Rx SD_CSR2.field.dfifo = 1; // Clear FIFO SD_CSR2.field.tfs = 0; // 8 Word Tx SD_CSR2.field.tie = 0; SD_CSR3.field.mask_ss = 1; // Mask SS SD_CSR3.field.dma_en = 0; SD_CSR3.field.tburst_len = 0; SD_CSR3.field.rburst_len = 10; // Set as 8 SD_CSR3.field.treq_len = 0; SD_CSR3.field.rreq_len = 0; SD_CSR1.field.bspe = 1; // BSPI Enable sdc_nac = SDP_NACDEFAULT; sdc_status.value = SDS_NONE;}void *get_sdc_cmd_event_data(t_event_stage i){ return (void *)&sdc_cmd_event_data[i];}void sdc_process_preevents(void){ if (IS_SDC_CMD_EVENT) { local_sdc_cmd_event = SDC_CMD; switch(local_sdc_cmd_event.command) { case CHILD_CMD_XFER_DATA: FSM_activate(&sdc_fsm_xfer, SDC_DATA_FSM_IDLE, 1); break; case CHILD_CMD_BACKGROUND: sdc_kick = 1; break; } }}void sdc_transition_handler(void){ uint16 sdc_awaited_transitions; do { sdc_awaited_transitions = 0; if (FSM_RUN == sdc_fsm_xfer.state) { sdc_awaited_transitions |= sdc_xfer_transition(); } } while(sdc_awaited_transitions); if(sdc_kick) { sdc_test_back(); sdc_kick = 0; }}uint16 sdc_xfer_transition(void){ static tU32 sdc_begin; static tU32 sdc_count; static tU16 sdc_offset; static tU8* sdc_target; tU16 sdc_size; switch (sdc_fsm_xfer.transition) { case SDC_DATA_FSM_IDLE: if(0 == sdc_status.f.Ready) { sdc_fsm_xfer.transition = SDC_DATA_FSM_ERROR; break; } sdc_begin = local_sdc_cmd_event.command_params.xfer_params.sector_start << 9; sdc_count = local_sdc_cmd_event.command_params.xfer_params.count; sdc_offset = local_sdc_cmd_event.command_params.xfer_params.offset; sdc_target = local_sdc_cmd_event.command_params.xfer_params.dest; if((0 == sdc_count) || (SDP_BLOCKLEN <= sdc_offset)) { sdc_fsm_xfer.transition = SDC_DATA_FSM_DONE; break; } sdc_fsm_xfer.transition = SDC_DATA_FSM_READ; case SDC_DATA_FSM_READ: sdc_size = SDP_BLOCKLEN - sdc_offset; if(sdc_size > sdc_count) { sdc_size = sdc_count; } if(SDE_TIME_OUT == sd_open(sdc_begin, sdc_offset, sdc_target, sdc_size)) { sdc_fsm_xfer.transition = SDC_DATA_FSM_ERROR; break; } sdc_count -= sdc_size; if(sdc_count) { sdc_begin += (sdc_size + sdc_offset); sdc_target += sdc_size; sdc_offset = 0; break; } case SDC_DATA_FSM_DONE: sdc_fsm_xfer.state = FSM_DONE; event_data_set_sdc(READY); return 0; default: sdc_set_error(&sdc_fsm_xfer, E_SDC_READ); if(sdc_status.f.Ready) { sdc_kick = 1; } else { event_mount_set_sdc(SDC_UMOUNT); } return 0; } return CTR_TRANSITION_SDC_DATA_FOR_SDC;}void sdc_set_error(t_fsm *sdc_fsm, GRESULT error_reason){ sdc_fsm->state = FSM_ERROR; sdc_fsm->error_reason = error_reason; event_data_set_sdc(error_reason); }void sdc_test(void){ sdc_kick = 1; OSAL_wake_thread(OSAL_THREAD_SDCTask);}void sdc_test_back(void) { uint16 delay; if (sdc_status.f.Ready) { if(OK != sd_check()) { sdc_status.value = SDS_NONE; event_mount_set_sdc(SDC_UMOUNT); delay = SD_ELAPSE_INSERTION; } else { delay = SD_ELAPSE_REMOVAL; } } else { switch(sd_detect()) { case READY : sdc_status.f.Ready = 1; event_mount_set_sdc(SDC_MOUNT); delay = SD_ELAPSE_MONITOR; break; case IN_PROGRESS : delay = SD_ELAPSE_DETECTION; break; default : delay = SD_ELAPSE_INSERTION; } } start_timer(SDC_TIMER, delay); }RETVAL sd_detect(void){ GRESULT res; switch(sdc_status.f.Step) { case SDC_STEP_SUPPLY : sd_delay(SD_CLOCK_SUPPLY); sdc_status.f.Step ++; return MEDIA_NOT_FOUND; case SDC_STEP_RESET : res = sd_reset(); break; case SDC_STEP_WAKEUP : if(E_FAIL == (res = sd_wakeup())) { return IN_PROGRESS; } break; case SDC_STEP_READOCR : res = sd_readocr(); break;#if 0 case SDC_STEP_SENDCSD : res = sd_sendcsd(); break;#endif // 0 case SDC_STEP_SETBL : res = sd_setbl(); break; case SDC_STEP_DONE : sdc_status.f.Step = 0; return READY; case SDC_STEP_FAIL : default : res = E_FAIL; } if(S_OK == res) { sdc_status.f.Step ++; return IN_PROGRESS; } sdc_status.f.Step = 0; return MEDIA_NOT_FOUND;}RETVAL sd_check(void){ if(SDE_OK == sd_command(SDC_READ_OCR, 0, SDR_3)) { return OK; }// sdc_status.value = SDS_NONE; // reset clock sd_reset_clock(); return MEDIA_NOT_FOUND;}RETVAL sdc_cmd(t_child_cmd_event* cmd_event){ t_child_cmd_event* pout_event = (t_child_cmd_event *)pevent_get_out(SDC_CMD_EVENT); *pout_event = *cmd_event; event_set_out(SDC_CMD_EVENT); event_out_shedule(SDC_CMD_EVENT); return BUSY;}GRESULT sd_reset(void){ switch(sd_command(SDC_GO_IDLE_STATE, 0, SDR_1)) { case SDE_OK : case SDE_IN_IDLE_STATE : sdc_status.f.Count = SDW_TRY_IDLE; return S_OK; default :// sdc_status.value = SDS_NONE; return E_DEVICE_NOT_AVAILABLE; }}GRESULT sd_wakeup(void){ e_SDErr res = sd_command(SDC_APP_CMD, 0, SDR_1); if(SDE_IN_IDLE_STATE == res) { res = sd_command(SDAC_SEND_OP_COND, 0, SDR_1); }// res = sd_command(SDC_READ_OCR, 0, SDR_3); if(SDE_ILLEGAL_COMMAND & res) { res = sd_command(SDC_SEND_OP_COND, 0, SDR_1); } if(SDE_OK == res) { return S_OK; } if(sdc_status.f.Count) { sdc_status.f.Count --; return E_FAIL; } return E_READ_TIMEOUT;}GRESULT sd_readocr(void){ if(SDE_OK != sd_command(SDC_READ_OCR, 0, SDR_3)) {// sdc_status.value = SDS_NONE; return E_READ_FAILURE; } // check voltage if(SDP_OCR_33_MSK != (SDP_OCR_33_MSK & sdc_data[SDP_OCR_33_IDX])) {// sdc_status.value = SDS_ERROR; return E_INVALID_DEVICE_TYPE; } return S_OK;}#if 0GRESULT sd_sendcsd(void){ const tU32 a_Unit[] = {0, 0, 0, 1, 10, 100, 1000, 10000}; const tU32 a_Value[] = {0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80}; // send csd if(SDE_OK != sd_command(SDC_SEND_CSD, 0, SDR_R)) {// sdc_status.value = SDS_NONE; return E_READ_FAILURE; } // get nac (we should assume clock cycle for taac. choose 10MHz safely.) sdc_nac = a_Unit[SDP_CSD_TAAC_UMSK & sdc_data[SDP_CSD_TAAC_IDX]]; if(sdc_nac) { sdc_nac *= a_Value[SDP_CSD_TAAC_VMSK & (sdc_data[SDP_CSD_TAAC_IDX] >> SDP_CSD_TAAC_VOFFSET)]; } else { sdc_nac = SDP_NACMIN; } sdc_nac += (SDP_CSD_NSAC_UNIT * sdc_data[SDP_CSD_NSAC_IDX]); // optional check to avoid error if(SDP_NACDEFAULT > sdc_nac) { sdc_nac = SDP_NACDEFAULT; } // check 8s multiple// sdc_nac >>= 3; // divide by 8 // Some SDC doesn't follow their spec. // Wait more safely return S_OK;}#endif //0GRESULT sd_setbl(void){ // set BLOCKLEN if(SDE_OK != sd_command(SDC_SET_BLOCKLEN, SDP_BLOCKLEN, SDR_1)) {// sdc_status.value = SDS_NONE; return E_READ_FAILURE; } // ready// sdc_status.value = SDS_READY; // update clock sd_burst_clock(); return S_OK;}e_SDErr sd_command(e_SDCmd cmd, tU32 param, e_SDRes type){ tU8 res; tU32 cnt; tU32 req; tU8* p_out = sdc_data; res = sd_query(cmd, param); // check response type switch(type) { case SDR_R : if(SDE_OK != res) { sd_close(); return res; } cnt = 8; req = 16; break; case SDR_2 : case SDR_3 : // set count cnt = (SDR_2 == type) ? 1 : 4; // set response *p_out ++ = res; // read response block while(cnt --) { *p_out ++ = sd_read(0xFF); } case SDR_1 : default : sd_close(); return res; } // wait data do { res = sd_read(0xFF); } while((0xFF == res) && (cnt --)); // check result if((0xFF == res) || (!(SDP_DATAERR_MSK & res))) { sd_close(); return res; } // read response p_out = sdc_data; cnt = req; while(cnt --) { *p_out ++ = sd_read(0xFF); } sd_close(); return SDE_OK;}e_SDErr sd_open(tU32 addr, tU32 offset, tU8* dest, tU32 size){ tU8 res; tU32 cnt; if(SDE_OK != (res = sd_query(SDC_READ_SINGLE_BLOCK, addr))) { sd_close(); return res; } // wait data cnt = sdc_nac; do { res = sd_read(0xFF); } while((0xFF == res) && (cnt --)); // check result if((0xFF == res) || (!(SDP_DATAERR_MSK & res))) { sd_close(); return res; } cnt = (SDP_BLOCKLEN > (offset + size)) ? (SDP_BLOCKLEN - size - offset) : 0; while(offset --) { sd_read(0xFF); } while(size --) { *dest ++ = sd_read(0xFF); } while(cnt --) { sd_read(0xFF); } sd_close(); return SDE_OK;}#if 0 // [RB] commented out to reduce ROM spacee_SDErr sd_wait(void){ return SDE_OK;}#endife_SDErr sd_query(e_SDCmd cmd, tU32 param){ tU8 res = SDE_TIME_OUT; tU32 cnt = 17; PDB |= 0x1000; // confirm - optional SD_CSR2.field.dfifo = 1; // clear fifo PDB &= ~0x1000; // CS // dummy high sd_read(0xFF); // start bit, transmission bit & command sd_read(0x40 | (0x3F & cmd)); // parameter sd_read(0xFF & (param >> 24)); sd_read(0xFF & (param >> 16)); sd_read(0xFF & (param >> 8)); sd_read(0xFF & param); // CRC7 & end bit sd_read(0x95); // dummy for CMD0 // dummy high sd_read(0xFF); // wait response do { res = sd_read(0xFF); } while((0xFF == res) && (cnt --)); return res;}e_SDErr sd_close(void){ // trash crc sd_delay(4); PDB |= 0x1000; sd_delay(2); return SDE_OK;}void sd_delay(tU32 cnt){ while(cnt --) { sd_read(0xFF); }}void sd_send(tU8 dat){ while(1) { if(SD_CSR2.field.tfe) { SD_TXR = (dat << 8); break; } }}tU8 sd_read(tU8 dat){ sd_send(dat); while(1) { if(SD_CSR2.field.rfne) { return (SD_RXR & 0xFF); } }}void sd_reset_clock(void){ SD_CLK = SDP_CLOCK_INIT; // 67.74MHz / 170 = 398.5 kHz < 400 kHz}void sd_burst_clock(void){ SD_CLK = SDP_CLOCK_BURST; // test value}#endif /* HAVE_SDC *//* End of sdc.c */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -