patch-2.3.25 linux/drivers/video/cyber2000fb.c
Next file: linux/drivers/video/cyber2000fb.h
Previous file: linux/drivers/video/clgenfb.c
Back to the patch index
Back to the overall index
- Lines: 1284
- Date:
Thu Oct 28 10:16:02 1999
- Orig file:
v2.3.24/linux/drivers/video/cyber2000fb.c
- Orig date:
Tue Aug 31 17:29:14 1999
diff -u --recursive --new-file v2.3.24/linux/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
@@ -35,7 +35,9 @@
#define DEFAULT_YRES 480
#define DEFAULT_BPP 8
-static volatile unsigned char *CyberRegs;
+#define MMIO_SIZE 0x000c0000
+
+static char *CyberRegs;
#include "cyber2000fb.h"
@@ -45,7 +47,7 @@
static struct display_switch *dispsw;
static struct fb_var_screeninfo __initdata init_var = {};
-#ifdef DEBUG
+#if defined(DEBUG) && defined(CONFIG_DEBUG_LL)
static void debug_printf(char *fmt, ...)
{
char buffer[128];
@@ -61,168 +63,6 @@
#define debug_printf(x...) do { } while (0)
#endif
-/*
- * Predefined Video Modes
- */
-static const struct res cyber2000_res[] = {
- {
- 640, 480,
- {
- 0x5f, 0x4f, 0x50, 0x80, 0x52, 0x9d, 0x0b, 0x3e,
- 0x00, 0x40,
- 0xe9, 0x8b, 0xdf, 0x50, 0x00, 0xe6, 0x04, 0xc3
- },
- 0x00,
- { 0xd2, 0xce, 0xdb, 0x54 }
- },
-
- {
- 800, 600,
- {
- 0x7f, 0x63, 0x64, 0x00, 0x66, 0x10, 0x6f, 0xf0,
- 0x00, 0x60,
- 0x5b, 0x8f, 0x57, 0x64, 0x00, 0x59, 0x6e, 0xe3
- },
- 0x00,
- { 0x52, 0x85, 0xdb, 0x54 }
- },
-
- {
- 1024, 768,
- {
- 0x9f, 0x7f, 0x80, 0x80, 0x8b, 0x94, 0x1e, 0xfd,
- 0x00, 0x60,
- 0x03, 0x86, 0xff, 0x80, 0x0f, 0x00, 0x1e, 0xe3
- },
- 0x00,
- { 0xd0, 0x52, 0xdb, 0x54 }
- },
-#if 0
- {
- 1152, 886,
- {
- },
- {
- }
- },
-#endif
- {
- 1280, 1024,
- {
- 0xce, 0x9f, 0xa0, 0x8f, 0xa2, 0x1f, 0x28, 0x52,
- 0x00, 0x40,
- 0x08, 0x8f, 0xff, 0xa0, 0x00, 0x03, 0x27, 0xe3
- },
- 0x1d,
- { 0xb4, 0x4b, 0xdb, 0x54 }
- },
-
- {
- 1600, 1200,
- {
- 0xff, 0xc7, 0xc9, 0x9f, 0xcf, 0xa0, 0xfe, 0x10,
- 0x00, 0x40,
- 0xcf, 0x89, 0xaf, 0xc8, 0x00, 0xbc, 0xf1, 0xe3
- },
- 0x1f,
- { 0xbd, 0x10, 0xdb, 0x54 }
- }
-};
-
-#define NUM_TOTAL_MODES arraysize(cyber2000_res)
-
-static const char igs_regs[] = {
- 0x10, 0x10, 0x12, 0x00, 0x13, 0x00,
- 0x30, 0x21, 0x31, 0x00, 0x32, 0x00, 0x33, 0x01,
- 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
- 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
- 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
- 0x70, 0x0b, 0x71, 0x10, 0x72, 0x45, 0x73, 0x30,
- 0x74, 0x1b, 0x75, 0x1e, 0x76, 0x00, 0x7a, 0xc8
-};
-
-static const char crtc_idx[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
-};
-
-static void cyber2000_init_hw(const struct res *res)
-{
- int i;
-
- debug_printf("init vga hw for %dx%d\n", res->xres, res->yres);
-
- cyber2000_outb(0xef, 0x3c2);
- cyber2000_crtcw(0x11, 0x0b);
- cyber2000_attrw(0x11, 0x00);
-
- cyber2000_seqw(0x00, 0x01);
- cyber2000_seqw(0x01, 0x01);
- cyber2000_seqw(0x02, 0x0f);
- cyber2000_seqw(0x03, 0x00);
- cyber2000_seqw(0x04, 0x0e);
- cyber2000_seqw(0x00, 0x03);
-
- for (i = 0; i < sizeof(crtc_idx); i++)
- cyber2000_crtcw(crtc_idx[i], res->crtc_regs[i]);
-
- for (i = 0x0a; i < 0x10; i++)
- cyber2000_crtcw(i, 0);
-
- cyber2000_crtcw(0x18, 0xff);
-
- cyber2000_grphw(0x00, 0x00);
- cyber2000_grphw(0x01, 0x00);
- cyber2000_grphw(0x02, 0x00);
- cyber2000_grphw(0x03, 0x00);
- cyber2000_grphw(0x04, 0x00);
- cyber2000_grphw(0x05, 0x60);
- cyber2000_grphw(0x06, 0x05);
- cyber2000_grphw(0x07, 0x0f);
- cyber2000_grphw(0x08, 0xff);
-
- for (i = 0; i < 16; i++)
- cyber2000_attrw(i, i);
-
- cyber2000_attrw(0x10, 0x01);
- cyber2000_attrw(0x11, 0x00);
- cyber2000_attrw(0x12, 0x0f);
- cyber2000_attrw(0x13, 0x00);
- cyber2000_attrw(0x14, 0x00);
-
- for (i = 0; i < sizeof(igs_regs); i += 2)
- cyber2000_grphw(igs_regs[i], igs_regs[i+1]);
-
- cyber2000_grphw(0x11, res->crtc_ofl);
-
- for (i = 0; i < 4; i += 1)
- cyber2000_grphw(0xb0 + i, res->clk_regs[i]);
-
- cyber2000_grphw(0x90, 0x01);
- cyber2000_grphw(0xb9, 0x80);
- cyber2000_grphw(0xb9, 0x00);
-
- cyber2000_outb(0x56, 0x3ce);
- i = cyber2000_inb(0x3cf);
- cyber2000_outb(i | 4, 0x3cf);
- cyber2000_outb(0x04, 0x3c6);
- cyber2000_outb(i, 0x3cf);
-
- cyber2000_outb(0x20, 0x3c0);
- cyber2000_outb(0xff, 0x3c6);
-
- for (i = 0; i < 256; i++) {
- cyber2000_outb(i, 0x3c8);
- cyber2000_outb(0, 0x3c9);
- cyber2000_outb(0, 0x3c9);
- cyber2000_outb(0, 0x3c9);
- }
-}
-
-
-static struct fb_ops cyber2000fb_ops;
-
/* -------------------- Hardware specific routines ------------------------- */
/*
@@ -232,10 +72,10 @@
{
int count = 10000;
- while (cyber2000_inb(0xbf011) & 0x80) {
+ while (cyber2000_inb(CO_REG_CONTROL) & 0x80) {
if (!count--) {
debug_printf("accel_wait timed out\n");
- cyber2000_outb(0, 0xbf011);
+ cyber2000_outb(0, CO_REG_CONTROL);
return;
}
udelay(10);
@@ -252,45 +92,54 @@
cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
int height, int width)
{
- unsigned long src, dst, chwidth = p->var.xres_virtual * fontheight(p);
- int v = 0x8000;
+ unsigned long src, dst;
+ unsigned int fh, fw;
+ int cmd = CO_CMD_L_PATTERN_FGCOL;
+
+ fw = fontwidth(p);
+ sx *= fw;
+ dx *= fw;
+ width *= fw;
+ width -= 1;
if (sx < dx) {
- sx += width - 1;
- dx += width - 1;
- v |= 4;
+ sx += width;
+ dx += width;
+ cmd |= CO_CMD_L_INC_LEFT;
}
+ fh = fontheight(p);
+ sy *= fh;
+ dy *= fh;
+ height *= fh;
+ height -= 1;
+
if (sy < dy) {
- sy += height - 1;
- dy += height - 1;
- v |= 2;
+ sy += height;
+ dy += height;
+ cmd |= CO_CMD_L_INC_UP;
}
- sx *= fontwidth(p);
- dx *= fontwidth(p);
- src = sx + sy * chwidth;
- dst = dx + dy * chwidth;
- width = width * fontwidth(p) - 1;
- height = height * fontheight(p) - 1;
+ src = sx + sy * p->var.xres_virtual;
+ dst = dx + dy * p->var.xres_virtual;
cyber2000_accel_wait();
- cyber2000_outb(0x00, 0xbf011);
- cyber2000_outb(0x03, 0xbf048);
- cyber2000_outw(width, 0xbf060);
+ cyber2000_outb(0x00, CO_REG_CONTROL);
+ cyber2000_outb(0x03, CO_REG_FORE_MIX);
+ cyber2000_outw(width, CO_REG_WIDTH);
if (p->var.bits_per_pixel != 24) {
- cyber2000_outl(dst, 0xbf178);
- cyber2000_outl(src, 0xbf170);
+ cyber2000_outl(dst, CO_REG_DEST_PTR);
+ cyber2000_outl(src, CO_REG_SRC_PTR);
} else {
- cyber2000_outl(dst * 3, 0xbf178);
- cyber2000_outb(dst, 0xbf078);
- cyber2000_outl(src * 3, 0xbf170);
+ cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
+ cyber2000_outb(dst, CO_REG_X_PHASE);
+ cyber2000_outl(src * 3, CO_REG_SRC_PTR);
}
- cyber2000_outw(height, 0xbf062);
- cyber2000_outw(v, 0xbf07c);
- cyber2000_outw(0x2800, 0xbf07e);
+ cyber2000_outw(height, CO_REG_HEIGHT);
+ cyber2000_outw(cmd, CO_REG_CMD_L);
+ cyber2000_outw(0x2800, CO_REG_CMD_H);
}
static void
@@ -298,36 +147,40 @@
int height, int width)
{
unsigned long dst;
+ unsigned int fw, fh;
u32 bgx = attr_bgcol_ec(p, conp);
- dst = sx * fontwidth(p) + sy * p->var.xres_virtual * fontheight(p);
- width = width * fontwidth(p) - 1;
- height = height * fontheight(p) - 1;
+ fw = fontwidth(p);
+ fh = fontheight(p);
+
+ dst = sx * fw + sy * p->var.xres_virtual * fh;
+ width = width * fw - 1;
+ height = height * fh - 1;
cyber2000_accel_wait();
- cyber2000_outb(0x00, 0xbf011);
- cyber2000_outb(0x03, 0xbf048);
- cyber2000_outw(width, 0xbf060);
- cyber2000_outw(height, 0xbf062);
+ cyber2000_outb(0x00, CO_REG_CONTROL);
+ cyber2000_outb(0x03, CO_REG_FORE_MIX);
+ cyber2000_outw(width, CO_REG_WIDTH);
+ cyber2000_outw(height, CO_REG_HEIGHT);
switch (p->var.bits_per_pixel) {
case 15:
case 16:
bgx = ((u16 *)p->dispsw_data)[bgx];
case 8:
- cyber2000_outl(dst, 0xbf178);
+ cyber2000_outl(dst, CO_REG_DEST_PTR);
break;
case 24:
- cyber2000_outl(dst * 3, 0xbf178);
- cyber2000_outb(dst, 0xbf078);
+ cyber2000_outl(dst * 3, CO_REG_DEST_PTR);
+ cyber2000_outb(dst, CO_REG_X_PHASE);
bgx = ((u32 *)p->dispsw_data)[bgx];
break;
}
- cyber2000_outl(bgx, 0xbf058);
- cyber2000_outw(0x8000, 0xbf07c);
- cyber2000_outw(0x0800, 0xbf07e);
+ cyber2000_outl(bgx, CO_REG_FOREGROUND);
+ cyber2000_outw(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L);
+ cyber2000_outw(0x0800, CO_REG_CMD_H);
}
static void
@@ -478,183 +331,136 @@
return 0;
}
-static void cyber2000fb_calculate_timing(unsigned char *v, struct fb_var_screeninfo *var)
-{
- int Htotal, Hdispend, Hblankstart, Hblankend, Hsyncstart, Hsyncend;
- int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
-#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
-
- Hdispend = var->xres;
- Hsyncstart = var->xres + var->right_margin;
- Hsyncend = var->xres + var->right_margin + var->hsync_len;
- Htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
-
- Hblankstart = var->xres;
- Hblankend = Htotal - 4*8;
-
- Vdispend = var->yres;
- Vsyncstart = var->yres + var->lower_margin;
- Vsyncend = var->yres + var->lower_margin + var->vsync_len;
- Vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
-
- Vblankstart = var->yres + 7;
- Vblankend = Vtotal - 11;
+struct par_info {
+ /*
+ * Hardware
+ */
+ unsigned char clock_mult;
+ unsigned char clock_div;
+ unsigned char visualid;
+ unsigned char pixformat;
+ unsigned char crtc_ofl;
+ unsigned char crtc[19];
+ unsigned int width;
+ unsigned int pitch;
- Hdispend >>= 3;
- Hsyncstart >>= 3;
- Hsyncend >>= 3;
- Htotal >>= 3;
- Hblankstart >>= 3;
- Hblankend >>= 3;
-
- Htotal -= 5;
- Hdispend -= 1;
- Vtotal -= 2;
- Vdispend -= 1;
- Vblankstart -= 1;
- Vblankend -= 1;
-
- v[0] = Htotal;
- v[1] = Hdispend;
- v[2] = Hblankstart;
- v[3] = BIT(Hblankend, 0, 0x1f, 0) |
- BIT(1, 0, 0x01, 7);
- v[4] = Hsyncstart;
- v[5] = BIT(Hsyncend, 0, 0x1f, 0) |
- BIT(Hblankend, 5, 0x01, 7);
-
- v[6] = Vtotal;
- v[7] = BIT(Vtotal, 8, 0x01, 0) |
- BIT(Vdispend, 8, 0x01, 1) |
- BIT(Vsyncstart, 8, 0x01, 2) |
- BIT(Vblankstart,8, 0x01, 3) |
- BIT(1, 0, 0x01, 4) |
- BIT(Vtotal, 9, 0x01, 5) |
- BIT(Vdispend, 9, 0x01, 6) |
- BIT(Vsyncstart, 9, 0x01, 7);
- v[8] = 0;
- v[9] = BIT(0, 0, 0x1f, 0) |
- BIT(Vblankstart,9, 0x01, 5) |
- BIT(1, 0, 0x01, 6);
- v[10] = Vsyncstart;
- v[11] = BIT(Vsyncend, 0, 0x0f, 0) |
- BIT(1, 0, 0x01, 7);
- v[12] = Vdispend;
- v[14] = 0;
- v[15] = Vblankstart;
- v[16] = Vblankend;
- v[17] = 0xe3;
+ /*
+ * Other
+ */
+ unsigned int visual;
+};
- /* overflow - graphics reg 0x11 */
- v[18] = BIT(Vtotal, 10, 0x01, 0) | /* guess */
- BIT(Vdispend, 10, 0x01, 1) |
- BIT(Vsyncstart, 10, 0x01, 2) | /* guess */
- BIT(Vblankstart,10, 0x01, 3) | /* guess */
- BIT(Hblankend, 6, 0x01, 4); /* guess */
-}
+static const char crtc_idx[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
+};
-static void cyber2000fb_set_timing(struct fb_var_screeninfo *var)
+static void cyber2000fb_set_timing(struct par_info *hw)
{
- unsigned int width = var->xres_virtual;
- unsigned int scr_pitch, fetchrow, i;
- char b, graph_r77, crtc[32];
+ unsigned int fetchrow, i;
- switch (var->bits_per_pixel) {
- case 8: /* PSEUDOCOLOUR, 256 */
- b = 0;
- graph_r77 = 1;
- scr_pitch = width;
- break;
+ /*
+ * Blank palette
+ */
+ for (i = 0; i < 256; i++) {
+ cyber2000_outb(i, 0x3c8);
+ cyber2000_outb(0, 0x3c9);
+ cyber2000_outb(0, 0x3c9);
+ cyber2000_outb(0, 0x3c9);
+ }
- case 15:/* DIRECTCOLOUR, 32k */
- b = 1;
- graph_r77 = 6;
- scr_pitch = width * 2;
- break;
+ cyber2000_outb(0xef, 0x3c2);
+ cyber2000_crtcw(0x11, 0x0b);
+ cyber2000_attrw(0x11, 0x00);
- case 16:/* DIRECTCOLOUR, 64k */
- b = 1;
- graph_r77 = 2;
- scr_pitch = width * 2;
- break;
+ cyber2000_seqw(0x00, 0x01);
+ cyber2000_seqw(0x01, 0x01);
+ cyber2000_seqw(0x02, 0x0f);
+ cyber2000_seqw(0x03, 0x00);
+ cyber2000_seqw(0x04, 0x0e);
+ cyber2000_seqw(0x00, 0x03);
- case 24:/* TRUECOLOUR, 16m */
- b = 2;
- graph_r77 = 4;
- width *= 3;
- scr_pitch = width;
- break;
+ for (i = 0; i < sizeof(crtc_idx); i++)
+ cyber2000_crtcw(crtc_idx[i], hw->crtc[i]);
- default:
- return;
- }
+ for (i = 0x0a; i < 0x10; i++)
+ cyber2000_crtcw(i, 0);
- width -= 1;
- scr_pitch >>= 3;
- fetchrow = scr_pitch + 1;
+ cyber2000_grphw(0x11, hw->crtc_ofl);
+ cyber2000_grphw(0x00, 0x00);
+ cyber2000_grphw(0x01, 0x00);
+ cyber2000_grphw(0x02, 0x00);
+ cyber2000_grphw(0x03, 0x00);
+ cyber2000_grphw(0x04, 0x00);
+ cyber2000_grphw(0x05, 0x60);
+ cyber2000_grphw(0x06, 0x05);
+ cyber2000_grphw(0x07, 0x0f);
+ cyber2000_grphw(0x08, 0xff);
- cyber2000fb_calculate_timing(crtc, var);
+ /* Attribute controller registers */
+ for (i = 0; i < 16; i++)
+ cyber2000_attrw(i, i);
- for (i = 0; i < NUM_TOTAL_MODES; i++)
- if (var->xres == cyber2000_res[i].xres &&
- var->yres == cyber2000_res[i].yres)
- break;
+ cyber2000_attrw(0x10, 0x01);
+ cyber2000_attrw(0x11, 0x00);
+ cyber2000_attrw(0x12, 0x0f);
+ cyber2000_attrw(0x13, 0x00);
+ cyber2000_attrw(0x14, 0x00);
- if (i < NUM_TOTAL_MODES)
- cyber2000_init_hw(cyber2000_res + i);
+ /* PLL registers */
+ cyber2000_grphw(0xb0, hw->clock_mult);
+ cyber2000_grphw(0xb1, hw->clock_div);
+ cyber2000_grphw(0xb2, 0xdb);
+ cyber2000_grphw(0xb3, 0x54); /* MCLK: 75MHz */
+ cyber2000_grphw(0x90, 0x01);
+ cyber2000_grphw(0xb9, 0x80);
+ cyber2000_grphw(0xb9, 0x00);
- crtc[13] = scr_pitch;
+ cyber2000_outb(0x56, 0x3ce);
+ i = cyber2000_inb(0x3cf);
+ cyber2000_outb(i | 4, 0x3cf);
+ cyber2000_outb(0x04, 0x3c6);
+ cyber2000_outb(i, 0x3cf);
- /*
- * reprogram the CRTC with the values we calculated
- * above. This should be cleaned up once we're
- * confident that we're generating the correct
- * values. Disable this if you're having problems,
- * and report the values obtained from the kernel
- * messages.
- */
-#if 1
- cyber2000_crtcw(0x11, 0x0b);
- for (i = 0; i < sizeof(crtc_idx); i++)
- cyber2000_crtcw(crtc_idx[i], crtc[i]);
-#else
- cyber2000_crtcw(0x13, crtc[13]);
-#endif
+ cyber2000_outb(0x20, 0x3c0);
+ cyber2000_outb(0xff, 0x3c6);
+ fetchrow = hw->pitch + 1;
cyber2000_grphw(0x14, fetchrow);
- /* FIXME: is this the right way round? */
- cyber2000_grphw(0x15, ((fetchrow >> 4) & 0xf0) | ((scr_pitch >> 8) & 0x0f));
- cyber2000_grphw(0x77, graph_r77);
+ /* FIXME: is this the right way round? */
+ cyber2000_grphw(0x15, ((fetchrow >> 4) & 0xf0) | ((hw->pitch >> 8) & 0x0f));
+ cyber2000_grphw(0x77, hw->visualid);
cyber2000_grphw(0x33, 0x1c);
- cyber2000_outw(width, 0xbf018);
- cyber2000_outw(width, 0xbf218);
- cyber2000_outb(b, 0xbf01c);
-
-#if 0
-{ int j; i = 0;
- printk(KERN_DEBUG);
- for (j = 0; j < 19; j++) printk("%2d ", j); printk("\n"KERN_DEBUG);
- for (j = 0; j < 19; j++) printk("%02X ", crtc[j]); printk("\n"KERN_DEBUG);
- for (j = 0; j < 18; j++) printk("%02X ", cyber2000_res[i].crtc_regs[j]);
- printk("%02X\n", cyber2000_res[i].crtc_ofl);
-}
-#endif
+ /*
+ * Set up accelerator registers
+ */
+ cyber2000_outw(hw->width, CO_REG_SRC_WIDTH);
+ cyber2000_outw(hw->width, CO_REG_DEST_WIDTH);
+ cyber2000_outb(hw->pixformat, CO_REG_PIX_FORMAT);
}
-static inline void
+static inline int
cyber2000fb_update_start(struct fb_var_screeninfo *var)
{
-#if 0
unsigned int base;
base = var->yoffset * var->xres_virtual + var->xoffset;
- cyber2000_crtcw(0x0c, base);
- cyber2000_crtcw(0x0d, base >> 8);
- /* FIXME: need the upper bits of the start offset */
-/* cyber2000_crtcw(0x??, base >> 16);*/
-#endif
+ base >>= 2;
+
+ if (base >= 1 << 20)
+ return -EINVAL;
+
+ /*
+ * FIXME: need the upper bits of the start offset
+ */
+ cyber2000_grphw(0x10, base >> 16 | 0x10);
+ cyber2000_crtcw(0x0c, base >> 8);
+ cyber2000_crtcw(0x0d, base);
+
+ return 0;
}
/*
@@ -723,30 +529,230 @@
return err;
}
+static int cyber2000fb_decode_crtc(struct par_info *hw, struct fb_var_screeninfo *var)
+{
+ unsigned int Htotal, Hblankend, Hsyncend;
+ unsigned int Vtotal, Vdispend, Vblankstart, Vblankend, Vsyncstart, Vsyncend;
+#define BIT(v,b1,m,b2) (((v >> b1) & m) << b2)
+
+ hw->crtc[13] = hw->pitch;
+ hw->crtc[17] = 0xe3;
+ hw->crtc[14] = 0;
+ hw->crtc[8] = 0;
+
+ Htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+ if (Htotal > 2080)
+ return -EINVAL;
+
+ hw->crtc[0] = (Htotal >> 3) - 5; /* Htotal */
+ hw->crtc[1] = (var->xres >> 3) - 1; /* Hdispend */
+ hw->crtc[2] = var->xres >> 3; /* Hblankstart */
+ hw->crtc[4] = (var->xres + var->right_margin) >> 3; /* Hsyncstart */
+
+ Hblankend = (Htotal - 4*8) >> 3;
+
+ hw->crtc[3] = BIT(Hblankend, 0, 0x1f, 0) | /* Hblankend */
+ BIT(1, 0, 0x01, 7);
+
+ Hsyncend = (var->xres + var->right_margin + var->hsync_len) >> 3;
+
+ hw->crtc[5] = BIT(Hsyncend, 0, 0x1f, 0) | /* Hsyncend */
+ BIT(Hblankend, 5, 0x01, 7);
+
+ Vdispend = var->yres - 1;
+ Vsyncstart = var->yres + var->lower_margin;
+ Vsyncend = var->yres + var->lower_margin + var->vsync_len;
+ Vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin - 2;
+
+ if (Vtotal > 2047)
+ return -EINVAL;
+
+ Vblankstart = var->yres + 6;
+ Vblankend = Vtotal - 10;
+
+ hw->crtc[6] = Vtotal;
+ hw->crtc[7] = BIT(Vtotal, 8, 0x01, 0) |
+ BIT(Vdispend, 8, 0x01, 1) |
+ BIT(Vsyncstart, 8, 0x01, 2) |
+ BIT(Vblankstart,8, 0x01, 3) |
+ BIT(1, 0, 0x01, 4) |
+ BIT(Vtotal, 9, 0x01, 5) |
+ BIT(Vdispend, 9, 0x01, 6) |
+ BIT(Vsyncstart, 9, 0x01, 7);
+ hw->crtc[9] = BIT(0, 0, 0x1f, 0) |
+ BIT(Vblankstart,9, 0x01, 5) |
+ BIT(1, 0, 0x01, 6);
+ hw->crtc[10] = Vsyncstart;
+ hw->crtc[11] = BIT(Vsyncend, 0, 0x0f, 0) |
+ BIT(1, 0, 0x01, 7);
+ hw->crtc[12] = Vdispend;
+ hw->crtc[15] = Vblankstart;
+ hw->crtc[16] = Vblankend;
+ hw->crtc[18] = 0xff;
+
+ /* overflow - graphics reg 0x11 */
+/* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10 4=LINECOMP:10 5-IVIDEO 6=FIXCNT */
+ hw->crtc_ofl =
+ BIT(Vtotal, 10, 0x01, 0) |
+ BIT(Vdispend, 10, 0x01, 1) |
+ BIT(Vsyncstart, 10, 0x01, 2) |
+ BIT(Vblankstart,10, 0x01, 3) |
+ 1 << 4;
+
+ return 0;
+}
+
+/*
+ * The following was discovered by a good monitor,
+ * bit twiddling, theorising and but mostly luck.
+ * Strangely, it looks like everyone elses' PLL!
+ *
+ * Clock registers:
+ * fclock = fpll / div2
+ * fpll = fref * mult / div1
+ * where:
+ * fref = 14.318MHz (69842ps)
+ * mult = reg0xb0.7:0
+ * div1 = (reg0xb1.5:0 + 1)
+ * div2 = 2^(reg0xb1.7:6)
+ * fpll should be between 150 and 220 MHz
+ * (6667ps and 4545ps)
+ */
static int
-cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
+cyber2000fb_decode_clock(struct par_info *hw, struct fb_var_screeninfo *var)
{
+ unsigned long pll_ps = var->pixclock;
+ unsigned long ref_ps = 69842;
+ int div2, div1, mult;
+
+ /*
+ * Step 1:
+ * find div2 such that 150MHz < fpll < 220MHz
+ * and 0 <= div2 < 4
+ */
+ for (div2 = 0; div2 < 4; div2++, pll_ps >>= 1)
+ if (6667 > pll_ps && pll_ps > 4545)
+ break;
+
+ if (div2 == 4)
+ return -EINVAL;
+
+#if 0
+ /*
+ * Step 2:
+ * Find fpll
+ * fpll = fref * mult / div1
+ *
+ * Note! This just picks any old values at the moment,
+ * and as such I don't trust it. It certainly doesn't
+ * come out with the values below, so the PLL may become
+ * unstable under some circumstances (you don't want an
+ * FM dot clock)
+ */
+ for (div1 = 32; div1 > 1; div1 -= 1) {
+ mult = (ref_ps * div1 + pll_ps / 2) / pll_ps;
+ if (mult < 256)
+ break;
+ }
+#else
+ if (pll_ps == 4630) { /* 216.0, 108.0, 54.00, 27.000 */
+ mult = 181; /* 4630 9260 18520 37040 */
+ div1 = 12;
+ } else if (pll_ps == 4965) { /* 201.0, 100.5, 50.25, 25.125 */
+ mult = 211; /* 4965 9930 19860 39720 */
+ div1 = 15;
+ } else if (pll_ps == 5050) { /* 198.0, 99.0, 49.50, 24.750 */
+ mult = 83; /* 5050 10100 20200 40400 */
+ div1 = 6;
+ } else if (pll_ps == 6349) { /* 158.0, 79.0, 39.50, 19.750 */
+ mult = 209; /* 6349 12698 25396 50792 */
+ div1 = 19;
+ } else if (pll_ps == 6422) { /* 156.0, 78.0, 39.00, 19.500 */
+ mult = 190; /* 6422 12844 25688 51376 */
+ div1 = 17;
+ } else
+ return -EINVAL;
+#endif
+ /*
+ * Step 3:
+ * combine values
+ */
+ hw->clock_mult = mult - 1;
+ hw->clock_div = div2 << 6 | (div1 - 1);
+
+ return 0;
+}
+
+/*
+ * Decode the info required for the hardware.
+ * This involves the PLL parameters for the dot clock,
+ * CRTC registers, and accelerator settings.
+ */
+static int
+cyber2000fb_decode_var(struct fb_var_screeninfo *var, int con, struct par_info *hw)
+{
+ int err;
+
+ hw->width = var->xres_virtual;
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB8
- case 8:
- *visual = FB_VISUAL_PSEUDOCOLOR;
+ case 8: /* PSEUDOCOLOUR, 256 */
+ hw->visual = FB_VISUAL_PSEUDOCOLOR;
+ hw->pixformat = PIXFORMAT_8BPP;
+ hw->visualid = VISUALID_256;
+ hw->pitch = hw->width >> 3;
break;
#endif
#ifdef FBCON_HAS_CFB16
- case 15:
- case 16:
- *visual = FB_VISUAL_DIRECTCOLOR;
+ case 15:/* DIRECTCOLOUR, 32k */
+ hw->visual = FB_VISUAL_DIRECTCOLOR;
+ hw->pixformat = PIXFORMAT_16BPP;
+ hw->visualid = VISUALID_32K;
+ hw->pitch = hw->width >> 2;
+ break;
+
+ case 16:/* DIRECTCOLOUR, 64k */
+ hw->visual = FB_VISUAL_DIRECTCOLOR;
+ hw->pixformat = PIXFORMAT_16BPP;
+ hw->visualid = VISUALID_64K;
+ hw->pitch = hw->width >> 2;
break;
#endif
#ifdef FBCON_HAS_CFB24
- case 24:
- *visual = FB_VISUAL_TRUECOLOR;
+ case 24:/* TRUECOLOUR, 16m */
+ hw->visual = FB_VISUAL_TRUECOLOR;
+ hw->pixformat = PIXFORMAT_24BPP;
+ hw->visualid = VISUALID_16M;
+ hw->width *= 3;
+ hw->pitch = hw->width >> 3;
break;
#endif
default:
return -EINVAL;
}
+ err = cyber2000fb_decode_clock(hw, var);
+ if (err)
+ return err;
+
+ err = cyber2000fb_decode_crtc(hw, var);
+ if (err)
+ return err;
+
+ debug_printf("Clock: %02X %02X\n",
+ hw->clock_mult, hw->clock_div);
+ {
+ int i;
+
+ for (i = 0; i < 19; i++)
+ debug_printf("%2d ", i);
+ debug_printf("\n");
+ for (i = 0; i < 18; i++)
+ debug_printf("%02X ", hw->crtc[i]);
+ debug_printf("%02X\n", hw->crtc_ofl);
+ }
+ hw->width -= 1;
+
return 0;
}
@@ -760,7 +766,7 @@
struct display *display;
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, "Cyber2000");
+ strcpy(fix->id, current_par.dev_name);
if (con >= 0)
display = fb_display + con;
@@ -770,7 +776,7 @@
fix->smem_start = current_par.screen_base_p;
fix->smem_len = current_par.screen_size;
fix->mmio_start = current_par.regs_base_p;
- fix->mmio_len = 0x000c0000;
+ fix->mmio_len = MMIO_SIZE;
fix->type = display->type;
fix->type_aux = display->type_aux;
fix->xpanstep = 0;
@@ -806,14 +812,15 @@
cyber2000fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct display *display;
- int err, chgvar = 0, visual;
+ struct par_info hw;
+ int err, chgvar = 0;
if (con >= 0)
display = fb_display + con;
else
display = &global_disp;
- err = cyber2000fb_decode_var(var, con, &visual);
+ err = cyber2000fb_decode_var(var, con, &hw);
if (err)
return err;
@@ -854,11 +861,11 @@
if (var->activate & FB_ACTIVATE_ALL)
global_disp.var = display->var;
- display->screen_base = (char *)current_par.screen_base;
- display->visual = visual;
+ display->screen_base = current_par.screen_base;
+ display->visual = hw.visual;
display->type = FB_TYPE_PACKED_PIXELS;
display->type_aux = 0;
- display->ypanstep = 0;
+ display->ypanstep = 1;
display->ywrapstep = 0;
display->can_soft_blank = 1;
display->inverse = 0;
@@ -887,8 +894,8 @@
break;
#endif
default:
- printk(KERN_WARNING "cyber2000: no support for %dbpp\n",
- display->var.bits_per_pixel);
+ printk(KERN_WARNING "%s: no support for %dbpp\n",
+ current_par.dev_name, display->var.bits_per_pixel);
dispsw = &fbcon_dummy;
break;
}
@@ -908,7 +915,7 @@
struct fb_cmap *cmap;
cyber2000fb_update_start(var);
- cyber2000fb_set_timing(var);
+ cyber2000fb_set_timing(&hw);
if (display->cmap.len)
cmap = &display->cmap;
@@ -938,10 +945,9 @@
return -EINVAL;
if (y_bottom > fb_display[con].var.yres_virtual)
return -EINVAL;
-/*disabled until we can update the start address properly */
-return -EINVAL;
- cyber2000fb_update_start(var);
+ if (cyber2000fb_update_start(var))
+ return -EINVAL;
fb_display[con].var.xoffset = var->xoffset;
fb_display[con].var.yoffset = var->yoffset;
@@ -970,9 +976,12 @@
static int
cyber2000fb_updatevar(int con, struct fb_info *info)
{
+ int ret = 0;
+
if (con == current_par.currcon)
- cyber2000fb_update_start(&fb_display[con].var);
- return 0;
+ ret = cyber2000fb_update_start(&fb_display[con].var);
+
+ return ret;
}
static int
@@ -1020,11 +1029,6 @@
}
}
-int __init cyber2000fb_setup(char *options)
-{
- return 0;
-}
-
static struct fb_ops cyber2000fb_ops =
{
cyber2000fb_open,
@@ -1038,6 +1042,27 @@
cyber2000fb_ioctl
};
+/*
+ * These parameters give
+ * 640x480, hsync 31.5kHz, vsync 60Hz
+ */
+static struct fb_videomode __initdata
+cyber2000fb_default_mode = {
+ name: NULL,
+ refresh: 60,
+ xres: 640,
+ yres: 480,
+ pixclock: 39722,
+ left_margin: 56,
+ right_margin: 16,
+ upper_margin: 34,
+ lower_margin: 9,
+ hsync_len: 88,
+ vsync_len: 2,
+ sync: FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ vmode: FB_VMODE_NONINTERLACED
+};
+
static void __init
cyber2000fb_init_fbinfo(void)
{
@@ -1063,23 +1088,6 @@
* setup initial parameters
*/
memset(&init_var, 0, sizeof(init_var));
- init_var.xres_virtual =
- init_var.xres = DEFAULT_XRES;
- init_var.yres_virtual =
- init_var.yres = DEFAULT_YRES;
- init_var.bits_per_pixel = DEFAULT_BPP;
-
- /*
- * These parameters give
- * 640x480, hsync 31.5kHz, vsync 60Hz
- */
- init_var.left_margin = 56;
- init_var.right_margin = 16;
- init_var.upper_margin = 34;
- init_var.lower_margin = 9;
- init_var.hsync_len = 88;
- init_var.vsync_len = 2;
- init_var.pixclock = 39722;
init_var.red.msb_right = 0;
init_var.green.msb_right = 0;
@@ -1134,8 +1142,81 @@
init_var.height = -1;
init_var.width = -1;
init_var.accel_flags = FB_ACCELF_TEXT;
- init_var.sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT;
- init_var.vmode = FB_VMODE_NONINTERLACED;
+}
+
+/*
+ * Cyber2000 options:
+ *
+ * font:fontname
+ * Set the fontname
+ *
+ * res:XxY
+ * Set the default display resolution
+ */
+static void __init
+cyber2000fb_parse_font(char *opt)
+{
+ strcpy(fb_info.fontname, opt);
+}
+
+static struct options {
+ char *name;
+ void (*parse)(char *opt);
+} opt_table[] __initdata = {
+ { "font", cyber2000fb_parse_font },
+ { NULL, NULL }
+};
+
+int __init
+cyber2000fb_setup(char *options)
+{
+ struct options *optp;
+ char *opt;
+
+ if (!options || !*options)
+ return 0;
+
+ cyber2000fb_init_fbinfo();
+
+ for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
+ if (!*opt)
+ continue;
+
+ for (optp = opt_table; optp->name; optp++) {
+ int optlen;
+
+ optlen = strlen(optp->name);
+
+ if (strncmp(opt, optp->name, optlen) == 0 &&
+ opt[optlen] == ':') {
+ optp->parse(opt + optlen + 1);
+ break;
+ }
+ }
+
+ if (!optp->name)
+ printk(KERN_ERR "CyberPro20x0: unknown parameter: %s\n",
+ opt);
+ }
+ return 0;
+}
+
+static char igs_regs[] __initdata = {
+ 0x10, 0x10, 0x12, 0x00, 0x13, 0x00,
+/* 0x30, 0x21,*/ 0x31, 0x00, 0x32, 0x00, 0x33, 0x01,
+ 0x50, 0x00, 0x51, 0x00, 0x52, 0x00, 0x53, 0x00,
+ 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57, 0x01,
+ 0x58, 0x00, 0x59, 0x00, 0x5a, 0x00,
+ 0x70, 0x0b,/* 0x71, 0x10, 0x72, 0x45,*/ 0x73, 0x30,
+ 0x74, 0x1b, 0x75, 0x1e, 0x76, 0x00, 0x7a, 0xc8
+};
+
+static void __init cyber2000fb_hw_init(void)
+{
+ int i;
+
+ for (i = 0; i < sizeof(igs_regs); i += 2)
+ cyber2000_grphw(igs_regs[i], igs_regs[i+1]);
}
/*
@@ -1145,37 +1226,96 @@
{
struct pci_dev *dev;
u_int h_sync, v_sync;
- u_long base_p, base_v;
+ u_long mmio_base, smem_base, smem_size;
+ int err = 0;
+
+ dev = pci_find_device(PCI_VENDOR_ID_INTERG,
+ PCI_DEVICE_ID_INTERG_2000, NULL);
+
+ if (!dev)
+ dev = pci_find_device(PCI_VENDOR_ID_INTERG,
+ PCI_DEVICE_ID_INTERG_2010, NULL);
- dev = pci_find_device(PCI_VENDOR_ID_INTERG, 0x2000, NULL);
if (!dev)
return -ENXIO;
- /* this should be done by PCI generic code */
- base_p = 0x80000000 + dev->resource[0].start;
+ sprintf(current_par.dev_name, "CyberPro%4X", dev->device);
+
+ smem_base = dev->resource[0].start;
+ mmio_base = dev->resource[0].start + 0x00800000;
/*
- * This should be ioremap'd, thus:
- *
- * base_v = ioremap(dev->resource[0].start, dev->resource[0].end - dev->resource[0].start + 1);
+ * Map in the registers
*/
- base_v = (u_long)bus_to_virt(dev->resource[0].start);
+ if (!request_mem_region(mmio_base, MMIO_SIZE, "memory mapped I/O")) {
+ printk("%s: memory mapped IO in use\n",
+ current_par.dev_name);
+ return -EBUSY;
+ }
- /*FIXME*/
- CyberRegs = base_v + 0x00800000;
+ CyberRegs = ioremap(mmio_base, MMIO_SIZE);
+ if (!CyberRegs) {
+ printk("%s: unable to map memory mapped IO\n",
+ current_par.dev_name);
+ err = -ENOMEM;
+ goto release_mmio_resource;
+ }
cyber2000_outb(0x18, 0x46e8);
cyber2000_outb(0x01, 0x102);
cyber2000_outb(0x08, 0x46e8);
+ /*
+ * get the video RAM size from the VGA register.
+ * This should have been already initialised by the BIOS,
+ * but if it's garbage, claim default 1MB VRAM (woody)
+ */
+ cyber2000_outb(0x72, 0x3ce);
+ switch (cyber2000_inb(0x3cf) & 3) {
+ case 2: smem_size = 0x00400000; break;
+ case 1: smem_size = 0x00200000; break;
+ default: smem_size = 0x00100000; break;
+ }
+
+ /*
+ * Map in screen memory
+ */
+ if (!request_mem_region(smem_base, smem_size, "frame buffer")) {
+ printk("%s: frame buffer in use\n",
+ current_par.dev_name);
+ err = -EBUSY;
+ goto release_mmio;
+ }
+
+ current_par.screen_base = ioremap(smem_base, smem_size);
+ if (!current_par.screen_base) {
+ printk("%s: unable to map screen memory\n",
+ current_par.dev_name);
+ err = -ENOMEM;
+ goto release_smem_resource;
+ }
+current_par.screen_base += IO_FUDGE_FACTOR;
+ current_par.screen_size = smem_size;
+ current_par.screen_base_p = smem_base + 0x80000000;
+ current_par.regs_base_p = mmio_base + 0x80000000;
+ current_par.currcon = -1;
+
cyber2000fb_init_fbinfo();
- current_par.currcon = -1;
- current_par.screen_base_p = base_p;
- current_par.screen_base = base_v;
- current_par.screen_size = 0x00200000;
- current_par.regs_base_p = base_p + 0x00800000;
+ if (!fb_find_mode(&init_var, &fb_info, NULL,
+ NULL, 0, &cyber2000fb_default_mode, 8)) {
+ printk("%s: no valid mode found\n",
+ current_par.dev_name);
+ goto release_smem_resource;
+ }
+
+ init_var.yres_virtual = smem_size * 8 /
+ (init_var.bits_per_pixel * init_var.xres_virtual);
+ if (init_var.yres_virtual < init_var.yres)
+ init_var.yres_virtual = init_var.yres;
+
+ cyber2000fb_hw_init();
cyber2000fb_set_var(&init_var, -1, &fb_info);
h_sync = 1953125000 / init_var.pixclock;
@@ -1184,24 +1324,44 @@
v_sync = h_sync / (init_var.yres + init_var.upper_margin +
init_var.lower_margin + init_var.vsync_len);
- printk("Cyber2000: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+ printk("%s: %ldkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+ current_par.dev_name,
current_par.screen_size >> 10,
init_var.xres, init_var.yres,
h_sync / 1000, h_sync % 1000, v_sync);
- if (register_framebuffer(&fb_info) < 0)
- return -EINVAL;
+ if (register_framebuffer(&fb_info) < 0) {
+ err = -EINVAL;
+ goto release_smem;
+ }
+
+ current_par.initialised = 1;
MOD_INC_USE_COUNT; /* TODO: This driver cannot be unloaded yet */
return 0;
-}
+release_smem:
+ iounmap(current_par.screen_base);
+release_smem_resource:
+ release_mem_region(smem_base, smem_size);
+release_mmio:
+ iounmap(CyberRegs);
+release_mmio_resource:
+ release_mem_region(mmio_base, MMIO_SIZE);
+ return err;
+}
#ifdef MODULE
int __init init_module(void)
{
- return cyber2000fb_init();
+ int ret;
+
+ ret = cyber2000fb_init();
+ if (ret)
+ return ret;
+
+ return 0;
}
void cleanup_module(void)
@@ -1210,6 +1370,12 @@
decremented to zero */
unregister_framebuffer(&fb_info);
/* TODO: clean up ... */
+
+ iounmap(current_par.screen_base);
+ iounmap(CyberRegs);
+
+ release_mem_region(smem_base, current_par.screen_size);
+ release_mem_region(mmio_base, MMIO_SIZE);
}
#endif /* MODULE */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)