📄 mmc_samsung.c.bak
字号:
else { request->nob-- ; } 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; 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 START_MMC_DEBUG(3) { u8 *b = request->buffer - 512 ; for ( i = 0 ; i < request->block_len ; i++ ) { printk(" %02x", *b++); if ( ((i + 1) % 16) == 0 ) printk("\n"); } } END_MMC_DEBUG;#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;}/******* * Prototype * static void mmc_s3c_split_status( struct s3c_mmc_data *sd, u16 status[], int timeout ) * Purpose: * 1. status[SDI_CMD]= command status * status[SDI_DATA]= data status * status[SDI_FIFO]= FIFO status * 2. collect the same sorts of interrupts. * Entry * Exit * timeout not used * Exceptions: * where is timeout routine ? * rSDIIMSK = S3C_ALL_MMC_INT_MASK is right ? * * 1. In MMC mode, MAX clock rate is 10 Mhz * 2. In MMC write mode(response only, ex cmd1), the CRC error is * occured in spite of correct writing. * 3. In case of long response, the CRC error should be detected after receiving * exact response data from SD device. User should check the CRC of received response * by software. * 4. Supposed that RESPONSE State and DATA RECEIVE don't appeare simultaneously. ********************************************************************************************/static void mmc_s3c_split_status( struct s3c_mmc_data *sd, u16 status[], int timeout ){ int retval = MMC_NO_ERROR; int rsp_done = 0,msk_reg =0,data_busy=0; if ((status[SDI_CMD] & MMC_STATUS_RESPONSE_TIMEOUT ) || (status[SDI_DATA]& MMC_STATUS_DATA_BUSY_TIMEOUT) ) { MMC_DEBUG(0," MMC_ERROR_TIMEOUT ");// mmc_s3c_get_response(sd->request); retval = MMC_ERROR_TIMEOUT; goto terminate_int; } if ((status[SDI_CMD] & MMC_STATUS_CRC_RESPONSE_ERROR ) || (status[SDI_DATA]& (MMC_STATUS_CRC_WRITE_ERROR|MMC_STATUS_CRC_READ_ERROR)) ) { if (/* Slot device is MMC && see Exception 2.*/ g_s3c_mmc_data.type == RT_RESPONSE_ONLY) { MMC_DEBUG(0," DUMMY MMC_ERROR_CRC "); } else { MMC_DEBUG(0," MMC_ERROR_CRC "); retval = MMC_ERROR_CRC; goto terminate_int; } } if ( status[SDI_CMD]& MMC_STATUS_RESPONSE_RECV_DONE && sd->request->result == MMC_NO_RESPONSE /* not yet response receveied. */ ) { rsp_done = 1; MMC_DEBUG(0," get_response "); mmc_s3c_get_response( sd->request ); } /** TODO :Fix me... * Read operation data error * Where do I handle "data error" not CRC Error--> I don't know */ if ((g_s3c_mmc_data.type==RT_READ) ){ if ( status[SDI_FIFO]&MMC_STATUS_FIFO_RX_FULL) { mmc_s3c_receive_data( sd->request,-1 ); } else { if (status[SDI_FIFO]&MMC_STATUS_FIFO_RX_LAST_DATA) { mmc_s3c_receive_data( sd->request, status[SDI_FIFO]&MMC_STATUS_FIFO_COUNT_MASK ); } else { if (rsp_done){ } else { MMC_DEBUG(0,": ERROR READ COMMAND 0x%08X,0x%08X,0x%08X" ,status[SDI_CMD],status[SDI_DATA],status[SDI_FIFO]); } } } } if (g_s3c_mmc_data.type==RT_WRITE && status[SDI_DATA]&MMC_STATUS_DATA_BUSY_TIMEOUT) { MMC_DEBUG(2," Not BUSY Finish"); data_busy =1; } if ((g_s3c_mmc_data.type==RT_WRITE)&& !rsp_done && !data_busy) { MMC_DEBUG(2, "nob=%d, counter=0x%08X", sd->request->nob, rSDIDCNT); if (!(status[SDI_DATA]&MMC_STATUS_DATA_TRANSFER_DONE)) { if (sd->request->nob>0) { if ((status[SDI_FIFO]&MMC_STATUS_FIFO_TX_HALF_FULL) || (status[SDI_FIFO]&MMC_STATUS_FIFO_EMPTY)) { mmc_s3c_transmit_data(sd->request); } } } } switch (g_s3c_mmc_data.type) { case RT_NO_RESPONSE: MMC_DEBUG(2," RT_NO_RESPONSE "); msk_reg = S3C_ALL_MMC_INT_MASK; break; case RT_RESPONSE_ONLY: MMC_DEBUG(2," RT_RESPONSE_ONLY "); if ( sd->request->result < 0 ) { printk(KERN_INFO "%s: illegal interrupt - command hasn't finished\n", __FUNCTION__); retval = MMC_ERROR_TIMEOUT; } msk_reg = S3C_ALL_MMC_INT_MASK; break; case RT_READ: if(sd->request->nob <=0 ) { msk_reg = S3C_ALL_MMC_INT_MASK; break; } /* It is impossible to get both response and data */ if ( sd->request->nob ) { msk_reg = S3C_RX_FIFO_LAST_DATA_INT_ON | S3C_RX_FIFO_FULL_INT_ON; MMC_DEBUG(2,": read SDIIMSK mask=0x%08x",rSDIIMSK); // mod_timer( &sd->irq_timer, jiffies + MMC_IRQ_TIMEOUT); // mmc_s3c_start_clock(); /* redundancy ? */ rSDIIMSK = msk_reg; return; } if(rsp_done) { MMC_DEBUG(2,": READ RESPONSE DONE "); MMC_DEBUG(2,": REGS sdicon 0x%08X sdiccon %08X sdidcon 0x%08X" ,rSDICON,rSDICCON,rSDIDCON); MMC_DEBUG(2,": REGS cmd 0x%08X data 0x%08X fifo 0x%08X",rSDICSTA,rSDIDSTA,rSDIFSTA); MMC_DEBUG(2,": REGS cmd 0x%08X data 0x%08X fifo 0x%08X",rSDICSTA,rSDIDSTA,rSDIFSTA); msk_reg = S3C_RX_FIFO_LAST_DATA_INT_ON | S3C_RX_FIFO_FULL_INT_ON; rSDIIMSK = msk_reg; return; } MMC_DEBUG(2," Unexpected Error "); break; case RT_WRITE: if( sd->request->nob <= 0) { if (!(status[SDI_DATA]& MMC_STATUS_DATA_TRANSFER_DONE)) { msk_reg = S3C_DATA_CNT_ZERO_INT_ON| S3C_BUSY_COMPLETE_INT_ON; mmc_s3c_start_clock(); /* redundancy ? */ rSDIIMSK = msk_reg; return; } else { msk_reg = S3C_ALL_MMC_INT_MASK; break; } } if( (sd->request->nob || !(status[SDI_DATA]& MMC_STATUS_DATA_TRANSFER_DONE)) && !data_busy ){ msk_reg = S3C_DATA_CNT_ZERO_INT_ON|S3C_BUSY_COMPLETE_INT_ON| S3C_TX_FIFO_EMPTY_INT_ON; MMC_DEBUG(2,": write SDIIMSK mask=0x%08x",rSDIIMSK); // mod_timer( &sd->irq_timer, jiffies + MMC_IRQ_TIMEOUT); mmc_s3c_start_clock(); /* redundancy ? */ rSDIIMSK = msk_reg; return; } if(data_busy) { msk_reg = S3C_BUSY_COMPLETE_INT_ON; } else { msk_reg = S3C_ALL_MMC_INT_MASK; } break; } // MMC_DEBUG(2,": terminating status=0x%04x", S3C_ASIC1_MMC_Status );terminate_int: rSDIIMSK = msk_reg; // del_timer_sync( &sd->irq_timer ); sd->request->result = retval; MMC_DEBUG(2," Before mmc_cmd_complete "); mmc_cmd_complete( sd->request ); sd->request = NULL;}/******* * Prototype * static void mmc_s3c_general_mmc_interrupt(int irq, void *dev_id, struct pt_regs *regs) * * Purpose: * 1. Analysis Command,Data and Fifo Status of SD/MMC registers * Entry * Exit * Exceptions: *****************************************************/static void mmc_s3c_general_mmc_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct s3c_mmc_data *sd = (struct s3c_mmc_data *) dev_id; /* Disable irq */ disable_irq( irq ); u16 status[SDI_STATUS_LENGTH]= {0}; status[SDI_CMD] = rSDICSTA; status[SDI_DATA] = rSDIDSTA; status[SDI_FIFO] = rSDIFSTA; sd_status_clear(2); MMC_DEBUG(2, " rSDIIMSK 0x%08X cmd 0x%08X data 0x%08X fifo 0x%08X",rSDIIMSK,status[0],status[1],status[2]); MMC_DEBUG(2, " rSDICON 0x%08X CCON 0x%08X DCONdata 0x%08X ",rSDICON,rSDICCON,rSDIDCON); /* this can happen if there is an old interrupt hanging around when the irq is registered */ if (sd->request == NULL) { printk ("ignoring mmc irq with null request\n"); enable_irq( irq ); return; }/*#ifdef DEBUG START_MMC_DEBUG(2) { printk(__FUNCTION__ " cmd 0x%08X data 0x%08X fifo 0x%08X",rSDICSTA,rSDIDSTA,rSDIFSTA); decode_status(status); printk(")\n"); } END_MMC_DEBUG;#endif*/ mmc_s3c_split_status( sd, status, 0 ); /* Clear the interrupt. Must write a one to the src pending register then the interrupt pending register. */ h5400_asic_write_register (H5400_ASIC_IC_SRCPND, _H5400_ASIC_IC_INT_SD); h5400_asic_write_register (H5400_ASIC_IC_INTPND, _H5400_ASIC_IC_INT_SD); /* Enable the irq */ enable_irq( irq );}/******* * Prototype * static void mmc_s3c_irq_timeout( unsigned long nr ) * Purpose: * 1. mmc_s3c_reset_timeout (start) * 2. mmc_s3c_exec_command (start) 3. mmc_s3c_split_status (stop) DATA Transfer (read/write), Reset timeout implementation * Entry * Exit * Exceptions: *****************************************************/static void mmc_s3c_irq_timeout( unsigned long nr ){ struct s3c_mmc_data *sd = (struct s3c_mmc_data *) nr; u16 status[SDI_STATUS_LENGTH]= {0}; status[SDI_CMD] = rSDICSTA; status[SDI_DATA] = rSDIDSTA; status[SDI_FIFO] = rSDIFSTA; sd_status_clear(2);/*#ifdef CONFIG_MMC_DEBUG START_MMC_DEBUG(2) { printk(__FUNCTION__ " sd=%p status=0x%04x (", sd, status); decode_status(status); printk(")\n"); } END_MMC_DEBUG;#endif*/ // g_s3c_asic_statistics.mmc_timeout++; mmc_s3c_split_status( sd, status, 1 );}static void mmc_s3c_slot_up( void ){ MMC_DEBUG(1," before slot_up"); /* Set up timers */ g_s3c_mmc_data.sd_detect_timer.function = mmc_s3c_fix_sd_detect; g_s3c_mmc_data.sd_detect_timer.data = (unsigned long) &g_s3c_mmc_data; init_timer(&g_s3c_mmc_data.sd_detect_timer); if (lowlevel->slot_init) lowlevel->slot_init(lowlevel); /* Important notice for MMC test condition */ /* Cmd & Data lines must be enabled pull up resister */ rSDIPRE=(2*PCLK)/(MMC_CLOCK_SLOW)-1; // 400KHz /* For SDIO use RECV_SDIO_INT_EN */ rSDICON=FIFO_RESET |CLOCK_OUT_EN; /* BYTE Type A */ rSDIDTIMER=0xffff; // Set timeout count}static void mmc_s3c_slot_down(void) { del_timer_sync(&g_s3c_mmc_data.sd_detect_timer); if (lowlevel->slot_cleanup) lowlevel->slot_cleanup(lowlevel);}/******* * Prototype * static int mmc_s3c_slot_is_empty (int slot) * Purpose: * Entry * Exit * 1 : slot is empty * 0 : occupied * Exceptions: *****************************************************/static int mmc_s3c_slot_is_empty (int slot){ int retval = 1; if (lowlevel->slot_is_empty) retval = lowlevel->slot_is_empty(lowlevel); return retval;}static int mmc_s3c_slot_init( void ){ int retval; MMC_DEBUG(1,""); /* Set up timers */ /* g_s3c_mmc_data.sd_detect_timer.function = mmc_s3c_fix_sd_detect; g_s3c_mmc_data.sd_detect_timer.data = (unsigned long) &g_s3c_mmc_data; init_timer(&g_s3c_mmc_data.sd_detect_timer); g_s3c_mmc_data.sd_detect_timer.expires = jiffies + (250 * HZ) / 1000; add_timer(&g_s3c_mmc_data.sd_detect_timer); */ /* g_s3c_mmc_data.reset_timer.function = mmc_s3c_reset_timeout; g_s3c_mmc_data.reset_timer.data = (unsigned long) &g_s3c_mmc_data; init_timer(&g_s3c_mmc_data.reset_timer);*//* g_s3c_mmc_data.irq_timer.function = mmc_s3c_irq_timeout; g_s3c_mmc_data.irq_timer.data = (unsigned long) &g_s3c_mmc_data; init_timer(&g_s3c_mmc_data.irq_timer);*/ /* Basic service interrupt */ mmc_s3c_slot_up(); retval = request_irq( lowlevel->sdi_irq, mmc_s3c_general_mmc_interrupt, SA_INTERRUPT, "mmc_s3c_int", &g_s3c_mmc_data ); if ( retval ) { printk(KERN_CRIT "%s: unable to grab MMC IRQ %d\n", __FUNCTION__, lowlevel->sdi_irq); return retval; } retval = request_irq( lowlevel->detect_irq, mmc_s3c_sd_detect_isr, SA_INTERRUPT, "mmc_s3c_sd_detect", &g_s3c_mmc_data ); if ( retval ) { printk(KERN_CRIT "%s: unable to grab SD_DETECT IRQ %d\n", __FUNCTION__, lowlevel->detect_irq); free_irq(lowlevel->sdi_irq, &g_s3c_mmc_data); } return retval;}static void mmc_s3c_slot_cleanup( void ){ MMC_DEBUG(1,""); mmc_s3c_slot_down(); free_irq(lowlevel->sdi_irq, &g_s3c_mmc_data); free_irq(lowlevel->detect_irq, &g_s3c_mmc_data);}/***********************************************************/static struct mmc_slot_driver dops = { owner: THIS_MODULE, name: "S3C2410 MMC", ocr: 0x00ff8000, /*Valid voltage ranges */ flags: MMC_SDFLAG_MMC_MODE, /* Slot driver flags */ init: mmc_s3c_slot_init, cleanup: mmc_s3c_slot_cleanup, is_empty: mmc_s3c_slot_is_empty, send_cmd: mmc_s3c_send_command, set_clock: mmc_s3c_set_clock,};int s3c_mmc_register_slot(struct s3c_mmc_lowlevel *s3c_mmc_lowlevel){ int retval; MMC_DEBUG(0," s3c_mmc_init function start"); lowlevel = s3c_mmc_lowlevel; retval = mmc_register_slot_driver(&dops,1); if ( retval < 0 ) printk(KERN_INFO "%s: unable to register slot", __FUNCTION__); return retval;}EXPORT_SYMBOL(s3c_mmc_register_slot);int s3c_mmc_unregister_slot(void){ int retval = 0; MMC_DEBUG(0,""); mmc_unregister_slot_driver(&dops); lowlevel = NULL; return retval;}EXPORT_SYMBOL(s3c_mmc_unregister_slot);MODULE_AUTHOR("Sangwook Lee<hitchcar@sec.samsung.com>, Jamey Hicks <jamey.hicks@hp.com>");MODULE_LICENSE("GPL");MODULE_DESCRIPTION("Samsung Asic SD/MMC driver ");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -