162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/sh/drivers/dma/dma-pvr2.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * NEC PowerVR 2 (Dreamcast) DMA support 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 2003, 2004 Paul Mundt 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <mach/sysasic.h> 1462306a36Sopenharmony_ci#include <mach/dma.h> 1562306a36Sopenharmony_ci#include <asm/dma.h> 1662306a36Sopenharmony_ci#include <asm/io.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic unsigned int xfer_complete; 1962306a36Sopenharmony_cistatic int count; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci if (get_dma_residue(PVR2_CASCADE_CHAN)) { 2462306a36Sopenharmony_ci printk(KERN_WARNING "DMA: SH DMAC did not complete transfer " 2562306a36Sopenharmony_ci "on channel %d, waiting..\n", PVR2_CASCADE_CHAN); 2662306a36Sopenharmony_ci dma_wait_for_completion(PVR2_CASCADE_CHAN); 2762306a36Sopenharmony_ci } 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (count++ < 10) 3062306a36Sopenharmony_ci pr_debug("Got a pvr2 dma interrupt for channel %d\n", 3162306a36Sopenharmony_ci irq - HW_EVENT_PVR2_DMA); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci xfer_complete = 1; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return IRQ_HANDLED; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int pvr2_request_dma(struct dma_channel *chan) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci if (__raw_readl(PVR2_DMA_MODE) != 0) 4162306a36Sopenharmony_ci return -EBUSY; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci __raw_writel(0, PVR2_DMA_LMMODE0); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci return 0; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int pvr2_get_dma_residue(struct dma_channel *chan) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci return xfer_complete == 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int pvr2_xfer_dma(struct dma_channel *chan) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci if (chan->sar || !chan->dar) 5662306a36Sopenharmony_ci return -EINVAL; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci xfer_complete = 0; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci __raw_writel(chan->dar, PVR2_DMA_ADDR); 6162306a36Sopenharmony_ci __raw_writel(chan->count, PVR2_DMA_COUNT); 6262306a36Sopenharmony_ci __raw_writel(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic struct dma_ops pvr2_dma_ops = { 6862306a36Sopenharmony_ci .request = pvr2_request_dma, 6962306a36Sopenharmony_ci .get_residue = pvr2_get_dma_residue, 7062306a36Sopenharmony_ci .xfer = pvr2_xfer_dma, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic struct dma_info pvr2_dma_info = { 7462306a36Sopenharmony_ci .name = "pvr2_dmac", 7562306a36Sopenharmony_ci .nr_channels = 1, 7662306a36Sopenharmony_ci .ops = &pvr2_dma_ops, 7762306a36Sopenharmony_ci .flags = DMAC_CHANNELS_TEI_CAPABLE, 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int __init pvr2_dma_init(void) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci if (request_irq(HW_EVENT_PVR2_DMA, pvr2_dma_interrupt, 0, 8362306a36Sopenharmony_ci "pvr2 DMA handler", NULL)) 8462306a36Sopenharmony_ci pr_err("Failed to register pvr2 DMA handler interrupt\n"); 8562306a36Sopenharmony_ci request_dma(PVR2_CASCADE_CHAN, "pvr2 cascade"); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return register_dmac(&pvr2_dma_info); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic void __exit pvr2_dma_exit(void) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci free_dma(PVR2_CASCADE_CHAN); 9362306a36Sopenharmony_ci free_irq(HW_EVENT_PVR2_DMA, 0); 9462306a36Sopenharmony_ci unregister_dmac(&pvr2_dma_info); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cisubsys_initcall(pvr2_dma_init); 9862306a36Sopenharmony_cimodule_exit(pvr2_dma_exit); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciMODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); 10162306a36Sopenharmony_ciMODULE_DESCRIPTION("NEC PowerVR 2 DMA driver"); 10262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 103