Re: ATI FB driver

Dan Hopper (eusdbho@rtp.ericsson.se)
Fri, 21 May 1999 10:42:47 -0400


--fUYQa+Pmc3FrFX/N
Content-Type: text/plain; charset=us-ascii

Russell Coker <russell@coker.com.au> remarked:
> The ATI FBcon driver is an option that is enabled for i386 builds.
> However the comments in the source say that this is only for
> PowerMac. Also there is no documentation on this at all.
>
> What is the status of this? Is it something that will work on a
> PC with an ATI card? If so how?

Hi,

I'm assuming this is with reference to the ATI Mach64 framebuffer
driver (atyfb), where the device in not detected at boot (the error,
"atyfb: Unknown mach64 0xffff"). If this is something different, I
apologize. Incidentally, I've got a P2-233, and a mach64GX (2MB ATI
Graphics Pro Turbo, circa 1995).

About a month back, I looked into this a bit, and came up with the
beginnings of a solution. I emailed
Geert.Uytterhoeven@cs.kuleuven.ac.be, but however it would seem he's
a busy guy right now (and I got an auto-reply that stated as much).

I've attached my message to him here, which talks about patching
2.2.7-pre3. There's some superfluous debug statements in that
patch, and it's not 100% effective, but at least it allowed the
device to be detected.

The root of the problem was that the 8MB linear memory aperture of
the Mach64 is disabled, and as a result none of the registers can be
seen. Read my message for the nitty-gritty, but basically I did a
_very_ kludgy I/O port write to the Config_Ctrl register to enable
the aperture:

outb(inb(0x6aec) | APERTURE_8M_ENABLE, 0x6aec);

I placed this at the top of aty_init(). Dunno where the ideal
location is.

Some documentation at
http://www.cubic.org/source/archive/hardware/video/cards/ati.txt
indicates that Config_Ctrl register is not memory-mapped with the
rest of the registers, and the driver is currently not setup to do
anything but memory-mapped accesses to the register. Thus, the I/O
access instead.

Now, it's detected correctly at boot up:
atyfb: mach64GX (ATI888GX00) [0x00d7 rev 0x01] 2M VRAM, 135 MHz PLL, 50 Mhz MCLK
Console: switching to colour frame buffer device 80x30
fb0: ATY Mach64 frame buffer device on PCI

And then it goes into graphics mode and things look pretty OK.

Three problems here:

1) this needs cleanup. the reference to I/O 0x6aec (Config_Cntl's
I/O port) should be #define'd somewhere, and it's not.

2) The penguin logo that pops up has some sort of palette problems.
It's recognizable, but not right.

3) The console works fine until you go into XFree86. After that,
it's never again visible. I'm guessing here that there's some other
snippet of code, either in the kernel or in XFree86, that's not
leaving that APERTURE_8M_ENABLE bit set after flipping back to the
console. I haven't verified this, though.

So, hopefully there are other interested Mach64 on x86 folks out
there who have more kernel experience than I do, and will be able to
complete the fix.

Thanks,
Dan Hopper

--fUYQa+Pmc3FrFX/N
Content-Type: message/rfc822

Date: Sun, 25 Apr 1999 17:31:55 -0400
From: Dan Hopper <dbhopper-N0SPAM@N0SPAM.ipass.net>
To: Geert.Uytterhoeven@cs.kuleuven.ac.be
Subject: Linux ATI Mach64 frame buffer detection problem
Message-ID: <19990425173155.A563@dhopper.dummynet>
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary=envbJBWh7q8WU6mo
X-Mailer: Mutt 0.95.3i

--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii

Hi Geert,

Sorry if you're not the right person to direct this to, but atyfb.c
was a little unclear on who was the current maintainer of the
driver. Your name appeared on framebuffer.txt, and I've seen some
posts from you on the subject in the past. Let me know if I should
redirect this elsewhere (linux-kernel?).

This is about the old Mach64 detection problem with the framebuffer
device. I've seen some posts as far back as December with the same
error messages as I get. The error in question is:

atyfb: Unknown mach64 0xffff

after which no framebuffer driver is activated. I had the same
problem several months back, but being a hardware rather than
software sort, I figured someone better qualified would eventually
figure it out. Since it's still a problem, I figured I'd take a
look at it.

I placed a bunch of kludgy debug statements throughout aty_init()
and atyfb_init(). The apparent problem is that the chip_id being
read from the device is bogus. The output from my debug statements
was thus:

DBH atyfb_init: loc1, addr = 0xe1000000
DBH atyfb_init: loc2, info->ati_regbase_phys = 0xe17ffc00
DBH atyfb_init: loc2, info->ati_regbase = 0xc4000c00
DBH atyfb_init: loc4, info->frame_buffer_phys = 0xe1000000
DBH atyfb_init: loc4, info->frame_buffer = 0xc4002000
DBH aty_init: info->ati_regbase_phys = 0xe17ffc00
DBH aty_init: info->ati_regbase = 0xc4000c00
DBH aty_init: compare #1 to SCRATCH_REG0 failed.
DBH aty_init: compare #2 to SCRATCH_REG0 failed.
DBH aty_init: info->aty_cmap_regs = 0xc4000cc0
DBH aty_init: chip_id = 0xffffffff
DBH aty_init: info->chip_type (Gx) = 0xffff
DBH aty_init: info->chip_rev (Rev) = 0xff
atyfb: Unknown mach64 0xffff

There's more info up there than is necessary. The important thing
is that the statement
chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
is returning all ones, which is bad. You'll also notice I stuffed
in some write/read pairs to the Mach64 scratch register, similar to
what the XFree86 driver does. Since it fails, there's likely no
valid memory or registers mapped in at all.

To my untrained eye, the PCI config registers look kinda OK. But
the Mach64 registers don't. Take a look at
http://www.cubic.org/source/archive/hardware/video/cards/ati.txt
down around Config_Ctrl register:

The Mach64 engine is different from the Mach8/Mach32. The Mach64
has a number of 32bit registers. Most are I/O mapped at x2ECh
(A2-A9 = 10111011), and all except the Config_Ctrl Register
(6AECh) is memory mapped as a 1KB block, either at 0BFC00h or the
last 1KB of the Linear Aperture.

6AECh D(R/W): Config_Ctrl
bit 0-1 Cfg_Mem_Ap_Size. Linear Memory Aperture Size.
0: Disabled, 1: 4MB Aperture, 2: 8MB Aperture
2 Cfg_Mem_VGA_Ap_En. VGA Aperture enabled if set
4-13 Cfg_Mem_Ap_Loc. Linear Memory Aperture Location in units of 4MB.
Bit 4 (lowest bit) is ignored for 8MB Apertures.
16-18 Cfg_Card_ID.
19 Cfg_VGA_Dis. VGA enabled if clear, disabled if set

The bit about the Config_Ctrl _not_ being memory mapped with
everything else keyed me off, since there doesn't appear to be
anything but memory-mapped operations in this driver (and none of
them reference Config_Ctrl anyway). If I do a read of that register
in the kernel (or in a user-land program at the console, for that
matter), I get:

DBH aty_init: I/O port 6aec = 0x00003840

which is wrong. If I read that set of I/O ports while in XFree86, I
get 0x00003842, which is as one would expect. The latter indicates
that an 8MB Linear Memory Aperture is enabled. The former (in the
kernel) indicates that the aperture is disabled (the aperture
location of 0xe1000000 seems OK, though).

So, my "solution" is to do an I/O port write in order to set that
bit in the Config_Ctrl (a.k.a. Config_Cntl) register (port 0x6aec):

outb(inb(0x6aec) | APERTURE_8M_ENABLE, 0x6aec);

This line is placed at the top of aty_init(), although that may or
may not not be the ideal location.

If I do that, my debug messages are:

DBH atyfb_init: loc1, addr = 0xe1000000
DBH atyfb_init: loc2, info->ati_regbase_phys = 0xe17ffc00
DBH atyfb_init: loc2, info->ati_regbase = 0xc4000c00
DBH atyfb_init: loc4, info->frame_buffer_phys = 0xe1000000
DBH atyfb_init: loc4, info->frame_buffer = 0xc4002000
DBH aty_init: I/O port 6eec = 0x010000d7
DBH aty_init: I/O port 52ec = 0x000001f2
DBH aty_init: I/O port 6aec = 0x00003840
DBH aty_init: info->ati_regbase_phys = 0xe17ffc00
DBH aty_init: info->ati_regbase = 0xc4000c00
DBH aty_init: Enabling 8MB Linear Mem Aperture, w/CONFIG_CNTL I/O port write.
DBH aty_init: I/O port 6aec = 0x00003842
DBH aty_init: compare #1 to SCRATCH_REG0 succeeded.
DBH aty_init: compare #2 to SCRATCH_REG0 succeeded.
DBH aty_init: info->aty_cmap_regs = 0xc4000cc0
DBH aty_init: chip_id = 0x010000d7
DBH aty_init: info->chip_type (Gx) = 0x00d7
DBH aty_init: info->chip_rev (Rev) = 0x01
atyfb: mach64GX (ATI888GX00) [0x00d7 rev 0x01] 2M VRAM, 135 MHz PLL, 50 Mhz MCLK
Console: switching to colour frame buffer device 80x30
fb0: ATY Mach64 frame buffer device on PCI

You'll notice that the scratch register stuff now succeeds, that the
chip_id is now valid, and that the rest of the normal atyfb code
seems to proceed to detect the features of the card (I do in fact
have a mach64 GX with 2MB of VRAM). It then flips into graphics
mode and proceeds to boot up.

I've attached my debug patch just so you can make heads or tails of
my kludgy debug messages up there if you're so inclined. You're
likely only really interested in the outb() line I mentioned above,
though.

This likely needs to be cleaned up. In particular, that reference
to 0x6aec (Config_Cntl's I/O port) should be #define'd somewhere.
It's not currently in the header file (since the driver never did
any direct port I/O before this). I do find it interesting that
other framebuffer drivers do in fact include outb instructions, so
perhaps there's a precedent.

I need to mention two problems that still exist. Both may/may not
be related to this particular problem.

1) When it switches into graphics mode, the text looks fine, scrolls
fine, etc. However, the penguin logo, while recognizable, appears
to have some sort of palette problems (the colors look inverted or
otherwise messed up). I've never used a framebuffer driver before
(on Linux), so I'm not sure if this is a FAQ or something.

2) Once logged in, the console seems to behave normally. I.e. text
looks fine, scrolling works fine, etc. I can run XFree86, and it
works fine. However, if I then go back to the console (either by
Ctrl-Alt-Backspace or Ctrl-Alt-1), there's no video. In fact, my
monitor complains that the frequencies are out of range: 163 kHz
horizontal, and 200 Hz vertical. I can go back into X any number of
times, and X works fine. The video looks fine in X, but not in the
console. Although it's not locked - the keyboard works, I just
can't see what's going on.

The first problem is not a big deal. The second probably _is_, for
most folks.

Anyway, sorry for the long email. But since I have limited kernel
programming experience, I thought it best to include as much detail
about what I had done as possible.

Thanks!
Dan Hopper

--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="atyfb.c.diff"

--- linux-2.2.7-pre3/drivers/video/atyfb.c.stock Sat Apr 24 17:27:59 1999
+++ linux-2.2.7-pre3/drivers/video/atyfb.c Sun Apr 25 16:34:58 1999
@@ -88,7 +88,7 @@
* Debug flags.
*/
#undef DEBUG
-
+#define DEBUG /* DBH */

#define GUI_RESERVE 0x00001000

@@ -2438,10 +2438,58 @@
int sense;
#endif

+#ifdef DEBUG
+ unsigned long dantest;
+#endif
+
+#ifdef DEBUG
+ printk("DBH aty_init: I/O port %04x = 0x%02x%02x%02x%02x\n", 0x6eec, inb(0x6eef), inb(0x6eee), inb(0x6eed), inb(0x6eec));
+ printk("DBH aty_init: I/O port %04x = 0x%02x%02x%02x%02x\n", 0x52ec, inb(0x52ef), inb(0x52ee), inb(0x52ed), inb(0x52ec));
+ printk("DBH aty_init: I/O port %04x = 0x%02x%02x%02x%02x\n", 0x6aec, inb(0x6aef), inb(0x6aee), inb(0x6aed), inb(0x6aec));
+#endif
+
+#ifdef DEBUG
+ printk("DBH aty_init: info->ati_regbase_phys = 0x%08lx\n", info->ati_regbase_phys);
+ printk("DBH aty_init: info->ati_regbase = 0x%08lx\n", info->ati_regbase);
+#endif
+
+#ifdef DEBUG
+ printk("DBH aty_init: Enabling 8MB Linear Mem Aperture, w/CONFIG_CNTL I/O port write.\n");
+ outb(inb(0x6aec) | APERTURE_8M_ENABLE, 0x6aec);
+ printk("DBH aty_init: I/O port %04x = 0x%02x%02x%02x%02x\n", 0x6aec, inb(0x6aef), inb(0x6aee), inb(0x6aed), inb(0x6aec));
+#endif
+
+#ifdef DEBUG
+ /* try poking the Mach64 scratch register, like in the XF86 stuff */
+ dantest = aty_ld_le32(SCRATCH_REG0, info);
+ aty_st_le32(SCRATCH_REG0, 0x55555555, info);
+ if (aty_ld_le32(SCRATCH_REG0, info) != 0x55555555)
+ printk("DBH aty_init: compare #1 to SCRATCH_REG0 failed.\n");
+ else
+ printk("DBH aty_init: compare #1 to SCRATCH_REG0 succeeded.\n");
+ aty_st_le32(SCRATCH_REG0, 0xaaaaaaaa, info);
+ if (aty_ld_le32(SCRATCH_REG0, info) != 0xaaaaaaaa)
+ printk("DBH aty_init: compare #2 to SCRATCH_REG0 failed.\n");
+ else
+ printk("DBH aty_init: compare #2 to SCRATCH_REG0 succeeded.\n");
+#endif
+
info->aty_cmap_regs = (struct aty_cmap_regs *)(info->ati_regbase+0xc0);
+#ifdef DEBUG
+ printk("DBH aty_init: info->aty_cmap_regs = 0x%08lx\n", info->aty_cmap_regs);
+#endif
chip_id = aty_ld_le32(CONFIG_CHIP_ID, info);
+#ifdef DEBUG
+ printk("DBH aty_init: chip_id = 0x%08x\n", chip_id);
+#endif
Gx = chip_id & CFG_CHIP_TYPE;
+#ifdef DEBUG
+ printk("DBH aty_init: info->chip_type (Gx) = 0x%04x\n", Gx);
+#endif
Rev = (chip_id & CFG_CHIP_REV)>>24;
+#ifdef DEBUG
+ printk("DBH aty_init: info->chip_rev (Rev) = 0x%02x\n", Rev);
+#endif
for (j = 0; j < (sizeof(aty_features)/sizeof(*aty_features)); j++)
if (aty_features[j].chip_type == Gx) {
chipname = aty_features[j].name;
@@ -2757,6 +2805,7 @@
u16 tmp;
#endif

+
for (pdev = pci_devices; pdev; pdev = pdev->next) {
if (((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY) &&
(pdev->vendor == PCI_VENDOR_ID_ATI)) {
@@ -2773,8 +2822,12 @@
addr = pdev->base_address[1];
if (!addr)
continue;
+#ifdef DEBUG
+ printk("DBH atyfb_init: loc1, addr = 0x%08lx\n", addr);
+#endif
addr &= PCI_BASE_ADDRESS_MEM_MASK;

+
#ifdef __sparc__
/*
* Map memory-mapped registers.
@@ -2986,6 +3039,11 @@
info->ati_regbase_phys += 0xc00;
info->ati_regbase += 0xc00;

+#ifdef DEBUG
+ printk("DBH atyfb_init: loc2, info->ati_regbase_phys = 0x%08lx\n", info->ati_regbase_phys);
+ printk("DBH atyfb_init: loc2, info->ati_regbase = 0x%08lx\n", info->ati_regbase);
+#endif
+
/*
* Enable memory-space accesses using config-space
* command register.
@@ -2994,6 +3052,9 @@
if (!(tmp & PCI_COMMAND_MEMORY)) {
tmp |= PCI_COMMAND_MEMORY;
pci_write_config_word(pdev, PCI_COMMAND, tmp);
+#ifdef DEBUG
+ printk("DBH atyfb_init: Had to enable PCI_COMMAND_MEMORY for ATI\n");
+#endif
}

#ifdef __BIG_ENDIAN
@@ -3004,6 +3065,10 @@
/* Map in frame buffer */
info->frame_buffer_phys = addr;
info->frame_buffer = (unsigned long)ioremap(addr, 0x800000);
+#ifdef DEBUG
+ printk("DBH atyfb_init: loc4, info->frame_buffer_phys = 0x%08lx\n", info->frame_buffer_phys);
+ printk("DBH atyfb_init: loc4, info->frame_buffer = 0x%08lx\n", info->frame_buffer);
+#endif

if(!info->frame_buffer) {
kfree(info);

--envbJBWh7q8WU6mo--

--fUYQa+Pmc3FrFX/N--

-
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/