hw: m25p80: Add Block Protect and Top Bottom bits for write protect
Signed-off-by: Iris Chen <irischenlj@fb.com> Reviewed-by: Francisco Iglesias <frasse.iglesias@gmail.com> Message-Id: <20220708164552.3462620-1-irischenlj@fb.com> Signed-off-by: Cédric Le Goater <clg@kaod.org>
This commit is contained in:
parent
bceb4d994d
commit
2113a12897
@ -36,21 +36,19 @@
|
||||
#include "trace.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/* Fields for FlashPartInfo->flags */
|
||||
|
||||
/* erase capabilities */
|
||||
#define ER_4K 1
|
||||
#define ER_32K 2
|
||||
/* set to allow the page program command to write 0s back to 1. Useful for
|
||||
* modelling EEPROM with SPI flash command set
|
||||
*/
|
||||
#define EEPROM 0x100
|
||||
|
||||
/* 16 MiB max in 3 byte address mode */
|
||||
#define MAX_3BYTES_SIZE 0x1000000
|
||||
|
||||
#define SPI_NOR_MAX_ID_LEN 6
|
||||
|
||||
/* Fields for FlashPartInfo->flags */
|
||||
enum spi_flash_option_flags {
|
||||
ER_4K = BIT(0),
|
||||
ER_32K = BIT(1),
|
||||
EEPROM = BIT(2),
|
||||
HAS_SR_TB = BIT(3),
|
||||
HAS_SR_BP3_BIT6 = BIT(4),
|
||||
};
|
||||
|
||||
typedef struct FlashPartInfo {
|
||||
const char *part_name;
|
||||
/*
|
||||
@ -251,7 +249,8 @@ static const FlashPartInfo known_devices[] = {
|
||||
{ INFO("n25q512a11", 0x20bb20, 0, 64 << 10, 1024, ER_4K) },
|
||||
{ INFO("n25q512a13", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
|
||||
{ INFO("n25q128", 0x20ba18, 0, 64 << 10, 256, 0) },
|
||||
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512, ER_4K) },
|
||||
{ INFO("n25q256a", 0x20ba19, 0, 64 << 10, 512,
|
||||
ER_4K | HAS_SR_BP3_BIT6 | HAS_SR_TB) },
|
||||
{ INFO("n25q512a", 0x20ba20, 0, 64 << 10, 1024, ER_4K) },
|
||||
{ INFO("n25q512ax3", 0x20ba20, 0x1000, 64 << 10, 1024, ER_4K) },
|
||||
{ INFO("mt25ql512ab", 0x20ba20, 0x1044, 64 << 10, 1024, ER_4K | ER_32K) },
|
||||
@ -478,6 +477,11 @@ struct Flash {
|
||||
bool reset_enable;
|
||||
bool quad_enable;
|
||||
bool aai_enable;
|
||||
bool block_protect0;
|
||||
bool block_protect1;
|
||||
bool block_protect2;
|
||||
bool block_protect3;
|
||||
bool top_bottom_bit;
|
||||
bool status_register_write_disabled;
|
||||
uint8_t ear;
|
||||
|
||||
@ -623,12 +627,36 @@ void flash_write8(Flash *s, uint32_t addr, uint8_t data)
|
||||
{
|
||||
uint32_t page = addr / s->pi->page_size;
|
||||
uint8_t prev = s->storage[s->cur_addr];
|
||||
uint32_t block_protect_value = (s->block_protect3 << 3) |
|
||||
(s->block_protect2 << 2) |
|
||||
(s->block_protect1 << 1) |
|
||||
(s->block_protect0 << 0);
|
||||
|
||||
if (!s->write_enable) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "M25P80: write with write protect!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (block_protect_value > 0) {
|
||||
uint32_t num_protected_sectors = 1 << (block_protect_value - 1);
|
||||
uint32_t sector = addr / s->pi->sector_size;
|
||||
|
||||
/* top_bottom_bit == 0 means TOP */
|
||||
if (!s->top_bottom_bit) {
|
||||
if (s->pi->n_sectors <= sector + num_protected_sectors) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"M25P80: write with write protect!\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (sector < num_protected_sectors) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"M25P80: write with write protect!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((prev ^ data) & data) {
|
||||
trace_m25p80_programming_zero_to_one(s, addr, prev, data);
|
||||
}
|
||||
@ -726,6 +754,15 @@ static void complete_collecting_data(Flash *s)
|
||||
break;
|
||||
case WRSR:
|
||||
s->status_register_write_disabled = extract32(s->data[0], 7, 1);
|
||||
s->block_protect0 = extract32(s->data[0], 2, 1);
|
||||
s->block_protect1 = extract32(s->data[0], 3, 1);
|
||||
s->block_protect2 = extract32(s->data[0], 4, 1);
|
||||
if (s->pi->flags & HAS_SR_TB) {
|
||||
s->top_bottom_bit = extract32(s->data[0], 5, 1);
|
||||
}
|
||||
if (s->pi->flags & HAS_SR_BP3_BIT6) {
|
||||
s->block_protect3 = extract32(s->data[0], 6, 1);
|
||||
}
|
||||
|
||||
switch (get_man(s)) {
|
||||
case MAN_SPANSION:
|
||||
@ -1212,6 +1249,15 @@ static void decode_new_cmd(Flash *s, uint32_t value)
|
||||
case RDSR:
|
||||
s->data[0] = (!!s->write_enable) << 1;
|
||||
s->data[0] |= (!!s->status_register_write_disabled) << 7;
|
||||
s->data[0] |= (!!s->block_protect0) << 2;
|
||||
s->data[0] |= (!!s->block_protect1) << 3;
|
||||
s->data[0] |= (!!s->block_protect2) << 4;
|
||||
if (s->pi->flags & HAS_SR_TB) {
|
||||
s->data[0] |= (!!s->top_bottom_bit) << 5;
|
||||
}
|
||||
if (s->pi->flags & HAS_SR_BP3_BIT6) {
|
||||
s->data[0] |= (!!s->block_protect3) << 6;
|
||||
}
|
||||
|
||||
if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) {
|
||||
s->data[0] |= (!!s->quad_enable) << 6;
|
||||
@ -1552,6 +1598,11 @@ static void m25p80_reset(DeviceState *d)
|
||||
|
||||
s->wp_level = true;
|
||||
s->status_register_write_disabled = false;
|
||||
s->block_protect0 = false;
|
||||
s->block_protect1 = false;
|
||||
s->block_protect2 = false;
|
||||
s->block_protect3 = false;
|
||||
s->top_bottom_bit = false;
|
||||
|
||||
reset_memory(s);
|
||||
}
|
||||
@ -1638,6 +1689,32 @@ static const VMStateDescription vmstate_m25p80_write_protect = {
|
||||
}
|
||||
};
|
||||
|
||||
static bool m25p80_block_protect_needed(void *opaque)
|
||||
{
|
||||
Flash *s = (Flash *)opaque;
|
||||
|
||||
return s->block_protect0 ||
|
||||
s->block_protect1 ||
|
||||
s->block_protect2 ||
|
||||
s->block_protect3 ||
|
||||
s->top_bottom_bit;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_m25p80_block_protect = {
|
||||
.name = "m25p80/block_protect",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = m25p80_block_protect_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_BOOL(block_protect0, Flash),
|
||||
VMSTATE_BOOL(block_protect1, Flash),
|
||||
VMSTATE_BOOL(block_protect2, Flash),
|
||||
VMSTATE_BOOL(block_protect3, Flash),
|
||||
VMSTATE_BOOL(top_bottom_bit, Flash),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_m25p80 = {
|
||||
.name = "m25p80",
|
||||
.version_id = 0,
|
||||
@ -1670,6 +1747,7 @@ static const VMStateDescription vmstate_m25p80 = {
|
||||
&vmstate_m25p80_data_read_loop,
|
||||
&vmstate_m25p80_aai_enable,
|
||||
&vmstate_m25p80_write_protect,
|
||||
&vmstate_m25p80_block_protect,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user