init_timer(&timer1); timer1.function = test_time; timer1.data = 0; timer1.expires = jiffies + msecs_to_jiffies(1); add_timer(&timer1); sd_test(mmc); printk("count = %d ",count);
sd_test()函数写在probe函数中,但要等待sd初始化完毕才行,需要在上电时就插入SD卡,而不要等待系统起来之后。另外,如果mmc_rescan函数使用的工作队列实现的,那么它与probe就属于两个线程,会造成在执行sd_test时,sd卡还没初始化好,所以测试时不要用工作队列,直接调用就可以了。
void test_time(void) { count++; mod_timer(&timer1,jiffies+msecs_to_jiffies(1)); }
计数方式,没1/HZ时间计数一次,HZ跟系统相关,我的是250HZ,精确度是0.004S,msecs_to_jiffies(x),x是指tick数,间断时间由tick数*精确度。系统的计数器是超时计数,使用mod_timer函数重启计数,并赋值新的值。
void sd_test(struct mmc_host *mmc) { struct sepmmc_host *host = mmc_priv(mmc); reset_hardware(host); disable_any_int(host); clear_any_pending_int(host); sepmmc_start_command(host); init_completion(&host->cmd_complete_request); enable_command_done_int(host); wait_for_completion(&host->cmd_complete_request); printk("command transfer over "); init_completion(&host->data_complete_request); enable_data_transfer_over_int(host); wait_for_completion(&host->data_complete_request); printk("data transfer over "); // dma_free_coherent(NULL, 0x2000, p ,bus_addr); // if (!mrq->data->error && mrq->stop) { // init_completion(&host->cmd_complete_request); // enable_command_done_int(host); // wait_for_completion(&host->cmd_complete_request); // } host->mrq = NULL; if(host->cmd) kfree(host->cmd); host->cmd = NULL; host->data = NULL; // mmc_request_done(mmc, mrq); printk("------sd_test out------ "); }
void sepmmc_start_command(struct sepmmc_host *host) { struct mmc_command *cmd; unsigned int cmd_reg=0; dma_test(host->mmc); cmd = (struct mmc_command *)kmalloc(sizeof(struct mmc_command),GFP_KERNEL); printk("sepmmc_start_command into "); cmd->opcode = 18; cmd->arg = 0; cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; cmd_reg |= cmd->opcode; if(cmd->flags & MMC_RSP_PRESENT) cmd_reg |= SDIO_CMD_RESP_EXPE(1); if(cmd->flags & MMC_RSP_136) cmd_reg |= SDIO_CMD_LONG_RESP(1); if(cmd->flags & MMC_RSP_CRC) cmd_reg |= SDIO_CMD_CHK_RESP_CRC(1); cmd_reg |= SDIO_CMD_HAVE_DAT_TRAN(1); cmd_reg |= SDIO_CMD_WAIT_DAT(1); cmd_reg |= SDIO_CMD_START; host->cmd = cmd; writel(0,SDIO1_CMDARG_V); // writel(cmd_reg,SDIO1_CMD_V); writel(0x80002352,SDIO1_CMD_V); printk("sepmmc_start_command over "); }
void dma_test(struct mmc_host *mmc) { struct sepmmc_host *host = mmc_priv(mmc); //struct sepmmc_dma_descriptor *descriptor_test[1]; struct mmc_data *data; //dma_addr_t DESCRIPTOR_BASE_TEST[1]; dma_addr_t bus_addr; int i = 0; char *p ; printk("------sd_test into------ "); writel(512,SDIO1_BLKSIZ_V); //block size 512 writel(0x800000,SDIO1_BYTCNT_V);//8M data = (struct mmc_data*)kmalloc(sizeof(struct mmc_data),GFP_KERNEL); data->blksz = 512; data->blocks = 0x4000; data->flags = MMC_DATA_READ; data->stop = NULL; host->data = data; for(i = 0;i < 1024;i++) { descriptor_test[i]=dma_alloc_coherent(NULL, sizeof(struct sepmmc_dma_descriptor),&DESCRIPTOR_BASE_TEST[i], GFP_KERNEL); if(!descriptor_test[i]) printk("descriptor malloc err "); } // p=dma_alloc_coherent(NULL,0x2000,&bus_addr,GFP_KERNEL); // if(!p) // printk("p malloc err "); // descriptor_test[0]->des0 = 0x8000003c; // descriptor_test[0]->des1 = 0x2000; // descriptor_test[0]->des2 = bus_addr; // descriptor_test[0]->des3 = 0; for(i=0;i<1024;i++) { if(i == 0) descriptor_test[i]->des0 = 0x80000018; else if(i == 1023) descriptor_test[i]->des0 = 0x80000034; else descriptor_test[i]->des0 = 0x80000010; } p=dma_alloc_coherent(NULL,0x2000,&bus_addr,GFP_KERNEL); if(!p) printk("p malloc err "); for(i = 0;i<1024;i++) { descriptor_test[i]->des1 = 0x2000; descriptor_test[i]->des2 = bus_addr; } for(i = 0;i<1024;i++) { if(i < 1023) descriptor_test[i]->des3 = DESCRIPTOR_BASE_TEST[i+1]; else descriptor_test[i]->des3 = 0; } writel(DESCRIPTOR_BASE_TEST[0],SDIO1_DBADDR_V); writel(0x82,SDIO1_BMOD_V); printk("dma init over "); }
这边配置要注意,自己创建cmd 和 data函数,比如不需要stop命令,就使用data->stop = NULL;这些在中断处理函数中要用,主要的错误就出现在中断处理函数中。
我使用的是内部DMA,与一般的外部DMA不一样,代码差距较大。