📄 s3c_mmc.c
字号:
else { MMC_DEBUG(2," RESPONSE OK "); } } rSDICSTA=status; /* Clear cmd & rsp end state */ } else /* CRC check */ { if( (status&0x1f00) != 0xa00 ) /* Check error */ { MMC_DEBUG(2," ERROR CMD%d:rSDICSTA=0x%x, rSDIRSP0=0x%x",cmd, rSDICSTA, rSDIRSP0); rSDICSTA=status; /* Clear error state */ if(((status&0x400)==0x400)) return -EIO; /* Timeout error */ } rSDICSTA=status; } return 0; }}static void mmc_CMD0(void) { rSDICARG = 0x0; rSDICCON = START_TRANSMISSION_PRE; s3c_mmc_start_clock (); rSDICCON |= CMD_START; mdelay(1); chk_CMDend(0,0);}/******* * Prototype * static int s3c_mmc_reset( struct s3c_mmc_data *sd ) * * Purpose: * 1. mmc_cim_init_stack(struct mmc_dev *dev,int first ) issue "MMC_CIM_RESET" * 2. implement "CMD0" * Entry * Exit * Exceptions: * It is nessecary to get clock slow that obtains the sufficient response time. *****************************************************************************/static int s3c_mmc_reset( struct s3c_mmc_data *sd ){ int retval = 0 ; g_s3c_mmc_data.type = RT_NO_RESPONSE; mmc_CMD0(); return retval;} /******* * Prototype * s3c_mmc_set_command( request->cmd, request->arg ) * * Purpose: * 1. set SDICARG * 2. set the "Command with data " of SDICCON * 3. clear registers * 4. set cmd index including Start bit & transmission bit * and response type. * Entry * Exit * Exceptions: * Not sure that 2 must be set here. *******************************************************************/static void s3c_mmc_set_command( u32 cmd, u32 arg, enum mmc_rsp_t rtype ){ u32 cc_reg = 0; /* write one clear */ rSDICSTA = ( MMC_STATUS_CRC_RESPONSE_ERROR |MMC_STATUS_CMD_SENT_DONE |MMC_STATUS_RESPONSE_TIMEOUT |MMC_STATUS_RESPONSE_RECV_DONE ); rSDICARG = arg; cc_reg = cmd |START_TRANSMISSION_PRE|NORMAL_COMMAND; if (g_s3c_mmc_data.type == RT_READ || g_s3c_mmc_data.type==RT_WRITE){ }#ifdef S3C_SDIO if (g_s3c_mmc_data.type == RT_READ || g_s3c_mmc_data.type==RT_WRITE){ cc_reg |= CMD_WITH_DATA; }#endif if( rtype != RESPONSE_NONE ) { cc_reg |= WAIT_RESPONSE; if ( rtype==RESPONSE_R2_CID || rtype==RESPONSE_R2_CSD ) { cc_reg |= LONG_136RESPONSE; } } else { MMC_DEBUG(2," RESPONSE_NONE"); } rSDICCON = cc_reg; MMC_DEBUG(2,": rSDICCON 0x%08X rSDIDTIMER Ox%08X ",rSDICCON,rSDIDTIMER);} static int s3c_mmc_exec_command( struct mmc_request *request ){ int irq = 0; MMC_DEBUG(2," request = %p request->rtype 0x%08X ",request,request->rtype); /* Start the actual transfer */ switch (request->cmd) { case MMC_READ_SINGLE_BLOCK: case MMC_READ_MULTIPLE_BLOCK: g_s3c_mmc_data.type = RT_READ; s3c_mmc_set_transfer(request->block_len,request->nob,request->cmd); irq = S3C_RX_FIFO_LAST_DATA_INT_ON| S3C_RX_FIFO_FULL_INT_ON |S3C_CMD_RESPONSE_TIMEOUT_INT_ON| S3C_RESPONSE_CRC_INT_ON|S3C_RESPONSE_RECV_INT_ON; break; case MMC_WRITE_BLOCK: case MMC_WRITE_MULTIPLE_BLOCK: g_s3c_mmc_data.type = RT_WRITE; s3c_mmc_set_transfer(request->block_len,request->nob,request->cmd); /* The other interrupts will be enbaled in the isr after the response recv has occured */ irq = S3C_CMD_RESPONSE_TIMEOUT_INT_ON | S3C_RESPONSE_RECV_INT_ON | S3C_RESPONSE_CRC_INT_ON; break; default: g_s3c_mmc_data.type = RT_RESPONSE_ONLY; irq = S3C_RESPONSE_RECV_INT_ON|S3C_CMD_RESPONSE_TIMEOUT_INT_ON; /* response only interrupt */ break; } /* s3c_mmc_set_command must run after s3c_mmc_set_transfer closely */ s3c_mmc_set_command(request->cmd,request->arg,request->rtype); rSDIIMSK = irq; MMC_DEBUG(2," Real Start clocking "); s3c_mmc_start_clock(); rSDICCON |= CMD_START;#if 0 /*S3C_CMD_DONE_BUSY_WAITING_DEBUG*/ if ( request->cmd == MMC_READ_SINGLE_BLOCK) { if ( chk_CMDend(MMC_READ_SINGLE_BLOCK,1) == 0 ) { MMC_DEBUG(2," RESPONSE & CMD done "); } do {} while(1); }#endif return MMC_NO_ERROR;}static void s3c_mmc_send_command( struct mmc_request *request ){ int retval; MMC_DEBUG(1, ": request=%p cmd=%d (%s) arg=%08x " " Cmd status=%04x" " Data status=%04x" " FIFO status=%04x\r\n", request, request->cmd, get_cmd_name(request->cmd), request->arg, rSDICSTA,rSDIDSTA,rSDIFSTA); /* Global Lock Needed */ g_s3c_mmc_data.request = request; request->result = MMC_NO_RESPONSE; /* Flag to indicate don't have result yet */ if ( request->cmd == MMC_CIM_RESET || request->cmd == 0 ) { retval = s3c_mmc_reset(&g_s3c_mmc_data); request->result = retval; MMC_DEBUG(2," Before mmc_cmd_complete "); mmc_cmd_complete(request); } else { retval = s3c_mmc_exec_command(request); MMC_DEBUG(2," retval 0x%08X ",retval); } if (retval) { request->result = retval; MMC_DEBUG(2," Before mmc_cmd_complete "); mmc_cmd_complete(request); } MMC_DEBUG(2, " rSDIIMSK 0x%08X cmd 0x%08X data 0x%08X fifo 0x%08X",rSDIIMSK,rSDICSTA,rSDIDSTA,rSDIFSTA); MMC_DEBUG(2, " rSDICON 0x%08X CCON 0x%08X DCONdata 0x%08X ",rSDICON,rSDICCON,rSDIDCON); }static void s3c_mmc_get_response( struct mmc_request *request ){ int reg; int len = rinfo[request->rtype].length; u8 *buf = request->response; request->result = MMC_NO_ERROR; /* Mark this as having a request result of some kind */ if ( len <= 0 ) /* MMC_NO_RESPONSE */ return; switch ( len) { case 6: /* 6 bytes response */ reg = rSDIRSP0; buf[0] = rSDICSTA & MMC_STATUS_RESPONSE_INDEX_MASK ;/* */ buf[1] = (reg & 0xff000000) >> 24; buf[2] = (reg & 0x00ff0000) >> 16; buf[3] = (reg & 0x0000ff00) >> 8; buf[4] = (reg & 0x000000ff) >> 0; buf[5] = (u8) ((rSDIRSP1&MMC_RESPONSE_CRC_8_0)>>SDIRSP1_CRC_SHIFT ); /* CRC+ end bit */ break; case 17: /* R2 (CID,CSD registers) */ reg = rSDIRSP0; buf[0] = MMC_RESPONSE_LONG_135_128_VAL; buf[1] = (reg & 0xff000000) >> 24; buf[2] = (reg & 0x00ff0000) >> 16; buf[3] = (reg & 0x0000ff00) >> 8; buf[4] = (reg & 0x000000ff) >> 0; reg = rSDIRSP1; buf[5] = (reg & 0xff000000) >> 24; buf[6] = (reg & 0x00ff0000) >> 16; buf[7] = (reg & 0x0000ff00) >> 8; buf[8] = (reg & 0x000000ff) >> 0; reg = rSDIRSP2; buf[9] = (reg & 0xff000000) >> 24; buf[10] = (reg & 0x00ff0000) >> 16; buf[11] = (reg & 0x0000ff00) >> 8; buf[12] = (reg & 0x000000ff) >> 0; reg = rSDIRSP3; buf[13] = (reg & 0xff000000) >> 24; buf[14] = (reg & 0x00ff0000) >> 16; buf[15] = (reg & 0x0000ff00) >> 8; buf[16] = (reg & 0x000000ff) >> 0; break; default: break; }#ifdef CONFIG_MMC_DEBUG { int i; printk("%s: Raw byte stream: ", __FUNCTION__); for ( i = 0 ; i < len; i++ ) printk("%02x ", buf[i]); printk("\n"); }#endif}/******* * Prototype * static void s3c_mmc_transmit_data( struct mmc_request *request ) * Purpose: * Entry * Exit * 0 : the other blocks to send remaind * 1 : transfer done * Exceptions: * S3C FIFO SIZE of SD is 64 Bytes * block_len * nob should be multiple of S3C_SD_FIFO_SIZE ***********************************************************************/static int s3c_mmc_transmit_data( struct mmc_request *request ){ u32 *buf32 = (u32 *)request->buffer; int maxdata = request->block_len * request->nob; int i; int fifobytes; int fillbytes; /*MMC_DEBUG(2,": maxdata=%d size2send=%d", maxdata, g_s3c_mmc_data.size2send);*/ if ( (g_s3c_mmc_data.size2send == maxdata) || (maxdata == 0) ) { request->nob = 0; g_s3c_mmc_data.size2send = 0; return 1; /* transfer done */ } /* Fill fifo with data, make sure not to overfill if data is still present in the fifo. Just add enough to refill the fifo to its maximum. */ if (rSDIFSTA & MMC_STATUS_FIFO_READY_FOR_TX) { fifobytes = rSDIFSTA & MMC_STATUS_FIFO_COUNT_MASK; if ((S3C_SD_FIFO_SIZE - fifobytes) > (maxdata - g_s3c_mmc_data.size2send)){ fillbytes = maxdata - g_s3c_mmc_data.size2send; } else { fillbytes = S3C_SD_FIFO_SIZE - fifobytes; } fillbytes = 4 * (fillbytes / 4 ); /* Makes sure it is a multiple of 4 */ for ( i = 0; i < fillbytes; i +=4 ) { rSDIDAT = *buf32++; udelay(1); } g_s3c_mmc_data.size2send += fillbytes; } if(rSDIDSTA & MMC_STATUS_DATA_TRANSFER_DONE) rSDIDSTA = MMC_STATUS_DATA_TRANSFER_DONE; /* Has a complete block been transfered */ if ( g_s3c_mmc_data.size2send >= request->block_len) { /* Reduce the number of blocks to send. */ request->nob--; g_s3c_mmc_data.size2send -= request->block_len; } /* Updated the request buffer to reflect the current state */ request->buffer = (u8 *) buf32; /* g_s3c_asic_statistics.mmc_written++; */ return 0;}/******* * Prototype * static int s3c_mmc_receive_data( struct mmc_request *request,int flag ) * Purpose: * Entry * flag -1 : RX_FIFO_HALF_FULL others : the size of last FIFO data when RX_FIFO_LAST_DATA occurs. * Exit * -1 : Unexpected Error * 0 : last data * 1 : keep receiving data. * Exceptions: ***********************************************************************/static int s3c_mmc_receive_data( struct mmc_request *request, int flag ){ u8 *buf = (u8 *)request->buffer; u32 data; int i; MMC_DEBUG(2,": nob=%d block_len=%d buf=%p", request->nob, request->block_len, buf); if ( request->nob <= 0 ) { MMC_DEBUG(1,": *** nob already at 0 ***"); return -1; } if ( flag != -1 ) { if (rSDIDSTA & MMC_STATUS_RX_DATA_ON_PROGRESS) { MMC_DEBUG(2, " Not yet DATA Rx in progress "); } g_s3c_mmc_data.size2read +=flag; i = flag % 4; if( i != 0 ) { MMC_DEBUG(2," UNEXPECTED FIFO COUNT 1 "); } i = g_s3c_mmc_data.size2read % 512; if ( i != 0 ) { MMC_DEBUG(2," UNEXPECTED FIFO COUNT 2"); } for (i=0; i < flag ; i += 4) { data = rSDIDAT; *buf++ = data >> 0 & 0xff; *buf++ = data >> 8 & 0xff; *buf++ = data >> 16 & 0xff; *buf++ = data >> 24 & 0xff; } if ( request->nob > 1 ) { MMC_DEBUG(2," Unexpected nob count error "); } else { request->nob-- ; } if(rSDIFSTA & MMC_STATUS_FIFO_RX_LAST_DATA) rSDIFSTA |= MMC_STATUS_FIFO_RX_LAST_DATA; request->buffer = buf; MMC_DEBUG(2," Total Read Size for single read cmd 0x%08X",g_s3c_mmc_data.size2read); g_s3c_mmc_data.size2read = 0; return 0 ; } if ( (rSDIFSTA & MMC_STATUS_FIFO_COUNT_MASK) != S3C_SD_FIFO_SIZE) { MMC_DEBUG(2, " Unexpected FIFO Data count v.s Received Data "); } for (i=0; i < S3C_SD_FIFO_SIZE; i += 4) { data = rSDIDAT; *buf++ = data >> 0 & 0xff; *buf++ = data >> 8 & 0xff; *buf++ = data >> 16 & 0xff; *buf++ = data >> 24 & 0xff; } g_s3c_mmc_data.size2read += S3C_SD_FIFO_SIZE; if (0 == (g_s3c_mmc_data.size2read % request->block_len)) request->nob--; if ( !request->nob ) { while(!(rSDIDSTA&MMC_STATUS_DATA_TRANSFER_DONE)){ ; } rSDIDSTA = MMC_STATUS_DATA_TRANSFER_DONE; if(rSDIFSTA & MMC_STATUS_FIFO_RX_LAST_DATA) rSDIFSTA |= MMC_STATUS_FIFO_RX_LAST_DATA; request->buffer = buf; g_s3c_mmc_data.size2read = 0; MMC_DEBUG(2,": Ending nob=%d block_len=%d buf=%p", request->nob, request->block_len, buf); MMC_DEBUG(2, " accumulated g_s3c_mmc_data.size2read 0x%08X rSDIDSTA 0x%08X rSDIFSTA 0x%08X", g_s3c_mmc_data.size2read,rSDIDSTA,rSDIFSTA);#ifdef CONFIG_MMC_DEBUG { u8 *b = request->buffer - 512 ; for ( i = 0 ; i < request->block_len ; i++ ) { printk(" %02x", *b++); if ( ((i + 1) % 16) == 0 ) printk("\n"); } } #endif return 0; } MMC_DEBUG(2, " accumulated g_s3c_mmc_data.size2read 0x%08X rSDIDSTA 0x%08X rSDIFSTA 0x%08X", g_s3c_mmc_data.size2read,rSDIDSTA,rSDIFSTA); /* Updated the request buffer to reflect the current state */ request->buffer = buf; /* g_s3c_asic_statistics.mmc_read++; */ return 1;}static void s3c_mmc_fix_sd_detect( unsigned long nr ){ int sd_card = ! lowlevel->slot_is_empty(lowlevel); /*int sd_con_slot = g_s3c_mmc_data.insert;*/ MMC_DEBUG(2,": card=%d con_slot=%d", sd_card, sd_con_slot); if ( sd_card ) { mmc_insert(0); } else { mmc_eject(0); s3c_mmc_set_clock (MMC_CLOCK_SLOW); }}static void s3c_mmc_detect_handler( unsigned long nr ){ int card_in = !lowlevel->slot_is_empty(lowlevel); /*int sd_con_slot = g_s3c_mmc_data.insert;*/ if (card_in ) { mmc_insert(0); MMC_DEBUG(1,"Card In"); } else { mmc_eject(0); MMC_DEBUG(1,"Card Eject"); s3c_mmc_set_clock (MMC_CLOCK_SLOW); }}/* the ASIC interrupted us because it detected card insertion or removal. * wait 1/4 second and see which it was. */static void s3c_mmc_detect_isr(int irq, void *dev_id, struct pt_regs *regs){ struct s3c_mmc_data *mmc_data = (struct s3c_mmc_data *) dev_id; set_gpio_ctrl( (lowlevel->sdi_gpio_cd) | GPIO_PULLUP_EN | GPIO_MODE_IN );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -