OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [sh64/] [kernel/] [dma.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * arch/sh64/kernel/dma.c
3
 *
4
 * DMA routines for the SH-5 DMAC.
5
 *
6
 * Copyright (C) 2003  Paul Mundt
7
 *
8
 * This file is subject to the terms and conditions of the GNU General Public
9
 * License.  See the file "COPYING" in the main directory of this archive
10
 * for more details.
11
 */
12
#include <linux/init.h>
13
#include <linux/module.h>
14
#include <linux/interrupt.h>
15
#include <linux/types.h>
16
#include <linux/irq.h>
17
#include <linux/spinlock.h>
18
#include <linux/mm.h>
19
#include <asm/hardware.h>
20
#include <asm/dma.h>
21
#include <asm/signal.h>
22
#include <asm/errno.h>
23
#include <asm/io.h>
24
 
25
typedef struct {
26
        unsigned long dev_addr;
27
        unsigned long mem_addr;
28
 
29
        unsigned int mode;
30
        unsigned int count;
31
} dma_info_t;
32
 
33
static dma_info_t dma_info[MAX_DMA_CHANNELS];
34
extern spinlock_t dma_spin_lock;
35
 
36
/* arch/sh64/kernel/irq_intc.c */
37
extern void make_intc_irq(unsigned int irq);
38
 
39
/* DMAC Interrupts */
40
#define DMA_IRQ_DMTE0   18
41
#define DMA_IRQ_DERR    22
42
 
43
#define DMAC_COMMON_BASE        (dmac_base + 0x08)
44
#define DMAC_SAR_BASE           (dmac_base + 0x10)
45
#define DMAC_DAR_BASE           (dmac_base + 0x18)
46
#define DMAC_COUNT_BASE         (dmac_base + 0x20)
47
#define DMAC_CTRL_BASE          (dmac_base + 0x28)
48
#define DMAC_STATUS_BASE        (dmac_base + 0x30)
49
 
50
#define DMAC_SAR(n)     (DMAC_SAR_BASE    + ((n) * 0x28))
51
#define DMAC_DAR(n)     (DMAC_DAR_BASE    + ((n) * 0x28))
52
#define DMAC_COUNT(n)   (DMAC_COUNT_BASE  + ((n) * 0x28))
53
#define DMAC_CTRL(n)    (DMAC_CTRL_BASE   + ((n) * 0x28))
54
#define DMAC_STATUS(n)  (DMAC_STATUS_BASE + ((n) * 0x28))
55
 
56
/* DMAC.COMMON Bit Definitions */
57
#define DMAC_COMMON_PR  0x00000001      /* Priority */
58
                                        /* Bits 1-2 Reserved */
59
#define DMAC_COMMON_ME  0x00000008      /* Master Enable */
60
#define DMAC_COMMON_NMI 0x00000010      /* NMI Flag */
61
                                        /* Bits 5-6 Reserved */
62
#define DMAC_COMMON_ER  0x00000780      /* Error Response */
63
#define DMAC_COMMON_AAE 0x00007800      /* Address Alignment Error */
64
                                        /* Bits 15-63 Reserved */
65
 
66
/* DMAC.SAR Bit Definitions */
67
#define DMAC_SAR_ADDR   0xffffffff      /* Source Address */
68
 
69
/* DMAC.DAR Bit Definitions */
70
#define DMAC_DAR_ADDR   0xffffffff      /* Destination Address */
71
 
72
/* DMAC.COUNT Bit Definitions */
73
#define DMAC_COUNT_CNT  0xffffffff      /* Transfer Count */
74
 
75
/* DMAC.CTRL Bit Definitions */
76
#define DMAC_CTRL_TS    0x00000007      /* Transfer Size */
77
#define DMAC_CTRL_SI    0x00000018      /* Source Increment */
78
#define DMAC_CTRL_DI    0x00000060      /* Destination Increment */
79
#define DMAC_CTRL_RS    0x00000780      /* Resource Select */
80
#define DMAC_CTRL_IE    0x00000800      /* Interrupt Enable */
81
#define DMAC_CTRL_TE    0x00001000      /* Transfer Enable */
82
                                        /* Bits 15-63 Reserved */
83
 
84
/* DMAC.STATUS Bit Definitions */
85
#define DMAC_STATUS_TE  0x00000001      /* Transfer End */
86
#define DMAC_STATUS_AAE 0x00000002      /* Address Alignment Error */
87
                                        /* Bits 2-63 Reserved */
88
 
89
static unsigned long dmac_base;
90
 
91
void set_dma_count(unsigned int chan, unsigned int count);
92
void set_dma_addr(unsigned int chan, unsigned int addr);
93
 
94
static void dma_mte(int irq, void *dev_id, struct pt_regs *regs)
95
{
96
        unsigned int chan = irq - DMA_IRQ_DMTE0;
97
        dma_info_t *info = dma_info + chan;
98
        u64 status;
99
 
100
        if (info->mode & DMA_MODE_WRITE) {
101
                sh64_out64(info->mem_addr & DMAC_SAR_ADDR, DMAC_SAR(chan));
102
        } else {
103
                sh64_out64(info->mem_addr & DMAC_DAR_ADDR, DMAC_DAR(chan));
104
        }
105
 
106
        set_dma_count(chan, info->count);
107
 
108
        /* Clear the TE bit */
109
        status = sh64_in64(DMAC_STATUS(chan));
110
        status &= ~DMAC_STATUS_TE;
111
        sh64_out64(status, DMAC_STATUS(chan));
112
}
113
 
114
static struct irqaction irq_dmte = {
115
        .handler        = dma_mte,
116
        .flags          = SA_INTERRUPT,
117
        .name           = "DMA MTE",
118
};
119
 
120
static void dma_err(int irq, void *dev_id, struct pt_regs *regs)
121
{
122
        u64 tmp;
123
        u8 chan;
124
 
125
        printk(KERN_NOTICE "DMAC: Got a DMA Error!\n");
126
 
127
        tmp = sh64_in64(DMAC_COMMON_BASE);
128
 
129
        /* Check for the type of error */
130
        if ((chan = tmp & DMAC_COMMON_AAE)) {
131
                /* It's an address alignment error.. */
132
                printk(KERN_NOTICE "DMAC: Alignment error on channel %d, ", chan);
133
 
134
                printk(KERN_NOTICE "SAR: 0x%08llx, DAR: 0x%08llx, COUNT: %lld\n",
135
                       (sh64_in64(DMAC_SAR(chan)) & DMAC_SAR_ADDR),
136
                       (sh64_in64(DMAC_DAR(chan)) & DMAC_DAR_ADDR),
137
                       (sh64_in64(DMAC_COUNT(chan)) & DMAC_COUNT_CNT));
138
 
139
        } else if ((chan = tmp & DMAC_COMMON_ER)) {
140
                /* Something else went wrong.. */
141
                printk(KERN_NOTICE "DMAC: Error on channel %d\n", chan);
142
        }
143
 
144
        /* Reset the ME bit to clear the interrupt */
145
        tmp |= DMAC_COMMON_ME;
146
        sh64_out64(tmp, DMAC_COMMON_BASE);
147
}
148
 
149
static struct irqaction irq_derr = {
150
        .handler        = dma_err,
151
        .flags          = SA_INTERRUPT,
152
        .name           = "DMA Error",
153
};
154
 
155
static inline unsigned long calc_xmit_shift(unsigned int chan)
156
{
157
        return sh64_in64(DMAC_CTRL(chan)) & 0x03;
158
}
159
 
160
void setup_dma(unsigned int chan, dma_info_t *info)
161
{
162
        unsigned int irq = DMA_IRQ_DMTE0 + chan;
163
        dma_info_t *dma = dma_info + chan;
164
 
165
        make_intc_irq(irq);
166
        setup_irq(irq, &irq_dmte);
167
        dma = info;
168
}
169
 
170
void enable_dma(unsigned int chan)
171
{
172
        u64 ctrl;
173
 
174
        ctrl = sh64_in64(DMAC_CTRL(chan));
175
        ctrl |= DMAC_CTRL_TE;
176
        sh64_out64(ctrl, DMAC_CTRL(chan));
177
}
178
 
179
void disable_dma(unsigned int chan)
180
{
181
        u64 ctrl;
182
 
183
        ctrl = sh64_in64(DMAC_CTRL(chan));
184
        ctrl &= ~DMAC_CTRL_TE;
185
        sh64_out64(ctrl, DMAC_CTRL(chan));
186
}
187
 
188
void set_dma_mode(unsigned int chan, char mode)
189
{
190
        dma_info_t *info = dma_info + chan;
191
 
192
        info->mode = mode;
193
 
194
        set_dma_addr(chan, info->mem_addr);
195
        set_dma_count(chan, info->count);
196
}
197
 
198
void set_dma_addr(unsigned int chan, unsigned int addr)
199
{
200
        dma_info_t *info = dma_info + chan;
201
        unsigned long sar, dar;
202
 
203
        info->mem_addr = addr;
204
        sar = (info->mode & DMA_MODE_WRITE) ? info->mem_addr : info->dev_addr;
205
        dar = (info->mode & DMA_MODE_WRITE) ? info->dev_addr : info->mem_addr;
206
 
207
        sh64_out64(sar & DMAC_SAR_ADDR, DMAC_SAR(chan));
208
        sh64_out64(dar & DMAC_SAR_ADDR, DMAC_DAR(chan));
209
}
210
 
211
void set_dma_count(unsigned int chan, unsigned int count)
212
{
213
        dma_info_t *info = dma_info + chan;
214
        u64 tmp;
215
 
216
        info->count = count;
217
 
218
        tmp = (info->count >> calc_xmit_shift(chan)) & DMAC_COUNT_CNT;
219
 
220
        sh64_out64(tmp, DMAC_COUNT(chan));
221
}
222
 
223
unsigned long claim_dma_lock(void)
224
{
225
        unsigned long flags;
226
 
227
        spin_lock_irqsave(&dma_spin_lock, flags);
228
 
229
        return flags;
230
}
231
 
232
void release_dma_lock(unsigned long flags)
233
{
234
        spin_unlock_irqrestore(&dma_spin_lock, flags);
235
}
236
 
237
int get_dma_residue(unsigned int chan)
238
{
239
        return sh64_in64(DMAC_COUNT(chan) << calc_xmit_shift(chan));
240
}
241
 
242
int __init init_dma(void)
243
{
244
        struct vcr_info vcr;
245
        u64 tmp;
246
 
247
        /* Remap the DMAC */
248
        dmac_base = onchip_remap(PHYS_DMAC_BLOCK, 1024, "DMAC");
249
        if (!dmac_base) {
250
                printk(KERN_ERR "Unable to remap DMAC\n");
251
                return -ENOMEM;
252
        }
253
 
254
        /* Report DMAC.VCR Info */
255
        vcr = sh64_get_vcr_info(dmac_base);
256
        printk("DMAC: Module ID: 0x%04x, Module version: 0x%04x\n",
257
               vcr.mod_id, vcr.mod_vers);
258
 
259
        /* Set the ME bit */
260
        tmp = sh64_in64(DMAC_COMMON_BASE);
261
        tmp |= DMAC_COMMON_ME;
262
        sh64_out64(tmp, DMAC_COMMON_BASE);
263
 
264
        /* Enable the DMAC Error Interrupt */
265
        make_intc_irq(DMA_IRQ_DERR);
266
        setup_irq(DMA_IRQ_DERR, &irq_derr);
267
 
268
        return 0;
269
}
270
 
271
static void __exit exit_dma(void)
272
{
273
        onchip_unmap(dmac_base);
274
        free_irq(DMA_IRQ_DERR, 0);
275
}
276
 
277
module_init(init_dma);
278
module_exit(exit_dma);
279
 
280
MODULE_AUTHOR("Paul Mundt");
281
MODULE_DESCRIPTION("DMA API for SH-5 DMAC");
282
MODULE_LICENSE("GPL");
283
 
284
EXPORT_SYMBOL(setup_dma);
285
EXPORT_SYMBOL(claim_dma_lock);
286
EXPORT_SYMBOL(release_dma_lock);
287
EXPORT_SYMBOL(enable_dma);
288
EXPORT_SYMBOL(disable_dma);
289
EXPORT_SYMBOL(set_dma_mode);
290
EXPORT_SYMBOL(set_dma_addr);
291
EXPORT_SYMBOL(set_dma_count);
292
EXPORT_SYMBOL(get_dma_residue);
293
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.