SD卡 内置DMA的使用
2013-03-27 16:50 至上 阅读(1578) 评论(0) 编辑 收藏 举报static inline void sepmmc_dma(int real_num,struct sepmmc_host *host) { struct sepmmc_dma_descriptor *descriptor[real_num]; dma_addr_t bus_addr; dma_addr_t DESCRIPTOR_BASE[real_num]; int seg_len; int temp=0; mmc_debug("[%s] into \n",__func__); addr_minus =(unsigned int *)kmalloc(sizeof(unsigned int)*real_num,GFP_KERNEL); if(real_num > 1){ for(host->cur_seg = 0;host->cur_seg<real_num;host->cur_seg++) { mmc_debug("[%s] real_num > 1 \n",__func__); descriptor[host->cur_seg]=dma_alloc_coherent(NULL, sizeof(struct sepmmc_dma_descriptor),&DESCRIPTOR_BASE[host->cur_seg], GFP_KERNEL); printk("descriptor = 0x%08x,DESCRIPTOR_BASE = 0x%08x\n",(unsigned int)descriptor[host->cur_seg],DESCRIPTOR_BASE[host->cur_seg]); addr_minus[host->cur_seg] = (unsigned int)descriptor[host->cur_seg] - (unsigned int)DESCRIPTOR_BASE[host->cur_seg]; printk("addr_minux = 0x%08x \n", addr_minus[host->cur_seg]); if(!descriptor[host->cur_seg]) printk("descriptor malloc err\n"); if(host->cur_seg == 0) descriptor[host->cur_seg]->des0 = 0x80000018; else if(host->cur_seg == (real_num-1)) descriptor[host->cur_seg]->des0 = 0x80000034; else descriptor[host->cur_seg]->des0 = 0x80000010; } for(host->cur_seg = 0;host->cur_seg<host->seg_num;host->cur_seg++) { seg_len = sg_dma_len(&host->data->sg[host->cur_seg]); bus_addr = sg_dma_address(&host->data->sg[host->cur_seg]); if((seg_len - 8192)>0) { descriptor[temp]->des1 = 0x2000; descriptor[temp+1]->des1 = seg_len-0x2000; descriptor[temp]->des2 = bus_addr; descriptor[temp+1]->des2 = bus_addr+0x2000; temp = temp + 2; } else { descriptor[temp]->des1 = seg_len; descriptor[temp]->des2 = bus_addr; temp++; } } for(host->cur_seg = 0;host->cur_seg<real_num;host->cur_seg++) { mmc_debug("[%s],cur_seg=%d,bus_addr=0x%08x,seg_len=0x%x\n",__func__,host->cur_seg,descriptor[host->cur_seg]->des2,descriptor[host->cur_seg]->des1); mmc_debug("[%s],descriptor->des0=0x%08x\n",__func__,descriptor[host->cur_seg]->des0); } for(host->cur_seg = 0;host->cur_seg<real_num;host->cur_seg++) { if(host->cur_seg < (real_num-1)) descriptor[host->cur_seg]->des3 = DESCRIPTOR_BASE[host->cur_seg+1]; else descriptor[host->cur_seg]->des3 = 0; printk("---descriptor->des3=0x%08x\n",descriptor[host->cur_seg]->des3); } }else{ mmc_debug("[%s] real_num = 1 \n",__func__); descriptor[0] =dma_alloc_coherent(NULL, sizeof(struct sepmmc_dma_descriptor),&DESCRIPTOR_BASE[0], GFP_KERNEL); descriptor[0]->des0 = 0x8000003c; seg_len = sg_dma_len(&host->data->sg[0]); descriptor[0]->des1 = seg_len; bus_addr = sg_dma_address(&host->data->sg[0]); descriptor[0]->des2 = bus_addr; mmc_debug("[%s],bus_addr=0x%08x,seg_len=0x%x\n",__func__,bus_addr,seg_len); descriptor[0]->des3 = 0; printk("descriptor[0] = 0x%08x,DESCRIPTOR_BASE[0]=0x%08x \n",(unsigned int)descriptor[0],DESCRIPTOR_BASE[0]); addr_minus[0] =(unsigned int)descriptor[0] - (unsigned int)DESCRIPTOR_BASE[0]; printk("addr_minux = 0x%08x \n",addr_minus[0]); } writel(DESCRIPTOR_BASE[0],SDIO1_DBADDR_V); writel(0x82,SDIO1_BMOD_V); mmc_debug("[%s] out \n",__func__); }
static inline void sepmmc_dma_transfer(struct sepmmc_host *host) { int i=0; int seg_len=0; host->seg_num = dma_map_sg(mmc_dev(host->mmc), host->data->sg, host->data->sg_len, host->dir); real_num = host->seg_num; for(i=0;i<host->seg_num;i++) { seg_len = ( int)sg_dma_len(&host->data->sg[i]); if(seg_len>8192) real_num++; } mmc_debug("[%s],seg_num = %d sg_len = %d real_num=%d\n",__func__,host->seg_num,host->data->sg_len,real_num); sepmmc_dma(real_num,host);
- DMA使用的是物理地址,需要使用dma_malloc_coherent,使用kmalloc不可行,虽然有virt_to_phys,好像还是不靠谱。
- 物理地址与虚拟地址不是一个层次的东西,但是可以进行数据运算,比如说free(0x30000000)其实真看不出来是物理地址还是虚拟地址,上文使用的释放操作就是用了地址的加减操作,只要你自己分清楚那个事虚拟地址那个是物理地址就ok了。
- 在内核中,使用free函数,最好不要在中断上下文,会有warning。
- dma传输单个segment数据超过0x3000就是12k时会导致控制器死掉,时钟消失,暂时不知道为什么。而且单个segment一般不会超过12k。
- 在sd卡控制器挂掉后,reset重启是不行的,需要断电重启
- 内存释放注意顺序,哎,刚吃过亏了,虽然书本上看过很多,真正写的时候还是没注意。