Hello,
I'm quite new to (embedded-kernel level) linux even though I have a lot of experience otherwise with embedded systems, RTOSes. I was asked to help and develop a DMA driver which would enable a clean access between the MPC8245 and a PCI area (SDRAM), where other processor would read the data. The driver would be written at kernel level. Since I plunged into this feature I wasn't aware how complex all the memory aspect is. While I seem to understand the module interface, the memory accesses are far less obvious to me. There are 2 modes of operation for this particular DMA (chaining and direct). The code reflects that. I tried both and it doesn't work. In the init command I could call the "ch_"/none versions for chaining/direct modes. The only thing I managed to make work is to write to 0xfdcc0000 (over PCI) (I guess it comes from 4G - 48M memory map). Whether this helps me to actually write the driver, I don't know. How do I access a register in the EUMB region? Is it using ioremap? or _nocache? Is that a logical/phys memory? What do I save in the source adress/dest address? What format? Bus address? Virtual? Should I use writeb(w,l), readb(w,l)? Or just go and access the registers?
Really appreciate any help.
Following are some code lines: #define MPC8240_EUMBAR 0xf8000000-0x100000 #define DMA_SPACE(x) MPC8240_EUMBAR+0x1000+0x100*((x)+1) #define I2C_SPACE MPC8240_EUMBAR+0x3000 #define U32 unsigned int #define U8 unsigned char #define MEMORY_SIZE 13*1024*1024
typedef struct txdes { volatile U32 sa; volatile U32 hsa; volatile U32 da; volatile U32 hda; volatile U32 next; volatile U32 hnext; volatile U32 count; volatile U32 res; } TXD;
typedef struct dmas{ volatile U32 dmr; volatile U32 dsr; volatile U32 cdar; volatile U32 hcdar; volatile U32 sar; volatile U32 hsar; volatile U32 dar; volatile U32 hdar; volatile U32 bcr; volatile U32 ndar; } DMAS;
volatile DMAS* dma_t; volatile DMAS* dma_r; volatile TXD* txd[2]; volatile TXD* rxd[2]; char hllo[8] = "Hello"; char rrr[8];
static ch_dma_init() { int i; U32 temp; dma_t = (DMAS*) ioremap_nocache(DMA_SPACE(0),1024*1024); txd[0] = kmalloc(1024,GFP_KERNEL); temp = kmalloc(1024,GFP_KERNEL); temp += 0x40; temp &= 0xffffffe0; txd[0] = (TXD*)temp; printk("desc0:%x %x\n",txd[0],virt_to_bus(&txd[0])); temp = kmalloc(1024,GFP_KERNEL); temp += 0x40; temp &= 0xffffffe0; txd[1] = (TXD*)temp; printk("desc1:%x %x\n",txd[1],virt_to_bus(hllo)); for (i=0;isa = virt_to_bus(hllo); //txd[i]->da = virt_to_bus(rrr); txd[i]->da = 0xfdcc0008; txd[i]->count = 4; if (i==1) { txd[i]->next = 3; }else { txd[i]->next = virt_to_bus(&txd[1]) | 2; } } writel(virt_to_bus(&txd[0]),&dma_t->cdar); printk("prim %x %x %x %x %x %x\n", (((U32)readl(&dma_t->dmr))),(((U32)readl(&dma_t->dsr))), (((U32)readl(&dma_t->cdar))),(((U32)readl(&dma_t->sar))), (((U32)readl(&dma_t->dar))),(((U32)readl(&dma_t->bcr))));
}static int direct_dma_init(void) { U8* scr; char* ttt; U8* hhh; // scr = (U8*)(spPciSyscfg_c + g_virt_start_addr); dev = pci_find_device(0x14e4,0x5615,dev); if (dev == NULL) { printk("no logical\n"); } ttt = kmalloc(6656,GFP_KERNEL|GFP_DMA); //scr = ioremap(spPciSyscfg_c,1024*1024); // scr = ioremap((unsigned long)pci_resource_start(dev,0),1024*1024); scr = 0xfdcc0000; if (scr == NULL) { printk("cannot allocate\n"); } // scr += spPciSyscfg_c; printk("pci:%x ttt:%x",scr,ttt); dma_t = (DMAS*) ioremap(DMA_SPACE(0),1024*1024); printk("udma_t:%x",dma_t); //hhh = ioremap(I2C_SPACE,1024*1024); hhh = ioremap(MPC8240_EUMBAR,1024*1024); printk("vdma_t:%x",dma_t); printk("hhh:%x hhh:%x %x %x %x %x %x %x %x", readl(((U32*)(hhh+0x41030))), readl(((U32*)(hhh+0x3004))),readl(((U32*)(hhh+0x41020))), (((U32)readl(&dma_t->dmr))),(((U32)readl(&dma_t->dsr))), (((U32)readl(&dma_t->cdar))),(((U32)readl(&dma_t->sar))), (((U32)readl(&dma_t->dar))),(((U32)readl(&dma_t->bcr)))); //dma_t = __va((DMAS*) DMA_SPACE(0)); printk("dma_t:%x",dma_t); // dma_r = (DMAS*) ioremap(DMA_SPACE(1),1024*1024); //printk("dma_r:%x",dma_r); //poll dma channel DSR[CB] //if (!DSR[CB]) return; if (dma_t->dsr & 0x4) { printk("nu pe aici0"); return; } //if (dma_r->dsr & 0x4) { //printk("nu pe aici1"); // return; // } //SAR = hllo; //dma_t->sar = virt_to_bus(hllo); //dma_t->sar = (0xfdcc0000); writel(virt_to_bus(hllo),&dma_t->sar); //dma_t->sar = ( virt_to_bus(hllo)); //DAR = scr; //dma_t->dar = __le32_to_cpu(0xfdcc0008); writel(virt_to_bus(rrr),&dma_t->dar); //dma_t->dar = __le32_to_cpu(virt_to_bus(rrr)); //BCR = strlen(hllo); //dma_t->bcr = strlen(hllo) + 1; //dma_t->bcr = __le32_to_cpu(3); writel(3,&dma_t->bcr); //CDAR[CTT](channel0) = 01 (local->PCI); //dma_t->cdar =(0x2); //dma_t->cdar =(0x0); //dma_t->cdar =__le32_to_cpu(0x6); writel(0,&dma_t->cdar); //CDAR[CTT](channel1) = 10 (PCI->local); // dma_r->cdar = 0x4; //DMR[CTM](channelX) = 1; (direct mode) //dma_t->dmr |= __le32_to_cpu(0x4); writel(4,&dma_t->dmr); //writeb(22,scr); }
void dma_start_t(void) { //DMR[CS](x) = 0; //dma_t->dmr &= __le32_to_cpu(~0x1); writel((~0x1) | 0x4,&dma_t->dmr); //DMR[CS](x) = 1; //dma_t->dmr |= __le32_to_cpu(0x1); writel(5, &dma_t->dmr); }
void ch_dma_start_t(void) { U32 tt; //DMR[CS](x) = 0; //dma_t->dmr &= __le32_to_cpu(~0x1); writel((~0x1),&dma_t->dmr); //DMR[CS](x) = 1; //dma_t->dmr |= __le32_to_cpu(0x1); writel(1, &dma_t->dmr); printk("astept"); tt = readl(&dma_t->dsr); writel(tt,&dma_t->dsr); printk("prim %x %x %x %x %x %x tt:%x\n", (((U32)readl(&dma_t->dmr))),(((U32)readl(&dma_t->dsr))), (((U32)readl(&dma_t->cdar))),(((U32)readl(&dma_t->sar))), (((U32)readl(&dma_t->dar))),(((U32)readl(&dma_t->bcr))),tt);
}int init_module(void) { int err,i;
ch_dma_init(); ch_dma_start_t(); /* err = register_chrdev(MY_MAJOR,DEVICE_NAME,&Fops); if (err) { PRINTK ("Device failed with %d\n",err); unregister_chrdev(MY_MAJOR,DEVICE_NAME); return err; } PRINTK (" Device %s inserted\n",DEVICE_NAME);
*/ printk("uuuu"); for(i=0;i