2 * Permedia2 framebuffer driver.
3 * Copyright (c) 1998-2000 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.213 2000/09/19 01:03:19 illo Exp $
8 * --------------------------------------------------------------------------
10 * 1999/05/09 added Jim Hague's 'var' kernel option (thanks Jim!)
11 * 2002/04/23 Jim Hague <jim.hague@acm.org>
12 * * Integrated Illo's last changes, No changelist available.
13 * Major items: acceleration support, hardware cursor code
15 * * Fixed -vsync, added lowhsync/lowvsync overrides for use with
17 * --------------------------------------------------------------------------
18 * TODO multiple boards support
19 * --------------------------------------------------------------------------
20 * This file is subject to the terms and conditions of the GNU General Public
21 * License. See the file COPYING in the main directory of this archive
25 #include <linux/config.h>
26 #include <linux/module.h>
27 #include <linux/kernel.h>
28 #include <linux/errno.h>
29 #include <linux/string.h>
31 #include <linux/tty.h>
32 #include <linux/slab.h>
33 #include <linux/vmalloc.h>
34 #include <linux/delay.h>
35 #include <linux/interrupt.h>
37 #include <linux/selection.h>
38 #include <linux/console.h>
39 #include <linux/init.h>
40 #include <linux/pci.h>
41 #include <asm/system.h>
43 #include <asm/uaccess.h>
44 #include <video/fbcon.h>
45 #include <video/fbcon-cfb8.h>
46 #include <video/fbcon-cfb16.h>
47 #include <video/fbcon-cfb24.h>
48 #include <video/fbcon-cfb32.h>
49 #include <video/pm2fb.h>
50 #include "cvisionppc.h"
56 #if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN)
57 #error "The endianness of the target host has not been defined."
60 #if defined(__BIG_ENDIAN) && !defined(__sparc__) && (!defined(CONFIG_PPC) || defined(CONFIG_FB_PM2_CVPPC))
61 #define PM2FB_BE_APERTURE
64 /* Need to debug this some more */
65 #undef PM2FB_HW_CURSOR
67 #if defined(CONFIG_FB_PM2_PCI) && !defined(CONFIG_PCI)
68 #undef CONFIG_FB_PM2_PCI
69 #warning "support for Permedia2 PCI boards with no generic PCI support!"
72 #undef PM2FB_MASTER_DEBUG
73 #ifdef PM2FB_MASTER_DEBUG
74 #define DPRINTK(a,b...) printk(KERN_DEBUG "pm2fb: %s: " a, __FUNCTION__ , ## b)
76 #define DPRINTK(a,b...)
79 #define PICOS2KHZ(a) (1000000000UL/(a))
80 #define KHZ2PICOS(a) (1000000000UL/(a))
83 * The _DEFINITIVE_ memory mapping/unmapping functions.
84 * This is due to the fact that they're changing soooo often...
86 #define MMAP(a,b) ioremap((unsigned long )(a), b)
87 #define UNMAP(a,b) iounmap(a)
90 * The _DEFINITIVE_ memory i/o barrier functions.
91 * This is due to the fact that they're changing soooo often...
104 #define MIN(a,b) ((a)<(b)?(a):(b))
108 #define MAX(a,b) ((a)>(b)?(a):(b))
111 #define VIDEO_MASK 0x00011e7f /* r/w values for VIDEO_CONTROL */
113 #define PM2FF_ACCEL (1L<<0)
116 u32 pixclock
; /* pixclock in KHz */
117 u32 width
; /* width of virtual screen */
118 u32 height
; /* height of virtual screen */
119 u32 hsstart
; /* horiz. sync start */
120 u32 hsend
; /* horiz. sync end */
121 u32 hbend
; /* horiz. blank end (also gate end) */
122 u32 htotal
; /* total width (w/ sync & blank) */
123 u32 vsstart
; /* vert. sync start */
124 u32 vsend
; /* vert. sync end */
125 u32 vbend
; /* vert. blank end */
126 u32 vtotal
; /* total height (w/ sync & blank) */
127 u32 stride
; /* screen stride */
128 u32 base
; /* screen base (xoffset+yoffset) */
129 u32 depth
; /* screen depth (8, 16, 24 or 32) */
130 u32 video
; /* video control (hsync,vsync) */
131 u32 flags
; /* internal flags (PM2FF_xxxx) */
134 #define OPTF_OLD_MEM (1L<<0)
135 #define OPTF_YPAN (1L<<1)
136 #define OPTF_VIRTUAL (1L<<2)
137 #define OPTF_USER (1L<<3)
138 #define OPTF_USER_VAR (1L<<4)
139 #define OPTF_LOW_HSYNC (1L<<5)
140 #define OPTF_LOW_VSYNC (1L<<6)
145 struct pm2fb_par user_mode
;
148 /* For some reason Raptor is not happy with the low-end mode */
149 {"\0", 0L, {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}};
151 {"\0", 0L, {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}};
154 static char curblink __initdata
= 1;
156 static struct fb_var_screeninfo user_var __initdata
={0,};
158 #define DEFAULT_USER_MODE 0
160 static const struct {
162 struct pm2fb_par par
;
163 } user_mode
[] __initdata
= {
165 {25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121,PM2FF_ACCEL
}},
167 {31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121,PM2FF_ACCEL
}},
169 {31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121,PM2FF_ACCEL
}},
171 {39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121,PM2FF_ACCEL
}},
173 {44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121,PM2FF_ACCEL
}},
175 {35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41,PM2FF_ACCEL
}},
177 {40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41,PM2FF_ACCEL
}},
179 {44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105,PM2FF_ACCEL
}},
181 {50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41,PM2FF_ACCEL
}},
183 {49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41,PM2FF_ACCEL
}},
185 {56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41,PM2FF_ACCEL
}},
187 {67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41,PM2FF_ACCEL
}},
189 {64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121,PM2FF_ACCEL
}},
191 {74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121,PM2FF_ACCEL
}},
193 {74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121,PM2FF_ACCEL
}},
195 {78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41,PM2FF_ACCEL
}},
197 {100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121,PM2FF_ACCEL
}},
199 {109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121,PM2FF_ACCEL
}},
201 {120336,1024,768,12,48,120,375,3,7,32,799,128,0,8,41,PM2FF_ACCEL
}},
203 {80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41,PM2FF_ACCEL
}},
205 {100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41,PM2FF_ACCEL
}},
207 {109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41,PM2FF_ACCEL
}},
209 {109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41,PM2FF_ACCEL
}},
211 {92940,1152,900,16,80,176,751,1,5,37,936,288,0,16,121,PM2FF_ACCEL
}},
213 {107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41,PM2FF_ACCEL
}},
215 {125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41,PM2FF_ACCEL
}},
217 {134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41,PM2FF_ACCEL
}},
219 {134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41,PM2FF_ACCEL
}},
221 {155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121,PM2FF_ACCEL
}},
223 {171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121,PM2FF_ACCEL
}},
225 {197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121,PM2FF_ACCEL
}},
229 #ifdef CONFIG_FB_PM2_PCI
238 #define DEFAULT_CURSOR_BLINK_RATE (20)
239 #define CURSOR_DRAW_DELAY (2)
252 struct timer_list
*timer
;
255 static const char permedia2_name
[16]="Permedia2";
257 static struct pm2fb_info
{
258 struct fb_info_gen gen
;
259 int board
; /* Permedia2 board index (see
260 board_table[] below) */
261 pm2type_t type
; /* Permedia2 board type */
263 unsigned long fb_base
; /* physical framebuffer memory base */
264 u32 fb_size
; /* framebuffer memory size */
265 unsigned long rg_base
; /* physical register memory base */
266 unsigned long p_fb
; /* physical address of frame buffer */
267 unsigned char* v_fb
; /* virtual address of frame buffer */
268 unsigned long p_regs
; /* physical address of registers
269 region, must be rg_base or
270 rg_base+PM2_REGS_SIZE depending on
271 the host endianness */
272 unsigned char* v_regs
; /* virtual address of p_regs */
274 union { /* here, the per-board par structs */
275 #ifdef CONFIG_FB_PM2_CVPPC
276 struct cvppc_par cvppc
; /* CVisionPPC data */
278 #ifdef CONFIG_FB_PM2_PCI
279 struct pm2pci_par pci
; /* Permedia2 PCI boards data */
282 struct pm2fb_par current_par
; /* displayed screen */
283 int current_par_valid
;
285 u32 memclock
; /* memclock (set by the per-board
295 #ifdef FBCON_HAS_CFB16
298 #ifdef FBCON_HAS_CFB24
301 #ifdef FBCON_HAS_CFB32
305 struct pm2_cursor
*cursor
;
308 #ifdef CONFIG_FB_PM2_CVPPC
309 static int cvppc_detect(struct pm2fb_info
*);
310 static void cvppc_init(struct pm2fb_info
*);
313 #ifdef CONFIG_FB_PM2_PCI
314 static int pm2pci_detect(struct pm2fb_info
*);
315 static void pm2pci_init(struct pm2fb_info
*);
318 #ifdef PM2FB_HW_CURSOR
319 static void pm2fb_cursor(struct display
*p
, int mode
, int x
, int y
);
320 static int pm2fb_set_font(struct display
*d
, int width
, int height
);
321 static struct pm2_cursor
*pm2_init_cursor(struct pm2fb_info
*fb
);
322 static void pm2v_set_cursor_color(struct pm2fb_info
*fb
, u8
*red
, u8
*green
, u8
*blue
);
323 static void pm2v_set_cursor_shape(struct pm2fb_info
*fb
);
324 static u8 cursor_color_map
[2] = { 0, 0xff };
326 #define pm2fb_cursor NULL
327 #define pm2fb_set_font NULL
331 * Table of the supported Permedia2 based boards.
332 * Three hooks are defined for each board:
333 * detect(): should return 1 if the related board has been detected, 0
334 * otherwise. It should also fill the fields 'regions.fb_base',
335 * 'regions.fb_size', 'regions.rg_base' and 'memclock' in the
336 * passed pm2fb_info structure.
337 * init(): called immediately after the reset of the Permedia2 chip.
338 * It should reset the memory controller if needed (the MClk
339 * is set shortly afterwards by the caller).
340 * cleanup(): called after the driver has been unregistered.
342 * the init and cleanup pointers can be NULL.
344 static const struct {
345 int (*detect
)(struct pm2fb_info
*);
346 void (*init
)(struct pm2fb_info
*);
347 void (*cleanup
)(struct pm2fb_info
*);
350 #ifdef CONFIG_FB_PM2_PCI
351 { pm2pci_detect
, pm2pci_init
, NULL
, "Permedia2 PCI board" },
353 #ifdef CONFIG_FB_PM2_CVPPC
354 { cvppc_detect
, cvppc_init
, NULL
, "CVisionPPC/BVisionPPC" },
360 * partial products for the supported horizontal resolutions.
362 #define PACKPP(p0,p1,p2) (((p2)<<6)|((p1)<<3)|(p0))
363 static const struct {
367 { 32, PACKPP(1, 0, 0) }, { 64, PACKPP(1, 1, 0) },
368 { 96, PACKPP(1, 1, 1) }, { 128, PACKPP(2, 1, 1) },
369 { 160, PACKPP(2, 2, 1) }, { 192, PACKPP(2, 2, 2) },
370 { 224, PACKPP(3, 2, 1) }, { 256, PACKPP(3, 2, 2) },
371 { 288, PACKPP(3, 3, 1) }, { 320, PACKPP(3, 3, 2) },
372 { 384, PACKPP(3, 3, 3) }, { 416, PACKPP(4, 3, 1) },
373 { 448, PACKPP(4, 3, 2) }, { 512, PACKPP(4, 3, 3) },
374 { 544, PACKPP(4, 4, 1) }, { 576, PACKPP(4, 4, 2) },
375 { 640, PACKPP(4, 4, 3) }, { 768, PACKPP(4, 4, 4) },
376 { 800, PACKPP(5, 4, 1) }, { 832, PACKPP(5, 4, 2) },
377 { 896, PACKPP(5, 4, 3) }, { 1024, PACKPP(5, 4, 4) },
378 { 1056, PACKPP(5, 5, 1) }, { 1088, PACKPP(5, 5, 2) },
379 { 1152, PACKPP(5, 5, 3) }, { 1280, PACKPP(5, 5, 4) },
380 { 1536, PACKPP(5, 5, 5) }, { 1568, PACKPP(6, 5, 1) },
381 { 1600, PACKPP(6, 5, 2) }, { 1664, PACKPP(6, 5, 3) },
382 { 1792, PACKPP(6, 5, 4) }, { 2048, PACKPP(6, 5, 5) },
385 static void pm2fb_detect(void);
386 static int pm2fb_encode_fix(struct fb_fix_screeninfo
* fix
,
387 const void* par
, struct fb_info_gen
* info
);
388 static int pm2fb_decode_var(const struct fb_var_screeninfo
* var
,
389 void* par
, struct fb_info_gen
* info
);
390 static int pm2fb_encode_var(struct fb_var_screeninfo
* var
,
391 const void* par
, struct fb_info_gen
* info
);
392 static void pm2fb_get_par(void* par
, struct fb_info_gen
* info
);
393 static void pm2fb_set_par(const void* par
, struct fb_info_gen
* info
);
394 static int pm2fb_getcolreg(unsigned regno
,
395 unsigned* red
, unsigned* green
, unsigned* blue
,
396 unsigned* transp
, struct fb_info
* info
);
397 static int pm2fb_blank(int blank_mode
, struct fb_info_gen
* info
);
398 static int pm2fb_pan_display(const struct fb_var_screeninfo
* var
,
399 struct fb_info_gen
* info
);
400 static void pm2fb_set_disp(const void* par
, struct display
* disp
,
401 struct fb_info_gen
* info
);
403 static struct fbgen_hwswitch pm2fb_hwswitch
={
404 pm2fb_detect
, pm2fb_encode_fix
, pm2fb_decode_var
,
405 pm2fb_encode_var
, pm2fb_get_par
, pm2fb_set_par
,
406 pm2fb_getcolreg
, pm2fb_pan_display
,
407 pm2fb_blank
, pm2fb_set_disp
411 static int pm2fb_setcolreg(unsigned regno
,
412 unsigned red
, unsigned green
, unsigned blue
,
413 unsigned transp
, struct fb_info
* info
);
415 static struct fb_ops pm2fb_ops
={
416 .owner
= THIS_MODULE
,
417 .fb_get_fix
= fbgen_get_fix
,
418 .fb_get_var
= fbgen_get_var
,
419 .fb_set_var
= fbgen_set_var
,
420 .fb_get_cmap
= fbgen_get_cmap
,
421 .fb_set_cmap
= fbgen_set_cmap
,
422 .fb_pan_display
=fbgen_pan_display
,
423 .fb_setcolreg
= pm2fb_setcolreg
,
424 .fb_blank
= fbgen_blank
,
427 /***************************************************************************
428 * Begin of Permedia2 specific functions
429 ***************************************************************************/
431 inline static u32
RD32(unsigned char* base
, s32 off
) {
433 return fb_readl(base
+off
);
436 inline static void WR32(unsigned char* base
, s32 off
, u32 v
) {
438 fb_writel(v
, base
+off
);
441 inline static u32
pm2_RD(struct pm2fb_info
* p
, s32 off
) {
443 return RD32(p
->regions
.v_regs
, off
);
446 inline static void pm2_WR(struct pm2fb_info
* p
, s32 off
, u32 v
) {
448 WR32(p
->regions
.v_regs
, off
, v
);
451 inline static u32
pm2_RDAC_RD(struct pm2fb_info
* p
, s32 idx
) {
453 int index
= PM2R_RD_INDEXED_DATA
;
455 case PM2_TYPE_PERMEDIA2
:
456 pm2_WR(p
, PM2R_RD_PALETTE_WRITE_ADDRESS
, idx
);
458 case PM2_TYPE_PERMEDIA2V
:
459 pm2_WR(p
, PM2VR_RD_INDEX_LOW
, idx
& 0xff);
460 index
= PM2VR_RD_INDEXED_DATA
;
464 return pm2_RD(p
, index
);
467 inline static void pm2_RDAC_WR(struct pm2fb_info
* p
, s32 idx
,
470 int index
= PM2R_RD_INDEXED_DATA
;
472 case PM2_TYPE_PERMEDIA2
:
473 pm2_WR(p
, PM2R_RD_PALETTE_WRITE_ADDRESS
, idx
);
475 case PM2_TYPE_PERMEDIA2V
:
476 pm2_WR(p
, PM2VR_RD_INDEX_LOW
, idx
& 0xff);
477 index
= PM2VR_RD_INDEXED_DATA
;
484 inline static u32
pm2v_RDAC_RD(struct pm2fb_info
* p
, s32 idx
) {
486 pm2_WR(p
, PM2VR_RD_INDEX_LOW
, idx
& 0xff);
488 return pm2_RD(p
, PM2VR_RD_INDEXED_DATA
);
491 inline static void pm2v_RDAC_WR(struct pm2fb_info
* p
, s32 idx
,
494 pm2_WR(p
, PM2VR_RD_INDEX_LOW
, idx
& 0xff);
496 pm2_WR(p
, PM2VR_RD_INDEXED_DATA
, v
);
499 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
500 #define WAIT_FIFO(p,a)
502 inline static void WAIT_FIFO(struct pm2fb_info
* p
, u32 a
) {
504 while(pm2_RD(p
, PM2R_IN_FIFO_SPACE
)<a
);
509 static u32
partprod(u32 xres
) {
512 for (i
=0; pp_table
[i
].width
&& pp_table
[i
].width
!=xres
; i
++);
513 if (!pp_table
[i
].width
)
514 DPRINTK("invalid width %u\n", xres
);
515 return pp_table
[i
].pp
;
518 static u32
to3264(u32 timing
, int bpp
, int is64
) {
522 timing
=timing
>>(2+is64
);
525 timing
=timing
>>(1+is64
);
528 timing
=(timing
*3)>>(2+is64
);
538 static u32
from3264(u32 timing
, int bpp
, int is64
) {
542 timing
=timing
<<(2+is64
);
545 timing
=timing
<<(1+is64
);
548 timing
=(timing
<<(2+is64
))/3;
558 static void pm2_mnp(u32 clk
, unsigned char* mm
, unsigned char* nn
,
568 for (n
=2; n
<15; n
++) {
570 f
=PM2_REFERENCE_CLOCK
*m
/n
;
571 if (f
>=150000 && f
<=300000) {
572 for (p
=0; p
<5; p
++, f
>>=1) {
573 curr
=clk
>f
?clk
-f
:f
-clk
;
586 static void pm2v_mnp(u32 clk
, unsigned char* mm
, unsigned char* nn
,
597 for (p
=0; p
<2; p
++) {
598 f
=PM2_REFERENCE_CLOCK
*n
/(m
* (1<<(p
+1)));
599 if (clk
>f
-delta
&& clk
<f
+delta
) {
600 delta
=clk
>f
?clk
-f
:f
-clk
;
610 static void wait_pm2(struct pm2fb_info
* i
) {
613 pm2_WR(i
, PM2R_SYNC
, 0);
616 while (pm2_RD(i
, PM2R_OUT_FIFO_WORDS
)==0);
618 } while (pm2_RD(i
, PM2R_OUT_FIFO
)!=PM2TAG(PM2R_SYNC
));
621 static void pm2_set_memclock(struct pm2fb_info
* info
, u32 clk
) {
623 unsigned char m
, n
, p
;
625 pm2_mnp(clk
, &m
, &n
, &p
);
627 pm2_RDAC_WR(info
, PM2I_RD_MEMORY_CLOCK_3
, 6);
629 pm2_RDAC_WR(info
, PM2I_RD_MEMORY_CLOCK_1
, m
);
630 pm2_RDAC_WR(info
, PM2I_RD_MEMORY_CLOCK_2
, n
);
632 pm2_RDAC_WR(info
, PM2I_RD_MEMORY_CLOCK_3
, 8|p
);
634 pm2_RDAC_RD(info
, PM2I_RD_MEMORY_CLOCK_STATUS
);
637 !(pm2_RD(info
, PM2R_RD_INDEXED_DATA
)&PM2F_PLL_LOCKED
); i
--);
640 static void pm2_set_pixclock(struct pm2fb_info
* info
, u32 clk
) {
642 unsigned char m
, n
, p
;
644 switch (info
->type
) {
645 case PM2_TYPE_PERMEDIA2
:
646 pm2_mnp(clk
, &m
, &n
, &p
);
648 pm2_RDAC_WR(info
, PM2I_RD_PIXEL_CLOCK_A3
, 0);
650 pm2_RDAC_WR(info
, PM2I_RD_PIXEL_CLOCK_A1
, m
);
651 pm2_RDAC_WR(info
, PM2I_RD_PIXEL_CLOCK_A2
, n
);
653 pm2_RDAC_WR(info
, PM2I_RD_PIXEL_CLOCK_A3
, 8|p
);
655 pm2_RDAC_RD(info
, PM2I_RD_PIXEL_CLOCK_STATUS
);
658 i
&& !(pm2_RD(info
, PM2R_RD_INDEXED_DATA
)&PM2F_PLL_LOCKED
);
662 case PM2_TYPE_PERMEDIA2V
:
663 pm2v_mnp(clk
/2, &m
, &n
, &p
);
665 pm2_WR(info
, PM2VR_RD_INDEX_HIGH
,
666 PM2VI_RD_CLK0_PRESCALE
>> 8);
667 pm2v_RDAC_WR(info
, PM2VI_RD_CLK0_PRESCALE
, m
);
668 pm2v_RDAC_WR(info
, PM2VI_RD_CLK0_FEEDBACK
, n
);
669 pm2v_RDAC_WR(info
, PM2VI_RD_CLK0_POSTSCALE
, p
);
670 pm2_WR(info
, PM2VR_RD_INDEX_HIGH
, 0);
675 static void clear_palette(struct pm2fb_info
* p
) {
679 pm2_WR(p
, PM2R_RD_PALETTE_WRITE_ADDRESS
, 0);
683 pm2_WR(p
, PM2R_RD_PALETTE_DATA
, 0);
684 pm2_WR(p
, PM2R_RD_PALETTE_DATA
, 0);
685 pm2_WR(p
, PM2R_RD_PALETTE_DATA
, 0);
689 static void set_color(struct pm2fb_info
* p
, unsigned char regno
,
690 unsigned char r
, unsigned char g
, unsigned char b
) {
693 pm2_WR(p
, PM2R_RD_PALETTE_WRITE_ADDRESS
, regno
);
695 pm2_WR(p
, PM2R_RD_PALETTE_DATA
, r
);
697 pm2_WR(p
, PM2R_RD_PALETTE_DATA
, g
);
699 pm2_WR(p
, PM2R_RD_PALETTE_DATA
, b
);
702 static void set_aperture(struct pm2fb_info
* i
, struct pm2fb_par
* p
) {
705 #ifdef __LITTLE_ENDIAN
706 pm2_WR(i
, PM2R_APERTURE_ONE
, 0);
707 pm2_WR(i
, PM2R_APERTURE_TWO
, 0);
712 pm2_WR(i
, PM2R_APERTURE_ONE
, 0);
713 pm2_WR(i
, PM2R_APERTURE_TWO
, 1);
716 pm2_WR(i
, PM2R_APERTURE_ONE
, 2);
717 pm2_WR(i
, PM2R_APERTURE_TWO
, 1);
720 pm2_WR(i
, PM2R_APERTURE_ONE
, 1);
721 pm2_WR(i
, PM2R_APERTURE_TWO
, 1);
727 static void set_video(struct pm2fb_info
* i
, u32 video
) {
734 * The hardware cursor needs +vsync to recognise vert retrace.
735 * We may not be using the hardware cursor, but the X Glint
736 * driver may well. So always set +hsync/+vsync and then set
737 * the RAMDAC to invert the sync if necessary.
739 vsync
&=~(PM2F_HSYNC_MASK
|PM2F_VSYNC_MASK
);
740 vsync
|=PM2F_HSYNC_ACT_HIGH
|PM2F_VSYNC_ACT_HIGH
;
743 pm2_WR(i
, PM2R_VIDEO_CONTROL
, vsync
);
746 case PM2_TYPE_PERMEDIA2
:
747 tmp
= PM2F_RD_PALETTE_WIDTH_8
;
748 if ((video
& PM2F_HSYNC_MASK
) == PM2F_HSYNC_ACT_LOW
)
749 tmp
|= 4; /* invert hsync */
750 if ((video
& PM2F_VSYNC_MASK
) == PM2F_VSYNC_ACT_LOW
)
751 tmp
|= 8; /* invert vsync */
752 pm2_RDAC_WR(i
, PM2I_RD_MISC_CONTROL
, tmp
);
754 case PM2_TYPE_PERMEDIA2V
:
756 if ((video
& PM2F_HSYNC_MASK
) == PM2F_HSYNC_ACT_LOW
)
757 tmp
|= 1; /* invert hsync */
758 if ((video
& PM2F_VSYNC_MASK
) == PM2F_VSYNC_ACT_LOW
)
759 tmp
|= 4; /* invert vsync */
760 pm2v_RDAC_WR(i
, PM2VI_RD_SYNC_CONTROL
, tmp
);
761 pm2v_RDAC_WR(i
, PM2VI_RD_MISC_CONTROL
, 1);
766 static void get_screen(struct pm2fb_info
* i
, struct pm2fb_par
* p
) {
771 memset(p
, 0, sizeof(struct pm2fb_par
));
772 p
->base
=pm2_RD(i
, PM2R_SCREEN_BASE
);
773 p
->video
=pm2_RD(i
, PM2R_VIDEO_CONTROL
) & VIDEO_MASK
;
775 case PM2_TYPE_PERMEDIA2
:
776 misc
=pm2_RDAC_RD(i
, PM2I_RD_MISC_CONTROL
);
778 /* Hsync is actually low */
779 p
->video
|= PM2F_HSYNC_ACT_LOW
;
781 /* Vsync is actually low */
782 p
->video
|= PM2F_VSYNC_ACT_LOW
;
784 case PM2_TYPE_PERMEDIA2V
:
785 misc
=pm2_RDAC_RD(i
, PM2VI_RD_SYNC_CONTROL
);
787 /* Hsync is actually low */
788 p
->video
|= PM2F_HSYNC_ACT_LOW
;
790 /* Vsync is actually low */
791 p
->video
|= PM2F_VSYNC_ACT_LOW
;
794 p
->width
=pm2_RD(i
, PM2R_SCREEN_SIZE
) & 0xffff;
795 p
->height
=pm2_RD(i
, PM2R_SCREEN_SIZE
) >> 16;
796 p
->htotal
=pm2_RD(i
, PM2R_H_TOTAL
);
797 p
->hsstart
=pm2_RD(i
, PM2R_HS_START
);
798 p
->hsend
=pm2_RD(i
, PM2R_HS_END
);
799 p
->hbend
=pm2_RD(i
, PM2R_HB_END
);
800 p
->vtotal
=pm2_RD(i
, PM2R_V_TOTAL
);
801 p
->vsstart
=pm2_RD(i
, PM2R_VS_START
);
802 p
->vsend
=pm2_RD(i
, PM2R_VS_END
);
803 p
->vbend
=pm2_RD(i
, PM2R_VB_END
);
804 p
->stride
=pm2_RD(i
, PM2R_SCREEN_STRIDE
);
805 clrmode
=pm2_RDAC_RD(i
, PM2I_RD_COLOR_MODE
);
806 readpx
=pm2_RD(i
, PM2R_FB_READ_PIXEL
);
807 if (clrmode
& PM2F_RD_GUI_ACTIVE
) {
808 clrmode
&= ~(PM2F_RD_COLOR_MODE_RGB
|PM2F_RD_GUI_ACTIVE
);
809 if (clrmode
==0 && readpx
==0)
811 else if (clrmode
==(PM2F_RD_TRUECOLOR
|0x06) && readpx
==1)
813 else if (clrmode
==(PM2F_RD_TRUECOLOR
|0x08) && readpx
==2)
815 else if (clrmode
==(PM2F_RD_TRUECOLOR
|0x09) && readpx
==4)
819 * Somehow I have to manage this unretrievable fields.
820 * To say the truth, 'flags' field ought to be somewhere else.
822 if (i
->current_par_valid
) {
823 p
->pixclock
=i
->current_par
.pixclock
;
824 p
->flags
=i
->current_par
.flags
;
828 static void set_screen(struct pm2fb_info
* i
, struct pm2fb_par
* p
) {
829 u32 clrmode
=PM2F_RD_COLOR_MODE_RGB
;
835 if (i
->type
== PM2_TYPE_PERMEDIA2V
) {
837 pm2_WR(i
, PM2VR_RD_INDEX_HIGH
, 0);
839 xres
=(p
->width
+31)&~31;
843 pm2_RDAC_WR(i
, PM2I_RD_COLOR_KEY_CONTROL
, p
->depth
==8?0:
844 PM2F_COLOR_KEY_TEST_OFF
);
847 pm2_WR(i
, PM2R_FB_READ_PIXEL
, 0);
851 pm2_WR(i
, PM2R_FB_READ_PIXEL
, 1);
852 clrmode
|=PM2F_RD_TRUECOLOR
|0x06;
853 txtmap
=PM2F_TEXTEL_SIZE_16
;
858 pm2_WR(i
, PM2R_FB_READ_PIXEL
, 2);
859 clrmode
|=PM2F_RD_TRUECOLOR
|0x08;
860 txtmap
=PM2F_TEXTEL_SIZE_32
;
865 pm2_WR(i
, PM2R_FB_READ_PIXEL
, 4);
866 clrmode
|=PM2F_RD_TRUECOLOR
|0x09;
867 #ifndef PM2FB_BE_APERTURE
868 clrmode
&=~PM2F_RD_COLOR_MODE_RGB
;
870 txtmap
=PM2F_TEXTEL_SIZE_24
;
875 pm2_WR(i
, PM2R_FB_WRITE_MODE
, PM2F_FB_WRITE_ENABLE
);
876 pm2_WR(i
, PM2R_FB_READ_MODE
, partprod(xres
));
877 pm2_WR(i
, PM2R_LB_READ_MODE
, partprod(xres
));
878 pm2_WR(i
, PM2R_TEXTURE_MAP_FORMAT
, txtmap
|partprod(xres
));
879 pm2_WR(i
, PM2R_H_TOTAL
, p
->htotal
);
880 pm2_WR(i
, PM2R_HS_START
, p
->hsstart
);
881 pm2_WR(i
, PM2R_HS_END
, p
->hsend
);
882 pm2_WR(i
, PM2R_HG_END
, p
->hbend
);
883 pm2_WR(i
, PM2R_HB_END
, p
->hbend
);
884 pm2_WR(i
, PM2R_V_TOTAL
, p
->vtotal
);
885 pm2_WR(i
, PM2R_VS_START
, p
->vsstart
);
886 pm2_WR(i
, PM2R_VS_END
, p
->vsend
);
887 pm2_WR(i
, PM2R_VB_END
, p
->vbend
);
888 pm2_WR(i
, PM2R_SCREEN_STRIDE
, p
->stride
);
890 pm2_WR(i
, PM2R_WINDOW_ORIGIN
, 0);
891 pm2_WR(i
, PM2R_SCREEN_SIZE
, (p
->height
<<16)|p
->width
);
892 pm2_WR(i
, PM2R_SCISSOR_MODE
, PM2F_SCREEN_SCISSOR_ENABLE
);
894 pm2_WR(i
, PM2R_SCREEN_BASE
, p
->base
);
896 set_video(i
, p
->video
);
899 case PM2_TYPE_PERMEDIA2
:
900 pm2_RDAC_WR(i
, PM2I_RD_COLOR_MODE
, PM2F_RD_COLOR_MODE_RGB
|
901 PM2F_RD_GUI_ACTIVE
|clrmode
);
903 case PM2_TYPE_PERMEDIA2V
:
904 pm2v_RDAC_WR(i
, PM2VI_RD_PIXEL_SIZE
, pixsize
);
905 pm2v_RDAC_WR(i
, PM2VI_RD_COLOR_FORMAT
, clrformat
);
908 pm2_set_pixclock(i
, p
->pixclock
);
911 static int screen_is_valid(struct pm2fb_info
* i
) {
912 struct pm2fb_par actual
;
914 get_screen(i
, &actual
);
915 return i
->current_par_valid
&&
916 !memcmp(&actual
, &i
->current_par
, sizeof(struct pm2fb_par
));
920 * copy with packed pixels (8/16bpp only).
922 static void pm2fb_pp_copy(struct pm2fb_info
* i
, s32 xsrc
, s32 ysrc
,
923 s32 x
, s32 y
, s32 w
, s32 h
) {
924 s32 scale
=i
->current_par
.depth
==8?2:1;
930 pm2_WR(i
, PM2R_CONFIG
, PM2F_CONFIG_FB_WRITE_ENABLE
|
931 PM2F_CONFIG_FB_PACKED_DATA
|
932 PM2F_CONFIG_FB_READ_SOURCE_ENABLE
);
933 pm2_WR(i
, PM2R_FB_SOURCE_DELTA
, ((ysrc
-y
)&0xfff)<<16|
935 offset
=(x
&0x3)-(xsrc
&0x3);
936 pm2_WR(i
, PM2R_RECTANGLE_ORIGIN
, (y
<<16)|(x
>>scale
));
937 pm2_WR(i
, PM2R_RECTANGLE_SIZE
, (h
<<16)|((w
+7)>>scale
));
938 pm2_WR(i
, PM2R_PACKED_DATA_LIMITS
, (offset
<<29)|(x
<<16)|(x
+w
));
940 pm2_WR(i
, PM2R_RENDER
, PM2F_RENDER_RECTANGLE
|
941 (x
<xsrc
?PM2F_INCREASE_X
:0)|
942 (y
<ysrc
?PM2F_INCREASE_Y
:0));
947 * block operation. copy=0: rectangle fill, copy=1: rectangle copy.
949 static void pm2fb_block_op(struct pm2fb_info
* i
, int copy
,
951 s32 x
, s32 y
, s32 w
, s32 h
,
957 pm2_WR(i
, PM2R_CONFIG
, PM2F_CONFIG_FB_WRITE_ENABLE
|
958 (copy
?PM2F_CONFIG_FB_READ_SOURCE_ENABLE
:0));
960 pm2_WR(i
, PM2R_FB_SOURCE_DELTA
, ((ysrc
-y
)&0xfff)<<16|
963 pm2_WR(i
, PM2R_FB_BLOCK_COLOR
, color
);
964 pm2_WR(i
, PM2R_RECTANGLE_ORIGIN
, (y
<<16)|x
);
965 pm2_WR(i
, PM2R_RECTANGLE_SIZE
, (h
<<16)|w
);
967 pm2_WR(i
, PM2R_RENDER
, PM2F_RENDER_RECTANGLE
|
968 (x
<xsrc
?PM2F_INCREASE_X
:0)|
969 (y
<ysrc
?PM2F_INCREASE_Y
:0)|
970 (copy
?0:PM2F_RENDER_FASTFILL
));
974 /***************************************************************************
975 * Begin of generic initialization functions
976 ***************************************************************************/
978 static void reset_units(struct pm2fb_info
* p
) {
981 pm2_WR(p
, PM2R_CHIP_CONFIG
, pm2_RD(p
, PM2R_CHIP_CONFIG
)&
982 ~(PM2F_VGA_ENABLE
|PM2F_VGA_FIXED
));
983 pm2_WR(p
, PM2R_BYPASS_WRITE_MASK
, ~(0L));
984 pm2_WR(p
, PM2R_FRAMEBUFFER_WRITE_MASK
, ~(0L));
985 pm2_WR(p
, PM2R_FIFO_CONTROL
, 0);
986 pm2_WR(p
, PM2R_APERTURE_ONE
, 0);
987 pm2_WR(p
, PM2R_APERTURE_TWO
, 0);
988 pm2_WR(p
, PM2R_RASTERIZER_MODE
, 0);
989 pm2_WR(p
, PM2R_DELTA_MODE
, PM2F_DELTA_ORDER_RGB
);
990 pm2_WR(p
, PM2R_LB_READ_FORMAT
, 0);
991 pm2_WR(p
, PM2R_LB_WRITE_FORMAT
, 0);
992 pm2_WR(p
, PM2R_LB_READ_MODE
, 0);
993 pm2_WR(p
, PM2R_LB_SOURCE_OFFSET
, 0);
994 pm2_WR(p
, PM2R_FB_SOURCE_OFFSET
, 0);
995 pm2_WR(p
, PM2R_FB_PIXEL_OFFSET
, 0);
996 pm2_WR(p
, PM2R_FB_WINDOW_BASE
, 0);
997 pm2_WR(p
, PM2R_LB_WINDOW_BASE
, 0);
998 pm2_WR(p
, PM2R_FB_SOFT_WRITE_MASK
, ~(0L));
999 pm2_WR(p
, PM2R_FB_HARD_WRITE_MASK
, ~(0L));
1000 pm2_WR(p
, PM2R_FB_READ_PIXEL
, 0);
1001 pm2_WR(p
, PM2R_DITHER_MODE
, 0);
1002 pm2_WR(p
, PM2R_AREA_STIPPLE_MODE
, 0);
1003 pm2_WR(p
, PM2R_DEPTH_MODE
, 0);
1004 pm2_WR(p
, PM2R_STENCIL_MODE
, 0);
1005 pm2_WR(p
, PM2R_TEXTURE_ADDRESS_MODE
, 0);
1006 pm2_WR(p
, PM2R_TEXTURE_READ_MODE
, 0);
1007 pm2_WR(p
, PM2R_TEXEL_LUT_MODE
, 0);
1008 pm2_WR(p
, PM2R_YUV_MODE
, 0);
1009 pm2_WR(p
, PM2R_COLOR_DDA_MODE
, 0);
1010 pm2_WR(p
, PM2R_TEXTURE_COLOR_MODE
, 0);
1011 pm2_WR(p
, PM2R_FOG_MODE
, 0);
1012 pm2_WR(p
, PM2R_ALPHA_BLEND_MODE
, 0);
1013 pm2_WR(p
, PM2R_LOGICAL_OP_MODE
, 0);
1014 pm2_WR(p
, PM2R_STATISTICS_MODE
, 0);
1015 pm2_WR(p
, PM2R_SCISSOR_MODE
, 0);
1016 pm2_WR(p
, PM2R_FILTER_MODE
, PM2F_SYNCHRONIZATION
);
1018 case PM2_TYPE_PERMEDIA2
:
1019 pm2_RDAC_WR(p
, PM2I_RD_MODE_CONTROL
, 0); /* no overlay */
1020 pm2_RDAC_WR(p
, PM2I_RD_CURSOR_CONTROL
, 0);
1021 pm2_RDAC_WR(p
, PM2I_RD_MISC_CONTROL
, PM2F_RD_PALETTE_WIDTH_8
);
1023 case PM2_TYPE_PERMEDIA2V
:
1024 pm2v_RDAC_WR(p
, PM2VI_RD_MISC_CONTROL
, 1); /* 8bit */
1027 pm2_RDAC_WR(p
, PM2I_RD_COLOR_KEY_CONTROL
, 0);
1028 pm2_RDAC_WR(p
, PM2I_RD_OVERLAY_KEY
, 0);
1029 pm2_RDAC_WR(p
, PM2I_RD_RED_KEY
, 0);
1030 pm2_RDAC_WR(p
, PM2I_RD_GREEN_KEY
, 0);
1031 pm2_RDAC_WR(p
, PM2I_RD_BLUE_KEY
, 0);
1034 static void pm2fb_reset(struct pm2fb_info
* p
) {
1036 if (p
->type
== PM2_TYPE_PERMEDIA2V
)
1037 pm2_WR(p
, PM2VR_RD_INDEX_HIGH
, 0);
1038 pm2_WR(p
, PM2R_RESET_STATUS
, 0);
1040 while (pm2_RD(p
, PM2R_RESET_STATUS
)&PM2F_BEING_RESET
);
1042 #ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
1043 DPRINTK("FIFO disconnect enabled\n");
1044 pm2_WR(p
, PM2R_FIFO_DISCON
, 1);
1047 if (board_table
[p
->board
].init
)
1048 board_table
[p
->board
].init(p
);
1052 pm2_set_memclock(p
, p
->memclock
);
1055 static int __init
pm2fb_conf(struct pm2fb_info
* p
) {
1057 for (p
->board
=0; board_table
[p
->board
].detect
&&
1058 !(board_table
[p
->board
].detect(p
)); p
->board
++);
1059 if (!board_table
[p
->board
].detect
) {
1060 DPRINTK("no board found.\n");
1063 DPRINTK("found board: %s\n", board_table
[p
->board
].name
);
1065 p
->regions
.p_fb
=p
->regions
.fb_base
;
1066 if (!request_mem_region((unsigned long )p
->regions
.p_fb
,
1067 p
->regions
.fb_size
, "pm2fb")) {
1068 printk (KERN_ERR
"pm2fb: cannot reserve fb memory, abort.\n");
1071 p
->regions
.v_fb
=MMAP(p
->regions
.p_fb
, p
->regions
.fb_size
);
1073 #ifndef PM2FB_BE_APERTURE
1074 p
->regions
.p_regs
=p
->regions
.rg_base
;
1076 p
->regions
.p_regs
=p
->regions
.rg_base
+PM2_REGS_SIZE
;
1078 if (!request_mem_region((unsigned long )p
->regions
.p_regs
,
1079 PM2_REGS_SIZE
, "pm2fb")) {
1080 printk (KERN_ERR
"pm2fb: cannot reserve mmio memory, abort.\n");
1081 UNMAP(p
->regions
.v_fb
, p
->regions
.fb_size
);
1084 p
->regions
.v_regs
=MMAP(p
->regions
.p_regs
, PM2_REGS_SIZE
);
1086 #ifdef PM2FB_HW_CURSOR
1087 p
->cursor
= pm2_init_cursor(p
);
1092 /***************************************************************************
1093 * Begin of per-board initialization functions
1094 ***************************************************************************/
1097 * Phase5 CvisionPPC/BVisionPPC
1099 #ifdef CONFIG_FB_PM2_CVPPC
1100 static int cvppc_PCI_init(struct cvppc_par
* p
) {
1101 extern u32 powerup_PCI_present
;
1103 if (!powerup_PCI_present
) {
1104 DPRINTK("no PCI bridge detected\n");
1107 if (!(p
->pci_config
=MMAP(CVPPC_PCI_CONFIG
, 256))) {
1108 DPRINTK("unable to map PCI config region\n");
1111 if (RD32(p
->pci_config
, PCI_VENDOR_ID
)!=
1112 ((PCI_DEVICE_ID_TI_TVP4020
<<16)|PCI_VENDOR_ID_TI
)) {
1113 DPRINTK("bad vendorID/deviceID\n");
1116 if (!(p
->pci_bridge
=MMAP(CSPPC_PCI_BRIDGE
, 256))) {
1117 DPRINTK("unable to map PCI bridge\n");
1120 WR32(p
->pci_bridge
, CSPPC_BRIDGE_ENDIAN
, CSPPCF_BRIDGE_BIG_ENDIAN
);
1122 if (pm2fb_options
.flags
& OPTF_OLD_MEM
)
1123 WR32(p
->pci_config
, PCI_CACHE_LINE_SIZE
, 0xff00);
1124 WR32(p
->pci_config
, PCI_BASE_ADDRESS_0
, CVPPC_REGS_REGION
);
1125 WR32(p
->pci_config
, PCI_BASE_ADDRESS_1
, CVPPC_FB_APERTURE_ONE
);
1126 WR32(p
->pci_config
, PCI_BASE_ADDRESS_2
, CVPPC_FB_APERTURE_TWO
);
1127 WR32(p
->pci_config
, PCI_ROM_ADDRESS
, CVPPC_ROM_ADDRESS
);
1129 WR32(p
->pci_config
, PCI_COMMAND
, 0xef000000 |
1131 PCI_COMMAND_MEMORY
|
1132 PCI_COMMAND_MASTER
);
1136 static int __init
cvppc_detect(struct pm2fb_info
* p
) {
1138 if (!cvppc_PCI_init(&p
->board_par
.cvppc
))
1140 p
->type
=PM2_TYPE_PERMEDIA2
;
1141 p
->regions
.fb_base
=CVPPC_FB_APERTURE_ONE
;
1142 p
->regions
.fb_size
=CVPPC_FB_SIZE
;
1143 p
->regions
.rg_base
=CVPPC_REGS_REGION
;
1144 p
->memclock
=CVPPC_MEMCLOCK
;
1148 static void cvppc_init(struct pm2fb_info
* p
) {
1151 pm2_WR(p
, PM2R_MEM_CONTROL
, 0);
1152 pm2_WR(p
, PM2R_BOOT_ADDRESS
, 0x30);
1154 if (pm2fb_options
.flags
& OPTF_OLD_MEM
)
1155 pm2_WR(p
, PM2R_MEM_CONFIG
, CVPPC_MEM_CONFIG_OLD
);
1157 pm2_WR(p
, PM2R_MEM_CONFIG
, CVPPC_MEM_CONFIG_NEW
);
1159 #endif /* CONFIG_FB_PM2_CVPPC */
1162 * Generic PCI detection routines
1164 #ifdef CONFIG_FB_PM2_PCI
1166 unsigned short vendor
, device
;
1169 } pm2pci_cards
[] __initdata
= {
1170 { PCI_VENDOR_ID_TI
, PCI_DEVICE_ID_TI_TVP4020
,
1171 "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2
},
1172 { PCI_VENDOR_ID_3DLABS
, PCI_DEVICE_ID_3DLABS_PERMEDIA2
,
1173 "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2
},
1174 { PCI_VENDOR_ID_3DLABS
, PCI_DEVICE_ID_3DLABS_PERMEDIA2V
,
1175 "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V
},
1179 static int __init
pm2pci_detect(struct pm2fb_info
* p
) {
1180 struct pm2pci_par
* pci
=&p
->board_par
.pci
;
1181 struct pci_dev
* dev
= NULL
;
1185 struct pcidev_cookie
*pcp
;
1188 memset(pci
, 0, sizeof(struct pm2pci_par
));
1189 DPRINTK("scanning PCI bus for known chipsets...\n");
1191 while ((dev
= pci_find_device(PCI_ANY_ID
, PCI_ANY_ID
, dev
)) != NULL
) {
1192 for (i
= 0; pm2pci_cards
[i
].vendor
; i
++)
1193 if (pm2pci_cards
[i
].vendor
== dev
->vendor
&&
1194 pm2pci_cards
[i
].device
== dev
->device
) {
1196 p
->type
= pm2pci_cards
[i
].type
;
1197 DPRINTK("... found %s\n", pm2pci_cards
[i
].name
);
1204 DPRINTK("no PCI board found.\n");
1207 DPRINTK("PCI board @%08lx %08lx %08lx rom %08lx\n",
1208 pci
->dev
->resource
[0].start
,
1209 pci
->dev
->resource
[1].start
,
1210 pci
->dev
->resource
[2].start
,
1211 pci
->dev
->resource
[PCI_ROM_RESOURCE
].start
);
1213 p
->regions
.rg_base
= pci
->dev
->resource
[0].start
;
1214 p
->regions
.fb_base
= pci
->dev
->resource
[1].start
;
1215 pcp
= pci
->dev
->sysdata
;
1216 /* If the user has not asked for a particular mode, lets guess */
1217 if (pcp
->prom_node
&&
1218 !(pm2fb_options
.flags
& (OPTF_USER
|OPTF_USER_VAR
))) {
1219 char timing
[256], *q
, *r
;
1222 prom_getstring(pcp
->prom_node
, "timing-numbers", timing
, 256);
1223 /* FIXME: Find out what the actual pixclock is
1224 * and other values as well */
1226 w
= simple_strtoul(timing
, &q
, 0);
1228 if (q
== timing
) w
= 0;
1230 for (i
= 0; i
< 3; i
++) {
1232 *r
&& (*r
< '0' || *r
> '9');
1235 simple_strtoul(r
, &q
, 0);
1241 for (r
= q
; *r
&& (*r
< '0' || *r
> '9'); r
++);
1242 h
= simple_strtoul(r
, &q
, 0);
1245 if (w
== 640 && h
== 480) w
= 0;
1247 for (i
=0; user_mode
[i
].name
[0] &&
1248 (w
!= user_mode
[i
].par
.width
||
1249 h
!= user_mode
[i
].par
.height
); i
++);
1250 if (user_mode
[i
].name
[0])
1251 memcpy(&p
->current_par
,
1253 sizeof(user_mode
[i
].par
));
1258 if (pm2fb_options
.flags
& OPTF_VIRTUAL
) {
1259 p
->regions
.rg_base
= __pa(pci_resource_start(pci
->dev
, 0));
1260 p
->regions
.fb_base
= __pa(pci_resource_start(pci
->dev
, 1));
1263 p
->regions
.rg_base
= pci_resource_start(pci
->dev
, 0);
1264 p
->regions
.fb_base
= pci_resource_start(pci
->dev
, 1);
1267 #ifdef PM2FB_BE_APERTURE
1268 p
->regions
.rg_base
+= PM2_REGS_SIZE
;
1270 if ((m
=MMAP(p
->regions
.rg_base
, PM2_REGS_SIZE
))) {
1271 pci
->mem_control
=RD32(m
, PM2R_MEM_CONTROL
);
1272 pci
->boot_address
=RD32(m
, PM2R_BOOT_ADDRESS
);
1273 pci
->mem_config
=RD32(m
, PM2R_MEM_CONFIG
);
1274 switch (pci
->mem_config
& PM2F_MEM_CONFIG_RAM_MASK
) {
1275 case PM2F_MEM_BANKS_1
:
1276 p
->regions
.fb_size
=0x200000;
1278 case PM2F_MEM_BANKS_2
:
1279 p
->regions
.fb_size
=0x400000;
1281 case PM2F_MEM_BANKS_3
:
1282 p
->regions
.fb_size
=0x600000;
1284 case PM2F_MEM_BANKS_4
:
1285 p
->regions
.fb_size
=0x800000;
1288 p
->memclock
=CVPPC_MEMCLOCK
;
1289 UNMAP(m
, PM2_REGS_SIZE
);
1292 DPRINTK("MMAP() failed.\n");
1296 static void pm2pci_init(struct pm2fb_info
* p
) {
1297 struct pm2pci_par
* pci
=&p
->board_par
.pci
;
1300 pm2_WR(p
, PM2R_MEM_CONTROL
, pci
->mem_control
);
1301 pm2_WR(p
, PM2R_BOOT_ADDRESS
, pci
->boot_address
);
1303 pm2_WR(p
, PM2R_MEM_CONFIG
, pci
->mem_config
);
1305 #endif /* CONFIG_FB_PM2_PCI */
1307 /***************************************************************************
1308 * Console hw acceleration
1309 ***************************************************************************/
1311 static int pm2fb_blank(int blank_mode
, struct fb_info_gen
* info
) {
1312 struct pm2fb_info
* i
=(struct pm2fb_info
* )info
;
1315 if (!i
->current_par_valid
)
1317 video
=i
->current_par
.video
;
1320 switch (blank_mode
-1) {
1321 case VESA_NO_BLANKING
: /* FIXME */
1322 video
=video
&~(PM2F_VIDEO_ENABLE
);
1324 case VESA_HSYNC_SUSPEND
:
1325 video
=video
&~(PM2F_HSYNC_MASK
|
1328 case VESA_VSYNC_SUSPEND
:
1329 video
=video
&~(PM2F_VSYNC_MASK
|
1332 case VESA_POWERDOWN
:
1333 video
=video
&~(PM2F_VSYNC_MASK
|
1341 set_video(i
, video
);
1345 static int pm2fb_pan_display(const struct fb_var_screeninfo
* var
,
1346 struct fb_info_gen
* info
) {
1347 struct pm2fb_info
* i
=(struct pm2fb_info
* )info
;
1349 if (!i
->current_par_valid
)
1351 i
->current_par
.base
=to3264(var
->yoffset
*i
->current_par
.width
+
1352 var
->xoffset
, i
->current_par
.depth
, 1);
1354 pm2_WR(i
, PM2R_SCREEN_BASE
, i
->current_par
.base
);
1358 static void pm2fb_pp_bmove(struct display
* p
, int sy
, int sx
,
1359 int dy
, int dx
, int height
, int width
) {
1361 if (fontwidthlog(p
)) {
1362 sx
=sx
<<fontwidthlog(p
);
1363 dx
=dx
<<fontwidthlog(p
);
1364 width
=width
<<fontwidthlog(p
);
1369 width
=width
*fontwidth(p
);
1371 sy
=sy
*fontheight(p
);
1372 dy
=dy
*fontheight(p
);
1373 height
=height
*fontheight(p
);
1374 pm2fb_pp_copy((struct pm2fb_info
* )p
->fb_info
, sx
, sy
, dx
,
1378 static void pm2fb_bmove(struct display
* p
, int sy
, int sx
,
1379 int dy
, int dx
, int height
, int width
) {
1381 if (fontwidthlog(p
)) {
1382 sx
=sx
<<fontwidthlog(p
);
1383 dx
=dx
<<fontwidthlog(p
);
1384 width
=width
<<fontwidthlog(p
);
1389 width
=width
*fontwidth(p
);
1391 sy
=sy
*fontheight(p
);
1392 dy
=dy
*fontheight(p
);
1393 height
=height
*fontheight(p
);
1394 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 1, sx
, sy
, dx
, dy
,
1398 #ifdef FBCON_HAS_CFB8
1399 static void pm2fb_clear8(struct vc_data
* conp
, struct display
* p
,
1400 int sy
, int sx
, int height
, int width
) {
1404 width
=width
*fontwidth(p
);
1405 sy
=sy
*fontheight(p
);
1406 height
=height
*fontheight(p
);
1407 c
=attr_bgcol_ec(p
, conp
);
1410 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 0, 0, 0, sx
, sy
,
1414 static void pm2fb_clear_margins8(struct vc_data
* conp
, struct display
* p
,
1420 c
=attr_bgcol_ec(p
, conp
);
1423 sx
=conp
->vc_cols
*fontwidth(p
);
1424 sy
=conp
->vc_rows
*fontheight(p
);
1426 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 0, 0, 0,
1427 sx
, 0, (p
->var
.xres
-sx
), p
->var
.yres_virtual
, c
);
1428 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 0, 0, 0,
1429 0, p
->var
.yoffset
+sy
, sx
, p
->var
.yres
-sy
, c
);
1432 static struct display_switch pm2_cfb8
= {
1433 .setup
= fbcon_cfb8_setup
,
1434 .bmove
= pm2fb_pp_bmove
,
1436 /* Not sure why, but this works and the other does not. */
1437 /* Also, perhaps we need a separate routine to wait for the
1438 blitter to stop before doing this? */
1439 /* In addition, maybe we need to do this for 16 and 32 bit depths? */
1440 .clear
= fbcon_cfb8_clear
,
1442 .clear
= pm2fb_clear8
,
1444 .putc
= fbcon_cfb8_putc
,
1445 .putcs
= fbcon_cfb8_putcs
,
1446 .revc
= fbcon_cfb8_revc
,
1447 .cursor
= pm2fb_cursor
,
1448 .set_font
= pm2fb_set_font
,
1449 .clear_margins
= pm2fb_clear_margins8
,
1450 .fontwidthmask
= FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16) };
1451 #endif /* FBCON_HAS_CFB8 */
1453 #ifdef FBCON_HAS_CFB16
1454 static void pm2fb_clear16(struct vc_data
* conp
, struct display
* p
,
1455 int sy
, int sx
, int height
, int width
) {
1459 width
=width
*fontwidth(p
);
1460 sy
=sy
*fontheight(p
);
1461 height
=height
*fontheight(p
);
1462 c
=((u16
*)p
->dispsw_data
)[attr_bgcol_ec(p
, conp
)];
1464 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 0, 0, 0, sx
, sy
,
1468 static void pm2fb_clear_margins16(struct vc_data
* conp
, struct display
* p
,
1474 c
=((u16
*)p
->dispsw_data
)[attr_bgcol_ec(p
, conp
)];
1476 sx
=conp
->vc_cols
*fontwidth(p
);
1477 sy
=conp
->vc_rows
*fontheight(p
);
1479 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 0, 0, 0,
1480 sx
, 0, (p
->var
.xres
-sx
), p
->var
.yres_virtual
, c
);
1481 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 0, 0, 0,
1482 0, p
->var
.yoffset
+sy
, sx
, p
->var
.yres
-sy
, c
);
1485 static struct display_switch pm2_cfb16
= {
1486 .setup
= fbcon_cfb16_setup
,
1487 .bmove
= pm2fb_pp_bmove
,
1488 .clear
= pm2fb_clear16
,
1489 .putc
= fbcon_cfb16_putc
,
1490 .putcs
= fbcon_cfb16_putcs
,
1491 .revc
= fbcon_cfb16_revc
,
1492 .cursor
= pm2fb_cursor
,
1493 .set_font
= pm2fb_set_font
,
1494 .clear_margins
=pm2fb_clear_margins16
,
1495 .fontwidthmask
=FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1497 #endif /* FBCON_HAS_CFB16 */
1499 #ifdef FBCON_HAS_CFB24
1501 * fast fill for 24bpp works only when red==green==blue
1503 static void pm2fb_clear24(struct vc_data
* conp
, struct display
* p
,
1504 int sy
, int sx
, int height
, int width
) {
1505 struct pm2fb_info
* i
=(struct pm2fb_info
* )p
->fb_info
;
1508 c
=attr_bgcol_ec(p
, conp
);
1509 if ( i
->palette
[c
].red
==i
->palette
[c
].green
&&
1510 i
->palette
[c
].green
==i
->palette
[c
].blue
) {
1511 c
=((u32
*)p
->dispsw_data
)[c
];
1514 width
=width
*fontwidth(p
);
1515 sy
=sy
*fontheight(p
);
1516 height
=height
*fontheight(p
);
1517 pm2fb_block_op(i
, 0, 0, 0, sx
, sy
, width
, height
, c
);
1520 fbcon_cfb24_clear(conp
, p
, sy
, sx
, height
, width
);
1524 static void pm2fb_clear_margins24(struct vc_data
* conp
, struct display
* p
,
1526 struct pm2fb_info
* i
=(struct pm2fb_info
* )p
->fb_info
;
1530 sx
=conp
->vc_cols
*fontwidth(p
);
1531 sy
=conp
->vc_rows
*fontheight(p
);
1533 pm2fb_block_op(i
, 0, 0, 0, sx
, 0, (p
->var
.xres
-sx
),
1534 p
->var
.yres_virtual
, 0L);
1535 pm2fb_block_op(i
, 0, 0, 0, 0, p
->var
.yoffset
+sy
, sx
, p
->var
.yres
-sy
, 0L);
1538 static struct display_switch pm2_cfb24
= {
1539 .setup
= fbcon_cfb24_setup
,
1540 .bmove
= pm2fb_bmove
,
1541 .clear
= pm2fb_clear24
,
1542 .putc
= fbcon_cfb24_putc
,
1543 .putcs
= fbcon_cfb24_putcs
,
1544 .revc
= fbcon_cfb24_revc
,
1545 .cursor
= pm2fb_cursor
,
1546 .set_font
= pm2fb_set_font
,
1547 .clear_margins
=pm2fb_clear_margins24
,
1548 .fontwidthmask
=FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1550 #endif /* FBCON_HAS_CFB24 */
1552 #ifdef FBCON_HAS_CFB32
1553 static void pm2fb_clear32(struct vc_data
* conp
, struct display
* p
,
1554 int sy
, int sx
, int height
, int width
) {
1558 width
=width
*fontwidth(p
);
1559 sy
=sy
*fontheight(p
);
1560 height
=height
*fontheight(p
);
1561 c
=((u32
*)p
->dispsw_data
)[attr_bgcol_ec(p
, conp
)];
1562 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 0, 0, 0, sx
, sy
,
1566 static void pm2fb_clear_margins32(struct vc_data
* conp
, struct display
* p
,
1572 c
=((u32
*)p
->dispsw_data
)[attr_bgcol_ec(p
, conp
)];
1573 sx
=conp
->vc_cols
*fontwidth(p
);
1574 sy
=conp
->vc_rows
*fontheight(p
);
1576 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 0, 0, 0,
1577 sx
, 0, (p
->var
.xres
-sx
), p
->var
.yres_virtual
, c
);
1578 pm2fb_block_op((struct pm2fb_info
* )p
->fb_info
, 0, 0, 0,
1579 0, p
->var
.yoffset
+sy
, sx
, p
->var
.yres
-sy
, c
);
1582 static struct display_switch pm2_cfb32
= {
1583 .setup
= fbcon_cfb32_setup
,
1584 .bmove
= pm2fb_bmove
,
1585 .clear
= pm2fb_clear32
,
1586 .putc
= fbcon_cfb32_putc
,
1587 .putcs
= fbcon_cfb32_putcs
,
1588 .revc
= fbcon_cfb32_revc
,
1589 .cursor
= pm2fb_cursor
,
1590 .set_font
= pm2fb_set_font
,
1591 .clear_margins
=pm2fb_clear_margins32
,
1592 .fontwidthmask
=FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
1594 #endif /* FBCON_HAS_CFB32 */
1596 /***************************************************************************
1597 * Framebuffer functions
1598 ***************************************************************************/
1600 static void pm2fb_detect(void) {}
1602 static int pm2fb_encode_fix(struct fb_fix_screeninfo
* fix
,
1603 const void* par
, struct fb_info_gen
* info
) {
1604 struct pm2fb_info
* i
=(struct pm2fb_info
* )info
;
1605 struct pm2fb_par
* p
=(struct pm2fb_par
* )par
;
1607 strcpy(fix
->id
, permedia2_name
);
1608 fix
->smem_start
=(unsigned long )i
->regions
.p_fb
;
1609 fix
->smem_len
=i
->regions
.fb_size
;
1610 fix
->mmio_start
=(unsigned long )i
->regions
.p_regs
;
1611 fix
->mmio_len
=PM2_REGS_SIZE
;
1612 fix
->accel
=FB_ACCEL_3DLABS_PERMEDIA2
;
1613 fix
->type
=FB_TYPE_PACKED_PIXELS
;
1614 fix
->visual
=p
->depth
==8?FB_VISUAL_PSEUDOCOLOR
:FB_VISUAL_TRUECOLOR
;
1615 fix
->line_length
=p
->width
*p
->depth
/8;
1616 fix
->xpanstep
=p
->depth
==24?8:64/p
->depth
;
1622 #ifdef PM2FB_MASTER_DEBUG
1623 static void pm2fb_display_var(const struct fb_var_screeninfo
* var
) {
1626 "- struct fb_var_screeninfo ---------------------------------------------------\n");
1628 "resolution: %ux%ux%u (virtual %ux%u+%u+%u)\n",
1629 var
->xres
, var
->yres
, var
->bits_per_pixel
,
1630 var
->xres_virtual
, var
->yres_virtual
,
1631 var
->xoffset
, var
->yoffset
);
1634 "R(%u,%u,%u), G(%u,%u,%u), B(%u,%u,%u), T(%u,%u,%u)\n",
1635 var
->grayscale
?'G':'C', var
->nonstd
?'N':'S',
1636 var
->red
.offset
, var
->red
.length
, var
->red
.msb_right
,
1637 var
->green
.offset
, var
->green
.length
, var
->green
.msb_right
,
1638 var
->blue
.offset
, var
->blue
.length
, var
->blue
.msb_right
,
1639 var
->transp
.offset
, var
->transp
.length
,
1640 var
->transp
.msb_right
);
1642 "timings: %ups (%u,%u)-(%u,%u)+%u+%u\n",
1644 var
->left_margin
, var
->upper_margin
, var
->right_margin
,
1645 var
->lower_margin
, var
->hsync_len
, var
->vsync_len
);
1647 "activate %08x accel_flags %08x sync %08x vmode %08x\n",
1648 var
->activate
, var
->accel_flags
, var
->sync
, var
->vmode
);
1650 "------------------------------------------------------------------------------\n");
1653 #define pm2fb_decode_var pm2fb_wrapped_decode_var
1656 static int pm2fb_decode_var(const struct fb_var_screeninfo
* var
,
1657 void* par
, struct fb_info_gen
* info
) {
1658 struct pm2fb_info
* i
=(struct pm2fb_info
* )info
;
1663 memset(&p
, 0, sizeof(struct pm2fb_par
));
1664 if (var
->accel_flags
& FB_ACCELF_TEXT
)
1665 p
.flags
|= PM2FF_ACCEL
;
1666 p
.width
=(var
->xres_virtual
+7)&~7;
1667 p
.height
=var
->yres_virtual
;
1668 p
.depth
=(var
->bits_per_pixel
+7)&~7;
1669 p
.depth
=p
.depth
>32?32:p
.depth
;
1670 data64
=p
.depth
>8 || i
->type
==PM2_TYPE_PERMEDIA2V
;
1671 xres
=(var
->xres
+31)&~31;
1672 if (p
.width
<xres
+var
->xoffset
)
1673 p
.width
=xres
+var
->xoffset
;
1674 if (p
.height
<var
->yres
+var
->yoffset
)
1675 p
.height
=var
->yres
+var
->yoffset
;
1676 if (!partprod(xres
)) {
1677 DPRINTK("width not supported: %u\n", xres
);
1681 DPRINTK("virtual width not supported: %u\n", p
.width
);
1684 if (var
->yres
<200) {
1685 DPRINTK("height not supported: %u\n",
1689 if (p
.height
<200 || p
.height
>2047) {
1690 DPRINTK("virtual height not supported: %u\n", p
.height
);
1694 DPRINTK("depth not supported: %u\n", p
.depth
);
1697 if (p
.width
*p
.height
*p
.depth
/8>i
->regions
.fb_size
) {
1698 DPRINTK("no memory for screen (%ux%ux%u)\n",
1699 p
.width
, p
.height
, p
.depth
);
1702 p
.pixclock
=PICOS2KHZ(var
->pixclock
);
1703 if (p
.pixclock
>PM2_MAX_PIXCLOCK
) {
1704 DPRINTK("pixclock too high (%uKHz)\n", p
.pixclock
);
1707 p
.hsstart
=to3264(var
->right_margin
, p
.depth
, data64
);
1708 p
.hsend
=p
.hsstart
+to3264(var
->hsync_len
, p
.depth
, data64
);
1709 p
.hbend
=p
.hsend
+to3264(var
->left_margin
, p
.depth
, data64
);
1710 p
.htotal
=to3264(xres
, p
.depth
, data64
)+p
.hbend
-1;
1711 p
.vsstart
=var
->lower_margin
?var
->lower_margin
-1:0; /* FIXME! */
1712 p
.vsend
=var
->lower_margin
+var
->vsync_len
-1;
1713 p
.vbend
=var
->lower_margin
+var
->vsync_len
+var
->upper_margin
;
1714 p
.vtotal
=var
->yres
+p
.vbend
-1;
1715 p
.stride
=to3264(p
.width
, p
.depth
, 1);
1716 p
.base
=to3264(var
->yoffset
*xres
+var
->xoffset
, p
.depth
, 1);
1718 p
.video
|=PM2F_DATA_64_ENABLE
;
1719 if (var
->sync
& FB_SYNC_HOR_HIGH_ACT
) {
1720 if (pm2fb_options
.flags
& OPTF_LOW_HSYNC
) {
1721 DPRINTK("ignoring +hsync, using -hsync.\n");
1722 p
.video
|=PM2F_HSYNC_ACT_LOW
;
1724 p
.video
|=PM2F_HSYNC_ACT_HIGH
;
1727 p
.video
|=PM2F_HSYNC_ACT_LOW
;
1728 if (var
->sync
& FB_SYNC_VERT_HIGH_ACT
) {
1729 if (pm2fb_options
.flags
& OPTF_LOW_VSYNC
) {
1730 DPRINTK("ignoring +vsync, using -vsync.\n");
1731 p
.video
|=PM2F_VSYNC_ACT_LOW
;
1733 p
.video
|=PM2F_VSYNC_ACT_HIGH
;
1736 p
.video
|=PM2F_VSYNC_ACT_LOW
;
1737 if ((var
->vmode
& FB_VMODE_MASK
)==FB_VMODE_INTERLACED
) {
1738 DPRINTK("interlaced not supported\n");
1741 if ((var
->vmode
& FB_VMODE_MASK
)==FB_VMODE_DOUBLE
)
1742 p
.video
|=PM2F_LINE_DOUBLE
;
1743 if (var
->activate
==FB_ACTIVATE_NOW
)
1744 p
.video
|=PM2F_VIDEO_ENABLE
;
1745 *((struct pm2fb_par
* )par
)=p
;
1749 #ifdef PM2FB_MASTER_DEBUG
1750 #undef pm2fb_decode_var
1752 static int pm2fb_decode_var(const struct fb_var_screeninfo
* var
,
1753 void* par
, struct fb_info_gen
* info
) {
1756 result
=pm2fb_wrapped_decode_var(var
, par
, info
);
1757 pm2fb_display_var(var
);
1762 static void pm2fb_par2var(struct fb_var_screeninfo
* v
,
1763 const struct pm2fb_par
* p
) {
1766 memset(v
, 0, sizeof(struct fb_var_screeninfo
));
1767 if (p
->flags
& PM2FF_ACCEL
)
1768 v
->accel_flags
|= FB_ACCELF_TEXT
;
1769 v
->xres_virtual
=p
->width
;
1770 v
->yres_virtual
=p
->height
;
1771 v
->xres
=(p
->htotal
+1)-p
->hbend
;
1772 v
->yres
=(p
->vtotal
+1)-p
->vbend
;
1773 v
->right_margin
=p
->hsstart
;
1774 v
->hsync_len
=p
->hsend
-p
->hsstart
;
1775 v
->left_margin
=p
->hbend
-p
->hsend
;
1776 v
->lower_margin
=p
->vsstart
+1;
1777 v
->vsync_len
=p
->vsend
-v
->lower_margin
+1;
1778 v
->upper_margin
=p
->vbend
-v
->lower_margin
-v
->vsync_len
;
1779 v
->bits_per_pixel
=p
->depth
;
1780 if (p
->video
& PM2F_DATA_64_ENABLE
) {
1782 v
->right_margin
=v
->right_margin
<<1;
1783 v
->hsync_len
=v
->hsync_len
<<1;
1784 v
->left_margin
=v
->left_margin
<<1;
1788 v
->red
.length
=v
->green
.length
=v
->blue
.length
=8;
1790 v
->right_margin
=v
->right_margin
<<2;
1791 v
->hsync_len
=v
->hsync_len
<<2;
1792 v
->left_margin
=v
->left_margin
<<2;
1801 v
->right_margin
=v
->right_margin
<<1;
1802 v
->hsync_len
=v
->hsync_len
<<1;
1803 v
->left_margin
=v
->left_margin
<<1;
1806 v
->transp
.offset
=24;
1809 v
->red
.length
=v
->green
.length
=v
->blue
.length
=
1815 v
->red
.length
=v
->green
.length
=v
->blue
.length
=8;
1816 v
->xres
=(v
->xres
<<2)/3;
1817 v
->right_margin
=(v
->right_margin
<<2)/3;
1818 v
->hsync_len
=(v
->hsync_len
<<2)/3;
1819 v
->left_margin
=(v
->left_margin
<<2)/3;
1822 base
=from3264(p
->base
, p
->depth
, 1);
1823 v
->xoffset
=base
%v
->xres
;
1824 v
->yoffset
=base
/v
->xres
;
1825 v
->height
=v
->width
=-1;
1826 v
->pixclock
=KHZ2PICOS(p
->pixclock
);
1827 if ((p
->video
& PM2F_HSYNC_MASK
)==PM2F_HSYNC_ACT_HIGH
)
1828 v
->sync
|=FB_SYNC_HOR_HIGH_ACT
;
1829 if ((p
->video
& PM2F_VSYNC_MASK
)==PM2F_VSYNC_ACT_HIGH
)
1830 v
->sync
|=FB_SYNC_VERT_HIGH_ACT
;
1831 if (p
->video
& PM2F_LINE_DOUBLE
)
1832 v
->vmode
=FB_VMODE_DOUBLE
;
1836 static int pm2fb_encode_var(struct fb_var_screeninfo
* var
,
1837 const void* par
, struct fb_info_gen
* info
) {
1839 pm2fb_par2var(var
, (struct pm2fb_par
* )par
);
1843 static void set_user_mode(struct pm2fb_info
* i
) {
1845 memcpy(&i
->current_par
, &pm2fb_options
.user_mode
,
1846 sizeof(i
->current_par
));
1847 if (pm2fb_options
.flags
& OPTF_YPAN
) {
1848 i
->current_par
.height
=i
->regions
.fb_size
/
1849 (i
->current_par
.width
*i
->current_par
.depth
/8);
1850 i
->current_par
.height
=MIN(i
->current_par
.height
,2047);
1851 i
->current_par
.height
=MAX(i
->current_par
.height
,
1852 pm2fb_options
.user_mode
.height
);
1856 static void pm2fb_get_par(void* par
, struct fb_info_gen
* info
) {
1857 struct pm2fb_info
* i
=(struct pm2fb_info
* )info
;
1859 if (!i
->current_par_valid
) {
1861 pm2fb_set_par(&i
->current_par
, info
);
1863 get_screen(i
, (struct pm2fb_par
* )par
);
1866 static void pm2fb_set_par(const void* par
, struct fb_info_gen
* info
) {
1867 struct pm2fb_info
* i
=(struct pm2fb_info
* )info
;
1868 struct pm2fb_par
* p
=(struct pm2fb_par
* )par
;
1870 if (screen_is_valid(i
)) {
1871 i
->current_par
.base
=p
->base
;
1872 if (!memcmp(p
, &i
->current_par
, sizeof(struct pm2fb_par
))) {
1874 pm2_WR(i
, PM2R_SCREEN_BASE
, p
->base
);
1883 i
->current_par_valid
=1;
1884 #ifdef PM2FB_HW_CURSOR
1886 pm2v_set_cursor_color(i
, cursor_color_map
,
1887 cursor_color_map
, cursor_color_map
);
1888 pm2v_set_cursor_shape(i
);
1893 static int pm2fb_getcolreg(unsigned regno
,
1894 unsigned* red
, unsigned* green
, unsigned* blue
,
1895 unsigned* transp
, struct fb_info
* info
) {
1896 struct pm2fb_info
* i
=(struct pm2fb_info
* )info
;
1899 *red
=i
->palette
[regno
].red
<<8|i
->palette
[regno
].red
;
1900 *green
=i
->palette
[regno
].green
<<8|i
->palette
[regno
].green
;
1901 *blue
=i
->palette
[regno
].blue
<<8|i
->palette
[regno
].blue
;
1902 *transp
=i
->palette
[regno
].transp
<<8|i
->palette
[regno
].transp
;
1907 static int pm2fb_setcolreg(unsigned regno
,
1908 unsigned red
, unsigned green
, unsigned blue
,
1909 unsigned transp
, struct fb_info
* info
) {
1910 struct pm2fb_info
* i
=(struct pm2fb_info
* )info
;
1913 switch (i
->current_par
.depth
) {
1914 #ifdef FBCON_HAS_CFB8
1918 #ifdef FBCON_HAS_CFB16
1920 i
->cmap
.cmap16
[regno
]=
1921 ((u32
)red
& 0xf800) |
1922 (((u32
)green
& 0xfc00)>>5) |
1923 (((u32
)blue
& 0xf800)>>11);
1926 #ifdef FBCON_HAS_CFB24
1928 i
->cmap
.cmap24
[regno
]=
1929 (((u32
)blue
& 0xff00) << 8) |
1930 ((u32
)green
& 0xff00) |
1931 (((u32
)red
& 0xff00) >> 8);
1934 #ifdef FBCON_HAS_CFB32
1936 i
->cmap
.cmap32
[regno
]=
1937 (((u32
)transp
& 0xff00) << 16) |
1938 (((u32
)red
& 0xff00) << 8) |
1939 (((u32
)green
& 0xff00)) |
1940 (((u32
)blue
& 0xff00) >> 8);
1944 DPRINTK("bad depth %u\n",
1945 i
->current_par
.depth
);
1950 i
->palette
[regno
].red
=red
>> 8;
1951 i
->palette
[regno
].green
=green
>> 8;
1952 i
->palette
[regno
].blue
=blue
>> 8;
1953 i
->palette
[regno
].transp
=transp
>> 8;
1954 if (i
->current_par
.depth
==8)
1955 set_color(i
, regno
, red
>>8, green
>>8, blue
>>8);
1960 static void pm2fb_set_disp(const void* par
, struct display
* disp
,
1961 struct fb_info_gen
* info
) {
1962 struct pm2fb_info
* i
=(struct pm2fb_info
* )info
;
1963 struct pm2fb_par
* p
=(struct pm2fb_par
* )par
;
1964 unsigned long flags
;
1966 local_irq_save(flags
);
1968 disp
->screen_base
=i
->regions
.v_fb
+ dense_mem(i
->regions
.v_fb
);
1970 disp
->screen_base
=i
->regions
.v_fb
;
1973 #ifdef FBCON_HAS_CFB8
1975 if (p
->flags
& PM2FF_ACCEL
)
1976 disp
->dispsw
=&pm2_cfb8
;
1978 disp
->dispsw
=&fbcon_cfb8
;
1981 #ifdef FBCON_HAS_CFB16
1983 if (p
->flags
& PM2FF_ACCEL
)
1984 disp
->dispsw
=&pm2_cfb16
;
1986 disp
->dispsw
=&fbcon_cfb16
;
1987 disp
->dispsw_data
=i
->cmap
.cmap16
;
1990 #ifdef FBCON_HAS_CFB24
1992 if (p
->flags
& PM2FF_ACCEL
)
1993 disp
->dispsw
=&pm2_cfb24
;
1995 disp
->dispsw
=&fbcon_cfb24
;
1996 disp
->dispsw_data
=i
->cmap
.cmap24
;
1999 #ifdef FBCON_HAS_CFB32
2001 if (p
->flags
& PM2FF_ACCEL
)
2002 disp
->dispsw
=&pm2_cfb32
;
2004 disp
->dispsw
=&fbcon_cfb32
;
2005 disp
->dispsw_data
=i
->cmap
.cmap32
;
2009 disp
->dispsw
=&fbcon_dummy
;
2012 local_irq_restore(flags
);
2015 #ifdef PM2FB_HW_CURSOR
2016 /***************************************************************************
2017 * Hardware cursor support
2018 ***************************************************************************/
2020 static u8 cursor_bits_lookup
[16] = {
2021 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
2022 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
2025 static u8 cursor_mask_lookup
[16] = {
2026 0x00, 0x80, 0x20, 0xa0, 0x08, 0x88, 0x28, 0xa8,
2027 0x02, 0x82, 0x22, 0xa2, 0x0a, 0x8a, 0x2a, 0xaa
2030 static void pm2v_set_cursor_color(struct pm2fb_info
*fb
, u8
*red
, u8
*green
, u8
*blue
)
2032 struct pm2_cursor
*c
= fb
->cursor
;
2035 for (i
= 0; i
< 2; i
++) {
2036 c
->color
[3*i
] = red
[i
];
2037 c
->color
[3*i
+1] = green
[i
];
2038 c
->color
[3*i
+2] = blue
[i
];
2042 pm2_WR(fb
, PM2VR_RD_INDEX_HIGH
, PM2VI_RD_CURSOR_PALETTE
>> 8);
2043 for (i
= 0; i
< 6; i
++)
2044 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_PALETTE
+i
, c
->color
[i
]);
2045 pm2_WR(fb
, PM2VR_RD_INDEX_HIGH
, 0);
2048 static void pm2v_set_cursor_shape(struct pm2fb_info
*fb
)
2050 struct pm2_cursor
*c
= fb
->cursor
;
2055 pm2_WR(fb
, PM2VR_RD_INDEX_HIGH
, PM2VI_RD_CURSOR_PATTERN
>> 8);
2056 for (y
= 0, i
= 0; y
< c
->size
.y
; y
++) {
2058 for (x
= 0; x
< c
->size
.x
>> 3; x
++) {
2061 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_PATTERN
+ i
,
2062 cursor_mask_lookup
[m
>> 4] |
2063 cursor_bits_lookup
[(b
& m
) >> 4]);
2064 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_PATTERN
+ i
+ 1,
2065 cursor_mask_lookup
[m
& 0x0f] |
2066 cursor_bits_lookup
[(b
& m
) & 0x0f]);
2069 for ( ; x
< 8; x
++) {
2070 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_PATTERN
+ i
, 0);
2071 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_PATTERN
+ i
+ 1, 0);
2075 for (; y
< 64; y
++) {
2077 for (x
= 0; x
< 8; x
++) {
2078 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_PATTERN
+ i
, 0);
2079 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_PATTERN
+ i
+ 1, 0);
2084 pm2_WR(fb
, PM2VR_RD_INDEX_HIGH
, 0);
2087 static void pm2v_set_cursor(struct pm2fb_info
*fb
, int on
)
2089 struct pm2_cursor
*c
= fb
->cursor
;
2094 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_X_LOW
, x
& 0xff);
2095 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_X_HIGH
, (x
>> 8) & 0x0f);
2096 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_Y_LOW
, c
->pos
.y
& 0xff);
2097 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_Y_HIGH
, (c
->pos
.y
>> 8) & 0x0f);
2098 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_X_HOT
, c
->hot
.x
& 0x3f);
2099 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_Y_HOT
, c
->hot
.y
& 0x3f);
2100 pm2v_RDAC_WR(fb
, PM2VI_RD_CURSOR_MODE
, 0x11);
2103 static void pm2_cursor_timer_handler(unsigned long dev_addr
)
2105 struct pm2fb_info
*fb
= (struct pm2fb_info
*)dev_addr
;
2107 if (!fb
->cursor
->enable
)
2110 if (fb
->cursor
->vbl_cnt
&& --fb
->cursor
->vbl_cnt
== 0) {
2111 fb
->cursor
->on
^= 1;
2112 pm2v_set_cursor(fb
, fb
->cursor
->on
);
2113 fb
->cursor
->vbl_cnt
= fb
->cursor
->blink_rate
;
2117 fb
->cursor
->timer
->expires
= jiffies
+ (HZ
/ 50);
2118 add_timer(fb
->cursor
->timer
);
2121 static void pm2fb_cursor(struct display
*p
, int mode
, int x
, int y
)
2123 struct pm2fb_info
*fb
= (struct pm2fb_info
*)p
->fb_info
;
2124 struct pm2_cursor
*c
= fb
->cursor
;
2130 if (c
->pos
.x
== x
&& c
->pos
.y
== y
&& (mode
== CM_ERASE
) == !c
->enable
)
2135 pm2v_set_cursor(fb
, 0);
2147 pm2v_set_cursor(fb
, 1);
2149 c
->vbl_cnt
= CURSOR_DRAW_DELAY
;
2155 static struct pm2_cursor
* __init
pm2_init_cursor(struct pm2fb_info
*fb
)
2157 struct pm2_cursor
*cursor
;
2159 if (fb
->type
!= PM2_TYPE_PERMEDIA2V
)
2160 return 0; /* FIXME: Support hw cursor everywhere */
2162 cursor
= kmalloc(sizeof(struct pm2_cursor
), GFP_ATOMIC
);
2165 memset(cursor
, 0, sizeof(*cursor
));
2167 cursor
->timer
= kmalloc(sizeof(*cursor
->timer
), GFP_KERNEL
);
2168 if (!cursor
->timer
) {
2172 memset(cursor
->timer
, 0, sizeof(*cursor
->timer
));
2174 cursor
->blink_rate
= DEFAULT_CURSOR_BLINK_RATE
;
2177 init_timer(cursor
->timer
);
2178 cursor
->timer
->expires
= jiffies
+ (HZ
/ 50);
2179 cursor
->timer
->data
= (unsigned long)fb
;
2180 cursor
->timer
->function
= pm2_cursor_timer_handler
;
2181 add_timer(cursor
->timer
);
2187 static int pm2fb_set_font(struct display
*d
, int width
, int height
)
2189 struct pm2fb_info
*fb
= (struct pm2fb_info
*)d
->fb_info
;
2190 struct pm2_cursor
*c
= fb
->cursor
;
2194 if (!width
|| !height
) {
2204 memset(c
->bits
, 0xff, sizeof(c
->bits
));
2205 memset(c
->mask
, 0, sizeof(c
->mask
));
2207 for (i
= 0, j
= width
; j
>= 0; j
-= 8, i
++) {
2208 c
->mask
[i
][height
-2] = (j
>= 8) ? 0xff : (0xff << (8 - j
));
2209 c
->mask
[i
][height
-1] = (j
>= 8) ? 0xff : (0xff << (8 - j
));
2212 pm2v_set_cursor_color(fb
, cursor_color_map
, cursor_color_map
, cursor_color_map
);
2213 pm2v_set_cursor_shape(fb
);
2217 #endif /* PM2FB_HW_CURSOR */
2219 /***************************************************************************
2220 * Begin of public functions
2221 ***************************************************************************/
2224 static void pm2fb_cleanup(void) {
2225 struct pm2fb_info
* i
=&fb_info
;
2227 unregister_framebuffer((struct fb_info
* )info
);
2230 UNMAP(i
->regions
.v_fb
, i
->regions
.fb_size
);
2231 release_mem_region(i
->regions
.p_fb
, i
->regions
.fb_size
);
2233 UNMAP(i
->regions
.v_regs
, PM2_REGS_SIZE
);
2234 release_mem_region(i
->regions
.p_regs
, PM2_REGS_SIZE
);
2236 if (board_table
[i
->board
].cleanup
)
2237 board_table
[i
->board
].cleanup(i
);
2241 int __init
pm2fb_init(void) {
2244 memset(&fb_info
, 0, sizeof(fb_info
));
2246 if (!pm2fb_conf(&fb_info
)) {
2251 /* Pick up user_var settings if set. */
2252 if ((pm2fb_options
.flags
& OPTF_USER_VAR
) &&
2253 pm2fb_decode_var(&user_var
, &pm2fb_options
.user_mode
,
2255 printk("pm2fb: user supplied var: mode is bad.\n");
2256 memcpy(&pm2fb_options
.user_mode
,
2257 &user_mode
[DEFAULT_USER_MODE
].par
,
2258 sizeof(struct pm2fb_par
));
2260 memcpy(&fb_info
.current_par
, &pm2fb_options
.user_mode
,
2261 sizeof(fb_info
.current_par
));
2263 pm2fb_reset(&fb_info
);
2264 fb_info
.disp
.scrollmode
=SCROLL_YNOMOVE
;
2265 fb_info
.gen
.parsize
=sizeof(struct pm2fb_par
);
2266 fb_info
.gen
.fbhw
=&pm2fb_hwswitch
;
2267 strcpy(fb_info
.gen
.info
.modename
, permedia2_name
);
2268 fb_info
.gen
.info
.flags
=FBINFO_FLAG_DEFAULT
;
2269 fb_info
.gen
.info
.fbops
=&pm2fb_ops
;
2270 fb_info
.gen
.info
.disp
=&fb_info
.disp
;
2271 strcpy(fb_info
.gen
.info
.fontname
, pm2fb_options
.font
);
2272 fb_info
.gen
.info
.switch_con
=&fbgen_switch
;
2273 fb_info
.gen
.info
.updatevar
=&fbgen_update_var
;
2275 fbgen_get_var(&fb_info
.disp
.var
, -1, &fb_info
.gen
.info
);
2276 fbgen_do_set_var(&fb_info
.disp
.var
, 1, &fb_info
.gen
);
2277 fbgen_set_disp(-1, &fb_info
.gen
);
2278 fbgen_install_cmap(0, &fb_info
.gen
);
2280 if (register_framebuffer(&fb_info
.gen
.info
)<0) {
2281 printk(KERN_ERR
"pm2fb: unable to register.\n");
2285 printk(KERN_INFO
"fb%d: %s (%s), using %uK of video memory.\n",
2286 fb_info
.gen
.info
.node
,
2287 board_table
[fb_info
.board
].name
,
2289 (u32
)(fb_info
.regions
.fb_size
>>10));
2293 static void __init
pm2fb_mode_setup(char* options
) {
2296 for (i
=0; user_mode
[i
].name
[0] &&
2297 strcmp(options
, user_mode
[i
].name
); i
++);
2298 if (user_mode
[i
].name
[0]) {
2299 memcpy(&pm2fb_options
.user_mode
, &user_mode
[i
].par
,
2300 sizeof(pm2fb_options
.user_mode
));
2301 pm2fb_options
.flags
|=OPTF_USER
;
2305 static void __init
pm2fb_font_setup(char* options
) {
2306 strlcpy(pm2fb_options
.font
, options
, sizeof(pm2fb_options
.font
));
2309 static void __init
pm2fb_var_setup(char* options
) {
2312 pm2fb_par2var(&user_var
, &pm2fb_options
.user_mode
);
2315 if ((next
=strchr(options
, ';')))
2317 if (!strncmp(options
, "bpp:", 4))
2318 user_var
.bits_per_pixel
=
2319 simple_strtoul(options
+4, NULL
, 0);
2320 else if (!strncmp(options
, "xres:", 5))
2321 user_var
.xres
=simple_strtoul(options
+5, NULL
, 0);
2322 else if (!strncmp(options
, "yres:", 5))
2323 user_var
.yres
=simple_strtoul(options
+5, NULL
, 0);
2324 else if (!strncmp(options
, "vxres:", 6))
2325 user_var
.xres_virtual
=
2326 simple_strtoul(options
+6, NULL
, 0);
2327 else if (!strncmp(options
, "vyres:", 6))
2328 user_var
.yres_virtual
=
2329 simple_strtoul(options
+6, NULL
, 0);
2330 else if (!strncmp(options
, "left:", 5))
2331 user_var
.left_margin
=
2332 simple_strtoul(options
+5, NULL
, 0);
2333 else if (!strncmp(options
, "right:", 6))
2334 user_var
.right_margin
=
2335 simple_strtoul(options
+6, NULL
, 0);
2336 else if (!strncmp(options
, "lower:", 6))
2337 user_var
.lower_margin
=
2338 simple_strtoul(options
+6, NULL
, 0);
2339 else if (!strncmp(options
, "upper:", 6))
2340 user_var
.upper_margin
=
2341 simple_strtoul(options
+6, NULL
, 0);
2342 else if (!strncmp(options
, "hslen:", 6))
2343 user_var
.hsync_len
=simple_strtoul(options
+6, NULL
, 0);
2344 else if (!strncmp(options
, "vslen:", 6))
2345 user_var
.vsync_len
=simple_strtoul(options
+6, NULL
, 0);
2346 else if (!strncmp(options
, "pixclock:", 9))
2347 user_var
.pixclock
=simple_strtoul(options
+9, NULL
, 0);
2348 else if (!strcmp(options
, "+hsync"))
2349 user_var
.sync
|=FB_SYNC_HOR_HIGH_ACT
;
2350 else if (!strcmp(options
, "-hsync"))
2351 user_var
.sync
&=~FB_SYNC_HOR_HIGH_ACT
;
2352 else if (!strcmp(options
, "+vsync"))
2353 user_var
.sync
|=FB_SYNC_VERT_HIGH_ACT
;
2354 else if (!strcmp(options
, "-vsync"))
2355 user_var
.sync
&=~FB_SYNC_VERT_HIGH_ACT
;
2356 else if (!strcmp(options
, "+double"))
2357 user_var
.vmode
|=FB_VMODE_DOUBLE
;
2358 else if (!strcmp(options
, "-double"))
2359 user_var
.vmode
&=~FB_VMODE_DOUBLE
;
2360 else if (!strcmp(options
, "+accel"))
2361 user_var
.accel_flags
|=FB_ACCELF_TEXT
;
2362 else if (!strcmp(options
, "-accel"))
2363 user_var
.accel_flags
&=~FB_ACCELF_TEXT
;
2366 pm2fb_options
.flags
|=OPTF_USER_VAR
;
2369 int __init
pm2fb_setup(char* options
) {
2373 if ((next
=strchr(options
, ',')))
2375 if (!strncmp(options
, "font:", 5))
2376 pm2fb_font_setup(options
+5);
2377 else if (!strncmp(options
, "mode:", 5))
2378 pm2fb_mode_setup(options
+5);
2379 else if (!strncmp(options
, "var:", 4))
2380 pm2fb_var_setup(options
+4);
2381 else if (!strcmp(options
, "ypan"))
2382 pm2fb_options
.flags
|= OPTF_YPAN
;
2383 else if (!strcmp(options
, "oldmem"))
2384 pm2fb_options
.flags
|= OPTF_OLD_MEM
;
2385 else if (!strcmp(options
, "virtual"))
2386 pm2fb_options
.flags
|= OPTF_VIRTUAL
;
2387 else if (!strcmp(options
, "lowhsync"))
2388 pm2fb_options
.flags
|= OPTF_LOW_HSYNC
;
2389 else if (!strcmp(options
, "lowvsync"))
2390 pm2fb_options
.flags
|= OPTF_LOW_VSYNC
;
2391 else if (!strcmp(options
, "noblink"))
2395 user_var
.activate
=FB_ACTIVATE_NOW
;
2399 /***************************************************************************
2400 * Begin of module functions
2401 ***************************************************************************/
2405 MODULE_LICENSE("GPL");
2407 static char *mode
= NULL
;
2409 MODULE_PARM(mode
, "s");
2411 int init_module(void) {
2414 pm2fb_mode_setup(mode
);
2415 return pm2fb_init();
2418 void cleanup_module(void) {
2424 /***************************************************************************
2426 ***************************************************************************/