[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