Patchwork RFC: Set status register option

login
register
about
Submitter David Hendricks
Date 2010-05-13 20:38:10
Message ID <z2nec9b26621005131338r90a34f08xc31c54d3491a948d@mail.gmail.com>
Download mbox | patch
Permalink /patch/1323/
State RFC
Headers show

Comments

David Hendricks - 2010-05-13 20:38:10
Hello all,
I'd like to know what people's thoughts are on setting the status register
for SPI flash memories using Flashrom. It seems like a good fit for Flashrom
and would go a long way in helping OEMs/ODMs migrate away from crappy DOS
utilities to using Flashrom for mass production. I've attached a very lame
patch that adds a command-line option (-s or --set-status) to do this for
SPI chips.
David Hendricks - 2010-05-13 20:47:24
oops, almost forgot to sign-off for the patch:
Signed-off by: David Hendricks <dhendrix@google.com>

Sorry for the spam.
Carl-Daniel Hailfinger - 2010-05-13 21:25:04
On 13.05.2010 22:38, David Hendricks wrote:
> I'd like to know what people's thoughts are on setting the status register
> for SPI flash memories using Flashrom. It seems like a good fit for Flashrom
> and would go a long way in helping OEMs/ODMs migrate away from crappy DOS
> utilities to using Flashrom for mass production. I've attached a very lame
> patch that adds a command-line option (-s or --set-status) to do this for
> SPI chips.
>   

Interesting idea, but the integration into overall flashrom architecture
needs to be discussed further, considering both the internal code
interface as well as the user interface. Those interface problems are
related, but need to be solved independently to ensure one interface
doesn't enforce a suboptimal design of the other interface.

You mentioned OEMs/ODMs. Could you elaborate on the exact use cases for
this? A user interface needs to be usable and at least somewhat
future-proof.

If this is only about flash protection, an interface to set protection
regions would be in order. That interface would provide the needed
abstraction to handle non-SPI flash as well, and odd SPI flash with
extra protection registers. We were already discussing an internal
interface for this in the past, but the problem is fundamentally hard,
and so we settled for a simple unlock-all function until we have the
details sorted out. The user interface part hasn't even been started
yet. Vendor input on the user interface design is really appreciated.

However, if this SPI status register stuff is about more than just write
protection, we ought to make sure we don't mix the interfaces for stuff
that is conceptually independent but happens to be implemented in the
same register. For example, some SPI chips support changing sector sizes
by changing the status register. Others control AAI programming with
that register.

As such, I'd like to postpone merging this patch until we know enough
about the problem to make enlightened decisions.

Regards,
Carl-Daniel
David Hendricks - 2010-05-13 22:32:44
Thanks for the quick response!

On Thu, May 13, 2010 at 2:25 PM, Carl-Daniel Hailfinger <
c-d.hailfinger.devel.2006@gmx.net> wrote:

> On 13.05.2010 22:38, David Hendricks wrote:
> > I'd like to know what people's thoughts are on setting the status
> register
> > for SPI flash memories using Flashrom. It seems like a good fit for
> Flashrom
> > and would go a long way in helping OEMs/ODMs migrate away from crappy DOS
> > utilities to using Flashrom for mass production. I've attached a very
> lame
> > patch that adds a command-line option (-s or --set-status) to do this for
> > SPI chips.
> >
>
> Interesting idea, but the integration into overall flashrom architecture
> needs to be discussed further, considering both the internal code
> interface as well as the user interface. Those interface problems are
> related, but need to be solved independently to ensure one interface
> doesn't enforce a suboptimal design of the other interface.
>

Definitely, that's the whole point of the RFC after all :-) I definitely
share a desire to avoid suboptimal interface design, but would also really,
really like to use Flashrom's internals.

Maybe we could make a separate utility for this task and bundle it with
Flashrom? Basically the utility would be a copy of flashrom.c, but gutted to
only serve a few very specific tasks. Think of it as Flashrom for
manufacturing rather than Flashrom for everyday development.

On Thu, May 13, 2010 at 2:25 PM, Carl-Daniel Hailfinger <
c-d.hailfinger.devel.2006@gmx.net> wrote:

> You mentioned OEMs/ODMs. Could you elaborate on the exact use cases for
> this? A user interface needs to be usable and at least somewhat
> future-proof.
>

At some point early in manufacturing processes, non-volatile memory/memories
get set to desired values. The status register on SPI flash chips is one of
many examples. Flashrom could easily handle both setting of the status reg
and imaging of the production firmware image, which could make people very
happy.

In any case the user-interface does not need to be particularly
friendly. Flashrom could just a very abstraction layer for chip and host
chipset details. Feeding raw values into Flashrom to set the value of these
registers is perfectly fine.

To get a little more details, the usage case I have in mind is something
like:
1) Run "flashrom" with no args and scrape output to obtain chip info.
2) Generate desired status register value based on the chip info.
3) Feed desired status reg. value into Flashrom.

Steps 1) and 2) are optional depending on how many possible combinations of
flash chip the manufacturer wants to support.

On Thu, May 13, 2010 at 2:25 PM, Carl-Daniel Hailfinger <
c-d.hailfinger.devel.2006@gmx.net> wrote:

> If this is only about flash protection, an interface to set protection
> regions would be in order. That interface would provide the needed
> abstraction to handle non-SPI flash as well, and odd SPI flash with
> extra protection registers. We were already discussing an internal
> interface for this in the past, but the problem is fundamentally hard,
> and so we settled for a simple unlock-all function until we have the
> details sorted out. The user interface part hasn't even been started
> yet. Vendor input on the user interface design is really appreciated.
>
> However, if this SPI status register stuff is about more than just write
> protection, we ought to make sure we don't mix the interfaces for stuff
> that is conceptually independent but happens to be implemented in the
> same register. For example, some SPI chips support changing sector sizes
> by changing the status register. Others control AAI programming with
> that register.
>

Yes -- There are many things one might wish to change in the status register
and it would be very burdensome to try and present all this stuff in a nice
manner. I'd like to keep whatever we come up with stupid simple and keep
Flashrom's responsibilities limited to abstracting the host/chip interface
from higher-level logic.

Patch

Index: flash.h
===================================================================
--- flash.h	(revision 997)
+++ flash.h	(working copy)
@@ -213,6 +213,7 @@ 
 	int (*unlock) (struct flashchip *flash);
 	int (*write) (struct flashchip *flash, uint8_t *buf);
 	int (*read) (struct flashchip *flash, uint8_t *buf, int start, int len);
+	int (*set_status) (uint8_t value);
 
 	/* Some flash devices have an additional register space. */
 	chipaddr virtual_memory;
@@ -549,7 +550,7 @@ 
 char *strcat_realloc(char *dest, const char *src);
 void print_version(void);
 int selfcheck(void);
-int doit(struct flashchip *flash, int force, char *filename, int read_it, int write_it, int erase_it, int verify_it);
+int doit(struct flashchip *flash, int force, char *filename, int read_it, int write_it, int erase_it, int verify_it, int set_status, char *arg);
 
 #define OK 0
 #define NT 1    /* Not tested */
Index: spi25.c
===================================================================
--- spi25.c	(revision 997)
+++ spi25.c	(working copy)
@@ -760,6 +760,23 @@ 
 	return result;
 }
 
+int spi_set_status(uint8_t val)
+{
+	uint8_t old_status = spi_read_status_register();
+
+	/* these two functions might not be necessary, depending on the flash
+	   chip and chipset */
+	spi_write_enable();
+	spi_write_status_enable();
+
+	if (spi_write_status_register(val))
+		return -1;
+
+	msg_cinfo("old status: 0x%02x, current status: 0x%02x\n",
+	           old_status, spi_read_status_register());
+	return 0;
+}
+
 int spi_byte_program(int addr, uint8_t databyte)
 {
 	int result;
Index: flashchips.c
===================================================================
--- flashchips.c	(revision 997)
+++ flashchips.c	(working copy)
@@ -337,6 +337,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -371,6 +372,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -405,6 +407,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -439,6 +442,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -473,6 +477,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -507,6 +512,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -541,6 +547,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -575,6 +582,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -609,6 +617,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -643,6 +652,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -699,6 +709,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -733,6 +744,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -767,6 +779,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	/*The AT26DF321 has the same ID as the AT25DF321. */
@@ -783,6 +796,7 @@ 
 		.probe_timing	= TIMING_ZERO,
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	  },*/
 
 	{
@@ -1163,6 +1177,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1194,6 +1209,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1370,6 +1386,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1400,6 +1417,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1430,6 +1448,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1460,6 +1479,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1491,6 +1511,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1522,6 +1543,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1553,6 +1575,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1584,6 +1607,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1615,6 +1639,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1646,6 +1671,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1677,6 +1703,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1708,6 +1735,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1739,6 +1767,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1770,6 +1799,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1801,6 +1831,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1832,6 +1863,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1866,6 +1898,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1900,6 +1933,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1934,6 +1968,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1968,6 +2003,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -1999,6 +2035,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2030,6 +2067,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2061,6 +2099,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2092,6 +2131,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2573,6 +2613,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2604,6 +2645,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2638,6 +2680,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2672,6 +2715,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2706,6 +2750,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2740,6 +2785,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2771,6 +2817,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2802,6 +2849,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2833,6 +2881,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2864,6 +2913,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -2895,6 +2945,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3075,6 +3126,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3103,6 +3155,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3131,6 +3184,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3159,6 +3213,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3187,6 +3242,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3215,6 +3271,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3249,6 +3306,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3277,6 +3335,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3305,6 +3364,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3339,6 +3399,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3367,6 +3428,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3601,6 +3663,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3658,6 +3721,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3683,6 +3747,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3717,6 +3782,7 @@ 
 		},
 		.write		= spi_chip_write_1,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3751,6 +3817,7 @@ 
 		},
 		.write		= spi_chip_write_1,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3779,6 +3846,7 @@ 
 		},
 		.write		= spi_chip_write_1,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3813,6 +3881,7 @@ 
 		},
 		.write		= spi_chip_write_1,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3847,6 +3916,7 @@ 
 		},
 		.write		= spi_chip_write_1,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -3881,6 +3951,7 @@ 
 		},
 		.write		= spi_chip_write_1,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4661,6 +4732,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	/* The ST M25P05 is a bit of a problem. It has the same ID as the
@@ -4691,6 +4763,7 @@ 
 		},
 		.write		= spi_chip_write_1, /* 128 */
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4716,6 +4789,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	/* The ST M25P10 has the same problem as the M25P05. */
@@ -4742,6 +4816,7 @@ 
 		},
 		.write		= spi_chip_write_1, /* 128 */
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4767,6 +4842,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4792,6 +4868,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4817,6 +4894,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4842,6 +4920,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4867,6 +4946,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4892,6 +4972,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4917,6 +4998,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -4942,6 +5024,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -5623,6 +5706,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -5691,6 +5775,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -5719,6 +5804,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -5747,6 +5833,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -5775,6 +5862,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -5803,6 +5891,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -5837,6 +5926,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -5871,6 +5961,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
@@ -5905,6 +5996,7 @@ 
 		},
 		.write		= spi_chip_write_256,
 		.read		= spi_chip_read,
+		.set_status	= spi_set_status,
 	},
 
 	{
Index: cli_classic.c
===================================================================
--- cli_classic.c	(revision 997)
+++ cli_classic.c	(working copy)
@@ -51,6 +51,7 @@ 
 	     "   -v | --verify:                    verify flash against file\n"
 	     "   -n | --noverify:                  don't verify flash against file\n"
 	     "   -E | --erase:                     erase flash device\n"
+	     "   -s | --set-status:                set status / control register\n"
 	     "   -V | --verbose:                   more verbose output\n"
 	     "   -c | --chip <chipname>:           probe only for specified flash chip\n"
 #if INTERNAL_SUPPORT == 1
@@ -107,7 +108,7 @@ 
 	int opt;
 	int option_index = 0;
 	int force = 0;
-	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
+	int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0, set_status = 0;
 	int dont_verify_it = 0, list_supported = 0;
 #if PRINT_WIKI_SUPPORT == 1
 	int list_supported_wiki = 0;
@@ -116,9 +117,9 @@ 
 	int i;
 
 #if PRINT_WIKI_SUPPORT == 1
-	const char *optstring = "rRwvnVEfc:m:l:i:p:Lzh";
+	const char *optstring = "rRwvnVEfs:c:m:l:i:p:Lzh";
 #else
-	const char *optstring = "rRwvnVEfc:m:l:i:p:Lh";
+	const char *optstring = "rRwvnVEfs:c:m:l:i:p:Lh";
 #endif
 	static struct option long_options[] = {
 		{"read", 0, 0, 'r'},
@@ -126,6 +127,7 @@ 
 		{"erase", 0, 0, 'E'},
 		{"verify", 0, 0, 'v'},
 		{"noverify", 0, 0, 'n'},
+		{"set-status", required_argument, 0, 's'},
 		{"chip", 1, 0, 'c'},
 		{"mainboard", 1, 0, 'm'},
 		{"verbose", 0, 0, 'V'},
@@ -145,6 +147,8 @@ 
 	char *filename = NULL;
 
 	char *tempstr = NULL;
+	char *arg = NULL;
+	int rc = 0;
 
 	print_version();
 
@@ -192,6 +196,14 @@ 
 			}
 			verify_it = 1;
 			break;
+		case 's':
+			if (++operation_specified > 1) {
+				fprintf(stderr, "More than one operation "
+					"specified. Aborting.\n");
+				exit(1);
+			}
+			arg = strdup(optarg);
+			set_status = 1;
 		case 'n':
 			if (verify_it) {
 				fprintf(stderr, "--verify and --noverify are"
@@ -379,14 +391,14 @@ 
 		return 1;
 	}
 
-	if (!(read_it | write_it | verify_it | erase_it)) {
+	if (!(read_it | write_it | verify_it | erase_it | set_status)) {
 		printf("No operations were specified.\n");
 		// FIXME: flash writes stay enabled!
 		programmer_shutdown();
 		exit(1);
 	}
 
-	if (!filename && !erase_it) {
+	if (!filename && !erase_it && !set_status) {
 		printf("Error: No filename specified.\n");
 		// FIXME: flash writes stay enabled!
 		programmer_shutdown();
@@ -397,5 +409,8 @@ 
 	if (write_it && !dont_verify_it)
 		verify_it = 1;
 
-	return doit(flash, force, filename, read_it, write_it, erase_it, verify_it);
+	rc = doit(flash, force, filename, read_it, write_it, erase_it, verify_it, set_status, arg);
+	if (arg)
+		free(arg);
+	return rc;
 }
Index: flashrom.c
===================================================================
--- flashrom.c	(revision 997)
+++ flashrom.c	(working copy)
@@ -1265,7 +1265,7 @@ 
 /* This function signature is horrible. We need to design a better interface,
  * but right now it allows us to split off the CLI code.
  */
-int doit(struct flashchip *flash, int force, char *filename, int read_it, int write_it, int erase_it, int verify_it)
+int doit(struct flashchip *flash, int force, char *filename, int read_it, int write_it, int erase_it, int verify_it, int set_status, char *arg)
 {
 	uint8_t *buf;
 	unsigned long numbytes;
@@ -1303,6 +1303,24 @@ 
 			programmer_shutdown();
 			return 1;
 		}
+	} else if (set_status) {
+		uint8_t val = (uint8_t)strtoul(arg, NULL, 0);
+
+		if (!flash->set_status) {
+			msg_cerr("set-status not supported for this chip.\n");
+			programmer_shutdown();
+			return 1;
+		}
+
+		if (flash->unlock)
+			flash->unlock(flash);
+
+		msg_cinfo("writing %02x to control status register\n", val);
+		if (flash->set_status(val)) {
+			msg_cerr("FAILED\n");
+			programmer_shutdown();
+			return 1;
+		}
 	} else {
 		struct stat image_stat;
 
Index: chipdrivers.h
===================================================================
--- chipdrivers.h	(revision 997)
+++ chipdrivers.h	(working copy)
@@ -46,6 +46,7 @@ 
 int spi_chip_write_256(struct flashchip *flash, uint8_t *buf);
 int spi_chip_read(struct flashchip *flash, uint8_t *buf, int start, int len);
 uint8_t spi_read_status_register(void);
+int spi_set_status(uint8_t val);
 int spi_disable_blockprotect(void);
 int spi_byte_program(int addr, uint8_t databyte);
 int spi_nbyte_program(int addr, uint8_t *bytes, int len);