Author: uwe Date: 2008-11-28 22:36:51 +0100 (Fri, 28 Nov 2008) New Revision: 3779
Added: trunk/util/flashrom/sb600spi.c Modified: trunk/util/flashrom/Makefile trunk/util/flashrom/chipset_enable.c trunk/util/flashrom/flash.h trunk/util/flashrom/flashrom.c trunk/util/flashrom/spi.c trunk/util/flashrom/spi.h Log: Add support for the AMD/ATI SB600 southbridge SPI functionality.
This has been tested by Uwe Hermann on an RS690/SB600 board.
Signed-off-by: Jason Wang Qingpei.Wang@amd.com Reviewed-by: Joe Bao zheng.bao@amd.com Acked-by: Uwe Hermann uwe@hermann-uwe.de
Modified: trunk/util/flashrom/Makefile =================================================================== --- trunk/util/flashrom/Makefile 2008-11-28 12:09:17 UTC (rev 3778) +++ trunk/util/flashrom/Makefile 2008-11-28 21:36:51 UTC (rev 3779) @@ -29,7 +29,7 @@ w49f002u.o 82802ab.o pm49fl00x.o sst49lf040.o en29f002a.o \ sst49lfxxxc.o sst_fwhub.o layout.o cbtable.o flashchips.o \ flashrom.o w39v080fa.o sharplhf00l04.o w29ee011.o spi.o it87spi.o \ - ichspi.o w39v040c.o + ichspi.o w39v040c.o sb600spi.o
all: pciutils dep $(PROGRAM)
Modified: trunk/util/flashrom/chipset_enable.c =================================================================== --- trunk/util/flashrom/chipset_enable.c 2008-11-28 12:09:17 UTC (rev 3778) +++ trunk/util/flashrom/chipset_enable.c 2008-11-28 21:36:51 UTC (rev 3779) @@ -647,21 +647,36 @@
static int enable_flash_sb600(struct pci_dev *dev, const char *name) { - uint32_t old, new; + uint32_t tmp, low_bits, num; uint8_t reg;
- /* Clear ROM Protect 0-3 */ + low_bits = tmp = pci_read_long(dev, 0xa0); + low_bits &= ~0xffffc000; /* for mmap aligning requirements */ + low_bits &= 0xfffffff0; /* remove low 4 bits */ + tmp &= 0xffffc000; + printf_debug("SPI base address is at 0x%x\n", tmp + low_bits); + + sb600_spibar = mmap(0, 0x4000, PROT_READ | PROT_WRITE, MAP_SHARED, + fd_mem, (off_t)tmp); + if (sb600_spibar == MAP_FAILED) { + perror("Can't mmap memory using " MEM_DEV); + exit(1); + } + sb600_spibar += low_bits; + + /* Clear ROM protect 0-3. */ for (reg = 0x50; reg < 0x60; reg += 4) { - old = pci_read_long(dev, reg); - new = old & 0xFFFFFFFC; - if (new != old) { - pci_write_byte(dev, reg, new); - if (pci_read_long(dev, reg) != new) { - printf("tried to set 0x%x to 0x%x on %s failed (WARNING ONLY)\n", 0x50, new, name); - } - } + num = pci_read_long(dev, reg); + num &= 0xfffffffc; + pci_write_byte(dev, reg, num); }
+ flashbus = BUS_TYPE_SB600_SPI; + + /* Enable SPI ROM in SB600 PM register. */ + OUTB(0x8f, 0xcd6); + OUTB(0x0e, 0xcd7); + return 0; }
Modified: trunk/util/flashrom/flash.h =================================================================== --- trunk/util/flashrom/flash.h 2008-11-28 12:09:17 UTC (rev 3778) +++ trunk/util/flashrom/flash.h 2008-11-28 21:36:51 UTC (rev 3779) @@ -414,6 +414,7 @@ BUS_TYPE_ICH7_SPI, BUS_TYPE_ICH9_SPI, BUS_TYPE_IT87XX_SPI, + BUS_TYPE_SB600_SPI, BUS_TYPE_VIA_SPI } flashbus_t;
@@ -497,6 +498,14 @@ int it8716f_spi_chip_read(struct flashchip *flash, uint8_t *buf); int it8716f_spi_chip_write(struct flashchip *flash, uint8_t *buf);
+/* sb600spi.c */ +int sb600_spi_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int sb600_spi_read(struct flashchip *flash, uint8_t *buf); +int sb600_spi_write(struct flashchip *flash, uint8_t *buf); +uint8_t sb600_read_status_register(void); +extern uint8_t volatile *sb600_spibar; + /* jedec.c */ uint8_t oddparity(uint8_t val); void toggle_ready_jedec(volatile uint8_t *dst);
Modified: trunk/util/flashrom/flashrom.c =================================================================== --- trunk/util/flashrom/flashrom.c 2008-11-28 12:09:17 UTC (rev 3778) +++ trunk/util/flashrom/flashrom.c 2008-11-28 21:36:51 UTC (rev 3779) @@ -463,7 +463,7 @@ perror(filename); exit(1); } - printf("Force reading flash..."); + printf("Force reading flash... "); if (!flashes[0]->read) memcpy(buf, (const char *)flashes[0]->virtual_memory, size); else @@ -476,7 +476,7 @@
fwrite(buf, sizeof(char), size, image); fclose(image); - printf("done\n"); + printf("done.\n"); free(buf); exit(0); } @@ -533,19 +533,20 @@ buf = (uint8_t *) calloc(size, sizeof(char));
if (erase_it) { - printf("Erasing flash chip.\n"); + printf("Erasing flash chip... "); if (!flash->erase) { fprintf(stderr, "Error: flashrom has no erase function for this flash chip.\n"); return 1; } flash->erase(flash); + printf("done.\n"); exit(0); } else if (read_it) { if ((image = fopen(filename, "w")) == NULL) { perror(filename); exit(1); } - printf("Reading Flash..."); + printf("Reading flash... "); if (flash->read == NULL) memcpy(buf, (const char *)flash->virtual_memory, size); else @@ -557,7 +558,7 @@
fwrite(buf, sizeof(char), size, image); fclose(image); - printf("done\n"); + printf("done.\n"); } else { struct stat image_stat;
Added: trunk/util/flashrom/sb600spi.c =================================================================== --- trunk/util/flashrom/sb600spi.c (rev 0) +++ trunk/util/flashrom/sb600spi.c 2008-11-28 21:36:51 UTC (rev 3779) @@ -0,0 +1,175 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2008 Stefan Wildemann stefan.wildemann@kontron.com + * Copyright (C) 2008 Claus Gindhart claus.gindhart@kontron.com + * Copyright (C) 2008 Dominik Geyer dominik.geyer@kontron.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <sys/mman.h> +#include <pci/pci.h> +#include "flash.h" +#include "spi.h" + +typedef struct _spi_controller { + unsigned int spi_cntrl0; /* 00h */ + unsigned int restrictedcmd1; /* 04h */ + unsigned int restrictedcmd2; /* 08h */ + unsigned int spi_cntrl1; /* 0ch */ + unsigned int spi_cmdvalue0; /* 10h */ + unsigned int spi_cmdvalue1; /* 14h */ + unsigned int spi_cmdvalue2; /* 18h */ + unsigned int spi_fakeid; /* 1Ch */ +} sb600_spi_controller; + +sb600_spi_controller *spi_bar = NULL; +uint8_t volatile *sb600_spibar; + +int sb600_spi_read(struct flashchip *flash, uint8_t *buf) +{ + int rc = 0, i; + int total_size = flash->total_size * 1024; + int page_size = 8; + + for (i = 0; i < total_size / page_size; i++) + spi_nbyte_read(i * page_size, (void *)(buf + i * page_size), + page_size); + return rc; +} + +uint8_t sb600_read_status_register(void) +{ + const unsigned char cmd[0x02] = { JEDEC_RDSR, 0x00 }; + unsigned char readarr[JEDEC_RDSR_INSIZE]; + + /* Read Status Register */ + spi_command(sizeof(cmd), sizeof(readarr), cmd, readarr); + return readarr[0]; +} + +int sb600_spi_write(struct flashchip *flash, uint8_t *buf) +{ + int rc = 0, i; + int total_size = flash->total_size * 1024; + + /* Erase first */ + printf("Erasing flash before programming... "); + flash->erase(flash); + printf("done.\n"); + + printf("Programming flash"); + for (i = 0; i < total_size; i++, buf++) { + spi_disable_blockprotect(); + spi_write_enable(); + spi_byte_program(i, *buf); + /* wait program complete. */ + if (i % 0x8000 == 0) + printf("."); + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + ; + } + printf(" done.\n"); + return rc; +} + +void reset_internal_fifo_pointer(void) +{ + sb600_spibar[2] |= 0x10; + + while (sb600_spibar[0xD] & 0x7) + printf("reset\n"); +} + +void execute_command(void) +{ + sb600_spibar[2] |= 1; + + while (sb600_spibar[2] & 1) + ; +} + +int sb600_spi_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + int count; + /* First byte is cmd which can not being sent through FIFO. */ + unsigned char cmd = *writearr++; + + writecnt--; + + spi_bar = (sb600_spi_controller *) sb600_spibar; + + printf_debug("%s, cmd=%x, writecnt=%x, readcnt=%x\n", + __func__, cmd, writecnt, readcnt); + + if (readcnt > 8) { + printf("%s, SB600 SPI controller can not receive %d bytes, " + "which is limited with 8 bytes\n", __func__, readcnt); + return 1; + } + + if (writecnt > 8) { + printf("%s, SB600 SPI controller can not sent %d bytes, " + "which is limited with 8 bytes\n", __func__, writecnt); + return 1; + } + + sb600_spibar[0] = cmd; + sb600_spibar[1] = readcnt << 4 | (writecnt); + + /* Before we use the FIFO, reset it first. */ + reset_internal_fifo_pointer(); + + /* Send the write byte to FIFO. */ + for (count = 0; count < writecnt; count++, writearr++) { + printf_debug(" [%x]", *writearr); + sb600_spibar[0xC] = *writearr; + } + printf_debug("\n"); + + /* + * We should send the data by sequence, which means we need to reset + * the FIFO pointer to the first byte we want to send. + */ + reset_internal_fifo_pointer(); + + execute_command(); + + /* + * After the command executed, we should find out the index of the + * received byte. Here we just reset the FIFO pointer, skip the + * writecnt, is there anyone who have anther method to replace it? + */ + reset_internal_fifo_pointer(); + + for (count = 0; count < writecnt; count++) { + cmd = sb600_spibar[0xC]; /* Skip the byte we send. */ + printf_debug("[ %2x]", cmd); + } + + printf_debug("The FIFO pointer 6 is %d.\n", sb600_spibar[0xd] & 0x07); + for (count = 0; count < readcnt; count++, readarr++) { + *readarr = sb600_spibar[0xC]; + printf_debug("[%02x]", *readarr); + } + printf_debug("\n"); + + return 0; +}
Modified: trunk/util/flashrom/spi.c =================================================================== --- trunk/util/flashrom/spi.c 2008-11-28 12:09:17 UTC (rev 3778) +++ trunk/util/flashrom/spi.c 2008-11-28 21:36:51 UTC (rev 3779) @@ -42,6 +42,8 @@ case BUS_TYPE_ICH9_SPI: case BUS_TYPE_VIA_SPI: return ich_spi_command(writecnt, readcnt, writearr, readarr); + case BUS_TYPE_SB600_SPI: + return sb600_spi_command(writecnt, readcnt, writearr, readarr); default: printf_debug ("%s called, but no SPI chipset/strapping detected\n", @@ -157,6 +159,7 @@ case BUS_TYPE_ICH7_SPI: case BUS_TYPE_ICH9_SPI: case BUS_TYPE_VIA_SPI: + case BUS_TYPE_SB600_SPI: return probe_spi_rdid_generic(flash, 4); default: printf_debug("4b ID not supported on this SPI controller\n"); @@ -229,7 +232,13 @@ unsigned char readarr[JEDEC_RDSR_INSIZE];
/* Read Status Register */ - spi_command(sizeof(cmd), sizeof(readarr), cmd, readarr); + if (flashbus == BUS_TYPE_SB600_SPI) { + /* SB600 uses a different way to read status register. */ + return sb600_read_status_register(); + } else { + spi_command(sizeof(cmd), sizeof(readarr), cmd, readarr); + } + return readarr[0]; }
@@ -464,6 +473,14 @@ return 0; }
+int spi_write_status_enable() +{ + const unsigned char cmd[JEDEC_EWSR_OUTSIZE] = { JEDEC_EWSR }; + + /* Send EWSR (Enable Write Status Register). */ + return spi_command(JEDEC_EWSR_OUTSIZE, JEDEC_EWSR_INSIZE, cmd, NULL); +} + /* * This is according the SST25VF016 datasheet, who knows it is more * generic that this... @@ -500,9 +517,9 @@ /* If there is block protection in effect, unprotect it first. */ if ((status & 0x3c) != 0) { printf_debug("Some block protection in effect, disabling\n"); - result = spi_write_enable(); + result = spi_write_status_enable(); if (result) { - printf_debug("spi_write_enable failed\n"); + printf_debug("spi_write_status_enable failed\n"); return result; } result = spi_write_status_register(status & ~0x3c); @@ -532,6 +549,8 @@ switch (flashbus) { case BUS_TYPE_IT87XX_SPI: return it8716f_spi_chip_read(flash, buf); + case BUS_TYPE_SB600_SPI: + return sb600_spi_read(flash, buf); case BUS_TYPE_ICH7_SPI: case BUS_TYPE_ICH9_SPI: case BUS_TYPE_VIA_SPI: @@ -550,6 +569,8 @@ switch (flashbus) { case BUS_TYPE_IT87XX_SPI: return it8716f_spi_chip_write(flash, buf); + case BUS_TYPE_SB600_SPI: + return sb600_spi_write(flash, buf); case BUS_TYPE_ICH7_SPI: case BUS_TYPE_ICH9_SPI: case BUS_TYPE_VIA_SPI:
Modified: trunk/util/flashrom/spi.h =================================================================== --- trunk/util/flashrom/spi.h 2008-11-28 12:09:17 UTC (rev 3778) +++ trunk/util/flashrom/spi.h 2008-11-28 21:36:51 UTC (rev 3779) @@ -80,6 +80,11 @@ #define JEDEC_RDSR_INSIZE 0x01 #define JEDEC_RDSR_BIT_WIP (0x01 << 0)
+/* Write Status Enable */ +#define JEDEC_EWSR 0x50 +#define JEDEC_EWSR_OUTSIZE 0x01 +#define JEDEC_EWSR_INSIZE 0x00 + /* Write Status Register */ #define JEDEC_WRSR 0x01 #define JEDEC_WRSR_OUTSIZE 0x02