1 /* $Id: cgthreefb.c,v 1.5 1999/08/10 15:56:04 davem Exp $
2 * cgthreefb.c: CGthree frame buffer driver
4 * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
5 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
6 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
9 #include <linux/module.h>
10 #include <linux/sched.h>
11 #include <linux/kernel.h>
12 #include <linux/errno.h>
13 #include <linux/string.h>
15 #include <linux/tty.h>
16 #include <linux/malloc.h>
17 #include <linux/vmalloc.h>
18 #include <linux/delay.h>
19 #include <linux/interrupt.h>
21 #include <linux/init.h>
22 #include <linux/selection.h>
24 #include <video/sbusfb.h>
27 #include <video/fbcon-cfb8.h>
29 /* Control Register Constants */
30 #define CG3_CR_ENABLE_INTS 0x80
31 #define CG3_CR_ENABLE_VIDEO 0x40
32 #define CG3_CR_ENABLE_TIMING 0x20
33 #define CG3_CR_ENABLE_CURCMP 0x10
34 #define CG3_CR_XTAL_MASK 0x0c
35 #define CG3_CR_DIVISOR_MASK 0x03
37 /* Status Register Constants */
38 #define CG3_SR_PENDING_INT 0x80
39 #define CG3_SR_RES_MASK 0x70
40 #define CG3_SR_1152_900_76_A 0x40
41 #define CG3_SR_1152_900_76_B 0x60
42 #define CG3_SR_ID_MASK 0x0f
43 #define CG3_SR_ID_COLOR 0x01
44 #define CG3_SR_ID_MONO 0x02
45 #define CG3_SR_ID_MONO_ECL 0x03
57 volatile u8 cursor_start
;
58 volatile u8 cursor_end
;
59 volatile u8 h_blank_start
;
60 volatile u8 h_blank_end
;
61 volatile u8 h_sync_start
;
62 volatile u8 h_sync_end
;
63 volatile u8 comp_sync_end
;
64 volatile u8 v_blank_start_high
;
65 volatile u8 v_blank_start_low
;
66 volatile u8 v_blank_end
;
67 volatile u8 v_sync_start
;
68 volatile u8 v_sync_end
;
69 volatile u8 xfer_holdoff_start
;
70 volatile u8 xfer_holdoff_end
;
73 /* Offset of interesting structures in the OBIO space */
74 #define CG3_REGS_OFFSET 0x400000
75 #define CG3_RAM_OFFSET 0x800000
77 static struct sbus_mmap_map cg3_mmap_map
[] = {
78 { CG3_MMAP_OFFSET
, CG3_RAM_OFFSET
, SBUS_MMAP_FBSIZE(1) },
82 /* The cg3 palette is loaded with 4 color values at each time */
83 /* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
85 #define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
86 #define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
88 static void cg3_loadcmap (struct fb_info_sbusfb
*fb
, struct display
*p
, int index
, int count
)
90 struct bt_regs
*bt
= &fb
->s
.cg3
.regs
->cmap
;
94 i
= (((u32
*)fb
->color_map
) + D4M3(index
));
95 steps
= D4M3(index
+count
-1) - D4M3(index
)+3;
97 *(volatile u8
*)&bt
->addr
= (u8
)D4M4(index
);
102 static void cg3_blank (struct fb_info_sbusfb
*fb
)
104 fb
->s
.cg3
.regs
->control
&= ~CG3_CR_ENABLE_VIDEO
;
107 static void cg3_unblank (struct fb_info_sbusfb
*fb
)
109 fb
->s
.cg3
.regs
->control
|= CG3_CR_ENABLE_VIDEO
;
112 static void cg3_margins (struct fb_info_sbusfb
*fb
, struct display
*p
, int x_margin
, int y_margin
)
114 p
->screen_base
+= (y_margin
- fb
->y_margin
) * p
->line_length
+ (x_margin
- fb
->x_margin
);
117 static u8 cg3regvals_66hz
[] __initdata
= { /* 1152 x 900, 66 Hz */
118 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
119 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
120 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
124 static u8 cg3regvals_76hz
[] __initdata
= { /* 1152 x 900, 76 Hz */
125 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
126 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
127 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
131 static u8 cg3regvals_rdi
[] __initdata
= { /* 640 x 480, cgRDI */
132 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
133 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
134 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
138 static u8
*cg3_regvals
[] __initdata
= {
139 cg3regvals_66hz
, cg3regvals_76hz
, cg3regvals_rdi
142 static u_char cg3_dacvals
[] __initdata
= {
143 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
146 static char idstring
[60] __initdata
= { 0 };
148 char __init
*cgthreefb_init(struct fb_info_sbusfb
*fb
)
150 struct fb_fix_screeninfo
*fix
= &fb
->fix
;
151 struct display
*disp
= &fb
->disp
;
152 struct fbtype
*type
= &fb
->type
;
153 unsigned long phys
= fb
->sbdp
->reg_addrs
[0].phys_addr
;
154 int cgRDI
= strstr(fb
->sbdp
->prom_name
, "cgRDI") != NULL
;
156 #ifndef FBCON_HAS_CFB8
160 if (!fb
->s
.cg3
.regs
) {
161 fb
->s
.cg3
.regs
= (struct cg3_regs
*)sparc_alloc_io(phys
+CG3_REGS_OFFSET
, 0,
162 sizeof(struct cg3_regs
), "cg3_regs", fb
->iospace
, 0);
169 prom_getstring (fb
->prom_node
, "params", buffer
, sizeof(buffer
));
171 ww
= simple_strtoul (buffer
, &p
, 10);
172 if (ww
&& *p
== 'x') {
173 hh
= simple_strtoul (p
+ 1, &p
, 10);
174 if (hh
&& *p
== '-') {
175 if (type
->fb_width
!= ww
|| type
->fb_height
!= hh
) {
177 type
->fb_height
= hh
;
178 return SBUSFBINIT_SIZECHANGE
;
186 strcpy(fb
->info
.modename
, "CGthree");
187 strcpy(fix
->id
, "CGthree");
188 fix
->line_length
= fb
->var
.xres_virtual
;
189 fix
->accel
= FB_ACCEL_SUN_CGTHREE
;
191 disp
->scrollmode
= SCROLL_YREDRAW
;
192 if (!disp
->screen_base
)
193 disp
->screen_base
= (char *)sparc_alloc_io(phys
+CG3_RAM_OFFSET
, 0,
194 type
->fb_size
, "cg3_ram", fb
->iospace
, 0);
195 disp
->screen_base
+= fix
->line_length
* fb
->y_margin
+ fb
->x_margin
;
196 fb
->dispsw
= fbcon_cfb8
;
198 fb
->margins
= cg3_margins
;
199 fb
->loadcmap
= cg3_loadcmap
;
200 fb
->blank
= cg3_blank
;
201 fb
->unblank
= cg3_unblank
;
204 fb
->mmap_map
= cg3_mmap_map
;
207 sprintf(idstring
, "%s at %016lx", cgRDI
? "cgRDI" : "cgthree", phys
);
209 sprintf(idstring
, "%s at %x.%08lx", cgRDI
? "cgRDI" : "cgthree", fb
->iospace
, phys
);
212 if (!prom_getbool(fb
->prom_node
, "width")) {
213 /* Ugh, broken PROM didn't initialize us.
214 * Let's deal with this ourselves.
222 u8 status
= fb
->s
.cg3
.regs
->status
, mon
;
223 if ((status
& CG3_SR_ID_MASK
) == CG3_SR_ID_COLOR
) {
224 mon
= status
& CG3_SR_RES_MASK
;
225 if (mon
== CG3_SR_1152_900_76_A
||
226 mon
== CG3_SR_1152_900_76_B
)
231 prom_printf("cgthree: can't handle SR %02x\n",
234 return NULL
; /* fool gcc. */
238 for (p
= cg3_regvals
[type
]; *p
; p
+= 2)
239 ((u8
*)fb
->s
.cg3
.regs
)[p
[0]] = p
[1];
241 for (p
= cg3_dacvals
; *p
; p
+= 2) {
242 *(volatile u8
*)&fb
->s
.cg3
.regs
->cmap
.addr
= p
[0];
243 *(volatile u8
*)&fb
->s
.cg3
.regs
->cmap
.control
= p
[1];