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,