Patchwork Add support for EN25Q series SPI flash chips

login
register
about
Submitter David Hendricks
Date 2011-06-22 23:04:42
Message ID <BANLkTinHWOdL4PYxdgdKvoJUBONBhm9==QFUpcGuNNpvtCPK_w@mail.gmail.com>
Download mbox | patch
Permalink /patch/3196/
State Accepted
Commit r1384
Headers show

Comments

David Hendricks - 2011-06-22 23:04:42
Thanks for the review! I've attached an updated patch to address your
comments.

I'm still not sure what the best course of action is for dealing with the
D16 versus Q16 evil twin scenario. Let's see if Carl-Daniel has further
comments.

New patch is:
Signed-off-by: David Hendricks <dhendrix@google.com>

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> On Tue, 12 Apr 2011 12:58:35 -0700
> David Hendricks <dhendrix@google.com> wrote:
>
> > Hello,
> > The attached patch adds support for the following Eon SPI flash chips:
> > EN25Q40, EN25Q80, EN25Q32A/B, EN25Q64, and EN25Q128
> >
> > I was going to add support for the EN25Q16 as well, but found that it
> shares
> > the same ID as the EN25D16 but has different write protection
> capabilities.
> > So I added a comment instead.
> >
> > I do not have real hardware to test with at the moment, so I left the
> status
> > as untested.
> >
> > Datasheets available from Eon @
> http://www.eonssi.com/products/products.aspx
> >
>
> hello david and thanks for your patch.
>
> i can confirm that the EN25D16 shares the ID with EN25Q16.
> there is also a EN25QH16 but with another ID 7015h (and an upcoming
> EN25QH256 w/o data sheet yet).
>

Thanks for pointing that out. I've added the EN25QH16 to the patch.

As we discussed on IRC, this particular chip supports "Serial Flash
Discoverable Parameters" (SFDP). I tried to add support using the values
listed in Table 9 of their datasheet, and left a TODO to update the probe
routine later on.

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> > Index: flashchips.h
> > ===================================================================
> > --- flashchips.h      (revision 1285)
> > +++ flashchips.h      (working copy)
> > @@ -232,7 +232,12 @@
> >  #define EON_EN25B64          0x2017  /* Same as P64 */
> >  #define EON_EN25B64T         0x46
> >  #define EON_EN25B64B         0x36
> > +#define EON_EN25Q40          0x3013
> ok
> > +#define EON_EN25Q80          0x3014
> i could only find references to a chip named EN25Q80A... either add a
> comment or rename to EON_EN25Q80A?
>

Appended "A" to the name.

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> >  #define EON_EN25D16          0x3015
> i think the twin's name should be noted here too.
> since the D is untested i would also suggest using Q as the variable
> name here, because there is no other D supported yet... so
> -#define EON_EN25D16            0x3015
> +#define EON_EN25Q16            0x3015 /* Same as D16 */
> or so..
>

Added a comment to the line with the EON_EN25D16 #define.

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> > +#define EON_EN25Q32          0x3016
> correct; similar to the EON_EN25Q80 there seem to exist 3 versions: 'A',
> 'B' and no suffix.
>

Added comment next to the #define.

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> somewhere below...
> +#define EON_EN25QH16           0x7015
>

Done. I rearranged the EN25Q* #defines a bit so they're in alphabetical
order with respect to the other EN25* chips.

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> > Index: flashchips.c
> > ===================================================================
> > --- flashchips.c      (revision 1285)
> > +++ flashchips.c      (working copy)
> > @@ -2807,6 +2807,8 @@
> >       },
> >
> >       {
> > +             /* Note: EN25Q16 is an evil twin which shares the model ID
> > +                but has different write protection capabilities */
> >               .vendor         = "Eon",
> >               .name           = "EN25D16",
> change according to the macro name chosen (if applicable see above)
>

The EN25D16 was there first... I'm not sure if we should change it. I
imagine the D16 is out of production, but I assume *somebody* is using it.

WWCDD? (What Would Carl-Daniel Do?)


> >               .bustype        = CHIP_BUSTYPE_SPI,
> > @@ -2814,6 +2816,7 @@
> >               .model_id       = EON_EN25D16,
> >               .total_size     = 2048,
> >               .page_size      = 256,
> > +             .feature_bits   = FEATURE_WRSR_WREN,
> true for the Q, did not check D
>

The EN25D16's datasheet no longer appears to be listed, but it is still
available here: http://www.eonssi.com/upfile/p2008929181445.pdf (found via
google :-))

It The D16 manual states, "The Write Status Register (WRSR) instruction
allows new values to be written to the Status Register. Before it can be
accepted, a Write Enable (WREN) instruction must previously have been
executed."

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> >               .tested         = TEST_UNTESTED,
> >               .probe          = probe_spi_rdid,
> >               .probe_timing   = TIMING_ZERO,
> .block_erase = spi_block_erase_52, is not supported by the Q version.
> add a comment please.
> other erasers seem to be ok with the Q version.
>

Done. Nice catch!

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

>
>                .voltage        = {2700, 3600}, (for the Q version)
>

Same as the D version (the original EN25Q* patch came before the .voltage
member was added)

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> > @@ -3083,6 +3086,171 @@
> >
> >       {
> >               .vendor         = "Eon",
> > +             .name           = "EN25Q40",
> > +             .bustype        = CHIP_BUSTYPE_SPI,
> > +             .manufacture_id = EON_ID_NOPREFIX,
> > +             .model_id       = EON_EN25Q40,
> > +             .total_size     = 512,
> > +             .page_size      = 256,
> > +             .feature_bits   = FEATURE_WRSR_WREN,
> > +             .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_60,
> > +                     }, {
> > +                             .eraseblocks = { {512 * 1024, 1} },
> > +                             .block_erase = spi_block_erase_c7,
> > +                     }
> > +             },
> > +             .unlock         = spi_disable_blockprotect,
> > +             .write          = spi_chip_write_256,
> > +             .read           = spi_chip_read,
>                .voltage        = {2700, 3600},
>

Added .voltage.

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> > +     },
> > +
> > +     {
> > +             .vendor         = "Eon",
> > +             .name           = "EN25Q80(A)",
> > +             .bustype        = CHIP_BUSTYPE_SPI,
> > +             .manufacture_id = EON_ID_NOPREFIX,
> > +             .model_id       = EON_EN25Q80,
> depends on macro name choice above
>

Updated to EON_EN25Q80A.

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> > +             .total_size     = 1024,
> > +             .page_size      = 256,
> > +             .feature_bits   = FEATURE_WRSR_WREN,
> > +             .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_60,
> > +                     }, {
> > +                             .eraseblocks = { {1024 * 1024, 1} },
> > +                             .block_erase = spi_block_erase_c7,
> > +                     }
> > +             },
> > +             .unlock         = spi_disable_blockprotect,
> > +             .write          = spi_chip_write_256,
> > +             .read           = spi_chip_read,
>                .voltage        = {2700, 3600},
>

Added the .voltage member.

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> > +     },
> > +
> > +     {
> > +             .vendor         = "Eon",
> > +             .name           = "EN25Q32(A)(B)",
> i think that should be (A/B)
>

Fixed.

On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner <
stefan.tauner@student.tuwien.ac.at> wrote:

> > +             .bustype        = CHIP_BUSTYPE_SPI,
> > +             .manufacture_id = EON_ID_NOPREFIX,
> > +             .model_id       = EON_EN25Q32,
> > +             .total_size     = 4096,
> > +             .page_size      = 256,
> > +             .feature_bits   = FEATURE_WRSR_WREN,
> > +             .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_d8,
> > +                     }, {
> > +                             .eraseblocks = { {4 * 1024 * 1024, 1} },
> > +                             .block_erase = spi_block_erase_60,
> > +                     }, {
> > +                             .eraseblocks = { {4 * 1024 * 1024, 1} },
> > +                             .block_erase = spi_block_erase_c7,
> > +                     }
> > +             },
> > +             .unlock         = spi_disable_blockprotect,
> > +             .write          = spi_chip_write_256,
> > +             .read           = spi_chip_read,
>                .voltage        = {2700, 3600},
> > +     },
> > +
> > +     {
> > +             .vendor         = "Eon",
> > +             .name           = "EN25Q64",
> > +             .bustype        = CHIP_BUSTYPE_SPI,
> > +             .manufacture_id = EON_ID_NOPREFIX,
> > +             .model_id       = EON_EN25Q64,
> > +             .total_size     = 8192,
> > +             .page_size      = 256,
> > +             .feature_bits   = FEATURE_WRSR_WREN,
> > +             .tested         = TEST_UNTESTED,
> > +             .probe          = probe_spi_rdid,
> > +             .probe_timing   = TIMING_ZERO,
> > +             .block_erasers  =
> > +             {
> > +                     {
> > +                             .eraseblocks = { {4 * 1024, 2048} },
> > +                             .block_erase = spi_block_erase_20,
> > +                     }, {
> > +                             .eraseblocks = { {64 * 1024, 128} },
> > +                             .block_erase = spi_block_erase_d8,
> > +                     }, {
> > +                             .eraseblocks = { {8 * 1024 * 1024, 1} },
> > +                             .block_erase = spi_block_erase_60,
> > +                     }, {
> > +                             .eraseblocks = { {8 * 1024 * 1024, 1} },
> > +                             .block_erase = spi_block_erase_c7,
> > +                     }
> > +             },
> > +             .unlock         = spi_disable_blockprotect,
> > +             .write          = spi_chip_write_256,
> > +             .read           = spi_chip_read,
>                .voltage        = {2700, 3600},
> > +     },
> > +
> > +     {
> > +             .vendor         = "Eon",
> > +             .name           = "EN25Q128",
> > +             .bustype        = CHIP_BUSTYPE_SPI,
> > +             .manufacture_id = EON_ID_NOPREFIX,
> > +             .model_id       = EON_EN25Q128,
> > +             .total_size     = 16384,
> > +             .page_size      = 256,
> > +             .feature_bits   = FEATURE_WRSR_WREN,
> > +             .tested         = TEST_UNTESTED,
> > +             .probe          = probe_spi_rdid,
> > +             .probe_timing   = TIMING_ZERO,
> > +             .block_erasers  =
> > +             {
> > +                     {
> > +                             .eraseblocks = { {4 * 1024, 4096} },
> > +                             .block_erase = spi_block_erase_20,
> > +                     }, {
> > +                             .eraseblocks = { {64 * 1024, 256} },
> > +                             .block_erase = spi_block_erase_d8,
> > +                     }, {
> > +                             .eraseblocks = { {16 * 1024 * 1024, 1} },
> > +                             .block_erase = spi_block_erase_60,
> > +                     }, {
> > +                             .eraseblocks = { {16 * 1024 * 1024, 1} },
> > +                             .block_erase = spi_block_erase_c7,
> > +                     }
> > +             },
> > +             .unlock         = spi_disable_blockprotect,
> > +             .write          = spi_chip_write_256,
> > +             .read           = spi_chip_read,
>                .voltage        = {2700, 3600},
>

Added .voltage members.


> > +     },
> > +
> > +     {
> > +             .vendor         = "Eon",
> >               .name           = "EN29F010",
> >               .bustype        = CHIP_BUSTYPE_PARALLEL,
> >               .manufacture_id = EON_ID,
>
> although the comment of the array indicates "alphabetically" sorted, it
> seems most of it is sorted by chipsize (if pushed). that means the
> entries above should be sorted like the IDs in flashchips.h
>
> also please add a comment to all chips with the respective OTP (=one
> time programmable) area size.
> we don't support that yet, nor do we warn the user (yet), but i am sure
> there is a patch to lure with such a comment... ;)
> 512B:
> Q128
> Q64
> Q32B
> (QH16)
>
> 256B:
> Q80A
> Q40
>
> 128B:
> Q16 (but D16 has 512B, oh my...)
>

Done -- Added the comments above the feature_bits.

most of this are rather small problems. hence if everything i put into
> this review was at least briefly considered.. it is
> Acked-by: Stefan Tauner <stefan.tauner@student.tuwien.ac.at>
> --
> Kind regards/Mit freundlichen Grüßen, Stefan Tauner
>
> _______________________________________________
> flashrom mailing list
> flashrom@flashrom.org
> http://www.flashrom.org/mailman/listinfo/flashrom
>
Carl-Daniel Hailfinger - 2011-06-27 00:00:48
Am 23.06.2011 01:04 schrieb David Hendricks:
> I'm still not sure what the best course of action is for dealing with the
> D16 versus Q16 evil twin scenario. Let's see if Carl-Daniel has further
> comments.
>
> Signed-off-by: David Hendricks <dhendrix@google.com>
>
> As we discussed on IRC, this particular chip supports "Serial Flash
> Discoverable Parameters" (SFDP). I tried to add support using the values
> listed in Table 9 of their datasheet, and left a TODO to update the probe
> routine later on.
>   

Ah yes, SFDP. Stefan has implemented a patch to support that in the
meantime.



> On Wed, Jun 22, 2011 at 9:15 AM, Stefan Tauner wrote:
>> somewhere below...
>> +#define EON_EN25QH16           0x7015
>
> Done. I rearranged the EN25Q* #defines a bit so they're in alphabetical
> order with respect to the other EN25* chips.
>
>
>   
>>> Index: flashchips.c
>>> ===================================================================
>>> --- flashchips.c      (revision 1285)
>>> +++ flashchips.c      (working copy)
>>> @@ -2807,6 +2807,8 @@
>>>       },
>>>
>>>       {
>>> +             /* Note: EN25Q16 is an evil twin which shares the model ID
>>> +                but has different write protection capabilities */
>>>               .vendor         = "Eon",
>>>               .name           = "EN25D16",
>>>       
>> change according to the macro name chosen (if applicable see above)
>>     
> The EN25D16 was there first... I'm not sure if we should change it. I
> imagine the D16 is out of production, but I assume *somebody* is using it.
>
> WWCDD? (What Would Carl-Daniel Do?)
>   

Evil twins... I have a patch for that: 
http://patchwork.coreboot.org/patch/1861/

The rules are simple:
If two chips are identical from a flashrom POV (same command set and
write/erase characteristics), combine them into one entry. If those
chips differ, give them two entries and mark them as evil twins.
Differing write protection is a corner case... we don't really have a
good write protection handling in flashrom (yet), and until one of the
four suggested/implemented designs is chosen, this is difficult to
handle. Is there a way to probe for the write protection capabilities?

Side note: Probing could be a bit more intelligent for the case of
almost-identical chips. It could calculate the greatest common command
set and offer to use that merging result. Other tricks are possible as well.

Regards,
Carl-Daniel
Stefan Tauner - 2011-06-30 02:43:35
On Mon, 27 Jun 2011 02:00:48 +0200
Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@gmx.net> wrote:

> Am 23.06.2011 01:04 schrieb David Hendricks:
> >>> Index: flashchips.c
> >>> ===================================================================
> >>> --- flashchips.c      (revision 1285)
> >>> +++ flashchips.c      (working copy)
> >>> @@ -2807,6 +2807,8 @@
> >>>       },
> >>>
> >>>       {
> >>> +             /* Note: EN25Q16 is an evil twin which shares the model ID
> >>> +                but has different write protection capabilities */
> >>>               .vendor         = "Eon",
> >>>               .name           = "EN25D16",
> >>>       
> >> change according to the macro name chosen (if applicable see above)
> >>     
> > The EN25D16 was there first... I'm not sure if we should change it. I
> > imagine the D16 is out of production, but I assume *somebody* is using it.
> >
> > WWCDD? (What Would Carl-Daniel Do?)
> >   

the main question regarding the evil twin was if we should rename the
old, existing EN25D16 to EN25Q16 to match the other 25Q chips. there is
only the one 25D one in flashrom and i can only find a datasheet for
another one of that series (EN25D80, id 0x3015).
so i think it makes sense to rename the D16 to Q16 and to annotate it
and the Q80 (similar problem with different block protection).

> Evil twins... I have a patch for that: 
> http://patchwork.coreboot.org/patch/1861/
> 
> The rules are simple:
> If two chips are identical from a flashrom POV (same command set and
> write/erase characteristics), combine them into one entry. If those
> chips differ, give them two entries and mark them as evil twins.
> Differing write protection is a corner case... we don't really have a
> good write protection handling in flashrom (yet), and until one of the
> four suggested/implemented designs is chosen, this is difficult to
> handle. Is there a way to probe for the write protection capabilities?

not directly, but the D series seems to not support "Dual I/O Fast
Read" (0xBB) and "Quad I/O Fast Read" (0xEB), so theoretically we could
(try to) probe for it, but it is not 100% conclusive and i have no
idea how we could do this right now anyway. :)

another possibility would be to read the OTP data. the D versions have
less OTP memory. it is not clear what data is returned for addresses
outside the specified OTP address range though and it is also not 100%
conclusive.

i think we just should not care for now because differentiation is
not really needed yet (no support for different protected ranges
anyway).
Stefan Tauner - 2011-07-24 22:25:03
On Wed, 22 Jun 2011 16:04:42 -0700
David Hendricks <dhendrix@google.com> wrote:

> Thanks for the review! I've attached an updated patch to address your
> comments.
> 
> I'm still not sure what the best course of action is for dealing with the
> D16 versus Q16 evil twin scenario. Let's see if Carl-Daniel has further
> comments.
> 
> New patch is:
> Signed-off-by: David Hendricks <dhendrix@google.com>

since carl-daniel wants to push 0.9.4 soon (no, really! ;) i have
committed your patch with some small changes which i think make it
better (including the D16 -> Q16 rename) in r1384. thank you!

Patch

Index: flashchips.c
===================================================================
--- flashchips.c	(revision 1349)
+++ flashchips.c	(working copy)
@@ -2910,6 +2910,8 @@ 
 	},
 
 	{
+		/* Note: EN25Q16 is an evil twin which shares the model ID
+		   but has different write protection capabilities */
 		.vendor		= "Eon",
 		.name		= "EN25D16",
 		.bustype	= CHIP_BUSTYPE_SPI,
@@ -2917,6 +2919,9 @@ 
 		.model_id	= EON_EN25D16,
 		.total_size	= 2048,
 		.page_size	= 256,
+		/* TODO: EN25D16 features 512-byte one-time programmable region,
+		 * EN25Q16 features a 128-byte one-time programmable region */
+		.feature_bits	= FEATURE_WRSR_WREN,
 		.tested		= TEST_UNTESTED,
 		.probe		= probe_spi_rdid,
 		.probe_timing	= TIMING_ZERO,
@@ -2929,6 +2934,7 @@ 
 				.eraseblocks = { {64 * 1024, 32} },
 				.block_erase = spi_block_erase_d8,
 			}, {
+				/* not supported by Q16 version */
 				.eraseblocks = { {64 * 1024, 32} },
 				.block_erase = spi_block_erase_52,
 			}, {
@@ -3194,6 +3200,218 @@ 
 
 	{
 		.vendor		= "Eon",
+		.name		= "EN25Q40",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EON_EN25Q40,
+		.total_size	= 512,
+		.page_size	= 256,
+		/* TODO: chip features 256-byte one-time programmable region */
+		.feature_bits	= FEATURE_WRSR_WREN,
+		.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_60,
+			}, {
+				.eraseblocks = { {512 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			}
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+		.voltage        = {2700, 3600},
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25Q80(A)",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EON_EN25Q80A,
+		.total_size	= 1024,
+		.page_size	= 256,
+		/* TODO: chip features 256-byte one-time programmable region */
+		.feature_bits	= FEATURE_WRSR_WREN,
+		.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_60,
+			}, {
+				.eraseblocks = { {1024 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			}
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+		.voltage        = {2700, 3600},
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25QH16",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EON_EN25QH16,
+		.total_size	= 2048,
+		.page_size	= 256,
+		/* TODO: chip features 512-byte one-time programmable region */
+		.feature_bits	= FEATURE_WRSR_WREN,
+		.tested		= TEST_UNTESTED,
+		/* TODO: EN25QH16 has "Serial Flash Discoverable Parameters"
+		 * (SFDP). We may wish to write a more sophisticated probe
+		 * routine to fully support this chip. */
+		.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 = { {1024 * 2048, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {1024 * 2048, 1} },
+				.block_erase = spi_block_erase_c7,
+			}
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+		.voltage        = {2700, 3600},
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25Q32(A/B)",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EON_EN25Q32,
+		.total_size	= 4096,
+		.page_size	= 256,
+		/* TODO: chip features 512-byte one-time programmable region */
+		.feature_bits	= FEATURE_WRSR_WREN,
+		.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_d8,
+			}, {
+				.eraseblocks = { {4 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {4 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			}
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+		.voltage        = {2700, 3600},
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25Q64",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EON_EN25Q64,
+		.total_size	= 8192,
+		.page_size	= 256,
+		/* TODO: chip features 512-byte one-time programmable region */
+		.feature_bits	= FEATURE_WRSR_WREN,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 2048} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {64 * 1024, 128} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {8 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			}
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+		.voltage        = {2700, 3600},
+	},
+
+	{
+		.vendor		= "Eon",
+		.name		= "EN25Q128",
+		.bustype	= CHIP_BUSTYPE_SPI,
+		.manufacture_id	= EON_ID_NOPREFIX,
+		.model_id	= EON_EN25Q128,
+		.total_size	= 16384,
+		.page_size	= 256,
+		/* TODO: chip features 512-byte one-time programmable region */
+		.feature_bits	= FEATURE_WRSR_WREN,
+		.tested		= TEST_UNTESTED,
+		.probe		= probe_spi_rdid,
+		.probe_timing	= TIMING_ZERO,
+		.block_erasers	=
+		{
+			{
+				.eraseblocks = { {4 * 1024, 4096} },
+				.block_erase = spi_block_erase_20,
+			}, {
+				.eraseblocks = { {64 * 1024, 256} },
+				.block_erase = spi_block_erase_d8,
+			}, {
+				.eraseblocks = { {16 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_60,
+			}, {
+				.eraseblocks = { {16 * 1024 * 1024, 1} },
+				.block_erase = spi_block_erase_c7,
+			}
+		},
+		.unlock		= spi_disable_blockprotect,
+		.write		= spi_chip_write_256,
+		.read		= spi_chip_read,
+	},
+
+	{
+		.vendor		= "Eon",
 		.name		= "EN29F010",
 		.bustype	= CHIP_BUSTYPE_PARALLEL,
 		.manufacture_id	= EON_ID,
Index: flashchips.h
===================================================================
--- flashchips.h	(revision 1349)
+++ flashchips.h	(working copy)
@@ -232,7 +232,7 @@ 
 #define EON_EN25B64		0x2017	/* Same as P64 */
 #define EON_EN25B64T		0x46
 #define EON_EN25B64B		0x36
-#define EON_EN25D16		0x3015
+#define EON_EN25D16		0x3015	/* Same as EN25Q16 */
 #define EON_EN25F05		0x3110
 #define EON_EN25F10		0x3111
 #define EON_EN25F20		0x3112
@@ -240,6 +240,12 @@ 
 #define EON_EN25F80		0x3114
 #define EON_EN25F16		0x3115
 #define EON_EN25F32		0x3116
+#define EON_EN25Q40		0x3013
+#define EON_EN25Q80A		0x3014
+#define EON_EN25Q32		0x3016	/* Same as (A) and (B) */
+#define EON_EN25Q64		0x3017
+#define EON_EN25Q128		0x3018
+#define EON_EN25QH16		0x7015
 #define EON_EN29F512		0x7F21
 #define EON_EN29F010		0x20
 #define EON_EN29F040A		0x7F04