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 #define arraysize(x) (sizeof(x)/sizeof(*(x)))
82 static int currcon
= 0;
83 static struct display disp
;
84 static struct fb_info fb_info
;
85 static struct { u_char red
, green
, blue
, pad
; } palette
[256];
87 static struct fb_fix_screeninfo fb_fix
= { { "G364 8plane", } };
88 static struct fb_var_screeninfo fb_var
= { 0, };
92 * Interface used by the world
94 static int g364fb_open(struct fb_info
*info
, int user
);
95 static int g364fb_release(struct fb_info
*info
, int user
);
96 static int g364fb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
97 struct fb_info
*info
);
98 static int g364fb_get_var(struct fb_var_screeninfo
*var
, int con
,
99 struct fb_info
*info
);
100 static int g364fb_set_var(struct fb_var_screeninfo
*var
, int con
,
101 struct fb_info
*info
);
102 static int g364fb_pan_display(struct fb_var_screeninfo
*var
, int con
,
103 struct fb_info
*info
);
104 static int g364fb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
105 struct fb_info
*info
);
106 static int g364fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
107 struct fb_info
*info
);
108 static int g364fb_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
109 u_long arg
, int con
, struct fb_info
*info
);
113 * Interface to the low level console driver
115 int g364fb_init(void);
116 static int g364fbcon_switch(int con
, struct fb_info
*info
);
117 static int g364fbcon_updatevar(int con
, struct fb_info
*info
);
118 static void g364fbcon_blank(int blank
, struct fb_info
*info
);
124 static int g364fb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
125 u_int
*transp
, struct fb_info
*info
);
126 static int g364fb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
127 u_int transp
, struct fb_info
*info
);
128 static void do_install_cmap(int con
, struct fb_info
*info
);
131 static struct fb_ops g364fb_ops
= {
132 g364fb_open
, g364fb_release
, g364fb_get_fix
, g364fb_get_var
, g364fb_set_var
,
133 g364fb_get_cmap
, g364fb_set_cmap
, g364fb_pan_display
, g364fb_ioctl
137 void fbcon_g364fb_cursor(struct display
*p
, int mode
, int x
, int y
)
141 *(unsigned int *) CTLA_REG
|= CURS_TOGGLE
;
146 *(unsigned int *) CTLA_REG
&= ~CURS_TOGGLE
;
147 *(unsigned int *) CURS_POS_REG
= ((x
* fontwidth(p
)) << 12) | ((y
* fontheight(p
))-p
->var
.yoffset
);
153 static struct display_switch fbcon_g364cfb8
= {
154 fbcon_cfb8_setup
, fbcon_cfb8_bmove
, fbcon_cfb8_clear
, fbcon_cfb8_putc
,
155 fbcon_cfb8_putcs
, fbcon_cfb8_revc
, fbcon_g364fb_cursor
, NULL
,
156 fbcon_cfb8_clear_margins
, FONTWIDTH(8)
161 * Open/Release the frame buffer device
163 static int g364fb_open(struct fb_info
*info
, int user
)
166 * Nothing, only a usage count for the moment
172 static int g364fb_release(struct fb_info
*info
, int user
)
180 * Get the Fixed Part of the Display
182 static int g364fb_get_fix(struct fb_fix_screeninfo
*fix
, int con
,
183 struct fb_info
*info
)
185 memcpy(fix
, &fb_fix
, sizeof(fb_fix
));
191 * Get the User Defined Part of the Display
193 static int g364fb_get_var(struct fb_var_screeninfo
*var
, int con
,
194 struct fb_info
*info
)
196 memcpy(var
, &fb_var
, sizeof(fb_var
));
202 * Set the User Defined Part of the Display
204 static int g364fb_set_var(struct fb_var_screeninfo
*var
, int con
,
205 struct fb_info
*info
)
207 struct display
*display
;
208 int oldbpp
= -1, err
;
211 display
= &fb_display
[con
];
213 display
= &disp
; /* used during initialization */
215 if (var
->xres
> fb_var
.xres
|| var
->yres
> fb_var
.yres
||
216 var
->xres_virtual
> fb_var
.xres_virtual
||
217 var
->yres_virtual
> fb_var
.yres_virtual
||
218 var
->bits_per_pixel
> fb_var
.bits_per_pixel
||
220 (var
->vmode
& FB_VMODE_MASK
) != FB_VMODE_NONINTERLACED
)
222 memcpy(var
, &fb_var
, sizeof(fb_var
));
224 if ((var
->activate
& FB_ACTIVATE_MASK
) == FB_ACTIVATE_NOW
) {
225 oldbpp
= display
->var
.bits_per_pixel
;
227 *(unsigned int *)TOP_REG
= var
->yoffset
* var
->xres
;
229 if (oldbpp
!= var
->bits_per_pixel
) {
230 if ((err
= fb_alloc_cmap(&display
->cmap
, 0, 0)))
232 do_install_cmap(con
, info
);
239 * Pan or Wrap the Display
241 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
243 static int g364fb_pan_display(struct fb_var_screeninfo
*var
, int con
,
244 struct fb_info
*info
)
246 if (var
->xoffset
|| var
->yoffset
+var
->yres
> var
->yres_virtual
)
249 *(unsigned int *)TOP_REG
= var
->yoffset
* var
->xres
;
256 static int g364fb_get_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
257 struct fb_info
*info
)
259 if (con
== currcon
) /* current console? */
260 return fb_get_cmap(cmap
, kspc
, g364fb_getcolreg
, info
);
261 else if (fb_display
[con
].cmap
.len
) /* non default colormap? */
262 fb_copy_cmap(&fb_display
[con
].cmap
, cmap
, kspc
? 0 : 2);
264 fb_copy_cmap(fb_default_cmap(1<<fb_display
[con
].var
.bits_per_pixel
),
272 static int g364fb_set_cmap(struct fb_cmap
*cmap
, int kspc
, int con
,
273 struct fb_info
*info
)
277 if (!fb_display
[con
].cmap
.len
) { /* no colormap allocated? */
278 if ((err
= fb_alloc_cmap(&fb_display
[con
].cmap
,
279 1<<fb_display
[con
].var
.bits_per_pixel
, 0)))
282 if (con
== currcon
) { /* current console? */
283 return fb_set_cmap(cmap
, kspc
, g364fb_setcolreg
, info
);
285 fb_copy_cmap(cmap
, &fb_display
[con
].cmap
, kspc
? 0 : 1);
290 static int g364fb_ioctl(struct inode
*inode
, struct file
*file
, u_int cmd
,
291 u_long arg
, int con
, struct fb_info
*info
)
300 int __init
g364fb_init(void)
303 volatile unsigned int *pal_ptr
= (volatile unsigned int *) CLR_PAL_REG
;
304 volatile unsigned int *curs_pal_ptr
= (volatile unsigned int *) CURS_PAL_REG
;
305 unsigned int xres
, yres
;
308 /* TBD: G364 detection */
310 /* get the resolution set by ARC console */
311 *(volatile unsigned int *)CTLA_REG
&= ~ENABLE_VTG
;
312 xres
= (*((volatile unsigned int*)DISPLAY_REG
) & 0x00ffffff) * 4;
313 yres
= (*((volatile unsigned int*)VDISPLAY_REG
) & 0x00ffffff) / 2;
314 *(volatile unsigned int *)CTLA_REG
|= ENABLE_VTG
;
316 /* initialise color palette */
317 for (i
= 0; i
< 16; i
++) {
319 palette
[i
].red
=default_red
[j
];
320 palette
[i
].green
=default_grn
[j
];
321 palette
[i
].blue
=default_blu
[j
];
322 pal_ptr
[i
<< 1] = (palette
[i
].red
<< 16) | (palette
[i
].green
<< 8) | palette
[i
].blue
;
326 curs_pal_ptr
[0] |= 0x00ffffff;
327 curs_pal_ptr
[2] |= 0x00ffffff;
328 curs_pal_ptr
[4] |= 0x00ffffff;
331 * first set the whole cursor to transparent
333 for (i
= 0; i
< 512; i
++)
334 *(unsigned short *)(CURS_PAT_REG
+i
*8) = 0;
337 * switch the last two lines to cursor palette 3
338 * we assume here, that FONTSIZE_X is 8
340 *(unsigned short *)(CURS_PAT_REG
+ 14*64) = 0xffff;
341 *(unsigned short *)(CURS_PAT_REG
+ 15*64) = 0xffff;
343 fb_var
.bits_per_pixel
= 8;
344 fb_var
.xres
= fb_var
.xres_virtual
= xres
;
347 fb_fix
.line_length
= (xres
/ 8) * fb_var
.bits_per_pixel
;
348 fb_fix
.smem_start
= 0x40000000; /* physical address */
349 /* get size of video memory; this is special for the JAZZ hardware */
350 mem
= (r4030_read_reg32(JAZZ_R4030_CONFIG
) >> 8) & 3;
351 fb_fix
.smem_len
= (1 << (mem
*2)) * 512 * 1024;
352 fb_fix
.type
= FB_TYPE_PACKED_PIXELS
;
354 fb_fix
.visual
= FB_VISUAL_PSEUDOCOLOR
;
357 fb_fix
.ywrapstep
= 0;
358 fb_fix
.mmio_start
= 0;
360 fb_fix
.accel
= FB_ACCEL_NONE
;
362 fb_var
.yres_virtual
= fb_fix
.smem_len
/ xres
;
363 fb_var
.xoffset
= fb_var
.yoffset
= 0;
364 fb_var
.grayscale
= 0;
366 fb_var
.red
.offset
= 0;
367 fb_var
.green
.offset
= 0;
368 fb_var
.blue
.offset
= 0;
370 fb_var
.red
.length
= fb_var
.green
.length
= fb_var
.blue
.length
= 8;
371 fb_var
.red
.msb_right
= fb_var
.green
.msb_right
= fb_var
.blue
.msb_right
= 0;
372 fb_var
.transp
.offset
= fb_var
.transp
.length
= fb_var
.transp
.msb_right
= 0;
375 fb_var
.height
= fb_var
.width
= -1;
376 fb_var
.accel_flags
= 0;
377 fb_var
.pixclock
= 39722;
378 fb_var
.left_margin
= 40;
379 fb_var
.right_margin
= 24;
380 fb_var
.upper_margin
= 32;
381 fb_var
.lower_margin
= 11;
382 fb_var
.hsync_len
= 96;
383 fb_var
.vsync_len
= 2;
385 fb_var
.vmode
= FB_VMODE_NONINTERLACED
;
390 disp
.cmap
.red
= disp
.cmap
.green
= disp
.cmap
.blue
= disp
.cmap
.transp
= NULL
;
391 disp
.screen_base
= (char *)G364_MEM_BASE
; /* virtual kernel address */
392 disp
.visual
= fb_fix
.visual
;
393 disp
.type
= fb_fix
.type
;
394 disp
.type_aux
= fb_fix
.type_aux
;
395 disp
.ypanstep
= fb_fix
.ypanstep
;
396 disp
.ywrapstep
= fb_fix
.ywrapstep
;
397 disp
.line_length
= fb_fix
.line_length
;
398 disp
.can_soft_blank
= 1;
400 disp
.dispsw
= &fbcon_g364cfb8
;
402 strcpy(fb_info
.modename
, fb_fix
.id
);
404 fb_info
.fbops
= &g364fb_ops
;
405 fb_info
.disp
= &disp
;
406 fb_info
.fontname
[0] = '\0';
407 fb_info
.changevar
= NULL
;
408 fb_info
.switch_con
= &g364fbcon_switch
;
409 fb_info
.updatevar
= &g364fbcon_updatevar
;
410 fb_info
.blank
= &g364fbcon_blank
;
411 fb_info
.flags
= FBINFO_FLAG_DEFAULT
;
413 g364fb_set_var(&fb_var
, -1, &fb_info
);
415 if (register_framebuffer(&fb_info
) < 0)
418 printk("fb%d: %s frame buffer device\n", GET_FB_IDX(fb_info
.node
),
424 static int g364fbcon_switch(int con
, struct fb_info
*info
)
426 /* Do we have to save the colormap? */
427 if (fb_display
[currcon
].cmap
.len
)
428 fb_get_cmap(&fb_display
[currcon
].cmap
, 1, g364fb_getcolreg
, info
);
431 /* Install new colormap */
432 do_install_cmap(con
, info
);
433 g364fbcon_updatevar(con
, info
);
438 * Update the `var' structure (called by fbcon.c)
440 static int g364fbcon_updatevar(int con
, struct fb_info
*info
)
442 if (con
== currcon
) {
443 struct fb_var_screeninfo
*var
= &fb_display
[currcon
].var
;
445 /* hardware scrolling */
446 *(unsigned int *)TOP_REG
= var
->yoffset
* var
->xres
;
454 static void g364fbcon_blank(int blank
, struct fb_info
*info
)
457 *(unsigned int *) CTLA_REG
|= FORCE_BLANK
;
459 *(unsigned int *) CTLA_REG
&= ~FORCE_BLANK
;
463 * Read a single color register and split it into
464 * colors/transparent. Return != 0 for invalid regno.
466 static int g364fb_getcolreg(u_int regno
, u_int
*red
, u_int
*green
, u_int
*blue
,
467 u_int
*transp
, struct fb_info
*info
)
471 *red
= (palette
[regno
].red
<< 8) | palette
[regno
].red
;
472 *green
= (palette
[regno
].green
<< 8) | palette
[regno
].green
;
473 *blue
= (palette
[regno
].blue
<< 8) | palette
[regno
].blue
;
479 * Set a single color register. Return != 0 for invalid regno.
481 static int g364fb_setcolreg(u_int regno
, u_int red
, u_int green
, u_int blue
,
482 u_int transp
, struct fb_info
*info
)
484 volatile unsigned int *ptr
= (volatile unsigned int *) CLR_PAL_REG
;
492 palette
[regno
].red
= red
;
493 palette
[regno
].green
= green
;
494 palette
[regno
].blue
= blue
;
496 ptr
[regno
<< 1] = (red
<< 16) | (green
<< 8) | blue
;
502 static void do_install_cmap(int con
, struct fb_info
*info
)
506 if (fb_display
[con
].cmap
.len
)
507 fb_set_cmap(&fb_display
[con
].cmap
, 1, g364fb_setcolreg
, info
);
509 fb_set_cmap(fb_default_cmap(1<<fb_display
[con
].var
.bits_per_pixel
), 1,
510 g364fb_setcolreg
, info
);