setup enviroment for compilation
[linux-2.4.21-pre4.git] / drivers / video / xilinxfb.c
1 /*
2  * xilinxfb.c
3  *
4  * Xilinx TFT LCD frame buffer driver
5  *
6  * Author: MontaVista Software, Inc.
7  *         source@mvista.com
8  *
9  * 2002 (c) MontaVista, Software, Inc.  This file is licensed under the terms
10  * of the GNU General Public License version 2.1.  This program is licensed
11  * "as is" without any warranty of any kind, whether express or implied.
12  */
13
14 /*
15  * This driver was based off of au1100fb.c by MontaVista, which in turn
16  * was based off of skeletonfb.c, Skeleton for a frame buffer device by
17  * Geert Uytterhoeven.
18  */
19
20 #include <linux/module.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <linux/string.h>
24 #include <linux/mm.h>
25 #include <linux/wrapper.h> /* mem_map_(un)reserve */
26 #include <linux/tty.h>
27 #include <linux/slab.h>
28 #include <linux/delay.h>
29 #include <linux/fb.h>
30 #include <linux/init.h>
31
32 #include <asm/io.h>
33 #include <video/fbcon.h>
34 #include <video/fbcon-cfb32.h>
35
36 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
37 MODULE_DESCRIPTION("Xilinx TFT LCD frame buffer driver");
38 MODULE_LICENSE("GPL");
39
40 /*
41  * The interface to the framebuffer is nice and simple.  There are two
42  * control registers.  The first tells the LCD interface where in memory
43  * the frame buffer is (only the 11 most significant bits are used, so
44  * don't start thinking about scrolling).  The second allows the LCD to
45  * be turned on or off as well as rotated 180 degrees.
46  */
47 #define NUM_REGS        2
48 #define REG_FB_ADDR     0
49 #define REG_CTRL        1
50 #define REG_CTRL_ENABLE  0x0001
51 #define REG_CTRL_ROTATE  0x0002
52 #if defined(CONFIG_FB_XILINX_ROTATE)
53 #define REG_CTRL_DEFAULT (REG_CTRL_ENABLE | REG_CTRL_ROTATE)
54 #else
55 #define REG_CTRL_DEFAULT (REG_CTRL_ENABLE)
56 #endif                          /* CONFIG_FB_XILINX_ROTATE */
57
58 /*
59  * The hardware only handles a single mode: 640x480 24 bit true
60  * color. Each pixel gets a word (32 bits) of memory.  Within each word,
61  * the 8 most significant bits are ignored, the next 8 bits are the red
62  * level, the next 8 bits are the green level and the 8 least
63  * significant bits are the blue level.  Each row of the LCD uses 1024
64  * words, but only the first 640 pixels are displayed with the other 384
65  * words being ignored.  There are 480 rows.
66  */
67 #define BYTES_PER_PIXEL 4
68 #define BITS_PER_PIXEL  (BYTES_PER_PIXEL * 8)
69 #define XRES            640
70 #define YRES            480
71 #define XRES_VIRTUAL    1024
72 #define YRES_VIRTUAL    YRES
73 #define LINE_LENGTH     (XRES_VIRTUAL * BYTES_PER_PIXEL)
74 #define FB_SIZE         (YRES_VIRTUAL * LINE_LENGTH)
75
76 /*
77  * Here's the definition of the information needed per frame buffer.  We
78  * start off with the generic structure and then follow that with our private
79  * data.
80  */
81 struct xilinxfb_info {
82         struct fb_info_gen gen;
83         struct xilinxfb_info *next;     /* The next node in info_list */
84         u32 *regs;              /* Virtual address of our control registers */
85         unsigned long fb_virt_start;    /* Virtual address of our frame buffer */
86         dma_addr_t fb_phys;     /* Physical address of our frame buffer */
87         u32 fbcon_cmap32[16];   /* Colormap */
88         struct display disp;
89 };
90
91 struct xilinxfb_par {
92         struct fb_var_screeninfo var;
93 };
94
95 /*
96  * So we can handle multiple frame buffers with this one driver, we need
97  * a list of xilinxfb_info's.
98  */
99 static struct xilinxfb_info *info_list = NULL;
100 static spinlock_t info_lock = SPIN_LOCK_UNLOCKED;
101
102 /* Our parameters are unchangeable, so we only need one parameters struct. */
103 static struct xilinxfb_par current_par;
104
105 /*
106  * Free the head of our info_list and remove it from the list.  Note
107  * that this function does *not* unregister_framebuffer().  That is up
108  * to the caller to do if it is appropriate.
109  */
110 static void
111 remove_head_info(void)
112 {
113         struct xilinxfb_info *i;
114
115         /* Pull the head off of info_list. */
116         spin_lock(&info_lock);
117         i = info_list;
118         info_list = i->next;
119         spin_unlock(&info_lock);
120
121         if (i->regs) {
122                 /* Turn off the display; the frame buffer is going away. */
123                 out_be32(i->regs + REG_CTRL, 0);
124                 iounmap(i->regs);
125         }
126
127         if (i->fb_virt_start)
128                 consistent_free((void *)i->fb_virt_start);
129
130         kfree(i);
131 }
132
133 static int
134 xilinxfb_ioctl(struct inode *inode, struct file *file, u_int cmd,
135                u_long arg, int con, struct fb_info *info)
136 {
137         /* nothing to do yet */
138         return -EINVAL;
139 }
140
141 static struct fb_ops xilinxfb_ops = {
142         owner:THIS_MODULE,
143         fb_get_fix:fbgen_get_fix,
144         fb_get_var:fbgen_get_var,
145         fb_set_var:fbgen_set_var,
146         fb_get_cmap:fbgen_get_cmap,
147         fb_set_cmap:fbgen_set_cmap,
148         fb_pan_display:fbgen_pan_display,
149         fb_ioctl:xilinxfb_ioctl,
150 };
151
152 static void
153 xilinx_detect(void)
154 {
155         /*
156          *  This function should detect the current video mode settings 
157          *  and store it as the default video mode
158          */
159
160         /*
161          * Yeh, well, we're not going to change any settings so we're
162          * always stuck with the default ...
163          */
164
165 }
166
167 static int
168 xilinx_encode_fix(struct fb_fix_screeninfo *fix, const void *par,
169                   struct fb_info_gen *info)
170 {
171         struct xilinxfb_info *i = (struct xilinxfb_info *) info;
172
173         memset(fix, 0, sizeof (struct fb_fix_screeninfo));
174
175         strcpy(fix->id, "Xilinx");
176         fix->smem_start = i->fb_phys;
177         fix->smem_len = FB_SIZE;
178         fix->type = FB_TYPE_PACKED_PIXELS;
179         fix->visual = FB_VISUAL_TRUECOLOR;
180         fix->line_length = LINE_LENGTH;
181         return 0;
182 }
183
184 static int
185 xilinx_decode_var(const struct fb_var_screeninfo *var, void *par,
186                   struct fb_info_gen *info)
187 {
188         struct xilinxfb_par *p = (struct xilinxfb_par *) par;
189
190         if (var->xres != XRES
191             || var->yres != YRES
192             || var->xres_virtual != XRES_VIRTUAL
193             || var->yres_virtual != YRES_VIRTUAL
194             || var->bits_per_pixel != BITS_PER_PIXEL
195             || var->xoffset != 0
196             || var->yoffset != 0
197             || var->grayscale != 0
198             || var->nonstd != 0
199             || var->pixclock != 0
200             || var->left_margin != 0
201             || var->right_margin != 0
202             || var->hsync_len != 0
203             || var->vsync_len != 0
204             || var->sync != 0 || var->vmode != FB_VMODE_NONINTERLACED) {
205                 return -EINVAL;
206         }
207
208         memset(p, 0, sizeof (struct xilinxfb_par));
209         p->var = *var;
210         p->var.red.offset = 16;
211         p->var.red.length = 8;
212         p->var.green.offset = 8;
213         p->var.green.length = 8;
214         p->var.blue.offset = 0;
215         p->var.blue.length = 8;
216         p->var.transp.offset = 0;
217         p->var.transp.length = 0;
218         p->var.red.msb_right = 0;
219         p->var.green.msb_right = 0;
220         p->var.blue.msb_right = 0;
221         p->var.transp.msb_right = 0;
222         p->var.height = 99;     /* in mm of NEC NL6448BC20-08 on ML300 */
223         p->var.width = 132;     /* in mm of NEC NL6448BC20-08 on ML300 */
224
225         return 0;
226 }
227
228 static int
229 xilinx_encode_var(struct fb_var_screeninfo *var, const void *par,
230                   struct fb_info_gen *info)
231 {
232         struct xilinxfb_par *p = (struct xilinxfb_par *) par;
233
234         *var = p->var;
235         return 0;
236 }
237
238 static void
239 xilinx_get_par(void *par, struct fb_info_gen *info)
240 {
241         struct xilinxfb_par *p = (struct xilinxfb_par *) par;
242
243         *p = current_par;
244 }
245
246 static void
247 xilinx_set_par(const void *par, struct fb_info_gen *info)
248 {
249         /* nothing to do: we don't change any settings */
250 }
251
252 static int
253 xilinx_getcolreg(unsigned regno, unsigned *red, unsigned *green,
254                  unsigned *blue, unsigned *transp, struct fb_info *info)
255 {
256         struct xilinxfb_info *i = (struct xilinxfb_info *) info;
257         unsigned r, g, b;
258
259         if (regno >= 16)
260                 return 1;
261
262         r = (i->fbcon_cmap32[regno] & 0xFF0000) >> 16;
263         g = (i->fbcon_cmap32[regno] & 0x00FF00) >> 8;
264         b = (i->fbcon_cmap32[regno] & 0x0000FF);
265
266         *red = r << 8;
267         *green = g << 8;
268         *blue = b << 8;
269         *transp = 0;
270
271         return 0;
272 }
273
274 static int
275 xilinx_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
276                  unsigned transp, struct fb_info *info)
277 {
278         struct xilinxfb_info *i = (struct xilinxfb_info *) info;
279
280         if (regno >= 16)
281                 return 1;
282
283         /* We only handle 8 bits of each color. */
284         red >>= 8;
285         green >>= 8;
286         blue >>= 8;
287         i->fbcon_cmap32[regno] = ((unsigned long) red << 16
288                                   | (unsigned long) green << 8
289                                   | (unsigned long) blue);
290         return 0;
291 }
292
293 static int
294 xilinx_pan_display(const struct fb_var_screeninfo *var,
295                    struct fb_info_gen *info)
296 {
297         if (var->xoffset != 0 || var->yoffset != 0)
298                 return -EINVAL;
299
300         return 0;
301 }
302
303 static int
304 xilinx_blank(int blank_mode, struct fb_info_gen *info)
305 {
306         struct xilinxfb_info *i = (struct xilinxfb_info *) info;
307
308         switch (blank_mode) {
309         case VESA_NO_BLANKING:
310                 /* turn on panel */
311                 out_be32(i->regs + REG_CTRL, REG_CTRL_DEFAULT);
312                 break;
313
314         case VESA_VSYNC_SUSPEND:
315         case VESA_HSYNC_SUSPEND:
316         case VESA_POWERDOWN:
317                 /* turn off panel */
318                 out_be32(i->regs + REG_CTRL, 0);
319         default:
320                 break;
321
322         }
323         return 0;
324 }
325
326 static void
327 xilinx_set_disp(const void *unused, struct display *disp,
328                 struct fb_info_gen *info)
329 {
330         struct xilinxfb_info *i = (struct xilinxfb_info *) info;
331
332         disp->screen_base = (char *) i->fb_virt_start;
333
334         disp->dispsw = &fbcon_cfb32;
335         disp->dispsw_data = i->fbcon_cmap32;
336 }
337
338 static struct fbgen_hwswitch xilinx_switch = {
339         xilinx_detect,
340         xilinx_encode_fix,
341         xilinx_decode_var,
342         xilinx_encode_var,
343         xilinx_get_par,
344         xilinx_set_par,
345         xilinx_getcolreg,
346         xilinx_setcolreg,
347         xilinx_pan_display,
348         xilinx_blank,
349         xilinx_set_disp
350 };
351
352 static int __init
353 probe(int index)
354 {
355         u32 *phys_reg_addr;
356         struct xilinxfb_info *i;
357         struct page *page, *end_page;
358
359         switch (index) {
360 #if defined(XPAR_TFT_0_BASEADDR)
361         case 0:
362                 phys_reg_addr = (u32 *) XPAR_TFT_0_BASEADDR;
363                 break;
364 #if defined(XPAR_TFT_1_BASEADDR)
365         case 1:
366                 phys_reg_addr = (u32 *) XPAR_TFT_1_BASEADDR;
367                 break;
368 #if defined(XPAR_TFT_2_BASEADDR)
369         case 2:
370                 phys_reg_addr = (u32 *) XPAR_TFT_2_BASEADDR;
371                 break;
372 #if defined(XPAR_TFT_3_BASEADDR)
373 #error Edit this file to add more devices.
374 #endif                          /* 3 */
375 #endif                          /* 2 */
376 #endif                          /* 1 */
377 #endif                          /* 0 */
378         default:
379                 return -ENODEV;
380         }
381
382         /* Allocate the info and zero it out. */
383         i = (struct xilinxfb_info *) kmalloc(sizeof (struct xilinxfb_info),
384                                              GFP_KERNEL);
385         if (!i) {
386                 printk(KERN_ERR "Could not allocate Xilinx "
387                        "frame buffer #%d information.\n", index);
388                 return -ENOMEM;
389         }
390         memset(i, 0, sizeof (struct xilinxfb_info));
391
392         /* Make it the head of info_list. */
393         spin_lock(&info_lock);
394         i->next = info_list;
395         info_list = i;
396         spin_unlock(&info_lock);
397
398         /*
399          * At this point, things are ok for us to call remove_head_info() to
400          * clean up if we run into any problems; i is on info_list and
401          * all the pointers are zeroed because of the memset above.
402          */
403
404         i->fb_virt_start = (unsigned long) consistent_alloc(GFP_KERNEL|GFP_DMA,
405                                                             FB_SIZE,
406                                                             &i->fb_phys);
407         if (!i->fb_virt_start) {
408                 printk(KERN_ERR "Could not allocate frame buffer memory "
409                        "for Xilinx device #%d.\n", index);
410                 remove_head_info();
411                 return -ENOMEM;
412         }
413
414         /*
415          * The 2.4 PPC version of consistent_alloc does not set the
416          * pages reserved.  The pages need to be reserved so that mmap
417          * will work.  This means that we need the following code.  When
418          * consistent_alloc gets fixed, this will no longer be needed.
419          * Note that in 2.4, consistent_alloc doesn't free up the extra
420          * pages either.  This is already fixed in 2.5.
421          */
422         page = virt_to_page(__va(i->fb_phys));
423         end_page = page + ((FB_SIZE+PAGE_SIZE-1)/PAGE_SIZE);
424         while (page < end_page)
425                 mem_map_reserve(page++);
426
427         /* Clear the frame buffer. */
428         memset((void *) i->fb_virt_start, 0, FB_SIZE);
429
430         /* Map the control registers in. */
431         i->regs = (u32 *) ioremap((unsigned long) phys_reg_addr, NUM_REGS);
432
433         /* Tell the hardware where the frame buffer is. */
434         out_be32(i->regs + REG_FB_ADDR, i->fb_phys);
435
436         /* Turn on the display. */
437         out_be32(i->regs + REG_CTRL, REG_CTRL_DEFAULT);
438
439         current_par.var.xres = XRES;
440         current_par.var.xres_virtual = XRES_VIRTUAL;
441         current_par.var.yres = YRES;
442         current_par.var.yres_virtual = YRES_VIRTUAL;
443         current_par.var.bits_per_pixel = BITS_PER_PIXEL;
444
445         i->gen.parsize = sizeof (struct xilinxfb_par);
446         i->gen.fbhw = &xilinx_switch;
447
448         strcpy(i->gen.info.modename, "Xilinx LCD");
449         i->gen.info.changevar = NULL;
450         i->gen.info.node = -1;
451
452         i->gen.info.fbops = &xilinxfb_ops;
453         i->gen.info.disp = &i->disp;
454         i->gen.info.switch_con = &fbgen_switch;
455         i->gen.info.updatevar = &fbgen_update_var;
456         i->gen.info.blank = &fbgen_blank;
457         i->gen.info.flags = FBINFO_FLAG_DEFAULT;
458
459         /* This should give a reasonable default video mode */
460         fbgen_get_var(&i->disp.var, -1, &i->gen.info);
461         fbgen_do_set_var(&i->disp.var, 1, &i->gen);
462         fbgen_set_disp(-1, &i->gen);
463         fbgen_install_cmap(0, &i->gen);
464         if (register_framebuffer(&i->gen.info) < 0) {
465                 printk(KERN_ERR "Could not register frame buffer "
466                        "for Xilinx device #%d.\n", index);
467                 remove_head_info();
468                 return -EINVAL;
469         }
470         printk(KERN_INFO "fb%d: %s frame buffer at 0x%08X mapped to 0x%08lX\n",
471                GET_FB_IDX(i->gen.info.node), i->gen.info.modename,
472                i->fb_phys, i->fb_virt_start);
473
474         return 0;
475 }
476
477 static int __init
478 xilinxfb_init(void)
479 {
480         int index = 0;
481
482         while (probe(index++) == 0) ;
483
484         /* If we found at least one, report success. */
485         return (index > 1) ? 0 : -ENODEV;
486 }
487
488 static void __exit
489 xilinxfb_cleanup(void)
490 {
491         while (info_list) {
492                 unregister_framebuffer((struct fb_info *) info_list);
493                 remove_head_info();
494         }
495 }
496
497 EXPORT_NO_SYMBOLS;
498
499 module_init(xilinxfb_init);
500 module_exit(xilinxfb_cleanup);