diff options
author | Florian Schirmer <devnull@localhost> | 2003-01-25 16:25:48 +0000 |
---|---|---|
committer | Florian Schirmer <devnull@localhost> | 2003-01-25 16:25:48 +0000 |
commit | 20f38ee4089ddef8a057920c8ded5b67fd24bd60 (patch) | |
tree | ae376aa3626c959aa6d64d1d74dfc1a1db366116 /linux/drivers/media/dvb/bt8xx/bt878.c | |
parent | 79dbc09e09d48ebb4a087f003789a8bf22d2cc13 (diff) | |
download | mediapointer-dvb-s2-20f38ee4089ddef8a057920c8ded5b67fd24bd60.tar.gz mediapointer-dvb-s2-20f38ee4089ddef8a057920c8ded5b67fd24bd60.tar.bz2 |
- Rewritten RISC programm
- Push sync handling down to DVB API
- Major fixes
Diffstat (limited to 'linux/drivers/media/dvb/bt8xx/bt878.c')
-rw-r--r-- | linux/drivers/media/dvb/bt8xx/bt878.c | 390 |
1 files changed, 160 insertions, 230 deletions
diff --git a/linux/drivers/media/dvb/bt8xx/bt878.c b/linux/drivers/media/dvb/bt8xx/bt878.c index 8ade22161..f24eb8705 100644 --- a/linux/drivers/media/dvb/bt8xx/bt878.c +++ b/linux/drivers/media/dvb/bt8xx/bt878.c @@ -84,228 +84,135 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val) #endif #define dprintk if(bt878_debug) printk -/*******************************/ -/* Memory management functions */ -/*******************************/ +static void bt878_mem_free(struct bt878 *bt) +{ -#define MDEBUG(x) do { } while(0) /* Debug memory management */ + if (bt->buf_cpu) { -/* All taken from [DaveM] from the bttv driver - * I will not pretend that I understand this, but - * it seems to work. - * - * The code used to assume that the kernel vmalloc mappings - * existed in the page tables of every process, this is simply - * not guarenteed. We now use pgd_offset_k which is the - * defined way to get at the kernel page tables. - */ + pci_free_consistent(bt->dev, bt->buf_size, bt->buf_cpu, bt->buf_dma); + bt->buf_cpu = NULL; -/* Given PGD from the address space's page table, return the kernel - * virtual mapping of the physical memory mapped at ADR. - */ -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) -{ - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - - if (!pgd_none(*pgd)) { - pmd = pmd_offset(pgd, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset(pmd, adr); - pte = *ptep; - if(pte_present(pte)) { - ret = (unsigned long) page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - - } - } - } - MDEBUG(printk("uv2kva(%lx-->%lx)", adr, ret)); - return ret; + } + + if (bt->risc_cpu) { + + pci_free_consistent(bt->dev, bt->risc_size, bt->risc_cpu, bt->risc_dma); + bt->risc_cpu = NULL; + + } + } -static inline unsigned long uvirt_to_bus(unsigned long adr) +static int bt878_mem_alloc(struct bt878 *bt) { - unsigned long kva, ret; - kva = uvirt_to_kva(pgd_offset(current->mm, adr), adr); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("uv2b(%lx-->%lx)", adr, ret)); - return ret; + if (!bt->buf_cpu) { + + bt->buf_size = 128 * 1024; + + bt->buf_cpu = pci_alloc_consistent(bt->dev, bt->buf_size, &bt->buf_dma); + + if (!bt->buf_cpu) + return -ENOMEM; + + memset(bt->buf_cpu, 0, bt->buf_size); + + } + + if (!bt->risc_cpu) { + + bt->risc_size = PAGE_SIZE; + bt->risc_cpu = pci_alloc_consistent(bt->dev, bt->risc_size, &bt->risc_dma); + + if (!bt->risc_cpu) { + + bt878_mem_free(bt); + + return -ENOMEM; + + } + + memset(bt->risc_cpu, 0, bt->risc_size); + + } + + return 0; + } -static inline unsigned long kvirt_to_bus(unsigned long adr) -{ - unsigned long va, kva, ret; +/* RISC instructions */ +#define RISC_WRITE (0x01 << 28) +#define RISC_JUMP (0x07 << 28) +#define RISC_SYNC (0x08 << 28) - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = virt_to_bus((void *)kva); - MDEBUG(printk("kv2b(%lx-->%lx)", adr, ret)); - return ret; -} +/* RISC bits */ +#define RISC_WR_SOL (1 << 27) +#define RISC_WR_EOL (1 << 26) +#define RISC_IRQ (1 << 24) +#define RISC_STATUS(status) ((((~status) & 0x0F) << 20) | ((status & 0x0F) << 16)) +#define RISC_SYNC_RESYNC (1 << 15) +#define RISC_SYNC_FM1 0x06 +#define RISC_SYNC_VRO 0x0C -/* Here we want the physical address of the memory. - * This is used when initializing the contents of the - * area and marking the pages as reserved. - */ -static inline unsigned long kvirt_to_pa(unsigned long adr) +#define RISC_FLUSH() bt->risc_pos = 0 +#define RISC_INSTR(instr) bt->risc_cpu[bt->risc_pos++] = cpu_to_le32(instr) + +static int bt878_make_risc(struct bt878 *bt) { - unsigned long va, kva, ret; - va = VMALLOC_VMADDR(adr); - kva = uvirt_to_kva(pgd_offset_k(va), va); - ret = __pa(kva); - MDEBUG(printk("kv2pa(%lx-->%lx)", adr, ret)); - return ret; -} + u32 buf_pos = 0; + u32 line; -static void * rvmalloc(signed long size) -{ - void * mem; - unsigned long adr, page; + bt->block_bytes = bt->buf_size >> 4; + bt->block_count = 1 << 4; + bt->line_bytes = bt->block_bytes; + bt->line_count = bt->block_count; - mem=vmalloc_32(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - page = kvirt_to_pa(adr); - mem_map_reserve(virt_to_page(__va(page))); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} + while (bt->line_bytes > 4095) { -static void rvfree(void * mem, signed long size) -{ - unsigned long adr, page; - - if (mem) - { - adr=(unsigned long) mem; - while (size > 0) - { - page = kvirt_to_pa(adr); - mem_map_unreserve(virt_to_page(__va(page))); - adr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); - } -} + bt->line_bytes >>= 1; + bt->line_count <<= 1; -/*****************************/ -/* Buffer setup function(s) */ -/*****************************/ + } -int bt878_get_buffers(struct bt878 *bt, int bpl, int lpf, int nbufs, int sync) -{ - /* try to allocate nbufs buffers, 2<=nbufs<=16. Each buffer is - a "frame" bpl bytes wide and lpf lines high. - The buffers will be contiguous in kernel virtual space, but - will consist of discontinuous physical pages. - Set up a DMA program to read all these buffers in sequence, - and generate an interrupt at the start of each buffer. - if sync==1, insert a sync RISC op at the start of each buffer, - else don't. - */ - - unsigned long *pc, *pc2; - unsigned char *bp; - int i, j, size, rest; - unsigned long op; - - dprintk("bt878 debug: bt878_get_buffers(%p, bpl=0x%x, lpf=0x%x, n=0x%x\n",bt,bpl,lpf,nbufs); - if(nbufs<2||nbufs>16) return -EINVAL; - if(bpl<0||bpl>4095) return -EINVAL; - if(lpf*nbufs<0||lpf*nbufs>255) return -EINVAL; - if(!bt) return -ENXIO; - - /* stop a possibly running DMA operation */ - btand(~0x0f,BT878_AGPIO_DMA_CTL); - i=btread(BT878_AGPIO_DMA_CTL); - - if(bt->buffer) {rvfree(bt->buffer,bt->allocbufsize); bt->buffer=0; } - if(bt->riscprog) {rvfree(bt->riscprog,PAGE_SIZE); bt->riscprog=0;} - - bt->framesize=bpl*lpf; - bt->buffersize=bt->framesize*nbufs; - bt->allocbufsize=(bpl*lpf*nbufs); - if(bt->allocbufsize&~PAGE_MASK) - bt->allocbufsize=(bt->allocbufsize&PAGE_MASK)+PAGE_SIZE; - dprintk("bt878 debug: allocating 0x%x bytes (min was 0x%x)\n",bt->allocbufsize,(bpl*lpf*nbufs)); - if(!(bt->buffer=rvmalloc(bt->allocbufsize))) { - return -ENOMEM; - } - if(!(bt->riscprog=rvmalloc(PAGE_SIZE))) { - goto fail1; - } - - dprintk("bt878 debug: buffer=%p, riscprog=%p\n",bt->buffer,bt->riscprog); - /* ok. We have the memory for the buffers. Let us set up the DMA prog */ - pc=bt->riscprog; - bp=bt->buffer; - /* sync operation at the beginning of the program */ - *pc++=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC| - BT848_FIFO_STATUS_FM1|(0xf<<20)); - *pc++=0; - for(i=0;i<nbufs;i++) { - for(j=0;j<lpf;j++) { - size=bpl; - rest=PAGE_SIZE-((unsigned int)bp&(~PAGE_MASK)); - if(rest<size) size=rest; - op=BT848_RISC_WRITE|((~i)&0x0f)<<20|(i&0x0f)<<16|size - |BT848_RISC_SOL; - if(j==0) op|=BT848_RISC_IRQ; - if(size==bpl) op|=BT848_RISC_EOL; - *pc++=cpu_to_le32(op); - *pc++=cpu_to_le32(kvirt_to_bus((unsigned long)bp)); - bp+=size; - if(size<bpl) { - size=bpl-size; - op=BT848_RISC_WRITE|((~i)&0x0f)<<20|(i&0x0f)<<16|size - |BT848_RISC_EOL; - *pc++=cpu_to_le32(op); - *pc++=cpu_to_le32(kvirt_to_bus((unsigned long)bp)); - bp+=size; - if((pc-(unsigned long *)bt->riscprog)*sizeof(long)>PAGE_SIZE) goto fail2; - } - } - if(sync) { - *pc++=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC| - BT848_FIFO_STATUS_FM1); - *pc++=0; - } - } - *pc++=cpu_to_le32(BT848_RISC_JUMP); - *pc++=cpu_to_le32(kvirt_to_bus((unsigned long)bt->riscprog)); - - btwrite(cpu_to_le32(bpl|((lpf*nbufs)<<16)),BT878_APACK_LEN); - btwrite(cpu_to_le32(kvirt_to_bus((unsigned long)bt->riscprog)),BT878_ARISC_START); - - if(bt878_debug) { - for(pc2=bt->riscprog;pc2<pc;pc2++) printk("riscprog[%3.3x]=%8.8lx\n", - (pc2-(unsigned long *)(bt->riscprog)),*pc2); - } - - bt->nbuffers=nbufs; - - return 0; - -fail2: - if(bt->riscprog) {rvfree(bt->riscprog,PAGE_SIZE); bt->riscprog=0;} -fail1: - if(bt->buffer) {rvfree(bt->buffer,bt->allocbufsize); bt->buffer=0; bt->allocbufsize=0;} - return -ENOMEM; + if (bt->line_count > 255) { + + printk("bt878: buffer size error!\n"); + + return -EINVAL; + + } + + RISC_FLUSH(); + + RISC_INSTR(RISC_SYNC | RISC_SYNC_FM1); + RISC_INSTR(0); + + for (line = 0; line < bt->line_count; line++) { + + // At the beginning of every block we issue an IRQ with previous (finished) block number set + if (!(buf_pos % bt->block_bytes)) + RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | RISC_IRQ | RISC_STATUS(((buf_pos / bt->block_bytes) + (bt->block_count - 1)) % bt->block_count) | bt->line_bytes); + else + RISC_INSTR(RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL | bt->line_bytes); + + RISC_INSTR(bt->buf_dma + buf_pos); + + buf_pos += bt->line_bytes; + + } + + RISC_INSTR(RISC_SYNC | RISC_SYNC_VRO); + RISC_INSTR(0); + + RISC_INSTR(RISC_JUMP); + RISC_INSTR(bt->risc_dma); + + btwrite((bt->line_count << 16) | bt->line_bytes, BT878_APACK_LEN); + + return 0; + } - -EXPORT_SYMBOL(bt878_get_buffers); /*****************************/ /* Start/Stop grabbing funcs */ @@ -313,33 +220,49 @@ EXPORT_SYMBOL(bt878_get_buffers); void bt878_start(struct bt878 *bt, u32 controlreg) { - if(!bt->buffer||!bt->riscprog) bt878_get_buffers(bt,0x400,1,4,0); - /* this call to bt878_get_buffers ought to succeed... */ + dprintk("bt878 debug: bt878_start (ctl=%8.8x)\n",controlreg); - controlreg&=~0x1f; - controlreg|=0x1b; - btwrite(cpu_to_le32(kvirt_to_bus((unsigned long)bt->riscprog)), - BT878_ARISC_START); - if(bt->tasklet) tasklet_enable(bt->tasklet); + + controlreg &= ~0x1F; + controlreg |= 0x1B; + + btwrite(cpu_to_le32(bt->risc_dma), BT878_ARISC_START); + + if(bt->tasklet) + tasklet_enable(bt->tasklet); + btwrite(0x000ff800,BT878_AINT_MASK); btwrite(controlreg,BT878_AGPIO_DMA_CTL); + } void bt878_stop(struct bt878 *bt) { + u32 stat; - int i=0; + int i = 0; - btwrite(0,BT878_AINT_MASK); - btand(~0x1f,BT878_AGPIO_DMA_CTL); - dprintk("bt878 debug: bt878_stop\n"); - do { - stat=btread(BT878_AINT_STAT); - if(!(stat&BT878_ARISC_EN)) break; - i++; - } while(i<500); - if(bt->tasklet) tasklet_disable(bt->tasklet); - dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n",bt->nr,i,stat); + dprintk("bt878 debug: bt878_stop\n"); + + btwrite(0, BT878_AINT_MASK); + btand(~0x1F, BT878_AGPIO_DMA_CTL); + + do { + + stat = btread(BT878_AINT_STAT); + + if (!(stat&BT878_ARISC_EN)) + break; + + i++; + + } while (i < 500); + + if(bt->tasklet) + tasklet_disable(bt->tasklet); + + dprintk("bt878(%d) debug: bt878_stop, i=%d, stat=0x%8.8x\n",bt->nr,i,stat); + } EXPORT_SYMBOL(bt878_start); @@ -356,7 +279,7 @@ static void bt878_irq(int irq, void *dev_id, struct pt_regs * regs) struct bt878 *bt; bt=(struct bt878 *)dev_id; - + count=0; while(1) { stat=btread(BT878_AINT_STAT); @@ -397,7 +320,7 @@ static void bt878_irq(int irq, void *dev_id, struct pt_regs * regs) } if(astat&BT878_ARISCI) { spin_lock(&bt->s_lock); - bt->writebuf=(stat&BT878_ARISCS)>>28; + bt->finished_block = (stat & BT878_ARISCS) >> 28; spin_unlock(&bt->s_lock); wake_up_interruptible(&bt->readq); if(bt->tasklet) tasklet_schedule(bt->tasklet); @@ -496,18 +419,26 @@ static int __devinit bt878_probe(struct pci_dev *dev, const struct pci_device_id return -EIO; } */ - bt->nbuffers=bt->allocbufsize=0; - bt->buffer=bt->riscprog=0; + if ((result = bt878_mem_alloc(bt))) { + + printk("bt878: failed to allocate memory!\n"); + + goto fail2; + + } + + bt878_make_risc(bt); + btwrite(0,BT878_AINT_MASK); bt878_num++; return 0; -/* fail2: + fail2: free_irq(bt->irq,bt); -*/ fail1: + fail1: release_mem_region(pci_resource_start(bt->dev,0), pci_resource_len(bt->dev,0)); return result; @@ -520,7 +451,7 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev) if (bt878_verbose) printk("bt878(%d): unloading\n",bt->nr); - + /* turn off all capturing, DMA and IRQs */ btand(~15, BT878_AGPIO_DMA_CTL); @@ -547,8 +478,7 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev) */ bt->shutdown=1; - if(bt->buffer) {rvfree(bt->buffer,bt->allocbufsize); bt->buffer=0;} - if(bt->riscprog) {rvfree(bt->riscprog,PAGE_SIZE); bt->riscprog=0;} + bt878_mem_free(bt); pci_set_drvdata(pci_dev, NULL); return; |