RE: [linux-fbdev] atyfb and aty128fb faillure 2.3.29 ond x86

Brad Douglas (Brad@NERUO.com)
Fri, 26 Nov 1999 11:44:06 -0500


> From: Gregoire FAVRE [mailto:gregoire.favre@urbanet.ch]
> Sent: Friday, November 26, 1999 4:06 AM
> Subject: [linux-fbdev] atyfb and aty128fb faillure 2.3.29 ond x86
>
> I have one ATI Xpert@play 8 Mb PCI and one ATI Rage Furry 32
> Mb AGP, with two monitors.
...
> Finaly, aty128fb only:
>
> The system boots, but can't see anything in any console other
> than garbage, but X just works
> as normal, I have taken those from dmesg:
>
> ...
> Rage128 BIOS located at segment C00C0000
> aty128fb: Rage128 [rev 0x2] 32M
> fbcon_setup: No support for fontwidth 8
> fbcon_setup: type 0 (aux 0, depth 8) not supported
> Console: switching to colour frame buffer device 80x30
> fb0: ATY Rage128 frame buffer device on PCI
> Detected PS/2 Mouse Port.
> pty: 256 Unix98 ptys configured

I'm not sure about atyfb, but I have a patch for aty128fb that somehow never
made it into the kernel (maybe it's in 2.3.29... I'm not sure because
2.3.27+ won't boot for me). It's against 2.3.26+ and should fix your
garbage problems. I've been slowly working on another patch that addresses
a much wider range of issues -- I'd like to finish it up this weekend.

> I found strange the AGP card being reported as PCI, isn't it?

Naw... AFAIK, AGP is just bastardized PCI on steroids.

--- /home/atong/src/aty128fb.c.26 Mon Oct 18 13:37:43 1999
+++ linux/drivers/video/aty128fb.c Sat Nov 13 16:35:20 1999
@@ -1,22 +1,27 @@
-/* $Id: aty128fb.c,v 1.1 1999/10/12 11:00:43 geert Exp $
+/* $Id: aty128fb.c,v 1.1.1.1.36.1 1999/12/11 09:03:05 brad Exp $
* linux/drivers/video/aty128fb.c -- Frame buffer device for ATI Rage128
*
* Copyright (C) Summer 1999, Anthony Tong <atong@uiuc.edu>
*
- * Brad Douglas <brad@neruo.com>
+ * Brad Douglas <brad@neruo.com>
* - x86 support
* - MTRR
* - Probe ROM for PLL
*
+ * Ani Joshi / Jeff Garzik
+ * - Code cleanup
+ *
* Based off of Geert's atyfb.c and vfb.c.
*
* TODO:
* - panning
* - fix 15/16 bpp on big endian arch's
* - monitor sensing (DDC)
+ * - virtual display
* - other platform support (only ppc/x86 supported)
* - PPLL_REF_DIV & XTALIN calculation
* - determine MCLK from previous hardware setting
+ * - MTRR 32bpp
*/

/*
@@ -40,6 +45,7 @@
#include <linux/init.h>
#include <linux/selection.h>
#include <linux/pci.h>
+#include <linux/ioport.h>
#include <asm/io.h>

#if defined(CONFIG_PPC)
@@ -49,6 +55,10 @@
#include <video/macmodes.h>
#endif

+#ifdef CONFIG_FB_COMPAT_XPMAC
+#include <asm/vc_ioctl.h>
+#endif
+
#include <video/fbcon.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb16.h>
@@ -62,7 +72,6 @@
#include "aty128.h"

#undef DEBUG
-#undef CONFIG_MTRR /* not ready? */

#ifdef DEBUG
#define DBG(x) printk(KERN_INFO "aty128fb: %s\n",(x));
@@ -72,6 +81,7 @@

static char *aty128fb_name = "ATY Rage128";

+/* default mode */
static struct fb_var_screeninfo default_var = {
/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
640, 480, 640, 480, 0, 0, 8, 0,
@@ -80,6 +90,25 @@
0, FB_VMODE_NONINTERLACED
};

+struct aty128_chip_info {
+ const char *name;
+ unsigned short vendor;
+ unsigned short device;
+};
+
+/* FIXME: change the names to their real ones and make the proper
+ #define's for the device id's and add them to pci.h
+ (ie: #define PCI_DEVICE_ID_ATI_RAGE128_ORION 0x5245)
+*/
+static const struct aty128_chip_info aty128_pci_probe_list[] =
+{
+ {"ATY-RAGE128 RE", PCI_VENDOR_ID_ATI, 0x5245},
+ {"ATY-RAGE128 RF", PCI_VENDOR_ID_ATI, 0x5246},
+ {"ATY-RAGE128 RK", PCI_VENDOR_ID_ATI, 0x524b},
+ {"ATY-RAGE128 RL", PCI_VENDOR_ID_ATI, 0x524c},
+ {NULL, 0, 0}
+};
+
#pragma pack(1)
typedef struct {
u8 clock_chip_type;
@@ -128,11 +157,17 @@
static int currcon = 0;
static char fontname[40] __initdata = { 0 };

+#ifndef MODULE
+static const char *mode_option __initdata = NULL;
+#endif
+
#if defined(CONFIG_PPC)
static int default_vmode __initdata = VMODE_NVRAM;
static int default_cmode __initdata = CMODE_NVRAM;
#endif

+static char noaccel __initdata = 0;
+
#if defined(CONFIG_MTRR)
static int mtrr = 1;
#endif
@@ -154,6 +189,7 @@
u32 v_total, v_sync_strt_wid;
u32 pitch;
u32 offset, offset_cntl;
+ u32 xoffset, yoffset;
u32 vxres, vyres;
u32 bpp;
};
@@ -180,11 +216,12 @@
struct fb_info_aty128 {
struct fb_info fb_info;
struct aty128_constants constants;
- unsigned long regbase_phys, regbase;
- unsigned long frame_buffer_phys, frame_buffer;
+ unsigned long regbase_phys; /* mmio memory */
+ unsigned long frame_buffer_phys; /* framebuffer memory */
+ void *regbase, *frame_buffer;
const struct aty128_meminfo *mem;
- u32 vram_size;
- u32 BIOS_SEG;
+ u32 vram_size; /* onboard video ram */
+ void *BIOS_SEG; /* BIOS segment */
#ifdef CONFIG_MTRR
struct { int vram; int vram_valid; } mtrr;
#endif
@@ -203,8 +240,14 @@
#endif
} fbcon_cmap;
int blitter_may_be_busy;
+#ifdef CONFIG_PCI
+ struct pci_dev *pdev;
+#endif
+ struct fb_info_aty128 *next;
};

+static struct fb_info_aty128 *board_list = NULL;
+
#define round_div(n, d) ((n+(d/2))/d)

/*
@@ -257,10 +300,18 @@
static int aty128_setcolreg(u_int regno, u_int red, u_int green, u_int
blue,
u_int transp, struct fb_info *info);
static void do_install_cmap(int con, struct fb_info *info);
+#ifndef CONFIG_FB_OF
static void aty128pci_probe(void);
+static int aty128_pci_register(struct pci_dev *pdev,
+ const struct aty128_chip_info *aci);
+#endif
+static struct fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128
+ *board_list, struct fb_info_aty128
*new_node);
+#ifndef CONFIG_PPC
static int aty128find_ROM(struct fb_info_aty128 *info);
-static void aty128_timings(struct fb_info_aty128 *info);
static void aty128_get_pllinfo(struct fb_info_aty128 *info);
+#endif
+static void aty128_timings(struct fb_info_aty128 *info);
static void aty128_reset_engine(const struct fb_info_aty128 *info);
static void aty128_flush_pixel_cache(const struct fb_info_aty128 *info);
static void wait_for_fifo(u16 entries, const struct fb_info_aty128 *info);
@@ -270,7 +321,15 @@
#ifdef FBCON_HAS_CFB8
static struct display_switch fbcon_aty128_8;
#endif
-
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_aty128_16;
+#endif
+#ifdef FBCON_HAS_CFB24
+static struct display_switch fbcon_aty128_24;
+#endif
+#ifdef FBCON_HAS_CFB32
+static struct display_switch fbcon_aty128_32;
+#endif

static struct fb_ops aty128fb_ops = {
aty128fb_open, aty128fb_release, aty128fb_get_fix,
@@ -285,64 +344,48 @@
* or using the other register aperture? TODO.
*/
static inline u32
-_aty_ld_le32(volatile unsigned int regindex,
- const struct fb_info_aty128 *info)
+_aty_ld_le32(unsigned int regindex, const struct fb_info_aty128 *info)
{
+#if defined(__powerpc__)
unsigned long temp;
u32 val;

-#if defined(__powerpc__)
- eieio();
- temp = info->regbase;
- asm("lwbrx %0,%1,%2" : "=b"(val) : "b" (regindex), "b" (temp));
-#elif defined(__sparc_v9__)
- temp = info->regbase + regindex;
- asm("lduwa [%1] %2, %0" : "=r" (val) : "r" (temp), "i" (ASI_PL));
+ temp = (unsigned long) info->regbase;
+ asm volatile("lwbrx %0,%1,%2" : "=r"(val) : "b" (regindex), "r"
(temp));
+ return val;
+#elif defined(__mc68000__)
+ return le32_to_cpu(*((volatile u32 *)(info->regbase+regindex)));
#else
- temp = info->regbase+regindex;
- val = le32_to_cpu(*((volatile u32 *)(temp)));
+ return readl (info->regbase + regindex);
#endif
- return val;
}

static inline void
-_aty_st_le32(volatile unsigned int regindex, u32 val,
- const struct fb_info_aty128 *info)
+_aty_st_le32(unsigned int regindex, u32 val, const struct fb_info_aty128
*info)
{
+#if defined(__powerpc__)
unsigned long temp;

-#if defined(__powerpc__)
- eieio();
- temp = info->regbase;
- asm("stwbrx %0,%1,%2" : : "b" (val), "b" (regindex), "b" (temp) :
+ temp = (unsigned long) info->regbase;
+ asm volatile("stwbrx %0,%1,%2" : : "r" (val), "b" (regindex), "r"
(temp) :
"memory");
-#elif defined(__sparc_v9__)
- temp = info->regbase + regindex;
- asm("stwa %0, [%1] %2" : : "r" (val), "r" (temp), "i" (ASI_PL) :
"memory");
+#elif defined(__mc68000__)
+ *((volatile u32 *)(info->regbase+regindex)) = cpu_to_le32(val);
#else
- temp = info->regbase+regindex;
- *((volatile u32 *)(temp)) = cpu_to_le32(val);
+ writel (val, info->regbase + regindex);
#endif
}

static inline u8
-_aty_ld_8(volatile unsigned int regindex,
- const struct fb_info_aty128 *info)
+_aty_ld_8(unsigned int regindex, const struct fb_info_aty128 *info)
{
-#if defined(__powerpc__)
- eieio();
-#endif
- return *(volatile u8 *)(info->regbase+regindex);
+ return readb (info->regbase + regindex);
}

static inline void
-_aty_st_8(volatile unsigned int regindex, u8 val,
- const struct fb_info_aty128 *info)
+_aty_st_8(unsigned int regindex, u8 val, const struct fb_info_aty128 *info)
{
-#if defined(__powerpc__)
- eieio();
-#endif
- *(volatile u8 *)(info->regbase+regindex) = val;
+ writeb (val, info->regbase + regindex);
}

#define aty_ld_le32(regindex) _aty_ld_le32(regindex, info)
@@ -507,23 +550,24 @@
aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4);

#ifdef DEBUG
- printk("aty128fb: engine reset\n");
+ printk(KERN_DEBUG "aty128fb: engine reset\n");
#endif
}


-static void
+static void __init
aty128_init_engine(const struct aty128fb_par *par,
const struct fb_info_aty128 *info)
{
- u32 temp;
- aty_st_le32(SCALE_3D_CNTL, 0x00000000);
+ u32 pitch_value;

aty128_reset_engine(info);

- temp = par->crtc.pitch; /* fix this up */
+ aty_st_le32(SCALE_3D_CNTL, 0x00000000);
+
+ pitch_value = par->crtc.pitch; /* fix this up */
if (par->crtc.bpp == 24) {
- temp = temp * 3;
+ pitch_value = pitch_value * 3;
}

/* setup engine offset registers */
@@ -531,7 +575,7 @@
aty_st_le32(DEFAULT_OFFSET, 0x00000000);

/* setup engine pitch registers */
- aty_st_le32(DEFAULT_PITCH, temp);
+ aty_st_le32(DEFAULT_PITCH, pitch_value);

/* set the default scissor register to max dimensions */
wait_for_fifo(1, info);
@@ -591,11 +635,7 @@
else if (bpp <= 15)
return 3;
else if (bpp <= 16)
-#if 0 /* force 15bpp */
return 4;
-#else
- return 3;
-#endif
else if (bpp <= 24)
return 5;
else if (bpp <= 32)
@@ -605,6 +645,7 @@
}


+/* Program the CRTC registers */
static void
aty128_set_crtc(const struct aty128_crtc *crtc,
const struct fb_info_aty128 *info)
@@ -720,6 +761,8 @@

crtc->vxres = vxres;
crtc->vyres = vyres;
+ crtc->xoffset = xoffset;
+ crtc->yoffset = yoffset;
crtc->bpp = bpp;

return 0;
@@ -730,16 +773,19 @@
aty128_crtc_to_var(const struct aty128_crtc *crtc,
struct fb_var_screeninfo *var)
{
-#ifdef notyet /* xoffset and yoffset are not correctly calculated */
+#ifdef notyet /* This does not work yet :( */
u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;
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;

+ /* init this to keep compiler from complaining */
+ bpp = 0;
+
h_total = crtc->h_total & 0x1ff;
h_disp = (crtc->h_total>>16) & 0xff;
h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |
- ((crtc->h_sync_strt_wid>>4) & 0x100);
+ ((crtc->h_sync_strt_wid>>4) & 0x100);
h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7;
h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f;
h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1;
@@ -760,83 +806,85 @@
lower = v_sync_strt-v_disp;
vslen = v_sync_wid;
sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |
- (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
- (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);
+ (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |
+ (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);

switch (pix_width) {
#if 0
- case CRTC_PIX_WIDTH_4BPP:
- bpp = 4;
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 0;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
-#endif
- case CRTC_PIX_WIDTH_8BPP:
- bpp = 8;
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 0;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case CRTC_PIX_WIDTH_15BPP:
- bpp = 16;
- var->red.offset = 10;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 5;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case CRTC_PIX_WIDTH_16BPP:
- bpp = 16;
- var->red.offset = 11;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 6;
- var->blue.offset = 0;
- var->blue.length = 5;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case CRTC_PIX_WIDTH_24BPP:
- bpp = 24;
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 0;
- var->transp.length = 0;
- break;
- case CRTC_PIX_WIDTH_32BPP:
- bpp = 32;
- var->red.offset = 16;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 0;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 8;
- break;
- default:
- printk(KERN_ERR "Invalid pixel width\n");
+ case CRTC_PIX_WIDTH_4BPP:
+ bpp = 4;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 8;
+ break;
+#endif
+ case CRTC_PIX_WIDTH_8BPP:
+ bpp = 8;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 8;
+ break;
+ case CRTC_PIX_WIDTH_15BPP:
+ bpp = 16;
+ var->red.offset = 10;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+#if 0
+ case CRTC_PIX_WIDTH_16BPP:
+ bpp = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+#endif
+ case CRTC_PIX_WIDTH_24BPP:
+ bpp = 24;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case CRTC_PIX_WIDTH_32BPP:
+ bpp = 32;
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ default:
+ printk(KERN_ERR "Invalid pixel width\n");
+ return -EINVAL;
}

-//Godda do math for xoffset and yoffset: does not exist in crtc
var->xres = xres;
var->yres = yres;
var->xres_virtual = crtc->vxres;
@@ -852,11 +900,11 @@
var->vsync_len = vslen;
var->sync = sync;
var->vmode = FB_VMODE_NONINTERLACED;
-
-#endif /* notyet */
+#endif
return 0;
}

+
static int
aty128_bpp_to_var(int bpp, struct fb_var_screeninfo *var)
{
@@ -904,6 +952,9 @@
var->transp.offset = 24;
var->transp.length = 8;
break;
+ default:
+ printk(KERN_ERR "Invalid pixel width\n");
+ return -1;
}

return 0;
@@ -920,7 +971,7 @@
/* select PPLL_DIV_3 */
aty_st_le32(CLOCK_CNTL_INDEX, aty_ld_le32(CLOCK_CNTL_INDEX) | (3 <<
8));

- /* reset ppll */
+ /* reset PLL */
aty_st_pll(PPLL_CNTL,
aty_ld_pll(PPLL_CNTL) | PPLL_RESET | PPLL_ATOMIC_UPDATE_EN);

@@ -979,7 +1030,7 @@

pll->vclk = vclk;
#ifdef DEBUG
- printk("post %x feedback %x vlck %x output %x\n",
+ printk(KERN_DEBUG "post %x feedback %x vlck %x output %x\n",
pll->post_divider, pll->feedback_divider, vclk, output_freq);
#endif

@@ -1033,7 +1084,7 @@
x;

#ifdef DEBUG
- printk("x %x\n", x);
+ printk(KERN_DEBUG "x %x\n", x);
#endif
b = 0;
while (x) {
@@ -1048,13 +1099,13 @@
x = round_div(n, d);
roff = x * (fifo_depth - 4);
if ((ron + m->Rloop) >= roff) {
- printk("Mode out of range\n");
+ printk(KERN_ERR "Mode out of range\n");
return -EINVAL;
}

#ifdef DEBUG
- printk("p: %x rloop: %x x: %x ron: %x roff: %x\n", p, m->Rloop, x,
- ron, roff);
+ printk(KERN_DEBUG "p: %x rloop: %x x: %x ron: %x roff: %x\n", p,
+ m->Rloop, x, ron, roff);
#endif
dsp->dda_config = p << 16 | m->Rloop << 20 | x;
dsp->dda_on_off = ron << 16 | roff;
@@ -1158,8 +1209,6 @@
{
int err;

- //memset(var, 0, sizeof(struct fb_var_screeninfo));
-
/* XXX aty128_*_to_var() aren't fully implemented! */
if ((err = aty128_crtc_to_var(&par->crtc, var)))
return err;
@@ -1168,7 +1217,7 @@
return err;

if ((err = aty128_bpp_to_var(var->bits_per_pixel, var)))
- return err;
+ return err;

var->height = -1;
var->width = -1;
@@ -1244,9 +1293,9 @@
accel = var->accel_flags & FB_ACCELF_TEXT;
aty128_set_disp(display, info, var->bits_per_pixel, accel);

-#if 0 /* acceleration is not ready */
- if (accel)
- display->scrollmode = 0;
+#if 0
+ if (accel) /* bmove is not ready */
+ display->scrollmode = SCROLL_YNOMOVE;
else
#endif
display->scrollmode = SCROLL_YREDRAW;
@@ -1264,6 +1313,26 @@
do_install_cmap(con, &info->fb_info);
}

+#ifdef CONFIG_FB_COMPAT_XPMAC
+ if (console_fb_info == &info->fb_info) {
+ int vmode, cmode;
+
+ display_info.width = var->xres;
+ display_info.height = var->yres;
+ display_info.depth = var->bits_per_pixel;
+ display_info.pitch = (var->xres_virtual)*(var->bits_per_pixel)/8;
+ if (mac_var_to_vmode(var, &vmode, &cmode))
+ display_info.mode = 0;
+ else
+ display_info.mode = vmode;
+ strcpy(info->fb_info.modename, aty128fb_name);
+ display_info.fb_address = info->frame_buffer_phys;
+ display_info.cmap_adr_address = 0;
+ display_info.cmap_data_address = 0;
+ display_info.disp_reg_address = info->regbase_phys;
+ }
+#endif
+
return 0;
}

@@ -1280,19 +1349,19 @@
#endif
#ifdef FBCON_HAS_CFB16
case 16:
- disp->dispsw = &fbcon_cfb16;
+ disp->dispsw = accel ? &fbcon_aty128_16 : &fbcon_cfb16;
disp->dispsw_data = info->fbcon_cmap.cfb16;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
- disp->dispsw = &fbcon_cfb24;
+ disp->dispsw = accel ? &fbcon_aty128_24 : &fbcon_cfb24;
disp->dispsw_data = info->fbcon_cmap.cfb24;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
- disp->dispsw = &fbcon_cfb32;
+ disp->dispsw = accel ? &fbcon_aty128_32 : &fbcon_cfb32;
disp->dispsw_data = info->fbcon_cmap.cfb32;
break;
#endif
@@ -1325,6 +1394,7 @@
fix->ypanstep = 1;

fix->accel = FB_ACCEL_ATI_RAGE128;
+
return;
}

@@ -1344,6 +1414,7 @@
aty128_decode_var(&fb_display[con].var, &par, info);

aty128_encode_fix(fix, &par, info);
+
return 0;
}

@@ -1405,10 +1476,11 @@
return err;
}
if (!info->display_fg || con == info->display_fg->vc_num)
-/* current console? */
+ /* current console? */
return fb_set_cmap(cmap, kspc, aty128_setcolreg, info);
else
fb_copy_cmap(cmap, &disp->cmap, kspc ? 0 : 1);
+
return 0;
}

@@ -1445,9 +1517,16 @@
break;
memcpy(fontname, this_opt + 5, i);
fontname[i] = 0;
+ } else if (!strncmp(this_opt, "noaccel", 7)) {
+ noaccel = 1;
}
+#if defined(CONFIG_MTRR)
+ else if (!strncmp(this_opt, "nomtrr", 5)) {
+ mtrr = 0;
+ }
+#endif
#if defined(CONFIG_PPC)
- if (!strncmp(this_opt, "vmode:", 6)) {
+ else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
if (vmode > 0 && vmode <= VMODE_MAX)
default_vmode = vmode;
@@ -1469,15 +1548,8 @@
}
}
#endif
-#ifdef CONFIG_MTRR
- if(mtrr) {
- ACCESS_FBINFO(mtrr.vram) =
- mtrr_add(video_base_phys, ACCESS_FBINFO(video.len),
- MTRR_TYPE_WRCOMB, 1);
- ACCESS_FBINFO(mtrr.valid_vram) = 1;
- printk(KERN_INFO "aty128fb: MTRR set to ON\n");
- }
-#endif
+ else
+ mode_option = this_opt;
}
return 0;
}
@@ -1487,7 +1559,7 @@
* Initialisation
*/

-static int
+static int __init
aty128_init(struct fb_info_aty128 *info, const char *name)
{
struct fb_var_screeninfo var;
@@ -1496,7 +1568,7 @@
u8 chip_rev;

if (!register_test(info)) {
- printk("Can't write to video registers\n");
+ printk(KERN_ERR "Can't write to video registers\n");
return 0;
}

@@ -1506,17 +1578,17 @@
chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;

/* TODO be more verbose */
- printk("aty128fb: Rage128 [rev 0x%x] ", chip_rev);
+ printk(KERN_INFO "aty128fb: Rage128 [rev 0x%x] ", chip_rev);

if (info->vram_size % (1024 * 1024) == 0)
- printk("%dM ", info->vram_size / (1024*1024));
+ printk(KERN_INFO "%dM \n", info->vram_size / (1024*1024));
else
- printk("%dk ", info->vram_size / 1024);
+ printk(KERN_INFO "%dk \n", info->vram_size / 1024);

var = default_var;

#ifdef CONFIG_PMAC
-
+ /* TODO: add code for mode_option here */
if (default_vmode == VMODE_NVRAM) {
#ifdef CONFIG_NVRAM
default_vmode = nvram_read_byte(NV_VMODE);
@@ -1539,8 +1611,13 @@

#endif /* CONFIG_PMAC */

+ if (noaccel)
+ var.accel_flags &= ~FB_ACCELF_TEXT;
+ else
+ var.accel_flags |= ~FB_ACCELF_TEXT;
+
if (aty128_decode_var(&var, &info->default_par, info)) {
- printk("Cannot set default mode.\n");
+ printk(KERN_ERR "Cannot set default mode.\n");
return 0;
}

@@ -1573,117 +1650,165 @@
aty128fb_set_var(&var, -1, &info->fb_info);
aty128_init_engine(&info->default_par, info);

- printk("\n");
+ board_list = aty128_board_list_add(board_list, info);
+
if (register_framebuffer(&info->fb_info) < 0)
return 0;

- printk("fb%d: %s frame buffer device on %s\n",
+ printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
GET_FB_IDX(info->fb_info.node), aty128fb_name, name);

return 1; /* success! */
}


+/* add a new card to the list ++ajoshi */
+static struct
+fb_info_aty128 *aty128_board_list_add(struct fb_info_aty128 *board_list,
+ struct fb_info_aty128 *new_node)
+{
+ struct fb_info_aty128 *i_p = board_list;
+ new_node->next = NULL;
+ if(board_list == NULL)
+ return new_node;
+ while(i_p->next != NULL)
+ i_p = i_p->next;
+ i_p->next = new_node;
+
+ return board_list;
+}
+
+
void __init
aty128fb_init(void)
{
#if defined(CONFIG_FB_OF)
-/* let offb handle init */
+ /* let offb handle init */
#elif defined (CONFIG_PCI)
aty128pci_probe();
#endif
}


-void
+#ifndef CONFIG_FB_OF
+void __init
aty128pci_probe(void)
{
struct pci_dev *pdev;
- struct fb_info_aty128 *info;
+ const struct aty128_chip_info *aci = &aty128_pci_probe_list[0];
+
+ while(aci->name != NULL) {
+ pdev = pci_find_device(aci->vendor, aci->device, NULL);
+ while(pdev != NULL) {
+ if(aty128_pci_register(pdev, aci) > 0)
+ return;
+ pdev = pci_find_device(aci->vendor, aci->device, pdev);
+ }
+ aci++;
+ }
+
+ return;
+}
+
+
+/* register a card ++ajoshi */
+static int aty128_pci_register(struct pci_dev *pdev,
+ const struct aty128_chip_info *aci)
+{
+ struct fb_info_aty128 *info = NULL;
unsigned long fb_addr, reg_addr;
+ struct resource *rp;
u16 tmp;

- for (pdev = pci_devices; pdev; pdev = pdev->next) {
- if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
- (pdev->vendor == PCI_VENDOR_ID_ATI)) {
- struct resource *rp;
-
- /* FIXME add other known R128 device ID's */
- switch (pdev->device) {
- case 0x5245:
- case 0x5246:
- case 0x524B:
- case 0x524C:
- break;
- default:
- continue;
- }

- rp = &pdev->resource[0];
- fb_addr = rp->start;
- if (!fb_addr)
- continue;
- fb_addr &= PCI_BASE_ADDRESS_MEM_MASK;
-
- rp = &pdev->resource[2];
- reg_addr = rp->start;
- if (!reg_addr)
- continue;
- reg_addr &= PCI_BASE_ADDRESS_MEM_MASK;
-
- info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC);
- if (!info) {
- printk("aty128fb: can't alloc fb_info_aty128\n");
- return;
- }
- memset(info, 0, sizeof(struct fb_info_aty128));
+ rp = &pdev->resource[0];
+ fb_addr = rp->start;
+ fb_addr &= PCI_BASE_ADDRESS_MEM_MASK;

- info->regbase_phys = reg_addr;
- info->regbase = (unsigned long) ioremap(reg_addr, 0x1FFF);
+ request_mem_region (rp->start, rp->end - rp->start + 1, "aty128fb");

- if (!info->regbase) {
- kfree(info);
- return;
- }
+ rp = &pdev->resource[2];
+ reg_addr = rp->start;
+ reg_addr &= PCI_BASE_ADDRESS_MEM_MASK;

- info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+ if (!reg_addr) {
+ release_mem_region (pdev->resource[0].start,
+ pdev->resource[0].end -
+ pdev->resource[0].start + 1);
+ return -1;
+ }

- info->frame_buffer = fb_addr;
- info->frame_buffer = (unsigned long)
- ioremap(fb_addr, info->vram_size);
-
- if (!info->frame_buffer) {
- kfree(info);
- return;
- }
+ request_mem_region (rp->start, rp->end - rp->start + 1, "aty128fb");

- pci_read_config_word(pdev, PCI_COMMAND, &tmp);
- if (!(tmp & PCI_COMMAND_MEMORY)) {
- tmp |= PCI_COMMAND_MEMORY;
- pci_write_config_word(pdev, PCI_COMMAND, tmp);
- }
+ info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC);
+ if(!info) {
+ printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
+ goto unmap_out;
+ }
+ memset(info, 0, sizeof(struct fb_info_aty128));
+
+ info->pdev = pdev;
+
+ info->regbase_phys = reg_addr;
+ info->regbase = ioremap(reg_addr, 0x1FFF);
+
+ if (!info->regbase)
+ goto err_out;
+
+ info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
+
+ info->frame_buffer_phys = fb_addr;
+ info->frame_buffer = ioremap(fb_addr, info->vram_size);
+
+ if (!info->frame_buffer)
+ goto err_out;
+
+ pci_read_config_word(pdev, PCI_COMMAND, &tmp);
+ if (!(tmp & PCI_COMMAND_MEMORY)) {
+ tmp |= PCI_COMMAND_MEMORY;
+ pci_write_config_word(pdev, PCI_COMMAND, tmp);
+ }

#if defined(CONFIG_PPC)
- aty128_timings(info);
+ aty128_timings(info);
#else
- if (!aty128find_ROM(info)) {
- printk("Rage128 BIOS not located. Guessing...\n");
- aty128_timings(info);
- }
- else
- aty128_get_pllinfo(info);
+ if (!aty128find_ROM(info)) {
+ printk(KERN_INFO "Rage128 BIOS not located. Guessing...\n");
+ aty128_timings(info);
+ }
+ else
+ aty128_get_pllinfo(info);
#endif
+#if defined(CONFIG_MTRR)
+ if (mtrr) {
+ info->mtrr.vram = mtrr_add(info->frame_buffer_phys,
info->vram_size,
+ MTRR_TYPE_WRCOMB, 1);
+ info->mtrr.vram_valid = 1;
+ /* let there be speed */
+ printk(KERN_INFO "aty128fb: MTRR set to ON\n");
+ }
+#endif /* CONFIG_MTRR */
+ if (!aty128_init(info, "PCI"))
+ goto err_out;

- if (!aty128_init(info, "PCI")) {
- kfree(info);
- return;
- }
- }
- }
+ return 0;
+
+err_out:
+ kfree (info);
+unmap_out:
+ release_mem_region (pdev->resource[0].start,
+ pdev->resource[0].end -
+ pdev->resource[0].start + 1);
+ release_mem_region (pdev->resource[2].start,
+ pdev->resource[2].end -
+ pdev->resource[2].start + 1);
+ return -1;
}
+#endif /* ! CONFIG_FB_OF */


-static int
+#ifndef CONFIG_PPC
+static int __init
aty128find_ROM(struct fb_info_aty128 *info)
{
u32 segstart;
@@ -1695,7 +1820,6 @@
char aty_rom_sig[] = "761295520";
char R128_sig[] = "R128";
int flag = 0;
-DBG("E aty128find_ROM");

for (segstart = 0x000c0000; segstart < 0x000f0000; segstart +=
0x00001000) {
stage = 1;
@@ -1740,13 +1864,13 @@
continue;
}

- printk("Rage128 BIOS located at segment %4.4X\n", (u32)rom_base);
- info->BIOS_SEG = (u32)rom_base;
+ printk(KERN_INFO "Rage128 BIOS located at segment %4.4X\n",
+ (u32)rom_base);
+ info->BIOS_SEG = rom_base;
flag = 1;

break;
}
-DBG("L aty128find_ROM");
return (flag);
}

@@ -1754,24 +1878,23 @@
static void
aty128_get_pllinfo(struct fb_info_aty128 *info)
{
- u32 bios_header;
- u32 *header_ptr;
+ void *bios_header;
+ void *header_ptr;
u16 bios_header_offset, pll_info_offset;
PLL_BLOCK pll;
-DBG("E aty128_get_pllinfo");

bios_header = info->BIOS_SEG + 0x48L;
- header_ptr = (u32 *)bios_header;
+ header_ptr = bios_header;

- bios_header_offset = (u16)*header_ptr;
- bios_header = info->BIOS_SEG + (u32)bios_header_offset;
+ bios_header_offset = readw (header_ptr);
+ bios_header = info->BIOS_SEG + bios_header_offset;
bios_header += 0x30;

- header_ptr = (u32 *)bios_header;
- pll_info_offset = (u16)*header_ptr;
- header_ptr = (u32 *)(info->BIOS_SEG + (u32)pll_info_offset);
+ header_ptr = bios_header;
+ pll_info_offset = readw (header_ptr);
+ header_ptr = info->BIOS_SEG + pll_info_offset;

- memcpy(&pll, header_ptr, 50);
+ memcpy_fromio(&pll, header_ptr, 50);

info->constants.ppll_max = pll.PCLK_max_freq;
info->constants.ppll_min = pll.PCLK_min_freq;
@@ -1796,13 +1919,13 @@
info->mem = &sdr_sgram;
}

-DBG("L aty128get_pllinfo");
return;
}
+#endif /* ! CONFIG_PPC */


#ifdef CONFIG_FB_OF
-void
+void __init
aty128fb_of_init(struct device_node *dp)
{
unsigned long addr, reg_addr, fb_addr;
@@ -1816,25 +1939,25 @@
reg_addr = dp->addrs[2].address;
break;
default:
- printk("aty128fb: TODO unexpected addresses\n");
+ printk(KERN_ERR "aty128fb: TODO unexpected addresses\n");
return;
}

addr = (unsigned long) ioremap(reg_addr, 0x1FFF);
if (!addr) {
- printk("aty128fb: can't map memory registers\n");
+ printk(KERN_ERR "aty128fb: can't map memory registers\n");
return;
}

info = kmalloc(sizeof(struct fb_info_aty128), GFP_ATOMIC);
if (!info) {
- printk("aty128fb: can't alloc fb_info_aty128\n");
+ printk(KERN_ERR "aty128fb: can't alloc fb_info_aty128\n");
return;
}
- memset(info, 0, sizeof(struct fb_info_aty128));
+ memset((void *) info, 0, sizeof(struct fb_info_aty128));

info->regbase_phys = reg_addr;
- info->regbase = addr;
+ info->regbase = (void *) addr;

/* enabled memory-space accesses using config-space command register */
if (pci_device_loc(dp, &bus, &devfn) == 0) {
@@ -1847,7 +1970,7 @@

info->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
info->frame_buffer_phys = fb_addr;
- info->frame_buffer = (unsigned long) ioremap(fb_addr, info->vram_size);
+ info->frame_buffer = (void *) ioremap(fb_addr, info->vram_size);

/*
* TODO find OF values/hints.
@@ -1857,7 +1980,8 @@
*/

if (!info->frame_buffer) {
- printk("aty128fb: can't map frame buffer\n");
+ printk(KERN_ERR "aty128fb: can't map frame buffer\n");
+ kfree(info);
return;
}

@@ -1867,8 +1991,13 @@
kfree(info);
return;
}
-}
+
+#ifdef CONFIG_FB_COMPAT_XPMAC
+ if (!console_fb_info)
+ console_fb_info = &info->fb_info;
#endif
+}
+#endif /* CONFIG_FB_OF */


/* fill in known card constants if pll_block is not available */
@@ -1949,7 +2078,6 @@
/*
* Blank the display.
*/
-
static void
aty128fbcon_blank(int blank, struct fb_info *fb)
{
@@ -2010,15 +2138,18 @@
info->palette[regno].green = green;
info->palette[regno].blue = blue;

- aty_st_8(PALETTE_INDEX, regno);
- col = red << 16 | green << 8 | blue;
- aty_st_le32(PALETTE_DATA, col);
+ if (info->current_par.crtc.bpp <= 8) {
+ aty_st_8(PALETTE_INDEX, regno);
+ col = red << 16 | green << 8 | blue;
+ aty_st_le32(PALETTE_DATA, col);
+ }

if (regno < 16)
switch (info->current_par.crtc.bpp) {
#ifdef FBCON_HAS_CFB16
case 16:
- info->fbcon_cmap.cfb16[regno] = (regno << 10) | (regno << 5) |
+ /* broken, need to fill in rgb values */
+ info->fbcon_cmap.cfb16[regno] = (regno << 11) | (regno << 5) |
regno;
break;
#endif
@@ -2134,18 +2265,65 @@
FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
};
#endif
+#ifdef FBCON_HAS_CFB16
+static struct display_switch fbcon_aty128_16 = {
+ fbcon_cfb16_setup, fbcon_aty128_bmove, fbcon_cfb16_clear,
+ fbcon_cfb16_putc, fbcon_cfb16_putcs, fbcon_cfb16_revc, NULL, NULL,
+ fbcon_cfb16_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB24
+static struct display_switch fbcon_aty128_24 = {
+ fbcon_cfb24_setup, fbcon_aty128_bmove, fbcon_cfb24_clear,
+ fbcon_cfb24_putc, fbcon_cfb24_putcs, fbcon_cfb24_revc, NULL, NULL,
+ fbcon_cfb24_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB32
+static struct display_switch fbcon_aty128_32 = {
+ fbcon_cfb32_setup, fbcon_aty128_bmove, fbcon_cfb32_clear,
+ fbcon_cfb32_putc, fbcon_cfb32_putcs, fbcon_cfb32_revc, NULL, NULL,
+ fbcon_cfb32_clear_margins,
+ FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif

#if defined(MODULE) && defined(DEBUG)
-int
+int __init
init_module(void)
{
aty128pci_probe();
return 0;
}

-void
+void __exit
cleanup_module(void)
{
-/* XXX unregister! */
+ struct fb_info_aty128 *tmp, *board = board_list;
+
+ while (board_list) {
+ tmp = board_list;
+ board_list = board_list->next;
+
+ unregister_framebuffer (&tmp->fb_info);
+#if defined(CONFIG_MTRR)
+ if(info->mtrr.vram_valid)
+ mtrr_del(info->mtrr.vram, info->frame_buffer_phys,
+ info->vram_size);
+#endif /* CONFIG_MTRR */
+ if (tmp->BIOS_SEG)
+ iounmap (tmp->BIOS_SEG);
+ iounmap (tmp->regbase);
+ iounmap (tmp->frame_buffer);
+ release_mem_region (tmp->pdev->resource[0].start,
+ tmp->pdev->resource[0].end -
+ tmp->pdev->resource[0].start + 1);
+ release_mem_region (tmp->pdev->resource[2].start,
+ tmp->pdev->resource[2].end -
+ tmp->pdev->resource[2].start + 1);
+ kfree (tmp);
+ }
}
#endif /* MODULE */

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/