flashrom-gerrit
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
January 2021
- 1 participants
- 310 discussions
Change in ...flashrom[master]: manibuilder: Allow warnings in NetBSD and CentOS builds
by Nico Huber (Code Review) March 16, 2021
by Nico Huber (Code Review) March 16, 2021
March 16, 2021
Nico Huber has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/33339
Change subject: manibuilder: Allow warnings in NetBSD and CentOS builds
......................................................................
manibuilder: Allow warnings in NetBSD and CentOS builds
Their old compilers stumble because of `-Wmissing-braces`.
Change-Id: Ia9ee17fd1f0c8b191091f89ffbf44329c6521d7d
Signed-off-by: Nico Huber <nico.h(a)gmx.de>
---
M util/manibuilder/Makefile
1 file changed, 2 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/39/33339/1
diff --git a/util/manibuilder/Makefile b/util/manibuilder/Makefile
index d93abec..7f76c33 100644
--- a/util/manibuilder/Makefile
+++ b/util/manibuilder/Makefile
@@ -53,9 +53,10 @@
djgpp\:6.1.0: LIBS_BASE=../
djgpp\:6.1.0: MAKEARGS+=strip CONFIG_JLINK_SPI=no
$(ANITA_TAGS): MAKECMD=gmake
-$(ANITA_TAGS): MAKEARGS+=CONFIG_JLINK_SPI=no
+$(ANITA_TAGS): MAKEARGS+=CONFIG_JLINK_SPI=no WARNERROR=no
$(filter alpine% centos%,$(MULTIARCH_TAGS)): MAKEARGS+=CONFIG_JLINK_SPI=no
$(filter %-xenial %-stretch,$(MULTIARCH_TAGS)): MAKEARGS+=CONFIG_JLINK_SPI=no
+$(filter centos%,$(MULTIARCH_TAGS)): MAKEARGS+=WARNERROR=no
$(ALL_TAGS): export QUIET_SETUP=$(QUIET_TEST)
$(ALL_TAGS): %: %-check-build
$(QUIET_TEST)docker rm -f mani_$(call ident,$*) >/dev/null 2>&1 || true
--
To view, visit https://review.coreboot.org/c/flashrom/+/33339
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: Ia9ee17fd1f0c8b191091f89ffbf44329c6521d7d
Gerrit-Change-Number: 33339
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h(a)gmx.de>
Gerrit-MessageType: newchange
3
3
Change in ...flashrom[master]: manibuilder: Add libjaylink where possible, disable where not
by Nico Huber (Code Review) March 16, 2021
by Nico Huber (Code Review) March 16, 2021
March 16, 2021
Nico Huber has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/33338
Change subject: manibuilder: Add libjaylink where possible, disable where not
......................................................................
manibuilder: Add libjaylink where possible, disable where not
Change-Id: I2f7aebe602ebdb0a4748640e281b9a92146f0ca8
Signed-off-by: Nico Huber <nico.h(a)gmx.de>
---
M util/manibuilder/Dockerfile.debian-debootstrap
M util/manibuilder/Dockerfile.fedora
M util/manibuilder/Dockerfile.ubuntu-debootstrap
M util/manibuilder/Makefile
4 files changed, 10 insertions(+), 4 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/38/33338/1
diff --git a/util/manibuilder/Dockerfile.debian-debootstrap b/util/manibuilder/Dockerfile.debian-debootstrap
index c6648e8..ce201f8 100644
--- a/util/manibuilder/Dockerfile.debian-debootstrap
+++ b/util/manibuilder/Dockerfile.debian-debootstrap
@@ -5,8 +5,9 @@
apt-get -qq update && \
apt-get -qq upgrade && \
apt-get -qq dist-upgrade && \
- apt-get -qqy install gcc make git doxygen ccache \
+ apt-get -qqy install gcc make git doxygen ccache pkg-config \
libpci-dev libusb-dev libftdi-dev libusb-1.0-0-dev && \
+ { apt-get -qqy install libjaylink-dev || true; } && \
apt-get clean
USER mani
diff --git a/util/manibuilder/Dockerfile.fedora b/util/manibuilder/Dockerfile.fedora
index 927e487..319039b 100644
--- a/util/manibuilder/Dockerfile.fedora
+++ b/util/manibuilder/Dockerfile.fedora
@@ -3,7 +3,8 @@
RUN \
useradd -p locked -m mani && \
dnf install -q -y git gcc ccache make \
- pciutils-devel libusb-devel libusbx-devel libftdi-devel && \
+ pciutils-devel libusb-devel libusbx-devel libftdi-devel \
+ libjaylink-devel && \
dnf clean -q -y all
USER mani
diff --git a/util/manibuilder/Dockerfile.ubuntu-debootstrap b/util/manibuilder/Dockerfile.ubuntu-debootstrap
index f50047c..fe3ad1e 100644
--- a/util/manibuilder/Dockerfile.ubuntu-debootstrap
+++ b/util/manibuilder/Dockerfile.ubuntu-debootstrap
@@ -18,8 +18,9 @@
apt-get -qq update && \
apt-get -qq upgrade && \
apt-get -qq dist-upgrade && \
- apt-get -qqy install gcc make git doxygen ccache \
+ apt-get -qqy install gcc make git doxygen ccache pkg-config \
libpci-dev libusb-dev libftdi-dev libusb-1.0-0-dev && \
+ { apt-get -qqy install libjaylink-dev || true; } && \
apt-get clean
USER mani
diff --git a/util/manibuilder/Makefile b/util/manibuilder/Makefile
index 9b87f45..d93abec 100644
--- a/util/manibuilder/Makefile
+++ b/util/manibuilder/Makefile
@@ -51,8 +51,11 @@
djgpp\:6.1.0: CC=ccache i586-pc-msdosdjgpp-gcc
djgpp\:6.1.0: STRIP=i586-pc-msdosdjgpp-strip
djgpp\:6.1.0: LIBS_BASE=../
-djgpp\:6.1.0: MAKEARGS+=strip
+djgpp\:6.1.0: MAKEARGS+=strip CONFIG_JLINK_SPI=no
$(ANITA_TAGS): MAKECMD=gmake
+$(ANITA_TAGS): MAKEARGS+=CONFIG_JLINK_SPI=no
+$(filter alpine% centos%,$(MULTIARCH_TAGS)): MAKEARGS+=CONFIG_JLINK_SPI=no
+$(filter %-xenial %-stretch,$(MULTIARCH_TAGS)): MAKEARGS+=CONFIG_JLINK_SPI=no
$(ALL_TAGS): export QUIET_SETUP=$(QUIET_TEST)
$(ALL_TAGS): %: %-check-build
$(QUIET_TEST)docker rm -f mani_$(call ident,$*) >/dev/null 2>&1 || true
--
To view, visit https://review.coreboot.org/c/flashrom/+/33338
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I2f7aebe602ebdb0a4748640e281b9a92146f0ca8
Gerrit-Change-Number: 33338
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h(a)gmx.de>
Gerrit-MessageType: newchange
3
3
Change in ...flashrom[master]: manibuilder: Enable CONFIG_EVERYTHING=yes
by Nico Huber (Code Review) March 16, 2021
by Nico Huber (Code Review) March 16, 2021
March 16, 2021
Nico Huber has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/33337
Change subject: manibuilder: Enable CONFIG_EVERYTHING=yes
......................................................................
manibuilder: Enable CONFIG_EVERYTHING=yes
Change-Id: I4651b55744d730956aa8fda8fdfccbbd68cdda19
Signed-off-by: Nico Huber <nico.h(a)gmx.de>
---
M util/manibuilder/Makefile
1 file changed, 3 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/37/33337/1
diff --git a/util/manibuilder/Makefile b/util/manibuilder/Makefile
index b1e161c..9b87f45 100644
--- a/util/manibuilder/Makefile
+++ b/util/manibuilder/Makefile
@@ -4,6 +4,7 @@
CC := ccache cc
MAKECMD := make
+MAKEARGS := CONFIG_EVERYTHING=yes
spc :=
spc +=
@@ -50,7 +51,7 @@
djgpp\:6.1.0: CC=ccache i586-pc-msdosdjgpp-gcc
djgpp\:6.1.0: STRIP=i586-pc-msdosdjgpp-strip
djgpp\:6.1.0: LIBS_BASE=../
-djgpp\:6.1.0: TARGET=strip
+djgpp\:6.1.0: MAKEARGS+=strip
$(ANITA_TAGS): MAKECMD=gmake
$(ALL_TAGS): export QUIET_SETUP=$(QUIET_TEST)
$(ALL_TAGS): %: %-check-build
@@ -65,7 +66,7 @@
$(MAKECMD) clean && $(MAKECMD) -j$${CPUS:-1} CC='$(CC)' \
$(if $(STRIP),STRIP='$(STRIP)') \
$(if $(LIBS_BASE),LIBS_BASE='$(LIBS_BASE)') \
- $(TARGET)" \
+ $(MAKEARGS)" \
$(if $(QUIET_TEST),>/dev/null 2>&1) || echo $*: $$?
$(addsuffix -shell,$(ALL_TAGS)): %-shell: %-check-build
--
To view, visit https://review.coreboot.org/c/flashrom/+/33337
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I4651b55744d730956aa8fda8fdfccbbd68cdda19
Gerrit-Change-Number: 33337
Gerrit-PatchSet: 1
Gerrit-Owner: Nico Huber <nico.h(a)gmx.de>
Gerrit-MessageType: newchange
3
4
Change in flashrom[master]: libflashrom: add querying functions with meson integration
by Michał Żygowski (Code Review) March 13, 2021
by Michał Żygowski (Code Review) March 13, 2021
March 13, 2021
Hello ?ukasz Dmitrowski,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/flashrom/+/34363
to review the following change.
Change subject: libflashrom: add querying functions with meson integration
......................................................................
libflashrom: add querying functions with meson integration
Work based on lukasz.dmitrowski(a)gmail.com code
Change-Id: I49041b8fa5700dabe59fef0d2337339d34cd6c6f
Signed-off-by: Artur Raglis <artur.raglis(a)3mdeb.com>
Signed-off-by: Lukasz Dmitrowski <lukasz.dmitrowski(a)gmail.com>
---
M libflashrom.c
M libflashrom.h
M libflashrom.map
M meson.build
4 files changed, 187 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/63/34363/1
diff --git a/libflashrom.c b/libflashrom.c
index f90a22c..cc26835 100644
--- a/libflashrom.c
+++ b/libflashrom.c
@@ -103,7 +103,142 @@
* @{
*/
-/* TBD */
+/**
+ * @brief Returns flashrom version
+ * @return Flashrom version
+ */
+const char *flashrom_version_info(void)
+{
+ return flashrom_version;
+}
+
+/**
+ * @brief Returns list of supported programmers
+ * @return List of supported programmers
+ */
+const char **flashrom_supported_programmers(void)
+{
+ enum programmer p = 0;
+ const char **supported_programmers = NULL;
+ supported_programmers = malloc((PROGRAMMER_INVALID + 1) * sizeof(char*));
+
+ if (supported_programmers != NULL) {
+ for (; p < PROGRAMMER_INVALID; ++p) {
+ supported_programmers[p] = programmer_table[p].name;
+ }
+ } else {
+ msg_gerr("Memory allocation error!\n");
+ }
+
+ return supported_programmers;
+}
+
+/**
+ * @brief Returns list of supported flash chips
+ * @return List of supported flash chips
+ */
+flashrom_flashchip_info *flashrom_supported_flash_chips(void)
+{
+ int i = 0;
+ flashrom_flashchip_info *supported_flashchips = malloc(flashchips_size * sizeof(flashrom_flashchip_info));
+
+ if (supported_flashchips != NULL) {
+ for (; i < flashchips_size; ++i) {
+ supported_flashchips[i].vendor = flashchips[i].vendor;
+ supported_flashchips[i].name = flashchips[i].name;
+ supported_flashchips[i].tested.erase = (flashrom_test_state) flashchips[i].tested.erase;
+ supported_flashchips[i].tested.probe = (flashrom_test_state) flashchips[i].tested.probe;
+ supported_flashchips[i].tested.read = (flashrom_test_state) flashchips[i].tested.read;
+ supported_flashchips[i].tested.write = (flashrom_test_state) flashchips[i].tested.write;
+ supported_flashchips[i].total_size = flashchips[i].total_size;
+ }
+ } else {
+ msg_gerr("Memory allocation error!\n");
+ }
+
+ return supported_flashchips;
+}
+
+/**
+ * @brief Returns list of supported mainboards
+ * @return List of supported mainboards
+ */
+flashrom_board_info *flashrom_supported_boards(void)
+{
+ int boards_known_size = 0;
+ int i = 0;
+ const struct board_info *binfo = boards_known;
+
+ while ((binfo++)->vendor)
+ ++boards_known_size;
+ binfo = boards_known;
+ /* add place for {0} */
+ ++boards_known_size;
+
+ flashrom_board_info *supported_boards = malloc(boards_known_size * sizeof(flashrom_board_info));
+
+ if (supported_boards != NULL) {
+ for (; i < boards_known_size; ++i) {
+ supported_boards[i].vendor = binfo[i].vendor;
+ supported_boards[i].name = binfo[i].name;
+ supported_boards[i].working = binfo[i].working;
+ }
+ } else {
+ msg_gerr("Memory allocation error!\n");
+ }
+
+ return supported_boards;
+}
+
+/**
+ * @brief Returns list of supported chipsets
+ * @return List of supported chipsets
+ */
+flashrom_chipset_info *flashrom_supported_chipsets(void)
+{
+ int chipset_enables_size = 0;
+ int i = 0;
+ const struct penable *chipset = chipset_enables;
+
+ while ((chipset++)->vendor_name)
+ ++chipset_enables_size;
+ chipset = chipset_enables;
+ /* add place for {0}*/
+ ++chipset_enables_size;
+
+ flashrom_chipset_info *supported_chipsets = malloc(chipset_enables_size * sizeof(flashrom_chipset_info));
+
+ if (supported_chipsets != NULL) {
+ for (; i < chipset_enables_size; ++i) {
+ supported_chipsets[i].vendor = chipset[i].vendor_name;
+ supported_chipsets[i].chipset = chipset[i].device_name;
+ supported_chipsets[i].vendor_id = chipset[i].vendor_id;
+ supported_chipsets[i].chipset_id = chipset[i].device_id;
+ supported_chipsets[i].status = chipset[i].status;
+ }
+ } else {
+ msg_gerr("Memory allocation error!\n");
+ }
+
+ return supported_chipsets;
+}
+
+/**
+ * @brief Frees memory allocated by libflashrom API
+ * @param Pointer to block of memory which should be freed
+ * @return 0 on success
+ * 1 on null pointer error
+ */
+int flashrom_data_free(void *const p)
+{
+ if (!p) {
+ msg_gerr("flashrom_data_free - Null pointer!\n");
+ return 1;
+ } else {
+ free(p);
+ return 0;
+ }
+}
/** @} */ /* end flashrom-query */
diff --git a/libflashrom.h b/libflashrom.h
index 38c95d2..ebba16b 100644
--- a/libflashrom.h
+++ b/libflashrom.h
@@ -37,6 +37,50 @@
typedef int(flashrom_log_callback)(enum flashrom_log_level, const char *format, va_list);
void flashrom_set_log_callback(flashrom_log_callback *);
+/** @ingroup flashrom-query */
+typedef enum {
+ FLASHROM_TESTED_OK = 0,
+ FLASHROM_TESTED_NT = 1,
+ FLASHROM_TESTED_BAD = 2,
+ FLASHROM_TESTED_DEP = 3,
+ FLASHROM_TESTED_NA = 4,
+} flashrom_test_state;
+
+typedef struct flashrom_flashchip_info {
+ const char *vendor;
+ const char *name;
+ unsigned int total_size;
+ struct flashrom_tested {
+ flashrom_test_state probe;
+ flashrom_test_state read;
+ flashrom_test_state erase;
+ flashrom_test_state write;
+ } tested;
+} flashrom_flashchip_info;
+
+typedef struct flashrom_board_info {
+ const char *vendor;
+ const char *name;
+ flashrom_test_state working;
+} flashrom_board_info;
+
+typedef struct flashrom_chipset_info {
+ const char *vendor;
+ const char *chipset;
+ uint16_t vendor_id;
+ uint16_t chipset_id;
+ flashrom_test_state status;
+} flashrom_chipset_info;
+
+const char *flashrom_version_info(void);
+void flashrom_system_info(void);
+const char **flashrom_supported_programmers(void);
+flashrom_flashchip_info *flashrom_supported_flash_chips(void);
+flashrom_board_info *flashrom_supported_boards(void);
+flashrom_chipset_info *flashrom_supported_chipsets(void);
+int flashrom_data_free(void *const p);
+
+/** @ingroup flashrom-prog */
struct flashrom_programmer;
int flashrom_programmer_init(struct flashrom_programmer **, const char *prog_name, const char *prog_params);
int flashrom_programmer_shutdown(struct flashrom_programmer *);
diff --git a/libflashrom.map b/libflashrom.map
index 3c287ff..d6dd24d 100644
--- a/libflashrom.map
+++ b/libflashrom.map
@@ -1,7 +1,11 @@
LIBFLASHROM_1.0 {
global:
+ flashrom_board_info;
+ flashrom_chipset_info;
+ flashrom_data_free;
flashrom_flag_get;
flashrom_flag_set;
+ flashrom_flashchip_info;
flashrom_flash_erase;
flashrom_flash_getsize;
flashrom_flash_probe;
@@ -20,5 +24,8 @@
flashrom_programmer_shutdown;
flashrom_set_log_callback;
flashrom_shutdown;
+ flashrom_supported_programmers;
+ flashrom_system_info;
+ flashrom_version_info;
local: *;
};
diff --git a/meson.build b/meson.build
index 1923fdf..00f4a2f 100644
--- a/meson.build
+++ b/meson.build
@@ -68,8 +68,6 @@
srcs = []
need_libusb0 = false
-need_raw_access = false
-need_serial = false
# check for required symbols
if cc.has_function('clock_gettime')
--
To view, visit https://review.coreboot.org/c/flashrom/+/34363
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I49041b8fa5700dabe59fef0d2337339d34cd6c6f
Gerrit-Change-Number: 34363
Gerrit-PatchSet: 1
Gerrit-Owner: Michał Żygowski <michal.zygowski(a)3mdeb.com>
Gerrit-Reviewer: ?ukasz Dmitrowski <lukasz.dmitrowski(a)gmail.com>
Gerrit-MessageType: newchange
5
23
Change in flashrom[master]: Introduce `extract_programmer_param_toggle` helper
by Angel Pons (Code Review) March 12, 2021
by Angel Pons (Code Review) March 12, 2021
March 12, 2021
Angel Pons has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/46717 )
Change subject: Introduce `extract_programmer_param_toggle` helper
......................................................................
Introduce `extract_programmer_param_toggle` helper
This is useful to retrieve programmer params which can only be 0 or 1.
Change-Id: I2a27f36b0fbafc2113387ad82321f3d026811f5e
Signed-off-by: Angel Pons <th3fanbus(a)gmail.com>
---
M flashrom.c
M programmer.h
M realtek_mst_i2c_spi.c
3 files changed, 45 insertions(+), 27 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/17/46717/1
diff --git a/flashrom.c b/flashrom.c
index c18a04f..d574902 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -789,6 +789,39 @@
return extract_param(&programmer_param, param_name, ",");
}
+/*
+ * Extract a 'toggle' (on/off) value from a programmer parameter.
+ * Returns 0 on success, -1 on bad usage (in code or at runtime).
+ * If the parameter was not specified, 'value' remains unchanged.
+ */
+int extract_programmer_param_toggle(const char *param_name, int *value)
+{
+ if (!param_name || !value)
+ return -1;
+
+ char *param_str = extract_programmer_param(param_name);
+
+ if (!param_str)
+ return 0;
+
+ const char c = param_str[0];
+
+ free(param_str);
+
+ if (c == '1') {
+ *value = 1;
+ return 0;
+ }
+
+ if (c == '0') {
+ *value = 0;
+ return 0;
+ }
+
+ msg_perr("Incorrect toggle parameter format, %s = 1 or 0.\n", param_name);
+ return -1;
+}
+
/* Returns the number of well-defined erasers for a chip. */
static unsigned int count_usable_erasers(const struct flashctx *flash)
{
diff --git a/programmer.h b/programmer.h
index 9a7892d..34aac88 100644
--- a/programmer.h
+++ b/programmer.h
@@ -612,6 +612,7 @@
extern unsigned long flashbase;
unsigned int count_max_decode_exceedings(const struct flashctx *flash);
char *extract_programmer_param(const char *param_name);
+int extract_programmer_param_toggle(const char *param_name, int *value);
/* spi.c */
#define MAX_DATA_UNSPECIFIED 0
diff --git a/realtek_mst_i2c_spi.c b/realtek_mst_i2c_spi.c
index 538b07a..574087b 100644
--- a/realtek_mst_i2c_spi.c
+++ b/realtek_mst_i2c_spi.c
@@ -434,7 +434,7 @@
static int get_params(int *i2c_bus, int *reset, int *enter_isp)
{
- char *bus_str = NULL, *reset_str = NULL, *isp_str = NULL;
+ char *bus_str = NULL;
int ret = SPI_GENERIC_ERROR;
bus_str = extract_programmer_param("bus");
@@ -464,33 +464,17 @@
msg_perr("%s: Bus number not specified.\n", __func__);
}
- reset_str = extract_programmer_param("reset-mcu");
- if (reset_str) {
- if (reset_str[0] == '1')
- *reset = 1;
- else if (reset_str[0] == '0')
- *reset = 0;
- else {
- msg_perr("%s: Incorrect param format, reset-mcu=1 or 0.\n", __func__);
- ret = SPI_GENERIC_ERROR;
- }
- } else
- *reset = 0; /* Default behaviour is no MCU reset on tear-down. */
- free(reset_str);
+ /* Default behaviour is no MCU reset on tear-down. */
+ *reset = 0;
+ ret = extract_programmer_param_toggle("reset-mcu", reset);
+ if (ret)
+ goto _get_params_failed;
- isp_str = extract_programmer_param("enter-isp");
- if (isp_str) {
- if (isp_str[0] == '1')
- *enter_isp = 1;
- else if (isp_str[0] == '0')
- *enter_isp = 0;
- else {
- msg_perr("%s: Incorrect param format, enter-isp=1 or 0.\n", __func__);
- ret = SPI_GENERIC_ERROR;
- }
- } else
- *enter_isp = 1; /* Default behaviour is enter ISP on setup. */
- free(isp_str);
+ /* Default behaviour is enter ISP on setup. */
+ *enter_isp = 1;
+ ret = extract_programmer_param_toggle("enter-isp", enter_isp);
+ if (ret)
+ goto _get_params_failed;
_get_params_failed:
if (bus_str)
--
To view, visit https://review.coreboot.org/c/flashrom/+/46717
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: I2a27f36b0fbafc2113387ad82321f3d026811f5e
Gerrit-Change-Number: 46717
Gerrit-PatchSet: 1
Gerrit-Owner: Angel Pons <th3fanbus(a)gmail.com>
Gerrit-MessageType: newchange
3
6
Change in flashrom[master]: CHROMIUM: flashrom: update .tested field for EN25QH128
by Nikolai Artemiev (Code Review) March 11, 2021
by Nikolai Artemiev (Code Review) March 11, 2021
March 11, 2021
Hello Tim Chen,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/flashrom/+/48104
to review the following change.
Change subject: CHROMIUM: flashrom: update .tested field for EN25QH128
......................................................................
CHROMIUM: flashrom: update .tested field for EN25QH128
update .tested field from TEST_UNTESTED to TEST_OK_PREW
BUG=b:159768722
BRANCH=none
TEST=Flash Duffy bios
pass on running `flashrom_tester /usr/sbin/flashrom host`
Original-Change-Id: I9467588988c2cab0987737c53ace0832144ef169
Original-Signed-off-by: Tim Chen <tim-chen(a)quanta.corp-partner.google.com>
Original-Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/flashrom/…
Original-Reviewed-by: Edward O'Callaghan <quasisec(a)chromium.org>
Original-Commit-Queue: Edward O'Callaghan <quasisec(a)chromium.org>
(cherry picked from commit 045e05eb92e3dd826e8ce61973c0d1004195a3ff)
Change-Id: Ic111f1a9cc5c7b5b5100ddda362c11c91e8a4165
Signed-off-by: Nikolai Artemiev <nartemiev(a)google.com>
---
M flashchips.c
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/04/48104/1
diff --git a/flashchips.c b/flashchips.c
index c4ba4c6..d10bb91 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -4249,7 +4249,7 @@
.total_size = 1024,
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
- .tested = TEST_UNTESTED,
+ .tested = TEST_OK_PREW,
.probe = probe_spi_rdid,
.probe_timing = TIMING_ZERO,
.block_erasers =
--
To view, visit https://review.coreboot.org/c/flashrom/+/48104
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: Ic111f1a9cc5c7b5b5100ddda362c11c91e8a4165
Gerrit-Change-Number: 48104
Gerrit-PatchSet: 1
Gerrit-Owner: Nikolai Artemiev <nartemiev(a)google.com>
Gerrit-Reviewer: Tim Chen <tim-chen(a)quanta.corp-partner.google.com>
Gerrit-MessageType: newchange
2
5
March 7, 2021
Martijn Berger has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/39966 )
Change subject: pcidev: Fix typo
......................................................................
pcidev: Fix typo
Fix typo
Change-Id: If70834715a51dea4111ba56e85df0680ed25c7a4
Signed-off-by: Martijn Berger <martijn.berger(a)gmail.com>
---
M pcidev.c
M programmer.h
2 files changed, 3 insertions(+), 3 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/66/39966/1
diff --git a/pcidev.c b/pcidev.c
index 973acde..38b9380 100644
--- a/pcidev.c
+++ b/pcidev.c
@@ -30,7 +30,7 @@
TYPE_UNKNOWN
};
-int pci_bar_nuber_from_offset(int offset)
+int pci_bar_number_from_offset(int offset)
{
switch (offset) {
case PCI_BASE_ADDRESS_0:
@@ -63,7 +63,7 @@
headertype = pci_read_byte(dev, PCI_HEADER_TYPE) & 0x7f;
msg_pspew("PCI header type 0x%02x\n", headertype);
- bar_number = pci_bar_nuber_from_offset(bar);
+ bar_number = pci_bar_number_from_offset(bar);
if (PCI_LIB_VERSION >= 0x030500 && bar_number > -1) {
addr = dev->base_addr[bar_number];
diff --git a/programmer.h b/programmer.h
index 5d4c1d7..42f646b 100644
--- a/programmer.h
+++ b/programmer.h
@@ -190,7 +190,7 @@
// FIXME: This needs to be local, not global(?)
extern struct pci_access *pacc;
int pci_init_common(void);
-int pci_bar_nuber_from_offset(int offset);
+int pci_bar_number_from_offset(int offset);
uintptr_t pcidev_readbar(struct pci_dev *dev, int bar);
struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar);
/* rpci_write_* are reversible writes. The original PCI config space register
--
To view, visit https://review.coreboot.org/c/flashrom/+/39966
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: If70834715a51dea4111ba56e85df0680ed25c7a4
Gerrit-Change-Number: 39966
Gerrit-PatchSet: 1
Gerrit-Owner: Martijn Berger
Gerrit-MessageType: newchange
4
8
Change in flashrom[master]: Add writeprotect support
by Edward O'Callaghan (Code Review) March 1, 2021
by Edward O'Callaghan (Code Review) March 1, 2021
March 1, 2021
Edward O'Callaghan has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/40325 )
Change subject: Add writeprotect support
......................................................................
Add writeprotect support
[NOT-FOR-MERGE-(yet)]: PoC WIP.
BUG=b:153800563
BRANCH=none
TEST=builds
Change-Id: Id93b5a1cb2da476fa8a7dde41d7b963024117474
Signed-off-by: Edward O'Callaghan <quasisec(a)google.com>
---
M Makefile
M cli_classic.c
M flash.h
M meson.build
A writeprotect.c
A writeprotect.h
6 files changed, 2,722 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/25/40325/1
diff --git a/Makefile b/Makefile
index a533acf..a1bf898 100644
--- a/Makefile
+++ b/Makefile
@@ -589,7 +589,7 @@
CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \
sst28sf040.o 82802ab.o \
sst49lfxxxc.o sst_fwhub.o edi.o flashchips.o spi.o spi25.o spi25_statusreg.o \
- spi95.o opaque.o sfdp.o en29lv640b.o at45db.o
+ spi95.o opaque.o sfdp.o en29lv640b.o at45db.o writeprotect.o
###############################################################################
# Library code.
diff --git a/cli_classic.c b/cli_classic.c
index 73cc417..9e2d8e8 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -17,6 +17,7 @@
* GNU General Public License for more details.
*/
+#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
@@ -27,6 +28,7 @@
#include "flashchips.h"
#include "fmap.h"
#include "programmer.h"
+#include "writeprotect.h"
#include "libflashrom.h"
static void cli_classic_usage(const char *name)
@@ -116,6 +118,8 @@
int list_supported_wiki = 0;
#endif
int flash_name = 0, flash_size = 0;
+ int set_wp_range = 0, set_wp_region = 0, set_wp_enable = 0,
+ set_wp_disable = 0, wp_status = 0, wp_list = 0;
int read_it = 0, write_it = 0, erase_it = 0, verify_it = 0;
int dont_verify_it = 0, dont_verify_all = 0, list_supported = 0, operation_specified = 0;
struct flashrom_layout *layout = NULL;
@@ -127,6 +131,12 @@
OPTION_FLASH_CONTENTS,
OPTION_FLASH_NAME,
OPTION_FLASH_SIZE,
+ OPTION_WP_STATUS,
+ OPTION_WP_SET_RANGE,
+ OPTION_WP_SET_REGION,
+ OPTION_WP_ENABLE,
+ OPTION_WP_DISABLE,
+ OPTION_WP_LIST,
};
int ret = 0;
@@ -150,6 +160,12 @@
{"flash-name", 0, NULL, OPTION_FLASH_NAME},
{"flash-size", 0, NULL, OPTION_FLASH_SIZE},
{"get-size", 0, NULL, OPTION_FLASH_SIZE}, // (deprecated): back compatibility.
+ {"wp-status", 0, 0, OPTION_WP_STATUS},
+ {"wp-range", 0, 0, OPTION_WP_SET_RANGE},
+ {"wp-region", 1, 0, OPTION_WP_SET_REGION},
+ {"wp-enable", optional_argument, 0, OPTION_WP_ENABLE},
+ {"wp-disable", 0, 0, OPTION_WP_DISABLE},
+ {"wp-list", 0, 0, OPTION_WP_LIST},
{"list-supported", 0, NULL, 'L'},
{"list-supported-wiki", 0, NULL, 'z'},
{"programmer", 1, NULL, 'p'},
@@ -169,6 +185,7 @@
char *tempstr = NULL;
char *pparam = NULL;
struct layout_include_args *include_args = NULL;
+ char *wp_mode_opt = NULL;
flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
@@ -283,6 +300,23 @@
cli_classic_validate_singleop(&operation_specified);
flash_size = 1;
break;
+ case OPTION_WP_STATUS:
+ wp_status = 1;
+ break;
+ case OPTION_WP_LIST:
+ wp_list = 1;
+ break;
+ case OPTION_WP_SET_RANGE:
+ set_wp_range = 1;
+ break;
+ case OPTION_WP_ENABLE:
+ set_wp_enable = 1;
+ if (optarg)
+ wp_mode_opt = strdup(optarg);
+ break;
+ case OPTION_WP_DISABLE:
+ set_wp_disable = 1;
+ break;
case 'L':
cli_classic_validate_singleop(&operation_specified);
list_supported = 1;
@@ -562,11 +596,19 @@
goto out_shutdown;
}
- if (!(read_it | write_it | verify_it | erase_it | flash_name | flash_size)) {
+ if (!(read_it | write_it | verify_it | erase_it | flash_name | flash_size
+ | set_wp_range | set_wp_region | set_wp_enable |
+ set_wp_disable | wp_status | wp_list )) {
msg_ginfo("No operations were specified.\n");
goto out_shutdown;
}
+ if (set_wp_enable && set_wp_disable) {
+ msg_ginfo("Error: --wp-enable and --wp-disable are mutually exclusive\n");
+ ret = 1;
+ goto out_shutdown;
+ }
+
if (flash_name) {
if (fill_flash->chip->vendor && fill_flash->chip->name) {
printf("vendor=\"%s\" name=\"%s\"\n",
@@ -583,6 +625,110 @@
goto out_shutdown;
}
+ if (wp_status) {
+ if (fill_flash->chip->wp && fill_flash->chip->wp->wp_status) {
+ ret |= fill_flash->chip->wp->wp_status(fill_flash);
+ } else {
+ msg_gerr("Error: write protect is not supported "
+ "on this flash chip.\n");
+ ret = 1;
+ }
+ goto out_shutdown;
+ }
+
+ /* Note: set_wp_disable should be done before setting the range */
+ if (set_wp_disable) {
+ if (fill_flash->chip->wp && fill_flash->chip->wp->disable) {
+ ret |= fill_flash->chip->wp->disable(fill_flash);
+ } else {
+ msg_gerr("Error: write protect is not supported "
+ "on this flash chip.\n");
+ ret = 1;
+ goto out_shutdown;
+ }
+ }
+
+ if (!ret && set_wp_enable) {
+ enum wp_mode wp_mode;
+
+ if (wp_mode_opt)
+ wp_mode = get_wp_mode(wp_mode_opt);
+ else
+ wp_mode = WP_MODE_HARDWARE; /* default */
+
+ if (wp_mode == WP_MODE_UNKNOWN) {
+ msg_gerr("Error: Invalid WP mode: \"%s\"\n", wp_mode_opt);
+ ret = 1;
+ goto out_shutdown;
+ }
+
+ if (fill_flash->chip->wp && fill_flash->chip->wp->enable) {
+ ret |= fill_flash->chip->wp->enable(fill_flash, wp_mode);
+ } else {
+ msg_gerr("Error: write protect is not supported "
+ "on this flash chip.\n");
+ ret = 1;
+ goto out_shutdown;
+ }
+ }
+
+ if (wp_list) {
+ msg_ginfo("Valid write protection ranges:\n");
+ if (fill_flash->chip->wp && fill_flash->chip->wp->list_ranges) {
+ ret |= fill_flash->chip->wp->list_ranges(fill_flash);
+ } else {
+ msg_gerr("Error: write protect is not supported "
+ "on this flash chip.\n");
+ ret = 1;
+ }
+ goto out_shutdown;
+ }
+
+ if (set_wp_range || set_wp_region) {
+ if (set_wp_range && set_wp_region) {
+ msg_gerr("Error: Cannot use both --wp-range and "
+ "--wp-region simultaneously.\n");
+ ret = 1;
+ goto out_shutdown;
+ }
+
+ if (!fill_flash->chip->wp || !fill_flash->chip->wp->set_range) {
+ msg_gerr("Error: write protect is not supported "
+ "on this flash chip.\n");
+ ret = 1;
+ goto out_shutdown;
+ }
+ }
+
+ /* Note: set_wp_range must happen before set_wp_enable */
+ if (set_wp_range) {
+ unsigned int start, len;
+ char *endptr = NULL;
+
+ if ((argc - optind) != 2) {
+ msg_gerr("Error: invalid number of arguments\n");
+ ret = 1;
+ goto out_shutdown;
+ }
+
+ /* FIXME: add some error checking */
+ start = strtoul(argv[optind], &endptr, 0);
+ if (errno == ERANGE || errno == EINVAL || *endptr != '\0') {
+ msg_gerr("Error: value \"%s\" invalid\n", argv[optind]);
+ ret = 1;
+ goto out_shutdown;
+ }
+
+ len = strtoul(argv[optind + 1], &endptr, 0);
+ if (errno == ERANGE || errno == EINVAL || *endptr != '\0') {
+ msg_gerr("Error: value \"%s\" invalid\n", argv[optind + 1]);
+ ret = 1;
+ goto out_shutdown;
+ }
+
+ ret |= fill_flash->chip->wp->set_range(fill_flash, start, len);
+ }
+
if (layoutfile) {
layout = get_global_layout();
} else if (ifd && (flashrom_layout_read_from_ifd(&layout, fill_flash, NULL, 0) ||
diff --git a/flash.h b/flash.h
index 2f0143b..fefca9d 100644
--- a/flash.h
+++ b/flash.h
@@ -235,6 +235,8 @@
int (*unlock) (struct flashctx *flash);
int (*write) (struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+ uint8_t (*read_status) (const struct flashctx *flash);
+ int (*write_status) (const struct flashctx *flash, int status);
struct voltage {
uint16_t min;
uint16_t max;
@@ -243,6 +245,8 @@
/* SPI specific options (TODO: Make it a union in case other bustypes get specific options.) */
uint8_t wrea_override; /**< override opcode for write extended address register */
+
+ struct wp *wp;
};
struct flashrom_flashctx {
diff --git a/meson.build b/meson.build
index 699370a..38bf671 100644
--- a/meson.build
+++ b/meson.build
@@ -350,6 +350,7 @@
srcs += 'udelay.c'
srcs += 'w29ee011.c'
srcs += 'w39.c'
+srcs += 'writeprotect.c'
mapfile = 'libflashrom.map'
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
diff --git a/writeprotect.c b/writeprotect.c
new file mode 100644
index 0000000..f54ccad
--- /dev/null
+++ b/writeprotect.c
@@ -0,0 +1,2512 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include "flash.h"
+#include "flashchips.h"
+#include "chipdrivers.h"
+#include "spi.h"
+#include "writeprotect.h"
+
+/*
+ * The following procedures rely on look-up tables to match the user-specified
+ * range with the chip's supported ranges. This turned out to be the most
+ * elegant approach since diferent flash chips use different levels of
+ * granularity and methods to determine protected ranges. In other words,
+ * be stupid and simple since clever arithmetic will not work for many chips.
+ */
+
+struct wp_range {
+ unsigned int start; /* starting address */
+ unsigned int len; /* len */
+};
+
+enum bit_state {
+ OFF = 0,
+ ON = 1,
+ X = -1 /* don't care. Must be bigger than max # of bp. */
+};
+
+/*
+ * Generic write-protection schema for 25-series SPI flash chips. This assumes
+ * there is a status register that contains one or more consecutive bits which
+ * determine which address range is protected.
+ */
+
+struct status_register_layout {
+ int bp0_pos; /* position of BP0 */
+ int bp_bits; /* number of block protect bits */
+ int srp_pos; /* position of status register protect enable bit */
+};
+
+/*
+ * The following ranges and functions are useful for representing the
+ * writeprotect schema in which there are typically 5 bits of
+ * relevant information stored in status register 1:
+ * m.sec: This bit indicates the units (sectors vs. blocks)
+ * m.tb: The top-bottom bit indicates if the affected range is at the top of
+ * the flash memory's address space or at the bottom.
+ * bp: Bitmask representing the number of affected sectors/blocks.
+ */
+struct wp_range_descriptor {
+ struct modifier_bits m;
+ unsigned int bp; /* block protect bitfield */
+ struct wp_range range;
+};
+
+struct wp_context {
+ struct status_register_layout sr1; /* status register 1 */
+ struct wp_range_descriptor *descrs;
+
+ /*
+ * Some chips store modifier bits in one or more special control
+ * registers instead of the status register like many older SPI NOR
+ * flash chips did. get_modifier_bits() and set_modifier_bits() will do
+ * any chip-specific operations necessary to get/set these bit values.
+ */
+ int (*get_modifier_bits)(const struct flashctx *flash,
+ struct modifier_bits *m);
+ int (*set_modifier_bits)(const struct flashctx *flash,
+ struct modifier_bits *m);
+};
+
+struct w25q_status {
+ /* this maps to register layout -- do not change ordering */
+ unsigned char busy : 1;
+ unsigned char wel : 1;
+ unsigned char bp0 : 1;
+ unsigned char bp1 : 1;
+ unsigned char bp2 : 1;
+ unsigned char tb : 1;
+ unsigned char sec : 1;
+ unsigned char srp0 : 1;
+} __attribute__ ((packed));
+
+/* Status register for large flash layouts with 4 BP bits */
+struct w25q_status_large {
+ unsigned char busy : 1;
+ unsigned char wel : 1;
+ unsigned char bp0 : 1;
+ unsigned char bp1 : 1;
+ unsigned char bp2 : 1;
+ unsigned char bp3 : 1;
+ unsigned char tb : 1;
+ unsigned char srp0 : 1;
+} __attribute__ ((packed));
+
+struct w25q_status_2 {
+ unsigned char srp1 : 1;
+ unsigned char qe : 1;
+ unsigned char rsvd : 6;
+} __attribute__ ((packed));
+
+int w25_range_to_status(const struct flashctx *flash,
+ unsigned int start, unsigned int len,
+ struct w25q_status *status);
+int w25_status_to_range(const struct flashctx *flash,
+ const struct w25q_status *status,
+ unsigned int *start, unsigned int *len);
+
+/*
+ * Mask to extract write-protect enable and range bits
+ * Status register 1:
+ * SRP0: bit 7
+ * range(BP2-BP0): bit 4-2
+ * range(BP3-BP0): bit 5-2 (large chips)
+ * Status register 2:
+ * SRP1: bit 1
+ */
+#define MASK_WP_AREA (0x9C)
+#define MASK_WP_AREA_LARGE (0x9C)
+#define MASK_WP2_AREA (0x01)
+
+struct wp_range_descriptor en25f40_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 504 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 496 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 480 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 448 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 384 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 512 * 1024} },
+};
+
+struct wp_range_descriptor en25q40_ranges[] = {
+ { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 504 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 496 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 480 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0x0, {0x000000, 448 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 384 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 512 * 1024} },
+};
+
+struct wp_range_descriptor en25q80_ranges[] = {
+ { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 1016 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 1008 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 992 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 960 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 896 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 768 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 1024 * 1024} },
+};
+
+struct wp_range_descriptor en25q32_ranges[] = {
+ { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 4032 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 3968 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 3840 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 3584 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 3072 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 2048 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 4096 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x010000, 4032 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x020000, 3968 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x040000, 3840 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x080000, 3584 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x100000, 3072 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x200000, 2048 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 4096 * 1024} },
+};
+
+struct wp_range_descriptor en25q64_ranges[] = {
+ { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 8128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 8064 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 7936 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 7680 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 7168 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 6144 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 8192 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x010000, 8128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x020000, 8064 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x040000, 7936 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x080000, 7680 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x100000, 7168 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x200000, 6144 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 8192 * 1024} },
+};
+
+struct wp_range_descriptor en25q128_ranges[] = {
+ { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 16320 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 16256 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 16128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 15872 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 15360 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 14336 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 16384 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x010000, 16320 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x020000, 16256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x040000, 16128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x080000, 15872 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x100000, 15360 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x200000, 14336 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 16384 * 1024} },
+};
+
+struct wp_range_descriptor en25s64_ranges[] = {
+ { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 8064 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 7936 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 7680 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 7168 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 6144 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 4096 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 8192 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x7e0000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x7c0000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x780000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x700000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x600000, 2048 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x400000, 4096 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 8192 * 1024} },
+};
+
+/* mx25l1005 ranges also work for the mx25l1005c */
+static struct wp_range_descriptor mx25l1005_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = X, .tb = X }, 0x1, {0x010000, 64 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x2, {0x000000, 128 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x3, {0x000000, 128 * 1024} },
+};
+
+static struct wp_range_descriptor mx25l2005_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = X, .tb = X }, 0x1, {0x030000, 64 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x2, {0x020000, 128 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x3, {0x000000, 256 * 1024} },
+};
+
+static struct wp_range_descriptor mx25l4005_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = X, .tb = X }, 0x1, {0x070000, 64 * 1 * 1024} }, /* block 7 */
+ { .m = { .sec = X, .tb = X }, 0x2, {0x060000, 64 * 2 * 1024} }, /* blocks 6-7 */
+ { .m = { .sec = X, .tb = X }, 0x3, {0x040000, 64 * 4 * 1024} }, /* blocks 4-7 */
+ { .m = { .sec = X, .tb = X }, 0x4, {0x000000, 512 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x5, {0x000000, 512 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x6, {0x000000, 512 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 512 * 1024} },
+};
+
+static struct wp_range_descriptor mx25l8005_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = X, .tb = X }, 0x1, {0x0f0000, 64 * 1 * 1024} }, /* block 15 */
+ { .m = { .sec = X, .tb = X }, 0x2, {0x0e0000, 64 * 2 * 1024} }, /* blocks 14-15 */
+ { .m = { .sec = X, .tb = X }, 0x3, {0x0c0000, 64 * 4 * 1024} }, /* blocks 12-15 */
+ { .m = { .sec = X, .tb = X }, 0x4, {0x080000, 64 * 8 * 1024} }, /* blocks 8-15 */
+ { .m = { .sec = X, .tb = X }, 0x5, {0x000000, 1024 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x6, {0x000000, 1024 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 1024 * 1024} },
+};
+
+static struct wp_range_descriptor mx25l1605d_ranges[] = {
+ { .m = { .sec = X, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = X, .tb = 0 }, 0x1, {0x1f0000, 64 * 1 * 1024} }, /* block 31 */
+ { .m = { .sec = X, .tb = 0 }, 0x2, {0x1e0000, 64 * 2 * 1024} }, /* blocks 30-31 */
+ { .m = { .sec = X, .tb = 0 }, 0x3, {0x1c0000, 64 * 4 * 1024} }, /* blocks 28-31 */
+ { .m = { .sec = X, .tb = 0 }, 0x4, {0x180000, 64 * 8 * 1024} }, /* blocks 24-31 */
+ { .m = { .sec = X, .tb = 0 }, 0x5, {0x100000, 64 * 16 * 1024} }, /* blocks 16-31 */
+ { .m = { .sec = X, .tb = 0 }, 0x6, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
+ { .m = { .sec = X, .tb = 0 }, 0x7, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
+
+ { .m = { .sec = X, .tb = 1 }, 0x0, {0x000000, 2048 * 1024} },
+ { .m = { .sec = X, .tb = 1 }, 0x1, {0x000000, 2048 * 1024} },
+ { .m = { .sec = X, .tb = 1 }, 0x2, {0x000000, 64 * 16 * 1024} }, /* blocks 0-15 */
+ { .m = { .sec = X, .tb = 1 }, 0x3, {0x000000, 64 * 24 * 1024} }, /* blocks 0-23 */
+ { .m = { .sec = X, .tb = 1 }, 0x4, {0x000000, 64 * 28 * 1024} }, /* blocks 0-27 */
+ { .m = { .sec = X, .tb = 1 }, 0x5, {0x000000, 64 * 30 * 1024} }, /* blocks 0-29 */
+ { .m = { .sec = X, .tb = 1 }, 0x6, {0x000000, 64 * 31 * 1024} }, /* blocks 0-30 */
+ { .m = { .sec = X, .tb = 1 }, 0x7, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
+};
+
+/* FIXME: Is there an mx25l3205 (without a trailing letter)? */
+static struct wp_range_descriptor mx25l3205d_ranges[] = {
+ { .m = { .sec = X, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = X, .tb = 0 }, 0x1, {0x3f0000, 64 * 1024} },
+ { .m = { .sec = X, .tb = 0 }, 0x2, {0x3e0000, 128 * 1024} },
+ { .m = { .sec = X, .tb = 0 }, 0x3, {0x3c0000, 256 * 1024} },
+ { .m = { .sec = X, .tb = 0 }, 0x4, {0x380000, 512 * 1024} },
+ { .m = { .sec = X, .tb = 0 }, 0x5, {0x300000, 1024 * 1024} },
+ { .m = { .sec = X, .tb = 0 }, 0x6, {0x200000, 2048 * 1024} },
+ { .m = { .sec = X, .tb = 0 }, 0x7, {0x000000, 4096 * 1024} },
+
+ { .m = { .sec = X, .tb = 1 }, 0x0, {0x000000, 4096 * 1024} },
+ { .m = { .sec = X, .tb = 1 }, 0x1, {0x000000, 2048 * 1024} },
+ { .m = { .sec = X, .tb = 1 }, 0x2, {0x000000, 3072 * 1024} },
+ { .m = { .sec = X, .tb = 1 }, 0x3, {0x000000, 3584 * 1024} },
+ { .m = { .sec = X, .tb = 1 }, 0x4, {0x000000, 3840 * 1024} },
+ { .m = { .sec = X, .tb = 1 }, 0x5, {0x000000, 3968 * 1024} },
+ { .m = { .sec = X, .tb = 1 }, 0x6, {0x000000, 4032 * 1024} },
+ { .m = { .sec = X, .tb = 1 }, 0x7, {0x000000, 4096 * 1024} },
+};
+
+static struct wp_range_descriptor mx25u3235e_ranges[] = {
+ { .m = { .sec = X, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x3f0000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x3e0000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x3c0000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x380000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x300000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x200000, 2048 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0x000000, 4096 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0x0, {0x000000, 4096 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 2048 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 3072 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 3584 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 3840 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 3968 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 4032 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 4096 * 1024} },
+};
+
+static struct wp_range_descriptor mx25u6435e_ranges[] = {
+ { .m = { .sec = X, .tb = 0 }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x7f0000, 1 * 64 * 1024} }, /* block 127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x7e0000, 2 * 64 * 1024} }, /* blocks 126-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x7c0000, 4 * 64 * 1024} }, /* blocks 124-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x780000, 8 * 64 * 1024} }, /* blocks 120-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x700000, 16 * 64 * 1024} }, /* blocks 112-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x600000, 32 * 64 * 1024} }, /* blocks 96-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0x400000, 64 * 64 * 1024} }, /* blocks 64-127 */
+
+ { .m = { .sec = 0, .tb = 1 }, 0x0, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 96 * 64 * 1024} }, /* blocks 0-95 */
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 112 * 64 * 1024} }, /* blocks 0-111 */
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 120 * 64 * 1024} }, /* blocks 0-119 */
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 124 * 64 * 1024} }, /* blocks 0-123 */
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 126 * 64 * 1024} }, /* blocks 0-125 */
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 127 * 64 * 1024} }, /* blocks 0-126 */
+ { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 128 * 64 * 1024} }, /* blocks 0-127 */
+};
+
+#define MX25U12835E_TB (1 << 3)
+static struct wp_range_descriptor mx25u12835e_tb0_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0xff0000, 1 * 64 * 1024} }, /* block 255 */
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0xfe0000, 2 * 64 * 1024} }, /* blocks 254-255 */
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0xfc0000, 4 * 64 * 1024} }, /* blocks 252-255 */
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0xf80000, 8 * 64 * 1024} }, /* blocks 248-255 */
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0xf00000, 16 * 64 * 1024} }, /* blocks 240-255 */
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0xe00000, 32 * 64 * 1024} }, /* blocks 224-255 */
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0xc00000, 64 * 64 * 1024} }, /* blocks 192-255 */
+ { .m = { .sec = 0, .tb = 0 }, 0x8, {0x800000, 128 * 64 * 1024} }, /* blocks 128-255 */
+ { .m = { .sec = 0, .tb = 0 }, 0x9, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 0 }, 0xa, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 0 }, 0xb, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 0 }, 0xc, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 0 }, 0xd, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 0 }, 0xe, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 0 }, 0xf, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+};
+
+static struct wp_range_descriptor mx25u12835e_tb1_ranges[] = {
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 1 * 64 * 1024} }, /* block 0 */
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 2 * 64 * 1024} }, /* blocks 0-1 */
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 4 * 64 * 1024} }, /* blocks 0-3 */
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 8 * 64 * 1024} }, /* blocks 0-7 */
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 16 * 64 * 1024} }, /* blocks 0-15 */
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 32 * 64 * 1024} }, /* blocks 0-31 */
+ { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
+ { .m = { .sec = 0, .tb = 1 }, 0x8, {0x000000, 128 * 64 * 1024} }, /* blocks 0-127 */
+ { .m = { .sec = 0, .tb = 1 }, 0x9, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 1 }, 0xa, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 1 }, 0xb, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 1 }, 0xc, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 1 }, 0xd, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 1 }, 0xe, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+ { .m = { .sec = 0, .tb = 1 }, 0xf, {0x000000, 256 * 64 * 1024} }, /* blocks all */
+};
+
+static struct wp_range_descriptor n25q064_ranges[] = {
+ /*
+ * Note: For N25Q064, sec (usually in bit position 6) is called BP3
+ * (block protect bit 3). It is only useful when all blocks are to
+ * be write-protected.
+ */
+ { .m = { .sec = 0, .tb = 0 }, 0, {0, 0} }, /* none */
+
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x7f0000, 64 * 1024} }, /* block 127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x7e0000, 2 * 64 * 1024} }, /* blocks 126-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x7c0000, 4 * 64 * 1024} }, /* blocks 124-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x780000, 8 * 64 * 1024} }, /* blocks 120-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x700000, 16 * 64 * 1024} }, /* blocks 112-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x600000, 32 * 64 * 1024} }, /* blocks 96-127 */
+ { .m = { .sec = 0, .tb = 0 }, 0x7, {0x400000, 64 * 64 * 1024} }, /* blocks 64-127 */
+
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} }, /* block 0 */
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 2 * 64 * 1024} }, /* blocks 0-1 */
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 4 * 64 * 1024} }, /* blocks 0-3 */
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 8 * 64 * 1024} }, /* blocks 0-7 */
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 16 * 64 * 1024} }, /* blocks 0-15 */
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 32 * 64 * 1024} }, /* blocks 0-31 */
+ { .m = { .sec = 0, .tb = 1 }, 0x7, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
+
+ { .m = { .sec = X, .tb = 1 }, 0x0, {0x000000, 128 * 64 * 1024} }, /* all */
+ { .m = { .sec = X, .tb = 1 }, 0x1, {0x000000, 128 * 64 * 1024} }, /* all */
+ { .m = { .sec = X, .tb = 1 }, 0x2, {0x000000, 128 * 64 * 1024} }, /* all */
+ { .m = { .sec = X, .tb = 1 }, 0x3, {0x000000, 128 * 64 * 1024} }, /* all */
+ { .m = { .sec = X, .tb = 1 }, 0x4, {0x000000, 128 * 64 * 1024} }, /* all */
+ { .m = { .sec = X, .tb = 1 }, 0x5, {0x000000, 128 * 64 * 1024} }, /* all */
+ { .m = { .sec = X, .tb = 1 }, 0x6, {0x000000, 128 * 64 * 1024} }, /* all */
+ { .m = { .sec = X, .tb = 1 }, 0x7, {0x000000, 128 * 64 * 1024} }, /* all */
+};
+
+static struct wp_range_descriptor w25q16_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x1f0000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x1e0000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x1c0000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x180000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x100000, 1024 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 1024 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x6, {0x000000, 2048 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 2048 * 1024} },
+
+ { .m = { .sec = 1, .tb = 0 }, 0x1, {0x1ff000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x2, {0x1fe000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x3, {0x1fc000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x4, {0x1f8000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x5, {0x1f8000, 32 * 1024} },
+
+ { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
+};
+
+static struct wp_range_descriptor w25q32_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x3f0000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x3e0000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x3c0000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x380000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x300000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x200000, 2048 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 2048 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 4096 * 1024} },
+
+ { .m = { .sec = 1, .tb = 0 }, 0x1, {0x3ff000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x2, {0x3fe000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x3, {0x3fc000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x4, {0x3f8000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x5, {0x3f8000, 32 * 1024} },
+
+ { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
+};
+
+static struct wp_range_descriptor w25q80_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x0f0000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x0e0000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x0c0000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x080000, 512 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 512 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x6, {0x000000, 1024 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 1024 * 1024} },
+
+ { .m = { .sec = 1, .tb = 0 }, 0x1, {0x1ff000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x2, {0x1fe000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x3, {0x1fc000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x4, {0x1f8000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x5, {0x1f8000, 32 * 1024} },
+
+ { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
+};
+
+static struct wp_range_descriptor w25q64_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x7e0000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x7c0000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x780000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x700000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x600000, 2048 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x400000, 4096 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 2048 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 4096 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 8192 * 1024} },
+
+ { .m = { .sec = 1, .tb = 0 }, 0x1, {0x7ff000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x2, {0x7fe000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x3, {0x7fc000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x4, {0x7f8000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x5, {0x7f8000, 32 * 1024} },
+
+ { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
+};
+
+static struct wp_range_descriptor w25rq128_cmp0_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* NONE */
+
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0xfc0000, 256 * 1024} }, /* Upper 1/64 */
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0xf80000, 512 * 1024} }, /* Upper 1/32 */
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0xf00000, 1024 * 1024} }, /* Upper 1/16 */
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0xe00000, 2048 * 1024} }, /* Upper 1/8 */
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0xc00000, 4096 * 1024} }, /* Upper 1/4 */
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x800000, 8192 * 1024} }, /* Upper 1/2 */
+
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 256 * 1024} }, /* Lower 1/64 */
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 512 * 1024} }, /* Lower 1/32 */
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 1024 * 1024} }, /* Lower 1/16 */
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 2048 * 1024} }, /* Lower 1/8 */
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 4096 * 1024} }, /* Lower 1/4 */
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 8192 * 1024} }, /* Lower 1/2 */
+
+ { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 16384 * 1024} }, /* ALL */
+
+ { .m = { .sec = 1, .tb = 0 }, 0x1, {0xfff000, 4 * 1024} }, /* Upper 1/4096 */
+ { .m = { .sec = 1, .tb = 0 }, 0x2, {0xffe000, 8 * 1024} }, /* Upper 1/2048 */
+ { .m = { .sec = 1, .tb = 0 }, 0x3, {0xffc000, 16 * 1024} }, /* Upper 1/1024 */
+ { .m = { .sec = 1, .tb = 0 }, 0x4, {0xff8000, 32 * 1024} }, /* Upper 1/512 */
+ { .m = { .sec = 1, .tb = 0 }, 0x5, {0xff8000, 32 * 1024} }, /* Upper 1/512 */
+
+ { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} }, /* Lower 1/4096 */
+ { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} }, /* Lower 1/2048 */
+ { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} }, /* Lower 1/1024 */
+ { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} }, /* Lower 1/512 */
+ { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} }, /* Lower 1/512 */
+};
+
+static struct wp_range_descriptor w25rq128_cmp1_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0x0, {0x000000, 16 * 1024 * 1024} }, /* ALL */
+
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 16128 * 1024} }, /* Lower 63/64 */
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 15872 * 1024} }, /* Lower 31/32 */
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 15 * 1024 * 1024} }, /* Lower 15/16 */
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x000000, 14 * 1024 * 1024} }, /* Lower 7/8 */
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x000000, 12 * 1024 * 1024} }, /* Lower 3/4 */
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x000000, 8 * 1024 * 1024} }, /* Lower 1/2 */
+
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x040000, 16128 * 1024} }, /* Upper 63/64 */
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x080000, 15872 * 1024} }, /* Upper 31/32 */
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x100000, 15 * 1024 * 1024} }, /* Upper 15/16 */
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x200000, 14 * 1024 * 1024} }, /* Upper 7/8 */
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x400000, 12 * 1024 * 1024} }, /* Upper 3/4 */
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x800000, 8 * 1024 * 1024} }, /* Upper 1/2 */
+
+ { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 0} }, /* NONE */
+
+ { .m = { .sec = 1, .tb = 0 }, 0x1, {0x000000, 16380 * 1024} }, /* Lower 4095/4096 */
+ { .m = { .sec = 1, .tb = 0 }, 0x2, {0x000000, 16376 * 1024} }, /* Lower 2048/2048 */
+ { .m = { .sec = 1, .tb = 0 }, 0x3, {0x000000, 16368 * 1024} }, /* Lower 1023/1024 */
+ { .m = { .sec = 1, .tb = 0 }, 0x4, {0x000000, 16352 * 1024} }, /* Lower 511/512 */
+ { .m = { .sec = 1, .tb = 0 }, 0x5, {0x000000, 16352 * 1024} }, /* Lower 511/512 */
+
+ { .m = { .sec = 1, .tb = 1 }, 0x1, {0x001000, 16380 * 1024} }, /* Upper 4095/4096 */
+ { .m = { .sec = 1, .tb = 1 }, 0x2, {0x002000, 16376 * 1024} }, /* Upper 2047/2048 */
+ { .m = { .sec = 1, .tb = 1 }, 0x3, {0x004000, 16368 * 1024} }, /* Upper 1023/1024 */
+ { .m = { .sec = 1, .tb = 1 }, 0x4, {0x008000, 16352 * 1024} }, /* Upper 511/512 */
+ { .m = { .sec = 1, .tb = 1 }, 0x5, {0x008000, 16352 * 1024} }, /* Upper 511/512 */
+};
+
+static struct wp_range_descriptor w25rq256_cmp0_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0x0, {0x0000000, 0x0000000} }, /* NONE */
+
+ { .m = { .sec = X, .tb = 0 }, 0x1, {0x1ff0000, 64 * 1 * 1024} }, /* Upper 1/512 */
+ { .m = { .sec = X, .tb = 0 }, 0x2, {0x1fe0000, 64 * 2 * 1024} }, /* Upper 1/256 */
+ { .m = { .sec = X, .tb = 0 }, 0x3, {0x1fc0000, 64 * 4 * 1024} }, /* Upper 1/128 */
+ { .m = { .sec = X, .tb = 0 }, 0x4, {0x1f80000, 64 * 8 * 1024} }, /* Upper 1/64 */
+ { .m = { .sec = X, .tb = 0 }, 0x5, {0x1f00000, 64 * 16 * 1024} }, /* Upper 1/32 */
+ { .m = { .sec = X, .tb = 0 }, 0x6, {0x1e00000, 64 * 32 * 1024} }, /* Upper 1/16 */
+ { .m = { .sec = X, .tb = 0 }, 0x7, {0x1c00000, 64 * 64 * 1024} }, /* Upper 1/8 */
+ { .m = { .sec = X, .tb = 0 }, 0x8, {0x1800000, 64 * 128 * 1024} }, /* Upper 1/4 */
+ { .m = { .sec = X, .tb = 0 }, 0x9, {0x1000000, 64 * 256 * 1024} }, /* Upper 1/2 */
+
+ { .m = { .sec = X, .tb = 1 }, 0x1, {0x0000000, 64 * 1 * 1024} }, /* Lower 1/512 */
+ { .m = { .sec = X, .tb = 1 }, 0x2, {0x0000000, 64 * 2 * 1024} }, /* Lower 1/256 */
+ { .m = { .sec = X, .tb = 1 }, 0x3, {0x0000000, 64 * 4 * 1024} }, /* Lower 1/128 */
+ { .m = { .sec = X, .tb = 1 }, 0x4, {0x0000000, 64 * 8 * 1024} }, /* Lower 1/64 */
+ { .m = { .sec = X, .tb = 1 }, 0x5, {0x0000000, 64 * 16 * 1024} }, /* Lower 1/32 */
+ { .m = { .sec = X, .tb = 1 }, 0x6, {0x0000000, 64 * 32 * 1024} }, /* Lower 1/16 */
+ { .m = { .sec = X, .tb = 1 }, 0x7, {0x0000000, 64 * 64 * 1024} }, /* Lower 1/8 */
+ { .m = { .sec = X, .tb = 1 }, 0x8, {0x0000000, 64 * 128 * 1024} }, /* Lower 1/4 */
+ { .m = { .sec = X, .tb = 1 }, 0x9, {0x0000000, 64 * 256 * 1024} }, /* Lower 1/2 */
+
+ { .m = { .sec = X, .tb = X }, 0xa, {0x0000000, 64 * 512 * 1024} }, /* ALL */
+ { .m = { .sec = X, .tb = X }, 0xb, {0x0000000, 64 * 512 * 1024} }, /* ALL */
+ { .m = { .sec = X, .tb = X }, 0xc, {0x0000000, 64 * 512 * 1024} }, /* ALL */
+ { .m = { .sec = X, .tb = X }, 0xd, {0x0000000, 64 * 512 * 1024} }, /* ALL */
+ { .m = { .sec = X, .tb = X }, 0xe, {0x0000000, 64 * 512 * 1024} }, /* ALL */
+ { .m = { .sec = X, .tb = X }, 0xf, {0x0000000, 64 * 512 * 1024} }, /* ALL */
+};
+
+static struct wp_range_descriptor w25rq256_cmp1_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0x0, {0x0000000, 64 * 512 * 1024} }, /* ALL */
+
+ { .m = { .sec = X, .tb = 0 }, 0x1, {0x0000000, 64 * 511 * 1024} }, /* Lower 511/512 */
+ { .m = { .sec = X, .tb = 0 }, 0x2, {0x0000000, 64 * 510 * 1024} }, /* Lower 255/256 */
+ { .m = { .sec = X, .tb = 0 }, 0x3, {0x0000000, 64 * 508 * 1024} }, /* Lower 127/128 */
+ { .m = { .sec = X, .tb = 0 }, 0x4, {0x0000000, 64 * 504 * 1024} }, /* Lower 63/64 */
+ { .m = { .sec = X, .tb = 0 }, 0x5, {0x0000000, 64 * 496 * 1024} }, /* Lower 31/32 */
+ { .m = { .sec = X, .tb = 0 }, 0x6, {0x0000000, 64 * 480 * 1024} }, /* Lower 15/16 */
+ { .m = { .sec = X, .tb = 0 }, 0x7, {0x0000000, 64 * 448 * 1024} }, /* Lower 7/8 */
+ { .m = { .sec = X, .tb = 0 }, 0x8, {0x0000000, 64 * 384 * 1024} }, /* Lower 3/4 */
+ { .m = { .sec = X, .tb = 0 }, 0x9, {0x0000000, 64 * 256 * 1024} }, /* Lower 1/2 */
+
+ { .m = { .sec = X, .tb = 1 }, 0x1, {0x0010000, 64 * 511 * 1024} }, /* Upper 511/512 */
+ { .m = { .sec = X, .tb = 1 }, 0x2, {0x0020000, 64 * 510 * 1024} }, /* Upper 255/256 */
+ { .m = { .sec = X, .tb = 1 }, 0x3, {0x0040000, 64 * 508 * 1024} }, /* Upper 127/128 */
+ { .m = { .sec = X, .tb = 1 }, 0x4, {0x0080000, 64 * 504 * 1024} }, /* Upper 63/64 */
+ { .m = { .sec = X, .tb = 1 }, 0x5, {0x0100000, 64 * 496 * 1024} }, /* Upper 31/32 */
+ { .m = { .sec = X, .tb = 1 }, 0x6, {0x0200000, 64 * 480 * 1024} }, /* Upper 15/16 */
+ { .m = { .sec = X, .tb = 1 }, 0x7, {0x0400000, 64 * 448 * 1024} }, /* Upper 7/8 */
+ { .m = { .sec = X, .tb = 1 }, 0x8, {0x0800000, 64 * 384 * 1024} }, /* Upper 3/4 */
+ { .m = { .sec = X, .tb = 1 }, 0x9, {0x1000000, 64 * 256 * 1024} }, /* Upper 1/2 */
+
+ { .m = { .sec = X, .tb = X }, 0xa, {0x0000000, 0x0000000} }, /* NONE */
+ { .m = { .sec = X, .tb = X }, 0xb, {0x0000000, 0x0000000} }, /* NONE */
+ { .m = { .sec = X, .tb = X }, 0xc, {0x0000000, 0x0000000} }, /* NONE */
+ { .m = { .sec = X, .tb = X }, 0xd, {0x0000000, 0x0000000} }, /* NONE */
+ { .m = { .sec = X, .tb = X }, 0xe, {0x0000000, 0x0000000} }, /* NONE */
+ { .m = { .sec = X, .tb = X }, 0xf, {0x0000000, 0x0000000} }, /* NONE */
+};
+
+struct wp_range_descriptor w25x10_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x010000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x2, {0x000000, 128 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x3, {0x000000, 128 * 1024} },
+};
+
+struct wp_range_descriptor w25x20_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x030000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x020000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = X }, 0x3, {0x000000, 256 * 1024} },
+};
+
+struct wp_range_descriptor w25x40_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x070000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x060000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x040000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = X }, 0x4, {0x000000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = X }, 0x5, {0x000000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = X }, 0x6, {0x000000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = X }, 0x7, {0x000000, 512 * 1024} },
+};
+
+struct wp_range_descriptor w25x80_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x0F0000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x0E0000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x0C0000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x080000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = X }, 0x5, {0x000000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = X }, 0x6, {0x000000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = X }, 0x7, {0x000000, 1024 * 1024} },
+};
+
+static struct wp_range_descriptor gd25q40_cmp0_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* None */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x070000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x060000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x040000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 64 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = X }, 0x4, {0x000000, 512 * 1024} }, /* All */
+ { .m = { .sec = 0, .tb = X }, 0x5, {0x000000, 512 * 1024} }, /* All */
+ { .m = { .sec = 0, .tb = X }, 0x6, {0x000000, 512 * 1024} }, /* All */
+ { .m = { .sec = 0, .tb = X }, 0x7, {0x000000, 512 * 1024} }, /* All */
+ { .m = { .sec = 1, .tb = 0 }, 0x1, {0x07F000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x2, {0x07E000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x3, {0x07C000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x4, {0x078000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x5, {0x078000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x6, {0x078000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x6, {0x000000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = X }, 0x7, {0x000000, 512 * 1024} }, /* All */
+};
+
+static struct wp_range_descriptor gd25q40_cmp1_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0x0, {0x000000, 512 * 1024} }, /* ALL */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x000000, 448 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x000000, 384 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x000000, 256 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x010000, 448 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x020000, 384 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x040000, 256 * 1024} },
+
+ { .m = { .sec = 0, .tb = X }, 0x4, {0x000000, 0} }, /* None */
+ { .m = { .sec = 0, .tb = X }, 0x5, {0x000000, 0} }, /* None */
+ { .m = { .sec = 0, .tb = X }, 0x6, {0x000000, 0} }, /* None */
+ { .m = { .sec = 0, .tb = X }, 0x7, {0x000000, 0} }, /* None */
+
+ { .m = { .sec = 1, .tb = 0 }, 0x1, {0x000000, 508 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x2, {0x000000, 504 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x3, {0x000000, 496 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x4, {0x000000, 480 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x5, {0x000000, 480 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x6, {0x000000, 480 * 1024} },
+
+ { .m = { .sec = 1, .tb = 1 }, 0x1, {0x001000, 508 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x2, {0x002000, 504 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x3, {0x004000, 496 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x4, {0x008000, 480 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x5, {0x008000, 480 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x6, {0x008000, 480 * 1024} },
+
+ { .m = { .sec = 1, .tb = X }, 0x7, {0x000000, 0} }, /* None */
+};
+
+static struct wp_range_descriptor gd25q64_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0, {0, 0} }, /* none */
+ { .m = { .sec = 0, .tb = 0 }, 0x1, {0x7e0000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x2, {0x7c0000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x3, {0x780000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x4, {0x700000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x5, {0x600000, 2048 * 1024} },
+ { .m = { .sec = 0, .tb = 0 }, 0x6, {0x400000, 4096 * 1024} },
+
+ { .m = { .sec = 0, .tb = 1 }, 0x1, {0x000000, 128 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x2, {0x000000, 256 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x3, {0x000000, 512 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x4, {0x000000, 1024 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x5, {0x000000, 2048 * 1024} },
+ { .m = { .sec = 0, .tb = 1 }, 0x6, {0x000000, 4096 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x7, {0x000000, 8192 * 1024} },
+
+ { .m = { .sec = 1, .tb = 0 }, 0x1, {0x7ff000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x2, {0x7fe000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x3, {0x7fc000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x4, {0x7f8000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x5, {0x7f8000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 0 }, 0x6, {0x7f8000, 32 * 1024} },
+
+ { .m = { .sec = 1, .tb = 1 }, 0x1, {0x000000, 4 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x2, {0x000000, 8 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x3, {0x000000, 16 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x4, {0x000000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x5, {0x000000, 32 * 1024} },
+ { .m = { .sec = 1, .tb = 1 }, 0x6, {0x000000, 32 * 1024} },
+};
+
+static struct wp_range_descriptor a25l040_ranges[] = {
+ { .m = { .sec = X, .tb = X }, 0x0, {0, 0} }, /* none */
+ { .m = { .sec = X, .tb = X }, 0x1, {0x70000, 64 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x2, {0x60000, 128 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x3, {0x40000, 256 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x4, {0x00000, 512 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x5, {0x00000, 512 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x6, {0x00000, 512 * 1024} },
+ { .m = { .sec = X, .tb = X }, 0x7, {0x00000, 512 * 1024} },
+};
+
+static uint8_t do_read_status(const struct flashctx *flash)
+{
+ if (flash->chip->read_status)
+ return flash->chip->read_status(flash);
+ else
+ return spi_read_status_register(flash);
+}
+
+static int do_write_status(const struct flashctx *flash, int status)
+{
+ if (flash->chip->write_status)
+ return flash->chip->write_status(flash, status);
+ else
+ return spi_write_status_register(flash, status);
+}
+
+/* FIXME: Move to spi25.c if it's a JEDEC standard opcode */
+static uint8_t w25q_read_status_register_2(const struct flashctx *flash)
+{
+ static const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { 0x35 };
+ unsigned char readarr[2];
+ int ret;
+
+ /* Read Status Register */
+ ret = spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr);
+ if (ret) {
+ /*
+ * FIXME: make this a benign failure for now in case we are
+ * unable to execute the opcode
+ */
+ msg_cdbg("RDSR2 failed!\n");
+ readarr[0] = 0x00;
+ }
+
+ return readarr[0];
+}
+
+/* FIXME: Move to spi25.c if it's a JEDEC standard opcode */
+uint8_t mx25l_read_config_register(const struct flashctx *flash);//XXX
+uint8_t mx25l_read_config_register(const struct flashctx *flash)
+{
+ static const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { 0x15 };
+ unsigned char readarr[2]; /* leave room for dummy byte */
+ int ret;
+
+ ret = spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr);
+ if (ret) {
+ msg_cdbg("RDCR failed!\n");
+ readarr[0] = 0x00;
+ }
+
+ return readarr[0];
+}
+
+/* Given a flash chip, this function returns its range table. */
+static int w25_range_table(const struct flashctx *flash,
+ struct wp_range_descriptor **descrs,
+ int *num_entries)
+{
+ uint8_t cr;
+
+ *descrs = 0;
+ *num_entries = 0;
+
+ switch (flash->chip->manufacture_id) {
+ case WINBOND_NEX_ID:
+ switch(flash->chip->model_id) {
+ case WINBOND_NEX_W25X10:
+ *descrs = w25x10_ranges;
+ *num_entries = ARRAY_SIZE(w25x10_ranges);
+ break;
+ case WINBOND_NEX_W25X20:
+ *descrs = w25x20_ranges;
+ *num_entries = ARRAY_SIZE(w25x20_ranges);
+ break;
+ case WINBOND_NEX_W25X40:
+ *descrs = w25x40_ranges;
+ *num_entries = ARRAY_SIZE(w25x40_ranges);
+ break;
+ case WINBOND_NEX_W25X80:
+ *descrs = w25x80_ranges;
+ *num_entries = ARRAY_SIZE(w25x80_ranges);
+ break;
+ case WINBOND_NEX_W25Q80_V:
+ *descrs = w25q80_ranges;
+ *num_entries = ARRAY_SIZE(w25q80_ranges);
+ break;
+ case WINBOND_NEX_W25Q16_V:
+ *descrs = w25q16_ranges;
+ *num_entries = ARRAY_SIZE(w25q16_ranges);
+ break;
+ case WINBOND_NEX_W25Q32_V:
+ case WINBOND_NEX_W25Q32_W:
+ //case WINBOND_NEX_W25Q32JW:
+ *descrs = w25q32_ranges;
+ *num_entries = ARRAY_SIZE(w25q32_ranges);
+ break;
+ case WINBOND_NEX_W25Q64_V:
+ case WINBOND_NEX_W25Q64_W:
+ *descrs = w25q64_ranges;
+ *num_entries = ARRAY_SIZE(w25q64_ranges);
+ break;
+ case WINBOND_NEX_W25Q128_DTR:
+ case WINBOND_NEX_W25Q128_V_M:
+ case WINBOND_NEX_W25Q128_V:
+ case WINBOND_NEX_W25Q128_W:
+ if (w25q_read_status_register_2(flash) & (1 << 6)) {
+ /* CMP == 1 */
+ *descrs = w25rq128_cmp1_ranges;
+ *num_entries = ARRAY_SIZE(w25rq128_cmp1_ranges);
+ } else {
+ /* CMP == 0 */
+ *descrs = w25rq128_cmp0_ranges;
+ *num_entries = ARRAY_SIZE(w25rq128_cmp0_ranges);
+ }
+ break;
+ case WINBOND_NEX_W25Q256JV_M:
+ if (w25q_read_status_register_2(flash) & (1 << 6)) {
+ /* CMP == 1 */
+ *descrs = w25rq256_cmp1_ranges;
+ *num_entries = ARRAY_SIZE(w25rq256_cmp1_ranges);
+ } else {
+ /* CMP == 0 */
+ *descrs = w25rq256_cmp0_ranges;
+ *num_entries = ARRAY_SIZE(w25rq256_cmp0_ranges);
+ }
+ break;
+ default:
+ msg_cerr("%s() %d: WINBOND flash chip mismatch (0x%04x)"
+ ", aborting\n", __func__, __LINE__,
+ flash->chip->model_id);
+ return -1;
+ }
+ break;
+ case EON_ID_NOPREFIX:
+ switch (flash->chip->model_id) {
+ case EON_EN25F40:
+ *descrs = en25f40_ranges;
+ *num_entries = ARRAY_SIZE(en25f40_ranges);
+ break;
+ case EON_EN25Q40:
+ *descrs = en25q40_ranges;
+ *num_entries = ARRAY_SIZE(en25q40_ranges);
+ break;
+ case EON_EN25Q80:
+ *descrs = en25q80_ranges;
+ *num_entries = ARRAY_SIZE(en25q80_ranges);
+ break;
+ case EON_EN25Q32:
+ *descrs = en25q32_ranges;
+ *num_entries = ARRAY_SIZE(en25q32_ranges);
+ break;
+ case EON_EN25Q64:
+ *descrs = en25q64_ranges;
+ *num_entries = ARRAY_SIZE(en25q64_ranges);
+ break;
+ case EON_EN25Q128:
+ *descrs = en25q128_ranges;
+ *num_entries = ARRAY_SIZE(en25q128_ranges);
+ break;
+ case EON_EN25S64:
+ *descrs = en25s64_ranges;
+ *num_entries = ARRAY_SIZE(en25s64_ranges);
+ break;
+ default:
+ msg_cerr("%s():%d: EON flash chip mismatch (0x%04x)"
+ ", aborting\n", __func__, __LINE__,
+ flash->chip->model_id);
+ return -1;
+ }
+ break;
+ case MACRONIX_ID:
+ switch (flash->chip->model_id) {
+ case MACRONIX_MX25L1005:
+ *descrs = mx25l1005_ranges;
+ *num_entries = ARRAY_SIZE(mx25l1005_ranges);
+ break;
+ case MACRONIX_MX25L2005:
+ *descrs = mx25l2005_ranges;
+ *num_entries = ARRAY_SIZE(mx25l2005_ranges);
+ break;
+ case MACRONIX_MX25L4005:
+ *descrs = mx25l4005_ranges;
+ *num_entries = ARRAY_SIZE(mx25l4005_ranges);
+ break;
+ case MACRONIX_MX25L8005:
+ *descrs = mx25l8005_ranges;
+ *num_entries = ARRAY_SIZE(mx25l8005_ranges);
+ break;
+ case MACRONIX_MX25L1605:
+ /* FIXME: MX25L1605 and MX25L1605D have different write
+ * protection capabilities, but share IDs */
+ *descrs = mx25l1605d_ranges;
+ *num_entries = ARRAY_SIZE(mx25l1605d_ranges);
+ break;
+ case MACRONIX_MX25L3205:
+ *descrs = mx25l3205d_ranges;
+ *num_entries = ARRAY_SIZE(mx25l3205d_ranges);
+ break;
+ case MACRONIX_MX25U3235E:
+ *descrs = mx25u3235e_ranges;
+ *num_entries = ARRAY_SIZE(mx25u3235e_ranges);
+ break;
+ case MACRONIX_MX25U6435E:
+ *descrs = mx25u6435e_ranges;
+ *num_entries = ARRAY_SIZE(mx25u6435e_ranges);
+ break;
+ case MACRONIX_MX25U12835E:
+ cr = mx25l_read_config_register(flash);
+ if (cr & MX25U12835E_TB) { /* T/B == 1 */
+ *descrs = mx25u12835e_tb1_ranges;
+ *num_entries = ARRAY_SIZE(mx25u12835e_tb1_ranges);
+ } else { /* T/B == 0 */
+ *descrs = mx25u12835e_tb0_ranges;
+ *num_entries = ARRAY_SIZE(mx25u12835e_tb0_ranges);
+ }
+ break;
+ default:
+ msg_cerr("%s():%d: MXIC flash chip mismatch (0x%04x)"
+ ", aborting\n", __func__, __LINE__,
+ flash->chip->model_id);
+ return -1;
+ }
+ break;
+ case ST_ID:
+ switch(flash->chip->model_id) {
+ case ST_N25Q064__1E:
+ case ST_N25Q064__3E:
+ *descrs = n25q064_ranges;
+ *num_entries = ARRAY_SIZE(n25q064_ranges);
+ break;
+ default:
+ msg_cerr("%s() %d: Micron flash chip mismatch"
+ " (0x%04x), aborting\n", __func__, __LINE__,
+ flash->chip->model_id);
+ return -1;
+ }
+ break;
+ case GIGADEVICE_ID:
+ switch(flash->chip->model_id) {
+ case GIGADEVICE_GD25LQ32:
+ *descrs = w25q32_ranges;
+ *num_entries = ARRAY_SIZE(w25q32_ranges);
+ break;
+ case GIGADEVICE_GD25Q40:
+ if (w25q_read_status_register_2(flash) & (1 << 6)) {
+ /* CMP == 1 */
+ *descrs = gd25q40_cmp1_ranges;
+ *num_entries = ARRAY_SIZE(gd25q40_cmp1_ranges);
+ } else {
+ *descrs = gd25q40_cmp0_ranges;
+ *num_entries = ARRAY_SIZE(gd25q40_cmp0_ranges);
+ }
+ break;
+ case GIGADEVICE_GD25Q64:
+ case GIGADEVICE_GD25LQ64:
+ *descrs = gd25q64_ranges;
+ *num_entries = ARRAY_SIZE(gd25q64_ranges);
+ break;
+ case GIGADEVICE_GD25Q128:
+ case GIGADEVICE_GD25LQ128CD:
+ if (w25q_read_status_register_2(flash) & (1 << 6)) {
+ /* CMP == 1 */
+ *descrs = w25rq128_cmp1_ranges;
+ *num_entries = ARRAY_SIZE(w25rq128_cmp1_ranges);
+ } else {
+ /* CMP == 0 */
+ *descrs = w25rq128_cmp0_ranges;
+ *num_entries = ARRAY_SIZE(w25rq128_cmp0_ranges);
+ }
+ break;
+ case GIGADEVICE_GD25Q256D:
+ *descrs = w25rq256_cmp0_ranges;
+ *num_entries = ARRAY_SIZE(w25rq256_cmp0_ranges);
+ break;
+ default:
+ msg_cerr("%s() %d: GigaDevice flash chip mismatch"
+ " (0x%04x), aborting\n", __func__, __LINE__,
+ flash->chip->model_id);
+ return -1;
+ }
+ break;
+ case AMIC_ID_NOPREFIX:
+ switch(flash->chip->model_id) {
+ case AMIC_A25L040:
+ *descrs = a25l040_ranges;
+ *num_entries = ARRAY_SIZE(a25l040_ranges);
+ break;
+ default:
+ msg_cerr("%s() %d: AMIC flash chip mismatch"
+ " (0x%04x), aborting\n", __func__, __LINE__,
+ flash->chip->model_id);
+ return -1;
+ }
+ break;
+ case ATMEL_ID:
+ switch(flash->chip->model_id) {
+ //case ATMEL_AT25SF128A:
+ case ATMEL_AT25SL128A:
+ if (w25q_read_status_register_2(flash) & (1 << 6)) {
+ /* CMP == 1 */
+ *descrs = w25rq128_cmp1_ranges;
+ *num_entries = ARRAY_SIZE(w25rq128_cmp1_ranges);
+ } else {
+ /* CMP == 0 */
+ *descrs = w25rq128_cmp0_ranges;
+ *num_entries = ARRAY_SIZE(w25rq128_cmp0_ranges);
+ }
+ break;
+ default:
+ msg_cerr("%s() %d: Atmel flash chip mismatch"
+ " (0x%04x), aborting\n", __func__, __LINE__,
+ flash->chip->model_id);
+ return -1;
+ }
+ break;
+ default:
+ msg_cerr("%s: flash vendor (0x%x) not found, aborting\n",
+ __func__, flash->chip->manufacture_id);
+ return -1;
+ }
+
+ return 0;
+}
+
+int w25_range_to_status(const struct flashctx *flash,
+ unsigned int start, unsigned int len,
+ struct w25q_status *status)
+{
+ struct wp_range_descriptor *descrs;
+ int i, range_found = 0;
+ int num_entries;
+
+ if (w25_range_table(flash, &descrs, &num_entries))
+ return -1;
+
+ for (i = 0; i < num_entries; i++) {
+ struct wp_range *r = &descrs[i].range;
+
+ msg_cspew("comparing range 0x%x 0x%x / 0x%x 0x%x\n",
+ start, len, r->start, r->len);
+ if ((start == r->start) && (len == r->len)) {
+ status->bp0 = descrs[i].bp & 1;
+ status->bp1 = descrs[i].bp >> 1;
+ status->bp2 = descrs[i].bp >> 2;
+ status->tb = descrs[i].m.tb;
+ status->sec = descrs[i].m.sec;
+
+ range_found = 1;
+ break;
+ }
+ }
+
+ if (!range_found) {
+ msg_cerr("%s: matching range not found\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int w25_status_to_range(const struct flashctx *flash,
+ const struct w25q_status *status,
+ unsigned int *start, unsigned int *len)
+{
+ struct wp_range_descriptor *descrs;
+ int i, status_found = 0;
+ int num_entries;
+
+ if (w25_range_table(flash, &descrs, &num_entries))
+ return -1;
+
+ for (i = 0; i < num_entries; i++) {
+ int bp;
+ int table_bp, table_tb, table_sec;
+
+ bp = status->bp0 | (status->bp1 << 1) | (status->bp2 << 2);
+ msg_cspew("comparing 0x%x 0x%x / 0x%x 0x%x / 0x%x 0x%x\n",
+ bp, descrs[i].bp,
+ status->tb, descrs[i].m.tb,
+ status->sec, descrs[i].m.sec);
+ table_bp = descrs[i].bp;
+ table_tb = descrs[i].m.tb;
+ table_sec = descrs[i].m.sec;
+ if ((bp == table_bp || table_bp == X) &&
+ (status->tb == table_tb || table_tb == X) &&
+ (status->sec == table_sec || table_sec == X)) {
+ *start = descrs[i].range.start;
+ *len = descrs[i].range.len;
+
+ status_found = 1;
+ break;
+ }
+ }
+
+ if (!status_found) {
+ msg_cerr("matching status not found\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Given a [start, len], this function calls w25_range_to_status() to convert
+ * it to flash-chip-specific range bits, then sets into status register.
+ */
+static int w25_set_range(const struct flashctx *flash,
+ unsigned int start, unsigned int len)
+{
+ struct w25q_status status;
+ int tmp = 0;
+ int expected = 0;
+
+ memset(&status, 0, sizeof(status));
+ tmp = do_read_status(flash);
+ memcpy(&status, &tmp, 1);
+ msg_cdbg("%s: old status: 0x%02x\n", __func__, tmp);
+
+ if (w25_range_to_status(flash, start, len, &status))
+ return -1;
+
+ msg_cdbg("status.busy: %x\n", status.busy);
+ msg_cdbg("status.wel: %x\n", status.wel);
+ msg_cdbg("status.bp0: %x\n", status.bp0);
+ msg_cdbg("status.bp1: %x\n", status.bp1);
+ msg_cdbg("status.bp2: %x\n", status.bp2);
+ msg_cdbg("status.tb: %x\n", status.tb);
+ msg_cdbg("status.sec: %x\n", status.sec);
+ msg_cdbg("status.srp0: %x\n", status.srp0);
+
+ memcpy(&expected, &status, sizeof(status));
+ do_write_status(flash, expected);
+
+ tmp = do_read_status(flash);
+ msg_cdbg("%s: new status: 0x%02x\n", __func__, tmp);
+ if ((tmp & MASK_WP_AREA) != (expected & MASK_WP_AREA)) {
+ msg_cerr("expected=0x%02x, but actual=0x%02x.\n",
+ expected, tmp);
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Print out the current status register value with human-readable text. */
+static int w25_wp_status(const struct flashctx *flash)
+{
+ struct w25q_status status;
+ int tmp;
+ unsigned int start, len;
+ int ret = 0;
+
+ memset(&status, 0, sizeof(status));
+ tmp = do_read_status(flash);
+ memcpy(&status, &tmp, 1);
+ msg_cinfo("WP: status: 0x%02x\n", tmp);
+ msg_cinfo("WP: status.srp0: %x\n", status.srp0);
+ msg_cinfo("WP: write protect is %s.\n",
+ status.srp0 ? "enabled" : "disabled");
+
+ msg_cinfo("WP: write protect range: ");
+ if (w25_status_to_range(flash, &status, &start, &len)) {
+ msg_cinfo("(cannot resolve the range)\n");
+ ret = -1;
+ } else {
+ msg_cinfo("start=0x%08x, len=0x%08x\n", start, len);
+ }
+
+ return ret;
+}
+
+static int w25q_large_range_to_status(const struct flashctx *flash,
+ unsigned int start, unsigned int len,
+ struct w25q_status_large *status)
+{
+ struct wp_range_descriptor *descrs;
+ int i, range_found = 0;
+ int num_entries;
+
+ if (w25_range_table(flash, &descrs, &num_entries))
+ return -1;
+
+ for (i = 0; i < num_entries; i++) {
+ struct wp_range *r = &descrs[i].range;
+
+ msg_cspew("comparing range 0x%x 0x%x / 0x%x 0x%x\n",
+ start, len, r->start, r->len);
+ if ((start == r->start) && (len == r->len)) {
+ status->bp0 = descrs[i].bp & 1;
+ status->bp1 = descrs[i].bp >> 1;
+ status->bp2 = descrs[i].bp >> 2;
+ status->bp3 = descrs[i].bp >> 3;
+ /*
+ * For MX25U12835E chip, Top/Bottom (T/B) bit is not
+ * part of status register and in that bit position is
+ * Quad Enable (QE)
+ */
+ if (flash->chip->manufacture_id != MACRONIX_ID ||
+ flash->chip->model_id != MACRONIX_MX25U12835E)
+ status->tb = descrs[i].m.tb;
+
+ range_found = 1;
+ break;
+ }
+ }
+
+ if (!range_found) {
+ msg_cerr("%s: matching range not found\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int w25_large_status_to_range(const struct flashctx *flash,
+ const struct w25q_status_large *status,
+ unsigned int *start, unsigned int *len)
+{
+ struct wp_range_descriptor *descrs;
+ int i, status_found = 0;
+ int num_entries;
+
+ if (w25_range_table(flash, &descrs, &num_entries))
+ return -1;
+
+ for (i = 0; i < num_entries; i++) {
+ int bp;
+ int table_bp, table_tb;
+
+ bp = status->bp0 | (status->bp1 << 1) | (status->bp2 << 2) |
+ (status->bp3 << 3);
+ msg_cspew("comparing 0x%x 0x%x / 0x%x 0x%x\n",
+ bp, descrs[i].bp,
+ status->tb, descrs[i].m.tb);
+ table_bp = descrs[i].bp;
+ table_tb = descrs[i].m.tb;
+ if ((bp == table_bp || table_bp == X) &&
+ (status->tb == table_tb || table_tb == X)) {
+ *start = descrs[i].range.start;
+ *len = descrs[i].range.len;
+
+ status_found = 1;
+ break;
+ }
+ }
+
+ if (!status_found) {
+ msg_cerr("matching status not found\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Given a [start, len], this function calls w25_range_to_status() to convert
+ * it to flash-chip-specific range bits, then sets into status register.
+ * Returns 0 if successful, -1 on error, and 1 if reading back was different.
+ */
+static int w25q_large_set_range(const struct flashctx *flash,
+ unsigned int start, unsigned int len)
+{
+ struct w25q_status_large status;
+ int tmp;
+ int expected = 0;
+
+ memset(&status, 0, sizeof(status));
+ tmp = do_read_status(flash);
+ memcpy(&status, &tmp, 1);
+ msg_cdbg("%s: old status: 0x%02x\n", __func__, tmp);
+
+ if (w25q_large_range_to_status(flash, start, len, &status))
+ return -1;
+
+ msg_cdbg("status.busy: %x\n", status.busy);
+ msg_cdbg("status.wel: %x\n", status.wel);
+ msg_cdbg("status.bp0: %x\n", status.bp0);
+ msg_cdbg("status.bp1: %x\n", status.bp1);
+ msg_cdbg("status.bp2: %x\n", status.bp2);
+ msg_cdbg("status.bp3: %x\n", status.bp3);
+ msg_cdbg("status.tb: %x\n", status.tb);
+ msg_cdbg("status.srp0: %x\n", status.srp0);
+
+ memcpy(&expected, &status, sizeof(status));
+ do_write_status(flash, expected);
+
+ tmp = do_read_status(flash);
+ msg_cdbg("%s: new status: 0x%02x\n", __func__, tmp);
+ if ((tmp & MASK_WP_AREA_LARGE) != (expected & MASK_WP_AREA_LARGE)) {
+ msg_cerr("expected=0x%02x, but actual=0x%02x.\n",
+ expected, tmp);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int w25q_large_wp_status(const struct flashctx *flash)
+{
+ struct w25q_status_large sr1;
+ struct w25q_status_2 sr2;
+ uint8_t tmp[2];
+ unsigned int start, len;
+ int ret = 0;
+
+ memset(&sr1, 0, sizeof(sr1));
+ tmp[0] = do_read_status(flash);
+ memcpy(&sr1, &tmp[0], 1);
+
+ memset(&sr2, 0, sizeof(sr2));
+ tmp[1] = w25q_read_status_register_2(flash);
+ memcpy(&sr2, &tmp[1], 1);
+
+ msg_cinfo("WP: status: 0x%02x%02x\n", tmp[1], tmp[0]);
+ msg_cinfo("WP: status.srp0: %x\n", sr1.srp0);
+ msg_cinfo("WP: status.srp1: %x\n", sr2.srp1);
+ msg_cinfo("WP: write protect is %s.\n",
+ (sr1.srp0 || sr2.srp1) ? "enabled" : "disabled");
+
+ msg_cinfo("WP: write protect range: ");
+ if (w25_large_status_to_range(flash, &sr1, &start, &len)) {
+ msg_cinfo("(cannot resolve the range)\n");
+ ret = -1;
+ } else {
+ msg_cinfo("start=0x%08x, len=0x%08x\n", start, len);
+ }
+
+ return ret;
+}
+
+/* Set/clear the SRP0 bit in the status register. */
+static int w25_set_srp0(const struct flashctx *flash, int enable)
+{
+ struct w25q_status status;
+ int tmp = 0;
+ int expected = 0;
+
+ memset(&status, 0, sizeof(status));
+ tmp = do_read_status(flash);
+ /* FIXME: this is NOT endian-free copy. */
+ memcpy(&status, &tmp, 1);
+ msg_cdbg("%s: old status: 0x%02x\n", __func__, tmp);
+
+ status.srp0 = enable ? 1 : 0;
+ memcpy(&expected, &status, sizeof(status));
+ do_write_status(flash, expected);
+
+ tmp = do_read_status(flash);
+ msg_cdbg("%s: new status: 0x%02x\n", __func__, tmp);
+ if ((tmp & MASK_WP_AREA) != (expected & MASK_WP_AREA))
+ return 1;
+
+ return 0;
+}
+
+static int w25_enable_writeprotect(const struct flashctx *flash,
+ enum wp_mode wp_mode)
+{
+ int ret;
+
+ if (wp_mode != WP_MODE_HARDWARE) {
+ msg_cerr("%s(): unsupported write-protect mode\n", __func__);
+ return 1;
+ }
+
+ ret = w25_set_srp0(flash, 1);
+ if (ret)
+ msg_cerr("%s(): error=%d.\n", __func__, ret);
+ return ret;
+}
+
+static int w25_disable_writeprotect(const struct flashctx *flash)
+{
+ int ret;
+
+ ret = w25_set_srp0(flash, 0);
+ if (ret)
+ msg_cerr("%s(): error=%d.\n", __func__, ret);
+
+ return ret;
+}
+
+static int w25_list_ranges(const struct flashctx *flash)
+{
+ struct wp_range_descriptor *descrs;
+ int i, num_entries;
+
+ if (w25_range_table(flash, &descrs, &num_entries))
+ return -1;
+
+ for (i = 0; i < num_entries; i++) {
+ msg_cinfo("start: 0x%06x, length: 0x%06x\n",
+ descrs[i].range.start,
+ descrs[i].range.len);
+ }
+
+ return 0;
+}
+
+static int w25q_wp_status(const struct flashctx *flash)
+{
+ struct w25q_status sr1;
+ struct w25q_status_2 sr2;
+ uint8_t tmp[2];
+ unsigned int start, len;
+ int ret = 0;
+
+ memset(&sr1, 0, sizeof(sr1));
+ tmp[0] = do_read_status(flash);
+ memcpy(&sr1, &tmp[0], 1);
+
+ memset(&sr2, 0, sizeof(sr2));
+ tmp[1] = w25q_read_status_register_2(flash);
+ memcpy(&sr2, &tmp[1], 1);
+
+ msg_cinfo("WP: status: 0x%02x%02x\n", tmp[1], tmp[0]);
+ msg_cinfo("WP: status.srp0: %x\n", sr1.srp0);
+ msg_cinfo("WP: status.srp1: %x\n", sr2.srp1);
+ msg_cinfo("WP: write protect is %s.\n",
+ (sr1.srp0 || sr2.srp1) ? "enabled" : "disabled");
+
+ msg_cinfo("WP: write protect range: ");
+ if (w25_status_to_range(flash, &sr1, &start, &len)) {
+ msg_cinfo("(cannot resolve the range)\n");
+ ret = -1;
+ } else {
+ msg_cinfo("start=0x%08x, len=0x%08x\n", start, len);
+ }
+
+ return ret;
+}
+
+/*
+ * W25Q adds an optional byte to the standard WRSR opcode. If /CS is
+ * de-asserted after the first byte, then it acts like a JEDEC-standard
+ * WRSR command. if /CS is asserted, then the next data byte is written
+ * into status register 2.
+ */
+#define W25Q_WRSR_OUTSIZE 0x03
+static int w25q_write_status_register_WREN(const struct flashctx *flash, uint8_t s1, uint8_t s2)
+{
+ int result;
+ struct spi_command cmds[] = {
+ {
+ /* FIXME: WRSR requires either EWSR or WREN depending on chip type. */
+ .writecnt = JEDEC_WREN_OUTSIZE,
+ .writearr = (const unsigned char[]){ JEDEC_WREN },
+ .readcnt = 0,
+ .readarr = NULL,
+ }, {
+ .writecnt = W25Q_WRSR_OUTSIZE,
+ .writearr = (const unsigned char[]){ JEDEC_WRSR, s1, s2 },
+ .readcnt = 0,
+ .readarr = NULL,
+ }, {
+ .writecnt = 0,
+ .writearr = NULL,
+ .readcnt = 0,
+ .readarr = NULL,
+ }};
+
+ result = spi_send_multicommand(flash, cmds);
+ if (result) {
+ msg_cerr("%s failed during command execution\n",
+ __func__);
+ }
+
+ /* WRSR performs a self-timed erase before the changes take effect. */
+ programmer_delay(100 * 1000);
+
+ return result;
+}
+
+/*
+ * Set/clear the SRP1 bit in status register 2.
+ * FIXME: make this more generic if other chips use the same SR2 layout
+ */
+static int w25q_set_srp1(const struct flashctx *flash, int enable)
+{
+ struct w25q_status sr1;
+ struct w25q_status_2 sr2;
+ uint8_t tmp, expected;
+
+ tmp = do_read_status(flash);
+ memcpy(&sr1, &tmp, 1);
+ tmp = w25q_read_status_register_2(flash);
+ memcpy(&sr2, &tmp, 1);
+
+ msg_cdbg("%s: old status 2: 0x%02x\n", __func__, tmp);
+
+ sr2.srp1 = enable ? 1 : 0;
+
+ memcpy(&expected, &sr2, 1);
+ w25q_write_status_register_WREN(flash, *((uint8_t *)&sr1), *((uint8_t *)&sr2));
+
+ tmp = w25q_read_status_register_2(flash);
+ msg_cdbg("%s: new status 2: 0x%02x\n", __func__, tmp);
+ if ((tmp & MASK_WP2_AREA) != (expected & MASK_WP2_AREA))
+ return 1;
+
+ return 0;
+}
+
+enum wp_mode get_wp_mode(const char *mode_str)
+{
+ enum wp_mode wp_mode = WP_MODE_UNKNOWN;
+
+ if (!strcasecmp(mode_str, "hardware"))
+ wp_mode = WP_MODE_HARDWARE;
+ else if (!strcasecmp(mode_str, "power_cycle"))
+ wp_mode = WP_MODE_POWER_CYCLE;
+ else if (!strcasecmp(mode_str, "permanent"))
+ wp_mode = WP_MODE_PERMANENT;
+
+ return wp_mode;
+}
+
+static int w25q_disable_writeprotect(const struct flashctx *flash,
+ enum wp_mode wp_mode)
+{
+ int ret = 1;
+ struct w25q_status_2 sr2;
+ uint8_t tmp;
+
+ switch (wp_mode) {
+ case WP_MODE_HARDWARE:
+ ret = w25_set_srp0(flash, 0);
+ break;
+ case WP_MODE_POWER_CYCLE:
+ tmp = w25q_read_status_register_2(flash);
+ memcpy(&sr2, &tmp, 1);
+ if (sr2.srp1) {
+ msg_cerr("%s(): must disconnect power to disable "
+ "write-protection\n", __func__);
+ } else {
+ ret = 0;
+ }
+ break;
+ case WP_MODE_PERMANENT:
+ msg_cerr("%s(): cannot disable permanent write-protection\n",
+ __func__);
+ break;
+ default:
+ msg_cerr("%s(): invalid mode specified\n", __func__);
+ break;
+ }
+
+ if (ret)
+ msg_cerr("%s(): error=%d.\n", __func__, ret);
+
+ return ret;
+}
+
+static int w25q_disable_writeprotect_default(const struct flashctx *flash)
+{
+ return w25q_disable_writeprotect(flash, WP_MODE_HARDWARE);
+}
+
+static int w25q_enable_writeprotect(const struct flashctx *flash,
+ enum wp_mode wp_mode)
+{
+ int ret = 1;
+ struct w25q_status sr1;
+ struct w25q_status_2 sr2;
+ uint8_t tmp;
+
+ switch (wp_mode) {
+ case WP_MODE_HARDWARE:
+ if (w25q_disable_writeprotect(flash, WP_MODE_POWER_CYCLE)) {
+ msg_cerr("%s(): cannot disable power cycle WP mode\n",
+ __func__);
+ break;
+ }
+
+ tmp = do_read_status(flash);
+ memcpy(&sr1, &tmp, 1);
+ if (sr1.srp0)
+ ret = 0;
+ else
+ ret = w25_set_srp0(flash, 1);
+
+ break;
+ case WP_MODE_POWER_CYCLE:
+ if (w25q_disable_writeprotect(flash, WP_MODE_HARDWARE)) {
+ msg_cerr("%s(): cannot disable hardware WP mode\n",
+ __func__);
+ break;
+ }
+
+ tmp = w25q_read_status_register_2(flash);
+ memcpy(&sr2, &tmp, 1);
+ if (sr2.srp1)
+ ret = 0;
+ else
+ ret = w25q_set_srp1(flash, 1);
+
+ break;
+ case WP_MODE_PERMANENT:
+ tmp = do_read_status(flash);
+ memcpy(&sr1, &tmp, 1);
+ if (sr1.srp0 == 0) {
+ ret = w25_set_srp0(flash, 1);
+ if (ret) {
+ msg_perr("%s(): cannot enable SRP0 for "
+ "permanent WP\n", __func__);
+ break;
+ }
+ }
+
+ tmp = w25q_read_status_register_2(flash);
+ memcpy(&sr2, &tmp, 1);
+ if (sr2.srp1 == 0) {
+ ret = w25q_set_srp1(flash, 1);
+ if (ret) {
+ msg_perr("%s(): cannot enable SRP1 for "
+ "permanent WP\n", __func__);
+ break;
+ }
+ }
+
+ break;
+ default:
+ msg_perr("%s(): invalid mode %d\n", __func__, wp_mode);
+ break;
+ }
+
+ if (ret)
+ msg_cerr("%s(): error=%d.\n", __func__, ret);
+ return ret;
+}
+
+/* W25P, W25X, and many flash chips from various vendors */
+struct wp wp_w25 = {
+ .list_ranges = w25_list_ranges,
+ .set_range = w25_set_range,
+ .enable = w25_enable_writeprotect,
+ .disable = w25_disable_writeprotect,
+ .wp_status = w25_wp_status,
+
+};
+
+/* W25Q series has features such as a second status register and SFDP */
+struct wp wp_w25q = {
+ .list_ranges = w25_list_ranges,
+ .set_range = w25_set_range,
+ .enable = w25q_enable_writeprotect,
+ /*
+ * By default, disable hardware write-protection. We may change
+ * this later if we want to add fine-grained write-protect disable
+ * as a command-line option.
+ */
+ .disable = w25q_disable_writeprotect_default,
+ .wp_status = w25q_wp_status,
+};
+
+/* W25Q large series has 4 block-protect bits */
+struct wp wp_w25q_large = {
+ .list_ranges = w25_list_ranges,
+ .set_range = w25q_large_set_range,
+ .enable = w25q_enable_writeprotect,
+ /*
+ * By default, disable hardware write-protection. We may change
+ * this later if we want to add fine-grained write-protect disable
+ * as a command-line option.
+ */
+ .disable = w25q_disable_writeprotect_default,
+ .wp_status = w25q_large_wp_status,
+};
+
+struct wp_range_descriptor gd25q32_cmp0_ranges[] = {
+ /* none, bp4 and bp3 => don't care */
+ { { }, 0x00, {0, 0} },
+ { { }, 0x08, {0, 0} },
+ { { }, 0x10, {0, 0} },
+ { { }, 0x18, {0, 0} },
+
+ { { }, 0x01, {0x3f0000, 64 * 1024} },
+ { { }, 0x02, {0x3e0000, 128 * 1024} },
+ { { }, 0x03, {0x3c0000, 256 * 1024} },
+ { { }, 0x04, {0x380000, 512 * 1024} },
+ { { }, 0x05, {0x300000, 1024 * 1024} },
+ { { }, 0x06, {0x200000, 2048 * 1024} },
+
+ { { }, 0x09, {0x000000, 64 * 1024} },
+ { { }, 0x0a, {0x000000, 128 * 1024} },
+ { { }, 0x0b, {0x000000, 256 * 1024} },
+ { { }, 0x0c, {0x000000, 512 * 1024} },
+ { { }, 0x0d, {0x000000, 1024 * 1024} },
+ { { }, 0x0e, {0x000000, 2048 * 1024} },
+
+ /* all, bp4 and bp3 => don't care */
+ { { }, 0x07, {0x000000, 4096 * 1024} },
+ { { }, 0x0f, {0x000000, 4096 * 1024} },
+ { { }, 0x17, {0x000000, 4096 * 1024} },
+ { { }, 0x1f, {0x000000, 4096 * 1024} },
+
+ { { }, 0x11, {0x3ff000, 4 * 1024} },
+ { { }, 0x12, {0x3fe000, 8 * 1024} },
+ { { }, 0x13, {0x3fc000, 16 * 1024} },
+ { { }, 0x14, {0x3f8000, 32 * 1024} }, /* bp0 => don't care */
+ { { }, 0x15, {0x3f8000, 32 * 1024} }, /* bp0 => don't care */
+ { { }, 0x16, {0x3f8000, 32 * 1024} },
+
+ { { }, 0x19, {0x000000, 4 * 1024} },
+ { { }, 0x1a, {0x000000, 8 * 1024} },
+ { { }, 0x1b, {0x000000, 16 * 1024} },
+ { { }, 0x1c, {0x000000, 32 * 1024} }, /* bp0 => don't care */
+ { { }, 0x1d, {0x000000, 32 * 1024} }, /* bp0 => don't care */
+ { { }, 0x1e, {0x000000, 32 * 1024} },
+};
+
+struct wp_range_descriptor gd25q32_cmp1_ranges[] = {
+ /* All, bp4 and bp3 => don't care */
+ { { }, 0x00, {0x000000, 4096 * 1024} }, /* All */
+ { { }, 0x08, {0x000000, 4096 * 1024} },
+ { { }, 0x10, {0x000000, 4096 * 1024} },
+ { { }, 0x18, {0x000000, 4096 * 1024} },
+
+ { { }, 0x01, {0x000000, 4032 * 1024} },
+ { { }, 0x02, {0x000000, 3968 * 1024} },
+ { { }, 0x03, {0x000000, 3840 * 1024} },
+ { { }, 0x04, {0x000000, 3584 * 1024} },
+ { { }, 0x05, {0x000000, 3 * 1024 * 1024} },
+ { { }, 0x06, {0x000000, 2 * 1024 * 1024} },
+
+ { { }, 0x09, {0x010000, 4032 * 1024} },
+ { { }, 0x0a, {0x020000, 3968 * 1024} },
+ { { }, 0x0b, {0x040000, 3840 * 1024} },
+ { { }, 0x0c, {0x080000, 3584 * 1024} },
+ { { }, 0x0d, {0x100000, 3 * 1024 * 1024} },
+ { { }, 0x0e, {0x200000, 2 * 1024 * 1024} },
+
+ /* None, bp4 and bp3 => don't care */
+ { { }, 0x07, {0, 0} }, /* None */
+ { { }, 0x0f, {0, 0} },
+ { { }, 0x17, {0, 0} },
+ { { }, 0x1f, {0, 0} },
+
+ { { }, 0x11, {0x000000, 4092 * 1024} },
+ { { }, 0x12, {0x000000, 4088 * 1024} },
+ { { }, 0x13, {0x000000, 4080 * 1024} },
+ { { }, 0x14, {0x000000, 4064 * 1024} }, /* bp0 => don't care */
+ { { }, 0x15, {0x000000, 4064 * 1024} }, /* bp0 => don't care */
+ { { }, 0x16, {0x000000, 4064 * 1024} },
+
+ { { }, 0x19, {0x001000, 4092 * 1024} },
+ { { }, 0x1a, {0x002000, 4088 * 1024} },
+ { { }, 0x1b, {0x040000, 4080 * 1024} },
+ { { }, 0x1c, {0x080000, 4064 * 1024} }, /* bp0 => don't care */
+ { { }, 0x1d, {0x080000, 4064 * 1024} }, /* bp0 => don't care */
+ { { }, 0x1e, {0x080000, 4064 * 1024} },
+};
+
+static struct wp_context gd25q32_wp = {
+ /* TODO: map second status register */
+ .sr1 = { .bp0_pos = 2, .bp_bits = 5, .srp_pos = 7 },
+};
+
+struct wp_range_descriptor gd25q128_cmp0_ranges[] = {
+ /* none, bp4 and bp3 => don't care, others = 0 */
+ { { .tb = 0 }, 0x00, {0, 0} },
+ { { .tb = 0 }, 0x08, {0, 0} },
+ { { .tb = 0 }, 0x10, {0, 0} },
+ { { .tb = 0 }, 0x18, {0, 0} },
+
+ { { .tb = 0 }, 0x01, {0xfc0000, 256 * 1024} },
+ { { .tb = 0 }, 0x02, {0xf80000, 512 * 1024} },
+ { { .tb = 0 }, 0x03, {0xf00000, 1024 * 1024} },
+ { { .tb = 0 }, 0x04, {0xe00000, 2048 * 1024} },
+ { { .tb = 0 }, 0x05, {0xc00000, 4096 * 1024} },
+ { { .tb = 0 }, 0x06, {0x800000, 8192 * 1024} },
+
+ { { .tb = 0 }, 0x09, {0x000000, 256 * 1024} },
+ { { .tb = 0 }, 0x0a, {0x000000, 512 * 1024} },
+ { { .tb = 0 }, 0x0b, {0x000000, 1024 * 1024} },
+ { { .tb = 0 }, 0x0c, {0x000000, 2048 * 1024} },
+ { { .tb = 0 }, 0x0d, {0x000000, 4096 * 1024} },
+ { { .tb = 0 }, 0x0e, {0x000000, 8192 * 1024} },
+
+ /* all, bp4 and bp3 => don't care, others = 1 */
+ { { .tb = 0 }, 0x07, {0x000000, 16384 * 1024} },
+ { { .tb = 0 }, 0x0f, {0x000000, 16384 * 1024} },
+ { { .tb = 0 }, 0x17, {0x000000, 16384 * 1024} },
+ { { .tb = 0 }, 0x1f, {0x000000, 16384 * 1024} },
+
+ { { .tb = 0 }, 0x11, {0xfff000, 4 * 1024} },
+ { { .tb = 0 }, 0x12, {0xffe000, 8 * 1024} },
+ { { .tb = 0 }, 0x13, {0xffc000, 16 * 1024} },
+ { { .tb = 0 }, 0x14, {0xff8000, 32 * 1024} }, /* bp0 => don't care */
+ { { .tb = 0 }, 0x15, {0xff8000, 32 * 1024} }, /* bp0 => don't care */
+
+ { { .tb = 0 }, 0x19, {0x000000, 4 * 1024} },
+ { { .tb = 0 }, 0x1a, {0x000000, 8 * 1024} },
+ { { .tb = 0 }, 0x1b, {0x000000, 16 * 1024} },
+ { { .tb = 0 }, 0x1c, {0x000000, 32 * 1024} }, /* bp0 => don't care */
+ { { .tb = 0 }, 0x1d, {0x000000, 32 * 1024} }, /* bp0 => don't care */
+ { { .tb = 0 }, 0x1e, {0x000000, 32 * 1024} },
+};
+
+struct wp_range_descriptor gd25q128_cmp1_ranges[] = {
+ /* none, bp4 and bp3 => don't care, others = 0 */
+ { { .tb = 1 }, 0x00, {0x000000, 16384 * 1024} },
+ { { .tb = 1 }, 0x08, {0x000000, 16384 * 1024} },
+ { { .tb = 1 }, 0x10, {0x000000, 16384 * 1024} },
+ { { .tb = 1 }, 0x18, {0x000000, 16384 * 1024} },
+
+ { { .tb = 1 }, 0x01, {0x000000, 16128 * 1024} },
+ { { .tb = 1 }, 0x02, {0x000000, 15872 * 1024} },
+ { { .tb = 1 }, 0x03, {0x000000, 15360 * 1024} },
+ { { .tb = 1 }, 0x04, {0x000000, 14336 * 1024} },
+ { { .tb = 1 }, 0x05, {0x000000, 12288 * 1024} },
+ { { .tb = 1 }, 0x06, {0x000000, 8192 * 1024} },
+
+ { { .tb = 1 }, 0x09, {0x000000, 16128 * 1024} },
+ { { .tb = 1 }, 0x0a, {0x000000, 15872 * 1024} },
+ { { .tb = 1 }, 0x0b, {0x000000, 15360 * 1024} },
+ { { .tb = 1 }, 0x0c, {0x000000, 14336 * 1024} },
+ { { .tb = 1 }, 0x0d, {0x000000, 12288 * 1024} },
+ { { .tb = 1 }, 0x0e, {0x000000, 8192 * 1024} },
+
+ /* none, bp4 and bp3 => don't care, others = 1 */
+ { { .tb = 1 }, 0x07, {0x000000, 16384 * 1024} },
+ { { .tb = 1 }, 0x08, {0x000000, 16384 * 1024} },
+ { { .tb = 1 }, 0x0f, {0x000000, 16384 * 1024} },
+ { { .tb = 1 }, 0x17, {0x000000, 16384 * 1024} },
+ { { .tb = 1 }, 0x1f, {0x000000, 16384 * 1024} },
+
+ { { .tb = 1 }, 0x11, {0x000000, 16380 * 1024} },
+ { { .tb = 1 }, 0x12, {0x000000, 16376 * 1024} },
+ { { .tb = 1 }, 0x13, {0x000000, 16368 * 1024} },
+ { { .tb = 1 }, 0x14, {0x000000, 16352 * 1024} }, /* bp0 => don't care */
+ { { .tb = 1 }, 0x15, {0x000000, 16352 * 1024} }, /* bp0 => don't care */
+
+ { { .tb = 1 }, 0x19, {0x001000, 16380 * 1024} },
+ { { .tb = 1 }, 0x1a, {0x002000, 16376 * 1024} },
+ { { .tb = 1 }, 0x1b, {0x004000, 16368 * 1024} },
+ { { .tb = 1 }, 0x1c, {0x008000, 16352 * 1024} }, /* bp0 => don't care */
+ { { .tb = 1 }, 0x1d, {0x008000, 16352 * 1024} }, /* bp0 => don't care */
+ { { .tb = 1 }, 0x1e, {0x008000, 16352 * 1024} },
+};
+
+static struct wp_context gd25q128_wp = {
+ /* TODO: map second and third status registers */
+ .sr1 = { .bp0_pos = 2, .bp_bits = 5, .srp_pos = 7 },
+};
+
+/* FIXME: MX25L6406 has same ID as MX25L6405D */
+struct wp_range_descriptor mx25l6406e_ranges[] = {
+ { { }, 0, {0, 0} }, /* none */
+ { { }, 0x1, {0x7e0000, 64 * 2 * 1024} }, /* blocks 126-127 */
+ { { }, 0x2, {0x7c0000, 64 * 4 * 1024} }, /* blocks 124-127 */
+ { { }, 0x3, {0x7a0000, 64 * 8 * 1024} }, /* blocks 120-127 */
+ { { }, 0x4, {0x700000, 64 * 16 * 1024} }, /* blocks 112-127 */
+ { { }, 0x5, {0x600000, 64 * 32 * 1024} }, /* blocks 96-127 */
+ { { }, 0x6, {0x400000, 64 * 64 * 1024} }, /* blocks 64-127 */
+
+ { { }, 0x7, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0x8, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0x9, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
+ { { }, 0xa, {0x000000, 64 * 96 * 1024} }, /* blocks 0-95 */
+ { { }, 0xb, {0x000000, 64 * 112 * 1024} }, /* blocks 0-111 */
+ { { }, 0xc, {0x000000, 64 * 120 * 1024} }, /* blocks 0-119 */
+ { { }, 0xd, {0x000000, 64 * 124 * 1024} }, /* blocks 0-123 */
+ { { }, 0xe, {0x000000, 64 * 126 * 1024} }, /* blocks 0-125 */
+ { { }, 0xf, {0x000000, 64 * 128 * 1024} }, /* all */
+};
+
+static struct wp_context mx25l6406e_wp = {
+ .sr1 = { .bp0_pos = 2, .bp_bits = 4, .srp_pos = 7 },
+ .descrs = &mx25l6406e_ranges[0],
+};
+
+struct wp_range_descriptor mx25l6495f_tb0_ranges[] = {
+ { { }, 0, {0, 0} }, /* none */
+ { { }, 0x1, {0x7f0000, 64 * 1 * 1024} }, /* block 127 */
+ { { }, 0x2, {0x7e0000, 64 * 2 * 1024} }, /* blocks 126-127 */
+ { { }, 0x3, {0x7c0000, 64 * 4 * 1024} }, /* blocks 124-127 */
+
+ { { }, 0x4, {0x780000, 64 * 8 * 1024} }, /* blocks 120-127 */
+ { { }, 0x5, {0x700000, 64 * 16 * 1024} }, /* blocks 112-127 */
+ { { }, 0x6, {0x600000, 64 * 32 * 1024} }, /* blocks 96-127 */
+ { { }, 0x7, {0x400000, 64 * 64 * 1024} }, /* blocks 64-127 */
+ { { }, 0x8, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0x9, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xa, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xb, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xc, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xd, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xe, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xf, {0x000000, 64 * 128 * 1024} }, /* all */
+};
+
+struct wp_range_descriptor mx25l6495f_tb1_ranges[] = {
+ { { }, 0, {0, 0} }, /* none */
+ { { }, 0x1, {0x000000, 64 * 1 * 1024} }, /* block 0 */
+ { { }, 0x2, {0x000000, 64 * 2 * 1024} }, /* blocks 0-1 */
+ { { }, 0x3, {0x000000, 64 * 4 * 1024} }, /* blocks 0-3 */
+ { { }, 0x4, {0x000000, 64 * 8 * 1024} }, /* blocks 0-7 */
+ { { }, 0x5, {0x000000, 64 * 16 * 1024} }, /* blocks 0-15 */
+ { { }, 0x6, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
+ { { }, 0x7, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
+ { { }, 0x8, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0x9, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xa, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xb, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xc, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xd, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xe, {0x000000, 64 * 128 * 1024} }, /* all */
+ { { }, 0xf, {0x000000, 64 * 128 * 1024} }, /* all */
+};
+
+static struct wp_context mx25l6495f_wp = {
+ .sr1 = { .bp0_pos = 2, .bp_bits = 4, .srp_pos = 7 },
+};
+
+struct wp_range_descriptor mx25l25635f_tb0_ranges[] = {
+ { { }, 0, {0, 0} }, /* none */
+ { { }, 0x1, {0x1ff0000, 64 * 1 * 1024} }, /* block 511 */
+ { { }, 0x2, {0x1fe0000, 64 * 2 * 1024} }, /* blocks 510-511 */
+ { { }, 0x3, {0x1fc0000, 64 * 4 * 1024} }, /* blocks 508-511 */
+ { { }, 0x4, {0x1f80000, 64 * 8 * 1024} }, /* blocks 504-511 */
+ { { }, 0x5, {0x1f00000, 64 * 16 * 1024} }, /* blocks 496-511 */
+ { { }, 0x6, {0x1e00000, 64 * 32 * 1024} }, /* blocks 480-511 */
+ { { }, 0x7, {0x1c00000, 64 * 64 * 1024} }, /* blocks 448-511 */
+ { { }, 0x8, {0x1800000, 64 * 128 * 1024} }, /* blocks 384-511 */
+ { { }, 0x9, {0x1000000, 64 * 256 * 1024} }, /* blocks 256-511 */
+ { { }, 0xa, {0x0000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xb, {0x0000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xc, {0x0000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xd, {0x0000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xe, {0x0000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xf, {0x0000000, 64 * 512 * 1024} }, /* all */
+};
+
+struct wp_range_descriptor mx25l25635f_tb1_ranges[] = {
+ { { }, 0, {0, 0} }, /* none */
+ { { }, 0x1, {0x000000, 64 * 1 * 1024} }, /* block 0 */
+ { { }, 0x2, {0x000000, 64 * 2 * 1024} }, /* blocks 0-1 */
+ { { }, 0x3, {0x000000, 64 * 4 * 1024} }, /* blocks 0-3 */
+ { { }, 0x4, {0x000000, 64 * 8 * 1024} }, /* blocks 0-7 */
+ { { }, 0x5, {0x000000, 64 * 16 * 1024} }, /* blocks 0-15 */
+ { { }, 0x6, {0x000000, 64 * 32 * 1024} }, /* blocks 0-31 */
+ { { }, 0x7, {0x000000, 64 * 64 * 1024} }, /* blocks 0-63 */
+ { { }, 0x8, {0x000000, 64 * 128 * 1024} }, /* blocks 0-127 */
+ { { }, 0x9, {0x000000, 64 * 256 * 1024} }, /* blocks 0-255 */
+ { { }, 0xa, {0x000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xb, {0x000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xc, {0x000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xd, {0x000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xe, {0x000000, 64 * 512 * 1024} }, /* all */
+ { { }, 0xf, {0x000000, 64 * 512 * 1024} }, /* all */
+};
+
+static struct wp_context mx25l25635f_wp = {
+ .sr1 = { .bp0_pos = 2, .bp_bits = 4, .srp_pos = 7 },
+};
+
+#if 0
+struct wp_range_descriptor s25fs128s_ranges[] = {
+ { { .tb = 1 }, 0, {0, 0} }, /* none */
+ { { .tb = 1 }, 0x1, {0x000000, 256 * 1024} }, /* lower 64th */
+ { { .tb = 1 }, 0x2, {0x000000, 512 * 1024} }, /* lower 32nd */
+ { { .tb = 1 }, 0x3, {0x000000, 1024 * 1024} }, /* lower 16th */
+ { { .tb = 1 }, 0x4, {0x000000, 2048 * 1024} }, /* lower 8th */
+ { { .tb = 1 }, 0x5, {0x000000, 4096 * 1024} }, /* lower 4th */
+ { { .tb = 1 }, 0x6, {0x000000, 8192 * 1024} }, /* lower half */
+ { { .tb = 1 }, 0x7, {0x000000, 16384 * 1024} }, /* all */
+
+ { { .tb = 0 }, 0, {0, 0} }, /* none */
+ { { .tb = 0 }, 0x1, {0xfc0000, 256 * 1024} }, /* upper 64th */
+ { { .tb = 0 }, 0x2, {0xf80000, 512 * 1024} }, /* upper 32nd */
+ { { .tb = 0 }, 0x3, {0xf00000, 1024 * 1024} }, /* upper 16th */
+ { { .tb = 0 }, 0x4, {0xe00000, 2048 * 1024} }, /* upper 8th */
+ { { .tb = 0 }, 0x5, {0xc00000, 4096 * 1024} }, /* upper 4th */
+ { { .tb = 0 }, 0x6, {0x800000, 8192 * 1024} }, /* upper half */
+ { { .tb = 0 }, 0x7, {0x000000, 16384 * 1024} }, /* all */
+};
+
+static struct wp_context s25fs128s_wp = {
+ .sr1 = { .bp0_pos = 2, .bp_bits = 3, .srp_pos = 7 },
+ .get_modifier_bits = s25f_get_modifier_bits,
+ .set_modifier_bits = s25f_set_modifier_bits,
+};
+
+
+struct wp_range_descriptor s25fl256s_ranges[] = {
+ { { .tb = 1 }, 0, {0, 0} }, /* none */
+ { { .tb = 1 }, 0x1, {0x000000, 512 * 1024} }, /* lower 64th */
+ { { .tb = 1 }, 0x2, {0x000000, 1024 * 1024} }, /* lower 32nd */
+ { { .tb = 1 }, 0x3, {0x000000, 2048 * 1024} }, /* lower 16th */
+ { { .tb = 1 }, 0x4, {0x000000, 4096 * 1024} }, /* lower 8th */
+ { { .tb = 1 }, 0x5, {0x000000, 8192 * 1024} }, /* lower 4th */
+ { { .tb = 1 }, 0x6, {0x000000, 16384 * 1024} }, /* lower half */
+ { { .tb = 1 }, 0x7, {0x000000, 32768 * 1024} }, /* all */
+
+ { { .tb = 0 }, 0, {0, 0} }, /* none */
+ { { .tb = 0 }, 0x1, {0x1f80000, 512 * 1024} }, /* upper 64th */
+ { { .tb = 0 }, 0x2, {0x1f00000, 1024 * 1024} }, /* upper 32nd */
+ { { .tb = 0 }, 0x3, {0x1e00000, 2048 * 1024} }, /* upper 16th */
+ { { .tb = 0 }, 0x4, {0x1c00000, 4096 * 1024} }, /* upper 8th */
+ { { .tb = 0 }, 0x5, {0x1800000, 8192 * 1024} }, /* upper 4th */
+ { { .tb = 0 }, 0x6, {0x1000000, 16384 * 1024} }, /* upper half */
+ { { .tb = 0 }, 0x7, {0x000000, 32768 * 1024} }, /* all */
+};
+
+static struct wp_context s25fl256s_wp = {
+ .sr1 = { .bp0_pos = 2, .bp_bits = 3, .srp_pos = 7 },
+ .get_modifier_bits = s25f_get_modifier_bits,
+ .set_modifier_bits = s25f_set_modifier_bits,
+};
+#endif
+
+/* Given a flash chip, this function returns its writeprotect info. */
+static int generic_range_table(const struct flashctx *flash,
+ struct wp_context **wp,
+ int *num_entries)
+{
+ *wp = NULL;
+ *num_entries = 0;
+
+ switch (flash->chip->manufacture_id) {
+ case GIGADEVICE_ID:
+ switch(flash->chip->model_id) {
+
+ case GIGADEVICE_GD25LQ32:
+ case GIGADEVICE_GD25Q32: {
+ uint8_t sr1 = w25q_read_status_register_2(flash);
+ *wp = &gd25q32_wp;
+
+ if (!(sr1 & (1 << 6))) { /* CMP == 0 */
+ (*wp)->descrs = &gd25q32_cmp0_ranges[0];
+ *num_entries = ARRAY_SIZE(gd25q32_cmp0_ranges);
+ } else { /* CMP == 1 */
+ (*wp)->descrs = &gd25q32_cmp1_ranges[0];
+ *num_entries = ARRAY_SIZE(gd25q32_cmp1_ranges);
+ }
+
+ break;
+ }
+ case GIGADEVICE_GD25Q128:
+ case GIGADEVICE_GD25LQ128CD: {
+ uint8_t sr1 = w25q_read_status_register_2(flash);
+ *wp = &gd25q128_wp;
+
+ if (!(sr1 & (1 << 6))) { /* CMP == 0 */
+ (*wp)->descrs = &gd25q128_cmp0_ranges[0];
+ *num_entries = ARRAY_SIZE(gd25q128_cmp0_ranges);
+ } else { /* CMP == 1 */
+ (*wp)->descrs = &gd25q128_cmp1_ranges[0];
+ *num_entries = ARRAY_SIZE(gd25q128_cmp1_ranges);
+ }
+
+ break;
+ }
+ default:
+ msg_cerr("%s() %d: GigaDevice flash chip mismatch"
+ " (0x%04x), aborting\n", __func__, __LINE__,
+ flash->chip->model_id);
+ return -1;
+ }
+ break;
+ case MACRONIX_ID:
+ switch (flash->chip->model_id) {
+ case MACRONIX_MX25L6405:
+ /* FIXME: MX25L64* chips have mixed capabilities and
+ share IDs */
+ *wp = &mx25l6406e_wp;
+ *num_entries = ARRAY_SIZE(mx25l6406e_ranges);
+ break;
+ case MACRONIX_MX25L6495F: {
+ uint8_t cr = mx25l_read_config_register(flash);
+
+ *wp = &mx25l6495f_wp;
+ if (!(cr & (1 << 3))) { /* T/B == 0 */
+ (*wp)->descrs = &mx25l6495f_tb0_ranges[0];
+ *num_entries = ARRAY_SIZE(mx25l6495f_tb0_ranges);
+ } else { /* T/B == 1 */
+ (*wp)->descrs = &mx25l6495f_tb1_ranges[0];
+ *num_entries = ARRAY_SIZE(mx25l6495f_tb1_ranges);
+ }
+ break;
+ }
+ case MACRONIX_MX25L25635F: {
+ uint8_t cr = mx25l_read_config_register(flash);
+
+ *wp = &mx25l25635f_wp;
+ if (!(cr & (1 << 3))) { /* T/B == 0 */
+ (*wp)->descrs = &mx25l25635f_tb0_ranges[0];
+ *num_entries = ARRAY_SIZE(mx25l25635f_tb0_ranges);
+ } else { /* T/B == 1 */
+ (*wp)->descrs = &mx25l25635f_tb1_ranges[0];
+ *num_entries = ARRAY_SIZE(mx25l25635f_tb1_ranges);
+ }
+ break;
+ }
+ default:
+ msg_cerr("%s():%d: MXIC flash chip mismatch (0x%04x)"
+ ", aborting\n", __func__, __LINE__,
+ flash->chip->model_id);
+ return -1;
+ }
+ break;
+ //case SPANSION_ID:
+ // switch (flash->chip->model_id) {
+ // case SPANSION_S25FS128S_L:
+ // case SPANSION_S25FS128S_S: {
+ // *wp = &s25fs128s_wp;
+ // (*wp)->descrs = s25fs128s_ranges;
+ // *num_entries = ARRAY_SIZE(s25fs128s_ranges);
+ // break;
+ // }
+ // case SPANSION_S25FL256S_UL:
+ // case SPANSION_S25FL256S_US: {
+ // *wp = &s25fl256s_wp;
+ // (*wp)->descrs = s25fl256s_ranges;
+ // *num_entries = ARRAY_SIZE(s25fl256s_ranges);
+ // break;
+ // }
+ // default:
+ // msg_cerr("%s():%d Spansion flash chip mismatch (0x%04x)"
+ // ", aborting\n", __func__, __LINE__,
+ // flash->chip->model_id);
+ // return -1;
+ // }
+ // break;
+ default:
+ msg_cerr("%s: flash vendor (0x%x) not found, aborting\n",
+ __func__, flash->chip->manufacture_id);
+ return -1;
+ }
+
+ return 0;
+}
+
+static uint8_t generic_get_bp_mask(struct wp_context *wp)
+{
+ return ((1 << (wp->sr1.bp0_pos + wp->sr1.bp_bits)) - 1) ^ \
+ ((1 << wp->sr1.bp0_pos) - 1);
+}
+
+static uint8_t generic_get_status_check_mask(struct wp_context *wp)
+{
+ return generic_get_bp_mask(wp) | 1 << wp->sr1.srp_pos;
+}
+
+/* Given a [start, len], this function finds a block protect bit combination
+ * (if possible) and sets the corresponding bits in "status". Remaining bits
+ * are preserved. */
+static int generic_range_to_status(const struct flashctx *flash,
+ unsigned int start, unsigned int len,
+ uint8_t *status, uint8_t *check_mask)
+{
+ struct wp_context *wp;
+ struct wp_range_descriptor *r;
+ int i, range_found = 0, num_entries;
+ uint8_t bp_mask;
+
+ if (generic_range_table(flash, &wp, &num_entries))
+ return -1;
+
+ bp_mask = generic_get_bp_mask(wp);
+
+ for (i = 0, r = &wp->descrs[0]; i < num_entries; i++, r++) {
+ msg_cspew("comparing range 0x%x 0x%x / 0x%x 0x%x\n",
+ start, len, r->range.start, r->range.len);
+ if ((start == r->range.start) && (len == r->range.len)) {
+ *status &= ~(bp_mask);
+ *status |= r->bp << (wp->sr1.bp0_pos);
+
+ if (wp->set_modifier_bits) {
+ if (wp->set_modifier_bits(flash, &r->m) < 0) {
+ msg_cerr("error setting modifier "
+ "bits for range.\n");
+ return -1;
+ }
+ }
+
+ range_found = 1;
+ break;
+ }
+ }
+
+ if (!range_found) {
+ msg_cerr("%s: matching range not found\n", __func__);
+ return -1;
+ }
+
+ *check_mask = generic_get_status_check_mask(wp);
+ return 0;
+}
+
+static int generic_status_to_range(const struct flashctx *flash,
+ const uint8_t sr1, unsigned int *start, unsigned int *len)
+{
+ struct wp_context *wp;
+ struct wp_range_descriptor *r;
+ int num_entries, i, status_found = 0;
+ uint8_t sr1_bp;
+ struct modifier_bits m;
+
+ if (generic_range_table(flash, &wp, &num_entries))
+ return -1;
+
+ /* modifier bits may be compared more than once, so get them here */
+ if (wp->get_modifier_bits && wp->get_modifier_bits(flash, &m) < 0)
+ return -1;
+
+ sr1_bp = (sr1 >> wp->sr1.bp0_pos) & ((1 << wp->sr1.bp_bits) - 1);
+
+ for (i = 0, r = &wp->descrs[0]; i < num_entries; i++, r++) {
+ if (wp->get_modifier_bits) {
+ if (memcmp(&m, &r->m, sizeof(m)))
+ continue;
+ }
+ msg_cspew("comparing 0x%02x 0x%02x\n", sr1_bp, r->bp);
+ if (sr1_bp == r->bp) {
+ *start = r->range.start;
+ *len = r->range.len;
+ status_found = 1;
+ break;
+ }
+ }
+
+ if (!status_found) {
+ msg_cerr("matching status not found\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Given a [start, len], this function calls generic_range_to_status() to
+ * convert it to flash-chip-specific range bits, then sets into status register.
+ */
+static int generic_set_range(const struct flashctx *flash,
+ unsigned int start, unsigned int len)
+{
+ uint8_t status, expected, check_mask;
+
+ status = do_read_status(flash);
+ msg_cdbg("%s: old status: 0x%02x\n", __func__, status);
+
+ expected = status; /* preserve non-bp bits */
+ if (generic_range_to_status(flash, start, len, &expected, &check_mask))
+ return -1;
+
+ do_write_status(flash, expected);
+
+ status = do_read_status(flash);
+ msg_cdbg("%s: new status: 0x%02x\n", __func__, status);
+ if ((status & check_mask) != (expected & check_mask)) {
+ msg_cerr("expected=0x%02x, but actual=0x%02x. check mask=0x%02x\n",
+ expected, status, check_mask);
+ return 1;
+ }
+ return 0;
+}
+
+/* Set/clear the status regsiter write protect bit in SR1. */
+static int generic_set_srp0(const struct flashctx *flash, int enable)
+{
+ uint8_t status, expected, check_mask;
+ struct wp_context *wp;
+ int num_entries;
+
+ if (generic_range_table(flash, &wp, &num_entries))
+ return -1;
+
+ expected = do_read_status(flash);
+ msg_cdbg("%s: old status: 0x%02x\n", __func__, expected);
+
+ if (enable)
+ expected |= 1 << wp->sr1.srp_pos;
+ else
+ expected &= ~(1 << wp->sr1.srp_pos);
+
+ do_write_status(flash, expected);
+
+ status = do_read_status(flash);
+ msg_cdbg("%s: new status: 0x%02x\n", __func__, status);
+
+ check_mask = generic_get_status_check_mask(wp);
+ msg_cdbg("%s: check mask: 0x%02x\n", __func__, check_mask);
+ if ((status & check_mask) != (expected & check_mask)) {
+ msg_cerr("expected=0x%02x, but actual=0x%02x. check mask=0x%02x\n",
+ expected, status, check_mask);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int generic_enable_writeprotect(const struct flashctx *flash,
+ enum wp_mode wp_mode)
+{
+ int ret;
+
+ if (wp_mode != WP_MODE_HARDWARE) {
+ msg_cerr("%s(): unsupported write-protect mode\n", __func__);
+ return 1;
+ }
+
+ ret = generic_set_srp0(flash, 1);
+ if (ret)
+ msg_cerr("%s(): error=%d.\n", __func__, ret);
+
+ return ret;
+}
+
+static int generic_disable_writeprotect(const struct flashctx *flash)
+{
+ int ret;
+
+ ret = generic_set_srp0(flash, 0);
+ if (ret)
+ msg_cerr("%s(): error=%d.\n", __func__, ret);
+
+ return ret;
+}
+
+static int generic_list_ranges(const struct flashctx *flash)
+{
+ struct wp_context *wp;
+ struct wp_range_descriptor *r;
+ int i, num_entries;
+
+ if (generic_range_table(flash, &wp, &num_entries))
+ return -1;
+
+ r = &wp->descrs[0];
+ for (i = 0; i < num_entries; i++) {
+ msg_cinfo("start: 0x%06x, length: 0x%06x\n",
+ r->range.start, r->range.len);
+ r++;
+ }
+
+ return 0;
+}
+
+static int wp_context_status(const struct flashctx *flash)
+{
+ uint8_t sr1;
+ unsigned int start, len;
+ int ret = 0;
+ struct wp_context *wp;
+ int num_entries, wp_en;
+
+ if (generic_range_table(flash, &wp, &num_entries))
+ return -1;
+
+ sr1 = do_read_status(flash);
+ wp_en = (sr1 >> wp->sr1.srp_pos) & 1;
+
+ msg_cinfo("WP: status: 0x%04x\n", sr1);
+ msg_cinfo("WP: status.srp0: %x\n", wp_en);
+ /* FIXME: SRP1 is not really generic, but we probably should print
+ * it anyway to have consistent output. #legacycruft */
+ msg_cinfo("WP: status.srp1: %x\n", 0);
+ msg_cinfo("WP: write protect is %s.\n",
+ wp_en ? "enabled" : "disabled");
+
+ msg_cinfo("WP: write protect range: ");
+ if (generic_status_to_range(flash, sr1, &start, &len)) {
+ msg_cinfo("(cannot resolve the range)\n");
+ ret = -1;
+ } else {
+ msg_cinfo("start=0x%08x, len=0x%08x\n", start, len);
+ }
+
+ return ret;
+}
+
+struct wp wp_generic = {
+ .list_ranges = generic_list_ranges,
+ .set_range = generic_set_range,
+ .enable = generic_enable_writeprotect,
+ .disable = generic_disable_writeprotect,
+ .wp_status = wp_context_status,
+};
diff --git a/writeprotect.h b/writeprotect.h
new file mode 100644
index 0000000..d39b993
--- /dev/null
+++ b/writeprotect.h
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __WRITEPROTECT_H__
+#define __WRITEPROTECT_H__ 1
+
+enum wp_mode {
+ WP_MODE_UNKNOWN = -1,
+ WP_MODE_HARDWARE, /* hardware WP pin determines status */
+ WP_MODE_POWER_CYCLE, /* WP active until power off/on cycle */
+ WP_MODE_PERMANENT, /* status register permanently locked,
+ WP permanently enabled */
+};
+
+struct wp {
+ int (*list_ranges)(const struct flashctx *flash);
+ int (*set_range)(const struct flashctx *flash,
+ unsigned int start, unsigned int len);
+ int (*enable)(const struct flashctx *flash, enum wp_mode mode);
+ int (*disable)(const struct flashctx *flash);
+ int (*wp_status)(const struct flashctx *flash);
+};
+
+/* winbond w25-series */
+extern struct wp wp_w25; /* older winbond chips (w25p, w25x, etc) */
+extern struct wp wp_w25q;
+extern struct wp wp_w25q_large; /* large winbond chips (>= 32MB) */
+
+extern struct wp wp_generic;
+extern struct wp wp_wpce775x;
+
+enum wp_mode get_wp_mode(const char *mode_str);
+
+/*
+ * Generic write-protect stuff
+ */
+
+struct modifier_bits {
+ int sec; /* if 1, bp bits describe sectors */
+ int tb; /* value of top/bottom select bit */
+};
+
+#endif /* !__WRITEPROTECT_H__ */
--
To view, visit https://review.coreboot.org/c/flashrom/+/40325
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: Id93b5a1cb2da476fa8a7dde41d7b963024117474
Gerrit-Change-Number: 40325
Gerrit-PatchSet: 1
Gerrit-Owner: Edward O'Callaghan <quasisec(a)chromium.org>
Gerrit-MessageType: newchange
6
26
Feb. 7, 2021
zapb has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/48379 )
Change subject: jlink_spi: Reduce transfer size
......................................................................
jlink_spi: Reduce transfer size
The maximum transfer size is too large for some devices and
results in an USB timeout.
Change-Id: If2c00b1524ec56740bdfe290096c3546cf375d73
Signed-off-by: Marc Schink <dev(a)zapb.de>
---
M jlink_spi.c
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/79/48379/1
diff --git a/jlink_spi.c b/jlink_spi.c
index 36611bf..3a73c01 100644
--- a/jlink_spi.c
+++ b/jlink_spi.c
@@ -34,7 +34,7 @@
* Maximum number of bytes that can be transferred at once via the JTAG
* interface, see jaylink_jtag_io().
*/
-#define JTAG_MAX_TRANSFER_SIZE (UINT16_MAX / 8)
+#define JTAG_MAX_TRANSFER_SIZE (32768 / 8)
/*
* Default base frequency in Hz. Used when the base frequency can not be
--
To view, visit https://review.coreboot.org/c/flashrom/+/48379
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: If2c00b1524ec56740bdfe290096c3546cf375d73
Gerrit-Change-Number: 48379
Gerrit-PatchSet: 1
Gerrit-Owner: zapb <dev(a)zapb.de>
Gerrit-MessageType: newchange
3
4
Change in flashrom[master]: sb600spi.c: add rev 0x51 to the leading comment block
by Idwer Vollering (Code Review) Feb. 7, 2021
by Idwer Vollering (Code Review) Feb. 7, 2021
Feb. 7, 2021
Idwer Vollering has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/48879 )
Change subject: sb600spi.c: add rev 0x51 to the leading comment block
......................................................................
sb600spi.c: add rev 0x51 to the leading comment block
Signed-off-by: Idwer Vollering <vidwer(a)gmail.com>
Change-Id: Ic74cff04f2d1fd92ad92aa37f71e5852f02d86a6
---
M sb600spi.c
1 file changed, 1 insertion(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/79/48879/1
diff --git a/sb600spi.c b/sb600spi.c
index ef9da4b..b9560e2 100644
--- a/sb600spi.c
+++ b/sb600spi.c
@@ -127,7 +127,7 @@
* found on both Stoney Ridge and Zen platforms.
*
* The revisions I have found by searching various lspci
- * outputs are as follows: 0x4b, 0x59 & 0x61.
+ * outputs are as follows: 0x4b, 0x51, 0x59 & 0x61.
*/
} else if (rev == 0x4b || rev == 0x51 || rev == 0x59 || rev == 0x61) {
msg_pdbg("Promontory (rev 0x%02x) detected.\n", rev);
--
To view, visit https://review.coreboot.org/c/flashrom/+/48879
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: flashrom
Gerrit-Branch: master
Gerrit-Change-Id: Ic74cff04f2d1fd92ad92aa37f71e5852f02d86a6
Gerrit-Change-Number: 48879
Gerrit-PatchSet: 1
Gerrit-Owner: Idwer Vollering <vidwer(a)gmail.com>
Gerrit-MessageType: newchange
2
4