[coreboot] SST25VF016B (2MB) flash on m57sli (IT8716F).

Carl-Daniel Hailfinger c-d.hailfinger.devel.2006 at gmx.net
Thu Jan 17 00:56:08 CET 2008


Hi Ronald,

first of all, welcome to coreboot.

I see you invested a lot of time to work around the deficiencies of the
IT8716F SPI translation function. You even did it the way I described
the process a few weeks ago (but I had no time to implement it).

Please see
http://www.coreboot.org/Development_Guidelines#Sign-off_Procedure for
details on patch submission. There are two things that block acceptance
of your patch:
- A "Signed-off-by:" line is missing. Please add one.
- The patch does not apply because Evolution mangled it on your side.
Either fix the configuration or attach the patch as plain text.

On 17.01.2008 00:13, Ronald Hoogenboom wrote:
> I mounted a SST25VF016B 2MByte flash chip on the second SPI bios
> landpattern on the m57sli mobo (as per the m57sli tutorial).
> There as some problems with that, on the one side from the point of the
> LPC memory mapping options of the IT8716F (max. 512KB contiguous) and on
> the other side with the programming method(s) supported by the SST flash
> chip (only the byte-mode programming is compatible with the IT8716).
> Lets call them problem1 and problem2.
>
> The reason why I want the 2MB is that I would like to try direct Linux
> kernel as the payload.
>   

Agreed.

> Problem1 and Problem2 have impact on the useability of flashrom, which I
> have sort-of solved (patch below). Problem1 also has impact on the
> elfboot.c and rom-stream.c in coreboot (linuxbios), which I'm still
> investigating (suggestions welcome!).
>   

I'd like to not handle this problem at all in coreboot v3. In v2, we can
probably work around this issue by ensuring that all code until RAM is
enabled has to be mapped in the contiguous 512 kByte area (which may
correspond to the first or last 512 kB of the flash chip, nobody really
knows and ITE are not answering my mails.

> Problem1 (for reading) is solved by NOT using the mmap method for
> reading the flash contents, but using outb() for sending the flash read
> commands (using a specific 25vf016 read function). Also the normal read
> command is only supported up to 25MHz by this chip, so I cannot use the
> 33MHz speed as used normally by spi.c. There is also a 'high speed' read
> command (0x0b), which inserts an extra dummy byte between address and
> data, but as the 8716 only allows max. 3 bytes read per io transfer, the
> gain (3 bytes per io transfer @ 16MHz versus 2 bytes per io transfer @
> 33MHz) is negligible.
>   

Yes. We have to specify a maximum speed for each SPI chip in
flashchips.c. Suggestions welcome.

> Problem2 (for writing) is solved similarly: The mmap write method cannot
> be used effectively, because the flash chip needs a Write-enable command
> for each Byte-program (no block program concept in byte-program mode).
> The chip has a so-called AAI (auto address increment) programming mode
> instead, but that cannot be used with the 8716 chip, because it needs 6
> byte and 3 byte io transfers, which it doesn't support (bah!). Not using
> the mmap writes also solves the limited LPC memory address window. So,
> there is also a 25vf016 specific write function.
>   

The function is probably more specific to IT8716F and chips bigger than
512 kByte. Maybe rename the function and have the IT8716F writing code
switch to you method if the chip is bigger than 512 kB?


> NOTE: there may be some offset because of other changes...
>
> Index: flash.h
> ===================================================================
> --- flash.h	(revision 3051)
> +++ flash.h	(working copy)
> @@ -297,6 +303,8 @@
>  void generic_spi_write_disable();
>  int generic_spi_chip_erase_c7(struct flashchip *flash);
>  int generic_spi_chip_write(struct flashchip *flash, uint8_t *buf);
> +int sst25vf016_spi_chip_write(struct flashchip *flash, uint8_t *buf);
> +int sst25vf016_spi_chip_read(struct flashchip *flash, uint8_t *buf);
>  
>  /* 82802ab.c */
>  int probe_82802ab(struct flashchip *flash);
> Index: flashchips.c
> ===================================================================
> --- flashchips.c	(revision 3051)
> +++ flashchips.c	(working copy)
> @@ -57,7 +57,7 @@
>  	{"SST25VF040B",	SST_ID,		SST_25VF040B,	512,	256,
>  	probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
>  	{"SST25VF016B",	SST_ID,		SST_25VF016B,	2048,	256,
> -	probe_spi,	generic_spi_chip_erase_c7,	generic_spi_chip_write},
> +	 probe_spi,	generic_spi_chip_erase_c7,	sst25vf016_spi_chip_write,
> sst25vf016_spi_chip_read},
>  	{"SST29EE020A", SST_ID,		SST_29EE020A,	256, 128,
>  	 probe_jedec,	erase_chip_jedec, write_jedec},
>  	{"SST28SF040A", SST_ID,		SST_28SF040,	512, 256,
> Index: spi.c
> ===================================================================
> --- spi.c	(revision 3051)
> +++ spi.c	(working copy)
> @@ -77,6 +77,8 @@
>  #define JEDEC_RDSR_BIT_WIP	(0x01 << 0)
>  
>  uint16_t it8716f_flashport = 0;
> +/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */
> +int fast_spi=1;
>  
>  void generic_spi_prettyprint_status_register(struct flashchip *flash);
>  
> @@ -203,10 +205,10 @@
>  			__FUNCTION__, writecnt);
>  		return 1;
>  	}
> -	/* Start IO, 33MHz, readcnt input bytes, writecnt output bytes. Note:
> +	/* Start IO, 33MHz (or 16), readcnt input bytes, writecnt output
> bytes. Note:
>  	 * We can't use writecnt directly, but have to use a strange encoding.
>  	 */ 
> -	outb((0x5 << 4) | ((readcnt & 0x3) << 2) | (writeenc), port);
> +	outb(((0x4+(fast_spi?1:0)) << 4) | ((readcnt & 0x3) << 2) |
> (writeenc), port);
>  	do {
>  		busy = inb(port) & 0x80;
>  	} while (busy);
> @@ -314,6 +316,39 @@
>  		"%sset\n", (status & (1 << 0)) ? "" : "not ");
>  }
>  
> +/* Prettyprint the status register. Works for
> + * SST 25VF016
> + */
> +void generic_spi_prettyprint_status_register_sst25vf016(uint8_t status)
> +{
> +	const char *bpt[]={
> +		"none",
> +		"1F0000H-1FFFFFH",
> +		"1E0000H-1FFFFFH",
> +		"1C0000H-1FFFFFH",
> +		"180000H-1FFFFFH",
> +		"100000H-1FFFFFH",
> +		"all","all"
> +	};
> +	printf_debug("Chip status register: Block Protect Write Disable "
> +		"(BPL) is %sset\n", (status & (1 << 7)) ? "" : "not ");
> +	printf_debug("Chip status register: Auto Address Increment Programming
> "
> +		"(AAI) is %sset\n", (status & (1 << 6)) ? "" : "not ");
> +	printf_debug("Chip status register: Bit 5 (BP3) is "
> +		"%sset\n", (status & (1 << 5)) ? "" : "not ");
> +	printf_debug("Chip status register: Bit 4 (BP2) is "
> +		"%sset\n", (status & (1 << 4)) ? "" : "not ");
> +	printf_debug("Chip status register: Bit 3 (BP1) is "
> +		"%sset\n", (status & (1 << 3)) ? "" : "not ");
> +	printf_debug("Chip status register: Bit 2 (BP0) is "
> +		"%sset\n", (status & (1 << 2)) ? "" : "not ");
> +	printf_debug("Resulting block protection : %s\n",
> bpt[(status&0x1c)>>2]);
> +	printf_debug("Chip status register: Write Enable Latch (WEL) is "
> +		"%sset\n", (status & (1 << 1)) ? "" : "not ");
> +	printf_debug("Chip status register: Write In Progress (BUSY) is "
> +		"%sset\n", (status & (1 << 0)) ? "" : "not ");
> +}
> +
>  void generic_spi_prettyprint_status_register(struct flashchip *flash)
>  {
>  	uint8_t status;
> @@ -326,6 +361,10 @@
>  		if ((flash->model_id & 0xff00) == 0x2000)
>  			generic_spi_prettyprint_status_register_st_m25p(status);
>  		break;
> +	case SST_ID:
> +		if (flash->model_id == SST_25VF016B)
> +			generic_spi_prettyprint_status_register_sst25vf016(status);
> +		break;
>  	}
>  }
>  	
> @@ -392,7 +431,7 @@
>  
>  	generic_spi_write_enable();
>  	outb(0x06 , it8716f_flashport + 1);
> -	outb((3 << 4), it8716f_flashport);
> +	outb(((2+(fast_spi?1:0)) << 4), it8716f_flashport);
>  	for (i = 0; i < 256; i++) {
>  		bios[256 * block + i] = buf[256 * block + i];
>  	}
> @@ -410,6 +449,94 @@
>  		it8716f_spi_page_program(block, buf, bios);
>  }
>  
> +/*
> + * This is according the SST25VF016 datasheet, who knows it is more
> + * generic that this...
> + */
> +void sst25vf016_spi_write_status_register(int status)
> +{
> +	const unsigned char cmd[] = {0x01,(unsigned char)status};
> +
> +	/* Send WRSR (Write Status Register) */
> +	generic_spi_command(2, 0, cmd, NULL);
> +
> +}
> +
> +void sst25vf016_spi_byte_program(int address, uint8_t byte)
> +{
> +	const unsigned char cmd[5] = {0x02,
> +		(address>>16)&0xff,
> +		(address>>8)&0xff,
> +		(address>>0)&0xff,
> +		byte
> +	};
> +
> +	/* Send Byte-Program */
> +	generic_spi_command(5, 0, cmd, NULL);
> +
> +}
> +
> +/*
> + * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory
> cycles
> + * Program chip using firmware cycle byte programming. (SLOW!)
> + */
> +int sst25vf016_spi_chip_write(struct flashchip *flash, uint8_t *buf)
> +{
> +	int total_size = 1024 * flash->total_size;
> +	uint8_t status;
> +	int i;
> +	fast_spi=0;
> +
> +	status = generic_spi_read_status_register();
> +	/* If there is block protection in effect, unprotect it first. */
> +	if ((status&0x3c)!=0) {
> +		printf_debug("Some block protection in effect, disabling\n");
> +		generic_spi_write_enable();
> +		sst25vf016_spi_write_status_register(status&~0x3c);
> +	}
> +	for (i=0; i<total_size; i++) {
> +		generic_spi_write_enable();
> +		sst25vf016_spi_byte_program(i,buf[i]);
> +		//while (generic_spi_read_status_register() & JEDEC_RDSR_BIT_WIP)
> +			usleep(10);
> +		if (i%1024==0) fputc('b',stderr);
> +	}
> +	/* resume normal ops... */
> +	outb(0x20, it8716f_flashport);
> +	return 0;
> +}
> +
> +void sst25vf016_spi_3byte_read(int address, uint8_t *bytes, int len)
> +{
> +	const unsigned char cmd[5] = {0x03,
> +		(address>>16)&0xff,
> +		(address>>8)&0xff,
> +		(address>>0)&0xff,
> +	};
> +
> +	/* Send Read */
> +	generic_spi_command(4, len, cmd, bytes);
> +
> +}
> +
> +/*
> + * IT8716F only allows maximum of 512 kb SPI mapped to LPC memory
> cycles
> + * Need to read this big flash using firmware cycles 3 byte at a time.
> + */
> +int sst25vf016_spi_chip_read(struct flashchip *flash, uint8_t *buf)
> +{
> +	int total_size = 1024 * flash->total_size;
> +	int i;
> +	fast_spi=0;
> +
> +	for (i = 0; i < total_size; i+=3) {
> +		int toread=3;
> +		if (total_size-i < toread) toread=total_size-i;
> +		sst25vf016_spi_3byte_read(i, buf+i, toread);
> +	}
> +	return 0;
> +}
> +
>  int generic_spi_chip_write(struct flashchip *flash, uint8_t *buf) {
>  	int total_size = 1024 * flash->total_size;
>  	int i;
>
>   

Please try to address the comments above and repost.
Note: I suggest that the "maximum frequency" stuff could be handled in
another patch because it requires redesign of some structures (needs
discussion) and is also is logically another change.


Regards,
Carl-Daniel




More information about the coreboot mailing list