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,