patch-2.1.79 linux/drivers/macintosh/aty.c

Next file: linux/drivers/macintosh/aty.h
Previous file: linux/drivers/macintosh/ati-vt.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.78/linux/drivers/macintosh/aty.c linux/drivers/macintosh/aty.c
@@ -4,6 +4,7 @@
  * Copyright (C) 1997 Michael AK Tesch
  *  written with much help from Jon Howell
  *  changes to support the vt chip set by harry ac eaton
+ *  gt chipset support, scrollback console by anthony tong <atong@uiuc.edu>
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -18,11 +19,11 @@
 #include <linux/pci.h>
 #include <linux/bios32.h>
 #include <linux/nvram.h>
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
 #include <asm/prom.h>
 #include <asm/io.h>
 #include <asm/pci-bridge.h>
-#include <linux/selection.h>
-#include <linux/vt_kern.h>
 #include "pmac-cons.h"
 #include "aty.h"
 
@@ -34,82 +35,105 @@
 	unsigned char cntl;
 };
 
-struct aty_regvals {
-     int	offset[3];		 /* first pixel address */
+typedef struct aty_regvals {
+	int offset[3];		/* first pixel address */
 
-     int	crtc_h_sync_strt_wid[3]; /* depth dependant */
-     int	crtc_gen_cntl[3];
-     int	mem_cntl[3];
-
-     int	crtc_h_tot_disp;         /* mode dependant */
-     int	crtc_v_tot_disp;
-     int	crtc_v_sync_strt_wid;
-     int	crtc_off_pitch;
-
-     unsigned char clock_val[2];        /* vals for 20 and 21 */
+	int crtc_h_sync_strt_wid[3];	/* depth dependant */
+	int crtc_gen_cntl[3];
+	int mem_cntl[3];
+
+	int crtc_h_tot_disp;	/* mode dependant */
+	int crtc_v_tot_disp;
+	int crtc_v_sync_strt_wid;
+	int crtc_off_pitch;
+
+	unsigned char clock_val[2];	/* vals for 20 and 21 */
+} aty_regvals;
+
+struct rage_regvals {
+	int h_total, h_sync_start, h_sync_width;
+	int v_total, v_sync_start, v_sync_width;
+	int h_sync_neg, v_sync_neg;
 };
 
-/*static void set_aty_clock(unsigned char *params);*/
 static int aty_vram_reqd(int vmode, int cmode);
+static aty_regvals *get_aty_struct(void);
 
 static unsigned char *frame_buffer;
 static int total_vram;		/* total amount of video memory, bytes */
-static int is_vt_chip;		/* whether a vt chip type was detected */
+static int chip_type;		/* what chip type was detected */
 
-static unsigned long aty_regbase;
+static unsigned long ati_regbase;
 static struct aty_cmap_regs *aty_cmap_regs;
 
+#if 0
 /* this array contains the number of bytes/line for each mode and color depth */
 static int pitch[20][3] = {
-	{0,0,0},  /* mode 1?? */
-	{0,0,0},  /* mode 2?? */
-	{0,0,0},  /* mode 3??*/
-	{0,0,0},  /* mode 4?? */
-	{640, 1280, 2560},  /* mode 5 */
-	{640, 1280, 2560},  /* mode 6 */
-	{640, 1280, 2560},  /* mode 7 */
-	{800, 1600, 3200},  /* mode 8 */
-	{0,0,0},  /* mode 9 ??*/
-	{800, 1600, 3200},  /* mode 10 */
-	{800, 1600, 3200},  /* mode 11 */
-	{800, 1600, 3200},  /* mode 12 */
-	{832, 1664, 3328},  /* mode 13 */
-	{1024, 2048, 4096},  /* mode 14 */
-	{1024, 2048, 4096},  /* mode 15 */
-	{1024, 2048, 4096},  /* mode 16 */
-	{1024, 2048, 4096},  /* mode 17 */
-	{1152, 2304, 4608},  /* mode 18 */
-	{1280, 2560, 5120},  /* mode 19 */
-	{1280, 2560, 5120}   /* mode 20 */
+	{512, 1024, 2048},		/* mode 1 */
+	{512, 1024, 2048},		/* mode 2 */
+	{640, 1024, 2048},		/* mode 3 */
+	{640, 1024, 2048},		/* mode 4 */
+	{640, 1280, 2560},		/* mode 5 */
+	{640, 1280, 2560},		/* mode 6 */
+	{640, 1280, 2560},		/* mode 7 */
+	{800, 1600, 3200},		/* mode 8 */
+	{768, 1536, 2072},		/* mode 9 */
+	{800, 1600, 3200},		/* mode 10 */
+	{800, 1600, 3200},		/* mode 11 */
+	{800, 1600, 3200},		/* mode 12 */
+	{832, 1664, 3328},		/* mode 13 */
+	{1024, 2048, 4096},		/* mode 14 */
+	{1024, 2048, 4096},		/* mode 15 */
+	{1024, 2048, 4096},		/* mode 16 */
+	{1024, 2048, 4096},		/* mode 17 */
+	{1152, 2304, 4608},		/* mode 18 */
+	{1280, 2560, 5120},		/* mode 19 */
+	{1280, 2560, 5120}		/* mode 20 */
 };
+#endif
 
+#include "ati-gx.h"
 #include "ati-gt.h"
 #include "ati-vt.h"
 
 static struct aty_regvals *aty_gt_reg_init[20] = {
 	NULL, NULL, NULL, NULL,
+	&aty_gt_reg_init_5,
 	&aty_gt_reg_init_6,
-	&aty_gt_reg_init_6,
-	NULL,
 	NULL, NULL,
-	NULL,
-	NULL,NULL,
+	&aty_gt_reg_init_9,
+	&aty_gt_reg_init_10,
+	&aty_gt_reg_init_11,
+	&aty_gt_reg_init_12,
 	&aty_gt_reg_init_13,
 	&aty_gt_reg_init_14,
 	&aty_gt_reg_init_15,
 	NULL,
 	&aty_gt_reg_init_17,
-	NULL,
+	&aty_gt_reg_init_18,
 	NULL,
 	&aty_gt_reg_init_20
 };
 
-static struct aty_regvals *aty_vt_reg_init[20] = {
+static struct aty_regvals *aty_gx_reg_init[20] = {
 	NULL, NULL, NULL, NULL,
-	&aty_vt_reg_init_5,
-	&aty_vt_reg_init_6,
+	&aty_gx_reg_init_6,
+	&aty_gx_reg_init_6,
+	NULL, NULL, NULL, NULL, NULL, NULL,
+	&aty_gx_reg_init_13,
+	&aty_gx_reg_init_14,
+	&aty_gx_reg_init_15,
 	NULL,
+	&aty_gx_reg_init_17,
 	NULL, NULL,
+	&aty_gx_reg_init_20
+};
+
+static struct aty_regvals *aty_vt_reg_init[21] = {
+	NULL, NULL, NULL, NULL,
+	&aty_vt_reg_init_5,
+	&aty_vt_reg_init_6,
+	NULL, NULL, NULL,
 	&aty_vt_reg_init_10,
 	&aty_vt_reg_init_11,
 	&aty_vt_reg_init_12,
@@ -119,330 +143,489 @@
 	NULL,
 	&aty_vt_reg_init_17,
 	&aty_vt_reg_init_18,
-	NULL,
+	&aty_vt_reg_init_19,
 	&aty_vt_reg_init_20
 };
 
-static inline int aty_vram_reqd(int vmode, int cmode)
+static inline int
+aty_vram_reqd(int vmode, int cmode)
 {
-	return vmode_attrs[vmode-1].vres
-		* pitch[vmode-1][cmode];
+	return vmode_attrs[vmode - 1].vres * 
+		(vmode_attrs[vmode - 1].hres << cmode);
 }
 
-extern inline unsigned aty_ld_rev(volatile unsigned long addr)
+extern inline unsigned aty_ld_le32(volatile unsigned long addr)
 {
-     unsigned val;
+	register unsigned long temp = ati_regbase,val;
 
-     (long)addr += (long)aty_regbase;
-     asm volatile("lwbrx %0,0,%1" : "=r" (val) : "r" (addr));
-     return val;
+	asm("lwbrx %0,%1,%2": "=r"(val):"r"(addr), "r"(temp));
+	return val;
 }
 
-extern inline void aty_st_rev(volatile unsigned long addr, unsigned val)
+extern inline void aty_st_le32(volatile unsigned long addr, unsigned val)
 {
-     (long)addr += (long)aty_regbase;
-     asm volatile("stwbrx %0,0,%1" : : "r" (val), "r" (addr) : "memory");
+	register unsigned long temp = ati_regbase;
+	asm("stwbrx %0,%1,%2": : "r"(val), "r"(addr), "r"(temp):"memory");
 }
 
-extern inline unsigned char aty_ld_byte(volatile unsigned long addr)
+extern inline unsigned char aty_ld_8(volatile unsigned long addr)
 {
-     unsigned char val;
-
-     val = *(char*)((long)addr+(long)aty_regbase);
-     return val;
+	return *(char *) ((long) addr + (long) ati_regbase);
 }
 
-extern inline void aty_st_byte(volatile unsigned long addr, unsigned char val)
+extern inline void aty_st_8(volatile unsigned long addr, unsigned char val)
 {
-     *(unsigned char*)(addr+(unsigned long)aty_regbase) = val;
+	*(unsigned char *) (addr + (unsigned long) ati_regbase) = val;
 }
 
-void
-aty_st_514( int offset, char val )
+static void aty_st_514(int offset, char val)
 {
-     aty_WaitQueue(5);
-     aty_st_byte( DAC_CNTL, 1);
-     aty_st_byte( DAC_W_INDEX, offset & 0xff );   /* right addr byte */
-     aty_st_byte( DAC_DATA, (offset>>8) & 0xff ); /* left addr byte */
-     aty_st_byte( DAC_MASK, val );
-     aty_st_byte( DAC_CNTL, 0 );
+	aty_WaitQueue(5);
+	aty_st_8(DAC_CNTL, 1);
+	aty_st_8(DAC_W_INDEX, offset & 0xff);	/* right addr byte */
+	aty_st_8(DAC_DATA, (offset >> 8) & 0xff);	/* left addr byte */
+	eieio();
+	aty_st_8(DAC_MASK, val);
+	eieio();
+	aty_st_8(DAC_CNTL, 0);
 }
 
-void
-aty_st_pll( int offset, char val )
+static void
+aty_st_pll(int offset, char val)
 {
-     aty_WaitQueue(3);
-     aty_st_byte( CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN );   /* write addr byte */
-     aty_st_byte( CLOCK_CNTL + 2, val); /* write the register value */
-     aty_st_byte( CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN);
+	aty_WaitQueue(3);
+	aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN);	/* write addr byte */
+	eieio();
+	aty_st_8(CLOCK_CNTL + 2, val);	/* write the register value */
+	eieio();
+	aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN);
+}
+
+#if 0 // unused
+static char
+aty_ld_pll(int offset)
+{
+	aty_WaitQueue(2);
+	aty_st_8(CLOCK_CNTL + 1, offset << 2);
+	eieio();
+	return aty_ld_8(CLOCK_CNTL + 2);
 }
+#endif
 
-#if 0
 unsigned char
-aty_ld_514( int offset )
+aty_ld_514(int offset)
 {
-/* do the same thing as aty_st_514, just read the DAC_MASK instead of writing*/
+/* do the same thing as aty_st_514, just read the DAC_MASK instead of writing */
+	char val;
+
+	aty_WaitQueue(5);
+	aty_st_8(DAC_CNTL, 1);
+	aty_st_8(DAC_W_INDEX, offset & 0xff);	/* right addr byte */
+	aty_st_8(DAC_DATA, (offset >> 8) & 0xff);	/* left addr byte */
+	val = aty_ld_8(DAC_MASK);
+	eieio();
+	aty_st_8(DAC_CNTL, 0);
+	return val;
 }
-#endif
 
 void
 aty_set_palette(unsigned char red[], unsigned char green[],
 		unsigned char blue[], int index, int ncolors)
 {
-     int i,scale;
+	int i, scale;
+
+	aty_WaitQueue(2);
+
+	i = aty_ld_8(DAC_CNTL) & 0xfc;
+	if (chip_type == MACH64_GT_ID)
+		i |= 0x2;		/*DAC_CNTL|0x2 turns off the extra brightness for gt*/
+	aty_st_8(DAC_CNTL, i);
+	aty_st_8(DAC_REGS + DAC_MASK, 0xff);
+	eieio();
+	scale = (chip_type != MACH64_GX_ID)
+		? ((color_mode == CMODE_16) ? 3 : 0) : 0;
+
+	for (i = 0; i < ncolors; ++i) {
+		aty_WaitQueue(4);
+		aty_cmap_regs->windex = (index + i) << scale; eieio();
+		aty_cmap_regs->lut = red[i];	eieio();
+		aty_cmap_regs->lut = green[i];	eieio();
+		aty_cmap_regs->lut = blue[i];	eieio();
+	}
+}
+
+static aty_regvals
+*get_aty_struct()
+{
+	int v = video_mode - 1;
+
+	switch (chip_type) {
+	case MACH64_GT_ID:
+		return aty_gt_reg_init[v];
+		break;
+	case MACH64_VT_ID:
+		return aty_vt_reg_init[v];
+		break;
+	default: /* default to MACH64_GX_ID */
+		return aty_gx_reg_init[v];
+		break;
+	}
+}
+
+static int
+read_aty_sense(void)
+{
+	int sense, i;
 
-     aty_WaitQueue(2);
-     aty_st_byte(DAC_CNTL, aty_ld_byte(DAC_CNTL) & 0xfc);
-     aty_st_byte(DAC_REGS + DAC_MASK, 0xff);
-     eieio();
-     scale = (is_vt_chip) ? ((color_mode == CMODE_16) ? 3 : 0) : 0;
-     for (i = 0; i < ncolors; ++i) {
-	  aty_WaitQueue(4);
-          aty_cmap_regs->windex = (index + i) << scale;	eieio();
-          aty_cmap_regs->lut = red[i];		eieio();
-          aty_cmap_regs->lut = green[i];	eieio();
-          aty_cmap_regs->lut = blue[i];		eieio();
-     }
-   
+	aty_st_le32(MON_SENSE, 0x31003100);	/* drive outputs high */
+	__delay(200);
+	aty_st_le32(MON_SENSE, 0);		/* turn off outputs */
+	__delay(2000);
+	i = aty_ld_le32(MON_SENSE);		/* get primary sense value */
+	sense = ((i & 0x3000) >> 3) | (i & 0x100);
+
+	/* drive each sense line low in turn and collect the other 2 */
+	aty_st_le32(MON_SENSE, 0x20000000);	/* drive A low */
+	__delay(2000);
+	i = aty_ld_le32(MON_SENSE);
+	sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4);
+	aty_st_le32(MON_SENSE, 0x20002000);	/* drive A high again */
+	__delay(200);
+
+	aty_st_le32(MON_SENSE, 0x10000000);	/* drive B low */
+	__delay(2000);
+	i = aty_ld_le32(MON_SENSE);
+	sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6);
+	aty_st_le32(MON_SENSE, 0x10001000);	/* drive B high again */
+	__delay(200);
+
+	aty_st_le32(MON_SENSE, 0x01000000);	/* drive C low */
+	__delay(2000);
+	sense |= (aty_ld_le32(MON_SENSE) & 0x3000) >> 12;
+	aty_st_le32(MON_SENSE, 0);		/* turn off outputs */
+
+	return sense;
 }
 
 void
 map_aty_display(struct device_node *dp)
 {
-     int i, sense;
-     unsigned long addr;
-     unsigned char bus, devfn;
-     unsigned short cmd;
-
-     if (dp->next != 0)
-	  printk("Warning: only using first ATI card detected\n");
-     if (dp->n_addrs != 1)
-	  panic("expecting 1 addresses for ATY (got %d)", dp->n_addrs);
-
-     aty_regbase = (int)ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
-     aty_cmap_regs = (struct aty_cmap_regs *)(aty_regbase+0xC0);
-
-     /* enable memory-space accesses using config-space command register */
-     if (pci_device_loc(dp, &bus, &devfn) == 0) {
-	  pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
-	  if (cmd != 0xffff) {
-	       cmd |= PCI_COMMAND_MEMORY;
-	       pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
-	  }
-     }
-
-     switch( aty_ld_rev(MEM_CNTL)&MEM_SIZE_ALIAS ) {
-     case MEM_SIZE_512K:
-	  total_vram = 0x80000;
-	  break;
-     case MEM_SIZE_1M:
-	  total_vram = 0x100000;
-	  break;
-     case MEM_SIZE_2M:
-	  total_vram = 0x200000;
-	  break;
-     case MEM_SIZE_4M:
-	  total_vram = 0x400000;
-	  break;
-     case MEM_SIZE_6M:
-	  total_vram = 0x600000;
-	  break;
-     case MEM_SIZE_8M:
-	  total_vram = 0x800000;
-	  break;
-     default:
-	  total_vram = 0x80000;
-     }
+	struct aty_regvals *init;
+	int i, sense;
+	unsigned long addr;
+	unsigned char bus, devfn;
+	unsigned short cmd;
+
+	if (dp->next != 0)
+	printk("Warning: only using first ATI card detected\n");
+	if (dp->n_addrs != 1 && dp->n_addrs != 3)
+	printk("Warning: expecting 1 or 3 addresses for ATY (got %d)",
+	       dp->n_addrs);
+
+	ati_regbase = (int) ioremap((0x7ffc00 + dp->addrs[0].address), 0x1000);
+	aty_cmap_regs = (struct aty_cmap_regs *) (ati_regbase + 0xC0);
+
+	/* enable memory-space accesses using config-space command register */
+	if (pci_device_loc(dp, &bus, &devfn) == 0) {
+		pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
+		if (cmd != 0xffff) {
+			cmd |= PCI_COMMAND_MEMORY;
+			pcibios_write_config_word(bus, devfn, PCI_COMMAND, cmd);
+		}
+	}
+	chip_type = (aty_ld_le32(CONFIG_CHIP_ID) & CFG_CHIP_TYPE);
+
+	i = aty_ld_le32(MEM_CNTL);
+	if (chip_type != MACH64_GT_ID)
+		switch (i & MEM_SIZE_ALIAS) {
+		case MEM_SIZE_512K:
+			total_vram = 0x80000;
+			break;
+		case MEM_SIZE_1M:
+			total_vram = 0x100000;
+			break;
+		case MEM_SIZE_2M:
+			total_vram = 0x200000;
+			break;
+		case MEM_SIZE_4M:
+			total_vram = 0x400000;
+			break;
+		case MEM_SIZE_6M:
+			total_vram = 0x600000;
+			break;
+		case MEM_SIZE_8M:
+			total_vram = 0x800000;
+			break;
+		default:
+			total_vram = 0x80000;
+		}
+	else
+		switch (i & 0xF) { /* 0xF used instead of MEM_SIZE_ALIAS */
+		case MEM_SIZE_512K:
+			total_vram = 0x80000;
+			break;
+		case MEM_SIZE_1M:
+			total_vram = 0x100000;
+			break;
+		case MEM_SIZE_2M_GTB:
+			total_vram = 0x200000;
+			break;
+		case MEM_SIZE_4M_GTB:
+			total_vram = 0x400000;
+			break;
+		case MEM_SIZE_6M_GTB:
+			total_vram = 0x600000;
+			break;
+		case MEM_SIZE_8M_GTB:
+			total_vram = 0x800000;
+			break;
+		default:
+			total_vram = 0x80000;
+		}
+
 #if 1
-     printk("aty_display_init: node = %p, addrs = ", dp->node);
-     printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
-     printk(", intrs =");
-     for (i = 0; i < dp->n_intrs; ++i)
-	  printk(" %x", dp->intrs[i]);
-     printk( "\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int)aty_regbase, 
-	     bus, devfn, total_vram, (int)aty_cmap_regs );
+	printk("aty_display_init: node = %p, addrs = ", dp->node);
+	printk(" %x(%x)", dp->addrs[0].address, dp->addrs[0].size);
+	printk(", intrs =");
+	for (i = 0; i < dp->n_intrs; ++i)
+	printk(" %x", dp->intrs[i]);
+	printk("\nregbase: %x pci loc: %x:%x total_vram: %x cregs: %x\n", (int) ati_regbase,
+		bus, devfn, total_vram, (int) aty_cmap_regs);
 #endif
-     is_vt_chip = ((aty_ld_rev(CONFIG_CHIP_ID) & CFG_CHIP_TYPE) == MACH64_VT_ID);
-     /* Map in frame buffer */
-     addr = dp->addrs[0].address;
-
-     /* use the big-endian aperture (??) */
-     addr += 0x800000;
-     frame_buffer = ioremap(addr, 0x800000);
-     
-
-     /*	sense = read_aty_sense(); XXX not yet, just give it mine */
-     sense = 0x62b;
-     if (video_mode == VMODE_NVRAM) {
-	  video_mode = nvram_read_byte(NV_VMODE);
-	  if (video_mode <= 0 || video_mode > VMODE_MAX
-	      || ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0)
-	       video_mode = VMODE_CHOOSE;
-     }
-     if (video_mode == VMODE_CHOOSE)
-	  video_mode = map_monitor_sense(sense);
-     if (((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1]) == 0)
-	  video_mode = VMODE_640_480_60;
-
-     /*
-      * Reduce the pixel size if we don't have enough VRAM.
-      */
-
-     if (color_mode == CMODE_NVRAM)
-        color_mode = nvram_read_byte(NV_CMODE);
-     if (color_mode < CMODE_8 || color_mode > CMODE_32)
-	color_mode = CMODE_8;
-     while (aty_vram_reqd(video_mode, color_mode) > total_vram) {
-     	while (color_mode > CMODE_8
-	    && aty_vram_reqd(video_mode, color_mode) > total_vram)
-	  --color_mode;
-        /*
-	 * adjust the video mode smaller if there still is not enough VRAM
+	/* Map in frame buffer */
+	addr = dp->addrs[0].address;
+
+	/* use the big-endian aperture (??) */
+	addr += 0x800000;
+	frame_buffer = ioremap(addr, 0x800000);
+
+	sense = read_aty_sense();
+	printk("monitor sense = %x\n", sense);
+	if (video_mode == VMODE_NVRAM) {
+		video_mode = nvram_read_byte(NV_VMODE);
+		init = get_aty_struct();
+		if (video_mode <= 0 || video_mode > VMODE_MAX || init == 0)
+			video_mode = VMODE_CHOOSE;
+	}
+	if (video_mode == VMODE_CHOOSE)
+		video_mode = map_monitor_sense(sense);
+
+	init = get_aty_struct();
+	if (!init)
+		video_mode = VMODE_640_480_60;
+
+	/*
+	 * Reduce the pixel size if we don't have enough VRAM.
 	 */
-	if (aty_vram_reqd(video_mode, color_mode) > total_vram)
-	  while ((((is_vt_chip) ? aty_vt_reg_init[--video_mode - 1]
-	        : aty_gt_reg_init[--video_mode -1 ]) == 0) && (video_mode > VMODE_640_480_60)) ;
-    }
-}
 
-#if 0
-static void
-set_aty_clock(unsigned char *params)
-{
-     /* done in aty_init...probably need to change for different modes */
-     printk("tried to set ATY clock\n");
+	if (color_mode == CMODE_NVRAM)
+		color_mode = nvram_read_byte(NV_CMODE);
+	if (color_mode < CMODE_8 || color_mode > CMODE_32)
+		color_mode = CMODE_8;
+
+	while (aty_vram_reqd(video_mode, color_mode) > total_vram) {
+		while (color_mode > CMODE_8
+			&& aty_vram_reqd(video_mode, color_mode) > total_vram)
+			--color_mode;
+		/*
+		 * adjust the video mode smaller if there still is not enough VRAM
+		 */
+		if (aty_vram_reqd(video_mode, color_mode) > total_vram) {
+			do {
+				video_mode--;
+				init = get_aty_struct();
+			} while ((init == 0) && (video_mode > VMODE_640_480_60));
+		}
+	}
+
+	if (chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5
+			&& init->crtc_gen_cntl[1] == 0) {
+		video_mode = 6; color_mode = 0;
+	}
+	return;
 }
-#endif
 
 void
 RGB514_Program(int cmode)
 {
-     typedef struct {
-          char    pixel_dly;
-          char    misc2_cntl;
-          char    pixel_rep;
-          char    pixel_cntl_index;
-          char    pixel_cntl_v1;
-     } RGB514_DAC_Table;
-
-     static  RGB514_DAC_Table RGB514DAC_Tab[8] = {
-          { 0, 0x41, 0x03, 0x71, 0x45 },          // 8bpp
-          { 0, 0x45, 0x04, 0x0c, 0x01 },          // 555
-          { 0, 0x45, 0x06, 0x0e, 0x00 },          // XRGB
-     };
-     RGB514_DAC_Table *pDacProgTab;
-
-     pDacProgTab = &RGB514DAC_Tab[cmode];
-
-     aty_st_514(0x90, 0x00);
-     aty_st_514(0x04, pDacProgTab->pixel_dly);
-     aty_st_514(0x05, 0x00);
-
-     aty_st_514(0x2, 0x1);
-     aty_st_514(0x71, pDacProgTab->misc2_cntl);
-     aty_st_514(0x0a, pDacProgTab->pixel_rep);
+	typedef struct {
+		char pixel_dly;
+		char misc2_cntl;
+		char pixel_rep;
+		char pixel_cntl_index;
+		char pixel_cntl_v1;
+	} RGB514_DAC_Table;
+
+	static RGB514_DAC_Table RGB514DAC_Tab[8] = {
+		{0, 0x41, 0x03, 0x71, 0x45},	// 8bpp
+		{0, 0x45, 0x04, 0x0c, 0x01},	// 555
+		{0, 0x45, 0x06, 0x0e, 0x00},	// XRGB
+	};
+	RGB514_DAC_Table *pDacProgTab;
+
+	pDacProgTab = &RGB514DAC_Tab[cmode];
+
+	aty_st_514(0x90, 0x00);
+	aty_st_514(0x04, pDacProgTab->pixel_dly);
+	aty_st_514(0x05, 0x00);
+
+	aty_st_514(0x2, 0x1);
+	aty_st_514(0x71, pDacProgTab->misc2_cntl);
+	aty_st_514(0x0a, pDacProgTab->pixel_rep);
 
-     aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1);
+	aty_st_514(pDacProgTab->pixel_cntl_index, pDacProgTab->pixel_cntl_v1);
 }
 
-/* The vt chipset seems to need a specialized color table for 15 bit mode */
 void
-VT_Program(int cmode)
+aty_init()
 {
-#if 0
-	int i;
-	if (cmode != CMODE_8) {
-		aty_WaitQueue(2);
-		aty_cmap_regs->mask = 0xff; eieio();
-		aty_cmap_regs->windex = 0; eieio();
-		for (i = 0; i < 0x100; i++) {
-			aty_WaitQueue(3);
-			aty_cmap_regs->lut = i;
-			aty_cmap_regs->lut = i;
-			aty_cmap_regs->lut = i; eieio();
+	int i, hres;
+	struct aty_regvals *init = get_aty_struct();
+	int vram_type = aty_ld_le32(CONFIG_STAT0) & 7;
+
+	if (init == 0) /* paranoia, shouldn't get here */
+		panic("aty: display mode %d not supported", video_mode);
+
+	n_scanlines = vmode_attrs[video_mode - 1].vres;
+	hres = vmode_attrs[video_mode - 1].hres;
+	pixel_size = 1 << color_mode;
+	line_pitch = vmode_attrs[video_mode - 1].hres << color_mode;
+	row_pitch = line_pitch * 16;
+
+	/* clear FIFO errors */
+	aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL) | BUS_HOST_ERR_ACK
+		| BUS_FIFO_ERR_ACK);
+
+	/* Reset engine */
+	i = aty_ld_le32(GEN_TEST_CNTL);
+	aty_st_le32(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE);
+	eieio();
+	aty_WaitIdleEmpty();
+	aty_st_le32(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE);
+	aty_WaitIdleEmpty();
+
+	if ( chip_type != MACH64_GT_ID ) {
+		i = aty_ld_le32(CRTC_GEN_CNTL);
+		aty_st_le32(CRTC_GEN_CNTL, i | CRTC_EXT_DISP_EN);
+	}
+
+	if ( chip_type == MACH64_GX_ID ) { 
+		i = aty_ld_le32(GEN_TEST_CNTL);
+		aty_st_le32(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN );
+	}
+
+	switch (chip_type) {
+	case MACH64_VT_ID:
+		aty_st_pll(PLL_MACRO_CNTL, 0xb5);
+		aty_st_pll(PLL_REF_DIV, 0x2d);
+		aty_st_pll(PLL_GEN_CNTL, 0x14);
+		aty_st_pll(MCLK_FB_DIV, 0xbd);
+		aty_st_pll(PLL_VCLK_CNTL, 0x0b);
+		aty_st_pll(VCLK_POST_DIV, init->clock_val[0]);
+		aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]);
+		aty_st_pll(VCLK1_FB_DIV, 0xd6);
+		aty_st_pll(VCLK2_FB_DIV, 0xee);
+		aty_st_pll(VCLK3_FB_DIV, 0xf8);
+		aty_st_pll(PLL_XCLK_CNTL, 0x0);
+		aty_st_pll(PLL_TEST_CTRL, 0x0);
+		aty_st_pll(PLL_TEST_COUNT, 0x0);
+		break;
+	case MACH64_GT_ID:
+		if (vram_type == 5) {
+			aty_st_pll(0, 0xcd);
+			aty_st_pll(PLL_MACRO_CNTL, 
+				  video_mode >= VMODE_1024_768_60? 0xd3: 0xd5);
+			aty_st_pll(PLL_REF_DIV, 0x21);
+			aty_st_pll(PLL_GEN_CNTL, 0x44);
+			aty_st_pll(MCLK_FB_DIV, 0xe8);
+			aty_st_pll(PLL_VCLK_CNTL, 0x03);
+			aty_st_pll(VCLK_POST_DIV, init->offset[0]);
+			aty_st_pll(VCLK0_FB_DIV, init->offset[1]);
+			aty_st_pll(VCLK1_FB_DIV, 0x8e);
+			aty_st_pll(VCLK2_FB_DIV, 0x9e);
+			aty_st_pll(VCLK3_FB_DIV, 0xc6);
+			aty_st_pll(PLL_XCLK_CNTL, init->offset[2]);
+			aty_st_pll(12, 0xa6);
+			aty_st_pll(13, 0x1b);
+		} else {
+			aty_st_pll(PLL_MACRO_CNTL, 0xd5);
+			aty_st_pll(PLL_REF_DIV, 0x21);
+			aty_st_pll(PLL_GEN_CNTL, 0xc4); 
+			aty_st_pll(MCLK_FB_DIV, 0xda);
+			aty_st_pll(PLL_VCLK_CNTL, 0x03);
+			/* offset actually holds clock values */
+			aty_st_pll(VCLK_POST_DIV, init->offset[0]);
+			aty_st_pll(VCLK0_FB_DIV, init->offset[1]);
+			aty_st_pll(VCLK1_FB_DIV, 0x8e);
+			aty_st_pll(VCLK2_FB_DIV, 0x9e);
+			aty_st_pll(VCLK3_FB_DIV, 0xc6);
+			aty_st_pll(PLL_TEST_CTRL, 0x0);
+			aty_st_pll(PLL_XCLK_CNTL, init->offset[2]);
+			aty_st_pll(12, 0xa0);
+			aty_st_pll(13, 0x1b);
 		}
+		break;
+	default:
+		RGB514_Program(color_mode);
+		aty_WaitIdleEmpty();
+		aty_st_514(0x06, 0x02);
+		aty_st_514(0x10, 0x01);
+		aty_st_514(0x70, 0x01);
+		aty_st_514(0x8f, 0x1f);
+		aty_st_514(0x03, 0x00);
+		aty_st_514(0x05, 0x00);
+		aty_st_514(0x20, init->clock_val[0]);
+		aty_st_514(0x21, init->clock_val[1]);
+		break;
 	}
-#endif
-}
 
-void
-aty_init()
-{
-     int i, yoff, hres;
-     unsigned *p;
-     struct aty_regvals *init;
-
-     if (video_mode <= 0 || video_mode > VMODE_MAX
-	 || (init = ((is_vt_chip) ? aty_vt_reg_init[video_mode-1] : aty_gt_reg_init[video_mode-1])) == 0)
-	  panic("aty: display mode %d not supported", video_mode);
-     n_scanlines = vmode_attrs[video_mode-1].vres;
-     hres = vmode_attrs[video_mode-1].hres;
-     pixel_size = 1 << color_mode;
-     line_pitch = pitch[video_mode-1][color_mode];
-     row_pitch = line_pitch * 16;
-
-     aty_st_rev(BUS_CNTL, aty_ld_rev(BUS_CNTL) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK);
-		
-     /* Reset engine */
-     i = aty_ld_rev(GEN_TEST_CNTL);
-     aty_st_rev(GEN_TEST_CNTL, i & ~GUI_ENGINE_ENABLE);
-     eieio();
-     aty_WaitIdleEmpty();
-     aty_st_rev(GEN_TEST_CNTL, i | GUI_ENGINE_ENABLE);
-     aty_WaitIdleEmpty();
-			
-     i = aty_ld_byte(CRTC_GEN_CNTL+3);
-     aty_st_byte(CRTC_GEN_CNTL+3, i | (CRTC_EXT_DISP_EN >> 24));
-
-     i = aty_ld_byte(GEN_TEST_CNTL);
-     aty_st_byte(GEN_TEST_CNTL, i | GEN_OVR_OUTPUT_EN );
-
-     if (!is_vt_chip) {		
-     	RGB514_Program(color_mode);
-
-     	aty_WaitIdleEmpty();
-
-     	aty_st_514(0x06, 0x02);
-     	aty_st_514(0x10, 0x01);
-     	aty_st_514(0x70, 0x01);
-     	aty_st_514(0x8f, 0x1f);
-     	aty_st_514(0x03, 0x00);
-     	aty_st_514(0x05, 0x00);
-     
-     	aty_st_514(0x20, init->clock_val[0]);
-    	aty_st_514(0x21, init->clock_val[1]);
-     } else {
-	VT_Program(color_mode);
-    	aty_st_pll(PLL_MACRO_CNTL, 0xb5);
-    	aty_st_pll(PLL_REF_DIV, 0x2d);
-    	aty_st_pll(PLL_GEN_CNTL, 0x14);
-    	aty_st_pll(MCLK_FB_DIV, 0xbd);
-    	aty_st_pll(PLL_VCLK_CNTL, 0x0b);
-    	aty_st_pll(VCLK_POST_DIV, init->clock_val[0]);
-    	aty_st_pll(VCLK0_FB_DIV, init->clock_val[1]);
-    	aty_st_pll(VCLK1_FB_DIV, 0xd6);
-    	aty_st_pll(VCLK2_FB_DIV, 0xee);
-    	aty_st_pll(VCLK3_FB_DIV, 0xf8);
-    	aty_st_pll(PLL_XCLK_CNTL, 0x0);
-    	aty_st_pll(PLL_TEST_CTRL, 0x0);
-     	aty_st_pll(PLL_TEST_COUNT, 0x0);
-     }
- 	  	
-     aty_ld_byte( DAC_REGS ); /* clear counter */
-			
-     aty_WaitIdleEmpty();
-
-     aty_st_rev(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp);
-     aty_st_rev(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[color_mode]);
-     aty_st_rev(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp);
-     aty_st_rev(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid);
-
-     aty_st_byte(CLOCK_CNTL, 0);
-     aty_st_byte(CLOCK_CNTL, CLOCK_STROBE);
-
-     aty_st_rev(CRTC_OFF_PITCH, init->crtc_off_pitch);
-     
-     aty_st_rev(CRTC_VLINE_CRNT_VLINE, 0x14e01d0);
+	aty_ld_8(DAC_REGS);	/* clear counter */
+	aty_WaitIdleEmpty();
+
+	aty_st_le32(CRTC_H_TOTAL_DISP, init->crtc_h_tot_disp);
+	aty_st_le32(CRTC_H_SYNC_STRT_WID, init->crtc_h_sync_strt_wid[color_mode]);
+	aty_st_le32(CRTC_V_TOTAL_DISP, init->crtc_v_tot_disp);
+	aty_st_le32(CRTC_V_SYNC_STRT_WID, init->crtc_v_sync_strt_wid);
+
+	aty_st_8(CLOCK_CNTL, 0);
+	aty_st_8(CLOCK_CNTL, CLOCK_STROBE);
+
+	aty_st_le32(CRTC_VLINE_CRNT_VLINE, 0);
+
+	if (chip_type == MACH64_GT_ID) {
+		aty_st_le32(BUS_CNTL, 0x7b23a040);
+
+		/* we calculate this so we can use a scrollback buffer.
+		 * this should theoretically work with other ati's
+		 * OFF_PITCH == (((hres + 7) & 0xfff8) >> 3) << 22 
+		 */
+		ati_set_origin(0);
+
+		/* need to set DSP values !! assume sdram */
+		i = init->crtc_gen_cntl[0] - (0x100000 * color_mode);
+		if ( vram_type == 5 )
+			i = init->crtc_gen_cntl[1] - (0x100000 * color_mode);
+		aty_st_le32(DSP_CONFIG, i); 
+
+		i = aty_ld_le32(MEM_CNTL) & MEM_SIZE_ALIAS;
+		if ( vram_type == 5 ) {
+			i |= ((1 * color_mode) << 26) | 0x4215b0;
+			aty_st_le32(DSP_ON_OFF,sgram_dsp[video_mode-1][color_mode]);
+
+		//aty_st_le32(CLOCK_CNTL,8192);
+		} else {
+			i |= ((1 * color_mode) << 26) | 0x300090;
+			aty_st_le32(DSP_ON_OFF, init->mem_cntl[color_mode]);
+		}
+
+		aty_st_le32(MEM_CNTL, i);
+		aty_st_le32(EXT_MEM_CNTL, 0x5000001);
+
+		/* if (total_vram > 0x400000)	
+			i |= 0x538; this not been verified on > 4Megs!! */
+	} else {
+		aty_st_le32(CRTC_OFF_PITCH, init->crtc_off_pitch);
+
 /* The magic constant below translates into: 
  * 5   = No RDY delay, 1 wait st for mem write, increment during burst transfer
  * 9   = DAC access delayed, 1 wait state for DAC
@@ -455,75 +638,115 @@
  * at some point it would be good to experiment with bench marks to see if
  * we can gain some speed by fooling with the wait states etc.
  */
-     aty_st_rev(BUS_CNTL, 0x590e10ff);
-     i = aty_ld_rev(MEM_CNTL) & MEM_SIZE_ALIAS;
-     if (total_vram >= 0x400000)
-        aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] &0xffff0000) | 0x0538 | i);
-     else
-        aty_st_rev(MEM_CNTL, (init->mem_cntl[color_mode] & ~MEM_SIZE_ALIAS) | i ); 
-     aty_st_rev(CRTC_INT_CNTL, 0x2);
-     aty_WaitIdleEmpty();
+		if (chip_type == MACH64_VT_ID)
+			aty_st_le32(BUS_CNTL, 0x680000f9);
+		else
+			aty_st_le32(BUS_CNTL, 0x590e10ff);
+
+		switch (total_vram) {
+		case 0x00100000:
+			aty_st_le32(MEM_CNTL, vt_mem_cntl[0][color_mode]);
+			break;
+		case 0x00200000:
+			aty_st_le32(MEM_CNTL, vt_mem_cntl[1][color_mode]);
+			break;
+		case 0x00400000:
+			aty_st_le32(MEM_CNTL, vt_mem_cntl[2][color_mode]);
+			break;
+		default:
+			i = aty_ld_le32(MEM_CNTL) & 0x000F;
+			aty_st_le32(MEM_CNTL, (init->mem_cntl[color_mode] & 0xFFFFFFF0) | i);
+		}
+	}
 /* These magic constants are harder to figure out
- * on the vt chipset bit 3 set makes the screen brighter
+ * on the vt chipset bit 2 set makes the screen brighter
  * and bit 15 makes the screen black! But nothing else
  * seems to matter for the vt DAC_CNTL
  */
-     if (is_vt_chip)
-	aty_st_rev(DAC_CNTL, 0x47012104);
-     else
-        aty_st_rev(DAC_CNTL, 0x47012100);
-
-     aty_st_byte(DAC_MASK, 0xff);
-
-     aty_st_rev(CRTC_INT_CNTL, 0x00000002);
-     
-     aty_st_byte(CRTC_FIFO, ((char*)&init->crtc_gen_cntl[color_mode])[1] );
-     aty_st_byte(CRTC_PIX_WIDTH, ((char*)&init->crtc_gen_cntl[color_mode])[2] );
-     aty_st_byte(CRTC_EXT_DISP, ((char*)&init->crtc_gen_cntl[color_mode])[0] );
-     
-     aty_st_rev(GEN_TEST_CNTL, 0x300); /* gui_en block_en*/
-
-     pmac_init_palette();		/* Initialize colormap */
-     yoff = (n_scanlines % 16) / 2;
-     fb_start = frame_buffer + yoff * line_pitch + init->offset[color_mode];
-
-     /* Clear screen */
-     p = (unsigned *) fb_start;
-
-     for (i = n_scanlines * line_pitch * pixel_size / sizeof(unsigned); i != 0; --i)
-	  *p++ = 0;
-     display_info.height = n_scanlines;
-     display_info.width = hres;
-     display_info.depth = pixel_size * 8;
-     display_info.pitch = line_pitch;
-     display_info.mode = video_mode;
-     strncpy(display_info.name, "ATY Mach64", sizeof(display_info.name));
-     display_info.fb_address = (unsigned long) frame_buffer + init->offset[color_mode];
-     display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex;
-     display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut;
-     display_info.disp_reg_address = aty_regbase;
+	switch (chip_type) {
+	case MACH64_GT_ID:
+		i = 0x86010102;
+		break;
+	case MACH64_VT_ID:
+		i = 0x87010184;
+		break;
+	default:
+		i = 0x47012100;
+		break;
+	}
+
+	aty_st_le32(DAC_CNTL, i);
+	aty_st_8(DAC_MASK, 0xff);
+
+	switch (color_mode) {
+	case CMODE_16:
+		i = CRTC_PIX_WIDTH_15BPP; break;
+	/*case CMODE_24: */
+	case CMODE_32:
+		i = CRTC_PIX_WIDTH_32BPP; break;
+	case CMODE_8:
+	default:
+		i = CRTC_PIX_WIDTH_8BPP; break;
+	}
+
+	if (chip_type != MACH64_GT_ID) {
+		aty_st_le32(CRTC_INT_CNTL, 0x00000002);
+		aty_st_le32(GEN_TEST_CNTL, GUI_ENGINE_ENABLE | BLOCK_WRITE_ENABLE);	/* gui_en block_en */
+		i |= init->crtc_gen_cntl[color_mode];
+	}
+	/* Gentlemen, start your crtc engine */
+	aty_st_le32(CRTC_GEN_CNTL, CRTC_EXT_DISP_EN | CRTC_EXT_EN | i);
+	pmac_init_palette();	/* Initialize colormap */
+
+	/* clear screen */
+	fb_start = frame_buffer + (((n_scanlines % 16) * line_pitch) >> 1);
+	memsetw((unsigned short *) fb_start, 0, total_vram);
+
+	display_info.height = n_scanlines;
+	display_info.width = hres;
+	display_info.depth = pixel_size << 3;
+	display_info.pitch = line_pitch;
+	display_info.mode = video_mode;
+	strncpy(display_info.name, "ATY Mach64", sizeof(display_info.name));
+	switch ( chip_type ) {
+	case MACH64_GX_ID: strcat(display_info.name,"GX");
+		break;
+	case MACH64_VT_ID: strcat(display_info.name,"VT");
+		break;
+	case MACH64_GT_ID: strcat(display_info.name,"GT");
+		break;
+	default: strcat(display_info.name,"unknown");
+		break;
+	}
+	display_info.fb_address = (chip_type != MACH64_GT_ID) ?
+		(unsigned long) frame_buffer + init->offset[color_mode] :
+		(unsigned long) frame_buffer;
+	display_info.cmap_adr_address = (unsigned long) &aty_cmap_regs->windex;
+	display_info.cmap_data_address = (unsigned long) &aty_cmap_regs->lut;
+	display_info.disp_reg_address = ati_regbase;
 }
 
 int
 aty_setmode(struct vc_mode *mode, int doit)
 {
-	int cmode;
-#if 0
+	int cmode,old_vmode=video_mode;
+	struct aty_regvals *init;
+
+#if 1
 	if (mode->mode == 21) {
-		printk("hace: about to set 0x%x to 0x%x\n",mode->depth, mode->pitch & 0xff);
-		aty_st_byte(mode->depth, mode->pitch & 0xff);
+		printk("hace: about to set 0x%x to 0x%x\n", mode->depth, mode->pitch & 0xff);
+		aty_st_8(mode->depth, mode->pitch & 0xff);
 		return 0;
 	}
-
 	if (mode->mode == 0) {
-		printk("hace: 0x%x contains 0x%x\n",mode->depth, aty_ld_byte(mode->depth));
+		printk("hace: 0x%x contains 0x%x\n", mode->depth, aty_ld_8(mode->depth));
 		return 0;
 	}
-#endif		
-	
-	if (mode->mode <= 0 || mode->mode > VMODE_MAX
-	    || ((is_vt_chip) ? aty_vt_reg_init[mode->mode-1] : aty_gt_reg_init[mode->mode-1]) == NULL)
+#endif
+
+	if (mode->mode <= 0 || mode->mode > VMODE_MAX )
 		return -EINVAL;
+
 	switch (mode->depth) {
 	case 24:
 	case 32:
@@ -539,12 +762,25 @@
 	default:
 		return -EINVAL;
 	}
-	if (aty_vram_reqd(mode->mode, cmode) > total_vram) {
+	if (aty_vram_reqd(mode->mode, cmode) > total_vram)
 		return -EINVAL;
+
+	video_mode = mode->mode;
+	init = get_aty_struct();
+
+	/* Check if we know about the wanted video mode */
+	if ( init == 0 || init->crtc_h_sync_strt_wid[cmode] == 0
+	   || (chip_type != MACH64_GT_ID && init->crtc_gen_cntl[cmode] == 0)
+	   || (chip_type == MACH64_GT_ID && (aty_ld_le32(CONFIG_STAT0) & 7) == 5
+	   && init->crtc_gen_cntl[1] == 0)) {
+			video_mode = old_vmode;
+			return -EINVAL;
 	}
+
 	if (doit) {
 		video_mode = mode->mode;
 		color_mode = cmode;
+		hide_cursor();
 		aty_init();
 	}
 	return 0;
@@ -555,7 +791,7 @@
 {
 	char gen_cntl;
 
-	gen_cntl = aty_ld_byte(CRTC_GEN_CNTL);
+	gen_cntl = aty_ld_8(CRTC_GEN_CNTL);
 	if (blank_mode & VESA_VSYNC_SUSPEND)
 		gen_cntl |= 0x8;
 	if (blank_mode & VESA_HSYNC_SUSPEND)
@@ -564,5 +800,33 @@
 		gen_cntl |= 0x40;
 	if (blank_mode == VESA_NO_BLANKING)
 		gen_cntl &= ~(0x4c);
-	aty_st_byte(CRTC_GEN_CNTL, gen_cntl);
+	aty_st_8(CRTC_GEN_CNTL, gen_cntl);
 }
+
+/* handle video scrollback; offset is in # of characters */
+void
+ati_set_origin(unsigned short offset)
+{
+	register int x = (vmode_attrs[video_mode - 1].hres + 7) & 0xfff8,
+		lines = offset / video_num_columns, reg;
+
+	reg = ((x >> 3) << 22) |	/* calculate pitch */
+	  ((lines * video_font_height * x * (1<<color_mode)) >> 3); /*offset*/
+
+	aty_st_le32(CRTC_OFF_PITCH, reg);
+	aty_st_le32(DST_OFF_PITCH, reg);
+	aty_st_le32(SRC_OFF_PITCH, reg);
+
+#if 0
+	fb_start = display_info.fb_address = 
+		(unsigned long) frame_buffer + ((lines-2) * 
+		vmode_attrs[video_mode-1].hres) << (4 + color_mode);
+#endif
+}
+
+int
+ati_vram(void)
+{
+	return total_vram;
+}
+

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov