📄 mmc_samsung.c
字号:
// mod_timer( &sd->reset_timer, jiffies + (100 * HZ) / 1000 );// g_s3c_asic_statistics.mmc_reset++; mmc_CMD0(); return retval;}/******* * Prototype * mmc_s3c_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 mmc_s3c_set_command( u32 cmd, u32 arg, enum mmc_rsp_t rtype ){ u32 cc_reg = 0; // MMC_DEBUG(2,": cmd=%d arg=0x%08x", cmd, arg); MMC_DEBUG(2,""); /* 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){ } #define S3C_SDIO#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);}/******* * Prototype * static void mmc_s3c_set_transfer(u16 block_len, u16 nob,u16 int cmd) * Purpose: * 1. set SDIDIMER, SDIDCON * Entry * Exit * Exceptions: * some field of SDIDCON must be moved into initial code of mmc driver. *******************************************************************/static void mmc_s3c_set_transfer(u16 block_len,u16 nob,int cmd){ MMC_DEBUG(2,": block_len=%d nob=%d", block_len, nob); rSDIDTIMER = SDIDTIMER_DEFAULT; if ( block_len > 0x1000) { MMC_DEBUG(2,"ERROR BLOCK SIZE"); } rSDIBSIZE = block_len; if ( nob > 0x1000) { MMC_DEBUG(2,"ERROR Num BLOCK "); }// rSDIDCON |= (rSDIDCON& ~DATA_MAX_BLKNUM)| nob; rSDIDCON = nob; /* ---------------------------------------------------------------*/ /* Move Me to init routine */ /* INT_PERIOD_SINGLEBLOCK , WIDE_BUS_MODE,DMA_MODE, STOP_BY_FORDE of SDIDCON */ /* Wide Bus Mode Disable */ rSDIDCON |=RECV_AF_CMD_NODIRECT|TRAS_AF_RESPONSE_NODIRECT| DATA_TRANS_BLOCK|BUSY_AF_CMD_NODIRECT|STANDARD_BUS_MODE; /* ---------------------------------------------------------------*/ switch (cmd) { case MMC_READ_SINGLE_BLOCK: case MMC_READ_MULTIPLE_BLOCK: rSDIDCON |= DATA_RECV_START; break; case MMC_WRITE_BLOCK: case MMC_WRITE_MULTIPLE_BLOCK: rSDIDCON |= DATA_TRANS_START; break; default: break; }}/******* * Prototype * static int mmc_s3c_exec_command( struct mmc_request *request ) * * Purpose: * 1. Directly Not containing Register * Entry * Exit * Exceptions: * what is busy check irq enable --- only for write ? * what is CRC status errors interrupt * where is RT_NO_RESPONSE ? -- must be implemented in mmc_s3c_reset *****************************************************************/static int mmc_s3c_exec_command( struct mmc_request *request ){ int retval; 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; mmc_s3c_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; mmc_s3c_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; } /* mmc_s3c_set_command must run after mmc_s3c_set_transfer closely */ mmc_s3c_set_command(request->cmd,request->arg,request->rtype); rSDIIMSK = irq; MMC_DEBUG(2," Real Start clocking "); mmc_s3c_start_clock(); rSDICCON |= CMD_START;#ifdef 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/*#ifdef CONFIG_MMC_DEBUG START_MMC_DEBUG(2) { u16 status[3]; status[0] = SDICSTA; status[1] = rSDIDSTA; status[2] = rSDIFSTA; printk(__FUNCTION__ ": status[0]=%04x status[1]=0x%04x status[2]=0x%04x ", status[0],status[1],status[2]); decode_status(status); printk(")\n"); } END_MMC_DEBUG;#endif*/ return MMC_NO_ERROR;}/******* * Prototype * static void mmc_s3c_send_cmd (struct mmc_request * mr) * Purpose: * Entry * Exit * Exceptions: * not fully convinced of mmc_s3c_reset functions ************************************************************/static void mmc_s3c_send_command (struct mmc_request * request) { int retval;/* MMC_DEBUG(2," rINTMSK 0x%08X rINTMOD 0x%08X rEXTINT2 0x%08X rEINTMSK 0x%08X rEINTPND 0x%08X rGPGCON 0x%08X ", rINTMSK,rINTMOD,rEXTINT2,rEINTMSK,rEINTPND,rGPGCON );*/ MMC_DEBUG(1, ": request=%p cmd=%d (%s) arg=%08x " " Cmd status=%04x" " Data status=%04x" " FIFO status=%04x", 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 /* GO_IDLE_STATE */) { retval = mmc_s3c_reset(&g_s3c_mmc_data); request->result = retval; MMC_DEBUG(2," Before mmc_cmd_complete "); mmc_cmd_complete(request); } else { retval = mmc_s3c_exec_command(request); MMC_DEBUG(2," retval 0x%08X ",retval); #if 0 if ( retval) { // g_s3c_statistics.mmc_error++; MMC_DEBUG(0," MMC not responding ! Trying to reset"); mmc_s3c_stop_clock(); retval = mmc_s3c_adjust_clock(g_s3c_mmc_data.clock); if(retval) { MMC_DEBUG(0," MMC doesn't response ! Panic Now"); } else { retval = mmc_s3c_exec_command(request); if (retval) { MMC_DEBUG(0," ASIC unable to exec !"); } } }#endif } if (retval) { request->result = retval; MMC_DEBUG(2," Before mmc_cmd_complete "); mmc_cmd_complete(request); }} static void mmc_s3c_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); // mmc_s3c_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 mmc_s3c_sd_detect_isr(int irq, void *dev_id, struct pt_regs *regs){ struct s3c_mmc_data *sd = (struct s3c_mmc_data *) dev_id; mod_timer( &sd->sd_detect_timer, jiffies + (250 * HZ) / 1000 );}/******* * Prototype * static void mmc_s3c_get_response( struct mmc_request *request ) * Purpose: the MMC upper layer determines only Response type and the other response information * should be provided in host adapter. * Entry * Exit * Exceptions: * 1. Command Status Register[8][command Transfer in progress] can happen * to exist with command response received[9] ? * 2. To improve the performance of S3C SD Host, we must put the component of * response into upper layer.but Now we reconstruct SDIRSP0 | SDIRSP1 into one response format * 3. response buffer is 18 bytes and last two byte means crc ***********************************************************************/static void mmc_s3c_get_response( struct mmc_request *request ){ int i,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 START_MMC_DEBUG(2) { printk("%s: Raw byte stream: ", __FUNCTION__); for ( i = 0 ; i < len; i++ ) printk("%02x ", buf[i]); printk("\n"); } END_MMC_DEBUG;#endif}/******* * Prototype * static void mmc_s3c_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 mmc_s3c_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; } /* 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; } /*#ifdef CONFIG_MMC_DEBUG START_MMC_DEBUG(2) { u16 status = H3800_ASIC1_MMC_Status; printk(__FUNCTION__ ": irq_mask=%04x status=0x%04x (", H3800_ASIC1_MMC_InterruptMask, status); decode_status(status); printk(")\n"); } END_MMC_DEBUG; START_MMC_DEBUG(3) { u8 *b = request->buffer; for ( i = 0 ; i < request->block_len ; i++ ) { printk(" %02x", *b++); if ( ((i + 1) % 16) == 0 ) printk("\n"); } } END_MMC_DEBUG;#endif*/ /* Updated the request buffer to reflect the current state */ request->buffer = (u8 *) buf32; // g_s3c_asic_statistics.mmc_written++; return 0;}/******* * Prototype * static int mmc_s3c_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 mmc_s3c_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 "); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -