代码改变世界

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重启是不行的,需要断电重启
  • 内存释放注意顺序,哎,刚吃过亏了,虽然书本上看过很多,真正写的时候还是没注意。