1 /* $Id: g364fb.c,v 1.3 1998/08/28 22:43:00 tsbogend Exp $
3 * linux/drivers/video/g364fb.c -- Mips Magnum frame buffer device
5 * (C) 1998 Thomas Bogendoerfer
7 * This driver is based on tgafb.c
9 * Copyright (C) 1997 Geert Uytterhoeven
10 * Copyright (C) 1995 Jay Estabrook
12 * This file is subject to the terms and conditions of the GNU General Public
13 * License. See the file COPYING in the main directory of this archive for
17 #include <linux/module.h>
18 #include <linux/sched.h>
19 #include <linux/kernel.h>
20 #include <linux/errno.h>
21 #include <linux/string.h>
23 #include <linux/tty.h>
24 #include <linux/malloc.h>
25 #include <linux/vmalloc.h>
26 #include <linux/delay.h>
27 #include <linux/interrupt.h>
29 #include <linux/init.h>
30 #include <linux/pci.h>
31 #include <linux/selection.h>
32 #include <linux/console.h>
36 #include <video/fbcon.h>
37 #include <video/fbcon-cfb8.h>
40 * Various defines for the G364
42 #define G364_MEM_BASE 0xe4400000
43 #define G364_PORT_BASE 0xe4000000
44 #define ID_REG 0xe4000000 /* Read only */
45 #define BOOT_REG 0xe4080000
46 #define TIMING_REG 0xe4080108 /* to 0x080170 - DON'T TOUCH! */
47 #define DISPLAY_REG 0xe4080118
48 #define VDISPLAY_REG 0xe4080150
49 #define MASK_REG 0xe4080200
50 #define CTLA_REG 0xe4080300
51 #define CURS_TOGGLE 0x800000
52 #define BIT_PER_PIX 0x700000 /* bits 22 to 20 of Control A */
53 #define DELAY_SAMPLE 0x080000
54 #define PORT_INTER 0x040000
55 #define PIX_PIPE_DEL 0x030000 /* bits 17 and 16 of Control A */
56 #define PIX_PIPE_DEL2 0x008000 /* same as above - don't ask me why */
57 #define TR_CYCLE_TOG 0x004000
58 #define VRAM_ADR_INC 0x003000 /* bits 13 and 12 of Control A */
59 #define BLANK_OFF 0x000800
60 #define FORCE_BLANK 0x000400
61 #define BLK_FUN_SWTCH 0x000200
62 #define BLANK_IO 0x000100
63 #define BLANK_LEVEL 0x000080
64 #define A_VID_FORM 0x000040
65 #define D_SYNC_FORM 0x000020
66 #define FRAME_FLY_PAT 0x000010
67 #define OP_MODE 0x000008
68 #define INTL_STAND 0x000004
69 #define SCRN_FORM 0x000002
70 #define ENABLE_VTG 0x000001
71 #define TOP_REG 0xe4080400
72 #define CURS_PAL_REG 0xe4080508 /* to 0x080518 */
73 #define CHKSUM_REG 0xe4080600 /* to 0x080610 - unused */
74 #define CURS_POS_REG 0xe4080638
75 #define CLR_PAL_REG 0xe4080800 /* to 0x080ff8 */
76 #define CURS_PAT_REG 0xe4081000 /* to 0x081ff8 */
77 #define MON_ID_REG 0xe4100000 /* unused */
78 #define RESET_REG 0xe4180000 /* Write only */
80 static int currcon
= 0;
81 static struct display disp
;
82 static struct fb_info fb_info
;
83 static struct { u_char red
, green
, blue
, pad
; } palette
[256];
85 static struct fb_fix_screeninfo fb_fix
= { { "G364 8plane", } };
86 static struct fb_var_screeninfo fb_var
= { 0, };
90 * Interface used by the world
92 static int g364fb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
93 struct fb_info
*info
);
94 static int g364fb_get_var(struct fb_var_screeninfo
*var
, int con
,
95 struct fb_info
*info
);
96 static int g364fb_set_var(struct fb_var_screeninfo
*var
, int con
,
97 struct fb_info
*info
);
98 static int g364fb_pan_display(struct fb_var_screeninfo
*var
, int con
,
99 struct fb_info
*info
);
100 static int g364fb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
101 struct fb_info
*info
);
102 static int g364fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
103 struct fb_info
*info
);
107 * Interface to the low level console driver
109 int g364fb_init(void);
110 static int g364fbcon_switch(int con
, struct fb_info
*info
);
111 static int g364fbcon_updatevar(int con
, struct fb_info
*info
);
112 static void g364fbcon_blank(int blank
, struct fb_info
*info
);
118 static int g364fb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
119 u_int
*transp
, struct fb_info
*info
);
120 static int g364fb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
121 u_int transp
, struct fb_info
*info
);
122 static void do_install_cmap(int con
, struct fb_info
*info
);
125 static struct fb_ops g364fb_ops
= {
127 fb_get_fix
: g364fb_get_fix
,
128 fb_get_var
: g364fb_get_var
,
129 fb_set_var
: g364fb_set_var
,
130 fb_get_cmap
: g364fb_get_cmap
,
131 fb_set_cmap
: g364fb_set_cmap
,
132 fb_pan_display
: g364fb_pan_display
,
136 void fbcon_g364fb_cursor(struct display
*p
, int mode
, int x
, int y
)
140 *(unsigned int *) CTLA_REG
|= CURS_TOGGLE
;
145 *(unsigned int *) CTLA_REG
&= ~CURS_TOGGLE
;
146 *(unsigned int *) CURS_POS_REG
= ((x
* fontwidth(p
)) << 12) | ((y
* fontheight(p
))-p
->var
.yoffset
);
152 static struct display_switch fbcon_g364cfb8
= {
153 setup
: fbcon_cfb8_setup
,
154 bmove
: fbcon_cfb8_bmove
,
155 clear
: fbcon_cfb8_clear
,
156 putc
: fbcon_cfb8_putc
,
157 putcs
: fbcon_cfb8_putcs
,
158 revc
: fbcon_cfb8_revc
,
159 cursor
: fbcon_g364fb_cursor
,
160 clear_margins
: fbcon_cfb8_clear_margins
,
161 fontwidthmask
: FONTWIDTH(8)
165 * Get the Fixed Part of the Display
167 static int g364fb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
168 struct fb_info
*info
)
170 memcpy(fix
, &fb_fix
, sizeof(fb_fix
));
176 * Get the User Defined Part of the Display
178 static int g364fb_get_var(struct fb_var_screeninfo
*var
, int con
,
179 struct fb_info
*info
)
181 memcpy(var
, &fb_var
, sizeof(fb_var
));
187 * Set the User Defined Part of the Display
189 static int g364fb_set_var(struct fb_var_screeninfo
*var
, int con
,
190 struct fb_info
*info
)
192 struct display
*display
;
193 int oldbpp
= -1, err
;
196 display
= &fb_display
[con
];
198 display
= &disp
; /* used during initialization */
200 if (var
->xres
> fb_var
.xres
|| var
->yres
> fb_var
.yres
||
201 var
->xres_virtual
> fb_var
.xres_virtual
||
202 var
->yres_virtual
> fb_var
.yres_virtual
||
203 var
->bits_per_pixel
> fb_var
.bits_per_pixel
||
205 (var
->vmode
& FB_VMODE_MASK
) != FB_VMODE_NONINTERLACED
)
207 memcpy(var
, &fb_var
, sizeof(fb_var
));
209 if ((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
210 oldbpp
= display
->var
.bits_per_pixel
;
212 *(unsigned int *)TOP_REG
= var
->yoffset
* var
->xres
;
214 if (oldbpp
!= var
->bits_per_pixel
) {
215 if ((err
= fb_alloc_cmap(&display
->cmap
, 0, 0)))
217 do_install_cmap(con
, info
);
224 * Pan or Wrap the Display
226 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
228 static int g364fb_pan_display(struct fb_var_screeninfo
*var
, int con
,
229 struct fb_info
*info
)
231 if (var
->xoffset
|| var
->yoffset
+var
->yres
> var
->yres_virtual
)
234 *(unsigned int *)TOP_REG
= var
->yoffset
* var
->xres
;
241 static int g364fb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
242 struct fb_info
*info
)
244 if (con
== currcon
) /* current console? */
245 return fb_get_cmap(cmap
, kspc
, g364fb_getcolreg
, info
);
246 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
247 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
249 fb_copy_cmap(fb_default_cmap(1<<fb_display
[con
].var
.bits_per_pixel
),
257 static int g364fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
258 struct fb_info
*info
)
262 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated? */
263 if ((err
= fb_alloc_cmap(&fb_display
[con
].cmap
,
264 1<<fb_display
[con
].var
.bits_per_pixel
, 0)))
267 if (con
== currcon
) { /* current console? */
268 return fb_set_cmap(cmap
, kspc
, g364fb_setcolreg
, info
);
270 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
278 int __init
g364fb_init(void)
281 volatile unsigned int *pal_ptr
= (volatile unsigned int *) CLR_PAL_REG
;
282 volatile unsigned int *curs_pal_ptr
= (volatile unsigned int *) CURS_PAL_REG
;
283 unsigned int xres
, yres
;
286 /* TBD: G364 detection */
288 /* get the resolution set by ARC console */
289 *(volatile unsigned int *)CTLA_REG
&= ~ENABLE_VTG
;
290 xres
= (*((volatile unsigned int*)DISPLAY_REG
) & 0x00ffffff) * 4;
291 yres
= (*((volatile unsigned int*)VDISPLAY_REG
) & 0x00ffffff) / 2;
292 *(volatile unsigned int *)CTLA_REG
|= ENABLE_VTG
;
294 /* initialise color palette */
295 for (i
= 0; i
< 16; i
++) {
297 palette
[i
].red
=default_red
[j
];
298 palette
[i
].green
=default_grn
[j
];
299 palette
[i
].blue
=default_blu
[j
];
300 pal_ptr
[i
<< 1] = (palette
[i
].red
<< 16) | (palette
[i
].green
<< 8) | palette
[i
].blue
;
304 curs_pal_ptr
[0] |= 0x00ffffff;
305 curs_pal_ptr
[2] |= 0x00ffffff;
306 curs_pal_ptr
[4] |= 0x00ffffff;
309 * first set the whole cursor to transparent
311 for (i
= 0; i
< 512; i
++)
312 *(unsigned short *)(CURS_PAT_REG
+i
*8) = 0;
315 * switch the last two lines to cursor palette 3
316 * we assume here, that FONTSIZE_X is 8
318 *(unsigned short *)(CURS_PAT_REG
+ 14*64) = 0xffff;
319 *(unsigned short *)(CURS_PAT_REG
+ 15*64) = 0xffff;
321 fb_var
.bits_per_pixel
= 8;
322 fb_var
.xres
= fb_var
.xres_virtual
= xres
;
325 fb_fix
.line_length
= (xres
/ 8) * fb_var
.bits_per_pixel
;
326 fb_fix
.smem_start
= 0x40000000; /* physical address */
327 /* get size of video memory; this is special for the JAZZ hardware */
328 mem
= (r4030_read_reg32(JAZZ_R4030_CONFIG
) >> 8) & 3;
329 fb_fix
.smem_len
= (1 << (mem
*2)) * 512 * 1024;
330 fb_fix
.type
= FB_TYPE_PACKED_PIXELS
;
332 fb_fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
335 fb_fix
.ywrapstep
= 0;
336 fb_fix
.mmio_start
= 0;
338 fb_fix
.accel
= FB_ACCEL_NONE
;
340 fb_var
.yres_virtual
= fb_fix
.smem_len
/ xres
;
341 fb_var
.xoffset
= fb_var
.yoffset
= 0;
342 fb_var
.grayscale
= 0;
344 fb_var
.red
.offset
= 0;
345 fb_var
.green
.offset
= 0;
346 fb_var
.blue
.offset
= 0;
348 fb_var
.red
.length
= fb_var
.green
.length
= fb_var
.blue
.length
= 8;
349 fb_var
.red
.msb_right
= fb_var
.green
.msb_right
= fb_var
.blue
.msb_right
= 0;
350 fb_var
.transp
.offset
= fb_var
.transp
.length
= fb_var
.transp
.msb_right
= 0;
353 fb_var
.height
= fb_var
.width
= -1;
354 fb_var
.accel_flags
= 0;
355 fb_var
.pixclock
= 39722;
356 fb_var
.left_margin
= 40;
357 fb_var
.right_margin
= 24;
358 fb_var
.upper_margin
= 32;
359 fb_var
.lower_margin
= 11;
360 fb_var
.hsync_len
= 96;
361 fb_var
.vsync_len
= 2;
363 fb_var
.vmode
= FB_VMODE_NONINTERLACED
;
368 disp
.cmap
.red
= disp
.cmap
.green
= disp
.cmap
.blue
= disp
.cmap
.transp
= NULL
;
369 disp
.screen_base
= (char *)G364_MEM_BASE
; /* virtual kernel address */
370 disp
.visual
= fb_fix
.visual
;
371 disp
.type
= fb_fix
.type
;
372 disp
.type_aux
= fb_fix
.type_aux
;
373 disp
.ypanstep
= fb_fix
.ypanstep
;
374 disp
.ywrapstep
= fb_fix
.ywrapstep
;
375 disp
.line_length
= fb_fix
.line_length
;
376 disp
.can_soft_blank
= 1;
378 disp
.dispsw
= &fbcon_g364cfb8
;
380 strcpy(fb_info
.modename
, fb_fix
.id
);
382 fb_info
.fbops
= &g364fb_ops
;
383 fb_info
.disp
= &disp
;
384 fb_info
.fontname
[0] = '\0';
385 fb_info
.changevar
= NULL
;
386 fb_info
.switch_con
= &g364fbcon_switch
;
387 fb_info
.updatevar
= &g364fbcon_updatevar
;
388 fb_info
.blank
= &g364fbcon_blank
;
389 fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
391 g364fb_set_var(&fb_var
, -1, &fb_info
);
393 if (register_framebuffer(&fb_info
) < 0)
396 printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info
.node
),
402 static int g364fbcon_switch(int con
, struct fb_info
*info
)
404 /* Do we have to save the colormap? */
405 if (fb_display
[currcon
].cmap
.len
)
406 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, g364fb_getcolreg
, info
);
409 /* Install new colormap */
410 do_install_cmap(con
, info
);
411 g364fbcon_updatevar(con
, info
);
416 * Update the `var' structure (called by fbcon.c)
418 static int g364fbcon_updatevar(int con
, struct fb_info
*info
)
420 if (con
== currcon
) {
421 struct fb_var_screeninfo
*var
= &fb_display
[currcon
].var
;
423 /* hardware scrolling */
424 *(unsigned int *)TOP_REG
= var
->yoffset
* var
->xres
;
432 static void g364fbcon_blank(int blank
, struct fb_info
*info
)
435 *(unsigned int *) CTLA_REG
|= FORCE_BLANK
;
437 *(unsigned int *) CTLA_REG
&= ~FORCE_BLANK
;
441 * Read a single color register and split it into
442 * colors/transparent. Return != 0 for invalid regno.
444 static int g364fb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
445 u_int
*transp
, struct fb_info
*info
)
449 *red
= (palette
[regno
].red
<< 8) | palette
[regno
].red
;
450 *green
= (palette
[regno
].green
<< 8) | palette
[regno
].green
;
451 *blue
= (palette
[regno
].blue
<< 8) | palette
[regno
].blue
;
457 * Set a single color register. Return != 0 for invalid regno.
459 static int g364fb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
460 u_int transp
, struct fb_info
*info
)
462 volatile unsigned int *ptr
= (volatile unsigned int *) CLR_PAL_REG
;
470 palette
[regno
].red
= red
;
471 palette
[regno
].green
= green
;
472 palette
[regno
].blue
= blue
;
474 ptr
[regno
<< 1] = (red
<< 16) | (green
<< 8) | blue
;
480 static void do_install_cmap(int con
, struct fb_info
*info
)
484 if (fb_display
[con
].cmap
.len
)
485 fb_set_cmap(&fb_display
[con
].cmap
, 1, g364fb_setcolreg
, info
);
487 fb_set_cmap(fb_default_cmap(1<<fb_display
[con
].var
.bits_per_pixel
), 1,
488 g364fb_setcolreg
, info
);