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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [char/] [lcddma.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * Device driver for driving LCD module via DMA.
3
 * It continously copies a memory area to the LCD.
4
 * It is up to the user to embed timing control signals in the memory data.
5
 *
6
 * Hardware config:
7
 *  Second timer output connected to DMA1 request (DREQ 0) input
8
 *
9
 * Copyright (C) 1999 Rob Scott (rscott@mtrob.fdns.net)
10
 */
11
 
12
#ifndef __KERNEL__
13
#define __KERNEL__
14
#endif
15
 
16
#include <linux/module.h>
17
#include <linux/config.h>
18
#include <linux/types.h>
19
#include <linux/kernel.h>
20
#include <linux/fs.h>
21
#include <linux/mm.h>
22
 
23
#include <asm/dma.h>
24
#include <asm/irq.h>
25
#include <asm/coldfire.h>
26
#include <asm/mcfsim.h>
27
#include <asm/mcfdma.h>
28
#include <asm/mcftimer.h>
29
#include <asm/param.h>     /* for HZ */
30
 
31
/*
32
 * From sysdep 2.1:
33
 */
34
 
35
#ifndef LINUX_VERSION_CODE
36
#  include <linux/version.h>
37
#endif
38
 
39
#ifndef VERSION_CODE
40
#  define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) )
41
#endif
42
 
43
/* only allow 2.0.x and 2.1.y */
44
 
45
#if LINUX_VERSION_CODE < VERSION_CODE(2,0,0)
46
#  error "This kernel is too old: not supported by this file"
47
#endif
48
#if LINUX_VERSION_CODE < VERSION_CODE(2,1,0)
49
#  define LINUX_20
50
#else
51
#  define LINUX_21
52
#endif
53
 
54
/* changed the prototype of read/write */
55
 
56
#if defined(LINUX_21) || defined(__alpha__)
57
# define count_t unsigned long
58
# define read_write_t long
59
#else
60
# define count_t int
61
# define read_write_t int
62
#endif
63
 
64
 
65
#if LINUX_VERSION_CODE < VERSION_CODE(2,1,31)
66
# define release_t void
67
#  define release_return(x) return
68
#else
69
#  define release_t int
70
#  define release_return(x) return (x)
71
#endif
72
 
73
/*
74
 * access to user space: use the 2.1 functions,
75
 * and implement them as macros for 2.0
76
 */
77
 
78
#ifdef LINUX_20
79
#  include <asm/segment.h>
80
#  define access_ok(t,a,sz)           (verify_area((t),(a),(sz)) ? 0 : 1)
81
#  define verify_area_20              verify_area
82
#  define copy_to_user(t,f,n)         (memcpy_tofs(t,f,n), 0)
83
#  define __copy_to_user(t,f,n)       copy_to_user((t),(f),(n))
84
#  define copy_to_user_ret(t,f,n,r)   copy_to_user((t),(f),(n))
85
#  define copy_from_user(t,f,n)       (memcpy_fromfs((t),(f),(n)), 0)
86
#  define __copy_from_user(t,f,n)     copy_from_user((t),(f),(n))
87
#  define copy_from_user_ret(t,f,n,r) copy_from_user((t),(f),(n))
88
#  define PUT_USER(val,add)           (put_user((val),(add)), 0)
89
#  define __PUT_USER(val,add)         PUT_USER((val),(add))
90
#  define PUT_USER_RET(val,add,ret)   PUT_USER((val),(add))
91
#  define GET_USER(dest,add)          ((dest)=get_user((add)), 0)
92
#  define __GET_USER(dest,add)        GET_USER((dest),(add))
93
#  define GET_USER_RET(dest,add,ret)  GET_USER((dest),(add))
94
#else
95
#  include <asm/uaccess.h>
96
#  include <asm/io.h>
97
#  define verify_area_20(t,a,sz) (0) /* == success */
98
#  define PUT_USER put_user
99
#  define __PUT_USER __put_user
100
#  define PUT_USER_RET put_user_ret
101
#  define GET_USER get_user
102
#  define __GET_USER __get_user
103
#  define GET_USER_RET get_user_ret
104
#endif
105
 
106
 
107
/*
108
 * Use one of the "local" device numbers
109
 */
110
 
111
#define LCDDMA_MAJOR 120
112
 
113
/* Define interrupt vector location */
114
#define DMA_VEC_LOC 120
115
 
116
/* Define which dma channel to use */
117
#define CHAN 0 
118
 
119
/* Define DMA data destination address (I/O device) */
120
#define DMA_DEST_ADDR 0x40000000
121
 
122
/*
123
 * Driver data structures
124
 */
125
 
126
unsigned int dma_xfer_len = 16;
127
 
128
/* Place to store screen data */
129
unsigned short dma_buf[32*1024];
130
 
131
unsigned short twiddle_array[16] = {0x3f00, 0x0600, 0x5b00, 0x4f00,
132
                                    0x6600, 0x6d00, 0x7d00, 0x0700,
133
                                    0x7f00, 0x6700, 0x7700, 0x7c00,
134
                                    0x3900, 0x5e00, 0x7900, 0x7100};
135
 
136
 
137
/*
138
 * Define return values
139
 */
140
static int lcddma_open(struct inode *inode, struct file *filp);
141
static release_t lcddma_release (struct inode *inode, struct file *filp);
142
static read_write_t lcddma_read (struct inode *inode, struct file *filp,
143
                                 char *buf, count_t count);
144
 
145
static read_write_t lcddma_write (struct inode *inode, struct file *filp,
146
                                  const char *buf, count_t count);
147
 
148
/* structure defined in fs.h */
149
struct file_operations lcddma_fops = {
150
  NULL,          /* lseek */
151
  lcddma_read,
152
  lcddma_write,
153
  NULL,          /* readdir */
154
  NULL,          /* poll */
155
  NULL,          /* ioctl */
156
  NULL,          /* mmap */
157
  lcddma_open,
158
  lcddma_release,
159
  NULL,          /* fsync */
160
  NULL,          /* fasync */
161
  NULL,          /* check_media_change */
162
  NULL           /* revalidate */
163
};
164
 
165
//#define LCDDMA_DEBUG
166
 
167
#ifdef LCDDMA_DEBUG
168
void lcddma_dump_regs(void) {
169
  volatile unsigned long        *dmap;
170
  volatile unsigned short       *dmapw;
171
  volatile unsigned char        *dmapb;
172
 
173
  dmap = (unsigned long *)   (MCF_MBAR + MCFDMA_BASE0);
174
  dmapw = (unsigned short *) (MCF_MBAR + MCFDMA_BASE0);
175
  dmapb = (unsigned char *)  (MCF_MBAR + MCFDMA_BASE0);
176
 
177
  /* Dump regs */
178
  printk("Src:  %08x\n", dmap[MCFDMA_SAR]);
179
  printk("Dest: %08x\n", dmap[MCFDMA_DAR]);
180
  printk("Byte: %08x\n", dmapw[MCFDMA_BCR]);
181
  printk("Ctl:  %08x\n", dmapw[MCFDMA_DCR]);
182
  printk("stat: %08x\n", dmapb[MCFDMA_DSR]);
183
  printk("vec:  %08x\n", dmapb[MCFDMA_DIVR]);
184
}
185
#endif
186
 
187
 
188
/*
189
 * lcddma_open - allocate memory buffer, start DMA
190
 */
191
 
192
static int lcddma_open(struct inode *inode, struct file *filp) {
193
 
194
  /* Clear DMA interrupt */
195
  disable_dma(CHAN);
196
 
197
  /* Do DMA write to i/o operation */
198
  set_dma_mode(CHAN, DMA_MODE_WRITE_WORD);
199
  set_dma_device_addr(CHAN, DMA_DEST_ADDR);
200
  set_dma_addr(CHAN, (unsigned int)dma_buf);
201
  set_dma_count(CHAN, dma_xfer_len);
202
 
203
#ifdef LCDDMA_DEBUG
204
  lcddma_dump_regs();
205
#endif
206
 
207
  /* Fire it off! */
208
  enable_dma(CHAN);
209
 
210
  return(0);
211
}
212
 
213
/*
214
 * lcddma_read - return device bitmap address
215
 */
216
 
217
static read_write_t lcddma_read (struct inode *inode, struct file *filp,
218
                          char *buf, count_t count)
219
{
220
  unsigned long temp;
221
  unsigned long *tempP;
222
 
223
  tempP = &(temp);
224
  temp = (unsigned int)(dma_buf);
225
 
226
  copy_to_user(buf, tempP, 4);
227
 
228
  /* Return number of bytes read */
229
  return (4);
230
}
231
 
232
 
233
/*
234
 * lcddma_write - set dma xfer length
235
 */
236
 
237
static read_write_t lcddma_write (struct inode *inode, struct file *filp,
238
                           const char *buf, count_t count)
239
{
240
  int i;
241
  unsigned int temp;
242
 
243
  temp = 0;
244
  for (i = 0; i < 4; i++) {
245
    temp = (temp << 8) | (unsigned char)buf[i];
246
  }
247
 
248
  dma_xfer_len = temp & 0xffff;
249
 
250
  return(4);
251
}
252
 
253
/*
254
 * lcddma_release - deallocate DMA buffer, stop DMAs...
255
 */
256
 
257
static release_t lcddma_release (struct inode *inode, struct file *filp) {
258
  unsigned long flags;
259
 
260
  /* Save current interrupt status: enabled or disabled */
261
  save_flags(flags);
262
 
263
  /* Disable interrupts */
264
  cli();
265
 
266
  /* Turn off DMA interrupts and stop any DMA in progress */
267
  disable_dma(CHAN);
268
 
269
  /* Restore interrupt status */
270
  restore_flags(flags);
271
 
272
  MOD_DEC_USE_COUNT;
273
 
274
  release_return(0);
275
}
276
 
277
/*
278
 * Send out the same buffer upon completion of DMA
279
 */
280
 
281
void lcddma_isr(int irq, void *dev_id, struct pt_regs *regs) {
282
 
283
  /* Clear DMA interrupt */
284
  disable_dma(CHAN);
285
 
286
  /* Do DMA write to i/o operation */
287
  set_dma_mode(CHAN, DMA_MODE_WRITE_WORD);
288
  set_dma_device_addr(CHAN, DMA_DEST_ADDR);
289
  set_dma_addr(CHAN, (unsigned int)dma_buf);
290
  set_dma_count(CHAN, dma_xfer_len);
291
 
292
  /* Fire it off! */
293
  enable_dma(CHAN);
294
 
295
}
296
 
297
 
298
/*
299
 * Init the interrupt vector location, and setup timer 2
300
 */
301
 
302
 
303
void lcddma_init(void) {
304
  volatile unsigned char *regp;
305
  volatile unsigned short *shortp;
306
  int i;
307
  int result;
308
 
309
  /* Init dma buffer */
310
  for (i= 0; i < 16; i++) {
311
    dma_buf[i] = twiddle_array[i] | i;
312
  }
313
 
314
  /* Register lcddma as character device */
315
  result = register_chrdev(LCDDMA_MAJOR, "lcddma", &lcddma_fops);
316
  if (result < 0) {
317
    printk(KERN_WARNING "LCDDMA: can't get major %d\n",LCDDMA_MAJOR);
318
    return;
319
  }
320
 
321
  /* Set interrupt level and priority */
322
  /* Note: this is hardwired for channel 0 */
323
  regp = (volatile unsigned char *) (MCF_MBAR);
324
  regp[MCFSIM_DMA1ICR] = MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3;
325
  mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_DMA1);
326
 
327
  /* Set interrupt vector location */
328
  /* Note: this is hardwired for channel 0 */
329
  regp[MCFDMA_BASE0 + MCFDMA_DIVR] = DMA_VEC_LOC;
330
 
331
  /* Install ISR (interrupt service routine) */
332
  printk ("lcddma: requesting IRQ %d\n", DMA_VEC_LOC);
333
  result = request_irq(DMA_VEC_LOC, lcddma_isr, SA_INTERRUPT, "lcddma", NULL);
334
  if (result) {
335
    printk ("lcddma: IRQ %d already in use\n", DMA_VEC_LOC);
336
    return;
337
  }
338
 
339
  /* Request DMA channel */
340
  printk ("lcddma: requesting DMA channel %d\n", CHAN);
341
  result = request_dma(CHAN, "lcddma");
342
  if (result) {
343
    printk ("lcddma: dma channel %d already in use\n", CHAN);
344
    return;
345
  }
346
 
347
  /* Setup timer 2 as LCD pixel clock */
348
  shortp = (volatile unsigned short *) (MCF_MBAR + MCFTIMER_BASE2);
349
 
350
  shortp[MCFTIMER_TMR] = MCFTIMER_TMR_DISABLE;
351
  shortp[MCFTIMER_TER] = MCFTIMER_TER_CAP | MCFTIMER_TER_REF;
352
  shortp[MCFTIMER_TRR] = (unsigned short) ((MCF_CLK/10000) / HZ );
353
  shortp[MCFTIMER_TMR] = (0 << 8) | /* set prescaler to divide by 1 */
354
                        MCFTIMER_TMR_DISCE | MCFTIMER_TMR_DISOM |
355
                        MCFTIMER_TMR_ENORI | MCFTIMER_TMR_RESTART |
356
                        MCFTIMER_TMR_CLK1  | MCFTIMER_TMR_ENABLE;
357
 
358
  /* Enable external DMA requests on TIN0/DREQ0 pin */
359
#define MCFSIM_PAR_PAR8 (1 << 8)
360
  shortp = (volatile unsigned short *)(MCF_MBAR + MCFSIM_PAR);
361
  shortp[0] |= MCFSIM_PAR_PAR8;
362
}

powered by: WebSVN 2.1.0

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