Hello Stefan,
Am Donnerstag, 6. Oktober 2011, um 23:27:32 schrieb Stefan Tauner:
> On Sat, 1 Oct 2011 08:04:44 +0200
>
> Christoph Grenz <[email protected]> wrote:
> > adds board enable for ABIT AV8 (first revision).
> >
> > Signed-off-by: Christoph Grenz <christophg+cb at grenz-bonn.de>
>
> hello christoph and thanks for the patch!
>
> i guess you own such a board and have tested the board enable yourself?
> could you please provide a verbose log of its action?
> also we would like to see lspci -nn and lspci -xxnnvvv logs to verify
> that the pci ids are well chosen.
Yes, i own it and tested the board enable.
The board's temporarily in use by a family member, but I can provide a verbose
log in about a week.
Ok, I'll append the lspci outputs for verification when I send the verbose
log. (btw, I chose the pci ids by the K8 host bride (00:00.0) and the SuperIO
ISA bridge)
> i cant really comment the enabling function itself besides that it
> maybe it would make sense to add a more general function to set/clear
> GPO on that chipset? though that is probably overkill yet.
>
> how did you find out what to do? is there a public datasheet? etc.
> please tell us the story :)
I disassembled the write enable and the write disable functions from the Award
BIOS image and reconstructed C code to understand for myself what happens.
(Only took me half a night, until this weekend I have semester break, so I had
spare time ;-) )
The ABIT AV8 board uses both the VT8237 chipset write protection, which is
already handled by the code in chipset_enable.c, and the write protection I
handled in my patch, which apparently is connected to some GPIO ports. After
reading the DSDT I found they were called GP22 und GP23 in a region called
GPOB (0x404C-0x404F). I can't really tell which chip they are connected to and
found no writes to the same region in another board enable function, so I
didn't add a general function.
I attached the C code I reconstructed from the bios image to this mail.
> btw i think we usually use the designation "rev. 1.0" (or whatever the
> vendor used) instead of "first revision". did you name it yourself like
> that or was it documented by abit that way?
I named it myself like that because I couldn't find any reference to a
revision number by abit, but as there is a board AV8-3rd-Eye which slightly
differs from the original AV8 and as I don't own it I couldn't test if it
works the same way, so I just wanted to add an indicator which revision I
tested on. So I could change it to "rev. 1.0" or omit it if that's better.
Kind regards,
Christoph Grenz
#include <sys/io.h>
#include <unistd.h>
#include <stdio.h>
#define uchar unsigned char
#define ushort unsigned short
#define uint unsigned int
#define IO_READ inb_p
#define IO_WRITE outb_p
#define IO_WRITE_INT outl_p
inline void PCI_SELECT(uchar bus, uchar device, uchar addr) {
unsigned int data = (1<<31)|(bus << 16)|(device<<8)|addr;
IO_WRITE_INT(data, 0xCF8);
}
inline uchar PCI_READ_BYTE(uchar byte) {
ushort reg = 0xCFC;
reg += byte;
return IO_READ(reg);
}
inline void PCI_WRITE_BYTE(uchar data, uchar byte) {
ushort reg = 0xCFC;
reg += byte;
IO_WRITE(data, reg);
}
// Reads a byte from PCI config space or from ACPI PM I/O space if pcidev == 0xFF
uchar pci_config_read(uchar pcidev, uchar addr) { // 0x0001F75C
if (pcidev != 0xFF) {
uchar addrbase = addr & ~(0x03);
uchar byte = addr & 0x03;
PCI_SELECT (0, pcidev, addrbase);
return PCI_READ_BYTE(byte);
} else {
return IO_READ(0x4000 | addr);
}
}
// Sets a byte from PCI config space or from ACPI PM I/O space if pcidev == 0xFF
void pci_config_write(uchar data, uchar pcidev, uchar addr) { // 0x0001F782
if (pcidev != 0xFF) {
uchar addrbase = addr & ~(0x03);
uchar byte = addr & 0x03;
PCI_SELECT (0, pcidev, addrbase);
PCI_WRITE_BYTE(data, byte);
} else {
IO_WRITE(data, 0x4000 | addr);
}
}
// Sets bits set to 1 in bitmask in PCI config space (or ACPI PM I/O space if pcidev == 0xFF)
void pci_config_setbits(uchar bitmask, uchar pcidev, uchar addr) { // 0x00018539
uchar val = pci_config_read(pcidev, addr);
val = val | bitmask;
pci_config_write(val, pcidev, addr);
}
// Clears bits set to 0 in bitmask in PCI config space (or ACPI PM I/O space if pcidev == 0xFF)
void pci_config_clrbits(uchar bitmask, uchar pcidev, uchar addr) { // 0x00018542
uchar val = pci_config_read(pcidev, addr);
val = val & bitmask;
pci_config_write(val, pcidev, addr);
}
// Calculates the port and 1-byte bitmask from a 4-byte bitmask for the GPO block
void calc_gpo_port(uint *bitmask, ushort *port) { // 0x0001B31A
(*port) = 0x404C;
while ((*bitmask) > 0x80) {
(*port)++;
(*bitmask) >>= 8;
}
}
// Sets bits in the GPO block (delayed/flushed with writes to 0xEB)
// All set bits in the bitmask must be in one byte
void set_gpo_bits(uint bitmask) { // 0x0001B300
ushort port;
calc_gpo_port(&bitmask, &port);
uchar val = IO_READ(port);
IO_WRITE(val, 0xEB);
val |= (uchar)(bitmask);
IO_WRITE(val, port);
IO_WRITE(val, 0xEB);
}
// Clears bits in the GPO block which are set in the bitmask (delayed/flushed with writes to 0xEB)
// All set bits in the bitmask must be in one byte
void clear_gpo_bits(uint bitmask) { // 0x0001B30C
ushort port;
calc_gpo_port(&bitmask, &port);
uchar val = IO_READ(port);
IO_WRITE(val, 0xEB);
val &= ~((uchar)(bitmask));
IO_WRITE(val, port);
IO_WRITE(val, 0xEB);
}
// Clears some bit in southbridge PCI config space and enables GPO ports 22 and 23
// Port names from BIOS DSDT
void enable_gp22_23() { // 0x0001B2E5
// All memory cycles, not just ROM ones, go to LPC. (found out what it does through comments in flashrom code for the chipset, no idea why it's in this subfunction)
uchar pcidev = 0x88; // PCI device 11.0
uchar addr = 0x59;
uchar mask = 0x7F; // 0b01111111
pci_config_clrbits(mask, pcidev, addr);
// Set GPO 22
uint gpomask = 0x00400000;
set_gpo_bits(gpomask);
// Set GPO 23
gpomask = 0x00800000;
set_gpo_bits(gpomask);
}
// Sets some bit in southbridge PCI config space and disables GPO ports 22 and 23
// Port names from BIOS DSDT
void disable_gp22_23() { // 0x0001B2CA
// Reverting which memory cycles go to LPC.
uchar pcidev = 0x88; // PCI device 11.0
uchar addr = 0x59;
uchar mask = 0x80; // 0b10000000
pci_config_setbits(mask, pcidev, addr);
// Clear GPO 22
uint gpomask = 0x00400000;
clear_gpo_bits(gpomask);
// Clear GPO 23
gpomask = 0x00800000;
clear_gpo_bits(gpomask);
}
void write_enable() { // 0x00013DEF
// Enable a bit in a VT8237 southbridge register
uchar pcidev = 0x88; // PCI device 11.0
uchar addr = 0x40;
uchar mask = 0x10;
pci_config_setbits(mask, pcidev, addr);
// Enable GPOs 22 & 23
enable_gp22_23();
// Appears in original BIOS code, but seems to be unnecessary
#if 0
// Do some other io port magic (2.F. appears on internal CMOS display)
while (1) {
uchar val = IO_READ(0xE4); // 0xE4: "CMDP" in DSDT, probably "Command Port"
if ((val & 0x2) == 0) {
IO_WRITE(0x2F, 0xE4);
do {
val = IO_READ(0xE4);
} while ((val & 1) == 0);
IO_READ(0xE0); // 0xE0: "DTAP" in DSDT, probably "Data Port"
return;
}
}
#endif
}
void write_disable() { // 0x00013E13
// Disable a bit in a VT8237 southbridge register
uchar pcidev = 0x88; // PCI device 11.0
uchar addr = 0x40;
uchar mask = 0xEF;
pci_config_clrbits(mask, pcidev, addr);
// Disable GPOs 22 & 23
disable_gp22_23();
// Appears in original BIOS code, but seems to be unnecessary
#if 0
// Do some other io port magic (3.0. appears on internal CMOS display)
while (1) {
uchar val = IO_READ(0xE4); // 0xE4: "CMDP" in DSDT, probably "Command Port"
if ((val & 0x2) == 0) {
IO_WRITE(0x30, 0xE4);
do {
val = IO_READ(0xE4);
} while ((val & 1) == 0);
IO_READ(0xE0); // 0xE0: "DTAP" in DSDT, probably "Data Port"
return;
}
}
#endif
}
/* Testing.. toggle the protection! */
int main () {
if(iopl(3)) {
perror("iopl");
return 1;
}
if (pci_config_read(0x88, 0x40) & 0x10) {
printf ("Disabling ROM write...\n");
write_disable();
printf ("Done.\n");
} else {
printf ("Enabling ROM write...\n");
write_enable();
printf ("Done.\n");
}
}_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom