--- drivers/video/atyfb.c.org	Mon Apr  3 20:20:24 2000
+++ drivers/video/atyfb.c	Thu Jul 27 21:25:42 2000
@@ -1061,6 +1061,7 @@
     u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;
     u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;
     u32 pix_width, dp_pix_width, dp_chain_mask;
+    u32 depth;
 
     /* input */
     xres = var->xres;
@@ -1070,6 +1071,7 @@
     xoffset = var->xoffset;
     yoffset = var->yoffset;
     bpp = var->bits_per_pixel;
+    depth = var->red.length + var->green.length + var->blue.length + var->transp.length;
     left = var->left_margin;
     right = var->right_margin;
     upper = var->upper_margin;
@@ -1118,6 +1120,9 @@
 
     c_sync = sync & FB_SYNC_COMP_HIGH_ACT ? CRTC_CSYNC_EN : 0;
 
+    if (depth > bpp+1)
+        depth = bpp;
+
     if (bpp <= 8) {
 	bpp = 8;
 	pix_width = CRTC_PIX_WIDTH_8BPP;
@@ -1125,10 +1130,24 @@
 	dp_chain_mask = 0x8080;
     } else if (bpp <= 16) {
 	bpp = 16;
+#if 1
 	pix_width = CRTC_PIX_WIDTH_15BPP;
 	dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
 		       BYTE_ORDER_LSB_TO_MSB;
 	dp_chain_mask = 0x4210;
+#else
+	if (depth == 15) {
+	    pix_width = CRTC_PIX_WIDTH_15BPP;
+	    dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP |
+		           BYTE_ORDER_LSB_TO_MSB;
+	    dp_chain_mask = 0x4210;
+	} else {
+	    pix_width = CRTC_PIX_WIDTH_16BPP;
+	    dp_pix_width = HOST_16BPP | SRC_16BPP | DST_16BPP |
+		           BYTE_ORDER_LSB_TO_MSB;
+	    dp_chain_mask = 0x8410;
+	}
+#endif
     } else if ((bpp <= 24) && (Gx != GX_CHIP_ID) && (Gx != CX_CHIP_ID)) {
 	bpp = 24;
 	pix_width = CRTC_PIX_WIDTH_24BPP;
@@ -1285,7 +1304,7 @@
 	    var->transp.offset = 0;
 	    var->transp.length = 0;
 	    break;
-#if 0
+#if 1
 	case CRTC_PIX_WIDTH_16BPP:	/* RGB 565 */
 	    bpp = 16;
 	    var->red.offset = 11;
@@ -3176,7 +3195,7 @@
     u8 bus, devfn;
     u16 cmd;
     struct fb_info_aty *info;
-    int i;
+    int i, i_frame, i_regs, i_io, naddr;
 
     if (device_is_compatible(dp, "ATY,264LTPro")) {
 	/* XXX kludge for now */
@@ -3204,6 +3223,13 @@
 	    return;
     }
 
+    printk("atyfb: of_init got %d OF adresses for ATY:\n", dp->n_addrs);
+    for (i = 0; i < dp->n_addrs; i++)
+	printk(" %08x-%08x", dp->addrs[i].address,
+	       dp->addrs[i].address+dp->addrs[i].size-1);
+    if (dp->n_addrs)
+	printk("\n");
+
     info = kmalloc(sizeof(struct fb_info_aty), GFP_ATOMIC);
     if (!info) {
 	printk("atyfb_of_init: can't alloc fb_info_aty\n");
@@ -3215,6 +3241,8 @@
     info->ati_regbase = (unsigned long)ioremap(info->ati_regbase_phys,
 						   0x1000);
 
+    printk("atyfb: regbase phys 0x%lx virt 0x%lx\n", info->ati_regbase_phys, info->ati_regbase);
+
     if(! info->ati_regbase) {
 	    printk("atyfb_init: ioremap() returned NULL\n");
 	    kfree(info);
@@ -3226,6 +3254,53 @@
 
     /* enable memory-space accesses using config-space command register */
     if (pci_device_loc(dp, &bus, &devfn) == 0) {
+
+	for (i = 0; i < dp->n_addrs + 2; i++) {
+	    int io, breg = PCI_BASE_ADDRESS_0 + (i << 2);
+	    unsigned long base;
+	    u32 size, pbase;
+
+	    base = dp->addrs[i].address;
+
+	    pcibios_read_config_dword(bus, devfn, breg, &pbase);
+	    pcibios_write_config_dword(bus, devfn, breg, 0xffffffff);
+	    pcibios_read_config_dword(bus, devfn, breg, &size);
+	    pcibios_write_config_dword(bus, devfn, breg, pbase);
+
+	    io = (pbase & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+
+	    if (io) {
+		size &= ~1;
+		i_io = i;
+	    }
+
+	    size = ~(size) + 1;
+	    
+	    if (size == 0) 
+	    	break;
+
+	    printk("atyfb: chunk %d ofbase 0x%lx breg %d io %d pbase 0x%lx size 0x%lx \n",
+		i, base, breg, io, pbase, size);
+
+	    if (!base) {
+		printk("atyfb: chunk %d assigning ofbase 0x%lx \n", i, pbase);
+		dp->addrs[i].address = pbase;
+		dp->addrs[i].size = size;
+	    }
+	    if (pbase == addr) {
+		printk("atyfb: chunk %d assigned as VRAM aperture! \n", i);
+		i_frame = i;
+	    }
+	    if (size == 0x1000) {
+		printk("atyfb: chunk %d assigned as MMIO aperture! \n", i);
+		i_regs = i;
+	    }
+
+	}
+
+	naddr = i;
+	printk("atyfb: found %d PCI addresses total. \n", i);
+
 	pcibios_read_config_word(bus, devfn, PCI_COMMAND, &cmd);
 	if (cmd != 0xffff) {
 	    cmd |= PCI_COMMAND_MEMORY;
@@ -3242,12 +3317,88 @@
     info->frame_buffer_phys = addr;
     info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
 
+    printk("atyfb: framebuffer phys 0x%lx virt 0x%lx\n", info->frame_buffer_phys, info->frame_buffer);
+
     if(! info->frame_buffer) {
 	    printk("atyfb_init: ioremap() returned NULL\n");
 	    kfree(info);
 	    return;
     }
 
+    /* 
+     * Fix MMIO mapping if MMIO and VRAM overlap 
+     * Note that we can't move the VRAM base address to the BE aperture (this would move the whole
+     * VRAM region, not resize it) so it's easier to remap MMIO someplace else.
+     */
+    if ( (dp->addrs[i_frame].address < dp->addrs[i_regs].address+dp->addrs[i_regs].size 
+	 && dp->addrs[i_frame].address+dp->addrs[i_frame].size >= dp->addrs[i_regs].address)
+    	 || (dp->addrs[i_regs].address < dp->addrs[i_frame].address+dp->addrs[i_frame].size
+    	    && dp->addrs[i_regs].address+dp->addrs[i_regs].size >= dp->addrs[i_frame].address) ) {
+
+	    struct pci_dev *pdev = pci_find_slot(bus, devfn);
+	    int io, breg = PCI_BASE_ADDRESS_0 + (i_regs << 2);
+	    int flags;
+	    unsigned long base;
+	    u32 size, pbase, new;
+
+	    base = dp->addrs[i_regs].address;
+
+	    pcibios_read_config_dword(bus, devfn, breg, &pbase);
+	    pcibios_write_config_dword(bus, devfn, breg, 0xffffffff);
+	    pcibios_read_config_dword(bus, devfn, breg, &size);
+	    pcibios_write_config_dword(bus, devfn, breg, pbase);
+
+	    io = (pbase & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+	    flags = (pbase & PCI_BASE_ADDRESS_MEM_MASK);
+
+	    if (io)
+		size &= ~1;
+	    size = ~(size) + 1;
+	    
+	    printk("atyfb: chunk %d ofbase 0x%lx breg %d io %d pbase 0x%lx size 0x%lx needs reassigning! \n",
+		i_regs, base, breg, io, pbase, size);
+
+#if 0
+	    /* move MMIO past frame buffer for now. Need to walk PCI resources to find safe place */
+	    new = (dp->addrs[i_frame].address+dp->addrs[i_frame].size) | (flags & 0x0f);
+#else
+	    /* move MMIO before frame buffer and past I/O for now. Need to walk PCI resources to find safe place */
+	    if (dp->addrs[i_io].address+dp->addrs[i_io].size+dp->addrs[i_regs].size < dp->addrs[i_frame].address)
+	    	new = (dp->addrs[i_io].address&0xff000000) | (dp->addrs[i_regs].address&0x00ffffff) | (flags & 0x0f);
+	    else
+		new = (dp->addrs[i_frame].address+dp->addrs[i_frame].size) | (flags & 0x0f);
+#endif
+
+	    pcibios_write_config_dword(bus, devfn, breg, new);
+
+	    pcibios_read_config_dword(bus, devfn, breg, &pbase);
+	    pcibios_write_config_dword(bus, devfn, breg, 0xffffffff);
+	    pcibios_read_config_dword(bus, devfn, breg, &size);
+	    pcibios_write_config_dword(bus, devfn, breg, pbase);
+
+	    if (new != pbase) 
+	    	printk("atyfb: failed to remap MMIO region! \n");
+
+	    /* update PCI struct */
+	    if (!pdev) 
+	    	printk("atyfb: no pci_dev registered for device!\n");
+	    else
+	    	pdev->base_address[i_regs] = pbase;
+
+	    io = (pbase & PCI_BASE_ADDRESS_SPACE)==PCI_BASE_ADDRESS_SPACE_IO;
+	    flags = (pbase & ~PCI_BASE_ADDRESS_MEM_MASK);
+
+	    if (io)
+		size &= ~1;
+	    size = ~(size) + 1;
+	    
+	    printk("atyfb: chunk %d ofbase 0x%lx breg %d io %d reassigned to pbase 0x%lx size 0x%lx ! \n",
+		i_regs, base, breg, io, pbase, size);
+
+	    /* update OF device tree */
+	    dp->addrs[i_regs].address = dp->addrs[i_frame].address+dp->addrs[i_frame].size;
+    }
+
     if (!aty_init(info, dp->full_name)) {
 	kfree(info);
 	return;
