1 /* $Id: cgthreefb.c,v 1.1.1.1 2005/04/11 02:50:41 jack 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/slab.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
47 MODULE_LICENSE("GPL");
59 volatile u8 cursor_start;
60 volatile u8 cursor_end;
61 volatile u8 h_blank_start;
62 volatile u8 h_blank_end;
63 volatile u8 h_sync_start;
64 volatile u8 h_sync_end;
65 volatile u8 comp_sync_end;
66 volatile u8 v_blank_start_high;
67 volatile u8 v_blank_start_low;
68 volatile u8 v_blank_end;
69 volatile u8 v_sync_start;
70 volatile u8 v_sync_end;
71 volatile u8 xfer_holdoff_start;
72 volatile u8 xfer_holdoff_end;
75 /* Offset of interesting structures in the OBIO space */
76 #define CG3_REGS_OFFSET 0x400000UL
77 #define CG3_RAM_OFFSET 0x800000UL
79 static struct sbus_mmap_map cg3_mmap_map[] = {
80 { CG3_MMAP_OFFSET, CG3_RAM_OFFSET, SBUS_MMAP_FBSIZE(1) },
84 /* The cg3 palette is loaded with 4 color values at each time */
85 /* so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on */
87 #define D4M3(x) ((((x)>>2)<<1) + ((x)>>2)) /* (x/4)*3 */
88 #define D4M4(x) ((x)&~0x3) /* (x/4)*4 */
90 static void cg3_loadcmap (struct fb_info_sbusfb *fb, struct display *p, int index, int count)
92 struct bt_regs *bt = &fb->s.cg3.regs->cmap;
98 spin_lock_irqsave(&fb->lock, flags);
100 i = (((u32 *)fb->color_map) + D4M3(index));
101 steps = D4M3(index+count-1) - D4M3(index)+3;
103 regp = (volatile u8 *)&bt->addr;
104 sbus_writeb(D4M4(index), regp);
107 sbus_writel(val, &bt->color_map);
110 spin_unlock_irqrestore(&fb->lock, flags);
113 static void cg3_blank (struct fb_info_sbusfb *fb)
118 spin_lock_irqsave(&fb->lock, flags);
119 tmp = sbus_readb(&fb->s.cg3.regs->control);
120 tmp &= ~CG3_CR_ENABLE_VIDEO;
121 sbus_writeb(tmp, &fb->s.cg3.regs->control);
122 spin_unlock_irqrestore(&fb->lock, flags);
125 static void cg3_unblank (struct fb_info_sbusfb *fb)
130 spin_lock_irqsave(&fb->lock, flags);
131 tmp = sbus_readb(&fb->s.cg3.regs->control);
132 tmp |= CG3_CR_ENABLE_VIDEO;
133 sbus_writeb(tmp, &fb->s.cg3.regs->control);
134 spin_unlock_irqrestore(&fb->lock, flags);
137 static void cg3_margins (struct fb_info_sbusfb *fb, struct display *p,
138 int x_margin, int y_margin)
140 p->screen_base += (y_margin - fb->y_margin) *
141 p->line_length + (x_margin - fb->x_margin);
144 static u8 cg3regvals_66hz[] __initdata = { /* 1152 x 900, 66 Hz */
145 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14,
146 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24,
147 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01,
151 static u8 cg3regvals_76hz[] __initdata = { /* 1152 x 900, 76 Hz */
152 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f,
153 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a,
154 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01,
158 static u8 cg3regvals_rdi[] __initdata = { /* 640 x 480, cgRDI */
159 0x14, 0x70, 0x15, 0x20, 0x16, 0x08, 0x17, 0x10,
160 0x18, 0x06, 0x19, 0x02, 0x1a, 0x31, 0x1b, 0x51,
161 0x1c, 0x06, 0x1d, 0x0c, 0x1e, 0xff, 0x1f, 0x01,
165 static u8 *cg3_regvals[] __initdata = {
166 cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi
169 static u_char cg3_dacvals[] __initdata = {
170 4, 0xff, 5, 0x00, 6, 0x70, 7, 0x00, 0
173 static char idstring[60] __initdata = { 0 };
175 char __init *cgthreefb_init(struct fb_info_sbusfb *fb)
177 struct fb_fix_screeninfo *fix = &fb->fix;
178 struct display *disp = &fb->disp;
179 struct fbtype *type = &fb->type;
180 struct sbus_dev *sdev = fb->sbdp;
181 unsigned long phys = sdev->reg_addrs[0].phys_addr;
182 int cgRDI = strstr(fb->sbdp->prom_name, "cgRDI") != NULL;
184 #ifndef FBCON_HAS_CFB8
188 if (!fb->s.cg3.regs) {
189 fb->s.cg3.regs = (struct cg3_regs *)
190 sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET,
191 sizeof(struct cg3_regs), "cg3 regs");
198 prom_getstring (fb->prom_node, "params", buffer, sizeof(buffer));
200 ww = simple_strtoul (buffer, &p, 10);
201 if (ww && *p == 'x') {
202 hh = simple_strtoul (p + 1, &p, 10);
203 if (hh && *p == '-') {
204 if (type->fb_width != ww || type->fb_height != hh) {
206 type->fb_height = hh;
207 return SBUSFBINIT_SIZECHANGE;
215 strcpy(fb->info.modename, "CGthree");
216 strcpy(fix->id, "CGthree");
217 fix->line_length = fb->var.xres_virtual;
218 fix->accel = FB_ACCEL_SUN_CGTHREE;
220 disp->scrollmode = SCROLL_YREDRAW;
221 if (!disp->screen_base) {
222 disp->screen_base = (char *)
223 sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET,
224 type->fb_size, "cg3 ram");
226 disp->screen_base += fix->line_length * fb->y_margin + fb->x_margin;
227 fb->dispsw = fbcon_cfb8;
229 fb->margins = cg3_margins;
230 fb->loadcmap = cg3_loadcmap;
231 fb->blank = cg3_blank;
232 fb->unblank = cg3_unblank;
235 fb->mmap_map = cg3_mmap_map;
238 sprintf(idstring, "%s at %016lx", cgRDI ? "cgRDI" : "cgthree", phys);
240 sprintf(idstring, "%s at %x.%08lx", cgRDI ? "cgRDI" : "cgthree", fb->iospace, phys);
243 if (!prom_getbool(fb->prom_node, "width")) {
244 /* Ugh, broken PROM didn't initialize us.
245 * Let's deal with this ourselves.
253 u8 status = sbus_readb(&fb->s.cg3.regs->status), mon;
254 if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {
255 mon = status & CG3_SR_RES_MASK;
256 if (mon == CG3_SR_1152_900_76_A ||
257 mon == CG3_SR_1152_900_76_B)
262 prom_printf("cgthree: can't handle SR %02x\n",
265 return NULL; /* fool gcc. */
269 for (p = cg3_regvals[type]; *p; p += 2) {
270 u8 *regp = &((u8 *)fb->s.cg3.regs)[p[0]];
271 sbus_writeb(p[1], regp);
273 for (p = cg3_dacvals; *p; p += 2) {
276 regp = (volatile u8 *)&fb->s.cg3.regs->cmap.addr;
277 sbus_writeb(p[0], regp);
278 regp = (volatile u8 *)&fb->s.cg3.regs->cmap.control;
279 sbus_writeb(p[1], regp);