I've been extremely busy with preparing for the US Air Force, which I leave for Basic on November 2nd.
But... Fintek SPI Flashrom Driver: * based off of it87spi.c * untested * should be good for F71882 and F71889
Signed-off-by: Sean Nelson audiohacked@gmail.com
Auf 19.09.2010 06:14, Sean Nelson schrieb:
Fintek SPI Flashrom Driver:
- based off of it87spi.c
- untested
- should be good for F71882 and F71889
Signed-off-by: Sean Nelson audiohacked@gmail.com
Updated against latest svn, still untested. Testers welcome!
This needs to be cleaned up before being merged, but if anyone has that hardware, he/she now has a chance to test with current svn.
Regards, Carl-Daniel
Index: flashrom-snelson_fintek_spi/Makefile =================================================================== --- flashrom-snelson_fintek_spi/Makefile (Revision 1280) +++ flashrom-snelson_fintek_spi/Makefile (Arbeitskopie) @@ -219,7 +219,7 @@ FEATURE_CFLAGS += -D'CONFIG_INTERNAL=1' PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o dmi.o internal.o # FIXME: The PROGRAMMER_OBJS below should only be included on x86. -PROGRAMMER_OBJS += it87spi.o it85spi.o ichspi.o sb600spi.o wbsio_spi.o mcp6x_spi.o +PROGRAMMER_OBJS += it87spi.o it85spi.o ichspi.o sb600spi.o wbsio_spi.o mcp6x_spi.o fintek_spi.o NEED_PCI := yes endif
Index: flashrom-snelson_fintek_spi/spi.c =================================================================== --- flashrom-snelson_fintek_spi/spi.c (Revision 1280) +++ flashrom-snelson_fintek_spi/spi.c (Arbeitskopie) @@ -42,6 +42,13 @@
#if CONFIG_INTERNAL == 1 #if defined(__i386__) || defined(__x86_64__) + { /* SPI_CONTROLLER_FINTEK */ + .command = fintek_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = fintek_spi_chip_read, + .write_256 = fintek_spi_chip_write_256, + }, + { /* SPI_CONTROLLER_ICH7 */ .command = ich_spi_send_command, .multicommand = ich_spi_send_multicommand, Index: flashrom-snelson_fintek_spi/programmer.h =================================================================== --- flashrom-snelson_fintek_spi/programmer.h (Revision 1280) +++ flashrom-snelson_fintek_spi/programmer.h (Arbeitskopie) @@ -276,6 +276,7 @@ extern struct superio superio; #define SUPERIO_VENDOR_NONE 0x0 #define SUPERIO_VENDOR_ITE 0x1 +#define SUPERIO_VENDOR_FINTEK 0x2 struct pci_dev *pci_dev_find_filter(struct pci_filter filter); struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t class); struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device); @@ -518,6 +519,7 @@ SPI_CONTROLLER_NONE, #if CONFIG_INTERNAL == 1 #if defined(__i386__) || defined(__x86_64__) + SPI_CONTROLLER_FINTEK, SPI_CONTROLLER_ICH7, SPI_CONTROLLER_ICH9, SPI_CONTROLLER_IT85XX, @@ -568,6 +570,19 @@ const unsigned char *writearr, unsigned char *readarr); int default_spi_send_multicommand(struct spi_command *cmds);
+/* fintek_spi.c */ +#if CONFIG_INTERNAL == 1 +void enter_conf_mode_fintek(uint16_t port); +void exit_conf_mode_fintek(uint16_t port); +struct superio probe_superio_fintek(void); +int init_superio_fintek(void); +int fintek_spi_init(void); +int fintek_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int fintek_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int fintek_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len); +#endif + /* ichspi.c */ #if CONFIG_INTERNAL == 1 extern uint32_t ichspi_bbar; Index: flashrom-snelson_fintek_spi/fintek_spi.c =================================================================== --- flashrom-snelson_fintek_spi/fintek_spi.c (Revision 0) +++ flashrom-snelson_fintek_spi/fintek_spi.c (Revision 0) @@ -0,0 +1,438 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2010 Sean Nelson audiohacked@gmail.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; version 2 of the License. + * + * 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 + */ + +/* + * Contains the Fintek F7188x SPI specific routines + * + * The Fintek SPI is different from the it87xxx SIO in that there's no + * base address to help program through SPI, but in the F7188x SIOs the + * SPI Interface is accessed through LDN 0x8 and configuration registers + * 0xf0 - 0xf8 and 0xfa - 0xff. + */ + +#if defined(__i386__) || defined(__x86_64__) + +#include <string.h> +#include <stdlib.h> +#include "flash.h" +#include "chipdrivers.h" +#include "programmer.h" +#include "spi.h" + +#define FINTEK_SUPERIO_PORT1 0x2e +#define FINTEK_SUPERIO_PORT2 0x4e + +/* Logical Device Number for the SPI Device in Fintek SIO */ +#define SPI_LDN 0x08 + +/* the Configuration Register for ROM address masking + * Bit 7 is the ROM Write Enable. + * Bit 0 which enables address range 0xfff00000 - 0xfff7ffff + * The rest of the bits are 'power on trapped' + * via pull-up/down sio pin connections. + */ +#define FINTEK_SIO_ROM_ADDR_SELECT 0x27 + +/* Configuration Registers of the SPI Device */ +#define SPI_CTRL 0xf0 +#define SPI_CTRL_SPTIE (1 << 5) +#define SPI_CTRL_CPOL (1 << 3) +#define SPI_CTRL_CPHA (1 << 2) +#define SPI_CTRL_LSBFE (1 << 0) + +#define SPI_TIMEOUT 0xf1 +#define SPI_BAUD 0xf2 +#define SPI_BAUD_33 (0 << 0) +#define SPI_BAUD_16 (1 << 0) + +#define SPI_STATUS 0xf3 +#define SPI_STATUS_SPIE (1 << 7) +#define SPI_STATUS_SPE (1 << 5) +#define SPI_STATUS_SPTEF (1 << 3) + +#define SPI_H_DATA 0xf4 +#define SPI_CMD_DATA 0xf5 +#define SPI_CS 0xf6 +#define SPI_CS_CS0 (1 << 0) +#define SPI_CS_CS1 (1 << 1) +#define SPI_CS_CS2 (1 << 2) +#define SPI_CS_CS3 (1 << 3) + +#define SPI_MMAP 0xf7 +#define SPI_MMAP_512 0x00 +#define SPI_MMAP_1024 0x01 +#define SPI_MMAP_2048 0x02 +#define SPI_MMAP_4096 0x03 +#define SPI_MMAP_8092 0x04 + +#define SPI_OP 0xf8 +#define SPI_OP_TYPE (1 << 7) +#define SPI_OP_IO_SPI (1 << 6) +#define SPI_OP_RDSR (1 << 5) +#define SPI_OP_WRSR (1 << 4) +#define SPI_OP_ERASE (1 << 3) +#define SPI_OP_RDID (1 << 2) +#define SPI_OP_PROG (1 << 1) +#define SPI_OP_READ (1 << 0) + +#define SPI_L_DATA 0xfa +#define SPI_H_ADDR 0xfb +#define SPI_M_ADDR 0xfc +#define SPI_L_ADDR 0xfd +#define SPI_PROG 0xfe +#define SPI_WR_DATA 0xff + +uint16_t fintek_flashport = 0; +/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */ +static int fast_spi = 1; + +/* Helper functions for Fintek F7188x Super I/O chips */ +#define CHIP_ID_BYTE1_REG 0x20 +#define CHIP_ID_BYTE2_REG 0x21 +void enter_conf_mode_fintek(uint16_t port) +{ + OUTB(0x87, port); + OUTB(0x87, port); +} + +void exit_conf_mode_fintek(uint16_t port) +{ + OUTB(0xaa, port); +} + +uint16_t probe_id_fintek(uint16_t port) +{ + uint16_t id; + + enter_conf_mode_fintek(port); + id = sio_read(port, CHIP_ID_BYTE1_REG) << 8; + id |= sio_read(port, CHIP_ID_BYTE2_REG); + exit_conf_mode_fintek(port); + + return id; +} + +struct superio probe_superio_fintek(void) +{ + struct superio ret = {}; + uint16_t fintek_ports[] = {FINTEK_SUPERIO_PORT1, FINTEK_SUPERIO_PORT2, 0}; + uint16_t *i = fintek_ports; + + ret.vendor = SUPERIO_VENDOR_FINTEK; + for (; *i; i++) { + ret.port = *i; + ret.model = probe_id_fintek(ret.port); + switch (ret.model >> 8) { + case 0x0541: /* f71882 */ + case 0x0723: /* f71889 */ + msg_pinfo("Found Fintek Super I/O, ID 0x%04hx.\n", + ret.model); + return ret; + } + } + + /* No good ID found. */ + ret.vendor = SUPERIO_VENDOR_NONE; + ret.port = 0; + ret.model = 0; + return ret; +} + +static uint16_t fintek_spi_probe(struct superio fintek) +{ + uint8_t tmp = 0; + + enter_conf_mode_fintek(fintek.port); + /* NOLDN, reg 0x27, mask out lowest bit (suspend) */ + tmp = sio_read(fintek.port, 0x27); + /* If Fintek was not explicitly selected, we want to check + * quickly if LPC->SPI translation is active. + */ + + if (fintek.model == 0x0541) { + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis"); + msg_pdbg("LPC write to serial flash %sabled\n", + (tmp & 1 << 4) ? "en" : "dis"); + } + /* The LPC->SPI force write enable below only makes sense for + * non-programmer mode. + */ + /* If any serial flash segment is enabled, enable writing. */ + if ((tmp & 0xe) && (!(tmp & 1 << 4))) { + msg_pdbg("Enabling LPC write to serial flash\n"); + tmp |= 1 << 4; + sio_write(fintek.port, 0x27, tmp); + } + msg_pdbg("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29); + + sio_write(fintek.port, 0x07, 0x8); + if (fintek.model == 0x0541) { + /* disable FWH */ + tmp = sio_read(fintek.port, SPI_STATUS); + tmp |= (1<<6); + sio_write(fintek.port, SPI_STATUS, tmp); + + /* set max decode size: 8092k bytes */ + sio_write(fintek.port, SPI_MMAP, 0x4); + } + + exit_conf_mode_fintek(fintek.port); + fintek_flashport = fintek.port; + if (buses_supported & CHIP_BUSTYPE_SPI) + msg_pdbg("Overriding chipset SPI with Fintek SPI.\n"); + spi_controller = SPI_CONTROLLER_FINTEK; + buses_supported |= CHIP_BUSTYPE_SPI; + return 0; +} + +int init_superio_fintek(void) +{ + if (superio.vendor != SUPERIO_VENDOR_FINTEK) + return 1; + + switch (superio.model) { + case 0x8718: + case 0x8720: + return fintek_spi_probe(superio); + break; + default: + msg_pdbg("Super I/O ID 0x%04hx is not on the list of flash " + "capable controllers.\n", superio.model); + } + return 1; +} + + +int fintek_spi_init(void) +{ + int ret; + + get_io_perms(); + /* Probe for the Super I/O chip and fill global struct superio. */ + probe_superio(); + ret = init_superio_fintek(); + if (!ret) { + buses_supported = CHIP_BUSTYPE_SPI; + } else { + buses_supported = CHIP_BUSTYPE_NONE; + } + return ret; +} + +/* + * The IT8716F only supports commands with length 1,2,4,5 bytes including + * command byte and can not read more than 3 bytes from the device. + * + * This function expects writearr[0] to be the first byte sent to the device, + * whereas the IT8716F splits commands internally into address and non-address + * commands with the address in inverse wire order. That's why the register + * ordering in case 4 and 5 may seem strange. + */ +int fintek_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + uint8_t busy, operate; + + enter_conf_mode_fintek(fintek_flashport); + sio_write(fintek_flashport, 0x07, 0x8); + /* + * wait to make sure the SPI isn't doing anything, + * before we do our thing + */ + do { + busy = sio_read(fintek_flashport, SPI_STATUS) & 0x03; + } while (busy); + + if (readcnt > 2) { + msg_pinfo("%s called with unsupported readcnt %i.\n", + __func__, readcnt); + return SPI_INVALID_LENGTH; + } + + switch (writecnt) { + case 1: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + break; + case 2: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + sio_write(fintek_flashport, SPI_WR_DATA, writearr[1]); + break; + case 4: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + sio_write(fintek_flashport, SPI_H_ADDR, writearr[1]); + sio_write(fintek_flashport, SPI_M_ADDR, writearr[2]); + sio_write(fintek_flashport, SPI_L_ADDR, writearr[3]); + break; + case 5: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + sio_write(fintek_flashport, SPI_H_ADDR, writearr[1]); + sio_write(fintek_flashport, SPI_M_ADDR, writearr[2]); + sio_write(fintek_flashport, SPI_L_ADDR, writearr[3]); + sio_write(fintek_flashport, SPI_WR_DATA, writearr[4]); + break; + default: + msg_pinfo("%s called with unsupported writecnt %i.\n", + __func__, writecnt); + return SPI_INVALID_LENGTH; + } + /* + * Start IO, 33 or 16 MHz, readcnt input bytes, writecnt output bytes. + * Note: + * We can't use writecnt directly, but have to use a strange encoding. + */ + operate = sio_read(fintek_flashport, SPI_BAUD); + operate |= ((fast_spi ? 0 : 1) << 0); + sio_write(fintek_flashport, SPI_BAUD, operate); + + /* + * The Fintek F7188x SuperIOs use a SPI operate Register at Index 0xf8 to + * set off the execution of various SPI functions + */ + operate = sio_read(fintek_flashport, SPI_OP); + sio_write(fintek_flashport, SPI_OP, operate|(1 << 7)); + + switch(writearr[0]) + { + case JEDEC_RDSR: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 5)); + break; + case JEDEC_WRSR: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 4)); + break; + case JEDEC_SE: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 3)); + break; + case JEDEC_RDID: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 2)); + break; + case JEDEC_BYTE_PROGRAM: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 1)); + break; + case JEDEC_READ: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 0)); + break; + default: /* IO_SPI */ + sio_write(fintek_flashport, SPI_OP, operate|(1 << 6)); + } + + if (readcnt > 0) { + do { + busy = sio_read(fintek_flashport, SPI_STATUS) & 0x03; + } while (busy); + + /* save the low byte from SPI first */ + readarr[0] = sio_read(fintek_flashport, SPI_L_DATA); + /* next save the high byte from SPI */ + readarr[1] = sio_read(fintek_flashport, SPI_H_DATA); + } + sio_write(fintek_flashport, SPI_OP, 0); + exit_conf_mode_fintek(fintek_flashport); + + return 0; +} + +/* Page size is usually 256 bytes */ +static int fintek_spi_page_program(struct flashchip *flash, uint8_t *buf, int start) +{ + int i; + int result; + //uint8_t tmp; + chipaddr bios = flash->virtual_memory; + + enter_conf_mode_fintek(fintek_flashport); + sio_write(fintek_flashport, 0x07, 0x8); + + result = spi_write_enable(); + if (result) + return result; + /* FIXME: The command below seems to be redundant or wrong. */ + sio_write(fintek_flashport, SPI_CMD_DATA, 0x06); + + sio_write(fintek_flashport, SPI_BAUD, ((fast_spi ? 0 : 1) << 0) ); + for (i = 0; i < 256; i++) { + chip_writeb(buf[i], bios + start + i); + } + sio_write(fintek_flashport, SPI_OP, 0); + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 1-10 ms, so wait in 1 ms steps. + */ + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(1000); + + exit_conf_mode_fintek(fintek_flashport); + return 0; +} + +int fintek_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + int total_size = 1024 * flash->total_size; + fast_spi = 0; + + /* FIXME: Allow force-activating Fintek SPI even if flash translation is not active? */ + if ((total_size > 8 * 1024 * 1024)) { + spi_read_chunked(flash, buf, start, len, 2); + } else { + read_memmapped(flash, buf, start, len); + } + + return 0; +} + +int fintek_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + /* FIXME: Allow force-activating Fintek SPI even if flash translation is not active? */ + if ((flash->total_size * 1024 > 8 * 1024 * 1024)) { + spi_chip_write_1(flash, buf, start, len); + } else { + int lenhere; + + if (start % 256) { + /* start to the end of the page or start + len, + * whichever is smaller. Page length is hardcoded to + * 256 bytes (IT87 SPI hardware limitation). + */ + lenhere = min(len, (start | 0xff) - start + 1); + spi_chip_write_1(flash, buf, start, lenhere); + start += lenhere; + len -= lenhere; + buf += lenhere; + } + + /* FIXME: Handle chips which have max writechunk size >1 and <256. */ + while (len >= 256) { + fintek_spi_page_program(flash, buf, start); + start += 256; + len -= 256; + buf += 256; + } + if (len) + spi_chip_write_1(flash, buf, start, len); + } + + return 0; +} + +#endif
Am 10.03.2011 01:49 schrieb Carl-Daniel Hailfinger:
Auf 19.09.2010 06:14, Sean Nelson schrieb:
Fintek SPI Flashrom Driver:
- based off of it87spi.c
- untested
- should be good for F71882 and F71889
Signed-off-by: Sean Nelson audiohacked@gmail.com
The driver had lots of ITE IT87* related code which should have been removed. I adapted the code to the current superio interfaces, but in the process I disabled all flashing completely. Right now I mostly want to check if detection works or not.
This code should be safe to run. Please supply the log of flashrom -V
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-snelson_fintek_spi/Makefile =================================================================== --- flashrom-snelson_fintek_spi/Makefile (Revision 1455) +++ flashrom-snelson_fintek_spi/Makefile (Arbeitskopie) @@ -350,7 +350,7 @@ PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o dmi.o internal.o ifeq ($(ARCH),"x86") PROGRAMMER_OBJS += it87spi.o it85spi.o sb600spi.o wbsio_spi.o mcp6x_spi.o -PROGRAMMER_OBJS += ichspi.o ich_descriptors.o +PROGRAMMER_OBJS += ichspi.o ich_descriptors.o fintek_spi.o else endif NEED_PCI := yes Index: flashrom-snelson_fintek_spi/internal.c =================================================================== --- flashrom-snelson_fintek_spi/internal.c (Revision 1455) +++ flashrom-snelson_fintek_spi/internal.c (Arbeitskopie) @@ -102,10 +102,10 @@ void probe_superio(void) { probe_superio_ite(); + probe_superio_fintek(); #if 0 /* Winbond Super I/O code is not yet available. */ - if (superio.vendor == SUPERIO_VENDOR_NONE) - superio = probe_superio_winbond(); + probe_superio_winbond(); #endif }
@@ -278,6 +278,7 @@ * IT87* Parallel write enable. */ init_superio_ite(); + init_superio_fintek(); #endif
board_flash_enable(lb_vendor, lb_part); Index: flashrom-snelson_fintek_spi/programmer.h =================================================================== --- flashrom-snelson_fintek_spi/programmer.h (Revision 1455) +++ flashrom-snelson_fintek_spi/programmer.h (Arbeitskopie) @@ -287,6 +287,7 @@ extern int superio_count; #define SUPERIO_VENDOR_NONE 0x0 #define SUPERIO_VENDOR_ITE 0x1 +#define SUPERIO_VENDOR_FINTEK 0x3 #endif #if NEED_PCI == 1 struct pci_dev *pci_dev_find_filter(struct pci_filter filter); @@ -518,6 +519,7 @@ SPI_CONTROLLER_NONE, #if CONFIG_INTERNAL == 1 #if defined(__i386__) || defined(__x86_64__) + SPI_CONTROLLER_FINTEK, SPI_CONTROLLER_ICH7, SPI_CONTROLLER_ICH9, SPI_CONTROLLER_IT85XX, @@ -575,6 +577,19 @@ int default_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len); void register_spi_programmer(const struct spi_programmer *programmer);
+/* fintek_spi.c */ +#if CONFIG_INTERNAL == 1 +void enter_conf_mode_fintek(uint16_t port); +void exit_conf_mode_fintek(uint16_t port); +void probe_superio_fintek(void); +int init_superio_fintek(void); +int fintek_spi_init(void); +int fintek_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int fintek_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int fintek_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len); +#endif + /* ichspi.c */ #if CONFIG_INTERNAL == 1 extern uint32_t ichspi_bbar; Index: flashrom-snelson_fintek_spi/fintek_spi.c =================================================================== --- flashrom-snelson_fintek_spi/fintek_spi.c (Revision 0) +++ flashrom-snelson_fintek_spi/fintek_spi.c (Revision 0) @@ -0,0 +1,455 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2010 Sean Nelson audiohacked@gmail.com + * Copyright (C) 2011 Carl-Daniel Hailfinger + * + * 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; version 2 of the License. + * + * 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 + */ + +/* + * Contains the Fintek F7188x SPI specific routines + * + * The Fintek SPI is different from the it87xxx SIO in that there's no + * base address to help program through SPI, but in the F7188x SIOs the + * SPI Interface is accessed through LDN 0x8 and configuration registers + * 0xf0 - 0xf8 and 0xfa - 0xff. + */ + +#if defined(__i386__) || defined(__x86_64__) + +#include <string.h> +#include <stdlib.h> +#include "flash.h" +#include "chipdrivers.h" +#include "programmer.h" +#include "spi.h" + +#define FINTEK_SUPERIO_PORT1 0x2e +#define FINTEK_SUPERIO_PORT2 0x4e + +/* Logical Device Number for the SPI Device in Fintek SIO */ +#define SPI_LDN 0x08 + +/* the Configuration Register for ROM address masking + * Bit 7 is the ROM Write Enable. + * Bit 0 which enables address range 0xfff00000 - 0xfff7ffff + * The rest of the bits are 'power on trapped' + * via pull-up/down sio pin connections. + */ +#define FINTEK_SIO_ROM_ADDR_SELECT 0x27 + +/* Configuration Registers of the SPI Device */ +#define SPI_CTRL 0xf0 +#define SPI_CTRL_SPTIE (1 << 5) +#define SPI_CTRL_CPOL (1 << 3) +#define SPI_CTRL_CPHA (1 << 2) +#define SPI_CTRL_LSBFE (1 << 0) + +#define SPI_TIMEOUT 0xf1 +#define SPI_BAUD 0xf2 +#define SPI_BAUD_33 (0 << 0) +#define SPI_BAUD_16 (1 << 0) + +#define SPI_STATUS 0xf3 +#define SPI_STATUS_SPIE (1 << 7) +#define SPI_STATUS_SPE (1 << 5) +#define SPI_STATUS_SPTEF (1 << 3) + +#define SPI_H_DATA 0xf4 +#define SPI_CMD_DATA 0xf5 +#define SPI_CS 0xf6 +#define SPI_CS_CS0 (1 << 0) +#define SPI_CS_CS1 (1 << 1) +#define SPI_CS_CS2 (1 << 2) +#define SPI_CS_CS3 (1 << 3) + +#define SPI_MMAP 0xf7 +#define SPI_MMAP_512 0x00 +#define SPI_MMAP_1024 0x01 +#define SPI_MMAP_2048 0x02 +#define SPI_MMAP_4096 0x03 +#define SPI_MMAP_8092 0x04 + +#define SPI_OP 0xf8 +#define SPI_OP_TYPE (1 << 7) +#define SPI_OP_IO_SPI (1 << 6) +#define SPI_OP_RDSR (1 << 5) +#define SPI_OP_WRSR (1 << 4) +#define SPI_OP_ERASE (1 << 3) +#define SPI_OP_RDID (1 << 2) +#define SPI_OP_PROG (1 << 1) +#define SPI_OP_READ (1 << 0) + +#define SPI_L_DATA 0xfa +#define SPI_H_ADDR 0xfb +#define SPI_M_ADDR 0xfc +#define SPI_L_ADDR 0xfd +#define SPI_PROG 0xfe +#define SPI_WR_DATA 0xff + +uint16_t fintek_flashport = 0; +/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */ +//static int fast_spi = 1; + +/* Helper functions for Fintek F7188x Super I/O chips */ +#define DEVICE_ID_BYTE1_REG 0x20 +#define DEVICE_ID_BYTE2_REG 0x21 + +#define VENDOR_ID_BYTE1_REG 0x23 +#define VENDOR_ID_BYTE2_REG 0x24 + +#define FINTEK_VENDOR_ID 0x3419 + +void enter_conf_mode_fintek_ite_8787(uint16_t port) +{ + OUTB(0x87, port); + OUTB(0x87, port); +} + +void exit_conf_mode_winbond_fintek_ite_8787(uint16_t port) +{ + OUTB(0xaa, port); +} + +uint16_t probe_vid_fintek(uint16_t port) +{ + uint16_t id; + + enter_conf_mode_fintek_ite_8787(port); + id = sio_read(port, VENDOR_ID_BYTE1_REG); + id |= (sio_read(port, VENDOR_ID_BYTE2_REG) << 8); + exit_conf_mode_winbond_fintek_ite_8787(port); + return id; +} + +uint16_t probe_id_fintek(uint16_t port) +{ + uint16_t id; + + enter_conf_mode_fintek_ite_8787(port); + id = sio_read(port, DEVICE_ID_BYTE1_REG); + id |= (sio_read(port, DEVICE_ID_BYTE2_REG) << 8); + exit_conf_mode_winbond_fintek_ite_8787(port); + return id; +} + +void probe_superio_fintek(void) +{ + struct superio s = {}; + uint16_t fintek_ports[] = {FINTEK_SUPERIO_PORT1, FINTEK_SUPERIO_PORT2, 0}; + uint16_t *i = fintek_ports; + + s.vendor = SUPERIO_VENDOR_FINTEK; + for (; *i; i++) { + s.port = *i; + if (probe_vid_fintek(s.port) != FINTEK_VENDOR_ID) + continue; + s.model = probe_id_fintek(s.port); + switch (s.model >> 8) { + case 0x2307: /* f71889 */ + case 0x4105: /* F71882FG/F71883FG */ + msg_pinfo("Found Fintek Super I/O, ID 0x%04hx.\n", + s.model); + register_superio(s); + break; + } + } + + return; +} + +static uint16_t fintek_spi_probe(uint16_t port) +{ +#if 0 + uint8_t tmp = 0; + + enter_conf_mode_fintek_ite_8787(port); + /* NOLDN, reg 0x27, mask out lowest bit (suspend) */ + tmp = sio_read(port, 0x27); + /* Check if LPC->SPI translation is active. + */ + + if (fintek.model == 0x0541) { + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFFE0000, 0xFFFFFFFF, (tmp & 1 << 1) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0x000E0000, 0x000FFFFF, (tmp & 1 << 1) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 2) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFF80000, 0xFFFEFFFF, (tmp & 1 << 3) ? "en" : "dis"); + msg_pdbg("LPC write to serial flash %sabled\n", + (tmp & 1 << 4) ? "en" : "dis"); + } + /* FIXME: Really? If any serial flash segment is enabled, enable writing. */ + if ((tmp & 0xe) && (!(tmp & 1 << 4))) { + msg_pdbg("Enabling LPC write to serial flash\n"); + tmp |= 1 << 4; + sio_write(port, 0x27, tmp); + } + msg_pdbg("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29); + + sio_write(port, 0x07, 0x8); + if (model == 0x0541) { + /* disable FWH */ + tmp = sio_read(port, SPI_STATUS); + tmp |= (1<<6); + sio_write(port, SPI_STATUS, tmp); + + /* set max decode size: 8092k bytes */ + sio_write(port, SPI_MMAP, 0x4); + } + + exit_conf_mode_winbond_fintek_ite_8787(port); + fintek_flashport = port; + if (buses_supported & CHIP_BUSTYPE_SPI) + msg_pdbg("Overriding chipset SPI with Fintek SPI.\n"); + spi_controller = SPI_CONTROLLER_FINTEK; + buses_supported |= CHIP_BUSTYPE_SPI; +#endif + return 0; +} + +#if 0 +static const struct spi_programmer spi_programmer_fintek = { + .type = SPI_CONTROLLER_FINTEK, + .max_data_read = MAX_DATA_UNSPECIFIED, + .max_data_write = MAX_DATA_UNSPECIFIED, + .command = fintek_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = fintek_spi_chip_read, + .write_256 = fintek_spi_chip_write_256, +}; +#endif + +int init_superio_fintek(void) +{ + int i; + int ret = 0; + + for (i = 0; i < superio_count; i++) { + if (superios[i].vendor != SUPERIO_VENDOR_FINTEK) + continue; + + switch (superios[i].model) { + case 0x0541: /* f71882 */ + case 0x0723: /* f71889 */ + ret |= fintek_spi_probe(superios[i].port); + break; + default: + msg_pdbg("Super I/O ID 0x%04hx is not on the list of " + "flash capable controllers.\n", + superios[i].model); + } + } + return ret; +} + +#if 0 +/* + * The IT8716F only supports commands with length 1,2,4,5 bytes including + * command byte and can not read more than 3 bytes from the device. + * + * This function expects writearr[0] to be the first byte sent to the device, + * whereas the IT8716F splits commands internally into address and non-address + * commands with the address in inverse wire order. That's why the register + * ordering in case 4 and 5 may seem strange. + */ +int fintek_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + uint8_t busy, operate; + + enter_conf_mode_fintek_ite_8787(fintek_flashport); + sio_write(fintek_flashport, 0x07, 0x8); + /* + * wait to make sure the SPI isn't doing anything, + * before we do our thing + */ + do { + busy = sio_read(fintek_flashport, SPI_STATUS) & 0x03; + } while (busy); + + if (readcnt > 2) { + msg_pinfo("%s called with unsupported readcnt %i.\n", + __func__, readcnt); + return SPI_INVALID_LENGTH; + } + + switch (writecnt) { + case 1: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + break; + case 2: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + sio_write(fintek_flashport, SPI_WR_DATA, writearr[1]); + break; + case 4: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + sio_write(fintek_flashport, SPI_H_ADDR, writearr[1]); + sio_write(fintek_flashport, SPI_M_ADDR, writearr[2]); + sio_write(fintek_flashport, SPI_L_ADDR, writearr[3]); + break; + case 5: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + sio_write(fintek_flashport, SPI_H_ADDR, writearr[1]); + sio_write(fintek_flashport, SPI_M_ADDR, writearr[2]); + sio_write(fintek_flashport, SPI_L_ADDR, writearr[3]); + sio_write(fintek_flashport, SPI_WR_DATA, writearr[4]); + break; + default: + msg_pinfo("%s called with unsupported writecnt %i.\n", + __func__, writecnt); + return SPI_INVALID_LENGTH; + } + /* + * Start IO, 33 or 16 MHz, readcnt input bytes, writecnt output bytes. + * Note: + * We can't use writecnt directly, but have to use a strange encoding. + */ + operate = sio_read(fintek_flashport, SPI_BAUD); + operate |= ((fast_spi ? 0 : 1) << 0); + sio_write(fintek_flashport, SPI_BAUD, operate); + + /* + * The Fintek F7188x SuperIOs use a SPI operate Register at Index 0xf8 to + * set off the execution of various SPI functions + */ + operate = sio_read(fintek_flashport, SPI_OP); + sio_write(fintek_flashport, SPI_OP, operate|(1 << 7)); + + switch(writearr[0]) + { + case JEDEC_RDSR: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 5)); + break; + case JEDEC_WRSR: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 4)); + break; + case JEDEC_SE: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 3)); + break; + case JEDEC_RDID: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 2)); + break; + case JEDEC_BYTE_PROGRAM: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 1)); + break; + case JEDEC_READ: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 0)); + break; + default: /* IO_SPI */ + sio_write(fintek_flashport, SPI_OP, operate|(1 << 6)); + } + + if (readcnt > 0) { + do { + busy = sio_read(fintek_flashport, SPI_STATUS) & 0x03; + } while (busy); + + /* save the low byte from SPI first */ + readarr[0] = sio_read(fintek_flashport, SPI_L_DATA); + /* next save the high byte from SPI */ + readarr[1] = sio_read(fintek_flashport, SPI_H_DATA); + } + sio_write(fintek_flashport, SPI_OP, 0); + exit_conf_mode_winbond_fintek_ite_8787(fintek_flashport); + + return 0; +} + +/* Page size is usually 256 bytes */ +static int fintek_spi_page_program(struct flashchip *flash, uint8_t *buf, int start) +{ + int i; + int result; + //uint8_t tmp; + chipaddr bios = flash->virtual_memory; + + enter_conf_mode_fintek_ite_8787(fintek_flashport); + sio_write(fintek_flashport, 0x07, 0x8); + + result = spi_write_enable(); + if (result) + return result; + /* FIXME: The command below seems to be redundant or wrong. */ + sio_write(fintek_flashport, SPI_CMD_DATA, 0x06); + + sio_write(fintek_flashport, SPI_BAUD, ((fast_spi ? 0 : 1) << 0) ); + for (i = 0; i < 256; i++) { + chip_writeb(buf[i], bios + start + i); + } + sio_write(fintek_flashport, SPI_OP, 0); + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 1-10 ms, so wait in 1 ms steps. + */ + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(1000); + + exit_conf_mode_winbond_fintek_ite_8787(fintek_flashport); + return 0; +} + +int fintek_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + int total_size = 1024 * flash->total_size; + fast_spi = 0; + + /* FIXME: Allow force-activating Fintek SPI even if flash translation is not active? */ + if ((total_size > 8 * 1024 * 1024)) { + spi_read_chunked(flash, buf, start, len, 2); + } else { + read_memmapped(flash, buf, start, len); + } + + return 0; +} + +int fintek_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + /* FIXME: Allow force-activating Fintek SPI even if flash translation is not active? */ + if ((flash->total_size * 1024 > 8 * 1024 * 1024)) { + spi_chip_write_1(flash, buf, start, len); + } else { + int lenhere; + + if (start % 256) { + /* start to the end of the page or start + len, + * whichever is smaller. Page length is hardcoded to + * 256 bytes (IT87 SPI hardware limitation). + */ + lenhere = min(len, (start | 0xff) - start + 1); + spi_chip_write_1(flash, buf, start, lenhere); + start += lenhere; + len -= lenhere; + buf += lenhere; + } + + /* FIXME: Handle chips which have max writechunk size >1 and <256. */ + while (len >= 256) { + fintek_spi_page_program(flash, buf, start); + start += 256; + len -= 256; + buf += 256; + } + if (len) + spi_chip_write_1(flash, buf, start, len); + } + + return 0; +} +#endif + +#endif
Am 22.10.2011 19:02 schrieb Carl-Daniel Hailfinger:
Am 10.03.2011 01:49 schrieb Carl-Daniel Hailfinger:
Auf 19.09.2010 06:14, Sean Nelson schrieb:
Fintek SPI Flashrom Driver:
- based off of it87spi.c
- untested
- should be good for F71882 and F71889
Signed-off-by: Sean Nelson audiohacked@gmail.com
The driver had lots of ITE IT87* related code which should have been removed. I adapted the code to the current superio interfaces, but in the process I disabled all flashing completely. Right now I mostly want to check if detection works or not.
This code should be safe to run. Please supply the log of flashrom -V
Next round. This one should print more info, and only one SuperI/O is supported. No flash access at all will happen.
Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Index: flashrom-snelson_fintek_spi/Makefile =================================================================== --- flashrom-snelson_fintek_spi/Makefile (Revision 1455) +++ flashrom-snelson_fintek_spi/Makefile (Arbeitskopie) @@ -350,7 +350,7 @@ PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o dmi.o internal.o ifeq ($(ARCH),"x86") PROGRAMMER_OBJS += it87spi.o it85spi.o sb600spi.o wbsio_spi.o mcp6x_spi.o -PROGRAMMER_OBJS += ichspi.o ich_descriptors.o +PROGRAMMER_OBJS += ichspi.o ich_descriptors.o fintek_spi.o else endif NEED_PCI := yes Index: flashrom-snelson_fintek_spi/internal.c =================================================================== --- flashrom-snelson_fintek_spi/internal.c (Revision 1455) +++ flashrom-snelson_fintek_spi/internal.c (Arbeitskopie) @@ -102,10 +102,10 @@ void probe_superio(void) { probe_superio_ite(); + probe_superio_fintek(); #if 0 /* Winbond Super I/O code is not yet available. */ - if (superio.vendor == SUPERIO_VENDOR_NONE) - superio = probe_superio_winbond(); + probe_superio_winbond(); #endif }
@@ -278,6 +278,7 @@ * IT87* Parallel write enable. */ init_superio_ite(); + init_superio_fintek(); #endif
board_flash_enable(lb_vendor, lb_part); Index: flashrom-snelson_fintek_spi/programmer.h =================================================================== --- flashrom-snelson_fintek_spi/programmer.h (Revision 1455) +++ flashrom-snelson_fintek_spi/programmer.h (Arbeitskopie) @@ -287,6 +287,7 @@ extern int superio_count; #define SUPERIO_VENDOR_NONE 0x0 #define SUPERIO_VENDOR_ITE 0x1 +#define SUPERIO_VENDOR_FINTEK 0x3 #endif #if NEED_PCI == 1 struct pci_dev *pci_dev_find_filter(struct pci_filter filter); @@ -518,6 +519,7 @@ SPI_CONTROLLER_NONE, #if CONFIG_INTERNAL == 1 #if defined(__i386__) || defined(__x86_64__) + SPI_CONTROLLER_FINTEK, SPI_CONTROLLER_ICH7, SPI_CONTROLLER_ICH9, SPI_CONTROLLER_IT85XX, @@ -575,6 +577,19 @@ int default_spi_write_256(struct flashchip *flash, uint8_t *buf, int start, int len); void register_spi_programmer(const struct spi_programmer *programmer);
+/* fintek_spi.c */ +#if CONFIG_INTERNAL == 1 +void enter_conf_mode_fintek(uint16_t port); +void exit_conf_mode_fintek(uint16_t port); +void probe_superio_fintek(void); +int init_superio_fintek(void); +int fintek_spi_init(void); +int fintek_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr); +int fintek_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len); +int fintek_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len); +#endif + /* ichspi.c */ #if CONFIG_INTERNAL == 1 extern uint32_t ichspi_bbar; Index: flashrom-snelson_fintek_spi/fintek_spi.c =================================================================== --- flashrom-snelson_fintek_spi/fintek_spi.c (Revision 0) +++ flashrom-snelson_fintek_spi/fintek_spi.c (Revision 0) @@ -0,0 +1,460 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2010 Sean Nelson audiohacked@gmail.com + * Copyright (C) 2011 Carl-Daniel Hailfinger + * + * 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; version 2 of the License. + * + * 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 + */ + +/* + * Contains the Fintek F7188x SPI specific routines + * + * The Fintek SPI is different from the it87xxx SIO in that there's no + * base address to help program through SPI, but in the F7188x SIOs the + * SPI Interface is accessed through LDN 0x8 and configuration registers + * 0xf0 - 0xf8 and 0xfa - 0xff. + */ + +#if defined(__i386__) || defined(__x86_64__) + +#include <string.h> +#include <stdlib.h> +#include "flash.h" +#include "chipdrivers.h" +#include "programmer.h" +#include "spi.h" + +#define FINTEK_SUPERIO_PORT1 0x2e +#define FINTEK_SUPERIO_PORT2 0x4e + +/* Logical Device Number for the SPI Device in Fintek SIO */ +#define SPI_LDN 0x08 + +/* the Configuration Register for ROM address masking + * Bit 7 is the ROM Write Enable. + * Bit 0 which enables address range 0xfff00000 - 0xfff7ffff + * The rest of the bits are 'power on trapped' + * via pull-up/down sio pin connections. + */ +#define FINTEK_SIO_ROM_ADDR_SELECT 0x27 + +/* Configuration Registers of the SPI Device */ +#define SPI_CTRL 0xf0 +#define SPI_CTRL_SPTIE (1 << 5) +#define SPI_CTRL_CPOL (1 << 3) +#define SPI_CTRL_CPHA (1 << 2) +#define SPI_CTRL_LSBFE (1 << 0) + +#define SPI_TIMEOUT 0xf1 +#define SPI_BAUD 0xf2 +#define SPI_BAUD_33 (0 << 0) +#define SPI_BAUD_16 (1 << 0) + +#define SPI_STATUS 0xf3 +#define SPI_STATUS_SPIE (1 << 7) +#define SPI_STATUS_SPE (1 << 5) +#define SPI_STATUS_SPTEF (1 << 3) + +#define SPI_H_DATA 0xf4 +#define SPI_CMD_DATA 0xf5 +#define SPI_CS 0xf6 +#define SPI_CS_CS0 (1 << 0) +#define SPI_CS_CS1 (1 << 1) +#define SPI_CS_CS2 (1 << 2) +#define SPI_CS_CS3 (1 << 3) + +#define SPI_MMAP 0xf7 +#define SPI_MMAP_512 0x00 +#define SPI_MMAP_1024 0x01 +#define SPI_MMAP_2048 0x02 +#define SPI_MMAP_4096 0x03 +#define SPI_MMAP_8092 0x04 + +#define SPI_OP 0xf8 +#define SPI_OP_TYPE (1 << 7) +#define SPI_OP_IO_SPI (1 << 6) +#define SPI_OP_RDSR (1 << 5) +#define SPI_OP_WRSR (1 << 4) +#define SPI_OP_ERASE (1 << 3) +#define SPI_OP_RDID (1 << 2) +#define SPI_OP_PROG (1 << 1) +#define SPI_OP_READ (1 << 0) + +#define SPI_L_DATA 0xfa +#define SPI_H_ADDR 0xfb +#define SPI_M_ADDR 0xfc +#define SPI_L_ADDR 0xfd +#define SPI_PROG 0xfe +#define SPI_WR_DATA 0xff + +uint16_t fintek_flashport = 0; +/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */ +//static int fast_spi = 1; + +/* Helper functions for Fintek F7188x Super I/O chips */ +#define DEVICE_ID_BYTE1_REG 0x20 +#define DEVICE_ID_BYTE2_REG 0x21 + +#define VENDOR_ID_BYTE1_REG 0x23 +#define VENDOR_ID_BYTE2_REG 0x24 + +#define FINTEK_VENDOR_ID 0x3419 + +void enter_conf_mode_fintek_ite_8787(uint16_t port) +{ + OUTB(0x87, port); + OUTB(0x87, port); +} + +void exit_conf_mode_winbond_fintek_ite_8787(uint16_t port) +{ + OUTB(0xaa, port); +} + +uint16_t probe_vid_fintek(uint16_t port) +{ + uint16_t id; + + enter_conf_mode_fintek_ite_8787(port); + id = sio_read(port, VENDOR_ID_BYTE1_REG); + id |= (sio_read(port, VENDOR_ID_BYTE2_REG) << 8); + exit_conf_mode_winbond_fintek_ite_8787(port); + return id; +} + +uint16_t probe_id_fintek(uint16_t port) +{ + uint16_t id; + + enter_conf_mode_fintek_ite_8787(port); + id = sio_read(port, DEVICE_ID_BYTE1_REG); + id |= (sio_read(port, DEVICE_ID_BYTE2_REG) << 8); + exit_conf_mode_winbond_fintek_ite_8787(port); + return id; +} + +void probe_superio_fintek(void) +{ + struct superio s = {}; + uint16_t fintek_ports[] = {FINTEK_SUPERIO_PORT1, FINTEK_SUPERIO_PORT2, 0}; + uint16_t *i = fintek_ports; + + s.vendor = SUPERIO_VENDOR_FINTEK; + for (; *i; i++) { + s.port = *i; + if (probe_vid_fintek(s.port) != FINTEK_VENDOR_ID) + continue; + s.model = probe_id_fintek(s.port); + switch (s.model) { + case 0x2307: /* f71889 */ + case 0x4105: /* F71882FG/F71883FG */ + msg_pinfo("Found Fintek Super I/O, ID 0x%04hx.\n", + s.model); + register_superio(s); + break; + } + } + + return; +} + +static uint16_t fintek_spi_probe(uint16_t port) +{ + uint8_t tmp = 0; + + enter_conf_mode_fintek_ite_8787(port); + /* NOLDN, reg 0x27 */ + tmp = sio_read(port, 0x27); + /* Check if LPC->SPI translation is active. */ + msg_pdbg("F71882 LPC to serial flash translation %sabled\n", + (tmp & 1 << 6) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFF00000, 0xFFF7FFFF, (tmp & 1 << 0) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFEE0000, 0xFFEFFFFF, (tmp & 1 << 1) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0x000F0000, 0x000FFFFF, (tmp & 1 << 2) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0xFFF80000, 0xFFFFFFFF, (tmp & 1 << 2) ? "en" : "dis"); + msg_pdbg("Serial flash segment 0x%08x-0x%08x %sabled\n", + 0x000E0000, 0x000EFFFF, (tmp & 1 << 3) ? "en" : "dis"); + msg_pdbg("LPC write to serial flash %sabled\n", + (tmp & 1 << 7) ? "en" : "dis"); + + /* NOLDN, reg 0x27 */ + tmp = sio_read(port, 0x2D); + msg_pdbg("SPI_CS_EN is %i\n", (tmp >> 7) & 1); + exit_conf_mode_winbond_fintek_ite_8787(port); +#if 0 + + /* FIXME: Really? If any serial flash segment is enabled, enable writing. */ + if ((tmp & 0xe) && (!(tmp & 1 << 4))) { + msg_pdbg("Enabling LPC write to serial flash\n"); + tmp |= 1 << 4; + sio_write(port, 0x27, tmp); + } + msg_pdbg("Serial flash pin %i\n", (tmp & 1 << 5) ? 87 : 29); + + sio_write(port, 0x07, 0x8); + if (model == 0x0541) { + /* disable FWH */ + tmp = sio_read(port, SPI_STATUS); + tmp |= (1<<6); + sio_write(port, SPI_STATUS, tmp); + + /* set max decode size: 8092k bytes */ + sio_write(port, SPI_MMAP, 0x4); + } + + fintek_flashport = port; + if (buses_supported & CHIP_BUSTYPE_SPI) + msg_pdbg("Overriding chipset SPI with Fintek SPI.\n"); + spi_controller = SPI_CONTROLLER_FINTEK; + buses_supported |= CHIP_BUSTYPE_SPI; +#endif + return 0; +} + +#if 0 +static const struct spi_programmer spi_programmer_fintek = { + .type = SPI_CONTROLLER_FINTEK, + .max_data_read = MAX_DATA_UNSPECIFIED, + .max_data_write = MAX_DATA_UNSPECIFIED, + .command = fintek_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = fintek_spi_chip_read, + .write_256 = fintek_spi_chip_write_256, +}; +#endif + +int init_superio_fintek(void) +{ + int i; + int ret = 0; + + for (i = 0; i < superio_count; i++) { + if (superios[i].vendor != SUPERIO_VENDOR_FINTEK) + continue; + + switch (superios[i].model) { + case 0x4105: /* F71882FG/F71883FG */ + //case 0x2307: /* f71889 */ + ret |= fintek_spi_probe(superios[i].port); + break; + default: + msg_pdbg("Super I/O ID 0x%04hx is not on the list of " + "flash capable controllers.\n", + superios[i].model); + } + } + return ret; +} + +#if 0 +/* + * The IT8716F only supports commands with length 1,2,4,5 bytes including + * command byte and can not read more than 3 bytes from the device. + * + * This function expects writearr[0] to be the first byte sent to the device, + * whereas the IT8716F splits commands internally into address and non-address + * commands with the address in inverse wire order. That's why the register + * ordering in case 4 and 5 may seem strange. + */ +int fintek_spi_send_command(unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + uint8_t busy, operate; + + enter_conf_mode_fintek_ite_8787(fintek_flashport); + sio_write(fintek_flashport, 0x07, 0x8); + /* + * wait to make sure the SPI isn't doing anything, + * before we do our thing + */ + do { + busy = sio_read(fintek_flashport, SPI_STATUS) & 0x03; + } while (busy); + + if (readcnt > 2) { + msg_pinfo("%s called with unsupported readcnt %i.\n", + __func__, readcnt); + return SPI_INVALID_LENGTH; + } + + switch (writecnt) { + case 1: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + break; + case 2: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + sio_write(fintek_flashport, SPI_WR_DATA, writearr[1]); + break; + case 4: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + sio_write(fintek_flashport, SPI_H_ADDR, writearr[1]); + sio_write(fintek_flashport, SPI_M_ADDR, writearr[2]); + sio_write(fintek_flashport, SPI_L_ADDR, writearr[3]); + break; + case 5: + sio_write(fintek_flashport, SPI_CMD_DATA, writearr[0]); + sio_write(fintek_flashport, SPI_H_ADDR, writearr[1]); + sio_write(fintek_flashport, SPI_M_ADDR, writearr[2]); + sio_write(fintek_flashport, SPI_L_ADDR, writearr[3]); + sio_write(fintek_flashport, SPI_WR_DATA, writearr[4]); + break; + default: + msg_pinfo("%s called with unsupported writecnt %i.\n", + __func__, writecnt); + return SPI_INVALID_LENGTH; + } + /* + * Start IO, 33 or 16 MHz, readcnt input bytes, writecnt output bytes. + * Note: + * We can't use writecnt directly, but have to use a strange encoding. + */ + operate = sio_read(fintek_flashport, SPI_BAUD); + operate |= ((fast_spi ? 0 : 1) << 0); + sio_write(fintek_flashport, SPI_BAUD, operate); + + /* + * The Fintek F7188x SuperIOs use a SPI operate Register at Index 0xf8 to + * set off the execution of various SPI functions + */ + operate = sio_read(fintek_flashport, SPI_OP); + sio_write(fintek_flashport, SPI_OP, operate|(1 << 7)); + + switch(writearr[0]) + { + case JEDEC_RDSR: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 5)); + break; + case JEDEC_WRSR: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 4)); + break; + case JEDEC_SE: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 3)); + break; + case JEDEC_RDID: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 2)); + break; + case JEDEC_BYTE_PROGRAM: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 1)); + break; + case JEDEC_READ: + sio_write(fintek_flashport, SPI_OP, operate|(1 << 0)); + break; + default: /* IO_SPI */ + sio_write(fintek_flashport, SPI_OP, operate|(1 << 6)); + } + + if (readcnt > 0) { + do { + busy = sio_read(fintek_flashport, SPI_STATUS) & 0x03; + } while (busy); + + /* save the low byte from SPI first */ + readarr[0] = sio_read(fintek_flashport, SPI_L_DATA); + /* next save the high byte from SPI */ + readarr[1] = sio_read(fintek_flashport, SPI_H_DATA); + } + sio_write(fintek_flashport, SPI_OP, 0); + exit_conf_mode_winbond_fintek_ite_8787(fintek_flashport); + + return 0; +} + +/* Page size is usually 256 bytes */ +static int fintek_spi_page_program(struct flashchip *flash, uint8_t *buf, int start) +{ + int i; + int result; + //uint8_t tmp; + chipaddr bios = flash->virtual_memory; + + enter_conf_mode_fintek_ite_8787(fintek_flashport); + sio_write(fintek_flashport, 0x07, 0x8); + + result = spi_write_enable(); + if (result) + return result; + /* FIXME: The command below seems to be redundant or wrong. */ + sio_write(fintek_flashport, SPI_CMD_DATA, 0x06); + + sio_write(fintek_flashport, SPI_BAUD, ((fast_spi ? 0 : 1) << 0) ); + for (i = 0; i < 256; i++) { + chip_writeb(buf[i], bios + start + i); + } + sio_write(fintek_flashport, SPI_OP, 0); + /* Wait until the Write-In-Progress bit is cleared. + * This usually takes 1-10 ms, so wait in 1 ms steps. + */ + while (spi_read_status_register() & JEDEC_RDSR_BIT_WIP) + programmer_delay(1000); + + exit_conf_mode_winbond_fintek_ite_8787(fintek_flashport); + return 0; +} + +int fintek_spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + int total_size = 1024 * flash->total_size; + fast_spi = 0; + + /* FIXME: Allow force-activating Fintek SPI even if flash translation is not active? */ + if ((total_size > 8 * 1024 * 1024)) { + spi_read_chunked(flash, buf, start, len, 2); + } else { + read_memmapped(flash, buf, start, len); + } + + return 0; +} + +int fintek_spi_chip_write_256(struct flashchip *flash, uint8_t *buf, int start, int len) +{ + /* FIXME: Allow force-activating Fintek SPI even if flash translation is not active? */ + if ((flash->total_size * 1024 > 8 * 1024 * 1024)) { + spi_chip_write_1(flash, buf, start, len); + } else { + int lenhere; + + if (start % 256) { + /* start to the end of the page or start + len, + * whichever is smaller. Page length is hardcoded to + * 256 bytes (IT87 SPI hardware limitation). + */ + lenhere = min(len, (start | 0xff) - start + 1); + spi_chip_write_1(flash, buf, start, lenhere); + start += lenhere; + len -= lenhere; + buf += lenhere; + } + + /* FIXME: Handle chips which have max writechunk size >1 and <256. */ + while (len >= 256) { + fintek_spi_page_program(flash, buf, start); + start += 256; + len -= 256; + buf += 256; + } + if (len) + spi_chip_write_1(flash, buf, start, len); + } + + return 0; +} +#endif + +#endif