18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/sh/drivers/dma/dma-pvr2.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * NEC PowerVR 2 (Dreamcast) DMA support 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2003, 2004 Paul Mundt 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <mach/sysasic.h> 148c2ecf20Sopenharmony_ci#include <mach/dma.h> 158c2ecf20Sopenharmony_ci#include <asm/dma.h> 168c2ecf20Sopenharmony_ci#include <asm/io.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic unsigned int xfer_complete; 198c2ecf20Sopenharmony_cistatic int count; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci if (get_dma_residue(PVR2_CASCADE_CHAN)) { 248c2ecf20Sopenharmony_ci printk(KERN_WARNING "DMA: SH DMAC did not complete transfer " 258c2ecf20Sopenharmony_ci "on channel %d, waiting..\n", PVR2_CASCADE_CHAN); 268c2ecf20Sopenharmony_ci dma_wait_for_completion(PVR2_CASCADE_CHAN); 278c2ecf20Sopenharmony_ci } 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (count++ < 10) 308c2ecf20Sopenharmony_ci pr_debug("Got a pvr2 dma interrupt for channel %d\n", 318c2ecf20Sopenharmony_ci irq - HW_EVENT_PVR2_DMA); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci xfer_complete = 1; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return IRQ_HANDLED; 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int pvr2_request_dma(struct dma_channel *chan) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci if (__raw_readl(PVR2_DMA_MODE) != 0) 418c2ecf20Sopenharmony_ci return -EBUSY; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci __raw_writel(0, PVR2_DMA_LMMODE0); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci return 0; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic int pvr2_get_dma_residue(struct dma_channel *chan) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return xfer_complete == 0; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int pvr2_xfer_dma(struct dma_channel *chan) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci if (chan->sar || !chan->dar) 568c2ecf20Sopenharmony_ci return -EINVAL; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci xfer_complete = 0; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci __raw_writel(chan->dar, PVR2_DMA_ADDR); 618c2ecf20Sopenharmony_ci __raw_writel(chan->count, PVR2_DMA_COUNT); 628c2ecf20Sopenharmony_ci __raw_writel(chan->mode & DMA_MODE_MASK, PVR2_DMA_MODE); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct dma_ops pvr2_dma_ops = { 688c2ecf20Sopenharmony_ci .request = pvr2_request_dma, 698c2ecf20Sopenharmony_ci .get_residue = pvr2_get_dma_residue, 708c2ecf20Sopenharmony_ci .xfer = pvr2_xfer_dma, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic struct dma_info pvr2_dma_info = { 748c2ecf20Sopenharmony_ci .name = "pvr2_dmac", 758c2ecf20Sopenharmony_ci .nr_channels = 1, 768c2ecf20Sopenharmony_ci .ops = &pvr2_dma_ops, 778c2ecf20Sopenharmony_ci .flags = DMAC_CHANNELS_TEI_CAPABLE, 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int __init pvr2_dma_init(void) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci if (request_irq(HW_EVENT_PVR2_DMA, pvr2_dma_interrupt, 0, 838c2ecf20Sopenharmony_ci "pvr2 DMA handler", NULL)) 848c2ecf20Sopenharmony_ci pr_err("Failed to register pvr2 DMA handler interrupt\n"); 858c2ecf20Sopenharmony_ci request_dma(PVR2_CASCADE_CHAN, "pvr2 cascade"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return register_dmac(&pvr2_dma_info); 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void __exit pvr2_dma_exit(void) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci free_dma(PVR2_CASCADE_CHAN); 938c2ecf20Sopenharmony_ci free_irq(HW_EVENT_PVR2_DMA, 0); 948c2ecf20Sopenharmony_ci unregister_dmac(&pvr2_dma_info); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cisubsys_initcall(pvr2_dma_init); 988c2ecf20Sopenharmony_cimodule_exit(pvr2_dma_exit); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ciMODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>"); 1018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("NEC PowerVR 2 DMA driver"); 1028c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 103