Hello,
I'm interested in a free software BIOS for the newer Radeon cards which use the AtomBIOS format. The previous legacy BIOS is completely x86 assembly code unique to each card, but the AtomBIOS is modular and *should* be easier to replace. I haven't really done any serious work on this yet, and it's just a spare time project (which isn't very much because of other projects and real life) but there seems to be some interest.
There is some information on my blog (http://olivermcfadden.livejournal.com/) trying to figure out how to flash these cards, but I think it's some kind of GPIO based SPI interface.
AMD have released some register information for the Radeon cards (http://www.x.org/docs/AMD/42589_rv630_rrg_1.01o.pdf and http://www.x.org/docs/AMD/RRG-216M56-03oOEM.pdf) and a working AtomBIOS parser in the radeonhd driver (http://gitweb.freedesktop.org/?p=xorg/driver/xf86-video-radeonhd;a=summary)
I believe the parser in radeonhd is also compiled into the BIOS flashed to the card. I guessed this from some left over preprocessor defines, etc.
As far as I know, the AtomBIOS on the card consists of an interpreter in x86 code, some binary scripts executed by the interpreter, and some data tables, all wrapped up inside the PCI expansion ROM format.
The opcodes and format of the binary scripts and data tables are described by the parser code, so I think there is enough information, except for how to actually flash the on-card ROM...
I don't whether there is much interest for this project, but at least one LinuxBIOS developer seems interested, so let's see where it goes...
On Sunday 09 December 2007, Oliver McFadden wrote:
I believe the parser in radeonhd is also compiled into the BIOS flashed to the card. I guessed this from some left over preprocessor defines, etc.
Not quite,
As far as I know, the AtomBIOS on the card consists of an interpreter in x86 code, some binary scripts executed by the interpreter, and some data tables, all wrapped up inside the PCI expansion ROM format.
That's right. My understanding is AtomBIOS basically consists of tables/code run by an interpreter. The card's ROM has one, and radeonHD has a different one.
The opcodes and format of the binary scripts and data tables are described by the parser code, so I think there is enough information, except for how to actually flash the on-card ROM...
My first interest is to _use_ AtomBIOS cards, and hence I started working on getting the interpreter glued to LinuxBIOS. At least my monitor currently stays totally black with LinuxBIOS, until X comes up, see my previous mails to this list.
Torsten
On 12/9/07, Torsten Duwe duwe@lst.de wrote:
On Sunday 09 December 2007, Oliver McFadden wrote:
I believe the parser in radeonhd is also compiled into the BIOS flashed to the card. I guessed this from some left over preprocessor defines, etc.
Not quite,
Well, obviously AMD removed a lot of the BIOS specific code, but you can still see some defines left in the code; grep for PARSER_TYPE etc. Perhaps more accurate is the BIOS and radeonhd parsers share some code...
As far as I know, the AtomBIOS on the card consists of an interpreter in x86 code, some binary scripts executed by the interpreter, and some data tables, all wrapped up inside the PCI expansion ROM format.
That's right. My understanding is AtomBIOS basically consists of tables/code run by an interpreter. The card's ROM has one, and radeonHD has a different one.
The opcodes and format of the binary scripts and data tables are described by the parser code, so I think there is enough information, except for how to actually flash the on-card ROM...
My first interest is to _use_ AtomBIOS cards, and hence I started working on getting the interpreter glued to LinuxBIOS. At least my monitor currently stays totally black with LinuxBIOS, until X comes up, see my previous mails to this list.
I'll have to find those sometime... I might get some sleep soon...
On 10.12.2007 01:19, Torsten Duwe wrote:
On Sunday 09 December 2007, Oliver McFadden wrote:
The opcodes and format of the binary scripts and data tables are described by the parser code, so I think there is enough information, except for how to actually flash the on-card ROM...
My first interest is to _use_ AtomBIOS cards, and hence I started working on getting the interpreter glued to LinuxBIOS. At least my monitor currently stays totally black with LinuxBIOS, until X comes up, see my previous mails to this list.
Have you tried uvesafb to boot the card under Linux? In that case, you probably have to skip option ROM execution during LinuxBIOS boot.
Regards, Carl-Daniel
Hi Oliver,
On 09.12.2007 23:47, Oliver McFadden wrote:
There is some information on my blog (http://olivermcfadden.livejournal.com/) trying to figure out how to flash these cards, but I think it's some kind of GPIO based SPI interface.
AMD have released some register information for the Radeon cards (http://www.x.org/docs/AMD/42589_rv630_rrg_1.01o.pdf and http://www.x.org/docs/AMD/RRG-216M56-03oOEM.pdf) and a working AtomBIOS parser in the radeonhd driver (http://gitweb.freedesktop.org/?p=xorg/driver/xf86-video-radeonhd;a=summary)
Thanks for the pointers. I will look into implementing SPI support for these cards in a week or so. Ping me if you don't see any code/questions until then.
Regards, Carl-Daniel
On 12/10/07, Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net wrote:
Thanks for the pointers. I will look into implementing SPI support for these cards in a week or so. Ping me if you don't see any code/questions until then.
Here is the code for a simple mmap based interface to the card. You'll need to check lspci -v for the appropriate reg_addr and reg_len variables; the detection code is quite big to include...
You're looking for a block of non-prefetchable memory exactly 64K in size; this is from my card:
Memory at ff5f0000 (32-bit, non-prefetchable) [size=64K]
On 12/11/07, Oliver McFadden z3ro.geek@gmail.com wrote:
On 12/10/07, Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net wrote:
Thanks for the pointers. I will look into implementing SPI support for these cards in a week or so. Ping me if you don't see any code/questions until then.
Here is the code for a simple mmap based interface to the card. You'll need to check lspci -v for the appropriate reg_addr and reg_len variables; the detection code is quite big to include...
You're looking for a block of non-prefetchable memory exactly 64K in size; this is from my card:
Memory at ff5f0000 (32-bit, non-prefetchable) [size=64K]
I forgot to comment out the bogus register_write in that code, so anyone who wants to use it, first comment out the register_write.
On 11.12.2007 22:43, Oliver McFadden wrote:
On 12/11/07, Oliver McFadden z3ro.geek@gmail.com wrote:
On 12/10/07, Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net wrote:
Thanks for the pointers. I will look into implementing SPI support for these cards in a week or so. Ping me if you don't see any code/questions until then.
Here is the code for a simple mmap based interface to the card. You'll need to check lspci -v for the appropriate reg_addr and reg_len variables; the detection code is quite big to include...
You're looking for a block of non-prefetchable memory exactly 64K in size; this is from my card:
Memory at ff5f0000 (32-bit, non-prefetchable) [size=64K]
I forgot to comment out the bogus register_write in that code, so anyone who wants to use it, first comment out the register_write.
First stab at the code, needs a board enable command line option, does a lot of things the wrong way and only works with RV630.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-ati/flash.h =================================================================== --- flashrom-ati/flash.h (Revision 3003) +++ flashrom-ati/flash.h (Arbeitskopie) @@ -249,6 +249,8 @@ /* spi.c */ int probe_spi(struct flashchip *flash); int it87xx_probe_spi_flash(const char *name); +int ati_probe_spi_settings(const char *name); +void read_ati_rom(char *buf, int size); int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); void generic_spi_write_enable(); void generic_spi_write_disable(); Index: flashrom-ati/spi.c =================================================================== --- flashrom-ati/spi.c (Revision 3003) +++ flashrom-ati/spi.c (Arbeitskopie) @@ -22,9 +22,14 @@ */
#include <stdio.h> +#include <errno.h> +#include <fcntl.h> #include <pci/pci.h> #include <stdint.h> +#include <stdlib.h> #include <string.h> +#include <sys/mman.h> +#include <unistd.h> #include "flash.h"
#define ITE_SUPERIO_PORT1 0x2e @@ -216,6 +221,151 @@ return 0; }
+int mem_fd = -1; +unsigned int *ati_reg_mem_map = NULL; + +/* + * 05:00.0 VGA compatible controller: ATI Technologies Inc Radeon R350 [Radeon 9800 Pro] (prog-if 00 [VGA]) + * Subsystem: ATI Technologies Inc Unknown device 0002 + * Flags: bus master, stepping, 66MHz, medium devsel, latency 64, IRQ 16 + * Memory at e8000000 (32-bit, prefetchable) [size=128M] + * I/O ports at c800 [size=256] + * Memory at ff5f0000 (32-bit, non-prefetchable) [size=64K] + * Expansion ROM at ff5c0000 [disabled] [size=128K] + * Capabilities: [58] AGP version 3.0 + * Capabilities: [50] Power Management version 2 + */ + +unsigned int reg_addr = 0xff5f0000; +unsigned int reg_len = 0x10000; + +unsigned int ati_register_read(unsigned int key) +{ + return ati_reg_mem_map[key >> 2]; +} + +/* FIXME: How are we going to make sure the write actually gets posted? */ +void ati_register_write(unsigned int key, unsigned int val) +{ + ati_reg_mem_map[key >> 2] = val; +} + +int ati_open() +{ + if ((mem_fd = open("/dev/mem", O_RDWR)) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + // detect_reg_aperture(); + if ((ati_reg_mem_map = + mmap(NULL, reg_len, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, + reg_addr)) == MAP_FAILED) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + return 0; +} + +int ati_close() +{ + if (munmap(ati_reg_mem_map, reg_len) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (close(mem_fd) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + return 0; +} + +#define ATI_RV630 + +#ifdef ATI_RV630 +/* all of the register indices are relative to GpuF0MMREG */ +#define ATI_BUS_CNTL 0x5420 +#define ATI_ROM_CNTL 0x1600 +#define ATI_ROM_STATUS 0x1608 +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#define ATI_ROM_START 0x1614 +#define ATI_ROM_UNK1 0x1604 +#define ATI_ROM_UNK2 0x160C +#define ATI_ROM_UNK3 0x1610 +#else /* M56, does not work yet */ +/* register indices are relative to HIDEC */ +#define ATI_BIOS_ROM 0x5030 +#define ATI_BUS_CNTL 0x4C +/* register indices are relative to VIPDEC */ +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#endif + +/* WARNING: This is only for RV630! */ +int ati_probe_spi_settings(const char *name) +{ + uint32_t tmp; + int ati_rom_size = 64 * 1024; + char *buf = malloc(ati_rom_size); + + ati_open(); + tmp = ati_register_read(ATI_BUS_CNTL); + printf("BIOS_ROM_WRT_EN: %sabled\n", (tmp & (1 << 0)) ? "en" : "dis"); + printf("BIOS_ROM_DIS: %sabled\n", (tmp & (1 << 1)) ? "dis" : "en"); + tmp = ati_register_read(ATI_ROM_CNTL); + printf("SCK_OVERWRITE: SCK sourced from %s\n", (tmp & (1 << 1)) ? "crystal clock" : "sclk"); + printf("CLOCK_GATING_EN: dynamic clock gating %sabled\n", (tmp & (1 << 2)) ? "en" : "dis"); + printf("CSB_ACTIVE_TO_SCK_SETUP_TIME: 0x%x\n", (tmp & 0xff00) >> 8); + printf("CSB_ACTIVE_TO_SCK_HOLD_TIME: 0x%x\n", (tmp & 0xff0000) >> 16); + printf("SCK_PRESCALE_REFCLK: 0x%x\n", (tmp & 0xf000000) >> 24); + printf("SCK_PRESCALE_CRYSTAL_CLK: 0x%x\n", (tmp & 0xf0000000) >> 28); + tmp = ati_register_read(ATI_ROM_STATUS); + printf("ROM_BUSY: SPI interface is %sbusy\n", (tmp & (1 << 0)) ? "" : "not "); + tmp = ati_register_read(ATI_ROM_INDEX); + printf("ROM_INDEX: address in ROM aperture relative to ROM_START is 0x%06x\n", tmp & 0xffffff); + tmp = ati_register_read(ATI_ROM_DATA); + printf("ROM_DATA: last four bytes read from ROM were 0x%08x\n", tmp); + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture is 0x%06x\n", tmp & 0xffffff); + + read_ati_rom(buf, ati_rom_size); + ati_close(); + + return 0; +} + +void read_ati_rom(char *buf, int size) +{ + int i; + uint32_t tmp; + + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture at time of dump is 0x%06x\n", tmp & 0xffffff); + + for (i = 0; i < size; i += 4) { + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + ati_register_write(ATI_ROM_INDEX, i); + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + tmp = ati_register_read(ATI_ROM_DATA); + printf("%08x ", tmp); + /* Line break after 72 chars */ + if (((i / 4) % 8) == 7) + printf("\n"); + } + printf("dump finished.\n"); + + return; +} + int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { if (it8716f_flashport) Index: flashrom-ati/board_enable.c =================================================================== --- flashrom-ati/board_enable.c (Revision 3003) +++ flashrom-ati/board_enable.c (Arbeitskopie) @@ -377,6 +377,9 @@ };
struct board_pciid_enable board_pciid_enables[] = { + /* FIXME: Check whether this is the correct PCI ID of the RV630 chipset. */ + {0x1002, 0x9589, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + "AMDATI", "RV630", "AMD/ATI RV630 graphics chipset", ati_probe_spi_settings}, {0x10de, 0x0360, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, "gigabyte", "m57sli", "GIGABYTE GA-M57SLI-S4", it87xx_probe_spi_flash}, {0x10de, 0x03e0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
Add support for reading the AMD/ATI RV630 graphics chipset flash ROM. Needs a board enable command line option (flashrom -m AMDATI:RV630) Works with RV630, but BAR addresses have to be fixed up. A timing issue causes all reads to be right-shifted by one bit, resulting in the loss of the LSB. For better debugging, I have to know the exact model of the flash chip and the frequency currently on the SCK connector of the flash chip.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-ati/flash.h =================================================================== --- flashrom-ati/flash.h (Revision 3012) +++ flashrom-ati/flash.h (Arbeitskopie) @@ -262,6 +262,8 @@ /* spi.c */ int probe_spi(struct flashchip *flash); int it87xx_probe_spi_flash(const char *name); +int ati_probe_spi_settings(const char *name); +void read_ati_rom(char *buf, int size); int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); void generic_spi_write_enable(); void generic_spi_write_disable(); Index: flashrom-ati/spi.c =================================================================== --- flashrom-ati/spi.c (Revision 3012) +++ flashrom-ati/spi.c (Arbeitskopie) @@ -22,9 +22,14 @@ */
#include <stdio.h> +#include <errno.h> +#include <fcntl.h> #include <pci/pci.h> #include <stdint.h> +#include <stdlib.h> #include <string.h> +#include <sys/mman.h> +#include <unistd.h> #include "flash.h"
#define ITE_SUPERIO_PORT1 0x2e @@ -216,6 +221,158 @@ return 0; }
+int mem_fd = -1; +unsigned int *ati_reg_mem_map = NULL; + +/* lspci output... + */ + +#error You must fix up reg_addr and reg_len below, then remove the #error. +unsigned int reg_addr = 0xff5f0000; +unsigned int reg_len = 0x10000; + +unsigned int ati_register_read(unsigned int key) +{ + return ati_reg_mem_map[key >> 2]; +} + +/* FIXME: How are we going to make sure the write actually gets posted? */ +void ati_register_write(unsigned int key, unsigned int val) +{ + ati_reg_mem_map[key >> 2] = val; +} + +int ati_open() +{ + if ((mem_fd = open("/dev/mem", O_RDWR)) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + // detect_reg_aperture(); + if ((ati_reg_mem_map = + mmap(NULL, reg_len, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, + reg_addr)) == MAP_FAILED) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + return 0; +} + +int ati_close() +{ + if (munmap(ati_reg_mem_map, reg_len) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (close(mem_fd) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + return 0; +} + +#define ATI_RV630 + +#ifdef ATI_RV630 +/* all of the register indices are relative to GpuF0MMREG */ +#define ATI_BUS_CNTL 0x5420 +#define ATI_ROM_CNTL 0x1600 +#define ATI_ROM_STATUS 0x1608 +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#define ATI_ROM_START 0x1614 +#define ATI_ROM_UNK1 0x1604 +#define ATI_ROM_UNK2 0x160C +#define ATI_ROM_UNK3 0x1610 +#else /* M56, does not work yet */ +/* register indices are relative to HIDEC */ +#define ATI_BIOS_ROM 0x5030 +#define ATI_BUS_CNTL 0x4C +/* register indices are relative to VIPDEC */ +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#endif + +/* WARNING: This is only for RV630! */ +int ati_probe_spi_settings(const char *name) +{ + uint32_t tmp; + int ati_rom_size = 64 * 1024; + char *buf = malloc(ati_rom_size); + + ati_open(); + tmp = ati_register_read(ATI_BUS_CNTL); + printf("BIOS_ROM_WRT_EN: %sabled\n", (tmp & (1 << 0)) ? "en" : "dis"); + printf("BIOS_ROM_DIS: %sabled\n", (tmp & (1 << 1)) ? "dis" : "en"); + tmp = ati_register_read(ATI_ROM_CNTL); + printf("SCK_OVERWRITE: SCK sourced from %s\n", (tmp & (1 << 1)) ? "crystal clock" : "sclk"); + printf("CLOCK_GATING_EN: dynamic clock gating %sabled\n", (tmp & (1 << 2)) ? "en" : "dis"); + printf("CSB_ACTIVE_TO_SCK_SETUP_TIME: 0x%x\n", (tmp & 0xff00) >> 8); + printf("CSB_ACTIVE_TO_SCK_HOLD_TIME: 0x%x\n", (tmp & 0xff0000) >> 16); + printf("SCK_PRESCALE_REFCLK: 0x%x\n", (tmp & 0xf000000) >> 24); + printf("SCK_PRESCALE_CRYSTAL_CLK: 0x%x\n", (tmp & 0xf0000000) >> 28); + tmp = ati_register_read(ATI_ROM_STATUS); + printf("ROM_BUSY: SPI interface is %sbusy\n", (tmp & (1 << 0)) ? "" : "not "); + tmp = ati_register_read(ATI_ROM_INDEX); + printf("ROM_INDEX: address in ROM aperture relative to ROM_START is 0x%06x\n", tmp & 0xffffff); + tmp = ati_register_read(ATI_ROM_DATA); + printf("ROM_DATA: last four bytes read from ROM were 0x%08x\n", tmp); + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture is 0x%06x\n", tmp & 0xffffff); + + read_ati_rom(buf, ati_rom_size); + ati_close(); + + return 0; +} + +void read_ati_rom(char *buf, int size) +{ + int i; + uint32_t tmp; + + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture at time of dump is 0x%06x\n", tmp & 0xffffff); + + for (i = 0; i < size; i += 4) { + usleep(1000); + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + ati_register_write(ATI_ROM_INDEX, i); + usleep(1000); + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + tmp = ati_register_read(ATI_ROM_DATA); + /* FIXME: The bitshift is most likely due to a timing problem. + * To be clear: All ROM readouts are missing the LSB. + * Two likely reasons: + * - We read ATI_ROM_DATA too early. The unconditional + * usleep(1000) above should fix that. + * - SCK has a too high frequency. Adjusting SCK_PRESCALE_* + * should fix that. If that doesn't work, we can try to use + * a different clock reference. + */ + tmp <<= 1; + printf("%02x", (tmp >> 0) & 0xff); + printf("%02x", (tmp >> 8) & 0xff); + printf("%02x", (tmp >> 16) & 0xff); + printf("%02x ", (tmp >> 24) & 0xff); + /* Line break after 72 chars */ + if (((i / 4) % 8) == 7) + printf("\n"); + } + printf("dump finished.\n"); + + return; +} + int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { if (it8716f_flashport) Index: flashrom-ati/board_enable.c =================================================================== --- flashrom-ati/board_enable.c (Revision 3012) +++ flashrom-ati/board_enable.c (Arbeitskopie) @@ -377,6 +377,9 @@ };
struct board_pciid_enable board_pciid_enables[] = { + /* FIXME: Check whether this is the correct PCI ID of the RV630 chipset. */ + {0x1002, 0x9589, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + "AMDATI", "RV630", "AMD/ATI RV630 graphics chipset", ati_probe_spi_settings}, {0x10de, 0x0360, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, "gigabyte", "m57sli", "GIGABYTE GA-M57SLI-S4", it87xx_probe_spi_flash}, {0x10de, 0x03e0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
On 18.12.2007 15:56, Carl-Daniel Hailfinger wrote:
Add support for reading the AMD/ATI RV630 graphics chipset flash ROM. Needs a board enable command line option (flashrom -m AMDATI:RV630) Works with RV630, but BAR addresses have to be fixed up. A timing issue causes all reads to be right-shifted by one bit, resulting in the loss of the LSB. For better debugging, I have to know the exact model of the flash chip and the frequency currently on the SCK connector of the flash chip.
Easiest way to debug would be to try this against a not POSTed card (secondary card) and then try it again when the card is POSTed. Compare the results (including status registers). Send them to the list.
Regards, Carl-Daniel
On 18.12.2007 16:11, Carl-Daniel Hailfinger wrote:
On 18.12.2007 15:56, Carl-Daniel Hailfinger wrote:
Add support for reading the AMD/ATI RV630 graphics chipset flash ROM. Needs a board enable command line option (flashrom -m AMDATI:RV630) Works with RV630, but BAR addresses have to be fixed up. A timing issue causes all reads to be right-shifted by one bit, resulting in the loss of the LSB. For better debugging, I have to know the exact model of the flash chip and the frequency currently on the SCK connector of the flash chip.
Easiest way to debug would be to try this against a not POSTed card (secondary card) and then try it again when the card is POSTed. Compare the results (including status registers). Send them to the list.
Bit shift needed to happen in native byte order. Use interleaving read to workaround the issue of lost LSB.
Index: flashrom-ati/flash.h =================================================================== --- flashrom-ati/flash.h (Revision 3012) +++ flashrom-ati/flash.h (Arbeitskopie) @@ -262,6 +262,8 @@ /* spi.c */ int probe_spi(struct flashchip *flash); int it87xx_probe_spi_flash(const char *name); +int ati_probe_spi_settings(const char *name); +void read_ati_rom(char *buf, int size); int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); void generic_spi_write_enable(); void generic_spi_write_disable(); Index: flashrom-ati/spi.c =================================================================== --- flashrom-ati/spi.c (Revision 3012) +++ flashrom-ati/spi.c (Arbeitskopie) @@ -22,9 +22,14 @@ */
#include <stdio.h> +#include <errno.h> +#include <fcntl.h> #include <pci/pci.h> #include <stdint.h> +#include <stdlib.h> #include <string.h> +#include <sys/mman.h> +#include <unistd.h> #include "flash.h"
#define ITE_SUPERIO_PORT1 0x2e @@ -216,6 +221,163 @@ return 0; }
+int mem_fd = -1; +unsigned int *ati_reg_mem_map = NULL; + +/* lspci output... + */ + +#error You must fix up reg_addr and reg_len below, then remove the #error. +unsigned int reg_addr = 0xdfff0000; +unsigned int reg_len = 0x10000; + +unsigned int ati_register_read(unsigned int key) +{ + return ati_reg_mem_map[key >> 2]; +} + +/* FIXME: How are we going to make sure the write actually gets posted? */ +void ati_register_write(unsigned int key, unsigned int val) +{ + ati_reg_mem_map[key >> 2] = val; +} + +int ati_open() +{ + if ((mem_fd = open("/dev/mem", O_RDWR)) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + // detect_reg_aperture(); + if ((ati_reg_mem_map = + mmap(NULL, reg_len, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, + reg_addr)) == MAP_FAILED) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + return 0; +} + +int ati_close() +{ + if (munmap(ati_reg_mem_map, reg_len) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (close(mem_fd) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + return 0; +} + +#define ATI_RV630 + +#ifdef ATI_RV630 +/* all of the register indices are relative to GpuF0MMREG */ +#define ATI_BUS_CNTL 0x5420 +#define ATI_ROM_CNTL 0x1600 +#define ATI_ROM_STATUS 0x1608 +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#define ATI_ROM_START 0x1614 +#define ATI_ROM_UNK1 0x1604 +#define ATI_ROM_UNK2 0x160C +#define ATI_ROM_UNK3 0x1610 +#else /* M56, does not work yet */ +/* register indices are relative to HIDEC */ +#define ATI_BIOS_ROM 0x5030 +#define ATI_BUS_CNTL 0x4C +/* register indices are relative to VIPDEC */ +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#endif + +/* WARNING: This is only for RV630! */ +int ati_probe_spi_settings(const char *name) +{ + uint32_t tmp; + int ati_rom_size = 64 * 1024; + char *buf = malloc(ati_rom_size); + + ati_open(); + tmp = ati_register_read(ATI_BUS_CNTL); + printf("BIOS_ROM_WRT_EN: %sabled\n", (tmp & (1 << 0)) ? "en" : "dis"); + printf("BIOS_ROM_DIS: %sabled\n", (tmp & (1 << 1)) ? "dis" : "en"); + tmp = ati_register_read(ATI_ROM_CNTL); + printf("SCK_OVERWRITE: SCK sourced from %s\n", (tmp & (1 << 1)) ? "crystal clock" : "sclk"); + printf("CLOCK_GATING_EN: dynamic clock gating %sabled\n", (tmp & (1 << 2)) ? "en" : "dis"); + printf("CSB_ACTIVE_TO_SCK_SETUP_TIME: 0x%x\n", (tmp & 0xff00) >> 8); + printf("CSB_ACTIVE_TO_SCK_HOLD_TIME: 0x%x\n", (tmp & 0xff0000) >> 16); + printf("SCK_PRESCALE_REFCLK: 0x%x\n", (tmp & 0xf000000) >> 24); + printf("SCK_PRESCALE_CRYSTAL_CLK: 0x%x\n", (tmp & 0xf0000000) >> 28); + tmp = ati_register_read(ATI_ROM_STATUS); + printf("ROM_BUSY: SPI interface is %sbusy\n", (tmp & (1 << 0)) ? "" : "not "); + tmp = ati_register_read(ATI_ROM_INDEX); + printf("ROM_INDEX: address in ROM aperture relative to ROM_START is 0x%06x\n", tmp & 0xffffff); + tmp = ati_register_read(ATI_ROM_DATA); + printf("ROM_DATA: last four bytes read from ROM were 0x%08x\n", tmp); + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture is 0x%06x\n", tmp & 0xffffff); + + read_ati_rom(buf, ati_rom_size); + ati_close(); + + return 0; +} + +void read_ati_rom(char *buf, int size) +{ + int i; + uint32_t tmp, tmp2; + + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture at time of dump is 0x%06x\n", tmp & 0xffffff); + + for (i = 0; i < size; i += 2) { + usleep(1000); + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + ati_register_write(ATI_ROM_INDEX, i); + usleep(1000); + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + tmp = ati_register_read(ATI_ROM_DATA); + /* FIXME: The bitshift is most likely due to a timing problem. + * To be clear: All ROM readouts are missing the LSB. + * Two likely reasons: + * - We read ATI_ROM_DATA too early. The unconditional + * usleep(1000) above should fix that. + * - SCK has a too high frequency. Adjusting SCK_PRESCALE_* + * should fix that. If that doesn't work, we can try to use + * a different clock reference. + */ + tmp2 = ntohl(tmp); + tmp2 <<= 1; + tmp = htonl(tmp2); + printf("%02x", (tmp >> 0) & 0xff); + printf("%02x ", (tmp >> 8) & 0xff); + /* As a temporary band-aid, we discard the last two bytes + * and read in 2 byte increments. + */ + /*printf("%02x", (tmp >> 16) & 0xff); + printf("%02x ", (tmp >> 24) & 0xff); */ + /* Line break after 32 bytes. */ + if ((i % 32) == 30) + printf("\n"); + } + printf("dump finished.\n"); + + return; +} + int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { if (it8716f_flashport) Index: flashrom-ati/board_enable.c =================================================================== --- flashrom-ati/board_enable.c (Revision 3012) +++ flashrom-ati/board_enable.c (Arbeitskopie) @@ -377,6 +377,10 @@ };
struct board_pciid_enable board_pciid_enables[] = { + {0x1002, 0x9589, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + "ATI", "RV630", "ATI Technologies RV630 graphics", ati_probe_spi_settings}, + {0x1002, 0x94c3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + "ATI", "94c3", "ATI Technologies Inc 94c3", ati_probe_spi_settings}, {0x10de, 0x0360, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, "gigabyte", "m57sli", "GIGABYTE GA-M57SLI-S4", it87xx_probe_spi_flash}, {0x10de, 0x03e0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
On 18.12.2007 18:38, Carl-Daniel Hailfinger wrote:
On 18.12.2007 16:11, Carl-Daniel Hailfinger wrote:
On 18.12.2007 15:56, Carl-Daniel Hailfinger wrote:
Add support for reading the AMD/ATI RV630 graphics chipset flash ROM. Needs a board enable command line option (flashrom -m AMDATI:RV630) Works with RV630, but BAR addresses have to be fixed up. A timing issue causes all reads to be right-shifted by one bit, resulting in the loss of the LSB. For better debugging, I have to know the exact model of the flash chip and the frequency currently on the SCK connector of the flash chip.
Easiest way to debug would be to try this against a not POSTed card (secondary card) and then try it again when the card is POSTed. Compare the results (including status registers). Send them to the list.
Bit shift needed to happen in native byte order. Use interleaving read to workaround the issue of lost LSB.
Workaround didn't work: Register documentation was wrong. Simply accept that every 32th bit will be wrong.
Index: flashrom-ati/flash.h =================================================================== --- flashrom-ati/flash.h (Revision 3012) +++ flashrom-ati/flash.h (Arbeitskopie) @@ -262,6 +262,8 @@ /* spi.c */ int probe_spi(struct flashchip *flash); int it87xx_probe_spi_flash(const char *name); +int ati_probe_spi_settings(const char *name); +void read_ati_rom(char *buf, int size); int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); void generic_spi_write_enable(); void generic_spi_write_disable(); Index: flashrom-ati/spi.c =================================================================== --- flashrom-ati/spi.c (Revision 3012) +++ flashrom-ati/spi.c (Arbeitskopie) @@ -22,9 +22,14 @@ */
#include <stdio.h> +#include <errno.h> +#include <fcntl.h> #include <pci/pci.h> #include <stdint.h> +#include <stdlib.h> #include <string.h> +#include <sys/mman.h> +#include <unistd.h> #include "flash.h"
#define ITE_SUPERIO_PORT1 0x2e @@ -216,6 +221,168 @@ return 0; }
+int mem_fd = -1; +unsigned int *ati_reg_mem_map = NULL; + +/* +lspci output: +02:00.0 VGA compatible controller: ATI Technologies Inc Unknown device 94c3 (prog-if 00 [VGA]) + Subsystem: Hightech Information System Ltd. Unknown device 2232 + Flags: bus master, fast devsel, latency 0, IRQ 11 + Memory at c0000000 (64-bit, prefetchable) [size=256M] +------> Memory at dfff0000 (64-bit, non-prefetchable) [size=64K] <------------ + I/O ports at e800 [size=256] + Expansion ROM at dffc0000 [disabled] [size=128K] + */ + +#error You must fix up reg_addr and reg_len below, then remove the #error. +unsigned int reg_addr = 0xdfff0000; +unsigned int reg_len = 0x10000; + +unsigned int ati_register_read(unsigned int key) +{ + return ati_reg_mem_map[key >> 2]; +} + +/* FIXME: How are we going to make sure the write actually gets posted? */ +void ati_register_write(unsigned int key, unsigned int val) +{ + ati_reg_mem_map[key >> 2] = val; +} + +int ati_open() +{ + if ((mem_fd = open("/dev/mem", O_RDWR)) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + // detect_reg_aperture(); + if ((ati_reg_mem_map = + mmap(NULL, reg_len, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, + reg_addr)) == MAP_FAILED) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + return 0; +} + +int ati_close() +{ + if (munmap(ati_reg_mem_map, reg_len) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (close(mem_fd) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + return 0; +} + +#define ATI_RV630 + +#ifdef ATI_RV630 +/* all of the register indices are relative to GpuF0MMREG */ +#define ATI_BUS_CNTL 0x5420 +#define ATI_ROM_CNTL 0x1600 +#define ATI_ROM_STATUS 0x1608 +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#define ATI_ROM_START 0x1614 +#define ATI_ROM_UNK1 0x1604 +#define ATI_ROM_UNK2 0x160C +#define ATI_ROM_UNK3 0x1610 +#else /* M56, does not work yet */ +/* register indices are relative to HIDEC */ +#define ATI_BIOS_ROM 0x5030 +#define ATI_BUS_CNTL 0x4C +/* register indices are relative to VIPDEC */ +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#endif + +/* WARNING: This is only for RV630! */ +int ati_probe_spi_settings(const char *name) +{ + uint32_t tmp; + int ati_rom_size = 64 * 1024; + char *buf = malloc(ati_rom_size); + + ati_open(); + tmp = ati_register_read(ATI_BUS_CNTL); + printf("BIOS_ROM_WRT_EN: %sabled\n", (tmp & (1 << 0)) ? "en" : "dis"); + printf("BIOS_ROM_DIS: %sabled\n", (tmp & (1 << 1)) ? "dis" : "en"); + tmp = ati_register_read(ATI_ROM_CNTL); + printf("SCK_OVERWRITE: SCK sourced from %s\n", (tmp & (1 << 1)) ? "crystal clock" : "sclk"); + printf("CLOCK_GATING_EN: dynamic clock gating %sabled\n", (tmp & (1 << 2)) ? "en" : "dis"); + printf("CSB_ACTIVE_TO_SCK_SETUP_TIME: 0x%x\n", (tmp & 0xff00) >> 8); + printf("CSB_ACTIVE_TO_SCK_HOLD_TIME: 0x%x\n", (tmp & 0xff0000) >> 16); + printf("SCK_PRESCALE_REFCLK: 0x%x\n", (tmp & 0xf000000) >> 24); + printf("SCK_PRESCALE_CRYSTAL_CLK: 0x%x\n", (tmp & 0xf0000000) >> 28); + tmp = ati_register_read(ATI_ROM_STATUS); + printf("ROM_BUSY: SPI interface is %sbusy\n", (tmp & (1 << 0)) ? "" : "not "); + tmp = ati_register_read(ATI_ROM_INDEX); + printf("ROM_INDEX: address in ROM aperture relative to ROM_START is 0x%06x\n", tmp & 0xffffff); + tmp = ati_register_read(ATI_ROM_DATA); + printf("ROM_DATA: last four bytes read from ROM were 0x%08x\n", tmp); + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture is 0x%06x\n", tmp & 0xffffff); + + read_ati_rom(buf, ati_rom_size); + ati_close(); + + return 0; +} + +void read_ati_rom(char *buf, int size) +{ + int i; + uint32_t tmp, tmp2; + + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture at time of dump is 0x%06x\n", tmp & 0xffffff); + + for (i = 0; i < size; i += 4) { + usleep(1000); + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + ati_register_write(ATI_ROM_INDEX, i); + usleep(1000); + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + tmp = ati_register_read(ATI_ROM_DATA); + /* FIXME: The bitshift is most likely due to a timing problem. + * To be clear: All ROM readouts are missing the LSB. + * Two likely reasons: + * - We read ATI_ROM_DATA too early. The unconditional + * usleep(1000) above should fix that. + * - SCK has a too high frequency. Adjusting SCK_PRESCALE_* + * should fix that. If that doesn't work, we can try to use + * a different clock reference. + */ + tmp2 = ntohl(tmp); + tmp2 <<= 1; + tmp = htonl(tmp2); + printf("%02x", (tmp >> 0) & 0xff); + printf("%02x ", (tmp >> 8) & 0xff); + printf("%02x", (tmp >> 16) & 0xff); + printf("%02x ", (tmp >> 24) & 0xff); + /* Line break after 32 bytes. */ + if ((i & 31) == 28) + printf("\n"); + } + printf("dump finished.\n"); + + return; +} + int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { if (it8716f_flashport) Index: flashrom-ati/board_enable.c =================================================================== --- flashrom-ati/board_enable.c (Revision 3012) +++ flashrom-ati/board_enable.c (Arbeitskopie) @@ -377,6 +377,10 @@ };
struct board_pciid_enable board_pciid_enables[] = { + {0x1002, 0x9589, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + "ATI", "RV630", "ATI Technologies RV630 graphics", ati_probe_spi_settings}, + {0x1002, 0x94c3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + "ATI", "94c3", "ATI Technologies Inc 94c3", ati_probe_spi_settings}, {0x10de, 0x0360, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, "gigabyte", "m57sli", "GIGABYTE GA-M57SLI-S4", it87xx_probe_spi_flash}, {0x10de, 0x03e0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
On 18.12.2007 18:49, Carl-Daniel Hailfinger wrote:
On 18.12.2007 18:38, Carl-Daniel Hailfinger wrote:
On 18.12.2007 16:11, Carl-Daniel Hailfinger wrote:
On 18.12.2007 15:56, Carl-Daniel Hailfinger wrote:
Add support for reading the AMD/ATI RV630 graphics chipset flash ROM. Needs a board enable command line option (flashrom -m AMDATI:RV630) Works with RV630, but BAR addresses have to be fixed up. A timing issue causes all reads to be right-shifted by one bit, resulting in the loss of the LSB. For better debugging, I have to know the exact model of the flash chip and the frequency currently on the SCK connector of the flash chip.
Easiest way to debug would be to try this against a not POSTed card (secondary card) and then try it again when the card is POSTed. Compare the results (including status registers). Send them to the list.
Bit shift needed to happen in native byte order. Use interleaving read to workaround the issue of lost LSB.
Workaround didn't work: Register documentation was wrong.
Change PRESCALE from 1 to 3.
Index: flashrom-ati/flash.h =================================================================== --- flashrom-ati/flash.h (Revision 3012) +++ flashrom-ati/flash.h (Arbeitskopie) @@ -262,6 +262,8 @@ /* spi.c */ int probe_spi(struct flashchip *flash); int it87xx_probe_spi_flash(const char *name); +int ati_probe_spi_settings(const char *name); +void read_ati_rom(char *buf, int size); int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); void generic_spi_write_enable(); void generic_spi_write_disable(); Index: flashrom-ati/spi.c =================================================================== --- flashrom-ati/spi.c (Revision 3012) +++ flashrom-ati/spi.c (Arbeitskopie) @@ -22,9 +22,14 @@ */
#include <stdio.h> +#include <errno.h> +#include <fcntl.h> #include <pci/pci.h> #include <stdint.h> +#include <stdlib.h> #include <string.h> +#include <sys/mman.h> +#include <unistd.h> #include "flash.h"
#define ITE_SUPERIO_PORT1 0x2e @@ -216,6 +221,175 @@ return 0; }
+int mem_fd = -1; +unsigned int *ati_reg_mem_map = NULL; + +/* +lspci output: +02:00.0 VGA compatible controller: ATI Technologies Inc Unknown device 94c3 (prog-if 00 [VGA]) + Subsystem: Hightech Information System Ltd. Unknown device 2232 + Flags: bus master, fast devsel, latency 0, IRQ 11 + Memory at c0000000 (64-bit, prefetchable) [size=256M] +------> Memory at dfff0000 (64-bit, non-prefetchable) [size=64K] <------------ + I/O ports at e800 [size=256] + Expansion ROM at dffc0000 [disabled] [size=128K] + */ + +#error You must fix up reg_addr and reg_len below, then remove the #error. +unsigned int reg_addr = 0xdfff0000; +unsigned int reg_len = 0x10000; + +unsigned int ati_register_read(unsigned int key) +{ + return ati_reg_mem_map[key >> 2]; +} + +/* FIXME: How are we going to make sure the write actually gets posted? */ +void ati_register_write(unsigned int key, unsigned int val) +{ + ati_reg_mem_map[key >> 2] = val; +} + +int ati_open() +{ + if ((mem_fd = open("/dev/mem", O_RDWR)) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + // detect_reg_aperture(); + if ((ati_reg_mem_map = + mmap(NULL, reg_len, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, + reg_addr)) == MAP_FAILED) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + return 0; +} + +int ati_close() +{ + if (munmap(ati_reg_mem_map, reg_len) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (close(mem_fd) < 0) { + fprintf(stderr, "flashrom: %s:%d: %s\n", + __FILE__, __LINE__, strerror(errno)); + exit(EXIT_FAILURE); + } + + return 0; +} + +#define ATI_RV630 + +#ifdef ATI_RV630 +/* all of the register indices are relative to GpuF0MMREG */ +#define ATI_BUS_CNTL 0x5420 +#define ATI_ROM_CNTL 0x1600 +#define ATI_ROM_STATUS 0x1608 +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#define ATI_ROM_START 0x1614 +#define ATI_ROM_UNK1 0x1604 +#define ATI_ROM_UNK2 0x160C +#define ATI_ROM_UNK3 0x1610 +#else /* M56, does not work yet */ +/* register indices are relative to HIDEC */ +#define ATI_BIOS_ROM 0x5030 +#define ATI_BUS_CNTL 0x4C +/* register indices are relative to VIPDEC */ +#define ATI_ROM_INDEX 0xA8 +#define ATI_ROM_DATA 0xAC +#endif + +/* WARNING: This is only for RV630! */ +int ati_probe_spi_settings(const char *name) +{ + uint32_t tmp; + int ati_rom_size = 64 * 1024; + char *buf = malloc(ati_rom_size); + + ati_open(); + tmp = ati_register_read(ATI_BUS_CNTL); + printf("BIOS_ROM_WRT_EN: %sabled\n", (tmp & (1 << 0)) ? "en" : "dis"); + printf("BIOS_ROM_DIS: %sabled\n", (tmp & (1 << 1)) ? "dis" : "en"); + tmp = ati_register_read(ATI_ROM_CNTL); + printf("SCK_OVERWRITE: SCK sourced from %s\n", (tmp & (1 << 1)) ? "crystal clock" : "sclk"); + printf("CLOCK_GATING_EN: dynamic clock gating %sabled\n", (tmp & (1 << 2)) ? "en" : "dis"); + printf("CSB_ACTIVE_TO_SCK_SETUP_TIME: 0x%x\n", (tmp & 0xff00) >> 8); + printf("CSB_ACTIVE_TO_SCK_HOLD_TIME: 0x%x\n", (tmp & 0xff0000) >> 16); + printf("SCK_PRESCALE_REFCLK: 0x%x\n", (tmp & 0xf000000) >> 24); + printf("SCK_PRESCALE_CRYSTAL_CLK: 0x%x\n", (tmp & 0xf0000000) >> 28); + tmp = ati_register_read(ATI_ROM_STATUS); + printf("ROM_BUSY: SPI interface is %sbusy\n", (tmp & (1 << 0)) ? "" : "not "); + tmp = ati_register_read(ATI_ROM_INDEX); + printf("ROM_INDEX: address in ROM aperture relative to ROM_START is 0x%06x\n", tmp & 0xffffff); + tmp = ati_register_read(ATI_ROM_DATA); + printf("ROM_DATA: last four bytes read from ROM were 0x%08x\n", tmp); + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture is 0x%06x\n", tmp & 0xffffff); + + read_ati_rom(buf, ati_rom_size); + ati_close(); + + return 0; +} + +void read_ati_rom(char *buf, int size) +{ + int i; + uint32_t tmp, tmp2; + + tmp = ati_register_read(ATI_ROM_START); + printf("ROM_START: start address of ROM aperture at time of dump is 0x%06x\n", tmp & 0xffffff); + + printf("Setting SCK_PRESCALE_* to 3\n"); + tmp = ati_register_read(ATI_ROM_CNTL); + tmp &= 0x00ffffff; + /* SCK_PRESCALE_REFCLK = 3 */ + tmp |= (0x3 << 24) & 0xf000000; + /* SCK_PRESCALE_CRYSTAL_CLK = 3 */ + tmp |= (0x3 << 28) & 0xf0000000; + ati_register_write(ATI_ROM_CNTL, tmp); + + for (i = 0; i < size; i += 4) { + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + ati_register_write(ATI_ROM_INDEX, i); + while (ati_register_read(ATI_ROM_STATUS) & 0x1) + usleep(1000); + tmp = ati_register_read(ATI_ROM_DATA); + /* FIXME: The bitshift is most likely due to a timing problem. + * To be clear: All ROM readouts are missing the LSB. + * Two likely reasons: + * - We read ATI_ROM_DATA too early. The unconditional + * usleep(1000) above should fix that. + * - SCK has a too high frequency. Adjusting SCK_PRESCALE_* + * should fix that. If that doesn't work, we can try to use + * a different clock reference. + */ + tmp2 = ntohl(tmp); + tmp2 <<= 1; + tmp = htonl(tmp2); + printf("%02x", (tmp >> 0) & 0xff); + printf("%02x ", (tmp >> 8) & 0xff); + printf("%02x", (tmp >> 16) & 0xff); + printf("%02x ", (tmp >> 24) & 0xff); + /* Line break after 32 bytes. */ + if ((i & 31) == 28) + printf("\n"); + } + printf("dump finished.\n"); + + return; +} + int generic_spi_command(unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr) { if (it8716f_flashport) Index: flashrom-ati/board_enable.c =================================================================== --- flashrom-ati/board_enable.c (Revision 3012) +++ flashrom-ati/board_enable.c (Arbeitskopie) @@ -377,6 +377,10 @@ };
struct board_pciid_enable board_pciid_enables[] = { + {0x1002, 0x9589, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + "ATI", "RV630", "ATI Technologies RV630 graphics", ati_probe_spi_settings}, + {0x1002, 0x94c3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + "ATI", "94c3", "ATI Technologies Inc 94c3", ati_probe_spi_settings}, {0x10de, 0x0360, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, "gigabyte", "m57sli", "GIGABYTE GA-M57SLI-S4", it87xx_probe_spi_flash}, {0x10de, 0x03e0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,