make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / video / q40fb.c
1 #include <linux/kernel.h>
2 #include <linux/errno.h>
3 #include <linux/string.h>
4 #include <linux/mm.h>
5 #include <linux/tty.h>
6 #include <linux/slab.h>
7 #include <linux/delay.h>
8 #include <linux/interrupt.h>
9
10 #include <asm/uaccess.h>
11 #include <asm/setup.h>
12 #include <asm/segment.h>
13 #include <asm/system.h>
14 /*#include <asm/irq.h>*/
15 #include <asm/q40_master.h>
16 #include <linux/fb.h>
17 #include <linux/module.h>
18 #include <asm/pgtable.h>
19
20 #include <video/fbcon.h>
21 #include <video/fbcon-cfb16.h>
22
23 #define FBIOSETSCROLLMODE   0x4611
24
25 #define Q40_PHYS_SCREEN_ADDR 0xFE800000
26 static unsigned long q40_screen_addr;
27
28 static u16 fbcon_cmap_cfb16[16];
29
30 /* frame buffer operations */
31
32 static int q40fb_get_fix(struct fb_fix_screeninfo *fix, int con,
33                         struct fb_info *info);
34 static int q40fb_get_var(struct fb_var_screeninfo *var, int con,
35                         struct fb_info *info);
36 static int q40fb_set_var(struct fb_var_screeninfo *var, int con,
37                         struct fb_info *info);
38 static int q40fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
39                          struct fb_info *info);
40 static int q40fb_set_cmap(struct fb_cmap *cmap,int kspc,int con,
41                          struct fb_info *info);
42 static int q40fb_ioctl(struct inode *inode, struct file *file,
43                       unsigned int cmd, unsigned long arg, int con,
44                       struct fb_info *info);
45
46 static int q40con_switch(int con, struct fb_info *info);
47 static int q40con_updatevar(int con, struct fb_info *info);
48 static void q40con_blank(int blank, struct fb_info *info);
49
50 static void q40fb_set_disp(int con, struct fb_info *info);
51
52 static struct display disp[MAX_NR_CONSOLES];
53 static struct fb_info fb_info;
54 static struct fb_ops q40fb_ops = {
55         owner:          THIS_MODULE,
56         fb_get_fix:     q40fb_get_fix,
57         fb_get_var:     q40fb_get_var,
58         fb_set_var:     q40fb_set_var,
59         fb_get_cmap:    q40fb_get_cmap,
60         fb_set_cmap:    q40fb_set_cmap,
61         fb_ioctl:       q40fb_ioctl,
62 };
63
64 static int currcon=0;
65
66 static char q40fb_name[]="Q40";
67
68 static int q40fb_get_fix(struct fb_fix_screeninfo *fix, int con,
69                         struct fb_info *info)
70 {
71         memset(fix, 0, sizeof(struct fb_fix_screeninfo));
72
73         strcpy(fix->id,"Q40");
74         fix->smem_start=q40_screen_addr;
75         fix->smem_len=1024*1024;
76         fix->type=FB_TYPE_PACKED_PIXELS;
77         fix->type_aux=0;
78         fix->visual=FB_VISUAL_TRUECOLOR;  /* good approximation so far ..*/;
79         fix->xpanstep=0;
80         fix->ypanstep=0;
81         fix->ywrapstep=0;
82         fix->line_length=1024*2;
83
84         /* no mmio,accel ...*/
85
86         return 0;
87
88 }
89         
90 static int q40fb_get_var(struct fb_var_screeninfo *var, int con,
91                         struct fb_info *info)
92 {
93         memset(var, 0, sizeof(struct fb_var_screeninfo));
94
95         var->xres=1024;
96         var->yres=512;
97         var->xres_virtual=1024;
98         var->yres_virtual=512;
99         var->xoffset=0;
100         var->yoffset=0;
101         var->bits_per_pixel=16;
102         var->grayscale=0;
103         var->nonstd=0;
104         var->activate=FB_ACTIVATE_NOW;
105         var->height=230;     /* approx for my 17" monitor, more important */
106         var->width=300;      /* than the absolute values is the unusual aspect ratio*/
107
108         var->red.offset=6; /*6*/
109         var->red.length=5;
110         var->green.offset=11; /*11*/
111         var->green.length=5;
112         var->blue.offset=0;
113         var->blue.length=6;
114         var->transp.length=0;
115
116         var->pixclock=0;
117         var->left_margin=0;
118         var->right_margin=0;
119         var->hsync_len=0;
120         var->vsync_len=0;
121         var->sync=0;
122         var->vmode=FB_VMODE_NONINTERLACED;
123
124         return 0;
125
126 }
127
128 static int q40fb_set_var(struct fb_var_screeninfo *var, int con,
129                         struct fb_info *info)
130 {
131         if(var->xres!=1024) 
132                 return -EINVAL;
133         if(var->yres!=512)
134                 return -EINVAL;
135         if(var->xres_virtual!=1024)
136                 return -EINVAL;
137         if(var->yres_virtual!=512)
138                 return -EINVAL;
139         if(var->xoffset!=0)
140                 return -EINVAL;
141         if(var->yoffset!=0)
142                 return -EINVAL;
143         if(var->bits_per_pixel!=16)
144                 return -EINVAL;
145         if(var->grayscale!=0)
146                 return -EINVAL;
147         if(var->nonstd!=0)
148                 return -EINVAL;
149         if(var->activate!=FB_ACTIVATE_NOW)
150                 return -EINVAL;
151         if(var->pixclock!=0)
152                 return -EINVAL;
153         if(var->left_margin!=0)
154                 return -EINVAL;
155         if(var->right_margin!=0)
156                 return -EINVAL;
157         if(var->hsync_len!=0)
158                 return -EINVAL;
159         if(var->vsync_len!=0)
160                 return -EINVAL;
161         if(var->sync!=0)
162                 return -EINVAL;
163         if(var->vmode!=FB_VMODE_NONINTERLACED)
164                 return -EINVAL;
165
166         return 0;
167
168 }
169
170 static int q40_getcolreg(unsigned regno, unsigned *red, unsigned *green,
171                          unsigned *blue, unsigned *transp,
172                          struct fb_info *info)
173 {
174     /*
175      *  Read a single color register and split it into colors/transparent.
176      *  The return values must have a 16 bit magnitude.
177      *  Return != 0 for invalid regno.
178      */
179     if (regno>=16) return 1;
180
181     *transp=0;
182     *green = ((fbcon_cmap_cfb16[regno]>>11) & 31)<<11;
183     *red   = ((fbcon_cmap_cfb16[regno]>>6) & 31)<<11;
184     *blue  = ((fbcon_cmap_cfb16[regno]) & 63)<<10;
185
186     return 0;
187 }
188
189 static int q40_setcolreg(unsigned regno, unsigned red, unsigned green,
190                          unsigned blue, unsigned transp, struct fb_info *info)
191 {
192     /*
193      *  Set a single color register. The values supplied have a 16 bit
194      *  magnitude.
195      *  Return != 0 for invalid regno.
196      */
197   
198   red>>=11;
199   green>>=11;
200   blue>>=10;
201
202     if (regno < 16) {
203       fbcon_cmap_cfb16[regno] = ((red & 31) <<6) |
204                                  ((green & 31) << 11) |
205                                  (blue & 63);
206     }
207     return 0;
208 }
209
210 static int q40fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
211                          struct fb_info *info)
212 {
213 #if 1
214         if (con == currcon) /* current console? */
215                 return fb_get_cmap(cmap, kspc, q40_getcolreg, info);
216         else if (fb_display[con].cmap.len) /* non default colormap? */
217                 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
218         else
219                 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
220                              cmap, kspc ? 0 : 2);
221         return 0;
222 #else
223         printk(KERN_ERR "get cmap not supported\n");
224
225         return -EINVAL;
226 #endif
227 }
228
229 static int q40fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
230                          struct fb_info *info)
231 {
232 #if 1
233         int err;
234
235         if (!fb_display[con].cmap.len) {        /* no colormap allocated? */
236                 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
237                                          1<<fb_display[con].var.bits_per_pixel,
238                                          0)))
239                         return err;
240         }
241         if (con == currcon)                     /* current console? */
242                 return fb_set_cmap(cmap, kspc, q40_setcolreg, info);
243         else
244                 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
245         return 0;
246 #else
247         printk(KERN_ERR "set cmap not supported\n");
248
249         return -EINVAL;
250 #endif
251 }
252
253 static int q40fb_ioctl(struct inode *inode, struct file *file,
254                       unsigned int cmd, unsigned long arg, int con,
255                       struct fb_info *info)
256 {
257 #if 0
258         unsigned long i;
259         struct display *display;
260
261         if (con>=0)
262           display = &fb_display[con];
263         else
264           display = &disp[0];
265
266         if (cmd == FBIOSETSCROLLMODE)
267           {
268             i = verify_area(VERIFY_READ, (void *)arg, sizeof(unsigned long));
269             if (!i) 
270               {
271                 copy_from_user(&i, (void *)arg, sizeof(unsigned long));
272                 display->scrollmode = i;
273               }
274             q40_updatescrollmode(display);
275             return i;
276           }
277 #endif
278         return -EINVAL;
279 }
280
281 static void q40fb_set_disp(int con, struct fb_info *info)
282 {
283   struct fb_fix_screeninfo fix;
284   struct display *display;
285
286   q40fb_get_fix(&fix, con, info);
287
288   if (con>=0)
289     display = &fb_display[con];
290   else  
291     display = &disp[0];
292
293   if (con<0) con=0;
294
295    display->screen_base = (char *)fix.smem_start;
296    display->visual = fix.visual;
297    display->type = fix.type;
298    display->type_aux = fix.type_aux;
299    display->ypanstep = fix.ypanstep;
300    display->ywrapstep = fix.ywrapstep;
301    display->can_soft_blank = 0;
302    display->inverse = 0;
303    display->line_length = fix.line_length;
304
305    display->scrollmode = SCROLL_YREDRAW;
306
307 #ifdef FBCON_HAS_CFB16
308    display->dispsw = &fbcon_cfb16;
309    disp->dispsw_data = fbcon_cmap_cfb16;
310 #else
311    display->dispsw = &fbcon_dummy;
312 #endif
313 }
314   
315 int __init q40fb_init(void)
316 {
317
318         if ( !MACH_IS_Q40)
319           return -ENXIO;
320 #if 0
321         q40_screen_addr = kernel_map(Q40_PHYS_SCREEN_ADDR, 1024*1024,
322                                            KERNELMAP_NO_COPYBACK, NULL);
323 #else
324         q40_screen_addr = Q40_PHYS_SCREEN_ADDR; /* mapped in q40/config.c */
325 #endif
326
327         fb_info.changevar=NULL;
328         strcpy(&fb_info.modename[0],q40fb_name);
329         fb_info.fontname[0]=0;
330         fb_info.disp=disp;
331         fb_info.switch_con=&q40con_switch;
332         fb_info.updatevar=&q40con_updatevar;
333         fb_info.blank=&q40con_blank;    
334         fb_info.node = -1;
335         fb_info.fbops = &q40fb_ops;
336         fb_info.flags = FBINFO_FLAG_DEFAULT;  /* not as module for now */
337         
338         master_outb(3,DISPLAY_CONTROL_REG);
339
340         q40fb_get_var(&disp[0].var, 0, &fb_info);
341         q40fb_set_disp(-1, &fb_info);
342
343         if (register_framebuffer(&fb_info) < 0) {
344                 printk(KERN_ERR "unable to register Q40 frame buffer\n");
345                 return -EINVAL;
346         }
347
348         printk(KERN_INFO "fb%d: Q40 frame buffer alive and kicking !\n",
349                GET_FB_IDX(fb_info.node));
350         return 0;
351 }       
352
353         
354 static int q40con_switch(int con, struct fb_info *info)
355
356         currcon=con;
357         
358         return 0;
359
360 }
361
362 static int q40con_updatevar(int con, struct fb_info *info)
363 {
364         return 0;
365 }
366
367 static void q40con_blank(int blank, struct fb_info *info)
368 {
369 }
370
371 MODULE_LICENSE("GPL");