2 * Permedia2 framebuffer driver.
3 * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
4 * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
5 * Based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven.
6 * --------------------------------------------------------------------------
7 * $Id: pm2fb.c,v 1.1.1.1 2005/04/11 02:50:42 jack Exp $
8 * --------------------------------------------------------------------------
9 * TODO multiple boards support
10 * --------------------------------------------------------------------------
11 * This file is subject to the terms and conditions of the GNU General Public
12 * License. See the file COPYING in the main directory of this archive
16 #include <linux/config.h>
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/errno.h>
20 #include <linux/string.h>
22 #include <linux/tty.h>
23 #include <linux/slab.h>
24 #include <linux/vmalloc.h>
25 #include <linux/delay.h>
26 #include <linux/interrupt.h>
28 #include <linux/selection.h>
29 #include <linux/console.h>
30 #include <linux/init.h>
31 #include <linux/pci.h>
32 #include <asm/system.h>
34 #include <asm/uaccess.h>
35 #include <video/fbcon.h>
36 #include <video/fbcon-cfb8.h>
37 #include <video/fbcon-cfb16.h>
38 #include <video/fbcon-cfb24.h>
39 #include <video/fbcon-cfb32.h>
41 #include "cvisionppc.h"
47 #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
48 #error "The endianness of the target host has not been defined."
51 #if defined(__BIG_ENDIAN) && !defined(__sparc__)
52 #define PM2FB_BE_APERTURE
55 /* Need to debug this some more */
56 #undef PM2FB_HW_CURSOR
58 #if defined(CONFIG_FB_PM2_PCI) && !defined(CONFIG_PCI)
59 #undef CONFIG_FB_PM2_PCI
60 #warning "support for Permedia2 PCI boards with no generic PCI support!"
63 #undef PM2FB_MASTER_DEBUG
64 #ifdef PM2FB_MASTER_DEBUG
65 #define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
67 #define DPRINTK(a,b...)
70 #define PICOS2KHZ(a) (1000000000UL/(a))
71 #define KHZ2PICOS(a) (1000000000UL/(a))
74 * The _DEFINITIVE_ memory mapping/unmapping functions.
75 * This is due to the fact that they're changing soooo often...
77 #define MMAP(a,b) ioremap((unsigned long )(a), b)
78 #define UNMAP(a,b) iounmap(a)
81 * The _DEFINITIVE_ memory i/o barrier functions.
82 * This is due to the fact that they're changing soooo often...
89 #define MIN(a,b) ((a)<(b)?(a):(b))
93 #define MAX(a,b) ((a)>(b)?(a):(b))
97 u32 pixclock; /* pixclock in KHz */
98 u32 width; /* width of virtual screen */
99 u32 height; /* height of virtual screen */
100 u32 hsstart; /* horiz. sync start */
101 u32 hsend; /* horiz. sync end */
102 u32 hbend; /* horiz. blank end (also gate end) */
103 u32 htotal; /* total width (w/ sync & blank) */
104 u32 vsstart; /* vert. sync start */
105 u32 vsend; /* vert. sync end */
106 u32 vbend; /* vert. blank end */
107 u32 vtotal; /* total height (w/ sync & blank) */
108 u32 stride; /* screen stride */
109 u32 base; /* screen base (xoffset+yoffset) */
110 u32 depth; /* screen depth (8, 16, 24 or 32) */
111 u32 video; /* video control (hsync,vsync) */
114 #define OPTF_OLD_MEM (1L<<0)
115 #define OPTF_YPAN (1L<<1)
116 #define OPTF_VIRTUAL (1L<<2)
117 #define OPTF_USER (1L<<3)
121 struct pm2fb_par user_mode;
124 /* For some reason Raptor is not happy with the low-end mode */
125 {"\0", 0L, {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}};
127 {"\0", 0L, {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}};
130 static char curblink __initdata = 1;
134 struct pm2fb_par par;
135 } user_mode[] __initdata = {
137 {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}},
139 {31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121}},
141 {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}},
143 {39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121}},
145 {44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121}},
147 {35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41}},
149 {40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41}},
151 {44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105}},
153 {50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41}},
155 {49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41}},
157 {56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41}},
159 {67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41}},
161 {64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121}},
163 {74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121}},
165 {74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121}},
167 {78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41}},
169 {100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121}},
171 {109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121}},
173 {120322,1024,768,12,48,120,375,3,7,32,799,128,0,8,41}},
175 {80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41}},
177 {100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41}},
179 {109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41}},
181 {109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41}},
183 {107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41}},
185 {125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41}},
187 {134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41}},
189 {134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41}},
191 {155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121}},
193 {171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121}},
195 {197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121}},
199 #ifdef CONFIG_FB_PM2_PCI
208 #define DEFAULT_CURSOR_BLINK_RATE (20)
209 #define CURSOR_DRAW_DELAY (2)
222 struct timer_list *timer;
225 static const char permedia2_name[16]="Permedia2";
227 static struct pm2fb_info {
228 struct fb_info_gen gen;
229 int board; /* Permedia2 board index (see
230 board_table[] below) */
233 unsigned long fb_base; /* physical framebuffer memory base */
234 u32 fb_size; /* framebuffer memory size */
235 unsigned long rg_base; /* physical register memory base */
236 unsigned long p_fb; /* physical address of frame buffer */
237 unsigned char* v_fb; /* virtual address of frame buffer */
238 unsigned long p_regs; /* physical address of registers
239 region, must be rg_base or
240 rg_base+PM2_REGS_SIZE depending on
241 the host endianness */
242 unsigned char* v_regs; /* virtual address of p_regs */
244 union { /* here, the per-board par structs */
245 #ifdef CONFIG_FB_PM2_CVPPC
246 struct cvppc_par cvppc; /* CVisionPPC data */
248 #ifdef CONFIG_FB_PM2_PCI
249 struct pm2pci_par pci; /* Permedia2 PCI boards data */
252 struct pm2fb_par current_par; /* displayed screen */
253 int current_par_valid;
254 u32 memclock; /* memclock (set by the per-board
264 #ifdef FBCON_HAS_CFB16
267 #ifdef FBCON_HAS_CFB24
270 #ifdef FBCON_HAS_CFB32
274 struct pm2_cursor *cursor;
277 #ifdef CONFIG_FB_PM2_CVPPC
278 static int cvppc_detect(struct pm2fb_info*);
279 static void cvppc_init(struct pm2fb_info*);
282 #ifdef CONFIG_FB_PM2_PCI
283 static int pm2pci_detect(struct pm2fb_info*);
284 static void pm2pci_init(struct pm2fb_info*);
287 #ifdef PM2FB_HW_CURSOR
288 static void pm2fb_cursor(struct display *p, int mode, int x, int y);
289 static int pm2fb_set_font(struct display *d, int width, int height);
290 static struct pm2_cursor *pm2_init_cursor(struct pm2fb_info *fb);
291 static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue);
292 static void pm2v_set_cursor_shape(struct pm2fb_info *fb);
293 static u8 cursor_color_map[2] = { 0, 0xff };
295 #define pm2fb_cursor NULL
296 #define pm2fb_set_font NULL
300 * Table of the supported Permedia2 based boards.
301 * Three hooks are defined for each board:
302 * detect(): should return 1 if the related board has been detected, 0
303 * otherwise. It should also fill the fields 'regions.fb_base',
304 * 'regions.fb_size', 'regions.rg_base' and 'memclock' in the
305 * passed pm2fb_info structure.
306 * init(): called immediately after the reset of the Permedia2 chip.
307 * It should reset the memory controller if needed (the MClk
308 * is set shortly afterwards by the caller).
309 * cleanup(): called after the driver has been unregistered.
311 * the init and cleanup pointers can be NULL.
313 static const struct {
314 int (*detect)(struct pm2fb_info*);
315 void (*init)(struct pm2fb_info*);
316 void (*cleanup)(struct pm2fb_info*);
319 #ifdef CONFIG_FB_PM2_PCI
320 { pm2pci_detect, pm2pci_init, NULL, "Permedia2 PCI board" },
322 #ifdef CONFIG_FB_PM2_CVPPC
323 { cvppc_detect, cvppc_init, NULL, "CVisionPPC/BVisionPPC" },
329 * partial products for the supported horizontal resolutions.
331 #define PACKPP(p0,p1,p2) (((p2)<<6)|((p1)<<3)|(p0))
332 static const struct {
336 { 32, PACKPP(1, 0, 0) }, { 64, PACKPP(1, 1, 0) },
337 { 96, PACKPP(1, 1, 1) }, { 128, PACKPP(2, 1, 1) },
338 { 160, PACKPP(2, 2, 1) }, { 192, PACKPP(2, 2, 2) },
339 { 224, PACKPP(3, 2, 1) }, { 256, PACKPP(3, 2, 2) },
340 { 288, PACKPP(3, 3, 1) }, { 320, PACKPP(3, 3, 2) },
341 { 384, PACKPP(3, 3, 3) }, { 416, PACKPP(4, 3, 1) },
342 { 448, PACKPP(4, 3, 2) }, { 512, PACKPP(4, 3, 3) },
343 { 544, PACKPP(4, 4, 1) }, { 576, PACKPP(4, 4, 2) },
344 { 640, PACKPP(4, 4, 3) }, { 768, PACKPP(4, 4, 4) },
345 { 800, PACKPP(5, 4, 1) }, { 832, PACKPP(5, 4, 2) },
346 { 896, PACKPP(5, 4, 3) }, { 1024, PACKPP(5, 4, 4) },
347 { 1056, PACKPP(5, 5, 1) }, { 1088, PACKPP(5, 5, 2) },
348 { 1152, PACKPP(5, 5, 3) }, { 1280, PACKPP(5, 5, 4) },
349 { 1536, PACKPP(5, 5, 5) }, { 1568, PACKPP(6, 5, 1) },
350 { 1600, PACKPP(6, 5, 2) }, { 1664, PACKPP(6, 5, 3) },
351 { 1792, PACKPP(6, 5, 4) }, { 2048, PACKPP(6, 5, 5) },
354 static void pm2fb_detect(void);
355 static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
356 const void* par, struct fb_info_gen* info);
357 static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
358 void* par, struct fb_info_gen* info);
359 static int pm2fb_encode_var(struct fb_var_screeninfo* var,
360 const void* par, struct fb_info_gen* info);
361 static void pm2fb_get_par(void* par, struct fb_info_gen* info);
362 static void pm2fb_set_par(const void* par, struct fb_info_gen* info);
363 static int pm2fb_getcolreg(unsigned regno,
364 unsigned* red, unsigned* green, unsigned* blue,
365 unsigned* transp, struct fb_info* info);
366 static int pm2fb_setcolreg(unsigned regno,
367 unsigned red, unsigned green, unsigned blue,
368 unsigned transp, struct fb_info* info);
369 static int pm2fb_blank(int blank_mode, struct fb_info_gen* info);
370 static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
371 struct fb_info_gen* info);
372 static void pm2fb_set_disp(const void* par, struct display* disp,
373 struct fb_info_gen* info);
375 static struct fbgen_hwswitch pm2fb_hwswitch={
376 pm2fb_detect, pm2fb_encode_fix, pm2fb_decode_var,
377 pm2fb_encode_var, pm2fb_get_par, pm2fb_set_par,
378 pm2fb_getcolreg, pm2fb_setcolreg, pm2fb_pan_display,
379 pm2fb_blank, pm2fb_set_disp
382 static struct fb_ops pm2fb_ops={
384 fb_get_fix: fbgen_get_fix,
385 fb_get_var: fbgen_get_var,
386 fb_set_var: fbgen_set_var,
387 fb_get_cmap: fbgen_get_cmap,
388 fb_set_cmap: fbgen_set_cmap,
389 fb_pan_display: fbgen_pan_display,
392 /***************************************************************************
393 * Begin of Permedia2 specific functions
394 ***************************************************************************/
396 inline static u32 RD32(unsigned char* base, s32 off) {
398 return readl(base+off);
401 inline static void WR32(unsigned char* base, s32 off, u32 v) {
406 inline static u32 pm2_RD(struct pm2fb_info* p, s32 off) {
408 return RD32(p->regions.v_regs, off);
411 inline static void pm2_WR(struct pm2fb_info* p, s32 off, u32 v) {
413 WR32(p->regions.v_regs, off, v);
416 inline static u32 pm2_RDAC_RD(struct pm2fb_info* p, s32 idx) {
418 int index = PM2R_RD_INDEXED_DATA;
420 case PM2_TYPE_PERMEDIA2:
421 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
423 case PM2_TYPE_PERMEDIA2V:
424 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
425 index = PM2VR_RD_INDEXED_DATA;
429 return pm2_RD(p, index);
432 inline static void pm2_RDAC_WR(struct pm2fb_info* p, s32 idx,
435 int index = PM2R_RD_INDEXED_DATA;
437 case PM2_TYPE_PERMEDIA2:
438 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, idx);
440 case PM2_TYPE_PERMEDIA2V:
441 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
442 index = PM2VR_RD_INDEXED_DATA;
449 inline static u32 pm2v_RDAC_RD(struct pm2fb_info* p, s32 idx) {
451 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
453 return pm2_RD(p, PM2VR_RD_INDEXED_DATA);
456 inline static void pm2v_RDAC_WR(struct pm2fb_info* p, s32 idx,
459 pm2_WR(p, PM2VR_RD_INDEX_LOW, idx & 0xff);
461 pm2_WR(p, PM2VR_RD_INDEXED_DATA, v);
464 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
465 #define WAIT_FIFO(p,a)
467 inline static void WAIT_FIFO(struct pm2fb_info* p, u32 a) {
469 while(pm2_RD(p, PM2R_IN_FIFO_SPACE)<a);
474 static u32 partprod(u32 xres) {
477 for (i=0; pp_table[i].width && pp_table[i].width!=xres; i++);
478 if (!pp_table[i].width)
479 DPRINTK("invalid width %u\n", xres);
480 return pp_table[i].pp;
483 static u32 to3264(u32 timing, int bpp, int is64) {
487 timing=timing>>(2+is64);
490 timing=timing>>(1+is64);
493 timing=(timing*3)>>(2+is64);
503 static u32 from3264(u32 timing, int bpp, int is64) {
507 timing=timing<<(2+is64);
510 timing=timing<<(1+is64);
513 timing=(timing<<(2+is64))/3;
523 static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
533 for (n=2; n<15; n++) {
535 f=PM2_REFERENCE_CLOCK*m/n;
536 if (f>=150000 && f<=300000) {
537 for (p=0; p<5; p++, f>>=1) {
538 curr=clk>f?clk-f:f-clk;
551 static void pm2v_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
562 for (p=0; p<2; p++) {
563 f=PM2_REFERENCE_CLOCK*n/(m * (1<<(p+1)));
564 if (clk>f-delta && clk<f+delta) {
565 delta=clk>f?clk-f:f-clk;
575 static void wait_pm2(struct pm2fb_info* i) {
578 pm2_WR(i, PM2R_SYNC, 0);
581 while (pm2_RD(i, PM2R_OUT_FIFO_WORDS)==0);
583 } while (pm2_RD(i, PM2R_OUT_FIFO)!=PM2TAG(PM2R_SYNC));
586 static void pm2_set_memclock(struct pm2fb_info* info, u32 clk) {
588 unsigned char m, n, p;
590 pm2_mnp(clk, &m, &n, &p);
592 pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 6);
594 pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_1, m);
595 pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_2, n);
597 pm2_RDAC_WR(info, PM2I_RD_MEMORY_CLOCK_3, 8|p);
599 pm2_RDAC_RD(info, PM2I_RD_MEMORY_CLOCK_STATUS);
602 !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
605 static void pm2_set_pixclock(struct pm2fb_info* info, u32 clk) {
607 unsigned char m, n, p;
609 switch (info->type) {
610 case PM2_TYPE_PERMEDIA2:
611 pm2_mnp(clk, &m, &n, &p);
613 pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
615 pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
616 pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A2, n);
618 pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 8|p);
620 pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
623 !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
625 case PM2_TYPE_PERMEDIA2V:
626 pm2v_mnp(clk/2, &m, &n, &p);
628 pm2_WR(info, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
629 pm2v_RDAC_WR(info, PM2VI_RD_CLK0_PRESCALE, m);
630 pm2v_RDAC_WR(info, PM2VI_RD_CLK0_FEEDBACK, n);
631 pm2v_RDAC_WR(info, PM2VI_RD_CLK0_POSTSCALE, p);
632 pm2_WR(info, PM2VR_RD_INDEX_HIGH, 0);
637 static void clear_palette(struct pm2fb_info* p) {
641 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, 0);
645 pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
646 pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
647 pm2_WR(p, PM2R_RD_PALETTE_DATA, 0);
651 static void set_color(struct pm2fb_info* p, unsigned char regno,
652 unsigned char r, unsigned char g, unsigned char b) {
655 pm2_WR(p, PM2R_RD_PALETTE_WRITE_ADDRESS, regno);
657 pm2_WR(p, PM2R_RD_PALETTE_DATA, r);
659 pm2_WR(p, PM2R_RD_PALETTE_DATA, g);
661 pm2_WR(p, PM2R_RD_PALETTE_DATA, b);
664 static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) {
667 #ifdef __LITTLE_ENDIAN
668 pm2_WR(i, PM2R_APERTURE_ONE, 0);
669 pm2_WR(i, PM2R_APERTURE_TWO, 0);
674 pm2_WR(i, PM2R_APERTURE_ONE, 0);
675 pm2_WR(i, PM2R_APERTURE_TWO, 1);
678 pm2_WR(i, PM2R_APERTURE_ONE, 2);
679 pm2_WR(i, PM2R_APERTURE_TWO, 1);
682 pm2_WR(i, PM2R_APERTURE_ONE, 1);
683 pm2_WR(i, PM2R_APERTURE_TWO, 1);
689 static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
697 if (i->type == PM2_TYPE_PERMEDIA2V) {
699 pm2_WR(i, PM2VR_RD_INDEX_HIGH, 0);
701 xres=(p->width+31)&~31;
705 pm2_RDAC_WR(i, PM2I_RD_COLOR_KEY_CONTROL, p->depth==8?0:
706 PM2F_COLOR_KEY_TEST_OFF);
709 pm2_WR(i, PM2R_FB_READ_PIXEL, 0);
713 pm2_WR(i, PM2R_FB_READ_PIXEL, 1);
714 clrmode=PM2F_RD_TRUECOLOR|0x06;
715 txtmap=PM2F_TEXTEL_SIZE_16;
720 pm2_WR(i, PM2R_FB_READ_PIXEL, 2);
721 clrmode=PM2F_RD_TRUECOLOR|0x08;
722 txtmap=PM2F_TEXTEL_SIZE_32;
727 pm2_WR(i, PM2R_FB_READ_PIXEL, 4);
728 clrmode=PM2F_RD_TRUECOLOR|0x09;
729 txtmap=PM2F_TEXTEL_SIZE_24;
734 pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
735 pm2_WR(i, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
736 pm2_WR(i, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
737 pm2_WR(i, PM2R_FB_READ_MODE, partprod(xres));
738 pm2_WR(i, PM2R_LB_READ_MODE, partprod(xres));
739 pm2_WR(i, PM2R_TEXTURE_MAP_FORMAT, txtmap|partprod(xres));
740 pm2_WR(i, PM2R_H_TOTAL, p->htotal);
741 pm2_WR(i, PM2R_HS_START, p->hsstart);
742 pm2_WR(i, PM2R_HS_END, p->hsend);
743 pm2_WR(i, PM2R_HG_END, p->hbend);
744 pm2_WR(i, PM2R_HB_END, p->hbend);
745 pm2_WR(i, PM2R_V_TOTAL, p->vtotal);
746 pm2_WR(i, PM2R_VS_START, p->vsstart);
747 pm2_WR(i, PM2R_VS_END, p->vsend);
748 pm2_WR(i, PM2R_VB_END, p->vbend);
749 pm2_WR(i, PM2R_SCREEN_STRIDE, p->stride);
751 pm2_WR(i, PM2R_SCREEN_BASE, p->base);
752 /* HW cursor needs /VSYNC for recognizing vert retrace */
753 video=p->video & ~(PM2F_HSYNC_ACT_LOW|PM2F_VSYNC_ACT_LOW);
754 video|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
756 case PM2_TYPE_PERMEDIA2:
757 tmp = PM2F_RD_PALETTE_WIDTH_8;
758 pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
759 PM2F_RD_GUI_ACTIVE|clrmode);
760 if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
761 tmp |= 4; /* invert hsync */
762 if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
763 tmp |= 8; /* invert vsync */
764 pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
766 case PM2_TYPE_PERMEDIA2V:
768 pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
769 pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
770 if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
771 tmp |= 1; /* invert hsync */
772 if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
773 tmp |= 4; /* invert vsync */
774 pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
775 pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
778 pm2_WR(i, PM2R_VIDEO_CONTROL, video);
779 pm2_set_pixclock(i, p->pixclock);
783 * copy with packed pixels (8/16bpp only).
785 static void pm2fb_pp_copy(struct pm2fb_info* i, s32 xsrc, s32 ysrc,
786 s32 x, s32 y, s32 w, s32 h) {
787 s32 scale=i->current_par.depth==8?2:1;
793 pm2_WR(i, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE|
794 PM2F_CONFIG_FB_PACKED_DATA|
795 PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
796 pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
797 pm2_WR(i, PM2R_FB_SOURCE_DELTA, ((ysrc-y)&0xfff)<<16|
799 offset=(x&0x3)-(xsrc&0x3);
800 pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|(x>>scale));
801 pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|((w+7)>>scale));
802 pm2_WR(i, PM2R_PACKED_DATA_LIMITS, (offset<<29)|(x<<16)|(x+w));
804 pm2_WR(i, PM2R_RENDER, PM2F_RENDER_RECTANGLE|
805 (x<xsrc?PM2F_INCREASE_X:0)|
806 (y<ysrc?PM2F_INCREASE_Y:0));
811 * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
813 static void pm2fb_block_op(struct pm2fb_info* i, int copy,
815 s32 x, s32 y, s32 w, s32 h,
821 pm2_WR(i, PM2R_CONFIG, PM2F_CONFIG_FB_WRITE_ENABLE|
822 PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
823 pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
825 pm2_WR(i, PM2R_FB_SOURCE_DELTA, ((ysrc-y)&0xfff)<<16|
828 pm2_WR(i, PM2R_FB_BLOCK_COLOR, color);
829 pm2_WR(i, PM2R_RECTANGLE_ORIGIN, (y<<16)|x);
830 pm2_WR(i, PM2R_RECTANGLE_SIZE, (h<<16)|w);
832 pm2_WR(i, PM2R_RENDER, PM2F_RENDER_RECTANGLE|
833 (x<xsrc?PM2F_INCREASE_X:0)|
834 (y<ysrc?PM2F_INCREASE_Y:0)|
835 (copy?0:PM2F_RENDER_FASTFILL));
839 /***************************************************************************
840 * Begin of generic initialization functions
841 ***************************************************************************/
843 static void pm2fb_reset(struct pm2fb_info* p) {
845 if (p->type == PM2_TYPE_PERMEDIA2V)
846 pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
847 pm2_WR(p, PM2R_RESET_STATUS, 0);
849 while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
851 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
852 DPRINTK("FIFO disconnect enabled\n");
853 pm2_WR(p, PM2R_FIFO_DISCON, 1);
856 if (board_table[p->board].init)
857 board_table[p->board].init(p);
859 pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)&
860 ~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
861 pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
862 pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
863 pm2_WR(p, PM2R_FIFO_CONTROL, 0);
864 pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
865 pm2_WR(p, PM2R_APERTURE_ONE, 0);
866 pm2_WR(p, PM2R_APERTURE_TWO, 0);
867 pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
868 pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0);
869 pm2_WR(p, PM2R_LB_READ_MODE, 0);
870 pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
871 pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
872 pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
873 pm2_WR(p, PM2R_WINDOW_ORIGIN, 0);
874 pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
875 pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
876 pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
877 pm2_WR(p, PM2R_FB_HARD_WRITE_MASK, ~(0L));
878 pm2_WR(p, PM2R_FB_READ_PIXEL, 0);
879 pm2_WR(p, PM2R_DITHER_MODE, 0);
880 pm2_WR(p, PM2R_AREA_STIPPLE_MODE, 0);
881 pm2_WR(p, PM2R_DEPTH_MODE, 0);
882 pm2_WR(p, PM2R_STENCIL_MODE, 0);
883 pm2_WR(p, PM2R_TEXTURE_ADDRESS_MODE, 0);
884 pm2_WR(p, PM2R_TEXTURE_READ_MODE, 0);
885 pm2_WR(p, PM2R_TEXEL_LUT_MODE, 0);
886 pm2_WR(p, PM2R_YUV_MODE, 0);
887 pm2_WR(p, PM2R_COLOR_DDA_MODE, 0);
888 pm2_WR(p, PM2R_TEXTURE_COLOR_MODE, 0);
889 pm2_WR(p, PM2R_FOG_MODE, 0);
890 pm2_WR(p, PM2R_ALPHA_BLEND_MODE, 0);
891 pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
892 pm2_WR(p, PM2R_STATISTICS_MODE, 0);
893 pm2_WR(p, PM2R_SCISSOR_MODE, 0);
895 case PM2_TYPE_PERMEDIA2:
896 pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
897 pm2_RDAC_WR(p, PM2I_RD_CURSOR_CONTROL, 0);
898 pm2_RDAC_WR(p, PM2I_RD_MISC_CONTROL, PM2F_RD_PALETTE_WIDTH_8);
900 case PM2_TYPE_PERMEDIA2V:
901 pm2v_RDAC_WR(p, PM2VI_RD_MISC_CONTROL, 1); /* 8bit */
904 pm2_RDAC_WR(p, PM2I_RD_COLOR_KEY_CONTROL, 0);
905 pm2_RDAC_WR(p, PM2I_RD_OVERLAY_KEY, 0);
906 pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
907 pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
908 pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
911 pm2_set_memclock(p, p->memclock);
914 static int __init pm2fb_conf(struct pm2fb_info* p){
916 for (p->board=0; board_table[p->board].detect &&
917 !(board_table[p->board].detect(p)); p->board++);
918 if (!board_table[p->board].detect) {
919 DPRINTK("no board found.\n");
922 DPRINTK("found board: %s\n", board_table[p->board].name);
924 p->regions.p_fb=p->regions.fb_base;
925 if (!request_mem_region(p->regions.p_fb, p->regions.fb_size,
927 printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n");
930 p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size);
932 #ifndef PM2FB_BE_APERTURE
933 p->regions.p_regs=p->regions.rg_base;
935 p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
937 if (!request_mem_region(p->regions.p_regs, PM2_REGS_SIZE, "pm2fb")) {
938 printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n");
939 UNMAP(p->regions.v_fb, p->regions.fb_size);
942 p->regions.v_regs=MMAP(p->regions.p_regs, PM2_REGS_SIZE);
944 #ifdef PM2FB_HW_CURSOR
945 p->cursor = pm2_init_cursor(p);
950 /***************************************************************************
951 * Begin of per-board initialization functions
952 ***************************************************************************/
955 * Phase5 CvisionPPC/BVisionPPC
957 #ifdef CONFIG_FB_PM2_CVPPC
958 static int cvppc_PCI_init(struct cvppc_par* p) {
959 extern u32 powerup_PCI_present;
961 if (!powerup_PCI_present) {
962 DPRINTK("no PCI bridge detected\n");
965 if (!(p->pci_config=MMAP(CVPPC_PCI_CONFIG, 256))) {
966 DPRINTK("unable to map PCI config region\n");
969 if (RD32(p->pci_config, PCI_VENDOR_ID)!=
970 ((PCI_DEVICE_ID_TI_TVP4020<<16)|PCI_VENDOR_ID_TI)) {
971 DPRINTK("bad vendorID/deviceID\n");
974 if (!(p->pci_bridge=MMAP(CSPPC_PCI_BRIDGE, 256))) {
975 DPRINTK("unable to map PCI bridge\n");
978 WR32(p->pci_bridge, CSPPC_BRIDGE_ENDIAN, CSPPCF_BRIDGE_BIG_ENDIAN);
980 if (pm2fb_options.flags & OPTF_OLD_MEM)
981 WR32(p->pci_config, PCI_CACHE_LINE_SIZE, 0xff00);
982 WR32(p->pci_config, PCI_BASE_ADDRESS_0, CVPPC_REGS_REGION);
983 WR32(p->pci_config, PCI_BASE_ADDRESS_1, CVPPC_FB_APERTURE_ONE);
984 WR32(p->pci_config, PCI_BASE_ADDRESS_2, CVPPC_FB_APERTURE_TWO);
985 WR32(p->pci_config, PCI_ROM_ADDRESS, CVPPC_ROM_ADDRESS);
987 WR32(p->pci_config, PCI_COMMAND, 0xef000000 |
994 static int __init cvppc_detect(struct pm2fb_info* p) {
996 if (!cvppc_PCI_init(&p->board_par.cvppc))
998 p->type = PM2_TYPE_PERMEDIA2;
999 p->regions.fb_base=CVPPC_FB_APERTURE_ONE;
1000 p->regions.fb_size=CVPPC_FB_SIZE;
1001 p->regions.rg_base=CVPPC_REGS_REGION;
1002 p->memclock=CVPPC_MEMCLOCK;
1006 static void cvppc_init(struct pm2fb_info* p) {
1009 pm2_WR(p, PM2R_MEM_CONTROL, 0);
1010 pm2_WR(p, PM2R_BOOT_ADDRESS, 0x30);
1012 if (pm2fb_options.flags & OPTF_OLD_MEM)
1013 pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_OLD);
1015 pm2_WR(p, PM2R_MEM_CONFIG, CVPPC_MEM_CONFIG_NEW);
1017 #endif /* CONFIG_FB_PM2_CVPPC */
1020 * Generic PCI detection routines
1022 #ifdef CONFIG_FB_PM2_PCI
1024 unsigned short vendor, device;
1027 } pm2pci_cards[] __initdata = {
1028 { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
1029 { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
1030 { PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
1034 static int __init pm2pci_detect(struct pm2fb_info* p) {
1035 struct pm2pci_par* pci=&p->board_par.pci;
1036 struct pci_dev* dev;
1040 struct pcidev_cookie *pcp;
1043 memset(pci, 0, sizeof(struct pm2pci_par));
1044 if (!pci_present()) {
1045 DPRINTK("no PCI bus found.\n");
1048 DPRINTK("scanning PCI bus for known chipsets...\n");
1050 pci_for_each_dev(dev) {
1051 for (i = 0; pm2pci_cards[i].vendor; i++)
1052 if (pm2pci_cards[i].vendor == dev->vendor &&
1053 pm2pci_cards[i].device == dev->device) {
1055 p->type = pm2pci_cards[i].type;
1056 DPRINTK("... found %s\n", pm2pci_cards[i].name);
1063 DPRINTK("no PCI board found.\n");
1066 DPRINTK("PCI board @%08lx %08lx %08lx rom %08lx\n",
1067 pci->dev->resource[0].start,
1068 pci->dev->resource[1].start,
1069 pci->dev->resource[2].start,
1070 pci->dev->resource[PCI_ROM_RESOURCE].start);
1072 p->regions.rg_base= pci->dev->resource[0].start;
1073 p->regions.fb_base= pci->dev->resource[1].start;
1074 pcp = pci->dev->sysdata;
1075 /* If the user has not asked for a particular mode, lets guess */
1076 if (pcp->prom_node && !(pm2fb_options.flags & OPTF_USER)) {
1077 char timing[256], *q, *r;
1080 prom_getstring(pcp->prom_node, "timing-numbers", timing, 256);
1081 /* FIXME: Find out what the actual pixclock is and other values as well */
1083 w = simple_strtoul(timing, &q, 0);
1085 if (q == timing) w = 0;
1087 for (i = 0; i < 3; i++) {
1088 for (r = q; *r && (*r < '0' || *r > '9'); r++);
1089 simple_strtoul(r, &q, 0);
1095 for (r = q; *r && (*r < '0' || *r > '9'); r++);
1096 h = simple_strtoul(r, &q, 0);
1099 if (w == 640 && h == 480) w = 0;
1101 for (i=0; user_mode[i].name[0] &&
1102 (w != user_mode[i].par.width ||
1103 h != user_mode[i].par.height); i++);
1104 if (user_mode[i].name[0])
1105 memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par));
1110 if (pm2fb_options.flags & OPTF_VIRTUAL) {
1111 p->regions.rg_base = __pa(pci_resource_start(pci->dev, 0));
1112 p->regions.fb_base = __pa(pci_resource_start(pci->dev, 1));
1115 p->regions.rg_base = pci_resource_start(pci->dev, 0);
1116 p->regions.fb_base = pci_resource_start(pci->dev, 1);
1119 #ifdef PM2FB_BE_APERTURE
1120 p->regions.rg_base += PM2_REGS_SIZE;
1122 if ((m=MMAP(p->regions.rg_base, PM2_REGS_SIZE))) {
1123 pci->mem_control=RD32(m, PM2R_MEM_CONTROL);
1124 pci->boot_address=RD32(m, PM2R_BOOT_ADDRESS);
1125 pci->mem_config=RD32(m, PM2R_MEM_CONFIG);
1126 switch (pci->mem_config & PM2F_MEM_CONFIG_RAM_MASK) {
1127 case PM2F_MEM_BANKS_1:
1128 p->regions.fb_size=0x200000;
1130 case PM2F_MEM_BANKS_2:
1131 p->regions.fb_size=0x400000;
1133 case PM2F_MEM_BANKS_3:
1134 p->regions.fb_size=0x600000;
1136 case PM2F_MEM_BANKS_4:
1137 p->regions.fb_size=0x800000;
1140 p->memclock=CVPPC_MEMCLOCK;
1141 UNMAP(m, PM2_REGS_SIZE);
1144 DPRINTK("MMAP() failed.\n");
1148 static void pm2pci_init(struct pm2fb_info* p) {
1149 struct pm2pci_par* pci=&p->board_par.pci;
1152 pm2_WR(p, PM2R_MEM_CONTROL, pci->mem_control);
1153 pm2_WR(p, PM2R_BOOT_ADDRESS, pci->boot_address);
1155 pm2_WR(p, PM2R_MEM_CONFIG, pci->mem_config);
1157 #endif /* CONFIG_FB_PM2_PCI */
1159 /***************************************************************************
1160 * Console hw acceleration
1161 ***************************************************************************/
1164 static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) {
1165 struct pm2fb_info* i=(struct pm2fb_info* )info;
1168 if (!i->current_par_valid)
1170 video=i->current_par.video;
1172 switch (blank_mode-1) {
1173 case VESA_NO_BLANKING: /* FIXME */
1174 video=video&~(PM2F_VIDEO_ENABLE);
1176 case VESA_HSYNC_SUSPEND:
1177 video=video&~(PM2F_HSYNC_MASK|
1180 case VESA_VSYNC_SUSPEND:
1181 video=video&~(PM2F_VSYNC_MASK|
1184 case VESA_POWERDOWN:
1185 video=video&~(PM2F_VSYNC_MASK|
1192 pm2_WR(i, PM2R_VIDEO_CONTROL, video);
1196 static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
1197 struct fb_info_gen* info) {
1198 struct pm2fb_info* i=(struct pm2fb_info* )info;
1200 if (!i->current_par_valid)
1202 i->current_par.base=to3264(var->yoffset*i->current_par.width+
1203 var->xoffset, i->current_par.depth, 1);
1205 pm2_WR(i, PM2R_SCREEN_BASE, i->current_par.base);
1209 static void pm2fb_pp_bmove(struct display* p, int sy, int sx,
1210 int dy, int dx, int height, int width) {
1212 if (fontwidthlog(p)) {
1213 sx=sx<<fontwidthlog(p);
1214 dx=dx<<fontwidthlog(p);
1215 width=width<<fontwidthlog(p);
1220 width=width*fontwidth(p);
1222 sy=sy*fontheight(p);
1223 dy=dy*fontheight(p);
1224 height=height*fontheight(p);
1225 pm2fb_pp_copy((struct pm2fb_info* )p->fb_info, sx, sy, dx,
1229 static void pm2fb_bmove(struct display* p, int sy, int sx,
1230 int dy, int dx, int height, int width) {
1232 if (fontwidthlog(p)) {
1233 sx=sx<<fontwidthlog(p);
1234 dx=dx<<fontwidthlog(p);
1235 width=width<<fontwidthlog(p);
1240 width=width*fontwidth(p);
1242 sy=sy*fontheight(p);
1243 dy=dy*fontheight(p);
1244 height=height*fontheight(p);
1245 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 1, sx, sy, dx, dy,
1249 #ifdef FBCON_HAS_CFB8
1250 static void pm2fb_clear8(struct vc_data* conp, struct display* p,
1251 int sy, int sx, int height, int width) {
1255 width=width*fontwidth(p);
1256 sy=sy*fontheight(p);
1257 height=height*fontheight(p);
1258 c=attr_bgcol_ec(p, conp);
1261 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1265 static void pm2fb_clear_margins8(struct vc_data* conp, struct display* p,
1271 c=attr_bgcol_ec(p, conp);
1274 sx=conp->vc_cols*fontwidth(p);
1275 sy=conp->vc_rows*fontheight(p);
1277 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1278 sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1279 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1280 0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1283 static struct display_switch pm2_cfb8 = {
1284 setup: fbcon_cfb8_setup,
1285 bmove: pm2fb_pp_bmove,
1287 /* Not sure why, but this works and the other does not. */
1288 /* Also, perhaps we need a separate routine to wait for the
1289 blitter to stop before doing this? */
1290 /* In addition, maybe we need to do this for 16 and 32 bit depths? */
1291 clear: fbcon_cfb8_clear,
1293 clear: pm2fb_clear8,
1295 putc: fbcon_cfb8_putc,
1296 putcs: fbcon_cfb8_putcs,
1297 revc: fbcon_cfb8_revc,
1298 cursor: pm2fb_cursor,
1299 set_font: pm2fb_set_font,
1300 clear_margins: pm2fb_clear_margins8,
1301 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
1302 #endif /* FBCON_HAS_CFB8 */
1304 #ifdef FBCON_HAS_CFB16
1305 static void pm2fb_clear16(struct vc_data* conp, struct display* p,
1306 int sy, int sx, int height, int width) {
1310 width=width*fontwidth(p);
1311 sy=sy*fontheight(p);
1312 height=height*fontheight(p);
1313 c=((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1315 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1319 static void pm2fb_clear_margins16(struct vc_data* conp, struct display* p,
1325 c = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1327 sx=conp->vc_cols*fontwidth(p);
1328 sy=conp->vc_rows*fontheight(p);
1330 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1331 sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1332 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1333 0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1336 static struct display_switch pm2_cfb16 = {
1337 setup: fbcon_cfb16_setup,
1338 bmove: pm2fb_pp_bmove,
1339 clear: pm2fb_clear16,
1340 putc: fbcon_cfb16_putc,
1341 putcs: fbcon_cfb16_putcs,
1342 revc: fbcon_cfb16_revc,
1343 cursor: pm2fb_cursor,
1344 set_font: pm2fb_set_font,
1345 clear_margins: pm2fb_clear_margins16,
1346 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1348 #endif /* FBCON_HAS_CFB16 */
1350 #ifdef FBCON_HAS_CFB24
1352 * fast fill for 24bpp works only when red==green==blue
1354 static void pm2fb_clear24(struct vc_data* conp, struct display* p,
1355 int sy, int sx, int height, int width) {
1356 struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
1359 c=attr_bgcol_ec(p, conp);
1360 if ( i->palette[c].red==i->palette[c].green &&
1361 i->palette[c].green==i->palette[c].blue) {
1362 c=((u32 *)p->dispsw_data)[c];
1365 width=width*fontwidth(p);
1366 sy=sy*fontheight(p);
1367 height=height*fontheight(p);
1368 pm2fb_block_op(i, 0, 0, 0, sx, sy, width, height, c);
1371 fbcon_cfb24_clear(conp, p, sy, sx, height, width);
1375 static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p,
1377 struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
1382 c=attr_bgcol_ec(p, conp);
1383 if ( i->palette[c].red==i->palette[c].green &&
1384 i->palette[c].green==i->palette[c].blue) {
1385 c=((u32 *)p->dispsw_data)[c];
1387 sx=conp->vc_cols*fontwidth(p);
1388 sy=conp->vc_rows*fontheight(p);
1390 pm2fb_block_op(i, 0, 0, 0, sx, 0, (p->var.xres-sx),
1391 p->var.yres_virtual, c);
1392 pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy,
1393 sx, p->var.yres-sy, c);
1396 fbcon_cfb24_clear_margins(conp, p, bottom_only);
1400 static struct display_switch pm2_cfb24 = {
1401 setup: fbcon_cfb24_setup,
1403 clear: pm2fb_clear24,
1404 putc: fbcon_cfb24_putc,
1405 putcs: fbcon_cfb24_putcs,
1406 revc: fbcon_cfb24_revc,
1407 cursor: pm2fb_cursor,
1408 set_font: pm2fb_set_font,
1409 clear_margins: pm2fb_clear_margins24,
1410 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1412 #endif /* FBCON_HAS_CFB24 */
1414 #ifdef FBCON_HAS_CFB32
1415 static void pm2fb_clear32(struct vc_data* conp, struct display* p,
1416 int sy, int sx, int height, int width) {
1420 width=width*fontwidth(p);
1421 sy=sy*fontheight(p);
1422 height=height*fontheight(p);
1423 c=((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1424 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0, sx, sy,
1428 static void pm2fb_clear_margins32(struct vc_data* conp, struct display* p,
1434 c = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
1435 sx=conp->vc_cols*fontwidth(p);
1436 sy=conp->vc_rows*fontheight(p);
1438 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1439 sx, 0, (p->var.xres-sx), p->var.yres_virtual, c);
1440 pm2fb_block_op((struct pm2fb_info* )p->fb_info, 0, 0, 0,
1441 0, p->var.yoffset+sy, sx, p->var.yres-sy, c);
1444 static struct display_switch pm2_cfb32 = {
1445 setup: fbcon_cfb32_setup,
1447 clear: pm2fb_clear32,
1448 putc: fbcon_cfb32_putc,
1449 putcs: fbcon_cfb32_putcs,
1450 revc: fbcon_cfb32_revc,
1451 cursor: pm2fb_cursor,
1452 set_font: pm2fb_set_font,
1453 clear_margins: pm2fb_clear_margins32,
1454 fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1456 #endif /* FBCON_HAS_CFB32 */
1458 /***************************************************************************
1459 * Framebuffer functions
1460 ***************************************************************************/
1462 static void pm2fb_detect(void) {}
1464 static int pm2fb_encode_fix(struct fb_fix_screeninfo* fix,
1465 const void* par, struct fb_info_gen* info) {
1466 struct pm2fb_info* i=(struct pm2fb_info* )info;
1467 struct pm2fb_par* p=(struct pm2fb_par* )par;
1469 strcpy(fix->id, permedia2_name);
1470 fix->smem_start=i->regions.p_fb;
1471 fix->smem_len=i->regions.fb_size;
1472 fix->mmio_start=i->regions.p_regs;
1473 fix->mmio_len=PM2_REGS_SIZE;
1474 fix->accel=FB_ACCEL_3DLABS_PERMEDIA2;
1475 fix->type=FB_TYPE_PACKED_PIXELS;
1476 fix->visual=p->depth==8?FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR;
1477 if (i->current_par_valid)
1478 fix->line_length=i->current_par.width*(i->current_par.depth/8);
1481 fix->xpanstep=p->depth==24?8:64/p->depth;
1487 #ifdef PM2FB_MASTER_DEBUG
1488 static void pm2fb_display_var(const struct fb_var_screeninfo* var) {
1491 "- struct fb_var_screeninfo ---------------------------------------------------\n");
1493 "resolution: %ux%ux%u (virtual %ux%u+%u+%u)\n",
1494 var->xres, var->yres, var->bits_per_pixel,
1495 var->xres_virtual, var->yres_virtual,
1496 var->xoffset, var->yoffset);
1499 "R(%u,%u,%u), G(%u,%u,%u), B(%u,%u,%u), T(%u,%u,%u)\n",
1500 var->grayscale?'G':'C', var->nonstd?'N':'S',
1501 var->red.offset, var->red.length, var->red.msb_right,
1502 var->green.offset, var->green.length, var->green.msb_right,
1503 var->blue.offset, var->blue.length, var->blue.msb_right,
1504 var->transp.offset, var->transp.length,
1505 var->transp.msb_right);
1507 "timings: %ups (%u,%u)-(%u,%u)+%u+%u\n",
1509 var->left_margin, var->upper_margin, var->right_margin,
1510 var->lower_margin, var->hsync_len, var->vsync_len);
1512 "activate %08x accel_flags %08x sync %08x vmode %08x\n",
1513 var->activate, var->accel_flags, var->sync, var->vmode);
1515 "------------------------------------------------------------------------------\n");
1518 #define pm2fb_decode_var pm2fb_wrapped_decode_var
1521 static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
1522 void* par, struct fb_info_gen* info) {
1523 struct pm2fb_info* i=(struct pm2fb_info* )info;
1528 memset(&p, 0, sizeof(struct pm2fb_par));
1529 p.width=(var->xres_virtual+7)&~7;
1530 p.height=var->yres_virtual;
1531 p.depth=(var->bits_per_pixel+7)&~7;
1532 p.depth=p.depth>32?32:p.depth;
1533 data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V;
1534 xres=(var->xres+31)&~31;
1535 if (p.width<xres+var->xoffset)
1536 p.width=xres+var->xoffset;
1537 if (p.height<var->yres+var->yoffset)
1538 p.height=var->yres+var->yoffset;
1539 if (!partprod(xres)) {
1540 DPRINTK("width not supported: %u\n", xres);
1544 DPRINTK("virtual width not supported: %u\n", p.width);
1547 if (var->yres<200) {
1548 DPRINTK("height not supported: %u\n",
1552 if (p.height<200 || p.height>2047) {
1553 DPRINTK("virtual height not supported: %u\n", p.height);
1557 DPRINTK("depth not supported: %u\n", p.depth);
1560 if (p.width*p.height*p.depth/8>i->regions.fb_size) {
1561 DPRINTK("no memory for screen (%ux%ux%u)\n",
1562 p.width, p.height, p.depth);
1565 p.pixclock=PICOS2KHZ(var->pixclock);
1566 if (p.pixclock>PM2_MAX_PIXCLOCK) {
1567 DPRINTK("pixclock too high (%uKHz)\n", p.pixclock);
1570 p.hsstart=to3264(var->right_margin, p.depth, data64);
1571 p.hsend=p.hsstart+to3264(var->hsync_len, p.depth, data64);
1572 p.hbend=p.hsend+to3264(var->left_margin, p.depth, data64);
1573 p.htotal=to3264(xres, p.depth, data64)+p.hbend-1;
1574 p.vsstart=var->lower_margin?var->lower_margin-1:0; /* FIXME! */
1575 p.vsend=var->lower_margin+var->vsync_len-1;
1576 p.vbend=var->lower_margin+var->vsync_len+var->upper_margin;
1577 p.vtotal=var->yres+p.vbend-1;
1578 p.stride=to3264(p.width, p.depth, 1);
1579 p.base=to3264(var->yoffset*xres+var->xoffset, p.depth, 1);
1581 p.video|=PM2F_DATA_64_ENABLE;
1582 if (var->sync & FB_SYNC_HOR_HIGH_ACT)
1583 p.video|=PM2F_HSYNC_ACT_HIGH;
1585 p.video|=PM2F_HSYNC_ACT_LOW;
1586 if (var->sync & FB_SYNC_VERT_HIGH_ACT)
1587 p.video|=PM2F_VSYNC_ACT_HIGH;
1589 p.video|=PM2F_VSYNC_ACT_LOW;
1590 if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
1591 DPRINTK("interlaced not supported\n");
1594 if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_DOUBLE)
1595 p.video|=PM2F_LINE_DOUBLE;
1596 if (var->activate==FB_ACTIVATE_NOW)
1597 p.video|=PM2F_VIDEO_ENABLE;
1598 *((struct pm2fb_par* )par)=p;
1602 #ifdef PM2FB_MASTER_DEBUG
1603 #undef pm2fb_decode_var
1605 static int pm2fb_decode_var(const struct fb_var_screeninfo* var,
1606 void* par, struct fb_info_gen* info) {
1609 result=pm2fb_wrapped_decode_var(var, par, info);
1610 pm2fb_display_var(var);
1615 static int pm2fb_encode_var(struct fb_var_screeninfo* var,
1616 const void* par, struct fb_info_gen* info) {
1617 struct pm2fb_par* p=(struct pm2fb_par* )par;
1618 struct fb_var_screeninfo v;
1621 memset(&v, 0, sizeof(struct fb_var_screeninfo));
1622 v.xres_virtual=p->width;
1623 v.yres_virtual=p->height;
1624 v.xres=(p->htotal+1)-p->hbend;
1625 v.yres=(p->vtotal+1)-p->vbend;
1626 v.right_margin=p->hsstart;
1627 v.hsync_len=p->hsend-p->hsstart;
1628 v.left_margin=p->hbend-p->hsend;
1629 v.lower_margin=p->vsstart+1;
1630 v.vsync_len=p->vsend-v.lower_margin+1;
1631 v.upper_margin=p->vbend-v.lower_margin-v.vsync_len;
1632 v.bits_per_pixel=p->depth;
1633 if (p->video & PM2F_DATA_64_ENABLE) {
1635 v.right_margin=v.right_margin<<1;
1636 v.hsync_len=v.hsync_len<<1;
1637 v.left_margin=v.left_margin<<1;
1641 v.red.length=v.green.length=v.blue.length=8;
1643 v.right_margin=v.right_margin<<2;
1644 v.hsync_len=v.hsync_len<<2;
1645 v.left_margin=v.left_margin<<2;
1654 v.right_margin=v.right_margin<<1;
1655 v.hsync_len=v.hsync_len<<1;
1656 v.left_margin=v.left_margin<<1;
1662 v.red.length=v.green.length=v.blue.length=
1668 v.red.length=v.green.length=v.blue.length=8;
1669 v.xres=(v.xres<<2)/3;
1670 v.right_margin=(v.right_margin<<2)/3;
1671 v.hsync_len=(v.hsync_len<<2)/3;
1672 v.left_margin=(v.left_margin<<2)/3;
1675 base=from3264(p->base, p->depth, 1);
1676 v.xoffset=base%v.xres;
1677 v.yoffset=base/v.xres;
1678 v.height=v.width=-1;
1679 v.pixclock=KHZ2PICOS(p->pixclock);
1680 if ((p->video & PM2F_HSYNC_MASK)==PM2F_HSYNC_ACT_HIGH)
1681 v.sync|=FB_SYNC_HOR_HIGH_ACT;
1682 if ((p->video & PM2F_VSYNC_MASK)==PM2F_VSYNC_ACT_HIGH)
1683 v.sync|=FB_SYNC_VERT_HIGH_ACT;
1684 if (p->video & PM2F_LINE_DOUBLE)
1685 v.vmode=FB_VMODE_DOUBLE;
1690 static void set_user_mode(struct pm2fb_info* i) {
1692 if (pm2fb_options.flags & OPTF_YPAN) {
1693 int h = i->current_par.height;
1694 i->current_par.height=i->regions.fb_size/
1695 (i->current_par.width*i->current_par.depth/8);
1696 i->current_par.height=MIN(i->current_par.height,2047);
1697 i->current_par.height=MAX(i->current_par.height,h);
1701 static void pm2fb_get_par(void* par, struct fb_info_gen* info) {
1702 struct pm2fb_info* i=(struct pm2fb_info* )info;
1704 if (!i->current_par_valid) {
1707 set_screen(i, &i->current_par);
1708 i->current_par_valid=1;
1710 *((struct pm2fb_par* )par)=i->current_par;
1713 static void pm2fb_set_par(const void* par, struct fb_info_gen* info) {
1714 struct pm2fb_info* i=(struct pm2fb_info* )info;
1715 struct pm2fb_par* p;
1717 p=(struct pm2fb_par* )par;
1718 if (i->current_par_valid) {
1719 i->current_par.base=p->base;
1720 if (!memcmp(p, &i->current_par, sizeof(struct pm2fb_par))) {
1722 pm2_WR(i, PM2R_SCREEN_BASE, p->base);
1728 i->current_par_valid=1;
1729 #ifdef PM2FB_HW_CURSOR
1731 pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map);
1732 pm2v_set_cursor_shape(i);
1737 static int pm2fb_getcolreg(unsigned regno,
1738 unsigned* red, unsigned* green, unsigned* blue,
1739 unsigned* transp, struct fb_info* info) {
1740 struct pm2fb_info* i=(struct pm2fb_info* )info;
1743 *red=i->palette[regno].red<<8|i->palette[regno].red;
1744 *green=i->palette[regno].green<<8|i->palette[regno].green;
1745 *blue=i->palette[regno].blue<<8|i->palette[regno].blue;
1746 *transp=i->palette[regno].transp<<8|i->palette[regno].transp;
1751 static int pm2fb_setcolreg(unsigned regno,
1752 unsigned red, unsigned green, unsigned blue,
1753 unsigned transp, struct fb_info* info) {
1754 struct pm2fb_info* i=(struct pm2fb_info* )info;
1757 switch (i->current_par.depth) {
1758 #ifdef FBCON_HAS_CFB8
1762 #ifdef FBCON_HAS_CFB16
1764 i->cmap.cmap16[regno]=
1765 ((u32 )red & 0xf800) |
1766 (((u32 )green & 0xfc00)>>5) |
1767 (((u32 )blue & 0xf800)>>11);
1770 #ifdef FBCON_HAS_CFB24
1772 i->cmap.cmap24[regno]=
1773 (((u32 )blue & 0xff00) << 8) |
1774 ((u32 )green & 0xff00) |
1775 (((u32 )red & 0xff00) >> 8);
1778 #ifdef FBCON_HAS_CFB32
1780 i->cmap.cmap32[regno]=
1781 (((u32 )transp & 0xff00) << 16) |
1782 (((u32 )red & 0xff00) << 8) |
1783 (((u32 )green & 0xff00)) |
1784 (((u32 )blue & 0xff00) >> 8);
1788 DPRINTK("bad depth %u\n",
1789 i->current_par.depth);
1794 i->palette[regno].red=red >> 8;
1795 i->palette[regno].green=green >> 8;
1796 i->palette[regno].blue=blue >> 8;
1797 i->palette[regno].transp=transp >> 8;
1798 if (i->current_par.depth==8)
1799 set_color(i, regno, red>>8, green>>8, blue>>8);
1804 static void pm2fb_set_disp(const void* par, struct display* disp,
1805 struct fb_info_gen* info) {
1806 struct pm2fb_info* i=(struct pm2fb_info* )info;
1807 unsigned long flags;
1808 unsigned long depth;
1812 disp->screen_base = i->regions.v_fb;
1813 switch (depth=((struct pm2fb_par* )par)->depth) {
1814 #ifdef FBCON_HAS_CFB8
1816 disp->dispsw=&pm2_cfb8;
1819 #ifdef FBCON_HAS_CFB16
1821 disp->dispsw=&pm2_cfb16;
1822 disp->dispsw_data=i->cmap.cmap16;
1825 #ifdef FBCON_HAS_CFB24
1827 disp->dispsw=&pm2_cfb24;
1828 disp->dispsw_data=i->cmap.cmap24;
1831 #ifdef FBCON_HAS_CFB32
1833 disp->dispsw=&pm2_cfb32;
1834 disp->dispsw_data=i->cmap.cmap32;
1838 disp->dispsw=&fbcon_dummy;
1841 restore_flags(flags);
1844 #ifdef PM2FB_HW_CURSOR
1845 /***************************************************************************
1846 * Hardware cursor support
1847 ***************************************************************************/
1849 static u8 cursor_bits_lookup[16] = {
1850 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
1851 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
1854 static u8 cursor_mask_lookup[16] = {
1855 0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
1856 0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa
1859 static void pm2v_set_cursor_color(struct pm2fb_info *fb, u8 *red, u8 *green, u8 *blue)
1861 struct pm2_cursor *c = fb->cursor;
1864 for (i = 0; i < 2; i++) {
1865 c->color[3*i] = red[i];
1866 c->color[3*i+1] = green[i];
1867 c->color[3*i+2] = blue[i];
1871 pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PALETTE >> 8);
1872 for (i = 0; i < 6; i++)
1873 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PALETTE+i, c->color[i]);
1874 pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
1877 static void pm2v_set_cursor_shape(struct pm2fb_info *fb)
1879 struct pm2_cursor *c = fb->cursor;
1884 pm2_WR(fb, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CURSOR_PATTERN >> 8);
1885 for (y = 0, i = 0; y < c->size.y; y++) {
1887 for (x = 0; x < c->size.x >> 3; x++) {
1890 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i,
1891 cursor_mask_lookup[m >> 4] |
1892 cursor_bits_lookup[(b & m) >> 4]);
1893 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1,
1894 cursor_mask_lookup[m & 0x0f] |
1895 cursor_bits_lookup[(b & m) & 0x0f]);
1898 for ( ; x < 8; x++) {
1899 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
1900 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
1904 for (; y < 64; y++) {
1906 for (x = 0; x < 8; x++) {
1907 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i, 0);
1908 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_PATTERN + i + 1, 0);
1913 pm2_WR(fb, PM2VR_RD_INDEX_HIGH, 0);
1916 static void pm2v_set_cursor(struct pm2fb_info *fb, int on)
1918 struct pm2_cursor *c = fb->cursor;
1923 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_LOW, x & 0xff);
1924 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HIGH, (x >> 8) & 0x0f);
1925 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_LOW, c->pos.y & 0xff);
1926 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HIGH, (c->pos.y >> 8) & 0x0f);
1927 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_X_HOT, c->hot.x & 0x3f);
1928 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_Y_HOT, c->hot.y & 0x3f);
1929 pm2v_RDAC_WR(fb, PM2VI_RD_CURSOR_MODE, 0x11);
1932 static void pm2_cursor_timer_handler(unsigned long dev_addr)
1934 struct pm2fb_info *fb = (struct pm2fb_info *)dev_addr;
1936 if (!fb->cursor->enable)
1939 if (fb->cursor->vbl_cnt && --fb->cursor->vbl_cnt == 0) {
1940 fb->cursor->on ^= 1;
1941 pm2v_set_cursor(fb, fb->cursor->on);
1942 fb->cursor->vbl_cnt = fb->cursor->blink_rate;
1946 fb->cursor->timer->expires = jiffies + (HZ / 50);
1947 add_timer(fb->cursor->timer);
1950 static void pm2fb_cursor(struct display *p, int mode, int x, int y)
1952 struct pm2fb_info *fb = (struct pm2fb_info *)p->fb_info;
1953 struct pm2_cursor *c = fb->cursor;
1959 if (c->pos.x == x && c->pos.y == y && (mode == CM_ERASE) == !c->enable)
1964 pm2v_set_cursor(fb, 0);
1976 pm2v_set_cursor(fb, 1);
1978 c->vbl_cnt = CURSOR_DRAW_DELAY;
1984 static struct pm2_cursor * __init pm2_init_cursor(struct pm2fb_info *fb)
1986 struct pm2_cursor *cursor;
1988 if (fb->type != PM2_TYPE_PERMEDIA2V)
1989 return 0; /* FIXME: Support hw cursor everywhere */
1991 cursor = kmalloc(sizeof(struct pm2_cursor), GFP_ATOMIC);
1994 memset(cursor, 0, sizeof(*cursor));
1996 cursor->timer = kmalloc(sizeof(*cursor->timer), GFP_KERNEL);
1997 if (!cursor->timer) {
2001 memset(cursor->timer, 0, sizeof(*cursor->timer));
2003 cursor->blink_rate = DEFAULT_CURSOR_BLINK_RATE;
2006 init_timer(cursor->timer);
2007 cursor->timer->expires = jiffies + (HZ / 50);
2008 cursor->timer->data = (unsigned long)fb;
2009 cursor->timer->function = pm2_cursor_timer_handler;
2010 add_timer(cursor->timer);
2016 static int pm2fb_set_font(struct display *d, int width, int height)
2018 struct pm2fb_info *fb = (struct pm2fb_info *)d->fb_info;
2019 struct pm2_cursor *c = fb->cursor;
2023 if (!width || !height) {
2033 memset(c->bits, 0xff, sizeof(c->bits));
2034 memset(c->mask, 0, sizeof(c->mask));
2036 for (i = 0, j = width; j >= 0; j -= 8, i++) {
2037 c->mask[i][height-2] = (j >= 8) ? 0xff : (0xff << (8 - j));
2038 c->mask[i][height-1] = (j >= 8) ? 0xff : (0xff << (8 - j));
2041 pm2v_set_cursor_color(fb, cursor_color_map, cursor_color_map, cursor_color_map);
2042 pm2v_set_cursor_shape(fb);
2046 #endif /* PM2FB_HW_CURSOR */
2048 /***************************************************************************
2049 * Begin of public functions
2050 ***************************************************************************/
2053 static void pm2fb_cleanup(void) {
2054 struct pm2fb_info* i = &fb_info;
2056 unregister_framebuffer((struct fb_info *)i);
2059 UNMAP(i->regions.v_fb, i->regions.fb_size);
2060 release_mem_region(i->regions.p_fb, i->regions.fb_size);
2062 UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
2063 release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
2065 if (board_table[i->board].cleanup)
2066 board_table[i->board].cleanup(i);
2070 int __init pm2fb_init(void){
2073 memset(&fb_info, 0, sizeof(fb_info));
2074 memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
2075 if (!pm2fb_conf(&fb_info)) {
2079 pm2fb_reset(&fb_info);
2080 fb_info.disp.scrollmode=SCROLL_YNOMOVE;
2081 fb_info.gen.parsize=sizeof(struct pm2fb_par);
2082 fb_info.gen.fbhw=&pm2fb_hwswitch;
2083 strcpy(fb_info.gen.info.modename, permedia2_name);
2084 fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
2085 fb_info.gen.info.fbops=&pm2fb_ops;
2086 fb_info.gen.info.disp=&fb_info.disp;
2087 strcpy(fb_info.gen.info.fontname, pm2fb_options.font);
2088 fb_info.gen.info.switch_con=&fbgen_switch;
2089 fb_info.gen.info.updatevar=&fbgen_update_var;
2090 fb_info.gen.info.blank=&fbgen_blank;
2091 fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
2092 fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
2093 fbgen_set_disp(-1, &fb_info.gen);
2094 fbgen_install_cmap(0, &fb_info.gen);
2095 if (register_framebuffer(&fb_info.gen.info)<0) {
2096 printk(KERN_ERR "pm2fb: unable to register.\n");
2100 printk(KERN_INFO "fb%d: %s (%s), using %uK of video memory.\n",
2101 GET_FB_IDX(fb_info.gen.info.node),
2102 board_table[fb_info.board].name,
2104 (u32 )(fb_info.regions.fb_size>>10));
2108 static void __init pm2fb_mode_setup(char* options){
2111 for (i=0; user_mode[i].name[0] &&
2112 strcmp(options, user_mode[i].name); i++);
2113 if (user_mode[i].name[0]) {
2114 memcpy(&pm2fb_options.user_mode, &user_mode[i].par,
2115 sizeof(pm2fb_options.user_mode));
2116 pm2fb_options.flags |= OPTF_USER;
2120 static void __init pm2fb_font_setup(char* options){
2122 strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
2123 pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
2126 int __init pm2fb_setup(char* options){
2130 if ((next=strchr(options, ',')))
2132 if (!strncmp(options, "font:", 5))
2133 pm2fb_font_setup(options+5);
2134 else if (!strncmp(options, "mode:", 5))
2135 pm2fb_mode_setup(options+5);
2136 else if (!strcmp(options, "ypan"))
2137 pm2fb_options.flags |= OPTF_YPAN;
2138 else if (!strcmp(options, "oldmem"))
2139 pm2fb_options.flags |= OPTF_OLD_MEM;
2140 else if (!strcmp(options, "virtual"))
2141 pm2fb_options.flags |= OPTF_VIRTUAL;
2142 else if (!strcmp(options, "noblink"))
2149 /***************************************************************************
2150 * Begin of module functions
2151 ***************************************************************************/
2155 MODULE_LICENSE("GPL");
2157 static char *mode = NULL;
2159 MODULE_PARM(mode, "s");
2161 int __init init_module(void) {
2163 if (mode) pm2fb_mode_setup(mode);
2164 return pm2fb_init();
2167 void cleanup_module(void) {
2173 /***************************************************************************
2175 ***************************************************************************/