Patchwork Add preliminary support for AMIC chips with uniform 4kB sectors

login
register
about
Submitter Daniel Lenski
Date 2010-07-24 21:22:49
Message ID <1280006569.3185.27.camel@dlenski-desktop>
Download mbox | patch
Permalink /patch/1678/
State Accepted
Commit r1118
Headers show

Comments

Daniel Lenski - 2010-07-24 21:22:49
On Sat, 2010-07-24 at 10:16 +0200, Carl-Daniel Hailfinger wrote:
> General remark: Can you order the eraseblock definitions by eraseblock
> size (smallest one first)? This allows us to use a better reflashing
> granularity in the first write/erase attempt, and reserves bigger
> granularities for the case where smaller granularities fail.

Got it, done.

> I can't find the 52h SPI opcode in the datasheet.
> I can't find the 60h SPI opcode in the datasheet.
>  (etc.)

Changed these.  I found other versions of the datasheets that suggested
these were valid and had been inadvertently omitted... but I think I'm
probably erring on the wrong side of caution by doing that.

> Can you add a comment so it looks like this:
> 
> 		.unlock		= NULL, /* Two-byte status reg */

Done.  I made a careless mistake, which is that only the 032 and Q032
chips have the two-byte status reg and more complex protection features.
The smaller-capacity ones can still use the standard
spi_disable_blockprotect unlock function.  I have corrected this in the
patch.

One other feature of the A25L032 and A25LQ032 chips which Flashrom may
want to be aware of: they have 64 bytes of one-time-programmable memory
on them.  Is reading/writing this outside the scope of Flashrom?  I
assume they'd be used for serial numbers or crypto keys... and it might
be misleading to assume Flashrom was completely backing up/restoring a
BIOS image if it can't read and write this OTP region.

Revised patch is attached, with revised description.

Dan
Carl-Daniel Hailfinger - 2010-07-29 15:05:39
On 24.07.2010 23:22, Daniel Lenski wrote:
> On Sat, 2010-07-24 at 10:16 +0200, Carl-Daniel Hailfinger wrote:
>   
>> General remark: Can you order the eraseblock definitions by eraseblock
>> size (smallest one first)? This allows us to use a better reflashing
>> granularity in the first write/erase attempt, and reserves bigger
>> granularities for the case where smaller granularities fail.
>>     
>
> Got it, done.
>
>   
>> I can't find the 52h SPI opcode in the datasheet.
>> I can't find the 60h SPI opcode in the datasheet.
>>  (etc.)
>>     
>
> Changed these.  I found other versions of the datasheets that suggested
> these were valid and had been inadvertently omitted... but I think I'm
> probably erring on the wrong side of caution by doing that.
>   

flashrom can deal fine with failing erase, so if you can dig up those
datasheets again, please send a followup patch which adds those SPI
erase opcodes again. I had assumed you were extrapolating, but having
solid data is an entirely different thing. And yes, datasheets often
contradict each other.


>> Can you add a comment so it looks like this:
>>
>> 		.unlock		= NULL, /* Two-byte status reg */
>>     
>
> Done.  I made a careless mistake, which is that only the 032 and Q032
> chips have the two-byte status reg and more complex protection features.
> The smaller-capacity ones can still use the standard
> spi_disable_blockprotect unlock function.  I have corrected this in the
> patch.
>   

OK. I have added support for some Atmel chips which need a more
complicated unlocking, and maybe that can serve as a template for you.
In the interest of full disclosure I should say that the structure of my
unlock functions for AT25* is suboptimal, and probably would benefit
from some generalization and/or refactoring.


> One other feature of the A25L032 and A25LQ032 chips which Flashrom may
> want to be aware of: they have 64 bytes of one-time-programmable memory
> on them.  Is reading/writing this outside the scope of Flashrom?  I
> assume they'd be used for serial numbers or crypto keys... and it might
> be misleading to assume Flashrom was completely backing up/restoring a
> BIOS image if it can't read and write this OTP region.
>   

Good point. Given that those are accessible with special commands only,
and are not "normal" flash contents per se, I feel it is OK to ignore
them for now. Future flashrom versions will have an interface which
allows running arbitrary commands, and that interface could be used for
OTP and security regions.


> Revised patch is attached, with revised description.
>   

Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net>

Thanks for your patch, committed in r1118.

Regards,
Carl-Daniel
Daniel Lenski - 2010-07-29 19:07:57
On Thu, 2010-07-29 at 17:05 +0200, Carl-Daniel Hailfinger wrote:
> >> I can't find the 52h SPI opcode in the datasheet.
> >> I can't find the 60h SPI opcode in the datasheet.
> >>  (etc.)
> >>     
> >
> > Changed these.  I found other versions of the datasheets that suggested
> > these were valid and had been inadvertently omitted... but I think I'm
> > probably erring on the wrong side of caution by doing that.
> >   
> 
> flashrom can deal fine with failing erase, so if you can dig up those
> datasheets again, please send a followup patch which adds those SPI
> erase opcodes again. I had assumed you were extrapolating, but having
> solid data is an entirely different thing. And yes, datasheets often
> contradict each other.

I had found an early (version number <1.0) version of the
A25L020/A25L010/A25L512 datasheet that listed these, but I'm
unfortunately not finding it now.  It doesn't appear in any of the
versions >=1.0, so it's probably wrong.

> OK. I have added support for some Atmel chips which need a more
> complicated unlocking, and maybe that can serve as a template for you.
> In the interest of full disclosure I should say that the structure of my
> unlock functions for AT25* is suboptimal, and probably would benefit
> from some generalization and/or refactoring.

I took a look at the at25f* unlock functions.  If I understand
correctly, they involve various manipulations of the standard 1-byte
status register.

The A25L032/Q032 will require new functions to read and write the 2-byte
status register.  The good thing is that the standard commands can be
used except when manipulating the second byte, AFAICT.  Would you prefer
one big ugly function to do the whole thing, or factor things out into
separate functions to read/write the 2-byte SR?

> > One other feature of the A25L032 and A25LQ032 chips which Flashrom may
> > want to be aware of: they have 64 bytes of one-time-programmable memory
> > on them.  Is reading/writing this outside the scope of Flashrom?  I
> > assume they'd be used for serial numbers or crypto keys... and it might
> > be misleading to assume Flashrom was completely backing up/restoring a
> > BIOS image if it can't read and write this OTP region.
> >   
> 
> Good point. Given that those are accessible with special commands only,
> and are not "normal" flash contents per se, I feel it is OK to ignore
> them for now. Future flashrom versions will have an interface which
> allows running arbitrary commands, and that interface could be used for
> OTP and security regions.

Perhaps a FEATURE_UNHANDLED_OTP bit (or something more concise to that
effect) could be designed, which would just give a warning prior to
read/write/erase?  Something like the FEATURE_EVIL_TWIN bit that you
proposed to warn about pairs like the A25L40P{T,U}.

I've coded up a small patch for that, to follow.

Dan

Patch

This patch should enable read/write/erase support for these chips.  Unlock
functionality is *not* implemented yet for A25L032 or A25LQ032, because they
have more complex protection features than simply BPx block-protect bits.

Datasheets:
http://www.amictechnology.com/pdf/A25L512.pdf
http://www.amictechnology.com/pdf/A25L010.pdf
http://www.amictechnology.com/pdf/A25L020.pdf
http://www.amictechnology.com/pdf/A25L040.pdf
http://www.amictechnology.com/pdf/A25L080.pdf
http://www.amictechnology.com/pdf/A25L016.pdf
http://www.amictechnology.com/pdf/A25L032.pdf
http://www.amictechnology.com/pdf/A25LQ032.pdf

IDs:
0x37 0x3010 is A25L512 (uniform 4k sectors)
0x37 0x3011 is A25L010 (uniform 4k sectors)
0x37 0x3012 is A25L020 (uniform 4k sectors)
0x37 0x3013 is A25L040 (uniform 4k sectors)
0x37 0x3014 is A25L080 (uniform 4k sectors)
0x37 0x3015 is A25L016 (uniform 4k sectors)
0x37 0x3016 is A25L032 (uniform 4k sectors)
0x37 0x4016 is A25LQ032 (uniform 4k sectors, has quad-rate read)

Please note that the IDs of the newer chips all use AMIC_ID_NOPREFIX instead
of AMIC_ID, and that means they use probe_spi_rdid instead of
probe_spi_rdid4.

Signed-off-by: Dan Lenski <dlenski@gmail.com>
---
 flashchips.c |  244 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 flashchips.h |    8 ++
 2 files changed, 252 insertions(+), 0 deletions(-)

diff --git a/flashchips.c b/flashchips.c
index c6d265e..abe5f24 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -1532,6 +1532,250 @@  struct flashchip flashchips[] = {
 
 	{
 		.vendor		= "AMIC",
+		.name		= "A25L512",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A25L512,
+		.total_size	= 64,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { { 4 * 1024, 16 } },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { { 64 * 1024, 1 } },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { { 64 * 1024, 1 } },
+				.block_erase = spi_block_erase_c7,
+			}			
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A25L010",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A25L010,
+		.total_size	= 128,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { { 4 * 1024, 32 } },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { { 64 * 1024, 2 } },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { { 128 * 1024, 1 } },
+				.block_erase = spi_block_erase_c7,
+			}			
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A25L020",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A25L020,
+		.total_size	= 256,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { { 4 * 1024, 64 } },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { { 64 * 1024, 4 } },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { { 256 * 1024, 1 } },
+				.block_erase = spi_block_erase_c7,
+			}			
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A25L040",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A25L040,
+		.total_size	= 512,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { { 4 * 1024, 128 } },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { { 64 * 1024, 8 } },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { { 512 * 1024, 1 } },
+				.block_erase = spi_block_erase_c7,
+			}			
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A25L080",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A25L080,
+		.total_size	= 1024,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { { 4 * 1024, 256 } },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { { 64 * 1024, 16 } },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { { 1024 * 1024, 1 } },
+				.block_erase = spi_block_erase_c7,
+			}			
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A25L016",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A25L016,
+		.total_size	= 2048,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { { 4 * 1024, 512 } },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { { 64 * 1024, 32 } },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { { 2048 * 1024, 1 } },
+				.block_erase = spi_block_erase_c7,
+			}			
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A25L032",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A25L032,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { { 4 * 1024, 1024 } },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { { 64 * 1024, 64 } },
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { { 64 * 1024, 64 } },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { { 4096 * 1024, 1 } },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { { 4096 * 1024, 1 } },
+				.block_erase = spi_block_erase_c7,
+			}			
+		},
+		.unlock		= NULL, /* Two status reg bytes (read with 0x35 and 0x05) */
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "AMIC",
+		.name		= "A25LQ032",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= AMIC_ID_NOPREFIX,
+		.model_id	= AMIC_A25LQ032,
+		.total_size	= 4096,
+		.page_size	= 256,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { { 4 * 1024, 1024 } },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { { 64 * 1024, 64 } },
+				.block_erase = spi_block_erase_52,
+			}, {
+				.eraseblocks = { { 64 * 1024, 64 } },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { { 4096 * 1024, 1 } },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { { 4096 * 1024, 1 } },
+				.block_erase = spi_block_erase_c7,
+			}			
+		},
+		.unlock		= NULL, /* Two status reg bytes (read with 0x35 and 0x05) */
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "AMIC",
 		.name		= "A29002B",
 		.bustype	= CHIP_BUSTYPE_PARALLEL,
 		.manufacture_id	= AMIC_ID_NOPREFIX,
diff --git a/flashchips.h b/flashchips.h
index 3e2befa..0b16e3b 100644
--- a/flashchips.h
+++ b/flashchips.h
@@ -88,6 +88,14 @@ 
 #define AMIC_A25L80P		0x2014	/* Seems that no A25L80PT exists */
 #define AMIC_A25L16PT		0x2025
 #define AMIC_A25L16PU		0x2015
+#define AMIC_A25L512		0x3010
+#define AMIC_A25L010		0x3011
+#define AMIC_A25L020		0x3012
+#define AMIC_A25L040		0x3013
+#define AMIC_A25L080		0x3014
+#define AMIC_A25L016		0x3015
+#define AMIC_A25L032		0x3016
+#define AMIC_A25LQ032		0x4016
 #define AMIC_A29002B		0x0d
 #define AMIC_A29002T		0x8C	/* Same as A290021T */
 #define AMIC_A29040B		0x86
-- 
1.7.0.4