1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * arch/sh/boards/dreamcast/dma-pvr2.c 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * NEC PowerVR 2 (Dreamcast) DMA support 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Copyright (C) 2003, 2004 Paul Mundt 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public 9*1da177e4SLinus Torvalds * License. See the file "COPYING" in the main directory of this archive 10*1da177e4SLinus Torvalds * for more details. 11*1da177e4SLinus Torvalds */ 12*1da177e4SLinus Torvalds #include <linux/init.h> 13*1da177e4SLinus Torvalds #include <linux/kernel.h> 14*1da177e4SLinus Torvalds #include <linux/module.h> 15*1da177e4SLinus Torvalds #include <linux/interrupt.h> 16*1da177e4SLinus Torvalds #include <asm/mach/sysasic.h> 17*1da177e4SLinus Torvalds #include <asm/mach/dma.h> 18*1da177e4SLinus Torvalds #include <asm/dma.h> 19*1da177e4SLinus Torvalds #include <asm/io.h> 20*1da177e4SLinus Torvalds 21*1da177e4SLinus Torvalds static unsigned int xfer_complete = 0; 22*1da177e4SLinus Torvalds static int count = 0; 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) 25*1da177e4SLinus Torvalds { 26*1da177e4SLinus Torvalds if (get_dma_residue(PVR2_CASCADE_CHAN)) { 27*1da177e4SLinus Torvalds printk(KERN_WARNING "DMA: SH DMAC did not complete transfer " 28*1da177e4SLinus Torvalds "on channel %d, waiting..\n", PVR2_CASCADE_CHAN); 29*1da177e4SLinus Torvalds dma_wait_for_completion(PVR2_CASCADE_CHAN); 30*1da177e4SLinus Torvalds } 31*1da177e4SLinus Torvalds 32*1da177e4SLinus Torvalds if (count++ < 10) 33*1da177e4SLinus Torvalds pr_debug("Got a pvr2 dma interrupt for channel %d\n", 34*1da177e4SLinus Torvalds irq - HW_EVENT_PVR2_DMA); 35*1da177e4SLinus Torvalds 36*1da177e4SLinus Torvalds xfer_complete = 1; 37*1da177e4SLinus Torvalds 38*1da177e4SLinus Torvalds return IRQ_HANDLED; 39*1da177e4SLinus Torvalds } 40*1da177e4SLinus Torvalds 41*1da177e4SLinus Torvalds static int pvr2_request_dma(struct dma_channel *chan) 42*1da177e4SLinus Torvalds { 43*1da177e4SLinus Torvalds if (ctrl_inl(PVR2_DMA_MODE) != 0) 44*1da177e4SLinus Torvalds return -EBUSY; 45*1da177e4SLinus Torvalds 46*1da177e4SLinus Torvalds ctrl_outl(0, PVR2_DMA_LMMODE0); 47*1da177e4SLinus Torvalds 48*1da177e4SLinus Torvalds return 0; 49*1da177e4SLinus Torvalds } 50*1da177e4SLinus Torvalds 51*1da177e4SLinus Torvalds static int pvr2_get_dma_residue(struct dma_channel *chan) 52*1da177e4SLinus Torvalds { 53*1da177e4SLinus Torvalds return xfer_complete == 0; 54*1da177e4SLinus Torvalds } 55*1da177e4SLinus Torvalds 56*1da177e4SLinus Torvalds static int pvr2_xfer_dma(struct dma_channel *chan) 57*1da177e4SLinus Torvalds { 58*1da177e4SLinus Torvalds if (chan->sar || !chan->dar) 59*1da177e4SLinus Torvalds return -EINVAL; 60*1da177e4SLinus Torvalds 61*1da177e4SLinus Torvalds xfer_complete = 0; 62*1da177e4SLinus Torvalds 63*1da177e4SLinus Torvalds ctrl_outl(chan->dar, PVR2_DMA_ADDR); 64*1da177e4SLinus Torvalds ctrl_outl(chan->count, PVR2_DMA_COUNT); 65*1da177e4SLinus Torvalds ctrl_outl(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE); 66*1da177e4SLinus Torvalds 67*1da177e4SLinus Torvalds return 0; 68*1da177e4SLinus Torvalds } 69*1da177e4SLinus Torvalds 70*1da177e4SLinus Torvalds static struct irqaction pvr2_dma_irq = { 71*1da177e4SLinus Torvalds .name = "pvr2 DMA handler", 72*1da177e4SLinus Torvalds .handler = pvr2_dma_interrupt, 73*1da177e4SLinus Torvalds .flags = SA_INTERRUPT, 74*1da177e4SLinus Torvalds }; 75*1da177e4SLinus Torvalds 76*1da177e4SLinus Torvalds static struct dma_ops pvr2_dma_ops = { 77*1da177e4SLinus Torvalds .request = pvr2_request_dma, 78*1da177e4SLinus Torvalds .get_residue = pvr2_get_dma_residue, 79*1da177e4SLinus Torvalds .xfer = pvr2_xfer_dma, 80*1da177e4SLinus Torvalds }; 81*1da177e4SLinus Torvalds 82*1da177e4SLinus Torvalds static struct dma_info pvr2_dma_info = { 83*1da177e4SLinus Torvalds .name = "PowerVR 2 DMA", 84*1da177e4SLinus Torvalds .nr_channels = 1, 85*1da177e4SLinus Torvalds .ops = &pvr2_dma_ops, 86*1da177e4SLinus Torvalds .flags = DMAC_CHANNELS_TEI_CAPABLE, 87*1da177e4SLinus Torvalds }; 88*1da177e4SLinus Torvalds 89*1da177e4SLinus Torvalds static int __init pvr2_dma_init(void) 90*1da177e4SLinus Torvalds { 91*1da177e4SLinus Torvalds setup_irq(HW_EVENT_PVR2_DMA, &pvr2_dma_irq); 92*1da177e4SLinus Torvalds request_dma(PVR2_CASCADE_CHAN, "pvr2 cascade"); 93*1da177e4SLinus Torvalds 94*1da177e4SLinus Torvalds return register_dmac(&pvr2_dma_info); 95*1da177e4SLinus Torvalds } 96*1da177e4SLinus Torvalds 97*1da177e4SLinus Torvalds static void __exit pvr2_dma_exit(void) 98*1da177e4SLinus Torvalds { 99*1da177e4SLinus Torvalds free_dma(PVR2_CASCADE_CHAN); 100*1da177e4SLinus Torvalds free_irq(HW_EVENT_PVR2_DMA, 0); 101*1da177e4SLinus Torvalds } 102*1da177e4SLinus Torvalds 103*1da177e4SLinus Torvalds subsys_initcall(pvr2_dma_init); 104*1da177e4SLinus Torvalds module_exit(pvr2_dma_exit); 105*1da177e4SLinus Torvalds 106*1da177e4SLinus Torvalds MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); 107*1da177e4SLinus Torvalds MODULE_DESCRIPTION("NEC PowerVR 2 DMA driver"); 108*1da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 109*1da177e4SLinus Torvalds 110