📄 ftsdc010.c
字号:
parm.size = size >> 4; parm.burst = TRUE; parm.irq = APBDMA_TRIGGER_IRQ_WITH_ERROR; fa_set_apb_dma_params(SD_DMA_CHANNEL, &parm); if (dma_buf) consistent_sync(__va(dma_buf), size, DMA_TO_DEVICE); else consistent_sync(buf, size, DMA_TO_DEVICE); #ifndef CONFIG_FTSDC010_USE_APBDMA_POLL /* Set up time out timer */ init_timer(&to_timer); to_timer.expires = timeout; to_timer.function = sdc_apbdma_timeout_handler; to_timer.data = (unsigned long) info; add_timer(&to_timer); /* Start DMA */ fa_apb_dma_start(SD_DMA_CHANNEL); interruptible_sleep_on(&sd_dma_queue); //wait_event_interruptible_timeout(sd_dma_queue, !fa_apb_dma_get_cycle(SD_DMA_CHANNEL), SDC_TIMEOUT_BASE*((size+511)>>9)); //wait_event_interruptible_timeout(sd_dma_queue,fa_apb_dma_get_status(SD_DMA_CHANNEL) != INT_DMA_TRIGGER, SDC_TIMEOUT_BASE*((size+511)>>9)); /* clean up the timeout timer */ del_timer_sync(&to_timer); #else /* Start DMA */ fa_apb_dma_start(SD_DMA_CHANNEL); while( (i=fa_apb_dma_get_status(SD_DMA_CHANNEL)) == 0 ) { if ( time_after(jiffies, timeout) ) { sd_time_out=1; break; } } if ( sd_time_out == 1 ) { P_DEBUG("SD_Rx: APB DMA Tx Time-out\n"); sd_err_code = ERR_DATA_TIMEOUT_ERROR; } else if ( i&INT_DMA_ERROR ) { P_DEBUG(KERN_ERR "SD_Tx: APB DMA Error\n"); sd_err_code = ERR_APBDMA_RSP_ERROR; } else if ( i&INT_DMA_TRIGGER ) { P_DEBUG("SD_Tx: APB DMA Finish\n"); } #endif if ( sd_err_code == ERR_DATA_TIMEOUT_ERROR ) { printk("SD_Tx: APB DMA Tx Time-out\n"); //printk("dest=%x,size=%x\n",buf,size); } /* Stop DMA */ fa_apb_dma_stop(SD_DMA_CHANNEL); fa_apb_dma_reset(SD_DMA_CHANNEL); P_DEBUG("DMA Read sleep_on()\n"); } else#endif /* #ifdef CONFIG_FTSDC010_USE_APBDMA */#ifdef CONFIG_FTSDC010_USE_AHBDMA if (info->DMAEnable) { P_DEBUG("%s:size=%d, buf=%p) - DMA Write\n", __func__, size,buf ); if (dma_buf) parm.src = dma_buf; else parm.src = __pa(buf); fa_set_ahb_dma_src_params(SD_DMA_CHANNEL, parm.src, AHBDMA_MASTER_0, 2, 0); fa_set_ahb_dma_dst_params(SD_DMA_CHANNEL, FTSDC_PA_BASE + SDC_DATA_WINDOW_REG, AHBDMA_MASTER_0, 2, 2); fa_set_ahb_dma_transfer_bs(SD_DMA_CHANNEL, 1); //set burst fa_set_ahb_dma_transfer_params2(SD_DMA_CHANNEL, AHBDMA_MASTER_0, size, 1); fa_ahb_dma_init(SD_DMA_CHANNEL, 7); fa_ahb_dma_add_auto(SD_DMA_CHANNEL, size); if (dma_buf) consistent_sync(__va(dma_buf), size, DMA_TO_DEVICE); else consistent_sync(buf, size, DMA_TO_DEVICE); /* Set up time out timer */ init_timer(&to_timer); to_timer.expires = timeout; to_timer.function = sdc_ahbdma_timeout_handler; to_timer.data = (unsigned long) info; add_timer(&to_timer); /* Start DMA */ fa_ahb_dma_start(SD_DMA_CHANNEL); //interruptible_sleep_on(&sd_dma_queue); wait_event_interruptible_timeout(sd_dma_queue, fa_ahb_dma_all_done(SD_DMA_CHANNEL), SDC_TIMEOUT_BASE*((size+511)>>9)); /* clean up the timeout timer */ del_timer_sync(&to_timer); /* Stop DMA */ fa_ahb_dma_stop(SD_DMA_CHANNEL); fa_ahb_dma_reset(SD_DMA_CHANNEL); P_DEBUG("DMA Read sleep_on()\n"); } else#endif { while (size > 0) { if (!sdc_check_tx_ready()) return FALSE; /* write data from FIFO */ if (size >= (SDC_WRITE_FIFO_LEN << 2)) count = SDC_WRITE_FIFO_LEN; else count = (size >> 2) ; /* write data from FIFO */ for (i = 0; i < count; i++, buf++) SDC_W_REG(SDC_DATA_WINDOW_REG, *buf); size -= (count << 2); } } return sdc_check_data_crc();}void sdc_config_transfer(sd_card_t *SDCard, uint len, uint size, uint rw, uint timeout){ /* write timeout */ SDC_W_REG(SDC_DATA_TIMER_REG, timeout * 2); /* set data length */ SDC_W_REG(SDC_DATA_LEN_REG, len); /* set data block */ if (SDCard->DMAEnable) { P_DEBUG("%s() transfer DMA mode\n", __func__); SDC_W_REG(SDC_DATA_CTRL_REG, sd_block_size_convert(size) | SDC_DATA_CTRL_REG_DMA_EN | rw | SDC_DATA_CTRL_REG_DATA_EN); } else { P_DEBUG("%s() transfer nonDMA mode\n", __func__); SDC_W_REG(SDC_DATA_CTRL_REG, sd_block_size_convert(size) | rw | SDC_DATA_CTRL_REG_DATA_EN); }}/* Note: This funciton may be called by interrupt handler */void sdc_reset(void){ uint ret; unsigned long delay = jiffies + (HZ/10)*3; //Delay 300ms /* reset host interface */ SDC_W_REG(SDC_CMD_REG, SDC_CMD_REG_SDC_RST); /* loop, until the reset bit is clear */ do { ret = SDC_R_REG(SDC_CMD_REG); } while ((ret & SDC_CMD_REG_SDC_RST) != 0); #if 0 udelay(1000); #else while(time_before(jiffies, delay)); #endif}/* * SD card operation */void sd_endian_change(uint *dt, int len){ uint ul; for(; len > 0; len--, dt++) { ul = *dt; ((unchar *)dt)[0] = ((unchar *)&ul)[3]; ((unchar *)dt)[1] = ((unchar *)&ul)[2]; ((unchar *)dt)[2] = ((unchar *)&ul)[1]; ((unchar *)dt)[3] = ((unchar *)&ul)[0]; }}int sd_get_ocr(sd_card_t *info, uint hocr, uint *cocr){ uint status; int count = 0; do { if (info->CardType == MEMORY_CARD_TYPE_SD) { /* send CMD55 to indicate to the card that the next command is an application specific command */ if (!sdc_send_cmd(SD_APP_CMD | SDC_CMD_REG_NEED_RSP, ((uint) info->RCA) << 16, &status)) return FALSE; if (!sd_check_err(status)) return FALSE; /* send ACMD41 to get OCR register */ if (!sdc_send_cmd(SD_APP_OP_COND | SDC_CMD_REG_APP_CMD | SDC_CMD_REG_NEED_RSP, (uint) hocr, (uint *) cocr)) return FALSE; } else { /* send CMD1 to get OCR register */ if (!sdc_send_cmd(SD_MMC_OP_COND | SDC_CMD_REG_NEED_RSP, (uint) hocr, (uint *) cocr)) return FALSE; } if (count++ > SD_CARD_GET_OCR_RETRY_COUNT) { sd_err_code = ERR_SD_CARD_IS_BUSY; printk("%s : ERR_SD_CARD_IS_BUSY\n", __func__); return FALSE; } udelay(1000); /* According to spec, at most 1 msec or 74 clock cycles */ } while ((*cocr & SD_OCR_BUSY_BIT) != SD_OCR_BUSY_BIT); return TRUE;}int sd_get_scr(sd_card_t *info, uint *scr){ uint status; if (!sd_set_transfer_state(info)) return FALSE; if (!sdc_set_block_size(8)) return FALSE; sdc_config_transfer(info, 8, 8, SDC_DATA_CTRL_REG_DATA_READ, 0xFFFFFFFF); /* send CMD55 to indicate to the card that the next command is an application specific command */ if (!sdc_send_cmd(SD_APP_CMD | SDC_CMD_REG_NEED_RSP, ((uint) info->RCA) << 16, &status)) return FALSE; if (!sd_check_err(status)) return FALSE; /* send ACMD51 to get SCR */ if (!sdc_send_cmd(SD_SEND_SCR_CMD | SDC_CMD_REG_APP_CMD | SDC_CMD_REG_NEED_RSP, 0, &status)) return FALSE; if (!sd_check_err(status)) return FALSE; if (!sdc_read_block(info, 8, (uint *) scr)) return FALSE; if (!sdc_check_data_end()) return FALSE; sd_endian_change(scr, 2); return TRUE;}int sd_check_err(uint status){ if (status & SD_STATUS_ERROR_BITS) { sd_err_code = ERR_SD_CARD_STATUS_ERROR; printk("%s() ERR_SD_CARD_STATUS_ERROR %X\n", __func__, status); return FALSE; } sd_err_code = ERR_NO_ERROR; return TRUE;}int sd_get_card_state(sd_card_t *info, uint *ret){ uint status; /* send CMD13 to get card status */ if (!sdc_send_cmd(SD_SEND_STATUS_CMD | SDC_CMD_REG_NEED_RSP, ((uint) info->RCA) << 16, &status)) return FALSE; if (!sd_check_err(status)) return FALSE; *ret = (status & SD_STATUS_CURRENT_STATE) >> SD_STATUS_CURRENT_STATE_LOC; return TRUE;}int sd_operation_complete(sd_card_t *info, uint finish){ uint state; int count = 0; while (count++ < SD_CARD_WAIT_OPERATION_COMPLETE_RETRY_COUNT) { if (!sd_get_card_state(info, &state)) return FALSE; if (state == finish) return TRUE; } P_DEBUG("%s() error\n", __func__); return FALSE;}int sd_stop_transmission(void){ uint status; /* send CMD12 to stop transmission */ if (!sdc_send_cmd(SD_STOP_TRANSMISSION_CMD | SDC_CMD_REG_NEED_RSP, 0, &status)) return FALSE; if (!sd_check_err(status)) return FALSE; return TRUE;}int sd_set_card_standby(sd_card_t *info){ uint state; int count = 0; while (count++ < SD_CARD_STATE_CHANGE_RETRY_COUNT) { if (!sd_get_card_state(info, &state)) return FALSE; switch (state) { case SD_IDLE_STATE: case SD_READY_STATE: case SD_IDENT_STATE: printk("%s() error\n", __func__); return FALSE; case SD_DIS_STATE: return sd_operation_complete(info, SD_STBY_STATE); case SD_TRAN_STATE: if (!sdc_send_cmd(SD_SELECT_CARD_CMD, 0, NULL)) return FALSE; break; case SD_DATA_STATE: if (sd_operation_complete(info, SD_TRAN_STATE)) return TRUE; if (sd_err_code != ERR_NO_ERROR) return FALSE; if (!sd_stop_transmission()) return FALSE; break; case SD_RCV_STATE: if (sd_operation_complete(info, SD_TRAN_STATE)) return TRUE; if (sd_err_code != ERR_NO_ERROR) return FALSE; if (!sd_stop_transmission()) return FALSE; break; case SD_PRG_STATE: if (!sd_operation_complete(info, SD_TRAN_STATE)) return FALSE; break; case SD_STBY_STATE: return TRUE; } } P_DEBUG("%s() error\n", __func__); return FALSE;}uint two_power(uint n){ uint pow = 1; for (; n > 0; n--) pow <<= 1; return pow;}int sd_csd_parse(sd_csd_t *csd, uint *csd_word){ sd_csd_bit_t *csd_bit; SD_CSD_BIT_Struct_V2 *CSDPtr2; uint mult, blocks; if ((csd_word[0] & 0x00000001) != 1) { sd_err_code = ERR_CSD_REGISTER_ERROR; printk("%s() ERR_CSD_REGISTER_ERROR\n", __func__); return FALSE; } csd_bit = (sd_csd_bit_t *) csd_word; csd->CSDStructure = csd_bit->CSD_STRUCTURE; csd->MMCSpecVersion = csd_bit->MMC_SPEC_VERS; csd->TAAC_u = TAAC_TimeValueTable_u[csd_bit->TAAC_TimeValue] * TAAC_TimeUnitTable[csd_bit->TAAC_TimeUnit] / 10; csd->NSAC_u = csd_bit->NSAC * 100; csd->TransferSpeed = TRANS_SPEED_RateUintTable[csd_bit->TRAN_SPEED_RateUnit] * TRANS_SPEED_TimeValueTable_u[csd_bit->TRAN_SPEED_TimeValue] / 10; csd->CardCmdClass = csd_bit->CCC; //added by FTC_mingfeng, for compatible with SD1.0, SD1.0 < 512 bytes and SD2.0 = 512 bytes csd->ReadBlockLength = two_power((csd_bit->READ_BL_LEN>9)?9:csd_bit->READ_BL_LEN); csd->ReadBlockPartial = csd_bit->READ_BL_PARTIAL; csd->WriteBlockMisalign = csd_bit->WRITE_BLK_MISALIGN; csd->ReadBlockMisalign = csd_bit->READ_BLK_MISALIGN; csd->DSRImplemant = csd_bit->DSR_IMP; if(sd_card_info.OCR & SD_OCR_STATUS_BIT ){ //high capacity support CSDPtr2 = (SD_CSD_BIT_Struct_V2 *)csd_word; blocks = ( CSDPtr2->C_SIZE_1 + 1 ) << 10; } else{ mult = 1 << (csd_bit->C_SIZE_MULT + 2); //added by FTC_mingfeng, for compatible with SD1.0, SD1.0 IP must <= 512 bytes and SD2.0 = 512 bytes blocks = (((csd_bit->C_SIZE_1 | (csd_bit->C_SIZE_2 << 2)) + 1) * mult) << (csd_bit->READ_BL_LEN - 9); } csd->BlockNumber = blocks; csd->MemorySize = (blocks >> 14) * (csd->ReadBlockLength >> 6); // size > 2G can't show, use MB unit// printk("MemorySize=%d MB,ReadBlockLength=%d,BlockNumber=%d\n",csd->MemorySize,csd->ReadBlockLength,csd->BlockNumber);// printk("C_SIZE_1=%d,C_SIZE_2=%d\n",csd_bit->C_SIZE_1,csd_bit->C_SIZE_2);// printk("C_SIZE_1=%d,C_SIZE_2=%d\n",CSDPtr2->C_SIZE_1,CSDPtr2->C_SIZE_2);// csd->MemorySize = blocks * csd->ReadBlockLength; //for SD 2.0, the following four are 'don't care' csd->VDDReadMin_u = VDD_CURR_MIN_Table_u[csd_bit->VDD_R_CURR_MIN]; csd->VDDReadMax_u = VDD_CURR_MAX_Table_u[csd_bit->VDD_R_CURR_MAX]; csd->VDDWriteMin_u = VDD_CURR_MIN_Table_u[csd_bit->VDD_W_CURR_MIN]; csd->VDDWriteMax_u = VDD_CURR_MAX_Table_u[csd_bit->VDD_W_CURR_MAX]; csd->EraseBlkEnable = csd_bit->ERASE_BLK_ENABLE; csd->EraseSectorSize = csd_bit->ERASE_SECTOR_SIZE + 1; csd->WriteProtectGroupSize = csd_bit->WP_GRP_SIZE + 1; csd->WriteProtectGroupEnable = csd_bit->WP_GRP_ENABLE; csd->WriteSpeedFactor = two_power(csd_bit->R2W_FACTOR); //added by FTC_mingfeng, for compatible with SD1.0, SD1.0 < 512 bytes and SD2.0 = 512 bytes csd->WriteBlockLength = two_power((csd_bit->WRITE_BL_LEN>9)?9:csd_bit->WRITE_BL_LEN); csd->WriteBlockPartial = csd_bit->WRITE_BL_PARTIAL; csd->CopyFlag = csd_bit->COPY; csd->PermanentWriteProtect = csd_bit->PERM_WRITE_PROTECT; csd->TemporaryWriteProtect = csd_bit->TMP_WRITE_PROTECT; if (csd_bit->FILE_FORMAT_GRP == 0) csd->FileFormat = csd_bit->FILE_FORMAT; else csd->FileFormat = FILE_FORMAT_RESERVED; return TRUE;}int sd_cid_parse(sd_cid_t *cid, uint *cid_word){ unchar *ptr; int i; if ((cid_word[0] & 0x00000001) != 1) { sd_err_code = ERR_CID_REGISTER_ERROR; printk("%s() ERR_CID_REGISTER_ERROR\n", __func__); return FALSE; } cid->ManufacturerID = (cid_word[3] & 0xFF000000) >> 24; cid->ApplicationID = (cid_word[3] & 0x00FFFF00) >> 8; ptr = (unchar *) cid_word; ptr += 15 - 3; for (i = 0; i < 6; i++, ptr--) cid->ProductName[i] = *ptr; cid->ProductName[6] = '\0' ; cid->ProductRevisionLow = (cid_word[1] & 0x00F00000) >> 20; cid->ProductRevisionHigh = (cid_word[1] & 0x000F0000) >> 16; cid->ProductSerialNumber = ((cid_word[1] & 0x0000FFFF) << 16) + ((cid_word[0] & 0xFFFF0000) >> 16); cid->ManufactureMonth = ((cid_word[0] & 0x00000F00) >> 8);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -