clean
[linux-2.4.21-pre4.git] / drivers / video / hitfb.c
1 /*
2  * $Id: hitfb.c,v 1.1.1.1 2005/04/11 02:50:42 jack Exp $
3  * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device
4  * (C) 1999 Mihai Spatar
5  * (C) 2000 YAEGASHI Takeshi
6  *
7  *  This file is subject to the terms and conditions of the GNU General Public
8  *  License. See the file COPYING in the main directory of this archive for
9  *  more details.
10  */
11  
12 #include <linux/config.h>
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/errno.h>
17 #include <linux/string.h>
18 #include <linux/mm.h>
19 #include <linux/tty.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
22 #include <linux/nubus.h>
23 #include <linux/init.h>
24
25 #include <asm/machvec.h>
26 #include <asm/uaccess.h>
27 #include <asm/pgtable.h>
28 #include <asm/io.h>
29 #include <asm/hd64461.h>
30
31 #include <linux/fb.h>
32
33 #include <video/fbcon.h>
34 #include <video/fbcon-cfb8.h>
35 #include <video/fbcon-cfb16.h>
36
37
38 struct hitfb_par
39 {
40     int x, y;
41     int bpp;
42 };
43
44
45 struct hitfb_info {
46     struct fb_info_gen gen;
47     struct display disp;
48     struct hitfb_par current_par;
49     struct fb_var_screeninfo default_var;
50     int current_par_valid;
51     unsigned long hit_videobase, hit_videosize;
52     union {
53 #ifdef FBCON_HAS_CFB16
54         u16 cfb16[16];
55 #endif
56     } fbcon_cmap;
57 } fb_info = {
58     {},
59     {},
60     {},
61     {},
62     0, 0, 0,
63     {},
64 };
65
66
67 static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info);
68 static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
69                             struct fb_info_gen *info);
70
71
72 static void hitfb_detect(void)
73 {
74     struct hitfb_par par;
75     unsigned short lcdclor, ldr3, ldvntr;
76
77     fb_info.hit_videobase = CONFIG_HD64461_IOBASE + 0x02000000;
78     fb_info.hit_videosize = (MACH_HP680 || MACH_HP690) ? 1024*1024 : 512*1024;
79
80     lcdclor = inw(HD64461_LCDCLOR);
81     ldvntr = inw(HD64461_LDVNTR);
82     ldr3 = inw(HD64461_LDR3);
83
84     switch(ldr3&15) {
85     default:
86     case 4:
87         par.bpp = 8;
88         par.x = lcdclor;
89         break;
90     case 8:
91         par.bpp = 16;
92         par.x = lcdclor/2;
93         break;
94     }
95
96     par.y = ldvntr+1;
97
98     hitfb_set_par(&par, NULL);
99     hitfb_encode_var(&fb_info.default_var, &par, NULL);
100 }
101
102
103 static int hitfb_encode_fix(struct fb_fix_screeninfo *fix, const void *fb_par,
104                              struct fb_info_gen *info)
105 {
106     const struct hitfb_par *par = fb_par;
107
108     memset(fix, 0, sizeof(struct fb_fix_screeninfo));
109
110     strcpy(fix->id, "Hitachi HD64461");
111     fix->smem_start = fb_info.hit_videobase;
112     fix->smem_len = fb_info.hit_videosize;
113     fix->type = FB_TYPE_PACKED_PIXELS;
114     fix->type_aux = 0;
115     fix->visual = (par->bpp == 8) ?
116         FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
117     fix->xpanstep = 0;
118     fix->ypanstep = 0;
119     fix->ywrapstep = 0;
120
121     switch(par->bpp) {
122     default:
123     case 8:
124         fix->line_length = par->x;
125         break;
126     case 16:
127         fix->line_length = par->x*2;
128         break;
129     }
130
131     return 0;
132 }
133
134
135 static int hitfb_decode_var(const struct fb_var_screeninfo *var, void *fb_par,
136                              struct fb_info_gen *info)
137 {
138     struct hitfb_par *par = fb_par;
139
140     par->x = var->xres;
141     par->y = var->yres;
142     par->bpp = var->bits_per_pixel;
143     return 0;
144 }
145
146
147 static int hitfb_encode_var(struct fb_var_screeninfo *var, const void *fb_par,
148                              struct fb_info_gen *info)
149 {
150     const struct hitfb_par *par = fb_par;
151
152     memset(var, 0, sizeof(*var));
153
154     var->xres = par->x;
155     var->yres = par->y;
156     var->xres_virtual = var->xres;
157     var->yres_virtual = var->yres;
158     var->xoffset = 0;
159     var->yoffset = 0;
160     var->bits_per_pixel = par->bpp;
161     var->grayscale = 0;
162     var->transp.offset = 0;
163     var->transp.length = 0;
164     var->transp.msb_right = 0;
165     var->nonstd = 0;
166     var->activate = 0;
167     var->height = -1;
168     var->width = -1;
169     var->vmode = FB_VMODE_NONINTERLACED;
170     var->pixclock = 0;
171     var->sync = 0;
172     var->left_margin = 0;
173     var->right_margin = 0;
174     var->upper_margin = 0;
175     var->lower_margin = 0;
176     var->hsync_len = 0;
177     var->vsync_len = 0;
178
179     switch (var->bits_per_pixel) {
180
181         case 8:
182             var->red.offset = 0;
183             var->red.length = 8;
184             var->green.offset = 0;
185             var->green.length = 8;
186             var->blue.offset = 0;
187             var->blue.length = 8;
188             var->transp.offset = 0;
189             var->transp.length = 0;
190             break;
191
192         case 16:        /* RGB 565 */
193             var->red.offset = 11;
194             var->red.length = 5;
195             var->green.offset = 5;
196             var->green.length = 6;
197             var->blue.offset = 0;
198             var->blue.length = 5;
199             var->transp.offset = 0;
200             var->transp.length = 0;
201             break;
202     }
203
204     var->red.msb_right = 0;
205     var->green.msb_right = 0;
206     var->blue.msb_right = 0;
207     var->transp.msb_right = 0;
208
209     return 0;
210 }
211
212
213 static void hitfb_get_par(void *par, struct fb_info_gen *info)
214 {
215     *(struct hitfb_par *)par = fb_info.current_par;
216 }
217
218
219 static void hitfb_set_par(const void *fb_par, struct fb_info_gen *info)
220 {
221     const struct hitfb_par *par = fb_par;
222     fb_info.current_par = *par;
223     fb_info.current_par_valid = 1;
224 }
225
226
227 static int hitfb_getcolreg(unsigned regno, unsigned *red, unsigned *green,
228                            unsigned *blue, unsigned *transp,
229                            struct fb_info *info)
230 {
231     if (regno > 255)
232         return 1;       
233
234     outw(regno<<8, HD64461_CPTRAR);
235     *red = inw(HD64461_CPTRDR)<<10;
236     *green = inw(HD64461_CPTRDR)<<10;
237     *blue = inw(HD64461_CPTRDR)<<10;
238     *transp = 0;
239     
240     return 0;
241 }
242
243
244 static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
245                            unsigned blue, unsigned transp,
246                            struct fb_info *info)
247 {
248     if (regno > 255)
249         return 1;
250     
251     outw(regno<<8, HD64461_CPTWAR);
252     outw(red>>10, HD64461_CPTWDR);
253     outw(green>>10, HD64461_CPTWDR);
254     outw(blue>>10, HD64461_CPTWDR);
255     
256     if(regno<16) {
257         switch(fb_info.current_par.bpp) {
258 #ifdef FBCON_HAS_CFB16
259         case 16:
260             fb_info.fbcon_cmap.cfb16[regno] =
261                 ((red   & 0xf800)      ) |
262                 ((green & 0xfc00) >>  5) |
263                 ((blue  & 0xf800) >> 11);
264             break;
265 #endif
266         }
267     }
268
269     return 0;
270 }
271
272
273 static int hitfb_pan_display(const struct fb_var_screeninfo *var,
274                              struct fb_info_gen *info)
275 {
276     if (!fb_info.current_par_valid)
277         return -EINVAL;
278
279     return 0;
280 }
281
282
283 static int hitfb_blank(int blank_mode, struct fb_info_gen *info)
284 {
285     if (!fb_info.current_par_valid)
286         return 1;
287
288     return 0;
289 }
290
291
292 static void hitfb_set_disp(const void *fb_par, struct display *disp,
293                             struct fb_info_gen *info)
294 {
295     const struct hitfb_par *par = fb_par;
296
297     disp->screen_base = (void *)fb_info.hit_videobase;
298     disp->scrollmode = SCROLL_YREDRAW;
299
300     switch(((struct hitfb_par *)par)->bpp) {
301 #ifdef FBCON_HAS_CFB8
302     case 8:
303         disp->dispsw = &fbcon_cfb8;
304         break;
305 #endif
306 #ifdef FBCON_HAS_CFB16
307     case 16:
308         disp->dispsw = &fbcon_cfb16;
309         disp->dispsw_data = fb_info.fbcon_cmap.cfb16;
310         break;
311 #endif
312     default:
313         disp->dispsw = &fbcon_dummy;
314     }
315 }
316
317
318 struct fbgen_hwswitch hitfb_switch = {
319     hitfb_detect,
320     hitfb_encode_fix,
321     hitfb_decode_var,
322     hitfb_encode_var,
323     hitfb_get_par,
324     hitfb_set_par,
325     hitfb_getcolreg,
326     hitfb_setcolreg,
327     hitfb_pan_display,
328     hitfb_blank,
329     hitfb_set_disp
330 };
331
332
333 static struct fb_ops hitfb_ops = {
334     owner:              THIS_MODULE,
335     fb_get_fix:         fbgen_get_fix,
336     fb_get_var:         fbgen_get_var,
337     fb_set_var:         fbgen_set_var,
338     fb_get_cmap:        fbgen_get_cmap,
339     fb_set_cmap:        fbgen_set_cmap,
340     fb_pan_display:     fbgen_pan_display,
341 };
342
343
344 int __init hitfb_init(void)
345 {
346     strcpy(fb_info.gen.info.modename, "Hitachi HD64461");
347     fb_info.gen.info.node = -1;
348     fb_info.gen.info.flags = FBINFO_FLAG_DEFAULT;
349     fb_info.gen.info.fbops = &hitfb_ops;
350     fb_info.gen.info.disp = &fb_info.disp;
351     fb_info.gen.info.changevar = NULL;
352     fb_info.gen.info.switch_con = &fbgen_switch;
353     fb_info.gen.info.updatevar = &fbgen_update_var;
354     fb_info.gen.info.blank = &fbgen_blank;
355     fb_info.gen.parsize = sizeof(struct hitfb_par);
356     fb_info.gen.fbhw = &hitfb_switch;
357     fb_info.gen.fbhw->detect();
358     
359     fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
360     fb_info.disp.var.activate = FB_ACTIVATE_NOW;
361     fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
362     fbgen_set_disp(-1, &fb_info.gen);
363     fbgen_install_cmap(0, &fb_info.gen);
364     
365     if(register_framebuffer(&fb_info.gen.info)<0) return -EINVAL;
366     
367     printk(KERN_INFO "fb%d: %s frame buffer device\n",
368            GET_FB_IDX(fb_info.gen.info.node), fb_info.gen.info.modename);
369     
370     return 0;
371 }
372
373
374 void hitfb_cleanup(struct fb_info *info)
375 {
376     unregister_framebuffer(info);
377 }
378
379
380 #ifdef MODULE
381 MODULE_LICENSE("GPL");
382
383 int init_module(void)
384 {
385     return hitfb_init();
386 }
387
388 void cleanup_module(void)
389 {
390   hitfb_cleanup(void);
391 }
392 #endif
393
394
395 /*
396  * Local variables:
397  * c-basic-offset: 4
398  * End:
399  */