1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/string.h>
18#include <linux/tty.h>
19#include <linux/delay.h>
20#include <linux/interrupt.h>
21#include <linux/init.h>
22#include <linux/pm.h>
23#include <linux/fb.h>
24#include <video/fbcon.h>
25#include <video/fbcon-mfb.h>
26#include <video/fbcon-cfb2.h>
27#include <video/fbcon-cfb4.h>
28#include <video/fbcon-cfb8.h>
29#include <asm/io.h>
30#include <asm/bootinfo.h>
31#include <asm/uaccess.h>
32#include <asm/tx3912.h>
33#include "tx3912fb.h"
34
35
36
37
38static struct fb_info fb_info;
39static struct { u_char red, green, blue, pad; } palette[256];
40#ifdef FBCON_HAS_CFB8
41static union { u16 cfb8[16]; } fbcon_cmap;
42#endif
43static struct display global_disp;
44static int currcon = 0;
45
46
47
48
49static int tx3912fb_get_fix(struct fb_fix_screeninfo *fix, int con,
50 struct fb_info *info);
51static int tx3912fb_get_var(struct fb_var_screeninfo *var, int con,
52 struct fb_info *info);
53static int tx3912fb_set_var(struct fb_var_screeninfo *var, int con,
54 struct fb_info *info);
55static int tx3912fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
56 struct fb_info *info);
57static int tx3912fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
58 struct fb_info *info);
59static int tx3912fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
60 u_long arg, int con, struct fb_info *info);
61
62
63
64
65int tx3912fb_init(void);
66static int tx3912fbcon_switch(int con, struct fb_info *info);
67static int tx3912fbcon_updatevar(int con, struct fb_info *info);
68static void tx3912fbcon_blank(int blank, struct fb_info *info);
69
70
71
72
73#define get_line_length(xres_virtual, bpp) \
74 (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3)
75
76
77
78
79static int tx3912fb_getcolreg(u_int regno, u_int *red, u_int *green,
80 u_int *blue, u_int *transp, struct fb_info *info);
81static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
82 u_int transp, struct fb_info *info);
83static void tx3912fb_install_cmap(int con, struct fb_info *info);
84
85
86
87
88
89static struct fb_ops tx3912fb_ops = {
90 owner: THIS_MODULE,
91 fb_get_fix: tx3912fb_get_fix,
92 fb_get_var: tx3912fb_get_var,
93 fb_set_var: tx3912fb_set_var,
94 fb_get_cmap: tx3912fb_get_cmap,
95 fb_set_cmap: tx3912fb_set_cmap,
96 fb_ioctl: tx3912fb_ioctl,
97};
98
99
100
101
102
103static int tx3912fb_get_fix(struct fb_fix_screeninfo *fix, int con,
104 struct fb_info *info)
105{
106 struct display *display;
107
108 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
109 strcpy(fix->id, TX3912FB_NAME);
110
111 if (con == -1)
112 display = &global_disp;
113 else
114 display = &fb_display[con];
115
116 fix->smem_start = tx3912fb_vaddr;
117 fix->smem_len = tx3912fb_size;
118 fix->type = display->type;
119 fix->type_aux = display->type_aux;
120 fix->xpanstep = 0;
121 fix->ypanstep = display->ypanstep;
122 fix->ywrapstep = display->ywrapstep;
123 fix->visual = display->visual;
124 fix->line_length = display->line_length;
125 fix->accel = FB_ACCEL_NONE;
126
127 return 0;
128}
129
130
131
132
133static int tx3912fb_get_var(struct fb_var_screeninfo *var, int con,
134 struct fb_info *info)
135{
136 if (con == -1)
137 *var = tx3912fb_info;
138 else
139 *var = fb_display[con].var;
140
141 return 0;
142}
143
144
145
146
147static int tx3912fb_set_var(struct fb_var_screeninfo *var, int con,
148 struct fb_info *info)
149{
150 int err, activate = var->activate;
151 int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
152 u_long line_length;
153 struct display *display;
154
155 if (con == -1)
156 display = &global_disp;
157 else
158 display = &fb_display[con];
159
160
161
162
163
164 if (var->vmode & FB_VMODE_CONUPDATE) {
165 var->xoffset = display->var.xoffset;
166 var->yoffset = display->var.yoffset;
167 var->vmode |= FB_VMODE_YWRAP;
168 }
169
170
171
172
173 if (!var->xres)
174 var->xres = 1;
175 if (!var->yres)
176 var->yres = 1;
177 if (var->xres > var->xres_virtual)
178 var->xres_virtual = var->xres;
179 if (var->yres > var->yres_virtual)
180 var->yres_virtual = var->yres;
181 if (var->bits_per_pixel <= 1)
182 var->bits_per_pixel = 1;
183 else if (var->bits_per_pixel <= 2)
184 var->bits_per_pixel = 2;
185 else if (var->bits_per_pixel <= 4)
186 var->bits_per_pixel = 4;
187 else if (var->bits_per_pixel <= 8)
188 var->bits_per_pixel = 8;
189 else
190 return -EINVAL;
191
192
193
194
195 line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
196 if ((line_length * var->yres_virtual) > tx3912fb_size)
197 return -ENOMEM;
198
199
200
201
202 if (var->bits_per_pixel) {
203
204 var->red.offset = 5;
205 var->red.length = 3;
206 var->green.offset = 2;
207 var->green.length = 3;
208 var->blue.offset = 0;
209 var->blue.length = 2;
210 var->transp.offset = 0;
211 var->transp.length = 0;
212 }
213 var->red.msb_right = 0;
214 var->green.msb_right = 0;
215 var->blue.msb_right = 0;
216 var->transp.msb_right = 0;
217
218
219
220
221 if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
222
223 oldxres = display->var.xres;
224 oldyres = display->var.yres;
225 oldvxres = display->var.xres_virtual;
226 oldvyres = display->var.yres_virtual;
227 oldbpp = display->var.bits_per_pixel;
228 display->var = *var;
229
230 if (oldxres != var->xres || oldyres != var->yres ||
231 oldvxres != var->xres_virtual ||
232 oldvyres != var->yres_virtual ||
233 oldbpp != var->bits_per_pixel) {
234
235 display->screen_base = (u_char *) tx3912fb_vaddr;
236
237 switch (var->bits_per_pixel) {
238 case 1:
239 display->visual = FB_VISUAL_MONO10;
240 break;
241 case 2:
242 display->visual = FB_VISUAL_PSEUDOCOLOR;
243 case 4:
244 case 8:
245 display->visual = FB_VISUAL_TRUECOLOR;
246 break;
247 }
248
249 display->type = FB_TYPE_PACKED_PIXELS;
250 display->type_aux = 0;
251 display->ypanstep = 0;
252 display->ywrapstep = 0;
253 display->next_line =
254 display->line_length =
255 get_line_length(var->xres_virtual,
256 var->bits_per_pixel);
257 display->can_soft_blank = 0;
258 display->inverse = FB_IS_INVERSE;
259
260 switch (var->bits_per_pixel) {
261#ifdef CONFIG_FBCON_MFB
262 case 1:
263 display->dispsw = &fbcon_mfb;
264 break;
265#endif
266#ifdef CONFIG_FBCON_CFB2
267 case 2:
268 display->dispsw = &fbcon_cfb2;
269 break;
270#endif
271#ifdef CONFIG_FBCON_CFB4
272 case 4:
273 display->dispsw = &fbcon_cfb4;
274 break;
275#endif
276#ifdef CONFIG_FBCON_CFB8
277 case 8:
278 display->dispsw = &fbcon_cfb8;
279 display->dispsw_data = fbcon_cmap.cfb8;
280 break;
281#endif
282 default:
283 display->dispsw = &fbcon_dummy;
284 break;
285 }
286
287 if (fb_info.changevar)
288 (*fb_info.changevar)(con);
289 }
290
291 if (oldbpp != var->bits_per_pixel) {
292 if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
293 return err;
294 tx3912fb_install_cmap(con, info);
295 }
296 }
297
298 return 0;
299}
300
301
302
303
304static int tx3912fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
305 struct fb_info *info)
306{
307 if (con == currcon)
308 return fb_get_cmap(cmap, kspc, tx3912fb_getcolreg, info);
309 else if (fb_display[con].cmap.len)
310 fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
311 else
312 fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
313
314 return 0;
315}
316
317
318
319
320static int tx3912fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
321 struct fb_info *info)
322{
323 int err;
324
325 if (!fb_display[con].cmap.len)
326 if ((err = fb_alloc_cmap(&fb_display[con].cmap,
327 1<<fb_display[con].var.bits_per_pixel, 0)))
328 return err;
329
330 if (con == currcon)
331 return fb_set_cmap(cmap, kspc, tx3912fb_setcolreg, info);
332 else
333 fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
334
335 return 0;
336}
337
338
339
340
341static int tx3912fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
342 u_long arg, int con, struct fb_info *info)
343{
344 return -EINVAL;
345}
346
347
348
349
350int __init tx3912fb_init(void)
351{
352
353 outl(inl(TX3912_VIDEO_CTRL1) &
354 ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
355 TX3912_VIDEO_CTRL1);
356 udelay(200);
357
358
359 outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
360
361
362 outl((tx3912fb_paddr + tx3912fb_size + 1), TX3912_VIDEO_CTRL4);
363
364
365 switch (tx3912fb_info.bits_per_pixel) {
366 case 1:
367
368 outl(inl(TX3912_VIDEO_CTRL1) & ~TX3912_VIDEO_CTRL1_BITSEL_MASK,
369 TX3912_VIDEO_CTRL1);
370 break;
371 case 4:
372
373 outl(inl(TX3912_VIDEO_CTRL1) & ~TX3912_VIDEO_CTRL1_BITSEL_MASK,
374 TX3912_VIDEO_CTRL1);
375 outl(inl(TX3912_VIDEO_CTRL1) |
376 TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
377 TX3912_VIDEO_CTRL1);
378 break;
379 case 8:
380
381 outl(inl(TX3912_VIDEO_CTRL1) & ~TX3912_VIDEO_CTRL1_BITSEL_MASK,
382 TX3912_VIDEO_CTRL1);
383 outl(inl(TX3912_VIDEO_CTRL1) |
384 TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
385 TX3912_VIDEO_CTRL1);
386 break;
387 case 2:
388 default:
389
390 outl(inl(TX3912_VIDEO_CTRL1) & ~TX3912_VIDEO_CTRL1_BITSEL_MASK,
391 TX3912_VIDEO_CTRL1);
392 outl(inl(TX3912_VIDEO_CTRL1) |
393 TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
394 TX3912_VIDEO_CTRL1);
395 break;
396 }
397
398
399 outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
400 TX3912_CLK_CTRL);
401
402
403 outl(inl(TX3912_VIDEO_CTRL1) &
404 ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE),
405 TX3912_VIDEO_CTRL1);
406 udelay(200);
407
408
409 memset((void *) tx3912fb_vaddr, 0xff, tx3912fb_size);
410 udelay(200);
411
412
413 outl(inl(TX3912_VIDEO_CTRL1) |
414 (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
415 TX3912_VIDEO_CTRL1);
416
417 strcpy(fb_info.modename, TX3912FB_NAME);
418 fb_info.changevar = NULL;
419 fb_info.node = -1;
420 fb_info.fbops = &tx3912fb_ops;
421 fb_info.disp = &global_disp;
422 fb_info.switch_con = &tx3912fbcon_switch;
423 fb_info.updatevar = &tx3912fbcon_updatevar;
424 fb_info.blank = &tx3912fbcon_blank;
425 fb_info.flags = FBINFO_FLAG_DEFAULT;
426
427 tx3912fb_set_var(&tx3912fb_info, -1, &fb_info);
428
429 if (register_framebuffer(&fb_info) < 0)
430 return -1;
431
432 printk (KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n",
433 GET_FB_IDX(fb_info.node), (u_int) (tx3912fb_size >> 10));
434
435 return 0;
436}
437
438
439
440
441static int tx3912fbcon_switch(int con, struct fb_info *info)
442{
443
444 if (fb_display[currcon].cmap.len)
445 fb_get_cmap(&fb_display[currcon].cmap, 1,
446 tx3912fb_getcolreg, info);
447
448
449 currcon = con;
450
451
452 tx3912fb_install_cmap(con, info);
453
454 return 0;
455}
456
457
458
459
460static int tx3912fbcon_updatevar(int con, struct fb_info *info)
461{
462
463 return 0;
464}
465
466
467
468
469static void tx3912fbcon_blank(int blank, struct fb_info *info)
470{
471
472 printk("tx3912fbcon_blank\n");
473}
474
475
476
477
478static int tx3912fb_getcolreg(u_int regno, u_int *red, u_int *green,
479 u_int *blue, u_int *transp, struct fb_info *info)
480{
481 if (regno > 255)
482 return 1;
483
484#if FB_IS_GREY
485 {
486 u_int grey;
487
488 grey = regno * 255 / 15;
489
490#if FB_IS_INVERSE
491 grey ^= 255;
492#endif
493 grey |= grey << 8;
494 *red = grey;
495 *green = grey;
496 *blue = grey;
497 }
498#else
499 *red = (palette[regno].red<<8) | palette[regno].red;
500 *green = (palette[regno].green<<8) | palette[regno].green;
501 *blue = (palette[regno].blue<<8) | palette[regno].blue;
502#endif
503 *transp = 0;
504
505 return 0;
506}
507
508
509
510
511static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
512 u_int transp, struct fb_info *info)
513{
514 if (regno > 255)
515 return 1;
516
517#ifdef FBCON_HAS_CFB8
518 if( regno < 16 )
519 fbcon_cmap.cfb8[regno] = ((red & 0xe000) >> 8)
520 | ((green & 0xe000) >> 11)
521 | ((blue & 0xc000) >> 14);
522#endif
523
524 red >>= 8;
525 green >>= 8;
526 blue >>= 8;
527 palette[regno].red = red;
528 palette[regno].green = green;
529 palette[regno].blue = blue;
530
531 return 0;
532}
533
534
535
536
537static void tx3912fb_install_cmap(int con, struct fb_info *info)
538{
539 if (con != currcon)
540 return;
541
542 if (fb_display[con].cmap.len)
543 fb_set_cmap(&fb_display[con].cmap, 1, tx3912fb_setcolreg, info);
544 else
545 fb_set_cmap(fb_default_cmap(1 << fb_display[con].var.bits_per_pixel), 1, tx3912fb_setcolreg, info);
546}
547
548MODULE_LICENSE("GPL");
549