2
* linux/arch/unicore32/kernel/dma.c
4
* Code specific to PKUnity SoC and UniCore ISA
6
* Maintained by GUAN Xue-tao <gxt@mprc.pku.edu.cn>
7
* Copyright (C) 2001-2010 Guan Xuetao
9
* This program is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License version 2 as
11
* published by the Free Software Foundation.
14
#include <linux/module.h>
15
#include <linux/init.h>
16
#include <linux/kernel.h>
17
#include <linux/interrupt.h>
18
#include <linux/errno.h>
21
#include <asm/system.h>
23
#include <mach/hardware.h>
29
void (*irq_handler)(int, void *);
30
void (*err_handler)(int, void *);
34
static struct dma_channel dma_channels[MAX_DMA_CHANNELS];
36
int puv3_request_dma(char *name, puv3_dma_prio prio,
37
void (*irq_handler)(int, void *),
38
void (*err_handler)(int, void *),
44
/* basic sanity checks */
48
local_irq_save(flags);
51
/* try grabbing a DMA channel with the requested priority */
52
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
53
if ((dma_channels[i].prio == prio) &&
54
!dma_channels[i].name) {
59
/* if requested prio group is full, try a hier priority */
60
} while (!found && prio--);
63
dma_channels[i].name = name;
64
dma_channels[i].irq_handler = irq_handler;
65
dma_channels[i].err_handler = err_handler;
66
dma_channels[i].data = data;
68
printk(KERN_WARNING "No more available DMA channels for %s\n",
73
local_irq_restore(flags);
76
EXPORT_SYMBOL(puv3_request_dma);
78
void puv3_free_dma(int dma_ch)
82
if (!dma_channels[dma_ch].name) {
84
"%s: trying to free channel %d which is already freed\n",
89
local_irq_save(flags);
90
dma_channels[dma_ch].name = NULL;
91
dma_channels[dma_ch].err_handler = NULL;
92
local_irq_restore(flags);
94
EXPORT_SYMBOL(puv3_free_dma);
96
static irqreturn_t dma_irq_handler(int irq, void *dev_id)
100
dint = readl(DMAC_ITCSR);
101
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
102
if (dint & DMAC_CHANNEL(i)) {
103
struct dma_channel *channel = &dma_channels[i];
105
/* Clear TC interrupt of channel i */
106
writel(DMAC_CHANNEL(i), DMAC_ITCCR);
107
writel(0, DMAC_ITCCR);
109
if (channel->name && channel->irq_handler) {
110
channel->irq_handler(i, channel->data);
113
* IRQ for an unregistered DMA channel:
114
* let's clear the interrupts and disable it.
116
printk(KERN_WARNING "spurious IRQ for"
117
" DMA channel %d\n", i);
124
static irqreturn_t dma_err_handler(int irq, void *dev_id)
128
dint = readl(DMAC_IESR);
129
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
130
if (dint & DMAC_CHANNEL(i)) {
131
struct dma_channel *channel = &dma_channels[i];
133
/* Clear Err interrupt of channel i */
134
writel(DMAC_CHANNEL(i), DMAC_IECR);
135
writel(0, DMAC_IECR);
137
if (channel->name && channel->err_handler) {
138
channel->err_handler(i, channel->data);
141
* IRQ for an unregistered DMA channel:
142
* let's clear the interrupts and disable it.
144
printk(KERN_WARNING "spurious IRQ for"
145
" DMA channel %d\n", i);
152
int __init puv3_init_dma(void)
156
/* dma channel priorities on v8 processors:
157
* ch 0 - 1 <--> (0) DMA_PRIO_HIGH
158
* ch 2 - 3 <--> (1) DMA_PRIO_MEDIUM
159
* ch 4 - 5 <--> (2) DMA_PRIO_LOW
161
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
163
dma_channels[i].name = NULL;
164
dma_channels[i].prio = min((i & 0x7) >> 1, DMA_PRIO_LOW);
167
ret = request_irq(IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
169
printk(KERN_CRIT "Can't register IRQ for DMA\n");
173
ret = request_irq(IRQ_DMAERR, dma_err_handler, 0, "DMAERR", NULL);
175
printk(KERN_CRIT "Can't register IRQ for DMAERR\n");
176
free_irq(IRQ_DMA, "DMA");
183
postcore_initcall(puv3_init_dma);