[coreboot] Add support for SPI-Chips on ICH9 to flash rom
Carl-Daniel Hailfinger
c-d.hailfinger.devel.2006 at gmx.net
Fri May 9 15:35:38 CEST 2008
Hi Claus,
On 09.05.2008 15:02, Claus Gindhart wrote:
> This patch adds support for the SPI Chips Atmel AT25DF32,
> ST M25P80, ST M25P16, M25P32, ST M25P64 attached to the ICH9.
> Because chipset plays an important role in communicating with these
> chips, it was not possible to integrate this support into the already
> existing spi.c
> This module was tested with the devices as mentioned above, but
> it should be easy to expand it for other SPI chips attached to an ICH.
>
> Signed-off-by: Claus Gindhart <claus.gindhart at kontron.com>
>
Thank you very much for your contribution! I'll review the code in the
next few days. There are a few merging errors in ichspi.c which make
compilation impossible. I have highlighted them below. Could you resend
the patch with those merging errors fixed?
I can see what you mean with the problems of integrating your code into
spi.c. The redesign I have in mind fixes that.
Regards,
Carl-Daniel
> Index: ichspi.c
> ===================================================================
> --- ichspi.c (revision 0)
> +++ ichspi.c (revision 0)
> @@ -0,0 +1,665 @@
> +/*
> + * This file is part of the flashrom project.
> + *
> + * Initially implemented by Stefan Wildemann <stefan.wildemann at kontron.com>
> + * Adapted to flashrom by Claus Gindhart <claus.gindhart at 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
> + *
> + */
> +
> +/*
> + * This module is designed for supporting the devices
> + * ST M25P40
> + * ST M25P80
> + * ST M25P16
> + * ST M25P32
> + * ST M25P64
> + * AT 25DF321
> + *
> + */
> +
> +#define DEVELOPPERS_DEBUG
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdint.h>
> +#include <sys/mman.h>
> +#include <pci/pci.h>
> +#include "flash.h"
> +
> +/* Includes from the testsw_ng module */
> +#include "ichspiacc.h"
> +
> +/* HW access functions */
> +
> +/* Current flash descriptor, to avoid passing it as argument everywhere */
> +static struct flashchip *curflash;
> +static OPCODES *curopcodes;
> +
> +static inline uint8_t REGREAD8(int X)
> +{
> + volatile uint8_t regval;
> + regval = *(volatile uint8_t *)(curflash->virtual_registers + X);
> + return regval;
> +}
> +
> +static inline uint16_t REGREAD16(int X)
> +{
> + volatile uint16_t regval;
> + regval = *(volatile uint16_t *)(curflash->virtual_registers + X);
> + return regval;
> +}
> +
> +static inline uint32_t REGREAD32(int X)
> +{
> + volatile uint32_t regval;
> + regval = *(volatile uint32_t *)(curflash->virtual_registers + X);
> + return regval;
> +}
> +
> +#define REGWRITE32(X,Y) (*(uint32_t *)(curflash->virtual_registers+X)=Y)
> +#define REGWRITE16(X,Y) (*(uint16_t *)(curflash->virtual_registers+X)=Y)
> +#define REGWRITE8(X,Y) (*(uint8_t *)(curflash->virtual_registers+X)=Y)
> +
> +/* Common SPI functions */
> +static int ProgramOpcodes(OPCODES * op);
> +static int RunOpcode(uint8_t nr, OPCODE op, uint32_t offset, uint8_t datalength,
> + uint8_t * data);
> +static int read_page_ichspi(struct flashchip *flash, uint8_t * buf, int Offset);
> +static int is_supported_chipset();
> +
> +OPCODES O_ST_M25P = {
> + {
> + SPI_ST_M25P_COMMAND_WRITE_ENABLE,
> + 0
> + },
> + {
> + {SPI_ST_M25P_COMMAND_WRITE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte
> + {SPI_ST_M25P_COMMAND_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
> + {SPI_ST_M25P_COMMAND_ERASE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase 4k Sector
> + {SPI_ST_M25P_COMMAND_READ_STATUS, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
> + {SPI_ST_M25P_COMMAND_RES_PD, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Resume Deep Power-Down
> + {SPI_ST_M25P_COMMAND_WRITE_S, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register
> + {SPI_ST_M25P_COMMAND_JDEC, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
> + {SPI_ST_M25P_COMMAND_BULK_ERASE, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase
> + }
> +};
> +
> +OPCODES O_AT_25DF = {
> + {
> + SPI_ST_M25P_COMMAND_WRITE_ENABLE,
> + 0
> + },
> + {
> + {SPI_ST_M25P_COMMAND_WRITE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Write Byte
> + {SPI_ST_M25P_COMMAND_READ, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Read Data
> + {SPI_ST_M25P_COMMAND_ERASE, SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS, 1}, // Erase Sector
> + {SPI_ST_M25P_COMMAND_READ_STATUS, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read Device Status Reg
> + {SPI_ST_M25P_COMMAND_RES_PD, SPI_OPCODE_TYPE_READ_WITH_ADDRESS, 0}, // Resume Deep Power-Down
> + {SPI_ST_M25P_COMMAND_WRITE_S, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Write Status Register
> + {SPI_ST_M25P_COMMAND_JDEC, SPI_OPCODE_TYPE_READ_NO_ADDRESS, 0}, // Read JDEC ID
> + {SPI_ST_M25P_COMMAND_BULK_ERASE, SPI_OPCODE_TYPE_WRITE_NO_ADDRESS, 1}, // Bulk erase
> + }
> +};
> +
> +int ProgramOpcodes(OPCODES * op)
> +{
> + uint8_t a;
> +#ifdef DEVELOPPERS_DEBUG
> + printf_debug("ProgramOpcodes:");
> +#endif
> +
> + uint16_t temp16;
> + uint32_t temp32;
> +
> + /* Program Prefix Opcodes */
> + temp16 = 0;
> + /* 0:7 Prefix Opcode 1 */
> + temp16 = (op->preop[0]);
> + /* 8:16 Prefix Opcode 2 */
> + temp16 |= ((uint16_t) op->preop[1]) << 8;
> + REGWRITE16(REG_PREOP, temp16);
> +#ifdef DEVELOPPERS_DEBUG
> + printf("REG_PREOP == 0x%04X (0x%04X)\n", REGREAD16(REG_PREOP), temp16);
> +#endif
> +
> + /*Program Opcode Types 0 - 7 */
> + temp16 = 0;
> + for (a = 0; a < 8; a++) {
> + temp16 |= ((uint16_t) op->opcode[a].spi_type) << (a * 2);
> + }
> + REGWRITE16(REG_OPTYPE, temp16);
> +#ifdef DEVELOPPERS_DEBUG
> + printf("REG_OPTYPE = 0x%04X (0x%04X)\n", REGREAD16(REG_OPTYPE), temp16);
> +#endif
> +
> + /*Program Allowable Opcodes 0 - 3 */
> + temp32 = 0;
> + for (a = 0; a < 4; a++) {
> + temp32 |= ((uint32_t) op->opcode[a].opcode) << (a * 8);
> + }
> + REGWRITE32(REG_OPMENU, temp32);
> +
> + /*Program Allowable Opcodes 4 - 7 */
> + temp32 = 0;
> + for (a = 4; a < 8; a++) {
> + temp32 |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
> + }
> + REGWRITE32(REG_OPMENU + 4, temp32);
> +
> +#ifdef DEVELOPPERS_DEBUG
> + printf("REG_OPMENU = 0x%08X%08X\n", REGREAD32(REG_OPMENU + 4),
> + REGREAD32(REG_OPMENU));
> +
> + printf("ProgramOpcodes end\n");
> +#endif
> +
> + return 0;
> +}
> +
> +int RunOpcode(uint8_t nr, OPCODE op, uint32_t offset, uint8_t datalength,
> + uint8_t * data)
> +{
> +#ifdef DEVELOPPERS_DEBUG
> + printf_debug("RunOpcode::");
> +#endif
> + int write_cmd = 0;
> + uint32_t temp32;
> + uint32_t a;
> +
> + /* Is it a write command? */
> + if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
> + || (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
> + write_cmd = 1;
> + printf_debug("Write command detected!");
> + }
> +
> + /* Programm Offset in Flash into FADDR */
> + REGWRITE32(REG_FADDR, (offset & 0x00FFFFFF)); /*SPI addresses are 24 BIT only */
> + printf_debug("REG_FADDR == 0x%08X (0x%08X)", REGREAD32(REG_FADDR),
> + offset);
> +
> + /* Program data into FDATA0 to N */
> + if (write_cmd && (datalength != 0)) {
> + printf_debug("Going to write data bytes to FDATA0");
> + temp32 = 0;
> + for (a = 0; a < datalength; a++) {
> + if ((a % 4) == 0) {
> + temp32 = 0;
> + }
> +
> + temp32 |= ((uint32_t) data[a]) << ((a % 4) * 8);
> +
> + if ((a % 4) == 3) {
> + REGWRITE32(REG_FDATA0 + (a - (a % 4)), temp32);
> + printf_debug("REG_FDATA0 + 0x%X) == 0x%08X",
> + a - (a % 4),
> + REGREAD32(REG_FDATA0 +
> + (a - (a % 4))));
> + }
> + }
> + if (((a - 1) % 4) != 3) {
> + printf_debug("writing rest");
> + REGWRITE32(REG_FDATA0 + ((a - 1) - ((a - 1) % 4)),
> + temp32);
> + printf_debug("REG_FDATA0 + 0x%X) == 0x%08X",
> + (a - 1) - ((a - 1) % 4),
> + REGREAD32(REG_FDATA0 +
> + ((a - 1) - ((a - 1) % 4))));
> +
> + }
> +
> + }
> +
> + /* Assemble SSFS + SSFC */
> + temp32 = 0;
> +
> + /* clear error status registers */
> + temp32 |= (SSFS_CDS + SSFS_FCERR);
> + /* USE 20 MhZ */
> + temp32 |= SSFC_SCF_20MHZ;
> +
> + if (datalength != 0) {
> + uint32_t datatemp;
> + temp32 |= SSFC_DS;
> + datatemp = ((uint32_t) ((datalength - 1) & 0x3f)) << (8 + 8);
> + //printf_debug("datatemp = 0x%08X", datatemp);
> + temp32 |= datatemp;
> + }
> +
> + /* Select opcode */
> + temp32 |= ((uint32_t) (nr & 0x07)) << (8 + 4);
> +
> + /* Handle Atomic */
> + if (op.atomic != 0) {
> + printf_debug("Atomic operation detected");
> + /* Select atomic command */
> + temp32 |= SSFC_ACS;
> + /* Selct prefix opcode */
> + if ((op.atomic - 1) == 1) {
> + /*Select prefix opcode 2 */
> + temp32 |= SSFC_SPOP;
> + }
> + }
> +
> + /* Start */
> + temp32 |= SSFC_SCGO;
> +
> + /* write it */
> + //printf_debug("going to write 0x%08X to REG_SSFS", temp32);
> + REGWRITE32(REG_SSFS, temp32);
> +
> + /*wait for cycle complete */
> + while ((REGREAD32(REG_SSFS) & SSFS_CDS) == 0) {
> + /*TODO; Do something that this can't lead into an endless loop. but some
> + * commands may cause this to be last more than 30 seconds */
> + }
> +
> + //printf_debug("REG_SSFS == 0x%08X", REGREAD32(REG_SSFS));
> + if ((REGREAD32(REG_SSFS) & SSFS_FCERR) != 0) {
> + printf_debug("Transaction error!");
> + return 1;
> + }
> +
> + if ((!write_cmd) && (datalength != 0)) {
> + printf_debug("Going to read data from FDATA0");
> + for (a = 0; a < datalength; a++) {
> + if ((a % 4) == 0) {
> + temp32 = REGREAD32(REG_FDATA0 + (a));
> + printf_debug("REG_FDATA0 + 0x%X == 0x%08X", (a),
> + REGREAD32(REG_FDATA0 + (a)));
> + }
> +
> + data[a] =
> + (temp32 & (((uint32_t) 0xff) << ((a % 4) * 8))) >>
> + ((a % 4) * 8);
> + }
> + }
> +
> + return 0;
> +}
> +
> +static volatile uint8_t *mmap_base = 0;
> +
> +int map_ich_registers(struct flashchip *flash)
> +{
> + int offset_from_page = (RCRB + SPIBAR) % 0x1000;
> + int base_of_page = (RCRB + SPIBAR) & ~0xFFF;
> +
> + mmap_base = mmap(0, 0x1000, PROT_WRITE | PROT_READ, MAP_SHARED,
> + fd_mem, (off_t) base_of_page);
> +
> + if (mmap_base == MAP_FAILED) {
> + perror("Can't mmap registers using " MEM_DEV);
> + return -1;
> + }
> + flash->virtual_registers = mmap_base + offset_from_page;
> +
> + return 0;
> +}
> +
> +void munmap_ich_registers(void)
> +{
> + if (mmap_base) {
> + munmap((void *)mmap_base, 0x1000);
> + mmap_base = 0;
> + }
> +}
> +
> +
> +/* check for ICH8/9 chipset */
> +static int is_supported_chipset()
> +{
> + struct pci_dev *temp;
> + struct pci_filter filter;
> + uint8_t tmpid;
> +
> + pci_filter_init(NULL, &filter);
> + filter.vendor = 0x8086; /* Vendor Intel */
> +
> + for (temp = pacc->devices; temp; temp = temp->next) {
> + if (pci_filter_match(&filter, temp)) {
> + tmpid = (temp->device_id & 0xff00) >> 8; /* upper byte of device-id */
> +
> + /* return success if ICH8/9 found */
> + if ((tmpid == 0x28) || (tmpid == 0x29))
> + return 1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/* ST-chips with deprecated 'Electronic Signature' and no JEDEC id support */
> +/* untested */
> +int probe_ichspi_stm25_sig(struct flashchip *flash)
> +{
> + uint8_t byte[65];
> +
> + curflash = flash;
> + curopcodes = &O_ST_M25P;
> +
> + if (!is_supported_chipset())
> + return 0;
> +
> + if (map_ich_registers(flash)) {
> + perror("Error mapping ICH registers\n");
> + return 0;
> + }
> +
> + ProgramOpcodes(curopcodes);
> +
> + /* resume from Deep Power-Down mode and read Electronic Signature (4) */
> + if (RunOpcode(4, curopcodes->opcode[4], 0x00000000, 1, byte) != 0) {
> + perror("RunOpcode");
> + munmap_ich_registers();
> + return 0;
> + }
> +
> + printf_debug("ReadID Result %02x", byte[0]);
> +
> + /* FIXME: use defines for the signatures */
> + if (!
> + ((byte[0] == 0x12) || (byte[0] == 0x13) || (byte[0] == 0x14)
> + || (byte[0] == 0x15) || (byte[0] == 0x16))) {
> + munmap_ich_registers();
> + return 0;
> + }
> +
> + printf_debug("Chip detected, Electronic Signature 0x%02x\n", byte[0]);
> +
> + return 1;
> +}
> +
> +/* untested */
> +int probe_ichspi_stm25(struct flashchip *flash)
> +{
> + uint8_t byte[65];
> + uint32_t largeid1;
> +
> + curflash = flash;
> + curopcodes = &O_ST_M25P;
> +
> + if (!is_supported_chipset())
> + return 0;
> +
> + if (map_ich_registers(flash)) {
> + perror("Error mapping ICH registers\n");
> + return 0;
> + }
> +
> + /* initialize controller with opcodes */
> + ProgramOpcodes(curopcodes);
> +
> + /* resume from Deep Power-Down mode (4) */
> + if (RunOpcode(4, curopcodes->opcode[4], 0x00000000, 0, byte) != 0) {
> + perror("RunOpcode");
> + munmap_ich_registers();
> + return 0;
> + }
> +
> + /* do a read JEDEC id (6) */
> + if (RunOpcode(6, curopcodes->opcode[6], 0x00000000, 3, byte) != 0) {
> + perror("RunOpcode");
> + munmap_ich_registers();
> + return 0;
> + }
> +<<<<<<< ichspi.c
The line above indicates a merging error.
> +
> + printf("ReadID Result %02x %02x %02x %02x\n",byte[0],byte[1],byte[2],byte[3]);
> +
> + if(!((byte[0] == 0x13) || (byte[0] == 0x14) || (byte[0] == 0x15) || (byte[0] == 0x16)))
> + {
> +=======
The line above indicates a merging error.
> +#ifdef DEVELOPPERS_DEBUG
> + printf_debug("JEDEC-ID Result %02x %02x %02x\n", byte[0], byte[1],
> + byte[2]);
> +#endif
> +
> + if (byte[0] != flash->manufacture_id) {
> + munmap_ich_registers();
> + return 0;
> + }
> +
> + largeid1 = (byte[1] << 8) | byte[2];
> +
> + if (largeid1 != flash->model_id) {
> +>>>>>>> 1.7
The line above indicates a merging error.
> + munmap_ich_registers();
> + return 0;
> + }
> +
> +<<<<<<< ichspi.c
> +=======
The 2 lines above indicates a merging error.
> + printf_debug("Chip detected, Jedec ID 0x%x\n", largeid1);
> +
> + return 1;
> +}
> +
> +int probe_ichspi_at25df(struct flashchip *flash)
> +{
> + uint8_t byte[65];
> + uint32_t largeid1;
> +
> + curflash = flash;
> + curopcodes = &O_AT_25DF;
> +
> + if (!is_supported_chipset())
> + return 0;
> +
> + if (map_ich_registers(flash)) {
> + perror("Error mapping ICH registers\n");
> + return 0;
> + }
> +
> + /* initialize controller with opcodes */
> + ProgramOpcodes(curopcodes);
> +
> + /* resume from Deep Power-Down mode (4) */
> + if (RunOpcode(4, curopcodes->opcode[4], 0x00000000, 0, byte) != 0) {
> + perror("RunOpcode");
> + munmap_ich_registers();
> + return 0;
> + }
> +>>>>>>> 1.7
The line above indicates a merging error.
> +
> + /* do a read JEDEC id (6) */
> + if (RunOpcode(6, curopcodes->opcode[6], 0x00000000, 3, byte) != 0) {
> + perror("RunOpcode");
> + munmap_ich_registers();
> + return 0;
> + }
> +#ifdef DEVELOPPERS_DEBUG
> + printf_debug("JEDEC-ID Result %02x %02x %02x\n", byte[0], byte[1],
> + byte[2]);
> +#endif
> +
> + if (byte[0] != flash->manufacture_id) {
> + munmap_ich_registers();
> + return 0;
> + }
> +
> + largeid1 = (byte[1] << 8) | byte[2];
> +
> + if (largeid1 != flash->model_id) {
> + munmap_ich_registers();
> + return 0;
> + }
> +
> + /* perform global unprotect by writing 0 into whole status reg */
> + byte[0] = 0;
> +
> + if (RunOpcode(5, curopcodes->opcode[5], 0x00000000, 1, byte) != 0) {
> + printf_debug("Error global unprotect\n");
> + return -1;
> + }
> +
> + printf_debug("Chip detected, Jedec ID 0x%x\n", largeid1);
> +
> + return 1;
> +}
> +
> +int erase_block_ichspi(struct flashchip *flash, int offset)
> +{
> +#ifdef DEVELOPPERS_DEBUG
> + printf("Spi_Erase,Offset=%d,sectors=%d\n", offset, 1);
> +#endif
> +
> + // TODO: Is this correct ?
> + if (RunOpcode(2, curopcodes->opcode[2], offset, 0, NULL) != 0) {
> + printf_debug("Error erasing sector at 0x%x", offset);
> + return -1;
> + }
> +
> + printf("DONE BLOCK 0x%x\n", offset);
> +
> + return 0;
> +}
> +
> +static int read_page_ichspi(struct flashchip *flash, uint8_t * buf, int Offset)
> +{
> + int page_size = flash->page_size;
> + uint32_t remaining = flash->page_size;
> + int a;
> +
> +#ifdef DEVELOPPERS_DEBUG
> + printf("Spi_Read,Offset=%d,number=%d,buf=%p\n", Offset, page_size, buf);
> +#endif
> +
> + for (a = 0; a < page_size; a += MAXDATABYTES) {
> + if (remaining < MAXDATABYTES) {
> +
> + if (RunOpcode
> + (1, curopcodes->opcode[1],
> + Offset + (page_size - remaining), remaining,
> + &buf[page_size - remaining]) != 0) {
> + printf_debug("Error reading");
> + return 1;
> + }
> + remaining = 0;
> + } else {
> + if (RunOpcode
> + (1, curopcodes->opcode[1],
> + Offset + (page_size - remaining), MAXDATABYTES,
> + &buf[page_size - remaining]) != 0) {
> + printf_debug("Error reading");
> + return 1;
> + }
> + remaining -= MAXDATABYTES;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int write_page_ichspi(struct flashchip *flash, uint8_t * bytes,
> + int Offset)
> +{
> + int page_size = flash->page_size;
> + uint32_t remaining = page_size;
> + int a;
> +
> +#ifdef DEVELOPPERS_DEBUG
> + printf("Spi_Write,Offset=%d,number=%d,buf=%p\n", Offset, page_size,
> + bytes);
> +#endif
> +
> + for (a = 0; a < page_size; a += MAXDATABYTES) {
> + if (remaining < MAXDATABYTES) {
> + if (RunOpcode
> + (0, curopcodes->opcode[0],
> + Offset + (page_size - remaining), remaining,
> + &bytes[page_size - remaining]) != 0) {
> + printf_debug("Error writing");
> + return 1;
> + }
> + remaining = 0;
> + } else {
> + if (RunOpcode
> + (0, curopcodes->opcode[0],
> + Offset + (page_size - remaining), MAXDATABYTES,
> + &bytes[page_size - remaining]) != 0) {
> + printf_debug("Error writing");
> + return 1;
> + }
> + remaining -= MAXDATABYTES;
> + }
> + }
> +
> + return 0;
> +}
> +
> +/* Bulk erase
> + */
> +int erase_ichspi(struct flashchip *flash)
> +{
> + printf_debug("Bulk erase requested");
> + if (RunOpcode(7, curopcodes->opcode[7], 0, 0, NULL) != 0) {
> + printf_debug("Error erasing sector");
> + return 1;
> + }
> + return 0;
> +}
> +
> +int read_ichspi(struct flashchip *flash, uint8_t * buf)
> +{
> + int i, rc = 0;
> + int total_size = flash->total_size * 1024;
> + int page_size = flash->page_size;
> +
> + for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
> + rc = read_page_ichspi(flash, (void *)(buf + i * page_size),
> + i * page_size);
> + }
> +
> + return rc;
> +}
> +
> +int write_ichspi(struct flashchip *flash, uint8_t * buf)
> +{
> + int i, rc = 0;
> + int total_size = flash->total_size * 1024;
> + int page_size = flash->page_size;
> +
> + printf("Programming page: \n");
> + for (i = 0; (i < total_size / page_size) && (rc == 0); i++) {
> + printf
> + ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
> +
> + /* Auto Skip Blocks, which already contain the desired data
> + * Faster, because we only write, what has changed
> + * More secure, because blocks, which are excluded
> + * (with the exclude or layout feature)
> + * are not erased and rewritten; data is retained also
> + * in sudden power off situations
> + */
> + if (!memcmp((void *)(buf + i * page_size),
> + (void *)(flash->virtual_memory + i * page_size),
> + page_size)) {
> + printf("SKIPPED\n");
> + continue;
> + }
> +
> + rc = erase_block_ichspi(flash, i * page_size);
> + if (!rc)
> + write_page_ichspi(flash, (void *)(buf + i * page_size),
> + i * page_size);
> + }
> + printf("\n");
> + munmap_ich_registers();
> +
> + return rc;
> +}
More information about the coreboot
mailing list