summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes2
-rw-r--r--.github/workflows/lockdown.yml36
-rw-r--r--.gitignore7
-rw-r--r--82802ab.c36
-rw-r--r--Doxyfile5
-rw-r--r--MAINTAINERS205
-rw-r--r--Makefile1723
-rw-r--r--Makefile.d/arch_test.h55
-rw-r--r--Makefile.d/cc_test.c6
-rw-r--r--Makefile.d/clock_gettime_test.c9
-rw-r--r--Makefile.d/endian_test.h (renamed from platform.h)120
-rw-r--r--Makefile.d/ft232h_test.c3
-rw-r--r--Makefile.d/linux_i2c_test.c9
-rw-r--r--Makefile.d/linux_mtd_test.c8
-rw-r--r--Makefile.d/linux_spi_test.c9
-rw-r--r--Makefile.d/os_test.h (renamed from os.h)6
-rw-r--r--Makefile.d/utsname_test.c9
-rw-r--r--Makefile.include65
-rw-r--r--README192
-rw-r--r--README.rst58
-rw-r--r--VERSION1
-rw-r--r--amd_imc.c11
-rw-r--r--archtest.c2
-rw-r--r--asm106x.c154
-rw-r--r--at45db.c20
-rw-r--r--atahpt.c100
-rw-r--r--atapromise.c123
-rw-r--r--atavia.c107
-rw-r--r--bindings/rust/README32
-rw-r--r--bindings/rust/libflashrom-sys/.cargo/config.toml2
-rw-r--r--bindings/rust/libflashrom-sys/Cargo.toml16
-rw-r--r--bindings/rust/libflashrom-sys/build.rs32
-rw-r--r--bindings/rust/libflashrom-sys/src/lib.rs5
-rw-r--r--bindings/rust/libflashrom/.cargo/config.toml2
-rw-r--r--bindings/rust/libflashrom/Cargo.toml24
-rw-r--r--bindings/rust/libflashrom/build.rs17
-rw-r--r--bindings/rust/libflashrom/src/lib.rs1124
-rw-r--r--bindings/rust/libflashrom/src/log.c61
-rw-r--r--bitbang_spi.c120
-rw-r--r--board_enable.c291
-rw-r--r--buspirate_spi.c450
-rw-r--r--cbtable.c77
-rw-r--r--ch341a_spi.c214
-rw-r--r--ch347_spi.c343
-rw-r--r--chipset_enable.c443
-rw-r--r--cli_classic.c1091
-rw-r--r--cli_common.c13
-rw-r--r--cli_getopt.c263
-rw-r--r--cli_output.c31
-rw-r--r--custom_baud.c49
-rw-r--r--custom_baud_darwin.c61
-rw-r--r--custom_baud_linux.c60
-rw-r--r--dediprog.c386
-rw-r--r--developerbox_spi.c93
-rw-r--r--digilent_spi.c154
-rw-r--r--dirtyjtag_spi.c318
-rw-r--r--dmi.c64
-rw-r--r--doc/about_flashrom/index.rst7
-rw-r--r--doc/about_flashrom/team.rst61
-rw-r--r--doc/classic_cli_manpage.rst1370
-rw-r--r--doc/conf.py49
-rw-r--r--doc/contact.rst157
-rw-r--r--doc/dev_guide/building_from_source.rst288
-rw-r--r--doc/dev_guide/building_with_make.rst195
-rw-r--r--doc/dev_guide/development_guide.rst342
-rw-r--r--doc/dev_guide/index.rst9
-rw-r--r--doc/documentation_license.rst296
-rw-r--r--doc/how_to_add_docs.rst35
-rw-r--r--doc/index.rst22
-rw-r--r--doc/intro.rst34
-rw-r--r--doc/logo/COPYING12
-rw-r--r--doc/logo/flashrom_icon_bw.svg184
-rw-r--r--doc/logo/flashrom_icon_color-128x128.pngbin0 -> 11547 bytes
-rw-r--r--doc/logo/flashrom_icon_color-16x16.icobin0 -> 1150 bytes
-rw-r--r--doc/logo/flashrom_icon_color-16x16.pngbin0 -> 714 bytes
-rw-r--r--doc/logo/flashrom_icon_color-16x16.xcfbin0 -> 2267 bytes
-rw-r--r--doc/logo/flashrom_icon_color-256x256.pngbin0 -> 26003 bytes
-rw-r--r--doc/logo/flashrom_icon_color-32x32.icobin0 -> 4286 bytes
-rw-r--r--doc/logo/flashrom_icon_color-32x32.pngbin0 -> 1803 bytes
-rw-r--r--doc/logo/flashrom_icon_color-32x32.xcfbin0 -> 20389 bytes
-rw-r--r--doc/logo/flashrom_icon_color-64x64.pngbin0 -> 4562 bytes
-rw-r--r--doc/logo/flashrom_icon_color-64x64.xcfbin0 -> 20886 bytes
-rw-r--r--doc/logo/flashrom_icon_color.svg186
-rw-r--r--doc/logo/flashrom_icon_gray.svg183
-rw-r--r--doc/logo/flashrom_logo.pngbin0 -> 13378 bytes
-rw-r--r--doc/logo/flashrom_logo.svg199
-rw-r--r--doc/meson.build36
-rw-r--r--drkaiser.c98
-rw-r--r--dummyflasher.c1436
-rw-r--r--edi.c6
-rw-r--r--en29lv640b.c5
-rw-r--r--endiantest.c6
-rw-r--r--ene_lpc.c596
-rw-r--r--erasure_layout.c408
-rw-r--r--flashchips.c11012
-rw-r--r--flashrom.8.tmpl1539
-rw-r--r--flashrom.c2134
-rw-r--r--fmap.c34
-rw-r--r--ft2232_spi.c477
-rw-r--r--gfxnvidia.c104
-rw-r--r--helpers.c19
-rw-r--r--helpers_fileio.c132
-rw-r--r--hwaccess.c314
-rw-r--r--hwaccess.h305
-rw-r--r--hwaccess_physmap.c (renamed from physmap.c)408
-rw-r--r--hwaccess_x86_io.c428
-rw-r--r--hwaccess_x86_msr.c382
-rw-r--r--i2c_helper_linux.c99
-rw-r--r--ich_descriptors.c372
-rw-r--r--ichspi.c1689
-rw-r--r--include/chipdrivers.h (renamed from chipdrivers.h)66
-rw-r--r--include/cli_classic.h43
-rw-r--r--include/coreboot_tables.h (renamed from coreboot_tables.h)0
-rw-r--r--include/custom_baud.h (renamed from custom_baud.h)8
-rw-r--r--include/edi.h (renamed from edi.h)0
-rw-r--r--include/ene.h (renamed from ene.h)0
-rw-r--r--include/erasure_layout.h41
-rw-r--r--include/flash.h (renamed from flash.h)411
-rw-r--r--include/flashchips.h (renamed from flashchips.h)45
-rw-r--r--include/fmap.h (renamed from fmap.h)0
-rw-r--r--include/hwaccess_physmap.h59
-rw-r--r--include/hwaccess_x86_io.h37
-rw-r--r--include/hwaccess_x86_msr.h28
-rw-r--r--include/i2c_helper.h (renamed from i2c_helper.h)23
-rw-r--r--include/ich_descriptors.h (renamed from ich_descriptors.h)20
-rw-r--r--include/layout.h (renamed from layout.h)46
-rw-r--r--include/libflashrom.h598
-rw-r--r--include/platform.h64
-rw-r--r--include/platform/pci.h31
-rw-r--r--include/platform/swap.h80
-rw-r--r--include/programmer.h (renamed from programmer.h)602
-rw-r--r--include/spi.h (renamed from spi.h)37
-rw-r--r--include/usb_device.h (renamed from usb_device.h)32
-rw-r--r--include/writeprotect.h98
-rw-r--r--internal.c320
-rw-r--r--internal_par.c79
-rw-r--r--it8212.c92
-rw-r--r--it85spi.c381
-rw-r--r--it87spi.c84
-rw-r--r--jedec.c524
-rw-r--r--jlink_spi.c239
-rw-r--r--known_boards.c691
-rw-r--r--layout.c407
-rw-r--r--libflashrom.c522
-rw-r--r--libflashrom.h120
-rw-r--r--libflashrom.map24
-rw-r--r--linux_mtd.c295
-rw-r--r--linux_spi.c278
-rw-r--r--lspcon_i2c_spi.c505
-rw-r--r--mcp6x_spi.c116
-rw-r--r--mec1308.c523
-rw-r--r--mediatek_i2c_spi.c542
-rw-r--r--meson.build1072
-rw-r--r--meson_cross/i586_djgpp_dos.txt29
-rw-r--r--meson_options.txt66
-rw-r--r--mstarddc_spi.c209
-rw-r--r--ni845x_spi.c393
-rw-r--r--nic3com.c111
-rw-r--r--nicintel.c95
-rw-r--r--nicintel_eeprom.c278
-rw-r--r--nicintel_spi.c182
-rw-r--r--nicnatsemi.c117
-rw-r--r--nicrealtek.c139
-rw-r--r--ogp_spi.c105
-rw-r--r--opaque.c13
-rw-r--r--parade_lspcon.c508
-rw-r--r--parallel.c165
-rw-r--r--pcidev.c77
-rw-r--r--pickit2_spi.c140
-rw-r--r--platform/endian_big.c43
-rw-r--r--platform/endian_little.c43
-rw-r--r--platform/memaccess.c42
-rw-r--r--platform/meson.build42
-rw-r--r--pony_spi.c186
-rw-r--r--print.c779
-rw-r--r--print_wiki.c40
-rw-r--r--printlock.c224
-rw-r--r--programmer.c81
-rw-r--r--programmer_table.c184
-rw-r--r--raiden_debug_spi.c192
-rw-r--r--rayer_spi.c302
-rw-r--r--realtek_mst_i2c_spi.c200
-rw-r--r--s25f.c60
-rw-r--r--satamv.c191
-rw-r--r--satasii.c141
-rw-r--r--sb600spi.c263
-rwxr-xr-xscripts/llvm-cov6
-rw-r--r--serial.c29
-rw-r--r--serprog.c680
-rw-r--r--serprog.h25
-rw-r--r--sfdp.c30
-rw-r--r--spi.c127
-rw-r--r--spi25.c131
-rw-r--r--spi25_statusreg.c581
-rw-r--r--spi95.c2
-rw-r--r--sst28sf040.c3
-rw-r--r--stlinkv3_spi.c217
-rw-r--r--stm50.c2
-rw-r--r--superio.c42
-rwxr-xr-xtest_build.sh80
-rw-r--r--tests/ch341a_spi.c136
-rw-r--r--tests/chip.c580
-rw-r--r--tests/chip_wp.c402
-rw-r--r--tests/dediprog.c58
-rw-r--r--tests/dummyflasher.c153
-rw-r--r--tests/flashrom.c40
-rw-r--r--tests/helpers.c4
-rw-r--r--tests/include/test.h15
-rw-r--r--tests/io_mock.c31
-rw-r--r--tests/io_mock.h134
-rw-r--r--tests/io_real.c78
-rw-r--r--tests/io_real.h24
-rw-r--r--tests/layout.c214
-rw-r--r--tests/libusb_wraps.c222
-rw-r--r--tests/libusb_wraps.h57
-rw-r--r--tests/lifecycle.c98
-rw-r--r--tests/lifecycle.h39
-rw-r--r--tests/linux_mtd.c94
-rw-r--r--tests/linux_spi.c72
-rw-r--r--tests/mediatek_i2c_spi.c52
-rw-r--r--tests/meson.build111
-rw-r--r--tests/nicrealtek.c33
-rw-r--r--tests/parade_lspcon.c138
-rw-r--r--tests/raiden_debug_spi.c118
-rw-r--r--tests/realtek_mst_i2c_spi.c79
-rw-r--r--tests/selfcheck.c156
-rw-r--r--tests/spi25.c101
-rw-r--r--tests/tests.c456
-rw-r--r--tests/tests.h60
-rw-r--r--tests/unittest_env.h48
-rw-r--r--tests/usb_unittests.h62
-rw-r--r--tests/wraps.h79
-rw-r--r--udelay.c4
-rw-r--r--usb_device.c66
-rw-r--r--usbblaster_spi.c140
-rw-r--r--util/docker/flashrom.org/Dockerfile29
-rw-r--r--util/docker/flashrom.org/README.md32
-rwxr-xr-xutil/docker/flashrom.org/ditaa.sh2
-rwxr-xr-xutil/docker/flashrom.org/makeSphinx.sh12
-rw-r--r--util/flashrom.bash-completion.tmpl77
-rw-r--r--util/flashrom_tester/.cargo/config.toml2
-rw-r--r--util/flashrom_tester/Cargo.toml13
-rw-r--r--util/flashrom_tester/flashrom/Cargo.toml5
-rw-r--r--util/flashrom_tester/flashrom/src/cmd.rs489
-rw-r--r--util/flashrom_tester/flashrom/src/flashromlib.rs184
-rw-r--r--util/flashrom_tester/flashrom/src/lib.rs372
-rw-r--r--util/flashrom_tester/src/cros_sysinfo.rs24
-rw-r--r--util/flashrom_tester/src/logger.rs93
-rw-r--r--util/flashrom_tester/src/main.rs106
-rw-r--r--util/flashrom_tester/src/rand_util.rs11
-rw-r--r--util/flashrom_tester/src/tester.rs405
-rw-r--r--util/flashrom_tester/src/tests.rs185
-rw-r--r--util/flashrom_tester/src/types.rs39
-rw-r--r--util/flashrom_tester/src/utils.rs155
-rw-r--r--util/flashrom_udev.rules (renamed from util/z60_flashrom.rules)4
-rwxr-xr-xutil/getrevision.sh238
-rwxr-xr-xutil/getversion.sh71
-rwxr-xr-xutil/git-hooks/commit-msg2
-rw-r--r--util/ich_descriptors_tool/Makefile23
-rw-r--r--util/ich_descriptors_tool/ich_descriptors_tool.c27
-rw-r--r--util/ich_descriptors_tool/meson.build5
-rw-r--r--util/lint/helper_functions.sh45
-rwxr-xr-xutil/lint/lint-extended-020-signed-off-by23
-rw-r--r--util/manibuilder/Dockerfile.alpine24
-rw-r--r--util/manibuilder/Dockerfile.anita65
-rw-r--r--util/manibuilder/Dockerfile.centos18
-rw-r--r--util/manibuilder/Dockerfile.debian-debootstrap21
-rw-r--r--util/manibuilder/Dockerfile.djgpp30
-rw-r--r--util/manibuilder/Dockerfile.fedora19
-rw-r--r--util/manibuilder/Dockerfile.qemu-user-static3
-rw-r--r--util/manibuilder/Dockerfile.ubuntu-debootstrap34
-rw-r--r--util/manibuilder/Makefile93
-rw-r--r--util/manibuilder/Makefile.anita52
-rw-r--r--util/manibuilder/Makefile.targets223
-rw-r--r--util/manibuilder/README.md72
-rw-r--r--util/manibuilder/anita-wrapper.sh18
-rw-r--r--util/manibuilder/mani-wrapper.sh9
-rw-r--r--util/meson.build1
-rw-r--r--util/shell.nix18
-rwxr-xr-xutil/ubertest/ubertest.sh4
-rw-r--r--w29ee011.c41
-rw-r--r--w39.c4
-rw-r--r--wbsio_spi.c41
-rw-r--r--writeprotect.c793
-rw-r--r--writeprotect.h51
-rw-r--r--writeprotect_ranges.c144
286 files changed, 37851 insertions, 22117 deletions
diff --git a/.gitattributes b/.gitattributes
index 10f89626d..a663df718 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,7 @@
.gitattributes export-ignore
.gitignore export-ignore
+/bindings export-ignore
+/bindings/** export-ignore
/util/getrevision.sh export-ignore
/util/git-hooks export-ignore
/util/git-hooks/** export-ignore
diff --git a/.github/workflows/lockdown.yml b/.github/workflows/lockdown.yml
new file mode 100644
index 000000000..f92e086d0
--- /dev/null
+++ b/.github/workflows/lockdown.yml
@@ -0,0 +1,36 @@
+name: 'Close issues and PRs'
+
+on:
+ issues:
+ types: opened
+ pull_request_target:
+ types: opened
+
+permissions:
+ issues: write
+ pull-requests: write
+
+jobs:
+ action:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: dessant/repo-lockdown@0b093279a77b44bbc38e85089b5463dd06b4aea4
+ with:
+ issue-comment: >
+ Thank you for your contribution. The flashrom project does not handle
+ GitHub issues or pull requests, since this repository on GitHub is
+ just a mirror of our actual repository. Thus, we would like to
+ encourage you to have a look at on our [development guide](https://www.flashrom.org/dev_guide/development_guide.html)
+ and submit your patch to [review.coreboot.org](https://review.coreboot.org/q/project:flashrom).
+ Issues are handled over our [ticket system](https://ticket.coreboot.org/projects/flashrom).
+ If you have questions, feel free to reach out to us. There are
+ multiple ways to [contact us](https://www.flashrom.org/contact.html).
+ pr-comment: >
+ Thank you for your contribution. The flashrom project does not handle
+ GitHub issues or pull requests, since this repository on GitHub is
+ just a mirror of our actual repository. Thus, we would like to
+ encourage you to have a look at on our [development guide](https://www.flashrom.org/dev_guide/development_guide.html)
+ and submit your patch to [review.coreboot.org](https://review.coreboot.org/q/project:flashrom).
+ Issues are handled over our [ticket system](https://ticket.coreboot.org/projects/flashrom).
+ If you have questions, feel free to reach out to us. There are
+ multiple ways to [contact us](https://www.flashrom.org/contact.html).
diff --git a/.gitignore b/.gitignore
index 2d621dcd9..4e3873924 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,7 @@
*.d
+!Makefile.d/
*.o
+/.doctrees
/.features
/.dependencies
/.libdeps
@@ -8,9 +10,14 @@
/flashrom-*
/flashrom.exe
/flashrom.8
+/flashrom.bash
+/libflashrom.a
/libflashrom-doc/
+/man8
/util/ich_descriptors_tool/ich_descriptors_tool
/util/ich_descriptors_tool/ich_descriptors_tool.exe
/util/ich_descriptors_tool/.dep
/util/ich_descriptors_tool/.obj
+
+target/
diff --git a/82802ab.c b/82802ab.c
index b485c114c..a440bd45b 100644
--- a/82802ab.c
+++ b/82802ab.c
@@ -22,6 +22,7 @@
* - Order number: 290658-004
*/
+#include <stdbool.h>
#include "flash.h"
#include "chipdrivers.h"
@@ -44,11 +45,11 @@ int probe_82802ab(struct flashctx *flash)
/* Reset to get a clean state */
chip_writeb(flash, 0xFF, bios);
- programmer_delay(10);
+ programmer_delay(flash, 10);
/* Enter ID mode */
chip_writeb(flash, 0x90, bios);
- programmer_delay(10);
+ programmer_delay(flash, 10);
id1 = chip_readb(flash, bios + (0x00 << shifted));
id2 = chip_readb(flash, bios + (0x01 << shifted));
@@ -56,7 +57,7 @@ int probe_82802ab(struct flashctx *flash)
/* Leave ID mode */
chip_writeb(flash, 0xFF, bios);
- programmer_delay(10);
+ programmer_delay(flash, 10);
msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, id1, id2);
@@ -113,7 +114,7 @@ int erase_block_82802ab(struct flashctx *flash, unsigned int page,
// now start it
chip_writeb(flash, 0x20, bios + page);
chip_writeb(flash, 0xd0, bios + page);
- programmer_delay(10);
+ programmer_delay(flash, 10);
// now let's see what the register is
status = wait_82802ab(flash);
@@ -134,16 +135,18 @@ int write_82802ab(struct flashctx *flash, const uint8_t *src, unsigned int start
chip_writeb(flash, 0x40, dst);
chip_writeb(flash, *src++, dst++);
wait_82802ab(flash);
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, len);
}
/* FIXME: Ignore errors for now. */
return 0;
}
-int unlock_28f004s5(struct flashctx *flash)
+static int unlock_28f004s5(struct flashctx *flash)
{
chipaddr bios = flash->virtual_memory;
- uint8_t mcfg, bcfg, need_unlock = 0, can_unlock = 0;
+ uint8_t mcfg, bcfg;
+ bool need_unlock = false, can_unlock = false;
unsigned int i;
/* Clear status register */
@@ -159,7 +162,7 @@ int unlock_28f004s5(struct flashctx *flash)
msg_cdbg("locked!\n");
} else {
msg_cdbg("unlocked!\n");
- can_unlock = 1;
+ can_unlock = true;
}
/* Read block lock-bits */
@@ -167,7 +170,7 @@ int unlock_28f004s5(struct flashctx *flash)
bcfg = chip_readb(flash, bios + i + 2); // read block lock config
msg_cdbg("block lock at %06x is %slocked!\n", i, bcfg ? "" : "un");
if (bcfg) {
- need_unlock = 1;
+ need_unlock = true;
}
}
@@ -192,11 +195,11 @@ int unlock_28f004s5(struct flashctx *flash)
return 0;
}
-int unlock_lh28f008bjt(struct flashctx *flash)
+static int unlock_lh28f008bjt(struct flashctx *flash)
{
chipaddr bios = flash->virtual_memory;
uint8_t mcfg, bcfg;
- uint8_t need_unlock = 0, can_unlock = 0;
+ bool need_unlock = false, can_unlock = false;
unsigned int i;
/* Wait if chip is busy */
@@ -212,7 +215,7 @@ int unlock_lh28f008bjt(struct flashctx *flash)
msg_cdbg("locked!\n");
} else {
msg_cdbg("unlocked!\n");
- can_unlock = 1;
+ can_unlock = true;
}
/* Read block lock-bits, 8 * 8 KB + 15 * 64 KB */
@@ -222,7 +225,7 @@ int unlock_lh28f008bjt(struct flashctx *flash)
msg_cdbg("block lock at %06x is %slocked!\n", i,
bcfg ? "" : "un");
if (bcfg)
- need_unlock = 1;
+ need_unlock = true;
}
/* Reset chip */
@@ -246,3 +249,12 @@ int unlock_lh28f008bjt(struct flashctx *flash)
return 0;
}
+
+blockprotect_func_t *lookup_82802ab_blockprotect_func_ptr(const struct flashchip *const chip)
+{
+ switch (chip->unlock) {
+ case UNLOCK_28F004S5: return unlock_28f004s5;
+ case UNLOCK_LH28F008BJT: return unlock_lh28f008bjt;
+ default: return NULL; /* fallthough */
+ };
+}
diff --git a/Doxyfile b/Doxyfile
index 6906cc82c..a13c06f6a 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -780,10 +780,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
-INPUT = libflashrom.c \
- libflashrom.h \
- flashrom.c \
- layout.c \
+INPUT = include/libflashrom.h
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
diff --git a/MAINTAINERS b/MAINTAINERS
new file mode 100644
index 000000000..40aa3edcc
--- /dev/null
+++ b/MAINTAINERS
@@ -0,0 +1,205 @@
+
+ List of upstream flashrom maintainers
+
+This represents the list of maintainers that work on the upstream flashrom
+code base (on flashrom.org). Maintainers are assigned to topics and when
+applicable to subtrees of the source tree. You'll find some subtrees that
+don't have a maintainer. If you are looking for reviewers for such a subtree,
+it's often a good choice to look at the git history to see who worked on
+it last.
+
+Please follow our development guide:
+https://www.flashrom.org/dev_guide/development_guide.html
+
+Happy hacking!
+
+Descriptions of section entries:
+
+ M: Maintainer: FullName <address@domain>
+ Must be registered to Gerrit (https://review.coreboot.org) and
+ must have experience with upstream flashrom development.
+ R: Designated reviewer: FullName <address@domain>
+ These reviewers are CCed on patches.
+ L: Mailing list that is relevant to this area
+ W: Web-page with status/info
+ S: Status, one of the following:
+ Supported: Someone is continuously paid to look after this and
+ a reaction to review requests can be expected
+ within a few days, a month at most.
+ Maintained: Someone actually looks after it and a reaction to
+ review requests can usually be expected within a
+ few weeks.
+ Odd Fixes: It has a maintainer but they don't have time to do
+ much other than throw the odd patch in. See below..
+ Orphan: No current maintainer [but maybe you could take the
+ role as you write your new code].
+ Obsolete: Old code. Something tagged obsolete generally means
+ it has been replaced by a better system and you
+ should be using that.
+ F: Files and directories with wildcard patterns.
+ A trailing slash includes all files and subdirectory files.
+ F: drivers/net/ all files in and below drivers/net
+ F: drivers/net/* all files in drivers/net, but not below
+ F: */net/* all files in "any top level directory"/net
+ One pattern per line. Multiple F: lines acceptable.
+ N: Files and directories with regex patterns.
+ N: [^a-z]tegra all files whose path contains the word tegra
+ One pattern per line. Multiple N: lines acceptable.
+ scripts/get_maintainer.pl has different behavior for files that
+ match F: pattern and matches of N: patterns. By default,
+ get_maintainer will not look at git log history when an F: pattern
+ match occurs. When an N: match occurs, git log history is used
+ to also notify the people that have git commit signatures.
+ X: Files and directories that are NOT maintained, same rules as F:
+ Files exclusions are tested before file matches.
+ Can be useful for excluding a specific subdirectory, for instance:
+ F: net/
+ X: net/ipv6/
+ matches all files in and below net excluding net/ipv6/
+ K: Keyword perl extended regex pattern to match content in a
+ patch or file. For instance:
+ K: of_get_profile
+ matches patches or files that contain "of_get_profile"
+ K: \b(printk|pr_(info|err))\b
+ matches patches or files that contain one or more of the words
+ printk, pr_info or pr_err
+ One regex pattern per line. Multiple K: lines acceptable.
+
+Note: The categories and topics in this list are meant to remain in alphabetical
+ order. Please keep them sorted when you change them.
+
+Maintainers List (try to look for most precise areas first)
+
+ -----------------------------------
+
+################################################################################
+# CORE
+################################################################################
+
+BUILD SYSTEM
+M: Thomas Heijligen <src@posteo.de>
+S: Maintained
+F: Makefile*
+F: meson*
+F: Makefile*/
+F: */meson*
+F: */Makefile*
+F: util/ich_descriptors_tool/meson*
+F: util/ich_descriptors_tool/Makefile*
+
+ERASE/WRITE ALGORITHM
+M: Aarya Chaumal <aarya.chaumal@gmail.com>
+S: Maintained
+F: erasure_layout*
+F: include/erasure_layout*
+
+FLASHCHIPS
+M: Anastasia Klimchuk <aklm@chromium.org>
+M: Nikolai Artemiev <nartemiev@google.com>
+M: Stefan Reinauer <stefan.reinauer@coreboot.org>
+S: Maintained
+F: flashchips*
+F: include/flashchips*
+
+I2C HELPERS
+M: Peter Marheine <pmarheine@chromium.org>
+S: Supported
+F: i2c_helper_linux.c
+
+WRITEPROTECT
+M: Nikolai Artemiev <nartemiev@google.com>
+M: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
+S: Supported
+F: writeprotect*
+F: include/writeprotect*
+
+################################################################################
+# DOCUMENTATION
+################################################################################
+
+MAINTAINERS
+M: Anastasia Klimchuk <aklm@chromium.org>
+S: Maintained
+F: MAINTAINERS
+
+SPHINX DOCS
+M: Thomas Heijligen <src@posteo.de>
+M: Anastasia Klimchuk <aklm@chromium.org>
+S: Maintained
+F: doc/
+F: README.rst
+
+################################################################################
+# PROGRAMMERS
+################################################################################
+
+AMD SB600SPI
+M: Martin Roth <gaumless@tutanota.com>
+S: Maintained
+F: sb600spi.c
+
+CH347
+M: Nicholas Chin <nic.c3.14@gmail.com>
+S: Maintained
+F: ch347_spi.c
+
+DirtyJTAG
+M: Jean THOMAS <virgule@jeanthomas.me>
+S: Maintained
+F: dirtyjtag_spi.c
+
+I2C PROGRAMMERS
+M: Peter Marheine <pmarheine@chromium.org>
+S: Supported
+F: mediatek_i2c_spi.c
+F: parade_lspcon.c
+F: realtek_mst_i2c_spi.c
+
+LINUX MTD
+M: Nikolai Artemiev <nartemiev@google.com>
+S: Supported
+F: linux_mtd.c
+
+National Instruments USB-845x
+M: Miklos Marton <martonmiklosqdev@gmail.com>
+S: Maintained
+F: ni845x_spi.c
+
+RAIDEN DEBUG SPI
+M: Nikolai Artemiev <nartemiev@google.com>
+S: Maintained
+F: raiden_debug_spi.c
+
+STLINK-V3
+M: Miklos Marton <martonmiklosqdev@gmail.com>
+S: Maintained
+F: stlinkv3_spi.c
+
+################################################################################
+# TESTS
+################################################################################
+
+UNIT TESTS
+M: Anastasia Klimchuk <aklm@chromium.org>
+S: Maintained
+F: tests/
+F: subprojects/cmocka.wrap
+
+################################################################################
+# UTILS
+################################################################################
+
+BASH COMPLETION
+M: Alexander Goncharov <chat@joursoir.net>
+S: Maintained
+F: util/flashrom.bash-completion.tmpl
+
+FLASHROM TESTER
+R: Evan Benn <evanbenn@gmail.com>
+S: Supported
+F: util/flashrom_tester/
+
+FLASHROM DOCKER
+M: Stefan Reinauer <stefan.reinauer@coreboot.org>
+S: Maintained
+F: util/docker/
diff --git a/Makefile b/Makefile
index 6d37d55b4..bf01d0f8c 100644
--- a/Makefile
+++ b/Makefile
@@ -26,15 +26,17 @@ PROGRAM = flashrom
# Note for anyone editing this Makefile: gnumake will happily ignore any
# changes in this Makefile to variables set on the command line.
STRIP ?= strip
+STRIP_ARGS = -s
INSTALL = install
-DIFF = diff
PREFIX ?= /usr/local
MANDIR ?= $(PREFIX)/share/man
-CFLAGS ?= -std=c99 -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L -D_BSD_SOURCE -Os -Wall -Wextra -Wno-unused-parameter -Wshadow -Wmissing-prototypes -Wwrite-strings
+BASHCOMPDIR ?= $(PREFIX)/share/bash-completion/completions
+CFLAGS ?= -Os -Wall -Wextra -Wno-unused-parameter -Wshadow -Wmissing-prototypes -Wwrite-strings
EXPORTDIR ?= .
RANLIB ?= ranlib
PKG_CONFIG ?= pkg-config
BUILD_DETAILS_FILE ?= build_details.txt
+SPHINXBUILD ?= sphinx-build
# The following parameter changes the default programmer that will be used if there is no -p/--programmer
# argument given when running flashrom. The predefined setting does not enable any default so that every
@@ -44,22 +46,25 @@ BUILD_DETAILS_FILE ?= build_details.txt
# system attached to an external programmer while the default programmer is set to the internal programmer, and
# you forget to use the -p parameter. This would (try to) overwrite the existing firmware of the computer
# running flashrom). Please do not enable this without thinking about the possible consequences. Possible
-# values are those specified in enum programmer in programmer.h (which depend on other CONFIG_* options
-# evaluated below, namely those that enable/disable the various programmers).
-# Compilation will fail for unspecified values.
-CONFIG_DEFAULT_PROGRAMMER ?= PROGRAMMER_INVALID
+# values can be found when running 'flashrom --list-supported' under the 'Supported programmers' section.
+CONFIG_DEFAULT_PROGRAMMER_NAME ?=
# The following adds a default parameter for the default programmer set above (only).
-CONFIG_DEFAULT_PROGRAMMER_ARGS ?= ''
+CONFIG_DEFAULT_PROGRAMMER_ARGS ?=
# Example: compiling with
-# make CONFIG_DEFAULT_PROGRAMMER=PROGRAMMER_SERPROG CONFIG_DEFAULT_PROGRAMMER_ARGS="dev=/dev/ttyUSB0:1500000"
+# make CONFIG_DEFAULT_PROGRAMMER_NAME=serprog CONFIG_DEFAULT_PROGRAMMER_ARGS="dev=/dev/ttyUSB0:1500000"
# would make executing './flashrom' (almost) equivialent to './flashrom -p serprog:dev=/dev/ttyUSB0:1500000'.
+# The user can provide CPP, C and LDFLAGS and the Makefile will extend these
+override CPPFLAGS := $(CPPFLAGS)
+override CFLAGS := $(CFLAGS)
+override LDFLAGS := $(LDFLAGS)
+
# If your compiler spits out excessive warnings, run make WARNERROR=no
# You shouldn't have to change this flag.
WARNERROR ?= yes
ifeq ($(WARNERROR), yes)
-CFLAGS += -Werror
+override CFLAGS += -Werror
endif
ifdef LIBS_BASE
@@ -69,13 +74,12 @@ override LDFLAGS += -L$(LIBS_BASE)/lib -Wl,-rpath -Wl,$(LIBS_BASE)/lib
endif
ifeq ($(CONFIG_STATIC),yes)
-override PKG_CONFIG += --static
override LDFLAGS += -static
endif
# Set LC_ALL=C to minimize influences of the locale.
# However, this won't work for the majority of relevant commands because they use the $(shell) function and
-# GNU make does not relay variables exported within the makefile to their evironment.
+# GNU make does not relay variables exported within the makefile to their environment.
LC_ALL=C
export LC_ALL
@@ -86,6 +90,107 @@ dummy_for_make_3_80:=$(shell printf "Build started on %s\n\n" "$$(date)" >$(BUIL
debug_shell = $(shell export LC_ALL=C ; { echo 'exec: export LC_ALL=C ; { $(subst ','\'',$(1)) ; }' >&2; \
{ $(1) ; } | tee -a $(BUILD_DETAILS_FILE) ; echo >&2 ; } 2>>$(BUILD_DETAILS_FILE))
+include Makefile.include
+
+###############################################################################
+# Dependency handling.
+
+DEPENDS_ON_SERIAL := \
+ CONFIG_BUSPIRATE_SPI \
+ CONFIG_PONY_SPI \
+ CONFIG_SERPROG \
+
+DEPENDS_ON_SOCKETS := \
+ CONFIG_SERPROG \
+
+DEPENDS_ON_BITBANG_SPI := \
+ CONFIG_DEVELOPERBOX_SPI \
+ CONFIG_INTERNAL_X86 \
+ CONFIG_NICINTEL_SPI \
+ CONFIG_OGP_SPI \
+ CONFIG_PONY_SPI \
+ CONFIG_RAYER_SPI \
+
+DEPENDS_ON_RAW_MEM_ACCESS := \
+ CONFIG_ATAPROMISE \
+ CONFIG_DRKAISER \
+ CONFIG_GFXNVIDIA \
+ CONFIG_INTERNAL_X86 \
+ CONFIG_IT8212 \
+ CONFIG_NICINTEL \
+ CONFIG_NICINTEL_EEPROM \
+ CONFIG_NICINTEL_SPI \
+ CONFIG_OGP_SPI \
+ CONFIG_SATAMV \
+ CONFIG_SATASII \
+
+DEPENDS_ON_X86_MSR := \
+ CONFIG_INTERNAL_X86 \
+
+DEPENDS_ON_X86_PORT_IO := \
+ CONFIG_ATAHPT \
+ CONFIG_ATAPROMISE \
+ CONFIG_INTERNAL_X86 \
+ CONFIG_NIC3COM \
+ CONFIG_NICNATSEMI \
+ CONFIG_NICREALTEK \
+ CONFIG_RAYER_SPI \
+ CONFIG_SATAMV \
+
+DEPENDS_ON_LIBPCI := \
+ CONFIG_ASM106X \
+ CONFIG_ATAHPT \
+ CONFIG_ATAPROMISE \
+ CONFIG_ATAVIA \
+ CONFIG_DRKAISER \
+ CONFIG_GFXNVIDIA \
+ CONFIG_INTERNAL \
+ CONFIG_IT8212 \
+ CONFIG_NIC3COM \
+ CONFIG_NICINTEL \
+ CONFIG_NICINTEL_EEPROM \
+ CONFIG_NICINTEL_SPI \
+ CONFIG_NICNATSEMI \
+ CONFIG_NICREALTEK \
+ CONFIG_OGP_SPI \
+ CONFIG_SATAMV \
+ CONFIG_SATASII \
+
+DEPENDS_ON_LIBUSB1 := \
+ CONFIG_CH341A_SPI \
+ CONFIG_CH347_SPI \
+ CONFIG_DEDIPROG \
+ CONFIG_DEVELOPERBOX_SPI \
+ CONFIG_DIGILENT_SPI \
+ CONFIG_PICKIT2_SPI \
+ CONFIG_RAIDEN_DEBUG_SPI \
+ CONFIG_STLINKV3_SPI \
+ CONFIG_DIRTYJTAG_SPI \
+
+DEPENDS_ON_LIBFTDI1 := \
+ CONFIG_FT2232_SPI \
+ CONFIG_USBBLASTER_SPI \
+
+DEPENDS_ON_LIBJAYLINK := \
+ CONFIG_JLINK_SPI \
+
+DEPENDS_ON_LIB_NI845X := \
+ CONFIG_NI845X_SPI \
+
+DEPENDS_ON_LINUX_I2C := \
+ CONFIG_MSTARDDC_SPI \
+ CONFIG_PARADE_LSPCON \
+ CONFIG_REALTEK_MST_I2C_SPI \
+ CONFIG_MEDIATEK_I2C_SPI \
+
+ifeq ($(CONFIG_ENABLE_LIBUSB1_PROGRAMMERS), no)
+$(call disable_all,$(DEPENDS_ON_LIBUSB1))
+endif
+
+ifeq ($(CONFIG_ENABLE_LIBPCI_PROGRAMMERS), no)
+$(call disable_all,$(DEPENDS_ON_LIBPCI))
+endif
+
###############################################################################
# General OS-specific settings.
# 1. Prepare for later by gathering information about host and target OS
@@ -99,264 +204,90 @@ ifeq ($(findstring MINGW, $(HOST_OS)), MINGW)
CC = gcc
endif
-ifneq ($(HOST_OS), SunOS)
-STRIP_ARGS = -s
-endif
+CC_WORKING := $(call c_compile_test, Makefile.d/cc_test.c)
-# Determine the destination OS.
-# IMPORTANT: The following line must be placed before TARGET_OS is ever used
-# (of course), but should come after any lines setting CC because the line
-# below uses CC itself.
-override TARGET_OS := $(strip $(call debug_shell,$(CC) $(CPPFLAGS) -E os.h 2>/dev/null \
- | tail -1 | cut -f 2 -d'"'))
+# Configs for dependencies. Can be overwritten by commandline
+CONFIG_LIBFTDI1_VERSION := $(call dependency_version, libftdi1)
+CONFIG_LIBFTDI1_CFLAGS := $(call dependency_cflags, libftdi1)
+CONFIG_LIBFTDI1_LDFLAGS := $(call dependency_ldflags, libftdi1)
-ifeq ($(TARGET_OS), Darwin)
-override CPPFLAGS += -I/opt/local/include -I/usr/local/include
-override LDFLAGS += -L/opt/local/lib -L/usr/local/lib
-endif
+CONFIG_NI845X_LIBRARY_PATH := 'C:\Program Files (x86)\National Instruments\NI-845x\MS Visual C'
+CONFIG_LIB_NI845X_CFLAGS := -I$(CONFIG_NI845X_LIBRARY_PATH)
+CONFIG_LIB_NI845X_LDFLAGS := -L$(CONFIG_NI845X_LIBRARY_PATH) -lni845x
-ifeq ($(TARGET_OS), FreeBSD)
-override CPPFLAGS += -I/usr/local/include
-override LDFLAGS += -L/usr/local/lib
-endif
+CONFIG_LIBJAYLINK_VERSION := $(call dependency_version, libjaylink)
+CONFIG_LIBJAYLINK_CFLAGS := $(call dependency_cflags, libjaylink)
+CONFIG_LIBJAYLINK_LDFLAGS := $(call dependency_ldflags, libjaylink)
-ifeq ($(TARGET_OS), OpenBSD)
-override CPPFLAGS += -I/usr/local/include
-override LDFLAGS += -L/usr/local/lib
-endif
+CONFIG_LIBUSB1_VERSION := $(call dependency_version, libusb-1.0)
+CONFIG_LIBUSB1_CFLAGS := $(call dependency_cflags, libusb-1.0)
+CONFIG_LIBUSB1_LDFLAGS := $(call dependency_ldflags, libusb-1.0)
-ifeq ($(TARGET_OS), NetBSD)
-override CPPFLAGS += -I/usr/pkg/include
-override LDFLAGS += -L/usr/pkg/lib
-endif
+CONFIG_LIBPCI_VERSION := $(call dependency_version, libpci)
+CONFIG_LIBPCI_CFLAGS := $(call dependency_cflags, libpci)
+CONFIG_LIBPCI_LDFLAGS := $(call dependency_ldflags, libpci)
-ifeq ($(TARGET_OS), DragonFlyBSD)
-override CPPFLAGS += -I/usr/local/include
-override LDFLAGS += -L/usr/local/lib
-endif
+# Determine the destination OS, architecture and endian
+# IMPORTANT: The following lines must be placed before TARGET_OS, ARCH or ENDIAN
+# is ever used (of course), but should come after any lines setting CC because
+# the lines below use CC itself.
+override TARGET_OS := $(call c_macro_test, Makefile.d/os_test.h)
+override ARCH := $(call c_macro_test, Makefile.d/arch_test.h)
+override ENDIAN := $(call c_macro_test, Makefile.d/endian_test.h)
+
+
+HAS_LIBFTDI1 := $(call find_dependency, libftdi1)
+HAS_LIB_NI845X := no
+HAS_LIBJAYLINK := $(call find_dependency, libjaylink)
+HAS_LIBUSB1 := $(call find_dependency, libusb-1.0)
+HAS_LIBPCI := $(call find_dependency, libpci)
+
+HAS_FT232H := $(call c_compile_test, Makefile.d/ft232h_test.c, $(CONFIG_LIBFTDI1_CFLAGS))
+HAS_UTSNAME := $(call c_compile_test, Makefile.d/utsname_test.c)
+HAS_CLOCK_GETTIME := $(call c_compile_test, Makefile.d/clock_gettime_test.c)
+HAS_EXTERN_LIBRT := $(call c_link_test, Makefile.d/clock_gettime_test.c, , -lrt)
+HAS_LINUX_MTD := $(call c_compile_test, Makefile.d/linux_mtd_test.c)
+HAS_LINUX_SPI := $(call c_compile_test, Makefile.d/linux_spi_test.c)
+HAS_LINUX_I2C := $(call c_compile_test, Makefile.d/linux_i2c_test.c)
+HAS_SERIAL := $(strip $(if $(filter $(TARGET_OS), DOS libpayload), no, yes))
+HAS_SPHINXBUILD := $(shell command -v $(SPHINXBUILD) >/dev/null 2>/dev/null && echo yes || echo no)
+EXEC_SUFFIX := $(strip $(if $(filter $(TARGET_OS), DOS MinGW), .exe))
+
+override CFLAGS += -Iinclude
ifeq ($(TARGET_OS), DOS)
-EXEC_SUFFIX := .exe
# DJGPP has odd uint*_t definitions which cause lots of format string warnings.
override CFLAGS += -Wno-format
-LIBS += -lgetopt
-# Bus Pirate, Serprog and PonyProg are not supported under DOS (missing serial support).
-ifeq ($(CONFIG_BUSPIRATE_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_BUSPIRATE_SPI=yes
-else
-override CONFIG_BUSPIRATE_SPI = no
-endif
-ifeq ($(CONFIG_SERPROG), yes)
-UNSUPPORTED_FEATURES += CONFIG_SERPROG=yes
-else
-override CONFIG_SERPROG = no
-endif
-ifeq ($(CONFIG_PONY_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_PONY_SPI=yes
-else
-override CONFIG_PONY_SPI = no
-endif
-# Digilent SPI, Dediprog, Developerbox, USB-Blaster, PICkit2, CH341A and FT2232 are not supported under DOS (missing USB support).
-ifeq ($(CONFIG_DIGILENT_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_DIGILENT_SPI=yes
-else
-override CONFIG_DIGILENT_SPI = no
-endif
-ifeq ($(CONFIG_DEDIPROG), yes)
-UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes
-else
-override CONFIG_DEDIPROG = no
-endif
-ifeq ($(CONFIG_DEVELOPERBOX_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_DEVELOPERBOX_SPI=yes
-else
-override CONFIG_DEVELOPERBOX_SPI = no
-endif
-ifeq ($(CONFIG_ENE_LPC), yes)
-UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes
-else
-override CONFIG_ENE_LPC = no
-endif
-ifeq ($(CONFIG_FT2232_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
-else
-override CONFIG_FT2232_SPI = no
-endif
-ifeq ($(CONFIG_MEC1308), yes)
-UNSUPPORTED_FEATURES += CONFIG_MEC1308=yes
-else
-override CONFIG_MEC1308 = no
-endif
-ifeq ($(CONFIG_USBBLASTER_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes
-else
-override CONFIG_USBBLASTER_SPI = no
-endif
-ifeq ($(CONFIG_PICKIT2_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_PICKIT2_SPI=yes
-else
-override CONFIG_PICKIT2_SPI = no
-endif
-ifeq ($(CONFIG_CH341A_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_CH341A_SPI=yes
-else
-override CONFIG_CH341A_SPI = no
+override LDFLAGS += -lgetopt
endif
-ifeq ($(CONFIG_STLINKV3_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_STLINKV3_SPI=yes
-else
-override CONFIG_STLINKV3_SPI = no
-endif
-ifeq ($(CONFIG_LSPCON_I2C_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_LSPCON_I2C_SPI=yes
-else
-override CONFIG_LSPCON_I2C_SPI = no
-endif
-ifeq ($(CONFIG_REALTEK_MST_I2C_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_REALTEK_MST_I2C_SPI=yes
-else
-override CONFIG_REALTEK_MST_I2C_SPI = no
-endif
-# libjaylink is also not available for DOS
-ifeq ($(CONFIG_JLINK_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_JLINK_SPI=yes
+
+ifeq ($(TARGET_OS), $(filter $(TARGET_OS), MinGW Cygwin))
+$(call mark_unsupported,$(DEPENDS_ON_RAW_MEM_ACCESS))
+$(call mark_unsupported,$(DEPENDS_ON_X86_PORT_IO))
+$(call mark_unsupported,$(DEPENDS_ON_X86_MSR))
+FEATURE_FLAGS += -D'IS_WINDOWS=1'
else
-override CONFIG_JLINK_SPI = no
-endif
+FEATURE_FLAGS += -D'IS_WINDOWS=0'
endif
# FIXME: Should we check for Cygwin/MSVC as well?
ifeq ($(TARGET_OS), MinGW)
-EXEC_SUFFIX := .exe
# MinGW doesn't have the ffs() function, but we can use gcc's __builtin_ffs().
FLASHROM_CFLAGS += -Dffs=__builtin_ffs
# Some functions provided by Microsoft do not work as described in C99 specifications. This macro fixes that
# for MinGW. See http://sourceforge.net/p/mingw-w64/wiki2/printf%20and%20scanf%20family/ */
FLASHROM_CFLAGS += -D__USE_MINGW_ANSI_STDIO=1
-# National Instruments USB-845x is Windows only for now
-CONFIG_NI845X_SPI ?= no
-
# For now we disable all PCI-based programmers on Windows/MinGW (no libpci).
-ifeq ($(CONFIG_INTERNAL), yes)
-UNSUPPORTED_FEATURES += CONFIG_INTERNAL=yes
-else
-override CONFIG_INTERNAL = no
-endif
-ifeq ($(CONFIG_RAYER_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_RAYER_SPI=yes
-else
-override CONFIG_RAYER_SPI = no
-endif
-ifeq ($(CONFIG_RAIDEN_DEBUG_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_RAIDEN_DEBUG_SPI=yes
-else
-override CONFIG_RAIDEN_DEBUG_SPI = no
-endif
-ifeq ($(CONFIG_NIC3COM), yes)
-UNSUPPORTED_FEATURES += CONFIG_NIC3COM=yes
-else
-override CONFIG_NIC3COM = no
-endif
-ifeq ($(CONFIG_GFXNVIDIA), yes)
-UNSUPPORTED_FEATURES += CONFIG_GFXNVIDIA=yes
-else
-override CONFIG_GFXNVIDIA = no
-endif
-ifeq ($(CONFIG_SATASII), yes)
-UNSUPPORTED_FEATURES += CONFIG_SATASII=yes
-else
-override CONFIG_SATASII = no
-endif
-ifeq ($(CONFIG_ATAHPT), yes)
-UNSUPPORTED_FEATURES += CONFIG_ATAHPT=yes
-else
-override CONFIG_ATAHPT = no
-endif
-ifeq ($(CONFIG_ATAVIA), yes)
-UNSUPPORTED_FEATURES += CONFIG_ATAVIA=yes
-else
-override CONFIG_ATAVIA = no
-endif
-ifeq ($(CONFIG_ATAPROMISE), yes)
-UNSUPPORTED_FEATURES += CONFIG_ATAPROMISE=yes
-else
-override CONFIG_ATAPROMISE = no
-endif
-ifeq ($(CONFIG_ENE_LPC), yes)
-UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes
-else
-override CONFIG_ENE_LPC = no
-endif
-ifeq ($(CONFIG_IT8212), yes)
-UNSUPPORTED_FEATURES += CONFIG_IT8212=yes
-else
-override CONFIG_IT8212 = no
-endif
-ifeq ($(CONFIG_DRKAISER), yes)
-UNSUPPORTED_FEATURES += CONFIG_DRKAISER=yes
-else
-override CONFIG_DRKAISER = no
-endif
-ifeq ($(CONFIG_MEC1308), yes)
-UNSUPPORTED_FEATURES += CONFIG_MEC1308=yes
-else
-override CONFIG_MEC1308 = no
-endif
-ifeq ($(CONFIG_NICREALTEK), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICREALTEK=yes
-else
-override CONFIG_NICREALTEK = no
-endif
-ifeq ($(CONFIG_NICNATSEMI), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICNATSEMI=yes
-else
-override CONFIG_NICNATSEMI = no
-endif
-ifeq ($(CONFIG_NICINTEL), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICINTEL=yes
-else
-override CONFIG_NICINTEL = no
-endif
-ifeq ($(CONFIG_NICINTEL_EEPROM), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICINTEL_EEPROM=yes
-else
-override CONFIG_NICINTEL_EEPROM = no
-endif
-ifeq ($(CONFIG_NICINTEL_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICINTEL_SPI=yes
-else
-override CONFIG_NICINTEL_SPI = no
-endif
-ifeq ($(CONFIG_OGP_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_OGP_SPI=yes
-else
-override CONFIG_OGP_SPI = no
-endif
-ifeq ($(CONFIG_SATAMV), yes)
-UNSUPPORTED_FEATURES += CONFIG_SATAMV=yes
-else
-override CONFIG_SATAMV = no
-endif
-ifeq ($(CONFIG_LSPCON_I2C_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_LSPCON_I2C_SPI=yes
-else
-override CONFIG_LSPCON_I2C_SPI = no
-endif
-ifeq ($(CONFIG_REALTEK_MST_I2C_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_REALTEK_MST_I2C_SPI=yes
-else
-override CONFIG_REALTEK_MST_I2C_SPI = no
-endif
-endif
+$(call mark_unsupported,$(DEPENDS_ON_LIBPCI))
+# And programmers that need raw access.
+$(call mark_unsupported,$(DEPENDS_ON_RAW_MEM_ACCESS))
+
+else # No MinGW
-ifneq ($(TARGET_OS), MinGW)
# NI USB-845x only supported on Windows at the moment
-ifeq ($(CONFIG_NI845X_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_NI845X_SPI=yes
-else
-override CONFIG_NI845X_SPI = no
-endif
+$(call mark_unsupported,CONFIG_NI845X_SPI)
+
endif
ifeq ($(TARGET_OS), libpayload)
@@ -364,325 +295,116 @@ ifeq ($(MAKECMDGOALS),)
.DEFAULT_GOAL := libflashrom.a
$(info Setting default goal to libflashrom.a)
endif
-FLASHROM_CFLAGS += -DSTANDALONE
-ifeq ($(CONFIG_DUMMY), yes)
-UNSUPPORTED_FEATURES += CONFIG_DUMMY=yes
-else
-override CONFIG_DUMMY = no
-endif
+$(call mark_unsupported,CONFIG_DUMMY)
# libpayload does not provide the romsize field in struct pci_dev that the atapromise code requires.
-ifeq ($(CONFIG_ATAPROMISE), yes)
-UNSUPPORTED_FEATURES += CONFIG_ATAPROMISE=yes
-else
-override CONFIG_ATAPROMISE = no
-endif
-# Bus Pirate, Serprog and PonyProg are not supported with libpayload (missing serial support).
-ifeq ($(CONFIG_BUSPIRATE_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_BUSPIRATE_SPI=yes
-else
-override CONFIG_BUSPIRATE_SPI = no
-endif
-ifeq ($(CONFIG_SERPROG), yes)
-UNSUPPORTED_FEATURES += CONFIG_SERPROG=yes
-else
-override CONFIG_SERPROG = no
-endif
-ifeq ($(CONFIG_PONY_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_PONY_SPI=yes
-else
-override CONFIG_PONY_SPI = no
-endif
+$(call mark_unsupported,CONFIG_ATAPROMISE)
# Dediprog, Developerbox, USB-Blaster, PICkit2, CH341A and FT2232 are not supported with libpayload (missing libusb support).
-ifeq ($(CONFIG_DEDIPROG), yes)
-UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes
-else
-override CONFIG_DEDIPROG = no
-endif
-ifeq ($(CONFIG_DEVELOPERBOX_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_DEVELOPERBOX_SPI=yes
-else
-override CONFIG_DEVELOPERBOX_SPI = no
-endif
-ifeq ($(CONFIG_ENE_LPC), yes)
-UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes
-else
-override CONFIG_ENE_LPC = no
+$(call mark_unsupported,$(DEPENDS_ON_LIBUSB1) $(DEPENDS_ON_LIBFTDI) $(DEPENDS_ON_LIBJAYLINK))
endif
-ifeq ($(CONFIG_FT2232_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes
-else
-override CONFIG_FT2232_SPI = no
-endif
-ifeq ($(CONFIG_MEC1308), yes)
-UNSUPPORTED_FEATURES += CONFIG_MEC1308=yes
-else
-override CONFIG_MEC1308 = no
-endif
-ifeq ($(CONFIG_USBBLASTER_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes
-else
-override CONFIG_USBBLASTER_SPI = no
-endif
-ifeq ($(CONFIG_PICKIT2_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_PICKIT2_SPI=yes
-else
-override CONFIG_PICKIT2_SPI = no
-endif
-ifeq ($(CONFIG_STLINKV3_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_STLINKV3_SPI=yes
-else
-override CONFIG_STLINKV3_SPI = no
-endif
-ifeq ($(CONFIG_LSPCON_I2C_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_LSPCON_I2C_SPI=yes
-else
-override CONFIG_LSPCON_I2C_SPI = no
-endif
-ifeq ($(CONFIG_REALTEK_MST_I2C_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_REALTEK_MST_I2C_SPI=yes
-else
-override CONFIG_REALTEK_MST_I2C_SPI = no
+
+ifeq ($(HAS_LINUX_MTD), no)
+$(call mark_unsupported,CONFIG_LINUX_MTD)
endif
-ifeq ($(CONFIG_CH341A_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_CH341A_SPI=yes
-else
-override CONFIG_CH341A_SPI = no
+
+ifeq ($(HAS_LINUX_SPI), no)
+$(call mark_unsupported,CONFIG_LINUX_SPI)
endif
+
+ifeq ($(HAS_LINUX_I2C), no)
+$(call mark_unsupported,DEPENDS_ON_LINUX_I2C)
endif
-ifneq ($(TARGET_OS), Linux)
-# Android is handled internally as separate OS, but it supports CONFIG_LINUX_SPI and CONFIG_MSTARDDC_SPI
-ifneq ($(TARGET_OS), Android)
-ifeq ($(CONFIG_LINUX_MTD), yes)
-UNSUPPORTED_FEATURES += CONFIG_LINUX_MTD=yes
-else
-override CONFIG_LINUX_MTD = no
+ifeq ($(TARGET_OS), Android)
+# Android on x86 (currently) does not provide raw PCI port I/O operations.
+$(call mark_unsupported,$(DEPENDS_ON_X86_PORT_IO))
endif
-ifeq ($(CONFIG_LINUX_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_LINUX_SPI=yes
-else
-override CONFIG_LINUX_SPI = no
+
+# Disable the internal programmer on unsupported architectures or systems
+ifeq ($(or $(filter $(ARCH), x86), $(filter $(TARGET_OS), Linux)), )
+$(call mark_unsupported,CONFIG_INTERNAL)
endif
-ifeq ($(CONFIG_MSTARDDC_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_MSTARDDC_SPI=yes
-else
-override CONFIG_MSTARDDC_SPI = no
+
+ifeq ($(HAS_LIBPCI), no)
+$(call mark_unsupported,$(DEPENDS_ON_LIBPCI))
endif
+
+ifeq ($(HAS_LIBFTDI1), no)
+$(call mark_unsupported,$(DEPENDS_ON_LIBFTDI1))
endif
+
+ifeq ($(HAS_LIB_NI845X), no)
+$(call mark_unsupported,$(DEPENDS_ON_LIB_NI845X))
endif
-ifeq ($(TARGET_OS), Android)
-# Android on x86 (currently) does not provide raw PCI port I/O operations
-ifeq ($(CONFIG_RAYER_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_RAYER_SPI=yes
-else
-override CONFIG_RAYER_SPI = no
+ifeq ($(HAS_LIBJAYLINK), no)
+$(call mark_unsupported,$(DEPENDS_ON_LIBJAYLINK))
endif
+
+ifeq ($(HAS_LIBUSB1), no)
+$(call mark_unsupported,$(DEPENDS_ON_LIBUSB1))
endif
-ifeq ($(TARGET_OS), Linux)
-CONFIG_LINUX_I2C_HELPER = yes
+ifeq ($(HAS_SERIAL), no)
+$(call mark_unsupported, $(DEPENDS_ON_SERIAL))
endif
-###############################################################################
-# General architecture-specific settings.
-# Like above for the OS, below we verify user-supplied options depending on the target architecture.
-
-# Determine the destination processor architecture.
-# IMPORTANT: The following line must be placed before ARCH is ever used
-# (of course), but should come after any lines setting CC because the line
-# below uses CC itself.
-override ARCH := $(strip $(call debug_shell,$(CC) $(CPPFLAGS) -E archtest.c 2>/dev/null \
- | tail -1 | cut -f 2 -d'"'))
-override ENDIAN := $(strip $(call debug_shell,$(CC) $(CPPFLAGS) -E endiantest.c 2>/dev/null \
- | tail -1))
-
-# Disable the internal programmer on unsupported architectures (everything but x86 and mipsel)
-ifneq ($(ARCH)-little, $(filter $(ARCH),x86 mips)-$(ENDIAN))
-ifeq ($(CONFIG_INTERNAL), yes)
-UNSUPPORTED_FEATURES += CONFIG_INTERNAL=yes
-else
-override CONFIG_INTERNAL = no
+ifeq ($(ENDIAN), little)
+FEATURE_FLAGS += -D'__FLASHROM_LITTLE_ENDIAN__=1'
endif
+ifeq ($(ENDIAN), big)
+FEATURE_FLAGS += -D'__FLASHROM_BIG_ENDIAN__=1'
endif
# PCI port I/O support is unimplemented on PPC/MIPS/SPARC and unavailable on ARM.
# Right now this means the drivers below only work on x86.
ifneq ($(ARCH), x86)
-ifeq ($(CONFIG_NIC3COM), yes)
-UNSUPPORTED_FEATURES += CONFIG_NIC3COM=yes
-else
-override CONFIG_NIC3COM = no
-endif
-ifeq ($(CONFIG_NICREALTEK), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICREALTEK=yes
-else
-override CONFIG_NICREALTEK = no
-endif
-ifeq ($(CONFIG_NICNATSEMI), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICNATSEMI=yes
-else
-override CONFIG_NICNATSEMI = no
-endif
-ifeq ($(CONFIG_RAYER_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_RAYER_SPI=yes
-else
-override CONFIG_RAYER_SPI = no
-endif
-ifeq ($(CONFIG_ATAHPT), yes)
-UNSUPPORTED_FEATURES += CONFIG_ATAHPT=yes
-else
-override CONFIG_ATAHPT = no
-endif
-ifeq ($(CONFIG_ATAPROMISE), yes)
-UNSUPPORTED_FEATURES += CONFIG_ATAPROMISE=yes
-else
-override CONFIG_ATAPROMISE = no
-endif
-ifeq ($(CONFIG_SATAMV), yes)
-UNSUPPORTED_FEATURES += CONFIG_SATAMV=yes
-else
-override CONFIG_SATAMV = no
-endif
-ifeq ($(CONFIG_ENE_LPC), yes)
-UNSUPPORTED_FEATURES += CONFIG_ENE_LPC=yes
-else
-override CONFIG_ENE_LPC = no
-endif
-ifeq ($(CONFIG_MEC1308), yes)
-UNSUPPORTED_FEATURES += CONFIG_MEC1308=yes
-else
-override CONFIG_MEC1308 = no
-endif
+$(call mark_unsupported,$(DEPENDS_ON_X86_MSR))
+$(call mark_unsupported,$(DEPENDS_ON_X86_PORT_IO))
endif
-# Disable all drivers needing raw access (memory, PCI, port I/O) on
-# architectures with unknown raw access properties.
+# Additionally disable all drivers needing raw access (memory, PCI, port I/O)
+# on architectures with unknown raw access properties.
# Right now those architectures are alpha hppa m68k sh s390
-ifneq ($(ARCH),$(filter $(ARCH),x86 mips ppc arm sparc arc))
-ifeq ($(CONFIG_RAYER_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_RAYER_SPI=yes
-else
-override CONFIG_RAYER_SPI = no
-endif
-ifeq ($(CONFIG_NIC3COM), yes)
-UNSUPPORTED_FEATURES += CONFIG_NIC3COM=yes
-else
-override CONFIG_NIC3COM = no
-endif
-ifeq ($(CONFIG_GFXNVIDIA), yes)
-UNSUPPORTED_FEATURES += CONFIG_GFXNVIDIA=yes
-else
-override CONFIG_GFXNVIDIA = no
-endif
-ifeq ($(CONFIG_SATASII), yes)
-UNSUPPORTED_FEATURES += CONFIG_SATASII=yes
-else
-override CONFIG_SATASII = no
-endif
-ifeq ($(CONFIG_ATAHPT), yes)
-UNSUPPORTED_FEATURES += CONFIG_ATAHPT=yes
-else
-override CONFIG_ATAHPT = no
-endif
-ifeq ($(CONFIG_ATAVIA), yes)
-UNSUPPORTED_FEATURES += CONFIG_ATAVIA=yes
-else
-override CONFIG_ATAVIA = no
-endif
-ifeq ($(CONFIG_ATAPROMISE), yes)
-UNSUPPORTED_FEATURES += CONFIG_ATAPROMISE=yes
-else
-override CONFIG_ATAPROMISE = no
-endif
-ifeq ($(CONFIG_DRKAISER), yes)
-UNSUPPORTED_FEATURES += CONFIG_DRKAISER=yes
-else
-override CONFIG_DRKAISER = no
-endif
-ifeq ($(CONFIG_NICREALTEK), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICREALTEK=yes
-else
-override CONFIG_NICREALTEK = no
-endif
-ifeq ($(CONFIG_NICNATSEMI), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICNATSEMI=yes
-else
-override CONFIG_NICNATSEMI = no
-endif
-ifeq ($(CONFIG_NICINTEL), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICINTEL=yes
-else
-override CONFIG_NICINTEL = no
-endif
-ifeq ($(CONFIG_NICINTEL_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICINTEL_SPI=yes
-else
-override CONFIG_NICINTEL_SPI = no
-endif
-ifeq ($(CONFIG_NICINTEL_EEPROM), yes)
-UNSUPPORTED_FEATURES += CONFIG_NICINTEL_EEPROM=yes
-else
-override CONFIG_NICINTEL_EEPROM = no
-endif
-ifeq ($(CONFIG_OGP_SPI), yes)
-UNSUPPORTED_FEATURES += CONFIG_OGP_SPI=yes
-else
-override CONFIG_OGP_SPI = no
-endif
-ifeq ($(CONFIG_SATAMV), yes)
-UNSUPPORTED_FEATURES += CONFIG_SATAMV=yes
-else
-override CONFIG_SATAMV = no
-endif
-ifeq ($(CONFIG_IT8212), yes)
-UNSUPPORTED_FEATURES += CONFIG_IT8212=yes
-else
-override CONFIG_IT8212 = no
-endif
+ifneq ($(ARCH), $(filter $(ARCH), x86 mips ppc arm sparc arc e2k))
+$(call mark_unsupported,$(DEPENDS_ON_RAW_MEM_ACCESS))
endif
###############################################################################
# Flash chip drivers and bus support infrastructure.
-CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \
+CHIP_OBJS = jedec.o printlock.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 writeprotect.o s25f.o
+ spi95.o opaque.o sfdp.o en29lv640b.o at45db.o s25f.o \
+ writeprotect.o writeprotect_ranges.o
###############################################################################
# Library code.
-LIB_OBJS = libflashrom.o layout.o flashrom.o udelay.o programmer.o helpers.o ich_descriptors.o fmap.o
+LIB_OBJS = libflashrom.o layout.o erasure_layout.o flashrom.o udelay.o parallel.o programmer.o programmer_table.o \
+ helpers.o helpers_fileio.o ich_descriptors.o fmap.o platform/endian_$(ENDIAN).o platform/memaccess.o
+
###############################################################################
# Frontend related stuff.
CLI_OBJS = cli_classic.o cli_output.o cli_common.o print.o
-# versioninfo.inc stores metadata required to build a packaged flashrom. It is generated by the export rule and
-# imported below. If versioninfo.inc is not found and the variables are not defined by the user, the info will
-# be obtained using util/getrevision.sh, which is the common case during development.
--include versioninfo.inc
-VERSION ?= $(shell ./util/getrevision.sh --revision)
-MAN_DATE ?= $(shell ./util/getrevision.sh --date $(PROGRAM).8.tmpl 2>/dev/null)
-
-SCMDEF := -D'FLASHROM_VERSION="$(VERSION)"'
+VERSION ?= $(shell cat ./VERSION)
+VERSION_GIT ?= $(shell git describe 2>/dev/null)
+ifdef VERSION_GIT
+ VERSION := "$(VERSION) (git:$(VERSION_GIT))"
+endif
# No spaces in release names unless set explicitly
RELEASENAME ?= $(shell echo "$(VERSION)" | sed -e 's/ /_/')
-# Inform user of the version string
-$(info Replacing all version templates with $(VERSION).)
-
-# If a VCS is found then try to install hooks.
-$(shell ./util/getrevision.sh -c 2>/dev/null && ./util/git-hooks/install.sh)
-
###############################################################################
# Default settings of CONFIG_* variables.
# Always enable internal/onboard support for now.
CONFIG_INTERNAL ?= yes
+CONFIG_INTERNAL_X86 ?= yes
# Always enable serprog for now.
CONFIG_SERPROG ?= yes
@@ -705,6 +427,9 @@ CONFIG_GFXNVIDIA ?= yes
# Always enable SiI SATA controllers for now.
CONFIG_SATASII ?= yes
+# ASMedia ASM106x
+CONFIG_ASM106X ?= yes
+
# Highpoint (HPT) ATA/RAID controller support.
# IMPORTANT: This code is not yet working!
CONFIG_ATAHPT ?= no
@@ -715,15 +440,9 @@ CONFIG_ATAVIA ?= yes
# Promise ATA controller support.
CONFIG_ATAPROMISE ?= no
-# ENE LPC interface keyboard controller
-CONFIG_ENE_LPC ?= yes
-
# Always enable FT2232 SPI dongles for now.
CONFIG_FT2232_SPI ?= yes
-# Microchip MEC1308 Embedded Controller
-CONFIG_MEC1308 ?= yes
-
# Always enable Altera USB-Blaster dongles for now.
CONFIG_USBBLASTER_SPI ?= yes
@@ -736,8 +455,11 @@ CONFIG_PICKIT2_SPI ?= yes
# Always enable STLink V3
CONFIG_STLINKV3_SPI ?= yes
-# Disables LSPCON support until the i2c helper supports multiple systems.
-CONFIG_LSPCON_I2C_SPI ?= no
+# Disables Parade LSPCON support until the i2c helper supports multiple systems.
+CONFIG_PARADE_LSPCON ?= no
+
+# Disables MediaTek support until the i2c helper supports multiple systems.
+CONFIG_MEDIATEK_I2C_SPI ?= no
# Disables REALTEK_MST support until the i2c helper supports multiple systems.
CONFIG_REALTEK_MST_I2C_SPI ?= no
@@ -788,12 +510,21 @@ CONFIG_IT8212 ?= yes
# Winchiphead CH341A
CONFIG_CH341A_SPI ?= yes
+# Winchiphead CH347
+CONFIG_CH347_SPI ?= yes
+
# Digilent Development board JTAG
CONFIG_DIGILENT_SPI ?= yes
+# DirtyJTAG
+CONFIG_DIRTYJTAG_SPI ?= yes
+
# Disable J-Link for now.
CONFIG_JLINK_SPI ?= no
+# National Instruments USB-845x is Windows only and needs a proprietary library.
+CONFIG_NI845X_SPI ?= no
+
# Disable wiki printing by default. It is only useful if you have wiki access.
CONFIG_PRINT_WIKI ?= no
@@ -814,59 +545,6 @@ $(foreach var, $(filter CONFIG_%, $(.VARIABLES)),\
$(eval $(var)=yes)))
endif
-ifeq ($(CONFIG_ENABLE_LIBUSB1_PROGRAMMERS), no)
-override CONFIG_CH341A_SPI = no
-override CONFIG_DEDIPROG = no
-override CONFIG_DIGILENT_SPI = no
-override CONFIG_DEVELOPERBOX_SPI = no
-override CONFIG_PICKIT2_SPI = no
-override CONFIG_RAIDEN_DEBUG_SPI = no
-override CONFIG_STLINKV3_SPI = no
-endif
-ifeq ($(CONFIG_ENABLE_LIBPCI_PROGRAMMERS), no)
-override CONFIG_INTERNAL = no
-override CONFIG_NIC3COM = no
-override CONFIG_GFXNVIDIA = no
-override CONFIG_SATASII = no
-override CONFIG_ATAHPT = no
-override CONFIG_ATAVIA = no
-override CONFIG_ATAPROMISE = no
-override CONFIG_ENE_LPC = no
-override CONFIG_IT8212 = no
-override CONFIG_DRKAISER = no
-override CONFIG_MEC1308 = no
-override CONFIG_NICREALTEK = no
-override CONFIG_NICNATSEMI = no
-override CONFIG_NICINTEL = no
-override CONFIG_NICINTEL_SPI = no
-override CONFIG_NICINTEL_EEPROM = no
-override CONFIG_OGP_SPI = no
-override CONFIG_SATAMV = no
-endif
-
-# Bitbanging SPI infrastructure, default off unless needed.
-ifeq ($(CONFIG_RAYER_SPI), yes)
-override CONFIG_BITBANG_SPI = yes
-else
-ifeq ($(CONFIG_PONY_SPI), yes)
-override CONFIG_BITBANG_SPI = yes
-else
-ifeq ($(CONFIG_INTERNAL), yes)
-override CONFIG_BITBANG_SPI = yes
-else
-ifeq ($(CONFIG_NICINTEL_SPI), yes)
-override CONFIG_BITBANG_SPI = yes
-else
-ifeq ($(CONFIG_OGP_SPI), yes)
-override CONFIG_BITBANG_SPI = yes
-else
-CONFIG_BITBANG_SPI ?= no
-endif
-endif
-endif
-endif
-endif
-
###############################################################################
# Handle CONFIG_* variables that depend on others set (and verified) above.
@@ -888,821 +566,506 @@ CONFIG_INTERNAL_DMI ?= yes
# Programmer drivers and programmer support infrastructure.
# Depending on the CONFIG_* variables set and verified above we set compiler flags and parameters below.
-FEATURE_CFLAGS += -D'CONFIG_DEFAULT_PROGRAMMER=$(CONFIG_DEFAULT_PROGRAMMER)'
-FEATURE_CFLAGS += -D'CONFIG_DEFAULT_PROGRAMMER_ARGS="$(CONFIG_DEFAULT_PROGRAMMER_ARGS)"'
+ifdef CONFIG_DEFAULT_PROGRAMMER_NAME
+FEATURE_FLAGS += -D'CONFIG_DEFAULT_PROGRAMMER_NAME=&programmer_$(CONFIG_DEFAULT_PROGRAMMER_NAME)'
+else
+FEATURE_FLAGS += -D'CONFIG_DEFAULT_PROGRAMMER_NAME=NULL'
+endif
+
+FEATURE_FLAGS += -D'CONFIG_DEFAULT_PROGRAMMER_ARGS="$(CONFIG_DEFAULT_PROGRAMMER_ARGS)"'
+
+################################################################################
-ifeq ($(CONFIG_INTERNAL), yes)
-FEATURE_CFLAGS += -D'CONFIG_INTERNAL=1'
-PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o internal.o
ifeq ($(ARCH), x86)
-PROGRAMMER_OBJS += it87spi.o it85spi.o sb600spi.o amd_imc.o wbsio_spi.o mcp6x_spi.o
-PROGRAMMER_OBJS += ichspi.o dmi.o
-ifeq ($(CONFIG_INTERNAL_DMI), yes)
-FEATURE_CFLAGS += -D'CONFIG_INTERNAL_DMI=1'
+ifeq ($(CONFIG_INTERNAL) $(CONFIG_INTERNAL_X86), yes yes)
+FEATURE_FLAGS += -D'CONFIG_INTERNAL=1'
+PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o \
+ internal.o internal_par.o it87spi.o sb600spi.o superio.o amd_imc.o wbsio_spi.o mcp6x_spi.o \
+ ichspi.o dmi.o known_boards.o
+ACTIVE_PROGRAMMERS += internal
endif
else
+ifeq ($(CONFIG_INTERNAL), yes)
+FEATURE_FLAGS += -D'CONFIG_INTERNAL=1'
+PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o internal.o internal_par.o known_boards.o
+ACTIVE_PROGRAMMERS += internal
endif
-NEED_LIBPCI += CONFIG_INTERNAL
-endif
-
-ifeq ($(CONFIG_ENE_LPC), yes)
-FEATURE_CFLAGS += -D'CONFIG_ENE_LPC=1'
-PROGRAMMER_OBJS += ene_lpc.o
-NEED_RAW_ACCESS += CONFIG_ENE_LPC
-NEED_LIBPCI += CONFIG_ENE_LPC
endif
-ifeq ($(CONFIG_MEC1308), yes)
-FEATURE_CFLAGS += -D'CONFIG_MEC1308=1'
-PROGRAMMER_OBJS += mec1308.o
-NEED_RAW_ACCESS += CONFIG_MEC1308
-NEED_LIBPCI += CONFIG_MEC1308
+ifeq ($(CONFIG_INTERNAL_DMI), yes)
+FEATURE_FLAGS += -D'CONFIG_INTERNAL_DMI=1'
endif
ifeq ($(CONFIG_SERPROG), yes)
-FEATURE_CFLAGS += -D'CONFIG_SERPROG=1'
+FEATURE_FLAGS += -D'CONFIG_SERPROG=1'
PROGRAMMER_OBJS += serprog.o
-NEED_SERIAL += CONFIG_SERPROG
-NEED_POSIX_SOCKETS += CONFIG_SERPROG
+ACTIVE_PROGRAMMERS += serprog
endif
ifeq ($(CONFIG_RAYER_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_RAYER_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_RAYER_SPI=1'
PROGRAMMER_OBJS += rayer_spi.o
-NEED_RAW_ACCESS += CONFIG_RAYER_SPI
+ACTIVE_PROGRAMMERS += rayer_spi
endif
ifeq ($(CONFIG_RAIDEN_DEBUG_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_RAIDEN_DEBUG_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_RAIDEN_DEBUG_SPI=1'
PROGRAMMER_OBJS += raiden_debug_spi.o
+ACTIVE_PROGRAMMERS += raiden_debug_spi
endif
ifeq ($(CONFIG_PONY_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_PONY_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_PONY_SPI=1'
PROGRAMMER_OBJS += pony_spi.o
-NEED_SERIAL += CONFIG_PONY_SPI
-endif
-
-ifeq ($(CONFIG_BITBANG_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_BITBANG_SPI=1'
-PROGRAMMER_OBJS += bitbang_spi.o
+ACTIVE_PROGRAMMERS += pony_spi
endif
ifeq ($(CONFIG_NIC3COM), yes)
-FEATURE_CFLAGS += -D'CONFIG_NIC3COM=1'
+FEATURE_FLAGS += -D'CONFIG_NIC3COM=1'
PROGRAMMER_OBJS += nic3com.o
-NEED_LIBPCI += CONFIG_NIC3COM
+ACTIVE_PROGRAMMERS += nic3com
endif
ifeq ($(CONFIG_GFXNVIDIA), yes)
-FEATURE_CFLAGS += -D'CONFIG_GFXNVIDIA=1'
+FEATURE_FLAGS += -D'CONFIG_GFXNVIDIA=1'
PROGRAMMER_OBJS += gfxnvidia.o
-NEED_LIBPCI += CONFIG_GFXNVIDIA
+ACTIVE_PROGRAMMERS += gfxnvidia
endif
ifeq ($(CONFIG_SATASII), yes)
-FEATURE_CFLAGS += -D'CONFIG_SATASII=1'
+FEATURE_FLAGS += -D'CONFIG_SATASII=1'
PROGRAMMER_OBJS += satasii.o
-NEED_LIBPCI += CONFIG_SATASII
+ACTIVE_PROGRAMMERS += satasii
+endif
+
+ifeq ($(CONFIG_ASM106X), yes)
+FEATURE_FLAGS += -D'CONFIG_ASM106X=1'
+PROGRAMMER_OBJS += asm106x.o
+ACTIVE_PROGRAMMERS += asm106x
endif
ifeq ($(CONFIG_ATAHPT), yes)
-FEATURE_CFLAGS += -D'CONFIG_ATAHPT=1'
+FEATURE_FLAGS += -D'CONFIG_ATAHPT=1'
PROGRAMMER_OBJS += atahpt.o
-NEED_LIBPCI += CONFIG_ATAHPT
+ACTIVE_PROGRAMMERS += atahpt
endif
ifeq ($(CONFIG_ATAVIA), yes)
-FEATURE_CFLAGS += -D'CONFIG_ATAVIA=1'
+FEATURE_FLAGS += -D'CONFIG_ATAVIA=1'
PROGRAMMER_OBJS += atavia.o
-NEED_LIBPCI += CONFIG_ATAVIA
+ACTIVE_PROGRAMMERS += atavia
endif
ifeq ($(CONFIG_ATAPROMISE), yes)
-FEATURE_CFLAGS += -D'CONFIG_ATAPROMISE=1'
+FEATURE_FLAGS += -D'CONFIG_ATAPROMISE=1'
PROGRAMMER_OBJS += atapromise.o
-NEED_LIBPCI += CONFIG_ATAPROMISE
+ACTIVE_PROGRAMMERS += atapromise
endif
ifeq ($(CONFIG_IT8212), yes)
-FEATURE_CFLAGS += -D'CONFIG_IT8212=1'
+FEATURE_FLAGS += -D'CONFIG_IT8212=1'
PROGRAMMER_OBJS += it8212.o
-NEED_LIBPCI += CONFIG_IT8212
+ACTIVE_PROGRAMMERS += it8212
endif
ifeq ($(CONFIG_FT2232_SPI), yes)
-# This is a totally ugly hack.
-FEATURE_CFLAGS += $(call debug_shell,grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_FT2232_SPI=1'")
-NEED_LIBFTDI += CONFIG_FT2232_SPI
+FEATURE_FLAGS += -D'CONFIG_FT2232_SPI=1'
PROGRAMMER_OBJS += ft2232_spi.o
+ACTIVE_PROGRAMMERS += ft2232_spi
endif
ifeq ($(CONFIG_USBBLASTER_SPI), yes)
-# This is a totally ugly hack.
-FEATURE_CFLAGS += $(call debug_shell,grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_USBBLASTER_SPI=1'")
-NEED_LIBFTDI += CONFIG_USBBLASTER_SPI
+FEATURE_FLAGS += -D'CONFIG_USBBLASTER_SPI=1'
PROGRAMMER_OBJS += usbblaster_spi.o
+ACTIVE_PROGRAMMERS += usbblaster_spi
endif
ifeq ($(CONFIG_PICKIT2_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_PICKIT2_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_PICKIT2_SPI=1'
PROGRAMMER_OBJS += pickit2_spi.o
-NEED_LIBUSB1 += CONFIG_PICKIT2_SPI
+ACTIVE_PROGRAMMERS += pickit2_spi
endif
ifeq ($(CONFIG_STLINKV3_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_STLINKV3_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_STLINKV3_SPI=1'
PROGRAMMER_OBJS += stlinkv3_spi.o
-NEED_LIBUSB1 += CONFIG_STLINKV3_SPI
+ACTIVE_PROGRAMMERS += stlinkv3_spi
endif
-ifeq ($(CONFIG_LSPCON_I2C_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_LSPCON_I2C_SPI=1'
-PROGRAMMER_OBJS += lspcon_i2c_spi.o
+ifeq ($(CONFIG_PARADE_LSPCON), yes)
+FEATURE_FLAGS += -D'CONFIG_PARADE_LSPCON=1'
+PROGRAMMER_OBJS += parade_lspcon.o
+ACTIVE_PROGRAMMERS += parade_lspcon
endif
-ifeq ($(CONFIG_REALTEK_MST_I2C_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_REALTEK_MST_I2C_SPI=1'
-PROGRAMMER_OBJS += realtek_mst_i2c_spi.o
+ifeq ($(CONFIG_MEDIATEK_I2C_SPI), yes)
+FEATURE_FLAGS += -D'CONFIG_MEDIATEK_I2C_SPI=1'
+PROGRAMMER_OBJS += mediatek_i2c_spi.o
+ACTIVE_PROGRAMMERS += mediatek_i2c_spi
endif
-ifneq ($(NEED_LIBFTDI), )
-FTDILIBS := $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)" ; $(PKG_CONFIG) --libs libftdi1 || $(PKG_CONFIG) --libs libftdi || printf "%s" "-lftdi -lusb")
-FEATURE_CFLAGS += $(call debug_shell,grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'")
-FTDI_INCLUDES := $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)" ; $(PKG_CONFIG) --cflags-only-I libftdi1)
-FEATURE_CFLAGS += $(FTDI_INCLUDES)
-FEATURE_LIBS += $(call debug_shell,grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)")
-# We can't set NEED_LIBUSB1 here because that would transform libftdi auto-enabling
-# into a hard requirement for libusb, defeating the purpose of auto-enabling.
+ifeq ($(CONFIG_REALTEK_MST_I2C_SPI), yes)
+FEATURE_FLAGS += -D'CONFIG_REALTEK_MST_I2C_SPI=1'
+PROGRAMMER_OBJS += realtek_mst_i2c_spi.o
+ACTIVE_PROGRAMMERS += realtek_mst_i2c_spi
endif
ifeq ($(CONFIG_DUMMY), yes)
-FEATURE_CFLAGS += -D'CONFIG_DUMMY=1'
+FEATURE_FLAGS += -D'CONFIG_DUMMY=1'
PROGRAMMER_OBJS += dummyflasher.o
+ACTIVE_PROGRAMMERS += dummyflasher
endif
ifeq ($(CONFIG_DRKAISER), yes)
-FEATURE_CFLAGS += -D'CONFIG_DRKAISER=1'
+FEATURE_FLAGS += -D'CONFIG_DRKAISER=1'
PROGRAMMER_OBJS += drkaiser.o
-NEED_LIBPCI += CONFIG_DRKAISER
+ACTIVE_PROGRAMMERS += drkaiser
endif
ifeq ($(CONFIG_NICREALTEK), yes)
-FEATURE_CFLAGS += -D'CONFIG_NICREALTEK=1'
+FEATURE_FLAGS += -D'CONFIG_NICREALTEK=1'
PROGRAMMER_OBJS += nicrealtek.o
-NEED_LIBPCI += CONFIG_NICREALTEK
+ACTIVE_PROGRAMMERS += nicrealtek
endif
ifeq ($(CONFIG_NICNATSEMI), yes)
-FEATURE_CFLAGS += -D'CONFIG_NICNATSEMI=1'
+FEATURE_FLAGS += -D'CONFIG_NICNATSEMI=1'
PROGRAMMER_OBJS += nicnatsemi.o
-NEED_LIBPCI += CONFIG_NICNATSEMI
+ACTIVE_PROGRAMMERS += nicnatsemi
endif
ifeq ($(CONFIG_NICINTEL), yes)
-FEATURE_CFLAGS += -D'CONFIG_NICINTEL=1'
+FEATURE_FLAGS += -D'CONFIG_NICINTEL=1'
PROGRAMMER_OBJS += nicintel.o
-NEED_LIBPCI += CONFIG_NICINTEL
+ACTIVE_PROGRAMMERS += nicintel
endif
ifeq ($(CONFIG_NICINTEL_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_NICINTEL_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_NICINTEL_SPI=1'
PROGRAMMER_OBJS += nicintel_spi.o
-NEED_LIBPCI += CONFIG_NICINTEL_SPI
+ACTIVE_PROGRAMMERS += nicintel_spi
endif
ifeq ($(CONFIG_NICINTEL_EEPROM), yes)
-FEATURE_CFLAGS += -D'CONFIG_NICINTEL_EEPROM=1'
+FEATURE_FLAGS += -D'CONFIG_NICINTEL_EEPROM=1'
PROGRAMMER_OBJS += nicintel_eeprom.o
-NEED_LIBPCI += CONFIG_NICINTEL_EEPROM
+ACTIVE_PROGRAMMERS += nicintel_eeprom
endif
ifeq ($(CONFIG_OGP_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_OGP_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_OGP_SPI=1'
PROGRAMMER_OBJS += ogp_spi.o
-NEED_LIBPCI += CONFIG_OGP_SPI
+ACTIVE_PROGRAMMERS += ogp_spi
endif
ifeq ($(CONFIG_BUSPIRATE_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_BUSPIRATE_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_BUSPIRATE_SPI=1'
PROGRAMMER_OBJS += buspirate_spi.o
-NEED_SERIAL += CONFIG_BUSPIRATE_SPI
+ACTIVE_PROGRAMMERS += buspirate_spi
endif
ifeq ($(CONFIG_DEDIPROG), yes)
-FEATURE_CFLAGS += -D'CONFIG_DEDIPROG=1'
+FEATURE_FLAGS += -D'CONFIG_DEDIPROG=1'
PROGRAMMER_OBJS += dediprog.o
-NEED_LIBUSB1 += CONFIG_DEDIPROG
+ACTIVE_PROGRAMMERS += dediprog
endif
ifeq ($(CONFIG_DEVELOPERBOX_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_DEVELOPERBOX_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_DEVELOPERBOX_SPI=1'
PROGRAMMER_OBJS += developerbox_spi.o
-NEED_LIBUSB1 += CONFIG_DEVELOPERBOX_SPI
+ACTIVE_PROGRAMMERS += developerbox_spi
endif
ifeq ($(CONFIG_SATAMV), yes)
-FEATURE_CFLAGS += -D'CONFIG_SATAMV=1'
+FEATURE_FLAGS += -D'CONFIG_SATAMV=1'
PROGRAMMER_OBJS += satamv.o
-NEED_LIBPCI += CONFIG_SATAMV
+ACTIVE_PROGRAMMERS += satamv
endif
ifeq ($(CONFIG_LINUX_MTD), yes)
-# This is a totally ugly hack.
-FEATURE_CFLAGS += $(call debug_shell,grep -q "LINUX_MTD_SUPPORT := yes" .features && printf "%s" "-D'CONFIG_LINUX_MTD=1'")
+FEATURE_FLAGS += -D'CONFIG_LINUX_MTD=1'
PROGRAMMER_OBJS += linux_mtd.o
+ACTIVE_PROGRAMMERS += linux_mtd
endif
ifeq ($(CONFIG_LINUX_SPI), yes)
-# This is a totally ugly hack.
-FEATURE_CFLAGS += $(call debug_shell,grep -q "LINUX_SPI_SUPPORT := yes" .features && printf "%s" "-D'CONFIG_LINUX_SPI=1'")
+FEATURE_FLAGS += -D'CONFIG_LINUX_SPI=1'
PROGRAMMER_OBJS += linux_spi.o
+ACTIVE_PROGRAMMERS += linux_spi
endif
ifeq ($(CONFIG_MSTARDDC_SPI), yes)
-# This is a totally ugly hack.
-FEATURE_CFLAGS += $(call debug_shell,grep -q "LINUX_I2C_SUPPORT := yes" .features && printf "%s" "-D'CONFIG_MSTARDDC_SPI=1'")
-NEED_LINUX_I2C += CONFIG_MSTARDDC_SPI
+FEATURE_FLAGS += -D'CONFIG_MSTARDDC_SPI=1'
PROGRAMMER_OBJS += mstarddc_spi.o
+ACTIVE_PROGRAMMERS += mstarddc_spi
endif
ifeq ($(CONFIG_CH341A_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_CH341A_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_CH341A_SPI=1'
PROGRAMMER_OBJS += ch341a_spi.o
-NEED_LIBUSB1 += CONFIG_CH341A_SPI
+ACTIVE_PROGRAMMERS += ch341a_spi
+endif
+
+ifeq ($(CONFIG_CH347_SPI), yes)
+FEATURE_FLAGS += -D'CONFIG_CH347_SPI=1'
+PROGRAMMER_OBJS += ch347_spi.o
endif
ifeq ($(CONFIG_DIGILENT_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_DIGILENT_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_DIGILENT_SPI=1'
PROGRAMMER_OBJS += digilent_spi.o
-NEED_LIBUSB1 += CONFIG_DIGILENT_SPI
+ACTIVE_PROGRAMMERS += digilent_spi
+endif
+
+ifeq ($(CONFIG_DIRTYJTAG_SPI), yes)
+FEATURE_FLAGS += -D'CONFIG_DIRTYJTAG_SPI=1'
+PROGRAMMER_OBJS += dirtyjtag_spi.o
+ACTIVE_PROGRAMMERS += dirtyjtag_spi
endif
ifeq ($(CONFIG_JLINK_SPI), yes)
-NEED_LIBJAYLINK += CONFIG_JLINK_SPI
-FEATURE_CFLAGS += -D'CONFIG_JLINK_SPI=1'
+FEATURE_FLAGS += -D'CONFIG_JLINK_SPI=1'
PROGRAMMER_OBJS += jlink_spi.o
+ACTIVE_PROGRAMMERS += jlink_spi
endif
ifeq ($(CONFIG_NI845X_SPI), yes)
-FEATURE_CFLAGS += -D'CONFIG_NI845X_SPI=1'
-
-ifeq ($(CONFIG_NI845X_LIBRARY_PATH),)
-# if the user did not specified the NI-845x headers/lib path
-# do a guess for both 32 and 64 bit Windows versions
-NI845X_LIBS += -L'${PROGRAMFILES}\National Instruments\NI-845x\MS Visual C'
-NI845X_LIBS += -L'${PROGRAMFILES(x86)}\National Instruments\NI-845x\MS Visual C'
-NI845X_INCLUDES += -I'${PROGRAMFILES}\National Instruments\NI-845x\MS Visual C'
-NI845X_INCLUDES += -I'${PROGRAMFILES(x86)}\National Instruments\NI-845x\MS Visual C'
-else
-NI845X_LIBS += -L'$(CONFIG_NI845X_LIBRARY_PATH)'
-NI845X_INCLUDES += -I'$(CONFIG_NI845X_LIBRARY_PATH)'
+FEATURE_FLAGS += -D'CONFIG_NI845X_SPI=1'
+PROGRAMMER_OBJS += ni845x_spi.o
+ACTIVE_PROGRAMMERS += ni845x_spi
endif
-FEATURE_CFLAGS += $(NI845X_INCLUDES)
-LIBS += -lni845x
-PROGRAMMER_OBJS += ni845x_spi.o
+USE_BITBANG_SPI := $(if $(call filter_deps,$(DEPENDS_ON_BITBANG_SPI)),yes,no)
+ifeq ($(USE_BITBANG_SPI), yes)
+LIB_OBJS += bitbang_spi.o
endif
-ifeq ($(CONFIG_LINUX_I2C_HELPER), yes)
+USE_LINUX_I2C := $(if $(call filter_deps,$(DEPENDS_ON_LINUX_I2C)),yes,no)
+ifeq ($(USE_LINUX_I2C), yes)
LIB_OBJS += i2c_helper_linux.o
-FEATURE_CFLAGS += -D'CONFIG_I2C_SUPPORT=1'
endif
-ifneq ($(NEED_SERIAL), )
-LIB_OBJS += serial.o custom_baud.o
+USE_SERIAL := $(if $(call filter_deps,$(DEPENDS_ON_SERIAL)),yes,no)
+ifeq ($(USE_SERIAL), yes)
+LIB_OBJS += serial.o
+ifeq ($(TARGET_OS), Linux)
+LIB_OBJS += custom_baud_linux.o
+else
+ifeq ($(TARGET_OS), Darwin)
+LIB_OBJS += custom_baud_darwin.o
+else
+LIB_OBJS += custom_baud.o
+endif
+endif
endif
-ifneq ($(NEED_POSIX_SOCKETS), )
+USE_SOCKETS := $(if $(call filter_deps,$(DEPENDS_ON_SOCKETS)),yes,no)
+ifeq ($(USE_SOCKETS), yes)
ifeq ($(TARGET_OS), SunOS)
-LIBS += -lsocket -lnsl
+override LDFLAGS += -lsocket -lnsl
endif
endif
-ifneq ($(NEED_LIBPCI), )
-CHECK_LIBPCI = yes
-# This is a dirty hack, but it saves us from checking all PCI drivers and all platforms manually.
-# libpci may need raw memory, MSR or PCI port I/O on some platforms.
-# Individual drivers might have the same needs as well.
-NEED_RAW_ACCESS += $(NEED_LIBPCI)
-FEATURE_CFLAGS += -D'NEED_PCI=1'
-FEATURE_CFLAGS += $(call debug_shell,grep -q "OLD_PCI_GET_DEV := yes" .libdeps && printf "%s" "-D'OLD_PCI_GET_DEV=1'")
-
-PROGRAMMER_OBJS += pcidev.o
-ifeq ($(TARGET_OS), NetBSD)
-# The libpci we want is called libpciutils on NetBSD and needs NetBSD libpci.
-PCILIBS += -lpciutils -lpci
-else
-PCILIBS += -lpci
+USE_X86_MSR := $(if $(call filter_deps,$(DEPENDS_ON_X86_MSR)),yes,no)
+ifeq ($(USE_X86_MSR), yes)
+PROGRAMMER_OBJS += hwaccess_x86_msr.o
endif
+
+USE_X86_PORT_IO := $(if $(call filter_deps,$(DEPENDS_ON_X86_PORT_IO)),yes,no)
+ifeq ($(USE_X86_PORT_IO), yes)
+FEATURE_FLAGS += -D'__FLASHROM_HAVE_OUTB__=1'
+PROGRAMMER_OBJS += hwaccess_x86_io.o
endif
-ifneq ($(NEED_RAW_ACCESS), )
-# Raw memory, MSR or PCI port I/O access.
-FEATURE_CFLAGS += -D'NEED_RAW_ACCESS=1'
-PROGRAMMER_OBJS += physmap.o hwaccess.o
+USE_RAW_MEM_ACCESS := $(if $(call filter_deps,$(DEPENDS_ON_RAW_MEM_ACCESS)),yes,no)
+ifeq ($(USE_RAW_MEM_ACCESS), yes)
+PROGRAMMER_OBJS += hwaccess_physmap.o
+endif
-ifeq ($(TARGET_OS), NetBSD)
-# For (i386|x86_64)_iopl(2).
-PCILIBS += -l$(shell uname -p)
-else
-ifeq ($(TARGET_OS), OpenBSD)
-# For (i386|amd64)_iopl(2).
-PCILIBS += -l$(shell uname -m)
-else
-ifeq ($(TARGET_OS), Darwin)
-# DirectHW framework can be found in the DirectHW library.
-PCILIBS += -framework IOKit -framework DirectHW
+ifeq (Darwin yes, $(TARGET_OS) $(filter $(USE_X86_MSR) $(USE_X86_PORT_IO) $(USE_RAW_MEM_ACCESS), yes))
+override LDFLAGS += -framework IOKit -framework DirectHW
endif
+
+ifeq (NetBSD yes, $(TARGET_OS) $(filter $(USE_X86_MSR) $(USE_X86_PORT_IO), yes))
+override LDFLAGS += -l$(shell uname -p)
endif
+
+ifeq (OpenBSD yes, $(TARGET_OS) $(filter $(USE_X86_MSR) $(USE_X86_PORT_IO), yes))
+override LDFLAGS += -l$(shell uname -m)
endif
+USE_LIBPCI := $(if $(call filter_deps,$(DEPENDS_ON_LIBPCI)),yes,no)
+ifeq ($(USE_LIBPCI), yes)
+PROGRAMMER_OBJS += pcidev.o
+override CFLAGS += $(CONFIG_LIBPCI_CFLAGS)
+override LDFLAGS += $(CONFIG_LIBPCI_LDFLAGS)
endif
+USE_LIBUSB1 := $(if $(call filter_deps,$(DEPENDS_ON_LIBUSB1)),yes,no)
+ifeq ($(USE_LIBUSB1), yes)
+override CFLAGS += $(CONFIG_LIBUSB1_CFLAGS)
+override LDFLAGS += $(CONFIG_LIBUSB1_LDFLAGS)
+PROGRAMMER_OBJS +=usbdev.o usb_device.o
+endif
-ifneq ($(NEED_LIBUSB1), )
-CHECK_LIBUSB1 = yes
-FEATURE_CFLAGS += -D'NEED_LIBUSB1=1'
-PROGRAMMER_OBJS += usbdev.o usb_device.o
-# FreeBSD and DragonflyBSD use a reimplementation of libusb-1.0 that is simply called libusb
-ifeq ($(TARGET_OS),$(filter $(TARGET_OS),FreeBSD DragonFlyBSD))
-USB1LIBS += -lusb
-else
-ifeq ($(TARGET_OS),NetBSD)
-override CPPFLAGS += -I/usr/pkg/include/libusb-1.0
-USB1LIBS += -lusb-1.0
-else
-USB1LIBS += $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)"; $(PKG_CONFIG) --libs libusb-1.0 || printf "%s" "-lusb-1.0")
-override CPPFLAGS += $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)"; $(PKG_CONFIG) --cflags-only-I libusb-1.0 || printf "%s" "-I/usr/include/libusb-1.0")
+USE_LIBFTDI1 := $(if $(call filter_deps,$(DEPENDS_ON_LIBFTDI1)),yes,no)
+ifeq ($(USE_LIBFTDI1), yes)
+override CFLAGS += $(CONFIG_LIBFTDI1_CFLAGS)
+override LDFLAGS += $(CONFIG_LIBFTDI1_LDFLAGS)
+ifeq ($(HAS_FT232H), yes)
+FEATURE_FLAGS += -D'HAVE_FT232H=1'
endif
endif
+
+USE_LIB_NI845X := $(if $(call filter_deps,$(DEPENDS_ON_LIB_NI845X)),yes,no)
+ifeq ($(USE_LIB_NI845X), yes)
+override CFLAGS += $(CONFIG_LIB_NI845X_CFLAGS)
+override LDFLAGS += $(CONFIG_LIB_NI845X_LDFLAGS)
endif
-ifneq ($(NEED_LIBJAYLINK), )
-CHECK_LIBJAYLINK = yes
-JAYLINKLIBS += $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)"; $(PKG_CONFIG) --libs libjaylink)
-override CPPFLAGS += $(call debug_shell,[ -n "$(PKG_CONFIG_LIBDIR)" ] && export PKG_CONFIG_LIBDIR="$(PKG_CONFIG_LIBDIR)"; $(PKG_CONFIG) --cflags-only-I libjaylink)
+USE_LIBJAYLINK := $(if $(call filter_deps,$(DEPENDS_ON_LIBJAYLINK)),yes,no)
+ifeq ($(USE_LIBJAYLINK), yes)
+override CFLAGS += $(CONFIG_LIBJAYLINK_CFLAGS)
+override LDFLAGS += $(CONFIG_LIBJAYLINK_LDFLAGS)
endif
ifeq ($(CONFIG_PRINT_WIKI), yes)
-FEATURE_CFLAGS += -D'CONFIG_PRINT_WIKI=1'
+FEATURE_FLAGS += -D'CONFIG_PRINT_WIKI=1'
CLI_OBJS += print_wiki.o
endif
-FEATURE_CFLAGS += $(call debug_shell,grep -q "UTSNAME := yes" .features && printf "%s" "-D'HAVE_UTSNAME=1'")
+ifeq ($(HAS_UTSNAME), yes)
+FEATURE_FLAGS += -D'HAVE_UTSNAME=1'
+endif
-# We could use PULLED_IN_LIBS, but that would be ugly.
-FEATURE_LIBS += $(call debug_shell,grep -q "NEEDLIBZ := yes" .libdeps && printf "%s" "-lz")
+ifeq ($(HAS_CLOCK_GETTIME), yes)
+FEATURE_FLAGS += -D'HAVE_CLOCK_GETTIME=1'
+ifeq ($(HAS_EXTERN_LIBRT), yes)
+override LDFLAGS += -lrt
+endif
+endif
-FEATURE_CFLAGS += $(call debug_shell,grep -q "CLOCK_GETTIME := yes" .features && printf "%s" "-D'HAVE_CLOCK_GETTIME=1'")
-FEATURE_LIBS += $(call debug_shell,grep -q "CLOCK_GETTIME := yes" .features && printf "%s" "-lrt")
+OBJS = $(CHIP_OBJS) $(PROGRAMMER_OBJS) $(LIB_OBJS)
-LIBFLASHROM_OBJS = $(CHIP_OBJS) $(PROGRAMMER_OBJS) $(LIB_OBJS)
-OBJS = $(CLI_OBJS) $(LIBFLASHROM_OBJS)
-all: hwlibs features $(PROGRAM)$(EXEC_SUFFIX) $(PROGRAM).8
+all: $(PROGRAM)$(EXEC_SUFFIX) $(call has_dependency, $(HAS_SPHINXBUILD), man8/$(PROGRAM).8)
ifeq ($(ARCH), x86)
- @+$(MAKE) -C util/ich_descriptors_tool/ TARGET_OS=$(TARGET_OS) EXEC_SUFFIX=$(EXEC_SUFFIX)
-endif
-
-$(PROGRAM)$(EXEC_SUFFIX): $(OBJS)
- $(CC) $(LDFLAGS) -o $(PROGRAM)$(EXEC_SUFFIX) $(OBJS) $(LIBS) $(PCILIBS) $(FEATURE_LIBS) $(USBLIBS) $(USB1LIBS) $(JAYLINKLIBS) $(NI845X_LIBS)
-
-libflashrom.a: $(LIBFLASHROM_OBJS)
+ @+$(MAKE) -C util/ich_descriptors_tool/ HOST_OS=$(HOST_OS) TARGET_OS=$(TARGET_OS)
+endif
+
+config:
+ @echo Building flashrom version $(VERSION)
+ @printf "C compiler found: "
+ @if [ $(CC_WORKING) = yes ]; \
+ then $(CC) --version 2>/dev/null | head -1; \
+ else echo no; echo Aborting.; exit 1; fi
+ @echo "Target arch: $(ARCH)"
+ @if [ $(ARCH) = unknown ]; then echo Aborting.; exit 1; fi
+ @echo "Target OS: $(TARGET_OS)"
+ @if [ $(TARGET_OS) = unknown ]; then echo Aborting.; exit 1; fi
+ @if [ $(TARGET_OS) = libpayload ] && ! $(CC) --version 2>&1 | grep -q coreboot; then \
+ echo " Warning: It seems you are not using coreboot's reference compiler."; \
+ echo " This might work but usually does not, please beware."; fi
+ @echo "Target endian: $(ENDIAN)"
+ @if [ $(ENDIAN) = unknown ]; then echo Aborting.; exit 1; fi
+ @echo Dependency libpci found: $(HAS_LIBPCI) $(CONFIG_LIBPCI_VERSION)
+ @if [ $(HAS_LIBPCI) = yes ]; then \
+ echo " CFLAGS: $(CONFIG_LIBPCI_CFLAGS)"; \
+ echo " LDFLAGS: $(CONFIG_LIBPCI_LDFLAGS)"; \
+ fi
+ @echo Dependency libusb1 found: $(HAS_LIBUSB1) $(CONFIG_LIBUSB1_VERSION)
+ @if [ $(HAS_LIBUSB1) = yes ]; then \
+ echo " CFLAGS: $(CONFIG_LIBUSB1_CFLAGS)"; \
+ echo " LDFLAGS: $(CONFIG_LIBUSB1_LDFLAGS)"; \
+ fi
+ @echo Dependency libjaylink found: $(HAS_LIBJAYLINK) $(CONFIG_LIBJAYLINK_VERSION)
+ @if [ $(HAS_LIBJAYLINK) = yes ]; then \
+ echo " CFLAGS: $(CONFIG_LIBJAYLINK_CFLAGS)"; \
+ echo " LDFLAGS: $(CONFIG_LIBJAYLINK_LDFLAGS)"; \
+ fi
+ @echo Dependency NI-845x found: $(HAS_LIB_NI845X)
+ @if [ $(HAS_LIB_NI845X) = yes ]; then \
+ echo " CFLAGS: $(CONFIG_LIB_NI845X_CFLAGS)"; \
+ echo " LDFLAGS: $(CONFIG_LIB_NI845X_LDFLAGS)"; \
+ fi
+ @echo Dependency libftdi1 found: $(HAS_LIBFTDI1) $(CONFIG_LIBFTDI1_VERSION)
+ @if [ $(HAS_LIBFTDI1) = yes ]; then \
+ echo " Checking for \"TYPE_232H\" in \"enum ftdi_chip_type\": $(HAS_FT232H)"; \
+ echo " CFLAGS: $(CONFIG_LIBFTDI1_CFLAGS)"; \
+ echo " LDFLAGS: $(CONFIG_LIBFTDI1_LDFLAGS)"; \
+ fi
+ @echo "Checking for header \"mtd/mtd-user.h\": $(HAS_LINUX_MTD)"
+ @echo "Checking for header \"linux/spi/spidev.h\": $(HAS_LINUX_SPI)"
+ @echo "Checking for header \"linux/i2c-dev.h\": $(HAS_LINUX_I2C)"
+ @echo "Checking for header \"linux/i2c.h\": $(HAS_LINUX_I2C)"
+ @echo "Checking for header \"sys/utsname.h\": $(HAS_UTSNAME)"
+ @echo "Checking for function \"clock_gettime\": $(HAS_CLOCK_GETTIME)"
+ @echo "Checking for external \"librt\": $(HAS_EXTERN_LIBRT)"
+ @if ! [ "$(PROGRAMMER_OBJS)" ]; then \
+ echo "You have to enable at least one programmer driver!"; \
+ exit 1; \
+ fi
+ @if [ "$(UNSUPPORTED_FEATURES)" ]; then \
+ echo "The following features are unavailable on your machine: $(UNSUPPORTED_FEATURES)" \
+ exit 1; \
+ fi
+ @echo "Checking for program \"sphinx-build\": $(HAS_SPHINXBUILD)"
+
+%.o: %.c | config
+ $(CC) -MMD $(CFLAGS) $(CPPFLAGS) $(FLASHROM_CFLAGS) $(FEATURE_FLAGS) -D'FLASHROM_VERSION=$(VERSION)' -o $@ -c $<
+
+$(PROGRAM)$(EXEC_SUFFIX): $(CLI_OBJS) libflashrom.a
+ $(CC) -o $@ $^ $(LDFLAGS)
+
+libflashrom.a: $(OBJS)
$(AR) rcs $@ $^
$(RANLIB) $@
-# TAROPTIONS reduces information leakage from the packager's system.
-# If other tar programs support command line arguments for setting uid/gid of
-# stored files, they can be handled here as well.
-TAROPTIONS = $(shell LC_ALL=C tar --version|grep -q GNU && echo "--owner=root --group=root")
+man8/$(PROGRAM).8: doc/*
+ @if [ "$(HAS_SPHINXBUILD)" = "yes" ]; then \
+ $(SPHINXBUILD) -Drelease=$(VERSION) -b man doc .; \
+ else \
+ echo "$(SPHINXBUILD) not found. Can't build man-page"; \
+ exit 1; \
+ fi
+
+$(PROGRAM).bash: util/$(PROGRAM).bash-completion.tmpl
+ @# Add to the bash completion file a list of enabled programmers.
+ sed -e 's/@PROGRAMMERS@/$(ACTIVE_PROGRAMMERS)/g' <$< >$@
-%.o: %.c .features
- $(CC) -MMD $(CFLAGS) $(CPPFLAGS) $(FLASHROM_CFLAGS) $(FEATURE_CFLAGS) $(SCMDEF) -o $@ -c $<
+strip: $(PROGRAM)$(EXEC_SUFFIX)
+ $(STRIP) $(STRIP_ARGS) $(PROGRAM)$(EXEC_SUFFIX)
# Make sure to add all names of generated binaries here.
# This includes all frontends and libflashrom.
# We don't use EXEC_SUFFIX here because we want to clean everything.
clean:
- rm -f $(PROGRAM) $(PROGRAM).exe libflashrom.a *.o *.d $(PROGRAM).8 $(PROGRAM).8.html $(BUILD_DETAILS_FILE)
+ rm -rf $(PROGRAM) $(PROGRAM).exe libflashrom.a $(filter-out Makefile.d, $(wildcard *.d *.o platform/*.d platform/*.o)) \
+ man8 .doctrees $(PROGRAM).bash $(BUILD_DETAILS_FILE)
@+$(MAKE) -C util/ich_descriptors_tool/ clean
-distclean: clean
- rm -f .features .libdeps
-
-strip: $(PROGRAM)$(EXEC_SUFFIX)
- $(STRIP) $(STRIP_ARGS) $(PROGRAM)$(EXEC_SUFFIX)
-
-# to define test programs we use verbatim variables, which get exported
-# to environment variables and are referenced with $$<varname> later
-
-define COMPILER_TEST
-int main(int argc, char **argv)
-{
- (void) argc;
- (void) argv;
- return 0;
-}
-endef
-export COMPILER_TEST
-
-compiler: featuresavailable
- @printf "Checking for a C compiler... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$COMPILER_TEST" > .test.c
- @printf "\nexec: %s\n" "$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .test.c -o .test$(EXEC_SUFFIX)" >>$(BUILD_DETAILS_FILE)
- @{ { { { { $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .test.c -o .test$(EXEC_SUFFIX) >&2 && \
- echo "found." || { echo "not found."; \
- rm -f .test.c .test$(EXEC_SUFFIX); exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
- @rm -f .test.c .test$(EXEC_SUFFIX)
- @printf "Target arch is "
- @# FreeBSD wc will output extraneous whitespace.
- @echo $(ARCH)|wc -w|grep -q '^[[:blank:]]*1[[:blank:]]*$$' || \
- ( echo "unknown (\"$(ARCH)\"). Aborting."; exit 1)
- @printf "%s\n" '$(ARCH)'
- @printf "Target OS is "
- @# FreeBSD wc will output extraneous whitespace.
- @echo $(TARGET_OS)|wc -w|grep -q '^[[:blank:]]*1[[:blank:]]*$$' || \
- ( echo "unknown (\"$(TARGET_OS)\"). Aborting."; exit 1)
- @printf "%s\n" '$(TARGET_OS)'
-ifeq ($(TARGET_OS), libpayload)
- @$(CC) --version 2>&1 | grep -q coreboot || \
- ( echo "Warning: It seems you are not using coreboot's reference compiler."; \
- echo "This might work but usually does not, please beware." )
-endif
-
-define LIBPCI_TEST
-/* Avoid a failing test due to libpci header symbol shadowing breakage */
-#define index shadow_workaround_index
-#if !defined __NetBSD__
-#include <pci/pci.h>
-#else
-#include <pciutils/pci.h>
-#endif
-struct pci_access *pacc;
-int main(int argc, char **argv)
-{
- (void) argc;
- (void) argv;
- pacc = pci_alloc();
- return 0;
-}
-endef
-export LIBPCI_TEST
-
-define PCI_GET_DEV_TEST
-/* Avoid a failing test due to libpci header symbol shadowing breakage */
-#define index shadow_workaround_index
-#if !defined __NetBSD__
-#include <pci/pci.h>
-#else
-#include <pciutils/pci.h>
-#endif
-struct pci_access *pacc;
-struct pci_dev *dev = {0};
-int main(int argc, char **argv)
-{
- (void) argc;
- (void) argv;
- pacc = pci_alloc();
- dev = pci_get_dev(pacc, dev->domain, dev->bus, dev->dev, 1);
- return 0;
-}
-endef
-export PCI_GET_DEV_TEST
-
-define LIBUSB1_TEST
-#include <stddef.h>
-#include <libusb.h>
-int main(int argc, char **argv)
-{
- (void)argc;
- (void)argv;
- libusb_init(NULL);
- return 0;
-}
-endef
-export LIBUSB1_TEST
-
-define LIBJAYLINK_TEST
-#include <stddef.h>
-#include <libjaylink/libjaylink.h>
-int main(int argc, char **argv)
-{
- struct jaylink_context *ctx;
-
- (void)argc;
- (void)argv;
-
- jaylink_init(&ctx);
- jaylink_exit(ctx);
-
- return 0;
-}
-endef
-export LIBJAYLINK_TEST
-
-hwlibs: compiler
- @printf "" > .libdeps
-ifeq ($(CHECK_LIBPCI), yes)
- @printf "Checking for libpci headers... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$LIBPCI_TEST" > .test.c
- @printf "\nexec: %s\n" "$(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o" >>$(BUILD_DETAILS_FILE)
- @{ { { { { $(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o >&2 && \
- echo "found." || { echo "not found."; echo; \
- echo "The following features require libpci: $(NEED_LIBPCI)."; \
- echo "Please install libpci headers or disable all features"; \
- echo "mentioned above by specifying make CONFIG_ENABLE_LIBPCI_PROGRAMMERS=no"; \
- echo "See README for more information."; echo; \
- rm -f .test.c .test.o; exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
- @printf "Checking version of pci_get_dev... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$PCI_GET_DEV_TEST" > .test.c
- @printf "\nexec: %s\n" "$(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o" >>$(BUILD_DETAILS_FILE)
- @ { $(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o >&2 && \
- ( echo "new version (including PCI domain parameter)."; echo "OLD_PCI_GET_DEV := no" >> .libdeps ) || \
- ( echo "old version (without PCI domain parameter)."; echo "OLD_PCI_GET_DEV := yes" >> .libdeps ) } 2>>$(BUILD_DETAILS_FILE) | tee -a $(BUILD_DETAILS_FILE)
- @printf "Checking if libpci is present and sufficient... " | tee -a $(BUILD_DETAILS_FILE)
- @printf "\nexec: %s\n" "$(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(PCILIBS)" >>$(BUILD_DETAILS_FILE)
- @{ { { { $(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(PCILIBS) 2>>$(BUILD_DETAILS_FILE) >&2 && \
- echo "yes." || { echo "no."; \
- printf "Checking if libz+libpci are present and sufficient..." ; \
- { printf "\nexec: %s\n" "$(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(PCILIBS) -lz" >>$(BUILD_DETAILS_FILE) ; \
- $(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(PCILIBS) -lz >&2 && \
- echo "yes." && echo "NEEDLIBZ := yes" > .libdeps } || { echo "no."; echo; \
- echo "The following features require libpci: $(NEED_LIBPCI)."; \
- echo "Please install libpci (package pciutils) and/or libz or disable all features"; \
- echo "mentioned above by specifying make CONFIG_ENABLE_LIBPCI_PROGRAMMERS=no"; \
- echo "See README for more information."; echo; \
- rm -f .test.c .test.o .test$(EXEC_SUFFIX); exit 1; }; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
- @rm -f .test.c .test.o .test$(EXEC_SUFFIX)
-endif
-ifeq ($(CHECK_LIBUSB1), yes)
- @printf "Checking for libusb-1.0 headers... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$LIBUSB1_TEST" > .test.c
- @printf "\nexec: %s\n" "$(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o" >>$(BUILD_DETAILS_FILE)
- @{ { { { { $(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o >&2 && \
- echo "found." || { echo "not found."; echo; \
- echo "The following features require libusb-1.0: $(NEED_LIBUSB1)."; \
- echo "Please install libusb-1.0 headers or disable all features"; \
- echo "mentioned above by specifying make CONFIG_ENABLE_LIBUSB1_PROGRAMMERS=no"; \
- echo "See README for more information."; echo; \
- rm -f .test.c .test.o; exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
- @printf "Checking if libusb-1.0 is usable... " | tee -a $(BUILD_DETAILS_FILE)
- @printf "\nexec: %s\n" "$(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(USB1LIBS)" >>$(BUILD_DETAILS_FILE)
- @{ { { { { $(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(USB1LIBS) >&2 && \
- echo "yes." || { echo "no."; \
- echo "The following features require libusb-1.0: $(NEED_LIBUSB1)."; \
- echo "Please install libusb-1.0 or disable all features"; \
- echo "mentioned above by specifying make CONFIG_ENABLE_LIBUSB1_PROGRAMMERS=no"; \
- echo "See README for more information."; echo; \
- rm -f .test.c .test.o .test$(EXEC_SUFFIX); exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
- @rm -f .test.c .test.o .test$(EXEC_SUFFIX)
-endif
-ifeq ($(CHECK_LIBJAYLINK), yes)
- @printf "Checking for libjaylink headers... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$LIBJAYLINK_TEST" > .test.c
- @printf "\nexec: %s\n" "$(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o" >>$(BUILD_DETAILS_FILE)
- @{ { { { { $(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o >&2 && \
- echo "found." || { echo "not found."; echo; \
- echo "The following feature requires libjaylink: $(NEED_LIBJAYLINK)."; \
- echo "Please install libjaylink headers or disable the feature"; \
- echo "mentioned above by specifying make CONFIG_JLINK_SPI=no"; \
- echo "See README for more information."; echo; \
- rm -f .test.c .test.o; exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
- @printf "Checking if libjaylink is usable... " | tee -a $(BUILD_DETAILS_FILE)
- @printf "\nexec: %s\n" "$(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(JAYLINKLIBS)" >>$(BUILD_DETAILS_FILE)
- @{ { { { { $(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(JAYLINKLIBS) >&2 && \
- echo "yes." || { echo "no."; \
- echo "The following feature requires libjaylink: $(NEED_LIBJAYLINK)."; \
- echo "Please install libjaylink or disable the feature"; \
- echo "mentioned above by specifying make CONFIG_JLINK_SPI=no"; \
- echo "See README for more information."; echo; \
- rm -f .test.c .test.o .test$(EXEC_SUFFIX); exit 1; }; } 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
- @rm -f .test.c .test.o .test$(EXEC_SUFFIX)
-endif
-
-.features: features
-
-# If a user does not explicitly request a non-working feature, we should
-# silently disable it. However, if a non-working (does not compile) feature
-# is explicitly requested, we should bail out with a descriptive error message.
-# We also have to check that at least one programmer driver is enabled.
-featuresavailable:
-ifeq ($(PROGRAMMER_OBJS),)
- @echo "You have to enable at least one programmer driver!"
- @false
-endif
-ifneq ($(UNSUPPORTED_FEATURES), )
- @echo "The following features are unavailable on your machine: $(UNSUPPORTED_FEATURES)"
- @false
-endif
-
-define FTDI_TEST
-#include <stdlib.h>
-#include <ftdi.h>
-struct ftdi_context *ftdic = NULL;
-int main(int argc, char **argv)
-{
- (void) argc;
- (void) argv;
- return ftdi_init(ftdic);
-}
-endef
-export FTDI_TEST
-
-define FTDI_232H_TEST
-#include <ftdi.h>
-enum ftdi_chip_type type = TYPE_232H;
-endef
-export FTDI_232H_TEST
-
-define UTSNAME_TEST
-#include <sys/utsname.h>
-struct utsname osinfo;
-int main(int argc, char **argv)
-{
- (void) argc;
- (void) argv;
- uname (&osinfo);
- return 0;
-}
-endef
-export UTSNAME_TEST
-
-define LINUX_MTD_TEST
-#include <mtd/mtd-user.h>
-
-int main(int argc, char **argv)
-{
- (void) argc;
- (void) argv;
- return 0;
-}
-endef
-export LINUX_MTD_TEST
-
-define LINUX_SPI_TEST
-#include <linux/types.h>
-#include <linux/spi/spidev.h>
-
-int main(int argc, char **argv)
-{
- (void) argc;
- (void) argv;
- return 0;
-}
-endef
-export LINUX_SPI_TEST
-
-define LINUX_I2C_TEST
-#include <linux/i2c-dev.h>
-#include <linux/i2c.h>
-
-int main(int argc, char **argv)
-{
- (void) argc;
- (void) argv;
- return 0;
-}
-endef
-export LINUX_I2C_TEST
-
-define CLOCK_GETTIME_TEST
-#include <time.h>
-
-int main(int argc, char **argv)
-{
- struct timespec res;
- clock_gettime(CLOCK_REALTIME, &res);
- return 0;
-}
-endef
-export CLOCK_GETTIME_TEST
-
-define NI845X_TEST
-#include <ni845x.h>
-
-int main(int argc, char **argv)
-{
- (void) argc;
- (void) argv;
- char I2C_Device[256];
- NiHandle Dev_Handle;
- uInt32 NumberFound = 0;
- ni845xFindDevice(I2C_Device, &Dev_Handle, &NumberFound);
- ni845xCloseFindDeviceHandle(Dev_Handle);
- return 0;
-}
-endef
-export NI845X_TEST
-
-features: compiler
- @echo "FEATURES := yes" > .features.tmp
-ifneq ($(NEED_LIBFTDI), )
- @printf "Checking for FTDI support... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$FTDI_TEST" > .featuretest.c
- @printf "\nexec: %s\n" "$(CC) $(CPPFLAGS) $(CFLAGS) $(FTDI_INCLUDES) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS)" >>$(BUILD_DETAILS_FILE)
- @ { $(CC) $(CPPFLAGS) $(CFLAGS) $(FTDI_INCLUDES) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >&2 && \
- ( echo "found."; echo "FTDISUPPORT := yes" >> .features.tmp ; \
- printf "Checking for FT232H support in libftdi... " ; \
- echo "$$FTDI_232H_TEST" >> .featuretest.c ; \
- printf "\nexec: %s\n" "$(CC) $(CPPFLAGS) $(CFLAGS) $(FTDI_INCLUDES) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS)" >>$(BUILD_DETAILS_FILE) ; \
- { $(CC) $(CPPFLAGS) $(CFLAGS) $(FTDI_INCLUDES) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >&2 && \
- ( echo "found."; echo "FT232H := yes" >> .features.tmp ) || \
- ( echo "not found."; echo "FT232H := no" >> .features.tmp ) } \
- ) || \
- ( echo "not found."; echo "FTDISUPPORT := no" >> .features.tmp ) } \
- 2>>$(BUILD_DETAILS_FILE) | tee -a $(BUILD_DETAILS_FILE)
-endif
-ifeq ($(CONFIG_LINUX_MTD), yes)
- @printf "Checking if Linux MTD headers are present... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$LINUX_MTD_TEST" > .featuretest.c
- @printf "\nexec: %s\n" "$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX)" >>$(BUILD_DETAILS_FILE)
- @ { $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) >&2 && \
- ( echo "yes."; echo "LINUX_MTD_SUPPORT := yes" >> .features.tmp ) || \
- ( echo "no."; echo "LINUX_MTD_SUPPORT := no" >> .features.tmp ) } \
- 2>>$(BUILD_DETAILS_FILE) | tee -a $(BUILD_DETAILS_FILE)
-endif
-ifeq ($(CONFIG_LINUX_SPI), yes)
- @printf "Checking if Linux SPI headers are present... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$LINUX_SPI_TEST" > .featuretest.c
- @printf "\nexec: %s\n" "$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX)" >>$(BUILD_DETAILS_FILE)
- @ { $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) >&2 && \
- ( echo "yes."; echo "LINUX_SPI_SUPPORT := yes" >> .features.tmp ) || \
- ( echo "no."; echo "LINUX_SPI_SUPPORT := no" >> .features.tmp ) } \
- 2>>$(BUILD_DETAILS_FILE) | tee -a $(BUILD_DETAILS_FILE)
-endif
-ifneq ($(NEED_LINUX_I2C), )
- @printf "Checking if Linux I2C headers are present... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$LINUX_I2C_TEST" > .featuretest.c
- @printf "\nexec: %s\n" "$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX)" >>$(BUILD_DETAILS_FILE)
- @ { $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) >&2 && \
- ( echo "yes."; echo "LINUX_I2C_SUPPORT := yes" >> .features.tmp ) || \
- ( echo "no."; echo "LINUX_I2C_SUPPORT := no" >> .features.tmp ) } \
- 2>>$(BUILD_DETAILS_FILE) | tee -a $(BUILD_DETAILS_FILE)
-endif
-ifeq ($(CONFIG_NI845X_SPI), yes)
- @printf "Checking for NI USB-845x installation... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$NI845X_TEST" > .featuretest.c
- @printf "\nexec: %s\n" "$(CC) $(CPPFLAGS) $(CFLAGS) $(NI845X_INCLUDES) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(NI845X_LIBS) $(LIBS)" >>$(BUILD_DETAILS_FILE)
-
- @ { { { { { $(CC) $(CPPFLAGS) $(CFLAGS) $(NI845X_INCLUDES) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(NI845X_LIBS) $(LIBS) >&2 && \
- ( echo "yes."; echo "NI845X_SUPPORT := yes" >> .features.tmp ) || \
- { echo -e "\nUnable to find NI-845x headers or libraries."; \
- echo "Please pass the NI-845x library path to the make with the CONFIG_NI845X_LIBRARY_PATH parameter,"; \
- echo "or disable the NI-845x support by specifying make CONFIG_NI845X_SPI=no"; \
- echo "For the NI-845x 17.0 the library path is:"; \
- echo " On 32 bit systems: C:\Program Files)\National Instruments\NI-845x\MS Visual C"; \
- echo " On 64 bit systems: C:\Program Files (x86)\National Instruments\NI-845x\MS Visual C"; \
- exit 1; }; } \
- 2>>$(BUILD_DETAILS_FILE); echo $? >&3 ; } | tee -a $(BUILD_DETAILS_FILE) >&4; } 3>&1;} | { read rc ; exit ${rc}; } } 4>&1
-endif
- @printf "Checking for utsname support... " | tee -a $(BUILD_DETAILS_FILE)
- @echo "$$UTSNAME_TEST" > .featuretest.c
- @printf "\nexec: %s\n" "$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX)" >>$(BUILD_DETAILS_FILE)
- @ { $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) >&2 && \
- ( echo "found."; echo "UTSNAME := yes" >> .features.tmp ) || \
- ( echo "not found."; echo "UTSNAME := no" >> .features.tmp ) } 2>>$(BUILD_DETAILS_FILE) | tee -a $(BUILD_DETAILS_FILE)
- @printf "Checking for clock_gettime support... " | tee -a $(BUILD_DETAILS_FILE)
-ifeq ($(DISABLE_CLOCK_GETTIME), yes)
- @ { ( echo "disabled."; echo "CLOCK_GETTIME := no" >>.features.tmp ) } \
- 2>>$(BUILD_DETAILS_FILE) | tee -a $(BUILD_DETAILS_FILE)
-else
- @echo "$$CLOCK_GETTIME_TEST" >.featuretest.c
- @printf "\nexec: %s\n" "$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -lrt .featuretest.c -o .featuretest$(EXEC_SUFFIX)" >>$(BUILD_DETAILS_FILE)
- @ { $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -lrt .featuretest.c -o .featuretest$(EXEC_SUFFIX) >&2 && \
- ( echo "found."; echo "CLOCK_GETTIME := yes" >>.features.tmp ) || \
- ( echo "not found."; echo "CLOCK_GETTIME := no" >>.features.tmp ) } \
- 2>>$(BUILD_DETAILS_FILE) | tee -a $(BUILD_DETAILS_FILE)
-endif
- @$(DIFF) -q .features.tmp .features >/dev/null 2>&1 && rm .features.tmp || mv .features.tmp .features
- @rm -f .featuretest.c .featuretest$(EXEC_SUFFIX)
-
-$(PROGRAM).8.html: $(PROGRAM).8
- @groff -mandoc -Thtml $< >$@
-
-$(PROGRAM).8: $(PROGRAM).8.tmpl
- @# Add the man page change date and version to the man page
- @sed -e 's#.TH FLASHROM 8 .*#.TH FLASHROM 8 "$(MAN_DATE)" "$(VERSION)" "$(MAN_DATE)"#' <$< >$@
-
-install: $(PROGRAM)$(EXEC_SUFFIX) $(PROGRAM).8
+install: $(PROGRAM)$(EXEC_SUFFIX) $(call has_dependency, $(HAS_SPHINXBUILD), man8/$(PROGRAM).8) $(PROGRAM).bash
mkdir -p $(DESTDIR)$(PREFIX)/sbin
- mkdir -p $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 0755 $(PROGRAM)$(EXEC_SUFFIX) $(DESTDIR)$(PREFIX)/sbin
- $(INSTALL) -m 0644 $(PROGRAM).8 $(DESTDIR)$(MANDIR)/man8
+ mkdir -p $(DESTDIR)$(BASHCOMPDIR)
+ $(INSTALL) -m 0644 $(PROGRAM).bash $(DESTDIR)$(BASHCOMPDIR)
+ifeq ($(HAS_SPHINXBUILD), yes)
+ mkdir -p $(DESTDIR)$(MANDIR)/man8
+ $(INSTALL) -m 0644 man8/$(PROGRAM).8 $(DESTDIR)$(MANDIR)/man8
+endif
-libinstall: libflashrom.a libflashrom.h
+libinstall: libflashrom.a include/libflashrom.h
mkdir -p $(DESTDIR)$(PREFIX)/lib
$(INSTALL) -m 0644 libflashrom.a $(DESTDIR)$(PREFIX)/lib
mkdir -p $(DESTDIR)$(PREFIX)/include
- $(INSTALL) -m 0644 libflashrom.h $(DESTDIR)$(PREFIX)/include
+ $(INSTALL) -m 0644 include/libflashrom.h $(DESTDIR)$(PREFIX)/include
-_export: $(PROGRAM).8
+_export: man8/$(PROGRAM).8
@rm -rf "$(EXPORTDIR)/flashrom-$(RELEASENAME)"
@mkdir -p "$(EXPORTDIR)/flashrom-$(RELEASENAME)"
@git archive HEAD | tar -x -C "$(EXPORTDIR)/flashrom-$(RELEASENAME)"
# Generate versioninfo.inc containing metadata that would not be available in exported sources otherwise.
@echo "VERSION = $(VERSION)" > "$(EXPORTDIR)/flashrom-$(RELEASENAME)/versioninfo.inc"
- @echo "MAN_DATE = $(MAN_DATE)" >> "$(EXPORTDIR)/flashrom-$(RELEASENAME)/versioninfo.inc"
# Restore modification date of all tracked files not marked 'export-ignore' in .gitattributes.
# sed is required to filter out file names having the attribute set.
# The sed program saves the file name in the hold buffer and then checks if the respective value is 'set'.
@@ -1718,6 +1081,12 @@ _export: $(PROGRAM).8
export: _export
@echo "Exported $(EXPORTDIR)/flashrom-$(RELEASENAME)/"
+
+# TAROPTIONS reduces information leakage from the packager's system.
+# If other tar programs support command line arguments for setting uid/gid of
+# stored files, they can be handled here as well.
+TAROPTIONS = $(shell LC_ALL=C tar --version|grep -q GNU && echo "--owner=root --group=root")
+
tarball: _export
@tar -cj --format=ustar -f "$(EXPORTDIR)/flashrom-$(RELEASENAME).tar.bz2" -C $(EXPORTDIR)/ \
$(TAROPTIONS) "flashrom-$(RELEASENAME)/"
@@ -1728,7 +1097,7 @@ tarball: _export
libpayload: clean
make CC="CC=i386-elf-gcc lpgcc" AR=i386-elf-ar RANLIB=i386-elf-ranlib
-.PHONY: all install clean distclean compiler hwlibs features _export export tarball featuresavailable libpayload
+.PHONY: all install clean distclean config _export export tarball libpayload
# Disable implicit suffixes and built-in rules (for performance and profit)
.SUFFIXES:
diff --git a/Makefile.d/arch_test.h b/Makefile.d/arch_test.h
new file mode 100644
index 000000000..654f8e562
--- /dev/null
+++ b/Makefile.d/arch_test.h
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2011 Carl-Daniel Hailfinger
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+/*
+ * This file determinate the target architecture. It should only be used
+ * by the Makefile
+ */
+
+#if defined (__i386__) || defined (__x86_64__) || defined(__amd64__)
+ #define __FLASHROM_ARCH__ "x86"
+#elif defined (__mips) || defined (__mips__) || defined (__MIPS__) || defined (mips)
+ #define __FLASHROM_ARCH__ "mips"
+#elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || \
+ defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || \
+ defined(_ARCH_PPC64) || defined(__ppc)
+ #define __FLASHROM_ARCH__ "ppc"
+#elif defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_ARM) || defined(_M_ARM) || defined(__arm) || \
+ defined(__aarch64__)
+ #define __FLASHROM_ARCH__ "arm"
+#elif defined (__sparc__) || defined (__sparc)
+ #define __FLASHROM_ARCH__ "sparc"
+#elif defined (__alpha__)
+ #define __FLASHROM_ARCH__ "alpha"
+#elif defined (__hppa__) || defined (__hppa)
+ #define __FLASHROM_ARCH__ "hppa"
+#elif defined (__m68k__)
+ #define __FLASHROM_ARCH__ "m68k"
+#elif defined (__riscv)
+ #define __FLASHROM_ARCH__ "riscv"
+#elif defined (__sh__)
+ #define __FLASHROM_ARCH__ "sh"
+#elif defined(__s390__) || defined(__s390x__) || defined(__zarch__)
+ #define __FLASHROM_ARCH__ "s390"
+#elif defined(__arc__)
+ #define __FLASHROM_ARCH__ "arc"
+#elif defined(__ARC64__)
+ #define __FLASHROM_ARCH__ "arc64"
+#elif defined(__e2k__)
+ #define __FLASHROM_ARCH__ "e2k"
+#else
+ #define __FLASHROM_ARCH__ "unknown"
+#endif
+__FLASHROM_ARCH__
diff --git a/Makefile.d/cc_test.c b/Makefile.d/cc_test.c
new file mode 100644
index 000000000..0610964d8
--- /dev/null
+++ b/Makefile.d/cc_test.c
@@ -0,0 +1,6 @@
+int main(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ return 0;
+}
diff --git a/Makefile.d/clock_gettime_test.c b/Makefile.d/clock_gettime_test.c
new file mode 100644
index 000000000..000aa425f
--- /dev/null
+++ b/Makefile.d/clock_gettime_test.c
@@ -0,0 +1,9 @@
+#include <time.h>
+int main(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ struct timespec res;
+ clock_gettime(CLOCK_REALTIME, &res);
+ return 0;
+}
diff --git a/platform.h b/Makefile.d/endian_test.h
index 751957cae..36658b318 100644
--- a/platform.h
+++ b/Makefile.d/endian_test.h
@@ -14,133 +14,51 @@
*/
/*
- * Header file to determine target OS and CPU architecture.
+ * This file determinate the target endian. It should only be used my the Makefile
*/
-#ifndef __PLATFORM_H__
-#define __PLATFORM_H__ 1
-
-// Helper defines for operating systems
-#if defined(__gnu_linux__) || defined(__linux__)
-#define IS_LINUX 1
-#else
-#define IS_LINUX 0
-#endif
-#if defined(__APPLE__) && defined(__MACH__) /* yes, both. */
-#define IS_MACOSX 1
-#else
-#define IS_MACOSX 0
-#endif
-#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__WINDOWS__)
-#define IS_WINDOWS 1
-#else
-#define IS_WINDOWS 0
-#endif
-
-// Likewise for target architectures
#if defined (__i386__) || defined (__x86_64__) || defined(__amd64__)
- #define __FLASHROM_ARCH__ "x86"
- #define IS_X86 1
-#elif defined (__mips) || defined (__mips__) || defined (__MIPS__) || defined (mips)
- #define __FLASHROM_ARCH__ "mips"
- #define IS_MIPS 1
-#elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || \
- defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || \
- defined(_ARCH_PPC64) || defined(__ppc)
- #define __FLASHROM_ARCH__ "ppc"
- #define IS_PPC 1
-#elif defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_ARM) || defined(_M_ARM) || defined(__arm) || \
- defined(__aarch64__)
- #define __FLASHROM_ARCH__ "arm"
- #define IS_ARM 1
-#elif defined (__sparc__) || defined (__sparc)
- #define __FLASHROM_ARCH__ "sparc"
- #define IS_SPARC 1
-#elif defined (__alpha__)
- #define __FLASHROM_ARCH__ "alpha"
- #define IS_ALPHA 1
-#elif defined (__hppa__) || defined (__hppa)
- #define __FLASHROM_ARCH__ "hppa"
- #define IS_HPPA 1
-#elif defined (__m68k__)
- #define __FLASHROM_ARCH__ "m68k"
- #define IS_M68K 1
-#elif defined (__riscv)
- #define __FLASHROM_ARCH__ "riscv"
- #define IS_RISCV 1
-#elif defined (__sh__)
- #define __FLASHROM_ARCH__ "sh"
- #define IS_SH 1
-#elif defined(__s390__) || defined(__s390x__) || defined(__zarch__)
- #define __FLASHROM_ARCH__ "s390"
- #define IS_S390 1
-#elif defined(__arc__)
- #define __FLASHROM_ARCH__ "arc"
- #define IS_ARC 1
-#endif
-
-#if !(IS_X86 || IS_MIPS || IS_PPC || IS_ARM || IS_SPARC || IS_ALPHA || IS_HPPA || IS_M68K || IS_RISCV || IS_SH || IS_S390 || IS_ARC)
-#error Unknown architecture
-#endif
-
-/* The next big hunk tries to guess endianness from various preprocessor macros */
-/* First some error checking in case some weird header has defined both.
- * NB: OpenBSD always defines _BIG_ENDIAN and _LITTLE_ENDIAN. */
-#if defined (__LITTLE_ENDIAN__) && defined (__BIG_ENDIAN__)
-#error Conflicting endianness #define
-#endif
-
-#if IS_X86
-
/* All x86 is little-endian. */
#define __FLASHROM_LITTLE_ENDIAN__ 1
-
-#elif IS_MIPS
-
+#elif defined (__mips) || defined (__mips__) || defined (__MIPS__) || defined (mips)
/* MIPS can be either endian. */
#if defined (__MIPSEL) || defined (__MIPSEL__) || defined (_MIPSEL) || defined (MIPSEL)
#define __FLASHROM_LITTLE_ENDIAN__ 1
#elif defined (__MIPSEB) || defined (__MIPSEB__) || defined (_MIPSEB) || defined (MIPSEB)
#define __FLASHROM_BIG_ENDIAN__ 1
#endif
-
-#elif IS_PPC
-
+#elif defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || \
+ defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || \
+ defined(_ARCH_PPC64) || defined(__ppc)
/* PowerPC can be either endian. */
#if defined (_BIG_ENDIAN) || defined (__BIG_ENDIAN__)
#define __FLASHROM_BIG_ENDIAN__ 1
#elif defined (_LITTLE_ENDIAN) || defined (__LITTLE_ENDIAN__)
#define __FLASHROM_LITTLE_ENDIAN__ 1
#endif
-
-#elif IS_ARM
-
+#elif defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_ARM) || defined(_M_ARM) || defined(__arm) || \
+ defined(__aarch64__)
/* ARM can be either endian. */
-#if defined (__ARMEB__)
+#if defined (__ARMEB__) || defined (__BIG_ENDIAN__)
#define __FLASHROM_BIG_ENDIAN__ 1
-#elif defined (__ARMEL__)
+#elif defined (__ARMEL__) || defined (__LITTLE_ENDIAN__)
#define __FLASHROM_LITTLE_ENDIAN__ 1
#endif
-
-#elif IS_SPARC
+#elif defined (__sparc__) || defined (__sparc)
/* SPARC is big endian in general (but allows to access data in little endian too). */
#define __FLASHROM_BIG_ENDIAN__ 1
-
-#elif IS_ARC
+#elif defined(__arc__)
#if defined(__BIG_ENDIAN__)
#define __FLASHROM_BIG_ENDIAN__ 1
#else
#define __FLASHROM_LITTLE_ENDIAN__ 1
#endif
-
-#endif /* IS_? */
+#endif
#if !defined (__FLASHROM_BIG_ENDIAN__) && !defined (__FLASHROM_LITTLE_ENDIAN__)
-
/* If architecture-specific approaches fail try generic variants. First: BSD (works about everywhere). */
-#if !IS_WINDOWS
+#if !(defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__WINDOWS__))
#include <sys/param.h>
-
#if defined (__BYTE_ORDER)
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define __FLASHROM_LITTLE_ENDIAN__
@@ -151,9 +69,7 @@
#endif
#endif /* defined __BYTE_ORDER */
#endif /* !IS_WINDOWS */
-
#if !defined (__FLASHROM_BIG_ENDIAN__) && !defined (__FLASHROM_LITTLE_ENDIAN__)
-
/* Nonstandard libc-specific macros for determining endianness. */
/* musl provides an endian.h as well... but it can not be detected from within C. */
#if defined(__GLIBC__)
@@ -165,11 +81,9 @@
#endif
#endif
#endif
-
#endif
-
-#if !defined (__FLASHROM_BIG_ENDIAN__) && !defined (__FLASHROM_LITTLE_ENDIAN__)
-#error Unable to determine endianness.
+#if defined(__FLASHROM_LITTLE_ENDIAN__)
+"little"
+#else
+"big"
#endif
-
-#endif /* !__PLATFORM_H__ */
diff --git a/Makefile.d/ft232h_test.c b/Makefile.d/ft232h_test.c
new file mode 100644
index 000000000..21bc99589
--- /dev/null
+++ b/Makefile.d/ft232h_test.c
@@ -0,0 +1,3 @@
+#include <ftdi.h>
+
+enum ftdi_chip_type type = TYPE_232H; \ No newline at end of file
diff --git a/Makefile.d/linux_i2c_test.c b/Makefile.d/linux_i2c_test.c
new file mode 100644
index 000000000..768226bab
--- /dev/null
+++ b/Makefile.d/linux_i2c_test.c
@@ -0,0 +1,9 @@
+#include <linux/i2c-dev.h>
+#include <linux/i2c.h>
+
+int main(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ return 0;
+}
diff --git a/Makefile.d/linux_mtd_test.c b/Makefile.d/linux_mtd_test.c
new file mode 100644
index 000000000..d254e242c
--- /dev/null
+++ b/Makefile.d/linux_mtd_test.c
@@ -0,0 +1,8 @@
+#include <mtd/mtd-user.h>
+
+int main(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ return 0;
+}
diff --git a/Makefile.d/linux_spi_test.c b/Makefile.d/linux_spi_test.c
new file mode 100644
index 000000000..a4d265786
--- /dev/null
+++ b/Makefile.d/linux_spi_test.c
@@ -0,0 +1,9 @@
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+int main(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ return 0;
+}
diff --git a/os.h b/Makefile.d/os_test.h
index ddfa46b5d..17045b254 100644
--- a/os.h
+++ b/Makefile.d/os_test.h
@@ -14,11 +14,9 @@
*/
/*
- * Header file for OS checking.
+ * This file determinate the target os. It should only be used my the Makefile
*/
-#include "platform.h"
-
// Solaris
#if defined (__sun) && (defined(__i386) || defined(__amd64))
#define __FLASHROM_OS__ "SunOS"
@@ -63,5 +61,7 @@
#else
#define __FLASHROM_OS__ "Linux"
#endif
+#else
+#define __FLASHROM_OS__ "unknown"
#endif
__FLASHROM_OS__
diff --git a/Makefile.d/utsname_test.c b/Makefile.d/utsname_test.c
new file mode 100644
index 000000000..7bc666527
--- /dev/null
+++ b/Makefile.d/utsname_test.c
@@ -0,0 +1,9 @@
+#include <sys/utsname.h>
+struct utsname osinfo;
+int main(int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+ uname(&osinfo);
+ return 0;
+}
diff --git a/Makefile.include b/Makefile.include
new file mode 100644
index 000000000..5f81ccc9d
--- /dev/null
+++ b/Makefile.include
@@ -0,0 +1,65 @@
+#
+# This file is part of the flashrom project.
+#
+# 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; version 2 of the License.
+#
+# 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.
+#
+
+# Here are functions and macros defined for the Makefile
+
+define mark_unsupported
+$(foreach p,$1, \
+ $(if $(filter $($(p)),yes), \
+ $(eval UNSUPPORTED_FEATURES += $(p)=yes), \
+ $(eval override $(p) := no)))
+endef
+
+define filter_deps
+$(strip $(foreach p,$1, \
+ $(if $(filter $($(p)),yes), \
+ $(p))))
+endef
+
+define disable_all
+$(foreach p,$1, \
+ $(eval override $(p) := no))
+endef
+
+# Run the C Preprocessor with file $1 and return the last line, removing quotes.
+define c_macro_test
+$(strip $(call debug_shell, $(CC) -E $1 | tail -1 | tr -d '"'))
+endef
+
+define c_compile_test # $1: files to compile, $2: cflags
+$(call debug_shell, $(CC) -c -Wall -Werror $2 $1 -o /dev/null && echo yes || echo no)
+endef
+
+define c_link_test # $1: file to compile and link, $2: cflags, $3: ldflags
+$(call debug_shell, $(CC) -Wall -Werror $2 $1 $3 -o /dev/null && echo yes || echo no)
+endef
+
+define find_dependency
+$(call debug_shell, $(if $(PKG_CONFIG_LIBDIR),PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR),) $(PKG_CONFIG) --exists $1 && echo yes || echo no)
+endef
+
+define dependency_version
+$(call debug_shell, $(if $(PKG_CONFIG_LIBDIR),PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR),) $(PKG_CONFIG) --modversion $1 2>/dev/null)
+endef
+
+define has_dependency # $1: dependency, $2: action/target
+$(if $(findstring $(strip $1),yes), $(strip $2))
+endef
+
+define dependency_cflags
+$(call debug_shell, $(if $(PKG_CONFIG_LIBDIR),PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR),) $(PKG_CONFIG) --cflags $1 2>/dev/null)
+endef
+
+define dependency_ldflags
+$(call debug_shell, $(if $(PKG_CONFIG_LIBDIR),PKG_CONFIG_LIBDIR=$(PKG_CONFIG_LIBDIR),) $(PKG_CONFIG) --libs --static $1 2>/dev/null)
+endef
diff --git a/README b/README
deleted file mode 100644
index 4e7bd4fbc..000000000
--- a/README
+++ /dev/null
@@ -1,192 +0,0 @@
--------------------------------------------------------------------------------
-flashrom README
--------------------------------------------------------------------------------
-
-flashrom is a utility for detecting, reading, writing, verifying and erasing
-flash chips. It is often used to flash BIOS/EFI/coreboot/firmware images
-in-system using a supported mainboard, but it also supports flashing of network
-cards (NICs), SATA controller cards, and other external devices which can
-program flash chips.
-
-It supports a wide range of flash chips (most commonly found in SOIC8, DIP8,
-SOIC16, WSON8, PLCC32, DIP32, TSOP32, and TSOP40 packages), which use various
-protocols such as LPC, FWH, parallel flash, or SPI.
-
-Do not use flashrom on laptops (yet)! The embedded controller (EC) present in
-many laptops might interact badly with any attempts to communicate with the
-flash chip and may brick your laptop.
-
-Please make a backup of your flash chip before writing to it.
-
-Please see the flashrom(8) manpage.
-
-
-Packaging
----------
-
-To package flashrom and remove dependencies on Git, either use
-make export
-or
-make tarball
-
-'make export' will export all flashrom files from the Git repository at
-revision HEAD into a directory named "$EXPORTDIR/flashrom-$RELEASENAME"
-and will additionally add a "versioninfo.inc" file in that directory to
-contain the Git revision of the exported tree and a date for the manual
-page.
-
-'make tarball' will simply tar up the result of make export and compress
-it with bzip2.
-
-The snapshot tarballs are the result of 'make tarball' and require no
-further processing.
-
-
-Build Instructions
-------------------
-
-To build flashrom you need to install the following software:
-
- * pciutils+libpci (if you want support for mainboard or PCI device flashing)
- * libusb (if you want FT2232, Dediprog or USB-Blaster support)
- * libftdi (if you want FT2232 or USB-Blaster support)
- * libjaylink (if you want support for SEGGER J-Link and compatible devices)
-
-Linux et al:
-
- * pciutils / libpci
- * pciutils-devel / pciutils-dev / libpci-dev
- * zlib-devel / zlib1g-dev (needed if libpci was compiled with libz support)
-
-On FreeBSD, you need the following ports:
-
- * devel/gmake
- * devel/libpci
-
-On OpenBSD, you need the following ports:
-
- * devel/gmake
- * sysutils/pciutils
-
-To compile on Linux, use:
-
- make
-
-To compile on FreeBSD, OpenBSD or DragonFly BSD, use:
-
- gmake
-
-To compile on Nexenta, use:
-
- make
-
-To compile on Solaris, use:
-
- gmake LDFLAGS="-L$pathtolibpci" CC="gcc -I$pathtopciheaders" CFLAGS=-O2
-
-To compile on NetBSD (with pciutils, libftdi, libusb installed in /usr/pkg/), use:
-
- gmake
-
-To compile and run on Darwin/Mac OS X:
-
- Install DirectHW from coresystems GmbH.
- DirectHW is available at http://www.coreboot.org/DirectHW .
-
-To cross-compile on Linux for DOS:
-
- Get packages of the DJGPP cross compiler and install them:
- djgpp-filesystem djgpp-gcc djgpp-cpp djgpp-runtime djgpp-binutils
- As an alternative, the DJGPP web site offers packages for download as well:
- djcross-binutils-2.29.1-1ap.x86_64.rpm
- djcross-gcc-7.2.0-1ap.x86_64.rpm
- djcrx-2.05-5.x86_64.rpm
- The cross toolchain packages for your distribution may have slightly different
- names (look for packages named *djgpp*).
-
- Alternatively, you could use a script to build it from scratch:
- https://github.com/andrewwutw/build-djgpp
-
- You will need the libpci and libgetopt library source trees and
- their compiled static libraries and header files installed in some
- directory say libpci-libgetopt/, which will be later specified with
- LIBS_BASE parameter during flashrom compilation. Easiest way to
- handle it is to put pciutils, libgetopt and flashrom directories
- in one subdirectory. There will be an extra subdirectory libpci-libgetopt
- created, which will contain compiled libpci and libgetopt.
-
- Download pciutils 3.5.6 and apply http://flashrom.org/File:Pciutils-3.5.6.patch.gz
- Compile pciutils, using following command line:
-
- make ZLIB=no DNS=no HOST=i386-djgpp-djgpp CROSS_COMPILE=i586-pc-msdosdjgpp- \
- PREFIX=/ DESTDIR=$PWD/../libpci-libgetopt \
- STRIP="--strip-program=i586-pc-msdosdjgpp-strip -s" install install-lib
-
- Download and compile with 'make' http://flashrom.org/File:Libgetopt.tar.gz
-
- Copy the libgetopt.a to ../libpci-libgetopt/lib and
- getopt.h to ../libpci-libgetopt/include
-
- Enter the flashrom directory.
-
- make CC=i586-pc-msdosdjgpp-gcc STRIP=i586-pc-msdosdjgpp-strip LIBS_BASE=../libpci-libgetopt/ strip
-
- If you like, you can compress the resulting executable with UPX:
-
- upx -9 flashrom.exe
-
- To run flashrom.exe, download http://flashrom.org/File:Csdpmi7b.zip and
- unpack CWSDPMI.EXE into the current directory or one in PATH.
-
-To cross-compile on Linux for Windows:
-
- Get packages of the MinGW cross compiler and install them:
- mingw32-filesystem mingw32-cross-cpp mingw32-cross-binutils mingw32-cross-gcc
- mingw32-runtime mingw32-headers
- The cross toolchain packages for your distribution may have slightly different
- names (look for packages named *mingw*).
- PCI-based programmers (internal etc.) are not supported on Windows.
- Run (change CC= and STRIP= settings where appropriate)
- make CC=i686-w64-mingw32-gcc STRIP=i686-w64-mingw32-strip
-
-Processor architecture dependent features:
-
- On non-x86 architectures a few programmers don't work (yet) because they
- use port-based I/O which is not directly available on non-x86. Those
- programmers will be disabled automatically if you run "make".
-
-Compiler quirks:
-
-If you are using clang and if you want to enable only one driver, you may hit an
-overzealous compiler warning from clang. Compile with "make WARNERROR=no" to
-force it to continue and enjoy.
-
-Installation
-------------
-
-In order to install flashrom and the manpage into /usr/local, type:
-
- make install
-
-For installation in a different directory use DESTDIR, e.g. like this:
-
- make DESTDIR=/usr install
-
-If you have insufficient permissions for the destination directory, use sudo
-by adding sudo in front of the commands above.
-
-
-Contact
--------
-
-The official flashrom website is:
-
- http://www.flashrom.org/
-
-The IRC channel is
-
- #flashrom at irc.freenode.net
-
-The mailing list address is
-
- flashrom@flashrom.org
diff --git a/README.rst b/README.rst
new file mode 100644
index 000000000..0a0ea08f7
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,58 @@
+flashrom README
+===============
+
+flashrom is a utility for detecting, reading, writing, verifying and erasing
+flash chips. It is often used to flash BIOS/EFI/coreboot/firmware images
+in-system using a supported mainboard, but it also supports flashing of network
+cards (NICs), SATA controller cards, and other external devices which can
+program flash chips.
+
+It supports a wide range of flash chips (most commonly found in SOIC8, DIP8,
+SOIC16, WSON8, PLCC32, DIP32, TSOP32, and TSOP40 packages), which use various
+protocols such as LPC, FWH, parallel flash, or SPI.
+
+Do not use flashrom on laptops (yet)! The embedded controller (EC) present in
+many laptops might interact badly with any attempts to communicate with the
+flash chip and may brick your laptop.
+
+Please make a backup of your flash chip before writing to it.
+
+Please see the flashrom(8) manpage :doc:`classic_cli_manpage`.
+
+
+Building / installing / packaging
+---------------------------------
+
+flashrom supports building with **make** and **meson**.
+
+TLDR, building with meson
+"""""""""""""""""""""""""
+
+::
+
+ meson setup builddir
+ meson compile -C builddir
+ meson install -C builddir
+
+For full detailed instructions, follow the information in
+:doc:`dev_guide/building_from_source`
+
+TLDR, building with make
+""""""""""""""""""""""""
+
+::
+
+ make
+ make install
+
+For full detailed instructions, follow the information in
+:doc:`dev_guide/building_with_make`
+
+Contact
+-------
+
+The official flashrom website is:
+
+ https://www.flashrom.org/
+
+For available contact methods see :doc:`contact`
diff --git a/VERSION b/VERSION
new file mode 100644
index 000000000..90e4bc277
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+1.4.0-devel
diff --git a/amd_imc.c b/amd_imc.c
index 8b0bcf2f5..d57728e56 100644
--- a/amd_imc.c
+++ b/amd_imc.c
@@ -15,12 +15,11 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_x86_io.h"
#include "spi.h"
+#include "platform/pci.h"
/* same as serverengines */
static void enter_conf_mode_ec(uint16_t port)
@@ -61,7 +60,7 @@ static int mbox_wait_ack(uint16_t mbox_port)
msg_pwarn("IMC MBOX: Timeout!\n");
return 1;
}
- programmer_delay(1000);
+ default_delay(1000);
}
return 0;
}
@@ -123,7 +122,7 @@ static int imc_resume(void *data)
int ret = imc_send_cmd(dev, 0xb5);
if (ret != 0)
- msg_pinfo("Resuming IMC failed)\n");
+ msg_pinfo("Resuming IMC failed.\n");
else
msg_pdbg2("IMC resumed.\n");
return ret;
@@ -151,5 +150,3 @@ int amd_imc_shutdown(struct pci_dev *dev)
return ret;
}
-
-#endif
diff --git a/archtest.c b/archtest.c
deleted file mode 100644
index 791f1a3a7..000000000
--- a/archtest.c
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "platform.h"
-__FLASHROM_ARCH__
diff --git a/asm106x.c b/asm106x.c
new file mode 100644
index 000000000..0c9cf111d
--- /dev/null
+++ b/asm106x.c
@@ -0,0 +1,154 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2023 Alex Badea <vamposdecampos@gmail.com>
+ *
+ * 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 "programmer.h"
+#include "platform/pci.h"
+
+#define PCI_VENDOR_ID_ASMEDIA 0x1b21
+
+#define ASM106X_REG_DATA 0xf0
+#define ASM106X_REG_CTRL 0xf4
+#define ASM106X_CTRL_RUN 0x20 /* SPI master is running */
+#define ASM106X_CTRL_CSN 0x10 /* CS_n pin output */
+#define ASM106X_CTRL_WRITE 0x08 /* 0=read, 1=write */
+#define ASM106X_CTRL_MASK 0xc0 /* unknown, untouched */
+
+struct asm106x_data {
+ struct pci_dev *pci;
+};
+
+static const struct dev_entry asm106x_devs[] = {
+ {PCI_VENDOR_ID_ASMEDIA, 0x0612, OK, "ASMedia", "ASM106x"},
+
+ {0},
+};
+
+static int asm106x_wait_ready(struct pci_dev *pci, uint8_t *pval)
+{
+ unsigned int timeout = 100;
+ uint8_t val;
+
+ while (timeout) {
+ val = pci_read_byte(pci, ASM106X_REG_CTRL);
+ msg_pdbg2("asm106x status %#02"PRIx8" tries %d\n", val, timeout);
+ if (!(val & ASM106X_CTRL_RUN)) {
+ if (pval)
+ *pval = val;
+ return 0;
+ }
+ default_delay(10);
+ timeout--;
+ }
+
+ msg_pdbg("asm106x timed out, ctrl %#02"PRIx8"\n", val);
+ return 1;
+}
+
+
+static int asm106x_command(const struct flashctx *flash,
+ unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
+{
+ struct asm106x_data *data = flash->mst->spi.data;
+ uint8_t ctrl;
+ int rv = 1;
+
+ msg_pdbg2("asm106x command: wr %d rd %d\n", writecnt, readcnt);
+ if (asm106x_wait_ready(data->pci, &ctrl))
+ return 1;
+ ctrl &= ASM106X_CTRL_MASK;
+
+ while (writecnt) {
+ const unsigned int chunk = min(writecnt, 4);
+ uint32_t val = 0;
+
+ for (int k = chunk-1; k >= 0; k--)
+ val = (val << 8) | writearr[k];
+ msg_pdbg2("asm106x write %#08"PRIx32" chunk %u\n", val, chunk);
+ pci_write_long(data->pci, ASM106X_REG_DATA, val);
+ pci_write_byte(data->pci, ASM106X_REG_CTRL,
+ ctrl | ASM106X_CTRL_RUN | ASM106X_CTRL_WRITE | chunk);
+ if (asm106x_wait_ready(data->pci, NULL))
+ goto out;
+ writecnt -= chunk;
+ writearr += chunk;
+ }
+ while (readcnt) {
+ const unsigned int chunk = min(readcnt, 4);
+
+ pci_write_byte(data->pci, ASM106X_REG_CTRL,
+ ctrl | ASM106X_CTRL_RUN | chunk);
+ if (asm106x_wait_ready(data->pci, NULL))
+ goto out;
+
+ uint32_t val = pci_read_long(data->pci, ASM106X_REG_DATA);
+ msg_pdbg2("asm106x read %#08"PRIx32" chunk %u\n", val, chunk);
+ for (unsigned int k = 0; k < chunk; k++) {
+ readarr[k] = val & 0xff;
+ val >>= 8;
+ }
+ readcnt -= chunk;
+ readarr += chunk;
+ }
+
+ rv = 0;
+out:
+ pci_write_byte(data->pci, ASM106X_REG_CTRL, ctrl | ASM106X_CTRL_CSN);
+ return rv;
+}
+
+static int asm106x_shutdown(void *data)
+{
+ free(data);
+ return 0;
+}
+
+static const struct spi_master asm106x_spi_master = {
+ .features = SPI_MASTER_4BA,
+ .max_data_read = MAX_DATA_READ_UNLIMITED,
+ .max_data_write = MAX_DATA_WRITE_UNLIMITED,
+ .command = asm106x_command,
+ .shutdown = asm106x_shutdown,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+};
+
+static int asm106x_init(const struct programmer_cfg *cfg)
+{
+ struct pci_dev *pci;
+ struct asm106x_data *data;
+
+ /* TODO: no BAR required (just config space) */
+ pci = pcidev_init(cfg, asm106x_devs, PCI_ROM_ADDRESS);
+ if (!pci)
+ return 1;
+
+ data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("cannot allocate memory for asm106x_data\n");
+ return 1;
+ }
+ data->pci = pci;
+ return register_spi_master(&asm106x_spi_master, data);
+}
+
+const struct programmer_entry programmer_asm106x = {
+ .name = "asm106x",
+ .type = PCI,
+ .devs.dev = asm106x_devs,
+ .init = asm106x_init,
+};
diff --git a/at45db.c b/at45db.c
index 5f949bb20..6d66a6e99 100644
--- a/at45db.c
+++ b/at45db.c
@@ -80,9 +80,10 @@ static unsigned int at45db_get_sector_count(struct flashctx *flash)
unsigned int i, j;
unsigned int cnt = 0;
for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
- if (flash->chip->block_erasers[i].block_erase == &spi_erase_at45db_sector) {
+ const struct block_eraser *const eraser = &flash->chip->block_erasers[i];
+ if (eraser->block_erase == SPI_ERASE_AT45DB_SECTOR) {
for (j = 0; j < NUM_ERASEREGIONS; j++) {
- cnt += flash->chip->block_erasers[i].eraseblocks[j].count;
+ cnt += eraser->eraseblocks[j].count;
}
}
}
@@ -199,12 +200,12 @@ int probe_spi_at45db(struct flashctx *flash)
}
switch (chip->page_size) {
- case 256: chip->gran = write_gran_256bytes; break;
- case 264: chip->gran = write_gran_264bytes; break;
- case 512: chip->gran = write_gran_512bytes; break;
- case 528: chip->gran = write_gran_528bytes; break;
- case 1024: chip->gran = write_gran_1024bytes; break;
- case 1056: chip->gran = write_gran_1056bytes; break;
+ case 256: chip->gran = WRITE_GRAN_256BYTES; break;
+ case 264: chip->gran = WRITE_GRAN_264BYTES; break;
+ case 512: chip->gran = WRITE_GRAN_512BYTES; break;
+ case 528: chip->gran = WRITE_GRAN_528BYTES; break;
+ case 1024: chip->gran = WRITE_GRAN_1024BYTES; break;
+ case 1056: chip->gran = WRITE_GRAN_1056BYTES; break;
default:
msg_cerr("%s: unknown page size %d.\n", __func__, chip->page_size);
return 0;
@@ -309,7 +310,7 @@ static int at45db_wait_ready (struct flashctx *flash, unsigned int us, unsigned
return 0;
if (ret != 0 || retries-- == 0)
return 1;
- programmer_delay(us);
+ programmer_delay(flash, us);
}
}
@@ -550,6 +551,7 @@ int spi_write_at45db(struct flashctx *flash, const uint8_t *buf, unsigned int st
msg_cerr("Writing page %u failed!\n", i);
return 1;
}
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i + page_size, len);
}
return 0;
}
diff --git a/atahpt.c b/atahpt.c
index dae022250..71fd4d5b5 100644
--- a/atahpt.c
+++ b/atahpt.c
@@ -14,24 +14,28 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <stdlib.h>
#include <string.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_x86_io.h"
+#include "platform/pci.h"
#define BIOS_ROM_ADDR 0x90
#define BIOS_ROM_DATA 0x94
#define REG_FLASH_ACCESS 0x58
+#define BIT_FLASH_ACCESS BIT(24)
#define PCI_VENDOR_ID_HPT 0x1103
-static uint32_t io_base_addr = 0;
+struct atahpt_data {
+ struct pci_dev *dev;
+ uint32_t io_base_addr;
+ uint32_t flash_access;
+};
-const struct dev_entry ata_hpt[] = {
+static const struct dev_entry ata_hpt[] = {
{0x1103, 0x0004, NT, "Highpoint", "HPT366/368/370/370A/372/372N"},
{0x1103, 0x0005, NT, "Highpoint", "HPT372A/372N"},
{0x1103, 0x0006, NT, "Highpoint", "HPT302/302N"},
@@ -40,29 +44,49 @@ const struct dev_entry ata_hpt[] = {
};
static void atahpt_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr);
+ chipaddr addr)
+{
+ struct atahpt_data *data = flash->mst->par.data;
+
+ OUTL((uint32_t)addr, data->io_base_addr + BIOS_ROM_ADDR);
+ OUTB(val, data->io_base_addr + BIOS_ROM_DATA);
+}
+
static uint8_t atahpt_chip_readb(const struct flashctx *flash,
- const chipaddr addr);
+ const chipaddr addr)
+{
+ struct atahpt_data *data = flash->mst->par.data;
+
+ OUTL((uint32_t)addr, data->io_base_addr + BIOS_ROM_ADDR);
+ return INB(data->io_base_addr + BIOS_ROM_DATA);
+}
+
+static int atahpt_shutdown(void *par_data)
+{
+ struct atahpt_data *data = par_data;
+
+ /* Restore original flash access state. */
+ pci_write_long(data->dev, REG_FLASH_ACCESS, data->flash_access);
+
+ free(par_data);
+ return 0;
+}
+
static const struct par_master par_master_atahpt = {
- .chip_readb = atahpt_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = atahpt_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
+ .chip_readb = atahpt_chip_readb,
+ .chip_writeb = atahpt_chip_writeb,
+ .shutdown = atahpt_shutdown,
};
-int atahpt_init(void)
+static int atahpt_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
- uint32_t reg32;
+ uint32_t io_base_addr;
if (rget_io_perms())
return 1;
- dev = pcidev_init(ata_hpt, PCI_BASE_ADDRESS_4);
+ dev = pcidev_init(cfg, ata_hpt, PCI_BASE_ADDRESS_4);
if (!dev)
return 1;
@@ -70,30 +94,24 @@ int atahpt_init(void)
if (!io_base_addr)
return 1;
- /* Enable flash access. */
- reg32 = pci_read_long(dev, REG_FLASH_ACCESS);
- reg32 |= (1 << 24);
- rpci_write_long(dev, REG_FLASH_ACCESS, reg32);
-
- register_par_master(&par_master_atahpt, BUS_PARALLEL);
-
- return 0;
-}
+ struct atahpt_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
+ return 1;
+ }
+ data->dev = dev;
+ data->io_base_addr = io_base_addr;
-static void atahpt_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
- OUTB(val, io_base_addr + BIOS_ROM_DATA);
-}
+ /* Enable flash access. */
+ data->flash_access = pci_read_long(dev, REG_FLASH_ACCESS);
+ pci_write_long(dev, REG_FLASH_ACCESS, data->flash_access | BIT_FLASH_ACCESS);
-static uint8_t atahpt_chip_readb(const struct flashctx *flash,
- const chipaddr addr)
-{
- OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
- return INB(io_base_addr + BIOS_ROM_DATA);
+ return register_par_master(&par_master_atahpt, BUS_PARALLEL, data);
}
-#else
-#error PCI port I/O access is not supported on this architecture yet.
-#endif
+const struct programmer_entry programmer_atahpt = {
+ .name = "atahpt",
+ .type = PCI,
+ .devs.dev = ata_hpt,
+ .init = atahpt_init,
+};
diff --git a/atapromise.c b/atapromise.c
index ab34a1ec8..9beebf142 100644
--- a/atapromise.c
+++ b/atapromise.c
@@ -14,13 +14,13 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <string.h>
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_x86_io.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
#define MAX_ROM_DECODE (32 * 1024)
#define ADDR_MASK (MAX_ROM_DECODE - 1)
@@ -40,40 +40,21 @@
* tested Ultra100 uses a 128 kB MX29F001T chip), the chip size is hackishly adjusted in atapromise_limit_chip.
*/
-static uint32_t io_base_addr = 0;
-static uint32_t rom_base_addr = 0;
-
-static uint8_t *atapromise_bar = NULL;
-static size_t rom_size = 0;
+struct atapromise_data {
+ uint32_t io_base_addr;
+ uint32_t rom_base_addr;
+ uint8_t *bar;
+ size_t rom_size;
+};
-const struct dev_entry ata_promise[] = {
+static const struct dev_entry ata_promise[] = {
{0x105a, 0x4d38, NT, "Promise", "PDC20262 (FastTrak66/Ultra66)"},
{0x105a, 0x0d30, NT, "Promise", "PDC20265 (FastTrak100 Lite/Ultra100)"},
{0x105a, 0x4d30, OK, "Promise", "PDC20267 (FastTrak100/Ultra100)"},
{0},
};
-static void atapromise_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
-static uint8_t atapromise_chip_readb(const struct flashctx *flash, const chipaddr addr);
-
-static const struct par_master par_master_atapromise = {
- .chip_readb = atapromise_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = atapromise_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
-};
-
-void *atapromise_map(const char *descr, uintptr_t phys_addr, size_t len)
-{
- /* In case fallback_map ever returns something other than NULL. */
- return NULL;
-}
-
-static void atapromise_limit_chip(struct flashchip *chip)
+static void atapromise_limit_chip(struct flashchip *chip, size_t rom_size)
{
unsigned int i, size;
unsigned int usable_erasers = 0;
@@ -90,7 +71,7 @@ static void atapromise_limit_chip(struct flashchip *chip)
for (i = 0; i < NUM_ERASEFUNCTIONS; ++i) {
if (chip->block_erasers[i].eraseblocks[0].size != size) {
chip->block_erasers[i].eraseblocks[0].count = 0;
- chip->block_erasers[i].block_erase = NULL;
+ chip->block_erasers[i].block_erase = NO_BLOCK_ERASE_FUNC;
} else {
chip->block_erasers[i].eraseblocks[0].size = rom_size;
usable_erasers++;
@@ -106,14 +87,48 @@ static void atapromise_limit_chip(struct flashchip *chip)
}
}
-int atapromise_init(void)
+static void atapromise_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
+{
+ const struct atapromise_data *data = flash->mst->par.data;
+ uint32_t value;
+
+ atapromise_limit_chip(flash->chip, data->rom_size);
+ value = (data->rom_base_addr + (addr & ADDR_MASK)) << 8 | val;
+ OUTL(value, data->io_base_addr + 0x14);
+}
+
+static uint8_t atapromise_chip_readb(const struct flashctx *flash, const chipaddr addr)
+{
+ const struct atapromise_data *data = flash->mst->par.data;
+
+ atapromise_limit_chip(flash->chip, data->rom_size);
+ return pci_mmio_readb(data->bar + (addr & ADDR_MASK));
+}
+
+static int atapromise_shutdown(void *par_data)
+{
+ free(par_data);
+ return 0;
+}
+
+static const struct par_master par_master_atapromise = {
+ .chip_readb = atapromise_chip_readb,
+ .chip_writeb = atapromise_chip_writeb,
+ .shutdown = atapromise_shutdown,
+};
+
+static int atapromise_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
+ uint32_t io_base_addr;
+ uint32_t rom_base_addr;
+ uint8_t *bar;
+ size_t rom_size;
if (rget_io_perms())
return 1;
- dev = pcidev_init(ata_promise, PCI_BASE_ADDRESS_4);
+ dev = pcidev_init(cfg, ata_promise, PCI_BASE_ADDRESS_4);
if (!dev)
return 1;
@@ -134,37 +149,33 @@ int atapromise_init(void)
}
rom_size = dev->rom_size > MAX_ROM_DECODE ? MAX_ROM_DECODE : dev->rom_size;
- atapromise_bar = (uint8_t*)rphysmap("Promise", rom_base_addr, rom_size);
- if (atapromise_bar == ERROR_PTR) {
+ bar = (uint8_t*)rphysmap("Promise", rom_base_addr, rom_size);
+ if (bar == ERROR_PTR) {
return 1;
}
- max_rom_decode.parallel = rom_size;
- register_par_master(&par_master_atapromise, BUS_PARALLEL);
-
msg_pwarn("Do not use this device as a generic programmer. It will leave anything outside\n"
"the first %zu kB of the flash chip in an undefined state. It works fine for the\n"
"purpose of updating the firmware of this device (padding may necessary).\n",
rom_size / 1024);
- return 0;
-}
-
-static void atapromise_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
-{
- uint32_t data;
-
- atapromise_limit_chip(flash->chip);
- data = (rom_base_addr + (addr & ADDR_MASK)) << 8 | val;
- OUTL(data, io_base_addr + 0x14);
-}
+ struct atapromise_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
+ return 1;
+ }
+ data->io_base_addr = io_base_addr;
+ data->rom_base_addr = rom_base_addr;
+ data->bar = bar;
+ data->rom_size = rom_size;
-static uint8_t atapromise_chip_readb(const struct flashctx *flash, const chipaddr addr)
-{
- atapromise_limit_chip(flash->chip);
- return pci_mmio_readb(atapromise_bar + (addr & ADDR_MASK));
+ max_rom_decode.parallel = rom_size;
+ return register_par_master(&par_master_atapromise, BUS_PARALLEL, data);
}
-#else
-#error PCI port I/O access is not supported on this architecture yet.
-#endif
+const struct programmer_entry programmer_atapromise = {
+ .name = "atapromise",
+ .type = PCI,
+ .devs.dev = ata_promise,
+ .init = atapromise_init,
+};
diff --git a/atavia.c b/atavia.c
index b407a30cf..da2ab2fc3 100644
--- a/atavia.c
+++ b/atavia.c
@@ -20,7 +20,7 @@
#include <string.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_VIA 0x1106
@@ -46,27 +46,14 @@
/* Select the byte we want to access. This is done by clearing the bit corresponding to the byte we want to
* access, leaving the others set (yes, really). */
#define ENABLE_BYTE(address) ((~(1 << ((address) & 3))) & BROM_BYTE_ENABLE_MASK)
-#define BYTE_OFFSET(address) (((addr) & 3) * 8)
+#define BYTE_OFFSET(address) (((address) & 3) * 8)
-const struct dev_entry ata_via[] = {
+static const struct dev_entry ata_via[] = {
{PCI_VENDOR_ID_VIA, 0x3249, DEP, "VIA", "VT6421A"},
{0},
};
-static void atavia_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
-static uint8_t atavia_chip_readb(const struct flashctx *flash, const chipaddr addr);
-static const struct par_master lpc_master_atavia = {
- .chip_readb = atavia_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = atavia_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
-};
-
static void *atavia_offset = NULL;
static struct pci_dev *dev = NULL;
@@ -103,7 +90,7 @@ static bool atavia_ready(struct pci_dev *pcidev_dev)
ready = true;
break;
} else {
- programmer_delay(1);
+ default_delay(1);
continue;
}
}
@@ -114,43 +101,72 @@ static bool atavia_ready(struct pci_dev *pcidev_dev)
return ready;
}
-void *atavia_map(const char *descr, uintptr_t phys_addr, size_t len)
+static void *atavia_map(const char *descr, uintptr_t phys_addr, size_t len)
{
return (atavia_offset != 0) ? atavia_offset : (void *)phys_addr;
}
-int atavia_init(void)
+static void atavia_chip_writeb(const struct flashctx *flash, uint8_t val, const chipaddr addr)
+{
+ msg_pspew("%s: 0x%02x to 0x%*" PRIxPTR ".\n", __func__, val, PRIxPTR_WIDTH, addr);
+ pci_write_long(dev, BROM_ADDR, (addr & ~3));
+ pci_write_long(dev, BROM_DATA, val << BYTE_OFFSET(addr));
+ pci_write_byte(dev, BROM_ACCESS, BROM_TRIGGER | BROM_WRITE | ENABLE_BYTE(addr));
+
+ if (!atavia_ready(dev)) {
+ msg_perr("not ready after write\n");
+ }
+}
+
+static uint8_t atavia_chip_readb(const struct flashctx *flash, const chipaddr addr)
{
- char *arg = extract_programmer_param("offset");
+ pci_write_long(dev, BROM_ADDR, (addr & ~3));
+ pci_write_byte(dev, BROM_ACCESS, BROM_TRIGGER | ENABLE_BYTE(addr));
+
+ if (!atavia_ready(dev)) {
+ msg_perr("not ready after read\n");
+ }
+
+ uint8_t val = (pci_read_long(dev, BROM_DATA) >> BYTE_OFFSET(addr)) & 0xff;
+ msg_pspew("%s: 0x%02x from 0x%*" PRIxPTR ".\n", __func__, val, PRIxPTR_WIDTH, addr);
+ return val;
+}
+
+static const struct par_master lpc_master_atavia = {
+ .map_flash_region = atavia_map,
+ .chip_readb = atavia_chip_readb,
+ .chip_writeb = atavia_chip_writeb,
+};
+
+static int atavia_init(const struct programmer_cfg *cfg)
+{
+ char *arg = extract_programmer_param_str(cfg, "offset");
if (arg) {
if (strlen(arg) == 0) {
msg_perr("Missing argument for offset.\n");
free(arg);
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
char *endptr;
atavia_offset = (void *)strtoul(arg, &endptr, 0);
if (*endptr) {
msg_perr("Error: Invalid offset specified: \"%s\".\n", arg);
free(arg);
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
msg_pinfo("Mapping addresses to base %p.\n", atavia_offset);
}
free(arg);
- if (rget_io_perms())
- return 1;
-
- dev = pcidev_init(ata_via, PCI_ROM_ADDRESS); /* Actually no BAR setup needed at all. */
+ dev = pcidev_init(cfg, ata_via, PCI_ROM_ADDRESS); /* Actually no BAR setup needed at all. */
if (!dev)
return 1;
/* Test if a flash chip is attached. */
pci_write_long(dev, PCI_ROM_ADDRESS, (uint32_t)PCI_ROM_ADDRESS_MASK);
- programmer_delay(90);
+ default_delay(90);
uint32_t base = pci_read_long(dev, PCI_ROM_ADDRESS);
- msg_pdbg2("BROM base=0x%08x\n", base);
+ msg_pdbg2("BROM base=0x%08"PRIx32"\n", base);
if ((base & PCI_ROM_ADDRESS_MASK) == 0) {
msg_pwarn("Controller thinks there is no ROM attached.\n");
}
@@ -160,33 +176,12 @@ int atavia_init(void)
return 1;
}
- register_par_master(&lpc_master_atavia, BUS_LPC);
-
- return 0;
-}
-
-static void atavia_chip_writeb(const struct flashctx *flash, uint8_t val, const chipaddr addr)
-{
- msg_pspew("%s: 0x%02x to 0x%*" PRIxPTR ".\n", __func__, val, PRIxPTR_WIDTH, addr);
- pci_write_long(dev, BROM_ADDR, (addr & ~3));
- pci_write_long(dev, BROM_DATA, val << BYTE_OFFSET(addr));
- pci_write_byte(dev, BROM_ACCESS, BROM_TRIGGER | BROM_WRITE | ENABLE_BYTE(addr));
-
- if (!atavia_ready(dev)) {
- msg_perr("not ready after write\n");
- }
+ return register_par_master(&lpc_master_atavia, BUS_LPC, NULL);
}
-static uint8_t atavia_chip_readb(const struct flashctx *flash, const chipaddr addr)
-{
- pci_write_long(dev, BROM_ADDR, (addr & ~3));
- pci_write_byte(dev, BROM_ACCESS, BROM_TRIGGER | ENABLE_BYTE(addr));
-
- if (!atavia_ready(dev)) {
- msg_perr("not ready after read\n");
- }
-
- uint8_t val = (pci_read_long(dev, BROM_DATA) >> BYTE_OFFSET(addr)) & 0xff;
- msg_pspew("%s: 0x%02x from 0x%*" PRIxPTR ".\n", __func__, val, PRIxPTR_WIDTH, addr);
- return val;
-}
+const struct programmer_entry programmer_atavia = {
+ .name = "atavia",
+ .type = PCI,
+ .devs.dev = ata_via,
+ .init = atavia_init,
+};
diff --git a/bindings/rust/README b/bindings/rust/README
new file mode 100644
index 000000000..034118954
--- /dev/null
+++ b/bindings/rust/README
@@ -0,0 +1,32 @@
+-------------------------------------------------------------------------------
+flashrom rust bindings README
+-------------------------------------------------------------------------------
+
+Included within this folder are rust foreign function interface bindings for the
+libflashrom API. libflashrom-sys is an automatically generated binding built
+from the header file by the rust `bindgen` utility. It can be used for 'unsafe'
+raw access to the libflashrom API. libflashrom is a library built on
+libflashrom-sys, exporting a convential rust API.
+
+See the /util/flashrom_tester/flashrom/src/flashromlib.rs file for an example of
+usage.
+
+Build Instructions
+------------------
+
+A rust toolchain is required, rustup is one source for that: https://rustup.rs/
+
+From within child folders of this directory, where the Cargo.toml files live,
+run:
+
+ cargo build
+ cargo test
+ cargo doc --open
+
+The build process uses pkg-config to find the installed version of libflashrom.
+To override the desired version you wish to compile against pkg-config can be
+told where to find the desired header and library, for example:
+
+ env PKG_CONFIG_PATH=$HOME/src/flashrom/build/install/lib/x86_64-linux-gnu/pkgconfig \
+ LD_LIBRARY_PATH=$HOME/src/flashrom/build/install/lib/x86_64-linux-gnu \
+ cargo test
diff --git a/bindings/rust/libflashrom-sys/.cargo/config.toml b/bindings/rust/libflashrom-sys/.cargo/config.toml
new file mode 100644
index 000000000..8af59dd8c
--- /dev/null
+++ b/bindings/rust/libflashrom-sys/.cargo/config.toml
@@ -0,0 +1,2 @@
+[env]
+RUST_TEST_THREADS = "1"
diff --git a/bindings/rust/libflashrom-sys/Cargo.toml b/bindings/rust/libflashrom-sys/Cargo.toml
new file mode 100644
index 000000000..af84b8af8
--- /dev/null
+++ b/bindings/rust/libflashrom-sys/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "libflashrom-sys"
+version = "0.1.0"
+description = "Native bindings to the libflashrom library."
+readme = "../README"
+homepage = "https://www.flashrom.org/"
+repository = "https://review.coreboot.org/plugins/gitiles/flashrom/"
+license = "GPL-2.0-only"
+categories = ["external-ffi-bindings", "hardware-support"]
+links = "flashrom"
+build = "build.rs"
+edition = "2021"
+
+[build-dependencies]
+pkg-config = "0.3.19"
+bindgen = "0.59.2"
diff --git a/bindings/rust/libflashrom-sys/build.rs b/bindings/rust/libflashrom-sys/build.rs
new file mode 100644
index 000000000..43e7cf6c8
--- /dev/null
+++ b/bindings/rust/libflashrom-sys/build.rs
@@ -0,0 +1,32 @@
+fn main() {
+ pkg_config::probe_library("flashrom").unwrap();
+ let bindings = bindgen::Builder::default()
+ .header("../../../include/libflashrom.h")
+ // Tell cargo to invalidate the built crate whenever any of the
+ // included header files changed.
+ .parse_callbacks(Box::new(bindgen::CargoCallbacks))
+ // only generate the flashrom functions and used types.
+ .allowlist_function("flashrom_.*")
+ // newtype enums provide type checking without the UB potential of rust enums.
+ .default_enum_style(bindgen::EnumVariation::NewType { is_bitfield: false })
+ // We use constified enum for flashrom_log_level to allow '<' comparison.
+ .constified_enum("flashrom_log_level")
+ .prepend_enum_name(false)
+ .derive_copy(false)
+ .must_use_type("flashrom_wp_result")
+ // Avoid some va_list related functionality that is not easy to use in rust.
+ .blocklist_function("flashrom_set_log_callback")
+ .blocklist_type("flashrom_log_callback")
+ .blocklist_type("va_list")
+ .blocklist_type("__builtin_va_list")
+ .blocklist_type("__va_list_tag")
+ .size_t_is_usize(true)
+ .generate()
+ .expect("Unable to generate bindings");
+
+ // Write the bindings to the $OUT_DIR/bindings.rs file.
+ let out_path = std::path::PathBuf::from(std::env::var("OUT_DIR").unwrap());
+ bindings
+ .write_to_file(out_path.join("bindings.rs"))
+ .expect("Couldn't write bindings!");
+}
diff --git a/bindings/rust/libflashrom-sys/src/lib.rs b/bindings/rust/libflashrom-sys/src/lib.rs
new file mode 100644
index 000000000..4dc828274
--- /dev/null
+++ b/bindings/rust/libflashrom-sys/src/lib.rs
@@ -0,0 +1,5 @@
+#![allow(non_upper_case_globals)]
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(deref_nullptr)]
+include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
diff --git a/bindings/rust/libflashrom/.cargo/config.toml b/bindings/rust/libflashrom/.cargo/config.toml
new file mode 100644
index 000000000..8af59dd8c
--- /dev/null
+++ b/bindings/rust/libflashrom/.cargo/config.toml
@@ -0,0 +1,2 @@
+[env]
+RUST_TEST_THREADS = "1"
diff --git a/bindings/rust/libflashrom/Cargo.toml b/bindings/rust/libflashrom/Cargo.toml
new file mode 100644
index 000000000..1d8fb5298
--- /dev/null
+++ b/bindings/rust/libflashrom/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "libflashrom"
+version = "0.1.0"
+description = "Bindings to the libflashrom library."
+readme = "../README"
+homepage = "https://www.flashrom.org/"
+repository = "https://review.coreboot.org/plugins/gitiles/flashrom/"
+license = "GPL-2.0-only"
+categories = ["api-bindings", "hardware-support"]
+edition = "2021"
+
+[dependencies]
+libflashrom-sys = { path = "../libflashrom-sys" }
+libc = "0.2.124"
+regex = "1.5.5"
+once_cell = "1.7.2"
+
+[dev-dependencies]
+rusty-fork = "0.3.0"
+gag = "1"
+
+[build-dependencies]
+pkg-config = "0.3.19"
+cc = "1.0.72"
diff --git a/bindings/rust/libflashrom/build.rs b/bindings/rust/libflashrom/build.rs
new file mode 100644
index 000000000..9908ebbc2
--- /dev/null
+++ b/bindings/rust/libflashrom/build.rs
@@ -0,0 +1,17 @@
+extern crate cc;
+
+fn main() {
+ // pkg_config is needed only to pick up the include path for log.c to use.
+ // libflashrom-sys tells cargo how to link to libflashrom.
+ let flashrom = pkg_config::Config::new()
+ .cargo_metadata(false)
+ .probe("flashrom")
+ .unwrap();
+ let mut log_c = cc::Build::new();
+ log_c.file("src/log.c");
+ for p in flashrom.include_paths {
+ log_c.include(p);
+ }
+ log_c.compile("log.o");
+ println!("cargo:rerun-if-changed=src/log.c");
+}
diff --git a/bindings/rust/libflashrom/src/lib.rs b/bindings/rust/libflashrom/src/lib.rs
new file mode 100644
index 000000000..3f3fbc076
--- /dev/null
+++ b/bindings/rust/libflashrom/src/lib.rs
@@ -0,0 +1,1124 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2022 The Chromium OS Authors
+ *
+ * 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.
+ */
+
+//! # libflashrom
+//!
+//! The `libflashrom` library is a rust FFI binding to the flashrom library.
+//! libflashrom can be used to read write and modify some settings of flash chips.
+//! The library closely follows the libflashrom C API, but exports a `safe` interface
+//! including automatic resource management and forced error checking.
+//!
+//! libflashrom does not support threading, all usage of this library must occur on one thread.
+//!
+//! Most of the library functionality is defined on the [`Chip`] type.
+//!
+//! Example:
+//!
+//! ```
+//! use libflashrom::*;
+//! let mut chip = Chip::new(
+//! Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(),
+//! Some("W25Q128.V")
+//! ).unwrap();
+//! let mut buf = chip.image_read(None).unwrap();
+//! buf[0] = 0xFE;
+//! chip.image_write(&mut buf, None).unwrap();
+//! ```
+
+use once_cell::sync::Lazy;
+use regex::Regex;
+use std::error;
+use std::ffi::c_void;
+use std::ffi::CStr;
+use std::ffi::CString;
+use std::fmt;
+use std::io::Write;
+use std::ptr::null;
+use std::ptr::null_mut;
+use std::ptr::NonNull;
+use std::sync::Mutex;
+use std::sync::Once;
+
+pub use libflashrom_sys::{
+ flashrom_log_level, FLASHROM_MSG_DEBUG, FLASHROM_MSG_DEBUG2, FLASHROM_MSG_ERROR,
+ FLASHROM_MSG_INFO, FLASHROM_MSG_SPEW, FLASHROM_MSG_WARN,
+};
+
+pub use libflashrom_sys::flashrom_wp_mode;
+
+// libflashrom uses (start, len) or inclusive [start, end] for ranges.
+// This type exists to rust RangeBounds types to a convenient internal format.
+#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+struct RangeInternal {
+ start: usize,
+ len: usize,
+}
+
+/// The type returned for write protect and layout queries
+pub type Range = std::ops::Range<usize>;
+
+impl<T> From<T> for RangeInternal
+where
+ T: std::ops::RangeBounds<usize>,
+{
+ fn from(range: T) -> Self {
+ let start = match range.start_bound() {
+ std::ops::Bound::Included(start) => *start,
+ std::ops::Bound::Excluded(start) => *start + 1,
+ std::ops::Bound::Unbounded => 0,
+ };
+ RangeInternal {
+ start,
+ len: match range.end_bound() {
+ std::ops::Bound::Included(end) => *end - start + 1,
+ std::ops::Bound::Excluded(end) => *end - start,
+ std::ops::Bound::Unbounded => usize::MAX - start,
+ },
+ }
+ }
+}
+
+impl RangeInternal {
+ // inclusive end for libflashrom
+ fn end(&self) -> usize {
+ self.start + self.len - 1
+ }
+}
+
+// log_c is set to be the callback at [`Programmer`] init. It deals with va_list and calls log_rust.
+// log_rust calls a user defined function, or by default log_eprint.
+// log_eprint just writes to stderr.
+extern "C" {
+ fn set_log_callback();
+ // Modifying and reading current_level is not thread safe, but neither is
+ // the libflashrom implementation, so we shouldnt be using threads anyway.
+ static mut current_level: libflashrom_sys::flashrom_log_level;
+}
+
+/// Callers can use this function to log to the [`Logger`] they have set via [`set_log_level`]
+///
+/// However from rust it is likely easier to call the [`Logger`] directly.
+#[no_mangle]
+pub extern "C" fn log_rust(
+ level: libflashrom_sys::flashrom_log_level,
+ format: &std::os::raw::c_char,
+) {
+ // Because this function is called from C, it must not panic.
+ // SAFETY: log_c always provides a non null ptr to a null terminated string
+ // msg does not outlive format.
+ let msg = unsafe { CStr::from_ptr(format) }.to_string_lossy();
+ // Locking can fail if a thread panics while holding the lock.
+ match LOG_FN.lock() {
+ Ok(g) => (*g)(level, msg.as_ref()),
+ Err(_) => eprintln!("ERROR: libflashrom log failure to lock function"),
+ };
+}
+
+fn log_eprint(_level: libflashrom_sys::flashrom_log_level, msg: &str) {
+ // Because this function is called from C, it must not panic.
+ // Ignore the error.
+ let _ = std::io::stderr().write_all(msg.as_bytes());
+}
+
+// Can't directly atexit(flashrom_shutdown) because it is unsafe
+extern "C" fn shutdown_wrapper() {
+ unsafe {
+ libflashrom_sys::flashrom_shutdown();
+ }
+}
+
+/// A callback to log flashrom messages. This must not panic.
+pub type Logger = fn(libflashrom_sys::flashrom_log_level, &str);
+
+static LOG_FN: Lazy<Mutex<Logger>> = Lazy::new(|| Mutex::new(log_eprint));
+
+/// Set the maximum log message level that will be passed to [`Logger`]
+///
+/// log_rust and therefore the provided [`Logger`] will only be called for messages
+/// greater or equal to the provided priority.
+///
+/// ```
+/// use libflashrom::set_log_level;
+/// use libflashrom::FLASHROM_MSG_SPEW;
+/// // Disable logging.
+/// set_log_level(None);
+/// // Log all messages at priority FLASHROM_MSG_SPEW and above.
+/// set_log_level(Some(FLASHROM_MSG_SPEW));
+/// ```
+pub fn set_log_level(level: Option<libflashrom_sys::flashrom_log_level>) {
+ // SAFETY: current_level is only read by log_c, in this thread.
+ match level {
+ Some(level) => unsafe { current_level = level + 1 },
+ None => unsafe { current_level = 0 },
+ };
+}
+
+/// Set a [`Logger`] logging callback function
+///
+/// Provided function must not panic, as it is called from C.
+pub fn set_log_function(logger: Logger) {
+ *LOG_FN.lock().unwrap() = logger;
+}
+
+/// A type holding the error code returned by libflashrom and the function that returned the error.
+///
+/// The error codes returned from each function differ in meaning, see libflashrom.h
+#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct ErrorCode {
+ function: &'static str,
+ code: i32,
+}
+
+impl fmt::Display for ErrorCode {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "libflashrom: {} returned {}", self.function, self.code)
+ }
+}
+
+impl error::Error for ErrorCode {}
+
+impl From<ErrorCode> for String {
+ fn from(e: ErrorCode) -> Self {
+ format!("{}", e)
+ }
+}
+
+/// Errors from initialising libflashrom or a [`Programmer`]
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum InitError {
+ DuplicateInit,
+ FlashromInit(ErrorCode),
+ InvalidName(std::ffi::NulError),
+ ProgrammerInit(ErrorCode),
+}
+
+impl fmt::Display for InitError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl error::Error for InitError {}
+
+impl From<InitError> for String {
+ fn from(e: InitError) -> Self {
+ format!("{:?}", e)
+ }
+}
+
+impl From<std::ffi::NulError> for InitError {
+ fn from(err: std::ffi::NulError) -> InitError {
+ InitError::InvalidName(err)
+ }
+}
+
+/// Errors from probing a [`Chip`]
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum ChipInitError {
+ InvalidName(std::ffi::NulError),
+ NoChipError,
+ MultipleChipsError,
+ ProbeError,
+}
+
+impl fmt::Display for ChipInitError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl error::Error for ChipInitError {}
+
+impl From<ChipInitError> for String {
+ fn from(e: ChipInitError) -> Self {
+ format!("{:?}", e)
+ }
+}
+
+impl From<std::ffi::NulError> for ChipInitError {
+ fn from(err: std::ffi::NulError) -> ChipInitError {
+ ChipInitError::InvalidName(err)
+ }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum RegionError {
+ ErrorCode(ErrorCode),
+ InvalidName(std::ffi::NulError),
+}
+
+impl fmt::Display for RegionError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl error::Error for RegionError {}
+
+impl From<RegionError> for String {
+ fn from(e: RegionError) -> Self {
+ format!("{:?}", e)
+ }
+}
+
+impl From<std::ffi::NulError> for RegionError {
+ fn from(err: std::ffi::NulError) -> RegionError {
+ RegionError::InvalidName(err)
+ }
+}
+
+#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct ParseLayoutError(String);
+
+impl fmt::Display for ParseLayoutError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl error::Error for ParseLayoutError {}
+
+impl From<ParseLayoutError> for String {
+ fn from(e: ParseLayoutError) -> Self {
+ format!("{:?}", e)
+ }
+}
+
+/// A translation of the flashrom_wp_result type
+///
+/// WpOK is omitted, as it is not an error.
+/// WpErrUnknown is used for an unknown error type.
+/// Keep this list in sync with libflashrom.h
+#[derive(Clone, Debug, Eq, Hash, PartialEq)]
+pub enum WPError {
+ WpErrChipUnsupported,
+ WpErrOther,
+ WpErrReadFailed,
+ WpErrWriteFailed,
+ WpErrVerifyFailed,
+ WpErrRangeUnsupported,
+ WpErrModeUnsupported,
+ WpErrRangeListUnavailable,
+ WpErrUnsupportedState,
+ WpErrUnknown(libflashrom_sys::flashrom_wp_result),
+}
+
+impl From<libflashrom_sys::flashrom_wp_result> for WPError {
+ fn from(e: libflashrom_sys::flashrom_wp_result) -> Self {
+ assert!(e != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK);
+ match e {
+ libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_CHIP_UNSUPPORTED => {
+ WPError::WpErrChipUnsupported
+ }
+ libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_OTHER => WPError::WpErrOther,
+ libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_READ_FAILED => {
+ WPError::WpErrReadFailed
+ }
+ libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_WRITE_FAILED => {
+ WPError::WpErrWriteFailed
+ }
+ libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_VERIFY_FAILED => {
+ WPError::WpErrVerifyFailed
+ }
+ libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_RANGE_UNSUPPORTED => {
+ WPError::WpErrRangeUnsupported
+ }
+ libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_MODE_UNSUPPORTED => {
+ WPError::WpErrModeUnsupported
+ }
+ libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_RANGE_LIST_UNAVAILABLE => {
+ WPError::WpErrRangeListUnavailable
+ }
+ libflashrom_sys::flashrom_wp_result::FLASHROM_WP_ERR_UNSUPPORTED_STATE => {
+ WPError::WpErrUnsupportedState
+ }
+ _ => WPError::WpErrUnknown(e), // this could also be a panic
+ }
+ }
+}
+
+impl fmt::Display for WPError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self)
+ }
+}
+
+impl error::Error for WPError {}
+
+impl From<WPError> for String {
+ fn from(e: WPError) -> Self {
+ format!("{:?}", e)
+ }
+}
+
+/// Return a rust sanitised string derived from flashrom_version_info.
+pub fn flashrom_version_info() -> Option<String> {
+ let p = unsafe { libflashrom_sys::flashrom_version_info() };
+ if p.is_null() {
+ None
+ } else {
+ // SAFETY: flashrom_version_info returns a global `const char flashrom_version[]`
+ // derived from `-DFLASHROM_VERSION`, this is not guaranteed to be
+ // null terminated, but is in a normal build.
+ Some(unsafe { CStr::from_ptr(p) }.to_string_lossy().into_owned())
+ }
+}
+
+/// Structure for an initialised flashrom_programmer
+// flashrom_programmer_init returns a pointer accepted by flashrom_flash_probe
+// but this is not implemented at time of writing. When implemented the pointer
+// can be stored here.
+#[derive(Debug)]
+pub struct Programmer {}
+
+/// Structure for an initialised flashrom chip, or flashrom_flashctx
+// As returned by flashrom_flash_probe
+// The layout is owned here as the chip only stores a pointer when a layout is set.
+#[derive(Debug)]
+pub struct Chip {
+ ctx: NonNull<libflashrom_sys::flashrom_flashctx>,
+ _programmer: Programmer,
+ layout: Option<Layout>,
+}
+
+impl Programmer {
+ /// Initialise libflashrom and a programmer
+ ///
+ /// See libflashrom.h flashrom_programmer_init for argument documentation.
+ ///
+ /// Panics:
+ ///
+ /// If this libflashrom implementation returns a programmer pointer.
+ pub fn new(
+ programmer_name: &str,
+ programmer_options: Option<&str>,
+ ) -> Result<Programmer, InitError> {
+ static ONCE: Once = Once::new();
+ if ONCE.is_completed() {
+ // Flashrom does not currently support concurrent programmers
+ // Flashrom also does not currently support initialising a second programmer after a first has been initialised.
+ // This is used to warn the user if they try to initialise a second programmer.
+ return Err(InitError::DuplicateInit);
+ }
+ ONCE.call_once(|| {});
+
+ static INIT_RES: Lazy<Result<(), InitError>> = Lazy::new(|| {
+ unsafe { set_log_callback() };
+ // always perform_selfcheck
+ let res = unsafe { libflashrom_sys::flashrom_init(1) };
+ if res == 0 {
+ let res = unsafe { libc::atexit(shutdown_wrapper) };
+ if res == 0 {
+ Ok(())
+ } else {
+ unsafe { libflashrom_sys::flashrom_shutdown() };
+ Err(InitError::FlashromInit(ErrorCode {
+ function: "atexit",
+ code: res,
+ }))
+ }
+ } else {
+ Err(InitError::FlashromInit(ErrorCode {
+ function: "flashrom_init",
+ code: res,
+ }))
+ }
+ });
+ (*INIT_RES).clone()?;
+
+ let mut programmer: *mut libflashrom_sys::flashrom_programmer = null_mut();
+ let programmer_name = CString::new(programmer_name)?;
+ let programmer_options = match programmer_options {
+ Some(programmer_options) => Some(CString::new(programmer_options)?),
+ None => None,
+ };
+ let res = unsafe {
+ libflashrom_sys::flashrom_programmer_init(
+ &mut programmer,
+ programmer_name.as_ptr(),
+ programmer_options.as_ref().map_or(null(), |x| x.as_ptr()),
+ )
+ };
+ if res != 0 {
+ Err(InitError::ProgrammerInit(ErrorCode {
+ function: "flashrom_programmer_init",
+ code: res,
+ }))
+ } else if !programmer.is_null() {
+ panic!("flashrom_programmer_init returning a programmer pointer is not supported")
+ } else {
+ Ok(Programmer {})
+ }
+ }
+}
+
+impl Drop for Programmer {
+ fn drop(&mut self) {
+ unsafe {
+ libflashrom_sys::flashrom_programmer_shutdown(null_mut());
+ }
+ }
+}
+
+impl Chip {
+ /// Probe for a chip
+ ///
+ /// See libflashrom.h flashrom_flash_probe for argument documentation.
+ pub fn new(programmer: Programmer, chip_name: Option<&str>) -> Result<Chip, ChipInitError> {
+ let mut flash_ctx: *mut libflashrom_sys::flashrom_flashctx = null_mut();
+ let chip_name = match chip_name {
+ Some(chip_name) => Some(CString::new(chip_name)?),
+ None => None,
+ };
+ match unsafe {
+ libflashrom_sys::flashrom_flash_probe(
+ &mut flash_ctx,
+ null(),
+ chip_name.as_ref().map_or(null(), |x| x.as_ptr()),
+ )
+ } {
+ 0 => Ok(Chip {
+ ctx: NonNull::new(flash_ctx).expect("flashrom_flash_probe returned null"),
+ _programmer: programmer,
+ layout: None,
+ }),
+ 3 => Err(ChipInitError::MultipleChipsError),
+ 2 => Err(ChipInitError::NoChipError),
+ _ => Err(ChipInitError::ProbeError),
+ }
+ }
+
+ pub fn get_size(&self) -> usize {
+ unsafe { libflashrom_sys::flashrom_flash_getsize(self.ctx.as_ref()) }
+ }
+
+ /// Read the write protect config of this [`Chip`]
+ pub fn get_wp(&mut self) -> std::result::Result<WriteProtectCfg, WPError> {
+ let mut cfg = WriteProtectCfg::new()?;
+ let res =
+ unsafe { libflashrom_sys::flashrom_wp_read_cfg(cfg.wp.as_mut(), self.ctx.as_mut()) };
+ if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
+ return Err(res.into());
+ }
+ Ok(cfg)
+ }
+
+ /// Set the write protect config of this [`Chip`]
+ pub fn set_wp(&mut self, wp: &WriteProtectCfg) -> std::result::Result<(), WPError> {
+ let res =
+ unsafe { libflashrom_sys::flashrom_wp_write_cfg(self.ctx.as_mut(), wp.wp.as_ref()) };
+ if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
+ return Err(res.into());
+ }
+ Ok(())
+ }
+
+ /// Read the write protect ranges of this [`Chip`]
+ ///
+ /// # Panics
+ ///
+ /// Panics if flashrom_wp_get_available_ranges returns FLASHROM_WP_OK and a NULL pointer.
+ pub fn get_wp_ranges(&mut self) -> std::result::Result<Vec<Range>, WPError> {
+ let mut ranges: *mut libflashrom_sys::flashrom_wp_ranges = null_mut();
+ let res = unsafe {
+ libflashrom_sys::flashrom_wp_get_available_ranges(&mut ranges, self.ctx.as_mut())
+ };
+ if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
+ return Err(res.into());
+ }
+ let ranges = WriteProtectRanges {
+ ranges: NonNull::new(ranges).expect("flashrom_wp_get_available_ranges returned null"),
+ };
+
+ let count =
+ unsafe { libflashrom_sys::flashrom_wp_ranges_get_count(ranges.ranges.as_ref()) };
+ let mut ret = Vec::with_capacity(count);
+ for index in 0..count {
+ let mut start = 0;
+ let mut len = 0;
+ let res = unsafe {
+ libflashrom_sys::flashrom_wp_ranges_get_range(
+ &mut start,
+ &mut len,
+ ranges.ranges.as_ref(),
+ // TODO: fix after https://review.coreboot.org/c/flashrom/+/64996
+ index
+ .try_into()
+ .expect("flashrom_wp_ranges_get_count does not fit in a u32"),
+ )
+ };
+ if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
+ return Err(res.into());
+ }
+ ret.push(start..(start + len))
+ }
+ Ok(ret)
+ }
+
+ /// Returns the layout read from the fmap of this [`Chip`]
+ ///
+ /// # Panics
+ ///
+ /// Panics if flashrom_layout_read_fmap_from_rom returns FLASHROM_WP_OK and a NULL pointer.
+ pub fn layout_read_fmap_from_rom(&mut self) -> std::result::Result<Layout, ErrorCode> {
+ let mut layout: *mut libflashrom_sys::flashrom_layout = null_mut();
+ let err = unsafe {
+ libflashrom_sys::flashrom_layout_read_fmap_from_rom(
+ &mut layout,
+ self.ctx.as_mut(),
+ 0,
+ self.get_size(),
+ )
+ };
+ if err != 0 {
+ return Err(ErrorCode {
+ function: "flashrom_layout_read_fmap_from_rom",
+ code: err,
+ });
+ }
+ Ok(Layout {
+ layout: NonNull::new(layout).expect("flashrom_layout_read_fmap_from_rom returned null"),
+ })
+ }
+
+ /// Sets the layout of this [`Chip`]
+ ///
+ /// [`Chip`] takes ownership of Layout to ensure it is not released before the [`Chip`].
+ fn set_layout(&mut self, layout: Layout) {
+ unsafe { libflashrom_sys::flashrom_layout_set(self.ctx.as_mut(), layout.layout.as_ref()) };
+ self.layout = Some(layout)
+ }
+
+ fn unset_layout(&mut self) -> Option<Layout> {
+ unsafe { libflashrom_sys::flashrom_layout_set(self.ctx.as_mut(), null()) };
+ self.layout.take()
+ }
+
+ /// Read the whole [`Chip`], or a portion specified in a Layout
+ pub fn image_read(
+ &mut self,
+ layout: Option<Layout>,
+ ) -> std::result::Result<Vec<u8>, ErrorCode> {
+ if let Some(layout) = layout {
+ self.set_layout(layout);
+ }
+ let len = self.get_size();
+ let mut buf = vec![0; len];
+ let res = unsafe {
+ libflashrom_sys::flashrom_image_read(
+ self.ctx.as_mut(),
+ buf.as_mut_ptr() as *mut c_void,
+ len,
+ )
+ };
+ self.unset_layout();
+
+ if res == 0 {
+ Ok(buf)
+ } else {
+ Err(ErrorCode {
+ function: "flashrom_image_read",
+ code: res,
+ })
+ }
+ }
+
+ /// Write the whole [`Chip`], or a portion specified in a Layout
+ pub fn image_write(
+ &mut self,
+ buf: &mut [u8],
+ layout: Option<Layout>,
+ ) -> std::result::Result<(), ErrorCode> {
+ if let Some(layout) = layout {
+ self.set_layout(layout);
+ }
+ let res = unsafe {
+ libflashrom_sys::flashrom_image_write(
+ self.ctx.as_mut(),
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ null(),
+ )
+ };
+ self.unset_layout();
+
+ if res == 0 {
+ Ok(())
+ } else {
+ Err(ErrorCode {
+ function: "flashrom_image_write",
+ code: res,
+ })
+ }
+ }
+
+ /// Verify the whole [`Chip`], or a portion specified in a Layout
+ pub fn image_verify(
+ &mut self,
+ buf: &[u8],
+ layout: Option<Layout>,
+ ) -> std::result::Result<(), ErrorCode> {
+ if let Some(layout) = layout {
+ self.set_layout(layout);
+ }
+ let res = unsafe {
+ libflashrom_sys::flashrom_image_verify(
+ self.ctx.as_mut(),
+ buf.as_ptr() as *const c_void,
+ buf.len(),
+ )
+ };
+ self.unset_layout();
+
+ if res == 0 {
+ Ok(())
+ } else {
+ Err(ErrorCode {
+ function: "flashrom_image_verify",
+ code: res,
+ })
+ }
+ }
+
+ /// Erase the whole [`Chip`]
+ pub fn erase(&mut self) -> std::result::Result<(), ErrorCode> {
+ let res = unsafe { libflashrom_sys::flashrom_flash_erase(self.ctx.as_mut()) };
+ if res == 0 {
+ Ok(())
+ } else {
+ Err(ErrorCode {
+ function: "flashrom_flash_erase",
+ code: res,
+ })
+ }
+ }
+}
+
+impl Drop for Chip {
+ fn drop(&mut self) {
+ unsafe {
+ libflashrom_sys::flashrom_flash_release(self.ctx.as_mut());
+ }
+ }
+}
+
+/// Structure for an initialised flashrom_wp_cfg
+#[derive(Debug)]
+pub struct WriteProtectCfg {
+ wp: NonNull<libflashrom_sys::flashrom_wp_cfg>,
+}
+
+impl WriteProtectCfg {
+ /// Create an empty [`WriteProtectCfg`]
+ ///
+ /// # Panics
+ ///
+ /// Panics if flashrom_wp_cfg_new returns FLASHROM_WP_OK and a NULL pointer.
+ pub fn new() -> std::result::Result<WriteProtectCfg, WPError> {
+ let mut cfg: *mut libflashrom_sys::flashrom_wp_cfg = null_mut();
+ let res = unsafe { libflashrom_sys::flashrom_wp_cfg_new(&mut cfg) };
+ if res != libflashrom_sys::flashrom_wp_result::FLASHROM_WP_OK {
+ return Err(res.into());
+ }
+ Ok(WriteProtectCfg {
+ wp: NonNull::new(cfg).expect("flashrom_wp_cfg_new returned null"),
+ })
+ }
+
+ pub fn get_mode(&self) -> libflashrom_sys::flashrom_wp_mode {
+ unsafe { libflashrom_sys::flashrom_wp_get_mode(self.wp.as_ref()) }
+ }
+
+ pub fn set_mode(&mut self, mode: libflashrom_sys::flashrom_wp_mode) {
+ unsafe { libflashrom_sys::flashrom_wp_set_mode(self.wp.as_mut(), mode) }
+ }
+
+ pub fn get_range(&self) -> Range {
+ let mut start = 0;
+ let mut len = 0;
+ unsafe { libflashrom_sys::flashrom_wp_get_range(&mut start, &mut len, self.wp.as_ref()) };
+ start..(start + len)
+ }
+
+ pub fn set_range<T>(&mut self, range: T)
+ where
+ T: std::ops::RangeBounds<usize>,
+ {
+ let range: RangeInternal = range.into();
+ unsafe { libflashrom_sys::flashrom_wp_set_range(self.wp.as_mut(), range.start, range.len) }
+ }
+}
+
+impl Drop for WriteProtectCfg {
+ fn drop(&mut self) {
+ unsafe {
+ libflashrom_sys::flashrom_wp_cfg_release(self.wp.as_mut());
+ }
+ }
+}
+
+impl fmt::Display for WriteProtectCfg {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "range:{:?} mode:{:?}", self.get_range(), self.get_mode())
+ }
+}
+
+#[derive(Debug)]
+struct WriteProtectRanges {
+ ranges: NonNull<libflashrom_sys::flashrom_wp_ranges>,
+}
+
+impl WriteProtectRanges {}
+
+impl Drop for WriteProtectRanges {
+ fn drop(&mut self) {
+ unsafe {
+ libflashrom_sys::flashrom_wp_ranges_release(self.ranges.as_mut());
+ }
+ }
+}
+
+/// Structure for an initialised flashrom_layout
+#[derive(Debug)]
+pub struct Layout {
+ layout: NonNull<libflashrom_sys::flashrom_layout>,
+}
+
+impl Layout {
+ /// Create an empty [`Layout`]
+ ///
+ /// # Panics
+ ///
+ /// Panics if flashrom_layout_new returns 0 and a NULL pointer.
+ pub fn new() -> std::result::Result<Layout, ErrorCode> {
+ let mut layout: *mut libflashrom_sys::flashrom_layout = null_mut();
+ let err = unsafe { libflashrom_sys::flashrom_layout_new(&mut layout) };
+ if err != 0 {
+ Err(ErrorCode {
+ function: "flashrom_layout_new",
+ code: err,
+ })
+ } else {
+ Ok(Layout {
+ layout: NonNull::new(layout).expect("flashrom_layout_new returned null"),
+ })
+ }
+ }
+
+ /// Add a region to the [`Layout`]
+ ///
+ /// Not the region will not be 'included', include_region must be called to include the region.
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the region is not a valid CString,
+ /// or if libflashrom returns an error.
+ pub fn add_region<T>(&mut self, region: &str, range: T) -> std::result::Result<(), RegionError>
+ where
+ T: std::ops::RangeBounds<usize>,
+ {
+ let range: RangeInternal = range.into();
+ let err = {
+ let region = CString::new(region)?;
+ unsafe {
+ libflashrom_sys::flashrom_layout_add_region(
+ self.layout.as_mut(),
+ range.start,
+ range.end(),
+ region.as_ptr(),
+ )
+ }
+ };
+
+ if err != 0 {
+ Err(RegionError::ErrorCode(ErrorCode {
+ function: "flashrom_layout_add_region",
+ code: err,
+ }))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Include a region
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the region is not a valid CString,
+ /// or if libflashrom returns an error.
+ pub fn include_region(&mut self, region: &str) -> std::result::Result<(), RegionError> {
+ let err = {
+ let region = CString::new(region)?;
+ unsafe {
+ libflashrom_sys::flashrom_layout_include_region(
+ self.layout.as_mut(),
+ region.as_ptr(),
+ )
+ }
+ };
+ if err != 0 {
+ Err(RegionError::ErrorCode(ErrorCode {
+ function: "flashrom_layout_include_region",
+ code: err,
+ }))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Exclude a region
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the region is not a valid CString,
+ /// or if libflashrom returns an error.
+ pub fn exclude_region(&mut self, region: &str) -> std::result::Result<(), RegionError> {
+ let err = {
+ let region = CString::new(region)?;
+ unsafe {
+ libflashrom_sys::flashrom_layout_exclude_region(
+ self.layout.as_mut(),
+ region.as_ptr(),
+ )
+ }
+ };
+ if err != 0 {
+ Err(RegionError::ErrorCode(ErrorCode {
+ function: "flashrom_layout_exclude_region",
+ code: err,
+ }))
+ } else {
+ Ok(())
+ }
+ }
+
+ /// Get the [`Range`] for the given region
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the region is not a valid CString,
+ /// or if libflashrom returns an error.
+ pub fn get_region_range(&mut self, region: &str) -> std::result::Result<Range, RegionError> {
+ let mut start: std::os::raw::c_uint = 0;
+ let mut len: std::os::raw::c_uint = 0;
+ let err = {
+ let region = CString::new(region)?;
+ unsafe {
+ libflashrom_sys::flashrom_layout_get_region_range(
+ self.layout.as_mut(),
+ region.as_ptr(),
+ &mut start,
+ &mut len,
+ )
+ }
+ };
+ if err != 0 {
+ Err(RegionError::ErrorCode(ErrorCode {
+ function: "flashrom_layout_get_region_range",
+ code: err,
+ }))
+ } else {
+ // should be safe to assume sizeof(size_t) >= sizeof(unsigned int)
+ // TODO: fix after https://review.coreboot.org/c/flashrom/+/65944
+ Ok(start.try_into().unwrap()..(start + len).try_into().unwrap())
+ }
+ }
+}
+
+// TODO this will be replaced with an API implementation: https://review.coreboot.org/c/flashrom/+/65999
+impl std::str::FromStr for Layout {
+ type Err = Box<dyn error::Error>;
+
+ /// This will attempt to parse the [`Layout`] file format into a [`Layout`]
+ ///
+ /// The format is documented in the flashrom man page.
+ fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+ let mut ret = Layout::new()?;
+
+ // format is hex:hex name
+ // flashrom layout.c seems to allow any characters in the name string
+ // I am restricting here to non whitespace
+ let re = Regex::new(r"^([0-9A-Za-z]+):([0-9A-Za-z]+)\s+(\S+)$").unwrap();
+
+ // we dont use captures_iter else we would ignore incorrect lines
+ for line in s.lines() {
+ let (start, end, name) = match re.captures(line) {
+ Some(caps) => (
+ caps.get(1).unwrap(),
+ caps.get(2).unwrap(),
+ caps.get(3).unwrap(),
+ ),
+ None => Err(ParseLayoutError(format!("failed to parse: {:?}", line)))?,
+ };
+ let start = usize::from_str_radix(start.as_str(), 16)?;
+ let end = usize::from_str_radix(end.as_str(), 16)?;
+ ret.add_region(name.as_str(), start..=end)?;
+ }
+
+ Ok(ret)
+ }
+}
+
+impl Drop for Layout {
+ fn drop(&mut self) {
+ unsafe {
+ libflashrom_sys::flashrom_layout_release(self.layout.as_mut());
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use gag::BufferRedirect;
+ use std::io::Read;
+
+ use super::flashrom_version_info;
+ use super::set_log_level;
+ use super::Chip;
+ use super::ChipInitError;
+ use super::InitError;
+ use crate::set_log_function;
+ use crate::Layout;
+ use crate::Programmer;
+ use crate::WriteProtectCfg;
+
+ // flashrom contains global state, which prevents correct initialisation of
+ // a second programmer or probing of a second chip. Run all unit tests in
+ // forked subprocesses to avoid this issue.
+ use rusty_fork::rusty_fork_test;
+ rusty_fork_test! {
+
+ #[test]
+ fn version() {
+ // There is no version requirement yet, but for example:
+ // assert!(flashrom_version_info().contains("v1.2"))
+ assert!(!flashrom_version_info().unwrap().is_empty())
+ }
+
+ #[test]
+ fn only_one_programmer() {
+ {
+ let _1 = Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap();
+ // Only one programmer can be initialised at a time.
+ assert_eq!(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap_err(), InitError::DuplicateInit)
+ }
+ // Only one programmer can ever be initialised
+ assert_eq!(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap_err(), InitError::DuplicateInit)
+ }
+
+ #[test]
+ fn programmer_bad_cstring_name() {
+ assert!(matches!(Programmer::new("dummy\0", None).unwrap_err(), InitError::InvalidName(_)))
+ }
+
+ #[test]
+ fn chip_none() {
+ // Not specifying a chip will select one if there is one.
+ Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), None).unwrap();
+ }
+
+ #[test]
+ fn chip_some() {
+ // Specifying a valid chip.
+ Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), Some("W25Q128.V")).unwrap();
+ }
+
+ #[test]
+ fn chip_nochip() {
+ // Choosing a non existent chip fails.
+ assert_eq!(
+ Chip::new(Programmer::new("dummy", None).unwrap(), Some("W25Q128.V")).unwrap_err(),
+ ChipInitError::NoChipError
+ );
+ }
+
+ #[test]
+ fn logging_stderr() {
+ let mut buf = BufferRedirect::stderr().unwrap();
+ let mut fc = Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), Some("W25Q128.V")).unwrap();
+
+ set_log_level(Some(libflashrom_sys::FLASHROM_MSG_INFO));
+ fc.image_read(None).unwrap();
+ let mut stderr = String::new();
+ if buf.read_to_string(&mut stderr).unwrap() == 0 {
+ panic!("stderr empty when it should have some messages");
+ }
+
+ set_log_level(None);
+ fc.image_read(None).unwrap();
+ if buf.read_to_string(&mut stderr).unwrap() != 0 {
+ panic!("stderr not empty when it should be silent");
+ }
+ }
+
+ #[test]
+ fn logging_custom() {
+ // Check that a custom logging callback works
+ static mut BUF: String = String::new();
+ fn logger(
+ _: libflashrom_sys::flashrom_log_level,
+ format: &str,
+ ) {
+ unsafe {BUF.push_str(format)}
+ }
+ set_log_function(logger);
+ set_log_level(Some(libflashrom_sys::FLASHROM_MSG_SPEW));
+ Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), Some("W25Q128.V")).unwrap();
+ assert_ne!(unsafe{BUF.len()}, 0);
+ }
+
+ #[test]
+ fn flashchip() {
+ // basic tests of the flashchip methods
+ let mut fc = Chip::new(Programmer::new("dummy", Some("emulate=W25Q128FV")).unwrap(), Some("W25Q128.V")).unwrap();
+ fc.get_size();
+
+ let mut wp = fc.get_wp().unwrap();
+ wp.set_mode(libflashrom_sys::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED);
+ fc.set_wp(&wp).unwrap();
+ fc.get_wp_ranges().unwrap();
+
+ fn test_layout() -> Layout {
+ let mut layout = Layout::new().unwrap();
+ layout.add_region("xyz", 100..200).unwrap();
+ layout.include_region("xyz").unwrap();
+ layout.add_region("abc", 100..200).unwrap();
+ layout
+ }
+
+ fc.image_read(None).unwrap();
+ fc.image_read(Some(test_layout())).unwrap();
+
+ let mut buf = vec![0; fc.get_size()];
+ fc.image_write(&mut buf, None).unwrap();
+ fc.image_write(&mut buf, Some(test_layout())).unwrap();
+
+ fc.image_verify(&buf, None).unwrap();
+ fc.image_verify(&buf, Some(test_layout())).unwrap();
+
+ fc.erase().unwrap();
+ }
+
+ #[test]
+ fn write_protect() {
+ let mut wp = WriteProtectCfg::new().unwrap();
+ wp.set_mode(libflashrom_sys::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED);
+ wp.set_range(100..200);
+ assert_eq!(wp.get_mode(), libflashrom_sys::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED);
+ assert_eq!(wp.get_range(), 100..200);
+ }
+ }
+}
diff --git a/bindings/rust/libflashrom/src/log.c b/bindings/rust/libflashrom/src/log.c
new file mode 100644
index 000000000..6ca3ad155
--- /dev/null
+++ b/bindings/rust/libflashrom/src/log.c
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2022 The Chromium OS Authors
+ *
+ * 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 <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libflashrom.h"
+
+void log_rust(enum flashrom_log_level level, const char *format);
+
+// LOG_LEVEL = 0 (ERROR) means no messages are printed.
+enum flashrom_log_level current_level = 0;
+
+static int log_c(enum flashrom_log_level level, const char *format, va_list ap)
+{
+ static char *buf = NULL;
+ static int len = 0;
+ if (level >= current_level) {
+ return 0;
+ }
+
+ va_list ap2;
+ va_copy(ap2, ap);
+ // when buf is NULL, len is zero and this will not write to buf
+ int req_len = vsnprintf(buf, len, format, ap2);
+ va_end(ap2);
+
+ if (req_len > len) {
+ char *new_buf = realloc(buf, req_len + 1);
+ if (!new_buf) {
+ return 0;
+ }
+ buf = new_buf;
+ len = req_len + 1;
+ req_len = vsnprintf(buf, len, format, ap);
+ }
+
+ if (req_len > 0) {
+ log_rust(level, buf);
+ }
+ return req_len;
+}
+
+void set_log_callback()
+{
+ flashrom_set_log_callback(log_c);
+}
diff --git a/bitbang_spi.c b/bitbang_spi.c
index b12d81acb..dde5dbc42 100644
--- a/bitbang_spi.c
+++ b/bitbang_spi.c
@@ -22,80 +22,83 @@
#include "spi.h"
/* Note that CS# is active low, so val=0 means the chip is active. */
-static void bitbang_spi_set_cs(const struct bitbang_spi_master * const master, int val)
+static void bitbang_spi_set_cs(const struct bitbang_spi_master * const master, int val, void *spi_data)
{
- master->set_cs(val);
+ master->set_cs(val, spi_data);
}
-static void bitbang_spi_set_sck(const struct bitbang_spi_master * const master, int val)
+static void bitbang_spi_set_sck(const struct bitbang_spi_master * const master, int val, void *spi_data)
{
- master->set_sck(val);
+ master->set_sck(val, spi_data);
}
-static void bitbang_spi_request_bus(const struct bitbang_spi_master * const master)
+static void bitbang_spi_request_bus(const struct bitbang_spi_master * const master, void *spi_data)
{
if (master->request_bus)
- master->request_bus();
+ master->request_bus(spi_data);
}
-static void bitbang_spi_release_bus(const struct bitbang_spi_master * const master)
+static void bitbang_spi_release_bus(const struct bitbang_spi_master * const master, void *spi_data)
{
if (master->release_bus)
- master->release_bus();
+ master->release_bus(spi_data);
}
-static void bitbang_spi_set_sck_set_mosi(const struct bitbang_spi_master * const master, int sck, int mosi)
+static void bitbang_spi_set_sck_set_mosi(const struct bitbang_spi_master * const master, int sck, int mosi,
+ void *spi_data)
{
if (master->set_sck_set_mosi) {
- master->set_sck_set_mosi(sck, mosi);
+ master->set_sck_set_mosi(sck, mosi, spi_data);
return;
}
- master->set_sck(sck);
- master->set_mosi(mosi);
+ master->set_sck(sck, spi_data);
+ master->set_mosi(mosi, spi_data);
}
-static int bitbang_spi_set_sck_get_miso(const struct bitbang_spi_master * const master, int sck)
+static int bitbang_spi_set_sck_get_miso(const struct bitbang_spi_master * const master, int sck,
+ void *spi_data)
{
if (master->set_sck_get_miso)
- return master->set_sck_get_miso(sck);
+ return master->set_sck_get_miso(sck, spi_data);
- master->set_sck(sck);
- return master->get_miso();
+ master->set_sck(sck, spi_data);
+ return master->get_miso(spi_data);
}
-static uint8_t bitbang_spi_read_byte(const struct bitbang_spi_master *master)
+static uint8_t bitbang_spi_read_byte(const struct bitbang_spi_master *master, void *spi_data)
{
uint8_t ret = 0;
int i;
for (i = 7; i >= 0; i--) {
if (i == 0)
- bitbang_spi_set_sck_set_mosi(master, 0, 0);
+ bitbang_spi_set_sck_set_mosi(master, 0, 0, spi_data);
else
- bitbang_spi_set_sck(master, 0);
- programmer_delay(master->half_period);
+ bitbang_spi_set_sck(master, 0, spi_data);
+ default_delay(master->half_period);
ret <<= 1;
- ret |= bitbang_spi_set_sck_get_miso(master, 1);
- programmer_delay(master->half_period);
+ ret |= bitbang_spi_set_sck_get_miso(master, 1, spi_data);
+ default_delay(master->half_period);
}
return ret;
}
-static void bitbang_spi_write_byte(const struct bitbang_spi_master *master, uint8_t val)
+static void bitbang_spi_write_byte(const struct bitbang_spi_master *master, uint8_t val, void *spi_data)
{
int i;
for (i = 7; i >= 0; i--) {
- bitbang_spi_set_sck_set_mosi(master, 0, (val >> i) & 1);
- programmer_delay(master->half_period);
- bitbang_spi_set_sck(master, 1);
- programmer_delay(master->half_period);
+ bitbang_spi_set_sck_set_mosi(master, 0, (val >> i) & 1, spi_data);
+ default_delay(master->half_period);
+ bitbang_spi_set_sck(master, 1, spi_data);
+ default_delay(master->half_period);
}
}
struct bitbang_spi_master_data {
- const struct bitbang_spi_master *mst;
+ const struct bitbang_spi_master *master;
+ void *spi_data;
};
static int bitbang_spi_send_command(const struct flashctx *flash,
@@ -105,48 +108,47 @@ static int bitbang_spi_send_command(const struct flashctx *flash,
{
unsigned int i;
const struct bitbang_spi_master_data *data = flash->mst->spi.data;
- const struct bitbang_spi_master *master = data->mst;
+ const struct bitbang_spi_master *master = data->master;
/* FIXME: Run bitbang_spi_request_bus here or in programmer init?
* Requesting and releasing the SPI bus is handled in here to allow the
* programmer to use its own SPI engine for native accesses.
*/
- bitbang_spi_request_bus(master);
- bitbang_spi_set_cs(master, 0);
+ bitbang_spi_request_bus(master, data->spi_data);
+ bitbang_spi_set_cs(master, 0, data->spi_data);
for (i = 0; i < writecnt; i++)
- bitbang_spi_write_byte(master, writearr[i]);
+ bitbang_spi_write_byte(master, writearr[i], data->spi_data);
for (i = 0; i < readcnt; i++)
- readarr[i] = bitbang_spi_read_byte(master);
+ readarr[i] = bitbang_spi_read_byte(master, data->spi_data);
- bitbang_spi_set_sck(master, 0);
- programmer_delay(master->half_period);
- bitbang_spi_set_cs(master, 1);
- programmer_delay(master->half_period);
+ bitbang_spi_set_sck(master, 0, data->spi_data);
+ default_delay(master->half_period);
+ bitbang_spi_set_cs(master, 1, data->spi_data);
+ default_delay(master->half_period);
/* FIXME: Run bitbang_spi_release_bus here or in programmer init? */
- bitbang_spi_release_bus(master);
+ bitbang_spi_release_bus(master, data->spi_data);
return 0;
}
+static int bitbang_spi_shutdown(void *data)
+{
+ /* FIXME: Run bitbang_spi_release_bus here or per command? */
+ free(data);
+ return 0;
+}
+
static const struct spi_master spi_master_bitbang = {
.features = SPI_MASTER_4BA,
.max_data_read = MAX_DATA_READ_UNLIMITED,
.max_data_write = MAX_DATA_WRITE_UNLIMITED,
.command = bitbang_spi_send_command,
- .multicommand = default_spi_send_multicommand,
.read = default_spi_read,
.write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .shutdown = bitbang_spi_shutdown,
};
-static int bitbang_spi_shutdown(void *data)
-{
- /* FIXME: Run bitbang_spi_release_bus here or per command? */
- free(data);
- return 0;
-}
-
-int register_spi_bitbang_master(const struct bitbang_spi_master *master)
+int register_spi_bitbang_master(const struct bitbang_spi_master *master, void *spi_data)
{
struct spi_master mst = spi_master_bitbang;
/* If someone forgot to initialize a bitbang function, we catch it here. */
@@ -159,19 +161,23 @@ int register_spi_bitbang_master(const struct bitbang_spi_master *master)
return ERROR_FLASHROM_BUG;
}
- struct bitbang_spi_master_data *data = calloc(1, sizeof(struct bitbang_spi_master_data));
- data->mst = master;
- mst.data = data;
- register_spi_master(&mst);
- register_shutdown(bitbang_spi_shutdown, data);
+ struct bitbang_spi_master_data *data = calloc(1, sizeof(*data));
+ if (!data)
+ return ERROR_FLASHROM_FATAL;
+
+ data->master = master;
+ if (spi_data)
+ data->spi_data = spi_data;
+
+ register_spi_master(&mst, data);
/* Only mess with the bus if we're sure nobody else uses it. */
- bitbang_spi_request_bus(master);
- bitbang_spi_set_cs(master, 1);
- bitbang_spi_set_sck_set_mosi(master, 0, 0);
+ bitbang_spi_request_bus(master, spi_data);
+ bitbang_spi_set_cs(master, 1, spi_data);
+ bitbang_spi_set_sck_set_mosi(master, 0, 0, spi_data);
/* FIXME: Release SPI bus here and request it again for each command or
* don't release it now and only release it on programmer shutdown?
*/
- bitbang_spi_release_bus(master);
+ bitbang_spi_release_bus(master, spi_data);
return 0;
}
diff --git a/board_enable.c b/board_enable.c
index 9cf01031a..6e48a6263 100644
--- a/board_enable.c
+++ b/board_enable.c
@@ -22,12 +22,17 @@
#include <strings.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "platform/pci.h"
#if defined(__i386__) || defined(__x86_64__)
+
+#include "hwaccess_x86_io.h"
+#include "hwaccess_x86_msr.h"
+
/*
* Helper functions for many Winbond Super I/Os of the W836xx range.
*/
@@ -141,7 +146,7 @@ static int fdc37b787_gpio50_raise(uint16_t port)
* Suited for:
* - Nokia IP530: Intel 440BX + PIIX4 + FDC37B787
*/
-static int fdc37b787_gpio50_raise_3f0(void)
+static int fdc37b787_gpio50_raise_3f0(struct board_cfg *cfg)
{
return fdc37b787_gpio50_raise(0x3f0);
}
@@ -452,7 +457,7 @@ static int winbond_gpio_set(uint16_t base, enum winbond_id chipid,
* - Agami Aruma
* - IWILL DK8-HTX
*/
-static int w83627hf_gpio24_raise_2e(void)
+static int w83627hf_gpio24_raise_2e(struct board_cfg *cfg)
{
return winbond_gpio_set(0x2e, WINBOND_W83627HF_ID, 24, 1);
}
@@ -463,7 +468,7 @@ static int w83627hf_gpio24_raise_2e(void)
* Suited for:
* - MSI MS-6577
*/
-static int w83627hf_gpio25_raise_2e(void)
+static int w83627hf_gpio25_raise_2e(struct board_cfg *cfg)
{
return winbond_gpio_set(0x2e, WINBOND_W83627HF_ID, 25, 1);
}
@@ -474,7 +479,7 @@ static int w83627hf_gpio25_raise_2e(void)
* Suited for:
* - ASUS A8N-VM CSM: AMD Socket 939 + GeForce 6150 (C51) + MCP51
*/
-static int w83627ehf_gpio22_raise_2e(void)
+static int w83627ehf_gpio22_raise_2e(struct board_cfg *cfg)
{
return winbond_gpio_set(0x2e, WINBOND_W83627EHF_ID, 22, 1);
}
@@ -485,7 +490,7 @@ static int w83627ehf_gpio22_raise_2e(void)
* Suited for:
* - MSI K8T Neo2-F V2.0
*/
-static int w83627thf_gpio44_raise_2e(void)
+static int w83627thf_gpio44_raise_2e(struct board_cfg *cfg)
{
return winbond_gpio_set(0x2e, WINBOND_W83627THF_ID, 44, 1);
}
@@ -496,7 +501,7 @@ static int w83627thf_gpio44_raise_2e(void)
* Suited for:
* - MSI K8N Neo3
*/
-static int w83627thf_gpio44_raise_4e(void)
+static int w83627thf_gpio44_raise_4e(struct board_cfg *cfg)
{
return winbond_gpio_set(0x4e, WINBOND_W83627THF_ID, 44, 1);
}
@@ -552,7 +557,7 @@ static void w83697xx_memw_enable(uint16_t port)
* Suited for:
* - Biostar M7VIQ: VIA KM266 + VT8235
*/
-static int w83697xx_memw_enable_2e(void)
+static int w83697xx_memw_enable_2e(struct board_cfg *cfg)
{
w83697xx_memw_enable(0x2E);
@@ -574,7 +579,7 @@ static int w83697xx_memw_enable_2e(void)
* - ASRock K7S41: SiS 741 + SiS 963 + W83697HF
* - ASRock K7S41GX: SiS 741GX + SiS 963L + W83697HF
*/
-static int w836xx_memw_enable_2e(void)
+static int w836xx_memw_enable_2e(struct board_cfg *cfg)
{
w836xx_memw_enable(0x2E);
@@ -585,7 +590,7 @@ static int w836xx_memw_enable_2e(void)
* Suited for:
* - Termtek TK-3370 (rev. 2.5b)
*/
-static int w836xx_memw_enable_4e(void)
+static int w836xx_memw_enable_4e(struct board_cfg *cfg)
{
w836xx_memw_enable(0x4E);
@@ -667,7 +672,7 @@ int it8705f_write_enable(uint8_t port)
*/
ret = 1;
}
- msg_pdbg("Maximum IT8705F parallel flash decode size is %u.\n",
+ msg_pdbg("Maximum IT8705F parallel flash decode size is %"PRIu32".\n",
max_rom_decode.parallel);
if (ret) {
msg_pinfo("Not enabling IT8705F flash write.\n");
@@ -720,7 +725,7 @@ static int it8707f_write_enable(uint8_t port)
* Suited for:
* - ASUS P4SC-E: SiS 651 + 962 + ITE IT8707F
*/
-static int it8707f_write_enable_2e(void)
+static int it8707f_write_enable_2e(struct board_cfg *cfg)
{
return it8707f_write_enable(0x2e);
}
@@ -778,7 +783,7 @@ static int via_vt823x_gpio_set(uint8_t gpio, int raise)
uint16_t base;
uint8_t val, bit, offset;
- dev = pci_dev_find_vendorclass(0x1106, 0x0601);
+ dev = pcidev_find_vendorclass(0x1106, 0x0601);
switch (dev->device_id) {
case 0x3177: /* VT8235 */
case 0x3227: /* VT8237/VT8237R */
@@ -829,7 +834,7 @@ static int via_vt823x_gpio_set(uint8_t gpio, int raise)
* Suited for:
* - ASUS M2V-MX: VIA K8M890 + VT8237A + IT8716F
*/
-static int via_vt823x_gpio5_raise(void)
+static int via_vt823x_gpio5_raise(struct board_cfg *cfg)
{
/* On M2V-MX: GPO5 is connected to WP# and TBL#. */
return via_vt823x_gpio_set(5, 1);
@@ -839,7 +844,7 @@ static int via_vt823x_gpio5_raise(void)
* Suited for:
* - VIA EPIA EK & N & NL
*/
-static int via_vt823x_gpio9_raise(void)
+static int via_vt823x_gpio9_raise(struct board_cfg *cfg)
{
return via_vt823x_gpio_set(9, 1);
}
@@ -851,7 +856,7 @@ static int via_vt823x_gpio9_raise(void)
* We don't need to do this for EPIA M when using coreboot, GPIO15 is never
* lowered there.
*/
-static int via_vt823x_gpio15_raise(void)
+static int via_vt823x_gpio15_raise(struct board_cfg *cfg)
{
return via_vt823x_gpio_set(15, 1);
}
@@ -863,7 +868,7 @@ static int via_vt823x_gpio15_raise(void)
* - MSI KT4V and KT4V-L: AMD K7 + VIA KT400 + VT8235
* - MSI KT4 Ultra: AMD K7 + VIA KT400 + VT8235
*/
-static int board_msi_kt4v(void)
+static int board_msi_kt4v(struct board_cfg *cfg)
{
int ret;
@@ -880,7 +885,7 @@ static int board_msi_kt4v(void)
* We are talking to a proprietary device on SMBus: the AS99127F which does
* much more than the Winbond W83781D it tries to be compatible with.
*/
-static int board_asus_p3b_f(void)
+static int board_asus_p3b_f(struct board_cfg *cfg)
{
/*
* Find where the SMBus host is. ASUS sets it to 0xE800; coreboot sets it to 0x0F00.
@@ -889,7 +894,7 @@ static int board_asus_p3b_f(void)
uint16_t smbba;
uint8_t b;
- dev = pci_dev_find(0x8086, 0x7113); /* Intel PIIX4, PM/SMBus function. */
+ dev = pcidev_find(0x8086, 0x7113); /* Intel PIIX4, PM/SMBus function. */
if (!dev) {
msg_perr("\nERROR: Intel PIIX4 PM not found.\n");
return -1;
@@ -906,7 +911,7 @@ static int board_asus_p3b_f(void)
/* Wait until SMBus transaction is complete. */
b = 0x1;
while (b & 0x01) {
- b = INB(0x80);
+ INB(0x80);
b = INB(smbba);
}
@@ -927,7 +932,7 @@ static int board_asus_p3b_f(void)
* We're basically talking to some unknown device on SMBus, my guess
* is that it is the Winbond W83781D that lives near the DIP BIOS.
*/
-static int board_asus_p5a(void)
+static int board_asus_p5a(struct board_cfg *cfg)
{
uint8_t tmp;
int i;
@@ -1001,7 +1006,7 @@ static int board_asus_p5a(void)
*
* It's not a Super I/O but it uses the same index/data port method.
*/
-static int board_hp_dl145_g3_enable(void)
+static int board_hp_dl145_g3_enable(struct board_cfg *cfg)
{
/* GPIO 0 reg from PM regs */
/* Set GPIO 2 and 5 high, connected to flash WP# and TBL# pins. */
@@ -1015,7 +1020,7 @@ static int board_hp_dl145_g3_enable(void)
*
* It's not a Super I/O but it uses the same index/data port method.
*/
-static int board_hp_dl165_g6_enable(void)
+static int board_hp_dl165_g6_enable(struct board_cfg *cfg)
{
/* Variant of DL145, with slightly different pin placement. */
sio_mask(0xcd6, 0x44, 0x80, 0x80); /* TBL# */
@@ -1024,7 +1029,7 @@ static int board_hp_dl165_g6_enable(void)
return 0;
}
-static int board_ibm_x3455(void)
+static int board_ibm_x3455(struct board_cfg *cfg)
{
/* Raise GPIO13. */
sio_mask(0xcd6, 0x45, 0x20, 0x20);
@@ -1036,12 +1041,12 @@ static int board_ibm_x3455(void)
* Suited for:
* - Elitegroup GeForce6100SM-M: NVIDIA MCP61 + ITE IT8726F
*/
-static int board_ecs_geforce6100sm_m(void)
+static int board_ecs_geforce6100sm_m(struct board_cfg *cfg)
{
struct pci_dev *dev;
uint32_t tmp;
- dev = pci_dev_find(0x10DE, 0x03EB); /* NVIDIA MCP61 SMBus. */
+ dev = pcidev_find(0x10DE, 0x03EB); /* NVIDIA MCP61 SMBus. */
if (!dev) {
msg_perr("\nERROR: NVIDIA MCP61 SMBus not found.\n");
return -1;
@@ -1069,7 +1074,7 @@ static int nvidia_mcp_gpio_set(int gpio, int raise)
}
/* Check for the ISA bridge first. */
- dev = pci_dev_find_vendorclass(0x10DE, 0x0601);
+ dev = pcidev_find_vendorclass(0x10DE, 0x0601);
switch (dev->device_id) {
case 0x0030: /* CK804 */
case 0x0050: /* MCP04 */
@@ -1090,15 +1095,7 @@ static int nvidia_mcp_gpio_set(int gpio, int raise)
return -1;
}
-#if !defined(OLD_PCI_GET_DEV)
- dev = pci_get_dev(pacc, dev->domain, dev->bus, dev->dev, 1);
-#else
- /* pciutils/libpci before version 2.2 is too old to support
- * PCI domains. Such old machines usually don't have domains
- * besides domain 0, so this is not a problem.
- */
- dev = pci_get_dev(pacc, dev->bus, dev->dev, 1);
-#endif
+ dev = pcidev_getdevfn(dev, 1);
if (!dev) {
msg_perr("MCP SMBus controller could not be found\n");
return -1;
@@ -1134,7 +1131,7 @@ static int nvidia_mcp_gpio_set(int gpio, int raise)
* - ASUS A8N-LA (HP OEM "Nagami-GL8E"): NVIDIA MCP51
* - ASUS M2NBP-VM CSM: NVIDIA MCP51
*/
-static int nvidia_mcp_gpio0_raise(void)
+static int nvidia_mcp_gpio0_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x00, 1);
}
@@ -1144,7 +1141,7 @@ static int nvidia_mcp_gpio0_raise(void)
* - abit KN8 Ultra: NVIDIA CK804
* - abit KN9 Ultra: NVIDIA MCP55
*/
-static int nvidia_mcp_gpio2_lower(void)
+static int nvidia_mcp_gpio2_lower(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x02, 0);
}
@@ -1156,7 +1153,7 @@ static int nvidia_mcp_gpio2_lower(void)
* - MSI K8NGM2-L: NVIDIA MCP51
* - MSI K9N SLI: NVIDIA MCP55
*/
-static int nvidia_mcp_gpio2_raise(void)
+static int nvidia_mcp_gpio2_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x02, 1);
}
@@ -1165,7 +1162,7 @@ static int nvidia_mcp_gpio2_raise(void)
* Suited for:
* - EPoX EP-8NPA7I: Socket 754 + NVIDIA nForce4 4X
*/
-static int nvidia_mcp_gpio4_raise(void)
+static int nvidia_mcp_gpio4_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x04, 1);
}
@@ -1182,7 +1179,7 @@ static int nvidia_mcp_gpio4_raise(void)
* b) #TBL is hardwired on that board to a pull-down. It can be
* overridden by connecting the two solder points next to F2.
*/
-static int nvidia_mcp_gpio5_raise(void)
+static int nvidia_mcp_gpio5_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x05, 1);
}
@@ -1191,7 +1188,7 @@ static int nvidia_mcp_gpio5_raise(void)
* Suited for:
* - abit NF7-S: NVIDIA CK804
*/
-static int nvidia_mcp_gpio8_raise(void)
+static int nvidia_mcp_gpio8_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x08, 1);
}
@@ -1201,7 +1198,7 @@ static int nvidia_mcp_gpio8_raise(void)
* - GIGABYTE GA-K8NS Pro-939: Socket 939 + NVIDIA nForce3 + CK8
* - Probably other versions of the GA-K8NS
*/
-static int nvidia_mcp_gpio0a_raise(void)
+static int nvidia_mcp_gpio0a_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x0a, 1);
}
@@ -1211,7 +1208,7 @@ static int nvidia_mcp_gpio0a_raise(void)
* - MSI K8N Neo Platinum: Socket 754 + nForce3 Ultra + CK8
* - MSI K8N Neo2 Platinum: Socket 939 + nForce3 Ultra + CK8
*/
-static int nvidia_mcp_gpio0c_raise(void)
+static int nvidia_mcp_gpio0c_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x0c, 1);
}
@@ -1220,7 +1217,7 @@ static int nvidia_mcp_gpio0c_raise(void)
* Suited for:
* - abit NF-M2 nView: Socket AM2 + NVIDIA MCP51
*/
-static int nvidia_mcp_gpio4_lower(void)
+static int nvidia_mcp_gpio4_lower(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x04, 0);
}
@@ -1229,7 +1226,7 @@ static int nvidia_mcp_gpio4_lower(void)
* Suited for:
* - ASUS P5ND2-SLI Deluxe: LGA775 + nForce4 SLI + MCP04
*/
-static int nvidia_mcp_gpio10_raise(void)
+static int nvidia_mcp_gpio10_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x10, 1);
}
@@ -1238,7 +1235,7 @@ static int nvidia_mcp_gpio10_raise(void)
* Suited for:
* - GIGABYTE GA-K8N-SLI: AMD socket 939 + NVIDIA CK804 + ITE IT8712F
*/
-static int nvidia_mcp_gpio21_raise(void)
+static int nvidia_mcp_gpio21_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x21, 0x01);
}
@@ -1247,7 +1244,7 @@ static int nvidia_mcp_gpio21_raise(void)
* Suited for:
* - EPoX EP-8RDA3+: Socket A + nForce2 Ultra 400 + MCP2
*/
-static int nvidia_mcp_gpio31_raise(void)
+static int nvidia_mcp_gpio31_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x31, 0x01);
}
@@ -1257,7 +1254,7 @@ static int nvidia_mcp_gpio31_raise(void)
* - GIGABYTE GA-K8N51GMF: Socket 754 + Geforce 6100 + MCP51
* - GIGABYTE GA-K8N51GMF-9: Socket 939 + Geforce 6100 + MCP51
*/
-static int nvidia_mcp_gpio3b_raise(void)
+static int nvidia_mcp_gpio3b_raise(struct board_cfg *cfg)
{
return nvidia_mcp_gpio_set(0x3b, 1);
}
@@ -1266,18 +1263,18 @@ static int nvidia_mcp_gpio3b_raise(void)
* Suited for:
* - Sun Ultra 40 M2: Dual Socket F (1207) + MCP55
*/
-static int board_sun_ultra_40_m2(void)
+static int board_sun_ultra_40_m2(struct board_cfg *cfg)
{
int ret;
uint8_t reg;
uint16_t base;
struct pci_dev *dev;
- ret = nvidia_mcp_gpio4_lower();
+ ret = nvidia_mcp_gpio4_lower(cfg);
if (ret)
return ret;
- dev = pci_dev_find(0x10de, 0x0364); /* NVIDIA MCP55 LPC bridge */
+ dev = pcidev_find(0x10de, 0x0364); /* NVIDIA MCP55 LPC bridge */
if (!dev) {
msg_perr("\nERROR: NVIDIA MCP55 LPC bridge not found.\n");
return -1;
@@ -1298,7 +1295,7 @@ static int board_sun_ultra_40_m2(void)
* Suited for:
* - Artec Group DBE61 and DBE62
*/
-static int board_artecgroup_dbe6x(void)
+static int board_artecgroup_dbe6x(struct board_cfg *cfg)
{
#define DBE6x_MSR_DIVIL_BALL_OPTS 0x51400015
#define DBE6x_PRI_BOOT_LOC_SHIFT 2
@@ -1314,10 +1311,10 @@ static int board_artecgroup_dbe6x(void)
unsigned long boot_loc;
/* Geode only has a single core */
- if (setup_cpu_msr(0))
+ if (msr_setup(0))
return -1;
- msr = rdmsr(DBE6x_MSR_DIVIL_BALL_OPTS);
+ msr = msr_read(DBE6x_MSR_DIVIL_BALL_OPTS);
if ((msr.lo & (DBE6x_BOOT_OP_LATCHED)) ==
(DBE6x_BOOT_LOC_FWHUB << DBE6x_BOOT_OP_LATCHED_SHIFT))
@@ -1329,9 +1326,9 @@ static int board_artecgroup_dbe6x(void)
msr.lo |= ((boot_loc << DBE6x_PRI_BOOT_LOC_SHIFT) |
(boot_loc << DBE6x_SEC_BOOT_LOC_SHIFT));
- wrmsr(DBE6x_MSR_DIVIL_BALL_OPTS, msr);
+ msr_write(DBE6x_MSR_DIVIL_BALL_OPTS, msr);
- cleanup_cpu_msr();
+ msr_cleanup();
return 0;
}
@@ -1342,12 +1339,12 @@ static int board_artecgroup_dbe6x(void)
* Datasheet(s) used:
* - AMD document 43009 "AMD SB700/710/750 Register Reference Guide" rev. 1.00
*/
-static int amd_sbxxx_gpio9_raise(void)
+static int amd_sbxxx_gpio9_raise(struct board_cfg *cfg)
{
struct pci_dev *dev;
uint32_t reg;
- dev = pci_dev_find(0x1002, 0x4372); /* AMD SMBus controller */
+ dev = pcidev_find(0x1002, 0x4372); /* AMD SMBus controller */
if (!dev) {
msg_perr("\nERROR: AMD SMBus Controller (0x4372) not found.\n");
return -1;
@@ -1411,7 +1408,7 @@ static int intel_piix4_gpo_set(unsigned int gpo, int raise)
{0}
};
- dev = pci_dev_find(0x8086, 0x7110); /* Intel PIIX4 ISA bridge */
+ dev = pcidev_find(0x8086, 0x7110); /* Intel PIIX4 ISA bridge */
if (!dev) {
msg_perr("\nERROR: Intel PIIX4 ISA bridge not found.\n");
return -1;
@@ -1430,7 +1427,7 @@ static int intel_piix4_gpo_set(unsigned int gpo, int raise)
return -1;
}
- dev = pci_dev_find(0x8086, 0x7113); /* Intel PIIX4 PM */
+ dev = pcidev_find(0x8086, 0x7113); /* Intel PIIX4 PM */
if (!dev) {
msg_perr("\nERROR: Intel PIIX4 PM not found.\n");
return -1;
@@ -1456,7 +1453,7 @@ static int intel_piix4_gpo_set(unsigned int gpo, int raise)
* - ASUS OPLX-M
* - ASUS P2B-N
*/
-static int intel_piix4_gpo18_lower(void)
+static int intel_piix4_gpo18_lower(struct board_cfg *cfg)
{
return intel_piix4_gpo_set(18, 0);
}
@@ -1465,7 +1462,7 @@ static int intel_piix4_gpo18_lower(void)
* Suited for:
* - MSI MS-6163 v2 (MS-6163 Pro): Intel 440BX + PIIX4E + Winbond W83977EF
*/
-static int intel_piix4_gpo14_raise(void)
+static int intel_piix4_gpo14_raise(struct board_cfg *cfg)
{
return intel_piix4_gpo_set(14, 1);
}
@@ -1474,7 +1471,7 @@ static int intel_piix4_gpo14_raise(void)
* Suited for:
* - EPoX EP-BX3
*/
-static int intel_piix4_gpo22_raise(void)
+static int intel_piix4_gpo22_raise(struct board_cfg *cfg)
{
return intel_piix4_gpo_set(22, 1);
}
@@ -1483,7 +1480,7 @@ static int intel_piix4_gpo22_raise(void)
* Suited for:
* - abit BM6
*/
-static int intel_piix4_gpo26_lower(void)
+static int intel_piix4_gpo26_lower(struct board_cfg *cfg)
{
return intel_piix4_gpo_set(26, 0);
}
@@ -1492,7 +1489,7 @@ static int intel_piix4_gpo26_lower(void)
* Suited for:
* - Intel SE440BX-2
*/
-static int intel_piix4_gpo27_lower(void)
+static int intel_piix4_gpo27_lower(struct board_cfg *cfg)
{
return intel_piix4_gpo_set(27, 0);
}
@@ -1501,7 +1498,7 @@ static int intel_piix4_gpo27_lower(void)
* Suited for:
* - Dell OptiPlex GX1
*/
-static int intel_piix4_gpo30_lower(void)
+static int intel_piix4_gpo30_lower(struct board_cfg *cfg)
{
return intel_piix4_gpo_set(30, 0);
}
@@ -1559,23 +1556,17 @@ static int intel_ich_gpio_set(int gpio, int raise)
int i, allowed;
/* First, look for a known LPC bridge */
- for (dev = pacc->devices; dev; dev = dev->next) {
- uint16_t device_class;
- /* libpci before version 2.2.4 does not store class info. */
- device_class = pci_read_word(dev, PCI_CLASS_DEVICE);
- if ((dev->vendor_id == 0x8086) &&
- (device_class == 0x0601)) { /* ISA bridge */
- /* Is this device in our list? */
- for (i = 0; intel_ich_gpio_table[i].id; i++)
- if (dev->device_id == intel_ich_gpio_table[i].id)
- break;
-
- if (intel_ich_gpio_table[i].id)
- break;
- }
+ dev = pcidev_find_vendorclass(0x8086, 0x0601); /* ISA bridge */
+ if (!dev) {
+ msg_perr("\nERROR: No known Intel LPC bridge found.\n");
+ return -1;
}
+ /* Is this device in our list? */
+ for (i = 0; intel_ich_gpio_table[i].id; i++)
+ if (dev->device_id == intel_ich_gpio_table[i].id)
+ break;
- if (!dev) {
+ if (!intel_ich_gpio_table[i].id) {
msg_perr("\nERROR: No known Intel LPC bridge found.\n");
return -1;
}
@@ -1711,8 +1702,9 @@ static int intel_ich_gpio_set(int gpio, int raise)
* - ASUS P5LD2-MQ
* - ASUS P5LD2-VM
* - ASUS P5LD2-VM DH
+ * - ASUS P5W DH Deluxe
*/
-static int intel_ich_gpio16_raise(void)
+static int intel_ich_gpio16_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(16, 1);
}
@@ -1721,7 +1713,7 @@ static int intel_ich_gpio16_raise(void)
* Suited for:
* - HP Puffer2-UL8E (ASUS PTGD-LA OEM): LGA775 + 915 + ICH6
*/
-static int intel_ich_gpio18_raise(void)
+static int intel_ich_gpio18_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(18, 1);
}
@@ -1730,7 +1722,7 @@ static int intel_ich_gpio18_raise(void)
* Suited for:
* - MSI MS-7046: LGA775 + 915P + ICH6
*/
-static int intel_ich_gpio19_raise(void)
+static int intel_ich_gpio19_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(19, 1);
}
@@ -1740,7 +1732,7 @@ static int intel_ich_gpio19_raise(void)
* - ASUS P5BV-R: LGA775 + 3200 + ICH7
* - AOpen i965GMt-LA: Intel Socket479 + 965GM + ICH8M
*/
-static int intel_ich_gpio20_raise(void)
+static int intel_ich_gpio20_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(20, 1);
}
@@ -1762,7 +1754,7 @@ static int intel_ich_gpio20_raise(void)
* - ASUS TUSL2-C: Intel socket370 + 815 + ICH2
* - Samsung Polaris 32: socket478 + 865P + ICH5
*/
-static int intel_ich_gpio21_raise(void)
+static int intel_ich_gpio21_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(21, 1);
}
@@ -1774,7 +1766,7 @@ static int intel_ich_gpio21_raise(void)
* - ASUS P4B-MX variant in HP Vectra VL420 SFF: socket478 + 845D + ICH2
* - TriGem Anaheim-3: socket370 + Intel 810 + ICH
*/
-static int intel_ich_gpio22_raise(void)
+static int intel_ich_gpio22_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(22, 1);
}
@@ -1786,7 +1778,7 @@ static int intel_ich_gpio22_raise(void)
* - HP Media Center m7270.fr Desktop PC as "Lithium-UL8E"
* - Epson Endeavor MT7700
*/
-static int intel_ich_gpio34_raise(void)
+static int intel_ich_gpio34_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(34, 1);
}
@@ -1796,7 +1788,7 @@ static int intel_ich_gpio34_raise(void)
* - AOpen i945GMx-VFX: Intel 945GM + ICH7-M used in ...
* - FSC ESPRIMO Q5010 (SMBIOS: D2544-B1)
*/
-static int intel_ich_gpio38_raise(void)
+static int intel_ich_gpio38_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(38, 1);
}
@@ -1805,7 +1797,7 @@ static int intel_ich_gpio38_raise(void)
* Suited for:
* - ASUS M6Ne (laptop): socket 479M (guessed) + Intel 855PM + ICH4-M
*/
-static int intel_ich_gpio43_raise(void)
+static int intel_ich_gpio43_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(43, 1);
}
@@ -1814,7 +1806,7 @@ static int intel_ich_gpio43_raise(void)
* Suited for:
* - HP Vectra VL400: 815 + ICH + PC87360
*/
-static int board_hp_vl400(void)
+static int board_hp_vl400(struct board_cfg *cfg)
{
int ret;
ret = intel_ich_gpio_set(25, 1); /* Master write enable ? */
@@ -1829,7 +1821,7 @@ static int board_hp_vl400(void)
* Suited for:
* - HP e-Vectra P2706T: 810E + ICH + PC87364
*/
-static int board_hp_p2706t(void)
+static int board_hp_p2706t(struct board_cfg *cfg)
{
int ret;
ret = pc8736x_gpio_set(PC87364_ID, 0x25, 1);
@@ -1845,7 +1837,7 @@ static int board_hp_p2706t(void)
* - ASRock 775i65G: Intel LGA 775 + 865G + ICH5
* - MSI MS-6391 (845 Pro4): Intel Socket478 + 845 + ICH2
*/
-static int intel_ich_gpio23_raise(void)
+static int intel_ich_gpio23_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(23, 1);
}
@@ -1855,7 +1847,7 @@ static int intel_ich_gpio23_raise(void)
* - GIGABYTE GA-6IEM: Intel Socket370 + i815 + ICH2
* - GIGABYTE GA-8IRML: Intel Socket478 + i845 + ICH2
*/
-static int intel_ich_gpio25_raise(void)
+static int intel_ich_gpio25_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(25, 1);
}
@@ -1864,7 +1856,7 @@ static int intel_ich_gpio25_raise(void)
* Suited for:
* - IBASE MB899: i945GM + ICH7
*/
-static int intel_ich_gpio26_raise(void)
+static int intel_ich_gpio26_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(26, 1);
}
@@ -1877,7 +1869,7 @@ static int intel_ich_gpio26_raise(void)
* - GIGABYTE GA-8PE667 Ultra 2: socket 478 + i845PE + ICH4
* - MSI MS-6788-40 (aka 848P Neo-V)
*/
-static int intel_ich_gpio32_raise(void)
+static int intel_ich_gpio32_raise(struct board_cfg *cfg)
{
return intel_ich_gpio_set(32, 1);
}
@@ -1886,7 +1878,7 @@ static int intel_ich_gpio32_raise(void)
* Suited for:
* - AOpen i975Xa-YDG: i975X + ICH7 + W83627EHF
*/
-static int board_aopen_i975xa_ydg(void)
+static int board_aopen_i975xa_ydg(struct board_cfg *cfg)
{
int ret;
@@ -1908,7 +1900,7 @@ static int board_aopen_i975xa_ydg(void)
* Suited for:
* - Acorp 6A815EPD: socket 370 + intel 815 + ICH2
*/
-static int board_acorp_6a815epd(void)
+static int board_acorp_6a815epd(struct board_cfg *cfg)
{
int ret;
@@ -1924,7 +1916,7 @@ static int board_acorp_6a815epd(void)
* Suited for:
* - Kontron 986LCD-M: Socket478 + 915GM + ICH7R
*/
-static int board_kontron_986lcd_m(void)
+static int board_kontron_986lcd_m(struct board_cfg *cfg)
{
int ret;
@@ -1945,7 +1937,7 @@ static int via_apollo_gpo_set(int gpio, int raise)
uint32_t base, tmp;
/* VT82C686 power management */
- dev = pci_dev_find(0x1106, 0x3057);
+ dev = pcidev_find(0x1106, 0x3057);
if (!dev) {
msg_perr("\nERROR: VT82C686 PM device not found.\n");
return -1;
@@ -1991,7 +1983,7 @@ static int via_apollo_gpo_set(int gpio, int raise)
* - abit VT6X4: Pro133x + VT82C686A
* - abit VA6: Pro133x + VT82C686A
*/
-static int via_apollo_gpo4_lower(void)
+static int via_apollo_gpo4_lower(struct board_cfg *cfg)
{
return via_apollo_gpo_set(4, 0);
}
@@ -2000,7 +1992,7 @@ static int via_apollo_gpo4_lower(void)
* Suited for:
* - Soyo SY-7VCA: Pro133A + VT82C686
*/
-static int via_apollo_gpo0_lower(void)
+static int via_apollo_gpo0_lower(struct board_cfg *cfg)
{
return via_apollo_gpo_set(0, 0);
}
@@ -2013,12 +2005,12 @@ static int via_apollo_gpo0_lower(void)
* - GIGABYTE GA-8SIMLFS 2.0
* - GIGABYTE GA-8SIMLH
*/
-static int sis_gpio0_raise_and_w836xx_memw(void)
+static int sis_gpio0_raise_and_w836xx_memw(struct board_cfg *cfg)
{
struct pci_dev *dev;
uint16_t base, temp;
- dev = pci_dev_find(0x1039, 0x0962);
+ dev = pcidev_find(0x1039, 0x0962);
if (!dev) {
msg_perr("Expected south bridge not found\n");
return 1;
@@ -2076,13 +2068,13 @@ out:
* Disable write protection on the Mitac 6513WU. WP# on the FWH is
* connected to GP30 on the Super I/O, and TBL# is always high.
*/
-static int board_mitac_6513wu(void)
+static int board_mitac_6513wu(struct board_cfg *cfg)
{
struct pci_dev *dev;
uint16_t rt_port;
uint8_t val;
- dev = pci_dev_find(0x8086, 0x2410); /* Intel 82801AA ISA bridge */
+ dev = pcidev_find(0x8086, 0x2410); /* Intel 82801AA ISA bridge */
if (!dev) {
msg_perr("\nERROR: Intel 82801AA ISA bridge not found.\n");
return -1;
@@ -2109,7 +2101,7 @@ static int board_mitac_6513wu(void)
* Suited for:
* - abit AV8: Socket939 + K8T800Pro + VT8237
*/
-static int board_abit_av8(void)
+static int board_abit_av8(struct board_cfg *cfg)
{
uint8_t val;
@@ -2126,7 +2118,7 @@ static int board_abit_av8(void)
* - ASUS A7V333: VIA KT333 + VT8233A + IT8703F
* - ASUS A7V8X: VIA KT400 + VT8235 + IT8703F
*/
-static int it8703f_gpio51_raise(void)
+static int it8703f_gpio51_raise(struct board_cfg *cfg)
{
uint16_t id, base;
uint8_t tmp;
@@ -2255,7 +2247,7 @@ found:
* Suited for:
* - ASUS A7N8X-VM/400: NVIDIA nForce2 IGP2 + IT8712F
*/
-static int it8712f_gpio12_raise(void)
+static int it8712f_gpio12_raise(struct board_cfg *cfg)
{
return it87_gpio_set(12, 1);
}
@@ -2265,7 +2257,7 @@ static int it8712f_gpio12_raise(void)
* - ASUS A7V600-X: VIA KT600 + VT8237 + IT8712F
* - ASUS A7V8X-X: VIA KT400 + VT8235 + IT8712F
*/
-static int it8712f_gpio31_raise(void)
+static int it8712f_gpio31_raise(struct board_cfg *cfg)
{
return it87_gpio_set(32, 1);
}
@@ -2275,7 +2267,7 @@ static int it8712f_gpio31_raise(void)
* - ASUS P5N-D: NVIDIA MCP51 + IT8718F
* - ASUS P5N-E SLI: NVIDIA MCP51 + IT8718F
*/
-static int it8718f_gpio63_raise(void)
+static int it8718f_gpio63_raise(struct board_cfg *cfg)
{
return it87_gpio_set(63, 1);
}
@@ -2287,10 +2279,10 @@ static int it8718f_gpio63_raise(void)
* - Intel D945GCNL
* - MSC Q7 Tunnel Creek Module (Q7-TCTC)
*/
-static int p2_not_a_laptop(void)
+static int p2_not_a_laptop(struct board_cfg *cfg)
{
/* label this board as not a laptop */
- is_laptop = 0;
+ cfg->is_laptop = 0;
msg_pdbg("Laptop detection overridden by P2 board enable.\n");
return 0;
}
@@ -2298,10 +2290,10 @@ static int p2_not_a_laptop(void)
/*
* Suited for all laptops, which are known to *not* have interfering embedded controllers.
*/
-static int p2_whitelist_laptop(void)
+static int p2_whitelist_laptop(struct board_cfg *cfg)
{
- is_laptop = 1;
- laptop_ok = 1;
+ cfg->is_laptop = 1;
+ cfg->laptop_ok = true;
msg_pdbg("Whitelisted laptop detected.\n");
return 0;
}
@@ -2435,6 +2427,7 @@ const struct board_match board_matches[] = {
{0x10DE, 0x0260, 0x1043, 0x81BC, 0x10DE, 0x026C, 0x1043, 0x829E, "^P5N-D$", NULL, NULL, P3, "ASUS", "P5N-D", 0, OK, it8718f_gpio63_raise},
{0x10DE, 0x0260, 0x1043, 0x81BC, 0x10DE, 0x026C, 0x1043, 0x8249, "^P5N-E SLI$",NULL, NULL, P3, "ASUS", "P5N-E SLI", 0, NT, it8718f_gpio63_raise},
{0x8086, 0x24dd, 0x1043, 0x80a6, 0x8086, 0x2570, 0x1043, 0x8157, NULL, NULL, NULL, P3, "ASUS", "P5PE-VM", 0, OK, intel_ich_gpio21_raise},
+ {0x8086, 0x27da, 0x1043, 0x8179, 0x8086, 0x27b8, 0x1043, 0x8179, "^P5W DH Deluxe$", NULL, NULL, P3, "ASUS", "P5W DH Deluxe", 0, OK, intel_ich_gpio16_raise},
{0x8086, 0x2443, 0x1043, 0x8027, 0x8086, 0x1130, 0x1043, 0x8027, "^CUSL2-C", NULL, NULL, P3, "ASUS", "CUSL2-C", 0, OK, intel_ich_gpio21_raise},
{0x8086, 0x2443, 0x1043, 0x8027, 0x8086, 0x1130, 0x1043, 0x8027, "^TUSL2-C", NULL, NULL, P3, "ASUS", "TUSL2-C", 0, NT, intel_ich_gpio21_raise},
{0x1022, 0x780E, 0x1043, 0x1437, 0x1022, 0x780B, 0x1043, 0x1437, "^U38N$", NULL, NULL, P2, "ASUS", "U38N", 0, OK, p2_whitelist_laptop},
@@ -2478,6 +2471,7 @@ const struct board_match board_matches[] = {
{0x8086, 0x27b8, 0x8086, 0xd606, 0x8086, 0x2770, 0x8086, 0xd606, "^D945GCNL$", NULL, NULL, P2, "Intel", "D945GCNL", 0, OK, p2_not_a_laptop},
{0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, "^SE440BX-2$", NULL, NULL, P3, "Intel", "SE440BX-2", 0, NT, intel_piix4_gpo27_lower},
{0x1022, 0x7468, 0, 0, 0x1022, 0x7460, 0, 0, NULL, "iwill", "dk8_htx", P3, "IWILL", "DK8-HTX", 0, OK, w83627hf_gpio24_raise_2e},
+ {0x5333, 0x8d04, 0x1106, 0x3065, 0x1106, 0x3059, 0x1106, 0x0571, "P4M266-8235", NULL, NULL, P3, "Jetway", "P4MDPT", 0, OK, w836xx_memw_enable_2e},
{0x8086, 0x27A0, 0x8086, 0x27a0, 0x8086, 0x27b8, 0x8086, 0x27b8, NULL, "kontron", "986lcd-m", P3, "Kontron", "986LCD-M", 0, OK, board_kontron_986lcd_m},
{0x8086, 0x2917, 0x17AA, 0x20F5, 0x8086, 0x2930, 0x17AA, 0x20F9, "^ThinkPad R400", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad R400", 0, OK, p2_whitelist_laptop},
{0x8086, 0x2917, 0x17AA, 0x20F5, 0x8086, 0x2930, 0x17AA, 0x20F9, "^ThinkPad T400", NULL, NULL, P2, "IBM/Lenovo", "ThinkPad T400", 0, OK, p2_whitelist_laptop},
@@ -2530,6 +2524,7 @@ const struct board_match board_matches[] = {
#endif
{ 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, P3, NULL, NULL, 0, NT, NULL}, /* end marker */
};
+const size_t board_matches_size = ARRAY_SIZE(board_matches);
int selfcheck_board_enables(void)
{
@@ -2607,13 +2602,13 @@ static const struct board_match *board_match_name(const char *vendor, const char
if (!cur_model || strcasecmp(cur_model, model))
continue;
- if (!pci_dev_find(board->first_vendor, board->first_device)) {
+ if (!pcidev_find(board->first_vendor, board->first_device)) {
msg_pdbg("Odd. Board name \"%s\":\"%s\" matches, but first PCI device %04x:%04x "
"doesn't.\n", vendor, model, board->first_vendor, board->first_device);
continue;
}
- if (!pci_dev_find(board->second_vendor, board->second_device)) {
+ if (!pcidev_find(board->second_vendor, board->second_device)) {
msg_pdbg("Odd. Board name \"%s\":\"%s\" matches, but second PCI device %04x:%04x "
"doesn't.\n", vendor, model, board->second_vendor, board->second_device);
continue;
@@ -2649,20 +2644,20 @@ static const struct board_match *board_match_pci_ids(enum board_match_phase phas
if (board->phase != phase)
continue;
- if (!pci_card_find(board->first_vendor, board->first_device,
- board->first_card_vendor,
- board->first_card_device))
+ if (!pcidev_card_find(board->first_vendor, board->first_device,
+ board->first_card_vendor,
+ board->first_card_device))
continue;
if (board->second_vendor) {
if (board->second_card_vendor) {
- if (!pci_card_find(board->second_vendor,
- board->second_device,
- board->second_card_vendor,
- board->second_card_device))
+ if (!pcidev_card_find(board->second_vendor,
+ board->second_device,
+ board->second_card_vendor,
+ board->second_card_device))
continue;
} else {
- if (!pci_dev_find(board->second_vendor,
+ if (!pcidev_find(board->second_vendor,
board->second_device))
continue;
}
@@ -2670,7 +2665,7 @@ static const struct board_match *board_match_pci_ids(enum board_match_phase phas
#if defined(__i386__) || defined(__x86_64__)
if (board->dmi_pattern) {
- if (!has_dmi_support) {
+ if (!dmi_is_supported()) {
msg_pwarn("Warning: Can't autodetect %s %s, DMI info unavailable.\n",
board->vendor_name, board->board_name);
msg_pinfo("Please supply the board vendor and model name with the "
@@ -2688,7 +2683,7 @@ static const struct board_match *board_match_pci_ids(enum board_match_phase phas
return NULL;
}
-static int board_enable_safetycheck(const struct board_match *board)
+static int board_enable_safetycheck(const struct board_match *board, bool force_boardenable)
{
if (!board)
return 1;
@@ -2710,16 +2705,12 @@ static int board_enable_safetycheck(const struct board_match *board)
}
/* FIXME: Should this be identical to board_flash_enable? */
-static int board_handle_phase(enum board_match_phase phase)
+static int board_handle_phase(struct board_cfg *cfg,
+ enum board_match_phase phase, bool force_boardenable)
{
- const struct board_match *board = NULL;
-
- board = board_match_pci_ids(phase);
-
- if (!board)
- return 0;
+ const struct board_match *board = board_match_pci_ids(phase);
- if (board_enable_safetycheck(board))
+ if (board_enable_safetycheck(board, force_boardenable))
return 0;
if (!board->enable) {
@@ -2728,25 +2719,27 @@ static int board_handle_phase(enum board_match_phase phase)
return 0;
}
- return board->enable();
+ return board->enable(cfg);
}
-void board_handle_before_superio(void)
+void board_handle_before_superio(struct board_cfg *cfg, bool force_boardenable)
{
- board_handle_phase(P1);
+ board_handle_phase(cfg, P1, force_boardenable);
}
-void board_handle_before_laptop(void)
+void board_handle_before_laptop(struct board_cfg *cfg, bool force_boardenable)
{
- board_handle_phase(P2);
+ board_handle_phase(cfg, P2, force_boardenable);
}
-int board_flash_enable(const char *vendor, const char *model, const char *cb_vendor, const char *cb_model)
+int board_flash_enable(struct board_cfg *cfg,
+ const char *vendor, const char *model, const char *cb_vendor, const char *cb_model,
+ bool force_boardenable)
{
const struct board_match *board = NULL;
int ret = 0;
- if (vendor != NULL && model != NULL) {
+ if (vendor && model) {
board = board_match_name(vendor, model, false);
if (!board) { /* If a board was given by the user it has to match, else we abort here. */
msg_perr("No suitable board enable found for vendor=\"%s\", model=\"%s\".\n",
@@ -2754,31 +2747,31 @@ int board_flash_enable(const char *vendor, const char *model, const char *cb_ven
return 1;
}
}
- if (board == NULL && cb_vendor != NULL && cb_model != NULL) {
+ if (!board && cb_vendor && cb_model) {
board = board_match_name(cb_vendor, cb_model, true);
if (!board) { /* Failure is an option here, because many cb boards don't require an enable. */
msg_pdbg2("No board enable found matching coreboot IDs vendor=\"%s\", model=\"%s\".\n",
cb_vendor, cb_model);
}
}
- if (board == NULL) {
+ if (!board) {
board = board_match_pci_ids(P3);
if (!board) /* i.e. there is just no board enable available for this board */
return 0;
}
- if (board_enable_safetycheck(board))
+ if (board_enable_safetycheck(board, force_boardenable))
return 1;
/* limit the maximum size of the parallel bus */
if (board->max_rom_decode_parallel)
max_rom_decode.parallel = board->max_rom_decode_parallel * 1024;
- if (board->enable != NULL) {
+ if (board->enable) {
msg_pinfo("Enabling full flash access for board \"%s %s\"... ",
board->vendor_name, board->board_name);
- ret = board->enable();
+ ret = board->enable(cfg);
if (ret)
msg_pinfo("FAILED!\n");
else
diff --git a/buspirate_spi.c b/buspirate_spi.c
index fdfc0e456..72c28b0ad 100644
--- a/buspirate_spi.c
+++ b/buspirate_spi.c
@@ -16,6 +16,7 @@
#include <stdio.h>
#include <strings.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
@@ -50,26 +51,28 @@ static int buspirate_serialport_setup(char *dev)
#define sp_flush_incoming(...) 0
#endif
-static unsigned char *bp_commbuf = NULL;
-static int bp_commbufsize = 0;
+struct bp_spi_data {
+ unsigned char *commbuf;
+ int commbufsize;
+};
-static int buspirate_commbuf_grow(int bufsize)
+static int buspirate_commbuf_grow(int bufsize, unsigned char **bp_commbuf, int *bp_commbufsize)
{
unsigned char *tmpbuf;
/* Never shrink. realloc() calls are expensive. */
- if (bufsize <= bp_commbufsize)
+ if (bufsize <= *bp_commbufsize)
return 0;
- tmpbuf = realloc(bp_commbuf, bufsize);
+ tmpbuf = realloc(*bp_commbuf, bufsize);
if (!tmpbuf) {
/* Keep the existing buffer because memory is already tight. */
msg_perr("Out of memory!\n");
return ERROR_OOM;
}
- bp_commbuf = tmpbuf;
- bp_commbufsize = bufsize;
+ *bp_commbuf = tmpbuf;
+ *bp_commbufsize = bufsize;
return 0;
}
@@ -128,20 +131,56 @@ static int buspirate_wait_for_string(unsigned char *buf, const char *key)
return ret;
}
-static int buspirate_spi_send_command_v1(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr);
-static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr);
+static int buspirate_spi_shutdown(void *data)
+{
+ struct bp_spi_data *bp_data = data;
+ unsigned char *const bp_commbuf = bp_data->commbuf;
+ int ret = 0, ret2 = 0;
+ /* No need to allocate a buffer here, we know that bp_commbuf is at least DEFAULT_BUFSIZE big. */
+
+ /* Exit raw SPI mode (enter raw bitbang mode) */
+ bp_commbuf[0] = 0x00;
+ if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
+ goto out_shutdown;
+ if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
+ goto out_shutdown;
+ if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
+ goto out_shutdown;
+ msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[0]);
+ if (bp_commbuf[0] != '1') {
+ msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[0]);
+ ret = 1;
+ goto out_shutdown;
+ }
+ /* Reset Bus Pirate (return to user terminal) */
+ bp_commbuf[0] = 0x0f;
+ ret = buspirate_sendrecv(bp_commbuf, 1, 0);
+
+out_shutdown:
+ /* Shut down serial port communication */
+ ret2 = serialport_shutdown(NULL);
+ /* Keep the oldest error, it is probably the best indicator. */
+ if (ret2 && !ret)
+ ret = ret2;
+
+ free(bp_commbuf);
+ if (ret)
+ msg_pdbg("Bus Pirate shutdown failed.\n");
+ else
+ msg_pdbg("Bus Pirate shutdown completed.\n");
+
+ free(data);
+ return ret;
+}
static struct spi_master spi_master_buspirate = {
.features = SPI_MASTER_4BA,
.max_data_read = MAX_DATA_UNSPECIFIED,
.max_data_write = MAX_DATA_UNSPECIFIED,
.command = NULL,
- .multicommand = default_spi_send_multicommand,
.read = default_spi_read,
.write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .shutdown = buspirate_spi_shutdown,
};
static const struct buspirate_speeds spispeeds[] = {
@@ -165,42 +204,101 @@ static const struct buspirate_speeds serialspeeds[] = {
{NULL, 0}
};
-static int buspirate_spi_shutdown(void *data)
+static int buspirate_spi_send_command_v1(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
{
- int ret = 0, ret2 = 0;
- /* No need to allocate a buffer here, we know that bp_commbuf is at least DEFAULT_BUFSIZE big. */
+ unsigned int i = 0;
+ int ret = 0;
+ struct bp_spi_data *bp_data = flash->mst->spi.data;
- /* Exit raw SPI mode (enter raw bitbang mode) */
- bp_commbuf[0] = 0x00;
- if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
- goto out_shutdown;
- if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
- goto out_shutdown;
- if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
- goto out_shutdown;
- msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[0]);
- if (bp_commbuf[0] != '1') {
- msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[0]);
- ret = 1;
- goto out_shutdown;
+ if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
+ return SPI_INVALID_LENGTH;
+
+ /* 3 bytes extra for CS#, len, CS#. */
+ if (buspirate_commbuf_grow(writecnt + readcnt + 3, &bp_data->commbuf, &bp_data->commbufsize))
+ return ERROR_OOM;
+
+ unsigned char *const bp_commbuf = bp_data->commbuf;
+
+ /* Assert CS# */
+ bp_commbuf[i++] = 0x02;
+
+ bp_commbuf[i++] = 0x10 | (writecnt + readcnt - 1);
+ memcpy(bp_commbuf + i, writearr, writecnt);
+ i += writecnt;
+ memset(bp_commbuf + i, 0, readcnt);
+
+ i += readcnt;
+ /* De-assert CS# */
+ bp_commbuf[i++] = 0x03;
+
+ ret = buspirate_sendrecv(bp_commbuf, i, i);
+
+ if (ret) {
+ msg_perr("Bus Pirate communication error!\n");
+ return SPI_GENERIC_ERROR;
}
- /* Reset Bus Pirate (return to user terminal) */
- bp_commbuf[0] = 0x0f;
- ret = buspirate_sendrecv(bp_commbuf, 1, 0);
-out_shutdown:
- /* Shut down serial port communication */
- ret2 = serialport_shutdown(NULL);
- /* Keep the oldest error, it is probably the best indicator. */
- if (ret2 && !ret)
- ret = ret2;
- bp_commbufsize = 0;
- free(bp_commbuf);
- bp_commbuf = NULL;
- if (ret)
- msg_pdbg("Bus Pirate shutdown failed.\n");
- else
- msg_pdbg("Bus Pirate shutdown completed.\n");
+ if (bp_commbuf[0] != 0x01) {
+ msg_perr("Protocol error while lowering CS#!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ if (bp_commbuf[1] != 0x01) {
+ msg_perr("Protocol error while reading/writing SPI!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ if (bp_commbuf[i - 1] != 0x01) {
+ msg_perr("Protocol error while raising CS#!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ /* Skip CS#, length, writearr. */
+ memcpy(readarr, bp_commbuf + 2 + writecnt, readcnt);
+
+ return ret;
+}
+
+static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
+{
+ int i = 0, ret = 0;
+ struct bp_spi_data *bp_data = flash->mst->spi.data;
+
+ if (writecnt > 4096 || readcnt > 4096 || (readcnt + writecnt) > 4096)
+ return SPI_INVALID_LENGTH;
+
+ /* 5 bytes extra for command, writelen, readlen.
+ * 1 byte extra for Ack/Nack.
+ */
+ if (buspirate_commbuf_grow(max(writecnt + 5, readcnt + 1), &bp_data->commbuf, &bp_data->commbufsize))
+ return ERROR_OOM;
+
+ unsigned char *const bp_commbuf = bp_data->commbuf;
+
+ /* Combined SPI write/read. */
+ bp_commbuf[i++] = 0x04;
+ bp_commbuf[i++] = (writecnt >> 8) & 0xff;
+ bp_commbuf[i++] = writecnt & 0xff;
+ bp_commbuf[i++] = (readcnt >> 8) & 0xff;
+ bp_commbuf[i++] = readcnt & 0xff;
+ memcpy(bp_commbuf + i, writearr, writecnt);
+
+ ret = buspirate_sendrecv(bp_commbuf, i + writecnt, 1 + readcnt);
+
+ if (ret) {
+ msg_perr("Bus Pirate communication error!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ if (bp_commbuf[0] != 0x01) {
+ msg_perr("Protocol error while sending SPI write/read!\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ /* Skip Ack. */
+ memcpy(readarr, bp_commbuf + 1, readcnt);
return ret;
}
@@ -214,7 +312,7 @@ out_shutdown:
*/
#define BP_DIVISOR(baud) ((4000000/(baud)) - 1)
-int buspirate_spi_init(void)
+static int buspirate_spi_init(const struct programmer_cfg *cfg)
{
char *tmp;
char *dev;
@@ -227,9 +325,13 @@ int buspirate_spi_init(void)
int spispeed = 0x7;
int serialspeed_index = -1;
int ret = 0;
- int pullup = 0;
+ bool pullup = false;
+ bool psu = false;
+ bool aux = true;
+ unsigned char *bp_commbuf;
+ int bp_commbufsize;
- dev = extract_programmer_param("dev");
+ dev = extract_programmer_param_str(cfg, "dev");
if (dev && !strlen(dev)) {
free(dev);
dev = NULL;
@@ -239,7 +341,7 @@ int buspirate_spi_init(void)
return 1;
}
- tmp = extract_programmer_param("spispeed");
+ tmp = extract_programmer_param_str(cfg, "spispeed");
if (tmp) {
for (i = 0; spispeeds[i].name; i++) {
if (!strncasecmp(spispeeds[i].name, tmp, strlen(spispeeds[i].name))) {
@@ -253,7 +355,7 @@ int buspirate_spi_init(void)
free(tmp);
/* Extract serialspeed parameter */
- tmp = extract_programmer_param("serialspeed");
+ tmp = extract_programmer_param_str(cfg, "serialspeed");
if (tmp) {
for (i = 0; serialspeeds[i].name; i++) {
if (!strncasecmp(serialspeeds[i].name, tmp, strlen(serialspeeds[i].name))) {
@@ -266,10 +368,10 @@ int buspirate_spi_init(void)
}
free(tmp);
- tmp = extract_programmer_param("pullups");
+ tmp = extract_programmer_param_str(cfg, "pullups");
if (tmp) {
if (strcasecmp("on", tmp) == 0)
- pullup = 1;
+ pullup = true;
else if (strcasecmp("off", tmp) == 0)
; // ignore
else
@@ -277,11 +379,32 @@ int buspirate_spi_init(void)
}
free(tmp);
+ tmp = extract_programmer_param_str(cfg, "psus");
+ if (tmp) {
+ if (strcasecmp("on", tmp) == 0)
+ psu = true;
+ else if (strcasecmp("off", tmp) == 0)
+ ; // ignore
+ else
+ msg_perr("Invalid psus state, not enabling.\n");
+ }
+ free(tmp);
+
+ tmp = extract_programmer_param_str(cfg, "aux");
+ if (tmp) {
+ if (strcasecmp("high", tmp) == 0)
+ ; /* Default */
+ else if (strcasecmp("low", tmp) == 0)
+ aux = false;
+ else
+ msg_perr("Invalid AUX state, driving high by default.\n");
+ }
+ free(tmp);
+
/* Default buffer size is 19: 16 bytes data, 3 bytes control. */
#define DEFAULT_BUFSIZE (16 + 3)
bp_commbuf = malloc(DEFAULT_BUFSIZE);
if (!bp_commbuf) {
- bp_commbufsize = 0;
msg_perr("Out of memory!\n");
free(dev);
return ERROR_OOM;
@@ -291,18 +414,19 @@ int buspirate_spi_init(void)
ret = buspirate_serialport_setup(dev);
free(dev);
if (ret) {
- bp_commbufsize = 0;
free(bp_commbuf);
- bp_commbuf = NULL;
return ret;
}
- if (register_shutdown(buspirate_spi_shutdown, NULL) != 0) {
- bp_commbufsize = 0;
+
+ struct bp_spi_data *bp_data = calloc(1, sizeof(*bp_data));
+ if (!bp_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
free(bp_commbuf);
- bp_commbuf = NULL;
return 1;
}
+ bp_data->commbuf = bp_commbuf;
+ bp_data->commbufsize = bp_commbufsize;
/* This is the brute force version, but it should work.
* It is likely to fail if a previous flashrom run was aborted during a write with the new SPI commands
@@ -315,7 +439,7 @@ int buspirate_spi_init(void)
/* Send the command, don't read the response. */
ret = buspirate_sendrecv(bp_commbuf, 1, 0);
if (ret)
- return ret;
+ goto init_err_cleanup_exit;
/* The old way to handle responses from a Bus Pirate already in BBIO mode was to flush any
* response which came in over serial. Unfortunately that does not work reliably on Linux
* with FTDI USB-serial.
@@ -328,19 +452,19 @@ int buspirate_spi_init(void)
}
/* We know that 20 commands of \0 should elicit at least one BBIO1 response. */
if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
- return ret;
+ goto init_err_cleanup_exit;
/* Reset the Bus Pirate. */
bp_commbuf[0] = 0x0f;
/* Send the command, don't read the response. */
if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, "irate ")))
- return ret;
+ goto init_err_cleanup_exit;
/* Read the hardware version string. Last byte of the buffer is reserved for \0. */
for (i = 0; i < DEFAULT_BUFSIZE - 1; i++) {
if ((ret = buspirate_sendrecv(bp_commbuf + i, 0, 1)))
- return ret;
+ goto init_err_cleanup_exit;
if (strchr("\r\n\t ", bp_commbuf[i]))
break;
}
@@ -361,11 +485,11 @@ int buspirate_spi_init(void)
msg_pdbg("\n");
if ((ret = buspirate_wait_for_string(bp_commbuf, "irmware ")))
- return ret;
+ goto init_err_cleanup_exit;
/* Read the firmware version string. Last byte of the buffer is reserved for \0. */
for (i = 0; i < DEFAULT_BUFSIZE - 1; i++) {
if ((ret = buspirate_sendrecv(bp_commbuf + i, 0, 1)))
- return ret;
+ goto init_err_cleanup_exit;
if (strchr("\r\n\t ", bp_commbuf[i]))
break;
}
@@ -386,21 +510,26 @@ int buspirate_spi_init(void)
msg_pdbg("\n");
if ((ret = buspirate_wait_for_string(bp_commbuf, "HiZ>")))
- return ret;
+ goto init_err_cleanup_exit;
/* Tell the user about missing SPI binary mode in firmware 2.3 and older. */
if (BP_FWVERSION(fw_version_major, fw_version_minor) < BP_FWVERSION(2, 4)) {
msg_pinfo("Bus Pirate firmware 2.3 and older does not support binary SPI access.\n");
msg_pinfo("Please upgrade to the latest firmware (at least 2.4).\n");
- return SPI_PROGRAMMER_ERROR;
+ ret = SPI_PROGRAMMER_ERROR;
+ goto init_err_cleanup_exit;
}
/* Use fast SPI mode in firmware 5.5 and newer. */
if (BP_FWVERSION(fw_version_major, fw_version_minor) >= BP_FWVERSION(5, 5)) {
msg_pdbg("Using SPI command set v2.\n");
/* Sensible default buffer size. */
- if (buspirate_commbuf_grow(260 + 5))
- return ERROR_OOM;
+ if (buspirate_commbuf_grow(260 + 5, &bp_commbuf, &bp_commbufsize)) {
+ ret = ERROR_OOM;
+ goto init_err_cleanup_exit;
+ }
+ bp_data->commbuf = bp_commbuf;
+ bp_data->commbufsize = bp_commbufsize;
spi_master_buspirate.max_data_read = 2048;
spi_master_buspirate.max_data_write = 256;
spi_master_buspirate.command = buspirate_spi_send_command_v2;
@@ -409,8 +538,12 @@ int buspirate_spi_init(void)
msg_pinfo("Reading/writing a flash chip may take hours.\n");
msg_pinfo("It is recommended to upgrade to firmware 5.5 or newer.\n");
/* Sensible default buffer size. */
- if (buspirate_commbuf_grow(16 + 3))
- return ERROR_OOM;
+ if (buspirate_commbuf_grow(16 + 3, &bp_commbuf, &bp_commbufsize)) {
+ ret = ERROR_OOM;
+ goto init_err_cleanup_exit;
+ }
+ bp_data->commbuf = bp_commbuf;
+ bp_data->commbufsize = bp_commbufsize;
spi_master_buspirate.max_data_read = 12;
spi_master_buspirate.max_data_write = 12;
spi_master_buspirate.command = buspirate_spi_send_command_v1;
@@ -450,37 +583,37 @@ int buspirate_spi_init(void)
/* Enter baud rate configuration mode */
cnt = snprintf((char *)bp_commbuf, DEFAULT_BUFSIZE, "b\n");
if ((ret = buspirate_sendrecv(bp_commbuf, cnt, 0)))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, ">")))
- return ret;
+ goto init_err_cleanup_exit;
/* Enter manual clock divisor entry mode */
cnt = snprintf((char *)bp_commbuf, DEFAULT_BUFSIZE, "10\n");
if ((ret = buspirate_sendrecv(bp_commbuf, cnt, 0)))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, ">")))
- return ret;
+ goto init_err_cleanup_exit;
/* Set the clock divisor to the value calculated from the user's input */
cnt = snprintf((char *)bp_commbuf, DEFAULT_BUFSIZE, "%d\n",
BP_DIVISOR(serialspeeds[serialspeed_index].speed));
if ((ret = buspirate_sendrecv(bp_commbuf, cnt, 0)))
- return ret;
+ goto init_err_cleanup_exit;
sleep(1);
/* Reconfigure the host's serial baud rate to the new value */
if ((ret = serialport_config(sp_fd, serialspeeds[serialspeed_index].speed))) {
msg_perr("Unable to configure system baud rate to specified value.");
- return ret;
+ goto init_err_cleanup_exit;
}
/* Return to the main prompt */
bp_commbuf[0] = ' ';
if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, "HiZ>")))
- return ret;
+ goto init_err_cleanup_exit;
msg_pdbg("Serial speed is %d baud\n", serialspeeds[serialspeed_index].speed);
}
@@ -493,174 +626,107 @@ int buspirate_spi_init(void)
for (i = 0; i < 20; i++) {
bp_commbuf[0] = 0x00;
if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
- return ret;
+ goto init_err_cleanup_exit;
}
if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
- return ret;
+ goto init_err_cleanup_exit;
msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[0]);
if (bp_commbuf[0] != '1') {
msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[0]);
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
/* Enter raw SPI mode */
bp_commbuf[0] = 0x01;
ret = buspirate_sendrecv(bp_commbuf, 1, 0);
if (ret)
- return 1;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, "SPI")))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
- return ret;
+ goto init_err_cleanup_exit;
msg_pdbg("Raw SPI mode version %c\n", bp_commbuf[0]);
if (bp_commbuf[0] != '1') {
msg_perr("Can't handle raw SPI mode version %c!\n", bp_commbuf[0]);
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
- /* Initial setup (SPI peripherals config): Enable power, CS high, AUX */
- bp_commbuf[0] = 0x40 | 0x0b;
- if (pullup == 1) {
+ /* Initial setup (SPI peripherals config): Enable power, CS high */
+ bp_commbuf[0] = 0x40 | 0x09;
+ if (pullup) {
bp_commbuf[0] |= (1 << 2);
msg_pdbg("Enabling pull-up resistors.\n");
}
+ if (psu) {
+ bp_commbuf[0] |= (1 << 3);
+ msg_pdbg("Enabling PSUs.\n");
+ }
+ if (aux) {
+ bp_commbuf[0] |= (1 << 1);
+ msg_pdbg("Driving AUX high.\n");
+ } else {
+ msg_pdbg("Driving AUX low.\n");
+ }
ret = buspirate_sendrecv(bp_commbuf, 1, 1);
if (ret)
- return 1;
+ goto init_err_cleanup_exit;
if (bp_commbuf[0] != 0x01) {
msg_perr("Protocol error while setting power/CS/AUX(/Pull-up resistors)!\n");
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
/* Set SPI speed */
bp_commbuf[0] = 0x60 | spispeed;
ret = buspirate_sendrecv(bp_commbuf, 1, 1);
if (ret)
- return 1;
+ goto init_err_cleanup_exit;
if (bp_commbuf[0] != 0x01) {
msg_perr("Protocol error while setting SPI speed!\n");
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
/* Set SPI config: output type, idle, clock edge, sample */
bp_commbuf[0] = 0x80 | 0xa;
- if (pullup == 1) {
+ if (pullup) {
bp_commbuf[0] &= ~(1 << 3);
msg_pdbg("Pull-ups enabled, so using HiZ pin output! (Open-Drain mode)\n");
}
ret = buspirate_sendrecv(bp_commbuf, 1, 1);
if (ret)
- return 1;
+ goto init_err_cleanup_exit;
if (bp_commbuf[0] != 0x01) {
msg_perr("Protocol error while setting SPI config!\n");
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
/* De-assert CS# */
bp_commbuf[0] = 0x03;
ret = buspirate_sendrecv(bp_commbuf, 1, 1);
if (ret)
- return 1;
- if (bp_commbuf[0] != 0x01) {
- msg_perr("Protocol error while raising CS#!\n");
- return 1;
- }
-
- register_spi_master(&spi_master_buspirate);
-
- return 0;
-}
-
-static int buspirate_spi_send_command_v1(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr)
-{
- unsigned int i = 0;
- int ret = 0;
-
- if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
- return SPI_INVALID_LENGTH;
-
- /* 3 bytes extra for CS#, len, CS#. */
- if (buspirate_commbuf_grow(writecnt + readcnt + 3))
- return ERROR_OOM;
-
- /* Assert CS# */
- bp_commbuf[i++] = 0x02;
-
- bp_commbuf[i++] = 0x10 | (writecnt + readcnt - 1);
- memcpy(bp_commbuf + i, writearr, writecnt);
- i += writecnt;
- memset(bp_commbuf + i, 0, readcnt);
-
- i += readcnt;
- /* De-assert CS# */
- bp_commbuf[i++] = 0x03;
-
- ret = buspirate_sendrecv(bp_commbuf, i, i);
-
- if (ret) {
- msg_perr("Bus Pirate communication error!\n");
- return SPI_GENERIC_ERROR;
- }
-
+ goto init_err_cleanup_exit;
if (bp_commbuf[0] != 0x01) {
- msg_perr("Protocol error while lowering CS#!\n");
- return SPI_GENERIC_ERROR;
- }
-
- if (bp_commbuf[1] != 0x01) {
- msg_perr("Protocol error while reading/writing SPI!\n");
- return SPI_GENERIC_ERROR;
- }
-
- if (bp_commbuf[i - 1] != 0x01) {
msg_perr("Protocol error while raising CS#!\n");
- return SPI_GENERIC_ERROR;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
- /* Skip CS#, length, writearr. */
- memcpy(readarr, bp_commbuf + 2 + writecnt, readcnt);
+ return register_spi_master(&spi_master_buspirate, bp_data);
+init_err_cleanup_exit:
+ buspirate_spi_shutdown(bp_data);
return ret;
}
-static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr)
-{
- int i = 0, ret = 0;
-
- if (writecnt > 4096 || readcnt > 4096 || (readcnt + writecnt) > 4096)
- return SPI_INVALID_LENGTH;
-
- /* 5 bytes extra for command, writelen, readlen.
- * 1 byte extra for Ack/Nack.
- */
- if (buspirate_commbuf_grow(max(writecnt + 5, readcnt + 1)))
- return ERROR_OOM;
-
- /* Combined SPI write/read. */
- bp_commbuf[i++] = 0x04;
- bp_commbuf[i++] = (writecnt >> 8) & 0xff;
- bp_commbuf[i++] = writecnt & 0xff;
- bp_commbuf[i++] = (readcnt >> 8) & 0xff;
- bp_commbuf[i++] = readcnt & 0xff;
- memcpy(bp_commbuf + i, writearr, writecnt);
-
- ret = buspirate_sendrecv(bp_commbuf, i + writecnt, 1 + readcnt);
-
- if (ret) {
- msg_perr("Bus Pirate communication error!\n");
- return SPI_GENERIC_ERROR;
- }
-
- if (bp_commbuf[0] != 0x01) {
- msg_perr("Protocol error while sending SPI write/read!\n");
- return SPI_GENERIC_ERROR;
- }
-
- /* Skip Ack. */
- memcpy(readarr, bp_commbuf + 1, readcnt);
-
- return ret;
-}
+const struct programmer_entry programmer_buspirate_spi = {
+ .name = "buspirate_spi",
+ .type = OTHER,
+ /* FIXME */
+ .devs.note = "Dangerous Prototypes Bus Pirate\n",
+ .init = buspirate_spi_init,
+};
diff --git a/cbtable.c b/cbtable.c
index 6185f125a..dd6a0b956 100644
--- a/cbtable.c
+++ b/cbtable.c
@@ -26,6 +26,7 @@
#include "flash.h"
#include "programmer.h"
#include "coreboot_tables.h"
+#include "hwaccess_physmap.h"
static char *cb_vendor = NULL, *cb_model = NULL;
@@ -158,7 +159,7 @@ static int lb_header_valid(struct lb_header *head, unsigned long addr)
msg_pdbg("Found candidate at: %08lx-%08lx\n",
addr, addr + sizeof(*head) + head->table_bytes);
if (head->header_bytes != sizeof(*head)) {
- msg_perr("Header bytes of %d are incorrect.\n",
+ msg_perr("Header bytes of %"PRId32" are incorrect.\n",
head->header_bytes);
return 0;
}
@@ -174,12 +175,12 @@ static int lb_table_valid(struct lb_header *head, struct lb_record *recs)
{
if (compute_checksum(recs, head->table_bytes)
!= head->table_checksum) {
- msg_perr("Bad table checksum: %04x.\n",
+ msg_perr("Bad table checksum: %04"PRIx32".\n",
head->table_checksum);
return 0;
}
if (count_lb_records(head) != head->table_entries) {
- msg_perr("Bad record count: %d.\n",
+ msg_perr("Bad record count: %"PRId32".\n",
head->table_entries);
return 0;
}
@@ -210,6 +211,62 @@ static struct lb_header *find_lb_table(void *base, unsigned long start,
return NULL;
}
+static struct lb_header *find_lb_table_remap(unsigned long start_addr,
+ uint8_t **table_area)
+{
+ size_t offset;
+ unsigned long end;
+ size_t mapping_size;
+ void *base;
+
+ mapping_size = getpagesize();
+ offset = start_addr % getpagesize();
+ start_addr -= offset;
+
+ base = physmap_ro("high tables", start_addr, mapping_size);
+ if (ERROR_PTR == base) {
+ msg_perr("Failed getting access to coreboot high tables.\n");
+ return NULL;
+ }
+
+ for (end = getpagesize(); offset < end; offset += 16) {
+ struct lb_record *recs;
+ struct lb_header *head;
+
+ /* No more headers to check. */
+ if (end - offset < sizeof(*head))
+ return NULL;
+
+ head = (struct lb_header *)(((char *)base) + offset);
+
+ if (!lb_header_valid(head, offset))
+ continue;
+
+ if (mapping_size - offset < head->table_bytes + sizeof(*head)) {
+ size_t prev_mapping_size = mapping_size;
+ mapping_size = head->table_bytes + sizeof(*head);
+ mapping_size += offset;
+ mapping_size += getpagesize() - (mapping_size % getpagesize());
+ physunmap(base, prev_mapping_size);
+ base = physmap_ro("high tables", start_addr, mapping_size);
+ if (ERROR_PTR == base)
+ msg_perr("Failed getting access to coreboot high tables.\n");
+ else
+ head = (struct lb_header *)(((char *)base) + offset);
+ }
+
+ recs = (struct lb_record *)(((char *)base) + offset + sizeof(*head));
+ if (!lb_table_valid(head, recs))
+ continue;
+ msg_pdbg("Found coreboot table at 0x%08zx.\n", offset);
+ *table_area = base;
+ return head;
+ }
+
+ physunmap(base, mapping_size);
+ return NULL;
+}
+
static void find_mainboard(struct lb_record *ptr, unsigned long addr)
{
struct lb_mainboard *rec;
@@ -238,13 +295,10 @@ static struct lb_record *next_record(struct lb_record *rec)
static void search_lb_records(struct lb_record *rec, struct lb_record *last, unsigned long addr)
{
struct lb_record *next;
- int count;
- count = 0;
for (next = next_record(rec); (rec < last) && (next <= last);
rec = next, addr += rec->size) {
next = next_record(rec);
- count++;
if (rec->tag == LB_TAG_MAINBOARD) {
find_mainboard(rec, addr);
break;
@@ -283,15 +337,8 @@ int cb_parse_table(const char **vendor, const char **model)
(((char *)lb_table) + lb_table->header_bytes);
if (forward->tag == LB_TAG_FORWARD) {
start = forward->forward;
- start &= ~(getpagesize() - 1);
physunmap_unaligned(table_area, BYTES_TO_MAP);
- // FIXME: table_area is never unmapped below, nor is it unmapped above in the no-forward case
- table_area = physmap_ro_unaligned("high tables", start, BYTES_TO_MAP);
- if (ERROR_PTR == table_area) {
- msg_perr("Failed getting access to coreboot high tables.\n");
- return -1;
- }
- lb_table = find_lb_table(table_area, 0x00000, 0x1000);
+ lb_table = find_lb_table_remap(start, &table_area);
}
}
@@ -305,7 +352,7 @@ int cb_parse_table(const char **vendor, const char **model)
(unsigned long)lb_table - (unsigned long)table_area + start);
rec = (struct lb_record *)(((char *)lb_table) + lb_table->header_bytes);
last = (struct lb_record *)(((char *)rec) + lb_table->table_bytes);
- msg_pdbg("coreboot header(%d) checksum: %04x table(%d) checksum: %04x entries: %d\n",
+ msg_pdbg("coreboot header(%"PRId32") checksum: %04"PRIx32" table(%"PRId32") checksum: %04"PRIx32" entries: %"PRId32"\n",
lb_table->header_bytes, lb_table->header_checksum,
lb_table->table_bytes, lb_table->table_checksum,
lb_table->table_entries);
diff --git a/ch341a_spi.c b/ch341a_spi.c
index 84cc3fe7b..8f42f09c7 100644
--- a/ch341a_spi.c
+++ b/ch341a_spi.c
@@ -17,10 +17,10 @@
* GNU General Public License for more details.
*/
+#include <stdlib.h>
#include <string.h>
#include <libusb.h>
#include "flash.h"
-#include "platform.h"
#include "programmer.h"
/* LIBUSB_CALL ensures the right calling conventions on libusb callbacks.
@@ -73,18 +73,20 @@
/* Number of parallel IN transfers. 32 seems to produce the most stable throughput on Windows. */
#define USB_IN_TRANSFERS 32
-/* We need to use many queued IN transfers for any resemblance of performance (especially on Windows)
- * because USB spec says that transfers end on non-full packets and the device sends the 31 reply
- * data bytes to each 32-byte packet with command + 31 bytes of data... */
-static struct libusb_transfer *transfer_out = NULL;
-static struct libusb_transfer *transfer_ins[USB_IN_TRANSFERS] = {0};
+struct ch341a_spi_data {
+ struct libusb_device_handle *handle;
-/* Accumulate delays to be plucked between CS deassertion and CS assertions. */
-static unsigned int stored_delay_us = 0;
+ /* We need to use many queued IN transfers for any resemblance of performance (especially on Windows)
+ * because USB spec says that transfers end on non-full packets and the device sends the 31 reply
+ * data bytes to each 32-byte packet with command + 31 bytes of data... */
+ struct libusb_transfer *transfer_out;
+ struct libusb_transfer *transfer_ins[USB_IN_TRANSFERS];
-static struct libusb_device_handle *handle = NULL;
+ /* Accumulate delays to be plucked between CS deassertion and CS assertions. */
+ unsigned int stored_delay_us;
+};
-const struct dev_entry devs_ch341a_spi[] = {
+static const struct dev_entry devs_ch341a_spi[] = {
{0x1A86, 0x5512, OK, "Winchiphead (WCH)", "CH341A"},
{0},
@@ -132,20 +134,18 @@ static void LIBUSB_CALL cb_in(struct libusb_transfer *transfer)
cb_common(__func__, transfer);
}
-static int32_t usb_transfer(const char *func, unsigned int writecnt, unsigned int readcnt, const uint8_t *writearr, uint8_t *readarr)
+static int32_t usb_transfer(const struct ch341a_spi_data *data, const char *func,
+ unsigned int writecnt, unsigned int readcnt, const uint8_t *writearr, uint8_t *readarr)
{
- if (handle == NULL)
- return -1;
-
int state_out = TRANS_IDLE;
- transfer_out->buffer = (uint8_t*)writearr;
- transfer_out->length = writecnt;
- transfer_out->user_data = &state_out;
+ data->transfer_out->buffer = (uint8_t*)writearr;
+ data->transfer_out->length = writecnt;
+ data->transfer_out->user_data = &state_out;
/* Schedule write first */
if (writecnt > 0) {
state_out = TRANS_ACTIVE;
- int ret = libusb_submit_transfer(transfer_out);
+ int ret = libusb_submit_transfer(data->transfer_out);
if (ret) {
msg_perr("%s: failed to submit OUT transfer: %s\n", func, libusb_error_name(ret));
state_out = TRANS_ERR;
@@ -166,10 +166,10 @@ static int32_t usb_transfer(const char *func, unsigned int writecnt, unsigned in
/* Schedule new reads as long as there are free transfers and unscheduled bytes to read. */
while ((in_done + in_active) < readcnt && state_in[free_idx] == TRANS_IDLE) {
unsigned int cur_todo = min(CH341_PACKET_LENGTH - 1, readcnt - in_done - in_active);
- transfer_ins[free_idx]->length = cur_todo;
- transfer_ins[free_idx]->buffer = in_buf;
- transfer_ins[free_idx]->user_data = &state_in[free_idx];
- int ret = libusb_submit_transfer(transfer_ins[free_idx]);
+ data->transfer_ins[free_idx]->length = cur_todo;
+ data->transfer_ins[free_idx]->buffer = in_buf;
+ data->transfer_ins[free_idx]->user_data = &state_in[free_idx];
+ int ret = libusb_submit_transfer(data->transfer_ins[free_idx]);
if (ret) {
state_in[free_idx] = TRANS_ERR;
msg_perr("%s: failed to submit IN transfer: %s\n",
@@ -224,14 +224,14 @@ err:
(state_out == TRANS_ERR) ? writecnt : readcnt);
/* First, we must cancel any ongoing requests and wait for them to be canceled. */
if ((writecnt > 0) && (state_out == TRANS_ACTIVE)) {
- if (libusb_cancel_transfer(transfer_out) != 0)
+ if (libusb_cancel_transfer(data->transfer_out) != 0)
state_out = TRANS_ERR;
}
if (readcnt > 0) {
unsigned int i;
for (i = 0; i < USB_IN_TRANSFERS; i++) {
if (state_in[i] == TRANS_ACTIVE)
- if (libusb_cancel_transfer(transfer_ins[i]) != 0)
+ if (libusb_cancel_transfer(data->transfer_ins[i]) != 0)
state_in[i] = TRANS_ERR;
}
}
@@ -257,18 +257,15 @@ err:
/* Set the I2C bus speed (speed(b1b0): 0 = 20kHz; 1 = 100kHz, 2 = 400kHz, 3 = 750kHz).
* Set the SPI bus data width (speed(b2): 0 = Single, 1 = Double). */
-static int32_t config_stream(uint32_t speed)
+static int32_t config_stream(const struct ch341a_spi_data *data, uint32_t speed)
{
- if (handle == NULL)
- return -1;
-
uint8_t buf[] = {
CH341A_CMD_I2C_STREAM,
CH341A_CMD_I2C_STM_SET | (speed & 0x7),
CH341A_CMD_I2C_STM_END
};
- int32_t ret = usb_transfer(__func__, sizeof(buf), 0, buf, NULL);
+ int32_t ret = usb_transfer(data, __func__, sizeof(buf), 0, buf, NULL);
if (ret < 0) {
msg_perr("Could not configure stream interface.\n");
}
@@ -288,7 +285,7 @@ static int32_t config_stream(uint32_t speed)
* D6/21 unused (DIN2)
* D7/22 SO/2 (DIN)
*/
-static int32_t enable_pins(bool enable)
+static int32_t enable_pins(const struct ch341a_spi_data *data, bool enable)
{
uint8_t buf[] = {
CH341A_CMD_UIO_STREAM,
@@ -297,7 +294,7 @@ static int32_t enable_pins(bool enable)
CH341A_CMD_UIO_STM_END,
};
- int32_t ret = usb_transfer(__func__, sizeof(buf), 0, buf, NULL);
+ int32_t ret = usb_transfer(data, __func__, sizeof(buf), 0, buf, NULL);
if (ret < 0) {
msg_perr("Could not %sable output pins.\n", enable ? "en" : "dis");
}
@@ -305,14 +302,14 @@ static int32_t enable_pins(bool enable)
}
/* De-assert and assert CS in one operation. */
-static void pluck_cs(uint8_t *ptr)
+static void pluck_cs(uint8_t *ptr, unsigned int *stored_delay_us)
{
/* This was measured to give a minimum deassertion time of 2.25 us,
* >20x more than needed for most SPI chips (100ns). */
int delay_cnt = 2;
- if (stored_delay_us) {
- delay_cnt = (stored_delay_us * 4) / 3;
- stored_delay_us = 0;
+ if (*stored_delay_us) {
+ delay_cnt = (*stored_delay_us * 4) / 3;
+ *stored_delay_us = 0;
}
*ptr++ = CH341A_CMD_UIO_STREAM;
*ptr++ = CH341A_CMD_UIO_STM_OUT | 0x37; /* deasserted */
@@ -323,23 +320,24 @@ static void pluck_cs(uint8_t *ptr)
*ptr++ = CH341A_CMD_UIO_STM_END;
}
-void ch341a_spi_delay(unsigned int usecs)
+static void ch341a_spi_delay(const struct flashctx *flash, unsigned int usecs)
{
+ struct ch341a_spi_data *data = flash->mst->spi.data;
+
/* There is space for 28 bytes instructions of 750 ns each in the CS packet (32 - 4 for the actual CS
* instructions), thus max 21 us, but we avoid getting too near to this boundary and use
- * internal_delay() for durations over 20 us. */
- if ((usecs + stored_delay_us) > 20) {
- unsigned int inc = 20 - stored_delay_us;
- internal_delay(usecs - inc);
+ * default_delay() for durations over 20 us. */
+ if ((usecs + data->stored_delay_us) > 20) {
+ unsigned int inc = 20 - data->stored_delay_us;
+ default_delay(usecs - inc);
usecs = inc;
}
- stored_delay_us += usecs;
+ data->stored_delay_us += usecs;
}
static int ch341a_spi_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr)
{
- if (handle == NULL)
- return -1;
+ struct ch341a_spi_data *data = flash->mst->spi.data;
/* How many packets ... */
const size_t packets = (writecnt + readcnt + CH341_PACKET_LENGTH - 2) / (CH341_PACKET_LENGTH - 1);
@@ -353,7 +351,7 @@ static int ch341a_spi_spi_send_command(const struct flashctx *flash, unsigned in
uint8_t *ptr = wbuf[0];
/* CS usage is optimized by doing both transitions in one packet.
* Final transition to deselected state is in the pin disable. */
- pluck_cs(ptr);
+ pluck_cs(ptr, &data->stored_delay_us);
unsigned int write_left = writecnt;
unsigned int read_left = readcnt;
unsigned int p;
@@ -372,7 +370,7 @@ static int ch341a_spi_spi_send_command(const struct flashctx *flash, unsigned in
write_left -= write_now;
}
- int32_t ret = usb_transfer(__func__, CH341_PACKET_LENGTH + packets + writecnt + readcnt,
+ int32_t ret = usb_transfer(data, __func__, CH341_PACKET_LENGTH + packets + writecnt + readcnt,
writecnt + readcnt, wbuf[0], rbuf);
if (ret < 0)
return -1;
@@ -385,50 +383,43 @@ static int ch341a_spi_spi_send_command(const struct flashctx *flash, unsigned in
return 0;
}
+static int ch341a_spi_shutdown(void *data)
+{
+ struct ch341a_spi_data *ch341a_data = data;
+
+ enable_pins(ch341a_data, false);
+ libusb_free_transfer(ch341a_data->transfer_out);
+ int i;
+ for (i = 0; i < USB_IN_TRANSFERS; i++)
+ libusb_free_transfer(ch341a_data->transfer_ins[i]);
+ libusb_release_interface(ch341a_data->handle, 0);
+ libusb_attach_kernel_driver(ch341a_data->handle, 0);
+ libusb_close(ch341a_data->handle);
+ libusb_exit(NULL);
+
+ free(data);
+ return 0;
+}
+
static const struct spi_master spi_master_ch341a_spi = {
.features = SPI_MASTER_4BA,
- /* flashrom's current maximum is 256 B. CH341A was tested on Linux and Windows to accept atleast
+ /* flashrom's current maximum is 256 B. CH341A was tested on Linux and Windows to accept at least
* 128 kB. Basically there should be no hard limit because transfers are broken up into USB packets
* sent to the device and most of their payload streamed via SPI. */
.max_data_read = 4 * 1024,
.max_data_write = 4 * 1024,
.command = ch341a_spi_spi_send_command,
- .multicommand = default_spi_send_multicommand,
.read = default_spi_read,
.write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .shutdown = ch341a_spi_shutdown,
+ .delay = ch341a_spi_delay,
};
-static int ch341a_spi_shutdown(void *data)
-{
- if (handle == NULL)
- return -1;
-
- enable_pins(false);
- libusb_free_transfer(transfer_out);
- transfer_out = NULL;
- int i;
- for (i = 0; i < USB_IN_TRANSFERS; i++) {
- libusb_free_transfer(transfer_ins[i]);
- transfer_ins[i] = NULL;
- }
- libusb_release_interface(handle, 0);
- libusb_close(handle);
- libusb_exit(NULL);
- handle = NULL;
- return 0;
-}
-
-int ch341a_spi_init(void)
+static int ch341a_spi_init(const struct programmer_cfg *cfg)
{
- if (handle != NULL) {
- msg_cerr("%s: handle already set! Please report a bug at flashrom@flashrom.org\n", __func__);
- return -1;
- }
-
int32_t ret = libusb_init(NULL);
if (ret < 0) {
- msg_perr("Couldnt initialize libusb!\n");
+ msg_perr("Couldn't initialize libusb!\n");
return -1;
}
@@ -439,34 +430,33 @@ int ch341a_spi_init(void)
libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
#endif
+ struct ch341a_spi_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Out of memory!\n");
+ return 1;
+ }
+
uint16_t vid = devs_ch341a_spi[0].vendor_id;
uint16_t pid = devs_ch341a_spi[0].device_id;
- handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
- if (handle == NULL) {
+ data->handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
+ if (data->handle == NULL) {
msg_perr("Couldn't open device %04x:%04x.\n", vid, pid);
- return -1;
+ goto free_data;
}
-/* libusb_detach_kernel_driver() and friends basically only work on Linux. We simply try to detach on Linux
- * without a lot of passion here. If that works fine else we will fail on claiming the interface anyway. */
-#if IS_LINUX
- ret = libusb_detach_kernel_driver(handle, 0);
- if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
- msg_pwarn("Detaching kernel drivers is not supported. Further accesses may fail.\n");
- } else if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) {
- msg_pwarn("Failed to detach kernel driver: '%s'. Further accesses will probably fail.\n",
- libusb_error_name(ret));
- }
-#endif
+ ret = libusb_detach_kernel_driver(data->handle, 0);
+ if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND)
+ msg_pwarn("Cannot detach the existing USB driver. Claiming the interface may fail. %s\n",
+ libusb_error_name(ret));
- ret = libusb_claim_interface(handle, 0);
+ ret = libusb_claim_interface(data->handle, 0);
if (ret != 0) {
msg_perr("Failed to claim interface 0: '%s'\n", libusb_error_name(ret));
goto close_handle;
}
struct libusb_device *dev;
- if (!(dev = libusb_get_device(handle))) {
+ if (!(dev = libusb_get_device(data->handle))) {
msg_perr("Failed to get device from device handle.\n");
goto close_handle;
}
@@ -484,45 +474,49 @@ int ch341a_spi_init(void)
(desc.bcdDevice >> 0) & 0x000F);
/* Allocate and pre-fill transfer structures. */
- transfer_out = libusb_alloc_transfer(0);
- if (!transfer_out) {
+ data->transfer_out = libusb_alloc_transfer(0);
+ if (!data->transfer_out) {
msg_perr("Failed to alloc libusb OUT transfer\n");
goto release_interface;
}
int i;
for (i = 0; i < USB_IN_TRANSFERS; i++) {
- transfer_ins[i] = libusb_alloc_transfer(0);
- if (transfer_ins[i] == NULL) {
+ data->transfer_ins[i] = libusb_alloc_transfer(0);
+ if (data->transfer_ins[i] == NULL) {
msg_perr("Failed to alloc libusb IN transfer %d\n", i);
goto dealloc_transfers;
}
}
/* We use these helpers but dont fill the actual buffer yet. */
- libusb_fill_bulk_transfer(transfer_out, handle, WRITE_EP, NULL, 0, cb_out, NULL, USB_TIMEOUT);
+ libusb_fill_bulk_transfer(data->transfer_out, data->handle, WRITE_EP, NULL, 0, cb_out, NULL, USB_TIMEOUT);
for (i = 0; i < USB_IN_TRANSFERS; i++)
- libusb_fill_bulk_transfer(transfer_ins[i], handle, READ_EP, NULL, 0, cb_in, NULL, USB_TIMEOUT);
+ libusb_fill_bulk_transfer(data->transfer_ins[i], data->handle, READ_EP, NULL, 0, cb_in, NULL, USB_TIMEOUT);
- if ((config_stream(CH341A_STM_I2C_100K) < 0) || (enable_pins(true) < 0))
+ if ((config_stream(data, CH341A_STM_I2C_100K) < 0) || (enable_pins(data, true) < 0))
goto dealloc_transfers;
- register_shutdown(ch341a_spi_shutdown, NULL);
- register_spi_master(&spi_master_ch341a_spi);
-
- return 0;
+ return register_spi_master(&spi_master_ch341a_spi, data);
dealloc_transfers:
for (i = 0; i < USB_IN_TRANSFERS; i++) {
- if (transfer_ins[i] == NULL)
+ if (data->transfer_ins[i] == NULL)
break;
- libusb_free_transfer(transfer_ins[i]);
- transfer_ins[i] = NULL;
+ libusb_free_transfer(data->transfer_ins[i]);
}
- libusb_free_transfer(transfer_out);
- transfer_out = NULL;
+ libusb_free_transfer(data->transfer_out);
release_interface:
- libusb_release_interface(handle, 0);
+ libusb_release_interface(data->handle, 0);
close_handle:
- libusb_close(handle);
- handle = NULL;
+ libusb_attach_kernel_driver(data->handle, 0);
+ libusb_close(data->handle);
+free_data:
+ free(data);
return -1;
}
+
+const struct programmer_entry programmer_ch341a_spi = {
+ .name = "ch341a_spi",
+ .type = USB,
+ .devs.dev = devs_ch341a_spi,
+ .init = ch341a_spi_init,
+};
diff --git a/ch347_spi.c b/ch347_spi.c
new file mode 100644
index 000000000..570e25be6
--- /dev/null
+++ b/ch347_spi.c
@@ -0,0 +1,343 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2022 Nicholas Chin <nic.c3.14@gmail.com>
+ *
+ * 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 <string.h>
+#include <stdlib.h>
+#include <libusb.h>
+#include "platform.h"
+#include "programmer.h"
+#include "flash.h"
+
+#define CH347_CMD_SPI_SET_CFG 0xC0
+#define CH347_CMD_SPI_CS_CTRL 0xC1
+#define CH347_CMD_SPI_OUT_IN 0xC2
+#define CH347_CMD_SPI_IN 0xC3
+#define CH347_CMD_SPI_OUT 0xC4
+#define CH347_CMD_SPI_GET_CFG 0xCA
+
+#define CH347_CS_ASSERT 0x00
+#define CH347_CS_DEASSERT 0x40
+#define CH347_CS_CHANGE 0x80
+#define CH347_CS_IGNORE 0x00
+
+#define WRITE_EP 0x06
+#define READ_EP 0x86
+
+#define MODE_1_IFACE 2
+#define MODE_2_IFACE 1
+
+/* The USB descriptor says the max transfer size is 512 bytes, but the
+ * vendor driver only seems to transfer a maximum of 510 bytes at once,
+ * leaving 507 bytes for data as the command + length take up 3 bytes
+ */
+#define CH347_PACKET_SIZE 510
+#define CH347_MAX_DATA_LEN (CH347_PACKET_SIZE - 3)
+
+struct ch347_spi_data {
+ struct libusb_device_handle *handle;
+};
+
+/* TODO: Add support for HID mode */
+static const struct dev_entry devs_ch347_spi[] = {
+ {0x1A86, 0x55DB, OK, "QinHeng Electronics", "USB To UART+SPI+I2C"},
+ {0}
+};
+
+static int ch347_spi_shutdown(void *data)
+{
+ struct ch347_spi_data *ch347_data = data;
+
+ /* TODO: Set this depending on the mode */
+ int spi_interface = MODE_1_IFACE;
+ libusb_release_interface(ch347_data->handle, spi_interface);
+ libusb_attach_kernel_driver(ch347_data->handle, spi_interface);
+ libusb_close(ch347_data->handle);
+ libusb_exit(NULL);
+
+ free(data);
+ return 0;
+}
+
+static int ch347_cs_control(struct ch347_spi_data *ch347_data, uint8_t cs1, uint8_t cs2)
+{
+ uint8_t cmd[13] = {
+ [0] = CH347_CMD_SPI_CS_CTRL,
+ /* payload length, uint16 LSB: 10 */
+ [1] = 10,
+ [3] = cs1,
+ [8] = cs2
+ };
+
+ int32_t ret = libusb_bulk_transfer(ch347_data->handle, WRITE_EP, cmd, sizeof(cmd), NULL, 1000);
+ if (ret < 0) {
+ msg_perr("Could not change CS!\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int ch347_write(struct ch347_spi_data *ch347_data, unsigned int writecnt, const uint8_t *writearr)
+{
+ unsigned int data_len;
+ int packet_len;
+ int transferred;
+ int ret;
+ uint8_t resp_buf[4] = {0};
+ uint8_t buffer[CH347_PACKET_SIZE] = {0};
+ unsigned int bytes_written = 0;
+
+ while (bytes_written < writecnt) {
+ data_len = min(CH347_MAX_DATA_LEN, writecnt - bytes_written );
+ packet_len = data_len + 3;
+
+ buffer[0] = CH347_CMD_SPI_OUT;
+ buffer[1] = (data_len) & 0xFF;
+ buffer[2] = ((data_len) & 0xFF00) >> 8;
+ memcpy(buffer + 3, writearr + bytes_written, data_len);
+
+ ret = libusb_bulk_transfer(ch347_data->handle, WRITE_EP, buffer, packet_len, &transferred, 1000);
+ if (ret < 0 || transferred != packet_len) {
+ msg_perr("Could not send write command\n");
+ return -1;
+ }
+
+ ret = libusb_bulk_transfer(ch347_data->handle, READ_EP, resp_buf, sizeof(resp_buf), NULL, 1000);
+ if (ret < 0) {
+ msg_perr("Could not receive write command response\n");
+ return -1;
+ }
+ bytes_written += data_len;
+ }
+ return 0;
+}
+
+static int ch347_read(struct ch347_spi_data *ch347_data, unsigned int readcnt, uint8_t *readarr)
+{
+ uint8_t *read_ptr = readarr;
+ int ret;
+ int transferred;
+ unsigned int bytes_read = 0;
+ uint8_t buffer[CH347_PACKET_SIZE] = {0};
+ uint8_t command_buf[7] = {
+ [0] = CH347_CMD_SPI_IN,
+ [1] = 4,
+ [2] = 0,
+ [3] = readcnt & 0xFF,
+ [4] = (readcnt & 0xFF00) >> 8,
+ [5] = (readcnt & 0xFF0000) >> 16,
+ [6] = (readcnt & 0xFF000000) >> 24
+ };
+
+ ret = libusb_bulk_transfer(ch347_data->handle, WRITE_EP, command_buf, sizeof(command_buf), &transferred, 1000);
+ if (ret < 0 || transferred != sizeof(command_buf)) {
+ msg_perr("Could not send read command\n");
+ return -1;
+ }
+
+ while (bytes_read < readcnt) {
+ ret = libusb_bulk_transfer(ch347_data->handle, READ_EP, buffer, CH347_PACKET_SIZE, &transferred, 1000);
+ if (ret < 0) {
+ msg_perr("Could not read data\n");
+ return -1;
+ }
+ if (transferred > CH347_PACKET_SIZE) {
+ msg_perr("libusb bug: bytes received overflowed buffer\n");
+ return -1;
+ }
+ /* Response: u8 command, u16 data length, then the data that was read */
+ if (transferred < 3) {
+ msg_perr("CH347 returned an invalid response to read command\n");
+ return -1;
+ }
+ int ch347_data_length = read_le16(buffer, 1);
+ if (transferred - 3 < ch347_data_length) {
+ msg_perr("CH347 returned less data than data length header indicates\n");
+ return -1;
+ }
+ bytes_read += ch347_data_length;
+ if (bytes_read > readcnt) {
+ msg_perr("CH347 returned more bytes than requested\n");
+ return -1;
+ }
+ memcpy(read_ptr, buffer + 3, ch347_data_length);
+ read_ptr += ch347_data_length;
+ }
+ return 0;
+}
+
+static int ch347_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
+ unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr)
+{
+ struct ch347_spi_data *ch347_data = flash->mst->spi.data;
+ int ret = 0;
+
+ ch347_cs_control(ch347_data, CH347_CS_ASSERT | CH347_CS_CHANGE, CH347_CS_IGNORE);
+ if (writecnt) {
+ ret = ch347_write(ch347_data, writecnt, writearr);
+ if (ret < 0) {
+ msg_perr("CH347 write error\n");
+ return -1;
+ }
+ }
+ if (readcnt) {
+ ret = ch347_read(ch347_data, readcnt, readarr);
+ if (ret < 0) {
+ msg_perr("CH347 read error\n");
+ return -1;
+ }
+ }
+ ch347_cs_control(ch347_data, CH347_CS_DEASSERT | CH347_CS_CHANGE, CH347_CS_IGNORE);
+
+ return 0;
+}
+
+static int32_t ch347_spi_config(struct ch347_spi_data *ch347_data, uint8_t divisor)
+{
+ int32_t ret;
+ uint8_t buff[29] = {
+ [0] = CH347_CMD_SPI_SET_CFG,
+ [1] = (sizeof(buff) - 3) & 0xFF,
+ [2] = ((sizeof(buff) - 3) & 0xFF00) >> 8,
+ /* Not sure what these two bytes do, but the vendor
+ * drivers seem to unconditionally set these values
+ */
+ [5] = 4,
+ [6] = 1,
+ /* Clock polarity: bit 1 */
+ [9] = 0,
+ /* Clock phase: bit 0 */
+ [11] = 0,
+ /* Another mystery byte */
+ [14] = 2,
+ /* Clock divisor: bits 5:3 */
+ [15] = (divisor & 0x7) << 3,
+ /* Bit order: bit 7, 0=MSB */
+ [17] = 0,
+ /* Yet another mystery byte */
+ [19] = 7,
+ /* CS polarity: bit 7 CS2, bit 6 CS1. 0 = active low */
+ [24] = 0
+ };
+
+ ret = libusb_bulk_transfer(ch347_data->handle, WRITE_EP, buff, sizeof(buff), NULL, 1000);
+ if (ret < 0) {
+ msg_perr("Could not configure SPI interface\n");
+ }
+
+ /* FIXME: Not sure if the CH347 sends error responses for
+ * invalid config data, if so the code should check
+ */
+ ret = libusb_bulk_transfer(ch347_data->handle, READ_EP, buff, sizeof(buff), NULL, 1000);
+ if (ret < 0) {
+ msg_perr("Could not receive configure SPI command response\n");
+ }
+ return ret;
+}
+
+static const struct spi_master spi_master_ch347_spi = {
+ .features = SPI_MASTER_4BA,
+ .max_data_read = MAX_DATA_READ_UNLIMITED,
+ .max_data_write = MAX_DATA_WRITE_UNLIMITED,
+ .command = ch347_spi_send_command,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .write_aai = default_spi_write_aai,
+ .shutdown = ch347_spi_shutdown,
+};
+
+/* Largely copied from ch341a_spi.c */
+static int ch347_spi_init(const struct programmer_cfg *cfg)
+{
+ struct ch347_spi_data *ch347_data = calloc(1, sizeof(*ch347_data));
+ if (!ch347_data) {
+ msg_perr("Could not allocate space for SPI data\n");
+ return 1;
+ }
+
+ int32_t ret = libusb_init(NULL);
+ if (ret < 0) {
+ msg_perr("Could not initialize libusb!\n");
+ free(ch347_data);
+ return 1;
+ }
+
+ /* Enable information, warning, and error messages (only). */
+#if LIBUSB_API_VERSION < 0x01000106
+ libusb_set_debug(NULL, 3);
+#else
+ libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
+#endif
+
+ uint16_t vid = devs_ch347_spi[0].vendor_id;
+ uint16_t pid = devs_ch347_spi[0].device_id;
+ ch347_data->handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
+ if (ch347_data->handle == NULL) {
+ msg_perr("Couldn't open device %04x:%04x.\n", vid, pid);
+ free(ch347_data);
+ return 1;
+ }
+
+ /* TODO: set based on mode */
+ /* Mode 1 uses interface 2 for the SPI interface */
+ int spi_interface = MODE_1_IFACE;
+
+ ret = libusb_detach_kernel_driver(ch347_data->handle, spi_interface);
+ if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND)
+ msg_pwarn("Cannot detach the existing USB driver. Claiming the interface may fail. %s\n",
+ libusb_error_name(ret));
+
+ ret = libusb_claim_interface(ch347_data->handle, spi_interface);
+ if (ret != 0) {
+ msg_perr("Failed to claim interface 2: '%s'\n", libusb_error_name(ret));
+ goto error_exit;
+ }
+
+ struct libusb_device *dev;
+ if (!(dev = libusb_get_device(ch347_data->handle))) {
+ msg_perr("Failed to get device from device handle.\n");
+ goto error_exit;
+ }
+
+ struct libusb_device_descriptor desc;
+ ret = libusb_get_device_descriptor(dev, &desc);
+ if (ret < 0) {
+ msg_perr("Failed to get device descriptor: '%s'\n", libusb_error_name(ret));
+ goto error_exit;
+ }
+
+ msg_pdbg("Device revision is %d.%01d.%01d\n",
+ (desc.bcdDevice >> 8) & 0x00FF,
+ (desc.bcdDevice >> 4) & 0x000F,
+ (desc.bcdDevice >> 0) & 0x000F);
+
+ /* TODO: add programmer cfg for things like CS pin and divisor */
+ if (ch347_spi_config(ch347_data, 2) < 0)
+ goto error_exit;
+
+ return register_spi_master(&spi_master_ch347_spi, ch347_data);
+
+error_exit:
+ ch347_spi_shutdown(ch347_data);
+ return 1;
+}
+
+const struct programmer_entry programmer_ch347_spi = {
+ .name = "ch347_spi",
+ .type = USB,
+ .devs.dev = devs_ch347_spi,
+ .init = ch347_spi_init,
+};
diff --git a/chipset_enable.c b/chipset_enable.c
index 040b151b0..3846ecfb6 100644
--- a/chipset_enable.c
+++ b/chipset_enable.c
@@ -24,8 +24,7 @@
* Contains the chipset specific flash enables.
*/
-#define _LARGEFILE64_SOURCE
-
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -33,13 +32,17 @@
#include <errno.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
#define NOT_DONE_YET 1
#if defined(__i386__) || defined(__x86_64__)
-static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name)
+#include "hwaccess_x86_io.h"
+#include "hwaccess_x86_msr.h"
+
+static int enable_flash_ali_m1533(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t tmp;
@@ -54,7 +57,7 @@ static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name)
return 0;
}
-static int enable_flash_rdc_r8610(struct pci_dev *dev, const char *name)
+static int enable_flash_rdc_r8610(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t tmp;
@@ -80,7 +83,7 @@ static int enable_flash_rdc_r8610(struct pci_dev *dev, const char *name)
return 0;
}
-static int enable_flash_sis85c496(struct pci_dev *dev, const char *name)
+static int enable_flash_sis85c496(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t tmp;
@@ -91,7 +94,7 @@ static int enable_flash_sis85c496(struct pci_dev *dev, const char *name)
return 0;
}
-static int enable_flash_sis_mapping(struct pci_dev *dev, const char *name)
+static int enable_flash_sis_mapping(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
#define SIS_MAPREG 0x40
uint8_t new, newer;
@@ -116,11 +119,11 @@ static struct pci_dev *find_southbridge(uint16_t vendor, const char *name)
{
struct pci_dev *sbdev;
- sbdev = pci_dev_find_vendorclass(vendor, 0x0601);
+ sbdev = pcidev_find_vendorclass(vendor, 0x0601);
if (!sbdev)
- sbdev = pci_dev_find_vendorclass(vendor, 0x0680);
+ sbdev = pcidev_find_vendorclass(vendor, 0x0680);
if (!sbdev)
- sbdev = pci_dev_find_vendorclass(vendor, 0x0000);
+ sbdev = pcidev_find_vendorclass(vendor, 0x0000);
if (!sbdev)
msg_perr("No southbridge found for %s!\n", name);
if (sbdev)
@@ -130,7 +133,7 @@ static struct pci_dev *find_southbridge(uint16_t vendor, const char *name)
return sbdev;
}
-static int enable_flash_sis501(struct pci_dev *dev, const char *name)
+static int enable_flash_sis501(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t tmp;
int ret = 0;
@@ -140,7 +143,7 @@ static int enable_flash_sis501(struct pci_dev *dev, const char *name)
if (!sbdev)
return -1;
- ret = enable_flash_sis_mapping(sbdev, name);
+ ret = enable_flash_sis_mapping(cfg, sbdev, name);
tmp = sio_read(0x22, 0x80);
tmp &= (~0x20);
@@ -155,7 +158,7 @@ static int enable_flash_sis501(struct pci_dev *dev, const char *name)
return ret;
}
-static int enable_flash_sis5511(struct pci_dev *dev, const char *name)
+static int enable_flash_sis5511(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t tmp;
int ret = 0;
@@ -165,7 +168,7 @@ static int enable_flash_sis5511(struct pci_dev *dev, const char *name)
if (!sbdev)
return -1;
- ret = enable_flash_sis_mapping(sbdev, name);
+ ret = enable_flash_sis_mapping(cfg, sbdev, name);
tmp = sio_read(0x22, 0x50);
tmp &= (~0x20);
@@ -175,7 +178,7 @@ static int enable_flash_sis5511(struct pci_dev *dev, const char *name)
return ret;
}
-static int enable_flash_sis5x0(struct pci_dev *dev, const char *name, uint8_t dis_mask, uint8_t en_mask)
+static int enable_flash_sis5x0(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name, uint8_t dis_mask, uint8_t en_mask)
{
#define SIS_REG 0x45
uint8_t new, newer;
@@ -186,7 +189,7 @@ static int enable_flash_sis5x0(struct pci_dev *dev, const char *name, uint8_t di
if (!sbdev)
return -1;
- ret = enable_flash_sis_mapping(sbdev, name);
+ ret = enable_flash_sis_mapping(cfg, sbdev, name);
new = pci_read_byte(sbdev, SIS_REG);
new &= (~dis_mask);
@@ -202,14 +205,14 @@ static int enable_flash_sis5x0(struct pci_dev *dev, const char *name, uint8_t di
return ret;
}
-static int enable_flash_sis530(struct pci_dev *dev, const char *name)
+static int enable_flash_sis530(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_sis5x0(dev, name, 0x20, 0x04);
+ return enable_flash_sis5x0(cfg, dev, name, 0x20, 0x04);
}
-static int enable_flash_sis540(struct pci_dev *dev, const char *name)
+static int enable_flash_sis540(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_sis5x0(dev, name, 0x80, 0x40);
+ return enable_flash_sis5x0(cfg, dev, name, 0x80, 0x40);
}
/* Datasheet:
@@ -218,7 +221,7 @@ static int enable_flash_sis540(struct pci_dev *dev, const char *name)
* - PDF: http://www.intel.com/design/intarch/datashts/29056201.pdf
* - Order Number: 290562-001
*/
-static int enable_flash_piix4(struct pci_dev *dev, const char *name)
+static int enable_flash_piix4(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint16_t old, new;
uint16_t xbcs = 0x4e; /* X-Bus Chip Select register. */
@@ -270,7 +273,7 @@ static int enable_flash_ich_bios_cntl_common(enum ich_chipset ich_generation, vo
switch (ich_generation) {
case CHIPSET_ICH_UNKNOWN:
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
/* Non-SPI-capable */
case CHIPSET_ICH:
case CHIPSET_ICH2345:
@@ -375,7 +378,7 @@ static int enable_flash_ich_bios_cntl_memmapped(enum ich_chipset ich_generation,
return enable_flash_ich_bios_cntl_common(ich_generation, addr, NULL, 0);
}
-static int enable_flash_ich_fwh_decode(struct pci_dev *dev, enum ich_chipset ich_generation)
+static int enable_flash_ich_fwh_decode(const struct programmer_cfg *cfg, struct pci_dev *dev, enum ich_chipset ich_generation)
{
uint8_t fwh_sel1 = 0, fwh_sel2 = 0, fwh_dec_en_lo = 0, fwh_dec_en_hi = 0; /* silence compilers */
bool implemented = 0;
@@ -404,7 +407,7 @@ static int enable_flash_ich_fwh_decode(struct pci_dev *dev, enum ich_chipset ich
uint32_t ilb_base = pci_read_long(dev, 0x50) & 0xfffffe00; /* bits 31:9 */
if (ilb_base == 0) {
msg_perr("Error: Invalid ILB_BASE_ADDRESS\n");
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
ilb = rphysmap("BYT IBASE", ilb_base, 512);
fwh_sel1 = 0x18;
@@ -424,7 +427,7 @@ static int enable_flash_ich_fwh_decode(struct pci_dev *dev, enum ich_chipset ich
break;
}
- char *idsel = extract_programmer_param("fwh_idsel");
+ char *idsel = extract_programmer_param_str(cfg, "fwh_idsel");
if (idsel && strlen(idsel)) {
if (!implemented) {
msg_perr("Error: fwh_idsel= specified, but (yet) unsupported on this chipset.\n");
@@ -463,7 +466,7 @@ static int enable_flash_ich_fwh_decode(struct pci_dev *dev, enum ich_chipset ich
msg_perr("Error: fwh_idsel= specified, but no value given.\n");
idsel_garbage_out:
free(idsel);
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
free(idsel);
@@ -545,41 +548,41 @@ idsel_garbage_out:
}
}
max_rom_decode.fwh = min(max_decode_fwh_idsel, max_decode_fwh_decode);
- msg_pdbg("Maximum FWH chip size: 0x%x bytes\n", max_rom_decode.fwh);
+ msg_pdbg("Maximum FWH chip size: 0x%"PRIx32" bytes\n", max_rom_decode.fwh);
return 0;
}
-static int enable_flash_ich_fwh(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
+static int enable_flash_ich_fwh(const struct programmer_cfg *cfg, struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
{
int err;
/* Configure FWH IDSEL decoder maps. */
- if ((err = enable_flash_ich_fwh_decode(dev, ich_generation)) != 0)
+ if ((err = enable_flash_ich_fwh_decode(cfg, dev, ich_generation)) != 0)
return err;
internal_buses_supported &= BUS_FWH;
return enable_flash_ich_bios_cntl_config_space(dev, ich_generation, bios_cntl);
}
-static int enable_flash_ich0(struct pci_dev *dev, const char *name)
+static int enable_flash_ich0(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_fwh(dev, CHIPSET_ICH, 0x4e);
+ return enable_flash_ich_fwh(cfg, dev, CHIPSET_ICH, 0x4e);
}
-static int enable_flash_ich2345(struct pci_dev *dev, const char *name)
+static int enable_flash_ich2345(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_fwh(dev, CHIPSET_ICH2345, 0x4e);
+ return enable_flash_ich_fwh(cfg, dev, CHIPSET_ICH2345, 0x4e);
}
-static int enable_flash_ich6(struct pci_dev *dev, const char *name)
+static int enable_flash_ich6(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_fwh(dev, CHIPSET_ICH6, 0xdc);
+ return enable_flash_ich_fwh(cfg, dev, CHIPSET_ICH6, 0xdc);
}
-static int enable_flash_poulsbo(struct pci_dev *dev, const char *name)
+static int enable_flash_poulsbo(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_fwh(dev, CHIPSET_POULSBO, 0xd8);
+ return enable_flash_ich_fwh(cfg, dev, CHIPSET_POULSBO, 0xd8);
}
static enum chipbustype enable_flash_ich_report_gcs(
@@ -600,7 +603,13 @@ static enum chipbustype enable_flash_ich_report_gcs(
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ case CHIPSET_ELKHART_LAKE:
case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
reg_name = "BIOS_SPI_BC";
gcs = pci_read_long(dev, 0xdc);
bild = (gcs >> 7) & 1;
@@ -614,7 +623,7 @@ static enum chipbustype enable_flash_ich_report_gcs(
break;
}
- msg_pdbg("%s = 0x%x: ", reg_name, gcs);
+ msg_pdbg("%s = 0x%"PRIx32": ", reg_name, gcs);
msg_pdbg("BIOS Interface Lock-Down: %sabled, ", bild ? "en" : "dis");
struct boot_straps {
@@ -652,6 +661,9 @@ static enum chipbustype enable_flash_ich_report_gcs(
static const struct boot_straps boot_straps_pch8_lp[] =
{ { "SPI", BUS_SPI },
{ "LPC", BUS_LPC | BUS_FWH } };
+ static const struct boot_straps boot_straps_pch500[] =
+ { { "SPI", BUS_SPI },
+ { "eSPI", BUS_NONE } };
static const struct boot_straps boot_straps_apl[] =
{ { "SPI", BUS_SPI },
{ "reserved", BUS_NONE } };
@@ -698,7 +710,15 @@ static enum chipbustype enable_flash_ich_report_gcs(
case CHIPSET_400_SERIES_COMET_POINT:
boot_straps = boot_straps_pch8_lp;
break;
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ boot_straps = boot_straps_pch500;
+ break;
case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
boot_straps = boot_straps_apl;
break;
case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet
@@ -725,7 +745,13 @@ static enum chipbustype enable_flash_ich_report_gcs(
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
bbs = (gcs >> 6) & 0x1;
break;
default:
@@ -742,22 +768,22 @@ static enum chipbustype enable_flash_ich_report_gcs(
return boot_straps[bbs].bus;
}
-static int enable_flash_ich_spi(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
+static int enable_flash_ich_spi(const struct programmer_cfg *cfg, struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl)
{
/* Get physical address of Root Complex Register Block */
uint32_t rcra = pci_read_long(dev, 0xf0) & 0xffffc000;
- msg_pdbg("Root Complex Register Block address = 0x%x\n", rcra);
+ msg_pdbg("Root Complex Register Block address = 0x%"PRIx32"\n", rcra);
/* Map RCBA to virtual memory */
void *rcrb = rphysmap("ICH RCRB", rcra, 0x4000);
if (rcrb == ERROR_PTR)
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
const enum chipbustype boot_buses = enable_flash_ich_report_gcs(dev, ich_generation, rcrb);
/* Handle FWH-related parameters and initialization */
- int ret_fwh = enable_flash_ich_fwh(dev, ich_generation, bios_cntl);
- if (ret_fwh == ERROR_FATAL)
+ int ret_fwh = enable_flash_ich_fwh(cfg, dev, ich_generation, bios_cntl);
+ if (ret_fwh == ERROR_FLASHROM_FATAL)
return ret_fwh;
/*
@@ -773,7 +799,7 @@ static int enable_flash_ich_spi(struct pci_dev *dev, enum ich_chipset ich_genera
switch (ich_generation) {
case CHIPSET_BAYTRAIL:
case CHIPSET_ICH_UNKNOWN:
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
case CHIPSET_ICH7:
case CHIPSET_ICH8:
case CHIPSET_TUNNEL_CREEK:
@@ -789,96 +815,96 @@ static int enable_flash_ich_spi(struct pci_dev *dev, enum ich_chipset ich_genera
void *spibar = rcrb + spibar_offset;
/* This adds BUS_SPI */
- int ret_spi = ich_init_spi(spibar, ich_generation);
- if (ret_spi == ERROR_FATAL)
+ int ret_spi = ich_init_spi(cfg, spibar, ich_generation);
+ if (ret_spi == ERROR_FLASHROM_FATAL)
return ret_spi;
if (((boot_buses & BUS_FWH) && ret_fwh) || ((boot_buses & BUS_SPI) && ret_spi))
- return ERROR_NONFATAL;
+ return ERROR_FLASHROM_NONFATAL;
/* Suppress unknown laptop warning if we booted from SPI. */
if (boot_buses & BUS_SPI)
- laptop_ok = 1;
+ cfg->bcfg->laptop_ok = true;
return 0;
}
-static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name)
+static int enable_flash_tunnelcreek(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_TUNNEL_CREEK, 0xd8);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_TUNNEL_CREEK, 0xd8);
}
-static int enable_flash_s12x0(struct pci_dev *dev, const char *name)
+static int enable_flash_s12x0(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_CENTERTON, 0xd8);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_CENTERTON, 0xd8);
}
-static int enable_flash_ich7(struct pci_dev *dev, const char *name)
+static int enable_flash_ich7(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_ICH7, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_ICH7, 0xdc);
}
-static int enable_flash_ich8(struct pci_dev *dev, const char *name)
+static int enable_flash_ich8(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_ICH8, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_ICH8, 0xdc);
}
-static int enable_flash_ich9(struct pci_dev *dev, const char *name)
+static int enable_flash_ich9(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_ICH9, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_ICH9, 0xdc);
}
-static int enable_flash_ich10(struct pci_dev *dev, const char *name)
+static int enable_flash_ich10(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_ICH10, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_ICH10, 0xdc);
}
/* Ibex Peak aka. 5 series & 3400 series */
-static int enable_flash_pch5(struct pci_dev *dev, const char *name)
+static int enable_flash_pch5(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_5_SERIES_IBEX_PEAK, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_5_SERIES_IBEX_PEAK, 0xdc);
}
/* Cougar Point aka. 6 series & c200 series */
-static int enable_flash_pch6(struct pci_dev *dev, const char *name)
+static int enable_flash_pch6(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_6_SERIES_COUGAR_POINT, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_6_SERIES_COUGAR_POINT, 0xdc);
}
/* Panther Point aka. 7 series */
-static int enable_flash_pch7(struct pci_dev *dev, const char *name)
+static int enable_flash_pch7(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_7_SERIES_PANTHER_POINT, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_7_SERIES_PANTHER_POINT, 0xdc);
}
/* Lynx Point aka. 8 series */
-static int enable_flash_pch8(struct pci_dev *dev, const char *name)
+static int enable_flash_pch8(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_8_SERIES_LYNX_POINT, 0xdc);
}
/* Lynx Point LP aka. 8 series low-power */
-static int enable_flash_pch8_lp(struct pci_dev *dev, const char *name)
+static int enable_flash_pch8_lp(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT_LP, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_8_SERIES_LYNX_POINT_LP, 0xdc);
}
/* Wellsburg (for Haswell-EP Xeons) */
-static int enable_flash_pch8_wb(struct pci_dev *dev, const char *name)
+static int enable_flash_pch8_wb(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_WELLSBURG, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_8_SERIES_WELLSBURG, 0xdc);
}
/* Wildcat Point */
-static int enable_flash_pch9(struct pci_dev *dev, const char *name)
+static int enable_flash_pch9(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_9_SERIES_WILDCAT_POINT, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_9_SERIES_WILDCAT_POINT, 0xdc);
}
/* Wildcat Point LP */
-static int enable_flash_pch9_lp(struct pci_dev *dev, const char *name)
+static int enable_flash_pch9_lp(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- return enable_flash_ich_spi(dev, CHIPSET_9_SERIES_WILDCAT_POINT_LP, 0xdc);
+ return enable_flash_ich_spi(cfg, dev, CHIPSET_9_SERIES_WILDCAT_POINT_LP, 0xdc);
}
/* Sunrise Point */
@@ -888,11 +914,11 @@ static int enable_flash_pch100_shutdown(void *const pci_acc)
return 0;
}
-static int enable_flash_pch100_or_c620(
+static int enable_flash_pch100_or_c620(const struct programmer_cfg *cfg,
struct pci_dev *const dev, const char *const name,
const int slot, const int func, const enum ich_chipset pch_generation)
{
- int ret = ERROR_FATAL;
+ int ret = ERROR_FLASHROM_FATAL;
/*
* The SPI PCI device is usually hidden (by hiding PCI vendor
@@ -923,27 +949,27 @@ static int enable_flash_pch100_or_c620(
const enum chipbustype boot_buses = enable_flash_ich_report_gcs(spi_dev, pch_generation, NULL);
const int ret_bc = enable_flash_ich_bios_cntl_config_space(spi_dev, pch_generation, 0xdc);
- if (ret_bc == ERROR_FATAL)
+ if (ret_bc == ERROR_FLASHROM_FATAL)
goto _freepci_ret;
const uint32_t phys_spibar = pci_read_long(spi_dev, PCI_BASE_ADDRESS_0) & 0xfffff000;
void *const spibar = rphysmap("SPIBAR", phys_spibar, 0x1000);
if (spibar == ERROR_PTR)
goto _freepci_ret;
- msg_pdbg("SPIBAR = 0x%0*" PRIxPTR " (phys = 0x%08x)\n", PRIxPTR_WIDTH, (uintptr_t)spibar, phys_spibar);
+ msg_pdbg("SPIBAR = 0x%0*" PRIxPTR " (phys = 0x%08"PRIx32")\n", PRIxPTR_WIDTH, (uintptr_t)spibar, phys_spibar);
/* This adds BUS_SPI */
- const int ret_spi = ich_init_spi(spibar, pch_generation);
- if (ret_spi != ERROR_FATAL) {
+ const int ret_spi = ich_init_spi(cfg, spibar, pch_generation);
+ if (ret_spi != ERROR_FLASHROM_FATAL) {
if (ret_bc || ret_spi)
- ret = ERROR_NONFATAL;
+ ret = ERROR_FLASHROM_NONFATAL;
else
ret = 0;
}
/* Suppress unknown laptop warning if we booted from SPI. */
if (!ret && (boot_buses & BUS_SPI))
- laptop_ok = 1;
+ cfg->bcfg->laptop_ok = true;
_freepci_ret:
pci_free_dev(spi_dev);
@@ -951,29 +977,59 @@ _freepci_ret:
return ret;
}
-static int enable_flash_pch100(struct pci_dev *const dev, const char *const name)
+static int enable_flash_pch100(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
+{
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x1f, 5, CHIPSET_100_SERIES_SUNRISE_POINT);
+}
+
+static int enable_flash_c620(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
+{
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x1f, 5, CHIPSET_C620_SERIES_LEWISBURG);
+}
+
+static int enable_flash_pch300(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
+{
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x1f, 5, CHIPSET_300_SERIES_CANNON_POINT);
+}
+
+static int enable_flash_pch400(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
+{
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x1f, 5, CHIPSET_400_SERIES_COMET_POINT);
+}
+
+static int enable_flash_pch500(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
+{
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x1f, 5, CHIPSET_500_SERIES_TIGER_POINT);
+}
+
+static int enable_flash_pch600(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
+{
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x1f, 5, CHIPSET_600_SERIES_ALDER_POINT);
+}
+
+static int enable_flash_mtl(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
{
- return enable_flash_pch100_or_c620(dev, name, 0x1f, 5, CHIPSET_100_SERIES_SUNRISE_POINT);
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x1f, 5, CHIPSET_METEOR_LAKE);
}
-static int enable_flash_c620(struct pci_dev *const dev, const char *const name)
+static int enable_flash_mcc(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
{
- return enable_flash_pch100_or_c620(dev, name, 0x1f, 5, CHIPSET_C620_SERIES_LEWISBURG);
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x1f, 5, CHIPSET_ELKHART_LAKE);
}
-static int enable_flash_pch300(struct pci_dev *const dev, const char *const name)
+static int enable_flash_jsl(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
{
- return enable_flash_pch100_or_c620(dev, name, 0x1f, 5, CHIPSET_300_SERIES_CANNON_POINT);
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x1f, 5, CHIPSET_JASPER_LAKE);
}
-static int enable_flash_pch400(struct pci_dev *const dev, const char *const name)
+static int enable_flash_apl(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
{
- return enable_flash_pch100_or_c620(dev, name, 0x1f, 5, CHIPSET_400_SERIES_COMET_POINT);
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x0d, 2, CHIPSET_APOLLO_LAKE);
}
-static int enable_flash_apl(struct pci_dev *const dev, const char *const name)
+static int enable_flash_glk(const struct programmer_cfg *cfg, struct pci_dev *const dev, const char *const name)
{
- return enable_flash_pch100_or_c620(dev, name, 0x0d, 2, CHIPSET_APOLLO_LAKE);
+ return enable_flash_pch100_or_c620(cfg, dev, name, 0x0d, 2, CHIPSET_GEMINI_LAKE);
}
/* Silvermont architecture: Bay Trail(-T/-I), Avoton/Rangeley.
@@ -986,55 +1042,55 @@ static int enable_flash_apl(struct pci_dev *const dev, const char *const name)
* - SPIBAR (coined SBASE) at LPC config 0x54 (instead of [RCRB] + 0x3800).
* - BIOS_CNTL (coined BCR) at [SPIBAR] + 0xFC (instead of LPC config 0xDC).
*/
-static int enable_flash_silvermont(struct pci_dev *dev, const char *name)
+static int enable_flash_silvermont(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
enum ich_chipset ich_generation = CHIPSET_BAYTRAIL;
/* Get physical address of Root Complex Register Block */
uint32_t rcba = pci_read_long(dev, 0xf0) & 0xfffffc00;
- msg_pdbg("Root Complex Register Block address = 0x%x\n", rcba);
+ msg_pdbg("Root Complex Register Block address = 0x%"PRIx32"\n", rcba);
/* Handle GCS (in RCRB) */
void *rcrb = physmap("BYT RCRB", rcba, 4);
if (rcrb == ERROR_PTR)
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
const enum chipbustype boot_buses = enable_flash_ich_report_gcs(dev, ich_generation, rcrb);
physunmap(rcrb, 4);
/* Handle fwh_idsel parameter */
- int ret_fwh = enable_flash_ich_fwh_decode(dev, ich_generation);
- if (ret_fwh == ERROR_FATAL)
+ int ret_fwh = enable_flash_ich_fwh_decode(cfg, dev, ich_generation);
+ if (ret_fwh == ERROR_FLASHROM_FATAL)
return ret_fwh;
internal_buses_supported &= BUS_FWH;
/* Get physical address of SPI Base Address and map it */
uint32_t sbase = pci_read_long(dev, 0x54) & 0xfffffe00;
- msg_pdbg("SPI_BASE_ADDRESS = 0x%x\n", sbase);
+ msg_pdbg("SPI_BASE_ADDRESS = 0x%"PRIx32"\n", sbase);
void *spibar = rphysmap("BYT SBASE", sbase, 512); /* Last defined address on Bay Trail is 0x100 */
if (spibar == ERROR_PTR)
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
/* Enable Flash Writes.
* Silvermont-based: BCR at SBASE + 0xFC (some bits of BCR are also accessible via BC at IBASE + 0x1C).
*/
enable_flash_ich_bios_cntl_memmapped(ich_generation, spibar + 0xFC);
- int ret_spi = ich_init_spi(spibar, ich_generation);
- if (ret_spi == ERROR_FATAL)
+ int ret_spi = ich_init_spi(cfg, spibar, ich_generation);
+ if (ret_spi == ERROR_FLASHROM_FATAL)
return ret_spi;
if (((boot_buses & BUS_FWH) && ret_fwh) || ((boot_buses & BUS_SPI) && ret_spi))
- return ERROR_NONFATAL;
+ return ERROR_FLASHROM_NONFATAL;
/* Suppress unknown laptop warning if we booted from SPI. */
if (boot_buses & BUS_SPI)
- laptop_ok = 1;
+ cfg->bcfg->laptop_ok = true;
return 0;
}
-static int via_no_byte_merge(struct pci_dev *dev, const char *name)
+static int via_no_byte_merge(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t val;
@@ -1047,7 +1103,7 @@ static int via_no_byte_merge(struct pci_dev *dev, const char *name)
return NOT_DONE_YET; /* need to find south bridge, too */
}
-static int enable_flash_vt823x(struct pci_dev *dev, const char *name)
+static int enable_flash_vt823x(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t val;
@@ -1074,18 +1130,18 @@ static int enable_flash_vt823x(struct pci_dev *dev, const char *name)
return 0;
}
-static int enable_flash_vt_vx(struct pci_dev *dev, const char *name)
+static int enable_flash_vt_vx(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
- struct pci_dev *south_north = pci_dev_find(0x1106, 0xa353);
+ struct pci_dev *south_north = pcidev_find(0x1106, 0xa353);
if (south_north == NULL) {
msg_perr("Could not find South-North Module Interface Control device!\n");
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
msg_pdbg("Strapped to ");
if ((pci_read_byte(south_north, 0x56) & 0x01) == 0) {
msg_pdbg("LPC.\n");
- return enable_flash_vt823x(dev, name);
+ return enable_flash_vt823x(cfg, dev, name);
}
msg_pdbg("SPI.\n");
@@ -1099,7 +1155,7 @@ static int enable_flash_vt_vx(struct pci_dev *dev, const char *name)
spi0_mm_base = pci_read_long(dev, 0xbc) << 8;
if (spi0_mm_base == 0x0) {
msg_pdbg ("MMIO not enabled!\n");
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
break;
case 0x8409: /* VX855/VX875 */
@@ -1107,18 +1163,18 @@ static int enable_flash_vt_vx(struct pci_dev *dev, const char *name)
mmio_base = pci_read_long(dev, 0xbc) << 8;
if (mmio_base == 0x0) {
msg_pdbg ("MMIO not enabled!\n");
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
mmio_base_physmapped = physmap("VIA VX MMIO register", mmio_base, SPI_CNTL_LEN);
if (mmio_base_physmapped == ERROR_PTR)
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
/* Offset 0 - Bit 0 holds SPI Bus0 Enable Bit. */
spi_cntl = mmio_readl(mmio_base_physmapped) + 0x00;
if ((spi_cntl & 0x01) == 0) {
msg_pdbg ("SPI Bus0 disabled!\n");
physunmap(mmio_base_physmapped, SPI_CNTL_LEN);
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
/* Offset 1-3 has SPI Bus Memory Map Base Address: */
spi0_mm_base = spi_cntl & 0xFFFFFF00;
@@ -1132,18 +1188,18 @@ static int enable_flash_vt_vx(struct pci_dev *dev, const char *name)
break;
default:
msg_perr("%s: Unsupported chipset %x:%x!\n", __func__, dev->vendor_id, dev->device_id);
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
return via_init_spi(spi0_mm_base);
}
-static int enable_flash_vt8237s_spi(struct pci_dev *dev, const char *name)
+static int enable_flash_vt8237s_spi(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
return via_init_spi(pci_read_long(dev, 0xbc) << 8);
}
-static int enable_flash_cs5530(struct pci_dev *dev, const char *name)
+static int enable_flash_cs5530(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t reg8;
@@ -1207,7 +1263,7 @@ static int enable_flash_cs5530(struct pci_dev *dev, const char *name)
* To enable write to NOR Boot flash for the benefit of systems that have such
* a setup, raise MSR 0x51400018 WE_CS3 (write enable Boot Flash Chip Select).
*/
-static int enable_flash_cs5536(struct pci_dev *dev, const char *name)
+static int enable_flash_cs5536(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
#define MSR_RCONF_DEFAULT 0x1808
#define MSR_NORF_CTL 0x51400018
@@ -1215,28 +1271,28 @@ static int enable_flash_cs5536(struct pci_dev *dev, const char *name)
msr_t msr;
/* Geode only has a single core */
- if (setup_cpu_msr(0))
+ if (msr_setup(0))
return -1;
- msr = rdmsr(MSR_RCONF_DEFAULT);
+ msr = msr_read(MSR_RCONF_DEFAULT);
if ((msr.hi >> 24) != 0x22) {
msr.hi &= 0xfbffffff;
- wrmsr(MSR_RCONF_DEFAULT, msr);
+ msr_write(MSR_RCONF_DEFAULT, msr);
}
- msr = rdmsr(MSR_NORF_CTL);
+ msr = msr_read(MSR_NORF_CTL);
/* Raise WE_CS3 bit. */
msr.lo |= 0x08;
- wrmsr(MSR_NORF_CTL, msr);
+ msr_write(MSR_NORF_CTL, msr);
- cleanup_cpu_msr();
+ msr_cleanup();
#undef MSR_RCONF_DEFAULT
#undef MSR_NORF_CTL
return 0;
}
-static int enable_flash_sc1100(struct pci_dev *dev, const char *name)
+static int enable_flash_sc1100(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
#define SC_REG 0x52
uint8_t new;
@@ -1261,7 +1317,7 @@ static int enable_flash_sc1100(struct pci_dev *dev, const char *name)
* 6 FFB0_0000h–FFBF_FFFFh <- FFF80000h-FFFDFFFFh <- <-
* 5 00E8... <- <- FFF00000h-FFF7FFFFh <-
*/
-static int enable_flash_amd_via(struct pci_dev *dev, const char *name, uint8_t decode_val)
+static int enable_flash_amd_via(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name, uint8_t decode_val)
{
#define AMD_MAPREG 0x43
#define AMD_ENREG 0x40
@@ -1288,36 +1344,36 @@ static int enable_flash_amd_via(struct pci_dev *dev, const char *name, uint8_t d
if (pci_read_byte(dev, AMD_ENREG) != new) {
msg_pwarn("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n",
AMD_ENREG, new, name);
- return ERROR_NONFATAL;
+ return ERROR_FLASHROM_NONFATAL;
}
msg_pdbg2("Set ROM enable bit successfully.\n");
return 0;
}
-static int enable_flash_amd_768_8111(struct pci_dev *dev, const char *name)
+static int enable_flash_amd_768_8111(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
/* Enable decoding of 0xFFB00000 to 0xFFFFFFFF (5 MB). */
max_rom_decode.lpc = 5 * 1024 * 1024;
- return enable_flash_amd_via(dev, name, 0xC0);
+ return enable_flash_amd_via(cfg, dev, name, 0xC0);
}
-static int enable_flash_vt82c586(struct pci_dev *dev, const char *name)
+static int enable_flash_vt82c586(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
/* Enable decoding of 0xFFF80000 to 0xFFFFFFFF. (512 kB) */
max_rom_decode.parallel = 512 * 1024;
- return enable_flash_amd_via(dev, name, 0xC0);
+ return enable_flash_amd_via(cfg, dev, name, 0xC0);
}
/* Works for VT82C686A/B too. */
-static int enable_flash_vt82c596(struct pci_dev *dev, const char *name)
+static int enable_flash_vt82c596(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
/* Enable decoding of 0xFFF00000 to 0xFFFFFFFF. (1 MB) */
max_rom_decode.parallel = 1024 * 1024;
- return enable_flash_amd_via(dev, name, 0xE0);
+ return enable_flash_amd_via(cfg, dev, name, 0xE0);
}
-static int enable_flash_sb600(struct pci_dev *dev, const char *name)
+static int enable_flash_sb600(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint32_t prot;
uint8_t reg;
@@ -1329,7 +1385,7 @@ static int enable_flash_sb600(struct pci_dev *dev, const char *name)
/* No protection flags for this region?*/
if ((prot & 0x3) == 0)
continue;
- msg_pdbg("Chipset %s%sprotected flash from 0x%08x to 0x%08x, unlocking...",
+ msg_pdbg("Chipset %s%sprotected flash from 0x%08"PRIx32" to 0x%08"PRIx32", unlocking...",
(prot & 0x2) ? "read " : "",
(prot & 0x1) ? "write " : "",
(prot & 0xfffff800),
@@ -1338,7 +1394,7 @@ static int enable_flash_sb600(struct pci_dev *dev, const char *name)
rpci_write_byte(dev, reg, prot);
prot = pci_read_long(dev, reg);
if ((prot & 0x3) != 0) {
- msg_perr("Disabling %s%sprotection of flash addresses from 0x%08x to 0x%08x failed.\n",
+ msg_perr("Disabling %s%sprotection of flash addresses from 0x%08"PRIx32" to 0x%08"PRIx32" failed.\n",
(prot & 0x2) ? "read " : "",
(prot & 0x1) ? "write " : "",
(prot & 0xfffff800),
@@ -1350,7 +1406,7 @@ static int enable_flash_sb600(struct pci_dev *dev, const char *name)
internal_buses_supported &= BUS_LPC | BUS_FWH;
- ret = sb600_probe_spi(dev);
+ ret = sb600_probe_spi(cfg, dev);
/* Read ROM strap override register. */
OUTB(0x8f, 0xcd6);
@@ -1391,7 +1447,7 @@ static int enable_flash_sb600(struct pci_dev *dev, const char *name)
}
/* sets bit 0 in 0x6d */
-static int enable_flash_nvidia_common(struct pci_dev *dev, const char *name)
+static int enable_flash_nvidia_common(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t old, new;
@@ -1408,16 +1464,16 @@ static int enable_flash_nvidia_common(struct pci_dev *dev, const char *name)
return 0;
}
-static int enable_flash_nvidia_nforce2(struct pci_dev *dev, const char *name)
+static int enable_flash_nvidia_nforce2(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
rpci_write_byte(dev, 0x92, 0);
- if (enable_flash_nvidia_common(dev, name))
- return ERROR_NONFATAL;
+ if (enable_flash_nvidia_common(cfg, dev, name))
+ return ERROR_FLASHROM_NONFATAL;
else
return 0;
}
-static int enable_flash_ck804(struct pci_dev *dev, const char *name)
+static int enable_flash_ck804(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint32_t segctrl;
uint8_t reg, old, new;
@@ -1436,7 +1492,7 @@ static int enable_flash_ck804(struct pci_dev *dev, const char *name)
segctrl = pci_read_byte(dev, reg);
if ((segctrl & 0x3) != 0x0) {
- msg_pinfo("Could not unlock protection in register 0x%02x (new value: 0x%x).\n",
+ msg_pinfo("Could not unlock protection in register 0x%02x (new value: 0x%"PRIx32").\n",
reg, segctrl);
err++;
} else
@@ -1460,7 +1516,7 @@ static int enable_flash_ck804(struct pci_dev *dev, const char *name)
segctrl = pci_read_long(dev, reg);
if ((segctrl & 0x33333333) != 0x00000000) {
- msg_pinfo("Could not unlock protection in register 0x%02x (new value: 0x%08x).\n",
+ msg_pinfo("Could not unlock protection in register 0x%02x (new value: 0x%08"PRIx32").\n",
reg, segctrl);
err++;
} else
@@ -1469,7 +1525,7 @@ static int enable_flash_ck804(struct pci_dev *dev, const char *name)
if (err > 0) {
msg_pinfo("%d locks could not be disabled, disabling writes (reads may also fail).\n", err);
- programmer_may_write = 0;
+ programmer_may_write = false;
}
reg = 0x88;
@@ -1483,16 +1539,16 @@ static int enable_flash_ck804(struct pci_dev *dev, const char *name)
}
}
- if (enable_flash_nvidia_common(dev, name))
+ if (enable_flash_nvidia_common(cfg, dev, name))
err++;
if (err > 0)
- return ERROR_NONFATAL;
+ return ERROR_FLASHROM_NONFATAL;
else
return 0;
}
-static int enable_flash_osb4(struct pci_dev *dev, const char *name)
+static int enable_flash_osb4(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t tmp;
@@ -1510,17 +1566,17 @@ static int enable_flash_osb4(struct pci_dev *dev, const char *name)
}
/* ATI Technologies Inc IXP SB400 PCI-ISA Bridge (rev 80) */
-static int enable_flash_sb400(struct pci_dev *dev, const char *name)
+static int enable_flash_sb400(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t tmp;
struct pci_dev *smbusdev;
/* Look for the SMBus device. */
- smbusdev = pci_dev_find(0x1002, 0x4372);
+ smbusdev = pcidev_find(0x1002, 0x4372);
if (!smbusdev) {
msg_perr("ERROR: SMBus device not found. Aborting.\n");
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
/* Enable some SMBus stuff. */
@@ -1545,7 +1601,7 @@ static int enable_flash_sb400(struct pci_dev *dev, const char *name)
return 0;
}
-static int enable_flash_mcp55(struct pci_dev *dev, const char *name)
+static int enable_flash_mcp55(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t val;
uint16_t wordval;
@@ -1561,8 +1617,8 @@ static int enable_flash_mcp55(struct pci_dev *dev, const char *name)
wordval |= 0x7fff; /* 16M */
rpci_write_word(dev, 0x90, wordval);
- if (enable_flash_nvidia_common(dev, name))
- return ERROR_NONFATAL;
+ if (enable_flash_nvidia_common(cfg, dev, name))
+ return ERROR_FLASHROM_NONFATAL;
else
return 0;
}
@@ -1572,7 +1628,7 @@ static int enable_flash_mcp55(struct pci_dev *dev, const char *name)
* It is assumed that LPC chips need the MCP55 code and SPI chips need the
* code provided in enable_flash_mcp6x_7x_common.
*/
-static int enable_flash_mcp6x_7x(struct pci_dev *dev, const char *name)
+static int enable_flash_mcp6x_7x(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
int ret = 0, want_spi = 0;
uint8_t val;
@@ -1584,7 +1640,7 @@ static int enable_flash_mcp6x_7x(struct pci_dev *dev, const char *name)
switch ((val >> 5) & 0x3) {
case 0x0:
- ret = enable_flash_mcp55(dev, name);
+ ret = enable_flash_mcp55(cfg, dev, name);
internal_buses_supported &= BUS_LPC;
msg_pdbg("Flash bus type is LPC\n");
break;
@@ -1603,7 +1659,7 @@ static int enable_flash_mcp6x_7x(struct pci_dev *dev, const char *name)
msg_pinfo("Please send the log files created by \"flashrom -p internal -o logfile\" to\n"
"flashrom@flashrom.org with \"your board name: flashrom -V\" as the subject to\n"
"help us finish support for your chipset. Thanks.\n");
- return ERROR_NONFATAL;
+ return ERROR_FLASHROM_NONFATAL;
}
/* Force enable SPI and disable LPC? Not a good idea. */
@@ -1618,12 +1674,12 @@ static int enable_flash_mcp6x_7x(struct pci_dev *dev, const char *name)
/* Suppress unknown laptop warning if we booted from SPI. */
if (!ret && want_spi)
- laptop_ok = 1;
+ cfg->bcfg->laptop_ok = true;
return ret;
}
-static int enable_flash_ht1000(struct pci_dev *dev, const char *name)
+static int enable_flash_ht1000(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
uint8_t val;
@@ -1646,7 +1702,7 @@ static int enable_flash_ht1000(struct pci_dev *dev, const char *name)
* complete flash is mapped somewhere below 1G. The position can be determined
* by the BOOTCS PAR register.
*/
-static int get_flashbase_sc520(struct pci_dev *dev, const char *name)
+static int get_flashbase_sc520(const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name)
{
int i, bootcs_found = 0;
uint32_t parx = 0;
@@ -1655,7 +1711,7 @@ static int get_flashbase_sc520(struct pci_dev *dev, const char *name)
/* 1. Map MMCR */
mmcr = physmap("Elan SC520 MMCR", 0xfffef000, getpagesize());
if (mmcr == ERROR_PTR)
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
/* 2. Scan PAR0 (0x88) - PAR15 (0xc4) for
* BOOTCS region (PARx[31:29] = 100b)e
@@ -1830,7 +1886,7 @@ const struct penable chipset_enables[] = {
{0x8086, 0x1c4a, B_FS, DEP, "Intel", "H67", enable_flash_pch6},
{0x8086, 0x1c4b, B_FS, NT, "Intel", "HM67", enable_flash_pch6},
{0x8086, 0x1c4c, B_FS, NT, "Intel", "Q65", enable_flash_pch6},
- {0x8086, 0x1c4d, B_FS, NT, "Intel", "QS67", enable_flash_pch6},
+ {0x8086, 0x1c4d, B_FS, DEP, "Intel", "QS67", enable_flash_pch6},
{0x8086, 0x1c4e, B_FS, DEP, "Intel", "Q67", enable_flash_pch6},
{0x8086, 0x1c4f, B_FS, DEP, "Intel", "QM67", enable_flash_pch6},
{0x8086, 0x1c50, B_FS, NT, "Intel", "B65", enable_flash_pch6},
@@ -1849,7 +1905,7 @@ const struct penable chipset_enables[] = {
{0x8086, 0x1e48, B_FS, DEP, "Intel", "Q75", enable_flash_pch7},
{0x8086, 0x1e49, B_FS, DEP, "Intel", "B75", enable_flash_pch7},
{0x8086, 0x1e4a, B_FS, DEP, "Intel", "H77", enable_flash_pch7},
- {0x8086, 0x1e53, B_FS, NT, "Intel", "C216", enable_flash_pch7},
+ {0x8086, 0x1e53, B_FS, DEP, "Intel", "C216", enable_flash_pch7},
{0x8086, 0x1e55, B_FS, DEP, "Intel", "QM77", enable_flash_pch7},
{0x8086, 0x1e56, B_FS, DEP, "Intel", "QS77", enable_flash_pch7},
{0x8086, 0x1e57, B_FS, DEP, "Intel", "HM77", enable_flash_pch7},
@@ -1961,8 +2017,8 @@ const struct penable chipset_enables[] = {
{0x8086, 0x8cc1, B_FS, NT, "Intel", "9 Series", enable_flash_pch9},
{0x8086, 0x8cc2, B_FS, NT, "Intel", "9 Series Engineering Sample", enable_flash_pch9},
{0x8086, 0x8cc3, B_FS, NT, "Intel", "9 Series", enable_flash_pch9},
- {0x8086, 0x8cc4, B_FS, NT, "Intel", "Z97", enable_flash_pch9},
- {0x8086, 0x8cc6, B_FS, NT, "Intel", "H97", enable_flash_pch9},
+ {0x8086, 0x8cc4, B_FS, DEP, "Intel", "Z97", enable_flash_pch9},
+ {0x8086, 0x8cc6, B_FS, DEP, "Intel", "H97", enable_flash_pch9},
{0x8086, 0x8d40, B_FS, NT, "Intel", "C610/X99 (Wellsburg)", enable_flash_pch8_wb},
{0x8086, 0x8d41, B_FS, NT, "Intel", "C610/X99 (Wellsburg)", enable_flash_pch8_wb},
{0x8086, 0x8d42, B_FS, NT, "Intel", "C610/X99 (Wellsburg)", enable_flash_pch8_wb},
@@ -2020,6 +2076,9 @@ const struct penable chipset_enables[] = {
{0x8086, 0x9d58, B_S, NT, "Intel", "Kaby Lake U Premium", enable_flash_pch100},
{0x8086, 0x9d84, B_S, DEP, "Intel", "Cannon Lake U Premium", enable_flash_pch300},
{0x8086, 0x0284, B_S, DEP, "Intel", "Comet Lake U Premium", enable_flash_pch400},
+ {0x8086, 0x0285, B_S, DEP, "Intel", "Comet Lake U Base", enable_flash_pch400},
+ {0x8086, 0xa082, B_S, DEP, "Intel", "Tiger Lake U Premium", enable_flash_pch500},
+ {0x8086, 0xa088, B_S, DEP, "Intel", "Tiger Lake UP3", enable_flash_pch500},
{0x8086, 0xa141, B_S, NT, "Intel", "Sunrise Point Desktop Sample", enable_flash_pch100},
{0x8086, 0xa142, B_S, NT, "Intel", "Sunrise Point Unknown Sample", enable_flash_pch100},
{0x8086, 0xa143, B_S, DEP, "Intel", "H110", enable_flash_pch100},
@@ -2064,31 +2123,67 @@ const struct penable chipset_enables[] = {
{0x8086, 0xa247, B_S, NT, "Intel", "C620 Series Chipset Supersku", enable_flash_c620},
{0x8086, 0xa248, B_S, NT, "Intel", "C620 Series Chipset Supersku", enable_flash_c620},
{0x8086, 0xa249, B_S, NT, "Intel", "C620 Series Chipset Supersku", enable_flash_c620},
+ {0x8086, 0x1bca, B_S, NT, "Intel", "Emmitsburg Chipset SKU", enable_flash_c620},
{0x8086, 0xa2c4, B_S, NT, "Intel", "H270", enable_flash_pch100},
{0x8086, 0xa2c5, B_S, NT, "Intel", "Z270", enable_flash_pch100},
{0x8086, 0xa2c6, B_S, NT, "Intel", "Q270", enable_flash_pch100},
{0x8086, 0xa2c7, B_S, NT, "Intel", "Q250", enable_flash_pch100},
{0x8086, 0xa2c8, B_S, NT, "Intel", "B250", enable_flash_pch100},
{0x8086, 0xa2c9, B_S, NT, "Intel", "Z370", enable_flash_pch100},
+ {0x8086, 0xa2ca, B_S, DEP, "Intel", "H310C", enable_flash_pch100},
+ {0x8086, 0xa2cc, B_S, DEP, "Intel", "B365", enable_flash_pch100},
{0x8086, 0xa2d2, B_S, NT, "Intel", "X299", enable_flash_pch100},
{0x8086, 0x5ae8, B_S, DEP, "Intel", "Apollo Lake", enable_flash_apl},
{0x8086, 0x5af0, B_S, DEP, "Intel", "Apollo Lake", enable_flash_apl},
+ {0x8086, 0x3197, B_S, NT, "Intel", "Gemini Lake", enable_flash_glk},
+ {0x8086, 0x31e8, B_S, DEP, "Intel", "Gemini Lake", enable_flash_glk},
+ {0x8086, 0x4da4, B_S, DEP, "Intel", "Jasper Lake", enable_flash_jsl},
+ {0x8086, 0x4b24, B_S, DEP, "Intel", "Elkhart Lake", enable_flash_mcc},
{0x8086, 0xa303, B_S, NT, "Intel", "H310", enable_flash_pch300},
{0x8086, 0xa304, B_S, NT, "Intel", "H370", enable_flash_pch300},
- {0x8086, 0xa305, B_S, NT, "Intel", "Z390", enable_flash_pch300},
+ {0x8086, 0xa305, B_S, DEP, "Intel", "Z390", enable_flash_pch300},
{0x8086, 0xa306, B_S, NT, "Intel", "Q370", enable_flash_pch300},
{0x8086, 0xa308, B_S, NT, "Intel", "B360", enable_flash_pch300},
- {0x8086, 0xa309, B_S, NT, "Intel", "C246", enable_flash_pch300},
+ {0x8086, 0xa309, B_S, DEP, "Intel", "C246", enable_flash_pch300},
{0x8086, 0xa30a, B_S, NT, "Intel", "C242", enable_flash_pch300},
{0x8086, 0xa30c, B_S, NT, "Intel", "QM370", enable_flash_pch300},
{0x8086, 0xa30d, B_S, NT, "Intel", "HM370", enable_flash_pch300},
{0x8086, 0xa30e, B_S, DEP, "Intel", "CM246", enable_flash_pch300},
{0x8086, 0x3482, B_S, DEP, "Intel", "Ice Lake U Premium", enable_flash_pch300},
+ {0x8086, 0xa3c8, B_S, OK, "Intel", "B460", enable_flash_pch400},
+ {0x8086, 0x0684, B_S, NT, "Intel", "H470", enable_flash_pch400},
+ {0x8086, 0x0685, B_S, NT, "Intel", "Z490", enable_flash_pch400},
+ {0x8086, 0x0687, B_S, NT, "Intel", "Q470", enable_flash_pch400},
+ {0x8086, 0x068c, B_S, NT, "Intel", "QM480", enable_flash_pch400},
+ {0x8086, 0x068d, B_S, NT, "Intel", "HM470", enable_flash_pch400},
+ {0x8086, 0x068e, B_S, NT, "Intel", "WM490", enable_flash_pch400},
+ {0x8086, 0x0697, B_S, NT, "Intel", "W480", enable_flash_pch400},
+ {0x8086, 0x4384, B_S, NT, "Intel", "Q570", enable_flash_pch500},
+ {0x8086, 0x4385, B_S, NT, "Intel", "Z590", enable_flash_pch500},
+ {0x8086, 0x4386, B_S, NT, "Intel", "H570", enable_flash_pch500},
+ {0x8086, 0x4387, B_S, NT, "Intel", "B560", enable_flash_pch500},
+ {0x8086, 0x4388, B_S, NT, "Intel", "H510", enable_flash_pch500},
+ {0x8086, 0x438f, B_S, NT, "Intel", "W580", enable_flash_pch500},
+ {0x8086, 0x4389, B_S, NT, "Intel", "WM590", enable_flash_pch500},
+ {0x8086, 0x438a, B_S, NT, "Intel", "QM580", enable_flash_pch500},
+ {0x8086, 0x438b, B_S, DEP, "Intel", "HM570", enable_flash_pch500},
+ {0x8086, 0x54a4, B_S, DEP, "Intel", "Alder Lake-N", enable_flash_pch600},
+ {0x8086, 0x51a4, B_S, DEP, "Intel", "Alder Lake-P", enable_flash_pch600},
+ {0x8086, 0x7a87, B_S, NT, "Intel", "H610", enable_flash_pch600},
+ {0x8086, 0x7a86, B_S, NT, "Intel", "B660", enable_flash_pch600},
+ {0x8086, 0x7a85, B_S, NT, "Intel", "H670", enable_flash_pch600},
+ {0x8086, 0x7a83, B_S, NT, "Intel", "Q670", enable_flash_pch600},
+ {0x8086, 0x7a84, B_S, DEP, "Intel", "Z690", enable_flash_pch600},
+ {0x8086, 0x7a88, B_S, NT, "Intel", "W680", enable_flash_pch600},
+ {0x8086, 0x7a8a, B_S, NT, "Intel", "W685", enable_flash_pch600},
+ {0x8086, 0x7a8d, B_S, NT, "Intel", "WM690", enable_flash_pch600},
+ {0x8086, 0x7a8c, B_S, NT, "Intel", "HM670", enable_flash_pch600},
+ {0x8086, 0x7e23, B_S, DEP, "Intel", "Meteor Lake-P/M", enable_flash_mtl},
#endif
{0},
};
-int chipset_flash_enable(void)
+int chipset_flash_enable(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
int ret = -2; /* Nothing! */
@@ -2096,7 +2191,7 @@ int chipset_flash_enable(void)
/* Now let's try to find the chipset we have... */
for (i = 0; chipset_enables[i].vendor_name != NULL; i++) {
- dev = pci_dev_find(chipset_enables[i].vendor_id,
+ dev = pcidev_find(chipset_enables[i].vendor_id,
chipset_enables[i].device_id);
if (!dev)
continue;
@@ -2121,7 +2216,7 @@ int chipset_flash_enable(void)
if (chipset_enables[i].status == BAD) {
msg_perr("ERROR: This chipset is not supported yet.\n");
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
}
if (chipset_enables[i].status == NT) {
msg_pinfo("This chipset is marked as untested. If "
@@ -2137,7 +2232,7 @@ int chipset_flash_enable(void)
continue;
}
msg_pinfo("Enabling flash write... ");
- ret = chipset_enables[i].doit(dev, chipset_enables[i].device_name);
+ ret = chipset_enables[i].doit(cfg, dev, chipset_enables[i].device_name);
if (ret == NOT_DONE_YET) {
ret = -2;
msg_pinfo("OK - searching further chips.\n");
@@ -2145,9 +2240,9 @@ int chipset_flash_enable(void)
msg_pinfo("FAILED!\n");
else if (ret == 0)
msg_pinfo("OK.\n");
- else if (ret == ERROR_NONFATAL)
+ else if (ret == ERROR_FLASHROM_NONFATAL)
msg_pinfo("PROBLEMS, continuing anyway\n");
- if (ret == ERROR_FATAL) {
+ if (ret == ERROR_FLASHROM_FATAL) {
msg_perr("FATAL ERROR!\n");
return ret;
}
diff --git a/cli_classic.c b/cli_classic.c
index 3dbaec2b5..60f3fd508 100644
--- a/cli_classic.c
+++ b/cli_classic.c
@@ -22,15 +22,62 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
-#include <getopt.h>
+#include <cli_classic.h>
#include "flash.h"
#include "flashchips.h"
#include "fmap.h"
#include "programmer.h"
-#include "writeprotect.h"
#include "libflashrom.h"
+enum {
+ OPTION_IFD = 0x0100,
+ OPTION_FMAP,
+ OPTION_FMAP_FILE,
+ 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,
+ OPTION_PROGRESS,
+};
+
+struct cli_options {
+ bool read_it, extract_it, write_it, erase_it, verify_it;
+ bool dont_verify_it, dont_verify_all;
+ bool list_supported;
+#if CONFIG_PRINT_WIKI == 1
+ bool list_supported_wiki;
+#endif
+ char *filename;
+
+ const struct programmer_entry *prog;
+ char *pparam;
+
+ bool ifd, fmap;
+ struct flashrom_layout *layout;
+ struct layout_include_args *include_args;
+ char *layoutfile;
+ char *fmapfile;
+
+ unsigned int wp_start, wp_len;
+ bool enable_wp, disable_wp, print_wp_status;
+ bool set_wp_range, set_wp_region, print_wp_ranges;
+ char *wp_region;
+
+ bool force;
+ bool flash_name, flash_size;
+ bool show_progress;
+ char *logfile;
+ char *referencefile;
+ const char *chip_to_probe;
+};
+
static void cli_classic_usage(const char *name)
{
printf("Usage: %s [-h|-R|-L|"
@@ -39,40 +86,48 @@ static void cli_classic_usage(const char *name)
#endif
"\n\t-p <programmername>[:<parameters>] [-c <chipname>]\n"
"\t\t(--flash-name|--flash-size|\n"
- "\t\t [-E|(-r|-w|-v) <file>]\n"
- "\t\t [(-l <layoutfile>|--ifd| --fmap|--fmap-file <file>) [-i <imagename>]...]\n"
+ "\t\t [-E|-x|(-r|-w|-v) <file>]\n"
+ "\t\t [(-l <layoutfile>|--ifd| --fmap|--fmap-file <file>) [-i <region>[:<file>]]...]\n"
"\t\t [-n] [-N] [-f])]\n"
"\t[-V[V[V]]] [-o <logfile>]\n\n", name);
printf(" -h | --help print this help text\n"
" -R | --version print version (release)\n"
" -r | --read <file> read flash and save to <file>\n"
- " -w | --write <file> write <file> to flash\n"
- " -v | --verify <file> verify flash against <file>\n"
+ " -w | --write (<file>|-) write <file> or the content provided\n"
+ " on the standard input to flash\n"
+ " -v | --verify (<file>|-) verify flash against <file>\n"
+ " or the content provided on the standard input\n"
" -E | --erase erase flash memory\n"
" -V | --verbose more verbose output\n"
" -c | --chip <chipname> probe only for specified flash chip\n"
" -f | --force force specific operations (see man page)\n"
" -n | --noverify don't auto-verify\n"
" -N | --noverify-all verify included regions only (cf. -i)\n"
+ " -x | --extract extract regions to files\n"
" -l | --layout <layoutfile> read ROM layout from <layoutfile>\n"
" --wp-disable disable write protection\n"
" --wp-enable enable write protection\n"
- " --wp-list list write protect range\n"
- " --wp-status show write protect status\n"
- " --wp-range=<start>,<len> set write protect range\n"
+ " --wp-list list supported write protection ranges\n"
+ " --wp-status show write protection status\n"
+ " --wp-range=<start>,<len> set write protection range (use --wp-range=0,0\n"
+ " to unprotect the entire flash)\n"
+ " --wp-region <region> set write protection region\n"
" --flash-name read out the detected flash name\n"
" --flash-size read out the detected flash size\n"
" --fmap read ROM layout from fmap embedded in ROM\n"
" --fmap-file <fmapfile> read ROM layout from fmap in <fmapfile>\n"
" --ifd read layout from an Intel Firmware Descriptor\n"
- " -i | --image <name> only flash image <name> from flash layout\n"
+ " -i | --include <region>[:<file>] only read/write image <region> from layout\n"
+ " (optionally with data from <file>)\n"
+ " --image <region>[:<file>] deprecated, please use --include\n"
" -o | --output <logfile> log output to <logfile>\n"
" --flash-contents <ref-file> assume flash contents to be <ref-file>\n"
" -L | --list-supported print supported devices\n"
#if CONFIG_PRINT_WIKI == 1
" -z | --list-supported-wiki print supported devices in wiki syntax\n"
#endif
+ " --progress show progress percentage on the standard output\n"
" -p | --programmer <name>[:<param>] specify the programmer device. One of\n");
list_programmers_linebreak(4, 80, 0);
printf(".\n\nYou can specify one of -h, -R, -L, "
@@ -105,11 +160,21 @@ static int check_filename(char *filename, const char *type)
return 1;
}
/* Not an error, but maybe the user intended to specify a CLI option instead of a file name. */
- if (filename[0] == '-')
+ if (filename[0] == '-' && filename[1] != '\0')
fprintf(stderr, "Warning: Supplied %s file name starts with -\n", type);
return 0;
}
+/* Ensure a file is open by means of fstat */
+static bool check_file(FILE *file)
+{
+ struct stat statbuf;
+
+ if (fstat(fileno(file), &statbuf) < 0)
+ return false;
+ return true;
+}
+
static int parse_wp_range(unsigned int *start, unsigned int *len)
{
char *endptr = NULL, *token = NULL;
@@ -136,98 +201,425 @@ static int parse_wp_range(unsigned int *start, unsigned int *len)
return 0;
}
-int main(int argc, char *argv[])
+static int print_wp_range(struct flashrom_flashctx *flash, size_t start, size_t len)
{
- const struct flashchip *chip = NULL;
- /* Probe for up to eight flash chips. */
- struct flashctx flashes[8] = {{0}};
- struct flashctx *fill_flash;
- const char *name;
- int namelen, opt, i, j;
- int startchip = -1, chipcount = 0, option_index = 0, force = 0, ifd = 0, fmap = 0;
-#if CONFIG_PRINT_WIKI == 1
- int list_supported_wiki = 0;
-#endif
- int flash_name = 0, flash_size = 0;
- int set_wp_enable = 0, set_wp_disable = 0, wp_status = 0;
- int set_wp_range = 0, set_wp_region = 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;
- enum programmer prog = PROGRAMMER_INVALID;
- enum {
- OPTION_IFD = 0x0100,
- OPTION_FMAP,
- OPTION_FMAP_FILE,
- 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;
- unsigned int wp_start = 0, wp_len = 0;
+ /* Start address and length */
+ msg_ginfo("start=0x%08zx length=0x%08zx ", start, len);
- static const char optstring[] = "r:Rw:v:nNVEfc:l:i:p:Lzho:";
- static const struct option long_options[] = {
- {"read", 1, NULL, 'r'},
- {"write", 1, NULL, 'w'},
- {"erase", 0, NULL, 'E'},
- {"verify", 1, NULL, 'v'},
- {"noverify", 0, NULL, 'n'},
- {"noverify-all", 0, NULL, 'N'},
- {"chip", 1, NULL, 'c'},
- {"verbose", 0, NULL, 'V'},
- {"force", 0, NULL, 'f'},
- {"layout", 1, NULL, 'l'},
- {"ifd", 0, NULL, OPTION_IFD},
- {"fmap", 0, NULL, OPTION_FMAP},
- {"fmap-file", 1, NULL, OPTION_FMAP_FILE},
- {"image", 1, NULL, 'i'},
- {"flash-contents", 1, NULL, OPTION_FLASH_CONTENTS},
- {"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", required_argument, NULL, 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'},
- {"help", 0, NULL, 'h'},
- {"version", 0, NULL, 'R'},
- {"output", 1, NULL, 'o'},
- {NULL, 0, NULL, 0},
- };
+ /* Easily readable description like 'none' or 'lower 1/8' */
+ size_t chip_len = flashrom_flash_getsize(flash);
- char *filename = NULL;
- char *referencefile = NULL;
- char *layoutfile = NULL;
- char *fmapfile = NULL;
-#ifndef STANDALONE
- char *logfile = NULL;
-#endif /* !STANDALONE */
- char *tempstr = NULL;
- char *pparam = NULL;
- struct layout_include_args *include_args = NULL;
- char *wp_mode_opt = NULL;
+ if (len == 0) {
+ msg_ginfo("(none)");
+ } else if (len == chip_len) {
+ msg_ginfo("(all)");
+ } else {
+ const char *location = "";
+ if (start == 0)
+ location = "lower ";
+ if (start == chip_len - len)
+ location = "upper ";
- flashrom_set_log_callback((flashrom_log_callback *)&flashrom_print_cb);
+ /* Remove common factors of 2 to simplify */
+ /* the (range_len/chip_len) fraction. */
+ while ((chip_len % 2) == 0 && (len % 2) == 0) {
+ chip_len /= 2;
+ len /= 2;
+ }
- print_version();
- print_banner();
+ msg_ginfo("(%s%zu/%zu)", location, len, chip_len);
+ }
- if (selfcheck())
- exit(1);
+ return 0;
+}
+
+static const char *get_wp_error_str(int err)
+{
+ switch (err) {
+ case FLASHROM_WP_ERR_CHIP_UNSUPPORTED:
+ return "WP operations are not implemented for this chip";
+ case FLASHROM_WP_ERR_READ_FAILED:
+ return "failed to read the current WP configuration";
+ case FLASHROM_WP_ERR_WRITE_FAILED:
+ return "failed to write the new WP configuration";
+ case FLASHROM_WP_ERR_VERIFY_FAILED:
+ return "unexpected WP configuration read back from chip";
+ case FLASHROM_WP_ERR_MODE_UNSUPPORTED:
+ return "the requested protection mode is not supported";
+ case FLASHROM_WP_ERR_RANGE_UNSUPPORTED:
+ return "the requested protection range is not supported";
+ case FLASHROM_WP_ERR_RANGE_LIST_UNAVAILABLE:
+ return "could not determine what protection ranges are available";
+ case FLASHROM_WP_ERR_UNSUPPORTED_STATE:
+ return "can't operate on current WP configuration of the chip";
+ }
+ return "unknown WP error";
+}
+
+static int wp_cli(
+ struct flashctx *flash,
+ bool enable_wp,
+ bool disable_wp,
+ bool print_wp_status,
+ bool print_wp_ranges,
+ bool set_wp_range,
+ uint32_t wp_start,
+ uint32_t wp_len)
+{
+ if (print_wp_ranges) {
+ struct flashrom_wp_ranges *list;
+ enum flashrom_wp_result ret = flashrom_wp_get_available_ranges(&list, flash);
+ if (ret != FLASHROM_WP_OK) {
+ msg_gerr("Failed to get list of protection ranges: %s\n",
+ get_wp_error_str(ret));
+ return 1;
+ }
+ size_t count = flashrom_wp_ranges_get_count(list);
+
+ msg_ginfo("Available protection ranges:\n");
+ for (size_t i = 0; i < count; i++) {
+ size_t start, len;
+
+ flashrom_wp_ranges_get_range(&start, &len, list, i);
+ msg_ginfo("\t");
+ print_wp_range(flash, start, len);
+ msg_ginfo("\n");
+ }
+
+ flashrom_wp_ranges_release(list);
+ }
+
+ if (set_wp_range || disable_wp || enable_wp) {
+ enum flashrom_wp_mode old_mode = FLASHROM_WP_MODE_DISABLED;
+ struct flashrom_wp_cfg *cfg = NULL;
+ enum flashrom_wp_result ret = flashrom_wp_cfg_new(&cfg);
+
+ if (ret == FLASHROM_WP_OK)
+ ret = flashrom_wp_read_cfg(cfg, flash);
+
+ if (ret == FLASHROM_WP_OK) {
+ /* Store current WP mode for printing help text if */
+ /* changing the cfg fails. */
+ old_mode = flashrom_wp_get_mode(cfg);
+
+ if (set_wp_range)
+ flashrom_wp_set_range(cfg, wp_start, wp_len);
+
+ if (disable_wp)
+ flashrom_wp_set_mode(cfg, FLASHROM_WP_MODE_DISABLED);
+
+ if (enable_wp)
+ flashrom_wp_set_mode(cfg, FLASHROM_WP_MODE_HARDWARE);
+
+ ret = flashrom_wp_write_cfg(flash, cfg);
+ }
+
+ flashrom_wp_cfg_release(cfg);
+
+ if (ret != FLASHROM_WP_OK) {
+ msg_gerr("Failed to apply new WP settings: %s\n",
+ get_wp_error_str(ret));
+
+ /* Warn user if active WP is likely to have caused failure */
+ if (ret == FLASHROM_WP_ERR_VERIFY_FAILED) {
+ switch (old_mode) {
+ case FLASHROM_WP_MODE_HARDWARE:
+ msg_gerr("Note: hardware status register protection is enabled. "
+ "The chip's WP# pin must be set to an inactive voltage "
+ "level to be able to change the WP settings.\n");
+ break;
+ case FLASHROM_WP_MODE_POWER_CYCLE:
+ msg_gerr("Note: power-cycle status register protection is enabled. "
+ "A power-off, power-on cycle is usually required to change "
+ "the chip's WP settings.\n");
+ break;
+ case FLASHROM_WP_MODE_PERMANENT:
+ msg_gerr("Note: permanent status register protection is enabled. "
+ "The chip's WP settings cannot be modified.\n");
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 1;
+ }
+
+ if (disable_wp)
+ msg_ginfo("Disabled hardware protection\n");
+
+ if (enable_wp)
+ msg_ginfo("Enabled hardware protection\n");
+
+ if (set_wp_range) {
+ msg_ginfo("Activated protection range: ");
+ print_wp_range(flash, wp_start, wp_len);
+ msg_ginfo("\n");
+ }
+ }
+
+ if (print_wp_status) {
+ size_t start, len;
+ enum flashrom_wp_mode mode;
+ struct flashrom_wp_cfg *cfg = NULL;
+ enum flashrom_wp_result ret = flashrom_wp_cfg_new(&cfg);
+
+ if (ret == FLASHROM_WP_OK)
+ ret = flashrom_wp_read_cfg(cfg, flash);
+
+ if (ret != FLASHROM_WP_OK) {
+ msg_gerr("Failed to get WP status: %s\n",
+ get_wp_error_str(ret));
+
+ flashrom_wp_cfg_release(cfg);
+ return 1;
+ }
+
+ flashrom_wp_get_range(&start, &len, cfg);
+ mode = flashrom_wp_get_mode(cfg);
+ flashrom_wp_cfg_release(cfg);
+
+ msg_ginfo("Protection range: ");
+ print_wp_range(flash, start, len);
+ msg_ginfo("\n");
+
+ msg_ginfo("Protection mode: ");
+ switch (mode) {
+ case FLASHROM_WP_MODE_DISABLED:
+ msg_ginfo("disabled");
+ break;
+ case FLASHROM_WP_MODE_HARDWARE:
+ msg_ginfo("hardware");
+ break;
+ case FLASHROM_WP_MODE_POWER_CYCLE:
+ msg_ginfo("power_cycle");
+ break;
+ case FLASHROM_WP_MODE_PERMANENT:
+ msg_ginfo("permanent");
+ break;
+ default:
+ msg_ginfo("unknown");
+ break;
+ }
+ msg_ginfo("\n");
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Reads content to buffer from one or more files.
+ *
+ * Reads content to supplied buffer from files. If a filename is specified for
+ * individual regions using the partial read syntax ('-i <region>[:<filename>]')
+ * then this will read file data into the corresponding region in the
+ * supplied buffer.
+ *
+ * @param layout The layout to be used.
+ * @param buf Chip-sized buffer to write data to
+ * @return 0 on success
+ */
+static int read_buf_from_include_args(const struct flashrom_layout *const layout, unsigned char *buf)
+{
+ const struct romentry *entry = NULL;
+
+ /*
+ * Content will be read from -i args, so they must not overlap since
+ * we need to know exactly what content to write to the ROM.
+ */
+ if (included_regions_overlap(layout)) {
+ msg_gerr("Error: Included regions must not overlap when writing.\n");
+ return 1;
+ }
+
+ while ((entry = layout_next_included(layout, entry))) {
+ if (!entry->file)
+ continue;
+ const struct flash_region *region = &entry->region;
+ if (read_buf_from_file(buf + region->start,
+ region->end - region->start + 1, entry->file))
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * @brief Writes content from buffer to one or more files.
+ *
+ * Writes content from supplied buffer to files. If a filename is specified for
+ * individual regions using the partial read syntax ('-i <region>[:<filename>]')
+ * then this will write files using data from the corresponding region in the
+ * supplied buffer.
+ *
+ * @param layout The layout to be used.
+ * @param buf Chip-sized buffer to read data from
+ * @return 0 on success
+ */
+static int write_buf_to_include_args(const struct flashrom_layout *const layout, unsigned char *buf)
+{
+ const struct romentry *entry = NULL;
+
+ while ((entry = layout_next_included(layout, entry))) {
+ if (!entry->file)
+ continue;
+ const struct flash_region *region = &entry->region;
+ if (write_buf_to_file(buf + region->start,
+ region->end - region->start + 1, entry->file))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int do_read(struct flashctx *const flash, const char *const filename)
+{
+ int ret;
+
+ unsigned long size = flashrom_flash_getsize(flash);
+ unsigned char *buf = calloc(size, sizeof(unsigned char));
+ if (!buf) {
+ msg_gerr("Memory allocation failed!\n");
+ return 1;
+ }
+
+ ret = flashrom_image_read(flash, buf, size);
+ if (ret > 0)
+ goto free_out;
+
+ if (write_buf_to_include_args(get_layout(flash), buf)) {
+ ret = 1;
+ goto free_out;
+ }
+ if (filename)
+ ret = write_buf_to_file(buf, size, filename);
+
+free_out:
+ free(buf);
+ return ret;
+}
+
+static int do_extract(struct flashctx *const flash)
+{
+ prepare_layout_for_extraction(flash);
+ return do_read(flash, NULL);
+}
+
+static int do_write(struct flashctx *const flash, const char *const filename, const char *const referencefile)
+{
+ const size_t flash_size = flashrom_flash_getsize(flash);
+ int ret = 1;
+
+ uint8_t *const newcontents = malloc(flash_size);
+ uint8_t *const refcontents = referencefile ? malloc(flash_size) : NULL;
+
+ if (!newcontents || (referencefile && !refcontents)) {
+ msg_gerr("Out of memory!\n");
+ goto _free_ret;
+ }
+
+ /* Read '-w' argument first... */
+ if (read_buf_from_file(newcontents, flash_size, filename))
+ goto _free_ret;
+ /*
+ * ... then update newcontents with contents from files provided to '-i'
+ * args if needed.
+ */
+ if (read_buf_from_include_args(get_layout(flash), newcontents))
+ goto _free_ret;
+
+ if (referencefile) {
+ if (read_buf_from_file(refcontents, flash_size, referencefile))
+ goto _free_ret;
+ }
+
+ ret = flashrom_image_write(flash, newcontents, flash_size, refcontents);
+
+_free_ret:
+ free(refcontents);
+ free(newcontents);
+ return ret;
+}
+
+static int do_verify(struct flashctx *const flash, const char *const filename)
+{
+ const size_t flash_size = flashrom_flash_getsize(flash);
+ int ret = 1;
+
+ uint8_t *const newcontents = malloc(flash_size);
+ if (!newcontents) {
+ msg_gerr("Out of memory!\n");
+ goto _free_ret;
+ }
+
+ /* Read '-v' argument first... */
+ if (read_buf_from_file(newcontents, flash_size, filename))
+ goto _free_ret;
+ /*
+ * ... then update newcontents with contents from files provided to '-i'
+ * args if needed.
+ */
+ if (read_buf_from_include_args(get_layout(flash), newcontents))
+ goto _free_ret;
+
+ ret = flashrom_image_verify(flash, newcontents, flash_size);
+
+_free_ret:
+ free(newcontents);
+ return ret;
+}
+
+/* Returns the number of buses commonly supported by the current programmer and flash chip where the latter
+ * can not be completely accessed due to size/address limits of the programmer. */
+static unsigned int count_max_decode_exceedings(const struct flashctx *flash,
+ const struct decode_sizes *max_rom_decode_)
+{
+ unsigned int limitexceeded = 0;
+ uint32_t size = flash->chip->total_size * 1024;
+ enum chipbustype buses = flash->mst->buses_supported & flash->chip->bustype;
+
+ if ((buses & BUS_PARALLEL) && (max_rom_decode_->parallel < size)) {
+ limitexceeded++;
+ msg_pdbg("Chip size %"PRIu32" kB is bigger than supported "
+ "size %"PRIu32" kB of chipset/board/programmer "
+ "for %s interface, "
+ "probe/read/erase/write may fail. ", size / 1024,
+ max_rom_decode_->parallel / 1024, "Parallel");
+ }
+ if ((buses & BUS_LPC) && (max_rom_decode_->lpc < size)) {
+ limitexceeded++;
+ msg_pdbg("Chip size %"PRIu32" kB is bigger than supported "
+ "size %"PRIu32" kB of chipset/board/programmer "
+ "for %s interface, "
+ "probe/read/erase/write may fail. ", size / 1024,
+ max_rom_decode_->lpc / 1024, "LPC");
+ }
+ if ((buses & BUS_FWH) && (max_rom_decode_->fwh < size)) {
+ limitexceeded++;
+ msg_pdbg("Chip size %"PRIu32" kB is bigger than supported "
+ "size %"PRIu32" kB of chipset/board/programmer "
+ "for %s interface, "
+ "probe/read/erase/write may fail. ", size / 1024,
+ max_rom_decode_->fwh / 1024, "FWH");
+ }
+ if ((buses & BUS_SPI) && (max_rom_decode_->spi < size)) {
+ limitexceeded++;
+ msg_pdbg("Chip size %"PRIu32" kB is bigger than supported "
+ "size %"PRIu32" kB of chipset/board/programmer "
+ "for %s interface, "
+ "probe/read/erase/write may fail. ", size / 1024,
+ max_rom_decode_->spi / 1024, "SPI");
+ }
+ return limitexceeded;
+}
+
+static void parse_options(int argc, char **argv, const char *optstring,
+ const struct option *long_options,
+ struct cli_options *options)
+{
+ const char *name;
+ int namelen, opt;
+ int option_index = 0, operation_specified = 0;
- setbuf(stdout, NULL);
/* FIXME: Delay all operation_specified checks until after command
* line parsing to allow --help overriding everything else.
*/
@@ -236,34 +628,38 @@ int main(int argc, char *argv[])
switch (opt) {
case 'r':
cli_classic_validate_singleop(&operation_specified);
- filename = strdup(optarg);
- read_it = 1;
+ options->filename = strdup(optarg);
+ options->read_it = true;
break;
case 'w':
cli_classic_validate_singleop(&operation_specified);
- filename = strdup(optarg);
- write_it = 1;
+ options->filename = strdup(optarg);
+ options->write_it = true;
break;
case 'v':
//FIXME: gracefully handle superfluous -v
cli_classic_validate_singleop(&operation_specified);
- if (dont_verify_it) {
+ if (options->dont_verify_it) {
cli_classic_abort_usage("--verify and --noverify are mutually exclusive. Aborting.\n");
}
- filename = strdup(optarg);
- verify_it = 1;
+ options->filename = strdup(optarg);
+ options->verify_it = true;
break;
case 'n':
- if (verify_it) {
+ if (options->verify_it) {
cli_classic_abort_usage("--verify and --noverify are mutually exclusive. Aborting.\n");
}
- dont_verify_it = 1;
+ options->dont_verify_it = true;
break;
case 'N':
- dont_verify_all = 1;
+ options->dont_verify_all = true;
+ break;
+ case 'x':
+ cli_classic_validate_singleop(&operation_specified);
+ options->extract_it = true;
break;
case 'c':
- chip_to_probe = strdup(optarg);
+ options->chip_to_probe = strdup(optarg);
break;
case 'V':
verbose_screen++;
@@ -272,123 +668,125 @@ int main(int argc, char *argv[])
break;
case 'E':
cli_classic_validate_singleop(&operation_specified);
- erase_it = 1;
+ options->erase_it = true;
break;
case 'f':
- force = 1;
+ options->force = true;
break;
case 'l':
- if (layoutfile)
+ if (options->layoutfile)
cli_classic_abort_usage("Error: --layout specified more than once. Aborting.\n");
- if (ifd)
+ if (options->ifd)
cli_classic_abort_usage("Error: --layout and --ifd both specified. Aborting.\n");
- if (fmap)
+ if (options->fmap)
cli_classic_abort_usage("Error: --layout and --fmap-file both specified. Aborting.\n");
- layoutfile = strdup(optarg);
+ options->layoutfile = strdup(optarg);
break;
case OPTION_IFD:
- if (layoutfile)
+ if (options->layoutfile)
cli_classic_abort_usage("Error: --layout and --ifd both specified. Aborting.\n");
- if (fmap)
+ if (options->fmap)
cli_classic_abort_usage("Error: --fmap-file and --ifd both specified. Aborting.\n");
- ifd = 1;
+ options->ifd = true;
break;
case OPTION_FMAP_FILE:
- if (fmap)
+ if (options->fmap)
cli_classic_abort_usage("Error: --fmap or --fmap-file specified "
"more than once. Aborting.\n");
- if (ifd)
+ if (options->ifd)
cli_classic_abort_usage("Error: --fmap-file and --ifd both specified. Aborting.\n");
- if (layoutfile)
+ if (options->layoutfile)
cli_classic_abort_usage("Error: --fmap-file and --layout both specified. Aborting.\n");
- fmapfile = strdup(optarg);
- fmap = 1;
+ options->fmapfile = strdup(optarg);
+ options->fmap = true;
break;
case OPTION_FMAP:
- if (fmap)
+ if (options->fmap)
cli_classic_abort_usage("Error: --fmap or --fmap-file specified "
"more than once. Aborting.\n");
- if (ifd)
+ if (options->ifd)
cli_classic_abort_usage("Error: --fmap and --ifd both specified. Aborting.\n");
- if (layoutfile)
+ if (options->layoutfile)
cli_classic_abort_usage("Error: --layout and --fmap both specified. Aborting.\n");
- fmap = 1;
+ options->fmap = true;
break;
case 'i':
- tempstr = strdup(optarg);
- if (register_include_arg(&include_args, tempstr)) {
- free(tempstr);
+ if (register_include_arg(&options->include_args, optarg))
cli_classic_abort_usage(NULL);
- }
break;
case OPTION_FLASH_CONTENTS:
- if (referencefile)
+ if (options->referencefile)
cli_classic_abort_usage("Error: --flash-contents specified more than once."
"Aborting.\n");
- referencefile = strdup(optarg);
+ options->referencefile = strdup(optarg);
break;
case OPTION_FLASH_NAME:
cli_classic_validate_singleop(&operation_specified);
- flash_name = 1;
+ options->flash_name = true;
break;
case OPTION_FLASH_SIZE:
cli_classic_validate_singleop(&operation_specified);
- flash_size = 1;
+ options->flash_size = true;
break;
case OPTION_WP_STATUS:
- wp_status = 1;
+ options->print_wp_status = true;
break;
case OPTION_WP_LIST:
- wp_list = 1;
+ options->print_wp_ranges = true;
break;
case OPTION_WP_SET_RANGE:
- if (parse_wp_range(&wp_start, &wp_len) < 0)
+ if (parse_wp_range(&options->wp_start, &options->wp_len) < 0)
cli_classic_abort_usage("Incorrect wp-range arguments provided.\n");
- set_wp_range = 1;
+ options->set_wp_range = true;
+ break;
+ case OPTION_WP_SET_REGION:
+ options->set_wp_region = true;
+ options->wp_region = strdup(optarg);
break;
case OPTION_WP_ENABLE:
- set_wp_enable = 1;
- if (optarg)
- wp_mode_opt = strdup(optarg);
+ options->enable_wp = true;
break;
case OPTION_WP_DISABLE:
- set_wp_disable = 1;
+ options->disable_wp = true;
break;
case 'L':
cli_classic_validate_singleop(&operation_specified);
- list_supported = 1;
+ options->list_supported = true;
break;
case 'z':
#if CONFIG_PRINT_WIKI == 1
cli_classic_validate_singleop(&operation_specified);
- list_supported_wiki = 1;
+ options->list_supported_wiki = true;
#else
cli_classic_abort_usage("Error: Wiki output was not "
"compiled in. Aborting.\n");
#endif
break;
case 'p':
- if (prog != PROGRAMMER_INVALID) {
+ if (options->prog != NULL) {
cli_classic_abort_usage("Error: --programmer specified "
"more than once. You can separate "
"multiple\nparameters for a programmer "
"with \",\". Please see the man page "
"for details.\n");
}
- for (prog = 0; prog < PROGRAMMER_INVALID; prog++) {
- name = programmer_table[prog].name;
+ size_t p;
+ for (p = 0; p < programmer_table_size; p++) {
+ name = programmer_table[p]->name;
namelen = strlen(name);
if (strncmp(optarg, name, namelen) == 0) {
switch (optarg[namelen]) {
case ':':
- pparam = strdup(optarg + namelen + 1);
- if (!strlen(pparam)) {
- free(pparam);
- pparam = NULL;
+ options->pparam = strdup(optarg + namelen + 1);
+ if (!strlen(options->pparam)) {
+ free(options->pparam);
+ options->pparam = NULL;
}
+ options->prog = programmer_table[p];
break;
case '\0':
+ options->prog = programmer_table[p];
break;
default:
/* The continue refers to the
@@ -401,7 +799,7 @@ int main(int argc, char *argv[])
break;
}
}
- if (prog == PROGRAMMER_INVALID) {
+ if (options->prog == NULL) {
fprintf(stderr, "Error: Unknown programmer \"%s\". Valid choices are:\n",
optarg);
list_programmers_linebreak(0, 80, 0);
@@ -420,19 +818,18 @@ int main(int argc, char *argv[])
exit(0);
break;
case 'o':
-#ifdef STANDALONE
- cli_classic_abort_usage("Log file not supported in standalone mode. Aborting.\n");
-#else /* STANDALONE */
- if (logfile) {
+ if (options->logfile) {
fprintf(stderr, "Warning: -o/--output specified multiple times.\n");
- free(logfile);
+ free(options->logfile);
}
- logfile = strdup(optarg);
- if (logfile[0] == '\0') {
+ options->logfile = strdup(optarg);
+ if (options->logfile[0] == '\0') {
cli_classic_abort_usage("No log filename specified.\n");
}
-#endif /* STANDALONE */
+ break;
+ case OPTION_PROGRESS:
+ options->show_progress = true;
break;
default:
cli_classic_abort_usage(NULL);
@@ -442,38 +839,119 @@ int main(int argc, char *argv[])
if (optind < argc)
cli_classic_abort_usage("Error: Extra parameter found.\n");
- if ((read_it | write_it | verify_it) && check_filename(filename, "image"))
+}
+
+static void free_options(struct cli_options *options)
+{
+ cleanup_include_args(&options->include_args);
+ free(options->filename);
+ free(options->fmapfile);
+ free(options->referencefile);
+ free(options->layoutfile);
+ free(options->pparam);
+ free(options->wp_region);
+ free(options->logfile);
+ free((char *)options->chip_to_probe);
+}
+
+int main(int argc, char *argv[])
+{
+ const struct flashchip *chip = NULL;
+ /* Probe for up to eight flash chips. */
+ struct flashctx flashes[8] = {{0}};
+ struct flashctx *fill_flash;
+ char *tempstr = NULL;
+ int startchip = -1, chipcount = 0;
+ int i, j;
+ int ret = 0;
+
+ struct cli_options options = { 0 };
+ static const char optstring[] = "r:Rw:v:nNVEfc:l:i:p:Lzho:x";
+ static const struct option long_options[] = {
+ {"read", 1, NULL, 'r'},
+ {"write", 1, NULL, 'w'},
+ {"erase", 0, NULL, 'E'},
+ {"verify", 1, NULL, 'v'},
+ {"noverify", 0, NULL, 'n'},
+ {"noverify-all", 0, NULL, 'N'},
+ {"extract", 0, NULL, 'x'},
+ {"chip", 1, NULL, 'c'},
+ {"verbose", 0, NULL, 'V'},
+ {"force", 0, NULL, 'f'},
+ {"layout", 1, NULL, 'l'},
+ {"ifd", 0, NULL, OPTION_IFD},
+ {"fmap", 0, NULL, OPTION_FMAP},
+ {"fmap-file", 1, NULL, OPTION_FMAP_FILE},
+ {"image", 1, NULL, 'i'}, // (deprecated): back compatibility.
+ {"include", 1, NULL, 'i'},
+ {"flash-contents", 1, NULL, OPTION_FLASH_CONTENTS},
+ {"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, NULL, OPTION_WP_STATUS},
+ {"wp-list", 0, NULL, OPTION_WP_LIST},
+ {"wp-range", 1, NULL, OPTION_WP_SET_RANGE},
+ {"wp-region", 1, NULL, OPTION_WP_SET_REGION},
+ {"wp-enable", 0, NULL, OPTION_WP_ENABLE},
+ {"wp-disable", 0, NULL, OPTION_WP_DISABLE},
+ {"list-supported", 0, NULL, 'L'},
+ {"list-supported-wiki", 0, NULL, 'z'},
+ {"programmer", 1, NULL, 'p'},
+ {"help", 0, NULL, 'h'},
+ {"version", 0, NULL, 'R'},
+ {"output", 1, NULL, 'o'},
+ {"progress", 0, NULL, OPTION_PROGRESS},
+ {NULL, 0, NULL, 0},
+ };
+
+ /*
+ * Safety-guard against a user who has (mistakenly) closed
+ * stdout or stderr before exec'ing flashrom. We disable
+ * logging in this case to prevent writing log data to a flash
+ * chip when a flash device gets opened with fd 1 or 2.
+ */
+ if (check_file(stdout) && check_file(stderr)) {
+ flashrom_set_log_callback(&flashrom_print_cb);
+ }
+
+ print_version();
+ print_banner();
+
+ /* FIXME: Delay calibration should happen in programmer code. */
+ if (flashrom_init(1))
+ exit(1);
+
+ setbuf(stdout, NULL);
+
+ parse_options(argc, argv, optstring, long_options, &options);
+
+ if ((options.read_it | options.write_it | options.verify_it) && check_filename(options.filename, "image"))
cli_classic_abort_usage(NULL);
- if (layoutfile && check_filename(layoutfile, "layout"))
+ if (options.layoutfile && check_filename(options.layoutfile, "layout"))
cli_classic_abort_usage(NULL);
- if (fmapfile && check_filename(fmapfile, "fmap"))
+ if (options.fmapfile && check_filename(options.fmapfile, "fmap"))
cli_classic_abort_usage(NULL);
- if (referencefile && check_filename(referencefile, "reference"))
+ if (options.referencefile && check_filename(options.referencefile, "reference"))
cli_classic_abort_usage(NULL);
-
-#ifndef STANDALONE
- if (logfile && check_filename(logfile, "log"))
+ if (options.logfile && check_filename(options.logfile, "log"))
cli_classic_abort_usage(NULL);
- if (logfile && open_logfile(logfile))
+ if (options.logfile && open_logfile(options.logfile))
cli_classic_abort_usage(NULL);
-#endif /* !STANDALONE */
#if CONFIG_PRINT_WIKI == 1
- if (list_supported_wiki) {
+ if (options.list_supported_wiki) {
print_supported_wiki();
goto out;
}
#endif
- if (list_supported) {
+ if (options.list_supported) {
if (print_supported())
ret = 1;
goto out;
}
-#ifndef STANDALONE
start_logging();
-#endif /* !STANDALONE */
print_buildinfo();
msg_gdbg("Command line (%i args):", argc - 1);
@@ -482,22 +960,22 @@ int main(int argc, char *argv[])
}
msg_gdbg("\n");
- if (layoutfile && read_romlayout(layoutfile)) {
+ if (options.layoutfile && layout_from_file(&options.layout, options.layoutfile)) {
ret = 1;
goto out;
}
- if (!ifd && !fmap && process_include_args(get_global_layout(), include_args)) {
+ if (!options.ifd && !options.fmap && process_include_args(options.layout, options.include_args)) {
ret = 1;
goto out;
}
/* Does a chip with the requested name exist in the flashchips array? */
- if (chip_to_probe) {
+ if (options.chip_to_probe) {
for (chip = flashchips; chip && chip->name; chip++)
- if (!strcmp(chip->name, chip_to_probe))
+ if (!strcmp(chip->name, options.chip_to_probe))
break;
if (!chip || !chip->name) {
- msg_cerr("Error: Unknown chip '%s' specified.\n", chip_to_probe);
+ msg_cerr("Error: Unknown chip '%s' specified.\n", options.chip_to_probe);
msg_gerr("Run flashrom -L to view the hardware supported in this flashrom version.\n");
ret = 1;
goto out;
@@ -505,13 +983,15 @@ int main(int argc, char *argv[])
/* Keep chip around for later usage in case a forced read is requested. */
}
- if (prog == PROGRAMMER_INVALID) {
- if (CONFIG_DEFAULT_PROGRAMMER != PROGRAMMER_INVALID) {
- prog = CONFIG_DEFAULT_PROGRAMMER;
+ if (options.prog == NULL) {
+ const struct programmer_entry *const default_programmer = CONFIG_DEFAULT_PROGRAMMER_NAME;
+
+ if (default_programmer) {
+ options.prog = default_programmer;
/* We need to strdup here because we free(pparam) unconditionally later. */
- pparam = strdup(CONFIG_DEFAULT_PROGRAMMER_ARGS);
+ options.pparam = strdup(CONFIG_DEFAULT_PROGRAMMER_ARGS);
msg_pinfo("Using default programmer \"%s\" with arguments \"%s\".\n",
- programmer_table[CONFIG_DEFAULT_PROGRAMMER].name, pparam);
+ default_programmer->name, options.pparam);
} else {
msg_perr("Please select a programmer with the --programmer parameter.\n"
#if CONFIG_INTERNAL == 1
@@ -525,22 +1005,19 @@ int main(int argc, char *argv[])
}
}
- /* FIXME: Delay calibration should happen in programmer code. */
- myusec_calibrate_delay();
-
- if (programmer_init(prog, pparam)) {
+ if (programmer_init(options.prog, options.pparam)) {
msg_perr("Error: Programmer initialization failed.\n");
ret = 1;
goto out_shutdown;
}
tempstr = flashbuses_to_text(get_buses_supported());
- msg_pdbg("The following protocols are supported: %s.\n", tempstr);
+ msg_pdbg("The following protocols are supported: %s.\n", tempstr ? tempstr : "?");
free(tempstr);
for (j = 0; j < registered_master_count; j++) {
startchip = 0;
while (chipcount < (int)ARRAY_SIZE(flashes)) {
- startchip = probe_flash(&registered_masters[j], startchip, &flashes[chipcount], 0);
+ startchip = probe_flash(&registered_masters[j], startchip, &flashes[chipcount], 0, options.chip_to_probe);
if (startchip == -1)
break;
chipcount++;
@@ -558,11 +1035,11 @@ int main(int argc, char *argv[])
goto out_shutdown;
} else if (!chipcount) {
msg_cinfo("No EEPROM/flash device found.\n");
- if (!force || !chip_to_probe) {
+ if (!options.force || !options.chip_to_probe) {
msg_cinfo("Note: flashrom can never write if the flash chip isn't found "
"automatically.\n");
}
- if (force && read_it && chip_to_probe) {
+ if (options.force && options.read_it && options.chip_to_probe) {
struct registered_master *mst;
int compatible_masters = 0;
msg_cinfo("Force read (-f -r -c) requested, pretending the chip is there:\n");
@@ -583,43 +1060,46 @@ int main(int argc, char *argv[])
"chip, using the first one.\n");
for (j = 0; j < registered_master_count; j++) {
mst = &registered_masters[j];
- startchip = probe_flash(mst, 0, &flashes[0], 1);
+ startchip = probe_flash(mst, 0, &flashes[0], 1, options.chip_to_probe);
if (startchip != -1)
break;
}
if (startchip == -1) {
// FIXME: This should never happen! Ask for a bug report?
- msg_cinfo("Probing for flash chip '%s' failed.\n", chip_to_probe);
- ret = 1;
- goto out_shutdown;
- }
- if (map_flash(&flashes[0]) != 0) {
- free(flashes[0].chip);
+ msg_cinfo("Probing for flash chip '%s' failed.\n", options.chip_to_probe);
ret = 1;
goto out_shutdown;
}
msg_cinfo("Please note that forced reads most likely contain garbage.\n");
- ret = read_flash_to_file(&flashes[0], filename);
- unmap_flash(&flashes[0]);
+ flashrom_flag_set(&flashes[0], FLASHROM_FLAG_FORCE, options.force);
+ ret = do_read(&flashes[0], options.filename);
free(flashes[0].chip);
goto out_shutdown;
}
ret = 1;
goto out_shutdown;
- } else if (!chip_to_probe) {
+ } else if (!options.chip_to_probe) {
/* repeat for convenience when looking at foreign logs */
tempstr = flashbuses_to_text(flashes[0].chip->bustype);
msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n",
- flashes[0].chip->vendor, flashes[0].chip->name, flashes[0].chip->total_size, tempstr);
+ flashes[0].chip->vendor, flashes[0].chip->name, flashes[0].chip->total_size,
+ tempstr ? tempstr : "?");
free(tempstr);
}
fill_flash = &flashes[0];
+ unsigned int progress_user_data[FLASHROM_PROGRESS_NR];
+ struct flashrom_progress progress_state = {
+ .user_data = progress_user_data
+ };
+ if (options.show_progress)
+ flashrom_set_progress_callback(fill_flash, &flashrom_progress_cb, &progress_state);
+
print_chip_support_status(fill_flash->chip);
- unsigned int limitexceeded = count_max_decode_exceedings(fill_flash);
- if (limitexceeded > 0 && !force) {
+ unsigned int limitexceeded = count_max_decode_exceedings(fill_flash, &max_rom_decode);
+ if (limitexceeded > 0 && !options.force) {
enum chipbustype commonbuses = fill_flash->mst->buses_supported & fill_flash->chip->bustype;
/* Sometimes chip and programmer have more than one bus in common,
@@ -634,33 +1114,31 @@ int main(int argc, char *argv[])
goto out_shutdown;
}
- 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)) {
+ const bool any_wp_op =
+ options.set_wp_range || options.set_wp_region || options.enable_wp ||
+ options.disable_wp || options.print_wp_status || options.print_wp_ranges;
+
+ const bool any_op = options.read_it || options.write_it || options.verify_it ||
+ options.erase_it || options.flash_name || options.flash_size ||
+ options.extract_it || any_wp_op;
+
+ if (!any_op) {
msg_ginfo("No operations were specified.\n");
goto out_shutdown;
}
- if (set_wp_enable && set_wp_disable) {
+ if (options.enable_wp && options.disable_wp) {
msg_ginfo("Error: --wp-enable and --wp-disable are mutually exclusive\n");
ret = 1;
goto out_shutdown;
}
- if (set_wp_range && set_wp_region) {
+ if (options.set_wp_range && options.set_wp_region) {
msg_gerr("Error: Cannot use both --wp-range and --wp-region simultaneously.\n");
ret = 1;
goto out_shutdown;
}
- if (set_wp_range || set_wp_region) {
- 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;
- }
- }
-
- if (flash_name) {
+ if (options.flash_name) {
if (fill_flash->chip->vendor && fill_flash->chip->name) {
printf("vendor=\"%s\" name=\"%s\"\n",
fill_flash->chip->vendor,
@@ -671,81 +1149,19 @@ int main(int argc, char *argv[])
goto out_shutdown;
}
- if (flash_size) {
- printf("%d\n", fill_flash->chip->total_size * 1024);
- 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;
- }
+ if (options.flash_size) {
+ printf("%zu\n", flashrom_flash_getsize(fill_flash));
goto out_shutdown;
}
- /* Note: set_wp_range must happen before set_wp_enable */
- if (set_wp_range) {
- ret |= fill_flash->chip->wp->set_range(fill_flash, wp_start, wp_len);
- }
-
- if (layoutfile) {
- layout = get_global_layout();
- } else if (ifd && (flashrom_layout_read_from_ifd(&layout, fill_flash, NULL, 0) ||
- process_include_args(layout, include_args))) {
+ if (options.ifd && (flashrom_layout_read_from_ifd(&options.layout, fill_flash, NULL, 0) ||
+ process_include_args(options.layout, options.include_args))) {
ret = 1;
goto out_shutdown;
- } else if (fmap && fmapfile) {
+ } else if (options.fmap && options.fmapfile) {
struct stat s;
- if (stat(fmapfile, &s) != 0) {
- msg_gerr("Failed to stat fmapfile \"%s\"\n", fmapfile);
+ if (stat(options.fmapfile, &s) != 0) {
+ msg_gerr("Failed to stat fmapfile \"%s\"\n", options.fmapfile);
ret = 1;
goto out_shutdown;
}
@@ -757,67 +1173,100 @@ int main(int argc, char *argv[])
goto out_shutdown;
}
- if (read_buf_from_file(fmapfile_buffer, fmapfile_size, fmapfile)) {
+ if (read_buf_from_file(fmapfile_buffer, fmapfile_size, options.fmapfile)) {
ret = 1;
free(fmapfile_buffer);
goto out_shutdown;
}
- if (flashrom_layout_read_fmap_from_buffer(&layout, fill_flash, fmapfile_buffer, fmapfile_size) ||
- process_include_args(layout, include_args)) {
+ if (flashrom_layout_read_fmap_from_buffer(&options.layout, fill_flash, fmapfile_buffer, fmapfile_size) ||
+ process_include_args(options.layout, options.include_args)) {
ret = 1;
free(fmapfile_buffer);
goto out_shutdown;
}
free(fmapfile_buffer);
- } else if (fmap && (flashrom_layout_read_fmap_from_rom(&layout, fill_flash, 0,
- fill_flash->chip->total_size * 1024) || process_include_args(layout, include_args))) {
+ } else if (options.fmap && (flashrom_layout_read_fmap_from_rom(&options.layout, fill_flash, 0,
+ flashrom_flash_getsize(fill_flash)) ||
+ process_include_args(options.layout, options.include_args))) {
ret = 1;
goto out_shutdown;
}
+ flashrom_layout_set(fill_flash, options.layout);
- flashrom_layout_set(fill_flash, layout);
- flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE, !!force);
+ if (any_wp_op) {
+ if (options.set_wp_region && options.wp_region) {
+ if (!options.layout) {
+ msg_gerr("Error: A flash layout must be specified to use --wp-region.\n");
+ ret = 1;
+ goto out_release;
+ }
+
+ ret = flashrom_layout_get_region_range(options.layout, options.wp_region, &options.wp_start, &options.wp_len);
+ if (ret) {
+ msg_gerr("Error: Region %s not found in flash layout.\n", options.wp_region);
+ goto out_release;
+ }
+ options.set_wp_range = true;
+ }
+ ret = wp_cli(
+ fill_flash,
+ options.enable_wp,
+ options.disable_wp,
+ options.print_wp_status,
+ options.print_wp_ranges,
+ options.set_wp_range,
+ options.wp_start,
+ options.wp_len
+ );
+ if (ret)
+ goto out_release;
+ }
+
+ flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE, options.force);
#if CONFIG_INTERNAL == 1
- flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE_BOARDMISMATCH, !!force_boardmismatch);
+ flashrom_flag_set(fill_flash, FLASHROM_FLAG_FORCE_BOARDMISMATCH, force_boardmismatch);
#endif
- flashrom_flag_set(fill_flash, FLASHROM_FLAG_VERIFY_AFTER_WRITE, !dont_verify_it);
- flashrom_flag_set(fill_flash, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, !dont_verify_all);
+ flashrom_flag_set(fill_flash, FLASHROM_FLAG_VERIFY_AFTER_WRITE, !options.dont_verify_it);
+ flashrom_flag_set(fill_flash, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, !options.dont_verify_all);
/* FIXME: We should issue an unconditional chip reset here. This can be
* done once we have a .reset function in struct flashchip.
* Give the chip time to settle.
*/
- programmer_delay(100000);
- if (read_it)
- ret = do_read(fill_flash, filename);
- else if (erase_it)
- ret = do_erase(fill_flash);
- else if (write_it)
- ret = do_write(fill_flash, filename, referencefile);
- else if (verify_it)
- ret = do_verify(fill_flash, filename);
-
- flashrom_layout_release(layout);
+ programmer_delay(fill_flash, 100000);
+ if (options.read_it)
+ ret = do_read(fill_flash, options.filename);
+ else if (options.extract_it)
+ ret = do_extract(fill_flash);
+ else if (options.erase_it) {
+ ret = flashrom_flash_erase(fill_flash);
+ /*
+ * FIXME: Do we really want the scary warning if erase failed?
+ * After all, after erase the chip is either blank or partially
+ * blank or it has the old contents. A blank chip won't boot,
+ * so if the user wanted erase and reboots afterwards, the user
+ * knows very well that booting won't work.
+ */
+ if (ret)
+ emergency_help_message();
+ }
+ else if (options.write_it)
+ ret = do_write(fill_flash, options.filename, options.referencefile);
+ else if (options.verify_it)
+ ret = do_verify(fill_flash, options.filename);
+out_release:
+ flashrom_layout_release(options.layout);
out_shutdown:
- programmer_shutdown();
+ flashrom_programmer_shutdown(NULL);
out:
- for (i = 0; i < chipcount; i++)
+ for (i = 0; i < chipcount; i++) {
+ flashrom_layout_release(flashes[i].default_layout);
free(flashes[i].chip);
+ }
- layout_cleanup(&include_args);
- free(filename);
- free(fmapfile);
- free(referencefile);
- free(layoutfile);
- free(pparam);
- /* clean up global variables */
- free((char *)chip_to_probe); /* Silence! Freeing is not modifying contents. */
- chip_to_probe = NULL;
-#ifndef STANDALONE
- free(logfile);
+ free_options(&options);
ret |= close_logfile();
-#endif /* !STANDALONE */
return ret;
}
diff --git a/cli_common.c b/cli_common.c
index 93758590b..537358569 100644
--- a/cli_common.c
+++ b/cli_common.c
@@ -35,12 +35,14 @@ void print_chip_support_status(const struct flashchip *chip)
if ((chip->tested.probe == BAD) || (chip->tested.probe == NT) ||
(chip->tested.read == BAD) || (chip->tested.read == NT) ||
(chip->tested.erase == BAD) || (chip->tested.erase == NT) ||
- (chip->tested.write == BAD) || (chip->tested.write == NT)){
+ (chip->tested.write == BAD) || (chip->tested.write == NT) ||
+ (chip->tested.wp == BAD) || (chip->tested.wp == NT)){
msg_cinfo("===\n");
if ((chip->tested.probe == BAD) ||
(chip->tested.read == BAD) ||
(chip->tested.erase == BAD) ||
- (chip->tested.write == BAD)) {
+ (chip->tested.write == BAD) ||
+ (chip->tested.wp == BAD)) {
msg_cinfo("This flash part has status NOT WORKING for operations:");
if (chip->tested.probe == BAD)
msg_cinfo(" PROBE");
@@ -50,12 +52,15 @@ void print_chip_support_status(const struct flashchip *chip)
msg_cinfo(" ERASE");
if (chip->tested.write == BAD)
msg_cinfo(" WRITE");
+ if (chip->tested.wp == BAD)
+ msg_cinfo(" WP");
msg_cinfo("\n");
}
if ((chip->tested.probe == NT) ||
(chip->tested.read == NT) ||
(chip->tested.erase == NT) ||
- (chip->tested.write == NT)) {
+ (chip->tested.write == NT) ||
+ (chip->tested.wp == NT)) {
msg_cinfo("This flash part has status UNTESTED for operations:");
if (chip->tested.probe == NT)
msg_cinfo(" PROBE");
@@ -65,6 +70,8 @@ void print_chip_support_status(const struct flashchip *chip)
msg_cinfo(" ERASE");
if (chip->tested.write == NT)
msg_cinfo(" WRITE");
+ if (chip->tested.wp == NT)
+ msg_cinfo(" WP");
msg_cinfo("\n");
}
msg_cinfo("The test status of this chip may have been updated in the latest development\n"
diff --git a/cli_getopt.c b/cli_getopt.c
new file mode 100644
index 000000000..fc51fcf92
--- /dev/null
+++ b/cli_getopt.c
@@ -0,0 +1,263 @@
+/*
+ * This file is part of the flashrom project.
+ * It comes originally from the musl libc project and is licensed under the
+ * terms of the MIT license.
+ *
+ * Copyringht (C) 2023 Rich Felker and the musl authors
+ * Adjusted for flashrom by Thomas Heijligen<thomas.heijligen@secunet.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <unistd.h>
+#include <wchar.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "cli_classic.h"
+#include "flash.h"
+
+char *optarg;
+int optind=1, opterr=1, optopt, optpos;
+
+static void getopt_msg(const char *a, const char *b, const char *c, size_t l)
+{
+ msg_gerr("%s%s%*c\n", a, b, l, c);
+}
+
+int getopt(int argc, char * const argv[], const char *optstring)
+{
+ int i;
+ wchar_t c, d;
+ int k, l;
+ char *optchar;
+
+ if (!optind) {
+ optind = 1;
+ optpos = 0;
+ }
+
+ if (optind >= argc || !argv[optind])
+ return -1;
+
+ if (argv[optind][0] != '-') {
+ if (optstring[0] == '-') {
+ optarg = argv[optind++];
+ return 1;
+ }
+ return -1;
+ }
+
+ if (!argv[optind][1])
+ return -1;
+
+ if (argv[optind][1] == '-' && !argv[optind][2])
+ return optind++, -1;
+
+ if (!optpos)
+ optpos++;
+ if ((k = mbtowc(&c, argv[optind]+optpos, MB_LEN_MAX)) < 0) {
+ k = 1;
+ c = 0xfffd; /* replacement char */
+ }
+ optchar = argv[optind]+optpos;
+ optpos += k;
+
+ if (!argv[optind][optpos]) {
+ optind++;
+ optpos = 0;
+ }
+
+ if (optstring[0] == '-' || optstring[0] == '+')
+ optstring++;
+
+ i = 0;
+ d = 0;
+ do {
+ l = mbtowc(&d, optstring+i, MB_LEN_MAX);
+ if (l>0) i+=l; else i++;
+ } while (l && d != c);
+
+ if (d != c || c == ':') {
+ optopt = c;
+ if (optstring[0] != ':' && opterr)
+ getopt_msg(argv[0], ": unrecognized option: ", optchar, k);
+ return '?';
+ }
+ if (optstring[i] == ':') {
+ optarg = 0;
+ if (optstring[i+1] != ':' || optpos) {
+ optarg = argv[optind++] + optpos;
+ optpos = 0;
+ }
+ if (optind > argc) {
+ optopt = c;
+ if (optstring[0] == ':')
+ return ':';
+ if (opterr) getopt_msg(argv[0],
+ ": option requires an argument: ",
+ optchar, k);
+ return '?';
+ }
+ }
+ return c;
+}
+
+static int __getopt_long_core(int argc, char *const *argv, const char *optstring,
+ const struct option *longopts, int *idx, int longonly)
+{
+ optarg = 0;
+ if (longopts && argv[optind][0] == '-' &&
+ ((longonly && argv[optind][1] && argv[optind][1] != '-') ||
+ (argv[optind][1] == '-' && argv[optind][2])))
+ {
+ int colon = optstring[optstring[0]=='+'||optstring[0]=='-']==':';
+ int i, cnt, match = 0;
+ char *arg = NULL, *opt, *start = argv[optind]+1;
+ for (cnt=i=0; longopts[i].name; i++) {
+ const char *name = longopts[i].name;
+ opt = start;
+ if (*opt == '-') opt++;
+ while (*opt && *opt != '=' && *opt == *name)
+ name++, opt++;
+ if (*opt && *opt != '=') continue;
+ arg = opt;
+ match = i;
+ if (!*name) {
+ cnt = 1;
+ break;
+ }
+ cnt++;
+ }
+ if (cnt==1 && longonly && arg-start == mblen(start, MB_LEN_MAX)) {
+ int l = arg-start;
+ for (i=0; optstring[i]; i++) {
+ int j;
+ for (j=0; j<l && start[j]==optstring[i+j]; j++);
+ if (j==l) {
+ cnt++;
+ break;
+ }
+ }
+ }
+ if (cnt==1) {
+ i = match;
+ opt = arg;
+ optind++;
+ if (*opt == '=') {
+ if (!longopts[i].has_arg) {
+ optopt = longopts[i].val;
+ if (colon || !opterr)
+ return '?';
+ getopt_msg(argv[0],
+ ": option does not take an argument: ",
+ longopts[i].name,
+ strlen(longopts[i].name));
+ return '?';
+ }
+ optarg = opt+1;
+ } else if (longopts[i].has_arg == required_argument) {
+ if (!(optarg = argv[optind])) {
+ optopt = longopts[i].val;
+ if (colon) return ':';
+ if (!opterr) return '?';
+ getopt_msg(argv[0],
+ ": option requires an argument: ",
+ longopts[i].name,
+ strlen(longopts[i].name));
+ return '?';
+ }
+ optind++;
+ }
+ if (idx)
+ *idx = i;
+ if (longopts[i].flag) {
+ *longopts[i].flag = longopts[i].val;
+ return 0;
+ }
+ return longopts[i].val;
+ }
+ if (argv[optind][1] == '-') {
+ optopt = 0;
+ if (!colon && opterr)
+ getopt_msg(argv[0], cnt ?
+ ": option is ambiguous: " :
+ ": unrecognized option: ",
+ argv[optind]+2,
+ strlen(argv[optind]+2));
+ optind++;
+ return '?';
+ }
+ }
+ return getopt(argc, argv, optstring);
+}
+
+static void permute(char *const *argv, int dest, int src)
+{
+ char **av = (char **)argv;
+ char *tmp = av[src];
+ int i;
+ for (i=src; i>dest; i--)
+ av[i] = av[i-1];
+ av[dest] = tmp;
+}
+
+static int __getopt_long(int argc, char *const *argv, const char *optstring, const struct option *longopts, int *idx, int longonly)
+{
+ int ret, skipped, resumed;
+ if (!optind) {
+ optind = 1;
+ optpos = 0;
+ }
+
+ if (optind >= argc || !argv[optind])
+ return -1;
+ skipped = optind;
+ if (optstring[0] != '+' && optstring[0] != '-') {
+ int i;
+ for (i=optind; ; i++) {
+ if (i >= argc || !argv[i])
+ return -1;
+ if (argv[i][0] == '-' && argv[i][1])
+ break;
+ }
+ optind = i;
+ }
+ resumed = optind;
+ ret = __getopt_long_core(argc, argv, optstring, longopts, idx, longonly);
+ if (resumed > skipped) {
+ int i, cnt = optind-resumed;
+ for (i=0; i<cnt; i++)
+ permute(argv, skipped, optind-1);
+ optind = skipped + cnt;
+ }
+ return ret;
+}
+
+int getopt_long(int argc, char *const *argv, const char *optstring,
+ const struct option *longopts, int *idx)
+{
+ return __getopt_long(argc, argv, optstring, longopts, idx, 0);
+}
+
+int getopt_long_only(int argc, char *const *argv, const char *optstring,
+ const struct option *longopts, int *idx)
+{
+ return __getopt_long(argc, argv, optstring, longopts, idx, 1);
+}
diff --git a/cli_output.c b/cli_output.c
index e12446d50..e5b829a7d 100644
--- a/cli_output.c
+++ b/cli_output.c
@@ -24,7 +24,6 @@
enum flashrom_log_level verbose_screen = FLASHROM_MSG_INFO;
enum flashrom_log_level verbose_logfile = FLASHROM_MSG_DEBUG2;
-#ifndef STANDALONE
static FILE *logfile = NULL;
int close_logfile(void)
@@ -64,7 +63,31 @@ void start_logging(void)
print_version();
verbose_screen = oldverbose_screen;
}
-#endif /* !STANDALONE */
+
+static const char *flashrom_progress_stage_to_string(enum flashrom_progress_stage stage)
+{
+ if (stage == FLASHROM_PROGRESS_READ)
+ return "READ";
+ if (stage == FLASHROM_PROGRESS_WRITE)
+ return "WRITE";
+ if (stage == FLASHROM_PROGRESS_ERASE)
+ return "ERASE";
+ return "UNKNOWN";
+}
+
+void flashrom_progress_cb(struct flashrom_flashctx *flashctx)
+{
+ struct flashrom_progress *progress_state = flashctx->progress_state;
+ unsigned int pc = 0;
+ unsigned int *percentages = progress_state->user_data;
+ if (progress_state->current > 0 && progress_state->total > 0)
+ pc = ((unsigned long long) progress_state->current * 10000llu) /
+ ((unsigned long long) progress_state->total * 100llu);
+ if (percentages[progress_state->stage] != pc) {
+ percentages[progress_state->stage] = pc;
+ msg_ginfo("[%s] %u%% complete... ", flashrom_progress_stage_to_string(progress_state->stage), pc);
+ }
+}
/* Please note that level is the verbosity, not the importance of the message. */
int flashrom_print_cb(enum flashrom_log_level level, const char *fmt, va_list ap)
@@ -85,13 +108,13 @@ int flashrom_print_cb(enum flashrom_log_level level, const char *fmt, va_list ap
if (level != FLASHROM_MSG_SPEW)
fflush(output_type);
}
-#ifndef STANDALONE
+
if ((level <= verbose_logfile) && logfile) {
ret = vfprintf(logfile, fmt, logfile_args);
if (level != FLASHROM_MSG_SPEW)
fflush(logfile);
}
-#endif /* !STANDALONE */
+
va_end(logfile_args);
return ret;
}
diff --git a/custom_baud.c b/custom_baud.c
index caf2b78c2..8bbe6cc74 100644
--- a/custom_baud.c
+++ b/custom_baud.c
@@ -14,54 +14,12 @@
* GNU General Public License for more details.
*/
-#include "platform.h"
-#include "custom_baud.h"
-
-#if IS_LINUX
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <asm-generic/termbits.h>
-#include <asm-generic/ioctls.h>
-
-/*
- * This include hell above is why this is in a separate source file. See eg.
- * https://www.downtowndougbrown.com/2013/11/linux-custom-serial-baud-rates/
- * https://stackoverflow.com/questions/12646324/how-to-set-a-custom-baud-rate-on-linux
- * https://github.com/jbkim/Linux-custom-baud-rate
- * for more info.
- */
-
-int set_custom_baudrate(int fd, unsigned int baud)
-{
- struct termios2 tio;
- if (ioctl(fd, TCGETS2, &tio)) {
- return -1;
- }
- tio.c_cflag &= ~CBAUD;
- tio.c_cflag |= BOTHER;
- tio.c_ispeed = baud;
- tio.c_ospeed = baud;
- return ioctl(fd, TCSETS2, &tio);
-}
-
-int use_custom_baud(unsigned int baud, const struct baudentry *baudtable)
-{
- int i;
- for (i = 0; baudtable[i].baud; i++) {
- if (baudtable[i].baud == baud)
- return 0;
-
- if (baudtable[i].baud > baud)
- return 1;
- }
- return 1;
-}
-
-#else
#include <errno.h>
+#include "custom_baud.h"
+
/* Stub, should not get called. */
-int set_custom_baudrate(int fd, unsigned int baud)
+int set_custom_baudrate(int fd, unsigned int baud, const enum custom_baud_stage stage, void *tio_wanted)
{
errno = ENOSYS; /* Hoping "Function not supported" will make you look here. */
return -1;
@@ -71,4 +29,3 @@ int use_custom_baud(unsigned int baud, const struct baudentry *baudtable)
{
return 0;
}
-#endif
diff --git a/custom_baud_darwin.c b/custom_baud_darwin.c
new file mode 100644
index 000000000..e8764ddf5
--- /dev/null
+++ b/custom_baud_darwin.c
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2022 Peter Stuge <peter@stuge.se>
+ *
+ * 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 <termios.h>
+#include <sys/ioctl.h>
+#include <IOKit/serial/ioss.h>
+#include <errno.h>
+
+#include "custom_baud.h"
+
+int use_custom_baud(unsigned int baud, const struct baudentry *baudtable)
+{
+ int i;
+
+ if (baud > 230400)
+ return 1;
+
+ for (i = 0; baudtable[i].baud; i++) {
+ if (baudtable[i].baud == baud)
+ return 0;
+
+ if (baudtable[i].baud > baud)
+ return 1;
+ }
+
+ return 1;
+}
+
+int set_custom_baudrate(int fd, unsigned int baud, const enum custom_baud_stage stage, void *tio_wanted)
+{
+ struct termios *wanted;
+ speed_t speed;
+
+ switch (stage) {
+ case BEFORE_FLAGS:
+ break;
+
+ case WITH_FLAGS:
+ wanted = tio_wanted;
+ return cfsetspeed(wanted, B19200);
+
+ case AFTER_FLAGS:
+ speed = baud;
+ return ioctl(fd, IOSSIOSPEED, &speed);
+ }
+
+ return 0;
+}
diff --git a/custom_baud_linux.c b/custom_baud_linux.c
new file mode 100644
index 000000000..761d49611
--- /dev/null
+++ b/custom_baud_linux.c
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2017 Urja Rannikko <urjaman@gmail.com>
+ *
+ * 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 <sys/ioctl.h>
+#include <fcntl.h>
+#include <asm-generic/termbits.h>
+#include <asm-generic/ioctls.h>
+
+#include "custom_baud.h"
+
+/*
+ * This include hell above is why this is in a separate source file. See eg.
+ * https://www.downtowndougbrown.com/2013/11/linux-custom-serial-baud-rates/
+ * https://stackoverflow.com/questions/12646324/how-to-set-a-custom-baud-rate-on-linux
+ * https://github.com/jbkim/Linux-custom-baud-rate
+ * for more info.
+ */
+
+int set_custom_baudrate(int fd, unsigned int baud, const enum custom_baud_stage stage, void *tio_wanted)
+{
+ struct termios2 tio;
+
+ if (stage != BEFORE_FLAGS)
+ return 0;
+
+ if (ioctl(fd, TCGETS2, &tio)) {
+ return -1;
+ }
+ tio.c_cflag &= ~CBAUD;
+ tio.c_cflag |= BOTHER;
+ tio.c_ispeed = baud;
+ tio.c_ospeed = baud;
+ return ioctl(fd, TCSETS2, &tio);
+}
+
+int use_custom_baud(unsigned int baud, const struct baudentry *baudtable)
+{
+ int i;
+ for (i = 0; baudtable[i].baud; i++) {
+ if (baudtable[i].baud == baud)
+ return 0;
+
+ if (baudtable[i].baud > baud)
+ return 1;
+ }
+ return 1;
+}
diff --git a/dediprog.c b/dediprog.c
index c50e374e7..734fcfa11 100644
--- a/dediprog.c
+++ b/dediprog.c
@@ -15,8 +15,6 @@
* GNU General Public License for more details.
*/
-#include "platform.h"
-
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
@@ -43,10 +41,6 @@
#define REQTYPE_OTHER_IN (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_OTHER) /* 0xC3 */
#define REQTYPE_EP_OUT (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT) /* 0x42 */
#define REQTYPE_EP_IN (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT) /* 0xC2 */
-static struct libusb_context *usb_ctx;
-static libusb_device_handle *dediprog_handle;
-static int dediprog_in_endpoint;
-static int dediprog_out_endpoint;
enum dediprog_devtype {
DEV_UNKNOWN = 0,
@@ -152,14 +146,20 @@ enum protocol {
PROTOCOL_V3,
};
-const struct dev_entry devs_dediprog[] = {
+static const struct dev_entry devs_dediprog[] = {
{0x0483, 0xDADA, OK, "Dediprog", "SF100/SF200/SF600"},
{0},
};
-static int dediprog_firmwareversion = FIRMWARE_VERSION(0, 0, 0);
-static enum dediprog_devtype dediprog_devicetype = DEV_UNKNOWN;
+struct dediprog_data {
+ struct libusb_context *usb_ctx;
+ libusb_device_handle *handle;
+ int in_endpoint;
+ int out_endpoint;
+ int firmwareversion;
+ enum dediprog_devtype devicetype;
+};
#if defined(LIBUSB_MAJOR) && defined(LIBUSB_MINOR) && defined(LIBUSB_MICRO) && \
LIBUSB_MAJOR <= 1 && LIBUSB_MINOR == 0 && LIBUSB_MICRO < 9
@@ -177,20 +177,20 @@ const char * LIBUSB_CALL libusb_error_name(int error_code)
}
#endif
-static enum protocol protocol(void)
+static enum protocol protocol(const struct dediprog_data *dp_data)
{
/* Firmware version < 5.0.0 is handled explicitly in some cases. */
- switch (dediprog_devicetype) {
+ switch (dp_data->devicetype) {
case DEV_SF100:
case DEV_SF200:
- if (dediprog_firmwareversion < FIRMWARE_VERSION(5, 5, 0))
+ if (dp_data->firmwareversion < FIRMWARE_VERSION(5, 5, 0))
return PROTOCOL_V1;
else
return PROTOCOL_V2;
case DEV_SF600:
- if (dediprog_firmwareversion < FIRMWARE_VERSION(6, 9, 0))
+ if (dp_data->firmwareversion < FIRMWARE_VERSION(6, 9, 0))
return PROTOCOL_V1;
- else if (dediprog_firmwareversion <= FIRMWARE_VERSION(7, 2, 21))
+ else if (dp_data->firmwareversion <= FIRMWARE_VERSION(7, 2, 21))
return PROTOCOL_V2;
else
return PROTOCOL_V3;
@@ -215,7 +215,9 @@ static void LIBUSB_CALL dediprog_bulk_read_cb(struct libusb_transfer *const tran
++status->finished_idx;
}
-static int dediprog_bulk_read_poll(const struct dediprog_transfer_status *const status, const int finish)
+static int dediprog_bulk_read_poll(struct libusb_context *usb_ctx,
+ const struct dediprog_transfer_status *const status,
+ const int finish)
{
if (status->finished_idx >= status->queued_idx)
return 0;
@@ -231,13 +233,17 @@ static int dediprog_bulk_read_poll(const struct dediprog_transfer_status *const
return 0;
}
-static int dediprog_read(enum dediprog_cmds cmd, unsigned int value, unsigned int idx, uint8_t *bytes, size_t size)
+static int dediprog_read(libusb_device_handle *dediprog_handle,
+ enum dediprog_cmds cmd, unsigned int value, unsigned int idx,
+ uint8_t *bytes, size_t size)
{
return libusb_control_transfer(dediprog_handle, REQTYPE_EP_IN, cmd, value, idx,
(unsigned char *)bytes, size, DEFAULT_TIMEOUT);
}
-static int dediprog_write(enum dediprog_cmds cmd, unsigned int value, unsigned int idx, const uint8_t *bytes, size_t size)
+static int dediprog_write(libusb_device_handle *dediprog_handle,
+ enum dediprog_cmds cmd, unsigned int value, unsigned int idx,
+ const uint8_t *bytes, size_t size)
{
return libusb_control_transfer(dediprog_handle, REQTYPE_EP_OUT, cmd, value, idx,
(unsigned char *)bytes, size, DEFAULT_TIMEOUT);
@@ -245,7 +251,7 @@ static int dediprog_write(enum dediprog_cmds cmd, unsigned int value, unsigned i
/* This function sets the GPIOs connected to the LEDs as well as IO1-IO4. */
-static int dediprog_set_leds(int leds)
+static int dediprog_set_leds(int leds, const struct dediprog_data *dp_data)
{
if (leds < LED_NONE || leds > LED_ALL)
leds = LED_ALL;
@@ -260,18 +266,18 @@ static int dediprog_set_leds(int leds)
* FIXME: take IO pins into account
*/
int target_leds, ret;
- if (protocol() >= PROTOCOL_V2) {
+ if (protocol(dp_data) >= PROTOCOL_V2) {
target_leds = (leds ^ 7) << 8;
- ret = dediprog_write(CMD_SET_IO_LED, target_leds, 0, NULL, 0);
+ ret = dediprog_write(dp_data->handle, CMD_SET_IO_LED, target_leds, 0, NULL, 0);
} else {
- if (dediprog_firmwareversion < FIRMWARE_VERSION(5, 0, 0)) {
+ if (dp_data->firmwareversion < FIRMWARE_VERSION(5, 0, 0)) {
target_leds = ((leds & LED_ERROR) >> 2) | ((leds & LED_PASS) << 2);
} else {
target_leds = leds;
}
target_leds ^= 7;
- ret = dediprog_write(CMD_SET_IO_LED, 0x9, target_leds, NULL, 0);
+ ret = dediprog_write(dp_data->handle, CMD_SET_IO_LED, 0x9, target_leds, NULL, 0);
}
if (ret != 0x0) {
@@ -282,7 +288,7 @@ static int dediprog_set_leds(int leds)
return 0;
}
-static int dediprog_set_spi_voltage(int millivolt)
+static int dediprog_set_spi_voltage(libusb_device_handle *dediprog_handle, int millivolt)
{
int ret;
uint16_t voltage_selector;
@@ -310,9 +316,9 @@ static int dediprog_set_spi_voltage(int millivolt)
if (voltage_selector == 0) {
/* Wait some time as the original driver does. */
- programmer_delay(200 * 1000);
+ default_delay(200 * 1000);
}
- ret = dediprog_write(CMD_SET_VCC, voltage_selector, 0, NULL, 0);
+ ret = dediprog_write(dediprog_handle, CMD_SET_VCC, voltage_selector, 0, NULL, 0);
if (ret != 0x0) {
msg_perr("Command Set SPI Voltage 0x%x failed!\n",
voltage_selector);
@@ -320,7 +326,7 @@ static int dediprog_set_spi_voltage(int millivolt)
}
if (voltage_selector != 0) {
/* Wait some time as the original driver does. */
- programmer_delay(200 * 1000);
+ default_delay(200 * 1000);
}
return 0;
}
@@ -342,9 +348,9 @@ static const struct dediprog_spispeeds spispeeds[] = {
{ NULL, 0x0 },
};
-static int dediprog_set_spi_speed(unsigned int spispeed_idx)
+static int dediprog_set_spi_speed(unsigned int spispeed_idx, const struct dediprog_data *dp_data)
{
- if (dediprog_firmwareversion < FIRMWARE_VERSION(5, 0, 0)) {
+ if (dp_data->firmwareversion < FIRMWARE_VERSION(5, 0, 0)) {
msg_pwarn("Skipping to set SPI speed because firmware is too old.\n");
return 0;
}
@@ -352,7 +358,7 @@ static int dediprog_set_spi_speed(unsigned int spispeed_idx)
const struct dediprog_spispeeds *spispeed = &spispeeds[spispeed_idx];
msg_pdbg("SPI speed is %sHz\n", spispeed->name);
- int ret = dediprog_write(CMD_SET_SPI_CLK, spispeed->speed, 0, NULL, 0);
+ int ret = dediprog_write(dp_data->handle, CMD_SET_SPI_CLK, spispeed->speed, 0, NULL, 0);
if (ret != 0x0) {
msg_perr("Command Set SPI Speed 0x%x failed!\n", spispeed->speed);
return 1;
@@ -364,6 +370,8 @@ static int prepare_rw_cmd(
struct flashctx *const flash, uint8_t *data_packet, unsigned int count,
uint8_t dedi_spi_cmd, unsigned int *value, unsigned int *idx, unsigned int start, int is_read)
{
+ const struct dediprog_data *dp_data = flash->mst->spi.data;
+
if (count >= 1 << 16) {
msg_perr("%s: Unsupported transfer length of %u blocks! "
"Please report a bug at flashrom@flashrom.org\n",
@@ -378,7 +386,7 @@ static int prepare_rw_cmd(
data_packet[3] = dedi_spi_cmd; /* Read/Write Mode (currently READ_MODE_STD, WRITE_MODE_PAGE_PGM or WRITE_MODE_2B_AAI) */
data_packet[4] = 0; /* "Opcode". Specs imply necessity only for READ_MODE_4B_ADDR_FAST and WRITE_MODE_4B_ADDR_256B_PAGE_PGM */
- if (protocol() >= PROTOCOL_V2) {
+ if (protocol(dp_data) >= PROTOCOL_V2) {
if (is_read && flash->chip->feature_bits & FEATURE_4BA_FAST_READ) {
data_packet[3] = READ_MODE_4B_ADDR_FAST_0x0C;
data_packet[4] = JEDEC_READ_4BA_FAST;
@@ -394,7 +402,7 @@ static int prepare_rw_cmd(
data_packet[7] = (start >> 8) & 0xff;
data_packet[8] = (start >> 16) & 0xff;
data_packet[9] = (start >> 24) & 0xff;
- if (protocol() >= PROTOCOL_V3) {
+ if (protocol(dp_data) >= PROTOCOL_V3) {
if (is_read) {
data_packet[10] = 0x00; /* address length (3 or 4) */
data_packet[11] = 0x00; /* dummy cycle / 2 */
@@ -408,7 +416,7 @@ static int prepare_rw_cmd(
}
}
} else {
- if (flash->chip->feature_bits & FEATURE_4BA_EXT_ADDR) {
+ if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) {
if (spi_set_extended_address(flash, start >> 24))
return 1;
} else if (start >> 24) {
@@ -435,6 +443,7 @@ static int prepare_rw_cmd(
static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
{
int err = 1;
+ const struct dediprog_data *dp_data = flash->mst->spi.data;
/* chunksize must be 512, other sizes will NOT work at all. */
const unsigned int chunksize = 512;
@@ -454,7 +463,7 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned
}
int command_packet_size;
- switch (protocol()) {
+ switch (protocol(dp_data)) {
case PROTOCOL_V1:
command_packet_size = 5;
break;
@@ -473,7 +482,7 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned
if (prepare_rw_cmd(flash, data_packet, count, READ_MODE_STD, &value, &idx, start, 1))
return 1;
- int ret = dediprog_write(CMD_READ, value, idx, data_packet, sizeof(data_packet));
+ int ret = dediprog_write(dp_data->handle, CMD_READ, value, idx, data_packet, sizeof(data_packet));
if (ret != (int)sizeof(data_packet)) {
msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, libusb_error_name(ret));
return 1;
@@ -501,7 +510,7 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned
(status.queued_idx - status.finished_idx) < DEDIPROG_ASYNC_TRANSFERS)
{
transfer = transfers[status.queued_idx % DEDIPROG_ASYNC_TRANSFERS];
- libusb_fill_bulk_transfer(transfer, dediprog_handle, 0x80 | dediprog_in_endpoint,
+ libusb_fill_bulk_transfer(transfer, dp_data->handle, 0x80 | dp_data->in_endpoint,
(unsigned char *)buf + status.queued_idx * chunksize, chunksize,
dediprog_bulk_read_cb, &status, DEFAULT_TIMEOUT);
transfer->flags |= LIBUSB_TRANSFER_SHORT_NOT_OK;
@@ -513,11 +522,11 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned
}
++status.queued_idx;
}
- if (dediprog_bulk_read_poll(&status, 0))
+ if (dediprog_bulk_read_poll(dp_data->usb_ctx, &status, 0))
goto err_free;
}
/* Wait for transfers to finish. */
- if (dediprog_bulk_read_poll(&status, 1))
+ if (dediprog_bulk_read_poll(dp_data->usb_ctx, &status, 1))
goto err_free;
/* Check if everything has been transmitted. */
if ((status.finished_idx < count) || status.error)
@@ -526,7 +535,7 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned
err = 0;
err_free:
- dediprog_bulk_read_poll(&status, 1);
+ dediprog_bulk_read_poll(dp_data->usb_ctx, &status, 1);
for (i = 0; i < DEDIPROG_ASYNC_TRANSFERS; ++i)
if (transfers[i]) libusb_free_transfer(transfers[i]);
return err;
@@ -539,8 +548,9 @@ static int dediprog_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int
const unsigned int chunksize = 0x200;
unsigned int residue = start % chunksize ? min(len, chunksize - start % chunksize) : 0;
unsigned int bulklen;
+ const struct dediprog_data *dp_data = flash->mst->spi.data;
- dediprog_set_leds(LED_BUSY);
+ dediprog_set_leds(LED_BUSY, dp_data);
if (residue) {
msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n",
@@ -566,10 +576,10 @@ static int dediprog_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int
goto err;
}
- dediprog_set_leds(LED_PASS);
+ dediprog_set_leds(LED_PASS, dp_data);
return 0;
err:
- dediprog_set_leds(LED_ERROR);
+ dediprog_set_leds(LED_ERROR, dp_data);
return ret;
}
@@ -588,6 +598,7 @@ static int dediprog_spi_bulk_write(struct flashctx *flash, const uint8_t *buf, u
* space in a USB bulk transfer must be filled with 0xff padding.
*/
const unsigned int count = len / chunksize;
+ const struct dediprog_data *dp_data = flash->mst->spi.data;
/*
* We should change this check to
@@ -611,7 +622,7 @@ static int dediprog_spi_bulk_write(struct flashctx *flash, const uint8_t *buf, u
return 0;
int command_packet_size;
- switch (protocol()) {
+ switch (protocol(dp_data)) {
case PROTOCOL_V1:
command_packet_size = 5;
break;
@@ -629,7 +640,7 @@ static int dediprog_spi_bulk_write(struct flashctx *flash, const uint8_t *buf, u
unsigned int value, idx;
if (prepare_rw_cmd(flash, data_packet, count, dedi_spi_cmd, &value, &idx, start, 0))
return 1;
- int ret = dediprog_write(CMD_WRITE, value, idx, data_packet, sizeof(data_packet));
+ int ret = dediprog_write(dp_data->handle, CMD_WRITE, value, idx, data_packet, sizeof(data_packet));
if (ret != (int)sizeof(data_packet)) {
msg_perr("Command Write SPI Bulk failed, %s!\n", libusb_error_name(ret));
return 1;
@@ -641,12 +652,13 @@ static int dediprog_spi_bulk_write(struct flashctx *flash, const uint8_t *buf, u
memcpy(usbbuf, buf + i * chunksize, chunksize);
memset(usbbuf + chunksize, 0xff, sizeof(usbbuf) - chunksize); // fill up with 0xFF
int transferred;
- ret = libusb_bulk_transfer(dediprog_handle, dediprog_out_endpoint, usbbuf, 512, &transferred,
+ ret = libusb_bulk_transfer(dp_data->handle, dp_data->out_endpoint, usbbuf, 512, &transferred,
DEFAULT_TIMEOUT);
if ((ret < 0) || (transferred != 512)) {
msg_perr("SPI bulk write failed, expected %i, got %s!\n", 512, libusb_error_name(ret));
return 1;
}
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, count);
}
return 0;
@@ -659,8 +671,9 @@ static int dediprog_spi_write(struct flashctx *flash, const uint8_t *buf,
const unsigned int chunksize = flash->chip->page_size;
unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0;
unsigned int bulklen;
+ const struct dediprog_data *dp_data = flash->mst->spi.data;
- dediprog_set_leds(LED_BUSY);
+ dediprog_set_leds(LED_BUSY, dp_data);
if (chunksize != 256) {
msg_pdbg("Page sizes other than 256 bytes are unsupported as "
@@ -675,7 +688,7 @@ static int dediprog_spi_write(struct flashctx *flash, const uint8_t *buf,
/* No idea about the real limit. Maybe 16 including command and address, maybe more. */
ret = spi_write_chunked(flash, buf, start, residue, 11);
if (ret) {
- dediprog_set_leds(LED_ERROR);
+ dediprog_set_leds(LED_ERROR, dp_data);
return ret;
}
}
@@ -684,7 +697,7 @@ static int dediprog_spi_write(struct flashctx *flash, const uint8_t *buf,
bulklen = (len - residue) / chunksize * chunksize;
ret = dediprog_spi_bulk_write(flash, buf + residue, chunksize, start + residue, bulklen, dedi_spi_cmd);
if (ret) {
- dediprog_set_leds(LED_ERROR);
+ dediprog_set_leds(LED_ERROR, dp_data);
return ret;
}
@@ -695,12 +708,12 @@ static int dediprog_spi_write(struct flashctx *flash, const uint8_t *buf,
ret = spi_write_chunked(flash, buf + residue + bulklen,
start + residue + bulklen, len, 11);
if (ret) {
- dediprog_set_leds(LED_ERROR);
+ dediprog_set_leds(LED_ERROR, dp_data);
return ret;
}
}
- dediprog_set_leds(LED_PASS);
+ dediprog_set_leds(LED_PASS, dp_data);
return 0;
}
@@ -721,6 +734,7 @@ static int dediprog_spi_send_command(const struct flashctx *flash,
unsigned char *readarr)
{
int ret;
+ const struct dediprog_data *dp_data = flash->mst->spi.data;
msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
if (writecnt > flash->mst->spi.max_data_write) {
@@ -735,14 +749,14 @@ static int dediprog_spi_send_command(const struct flashctx *flash,
unsigned int idx, value;
/* New protocol has options and timeout combined as value while the old one used the value field for
* timeout and the index field for options. */
- if (protocol() >= PROTOCOL_V2) {
+ if (protocol(dp_data) >= PROTOCOL_V2) {
idx = 0;
value = readcnt ? 0x1 : 0x0; // Indicate if we require a read
} else {
idx = readcnt ? 0x1 : 0x0; // Indicate if we require a read
value = 0;
}
- ret = dediprog_write(CMD_TRANSCEIVE, value, idx, writearr, writecnt);
+ ret = dediprog_write(dp_data->handle, CMD_TRANSCEIVE, value, idx, writearr, writecnt);
if (ret != (int)writecnt) {
msg_perr("Send SPI failed, expected %i, got %i %s!\n",
writecnt, ret, libusb_error_name(ret));
@@ -767,9 +781,9 @@ static int dediprog_spi_send_command(const struct flashctx *flash,
idx = (0 & 0xFF); // Lower byte is option (0x01 = require SR, 0x02 keep CS low)
value = min(read_timeout, 0xFF); // Possibly two bytes but we play safe here
}
- ret = dediprog_read(CMD_TRANSCEIVE, value, idx, readarr, readcnt);
+ ret = dediprog_read(dp_data->dediprog_handle, CMD_TRANSCEIVE, value, idx, readarr, readcnt);
*/
- ret = dediprog_read(CMD_TRANSCEIVE, 0, 0, readarr, readcnt);
+ ret = dediprog_read(dp_data->handle, CMD_TRANSCEIVE, 0, 0, readarr, readcnt);
if (ret != (int)readcnt) {
msg_perr("Receive SPI failed, expected %i, got %i %s!\n", readcnt, ret, libusb_error_name(ret));
return 1;
@@ -777,13 +791,13 @@ static int dediprog_spi_send_command(const struct flashctx *flash,
return 0;
}
-static int dediprog_check_devicestring(void)
+static int dediprog_check_devicestring(struct dediprog_data *dp_data)
{
int ret;
char buf[0x11];
/* Command Receive Device String. */
- ret = dediprog_read(CMD_READ_PROG_INFO, 0, 0, (uint8_t *)buf, 0x10);
+ ret = dediprog_read(dp_data->handle, CMD_READ_PROG_INFO, 0, 0, (uint8_t *)buf, 0x10);
if (ret != 0x10) {
msg_perr("Incomplete/failed Command Receive Device String!\n");
return 1;
@@ -791,11 +805,11 @@ static int dediprog_check_devicestring(void)
buf[0x10] = '\0';
msg_pdbg("Found a %s\n", buf);
if (memcmp(buf, "SF100", 0x5) == 0)
- dediprog_devicetype = DEV_SF100;
+ dp_data->devicetype = DEV_SF100;
else if (memcmp(buf, "SF200", 0x5) == 0)
- dediprog_devicetype = DEV_SF200;
+ dp_data->devicetype = DEV_SF200;
else if (memcmp(buf, "SF600", 0x5) == 0)
- dediprog_devicetype = DEV_SF600;
+ dp_data->devicetype = DEV_SF600;
else {
msg_perr("Device not a SF100, SF200, or SF600!\n");
return 1;
@@ -804,7 +818,7 @@ static int dediprog_check_devicestring(void)
int sfnum;
int fw[3];
if (sscanf(buf, "SF%d V:%d.%d.%d ", &sfnum, &fw[0], &fw[1], &fw[2]) != 4 ||
- sfnum != (int)dediprog_devicetype) {
+ sfnum != (int)dp_data->devicetype) {
msg_perr("Unexpected firmware version string '%s'\n", buf);
return 1;
}
@@ -814,8 +828,8 @@ static int dediprog_check_devicestring(void)
return 1;
}
- dediprog_firmwareversion = FIRMWARE_VERSION(fw[0], fw[1], fw[2]);
- if (protocol() == PROTOCOL_UNKNOWN) {
+ dp_data->firmwareversion = FIRMWARE_VERSION(fw[0], fw[1], fw[2]);
+ if (protocol(dp_data) == PROTOCOL_UNKNOWN) {
msg_perr("Internal error: Unable to determine protocol version.\n");
return 1;
}
@@ -831,7 +845,7 @@ static int dediprog_check_devicestring(void)
* much different.
* @return the id on success, -1 on failure
*/
-static int dediprog_read_id(void)
+static int dediprog_read_id(libusb_device_handle *dediprog_handle)
{
int ret;
uint8_t buf[3];
@@ -859,7 +873,7 @@ static int dediprog_read_id(void)
/* This command presumably sets the voltage for the SF100 itself (not the SPI flash).
* Only use dediprog_set_voltage on SF100 programmers with firmware older
* than V6.0.0. Newer programmers (including all SF600s) do not support it. */
-static int dediprog_set_voltage(void)
+static int dediprog_set_voltage(libusb_device_handle *dediprog_handle)
{
unsigned char buf[1] = {0};
int ret = libusb_control_transfer(dediprog_handle, REQTYPE_OTHER_IN, CMD_SET_VOLTAGE, 0x0, 0x0,
@@ -876,15 +890,15 @@ static int dediprog_set_voltage(void)
return 0;
}
-static int dediprog_standalone_mode(void)
+static int dediprog_standalone_mode(const struct dediprog_data *dp_data)
{
int ret;
- if (dediprog_devicetype != DEV_SF600)
+ if (dp_data->devicetype != DEV_SF600)
return 0;
msg_pdbg2("Disabling standalone mode.\n");
- ret = dediprog_write(CMD_SET_STANDALONE, LEAVE_STANDALONE_MODE, 0, NULL, 0);
+ ret = dediprog_write(dp_data->handle, CMD_SET_STANDALONE, LEAVE_STANDALONE_MODE, 0, NULL, 0);
if (ret) {
msg_perr("Failed to disable standalone mode: %s\n", libusb_error_name(ret));
return 1;
@@ -898,7 +912,7 @@ static int dediprog_standalone_mode(void)
* Present in eng_detect_blink.log with firmware 3.1.8
* Always preceded by Command Receive Device String
*/
-static int dediprog_command_b(void)
+static int dediprog_command_b(libusb_device_handle *dediprog_handle)
{
int ret;
char buf[0x3];
@@ -919,9 +933,9 @@ static int dediprog_command_b(void)
}
#endif
-static int set_target_flash(enum dediprog_target target)
+static int set_target_flash(libusb_device_handle *dediprog_handle, enum dediprog_target target)
{
- int ret = dediprog_write(CMD_SET_TARGET, target, 0, NULL, 0);
+ int ret = dediprog_write(dediprog_handle, CMD_SET_TARGET, target, 0, NULL, 0);
if (ret != 0) {
msg_perr("set_target_flash failed (%s)!\n", libusb_error_name(ret));
return 1;
@@ -931,7 +945,7 @@ static int set_target_flash(enum dediprog_target target)
#if 0
/* Returns true if the button is currently pressed. */
-static bool dediprog_get_button(void)
+static bool dediprog_get_button(libusb_device_handle *dediprog_handle)
{
char buf[1];
int ret = usb_control_msg(dediprog_handle, REQTYPE_EP_IN, CMD_GET_BUTTON, 0, 0,
@@ -992,15 +1006,38 @@ static int parse_voltage(char *voltage)
return millivolt;
}
+static int dediprog_shutdown(void *data)
+{
+ int ret = 0;
+ struct dediprog_data *dp_data = data;
+
+ /* URB 28. Command Set SPI Voltage to 0. */
+ if (dediprog_set_spi_voltage(dp_data->handle, 0x0)) {
+ ret = 1;
+ goto out;
+ }
+
+ if (libusb_release_interface(dp_data->handle, 0)) {
+ msg_perr("Could not release USB interface!\n");
+ ret = 1;
+ goto out;
+ }
+ libusb_close(dp_data->handle);
+ libusb_exit(dp_data->usb_ctx);
+out:
+ free(data);
+ return ret;
+}
+
static struct spi_master spi_master_dediprog = {
.features = SPI_MASTER_NO_4BA_MODES,
.max_data_read = 16, /* 18 seems to work fine as well, but 19 times out sometimes with FW 5.15. */
.max_data_write = 16,
.command = dediprog_spi_send_command,
- .multicommand = default_spi_send_multicommand,
.read = dediprog_spi_read,
.write_256 = dediprog_spi_write_256,
.write_aai = dediprog_spi_write_aai,
+ .shutdown = dediprog_shutdown,
};
/*
@@ -1008,56 +1045,38 @@ static struct spi_master spi_master_dediprog = {
* @index index of the USB device
* @return 0 for success, -1 for error, -2 for busy device
*/
-static int dediprog_open(int index)
+static int dediprog_open(int index, struct dediprog_data *dp_data)
{
const uint16_t vid = devs_dediprog[0].vendor_id;
const uint16_t pid = devs_dediprog[0].device_id;
int ret;
- dediprog_handle = usb_dev_get_by_vid_pid_number(usb_ctx, vid, pid, (unsigned int) index);
- if (!dediprog_handle) {
+ dp_data->handle = usb_dev_get_by_vid_pid_number(dp_data->usb_ctx, vid, pid, (unsigned int) index);
+ if (!dp_data->handle) {
msg_perr("Could not find a Dediprog programmer on USB.\n");
- libusb_exit(usb_ctx);
+ libusb_exit(dp_data->usb_ctx);
return -1;
}
- ret = libusb_set_configuration(dediprog_handle, 1);
+ ret = libusb_set_configuration(dp_data->handle, 1);
if (ret != 0) {
msg_perr("Could not set USB device configuration: %i %s\n",
ret, libusb_error_name(ret));
- libusb_close(dediprog_handle);
+ libusb_close(dp_data->handle);
return -2;
}
- ret = libusb_claim_interface(dediprog_handle, 0);
+ ret = libusb_claim_interface(dp_data->handle, 0);
if (ret < 0) {
msg_perr("Could not claim USB device interface %i: %i %s\n",
0, ret, libusb_error_name(ret));
- libusb_close(dediprog_handle);
+ libusb_close(dp_data->handle);
return -2;
}
return 0;
}
-static int dediprog_shutdown(void *data)
+static int dediprog_init(const struct programmer_cfg *cfg)
{
- dediprog_devicetype = DEV_UNKNOWN;
-
- /* URB 28. Command Set SPI Voltage to 0. */
- if (dediprog_set_spi_voltage(0x0))
- return 1;
-
- if (libusb_release_interface(dediprog_handle, 0)) {
- msg_perr("Could not release USB interface!\n");
- return 1;
- }
- libusb_close(dediprog_handle);
- libusb_exit(usb_ctx);
-
- return 0;
-}
-
-int dediprog_init(void)
-{
- char *voltage, *id_str, *device, *spispeed, *target_str;
+ char *param_str;
int spispeed_idx = 1;
int millivolt = 3500;
int id = -1; /* -1 defaults to enumeration order */
@@ -1066,99 +1085,99 @@ int dediprog_init(void)
long target = FLASH_TYPE_APPLICATION_FLASH_1;
int i, ret;
- spispeed = extract_programmer_param("spispeed");
- if (spispeed) {
+ param_str = extract_programmer_param_str(cfg, "spispeed");
+ if (param_str) {
for (i = 0; spispeeds[i].name; ++i) {
- if (!strcasecmp(spispeeds[i].name, spispeed)) {
+ if (!strcasecmp(spispeeds[i].name, param_str)) {
spispeed_idx = i;
break;
}
}
if (!spispeeds[i].name) {
- msg_perr("Error: Invalid spispeed value: '%s'.\n", spispeed);
- free(spispeed);
+ msg_perr("Error: Invalid spispeed value: '%s'.\n", param_str);
+ free(param_str);
return 1;
}
- free(spispeed);
+ free(param_str);
}
- voltage = extract_programmer_param("voltage");
- if (voltage) {
- millivolt = parse_voltage(voltage);
- free(voltage);
+ param_str = extract_programmer_param_str(cfg, "voltage");
+ if (param_str) {
+ millivolt = parse_voltage(param_str);
+ free(param_str);
if (millivolt < 0)
return 1;
msg_pinfo("Setting voltage to %i mV\n", millivolt);
}
- id_str = extract_programmer_param("id");
- if (id_str) {
+ param_str = extract_programmer_param_str(cfg, "id");
+ if (param_str) {
char prefix0, prefix1;
- if (sscanf(id_str, "%c%c%d", &prefix0, &prefix1, &id) != 3) {
+ if (sscanf(param_str, "%c%c%d", &prefix0, &prefix1, &id) != 3) {
msg_perr("Error: Could not parse dediprog 'id'.\n");
msg_perr("Expected a string like SF012345 or DP012345.\n");
- free(id_str);
+ free(param_str);
return 1;
}
if (id < 0 || id >= 0x1000000) {
- msg_perr("Error: id %s is out of range!\n", id_str);
- free(id_str);
+ msg_perr("Error: id %s is out of range!\n", param_str);
+ free(param_str);
return 1;
}
if (!(prefix0 == 'S' && prefix1 == 'F') && !(prefix0 == 'D' && prefix1 == 'P')) {
- msg_perr("Error: %s is an invalid id!\n", id_str);
- free(id_str);
+ msg_perr("Error: %s is an invalid id!\n", param_str);
+ free(param_str);
return 1;
}
- msg_pinfo("Will search for dediprog id %s.\n", id_str);
+ msg_pinfo("Will search for dediprog id %s.\n", param_str);
}
- free(id_str);
+ free(param_str);
- device = extract_programmer_param("device");
- if (device) {
+ param_str = extract_programmer_param_str(cfg, "device");
+ if (param_str) {
char *dev_suffix;
if (id != -1) {
msg_perr("Error: Cannot use 'id' and 'device'.\n");
}
errno = 0;
- usedevice = strtol(device, &dev_suffix, 10);
- if (errno != 0 || device == dev_suffix) {
+ usedevice = strtol(param_str, &dev_suffix, 10);
+ if (errno != 0 || param_str == dev_suffix) {
msg_perr("Error: Could not convert 'device'.\n");
- free(device);
+ free(param_str);
return 1;
}
if (usedevice < 0 || usedevice > INT_MAX) {
msg_perr("Error: Value for 'device' is out of range.\n");
- free(device);
+ free(param_str);
return 1;
}
if (strlen(dev_suffix) > 0) {
msg_perr("Error: Garbage following 'device' value.\n");
- free(device);
+ free(param_str);
return 1;
}
msg_pinfo("Using device %li.\n", usedevice);
}
- free(device);
+ free(param_str);
- target_str = extract_programmer_param("target");
- if (target_str) {
+ param_str = extract_programmer_param_str(cfg, "target");
+ if (param_str) {
char *target_suffix;
errno = 0;
- target = strtol(target_str, &target_suffix, 10);
- if (errno != 0 || target_str == target_suffix) {
+ target = strtol(param_str, &target_suffix, 10);
+ if (errno != 0 || param_str == target_suffix) {
msg_perr("Error: Could not convert 'target'.\n");
- free(target_str);
+ free(param_str);
return 1;
}
if (target < 1 || target > 2) {
msg_perr("Error: Value for 'target' is out of range.\n");
- free(target_str);
+ free(param_str);
return 1;
}
if (strlen(target_suffix) > 0) {
msg_perr("Error: Garbage following 'target' value.\n");
- free(target_str);
+ free(param_str);
return 1;
}
switch (target) {
@@ -1174,21 +1193,29 @@ int dediprog_init(void)
break;
}
}
- free(target_str);
+ free(param_str);
+
+ struct dediprog_data *dp_data = calloc(1, sizeof(*dp_data));
+ if (!dp_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ return 1;
+ }
+ dp_data->firmwareversion = FIRMWARE_VERSION(0, 0, 0);
+ dp_data->devicetype = DEV_UNKNOWN;
/* Here comes the USB stuff. */
- libusb_init(&usb_ctx);
- if (!usb_ctx) {
+ ret = libusb_init(&dp_data->usb_ctx);
+ if (ret) {
msg_perr("Could not initialize libusb!\n");
- return 1;
+ goto init_err_exit;
}
if (id != -1) {
for (i = 0; ; i++) {
- ret = dediprog_open(i);
+ ret = dediprog_open(i, dp_data);
if (ret == -1) {
/* no dev */
- return 1;
+ goto init_err_exit;
} else if (ret == -2) {
/* busy dev */
continue;
@@ -1201,80 +1228,93 @@ int dediprog_init(void)
* device is in use by another instance of flashrom),
* the device is skipped and the next device is tried.
*/
- found_id = dediprog_read_id();
+ found_id = dediprog_read_id(dp_data->handle);
if (found_id < 0) {
msg_perr("Could not read id.\n");
- libusb_release_interface(dediprog_handle, 0);
- libusb_close(dediprog_handle);
+ libusb_release_interface(dp_data->handle, 0);
+ libusb_close(dp_data->handle);
continue;
}
msg_pinfo("Found dediprog id SF%06d.\n", found_id);
if (found_id != id) {
- libusb_release_interface(dediprog_handle, 0);
- libusb_close(dediprog_handle);
+ libusb_release_interface(dp_data->handle, 0);
+ libusb_close(dp_data->handle);
continue;
}
break;
}
} else {
- if (dediprog_open(usedevice)) {
- return 1;
+ if (dediprog_open(usedevice, dp_data)) {
+ goto init_err_exit;
}
- found_id = dediprog_read_id();
+ found_id = dediprog_read_id(dp_data->handle);
}
if (found_id >= 0) {
msg_pinfo("Using dediprog id SF%06d.\n", found_id);
}
- if (register_shutdown(dediprog_shutdown, NULL))
- return 1;
-
/* Try reading the devicestring. If that fails and the device is old (FW < 6.0.0, which we can not know)
* then we need to try the "set voltage" command and then attempt to read the devicestring again. */
- if (dediprog_check_devicestring()) {
- if (dediprog_set_voltage())
- return 1;
- if (dediprog_check_devicestring())
- return 1;
+ if (dediprog_check_devicestring(dp_data)) {
+ if (dediprog_set_voltage(dp_data->handle))
+ goto init_err_cleanup_exit;
+ if (dediprog_check_devicestring(dp_data))
+ goto init_err_cleanup_exit;
}
/* SF100/SF200 uses one in/out endpoint, SF600 uses separate in/out endpoints */
- dediprog_in_endpoint = 2;
- switch (dediprog_devicetype) {
+ dp_data->in_endpoint = 2;
+ switch (dp_data->devicetype) {
case DEV_SF100:
case DEV_SF200:
- dediprog_out_endpoint = 2;
+ dp_data->out_endpoint = 2;
break;
default:
- dediprog_out_endpoint = 1;
+ dp_data->out_endpoint = 1;
break;
}
/* Set all possible LEDs as soon as possible to indicate activity.
* Because knowing the firmware version is required to set the LEDs correctly we need to this after
* dediprog_check_devicestring() has queried the device. */
- dediprog_set_leds(LED_ALL);
+ dediprog_set_leds(LED_ALL, dp_data);
/* Select target/socket, frequency and VCC. */
- if (set_target_flash(target) ||
- dediprog_set_spi_speed(spispeed_idx) ||
- dediprog_set_spi_voltage(millivolt)) {
- dediprog_set_leds(LED_ERROR);
- return 1;
+ if (set_target_flash(dp_data->handle, target) ||
+ dediprog_set_spi_speed(spispeed_idx, dp_data) ||
+ dediprog_set_spi_voltage(dp_data->handle, millivolt)) {
+ dediprog_set_leds(LED_ERROR, dp_data);
+ goto init_err_cleanup_exit;
}
- if (dediprog_standalone_mode())
- return 1;
+ if (dediprog_standalone_mode(dp_data))
+ goto init_err_cleanup_exit;
- if (dediprog_devicetype == DEV_SF100 && protocol() == PROTOCOL_V1)
+ if ((dp_data->devicetype == DEV_SF100) ||
+ (dp_data->devicetype == DEV_SF600 && protocol(dp_data) == PROTOCOL_V3))
spi_master_dediprog.features &= ~SPI_MASTER_NO_4BA_MODES;
- if (protocol() == PROTOCOL_V2)
+ if (protocol(dp_data) >= PROTOCOL_V2)
spi_master_dediprog.features |= SPI_MASTER_4BA;
- if (register_spi_master(&spi_master_dediprog) || dediprog_set_leds(LED_NONE))
- return 1;
+ if (dediprog_set_leds(LED_NONE, dp_data))
+ goto init_err_cleanup_exit;
- return 0;
+ return register_spi_master(&spi_master_dediprog, dp_data);
+
+init_err_cleanup_exit:
+ dediprog_shutdown(dp_data);
+ return 1;
+
+init_err_exit:
+ free(dp_data);
+ return 1;
}
+
+const struct programmer_entry programmer_dediprog = {
+ .name = "dediprog",
+ .type = USB,
+ .devs.dev = devs_dediprog,
+ .init = dediprog_init,
+};
diff --git a/developerbox_spi.c b/developerbox_spi.c
index 4ff2fb609..64b7e8a1b 100644
--- a/developerbox_spi.c
+++ b/developerbox_spi.c
@@ -31,8 +31,6 @@
* should be turned on).
*/
-#include "platform.h"
-
#include <stdlib.h>
#include <libusb.h>
#include "programmer.h"
@@ -55,20 +53,23 @@
#define CP210X_WRITE_LATCH 0x37e1
#define CP210X_READ_LATCH 0x00c2
-const struct dev_entry devs_developerbox_spi[] = {
+static const struct dev_entry devs_developerbox_spi[] = {
{0x10c4, 0xea60, OK, "Silicon Labs", "CP2102N USB to UART Bridge Controller"},
{0},
};
-static struct libusb_context *usb_ctx;
-static libusb_device_handle *cp210x_handle;
+struct devbox_spi_data {
+ struct libusb_context *usb_ctx;
+ libusb_device_handle *cp210x_handle;
+};
-static int cp210x_gpio_get(void)
+static int cp210x_gpio_get(void *spi_data)
{
int res;
uint8_t gpio;
+ struct devbox_spi_data *data = spi_data;
- res = libusb_control_transfer(cp210x_handle, REQTYPE_DEVICE_TO_HOST,
+ res = libusb_control_transfer(data->cp210x_handle, REQTYPE_DEVICE_TO_HOST,
CP210X_VENDOR_SPECIFIC, CP210X_READ_LATCH,
0, &gpio, 1, 0);
if (res < 0) {
@@ -79,72 +80,79 @@ static int cp210x_gpio_get(void)
return gpio;
}
-static void cp210x_gpio_set(uint8_t val, uint8_t mask)
+static void cp210x_gpio_set(uint8_t val, uint8_t mask, void *spi_data)
{
int res;
uint16_t gpio;
+ struct devbox_spi_data *data = spi_data;
gpio = ((val & 0xf) << 8) | (mask & 0xf);
/* Set relay state on the card */
- res = libusb_control_transfer(cp210x_handle, REQTYPE_HOST_TO_DEVICE,
+ res = libusb_control_transfer(data->cp210x_handle, REQTYPE_HOST_TO_DEVICE,
CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH,
gpio, NULL, 0, 0);
if (res < 0)
msg_perr("Failed to read GPIO pins (%s)\n", libusb_error_name(res));
}
-static void cp210x_bitbang_set_cs(int val)
+static void cp210x_bitbang_set_cs(int val, void *spi_data)
{
- cp210x_gpio_set(val << DEVELOPERBOX_SPI_CS, 1 << DEVELOPERBOX_SPI_CS);
+ cp210x_gpio_set(val << DEVELOPERBOX_SPI_CS, 1 << DEVELOPERBOX_SPI_CS, spi_data);
}
-static void cp210x_bitbang_set_sck(int val)
+static void cp210x_bitbang_set_sck(int val, void *spi_data)
{
- cp210x_gpio_set(val << DEVELOPERBOX_SPI_SCK, 1 << DEVELOPERBOX_SPI_SCK);
+ cp210x_gpio_set(val << DEVELOPERBOX_SPI_SCK, 1 << DEVELOPERBOX_SPI_SCK, spi_data);
}
-static void cp210x_bitbang_set_mosi(int val)
+static void cp210x_bitbang_set_mosi(int val, void *spi_data)
{
- cp210x_gpio_set(val << DEVELOPERBOX_SPI_MOSI, 1 << DEVELOPERBOX_SPI_MOSI);
+ cp210x_gpio_set(val << DEVELOPERBOX_SPI_MOSI, 1 << DEVELOPERBOX_SPI_MOSI, spi_data);
}
-static int cp210x_bitbang_get_miso(void)
+static int cp210x_bitbang_get_miso(void *spi_data)
{
- return !!(cp210x_gpio_get() & (1 << DEVELOPERBOX_SPI_MISO));
+ return !!(cp210x_gpio_get(spi_data) & (1 << DEVELOPERBOX_SPI_MISO));
}
-static void cp210x_bitbang_set_sck_set_mosi(int sck, int mosi)
+static void cp210x_bitbang_set_sck_set_mosi(int sck, int mosi, void *spi_data)
{
cp210x_gpio_set(sck << DEVELOPERBOX_SPI_SCK | mosi << DEVELOPERBOX_SPI_MOSI,
- 1 << DEVELOPERBOX_SPI_SCK | 1 << DEVELOPERBOX_SPI_MOSI);
+ 1 << DEVELOPERBOX_SPI_SCK | 1 << DEVELOPERBOX_SPI_MOSI,
+ spi_data);
}
static const struct bitbang_spi_master bitbang_spi_master_cp210x = {
- .set_cs = cp210x_bitbang_set_cs,
- .set_sck = cp210x_bitbang_set_sck,
- .set_mosi = cp210x_bitbang_set_mosi,
- .get_miso = cp210x_bitbang_get_miso,
- .set_sck_set_mosi = cp210x_bitbang_set_sck_set_mosi,
+ .set_cs = cp210x_bitbang_set_cs,
+ .set_sck = cp210x_bitbang_set_sck,
+ .set_mosi = cp210x_bitbang_set_mosi,
+ .get_miso = cp210x_bitbang_get_miso,
+ .set_sck_set_mosi = cp210x_bitbang_set_sck_set_mosi,
};
-static int developerbox_spi_shutdown(void *data)
+static int developerbox_spi_shutdown(void *spi_data)
{
- libusb_close(cp210x_handle);
- libusb_exit(usb_ctx);
+ struct devbox_spi_data *data = spi_data;
+ libusb_close(data->cp210x_handle);
+ libusb_exit(data->usb_ctx);
+
+ free(data);
return 0;
}
-int developerbox_spi_init(void)
+static int developerbox_spi_init(const struct programmer_cfg *cfg)
{
- libusb_init(&usb_ctx);
- if (!usb_ctx) {
+ struct libusb_context *usb_ctx;
+ libusb_device_handle *cp210x_handle;
+
+ if (libusb_init(&usb_ctx)) {
msg_perr("Could not initialize libusb!\n");
return 1;
}
- char *serialno = extract_programmer_param("serial");
+ char *serialno = extract_programmer_param_str(cfg, "serial");
if (serialno)
msg_pdbg("Looking for serial number commencing %s\n", serialno);
cp210x_handle = usb_dev_get_by_vid_pid_serial(usb_ctx,
@@ -155,15 +163,34 @@ int developerbox_spi_init(void)
goto err_exit;
}
- if (register_shutdown(developerbox_spi_shutdown, NULL))
+ struct devbox_spi_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
goto err_exit;
+ }
+ data->usb_ctx = usb_ctx;
+ data->cp210x_handle = cp210x_handle;
- if (register_spi_bitbang_master(&bitbang_spi_master_cp210x))
+ if (register_shutdown(developerbox_spi_shutdown, data)) {
+ free(data);
goto err_exit;
+ }
+
+ if (register_spi_bitbang_master(&bitbang_spi_master_cp210x, data))
+ return 1; /* shutdown function does the cleanup */
return 0;
err_exit:
+ if (cp210x_handle)
+ libusb_close(cp210x_handle);
libusb_exit(usb_ctx);
return 1;
}
+
+const struct programmer_entry programmer_developerbox = {
+ .name = "developerbox",
+ .type = USB,
+ .devs.dev = devs_developerbox_spi,
+ .init = developerbox_spi_init,
+};
diff --git a/digilent_spi.c b/digilent_spi.c
index 0f7a9da12..ef0d23cf7 100644
--- a/digilent_spi.c
+++ b/digilent_spi.c
@@ -45,13 +45,15 @@
#define DATA_WRITE_EP 0x03
#define DATA_READ_EP 0x84
-static struct libusb_device_handle *handle = NULL;
-static bool reset_board;
+struct digilent_spi_data {
+ struct libusb_device_handle *handle;
+ bool reset_board;
+};
#define DIGILENT_VID 0x1443
#define DIGILENT_JTAG_PID 0x0007
-const struct dev_entry devs_digilent_spi[] = {
+static const struct dev_entry devs_digilent_spi[] = {
{ DIGILENT_VID, DIGILENT_JTAG_PID, OK, "Digilent", "Development board JTAG" },
{ 0 },
};
@@ -97,7 +99,7 @@ enum {
CMD_SPI_TX_END = 0x87,
};
-static int do_command(uint8_t *req, int req_len, uint8_t *res, int res_len)
+static int do_command(uint8_t *req, int req_len, uint8_t *res, int res_len, struct libusb_device_handle *handle)
{
int tx_len = 0;
int ret;
@@ -133,41 +135,41 @@ static int do_command(uint8_t *req, int req_len, uint8_t *res, int res_len)
return 0;
}
-static int gpio_open(void)
+static int gpio_open(struct libusb_device_handle *handle)
{
uint8_t req[] = { 0x00, CMD_GPIO, CMD_GPIO_OPEN, 0x00 };
uint8_t res[2];
- return do_command(req, sizeof(req), res, sizeof(res));
+ return do_command(req, sizeof(req), res, sizeof(res), handle);
}
-static int gpio_set_dir(uint8_t direction)
+static int gpio_set_dir(uint8_t direction, struct libusb_device_handle *handle)
{
uint8_t req[] = { 0x00, CMD_GPIO, CMD_GPIO_SET_DIR, 0x00,
direction, 0x00, 0x00, 0x00 };
uint8_t res[6];
- return do_command(req, sizeof(req), res, sizeof(res));
+ return do_command(req, sizeof(req), res, sizeof(res), handle);
}
-static int gpio_set_value(uint8_t value)
+static int gpio_set_value(uint8_t value, struct libusb_device_handle *handle)
{
uint8_t req[] = { 0x00, CMD_GPIO, CMD_GPIO_SET_VAL, 0x00,
value, 0x00, 0x00, 0x00 };
uint8_t res[2];
- return do_command(req, sizeof(req), res, sizeof(res));
+ return do_command(req, sizeof(req), res, sizeof(res), handle);
}
-static int spi_open(void)
+static int spi_open(struct libusb_device_handle *handle)
{
uint8_t req[] = { 0x00, CMD_SPI, CMD_SPI_OPEN, 0x00 };
uint8_t res[2];
- return do_command(req, sizeof(req), res, sizeof(res));
+ return do_command(req, sizeof(req), res, sizeof(res), handle);
}
-static int spi_set_speed(uint32_t speed)
+static int spi_set_speed(uint32_t speed, struct libusb_device_handle *handle)
{
uint8_t req[] = { 0x00, CMD_SPI, CMD_SPI_SET_SPEED, 0x00,
(speed) & 0xff,
@@ -178,7 +180,7 @@ static int spi_set_speed(uint32_t speed)
uint32_t real_speed;
int ret;
- ret = do_command(req, sizeof(req), res, sizeof(res));
+ ret = do_command(req, sizeof(req), res, sizeof(res), handle);
if (ret)
return ret;
@@ -189,23 +191,23 @@ static int spi_set_speed(uint32_t speed)
return 0;
}
-static int spi_set_mode(uint8_t mode)
+static int spi_set_mode(uint8_t mode, struct libusb_device_handle *handle)
{
uint8_t req[] = { 0x00, CMD_SPI, CMD_SPI_SET_MODE, 0x00, mode };
uint8_t res[2];
- return do_command(req, sizeof(req), res, sizeof(res));
+ return do_command(req, sizeof(req), res, sizeof(res), handle);
}
-static int spi_set_cs(uint8_t cs)
+static int spi_set_cs(uint8_t cs, struct libusb_device_handle *handle)
{
uint8_t req[] = { 0x00, CMD_SPI, CMD_SPI_SET_CS, 0x00, cs };
uint8_t res[2];
- return do_command(req, sizeof(req), res, sizeof(res));
+ return do_command(req, sizeof(req), res, sizeof(res), handle);
}
-static int spi_start_io(uint8_t read_follows, uint32_t write_len)
+static int spi_start_io(uint8_t read_follows, uint32_t write_len, struct libusb_device_handle *handle)
{
uint8_t req[] = { 0x00, CMD_SPI, CMD_SPI_START_IO, 0x00,
0x00, 0x00, /* meaning unknown */
@@ -216,17 +218,17 @@ static int spi_start_io(uint8_t read_follows, uint32_t write_len)
(write_len >> 24) & 0xff };
uint8_t res[2];
- return do_command(req, sizeof(req), res, sizeof(res));
+ return do_command(req, sizeof(req), res, sizeof(res), handle);
}
-static int spi_tx_end(uint8_t read_follows, uint32_t tx_len)
+static int spi_tx_end(uint8_t read_follows, uint32_t tx_len, struct libusb_device_handle *handle)
{
uint8_t req[] = { 0x00, CMD_SPI, CMD_SPI_TX_END, 0x00 };
uint8_t res[read_follows ? 10 : 6];
int ret;
uint32_t count;
- ret = do_command(req, sizeof(req), res, sizeof(res));
+ ret = do_command(req, sizeof(req), res, sizeof(res), handle);
if (ret != 0)
return ret;
@@ -265,19 +267,20 @@ static int digilent_spi_send_command(const struct flashctx *flash, unsigned int
int tx_len = 0;
uint8_t buf[len];
uint8_t read_follows = readcnt > 0 ? 1 : 0;
+ struct digilent_spi_data *digilent_data = flash->mst->spi.data;
memcpy(buf, writearr, writecnt);
memset(buf + writecnt, 0xff, readcnt);
- ret = spi_set_cs(0);
+ ret = spi_set_cs(0, digilent_data->handle);
if (ret != 0)
return ret;
- ret = spi_start_io(read_follows, writecnt);
+ ret = spi_start_io(read_follows, writecnt, digilent_data->handle);
if (ret != 0)
return ret;
- ret = libusb_bulk_transfer(handle, DATA_WRITE_EP, buf, len, &tx_len, USB_TIMEOUT);
+ ret = libusb_bulk_transfer(digilent_data->handle, DATA_WRITE_EP, buf, len, &tx_len, USB_TIMEOUT);
if (ret != 0) {
msg_perr("%s: failed to write data: '%s'\n", __func__, libusb_error_name(ret));
return -1;
@@ -288,7 +291,7 @@ static int digilent_spi_send_command(const struct flashctx *flash, unsigned int
}
if (read_follows) {
- ret = libusb_bulk_transfer(handle, DATA_READ_EP, buf, len, &tx_len, USB_TIMEOUT);
+ ret = libusb_bulk_transfer(digilent_data->handle, DATA_READ_EP, buf, len, &tx_len, USB_TIMEOUT);
if (ret != 0) {
msg_perr("%s: failed to read data: '%s'\n", __func__, libusb_error_name(ret));
return -1;
@@ -299,11 +302,11 @@ static int digilent_spi_send_command(const struct flashctx *flash, unsigned int
}
}
- ret = spi_tx_end(read_follows, len);
+ ret = spi_tx_end(read_follows, len, digilent_data->handle);
if (ret != 0)
return ret;
- ret = spi_set_cs(1);
+ ret = spi_set_cs(1, digilent_data->handle);
if (ret != 0)
return ret;
@@ -312,30 +315,30 @@ static int digilent_spi_send_command(const struct flashctx *flash, unsigned int
return 0;
}
+static int digilent_spi_shutdown(void *data)
+{
+ struct digilent_spi_data *digilent_data = data;
+
+ if (digilent_data->reset_board)
+ gpio_set_dir(0, digilent_data->handle);
+
+ libusb_close(digilent_data->handle);
+
+ free(data);
+ return 0;
+}
+
static const struct spi_master spi_master_digilent_spi = {
.features = SPI_MASTER_4BA,
.max_data_read = 252,
.max_data_write = 252,
.command = digilent_spi_send_command,
- .multicommand = default_spi_send_multicommand,
.read = default_spi_read,
.write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .shutdown = digilent_spi_shutdown,
};
-
-static int digilent_spi_shutdown(void *data)
-{
- if (reset_board)
- gpio_set_dir(0);
-
- libusb_close(handle);
- handle = NULL;
-
- return 0;
-}
-
-static bool default_reset(void)
+static bool default_reset(struct libusb_device_handle *handle)
{
char board[17];
@@ -368,16 +371,13 @@ static const struct digilent_spispeeds spispeeds[] = {
{ NULL, 0 },
};
-int digilent_spi_init(void)
+static int digilent_spi_init(const struct programmer_cfg *cfg)
{
- char *p;
+ char *param_str;
uint32_t speed_hz = spispeeds[0].speed;
int i;
-
- if (handle != NULL) {
- msg_cerr("%s: handle already set! Please report a bug at flashrom@flashrom.org\n", __func__);
- return -1;
- }
+ struct libusb_device_handle *handle = NULL;
+ bool reset_board;
int32_t ret = libusb_init(NULL);
if (ret < 0) {
@@ -405,52 +405,64 @@ int digilent_spi_init(void)
goto close_handle;
}
- p = extract_programmer_param("spispeed");
- if (p) {
+ param_str = extract_programmer_param_str(cfg, "spispeed");
+ if (param_str) {
for (i = 0; spispeeds[i].name; ++i) {
- if (!strcasecmp(spispeeds[i].name, p)) {
+ if (!strcasecmp(spispeeds[i].name, param_str)) {
speed_hz = spispeeds[i].speed;
break;
}
}
if (!spispeeds[i].name) {
- msg_perr("Error: Invalid spispeed value: '%s'.\n", p);
- free(p);
+ msg_perr("Error: Invalid spispeed value: '%s'.\n", param_str);
+ free(param_str);
goto close_handle;
}
- free(p);
+ free(param_str);
}
- p = extract_programmer_param("reset");
- if (p && strlen(p))
- reset_board = (p[0] == '1');
+ param_str = extract_programmer_param_str(cfg, "reset");
+ if (param_str && strlen(param_str))
+ reset_board = (param_str[0] == '1');
else
- reset_board = default_reset();
- free(p);
+ reset_board = default_reset(handle);
+ free(param_str);
+
if (reset_board) {
- if (gpio_open() != 0)
+ if (gpio_open(handle) != 0)
goto close_handle;
- if (gpio_set_dir(1) != 0)
+ if (gpio_set_dir(1, handle) != 0)
goto close_handle;
- if (gpio_set_value(0) != 0)
+ if (gpio_set_value(0, handle) != 0)
goto close_handle;
}
- if (spi_open() != 0)
+ if (spi_open(handle) != 0)
goto close_handle;
- if (spi_set_speed(speed_hz) != 0)
+ if (spi_set_speed(speed_hz, handle) != 0)
goto close_handle;
- if (spi_set_mode(0x00) != 0)
+ if (spi_set_mode(0x00, handle) != 0)
goto close_handle;
- register_shutdown(digilent_spi_shutdown, NULL);
- register_spi_master(&spi_master_digilent_spi);
+ struct digilent_spi_data *digilent_data = calloc(1, sizeof(*digilent_data));
+ if (!digilent_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ goto close_handle;
+ }
+ digilent_data->reset_board = reset_board;
+ digilent_data->handle = handle;
- return 0;
+ return register_spi_master(&spi_master_digilent_spi, digilent_data);
close_handle:
libusb_close(handle);
- handle = NULL;
return -1;
}
+
+const struct programmer_entry programmer_digilent_spi = {
+ .name = "digilent_spi",
+ .type = USB,
+ .devs.dev = devs_digilent_spi,
+ .init = digilent_spi_init,
+};
diff --git a/dirtyjtag_spi.c b/dirtyjtag_spi.c
new file mode 100644
index 000000000..19764f62b
--- /dev/null
+++ b/dirtyjtag_spi.c
@@ -0,0 +1,318 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2021-2022 Jean THOMAS <virgule@jeanthomas.me>
+ *
+ * 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.
+ */
+
+/*
+ * Driver for the DirtyJTAG project.
+ * See https://github.com/jeanthom/dirtyjtag for more info.
+ *
+ * SPI-JTAG Pin Mapping
+ * |=========|==========|
+ * | SPI pin | JTAG pin |
+ * |=========|==========|
+ * | #CS | TMS |
+ * | #WP | SRST |
+ * | #HOLD | TRST |
+ * | MISO | TDO |
+ * | MOSI | TDI |
+ * | CLK | TCK |
+ * |=========|==========|
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <libusb.h>
+#include "programmer.h"
+
+struct dirtyjtag_spi_data {
+ struct libusb_context *libusb_ctx;
+ struct libusb_device_handle *libusb_handle;
+};
+
+static const struct dev_entry devs_dirtyjtag_spi[] = {
+ { 0x1209, 0xc0ca, OK, "DirtyJTAG", "JTAG probe" },
+ { 0 },
+};
+
+static const char dirtyjtag_write_endpoint = 0x01;
+static const char dirtyjtag_read_endpoint = 0x82;
+static const int dirtyjtag_timeout = 100 * 10; /* 100 ms */
+
+enum dirtyjtag_command_identifier {
+ CMD_STOP = 0x00,
+ CMD_INFO = 0x01,
+ CMD_FREQ = 0x02,
+ CMD_XFER = 0x03,
+ CMD_SETSIG = 0x04,
+ CMD_GETSIG = 0x05,
+ CMD_CLK = 0x06
+};
+
+enum dirtyjtag_signal_identifier {
+ SIG_TCK = 1 << 1,
+ SIG_TDI = 1 << 2,
+ SIG_TDO = 1 << 3,
+ SIG_TMS = 1 << 4,
+ SIG_TRST = 1 << 5,
+ SIG_SRST = 1 << 6
+};
+
+static int dirtyjtag_send(struct dirtyjtag_spi_data *djtag_data, uint8_t *data, size_t len)
+{
+ int transferred;
+ int ret = libusb_bulk_transfer(djtag_data->libusb_handle,
+ dirtyjtag_write_endpoint,
+ data,
+ len,
+ &transferred,
+ dirtyjtag_timeout);
+ if (ret != 0) {
+ msg_perr("%s: failed to send query command\n", __func__);
+ return -1;
+ }
+ if (transferred != (int)len) {
+ msg_perr("%s: failed to send whole packet\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int dirtyjtag_receive(struct dirtyjtag_spi_data *djtag_data, uint8_t *data, size_t buffer_len, int expected)
+{
+ int transferred;
+ int ret = libusb_bulk_transfer(djtag_data->libusb_handle,
+ dirtyjtag_read_endpoint,
+ data,
+ buffer_len,
+ &transferred,
+ dirtyjtag_timeout);
+ if (ret != 0) {
+ msg_perr("%s: Failed to read SPI commands\n", __func__);
+ return -1;
+ }
+
+ if (expected != -1 && transferred != expected) {
+ msg_perr("%s: failed to meet expected\n", __func__);
+ return -1;
+ }
+
+ return transferred;
+}
+
+static int dirtyjtag_spi_shutdown(void *data)
+{
+ struct dirtyjtag_spi_data *djtag_data = (struct dirtyjtag_spi_data*)data;
+ libusb_release_interface(djtag_data->libusb_handle, 0);
+ libusb_attach_kernel_driver(djtag_data->libusb_handle, 0);
+ libusb_close(djtag_data->libusb_handle);
+ libusb_exit(djtag_data->libusb_ctx);
+ free(data);
+ return 0;
+}
+
+static int dirtyjtag_djtag1_spi_send_command(struct dirtyjtag_spi_data *context,
+ unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
+{
+ const size_t max_xfer_size = 30; // max transfer size in DJTAG1
+ size_t len = writecnt + readcnt;
+ size_t num_xfer = (len + max_xfer_size - 1 ) / max_xfer_size; // ceil(len/max_xfer_size)
+
+ uint8_t *rxtx_buffer = malloc(max_xfer_size * num_xfer);
+ if (!rxtx_buffer) {
+ msg_perr("%s: Failed rxtx_buffer allocation\n", __func__);
+ return -1;
+ }
+
+ memcpy(rxtx_buffer, writearr, writecnt);
+ for (size_t i = 0; i < num_xfer; i++) {
+ const size_t xfer_offset = i * max_xfer_size;
+ size_t txn_size = max_xfer_size;
+ if (i == num_xfer-1 && len % max_xfer_size != 0)
+ txn_size = len % max_xfer_size;
+
+ uint8_t transfer_buffer[32] = {
+ CMD_XFER,
+ txn_size * 8
+ };
+ memcpy(transfer_buffer + 2, rxtx_buffer + xfer_offset, txn_size);
+
+ if (dirtyjtag_send(context, transfer_buffer, sizeof(transfer_buffer)))
+ goto cleanup_fail;
+
+ if (dirtyjtag_receive(context, transfer_buffer, sizeof(transfer_buffer), 32) < 0)
+ goto cleanup_fail;
+
+ memcpy(rxtx_buffer + xfer_offset, transfer_buffer, txn_size);
+ }
+ memcpy(readarr, rxtx_buffer + writecnt, readcnt);
+
+ free(rxtx_buffer);
+
+ uint8_t tms_reset_buffer[] = {
+ CMD_SETSIG,
+ SIG_TMS,
+ SIG_TMS,
+
+ CMD_STOP,
+ };
+ dirtyjtag_send(context, tms_reset_buffer, sizeof(tms_reset_buffer));
+
+ return 0;
+
+cleanup_fail:
+ free(rxtx_buffer);
+ return -1;
+}
+
+static int dirtyjtag_spi_spi_send_command(const struct flashctx *flash,
+ unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr)
+{
+ struct dirtyjtag_spi_data *djtag_data = flash->mst->spi.data;
+ return dirtyjtag_djtag1_spi_send_command(djtag_data, writecnt, readcnt, writearr, readarr);
+}
+
+static const struct spi_master spi_master_dirtyjtag_spi = {
+ .features = SPI_MASTER_4BA,
+ .max_data_read = MAX_DATA_READ_UNLIMITED,
+ .max_data_write = MAX_DATA_WRITE_UNLIMITED,
+ .command = dirtyjtag_spi_spi_send_command,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .write_aai = default_spi_write_aai,
+ .shutdown = dirtyjtag_spi_shutdown,
+};
+
+static int dirtyjtag_spi_init(const struct programmer_cfg *cfg)
+{
+ struct libusb_device_handle *handle = NULL;
+ struct dirtyjtag_spi_data *djtag_data = NULL;
+
+ djtag_data = calloc(1, sizeof(struct dirtyjtag_spi_data));
+ if (djtag_data == NULL) {
+ msg_perr("%s: failed to allocate internal driver data structure\n", __func__);
+ return -1;
+ }
+
+ int ret = libusb_init(&djtag_data->libusb_ctx);
+ if (ret < 0) {
+ msg_perr("%s: couldn't initialize libusb!\n", __func__);
+ goto cleanup_djtag_struct;
+ }
+
+#if LIBUSB_API_VERSION < 0x01000106
+ libusb_set_debug(djtag_data->libusb_ctx, 3);
+#else
+ libusb_set_option(djtag_data->libusb_ctx, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
+#endif
+
+ uint16_t vid = devs_dirtyjtag_spi[0].vendor_id;
+ uint16_t pid = devs_dirtyjtag_spi[0].device_id;
+ handle = libusb_open_device_with_vid_pid(djtag_data->libusb_ctx, vid, pid);
+ if (handle == NULL) {
+ msg_perr("%s: couldn't open device %04x:%04x.\n", __func__, vid, pid);
+ goto cleanup_libusb_ctx;
+ }
+
+ ret = libusb_detach_kernel_driver(handle, 0);
+ if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) {
+ msg_pwarn("Cannot detach the existing USB driver. Claiming the interface may fail. %s\n",
+ libusb_error_name(ret));
+ }
+
+ ret = libusb_claim_interface(handle, 0);
+ if (ret != 0) {
+ msg_perr("%s: failed to claim interface 0: '%s'\n", __func__, libusb_error_name(ret));
+ goto cleanup_libusb_handle;
+ }
+
+ djtag_data->libusb_handle = handle;
+
+ unsigned long int freq = 100;
+ char *tmp = extract_programmer_param_str(cfg, "spispeed");
+ if (tmp) {
+ char *units = tmp;
+
+ errno = 0;
+ freq = strtoul(tmp, &units, 0);
+ if (errno) {
+ msg_perr("Invalid frequency \"%s\", %s\n", tmp, strerror(errno));
+ free(tmp);
+ goto cleanup_libusb_handle;
+ }
+
+ if (!strcasecmp(units, "hz")) {
+ freq /= 1000;
+ } else if (!strcasecmp(units, "khz")) {
+ /* Do nothing, already in the right unit */
+ } else if (!strcasecmp(units, "mhz")) {
+ freq *= 1000;
+ } else {
+ msg_perr("Invalid unit: %s, use hz, khz or mhz\n", units);
+ free(tmp);
+ goto cleanup_libusb_handle;
+ }
+
+ if (freq > UINT16_MAX) {
+ msg_perr("%s: Frequency set above DJTAG1 limits (%d kHz)", __func__, UINT16_MAX);
+ free(tmp);
+ goto cleanup_libusb_handle;
+ }
+
+ msg_pinfo("%s: programmer speed set to %lu kHz\n", __func__, freq);
+ }
+ free(tmp);
+
+ uint8_t commands[] = {
+ CMD_SETSIG, /* Set TDI/TCK to low, SRST/TRST/TMS to high */
+ SIG_TDI | SIG_TMS | SIG_TCK | SIG_SRST | SIG_TRST,
+ SIG_SRST | SIG_TRST | SIG_TMS,
+
+ CMD_FREQ, /* Set frequency */
+ (freq >> 8) & 0xff,
+ freq & 0xff,
+
+ CMD_STOP,
+ };
+ ret = dirtyjtag_send(djtag_data, commands, sizeof(commands));
+ if (ret != 0) {
+ msg_perr("%s: failed to configure DirtyJTAG into initialized state\n", __func__);
+ goto cleanup_libusb_handle;
+ }
+
+ return register_spi_master(&spi_master_dirtyjtag_spi, (void*)djtag_data);
+
+cleanup_libusb_handle:
+ libusb_attach_kernel_driver(handle, 0);
+ libusb_close(handle);
+
+cleanup_libusb_ctx:
+ libusb_exit(djtag_data->libusb_ctx);
+
+cleanup_djtag_struct:
+ free(djtag_data);
+ return -1;
+}
+
+const struct programmer_entry programmer_dirtyjtag_spi = {
+ .name = "dirtyjtag_spi",
+ .type = USB,
+ .devs.dev = devs_dirtyjtag_spi,
+ .init = dirtyjtag_spi_init,
+};
diff --git a/dmi.c b/dmi.c
index 3b717cd23..94e47fb49 100644
--- a/dmi.c
+++ b/dmi.c
@@ -19,9 +19,7 @@
/* strnlen is in POSIX but was a GNU extension up to glibc 2.10 */
#if (__GLIBC__ == 2 && __GLIBC_MINOR__ < 10) || __GLIBC__ < 2
-#ifndef _GNU_SOURCE
#define _GNU_SOURCE
-#endif /* !GNU_SOURCE */
#else
#define _POSIX_C_SOURCE 200809L
#endif
@@ -29,11 +27,12 @@
#include <strings.h>
#include <string.h>
#include <ctype.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
-#include "platform.h"
#include "flash.h"
+#include "hwaccess_physmap.h"
#include "programmer.h"
/* Enable SMBIOS decoding. Currently legacy DMI decoding is enough. */
@@ -42,7 +41,12 @@
/* Strings longer than 4096 in DMI are just insane. */
#define DMI_MAX_ANSWER_LEN 4096
-int has_dmi_support = 0;
+static bool g_has_dmi_support = false;
+
+bool dmi_is_supported(void)
+{
+ return g_has_dmi_support;
+}
static struct {
const char *const keyword;
@@ -147,11 +151,11 @@ static char *dmi_string(const char *buf, uint8_t string_id, const char *limit)
return newbuf;
}
-static void dmi_chassis_type(uint8_t code)
+static int dmi_chassis_type(uint8_t code)
{
unsigned int i;
code &= 0x7f; /* bits 6:0 are chassis type, 7th bit is the lock bit */
- is_laptop = 2;
+ int is_laptop = 2;
for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) {
if (code == dmi_chassis_types[i].type) {
msg_pdbg("DMI string chassis-type: \"%s\"\n", dmi_chassis_types[i].name);
@@ -159,14 +163,15 @@ static void dmi_chassis_type(uint8_t code)
break;
}
}
+ return is_laptop;
}
-static void dmi_table(uint32_t base, uint16_t len, uint16_t num)
+static void dmi_table(uint32_t base, uint16_t len, uint16_t num, int *is_laptop)
{
unsigned int i = 0, j = 0;
uint8_t *dmi_table_mem = physmap_ro("DMI Table", base, len);
- if (dmi_table_mem == NULL) {
+ if (dmi_table_mem == ERROR_PTR) {
msg_perr("Unable to access DMI Table\n");
return;
}
@@ -184,7 +189,7 @@ static void dmi_table(uint32_t base, uint16_t len, uint16_t num)
* is invalid, but we cannot reliably locate the next entry.
* - If the length value indicates that this structure spreads
* across the table border, something is fishy too.
- * Better stop at this point, and let the user know his/her
+ * Better stop at this point, and let the user know their
* table is broken.
*/
if (data[1] < 4 || data + data[1] >= limit) {
@@ -194,7 +199,7 @@ static void dmi_table(uint32_t base, uint16_t len, uint16_t num)
if(data[0] == 3) {
if (data + 5 < limit)
- dmi_chassis_type(data[5]);
+ *is_laptop = dmi_chassis_type(data[5]);
else /* the table is broken, but laptop detection is optional, hence continue. */
msg_pwarn("DMI table is broken (chassis_type out of bounds)!\n");
} else
@@ -228,7 +233,7 @@ out:
}
#if SM_SUPPORT
-static int smbios_decode(uint8_t *buf)
+static int smbios_decode(uint8_t *buf, int *is_laptop)
{
/* TODO: other checks mentioned in the conformance guidelines? */
if (!dmi_checksum(buf, buf[0x05]) ||
@@ -236,23 +241,23 @@ static int smbios_decode(uint8_t *buf)
!dmi_checksum(buf + 0x10, 0x0F))
return 0;
- dmi_table(mmio_readl(buf + 0x18), mmio_readw(buf + 0x16), mmio_readw(buf + 0x1C));
+ dmi_table(mmio_readl(buf + 0x18), mmio_readw(buf + 0x16), mmio_readw(buf + 0x1C), is_laptop);
return 1;
}
#endif
-static int legacy_decode(uint8_t *buf)
+static int legacy_decode(uint8_t *buf, int *is_laptop)
{
if (!dmi_checksum(buf, 0x0F))
return 1;
- dmi_table(mmio_readl(buf + 0x08), mmio_readw(buf + 0x06), mmio_readw(buf + 0x0C));
+ dmi_table(mmio_readl(buf + 0x08), mmio_readw(buf + 0x06), mmio_readw(buf + 0x0C), is_laptop);
return 0;
}
-static int dmi_fill(void)
+static int dmi_fill(int *is_laptop)
{
size_t fp;
uint8_t *dmi_mem;
@@ -270,12 +275,12 @@ static int dmi_fill(void)
for (fp = 0; fp <= 0xFFF0; fp += 16) {
#if SM_SUPPORT
if (memcmp(dmi_mem + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) {
- if (smbios_decode(dmi_mem + fp)) // FIXME: length check
+ if (smbios_decode(dmi_mem + fp), is_laptop) // FIXME: length check
goto out;
} else
#endif
if (memcmp(dmi_mem + fp, "_DMI_", 5) == 0)
- if (legacy_decode(dmi_mem + fp) == 0) {
+ if (legacy_decode(dmi_mem + fp, is_laptop) == 0) {
ret = 0;
goto out;
}
@@ -346,7 +351,7 @@ static char *get_dmi_string(const char *string_name)
return result;
}
-static int dmi_fill(void)
+static int dmi_fill(int *is_laptop)
{
unsigned int i;
char *chassis_type;
@@ -363,10 +368,10 @@ static int dmi_fill(void)
return 0; /* chassis-type handling is optional anyway */
msg_pdbg("DMI string chassis-type: \"%s\"\n", chassis_type);
- is_laptop = 2;
+ *is_laptop = 2;
for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) {
if (strcasecmp(chassis_type, dmi_chassis_types[i].name) == 0) {
- is_laptop = dmi_chassis_types[i].is_laptop;
+ *is_laptop = dmi_chassis_types[i].is_laptop;
break;
}
}
@@ -383,10 +388,11 @@ static int dmi_shutdown(void *data)
free(dmi_strings[i].value);
dmi_strings[i].value = NULL;
}
+ g_has_dmi_support = false;
return 0;
}
-void dmi_init(void)
+void dmi_init(int *is_laptop)
{
/* Register shutdown function before we allocate anything. */
if (register_shutdown(dmi_shutdown, NULL)) {
@@ -394,11 +400,11 @@ void dmi_init(void)
return;
}
- /* dmi_fill fills the dmi_strings array, and if possible sets the global is_laptop variable. */
- if (dmi_fill() != 0)
+ /* dmi_fill fills the dmi_strings array, and if possible set the is_laptop parameter. */
+ if (dmi_fill(is_laptop) != 0)
return;
- switch (is_laptop) {
+ switch (*is_laptop) {
case 1:
msg_pdbg("Laptop detected via DMI.\n");
break;
@@ -407,7 +413,7 @@ void dmi_init(void)
break;
}
- has_dmi_support = 1;
+ g_has_dmi_support = true;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) {
msg_pdbg("DMI string %s: \"%s\"\n", dmi_strings[i].keyword,
@@ -428,7 +434,7 @@ void dmi_init(void)
*/
static int dmi_compare(const char *value, const char *pattern)
{
- int anchored = 0;
+ bool anchored = false;
int patternlen;
msg_pspew("matching %s against %s\n", value, pattern);
@@ -437,7 +443,7 @@ static int dmi_compare(const char *value, const char *pattern)
return 1;
if (pattern[0] == '^') {
- anchored = 1;
+ anchored = true;
pattern++;
}
@@ -454,7 +460,7 @@ static int dmi_compare(const char *value, const char *pattern)
/* start character to make ends match */
value += valuelen - patternlen;
- anchored = 1;
+ anchored = true;
}
if (anchored)
@@ -467,7 +473,7 @@ int dmi_match(const char *pattern)
{
unsigned int i;
- if (!has_dmi_support)
+ if (!dmi_is_supported())
return 0;
for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) {
diff --git a/doc/about_flashrom/index.rst b/doc/about_flashrom/index.rst
new file mode 100644
index 000000000..de36fc2a6
--- /dev/null
+++ b/doc/about_flashrom/index.rst
@@ -0,0 +1,7 @@
+About flashrom
+==============
+
+.. toctree::
+ :maxdepth: 1
+
+ team
diff --git a/doc/about_flashrom/team.rst b/doc/about_flashrom/team.rst
new file mode 100644
index 000000000..9d002bb66
--- /dev/null
+++ b/doc/about_flashrom/team.rst
@@ -0,0 +1,61 @@
+=========
+Team
+=========
+
+flashrom development process is happening in Gerrit.
+All contributors and users who have a Gerrit account can send patches,
+add comments to patches and vote +1..-1 on patches.
+
+All contributors and users are expected to follow Development guidelines,
+Code of Conduct and Friendliness guidelines.
+
+There are two special groups in Gerrit.
+
+"flashrom reviewers" group
+==========================
+
+Members of the group can do full approval of patches (i.e. vote +2).
+
+In general, members of the group have some area of responsibility in the MAINTAINERS file,
+and are automatically added as reviewers to patches when the patch touches this area.
+
+The responsibilities are the following.
+
+* React to patches when added as a reviewer.
+
+* Try to respond to technical questions on the mailing list if the topic is something you know about
+ and can provide a useful response.
+
+* Know development guidelines and check the patches you are reviewing align with the guidelines.
+
+"flashrom developers" group
+===========================
+
+Members of the group can merge patches.
+The responsibilities for the members of the group are described in more details below.
+
+There is no expectation on how much time you spend on your duties, some non-zero amount of time,
+whatever capacity you have. But in general, you stay around on flashrom.
+
+If you disappear for some time (life happens), especially for a longer time, like several months,
+especially without a warning: you implicitly agree that the others will handle the duties and make decisions if needed
+(potentially without waiting for you to come back, if the decision is needed quickly).
+
+* Merge all contributors's patches (when they are ready), not just your own.
+
+* Be at least vaguely aware what development efforts are ongoing, this helps to make decisions
+ in what order the patches should be merged, and where could be merge conflicts.
+
+* Know development guidelines, and educate other contributors if needed (e.g. give links).
+
+* React to patches when added as a reviewer.
+
+* Try to respond to technical questions on the mailing list if the topic is something you know about
+ and can provide a useful response.
+
+* From time to time show up in real-time channel(s) and/or dev meetings.
+
+* Follow the Code of Conduct and Friendliness guidelines, be a good example for others.
+
+* Bonus point: if you work in a [software] company, educate and help contributors from your company
+ with upstream culture and dev guidelines.
diff --git a/doc/classic_cli_manpage.rst b/doc/classic_cli_manpage.rst
new file mode 100644
index 000000000..9a455b08a
--- /dev/null
+++ b/doc/classic_cli_manpage.rst
@@ -0,0 +1,1370 @@
+Manual page
+===========
+
+
+NAME
+----
+
+**flashrom** - detect, read, write, verify and erase flash chips
+
+
+SYNOPSIS
+--------
+
+| **flashrom** [-h|-R|-L|-z|
+| -p <programmername>[:<parameters>] [-c <chipname>]
+| (--flash-name|--flash-size|
+| [-E|-x|-r <file>|-w <file>|-v <file>]
+| [(-l <file>|--ifd|--fmap|--fmap-file <file>)
+| [-i <include>[:<file>]]]
+| [--wp-status] [--wp-list] [--wp-enable|--wp-disable]
+| [--wp-range <start>,<length>|--wp-region <region>]
+| [-n] [-N] [-f])]
+| [-V[V[V]]] [-o <logfile>] [--progress]
+
+
+DESCRIPTION
+-----------
+
+**flashrom** is a utility for detecting, reading, writing, verifying and erasing flash chips.
+It's often used to flash BIOS/EFI/coreboot/firmware images in-system using a supported mainboard.
+However, it also supports various external PCI/USB/parallel-port/serial-port based devices which can program flash
+chips, including some network cards (NICs), SATA/IDE controller cards, graphics cards, the Bus Pirate device,
+various FTDI FT2232/FT4232H/FT4233H/FT232H based USB devices, and more.
+
+It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, TSOP40, TSOP48, and BGA chips,
+which use various protocols such as LPC, FWH, parallel flash, or SPI.
+
+
+OPTIONS
+-------
+
+You can specify one of ``-h``, ``-R``, ``-L``, ``-z``, ``-E``, ``-r``, ``-w``, ``-v`` or no operation.
+If no operation is specified, **flashrom** will only probe for flash chips. It is recommended that if you try **flashrom** the
+first time on a system, you run it in probe-only mode and check the output.
+Also you are advised to make a backup of your current ROM contents with ``-r`` before you try to write a new image.
+All operations involving any chip access (probe/read/write/...) require the ``-p/--programmer`` option to be used (please see below).
+
+
+**-r, --read <file>**
+ Read flash ROM contents and save them into the given **<file>**.
+ If the file already exists, it will be overwritten.
+
+
+**-w, --write (<file>|-)**
+ Write **<file>** into flash ROM. If **-** is provided instead, contents will be read from stdin.
+ This will first automatically erase the chip, then write to it.
+
+ In the process the chip is also read several times. First an in-memory backup is made for disaster recovery and to be
+ able to skip regions that are already equal to the image file.
+ This copy is updated along with the write operation. In case of erase errors it is even re-read completely.
+ After writing has finished and if verification is enabled, the whole flash chip is read out and compared with the input image.
+
+
+**-n, --noverify**
+ Skip the automatic verification of flash ROM contents after writing. Using this option is **not** recommended,
+ you should only use it if you know what you are doing and if you feel that the time for verification takes too long.
+
+ Typical usage is::
+
+ flashrom -p prog -n -w <file>
+
+ This option is only useful in combination with ``--write``.
+
+
+**-N, --noverify-all**
+ Skip not included regions during automatic verification after writing (cf. ``-l`` and ``-i``).
+ You should only use this option if you are sure that communication with the flash chip is reliable
+ (e.g. when using the **internal** programmer).
+ Even if **flashrom** is instructed not to touch parts of the flash chip, their contents could be damaged
+ (e.g. due to misunderstood erase commands).
+
+ This option is required to flash an Intel system with locked ME flash region using the **internal** programmer.
+ It may be enabled by default in this case in the future.
+
+
+**-v, --verify (<file>|-)**
+ Verify the flash ROM contents against the given **<file>**.
+ If **-** is provided instead, contents will be written to the stdout.
+
+
+**-E, --erase**
+ Erase the flash ROM chip.
+
+
+**-x, --extract**
+ Extract every region defined on the layout from flash ROM chip to a file with the same name as the extracted region
+ (replacing spaces with underscores).
+
+
+**-V, --verbose**
+ More verbose output. This option can be supplied multiple times (max. 3 times, i.e. ``-VVV`` ) for even more debug output.
+
+
+**-c, --chip <chipname>**
+ Probe only for the specified flash ROM chip. This option takes the chip name as printed by ``flashrom -L`` without the
+ vendor name as parameter. Please note that the chip name is case sensitive.
+
+
+**-f, --force**
+ Force one or more of the following actions:
+
+ * Force chip read and pretend the chip is there.
+ * Force chip access even if the chip is bigger than the maximum supported size for the flash bus.
+ * Force erase even if erase is known bad.
+ * Force write even if write is known bad.
+
+
+**-l, --layout <file>**
+ Read ROM layout from **<file>**.
+
+ **flashrom** supports ROM layouts. This allows you to flash certain parts of the flash chip only.
+ A ROM layout file contains multiple lines with the following syntax::
+
+ startaddr:endaddr imagename
+
+ ``startaddr`` and ``endaddr`` are hexadecimal addresses within the ROM file and do not refer to any physical address.
+ Please note that using a 0x prefix for those hexadecimal numbers is not necessary, but you can't specify decimal/octal numbers.
+ ``imagename`` is an arbitrary name for the region/image from ``startaddr`` to ``endaddr`` (both addresses included).
+
+ Example::
+
+ 00000000:00008fff gfxrom
+ 00009000:0003ffff normal
+ 00040000:0007ffff fallback
+
+ If you only want to update the image named **normal** in a ROM based on the layout above, run::
+
+ flashrom -p prog --layout rom.layout --image normal -w some.rom
+
+ To update only the images named **normal** and **fallback**, run::
+
+ flashrom -p prog -l rom.layout -i normal -i fallback -w some.rom
+
+ Overlapping sections are not supported.
+
+
+**--fmap**
+ Read layout from fmap in flash chip.
+
+ **flashrom** supports the fmap binary format which is commonly used by coreboot for partitioning a flash chip.
+ The on-chip fmap will be read and used to generate the layout.
+
+ If you only want to update the **COREBOOT** region defined in the fmap, run::
+
+ flashrom -p prog --fmap --image COREBOOT -w some.rom
+
+
+**--fmap-file <file>**
+ Read layout from a **<file>** containing binary fmap (e.g. coreboot roms).
+
+ **flashrom** supports the fmap binary format which is commonly used by coreboot for partitioning a flash chip.
+ The fmap in the specified file will be read and used to generate the layout.
+
+ If you only want to update the **COREBOOT** region defined in the binary fmap file, run::
+
+ flashrom -p prog --fmap-file some.rom --image COREBOOT -w some.rom
+
+
+**--ifd**
+ Read ROM layout from Intel Firmware Descriptor.
+
+ **flashrom** supports ROM layouts given by an Intel Firmware Descriptor (IFD).
+ The on-chip descriptor will be read and used to generate the layout. If you need to change the layout,
+ you have to update the IFD only first.
+
+ The following ROM images may be present in an IFD:
+
+ | ``fd`` - the IFD itself
+ | ``bios`` - the host firmware aka. BIOS
+ | ``me`` - Intel Management Engine firmware
+ | ``gbe`` - gigabit ethernet firmware
+ | ``pd`` - platform specific data
+
+
+**-i, --include <region>[:<file>]**
+ Read or write only **<region>** to or from ROM.
+ The **-i** option may be used multiple times if the user wishes to read or write multiple regions using a single command.
+
+ The user may optionally specify a corresponding **<file>** for any region they wish to read or write.
+ A read operation will read the corresponding regions from ROM and write individual files for each one.
+ A write option will read file(s) and write to the corresponding region(s) in ROM.
+
+ For write operations, files specified using ``-i`` take precedence over content from the argument to ``-w``.
+
+ Examples:
+ To read regions named **foo** and **bar** in layout file **<layout>** into region-sized files **foo.bin** and **bar.bin**, run::
+
+ flashrom -p prog -l <layout> -i foo:foo.bin -i bar:bar.bin -r rom.bin
+
+ To write files **foo.bin** and **bar.bin** into regions named **foo** and **bar** in layout file **<layout>** to the ROM, run::
+
+ flashrom -p prog -l <layout> -i foo:foo.bin -i bar:bar.bin -w rom.bin
+
+
+**--wp-status**
+ Prints the flash's current status register protection mode and write protection range.
+
+
+**--wp-list**
+ Prints a list of all protection ranges that the flash supports.
+
+
+**--wp-enable**
+ Enables hardware status register protection (SRP) if the flash supports it.
+ Once SRP is enabled, operations that change the flash's status registers (including ``--wp-disable`` and ``--wp-range``)
+ can only be performed if the flash's #WP pin is at an inactive logic level.
+
+
+**--wp-disable**
+ Disables status register protection if the flash allows it.
+
+
+**--wp-range <start>,<length>**
+ Configures the flash to protect a range of addresses from <start> to (<start> + <length> - 1), bounds inclusive.
+ The range must be supported by the flash, see ``--wp-list``.
+
+
+**--wp-region <region>**
+ Same as ``--wp-range`` but protects the range occupied by an image region.
+ This option requires a image layout to be specified, see ``--layout``.
+ The region must be supported by the flash, see ``--wp-list``.
+
+
+**--flash-name**
+ Prints out the detected flash chip's name.
+
+
+**--flash-size**
+ Prints out the detected flash chip's size.
+
+
+**--flash-contents <ref-file>**
+ The file contents of **<ref-file>** will be used to decide which parts of the flash need to be written.
+ Providing this saves an initial read of the full flash chip.
+ Be careful, if the provided data doesn't actually match the flash contents, results are undefined.
+
+
+**-L, --list-supported**
+ List the flash chips, chipsets, mainboards, and external programmers (including PCI, USB, parallel port, and serial port based devices)
+ supported by **flashrom**.
+
+ There are many unlisted boards which will work out of the box, without special support in **flashrom**.
+ Please let us know if you can verify that other boards work or do not work out of the box.
+
+ **IMPORTANT**:
+ For verification you have to test an ERASE and/or WRITE operation, so make sure you only do that if you have proper means to recover from failure!
+
+
+**-z, --list-supported-wiki**
+ Same as ``--list-supported``, but outputs the supported hardware in MediaWiki syntax,
+ so that it can be easily pasted into the `supported hardware wiki page <https://flashrom.org/Supported_hardware>`_.
+ Please note that MediaWiki output is not compiled in by default.
+
+
+**-p, --programmer <name>[:parameter[,parameter[,parameter]]]**
+ Specify the programmer device. This is mandatory for all operations involving any chip access (probe/read/write/...).
+ Currently supported are:
+
+ * ``internal`` (for in-system flashing in the mainboard)
+ * ``dummy`` (virtual programmer for testing **flashrom**)
+ * ``nic3com`` (for flash ROMs on 3COM network cards)
+ * ``nicrealtek`` (for flash ROMs on Realtek and SMC 1211 network cards)
+ * ``nicnatsemi`` (for flash ROMs on National Semiconductor DP838* network cards)
+ * ``nicintel`` (for parallel flash ROMs on Intel 10/100Mbit network cards)
+ * ``gfxnvidia`` (for flash ROMs on NVIDIA graphics cards)
+ * ``drkaiser`` (for flash ROMs on Dr. Kaiser PC-Waechter PCI cards)
+ * ``satasii`` (for flash ROMs on Silicon Image SATA/IDE controllers)
+ * ``satamv`` (for flash ROMs on Marvell SATA controllers)
+ * ``atahpt`` (for flash ROMs on Highpoint ATA/RAID controllers)
+ * ``atavia`` (for flash ROMs on VIA VT6421A SATA controllers)
+ * ``atapromise`` (for flash ROMs on Promise PDC2026x ATA/RAID controllers)
+ * ``it8212`` (for flash ROMs on ITE IT8212F ATA/RAID controller)
+ * ``ft2232_spi`` (for SPI flash ROMs attached to an FT2232/FT4232H/FT232H family based USB SPI programmer)
+ * ``serprog`` (for flash ROMs attached to a programmer speaking serprog, including some Arduino-based devices)
+ * ``buspirate_spi`` (for SPI flash ROMs attached to a Bus Pirate)
+ * ``dediprog`` (for SPI flash ROMs attached to a Dediprog SF100)
+ * ``rayer_spi`` (for SPI flash ROMs attached to a parallel port by one of various cable types)
+ * ``raiden_debug_spi`` (For Chrome EC based debug tools - SuzyQable, Servo V4, C2D2 & uServo)
+ * ``pony_spi`` (for SPI flash ROMs attached to a SI-Prog serial port bitbanging adapter)
+ * ``nicintel_spi`` (for SPI flash ROMs on Intel Gigabit network cards)
+ * ``ogp_spi`` (for SPI flash ROMs on Open Graphics Project graphics card)
+ * ``linux_mtd`` (for SPI flash ROMs accessible via /dev/mtdX on Linux)
+ * ``linux_spi`` (for SPI flash ROMs accessible via /dev/spidevX.Y on Linux)
+ * ``usbblaster_spi`` (for SPI flash ROMs attached to an Altera USB-Blaster compatible cable)
+ * ``nicintel_eeprom`` (for SPI EEPROMs on Intel Gigabit network cards)
+ * ``mstarddc_spi`` (for SPI flash ROMs accessible through DDC in MSTAR-equipped displays)
+ * ``pickit2_spi`` (for SPI flash ROMs accessible via Microchip PICkit2)
+ * ``ch341a_spi`` (for SPI flash ROMs attached to WCH CH341A)
+ * ``ch347_api`` (for SPI flash ROMs attached to WHC CH347)
+ * ``digilent_spi`` (for SPI flash ROMs attached to iCEblink40 development boards)
+ * ``jlink_spi`` (for SPI flash ROMs attached to SEGGER J-Link and compatible devices)
+ * ``ni845x_spi`` (for SPI flash ROMs attached to National Instruments USB-8451 or USB-8452)
+ * ``stlinkv3_spi`` (for SPI flash ROMs attached to STMicroelectronics STLINK V3 devices)
+ * ``realtek_mst_i2c_spi`` (for SPI flash ROMs attached to Realtek DisplayPort hubs accessible through I2C)
+ * ``parade_lspcon`` (for SPI flash ROMs attached to Parade Technologies LSPCONs (PS175))
+ * ``mediatek_i2c_spi`` (for SPI flash ROMs attached to some Mediatek display devices accessible over I2C)
+ * ``dirtyjtag_spi`` (for SPI flash ROMs attached to DirtyJTAG-compatible devices)
+ * ``asm106x`` (for SPI flash ROMs attached to asm106x PCI SATA controllers)
+
+ Some programmers have optional or mandatory parameters which are described in detail in the
+ **PROGRAMMER-SPECIFIC INFORMATION** section. Support for some programmers can be disabled at compile time.
+ ``flashrom -h`` lists all supported programmers.
+
+
+**-h, --help**
+ Show a help text and exit.
+
+
+**-o, --output <logfile>**
+ Save the full debug log to **<logfile>**.
+ If the file already exists, it will be overwritten. This is the recommended way to gather logs from **flashrom**
+ because they will be verbose even if the on-screen messages are not verbose and don't require output redirection.
+
+
+**--progress**
+ [Experimental feature] Show progress percentage of operations on the standard output.
+
+
+**-R, --version**
+ Show version information and exit.
+
+
+PROGRAMMER-SPECIFIC INFORMATION
+-------------------------------
+Some programmer drivers accept further parameters to set programmer-specific parameters. These parameters are separated
+from the programmer name by a colon. While some programmers take arguments atfixed positions, other programmers use a
+key/value interface in which the key and value is separated by an equal sign and different pairs are separated by a
+comma or a colon.
+
+
+internal programmer
+^^^^^^^^^^^^^^^^^^^
+
+
+**Board Enables**
+ Some mainboards require to run mainboard specific code to enable flash erase and write support
+ (and probe support on old systems with parallel flash).
+ The mainboard brand and model (if it requires specific code) is usually autodetected using one of the following mechanisms:
+ If your system is running coreboot, the mainboard type is determined from the coreboot table.
+ Otherwise, the mainboard is detected by examining the onboard PCI devices and possibly DMI info.
+ If PCI and DMI do not contain information to uniquely identify the mainboard (which is the exception),
+ or if you want to override the detected mainboard model, you can specify the mainboard using the::
+
+ flashrom -p internal:mainboard=<vendor>:<board>
+
+ syntax.
+
+ See the **Known boards** or **Known laptops** section in the output of ``flashrom -L`` for a list of boards
+ which require the specification of the board name, if no coreboot table is found.
+
+ Some of these board-specific flash enabling functions (called **board enables** ) in **flashrom** have not yet been tested.
+ If your mainboard is detected needing an untested board enable function, a warning message is printed and the board enableis not executed,
+ because a wrong board enable function might cause the system to behave erratically, as board enable functions touch the
+ low-level internals of a mainboard.
+ Not executing a board enable function (if one is needed) might cause detection or erasing failure.
+ If your board protects only part of the flash (commonly the top end, called boot block),
+ **flashrom** might encounter an error only after erasing the unprotected part, so running without the board-enable function
+ might be dangerous for erase and write (which includes erase).
+
+ The suggested procedure for a mainboard with untested board specific code is to first try to probe the ROM
+ (just invoke **flashrom** and check that it detects your flash chip type) without running the board enable code
+ (i.e. without any parameters). If it finds your chip, fine. Otherwise, retry probing your chip with the board-enable code running, using::
+
+ flashrom -p internal:boardenable=force
+
+ If your chip is still not detected, the board enable code seems to be broken or the flash chip unsupported.
+ Otherwise, make a backup of your current ROM contents (using ``-r``) and store it to a medium outside of your computer,
+ like a USB drive or a network share. If you needed to run the board enable code already for probing, use it for reading too.
+ If reading succeeds and the contents of the read file look legit you can try to write the new image.
+ You should enable the board enable code in any case now, as it has been written because it is known that writing/erasing
+ without the board enable is going to fail. In any case (success or failure), please report to the **flashrom** mailing list, see below.
+
+**Coreboot**
+ On systems running coreboot, **flashrom** checks whether the desired image matches your mainboard.
+ This needs some special board ID to be present in the image.
+ If **flashrom** detects that the image you want to write and the current board do not match,
+ it will refuse to write the image unless you specify::
+
+ flashrom -p internal:boardmismatch=force
+
+
+**ITE IT87 Super I/O**
+ If your mainboard is manufactured by GIGABYTE and supports DualBIOS it is very likely that it uses an
+ ITE IT87 series Super I/O to switch between the two flash chips.
+ Only one of them can be accessed at a time and you can manually select which one to use with the::
+
+ flashrom -p internal:dualbiosindex=chip
+
+ syntax where ``chip`` is the index of the chip to use (0 = main, 1 = backup).
+ You can check which one is currently selected by leaving out the ``chip`` parameter.
+
+ If your mainboard uses an ITE IT87 series Super I/O for LPC<->SPI flash bus translation, **flashrom** should autodetect that configuration.
+ If you want to set the I/O base port of the IT87 series SPI controller manually instead of using the value provided by the BIOS,
+ use the::
+
+ flashrom -p internal:it87spiport=portnum
+
+ syntax where ``portnum`` is the I/O port number (must be a multiple of 8).
+ In the unlikely case **flashrom** doesn't detect an active IT87 LPC<->SPI bridge, please send a bug report so we can diagnose the problem.
+
+
+**AMD chipsets**
+ Beginning with the SB700 chipset there is an integrated microcontroller (IMC) based on the 8051 embedded in every AMD southbridge.
+ Its firmware resides in the same flash chip as the host's which makes writing to the flash risky if the IMC is active.
+ Flashrom tries to temporarily disable the IMC but even then changing the contents of the flash can have unwanted effects:
+ when the IMC continues (at the latest after a reboot) it will continue executing code from the flash.
+ If the code was removed or changed in an unfortunate way it is unpredictable what the IMC will do.
+ Therefore, if **flashrom** detects an active IMC it will disable write support unless the user forces it with the::
+
+ flashrom -p internal:amd_imc_force=yes
+
+ syntax. The user is responsible for supplying a suitable image or leaving out the IMC region with the help of a layout file.
+ This limitation might be removed in the future when we understand the details better and have received enough feedback from users.
+ Please report the outcome if you had to use this option to write a chip.
+
+ An optional ``spispeed`` parameter specifies the frequency of the SPI bus where applicable
+ (i.e.SB600 or later with an SPI flash chip directly attached to the chipset).
+ Syntax is::
+
+ flashrom -p internal:spispeed=frequency
+
+ where ``frequency`` can be ``'16.5 MHz'``, ``'22 MHz'``, ``'33 MHz'``, ``'66 MHz'``, ``'100 MHZ'``, or ``'800 kHz'``.
+ Support of individual frequencies depends on the generation of the chipset:
+
+ * SB6xx, SB7xx, SP5xxx: from 16.5 MHz up to and including 33 MHz.
+ The default is to use 16.5 MHz and disable Fast Reads.
+ * SB8xx, SB9xx, Hudson: from 16.5 MHz up to and including 66 MHz.
+ The default is to use 16.5 MHz and disable Fast Reads.
+ * Yangtze (with SPI 100 engine as found in Kabini and Tamesh): all of them.
+ The default is to use the frequency that is currently configured.
+
+ An optional ``spireadmode`` parameter specifies the read mode of the SPI bus where applicable (Bolton or later).
+ Syntax is::
+
+ flashrom -p internal:spireadmode=mode
+
+ where ``mode`` can be ``'Normal (up to 33 MHz)'``, ``'Normal (up to 66 MHz)'``, ``'Dual IO (1-1-2)'``, ``'Quad IO (1-1-4)'``,
+ ``'Dual IO (1-2-2)'``, ``'Quad IO (1-4-4)'``, or ``'Fast Read'``.
+
+ The default is to use the read mode that is currently configured.
+
+
+**Intel chipsets**
+ If you have an Intel chipset with an ICH8 or later southbridge with SPI flash attached, and if a valid descriptor was written
+ to it (e.g. by the vendor), the chipset provides an alternative way to access the flash chip(s) named **Hardware Sequencing**.
+ It is much simpler than the normal access method (called **Software Sequencing**), but does not allow the software to
+ choose the SPI commands to be sent. You can use the::
+
+ flashrom -p internal:ich_spi_mode=value
+
+ syntax where ``value`` can be ``auto``, ``swseq`` or ``hwseq``. By default (or when setting ``ich_spi_mode=auto``) the
+ module tries to use swseq and only activates hwseq if need be (e.g. if important opcodes are inaccessible due to lockdown;
+ or if more than one flash chip is attached). The other options (swseq, hwseq) select the respective mode (if possible).
+
+ ICH8 and later southbridges may also have locked address ranges of different kinds if a valid descriptor was written to it.
+ The flash address space is then partitioned in multiple so called "Flash Regions" containing the host firmware,
+ the ME firmware and so on respectively. The flash descriptor can also specify up to 5 so called **Protected Regions**,
+ which are freely chosen address ranges independent from the aforementioned **Flash Regions**.
+ All of them can be write and/or read protected individually.
+
+ If you have an Intel chipset with an ICH2 or later southbridge and if you want to set specific IDSEL values for a
+ non-default flash chip or an embedded controller (EC), you can use the::
+
+ flashrom -p internal:fwh_idsel=value
+
+ syntax where ``value`` is the 48-bit hexadecimal raw value to be written in the IDSEL registers of the Intel southbridge.
+ The upper 32 bits use one hex digit each per 512 kB range between 0xffc00000 and 0xffffffff, and the lower 16 bits
+ use one hex digit each per 1024 kB range between 0xff400000 and 0xff7fffff.
+ The rightmost hex digit corresponds with the lowest address range. All address ranges have a corresponding sister range
+ 4 MB below with identical IDSEL settings. The default value for ICH7 is given in the example below.
+
+ Example::
+
+ flashrom -p internal:fwh_idsel=0x001122334567
+
+
+**Laptops**
+ Using **flashrom** on older laptops that don't boot from the SPI bus is dangerous and may easily make your hardware unusable
+ (see also the **BUGS** section). The embedded controller (EC) in some machines may interact badly with flashing.
+ More information is `in the wiki <https://flashrom.org/Laptops>`_.
+ Problems occur when the flash chip is shared between BIOS and EC firmware, and the latter does not expect **flashrom**
+ to access the chip. While **flashrom** tries to change the contents of that memory the EC might need to fetch new
+ instructions or data from it and could stop working correctly. Probing for and reading from the chip may also irritate
+ your EC and cause fan failure, backlight failure, sudden poweroff, and other nasty effects. **flashrom** will attempt to
+ detect if it is running on such a laptop and limit probing to SPI buses. If you want to probe the LPC bus anyway at your own risk, use::
+
+ flashrom -p internal:laptop=force_I_want_a_brick
+
+ We will not help you if you force flashing on a laptop because this is a really dumb idea.
+
+ You have been warned.
+
+ Currently we rely on the chassis type encoded in the DMI/SMBIOS data to detect laptops. Some vendors did not implement
+ those bits correctly or set them to generic and/or dummy values. **flashrom** will then issue a warning and restrict buses like above.
+ In this case you can use::
+
+ flashrom -p internal:laptop=this_is_not_a_laptop
+
+ to tell **flashrom** (at your own risk) that it is not running on a laptop.
+
+
+dummy programmer
+^^^^^^^^^^^^^^^^
+
+The dummy programmer operates on a buffer in memory only. It provides a safe and fast way to test various aspects of
+**flashrom** and is mainly used in development and while debugging.
+It is able to emulate some chips to a certain degree (basic identify/read/erase/write operations work).
+
+An optional parameter specifies the bus types it should support. For that you have to use the::
+
+ flashrom -p dummy:bus=[type[+type[+type]]]
+
+syntax where ``type`` can be ``parallel``, ``lpc``, ``fwh``, ``spi`` in any order. If you specify bus without type,
+all buses will be disabled. If you do not specify bus, all buses will be enabled.
+
+Example::
+
+ flashrom -p dummy:bus=lpc+fwh
+
+The dummy programmer supports flash chip emulation for automated self-tests without hardware access.
+If you want to emulate a flash chip, use the::
+
+ flashrom -p dummy:emulate=chip
+
+syntax where ``chip`` is one of the following chips (please specify only the chip name, not the vendor):
+
+* ST ``M25P10.RES`` SPI flash chip (128 kB, RES, page write)
+* SST ``SST25VF040.REMS`` SPI flash chip (512 kB, REMS, byte write)
+* SST ``SST25VF032B`` SPI flash chip (4096 kB, RDID, AAI write)
+* Macronix ``MX25L6436`` SPI flash chip (8192 kB, RDID, SFDP)
+* Winbond ``W25Q128FV`` SPI flash chip (16384 kB, RDID)
+* Spansion ``S25FL128L`` SPI flash chip (16384 kB, RDID)
+* Dummy vendor ``VARIABLE_SIZE`` SPI flash chip (configurable size, page write)
+
+Example::
+
+ flashrom -p dummy:emulate=SST25VF040.REMS
+
+To use ``VARIABLE_SIZE`` chip, ``size`` must be specified to configure the size of the flash chip as a power of two.
+
+Example::
+
+ flashrom -p dummy:emulate=VARIABLE_SIZE,size=16777216,image=dummy.bin
+
+
+**Persistent images**
+ If you use flash chip emulation, flash image persistence is available as well by using the::
+
+ flashrom -p dummy:emulate=chip,image=image.rom
+
+ syntax where ``image.rom`` is the file where the simulated chip contents are read on **flashrom** startup and where the
+ chip contents on **flashrom** shutdown are written to.
+
+ Example::
+
+ flashrom -p dummy:emulate=M25P10.RES,image=dummy.bin
+
+
+**SPI write chunk size**
+ If you use SPI flash chip emulation for a chip which supports SPI page write with the default opcode,
+ you can set the maximum allowed write chunk size with the::
+
+ flashrom -p dummy:emulate=chip,spi_write_256_chunksize=size
+
+ syntax where ``size`` is the number of bytes (min.\& 1, max.\& 256).
+ Example::
+
+ flashrom -p dummy:emulate=M25P10.RES,spi_write_256_chunksize=5
+
+
+**SPI blacklist**
+ To simulate a programmer which refuses to send certain SPI commands to the flash chip, you can specify a blacklist of
+ SPI commands with the::
+
+ flashrom -p dummy:spi_blacklist=commandlist
+
+ syntax where ``ommandlist`` is a list of two-digit hexadecimal representations of SPI commands.
+ If commandlist is e.g. 0302, **flashrom** will behave as if the SPI controller refuses to run command 0x03 (READ) and command 0x02 (WRITE).
+ commandlist may be up to 512 characters (256 commands) long.
+ Implementation note: **flashrom** will detect an error during command execution.
+
+
+**SPI ignorelist**
+ To simulate a flash chip which ignores (doesn't support) certain SPI commands, you can specify an ignorelist of SPI commands with the::
+
+ flashrom -p dummy:spi_ignorelist=commandlist
+
+ syntax where ``commandlist`` is a list of two-digit hexadecimal representations of SPI commands.
+ If commandlist is e.g. 0302, the emulated flash chip will ignore command 0x03 (READ) and command 0x02 (WRITE).
+ ``commandlist`` may be up to 512 characters (256 commands) long.
+ Implementation note: **flashrom** won't detect an error during command execution.
+
+
+**SPI status register**
+ You can specify the initial content of the chip's status register with the::
+
+ flashrom -p dummy:spi_status=content"
+
+ syntax where ``content`` is a hexadecimal value of up to 24 bits. For example, ``0x332211`` assigns 0x11 to SR1,
+ 0x22 to SR2 and 0x33 to SR3. Shorter value is padded to 24 bits with zeroes on the left.
+ See datasheet for chosen chip for details about the registers content.
+
+
+**Write protection**
+ Chips with emulated WP: **W25Q128FV**, **S25FL128L**.
+
+ You can simulate state of hardware protection pin (WP) with the::
+
+ flashrom -p dummy:hwwp=state
+
+ syntax where ``state`` is ``yes`` or ``no`` (default value). ``yes`` means active state of the pin implies that chip is
+ write-protected (on real hardware the pin is usually negated, but not here).
+
+
+nic3com, nicrealtek, nicnatsemi, nicintel, nicintel_eeprom, nicintel_spi, gfxnvidia, ogp_spi, drkaiser, satasii, satamv, atahpt, atavia, atapromise, it8212 programmers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+These programmers have an option to specify the PCI address of the card your want to use, which must be specified if
+more than one card supported by the selected programmer is installed in your system. The syntax is::
+
+ flashrom -p xxxx:pci=bb:dd.f
+
+where ``xxxx`` is the name of the programmer, ``bb`` is the PCI bus number, ``dd`` is the PCI device number, and ``b``
+is the PCI function number of the desired device. Example::
+
+ flashrom -p nic3com:pci=05:04.0
+
+
+atavia programmer
+^^^^^^^^^^^^^^^^^
+
+Due to the mysterious address handling of the VIA VT6421A controller the user can specify an offset with the::
+
+ flashrom -p atavia:offset=addr
+
+syntax where ``addr`` will be interpreted as usual (leading 0x (0) for hexadecimal (octal) values, or else decimal).
+For more information please see `its wiki page <https://flashrom.org/VT6421A "its wiki page>`_.
+
+
+atapromise programmer
+^^^^^^^^^^^^^^^^^^^^^
+
+This programmer is currently limited to 32 kB, regardless of the actual size of the flash chip. This stems from the
+fact that, on the tested device (a Promise Ultra100), not all of the chip's address lines were actually connected.
+You may use this programmer to flash firmware updates, since these are only 16 kB in size (padding to 32 kB is required).
+
+
+nicintel_eeprom programmer
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This is the first programmer module in **flashrom** that does not provide access to NOR flash chips but EEPROMs mounted on
+gigabit Ethernet cards based on Intel's 82580 NIC. Because EEPROMs normally do not announce their size nor allow
+themselves to be identified, the controller relies on correct size values written to predefined addresses within the chip.
+**Flashrom** follows this scheme but assumes the minimum size of 16 kB (128 kb) if an unprogrammed EEPROM/card is detected.
+Intel specifies following EEPROMs to be compatible:
+Atmel AT25128, AT25256, Micron (ST) M95128, M95256 and OnSemi (Catalyst) CAT25CS128.
+
+
+ft2232_spi programmer
+^^^^^^^^^^^^^^^^^^^^^
+
+This module supports various programmers based on FTDI FT2232/FT4232H/FT232H chips including the DLP Design DLP-USB1232H,
+openbiosprog-spi, Amontec JTAGkey/JTAGkey-tiny/JTAGkey-2, Dangerous Prototypes Bus Blaster, Olimex ARM-USB-TINY/-H,
+Olimex ARM-USB-OCD/-H, OpenMoko Neo1973 Debug board (V2+), TIAO/DIYGADGET USB Multi-Protocol Adapter (TUMPA), TUMPA Lite,
+GOEPEL PicoTAP, Google Servo v1/v2, Tin Can Tools Flyswatter/Flyswatter 2 and Kristech KT-LINK.
+
+An optional parameter specifies the controller type, channel/interface/port it should support. For that you have to use the::
+
+ flashrom \-p ft2232_spi:type=model,port=interface
+
+syntax where ``model`` can be ``2232H``, ``4232H``, ``232H``, ``jtagkey``, ``busblaster``, ``openmoko``, ``arm-usb-tiny``,
+``arm-usb-tiny-h``, ``arm-usb-ocd``, ``arm-usb-ocd-h``, ``tumpa``, ``tumpalite``, ``picotap``, ``google-servo,
+``google-servo-v2``, ``google-servo-v2-legacy`` or ``kt-link``.
+``interface`` can be ``A``, ``B``, ``C``, or ``D``. The default model is ``4232H``, the default interface is ``A`` and
+GPIO is not used by default.
+
+If there is more than one ft2232_spi-compatible device connected, you can select which one should be used by specifying
+its serial number with the::
+
+ flashrom -p ft2232_spi:serial=number
+
+syntax where ``number`` is the serial number of the device (which can be found for example in the output of lsusb -v).
+
+All models supported by the **ft2232_spi** driver can configure the SPI clock rate by setting a divisor. The expressible
+divisors are all **even** numbers between 2 and 2^17 (=131072) resulting in SPI clock frequencies of 6 MHz down to about
+92 Hz for 12 MHz inputs (non-H chips) and 30 MHz down to about 458 Hz for 60 MHz inputs ('H' chips). The default divisor
+is set to 2, but you can use another one by specifying the optional ``divisor`` parameter with the::
+
+ flashrom -p ft2232_spi:divisor=div
+
+syntax. Using the parameter ``csgpiol`` (DEPRECATED - use ``gpiol`` instead) an additional CS# pin can be chosen,
+where the value can be a number between 0 and 3, denoting GPIOL0-GPIOL3 correspondingly. Example::
+
+ flashrom -p ft2232_spi:csgpiol=3
+
+The parameter ``gpiolX=[HLC]`` allows use of the GPIOL pins either as generic gpios with a fixed value during flashing
+or as additional CS# signal, where ``X`` can be a number between 0 and 3, denoting GPIOL0-GPIOL3 correspondingly.
+The parameter may be specified multiple times, one time per GPIOL pin. Valid values are ``H``, ``L`` and ``C``:
+
+* ``H`` - Set GPIOL output high
+* ``L`` - Set GPIOL output low
+* ``C`` - Use GPIOL as additional CS# output
+
+Example::
+
+ flashrom -p ft2232_spi:gpiol0=H
+
+**Note** that not all GPIOL pins are freely usable with all programmers as some have special functionality.
+
+
+serprog programmer
+^^^^^^^^^^^^^^^^^^
+
+This module supports all programmers speaking the serprog protocol. This includes some Arduino-based devices as well as
+various programmers by Urja Rannikko, Juhana Helovuo, Stefan Tauner, Chi Zhang and many others.
+
+A mandatory parameter specifies either a serial device (and baud rate) or an IP/port combination for communicating with
+the programmer. The device/baud combination has to start with ``dev=`` and separate the optional baud rate with a colon.
+For example::
+
+ flashrom -p serprog:dev=/dev/ttyS0:115200
+
+If no baud rate is given the default values by the operating system/hardware will be used.
+For IP connections you have to use the::
+
+ flashrom -p serprog:ip=ipaddr:port
+
+syntax. In case the device supports it, you can set the SPI clock frequency with the optional ``spispeed`` parameter.
+The frequency is parsed as hertz, unless an ``M``, or ``k`` suffix is given, then megahertz or kilohertz are used respectively.
+Example that sets the frequency to 2 MHz::
+
+ flashrom -p serprog:dev=/dev/device:baud,spispeed=2M
+
+More information about serprog is available in **serprog-protocol.txt** in the source distribution.
+
+
+buspirate_spi programmer
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+A required ``dev`` parameter specifies the Bus Pirate device node and an optional ``spispeed`` parameter specifies the
+frequency of the SPI bus. The parameter delimiter is a comma. Syntax is::
+
+ flashrom -p buspirate_spi:dev=/dev/device,spispeed=frequency
+
+where ``frequency`` can be ``30k``, ``125k``, ``250k``, ``1M``, ``2M``, ``2.6M``, ``4M`` or ``8M`` (in Hz).
+The default is the maximum frequency of 8 MHz.
+
+The baud rate for communication between the host and the Bus Pirate can be specified with the optional ``serialspeed``
+parameter. Syntax is::
+
+ flashrom -p buspirate_spi:serialspeed=baud
+
+where ``baud`` can be ``115200``, ``230400``, ``250000`` or ``2000000`` (``2M``).
+The default is ``2M`` baud for Bus Pirate hardware version 3.0 and greater, and 115200 otherwise.
+
+An optional pullups parameter specifies the use of the Bus Pirate internal pull-up resistors. This may be needed if you
+are working with a flash ROM chip that you have physically removed from the board. Syntax is::
+
+ flashrom -p buspirate_spi:pullups=state
+
+where ``state`` can be ``on`` or ``off``.
+More information about the Bus Pirate pull-up resistors and their purpose is available
+`in a guide by dangerousprototypes <http://dangerousprototypes.com/docs/Practical_guide_to_Bus_Pirate_pull-up_resistors>`_.
+
+The state of the Bus Pirate power supply pins is controllable through an optional ``psus`` parameter. Syntax is::
+
+ flashrom -p buspirate_spi:psus=state
+
+where ``state`` can be ``on`` or ``off``.
+This allows the bus pirate to power the ROM chip directly. This may also be used to provide the required pullup voltage
+(when using the **pullups** option), by connecting the Bus Pirate's Vpu input to the appropriate Vcc pin.
+
+An optional aux parameter specifies the state of the Bus Pirate auxiliary pin.
+This may be used to drive the auxiliary pin high or low before a transfer.
+Syntax is::
+
+ flashrom -p buspirate_spi:aux=state
+
+where ``state`` can be ``high`` or ``low``. The default ``state`` is ``high``.
+
+
+pickit2_spi programmer
+^^^^^^^^^^^^^^^^^^^^^^
+
+An optional ``voltage`` parameter specifies the voltage the PICkit2 should use. The default unit is Volt if no unit is specified.
+You can use ``mV``, ``millivolt``, ``V`` or ``Volt`` as unit specifier. Syntax is::
+
+ flashrom \-p pickit2_spi:voltage=value
+
+where ``value`` can be ``0V``, ``1.8V``, ``2.5V``, ``3.5V`` or the equivalent in mV.
+
+An optional ``spispeed`` parameter specifies the frequency of the SPI bus. Syntax is::
+
+ flashrom -p pickit2_spi:spispeed=frequency
+
+where ``frequency`` can be ``250k``, ``333k``, ``500k`` or ``1M`` (in Hz). The default is a frequency of 1 MHz.
+
+
+dediprog programmer
+^^^^^^^^^^^^^^^^^^^
+
+An optional ``voltage`` parameter specifies the voltage the Dediprog should use. The default unit is Volt if no unit is specified.
+You can use ``mV``, ``milliVolt``, ``V`` or ``Volt`` as unit specifier. Syntax is::
+
+ flashrom -p dediprog:voltage=value
+
+where ``value`` can be ``0V``, ``1.8V``, ``2.5V``, ``3.5V`` or the equivalent in mV.
+
+An optional ``device`` parameter specifies which of multiple connected Dediprog devices should be used.
+Please be aware that the order depends on libusb's usb_get_busses() function and that the numbering starts at 0.
+Usage example to select the second device::
+
+ flashrom -p dediprog:device=1
+
+An optional ``spispeed`` parameter specifies the frequency of the SPI bus. The firmware on the device needs to be 5.0.0 or newer.
+Syntax is::
+
+ flashrom -p dediprog:spispeed=frequency
+
+where ``frequency`` can be ``375k``, ``750k``, ``1.5M``, ``2.18M``, ``3M``, ``8M``, ``12M`` or ``24M`` (in Hz).
+The default is a frequency of 12 MHz.
+
+An optional ``target`` parameter specifies which target chip should be used. Syntax is::
+
+ flashrom -p dediprog:target=value
+
+where ``value`` can be ``1`` or ``2`` to select target chip 1 or 2 respectively. The default is target chip 1.
+
+
+rayer_spi programmer
+^^^^^^^^^^^^^^^^^^^^
+
+The default I/O base address used for the parallel port is 0x378 and you can use the optional ``iobase`` parameter to
+specify an alternate base I/O address with the::
+
+ flashrom -p rayer_spi:iobase=baseaddr
+
+syntax where ``baseaddr`` is base I/O port address of the parallel port, which must be a multiple of four.
+Make sure to not forget the "0x" prefix for hexadecimal port addresses.
+
+The default cable type is the RayeR cable. You can use the optional ``type`` parameter to specify the cable type with the::
+
+ flashrom -p rayer_spi:type=model
+
+syntax where ``model`` can be ``rayer`` for the RayeR cable, ``byteblastermv`` for the Altera ByteBlasterMV,
+``stk200`` for the Atmel, ``STK200/300``, ``wiggler`` for the Macraigor Wiggler, ``xilinx`` for the Xilinx Parallel Cable III (DLC 5),
+or ``spi_tt`` for SPI Tiny Tools-compatible hardware.
+
+More information about the RayeR hardware is available at `RayeR's website <http://rayer.g6.cz/elektro/spipgm.htm>`_.
+The Altera ByteBlasterMV datasheet can be obtained from `Altera <http://www.altera.co.jp/literature/ds/dsbytemv.pdf>`_.
+For more information about the Macraigor Wiggler see `their company homepage <http://www.macraigor.com/wiggler.htm>`_.
+The schematic of the Xilinx DLC 5 was published in `a Xilinx guide <http://www.xilinx.com/support/documentation/user_guides/xtp029.pdf>`_.
+
+
+raiden_debug_spi programmer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The target of the SPI flashing mux must be specified with the ``target`` parameter with the::
+
+ flashrom -p raiden_debug_spi:target=chip
+
+syntax, where ``chip`` is either the ``ap`` or ``ec`` to flash, otherwise a unspecified target terminates at the end-point.
+
+The default is to use the first available servo. You can use the optional ``serial`` parameter to specify the servo
+USB device serial number to use specifically with::
+
+ flashrom -p raiden_debug_spi:serial=XXX
+
+The servo device serial number can be found via ``lsusb``.
+Raiden will poll the ``ap`` target waiting for the system power to settle on the AP and EC flash devices.
+
+The optional ``custom_rst=true`` parameter changes the timeout value from 3ms to 10ms::
+
+ flashrom -p raiden_debug_spi:custom_rst=<true|false>
+
+syntax, where ``custom_rst=false`` is the implicit default timeout of 3ms. More information about the ChromiumOS servo
+hardware is available at `servos website <https://chromium.googlesource.com/chromiumos/third_party/hdctools/+/HEAD/docs/servo_v4.md>`_.
+
+
+pony_spi programmer
+^^^^^^^^^^^^^^^^^^^
+
+The serial port (like /dev/ttyS0, /dev/ttyUSB0 on Linux or COM3 on windows) is specified using the mandatory ``dev``
+parameter. The adapter type is selectable between SI-Prog (used for SPI devices with PonyProg 2000) or a custom made
+serial bitbanging programmer named "serbang". The optional ``type`` parameter accepts the values ``si_prog`` (default)
+or ``serbang``.
+
+Information about the SI-Prog adapter can be found at `its website <http://www.lancos.com/siprogsch.html>`_.
+
+An example call to **flashrom** is::
+
+ flashrom -p pony_spi:dev=/dev/ttyS0,type=serbang
+
+Please note that while USB-to-serial adapters work under certain circumstances, this slows down operation considerably.
+
+
+ogp_spi programmer
+^^^^^^^^^^^^^^^^^^
+
+The flash ROM chip to access must be specified with the ``rom`` parameter::
+
+ flashrom -p ogp_spi:rom=name
+
+Where ``name`` is either ``cprom`` or ``s3`` for the configuration ROM and ``bprom`` or ``bios`` for the BIOS ROM.
+If more than one card supported by the **ogp_spi** programmer is installed in your system, you have to specify the PCI
+address of the card you want to use with the ``pci=`` parameter as explained in the **nic3com** et al. section above.
+
+
+linux_mtd programmer
+^^^^^^^^^^^^^^^^^^^^
+
+You may specify the MTD device to use with the::
+
+ flashrom -p linux_mtd:dev=/dev/mtdX
+
+syntax where ``/dev/mtdX`` is the Linux device node for your MTD device. If left unspecified the first MTD device found
+(e.g. /dev/mtd0) will be used by default.
+
+Please note that the linux_mtd driver only works on Linux.
+
+
+linux_spi programmer
+^^^^^^^^^^^^^^^^^^^^
+
+You have to specify the SPI controller to use with the::
+
+ flashrom -p linux_spi:dev=/dev/spidevX.Y
+
+syntax where ``/dev/spidevX.Y`` is the Linux device node for your SPI controller.
+
+In case the device supports it, you can set the SPI clock frequency with the optional ``spispeed`` parameter.
+The frequency is parsed as kilohertz. Example that sets the frequency to 8 MHz::
+
+ flashrom -p linux_spi:dev=/dev/spidevX.Y,spispeed=8000
+
+Please note that the linux_spi driver only works on Linux.
+
+
+mstarddc_spi programmer
+^^^^^^^^^^^^^^^^^^^^^^^
+
+The Display Data Channel (DDC) is an I2C bus present on VGA and DVI connectors, that allows exchanging information
+between a computer and attached displays. Its most common uses are getting display capabilities through EDID
+(at I2C address 0x50) and sending commands to the display using the DDC/CI protocol (at address 0x37).
+On displays driven by MSTAR SoCs, it is also possible to access the SoC firmware flash (connected to the Soc through another SPI bus)
+using an In-System Programming (ISP) port, usually at address 0x49. This **flashrom** module allows the latter via Linux's I2C driver.
+
+**IMPORTANT:**
+Before using this programmer, the display **MUST** be in standby mode, and only connected to the computer that will run
+**flashrom** using a VGA cable, to an inactive VGA output. It absolutely **MUST NOT** be used as a display during the procedure!
+
+You have to specify the DDC/I2C controller and I2C address to use with the::
+
+ flashrom -p mstarddc_spi:dev=/dev/i2c-X:YY
+
+syntax where ``/dev/i2c-X`` is the Linux device node for your I2C controller connected to the display's DDC channel, and
+``YY`` is the (hexadecimal) address of the MSTAR ISP port (address 0x49 is usually used).
+Example that uses I2C controller /dev/i2c-1 and address 0x49::
+
+ flashrom -p mstarddc_spi:dev=/dev/i2c-1:49
+
+It is also possible to inhibit the reset command that is normally sent to the display once the **flashrom** operation is
+completed using the optional ``noreset`` parameter. A value of 1 prevents **flashrom** from sending the reset command.
+Example that does not reset the display at the end of the operation::
+
+ flashrom -p mstarddc_spi:dev=/dev/i2c-1:49,noreset=1
+
+Please note that sending the reset command is also inhibited if an error occurred during the operation.
+To send the reset command afterwards, you can simply run **flashrom** once more, in chip probe mode (not specifying an operation),
+without the ``noreset`` parameter, once the flash read/write operation you intended to perform has completed successfully.
+
+Please also note that the mstarddc_spi driver only works on Linux.
+
+
+ch341a_spi programmer
+^^^^^^^^^^^^^^^^^^^^^
+
+The WCH CH341A programmer does not support any parameters currently. SPI frequency is fixed at 2 MHz, and CS0 is used
+as per the device.
+
+
+ch347_spi programmer
+^^^^^^^^^^^^^^^^^^^^
+
+The WCH CH347 programmer does not currently support any parameters. SPI frequency is fixed at 2 MHz, and CS0 is used
+as per the device.
+
+ni845x_spi programmer
+^^^^^^^^^^^^^^^^^^^^^
+
+An optional ``voltage`` parameter could be used to specify the IO voltage. This parameter is available for the NI USB-8452 device.
+The default unit is Volt if no unit is specified. You can use ``mV``, ``milliVolt``, ``V`` or ``Volt`` as unit specifier.
+Syntax is::
+
+ flashrom -p ni845x_spi:voltage=value
+
+where ``value`` can be ``1.2V``, ``1.5V``, ``1.8V``, ``2.5V``, ``3.3V`` or the equivalent in mV.
+
+In the case if none of the programmer's supported IO voltage is within the supported voltage range of the detected flash
+chip the **flashrom** will abort the operation (to prevent damaging the flash chip).
+You can override this behaviour by passing ``yes`` to the ``ignore_io_voltage_limits`` parameter
+(for e.g. if you are using an external voltage translator circuit). Syntax is::
+
+ flashrom -p ni845x_spi:ignore_io_voltage_limits=yes
+
+You can use the ``serial`` parameter to explicitly specify which connected NI USB-845x device should be used. You should
+use your device's 7 digit hexadecimal serial number. Usage example to select the device with 1230A12 serial number::
+
+ flashrom -p ni845x_spi:serial=1230A12
+
+An optional ``spispeed`` parameter specifies the frequency of the SPI bus. Syntax is::
+
+ flashrom -p ni845x_spi:spispeed=frequency
+
+where ``frequency`` should a number corresponding to the desired frequency in kHz.
+The maximum ``frequency`` is 12 MHz (12000 kHz) for the USB-8451 and 50 MHz (50000 kHz) for the USB-8452.
+The default is a frequency of 1 MHz (1000 kHz).
+
+An optional ``cs`` parameter specifies which target chip select line should be used. Syntax is::
+
+ flashrom -p ni845x_spi:csnumber=value
+
+where ``value`` should be between ``0`` and ``7``. By default the CS0 is used.
+
+
+digilent_spi programmer
+^^^^^^^^^^^^^^^^^^^^^^^
+
+An optional ``spispeed`` parameter specifies the frequency of the SPI bus. Syntax is::
+
+ flashrom -p digilent_spi:spispeed=frequency
+
+where ``frequency`` can be ``62.5k``, ``125k``, ``250k``, ``500k``, ``1M``, ``2M`` or ``4M`` (in Hz).
+The default is a frequency of 4 MHz.
+
+
+dirtyjtag_spi programmer
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+An optional ``freq`` parameter specifies the frequency of the SPI bus. Syntax is::
+
+ flashrom -p dirtyjtag_spi:spispeed=frequency
+
+where ``spispeed`` can be any value in hertz, kilohertz or megahertz supported by the programmer.
+The default is a frequency of 100 KHz.
+
+
+jlink_spi programmer
+^^^^^^^^^^^^^^^^^^^^
+
+This module supports SEGGER J-Link and compatible devices.
+
+The **MOSI** signal of the flash chip must be attached to **TDI** pin of the programmer, **MISO** to **TDO** and
+**SCK** to **TCK**. The chip select (**CS**) signal of the flash chip can be attached to different pins of the
+programmer which can be selected with the::
+
+ flashrom -p jlink_spi:cs=pin
+
+syntax where ``pin`` can be either ``TRST``, ``RESET`` or ``TMS``. The default pin for chip select is ``RESET``.
+Note that, when using ``RESET``, it is normal that the indicator LED blinks orange or red.
+
+Additionally, the ``Tref`` pin of the programmer must be attached to the logic level of the flash chip.
+The programmer measures the voltage on this pin and generates the reference
+voltage for its input comparators and adapts its output voltages to it.
+
+Pinout for devices with 20-pin JTAG connector::
+
+ +-------+
+ | 1 2 | 1: VTref 2:
+ | 3 4 | 3: TRST 4: GND
+ | 5 6 | 5: TDI 6: GND
+ +-+ 7 8 | 7: TMS 8: GND
+ | 9 10 | 9: TCK 10: GND
+ | 11 12 | 11: 12: GND
+ +-+ 13 14 | 13: TDO 14:
+ | 15 16 | 15: RESET 16:
+ | 17 18 | 17: 18:
+ | 19 20 | 19: PWR_5V 20:
+ +-------+
+
+If there is more than one compatible device connected, you can select which one should be used by specifying its serial
+number with the::
+
+ flashrom -p jlink_spi:serial=number
+
+syntax where ``number`` is the serial number of the device (which can be found for example in the output of ``lsusb -v``).
+
+The SPI speed can be selected by using the::
+
+ flashrom -p jlink_spi:spispeed=frequency
+
+syntax where ``frequency`` is the SPI clock frequency in kHz. The maximum speed depends on the device in use.
+
+The ``power=on`` option can be used to activate the 5 V power supply (PWR_5V) of the J-Link during a flash operation.
+
+
+stlinkv3_spi programmer
+^^^^^^^^^^^^^^^^^^^^^^^
+
+This module supports SPI flash programming through the STMicroelectronics STLINK V3 programmer/debugger's SPI bridge interface::
+
+ flashrom -p stlinkv3_spi
+
+If there is more than one compatible device connected, you can select which one should be used by specifying its
+serial number with the::
+
+ flashrom -p stlinkv3_spi:serial=number
+
+syntax where ``number`` is the serial number of the device (which can be found for example in the output of ``lsusb -v``).
+
+The SPI speed can be selected by using the::
+
+ flashrom -p stlinkv3_spi:spispeed=frequency
+
+syntax where ``frequency`` is the SPI clock frequency in kHz. If the passed frequency is not supported by the adapter
+the nearest lower supported frequency will be used.
+
+
+realtek_mst_i2c_spi, parade_lspcon and mediatek_i2c_spi programmers
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+These programmers tunnel SPI commands through I2C-connected devices. The I2C bus over which communication occurs must be
+specified either by device path with the ``devpath`` option::
+
+ flashrom -p realtek_mst_i2c_spi:devpath=/dev/i2c-8
+
+or by a bus number with the ``bus`` option, which implies a device path like ``/dev/i2c-N`` where ``N`` is the specified
+bus number::
+
+ flashrom -p parade_lspcon:bus=8
+
+
+realtek_mst_i2c_spi programmer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This programmer supports SPI flash programming for chips attached to Realtek DisplayPort MST hubs, themselves accessed
+through I2C (tunneling SPI flash commands through the MST hub's I2C connection with the host).
+
+
+In-system programming (ISP) mode
+""""""""""""""""""""""""""""""""
+
+The ``reset_mcu`` and ``enter_isp`` options provide control over device mode changes, where each can be set to ``0``
+or ``1`` to enable or disable the corresponding mode transition.
+
+``enter_isp`` defaults to ``1``, and if enabled will issue commands to the MST hub when beginning operation to put it
+into ISP mode.
+
+``reset_mcu`` defaults to ``0``, and if enabled will issue a reset command to the MST hub on programming completion,
+causing it to exit ISP mode and to reload its own firmware from flash.
+
+``allow_brick`` defaults to ``no``, however must be set explicitly to ``yes`` to allow the driver to run if you are sure
+you have a MST chip.
+
+The hub must be in ISP mode for SPI flash access to be possible, so it is usually only useful to disable ``enter_isp``
+if an earlier invocation avoided resetting it on completion. For instance, to erase the flash and rewrite it with the
+contents of a file without resetting in between (which could render it nonfunctional if attempting to load firmware
+from a blank flash)::
+
+ flashrom -p realtek_mst_i2c_spi:bus=0,enter_isp=1,reset_mcu=0 -E
+
+ flashrom -p realtek_mst_i2c_spi:bus=0,enter_isp=0,reset_mcu=1 -w new.bin
+
+
+parade_lspcon programmer
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+This programmer supports SPI flash programming for chips attached to Parade Technologies DisplayPort-to-HDMI level
+shifter/protocol converters (LSPCONs), e.g. the PS175. Communication to the SPI flash is tunneled through the LSPCON
+over I2C.
+
+
+mediatek_i2c_spi programmer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This programmer supports SPI flash programming for chips attached to some Mediatek display controllers, themselves
+accessed through I2C (tunneling SPI flash commands through an I2C connection with the host).
+
+The programmer is designed to support the TSUMOP82JUQ integrated display driver and scaler as used in the Google Meet
+Series One Desk 27 (which runs a version of ChromeOS and uses **flashrom** in its ``tsum-scaler-updater`` scripts that ship
+with the OS). Other chips may use compatible protocols but have not been tested with this programmer, and external chip
+IOs may need to be controlled through other non- **flashrom** means to configure the chip in order for it to operate as expected.
+
+``devpath`` and ``bus`` options select the I2C bus to use, as described previously. ``allow_brick`` defaults to ``no``,
+and must explicitly be set to ``yes`` in order for the programmer to operate. This is required because there is no
+mechanism in the driver to positively identify that a given I2C bus is actually connected to a supported device.
+
+
+EXAMPLES
+--------
+
+To back up and update your BIOS, run::
+
+ flashrom -p internal -r backup.rom -o backuplog.txt
+ flashrom -p internal -w newbios.rom -o writelog.txt
+
+Please make sure to copy backup.rom to some external media before you try to write. That makes offline recovery easier.
+
+If writing fails and **flashrom** complains about the chip being in an unknown state, you can try to restore the backup by running::
+
+ flashrom -p internal -w backup.rom -o restorelog.txt
+
+If you encounter any problems, please contact us and supply backuplog.txt, writelog.txt and restorelog.txt.
+See section **BUGS** for contact info.
+
+
+EXIT STATUS
+-----------
+
+**flashrom** exits with 0 on success, 1 on most failures but with 3 if a call to mmap() fails.
+
+
+REQUIREMENTS
+------------
+
+**flashrom** needs different access permissions for different programmers.
+
+* internal
+
+ * needs raw memory access
+ * PCI configuration space access
+ * raw I/O port access (x86)
+ * MSR access (x86)
+
+* atavia
+
+ * needs PCI configuration space access
+
+* nic3com, nicrealtek, nicnatsemi
+
+ * need PCI configuration space read access
+ * raw I/O port access
+
+* atahpt
+
+ * needs PCI configuration space access
+ * raw I/O port access
+
+* gfxnvidia, drkaiser, it8212
+
+ * need PCI configuration space access
+ * raw memory access
+
+* rayer_spi
+
+ * needs raw I/O port access
+
+* raiden_debug_spi
+
+ * needs access to the respective USB device via libusb API version 1.0
+
+* satasii, nicintel, nicintel_eeprom, nicintel_spi
+
+ * need PCI configuration space read access
+ * raw memory access
+
+* satamv, atapromise
+
+ * need PCI configuration space read access
+ * raw I/O port access
+ * raw memory access
+
+* serprog
+
+ * needs TCP access to the network or userspace access to a serial port
+
+* buspirate_spi
+
+ * needs userspace access to a serial port
+
+* ft2232_spi, usbblaster_spi, pickit2_spi
+
+ * need access to the respective USB device via libusb API version 1.0
+
+* ch341a_spi, dediprog
+
+ * need access to the respective USB device via libusb API version 1.0
+
+* dummy
+
+ * needs no access permissions at all
+
+* internal, nic3com, nicrealtek, nicnatsemi, gfxnvidia, drkaiser, satasii, satamv, atahpt, atavia, atapromise, asm106x
+
+ * have to be run as superuser/root
+ * need raw access permission
+
+* serprog, buspirate_spi, dediprog, usbblaster_spi, ft2232_spi, pickit2_spi, ch341a_spi, digilent_spi, dirtyjtag_spi
+
+ * can be run as normal user on most operating systems if appropriate device permissions are set
+
+* ogp
+
+ * needs PCI configuration space read access and raw memory access
+
+* realtek_mst_i2c_spi, parade_lspcon
+
+ * need userspace access to the selected I2C bus
+
+On OpenBSD, you can obtain raw access permission by setting::
+
+ securelevel=-1
+
+in **/etc/rc.securelevel** and rebooting, or rebooting into single user mode.
+
+
+BUGS
+----
+
+You can report bugs, ask us questions or send success reports via our communication channels listed here:
+`Contact <https://www.flashrom.org/Contact>`_
+
+Also, we provide a `pastebin service <https://paste.flashrom.org>`_ that is very useful to share logs without spamming
+the communication channels.
+
+
+Laptops
+-------
+
+Using **flashrom** on older laptops is dangerous and may easily make your hardware unusable. **flashrom** will attempt to detect
+if it is running on a susceptible laptop and restrict flash-chip probing for safety reasons. Please see the detailed
+discussion of this topic and associated **flashrom** options in the **Laptops** paragraph in the **internal programmer**
+subsection of the **PROGRAMMER-SPECIFIC INFORMATION** section and the information `in our wiki <https://flashrom.org/Laptops>`_.
+
+One-time programmable (OTP) memory and unique IDs
+
+Some flash chips contain OTP memory often denoted as **security registers**. They usually have a capacity in the range
+of some bytes to a few hundred bytes and can be used to give devices unique IDs etc. **flashrom** is not able to read
+or write these memories and may therefore not be able to duplicate a chip completely. For chip types known to include
+OTP memories a warning is printed when they are detected.
+
+Similar to OTP memories are unique, factory programmed, unforgeable IDs. They are not modifiable by the user at all.
+
+
+LICENSE
+-------
+
+**flashrom** is covered by the GNU General Public License (GPL), version 2. Some files are additionally available
+under any later version of the GPL.
+
+
+COPYRIGHT
+---------
+Please see the individual files.
+
+
+AUTHORS
+-------
+
+Andrew Morgan, Anastasia Klimchuk, Carl-Daniel Hailfinger, Claus Gindhart, David Borg, David Hendricks, Dominik Geyer,
+Edward O'Callaghan, Eric Biederman, Giampiero Giancipoli, Helge Wagner, Idwer Vollering, Joe Bao, Joerg Fischer,
+Joshua Roys, Kyösti Mälkki, Luc Verhaegen, Li-Ta Lo, Mark Marshall, Markus Boas, Mattias Mattsson, Michael Karcher,
+Nikolay Petukhov, Patrick Georgi, Peter Lemenkov, Peter Stuge, Reinder E.N. de Haan, Ronald G. Minnich, Ronald Hoogenboom,
+Sean Nelson, Stefan Reinauer, Stefan Tauner, Stefan Wildemann, Stephan Guilloux, Steven James, Urja Rannikko, Uwe Hermann,
+Wang Qingpei, Yinghai Lu and others, please see the **flashrom** git history for details.
+
+All still active authors can be reached via `the mailing list <flashrom\@flashrom.org>`_.
+
+This manual page was written by `Uwe Hermann <uwe\@hermann-uwe.de>`_, Carl-Daniel Hailfinger, Stefan Tauner and others.
+It is licensed under the terms of the GNU GPL (version 2 or later).
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 000000000..be9cc0174
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,49 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+import os
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+project = 'flashrom'
+# copyright = '2023, The flashrom authors'
+author = 'The flashrom authors'
+
+# -- General configuration ---------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
+
+master_doc = 'index' # this is needed for old versions
+
+extensions = [
+ 'sphinx.ext.todo'
+]
+
+#templates_path = ['_templates']
+exclude_patterns = []
+
+# -- Options for Todo extension ----------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/extensions/todo.html
+
+# If this is True, todo and todolist produce output, else they produce nothing. The default is False.
+todo_include_todos = False
+
+
+
+# -- Options for HTML output -------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
+
+html_theme = 'alabaster'
+#html_static_path = ['_static']
+
+html_favicon = 'logo/flashrom_icon_color-32x32.ico'
+
+
+# -- Options for manual page output --------------------------------------------
+man_make_section_directory = True
+man_show_urls = True
+man_pages = [
+ ('classic_cli_manpage', project, '', [], 8),
+]
diff --git a/doc/contact.rst b/doc/contact.rst
new file mode 100644
index 000000000..5bcac3fd0
--- /dev/null
+++ b/doc/contact.rst
@@ -0,0 +1,157 @@
+Contact
+========
+.. The extra = is needed to prevent git from throwing a `leftover conflict marker`
+ error when commiting.
+
+.. _mailing list:
+
+Mailing List
+------------
+Flashrom related mails are welcome on the flashrom mailing list at `flashrom@flashrom.org <mailto:flashrom@flashrom.org>`_.
+Please do NOT send any BIOS images or F segment dumps to the list!
+
+E-mails with binary files attached will be rejected. Images for things such as scope or logic analyzer traces are acceptable
+if hosted on a third-party photo sharing service that assigns a unique URL to the image, such as Google Photos.
+This prevents the photo URL from being abused for malicious or inappropriate content.
+
+Please note that the list is moderated for non-subscribers and we recommend to subscribe first.
+
+Subscription
+""""""""""""
+https://mail.coreboot.org/postorius/lists/flashrom.flashrom.org/
+
+Archives
+""""""""
+| https://mail.coreboot.org/hyperkitty/list/flashrom@flashrom.org/
+| https://mail.coreboot.org/pipermail/flashrom/ (Up to Dec. 2018)
+| https://marc.info/?l=flashrom
+| https://www.mail-archive.com/flashrom@flashrom.org/
+
+Moderation rules
+""""""""""""""""
+If your mail is too big (the current limit is 256 kB) or if you're not on the subscriber list, your mail will be held for moderation.
+If your mail contains any BIOS images or F segment dumps (instead of links which are fine), the mail will be rejected for legal reasons
+(we do not have the right to distribute BIOS images).
+
+Real time chats
+---------------
+
+Flashrom has real time channels where you have the chance to talk to people being involved or interested in the project.
+Most of the discussion is about flashrom development, contributions, tech talk and user help.
+
+You are welcome to join and discuss current and future flashrom development, ideas and contributions.
+
+If you have a problem and would like to get help, don't ask for help. Instead, just **explain** your problem right away,
+and make sure to **describe** the situation as much as possible, so that other people can understand you and provide meaningful answers.
+Otherwise, others have to ask or guess the details of your problem, which is frustrating for both parties.
+
+Should you need to paste lots of text (more than three lines), please use a `paste service <https://en.wikipedia.org/wiki/Pastebin>`_.
+For flashrom logs, feel free to use `paste.flashrom.org <https://paste.flashrom.org>`_.
+Other good paste services are `ix.io <http://ix.io/>`_, `paste.rs <https://paste.rs/>`_, `bpaste.net <https://bpaste.net/>`_,
+`gist.github.com <https://gist.github.com/>`_ and `dpaste.com <http://dpaste.com/>`_.
+
+Questions on `coreboot <https://coreboot.org>`_, `OpenBIOS <http://www.openbios.info/>`_, firmware and related topics are welcome in **#coreboot** on the same server.
+
+IRC
+"""
+
+You can join `#flashrom <irc://irc.libera.chat/#flashrom>`_
+channel on the `Libera.chat <https://www.libera.chat/>`_ `IRC <https://en.wikipedia.org/wiki/Internet_Relay_Chat>`_ network.
+If you don't have an IRC client, you can use the Libera.chat `webchat <https://web.libera.chat/#flashrom>`_.
+
+**#flashrom** channel is bridged to `Matrix <https://matrix.org/>`_.
+If you would like to join, you can use `this invite link <https://matrix.to/#/#flashrom:libera.chat>`_.
+
+Do note that IRC's nature has a significant effect on conversations. People from all over the world can join this channel
+with many different cultures and timezones. Most people are in the `CET timezone <https://en.wikipedia.org/wiki/Central_European_Time>`_,
+so the channel may be very quiet during `CET nighttime <https://time.is/CET>`_.
+
+If you receive no replies, **please be patient**.
+After all, silence is better than getting replied with `"IDK" <https://en.wiktionary.org/wiki/IDK>`_.
+Frequently, somebody knows the answer, but hasn't checked IRC yet. In any case, please **do not leave the channel while waiting for an answer!**
+Since IRC does not store messages, replying to somebody who left the channel is **impossible**.
+
+To have persistence on IRC, you can set up an `IRC bouncer <https://en.wikipedia.org/wiki/Internet_Relay_Chat#Bouncer>`_
+like `ZNC <https://en.wikipedia.org/wiki/ZNC>`_, or use `IRCCloud <https://www.irccloud.com/>`_.
+Please **do not publish any logs** of this channel.
+
+Most of the time, people use IRC on wider-than-tall screens. Because of this, consider that pressing the return key is expensive.
+Instead of sending lots of tiny messages with only about two words, prefer using longer sentences, spaces and punctuation symbols.
+If reading and understanding your messages is easy, replying to them is also easy.
+
+Discord
+"""""""
+
+Flashrom Discord channel is hosted on coreboot's server. Once you join, you will be able to see all coreboot's and flashrom's channels in one place.
+To join, use the `invite link <https://discord.gg/dgcrkwVyeR>`_.
+
+Dev meeting
+-----------
+Flashrom developers community runs an online meeting every two weeks.
+The main purpose of the meeting is to discuss development plans, ideas,
+current ongoing projects, pending patches, and sometimes organisational questions.
+
+Note this meeting is NOT:
+
+* troubleshooting session
+* tech support forum
+* user training session
+
+For questions above, please use IRC or the mailing list.
+
+Time of meeting
+"""""""""""""""
+It runs once every two weeks.
+
+**IMPORTANT**: please calculate meeting time for your local timezone.
+
+Between November and March (inclusive)
+
+ **Wednesday 21:00-22:00 UTC+0**
+
+ also known as
+
+ | Wednesday 13.00-14.00 Pacific Standard Time UTC-8
+ | Wednesday 22.00-23.00 Central European Time UTC+1
+ | Thursday 8.00-9.00am Australian Eastern Daylight Time UTC+11
+
+Between April and September (inclusive)
+
+ **Thursday 6.00-7.00am UTC+0**
+
+ also known as
+
+ | Wednesday 11pm-midnight Pacific Daylight Time UTC-7
+ | Thursday 8.00-9.00am Central European Summer Time UTC+2
+ | Thursday 16.00-17.00 Australian Eastern Standard Time UTC+10
+
+The last week of March and 4 weeks of October there are no meetings
+This is because daylight saving time changes are happening on different dates in different locations, and setting up meeting time becomes too complicated.
+
+FAQ
+"""
+**When is the next meeting?**
+
+Look into the meeting notes `document <https://docs.google.com/document/d/18qKvEbfPszjsJJGJhwi8kRVDUG3GZkADzQSH6WFsKqw/edit?usp=sharing>`_.
+The top entry, on the first page, with the date in the future, and empty list of attendees - is the next meeting.
+
+
+**How to join the meeting?**
+
+In the meeting notes `document <https://docs.google.com/document/d/18qKvEbfPszjsJJGJhwi8kRVDUG3GZkADzQSH6WFsKqw/edit?usp=sharing>`_,
+on the top it says “to join, click the link”, click the link.
+
+
+**Do I need an invitation to join the meeting?**
+
+No, just join.
+
+
+**Do I need to create an account anywhere?**
+
+No, you can join without an account, and view/comment on the meeting doc without an account.
+
+
+**How do I add a topic to the agenda?**
+
+Add comments/suggestions on the meeting doc, and they will be accepted shortly after.
diff --git a/doc/dev_guide/building_from_source.rst b/doc/dev_guide/building_from_source.rst
new file mode 100644
index 000000000..64250dd09
--- /dev/null
+++ b/doc/dev_guide/building_from_source.rst
@@ -0,0 +1,288 @@
+Building from source
+====================
+
+You're going to need the following tools to get started:
+
+* gcc or clang
+* meson
+* ninja
+* pkg-config
+* sphinx-build*
+
+| \* optional, to build man-pages and html documentation
+
+And the following dependencies:
+
+* cmocka [#b1]_
+* linux-headers [#b2]_
+* libpci [#b2]_
+* libusb1 [#b2]_
+* libftdi1 [#b2]_
+* libjaylink [#b2]_
+* NI-845x driver & library package [#b3]_
+
+.. [#b1] | optional, for building unit testing
+.. [#b2] | optional, depending on the selected programmer
+.. [#b3] | optional, proprietary and Windows only. (See Windows build instructions)
+
+If you are cross compiling, install the dependencies for your target.
+
+TL;DR
+-----
+::
+
+ meson setup builddir
+ meson compile -C builddir
+ meson install -C builddir
+
+
+.. _installing-dependencies:
+
+Installing dependencies
+-----------------------
+
+.. todo:: Move the bullet points to `tabs <https://www.w3schools.com/howto/howto_js_tabs.asp>`_
+
+ * No external dependencies (documentation should be build without fetching all of pypi)
+ * No Javascript?
+
+* Linux
+ * Debian / Ubuntu
+ ::
+
+ apt-get install -y \
+ gcc meson ninja-build pkg-config python3-sphinx \
+ libcmocka-dev libpci-dev libusb-1.0-0-dev libftdi1-dev libjaylink-dev
+
+ * ArchLinux / Manjaro
+ ::
+
+ pacman -S --noconfirm \
+ gcc meson ninja pkg-config python-sphinx cmocka \
+ pciutils libusb libftdi libjaylink
+
+ * openSUSE / SUSE
+ ::
+
+ zypper install -y \
+ gcc meson ninja pkg-config python3-Sphinx \
+ libcmocka-devel pciutils-devel libusb-1_0-devel libftdi1-devel libjaylink-devel
+
+ * NixOS / nixpkgs
+ * There is a ``shell.nix`` under ``scripts/``
+
+ ::
+
+ nix-shell -p \
+ gcc meson ninja pkg-config sphinx \
+ cmocka pciutils libusb1 libftdi1 libjaylink
+
+ * Alpine Linux
+ ::
+
+ apk add \
+ build-base meson ninja pkgconf py3-sphinx \
+ cmocka-dev pciutils-dev libusb-dev libjaylink-dev
+
+* Windows
+ * MSYS2
+ Install `MSYS2 <https://www.msys2.org/>`_ and ensure it is `fully updated <https://www.msys2.org/docs/updating/>`_.
+
+ * ``libpci`` is not available through the package manager and pci based programmer are not supported on Windows.
+ * ``ni845x_spi`` is only available with the proprietary library from National Instruments. Download and install the driver
+ from `ni.com <https://www.ni.com/en-us/support/downloads/drivers/download.ni-845x-driver-software.html>`_ and build flashrom
+ for **32-bit**. Add ``-Dprogrammer=ni845x_spi`` to your meson configuration.
+
+ In the MINGW64 shell run::
+
+ pacman -Sy \
+ mingw-w64-x86_64-gcc mingw-w64-x86_64-meson mingw-w64-x86_64-ninja mingw-w64-x86_64-pkg-config mingw-w64-x86_64-python-sphinx \
+ mingw-w64-x86_64-cmocka mingw-w64-x86_64-libusb mingw-w64-x86_64-libftdi mingw-w64-x86_64-libjaylink-git
+
+ For building flashrom as 32-bit application, use the MSYS2 MINGW32 shell and run::
+
+ pacman -Sy \
+ mingw-w64-i686-gcc mingw-w64-i686-meson mingw-w64-i686-ninja mingw-w64-i686-pkg-config mingw-w64-i686-python-sphinx \
+ mingw-w64-i686-cmocka mingw-w64-i686-libusb mingw-w64-i686-libftdi mingw-w64-i686-libjaylink-git
+
+* MacOS
+ * Homebrew
+ * ``libpci`` is not available through the package manager
+ * ``libjaylink`` is not available through the package manager
+
+ ::
+
+ brew install \
+ meson ninja pkg-config sphinx-doc \
+ libusb libftdi
+
+* BSD
+ * FreeBSD / DragonFlyBSD
+ * ``libusb1`` is part of the system
+ * ``libjaylink`` is not available through the package manager
+
+ ::
+
+ pkg install \
+ meson ninja pkgconf py39-sphinx \
+ cmocka libpci libftdi1
+
+ * OpenBSD
+ * ``libjaylink`` is not available through the package manager
+
+ ::
+
+ pkg_add \
+ meson ninja pkg-config py39-sphinx\
+ cmocka pciutils libusb1 libftdi1
+
+ * NetBSD
+ * ``libjaylink`` is not available through the package manager
+ * note: https://www.cambus.net/installing-ca-certificates-on-netbsd/
+
+ ::
+
+ pkgin install \
+ meson ninja pkg-config py39-sphinx \
+ cmocka pciutils libusb1 libftdi1
+
+* OpenIndiana (Illumos, Solaris, SunOS)
+ * ``libpci`` missing, pciutils is build without it
+ * ``libftdi1`` & ``libjaylink`` are not available through the package manager
+ * TODO: replace ``build-essential`` with the default compiler
+
+ ::
+
+ pkg install build-essential meson ninja cmocka libusb-1
+
+* DJGPP-DOS
+ * Get `DJGPP <https://www.delorie.com/djgpp/>`_
+ * A great build script can be found `here <https://github.com/andrewwutw/build-djgpp>`_
+ * Download the `pciutils <https://mj.ucw.cz/sw/pciutils/>`_ sources
+
+ | Run the following commands in the the pciutils directory to build libpci for DOS.
+ | Replace ``<DOS_INSTALL_ROOT>`` with your cross-compile install root.
+
+ ::
+
+ make install-lib \
+ ZLIB=no \
+ DNS=no \
+ HOST=i386-djgpp-djgpp \
+ CROSS_COMPILE=i586-pc-msdosdjgpp- \
+ STRIP="--strip-program=i586-pc-msdosdjgpp-strip -s" \
+ PREFIX=<DOS_INSTALL_ROOT>
+
+ Point pkg-config to the ``<DOS_INSTALL_ROOT>`` ::
+
+ export PKG_CONFIG_SYSROOT=<DOS_INSTALL_ROOT>
+
+ * To compile flashrom use the ``meson_cross/i586_djgpp_dos.txt`` cross-file
+ * You will need `CWSDPMI.EXE <https://sandmann.dotster.com/cwsdpmi/>`_ to run flashrom
+
+* libpayload
+ .. todo:: Add building instructions for libpayload
+
+
+Configuration
+-------------
+In the flashrom repository run::
+
+ meson setup [builtin options] [flashrom options] <builddir>
+
+Mesons ``[builtin options]`` can be displayed with ``meson setup --help``.
+The flashrom specific options can be found in ``meson_options.txt`` in the top-level
+directory of flashrom and are used like in cmake with ``-Doption=value``
+Run ``meson configure`` to display all configuration options.
+
+.. todo:: Write a sphinx extension to render ``meson_options.txt`` here
+
+
+Configuration for Crossbuilds
+-----------------------------
+Flashrom specific cross-files can be found in the ``meson_cross`` folder.
+To use them run::
+
+ meson setup --cross-file <path/to/crossfile> [builtin options] [flashrom options] <builddir>
+
+The options are the same as the normal configuration options. For more information see
+https://mesonbuild.com/Cross-compilation.html
+
+
+Compiling
+---------
+Run::
+
+ meson compile -C <builddir>
+
+
+Update configuration
+--------------------
+If you want to change your initial configuration for some reason
+(for example you discovered that a programmer is missing), run::
+
+ meson configure [updated builtin options] [updated flashrom options] <builddir>
+
+
+Unit Tests
+----------
+To execute the unit tests run::
+
+ meson test -C <builddir>
+
+You will get a summary of the unit test results at the end.
+
+
+Code coverage
+"""""""""""""
+gcov
+ Due to a bug in lcov, the html file will only be correct if lcov is not
+ installed and gcovr is installed. See
+ https://github.com/linux-test-project/lcov/issues/168 and
+ https://github.com/mesonbuild/meson/issues/6747
+
+ To create the coverage target add ``-Db_coverage=true`` to your build configuration.
+ After executing the tests, you can run ::
+
+ ninja -C <builddir> coverage
+
+ to generate the coverage report.
+
+lcov / llvm
+ https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
+ Make sure that you are using `clang` as compiler, e.g. by setting `CC=clang` during configuration.
+ Beside that you need to add ``-Dllvm_cov=enabled`` to your build configuration ::
+
+ CC=clang meson setup -Dllvm_cov=enable <builddir>
+ meson test -C <builddir>
+ ninja -C <builddir> llvm-cov-tests
+
+For additional information see `the meson documentation <https://mesonbuild.com/Unit-tests.html#coverage>`_
+
+
+Installing
+----------
+To install flashrom and documentation, run::
+
+ meson install -C <builddir>
+
+This will install flashrom under the PREFIX selected in the configuration phase. Default is ``/usr/local``.
+
+To install into a different directory use DESTDIR, like this::
+
+ DESTDIR=/your/destination/directory meson install -C <your_build_dir>
+
+You can also set the prefix during configuration with::
+
+ meson setup --prefix <DESTDIR> <your_build_dir>
+
+Create distribution package
+---------------------------
+To create a distribution tarball from your ``builddir``, run::
+
+ meson dist -C <builddir>
+
+This will collect all git tracked files and pack them into an archive.
+
+Current flashrom version is in the VERSION file. To release a new flashrom
+version you need to change VERSION file and tag the changing commit.
diff --git a/doc/dev_guide/building_with_make.rst b/doc/dev_guide/building_with_make.rst
new file mode 100644
index 000000000..710aad3d1
--- /dev/null
+++ b/doc/dev_guide/building_with_make.rst
@@ -0,0 +1,195 @@
+Building with make
+==================
+
+TLDR
+----
+
+::
+
+ make
+ make install
+
+Build instructions
+------------------
+
+**To build flashrom you need to install the following software:**
+
+ * C compiler (GCC / clang)
+ * pkg-config
+
+ * pciutils+libpci (if you want support for mainboard or PCI device flashing)
+ * libusb (if you want FT2232, Dediprog or USB-Blaster support)
+ * libftdi (if you want FT2232 or USB-Blaster support)
+ * libjaylink (if you want support for SEGGER J-Link and compatible devices)
+ * NI-845x driver & library package (if you want support for NI-845x devices; uses a proprietary driver)
+
+**Linux et al:**
+
+ * pciutils / libpci
+ * pciutils-devel / pciutils-dev / libpci-dev
+ * zlib-devel / zlib1g-dev (needed if libpci was compiled with libz support)
+
+**On FreeBSD, you need the following ports:**
+
+ * devel/gmake
+ * devel/libpci
+
+**On OpenBSD, you need the following ports:**
+
+ * devel/gmake
+ * sysutils/pciutils
+
+**To compile on Linux, use**::
+
+ make
+
+**To compile on FreeBSD, OpenBSD or DragonFly BSD, use**::
+
+ gmake
+
+**To compile on Nexenta, use**::
+
+ make
+
+**To compile on Solaris, use**::
+
+ gmake LDFLAGS="-L$pathtolibpci" CC="gcc -I$pathtopciheaders" CFLAGS=-O2
+
+**To compile on NetBSD (with pciutils, libftdi, libusb installed in /usr/pkg/), use**::
+
+ gmake
+
+**To compile and run on Darwin/Mac OS X:**
+
+Install DirectHW from coresystems GmbH.
+DirectHW is available at https://www.coreboot.org/DirectHW .
+
+**To compile on Windows:**
+
+Install MSYS tools (and the NI-845x drivers if desired) as described in
+:ref:`installing-dependencies`.
+
+To build with support for NI-845x::
+
+ make HAS_LIB_NI845X=yes CONFIG_NI845X_SPI=yes
+
+**To cross-compile on Linux for DOS:**
+
+Get packages of the DJGPP cross compiler and install them:
+
+ * djgpp-filesystem djgpp-gcc djgpp-cpp djgpp-runtime djgpp-binutils
+
+As an alternative, the DJGPP web site offers packages for download as well:
+
+ * djcross-binutils-2.29.1-1ap.x86_64.rpm
+ * djcross-gcc-7.2.0-1ap.x86_64.rpm
+ * djcrx-2.05-5.x86_64.rpm
+
+The cross toolchain packages for your distribution may have slightly different
+names (look for packages named *djgpp*).
+
+Alternatively, you could use a script to build it from scratch:
+https://github.com/andrewwutw/build-djgpp
+
+You will need the libpci and libgetopt library source trees and
+their compiled static libraries and header files installed in some
+directory say libpci-libgetopt/, which will be later specified with
+LIBS_BASE parameter during flashrom compilation. Easiest way to
+handle it is to put pciutils, libgetopt and flashrom directories
+in one subdirectory. There will be an extra subdirectory libpci-libgetopt
+created, which will contain compiled libpci and libgetopt.
+
+Download pciutils 3.5.6 and apply https://flashrom.org/File:Pciutils-3.5.6.patch.gz
+Compile pciutils, using following command line::
+
+ make ZLIB=no DNS=no HOST=i386-djgpp-djgpp CROSS_COMPILE=i586-pc-msdosdjgpp- \
+ PREFIX=/ DESTDIR=$PWD/../libpci-libgetopt \
+ STRIP="--strip-program=i586-pc-msdosdjgpp-strip -s" install install-lib
+
+Download and compile with 'make' https://flashrom.org/File:Libgetopt.tar.gz
+
+Copy the libgetopt.a to ../libpci-libgetopt/lib and
+getopt.h to ../libpci-libgetopt/include
+
+Enter the flashrom directory::
+
+ make CC=i586-pc-msdosdjgpp-gcc STRIP=i586-pc-msdosdjgpp-strip LIBS_BASE=../libpci-libgetopt/ strip
+
+If you like, you can compress the resulting executable with UPX::
+
+ upx -9 flashrom.exe
+
+To run flashrom.exe, download https://flashrom.org/File:Csdpmi7b.zip and
+unpack CWSDPMI.EXE into the current directory or one in PATH.
+
+**To cross-compile on Linux for Windows:**
+
+Get packages of the MinGW cross compiler and install them::
+
+ mingw32-filesystem mingw32-cross-cpp mingw32-cross-binutils mingw32-cross-gcc
+ mingw32-runtime mingw32-headers
+
+The cross toolchain packages for your distribution may have slightly different
+names (look for packages named *mingw*).
+PCI-based programmers (internal etc.) are not supported on Windows.
+Run (change CC= and STRIP= settings where appropriate)::
+
+ make CC=i686-w64-mingw32-gcc STRIP=i686-w64-mingw32-strip
+
+**Processor architecture dependent features:**
+
+On non-x86 architectures a few programmers don't work (yet) because they
+use port-based I/O which is not directly available on non-x86. Those
+programmers will be disabled automatically if you run "make".
+
+**Compiler quirks:**
+
+If you are using clang and if you want to enable only one driver, you may hit an
+overzealous compiler warning from clang. Compile with "make WARNERROR=no" to
+force it to continue and enjoy.
+
+**Bindings:**
+
+Foreign function interface bindings for the rust language are included in the
+bindings folder. These are not compiled as part of the normal build process.
+See the readme under bindings/rust for more information.
+
+
+Installation
+------------
+
+In order to install flashrom and the manpage into /usr/local, type::
+
+ make install
+
+For installation in a different directory use DESTDIR, e.g. like this::
+
+ make DESTDIR=/usr install
+
+If you have insufficient permissions for the destination directory, use sudo
+by adding sudo in front of the commands above.
+
+
+Packaging
+---------
+
+To package flashrom and remove dependencies on Git, either use::
+
+ make export
+
+or::
+
+ make tarball
+
+``make export`` will export all flashrom files from the Git repository at
+revision HEAD into a directory named ``$EXPORTDIR/flashrom-$RELEASENAME``
+and will additionally add a ``versioninfo.inc`` file in that directory to
+contain the Git revision of the exported tree and a date for the manual
+page.
+
+``make tarball`` will simply tar up the result of make export and compress
+it with bzip2.
+
+The snapshot tarballs are the result of ``make tarball`` and require no
+further processing. Some git files (for example the rust bindings) are omitted
+from the tarball, as controlled by the .gitattributes files.
diff --git a/doc/dev_guide/development_guide.rst b/doc/dev_guide/development_guide.rst
new file mode 100644
index 000000000..40837a943
--- /dev/null
+++ b/doc/dev_guide/development_guide.rst
@@ -0,0 +1,342 @@
+=================
+Development Guide
+=================
+
+We welcome contributions from every human being, corporate entity or club.
+
+This document describes the rules and recommendations about the development, contribution and review processes.
+
+If you introduce new features (not flash chips, but stuff like partial
+programming, support for new external programmers, voltage handling, etc)
+please **discuss your plans** on the :ref:`mailing list` first. That way, we
+can avoid duplicated work and know about how flashrom internals need to be
+adjusted and you avoid frustration if there is some disagreement about the
+design.
+
+You can `look at the latest flashrom development efforts in Gerrit <https://review.coreboot.org/q/project:flashrom>`_.
+
+Set up the git repository and dev environment
+=============================================
+
+#. Clone git repository
+
+ * If using https: :code:`git clone "https://review.coreboot.org/flashrom"`
+ * If using ssh: :code:`git clone "ssh://<gerrit_username>@review.coreboot.org:29418/flashrom"`
+
+#. Follow the build guidelines to install dependencies :doc:`building_from_source`
+
+#. Install Git hooks: :code:`./util/git-hooks/install.sh`
+
+#. Add upstream as a remote:
+
+ * If using https: :code:`git remote add -f upstream https://review.coreboot.org/flashrom`
+ * If using ssh: :code:`git remote add -f upstream ssh://<gerrit_username>@review.coreboot.org:29418/flashrom`
+
+#. Check out a new local branch that tracks :code:`upstream/master`: :code:`git checkout -b <branch_name> upstream/master`
+
+#. Every patch is required to be signed-off (see also :ref:`sign-off`).
+ Set up your ``user.name`` and ``user.email`` in git config, and don't forget
+ to ``-s`` when creating a commit.
+
+#. See also build guidelines :doc:`building_from_source` and `git docs <https://git-scm.com/doc>`_
+
+Creating your patch
+===================
+
+In short, commit your changes with a descriptive message and remember to sign off
+on the commit (``git commit -s``).
+
+.. _commit-message:
+
+Commit message
+--------------
+
+Commit messages shall have the following format:
+
+.. code-block::
+
+ <component>: Short description (up to 72 characters)
+
+ This is a long description. Max width of each line in the description
+ is 72 characters. It is separated from the summary by a blank line. You
+ may skip the long description if the short description is sufficient,
+ for example "flashchips: Add FOO25Q128" to add FOO25Q128 chip support.
+
+ You may have multiple paragraphs in the long description, but please
+ do not write a novel here. For non-trivial changes you must explain
+ what your patch does, why, and how it was tested.
+
+ Finally, follow the sign-off procedure to add your sign-off!
+
+ Signed-off-by: Your Name <your@domain>
+
+Commit message should include:
+
+* Commit title
+* Commit description: explain what the patch is doing, or what it is fixing.
+* Testing information: how did you test the patch.
+* Signed-off-by line (see below :ref:`sign-off`)
+* If applicable, link to the ticket in the bugtracker `<https://ticket.coreboot.org/projects/flashrom>`_
+* Change-Id for Gerrit. If commit message doesn't have Change-Id, you forgot to install git hooks.
+
+.. _sign-off:
+
+Sign-off procedure
+^^^^^^^^^^^^^^^^^^
+
+We employ a similar sign-off procedure as the `Linux kernel developers
+<http://web.archive.org/web/20070306195036/http://osdlab.org/newsroom/press_releases/2004/2004_05_24_dco.html>`_
+do. Add a note such as
+
+:code:`Signed-off-by: Random J Developer <random@developer.example.org>`
+
+to your email/patch if you agree with the Developer's Certificate of Origin 1.1
+printed below. Read `this post on the LKML
+<https://lkml.org/lkml/2004/5/23/10>`_ for rationale (spoiler: SCO).
+
+You must use your known identity in the ``Signed-off-by`` line and in any
+copyright notices you add. Anonymous patches lack provenance and cannot be
+committed!
+
+Developer's Certificate of Origin 1.1
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ By making a contribution to this project, I certify that:
+
+ (a) The contribution was created in whole or in part by me and I have
+ the right to submit it under the open source license indicated in the file; or
+
+ (b) The contribution is based upon previous work that, to the best of my
+ knowledge, is covered under an appropriate open source license and I have the
+ right under that license to submit that work with modifications, whether created
+ in whole or in part by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated in the file; or
+
+ (c) The contribution was provided directly to me by some other person who
+ certified (a), (b) or (c) and I have not modified it; and
+
+ (d) In the case of each of (a), (b), or (c), I understand and agree that
+ this project and the contribution are public and that a record of the contribution
+ (including all personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with this project or the
+ open source license indicated in the file.
+
+.. note::
+
+ The `Developer's Certificate of Origin 1.1
+ <http://web.archive.org/web/20070306195036/http://osdlab.org/newsroom/press_releases/2004/2004_05_24_dco.html>`_
+ is licensed under the terms of the `Creative Commons Attribution-ShareAlike
+ 2.5 License <http://creativecommons.org/licenses/by-sa/2.5/>`_.
+
+Coding style
+------------
+
+Flashrom generally follows Linux kernel style:
+https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/coding-style.rst
+
+The notable exception is line length limit. Our guidelines are:
+
+* 80-columns soft limit for most code and comments. This is to encourage simple design and concise naming.
+* 112-columns hard limit. Use this to reduce line breaks in cases where they
+ harm grep-ability or overall readability, such as print statements and
+ function signatures. Don't abuse this for long variable/function names or
+ deep nesting.
+* Tables are the only exception to the hard limit and may be as long as needed
+ for practical purposes.
+
+Our guidelines borrow heavily from `coreboot coding style
+<https://doc.coreboot.org/contributing/coding_style.html>`_ and `coreboot Gerrit
+guidelines <https://doc.coreboot.org/contributing/gerrit_guidelines.html>`_,
+and most of them apply to flashrom as well. The really important part is about
+the :ref:`sign-off procedure <sign-off>`.
+
+We try to **reuse as much code as possible** and create new files only if
+absolutely needed, so if you find a function somewhere in the tree which
+already does what you want, please use it.
+
+Testing a patch
+---------------
+
+We expect the patch to be appropriately tested by the patch owner.
+Please add the testing information in commit message, for example that could be some of these:
+programmer you were using, programmer params, chip, OS, operations you were running
+(read/write/erase/verify), and anything else that is relevant.
+
+.. _working-with-gerrit:
+
+Working with Gerrit
+===================
+
+All of the patches and code reviews need to go via
+`Gerrit on review.coreboot.org <https://review.coreboot.org/#/q/project:flashrom>`_.
+While it is technically possible to send a patch to the mailing list, that patch
+still needs to be pushed to Gerrit by someone. We treat patches on the mailing list as a very
+exceptional situation. Normal process is to push a patch to Gerrit.
+Please read below for instructions and check `official Gerrit documentation <https://gerrit-review.googlesource.com/Documentation/>`_.
+
+Creating an account
+---------------------
+
+#. Go to https://review.coreboot.org/login and sign in using the credentials of
+ your choice.
+#. Edit your settings by clicking on the gear icon in the upper right corner.
+#. Set your Gerrit username (this may be the different from the username of an
+ external account you log in with).
+#. Add an e-mail address so that Gerrit can send notifications to you about
+ your patch.
+#. Upload an SSH public key, or click the button to generate an HTTPS password.
+
+.. _pushing-a-patch:
+
+Pushing a patch
+---------------
+
+To push patch to Gerrit, use the follow command: :code:`git push upstream HEAD:refs/for/master`.
+
+* If using HTTPS you will be prompted for the username and password you
+ set in the Gerrit UI.
+* If successful, the Gerrit URL for your patch will be shown in the output.
+
+There is an option to add a topic to the patch. For one-off standalone patches this
+is not necessary. However if your patch is a part of a larger effort, especially if the
+work involves multiple contributors, it can be useful to mark that the patch belongs
+to a certain topic.
+
+Adding a topic makes it easy to search "all the patches by the topic", even if the patches
+have been authored by multiple people.
+
+To add a topic, push with the command: :code:`git push upstream HEAD:refs/for/master%topic=example_topic`.
+Alternatively, you can add a topic from a Gerrit UI after the patch in pushed
+(on the top-left section) of patch UI.
+
+Adding reviewers to the patch
+-----------------------------
+
+After pushing the patch, ideally try to make sure there are some reviewers added to your patch.
+
+flashrom has MAINTAINERS file with people registered for some areas of the code. People who
+are in MAINTAINERS file will be automatically added as reviewers if the patch touches that
+area. However, not all areas are covered in the file, and it is possible that for the patch you
+sent no one is added automatically.
+
+If you know someone in the dev community who can help with patch review, add the person(s) you know.
+
+In general, it's a good idea to add someone who has a knowledge of whatever the patch is doing,
+even if the person has not been added automatically.
+
+If you are new, and don't know anyone, and no one has been added automatically: you can add
+Anastasia Klimchuk (aklm) as a reviewer.
+
+Going through code reviews
+--------------------------
+
+You will likely get some comments on your patch, and you will need to fix the comments.
+After doing the work locally, amend your commit ``git commit --amend -s`` and push to Gerrit again.
+Check that Change-Id in commit message stays the same. This way Gerrit knows your change belongs
+to the same patch, and will upload new change as new patchset for the same patch.
+
+After uploading the work, go through comments and respond to them. Mark as Done the ones you done
+and mark them as resolved. If there is something that is impossible to do, or maybe you have more questions,
+or maybe you are not sure what you are asked about: respond to a comment **without marking it as resolved**.
+
+It is completely fine to ask a clarifying questions if you don't understand what the comment is asking you to do.
+If is also fine to explain why a comment can't be done, if you think it can't be done.
+
+The patch reviews may take some time, but please don't get discouraged.
+We have quite high standards regarding code quality.
+
+Initial review should include a broad indication of acceptance or rejection of
+the idea/rationale/motivation or the implementation
+
+In general, reviews should focus on the architectural changes and things that
+affect flashrom as a whole. This includes (but is by no means limited to)
+changes in APIs and types, safety, portability, extensibility, and
+maintainability. The purpose of reviews is not to create perfect patches, but
+to steer development in the right direction and produce consensus within the
+community. The goal of each patch should be to improve the state of the project
+- it does not need to fix all problems of the respective field perfectly.
+
+ New contributors may need more detailed advices and should be told about
+ minor issues like formatting problems more precisely. The result of a review
+ should either be an accepted patch or a guideline how the existing code
+ should be changed to be eventually accepted.
+
+To get an idea whether the patch is ready or not, please check :ref:`merge-checklist`.
+
+If you sent a patch and later lost interest or no longer have time to follow up on code review,
+please add a comment saying so. Then, if any of our maintainers are interested in finishing the work,
+they can take over the patch.
+
+Downloading patch from Gerrit
+-----------------------------
+
+Sometimes you may need to download a patch into your local repository. This can be needed for example:
+
+* if you want to test someone else's patch,
+* if multiple developers are collaborating on a patch,
+* if you are continuing someone else's work, when original author left or unable to continue.
+
+First prepare local repository: sync to head or to desired tag / commit.
+
+Open patch in Gerrit, open "three dot" menu on top-right, open Download patch. Copy Cherry-pick command (pick
+the relevant tab for you: anonymous http / http / ssh) and run the copied command in your local repo.
+
+Now you have the commit locally and can do the testing or futher developing. To upload your local changes,
+push patch to Gerrit again (see :ref:`pushing-a-patch`).
+
+Make sure people involved in the patch agree that you are pushing new version of someone else's patch,
+so this does not come at a surprise for an original author.
+
+Merging patches
+---------------
+
+Merging to branches is limited to the "flashrom developers" group on Gerrit (see also :doc:`/about_flashrom/team`).
+
+The list of requirements for the patch to be ready for merging is below, see :ref:`merge-checklist`.
+Some of the requirements are enforced by Gerrit, but not all of them. In general, a person who clicks
+Submit button is responsible to go through Merge checklist. Code reviewers should be aware of the checklist
+as well.
+
+Patch owners can use the checklist to detect whether the patch is ready for merging or not.
+
+.. _merge-checklist:
+
+Merge checklist
+^^^^^^^^^^^^^^^
+
+#. Every patch has to be reviewed and needs at least one +2 that was not given by the commit's author.
+ Ideally, people who were actively reviewing the patch and adding comments, would be the ones approving it.
+#. If a patch is authored by more than one person (Co-developed-by), each author may +2 the other author's changes.
+#. Patch needs to get Verified +1 vote, typically from Jenkins build bot. This means the patch builds successfully
+ and all unit tests pass.
+#. Commit message should have Signed-off-by line, see :ref:`sign-off` and align with the rest
+ of the rules for :ref:`commit-message`
+#. All the comments need to be addressed, especially if there was a negative vote in the process of review (-1 or -2).
+#. flashrom developers are people from literally all around the planet, and various timezones. We usually wait
+ for 3 days (3 * 24hours) after the patch is fully approved just in case of last minute concerns from all timezones.
+#. In the case of emergency, merging should not take place within less than 24 hours after the review
+ started (i.e. the first message by a reviewer on Gerrit).
+
+To help search for patches which are potential candidates for merging, you can try using this search in Gerrit::
+
+ status:open project:flashrom -is:wip -label:Verified-1 label:Verified+1 -label:Code-Review<0 age:3d is:mergeable is:submittable -has:unresolved
+
+Note the search is not a replacement for Merge checklist, but it can help find candidates for merging.
+
+Bugtracker
+==========
+
+We have a bugtracker on `<https://ticket.coreboot.org/projects/flashrom>`_.
+Anyone can view tickets, but to be able to create/update/assign tickets you need an account.
+
+Mirrors
+========
+
+The only official repository is https://review.coreboot.org/flashrom ; GitHub and GitLab are just mirrors.
+**Reviewers do not look at pull requests** on mirrors.
+Even if pull requests were automatically transferred to Gerrit,
+requirements such as :ref:`sign-off` still present a problem.
+
+The quickest and best way to get your patch reviewed and merged is by sending
+it to review.coreboot.org (see :ref:`working-with-Gerrit`). Conveniently, you can use your GitHub, GitLab or
+Google account as an OAuth2 `login method <https://review.coreboot.org/login>`_.
diff --git a/doc/dev_guide/index.rst b/doc/dev_guide/index.rst
new file mode 100644
index 000000000..57cd8468c
--- /dev/null
+++ b/doc/dev_guide/index.rst
@@ -0,0 +1,9 @@
+Developers documentation
+========================
+
+.. toctree::
+ :maxdepth: 1
+
+ building_from_source
+ building_with_make
+ development_guide
diff --git a/doc/documentation_license.rst b/doc/documentation_license.rst
new file mode 100644
index 000000000..ebadeb77d
--- /dev/null
+++ b/doc/documentation_license.rst
@@ -0,0 +1,296 @@
+=====================
+Documentation license
+=====================
+
+Files under doc/ are licensed under CC-BY 4.0 terms, printed below.
+
+Attribution 4.0 International
+=============================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and does not provide
+legal services or legal advice. Distribution of Creative Commons public licenses does
+not create a lawyer-client or other relationship. Creative Commons makes its licenses
+and related information available on an "as-is" basis. Creative Commons gives no warranties
+regarding its licenses, any material licensed under their terms and conditions, or any
+related information. Creative Commons disclaims all liability for damages resulting from
+their use to the fullest extent possible.
+
+Using Creative Commons Public Licenses
+--------------------------------------
+
+Creative Commons public licenses provide a standard set of terms and conditions that
+creators and other rights holders may use to share original works of authorship and other
+material subject to copyright and certain other rights specified in the public license below.
+The following considerations are for informational purposes only, are not exhaustive, and do
+not form part of our licenses.
+
+* **Considerations for licensors:** Our public licenses are intended for use by those
+ authorized to give the public permission to use material in ways otherwise restricted
+ by copyright and certain other rights. Our licenses are irrevocable. Licensors should
+ read and understand the terms and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before applying our licenses so that the
+ public can reuse the material as expected. Licensors should clearly mark any material not
+ subject to the license. This includes other CC-licensed material, or material used under an
+ exception or limitation to copyright. `More considerations for licensors <http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors>`_
+
+* **Considerations for the public:** By using one of our public licenses, a licensor grants
+ the public permission to use the licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason - for example, because of any
+ applicable exception or limitation to copyright - then that use is not regulated by the
+ license. Our licenses grant only permissions under copyright and certain other rights that a
+ licensor has authority to grant. Use of the licensed material may still be restricted for
+ other reasons, including because others have copyright or other rights in the material.
+ A licensor may make special requests, such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to respect those requests where
+ reasonable. `More considerations for the public <http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees>`_
+
+Creative Commons Attribution 4.0 International Public License
+=============================================================
+
+By exercising the Licensed Rights (defined below), You accept and agree to be bound by the
+terms and conditions of this Creative Commons Attribution 4.0 International Public License
+("Public License"). To the extent this Public License may be interpreted as a contract, You
+are granted the Licensed Rights in consideration of Your acceptance of these terms and
+conditions, and the Licensor grants You such rights in consideration of benefits the Licensor
+receives from making the Licensed Material available under these terms and conditions.
+
+Section 1 - Definitions.
+------------------------
+
+\a. **Adapted Material** means material subject to Copyright and Similar Rights that is
+derived from or based upon the Licensed Material and in which the Licensed Material is
+translated, altered, arranged, transformed, or otherwise modified in a manner requiring
+permission under the Copyright and Similar Rights held by the Licensor. For purposes of
+this Public License, where the Licensed Material is a musical work, performance, or sound
+recording, Adapted Material is always produced where the Licensed Material is synched in
+timed relation with a moving image.
+
+\b. **Adapter's License** means the license You apply to Your Copyright and Similar Rights
+in Your contributions to Adapted Material in accordance with the terms and conditions of
+this Public License.
+
+\c. **Copyright and Similar Rights** means copyright and/or similar rights closely related
+to copyright including, without limitation, performance, broadcast, sound recording, and
+Sui Generis Database Rights, without regard to how the rights are labeled or categorized.
+For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not
+Copyright and Similar Rights.
+
+\d. **Effective Technological Measures** means those measures that, in the absence of proper
+authority, may not be circumvented under laws fulfilling obligations under Article 11 of
+the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
+
+\e. **Exceptions and Limitations** means fair use, fair dealing, and/or any other exception or
+limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
+
+\f. **Licensed Material** means the artistic or literary work, database, or other material to
+which the Licensor applied this Public License.
+
+\g. **Licensed Rights** means the rights granted to You subject to the terms and conditions of
+this Public License, which are limited to all Copyright and Similar Rights that apply to Your
+use of the Licensed Material and that the Licensor has authority to license.
+
+\h. **Licensor** means the individual(s) or entity(ies) granting rights under this Public License.
+
+\i. **Share** means to provide material to the public by any means or process that requires
+permission under the Licensed Rights, such as reproduction, public display, public performance,
+distribution, dissemination, communication, or importation, and to make material available to
+the public including in ways that members of the public may access the material from a place
+and at a time individually chosen by them.
+
+\j. **Sui Generis Database Rights** means rights other than copyright resulting from Directive 96/9/EC
+of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases,
+as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
+
+\k. **You** means the individual or entity exercising the Licensed Rights under this Public License.
+Your has a corresponding meaning.
+
+Section 2 - Scope.
+------------------
+
+\a. **License grant.**
+
+ 1) Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide,
+ royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in
+ the Licensed Material to:
+
+ \A. reproduce and Share the Licensed Material, in whole or in part; and
+
+ \B. produce, reproduce, and Share Adapted Material.
+
+ 2) **Exceptions and Limitations.** For the avoidance of doubt, where Exceptions and Limitations apply
+ to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
+
+ 3) **Term.** The term of this Public License is specified in Section 6(a).
+
+ 4) **Media and formats; technical modifications allowed.** The Licensor authorizes You to exercise
+ the Licensed Rights in all media and formats whether now known or hereafter created, and to make
+ technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right
+ or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights,
+ including technical modifications necessary to circumvent Effective Technological Measures. For purposes
+ of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
+
+ 5) **Downstream recipients.**
+
+ \A. **Offer from the Licensor - Licensed Material.** Every recipient of the Licensed Material
+ automatically receives an offer from the Licensor to exercise the Licensed Rights under the
+ terms and conditions of this Public License.
+
+ \B. **No downstream restrictions.** You may not offer or impose any additional or different terms
+ or conditions on, or apply any Effective Technological Measures to, the Licensed Material if
+ doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
+
+ 6) **No endorsement.** Nothing in this Public License constitutes or may be construed as permission
+ to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or
+ sponsored, endorsed, or granted official status by, the Licensor or others designated to receive
+ attribution as provided in Section 3(a)(1)(A)(i).
+
+\b. **Other rights.**
+
+ 1) Moral rights, such as the right of integrity, are not licensed under this Public License, nor are
+ publicity, privacy, and/or other similar personality rights; however, to the extent possible, the
+ Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent
+ necessary to allow You to exercise the Licensed Rights, but not otherwise.
+
+ 2) Patent and trademark rights are not licensed under this Public License.
+
+ 3) To the extent possible, the Licensor waives any right to collect royalties from You for the exercise
+ of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable
+ statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right
+ to collect such royalties.
+
+Section 3 - License Conditions.
+-------------------------------
+
+Your exercise of the Licensed Rights is expressly made subject to the following conditions.
+
+\a. **Attribution.**
+
+ 1) If You Share the Licensed Material (including in modified form), You must:
+
+ \A. retain the following if it is supplied by the Licensor with the Licensed Material:
+
+ \i. identification of the creator(s) of the Licensed Material and any others designated to receive
+ attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
+
+ \ii. a copyright notice;
+
+ \iii. a notice that refers to this Public License;
+
+ \iv. a notice that refers to the disclaimer of warranties;
+
+ \v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
+
+ \B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
+
+ \C. indicate the Licensed Material is licensed under this Public License, and include the text of,
+ or the URI or hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means,
+ and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the
+ conditions by providing a URI or hyperlink to a resource that includes the required information.
+
+ 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to
+ the extent reasonably practicable.
+
+ 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients
+ of the Adapted Material from complying with this Public License.
+
+Section 4 - Sui Generis Database Rights.
+----------------------------------------
+
+Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
+
+\a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share
+all or a substantial portion of the contents of the database;
+
+\b. if You include all or a substantial portion of the database contents in a database in which You have
+Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its
+individual contents) is Adapted Material; and
+
+\c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the
+contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this
+Public License where the Licensed Rights include other Copyright and Similar Rights.
+
+Section 5 - Disclaimer of Warranties and Limitation of Liability.
+-----------------------------------------------------------------
+
+\a. **Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers
+the Licensed Material as-is and as-available, and makes no representations or warranties of any kind
+oncerning the Licensed Material, whether express, implied, statutory, or other. This includes, without
+limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement,
+absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known
+or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may
+not apply to You.**
+
+\b. **To the extent possible, in no event will the Licensor be liable to You on any legal theory (including,
+without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential,
+punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use
+of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs,
+expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation
+may not apply to You.**
+
+\c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that,
+to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
+
+Section 6 - Term and Termination.
+---------------------------------
+
+\a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You
+fail to comply with this Public License, then Your rights under this Public License terminate automatically.
+
+\b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
+
+ 1) automatically as of the date the violation is cured, provided it is cured within 30 days of Your
+ discovery of the violation; or
+
+ 2) upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek
+ remedies for Your violations of this Public License.
+
+\c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or
+conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
+
+\d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
+
+Section 7 - Other Terms and Conditions.
+---------------------------------------
+
+\a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You
+unless expressly agreed.
+
+\b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are
+separate from and independent of the terms and conditions of this Public License.
+
+Section 8 - Interpretation.
+---------------------------
+
+\a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit,
+restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without
+permission under this Public License.
+
+\b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be
+automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot
+be reformed, it shall be severed from this Public License without affecting the enforceability of the
+remaining terms and conditions.
+
+\c. No term or condition of this Public License will be waived and no failure to comply consented to unless
+expressly agreed to by the Licensor.
+
+\d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any
+privileges and immunities that apply to the Licensor or You, including from the legal processes of any
+jurisdiction or authority.
+
+ Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect
+ to apply one of its public licenses to material it publishes and in those instances will be considered
+ the "Licensor". Except for the limited purpose of indicating that material is shared under a
+ Creative Commons public license or as otherwise permitted by the Creative Commons policies published at
+ `creativecommons.org/policies <http://creativecommons.org/policies>`_, Creative Commons does not authorize
+ the use of the trademark "Creative Commons" or any other trademark or logo of Creative Commons without
+ its prior written consent including, without limitation, in connection with any unauthorized modifications
+ to any of its public licenses or any other arrangements, understandings, or agreements concerning use of
+ licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.
+
+ Creative Commons may be contacted at creativecommons.org
diff --git a/doc/how_to_add_docs.rst b/doc/how_to_add_docs.rst
new file mode 100644
index 000000000..0b32acbd2
--- /dev/null
+++ b/doc/how_to_add_docs.rst
@@ -0,0 +1,35 @@
+How to add or update docs
+=========================
+
+To add or update a documentation page, you need to create or modify
+an ``.rst`` file in the ``/doc`` directory and send a patch for
+review.
+
+People who are registered in MAINTAINERS file for doc/ directory will
+be automatically added to the patch as reviewers. However, you are
+very welcome to add more reviewers who know the subject. In fact, it
+is always a good idea to add someone who has knowledge of the specific
+area you are documenting.
+
+We are using Sphinx doc engine for documentation (see
+https://www.sphinx-doc.org/) and reStructured Text format for content.
+reStructuredText Primer page has more details
+https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#restructuredtext-primer
+
+Brand new page needs to be added to the appropriate ``index.rst`` file
+under ``/doc`` directory (that could be a root index file or nested one).
+
+To test your changes, build flashrom with documentation and open
+generated ``.html`` file in the browser. Generated ``.html`` files are
+in meson ``builddir/doc/html`` directory.
+
+Misc questions
+--------------
+
+* We use CC-BY-4.0 license for documentation.
+* Writing style can be formal or informal, it's mostly up to you, the
+ important thing is to make the text clear, readable and unambiguous. You
+ can insert images if this really helps the readers to understand the
+ instructions.
+* Documentation should be relevant to either flashrom usage or flashrom
+ development
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 000000000..194393434
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,22 @@
+.. flashrom documentation master file, created by
+ sphinx-quickstart on Mon Jan 30 17:34:19 2023.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+.. image:: logo/flashrom_logo.png
+ :alt: flashrom logo
+
+.. toctree::
+ :hidden:
+
+ dev_guide/index
+ classic_cli_manpage
+ contact
+ about_flashrom/index
+ how_to_add_docs
+ documentation_license
+ Old wiki website <https://wiki.flashrom.org/>
+
+.. include:: intro.rst
+
+.. include:: ../README.rst
diff --git a/doc/intro.rst b/doc/intro.rst
new file mode 100644
index 000000000..b1fe99aed
--- /dev/null
+++ b/doc/intro.rst
@@ -0,0 +1,34 @@
+**flashrom** is a utility for identifying, reading, writing, verifying and erasing flash
+chips. It is designed to flash BIOS/EFI/coreboot/firmware/optionROM images on mainboards,
+network/graphics/storage controller cards, and various other programmer devices.
+
+* Supports more than 476 flash chips, 291 chipsets, 500 mainboards, 79 PCI devices,
+ 17 USB devices and various parallel/serial port-based programmers.
+* Supports parallel, LPC, FWH and SPI flash interfaces and various chip packages (DIP32,
+ PLCC32, DIP8, SO8/SOIC8, TSOP32, TSOP40, TSOP48, BGA and more).
+* No physical access needed, root access is sufficient (not needed for some programmers).
+* No bootable floppy disk, bootable CD-ROM or other media needed.
+* No keyboard or monitor needed. Simply reflash remotely via SSH.
+* No instant reboot needed. Reflash your chip in a running system, verify it, be happy.
+ The new firmware will be present next time you boot.
+* Crossflashing and hotflashing is possible as long as the flash chips are electrically
+ and logically compatible (same protocol). Great for recovery.
+* Scriptability. Reflash a whole pool of identical machines at the same time from the
+ command line. It is recommended to check flashrom output and error codes.
+* Speed. flashrom is often much faster than most vendor flash tools.
+* Portability. Supports DOS, Linux, FreeBSD (including Debian/kFreeBSD), NetBSD, OpenBSD,
+ DragonFlyBSD, anything Solaris-like, Mac OS X, and other Unix-like OSes as well as GNU Hurd.
+ Partial Windows support is available (no internal programmer support at the moment, hence
+ no "BIOS flashing").
+
+.. todo:: Convert Technology page and add links here
+
+.. container:: danger, admonition
+
+ **Emergency help**
+
+ IMPORTANT: If something went wrong during flashing, do NOT turn off/reboot your computer.
+ Instead, let us help you recover. We can be contacted via `IRC <https://www.flashrom.org/contact.html#irc>`_
+ (#flashrom on `libera.chat <irc://irc.libera.chat/#flashrom>`_, `webchat <https://web.libera.chat/#flashrom>`_),
+ `Discord <https://www.flashrom.org/contact.html#discord>`_, or `email <https://www.flashrom.org/contact.html#mailing-list-1>`_.
+ Please allow some time until someone responds, we're all volunteers.
diff --git a/doc/logo/COPYING b/doc/logo/COPYING
new file mode 100644
index 000000000..3a7d190ce
--- /dev/null
+++ b/doc/logo/COPYING
@@ -0,0 +1,12 @@
+The flashrom logo and icons in this directory were originally designed by Stefan Tauner in 2015.
+The lettering is based on the "Free Mono" font of the GNU FreeFont family.
+The SOIC chip seen in the lettering is based on the SOIC08 narrow STL CAD file from
+https://grabcad.com/library/soic-package-narrow-8-10-14-and-16-pins-1
+It was rendered by Blender with the Freestyle SVG plugin from
+https://github.com/hvfrancesco/freestylesvg
+
+All source image files within this directory (i.e. all with names ending with ".svg" or ."xcf")
+are licensed under the Creative Commons Attribution-NoDerivatives 4.0 license (CC BY-ND 4.0):
+http://creativecommons.org/licenses/by-nd/4.0/
+All image files produced from the source image files mentioned above and included in this
+directory are in the public domain.
diff --git a/doc/logo/flashrom_icon_bw.svg b/doc/logo/flashrom_icon_bw.svg
new file mode 100644
index 000000000..e19996e41
--- /dev/null
+++ b/doc/logo/flashrom_icon_bw.svg
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="96"
+ height="96"
+ id="svg21522"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="icon_bw.svg">
+ <defs
+ id="defs21524" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.8"
+ inkscape:cx="23.338046"
+ inkscape:cy="19.084347"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1440"
+ inkscape:window-height="852"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata21527">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-333.45093,-481.36112)">
+ <g
+ transform="matrix(1.2696942,0,0,1.2696942,204.20918,-1154.3652)"
+ id="g12303"
+ style="fill:#000000;stroke:#000000">
+ <g
+ transform="matrix(0.13886967,0,0,0.13886967,104.44891,1294.8775)"
+ id="g12305"
+ style="fill:#000000;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none">
+ <g
+ id="g12307"
+ style="fill:#000000;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ id="path12309"
+ style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 36.348,200.079 35.356,199.696 33.542,198.325 31.551,196.241 29.469,193.538 19.232,179.015 19.232,171.356 44.187,159.553 48.591,165.801 62.175,159.377 63.406,159.179 64.962,159.78 66.775,161.151 68.766,163.235 69.191,163.786 48.641,173.506 46.369,178.415 44.048,183.434 43.931,183.346 43.413,183.146 43.003,183.212 42.719,183.54 42.629,183.847 41.378,189.206 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ <path
+ id="path12311"
+ style="fill:#000000;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 37.22,171.179 38.451,170.982 40.007,171.582 41.82,172.953 43.811,175.037 45.894,177.74 46.369,178.415 M 48.591,165.801 44.542,167.716 37.22,171.179 36.369,172.164 36.072,173.044 32.752,187.405 32.644,187.738 32.421,187.995 32.36,188.066 31.95,188.132 31.431,187.932 30.827,187.475 30.163,186.78 29.469,185.879 19.232,171.356"
+ inkscape:connector-curvature="0" />
+ </g>
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use12317"
+ id="use12313"
+ transform="translate(154.597,-73.115)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#000000;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <path
+ d="M 295.432,338.349 270.478,350.151 270.478,357.81 270.478,357.81"
+ id="path12315"
+ inkscape:connector-curvature="0"
+ style="fill:#000000;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#g12307"
+ id="use12317"
+ transform="translate(77.299,-36.558)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#000000;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use12317"
+ id="use12319"
+ transform="translate(77.299,-36.557)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#000000;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <path
+ id="path12321"
+ style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 470.724,263.106 470.724,255.446 458.67236,222.67498 330.137,40.374 301.087,54.113 276.133,65.915 266.306,70.563 259.617,73.726 255.569,75.641 223.789,90.671 198.834,102.473 189.007,107.121 182.318,110.284 178.27,112.199 146.49,127.229 121.535,139.031 111.708,143.678 105.02,146.842 100.971,148.756 69.191,163.786 48.641,173.506 46.369,178.415 44.048,183.434 41.378,189.206 36.348,200.079 35.436,202.05 35.436,209.71 48.641,244.051 176.023,424.782 204.78,411.1635 233.185,397.747 282.086,374.62 310.484,361.189 359.384,338.062 387.783,324.632 436.683,301.5045 457.519,291.65 461.875,282.234 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ id="path12323"
+ style="color:#000000;fill:#000000;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 177.17536,355.80598 48.641,173.506 69.191,163.786 100.971,148.756 105.02,146.842 111.708,143.678 121.535,139.031 146.49,127.229 178.27,112.199 182.318,110.284 189.007,107.121 198.834,102.473 223.789,90.671 255.569,75.641 259.617,73.726 266.306,70.563 276.133,65.915 301.087,54.113 330.137,40.374 458.67236,222.67498 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ style="fill:#000000;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 177.17537,355.80588 174.054,377.75 172.485,396.496 172.485,404.155 176.023,424.782"
+ id="path12325"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <g
+ id="g12327"
+ style="fill:#000000;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccc"
+ style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ id="path12329"
+ d="M 193.179,386.709 193.179,394.368 193.179,394.368 203.415,408.892 204.109,409.96 204.78,411.1635 205.378,412.407 205.896,413.679 206.306,414.908 206.59,416.042 206.6795,416.6025 210.0465,440.505 210.315,442.186 211.167,445.588 212.398,449.277 213.953,453.092 215.767,456.865 217.758,460.433 219.84,463.638 230.077,478.162 255.031,466.36 255.031,458.7 244.795,444.177 244.101,443.108 243.437,441.919 242.833,440.661 242.314,439.39 241.904,438.16 241.62,437.026 241.54,436.479 238.1635,412.5635 237.895,410.883 237.043,407.48 235.812,403.791 234.257,399.977 233.185,397.747 232.443,396.203 230.452,392.635 228.37,389.43 222.182,380.651 218.133,374.907 z" />
+ <path
+ id="path12331"
+ style="fill:#000000;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 230.077,470.503 219.84,455.979 219.146,454.911 218.482,453.721 217.878,452.464 217.359,451.192 216.949,449.962 216.585,448.281 241.54,436.479 M 230.077,478.162 230.077,470.503 255.031,458.7 M 193.179,386.709 197.228,392.453 203.415,401.232 205.497,404.438 207.489,408.005 208.231,409.549 209.302,411.779 210.858,415.593 212.088,419.282 212.94,422.685 213.181,424.326 M 216.566,448.255 213.236,424.405 238.1635,412.5635"
+ inkscape:connector-curvature="0" />
+ </g>
+ <use
+ x="0"
+ y="0"
+ xlink:href="#g12327"
+ id="use12333"
+ transform="translate(77.299,-36.558)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#000000;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use12333"
+ id="use12335"
+ transform="translate(77.299,-36.558)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#000000;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use12335"
+ id="use12337"
+ transform="translate(77.299,-36.557)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#000000;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ </g>
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:3.15029216;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:1;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
+ d="M 165.76732,1292.3883 122.72375,1325.3334 C 122.18981,1325.7603 122.54984,1326.8129 123.23329,1326.8232 L 137.89036,1326.8232 112.29955,1356.1484 C 111.65153,1356.8444 112.65899,1357.948 113.40992,1357.3899 L 163.61186,1322.1186 C 164.18093,1321.7099 163.82914,1320.6063 163.12863,1320.6027 L 147.80532,1320.6027 166.95604,1293.5383 C 167.4597,1292.8418 166.4987,1291.8171 165.76732,1292.3883 z"
+ id="path12339"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccc" />
+ </g>
+ </g>
+</svg>
diff --git a/doc/logo/flashrom_icon_color-128x128.png b/doc/logo/flashrom_icon_color-128x128.png
new file mode 100644
index 000000000..0c1f50caf
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-128x128.png
Binary files differ
diff --git a/doc/logo/flashrom_icon_color-16x16.ico b/doc/logo/flashrom_icon_color-16x16.ico
new file mode 100644
index 000000000..6c8c777db
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-16x16.ico
Binary files differ
diff --git a/doc/logo/flashrom_icon_color-16x16.png b/doc/logo/flashrom_icon_color-16x16.png
new file mode 100644
index 000000000..fd977bb64
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-16x16.png
Binary files differ
diff --git a/doc/logo/flashrom_icon_color-16x16.xcf b/doc/logo/flashrom_icon_color-16x16.xcf
new file mode 100644
index 000000000..5a2785b9d
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-16x16.xcf
Binary files differ
diff --git a/doc/logo/flashrom_icon_color-256x256.png b/doc/logo/flashrom_icon_color-256x256.png
new file mode 100644
index 000000000..62d0b080b
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-256x256.png
Binary files differ
diff --git a/doc/logo/flashrom_icon_color-32x32.ico b/doc/logo/flashrom_icon_color-32x32.ico
new file mode 100644
index 000000000..d070e70a1
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-32x32.ico
Binary files differ
diff --git a/doc/logo/flashrom_icon_color-32x32.png b/doc/logo/flashrom_icon_color-32x32.png
new file mode 100644
index 000000000..d400d9a02
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-32x32.png
Binary files differ
diff --git a/doc/logo/flashrom_icon_color-32x32.xcf b/doc/logo/flashrom_icon_color-32x32.xcf
new file mode 100644
index 000000000..16c5e3907
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-32x32.xcf
Binary files differ
diff --git a/doc/logo/flashrom_icon_color-64x64.png b/doc/logo/flashrom_icon_color-64x64.png
new file mode 100644
index 000000000..1ee7d55c0
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-64x64.png
Binary files differ
diff --git a/doc/logo/flashrom_icon_color-64x64.xcf b/doc/logo/flashrom_icon_color-64x64.xcf
new file mode 100644
index 000000000..7c1d7503e
--- /dev/null
+++ b/doc/logo/flashrom_icon_color-64x64.xcf
Binary files differ
diff --git a/doc/logo/flashrom_icon_color.svg b/doc/logo/flashrom_icon_color.svg
new file mode 100644
index 000000000..07f0fc683
--- /dev/null
+++ b/doc/logo/flashrom_icon_color.svg
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="96"
+ height="96"
+ id="svg21522"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="icon_color.svg"
+ inkscape:export-filename="icon_color-256x256.png"
+ inkscape:export-xdpi="240"
+ inkscape:export-ydpi="240">
+ <defs
+ id="defs21524" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="7.1666667"
+ inkscape:cx="48"
+ inkscape:cy="48"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1440"
+ inkscape:window-height="852"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata21527">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-333.45093,-481.36112)">
+ <g
+ id="g12283"
+ transform="matrix(1.2696942,0,0,1.2696942,204.20918,-1154.3652)">
+ <g
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g4439-7"
+ transform="matrix(0.13886967,0,0,0.13886967,104.44891,1294.8775)">
+ <g
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g4441-0">
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ d="M 36.348,200.079 35.356,199.696 33.542,198.325 31.551,196.241 29.469,193.538 19.232,179.015 19.232,171.356 44.187,159.553 48.591,165.801 62.175,159.377 63.406,159.179 64.962,159.78 66.775,161.151 68.766,163.235 69.191,163.786 48.641,173.506 46.369,178.415 44.048,183.434 43.931,183.346 43.413,183.146 43.003,183.212 42.719,183.54 42.629,183.847 41.378,189.206 z"
+ style="color:#000000;fill:#cacaca;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4443-3" />
+ <path
+ inkscape:connector-curvature="0"
+ d="M 37.22,171.179 38.451,170.982 40.007,171.582 41.82,172.953 43.811,175.037 45.894,177.74 46.369,178.415 M 48.591,165.801 44.542,167.716 37.22,171.179 36.369,172.164 36.072,173.044 32.752,187.405 32.644,187.738 32.421,187.995 32.36,188.066 31.95,188.132 31.431,187.932 30.827,187.475 30.163,186.78 29.469,185.879 19.232,171.356"
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ id="path4445-4" />
+ </g>
+ <use
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none"
+ height="499.08807"
+ width="1476.6688"
+ transform="translate(154.597,-73.115)"
+ id="use4447-1"
+ xlink:href="#use4451-9"
+ y="0"
+ x="0" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ inkscape:connector-curvature="0"
+ id="path4449-2"
+ d="M 295.432,338.349 270.478,350.151 270.478,357.81 270.478,357.81" />
+ <use
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none"
+ height="499.08807"
+ width="1476.6688"
+ transform="translate(77.299,-36.558)"
+ id="use4451-9"
+ xlink:href="#g4441-0"
+ y="0"
+ x="0" />
+ <use
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none"
+ height="499.08807"
+ width="1476.6688"
+ transform="translate(77.299,-36.557)"
+ id="use4453-0"
+ xlink:href="#use4451-9"
+ y="0"
+ x="0" />
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ d="M 470.724,263.106 470.724,255.446 458.67236,222.67498 330.137,40.374 301.087,54.113 276.133,65.915 266.306,70.563 259.617,73.726 255.569,75.641 223.789,90.671 198.834,102.473 189.007,107.121 182.318,110.284 178.27,112.199 146.49,127.229 121.535,139.031 111.708,143.678 105.02,146.842 100.971,148.756 69.191,163.786 48.641,173.506 46.369,178.415 44.048,183.434 41.378,189.206 36.348,200.079 35.436,202.05 35.436,209.71 48.641,244.051 176.023,424.782 204.78,411.1635 233.185,397.747 282.086,374.62 310.484,361.189 359.384,338.062 387.783,324.632 436.683,301.5045 457.519,291.65 461.875,282.234 z"
+ style="color:#000000;fill:#262626;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4455-5" />
+ <path
+ sodipodi:nodetypes="ccccccccccccccccccccc"
+ inkscape:connector-curvature="0"
+ d="M 177.17536,355.80598 48.641,173.506 69.191,163.786 100.971,148.756 105.02,146.842 111.708,143.678 121.535,139.031 146.49,127.229 178.27,112.199 182.318,110.284 189.007,107.121 198.834,102.473 223.789,90.671 255.569,75.641 259.617,73.726 266.306,70.563 276.133,65.915 301.087,54.113 330.137,40.374 458.67236,222.67498 z"
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4457-6" />
+ <path
+ sodipodi:nodetypes="ccccc"
+ inkscape:connector-curvature="0"
+ id="path4459-5"
+ d="M 177.17537,355.80588 174.054,377.75 172.485,396.496 172.485,404.155 176.023,424.782"
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none" />
+ <g
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none"
+ id="g4461-2">
+ <path
+ d="M 193.179,386.709 193.179,394.368 193.179,394.368 203.415,408.892 204.109,409.96 204.78,411.1635 205.378,412.407 205.896,413.679 206.306,414.908 206.59,416.042 206.6795,416.6025 210.0465,440.505 210.315,442.186 211.167,445.588 212.398,449.277 213.953,453.092 215.767,456.865 217.758,460.433 219.84,463.638 230.077,478.162 255.031,466.36 255.031,458.7 244.795,444.177 244.101,443.108 243.437,441.919 242.833,440.661 242.314,439.39 241.904,438.16 241.62,437.026 241.54,436.479 238.1635,412.5635 237.895,410.883 237.043,407.48 235.812,403.791 234.257,399.977 233.185,397.747 232.443,396.203 230.452,392.635 228.37,389.43 222.182,380.651 218.133,374.907 z"
+ id="path4463-0"
+ inkscape:connector-curvature="0"
+ style="color:#000000;fill:#cacaca;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ d="M 230.077,470.503 219.84,455.979 219.146,454.911 218.482,453.721 217.878,452.464 217.359,451.192 216.949,449.962 216.585,448.281 241.54,436.479 M 230.077,478.162 230.077,470.503 255.031,458.7 M 193.179,386.709 197.228,392.453 203.415,401.232 205.497,404.438 207.489,408.005 208.231,409.549 209.302,411.779 210.858,415.593 212.088,419.282 212.94,422.685 213.181,424.326 M 216.566,448.255 213.236,424.405 238.1635,412.5635"
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ id="path4465-1" />
+ </g>
+ <use
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none"
+ height="499.08807"
+ width="1476.6688"
+ transform="translate(77.299,-36.558)"
+ id="use4467-4"
+ xlink:href="#g4461-2"
+ y="0"
+ x="0" />
+ <use
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none"
+ height="499.08807"
+ width="1476.6688"
+ transform="translate(77.299,-36.558)"
+ id="use4469-9"
+ xlink:href="#use4467-4"
+ y="0"
+ x="0" />
+ <use
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none"
+ height="499.08807"
+ width="1476.6688"
+ transform="translate(77.299,-36.557)"
+ id="use4471-6"
+ xlink:href="#use4469-9"
+ y="0"
+ x="0" />
+ </g>
+ <path
+ sodipodi:nodetypes="ccccccccccc"
+ inkscape:connector-curvature="0"
+ id="path8553-4"
+ d="M 165.76732,1292.3883 122.72375,1325.3334 C 122.18981,1325.7603 122.54984,1326.8129 123.23329,1326.8232 L 137.89036,1326.8232 112.29955,1356.1484 C 111.65153,1356.8444 112.65899,1357.948 113.40992,1357.3899 L 163.61186,1322.1186 C 164.18093,1321.7099 163.82914,1320.6063 163.12863,1320.6027 L 147.80532,1320.6027 166.95604,1293.5383 C 167.4597,1292.8418 166.4987,1291.8171 165.76732,1292.3883 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffff37;fill-opacity:1;fill-rule:nonzero;stroke:#4e4ad4;stroke-width:3.15029216;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:1;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" />
+ </g>
+ </g>
+</svg>
diff --git a/doc/logo/flashrom_icon_gray.svg b/doc/logo/flashrom_icon_gray.svg
new file mode 100644
index 000000000..f334b4455
--- /dev/null
+++ b/doc/logo/flashrom_icon_gray.svg
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="96"
+ height="96"
+ id="svg21522"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="icon_gray.svg">
+ <defs
+ id="defs21524" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.8"
+ inkscape:cx="23.338046"
+ inkscape:cy="19.084347"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1440"
+ inkscape:window-height="852"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata21527">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-333.45093,-481.36112)">
+ <g
+ transform="matrix(1.2696942,0,0,1.2696942,204.20918,-1154.3652)"
+ id="g12341">
+ <g
+ transform="matrix(0.13886967,0,0,0.13886967,104.44891,1294.8775)"
+ id="g12343"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none">
+ <g
+ id="g12345"
+ style="fill:#cacaca;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ id="path12347"
+ style="color:#000000;fill:#cacaca;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 36.348,200.079 35.356,199.696 33.542,198.325 31.551,196.241 29.469,193.538 19.232,179.015 19.232,171.356 44.187,159.553 48.591,165.801 62.175,159.377 63.406,159.179 64.962,159.78 66.775,161.151 68.766,163.235 69.191,163.786 48.641,173.506 46.369,178.415 44.048,183.434 43.931,183.346 43.413,183.146 43.003,183.212 42.719,183.54 42.629,183.847 41.378,189.206 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ <path
+ id="path12349"
+ style="fill:#cacaca;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 37.22,171.179 38.451,170.982 40.007,171.582 41.82,172.953 43.811,175.037 45.894,177.74 46.369,178.415 M 48.591,165.801 44.542,167.716 37.22,171.179 36.369,172.164 36.072,173.044 32.752,187.405 32.644,187.738 32.421,187.995 32.36,188.066 31.95,188.132 31.431,187.932 30.827,187.475 30.163,186.78 29.469,185.879 19.232,171.356"
+ inkscape:connector-curvature="0" />
+ </g>
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use12355"
+ id="use12351"
+ transform="translate(154.597,-73.115)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#cacaca;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <path
+ d="M 295.432,338.349 270.478,350.151 270.478,357.81 270.478,357.81"
+ id="path12353"
+ inkscape:connector-curvature="0"
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#g12345"
+ id="use12355"
+ transform="translate(77.299,-36.558)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#cacaca;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use12355"
+ id="use12357"
+ transform="translate(77.299,-36.557)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#cacaca;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <path
+ id="path12359"
+ style="color:#000000;fill:#262626;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 470.724,263.106 470.724,255.446 458.67236,222.67498 330.137,40.374 301.087,54.113 276.133,65.915 266.306,70.563 259.617,73.726 255.569,75.641 223.789,90.671 198.834,102.473 189.007,107.121 182.318,110.284 178.27,112.199 146.49,127.229 121.535,139.031 111.708,143.678 105.02,146.842 100.971,148.756 69.191,163.786 48.641,173.506 46.369,178.415 44.048,183.434 41.378,189.206 36.348,200.079 35.436,202.05 35.436,209.71 48.641,244.051 176.023,424.782 204.78,411.1635 233.185,397.747 282.086,374.62 310.484,361.189 359.384,338.062 387.783,324.632 436.683,301.5045 457.519,291.65 461.875,282.234 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ id="path12361"
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 177.17536,355.80598 48.641,173.506 69.191,163.786 100.971,148.756 105.02,146.842 111.708,143.678 121.535,139.031 146.49,127.229 178.27,112.199 182.318,110.284 189.007,107.121 198.834,102.473 223.789,90.671 255.569,75.641 259.617,73.726 266.306,70.563 276.133,65.915 301.087,54.113 330.137,40.374 458.67236,222.67498 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 177.17537,355.80588 174.054,377.75 172.485,396.496 172.485,404.155 176.023,424.782"
+ id="path12363"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <g
+ id="g12365"
+ style="fill:#cacaca;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccc"
+ style="color:#000000;fill:#cacaca;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ id="path12367"
+ d="M 193.179,386.709 193.179,394.368 193.179,394.368 203.415,408.892 204.109,409.96 204.78,411.1635 205.378,412.407 205.896,413.679 206.306,414.908 206.59,416.042 206.6795,416.6025 210.0465,440.505 210.315,442.186 211.167,445.588 212.398,449.277 213.953,453.092 215.767,456.865 217.758,460.433 219.84,463.638 230.077,478.162 255.031,466.36 255.031,458.7 244.795,444.177 244.101,443.108 243.437,441.919 242.833,440.661 242.314,439.39 241.904,438.16 241.62,437.026 241.54,436.479 238.1635,412.5635 237.895,410.883 237.043,407.48 235.812,403.791 234.257,399.977 233.185,397.747 232.443,396.203 230.452,392.635 228.37,389.43 222.182,380.651 218.133,374.907 z" />
+ <path
+ id="path12369"
+ style="fill:#cacaca;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 230.077,470.503 219.84,455.979 219.146,454.911 218.482,453.721 217.878,452.464 217.359,451.192 216.949,449.962 216.585,448.281 241.54,436.479 M 230.077,478.162 230.077,470.503 255.031,458.7 M 193.179,386.709 197.228,392.453 203.415,401.232 205.497,404.438 207.489,408.005 208.231,409.549 209.302,411.779 210.858,415.593 212.088,419.282 212.94,422.685 213.181,424.326 M 216.566,448.255 213.236,424.405 238.1635,412.5635"
+ inkscape:connector-curvature="0" />
+ </g>
+ <use
+ x="0"
+ y="0"
+ xlink:href="#g12365"
+ id="use12371"
+ transform="translate(77.299,-36.558)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#cacaca;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use12371"
+ id="use12373"
+ transform="translate(77.299,-36.558)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#cacaca;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use12373"
+ id="use12375"
+ transform="translate(77.299,-36.557)"
+ width="1476.6688"
+ height="499.08807"
+ style="fill:#cacaca;stroke:#000000;stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ </g>
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ababab;stroke-width:3.15029216;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:1;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
+ d="M 165.76732,1292.3883 122.72375,1325.3334 C 122.18981,1325.7603 122.54984,1326.8129 123.23329,1326.8232 L 137.89036,1326.8232 112.29955,1356.1484 C 111.65153,1356.8444 112.65899,1357.948 113.40992,1357.3899 L 163.61186,1322.1186 C 164.18093,1321.7099 163.82914,1320.6063 163.12863,1320.6027 L 147.80532,1320.6027 166.95604,1293.5383 C 167.4597,1292.8418 166.4987,1291.8171 165.76732,1292.3883 z"
+ id="path12377"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccc" />
+ </g>
+ </g>
+</svg>
diff --git a/doc/logo/flashrom_logo.png b/doc/logo/flashrom_logo.png
new file mode 100644
index 000000000..6f201a868
--- /dev/null
+++ b/doc/logo/flashrom_logo.png
Binary files differ
diff --git a/doc/logo/flashrom_logo.svg b/doc/logo/flashrom_logo.svg
new file mode 100644
index 000000000..b4ee6b75f
--- /dev/null
+++ b/doc/logo/flashrom_logo.svg
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="510"
+ height="90"
+ id="svg22342"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="flashrom_logo.svg">
+ <defs
+ id="defs22344" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.979899"
+ inkscape:cx="228.11024"
+ inkscape:cy="113.21682"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="2"
+ fit-margin-left="2"
+ fit-margin-right="2"
+ fit-margin-bottom="2"
+ inkscape:window-width="1440"
+ inkscape:window-height="852"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata22347">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(403.42828,-847.45728)">
+ <g
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="flashrom_logo.png"
+ id="g8517"
+ transform="matrix(1.4701023,0,0,1.4701023,1864.4331,1055.0748)">
+ <text
+ sodipodi:linespacing="125%"
+ id="text8555"
+ y="-92.549721"
+ x="-1544.792"
+ style="font-size:64px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;color:#000000;fill:#4e4ad4;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.0203371;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:1;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold Italic"
+ xml:space="preserve"><tspan
+ style="font-size:72px;font-style:italic;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#4e4ad4;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1.0203371;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:1;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold Italic"
+ y="-92.549721"
+ x="-1544.792"
+ id="tspan8557"
+ sodipodi:role="line"
+ dx="0 -5.1513548 -2.7801955 0 5.6434536 0 -2.1592376 1.6638348">fla hrom</tspan></text>
+ <g
+ transform="matrix(0.09446259,0,0,0.09446259,-1422.8187,-128.5835)"
+ id="g4439"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none">
+ <g
+ id="g4441"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ id="path4443"
+ style="color:#000000;fill:#cacaca;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 36.348,200.079 35.356,199.696 33.542,198.325 31.551,196.241 29.469,193.538 19.232,179.015 19.232,171.356 44.187,159.553 48.591,165.801 62.175,159.377 63.406,159.179 64.962,159.78 66.775,161.151 68.766,163.235 69.191,163.786 48.641,173.506 46.369,178.415 44.048,183.434 43.931,183.346 43.413,183.146 43.003,183.212 42.719,183.54 42.629,183.847 41.378,189.206 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccc" />
+ <path
+ id="path4445"
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 37.22,171.179 38.451,170.982 40.007,171.582 41.82,172.953 43.811,175.037 45.894,177.74 46.369,178.415 M 48.591,165.801 44.542,167.716 37.22,171.179 36.369,172.164 36.072,173.044 32.752,187.405 32.644,187.738 32.421,187.995 32.36,188.066 31.95,188.132 31.431,187.932 30.827,187.475 30.163,186.78 29.469,185.879 19.232,171.356"
+ inkscape:connector-curvature="0" />
+ </g>
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use4451"
+ id="use4447"
+ transform="translate(154.597,-73.115)"
+ width="1476.6688"
+ height="499.08807"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <path
+ d="M 295.432,338.349 270.478,350.151 270.478,357.81 270.478,357.81"
+ id="path4449"
+ inkscape:connector-curvature="0"
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#g4441"
+ id="use4451"
+ transform="translate(77.299,-36.558)"
+ width="1476.6688"
+ height="499.08807"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use4451"
+ id="use4453"
+ transform="translate(77.299,-36.557)"
+ width="1476.6688"
+ height="499.08807"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <path
+ id="path4455"
+ style="color:#000000;fill:#262626;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 470.724,263.106 470.724,255.446 458.67236,222.67498 330.137,40.374 301.087,54.113 276.133,65.915 266.306,70.563 259.617,73.726 255.569,75.641 223.789,90.671 198.834,102.473 189.007,107.121 182.318,110.284 178.27,112.199 146.49,127.229 121.535,139.031 111.708,143.678 105.02,146.842 100.971,148.756 69.191,163.786 48.641,173.506 46.369,178.415 44.048,183.434 41.378,189.206 36.348,200.079 35.436,202.05 35.436,209.71 48.641,244.051 176.023,424.782 204.78,411.1635 233.185,397.747 282.086,374.62 310.484,361.189 359.384,338.062 387.783,324.632 436.683,301.5045 457.519,291.65 461.875,282.234 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccc" />
+ <path
+ id="path4457"
+ style="color:#000000;fill:none;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="M 177.17536,355.80598 48.641,173.506 69.191,163.786 100.971,148.756 105.02,146.842 111.708,143.678 121.535,139.031 146.49,127.229 178.27,112.199 182.318,110.284 189.007,107.121 198.834,102.473 223.789,90.671 255.569,75.641 259.617,73.726 266.306,70.563 276.133,65.915 301.087,54.113 330.137,40.374 458.67236,222.67498 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 177.17537,355.80588 174.054,377.75 172.485,396.496 172.485,404.155 176.023,424.782"
+ id="path4459"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <g
+ id="g4461"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none">
+ <path
+ sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccccc"
+ style="color:#000000;fill:#cacaca;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.60049891;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ inkscape:connector-curvature="0"
+ id="path4463"
+ d="M 193.179,386.709 193.179,394.368 193.179,394.368 203.415,408.892 204.109,409.96 204.78,411.1635 205.378,412.407 205.896,413.679 206.306,414.908 206.59,416.042 206.6795,416.6025 210.0465,440.505 210.315,442.186 211.167,445.588 212.398,449.277 213.953,453.092 215.767,456.865 217.758,460.433 219.84,463.638 230.077,478.162 255.031,466.36 255.031,458.7 244.795,444.177 244.101,443.108 243.437,441.919 242.833,440.661 242.314,439.39 241.904,438.16 241.62,437.026 241.54,436.479 238.1635,412.5635 237.895,410.883 237.043,407.48 235.812,403.791 234.257,399.977 233.185,397.747 232.443,396.203 230.452,392.635 228.37,389.43 222.182,380.651 218.133,374.907 z" />
+ <path
+ id="path4465"
+ style="fill:none;stroke:#000000;stroke-width:3.60049891;stroke-miterlimit:4;stroke-dasharray:none"
+ d="M 230.077,470.503 219.84,455.979 219.146,454.911 218.482,453.721 217.878,452.464 217.359,451.192 216.949,449.962 216.585,448.281 241.54,436.479 M 230.077,478.162 230.077,470.503 255.031,458.7 M 193.179,386.709 197.228,392.453 203.415,401.232 205.497,404.438 207.489,408.005 208.231,409.549 209.302,411.779 210.858,415.593 212.088,419.282 212.94,422.685 213.181,424.326 M 216.566,448.255 213.236,424.405 238.1635,412.5635"
+ inkscape:connector-curvature="0" />
+ </g>
+ <use
+ x="0"
+ y="0"
+ xlink:href="#g4461"
+ id="use4467"
+ transform="translate(77.299,-36.558)"
+ width="1476.6688"
+ height="499.08807"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use4467"
+ id="use4469"
+ transform="translate(77.299,-36.558)"
+ width="1476.6688"
+ height="499.08807"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ <use
+ x="0"
+ y="0"
+ xlink:href="#use4469"
+ id="use4471"
+ transform="translate(77.299,-36.557)"
+ width="1476.6688"
+ height="499.08807"
+ style="stroke-width:2.01414251;stroke-miterlimit:4;stroke-dasharray:none" />
+ </g>
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ffff37;fill-opacity:1;fill-rule:nonzero;stroke:#4e4ad4;stroke-width:2.04067421;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:1;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
+ d="M -1381.1084,-130.27672 -1410.3877,-107.86663 C -1410.7509,-107.57626 -1410.506,-106.8602 -1410.0411,-106.85324 L -1400.071,-106.85324 -1417.4785,-86.905494 C -1417.9193,-86.432034 -1417.234,-85.681363 -1416.7232,-86.060995 L -1382.5746,-110.05341 C -1382.1875,-110.33145 -1382.4268,-111.0821 -1382.9033,-111.08458 L -1393.3266,-111.08458 -1380.2998,-129.49445 C -1379.9572,-129.96822 -1380.6109,-130.66524 -1381.1084,-130.27672 z"
+ id="path8553"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccc" />
+ </g>
+ </g>
+</svg>
diff --git a/doc/meson.build b/doc/meson.build
new file mode 100644
index 000000000..aca73d8a9
--- /dev/null
+++ b/doc/meson.build
@@ -0,0 +1,36 @@
+
+sphinx = find_program('sphinx-build', native : true, required : get_option('man-pages').enabled() or get_option('documentation').enabled())
+
+man_pages = [
+ 'flashrom.8'
+]
+
+if sphinx.found()
+ if get_option('man-pages').auto() or get_option('man-pages').enabled()
+ man_outputs = []
+ foreach page : man_pages
+ man_outputs += 'man' + page.substring(-1)
+ endforeach
+
+ custom_target(
+ 'man-pages',
+ command : [sphinx, '-b', 'man', '-q', '-d', '@PRIVATE_DIR@', '-Drelease=' + flashrom_version,'@CURRENT_SOURCE_DIR@', '@OUTDIR@'],
+ build_always_stale : true, # sphinx handles rebuilds
+ output : man_outputs,
+ install : true,
+ install_dir : get_option('mandir'),
+ )
+ endif
+
+ if get_option('documentation').auto() or get_option('documentation').enabled()
+ custom_target(
+ 'documentation',
+ command : [sphinx, '-b', 'html', '-q', '-d', '@PRIVATE_DIR@', '-Drelease=' + flashrom_version,'@CURRENT_SOURCE_DIR@', '@OUTDIR@/html'],
+ build_always_stale : true, # sphinx handles rebuilds
+ output : 'html',
+ install : true,
+ install_dir : get_option('datadir') + '/doc/flashrom'
+ )
+ endif
+
+endif
diff --git a/drkaiser.c b/drkaiser.c
index ac49df304..ebf511915 100644
--- a/drkaiser.c
+++ b/drkaiser.c
@@ -17,7 +17,8 @@
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_DRKAISER 0x1803
@@ -29,38 +30,58 @@
/* Mask to restrict flash accesses to the 128kB memory window. */
#define DRKAISER_MEMMAP_MASK ((1 << 17) - 1)
-const struct dev_entry drkaiser_pcidev[] = {
+struct drkaiser_data {
+ struct pci_dev *dev;
+ uint8_t *bar;
+ uint16_t flash_access;
+};
+
+static const struct dev_entry drkaiser_pcidev[] = {
{0x1803, 0x5057, OK, "Dr. Kaiser", "PC-Waechter (Actel FPGA)"},
{0},
};
-static uint8_t *drkaiser_bar;
-
static void drkaiser_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr);
+ chipaddr addr)
+{
+ struct drkaiser_data *data = flash->mst->par.data;
+
+ pci_mmio_writeb(val, data->bar + (addr & DRKAISER_MEMMAP_MASK));
+}
+
static uint8_t drkaiser_chip_readb(const struct flashctx *flash,
- const chipaddr addr);
+ const chipaddr addr)
+{
+ struct drkaiser_data *data = flash->mst->par.data;
+
+ return pci_mmio_readb(data->bar + (addr & DRKAISER_MEMMAP_MASK));
+}
+
+static int drkaiser_shutdown(void *par_data)
+{
+ struct drkaiser_data *data = par_data;
+
+ /* Restore original flash writing state. */
+ pci_write_word(data->dev, PCI_MAGIC_DRKAISER_ADDR, data->flash_access);
+
+ free(par_data);
+ return 0;
+}
+
static const struct par_master par_master_drkaiser = {
- .chip_readb = drkaiser_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = drkaiser_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
+ .chip_readb = drkaiser_chip_readb,
+ .chip_writeb = drkaiser_chip_writeb,
+ .shutdown = drkaiser_shutdown,
};
-int drkaiser_init(void)
+static int drkaiser_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
uint32_t addr;
+ uint8_t *bar;
- if (rget_io_perms())
- return 1;
-
- dev = pcidev_init(drkaiser_pcidev, PCI_BASE_ADDRESS_2);
+ dev = pcidev_init(cfg, drkaiser_pcidev, PCI_BASE_ADDRESS_2);
if (!dev)
return 1;
@@ -68,28 +89,31 @@ int drkaiser_init(void)
if (!addr)
return 1;
- /* Write magic register to enable flash write. */
- rpci_write_word(dev, PCI_MAGIC_DRKAISER_ADDR, PCI_MAGIC_DRKAISER_VALUE);
-
/* Map 128kB flash memory window. */
- drkaiser_bar = rphysmap("Dr. Kaiser PC-Waechter flash memory", addr, DRKAISER_MEMMAP_SIZE);
- if (drkaiser_bar == ERROR_PTR)
+ bar = rphysmap("Dr. Kaiser PC-Waechter flash memory", addr, DRKAISER_MEMMAP_SIZE);
+ if (bar == ERROR_PTR)
return 1;
- max_rom_decode.parallel = 128 * 1024;
- register_par_master(&par_master_drkaiser, BUS_PARALLEL);
+ struct drkaiser_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
+ return 1;
+ }
+ data->dev = dev;
+ data->bar = bar;
- return 0;
-}
+ /* Write magic register to enable flash write. */
+ data->flash_access = pci_read_word(dev, PCI_MAGIC_DRKAISER_ADDR);
+ pci_write_word(dev, PCI_MAGIC_DRKAISER_ADDR, PCI_MAGIC_DRKAISER_VALUE);
-static void drkaiser_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- pci_mmio_writeb(val, drkaiser_bar + (addr & DRKAISER_MEMMAP_MASK));
-}
+ max_rom_decode.parallel = 128 * 1024;
-static uint8_t drkaiser_chip_readb(const struct flashctx *flash,
- const chipaddr addr)
-{
- return pci_mmio_readb(drkaiser_bar + (addr & DRKAISER_MEMMAP_MASK));
+ return register_par_master(&par_master_drkaiser, BUS_PARALLEL, data);
}
+
+const struct programmer_entry programmer_drkaiser = {
+ .name = "drkaiser",
+ .type = PCI,
+ .devs.dev = drkaiser_pcidev,
+ .init = drkaiser_init,
+};
diff --git a/dummyflasher.c b/dummyflasher.c
index 92c30ee27..cf4ca03b9 100644
--- a/dummyflasher.c
+++ b/dummyflasher.c
@@ -13,31 +13,22 @@
* GNU General Public License for more details.
*/
+#include <assert.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include "flash.h"
#include "chipdrivers.h"
#include "programmer.h"
#include "flashchips.h"
-
-/* Remove the #define below if you don't want SPI flash chip emulation. */
-#define EMULATE_SPI_CHIP 1
-
-#if EMULATE_SPI_CHIP
-#define EMULATE_CHIP 1
#include "spi.h"
-#endif
-
-#if EMULATE_CHIP
-#include <sys/types.h>
-#include <sys/stat.h>
-#endif
+#include "writeprotect.h"
-#if EMULATE_CHIP
-static uint8_t *flashchip_contents = NULL;
enum emu_chip {
EMULATE_NONE,
EMULATE_ST_M25P10_RES,
@@ -45,6 +36,7 @@ enum emu_chip {
EMULATE_SST_SST25VF032B,
EMULATE_MACRONIX_MX25L6436,
EMULATE_WINBOND_W25Q128FV,
+ EMULATE_SPANSION_S25FL128L,
EMULATE_VARIABLE_SIZE,
};
@@ -52,9 +44,15 @@ struct emu_data {
enum emu_chip emu_chip;
char *emu_persistent_image;
unsigned int emu_chip_size;
- int erase_to_zero;
- int emu_modified; /* is the image modified since reading it? */
- uint8_t emu_status;
+ /* Note: W25Q128FV doesn't change value of SR2 if it's not provided, but
+ * even its previous generations do, so don't forget to update
+ * WRSR code on enabling WRSR_EXT2 for more chips. */
+ bool emu_wrsr_ext2;
+ bool emu_wrsr_ext3;
+ bool erase_to_zero;
+ bool emu_modified; /* is the image modified since reading it? */
+ uint8_t emu_status[3];
+ uint8_t emu_status_len; /* number of emulated status registers */
/* If "freq" parameter is passed in from command line, commands will delay
* for this period before returning. */
unsigned long int delay_us;
@@ -69,9 +67,20 @@ struct emu_data {
unsigned char spi_ignorelist[256];
unsigned int spi_blacklist_size;
unsigned int spi_ignorelist_size;
+
+ bool hwwp; /* state of hardware write protection */
+ /* wp_start == wp_end when write-protection is disabled */
+ uint32_t wp_start;
+ uint32_t wp_end;
+
+ unsigned int spi_write_256_chunksize;
+ uint8_t *flashchip_contents;
+
+ /* An instance of this structure is shared between multiple masters, so
+ * store the number of references to clean up only once at shutdown time. */
+ uint8_t refs_cnt;
};
-#if EMULATE_SPI_CHIP
/* A legit complete SFDP table based on the MX25L6436E (rev. 1.8) datasheet. */
static const uint8_t sfdp_table[] = {
0x53, 0x46, 0x44, 0x50, // @0x00: SFDP signature
@@ -98,459 +107,100 @@ static const uint8_t sfdp_table[] = {
0xFF, 0xFF, 0xFF, 0xFF, // @0x54: Macronix parameter table end
};
-#endif
-#endif
-
-static unsigned int spi_write_256_chunksize = 256;
-
-static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr);
-static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf,
- unsigned int start, unsigned int len);
-static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
-static void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr);
-static void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr);
-static void dummy_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len);
-static uint8_t dummy_chip_readb(const struct flashctx *flash, const chipaddr addr);
-static uint16_t dummy_chip_readw(const struct flashctx *flash, const chipaddr addr);
-static uint32_t dummy_chip_readl(const struct flashctx *flash, const chipaddr addr);
-static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len);
-
-static struct spi_master spi_master_dummyflasher = {
- .features = SPI_MASTER_4BA,
- .max_data_read = MAX_DATA_READ_UNLIMITED,
- .max_data_write = MAX_DATA_UNSPECIFIED,
- .command = dummy_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = dummy_spi_write_256,
- .write_aai = default_spi_write_aai,
-};
-
-static struct par_master par_master_dummy = {
- .chip_readb = dummy_chip_readb,
- .chip_readw = dummy_chip_readw,
- .chip_readl = dummy_chip_readl,
- .chip_readn = dummy_chip_readn,
- .chip_writeb = dummy_chip_writeb,
- .chip_writew = dummy_chip_writew,
- .chip_writel = dummy_chip_writel,
- .chip_writen = dummy_chip_writen,
-};
-
-static enum chipbustype dummy_buses_supported = BUS_NONE;
-
-static int dummy_shutdown(void *data)
+static void *dummy_map(const char *descr, uintptr_t phys_addr, size_t len)
{
- msg_pspew("%s\n", __func__);
-#if EMULATE_CHIP
- struct emu_data *emu_data = (struct emu_data *)data;
- if (emu_data->emu_chip != EMULATE_NONE) {
- if (emu_data->emu_persistent_image && emu_data->emu_modified) {
- msg_pdbg("Writing %s\n", emu_data->emu_persistent_image);
- write_buf_to_file(flashchip_contents,
- emu_data->emu_chip_size,
- emu_data->emu_persistent_image);
- free(emu_data->emu_persistent_image);
- emu_data->emu_persistent_image = NULL;
- }
- free(flashchip_contents);
- }
-#endif
- return 0;
+ msg_pspew("%s: Mapping %s, 0x%zx bytes at 0x%0*" PRIxPTR "\n",
+ __func__, descr, len, PRIxPTR_WIDTH, phys_addr);
+ return (void *)phys_addr;
}
-int dummy_init(void)
+static void dummy_unmap(void *virt_addr, size_t len)
{
- char *bustext = NULL;
- char *tmp = NULL;
- unsigned int i;
-#if EMULATE_SPI_CHIP
- char *status = NULL;
- int size = -1; /* size for VARIABLE_SIZE chip device */
-#endif
-#if EMULATE_CHIP
- struct stat image_stat;
-#endif
-
- struct emu_data *data = calloc(1, sizeof(struct emu_data));
- if (!data) {
- msg_perr("Out of memory!\n");
- return 1;
- }
- data->emu_chip = EMULATE_NONE;
- data->delay_us = 0;
- spi_master_dummyflasher.data = data;
- par_master_dummy.data = data;
-
- msg_pspew("%s\n", __func__);
-
- bustext = extract_programmer_param("bus");
- msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
- if (!bustext)
- bustext = strdup("parallel+lpc+fwh+spi");
- /* Convert the parameters to lowercase. */
- tolower_string(bustext);
-
- dummy_buses_supported = BUS_NONE;
- if (strstr(bustext, "parallel")) {
- dummy_buses_supported |= BUS_PARALLEL;
- msg_pdbg("Enabling support for %s flash.\n", "parallel");
- }
- if (strstr(bustext, "lpc")) {
- dummy_buses_supported |= BUS_LPC;
- msg_pdbg("Enabling support for %s flash.\n", "LPC");
- }
- if (strstr(bustext, "fwh")) {
- dummy_buses_supported |= BUS_FWH;
- msg_pdbg("Enabling support for %s flash.\n", "FWH");
- }
- if (strstr(bustext, "spi")) {
- dummy_buses_supported |= BUS_SPI;
- msg_pdbg("Enabling support for %s flash.\n", "SPI");
- }
- if (dummy_buses_supported == BUS_NONE)
- msg_pdbg("Support for all flash bus types disabled.\n");
- free(bustext);
-
- tmp = extract_programmer_param("spi_write_256_chunksize");
- if (tmp) {
- spi_write_256_chunksize = atoi(tmp);
- free(tmp);
- if (spi_write_256_chunksize < 1) {
- msg_perr("invalid spi_write_256_chunksize\n");
- return 1;
- }
- }
+ msg_pspew("%s: Unmapping 0x%zx bytes at %p\n", __func__, len, virt_addr);
+}
- tmp = extract_programmer_param("spi_blacklist");
- if (tmp) {
- i = strlen(tmp);
- if (!strncmp(tmp, "0x", 2)) {
- i -= 2;
- memmove(tmp, tmp + 2, i + 1);
- }
- if ((i > 512) || (i % 2)) {
- msg_perr("Invalid SPI command blacklist length\n");
- free(tmp);
- return 1;
- }
- data->spi_blacklist_size = i / 2;
- for (i = 0; i < data->spi_blacklist_size * 2; i++) {
- if (!isxdigit((unsigned char)tmp[i])) {
- msg_perr("Invalid char \"%c\" in SPI command "
- "blacklist\n", tmp[i]);
- free(tmp);
- return 1;
- }
- }
- for (i = 0; i < data->spi_blacklist_size; i++) {
- unsigned int tmp2;
- /* SCNx8 is apparently not supported by MSVC (and thus
- * MinGW), so work around it with an extra variable
- */
- sscanf(tmp + i * 2, "%2x", &tmp2);
- data->spi_blacklist[i] = (uint8_t)tmp2;
- }
- msg_pdbg("SPI blacklist is ");
- for (i = 0; i < data->spi_blacklist_size; i++)
- msg_pdbg("%02x ", data->spi_blacklist[i]);
- msg_pdbg(", size %u\n", data->spi_blacklist_size);
- }
- free(tmp);
+static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
+{
+ struct emu_data *emu_data = flash->mst->spi.data;
+ return spi_write_chunked(flash, buf, start, len,
+ emu_data->spi_write_256_chunksize);
+}
- tmp = extract_programmer_param("spi_ignorelist");
- if (tmp) {
- i = strlen(tmp);
- if (!strncmp(tmp, "0x", 2)) {
- i -= 2;
- memmove(tmp, tmp + 2, i + 1);
- }
- if ((i > 512) || (i % 2)) {
- msg_perr("Invalid SPI command ignorelist length\n");
- free(tmp);
- return 1;
- }
- data->spi_ignorelist_size = i / 2;
- for (i = 0; i < data->spi_ignorelist_size * 2; i++) {
- if (!isxdigit((unsigned char)tmp[i])) {
- msg_perr("Invalid char \"%c\" in SPI command "
- "ignorelist\n", tmp[i]);
- free(tmp);
- return 1;
- }
- }
- for (i = 0; i < data->spi_ignorelist_size; i++) {
- unsigned int tmp2;
- /* SCNx8 is apparently not supported by MSVC (and thus
- * MinGW), so work around it with an extra variable
- */
- sscanf(tmp + i * 2, "%2x", &tmp2);
- data->spi_ignorelist[i] = (uint8_t)tmp2;
- }
- msg_pdbg("SPI ignorelist is ");
- for (i = 0; i < data->spi_ignorelist_size; i++)
- msg_pdbg("%02x ", data->spi_ignorelist[i]);
- msg_pdbg(", size %u\n", data->spi_ignorelist_size);
+static bool dummy_spi_probe_opcode(const struct flashctx *flash, uint8_t opcode)
+{
+ size_t i;
+ const struct emu_data *emu_data = flash->mst->spi.data;
+ for (i = 0; i < emu_data->spi_blacklist_size; i++) {
+ if (emu_data->spi_blacklist[i] == opcode)
+ return false;
}
- free(tmp);
-
- /* frequency to emulate in Hz (default), KHz, or MHz */
- tmp = extract_programmer_param("freq");
- if (tmp) {
- unsigned long int freq;
- char *units = tmp;
- char *end = tmp + strlen(tmp);
-
- errno = 0;
- freq = strtoul(tmp, &units, 0);
- if (errno) {
- msg_perr("Invalid frequency \"%s\", %s\n",
- tmp, strerror(errno));
- free(tmp);
- return 1;
- }
-
- if ((units > tmp) && (units < end)) {
- int units_valid = 0;
+ return true;
+}
- if (units < end - 3) {
- ;
- } else if (units == end - 2) {
- if (!strcasecmp(units, "hz"))
- units_valid = 1;
- } else if (units == end - 3) {
- if (!strcasecmp(units, "khz")) {
- freq *= 1000;
- units_valid = 1;
- } else if (!strcasecmp(units, "mhz")) {
- freq *= 1000000;
- units_valid = 1;
- }
- }
+static int probe_variable_size(struct flashctx *flash)
+{
+ const struct emu_data *emu_data = flash->mst->opaque.data;
- if (!units_valid) {
- msg_perr("Invalid units: %s\n", units);
- free(tmp);
- return 1;
- }
- }
+ /* Skip the probing if we don't emulate "variable size" chip. */
+ if (!emu_data || emu_data->emu_chip != EMULATE_VARIABLE_SIZE)
+ return 0;
- /* Assume we only work with bytes and transfer at 1 bit/Hz */
- data->delay_us = (1000000 * 8) / freq;
- }
- free(tmp);
+ flash->chip->total_size = emu_data->emu_chip_size / 1024;
+ msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
+ flash->chip->total_size);
-#if EMULATE_CHIP
-#if EMULATE_SPI_CHIP
- tmp = extract_programmer_param("size");
- if (tmp) {
- size = strtol(tmp, NULL, 10);
- if (size <= 0 || (size % 1024 != 0)) {
- msg_perr("%s: Chip size is not a multipler of 1024: %s\n",
- __func__, tmp);
- free(tmp);
- return 1;
- }
- free(tmp);
- }
-#endif
+ flash->chip->tested = TEST_OK_PREWB;
- tmp = extract_programmer_param("emulate");
- if (!tmp) {
- msg_pdbg("Not emulating any flash chip.\n");
- /* Nothing else to do. */
- goto dummy_init_out;
- }
-#if EMULATE_SPI_CHIP
- if (!strcmp(tmp, "M25P10.RES")) {
- data->emu_chip = EMULATE_ST_M25P10_RES;
- data->emu_chip_size = 128 * 1024;
- data->emu_max_byteprogram_size = 128;
- data->emu_max_aai_size = 0;
- data->emu_jedec_se_size = 0;
- data->emu_jedec_be_52_size = 0;
- data->emu_jedec_be_d8_size = 32 * 1024;
- data->emu_jedec_ce_60_size = 0;
- data->emu_jedec_ce_c7_size = data->emu_chip_size;
- msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
- "write)\n");
- }
- if (!strcmp(tmp, "SST25VF040.REMS")) {
- data->emu_chip = EMULATE_SST_SST25VF040_REMS;
- data->emu_chip_size = 512 * 1024;
- data->emu_max_byteprogram_size = 1;
- data->emu_max_aai_size = 0;
- data->emu_jedec_se_size = 4 * 1024;
- data->emu_jedec_be_52_size = 32 * 1024;
- data->emu_jedec_be_d8_size = 0;
- data->emu_jedec_ce_60_size = data->emu_chip_size;
- data->emu_jedec_ce_c7_size = 0;
- msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
- "byte write)\n");
- }
- if (!strcmp(tmp, "SST25VF032B")) {
- data->emu_chip = EMULATE_SST_SST25VF032B;
- data->emu_chip_size = 4 * 1024 * 1024;
- data->emu_max_byteprogram_size = 1;
- data->emu_max_aai_size = 2;
- data->emu_jedec_se_size = 4 * 1024;
- data->emu_jedec_be_52_size = 32 * 1024;
- data->emu_jedec_be_d8_size = 64 * 1024;
- data->emu_jedec_ce_60_size = data->emu_chip_size;
- data->emu_jedec_ce_c7_size = data->emu_chip_size;
- msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
- "write)\n");
- }
- if (!strcmp(tmp, "MX25L6436")) {
- data->emu_chip = EMULATE_MACRONIX_MX25L6436;
- data->emu_chip_size = 8 * 1024 * 1024;
- data->emu_max_byteprogram_size = 256;
- data->emu_max_aai_size = 0;
- data->emu_jedec_se_size = 4 * 1024;
- data->emu_jedec_be_52_size = 32 * 1024;
- data->emu_jedec_be_d8_size = 64 * 1024;
- data->emu_jedec_ce_60_size = data->emu_chip_size;
- data->emu_jedec_ce_c7_size = data->emu_chip_size;
- msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
- "SFDP)\n");
- }
- if (!strcmp(tmp, "W25Q128FV")) {
- data->emu_chip = EMULATE_WINBOND_W25Q128FV;
- data->emu_chip_size = 16 * 1024 * 1024;
- data->emu_max_byteprogram_size = 256;
- data->emu_max_aai_size = 0;
- data->emu_jedec_se_size = 4 * 1024;
- data->emu_jedec_be_52_size = 32 * 1024;
- data->emu_jedec_be_d8_size = 64 * 1024;
- data->emu_jedec_ce_60_size = data->emu_chip_size;
- data->emu_jedec_ce_c7_size = data->emu_chip_size;
- msg_pdbg("Emulating Winbond W25Q128FV SPI flash chip (RDID)\n");
- }
+ if (emu_data->erase_to_zero)
+ flash->chip->feature_bits |= FEATURE_ERASED_ZERO;
- /* The name of variable-size virtual chip. A 4 MiB flash example:
- * flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
+ /*
+ * Update the first count of the block_eraser.
+ * Opaque flash chip entry in flashchips.c has only one block eraser.
+ *
+ * If this changes in future, the code below needs to be adjusted
+ * to update all block erasers.
*/
- if (!strcmp(tmp, "VARIABLE_SIZE")) {
- if (size == -1) {
- msg_perr("%s: the size parameter is not given.\n", __func__);
- free(tmp);
- return 1;
- }
- data->emu_chip = EMULATE_VARIABLE_SIZE;
- data->emu_chip_size = size;
- data->emu_max_byteprogram_size = 256;
- data->emu_max_aai_size = 0;
- data->emu_jedec_se_size = 4 * 1024;
- data->emu_jedec_be_52_size = 32 * 1024;
- data->emu_jedec_be_d8_size = 64 * 1024;
- data->emu_jedec_ce_60_size = data->emu_chip_size;
- data->emu_jedec_ce_c7_size = data->emu_chip_size;
- msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
- data->emu_chip_size);
- }
-#endif
- if (data->emu_chip == EMULATE_NONE) {
- msg_perr("Invalid chip specified for emulation: %s\n", tmp);
- free(tmp);
+ struct block_eraser *eraser = &flash->chip->block_erasers[0];
+ if (!eraser->block_erase)
return 1;
- }
- free(tmp);
- /* Should emulated flash erase to zero (yes/no)? */
- tmp = extract_programmer_param("erase_to_zero");
- if (tmp) {
- if (!strcmp(tmp, "yes")) {
- msg_pdbg("Emulated chip will erase to 0x00\n");
- data->erase_to_zero = 1;
- } else if (!strcmp(tmp, "no")) {
- msg_pdbg("Emulated chip will erase to 0xff\n");
- } else {
- msg_perr("erase_to_zero can be \"yes\" or \"no\"\n");
- free(tmp);
- return 1;
- }
- }
- free(tmp);
-
- flashchip_contents = malloc(data->emu_chip_size);
- if (!flashchip_contents) {
- msg_perr("Out of memory!\n");
- return 1;
- }
-
-#ifdef EMULATE_SPI_CHIP
- status = extract_programmer_param("spi_status");
- if (status) {
- char *endptr;
- errno = 0;
- data->emu_status = strtoul(status, &endptr, 0);
- free(status);
- if (errno != 0 || status == endptr) {
- msg_perr("Error: initial status register specified, "
- "but the value could not be converted.\n");
- return 1;
- }
- msg_pdbg("Initial status register is set to 0x%02x.\n",
- data->emu_status);
- }
-#endif
+ eraser->eraseblocks[0].count = 1;
+ eraser->eraseblocks[0].size = emu_data->emu_chip_size;
+ msg_cdbg("%s: eraser.size=%d, .count=%d\n",
+ __func__, eraser->eraseblocks[0].size,
+ eraser->eraseblocks[0].count);
- msg_pdbg("Filling fake flash chip with 0x%02x, size %i\n",
- data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
- memset(flashchip_contents, data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
+ return 1;
+}
- /* Will be freed by shutdown function if necessary. */
- data->emu_persistent_image = extract_programmer_param("image");
- if (!data->emu_persistent_image) {
- /* Nothing else to do. */
- goto dummy_init_out;
- }
- /* We will silently (in default verbosity) ignore the file if it does not exist (yet) or the size does
- * not match the emulated chip. */
- if (!stat(data->emu_persistent_image, &image_stat)) {
- msg_pdbg("Found persistent image %s, %jd B ",
- data->emu_persistent_image, (intmax_t)image_stat.st_size);
- if ((uintmax_t)image_stat.st_size == data->emu_chip_size) {
- msg_pdbg("matches.\n");
- msg_pdbg("Reading %s\n", data->emu_persistent_image);
- if (read_buf_from_file(flashchip_contents, data->emu_chip_size,
- data->emu_persistent_image)) {
- msg_perr("Unable to read %s\n", data->emu_persistent_image);
- free(flashchip_contents);
- return 1;
- }
- } else {
- msg_pdbg("doesn't match.\n");
- }
- }
-#endif
+static int dummy_opaque_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+ const struct emu_data *emu_data = flash->mst->opaque.data;
-dummy_init_out:
- if (register_shutdown(dummy_shutdown, data)) {
- free(flashchip_contents);
- free(data);
- return 1;
- }
- if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
- register_par_master(&par_master_dummy,
- dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH));
- if (dummy_buses_supported & BUS_SPI)
- register_spi_master(&spi_master_dummyflasher);
+ memcpy(buf, emu_data->flashchip_contents + start, len);
return 0;
}
-void *dummy_map(const char *descr, uintptr_t phys_addr, size_t len)
+static int dummy_opaque_write(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
{
- msg_pspew("%s: Mapping %s, 0x%zx bytes at 0x%0*" PRIxPTR "\n",
- __func__, descr, len, PRIxPTR_WIDTH, phys_addr);
- return (void *)phys_addr;
+ struct emu_data *emu_data = flash->mst->opaque.data;
+
+ memcpy(emu_data->flashchip_contents + start, buf, len);
+ emu_data->emu_modified = true;
+
+ return 0;
}
-void dummy_unmap(void *virt_addr, size_t len)
+static int dummy_opaque_erase(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen)
{
- msg_pspew("%s: Unmapping 0x%zx bytes at %p\n", __func__, len, virt_addr);
+ struct emu_data *emu_data = flash->mst->opaque.data;
+
+ memset(emu_data->flashchip_contents + blockaddr, emu_data->erase_to_zero ? 0x00 : 0xff, blocklen);
+ emu_data->emu_modified = true;
+
+ return 0;
}
static void dummy_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
@@ -565,7 +215,7 @@ static void dummy_chip_writew(const struct flashctx *flash, uint16_t val, chipad
static void dummy_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
{
- msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%08x\n", __func__, addr, val);
+ msg_pspew("%s: addr=0x%" PRIxPTR ", val=0x%08"PRIx32"\n", __func__, addr, val);
}
static void dummy_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
@@ -604,7 +254,136 @@ static void dummy_chip_readn(const struct flashctx *flash, uint8_t *buf, const c
return;
}
-#if EMULATE_SPI_CHIP
+static uint8_t get_reg_ro_bit_mask(const struct emu_data *data, enum flash_reg reg)
+{
+ /* Whoever adds a new register must not forget to update this function
+ or at least shouldn't use it incorrectly. */
+ assert(reg == STATUS1 || reg == STATUS2 || reg == STATUS3);
+
+ uint8_t ro_bits = reg == STATUS1 ? SPI_SR_WIP : 0;
+
+ if (data->emu_chip == EMULATE_WINBOND_W25Q128FV) {
+ const bool srp0 = (data->emu_status[0] >> 7);
+ const bool srp1 = (data->emu_status[1] & 1);
+
+ const bool wp_active = (srp1 || (srp0 && data->hwwp));
+
+ if (wp_active) {
+ ro_bits = 0xff;
+ } else if (reg == STATUS2) {
+ /* SUS (bit_7) and (R) (bit_2). */
+ ro_bits = 0x84;
+ /* Once any of the lock bits (LB[1..3]) are set, they
+ can't be unset. */
+ ro_bits |= data->emu_status[1] & (1 << 3);
+ ro_bits |= data->emu_status[1] & (1 << 4);
+ ro_bits |= data->emu_status[1] & (1 << 5);
+ } else if (reg == STATUS3) {
+ /* Four reserved bits. */
+ ro_bits = 0x1b;
+ }
+ }
+
+ if (data->emu_chip == EMULATE_SPANSION_S25FL128L) {
+ const bool srp0 = (data->emu_status[0] >> 7);
+ const bool srp1 = (data->emu_status[1] & 1);
+
+ const bool wp_active = (srp1 || (srp0 && data->hwwp));
+
+ if (wp_active) {
+ ro_bits = 0xff;
+ } else if (reg == STATUS2) {
+ /* SUS (bit_7) */
+ ro_bits = 0x80;
+ /* Once any of the lock bits (LB[0..3]) are set, they
+ can't be unset. */
+ ro_bits |= data->emu_status[1] & (1 << 2);
+ ro_bits |= data->emu_status[1] & (1 << 3);
+ ro_bits |= data->emu_status[1] & (1 << 4);
+ ro_bits |= data->emu_status[1] & (1 << 5);
+ } else if (reg == STATUS3) {
+ /* Two reserved bits. */
+ ro_bits = 0x11;
+ }
+ }
+
+ return ro_bits;
+}
+
+static void update_write_protection(struct emu_data *data)
+{
+ if (data->emu_chip != EMULATE_WINBOND_W25Q128FV &&
+ data->emu_chip != EMULATE_SPANSION_S25FL128L)
+ return;
+
+ const struct wp_bits bits = {
+ .srp = data->emu_status[0] >> 7,
+ .srl = data->emu_status[1] & 1,
+
+ .bp_bit_count = 3,
+ .bp =
+ {
+ (data->emu_status[0] >> 2) & 1,
+ (data->emu_status[0] >> 3) & 1,
+ (data->emu_status[0] >> 4) & 1
+ },
+
+ .tb_bit_present = true,
+ .tb = (data->emu_status[0] >> 5) & 1,
+
+ .sec_bit_present = true,
+ .sec = (data->emu_status[0] >> 6) & 1,
+
+ .cmp_bit_present = true,
+ .cmp = (data->emu_status[1] >> 6) & 1,
+ };
+
+ size_t start;
+ size_t len;
+ decode_range_spi25(&start, &len, &bits, data->emu_chip_size);
+
+ data->wp_start = start;
+ data->wp_end = start + len;
+}
+
+/* Checks whether range intersects a write-protected area of the flash if one is
+ * defined. */
+static bool is_write_protected(const struct emu_data *data, uint32_t start, uint32_t len)
+{
+ if (len == 0)
+ return false;
+
+ const uint32_t last = start + len - 1;
+ return (start < data->wp_end && last >= data->wp_start);
+}
+
+/* Returns non-zero on error. */
+static int write_flash_data(struct emu_data *data, uint32_t start, uint32_t len, const uint8_t *buf)
+{
+ if (is_write_protected(data, start, len)) {
+ msg_perr("At least part of the write range is write protected!\n");
+ return 1;
+ }
+
+ memcpy(data->flashchip_contents + start, buf, len);
+ data->emu_modified = true;
+ return 0;
+}
+
+/* Returns non-zero on error. */
+static int erase_flash_data(struct emu_data *data, uint32_t start, uint32_t len)
+{
+ if (is_write_protected(data, start, len)) {
+ msg_perr("At least part of the erase range is write protected!\n");
+ return 1;
+ }
+
+ /* FIXME: Maybe use ERASED_VALUE(flash) instead of 0xff ? */
+ memset(data->flashchip_contents + start, 0xff, len);
+ data->emu_modified = true;
+ return 0;
+}
+
static int emulate_spi_chip_response(unsigned int writecnt,
unsigned int readcnt,
const unsigned char *writearr,
@@ -612,6 +391,8 @@ static int emulate_spi_chip_response(unsigned int writecnt,
struct emu_data *data)
{
unsigned int offs, i, toread;
+ uint8_t ro_bits;
+ bool wrsr_ext2, wrsr_ext3;
static int unsigned aai_offs;
const unsigned char sst25vf040_rems_response[2] = {0xbf, 0x44};
const unsigned char sst25vf032b_rems_response[2] = {0xbf, 0x4a};
@@ -641,7 +422,7 @@ static int emulate_spi_chip_response(unsigned int writecnt,
}
}
- if (data->emu_max_aai_size && (data->emu_status & SPI_SR_AAI)) {
+ if (data->emu_max_aai_size && (data->emu_status[0] & SPI_SR_AAI)) {
if (writearr[0] != JEDEC_AAI_WORD_PROGRAM &&
writearr[0] != JEDEC_WRDI &&
writearr[0] != JEDEC_RDSR) {
@@ -679,6 +460,12 @@ static int emulate_spi_chip_response(unsigned int writecnt,
if (readcnt > 0)
memset(readarr, 0x17, readcnt);
break;
+ case EMULATE_SPANSION_S25FL128L:
+ if (readcnt > 0)
+ readarr[0] = 0x60;
+ if (readcnt > 1)
+ readarr[1] = 0x18;
+ break;
default: /* ignore */
break;
}
@@ -736,6 +523,14 @@ static int emulate_spi_chip_response(unsigned int writecnt,
if (readcnt > 2)
readarr[2] = 0x18;
break;
+ case EMULATE_SPANSION_S25FL128L:
+ if (readcnt > 0)
+ readarr[0] = 0x01;
+ if (readcnt > 1)
+ readarr[1] = 0x60;
+ if (readcnt > 2)
+ readarr[2] = 0x18;
+ break;
case EMULATE_VARIABLE_SIZE:
if (readcnt > 0)
readarr[0] = (PROGMANUF_ID >> 8) & 0xff;
@@ -751,35 +546,98 @@ static int emulate_spi_chip_response(unsigned int writecnt,
}
break;
case JEDEC_RDSR:
- memset(readarr, data->emu_status, readcnt);
+ memset(readarr, data->emu_status[0], readcnt);
+ break;
+ case JEDEC_RDSR2:
+ if (data->emu_status_len >= 2)
+ memset(readarr, data->emu_status[1], readcnt);
+ break;
+ case JEDEC_RDSR3:
+ if (data->emu_status_len >= 3)
+ memset(readarr, data->emu_status[2], readcnt);
break;
/* FIXME: this should be chip-specific. */
case JEDEC_EWSR:
case JEDEC_WREN:
- data->emu_status |= SPI_SR_WEL;
+ data->emu_status[0] |= SPI_SR_WEL;
break;
case JEDEC_WRSR:
- if (!(data->emu_status & SPI_SR_WEL)) {
+ if (!(data->emu_status[0] & SPI_SR_WEL)) {
msg_perr("WRSR attempted, but WEL is 0!\n");
break;
}
+
+ wrsr_ext2 = (writecnt == 3 && data->emu_wrsr_ext2);
+ wrsr_ext3 = (writecnt == 4 && data->emu_wrsr_ext3);
+
/* FIXME: add some reasonable simulation of the busy flag */
- data->emu_status = writearr[1] & ~SPI_SR_WIP;
- msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status);
+
+ ro_bits = get_reg_ro_bit_mask(data, STATUS1);
+ data->emu_status[0] &= ro_bits;
+ data->emu_status[0] |= writearr[1] & ~ro_bits;
+ if (wrsr_ext2 || wrsr_ext3) {
+ ro_bits = get_reg_ro_bit_mask(data, STATUS2);
+ data->emu_status[1] &= ro_bits;
+ data->emu_status[1] |= writearr[2] & ~ro_bits;
+ }
+ if (wrsr_ext3) {
+ ro_bits = get_reg_ro_bit_mask(data, STATUS3);
+ data->emu_status[2] &= ro_bits;
+ data->emu_status[2] |= writearr[3] & ~ro_bits;
+ }
+
+ if (wrsr_ext3)
+ msg_pdbg2("WRSR wrote 0x%02x%02x%02x.\n", data->emu_status[2], data->emu_status[1], data->emu_status[0]);
+ else if (wrsr_ext2)
+ msg_pdbg2("WRSR wrote 0x%02x%02x.\n", data->emu_status[1], data->emu_status[0]);
+ else
+ msg_pdbg2("WRSR wrote 0x%02x.\n", data->emu_status[0]);
+
+ update_write_protection(data);
+ break;
+ case JEDEC_WRSR2:
+ if (data->emu_status_len < 2)
+ break;
+ if (!(data->emu_status[0] & SPI_SR_WEL)) {
+ msg_perr("WRSR2 attempted, but WEL is 0!\n");
+ break;
+ }
+
+ ro_bits = get_reg_ro_bit_mask(data, STATUS2);
+ data->emu_status[1] &= ro_bits;
+ data->emu_status[1] |= (writearr[1] & ~ro_bits);
+
+ msg_pdbg2("WRSR2 wrote 0x%02x.\n", data->emu_status[1]);
+
+ update_write_protection(data);
+ break;
+ case JEDEC_WRSR3:
+ if (data->emu_status_len < 3)
+ break;
+ if (!(data->emu_status[0] & SPI_SR_WEL)) {
+ msg_perr("WRSR3 attempted, but WEL is 0!\n");
+ break;
+ }
+
+ ro_bits = get_reg_ro_bit_mask(data, STATUS3);
+ data->emu_status[2] &= ro_bits;
+ data->emu_status[2] |= (writearr[1] & ~ro_bits);
+
+ msg_pdbg2("WRSR3 wrote 0x%02x.\n", data->emu_status[2]);
break;
case JEDEC_READ:
offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
/* Truncate to emu_chip_size. */
offs %= data->emu_chip_size;
if (readcnt > 0)
- memcpy(readarr, flashchip_contents + offs, readcnt);
+ memcpy(readarr, data->flashchip_contents + offs, readcnt);
break;
case JEDEC_READ_4BA:
offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
/* Truncate to emu_chip_size. */
offs %= data->emu_chip_size;
if (readcnt > 0)
- memcpy(readarr, flashchip_contents + offs, readcnt);
+ memcpy(readarr, data->flashchip_contents + offs, readcnt);
break;
case JEDEC_BYTE_PROGRAM:
offs = writearr[1] << 16 | writearr[2] << 8 | writearr[3];
@@ -793,8 +651,10 @@ static int emulate_spi_chip_response(unsigned int writecnt,
msg_perr("Max BYTE PROGRAM size exceeded!\n");
return 1;
}
- memcpy(flashchip_contents + offs, writearr + 4, writecnt - 4);
- data->emu_modified = 1;
+ if (write_flash_data(data, offs, writecnt - 4, writearr + 4)) {
+ msg_perr("Failed to program flash!\n");
+ return 1;
+ }
break;
case JEDEC_BYTE_PROGRAM_4BA:
offs = writearr[1] << 24 | writearr[2] << 16 | writearr[3] << 8 | writearr[4];
@@ -808,13 +668,15 @@ static int emulate_spi_chip_response(unsigned int writecnt,
msg_perr("Max BYTE PROGRAM size exceeded!\n");
return 1;
}
- memcpy(flashchip_contents + offs, writearr + 5, writecnt - 5);
- data->emu_modified = 1;
+ if (write_flash_data(data, offs, writecnt - 5, writearr + 5)) {
+ msg_perr("Failed to program flash!\n");
+ return 1;
+ }
break;
case JEDEC_AAI_WORD_PROGRAM:
if (!data->emu_max_aai_size)
break;
- if (!(data->emu_status & SPI_SR_AAI)) {
+ if (!(data->emu_status[0] & SPI_SR_AAI)) {
if (writecnt < JEDEC_AAI_WORD_PROGRAM_OUTSIZE) {
msg_perr("Initial AAI WORD PROGRAM size too "
"short!\n");
@@ -825,12 +687,15 @@ static int emulate_spi_chip_response(unsigned int writecnt,
"long!\n");
return 1;
}
- data->emu_status |= SPI_SR_AAI;
+ data->emu_status[0] |= SPI_SR_AAI;
aai_offs = writearr[1] << 16 | writearr[2] << 8 |
writearr[3];
/* Truncate to emu_chip_size. */
aai_offs %= data->emu_chip_size;
- memcpy(flashchip_contents + aai_offs, writearr + 4, 2);
+ if (write_flash_data(data, aai_offs, 2, writearr + 4)) {
+ msg_perr("Failed to program flash!\n");
+ return 1;
+ }
aai_offs += 2;
} else {
if (writecnt < JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE) {
@@ -843,14 +708,16 @@ static int emulate_spi_chip_response(unsigned int writecnt,
"too long!\n");
return 1;
}
- memcpy(flashchip_contents + aai_offs, writearr + 1, 2);
+ if (write_flash_data(data, aai_offs, 2, writearr + 1)) {
+ msg_perr("Failed to program flash!\n");
+ return 1;
+ }
aai_offs += 2;
}
- data->emu_modified = 1;
break;
case JEDEC_WRDI:
if (data->emu_max_aai_size)
- data->emu_status &= ~SPI_SR_AAI;
+ data->emu_status[0] &= ~SPI_SR_AAI;
break;
case JEDEC_SE:
if (!data->emu_jedec_se_size)
@@ -867,8 +734,10 @@ static int emulate_spi_chip_response(unsigned int writecnt,
if (offs & (data->emu_jedec_se_size - 1))
msg_pdbg("Unaligned SECTOR ERASE 0x20: 0x%x\n", offs);
offs &= ~(data->emu_jedec_se_size - 1);
- memset(flashchip_contents + offs, 0xff, data->emu_jedec_se_size);
- data->emu_modified = 1;
+ if (erase_flash_data(data, offs, data->emu_jedec_se_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_BE_52:
if (!data->emu_jedec_be_52_size)
@@ -885,8 +754,10 @@ static int emulate_spi_chip_response(unsigned int writecnt,
if (offs & (data->emu_jedec_be_52_size - 1))
msg_pdbg("Unaligned BLOCK ERASE 0x52: 0x%x\n", offs);
offs &= ~(data->emu_jedec_be_52_size - 1);
- memset(flashchip_contents + offs, 0xff, data->emu_jedec_be_52_size);
- data->emu_modified = 1;
+ if (erase_flash_data(data, offs, data->emu_jedec_be_52_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_BE_D8:
if (!data->emu_jedec_be_d8_size)
@@ -903,8 +774,10 @@ static int emulate_spi_chip_response(unsigned int writecnt,
if (offs & (data->emu_jedec_be_d8_size - 1))
msg_pdbg("Unaligned BLOCK ERASE 0xd8: 0x%x\n", offs);
offs &= ~(data->emu_jedec_be_d8_size - 1);
- memset(flashchip_contents + offs, 0xff, data->emu_jedec_be_d8_size);
- data->emu_modified = 1;
+ if (erase_flash_data(data, offs, data->emu_jedec_be_d8_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_CE_60:
if (!data->emu_jedec_ce_60_size)
@@ -919,8 +792,10 @@ static int emulate_spi_chip_response(unsigned int writecnt,
}
/* JEDEC_CE_60_OUTSIZE is 1 (no address) -> no offset. */
/* emu_jedec_ce_60_size is emu_chip_size. */
- memset(flashchip_contents, 0xff, data->emu_jedec_ce_60_size);
- data->emu_modified = 1;
+ if (erase_flash_data(data, 0, data->emu_jedec_ce_60_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_CE_C7:
if (!data->emu_jedec_ce_c7_size)
@@ -935,8 +810,10 @@ static int emulate_spi_chip_response(unsigned int writecnt,
}
/* JEDEC_CE_C7_OUTSIZE is 1 (no address) -> no offset. */
/* emu_jedec_ce_c7_size is emu_chip_size. */
- memset(flashchip_contents, 0xff, data->emu_jedec_ce_c7_size);
- data->emu_modified = 1;
+ if (erase_flash_data(data, 0, data->emu_jedec_ce_c7_size)) {
+ msg_perr("Failed to erase flash!\n");
+ return 1;
+ }
break;
case JEDEC_SFDP:
if (data->emu_chip != EMULATE_MACRONIX_MX25L6436)
@@ -978,20 +855,9 @@ static int emulate_spi_chip_response(unsigned int writecnt,
break;
}
if (writearr[0] != JEDEC_WREN && writearr[0] != JEDEC_EWSR)
- data->emu_status &= ~SPI_SR_WEL;
+ data->emu_status[0] &= ~SPI_SR_WEL;
return 0;
}
-#endif
-
-static struct emu_data* get_data_from_context(const struct flashctx *flash)
-{
- if (dummy_buses_supported & (BUS_PARALLEL | BUS_LPC | BUS_FWH))
- return (struct emu_data *)flash->mst->par.data;
- else if (dummy_buses_supported & BUS_SPI)
- return (struct emu_data *)flash->mst->spi.data;
-
- return NULL; /* buses was set to BUS_NONE. */
-}
static int dummy_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
unsigned int readcnt,
@@ -999,7 +865,7 @@ static int dummy_spi_send_command(const struct flashctx *flash, unsigned int wri
unsigned char *readarr)
{
unsigned int i;
- struct emu_data *emu_data = get_data_from_context(flash);
+ struct emu_data *emu_data = flash->mst->spi.data;
if (!emu_data) {
msg_perr("No data in flash context!\n");
return 1;
@@ -1013,13 +879,13 @@ static int dummy_spi_send_command(const struct flashctx *flash, unsigned int wri
/* Response for unknown commands and missing chip is 0xff. */
memset(readarr, 0xff, readcnt);
-#if EMULATE_SPI_CHIP
switch (emu_data->emu_chip) {
case EMULATE_ST_M25P10_RES:
case EMULATE_SST_SST25VF040_REMS:
case EMULATE_SST_SST25VF032B:
case EMULATE_MACRONIX_MX25L6436:
case EMULATE_WINBOND_W25Q128FV:
+ case EMULATE_SPANSION_S25FL128L:
case EMULATE_VARIABLE_SIZE:
if (emulate_spi_chip_response(writecnt, readcnt, writearr,
readarr, emu_data)) {
@@ -1030,63 +896,583 @@ static int dummy_spi_send_command(const struct flashctx *flash, unsigned int wri
default:
break;
}
-#endif
msg_pspew(" reading %u bytes:", readcnt);
for (i = 0; i < readcnt; i++)
msg_pspew(" 0x%02x", readarr[i]);
msg_pspew("\n");
- programmer_delay((writecnt + readcnt) * emu_data->delay_us);
+ default_delay((writecnt + readcnt) * emu_data->delay_us);
return 0;
}
-static int dummy_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
+static int dummy_shutdown(void *data)
{
- return spi_write_chunked(flash, buf, start, len,
- spi_write_256_chunksize);
+ msg_pspew("%s\n", __func__);
+ struct emu_data *emu_data = (struct emu_data *)data;
+
+ emu_data->refs_cnt--;
+ if (emu_data->refs_cnt != 0)
+ return 0;
+
+ if (emu_data->emu_chip != EMULATE_NONE) {
+ if (emu_data->emu_persistent_image && emu_data->emu_modified) {
+ msg_pdbg("Writing %s\n", emu_data->emu_persistent_image);
+ write_buf_to_file(emu_data->flashchip_contents,
+ emu_data->emu_chip_size,
+ emu_data->emu_persistent_image);
+ }
+ free(emu_data->emu_persistent_image);
+ free(emu_data->flashchip_contents);
+ }
+ free(data);
+ return 0;
}
-#if EMULATE_CHIP && EMULATE_SPI_CHIP
-int probe_variable_size(struct flashctx *flash)
+static void dummy_nop_delay(const struct flashctx *flash, unsigned int usecs)
+{
+}
+
+static enum flashrom_wp_result dummy_wp_read_cfg(struct flashrom_wp_cfg *cfg, struct flashctx *flash)
+{
+ cfg->mode = FLASHROM_WP_MODE_DISABLED;
+ cfg->range.start = 0;
+ cfg->range.len = 0;
+
+ return FLASHROM_WP_OK;
+}
+
+static enum flashrom_wp_result dummy_wp_write_cfg(struct flashctx *flash, const struct flashrom_wp_cfg *cfg)
+{
+ if (cfg->mode != FLASHROM_WP_MODE_DISABLED)
+ return FLASHROM_WP_ERR_MODE_UNSUPPORTED;
+
+ if (cfg->range.start != 0 || cfg->range.len != 0)
+ return FLASHROM_WP_ERR_RANGE_UNSUPPORTED;
+
+ return FLASHROM_WP_OK;
+}
+
+static enum flashrom_wp_result dummy_wp_get_available_ranges(struct flashrom_wp_ranges **list, struct flashctx *flash)
+{
+ /* Not supported */
+ return FLASHROM_WP_ERR_RANGE_LIST_UNAVAILABLE;
+}
+
+
+static const struct spi_master spi_master_dummyflasher = {
+ .map_flash_region = dummy_map,
+ .unmap_flash_region = dummy_unmap,
+ .features = SPI_MASTER_4BA,
+ .max_data_read = MAX_DATA_READ_UNLIMITED,
+ .max_data_write = MAX_DATA_UNSPECIFIED,
+ .command = dummy_spi_send_command,
+ .read = default_spi_read,
+ .write_256 = dummy_spi_write_256,
+ .shutdown = dummy_shutdown,
+ .probe_opcode = dummy_spi_probe_opcode,
+ .delay = dummy_nop_delay,
+};
+
+static const struct par_master par_master_dummyflasher = {
+ .map_flash_region = dummy_map,
+ .unmap_flash_region = dummy_unmap,
+ .chip_readb = dummy_chip_readb,
+ .chip_readw = dummy_chip_readw,
+ .chip_readl = dummy_chip_readl,
+ .chip_readn = dummy_chip_readn,
+ .chip_writeb = dummy_chip_writeb,
+ .chip_writew = dummy_chip_writew,
+ .chip_writel = dummy_chip_writel,
+ .chip_writen = dummy_chip_writen,
+ .shutdown = dummy_shutdown,
+ .delay = dummy_nop_delay,
+};
+
+static const struct opaque_master opaque_master_dummyflasher = {
+ .probe = probe_variable_size,
+ .read = dummy_opaque_read,
+ .write = dummy_opaque_write,
+ .erase = dummy_opaque_erase,
+ .shutdown = dummy_shutdown,
+ .delay = dummy_nop_delay,
+ .wp_read_cfg = dummy_wp_read_cfg,
+ .wp_write_cfg = dummy_wp_write_cfg,
+ .wp_get_ranges = dummy_wp_get_available_ranges,
+};
+
+static int init_data(const struct programmer_cfg *cfg,
+ struct emu_data *data, enum chipbustype *dummy_buses_supported)
{
+ char *bustext = NULL;
+ char *tmp = NULL;
unsigned int i;
- const struct emu_data *emu_data = get_data_from_context(flash);
+ char *endptr;
+ char *status = NULL;
+ int size = -1; /* size for VARIABLE_SIZE chip device */
- /* Skip the probing if we don't emulate this chip. */
- if (!emu_data || emu_data->emu_chip != EMULATE_VARIABLE_SIZE)
+ bustext = extract_programmer_param_str(cfg, "bus");
+ msg_pdbg("Requested buses are: %s\n", bustext ? bustext : "default");
+ if (!bustext)
+ bustext = strdup("parallel+lpc+fwh+spi+prog");
+ /* Convert the parameters to lowercase. */
+ tolower_string(bustext);
+
+ *dummy_buses_supported = BUS_NONE;
+ if (strstr(bustext, "parallel")) {
+ *dummy_buses_supported |= BUS_PARALLEL;
+ msg_pdbg("Enabling support for %s flash.\n", "parallel");
+ }
+ if (strstr(bustext, "lpc")) {
+ *dummy_buses_supported |= BUS_LPC;
+ msg_pdbg("Enabling support for %s flash.\n", "LPC");
+ }
+ if (strstr(bustext, "fwh")) {
+ *dummy_buses_supported |= BUS_FWH;
+ msg_pdbg("Enabling support for %s flash.\n", "FWH");
+ }
+ if (strstr(bustext, "spi")) {
+ *dummy_buses_supported |= BUS_SPI;
+ msg_pdbg("Enabling support for %s flash.\n", "SPI");
+ }
+ if (strstr(bustext, "prog")) {
+ *dummy_buses_supported |= BUS_PROG;
+ msg_pdbg("Enabling support for %s flash.\n", "PROG");
+ }
+ if (*dummy_buses_supported == BUS_NONE)
+ msg_pdbg("Support for all flash bus types disabled.\n");
+ free(bustext);
+
+ tmp = extract_programmer_param_str(cfg, "spi_write_256_chunksize");
+ if (tmp) {
+ data->spi_write_256_chunksize = strtoul(tmp, &endptr, 0);
+ if (*endptr != '\0' || data->spi_write_256_chunksize < 1) {
+ msg_perr("invalid spi_write_256_chunksize\n");
+ free(tmp);
+ return 1;
+ }
+ }
+ free(tmp);
+
+ tmp = extract_programmer_param_str(cfg, "spi_blacklist");
+ if (tmp) {
+ i = strlen(tmp);
+ if (!strncmp(tmp, "0x", 2)) {
+ i -= 2;
+ memmove(tmp, tmp + 2, i + 1);
+ }
+ if ((i > 512) || (i % 2)) {
+ msg_perr("Invalid SPI command blacklist length\n");
+ free(tmp);
+ return 1;
+ }
+ data->spi_blacklist_size = i / 2;
+ for (i = 0; i < data->spi_blacklist_size * 2; i++) {
+ if (!isxdigit((unsigned char)tmp[i])) {
+ msg_perr("Invalid char \"%c\" in SPI command "
+ "blacklist\n", tmp[i]);
+ free(tmp);
+ return 1;
+ }
+ }
+ for (i = 0; i < data->spi_blacklist_size; i++) {
+ unsigned int tmp2;
+ /* SCNx8 is apparently not supported by MSVC (and thus
+ * MinGW), so work around it with an extra variable
+ */
+ sscanf(tmp + i * 2, "%2x", &tmp2);
+ data->spi_blacklist[i] = (uint8_t)tmp2;
+ }
+ msg_pdbg("SPI blacklist is ");
+ for (i = 0; i < data->spi_blacklist_size; i++)
+ msg_pdbg("%02x ", data->spi_blacklist[i]);
+ msg_pdbg(", size %u\n", data->spi_blacklist_size);
+ }
+ free(tmp);
+
+ tmp = extract_programmer_param_str(cfg, "spi_ignorelist");
+ if (tmp) {
+ i = strlen(tmp);
+ if (!strncmp(tmp, "0x", 2)) {
+ i -= 2;
+ memmove(tmp, tmp + 2, i + 1);
+ }
+ if ((i > 512) || (i % 2)) {
+ msg_perr("Invalid SPI command ignorelist length\n");
+ free(tmp);
+ return 1;
+ }
+ data->spi_ignorelist_size = i / 2;
+ for (i = 0; i < data->spi_ignorelist_size * 2; i++) {
+ if (!isxdigit((unsigned char)tmp[i])) {
+ msg_perr("Invalid char \"%c\" in SPI command "
+ "ignorelist\n", tmp[i]);
+ free(tmp);
+ return 1;
+ }
+ }
+ for (i = 0; i < data->spi_ignorelist_size; i++) {
+ unsigned int tmp2;
+ /* SCNx8 is apparently not supported by MSVC (and thus
+ * MinGW), so work around it with an extra variable
+ */
+ sscanf(tmp + i * 2, "%2x", &tmp2);
+ data->spi_ignorelist[i] = (uint8_t)tmp2;
+ }
+ msg_pdbg("SPI ignorelist is ");
+ for (i = 0; i < data->spi_ignorelist_size; i++)
+ msg_pdbg("%02x ", data->spi_ignorelist[i]);
+ msg_pdbg(", size %u\n", data->spi_ignorelist_size);
+ }
+ free(tmp);
+
+ /* frequency to emulate in Hz (default), KHz, or MHz */
+ tmp = extract_programmer_param_str(cfg, "freq");
+ if (tmp) {
+ unsigned long int freq;
+ char *units = tmp;
+ char *end = tmp + strlen(tmp);
+
+ errno = 0;
+ freq = strtoul(tmp, &units, 0);
+ if (errno) {
+ msg_perr("Invalid frequency \"%s\", %s\n",
+ tmp, strerror(errno));
+ free(tmp);
+ return 1;
+ }
+
+ if ((units > tmp) && (units < end)) {
+ bool units_valid = false;
+
+ if (units < end - 3) {
+ ;
+ } else if (units == end - 2) {
+ if (!strcasecmp(units, "hz"))
+ units_valid = true;
+ } else if (units == end - 3) {
+ if (!strcasecmp(units, "khz")) {
+ freq *= 1000;
+ units_valid = true;
+ } else if (!strcasecmp(units, "mhz")) {
+ freq *= 1000000;
+ units_valid = true;
+ }
+ }
+
+ if (!units_valid) {
+ msg_perr("Invalid units: %s\n", units);
+ free(tmp);
+ return 1;
+ }
+ }
+
+ if (freq == 0) {
+ msg_perr("%s: invalid value 0 for freq parameter\n", __func__);
+ free(tmp);
+ return 1;
+ }
+ /* Assume we only work with bytes and transfer at 1 bit/Hz */
+ data->delay_us = (1000000 * 8) / freq;
+ }
+ free(tmp);
+
+ tmp = extract_programmer_param_str(cfg, "size");
+ if (tmp) {
+ size = strtol(tmp, NULL, 10);
+ if (size <= 0 || (size % 1024 != 0)) {
+ msg_perr("%s: Chip size is not a multiple of 1024: %s\n",
+ __func__, tmp);
+ free(tmp);
+ return 1;
+ }
+ free(tmp);
+ }
+
+ tmp = extract_programmer_param_str(cfg, "hwwp");
+ if (tmp) {
+ if (!strcmp(tmp, "yes")) {
+ msg_pdbg("Emulated chip will have hardware WP enabled\n");
+ data->hwwp = true;
+ } else if (!strcmp(tmp, "no")) {
+ msg_pdbg("Emulated chip will have hardware WP disabled\n");
+ } else {
+ msg_perr("hwwp can be \"yes\" or \"no\"\n");
+ free(tmp);
+ return 1;
+ }
+ free(tmp);
+ }
+
+ tmp = extract_programmer_param_str(cfg, "emulate");
+ if (!tmp) {
+ if (size != -1) {
+ msg_perr("%s: size parameter is only valid for VARIABLE_SIZE chip.\n", __func__);
+ return 1;
+ }
+ msg_pdbg("Not emulating any flash chip.\n");
+ /* Nothing else to do. */
return 0;
+ }
- /*
- * This will break if one day flashctx becomes read-only.
- * Once that happens, we need to have special hacks in functions:
- *
- * erase_and_write_flash() in flashrom.c
- * read_flash_to_file()
- * handle_romentries()
- * ...
- *
- * Search "total_size * 1024" in code.
+ if (!strcmp(tmp, "M25P10.RES")) {
+ data->emu_chip = EMULATE_ST_M25P10_RES;
+ data->emu_chip_size = 128 * 1024;
+ data->emu_max_byteprogram_size = 128;
+ data->emu_max_aai_size = 0;
+ data->emu_status_len = 1;
+ data->emu_jedec_se_size = 0;
+ data->emu_jedec_be_52_size = 0;
+ data->emu_jedec_be_d8_size = 32 * 1024;
+ data->emu_jedec_ce_60_size = 0;
+ data->emu_jedec_ce_c7_size = data->emu_chip_size;
+ msg_pdbg("Emulating ST M25P10.RES SPI flash chip (RES, page "
+ "write)\n");
+ }
+ if (!strcmp(tmp, "SST25VF040.REMS")) {
+ data->emu_chip = EMULATE_SST_SST25VF040_REMS;
+ data->emu_chip_size = 512 * 1024;
+ data->emu_max_byteprogram_size = 1;
+ data->emu_max_aai_size = 0;
+ data->emu_status_len = 1;
+ data->emu_jedec_se_size = 4 * 1024;
+ data->emu_jedec_be_52_size = 32 * 1024;
+ data->emu_jedec_be_d8_size = 0;
+ data->emu_jedec_ce_60_size = data->emu_chip_size;
+ data->emu_jedec_ce_c7_size = 0;
+ msg_pdbg("Emulating SST SST25VF040.REMS SPI flash chip (REMS, "
+ "byte write)\n");
+ }
+ if (!strcmp(tmp, "SST25VF032B")) {
+ data->emu_chip = EMULATE_SST_SST25VF032B;
+ data->emu_chip_size = 4 * 1024 * 1024;
+ data->emu_max_byteprogram_size = 1;
+ data->emu_max_aai_size = 2;
+ data->emu_status_len = 1;
+ data->emu_jedec_se_size = 4 * 1024;
+ data->emu_jedec_be_52_size = 32 * 1024;
+ data->emu_jedec_be_d8_size = 64 * 1024;
+ data->emu_jedec_ce_60_size = data->emu_chip_size;
+ data->emu_jedec_ce_c7_size = data->emu_chip_size;
+ msg_pdbg("Emulating SST SST25VF032B SPI flash chip (RDID, AAI "
+ "write)\n");
+ }
+ if (!strcmp(tmp, "MX25L6436")) {
+ data->emu_chip = EMULATE_MACRONIX_MX25L6436;
+ data->emu_chip_size = 8 * 1024 * 1024;
+ data->emu_max_byteprogram_size = 256;
+ data->emu_max_aai_size = 0;
+ data->emu_status_len = 1;
+ data->emu_jedec_se_size = 4 * 1024;
+ data->emu_jedec_be_52_size = 32 * 1024;
+ data->emu_jedec_be_d8_size = 64 * 1024;
+ data->emu_jedec_ce_60_size = data->emu_chip_size;
+ data->emu_jedec_ce_c7_size = data->emu_chip_size;
+ msg_pdbg("Emulating Macronix MX25L6436 SPI flash chip (RDID, "
+ "SFDP)\n");
+ }
+ if (!strcmp(tmp, "W25Q128FV")) {
+ data->emu_chip = EMULATE_WINBOND_W25Q128FV;
+ data->emu_wrsr_ext2 = true;
+ data->emu_chip_size = 16 * 1024 * 1024;
+ data->emu_max_byteprogram_size = 256;
+ data->emu_max_aai_size = 0;
+ data->emu_status_len = 3;
+ data->emu_jedec_se_size = 4 * 1024;
+ data->emu_jedec_be_52_size = 32 * 1024;
+ data->emu_jedec_be_d8_size = 64 * 1024;
+ data->emu_jedec_ce_60_size = data->emu_chip_size;
+ data->emu_jedec_ce_c7_size = data->emu_chip_size;
+ msg_pdbg("Emulating Winbond W25Q128FV SPI flash chip (RDID)\n");
+ }
+ if (!strcmp(tmp, "S25FL128L")) {
+ data->emu_chip = EMULATE_SPANSION_S25FL128L;
+ data->emu_wrsr_ext2 = true;
+ data->emu_wrsr_ext3 = true;
+ data->emu_chip_size = 16 * 1024 * 1024;
+ data->emu_max_byteprogram_size = 256;
+ data->emu_max_aai_size = 0;
+ data->emu_status_len = 3;
+ data->emu_jedec_se_size = 4 * 1024;
+ data->emu_jedec_be_52_size = 32 * 1024;
+ data->emu_jedec_be_d8_size = 64 * 1024;
+ data->emu_jedec_ce_60_size = data->emu_chip_size;
+ data->emu_jedec_ce_c7_size = data->emu_chip_size;
+ msg_pdbg("Emulating Spansion S25FL128L SPI flash chip (RES, RDID, WP)\n");
+ }
+
+ /* The name of variable-size virtual chip. A 4 MiB flash example:
+ * flashrom -p dummy:emulate=VARIABLE_SIZE,size=4194304
*/
- flash->chip->total_size = emu_data->emu_chip_size / 1024;
- msg_cdbg("%s: set flash->total_size to %dK bytes.\n", __func__,
- flash->chip->total_size);
+ if (!strcmp(tmp, "VARIABLE_SIZE")) {
+ if (size == -1) {
+ msg_perr("%s: the size parameter is not given.\n", __func__);
+ free(tmp);
+ return 1;
+ }
+ data->emu_chip = EMULATE_VARIABLE_SIZE;
+ data->emu_chip_size = size;
+ msg_pdbg("Emulating generic SPI flash chip (size=%d bytes)\n",
+ data->emu_chip_size);
+ } else if (size != -1) {
+ msg_perr("%s: size parameter is only valid for VARIABLE_SIZE chip.\n", __func__);
+ free(tmp);
+ return 1;
+ }
- if (emu_data->erase_to_zero)
- flash->chip->feature_bits |= FEATURE_ERASED_ZERO;
+ if (data->emu_chip == EMULATE_NONE) {
+ msg_perr("Invalid chip specified for emulation: %s\n", tmp);
+ free(tmp);
+ return 1;
+ }
+ free(tmp);
- /* Update the first count of each of the block_erasers. */
- for (i = 0; i < NUM_ERASEFUNCTIONS; i++) {
- struct block_eraser *eraser = &flash->chip->block_erasers[i];
- if (!eraser->block_erase)
- break;
+ /* Should emulated flash erase to zero (yes/no)? */
+ tmp = extract_programmer_param_str(cfg, "erase_to_zero");
+ if (tmp) {
+ if (data->emu_chip != EMULATE_VARIABLE_SIZE) {
+ msg_perr("%s: erase_to_zero parameter is not valid for real chip.\n", __func__);
+ free(tmp);
+ return 1;
+ }
+ if (!strcmp(tmp, "yes")) {
+ msg_pdbg("Emulated chip will erase to 0x00\n");
+ data->erase_to_zero = true;
+ } else if (!strcmp(tmp, "no")) {
+ msg_pdbg("Emulated chip will erase to 0xff\n");
+ } else {
+ msg_perr("erase_to_zero can be \"yes\" or \"no\"\n");
+ free(tmp);
+ return 1;
+ }
+ }
+ free(tmp);
- eraser->eraseblocks[0].count = 1;
- eraser->eraseblocks[0].size = emu_data->emu_chip_size;
- msg_cdbg("%s: eraser.size=%d, .count=%d\n",
- __func__, eraser->eraseblocks[0].size,
- eraser->eraseblocks[0].count);
+ status = extract_programmer_param_str(cfg, "spi_status");
+ if (status) {
+ unsigned int emu_status;
+
+ errno = 0;
+ emu_status = strtoul(status, &endptr, 0);
+ if (errno != 0 || status == endptr) {
+ free(status);
+ msg_perr("Error: initial status register specified, "
+ "but the value could not be converted.\n");
+ return 1;
+ }
+ free(status);
+
+ data->emu_status[0] = emu_status;
+ data->emu_status[1] = emu_status >> 8;
+ data->emu_status[2] = emu_status >> 16;
+
+ if (data->emu_status_len == 3) {
+ msg_pdbg("Initial status registers:\n"
+ "\tSR1 is set to 0x%02x\n"
+ "\tSR2 is set to 0x%02x\n"
+ "\tSR3 is set to 0x%02x\n",
+ data->emu_status[0], data->emu_status[1], data->emu_status[2]);
+ } else if (data->emu_status_len == 2) {
+ msg_pdbg("Initial status registers:\n"
+ "\tSR1 is set to 0x%02x\n"
+ "\tSR2 is set to 0x%02x\n",
+ data->emu_status[0], data->emu_status[1]);
+ } else {
+ msg_pdbg("Initial status register is set to 0x%02x.\n",
+ data->emu_status[0]);
+ }
}
- return 1;
+ data->flashchip_contents = malloc(data->emu_chip_size);
+ if (!data->flashchip_contents) {
+ msg_perr("Out of memory!\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int dummy_init(const struct programmer_cfg *cfg)
+{
+ int ret = 0;
+ struct stat image_stat;
+
+ struct emu_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Out of memory!\n");
+ return 1;
+ }
+ data->emu_chip = EMULATE_NONE;
+ data->delay_us = 0;
+ data->spi_write_256_chunksize = 256;
+
+ msg_pspew("%s\n", __func__);
+
+ enum chipbustype dummy_buses_supported;
+ if (init_data(cfg, data, &dummy_buses_supported)) {
+ free(data);
+ return 1;
+ }
+
+ if (data->emu_chip == EMULATE_NONE) {
+ msg_pdbg("Not emulating any flash chip.\n");
+ /* Nothing else to do. */
+ goto dummy_init_out;
+ }
+
+ msg_pdbg("Filling fake flash chip with 0x%02x, size %i\n",
+ data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
+ memset(data->flashchip_contents, data->erase_to_zero ? 0x00 : 0xff, data->emu_chip_size);
+
+ /* Will be freed by shutdown function if necessary. */
+ data->emu_persistent_image = extract_programmer_param_str(cfg, "image");
+ if (!data->emu_persistent_image) {
+ /* Nothing else to do. */
+ goto dummy_init_out;
+ }
+ /* We will silently (in default verbosity) ignore the file if it does not exist (yet) or the size does
+ * not match the emulated chip. */
+ if (!stat(data->emu_persistent_image, &image_stat)) {
+ msg_pdbg("Found persistent image %s, %jd B ",
+ data->emu_persistent_image, (intmax_t)image_stat.st_size);
+ if ((uintmax_t)image_stat.st_size == data->emu_chip_size) {
+ msg_pdbg("matches.\n");
+ msg_pdbg("Reading %s\n", data->emu_persistent_image);
+ if (read_buf_from_file(data->flashchip_contents, data->emu_chip_size,
+ data->emu_persistent_image)) {
+ msg_perr("Unable to read %s\n", data->emu_persistent_image);
+ free(data->emu_persistent_image);
+ free(data->flashchip_contents);
+ free(data);
+ return 1;
+ }
+ } else {
+ msg_pdbg("doesn't match.\n");
+ }
+ }
+
+dummy_init_out:
+ if (dummy_buses_supported & BUS_PROG) {
+ data->refs_cnt++;
+ ret |= register_opaque_master(&opaque_master_dummyflasher, data);
+ }
+ if ((dummy_buses_supported & BUS_NONSPI) && !ret) {
+ data->refs_cnt++;
+ ret |= register_par_master(&par_master_dummyflasher,
+ dummy_buses_supported & BUS_NONSPI,
+ data);
+ }
+ if ((dummy_buses_supported & BUS_SPI) && !ret) {
+ data->refs_cnt++;
+ ret |= register_spi_master(&spi_master_dummyflasher, data);
+ }
+
+ return ret;
}
-#endif
+
+const struct programmer_entry programmer_dummy = {
+ .name = "dummy",
+ .type = OTHER,
+ /* FIXME */
+ .devs.note = "Dummy device, does nothing and logs all accesses\n",
+ .init = dummy_init,
+};
diff --git a/edi.c b/edi.c
index a2219ac6c..56ed62cec 100644
--- a/edi.c
+++ b/edi.c
@@ -304,7 +304,7 @@ int edi_chip_block_erase(struct flashctx *flash, unsigned int page, unsigned int
return -1;
while (edi_spi_busy(flash) == 1 && timeout) {
- programmer_delay(10);
+ programmer_delay(flash, 10);
timeout--;
}
@@ -379,7 +379,7 @@ int edi_chip_write(struct flashctx *flash, const uint8_t *buf, unsigned int star
return -1;
while (edi_spi_busy(flash) == 1 && timeout) {
- programmer_delay(10);
+ programmer_delay(flash, 10);
timeout--;
}
@@ -435,7 +435,7 @@ int edi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsi
/* Just in case. */
while (edi_spi_busy(flash) == 1 && timeout) {
- programmer_delay(10);
+ programmer_delay(flash, 10);
timeout--;
}
diff --git a/en29lv640b.c b/en29lv640b.c
index 5b019047e..8a8d6411b 100644
--- a/en29lv640b.c
+++ b/en29lv640b.c
@@ -48,6 +48,7 @@ int write_en29lv640b(struct flashctx *flash, const uint8_t *src, unsigned int st
#endif
dst += 2;
src += 2;
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 2, len);
}
/* FIXME: Ignore errors for now. */
@@ -63,7 +64,7 @@ int probe_en29lv640b(struct flashctx *flash)
chip_writeb(flash, 0x55, bios + 0x555);
chip_writeb(flash, 0x90, bios + 0xAAA);
- programmer_delay(10);
+ programmer_delay(flash, 10);
id1 = chip_readb(flash, bios + 0x200);
id1 |= (chip_readb(flash, bios) << 8);
@@ -72,7 +73,7 @@ int probe_en29lv640b(struct flashctx *flash)
chip_writeb(flash, 0xF0, bios + 0xAAA);
- programmer_delay(10);
+ programmer_delay(flash, 10);
msg_cdbg("%s: id1 0x%04x, id2 0x%04x\n", __func__, id1, id2);
diff --git a/endiantest.c b/endiantest.c
deleted file mode 100644
index a73b908a4..000000000
--- a/endiantest.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "platform.h"
-#if defined(__FLASHROM_LITTLE_ENDIAN__)
-little
-#else
-big
-#endif
diff --git a/ene_lpc.c b/ene_lpc.c
deleted file mode 100644
index 56d65807b..000000000
--- a/ene_lpc.c
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2012-2020, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- */
-
-#if defined(__i386__) || defined(__x86_64__)
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/time.h>
-
-#include "chipdrivers.h"
-#include "flash.h"
-#include "programmer.h"
-#include "hwaccess.h"
-#include "spi.h"
-
-/* MCU registers */
-#define REG_EC_HWVER 0xff00
-#define REG_EC_FWVER 0xff01
-#define REG_EC_EDIID 0xff24
-#define REG_8051_CTRL 0xff14
-#define REG_EC_EXTCMD 0xff10
-
-#define CPU_RESET 1
-
-/* MCU SPI peripheral registers */
-#define REG_SPI_DATA 0xfeab
-#define REG_SPI_COMMAND 0xfeac
-#define REG_SPI_CONFIG 0xfead
-
-#define CFG_CSn_FORCE_LOW (1 << 4)
-#define CFG_COMMAND_WRITE_ENABLE (1 << 3)
-#define CFG_STATUS (1 << 1)
-#define CFG_ENABLE_BUSY_STATUS_CHECK (1 << 0)
-
-/* Timeout */
-#define EC_COMMAND_TIMEOUT 4
-#define EC_RESTART_TIMEOUT 10
-#define ENE_SPI_DELAY_CYCLE 4
-#define EC_PAUSE_TIMEOUT 12
-#define EC_RESET_TRIES 3
-
-#define ENE_KB94X_PAUSE_WAKEUP_PORT 0x64
-
-#define MASK_INPUT_BUFFER_FULL 2
-#define MASK_OUTPUT_BUFFER_FULL 1
-
-const int port_ene_bank = 1;
-const int port_ene_offset = 2;
-const int port_ene_data = 3;
-
-/* Supported ENE ECs, ENE_LAST should always be LAST member */
-enum ene_chip_id {
- ENE_KB932 = 0,
- ENE_KB94X,
- ENE_LAST
-};
-
-/* EC state */
-enum ene_ec_state {
- EC_STATE_NORMAL,
- EC_STATE_IDLE,
- EC_STATE_RESET,
- EC_STATE_UNKNOWN
-};
-
-/* chip-specific parameters */
-typedef struct {
- enum ene_chip_id chip_id;
- uint8_t hwver;
- uint8_t ediid;
- uint32_t port_bios;
- uint32_t port_ec_command;
- uint32_t port_ec_data;
- uint8_t ec_reset_cmd;
- uint8_t ec_reset_data;
- uint8_t ec_restart_cmd;
- uint8_t ec_restart_data;
- uint8_t ec_pause_cmd;
- uint8_t ec_pause_data;
- uint16_t ec_status_buf;
- uint8_t ec_is_stopping;
- uint8_t ec_is_running;
- uint8_t ec_is_pausing;
- uint32_t port_io_base;
-} ene_chip_t;
-
-typedef struct
-{
- /* pointer to table entry of identified chip */
- ene_chip_t *chip;
- /* current ec state */
- enum ene_ec_state ec_state;
- struct timeval pause_begin;
-} ene_lpc_data_t;
-
-/* table of supported chips + parameters */
-static ene_chip_t ene_chips[] = {
- {
- ENE_KB932, /* chip_id */
- 0xa2, 0x02, /* hwver + ediid */
- 0x66, /* port_bios */
- 0x6c, 0x68, /* port_ec_{command,data} */
- 0x59, 0xf2, /* ec_reset_{cmd,data} */
- 0x59, 0xf9, /* ec_restart_{cmd,data} */
- 0x59, 0xf1, /* ec_pause_{cmd,data} */
- 0xf554, /* ec_status_buf */
- 0xa5, 0x00, /* ec_is_{stopping,running} masks */
- 0x33, /* ec_is_pausing mask */
- 0xfd60 /* port_io_base */
- },
- {
- ENE_KB94X, /* chip_id */
- 0xa3, 0x05, /* hwver + ediid */
- 0x66, /* port_bios */
- 0x66, 0x68, /* port_ec_{command,data} */
- 0x7d, 0x10, /* ec_reset_{cmd,data} */
- 0x7f, 0x10, /* ec_restart_{cmd,data} */
- 0x7e, 0x10, /* ec_pause_{cmd,data} */
- 0xf710, /* ec_status_buf */
- 0x02, 0x00, /* ec_is_{stopping,running} masks */
- 0x01, /* ec_is_pausing mask */
- 0x0380 /* port_io_base */
- }
-};
-
-static void ec_command(const ene_chip_t *chip, uint8_t cmd, uint8_t data)
-{
- struct timeval begin, now;
-
- /* Spin wait for EC input buffer empty */
- gettimeofday(&begin, NULL);
- while (INB(chip->port_ec_command) & MASK_INPUT_BUFFER_FULL) {
- gettimeofday(&now, NULL);
- if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) {
- msg_pdbg("%s: buf not empty\n", __func__);
- return;
- }
- }
-
- /* Write command */
- OUTB(cmd, chip->port_ec_command);
-
- if (chip->chip_id == ENE_KB932) {
- /* Spin wait for EC input buffer empty */
- gettimeofday(&begin, NULL);
- while (INB(chip->port_ec_command) &
- MASK_INPUT_BUFFER_FULL) {
- gettimeofday(&now, NULL);
- if ((now.tv_sec - begin.tv_sec) >=
- EC_COMMAND_TIMEOUT) {
- msg_pdbg("%s: buf not empty\n", __func__);
- return;
- }
- }
- /* Write data */
- OUTB(data, chip->port_ec_data);
- }
-}
-
-static uint8_t ene_read(const ene_chip_t *chip, uint16_t addr)
-{
- uint8_t bank;
- uint8_t offset;
- uint8_t data;
- uint32_t port_io_base;
-
- bank = addr >> 8;
- offset = addr & 0xff;
- port_io_base = chip->port_io_base;
-
- OUTB(bank, port_io_base + port_ene_bank);
- OUTB(offset, port_io_base + port_ene_offset);
- data = INB(port_io_base + port_ene_data);
-
- return data;
-}
-
-static void ene_write(const ene_chip_t *chip, uint16_t addr, uint8_t data)
-{
- uint8_t bank;
- uint8_t offset;
- uint32_t port_io_base;
-
- bank = addr >> 8;
- offset = addr & 0xff;
- port_io_base = chip->port_io_base;
-
- OUTB(bank, port_io_base + port_ene_bank);
- OUTB(offset, port_io_base + port_ene_offset);
-
- OUTB(data, port_io_base + port_ene_data);
-}
-
-/**
- * wait_cycles, wait for n LPC bus clock cycles
- *
- * @param n: number of LPC cycles to wait
- * @return void
- */
-static void wait_cycles(const ene_chip_t *chip,int n)
-{
- while (n--)
- INB(chip->port_io_base + port_ene_bank);
-}
-
-static int is_spicmd_write(uint8_t cmd)
-{
- switch (cmd) {
- case JEDEC_WREN:
- /* Chip Write Enable */
- case JEDEC_EWSR:
- /* Write Status Enable */
- case JEDEC_CE_60:
- /* Chip Erase 0x60 */
- case JEDEC_CE_C7:
- /* Chip Erase 0xc7 */
- case JEDEC_BE_52:
- /* Block Erase 0x52 */
- case JEDEC_BE_D8:
- /* Block Erase 0xd8 */
- case JEDEC_BE_D7:
- /* Block Erase 0xd7 */
- case JEDEC_SE:
- /* Sector Erase */
- case JEDEC_BYTE_PROGRAM:
- /* Write memory byte */
- case JEDEC_AAI_WORD_PROGRAM:
- /* Write AAI word */
- return 1;
- }
- return 0;
-}
-
-static void ene_spi_start(const ene_chip_t *chip)
-{
- int cfg;
-
- cfg = ene_read(chip, REG_SPI_CONFIG);
- cfg |= CFG_CSn_FORCE_LOW;
- cfg |= CFG_COMMAND_WRITE_ENABLE;
- ene_write(chip, REG_SPI_CONFIG, cfg);
-
- wait_cycles(chip, ENE_SPI_DELAY_CYCLE);
-}
-
-static void ene_spi_end(const ene_chip_t *chip)
-{
- int cfg;
-
- cfg = ene_read(chip, REG_SPI_CONFIG);
- cfg &= ~CFG_CSn_FORCE_LOW;
- cfg |= CFG_COMMAND_WRITE_ENABLE;
- ene_write(chip, REG_SPI_CONFIG, cfg);
-
- wait_cycles(chip, ENE_SPI_DELAY_CYCLE);
-}
-
-static int ene_spi_wait(const ene_chip_t *chip)
-{
- struct timeval begin, now;
-
- gettimeofday(&begin, NULL);
- while(ene_read(chip, REG_SPI_CONFIG) & CFG_STATUS) {
- gettimeofday(&now, NULL);
- if ((now.tv_sec - begin.tv_sec) >= EC_COMMAND_TIMEOUT) {
- msg_pdbg("%s: spi busy\n", __func__);
- return 1;
- }
- }
- return 0;
-}
-
-static int ene_pause_ec(ene_lpc_data_t *ctx_data)
-{
- struct timeval begin, now;
- const ene_chip_t *chip = ctx_data->chip;
-
- if (!chip->ec_pause_cmd)
- return -1;
-
- /* EC prepare pause */
- ec_command(chip, chip->ec_pause_cmd, chip->ec_pause_data);
-
- gettimeofday(&begin, NULL);
- /* Spin wait for EC ready */
- while (ene_read(chip, chip->ec_status_buf) !=
- chip->ec_is_pausing) {
- gettimeofday(&now, NULL);
- if ((now.tv_sec - begin.tv_sec) >=
- EC_COMMAND_TIMEOUT) {
- msg_pdbg("%s: unable to pause ec\n", __func__);
- return -1;
- }
- }
-
-
- gettimeofday(&ctx_data->pause_begin, NULL);
- ctx_data->ec_state = EC_STATE_IDLE;
- return 0;
-}
-
-static int ene_resume_ec(ene_lpc_data_t *ctx_data)
-{
- struct timeval begin, now;
- const ene_chip_t *chip = ctx_data->chip;
-
- if (chip->chip_id == ENE_KB94X)
- OUTB(0xff, ENE_KB94X_PAUSE_WAKEUP_PORT);
- else
- /* Trigger 8051 interrupt to resume */
- ene_write(chip, REG_EC_EXTCMD, 0xff);
-
- gettimeofday(&begin, NULL);
- while (ene_read(chip, chip->ec_status_buf) !=
- chip->ec_is_running) {
- gettimeofday(&now, NULL);
- if ((now.tv_sec - begin.tv_sec) >=
- EC_COMMAND_TIMEOUT) {
- msg_pdbg("%s: unable to resume ec\n", __func__);
- return -1;
- }
- }
-
- ctx_data->ec_state = EC_STATE_NORMAL;
- return 0;
-}
-
-static int ene_pause_timeout_check(ene_lpc_data_t *ctx_data)
-{
- struct timeval pause_now;
- gettimeofday(&pause_now, NULL);
- if ((pause_now.tv_sec - ctx_data->pause_begin.tv_sec) >=
- EC_PAUSE_TIMEOUT) {
- if(ene_resume_ec(ctx_data) == 0)
- ene_pause_ec(ctx_data);
-
- }
- return 0;
-}
-
-static int ene_reset_ec(ene_lpc_data_t *ctx_data)
-{
- uint8_t reg;
- struct timeval begin, now;
- const ene_chip_t *chip = ctx_data->chip;
-
- gettimeofday(&begin, NULL);
-
- /* EC prepare reset */
- ec_command(chip, chip->ec_reset_cmd, chip->ec_reset_data);
-
- /* Spin wait for EC ready */
- while (ene_read(chip, chip->ec_status_buf) !=
- chip->ec_is_stopping) {
- gettimeofday(&now, NULL);
- if ((now.tv_sec - begin.tv_sec) >=
- EC_COMMAND_TIMEOUT) {
- msg_pdbg("%s: unable to reset ec\n", __func__);
- return -1;
- }
- }
-
- /* Wait 1 second */
- sleep(1);
-
- /* Reset 8051 */
- reg = ene_read(chip, REG_8051_CTRL);
- reg |= CPU_RESET;
- ene_write(chip, REG_8051_CTRL, reg);
-
- ctx_data->ec_state = EC_STATE_RESET;
- return 0;
-}
-
-static int ene_enter_flash_mode(ene_lpc_data_t *ctx_data)
-{
- if (ene_pause_ec(ctx_data))
- return ene_reset_ec(ctx_data);
- return 0;
-}
-
-static int ene_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
-{
- unsigned int i;
- int tries = EC_RESET_TRIES;
- ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)flash->mst->spi.data;
- const ene_chip_t *chip = ctx_data->chip;
-
- if (ctx_data->ec_state == EC_STATE_IDLE && is_spicmd_write(writearr[0])) {
- do {
- /* Enter reset mode if we need to write/erase */
- if (ene_resume_ec(ctx_data))
- continue;
-
- if (!ene_reset_ec(ctx_data))
- break;
- } while (--tries > 0);
-
- if (!tries) {
- msg_perr("%s: EC failed reset, skipping write\n", __func__);
- ctx_data->ec_state = EC_STATE_IDLE;
- return 1;
- }
- }
- else if(chip->chip_id == ENE_KB94X && ctx_data->ec_state == EC_STATE_IDLE)
- ene_pause_timeout_check(ctx_data);
-
- ene_spi_start(chip);
-
- for (i = 0; i < writecnt; i++) {
- ene_write(chip, REG_SPI_COMMAND, writearr[i]);
- if (ene_spi_wait(chip)) {
- msg_pdbg("%s: write count %d\n", __func__, i);
- return 1;
- }
- }
-
- for (i = 0; i < readcnt; i++) {
- /* Push data by clock the serial bus */
- ene_write(chip, REG_SPI_COMMAND, 0);
- if (ene_spi_wait(chip)) {
- msg_pdbg("%s: read count %d\n", __func__, i);
- return 1;
- }
- readarr[i] = ene_read(chip, REG_SPI_DATA);
- if (ene_spi_wait(chip)) {
- msg_pdbg("%s: read count %d\n", __func__, i);
- return 1;
- }
- }
-
- ene_spi_end(chip);
- return 0;
-}
-
-static int ene_leave_flash_mode(void *data)
-{
- ene_lpc_data_t *ctx_data = (ene_lpc_data_t *)data;
- const ene_chip_t *chip = ctx_data->chip;
- int rv = 0;
- uint8_t reg;
- struct timeval begin, now;
-
- if (ctx_data->ec_state == EC_STATE_RESET) {
- reg = ene_read(chip, REG_8051_CTRL);
- reg &= ~CPU_RESET;
- ene_write(chip, REG_8051_CTRL, reg);
-
- gettimeofday(&begin, NULL);
- /* EC restart */
- while (ene_read(chip, chip->ec_status_buf) !=
- chip->ec_is_running) {
- gettimeofday(&now, NULL);
- if ((now.tv_sec - begin.tv_sec) >=
- EC_RESTART_TIMEOUT) {
- msg_pdbg("%s: ec restart busy\n", __func__);
- rv = 1;
- goto exit;
- }
- }
- msg_pdbg("%s: send ec restart\n", __func__);
- ec_command(chip, chip->ec_restart_cmd,
- chip->ec_restart_data);
-
- ctx_data->ec_state = EC_STATE_NORMAL;
- rv = 0;
- goto exit;
- }
-
- rv = ene_resume_ec(ctx_data);
-
-exit:
- /*
- * Trigger ec interrupt after pause/reset by sending 0x80
- * to bios command port.
- */
- OUTB(0x80, chip->port_bios);
- free(data);
- return rv;
-}
-
-static struct spi_master spi_master_ene = {
- .max_data_read = 256,
- .max_data_write = 256,
- .command = ene_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
-};
-
-int ene_lpc_init()
-{
- uint8_t hwver, ediid, i;
- int ret = 0;
- char *p = NULL;
- ene_lpc_data_t *ctx_data = NULL;
-
- msg_pdbg("%s\n", __func__);
-
- ctx_data = calloc(1, sizeof(ene_lpc_data_t));
- if (!ctx_data) {
- msg_perr("Unable to allocate space for extra context data.\n");
- return 1;
- }
- ctx_data->ec_state = EC_STATE_NORMAL;
-
- p = extract_programmer_param("type");
- if (p && strcmp(p, "ec")) {
- msg_pdbg("ene_lpc only supports \"ec\" type devices\n");
- ret = 1;
- goto ene_probe_spi_flash_exit;
- }
-
- for (i = 0; i < ENE_LAST; ++i) {
- ctx_data->chip = &ene_chips[i];
-
- hwver = ene_read(ctx_data->chip, REG_EC_HWVER);
- ediid = ene_read(ctx_data->chip, REG_EC_EDIID);
-
- if(hwver == ene_chips[i].hwver &&
- ediid == ene_chips[i].ediid) {
- break;
- }
- }
-
- if (i == ENE_LAST) {
- msg_pdbg("ENE EC not found (probe failed)\n");
- ret = 1;
- goto ene_probe_spi_flash_exit;
- }
-
- /* TODO: probe the EC stop protocol
- *
- * Compal - ec_command(0x41, 0xa1) returns 43 4f 4d 50 41 4c 9c
- */
-
-
- if (register_shutdown(ene_leave_flash_mode, ctx_data)) {
- ret = 1;
- goto ene_probe_spi_flash_exit;
- }
-
- ene_enter_flash_mode(ctx_data);
-
- internal_buses_supported |= BUS_LPC;
- spi_master_ene.data = ctx_data;
- register_spi_master(&spi_master_ene);
- msg_pdbg("%s: successfully initialized ene\n", __func__);
-
-ene_probe_spi_flash_exit:
- free(p);
- if (ret)
- free(ctx_data);
- return ret;
-}
-
-#endif /* __i386__ || __x86_64__ */
diff --git a/erasure_layout.c b/erasure_layout.c
new file mode 100644
index 000000000..c9ac44bc5
--- /dev/null
+++ b/erasure_layout.c
@@ -0,0 +1,408 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2022 Aarya Chaumal
+ *
+ * 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 <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+
+#include "flash.h"
+#include "layout.h"
+#include "erasure_layout.h"
+
+static size_t calculate_block_count(const struct flashchip *chip, size_t eraser_idx)
+{
+ size_t block_count = 0;
+
+ chipoff_t addr = 0;
+ for (size_t i = 0; addr < chip->total_size * 1024; i++) {
+ const struct eraseblock *block = &chip->block_erasers[eraser_idx].eraseblocks[i];
+ block_count += block->count;
+ addr += block->size * block->count;
+ }
+
+ return block_count;
+}
+
+static void init_eraseblock(struct erase_layout *layout, size_t idx, size_t block_num,
+ chipoff_t start_addr, chipoff_t end_addr, size_t *sub_block_index)
+{
+ struct eraseblock_data *edata = &layout[idx].layout_list[block_num];
+ edata->start_addr = start_addr;
+ edata->end_addr = end_addr;
+ edata->selected = false;
+ edata->block_num = block_num;
+
+ if (!idx)
+ return;
+
+ edata->first_sub_block_index = *sub_block_index;
+ struct eraseblock_data *subedata = &layout[idx - 1].layout_list[*sub_block_index];
+ while (subedata->start_addr >= start_addr && subedata->end_addr <= end_addr &&
+ *sub_block_index < layout[idx-1].block_count) {
+ (*sub_block_index)++;
+ subedata++;
+ }
+ edata->last_sub_block_index = *sub_block_index - 1;
+}
+
+/*
+ * @brief Function to free the created erase_layout
+ *
+ * @param layout pointer to allocated layout
+ * @param erasefn_count number of erase functions for which the layout was created
+ *
+ */
+void free_erase_layout(struct erase_layout *layout, unsigned int erasefn_count)
+{
+ if (!layout)
+ return;
+ for (size_t i = 0; i < erasefn_count; i++) {
+ free(layout[i].layout_list);
+ }
+ free(layout);
+}
+
+/*
+ * @brief Function to create an erase layout
+ *
+ * @param flashctx flash context
+ * @param e_layout address to the pointer to store the layout
+ * @return 0 on success,
+ * -1 if layout creation fails
+ *
+ * This function creates a layout of which erase functions erase which regions
+ * of the flash chip. This helps to optimally select the erase functions for
+ * erase/write operations.
+ */
+int create_erase_layout(struct flashctx *const flashctx, struct erase_layout **e_layout)
+{
+ const struct flashchip *chip = flashctx->chip;
+ const size_t erasefn_count = count_usable_erasers(flashctx);
+ if (!erasefn_count) {
+ msg_gerr("No erase functions supported\n");
+ return 0;
+ }
+
+ struct erase_layout *layout = calloc(erasefn_count, sizeof(struct erase_layout));
+ if (!layout) {
+ msg_gerr("Out of memory!\n");
+ return -1;
+ }
+
+ size_t layout_idx = 0;
+ for (size_t eraser_idx = 0; eraser_idx < NUM_ERASEFUNCTIONS; eraser_idx++) {
+ if (check_block_eraser(flashctx, eraser_idx, 0))
+ continue;
+
+ layout[layout_idx].eraser = &chip->block_erasers[eraser_idx];
+ const size_t block_count = calculate_block_count(flashctx->chip, eraser_idx);
+ size_t sub_block_index = 0;
+
+ layout[layout_idx].block_count = block_count;
+ layout[layout_idx].layout_list = (struct eraseblock_data *)calloc(block_count,
+ sizeof(struct eraseblock_data));
+
+ if (!layout[layout_idx].layout_list) {
+ free_erase_layout(layout, layout_idx);
+ return -1;
+ }
+
+ size_t block_num = 0;
+ chipoff_t start_addr = 0;
+
+ for (int i = 0; block_num < block_count; i++) {
+ const struct eraseblock *block = &chip->block_erasers[eraser_idx].eraseblocks[i];
+
+ for (size_t num = 0; num < block->count; num++) {
+ chipoff_t end_addr = start_addr + block->size - 1;
+ init_eraseblock(layout, layout_idx, block_num,
+ start_addr, end_addr, &sub_block_index);
+ block_num += 1;
+ start_addr = end_addr + 1;
+ }
+ }
+ layout_idx++;
+ }
+
+ *e_layout = layout;
+ return layout_idx;
+}
+
+/*
+ * @brief Function to align start and address of the region boundaries
+ *
+ * @param layout erase layout
+ * @param flashctx flash context
+ * @param region_start pointer to start address of the region to align
+ * @param region_end pointer to end address of the region to align
+ *
+ * This function aligns start and end address of the region (in struct walk_info)
+ * to some erase sector boundaries and modify the region start and end addresses
+ * to match nearest erase sector boundaries. This function will be used in the
+ * new algorithm for erase function selection.
+ */
+static void align_region(const struct erase_layout *layout, struct flashctx *const flashctx,
+ chipoff_t *region_start, chipoff_t *region_end)
+{
+ chipoff_t start_diff = UINT_MAX, end_diff = UINT_MAX;
+ const size_t erasefn_count = count_usable_erasers(flashctx);
+ for (size_t i = 0; i < erasefn_count; i++) {
+ for (size_t j = 0; j < layout[i].block_count; j++) {
+ const struct eraseblock_data *ll = &layout[i].layout_list[j];
+ if (ll->start_addr <= *region_start)
+ start_diff = (*region_start - ll->start_addr) > start_diff ?
+ start_diff : (*region_start - ll->start_addr);
+ if (ll->end_addr >= *region_end)
+ end_diff = (ll->end_addr - *region_end) > end_diff ?
+ end_diff : (ll->end_addr - *region_end);
+ }
+ }
+
+ if (start_diff) {
+ msg_cinfo("Region start not sector aligned! Extending start boundaries...\n");
+ *region_start = *region_start - start_diff;
+ }
+ if (end_diff) {
+ msg_cinfo("Region end not sector aligned! Extending end boundaries...\n");
+ *region_end = *region_end + end_diff;
+ }
+}
+
+/*
+ * @brief Function to select the list of sectors that need erasing
+ *
+ * @param flashctx flash context
+ * @param layout erase layout
+ * @param findex index of the erase function
+ * @param block_num index of the block to erase according to the erase function index
+ * @param curcontents buffer containg the current contents of the flash
+ * @param newcontents buffer containg the new contents of the flash
+ * @param rstart start address of the region
+ * @rend rend end address of the region
+ */
+static void select_erase_functions(struct flashctx *flashctx, const struct erase_layout *layout,
+ size_t findex, size_t block_num, uint8_t *curcontents, uint8_t *newcontents,
+ chipoff_t rstart, chipoff_t rend)
+{
+ struct eraseblock_data *ll = &layout[findex].layout_list[block_num];
+ if (!findex) {
+ if (ll->start_addr >= rstart && ll->end_addr <= rend) {
+ chipoff_t start_addr = ll->start_addr;
+ chipoff_t end_addr = ll->end_addr;
+ const chipsize_t erase_len = end_addr - start_addr + 1;
+ const uint8_t erased_value = ERASED_VALUE(flashctx);
+ ll->selected = need_erase(curcontents + start_addr, newcontents + start_addr, erase_len,
+ flashctx->chip->gran, erased_value);
+ }
+ } else {
+ int count = 0;
+ const int sub_block_start = ll->first_sub_block_index;
+ const int sub_block_end = ll->last_sub_block_index;
+
+ for (int j = sub_block_start; j <= sub_block_end; j++) {
+ select_erase_functions(flashctx, layout, findex - 1, j, curcontents, newcontents,
+ rstart, rend);
+ if (layout[findex - 1].layout_list[j].selected)
+ count++;
+ }
+
+ const int total_blocks = sub_block_end - sub_block_start + 1;
+ if (count && count > total_blocks/2) {
+ if (ll->start_addr >= rstart && ll->end_addr <= rend) {
+ for (int j = sub_block_start; j <= sub_block_end; j++)
+ layout[findex - 1].layout_list[j].selected = false;
+ ll->selected = true;
+ }
+ }
+ }
+}
+
+/*
+ * @brief wrapper to use the erase algorithm
+ *
+ * @param flashctx flash context
+ * @param region_start start address of the region
+ * @param region_end end address of the region
+ * @param curcontents buffer containg the current contents of the flash
+ * @param newcontents buffer containg the new contents of the flash
+ * @param erase_layout erase layout
+ * @param all_skipped pointer to the flag to chec if any block was erased
+ */
+int erase_write(struct flashctx *const flashctx, chipoff_t region_start, chipoff_t region_end,
+ uint8_t *curcontents, uint8_t *newcontents,
+ struct erase_layout *erase_layout, bool *all_skipped)
+{
+ const size_t erasefn_count = count_usable_erasers(flashctx);
+ int ret = 0;
+ size_t i;
+ chipoff_t old_start = region_start, old_end = region_end;
+ align_region(erase_layout, flashctx, &region_start, &region_end);
+
+ uint8_t *old_start_buf = NULL, *old_end_buf = NULL;
+ old_start_buf = (uint8_t *)malloc(old_start - region_start);
+ if (!old_start_buf) {
+ msg_cerr("Not enough memory!\n");
+ ret = -1;
+ goto _end;
+ }
+ old_end_buf = (uint8_t *)malloc(region_end - old_end);
+ if (!old_end_buf) {
+ msg_cerr("Not enough memory!\n");
+ ret = -1;
+ goto _end;
+ }
+
+ if (old_start - region_start) {
+ read_flash(flashctx, curcontents + region_start, region_start, old_start - region_start);
+ memcpy(old_start_buf, newcontents + region_start, old_start - region_start);
+ memcpy(newcontents + region_start, curcontents + region_start, old_start - region_start);
+ }
+ if (region_end - old_end) {
+ read_flash(flashctx, curcontents + old_end, old_end, region_end - old_end);
+ memcpy(old_end_buf, newcontents + old_end, region_end - old_end);
+ memcpy(newcontents + old_end, curcontents + old_end, region_end - old_end);
+ }
+
+ // select erase functions
+ for (i = 0; i < erase_layout[erasefn_count - 1].block_count; i++) {
+ if (erase_layout[erasefn_count - 1].layout_list[i].start_addr <= region_end &&
+ region_start <= erase_layout[erasefn_count - 1].layout_list[i].end_addr)
+ select_erase_functions(flashctx, erase_layout,
+ erasefn_count - 1, i,
+ curcontents, newcontents,
+ region_start, region_end);
+ }
+
+ for (i = 0; i < erasefn_count; i++) {
+ for (size_t j = 0; j < erase_layout[i].block_count; j++) {
+ if (!erase_layout[i].layout_list[j].selected) continue;
+
+ // erase
+ chipoff_t start_addr = erase_layout[i].layout_list[j].start_addr;
+ unsigned int block_len = erase_layout[i].layout_list[j].end_addr - start_addr + 1;
+ const uint8_t erased_value = ERASED_VALUE(flashctx);
+ // execute erase
+ erasefunc_t *erasefn = lookup_erase_func_ptr(erase_layout[i].eraser);
+
+ if (!flashctx->flags.skip_unwritable_regions) {
+ if (check_for_unwritable_regions(flashctx, start_addr, block_len))
+ goto _end;
+ }
+
+ unsigned int len;
+ for (unsigned int addr = start_addr; addr < start_addr + block_len; addr += len) {
+ struct flash_region region;
+ get_flash_region(flashctx, addr, &region);
+
+ len = min(start_addr + block_len, region.end) - addr;
+
+ if (region.write_prot) {
+ msg_gdbg("%s: cannot erase inside %s "
+ "region (%#08"PRIx32"..%#08"PRIx32"), skipping range (%#08x..%#08x).\n",
+ __func__, region.name,
+ region.start, region.end - 1,
+ addr, addr + len - 1);
+ free(region.name);
+ continue;
+ }
+
+ msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is "
+ "writable, erasing range (%#08x..%#08x).\n",
+ __func__, region.name,
+ region.start, region.end - 1,
+ addr, addr + len - 1);
+ free(region.name);
+
+ if (erasefn(flashctx, addr, len)) {
+ ret = -1;
+ goto _end;
+ }
+ if (check_erased_range(flashctx, addr, len)) {
+ ret = - 1;
+ msg_cerr("ERASE FAILED!\n");
+ goto _end;
+ }
+ }
+
+ ret = erasefn(flashctx, start_addr, block_len);
+ if (ret) {
+ msg_cerr("Failed to execute erase command "
+ "for offset %#"PRIx32" to %#"PRIx32".\n",
+ start_addr, start_addr + block_len);
+ ret = -1;
+ goto _end;
+ }
+
+ // adjust curcontents
+ memset(curcontents+start_addr, erased_value, block_len);
+ // after erase make it unselected again
+ erase_layout[i].layout_list[j].selected = false;
+ msg_cdbg("E(%"PRIx32":%"PRIx32")", start_addr, start_addr + block_len - 1);
+ // verify erase
+ ret = check_erased_range(flashctx, start_addr, block_len);
+ if (ret) {
+ msg_cerr("Verifying flash. Erase failed for range %#"PRIx32" : %#"PRIx32", Abort.\n",
+ start_addr, start_addr + block_len - 1);
+ goto _end;
+ }
+
+ *all_skipped = false;
+ }
+ }
+
+ // write
+ unsigned int start_here = 0, len_here = 0, erase_len = region_end - region_start + 1;
+ while ((len_here = get_next_write(curcontents + region_start + start_here,
+ newcontents + region_start + start_here,
+ erase_len - start_here, &start_here,
+ flashctx->chip->gran))) {
+ // execute write
+ ret = write_flash(flashctx,
+ newcontents + region_start + start_here,
+ region_start + start_here, len_here);
+ if (ret) {
+ msg_cerr("Write failed at %#zx, Abort.\n", i);
+ ret = -1;
+ goto _end;
+ }
+
+ // adjust curcontents
+ memcpy(curcontents + region_start + start_here,
+ newcontents + region_start + start_here, len_here);
+ msg_cdbg("W(%"PRIx32":%"PRIx32")", region_start + start_here, region_start + start_here + len_here - 1);
+
+ *all_skipped = false;
+ }
+ // verify write
+ ret = verify_range(flashctx, newcontents + region_start, region_start, region_end - region_start);
+ if (ret) {
+ msg_cerr("Verifying flash. Write failed for range %#"PRIx32" : %#"PRIx32", Abort.\n",
+ region_start, region_end);
+ goto _end;
+ }
+
+_end:
+ memcpy(newcontents + region_start, old_start_buf, old_start - region_start);
+ memcpy(newcontents + old_end, old_end_buf, region_end - old_end);
+
+ free(old_start_buf);
+ free(old_end_buf);
+
+ msg_cinfo("Erase/write done from %"PRIx32" to %"PRIx32"\n", region_start, region_end);
+ return ret;
+}
diff --git a/flashchips.c b/flashchips.c
index 38b0bfd09..26decb1ed 100644
--- a/flashchips.c
+++ b/flashchips.c
@@ -66,7 +66,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_SHORT_RESET | FEATURE_ADDR_2AA,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -77,14 +77,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4750, 5250}, /* 4.75-5.25V for type -55, others 4.5-5.5V */
},
@@ -98,7 +98,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_EITHER_RESET | FEATURE_ADDR_2AA,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -109,14 +109,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4750, 5250}, /* 4.75-5.25V for type -55, others 4.5-5.5V */
},
@@ -130,20 +130,20 @@ const struct flashchip flashchips[] = {
.page_size = 16 * 1024,
.feature_bits = FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {16 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -157,20 +157,20 @@ const struct flashchip flashchips[] = {
.page_size = 16 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PRE,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {16 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -184,20 +184,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -211,20 +211,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -238,20 +238,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -265,20 +265,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -292,20 +292,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -319,7 +319,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -329,14 +329,14 @@ const struct flashchip flashchips[] = {
{4 * 1024, 2},
{16 * 1024, 7},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -45R, others 2.7-3.6V */
},
@@ -350,7 +350,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -360,14 +360,14 @@ const struct flashchip flashchips[] = {
{4 * 1024, 2},
{8 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -45R, others 2.7-3.6V */
},
@@ -381,7 +381,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -392,14 +392,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -55, others 2.7-3.6V */
},
@@ -413,7 +413,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -424,14 +424,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -55, others 2.7-3.6V */
},
@@ -445,7 +445,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -456,14 +456,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 7},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -477,7 +477,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -488,14 +488,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -509,7 +509,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -520,14 +520,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 15},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -70R, others 2.7-3.6V */
},
@@ -541,7 +541,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -552,14 +552,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -70R, others 2.7-3.6V */
},
@@ -572,21 +572,21 @@ const struct flashchip flashchips[] = {
.total_size = 512,
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
- .tested = TEST_OK_PRE,
- .probe = probe_jedec,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -60R, others 2.7-3.6V*/
},
@@ -600,20 +600,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET, /* datasheet specifies address as don't care */
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -70R, others 2.7-3.6V */
},
@@ -627,25 +627,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 32 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 64 * 1024, 2 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 128 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -659,25 +659,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 512 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 64 * 1024, 32 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 2048 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -691,25 +691,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 64 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 64 * 1024, 4 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 256 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -724,31 +724,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, 0x48; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 1024 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 64 * 1024, 64 } },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { { 64 * 1024, 64 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 4096 * 1024, 1 } },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 4096 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_amic_a25l032, /* bit5: T/B, bit6: prot size */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AMIC_A25L032, /* bit5: T/B, bit6: prot size */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -762,25 +762,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 128 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 64 * 1024, 8 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 512 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -794,7 +794,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -805,16 +805,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -828,7 +828,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -839,16 +839,16 @@ const struct flashchip flashchips[] = {
{16 * 1024, 1},
{32 * 1024, 1},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -862,25 +862,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 256 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 64 * 1024, 16 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 1024 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -894,7 +894,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -906,16 +906,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -929,7 +929,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -941,16 +941,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 1},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -964,7 +964,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -976,19 +976,19 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1002,7 +1002,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PR,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -1014,19 +1014,19 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 31},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1040,7 +1040,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -1052,16 +1052,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1075,7 +1075,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -1087,16 +1087,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1115,7 +1115,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PR,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -1127,16 +1127,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1150,7 +1150,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -1162,16 +1162,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 7},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1185,25 +1185,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 16 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 64 * 1024, 1 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 64 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1217,7 +1217,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PRE,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -1229,16 +1229,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 15},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1254,31 +1254,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, 0x48; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 1024 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 64 * 1024, 64 } },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { { 64 * 1024, 64 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 4096 * 1024, 1 } },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 4096 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_amic_a25l032, /* bit5: T/B, bit6: prot size */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AMIC_A25L032, /* bit5: T/B, bit6: prot size */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1294,31 +1294,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, 0x48; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 512 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 64 * 1024, 32 } },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { { 64 * 1024, 32 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 2048 * 1024, 1 } },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 2048 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_amic_a25l032, /* bit5: T/B, bit6: prot size */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AMIC_A25L032, /* bit5: T/B, bit6: prot size */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1335,31 +1335,31 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x35, disable 0xF5 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 2048 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 32 * 1024, 256 } },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { { 64 * 1024, 128 } },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 8192 * 1024, 1 } },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 8192 * 1024, 1 } },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enhance (sic!) */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enhance (sic!) */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1373,7 +1373,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -1384,14 +1384,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -1405,7 +1405,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -1416,14 +1416,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -1437,20 +1437,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -1464,26 +1464,65 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PR,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
{
.vendor = "Atmel",
+ .name = "AT25DF011",
+ .bustype = BUS_SPI,
+ .manufacture_id = ATMEL_ID,
+ .model_id = ATMEL_AT25DF011,
+ .total_size = 128,
+ .page_size = 256,
+ /* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 4} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {32 * 1024, 4} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {128 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {128 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1650, 3600},
+ },
+
+ {
+ .vendor = "Atmel",
.name = "AT25DF021",
.bustype = BUS_SPI,
.manufacture_id = ATMEL_ID,
@@ -1493,31 +1532,31 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600}, /* 2.3-3.6V & 2.7-3.6V models available */
},
@@ -1532,31 +1571,31 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 3600},
},
@@ -1570,31 +1609,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600}, /* 2.3-3.6V & 2.7-3.6V models available */
},
@@ -1608,31 +1647,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1600, 2000}, /* Datasheet says range is 1.65-1.95 V */
},
@@ -1646,31 +1685,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df_sec,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF_SEC,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT_SEC,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1684,31 +1723,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df_sec,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF_SEC,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT_SEC,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1723,31 +1762,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1762,31 +1801,31 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df_sec,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF_SEC,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT_SEC,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1800,31 +1839,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df_sec,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF_SEC,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT_SEC,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1839,31 +1878,31 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df_sec,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec,
- .write = spi_chip_write_256, /* Dual I/O (0xA2) supported */
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF_SEC,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT_SEC,
+ .write = SPI_CHIP_WRITE256, /* Dual I/O (0xA2) supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O (0x3B) supported */
.voltage = {1650, 1950},
},
@@ -1878,31 +1917,31 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df_sec,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec,
- .write = spi_chip_write_256, /* Dual I/O (0xA2) supported */
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF_SEC,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT_SEC,
+ .write = SPI_CHIP_WRITE256, /* Dual I/O (0xA2) supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O (0x3B) supported */
.voltage = {1650, 1950},
},
@@ -1917,31 +1956,31 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df_sec,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect_sec,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF_SEC,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT_SEC,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1957,22 +1996,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at25f,
+ .probe = PROBE_SPI_AT25F,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_62,
+ .block_erase = SPI_BLOCK_ERASE_62,
}
},
- .printlock = spi_prettyprint_status_register_at25f,
- .unlock = spi_disable_blockprotect_at25f,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25F,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT25F,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -1986,22 +2025,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_at25f,
+ .probe = PROBE_SPI_AT25F,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_62,
+ .block_erase = SPI_BLOCK_ERASE_62,
}
},
- .printlock = spi_prettyprint_status_register_at25f,
- .unlock = spi_disable_blockprotect_at25f,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25F,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT25F,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2015,23 +2054,23 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at25f,
+ .probe = PROBE_SPI_AT25F,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_62,
+ .block_erase = SPI_BLOCK_ERASE_62,
}
},
- .printlock = spi_prettyprint_status_register_at25f4096,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25F4096,
/* "Bits 5-6 are 0s when device is not in an internal write cycle." Better leave them alone: */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2045,22 +2084,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at25f,
+ .probe = PROBE_SPI_AT25F,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_62,
+ .block_erase = SPI_BLOCK_ERASE_62,
}
},
- .printlock = spi_prettyprint_status_register_at25f,
- .unlock = spi_disable_blockprotect_at25f,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25F,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT25F,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2074,23 +2113,23 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at25f,
+ .probe = PROBE_SPI_AT25F,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_62,
+ .block_erase = SPI_BLOCK_ERASE_62,
}
},
- .printlock = spi_prettyprint_status_register_at25f512a,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25F512A,
/* FIXME: It is not correct to use this one, because the BP1 bit is N/A. */
- .unlock = spi_disable_blockprotect_at25f512a,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT25F512A,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2105,34 +2144,34 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_62,
+ .block_erase = SPI_BLOCK_ERASE_62,
}
},
- .printlock = spi_prettyprint_status_register_at25f512b,
- .unlock = spi_disable_blockprotect_at25f512b,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25F512B,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT25F512B,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2146,34 +2185,34 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25fs010,
- .unlock = spi_disable_blockprotect_at25fs010,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25FS010,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT25FS010,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2187,31 +2226,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25fs040,
- .unlock = spi_disable_blockprotect_at25fs040,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25FS040,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT25FS040,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2225,31 +2264,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2500, 3600},
},
@@ -2263,36 +2302,74 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
{
.vendor = "Atmel",
+ .name = "AT25SF128A",
+ .bustype = BUS_SPI,
+ .manufacture_id = ATMEL_ID,
+ .model_id = ATMEL_AT25SF128A,
+ .total_size = 16384,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
+ .tested = TEST_OK_PR,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 4096} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {16 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {16 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1700, 2000},
+ },
+
+ {
+ .vendor = "Atmel",
.name = "AT25SF161",
.bustype = BUS_SPI,
.manufacture_id = ATMEL_ID,
@@ -2301,31 +2378,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2500, 3600},
},
@@ -2339,31 +2416,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PR,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4096 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4096 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2500, 3600},
},
@@ -2376,34 +2453,44 @@ const struct flashchip flashchips[] = {
.total_size = 16384,
.page_size = 256,
/* supports SFDP */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR2,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 2000},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -2416,25 +2503,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* does not support EWSR nor WREN and has no writable status register bits whatsoever */
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 2048} },
- .block_erase = spi_block_erase_81,
+ .block_erase = SPI_BLOCK_ERASE_81,
}, {
.eraseblocks = { {2 * 1024, 256} },
- .block_erase = spi_block_erase_50,
+ .block_erase = SPI_BLOCK_ERASE_50,
}, {
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}
},
- .printlock = spi_prettyprint_status_register_plain,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
/* Supports also an incompatible page write (of exactly 256 B) and an auto-erasing write. */
- .write = spi_chip_write_1,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .write = SPI_CHIP_WRITE1,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600}, /* 3.0-3.6V for higher speed, 2.7-3.6V normal */
},
@@ -2448,31 +2535,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at26df081a,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT26DF081A,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2486,31 +2573,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at25df,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2524,31 +2611,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_at26df081a,
- .unlock = spi_disable_blockprotect_at2x_global_unprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT26DF081A,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2562,30 +2649,30 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = {.probe = NT, .read = NT, .erase = NT, .write = BAD},
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .write = NULL, /* Incompatible Page write */
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .write = 0, /* Incompatible Page write */
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -2599,17 +2686,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PRE,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10000, /* 10mS, Enter=Exec */
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec, /* FIXME */
- .read = read_memmapped,
+ .write = WRITE_JEDEC, /* FIXME */
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -2623,17 +2710,17 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10000, /* 10ms */
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -2647,17 +2734,17 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10000, /* 10 ms */
.block_erasers =
{
{
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -2671,17 +2758,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10000, /* 10mS, Enter=Exec */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -2697,7 +2784,7 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77 (4 dummy bytes); write 0x9A (via buffer) */
.feature_bits = FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -2707,14 +2794,14 @@ const struct flashchip flashchips[] = {
{248 * 1056, 1}, /* sector 0b: opcode 7Ch */
{256 * 1056, 63}, /* sectors 1 - 63: opcode 7Ch */
},
- .block_erase = spi_erase_at45cs_sector,
+ .block_erase = SPI_ERASE_AT45CS_SECTOR,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .write = spi_write_at45db,
- .read = spi_read_at45db,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB,
.voltage = {2700, 3600},
- .gran = write_gran_1056bytes,
+ .gran = WRITE_GRAN_1056BYTES,
},
{
@@ -2729,33 +2816,33 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at45db,
+ .probe = PROBE_SPI_AT45DB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 512} },
- .block_erase = spi_erase_at45db_page,
+ .block_erase = SPI_ERASE_AT45DB_PAGE,
}, {
.eraseblocks = { {8 * 256, 512/8} },
- .block_erase = spi_erase_at45db_block,
+ .block_erase = SPI_ERASE_AT45DB_BLOCK,
}, {
.eraseblocks = {
{8 * 256, 1},
{120 * 256, 1},
{128 * 256, 3},
},
- .block_erase = spi_erase_at45db_sector
+ .block_erase = SPI_ERASE_AT45DB_SECTOR
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_erase_at45db_chip,
+ .block_erase = SPI_ERASE_AT45DB_CHIP,
}
},
- .printlock = spi_prettyprint_status_register_at45db,
- .unlock = spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT45DB, /* Impossible if locked down or #WP is low */
/* granularity will be set by the probing function. */
- .write = spi_write_at45db,
- .read = spi_read_at45db, /* Fast read (0x0B) supported */
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -2771,33 +2858,33 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at45db,
+ .probe = PROBE_SPI_AT45DB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 1024} },
- .block_erase = spi_erase_at45db_page,
+ .block_erase = SPI_ERASE_AT45DB_PAGE,
}, {
.eraseblocks = { {8 * 256, 1024/8} },
- .block_erase = spi_erase_at45db_block,
+ .block_erase = SPI_ERASE_AT45DB_BLOCK,
}, {
.eraseblocks = {
{8 * 256, 1},
{120 * 256, 1},
{128 * 256, 7},
},
- .block_erase = spi_erase_at45db_sector
+ .block_erase = SPI_ERASE_AT45DB_SECTOR
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_erase_at45db_chip,
+ .block_erase = SPI_ERASE_AT45DB_CHIP,
}
},
- .printlock = spi_prettyprint_status_register_at45db,
- .unlock = spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT45DB, /* Impossible if locked down or #WP is low */
/* granularity will be set by the probing function. */
- .write = spi_write_at45db,
- .read = spi_read_at45db, /* Fast read (0x0B) supported */
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -2813,33 +2900,33 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at45db,
+ .probe = PROBE_SPI_AT45DB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 2048} },
- .block_erase = spi_erase_at45db_page,
+ .block_erase = SPI_ERASE_AT45DB_PAGE,
}, {
.eraseblocks = { {8 * 256, 2048/8} },
- .block_erase = spi_erase_at45db_block,
+ .block_erase = SPI_ERASE_AT45DB_BLOCK,
}, {
.eraseblocks = {
{8 * 256, 1},
{248 * 256, 1},
{256 * 256, 7},
},
- .block_erase = spi_erase_at45db_sector
+ .block_erase = SPI_ERASE_AT45DB_SECTOR
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_erase_at45db_chip,
+ .block_erase = SPI_ERASE_AT45DB_CHIP,
}
},
- .printlock = spi_prettyprint_status_register_at45db,
- .unlock = spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT45DB, /* Impossible if locked down or #WP is low */
/* granularity will be set by the probing function. */
- .write = spi_write_at45db,
- .read = spi_read_at45db, /* Fast read (0x0B) supported */
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB, /* Fast read (0x0B) supported */
.voltage = {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
},
@@ -2855,33 +2942,33 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at45db,
+ .probe = PROBE_SPI_AT45DB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 4096} },
- .block_erase = spi_erase_at45db_page,
+ .block_erase = SPI_ERASE_AT45DB_PAGE,
}, {
.eraseblocks = { {8 * 256, 4096/8} },
- .block_erase = spi_erase_at45db_block,
+ .block_erase = SPI_ERASE_AT45DB_BLOCK,
}, {
.eraseblocks = {
{8 * 256, 1},
{248 * 256, 1},
{256 * 256, 15},
},
- .block_erase = spi_erase_at45db_sector
+ .block_erase = SPI_ERASE_AT45DB_SECTOR
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_erase_at45db_chip,
+ .block_erase = SPI_ERASE_AT45DB_CHIP,
}
},
- .printlock = spi_prettyprint_status_register_at45db,
- .unlock = spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT45DB, /* Impossible if locked down or #WP is low */
/* granularity will be set by the probing function. */
- .write = spi_write_at45db,
- .read = spi_read_at45db, /* Fast read (0x0B) supported */
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB, /* Fast read (0x0B) supported */
.voltage = {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
},
@@ -2897,33 +2984,33 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at45db,
+ .probe = PROBE_SPI_AT45DB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {512, 4096} },
- .block_erase = spi_erase_at45db_page,
+ .block_erase = SPI_ERASE_AT45DB_PAGE,
}, {
.eraseblocks = { {8 * 512, 4096/8} },
- .block_erase = spi_erase_at45db_block,
+ .block_erase = SPI_ERASE_AT45DB_BLOCK,
}, {
.eraseblocks = {
{8 * 512, 1},
{248 * 512, 1},
{256 * 512, 15},
},
- .block_erase = spi_erase_at45db_sector
+ .block_erase = SPI_ERASE_AT45DB_SECTOR
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_erase_at45db_chip,
+ .block_erase = SPI_ERASE_AT45DB_CHIP,
}
},
- .printlock = spi_prettyprint_status_register_at45db,
- .unlock = spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT45DB, /* Impossible if locked down or #WP is low */
/* granularity will be set by the probing function. */
- .write = spi_write_at45db,
- .read = spi_read_at45db, /* Fast read (0x0B) supported */
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB, /* Fast read (0x0B) supported */
.voltage = {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
},
@@ -2939,16 +3026,16 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77 (4 dummy bytes); write 0x9A (via buffer) */
.feature_bits = FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {528, 8192} },
- .block_erase = spi_erase_at45db_page,
+ .block_erase = SPI_ERASE_AT45DB_PAGE,
}, {
.eraseblocks = { {8 * 528, 8192/8} },
- .block_erase = spi_erase_at45db_block,
+ .block_erase = SPI_ERASE_AT45DB_BLOCK,
}, /* Although the datasheets describes sectors (which can be write protected)
* there seems to be no erase functions for them.
{
@@ -2957,17 +3044,17 @@ const struct flashchip flashchips[] = {
{120 * 528, 1},
{128 * 528, 63},
},
- .block_erase = spi_erase_at45db_sector
+ .block_erase = SPI_ERASE_AT45DB_SECTOR
}, */ {
.eraseblocks = { {4224 * 1024, 1} },
- .block_erase = spi_erase_at45db_chip,
+ .block_erase = SPI_ERASE_AT45DB_CHIP,
}
},
- .printlock = spi_prettyprint_status_register_at45db, /* Bit 0 is undefined, no lockdown */
- .write = spi_write_at45db,
- .read = spi_read_at45db_e8, /* 3 address and 4 dummy bytes */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB, /* Bit 0 is undefined, no lockdown */
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB_E8, /* 3 address and 4 dummy bytes */
.voltage = {2700, 3600},
- .gran = write_gran_528bytes,
+ .gran = WRITE_GRAN_528BYTES,
},
{
@@ -2982,33 +3069,33 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at45db,
+ .probe = PROBE_SPI_AT45DB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {512, 8192} },
- .block_erase = spi_erase_at45db_page,
+ .block_erase = SPI_ERASE_AT45DB_PAGE,
}, {
.eraseblocks = { {8 * 512, 8192/8} },
- .block_erase = spi_erase_at45db_block,
+ .block_erase = SPI_ERASE_AT45DB_BLOCK,
}, {
.eraseblocks = {
{8 * 512, 1},
{120 * 512, 1},
{128 * 512, 63},
},
- .block_erase = spi_erase_at45db_sector
+ .block_erase = SPI_ERASE_AT45DB_SECTOR
}, {
.eraseblocks = { {4096 * 1024, 1} },
- .block_erase = spi_erase_at45db_chip,
+ .block_erase = SPI_ERASE_AT45DB_CHIP,
}
},
- .printlock = spi_prettyprint_status_register_at45db,
- .unlock = spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT45DB, /* Impossible if locked down or #WP is low */
/* granularity will be set by the probing function. */
- .write = spi_write_at45db,
- .read = spi_read_at45db, /* Fast read (0x0B) supported */
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB, /* Fast read (0x0B) supported */
.voltage = {2700, 3600}, /* 2.5-3.6V & 2.7-3.6V models available */
},
@@ -3024,33 +3111,33 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_at45db,
+ .probe = PROBE_SPI_AT45DB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {512, 8192} },
- .block_erase = spi_erase_at45db_page,
+ .block_erase = SPI_ERASE_AT45DB_PAGE,
}, {
.eraseblocks = { {8 * 512, 8192/8} },
- .block_erase = spi_erase_at45db_block,
+ .block_erase = SPI_ERASE_AT45DB_BLOCK,
}, {
.eraseblocks = {
{8 * 512, 1},
{120 * 512, 1},
{128 * 512, 63},
},
- .block_erase = spi_erase_at45db_sector
+ .block_erase = SPI_ERASE_AT45DB_SECTOR
}, {
.eraseblocks = { {4096 * 1024, 1} },
- .block_erase = spi_erase_at45db_chip,
+ .block_erase = SPI_ERASE_AT45DB_CHIP,
}
},
- .printlock = spi_prettyprint_status_register_at45db, /* has a 2nd status register */
- .unlock = spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB, /* has a 2nd status register */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT45DB, /* Impossible if locked down or #WP is low */
/* granularity will be set by the probing function. */
- .write = spi_write_at45db,
- .read = spi_read_at45db, /* Fast read (0x0B) supported */
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB, /* Fast read (0x0B) supported */
.voltage = {2500, 3600}, /* 2.3-3.6V & 2.5-3.6V models available */
},
@@ -3066,33 +3153,33 @@ const struct flashchip flashchips[] = {
/* OTP: 128B total, 64B pre-programmed; read 0x77; write 0x9B */
.feature_bits = FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_at45db,
+ .probe = PROBE_SPI_AT45DB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {1024, 8192} },
- .block_erase = spi_erase_at45db_page,
+ .block_erase = SPI_ERASE_AT45DB_PAGE,
}, {
.eraseblocks = { {8 * 1024, 8192/8} },
- .block_erase = spi_erase_at45db_block,
+ .block_erase = SPI_ERASE_AT45DB_BLOCK,
}, {
.eraseblocks = {
{8 * 1024, 1},
{248 * 1024, 1},
{256 * 1024, 31},
},
- .block_erase = spi_erase_at45db_sector
+ .block_erase = SPI_ERASE_AT45DB_SECTOR
}, {
.eraseblocks = { {8192 * 1024, 1} },
- .block_erase = spi_erase_at45db_chip,
+ .block_erase = SPI_ERASE_AT45DB_CHIP,
}
},
- .printlock = spi_prettyprint_status_register_at45db,
- .unlock = spi_disable_blockprotect_at45db, /* Impossible if locked down or #WP is low */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT45DB, /* Impossible if locked down or #WP is low */
/* granularity will be set by the probing function. */
- .write = spi_write_at45db,
- .read = spi_read_at45db, /* Fast read (0x0B) supported */
+ .write = SPI_WRITE_AT45DB,
+ .read = SPI_READ_AT45DB, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3106,18 +3193,18 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_at49f,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_AT49F,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3131,17 +3218,17 @@ const struct flashchip flashchips[] = {
.page_size = 64,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -3155,7 +3242,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -3166,14 +3253,14 @@ const struct flashchip flashchips[] = {
{96 * 1024, 1},
{128 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3187,7 +3274,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PR,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -3198,14 +3285,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3219,13 +3306,13 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PRE,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
/* Chip features an optional permanent write protection
* of the first 8 kB. The erase function is the same as
@@ -3234,9 +3321,9 @@ const struct flashchip flashchips[] = {
* supported.
*/
},
- .printlock = printlock_at49f,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_AT49F,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3250,13 +3337,13 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
/* Chip features an optional permanent write protection
* of the first 16 kB. The erase function is the same as
@@ -3265,9 +3352,9 @@ const struct flashchip flashchips[] = {
* supported.
*/
},
- .printlock = printlock_at49f,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_AT49F,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3281,13 +3368,13 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
/* Chip features an optional permanent write protection
* of the first 16 kB. The erase function is the same as
@@ -3296,9 +3383,9 @@ const struct flashchip flashchips[] = {
* supported.
*/
},
- .printlock = printlock_at49f,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_AT49F,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3313,13 +3400,13 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
/* Chip features an optional permanent write protection
* of the first 16 kB. The erase function is the same as
@@ -3328,9 +3415,9 @@ const struct flashchip flashchips[] = {
* supported.
*/
},
- .printlock = printlock_at49f,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_AT49F,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3344,7 +3431,7 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3355,18 +3442,18 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = NULL, /* TODO: Implement. */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* TODO: Implement. */
}, {
.eraseblocks = {
{64 * 1024, 4},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .printlock = printlock_regspace2_block_eraser_0,
- .unlock = unlock_regspace2_block_eraser_0,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -3380,7 +3467,7 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3391,18 +3478,18 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}, {
.eraseblocks = {
{64 * 1024, 8},
},
- .block_erase = NULL, /* TODO: Implement. */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* TODO: Implement. */
},
},
- .printlock = printlock_regspace2_block_eraser_0,
- .unlock = unlock_regspace2_block_eraser_0,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -3416,7 +3503,7 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3427,56 +3514,132 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 7},
},
- .block_erase = NULL, /* TODO: Implement. */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* TODO: Implement. */
}, {
.eraseblocks = {
{64 * 1024, 8},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .printlock = printlock_regspace2_block_eraser_0,
- .unlock = unlock_regspace2_block_eraser_0,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
{
- .vendor = "Boya Microelectronics",
- .name = "BY25Q128AS",
+ .vendor = "Boya/BoHong Microelectronics",
+ .name = "B.25D16A",
+ .bustype = BUS_SPI,
+ .manufacture_id = BOYA_BOHONG_ID,
+ .model_id = BOYA_BOHONG_B_25D16A,
+ .total_size = 2048,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN,
+ .tested = TEST_OK_PR,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "Boya/BoHong Microelectronics",
+ .name = "B.25D80A",
+ .bustype = BUS_SPI,
+ .manufacture_id = BOYA_BOHONG_ID,
+ .model_id = BOYA_BOHONG_B__25D80A,
+ .total_size = 1024,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN,
+ .tested = TEST_OK_PR,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 16} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {1 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {1 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "Boya/BoHong Microelectronics",
+ .name = "B.25Q128AS",
.bustype = BUS_SPI,
- .manufacture_id = BOYA_ID,
- .model_id = BOYA_BY25Q128AS,
+ .manufacture_id = BOYA_BOHONG_ID,
+ .model_id = BOYA_BOHONG_B_25Q128AS,
.total_size = 16384,
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect_at25fs040,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_AT25FS040,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -3490,20 +3653,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PR,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3517,17 +3680,17 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = 0,
.tested = {.probe = OK, .read = OK, .erase = BAD, .write = BAD},
- .probe = probe_jedec, /* FIXME! */
+ .probe = PROBE_JEDEC, /* FIXME! */
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = NULL, /* TODO */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* TODO */
},
},
- .write = NULL, /* TODO */
- .read = read_memmapped,
+ .write = 0, /* TODO */
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3540,19 +3703,19 @@ const struct flashchip flashchips[] = {
.feature_bits = FEATURE_ERASED_ZERO,
.tested = TEST_OK_PREW,
.spi_cmd_set = SPI_EDI,
- .probe = edi_probe_kb9012,
+ .probe = PROBE_EDI_KB9012,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {128, 1024} },
- .block_erase = edi_chip_block_erase,
+ .block_erase = EDI_CHIP_BLOCK_ERASE,
},
},
- .write = edi_chip_write,
- .read = edi_chip_read,
+ .write = EDI_CHIP_WRITE,
+ .read = EDI_CHIP_READ,
.voltage = {2700, 3600},
- .gran = write_gran_128bytes,
+ .gran = WRITE_GRAN_128BYTES,
},
{
@@ -3567,22 +3730,22 @@ const struct flashchip flashchips[] = {
* supports read (0x53), fast read (0x5B), erase (0xD5) and program (0x52) instructions. */
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast Read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast Read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3598,22 +3761,22 @@ const struct flashchip flashchips[] = {
* supports read (0x53), fast read (0x5B), erase (0xD5) and program (0x52) instructions. */
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast Read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast Read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3629,22 +3792,22 @@ const struct flashchip flashchips[] = {
* supports read (0x53), fast read (0x5B), erase (0xD5) and program (0x52) instructions. */
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast Read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast Read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3658,28 +3821,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EITHER,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_1,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE1,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -3693,28 +3856,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EITHER | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_bpl,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -3728,7 +3891,7 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -3739,14 +3902,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -3760,7 +3923,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3771,16 +3934,16 @@ const struct flashchip flashchips[] = {
{16 * 1024, 1},
{32 * 1024, 1},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3794,7 +3957,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3805,16 +3968,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3828,7 +3991,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3839,16 +4002,16 @@ const struct flashchip flashchips[] = {
{16 * 1024, 1},
{32 * 1024, 3},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3862,7 +4025,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3873,16 +4036,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3896,7 +4059,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3908,16 +4071,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 31},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3931,7 +4094,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3943,16 +4106,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -3966,7 +4129,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -3978,16 +4141,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3}
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4001,7 +4164,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -4013,16 +4176,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4037,7 +4200,7 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -4049,16 +4212,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 63},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4073,7 +4236,7 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -4085,16 +4248,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4108,7 +4271,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -4120,16 +4283,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 7}
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4143,7 +4306,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -4155,16 +4318,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4179,7 +4342,7 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -4191,16 +4354,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 127},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4215,7 +4378,7 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -4227,16 +4390,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4250,7 +4413,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -4262,16 +4425,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 15}
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4285,7 +4448,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -4297,16 +4460,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 1},
{4 * 1024, 2},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4320,31 +4483,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4357,32 +4520,32 @@ const struct flashchip flashchips[] = {
.total_size = 128,
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4396,28 +4559,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4431,31 +4594,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4469,28 +4632,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4504,28 +4667,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4539,28 +4702,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4574,28 +4737,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4609,23 +4772,23 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = {
{32 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4639,22 +4802,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4668,22 +4831,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4697,22 +4860,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4727,22 +4890,22 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4756,22 +4919,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4786,22 +4949,22 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4815,22 +4978,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -4845,28 +5008,28 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
},
{
@@ -4882,32 +5045,32 @@ const struct flashchip flashchips[] = {
/* OTP: D16 512B/Q16 128B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
/* not supported by Q16 version */
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4922,28 +5085,28 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4958,28 +5121,28 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -4994,28 +5157,28 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -5030,28 +5193,28 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -5067,30 +5230,37 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
/* QPI enable 0x38, disable 0xFF */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like TB */
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -5106,28 +5276,28 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x38, disable 0xFF */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 2048, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 2048, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -5144,28 +5314,76 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x38, disable 0xFF */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 4096, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 4096, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like TB */
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Eon",
+ .name = "EN25QH32B",
+ .bustype = BUS_SPI,
+ .manufacture_id = EON_ID_NOPREFIX,
+ .model_id = EON_EN25QH32,
+ .total_size = 4096,
+ .page_size = 256,
+ /* supports SFDP */
+ /* OTP: 1536B total; enter 0x3A */
+ /* QPI enable 0x38, disable 0xFF */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {1024 * 4096, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {1024 * 4096, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -5182,28 +5400,76 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x38, disable 0xFF */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 2048} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {64 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { { 8192 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { { 8192 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like TB */
+ },
+ .decode_range = DECODE_RANGE_SPI25_64K_BLOCK,
+ },
+
+ {
+ .vendor = "Eon",
+ .name = "EN25QH64A",
+ .bustype = BUS_SPI,
+ .manufacture_id = EON_ID_NOPREFIX,
+ .model_id = EON_EN25QH64,
+ .total_size = 8192,
+ .page_size = 256,
+ /* supports SFDP */
+ /* OTP: 512B total; enter 0x3A */
+ /* QPI enable 0x38, disable 0xFF */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 8192 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 8192 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -5218,28 +5484,28 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -5254,31 +5520,31 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
- }, {
- .eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {64 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_en25s_wp,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_EN25S_WP,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -5293,28 +5559,28 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -5329,31 +5595,31 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4096 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4096 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_en25s_wp,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_EN25S_WP,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -5368,28 +5634,28 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -5403,29 +5669,29 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* OTP: 512B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8192 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8192 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_en25s_wp,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_EN25S_WP,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -5440,28 +5706,28 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -5475,7 +5741,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -5486,14 +5752,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -5507,7 +5773,7 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -5518,14 +5784,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -5539,21 +5805,21 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PRE,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {16 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
},
{
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -5567,7 +5833,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -5576,14 +5842,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 127},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -5597,7 +5863,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -5606,14 +5872,14 @@ const struct flashchip flashchips[] = {
{64 * 1024, 127},
{8 * 1024, 8},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -5627,20 +5893,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -5654,20 +5920,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -5680,21 +5946,21 @@ const struct flashchip flashchips[] = {
.total_size = 512,
.page_size = 4 * 1024,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
},
{
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -45R and 55R, others 2.7-3.6V */
},
@@ -5708,7 +5974,7 @@ const struct flashchip flashchips[] = {
.page_size = 8192,
.feature_bits = FEATURE_ADDR_SHIFTED,
.tested = TEST_OK_PREW,
- .probe = probe_en29lv640b,
+ .probe = PROBE_EN29LV640B,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -5717,14 +5983,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 127},
},
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_en29lv640b,
- .read = read_memmapped,
+ .write = WRITE_EN29LV640B,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -5739,30 +6005,30 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers = {
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O (0x3B) supported */
.voltage = {2700, 3600}, /* 2.3-2.7V acceptable results in lower performance */
},
@@ -5777,30 +6043,30 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers = {
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O (0x3B) supported */
.voltage = {2700, 3600}, /* 2.3-2.7V acceptable results in lower performance */
},
@@ -5815,30 +6081,30 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A, (A version only:) read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers = {
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 256, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 256, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O (0x3B) supported */
.voltage = {2700, 3600}, /* 2.3-2.7V acceptable results in lower performance */
},
@@ -5853,30 +6119,30 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A, (A version only:) read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers = {
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 512, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 512, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O (0x3B) supported */
.voltage = {2700, 3600},
},
@@ -5893,30 +6159,30 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x38, disable 0xFF */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers = {
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl, /* bit6 selects size of protected blocks; TODO: SR2 */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL, /* bit6 selects size of protected blocks; TODO: SR2 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -5933,30 +6199,30 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x38, disable 0xFF */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers = {
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl, /* bit6 selects size of protected blocks; TODO: SR2 */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL, /* bit6 selects size of protected blocks; TODO: SR2 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -5973,30 +6239,30 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x38, disable 0xFF */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers = {
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl, /* bit6 selects size of protected blocks; TODO: SR2 */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL, /* bit6 selects size of protected blocks; TODO: SR2 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -6010,7 +6276,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -6021,14 +6287,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 7},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = NULL,
- .read = read_memmapped,
+ .write = 0,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -6042,7 +6308,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -6053,14 +6319,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = NULL,
- .read = read_memmapped,
+ .write = 0,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -6075,7 +6341,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_SHIFTED | FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
.block_erasers =
{
@@ -6086,14 +6352,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 7},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4750, 5250}, /* 4.75-5.25V for type -55, others 4.5-5.5V */
},
@@ -6107,7 +6373,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_SHIFTED | FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
.block_erasers =
{
@@ -6118,14 +6384,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4750, 5250}, /* 4.75-5.25V for type -55, others 4.5-5.5V */
},
@@ -6139,7 +6405,7 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_ADDR_SHIFTED | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
.block_erasers =
{
@@ -6150,14 +6416,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 31},
},
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1, /* Supports a fast mode too */
- .read = read_memmapped,
+ .write = WRITE_JEDEC1, /* Supports a fast mode too */
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -70, others 2.7-3.6V */
},
@@ -6171,7 +6437,7 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_ADDR_SHIFTED | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
.block_erasers =
{
@@ -6182,14 +6448,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1, /* Supports a fast mode too */
- .read = read_memmapped,
+ .write = WRITE_JEDEC1, /* Supports a fast mode too */
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* 3.0-3.6V for type -70, others 2.7-3.6V */
},
@@ -6204,71 +6470,81 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
{
.vendor = "GigaDevice",
- .name = "GD25LQ128C/GD25LQ128D",
+ .name = "GD25LQ128C/GD25LQ128D/GD25LQ128E",
.bustype = BUS_SPI,
.manufacture_id = GIGADEVICE_ID,
.model_id = GIGADEVICE_GD25LQ128CD,
.total_size = 16384,
.page_size = 256,
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT2,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1695, 1950},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like TB */
+ .sec = {STATUS1, 6, RW}, /* Called BP4 in datasheet, acts like SEC */
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -6282,31 +6558,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1695, 1950},
},
@@ -6321,31 +6597,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1695, 1950},
},
@@ -6360,31 +6636,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1695, 1950},
},
@@ -6397,34 +6673,44 @@ const struct flashchip flashchips[] = {
.total_size = 8192,
.page_size = 256,
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT2,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1695, 1950},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like TB */
+ .sec = {STATUS1, 6, RW}, /* Called BP4 in datasheet, acts like SEC */
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -6438,31 +6724,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1695, 1950},
},
@@ -6476,31 +6762,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -6514,35 +6800,45 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* OTP: 1536B total; read 0x48; write 0x42, erase 0x44 */
/* QPI: enable 0x38, disable 0xFF */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR2,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: 2nd status reg (read 0x35, write 0x31) and 3rd status reg (read 0x15, write 0x11) */
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like TB */
+ .sec = {STATUS1, 6, RW}, /* Called BP4 in datasheet, acts like SEC */
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -6556,31 +6852,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 (B version only) */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -6594,79 +6890,88 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
{
.vendor = "GigaDevice",
- .name = "GD25Q256D",
+ .name = "GD25Q256D/GD25Q256E",
.bustype = BUS_SPI,
.manufacture_id = GIGADEVICE_ID,
.model_id = GIGADEVICE_GD25Q256D,
.total_size = 32768,
.page_size = 256,
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA |
+ FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 6, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {STATUS1, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -6678,34 +6983,44 @@ const struct flashchip flashchips[] = {
.total_size = 4096,
.page_size = 256,
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR2,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like TB */
+ .sec = {STATUS1, 6, RW}, /* Called BP4 in datasheet, acts like SEC */
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -6717,32 +7032,32 @@ const struct flashchip flashchips[] = {
.total_size = 512,
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -6756,28 +7071,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -6790,34 +7105,44 @@ const struct flashchip flashchips[] = {
.total_size = 8192,
.page_size = 256,
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR2,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like TB */
+ .sec = {STATUS1, 6, RW}, /* Called BP4 in datasheet, acts like SEC */
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -6831,31 +7156,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 (B version only) */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -6870,31 +7195,31 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0x3A */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -6910,31 +7235,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total; read 0x48, write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { { 64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2300, 3600},
},
@@ -6949,31 +7274,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1536B total; read 0x48, write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { { 64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2300, 3600},
},
@@ -6989,31 +7314,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total; read 0x48, write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { { 64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2300, 3600},
},
@@ -7028,31 +7353,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1536B total; read 0x48, write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { { 64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2300, 3600},
},
@@ -7068,31 +7393,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total; read 0x48, write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { { 32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { { 64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd, /* TODO: 2nd status reg (read with 0x35) */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD, /* TODO: 2nd status reg (read with 0x35) */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2300, 3600},
},
@@ -7106,31 +7431,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp4_srwd,
- .unlock = spi_disable_blockprotect_bp4_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 3600},
},
@@ -7144,7 +7469,7 @@ const struct flashchip flashchips[] = {
.page_size = 256 * 1024,
.feature_bits = FEATURE_EITHER_RESET, /* Some revisions may need FEATURE_ADDR_2AA */
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -7155,14 +7480,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4750, 5250}, /* 4.75-5.25V for type -45, others 4.5-5.5V */
},
@@ -7176,7 +7501,7 @@ const struct flashchip flashchips[] = {
.page_size = 256 * 1024,
.feature_bits = FEATURE_EITHER_RESET, /* Some revisions may need FEATURE_ADDR_2AA */
.tested = TEST_OK_PRE,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -7187,14 +7512,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4750, 5250}, /* 4.75-5.25V for type -45, others 4.5-5.5V */
},
@@ -7208,25 +7533,66 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
{
.vendor = "ISSI",
+ .name = "IS25LP016",
+ .bustype = BUS_SPI,
+ .manufacture_id = ISSI_ID_SPI,
+ .model_id = ISSI_IS25LP016,
+ .total_size = 2048,
+ .page_size = 256,
+ /* OTP: 1024B total; read 0x48; write 0x42 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {4 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_D7,
+ }, {
+ .eraseblocks = { {32 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2300, 3600},
+ },
+
+ {
+ .vendor = "ISSI",
.name = "IS25LP064",
.bustype = BUS_SPI,
.manufacture_id = ISSI_ID_SPI,
@@ -7235,34 +7601,34 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* OTP: 1024B total; read 0x48; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
@@ -7277,33 +7643,33 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total; read 0x48; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
@@ -7317,46 +7683,170 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total; read 0x68; write 0x62, erase 0x64, read ID 0x4B */
- /* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA | FEATURE_4BA_ENTER_EAR7,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP |
+ FEATURE_4BA | FEATURE_4BA_ENTER_EAR7 | FEATURE_4BA_EAR_1716,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
- /* could also use spi_block_erase_d7 */
+ .block_erase = SPI_BLOCK_ERASE_20,
+ /* could also use SPI_BLOCK_ERASE_D7 */
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
+
+ {
+ .vendor = "ISSI",
+ .name = "IS25LQ016",
+ .bustype = BUS_SPI,
+ .manufacture_id = ISSI_ID_SPI,
+ .model_id = ISSI_IS25LQ016,
+ .total_size = 2048,
+ .page_size = 256,
+ /* OTP: 256B total; read 0x4b; write 0xb1 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {4 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_D7,
+ }, {
+ .eraseblocks = { {64 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2300, 3600},
+ },
+
+ {
+ .vendor = "ISSI",
+ .name = "IS25WP016",
+ .bustype = BUS_SPI,
+ .manufacture_id = ISSI_ID_SPI,
+ .model_id = ISSI_IS25WP016,
+ .total_size = 2048,
+ .page_size = 256,
+ /* OTP: 1024B total; read 0x48; write 0x42 */
+ /* QPI enable 0x35, disable 0xF5 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {4 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_D7,
+ }, {
+ .eraseblocks = { {32 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1650, 1950},
+ },
+
+ {
+ .vendor = "ISSI",
+ .name = "IS25WP020",
+ .bustype = BUS_SPI,
+ .manufacture_id = ISSI_ID_SPI,
+ .model_id = ISSI_IS25WP020,
+ .total_size = 256,
+ .page_size = 256,
+ /* OTP: 1024B total; read 0x48; write 0x42 */
+ /* QPI enable 0x35, disable 0xF5 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .tested = TEST_UNTESTED,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {4 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_D7,
+ }, {
+ .eraseblocks = { {32 * 1024, 8} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 4} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {256 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {256 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1650, 1950},
+ },
+
{
.vendor = "ISSI",
.name = "IS25WP032",
@@ -7369,33 +7859,75 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x35, disable 0xF5 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1650, 1950},
+ },
+
+ {
+ .vendor = "ISSI",
+ .name = "IS25WP040",
+ .bustype = BUS_SPI,
+ .manufacture_id = ISSI_ID_SPI,
+ .model_id = ISSI_IS25WP040,
+ .total_size = 512,
+ .page_size = 256,
+ /* OTP: 1024B total; read 0x48; write 0x42 */
+ /* QPI enable 0x35, disable 0xF5 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .tested = TEST_UNTESTED,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {4 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D7,
+ }, {
+ .eraseblocks = { {32 * 1024, 16} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 8} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {512 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {512 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -7411,33 +7943,75 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x35, disable 0xF5 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1650, 1950},
+ },
+
+ {
+ .vendor = "ISSI",
+ .name = "IS25WP080",
+ .bustype = BUS_SPI,
+ .manufacture_id = ISSI_ID_SPI,
+ .model_id = ISSI_IS25WP080,
+ .total_size = 1024,
+ .page_size = 256,
+ /* OTP: 1024B total; read 0x48; write 0x42 */
+ /* QPI enable 0x35, disable 0xF5 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {4 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_D7,
+ }, {
+ .eraseblocks = { {32 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 16} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -7453,33 +8027,33 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x35, disable 0xF5 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -7493,43 +8067,83 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total; read 0x68; write 0x62, erase 0x64, read ID 0x4B */
- /* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA | FEATURE_4BA_ENTER_EAR7,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP |
+ FEATURE_4BA | FEATURE_4BA_ENTER_EAR7 | FEATURE_4BA_EAR_1716,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
- /* could also use spi_block_erase_d7 */
+ .block_erase = SPI_BLOCK_ERASE_20,
+ /* could also use SPI_BLOCK_ERASE_D7 */
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1650, 1950},
+ },
+
+ {
+ .vendor = "ISSI",
+ .name = "IS25WQ040",
+ .bustype = BUS_SPI,
+ .manufacture_id = ISSI_ID_SPI,
+ .model_id = ISSI_IS25WQ040,
+ .total_size = 512,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {4 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D7,
+ }, {
+ .eraseblocks = { {32 * 1024, 16} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 8} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {512 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {512 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -7543,7 +8157,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -7552,14 +8166,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 127},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -7573,20 +8187,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -7600,7 +8214,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -7609,14 +8223,14 @@ const struct flashchip flashchips[] = {
{64 * 1024, 127},
{8 * 1024, 8},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -7630,20 +8244,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -7658,7 +8272,7 @@ const struct flashchip flashchips[] = {
/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -7670,19 +8284,19 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 31} // inaccessible
},
- .block_erase = spi_block_erase_40,
+ .block_erase = SPI_BLOCK_ERASE_40,
}, { */
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd,
- .unlock = spi_disable_blockprotect_bp2_ep_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* also fast read 0x0B */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_EP_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* also fast read 0x0B */
.voltage = {2700, 3600},
},
@@ -7697,7 +8311,7 @@ const struct flashchip flashchips[] = {
/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -7709,19 +8323,19 @@ const struct flashchip flashchips[] = {
{64 * 1024, 31}, // inaccessible
{8 * 1024, 8}
},
- .block_erase = spi_block_erase_40,
+ .block_erase = SPI_BLOCK_ERASE_40,
}, { */
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd,
- .unlock = spi_disable_blockprotect_bp2_ep_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* also fast read 0x0B */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_EP_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* also fast read 0x0B */
.voltage = {2700, 3600},
},
@@ -7736,7 +8350,7 @@ const struct flashchip flashchips[] = {
/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -7748,19 +8362,19 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 63} // inaccessible
},
- .block_erase = spi_block_erase_40,
+ .block_erase = SPI_BLOCK_ERASE_40,
}, { */
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd,
- .unlock = spi_disable_blockprotect_bp2_ep_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* also fast read 0x0B */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_EP_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* also fast read 0x0B */
.voltage = {2700, 3600},
},
@@ -7775,7 +8389,7 @@ const struct flashchip flashchips[] = {
/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -7787,19 +8401,19 @@ const struct flashchip flashchips[] = {
{64 * 1024, 63}, // inaccessible
{8 * 1024, 8}
},
- .block_erase = spi_block_erase_40,
+ .block_erase = SPI_BLOCK_ERASE_40,
}, { */
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd,
- .unlock = spi_disable_blockprotect_bp2_ep_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* also fast read 0x0B */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_EP_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* also fast read 0x0B */
.voltage = {2700, 3600},
},
@@ -7814,7 +8428,7 @@ const struct flashchip flashchips[] = {
/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -7826,19 +8440,19 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 127} // inaccessible
},
- .block_erase = spi_block_erase_40,
+ .block_erase = SPI_BLOCK_ERASE_40,
}, { */
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd,
- .unlock = spi_disable_blockprotect_bp2_ep_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* also fast read 0x0B */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_EP_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* also fast read 0x0B */
.voltage = {2700, 3600},
},
@@ -7853,7 +8467,7 @@ const struct flashchip flashchips[] = {
/* OTP: 506B total (2x 8B, 30x 16B, 1x 10B); read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -7865,19 +8479,19 @@ const struct flashchip flashchips[] = {
{64 * 1024, 127}, // inaccessible
{8 * 1024, 8}
},
- .block_erase = spi_block_erase_40,
+ .block_erase = SPI_BLOCK_ERASE_40,
}, { */
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd,
- .unlock = spi_disable_blockprotect_bp2_ep_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* also fast read 0x0B */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_EP_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* also fast read 0x0B */
.voltage = {2700, 3600},
},
@@ -7890,7 +8504,7 @@ const struct flashchip flashchips[] = {
.total_size = 128,
.page_size = 128 * 1024, /* 8k + 2x4k + 112k */
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -7900,11 +8514,11 @@ const struct flashchip flashchips[] = {
{4 * 1024, 2},
{112 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .write = write_82802ab,
- .read = read_memmapped,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -7917,7 +8531,7 @@ const struct flashchip flashchips[] = {
.total_size = 128,
.page_size = 128 * 1024, /* 112k + 2x4k + 8k */
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -7927,11 +8541,11 @@ const struct flashchip flashchips[] = {
{4 * 1024, 2},
{8 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .write = write_82802ab,
- .read = read_memmapped,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -7944,7 +8558,7 @@ const struct flashchip flashchips[] = {
.total_size = 256,
.page_size = 256 * 1024,
.tested = TEST_OK_PRE,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -7955,11 +8569,11 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .write = write_82802ab,
- .read = read_memmapped,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
},
{
@@ -7971,7 +8585,7 @@ const struct flashchip flashchips[] = {
.total_size = 512,
.page_size = 128 * 1024, /* maximal block size */
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -7982,11 +8596,11 @@ const struct flashchip flashchips[] = {
{96 * 1024, 1},
{128 * 1024, 3},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .write = write_82802ab,
- .read = read_memmapped,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
},
{
@@ -7998,7 +8612,7 @@ const struct flashchip flashchips[] = {
.total_size = 512,
.page_size = 128 * 1024, /* maximal block size */
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -8009,11 +8623,11 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .write = write_82802ab,
- .read = read_memmapped,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
},
{
@@ -8025,18 +8639,18 @@ const struct flashchip flashchips[] = {
.total_size = 512,
.page_size = 256,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .unlock = unlock_28f004s5,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_28F004S5,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
},
{
@@ -8049,7 +8663,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* maximal block size */
.feature_bits = FEATURE_ADDR_SHIFTED,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -8060,11 +8674,11 @@ const struct flashchip flashchips[] = {
{96 * 1024, 1},
{128 * 1024, 3},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .write = write_82802ab,
- .read = read_memmapped,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
},
{
@@ -8077,7 +8691,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* maximal block size */
.feature_bits = FEATURE_ADDR_SHIFTED,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -8088,16 +8702,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .write = write_82802ab,
- .read = read_memmapped,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
},
{
.vendor = "Intel",
- .name = "82802AB",
+ .name = "AT82802AB",
.bustype = BUS_FWH,
.manufacture_id = INTEL_ID,
.model_id = INTEL_82802AB,
@@ -8105,18 +8719,18 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_OK_PREW,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -8130,18 +8744,18 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_OK_PR,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine does not use probe_timing (82802ab.c) */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
},
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -8154,10 +8768,10 @@ const struct flashchip flashchips[] = {
.total_size = 16384,
.page_size = 256,
.tested = {.probe = NT, .read = NT, .erase = NA, .write = NA},
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL, /* MX23L12854 is a mask ROM, so it is read-only */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .write = 0, /* MX23L12854 is a mask ROM, so it is read-only */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {3000, 3600},
},
@@ -8170,10 +8784,10 @@ const struct flashchip flashchips[] = {
.total_size = 2048,
.page_size = 256,
.tested = {.probe = NT, .read = NT, .erase = NA, .write = NA},
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL, /* MX23L1654 is a mask ROM, so it is read-only */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .write = 0, /* MX23L1654 is a mask ROM, so it is read-only */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {3000, 3600},
},
@@ -8186,10 +8800,10 @@ const struct flashchip flashchips[] = {
.total_size = 4096,
.page_size = 256,
.tested = {.probe = OK, .read = OK, .erase = NA, .write = NA},
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL, /* MX23L3254 is a mask ROM, so it is read-only */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .write = 0, /* MX23L3254 is a mask ROM, so it is read-only */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {3000, 3600},
},
@@ -8202,10 +8816,10 @@ const struct flashchip flashchips[] = {
.total_size = 8192,
.page_size = 256,
.tested = {.probe = OK, .read = OK, .erase = NA, .write = NA},
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL, /* MX23L6454 is a mask ROM, so it is read-only */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .write = 0, /* MX23L6454 is a mask ROM, so it is read-only */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {3000, 3600},
},
@@ -8220,28 +8834,28 @@ const struct flashchip flashchips[] = {
/* MX25L1006E supports SFDP */
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported, MX25L1006E supports dual I/O */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported, MX25L1006E supports dual I/O */
.voltage = {2700, 3600},
},
@@ -8256,68 +8870,68 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
{
.vendor = "Macronix",
- .name = "MX25L12835F/MX25L12845E/MX25L12865E",
+ .name = "MX25L12833F/MX25L12835F/MX25L12845E/MX25L12865E/MX25L12873F",
.bustype = BUS_SPI,
.manufacture_id = MACRONIX_ID,
.model_id = MACRONIX_MX25L12805D,
.total_size = 16384,
.page_size = 256,
- /* OTP: 512B total; enter 0xB1, exit 0xC1 */
+ /* OTP: MX25L12833F has 1KB total, others have 512B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register and SBLK/SBULK; MX25L12835F: configuration register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -8331,28 +8945,66 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_srwd, /* bit6: error flag */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD, /* bit6: error flag */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "Macronix",
+ .name = "MX25V16066", /* was called KH25V16066 in rev v1.3 */
+ .bustype = BUS_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX25L1605,
+ .total_size = 2048, /* 16M-bits */
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN,
+ .tested = TEST_OK_PR,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ },
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -8367,31 +9019,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; enter 0xB1, exit 0xC1 (MX25L1606E and MX25L1608E only) */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* MX25L1605A bp2 only */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported (MX25L1608E supports dual-I/O read) */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* MX25L1605A bp2 only */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported (MX25L1608E supports dual-I/O read) */
.voltage = {2700, 3600},
},
@@ -8405,28 +9057,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6: Continuously Program (CP) mode, for 73E is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6: Continuously Program (CP) mode, for 73E is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O supported */
.voltage = {2700, 3600},
},
@@ -8440,29 +9092,29 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* OTP: 64B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -8477,28 +9129,28 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -8512,31 +9164,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -8551,41 +9203,41 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register and SBLK/SBULK; MX25L12835F: configuration register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -8599,28 +9251,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_srwd, /* bit6: error flag */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD, /* bit6: error flag */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -8635,28 +9287,28 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6: continuously program mode */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and dual I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6: continuously program mode */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and dual I/O supported */
.voltage = {2700, 3600},
},
@@ -8670,33 +9322,40 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* OTP: 64B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and dual I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and dual I/O supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .cmp = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like CMP */
+ },
+ .decode_range = DECODE_RANGE_SPI25_BIT_CMP,
},
{
@@ -8710,67 +9369,107 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
{
.vendor = "Macronix",
- .name = "MX25L3273E",
+ .name = "MX25L3233F/MX25L3273E",
.bustype = BUS_SPI,
.manufacture_id = MACRONIX_ID,
.model_id = MACRONIX_MX25L3205,
.total_size = 4096,
.page_size = 256,
- /* OTP: 64B total; enter 0xB1, exit 0xC1 */
+ /* OTP: 512B total; enter 0xB1, exit 0xC1 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ },
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and dual I/O supported */
+ .voltage = {2700, 3600}, /* 33F 2.65V..3.6V */
+ },
+
+ {
+ .vendor = "Macronix",
+ .name = "MX25L3255E",
+ .bustype = BUS_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX25L3255E,
+ .total_size = 4096,
+ .page_size = 256,
+ /* OTP: 4K total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and dual I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ /* Fast read (0x0B), 2x and 4x I/O supported */
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -8784,31 +9483,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -8823,31 +9522,31 @@ const struct flashchip flashchips[] = {
/* MX25L512E supports SFDP */
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported, MX25L512E supports dual I/O */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported, MX25L512E supports dual I/O */
.voltage = {2700, 3600}, /* 2.35-3.6V for MX25V512(C) */
},
@@ -8861,31 +9560,31 @@ const struct flashchip flashchips[] = {
.page_size = 32,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -8900,29 +9599,35 @@ const struct flashchip flashchips[] = {
/* Has an additional 512B EEPROM sector */
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6: error flag */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6: error flag */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -8936,29 +9641,36 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6: continuously program mode */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O read (0xBB) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6: continuously program mode */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O read (0xBB) supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .cmp = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like CMP */
+ },
+ .decode_range = DECODE_RANGE_SPI25_BIT_CMP,
},
{
@@ -8972,38 +9684,45 @@ const struct flashchip flashchips[] = {
/* MX25L6406E supports SFDP */
/* OTP: 06E 64B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O read supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O read supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .cmp = {STATUS1, 5, RW}, /* Called BP3 in datasheet, acts like CMP */
+ },
+ .decode_range = DECODE_RANGE_SPI25_BIT_CMP,
},
{
.vendor = "Macronix",
- .name = "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E/MX25L6473F",
+ .name = "MX25L6436E/MX25L6445E/MX25L6465E",
.bustype = BUS_SPI,
.manufacture_id = MACRONIX_ID,
.model_id = MACRONIX_MX25L6405,
@@ -9011,34 +9730,136 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 512B total; enter 0xB1, exit 0xC1 */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_SCUR,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 2048} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .wps = {SECURITY, 7, OTP}, /* This bit is set by WPSEL command */
+ },
+ .decode_range = DECODE_RANGE_SPI25_2X_BLOCK,
+ },
+
+ {
+ .vendor = "Macronix",
+ .name = "MX25L6473E",
+ .bustype = BUS_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX25L6405,
+ .total_size = 8192,
+ .page_size = 256,
+ /* supports SFDP */
+ /* OTP: 512B total; enter 0xB1, exit 0xC1 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT2 | FEATURE_SCUR,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 2048} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {CONFIG, 3, OTP},
+ .wps = {SECURITY, 7, OTP}, /* This bit is set by WPSEL command */
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Macronix",
+ .name = "MX25L6473F",
+ .bustype = BUS_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX25L6405,
+ .total_size = 8192,
+ .page_size = 256,
+ /* supports SFDP */
+ /* OTP: 512B total; enter 0xB1, exit 0xC1 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT2,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {CONFIG, 3, OTP},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -9052,30 +9873,30 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
- }, {
- .eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -9091,31 +9912,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; enter 0xB1, exit 0xC1 (MX25L8006E, MX25L8008E only) */
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600}, /* 2.35-3.6V for MX25V8005 */
},
@@ -9130,31 +9951,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
- }, {
- .eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit 6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit 6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1650, 3600},
},
@@ -9169,36 +9990,142 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
- }, {
- .eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1650, 3600},
},
{
.vendor = "Macronix",
+ .name = "MX25V4035F",
+ .bustype = BUS_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX25V4035F,
+ .total_size = 512,
+ .page_size = 256,
+ /* OTP: 8KiB total; enter 0xB1, exit 0xC1 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_SCUR,
+ .tested = TEST_UNTESTED,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { { 4 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 16} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 8} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {512 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
+ .voltage = {2300, 3600},
+ },
+ {
+ .vendor = "Macronix",
+ .name = "MX25V8035F",
+ .bustype = BUS_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX25V8035F,
+ .total_size = 1024,
+ .page_size = 256,
+ /* OTP: 8KiB total; enter 0xB1, exit 0xC1 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_SCUR,
+ .tested = TEST_UNTESTED,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { { 4 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 16} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {1 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
+ .voltage = {2300, 3600},
+ },
+ {
+ .vendor = "Macronix",
+ .name = "MX25V1635F",
+ .bustype = BUS_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX25V1635F,
+ .total_size = 2048,
+ .page_size = 256,
+ /* OTP: 8KiB total; enter 0xB1, exit 0xC1 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_SCUR,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { { 4 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {2 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
+ .voltage = {2300, 3600},
+ },
+
+ {
+ .vendor = "Macronix",
.name = "MX25U12835F",
.bustype = BUS_SPI,
.manufacture_id = MACRONIX_ID,
@@ -9208,32 +10135,32 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1650, 2000},
},
@@ -9249,38 +10176,38 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x35, disable 0xF5 (0xFF et al. work too) */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PR,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1650, 2000},
},
{
.vendor = "Macronix",
- .name = "MX25U25635F",
+ .name = "MX25U25635F/MX25U25643G",
.bustype = BUS_SPI,
.manufacture_id = MACRONIX_ID,
.model_id = MACRONIX_MX25U25635F,
@@ -9288,42 +10215,42 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* OTP: 512B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_4BA,
- .tested = TEST_OK_PR,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1650, 2000},
},
@@ -9340,32 +10267,32 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x35, disable 0xF5 (0xFF et al. work too) */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1650, 2000},
},
@@ -9380,41 +10307,41 @@ const struct flashchip flashchips[] = {
/* OTP: 512B factory programmed and 512B customer programmed; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_4BA,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2048} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 2048} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1650, 2000},
},
@@ -9431,32 +10358,32 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x35, disable 0xF5 (0xFF et al. work too) */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1650, 2000},
},
@@ -9471,32 +10398,32 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1650, 2000},
},
@@ -9510,7 +10437,7 @@ const struct flashchip flashchips[] = {
.page_size = 32 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9522,14 +10449,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -9543,7 +10470,7 @@ const struct flashchip flashchips[] = {
.page_size = 32 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9555,14 +10482,14 @@ const struct flashchip flashchips[] = {
{4 * 1024, 2},
{8 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -9576,7 +10503,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9587,14 +10514,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -9608,7 +10535,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9619,14 +10546,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -9640,7 +10567,7 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9651,14 +10578,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -9672,7 +10599,7 @@ const struct flashchip flashchips[] = {
.page_size = 0, /* unused */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9683,14 +10610,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -9704,20 +10631,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -9731,20 +10658,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -9758,7 +10685,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9767,14 +10694,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 63},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -9788,20 +10715,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -9815,7 +10742,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9824,14 +10751,14 @@ const struct flashchip flashchips[] = {
{64 * 1024, 63},
{8 * 1024, 8},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -9845,7 +10772,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9854,14 +10781,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 127},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -9875,20 +10802,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -9902,7 +10829,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -9911,14 +10838,14 @@ const struct flashchip flashchips[] = {
{64 * 1024, 127},
{8 * 1024, 8},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -9932,20 +10859,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -9960,47 +10887,136 @@ const struct flashchip flashchips[] = {
/* OTP: 512B total; enter 0xB1, exit 0xC1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2048} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 2048} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
/* TODO: security register and SBLK/SBULK; MX25L12835F: configuration register */
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "Macronix",
+ .name = "MX66L1G45G",
+ .bustype = BUS_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX66L1G45G,
+ .total_size = 131072,
+ .page_size = 256,
+ /* OTP: 512B total; enter 0xB1, exit 0xC1 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 32768} },
+ .block_erase = SPI_BLOCK_ERASE_21,
+ }, {
+ .eraseblocks = { {4 * 1024, 32768} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 4096} },
+ .block_erase = SPI_BLOCK_ERASE_5C,
+ }, {
+ .eraseblocks = { {32 * 1024, 4096} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 2048} },
+ .block_erase = SPI_BLOCK_ERASE_DC,
+ }, {
+ .eraseblocks = { {64 * 1024, 2048} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {128 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {128 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ /* TODO: security register and SBLK/SBULK, configuration register */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "Macronix",
+ .name = "MX77L25650F",
+ .bustype = BUS_SPI,
+ .manufacture_id = MACRONIX_ID,
+ .model_id = MACRONIX_MX77L25650F,
+ .total_size = 32768,
+ .page_size = 256,
+ /* OTP: 512B total; enter 0xB1, exit 0xC1 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 8192} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {32 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {32 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ /* TODO: block WP, security register, configuration register */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
/* The ST M25P05 is a bit of a problem. It has the same ID as the
* ST M25P05-A in RES mode, but supports only 128 byte writes instead
- * of 256 byte writes. We rely heavily on the fact that probe_spi_res1
+ * of 256 byte writes. We rely heavily on the fact that PROBE_SPI_RES1
* only is successful if RDID does not work.
*/
{
@@ -10013,22 +11029,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_res1,
+ .probe = PROBE_SPI_RES1,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_1, /* 128 */
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE1, /* 128 */
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10042,22 +11058,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10072,22 +11088,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_res1,
+ .probe = PROBE_SPI_RES1,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_1, /* 128 */
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE1, /* 128 */
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10101,22 +11117,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10130,22 +11146,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10159,22 +11175,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10188,22 +11204,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -10217,22 +11233,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_res1,
+ .probe = PROBE_SPI_RES1,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -10246,22 +11262,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10275,22 +11291,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10304,22 +11320,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_res1,
+ .probe = PROBE_SPI_RES1,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
},
{
@@ -10332,22 +11348,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10361,22 +11377,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* TODO: check */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10390,25 +11406,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10422,25 +11438,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10454,25 +11470,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10486,25 +11502,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10518,25 +11534,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10551,25 +11567,25 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 512 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd, /* bit5: T/B */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD, /* bit5: T/B */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
@@ -10584,25 +11600,25 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PRE,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 1024 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd, /* bit5: T/B */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD, /* bit5: T/B */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10617,25 +11633,25 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 2048 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd, /* bit5: T/B */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD, /* bit5: T/B */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10650,25 +11666,25 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 4 * 1024, 256 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd, /* bit5: T/B */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD, /* bit5: T/B */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -10681,22 +11697,22 @@ const struct flashchip flashchips[] = {
.total_size = 128,
.page_size = 256,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 512} },
- .block_erase = spi_block_erase_db,
+ .block_erase = SPI_BLOCK_ERASE_DB,
}, {
.eraseblocks = { {64 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}
},
- .printlock = spi_prettyprint_status_register_default_welwip,
- .unlock = NULL, /* #WP pin write-protects lower 64kB. */
- .write = spi_chip_write_256, /* Page write (similar to PP but allows 0->1 changes) */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_DEFAULT_WELWIP,
+ .unlock = NO_BLOCKPROTECT_FUNC, /* #WP pin write-protects lower 64kB. */
+ .write = SPI_CHIP_WRITE256, /* Page write (similar to PP but allows 0->1 changes) */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -10709,22 +11725,22 @@ const struct flashchip flashchips[] = {
.total_size = 2048,
.page_size = 256,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 8192} },
- .block_erase = spi_block_erase_db,
+ .block_erase = SPI_BLOCK_ERASE_DB,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}
},
- .printlock = spi_prettyprint_status_register_default_welwip,
- .unlock = NULL, /* #WP pin write-protects lower 64kB. */
- .write = spi_chip_write_256, /* Page write (similar to PP but allows 0->1 changes) */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_DEFAULT_WELWIP,
+ .unlock = NO_BLOCKPROTECT_FUNC, /* #WP pin write-protects lower 64kB. */
+ .write = SPI_CHIP_WRITE256, /* Page write (similar to PP but allows 0->1 changes) */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -10737,22 +11753,22 @@ const struct flashchip flashchips[] = {
.total_size = 256,
.page_size = 256,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 1024} },
- .block_erase = spi_block_erase_db,
+ .block_erase = SPI_BLOCK_ERASE_DB,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}
},
- .printlock = spi_prettyprint_status_register_default_welwip,
- .unlock = NULL, /* #WP pin write-protects lower 64kB. */
- .write = spi_chip_write_256, /* Page write (similar to PP but allows 0->1 changes) */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_DEFAULT_WELWIP,
+ .unlock = NO_BLOCKPROTECT_FUNC, /* #WP pin write-protects lower 64kB. */
+ .write = SPI_CHIP_WRITE256, /* Page write (similar to PP but allows 0->1 changes) */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -10765,22 +11781,22 @@ const struct flashchip flashchips[] = {
.total_size = 512,
.page_size = 256,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 2048} },
- .block_erase = spi_block_erase_db,
+ .block_erase = SPI_BLOCK_ERASE_DB,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}
},
- .printlock = spi_prettyprint_status_register_default_welwip,
- .unlock = NULL, /* #WP pin write-protects lower 64kB. */
- .write = spi_chip_write_256, /* Page write supported (similar to PP but allows 0->1 changes) */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_DEFAULT_WELWIP,
+ .unlock = NO_BLOCKPROTECT_FUNC, /* #WP pin write-protects lower 64kB. */
+ .write = SPI_CHIP_WRITE256, /* Page write supported (similar to PP but allows 0->1 changes) */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -10793,22 +11809,22 @@ const struct flashchip flashchips[] = {
.total_size = 1024,
.page_size = 256,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 4096} },
- .block_erase = spi_block_erase_db,
+ .block_erase = SPI_BLOCK_ERASE_DB,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}
},
- .printlock = spi_prettyprint_status_register_default_welwip,
- .unlock = NULL, /* #WP pin write-protects lower 64kB. */
- .write = spi_chip_write_256, /* Page write (similar to PP but allows 0->1 changes) */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_DEFAULT_WELWIP,
+ .unlock = NO_BLOCKPROTECT_FUNC, /* #WP pin write-protects lower 64kB. */
+ .write = SPI_CHIP_WRITE256, /* Page write (similar to PP but allows 0->1 changes) */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -10824,31 +11840,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32768} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 32768} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 2048} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 2048} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32768 * 1024, 4} },
- .block_erase = spi_block_erase_c4,
+ .block_erase = SPI_BLOCK_ERASE_C4,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -10864,31 +11880,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32768} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 32768} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 2048} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 2048} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32768 * 1024, 4} },
- .block_erase = spi_block_erase_c4,
+ .block_erase = SPI_BLOCK_ERASE_C4,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -10904,28 +11920,28 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -10941,26 +11957,37 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
+ .reg_bits =
+ {
+ /*
+ * There is also a volatile lock register per 64KiB sector, which is not
+ * mutually exclusive with BP-based protection.
+ */
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -10975,26 +12002,37 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ /*
+ * There is also a volatile lock register per 64KiB sector, which is not
+ * mutually exclusive with BP-based protection.
+ */
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -11009,26 +12047,37 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
+ .reg_bits =
+ {
+ /*
+ * There is also a volatile lock register per 64KiB sector, which is not
+ * mutually exclusive with BP-based protection.
+ */
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 6, RW}},
+ .tb = {STATUS1, 5, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -11043,26 +12092,37 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ /*
+ * There is also a volatile lock register per 64KiB sector, which is not
+ * mutually exclusive with BP-based protection.
+ */
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 6, RW}},
+ .tb = {STATUS1, 5, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -11077,25 +12137,25 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -11111,25 +12171,25 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096 } },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -11145,31 +12205,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32768 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -11185,31 +12245,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32768 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -11225,31 +12285,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32768 * 1024, 2} },
- .block_erase = spi_block_erase_c4,
+ .block_erase = SPI_BLOCK_ERASE_C4,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -11265,31 +12325,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32768 * 1024, 2} },
- .block_erase = spi_block_erase_c4,
+ .block_erase = SPI_BLOCK_ERASE_C4,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -11305,37 +12365,37 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32768} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 32768} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 4096} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 4096} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 2048} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 2048} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {65536 * 1024, 2} },
- .block_erase = spi_block_erase_c4,
+ .block_erase = SPI_BLOCK_ERASE_C4,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -11351,37 +12411,37 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32768} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 32768} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 4096} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 4096} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 2048} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 2048} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {65536 * 1024, 2} },
- .block_erase = spi_block_erase_c4,
+ .block_erase = SPI_BLOCK_ERASE_C4,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -11397,37 +12457,37 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 65536} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 65536} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8192} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 8192} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4096} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 4096} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {65536 * 1024, 4} },
- .block_erase = spi_block_erase_c4,
+ .block_erase = SPI_BLOCK_ERASE_C4,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -11443,37 +12503,37 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 65536} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 65536} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8192} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 8192} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4096} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 4096} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {65536 * 1024, 4} },
- .block_erase = spi_block_erase_c4,
+ .block_erase = SPI_BLOCK_ERASE_C4,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -11489,31 +12549,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}, {
.eraseblocks = { {16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -11527,33 +12587,33 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 64B total; read 0x4B, write 0x42 */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}, {
.eraseblocks = { {16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -11568,41 +12628,41 @@ const struct flashchip flashchips[] = {
/* supports SFDP */
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32768 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}, {
.eraseblocks = { {32768 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -11617,41 +12677,41 @@ const struct flashchip flashchips[] = {
/* supports SFDP */
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32768 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}, {
.eraseblocks = { {32768 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -11667,41 +12727,48 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2048} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 2048} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {65536 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}, {
.eraseblocks = { {65536 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 6, RW}},
+ .tb = {STATUS1, 5, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -11716,40 +12783,40 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2048} },
- .block_erase = spi_block_erase_5c,
+ .block_erase = SPI_BLOCK_ERASE_5C,
}, {
.eraseblocks = { {32 * 1024, 2048} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {65536 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}, {
.eraseblocks = { {65536 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}
},
- .printlock = spi_prettyprint_status_register_n25q, /* TODO: config, lock, flag regs */
- .unlock = spi_disable_blockprotect_n25q, /* TODO: per 64kB sector lock registers */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_N25Q, /* TODO: config, lock, flag regs */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_N25Q, /* TODO: per 64kB sector lock registers */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {1700, 2000},
},
@@ -11763,20 +12830,20 @@ const struct flashchip flashchips[] = {
.page_size = 512,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {512, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -11790,20 +12857,20 @@ const struct flashchip flashchips[] = {
.page_size = 512,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {512, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -11817,20 +12884,20 @@ const struct flashchip flashchips[] = {
.page_size = 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {1024, 512} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -11844,20 +12911,20 @@ const struct flashchip flashchips[] = {
.page_size = 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {1024, 512} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -11871,20 +12938,20 @@ const struct flashchip flashchips[] = {
.page_size = 512,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {512, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -11898,20 +12965,20 @@ const struct flashchip flashchips[] = {
.page_size = 512,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {512, 256} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -11925,20 +12992,20 @@ const struct flashchip flashchips[] = {
.page_size = 512,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {512, 512} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -11952,34 +13019,34 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O read (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O read (0x3B) supported */
.voltage = {2700, 3600},
},
@@ -11993,28 +13060,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O read (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O read (0x3B) supported */
.voltage = {2700, 3600},
},
@@ -12028,34 +13095,34 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O read (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O read (0x3B) supported */
.voltage = {2700, 3600},
},
@@ -12069,34 +13136,34 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O read (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O read (0x3B) supported */
.voltage = {2700, 3600},
},
@@ -12110,31 +13177,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O read (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O read (0x3B) supported */
.voltage = {2700, 3600},
},
@@ -12148,31 +13215,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect, /* FIXME: C version supports "Safe Guard" */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* FIXME: C version supports "Safe Guard" */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O supported */
.voltage = {2700, 3600}, /* 2.3-3.6V for Pm25LD010 */
},
@@ -12186,31 +13253,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect, /* FIXME: C version supports "Safe Guard" */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* FIXME: C version supports "Safe Guard" */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O supported */
.voltage = {2700, 3600}, /* 2.3-3.6V for Pm25LD020 */
},
@@ -12224,31 +13291,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O supported */
.voltage = {2700, 3600}, /* 2.3-3.6V for Pm25LD040 */
},
@@ -12262,31 +13329,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 8} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 1} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O supported */
.voltage = {2700, 3600},
},
@@ -12300,31 +13367,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect, /* FIXME: C version supports "Safe Guard" */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* FIXME: C version supports "Safe Guard" */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual I/O supported */
.voltage = {2300, 3600},
},
@@ -12339,31 +13406,31 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; read 0x4B, write 0xB1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2300, 3600},
},
@@ -12378,31 +13445,31 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; read 0x4B, write 0xB1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
@@ -12417,31 +13484,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0xB1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4096 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4096 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -12456,31 +13523,31 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; read 0x4B, write 0xB1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2300, 3600},
},
@@ -12495,31 +13562,31 @@ const struct flashchip flashchips[] = {
/* OTP: 64B total; read 0x4B, write 0xB1 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd, /* bit6 is quad enable */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD, /* bit6 is quad enable */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2300, 3600},
},
@@ -12533,25 +13600,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_res2, /* The continuation code is transferred as the 3rd byte m( */
+ .probe = PROBE_SPI_RES2, /* The continuation code is transferred as the 3rd byte m( */
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -12565,25 +13632,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -12597,31 +13664,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -12635,25 +13702,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -12667,25 +13734,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -12699,31 +13766,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -12737,25 +13804,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_res2, /* The continuation code is transferred as the 3rd byte m( */
+ .probe = PROBE_SPI_RES2, /* The continuation code is transferred as the 3rd byte m( */
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -12769,7 +13836,7 @@ const struct flashchip flashchips[] = {
.page_size = 8 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_FIXME,
.block_erasers =
{
@@ -12780,14 +13847,14 @@ const struct flashchip flashchips[] = {
{96 * 1024, 1},
{128 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -12801,7 +13868,7 @@ const struct flashchip flashchips[] = {
.page_size = 8 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_FIXME,
.block_erasers =
{
@@ -12812,14 +13879,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -12833,23 +13900,23 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 2} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -12863,23 +13930,23 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -12893,23 +13960,23 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PR,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -12923,23 +13990,23 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -12953,24 +14020,24 @@ const struct flashchip flashchips[] = {
.page_size = 16 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PR,
- .probe = probe_jedec,
- .probe_timing = TIMING_ZERO, /* routine is wrapper to probe_jedec (pm49fl00x.c) */
+ .probe = PROBE_JEDEC,
+ .probe_timing = TIMING_ZERO, /* routine is wrapper to JEDEC (pm49fl00x.c) */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {16 * 1024, 16} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .unlock = unlock_regspace2_uniform_32k,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_32K,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -12984,24 +14051,24 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -13015,25 +14082,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rems,
+ .probe = PROBE_SPI_REMS,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* FIXME: No BP2 & 3 */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* FIXME: No BP2 & 3 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE1, /* AAI supported, but opcode is 0xAF */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -13047,25 +14114,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* TODO: check */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE1, /* AAI supported, but opcode is 0xAF */
+ .read = SPI_CHIP_READ,
.voltage = {3000, 3600},
},
@@ -13079,25 +14146,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EITHER,
.tested = TEST_UNTESTED,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* TODO: check */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE1, /* AAI supported, but opcode is 0xAF */
+ .read = SPI_CHIP_READ,
.voltage = {3000, 3600},
},
@@ -13111,31 +14178,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rems,
+ .probe = PROBE_SPI_REMS,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8, /* Supported by SST25VF010A only */
+ .block_erase = SPI_BLOCK_ERASE_D8, /* Supported by SST25VF010A only */
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7, /* Supported by SST25VF010A only */
+ .block_erase = SPI_BLOCK_ERASE_C7, /* Supported by SST25VF010A only */
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* FIXME: No BP2 & 3 */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
- .read = spi_chip_read, /* Fast read (0x0B) supported by SST25VF010A only */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* FIXME: No BP2 & 3 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE1, /* AAI supported, but opcode is 0xAF */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported by SST25VF010A only */
.voltage = {2700, 3600},
},
@@ -13149,31 +14216,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EITHER,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25vf016,
- .unlock = spi_disable_blockprotect,
- .write = spi_aai_write,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25VF016,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_WRITE_AAI,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -13187,25 +14254,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rems,
+ .probe = PROBE_SPI_REMS,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* FIXME: No BP2 & 3 */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
- .read = spi_chip_read, /* only */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* FIXME: No BP2 & 3 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE1, /* AAI supported, but opcode is 0xAF */
+ .read = SPI_CHIP_READ, /* only */
.voltage = {2700, 3600},
},
@@ -13219,31 +14286,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* FIXME: No BP2 & 3 and 2nd SR */
- .unlock = spi_disable_blockprotect, /* FIXME: 2nd SR */
- .write = spi_aai_write, /* AAI supported (0xAD) */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* FIXME: No BP2 & 3 and 2nd SR */
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* FIXME: 2nd SR */
+ .write = SPI_WRITE_AAI, /* AAI supported (0xAD) */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -13257,31 +14324,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* TODO: check */
- .unlock = spi_disable_blockprotect,
- .write = spi_aai_write,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_WRITE_AAI,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -13295,25 +14362,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PR,
- .probe = probe_spi_rems,
+ .probe = PROBE_SPI_REMS,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* TODO: check */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE1, /* AAI supported, but opcode is 0xAF */
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -13327,31 +14394,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25vf040b,
- .unlock = spi_disable_blockprotect,
- .write = spi_aai_write, /* AAI supported (0xAD) */
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25VF040B,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_WRITE_AAI, /* AAI supported (0xAD) */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -13365,31 +14432,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rems,
+ .probe = PROBE_SPI_REMS,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25vf040b,
- .unlock = spi_disable_blockprotect,
- .write = spi_aai_write,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25VF040B,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_WRITE_AAI,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -13403,31 +14470,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* TODO: check */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -13441,31 +14508,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* TODO: check */
- .unlock = spi_disable_blockprotect,
- .write = spi_aai_write,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* TODO: check */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_WRITE_AAI,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -13479,31 +14546,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EWSR,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rems,
+ .probe = PROBE_SPI_REMS,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_d8, /* Supported by SST25VF512A only */
+ .block_erase = SPI_BLOCK_ERASE_D8, /* Supported by SST25VF512A only */
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7, /* Supported by SST25VF512A only */
+ .block_erase = SPI_BLOCK_ERASE_C7, /* Supported by SST25VF512A only */
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* FIXME: No BP2 & 3 */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_1, /* AAI supported, but opcode is 0xAF */
- .read = spi_chip_read, /* Fast read (0x0B) supported by SST25VF512A only */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* FIXME: No BP2 & 3 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE1, /* AAI supported, but opcode is 0xAF */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported by SST25VF512A only */
.voltage = {2700, 3600},
},
@@ -13517,28 +14584,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EITHER,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {1024 * 128, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 128, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* FIXME: does not have a BP3 */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_aai_write,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* FIXME: does not have a BP3 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_WRITE_AAI,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {1650, 1950},
},
@@ -13552,31 +14619,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EITHER,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 256, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 256, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* FIXME: does not have a BP3 */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_aai_write,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* FIXME: does not have a BP3 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_WRITE_AAI,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {1650, 1950},
},
@@ -13590,28 +14657,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {1650, 1950},
},
@@ -13625,31 +14692,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EITHER,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 512, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 512, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* FIXME: does not have a BP3 */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_aai_write,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* FIXME: does not have a BP3 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_WRITE_AAI,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {1650, 1950},
},
@@ -13663,28 +14730,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual O (0x3B), dual I/O read (0xBB) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual O (0x3B), dual I/O read (0xBB) supported */
.voltage = {1650, 1950},
},
@@ -13698,31 +14765,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EITHER,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* *does* have a BP3 but it is useless */
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_aai_write,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* *does* have a BP3 but it is useless */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_WRITE_AAI,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {1650, 1950},
},
@@ -13736,28 +14803,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_bp2_tb_bpl,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual O (0x3B), dual I/O read (0xBB) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual O (0x3B), dual I/O read (0xBB) supported */
.voltage = {1650, 1950},
},
@@ -13771,28 +14838,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_EITHER,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {1024 * 64, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 64, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_sst25, /* FIXME: does not have a BP3 */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_aai_write,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_SST25, /* FIXME: does not have a BP3 */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_WRITE_AAI,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {1650, 1950},
},
@@ -13806,13 +14873,13 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = {
{8 * 1024, 4},
@@ -13821,16 +14888,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{8 * 1024, 4},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect_sst26_global_unprotect,
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_SST26_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -13844,13 +14911,13 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = {
{8 * 1024, 4},
@@ -13859,16 +14926,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{8 * 1024, 4},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect_sst26_global_unprotect,
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_SST26_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -13882,13 +14949,13 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = {
{8 * 1024, 4},
@@ -13897,16 +14964,16 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{8 * 1024, 4},
},
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect_sst26_global_unprotect,
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_SST26_GLOBAL_UNPROTECT,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -13920,21 +14987,21 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = 0,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst28sf040.c) */
.block_erasers =
{
{
.eraseblocks = { {128, 4096} },
- .block_erase = erase_sector_28sf040,
+ .block_erase = ERASE_SECTOR_28SF040,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_28sf040,
+ .block_erase = ERASE_CHIP_28SF040,
}
},
- .unlock = unprotect_28sf040,
- .write = write_28sf040,
- .read = read_memmapped,
+ .unlock = UNPROTECT_28SF040,
+ .write = WRITE_28SF040,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -13948,17 +15015,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PR,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -13972,17 +15039,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PRE,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -13996,17 +15063,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14020,17 +15087,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PRE,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14044,20 +15111,20 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -14071,20 +15138,20 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -14098,20 +15165,20 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -14125,20 +15192,20 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -14152,20 +15219,20 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -14179,20 +15246,20 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -14206,20 +15273,20 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -14233,23 +15300,23 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -14263,20 +15330,20 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -14290,25 +15357,25 @@ const struct flashchip flashchips[] = {
.page_size = 16 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {16 * 1024, 16} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = NULL, /* AA 55 80 AA 55 10, only in A/A mux mode */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* AA 55 80 AA 55 10, only in A/A mux mode */
}
},
- .printlock = printlock_sst_fwhub,
- .unlock = unlock_sst_fwhub,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_SST_FWHUB,
+ .unlock = UNLOCK_SST_FWHUB,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14322,25 +15389,25 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 96} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 6} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {384 * 1024, 1} },
- .block_erase = NULL, /* AA 55 80 AA 55 10, only in A/A mux mode */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* AA 55 80 AA 55 10, only in A/A mux mode */
}
},
- .printlock = printlock_sst_fwhub,
- .unlock = unlock_sst_fwhub,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_SST_FWHUB,
+ .unlock = UNLOCK_SST_FWHUB,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14357,25 +15424,25 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = NULL, /* AA 55 80 AA 55 10, only in A/A mux mode */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* AA 55 80 AA 55 10, only in A/A mux mode */
},
},
- .printlock = printlock_sst_fwhub,
- .unlock = unlock_sst_fwhub,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_SST_FWHUB,
+ .unlock = UNLOCK_SST_FWHUB,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14389,13 +15456,13 @@ const struct flashchip flashchips[] = {
.page_size = 4 * 1024,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_sector_49lfxxxc,
+ .block_erase = ERASE_SECTOR_49LFXXXC,
}, {
.eraseblocks = {
{64 * 1024, 7},
@@ -14403,13 +15470,13 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .printlock = printlock_regspace2_block_eraser_1,
- .unlock = unlock_regspace2_block_eraser_1,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_1,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_1,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14423,25 +15490,25 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = NULL, /* AA 55 80 AA 55 10, only in A/A mux mode */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* AA 55 80 AA 55 10, only in A/A mux mode */
}
},
- .printlock = printlock_sst_fwhub,
- .unlock = unlock_sst_fwhub,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_SST_FWHUB,
+ .unlock = UNLOCK_SST_FWHUB,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14455,13 +15522,13 @@ const struct flashchip flashchips[] = {
.page_size = 4 * 1024,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = erase_sector_49lfxxxc,
+ .block_erase = ERASE_SECTOR_49LFXXXC,
}, {
.eraseblocks = {
{64 * 1024, 15},
@@ -14469,13 +15536,13 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .printlock = printlock_regspace2_block_eraser_1,
- .unlock = unlock_regspace2_block_eraser_1,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_1,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_1,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14489,13 +15556,13 @@ const struct flashchip flashchips[] = {
.page_size = 4 * 1024,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_OK_PREW,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = erase_sector_49lfxxxc,
+ .block_erase = ERASE_SECTOR_49LFXXXC,
}, {
.eraseblocks = {
{64 * 1024, 31},
@@ -14503,13 +15570,13 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .printlock = printlock_regspace2_block_eraser_1,
- .unlock = unlock_regspace2_block_eraser_1,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_1,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_1,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14523,23 +15590,23 @@ const struct flashchip flashchips[] = {
.page_size = 16 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {16 * 1024, 16} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = NULL,
+ .block_erase = NO_BLOCK_ERASE_FUNC,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14553,23 +15620,23 @@ const struct flashchip flashchips[] = {
.page_size = 4 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PRE,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {16 * 1024, 16} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = NULL,
+ .block_erase = NO_BLOCK_ERASE_FUNC,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14583,23 +15650,23 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150 ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = NULL,
+ .block_erase = NO_BLOCK_ERASE_FUNC,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14613,24 +15680,24 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET | FEATURE_REGISTERMAP,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 1, /* 150ns */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = NULL,
+ .block_erase = NO_BLOCK_ERASE_FUNC,
}
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14644,23 +15711,23 @@ const struct flashchip flashchips[] = {
.page_size = 4096,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_FIXME,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = NULL,
+ .block_erase = NO_BLOCK_ERASE_FUNC,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14674,13 +15741,13 @@ const struct flashchip flashchips[] = {
.page_size = 4 * 1024,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_OK_PR,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (sst49lfxxxc.c) */
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = erase_sector_49lfxxxc,
+ .block_erase = ERASE_SECTOR_49LFXXXC,
}, {
.eraseblocks = {
{64 * 1024, 31},
@@ -14688,13 +15755,13 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .printlock = printlock_regspace2_block_eraser_1,
- .unlock = unlock_regspace2_block_eraser_1,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_1,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_1,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -14708,7 +15775,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -14719,14 +15786,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4750, 5250}, /* 4.75-5.25V for type -X, others 4.5-5.5V */
},
@@ -14740,7 +15807,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_AAA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -14751,14 +15818,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4750, 5250}, /* 4.75-5.25V for type -X, others 4.5-5.5V */
},
@@ -14772,20 +15839,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* datasheet specifies no timing */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -14800,7 +15867,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_SHIFTED | FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
.block_erasers =
{
@@ -14811,14 +15878,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 7},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -14833,7 +15900,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_SHIFTED | FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10, // FIXME: check datasheet. Using the 10 us from probe_m29f400bt
.block_erasers =
{
@@ -14844,14 +15911,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -14865,20 +15932,20 @@ const struct flashchip flashchips[] = {
.page_size = 16 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {16 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -14892,20 +15959,20 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -14919,17 +15986,17 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -14943,7 +16010,7 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_FIXME,
.block_erasers =
{
@@ -14954,15 +16021,15 @@ const struct flashchip flashchips[] = {
{4 * 1024, 16}, /* sector */
{4 * 1024, 16}, /* sector */
},
- .block_erase = erase_sector_stm50,
+ .block_erase = STM50_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -14976,7 +16043,7 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_FIXME,
.block_erasers =
{
@@ -14987,15 +16054,15 @@ const struct flashchip flashchips[] = {
{64 * 1024, 5}, /* block */
{4 * 1024, 16}, /* sector */
},
- .block_erase = erase_sector_stm50,
+ .block_erase = STM50_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -15009,7 +16076,7 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_OK_PR,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_FIXME,
.block_erasers =
{
@@ -15020,16 +16087,16 @@ const struct flashchip flashchips[] = {
{4 * 1024, 16}, /* sector */
{4 * 1024, 16}, /* sector */
},
- .block_erase = erase_sector_stm50,
+ .block_erase = STM50_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .printlock = printlock_regspace2_block_eraser_0,
- .unlock = unlock_regspace2_block_eraser_0,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -15043,7 +16110,7 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_FIXME,
.block_erasers =
{
@@ -15054,16 +16121,16 @@ const struct flashchip flashchips[] = {
{64 * 1024, 13}, /* block */
{4 * 1024, 16}, /* sector */
},
- .block_erase = erase_sector_stm50,
+ .block_erase = STM50_SECTOR_ERASE,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .printlock = printlock_regspace2_block_eraser_0,
- .unlock = unlock_regspace2_block_eraser_0,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -15077,7 +16144,7 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_OK_PR,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */
.block_erasers =
{
@@ -15088,16 +16155,16 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = NULL, /* Only in A/A mux mode */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* Only in A/A mux mode */
}
},
- .printlock = printlock_regspace2_block_eraser_0,
- .unlock = unlock_regspace2_block_eraser_0,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -15111,18 +16178,18 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -15136,18 +16203,18 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_OK_PR,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -15161,18 +16228,18 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_OK_PR,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (82802ab.c) */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -15186,18 +16253,18 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -15211,7 +16278,7 @@ const struct flashchip flashchips[] = {
.page_size = 0,
.feature_bits = FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -15223,13 +16290,13 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}
},
- .printlock = printlock_regspace2_block_eraser_0,
- .unlock = unlock_regspace2_block_eraser_0,
- .write = write_82802ab,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .unlock = UNLOCK_REGSPACE2_BLOCK_ERASER_0,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program & erase */
},
@@ -15243,20 +16310,20 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN | FEATURE_NO_ERASE | FEATURE_ERASED_ZERO,
.tested = TEST_OK_PREW,
- .probe = probe_spi_st95,
+ .probe = PROBE_SPI_ST95,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_emulation,
+ .block_erase = SPI_BLOCK_ERASE_EMULATION,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect_bp1_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP1_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2500, 5500},
},
@@ -15270,27 +16337,27 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
/* FIXME: Is this correct?
{
.eraseblocks = { {2 * 1024, 64} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
},*/
{
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect_bp1_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP1_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
@@ -15304,25 +16371,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd,
- .unlock = spi_disable_blockprotect_bp1_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP1_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
@@ -15335,31 +16402,31 @@ const struct flashchip flashchips[] = {
.total_size = 256,
.page_size = 256,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
@@ -15373,25 +16440,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
@@ -15405,31 +16472,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B), dual read (0x3B) and dual I/O (0xBB) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B), dual read (0x3B) and dual I/O (0xBB) supported */
.voltage = {2300, 3600},
},
@@ -15443,25 +16510,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {2 * 1024, 64} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {32 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp1_srwd, /* FIXME: Add ERSER error flag. */
- .unlock = spi_disable_blockprotect_bp1_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD, /* FIXME: Add ERSER error flag. */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP1_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15474,25 +16541,25 @@ const struct flashchip flashchips[] = {
.total_size = 256,
.page_size = 256,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 1024} },
- .block_erase = spi_block_erase_db,
+ .block_erase = SPI_BLOCK_ERASE_DB,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_default_welwip,
- .unlock = NULL, /* #WP pin write-protects lower 64kB. */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_DEFAULT_WELWIP,
+ .unlock = NO_BLOCKPROTECT_FUNC, /* #WP pin write-protects lower 64kB. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15505,25 +16572,25 @@ const struct flashchip flashchips[] = {
.total_size = 512,
.page_size = 256,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256, 2 * 1024} },
- .block_erase = spi_block_erase_db,
+ .block_erase = SPI_BLOCK_ERASE_DB,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_default_welwip,
- .unlock = NULL, /* #WP pin write-protects lower 64kB. */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_DEFAULT_WELWIP,
+ .unlock = NO_BLOCKPROTECT_FUNC, /* #WP pin write-protects lower 64kB. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15537,25 +16604,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15569,25 +16636,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* some quad-read supported ("HD_READ mode") */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* some quad-read supported ("HD_READ mode") */
.voltage = {2700, 3600},
},
@@ -15601,28 +16668,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15636,25 +16703,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_res2,
+ .probe = PROBE_SPI_RES2,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {8 * 1024, 128} },
- .block_erase = spi_block_erase_d7,
+ .block_erase = SPI_BLOCK_ERASE_D7,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* some quad-read supported ("HD_READ mode") */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* some quad-read supported ("HD_READ mode") */
.voltage = {2700, 3600},
},
@@ -15667,7 +16734,7 @@ const struct flashchip flashchips[] = {
.total_size = 1024,
.page_size = 64 * 1024,
.tested = TEST_OK_PREW,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -15676,15 +16743,15 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 15}
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_sector_49lfxxxc,
+ .block_erase = ERASE_SECTOR_49LFXXXC,
}
},
- .unlock = unlock_lh28f008bjt,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_LH28F008BJT,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -15698,7 +16765,7 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET | FEATURE_REGISTERMAP,
.tested = TEST_UNTESTED,
- .probe = probe_82802ab,
+ .probe = PROBE_AT82802AB,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -15707,17 +16774,17 @@ const struct flashchip flashchips[] = {
{64 * 1024, 15},
{8 * 1024, 8}
},
- .block_erase = erase_block_82802ab,
+ .block_erase = ERASE_BLOCK_82802AB,
}, {
.eraseblocks = {
{1024 * 1024, 1}
},
- .block_erase = NULL, /* 30 D0, only in A/A mux mode */
+ .block_erase = NO_BLOCK_ERASE_FUNC, /* 30 D0, only in A/A mux mode */
},
},
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_82802ab,
- .read = read_memmapped,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_82802AB,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -15731,22 +16798,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15760,22 +16827,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PRE,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15789,22 +16856,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15818,22 +16885,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15847,22 +16914,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -15877,28 +16944,28 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 (S25FL116K only) */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 2048 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 2048 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and dual I/O (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and dual I/O (0x3B) supported */
.voltage = {2700, 3600},
},
@@ -15914,25 +16981,25 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 32B reserved; read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect_bp2_srwd, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -15949,7 +17016,7 @@ const struct flashchip flashchips[] = {
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
/* FIXME: we should distinguish the configuration on probing time like we do for AT45DB chips */
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -15962,27 +17029,84 @@ const struct flashchip flashchips[] = {
{4 * 1024, 32},
{64 * 1024, 254} // inaccessible
},
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, { */
.eraseblocks = { { 64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect_bp2_srwd, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
{
.vendor = "Spansion",
+ .name = "S25FL128L",
+ .bustype = BUS_SPI,
+ .manufacture_id = SPANSION_ID,
+ .model_id = SPANSION_S25FL128L,
+ .total_size = 16384,
+ .page_size = 256,
+ /* 4 x 256B Security Region (OTP) */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_WRSR_EXT3 | FEATURE_OTP,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 4096} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {16384 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {16384 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ /*
+ * Note: This chip has a read-only Status Register 2 that is not
+ * counted here. Registers are mapped as follows:
+ * STATUS1 ... Status Register 1
+ * STATUS2 ... Configuration Register 1
+ * STATUS3 ... Configuration Register 2
+ */
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Spansion",
.name = "S25FL128P......0", /* uniform 64 kB sectors */
.bustype = BUS_SPI,
.manufacture_id = SPANSION_ID,
@@ -15991,28 +17115,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -16026,22 +17150,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd,
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -16057,7 +17181,7 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 32B reserved; read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -16069,22 +17193,22 @@ const struct flashchip flashchips[] = {
{4 * 1024, 32},
{64 * 1024, 254} // inaccessible
},
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, { */
.eraseblocks = { { 64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd, /* TODO: SR2 and many others */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: various other locks */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD, /* TODO: SR2 and many others */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: various other locks */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -16100,25 +17224,25 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 32B reserved; read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd, /* TODO: SR2 and many others */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: various other locks */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD, /* TODO: SR2 and many others */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: various other locks */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -16132,24 +17256,24 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_big_spansion,
+ .probe = PROBE_SPI_BIG_SPANSION,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 2000},
},
@@ -16163,24 +17287,24 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_big_spansion,
+ .probe = PROBE_SPI_BIG_SPANSION,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 2000},
},
@@ -16195,7 +17319,7 @@ const struct flashchip flashchips[] = {
/* OTP: 506B total, 16B reserved; read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -16207,29 +17331,29 @@ const struct flashchip flashchips[] = {
{4 * 1024, 32},
{64 * 1024, 254} // inaccessible
},
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, { */
/* FIXME: Additionally it also supports erase opcode 40h for the respective 2*4 kB pairs
.eraseblocks = {
{8 * 1024, 16},
{64 * 1024, 254} // inaccessible
},
- .block_erase = spi_block_erase_40,
+ .block_erase = SPI_BLOCK_ERASE_40,
}, { */
.eraseblocks = { { 64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd, /* TODO: Configuration register */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD, /* TODO: Configuration register */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -16244,25 +17368,25 @@ const struct flashchip flashchips[] = {
/* OTP: 506B total, 16B reserved; read 0x4B; write 0x42 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 16384 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd, /* TODO: Configuration register */
- .unlock = spi_disable_blockprotect_bp2_srwd,
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD, /* TODO: Configuration register */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -16277,28 +17401,28 @@ const struct flashchip flashchips[] = {
/* OTP: 768B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 4096 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 4096 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd, /* TODO: improve */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -16313,28 +17437,28 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44 */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 8192 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 8192 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_srwd, /* TODO: improve */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -16348,28 +17472,28 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PR,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and dual I/O (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and dual I/O (0x3B) supported */
.voltage = {2700, 3600},
},
@@ -16383,29 +17507,95 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD, /* #WP pin write-protects SRWP bit. */
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and dual I/O (0x3B) supported */
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "Spansion",
+ .name = "S25FL256L",
+ .bustype = BUS_SPI,
+ .manufacture_id = SPANSION_ID,
+ .model_id = SPANSION_S25FL256L,
+ .total_size = 32768,
+ .page_size = 256,
+ /* 4 x 256B Security Region (OTP) */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_WRSR_EXT3 | FEATURE_OTP |
+ FEATURE_4BA_ENTER | FEATURE_4BA_NATIVE,
+ .tested = TEST_UNTESTED,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 8192} },
+ .block_erase = SPI_BLOCK_ERASE_21,
+ }, {
+ .eraseblocks = { {4 * 1024, 8192} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_53,
+ }, {
+ .eraseblocks = { {32 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_DC,
+ }, {
+ .eraseblocks = { {64 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {32768 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {32768 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp3_srwd,
- .unlock = spi_disable_blockprotect_bp3_srwd, /* #WP pin write-protects SRWP bit. */
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) and dual I/O (0x3B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ /*
+ * Note: This chip has a read-only Status Register 2 that is not
+ * counted here. Registers are mapped as follows:
+ * STATUS1 ... Status Register 1
+ * STATUS2 ... Configuration Register 1
+ * STATUS3 ... Configuration Register 2
+ */
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -16418,21 +17608,21 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_big_spansion,
+ .probe = PROBE_SPI_BIG_SPANSION,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 64} },
- .block_erase = s25fl_block_erase,
+ .block_erase = S25FL_BLOCK_ERASE,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
},
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 2000},
},
@@ -16446,21 +17636,21 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_big_spansion,
+ .probe = PROBE_SPI_BIG_SPANSION,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = s25fl_block_erase,
+ .block_erase = S25FL_BLOCK_ERASE,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
},
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 2000},
},
@@ -16473,9 +17663,10 @@ const struct flashchip flashchips[] = {
.total_size = 32768,
.page_size = 256,
/* OTP: 1024B total, 32B reserved; read 0x4B; write 0x42 */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_EAR7,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP |
+ FEATURE_4BA_NATIVE | FEATURE_4BA_ENTER_EAR7 | FEATURE_4BA_EAR_1716,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -16487,27 +17678,26 @@ const struct flashchip flashchips[] = {
{4 * 1024, 32},
{64 * 1024, 254} // inaccessible
},
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, { */
.eraseblocks = { { 64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { { 64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 32768 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 32768 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd, /* TODO: SR2 and many others */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: various other locks */
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD, /* TODO: SR2 and many others */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: various other locks */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
- .wrea_override = 0x17,
},
{
@@ -16519,27 +17709,31 @@ const struct flashchip flashchips[] = {
.total_size = 65536, /* 512 Mb (=> 64 MB)) */
.page_size = 256,
/* OTP: 1024B total, 32B reserved; read 0x4B; write 0x42 */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_NATIVE,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP |
+ FEATURE_4BA_NATIVE | FEATURE_4BA_ENTER_EAR7 | FEATURE_4BA_EAR_1716,
+ .tested = TEST_UNTESTED,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { { 256 * 1024, 256} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
+ }, {
+ .eraseblocks = { { 256 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { { 65536 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { { 65536 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_bp2_ep_srwd, /* TODO: SR2 and many others */
- .unlock = spi_disable_blockprotect_bp2_srwd, /* TODO: various other locks */
- .write = spi_chip_write_256, /* Multi I/O supported, IGNORE for now */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD, /* TODO: SR2 and many others */
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD, /* TODO: various other locks */
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported, IGNORE for now */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -16553,24 +17747,24 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_big_spansion,
+ .probe = PROBE_SPI_BIG_SPANSION,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = s25fs_block_erase_d8,
+ .block_erase = S25FS_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 2000},
},
@@ -16584,24 +17778,24 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_big_spansion,
+ .probe = PROBE_SPI_BIG_SPANSION,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = s25fs_block_erase_d8,
+ .block_erase = S25FS_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
},
},
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 2000},
},
@@ -16615,20 +17809,20 @@ const struct flashchip flashchips[] = {
.page_size = 512,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {512, 256} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -16642,20 +17836,20 @@ const struct flashchip flashchips[] = {
.page_size = 512,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {512, 256} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -16669,20 +17863,20 @@ const struct flashchip flashchips[] = {
.page_size = 512,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {512, 512} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
},
{
@@ -16695,20 +17889,20 @@ const struct flashchip flashchips[] = {
.page_size = 512,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {512, 512} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
},
{
@@ -16721,20 +17915,20 @@ const struct flashchip flashchips[] = {
.page_size = 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {1024, 512} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -16748,20 +17942,20 @@ const struct flashchip flashchips[] = {
.page_size = 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {1024, 512} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -16775,20 +17969,20 @@ const struct flashchip flashchips[] = {
.page_size = 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {1024, 512} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -16802,20 +17996,20 @@ const struct flashchip flashchips[] = {
.page_size = 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
{
.eraseblocks = { {1024, 512} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -16829,7 +18023,7 @@ const struct flashchip flashchips[] = {
.page_size = 16384, /* Non-uniform sectors */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -16840,14 +18034,14 @@ const struct flashchip flashchips[] = {
{32 * 1024, 1},
{64 * 1024, 3},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -16861,7 +18055,7 @@ const struct flashchip flashchips[] = {
.page_size = 16384, /* Non-uniform sectors */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = TIMING_ZERO, /* Datasheet has no timing info specified */
.block_erasers =
{
@@ -16872,14 +18066,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -16893,22 +18087,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2048 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -16922,22 +18116,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4096 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -16951,22 +18145,22 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read, /* Fast read (0x0B) supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) supported */
.voltage = {2700, 3600},
},
@@ -16980,34 +18174,46 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP |
+ FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -17018,34 +18224,44 @@ const struct flashchip flashchips[] = {
.model_id = WINBOND_NEX_W25Q128_V_M,
.total_size = 16384,
.page_size = 256,
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR2,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -17058,34 +18274,44 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR2,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -17096,34 +18322,44 @@ const struct flashchip flashchips[] = {
.model_id = WINBOND_NEX_W25Q128_DTR,
.total_size = 16384,
.page_size = 256,
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR2,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -17136,34 +18372,44 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR2,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -17178,31 +18424,31 @@ const struct flashchip flashchips[] = {
/* QPI enable 0x38, disable 0xFF */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 1950}, /* Fast read (0x0B) and multi I/O supported */
},
@@ -17217,37 +18463,37 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 1950}, /* Fast read (0x0B) and multi I/O supported */
},
{
.vendor = "Winbond",
- .name = "W25Q256.V",
+ .name = "W25Q256FV",
.bustype = BUS_SPI,
.manufacture_id = WINBOND_NEX_ID,
.model_id = WINBOND_NEX_W25Q256_V,
@@ -17255,36 +18501,100 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- /* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_ENTER_WREN
- | FEATURE_4BA_EXT_ADDR | FEATURE_4BA_READ | FEATURE_4BA_FAST_READ,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_ENTER_WREN |
+ FEATURE_4BA_EAR_C5C8 | FEATURE_4BA_READ | FEATURE_4BA_FAST_READ |
+ FEATURE_WRSR2,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Winbond",
+ .name = "W25Q256JV_Q",
+ .bustype = BUS_SPI,
+ .manufacture_id = WINBOND_NEX_ID,
+ .model_id = WINBOND_NEX_W25Q256_V,
+ .total_size = 32768,
+ .page_size = 256,
+ /* supports SFDP */
+ /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA | FEATURE_WRSR2,
+ .tested = TEST_UNTESTED,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 8192} },
+ .block_erase = SPI_BLOCK_ERASE_21,
+ }, {
+ .eraseblocks = { {4 * 1024, 8192} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_DC,
+ }, {
+ .eraseblocks = { {64 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {32 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {32 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -17297,46 +18607,54 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- /* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA | FEATURE_WRSR2,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
.vendor = "Winbond",
- .name = "W25Q256.W",
+ .name = "W25Q256JW",
.bustype = BUS_SPI,
.manufacture_id = WINBOND_NEX_ID,
.model_id = WINBOND_NEX_W25Q256_W,
@@ -17344,34 +18662,39 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_ENTER_WREN
- | FEATURE_4BA_EXT_ADDR | FEATURE_4BA_READ | FEATURE_4BA_FAST_READ,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_21,
+ }, {
+ .eraseblocks = { {4 * 1024, 8192} },
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -17385,46 +18708,56 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- /* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA | FEATURE_WRSR2
+ | FEATURE_WRSR3,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 1950},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
.vendor = "Winbond",
- .name = "W25Q32.V",
+ .name = "W25Q32BV/W25Q32CV/W25Q32DV",
.bustype = BUS_SPI,
.manufacture_id = WINBOND_NEX_ID,
.model_id = WINBOND_NEX_W25Q32_V,
@@ -17432,74 +18765,354 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT2,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Winbond",
+ .name = "W25Q32FV",
+ .bustype = BUS_SPI,
+ .manufacture_id = WINBOND_NEX_ID,
+ .model_id = WINBOND_NEX_W25Q32_V,
+ .total_size = 4096,
+ .page_size = 256,
+ /* supports SFDP */
+ /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI |
+ FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
.vendor = "Winbond",
- .name = "W25Q32.W",
+ .name = "W25Q32JV",
+ .bustype = BUS_SPI,
+ .manufacture_id = WINBOND_NEX_ID,
+ .model_id = WINBOND_NEX_W25Q32_V,
+ .total_size = 4096,
+ .page_size = 256,
+ /* supports SFDP */
+ /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP |
+ FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Winbond",
+ .name = "W25Q32BW/W25Q32CW/W25Q32DW",
.bustype = BUS_SPI,
.manufacture_id = WINBOND_NEX_ID,
.model_id = WINBOND_NEX_W25Q32_W,
.total_size = 4096,
.page_size = 256,
- /* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+ /* OTP: 1024B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
/* QPI enable 0x38, disable 0xFF */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR_EXT2,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1700, 1950}, /* Fast read (0x0B) and multi I/O supported */
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Winbond",
+ .name = "W25Q32FW",
+ .bustype = BUS_SPI,
+ .manufacture_id = WINBOND_NEX_ID,
+ .model_id = WINBOND_NEX_W25Q32_W,
+ .total_size = 4096,
+ .page_size = 256,
+ /* OTP: 768B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+ /* QPI enable 0x38, disable 0xFF */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI |
+ FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 1950}, /* Fast read (0x0B) and multi I/O supported */
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Winbond",
+ .name = "W25Q32JW...Q",
+ .bustype = BUS_SPI,
+ .manufacture_id = WINBOND_NEX_ID,
+ .model_id = WINBOND_NEX_W25Q32_W,
+ .total_size = 4096,
+ .page_size = 256,
+ /* OTP: 768B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+ /* QPI enable 0x38, disable 0xFF */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP |
+ FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1700, 1950}, /* Fast read (0x0B) and multi I/O supported */
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Winbond",
+ .name = "W25Q32JW...M",
+ .bustype = BUS_SPI,
+ .manufacture_id = WINBOND_NEX_ID,
+ .model_id = WINBOND_NEX_W25Q32JW_M,
+ .total_size = 4096,
+ .page_size = 256,
+ /* OTP: 768B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+ /* QPI enable 0x38, disable 0xFF */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP |
+ FEATURE_WRSR2 | FEATURE_WRSR3 | FEATURE_WRSR_EXT2,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {4 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1700, 1950},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -17514,31 +19127,31 @@ const struct flashchip flashchips[] = {
/* OTP: 756B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256, /* Multi I/O supported */
- .read = spi_chip_read, /* Fast read (0x0B) and multi I/O supported */
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256, /* Multi I/O supported */
+ .read = SPI_CHIP_READ, /* Fast read (0x0B) and multi I/O supported */
.voltage = {2700, 3600},
},
@@ -17553,31 +19166,31 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 1950}, /* Fast read (0x0B) and multi I/O supported */
},
@@ -17592,31 +19205,31 @@ const struct flashchip flashchips[] = {
/* OTP: 3*256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950}, /* Fast read (0x0B) and multi I/O supported */
},
@@ -17630,43 +19243,97 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_21,
+ .block_erase = SPI_BLOCK_ERASE_21,
}, {
.eraseblocks = { {4 * 1024, 16384} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2048} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_dc,
+ .block_erase = SPI_BLOCK_ERASE_DC,
}, {
.eraseblocks = { {64 * 1024, 1024} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {64 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {64 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
{
+ .vendor = "Winbond",
+ .name = "W25Q512NW-IM",
+ .bustype = BUS_SPI,
+ .manufacture_id = WINBOND_NEX_ID,
+ .model_id = WINBOND_NEX_W25Q512NW_IM,
+ .total_size = 64 * 1024,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA | FEATURE_WRSR2
+ | FEATURE_WRSR3,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 16384} },
+ .block_erase = SPI_BLOCK_ERASE_21,
+ }, {
+ .eraseblocks = { {4 * 1024, 16384} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 2048} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_DC,
+ }, {
+ .eraseblocks = { {64 * 1024, 1024} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {64 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {64 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {1650, 1950},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
.vendor = "Winbond",
- .name = "W25Q64.V",
+ .name = "W25Q64BV/W25Q64CV/W25Q64FV",
.bustype = BUS_SPI,
.manufacture_id = WINBOND_NEX_ID,
.model_id = WINBOND_NEX_W25Q64_V,
@@ -17674,33 +19341,135 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR2,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 2048} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Winbond",
+ .name = "W25Q64JV-.Q",
+ .bustype = BUS_SPI,
+ .manufacture_id = WINBOND_NEX_ID,
+ .model_id = WINBOND_NEX_W25Q64_V,
+ .total_size = 8192,
+ .page_size = 256,
+ /* supports SFDP */
+ /* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP |
+ FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 2048} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "Winbond",
+ .name = "W25Q64JV-.M",
+ .bustype = BUS_SPI,
+ .manufacture_id = WINBOND_NEX_ID,
+ .model_id = WINBOND_NEX_W25Q64JV,
+ .total_size = 8192,
+ .page_size = 256,
+ /* supports SFDP */
+ /* QPI enable 0x38 */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -17714,74 +19483,95 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
/* QPI enable 0x38, disable 0xFF */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR2,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 1950}, /* Fast read (0x0B) and multi I/O supported */
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
.vendor = "Winbond",
- .name = "W25Q64JW",
+ .name = "W25Q64JW...M",
.bustype = BUS_SPI,
.manufacture_id = WINBOND_NEX_ID,
- .model_id = WINBOND_NEX_W25Q64JW,
+ .model_id = WINBOND_NEX_W25Q64JW_M,
.total_size = 8192,
.page_size = 256,
/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
/* QPI enable 0x38, disable 0xFF */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR2 | FEATURE_WRSR3,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 1950}, /* Fast read (0x0B) and multi I/O supported */
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -17796,31 +19586,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -17835,31 +19625,31 @@ const struct flashchip flashchips[] = {
/* OTP: 256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1700, 1950}, /* Fast read (0x0B) and multi I/O supported */
},
@@ -17874,31 +19664,31 @@ const struct flashchip flashchips[] = {
/* OTP: 3*256B total; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 32} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {1 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950}, /* Fast read (0x0B) and multi I/O supported */
},
@@ -17912,25 +19702,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 16} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 2} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2300, 3600},
},
@@ -17944,25 +19734,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 2} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -17976,31 +19766,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 512} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 64} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 32} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {2 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -18013,27 +19803,34 @@ const struct flashchip flashchips[] = {
.total_size = 256,
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
- .tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREWB,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}},
+ .tb = {STATUS1, 5, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -18046,31 +19843,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 1024} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 128} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -18084,25 +19881,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -18116,31 +19913,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -18154,25 +19951,25 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_OK_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 256} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -18187,17 +19984,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10, /* used datasheet for the W29C011A */
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
},
{
@@ -18210,17 +20007,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_w29ee011,
+ .probe = PROBE_W29EE011,
.probe_timing = TIMING_IGNORED, /* routine doesn't use probe_timing (w29ee011.c) */
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
},
{
@@ -18233,17 +20030,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -18257,17 +20054,17 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -18281,17 +20078,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_LONG_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec,
- .read = read_memmapped,
+ .write = WRITE_JEDEC,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -18305,7 +20102,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -18314,14 +20111,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 63},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -18335,20 +20132,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 64} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -18362,7 +20159,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -18371,14 +20168,14 @@ const struct flashchip flashchips[] = {
{64 * 1024, 63},
{8 * 1024, 8},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {4 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -18392,7 +20189,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -18401,14 +20198,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 8},
{64 * 1024, 127},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -18422,20 +20219,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -18449,7 +20246,7 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
@@ -18458,14 +20255,14 @@ const struct flashchip flashchips[] = {
{64 * 1024, 127},
{8 * 1024, 8},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -18479,20 +20276,20 @@ const struct flashchip flashchips[] = {
.page_size = 128 * 1024, /* actual page size is 16 */
.feature_bits = FEATURE_ADDR_2AA | FEATURE_SHORT_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec_29gl,
+ .probe = PROBE_JEDEC_29GL,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {128 * 1024, 128} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
},
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {2700, 3600},
},
@@ -18506,21 +20303,21 @@ const struct flashchip flashchips[] = {
.page_size = 4 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39f010,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39F010,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -18534,21 +20331,21 @@ const struct flashchip flashchips[] = {
.page_size = 4 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 32} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {128 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39l010,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39L010,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -18562,24 +20359,24 @@ const struct flashchip flashchips[] = {
.page_size = 4 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39l020,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39L020,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -18593,24 +20390,24 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PR,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39l040,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39L040,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -18624,21 +20421,21 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39v040a,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39V040A,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -18652,21 +20449,21 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39v040b,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39V040B,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -18680,21 +20477,21 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39v040c,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39V040C,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -18708,25 +20505,25 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = erase_block_jedec,
+ .block_erase = JEDEC_BLOCK_ERASE,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39v040fa,
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39V040FA,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -18740,22 +20537,22 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39v040fb,
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39V040FB,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program */
},
@@ -18769,21 +20566,21 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39v040fc,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39V040FC,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program */
},
@@ -18797,21 +20594,21 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39v080a,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39V080A,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -18825,22 +20622,22 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 16} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {1024 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39v080fa,
- .unlock = unlock_regspace2_uniform_64k,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39V080FA,
+ .unlock = UNLOCK_REGSPACE2_UNIFORM_64K,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program */
},
@@ -18854,21 +20651,21 @@ const struct flashchip flashchips[] = {
.page_size = 64 * 1024,
.feature_bits = FEATURE_REGISTERMAP | FEATURE_EITHER_RESET,
.tested = TEST_UNTESTED,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .printlock = printlock_w39v080fa_dual,
- .write = write_jedec_1,
- .read = read_memmapped,
+ .printlock = PRINTLOCK_W39V080FA_DUAL,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600}, /* Also has 12V fast program */
},
@@ -18882,7 +20679,7 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
@@ -18893,14 +20690,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -18914,17 +20711,17 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PROBE,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
{
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {4500, 5500},
},
@@ -18938,7 +20735,7 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
@@ -18949,14 +20746,14 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
@@ -18970,7 +20767,7 @@ const struct flashchip flashchips[] = {
.page_size = 128,
.feature_bits = FEATURE_EITHER_RESET,
.tested = TEST_OK_PREW,
- .probe = probe_jedec,
+ .probe = PROBE_JEDEC,
.probe_timing = 10,
.block_erasers =
{
@@ -18981,19 +20778,57 @@ const struct flashchip flashchips[] = {
{8 * 1024, 2},
{16 * 1024, 1},
},
- .block_erase = erase_sector_jedec,
+ .block_erase = JEDEC_SECTOR_ERASE,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = erase_chip_block_jedec,
+ .block_erase = JEDEC_CHIP_BLOCK_ERASE,
}
},
- .write = write_jedec_1,
- .read = read_memmapped,
+ .write = WRITE_JEDEC1,
+ .read = READ_MEMMAPPED,
.voltage = {3000, 3600},
},
{
.vendor = "XMC",
+ .name = "XM25QH80B",
+ .bustype = BUS_SPI,
+ .manufacture_id = ST_ID,
+ .model_id = ST_M45PE80,
+ .total_size = 1024,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 32} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 16} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {1 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {1 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "XMC",
.name = "XM25QH64C",
.bustype = BUS_SPI,
.manufacture_id = ST_ID,
@@ -19001,32 +20836,32 @@ const struct flashchip flashchips[] = {
.total_size = 8192,
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -19040,70 +20875,128 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 2048} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 256} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 128} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {8 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
{
.vendor = "XMC",
+ .name = "XM25QH128A",
+ .bustype = BUS_SPI,
+ .manufacture_id = ST_ID,
+ .model_id = XMC_XM25QH128A,
+ .total_size = 16384,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR2,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 4096} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {16 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {16 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+ },
+
+ {
+ .vendor = "XMC",
.name = "XM25QH128C",
.bustype = BUS_SPI,
.manufacture_id = ST_ID,
.model_id = XMC_XM25QH128C,
.total_size = 16384,
.page_size = 256,
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI | FEATURE_WRSR2,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain,
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -19118,31 +21011,31 @@ const struct flashchip flashchips[] = {
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 4096} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 512} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 256} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {16 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
@@ -19156,36 +21049,44 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- /* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
- .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_ENTER_WREN
- | FEATURE_4BA_EXT_ADDR | FEATURE_4BA_READ | FEATURE_4BA_FAST_READ,
- .tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_ENTER_WREN |
+ FEATURE_4BA_EAR_C5C8 | FEATURE_4BA_READ | FEATURE_4BA_FAST_READ |
+ FEATURE_4BA_WRITE | FEATURE_WRSR2,
+ .tested = TEST_OK_PR,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}, {STATUS1, 5, RW}},
+ .tb = {STATUS1, 6, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
},
{
@@ -19198,39 +21099,114 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* supports SFDP */
/* OTP: 1024B total, 256B reserved; read 0x48; write 0x42, erase 0x44, read ID 0x4B */
- /* FOUR_BYTE_ADDR: supports 4-bytes addressing mode */
.feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_4BA_ENTER_WREN
- | FEATURE_4BA_EXT_ADDR | FEATURE_4BA_READ | FEATURE_4BA_FAST_READ,
+ | FEATURE_4BA_EAR_C5C8 | FEATURE_4BA_READ | FEATURE_4BA_FAST_READ
+ | FEATURE_4BA_WRITE,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 8192} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 1024} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 512} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {32 * 1024 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {1650, 1950},
},
{
+ .vendor = "XTX Technology Limited",
+ .name = "XT25F02E",
+ .bustype = BUS_SPI,
+ .manufacture_id = XTX_ID,
+ .model_id = XTX_XT25F02E,
+ .total_size = 256,
+ .page_size = 256,
+ .feature_bits = FEATURE_WRSR_WREN,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 64} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {64 * 1024, 4} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {256 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {256 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP1_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ },
+
+ {
+ .vendor = "XTX Technology Limited",
+ .name = "XT25F64B",
+ .bustype = BUS_SPI,
+ .manufacture_id = XTX_ID,
+ .model_id = XTX_XT25F64B,
+ .total_size = 8 * 1024,
+ .page_size = 256,
+ /* Supports SFDP */
+ /* OTP: 4 x 256 bytes */
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_QPI,
+ .tested = TEST_OK_PREW,
+ .probe = PROBE_SPI_RDID,
+ .probe_timing = TIMING_ZERO,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 2048} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 128} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {8 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ .unlock = SPI_DISABLE_BLOCKPROTECT_BP4_SRWD,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
+ .voltage = {2700, 3600},
+ },
+
+ {
.vendor = "Zetta Device",
.name = "ZD25D20",
.bustype = BUS_SPI,
@@ -19240,31 +21216,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 64} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 8} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 4} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {256 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -19278,31 +21254,31 @@ const struct flashchip flashchips[] = {
.page_size = 256,
.feature_bits = FEATURE_WRSR_WREN,
.tested = TEST_UNTESTED,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
.block_erasers =
{
{
.eraseblocks = { {4 * 1024, 128} },
- .block_erase = spi_block_erase_20,
+ .block_erase = SPI_BLOCK_ERASE_20,
}, {
.eraseblocks = { {32 * 1024, 16} },
- .block_erase = spi_block_erase_52,
+ .block_erase = SPI_BLOCK_ERASE_52,
}, {
.eraseblocks = { {64 * 1024, 8} },
- .block_erase = spi_block_erase_d8,
+ .block_erase = SPI_BLOCK_ERASE_D8,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_60,
+ .block_erase = SPI_BLOCK_ERASE_60,
}, {
.eraseblocks = { {512 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
+ .block_erase = SPI_BLOCK_ERASE_C7,
}
},
- .printlock = spi_prettyprint_status_register_plain, /* TODO: improve */
- .unlock = spi_disable_blockprotect,
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .printlock = SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN, /* TODO: improve */
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .write = SPI_CHIP_WRITE256,
+ .read = SPI_CHIP_READ,
.voltage = {2700, 3600},
},
@@ -19319,11 +21295,11 @@ const struct flashchip flashchips[] = {
/* want the default "This flash part has status UNTESTED..." */
/* text to be printed. */
.tested = TEST_OK_PREW,
- .probe = probe_spi_sfdp,
+ .probe = PROBE_SPI_SFDP,
.block_erasers = {}, /* set by probing function */
- .unlock = spi_disable_blockprotect, /* is this safe? */
- .write = NULL, /* set by probing function */
- .read = spi_chip_read,
+ .unlock = SPI_DISABLE_BLOCKPROTECT, /* is this safe? */
+ .write = 0, /* set by probing function */
+ .read = SPI_CHIP_READ,
/* FIXME: some vendor extensions define this */
.voltage = {0},
},
@@ -19338,16 +21314,16 @@ const struct flashchip flashchips[] = {
.page_size = 256,
/* probe is assumed to work, rest will be filled in by probe */
.tested = TEST_OK_PROBE,
- .probe = probe_opaque,
+ .probe = PROBE_OPAQUE,
/* eraseblock sizes will be set by the probing function */
.block_erasers =
{
{
- .block_erase = erase_opaque,
+ .block_erase = OPAQUE_ERASE,
}
},
- .write = write_opaque,
- .read = read_opaque,
+ .write = WRITE_OPAQUE,
+ .read = READ_OPAQUE,
},
{
@@ -19359,10 +21335,10 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid4,
+ .probe = PROBE_SPI_RDID4,
.probe_timing = TIMING_ZERO,
- .write = NULL,
- .read = NULL,
+ .write = 0,
+ .read = 0,
},
{
@@ -19374,10 +21350,10 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL,
- .read = NULL,
+ .write = 0,
+ .read = 0,
},
{
@@ -19389,10 +21365,10 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL,
- .read = NULL,
+ .write = 0,
+ .read = 0,
},
{
@@ -19404,10 +21380,10 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL,
- .read = NULL,
+ .write = 0,
+ .read = 0,
},
{
@@ -19419,10 +21395,10 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL,
- .read = NULL,
+ .write = 0,
+ .read = 0,
},
{
@@ -19434,10 +21410,10 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL,
- .read = NULL,
+ .write = 0,
+ .read = 0,
},
{
@@ -19449,10 +21425,10 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL,
- .read = NULL,
+ .write = 0,
+ .read = 0,
},
{
@@ -19464,10 +21440,10 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL,
- .read = NULL,
+ .write = 0,
+ .read = 0,
},
{
@@ -19479,32 +21455,10 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
+ .probe = PROBE_SPI_RDID,
.probe_timing = TIMING_ZERO,
- .write = NULL,
- .read = NULL,
- },
-
- {
- .vendor = "Generic",
- .name = "Variable Size SPI chip",
- .bustype = BUS_SPI,
- .manufacture_id = PROGMANUF_ID,
- .model_id = PROGDEV_ID,
- .total_size = 64, /* This size is set temporarily */
- .page_size = 256,
- .feature_bits = FEATURE_4BA,
- .tested = TEST_OK_PREW,
- .probe = probe_variable_size,
- .block_erasers =
- {
- {
- .eraseblocks = { {64 * 1024, 1} },
- .block_erase = spi_block_erase_c7,
- }
- },
- .write = spi_chip_write_256,
- .read = spi_chip_read,
+ .write = 0,
+ .read = 0,
},
{
@@ -19516,8 +21470,8 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
- .write = NULL,
+ .probe = PROBE_SPI_RDID,
+ .write = 0,
},
{
@@ -19529,8 +21483,8 @@ const struct flashchip flashchips[] = {
.total_size = 0,
.page_size = 256,
.tested = TEST_BAD_PREW,
- .probe = probe_spi_rems,
- .write = NULL,
+ .probe = PROBE_SPI_REMS,
+ .write = 0,
},
{0}
diff --git a/flashrom.8.tmpl b/flashrom.8.tmpl
deleted file mode 100644
index 02f60dc9b..000000000
--- a/flashrom.8.tmpl
+++ /dev/null
@@ -1,1539 +0,0 @@
-.\" Load the www device when using groff; provide a fallback for groff's MTO macro that formats email addresses.
-.ie \n[.g] \
-. mso www.tmac
-.el \{
-. de MTO
- \\$2 \(la\\$1 \(ra\\$3 \
-. .
-.\}
-.\" Create wrappers for .MTO and .URL that print only text on systems w/o groff or if not outputting to a HTML
-.\" device. To that end we need to distinguish HTML output on groff from other configurations first.
-.nr groffhtml 0
-.if \n[.g] \
-. if "\*[.T]"html" \
-. nr groffhtml 1
-.\" For code reuse it would be nice to have a single wrapper that gets its target macro as parameter.
-.\" However, this did not work out with NetBSD's and OpenBSD's groff...
-.de URLB
-. ie (\n[groffhtml]==1) \{\
-. URL \\$@
-. \}
-. el \{\
-. ie "\\$2"" \{\
-. BR "\\$1" "\\$3"
-. \}
-. el \{\
-. RB "\\$2 \(la" "\\$1" "\(ra\\$3"
-. \}
-. \}
-..
-.de MTOB
-. ie (\n[groffhtml]==1) \{\
-. MTO \\$@
-. \}
-. el \{\
-. ie "\\$2"" \{\
-. BR "\\$1" "\\$3"
-. \}
-. el \{\
-. RB "\\$2 \(la" "\\$1" "\(ra\\$3"
-. \}
-. \}
-..
-.TH FLASHROM 8 "@MAN_DATE@" "@VERSION@" "@MAN_DATE@"
-.SH NAME
-flashrom \- detect, read, write, verify and erase flash chips
-.SH SYNOPSIS
-.B flashrom \fR[\fB\-h\fR|\fB\-R\fR|\fB\-L\fR|\fB\-z\fR|
- \fB\-p\fR <programmername>[:<parameters>] [\fB\-c\fR <chipname>]
- (\fB\-\-flash\-name\fR|\fB\-\-flash\-size\fR|
- [\fB\-E\fR|\fB\-r\fR <file>|\fB\-w\fR <file>|\fB\-v\fR <file>]
- [(\fB\-l\fR <file>|\fB\-\-ifd|\fB \-\-fmap\fR|\fB\-\-fmap-file\fR <file>) [\fB\-i\fR <image>]]
- [\fB\-n\fR] [\fB\-N\fR] [\fB\-f\fR])]
- [\fB\-V\fR[\fBV\fR[\fBV\fR]]] [\fB-o\fR <logfile>]
-.SH DESCRIPTION
-.B flashrom
-is a utility for detecting, reading, writing, verifying and erasing flash
-chips. It's often used to flash BIOS/EFI/coreboot/firmware images in-system
-using a supported mainboard. However, it also supports various external
-PCI/USB/parallel-port/serial-port based devices which can program flash chips,
-including some network cards (NICs), SATA/IDE controller cards, graphics cards,
-the Bus Pirate device, various FTDI FT2232/FT4232H/FT232H based USB devices, and more.
-.PP
-It supports a wide range of DIP32, PLCC32, DIP8, SO8/SOIC8, TSOP32, TSOP40,
-TSOP48, and BGA chips, which use various protocols such as LPC, FWH,
-parallel flash, or SPI.
-.SH OPTIONS
-.B IMPORTANT:
-Please note that the command line interface for flashrom will change before
-flashrom 1.0. Do not use flashrom in scripts or other automated tools without
-checking that your flashrom version won't interpret options in a different way.
-.PP
-You can specify one of
-.BR \-h ", " \-R ", " \-L ", " \-z ", " \-E ", " \-r ", " \-w ", " \-v
-or no operation.
-If no operation is specified, flashrom will only probe for flash chips. It is
-recommended that if you try flashrom the first time on a system, you run it
-in probe-only mode and check the output. Also you are advised to make a
-backup of your current ROM contents with
-.B \-r
-before you try to write a new image. All operations involving any chip access (probe/read/write/...) require the
-.B -p/--programmer
-option to be used (please see below).
-.TP
-.B "\-r, \-\-read <file>"
-Read flash ROM contents and save them into the given
-.BR <file> .
-If the file already exists, it will be overwritten.
-.TP
-.B "\-w, \-\-write <file>"
-Write
-.B <file>
-into flash ROM. This will first automatically
-.B erase
-the chip, then write to it.
-.sp
-In the process the chip is also read several times. First an in-memory backup
-is made for disaster recovery and to be able to skip regions that are
-already equal to the image file. This copy is updated along with the write
-operation. In case of erase errors it is even re-read completely. After
-writing has finished and if verification is enabled, the whole flash chip is
-read out and compared with the input image.
-.TP
-.B "\-n, \-\-noverify"
-Skip the automatic verification of flash ROM contents after writing. Using this
-option is
-.B not
-recommended, you should only use it if you know what you are doing and if you
-feel that the time for verification takes too long.
-.sp
-Typical usage is:
-.B "flashrom \-p prog \-n \-w <file>"
-.sp
-This option is only useful in combination with
-.BR \-\-write .
-.TP
-.B "\-N, \-\-noverify-all"
-Skip not included regions during automatic verification after writing (cf.
-.BR "\-l " "and " "\-i" ).
-You should only use this option if you are sure that communication with
-the flash chip is reliable (e.g. when using the
-.BR internal
-programmer). Even if flashrom is instructed not to touch parts of the
-flash chip, their contents could be damaged (e.g. due to misunderstood
-erase commands).
-.sp
-This option is required to flash an Intel system with locked ME flash
-region using the
-.BR internal
-programmer. It may be enabled by default in this case in the future.
-.TP
-.B "\-v, \-\-verify <file>"
-Verify the flash ROM contents against the given
-.BR <file> .
-.TP
-.B "\-E, \-\-erase"
-Erase the flash ROM chip.
-.TP
-.B "\-V, \-\-verbose"
-More verbose output. This option can be supplied multiple times
-(max. 3 times, i.e.
-.BR \-VVV )
-for even more debug output.
-.TP
-.B "\-c, \-\-chip" <chipname>
-Probe only for the specified flash ROM chip. This option takes the chip name as
-printed by
-.B "flashrom \-L"
-without the vendor name as parameter. Please note that the chip name is
-case sensitive.
-.TP
-.B "\-f, \-\-force"
-Force one or more of the following actions:
-.sp
-* Force chip read and pretend the chip is there.
-.sp
-* Force chip access even if the chip is bigger than the maximum supported \
-size for the flash bus.
-.sp
-* Force erase even if erase is known bad.
-.sp
-* Force write even if write is known bad.
-.TP
-.B "\-l, \-\-layout <file>"
-Read ROM layout from
-.BR <file> .
-.sp
-flashrom supports ROM layouts. This allows you to flash certain parts of
-the flash chip only. A ROM layout file contains multiple lines with the
-following syntax:
-.sp
-.B " startaddr:endaddr imagename"
-.sp
-.BR "startaddr " "and " "endaddr "
-are hexadecimal addresses within the ROM file and do not refer to any
-physical address. Please note that using a 0x prefix for those hexadecimal
-numbers is not necessary, but you can't specify decimal/octal numbers.
-.BR "imagename " "is an arbitrary name for the region/image from"
-.BR " startaddr " "to " "endaddr " "(both addresses included)."
-.sp
-Example:
-.sp
- 00000000:00008fff gfxrom
- 00009000:0003ffff normal
- 00040000:0007ffff fallback
-.sp
-If you only want to update the image named
-.BR "normal " "in a ROM based on the layout above, run"
-.sp
-.B " flashrom \-p prog \-\-layout rom.layout \-\-image normal \-w some.rom"
-.sp
-To update only the images named
-.BR "normal " "and " "fallback" ", run:"
-.sp
-.B " flashrom \-p prog \-l rom.layout \-i normal -i fallback \-w some.rom"
-.sp
-Overlapping sections are not supported.
-.TP
-.B "\-\-fmap"
-Read layout from fmap in flash chip.
-.sp
-flashrom supports the fmap binary format which is commonly used by coreboot
-for partitioning a flash chip. The on-chip fmap will be read and used to generate
-the layout.
-.sp
-If you only want to update the
-.BR "COREBOOT"
-region defined in the fmap, run
-.sp
-.B " flashrom -p prog \-\-fmap \-\-image COREBOOT \-w some.rom"
-.TP
-.B "\-\-fmap-file <file>"
-Read layout from a
-.BR <file>
-containing binary fmap (e.g. coreboot roms).
-.sp
-flashrom supports the fmap binary format which is commonly used by coreboot
-for partitioning a flash chip. The fmap in the specified file will be read and
-used to generate the layout.
-.sp
-If you only want to update the
-.BR "COREBOOT"
-region defined in the binary fmap file, run
-.sp
-.B " flashrom \-p prog \-\-fmap-file some.rom \-\-image COREBOOT \-w some.rom"
-.TP
-.B "\-\-ifd"
-Read ROM layout from Intel Firmware Descriptor.
-.sp
-flashrom supports ROM layouts given by an Intel Firmware Descriptor
-(IFD). The on-chip descriptor will be read and used to generate the
-layout. If you need to change the layout, you have to update the IFD
-only first.
-.sp
-The following ROM images may be present in an IFD:
-.sp
- fd the IFD itself
- bios the host firmware aka. BIOS
- me Intel Management Engine firmware
- gbe gigabit ethernet firmware
- pd platform specific data
-.TP
-.B "\-i, \-\-image <imagename>"
-Only flash region/image
-.B <imagename>
-from flash layout.
-.TP
-.B "\-\-flash\-name"
-Prints out the detected flash chips name.
-.TP
-.B "\-\-flash\-size"
-Prints out the detected flash chips size.
-.TP
-.B "\-L, \-\-list\-supported"
-List the flash chips, chipsets, mainboards, and external programmers
-(including PCI, USB, parallel port, and serial port based devices)
-supported by flashrom.
-.sp
-There are many unlisted boards which will work out of the box, without
-special support in flashrom. Please let us know if you can verify that
-other boards work or do not work out of the box.
-.sp
-.B IMPORTANT:
-For verification you have
-to test an ERASE and/or WRITE operation, so make sure you only do that
-if you have proper means to recover from failure!
-.TP
-.B "\-z, \-\-list\-supported-wiki"
-Same as
-.BR \-\-list\-supported ,
-but outputs the supported hardware in MediaWiki syntax, so that it can be
-easily pasted into the
-.URLB https://flashrom.org/Supported_hardware "supported hardware wiki page" .
-Please note that MediaWiki output is not compiled in by default.
-.TP
-.B "\-p, \-\-programmer <name>[:parameter[,parameter[,parameter]]]"
-Specify the programmer device. This is mandatory for all operations
-involving any chip access (probe/read/write/...). Currently supported are:
-.sp
-.BR "* internal" " (for in-system flashing in the mainboard)"
-.sp
-.BR "* dummy" " (virtual programmer for testing flashrom)"
-.sp
-.BR "* nic3com" " (for flash ROMs on 3COM network cards)"
-.sp
-.BR "* nicrealtek" " (for flash ROMs on Realtek and SMC 1211 network cards)"
-.sp
-.BR "* nicnatsemi" " (for flash ROMs on National Semiconductor DP838* network \
-cards)"
-.sp
-.BR "* nicintel" " (for parallel flash ROMs on Intel 10/100Mbit network cards)
-.sp
-.BR "* gfxnvidia" " (for flash ROMs on NVIDIA graphics cards)"
-.sp
-.BR "* drkaiser" " (for flash ROMs on Dr. Kaiser PC-Waechter PCI cards)"
-.sp
-.BR "* satasii" " (for flash ROMs on Silicon Image SATA/IDE controllers)"
-.sp
-.BR "* satamv" " (for flash ROMs on Marvell SATA controllers)"
-.sp
-.BR "* atahpt" " (for flash ROMs on Highpoint ATA/RAID controllers)"
-.sp
-.BR "* atavia" " (for flash ROMs on VIA VT6421A SATA controllers)"
-.sp
-.BR "* atapromise" " (for flash ROMs on Promise PDC2026x ATA/RAID controllers)"
-.sp
-.BR "* it8212" " (for flash ROMs on ITE IT8212F ATA/RAID controller)"
-.sp
-.BR "* ft2232_spi" " (for SPI flash ROMs attached to an FT2232/FT4232H/FT232H family based USB SPI programmer).
-.sp
-.BR "* serprog" " (for flash ROMs attached to a programmer speaking serprog, \
-including some Arduino-based devices)."
-.sp
-.BR "* buspirate_spi" " (for SPI flash ROMs attached to a Bus Pirate)"
-.sp
-.BR "* dediprog" " (for SPI flash ROMs attached to a Dediprog SF100)"
-.sp
-.BR "* rayer_spi" " (for SPI flash ROMs attached to a parallel port by one of various cable types)"
-.sp
-.BR "* pony_spi" " (for SPI flash ROMs attached to a SI-Prog serial port "
-bitbanging adapter)
-.sp
-.BR "* nicintel_spi" " (for SPI flash ROMs on Intel Gigabit network cards)"
-.sp
-.BR "* ogp_spi" " (for SPI flash ROMs on Open Graphics Project graphics card)"
-.sp
-.BR "* linux_mtd" " (for SPI flash ROMs accessible via /dev/mtdX on Linux)"
-.sp
-.BR "* linux_spi" " (for SPI flash ROMs accessible via /dev/spidevX.Y on Linux)"
-.sp
-.BR "* usbblaster_spi" " (for SPI flash ROMs attached to an Altera USB-Blaster compatible cable)"
-.sp
-.BR "* nicintel_eeprom" " (for SPI EEPROMs on Intel Gigabit network cards)"
-.sp
-.BR "* mstarddc_spi" " (for SPI flash ROMs accessible through DDC in MSTAR-equipped displays)"
-.sp
-.BR "* pickit2_spi" " (for SPI flash ROMs accessible via Microchip PICkit2)"
-.sp
-.BR "* ch341a_spi" " (for SPI flash ROMs attached to WCH CH341A)"
-.sp
-.BR "* digilent_spi" " (for SPI flash ROMs attached to iCEblink40 development boards)"
-.sp
-.BR "* jlink_spi" " (for SPI flash ROMs attached to SEGGER J-Link and compatible devices)"
-.sp
-.BR "* ni845x_spi" " (for SPI flash ROMs attached to National Instruments USB-8451 or USB-8452)"
-.sp
-.BR "* stlinkv3_spi" " (for SPI flash ROMs attached to STMicroelectronics STLINK V3 devices)"
-.sp
-Some programmers have optional or mandatory parameters which are described
-in detail in the
-.B PROGRAMMER-SPECIFIC INFORMATION
-section. Support for some programmers can be disabled at compile time.
-.B "flashrom \-h"
-lists all supported programmers.
-.TP
-.B "\-h, \-\-help"
-Show a help text and exit.
-.TP
-.B "\-o, \-\-output <logfile>"
-Save the full debug log to
-.BR <logfile> .
-If the file already exists, it will be overwritten. This is the recommended
-way to gather logs from flashrom because they will be verbose even if the
-on-screen messages are not verbose and don't require output redirection.
-.TP
-.B "\-R, \-\-version"
-Show version information and exit.
-.SH PROGRAMMER-SPECIFIC INFORMATION
-Some programmer drivers accept further parameters to set programmer-specific
-parameters. These parameters are separated from the programmer name by a
-colon. While some programmers take arguments at fixed positions, other
-programmers use a key/value interface in which the key and value is separated
-by an equal sign and different pairs are separated by a comma or a colon.
-.SS
-.BR "internal " programmer
-.TP
-.B Board Enables
-.sp
-Some mainboards require to run mainboard specific code to enable flash erase
-and write support (and probe support on old systems with parallel flash).
-The mainboard brand and model (if it requires specific code) is usually
-autodetected using one of the following mechanisms: If your system is
-running coreboot, the mainboard type is determined from the coreboot table.
-Otherwise, the mainboard is detected by examining the onboard PCI devices
-and possibly DMI info. If PCI and DMI do not contain information to uniquely
-identify the mainboard (which is the exception), or if you want to override
-the detected mainboard model, you can specify the mainboard using the
-.sp
-.B " flashrom \-p internal:mainboard=<vendor>:<board>"
-syntax.
-.sp
-See the 'Known boards' or 'Known laptops' section in the output
-of 'flashrom \-L' for a list of boards which require the specification of
-the board name, if no coreboot table is found.
-.sp
-Some of these board-specific flash enabling functions (called
-.BR "board enables" )
-in flashrom have not yet been tested. If your mainboard is detected needing
-an untested board enable function, a warning message is printed and the
-board enable is not executed, because a wrong board enable function might
-cause the system to behave erratically, as board enable functions touch the
-low-level internals of a mainboard. Not executing a board enable function
-(if one is needed) might cause detection or erasing failure. If your board
-protects only part of the flash (commonly the top end, called boot block),
-flashrom might encounter an error only after erasing the unprotected part,
-so running without the board-enable function might be dangerous for erase
-and write (which includes erase).
-.sp
-The suggested procedure for a mainboard with untested board specific code is
-to first try to probe the ROM (just invoke flashrom and check that it
-detects your flash chip type) without running the board enable code (i.e.
-without any parameters). If it finds your chip, fine. Otherwise, retry
-probing your chip with the board-enable code running, using
-.sp
-.B " flashrom \-p internal:boardenable=force"
-.sp
-If your chip is still not detected, the board enable code seems to be broken
-or the flash chip unsupported. Otherwise, make a backup of your current ROM
-contents (using
-.BR \-r )
-and store it to a medium outside of your computer, like
-a USB drive or a network share. If you needed to run the board enable code
-already for probing, use it for reading too.
-If reading succeeds and the contens of the read file look legit you can try to write the new image.
-You should enable the board enable code in any case now, as it
-has been written because it is known that writing/erasing without the board
-enable is going to fail. In any case (success or failure), please report to
-the flashrom mailing list, see below.
-.sp
-.TP
-.B Coreboot
-.sp
-On systems running coreboot, flashrom checks whether the desired image matches
-your mainboard. This needs some special board ID to be present in the image.
-If flashrom detects that the image you want to write and the current board
-do not match, it will refuse to write the image unless you specify
-.sp
-.B " flashrom \-p internal:boardmismatch=force"
-.TP
-.B ITE IT87 Super I/O
-.sp
-If your mainboard is manufactured by GIGABYTE and supports DualBIOS it is very likely that it uses an
-ITE IT87 series Super I/O to switch between the two flash chips. Only one of them can be accessed at a time
-and you can manually select which one to use with the
-.sp
-.B " flashrom \-p internal:dualbiosindex=chip"
-.sp
-syntax where
-.B chip
-is the index of the chip to use (0 = main, 1 = backup). You can check which one is currently selected by
-leaving out the
-.B chip
-parameter.
-.sp
-If your mainboard uses an ITE IT87 series Super I/O for LPC<->SPI flash bus
-translation, flashrom should autodetect that configuration. If you want to
-set the I/O base port of the IT87 series SPI controller manually instead of
-using the value provided by the BIOS, use the
-.sp
-.B " flashrom \-p internal:it87spiport=portnum"
-.sp
-syntax where
-.B portnum
-is the I/O port number (must be a multiple of 8). In the unlikely case
-flashrom doesn't detect an active IT87 LPC<->SPI bridge, please send a bug
-report so we can diagnose the problem.
-.sp
-.TP
-.B AMD chipsets
-.sp
-Beginning with the SB700 chipset there is an integrated microcontroller (IMC) based on the 8051 embedded in
-every AMD southbridge. Its firmware resides in the same flash chip as the host's which makes writing to the
-flash risky if the IMC is active. Flashrom tries to temporarily disable the IMC but even then changing the
-contents of the flash can have unwanted effects: when the IMC continues (at the latest after a reboot) it will
-continue executing code from the flash. If the code was removed or changed in an unfortunate way it is
-unpredictable what the IMC will do. Therefore, if flashrom detects an active IMC it will disable write support
-unless the user forces it with the
-.sp
-.B " flashrom \-p internal:amd_imc_force=yes"
-.sp
-syntax. The user is responsible for supplying a suitable image or leaving out the IMC region with the help of
-a layout file. This limitation might be removed in the future when we understand the details better and have
-received enough feedback from users. Please report the outcome if you had to use this option to write a chip.
-.sp
-An optional
-.B spispeed
-parameter specifies the frequency of the SPI bus where applicable (i.e.\& SB600 or later with an SPI flash chip
-directly attached to the chipset).
-Syntax is
-.sp
-.B " flashrom \-p internal:spispeed=frequency"
-.sp
-where
-.B frequency
-can be
-.BR "'16.5\ MHz'" ", " "'22\ MHz'" ", " "'33\ MHz'" ", " "'66\ MHz'" ", " "'100\ MHZ'" ", or " "'800\ kHz'" "."
-Support of individual frequencies depends on the generation of the chipset:
-.sp
-* SB6xx, SB7xx, SP5xxx: from 16.5 MHz up to and including 33 MHz
-.sp
--The default is to use 16.5 MHz and disable Fast Reads.
-.sp
-* SB8xx, SB9xx, Hudson: from 16.5 MHz up to and including 66 MHz
-.sp
--The default is to use 16.5 MHz and disable Fast Reads.
-.sp
-* Yangtze (with SPI 100 engine as found in Kabini and Tamesh): all of them
-.sp
--The default is to use the frequency that is currently configured.
-.sp
-An optional
-.B spireadmode
-parameter specifies the read mode of the SPI bus where applicable (Bolton or later).
-Syntax is
-.sp
-.B " flashrom \-p internal:spireadmode=mode"
-.sp
-where
-.B mode
-can be
-.BR "'Normal\ (up\ to\ 33 MHz)'" ", " "'Normal\ (up\ to\ 66 MHz)'" ", " "'Dual\ IO\ (1-1-2)'" ", " "'Quad\ IO\ (1-1-4)'" ", " "'Dual\ IO\ (1-2-2)'" ", " "'Quad\ IO\ (1-4-4)'" ", or " "'Fast\ Read'" "."
-.sp
-The default is to use the read mode that is currently configured.
-.TP
-.B Intel chipsets
-.sp
-If you have an Intel chipset with an ICH8 or later southbridge with SPI flash
-attached, and if a valid descriptor was written to it (e.g.\& by the vendor), the
-chipset provides an alternative way to access the flash chip(s) named
-.BR "Hardware Sequencing" .
-It is much simpler than the normal access method (called
-.BR "Software Sequencing" "),"
-but does not allow the software to choose the SPI commands to be sent.
-You can use the
-.sp
-.B " flashrom \-p internal:ich_spi_mode=value"
-.sp
-syntax where
-.BR "value " "can be"
-.BR auto ", " swseq " or " hwseq .
-By default
-.RB "(or when setting " ich_spi_mode=auto )
-the module tries to use swseq and only activates hwseq if need be (e.g.\& if
-important opcodes are inaccessible due to lockdown; or if more than one flash
-chip is attached). The other options (swseq, hwseq) select the respective mode
-(if possible).
-.sp
-ICH8 and later southbridges may also have locked address ranges of different
-kinds if a valid descriptor was written to it. The flash address space is then
-partitioned in multiple so called "Flash Regions" containing the host firmware,
-the ME firmware and so on respectively. The flash descriptor can also specify up
-to 5 so called "Protected Regions", which are freely chosen address ranges
-independent from the aforementioned "Flash Regions". All of them can be write
-and/or read protected individually.
-.sp
-If you have an Intel chipset with an ICH2 or later southbridge and if you want
-to set specific IDSEL values for a non-default flash chip or an embedded
-controller (EC), you can use the
-.sp
-.B " flashrom \-p internal:fwh_idsel=value"
-.sp
-syntax where
-.B value
-is the 48-bit hexadecimal raw value to be written in the
-IDSEL registers of the Intel southbridge. The upper 32 bits use one hex digit
-each per 512 kB range between 0xffc00000 and 0xffffffff, and the lower 16 bits
-use one hex digit each per 1024 kB range between 0xff400000 and 0xff7fffff.
-The rightmost hex digit corresponds with the lowest address range. All address
-ranges have a corresponding sister range 4 MB below with identical IDSEL
-settings. The default value for ICH7 is given in the example below.
-.sp
-Example:
-.B "flashrom \-p internal:fwh_idsel=0x001122334567"
-.TP
-.B Laptops
-.sp
-Using flashrom on older laptops that don't boot from the SPI bus is
-dangerous and may easily make your hardware unusable (see also the
-.B BUGS
-section). The embedded controller (EC) in some
-machines may interact badly with flashing.
-More information is
-.URLB https://flashrom.org/Laptops "in the wiki" .
-Problems occur when the flash chip is shared between BIOS
-and EC firmware, and the latter does not expect flashrom
-to access the chip. While flashrom tries to change the contents of
-that memory the EC might need to fetch new instructions or data from it and
-could stop working correctly. Probing for and reading from the chip may also
-irritate your EC and cause fan failure, backlight failure, sudden poweroff, and
-other nasty effects. flashrom will attempt to detect if it is running on such a
-laptop and limit probing to SPI buses. If you want to probe the LPC bus
-anyway at your own risk, use
-.sp
-.B " flashrom \-p internal:laptop=force_I_want_a_brick"
-.sp
-We will not help you if you force flashing on a laptop because this is a really
-dumb idea.
-.sp
-You have been warned.
-.sp
-Currently we rely on the chassis type encoded in the DMI/SMBIOS data to detect
-laptops. Some vendors did not implement those bits correctly or set them to
-generic and/or dummy values. flashrom will then issue a warning and restrict
-buses like above. In this case you can use
-.sp
-.B " flashrom \-p internal:laptop=this_is_not_a_laptop"
-.sp
-to tell flashrom (at your own risk) that it is not running on a laptop.
-.SS
-.BR "dummy " programmer
-.IP
-The dummy programmer operates on a buffer in memory only. It provides a safe and fast way to test various
-aspects of flashrom and is mainly used in development and while debugging.
-It is able to emulate some chips to a certain degree (basic
-identify/read/erase/write operations work).
-.sp
-An optional parameter specifies the bus types it
-should support. For that you have to use the
-.sp
-.B " flashrom \-p dummy:bus=[type[+type[+type]]]"
-.sp
-syntax where
-.B type
-can be
-.BR parallel ", " lpc ", " fwh ", " spi
-in any order. If you specify bus without type, all buses will be disabled.
-If you do not specify bus, all buses will be enabled.
-.sp
-Example:
-.B "flashrom \-p dummy:bus=lpc+fwh"
-.sp
-The dummy programmer supports flash chip emulation for automated self-tests
-without hardware access. If you want to emulate a flash chip, use the
-.sp
-.B " flashrom \-p dummy:emulate=chip"
-.sp
-syntax where
-.B chip
-is one of the following chips (please specify only the chip name, not the
-vendor):
-.sp
-.RB "* ST " M25P10.RES " SPI flash chip (128 kB, RES, page write)"
-.sp
-.RB "* SST " SST25VF040.REMS " SPI flash chip (512 kB, REMS, byte write)"
-.sp
-.RB "* SST " SST25VF032B " SPI flash chip (4096 kB, RDID, AAI write)"
-.sp
-.RB "* Macronix " MX25L6436 " SPI flash chip (8192 kB, RDID, SFDP)"
-.sp
-.RB "* Dummy vendor " VARIABLE_SIZE " SPI flash chip (configurable size, page write)"
-.sp
-Example:
-.B "flashrom -p dummy:emulate=SST25VF040.REMS"
-.sp
-To use
-.B VARIABLE_SIZE
-chip,
-.B size
-must be specified to configure the size of the flash chip as a power of two.
-.sp
-Example:
-.B "flashrom -p dummy:emulate=VARIABLE_SIZE,size=16777216,image=dummy.bin"
-.TP
-.B Persistent images
-.sp
-If you use flash chip emulation, flash image persistence is available as well
-by using the
-.sp
-.B " flashrom \-p dummy:emulate=chip,image=image.rom"
-.sp
-syntax where
-.B image.rom
-is the file where the simulated chip contents are read on flashrom startup and
-where the chip contents on flashrom shutdown are written to.
-.sp
-Example:
-.B "flashrom -p dummy:emulate=M25P10.RES,image=dummy.bin"
-.TP
-.B SPI write chunk size
-.sp
-If you use SPI flash chip emulation for a chip which supports SPI page write
-with the default opcode, you can set the maximum allowed write chunk size with
-the
-.sp
-.B " flashrom \-p dummy:emulate=chip,spi_write_256_chunksize=size"
-.sp
-syntax where
-.B size
-is the number of bytes (min.\& 1, max.\& 256).
-.sp
-Example:
-.sp
-.B " flashrom -p dummy:emulate=M25P10.RES,spi_write_256_chunksize=5"
-.TP
-.B SPI blacklist
-.sp
-To simulate a programmer which refuses to send certain SPI commands to the
-flash chip, you can specify a blacklist of SPI commands with the
-.sp
-.B " flashrom -p dummy:spi_blacklist=commandlist"
-.sp
-syntax where
-.B commandlist
-is a list of two-digit hexadecimal representations of
-SPI commands. If commandlist is e.g.\& 0302, flashrom will behave as if the SPI
-controller refuses to run command 0x03 (READ) and command 0x02 (WRITE).
-commandlist may be up to 512 characters (256 commands) long.
-Implementation note: flashrom will detect an error during command execution.
-.sp
-.TP
-.B SPI ignorelist
-.sp
-To simulate a flash chip which ignores (doesn't support) certain SPI commands,
-you can specify an ignorelist of SPI commands with the
-.sp
-.B " flashrom -p dummy:spi_ignorelist=commandlist"
-.sp
-syntax where
-.B commandlist
-is a list of two-digit hexadecimal representations of
-SPI commands. If commandlist is e.g.\& 0302, the emulated flash chip will ignore
-command 0x03 (READ) and command 0x02 (WRITE). commandlist may be up to 512
-characters (256 commands) long.
-Implementation note: flashrom won't detect an error during command execution.
-.sp
-.TP
-.B SPI status register
-.sp
-You can specify the initial content of the chip's status register with the
-.sp
-.B " flashrom -p dummy:spi_status=content"
-.sp
-syntax where
-.B content
-is an 8-bit hexadecimal value.
-.SS
-.BR "nic3com" , " nicrealtek" , " nicnatsemi" , " nicintel", " nicintel_eeprom"\
-, " nicintel_spi" , " gfxnvidia" , " ogp_spi" , " drkaiser" , " satasii"\
-, " satamv" , " atahpt", " atavia ", " atapromise " and " it8212 " programmers
-.IP
-These programmers have an option to specify the PCI address of the card
-your want to use, which must be specified if more than one card supported
-by the selected programmer is installed in your system. The syntax is
-.sp
-.BR " flashrom \-p xxxx:pci=bb:dd.f" ,
-.sp
-where
-.B xxxx
-is the name of the programmer,
-.B bb
-is the PCI bus number,
-.B dd
-is the PCI device number, and
-.B f
-is the PCI function number of the desired device.
-.sp
-Example:
-.B "flashrom \-p nic3com:pci=05:04.0"
-.SS
-.BR "atavia " programmer
-.IP
-Due to the mysterious address handling of the VIA VT6421A controller the user can specify an offset with the
-.sp
-.B " flashrom \-p atavia:offset=addr"
-.sp
-syntax where
-.B addr
-will be interpreted as usual (leading 0x (0) for hexadecimal (octal) values, or else decimal).
-For more information please see
-.URLB https://flashrom.org/VT6421A "its wiki page" .
-.SS
-.BR "atapromise " programmer
-.IP
-This programmer is currently limited to 32 kB, regardless of the actual size of the flash chip. This stems
-from the fact that, on the tested device (a Promise Ultra100), not all of the chip's address lines were
-actually connected. You may use this programmer to flash firmware updates, since these are only 16 kB in
-size (padding to 32 kB is required).
-.SS
-.BR "nicintel_eeprom " programmer
-.IP
-This is the first programmer module in flashrom that does not provide access to NOR flash chips but EEPROMs
-mounted on gigabit Ethernet cards based on Intel's 82580 NIC. Because EEPROMs normally do not announce their
-size nor allow themselves to be identified, the controller relies on correct size values written to predefined
-addresses within the chip. Flashrom follows this scheme but assumes the minimum size of 16 kB (128 kb) if an
-unprogrammed EEPROM/card is detected. Intel specifies following EEPROMs to be compatible:
-Atmel AT25128, AT25256, Micron (ST) M95128, M95256 and OnSemi (Catalyst) CAT25CS128.
-.SS
-.BR "ft2232_spi " programmer
-.IP
-This module supports various programmers based on FTDI FT2232/FT4232H/FT232H chips including the DLP Design
-DLP-USB1232H, openbiosprog-spi, Amontec JTAGkey/JTAGkey-tiny/JTAGkey-2, Dangerous Prototypes Bus Blaster,
-Olimex ARM-USB-TINY/-H, Olimex ARM-USB-OCD/-H, OpenMoko Neo1973 Debug board (V2+), TIAO/DIYGADGET USB
-Multi-Protocol Adapter (TUMPA), TUMPA Lite, GOEPEL PicoTAP, Google Servo v1/v2 and Tin Can Tools
-Flyswatter/Flyswatter 2.
-.sp
-An optional parameter specifies the controller
-type, channel/interface/port and GPIO-based chip select it should support. For that you have to use the
-.sp
-.B " flashrom \-p ft2232_spi:type=model,port=interface,csgpiol=gpio"
-.sp
-syntax where
-.B model
-can be
-.BR 2232H ", " 4232H ", " 232H ", " jtagkey ", " busblaster ", " openmoko ", " \
-arm-usb-tiny ", " arm-usb-tiny-h ", " arm-usb-ocd ", " arm-usb-ocd-h \
-", " tumpa ", " tumpalite ", " picotap ", " google-servo ", " google-servo-v2 \
-" or " google-servo-v2-legacy
-.B interface
-can be
-.BR A ", " B ", " C ", or " D
-and
-.B csgpiol
-can be a number between 0 and 3, denoting GPIOL0-GPIOL3 correspondingly.
-The default model is
-.B 4232H
-the default interface is
-.BR A
-and GPIO is not used by default.
-.sp
-If there is more than one ft2232_spi-compatible device connected, you can select which one should be used by
-specifying its serial number with the
-.sp
-.B " flashrom \-p ft2232_spi:serial=number"
-.sp
-syntax where
-.B number
-is the serial number of the device (which can be found for example in the output of lsusb -v).
-.sp
-All models supported by the ft2232_spi driver can configure the SPI clock rate by setting a divisor. The
-expressible divisors are all
-.B even
-numbers between 2 and 2^17 (=131072) resulting in SPI clock frequencies of
-6 MHz down to about 92 Hz for 12 MHz inputs. The default divisor is set to 2, but you can use another one by
-specifying the optional
-.B divisor
-parameter with the
-.sp
-.B " flashrom \-p ft2232_spi:divisor=div"
-.sp
-syntax.
-.SS
-.BR "serprog " programmer
-.IP
-This module supports all programmers speaking the serprog protocol. This includes some Arduino-based devices
-as well as various programmers by Urja Rannikko, Juhana Helovuo, Stefan Tauner, Chi Zhang and many others.
-.sp
-A mandatory parameter specifies either a serial device (and baud rate) or an IP/port combination for
-communicating with the programmer.
-The device/baud combination has to start with
-.B dev=
-and separate the optional baud rate with a colon.
-For example
-.sp
-.B " flashrom \-p serprog:dev=/dev/ttyS0:115200"
-.sp
-If no baud rate is given the default values by the operating system/hardware will be used.
-For IP connections you have to use the
-.sp
-.B " flashrom \-p serprog:ip=ipaddr:port"
-.sp
-syntax.
-In case the device supports it, you can set the SPI clock frequency with the optional
-.B spispeed
-parameter. The frequency is parsed as hertz, unless an
-.BR M ", or " k
-suffix is given, then megahertz or kilohertz are used respectively.
-Example that sets the frequency to 2 MHz:
-.sp
-.B " flashrom \-p serprog:dev=/dev/device:baud,spispeed=2M"
-.sp
-More information about serprog is available in
-.B serprog-protocol.txt
-in the source distribution.
-.SS
-.BR "buspirate_spi " programmer
-.IP
-A required
-.B dev
-parameter specifies the Bus Pirate device node and an optional
-.B spispeed
-parameter specifies the frequency of the SPI bus. The parameter
-delimiter is a comma. Syntax is
-.sp
-.B " flashrom \-p buspirate_spi:dev=/dev/device,spispeed=frequency"
-.sp
-where
-.B frequency
-can be
-.BR 30k ", " 125k ", " 250k ", " 1M ", " 2M ", " 2.6M ", " 4M " or " 8M
-(in Hz). The default is the maximum frequency of 8 MHz.
-.sp
-The baud rate for communication between the host and the Bus Pirate can be specified with the optional
-.B serialspeed
-parameter. Syntax is
-.sp
-.B " flashrom -p buspirate_spi:serialspeed=baud
-.sp
-where
-.B baud
-can be
-.BR 115200 ", " 230400 ", " 250000 " or " 2000000 " (" 2M ")."
-The default is 2M baud for Bus Pirate hardware version 3.0 and greater, and 115200 otherwise.
-.sp
-An optional pullups parameter specifies the use of the Bus Pirate internal pull-up resistors. This may be
-needed if you are working with a flash ROM chip that you have physically removed from the board. Syntax is
-.sp
-.B " flashrom -p buspirate_spi:pullups=state"
-.sp
-where
-.B state
-can be
-.BR on " or " off .
-More information about the Bus Pirate pull-up resistors and their purpose is available
-.URLB "http://dangerousprototypes.com/docs/Practical_guide_to_Bus_Pirate_pull-up_resistors" \
-"in a guide by dangerousprototypes" .
-Only the external supply voltage (Vpu) is supported as of this writing.
-.SS
-.BR "pickit2_spi " programmer
-.IP
-An optional
-.B voltage
-parameter specifies the voltage the PICkit2 should use. The default unit is Volt if no unit is specified.
-You can use
-.BR mV ", " millivolt ", " V " or " Volt
-as unit specifier. Syntax is
-.sp
-.B " flashrom \-p pickit2_spi:voltage=value"
-.sp
-where
-.B value
-can be
-.BR 0V ", " 1.8V ", " 2.5V ", " 3.5V
-or the equivalent in mV.
-.sp
-An optional
-.B spispeed
-parameter specifies the frequency of the SPI bus. Syntax is
-.sp
-.B " flashrom \-p pickit2_spi:spispeed=frequency"
-.sp
-where
-.B frequency
-can be
-.BR 250k ", " 333k ", " 500k " or " 1M "
-(in Hz). The default is a frequency of 1 MHz.
-.SS
-.BR "dediprog " programmer
-.IP
-An optional
-.B voltage
-parameter specifies the voltage the Dediprog should use. The default unit is
-Volt if no unit is specified. You can use
-.BR mV ", " milliVolt ", " V " or " Volt
-as unit specifier. Syntax is
-.sp
-.B " flashrom \-p dediprog:voltage=value"
-.sp
-where
-.B value
-can be
-.BR 0V ", " 1.8V ", " 2.5V ", " 3.5V
-or the equivalent in mV.
-.sp
-An optional
-.B device
-parameter specifies which of multiple connected Dediprog devices should be used.
-Please be aware that the order depends on libusb's usb_get_busses() function and that the numbering starts
-at 0.
-Usage example to select the second device:
-.sp
-.B " flashrom \-p dediprog:device=1"
-.sp
-An optional
-.B spispeed
-parameter specifies the frequency of the SPI bus. The firmware on the device needs to be 5.0.0 or newer.
-Syntax is
-.sp
-.B " flashrom \-p dediprog:spispeed=frequency"
-.sp
-where
-.B frequency
-can be
-.BR 375k ", " 750k ", " 1.5M ", " 2.18M ", " 3M ", " 8M ", " 12M " or " 24M
-(in Hz). The default is a frequency of 12 MHz.
-.sp
-An optional
-.B target
-parameter specifies which target chip should be used. Syntax is
-.sp
-.B " flashrom \-p dediprog:target=value"
-.sp
-where
-.B value
-can be
-.BR 1 " or " 2
-to select target chip 1 or 2 respectively. The default is target chip 1.
-.SS
-.BR "rayer_spi " programmer
-.IP
-The default I/O base address used for the parallel port is 0x378 and you can use
-the optional
-.B iobase
-parameter to specify an alternate base I/O address with the
-.sp
-.B " flashrom \-p rayer_spi:iobase=baseaddr"
-.sp
-syntax where
-.B baseaddr
-is base I/O port address of the parallel port, which must be a multiple of
-four. Make sure to not forget the "0x" prefix for hexadecimal port addresses.
-.sp
-The default cable type is the RayeR cable. You can use the optional
-.B type
-parameter to specify the cable type with the
-.sp
-.B " flashrom \-p rayer_spi:type=model"
-.sp
-syntax where
-.B model
-can be
-.BR rayer " for the RayeR cable, " byteblastermv " for the Altera ByteBlasterMV, " stk200 " for the Atmel \
-STK200/300, " wiggler " for the Macraigor Wiggler, " xilinx " for the Xilinx Parallel Cable III (DLC 5), or" \
-" spi_tt" " for SPI Tiny Tools-compatible hardware.
-.sp
-More information about the RayeR hardware is available at
-.nh
-.URLB "http://rayer.g6.cz/elektro/spipgm.htm" "RayeR's website" .
-The Altera ByteBlasterMV datasheet can be obtained from
-.URLB "http://www.altera.co.jp/literature/ds/dsbytemv.pdf" Altera .
-For more information about the Macraigor Wiggler see
-.URLB "http://www.macraigor.com/wiggler.htm" "their company homepage" .
-The schematic of the Xilinx DLC 5 was published in
-.URLB "http://www.xilinx.com/support/documentation/user_guides/xtp029.pdf" "a Xilinx user guide" .
-.SS
-.BR "pony_spi " programmer
-.IP
-The serial port (like /dev/ttyS0, /dev/ttyUSB0 on Linux or COM3 on windows) is
-specified using the mandatory
-.B dev
-parameter. The adapter type is selectable between SI-Prog (used for
-SPI devices with PonyProg 2000) or a custom made serial bitbanging programmer
-named "serbang". The optional
-.B type
-parameter accepts the values "si_prog" (default) or "serbang".
-.sp
-Information about the SI-Prog adapter can be found at
-.URLB "http://www.lancos.com/siprogsch.html" "its website" .
-.sp
-An example call to flashrom is
-.sp
-.B " flashrom \-p pony_spi:dev=/dev/ttyS0,type=serbang"
-.sp
-Please note that while USB-to-serial adapters work under certain circumstances,
-this slows down operation considerably.
-.SS
-.BR "ogp_spi " programmer
-.IP
-The flash ROM chip to access must be specified with the
-.B rom
-parameter.
-.sp
-.B " flashrom \-p ogp_spi:rom=name"
-.sp
-Where
-.B name
-is either
-.B cprom
-or
-.B s3
-for the configuration ROM and
-.B bprom
-or
-.B bios
-for the BIOS ROM. If more than one card supported by the ogp_spi programmer
-is installed in your system, you have to specify the PCI address of the card
-you want to use with the
-.B pci=
-parameter as explained in the
-.B nic3com et al.\&
-section above.
-.SS
-.BR "linux_mtd " programmer
-.IP
-You may specify the MTD device to use with the
-.sp
-.B " flashrom \-p linux_mtd:dev=/dev/mtdX"
-.sp
-syntax where
-.B /dev/mtdX
-is the Linux device node for your MTD device. If left unspecified the first MTD
-device found (e.g. /dev/mtd0) will be used by default.
-.sp
-Please note that the linux_mtd driver only works on Linux.
-.SS
-.BR "linux_spi " programmer
-.IP
-You have to specify the SPI controller to use with the
-.sp
-.B " flashrom \-p linux_spi:dev=/dev/spidevX.Y"
-.sp
-syntax where
-.B /dev/spidevX.Y
-is the Linux device node for your SPI controller.
-.sp
-In case the device supports it, you can set the SPI clock frequency with the optional
-.B spispeed
-parameter. The frequency is parsed as kilohertz.
-Example that sets the frequency to 8 MHz:
-.sp
-.B " flashrom \-p linux_spi:dev=/dev/spidevX.Y,spispeed=8000"
-.sp
-Please note that the linux_spi driver only works on Linux.
-.SS
-.BR "mstarddc_spi " programmer
-.IP
-The Display Data Channel (DDC) is an I2C bus present on VGA and DVI connectors, that allows exchanging
-information between a computer and attached displays. Its most common uses are getting display capabilities
-through EDID (at I2C address 0x50) and sending commands to the display using the DDC/CI protocol (at address
-0x37). On displays driven by MSTAR SoCs, it is also possible to access the SoC firmware flash (connected to
-the Soc through another SPI bus) using an In-System Programming (ISP) port, usually at address 0x49.
-This flashrom module allows the latter via Linux's I2C driver.
-.sp
-.B IMPORTANT:
-Before using this programmer, the display
-.B MUST
-be in standby mode, and only connected to the computer that will run flashrom using a VGA cable, to an
-inactive VGA output. It absolutely
-.B MUST NOT
-be used as a display during the procedure!
-.sp
-You have to specify the DDC/I2C controller and I2C address to use with the
-.sp
-.B " flashrom \-p mstarddc_spi:dev=/dev/i2c-X:YY"
-.sp
-syntax where
-.B /dev/i2c-X
-is the Linux device node for your I2C controller connected to the display's DDC channel, and
-.B YY
-is the (hexadecimal) address of the MSTAR ISP port (address 0x49 is usually used).
-Example that uses I2C controller /dev/i2c-1 and address 0x49:
-.sp
-.B " flashrom \-p mstarddc_spi:dev=/dev/i2c-1:49
-.sp
-It is also possible to inhibit the reset command that is normally sent to the display once the flashrom
-operation is completed using the optional
-.B noreset
-parameter. A value of 1 prevents flashrom from sending the reset command.
-Example that does not reset the display at the end of the operation:
-.sp
-.B " flashrom \-p mstarddc_spi:dev=/dev/i2c-1:49,noreset=1
-.sp
-Please note that sending the reset command is also inhibited if an error occurred during the operation.
-To send the reset command afterwards, you can simply run flashrom once more, in chip probe mode (not specifying
-an operation), without the
-.B noreset
-parameter, once the flash read/write operation you intended to perform has completed successfully.
-.sp
-Please also note that the mstarddc_spi driver only works on Linux.
-.SS
-.BR "ch341a_spi " programmer
-The WCH CH341A programmer does not support any parameters currently. SPI frequency is fixed at 2 MHz, and CS0 is
-used as per the device.
-.SS
-.BR "ni845x_spi " programmer
-.IP
-An optional
-.B voltage
-parameter could be used to specify the IO voltage. This parameter is available for the NI USB-8452 device.
-The default unit is Volt if no unit is specified. You can use
-.BR mV ", " milliVolt ", " V " or " Volt
-as unit specifier.
-Syntax is
-.sp
-.B " flashrom \-p ni845x_spi:voltage=value"
-.sp
-where
-.B value
-can be
-.BR 1.2V ", " 1.5V ", " 1.8V ", " 2.5V ", " 3.3V
-or the equivalent in mV.
-.sp
-In the case if none of the programmer's supported IO voltage is within the supported voltage range of
-the detected flash chip the flashrom will abort the operation (to prevent damaging the flash chip).
-You can override this behaviour by passing "yes" to the
-.B ignore_io_voltage_limits
-parameter (for e.g. if you are using an external voltage translator circuit).
-Syntax is
-.sp
-.B " flashrom \-p ni845x_spi:ignore_io_voltage_limits=yes"
-.sp
-You can use the
-.B serial
-parameter to explicitly specify which connected NI USB-845x device should be used.
-You should use your device's 7 digit hexadecimal serial number.
-Usage example to select the device with 1230A12 serial number:
-.sp
-.B " flashrom \-p ni845x_spi:serial=1230A12"
-.sp
-An optional
-.B spispeed
-parameter specifies the frequency of the SPI bus.
-Syntax is
-.sp
-.B " flashrom \-p ni845x_spi:spispeed=frequency"
-.sp
-where
-.B frequency
-should a number corresponding to the desired frequency in kHz.
-The maximum
-.B frequency
-is 12 MHz (12000 kHz) for the USB-8451 and 50 MHz (50000 kHz) for the USB-8452.
-The default is a frequency of 1 MHz (1000 kHz).
-.sp
-An optional
-.B cs
-parameter specifies which target chip select line should be used. Syntax is
-.sp
-.B " flashrom \-p ni845x_spi:csnumber=value"
-.sp
-where
-.B value
-should be between
-.BR 0 " and " 7
-By default the CS0 is used.
-.SS
-.BR "digilent_spi " programmer
-.IP
-An optional
-.B spispeed
-parameter specifies the frequency of the SPI bus.
-Syntax is
-.sp
-.B " flashrom \-p digilent_spi:spispeed=frequency"
-.sp
-where
-.B frequency
-can be
-.BR 62.5k ", " 125k ", " 250k ", " 500k ", " 1M ", " 2M " or " 4M
-(in Hz). The default is a frequency of 4 MHz.
-.sp
-.SS
-.BR "jlink_spi " programmer
-.IP
-This module supports SEGGER J-Link and compatible devices.
-
-The \fBMOSI\fP signal of the flash chip must be attached to \fBTDI\fP pin of
-the programmer, \fBMISO\fP to \fBTDO\fP and \fBSCK\fP to \fBTCK\fP.
-The chip select (\fBCS\fP) signal of the flash chip can be attached to
-different pins of the programmer which can be selected with the
-.sp
-.B " flashrom \-p jlink_spi:cs=pin"
-.sp
-syntax where \fBpin\fP can be either \fBTRST\fP or \fBRESET\fP.
-The default pin for chip select is \fBRESET\fP.
-Note that, when using \fBRESET\fP, it is normal that the indicator LED blinks
-orange or red.
-.br
-Additionally, the \fBVTref\fP pin of the programmer must be attached to the
-logic level of the flash chip.
-The programmer measures the voltage on this pin and generates the reference
-voltage for its input comparators and adapts its output voltages to it.
-.sp
-Pinout for devices with 20-pin JTAG connector:
-.sp
- +-------+
- | 1 2 | 1: VTref 2:
- | 3 4 | 3: TRST 4: GND
- | 5 6 | 5: TDI 6: GND
- +-+ 7 8 | 7: 8: GND
- | 9 10 | 9: TCK 10: GND
- | 11 12 | 11: 12: GND
- +-+ 13 14 | 13: TDO 14:
- | 15 16 | 15: RESET 16:
- | 17 18 | 17: 18:
- | 19 20 | 19: PWR_5V 20:
- +-------+
-.sp
-If there is more than one compatible device connected, you can select which one
-should be used by specifying its serial number with the
-.sp
-.B " flashrom \-p jlink_spi:serial=number"
-.sp
-syntax where
-.B number
-is the serial number of the device (which can be found for example in the
-output of lsusb -v).
-.sp
-The SPI speed can be selected by using the
-.sp
-.B " flashrom \-p jlink_spi:spispeed=frequency"
-.sp
-syntax where \fBfrequency\fP is the SPI clock frequency in kHz.
-The maximum speed depends on the device in use.
-.SS
-.BR "stlinkv3_spi " programmer
-.IP
-This module supports SPI flash programming through the STMicroelectronics
-STLINK V3 programmer/debugger's SPI bridge interface
-.sp
-.B " flashrom \-p stlinkv3_spi"
-.sp
-If there is more than one compatible device connected, you can select which one
-should be used by specifying its serial number with the
-.sp
-.B " flashrom \-p stlinkv3_spi:serial=number"
-.sp
-syntax where
-.B number
-is the serial number of the device (which can be found for example in the
-output of lsusb -v).
-.sp
-The SPI speed can be selected by using the
-.sp
-.B " flashrom \-p stlinkv3_spi:spispeed=frequency"
-.sp
-syntax where \fBfrequency\fP is the SPI clock frequency in kHz.
-If the passed frequency is not supported by the adapter the nearest lower
-supported frequency will be used.
-.SS
-
-.SH EXAMPLES
-To back up and update your BIOS, run
-.sp
-.B flashrom -p internal -r backup.rom -o backuplog.txt
-.br
-.B flashrom -p internal -w newbios.rom -o writelog.txt
-.sp
-Please make sure to copy backup.rom to some external media before you try
-to write. That makes offline recovery easier.
-.br
-If writing fails and flashrom complains about the chip being in an unknown
-state, you can try to restore the backup by running
-.sp
-.B flashrom -p internal -w backup.rom -o restorelog.txt
-.sp
-If you encounter any problems, please contact us and supply
-backuplog.txt, writelog.txt and restorelog.txt. See section
-.B BUGS
-for contact info.
-.SH EXIT STATUS
-flashrom exits with 0 on success, 1 on most failures but with 3 if a call to mmap() fails.
-.SH REQUIREMENTS
-flashrom needs different access permissions for different programmers.
-.sp
-.B internal
-needs raw memory access, PCI configuration space access, raw I/O port
-access (x86) and MSR access (x86).
-.sp
-.B atavia
-needs PCI configuration space access.
-.sp
-.BR nic3com ", " nicrealtek " and " nicnatsemi "
-need PCI configuration space read access and raw I/O port access.
-.sp
-.B atahpt
-needs PCI configuration space access and raw I/O port access.
-.sp
-.BR gfxnvidia ", " drkaiser " and " it8212
-need PCI configuration space access and raw memory access.
-.sp
-.B rayer_spi
-needs raw I/O port access.
-.sp
-.BR satasii ", " nicintel ", " nicintel_eeprom " and " nicintel_spi
-need PCI configuration space read access and raw memory access.
-.sp
-.BR satamv " and " atapromise
-need PCI configuration space read access, raw I/O port access and raw memory
-access.
-.sp
-.B serprog
-needs TCP access to the network or userspace access to a serial port.
-.sp
-.B buspirate_spi
-needs userspace access to a serial port.
-.sp
-.BR ft2232_spi ", " usbblaster_spi " and " pickit2_spi
-need access to the respective USB device via libusb API version 0.1.
-.sp
-.BR ch341a_spi " and " dediprog
-need access to the respective USB device via libusb API version 1.0.
-.sp
-.B dummy
-needs no access permissions at all.
-.sp
-.BR internal ", " nic3com ", " nicrealtek ", " nicnatsemi ", "
-.BR gfxnvidia ", " drkaiser ", " satasii ", " satamv ", " atahpt ", " atavia " and " atapromise
-have to be run as superuser/root, and need additional raw access permission.
-.sp
-.BR serprog ", " buspirate_spi ", " dediprog ", " usbblaster_spi ", " ft2232_spi ", " pickit2_spi ", " \
-ch341a_spi " and " digilent_spi
-can be run as normal user on most operating systems if appropriate device
-permissions are set.
-.sp
-.B ogp
-needs PCI configuration space read access and raw memory access.
-.sp
-On OpenBSD, you can obtain raw access permission by setting
-.B "securelevel=-1"
-in
-.B "/etc/rc.securelevel"
-and rebooting, or rebooting into single user mode.
-.SH BUGS
-Please report any bugs to the
-.MTOB "flashrom@flashrom.org" "flashrom mailing list" .
-.sp
-We recommend to subscribe first at
-.URLB "https://flashrom.org/mailman/listinfo/flashrom" "" .
-.sp
-Many of the developers communicate via the
-.B "#flashrom"
-IRC channel on
-.BR chat.freenode.net .
-If you don't have an IRC client, you can use the
-.URLB http://webchat.freenode.net/?channels=flashrom "freenode webchat" .
-You are welcome to join and ask questions, send us bug and success reports there
-too. Please provide a way to contact you later (e.g.\& a mail address) and be
-patient if there is no immediate reaction. Also, we provide a
-.URLB https://paste.flashrom.org "pastebin service"
-that is very useful when you want to share logs etc.\& without spamming the
-channel.
-.SS
-.B Laptops
-.sp
-Using flashrom on older laptops is dangerous and may easily make your hardware
-unusable. flashrom will attempt to detect if it is running on a susceptible
-laptop and restrict flash-chip probing for safety reasons. Please see the
-detailed discussion of this topic and associated flashrom options in the
-.B Laptops
-paragraph in the
-.B internal programmer
-subsection of the
-.B PROGRAMMER-SPECIFIC INFORMATION
-section and the information
-.URLB "https://flashrom.org/Laptops" "in our wiki" .
-.SS
-One-time programmable (OTP) memory and unique IDs
-.sp
-Some flash chips contain OTP memory often denoted as "security registers".
-They usually have a capacity in the range of some bytes to a few hundred
-bytes and can be used to give devices unique IDs etc. flashrom is not able
-to read or write these memories and may therefore not be able to duplicate a
-chip completely. For chip types known to include OTP memories a warning is
-printed when they are detected.
-.sp
-Similar to OTP memories are unique, factory programmed, unforgeable IDs.
-They are not modifiable by the user at all.
-.SH LICENSE
-.B flashrom
-is covered by the GNU General Public License (GPL), version 2. Some files are
-additionally available under any later version of the GPL.
-.SH COPYRIGHT
-.br
-Please see the individual files.
-.SH AUTHORS
-Andrew Morgan
-.br
-Carl-Daniel Hailfinger
-.br
-Claus Gindhart
-.br
-David Borg
-.br
-David Hendricks
-.br
-Dominik Geyer
-.br
-Edward O'Callaghan
-.br
-Eric Biederman
-.br
-Giampiero Giancipoli
-.br
-Helge Wagner
-.br
-Idwer Vollering
-.br
-Joe Bao
-.br
-Joerg Fischer
-.br
-Joshua Roys
-.br
-Ky\[:o]sti M\[:a]lkki
-.br
-Luc Verhaegen
-.br
-Li-Ta Lo
-.br
-Mark Marshall
-.br
-Markus Boas
-.br
-Mattias Mattsson
-.br
-Michael Karcher
-.br
-Nikolay Petukhov
-.br
-Patrick Georgi
-.br
-Peter Lemenkov
-.br
-Peter Stuge
-.br
-Reinder E.N. de Haan
-.br
-Ronald G. Minnich
-.br
-Ronald Hoogenboom
-.br
-Sean Nelson
-.br
-Stefan Reinauer
-.br
-Stefan Tauner
-.br
-Stefan Wildemann
-.br
-Stephan Guilloux
-.br
-Steven James
-.br
-Urja Rannikko
-.br
-Uwe Hermann
-.br
-Wang Qingpei
-.br
-Yinghai Lu
-.br
-some others, please see the flashrom svn changelog for details.
-.br
-All still active authors can be reached via
-.MTOB "flashrom@flashrom.org" "the mailing list" .
-.PP
-This manual page was written by
-.MTOB "uwe@hermann-uwe.de" "Uwe Hermann" ,
-Carl-Daniel Hailfinger, Stefan Tauner and others.
-It is licensed under the terms of the GNU GPL (version 2 or later).
diff --git a/flashrom.c b/flashrom.c
index c89abad60..630c69db8 100644
--- a/flashrom.c
+++ b/flashrom.c
@@ -19,32 +19,28 @@
* GNU General Public License for more details.
*/
+#include <stdbool.h>
#include <stdio.h>
+#include <stdint.h>
#include <sys/types.h>
-#ifndef __LIBPAYLOAD__
-#include <fcntl.h>
-#include <sys/stat.h>
-#endif
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
-#include <getopt.h>
-#if HAVE_UTSNAME == 1
-#include <sys/utsname.h>
-#endif
+
#include "flash.h"
#include "flashchips.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
#include "chipdrivers.h"
+#include "erasure_layout.h"
+
+static bool use_legacy_erase_path = false;
const char flashrom_version[] = FLASHROM_VERSION;
-const char *chip_to_probe = NULL;
-static enum programmer programmer = PROGRAMMER_INVALID;
-static const char *programmer_param = NULL;
+static const struct programmer_entry *programmer = NULL;
/*
* Programmers supporting multiple buses can have differing size limits on
@@ -53,488 +49,10 @@ static const char *programmer_param = NULL;
struct decode_sizes max_rom_decode;
/* If nonzero, used as the start address of bottom-aligned flash. */
-unsigned long flashbase;
+uintptr_t flashbase;
/* Is writing allowed with this programmer? */
-int programmer_may_write;
-
-const struct programmer_entry programmer_table[] = {
-#if CONFIG_INTERNAL == 1
- {
- .name = "internal",
- .type = OTHER,
- .devs.note = NULL,
- .init = internal_init,
- .map_flash_region = physmap,
- .unmap_flash_region = physunmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_DUMMY == 1
- {
- .name = "dummy",
- .type = OTHER,
- /* FIXME */
- .devs.note = "Dummy device, does nothing and logs all accesses\n",
- .init = dummy_init,
- .map_flash_region = dummy_map,
- .unmap_flash_region = dummy_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_MEC1308 == 1
- {
- .name = "mec1308",
- .type = OTHER,
- .devs.note = "Microchip MEC1308 Embedded Controller.\n",
- .init = mec1308_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_NIC3COM == 1
- {
- .name = "nic3com",
- .type = PCI,
- .devs.dev = nics_3com,
- .init = nic3com_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_NICREALTEK == 1
- {
- /* This programmer works for Realtek RTL8139 and SMC 1211. */
- .name = "nicrealtek",
- .type = PCI,
- .devs.dev = nics_realtek,
- .init = nicrealtek_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_NICNATSEMI == 1
- {
- .name = "nicnatsemi",
- .type = PCI,
- .devs.dev = nics_natsemi,
- .init = nicnatsemi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_GFXNVIDIA == 1
- {
- .name = "gfxnvidia",
- .type = PCI,
- .devs.dev = gfx_nvidia,
- .init = gfxnvidia_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_RAIDEN_DEBUG_SPI == 1
- {
- .name = "raiden_debug_spi",
- .type = USB,
- .devs.dev = devs_raiden,
- .init = raiden_debug_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_DRKAISER == 1
- {
- .name = "drkaiser",
- .type = PCI,
- .devs.dev = drkaiser_pcidev,
- .init = drkaiser_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_SATASII == 1
- {
- .name = "satasii",
- .type = PCI,
- .devs.dev = satas_sii,
- .init = satasii_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_ATAHPT == 1
- {
- .name = "atahpt",
- .type = PCI,
- .devs.dev = ata_hpt,
- .init = atahpt_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_ATAVIA == 1
- {
- .name = "atavia",
- .type = PCI,
- .devs.dev = ata_via,
- .init = atavia_init,
- .map_flash_region = atavia_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_ATAPROMISE == 1
- {
- .name = "atapromise",
- .type = PCI,
- .devs.dev = ata_promise,
- .init = atapromise_init,
- .map_flash_region = atapromise_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_IT8212 == 1
- {
- .name = "it8212",
- .type = PCI,
- .devs.dev = devs_it8212,
- .init = it8212_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_FT2232_SPI == 1
- {
- .name = "ft2232_spi",
- .type = USB,
- .devs.dev = devs_ft2232spi,
- .init = ft2232_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_SERPROG == 1
- {
- .name = "serprog",
- .type = OTHER,
- /* FIXME */
- .devs.note = "All programmer devices speaking the serprog protocol\n",
- .init = serprog_init,
- .map_flash_region = serprog_map,
- .unmap_flash_region = fallback_unmap,
- .delay = serprog_delay,
- },
-#endif
-
-#if CONFIG_BUSPIRATE_SPI == 1
- {
- .name = "buspirate_spi",
- .type = OTHER,
- /* FIXME */
- .devs.note = "Dangerous Prototypes Bus Pirate\n",
- .init = buspirate_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_DEDIPROG == 1
- {
- .name = "dediprog",
- .type = USB,
- .devs.dev = devs_dediprog,
- .init = dediprog_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_DEVELOPERBOX_SPI == 1
- {
- .name = "developerbox",
- .type = USB,
- .devs.dev = devs_developerbox_spi,
- .init = developerbox_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_ENE_LPC == 1
- {
- .name = "ene_lpc",
- .type = OTHER,
- .devs.note = "ENE LPC interface keyboard controller\n",
- .init = ene_lpc_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_RAYER_SPI == 1
- {
- .name = "rayer_spi",
- .type = OTHER,
- /* FIXME */
- .devs.note = "RayeR parallel port programmer\n",
- .init = rayer_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_PONY_SPI == 1
- {
- .name = "pony_spi",
- .type = OTHER,
- /* FIXME */
- .devs.note = "Programmers compatible with SI-Prog, serbang or AJAWe\n",
- .init = pony_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_NICINTEL == 1
- {
- .name = "nicintel",
- .type = PCI,
- .devs.dev = nics_intel,
- .init = nicintel_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_NICINTEL_SPI == 1
- {
- .name = "nicintel_spi",
- .type = PCI,
- .devs.dev = nics_intel_spi,
- .init = nicintel_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_NICINTEL_EEPROM == 1
- {
- .name = "nicintel_eeprom",
- .type = PCI,
- .devs.dev = nics_intel_ee,
- .init = nicintel_ee_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_OGP_SPI == 1
- {
- .name = "ogp_spi",
- .type = PCI,
- .devs.dev = ogp_spi,
- .init = ogp_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_SATAMV == 1
- {
- .name = "satamv",
- .type = PCI,
- .devs.dev = satas_mv,
- .init = satamv_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_LINUX_MTD == 1
- {
- .name = "linux_mtd",
- .type = OTHER,
- .devs.note = "Device files /dev/mtd*\n",
- .init = linux_mtd_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_LINUX_SPI == 1
- {
- .name = "linux_spi",
- .type = OTHER,
- .devs.note = "Device files /dev/spidev*.*\n",
- .init = linux_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_LSPCON_I2C_SPI == 1
- {
- .name = "lspcon_i2c_spi",
- .type = OTHER,
- .devs.note = "Device files /dev/i2c-*.\n",
- .init = lspcon_i2c_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_REALTEK_MST_I2C_SPI == 1
- {
- .name = "realtek_mst_i2c_spi",
- .type = OTHER,
- .devs.note = "Device files /dev/i2c-*.\n",
- .init = realtek_mst_i2c_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_USBBLASTER_SPI == 1
- {
- .name = "usbblaster_spi",
- .type = USB,
- .devs.dev = devs_usbblasterspi,
- .init = usbblaster_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_MSTARDDC_SPI == 1
- {
- .name = "mstarddc_spi",
- .type = OTHER,
- .devs.note = "MSTAR DDC devices addressable via /dev/i2c-* on Linux.\n",
- .init = mstarddc_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_PICKIT2_SPI == 1
- {
- .name = "pickit2_spi",
- .type = USB,
- .devs.dev = devs_pickit2_spi,
- .init = pickit2_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_CH341A_SPI == 1
- {
- .name = "ch341a_spi",
- .type = USB,
- .devs.dev = devs_ch341a_spi,
- .init = ch341a_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = ch341a_spi_delay,
- },
-#endif
-
-#if CONFIG_DIGILENT_SPI == 1
- {
- .name = "digilent_spi",
- .type = USB,
- .devs.dev = devs_digilent_spi,
- .init = digilent_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_JLINK_SPI == 1
- {
- .name = "jlink_spi",
- .type = OTHER,
- .init = jlink_spi_init,
- .devs.note = "SEGGER J-Link and compatible devices\n",
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_NI845X_SPI == 1
- {
- .name = "ni845x_spi",
- .type = OTHER, // choose other because NI-845x uses own USB implementation
- .devs.note = "National Instruments USB-845x\n",
- .init = ni845x_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
-#if CONFIG_STLINKV3_SPI == 1
- {
- .name = "stlinkv3_spi",
- .type = USB,
- .devs.dev = devs_stlinkv3_spi,
- .init = stlinkv3_spi_init,
- .map_flash_region = fallback_map,
- .unmap_flash_region = fallback_unmap,
- .delay = internal_delay,
- },
-#endif
-
- {0}, /* This entry corresponds to PROGRAMMER_INVALID. */
-};
+bool programmer_may_write;
#define SHUTDOWN_MAXFN 32
static int shutdown_fn_count = 0;
@@ -546,12 +64,18 @@ static struct shutdown_func_data {
/* Initialize to 0 to make sure nobody registers a shutdown function before
* programmer init.
*/
-static int may_register_shutdown = 0;
-
-/* Did we change something or was every erase/write skipped (if any)? */
-static bool all_skipped = true;
-
-static int check_block_eraser(const struct flashctx *flash, int k, int log);
+static bool may_register_shutdown = false;
+
+static struct bus_type_info {
+ enum chipbustype type;
+ const char *name;
+} bustypes[] = {
+ { BUS_PARALLEL, "Parallel, " },
+ { BUS_LPC, "LPC, " },
+ { BUS_FWH, "FWH, " },
+ { BUS_SPI, "SPI, " },
+ { BUS_PROG, "Programmer-specific, " },
+};
/* Register a function to be executed on programmer shutdown.
* The advantage over atexit() is that you can supply a void pointer which will
@@ -581,7 +105,7 @@ int register_shutdown(int (*function) (void *data), void *data)
}
int register_chip_restore(chip_restore_fn_cb_t func,
- struct flashctx *flash, uint8_t status)
+ struct flashctx *flash, void *data)
{
if (flash->chip_restore_fn_count >= MAX_CHIP_RESTORE_FUNCTIONS) {
msg_perr("Tried to register more than %i chip restore"
@@ -589,7 +113,7 @@ int register_chip_restore(chip_restore_fn_cb_t func,
return 1;
}
flash->chip_restore_fn[flash->chip_restore_fn_count].func = func;
- flash->chip_restore_fn[flash->chip_restore_fn_count].status = status;
+ flash->chip_restore_fn[flash->chip_restore_fn_count].data = data;
flash->chip_restore_fn_count++;
return 0;
@@ -602,17 +126,17 @@ static int deregister_chip_restore(struct flashctx *flash)
while (flash->chip_restore_fn_count > 0) {
int i = --flash->chip_restore_fn_count;
rc |= flash->chip_restore_fn[i].func(
- flash, flash->chip_restore_fn[i].status);
+ flash, flash->chip_restore_fn[i].data);
}
return rc;
}
-int programmer_init(enum programmer prog, const char *param)
+int programmer_init(const struct programmer_entry *prog, const char *param)
{
int ret;
- if (prog >= PROGRAMMER_INVALID) {
+ if (prog == NULL) {
msg_perr("Invalid programmer specified!\n");
return -1;
}
@@ -628,29 +152,41 @@ int programmer_init(enum programmer prog, const char *param)
/* Default to top aligned flash at 4 GB. */
flashbase = 0;
/* Registering shutdown functions is now allowed. */
- may_register_shutdown = 1;
+ may_register_shutdown = true;
/* Default to allowing writes. Broken programmers set this to 0. */
- programmer_may_write = 1;
+ programmer_may_write = true;
+
+ struct programmer_cfg cfg;
- programmer_param = param;
- msg_pdbg("Initializing %s programmer\n", programmer_table[programmer].name);
- ret = programmer_table[programmer].init();
- if (programmer_param && strlen(programmer_param)) {
+ if (param) {
+ cfg.params = strdup(param);
+ if (!cfg.params) {
+ msg_perr("Out of memory!\n");
+ return ERROR_FLASHROM_FATAL;
+ }
+ } else {
+ cfg.params = NULL;
+ }
+
+ msg_pdbg("Initializing %s programmer\n", prog->name);
+ ret = prog->init(&cfg);
+ if (cfg.params && strlen(cfg.params)) {
if (ret != 0) {
/* It is quite possible that any unhandled programmer parameter would have been valid,
* but an error in actual programmer init happened before the parameter was evaluated.
*/
msg_pwarn("Unhandled programmer parameters (possibly due to another failure): %s\n",
- programmer_param);
+ cfg.params);
} else {
/* Actual programmer init was successful, but the user specified an invalid or unusable
* (for the current programmer configuration) parameter.
*/
- msg_perr("Unhandled programmer parameters: %s\n", programmer_param);
+ msg_perr("Unhandled programmer parameters: %s\n", cfg.params);
msg_perr("Aborting.\n");
- ret = ERROR_FATAL;
+ ret = ERROR_FLASHROM_FATAL;
}
}
+ free(cfg.params);
return ret;
}
@@ -664,77 +200,100 @@ int programmer_shutdown(void)
int ret = 0;
/* Registering shutdown functions is no longer allowed. */
- may_register_shutdown = 0;
+ may_register_shutdown = false;
while (shutdown_fn_count > 0) {
int i = --shutdown_fn_count;
ret |= shutdown_fn[i].func(shutdown_fn[i].data);
}
-
- programmer_param = NULL;
registered_master_count = 0;
return ret;
}
-void *programmer_map_flash_region(const char *descr, uintptr_t phys_addr, size_t len)
+void *master_map_flash_region(const struct registered_master *mst,
+ const char *descr, uintptr_t phys_addr,
+ size_t len)
{
- void *ret = programmer_table[programmer].map_flash_region(descr, phys_addr, len);
+ /* Check the bus master for a specialized map_flash_region; default to
+ * fallback if it does not specialize it
+ */
+ void *(*map_flash_region) (const char *descr, uintptr_t phys_addr, size_t len) = NULL;
+ if (mst->buses_supported & BUS_SPI)
+ map_flash_region = mst->spi.map_flash_region;
+ else if (mst->buses_supported & BUS_NONSPI)
+ map_flash_region = mst->par.map_flash_region;
+
+ /* A result of NULL causes mapped addresses to be chip physical
+ * addresses, assuming only a single region is mapped (the entire flash
+ * space). Chips with a second region (like a register map) require a
+ * real memory mapping to distinguish the different ranges. Those chips
+ * are FWH/LPC, so the bus master provides a real mapping.
+ */
+ void *ret = NULL;
+ if (map_flash_region)
+ ret = map_flash_region(descr, phys_addr, len);
msg_gspew("%s: mapping %s from 0x%0*" PRIxPTR " to 0x%0*" PRIxPTR "\n",
- __func__, descr, PRIxPTR_WIDTH, phys_addr, PRIxPTR_WIDTH, (uintptr_t) ret);
+ __func__, descr, PRIxPTR_WIDTH, phys_addr, PRIxPTR_WIDTH, (uintptr_t) ret);
return ret;
}
-void programmer_unmap_flash_region(void *virt_addr, size_t len)
+void master_unmap_flash_region(const struct registered_master *mst,
+ void *virt_addr, size_t len)
{
- programmer_table[programmer].unmap_flash_region(virt_addr, len);
- msg_gspew("%s: unmapped 0x%0*" PRIxPTR "\n", __func__, PRIxPTR_WIDTH, (uintptr_t)virt_addr);
-}
+ void (*unmap_flash_region) (void *virt_addr, size_t len) = NULL;
+ if (mst->buses_supported & BUS_SPI)
+ unmap_flash_region = mst->spi.unmap_flash_region;
+ else if (mst->buses_supported & BUS_NONSPI)
+ unmap_flash_region = mst->par.unmap_flash_region;
-void chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
-{
- flash->mst->par.chip_writeb(flash, val, addr);
-}
-
-void chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr)
-{
- flash->mst->par.chip_writew(flash, val, addr);
-}
-
-void chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
-{
- flash->mst->par.chip_writel(flash, val, addr);
-}
-
-void chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
-{
- flash->mst->par.chip_writen(flash, buf, addr, len);
+ if (unmap_flash_region)
+ unmap_flash_region(virt_addr, len);
+ msg_gspew("%s: unmapped 0x%0*" PRIxPTR "\n", __func__, PRIxPTR_WIDTH, (uintptr_t)virt_addr);
}
-uint8_t chip_readb(const struct flashctx *flash, const chipaddr addr)
+static bool master_uses_physmap(const struct registered_master *mst)
{
- return flash->mst->par.chip_readb(flash, addr);
+#if CONFIG_INTERNAL == 1
+ if (mst->buses_supported & BUS_SPI)
+ return mst->spi.map_flash_region == physmap;
+ else if (mst->buses_supported & BUS_NONSPI)
+ return mst->par.map_flash_region == physmap;
+#endif
+ return false;
}
-uint16_t chip_readw(const struct flashctx *flash, const chipaddr addr)
+void programmer_delay(const struct flashctx *flash, unsigned int usecs)
{
- return flash->mst->par.chip_readw(flash, addr);
-}
+ if (usecs == 0)
+ return;
-uint32_t chip_readl(const struct flashctx *flash, const chipaddr addr)
-{
- return flash->mst->par.chip_readl(flash, addr);
-}
+ /**
+ * Drivers should either use default_delay() directly or their
+ * own custom delay. Only core flashrom logic calls programmer_delay()
+ * which should always have a valid flash context. A NULL context
+ * more than likely indicates a layering violation or BUG however
+ * for now dispatch a default_delay() as a safe default for the NULL
+ * base case.
+ */
+ if (!flash) {
+ msg_perr("%s called with NULL flash context. "
+ "Please report a bug at flashrom@flashrom.org\n",
+ __func__);
+ return default_delay(usecs);
+ }
-void chip_readn(const struct flashctx *flash, uint8_t *buf, chipaddr addr,
- size_t len)
-{
- flash->mst->par.chip_readn(flash, buf, addr, len);
-}
+ if (flash->mst->buses_supported & BUS_SPI) {
+ if (flash->mst->spi.delay)
+ return flash->mst->spi.delay(flash, usecs);
+ } else if (flash->mst->buses_supported & BUS_PARALLEL) {
+ if (flash->mst->par.delay)
+ return flash->mst->par.delay(flash, usecs);
+ } else if (flash->mst->buses_supported & BUS_PROG) {
+ if (flash->mst->opaque.delay)
+ return flash->mst->opaque.delay(flash, usecs);
+ }
-void programmer_delay(unsigned int usecs)
-{
- if (usecs > 0)
- programmer_table[programmer].delay(usecs);
+ return default_delay(usecs);
}
int read_memmapped(struct flashctx *flash, uint8_t *buf, unsigned int start,
@@ -750,7 +309,7 @@ int read_memmapped(struct flashctx *flash, uint8_t *buf, unsigned int start,
* needle and remove everything from the first occurrence of needle to the next
* delimiter from haystack.
*/
-char *extract_param(const char *const *haystack, const char *needle, const char *delim)
+static char *extract_param(char *const *haystack, const char *needle, const char *delim)
{
char *param_pos, *opt_pos, *rest;
char *opt = NULL;
@@ -792,7 +351,7 @@ char *extract_param(const char *const *haystack, const char *needle, const char
opt = malloc(optlen + 1);
if (!opt) {
msg_gerr("Out of memory!\n");
- exit(1);
+ return NULL;
}
strncpy(opt, opt_pos, optlen);
opt[optlen] = '\0';
@@ -806,13 +365,133 @@ char *extract_param(const char *const *haystack, const char *needle, const char
return opt;
}
-char *extract_programmer_param(const char *param_name)
+char *extract_programmer_param_str(const struct programmer_cfg *cfg, const char *param_name)
{
- return extract_param(&programmer_param, param_name, ",");
+ return extract_param(&cfg->params, param_name, ",");
+}
+
+void get_flash_region(const struct flashctx *flash, int addr, struct flash_region *region)
+{
+ if ((flash->mst->buses_supported & BUS_PROG) && flash->mst->opaque.get_region) {
+ flash->mst->opaque.get_region(flash, addr, region);
+ } else if (flash->mst->buses_supported & BUS_SPI && flash->mst->spi.get_region) {
+ flash->mst->spi.get_region(flash, addr, region);
+ } else {
+ region->name = strdup("");
+ region->start = 0;
+ region->end = flashrom_flash_getsize(flash);
+ region->read_prot = false;
+ region->write_prot = false;
+ }
+}
+
+int check_for_unwritable_regions(const struct flashctx *flash, unsigned int start, unsigned int len)
+{
+ struct flash_region region;
+ for (unsigned int addr = start; addr < start + len; addr = region.end) {
+ get_flash_region(flash, addr, &region);
+
+ if (region.write_prot) {
+ msg_gerr("%s: cannot write/erase inside %s region (%#08"PRIx32"..%#08"PRIx32").\n",
+ __func__, region.name, region.start, region.end - 1);
+ free(region.name);
+ return -1;
+ }
+ free(region.name);
+ }
+ return 0;
+}
+
+/* special unit-test hook */
+erasefunc_t *g_test_erase_injector;
+
+erasefunc_t *lookup_erase_func_ptr(const struct block_eraser *const eraser)
+{
+ switch (eraser->block_erase) {
+ case SPI_BLOCK_ERASE_EMULATION: return &spi_block_erase_emulation;
+ case SPI_BLOCK_ERASE_20: return &spi_block_erase_20;
+ case SPI_BLOCK_ERASE_21: return &spi_block_erase_21;
+ case SPI_BLOCK_ERASE_40: return NULL; // FIXME unhandled &spi_block_erase_40;
+ case SPI_BLOCK_ERASE_50: return &spi_block_erase_50;
+ case SPI_BLOCK_ERASE_52: return &spi_block_erase_52;
+ case SPI_BLOCK_ERASE_53: return &spi_block_erase_53;
+ case SPI_BLOCK_ERASE_5C: return &spi_block_erase_5c;
+ case SPI_BLOCK_ERASE_60: return &spi_block_erase_60;
+ case SPI_BLOCK_ERASE_62: return &spi_block_erase_62;
+ case SPI_BLOCK_ERASE_81: return &spi_block_erase_81;
+ case SPI_BLOCK_ERASE_C4: return &spi_block_erase_c4;
+ case SPI_BLOCK_ERASE_C7: return &spi_block_erase_c7;
+ case SPI_BLOCK_ERASE_D7: return &spi_block_erase_d7;
+ case SPI_BLOCK_ERASE_D8: return &spi_block_erase_d8;
+ case SPI_BLOCK_ERASE_DB: return &spi_block_erase_db;
+ case SPI_BLOCK_ERASE_DC: return &spi_block_erase_dc;
+ case S25FL_BLOCK_ERASE: return &s25fl_block_erase;
+ case S25FS_BLOCK_ERASE_D8: return &s25fs_block_erase_d8;
+ case JEDEC_SECTOR_ERASE: return &erase_sector_jedec; // TODO rename to &jedec_sector_erase;
+ case JEDEC_BLOCK_ERASE: return &erase_block_jedec; // TODO rename to &jedec_block_erase;
+ case JEDEC_CHIP_BLOCK_ERASE: return &erase_chip_block_jedec; // TODO rename to &jedec_chip_block_erase;
+ case OPAQUE_ERASE: return &erase_opaque; // TODO rename to &opqaue_erase;
+ case SPI_ERASE_AT45CS_SECTOR: return &spi_erase_at45cs_sector;
+ case SPI_ERASE_AT45DB_BLOCK: return &spi_erase_at45db_block;
+ case SPI_ERASE_AT45DB_CHIP: return &spi_erase_at45db_chip;
+ case SPI_ERASE_AT45DB_PAGE: return &spi_erase_at45db_page;
+ case SPI_ERASE_AT45DB_SECTOR: return &spi_erase_at45db_sector;
+ case ERASE_CHIP_28SF040: return &erase_chip_28sf040;
+ case ERASE_SECTOR_28SF040: return &erase_sector_28sf040;
+ case ERASE_BLOCK_82802AB: return &erase_block_82802ab;
+ case ERASE_SECTOR_49LFXXXC: return &erase_sector_49lfxxxc;
+ case STM50_SECTOR_ERASE: return &erase_sector_stm50; // TODO rename to &stm50_sector_erase;
+ case EDI_CHIP_BLOCK_ERASE: return &edi_chip_block_erase;
+ case TEST_ERASE_INJECTOR: return g_test_erase_injector;
+ /* default: total function, 0 indicates no erase function set.
+ * We explicitly do not want a default catch-all case in the switch
+ * to ensure unhandled enum's are compiler warnings.
+ */
+ case NO_BLOCK_ERASE_FUNC: return NULL;
+ };
+
+ return NULL;
+}
+
+int check_block_eraser(const struct flashctx *flash, int k, int log)
+{
+ struct block_eraser eraser = flash->chip->block_erasers[k];
+
+ if (eraser.block_erase == NO_BLOCK_ERASE_FUNC && !eraser.eraseblocks[0].count) {
+ if (log)
+ msg_cdbg("not defined. ");
+ return 1;
+ }
+ if (eraser.block_erase == NO_BLOCK_ERASE_FUNC && eraser.eraseblocks[0].count) {
+ if (log)
+ msg_cdbg("eraseblock layout is known, but matching "
+ "block erase function is not implemented. ");
+ return 1;
+ }
+ if (eraser.block_erase != NO_BLOCK_ERASE_FUNC && !eraser.eraseblocks[0].count) {
+ if (log)
+ msg_cdbg("block erase function found, but "
+ "eraseblock layout is not defined. ");
+ return 1;
+ }
+
+ if (flash->mst->buses_supported & BUS_SPI) {
+ const uint8_t *opcode = spi_get_opcode_from_erasefn(eraser.block_erase);
+ for (int i = 0; opcode[i]; i++) {
+ if (!spi_probe_opcode(flash, opcode[i])) {
+ if (log)
+ msg_cdbg("block erase function and layout found "
+ "but SPI master doesn't support the function. ");
+ return 1;
+ }
+ }
+ }
+ // TODO: Once erase functions are annotated with allowed buses, check that as well.
+ return 0;
}
/* Returns the number of well-defined erasers for a chip. */
-static unsigned int count_usable_erasers(const struct flashctx *flash)
+unsigned int count_usable_erasers(const struct flashctx *flash)
{
unsigned int usable_erasefunctions = 0;
int k;
@@ -844,22 +523,102 @@ static int compare_range(const uint8_t *wantbuf, const uint8_t *havebuf, unsigne
}
/* start is an offset to the base address of the flash chip */
-static int check_erased_range(struct flashctx *flash, unsigned int start, unsigned int len)
+int check_erased_range(struct flashctx *flash, unsigned int start, unsigned int len)
{
int ret;
- uint8_t *cmpbuf = malloc(len);
const uint8_t erased_value = ERASED_VALUE(flash);
+ uint8_t *cmpbuf = malloc(len);
if (!cmpbuf) {
- msg_gerr("Could not allocate memory!\n");
- exit(1);
+ msg_gerr("Out of memory!\n");
+ return -1;
}
memset(cmpbuf, erased_value, len);
ret = verify_range(flash, cmpbuf, start, len);
+
free(cmpbuf);
return ret;
}
+/* special unit-test hook */
+read_func_t *g_test_read_injector;
+
+static read_func_t *lookup_read_func_ptr(const struct flashchip *chip)
+{
+ switch (chip->read) {
+ case SPI_CHIP_READ: return &spi_chip_read;
+ case READ_OPAQUE: return &read_opaque;
+ case READ_MEMMAPPED: return &read_memmapped;
+ case EDI_CHIP_READ: return &edi_chip_read;
+ case SPI_READ_AT45DB: return spi_read_at45db;
+ case SPI_READ_AT45DB_E8: return spi_read_at45db_e8;
+ case TEST_READ_INJECTOR: return g_test_read_injector;
+ /* default: total function, 0 indicates no read function set.
+ * We explicitly do not want a default catch-all case in the switch
+ * to ensure unhandled enum's are compiler warnings.
+ */
+ case NO_READ_FUNC: return NULL;
+ };
+
+ return NULL;
+}
+
+/*
+ * @brief Wrapper for flash->read() with additional high-level policy.
+ *
+ * @param flash flash chip
+ * @param buf buffer to store data in
+ * @param start start address
+ * @param len number of bytes to read
+ * @return 0 on success,
+ * -1 if any read fails.
+ *
+ * This wrapper simplifies most cases when the flash chip needs to be read
+ * since policy decisions such as non-fatal error handling is centralized.
+ */
+int read_flash(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+ unsigned int read_len;
+ for (unsigned int addr = start; addr < start + len; addr += read_len) {
+ struct flash_region region;
+ get_flash_region(flash, addr, &region);
+
+ read_len = min(start + len, region.end) - addr;
+ uint8_t *rbuf = buf + addr - start;
+
+ if (region.read_prot) {
+ if (flash->flags.skip_unreadable_regions) {
+ msg_gdbg("%s: cannot read inside %s region (%#08"PRIx32"..%#08"PRIx32"), "
+ "filling (%#08x..%#08x) with erased value instead.\n",
+ __func__, region.name, region.start, region.end - 1,
+ addr, addr + read_len - 1);
+ free(region.name);
+
+ memset(rbuf, ERASED_VALUE(flash), read_len);
+ continue;
+ }
+
+ msg_gerr("%s: cannot read inside %s region (%#08"PRIx32"..%#08"PRIx32").\n",
+ __func__, region.name, region.start, region.end - 1);
+ free(region.name);
+ return -1;
+ }
+ msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is readable, reading range (%#08x..%#08x).\n",
+ __func__, region.name, region.start, region.end - 1, addr, addr + read_len - 1);
+ free(region.name);
+
+ read_func_t *read_func = lookup_read_func_ptr(flash->chip);
+ int ret = read_func(flash, rbuf, addr, read_len);
+ if (ret) {
+ msg_gerr("%s: failed to read (%#08x..%#08x).\n", __func__, addr, addr + read_len - 1);
+ return -1;
+ }
+
+ }
+
+ return 0;
+}
+
/*
* @cmpbuf buffer to compare against, cmpbuf[0] is expected to match the
* flash content at location start
@@ -872,35 +631,62 @@ int verify_range(struct flashctx *flash, const uint8_t *cmpbuf, unsigned int sta
if (!len)
return -1;
- if (!flash->chip->read) {
- msg_cerr("ERROR: flashrom has no read function for this flash chip.\n");
+ if (start + len > flash->chip->total_size * 1024) {
+ msg_gerr("Error: %s called with start 0x%x + len 0x%x >"
+ " total_size 0x%x\n", __func__, start, len,
+ flash->chip->total_size * 1024);
return -1;
}
uint8_t *readbuf = malloc(len);
if (!readbuf) {
- msg_gerr("Could not allocate memory!\n");
+ msg_gerr("Out of memory!\n");
return -1;
}
+
int ret = 0;
- if (start + len > flash->chip->total_size * 1024) {
- msg_gerr("Error: %s called with start 0x%x + len 0x%x >"
- " total_size 0x%x\n", __func__, start, len,
- flash->chip->total_size * 1024);
- ret = -1;
- goto out_free;
- }
+ msg_gdbg("%#06x..%#06x ", start, start + len - 1);
+
+ unsigned int read_len;
+ for (size_t addr = start; addr < start + len; addr += read_len) {
+ struct flash_region region;
+ get_flash_region(flash, addr, &region);
+ read_len = min(start + len, region.end) - addr;
+
+ if ((region.write_prot && flash->flags.skip_unwritable_regions) ||
+ (region.read_prot && flash->flags.skip_unreadable_regions)) {
+ msg_gdbg("%s: Skipping verification of %s region (%#08"PRIx32"..%#08"PRIx32")\n",
+ __func__, region.name, region.start, region.end - 1);
+ free(region.name);
+ continue;
+ }
+
+ if (region.read_prot) {
+ msg_gerr("%s: Verification imposible because %s region (%#08"PRIx32"..%#08"PRIx32") is unreadable.\n",
+ __func__, region.name, region.start, region.end - 1);
+ free(region.name);
+ goto out_free;
+ }
+
+ msg_gdbg("%s: Verifying %s region (%#08"PRIx32"..%#08"PRIx32")\n",
+ __func__, region.name, region.start, region.end - 1);
+ free(region.name);
+
+ ret = read_flash(flash, readbuf, addr, read_len);
+ if (ret) {
+ msg_gerr("Verification impossible because read failed "
+ "at 0x%x (len 0x%x)\n", start, len);
+ ret = -1;
+ goto out_free;
+ }
+
+ ret = compare_range(cmpbuf + (addr - start), readbuf, addr, read_len);
+ if (ret)
+ goto out_free;
- ret = flash->chip->read(flash, readbuf, start, len);
- if (ret) {
- msg_gerr("Verification impossible because read failed "
- "at 0x%x (len 0x%x)\n", start, len);
- ret = -1;
- goto out_free;
}
- ret = compare_range(cmpbuf, readbuf, start, len);
out_free:
free(readbuf);
return ret;
@@ -945,42 +731,42 @@ int need_erase(const uint8_t *have, const uint8_t *want, unsigned int len,
unsigned int i;
switch (gran) {
- case write_gran_1bit:
+ case WRITE_GRAN_1BIT:
for (i = 0; i < len; i++)
if ((have[i] & want[i]) != want[i]) {
result = 1;
break;
}
break;
- case write_gran_1byte:
+ case WRITE_GRAN_1BYTE:
for (i = 0; i < len; i++)
if ((have[i] != want[i]) && (have[i] != erased_value)) {
result = 1;
break;
}
break;
- case write_gran_128bytes:
+ case WRITE_GRAN_128BYTES:
result = need_erase_gran_bytes(have, want, len, 128, erased_value);
break;
- case write_gran_256bytes:
+ case WRITE_GRAN_256BYTES:
result = need_erase_gran_bytes(have, want, len, 256, erased_value);
break;
- case write_gran_264bytes:
+ case WRITE_GRAN_264BYTES:
result = need_erase_gran_bytes(have, want, len, 264, erased_value);
break;
- case write_gran_512bytes:
+ case WRITE_GRAN_512BYTES:
result = need_erase_gran_bytes(have, want, len, 512, erased_value);
break;
- case write_gran_528bytes:
+ case WRITE_GRAN_528BYTES:
result = need_erase_gran_bytes(have, want, len, 528, erased_value);
break;
- case write_gran_1024bytes:
+ case WRITE_GRAN_1024BYTES:
result = need_erase_gran_bytes(have, want, len, 1024, erased_value);
break;
- case write_gran_1056bytes:
+ case WRITE_GRAN_1056BYTES:
result = need_erase_gran_bytes(have, want, len, 1056, erased_value);
break;
- case write_gran_1byte_implicit_erase:
+ case WRITE_GRAN_1BYTE_IMPLICIT_ERASE:
/* Do not erase, handle content changes from anything->0xff by writing 0xff. */
result = 0;
break;
@@ -1014,39 +800,39 @@ int need_erase(const uint8_t *have, const uint8_t *want, unsigned int len,
* in relation to the max write length of the programmer and the max write
* length of the chip.
*/
-static unsigned int get_next_write(const uint8_t *have, const uint8_t *want, unsigned int len,
+unsigned int get_next_write(const uint8_t *have, const uint8_t *want, unsigned int len,
unsigned int *first_start,
enum write_granularity gran)
{
- int need_write = 0;
+ bool need_write = false;
unsigned int rel_start = 0, first_len = 0;
unsigned int i, limit, stride;
switch (gran) {
- case write_gran_1bit:
- case write_gran_1byte:
- case write_gran_1byte_implicit_erase:
+ case WRITE_GRAN_1BIT:
+ case WRITE_GRAN_1BYTE:
+ case WRITE_GRAN_1BYTE_IMPLICIT_ERASE:
stride = 1;
break;
- case write_gran_128bytes:
+ case WRITE_GRAN_128BYTES:
stride = 128;
break;
- case write_gran_256bytes:
+ case WRITE_GRAN_256BYTES:
stride = 256;
break;
- case write_gran_264bytes:
+ case WRITE_GRAN_264BYTES:
stride = 264;
break;
- case write_gran_512bytes:
+ case WRITE_GRAN_512BYTES:
stride = 512;
break;
- case write_gran_528bytes:
+ case WRITE_GRAN_528BYTES:
stride = 528;
break;
- case write_gran_1024bytes:
+ case WRITE_GRAN_1024BYTES:
stride = 1024;
break;
- case write_gran_1056bytes:
+ case WRITE_GRAN_1056BYTES:
stride = 1056;
break;
default:
@@ -1063,7 +849,7 @@ static unsigned int get_next_write(const uint8_t *have, const uint8_t *want, uns
if (memcmp(have + i * stride, want + i * stride, limit)) {
if (!need_write) {
/* First location where have and want differ. */
- need_write = 1;
+ need_write = true;
rel_start = i * stride;
}
} else {
@@ -1081,59 +867,16 @@ static unsigned int get_next_write(const uint8_t *have, const uint8_t *want, uns
return first_len;
}
-/* Returns the number of busses commonly supported by the current programmer and flash chip where the latter
- * can not be completely accessed due to size/address limits of the programmer. */
-unsigned int count_max_decode_exceedings(const struct flashctx *flash)
-{
- unsigned int limitexceeded = 0;
- uint32_t size = flash->chip->total_size * 1024;
- enum chipbustype buses = flash->mst->buses_supported & flash->chip->bustype;
-
- if ((buses & BUS_PARALLEL) && (max_rom_decode.parallel < size)) {
- limitexceeded++;
- msg_pdbg("Chip size %u kB is bigger than supported "
- "size %u kB of chipset/board/programmer "
- "for %s interface, "
- "probe/read/erase/write may fail. ", size / 1024,
- max_rom_decode.parallel / 1024, "Parallel");
- }
- if ((buses & BUS_LPC) && (max_rom_decode.lpc < size)) {
- limitexceeded++;
- msg_pdbg("Chip size %u kB is bigger than supported "
- "size %u kB of chipset/board/programmer "
- "for %s interface, "
- "probe/read/erase/write may fail. ", size / 1024,
- max_rom_decode.lpc / 1024, "LPC");
- }
- if ((buses & BUS_FWH) && (max_rom_decode.fwh < size)) {
- limitexceeded++;
- msg_pdbg("Chip size %u kB is bigger than supported "
- "size %u kB of chipset/board/programmer "
- "for %s interface, "
- "probe/read/erase/write may fail. ", size / 1024,
- max_rom_decode.fwh / 1024, "FWH");
- }
- if ((buses & BUS_SPI) && (max_rom_decode.spi < size)) {
- limitexceeded++;
- msg_pdbg("Chip size %u kB is bigger than supported "
- "size %u kB of chipset/board/programmer "
- "for %s interface, "
- "probe/read/erase/write may fail. ", size / 1024,
- max_rom_decode.spi / 1024, "SPI");
- }
- return limitexceeded;
-}
-
void unmap_flash(struct flashctx *flash)
{
if (flash->virtual_registers != (chipaddr)ERROR_PTR) {
- programmer_unmap_flash_region((void *)flash->virtual_registers, flash->chip->total_size * 1024);
+ master_unmap_flash_region(flash->mst, (void *)flash->virtual_registers, flash->chip->total_size * 1024);
flash->physical_registers = 0;
flash->virtual_registers = (chipaddr)ERROR_PTR;
}
if (flash->virtual_memory != (chipaddr)ERROR_PTR) {
- programmer_unmap_flash_region((void *)flash->virtual_memory, flash->chip->total_size * 1024);
+ master_unmap_flash_region(flash->mst, (void *)flash->virtual_memory, flash->chip->total_size * 1024);
flash->physical_memory = 0;
flash->virtual_memory = (chipaddr)ERROR_PTR;
}
@@ -1153,7 +896,7 @@ int map_flash(struct flashctx *flash)
const chipsize_t size = flash->chip->total_size * 1024;
uintptr_t base = flashbase ? flashbase : (0xffffffff - size + 1);
- void *addr = programmer_map_flash_region(flash->chip->name, base, size);
+ void *addr = master_map_flash_region(flash->mst, flash->chip->name, base, size);
if (addr == ERROR_PTR) {
msg_perr("Could not map flash chip %s at 0x%0*" PRIxPTR ".\n",
flash->chip->name, PRIxPTR_WIDTH, base);
@@ -1167,7 +910,7 @@ int map_flash(struct flashctx *flash)
* Ignore these problems for now and always report success. */
if (flash->chip->feature_bits & FEATURE_REGISTERMAP) {
base = 0xffffffff - size - 0x400000 + 1;
- addr = programmer_map_flash_region("flash chip registers", base, size);
+ addr = master_map_flash_region(flash->mst, "flash chip registers", base, size);
if (addr == ERROR_PTR) {
msg_pdbg2("Could not map flash chip registers %s at 0x%0*" PRIxPTR ".\n",
flash->chip->name, PRIxPTR_WIDTH, base);
@@ -1181,38 +924,171 @@ int map_flash(struct flashctx *flash)
/*
* Return a string corresponding to the bustype parameter.
- * Memory is obtained with malloc() and must be freed with free() by the caller.
+ * Memory to store the string is allocated. The caller is responsible to free memory.
+ * If there is not enough memory remaining, then NULL is returned.
*/
char *flashbuses_to_text(enum chipbustype bustype)
{
- char *ret = calloc(1, 1);
+ char *ret, *ptr;
+
/*
* FIXME: Once all chipsets and flash chips have been updated, NONSPI
* will cease to exist and should be eliminated here as well.
*/
- if (bustype == BUS_NONSPI) {
- ret = strcat_realloc(ret, "Non-SPI, ");
- } else {
- if (bustype & BUS_PARALLEL)
- ret = strcat_realloc(ret, "Parallel, ");
- if (bustype & BUS_LPC)
- ret = strcat_realloc(ret, "LPC, ");
- if (bustype & BUS_FWH)
- ret = strcat_realloc(ret, "FWH, ");
- if (bustype & BUS_SPI)
- ret = strcat_realloc(ret, "SPI, ");
- if (bustype & BUS_PROG)
- ret = strcat_realloc(ret, "Programmer-specific, ");
- if (bustype == BUS_NONE)
- ret = strcat_realloc(ret, "None, ");
+ if (bustype == BUS_NONSPI)
+ return strdup("Non-SPI");
+ if (bustype == BUS_NONE)
+ return strdup("None");
+
+ ret = calloc(1, 1);
+ if (!ret)
+ return NULL;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(bustypes); i++)
+ {
+ if (bustype & bustypes[i].type) {
+ ptr = strcat_realloc(ret, bustypes[i].name);
+ if (!ptr) {
+ free(ret);
+ return NULL;
+ }
+ ret = ptr;
+ }
}
+
/* Kill last comma. */
ret[strlen(ret) - 2] = '\0';
- ret = realloc(ret, strlen(ret) + 1);
- return ret;
+ ptr = realloc(ret, strlen(ret) + 1);
+ if (!ptr)
+ free(ret);
+ return ptr;
+}
+
+static int init_default_layout(struct flashctx *flash)
+{
+ /* Fill default layout covering the whole chip. */
+ if (flashrom_layout_new(&flash->default_layout) ||
+ flashrom_layout_add_region(flash->default_layout,
+ 0, flash->chip->total_size * 1024 - 1, "complete flash") ||
+ flashrom_layout_include_region(flash->default_layout, "complete flash"))
+ return -1;
+ return 0;
+}
+
+/* special unit-test hook */
+write_func_t *g_test_write_injector;
+
+static write_func_t *lookup_write_func_ptr(const struct flashchip *chip)
+{
+ switch (chip->write) {
+ case WRITE_JEDEC: return &write_jedec;
+ case WRITE_JEDEC1: return &write_jedec_1;
+ case WRITE_OPAQUE: return &write_opaque;
+ case SPI_CHIP_WRITE1: return &spi_chip_write_1;
+ case SPI_CHIP_WRITE256: return &spi_chip_write_256;
+ case SPI_WRITE_AAI: return &spi_aai_write;
+ case SPI_WRITE_AT45DB: return &spi_write_at45db;
+ case WRITE_28SF040: return &write_28sf040;
+ case WRITE_82802AB: return &write_82802ab;
+ case WRITE_EN29LV640B: return &write_en29lv640b;
+ case EDI_CHIP_WRITE: return &edi_chip_write;
+ case TEST_WRITE_INJECTOR: return g_test_write_injector;
+ /* default: total function, 0 indicates no write function set.
+ * We explicitly do not want a default catch-all case in the switch
+ * to ensure unhandled enum's are compiler warnings.
+ */
+ case NO_WRITE_FUNC: return NULL;
+ };
+
+ return NULL;
+}
+
+/*
+ * write_flash - wrapper for flash->write() with additional high-level policy
+ *
+ * @param flash flash chip
+ * @param buf buffer to write to flash
+ * @param start start address in flash
+ * @param len number of bytes to write
+ * @return 0 on success,
+ * -1 if any write fails.
+ *
+ * This wrapper simplifies most cases when the flash chip needs to be written
+ * since policy decisions such as non-fatal error handling is centralized.
+ */
+int write_flash(struct flashctx *flash, const uint8_t *buf,
+ unsigned int start, unsigned int len)
+{
+ if (!flash->flags.skip_unwritable_regions) {
+ if (check_for_unwritable_regions(flash, start, len))
+ return -1;
+ }
+
+ unsigned int write_len;
+ for (unsigned int addr = start; addr < start + len; addr += write_len) {
+ struct flash_region region;
+ get_flash_region(flash, addr, &region);
+
+ write_len = min(start + len, region.end) - addr;
+ const uint8_t *rbuf = buf + addr - start;
+
+ if (region.write_prot) {
+ msg_gdbg("%s: cannot write inside %s region (%#08"PRIx32"..%#08"PRIx32"), skipping (%#08x..%#08x).\n",
+ __func__, region.name, region.start, region.end - 1, addr, addr + write_len - 1);
+ free(region.name);
+ continue;
+ }
+
+ msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is writable, writing range (%#08x..%#08x).\n",
+ __func__, region.name, region.start, region.end - 1, addr, addr + write_len - 1);
+
+ write_func_t *write_func = lookup_write_func_ptr(flash->chip);
+ int ret = write_func(flash, rbuf, addr, write_len);
+ if (ret) {
+ msg_gerr("%s: failed to write (%#08x..%#08x).\n", __func__, addr, addr + write_len - 1);
+ free(region.name);
+ return -1;
+ }
+
+ free(region.name);
+ }
+
+ return 0;
}
-int probe_flash(struct registered_master *mst, int startchip, struct flashctx *flash, int force)
+typedef int (probe_func_t)(struct flashctx *flash);
+
+static probe_func_t *lookup_probe_func_ptr(const struct flashchip *chip)
+{
+ switch (chip->probe) {
+ case PROBE_JEDEC: return &probe_jedec;
+ case PROBE_JEDEC_29GL: return &probe_jedec_29gl;
+ case PROBE_OPAQUE: return &probe_opaque;
+ case PROBE_EDI_KB9012: return &edi_probe_kb9012;
+ case PROBE_AT82802AB: return &probe_82802ab;
+ case PROBE_W29EE011: return &probe_w29ee011;
+ case PROBE_EN29LV640B: return &probe_en29lv640b;
+ case PROBE_SPI_AT25F: return &probe_spi_at25f;
+ case PROBE_SPI_AT45DB: return &probe_spi_at45db;
+ case PROBE_SPI_BIG_SPANSION: return &probe_spi_big_spansion;
+ case PROBE_SPI_RDID: return &probe_spi_rdid;
+ case PROBE_SPI_RDID4: return &probe_spi_rdid4;
+ case PROBE_SPI_REMS: return &probe_spi_rems;
+ case PROBE_SPI_RES1: return &probe_spi_res1;
+ case PROBE_SPI_RES2: return &probe_spi_res2;
+ case PROBE_SPI_SFDP: return &probe_spi_sfdp;
+ case PROBE_SPI_ST95: return &probe_spi_st95;
+ /* default: total function, 0 indicates no probe function set.
+ * We explicitly do not want a default catch-all case in the switch
+ * to ensure unhandled enum's are compiler warnings.
+ */
+ case NO_PROBE_FUNC: return NULL;
+ };
+
+ return NULL;
+}
+
+int probe_flash(struct registered_master *mst, int startchip, struct flashctx *flash, int force, const char *const chip_to_probe)
{
const struct flashchip *chip;
enum chipbustype buses_common;
@@ -1228,18 +1104,19 @@ int probe_flash(struct registered_master *mst, int startchip, struct flashctx *f
if (chip->bustype == BUS_SPI && !chip_to_probe && chip->spi_cmd_set != SPI25)
continue;
msg_gdbg("Probing for %s %s, %d kB: ", chip->vendor, chip->name, chip->total_size);
- if (!chip->probe && !force) {
+ probe_func_t *probe_func = lookup_probe_func_ptr(chip);
+ if (!probe_func && !force) {
msg_gdbg("failed! flashrom has no probe function for this flash chip.\n");
continue;
}
/* Start filling in the dynamic data. */
- flash->chip = calloc(1, sizeof(struct flashchip));
+ flash->chip = calloc(1, sizeof(*flash->chip));
if (!flash->chip) {
msg_gerr("Out of memory!\n");
- exit(1);
+ return -1;
}
- memcpy(flash->chip, chip, sizeof(struct flashchip));
+ *flash->chip = *chip;
flash->mst = mst;
if (map_flash(flash) != 0)
@@ -1251,7 +1128,11 @@ int probe_flash(struct registered_master *mst, int startchip, struct flashctx *f
if (force)
break;
- if (flash->chip->probe(flash) != 1)
+ if (probe_func == &probe_w29ee011)
+ if (!w29ee011_can_override(flash->chip->name, chip_to_probe))
+ goto notfound;
+
+ if (probe_func(flash) != 1)
goto notfound;
/* If this is the first chip found, accept it.
@@ -1300,36 +1181,26 @@ notfound:
if (!flash->chip)
return -1;
- /* Fill fallback layout covering the whole chip. */
- struct single_layout *const fallback = &flash->fallback_layout;
- fallback->base.entries = &fallback->entry;
- fallback->base.num_entries = 1;
- fallback->entry.start = 0;
- fallback->entry.end = flash->chip->total_size * 1024 - 1;
- fallback->entry.included = true;
- fallback->entry.name = strdup("complete flash");
- if (!fallback->entry.name) {
- msg_cerr("Failed to probe chip: %s\n", strerror(errno));
+ if (init_default_layout(flash) < 0)
return -1;
- }
tmp = flashbuses_to_text(flash->chip->bustype);
msg_cinfo("%s %s flash chip \"%s\" (%d kB, %s) ", force ? "Assuming" : "Found",
- flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp);
+ flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp ? tmp : "?");
free(tmp);
-#if CONFIG_INTERNAL == 1
- if (programmer_table[programmer].map_flash_region == physmap)
+ if (master_uses_physmap(mst))
msg_cinfo("mapped at physical address 0x%0*" PRIxPTR ".\n",
PRIxPTR_WIDTH, flash->physical_memory);
else
-#endif
- msg_cinfo("on %s.\n", programmer_table[programmer].name);
+ msg_cinfo("on %s.\n", programmer->name);
/* Flash registers may more likely not be mapped if the chip was forced.
* Lock info may be stored in registers, so avoid lock info printing. */
- if (!force)
- if (flash->chip->printlock)
- flash->chip->printlock(flash);
+ if (!force) {
+ printlockfunc_t *printlock = lookup_printlock_func_ptr(flash);
+ if (printlock)
+ printlock(flash);
+ }
/* Get out of the way for later runs. */
unmap_flash(flash);
@@ -1338,127 +1209,31 @@ notfound:
return chip - flashchips;
}
-int read_buf_from_file(unsigned char *buf, unsigned long size,
- const char *filename)
-{
-#ifdef __LIBPAYLOAD__
- msg_gerr("Error: No file I/O support in libpayload\n");
- return 1;
-#else
- int ret = 0;
-
- FILE *image;
- if ((image = fopen(filename, "rb")) == NULL) {
- msg_gerr("Error: opening file \"%s\" failed: %s\n", filename, strerror(errno));
- return 1;
- }
-
- struct stat image_stat;
- if (fstat(fileno(image), &image_stat) != 0) {
- msg_gerr("Error: getting metadata of file \"%s\" failed: %s\n", filename, strerror(errno));
- ret = 1;
- goto out;
- }
- if (image_stat.st_size != (intmax_t)size) {
- msg_gerr("Error: Image size (%jd B) doesn't match the flash chip's size (%lu B)!\n",
- (intmax_t)image_stat.st_size, size);
- ret = 1;
- goto out;
- }
-
- unsigned long numbytes = fread(buf, 1, size, image);
- if (numbytes != size) {
- msg_gerr("Error: Failed to read complete file. Got %ld bytes, "
- "wanted %ld!\n", numbytes, size);
- ret = 1;
- }
-out:
- (void)fclose(image);
- return ret;
-#endif
-}
-
-int write_buf_to_file(const unsigned char *buf, unsigned long size, const char *filename)
+/**
+ * @brief Reads the included layout regions into a buffer.
+ *
+ * If there is no layout set in the given flash context, the whole chip will
+ * be read.
+ *
+ * @param flashctx Flash context to be used.
+ * @param buffer Buffer of full chip size to read into.
+ * @return 0 on success,
+ * 1 if any read fails.
+ */
+static int read_by_layout(struct flashctx *const flashctx, uint8_t *const buffer)
{
-#ifdef __LIBPAYLOAD__
- msg_gerr("Error: No file I/O support in libpayload\n");
- return 1;
-#else
- FILE *image;
- int ret = 0;
-
- if (!filename) {
- msg_gerr("No filename specified.\n");
- return 1;
- }
- if ((image = fopen(filename, "wb")) == NULL) {
- msg_gerr("Error: opening file \"%s\" failed: %s\n", filename, strerror(errno));
- return 1;
- }
-
- unsigned long numbytes = fwrite(buf, 1, size, image);
- if (numbytes != size) {
- msg_gerr("Error: file %s could not be written completely.\n", filename);
- ret = 1;
- goto out;
- }
- if (fflush(image)) {
- msg_gerr("Error: flushing file \"%s\" failed: %s\n", filename, strerror(errno));
- ret = 1;
- }
- // Try to fsync() only regular files and if that function is available at all (e.g. not on MinGW).
-#if defined(_POSIX_FSYNC) && (_POSIX_FSYNC != -1)
- struct stat image_stat;
- if (fstat(fileno(image), &image_stat) != 0) {
- msg_gerr("Error: getting metadata of file \"%s\" failed: %s\n", filename, strerror(errno));
- ret = 1;
- goto out;
- }
- if (S_ISREG(image_stat.st_mode)) {
- if (fsync(fileno(image))) {
- msg_gerr("Error: fsyncing file \"%s\" failed: %s\n", filename, strerror(errno));
- ret = 1;
- }
- }
-#endif
-out:
- if (fclose(image)) {
- msg_gerr("Error: closing file \"%s\" failed: %s\n", filename, strerror(errno));
- ret = 1;
- }
- return ret;
-#endif
-}
+ const struct flashrom_layout *const layout = get_layout(flashctx);
+ const struct romentry *entry = NULL;
-static int read_by_layout(struct flashctx *, uint8_t *);
-int read_flash_to_file(struct flashctx *flash, const char *filename)
-{
- unsigned long size = flash->chip->total_size * 1024;
- unsigned char *buf = calloc(size, sizeof(unsigned char));
- int ret = 0;
+ while ((entry = layout_next_included(layout, entry))) {
+ const struct flash_region *region = &entry->region;
+ const chipoff_t region_start = region->start;
+ const chipsize_t region_len = region->end - region->start + 1;
- msg_cinfo("Reading flash... ");
- if (!buf) {
- msg_gerr("Memory allocation failed!\n");
- msg_cinfo("FAILED.\n");
- return 1;
- }
- if (!flash->chip->read) {
- msg_cerr("No read function available for this flash chip.\n");
- ret = 1;
- goto out_free;
- }
- if (read_by_layout(flash, buf)) {
- msg_cerr("Read operation failed!\n");
- ret = 1;
- goto out_free;
+ if (read_flash(flashctx, buffer + region_start, region_start, region_len))
+ return 1;
}
-
- ret = write_buf_to_file(buf, size, filename);
-out_free:
- free(buf);
- msg_cinfo("%s.\n", ret ? "FAILED" : "done");
- return ret;
+ return 0;
}
/* Even if an error is found, the function will keep going and check the rest. */
@@ -1466,10 +1241,12 @@ static int selfcheck_eraseblocks(const struct flashchip *chip)
{
int i, j, k;
int ret = 0;
+ unsigned int prev_eraseblock_count = chip->total_size * 1024;
for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
unsigned int done = 0;
struct block_eraser eraser = chip->block_erasers[k];
+ unsigned int curr_eraseblock_count = 0;
for (i = 0; i < NUM_ERASEREGIONS; i++) {
/* Blocks with zero size are bugs in flashchips.c. */
@@ -1492,6 +1269,7 @@ static int selfcheck_eraseblocks(const struct flashchip *chip)
}
done += eraser.eraseblocks[i].count *
eraser.eraseblocks[i].size;
+ curr_eraseblock_count += eraser.eraseblocks[i].count;
}
/* Empty eraseblock definition with erase function. */
if (!done && eraser.block_erase)
@@ -1523,61 +1301,17 @@ static int selfcheck_eraseblocks(const struct flashchip *chip)
ret = 1;
}
}
+ if (curr_eraseblock_count > prev_eraseblock_count) {
+ msg_gerr("ERROR: Flash chip %s erase function %i is not "
+ "in order. Please report a bug at flashrom@flashrom.org\n",
+ chip->name, k);
+ ret = 1;
+ }
+ prev_eraseblock_count = curr_eraseblock_count;
}
return ret;
}
-static int check_block_eraser(const struct flashctx *flash, int k, int log)
-{
- struct block_eraser eraser = flash->chip->block_erasers[k];
-
- if (!eraser.block_erase && !eraser.eraseblocks[0].count) {
- if (log)
- msg_cdbg("not defined. ");
- return 1;
- }
- if (!eraser.block_erase && eraser.eraseblocks[0].count) {
- if (log)
- msg_cdbg("eraseblock layout is known, but matching "
- "block erase function is not implemented. ");
- return 1;
- }
- if (eraser.block_erase && !eraser.eraseblocks[0].count) {
- if (log)
- msg_cdbg("block erase function found, but "
- "eraseblock layout is not defined. ");
- return 1;
- }
- // TODO: Once erase functions are annotated with allowed buses, check that as well.
- return 0;
-}
-
-/**
- * @brief Reads the included layout regions into a buffer.
- *
- * If there is no layout set in the given flash context, the whole chip will
- * be read.
- *
- * @param flashctx Flash context to be used.
- * @param buffer Buffer of full chip size to read into.
- * @return 0 on success,
- * 1 if any read fails.
- */
-static int read_by_layout(struct flashctx *const flashctx, uint8_t *const buffer)
-{
- const struct flashrom_layout *const layout = get_layout(flashctx);
- const struct romentry *entry = NULL;
-
- while ((entry = layout_next_included(layout, entry))) {
- const chipoff_t region_start = entry->start;
- const chipsize_t region_len = entry->end - entry->start + 1;
-
- if (flashctx->chip->read(flashctx, buffer + region_start, region_start, region_len))
- return 1;
- }
- return 0;
-}
-
typedef int (*erasefn_t)(struct flashctx *, unsigned int addr, unsigned int len);
/**
* @private
@@ -1601,11 +1335,12 @@ struct walk_info {
chipoff_t erase_end;
};
/* returns 0 on success, 1 to retry with another erase function, 2 for immediate abort */
-typedef int (*per_blockfn_t)(struct flashctx *, const struct walk_info *, erasefn_t);
+typedef int (*per_blockfn_t)(struct flashctx *, const struct walk_info *, erasefn_t, bool *);
static int walk_eraseblocks(struct flashctx *const flashctx,
struct walk_info *const info,
- const size_t erasefunction, const per_blockfn_t per_blockfn)
+ const size_t erasefunction, const per_blockfn_t per_blockfn,
+ bool *all_skipped)
{
int ret;
size_t i, j;
@@ -1630,9 +1365,10 @@ static int walk_eraseblocks(struct flashctx *const flashctx,
first = false;
else
msg_cdbg(", ");
- msg_cdbg("0x%06x-0x%06x:", info->erase_start, info->erase_end);
+ msg_cdbg("0x%06"PRIx32"-0x%06"PRIx32":", info->erase_start, info->erase_end);
- ret = per_blockfn(flashctx, info, eraser->block_erase);
+ erasefunc_t *erase_func = lookup_erase_func_ptr(eraser);
+ ret = per_blockfn(flashctx, info, erase_func, all_skipped);
if (ret)
return ret;
}
@@ -1644,17 +1380,18 @@ static int walk_eraseblocks(struct flashctx *const flashctx,
}
static int walk_by_layout(struct flashctx *const flashctx, struct walk_info *const info,
- const per_blockfn_t per_blockfn)
+ const per_blockfn_t per_blockfn, bool *all_skipped)
{
const struct flashrom_layout *const layout = get_layout(flashctx);
const struct romentry *entry = NULL;
- all_skipped = true;
+ *all_skipped = true;
msg_cinfo("Erasing and writing flash chip... ");
while ((entry = layout_next_included(layout, entry))) {
- info->region_start = entry->start;
- info->region_end = entry->end;
+ const struct flash_region *region = &entry->region;
+ info->region_start = region->start;
+ info->region_end = region->end;
size_t j;
int error = 1; /* retry as long as it's 1 */
@@ -1665,7 +1402,7 @@ static int walk_by_layout(struct flashctx *const flashctx, struct walk_info *con
if (check_block_eraser(flashctx, j, 1))
continue;
- error = walk_eraseblocks(flashctx, info, j, per_blockfn);
+ error = walk_eraseblocks(flashctx, info, j, per_blockfn, all_skipped);
if (error != 1)
break;
@@ -1689,14 +1426,15 @@ static int walk_by_layout(struct flashctx *const flashctx, struct walk_info *con
return 1;
}
}
- if (all_skipped)
+ if (*all_skipped)
msg_cinfo("\nWarning: Chip content is identical to the requested image.\n");
msg_cinfo("Erase/write done.\n");
return 0;
}
static int erase_block(struct flashctx *const flashctx,
- const struct walk_info *const info, const erasefn_t erasefn)
+ const struct walk_info *const info, const erasefn_t erasefn,
+ bool *all_skipped)
{
const unsigned int erase_len = info->erase_end + 1 - info->erase_start;
const bool region_unaligned = info->region_start > info->erase_start ||
@@ -1724,7 +1462,7 @@ static int erase_block(struct flashctx *const flashctx,
if (info->region_start > info->erase_start) {
const chipoff_t start = info->erase_start;
const chipsize_t len = info->region_start - info->erase_start;
- if (flashctx->chip->read(flashctx, backup_contents, start, len)) {
+ if (read_flash(flashctx, backup_contents, start, len)) {
msg_cerr("Can't read! Aborting.\n");
goto _free_ret;
}
@@ -1734,7 +1472,7 @@ static int erase_block(struct flashctx *const flashctx,
const chipoff_t start = info->region_end + 1;
const chipoff_t rel_start = start - info->erase_start; /* within this erase block */
const chipsize_t len = info->erase_end - info->region_end;
- if (flashctx->chip->read(flashctx, backup_contents + rel_start, start, len)) {
+ if (read_flash(flashctx, backup_contents + rel_start, start, len)) {
msg_cerr("Can't read! Aborting.\n");
goto _free_ret;
}
@@ -1742,16 +1480,42 @@ static int erase_block(struct flashctx *const flashctx,
}
ret = 1;
- all_skipped = false;
+ *all_skipped = false;
msg_cdbg("E");
- if (erasefn(flashctx, info->erase_start, erase_len))
- goto _free_ret;
- if (check_erased_range(flashctx, info->erase_start, erase_len)) {
- msg_cerr("ERASE FAILED!\n");
- goto _free_ret;
+
+ if (!flashctx->flags.skip_unwritable_regions) {
+ if (check_for_unwritable_regions(flashctx, info->erase_start, erase_len))
+ goto _free_ret;
}
+ unsigned int len;
+ for (unsigned int addr = info->erase_start; addr < info->erase_start + erase_len; addr += len) {
+ struct flash_region region;
+ get_flash_region(flashctx, addr, &region);
+
+ len = min(info->erase_start + erase_len, region.end) - addr;
+
+ if (region.write_prot) {
+ msg_gdbg("%s: cannot erase inside %s region (%#08"PRIx32"..%#08"PRIx32"), skipping range (%#08x..%#08x).\n",
+ __func__, region.name, region.start, region.end - 1, addr, addr + len - 1);
+ free(region.name);
+ continue;
+ }
+
+ msg_gdbg("%s: %s region (%#08"PRIx32"..%#08"PRIx32") is writable, erasing range (%#08x..%#08x).\n",
+ __func__, region.name, region.start, region.end - 1, addr, addr + len - 1);
+ free(region.name);
+
+ if (erasefn(flashctx, addr, len))
+ goto _free_ret;
+ if (check_erased_range(flashctx, addr, len)) {
+ msg_cerr("ERASE FAILED!\n");
+ goto _free_ret;
+ }
+ }
+
+
if (region_unaligned) {
unsigned int starthere = 0, lenhere = 0, writecount = 0;
/* get_next_write() sets starthere to a new value after the call. */
@@ -1760,7 +1524,7 @@ static int erase_block(struct flashctx *const flashctx,
if (!writecount++)
msg_cdbg("W");
/* Needs the partial write function signature. */
- if (flashctx->chip->write(flashctx, backup_contents + starthere,
+ if (write_flash(flashctx, backup_contents + starthere,
info->erase_start + starthere, lenhere))
goto _free_ret;
starthere += lenhere;
@@ -1782,18 +1546,69 @@ _free_ret:
* be erased.
*
* @param flashctx Flash context to be used.
- * @param buffer Buffer of full chip size to read into.
* @return 0 on success,
* 1 if all available erase functions failed.
*/
-static int erase_by_layout(struct flashctx *const flashctx)
+static int erase_by_layout_legacy(struct flashctx *const flashctx)
{
struct walk_info info = { 0 };
- return walk_by_layout(flashctx, &info, &erase_block);
+ bool all_skipped = true;
+ return walk_by_layout(flashctx, &info, &erase_block, &all_skipped);
+}
+
+static int erase_by_layout_new(struct flashctx *const flashctx)
+{
+ bool all_skipped = true;
+ const uint32_t flash_size = flashctx->chip->total_size * 1024;
+ uint8_t* curcontents = malloc(flash_size);
+ uint8_t* newcontents = malloc(flash_size);
+ struct erase_layout *erase_layout;
+ create_erase_layout(flashctx, &erase_layout);
+ int ret = 0;
+
+ //erase layout creation failed
+ if (!erase_layout) {
+ ret = 1;
+ goto _ret;
+ }
+
+ //not enough memory
+ if (!curcontents || !newcontents) {
+ ret = 1;
+ goto _ret;
+ }
+
+ memset(curcontents, ~ERASED_VALUE(flashctx), flash_size);
+ memset(newcontents, ERASED_VALUE(flashctx), flash_size);
+
+ const struct flashrom_layout *const flash_layout = get_layout(flashctx);
+ const struct romentry *entry = NULL;
+ while ((entry = layout_next_included(flash_layout, entry))) {
+ ret = erase_write(flashctx, entry->region.start, entry->region.end, curcontents, newcontents, erase_layout, &all_skipped);
+ if (ret) {
+ ret = 1;
+ msg_cerr("Erase Failed");
+ goto _ret;
+ }
+ }
+
+_ret:
+ free(curcontents);
+ free(newcontents);
+ free_erase_layout(erase_layout, count_usable_erasers(flashctx));
+ return ret;
+}
+
+static int erase_by_layout(struct flashctx *const flashctx)
+{
+ if (use_legacy_erase_path)
+ return erase_by_layout_legacy(flashctx);
+ return erase_by_layout_new(flashctx);
}
static int read_erase_write_block(struct flashctx *const flashctx,
- const struct walk_info *const info, const erasefn_t erasefn)
+ const struct walk_info *const info, const erasefn_t erasefn,
+ bool *all_skipped)
{
const chipsize_t erase_len = info->erase_end + 1 - info->erase_start;
const bool region_unaligned = info->region_start > info->erase_start ||
@@ -1822,7 +1637,7 @@ static int read_erase_write_block(struct flashctx *const flashctx,
if (info->region_start > info->erase_start) {
const chipoff_t start = info->erase_start;
const chipsize_t len = info->region_start - info->erase_start;
- if (flashctx->chip->read(flashctx, newc, start, len)) {
+ if (read_flash(flashctx, newc, start, len)) {
msg_cerr("Can't read! Aborting.\n");
goto _free_ret;
}
@@ -1833,7 +1648,7 @@ static int read_erase_write_block(struct flashctx *const flashctx,
const chipoff_t start = info->region_end + 1;
const chipoff_t rel_start = start - info->erase_start; /* within this erase block */
const chipsize_t len = info->erase_end - info->region_end;
- if (flashctx->chip->read(flashctx, newc + rel_start, start, len)) {
+ if (read_flash(flashctx, newc + rel_start, start, len)) {
msg_cerr("Can't read! Aborting.\n");
goto _free_ret;
}
@@ -1851,7 +1666,7 @@ static int read_erase_write_block(struct flashctx *const flashctx,
const uint8_t erased_value = ERASED_VALUE(flashctx);
if (!(flashctx->chip->feature_bits & FEATURE_NO_ERASE) &&
need_erase(curcontents, newcontents, erase_len, flashctx->chip->gran, erased_value)) {
- if (erase_block(flashctx, info, erasefn))
+ if (erase_block(flashctx, info, erasefn, all_skipped))
goto _free_ret;
/* Erase was successful. Adjust curcontents. */
memset(curcontents, erased_value, erase_len);
@@ -1865,7 +1680,7 @@ static int read_erase_write_block(struct flashctx *const flashctx,
if (!writecount++)
msg_cdbg("W");
/* Needs the partial write function signature. */
- if (flashctx->chip->write(flashctx, newcontents + starthere,
+ if (write_flash(flashctx, newcontents + starthere,
info->erase_start + starthere, lenhere))
goto _free_ret;
starthere += lenhere;
@@ -1874,7 +1689,7 @@ static int read_erase_write_block(struct flashctx *const flashctx,
if (skipped)
msg_cdbg("S");
else
- all_skipped = false;
+ *all_skipped = false;
/* Update curcontents, other regions with overlapping erase blocks
might rely on this. */
@@ -1899,13 +1714,58 @@ _free_ret:
* @return 0 on success,
* 1 if anything has gone wrong.
*/
-static int write_by_layout(struct flashctx *const flashctx,
- void *const curcontents, const void *const newcontents)
+static int write_by_layout_legacy(struct flashctx *const flashctx,
+ void *const curcontents, const void *const newcontents,
+ bool *all_skipped)
{
struct walk_info info;
info.curcontents = curcontents;
info.newcontents = newcontents;
- return walk_by_layout(flashctx, &info, read_erase_write_block);
+ return walk_by_layout(flashctx, &info, read_erase_write_block, all_skipped);
+}
+
+static int write_by_layout_new(struct flashctx *const flashctx,
+ void *const curcontents, const void *const newcontents,
+ bool *all_skipped)
+{
+ const int erasefn_count = count_usable_erasers(flashctx);
+ int ret = 1;
+
+ const struct flashrom_layout *const flash_layout = get_layout(flashctx);
+ struct erase_layout *erase_layout;
+ create_erase_layout(flashctx, &erase_layout);
+
+ if (!flash_layout) {
+ goto _ret;
+ }
+ if (!erase_layout) {
+ goto _ret;
+ }
+
+ const struct romentry *entry = NULL;
+ while ((entry = layout_next_included(flash_layout, entry))) {
+ ret = erase_write(flashctx, entry->region.start,
+ entry->region.end,
+ curcontents,
+ (uint8_t *)newcontents,
+ erase_layout, all_skipped);
+ if (ret) {
+ msg_cerr("Write Failed!");
+ goto _ret;
+ }
+ }
+_ret:
+ free_erase_layout(erase_layout, erasefn_count);
+ return ret;
+}
+
+static int write_by_layout(struct flashctx *const flashctx,
+ uint8_t *const curcontents, const uint8_t *const newcontents,
+ bool *all_skipped)
+{
+ if (use_legacy_erase_path)
+ return write_by_layout_legacy(flashctx, curcontents, newcontents, all_skipped);
+ return write_by_layout_new(flashctx, curcontents, newcontents, all_skipped);
}
/**
@@ -1915,23 +1775,26 @@ static int write_by_layout(struct flashctx *const flashctx,
* contents will be compared.
*
* @param flashctx Flash context to be used.
+ * @param layout Flash layout information.
* @param curcontents A buffer of full chip size to read current chip contents into.
* @param newcontents The new image to compare to.
* @return 0 on success,
* 1 if reading failed,
* 3 if the contents don't match.
*/
-static int verify_by_layout(struct flashctx *const flashctx,
- void *const curcontents, const uint8_t *const newcontents)
+static int verify_by_layout(
+ struct flashctx *const flashctx,
+ const struct flashrom_layout *const layout,
+ void *const curcontents, const uint8_t *const newcontents)
{
- const struct flashrom_layout *const layout = get_layout(flashctx);
const struct romentry *entry = NULL;
while ((entry = layout_next_included(layout, entry))) {
- const chipoff_t region_start = entry->start;
- const chipsize_t region_len = entry->end - entry->start + 1;
+ const struct flash_region *region = &entry->region;
+ const chipoff_t region_start = region->start;
+ const chipsize_t region_len = region->end - region->start + 1;
- if (flashctx->chip->read(flashctx, curcontents + region_start, region_start, region_len))
+ if (read_flash(flashctx, curcontents + region_start, region_start, region_len))
return 1;
if (compare_range(newcontents + region_start, curcontents + region_start,
region_start, region_len))
@@ -1940,37 +1803,42 @@ static int verify_by_layout(struct flashctx *const flashctx,
return 0;
}
+static bool is_internal_programmer()
+{
+#if CONFIG_INTERNAL == 1
+ return programmer == &programmer_internal;
+#else
+ return false;
+#endif
+}
+
static void nonfatal_help_message(void)
{
msg_gerr("Good, writing to the flash chip apparently didn't do anything.\n");
-#if CONFIG_INTERNAL == 1
- if (programmer == PROGRAMMER_INTERNAL)
+ if (is_internal_programmer())
msg_gerr("This means we have to add special support for your board, programmer or flash\n"
- "chip. Please report this on IRC at chat.freenode.net (channel #flashrom) or\n"
- "mail flashrom@flashrom.org, thanks!\n"
+ "chip. Please report this to the mailing list at flashrom@flashrom.org or on\n"
+ "IRC (see https://www.flashrom.org/Contact for details), thanks!\n"
"-------------------------------------------------------------------------------\n"
"You may now reboot or simply leave the machine running.\n");
else
-#endif
msg_gerr("Please check the connections (especially those to write protection pins) between\n"
"the programmer and the flash chip. If you think the error is caused by flashrom\n"
- "please report this on IRC at chat.freenode.net (channel #flashrom) or\n"
- "mail flashrom@flashrom.org, thanks!\n");
+ "please report this to the mailing list at flashrom@flashrom.org or on IRC (see\n"
+ "https://www.flashrom.org/Contact for details), thanks!\n");
}
-static void emergency_help_message(void)
+void emergency_help_message(void)
{
msg_gerr("Your flash chip is in an unknown state.\n");
-#if CONFIG_INTERNAL == 1
- if (programmer == PROGRAMMER_INTERNAL)
- msg_gerr("Get help on IRC at chat.freenode.net (channel #flashrom) or\n"
- "mail flashrom@flashrom.org with the subject \"FAILED: <your board name>\"!\n"
+ if (is_internal_programmer())
+ msg_gerr("Get help on IRC (see https://www.flashrom.org/Contact) or mail\n"
+ "flashrom@flashrom.org with the subject \"FAILED: <your board name>\"!"
"-------------------------------------------------------------------------------\n"
"DO NOT REBOOT OR POWEROFF!\n");
else
-#endif
- msg_gerr("Please report this on IRC at chat.freenode.net (channel #flashrom) or\n"
- "mail flashrom@flashrom.org, thanks!\n");
+ msg_gerr("Please report this to the mailing list at flashrom@flashrom.org or\n"
+ "on IRC (see https://www.flashrom.org/Contact for details), thanks!\n");
}
void list_programmers_linebreak(int startcol, int cols, int paren)
@@ -1978,11 +1846,11 @@ void list_programmers_linebreak(int startcol, int cols, int paren)
const char *pname;
int pnamelen;
int remaining = 0, firstline = 1;
- enum programmer p;
+ size_t p;
int i;
- for (p = 0; p < PROGRAMMER_INVALID; p++) {
- pname = programmer_table[p].name;
+ for (p = 0; p < programmer_table_size; p++) {
+ pname = programmer_table[p]->name;
pnamelen = strlen(pname);
if (remaining - pnamelen - 2 < 0) {
if (firstline)
@@ -2002,7 +1870,7 @@ void list_programmers_linebreak(int startcol, int cols, int paren)
}
msg_ginfo("%s", pname);
remaining -= pnamelen;
- if (p < PROGRAMMER_INVALID - 1) {
+ if (p < programmer_table_size - 1) {
msg_ginfo(",");
remaining--;
} else {
@@ -2012,147 +1880,44 @@ void list_programmers_linebreak(int startcol, int cols, int paren)
}
}
-static void print_sysinfo(void)
-{
-#if IS_WINDOWS
- SYSTEM_INFO si;
- OSVERSIONINFOEX osvi;
-
- memset(&si, 0, sizeof(SYSTEM_INFO));
- memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
- msg_ginfo(" on Windows");
- /* Tell Windows which version of the structure we want. */
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
- if (GetVersionEx((OSVERSIONINFO*) &osvi))
- msg_ginfo(" %lu.%lu", osvi.dwMajorVersion, osvi.dwMinorVersion);
- else
- msg_ginfo(" unknown version");
- GetSystemInfo(&si);
- switch (si.wProcessorArchitecture) {
- case PROCESSOR_ARCHITECTURE_AMD64:
- msg_ginfo(" (x86_64)");
- break;
- case PROCESSOR_ARCHITECTURE_INTEL:
- msg_ginfo(" (x86)");
- break;
- default:
- msg_ginfo(" (unknown arch)");
- break;
- }
-#elif HAVE_UTSNAME == 1
- struct utsname osinfo;
-
- uname(&osinfo);
- msg_ginfo(" on %s %s (%s)", osinfo.sysname, osinfo.release,
- osinfo.machine);
-#else
- msg_ginfo(" on unknown machine");
-#endif
-}
-
-void print_buildinfo(void)
-{
- msg_gdbg("flashrom was built with");
-#if NEED_PCI == 1
-#ifdef PCILIB_VERSION
- msg_gdbg(" libpci %s,", PCILIB_VERSION);
-#else
- msg_gdbg(" unknown PCI library,");
-#endif
-#endif
-#ifdef __clang__
- msg_gdbg(" LLVM Clang");
-#ifdef __clang_version__
- msg_gdbg(" %s,", __clang_version__);
-#else
- msg_gdbg(" unknown version (before r102686),");
-#endif
-#elif defined(__GNUC__)
- msg_gdbg(" GCC");
-#ifdef __VERSION__
- msg_gdbg(" %s,", __VERSION__);
-#else
- msg_gdbg(" unknown version,");
-#endif
-#else
- msg_gdbg(" unknown compiler,");
-#endif
-#if defined (__FLASHROM_LITTLE_ENDIAN__)
- msg_gdbg(" little endian");
-#elif defined (__FLASHROM_BIG_ENDIAN__)
- msg_gdbg(" big endian");
-#else
-#error Endianness could not be determined
-#endif
- msg_gdbg("\n");
-}
-
-void print_version(void)
-{
- msg_ginfo("flashrom %s", flashrom_version);
- print_sysinfo();
- msg_ginfo("\n");
-}
-
-void print_banner(void)
-{
- msg_ginfo("flashrom is free software, get the source code at "
- "https://flashrom.org\n");
- msg_ginfo("\n");
-}
-
int selfcheck(void)
{
unsigned int i;
int ret = 0;
- /* Safety check. Instead of aborting after the first error, check
- * if more errors exist.
- */
- if (ARRAY_SIZE(programmer_table) - 1 != PROGRAMMER_INVALID) {
- msg_gerr("Programmer table miscompilation!\n");
- ret = 1;
- }
- for (i = 0; i < PROGRAMMER_INVALID; i++) {
- const struct programmer_entry p = programmer_table[i];
- if (p.name == NULL) {
+ for (i = 0; i < programmer_table_size; i++) {
+ const struct programmer_entry *const p = programmer_table[i];
+ if (p == NULL) {
+ msg_gerr("Programmer with index %d is NULL instead of a valid pointer!\n", i);
+ ret = 1;
+ continue;
+ }
+ if (p->name == NULL) {
msg_gerr("All programmers need a valid name, but the one with index %d does not!\n", i);
ret = 1;
/* This might hide other problems with this programmer, but allows for better error
* messages below without jumping through hoops. */
continue;
}
- switch (p.type) {
+ switch (p->type) {
case USB:
case PCI:
case OTHER:
- if (p.devs.note == NULL) {
- if (strcmp("internal", p.name) == 0)
+ if (p->devs.note == NULL) {
+ if (strcmp("internal", p->name) == 0)
break; /* This one has its device list stored separately. */
msg_gerr("Programmer %s has neither a device list nor a textual description!\n",
- p.name);
+ p->name);
ret = 1;
}
break;
default:
- msg_gerr("Programmer %s does not have a valid type set!\n", p.name);
+ msg_gerr("Programmer %s does not have a valid type set!\n", p->name);
ret = 1;
break;
}
- if (p.init == NULL) {
- msg_gerr("Programmer %s does not have a valid init function!\n", p.name);
- ret = 1;
- }
- if (p.delay == NULL) {
- msg_gerr("Programmer %s does not have a valid delay function!\n", p.name);
- ret = 1;
- }
- if (p.map_flash_region == NULL) {
- msg_gerr("Programmer %s does not have a valid map_flash_region function!\n", p.name);
- ret = 1;
- }
- if (p.unmap_flash_region == NULL) {
- msg_gerr("Programmer %s does not have a valid unmap_flash_region function!\n", p.name);
+ if (p->init == NULL) {
+ msg_gerr("Programmer %s does not have a valid init function!\n", p->name);
ret = 1;
}
}
@@ -2189,8 +1954,8 @@ int selfcheck(void)
return ret;
}
-/* FIXME: This function signature needs to be improved once doit() has a better
- * function signature.
+/* FIXME: This function signature needs to be improved once prepare_flash_access()
+ * has a better function signature.
*/
static int chip_safety_check(const struct flashctx *flash, int force,
int read_it, int write_it, int erase_it, int verify_it)
@@ -2216,7 +1981,7 @@ static int chip_safety_check(const struct flashctx *flash, int force,
return 1;
msg_cerr("Continuing anyway.\n");
}
- if (!chip->read) {
+ if (!lookup_read_func_ptr(chip)) {
msg_cerr("flashrom has no read function for this "
"flash chip.\n");
return 1;
@@ -2251,7 +2016,7 @@ static int chip_safety_check(const struct flashctx *flash, int force,
return 1;
msg_cerr("Continuing anyway.\n");
}
- if (!chip->write) {
+ if (!lookup_write_func_ptr(chip)) {
msg_cerr("flashrom has no write function for this "
"flash chip.\n");
return 1;
@@ -2260,6 +2025,78 @@ static int chip_safety_check(const struct flashctx *flash, int force,
return 0;
}
+static int restore_flash_wp(struct flashctx *const flash, void *data)
+{
+ struct flashrom_wp_cfg *wp_cfg = data;
+ enum flashrom_wp_result ret = flashrom_wp_write_cfg(flash, wp_cfg);
+ flashrom_wp_cfg_release(wp_cfg);
+
+ return (ret == FLASHROM_WP_OK) ? 0 : -1;
+}
+
+static int save_initial_flash_wp(struct flashctx *const flash)
+{
+ struct flashrom_wp_cfg *initial_wp_cfg;
+ if (flashrom_wp_cfg_new(&initial_wp_cfg) != FLASHROM_WP_OK)
+ return -1;
+
+ if (flashrom_wp_read_cfg(initial_wp_cfg, flash) != FLASHROM_WP_OK) {
+ flashrom_wp_cfg_release(initial_wp_cfg);
+ return -1;
+ }
+
+ if (register_chip_restore(restore_flash_wp, flash, initial_wp_cfg)) {
+ flashrom_wp_cfg_release(initial_wp_cfg);
+ return -1;
+ }
+ return 0;
+}
+
+static int unlock_flash_wp(struct flashctx *const flash,
+ const bool write_it, const bool erase_it)
+
+{
+ int ret = 0;
+
+ /* WP only disables write protection, so only use WP to unlock
+ * for write/erase operations.
+ *
+ * For read/verify operations, we still call the chip's unlock
+ * function, which may disable read locks if the chip has them.
+ */
+ if (!write_it && !erase_it) {
+ msg_cdbg("Skipping writeprotect-based unlocking for read/verify operations.\n");
+ return -1;
+ }
+
+ /* Save original WP state to be restored later */
+ if (save_initial_flash_wp(flash)) {
+ ret = -1;
+ goto warn_out;
+ }
+
+ /* Disable WP */
+ struct flashrom_wp_cfg *unlocked_wp_cfg;
+ if (flashrom_wp_cfg_new(&unlocked_wp_cfg) != FLASHROM_WP_OK) {
+ ret = -1;
+ goto warn_out;
+ }
+
+ flashrom_wp_set_range(unlocked_wp_cfg, 0, 0);
+ flashrom_wp_set_mode(unlocked_wp_cfg, FLASHROM_WP_MODE_DISABLED);
+ if (flashrom_wp_write_cfg(flash, unlocked_wp_cfg) != FLASHROM_WP_OK) {
+ ret = -1;
+ }
+
+ flashrom_wp_cfg_release(unlocked_wp_cfg);
+
+warn_out:
+ if (ret)
+ msg_cerr("Failed to unlock flash status reg with wp support.\n");
+
+ return ret;
+}
+
int prepare_flash_access(struct flashctx *const flash,
const bool read_it, const bool write_it,
const bool erase_it, const bool verify_it)
@@ -2269,7 +2106,7 @@ int prepare_flash_access(struct flashctx *const flash,
return 1;
}
- if (flash->layout == get_global_layout() && normalize_romentries(flash)) {
+ if (layout_sanity_checks(flash)) {
msg_cerr("Requested regions can not be handled. Aborting.\n");
return 1;
}
@@ -2277,14 +2114,28 @@ int prepare_flash_access(struct flashctx *const flash,
if (map_flash(flash) != 0)
return 1;
- /* Given the existence of read locks, we want to unlock for read,
- erase and write. */
- if (flash->chip->unlock)
- flash->chip->unlock(flash);
+ /* Initialize chip_restore_fn_count before chip unlock calls. */
+ flash->chip_restore_fn_count = 0;
+
+ int ret = 1;
+ if (flash->chip->decode_range != NO_DECODE_RANGE_FUNC ||
+ (flash->mst->buses_supported & BUS_PROG && flash->mst->opaque.wp_write_cfg)) {
+ ret = unlock_flash_wp(flash, write_it, erase_it);
+ }
+ /*
+ * Fall back to chip unlock function if we haven't already successfully
+ * unlocked using WP (e.g. WP unlocking failed, chip had no WP support,
+ * WP was skipped for read/verify ops).
+ *
+ * Given the existence of read locks, we want to unlock for read,
+ * erase, write, and verify.
+ */
+ blockprotect_func_t *bp_func = lookup_blockprotect_func_ptr(flash->chip);
+ if (ret && bp_func)
+ bp_func(flash);
flash->address_high_byte = -1;
flash->in_4ba_mode = false;
- flash->chip_restore_fn_count = 0;
/* Be careful about 4BA chips and broken masters */
if (flash->chip->total_size > 16 * 1024 && spi_master_no_4ba_modes(flash)) {
@@ -2297,8 +2148,7 @@ int prepare_flash_access(struct flashctx *const flash,
}
/* Enable/disable 4-byte addressing mode if flash chip supports it */
- if (flash->chip->feature_bits & (FEATURE_4BA_ENTER | FEATURE_4BA_ENTER_WREN | FEATURE_4BA_ENTER_EAR7)) {
- int ret;
+ if (spi_chip_4ba(flash)) {
if (spi_master_4ba(flash))
ret = spi_enter_4ba(flash);
else
@@ -2318,20 +2168,6 @@ void finalize_flash_access(struct flashctx *const flash)
unmap_flash(flash);
}
-/**
- * @addtogroup flashrom-flash
- * @{
- */
-
-/**
- * @brief Erase the specified ROM chip.
- *
- * If a layout is set in the given flash context, only included regions
- * will be erased.
- *
- * @param flashctx The context of the flash chip to erase.
- * @return 0 on success.
- */
int flashrom_flash_erase(struct flashctx *const flashctx)
{
if (prepare_flash_access(flashctx, false, false, true, false))
@@ -2344,26 +2180,6 @@ int flashrom_flash_erase(struct flashctx *const flashctx)
return ret;
}
-/** @} */ /* end flashrom-flash */
-
-/**
- * @defgroup flashrom-ops Operations
- * @{
- */
-
-/**
- * @brief Read the current image from the specified ROM chip.
- *
- * If a layout is set in the specified flash context, only included regions
- * will be read.
- *
- * @param flashctx The context of the flash chip.
- * @param buffer Target buffer to write image to.
- * @param buffer_len Size of target buffer in bytes.
- * @return 0 on success,
- * 2 if buffer_len is too short for the flash chip's contents,
- * or 1 on any other failure.
- */
int flashrom_image_read(struct flashctx *const flashctx, void *const buffer, const size_t buffer_len)
{
const size_t flash_size = flashctx->chip->total_size * 1024;
@@ -2398,12 +2214,13 @@ static void combine_image_by_layout(const struct flashctx *const flashctx,
chipoff_t start = 0;
while ((included = layout_next_included_region(layout, start))) {
- if (included->start > start) {
+ const struct flash_region *region = &included->region;
+ if (region->start > start) {
/* copy everything up to the start of this included region */
- memcpy(newcontents + start, oldcontents + start, included->start - start);
+ memcpy(newcontents + start, oldcontents + start, region->start - start);
}
/* skip this included region */
- start = included->end + 1;
+ start = region->end + 1;
if (start == 0)
return;
}
@@ -2413,28 +2230,14 @@ static void combine_image_by_layout(const struct flashctx *const flashctx,
memcpy(newcontents + start, oldcontents + start, copy_len);
}
-/**
- * @brief Write the specified image to the ROM chip.
- *
- * If a layout is set in the specified flash context, only erase blocks
- * containing included regions will be touched.
- *
- * @param flashctx The context of the flash chip.
- * @param buffer Source buffer to read image from (may be altered for full verification).
- * @param buffer_len Size of source buffer in bytes.
- * @param refbuffer If given, assume flash chip contains same data as `refbuffer`.
- * @return 0 on success,
- * 4 if buffer_len doesn't match the size of the flash chip,
- * 3 if write was tried but nothing has changed,
- * 2 if write failed and flash contents changed,
- * or 1 on any other failure.
- */
int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, const size_t buffer_len,
const void *const refbuffer)
{
const size_t flash_size = flashctx->chip->total_size * 1024;
const bool verify_all = flashctx->flags.verify_whole_chip;
const bool verify = flashctx->flags.verify_after_write;
+ const struct flashrom_layout *const verify_layout =
+ verify_all ? get_default_layout(flashctx) : get_layout(flashctx);
if (buffer_len != flash_size)
return 4;
@@ -2453,7 +2256,7 @@ int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, co
}
#if CONFIG_INTERNAL == 1
- if (programmer == PROGRAMMER_INTERNAL && cb_check_image(newcontents, flash_size) < 0) {
+ if (is_internal_programmer() && cb_check_image(newcontents, flash_size) < 0) {
if (flashctx->flags.force_boardmismatch) {
msg_pinfo("Proceeding anyway because user forced us to.\n");
} else {
@@ -2483,7 +2286,7 @@ int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, co
*/
msg_cinfo("Reading old flash chip contents... ");
if (verify_all) {
- if (flashctx->chip->read(flashctx, oldcontents, 0, flash_size)) {
+ if (read_flash(flashctx, oldcontents, 0, flash_size)) {
msg_cinfo("FAILED.\n");
goto _finalize_ret;
}
@@ -2497,13 +2300,15 @@ int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, co
msg_cinfo("done.\n");
}
- if (write_by_layout(flashctx, curcontents, newcontents)) {
+ bool all_skipped = true;
+
+ if (write_by_layout(flashctx, curcontents, newcontents, &all_skipped)) {
msg_cerr("Uh oh. Erase/write failed. ");
ret = 2;
if (verify_all) {
msg_cerr("Checking if anything has changed.\n");
msg_cinfo("Reading current flash chip contents... ");
- if (!flashctx->chip->read(flashctx, curcontents, 0, flash_size)) {
+ if (!read_flash(flashctx, curcontents, 0, flash_size)) {
msg_cinfo("done.\n");
if (!memcmp(oldcontents, curcontents, flash_size)) {
nonfatal_help_message();
@@ -2523,19 +2328,14 @@ int flashrom_image_write(struct flashctx *const flashctx, void *const buffer, co
/* Verify only if we actually changed something. */
if (verify && !all_skipped) {
- const struct flashrom_layout *const layout_bak = flashctx->layout;
-
msg_cinfo("Verifying flash... ");
/* Work around chips which need some time to calm down. */
- programmer_delay(1000*1000);
+ programmer_delay(flashctx, 1000*1000);
- if (verify_all) {
+ if (verify_all)
combine_image_by_layout(flashctx, newcontents, oldcontents);
- flashctx->layout = NULL;
- }
- ret = verify_by_layout(flashctx, curcontents, newcontents);
- flashctx->layout = layout_bak;
+ ret = verify_by_layout(flashctx, verify_layout, curcontents, newcontents);
/* If we tried to write, and verification now fails, we
might have an emergency situation. */
if (ret)
@@ -2555,22 +2355,9 @@ _free_ret:
return ret;
}
-/**
- * @brief Verify the ROM chip's contents with the specified image.
- *
- * If a layout is set in the specified flash context, only included regions
- * will be verified.
- *
- * @param flashctx The context of the flash chip.
- * @param buffer Source buffer to verify with.
- * @param buffer_len Size of source buffer in bytes.
- * @return 0 on success,
- * 3 if the chip's contents don't match,
- * 2 if buffer_len doesn't match the size of the flash chip,
- * or 1 on any other failure.
- */
int flashrom_image_verify(struct flashctx *const flashctx, const void *const buffer, const size_t buffer_len)
{
+ const struct flashrom_layout *const layout = get_layout(flashctx);
const size_t flash_size = flashctx->chip->total_size * 1024;
if (buffer_len != flash_size)
@@ -2589,7 +2376,7 @@ int flashrom_image_verify(struct flashctx *const flashctx, const void *const buf
goto _free_ret;
msg_cinfo("Verifying flash... ");
- ret = verify_by_layout(flashctx, curcontents, newcontents);
+ ret = verify_by_layout(flashctx, layout, curcontents, newcontents);
if (!ret)
msg_cinfo("VERIFIED.\n");
@@ -2598,84 +2385,3 @@ _free_ret:
free(curcontents);
return ret;
}
-
-/** @} */ /* end flashrom-ops */
-
-int do_read(struct flashctx *const flash, const char *const filename)
-{
- if (prepare_flash_access(flash, true, false, false, false))
- return 1;
-
- const int ret = read_flash_to_file(flash, filename);
-
- finalize_flash_access(flash);
-
- return ret;
-}
-
-int do_erase(struct flashctx *const flash)
-{
- const int ret = flashrom_flash_erase(flash);
-
- /*
- * FIXME: Do we really want the scary warning if erase failed?
- * After all, after erase the chip is either blank or partially
- * blank or it has the old contents. A blank chip won't boot,
- * so if the user wanted erase and reboots afterwards, the user
- * knows very well that booting won't work.
- */
- if (ret)
- emergency_help_message();
-
- return ret;
-}
-
-int do_write(struct flashctx *const flash, const char *const filename, const char *const referencefile)
-{
- const size_t flash_size = flash->chip->total_size * 1024;
- int ret = 1;
-
- uint8_t *const newcontents = malloc(flash_size);
- uint8_t *const refcontents = referencefile ? malloc(flash_size) : NULL;
-
- if (!newcontents || (referencefile && !refcontents)) {
- msg_gerr("Out of memory!\n");
- goto _free_ret;
- }
-
- if (read_buf_from_file(newcontents, flash_size, filename))
- goto _free_ret;
-
- if (referencefile) {
- if (read_buf_from_file(refcontents, flash_size, referencefile))
- goto _free_ret;
- }
-
- ret = flashrom_image_write(flash, newcontents, flash_size, refcontents);
-
-_free_ret:
- free(refcontents);
- free(newcontents);
- return ret;
-}
-
-int do_verify(struct flashctx *const flash, const char *const filename)
-{
- const size_t flash_size = flash->chip->total_size * 1024;
- int ret = 1;
-
- uint8_t *const newcontents = malloc(flash_size);
- if (!newcontents) {
- msg_gerr("Out of memory!\n");
- goto _free_ret;
- }
-
- if (read_buf_from_file(newcontents, flash_size, filename))
- goto _free_ret;
-
- ret = flashrom_image_verify(flash, newcontents, flash_size);
-
-_free_ret:
- free(newcontents);
- return ret;
-}
diff --git a/fmap.c b/fmap.c
index 2f34a5ccf..7f5df2b5b 100644
--- a/fmap.c
+++ b/fmap.c
@@ -35,6 +35,7 @@
*/
#include <ctype.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@@ -91,14 +92,17 @@ static int is_valid_fmap(const struct fmap *fmap)
* -1 to indicate that fmap was not found
* -2 to indicate fmap is truncated or exceeds buffer + len
*/
-static off_t fmap_lsearch(const uint8_t *buf, size_t len)
+static ssize_t fmap_lsearch(const uint8_t *buf, size_t len)
{
- off_t offset;
- bool fmap_found = 0;
+ ssize_t offset;
+ bool fmap_found = false;
- for (offset = 0; offset <= (off_t)(len - sizeof(struct fmap)); offset++) {
+ if (len < sizeof(struct fmap))
+ return -1;
+
+ for (offset = 0; offset <= (ssize_t)(len - sizeof(struct fmap)); offset++) {
if (is_valid_fmap((struct fmap *)&buf[offset])) {
- fmap_found = 1;
+ fmap_found = true;
break;
}
}
@@ -128,7 +132,7 @@ static off_t fmap_lsearch(const uint8_t *buf, size_t len)
*/
int fmap_read_from_buffer(struct fmap **fmap_out, const uint8_t *const buf, size_t len)
{
- off_t offset = fmap_lsearch(buf, len);
+ ssize_t offset = fmap_lsearch(buf, len);
if (offset < 0) {
msg_gdbg("Unable to find fmap in provided buffer.\n");
return 2;
@@ -163,7 +167,7 @@ static int fmap_lsearch_rom(struct fmap **fmap_out,
goto _finalize_ret;
}
- ret = flashctx->chip->read(flashctx, buf + rom_offset, rom_offset, len);
+ ret = read_flash(flashctx, buf + rom_offset, rom_offset, len);
if (ret) {
msg_pdbg("Cannot read ROM contents.\n");
goto _free_ret;
@@ -181,7 +185,9 @@ static int fmap_bsearch_rom(struct fmap **fmap_out, struct flashctx *const flash
size_t rom_offset, size_t len, size_t min_stride)
{
size_t stride, fmap_len = 0;
- int ret = 1, fmap_found = 0, check_offset_0 = 1;
+ int ret = 1;
+ bool fmap_found = false;
+ bool check_offset_0 = true;
struct fmap *fmap;
const unsigned int chip_size = flashctx->chip->total_size * 1024;
const int sig_len = strlen(FMAP_SIGNATURE);
@@ -195,7 +201,7 @@ static int fmap_bsearch_rom(struct fmap **fmap_out, struct flashctx *const flash
if (prepare_flash_access(flashctx, true, false, false, false))
return 1;
- fmap = malloc(sizeof(struct fmap));
+ fmap = malloc(sizeof(*fmap));
if (!fmap) {
msg_gerr("Out of memory.\n");
goto _free_ret;
@@ -222,11 +228,11 @@ static int fmap_bsearch_rom(struct fmap **fmap_out, struct flashctx *const flash
continue;
if (offset == 0 && !check_offset_0)
continue;
- check_offset_0 = 0;
+ check_offset_0 = false;
/* Read errors are considered non-fatal since we may
* encounter locked regions and want to continue. */
- if (flashctx->chip->read(flashctx, (uint8_t *)fmap, offset, sig_len)) {
+ if (read_flash(flashctx, (uint8_t *)fmap, offset, sig_len)) {
/*
* Print in verbose mode only to avoid excessive
* messages for benign errors. Subsequent error
@@ -239,7 +245,7 @@ static int fmap_bsearch_rom(struct fmap **fmap_out, struct flashctx *const flash
if (memcmp(fmap, FMAP_SIGNATURE, sig_len) != 0)
continue;
- if (flashctx->chip->read(flashctx, (uint8_t *)fmap + sig_len,
+ if (read_flash(flashctx, (uint8_t *)fmap + sig_len,
offset + sig_len, sizeof(*fmap) - sig_len)) {
msg_cerr("Cannot read %zu bytes at offset %06zx\n",
sizeof(*fmap) - sig_len, offset + sig_len);
@@ -248,7 +254,7 @@ static int fmap_bsearch_rom(struct fmap **fmap_out, struct flashctx *const flash
if (is_valid_fmap(fmap)) {
msg_gdbg("fmap found at offset 0x%06zx\n", offset);
- fmap_found = 1;
+ fmap_found = true;
break;
}
msg_gerr("fmap signature found at %zu but header is invalid.\n", offset);
@@ -271,7 +277,7 @@ static int fmap_bsearch_rom(struct fmap **fmap_out, struct flashctx *const flash
goto _free_ret;
}
- if (flashctx->chip->read(flashctx, (uint8_t *)fmap + sizeof(*fmap),
+ if (read_flash(flashctx, (uint8_t *)fmap + sizeof(*fmap),
offset + sizeof(*fmap), fmap_len - sizeof(*fmap))) {
msg_cerr("Cannot read %zu bytes at offset %06zx\n",
fmap_len - sizeof(*fmap), offset + sizeof(*fmap));
diff --git a/ft2232_spi.c b/ft2232_spi.c
index 65ff4490b..7d7283bc9 100644
--- a/ft2232_spi.c
+++ b/ft2232_spi.c
@@ -14,8 +14,7 @@
* GNU General Public License for more details.
*/
-#if CONFIG_FT2232_SPI == 1
-
+#include <stdbool.h>
#include <stdio.h>
#include <strings.h>
#include <string.h>
@@ -27,7 +26,7 @@
#include <ftdi.h>
/* This is not defined in libftdi.h <0.20 (c7e4c09e68cfa6f5e112334aa1b3bb23401c8dc7 to be exact).
- * Some tests indicate that his is the only change that it is needed to support the FT232H in flashrom. */
+ * Some tests indicate that this is the only change that it is needed to support the FT232H in flashrom. */
#if !defined(HAVE_FT232H)
#define TYPE_232H 6
#endif
@@ -38,8 +37,10 @@
#define FTDI_FT2232H_PID 0x6010
#define FTDI_FT4232H_PID 0x6011
#define FTDI_FT232H_PID 0x6014
+#define FTDI_FT4233H_PID 0x6041
#define TIAO_TUMPA_PID 0x8a98
#define TIAO_TUMPA_LITE_PID 0x8a99
+#define KT_LINK_PID 0xbbe2
#define AMONTEC_JTAGKEY_PID 0xCFF8
#define GOEPEL_VID 0x096C
@@ -59,12 +60,14 @@
#define GOOGLE_SERVO_V2_PID0 0x5002
#define GOOGLE_SERVO_V2_PID1 0x5003
-const struct dev_entry devs_ft2232spi[] = {
+static const struct dev_entry devs_ft2232spi[] = {
{FTDI_VID, FTDI_FT2232H_PID, OK, "FTDI", "FT2232H"},
{FTDI_VID, FTDI_FT4232H_PID, OK, "FTDI", "FT4232H"},
{FTDI_VID, FTDI_FT232H_PID, OK, "FTDI", "FT232H"},
+ {FTDI_VID, FTDI_FT4233H_PID, OK, "FTDI", "FT4233H"},
{FTDI_VID, TIAO_TUMPA_PID, OK, "TIAO", "USB Multi-Protocol Adapter"},
{FTDI_VID, TIAO_TUMPA_LITE_PID, OK, "TIAO", "USB Multi-Protocol Adapter Lite"},
+ {FTDI_VID, KT_LINK_PID, OK, "Kristech", "KT-LINK"},
{FTDI_VID, AMONTEC_JTAGKEY_PID, OK, "Amontec", "JTAGkey"},
{GOEPEL_VID, GOEPEL_PICOTAP_PID, OK, "GOEPEL", "PicoTAP"},
{GOOGLE_VID, GOOGLE_SERVO_PID, OK, "Google", "Servo"},
@@ -79,13 +82,26 @@ const struct dev_entry devs_ft2232spi[] = {
{0},
};
+#define FTDI_HW_BUFFER_SIZE 4096 /* in bytes */
+
#define DEFAULT_DIVISOR 2
#define BITMODE_BITBANG_NORMAL 1
#define BITMODE_BITBANG_SPI 2
-/* The variables cs_bits and pindir store the values for the "set data bits low byte" MPSSE command that
- * sets the initial state and the direction of the I/O pins. The pin offsets are as follows:
+/*
+ * The variables `cs_bits` and `pindir` store the values for the
+ * "set data bits low byte" MPSSE command that sets the initial
+ * state and the direction of the I/O pins. `cs_bits` pins default
+ * to high and will be toggled during SPI transactions. All other
+ * output pins will be kept low all the time. For some programmers,
+ * some reserved GPIOL* pins are used as outputs. Free GPIOL* pins
+ * are configured as inputs, while it's possible to use them either
+ * as generic gpios or as additional CS# signal(s) through the
+ * parameter(s) `gpiolX`. On exit, all pins will be reconfigured
+ * as inputs.
+ *
+ * The pin offsets are as follows:
* TCK/SK is bit 0.
* TDI/DO is bit 1.
* TDO/DI is bit 2.
@@ -95,16 +111,17 @@ const struct dev_entry devs_ft2232spi[] = {
* GPIOL2 is bit 6.
* GPIOL3 is bit 7.
*
- * The pin signal direction bit offsets follow the same order; 0 means that
- * pin at the matching bit index is an input, 1 means pin is an output.
- *
- * The default values (set below) are used for most devices:
- * value: 0x08 CS=high, DI=low, DO=low, SK=low
+ * The default values (set below in ft2232_spi_init) are used for
+ * most devices:
+ * value: 0x08 CS=high, DI=low, DO=low, SK=low
* dir: 0x0b CS=output, DI=input, DO=output, SK=output
*/
-static uint8_t cs_bits = 0x08;
-static uint8_t pindir = 0x0b;
-static struct ftdi_context ftdic_context;
+struct ft2232_data {
+ uint8_t cs_bits;
+ uint8_t aux_bits;
+ uint8_t pindir;
+ struct ftdi_context ftdic_context;
+};
static const char *get_ft2232_devicename(int ft2232_vid, int ft2232_type)
{
@@ -159,27 +176,135 @@ static int get_buf(struct ftdi_context *ftdic, const unsigned char *buf,
return 0;
}
-static int ft2232_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr);
+static int ft2232_shutdown(void *data)
+{
+ struct ft2232_data *spi_data = (struct ft2232_data *) data;
+ struct ftdi_context *ftdic = &spi_data->ftdic_context;
+ unsigned char buf[3];
+ int ret = 0;
+
+ msg_pdbg("Releasing I/Os\n");
+ buf[0] = SET_BITS_LOW;
+ buf[1] = 0; /* Output byte ignored */
+ buf[2] = 0; /* Pin direction: all inputs */
+ if (send_buf(ftdic, buf, 3)) {
+ msg_perr("Unable to set pins back to inputs.\n");
+ ret = 1;
+ }
+
+ const int close_ret = ftdi_usb_close(ftdic);
+ if (close_ret < 0) {
+ msg_perr("Unable to close FTDI device: %d (%s)\n", close_ret,
+ ftdi_get_error_string(ftdic));
+ ret = 1;
+ }
+
+ free(spi_data);
+ return ret;
+}
+
+static bool ft2232_spi_command_fits(const struct spi_command *cmd, size_t buffer_size)
+{
+ const size_t cmd_len = 3; /* same length for any ft2232 command */
+ return
+ /* commands for CS# assertion and de-assertion: */
+ cmd_len + cmd_len
+ /* commands for either a write, a read or both: */
+ + (cmd->writecnt && cmd->readcnt ? cmd_len + cmd_len : cmd_len)
+ /* payload (only writecnt; readcnt concerns another buffer): */
+ + cmd->writecnt
+ <= buffer_size;
+}
+
+/* Returns 0 upon success, a negative number upon errors. */
+static int ft2232_spi_send_multicommand(const struct flashctx *flash, struct spi_command *cmds)
+{
+ struct ft2232_data *spi_data = flash->mst->spi.data;
+ struct ftdi_context *ftdic = &spi_data->ftdic_context;
+ static unsigned char buf[FTDI_HW_BUFFER_SIZE];
+ size_t i = 0;
+ int ret = 0;
+
+ /*
+ * Minimize FTDI-calls by packing as many commands as possible together.
+ */
+ for (; cmds->writecnt || cmds->readcnt; cmds++) {
+
+ if (cmds->writecnt > 65536 || cmds->readcnt > 65536)
+ return SPI_INVALID_LENGTH;
+
+ if (!ft2232_spi_command_fits(cmds, FTDI_HW_BUFFER_SIZE - i)) {
+ msg_perr("Command does not fit\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ msg_pspew("Assert CS#\n");
+ buf[i++] = SET_BITS_LOW;
+ /* assert CS# pins, keep aux_bits, all other output pins stay low */
+ buf[i++] = spi_data->aux_bits;
+ buf[i++] = spi_data->pindir;
+
+ /* WREN, OP(PROGRAM, ERASE), ADDR, DATA */
+ if (cmds->writecnt) {
+ buf[i++] = MPSSE_DO_WRITE | MPSSE_WRITE_NEG;
+ buf[i++] = (cmds->writecnt - 1) & 0xff;
+ buf[i++] = ((cmds->writecnt - 1) >> 8) & 0xff;
+ memcpy(buf + i, cmds->writearr, cmds->writecnt);
+ i += cmds->writecnt;
+ }
+
+ /* An optional read command */
+ if (cmds->readcnt) {
+ buf[i++] = MPSSE_DO_READ;
+ buf[i++] = (cmds->readcnt - 1) & 0xff;
+ buf[i++] = ((cmds->readcnt - 1) >> 8) & 0xff;
+ }
+
+ /* Add final de-assert CS# */
+ msg_pspew("De-assert CS#\n");
+ buf[i++] = SET_BITS_LOW;
+ buf[i++] = spi_data->cs_bits | spi_data->aux_bits;
+ buf[i++] = spi_data->pindir;
+
+ /* continue if there is no read-cmd and further cmds exist */
+ if (!cmds->readcnt &&
+ ((cmds + 1)->writecnt || (cmds + 1)->readcnt) &&
+ ft2232_spi_command_fits((cmds + 1), FTDI_HW_BUFFER_SIZE - i)) {
+ continue;
+ }
+
+ ret = send_buf(ftdic, buf, i);
+ i = 0;
+ if (ret) {
+ msg_perr("send_buf failed: %i\n", ret);
+ break;
+ }
+
+ if (cmds->readcnt) {
+ ret = get_buf(ftdic, cmds->readarr, cmds->readcnt);
+ if (ret) {
+ msg_perr("get_buf failed: %i\n", ret);
+ break;
+ }
+ }
+ }
+ return ret ? -1 : 0;
+}
static const struct spi_master spi_master_ft2232 = {
.features = SPI_MASTER_4BA,
.max_data_read = 64 * 1024,
.max_data_write = 256,
- .command = ft2232_spi_send_command,
- .multicommand = default_spi_send_multicommand,
+ .multicommand = ft2232_spi_send_multicommand,
.read = default_spi_read,
.write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .shutdown = ft2232_shutdown,
};
/* Returns 0 upon success, a negative number upon errors. */
-int ft2232_spi_init(void)
+static int ft2232_spi_init(const struct programmer_cfg *cfg)
{
int ret = 0;
- struct ftdi_context *ftdic = &ftdic_context;
unsigned char buf[512];
int ft2232_vid = FTDI_VID;
int ft2232_type = FTDI_FT4232H_PID;
@@ -190,7 +315,7 @@ int ft2232_spi_init(void)
* but the non-H chips can only run at 12 MHz. We disable the divide-by-5
* prescaler on 'H' chips so they run at 60MHz.
*/
- uint8_t clock_5x = 1;
+ bool clock_5x = true;
/* In addition to the prescaler mentioned above there is also another
* configurable one on all versions of the chips. Its divisor div can be
* set by a 16 bit value x according to the following formula:
@@ -202,10 +327,18 @@ int ft2232_spi_init(void)
*/
uint32_t divisor = DEFAULT_DIVISOR;
int f;
- char *arg;
+ char *arg, *arg2;
double mpsse_clk;
- arg = extract_programmer_param("type");
+ uint8_t cs_bits = 0x08;
+ uint8_t aux_bits = 0x00;
+ uint8_t pindir = 0x0b;
+ uint8_t aux_bits_high = 0x00;
+ uint8_t pindir_high = 0x00;
+ struct ftdi_context ftdic;
+ struct ft2232_data *spi_data;
+
+ arg = extract_programmer_param_str(cfg, "type");
if (arg) {
if (!strcasecmp(arg, "2232H")) {
ft2232_type = FTDI_FT2232H_PID;
@@ -216,6 +349,9 @@ int ft2232_spi_init(void)
} else if (!strcasecmp(arg, "232H")) {
ft2232_type = FTDI_FT232H_PID;
channel_count = 1;
+ } else if (!strcasecmp(arg, "4233H")) {
+ ft2232_type = FTDI_FT4233H_PID;
+ channel_count = 4;
} else if (!strcasecmp(arg, "jtagkey")) {
ft2232_type = AMONTEC_JTAGKEY_PID;
channel_count = 2;
@@ -287,6 +423,17 @@ int ft2232_spi_init(void)
/* Flyswatter and Flyswatter-2 require GPIO bits 0x80
* and 0x40 to be driven low to enable output buffers */
pindir = 0xcb;
+ } else if (!strcasecmp(arg, "kt-link")) {
+ ft2232_type = KT_LINK_PID;
+ /* port B is used as uart */
+ channel_count = 1;
+ /* Set GPIOL1 output high - route TMS and TDO through multiplexers */
+ aux_bits = 0x20;
+ pindir = 0x2b;
+ /* Set GPIOH4 output low - enable TMS output buffer */
+ /* Set GPIOH5 output low - enable TDI output buffer */
+ /* Set GPIOH6 output low - enable TCK output buffer */
+ pindir_high = 0x70;
} else {
msg_perr("Error: Invalid device type specified.\n");
free(arg);
@@ -295,7 +442,10 @@ int ft2232_spi_init(void)
}
free(arg);
- arg = extract_programmer_param("port");
+ /* Remember reserved pins before pindir gets modified. */
+ const uint8_t rsv_bits = pindir & 0xf0;
+
+ arg = extract_programmer_param_str(cfg, "port");
if (arg) {
switch (toupper((unsigned char)*arg)) {
case 'A':
@@ -328,7 +478,7 @@ int ft2232_spi_init(void)
}
free(arg);
- arg = extract_programmer_param("divisor");
+ arg = extract_programmer_param_str(cfg, "divisor");
if (arg && strlen(arg)) {
unsigned int temp = 0;
char *endptr;
@@ -343,27 +493,96 @@ int ft2232_spi_init(void)
}
free(arg);
- /* Allows setting multiple GPIOL states, for example: csgpiol=012 */
- arg = extract_programmer_param("csgpiol");
+ bool csgpiol_set = false;
+ arg = extract_programmer_param_str(cfg, "csgpiol");
if (arg) {
- unsigned int ngpios = strlen(arg);
- for (unsigned int i = 0; i <= ngpios; i++) {
- int temp = arg[i] - '0';
- if (ngpios == 0 || (ngpios != i && (temp < 0 || temp > 3))) {
- msg_perr("Error: Invalid GPIOLs specified: \"%s\".\n"
- "Valid values are numbers between 0 and 3. "
- "Multiple GPIOLs can be specified.\n", arg);
- free(arg);
- return -2;
- } else {
- unsigned int pin = temp + 4;
- cs_bits |= 1 << pin;
- pindir |= 1 << pin;
- }
+ csgpiol_set = true;
+ msg_pwarn("Deprecation warning: `csgpiol` is deprecated and will be removed "
+ "in the future.\nUse `gpiolX=C` instead.\n");
+
+ char *endptr;
+ unsigned int temp = strtoul(arg, &endptr, 10);
+ if (*endptr || endptr == arg || temp > 3) {
+ msg_perr("Error: Invalid GPIOL specified: \"%s\".\n"
+ "Valid values are between 0 and 3.\n", arg);
+ free(arg);
+ return -2;
}
+
+ unsigned int pin = temp + 4;
+ if (rsv_bits & 1 << pin) {
+ msg_perr("Error: Invalid GPIOL specified: \"%s\".\n"
+ "The pin is reserved on this programmer.\n",
+ arg);
+ free(arg);
+ return -2;
+ }
+
+ cs_bits |= 1 << pin;
+ pindir |= 1 << pin;
}
free(arg);
+ /* gpiolX */
+ for (int pin = 0; pin < 4; pin++) {
+ char gpiol_param[7];
+ snprintf(gpiol_param, sizeof(gpiol_param), "gpiol%d", pin);
+ arg = extract_programmer_param_str(cfg, gpiol_param);
+
+ if (!arg)
+ continue;
+
+ if (csgpiol_set) {
+ msg_perr("Error: `csgpiol` and `gpiolX` are mutually exclusive.\n"
+ "Since `csgpiol` is deprecated and will be removed in the "
+ "future, use of `gpiolX=C` is recommended.\n");
+ free(arg);
+ return -2;
+ }
+
+ uint8_t bit = 1 << (pin + 4);
+ if (rsv_bits & bit) {
+ msg_perr("Error: Invalid GPIOL specified: \"gpiol%d=%s\".\n"
+ "Pin GPIOL%i is reserved on this programmer.\n",
+ pin, arg, pin);
+ free(arg);
+ return -2;
+ }
+
+ if (strlen(arg) != 1)
+ goto format_error;
+
+ switch (toupper(arg[0])) {
+ case 'H':
+ aux_bits |= bit;
+ pindir |= bit;
+ break;
+ case 'L':
+ pindir |= bit;
+ break;
+ case 'C':
+ cs_bits |= bit;
+ pindir |= bit;
+ break;
+ default:
+ goto format_error;
+ }
+
+ free(arg);
+ continue;
+
+format_error:
+ msg_perr("Error: Invalid GPIOL specified: \"gpiol%d=%s\".\n"
+ "Valid values are H, L and C.\n"
+ " H - Set GPIOL output high\n"
+ " L - Set GPIOL output low\n"
+ " C - Use GPIOL as additional CS# output\n",
+ pin, arg);
+
+ free(arg);
+ return -2;
+ }
+
msg_pdbg("Using device type %s %s ",
get_ft2232_vendorname(ft2232_vid, ft2232_type),
get_ft2232_devicename(ft2232_vid, ft2232_type));
@@ -372,50 +591,50 @@ int ft2232_spi_init(void)
(ft2232_interface == INTERFACE_B) ? "B" :
(ft2232_interface == INTERFACE_C) ? "C" : "D");
- if (ftdi_init(ftdic) < 0) {
+ if (ftdi_init(&ftdic) < 0) {
msg_perr("ftdi_init failed.\n");
return -3;
}
- if (ftdi_set_interface(ftdic, ft2232_interface) < 0) {
- msg_perr("Unable to select channel (%s).\n", ftdi_get_error_string(ftdic));
+ if (ftdi_set_interface(&ftdic, ft2232_interface) < 0) {
+ msg_perr("Unable to select channel (%s).\n", ftdi_get_error_string(&ftdic));
}
- arg = extract_programmer_param("serial");
- f = ftdi_usb_open_desc(ftdic, ft2232_vid, ft2232_type, NULL, arg);
+ arg = extract_programmer_param_str(cfg, "serial");
+ arg2 = extract_programmer_param_str(cfg, "description");
+
+ f = ftdi_usb_open_desc(&ftdic, ft2232_vid, ft2232_type, arg2, arg);
+
free(arg);
+ free(arg2);
if (f < 0 && f != -5) {
msg_perr("Unable to open FTDI device: %d (%s)\n", f,
- ftdi_get_error_string(ftdic));
+ ftdi_get_error_string(&ftdic));
return -4;
}
- if (ftdic->type != TYPE_2232H && ftdic->type != TYPE_4232H && ftdic->type != TYPE_232H) {
- msg_pdbg("FTDI chip type %d is not high-speed.\n", ftdic->type);
- clock_5x = 0;
- }
-
- if (ftdi_usb_reset(ftdic) < 0) {
- msg_perr("Unable to reset FTDI device (%s).\n", ftdi_get_error_string(ftdic));
+ if (ftdic.type != TYPE_2232H && ftdic.type != TYPE_4232H && ftdic.type != TYPE_232H) {
+ msg_pdbg("FTDI chip type %d is not high-speed.\n", ftdic.type);
+ clock_5x = false;
}
- if (ftdi_set_latency_timer(ftdic, 2) < 0) {
- msg_perr("Unable to set latency timer (%s).\n", ftdi_get_error_string(ftdic));
+ if (ftdi_usb_reset(&ftdic) < 0) {
+ msg_perr("Unable to reset FTDI device (%s).\n", ftdi_get_error_string(&ftdic));
}
- if (ftdi_write_data_set_chunksize(ftdic, 270)) {
- msg_perr("Unable to set chunk size (%s).\n", ftdi_get_error_string(ftdic));
+ if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
+ msg_perr("Unable to set latency timer (%s).\n", ftdi_get_error_string(&ftdic));
}
- if (ftdi_set_bitmode(ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) {
- msg_perr("Unable to set bitmode to SPI (%s).\n", ftdi_get_error_string(ftdic));
+ if (ftdi_set_bitmode(&ftdic, 0x00, BITMODE_BITBANG_SPI) < 0) {
+ msg_perr("Unable to set bitmode to SPI (%s).\n", ftdi_get_error_string(&ftdic));
}
if (clock_5x) {
msg_pdbg("Disable divide-by-5 front stage\n");
buf[0] = DIS_DIV_5;
- if (send_buf(ftdic, buf, 1)) {
+ if (send_buf(&ftdic, buf, 1)) {
ret = -5;
goto ftdi_err;
}
@@ -428,7 +647,7 @@ int ft2232_spi_init(void)
buf[0] = TCK_DIVISOR;
buf[1] = (divisor / 2 - 1) & 0xff;
buf[2] = ((divisor / 2 - 1) >> 8) & 0xff;
- if (send_buf(ftdic, buf, 3)) {
+ if (send_buf(&ftdic, buf, 3)) {
ret = -6;
goto ftdi_err;
}
@@ -439,118 +658,54 @@ int ft2232_spi_init(void)
/* Disconnect TDI/DO to TDO/DI for loopback. */
msg_pdbg("No loopback of TDI/DO TDO/DI\n");
buf[0] = LOOPBACK_END;
- if (send_buf(ftdic, buf, 1)) {
+ if (send_buf(&ftdic, buf, 1)) {
ret = -7;
goto ftdi_err;
}
msg_pdbg("Set data bits\n");
buf[0] = SET_BITS_LOW;
- buf[1] = cs_bits;
+ buf[1] = cs_bits | aux_bits;
buf[2] = pindir;
- if (send_buf(ftdic, buf, 3)) {
+ if (send_buf(&ftdic, buf, 3)) {
ret = -8;
goto ftdi_err;
}
- register_spi_master(&spi_master_ft2232);
-
- return 0;
-
-ftdi_err:
- if ((f = ftdi_usb_close(ftdic)) < 0) {
- msg_perr("Unable to close FTDI device: %d (%s)\n", f,
- ftdi_get_error_string(ftdic));
- }
- return ret;
-}
-
-/* Returns 0 upon success, a negative number upon errors. */
-static int ft2232_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
-{
- struct ftdi_context *ftdic = &ftdic_context;
- static unsigned char *buf = NULL;
- /* failed is special. We use bitwise ops, but it is essentially bool. */
- int i = 0, ret = 0, failed = 0;
- size_t bufsize;
- static size_t oldbufsize = 0;
-
- if (writecnt > 65536 || readcnt > 65536)
- return SPI_INVALID_LENGTH;
-
- /* buf is not used for the response from the chip. */
- bufsize = max(writecnt + 9, 260 + 9);
- /* Never shrink. realloc() calls are expensive. */
- if (!buf || bufsize > oldbufsize) {
- buf = realloc(buf, bufsize);
- if (!buf) {
- msg_perr("Out of memory!\n");
- /* TODO: What to do with buf? */
- return SPI_GENERIC_ERROR;
+ if (pindir_high) {
+ msg_pdbg("Set data bits HighByte\n");
+ buf[0] = SET_BITS_HIGH;
+ buf[1] = aux_bits_high;
+ buf[2] = pindir_high;
+ if (send_buf(&ftdic, buf, 3)) {
+ ret = -8;
+ goto ftdi_err;
}
- oldbufsize = bufsize;
}
- /*
- * Minimize USB transfers by packing as many commands as possible
- * together. If we're not expecting to read, we can assert CS#, write,
- * and deassert CS# all in one shot. If reading, we do three separate
- * operations.
- */
- msg_pspew("Assert CS#\n");
- buf[i++] = SET_BITS_LOW;
- buf[i++] = ~ 0x08 & cs_bits; /* assert CS (3rd) bit only */
- buf[i++] = pindir;
-
- if (writecnt) {
- buf[i++] = MPSSE_DO_WRITE | MPSSE_WRITE_NEG;
- buf[i++] = (writecnt - 1) & 0xff;
- buf[i++] = ((writecnt - 1) >> 8) & 0xff;
- memcpy(buf + i, writearr, writecnt);
- i += writecnt;
+ spi_data = calloc(1, sizeof(*spi_data));
+ if (!spi_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ return SPI_GENERIC_ERROR;
}
+ spi_data->cs_bits = cs_bits;
+ spi_data->aux_bits = aux_bits;
+ spi_data->pindir = pindir;
+ spi_data->ftdic_context = ftdic;
- /*
- * Optionally terminate this batch of commands with a
- * read command, then do the fetch of the results.
- */
- if (readcnt) {
- buf[i++] = MPSSE_DO_READ;
- buf[i++] = (readcnt - 1) & 0xff;
- buf[i++] = ((readcnt - 1) >> 8) & 0xff;
- ret = send_buf(ftdic, buf, i);
- failed = ret;
- /* We can't abort here, we still have to deassert CS#. */
- if (ret)
- msg_perr("send_buf failed before read: %i\n", ret);
- i = 0;
- if (ret == 0) {
- /*
- * FIXME: This is unreliable. There's no guarantee that
- * we read the response directly after sending the read
- * command. We may be scheduled out etc.
- */
- ret = get_buf(ftdic, readarr, readcnt);
- failed |= ret;
- /* We can't abort here either. */
- if (ret)
- msg_perr("get_buf failed: %i\n", ret);
- }
- }
+ return register_spi_master(&spi_master_ft2232, spi_data);
- msg_pspew("De-assert CS#\n");
- buf[i++] = SET_BITS_LOW;
- buf[i++] = cs_bits;
- buf[i++] = pindir;
- ret = send_buf(ftdic, buf, i);
- failed |= ret;
- if (ret)
- msg_perr("send_buf failed at end: %i\n", ret);
-
- return failed ? -1 : 0;
+ftdi_err:
+ if ((f = ftdi_usb_close(&ftdic)) < 0) {
+ msg_perr("Unable to close FTDI device: %d (%s)\n", f,
+ ftdi_get_error_string(&ftdic));
+ }
+ return ret;
}
-#endif
+const struct programmer_entry programmer_ft2232_spi = {
+ .name = "ft2232_spi",
+ .type = USB,
+ .devs.dev = devs_ft2232spi,
+ .init = ft2232_spi_init,
+};
diff --git a/gfxnvidia.c b/gfxnvidia.c
index d8ea4d683..080c88546 100644
--- a/gfxnvidia.c
+++ b/gfxnvidia.c
@@ -14,11 +14,13 @@
* GNU General Public License for more details.
*/
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_NVIDIA 0x10de
@@ -28,9 +30,16 @@
#define GFXNVIDIA_MEMMAP_MASK ((1 << 17) - 1)
#define GFXNVIDIA_MEMMAP_SIZE (16 * 1024 * 1024)
-static uint8_t *nvidia_bar;
+#define REG_FLASH_ACCESS 0x50
+#define BIT_FLASH_ACCESS BIT(0)
-const struct dev_entry gfx_nvidia[] = {
+struct gfxnvidia_data {
+ struct pci_dev *dev;
+ uint8_t *bar;
+ uint32_t flash_access;
+};
+
+static const struct dev_entry gfx_nvidia[] = {
{0x10de, 0x0010, NT, "NVIDIA", "Mutara V08 [NV2]" },
{0x10de, 0x0018, NT, "NVIDIA", "RIVA 128" },
{0x10de, 0x0020, NT, "NVIDIA", "RIVA TNT" },
@@ -59,29 +68,45 @@ const struct dev_entry gfx_nvidia[] = {
};
static void gfxnvidia_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr);
+ chipaddr addr)
+{
+ const struct gfxnvidia_data *data = flash->mst->par.data;
+
+ pci_mmio_writeb(val, data->bar + (addr & GFXNVIDIA_MEMMAP_MASK));
+}
+
static uint8_t gfxnvidia_chip_readb(const struct flashctx *flash,
- const chipaddr addr);
+ const chipaddr addr)
+{
+ const struct gfxnvidia_data *data = flash->mst->par.data;
+
+ return pci_mmio_readb(data->bar + (addr & GFXNVIDIA_MEMMAP_MASK));
+}
+
+static int gfxnvidia_shutdown(void *par_data)
+{
+ struct gfxnvidia_data *data = par_data;
+
+ /* Restore original flash interface access state. */
+ pci_write_long(data->dev, REG_FLASH_ACCESS, data->flash_access);
+
+ free(par_data);
+ return 0;
+}
+
static const struct par_master par_master_gfxnvidia = {
- .chip_readb = gfxnvidia_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = gfxnvidia_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
+ .chip_readb = gfxnvidia_chip_readb,
+ .chip_writeb = gfxnvidia_chip_writeb,
+ .shutdown = gfxnvidia_shutdown,
};
-int gfxnvidia_init(void)
+static int gfxnvidia_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
uint32_t reg32;
+ uint8_t *bar;
- if (rget_io_perms())
- return 1;
-
- dev = pcidev_init(gfx_nvidia, PCI_BASE_ADDRESS_0);
+ dev = pcidev_init(cfg, gfx_nvidia, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -90,32 +115,33 @@ int gfxnvidia_init(void)
return 1;
io_base_addr += 0x300000;
- msg_pinfo("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr);
+ msg_pinfo("Detected NVIDIA I/O base address: 0x%"PRIx32".\n", io_base_addr);
+
+ bar = rphysmap("NVIDIA", io_base_addr, GFXNVIDIA_MEMMAP_SIZE);
+ if (bar == ERROR_PTR)
+ return 1;
- nvidia_bar = rphysmap("NVIDIA", io_base_addr, GFXNVIDIA_MEMMAP_SIZE);
- if (nvidia_bar == ERROR_PTR)
+ struct gfxnvidia_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
return 1;
+ }
+ data->dev = dev;
+ data->bar = bar;
/* Allow access to flash interface (will disable screen). */
- reg32 = pci_read_long(dev, 0x50);
- reg32 &= ~(1 << 0);
- rpci_write_long(dev, 0x50, reg32);
+ data->flash_access = pci_read_long(dev, REG_FLASH_ACCESS);
+ reg32 = data->flash_access & ~BIT_FLASH_ACCESS;
+ pci_write_long(dev, REG_FLASH_ACCESS, reg32);
/* Write/erase doesn't work. */
- programmer_may_write = 0;
- register_par_master(&par_master_gfxnvidia, BUS_PARALLEL);
-
- return 0;
+ programmer_may_write = false;
+ return register_par_master(&par_master_gfxnvidia, BUS_PARALLEL, data);
}
-static void gfxnvidia_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- pci_mmio_writeb(val, nvidia_bar + (addr & GFXNVIDIA_MEMMAP_MASK));
-}
-
-static uint8_t gfxnvidia_chip_readb(const struct flashctx *flash,
- const chipaddr addr)
-{
- return pci_mmio_readb(nvidia_bar + (addr & GFXNVIDIA_MEMMAP_MASK));
-}
+const struct programmer_entry programmer_gfxnvidia = {
+ .name = "gfxnvidia",
+ .type = PCI,
+ .devs.dev = gfx_nvidia,
+ .init = gfxnvidia_init,
+};
diff --git a/helpers.c b/helpers.c
index c83cd2cb0..5b47b68c6 100644
--- a/helpers.c
+++ b/helpers.c
@@ -25,7 +25,7 @@
uint32_t address_to_bits(uint32_t addr)
{
unsigned int lzb = 0;
- while (((1 << (31 - lzb)) & ~addr) != 0)
+ while (((1u << (31 - lzb)) & ~addr) != 0)
lzb++;
return 32 - lzb;
}
@@ -106,15 +106,16 @@ char* strtok_r(char *str, const char *delim, char **nextp)
/* strndup is a POSIX function not present in MinGW */
char *strndup(const char *src, size_t maxlen)
{
- if (strlen(src) > maxlen) {
- char *retbuf;
- if ((retbuf = malloc(1 + maxlen)) != NULL) {
- memcpy(retbuf, src, maxlen);
- retbuf[maxlen] = '\0';
- }
- return retbuf;
+ char *retbuf;
+ size_t len;
+ for (len = 0; len < maxlen; len++)
+ if (src[len] == '\0')
+ break;
+ if ((retbuf = malloc(1 + len)) != NULL) {
+ memcpy(retbuf, src, len);
+ retbuf[len] = '\0';
}
- return strdup(src);
+ return retbuf;
}
#endif
diff --git a/helpers_fileio.c b/helpers_fileio.c
new file mode 100644
index 000000000..cb7675db2
--- /dev/null
+++ b/helpers_fileio.c
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009-2010 Carl-Daniel Hailfinger
+ * Copyright (C) 2013 Stefan Tauner
+ *
+ * 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 <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifndef __LIBPAYLOAD__
+#include <fcntl.h>
+#include <sys/stat.h>
+#endif
+
+#include "flash.h"
+
+int read_buf_from_file(unsigned char *buf, unsigned long size,
+ const char *filename)
+{
+#ifdef __LIBPAYLOAD__
+ msg_gerr("Error: No file I/O support in libpayload\n");
+ return 1;
+#else
+ int ret = 0;
+
+ FILE *image;
+ if (!strcmp(filename, "-"))
+ image = fdopen(fileno(stdin), "rb");
+ else
+ image = fopen(filename, "rb");
+ if (image == NULL) {
+ msg_gerr("Error: opening file \"%s\" failed: %s\n", filename, strerror(errno));
+ return 1;
+ }
+
+ struct stat image_stat;
+ if (fstat(fileno(image), &image_stat) != 0) {
+ msg_gerr("Error: getting metadata of file \"%s\" failed: %s\n", filename, strerror(errno));
+ ret = 1;
+ goto out;
+ }
+ if ((image_stat.st_size != (intmax_t)size) && strcmp(filename, "-")) {
+ msg_gerr("Error: Image size (%jd B) doesn't match the expected size (%lu B)!\n",
+ (intmax_t)image_stat.st_size, size);
+ ret = 1;
+ goto out;
+ }
+
+ unsigned long numbytes = fread(buf, 1, size, image);
+ if (numbytes != size) {
+ msg_gerr("Error: Failed to read complete file. Got %ld bytes, "
+ "wanted %ld!\n", numbytes, size);
+ ret = 1;
+ }
+out:
+ (void)fclose(image);
+ return ret;
+#endif
+}
+
+/**
+ * @brief Writes passed data buffer into a file
+ *
+ * @param buf Buffer with data to write
+ * @param size Size of buffer
+ * @param filename File path to write to
+ * @return 0 on success
+ */
+int write_buf_to_file(const unsigned char *buf, unsigned long size, const char *filename)
+{
+#ifdef __LIBPAYLOAD__
+ msg_gerr("Error: No file I/O support in libpayload\n");
+ return 1;
+#else
+ FILE *image;
+ int ret = 0;
+
+ if (!filename) {
+ msg_gerr("No filename specified.\n");
+ return 1;
+ }
+ if ((image = fopen(filename, "wb")) == NULL) {
+ msg_gerr("Error: opening file \"%s\" failed: %s\n", filename, strerror(errno));
+ return 1;
+ }
+
+ unsigned long numbytes = fwrite(buf, 1, size, image);
+ if (numbytes != size) {
+ msg_gerr("Error: file %s could not be written completely.\n", filename);
+ ret = 1;
+ goto out;
+ }
+ if (fflush(image)) {
+ msg_gerr("Error: flushing file \"%s\" failed: %s\n", filename, strerror(errno));
+ ret = 1;
+ }
+ // Try to fsync() only regular files and if that function is available at all (e.g. not on MinGW).
+#if defined(_POSIX_FSYNC) && (_POSIX_FSYNC != -1)
+ struct stat image_stat;
+ if (fstat(fileno(image), &image_stat) != 0) {
+ msg_gerr("Error: getting metadata of file \"%s\" failed: %s\n", filename, strerror(errno));
+ ret = 1;
+ goto out;
+ }
+ if (S_ISREG(image_stat.st_mode)) {
+ if (fsync(fileno(image))) {
+ msg_gerr("Error: fsyncing file \"%s\" failed: %s\n", filename, strerror(errno));
+ ret = 1;
+ }
+ }
+#endif
+out:
+ if (fclose(image)) {
+ msg_gerr("Error: closing file \"%s\" failed: %s\n", filename, strerror(errno));
+ ret = 1;
+ }
+ return ret;
+#endif
+}
diff --git a/hwaccess.c b/hwaccess.c
deleted file mode 100644
index 48ccb3485..000000000
--- a/hwaccess.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
- *
- * 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 "platform.h"
-
-#include <stdint.h>
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#if !defined (__DJGPP__) && !defined(__LIBPAYLOAD__)
-/* No file access needed/possible to get hardware access permissions. */
-#include <unistd.h>
-#include <fcntl.h>
-#endif
-#include "flash.h"
-#include "programmer.h"
-#include "hwaccess.h"
-
-#if !(IS_LINUX || IS_MACOSX || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__DJGPP__) || defined(__LIBPAYLOAD__) || defined(__sun) || defined(__gnu_hurd__))
-#error "Unknown operating system"
-#endif
-
-#if IS_LINUX || IS_MACOSX || defined(__NetBSD__) || defined(__OpenBSD__)
-#define USE_IOPL 1
-#else
-#define USE_IOPL 0
-#endif
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-#define USE_DEV_IO 1
-#else
-#define USE_DEV_IO 0
-#endif
-#if defined(__gnu_hurd__)
-#define USE_IOPERM 1
-#else
-#define USE_IOPERM 0
-#endif
-
-#if USE_IOPERM
-#include <sys/io.h>
-#endif
-
-#if IS_X86 && USE_DEV_IO
-int io_fd;
-#endif
-
-/* Prevent reordering and/or merging of reads/writes to hardware.
- * Such reordering and/or merging would break device accesses which depend on the exact access order.
- */
-static inline void sync_primitive(void)
-{
-/* This is not needed for...
- * - x86: uses uncached accesses which have a strongly ordered memory model.
- * - MIPS: uses uncached accesses in mode 2 on /dev/mem which has also a strongly ordered memory model.
- * - ARM: uses a strongly ordered memory model for device memories.
- *
- * See also https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/memory-barriers.txt
- */
-#if IS_PPC // cf. http://lxr.free-electrons.com/source/arch/powerpc/include/asm/barrier.h
- asm("eieio" : : : "memory");
-#elif IS_SPARC
-#if defined(__sparc_v9__) || defined(__sparcv9)
- /* Sparc V9 CPUs support three different memory orderings that range from x86-like TSO to PowerPC-like
- * RMO. The modes can be switched at runtime thus to make sure we maintain the right order of access we
- * use the strongest hardware memory barriers that exist on Sparc V9. */
- asm volatile ("membar #Sync" ::: "memory");
-#elif defined(__sparc_v8__) || defined(__sparcv8)
- /* On SPARC V8 there is no RMO just PSO and that does not apply to I/O accesses... but if V8 code is run
- * on V9 CPUs it might apply... or not... we issue a write barrier anyway. That's the most suitable
- * operation in the V8 instruction set anyway. If you know better then please tell us. */
- asm volatile ("stbar");
-#else
- #error Unknown and/or unsupported SPARC instruction set version detected.
-#endif
-#endif
-}
-
-#if IS_X86 && !(defined(__DJGPP__) || defined(__LIBPAYLOAD__))
-static int release_io_perms(void *p)
-{
-#if defined (__sun)
- sysi86(SI86V86, V86SC_IOPL, 0);
-#elif USE_DEV_IO
- close(io_fd);
-#elif USE_IOPERM
- ioperm(0, 65536, 0);
-#elif USE_IOPL
- iopl(0);
-#endif
- return 0;
-}
-#endif
-
-/* Get I/O permissions with automatic permission release on shutdown. */
-int rget_io_perms(void)
-{
-#if IS_X86 && !(defined(__DJGPP__) || defined(__LIBPAYLOAD__))
-#if defined (__sun)
- if (sysi86(SI86V86, V86SC_IOPL, PS_IOPL) != 0) {
-#elif USE_DEV_IO
- if ((io_fd = open("/dev/io", O_RDWR)) < 0) {
-#elif USE_IOPERM
- if (ioperm(0, 65536, 1) != 0) {
-#elif USE_IOPL
- if (iopl(3) != 0) {
-#endif
- msg_perr("ERROR: Could not get I/O privileges (%s).\n", strerror(errno));
- msg_perr("You need to be root.\n");
-#if defined (__OpenBSD__)
- msg_perr("If you are root already please set securelevel=-1 in /etc/rc.securelevel and\n"
- "reboot, or reboot into single user mode.\n");
-#elif defined(__NetBSD__)
- msg_perr("If you are root already please reboot into single user mode or make sure\n"
- "that your kernel configuration has the option INSECURE enabled.\n");
-#endif
- return 1;
- } else {
- register_shutdown(release_io_perms, NULL);
- }
-#else
- /* DJGPP and libpayload environments have full PCI port I/O permissions by default. */
- /* PCI port I/O support is unimplemented on PPC/MIPS and unavailable on ARM. */
-#endif
- return 0;
-}
-
-void mmio_writeb(uint8_t val, void *addr)
-{
- *(volatile uint8_t *) addr = val;
- sync_primitive();
-}
-
-void mmio_writew(uint16_t val, void *addr)
-{
- *(volatile uint16_t *) addr = val;
- sync_primitive();
-}
-
-void mmio_writel(uint32_t val, void *addr)
-{
- *(volatile uint32_t *) addr = val;
- sync_primitive();
-}
-
-uint8_t mmio_readb(const void *addr)
-{
- return *(volatile const uint8_t *) addr;
-}
-
-uint16_t mmio_readw(const void *addr)
-{
- return *(volatile const uint16_t *) addr;
-}
-
-uint32_t mmio_readl(const void *addr)
-{
- return *(volatile const uint32_t *) addr;
-}
-
-void mmio_readn(const void *addr, uint8_t *buf, size_t len)
-{
- memcpy(buf, addr, len);
- return;
-}
-
-void mmio_le_writeb(uint8_t val, void *addr)
-{
- mmio_writeb(cpu_to_le8(val), addr);
-}
-
-void mmio_le_writew(uint16_t val, void *addr)
-{
- mmio_writew(cpu_to_le16(val), addr);
-}
-
-void mmio_le_writel(uint32_t val, void *addr)
-{
- mmio_writel(cpu_to_le32(val), addr);
-}
-
-uint8_t mmio_le_readb(const void *addr)
-{
- return le_to_cpu8(mmio_readb(addr));
-}
-
-uint16_t mmio_le_readw(const void *addr)
-{
- return le_to_cpu16(mmio_readw(addr));
-}
-
-uint32_t mmio_le_readl(const void *addr)
-{
- return le_to_cpu32(mmio_readl(addr));
-}
-
-enum mmio_write_type {
- mmio_write_type_b,
- mmio_write_type_w,
- mmio_write_type_l,
-};
-
-struct undo_mmio_write_data {
- void *addr;
- int reg;
- enum mmio_write_type type;
- union {
- uint8_t bdata;
- uint16_t wdata;
- uint32_t ldata;
- };
-};
-
-static int undo_mmio_write(void *p)
-{
- struct undo_mmio_write_data *data = p;
- msg_pdbg("Restoring MMIO space at %p\n", data->addr);
- switch (data->type) {
- case mmio_write_type_b:
- mmio_writeb(data->bdata, data->addr);
- break;
- case mmio_write_type_w:
- mmio_writew(data->wdata, data->addr);
- break;
- case mmio_write_type_l:
- mmio_writel(data->ldata, data->addr);
- break;
- }
- /* p was allocated in register_undo_mmio_write. */
- free(p);
- return 0;
-}
-
-#define register_undo_mmio_write(a, c) \
-{ \
- struct undo_mmio_write_data *undo_mmio_write_data; \
- undo_mmio_write_data = malloc(sizeof(struct undo_mmio_write_data)); \
- if (!undo_mmio_write_data) { \
- msg_gerr("Out of memory!\n"); \
- exit(1); \
- } \
- undo_mmio_write_data->addr = a; \
- undo_mmio_write_data->type = mmio_write_type_##c; \
- undo_mmio_write_data->c##data = mmio_read##c(a); \
- register_shutdown(undo_mmio_write, undo_mmio_write_data); \
-}
-
-#define register_undo_mmio_writeb(a) register_undo_mmio_write(a, b)
-#define register_undo_mmio_writew(a) register_undo_mmio_write(a, w)
-#define register_undo_mmio_writel(a) register_undo_mmio_write(a, l)
-
-void rmmio_writeb(uint8_t val, void *addr)
-{
- register_undo_mmio_writeb(addr);
- mmio_writeb(val, addr);
-}
-
-void rmmio_writew(uint16_t val, void *addr)
-{
- register_undo_mmio_writew(addr);
- mmio_writew(val, addr);
-}
-
-void rmmio_writel(uint32_t val, void *addr)
-{
- register_undo_mmio_writel(addr);
- mmio_writel(val, addr);
-}
-
-void rmmio_le_writeb(uint8_t val, void *addr)
-{
- register_undo_mmio_writeb(addr);
- mmio_le_writeb(val, addr);
-}
-
-void rmmio_le_writew(uint16_t val, void *addr)
-{
- register_undo_mmio_writew(addr);
- mmio_le_writew(val, addr);
-}
-
-void rmmio_le_writel(uint32_t val, void *addr)
-{
- register_undo_mmio_writel(addr);
- mmio_le_writel(val, addr);
-}
-
-void rmmio_valb(void *addr)
-{
- register_undo_mmio_writeb(addr);
-}
-
-void rmmio_valw(void *addr)
-{
- register_undo_mmio_writew(addr);
-}
-
-void rmmio_vall(void *addr)
-{
- register_undo_mmio_writel(addr);
-}
diff --git a/hwaccess.h b/hwaccess.h
deleted file mode 100644
index 5602c1592..000000000
--- a/hwaccess.h
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2009 Carl-Daniel Hailfinger
- *
- * 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; version 2 of the License.
- *
- * 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.
- */
-
-/*
- * Header file for hardware access and OS abstraction. Included from flash.h.
- */
-
-#ifndef __HWACCESS_H__
-#define __HWACCESS_H__ 1
-
-#include "platform.h"
-
-#if NEED_PCI == 1
-/*
- * libpci headers use the variable name "index" which triggers shadowing
- * warnings on systems which have the index() function in a default #include
- * or as builtin.
- */
-#define index shadow_workaround_index
-
-#if !defined (__NetBSD__)
-#include <pci/pci.h>
-#else
-#include <pciutils/pci.h>
-#endif
-
-#undef index
-#endif /* NEED_PCI == 1 */
-
-#define ___constant_swab8(x) ((uint8_t) ( \
- (((uint8_t)(x) & (uint8_t)0xffU))))
-
-#define ___constant_swab16(x) ((uint16_t) ( \
- (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
- (((uint16_t)(x) & (uint16_t)0xff00U) >> 8)))
-
-#define ___constant_swab32(x) ((uint32_t) ( \
- (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
- (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
- (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
- (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24)))
-
-#define ___constant_swab64(x) ((uint64_t) ( \
- (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
- (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
- (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
- (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
- (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
- (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
- (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
- (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56)))
-
-#if defined (__FLASHROM_BIG_ENDIAN__)
-
-#define cpu_to_le(bits) \
-static inline uint##bits##_t cpu_to_le##bits(uint##bits##_t val) \
-{ \
- return ___constant_swab##bits(val); \
-}
-
-cpu_to_le(8)
-cpu_to_le(16)
-cpu_to_le(32)
-cpu_to_le(64)
-
-#define cpu_to_be8
-#define cpu_to_be16
-#define cpu_to_be32
-#define cpu_to_be64
-
-#elif defined (__FLASHROM_LITTLE_ENDIAN__)
-
-#define cpu_to_be(bits) \
-static inline uint##bits##_t cpu_to_be##bits(uint##bits##_t val) \
-{ \
- return ___constant_swab##bits(val); \
-}
-
-cpu_to_be(8)
-cpu_to_be(16)
-cpu_to_be(32)
-cpu_to_be(64)
-
-#define cpu_to_le8
-#define cpu_to_le16
-#define cpu_to_le32
-#define cpu_to_le64
-
-#endif /* __FLASHROM_BIG_ENDIAN__ / __FLASHROM_LITTLE_ENDIAN__ */
-
-#define be_to_cpu8 cpu_to_be8
-#define be_to_cpu16 cpu_to_be16
-#define be_to_cpu32 cpu_to_be32
-#define be_to_cpu64 cpu_to_be64
-#define le_to_cpu8 cpu_to_le8
-#define le_to_cpu16 cpu_to_le16
-#define le_to_cpu32 cpu_to_le32
-#define le_to_cpu64 cpu_to_le64
-
-#if NEED_RAW_ACCESS == 1
-#if IS_X86
-
-/* sys/io.h provides iopl(2) and x86 I/O port access functions (inb, outb etc).
- * It is included in glibc (thus available also on debian/kFreeBSD) but also in other libcs that mimic glibc,
- * e.g. musl and uclibc. Because we cannot detect the libc or existence of the header or of the instructions
- * themselves safely in here we use some heuristic below:
- * On Android we don't have the header file and no way for I/O port access at all. However, sys/glibc-syscalls.h
- * refers to an iopl implementation and we therefore include at least that one for now. On non-Android we assume
- * that a Linux system's libc has a suitable sys/io.h or (on non-Linux) we depend on glibc to offer it. */
-#if defined(__ANDROID__)
-#include <sys/glibc-syscalls.h>
-#elif defined(__linux__) || defined(__GLIBC__)
-#include <sys/io.h>
-#endif
-
-#define __FLASHROM_HAVE_OUTB__ 1
-
-/* for iopl and outb under Solaris */
-#if defined (__sun)
-#include <sys/sysi86.h>
-#include <sys/psw.h>
-#include <asm/sunddi.h>
-#endif
-
-/* Clarification about OUTB/OUTW/OUTL argument order:
- * OUT[BWL](val, port)
- */
-
-#if defined(__FreeBSD__) || defined(__DragonFly__)
- /* Note that Debian/kFreeBSD (FreeBSD kernel with glibc) has conflicting
- * out[bwl] definitions in machine/cpufunc.h and sys/io.h at least in some
- * versions. Use machine/cpufunc.h only for plain FreeBSD/DragonFlyBSD.
- */
- #include <sys/types.h>
- #include <machine/cpufunc.h>
- #define OUTB(x, y) do { u_int outb_tmp = (y); outb(outb_tmp, (x)); } while (0)
- #define OUTW(x, y) do { u_int outw_tmp = (y); outw(outw_tmp, (x)); } while (0)
- #define OUTL(x, y) do { u_int outl_tmp = (y); outl(outl_tmp, (x)); } while (0)
- #define INB(x) __extension__ ({ u_int inb_tmp = (x); inb(inb_tmp); })
- #define INW(x) __extension__ ({ u_int inw_tmp = (x); inw(inw_tmp); })
- #define INL(x) __extension__ ({ u_int inl_tmp = (x); inl(inl_tmp); })
-#else
-
-#if defined (__sun)
- /* Note different order for outb */
- #define OUTB(x,y) outb(y, x)
- #define OUTW(x,y) outw(y, x)
- #define OUTL(x,y) outl(y, x)
- #define INB inb
- #define INW inw
- #define INL inl
-#else
-
-#ifdef __DJGPP__
-
-#include <pc.h>
-
- #define OUTB(x,y) outportb(y, x)
- #define OUTW(x,y) outportw(y, x)
- #define OUTL(x,y) outportl(y, x)
-
- #define INB inportb
- #define INW inportw
- #define INL inportl
-
-#else
-
-#if defined(__MACH__) && defined(__APPLE__)
- /* Header is part of the DirectHW library. */
- #include <DirectHW/DirectHW.h>
-#endif
-
- /* This is the usual glibc interface. */
- #define OUTB outb
- #define OUTW outw
- #define OUTL outl
- #define INB inb
- #define INW inw
- #define INL inl
-#endif
-#endif
-#endif
-
-#if defined(__NetBSD__) || defined (__OpenBSD__)
- #if defined(__i386__) || defined(__x86_64__)
- #include <sys/types.h>
- #include <machine/sysarch.h>
- #if defined(__NetBSD__)
- #if defined(__i386__)
- #define iopl i386_iopl
- #elif defined(__x86_64__)
- #define iopl x86_64_iopl
- #endif
- #elif defined (__OpenBSD__)
- #if defined(__i386__)
- #define iopl i386_iopl
- #elif defined(__amd64__)
- #define iopl amd64_iopl
- #endif
- #endif
-
-static inline void outb(uint8_t value, uint16_t port)
-{
- __asm__ volatile ("outb %b0,%w1": :"a" (value), "Nd" (port));
-}
-
-static inline uint8_t inb(uint16_t port)
-{
- uint8_t value;
- __asm__ volatile ("inb %w1,%0":"=a" (value):"Nd" (port));
- return value;
-}
-
-static inline void outw(uint16_t value, uint16_t port)
-{
- __asm__ volatile ("outw %w0,%w1": :"a" (value), "Nd" (port));
-}
-
-static inline uint16_t inw(uint16_t port)
-{
- uint16_t value;
- __asm__ volatile ("inw %w1,%0":"=a" (value):"Nd" (port));
- return value;
-}
-
-static inline void outl(uint32_t value, uint16_t port)
-{
- __asm__ volatile ("outl %0,%w1": :"a" (value), "Nd" (port));
-}
-
-static inline uint32_t inl(uint16_t port)
-{
- uint32_t value;
- __asm__ volatile ("inl %1,%0":"=a" (value):"Nd" (port));
- return value;
-}
- #endif
-#endif
-
-#if !(defined(__MACH__) && defined(__APPLE__)) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && !defined(__DragonFly__) && !defined(__LIBPAYLOAD__)
-typedef struct { uint32_t hi, lo; } msr_t;
-msr_t rdmsr(int addr);
-int wrmsr(int addr, msr_t msr);
-#endif
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-/* FreeBSD already has conflicting definitions for wrmsr/rdmsr. */
-#undef rdmsr
-#undef wrmsr
-#define rdmsr freebsd_rdmsr
-#define wrmsr freebsd_wrmsr
-typedef struct { uint32_t hi, lo; } msr_t;
-msr_t freebsd_rdmsr(int addr);
-int freebsd_wrmsr(int addr, msr_t msr);
-#endif
-#if defined(__LIBPAYLOAD__)
-#include <arch/io.h>
-#include <arch/msr.h>
-typedef struct { uint32_t hi, lo; } msr_t;
-msr_t libpayload_rdmsr(int addr);
-int libpayload_wrmsr(int addr, msr_t msr);
-#undef rdmsr
-#define rdmsr libpayload_rdmsr
-#define wrmsr libpayload_wrmsr
-#endif
-
-#elif IS_PPC
-
-/* PCI port I/O is not yet implemented on PowerPC. */
-
-#elif IS_MIPS
-
-/* PCI port I/O is not yet implemented on MIPS. */
-
-#elif IS_SPARC
-
-/* PCI port I/O is not yet implemented on SPARC. */
-
-#elif IS_ARM
-
-/* Non memory mapped I/O is not supported on ARM. */
-
-#elif IS_ARC
-
-/* Non memory mapped I/O is not supported on ARC. */
-
-#else
-
-#error Unknown architecture, please check if it supports PCI port IO.
-
-#endif /* IS_* */
-#endif /* NEED_RAW_ACCESS == 1 */
-
-#endif /* !__HWACCESS_H__ */
diff --git a/physmap.c b/hwaccess_physmap.c
index 72d589911..f95b5f647 100644
--- a/physmap.c
+++ b/hwaccess_physmap.c
@@ -18,17 +18,20 @@
#include <unistd.h>
#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "flash.h"
-#include "programmer.h"
-#include "hwaccess.h"
+#include "platform.h"
+#include "hwaccess_physmap.h"
#if !defined(__DJGPP__) && !defined(__LIBPAYLOAD__)
/* No file access needed/possible to get mmap access permissions or access MSR. */
+#include <unistd.h>
#include <sys/stat.h>
+#include <sys/types.h>
#include <fcntl.h>
#endif
@@ -118,7 +121,7 @@ static void sys_physunmap_unaligned(void *virt_addr, size_t len)
#define MEM_DEV ""
-void *sys_physmap(uintptr_t phys_addr, size_t len)
+static void *sys_physmap(uintptr_t phys_addr, size_t len)
{
return (void *)phys_to_virt(phys_addr);
}
@@ -130,6 +133,7 @@ static void sys_physunmap_unaligned(void *virt_addr, size_t len)
{
}
#elif defined(__MACH__) && defined(__APPLE__)
+#include <DirectHW/DirectHW.h>
#define MEM_DEV "DirectHW"
@@ -292,7 +296,7 @@ static void *physmap_common(const char *descr, uintptr_t phys_addr, size_t len,
}
if (autocleanup) {
- struct undo_physmap_data *d = malloc(sizeof(struct undo_physmap_data));
+ struct undo_physmap_data *d = malloc(sizeof(*d));
if (d == NULL) {
msg_perr("%s: Out of memory!\n", __func__);
physunmap_unaligned(virt_addr, len);
@@ -363,329 +367,211 @@ void *physmap_ro_unaligned(const char *descr, uintptr_t phys_addr, size_t len)
return physmap_common(descr, phys_addr, len, PHYSM_RO, PHYSM_NOCLEANUP, PHYSM_EXACT);
}
-#if CONFIG_INTERNAL == 1
-/* MSR abstraction implementations for Linux, OpenBSD, FreeBSD/Dragonfly, OSX, libpayload
- * and a non-working default implementation on the bottom. See also hwaccess.h for some (re)declarations. */
-#if defined(__i386__) || defined(__x86_64__)
-
-#ifdef __linux__
-/*
- * Reading and writing to MSRs, however requires instructions rdmsr/wrmsr,
- * which are ring0 privileged instructions so only the kernel can do the
- * read/write. This function, therefore, requires that the msr kernel module
- * be loaded to access these instructions from user space using device
- * /dev/cpu/0/msr.
+/* Prevent reordering and/or merging of reads/writes to hardware.
+ * Such reordering and/or merging would break device accesses which depend on the exact access order.
*/
-
-static int fd_msr = -1;
-
-msr_t rdmsr(int addr)
+static inline void sync_primitive(void)
{
- uint32_t buf[2];
- msr_t msr = { 0xffffffff, 0xffffffff };
-
- if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
- msg_perr("Could not lseek() MSR: %s\n", strerror(errno));
- close(fd_msr);
- exit(1);
- }
-
- if (read(fd_msr, buf, 8) == 8) {
- msr.lo = buf[0];
- msr.hi = buf[1];
- return msr;
- }
-
- if (errno != EIO) {
- // A severe error.
- msg_perr("Could not read() MSR: %s\n", strerror(errno));
- close(fd_msr);
- exit(1);
- }
-
- return msr;
+/* This is not needed for...
+ * - x86: uses uncached accesses which have a strongly ordered memory model.
+ * - MIPS: uses uncached accesses in mode 2 on /dev/mem which has also a strongly ordered memory model.
+ * - ARM: uses a strongly ordered memory model for device memories.
+ *
+ * See also https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/memory-barriers.txt
+ */
+// cf. http://lxr.free-electrons.com/source/arch/powerpc/include/asm/barrier.h
+#if defined(__powerpc) || defined(__powerpc__) || defined(__powerpc64__) || defined(__POWERPC__) || \
+ defined(__ppc__) || defined(__ppc64__) || defined(_M_PPC) || defined(_ARCH_PPC) || \
+ defined(_ARCH_PPC64) || defined(__ppc)
+ __asm__("eieio" : : : "memory");
+#elif (__sparc__) || defined (__sparc)
+#if defined(__sparc_v9__) || defined(__sparcv9)
+ /* Sparc V9 CPUs support three different memory orderings that range from x86-like TSO to PowerPC-like
+ * RMO. The modes can be switched at runtime thus to make sure we maintain the right order of access we
+ * use the strongest hardware memory barriers that exist on Sparc V9. */
+ __asm__ volatile ("membar #Sync" ::: "memory");
+#elif defined(__sparc_v8__) || defined(__sparcv8)
+ /* On SPARC V8 there is no RMO just PSO and that does not apply to I/O accesses... but if V8 code is run
+ * on V9 CPUs it might apply... or not... we issue a write barrier anyway. That's the most suitable
+ * operation in the V8 instruction set anyway. If you know better then please tell us. */
+ __asm__ volatile ("stbar");
+#else
+ #error Unknown and/or unsupported SPARC instruction set version detected.
+#endif
+#endif
}
-int wrmsr(int addr, msr_t msr)
+void mmio_writeb(uint8_t val, void *addr)
{
- uint32_t buf[2];
- buf[0] = msr.lo;
- buf[1] = msr.hi;
-
- if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
- msg_perr("Could not lseek() MSR: %s\n", strerror(errno));
- close(fd_msr);
- exit(1);
- }
-
- if (write(fd_msr, buf, 8) != 8 && errno != EIO) {
- msg_perr("Could not write() MSR: %s\n", strerror(errno));
- close(fd_msr);
- exit(1);
- }
-
- /* Some MSRs must not be written. */
- if (errno == EIO)
- return -1;
-
- return 0;
+ *(volatile uint8_t *) addr = val;
+ sync_primitive();
}
-int setup_cpu_msr(int cpu)
+void mmio_writew(uint16_t val, void *addr)
{
- char msrfilename[64];
- memset(msrfilename, 0, sizeof(msrfilename));
- snprintf(msrfilename, sizeof(msrfilename), "/dev/cpu/%d/msr", cpu);
-
- if (fd_msr != -1) {
- msg_pinfo("MSR was already initialized\n");
- return -1;
- }
-
- fd_msr = open(msrfilename, O_RDWR);
-
- if (fd_msr < 0) {
- msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
- msg_pinfo("Did you run 'modprobe msr'?\n");
- return -1;
- }
-
- return 0;
+ *(volatile uint16_t *) addr = val;
+ sync_primitive();
}
-void cleanup_cpu_msr(void)
+void mmio_writel(uint32_t val, void *addr)
{
- if (fd_msr == -1) {
- msg_pinfo("No MSR initialized.\n");
- return;
- }
-
- close(fd_msr);
-
- /* Clear MSR file descriptor. */
- fd_msr = -1;
+ *(volatile uint32_t *) addr = val;
+ sync_primitive();
}
-#elif defined(__OpenBSD__) && defined (__i386__) /* This does only work for certain AMD Geode LX systems see amdmsr(4). */
-#include <sys/ioctl.h>
-#include <machine/amdmsr.h>
-static int fd_msr = -1;
-
-msr_t rdmsr(int addr)
+uint8_t mmio_readb(const void *addr)
{
- struct amdmsr_req args;
-
- msr_t msr = { 0xffffffff, 0xffffffff };
-
- args.addr = (uint32_t)addr;
-
- if (ioctl(fd_msr, RDMSR, &args) < 0) {
- msg_perr("Error while executing RDMSR ioctl: %s\n", strerror(errno));
- close(fd_msr);
- exit(1);
- }
-
- msr.lo = args.val & 0xffffffff;
- msr.hi = args.val >> 32;
-
- return msr;
+ return *(volatile const uint8_t *) addr;
}
-int wrmsr(int addr, msr_t msr)
+uint16_t mmio_readw(const void *addr)
{
- struct amdmsr_req args;
-
- args.addr = addr;
- args.val = (((uint64_t)msr.hi) << 32) | msr.lo;
-
- if (ioctl(fd_msr, WRMSR, &args) < 0) {
- msg_perr("Error while executing WRMSR ioctl: %s\n", strerror(errno));
- close(fd_msr);
- exit(1);
- }
-
- return 0;
+ return *(volatile const uint16_t *) addr;
}
-int setup_cpu_msr(int cpu)
+uint32_t mmio_readl(const void *addr)
{
- char msrfilename[64];
- memset(msrfilename, 0, sizeof(msrfilename));
- snprintf(msrfilename, sizeof(msrfilename), "/dev/amdmsr");
-
- if (fd_msr != -1) {
- msg_pinfo("MSR was already initialized\n");
- return -1;
- }
-
- fd_msr = open(msrfilename, O_RDWR);
-
- if (fd_msr < 0) {
- msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
- return -1;
- }
-
- return 0;
+ return *(volatile const uint32_t *) addr;
}
-void cleanup_cpu_msr(void)
+void mmio_readn(const void *addr, uint8_t *buf, size_t len)
{
- if (fd_msr == -1) {
- msg_pinfo("No MSR initialized.\n");
- return;
- }
-
- close(fd_msr);
-
- /* Clear MSR file descriptor. */
- fd_msr = -1;
+ memcpy(buf, addr, len);
+ return;
}
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
-#include <sys/ioctl.h>
-
-typedef struct {
- int msr;
- uint64_t data;
-} cpu_msr_args_t;
-#define CPU_RDMSR _IOWR('c', 1, cpu_msr_args_t)
-#define CPU_WRMSR _IOWR('c', 2, cpu_msr_args_t)
-
-static int fd_msr = -1;
-
-msr_t rdmsr(int addr)
+void mmio_le_writeb(uint8_t val, void *addr)
{
- cpu_msr_args_t args;
-
- msr_t msr = { 0xffffffff, 0xffffffff };
-
- args.msr = addr;
-
- if (ioctl(fd_msr, CPU_RDMSR, &args) < 0) {
- msg_perr("Error while executing CPU_RDMSR ioctl: %s\n", strerror(errno));
- close(fd_msr);
- exit(1);
- }
-
- msr.lo = args.data & 0xffffffff;
- msr.hi = args.data >> 32;
-
- return msr;
+ mmio_writeb(cpu_to_le8(val), addr);
}
-int wrmsr(int addr, msr_t msr)
+void mmio_le_writew(uint16_t val, void *addr)
{
- cpu_msr_args_t args;
+ mmio_writew(cpu_to_le16(val), addr);
+}
- args.msr = addr;
- args.data = (((uint64_t)msr.hi) << 32) | msr.lo;
+void mmio_le_writel(uint32_t val, void *addr)
+{
+ mmio_writel(cpu_to_le32(val), addr);
+}
- if (ioctl(fd_msr, CPU_WRMSR, &args) < 0) {
- msg_perr("Error while executing CPU_WRMSR ioctl: %s\n", strerror(errno));
- close(fd_msr);
- exit(1);
- }
+uint8_t mmio_le_readb(const void *addr)
+{
+ return le_to_cpu8(mmio_readb(addr));
+}
- return 0;
+uint16_t mmio_le_readw(const void *addr)
+{
+ return le_to_cpu16(mmio_readw(addr));
}
-int setup_cpu_msr(int cpu)
+uint32_t mmio_le_readl(const void *addr)
{
- char msrfilename[64];
- memset(msrfilename, 0, sizeof(msrfilename));
- snprintf(msrfilename, sizeof(msrfilename), "/dev/cpu%d", cpu);
+ return le_to_cpu32(mmio_readl(addr));
+}
- if (fd_msr != -1) {
- msg_pinfo("MSR was already initialized\n");
- return -1;
- }
+enum mmio_write_type {
+ mmio_write_type_b,
+ mmio_write_type_w,
+ mmio_write_type_l,
+};
- fd_msr = open(msrfilename, O_RDWR);
+struct undo_mmio_write_data {
+ void *addr;
+ int reg;
+ enum mmio_write_type type;
+ union {
+ uint8_t bdata;
+ uint16_t wdata;
+ uint32_t ldata;
+ };
+};
- if (fd_msr < 0) {
- msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
- msg_pinfo("Did you install ports/sysutils/devcpu?\n");
- return -1;
+static int undo_mmio_write(void *p)
+{
+ struct undo_mmio_write_data *data = p;
+ msg_pdbg("Restoring MMIO space at %p\n", data->addr);
+ switch (data->type) {
+ case mmio_write_type_b:
+ mmio_writeb(data->bdata, data->addr);
+ break;
+ case mmio_write_type_w:
+ mmio_writew(data->wdata, data->addr);
+ break;
+ case mmio_write_type_l:
+ mmio_writel(data->ldata, data->addr);
+ break;
}
-
+ /* p was allocated in register_undo_mmio_write. */
+ free(p);
return 0;
}
-void cleanup_cpu_msr(void)
-{
- if (fd_msr == -1) {
- msg_pinfo("No MSR initialized.\n");
- return;
- }
-
- close(fd_msr);
-
- /* Clear MSR file descriptor. */
- fd_msr = -1;
+#define register_undo_mmio_write(a, c) \
+{ \
+ struct undo_mmio_write_data *undo_mmio_write_data; \
+ undo_mmio_write_data = malloc(sizeof(*undo_mmio_write_data)); \
+ if (!undo_mmio_write_data) { \
+ msg_gerr("Out of memory!\n"); \
+ exit(1); \
+ } \
+ undo_mmio_write_data->addr = a; \
+ undo_mmio_write_data->type = mmio_write_type_##c; \
+ undo_mmio_write_data->c##data = mmio_read##c(a); \
+ register_shutdown(undo_mmio_write, undo_mmio_write_data); \
}
-#elif defined(__MACH__) && defined(__APPLE__)
-/* rdmsr() and wrmsr() are provided by DirectHW which needs neither setup nor cleanup. */
-int setup_cpu_msr(int cpu)
-{
- // Always succeed for now
- return 0;
-}
+#define register_undo_mmio_writeb(a) register_undo_mmio_write(a, b)
+#define register_undo_mmio_writew(a) register_undo_mmio_write(a, w)
+#define register_undo_mmio_writel(a) register_undo_mmio_write(a, l)
-void cleanup_cpu_msr(void)
+void rmmio_writeb(uint8_t val, void *addr)
{
- // Nothing, yet.
+ register_undo_mmio_writeb(addr);
+ mmio_writeb(val, addr);
}
-#elif defined(__LIBPAYLOAD__)
-msr_t libpayload_rdmsr(int addr)
+
+void rmmio_writew(uint16_t val, void *addr)
{
- msr_t msr;
- unsigned long long val = _rdmsr(addr);
- msr.lo = val & 0xffffffff;
- msr.hi = val >> 32;
- return msr;
+ register_undo_mmio_writew(addr);
+ mmio_writew(val, addr);
}
-int libpayload_wrmsr(int addr, msr_t msr)
+void rmmio_writel(uint32_t val, void *addr)
{
- _wrmsr(addr, msr.lo | ((unsigned long long)msr.hi << 32));
- return 0;
+ register_undo_mmio_writel(addr);
+ mmio_writel(val, addr);
}
-int setup_cpu_msr(int cpu)
+void rmmio_le_writeb(uint8_t val, void *addr)
{
- return 0;
+ register_undo_mmio_writeb(addr);
+ mmio_le_writeb(val, addr);
}
-void cleanup_cpu_msr(void)
+void rmmio_le_writew(uint16_t val, void *addr)
{
+ register_undo_mmio_writew(addr);
+ mmio_le_writew(val, addr);
}
-#else
-/* default MSR implementation */
-msr_t rdmsr(int addr)
-{
- msr_t ret = { 0xffffffff, 0xffffffff };
- return ret;
+void rmmio_le_writel(uint32_t val, void *addr)
+{
+ register_undo_mmio_writel(addr);
+ mmio_le_writel(val, addr);
}
-int wrmsr(int addr, msr_t msr)
+void rmmio_valb(void *addr)
{
- return -1;
+ register_undo_mmio_writeb(addr);
}
-int setup_cpu_msr(int cpu)
+void rmmio_valw(void *addr)
{
- msg_pinfo("No MSR support for your OS yet.\n");
- return -1;
+ register_undo_mmio_writew(addr);
}
-void cleanup_cpu_msr(void)
+void rmmio_vall(void *addr)
{
- // Nothing, yet.
+ register_undo_mmio_writel(addr);
}
-#endif // OS switches for MSR code
-#else // x86
-/* Does MSR exist on non-x86 architectures? */
-#endif // arch switches for MSR code
-#endif // CONFIG_INTERNAL == 1
diff --git a/hwaccess_x86_io.c b/hwaccess_x86_io.c
new file mode 100644
index 000000000..93d29d82d
--- /dev/null
+++ b/hwaccess_x86_io.c
@@ -0,0 +1,428 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009,2010 Carl-Daniel Hailfinger
+ * Copyright (C) 2022 secunet Security Networks AG
+ * (Written by Thomas Heijligen <thomas.heijligen@secunet.com)
+ *
+ * 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.
+ */
+
+/*
+ * This file implements x86 I/O port permission and access handling.
+ *
+ * The first part of the file defines the platform dependend implementations to
+ * use on each platform. For getting I/O permissions set IO_PORT_PERMISSION to
+ * one of:
+ * - USE_DUMMY
+ * - USE_SUN
+ * - USE_DEVICE
+ * - USE_IOPERM
+ * - USE_IOPL
+ * For the IN[B/W/L] and OUT[B/W/L] functions set IO_PORT_FUNCTION to one of:
+ * - USE_LIBC_TARGET_LAST
+ * - USE_LIBC_TARGET_FIRST
+ * - USE_DOS
+ * - USE_ASM
+ *
+ * The platform specific code for getting I/O permissions consists of two
+ * functions. `platform_get_io_perms()` is called to get
+ * permissions and `platform_release_io_perms()` is called for releasing those.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "flash.h"
+#include "hwaccess_x86_io.h"
+
+/* IO_PORT_FUNCTION */
+#define USE_LIBC_TARGET_LAST 1
+#define USE_LIBC_TARGET_FIRST 2
+#define USE_ASM 3
+#define USE_DOS 4
+
+/* IO_PORT_PERMISSION */
+#define USE_IOPL 5
+#define USE_DEVICE 6
+#define USE_DUMMY 7
+#define USE_SUN 8
+#define USE_IOPERM 9
+
+#if defined(__ANDROID__)
+#include <sys/glibc-syscalls.h>
+
+#define IO_PORT_PERMISSION USE_IOPL
+#define IO_PORT_FUNCTION USE_LIBC_TARGET_LAST
+#endif
+
+#if defined(__linux__) && !defined(__ANDROID__)
+#include <sys/io.h>
+#include <unistd.h>
+
+#define IO_PORT_PERMISSION USE_IOPL
+#define IO_PORT_FUNCTION USE_LIBC_TARGET_LAST
+#endif
+
+#if defined(__FreeBSD_kernel) && defined(__GLIBC__)
+#include <sys/io.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define IO_PORT_PERMISSION USE_DEVICE
+#define IO_PORT_FUNCTION USE_LIBC_TARGET_LAST
+#endif
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define IO_PORT_PERMISSION USE_DEVICE
+#define IO_PORT_FUNCTION USE_LIBC_TARGET_FIRST
+#endif
+
+#if defined(__NetBSD__)
+#include <sys/types.h>
+#include <machine/sysarch.h>
+
+#if defined(__i386__)
+#define iopl i386_iopl
+#elif defined(__x86_64__)
+#define iopl x86_64_iopl
+#endif
+
+#define IO_PORT_PERMISSION USE_IOPL
+#define IO_PORT_FUNCTION USE_ASM
+#endif
+
+#if defined(__OpenBSD__)
+#include <sys/types.h>
+#include <machine/sysarch.h>
+
+#if defined(__i386__)
+#define iopl i386_iopl
+#elif defined(__amd64__)
+#define iopl amd64_iopl
+#endif
+
+#define IO_PORT_PERMISSION USE_IOPL
+#define IO_PORT_FUNCTION USE_ASM
+#endif
+
+#if defined(__MACH__) && defined(__APPLE__)
+#include <DirectHW/DirectHW.h>
+
+#define IO_PORT_PERMISSION USE_IOPL
+#define IO_PORT_FUNCTION USE_LIBC_TARGET_LAST
+#endif
+
+#if defined(__DJGPP__)
+#include <pc.h>
+
+#define IO_PORT_PERMISSION USE_DUMMY
+#define IO_PORT_FUNCTION USE_DOS
+#endif
+
+#if defined(__LIBPAYLOAD__)
+#include <arch/io.h>
+
+#define IO_PORT_PERMISSION USE_DUMMY
+#define IO_PORT_FUNCTION USE_LIBC_TARGET_LAST
+#endif
+
+#if defined(__sun)
+#include <sys/sysi86.h>
+#include <sys/psw.h>
+#include <asm/sunddi.h>
+
+#define IO_PORT_PERMISSION USE_SUN
+#define IO_PORT_FUNCTION USE_LIBC_TARGET_FIRST
+#endif
+
+#if defined(__gnu_hurd__)
+#include <sys/io.h>
+
+#define IO_PORT_PERMISSION USE_IOPERM
+#define IO_PORT_FUNCTION USE_LIBC_TARGET_LAST
+#endif
+
+/* Make sure IO_PORT_PERMISSION and IO_PORT_FUNCTION are set */
+#if IO_PORT_PERMISSION == 0 || IO_PORT_FUNCTION == 0
+#error Unsupported or misconfigured platform.
+#endif
+
+/*
+ * USE_DUMMY
+ * This is for platforms which have no privilege levels.
+ */
+#if IO_PORT_PERMISSION == USE_DUMMY
+static int platform_get_io_perms(void)
+{
+ return 0;
+}
+
+static int platform_release_io_perms(void *p)
+{
+ return 0;
+}
+#endif
+
+/*
+ * USE_SUN
+ * This implementation uses SunOS system call sysi86 to handle I/O port permissions.
+ */
+#if IO_PORT_PERMISSION == USE_SUN
+static int platform_get_io_perms(void)
+{
+ return sysi86(SI86V86, V86SC_IOPL, PS_IOPL);
+}
+
+static int platform_release_io_perms(void *p)
+{
+ sysi86(SI86V86, V86SC_IOPL, 0);
+ return 0;
+}
+#endif
+
+/*
+ * USE_DEVICE
+ * This implementation uses the virtual /dev/io file to handle I/O Port permissions.
+ */
+#if IO_PORT_PERMISSION == USE_DEVICE
+int io_fd;
+
+static int platform_get_io_perms(void)
+{
+ io_fd = open("/dev/io", O_RDWR);
+ return (io_fd >= 0 ? 0 : -1);
+}
+
+static int platform_release_io_perms(void *p)
+{
+ close(io_fd);
+ return 0;
+}
+#endif
+
+/*
+ * USE_IOPERM
+ * This implementation uses the ioperm system call to handle I/O port permissions.
+ */
+#if IO_PORT_PERMISSION == USE_IOPERM
+static int platform_get_io_perms(void)
+{
+ return ioperm(0, 65536, 1);
+}
+
+static int platform_release_io_perms(void *p)
+{
+ ioperm(0, 65536, 0);
+ return 0;
+}
+#endif
+
+/*
+ * USE_IOPL
+ * This implementation uses the iopl system call to handle I/O port permissions.
+ */
+#if IO_PORT_PERMISSION == USE_IOPL
+static int platform_get_io_perms(void)
+{
+ return iopl(3);
+}
+
+static int platform_release_io_perms(void *p)
+{
+ iopl(0);
+ return 0;
+}
+#endif
+
+/**
+ * @brief Get access to the x86 I/O ports
+ *
+ * This function abstracts the platform dependent function to get access to the
+ * x86 I/O ports and musst be called before using IN[B/W/L] or OUT[B/W/L].
+ * It registers a shutdown function to release those privileges.
+ *
+ * @return 0 on success, platform specific number on failure
+ */
+int rget_io_perms(void)
+{
+ if (platform_get_io_perms() == 0) {
+ register_shutdown(platform_release_io_perms, NULL);
+ return 0;
+ }
+
+ msg_perr("ERROR: Could not get I/O privileges (%s).\n", strerror(errno));
+#if defined(__linux__) && !defined(__ANDROID__)
+ if (getuid() != 0) {
+ msg_perr("Make sure you are running flashrom with root privileges.\n");
+ } else {
+ msg_perr("Your kernel may prevent access based on security policies.\n"
+ "Issue a 'dmesg | grep flashrom' for further information\n");
+ }
+#elif defined(__OpenBSD__)
+ msg_perr("On OpenBSD set securelevel=-1 in /etc/rc.securelevel and\n"
+ "reboot, or reboot into single user mode.\n");
+#elif defined(__NetBSD__)
+ msg_perr("On NetBSD reboot into single user mode or make sure\n"
+ "that your kernel configuration has the option INSECURE enabled.\n");
+#else
+ msg_perr("Make sure you are running flashrom with root privileges.\n");
+#endif
+ return 1;
+}
+
+/*
+ * USE_LIBC_LAST
+ * This implementation wraps the glibc functions with the port as 2nd argument.
+ */
+#if IO_PORT_FUNCTION == USE_LIBC_TARGET_LAST
+void OUTB(uint8_t value, uint16_t port)
+{
+ outb(value, port);
+}
+
+void OUTW(uint16_t value, uint16_t port)
+{
+ outw(value, port);
+}
+
+void OUTL(uint32_t value, uint16_t port)
+{
+ outl(value, port);
+}
+#endif
+
+/*
+ * USE_LIBC_FIRST
+ * This implementation uses libc based functions with the port as first argument
+ * like on BSDs.
+ */
+#if IO_PORT_FUNCTION == USE_LIBC_TARGET_FIRST
+void OUTB(uint8_t value, uint16_t port)
+{
+ outb(port, value);
+}
+
+void OUTW(uint16_t value, uint16_t port)
+{
+ outw(port, value);
+}
+
+void OUTL(uint32_t value, uint16_t port)
+{
+ outl(port, value);
+}
+#endif
+
+/*
+ * LIBC_xxx
+ * INx functions can be shared between _LAST and _FIRST
+ */
+#if IO_PORT_FUNCTION == USE_LIBC_TARGET_LAST || IO_PORT_FUNCTION == USE_LIBC_TARGET_FIRST
+uint8_t INB(uint16_t port)
+{
+ return inb(port);
+}
+
+uint16_t INW(uint16_t port)
+{
+ return inw(port);
+}
+
+uint32_t INL(uint16_t port)
+{
+ return inl(port);
+}
+#endif
+
+/*
+ * USE_DOS
+ * DOS provides the functions under a differnt name.
+ */
+#if IO_PORT_FUNCTION == USE_DOS
+void OUTB(uint8_t value, uint16_t port)
+{
+ outportb(port, value);
+}
+
+void OUTW(uint16_t value, uint16_t port)
+{
+ outportw(port, value);
+}
+
+void OUTL(uint32_t value, uint16_t port)
+{
+ outportl(port, value);
+}
+
+uint8_t INB(uint16_t port)
+{
+ return inportb(port);
+}
+
+uint16_t INW(uint16_t port)
+{
+ return inportw(port);
+}
+
+uint32_t INL(uint16_t port)
+{
+ return inportl(port);
+}
+#endif
+
+/*
+ * USE_ASM
+ * Pure assembly implementation.
+ */
+#if IO_PORT_FUNCTION == USE_ASM
+void OUTB(uint8_t value, uint16_t port)
+{
+ __asm__ volatile ("outb %b0,%w1": :"a" (value), "Nd" (port));
+}
+
+void OUTW(uint16_t value, uint16_t port)
+{
+ __asm__ volatile ("outw %w0,%w1": :"a" (value), "Nd" (port));
+}
+
+void OUTL(uint32_t value, uint16_t port)
+{
+ __asm__ volatile ("outl %0,%w1": :"a" (value), "Nd" (port));
+}
+
+uint8_t INB(uint16_t port)
+{
+ uint8_t value;
+ __asm__ volatile ("inb %w1,%0":"=a" (value):"Nd" (port));
+ return value;
+}
+
+uint16_t INW(uint16_t port)
+{
+ uint16_t value;
+ __asm__ volatile ("inw %w1,%0":"=a" (value):"Nd" (port));
+ return value;
+}
+
+uint32_t INL(uint16_t port)
+{
+ uint32_t value;
+ __asm__ volatile ("inl %1,%0":"=a" (value):"Nd" (port));
+ return value;
+}
+#endif
diff --git a/hwaccess_x86_msr.c b/hwaccess_x86_msr.c
new file mode 100644
index 000000000..98e51d441
--- /dev/null
+++ b/hwaccess_x86_msr.c
@@ -0,0 +1,382 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Peter Stuge <peter@stuge.se>
+ * Copyright (C) 2009 coresystems GmbH
+ * Copyright (C) 2010 Carl-Daniel Hailfinger
+ * Copyright (C) 2010 Rudolf Marek <r.marek@assembler.cz>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+/* MSR abstraction implementations for Linux, OpenBSD, FreeBSD/Dragonfly, OSX, libpayload
+ * and a non-working default implementation on the bottom.
+ */
+
+#include "hwaccess_x86_msr.h"
+#include "flash.h"
+
+#ifdef __linux__
+/*
+ * Reading and writing to MSRs, however requires instructions rdmsr/wrmsr,
+ * which are ring0 privileged instructions so only the kernel can do the
+ * read/write. This function, therefore, requires that the msr kernel module
+ * be loaded to access these instructions from user space using device
+ * /dev/cpu/0/msr.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+static int fd_msr = -1;
+
+msr_t msr_read(int addr)
+{
+ uint32_t buf[2];
+ msr_t msr = { 0xffffffff, 0xffffffff };
+
+ if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
+ msg_perr("Could not lseek() MSR: %s\n", strerror(errno));
+ close(fd_msr);
+ exit(1);
+ }
+
+ if (read(fd_msr, buf, 8) == 8) {
+ msr.lo = buf[0];
+ msr.hi = buf[1];
+ return msr;
+ }
+
+ if (errno != EIO) {
+ // A severe error.
+ msg_perr("Could not read() MSR: %s\n", strerror(errno));
+ close(fd_msr);
+ exit(1);
+ }
+
+ return msr;
+}
+
+int msr_write(int addr, msr_t msr)
+{
+ uint32_t buf[2];
+ buf[0] = msr.lo;
+ buf[1] = msr.hi;
+
+ if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
+ msg_perr("Could not lseek() MSR: %s\n", strerror(errno));
+ close(fd_msr);
+ exit(1);
+ }
+
+ if (write(fd_msr, buf, 8) != 8 && errno != EIO) {
+ msg_perr("Could not write() MSR: %s\n", strerror(errno));
+ close(fd_msr);
+ exit(1);
+ }
+
+ /* Some MSRs must not be written. */
+ if (errno == EIO)
+ return -1;
+
+ return 0;
+}
+
+int msr_setup(int cpu)
+{
+ char msrfilename[64] = { 0 };
+ snprintf(msrfilename, sizeof(msrfilename), "/dev/cpu/%d/msr", cpu);
+
+ if (fd_msr != -1) {
+ msg_pinfo("MSR was already initialized\n");
+ return -1;
+ }
+
+ fd_msr = open(msrfilename, O_RDWR);
+
+ if (fd_msr < 0) {
+ msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
+ msg_pinfo("Did you run 'modprobe msr'?\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void msr_cleanup(void)
+{
+ if (fd_msr == -1) {
+ msg_pinfo("No MSR initialized.\n");
+ return;
+ }
+
+ close(fd_msr);
+
+ /* Clear MSR file descriptor. */
+ fd_msr = -1;
+}
+#elif defined(__OpenBSD__) && defined (__i386__) /* This does only work for certain AMD Geode LX systems see amdmsr(4). */
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <machine/amdmsr.h>
+
+static int fd_msr = -1;
+
+msr_t msr_read(int addr)
+{
+ struct amdmsr_req args;
+
+ msr_t msr = { 0xffffffff, 0xffffffff };
+
+ args.addr = (uint32_t)addr;
+
+ if (ioctl(fd_msr, RDMSR, &args) < 0) {
+ msg_perr("Error while executing RDMSR ioctl: %s\n", strerror(errno));
+ close(fd_msr);
+ exit(1);
+ }
+
+ msr.lo = args.val & 0xffffffff;
+ msr.hi = args.val >> 32;
+
+ return msr;
+}
+
+int msr_write(int addr, msr_t msr)
+{
+ struct amdmsr_req args;
+
+ args.addr = addr;
+ args.val = (((uint64_t)msr.hi) << 32) | msr.lo;
+
+ if (ioctl(fd_msr, WRMSR, &args) < 0) {
+ msg_perr("Error while executing WRMSR ioctl: %s\n", strerror(errno));
+ close(fd_msr);
+ exit(1);
+ }
+
+ return 0;
+}
+
+int msr_setup(int cpu)
+{
+ char msrfilename[64] = { 0 };
+ snprintf(msrfilename, sizeof(msrfilename), "/dev/amdmsr");
+
+ if (fd_msr != -1) {
+ msg_pinfo("MSR was already initialized\n");
+ return -1;
+ }
+
+ fd_msr = open(msrfilename, O_RDWR);
+
+ if (fd_msr < 0) {
+ msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+void msr_cleanup(void)
+{
+ if (fd_msr == -1) {
+ msg_pinfo("No MSR initialized.\n");
+ return;
+ }
+
+ close(fd_msr);
+
+ /* Clear MSR file descriptor. */
+ fd_msr = -1;
+}
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+
+typedef struct {
+ int msr;
+ uint64_t data;
+} cpu_msr_args_t;
+#define CPU_RDMSR _IOWR('c', 1, cpu_msr_args_t)
+#define CPU_WRMSR _IOWR('c', 2, cpu_msr_args_t)
+
+static int fd_msr = -1;
+
+msr_t msr_read(int addr)
+{
+ cpu_msr_args_t args;
+
+ msr_t msr = { 0xffffffff, 0xffffffff };
+
+ args.msr = addr;
+
+ if (ioctl(fd_msr, CPU_RDMSR, &args) < 0) {
+ msg_perr("Error while executing CPU_RDMSR ioctl: %s\n", strerror(errno));
+ close(fd_msr);
+ exit(1);
+ }
+
+ msr.lo = args.data & 0xffffffff;
+ msr.hi = args.data >> 32;
+
+ return msr;
+}
+
+int msr_write(int addr, msr_t msr)
+{
+ cpu_msr_args_t args;
+
+ args.msr = addr;
+ args.data = (((uint64_t)msr.hi) << 32) | msr.lo;
+
+ if (ioctl(fd_msr, CPU_WRMSR, &args) < 0) {
+ msg_perr("Error while executing CPU_WRMSR ioctl: %s\n", strerror(errno));
+ close(fd_msr);
+ exit(1);
+ }
+
+ return 0;
+}
+
+int msr_setup(int cpu)
+{
+ char msrfilename[64] = { 0 };
+ snprintf(msrfilename, sizeof(msrfilename), "/dev/cpu%d", cpu);
+
+ if (fd_msr != -1) {
+ msg_pinfo("MSR was already initialized\n");
+ return -1;
+ }
+
+ fd_msr = open(msrfilename, O_RDWR);
+
+ if (fd_msr < 0) {
+ msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
+ msg_pinfo("Did you install ports/sysutils/devcpu?\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+void msr_cleanup(void)
+{
+ if (fd_msr == -1) {
+ msg_pinfo("No MSR initialized.\n");
+ return;
+ }
+
+ close(fd_msr);
+
+ /* Clear MSR file descriptor. */
+ fd_msr = -1;
+}
+
+#elif defined(__MACH__) && defined(__APPLE__)
+/*
+ * DirectHW has identical, but conflicting typedef for msr_t. We redefine msr_t
+ * to directhw_msr_t for DirectHW.
+ * rdmsr() and wrmsr() are provided by DirectHW and need neither setup nor cleanup.
+ */
+#define msr_t directhw_msr_t
+#include <DirectHW/DirectHW.h>
+#undef msr_t
+
+msr_t msr_read(int addr)
+{
+ directhw_msr_t msr;
+ msr = rdmsr(addr);
+ return (msr_t){msr.hi, msr.lo};
+}
+
+int msr_write(int addr, msr_t msr)
+{
+ return wrmsr(addr, (directhw_msr_t){msr.hi, msr.lo});
+}
+
+int msr_setup(int cpu)
+{
+ // Always succeed for now
+ return 0;
+}
+
+void msr_cleanup(void)
+{
+ // Nothing, yet.
+}
+#elif defined(__LIBPAYLOAD__)
+#include <arch/msr.h>
+
+msr_t msr_read(int addr)
+{
+ msr_t msr;
+ unsigned long long val = _rdmsr(addr);
+ msr.lo = val & 0xffffffff;
+ msr.hi = val >> 32;
+ return msr;
+}
+
+int msr_write(int addr, msr_t msr)
+{
+ _wrmsr(addr, msr.lo | ((unsigned long long)msr.hi << 32));
+ return 0;
+}
+
+int msr_setup(int cpu)
+{
+ return 0;
+}
+
+void msr_cleanup(void)
+{
+}
+#else
+/* default MSR implementation */
+msr_t msr_read(int addr)
+{
+ msr_t ret = { 0xffffffff, 0xffffffff };
+
+ return ret;
+}
+
+int msr_write(int addr, msr_t msr)
+{
+ return -1;
+}
+
+int msr_setup(int cpu)
+{
+ msg_pinfo("No MSR support for your OS yet.\n");
+ return -1;
+}
+
+void msr_cleanup(void)
+{
+ // Nothing, yet.
+}
+#endif // OS switches for MSR code
diff --git a/i2c_helper_linux.c b/i2c_helper_linux.c
index 0703518a7..19b4404fb 100644
--- a/i2c_helper_linux.c
+++ b/i2c_helper_linux.c
@@ -17,7 +17,7 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
-#include <sys/fcntl.h>
+#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
@@ -27,8 +27,10 @@
#include "flash.h"
#include "i2c_helper.h"
+#include "programmer.h"
-#define I2C_DEV_PREFIX "/dev/i2c-"
+/* Null characters are placeholders for bus number digits */
+#define I2C_DEV_PREFIX "/dev/i2c-\0\0\0"
#define I2C_MAX_BUS 255
int i2c_close(int fd)
@@ -36,52 +38,89 @@ int i2c_close(int fd)
return fd == -1 ? 0 : close(fd);
}
-int i2c_open(int bus, uint16_t addr, int force)
+int i2c_open_path(const char *path, uint16_t addr, int force)
{
- int ret = -1;
- int fd = -1;
+ int fd = open(path, O_RDWR);
+ if (fd < 0) {
+ msg_perr("Unable to open I2C device %s: %s.\n", path, strerror(errno));
+ return fd;
+ }
- /* Maximum i2c bus number is 255(3 char), +1 for null terminated string. */
- int path_len = strlen(I2C_DEV_PREFIX) + 4;
int request = force ? I2C_SLAVE_FORCE : I2C_SLAVE;
+ int ret = ioctl(fd, request, addr);
+ if (ret < 0) {
+ msg_perr("Unable to set I2C slave address to 0x%02x: %s.\n", addr, strerror(errno));
+ i2c_close(fd);
+ return ret;
+ }
+
+ return fd;
+}
+
+int i2c_open(int bus, uint16_t addr, int force)
+{
+ char dev[sizeof(I2C_DEV_PREFIX)] = {0};
+
+ int ret = -1;
if (bus < 0 || bus > I2C_MAX_BUS) {
msg_perr("Invalid I2C bus %d.\n", bus);
return ret;
}
- char *dev = calloc(1, path_len);
- if (!dev) {
- msg_perr("Unable to allocate space for device name of len %d: %s.\n",
- path_len, strerror(errno));
- goto linux_i2c_open_err;
- }
-
- ret = snprintf(dev, path_len, "%s%d", I2C_DEV_PREFIX, bus);
+ ret = snprintf(dev, sizeof(dev), "%s%d", I2C_DEV_PREFIX, bus);
if (ret < 0) {
msg_perr("Unable to join bus number to device name: %s.\n", strerror(errno));
- goto linux_i2c_open_err;
+ return ret;
}
- fd = open(dev, O_RDWR);
- if (fd < 0) {
- msg_perr("Unable to open I2C device %s: %s.\n", dev, strerror(errno));
- ret = fd;
- goto linux_i2c_open_err;
+ return i2c_open_path(dev, addr, force);
+}
+
+static int get_bus_number(char *bus_str)
+{
+ char *bus_suffix;
+ errno = 0;
+ int bus = (int)strtol(bus_str, &bus_suffix, 10);
+ if (errno != 0 || bus_str == bus_suffix) {
+ msg_perr("%s: Could not convert 'bus'.\n", __func__);
+ return -1;
}
- ret = ioctl(fd, request, addr);
- if (ret < 0) {
- msg_perr("Unable to set I2C slave address to 0x%02x: %s.\n", addr, strerror(errno));
- i2c_close(fd);
- goto linux_i2c_open_err;
+ if (strlen(bus_suffix) > 0) {
+ msg_perr("%s: Garbage following 'bus' value.\n", __func__);
+ return -1;
+ }
+
+ msg_pinfo("Using I2C bus %d.\n", bus);
+ return bus;
+}
+
+int i2c_open_from_programmer_params(const struct programmer_cfg *cfg, uint16_t addr, int force)
+{
+ int fd = -1;
+
+ char *bus_str = extract_programmer_param_str(cfg, "bus");
+ char *device_path = extract_programmer_param_str(cfg, "devpath");
+
+ if (device_path != NULL && bus_str != NULL) {
+ msg_perr("%s: only one of bus and devpath may be specified\n", __func__);
+ goto out;
+ }
+ if (device_path == NULL && bus_str == NULL) {
+ msg_perr("%s: one of bus and devpath must be specified\n", __func__);
+ goto out;
}
-linux_i2c_open_err:
- if (dev)
- free(dev);
+ if (device_path != NULL)
+ fd = i2c_open_path(device_path, addr, force);
+ else
+ fd = i2c_open(get_bus_number(bus_str), addr, force);
- return ret ? ret : fd;
+out:
+ free(bus_str);
+ free(device_path);
+ return fd;
}
int i2c_read(int fd, uint16_t addr, i2c_buffer_t *buf)
diff --git a/ich_descriptors.c b/ich_descriptors.c
index 7374984dc..a2a99bd0b 100644
--- a/ich_descriptors.c
+++ b/ich_descriptors.c
@@ -15,6 +15,7 @@
* GNU General Public License for more details.
*/
+#include "hwaccess_physmap.h"
#include "ich_descriptors.h"
#ifdef ICH_DESCRIPTORS_FROM_DUMP_ONLY
@@ -30,6 +31,7 @@
#define UPPER_MAP_OFFSET (4096 - 256 - 4)
#define getVTBA(flumap) (((flumap)->FLUMAP1 << 4) & 0x00000ff0)
+#include <stdbool.h>
#include <sys/types.h>
#include <string.h>
#include "flash.h" /* for msg_* */
@@ -39,10 +41,16 @@ ssize_t ich_number_of_regions(const enum ich_chipset cs, const struct ich_desc_c
{
switch (cs) {
case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
return 6;
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ case CHIPSET_ELKHART_LAKE:
+ case CHIPSET_JASPER_LAKE:
return 16;
case CHIPSET_100_SERIES_SUNRISE_POINT:
return 10;
@@ -68,6 +76,11 @@ ssize_t ich_number_of_masters(const enum ich_chipset cs, const struct ich_desc_c
switch (cs) {
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
if (cont->NM <= MAX_NUM_MASTERS)
return cont->NM;
break;
@@ -81,13 +94,13 @@ ssize_t ich_number_of_masters(const enum ich_chipset cs, const struct ich_desc_c
void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity, bool print_vcl)
{
- print(verbosity, "BES=0x%x, ", (reg_val & VSCC_BES) >> VSCC_BES_OFF);
- print(verbosity, "WG=%d, ", (reg_val & VSCC_WG) >> VSCC_WG_OFF);
- print(verbosity, "WSR=%d, ", (reg_val & VSCC_WSR) >> VSCC_WSR_OFF);
- print(verbosity, "WEWS=%d, ", (reg_val & VSCC_WEWS) >> VSCC_WEWS_OFF);
- print(verbosity, "EO=0x%x", (reg_val & VSCC_EO) >> VSCC_EO_OFF);
+ print(verbosity, "BES=0x%"PRIx32", ", (reg_val & VSCC_BES) >> VSCC_BES_OFF);
+ print(verbosity, "WG=%"PRId32", ", (reg_val & VSCC_WG) >> VSCC_WG_OFF);
+ print(verbosity, "WSR=%"PRId32", ", (reg_val & VSCC_WSR) >> VSCC_WSR_OFF);
+ print(verbosity, "WEWS=%"PRId32", ", (reg_val & VSCC_WEWS) >> VSCC_WEWS_OFF);
+ print(verbosity, "EO=0x%"PRIx32"", (reg_val & VSCC_EO) >> VSCC_EO_OFF);
if (print_vcl)
- print(verbosity, ", VCL=%d", (reg_val & VSCC_VCL) >> VSCC_VCL_OFF);
+ print(verbosity, ", VCL=%"PRId32"", (reg_val & VSCC_VCL) >> VSCC_VCL_OFF);
print(verbosity, "\n");
}
@@ -104,7 +117,9 @@ void prettyprint_ich_chipset(enum ich_chipset cs)
"5 series Ibex Peak", "6 series Cougar Point", "7 series Panther Point",
"8 series Lynx Point", "Baytrail", "8 series Lynx Point LP", "8 series Wellsburg",
"9 series Wildcat Point", "9 series Wildcat Point LP", "100 series Sunrise Point",
- "C620 series Lewisburg", "300 series Cannon Point", "Apollo Lake",
+ "C620 series Lewisburg", "300 series Cannon Point", "400 series Comet Point",
+ "500 series Tiger Point", "600 series Alder Point", "Meteor Lake",
+ "Apollo Lake", "Gemini Lake", "Jasper Lake", "Elkhart Lake",
};
if (cs < CHIPSET_ICH8 || cs - CHIPSET_ICH8 + 1 >= ARRAY_SIZE(chipset_names))
cs = 0;
@@ -130,23 +145,23 @@ void prettyprint_ich_descriptors(enum ich_chipset cs, const struct ich_descripto
void prettyprint_ich_descriptor_content(enum ich_chipset cs, const struct ich_desc_content *cont)
{
msg_pdbg2("=== Content Section ===\n");
- msg_pdbg2("FLVALSIG 0x%08x\n", cont->FLVALSIG);
- msg_pdbg2("FLMAP0 0x%08x\n", cont->FLMAP0);
- msg_pdbg2("FLMAP1 0x%08x\n", cont->FLMAP1);
- msg_pdbg2("FLMAP2 0x%08x\n", cont->FLMAP2);
+ msg_pdbg2("FLVALSIG 0x%08"PRIx32"\n", cont->FLVALSIG);
+ msg_pdbg2("FLMAP0 0x%08"PRIx32"\n", cont->FLMAP0);
+ msg_pdbg2("FLMAP1 0x%08"PRIx32"\n", cont->FLMAP1);
+ msg_pdbg2("FLMAP2 0x%08"PRIx32"\n", cont->FLMAP2);
msg_pdbg2("\n");
msg_pdbg2("--- Details ---\n");
msg_pdbg2("NR (Number of Regions): %5zd\n", ich_number_of_regions(cs, cont));
- msg_pdbg2("FRBA (Flash Region Base Address): 0x%03x\n", getFRBA(cont));
+ msg_pdbg2("FRBA (Flash Region Base Address): 0x%03"PRIx32"\n", getFRBA(cont));
msg_pdbg2("NC (Number of Components): %5d\n", cont->NC + 1);
- msg_pdbg2("FCBA (Flash Component Base Address): 0x%03x\n", getFCBA(cont));
+ msg_pdbg2("FCBA (Flash Component Base Address): 0x%03"PRIx32"\n", getFCBA(cont));
msg_pdbg2("ISL (ICH/PCH/SoC Strap Length): %5d\n", cont->ISL);
- msg_pdbg2("FISBA/FPSBA (Flash ICH/PCH/SoC Strap Base Addr): 0x%03x\n", getFISBA(cont));
+ msg_pdbg2("FISBA/FPSBA (Flash ICH/PCH/SoC Strap Base Addr): 0x%03"PRIx32"\n", getFISBA(cont));
msg_pdbg2("NM (Number of Masters): %5zd\n", ich_number_of_masters(cs, cont));
- msg_pdbg2("FMBA (Flash Master Base Address): 0x%03x\n", getFMBA(cont));
+ msg_pdbg2("FMBA (Flash Master Base Address): 0x%03"PRIx32"\n", getFMBA(cont));
msg_pdbg2("MSL/PSL (MCH/PROC Strap Length): %5d\n", cont->MSL);
- msg_pdbg2("FMSBA (Flash MCH/PROC Strap Base Address): 0x%03x\n", getFMSBA(cont));
+ msg_pdbg2("FMSBA (Flash MCH/PROC Strap Base Address): 0x%03"PRIx32"\n", getFMSBA(cont));
msg_pdbg2("\n");
}
@@ -198,7 +213,13 @@ static const char *pprint_density(enum ich_chipset cs, const struct ich_descript
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
- case CHIPSET_APOLLO_LAKE: {
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE: {
uint8_t size_enc;
if (idx == 0) {
size_enc = desc->component.dens_new.comp1_density;
@@ -217,7 +238,7 @@ static const char *pprint_density(enum ich_chipset cs, const struct ich_descript
static const char *pprint_freq(enum ich_chipset cs, uint8_t value)
{
- static const char *const freq_str[3][8] = { {
+ static const char *const freq_str[5][8] = { {
"20 MHz",
"33 MHz",
"reserved",
@@ -244,7 +265,25 @@ static const char *pprint_freq(enum ich_chipset cs, uint8_t value)
"reserved",
"14 MHz / 17 MHz",
"reserved"
- } };
+ }, {
+ "100 MHz",
+ "50 MHz",
+ "reserved",
+ "33 MHz",
+ "25 MHz",
+ "reserved",
+ "14 MHz",
+ "reserved"
+ }, {
+ "reserved",
+ "50 MHz",
+ "reserved",
+ "reserved",
+ "33 MHz",
+ "20 MHz",
+ "reserved",
+ "reserved",
+ }};
switch (cs) {
case CHIPSET_ICH8:
@@ -267,15 +306,50 @@ static const char *pprint_freq(enum ich_chipset cs, uint8_t value)
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_JASPER_LAKE:
return freq_str[1][value];
case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
return freq_str[2][value];
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ return freq_str[3][value];
+ case CHIPSET_ELKHART_LAKE:
+ return freq_str[4][value];
case CHIPSET_ICH_UNKNOWN:
default:
return "unknown";
}
}
+static void pprint_read_freq(enum ich_chipset cs, uint8_t value)
+{
+ static const char *const freq_str[1][8] = { {
+ "20 MHz",
+ "24 MHz",
+ "30 MHz",
+ "48 MHz",
+ "60 MHz",
+ "reserved",
+ "reserved",
+ "reserved"
+ }};
+
+ switch (cs) {
+ case CHIPSET_300_SERIES_CANNON_POINT:
+ case CHIPSET_400_SERIES_COMET_POINT:
+ msg_pdbg2("eSPI/EC Bus Clock Frequency: %s\n", freq_str[0][value]);
+ return;
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ msg_pdbg2("Read Clock Frequency: %s\n", "reserved");
+ return;
+ default:
+ msg_pdbg2("Read Clock Frequency: %s\n", pprint_freq(cs, value));
+ return;
+ }
+}
+
void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_descriptors *desc)
{
bool has_flill1;
@@ -285,7 +359,13 @@ void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
has_flill1 = true;
break;
default:
@@ -294,10 +374,10 @@ void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_
}
msg_pdbg2("=== Component Section ===\n");
- msg_pdbg2("FLCOMP 0x%08x\n", desc->component.FLCOMP);
- msg_pdbg2("FLILL 0x%08x\n", desc->component.FLILL );
+ msg_pdbg2("FLCOMP 0x%08"PRIx32"\n", desc->component.FLCOMP);
+ msg_pdbg2("FLILL 0x%08"PRIx32"\n", desc->component.FLILL );
if (has_flill1)
- msg_pdbg2("FLILL1 0x%08x\n", desc->component.FLILL1);
+ msg_pdbg2("FLILL1 0x%08"PRIx32"\n", desc->component.FLILL1);
msg_pdbg2("\n");
msg_pdbg2("--- Details ---\n");
@@ -306,7 +386,9 @@ void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_
msg_pdbg2("Component 2 density: %s\n", pprint_density(cs, desc, 1));
else
msg_pdbg2("Component 2 is not used.\n");
- msg_pdbg2("Read Clock Frequency: %s\n", pprint_freq(cs, desc->component.modes.freq_read));
+
+ pprint_read_freq(cs, desc->component.modes.freq_read);
+
msg_pdbg2("Read ID and Status Clock Freq.: %s\n", pprint_freq(cs, desc->component.modes.freq_read_id));
msg_pdbg2("Write and Erase Clock Freq.: %s\n", pprint_freq(cs, desc->component.modes.freq_write));
msg_pdbg2("Fast Read is %ssupported.\n", desc->component.modes.fastread ? "" : "not ");
@@ -315,11 +397,11 @@ void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_
pprint_freq(cs, desc->component.modes.freq_fastread));
if (cs > CHIPSET_6_SERIES_COUGAR_POINT)
msg_pdbg2("Dual Output Fast Read Support: %sabled\n",
- desc->component.modes.dual_output ? "dis" : "en");
+ desc->component.modes.dual_output ? "en" : "dis");
- int has_forbidden_opcode = 0;
+ bool has_forbidden_opcode = false;
if (desc->component.FLILL != 0) {
- has_forbidden_opcode = 1;
+ has_forbidden_opcode = true;
msg_pdbg2("Invalid instruction 0: 0x%02x\n",
desc->component.invalid_instr0);
msg_pdbg2("Invalid instruction 1: 0x%02x\n",
@@ -331,7 +413,7 @@ void prettyprint_ich_descriptor_component(enum ich_chipset cs, const struct ich_
}
if (has_flill1) {
if (desc->component.FLILL1 != 0) {
- has_forbidden_opcode = 1;
+ has_forbidden_opcode = true;
msg_pdbg2("Invalid instruction 4: 0x%02x\n",
desc->component.invalid_instr4);
msg_pdbg2("Invalid instruction 5: 0x%02x\n",
@@ -360,11 +442,11 @@ static void pprint_freg(const struct ich_desc_region *reg, uint32_t i)
}
uint32_t base = ICH_FREG_BASE(reg->FLREGs[i]);
uint32_t limit = ICH_FREG_LIMIT(reg->FLREGs[i]);
- msg_pdbg2("Region %d (%-7s) ", i, region_names[i]);
+ msg_pdbg2("Region %"PRId32" (%-7s) ", i, region_names[i]);
if (base > limit)
msg_pdbg2("is unused.\n");
else
- msg_pdbg2("0x%08x - 0x%08x\n", base, limit);
+ msg_pdbg2("0x%08"PRIx32" - 0x%08"PRIx32"\n", base, limit);
}
void prettyprint_ich_descriptor_region(const enum ich_chipset cs, const struct ich_descriptors *const desc)
@@ -378,7 +460,7 @@ void prettyprint_ich_descriptor_region(const enum ich_chipset cs, const struct i
return;
}
for (i = 0; i < nr; i++)
- msg_pdbg2("FLREG%zd 0x%08x\n", i, desc->region.FLREGs[i]);
+ msg_pdbg2("FLREG%zd 0x%08"PRIx32"\n", i, desc->region.FLREGs[i]);
msg_pdbg2("\n");
msg_pdbg2("--- Details ---\n");
@@ -398,13 +480,16 @@ void prettyprint_ich_descriptor_master(const enum ich_chipset cs, const struct i
return;
}
for (i = 0; i < nm; i++)
- msg_pdbg2("FLMSTR%zd 0x%08x\n", i + 1, desc->master.FLMSTRs[i]);
+ msg_pdbg2("FLMSTR%zd 0x%08"PRIx32"\n", i + 1, desc->master.FLMSTRs[i]);
msg_pdbg2("\n");
msg_pdbg2("--- Details ---\n");
if (cs == CHIPSET_100_SERIES_SUNRISE_POINT ||
cs == CHIPSET_300_SERIES_CANNON_POINT ||
- cs == CHIPSET_400_SERIES_COMET_POINT) {
+ cs == CHIPSET_400_SERIES_COMET_POINT ||
+ cs == CHIPSET_500_SERIES_TIGER_POINT ||
+ cs == CHIPSET_600_SERIES_ALDER_POINT ||
+ cs == CHIPSET_JASPER_LAKE || cs == CHIPSET_METEOR_LAKE) {
const char *const master_names[] = {
"BIOS", "ME", "GbE", "unknown", "EC",
};
@@ -424,16 +509,17 @@ void prettyprint_ich_descriptor_master(const enum ich_chipset cs, const struct i
msg_pdbg2(" RegA RegB RegC RegD RegE RegF\n");
}
for (i = 0; i < nm; i++) {
+ const unsigned int ext_region_start = 12;
size_t j;
msg_pdbg2("%-4s", master_names[i]);
- for (j = 0; j < (size_t)min(num_regions, 12); j++)
+ for (j = 0; j < (size_t)min(num_regions, ext_region_start); j++)
msg_pdbg2(" %c%c ",
desc->master.mstr[i].read & (1 << j) ? 'r' : ' ',
desc->master.mstr[i].write & (1 << j) ? 'w' : ' ');
- for (; j < num_regions; j++)
+ for (j = ext_region_start; j < num_regions; j++)
msg_pdbg2(" %c%c ",
- desc->master.mstr[i].ext_read & (1 << (j - 12)) ? 'r' : ' ',
- desc->master.mstr[i].ext_write & (1 << (j - 12)) ? 'w' : ' ');
+ desc->master.mstr[i].ext_read & (1 << (j - ext_region_start)) ? 'r' : ' ',
+ desc->master.mstr[i].ext_write & (1 << (j - ext_region_start)) ? 'w' : ' ');
msg_pdbg2("\n");
}
} else if (cs == CHIPSET_C620_SERIES_LEWISBURG) {
@@ -462,7 +548,7 @@ void prettyprint_ich_descriptor_master(const enum ich_chipset cs, const struct i
desc->master.mstr[i].write & (1 << j) ? 'w' : ' ');
msg_pdbg2("\n");
}
- } else if (cs == CHIPSET_APOLLO_LAKE) {
+ } else if (cs == CHIPSET_APOLLO_LAKE || cs == CHIPSET_GEMINI_LAKE || cs == CHIPSET_ELKHART_LAKE) {
const char *const master_names[] = { "BIOS", "TXE", };
if (nm > (ssize_t)ARRAY_SIZE(master_names)) {
msg_pdbg2("%s: number of masters too high (%d).\n", __func__, desc->content.NM);
@@ -826,7 +912,7 @@ void prettyprint_ich_descriptor_straps(enum ich_chipset cs, const struct ich_des
msg_pdbg2("--- North/MCH/PROC (%d entries) ---\n", max_count);
for (i = 0; i < max_count; i++)
- msg_pdbg2("STRP%-2d = 0x%08x\n", i, desc->north.STRPs[i]);
+ msg_pdbg2("STRP%-2d = 0x%08"PRIx32"\n", i, desc->north.STRPs[i]);
msg_pdbg2("\n");
max_count = MIN(ARRAY_SIZE(desc->south.STRPs), desc->content.ISL);
@@ -838,7 +924,7 @@ void prettyprint_ich_descriptor_straps(enum ich_chipset cs, const struct ich_des
msg_pdbg2("--- South/ICH/PCH (%d entries) ---\n", max_count);
for (i = 0; i < max_count; i++)
- msg_pdbg2("STRP%-2d = 0x%08x\n", i, desc->south.STRPs[i]);
+ msg_pdbg2("STRP%-2d = 0x%08"PRIx32"\n", i, desc->south.STRPs[i]);
msg_pdbg2("\n");
switch (cs) {
@@ -884,72 +970,103 @@ void prettyprint_ich_descriptor_upper_map(const struct ich_desc_upper_map *umap)
{
int i;
msg_pdbg2("=== Upper Map Section ===\n");
- msg_pdbg2("FLUMAP1 0x%08x\n", umap->FLUMAP1);
+ msg_pdbg2("FLUMAP1 0x%08"PRIx32"\n", umap->FLUMAP1);
msg_pdbg2("\n");
msg_pdbg2("--- Details ---\n");
msg_pdbg2("VTL (length in DWORDS) = %d\n", umap->VTL);
- msg_pdbg2("VTBA (base address) = 0x%6.6x\n", getVTBA(umap));
+ msg_pdbg2("VTBA (base address) = 0x%6.6"PRIx32"\n", getVTBA(umap));
msg_pdbg2("\n");
msg_pdbg2("VSCC Table: %d entries\n", umap->VTL/2);
for (i = 0; i < umap->VTL/2; i++) {
uint32_t jid = umap->vscc_table[i].JID;
uint32_t vscc = umap->vscc_table[i].VSCC;
- msg_pdbg2(" JID%d = 0x%08x\n", i, jid);
- msg_pdbg2(" VSCC%d = 0x%08x\n", i, vscc);
- msg_pdbg2(" "); /* indention */
+ msg_pdbg2(" JID%d = 0x%08"PRIx32"\n", i, jid);
+ msg_pdbg2(" VSCC%d = 0x%08"PRIx32"\n", i, vscc);
+ msg_pdbg2(" "); /* indentation */
prettyprint_rdid(jid);
- msg_pdbg2(" "); /* indention */
+ msg_pdbg2(" "); /* indentation */
prettyprint_ich_reg_vscc(vscc, 0, false);
}
msg_pdbg2("\n");
}
+static inline void warn_peculiar_desc(const char *const name)
+{
+ msg_pwarn("Peculiar flash descriptor, assuming %s compatibility.\n", name);
+}
+
/*
* Guesses a minimum chipset version based on the maximum number of
- * soft straps per generation.
+ * soft straps per generation and presence of the MIP base (MDTBA).
*/
-static enum ich_chipset guess_ich_chipset_from_content(const struct ich_desc_content *const content)
+static enum ich_chipset guess_ich_chipset_from_content(const struct ich_desc_content *const content,
+ const struct ich_desc_upper_map *const upper)
{
if (content->ICCRIBA == 0x00) {
if (content->MSL == 0 && content->ISL <= 2)
return CHIPSET_ICH8;
- else if (content->ISL <= 2)
+ if (content->ISL <= 2)
return CHIPSET_ICH9;
- else if (content->ISL <= 10)
+ if (content->ISL <= 10)
return CHIPSET_ICH10;
- else if (content->ISL <= 16)
+ if (content->ISL <= 16)
return CHIPSET_5_SERIES_IBEX_PEAK;
- else if (content->FLMAP2 == 0) {
- if (content->ISL != 19)
- msg_pwarn("Peculiar firmware descriptor, assuming Apollo Lake compatibility.\n");
- return CHIPSET_APOLLO_LAKE;
+ if (content->FLMAP2 == 0) {
+ if (content->ISL == 19)
+ return CHIPSET_APOLLO_LAKE;
+ if (content->ISL == 23)
+ return CHIPSET_GEMINI_LAKE;
+ warn_peculiar_desc("Gemini Lake");
+ return CHIPSET_GEMINI_LAKE;
}
- msg_pwarn("Peculiar firmware descriptor, assuming Ibex Peak compatibility.\n");
+ if (content->ISL <= 80)
+ return CHIPSET_C620_SERIES_LEWISBURG;
+ warn_peculiar_desc("Ibex Peak");
return CHIPSET_5_SERIES_IBEX_PEAK;
- } else if (content->ICCRIBA < 0x31 && content->FMSBA < 0x30) {
- if (content->MSL == 0 && content->ISL <= 17)
- return CHIPSET_BAYTRAIL;
- else if (content->MSL <= 1 && content->ISL <= 18)
- return CHIPSET_6_SERIES_COUGAR_POINT;
- else if (content->MSL <= 1 && content->ISL <= 21)
+ } else if (upper->MDTBA == 0x00) {
+ if (content->ICCRIBA < 0x31 && content->FMSBA < 0x30) {
+ if (content->MSL == 0 && content->ISL <= 17)
+ return CHIPSET_BAYTRAIL;
+ if (content->MSL <= 1 && content->ISL <= 18)
+ return CHIPSET_6_SERIES_COUGAR_POINT;
+ if (content->MSL <= 1 && content->ISL <= 21)
+ return CHIPSET_8_SERIES_LYNX_POINT;
+ warn_peculiar_desc("Lynx Point");
return CHIPSET_8_SERIES_LYNX_POINT;
- msg_pwarn("Peculiar firmware descriptor, assuming Wildcat Point compatibility.\n");
- return CHIPSET_9_SERIES_WILDCAT_POINT;
- } else if (content->ICCRIBA < 0x34) {
- if (content->NM == 6)
+ }
+ if (content->NM == 6) {
+ if (content->ICCRIBA <= 0x34)
+ return CHIPSET_C620_SERIES_LEWISBURG;
+ warn_peculiar_desc("C620 series");
return CHIPSET_C620_SERIES_LEWISBURG;
- else
+ }
+ if (content->ICCRIBA == 0x31)
return CHIPSET_100_SERIES_SUNRISE_POINT;
- } else if (content->ICCRIBA == 0x34) {
- if (content->NM == 6)
- return CHIPSET_C620_SERIES_LEWISBURG;
- else
- return CHIPSET_300_SERIES_CANNON_POINT;
+ warn_peculiar_desc("100 series");
+ return CHIPSET_100_SERIES_SUNRISE_POINT;
} else {
- msg_pwarn("Unknown firmware descriptor, assuming 300 series compatibility.\n");
- return CHIPSET_300_SERIES_CANNON_POINT;
+ if (content->ICCRIBA == 0x34)
+ return CHIPSET_300_SERIES_CANNON_POINT;
+ if (content->CSSL == 0x11) {
+ if (content->CSSO == 0x68)
+ return CHIPSET_500_SERIES_TIGER_POINT;
+ else if (content->CSSO == 0x5c)
+ return CHIPSET_600_SERIES_ALDER_POINT;
+ }
+ if (content->CSSL == 0x14)
+ return CHIPSET_600_SERIES_ALDER_POINT;
+ if (content->CSSL == 0x03) {
+ if (content->CSSO == 0x58)
+ return CHIPSET_ELKHART_LAKE;
+ else if (content->CSSO == 0x6c)
+ return CHIPSET_JASPER_LAKE;
+ else if (content->CSSO == 0x70)
+ return CHIPSET_METEOR_LAKE;
+ }
+ msg_pwarn("Unknown flash descriptor, assuming 500 series compatibility.\n");
+ return CHIPSET_500_SERIES_TIGER_POINT;
}
}
@@ -960,36 +1077,41 @@ static enum ich_chipset guess_ich_chipset_from_content(const struct ich_desc_con
* tinction because of the dropped number of regions field (NR).
*/
static enum ich_chipset guess_ich_chipset(const struct ich_desc_content *const content,
- const struct ich_desc_component *const component)
+ const struct ich_desc_component *const component,
+ const struct ich_desc_upper_map *const upper)
{
- const enum ich_chipset guess = guess_ich_chipset_from_content(content);
+ const enum ich_chipset guess = guess_ich_chipset_from_content(content, upper);
switch (guess) {
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
/* `freq_read` was repurposed, so can't check on it any more. */
- return guess;
+ break;
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_APOLLO_LAKE:
if (component->modes.freq_read != 6) {
- msg_pwarn("\nThe firmware descriptor looks like a Skylake/Sunrise Point descriptor.\n"
+ msg_pwarn("\nThe flash descriptor looks like a Skylake/Sunrise Point descriptor.\n"
"However, the read frequency isn't set to 17MHz (the only valid value).\n"
"Please report this message, the output of `ich_descriptors_tool` for\n"
"your descriptor and the output of `lspci -nn` to flashrom@flashrom.org\n\n");
- return CHIPSET_9_SERIES_WILDCAT_POINT;
}
- return guess;
+ break;
default:
if (component->modes.freq_read == 6) {
- msg_pwarn("\nThe firmware descriptor has the read frequency set to 17MHz. However,\n"
+ msg_pwarn("\nThe flash descriptor has the read frequency set to 17MHz. However,\n"
"it doesn't look like a Skylake/Sunrise Point compatible descriptor.\n"
"Please report this message, the output of `ich_descriptors_tool` for\n"
"your descriptor and the output of `lspci -nn` to flashrom@flashrom.org\n\n");
- return CHIPSET_100_SERIES_SUNRISE_POINT;
}
- return guess;
}
+ return guess;
}
/* len is the length of dump in bytes */
@@ -1024,8 +1146,25 @@ int read_ich_descriptors_from_dump(const uint32_t *const dump, const size_t len,
desc->component.FLILL = dump[(getFCBA(&desc->content) >> 2) + 1];
desc->component.FLPB = dump[(getFCBA(&desc->content) >> 2) + 2];
+ /* upper map */
+ desc->upper.FLUMAP1 = dump[(UPPER_MAP_OFFSET >> 2) + 0];
+
+ /* VTL is 8 bits long. Quote from the Ibex Peak SPI programming guide:
+ * "Identifies the 1s based number of DWORDS contained in the VSCC
+ * Table. Each SPI component entry in the table is 2 DWORDS long." So
+ * the maximum of 255 gives us 127.5 SPI components(!?) 8 bytes each. A
+ * check ensures that the maximum offset actually accessed is available.
+ */
+ if (len < getVTBA(&desc->upper) + (desc->upper.VTL / 2 * 8))
+ return ICH_RET_OOB;
+
+ for (i = 0; i < desc->upper.VTL/2; i++) {
+ desc->upper.vscc_table[i].JID = dump[(getVTBA(&desc->upper) >> 2) + i * 2 + 0];
+ desc->upper.vscc_table[i].VSCC = dump[(getVTBA(&desc->upper) >> 2) + i * 2 + 1];
+ }
+
if (*cs == CHIPSET_ICH_UNKNOWN) {
- *cs = guess_ich_chipset(&desc->content, &desc->component);
+ *cs = guess_ich_chipset(&desc->content, &desc->component, &desc->upper);
prettyprint_ich_chipset(*cs);
}
@@ -1043,23 +1182,6 @@ int read_ich_descriptors_from_dump(const uint32_t *const dump, const size_t len,
for (i = 0; i < nm; i++)
desc->master.FLMSTRs[i] = dump[(getFMBA(&desc->content) >> 2) + i];
- /* upper map */
- desc->upper.FLUMAP1 = dump[(UPPER_MAP_OFFSET >> 2) + 0];
-
- /* VTL is 8 bits long. Quote from the Ibex Peak SPI programming guide:
- * "Identifies the 1s based number of DWORDS contained in the VSCC
- * Table. Each SPI component entry in the table is 2 DWORDS long." So
- * the maximum of 255 gives us 127.5 SPI components(!?) 8 bytes each. A
- * check ensures that the maximum offset actually accessed is available.
- */
- if (len < getVTBA(&desc->upper) + (desc->upper.VTL / 2 * 8))
- return ICH_RET_OOB;
-
- for (i = 0; i < desc->upper.VTL/2; i++) {
- desc->upper.vscc_table[i].JID = dump[(getVTBA(&desc->upper) >> 2) + i * 2 + 0];
- desc->upper.vscc_table[i].VSCC = dump[(getVTBA(&desc->upper) >> 2) + i * 2 + 1];
- }
-
/* MCH/PROC (aka. North) straps */
if (len < getFMSBA(&desc->content) + desc->content.MSL * 4)
return ICH_RET_OOB;
@@ -1122,7 +1244,13 @@ int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
if (idx == 0) {
size_enc = desc->component.dens_new.comp1_density;
} else {
@@ -1151,20 +1279,33 @@ int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors
static uint32_t read_descriptor_reg(enum ich_chipset cs, uint8_t section, uint16_t offset, void *spibar)
{
uint32_t control = 0;
+ uint32_t woffset, roffset;
+
control |= (section << FDOC_FDSS_OFF) & FDOC_FDSS;
control |= (offset << FDOC_FDSI_OFF) & FDOC_FDSI;
+
switch (cs) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
- mmio_le_writel(control, spibar + PCH100_REG_FDOC);
- return mmio_le_readl(spibar + PCH100_REG_FDOD);
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
+ woffset = PCH100_REG_FDOC;
+ roffset = PCH100_REG_FDOD;
+ break;
default:
- mmio_le_writel(control, spibar + ICH9_REG_FDOC);
- return mmio_le_readl(spibar + ICH9_REG_FDOD);
+ woffset = ICH9_REG_FDOC;
+ roffset = ICH9_REG_FDOD;
}
+
+ mmio_le_writel(control, spibar + woffset);
+ return mmio_le_readl(spibar + roffset);
}
int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_descriptors *desc)
@@ -1246,7 +1387,9 @@ int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_d
* 1 if the descriptor couldn't be parsed,
* 2 when out of memory.
*/
-int layout_from_ich_descriptors(struct ich_layout *const layout, const void *const dump, const size_t len)
+int layout_from_ich_descriptors(
+ struct flashrom_layout **const layout,
+ const void *const dump, const size_t len)
{
static const char *const regions[] = {
"fd", "bios", "me", "gbe", "pd", "reg5", "bios2", "reg7", "ec", "reg9", "ie",
@@ -1262,25 +1405,22 @@ int layout_from_ich_descriptors(struct ich_layout *const layout, const void *con
return 1;
}
- memset(layout, 0x00, sizeof(*layout));
+ if (flashrom_layout_new(layout))
+ return 2;
- ssize_t i, j;
+ ssize_t i;
const ssize_t nr = MIN(ich_number_of_regions(cs, &desc.content), (ssize_t)ARRAY_SIZE(regions));
- for (i = 0, j = 0; i < nr; ++i) {
+ for (i = 0; i < nr; ++i) {
const chipoff_t base = ICH_FREG_BASE(desc.region.FLREGs[i]);
const chipoff_t limit = ICH_FREG_LIMIT(desc.region.FLREGs[i]);
if (limit <= base)
continue;
- layout->entries[j].start = base;
- layout->entries[j].end = limit;
- layout->entries[j].included = false;
- layout->entries[j].name = strdup(regions[i]);
- if (!layout->entries[j].name)
+ if (flashrom_layout_add_region(*layout, base, limit, regions[i])) {
+ flashrom_layout_release(*layout);
+ *layout = NULL;
return 2;
- ++j;
+ }
}
- layout->base.entries = layout->entries;
- layout->base.num_entries = j;
return 0;
}
diff --git a/ichspi.c b/ichspi.c
index 4209d6031..2e38ff17c 100644
--- a/ichspi.c
+++ b/ichspi.c
@@ -19,13 +19,12 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
#include "spi.h"
#include "ich_descriptors.h"
@@ -47,12 +46,41 @@
* however we still treat them separately in order to reuse code.
*/
-/* Changed HSFC Control bits */
-#define PCH100_HSFC_FCYCLE_OFF (17 - 16) /* 1-4: FLASH Cycle */
-#define PCH100_HSFC_FCYCLE (0xf << PCH100_HSFC_FCYCLE_OFF)
+/*
+ * HSFC Control bits
+ *
+ * FCYCLE is a 2 bit field (HSFC bits 1-2) on ICH9 and 4 bit field
+ * (HSFC bits 1-4) on PCH100.
+ *
+ * ICH9 and PCH100 use the same FCYCLE values for flash operations,
+ * however FCYCLE values above 3 are only supported by PCH100.
+ *
+ * 0: SPI Read
+ * 2: SPI Write
+ * 3: SPI Erase 4K
+ * 4: SPI Erase 64K
+ * 6: SPI RDID
+ * 7: SPI Write Status
+ * 8: SPI Read Status
+ */
+#define HSFC_FGO_OFF 0
+#define HSFC_FGO (0x1 << HSFC_FGO_OFF)
+#define HSFC_FCYCLE_MASK(n) ((n) << HSFC_FCYCLE_OFF)
+#define HSFC_FCYCLE_OFF 1
+#define HSFC_CYCLE_READ HSFC_FCYCLE_MASK(0x0)
+#define HSFC_CYCLE_WRITE HSFC_FCYCLE_MASK(0x2)
+#define HSFC_CYCLE_BLOCK_ERASE HSFC_FCYCLE_MASK(0x3)
+#define HSFC_CYCLE_RDID HSFC_FCYCLE_MASK(0x6)
+#define HSFC_CYCLE_WR_STATUS HSFC_FCYCLE_MASK(0x7)
+#define HSFC_CYCLE_RD_STATUS HSFC_FCYCLE_MASK(0x8)
+
+/* PCH100 controller register definition */
+#define PCH100_HSFC_FCYCLE_OFF 1
+#define PCH100_HSFC_FCYCLE_BIT_WIDTH 0xf
+#define PCH100_HSFC_FCYCLE HSFC_FCYCLE_MASK(PCH100_HSFC_FCYCLE_BIT_WIDTH)
/* New HSFC Control bit */
-#define HSFC_WET_OFF (21 - 16) /* 5: Write Enable Type */
-#define HSFC_WET (0x1 << HSFC_WET_OFF)
+#define PCH100_HSFC_WET_OFF (21 - 16) /* 5: Write Enable Type */
+#define PCH100_HSFC_WET (0x1 << PCH100_HSFC_WET_OFF)
#define PCH100_FADDR_FLA 0x07ffffff
@@ -107,13 +135,16 @@
#define HSFS_FLOCKDN (0x1 << HSFS_FLOCKDN_OFF)
#define ICH9_REG_HSFC 0x06 /* 16 Bits Hardware Sequencing Flash Control */
-#define HSFC_FGO_OFF 0 /* 0: Flash Cycle Go */
-#define HSFC_FGO (0x1 << HSFC_FGO_OFF)
-#define HSFC_FCYCLE_OFF 1 /* 1-2: FLASH Cycle */
-#define HSFC_FCYCLE (0x3 << HSFC_FCYCLE_OFF)
+
+ /* 0: Flash Cycle Go */
+ /* 1-2: FLASH Cycle */
+#define ICH9_HSFC_FCYCLE_OFF 1
+#define ICH9_HSFC_FCYCLE_BIT_WIDTH 3
+#define ICH9_HSFC_FCYCLE HSFC_FCYCLE_MASK(ICH9_HSFC_FCYCLE_BIT_WIDTH)
/* 3-7: reserved */
#define HSFC_FDBC_OFF 8 /* 8-13: Flash Data Byte Count */
#define HSFC_FDBC (0x3f << HSFC_FDBC_OFF)
+#define HSFC_FDBC_VAL(n) (((n) << HSFC_FDBC_OFF) & HSFC_FDBC)
/* 14: reserved */
#define HSFC_SME_OFF 15 /* 15: SPI SMI# Enable */
#define HSFC_SME (0x1 << HSFC_SME_OFF)
@@ -232,7 +263,7 @@ enum ich_access_protection {
};
/* ICH SPI configuration lock-down. May be set during chipset enabling. */
-static int ichspi_lock = 0;
+static bool ichspi_lock = false;
static enum ich_chipset ich_generation = CHIPSET_ICH_UNKNOWN;
static uint32_t ichspi_bbar;
@@ -286,12 +317,40 @@ static uint16_t REGREAD8(int X)
#define REGWRITE8(off, val) mmio_writeb(val, ich_spibar+(off))
/* Common SPI functions */
-static int find_opcode(OPCODES *op, uint8_t opcode);
-static int find_preop(OPCODES *op, uint8_t preop);
-static int generate_opcodes(OPCODES * op, enum ich_chipset ich_gen);
-static int program_opcodes(OPCODES *op, int enable_undo, enum ich_chipset ich_gen);
-static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset,
- uint8_t datalength, uint8_t * data);
+
+static int find_opcode(OPCODES *op, uint8_t opcode)
+{
+ int a;
+
+ if (op == NULL) {
+ msg_perr("\n%s: null OPCODES pointer!\n", __func__);
+ return -1;
+ }
+
+ for (a = 0; a < 8; a++) {
+ if (op->opcode[a].opcode == opcode)
+ return a;
+ }
+
+ return -1;
+}
+
+static int find_preop(OPCODES *op, uint8_t preop)
+{
+ int a;
+
+ if (op == NULL) {
+ msg_perr("\n%s: null OPCODES pointer!\n", __func__);
+ return -1;
+ }
+
+ for (a = 0; a < 2; a++) {
+ if (op->preop[a] == preop)
+ return a;
+ }
+
+ return -1;
+}
/* for pairing opcodes with their required preop */
struct preop_opcode_pair {
@@ -386,99 +445,105 @@ static void prettyprint_opcodes(OPCODES *ops)
ops->preop[1]);
}
-#define _pprint_reg(bit, mask, off, val, sep) msg_pdbg("%s=%d" sep, #bit, (val & mask) >> off)
-#define pprint_reg(reg, bit, val, sep) _pprint_reg(bit, reg##_##bit, reg##_##bit##_OFF, val, sep)
+#define pprint_reg16(reg, bit, val, sep) msg_pdbg("%s=%"PRId16"" sep, #bit, (val & reg##_##bit) >> reg##_##bit##_OFF)
+#define pprint_reg32(reg, bit, val, sep) msg_pdbg("%s=%"PRId32"" sep, #bit, (val & reg##_##bit) >> reg##_##bit##_OFF)
static void prettyprint_ich9_reg_hsfs(uint16_t reg_val, enum ich_chipset ich_gen)
{
msg_pdbg("HSFS: ");
- pprint_reg(HSFS, FDONE, reg_val, ", ");
- pprint_reg(HSFS, FCERR, reg_val, ", ");
- pprint_reg(HSFS, AEL, reg_val, ", ");
+ pprint_reg16(HSFS, FDONE, reg_val, ", ");
+ pprint_reg16(HSFS, FCERR, reg_val, ", ");
+ pprint_reg16(HSFS, AEL, reg_val, ", ");
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_ELKHART_LAKE:
break;
default:
- pprint_reg(HSFS, BERASE, reg_val, ", ");
+ pprint_reg16(HSFS, BERASE, reg_val, ", ");
break;
}
- pprint_reg(HSFS, SCIP, reg_val, ", ");
+ pprint_reg16(HSFS, SCIP, reg_val, ", ");
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
- pprint_reg(HSFS, PRR34_LOCKDN, reg_val, ", ");
- pprint_reg(HSFS, WRSDIS, reg_val, ", ");
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_ELKHART_LAKE:
+ pprint_reg16(HSFS, PRR34_LOCKDN, reg_val, ", ");
+ pprint_reg16(HSFS, WRSDIS, reg_val, ", ");
break;
default:
break;
}
- pprint_reg(HSFS, FDOPSS, reg_val, ", ");
- pprint_reg(HSFS, FDV, reg_val, ", ");
- pprint_reg(HSFS, FLOCKDN, reg_val, "\n");
+ pprint_reg16(HSFS, FDOPSS, reg_val, ", ");
+ pprint_reg16(HSFS, FDV, reg_val, ", ");
+ pprint_reg16(HSFS, FLOCKDN, reg_val, "\n");
}
static void prettyprint_ich9_reg_hsfc(uint16_t reg_val, enum ich_chipset ich_gen)
{
msg_pdbg("HSFC: ");
- pprint_reg(HSFC, FGO, reg_val, ", ");
+ pprint_reg16(HSFC, FGO, reg_val, ", ");
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
- _pprint_reg(HSFC, PCH100_HSFC_FCYCLE, PCH100_HSFC_FCYCLE_OFF, reg_val, ", ");
- pprint_reg(HSFC, WET, reg_val, ", ");
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_ELKHART_LAKE:
+ pprint_reg16(PCH100_HSFC, FCYCLE, reg_val, ", ");
+ pprint_reg16(PCH100_HSFC, WET, reg_val, ", ");
break;
default:
- pprint_reg(HSFC, FCYCLE, reg_val, ", ");
+ pprint_reg16(ICH9_HSFC, FCYCLE, reg_val, ", ");
break;
}
- pprint_reg(HSFC, FDBC, reg_val, ", ");
- pprint_reg(HSFC, SME, reg_val, "\n");
+ pprint_reg16(HSFC, FDBC, reg_val, ", ");
+ pprint_reg16(HSFC, SME, reg_val, "\n");
}
static void prettyprint_ich9_reg_ssfs(uint32_t reg_val)
{
msg_pdbg("SSFS: ");
- pprint_reg(SSFS, SCIP, reg_val, ", ");
- pprint_reg(SSFS, FDONE, reg_val, ", ");
- pprint_reg(SSFS, FCERR, reg_val, ", ");
- pprint_reg(SSFS, AEL, reg_val, "\n");
+ pprint_reg32(SSFS, SCIP, reg_val, ", ");
+ pprint_reg32(SSFS, FDONE, reg_val, ", ");
+ pprint_reg32(SSFS, FCERR, reg_val, ", ");
+ pprint_reg32(SSFS, AEL, reg_val, "\n");
}
static void prettyprint_ich9_reg_ssfc(uint32_t reg_val)
{
msg_pdbg("SSFC: ");
- pprint_reg(SSFC, SCGO, reg_val, ", ");
- pprint_reg(SSFC, ACS, reg_val, ", ");
- pprint_reg(SSFC, SPOP, reg_val, ", ");
- pprint_reg(SSFC, COP, reg_val, ", ");
- pprint_reg(SSFC, DBC, reg_val, ", ");
- pprint_reg(SSFC, SME, reg_val, ", ");
- pprint_reg(SSFC, SCF, reg_val, "\n");
+ pprint_reg32(SSFC, SCGO, reg_val, ", ");
+ pprint_reg32(SSFC, ACS, reg_val, ", ");
+ pprint_reg32(SSFC, SPOP, reg_val, ", ");
+ pprint_reg32(SSFC, COP, reg_val, ", ");
+ pprint_reg32(SSFC, DBC, reg_val, ", ");
+ pprint_reg32(SSFC, SME, reg_val, ", ");
+ pprint_reg32(SSFC, SCF, reg_val, "\n");
}
static void prettyprint_pch100_reg_dlock(const uint32_t reg_val)
{
msg_pdbg("DLOCK: ");
- pprint_reg(DLOCK, BMWAG_LOCKDN, reg_val, ", ");
- pprint_reg(DLOCK, BMRAG_LOCKDN, reg_val, ", ");
- pprint_reg(DLOCK, SBMWAG_LOCKDN, reg_val, ", ");
- pprint_reg(DLOCK, SBMRAG_LOCKDN, reg_val, ",\n ");
- pprint_reg(DLOCK, PR0_LOCKDN, reg_val, ", ");
- pprint_reg(DLOCK, PR1_LOCKDN, reg_val, ", ");
- pprint_reg(DLOCK, PR2_LOCKDN, reg_val, ", ");
- pprint_reg(DLOCK, PR3_LOCKDN, reg_val, ", ");
- pprint_reg(DLOCK, PR4_LOCKDN, reg_val, ",\n ");
- pprint_reg(DLOCK, SSEQ_LOCKDN, reg_val, "\n");
+ pprint_reg32(DLOCK, BMWAG_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, BMRAG_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, SBMWAG_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, SBMRAG_LOCKDN, reg_val, ",\n ");
+ pprint_reg32(DLOCK, PR0_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, PR1_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, PR2_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, PR3_LOCKDN, reg_val, ", ");
+ pprint_reg32(DLOCK, PR4_LOCKDN, reg_val, ",\n ");
+ pprint_reg32(DLOCK, SSEQ_LOCKDN, reg_val, "\n");
}
-static struct {
+static struct swseq_data {
size_t reg_ssfsc;
size_t reg_preop;
size_t reg_optype;
@@ -497,131 +562,6 @@ static uint8_t lookup_spi_type(uint8_t opcode)
return 0xFF;
}
-static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
-{
- uint8_t spi_type;
-
- spi_type = lookup_spi_type(opcode);
- if (spi_type > 3) {
- /* Try to guess spi type from read/write sizes.
- * The following valid writecnt/readcnt combinations exist:
- * writecnt = 4, readcnt >= 0
- * writecnt = 1, readcnt >= 0
- * writecnt >= 4, readcnt = 0
- * writecnt >= 1, readcnt = 0
- * writecnt >= 1 is guaranteed for all commands.
- */
- if (readcnt == 0)
- /* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
- * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
- * bytes are actual the address, they go to the bus anyhow
- */
- spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
- else if (writecnt == 1) // and readcnt is > 0
- spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
- else if (writecnt == 4) // and readcnt is > 0
- spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
- else // we have an invalid case
- return SPI_INVALID_LENGTH;
- }
- int oppos = 2; // use original JEDEC_BE_D8 offset
- curopcodes->opcode[oppos].opcode = opcode;
- curopcodes->opcode[oppos].spi_type = spi_type;
- program_opcodes(curopcodes, 0, ich_generation);
- oppos = find_opcode(curopcodes, opcode);
- msg_pdbg2("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
- return oppos;
-}
-
-static int find_opcode(OPCODES *op, uint8_t opcode)
-{
- int a;
-
- if (op == NULL) {
- msg_perr("\n%s: null OPCODES pointer!\n", __func__);
- return -1;
- }
-
- for (a = 0; a < 8; a++) {
- if (op->opcode[a].opcode == opcode)
- return a;
- }
-
- return -1;
-}
-
-static int find_preop(OPCODES *op, uint8_t preop)
-{
- int a;
-
- if (op == NULL) {
- msg_perr("\n%s: null OPCODES pointer!\n", __func__);
- return -1;
- }
-
- for (a = 0; a < 2; a++) {
- if (op->preop[a] == preop)
- return a;
- }
-
- return -1;
-}
-
-/* Create a struct OPCODES based on what we find in the locked down chipset. */
-static int generate_opcodes(OPCODES * op, enum ich_chipset ich_gen)
-{
- int a;
- uint16_t preop, optype;
- uint32_t opmenu[2];
-
- if (op == NULL) {
- msg_perr("\n%s: null OPCODES pointer!\n", __func__);
- return -1;
- }
-
- switch (ich_gen) {
- case CHIPSET_ICH7:
- case CHIPSET_TUNNEL_CREEK:
- case CHIPSET_CENTERTON:
- preop = REGREAD16(ICH7_REG_PREOP);
- optype = REGREAD16(ICH7_REG_OPTYPE);
- opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
- opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4);
- break;
- case CHIPSET_ICH8:
- default: /* Future version might behave the same */
- preop = REGREAD16(swseq_data.reg_preop);
- optype = REGREAD16(swseq_data.reg_optype);
- opmenu[0] = REGREAD32(swseq_data.reg_opmenu);
- opmenu[1] = REGREAD32(swseq_data.reg_opmenu + 4);
- break;
- }
-
- op->preop[0] = (uint8_t) preop;
- op->preop[1] = (uint8_t) (preop >> 8);
-
- for (a = 0; a < 8; a++) {
- op->opcode[a].spi_type = (uint8_t) (optype & 0x3);
- optype >>= 2;
- }
-
- for (a = 0; a < 4; a++) {
- op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff);
- opmenu[0] >>= 8;
- }
-
- for (a = 4; a < 8; a++) {
- op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff);
- opmenu[1] >>= 8;
- }
-
- /* No preopcodes used by default. */
- for (a = 0; a < 8; a++)
- op->opcode[a].atomic = 0;
-
- return 0;
-}
-
static int program_opcodes(OPCODES *op, int enable_undo, enum ich_chipset ich_gen)
{
uint8_t a;
@@ -652,7 +592,7 @@ static int program_opcodes(OPCODES *op, int enable_undo, enum ich_chipset ich_ge
opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8);
}
- msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]);
+ msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08"PRIx32"%08"PRIx32"\n", __func__, preop, optype, opmenu[0], opmenu[1]);
switch (ich_gen) {
case CHIPSET_ICH7:
case CHIPSET_TUNNEL_CREEK:
@@ -688,6 +628,42 @@ static int program_opcodes(OPCODES *op, int enable_undo, enum ich_chipset ich_ge
return 0;
}
+static int reprogram_opcode_on_the_fly(uint8_t opcode, unsigned int writecnt, unsigned int readcnt)
+{
+ uint8_t spi_type;
+
+ spi_type = lookup_spi_type(opcode);
+ if (spi_type > 3) {
+ /* Try to guess spi type from read/write sizes.
+ * The following valid writecnt/readcnt combinations exist:
+ * writecnt = 4, readcnt >= 0
+ * writecnt = 1, readcnt >= 0
+ * writecnt >= 4, readcnt = 0
+ * writecnt >= 1, readcnt = 0
+ * writecnt >= 1 is guaranteed for all commands.
+ */
+ if (readcnt == 0)
+ /* if readcnt=0 and writecount >= 4, we don't know if it is WRITE_NO_ADDRESS
+ * or WRITE_WITH_ADDRESS. But if we use WRITE_NO_ADDRESS and the first 3 data
+ * bytes are actual the address, they go to the bus anyhow
+ */
+ spi_type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
+ else if (writecnt == 1) // and readcnt is > 0
+ spi_type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
+ else if (writecnt == 4) // and readcnt is > 0
+ spi_type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
+ else // we have an invalid case
+ return SPI_INVALID_LENGTH;
+ }
+ int oppos = 2; // use original JEDEC_BE_D8 offset
+ curopcodes->opcode[oppos].opcode = opcode;
+ curopcodes->opcode[oppos].spi_type = spi_type;
+ program_opcodes(curopcodes, 0, ich_generation);
+ oppos = find_opcode(curopcodes, opcode);
+ msg_pdbg2("on-the-fly OPCODE (0x%02X) re-programmed, op-pos=%d\n", opcode, oppos);
+ return oppos;
+}
+
/*
* Returns -1 if at least one mandatory opcode is inaccessible, 0 otherwise.
* FIXME: this should also check for
@@ -738,7 +714,7 @@ static void ich_set_bbar(uint32_t min_addr, enum ich_chipset ich_gen)
ichspi_bbar = mmio_readl(ich_spibar + bbar_off) & ~BBAR_MASK;
if (ichspi_bbar) {
- msg_pdbg("Reserved bits in BBAR not zero: 0x%08x\n",
+ msg_pdbg("Reserved bits in BBAR not zero: 0x%08"PRIx32"\n",
ichspi_bbar);
}
min_addr &= BBAR_MASK;
@@ -750,53 +726,63 @@ static void ich_set_bbar(uint32_t min_addr, enum ich_chipset ich_gen)
* failed, the restore will fail as well, so no problem there.
*/
if (ichspi_bbar != min_addr)
- msg_perr("Setting BBAR to 0x%08x failed! New value: 0x%08x.\n",
+ msg_perr("Setting BBAR to 0x%08"PRIx32" failed! New value: 0x%08"PRIx32".\n",
min_addr, ichspi_bbar);
}
-/* Read len bytes from the fdata/spid register into the data array.
- *
- * Note that using len > flash->mst->spi.max_data_read will return garbage or
- * may even crash.
- */
-static void ich_read_data(uint8_t *data, int len, int reg0_off)
+/* Create a struct OPCODES based on what we find in the locked down chipset. */
+static int generate_opcodes(OPCODES * op, enum ich_chipset ich_gen)
{
- int i;
- uint32_t temp32 = 0;
-
- for (i = 0; i < len; i++) {
- if ((i % 4) == 0)
- temp32 = REGREAD32(reg0_off + i);
+ int a;
+ uint16_t preop, optype;
+ uint32_t opmenu[2];
- data[i] = (temp32 >> ((i % 4) * 8)) & 0xff;
+ if (op == NULL) {
+ msg_perr("\n%s: null OPCODES pointer!\n", __func__);
+ return -1;
}
-}
-/* Fill len bytes from the data array into the fdata/spid registers.
- *
- * Note that using len > flash->mst->spi.max_data_write will trash the registers
- * following the data registers.
- */
-static void ich_fill_data(const uint8_t *data, int len, int reg0_off)
-{
- uint32_t temp32 = 0;
- int i;
+ switch (ich_gen) {
+ case CHIPSET_ICH7:
+ case CHIPSET_TUNNEL_CREEK:
+ case CHIPSET_CENTERTON:
+ preop = REGREAD16(ICH7_REG_PREOP);
+ optype = REGREAD16(ICH7_REG_OPTYPE);
+ opmenu[0] = REGREAD32(ICH7_REG_OPMENU);
+ opmenu[1] = REGREAD32(ICH7_REG_OPMENU + 4);
+ break;
+ case CHIPSET_ICH8:
+ default: /* Future version might behave the same */
+ preop = REGREAD16(swseq_data.reg_preop);
+ optype = REGREAD16(swseq_data.reg_optype);
+ opmenu[0] = REGREAD32(swseq_data.reg_opmenu);
+ opmenu[1] = REGREAD32(swseq_data.reg_opmenu + 4);
+ break;
+ }
- if (len <= 0)
- return;
+ op->preop[0] = (uint8_t) preop;
+ op->preop[1] = (uint8_t) (preop >> 8);
- for (i = 0; i < len; i++) {
- if ((i % 4) == 0)
- temp32 = 0;
+ for (a = 0; a < 8; a++) {
+ op->opcode[a].spi_type = (uint8_t) (optype & 0x3);
+ optype >>= 2;
+ }
- temp32 |= ((uint32_t) data[i]) << ((i % 4) * 8);
+ for (a = 0; a < 4; a++) {
+ op->opcode[a].opcode = (uint8_t) (opmenu[0] & 0xff);
+ opmenu[0] >>= 8;
+ }
- if ((i % 4) == 3) /* 32 bits are full, write them to regs. */
- REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+ for (a = 4; a < 8; a++) {
+ op->opcode[a].opcode = (uint8_t) (opmenu[1] & 0xff);
+ opmenu[1] >>= 8;
}
- i--;
- if ((i % 4) != 3) /* Write remaining data to regs. */
- REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+
+ /* No preopcodes used by default. */
+ for (a = 0; a < 8; a++)
+ op->opcode[a].atomic = 0;
+
+ return 0;
}
/* This function generates OPCODES from or programs OPCODES to ICH according to
@@ -834,10 +820,55 @@ static int ich_init_opcodes(enum ich_chipset ich_gen)
}
}
+/* Fill len bytes from the data array into the fdata/spid registers.
+ *
+ * Note that using len > flash->mst->spi.max_data_write will trash the registers
+ * following the data registers.
+ */
+static void ich_fill_data(const uint8_t *data, int len, int reg0_off)
+{
+ uint32_t temp32 = 0;
+ int i;
+
+ if (len <= 0)
+ return;
+
+ for (i = 0; i < len; i++) {
+ if ((i % 4) == 0)
+ temp32 = 0;
+
+ temp32 |= ((uint32_t) data[i]) << ((i % 4) * 8);
+
+ if ((i % 4) == 3) /* 32 bits are full, write them to regs. */
+ REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+ }
+ i--;
+ if ((i % 4) != 3) /* Write remaining data to regs. */
+ REGWRITE32(reg0_off + (i - (i % 4)), temp32);
+}
+
+/* Read len bytes from the fdata/spid register into the data array.
+ *
+ * Note that using len > flash->mst->spi.max_data_read will return garbage or
+ * may even crash.
+ */
+static void ich_read_data(uint8_t *data, int len, int reg0_off)
+{
+ int i;
+ uint32_t temp32 = 0;
+
+ for (i = 0; i < len; i++) {
+ if ((i % 4) == 0)
+ temp32 = REGREAD32(reg0_off + i);
+
+ data[i] = (temp32 >> ((i % 4) * 8)) & 0xff;
+ }
+}
+
static int ich7_run_opcode(OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data, int maxdata)
{
- int write_cmd = 0;
+ bool write_cmd = false;
int timeout;
uint32_t temp32;
uint16_t temp16;
@@ -847,12 +878,12 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
/* Is it a write command? */
if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
|| (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
- write_cmd = 1;
+ write_cmd = true;
}
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
while ((REGREAD16(ICH7_REG_SPIS) & SPIS_SCIP) && --timeout) {
- programmer_delay(10);
+ default_delay(10);
}
if (!timeout) {
msg_perr("Error: SCIP never cleared!\n");
@@ -928,11 +959,10 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
/* Wait for Cycle Done Status or Flash Cycle Error. */
while (((REGREAD16(ICH7_REG_SPIS) & (SPIS_CDS | SPIS_FCERR)) == 0) &&
--timeout) {
- programmer_delay(10);
+ default_delay(10);
}
if (!timeout) {
- msg_perr("timeout, ICH7_REG_SPIS=0x%04x\n",
- REGREAD16(ICH7_REG_SPIS));
+ msg_perr("timeout, ICH7_REG_SPIS=0x%04x\n", REGREAD16(ICH7_REG_SPIS));
return 1;
}
@@ -955,7 +985,7 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset,
static int ich9_run_opcode(OPCODE op, uint32_t offset,
uint8_t datalength, uint8_t * data)
{
- int write_cmd = 0;
+ bool write_cmd = false;
int timeout;
uint32_t temp32;
uint64_t opmenu;
@@ -964,12 +994,12 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
/* Is it a write command? */
if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)
|| (op.spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS)) {
- write_cmd = 1;
+ write_cmd = true;
}
timeout = 100 * 60; /* 60 ms are 9.6 million cycles at 16 MHz. */
while ((REGREAD8(swseq_data.reg_ssfsc) & SSFS_SCIP) && --timeout) {
- programmer_delay(10);
+ default_delay(10);
}
if (!timeout) {
msg_perr("Error: SCIP never cleared!\n");
@@ -977,7 +1007,7 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
}
/* Program offset in flash into FADDR while preserve the reserved bits
- * and clearing the 25. address bit which is only useable in hwseq. */
+ * and clearing the 25. address bit which is only usable in hwseq. */
temp32 = REGREAD32(ICH9_REG_FADDR) & ~0x01FFFFFF;
REGWRITE32(ICH9_REG_FADDR, (offset & 0x00FFFFFF) | temp32);
@@ -1000,8 +1030,7 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
if (datalength != 0) {
uint32_t datatemp;
temp32 |= SSFC_DS;
- datatemp = ((((uint32_t)datalength - 1) << SSFC_DBC_OFF) &
- SSFC_DBC);
+ datatemp = ((((uint32_t)datalength - 1) << SSFC_DBC_OFF) & SSFC_DBC);
temp32 |= datatemp;
}
@@ -1050,11 +1079,10 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset,
/* Wait for Cycle Done Status or Flash Cycle Error. */
while (((REGREAD32(swseq_data.reg_ssfsc) & (SSFS_FDONE | SSFS_FCERR)) == 0) &&
--timeout) {
- programmer_delay(10);
+ default_delay(10);
}
if (!timeout) {
- msg_perr("timeout, REG_SSFS=0x%08x\n",
- REGREAD32(swseq_data.reg_ssfsc));
+ msg_perr("timeout, REG_SSFS=0x%08"PRIx32"\n", REGREAD32(swseq_data.reg_ssfsc));
return 1;
}
@@ -1128,8 +1156,7 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
msg_pdbg("OPCODE 0x%02x has unsupported length, will not execute.\n", cmd);
return SPI_INVALID_LENGTH;
} else if (opcode_index == -1) {
- msg_pdbg("Invalid OPCODE 0x%02x, will not execute.\n",
- cmd);
+ msg_pdbg("Invalid OPCODE 0x%02x, will not execute.\n", cmd);
return SPI_INVALID_OPCODE;
}
}
@@ -1146,30 +1173,26 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS) &&
(writecnt != 4)) {
msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got writecnt=%i, want =4\n", __func__, cmd,
- writecnt);
+ "0x%02x, got writecnt=%i, want =4\n", __func__, cmd, writecnt);
return SPI_INVALID_LENGTH;
}
if ((opcode->spi_type == SPI_OPCODE_TYPE_READ_NO_ADDRESS) &&
(writecnt != 1)) {
msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got writecnt=%i, want =1\n", __func__, cmd,
- writecnt);
+ "0x%02x, got writecnt=%i, want =1\n", __func__, cmd, writecnt);
return SPI_INVALID_LENGTH;
}
if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) &&
(writecnt < 4)) {
msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got writecnt=%i, want >=4\n", __func__, cmd,
- writecnt);
+ "0x%02x, got writecnt=%i, want >=4\n", __func__, cmd, writecnt);
return SPI_INVALID_LENGTH;
}
if (((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
(opcode->spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS)) &&
(readcnt)) {
msg_perr("%s: Internal command size error for opcode "
- "0x%02x, got readcnt=%i, want =0\n", __func__, cmd,
- readcnt);
+ "0x%02x, got readcnt=%i, want =0\n", __func__, cmd, readcnt);
return SPI_INVALID_LENGTH;
}
@@ -1208,7 +1231,7 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
if (addr < valid_base ||
addr_end < addr || /* integer overflow check */
addr_end > valid_end) {
- msg_perr("%s: Addressed region 0x%06x-0x%06x not in allowed range 0x%06x-0x%06x\n",
+ msg_perr("%s: Addressed region 0x%06"PRIx32"-0x%06"PRIx32" not in allowed range 0x%06"PRIx32"-0x%06"PRIx32"\n",
__func__, addr, addr_end - 1, valid_base, valid_end - 1);
return SPI_INVALID_ADDRESS;
}
@@ -1220,7 +1243,7 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
msg_pdbg("Running OPCODE 0x%02x failed ", opcode->opcode);
if ((opcode->spi_type == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS) ||
(opcode->spi_type == SPI_OPCODE_TYPE_READ_WITH_ADDRESS)) {
- msg_pdbg("at address 0x%06x ", addr);
+ msg_pdbg("at address 0x%06"PRIx32" ", addr);
}
msg_pdbg("(payload length was %d).\n", count);
@@ -1232,7 +1255,7 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
int i;
msg_pspew("The data was:\n");
for (i = 0; i < count; i++){
- msg_pspew("%3d: 0x%02x\n", i, data[i]);
+ msg_pspew("%3d: 0x%02"PRIx8"\n", i, data[i]);
}
}
}
@@ -1240,19 +1263,34 @@ static int ich_spi_send_command(const struct flashctx *flash, unsigned int write
return result;
}
-static struct hwseq_data {
+#define MAX_FD_REGIONS 16
+struct fd_region {
+ const char* name;
+ enum ich_access_protection level;
+ uint32_t base;
+ uint32_t limit;
+};
+
+struct hwseq_data {
uint32_t size_comp0;
uint32_t size_comp1;
uint32_t addr_mask;
bool only_4k;
uint32_t hsfc_fcycle;
-} hwseq_data;
-/* Sets FLA in FADDR to (addr & hwseq_data.addr_mask) without touching other bits. */
-static void ich_hwseq_set_addr(uint32_t addr)
+ struct fd_region fd_regions[MAX_FD_REGIONS];
+};
+
+static struct hwseq_data *get_hwseq_data_from_context(const struct flashctx *flash)
{
- uint32_t addr_old = REGREAD32(ICH9_REG_FADDR) & ~hwseq_data.addr_mask;
- REGWRITE32(ICH9_REG_FADDR, (addr & hwseq_data.addr_mask) | addr_old);
+ return flash->mst->opaque.data;
+}
+
+/* Sets FLA in FADDR to (addr & hwseq_data->addr_mask) without touching other bits. */
+static void ich_hwseq_set_addr(uint32_t addr, uint32_t mask)
+{
+ uint32_t addr_old = REGREAD32(ICH9_REG_FADDR) & ~mask;
+ REGWRITE32(ICH9_REG_FADDR, (addr & mask) | addr_old);
}
/* Sets FADDR.FLA to 'addr' and returns the erase block size in bytes
@@ -1262,7 +1300,7 @@ static void ich_hwseq_set_addr(uint32_t addr)
* by UVSCC and LVSCC respectively. An alternative to implement this method
* would be by querying FPB and the respective VSCC register directly.
*/
-static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr)
+static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr, uint32_t addr_mask, bool only_4k)
{
uint8_t enc_berase;
static const uint32_t dec_berase[4] = {
@@ -1272,11 +1310,11 @@ static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr)
64 * 1024
};
- if (hwseq_data.only_4k) {
+ if (only_4k) {
return 4 * 1024;
}
- ich_hwseq_set_addr(addr);
+ ich_hwseq_set_addr(addr, addr_mask);
enc_berase = (REGREAD16(ICH9_REG_HSFS) & HSFS_BERASE) >> HSFS_BERASE_OFF;
return dec_berase[enc_berase];
}
@@ -1285,24 +1323,27 @@ static uint32_t ich_hwseq_get_erase_block_size(unsigned int addr)
Resets all error flags in HSFS.
Returns 0 if the cycle completes successfully without errors within
timeout us, 1 on errors. */
-static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
- unsigned int len,
- enum ich_chipset ich_gen)
+static int ich_hwseq_wait_for_cycle_complete(unsigned int len, enum ich_chipset ich_gen, uint32_t addr_mask)
{
+ /*
+ * The SPI bus may be busy due to performing operations from other masters, hence
+ * introduce the long timeout of 30s to cover the worst case scenarios as well.
+ */
+ unsigned int timeout_us = 30 * 1000 * 1000;
uint16_t hsfs;
uint32_t addr;
- timeout /= 8; /* scale timeout duration to counter */
+ timeout_us /= 8; /* scale timeout duration to counter */
while ((((hsfs = REGREAD16(ICH9_REG_HSFS)) &
(HSFS_FDONE | HSFS_FCERR)) == 0) &&
- --timeout) {
- programmer_delay(8);
+ --timeout_us) {
+ default_delay(8);
}
REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
- if (!timeout) {
- addr = REGREAD32(ICH9_REG_FADDR) & hwseq_data.addr_mask;
- msg_perr("Timeout error between offset 0x%08x and "
- "0x%08x (= 0x%08x + %d)!\n",
+ if (!timeout_us) {
+ addr = REGREAD32(ICH9_REG_FADDR) & addr_mask;
+ msg_perr("Timeout error between offset 0x%08"PRIx32" and "
+ "0x%08"PRIx32" (= 0x%08"PRIx32" + %d)!\n",
addr, addr + len - 1, addr, len - 1);
prettyprint_ich9_reg_hsfs(hsfs, ich_gen);
prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC), ich_gen);
@@ -1310,9 +1351,9 @@ static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
}
if (hsfs & HSFS_FCERR) {
- addr = REGREAD32(ICH9_REG_FADDR) & hwseq_data.addr_mask;
- msg_perr("Transaction error between offset 0x%08x and "
- "0x%08x (= 0x%08x + %d)!\n",
+ addr = REGREAD32(ICH9_REG_FADDR) & addr_mask;
+ msg_perr("Transaction error between offset 0x%08"PRIx32" and "
+ "0x%08"PRIx32" (= 0x%08"PRIx32" + %d)!\n",
addr, addr + len - 1, addr, len - 1);
prettyprint_ich9_reg_hsfs(hsfs, ich_gen);
prettyprint_ich9_reg_hsfc(REGREAD16(ICH9_REG_HSFC), ich_gen);
@@ -1321,59 +1362,287 @@ static int ich_hwseq_wait_for_cycle_complete(unsigned int timeout,
return 0;
}
+/* Fire up a transfer using the hardware sequencer. */
+static void ich_start_hwseq_xfer(const struct flashctx *flash,
+ uint32_t hsfc_cycle, uint32_t flash_addr, size_t len,
+ uint32_t addr_mask)
+{
+ /* make sure HSFC register is cleared before initiate any operation */
+ uint16_t hsfc = 0;
+
+ /* Sets flash_addr in FADDR */
+ ich_hwseq_set_addr(flash_addr, addr_mask);
+
+ /* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */
+ REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
+
+ /* Set up transaction parameters. */
+ hsfc |= hsfc_cycle;
+ /*
+ * The number of bytes transferred is the value of `FDBC` plus 1, hence,
+ * subtracted 1 from the length field.
+ * As per Intel EDS, `0b` in the FDBC represents 1 byte while `0x3f`
+ * represents 64-bytes to be transferred.
+ */
+ hsfc |= HSFC_FDBC_VAL(len - 1);
+ hsfc |= HSFC_FGO; /* start */
+ prettyprint_ich9_reg_hsfc(hsfc, ich_generation);
+ REGWRITE16(ICH9_REG_HSFC, hsfc);
+}
+
+static int ich_wait_for_hwseq_spi_cycle_complete(void)
+{
+ if (REGREAD8(ICH9_REG_HSFS) & HSFS_SCIP) {
+ msg_perr("Error: SCIP bit is unexpectedly set.\n");
+ return 1;
+ }
+ return 0;
+}
+
+/* Execute SPI flash transfer */
+static int ich_exec_sync_hwseq_xfer(const struct flashctx *flash, uint32_t hsfc_cycle, uint32_t flash_addr,
+ size_t len, enum ich_chipset ich_gen, uint32_t addr_mask)
+{
+ if (ich_wait_for_hwseq_spi_cycle_complete()) {
+ msg_perr("SPI Transaction Timeout due to previous operation in process!\n");
+ return 1;
+ }
+
+ ich_start_hwseq_xfer(flash, hsfc_cycle, flash_addr, len, addr_mask);
+ return ich_hwseq_wait_for_cycle_complete(len, ich_gen, addr_mask);
+}
+
+static void ich_get_region(const struct flashctx *flash, unsigned int addr, struct flash_region *region)
+{
+ struct ich_descriptors desc = { 0 };
+ const ssize_t nr = ich_number_of_regions(ich_generation, &desc.content);
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
+ const struct fd_region *fd_regions = hwseq_data->fd_regions;
+
+ /*
+ * Set default values for the region. If no flash descriptor containing
+ * addr is found, these values will be used instead.
+ *
+ * The region start and end are constrained so that they do not overlap
+ * any flash descriptor regions.
+ */
+ const char *name = "";
+ region->read_prot = false;
+ region->write_prot = false;
+ region->start = 0;
+ region->end = flashrom_flash_getsize(flash);
+
+ for (ssize_t i = 0; i < nr; i++) {
+ uint32_t base = fd_regions[i].base;
+ uint32_t limit = fd_regions[i].limit;
+ enum ich_access_protection level = fd_regions[i].level;
+
+ if (addr < base) {
+ /*
+ * fd_regions[i] starts after addr, constrain
+ * region->end so that it does not overlap.
+ */
+ region->end = min(region->end, base);
+ } else if (addr > limit) {
+ /*
+ * fd_regions[i] ends before addr, constrain
+ * region->start so that it does not overlap.
+ */
+ region->start = max(region->start, limit + 1);
+ } else {
+ /* fd_regions[i] contains addr, copy to *region. */
+ name = fd_regions[i].name;
+ region->start = base;
+ region->end = limit + 1;
+ region->read_prot = (level == LOCKED) || (level == READ_PROT);
+ region->write_prot = (level == LOCKED) || (level == WRITE_PROT);
+ break;
+ }
+ }
+
+ region->name = strdup(name);
+}
+
+/* Given RDID info, return pointer to entry in flashchips[] */
+static const struct flashchip *flash_id_to_entry(uint32_t mfg_id, uint32_t model_id)
+{
+ const struct flashchip *chip;
+
+ for (chip = &flashchips[0]; chip->vendor; chip++) {
+ if ((chip->manufacture_id == mfg_id) &&
+ (chip->model_id == model_id) &&
+ (chip->probe == PROBE_SPI_RDID) &&
+ ((chip->bustype & BUS_SPI) == BUS_SPI))
+ return chip;
+ }
+
+ return NULL;
+}
+
+static int ich_hwseq_read_status(const struct flashctx *flash, enum flash_reg reg, uint8_t *value)
+{
+ const int len = 1;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
+
+ if (reg != STATUS1) {
+ msg_pdbg("%s: only supports STATUS1\n", __func__);
+ /*
+ * Return SPI_INVALID_OPCODE to be consistent with spi_read_register()
+ * and make error handling simpler even though this isn't a SPI master.
+ */
+ return SPI_INVALID_OPCODE;
+ }
+ msg_pdbg("Reading Status register\n");
+
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_RD_STATUS, 1, len, ich_generation,
+ hwseq_data->addr_mask)) {
+ msg_perr("Reading Status register failed\n!!");
+ return -1;
+ }
+ ich_read_data(value, len, ICH9_REG_FDATA0);
+
+ return 0;
+}
+
+static int ich_hwseq_write_status(const struct flashctx *flash, enum flash_reg reg, uint8_t value)
+{
+ const int len = 1;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
+
+ if (reg != STATUS1) {
+ msg_pdbg("%s: only supports STATUS1\n", __func__);
+ /*
+ * Return SPI_INVALID_OPCODE to be consistent with spi_write_register()
+ * and make error handling simpler even though this isn't a SPI master.
+ */
+ return SPI_INVALID_OPCODE;
+ }
+ msg_pdbg("Writing status register\n");
+
+ ich_fill_data(&value, len, ICH9_REG_FDATA0);
+
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_WR_STATUS, 1, len, ich_generation,
+ hwseq_data->addr_mask)) {
+ msg_perr("Writing Status register failed\n!!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ich_hwseq_get_flash_id(struct flashctx *flash, enum ich_chipset ich_gen)
+{
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
+ if (hwseq_data->size_comp1 != 0) {
+ msg_pinfo("Multiple flash components detected, skipping flash identification.\n");
+ return;
+ }
+
+ /* PCH100 or above is required for RDID, ICH9 does not support it. */
+ if (hwseq_data->hsfc_fcycle != PCH100_HSFC_FCYCLE) {
+ msg_pinfo("RDID cycle not supported, skipping flash identification.\n");
+ return;
+ }
+
+ /*
+ * RDID gives 3 byte output:
+ * Byte 0: Manufacturer ID
+ * Byte 1: Model ID (MSB)
+ * Byte 2: Model ID (LSB)
+ */
+ const int len = 3;
+ uint8_t data[len];
+
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_RDID, 1, len, ich_gen,
+ hwseq_data->addr_mask)) {
+ msg_perr("Timed out waiting for RDID to complete.\n");
+ }
+
+ ich_read_data(data, len, ICH9_REG_FDATA0);
+ uint32_t mfg_id = data[0];
+ uint32_t model_id = (data[1] << 8) | data[2];
+
+ const struct flashchip *entry = flash_id_to_entry(mfg_id, model_id);
+ if (!entry) {
+ msg_pwarn("Unable to identify chip, mfg_id: 0x%02"PRIx32", "
+ "model_id: 0x%02"PRIx32"\n", mfg_id, model_id);
+ return;
+ }
+
+ msg_pdbg("Chip identified: %s\n", entry->name);
+
+ /* Update informational flash chip entries only */
+ flash->chip->vendor = entry->vendor;
+ flash->chip->name = entry->name;
+ flash->chip->manufacture_id = entry->manufacture_id;
+ flash->chip->model_id = entry->model_id;
+ /* total_size read from flash descriptor */
+ flash->chip->page_size = entry->page_size;
+ flash->chip->feature_bits = entry->feature_bits;
+ flash->chip->tested = entry->tested;
+ /* Support writeprotect */
+ flash->chip->reg_bits = entry->reg_bits;
+ flash->chip->decode_range = entry->decode_range;
+}
+
static int ich_hwseq_probe(struct flashctx *flash)
{
uint32_t total_size, boundary;
uint32_t erase_size_low, size_low, erase_size_high, size_high;
struct block_eraser *eraser;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
- total_size = hwseq_data.size_comp0 + hwseq_data.size_comp1;
+ total_size = hwseq_data->size_comp0 + hwseq_data->size_comp1;
msg_cdbg("Hardware sequencing reports %d attached SPI flash chip",
- (hwseq_data.size_comp1 != 0) ? 2 : 1);
- if (hwseq_data.size_comp1 != 0)
+ (hwseq_data->size_comp1 != 0) ? 2 : 1);
+ if (hwseq_data->size_comp1 != 0)
msg_cdbg("s with a combined");
else
msg_cdbg(" with a");
- msg_cdbg(" density of %d kB.\n", total_size / 1024);
+ msg_cdbg(" density of %"PRId32" kB.\n", total_size / 1024);
flash->chip->total_size = total_size / 1024;
eraser = &(flash->chip->block_erasers[0]);
- if (!hwseq_data.only_4k)
+ if (!hwseq_data->only_4k)
boundary = (REGREAD32(ICH9_REG_FPB) & FPB_FPBA) << 12;
else
boundary = 0;
size_high = total_size - boundary;
- erase_size_high = ich_hwseq_get_erase_block_size(boundary);
+ erase_size_high = ich_hwseq_get_erase_block_size(boundary, hwseq_data->addr_mask, hwseq_data->only_4k);
if (boundary == 0) {
msg_cdbg2("There is only one partition containing the whole "
- "address space (0x%06x - 0x%06x).\n", 0, size_high-1);
+ "address space (0x%06x - 0x%06"PRIx32").\n", 0, size_high-1);
eraser->eraseblocks[0].size = erase_size_high;
eraser->eraseblocks[0].count = size_high / erase_size_high;
- msg_cdbg2("There are %d erase blocks with %d B each.\n",
+ msg_cdbg2("There are %"PRId32" erase blocks with %"PRId32" B each.\n",
size_high / erase_size_high, erase_size_high);
} else {
- msg_cdbg2("The flash address space (0x%06x - 0x%06x) is divided "
- "at address 0x%06x in two partitions.\n",
+ msg_cdbg2("The flash address space (0x%06x - 0x%06"PRIx32") is divided "
+ "at address 0x%06"PRIx32" in two partitions.\n",
0, total_size-1, boundary);
size_low = total_size - size_high;
- erase_size_low = ich_hwseq_get_erase_block_size(0);
+ erase_size_low = ich_hwseq_get_erase_block_size(0, hwseq_data->addr_mask, hwseq_data->only_4k);
eraser->eraseblocks[0].size = erase_size_low;
eraser->eraseblocks[0].count = size_low / erase_size_low;
- msg_cdbg("The first partition ranges from 0x%06x to 0x%06x.\n",
- 0, size_low-1);
- msg_cdbg("In that range are %d erase blocks with %d B each.\n",
+ msg_cdbg("The first partition ranges from 0x%06x to 0x%06"PRIx32".\n", 0, size_low-1);
+ msg_cdbg("In that range are %"PRId32" erase blocks with %"PRId32" B each.\n",
size_low / erase_size_low, erase_size_low);
eraser->eraseblocks[1].size = erase_size_high;
eraser->eraseblocks[1].count = size_high / erase_size_high;
- msg_cdbg("The second partition ranges from 0x%06x to 0x%06x.\n",
+ msg_cdbg("The second partition ranges from 0x%06"PRIx32" to 0x%06"PRIx32".\n",
boundary, total_size-1);
- msg_cdbg("In that range are %d erase blocks with %d B each.\n",
+ msg_cdbg("In that range are %"PRId32" erase blocks with %"PRId32" B each.\n",
size_high / erase_size_high, erase_size_high);
}
- flash->chip->tested = TEST_OK_PREW;
+
+ /* May be overwritten by ich_hwseq_get_flash_id(). */
+ flash->chip->tested = TEST_OK_PREWB;
+
+ ich_hwseq_get_flash_id(flash, ich_generation);
+
return 1;
}
@@ -1381,12 +1650,11 @@ static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
unsigned int len)
{
uint32_t erase_block;
- uint16_t hsfc;
- uint32_t timeout = 5000 * 1000; /* 5 s for max 64 kB */
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
- erase_block = ich_hwseq_get_erase_block_size(addr);
+ erase_block = ich_hwseq_get_erase_block_size(addr, hwseq_data->addr_mask, hwseq_data->only_4k);
if (len != erase_block) {
- msg_cerr("Erase block size for address 0x%06x is %d B, "
+ msg_cerr("Erase block size for address 0x%06x is %"PRId32" B, "
"but requested erase block size is %d B. "
"Not erasing anything.\n", addr, erase_block, len);
return -1;
@@ -1396,33 +1664,21 @@ static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
* containing the address) we play safe here. */
if (addr % erase_block != 0) {
msg_cerr("Erase address 0x%06x is not aligned to the erase "
- "block boundary (any multiple of %d). "
+ "block boundary (any multiple of %"PRId32"). "
"Not erasing anything.\n", addr, erase_block);
return -1;
}
if (addr + len > flash->chip->total_size * 1024) {
msg_perr("Request to erase some inaccessible memory address(es)"
- " (addr=0x%x, len=%d). "
- "Not erasing anything.\n", addr, len);
+ " (addr=0x%x, len=%d). Not erasing anything.\n", addr, len);
return -1;
}
msg_pdbg("Erasing %d bytes starting at 0x%06x.\n", len, addr);
- ich_hwseq_set_addr(addr);
-
- /* make sure FDONE, FCERR, AEL are cleared by writing 1 to them */
- REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
-
- hsfc = REGREAD16(ICH9_REG_HSFC);
- hsfc &= ~hwseq_data.hsfc_fcycle; /* clear operation */
- hsfc |= (0x3 << HSFC_FCYCLE_OFF); /* set erase operation */
- hsfc |= HSFC_FGO; /* start */
- msg_pdbg("HSFC used for block erasing: ");
- prettyprint_ich9_reg_hsfc(hsfc, ich_generation);
- REGWRITE16(ICH9_REG_HSFC, hsfc);
- if (ich_hwseq_wait_for_cycle_complete(timeout, len, ich_generation))
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_BLOCK_ERASE, addr, 1, ich_generation,
+ hwseq_data->addr_mask))
return -1;
return 0;
}
@@ -1430,9 +1686,8 @@ static int ich_hwseq_block_erase(struct flashctx *flash, unsigned int addr,
static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf,
unsigned int addr, unsigned int len)
{
- uint16_t hsfc;
- uint16_t timeout = 100 * 60;
uint8_t block_len;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
if (addr + len > flash->chip->total_size * 1024) {
msg_perr("Request to read from an inaccessible memory address "
@@ -1450,16 +1705,8 @@ static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf,
/* as well as flash chip page borders as demanded in the Intel datasheets. */
block_len = min(block_len, 256 - (addr & 0xFF));
- ich_hwseq_set_addr(addr);
- hsfc = REGREAD16(ICH9_REG_HSFC);
- hsfc &= ~hwseq_data.hsfc_fcycle; /* set read operation */
- hsfc &= ~HSFC_FDBC; /* clear byte count */
- /* set byte count */
- hsfc |= (((block_len - 1) << HSFC_FDBC_OFF) & HSFC_FDBC);
- hsfc |= HSFC_FGO; /* start */
- REGWRITE16(ICH9_REG_HSFC, hsfc);
-
- if (ich_hwseq_wait_for_cycle_complete(timeout, block_len, ich_generation))
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_READ, addr, block_len, ich_generation,
+ hwseq_data->addr_mask))
return 1;
ich_read_data(buf, block_len, ICH9_REG_FDATA0);
addr += block_len;
@@ -1471,9 +1718,8 @@ static int ich_hwseq_read(struct flashctx *flash, uint8_t *buf,
static int ich_hwseq_write(struct flashctx *flash, const uint8_t *buf, unsigned int addr, unsigned int len)
{
- uint16_t hsfc;
- uint16_t timeout = 100 * 60;
uint8_t block_len;
+ const struct hwseq_data *hwseq_data = get_hwseq_data_from_context(flash);
if (addr + len > flash->chip->total_size * 1024) {
msg_perr("Request to write to an inaccessible memory address "
@@ -1486,22 +1732,14 @@ static int ich_hwseq_write(struct flashctx *flash, const uint8_t *buf, unsigned
REGWRITE16(ICH9_REG_HSFS, REGREAD16(ICH9_REG_HSFS));
while (len > 0) {
- ich_hwseq_set_addr(addr);
/* Obey programmer limit... */
block_len = min(len, flash->mst->opaque.max_data_write);
/* as well as flash chip page borders as demanded in the Intel datasheets. */
block_len = min(block_len, 256 - (addr & 0xFF));
ich_fill_data(buf, block_len, ICH9_REG_FDATA0);
- hsfc = REGREAD16(ICH9_REG_HSFC);
- hsfc &= ~hwseq_data.hsfc_fcycle; /* clear operation */
- hsfc |= (0x2 << HSFC_FCYCLE_OFF); /* set write operation */
- hsfc &= ~HSFC_FDBC; /* clear byte count */
- /* set byte count */
- hsfc |= (((block_len - 1) << HSFC_FDBC_OFF) & HSFC_FDBC);
- hsfc |= HSFC_FGO; /* start */
- REGWRITE16(ICH9_REG_HSFC, hsfc);
-
- if (ich_hwseq_wait_for_cycle_complete(timeout, block_len, ich_generation))
+
+ if (ich_exec_sync_hwseq_xfer(flash, HSFC_CYCLE_WRITE, addr, block_len, ich_generation,
+ hwseq_data->addr_mask))
return -1;
addr += block_len;
buf += block_len;
@@ -1510,6 +1748,12 @@ static int ich_hwseq_write(struct flashctx *flash, const uint8_t *buf, unsigned
return 0;
}
+static int ich_hwseq_shutdown(void *data)
+{
+ free(data);
+ return 0;
+}
+
static int ich_spi_send_multicommand(const struct flashctx *flash,
struct spi_command *cmds)
{
@@ -1570,6 +1814,11 @@ static int ich_spi_send_multicommand(const struct flashctx *flash,
return ret;
}
+static bool ich_spi_probe_opcode(const struct flashctx *flash, uint8_t opcode)
+{
+ return find_opcode(curopcodes, opcode) >= 0;
+}
+
#define ICH_BMWAG(x) ((x >> 24) & 0xff)
#define ICH_BMRAG(x) ((x >> 16) & 0xff)
#define ICH_BRWA(x) ((x >> 8) & 0xff)
@@ -1579,12 +1828,12 @@ static const enum ich_access_protection access_perms_to_protection[] = {
LOCKED, WRITE_PROT, READ_PROT, NO_PROT
};
static const char *const access_names[] = {
- "locked", "read-only", "write-only", "read-write"
+ "read-write", "write-only", "read-only", "locked"
};
-static enum ich_access_protection ich9_handle_frap(uint32_t frap, unsigned int i)
+static enum ich_access_protection ich9_handle_frap(struct fd_region *fd_regions,
+ uint32_t frap, unsigned int i)
{
- const int rwperms_unknown = ARRAY_SIZE(access_names);
static const char *const region_names[] = {
"Flash Descriptor", "BIOS", "Management Engine",
"Gigabit Ethernet", "Platform Data", "Device Expansion",
@@ -1593,46 +1842,46 @@ static enum ich_access_protection ich9_handle_frap(uint32_t frap, unsigned int i
const char *const region_name = i < ARRAY_SIZE(region_names) ? region_names[i] : "unknown";
uint32_t base, limit;
- int rwperms;
+ unsigned int rwperms_idx;
+ enum ich_access_protection rwperms;
const int offset = i < 12
? ICH9_REG_FREG0 + i * 4
: APL_REG_FREG12 + (i - 12) * 4;
uint32_t freg = mmio_readl(ich_spibar + offset);
- if (i < 8) {
- rwperms = (((ICH_BRWA(frap) >> i) & 1) << 1) |
- (((ICH_BRRA(frap) >> i) & 1) << 0);
- } else {
- /* Datasheets don't define any access bits for regions > 7. We
- can't rely on the actual descriptor settings either as there
- are several overrides for them (those by other masters are
- not even readable by us, *shrug*). */
- rwperms = rwperms_unknown;
- }
-
base = ICH_FREG_BASE(freg);
limit = ICH_FREG_LIMIT(freg);
if (base > limit || (freg == 0 && i > 0)) {
/* this FREG is disabled */
- msg_pdbg2("0x%02X: 0x%08x FREG%u: %s region is unused.\n",
+ msg_pdbg2("0x%02X: 0x%08"PRIx32" FREG%u: %s region is unused.\n",
offset, freg, i, region_name);
return NO_PROT;
}
- msg_pdbg("0x%02X: 0x%08x ", offset, freg);
- if (rwperms == 0x3) {
- msg_pdbg("FREG%u: %s region (0x%08x-0x%08x) is %s.\n", i,
- region_name, base, limit, access_names[rwperms]);
- return NO_PROT;
- }
- if (rwperms == rwperms_unknown) {
- msg_pdbg("FREG%u: %s region (0x%08x-0x%08x) has unknown permissions.\n",
- i, region_name, base, limit);
+ msg_pdbg("0x%02X: 0x%08"PRIx32" ", offset, freg);
+
+ if (i < 8) {
+ rwperms_idx = (((ICH_BRWA(frap) >> i) & 1) << 1) |
+ (((ICH_BRRA(frap) >> i) & 1) << 0);
+ rwperms = access_perms_to_protection[rwperms_idx];
+ } else {
+ /* Datasheets don't define any access bits for regions > 7. We
+ can't rely on the actual descriptor settings either as there
+ are several overrides for them (those by other masters are
+ not even readable by us, *shrug*). */
+ msg_pdbg("FREG%u: %s region (0x%08"PRIx32"-0x%08"PRIx32") has unknown permissions.\n",
+ i, region_name, base, limit);
return NO_PROT;
}
-
- msg_pinfo("FREG%u: %s region (0x%08x-0x%08x) is %s.\n", i,
+ msg_pinfo("FREG%u: %s region (0x%08"PRIx32"-0x%08"PRIx32") is %s.\n", i,
region_name, base, limit, access_names[rwperms]);
- return access_perms_to_protection[rwperms];
+
+ /* Save region attributes for use by ich_get_region(). */
+ fd_regions[i].base = base;
+ fd_regions[i].limit = limit;
+ fd_regions[i].level = rwperms;
+ fd_regions[i].name = region_name;
+
+ return rwperms;
}
/* In contrast to FRAP and the master section of the descriptor the bits
@@ -1648,22 +1897,24 @@ static enum ich_access_protection ich9_handle_pr(const size_t reg_pr0, unsigned
{
uint8_t off = reg_pr0 + (i * 4);
uint32_t pr = mmio_readl(ich_spibar + off);
- unsigned int rwperms = ICH_PR_PERMS(pr);
+ unsigned int rwperms_idx = ICH_PR_PERMS(pr);
+ enum ich_access_protection rwperms = access_perms_to_protection[rwperms_idx];
/* From 5 on we have GPR registers and start from 0 again. */
const char *const prefix = i >= 5 ? "G" : "";
if (i >= 5)
i -= 5;
- if (rwperms == 0x3) {
- msg_pdbg2("0x%02X: 0x%08x (%sPR%u is unused)\n", off, pr, prefix, i);
+ if (rwperms == NO_PROT) {
+ msg_pdbg2("0x%02"PRIX8": 0x%08"PRIx32" (%sPR%u is unused)\n", off, pr, prefix, i);
return NO_PROT;
}
- msg_pdbg("0x%02X: 0x%08x ", off, pr);
- msg_pwarn("%sPR%u: Warning: 0x%08x-0x%08x is %s.\n", prefix, i, ICH_FREG_BASE(pr),
+ msg_pdbg("0x%02"PRIX8": 0x%08"PRIx32" ", off, pr);
+ msg_pwarn("%sPR%u: Warning: 0x%08"PRIx32"-0x%08"PRIx32" is %s.\n", prefix, i, ICH_FREG_BASE(pr),
ICH_FREG_LIMIT(pr), access_names[rwperms]);
- return access_perms_to_protection[rwperms];
+
+ return rwperms;
}
/* Set/Clear the read and write protection enable bits of PR register @i
@@ -1674,7 +1925,7 @@ static void ich9_set_pr(const size_t reg_pr0, int i, int read_prot, int write_pr
uint32_t old = mmio_readl(addr);
uint32_t new;
- msg_gspew("PR%u is 0x%08x", i, old);
+ msg_gspew("PR%u is 0x%08"PRIx32"", i, old);
new = old & ~((1 << PR_RP_OFF) | (1 << PR_WP_OFF));
if (read_prot)
new |= (1 << PR_RP_OFF);
@@ -1684,385 +1935,455 @@ static void ich9_set_pr(const size_t reg_pr0, int i, int read_prot, int write_pr
msg_gspew(" already.\n");
return;
}
- msg_gspew(", trying to set it to 0x%08x ", new);
+ msg_gspew(", trying to set it to 0x%08"PRIx32" ", new);
rmmio_writel(new, addr);
- msg_gspew("resulted in 0x%08x.\n", mmio_readl(addr));
+ msg_gspew("resulted in 0x%08"PRIx32".\n", mmio_readl(addr));
}
static const struct spi_master spi_master_ich7 = {
- .max_data_read = 64,
- .max_data_write = 64,
- .command = ich_spi_send_command,
- .multicommand = ich_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .max_data_read = 64,
+ .max_data_write = 64,
+ .command = ich_spi_send_command,
+ .multicommand = ich_spi_send_multicommand,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
};
static const struct spi_master spi_master_ich9 = {
- .max_data_read = 64,
- .max_data_write = 64,
- .command = ich_spi_send_command,
- .multicommand = ich_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .max_data_read = 64,
+ .max_data_write = 64,
+ .command = ich_spi_send_command,
+ .multicommand = ich_spi_send_multicommand,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .probe_opcode = ich_spi_probe_opcode,
};
static const struct opaque_master opaque_master_ich_hwseq = {
- .max_data_read = 64,
- .max_data_write = 64,
- .probe = ich_hwseq_probe,
- .read = ich_hwseq_read,
- .write = ich_hwseq_write,
- .erase = ich_hwseq_block_erase,
+ .max_data_read = 64,
+ .max_data_write = 64,
+ .probe = ich_hwseq_probe,
+ .read = ich_hwseq_read,
+ .write = ich_hwseq_write,
+ .erase = ich_hwseq_block_erase,
+ .read_register = ich_hwseq_read_status,
+ .write_register = ich_hwseq_write_status,
+ .get_region = ich_get_region,
+ .shutdown = ich_hwseq_shutdown,
};
-int ich_init_spi(void *spibar, enum ich_chipset ich_gen)
+static int init_ich7_spi(void *spibar, enum ich_chipset ich_gen)
{
unsigned int i;
- uint16_t tmp2;
- uint32_t tmp;
- char *arg;
- int ich_spi_rw_restricted = 0;
- int desc_valid = 0;
- struct ich_descriptors desc;
- enum ich_spi_mode {
- ich_auto,
- ich_hwseq,
- ich_swseq
- } ich_spi_mode = ich_auto;
- size_t num_freg, num_pr, reg_pr0;
- ich_generation = ich_gen;
- ich_spibar = spibar;
+ msg_pdbg("0x00: 0x%04"PRIx16" (SPIS)\n", mmio_readw(spibar + 0));
+ msg_pdbg("0x02: 0x%04"PRIx16" (SPIC)\n", mmio_readw(spibar + 2));
+ msg_pdbg("0x04: 0x%08"PRIx32" (SPIA)\n", mmio_readl(spibar + 4));
+
+ ichspi_bbar = mmio_readl(spibar + 0x50);
- memset(&desc, 0x00, sizeof(struct ich_descriptors));
+ msg_pdbg("0x50: 0x%08"PRIx32" (BBAR)\n", ichspi_bbar);
+ msg_pdbg("0x54: 0x%04"PRIx16" (PREOP)\n", mmio_readw(spibar + 0x54));
+ msg_pdbg("0x56: 0x%04"PRIx16" (OPTYPE)\n", mmio_readw(spibar + 0x56));
+ msg_pdbg("0x58: 0x%08"PRIx32" (OPMENU)\n", mmio_readl(spibar + 0x58));
+ msg_pdbg("0x5c: 0x%08"PRIx32" (OPMENU+4)\n", mmio_readl(spibar + 0x5c));
+
+ for (i = 0; i < 3; i++) {
+ int offs;
+ offs = 0x60 + (i * 4);
+ msg_pdbg("0x%02x: 0x%08"PRIx32" (PBR%u)\n", offs, mmio_readl(spibar + offs), i);
+ }
+ if (mmio_readw(spibar) & (1 << 15)) {
+ msg_pwarn("WARNING: SPI Configuration Lockdown activated.\n");
+ ichspi_lock = true;
+ }
+ ich_init_opcodes(ich_gen);
+ ich_set_bbar(0, ich_gen);
+ register_spi_master(&spi_master_ich7, NULL);
+
+ return 0;
+}
+enum ich_spi_mode {
+ ich_auto,
+ ich_hwseq,
+ ich_swseq
+};
+
+static int get_ich_spi_mode_param(const struct programmer_cfg *cfg, enum ich_spi_mode *ich_spi_mode)
+{
+ char *const arg = extract_programmer_param_str(cfg, "ich_spi_mode");
+ if (!arg) {
+ return 0;
+ } else if (!strcmp(arg, "hwseq")) {
+ *ich_spi_mode = ich_hwseq;
+ msg_pspew("user selected hwseq\n");
+ } else if (!strcmp(arg, "swseq")) {
+ *ich_spi_mode = ich_swseq;
+ msg_pspew("user selected swseq\n");
+ } else if (!strcmp(arg, "auto")) {
+ msg_pspew("user selected auto\n");
+ *ich_spi_mode = ich_auto;
+ } else if (!strlen(arg)) {
+ msg_perr("Missing argument for ich_spi_mode.\n");
+ free(arg);
+ return ERROR_FLASHROM_FATAL;
+ } else {
+ msg_perr("Unknown argument for ich_spi_mode: %s\n", arg);
+ free(arg);
+ return ERROR_FLASHROM_FATAL;
+ }
+ free(arg);
+
+ return 0;
+}
+
+static void init_chipset_properties(struct swseq_data *swseq, struct hwseq_data *hwseq,
+ size_t *num_freg, size_t *num_pr, size_t *reg_pr0,
+ enum ich_chipset ich_gen)
+{
/* Moving registers / bits */
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
- num_pr = 6; /* Includes GPR0 */
- reg_pr0 = PCH100_REG_FPR0;
- swseq_data.reg_ssfsc = PCH100_REG_SSFSC;
- swseq_data.reg_preop = PCH100_REG_PREOP;
- swseq_data.reg_optype = PCH100_REG_OPTYPE;
- swseq_data.reg_opmenu = PCH100_REG_OPMENU;
- hwseq_data.addr_mask = PCH100_FADDR_FLA;
- hwseq_data.only_4k = true;
- hwseq_data.hsfc_fcycle = PCH100_HSFC_FCYCLE;
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
+ *num_pr = 6; /* Includes GPR0 */
+ *reg_pr0 = PCH100_REG_FPR0;
+ swseq->reg_ssfsc = PCH100_REG_SSFSC;
+ swseq->reg_preop = PCH100_REG_PREOP;
+ swseq->reg_optype = PCH100_REG_OPTYPE;
+ swseq->reg_opmenu = PCH100_REG_OPMENU;
+ hwseq->addr_mask = PCH100_FADDR_FLA;
+ hwseq->only_4k = true;
+ hwseq->hsfc_fcycle = PCH100_HSFC_FCYCLE;
break;
default:
- num_pr = 5;
- reg_pr0 = ICH9_REG_PR0;
- swseq_data.reg_ssfsc = ICH9_REG_SSFS;
- swseq_data.reg_preop = ICH9_REG_PREOP;
- swseq_data.reg_optype = ICH9_REG_OPTYPE;
- swseq_data.reg_opmenu = ICH9_REG_OPMENU;
- hwseq_data.addr_mask = ICH9_FADDR_FLA;
- hwseq_data.only_4k = false;
- hwseq_data.hsfc_fcycle = HSFC_FCYCLE;
+ *num_pr = 5;
+ *reg_pr0 = ICH9_REG_PR0;
+ swseq->reg_ssfsc = ICH9_REG_SSFS;
+ swseq->reg_preop = ICH9_REG_PREOP;
+ swseq->reg_optype = ICH9_REG_OPTYPE;
+ swseq->reg_opmenu = ICH9_REG_OPMENU;
+ hwseq->addr_mask = ICH9_FADDR_FLA;
+ hwseq->only_4k = false;
+ hwseq->hsfc_fcycle = ICH9_HSFC_FCYCLE;
break;
}
+
switch (ich_gen) {
case CHIPSET_100_SERIES_SUNRISE_POINT:
- num_freg = 10;
+ *num_freg = 10;
break;
case CHIPSET_C620_SERIES_LEWISBURG:
- num_freg = 12; /* 12 MMIO regs, but 16 regions in FD spec */
+ *num_freg = 12; /* 12 MMIO regs, but 16 regions in FD spec */
break;
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
- num_freg = 16;
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
+ *num_freg = 16;
break;
default:
- num_freg = 5;
+ *num_freg = 5;
break;
}
+}
+
+static int init_ich_default(const struct programmer_cfg *cfg, void *spibar, enum ich_chipset ich_gen)
+{
+ unsigned int i;
+ uint16_t tmp2;
+ uint32_t tmp;
+ int ich_spi_rw_restricted = 0;
+ bool desc_valid = false;
+ struct ich_descriptors desc = { 0 };
+ enum ich_spi_mode ich_spi_mode = ich_auto;
+ size_t num_freg, num_pr, reg_pr0;
+ struct hwseq_data hwseq_data = { 0 };
+ init_chipset_properties(&swseq_data, &hwseq_data, &num_freg, &num_pr, &reg_pr0, ich_gen);
+
+ int ret = get_ich_spi_mode_param(cfg, &ich_spi_mode);
+ if (ret)
+ return ret;
+
+ tmp2 = mmio_readw(spibar + ICH9_REG_HSFS);
+ msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
+ prettyprint_ich9_reg_hsfs(tmp2, ich_gen);
+ if (tmp2 & HSFS_FLOCKDN) {
+ msg_pinfo("SPI Configuration is locked down.\n");
+ ichspi_lock = true;
+ }
+ if (tmp2 & HSFS_FDV)
+ desc_valid = true;
+ if (!(tmp2 & HSFS_FDOPSS) && desc_valid)
+ msg_pinfo("The Flash Descriptor Override Strap-Pin is set. Restrictions implied by\n"
+ "the Master Section of the flash descriptor are NOT in effect. Please note\n"
+ "that Protected Range (PR) restrictions still apply.\n");
+ ich_init_opcodes(ich_gen);
+
+ if (desc_valid) {
+ tmp2 = mmio_readw(spibar + ICH9_REG_HSFC);
+ msg_pdbg("0x06: 0x%04"PRIx16" (HSFC)\n", tmp2);
+ prettyprint_ich9_reg_hsfc(tmp2, ich_gen);
+ }
+
+ tmp = mmio_readl(spibar + ICH9_REG_FADDR);
+ msg_pdbg2("0x08: 0x%08"PRIx32" (FADDR)\n", tmp);
switch (ich_gen) {
- case CHIPSET_ICH7:
- case CHIPSET_TUNNEL_CREEK:
- case CHIPSET_CENTERTON:
- msg_pdbg("0x00: 0x%04x (SPIS)\n",
- mmio_readw(spibar + 0));
- msg_pdbg("0x02: 0x%04x (SPIC)\n",
- mmio_readw(spibar + 2));
- msg_pdbg("0x04: 0x%08x (SPIA)\n",
- mmio_readl(spibar + 4));
- ichspi_bbar = mmio_readl(spibar + 0x50);
- msg_pdbg("0x50: 0x%08x (BBAR)\n",
- ichspi_bbar);
- msg_pdbg("0x54: 0x%04x (PREOP)\n",
- mmio_readw(spibar + 0x54));
- msg_pdbg("0x56: 0x%04x (OPTYPE)\n",
- mmio_readw(spibar + 0x56));
- msg_pdbg("0x58: 0x%08x (OPMENU)\n",
- mmio_readl(spibar + 0x58));
- msg_pdbg("0x5c: 0x%08x (OPMENU+4)\n",
- mmio_readl(spibar + 0x5c));
- for (i = 0; i < 3; i++) {
- int offs;
- offs = 0x60 + (i * 4);
- msg_pdbg("0x%02x: 0x%08x (PBR%u)\n", offs,
- mmio_readl(spibar + offs), i);
- }
- if (mmio_readw(spibar) & (1 << 15)) {
- msg_pwarn("WARNING: SPI Configuration Lockdown activated.\n");
- ichspi_lock = 1;
- }
- ich_init_opcodes(ich_gen);
- ich_set_bbar(0, ich_gen);
- register_spi_master(&spi_master_ich7);
+ case CHIPSET_100_SERIES_SUNRISE_POINT:
+ case CHIPSET_C620_SERIES_LEWISBURG:
+ case CHIPSET_300_SERIES_CANNON_POINT:
+ case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
+ tmp = mmio_readl(spibar + PCH100_REG_DLOCK);
+ msg_pdbg("0x0c: 0x%08"PRIx32" (DLOCK)\n", tmp);
+ prettyprint_pch100_reg_dlock(tmp);
break;
- case CHIPSET_ICH8:
- default: /* Future version might behave the same */
- arg = extract_programmer_param("ich_spi_mode");
- if (arg && !strcmp(arg, "hwseq")) {
- ich_spi_mode = ich_hwseq;
- msg_pspew("user selected hwseq\n");
- } else if (arg && !strcmp(arg, "swseq")) {
- ich_spi_mode = ich_swseq;
- msg_pspew("user selected swseq\n");
- } else if (arg && !strcmp(arg, "auto")) {
- msg_pspew("user selected auto\n");
- ich_spi_mode = ich_auto;
- } else if (arg && !strlen(arg)) {
- msg_perr("Missing argument for ich_spi_mode.\n");
- free(arg);
- return ERROR_FATAL;
- } else if (arg) {
- msg_perr("Unknown argument for ich_spi_mode: %s\n",
- arg);
- free(arg);
- return ERROR_FATAL;
- }
- free(arg);
+ default:
+ break;
+ }
- tmp2 = mmio_readw(spibar + ICH9_REG_HSFS);
- msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2);
- prettyprint_ich9_reg_hsfs(tmp2, ich_gen);
- if (tmp2 & HSFS_FLOCKDN) {
- msg_pinfo("SPI Configuration is locked down.\n");
- ichspi_lock = 1;
- }
- if (tmp2 & HSFS_FDV)
- desc_valid = 1;
- if (!(tmp2 & HSFS_FDOPSS) && desc_valid)
- msg_pinfo("The Flash Descriptor Override Strap-Pin is set. Restrictions implied by\n"
- "the Master Section of the flash descriptor are NOT in effect. Please note\n"
- "that Protected Range (PR) restrictions still apply.\n");
- ich_init_opcodes(ich_gen);
-
- if (desc_valid) {
- tmp2 = mmio_readw(spibar + ICH9_REG_HSFC);
- msg_pdbg("0x06: 0x%04x (HSFC)\n", tmp2);
- prettyprint_ich9_reg_hsfc(tmp2, ich_gen);
- }
+ if (desc_valid) {
+ tmp = mmio_readl(spibar + ICH9_REG_FRAP);
+ msg_pdbg("0x50: 0x%08"PRIx32" (FRAP)\n", tmp);
+ msg_pdbg("BMWAG 0x%02"PRIx32", ", ICH_BMWAG(tmp));
+ msg_pdbg("BMRAG 0x%02"PRIx32", ", ICH_BMRAG(tmp));
+ msg_pdbg("BRWA 0x%02"PRIx32", ", ICH_BRWA(tmp));
+ msg_pdbg("BRRA 0x%02"PRIx32"\n", ICH_BRRA(tmp));
+
+ /* Handle FREGx and FRAP registers */
+ for (i = 0; i < num_freg; i++)
+ ich_spi_rw_restricted |= ich9_handle_frap(hwseq_data.fd_regions, tmp, i);
+ if (ich_spi_rw_restricted)
+ msg_pinfo("Not all flash regions are freely accessible by flashrom. This is "
+ "most likely\ndue to an active ME. Please see "
+ "https://flashrom.org/ME for details.\n");
+ }
+
+ /* Handle PR registers */
+ for (i = 0; i < num_pr; i++) {
+ /* if not locked down try to disable PR locks first */
+ if (!ichspi_lock)
+ ich9_set_pr(reg_pr0, i, 0, 0);
+ ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
+ }
+
+ switch (ich_spi_rw_restricted) {
+ case WRITE_PROT:
+ msg_pwarn("At least some flash regions are write protected. For write operations,\n"
+ "you should use a flash layout and include only writable regions. See\n"
+ "manpage for more details.\n");
+ break;
+ case READ_PROT:
+ case LOCKED:
+ msg_pwarn("At least some flash regions are read protected. You have to use a flash\n"
+ "layout and include only accessible regions. For write operations, you'll\n"
+ "additionally need the --noverify-all switch. See manpage for more details.\n");
+ break;
+ }
+
+ tmp = mmio_readl(spibar + swseq_data.reg_ssfsc);
+ msg_pdbg("0x%zx: 0x%02"PRIx32" (SSFS)\n", swseq_data.reg_ssfsc, tmp & 0xff);
+ prettyprint_ich9_reg_ssfs(tmp);
+ if (tmp & SSFS_FCERR) {
+ msg_pdbg("Clearing SSFS.FCERR\n");
+ mmio_writeb(SSFS_FCERR, spibar + swseq_data.reg_ssfsc);
+ }
+ msg_pdbg("0x%zx: 0x%06"PRIx32" (SSFC)\n", swseq_data.reg_ssfsc + 1, tmp >> 8);
+ prettyprint_ich9_reg_ssfc(tmp);
- tmp = mmio_readl(spibar + ICH9_REG_FADDR);
- msg_pdbg2("0x08: 0x%08x (FADDR)\n", tmp);
+ msg_pdbg("0x%zx: 0x%04"PRIx16" (PREOP)\n",
+ swseq_data.reg_preop, mmio_readw(spibar + swseq_data.reg_preop));
+ msg_pdbg("0x%zx: 0x%04"PRIx16" (OPTYPE)\n",
+ swseq_data.reg_optype, mmio_readw(spibar + swseq_data.reg_optype));
+ msg_pdbg("0x%zx: 0x%08"PRIx32" (OPMENU)\n",
+ swseq_data.reg_opmenu, mmio_readl(spibar + swseq_data.reg_opmenu));
+ msg_pdbg("0x%zx: 0x%08"PRIx32" (OPMENU+4)\n",
+ swseq_data.reg_opmenu + 4, mmio_readl(spibar + swseq_data.reg_opmenu + 4));
+ if (desc_valid) {
switch (ich_gen) {
+ case CHIPSET_ICH8:
case CHIPSET_100_SERIES_SUNRISE_POINT:
case CHIPSET_C620_SERIES_LEWISBURG:
case CHIPSET_300_SERIES_CANNON_POINT:
case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
case CHIPSET_APOLLO_LAKE:
- tmp = mmio_readl(spibar + PCH100_REG_DLOCK);
- msg_pdbg("0x0c: 0x%08x (DLOCK)\n", tmp);
- prettyprint_pch100_reg_dlock(tmp);
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_BAYTRAIL:
+ case CHIPSET_ELKHART_LAKE:
break;
default:
+ ichspi_bbar = mmio_readl(spibar + ICH9_REG_BBAR);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (BBAR)\n", ICH9_REG_BBAR, ichspi_bbar);
+ ich_set_bbar(0, ich_gen);
break;
}
- if (desc_valid) {
- tmp = mmio_readl(spibar + ICH9_REG_FRAP);
- msg_pdbg("0x50: 0x%08x (FRAP)\n", tmp);
- msg_pdbg("BMWAG 0x%02x, ", ICH_BMWAG(tmp));
- msg_pdbg("BMRAG 0x%02x, ", ICH_BMRAG(tmp));
- msg_pdbg("BRWA 0x%02x, ", ICH_BRWA(tmp));
- msg_pdbg("BRRA 0x%02x\n", ICH_BRRA(tmp));
-
- /* Handle FREGx and FRAP registers */
- for (i = 0; i < num_freg; i++)
- ich_spi_rw_restricted |= ich9_handle_frap(tmp, i);
- if (ich_spi_rw_restricted)
- msg_pinfo("Not all flash regions are freely accessible by flashrom. This is "
- "most likely\ndue to an active ME. Please see "
- "https://flashrom.org/ME for details.\n");
- }
-
- /* Handle PR registers */
- for (i = 0; i < num_pr; i++) {
- /* if not locked down try to disable PR locks first */
- if (!ichspi_lock)
- ich9_set_pr(reg_pr0, i, 0, 0);
- ich_spi_rw_restricted |= ich9_handle_pr(reg_pr0, i);
+ if (ich_gen == CHIPSET_ICH8) {
+ tmp = mmio_readl(spibar + ICH8_REG_VSCC);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (VSCC)\n", ICH8_REG_VSCC, tmp);
+ msg_pdbg("VSCC: ");
+ prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
+ } else {
+ tmp = mmio_readl(spibar + ICH9_REG_LVSCC);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (LVSCC)\n", ICH9_REG_LVSCC, tmp);
+ msg_pdbg("LVSCC: ");
+ prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
+
+ tmp = mmio_readl(spibar + ICH9_REG_UVSCC);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (UVSCC)\n", ICH9_REG_UVSCC, tmp);
+ msg_pdbg("UVSCC: ");
+ prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, false);
}
- switch (ich_spi_rw_restricted) {
- case WRITE_PROT:
- msg_pwarn("At least some flash regions are write protected. For write operations,\n"
- "you should use a flash layout and include only writable regions. See\n"
- "manpage for more details.\n");
+ switch (ich_gen) {
+ case CHIPSET_ICH8:
+ case CHIPSET_100_SERIES_SUNRISE_POINT:
+ case CHIPSET_C620_SERIES_LEWISBURG:
+ case CHIPSET_300_SERIES_CANNON_POINT:
+ case CHIPSET_400_SERIES_COMET_POINT:
+ case CHIPSET_500_SERIES_TIGER_POINT:
+ case CHIPSET_600_SERIES_ALDER_POINT:
+ case CHIPSET_METEOR_LAKE:
+ case CHIPSET_APOLLO_LAKE:
+ case CHIPSET_GEMINI_LAKE:
+ case CHIPSET_JASPER_LAKE:
+ case CHIPSET_ELKHART_LAKE:
break;
- case READ_PROT:
- case LOCKED:
- msg_pwarn("At least some flash regions are read protected. You have to use a flash\n"
- "layout and include only accessible regions. For write operations, you'll\n"
- "additionally need the --noverify-all switch. See manpage for more details.\n"
- );
+ default:
+ tmp = mmio_readl(spibar + ICH9_REG_FPB);
+ msg_pdbg("0x%x: 0x%08"PRIx32" (FPB)\n", ICH9_REG_FPB, tmp);
break;
}
- tmp = mmio_readl(spibar + swseq_data.reg_ssfsc);
- msg_pdbg("0x%zx: 0x%02x (SSFS)\n", swseq_data.reg_ssfsc, tmp & 0xff);
- prettyprint_ich9_reg_ssfs(tmp);
- if (tmp & SSFS_FCERR) {
- msg_pdbg("Clearing SSFS.FCERR\n");
- mmio_writeb(SSFS_FCERR, spibar + swseq_data.reg_ssfsc);
- }
- msg_pdbg("0x%zx: 0x%06x (SSFC)\n", swseq_data.reg_ssfsc + 1, tmp >> 8);
- prettyprint_ich9_reg_ssfc(tmp);
-
- msg_pdbg("0x%zx: 0x%04x (PREOP)\n",
- swseq_data.reg_preop, mmio_readw(spibar + swseq_data.reg_preop));
- msg_pdbg("0x%zx: 0x%04x (OPTYPE)\n",
- swseq_data.reg_optype, mmio_readw(spibar + swseq_data.reg_optype));
- msg_pdbg("0x%zx: 0x%08x (OPMENU)\n",
- swseq_data.reg_opmenu, mmio_readl(spibar + swseq_data.reg_opmenu));
- msg_pdbg("0x%zx: 0x%08x (OPMENU+4)\n",
- swseq_data.reg_opmenu + 4, mmio_readl(spibar + swseq_data.reg_opmenu + 4));
-
- if (desc_valid) {
- switch (ich_gen) {
- case CHIPSET_ICH8:
- case CHIPSET_100_SERIES_SUNRISE_POINT:
- case CHIPSET_C620_SERIES_LEWISBURG:
- case CHIPSET_300_SERIES_CANNON_POINT:
- case CHIPSET_400_SERIES_COMET_POINT:
- case CHIPSET_APOLLO_LAKE:
- case CHIPSET_BAYTRAIL:
- break;
- default:
- ichspi_bbar = mmio_readl(spibar + ICH9_REG_BBAR);
- msg_pdbg("0x%x: 0x%08x (BBAR)\n", ICH9_REG_BBAR, ichspi_bbar);
- ich_set_bbar(0, ich_gen);
- break;
- }
+ if (read_ich_descriptors_via_fdo(ich_gen, spibar, &desc) == ICH_RET_OK)
+ prettyprint_ich_descriptors(ich_gen, &desc);
- if (ich_gen == CHIPSET_ICH8) {
- tmp = mmio_readl(spibar + ICH8_REG_VSCC);
- msg_pdbg("0x%x: 0x%08x (VSCC)\n", ICH8_REG_VSCC, tmp);
- msg_pdbg("VSCC: ");
- prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
- } else {
- tmp = mmio_readl(spibar + ICH9_REG_LVSCC);
- msg_pdbg("0x%x: 0x%08x (LVSCC)\n", ICH9_REG_LVSCC, tmp);
- msg_pdbg("LVSCC: ");
- prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, true);
-
- tmp = mmio_readl(spibar + ICH9_REG_UVSCC);
- msg_pdbg("0x%x: 0x%08x (UVSCC)\n", ICH9_REG_UVSCC, tmp);
- msg_pdbg("UVSCC: ");
- prettyprint_ich_reg_vscc(tmp, FLASHROM_MSG_DEBUG, false);
- }
+ /* If the descriptor is valid and indicates multiple
+ * flash devices we need to use hwseq to be able to
+ * access the second flash device.
+ */
+ if (ich_spi_mode == ich_auto && desc.content.NC != 0) {
+ msg_pinfo("Enabling hardware sequencing due to multiple flash chips detected.\n");
+ ich_spi_mode = ich_hwseq;
+ }
+ }
- switch (ich_gen) {
- case CHIPSET_ICH8:
- case CHIPSET_100_SERIES_SUNRISE_POINT:
- case CHIPSET_C620_SERIES_LEWISBURG:
- case CHIPSET_300_SERIES_CANNON_POINT:
- case CHIPSET_400_SERIES_COMET_POINT:
- case CHIPSET_APOLLO_LAKE:
- break;
- default:
- tmp = mmio_readl(spibar + ICH9_REG_FPB);
- msg_pdbg("0x%x: 0x%08x (FPB)\n", ICH9_REG_FPB, tmp);
- break;
- }
+ if (ich_spi_mode == ich_auto && ichspi_lock &&
+ ich_missing_opcodes()) {
+ msg_pinfo("Enabling hardware sequencing because "
+ "some important opcode is locked.\n");
+ ich_spi_mode = ich_hwseq;
+ }
- if (read_ich_descriptors_via_fdo(ich_gen, spibar, &desc) == ICH_RET_OK)
- prettyprint_ich_descriptors(ich_gen, &desc);
+ if (ich_spi_mode == ich_auto &&
+ (ich_gen == CHIPSET_100_SERIES_SUNRISE_POINT ||
+ ich_gen == CHIPSET_300_SERIES_CANNON_POINT ||
+ ich_gen == CHIPSET_400_SERIES_COMET_POINT ||
+ ich_gen == CHIPSET_500_SERIES_TIGER_POINT ||
+ ich_gen == CHIPSET_600_SERIES_ALDER_POINT)) {
+ msg_pdbg("Enabling hardware sequencing by default for 100+ series PCH.\n");
+ ich_spi_mode = ich_hwseq;
+ }
- /* If the descriptor is valid and indicates multiple
- * flash devices we need to use hwseq to be able to
- * access the second flash device.
- */
- if (ich_spi_mode == ich_auto && desc.content.NC != 0) {
- msg_pinfo("Enabling hardware sequencing due to "
- "multiple flash chips detected.\n");
- ich_spi_mode = ich_hwseq;
- }
- }
+ if (ich_spi_mode == ich_auto &&
+ (ich_gen == CHIPSET_APOLLO_LAKE ||
+ ich_gen == CHIPSET_GEMINI_LAKE ||
+ ich_gen == CHIPSET_JASPER_LAKE ||
+ ich_gen == CHIPSET_ELKHART_LAKE ||
+ ich_gen == CHIPSET_METEOR_LAKE)) {
+ msg_pdbg("Enabling hardware sequencing by default for Apollo/Gemini/Jasper/Elkhart/Meteor Lake.\n");
+ ich_spi_mode = ich_hwseq;
+ }
- if (ich_spi_mode == ich_auto && ichspi_lock &&
- ich_missing_opcodes()) {
- msg_pinfo("Enabling hardware sequencing because "
- "some important opcode is locked.\n");
- ich_spi_mode = ich_hwseq;
+ if (ich_spi_mode == ich_hwseq) {
+ if (!desc_valid) {
+ msg_perr("Hardware sequencing was requested "
+ "but the flash descriptor is not valid. Aborting.\n");
+ return ERROR_FLASHROM_FATAL;
}
- if (ich_spi_mode == ich_auto &&
- (ich_gen == CHIPSET_100_SERIES_SUNRISE_POINT ||
- ich_gen == CHIPSET_300_SERIES_CANNON_POINT ||
- ich_gen == CHIPSET_400_SERIES_COMET_POINT)) {
- msg_pdbg("Enabling hardware sequencing by default for 100+ series PCH.\n");
- ich_spi_mode = ich_hwseq;
+ int tmpi = getFCBA_component_density(ich_gen, &desc, 0);
+ if (tmpi < 0) {
+ msg_perr("Could not determine density of flash component %d.\n", 0);
+ return ERROR_FLASHROM_FATAL;
}
+ hwseq_data.size_comp0 = tmpi;
- if (ich_spi_mode == ich_auto && ich_gen == CHIPSET_APOLLO_LAKE) {
- msg_pdbg("Enabling hardware sequencing by default for Apollo Lake.\n");
- ich_spi_mode = ich_hwseq;
+ tmpi = getFCBA_component_density(ich_gen, &desc, 1);
+ if (tmpi < 0) {
+ msg_perr("Could not determine density of flash component %d.\n", 1);
+ return ERROR_FLASHROM_FATAL;
}
+ hwseq_data.size_comp1 = tmpi;
- if (ich_spi_mode == ich_hwseq) {
- if (!desc_valid) {
- msg_perr("Hardware sequencing was requested "
- "but the flash descriptor is not "
- "valid. Aborting.\n");
- return ERROR_FATAL;
- }
+ struct hwseq_data *opaque_hwseq_data = calloc(1, sizeof(struct hwseq_data));
+ if (!opaque_hwseq_data)
+ return ERROR_FLASHROM_FATAL;
+ memcpy(opaque_hwseq_data, &hwseq_data, sizeof(*opaque_hwseq_data));
+ register_opaque_master(&opaque_master_ich_hwseq, opaque_hwseq_data);
+ } else {
+ register_spi_master(&spi_master_ich9, NULL);
+ }
- int tmpi = getFCBA_component_density(ich_gen, &desc, 0);
- if (tmpi < 0) {
- msg_perr("Could not determine density of flash component %d.\n", 0);
- return ERROR_FATAL;
- }
- hwseq_data.size_comp0 = tmpi;
+ return 0;
+}
- tmpi = getFCBA_component_density(ich_gen, &desc, 1);
- if (tmpi < 0) {
- msg_perr("Could not determine density of flash component %d.\n", 1);
- return ERROR_FATAL;
- }
- hwseq_data.size_comp1 = tmpi;
+int ich_init_spi(const struct programmer_cfg *cfg, void *spibar, enum ich_chipset ich_gen)
+{
+ ich_generation = ich_gen;
+ ich_spibar = spibar;
- register_opaque_master(&opaque_master_ich_hwseq);
- } else {
- register_spi_master(&spi_master_ich9);
- }
- break;
+ switch (ich_gen) {
+ case CHIPSET_ICH7:
+ case CHIPSET_TUNNEL_CREEK:
+ case CHIPSET_CENTERTON:
+ return init_ich7_spi(spibar, ich_gen);
+ case CHIPSET_ICH8:
+ default: /* Future version might behave the same */
+ return init_ich_default(cfg, spibar, ich_gen);
}
-
- return 0;
}
static const struct spi_master spi_master_via = {
- .max_data_read = 16,
- .max_data_write = 16,
- .command = ich_spi_send_command,
- .multicommand = ich_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .max_data_read = 16,
+ .max_data_write = 16,
+ .command = ich_spi_send_command,
+ .multicommand = ich_spi_send_multicommand,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .probe_opcode = ich_spi_probe_opcode,
};
int via_init_spi(uint32_t mmio_base)
@@ -2071,42 +2392,40 @@ int via_init_spi(uint32_t mmio_base)
ich_spibar = rphysmap("VIA SPI MMIO registers", mmio_base, 0x70);
if (ich_spibar == ERROR_PTR)
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
/* Do we really need no write enable? Like the LPC one at D17F0 0x40 */
/* Not sure if it speaks all these bus protocols. */
internal_buses_supported &= BUS_LPC | BUS_FWH;
ich_generation = CHIPSET_ICH7;
- register_spi_master(&spi_master_via);
+ register_spi_master(&spi_master_via, NULL);
- msg_pdbg("0x00: 0x%04x (SPIS)\n", mmio_readw(ich_spibar + 0));
- msg_pdbg("0x02: 0x%04x (SPIC)\n", mmio_readw(ich_spibar + 2));
- msg_pdbg("0x04: 0x%08x (SPIA)\n", mmio_readl(ich_spibar + 4));
+ msg_pdbg("0x00: 0x%04"PRIx16" (SPIS)\n", mmio_readw(ich_spibar + 0));
+ msg_pdbg("0x02: 0x%04"PRIx16" (SPIC)\n", mmio_readw(ich_spibar + 2));
+ msg_pdbg("0x04: 0x%08"PRIx32" (SPIA)\n", mmio_readl(ich_spibar + 4));
for (i = 0; i < 2; i++) {
int offs;
offs = 8 + (i * 8);
- msg_pdbg("0x%02x: 0x%08x (SPID%d)\n", offs,
- mmio_readl(ich_spibar + offs), i);
- msg_pdbg("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4,
+ msg_pdbg("0x%02x: 0x%08"PRIx32" (SPID%d)\n", offs, mmio_readl(ich_spibar + offs), i);
+ msg_pdbg("0x%02x: 0x%08"PRIx32" (SPID%d+4)\n", offs + 4,
mmio_readl(ich_spibar + offs + 4), i);
}
ichspi_bbar = mmio_readl(ich_spibar + 0x50);
- msg_pdbg("0x50: 0x%08x (BBAR)\n", ichspi_bbar);
- msg_pdbg("0x54: 0x%04x (PREOP)\n", mmio_readw(ich_spibar + 0x54));
- msg_pdbg("0x56: 0x%04x (OPTYPE)\n", mmio_readw(ich_spibar + 0x56));
- msg_pdbg("0x58: 0x%08x (OPMENU)\n", mmio_readl(ich_spibar + 0x58));
- msg_pdbg("0x5c: 0x%08x (OPMENU+4)\n", mmio_readl(ich_spibar + 0x5c));
+
+ msg_pdbg("0x50: 0x%08"PRIx32" (BBAR)\n", ichspi_bbar);
+ msg_pdbg("0x54: 0x%04"PRIx16" (PREOP)\n", mmio_readw(ich_spibar + 0x54));
+ msg_pdbg("0x56: 0x%04"PRIx16" (OPTYPE)\n", mmio_readw(ich_spibar + 0x56));
+ msg_pdbg("0x58: 0x%08"PRIx32" (OPMENU)\n", mmio_readl(ich_spibar + 0x58));
+ msg_pdbg("0x5c: 0x%08"PRIx32" (OPMENU+4)\n", mmio_readl(ich_spibar + 0x5c));
for (i = 0; i < 3; i++) {
int offs;
offs = 0x60 + (i * 4);
- msg_pdbg("0x%02x: 0x%08x (PBR%d)\n", offs,
- mmio_readl(ich_spibar + offs), i);
+ msg_pdbg("0x%02x: 0x%08"PRIx32" (PBR%d)\n", offs, mmio_readl(ich_spibar + offs), i);
}
- msg_pdbg("0x6c: 0x%04x (CLOCK/DEBUG)\n",
- mmio_readw(ich_spibar + 0x6c));
+ msg_pdbg("0x6c: 0x%04x (CLOCK/DEBUG)\n", mmio_readw(ich_spibar + 0x6c));
if (mmio_readw(ich_spibar) & (1 << 15)) {
msg_pwarn("Warning: SPI Configuration Lockdown activated.\n");
- ichspi_lock = 1;
+ ichspi_lock = true;
}
ich_set_bbar(0, ich_generation);
@@ -2114,5 +2433,3 @@ int via_init_spi(uint32_t mmio_base)
return 0;
}
-
-#endif
diff --git a/chipdrivers.h b/include/chipdrivers.h
index e1d6aa9e7..a2e75d1a5 100644
--- a/chipdrivers.h
+++ b/include/chipdrivers.h
@@ -26,6 +26,7 @@
int spi_aai_write(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
int spi_chip_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, int unsigned len);
+bool spi_probe_opcode(const struct flashctx *flash, uint8_t opcode);
/* spi25.c */
int probe_spi_rdid(struct flashctx *flash);
@@ -41,6 +42,7 @@ int spi_block_erase_20(struct flashctx *flash, unsigned int addr, unsigned int b
int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_50(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_52(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+int spi_block_erase_53(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_5c(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_60(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_62(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
@@ -51,7 +53,8 @@ int spi_block_erase_d7(struct flashctx *flash, unsigned int addr, unsigned int b
int spi_block_erase_d8(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_db(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
int spi_block_erase_dc(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
-erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode);
+enum block_erase_func spi25_get_erasefn_from_opcode(uint8_t opcode);
+const uint8_t *spi_get_opcode_from_erasefn(enum block_erase_func func);
int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
int spi_nbyte_read(struct flashctx *flash, unsigned int addr, uint8_t *bytes, unsigned int len);
int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len, unsigned int chunksize);
@@ -62,48 +65,9 @@ int spi_set_extended_address(struct flashctx *, uint8_t addr_high);
/* spi25_statusreg.c */
-uint8_t spi_read_status_register(const struct flashctx *flash);
-int spi_write_status_register(const struct flashctx *flash, int status);
+int spi_read_register(const struct flashctx *flash, enum flash_reg reg, uint8_t *value);
+int spi_write_register(const struct flashctx *flash, enum flash_reg reg, uint8_t value);
void spi_prettyprint_status_register_bit(uint8_t status, int bit);
-int spi_prettyprint_status_register_plain(struct flashctx *flash);
-int spi_prettyprint_status_register_default_welwip(struct flashctx *flash);
-int spi_prettyprint_status_register_bp1_srwd(struct flashctx *flash);
-int spi_prettyprint_status_register_bp2_srwd(struct flashctx *flash);
-int spi_prettyprint_status_register_bp3_srwd(struct flashctx *flash);
-int spi_prettyprint_status_register_bp4_srwd(struct flashctx *flash);
-int spi_prettyprint_status_register_bp2_bpl(struct flashctx *flash);
-int spi_prettyprint_status_register_bp2_tb_bpl(struct flashctx *flash);
-int spi_disable_blockprotect(struct flashctx *flash);
-int spi_disable_blockprotect_bp1_srwd(struct flashctx *flash);
-int spi_disable_blockprotect_bp2_srwd(struct flashctx *flash);
-int spi_disable_blockprotect_bp3_srwd(struct flashctx *flash);
-int spi_disable_blockprotect_bp4_srwd(struct flashctx *flash);
-int spi_prettyprint_status_register_amic_a25l032(struct flashctx *flash);
-int spi_prettyprint_status_register_at25df(struct flashctx *flash);
-int spi_prettyprint_status_register_at25df_sec(struct flashctx *flash);
-int spi_prettyprint_status_register_at25f(struct flashctx *flash);
-int spi_prettyprint_status_register_at25f512a(struct flashctx *flash);
-int spi_prettyprint_status_register_at25f512b(struct flashctx *flash);
-int spi_prettyprint_status_register_at25f4096(struct flashctx *flash);
-int spi_prettyprint_status_register_at25fs010(struct flashctx *flash);
-int spi_prettyprint_status_register_at25fs040(struct flashctx *flash);
-int spi_prettyprint_status_register_at26df081a(struct flashctx *flash);
-int spi_disable_blockprotect_at2x_global_unprotect(struct flashctx *flash);
-int spi_disable_blockprotect_at2x_global_unprotect_sec(struct flashctx *flash);
-int spi_disable_blockprotect_at25f(struct flashctx *flash);
-int spi_disable_blockprotect_at25f512a(struct flashctx *flash);
-int spi_disable_blockprotect_at25f512b(struct flashctx *flash);
-int spi_disable_blockprotect_at25fs010(struct flashctx *flash);
-int spi_disable_blockprotect_at25fs040(struct flashctx *flash);
-int spi_prettyprint_status_register_en25s_wp(struct flashctx *flash);
-int spi_prettyprint_status_register_n25q(struct flashctx *flash);
-int spi_disable_blockprotect_n25q(struct flashctx *flash);
-int spi_prettyprint_status_register_bp2_ep_srwd(struct flashctx *flash);
-int spi_disable_blockprotect_bp2_ep_srwd(struct flashctx *flash);
-int spi_prettyprint_status_register_sst25(struct flashctx *flash);
-int spi_prettyprint_status_register_sst25vf016(struct flashctx *flash);
-int spi_prettyprint_status_register_sst25vf040b(struct flashctx *flash);
-int spi_disable_blockprotect_sst26_global_unprotect(struct flashctx *flash);
/* sfdp.c */
int probe_spi_sfdp(struct flashctx *flash);
@@ -133,8 +97,7 @@ int probe_82802ab(struct flashctx *flash);
int erase_block_82802ab(struct flashctx *flash, unsigned int page, unsigned int pagesize);
int write_82802ab(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
void print_status_82802ab(uint8_t status);
-int unlock_28f004s5(struct flashctx *flash);
-int unlock_lh28f008bjt(struct flashctx *flash);
+blockprotect_func_t *lookup_82802ab_blockprotect_func_ptr(const struct flashchip *const chip);
/* jedec.c */
uint8_t oddparity(uint8_t val);
@@ -148,10 +111,7 @@ int erase_sector_jedec(struct flashctx *flash, unsigned int page, unsigned int p
int erase_block_jedec(struct flashctx *flash, unsigned int page, unsigned int blocksize);
int erase_chip_block_jedec(struct flashctx *flash, unsigned int page, unsigned int blocksize);
-int unlock_regspace2_uniform_32k(struct flashctx *flash);
-int unlock_regspace2_uniform_64k(struct flashctx *flash);
-int unlock_regspace2_block_eraser_0(struct flashctx *flash);
-int unlock_regspace2_block_eraser_1(struct flashctx *flash);
+blockprotect_func_t *lookup_jedec_blockprotect_func_ptr(const struct flashchip *const chip);
int printlock_regspace2_uniform_64k(struct flashctx *flash);
int printlock_regspace2_block_eraser_0(struct flashctx *flash);
int printlock_regspace2_block_eraser_1(struct flashctx *flash);
@@ -193,6 +153,7 @@ int printlock_at49f(struct flashctx *flash);
/* w29ee011.c */
int probe_w29ee011(struct flashctx *flash);
+bool w29ee011_can_override(const char *const chip_name, const char *const override_chip);
/* stm50.c */
int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int blocksize);
@@ -201,9 +162,6 @@ int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int
int probe_en29lv640b(struct flashctx *flash);
int write_en29lv640b(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
-/* dummyflasher.c */
-int probe_variable_size(struct flashctx *flash);
-
/* edi.c */
int edi_chip_block_erase(struct flashctx *flash, unsigned int page, unsigned int size);
int edi_chip_write(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
@@ -214,4 +172,10 @@ int edi_probe_kb9012(struct flashctx *flash);
int probe_spi_st95(struct flashctx *flash);
int spi_block_erase_emulation(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+/* writeprotect_ranges.c */
+void decode_range_spi25(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len);
+void decode_range_spi25_64k_block(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len);
+void decode_range_spi25_bit_cmp(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len);
+void decode_range_spi25_2x_block(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len);
+
#endif /* !__CHIPDRIVERS_H__ */
diff --git a/include/cli_classic.h b/include/cli_classic.h
new file mode 100644
index 000000000..e651cc636
--- /dev/null
+++ b/include/cli_classic.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * 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 CLI_CLASSIC_H
+#define CLI_CLASSIC_H
+
+#if __has_include(<getopt.h>)
+#include <getopt.h>
+#else
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+struct option {
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+int getopt (int argc, char *const *argv, const char *shortopts);
+int getopt_long (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+int getopt_long_only (int argc, char *const *argv, const char *shortopts,
+ const struct option *longopts, int *longind);
+
+#endif /* __has_include() */
+#endif /* CLI_CLASSIC_H */
diff --git a/coreboot_tables.h b/include/coreboot_tables.h
index e1f63a81d..e1f63a81d 100644
--- a/coreboot_tables.h
+++ b/include/coreboot_tables.h
diff --git a/custom_baud.h b/include/custom_baud.h
index c8b8fc296..38e6cfc40 100644
--- a/custom_baud.h
+++ b/include/custom_baud.h
@@ -22,7 +22,13 @@ struct baudentry {
unsigned int baud;
};
-int set_custom_baudrate(int fd, unsigned int baud);
+enum custom_baud_stage {
+ BEFORE_FLAGS = 0,
+ WITH_FLAGS,
+ AFTER_FLAGS
+};
+
+int set_custom_baudrate(int fd, unsigned int baud, const enum custom_baud_stage stage, void *tio_wanted);
/* Returns 1 if non-exact rate would be used, and setting a custom rate is supported.
The baudtable must be in ascending order and terminated with a 0-baud entry. */
diff --git a/edi.h b/include/edi.h
index 542bf26ec..542bf26ec 100644
--- a/edi.h
+++ b/include/edi.h
diff --git a/ene.h b/include/ene.h
index e03e49b2e..e03e49b2e 100644
--- a/ene.h
+++ b/include/ene.h
diff --git a/include/erasure_layout.h b/include/erasure_layout.h
new file mode 100644
index 000000000..b8b5f089a
--- /dev/null
+++ b/include/erasure_layout.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2022 Aarya Chaumal
+ *
+ * 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 __ERASURE_LAYOUT_H__
+#define __ERASURE_LAYOUT_H__ 1
+
+struct eraseblock_data {
+ chipoff_t start_addr;
+ chipoff_t end_addr;
+ bool selected;
+ size_t block_num;
+ size_t first_sub_block_index;
+ size_t last_sub_block_index;
+};
+
+struct erase_layout {
+ struct eraseblock_data* layout_list;
+ size_t block_count;
+ const struct block_eraser *eraser;
+};
+
+void free_erase_layout(struct erase_layout *layout, unsigned int erasefn_count);
+int create_erase_layout(struct flashctx *const flashctx, struct erase_layout **erase_layout);
+int erase_write(struct flashctx *const flashctx, chipoff_t region_start, chipoff_t region_end,
+ uint8_t* curcontents, uint8_t* newcontents,
+ struct erase_layout *erase_layout, bool *all_skipped);
+
+#endif /* !__ERASURE_LAYOUT_H__ */
diff --git a/flash.h b/include/flash.h
index 883b6f4b4..4c08549bc 100644
--- a/flash.h
+++ b/include/flash.h
@@ -20,8 +20,6 @@
#ifndef __FLASH_H__
#define __FLASH_H__ 1
-#include "platform.h"
-
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
@@ -36,10 +34,13 @@
#include "libflashrom.h"
#include "layout.h"
+#include "writeprotect.h"
#define KiB (1024)
#define MiB (1024 * KiB)
+#define BIT(x) (1<<(x))
+
/* Assumes `n` and `a` are at most 64-bit wide (to avoid typeof() operator). */
#define ALIGN_DOWN(n, a) ((n) & ~((uint64_t)(a) - 1))
@@ -54,9 +55,13 @@ typedef uintptr_t chipaddr;
#define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2))
int register_shutdown(int (*function) (void *data), void *data);
-void *programmer_map_flash_region(const char *descr, uintptr_t phys_addr, size_t len);
-void programmer_unmap_flash_region(void *virt_addr, size_t len);
-void programmer_delay(unsigned int usecs);
+struct registered_master;
+void *master_map_flash_region(const struct registered_master *mast,
+ const char *descr, uintptr_t phys_addr, size_t len);
+void master_unmap_flash_region(const struct registered_master *mast,
+ void *virt_addr, size_t len);
+/* NOTE: flashctx is not used in default_delay. In this case, a context should be NULL. */
+void programmer_delay(const struct flashrom_flashctx *flash, unsigned int usecs);
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
@@ -72,23 +77,23 @@ enum chipbustype {
/*
* The following enum defines possible write granularities of flash chips. These tend to reflect the properties
- * of the actual hardware not necesserily the write function(s) defined by the respective struct flashchip.
+ * of the actual hardware not necessarily the write function(s) defined by the respective struct flashchip.
* The latter might (and should) be more precisely specified, e.g. they might bail out early if their execution
* would result in undefined chip contents.
*/
enum write_granularity {
/* We assume 256 byte granularity by default. */
- write_gran_256bytes = 0,/* If less than 256 bytes are written, the unwritten bytes are undefined. */
- write_gran_1bit, /* Each bit can be cleared individually. */
- write_gran_1byte, /* A byte can be written once. Further writes to an already written byte cause
+ WRITE_GRAN_256BYTES = 0,/* If less than 256 bytes are written, the unwritten bytes are undefined. */
+ WRITE_GRAN_1BIT, /* Each bit can be cleared individually. */
+ WRITE_GRAN_1BYTE, /* A byte can be written once. Further writes to an already written byte cause
* its contents to be either undefined or to stay unchanged. */
- write_gran_128bytes, /* If less than 128 bytes are written, the unwritten bytes are undefined. */
- write_gran_264bytes, /* If less than 264 bytes are written, the unwritten bytes are undefined. */
- write_gran_512bytes, /* If less than 512 bytes are written, the unwritten bytes are undefined. */
- write_gran_528bytes, /* If less than 528 bytes are written, the unwritten bytes are undefined. */
- write_gran_1024bytes, /* If less than 1024 bytes are written, the unwritten bytes are undefined. */
- write_gran_1056bytes, /* If less than 1056 bytes are written, the unwritten bytes are undefined. */
- write_gran_1byte_implicit_erase, /* EEPROMs and other chips with implicit erase and 1-byte writes. */
+ WRITE_GRAN_128BYTES, /* If less than 128 bytes are written, the unwritten bytes are undefined. */
+ WRITE_GRAN_264BYTES, /* If less than 264 bytes are written, the unwritten bytes are undefined. */
+ WRITE_GRAN_512BYTES, /* If less than 512 bytes are written, the unwritten bytes are undefined. */
+ WRITE_GRAN_528BYTES, /* If less than 528 bytes are written, the unwritten bytes are undefined. */
+ WRITE_GRAN_1024BYTES, /* If less than 1024 bytes are written, the unwritten bytes are undefined. */
+ WRITE_GRAN_1056BYTES, /* If less than 1056 bytes are written, the unwritten bytes are undefined. */
+ WRITE_GRAN_1BYTE_IMPLICIT_ERASE, /* EEPROMs and other chips with implicit erase and 1-byte writes. */
};
/*
@@ -125,24 +130,42 @@ enum write_granularity {
#define FEATURE_4BA_ENTER (1 << 10) /**< Can enter/exit 4BA mode with instructions 0xb7/0xe9 w/o WREN */
#define FEATURE_4BA_ENTER_WREN (1 << 11) /**< Can enter/exit 4BA mode with instructions 0xb7/0xe9 after WREN */
#define FEATURE_4BA_ENTER_EAR7 (1 << 12) /**< Can enter/exit 4BA mode by setting bit7 of the ext addr reg */
-#define FEATURE_4BA_EXT_ADDR (1 << 13) /**< Regular 3-byte operations can be used by writing the most
- significant address byte into an extended address register. */
-#define FEATURE_4BA_READ (1 << 14) /**< Native 4BA read instruction (0x13) is supported. */
-#define FEATURE_4BA_FAST_READ (1 << 15) /**< Native 4BA fast read instruction (0x0c) is supported. */
-#define FEATURE_4BA_WRITE (1 << 16) /**< Native 4BA byte program (0x12) is supported. */
+#define FEATURE_4BA_EAR_C5C8 (1 << 13) /**< Regular 3-byte operations can be used by writing the most
+ significant address byte into an extended address register
+ (using 0xc5/0xc8 instructions). */
+#define FEATURE_4BA_EAR_1716 (1 << 14) /**< Like FEATURE_4BA_EAR_C5C8 but with 0x17/0x16 instructions. */
+#define FEATURE_4BA_READ (1 << 15) /**< Native 4BA read instruction (0x13) is supported. */
+#define FEATURE_4BA_FAST_READ (1 << 16) /**< Native 4BA fast read instruction (0x0c) is supported. */
+#define FEATURE_4BA_WRITE (1 << 17) /**< Native 4BA byte program (0x12) is supported. */
/* 4BA Shorthands */
+#define FEATURE_4BA_EAR_ANY (FEATURE_4BA_EAR_C5C8 | FEATURE_4BA_EAR_1716)
#define FEATURE_4BA_NATIVE (FEATURE_4BA_READ | FEATURE_4BA_FAST_READ | FEATURE_4BA_WRITE)
-#define FEATURE_4BA (FEATURE_4BA_ENTER | FEATURE_4BA_EXT_ADDR | FEATURE_4BA_NATIVE)
-#define FEATURE_4BA_WREN (FEATURE_4BA_ENTER_WREN | FEATURE_4BA_EXT_ADDR | FEATURE_4BA_NATIVE)
-#define FEATURE_4BA_EAR7 (FEATURE_4BA_ENTER_EAR7 | FEATURE_4BA_EXT_ADDR | FEATURE_4BA_NATIVE)
+#define FEATURE_4BA (FEATURE_4BA_ENTER | FEATURE_4BA_EAR_C5C8 | FEATURE_4BA_NATIVE)
+#define FEATURE_4BA_WREN (FEATURE_4BA_ENTER_WREN | FEATURE_4BA_EAR_C5C8 | FEATURE_4BA_NATIVE)
+#define FEATURE_4BA_EAR7 (FEATURE_4BA_ENTER_EAR7 | FEATURE_4BA_EAR_C5C8 | FEATURE_4BA_NATIVE)
/*
* Most flash chips are erased to ones and programmed to zeros. However, some
* other flash chips, such as the ENE KB9012 internal flash, work the opposite way.
*/
-#define FEATURE_ERASED_ZERO (1 << 17)
-#define FEATURE_NO_ERASE (1 << 18)
+#define FEATURE_ERASED_ZERO (1 << 18)
+#define FEATURE_NO_ERASE (1 << 19)
+
+#define FEATURE_WRSR_EXT2 (1 << 20)
+#define FEATURE_WRSR2 (1 << 21)
+#define FEATURE_WRSR_EXT3 ((1 << 22) | FEATURE_WRSR_EXT2)
+#define FEATURE_WRSR3 (1 << 23)
+
+/*
+ * Whether chip has security register (RDSCUR/WRSCUR commands).
+ * Not to be confused with "secure registers" of OTP.
+ */
+#define FEATURE_SCUR (1 << 24)
+
+/* Whether chip has configuration register (RDCR/WRSR_EXT2 commands) */
+#define FEATURE_CFGR (1 << 25)
#define ERASED_VALUE(flash) (((flash)->chip->feature_bits & FEATURE_ERASED_ZERO) ? 0x00 : 0xff)
+#define UNERASED_VALUE(flash) (((flash)->chip->feature_bits & FEATURE_ERASED_ZERO) ? 0xff : 0x00)
enum test_state {
OK = 0,
@@ -152,22 +175,229 @@ enum test_state {
NA, /* Not applicable (e.g. write support on ROM chips) */
};
-#define TEST_UNTESTED (struct tested){ .probe = NT, .read = NT, .erase = NT, .write = NT }
+#define TEST_UNTESTED (struct tested){ .probe = NT, .read = NT, .erase = NT, .write = NT, .wp = NT }
-#define TEST_OK_PROBE (struct tested){ .probe = OK, .read = NT, .erase = NT, .write = NT }
-#define TEST_OK_PR (struct tested){ .probe = OK, .read = OK, .erase = NT, .write = NT }
-#define TEST_OK_PRE (struct tested){ .probe = OK, .read = OK, .erase = OK, .write = NT }
-#define TEST_OK_PREW (struct tested){ .probe = OK, .read = OK, .erase = OK, .write = OK }
+#define TEST_OK_PROBE (struct tested){ .probe = OK, .read = NT, .erase = NT, .write = NT, .wp = NT }
+#define TEST_OK_PR (struct tested){ .probe = OK, .read = OK, .erase = NT, .write = NT, .wp = NT }
+#define TEST_OK_PRE (struct tested){ .probe = OK, .read = OK, .erase = OK, .write = NT, .wp = NT }
+#define TEST_OK_PREW (struct tested){ .probe = OK, .read = OK, .erase = OK, .write = OK, .wp = NT }
+#define TEST_OK_PREWB (struct tested){ .probe = OK, .read = OK, .erase = OK, .write = OK, .wp = OK }
-#define TEST_BAD_PROBE (struct tested){ .probe = BAD, .read = NT, .erase = NT, .write = NT }
-#define TEST_BAD_PR (struct tested){ .probe = BAD, .read = BAD, .erase = NT, .write = NT }
-#define TEST_BAD_PRE (struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = NT }
-#define TEST_BAD_PREW (struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = BAD }
+#define TEST_BAD_PROBE (struct tested){ .probe = BAD, .read = NT, .erase = NT, .write = NT, .wp = NT }
+#define TEST_BAD_PR (struct tested){ .probe = BAD, .read = BAD, .erase = NT, .write = NT, .wp = NT }
+#define TEST_BAD_PRE (struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = NT, .wp = NT }
+#define TEST_BAD_PREW (struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = BAD, .wp = NT }
+#define TEST_BAD_PREWB (struct tested){ .probe = BAD, .read = BAD, .erase = BAD, .write = BAD, .wp = BAD }
struct flashrom_flashctx;
-#define flashctx flashrom_flashctx /* TODO: Agree on a name and convert all occurences. */
+#define flashctx flashrom_flashctx /* TODO: Agree on a name and convert all occurrences. */
typedef int (erasefunc_t)(struct flashctx *flash, unsigned int addr, unsigned int blocklen);
+enum flash_reg {
+ INVALID_REG = 0,
+ STATUS1,
+ STATUS2,
+ STATUS3,
+ SECURITY,
+ CONFIG,
+ MAX_REGISTERS
+};
+
+struct reg_bit_info {
+ /* Register containing the bit */
+ enum flash_reg reg;
+
+ /* Bit index within register */
+ uint8_t bit_index;
+
+ /*
+ * Writability of the bit. RW does not guarantee the bit will be
+ * writable, for example if status register protection is enabled.
+ */
+ enum {
+ RO, /* Read only */
+ RW, /* Readable and writable */
+ OTP /* One-time programmable */
+ } writability;
+};
+
+struct wp_bits;
+
+enum decode_range_func {
+ NO_DECODE_RANGE_FUNC = 0, /* 0 indicates no range decode function is set. */
+ DECODE_RANGE_SPI25 = 1,
+ DECODE_RANGE_SPI25_64K_BLOCK = 2,
+ DECODE_RANGE_SPI25_BIT_CMP = 3,
+ DECODE_RANGE_SPI25_2X_BLOCK = 4,
+};
+typedef void (decode_range_func_t)(size_t *start, size_t *len, const struct wp_bits *, size_t chip_len);
+
+enum probe_func {
+ NO_PROBE_FUNC = 0, /* 0 indicates no probe function set. */
+ PROBE_JEDEC = 1,
+ PROBE_JEDEC_29GL,
+ PROBE_OPAQUE,
+ PROBE_EDI_KB9012,
+ PROBE_AT82802AB,
+ PROBE_W29EE011,
+ PROBE_EN29LV640B,
+ PROBE_SPI_AT25F,
+ PROBE_SPI_AT45DB,
+ PROBE_SPI_BIG_SPANSION,
+ PROBE_SPI_RDID,
+ PROBE_SPI_RDID4,
+ PROBE_SPI_REMS,
+ PROBE_SPI_RES1,
+ PROBE_SPI_RES2,
+ PROBE_SPI_SFDP,
+ PROBE_SPI_ST95,
+};
+
+enum write_func {
+ NO_WRITE_FUNC = 0, /* 0 indicates no write function set. */
+ WRITE_JEDEC = 1,
+ WRITE_JEDEC1,
+ WRITE_OPAQUE,
+ SPI_CHIP_WRITE1,
+ SPI_CHIP_WRITE256,
+ SPI_WRITE_AAI,
+ SPI_WRITE_AT45DB,
+ WRITE_28SF040,
+ WRITE_82802AB,
+ WRITE_EN29LV640B,
+ EDI_CHIP_WRITE,
+ TEST_WRITE_INJECTOR, /* special case must come last. */
+};
+typedef int (write_func_t)(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
+
+enum read_func {
+ NO_READ_FUNC = 0, /* 0 indicates no read function set. */
+ SPI_CHIP_READ = 1,
+ READ_OPAQUE,
+ READ_MEMMAPPED,
+ EDI_CHIP_READ,
+ SPI_READ_AT45DB,
+ SPI_READ_AT45DB_E8,
+ TEST_READ_INJECTOR, /* special case must come last. */
+};
+typedef int (read_func_t)(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+int read_flash(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
+
+enum block_erase_func {
+ NO_BLOCK_ERASE_FUNC = 0, /* 0 indicates no block erase function set. */
+ SPI_BLOCK_ERASE_EMULATION = 1,
+ SPI_BLOCK_ERASE_20,
+ SPI_BLOCK_ERASE_21,
+ SPI_BLOCK_ERASE_40,
+ SPI_BLOCK_ERASE_50,
+ SPI_BLOCK_ERASE_52,
+ SPI_BLOCK_ERASE_53,
+ SPI_BLOCK_ERASE_5C,
+ SPI_BLOCK_ERASE_60,
+ SPI_BLOCK_ERASE_62,
+ SPI_BLOCK_ERASE_81,
+ SPI_BLOCK_ERASE_C4,
+ SPI_BLOCK_ERASE_C7,
+ SPI_BLOCK_ERASE_D7,
+ SPI_BLOCK_ERASE_D8,
+ SPI_BLOCK_ERASE_DB,
+ SPI_BLOCK_ERASE_DC,
+ S25FL_BLOCK_ERASE,
+ S25FS_BLOCK_ERASE_D8,
+ JEDEC_SECTOR_ERASE,
+ JEDEC_BLOCK_ERASE,
+ JEDEC_CHIP_BLOCK_ERASE,
+ OPAQUE_ERASE,
+ SPI_ERASE_AT45CS_SECTOR,
+ SPI_ERASE_AT45DB_BLOCK,
+ SPI_ERASE_AT45DB_CHIP,
+ SPI_ERASE_AT45DB_PAGE,
+ SPI_ERASE_AT45DB_SECTOR,
+ ERASE_CHIP_28SF040,
+ ERASE_SECTOR_28SF040,
+ ERASE_BLOCK_82802AB,
+ ERASE_SECTOR_49LFXXXC,
+ STM50_SECTOR_ERASE,
+ EDI_CHIP_BLOCK_ERASE,
+ TEST_ERASE_INJECTOR, /* special case must come last. */
+};
+
+enum blockprotect_func {
+ NO_BLOCKPROTECT_FUNC = 0, /* 0 indicates no unlock function set. */
+ SPI_DISABLE_BLOCKPROTECT,
+ SPI_DISABLE_BLOCKPROTECT_BP2_EP_SRWD,
+ SPI_DISABLE_BLOCKPROTECT_BP1_SRWD,
+ SPI_DISABLE_BLOCKPROTECT_BP2_SRWD,
+ SPI_DISABLE_BLOCKPROTECT_BP3_SRWD,
+ SPI_DISABLE_BLOCKPROTECT_BP4_SRWD,
+ SPI_DISABLE_BLOCKPROTECT_AT45DB,
+ SPI_DISABLE_BLOCKPROTECT_AT25F,
+ SPI_DISABLE_BLOCKPROTECT_AT25FS010,
+ SPI_DISABLE_BLOCKPROTECT_AT25FS040,
+ SPI_DISABLE_BLOCKPROTECT_AT25F512A,
+ SPI_DISABLE_BLOCKPROTECT_AT25F512B,
+ SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT,
+ SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT_SEC,
+ SPI_DISABLE_BLOCKPROTECT_SST26_GLOBAL_UNPROTECT,
+ SPI_DISABLE_BLOCKPROTECT_N25Q,
+ UNLOCK_REGSPACE2_BLOCK_ERASER_0,
+ UNLOCK_REGSPACE2_BLOCK_ERASER_1,
+ UNLOCK_REGSPACE2_UNIFORM_32K,
+ UNLOCK_REGSPACE2_UNIFORM_64K,
+ UNLOCK_28F004S5,
+ UNLOCK_LH28F008BJT,
+ UNLOCK_SST_FWHUB,
+ UNPROTECT_28SF040,
+};
+
+enum printlock_func {
+ NO_PRINTLOCK_FUNC,
+ PRINTLOCK_AT49F,
+ PRINTLOCK_REGSPACE2_BLOCK_ERASER_0,
+ PRINTLOCK_REGSPACE2_BLOCK_ERASER_1,
+ PRINTLOCK_SST_FWHUB,
+ PRINTLOCK_W39F010,
+ PRINTLOCK_W39L010,
+ PRINTLOCK_W39L020,
+ PRINTLOCK_W39L040,
+ PRINTLOCK_W39V040A,
+ PRINTLOCK_W39V040B,
+ PRINTLOCK_W39V040C,
+ PRINTLOCK_W39V040FA,
+ PRINTLOCK_W39V040FB,
+ PRINTLOCK_W39V040FC,
+ PRINTLOCK_W39V080A,
+ PRINTLOCK_W39V080FA,
+ PRINTLOCK_W39V080FA_DUAL,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AMIC_A25L032,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF_SEC,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT25F,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT25F4096,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT25F512A,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT25F512B,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT25FS010,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT25FS040,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT26DF081A,
+ SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB,
+ SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD,
+ SPI_PRETTYPRINT_STATUS_REGISTER_BP2_BPL,
+ SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD,
+ SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD,
+ SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL,
+ SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD,
+ SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD,
+ SPI_PRETTYPRINT_STATUS_REGISTER_DEFAULT_WELWIP,
+ SPI_PRETTYPRINT_STATUS_REGISTER_EN25S_WP,
+ SPI_PRETTYPRINT_STATUS_REGISTER_N25Q,
+ SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN,
+ SPI_PRETTYPRINT_STATUS_REGISTER_SST25,
+ SPI_PRETTYPRINT_STATUS_REGISTER_SST25VF016,
+ SPI_PRETTYPRINT_STATUS_REGISTER_SST25VF040B,
+};
+typedef int (printlockfunc_t)(struct flashctx *flash);
+printlockfunc_t *lookup_printlock_func_ptr(struct flashctx *flash);
+
struct flashchip {
const char *vendor;
const char *name;
@@ -194,6 +424,7 @@ struct flashchip {
enum test_state read;
enum test_state erase;
enum test_state write;
+ enum test_state wp;
} tested;
/*
@@ -208,7 +439,7 @@ struct flashchip {
SPI_EDI = 1,
} spi_cmd_set;
- int (*probe) (struct flashctx *flash);
+ enum probe_func probe;
/* Delay after "enter/exit ID mode" commands in microseconds.
* NB: negative values have special meanings, see TIMING_* below.
@@ -218,9 +449,7 @@ struct flashchip {
/*
* Erase blocks and associated erase function. Any chip erase function
* is stored as chip-sized virtual block together with said function.
- * The first one that fits will be chosen. There is currently no way to
- * influence that behaviour. For testing just comment out the other
- * elements or set the function pointer to NULL.
+ * The logic for how to optimally select erase functions is in erasure_layout.c
*/
struct block_eraser {
struct eraseblock {
@@ -229,28 +458,64 @@ struct flashchip {
} eraseblocks[NUM_ERASEREGIONS];
/* a block_erase function should try to erase one block of size
* 'blocklen' at address 'blockaddr' and return 0 on success. */
- int (*block_erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
+ enum block_erase_func block_erase;
} block_erasers[NUM_ERASEFUNCTIONS];
- int (*printlock) (struct flashctx *flash);
- 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);
+ enum printlock_func printlock;
+ enum blockprotect_func unlock;
+ enum write_func write;
+ enum read_func read;
struct voltage {
uint16_t min;
uint16_t max;
} voltage;
enum write_granularity gran;
- /* 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 reg_bit_map {
+ /* Status register protection bit (SRP) */
+ struct reg_bit_info srp;
+
+ /* Status register lock bit (SRP) */
+ struct reg_bit_info srl;
+
+ /*
+ * Note: some datasheets refer to configuration bits that
+ * function like TB/SEC/CMP bits as BP bits (e.g. BP3 for a bit
+ * that functions like TB).
+ *
+ * As a convention, any config bit that functions like a
+ * TB/SEC/CMP bit should be assigned to the respective
+ * tb/sec/cmp field in this structure, even if the datasheet
+ * uses a different name.
+ */
+
+ /* Block protection bits (BP) */
+ /* Extra element for terminator */
+ struct reg_bit_info bp[MAX_BP_BITS + 1];
- struct wp *wp;
+ /* Top/bottom protection bit (TB) */
+ struct reg_bit_info tb;
+
+ /* Sector/block protection bit (SEC) */
+ struct reg_bit_info sec;
+
+ /* Complement bit (CMP) */
+ struct reg_bit_info cmp;
+
+ /* Write Protect Selection (per sector protection when set) */
+ struct reg_bit_info wps;
+ } reg_bits;
+
+ /*
+ * Function that takes a set of WP config bits (e.g. BP, SEC, TB, etc)
+ * and determines what protection range they select.
+ */
+ enum decode_range_func decode_range;
};
-typedef int (*chip_restore_fn_cb_t)(struct flashctx *flash, uint8_t status);
+typedef int (*chip_restore_fn_cb_t)(struct flashctx *flash, void *data);
+typedef int (blockprotect_func_t)(struct flashctx *flash);
+blockprotect_func_t *lookup_blockprotect_func_ptr(const struct flashchip *const chip);
struct flashrom_flashctx {
struct flashchip *chip;
@@ -265,12 +530,14 @@ struct flashrom_flashctx {
chipaddr virtual_registers;
struct registered_master *mst;
const struct flashrom_layout *layout;
- struct single_layout fallback_layout;
+ struct flashrom_layout *default_layout;
struct {
bool force;
bool force_boardmismatch;
bool verify_after_write;
bool verify_whole_chip;
+ bool skip_unreadable_regions;
+ bool skip_unwritable_regions;
} flags;
/* We cache the state of the extended address register (highest byte
* of a 4BA for 3BA instructions) and the state of the 4BA mode here.
@@ -283,8 +550,11 @@ struct flashrom_flashctx {
int chip_restore_fn_count;
struct chip_restore_func_data {
chip_restore_fn_cb_t func;
- uint8_t status;
+ void *data;
} chip_restore_fn[MAX_CHIP_RESTORE_FUNCTIONS];
+ /* Progress reporting */
+ flashrom_progress_callback *progress_callback;
+ struct flashrom_progress *progress_state;
};
/* Timing used in probe routines. ZERO is -2 to differentiate between an unset
@@ -300,6 +570,7 @@ struct flashrom_flashctx {
extern const struct flashchip flashchips[];
extern const unsigned int flashchips_size;
+/* parallel.c */
void chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
void chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr);
void chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr);
@@ -336,17 +607,14 @@ size_t strnlen(const char *str, size_t n);
/* flashrom.c */
extern const char flashrom_version[];
-extern const char *chip_to_probe;
char *flashbuses_to_text(enum chipbustype bustype);
int map_flash(struct flashctx *flash);
void unmap_flash(struct flashctx *flash);
int read_memmapped(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
int erase_flash(struct flashctx *flash);
-int probe_flash(struct registered_master *mst, int startchip, struct flashctx *fill_flash, int force);
-int read_flash_to_file(struct flashctx *flash, const char *filename);
-char *extract_param(const char *const *haystack, const char *needle, const char *delim);
+int probe_flash(struct registered_master *mst, int startchip, struct flashctx *flash, int force, const char *const chip_to_probe);
int verify_range(struct flashctx *flash, const uint8_t *cmpbuf, unsigned int start, unsigned int len);
-int need_erase(const uint8_t *have, const uint8_t *want, unsigned int len, enum write_granularity gran, const uint8_t erased_value);
+void emergency_help_message(void);
void print_version(void);
void print_buildinfo(void);
void print_banner(void);
@@ -356,17 +624,20 @@ int read_buf_from_file(unsigned char *buf, unsigned long size, const char *filen
int write_buf_to_file(const unsigned char *buf, unsigned long size, const char *filename);
int prepare_flash_access(struct flashctx *, bool read_it, bool write_it, bool erase_it, bool verify_it);
void finalize_flash_access(struct flashctx *);
-int do_read(struct flashctx *, const char *filename);
-int do_erase(struct flashctx *);
-int do_write(struct flashctx *, const char *const filename, const char *const referencefile);
-int do_verify(struct flashctx *, const char *const filename);
-int register_chip_restore(chip_restore_fn_cb_t func, struct flashctx *flash, uint8_t status);
+int register_chip_restore(chip_restore_fn_cb_t func, struct flashctx *flash, void *data);
+int check_block_eraser(const struct flashctx *flash, int k, int log);
+unsigned int count_usable_erasers(const struct flashctx *flash);
+int need_erase(const uint8_t *have, const uint8_t *want, unsigned int len, enum write_granularity gran, const uint8_t erased_value);
+erasefunc_t *lookup_erase_func_ptr(const struct block_eraser *const eraser);
+int check_erased_range(struct flashctx *flash, unsigned int start, unsigned int len);
+unsigned int get_next_write(const uint8_t *have, const uint8_t *want, unsigned int len, unsigned int *first_start, enum write_granularity gran);
+int write_flash(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
/* Something happened that shouldn't happen, but we can go on. */
-#define ERROR_NONFATAL 0x100
+#define ERROR_FLASHROM_NONFATAL 0x100
/* Something happened that shouldn't happen, we'll abort. */
-#define ERROR_FATAL -0xee
+#define ERROR_FLASHROM_FATAL -0xee
#define ERROR_FLASHROM_BUG -200
/* We reached one of the hardcoded limits of flashrom. This can be fixed by
* increasing the limit of a compile-time allocation or by switching to dynamic
@@ -381,12 +652,11 @@ void print_chip_support_status(const struct flashchip *chip);
/* cli_output.c */
extern enum flashrom_log_level verbose_screen;
extern enum flashrom_log_level verbose_logfile;
-#ifndef STANDALONE
int open_logfile(const char * const filename);
int close_logfile(void);
void start_logging(void);
-#endif
int flashrom_print_cb(enum flashrom_log_level level, const char *fmt, va_list ap);
+void flashrom_progress_cb(struct flashrom_flashctx *flashctx);
/* Let gcc and clang check for correct printf-style format strings. */
int print(enum flashrom_log_level level, const char *fmt, ...)
#ifdef __MINGW32__
@@ -415,12 +685,7 @@ __attribute__((format(printf, 2, 3)));
#define msg_gspew(...) print(FLASHROM_MSG_SPEW, __VA_ARGS__) /* general debug spew */
#define msg_pspew(...) print(FLASHROM_MSG_SPEW, __VA_ARGS__) /* programmer debug spew */
#define msg_cspew(...) print(FLASHROM_MSG_SPEW, __VA_ARGS__) /* chip debug spew */
-
-/* layout.c */
-int register_include_arg(struct layout_include_args **args, char *name);
-int read_romlayout(const char *name);
-int normalize_romentries(const struct flashctx *flash);
-void layout_cleanup(struct layout_include_args **args);
+void update_progress(struct flashctx *flash, enum flashrom_progress_stage stage, size_t current, size_t total);
/* spi.c */
struct spi_command {
diff --git a/flashchips.h b/include/flashchips.h
index a85fa6a6b..962e65e4d 100644
--- a/flashchips.h
+++ b/include/flashchips.h
@@ -127,6 +127,7 @@
#define AMIC_A49LF040A 0x9d
#define ATMEL_ID 0x1F /* Atmel (now used by Adesto) */
+#define ATMEL_AT25DF011 0x4200
#define ATMEL_AT25DF021 0x4300
#define ATMEL_AT25DF021A 0x4301
#define ATMEL_AT25DF041A 0x4401
@@ -152,6 +153,7 @@
#define ATMEL_AT25SF161 0x8601
#define ATMEL_AT25SF321 0x8701
#define ATMEL_AT25SL128A 0x4218
+#define ATMEL_AT25SF128A 0x8901 /* Adesto AT25SF128A */
#define ATMEL_AT26DF041 0x4400
#define ATMEL_AT26DF081 0x4500 /* guessed, no datasheet available */
#define ATMEL_AT26DF081A 0x4501
@@ -207,9 +209,11 @@
#define ATMEL_AT49F080 0x23
#define ATMEL_AT49F080T 0x27
-/* Boya Microelectronics Inc.*/
-#define BOYA_ID 0x68
-#define BOYA_BY25Q128AS 0x4018
+/* Boya/BoHong Microelectronics Inc. */
+#define BOYA_BOHONG_ID 0x68
+#define BOYA_BOHONG_B__25D80A 0x4014
+#define BOYA_BOHONG_B_25D16A 0x4015
+#define BOYA_BOHONG_B_25Q128AS 0x4018
/* Bright Microelectronics has the same manufacturer ID as Hyundai... */
#define BRIGHT_ID 0xAD /* Bright Microelectronics */
@@ -470,13 +474,20 @@
#define ISSI_ID 0xD5 /* ISSI Integrated Silicon Solutions, see also PMC. */
#define ISSI_ID_SPI 0x9D /* ISSI ID used for SPI flash, see also PMC_ID_NOPREFIX */
+#define ISSI_IS25LP016 0x6015
#define ISSI_IS25LP064 0x6017
#define ISSI_IS25LP128 0x6018
#define ISSI_IS25LP256 0x6019
+#define ISSI_IS25LQ016 0x1445
+#define ISSI_IS25WP016 0x7015
+#define ISSI_IS25WP020 0x7012
#define ISSI_IS25WP032 0x7016
+#define ISSI_IS25WP040 0x7013
#define ISSI_IS25WP064 0x7017
+#define ISSI_IS25WP080 0x7014
#define ISSI_IS25WP128 0x7018
#define ISSI_IS25WP256 0x7019
+#define ISSI_IS25WQ040 0x1253
#define ISSI_PMC_IS29GL032B 0xF9
#define ISSI_PMC_IS29GL032T 0xF6
#define ISSI_PMC_IS29GL064B 0x7E1000
@@ -501,23 +512,29 @@
#define MACRONIX_MX25L2005 0x2012 /* Same as MX25L2005C, MX25L2006E */
#define MACRONIX_MX25L4005 0x2013 /* Same as MX25L4005A, MX25L4005C, MX25L4006E */
#define MACRONIX_MX25L8005 0x2014 /* Same as MX25V8005, MX25L8006E, MX25L8008E, FIXME: MX25L8073E (4k 0x20) */
-#define MACRONIX_MX25L1605 0x2015 /* MX25L1605 (64k 0x20); MX25L1605A/MX25L1606E/MX25L1608E (4k 0x20, 64k 0x52); MX25L1605D/MX25L1608D/MX25L1673E (4k 0x20) */
-#define MACRONIX_MX25L3205 0x2016 /* MX25L3205, MX25L3205A (64k 0x20); MX25L3205D/MX25L3208D (4k 0x20); MX25L3206E/MX25L3208E (4k 0x20, 64k 0x52); MX25L3273E (4k 0x20, 32k 0x52) */
+#define MACRONIX_MX25L1605 0x2015 /* MX25L1605 (64k 0x20); MX25V16066 (4k 0x20, 32k 0x52, 64k 0xD8); MX25L1605A/MX25L1606E/MX25L1608E (4k 0x20, 64k 0x52); MX25L1605D/MX25L1608D/MX25L1673E (4k 0x20) */
+#define MACRONIX_MX25L3205 0x2016 /* MX25L3205, MX25L3205A (64k 0x20); MX25L3205D/MX25L3208D (4k 0x20); MX25L3206E/MX25L3208E (4k 0x20, 64k 0x52); MX25L3233F/MX25L3273E (4k 0x20, 32k 0x52) */
#define MACRONIX_MX25L6405 0x2017 /* MX25L6405, MX25L6405D (64k 0x20); MX25L6406E/MX25L6408E (4k 0x20); MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E (4k 0x20, 32k 0x52) */
-#define MACRONIX_MX25L12805D 0x2018 /* MX25L12805D (no 32k); MX25L12865E, MX25L12835F, MX25L12845E (32k 0x52) */
+#define MACRONIX_MX25L12805D 0x2018 /* MX25L12805D (no 32k); MX25L12865E, MX25L12835F, MX25L12845E, MX25L12873F, MX25L12833F (32k 0x52) */
#define MACRONIX_MX25L25635F 0x2019 /* Same as MX25L25639F, but the latter seems to not support REMS */
#define MACRONIX_MX25L1635D 0x2415
#define MACRONIX_MX25L1635E 0x2515 /* MX25L1635{E} */
#define MACRONIX_MX66L51235F 0x201a /* MX66L51235F, MX25L51245G */
+#define MACRONIX_MX66L1G45G 0x201b /* MX66L1G45G */
+#define MACRONIX_MX25V4035F 0x2313
+#define MACRONIX_MX25V8035F 0x2314
+#define MACRONIX_MX25V1635F 0x2315 /* MX25V1636E */
#define MACRONIX_MX25U8032E 0x2534
#define MACRONIX_MX25U1635E 0x2535
#define MACRONIX_MX25U3235E 0x2536 /* Same as MX25U6435F */
#define MACRONIX_MX25U6435E 0x2537 /* Same as MX25U6435F */
#define MACRONIX_MX25U12835E 0x2538 /* Same as MX25U12835F */
-#define MACRONIX_MX25U25635F 0x2539
+#define MACRONIX_MX25U25635F 0x2539 /* Same as MX25U25643G */
#define MACRONIX_MX25U51245G 0x253a
#define MACRONIX_MX25L3235D 0x5E16 /* MX25L3225D/MX25L3235D/MX25L3237D */
#define MACRONIX_MX25L6495F 0x9517
+#define MACRONIX_MX25L3255E 0x9e16
+#define MACRONIX_MX77L25650F 0x7519
#define MACRONIX_MX25R3235F 0x2816
#define MACRONIX_MX25R6435F 0x2817
@@ -665,6 +682,8 @@
#define SPANSION_S25FL116K 0x4015
#define SPANSION_S25FL132K 0x4016
#define SPANSION_S25FL164K 0x4017
+#define SPANSION_S25FL128L 0x6018
+#define SPANSION_S25FL256L 0x6019
#define SPANSION_S25FS128S_L 0x20180081 /* Large sectors. */
#define SPANSION_S25FS128S_S 0x20180181 /* Small sectors. */
#define SPANSION_S25FS256S_L 0x02190081 /* Large sectors. */
@@ -809,10 +828,11 @@
#define ST_M45PE10 0x4011
#define ST_M45PE20 0x4012
#define ST_M45PE40 0x4013
-#define ST_M45PE80 0x4014
+#define ST_M45PE80 0x4014 /* Same as XM25QH80B */
#define ST_M45PE16 0x4015
#define XMC_XM25QH64C 0x4017
#define XMC_XM25QU64C 0x4117
+#define XMC_XM25QH128A 0x7018
#define XMC_XM25QH128C 0x4018
#define XMC_XM25QU128C 0x4118
#define XMC_XM25QH256C 0x4019
@@ -973,11 +993,14 @@
#define WINBOND_NEX_W25Q64_W 0x6017 /* W25Q64DW; W25Q64FV in QPI mode */
#define WINBOND_NEX_W25Q128_W 0x6018 /* W25Q128FW; W25Q128FV in QPI mode */
#define WINBOND_NEX_W25Q256_W 0x6019 /* W25Q256JW */
+#define WINBOND_NEX_W25Q64JV 0x7017 /* W25Q64JV */
#define WINBOND_NEX_W25Q128_V_M 0x7018 /* W25Q128JVSM */
#define WINBOND_NEX_W25Q256JV_M 0x7019 /* W25Q256JV_M (QE=0) */
-#define WINBOND_NEX_W25Q64JW 0x8017
+#define WINBOND_NEX_W25Q32JW_M 0x8016 /* W25Q32JW...M */
+#define WINBOND_NEX_W25Q64JW_M 0x8017 /* W25Q64JW...M */
#define WINBOND_NEX_W25Q128_DTR 0x8018 /* W25Q128JW_DTR */
#define WINBOND_NEX_W25Q256_DTR 0x8019 /* W25Q256JW_DTR aka W25Q256256JW-IM */
+#define WINBOND_NEX_W25Q512NW_IM 0x8020 /* W25Q512NW-IM */
#define WINBOND_ID 0xDA /* Winbond */
#define WINBOND_W19B160BB 0x49
@@ -1021,6 +1044,10 @@
#define WINBOND_W49V002A 0xB0
#define WINBOND_W49V002FA 0x32
+#define XTX_ID 0x0B /* XTX Technology Limited */
+#define XTX_XT25F02E 0x4012
+#define XTX_XT25F64B 0x4017
+
#define ZETTADEVICE_ID 0xBA /* Zetta Device */
#define ZETTADEVICE_ZD25D20 0x2012
#define ZETTADEVICE_ZD25D40 0x2013
diff --git a/fmap.h b/include/fmap.h
index 924e11f6b..924e11f6b 100644
--- a/fmap.h
+++ b/include/fmap.h
diff --git a/include/hwaccess_physmap.h b/include/hwaccess_physmap.h
new file mode 100644
index 000000000..a0a7e74d8
--- /dev/null
+++ b/include/hwaccess_physmap.h
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 __HWACCESS_PHYSMAP_H__
+#define __HWACCESS_PHYSMAP_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+void *physmap(const char *descr, uintptr_t phys_addr, size_t len);
+void *rphysmap(const char *descr, uintptr_t phys_addr, size_t len);
+void *physmap_ro(const char *descr, uintptr_t phys_addr, size_t len);
+void *physmap_ro_unaligned(const char *descr, uintptr_t phys_addr, size_t len);
+void physunmap(void *virt_addr, size_t len);
+void physunmap_unaligned(void *virt_addr, size_t len);
+
+void mmio_writeb(uint8_t val, void *addr);
+void mmio_writew(uint16_t val, void *addr);
+void mmio_writel(uint32_t val, void *addr);
+uint8_t mmio_readb(const void *addr);
+uint16_t mmio_readw(const void *addr);
+uint32_t mmio_readl(const void *addr);
+void mmio_readn(const void *addr, uint8_t *buf, size_t len);
+void mmio_le_writeb(uint8_t val, void *addr);
+void mmio_le_writew(uint16_t val, void *addr);
+void mmio_le_writel(uint32_t val, void *addr);
+uint8_t mmio_le_readb(const void *addr);
+uint16_t mmio_le_readw(const void *addr);
+uint32_t mmio_le_readl(const void *addr);
+#define pci_mmio_writeb mmio_le_writeb
+#define pci_mmio_writew mmio_le_writew
+#define pci_mmio_writel mmio_le_writel
+#define pci_mmio_readb mmio_le_readb
+#define pci_mmio_readw mmio_le_readw
+#define pci_mmio_readl mmio_le_readl
+void rmmio_writeb(uint8_t val, void *addr);
+void rmmio_writew(uint16_t val, void *addr);
+void rmmio_writel(uint32_t val, void *addr);
+void rmmio_le_writeb(uint8_t val, void *addr);
+void rmmio_le_writew(uint16_t val, void *addr);
+void rmmio_le_writel(uint32_t val, void *addr);
+#define pci_rmmio_writeb rmmio_le_writeb
+#define pci_rmmio_writew rmmio_le_writew
+#define pci_rmmio_writel rmmio_le_writel
+void rmmio_valb(void *addr);
+void rmmio_valw(void *addr);
+void rmmio_vall(void *addr);
+
+#endif /* __HWACCESS_PHYSMAP_H__ */ \ No newline at end of file
diff --git a/include/hwaccess_x86_io.h b/include/hwaccess_x86_io.h
new file mode 100644
index 000000000..31d1e86c8
--- /dev/null
+++ b/include/hwaccess_x86_io.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2022 secunet Security Networks AG
+ * (Written by Thomas Heijligen <thomas.heijligen@secunet.com)
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+/*
+ * This file contains prototypes for x86 I/O Port access.
+ */
+
+#ifndef __HWACCESS_X86_IO_H__
+#define __HWACCESS_X86_IO_H__ 1
+
+#include <stdint.h>
+/**
+ */
+int rget_io_perms(void);
+
+void OUTB(uint8_t value, uint16_t port);
+void OUTW(uint16_t value, uint16_t port);
+void OUTL(uint32_t value, uint16_t port);
+uint8_t INB(uint16_t port);
+uint16_t INW(uint16_t port);
+uint32_t INL(uint16_t port);
+
+#endif /* __HWACCESS_X86_IO_H__ */
diff --git a/include/hwaccess_x86_msr.h b/include/hwaccess_x86_msr.h
new file mode 100644
index 000000000..eda007e80
--- /dev/null
+++ b/include/hwaccess_x86_msr.h
@@ -0,0 +1,28 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 __HWACCESS_X86_MSR_H__
+#define __HWACCESS_X86_MSR_H__ 1
+
+#include <stdint.h>
+
+typedef struct { uint32_t hi, lo; } msr_t;
+
+msr_t msr_read(int addr);
+int msr_write(int addr, msr_t msr);
+int msr_setup(int cpu);
+void msr_cleanup(void);
+
+#endif /* __HWACCESS_X86_MSR_H__ */ \ No newline at end of file
diff --git a/i2c_helper.h b/include/i2c_helper.h
index 599e08bbd..b840b3a9d 100644
--- a/i2c_helper.h
+++ b/include/i2c_helper.h
@@ -19,8 +19,10 @@
#include <inttypes.h>
+struct programmer_cfg; /* defined in programmer.h */
+
/**
- * An convinent structure that contains the buffer size and the buffer
+ * An convenient structure that contains the buffer size and the buffer
* pointer. Used to wrap buffer details while doing the I2C data
* transfer on both input and output. It is the client's responsibility
* to use i2c_buffer_t_fill to initialize this struct instead of
@@ -72,6 +74,23 @@ static inline int i2c_buffer_t_fill(i2c_buffer_t *i2c_buf, void *buf, uint16_t l
int i2c_open(int bus, uint16_t addr, int force);
/**
+ * i2c_open_path: open an I2C device by device path
+ *
+ * This function behaves the same as i2c_open, but takes a filesystem
+ * path (assumed to be an I2C device file) instead of a bus number.
+ */
+int i2c_open_path(const char *path, uint16_t addr, int force);
+
+/**
+ * i2c_open_from_programmer_params: open an I2C device from programmer params
+ *
+ * This function is a wrapper for i2c_open and i2c_open_path that obtains the
+ * I2C device to use from programmer parameters. It is meant to be called
+ * from I2C-based programmers to avoid repeating parameter parsing code.
+ */
+int i2c_open_from_programmer_params(const struct programmer_cfg *cfg, uint16_t addr, int force);
+
+/**
* i2c_close - closes the file descriptor returned by i2c_open
*
* @fd: file descriptor to be closed.
@@ -101,7 +120,7 @@ int i2c_read(int fd, uint16_t addr, i2c_buffer_t *buf_read);
*
* @fd: file descriptor of the target device.
* @addr: I2C slave address of the target device.
- * @buf_write: data struct includes writting buffer and size.
+ * @buf_write: data struct includes writing buffer and size.
*
* This function does accept empty write and do nothing on such case.
*
diff --git a/ich_descriptors.h b/include/ich_descriptors.h
index c6bf5d802..5a6cdf10c 100644
--- a/ich_descriptors.h
+++ b/include/ich_descriptors.h
@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <stdint.h>
+#include <stdbool.h>
#include "programmer.h" /* for enum ich_chipset */
/* FIXME: Replace with generic return codes */
@@ -95,6 +96,13 @@ struct ich_desc_content {
ICCRIBA :8, /* ICC Reg. Init Base Addr. (new since Sandy Bridge) */
RIL :8; /* Register Init Length (new since Hawell) */
};
+ struct { /* new since Tiger Point */
+ uint32_t :2,
+ CSSO :10, /* CPU Soft Strap Offset from PMC Base */
+ :4,
+ CSSL :8, /* CPU Soft Strap Length */
+ :8;
+ };
};
};
@@ -257,7 +265,7 @@ struct ich_desc_north_strap {
struct ich_desc_south_strap {
union {
- uint32_t STRPs[18]; /* current maximum: cougar point */
+ uint32_t STRPs[23]; /* current maximum: gemini lake */
struct { /* ich8 */
struct { /* STRP1 */
uint32_t ME_DISABLE :1,
@@ -521,7 +529,8 @@ struct ich_desc_upper_map {
struct {
uint32_t VTBA :8, /* ME VSCC Table Base Address */
VTL :8, /* ME VSCC Table Length */
- :16;
+ :8,
+ MDTBA :8; /* MIP Descr. Table Base Addr. (new since Cannon Point/300) */
};
};
struct {
@@ -564,11 +573,6 @@ struct ich_descriptors {
struct ich_desc_upper_map upper;
};
-struct ich_layout {
- struct flashrom_layout base;
- struct romentry entries[MAX_NUM_FLREGS];
-};
-
ssize_t ich_number_of_regions(enum ich_chipset cs, const struct ich_desc_content *content);
ssize_t ich_number_of_masters(enum ich_chipset cs, const struct ich_desc_content *content);
@@ -587,6 +591,6 @@ int read_ich_descriptors_from_dump(const uint32_t *dump, size_t len, enum ich_ch
int read_ich_descriptors_via_fdo(enum ich_chipset cs, void *spibar, struct ich_descriptors *desc);
int getFCBA_component_density(enum ich_chipset cs, const struct ich_descriptors *desc, uint8_t idx);
-int layout_from_ich_descriptors(struct ich_layout *, const void *dump, size_t len);
+int layout_from_ich_descriptors(struct flashrom_layout **, const void *dump, size_t len);
#endif /* __ICH_DESCRIPTORS_H__ */
diff --git a/layout.h b/include/layout.h
index cceedd1fe..5614beaf8 100644
--- a/layout.h
+++ b/include/layout.h
@@ -35,36 +35,44 @@ typedef uint32_t chipsize_t; /* Able to store the number of bytes of any support
#define MAX_ROMLAYOUT 128
-struct romentry {
+struct flash_region {
+ char *name;
chipoff_t start;
chipoff_t end;
- bool included;
- char *name;
+ bool read_prot;
+ bool write_prot;
};
-struct flashrom_layout {
- /* entries store the entries specified in a layout file and associated run-time data */
- struct romentry *entries;
- /* the number of successfully parsed entries */
- size_t num_entries;
-};
+struct romentry {
+ struct romentry *next;
-struct single_layout {
- struct flashrom_layout base;
- struct romentry entry;
-};
+ bool included;
+ char *file;
-struct layout_include_args {
- char *name;
- struct layout_include_args *next;
+ struct flash_region region;
};
-struct flashrom_layout *get_global_layout(void);
+struct flashrom_layout;
+
+struct layout_include_args;
+
struct flashrom_flashctx;
-const struct flashrom_layout *get_layout(const struct flashrom_flashctx *const flashctx);
+const struct flashrom_layout *get_default_layout(const struct flashrom_flashctx *);
+const struct flashrom_layout *get_layout(const struct flashrom_flashctx *);
+
+int layout_from_file(struct flashrom_layout **, const char *name);
+
+int register_include_arg(struct layout_include_args **, const char *arg);
+int process_include_args(struct flashrom_layout *, const struct layout_include_args *);
+void cleanup_include_args(struct layout_include_args **);
-int process_include_args(struct flashrom_layout *l, const struct layout_include_args *const args);
const struct romentry *layout_next_included_region(const struct flashrom_layout *, chipoff_t);
const struct romentry *layout_next_included(const struct flashrom_layout *, const struct romentry *);
+const struct romentry *layout_next(const struct flashrom_layout *, const struct romentry *);
+int included_regions_overlap(const struct flashrom_layout *);
+void prepare_layout_for_extraction(struct flashrom_flashctx *);
+int layout_sanity_checks(const struct flashrom_flashctx *);
+int check_for_unwritable_regions(const struct flashrom_flashctx *flash, unsigned int start, unsigned int len);
+void get_flash_region(const struct flashrom_flashctx *flash, int addr, struct flash_region *region);
#endif /* !__LAYOUT_H__ */
diff --git a/include/libflashrom.h b/include/libflashrom.h
new file mode 100644
index 000000000..e87776be1
--- /dev/null
+++ b/include/libflashrom.h
@@ -0,0 +1,598 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2010 Google Inc.
+ * Copyright (C) 2012 secunet Security Networks AG
+ * (Written by Nico Huber <nico.huber@secunet.com> for secunet)
+ *
+ * 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 __LIBFLASHROM_H__
+#define __LIBFLASHROM_H__ 1
+
+/**
+ * @mainpage
+ *
+ * Have a look at the Modules section for a function reference.
+ */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdarg.h>
+
+/**
+ * @defgroup flashrom-general General
+ * @{
+ */
+
+/**
+ * @brief Initialize libflashrom.
+ *
+ * @param perform_selfcheck If not zero, perform a self check.
+ * @return 0 on success
+ */
+int flashrom_init(int perform_selfcheck);
+/**
+ * @brief Shut down libflashrom.
+ * @return 0 on success
+ */
+int flashrom_shutdown(void);
+enum flashrom_log_level {
+ FLASHROM_MSG_ERROR = 0,
+ FLASHROM_MSG_WARN = 1,
+ FLASHROM_MSG_INFO = 2,
+ FLASHROM_MSG_DEBUG = 3,
+ FLASHROM_MSG_DEBUG2 = 4,
+ FLASHROM_MSG_SPEW = 5,
+};
+typedef int(flashrom_log_callback)(enum flashrom_log_level, const char *format, va_list);
+/**
+ * @brief Set the log callback function.
+ *
+ * Set a callback function which will be invoked whenever libflashrom wants
+ * to output messages. This allows frontends to do whatever they see fit with
+ * such messages, e.g. write them to syslog, or to a file, or print them in a
+ * GUI window, etc.
+ *
+ * @param log_callback Pointer to the new log callback function.
+ */
+void flashrom_set_log_callback(flashrom_log_callback *log_callback);
+
+enum flashrom_progress_stage {
+ FLASHROM_PROGRESS_READ,
+ FLASHROM_PROGRESS_WRITE,
+ FLASHROM_PROGRESS_ERASE,
+ FLASHROM_PROGRESS_NR,
+};
+struct flashrom_progress {
+ enum flashrom_progress_stage stage;
+ size_t current;
+ size_t total;
+ void *user_data;
+};
+struct flashrom_flashctx;
+typedef void(flashrom_progress_callback)(struct flashrom_flashctx *flashctx);
+/**
+ * @brief Set the progress callback function.
+ *
+ * Set a callback function which will be invoked whenever libflashrom wants
+ * to indicate the progress has changed. This allows frontends to do whatever
+ * they see fit with such values, e.g. update a progress bar in a GUI tool.
+ *
+ * @param progress_callback Pointer to the new progress callback function.
+ * @param progress_state Pointer to progress state to include with the progress
+ * callback.
+ */
+void flashrom_set_progress_callback(struct flashrom_flashctx *const flashctx,
+ flashrom_progress_callback *progress_callback, struct flashrom_progress *progress_state);
+
+/** @} */ /* end flashrom-general */
+
+/**
+ * @defgroup flashrom-query Querying
+ * @{
+ */
+
+enum flashrom_test_state {
+ FLASHROM_TESTED_OK = 0,
+ FLASHROM_TESTED_NT = 1,
+ FLASHROM_TESTED_BAD = 2,
+ FLASHROM_TESTED_DEP = 3,
+ FLASHROM_TESTED_NA = 4,
+};
+
+struct flashrom_flashchip_info {
+ const char *vendor;
+ const char *name;
+ unsigned int total_size;
+ struct flashrom_tested {
+ enum flashrom_test_state probe;
+ enum flashrom_test_state read;
+ enum flashrom_test_state erase;
+ enum flashrom_test_state write;
+ enum flashrom_test_state wp;
+ } tested;
+};
+
+struct flashrom_board_info {
+ const char *vendor;
+ const char *name;
+ enum flashrom_test_state working;
+};
+
+struct flashrom_chipset_info {
+ const char *vendor;
+ const char *chipset;
+ uint16_t vendor_id;
+ uint16_t chipset_id;
+ enum flashrom_test_state status;
+};
+
+/**
+ * @brief Returns flashrom version
+ * @return flashrom version
+ */
+const char *flashrom_version_info(void);
+/**
+ * @brief Returns list of supported flash chips
+ * @return List of supported flash chips, or NULL if an error occurred
+ */
+struct flashrom_flashchip_info *flashrom_supported_flash_chips(void);
+/**
+ * @brief Returns list of supported mainboards
+ * @return List of supported mainboards, or NULL if an error occurred
+ */
+struct flashrom_board_info *flashrom_supported_boards(void);
+/**
+ * @brief Returns list of supported chipsets
+ * @return List of supported chipsets, or NULL if an error occurred
+ */
+struct flashrom_chipset_info *flashrom_supported_chipsets(void);
+/**
+ * @brief Frees memory allocated by libflashrom API
+ * @param p Pointer to block of memory which should be freed
+ * @return 0 on success
+ */
+int flashrom_data_free(void *const p);
+
+/** @} */ /* end flashrom-query */
+
+/**
+ * @defgroup flashrom-prog Programmers
+ * @{
+ */
+struct flashrom_programmer;
+
+/**
+ * @brief Initialize the specified programmer.
+ *
+ * Currently, only one programmer may be initialized at a time.
+ *
+ * @param[out] flashprog Points to a pointer of type struct flashrom_programmer
+ * that will be set if programmer initialization succeeds.
+ * *flashprog has to be shutdown by the caller with @ref
+ * flashrom_programmer_shutdown.
+ * @param[in] prog_name Name of the programmer to initialize.
+ * @param[in] prog_params Pointer to programmer specific parameters.
+ * @return 0 on success
+ */
+int flashrom_programmer_init(struct flashrom_programmer **flashprog, const char *prog_name, const char *prog_params);
+/**
+ * @brief Shut down the initialized programmer.
+ *
+ * @param flashprog The programmer to shut down.
+ * @return 0 on success
+ */
+int flashrom_programmer_shutdown(struct flashrom_programmer *flashprog);
+
+/** @} */ /* end flashrom-prog */
+
+/**
+ * @defgroup flashrom-flash Flash chips
+ * @{
+ */
+
+/**
+ * @brief Probe for a flash chip.
+ *
+ * Probes for a flash chip and returns a flash context, that can be used
+ * later with flash chip and @ref flashrom-ops "image operations", if
+ * exactly one matching chip is found.
+ *
+ * @param[out] flashctx Points to a pointer of type struct flashrom_flashctx
+ * that will be set if exactly one chip is found. *flashctx
+ * has to be freed by the caller with @ref flashrom_flash_release.
+ * @param[in] flashprog The flash programmer used to access the chip.
+ * @param[in] chip_name Name of a chip to probe for, or NULL to probe for
+ * all known chips.
+ * @return 0 on success,
+ * 3 if multiple chips were found,
+ * 2 if no chip was found,
+ * or 1 on any other error.
+ */
+int flashrom_flash_probe(struct flashrom_flashctx **flashctx, const struct flashrom_programmer *flashprog, const char *chip_name);
+/**
+ * @brief Returns the size of the specified flash chip in bytes.
+ *
+ * @param flashctx The queried flash context.
+ * @return Size of flash chip in bytes.
+ */
+size_t flashrom_flash_getsize(const struct flashrom_flashctx *flashctx);
+/**
+ * @brief Erase the specified ROM chip.
+ *
+ * If a layout is set in the given flash context, only included regions
+ * will be erased.
+ *
+ * @param flashctx The context of the flash chip to erase.
+ * @return 0 on success.
+ */
+int flashrom_flash_erase(struct flashrom_flashctx *flashctx);
+/**
+ * @brief Free a flash context.
+ *
+ * @param flashctx Flash context to free.
+ */
+void flashrom_flash_release(struct flashrom_flashctx *flashctx);
+
+enum flashrom_flag {
+ FLASHROM_FLAG_FORCE,
+ FLASHROM_FLAG_FORCE_BOARDMISMATCH,
+ FLASHROM_FLAG_VERIFY_AFTER_WRITE,
+ FLASHROM_FLAG_VERIFY_WHOLE_CHIP,
+ FLASHROM_FLAG_SKIP_UNREADABLE_REGIONS,
+ FLASHROM_FLAG_SKIP_UNWRITABLE_REGIONS,
+};
+
+/**
+ * @brief Set a flag in the given flash context.
+ *
+ * @param flashctx Flash context to alter.
+ * @param flag Flag that is to be set / cleared.
+ * @param value Value to set.
+ */
+void flashrom_flag_set(struct flashrom_flashctx *flashctx, enum flashrom_flag flag, bool value);
+/**
+ * @brief Return the current value of a flag in the given flash context.
+ *
+ * @param flashctx Flash context to read from.
+ * @param flag Flag to be read.
+ * @return Current value of the flag.
+ */
+bool flashrom_flag_get(const struct flashrom_flashctx *flashctx, enum flashrom_flag flag);
+
+/** @} */ /* end flashrom-flash */
+
+/**
+ * @defgroup flashrom-ops Operations
+ * @{
+ */
+
+/**
+ * @brief Read the current image from the specified ROM chip.
+ *
+ * If a layout is set in the specified flash context, only included regions
+ * will be read.
+ *
+ * @param flashctx The context of the flash chip.
+ * @param buffer Target buffer to write image to.
+ * @param buffer_len Size of target buffer in bytes.
+ * @return 0 on success,
+ * 2 if buffer_len is too small for the flash chip's contents,
+ * or 1 on any other failure.
+ */
+int flashrom_image_read(struct flashrom_flashctx *flashctx, void *buffer, size_t buffer_len);
+/**
+ * @brief Write the specified image to the ROM chip.
+ *
+ * If a layout is set in the specified flash context, only erase blocks
+ * containing included regions will be touched.
+ *
+ * @param flashctx The context of the flash chip.
+ * @param buffer Source buffer to read image from (may be altered for full verification).
+ * @param buffer_len Size of source buffer in bytes.
+ * @param refbuffer If given, assume flash chip contains same data as `refbuffer`.
+ * @return 0 on success,
+ * 4 if buffer_len doesn't match the size of the flash chip,
+ * 3 if write was tried but nothing has changed,
+ * 2 if write failed and flash contents changed,
+ * or 1 on any other failure.
+ */
+int flashrom_image_write(struct flashrom_flashctx *flashctx, void *buffer, size_t buffer_len, const void *refbuffer);
+/**
+ * @brief Verify the ROM chip's contents with the specified image.
+ *
+ * If a layout is set in the specified flash context, only included regions
+ * will be verified.
+ *
+ * @param flashctx The context of the flash chip.
+ * @param buffer Source buffer to verify with.
+ * @param buffer_len Size of source buffer in bytes.
+ * @return 0 on success,
+ * 3 if the chip's contents don't match,
+ * 2 if buffer_len doesn't match the size of the flash chip,
+ * or 1 on any other failure.
+ */
+int flashrom_image_verify(struct flashrom_flashctx *flashctx, const void *buffer, size_t buffer_len);
+
+/** @} */ /* end flashrom-ops */
+
+/**
+ * @defgroup flashrom-layout Layout handling
+ * @{
+ */
+
+struct flashrom_layout;
+/**
+ * @brief Create a new, empty layout.
+ *
+ * @param layout Pointer to returned layout reference.
+ *
+ * @return 0 on success,
+ * 1 if out of memory.
+ */
+int flashrom_layout_new(struct flashrom_layout **layout);
+
+/**
+ * @brief Read a layout from the Intel ICH descriptor in the flash.
+ *
+ * Optionally verify that the layout matches the one in the given
+ * descriptor dump.
+ *
+ * @param[out] layout Points to a struct flashrom_layout pointer that
+ * gets set if the descriptor is read and parsed
+ * successfully.
+ * @param[in] flashctx Flash context to read the descriptor from flash.
+ * @param[in] dump The descriptor dump to compare to or NULL.
+ * @param[in] len The length of the descriptor dump.
+ *
+ * @return 0 on success,
+ * 6 if descriptor parsing isn't implemented for the host,
+ * 5 if the descriptors don't match,
+ * 4 if the descriptor dump couldn't be parsed,
+ * 3 if the descriptor on flash couldn't be parsed,
+ * 2 if the descriptor on flash couldn't be read,
+ * 1 on any other error.
+ */
+int flashrom_layout_read_from_ifd(struct flashrom_layout **layout, struct flashrom_flashctx *flashctx, const void *dump, size_t len);
+/**
+ * @brief Read a layout by searching the flash chip for fmap.
+ *
+ * @param[out] layout Points to a struct flashrom_layout pointer that
+ * gets set if the fmap is read and parsed successfully.
+ * @param[in] flashctx Flash context
+ * @param[in] offset Offset to begin searching for fmap.
+ * @param[in] length Length of address space to search.
+ *
+ * @return 0 on success,
+ * 3 if fmap parsing isn't implemented for the host,
+ * 2 if the fmap couldn't be read,
+ * 1 on any other error.
+ */
+int flashrom_layout_read_fmap_from_rom(struct flashrom_layout **layout,
+ struct flashrom_flashctx *flashctx, size_t offset, size_t length);
+/**
+ * @brief Read a layout by searching a buffer for fmap.
+ *
+ * @param[out] layout Points to a struct flashrom_layout pointer that
+ * gets set if the fmap is read and parsed successfully.
+ * @param[in] flashctx Flash context
+ * @param[in] buffer Buffer to search in
+ * @param[in] len Size of buffer to search
+ *
+ * @return 0 on success,
+ * 3 if fmap parsing isn't implemented for the host,
+ * 2 if the fmap couldn't be read,
+ * 1 on any other error.
+ */
+int flashrom_layout_read_fmap_from_buffer(struct flashrom_layout **layout,
+ struct flashrom_flashctx *flashctx, const uint8_t *buffer, size_t len);
+/**
+ * @brief Add a region to an existing layout.
+ *
+ * @param layout The existing layout.
+ * @param start Start address of the region.
+ * @param end End address (inclusive) of the region.
+ * @param name Name of the region.
+ *
+ * @return 0 on success,
+ * 1 if out of memory.
+ */
+int flashrom_layout_add_region(struct flashrom_layout *layout, size_t start, size_t end, const char *name);
+/**
+ * @brief Mark given region as included.
+ *
+ * @param layout The layout to alter.
+ * @param name The name of the region to include.
+ *
+ * @return 0 on success,
+ * 1 if the given name can't be found.
+ */
+int flashrom_layout_include_region(struct flashrom_layout *layout, const char *name);
+/**
+ * @brief Mark given region as not included.
+ *
+ * @param layout The layout to alter.
+ * @param name The name of the region to exclude.
+ *
+ * @return 0 on success,
+ * 1 if the given name can't be found.
+ */
+int flashrom_layout_exclude_region(struct flashrom_layout *layout, const char *name);
+/**
+ * @brief Get given region's offset and length.
+ *
+ * @param[in] layout The existing layout.
+ * @param[in] name The name of the region.
+ * @param[out] start The start address to be written.
+ * @param[out] len The length of the region to be written.
+ *
+ * @return 0 on success,
+ * 1 if the given name can't be found.
+ */
+int flashrom_layout_get_region_range(struct flashrom_layout *layout, const char *name,
+ unsigned int *start, unsigned int *len);
+/**
+ * @brief Free a layout.
+ *
+ * @param layout Layout to free.
+ */
+void flashrom_layout_release(struct flashrom_layout *layout);
+/**
+ * @brief Set the active layout for a flash context.
+ *
+ * Note: The caller must not release the layout as long as it is used through
+ * the given flash context.
+ *
+ * @param flashctx Flash context whose layout will be set.
+ * @param layout Layout to bet set.
+ */
+void flashrom_layout_set(struct flashrom_flashctx *flashctx, const struct flashrom_layout *layout);
+
+/** @} */ /* end flashrom-layout */
+
+/**
+ * @defgroup flashrom-wp Write Protect
+ * @{
+ */
+
+enum flashrom_wp_result {
+ FLASHROM_WP_OK = 0,
+ FLASHROM_WP_ERR_CHIP_UNSUPPORTED = 1,
+ FLASHROM_WP_ERR_OTHER = 2,
+ FLASHROM_WP_ERR_READ_FAILED = 3,
+ FLASHROM_WP_ERR_WRITE_FAILED = 4,
+ FLASHROM_WP_ERR_VERIFY_FAILED = 5,
+ FLASHROM_WP_ERR_RANGE_UNSUPPORTED = 6,
+ FLASHROM_WP_ERR_MODE_UNSUPPORTED = 7,
+ FLASHROM_WP_ERR_RANGE_LIST_UNAVAILABLE = 8,
+ FLASHROM_WP_ERR_UNSUPPORTED_STATE = 9
+};
+
+enum flashrom_wp_mode {
+ FLASHROM_WP_MODE_DISABLED,
+ FLASHROM_WP_MODE_HARDWARE,
+ FLASHROM_WP_MODE_POWER_CYCLE,
+ FLASHROM_WP_MODE_PERMANENT
+};
+struct flashrom_wp_cfg;
+struct flashrom_wp_ranges;
+/**
+ * @brief Create a new empty WP configuration.
+ *
+ * @param[out] cfg Points to a pointer of type struct flashrom_wp_cfg that will
+ * be set if creation succeeds. *cfg has to be freed by the
+ * caller with @ref flashrom_wp_cfg_release.
+ * @return 0 on success
+ * >0 on failure
+ */
+enum flashrom_wp_result flashrom_wp_cfg_new(struct flashrom_wp_cfg **cfg);
+/**
+ * @brief Free a WP configuration.
+ *
+ * @param[in] cfg Pointer to the flashrom_wp_cfg to free.
+ */
+void flashrom_wp_cfg_release(struct flashrom_wp_cfg *cfg);
+/**
+ * @brief Set the protection mode for a WP configuration.
+ *
+ * @param[in] mode The protection mode to set.
+ * @param[out] cfg Pointer to the flashrom_wp_cfg structure to modify.
+ */
+void flashrom_wp_set_mode(struct flashrom_wp_cfg *cfg, enum flashrom_wp_mode mode);
+/**
+ * @brief Get the protection mode from a WP configuration.
+ *
+ * @param[in] cfg The WP configuration to get the protection mode from.
+ * @return The configuration's protection mode.
+ */
+enum flashrom_wp_mode flashrom_wp_get_mode(const struct flashrom_wp_cfg *cfg);
+/**
+ * @brief Set the protection range for a WP configuration.
+ *
+ * @param[out] cfg Pointer to the flashrom_wp_cfg structure to modify.
+ * @param[in] start The range's start address.
+ * @param[in] len The range's length.
+ */
+void flashrom_wp_set_range(struct flashrom_wp_cfg *cfg, size_t start, size_t len);
+/**
+ * @brief Get the protection range from a WP configuration.
+ *
+ * @param[out] start Points to a size_t to write the range start to.
+ * @param[out] len Points to a size_t to write the range length to.
+ * @param[in] cfg The WP configuration to get the range from.
+ */
+void flashrom_wp_get_range(size_t *start, size_t *len, const struct flashrom_wp_cfg *cfg);
+
+/**
+ * @brief Read the current WP configuration from a flash chip.
+ *
+ * @param[out] cfg Pointer to a struct flashrom_wp_cfg to store the chip's
+ * configuration in.
+ * @param[in] flash The flash context used to access the chip.
+ * @return 0 on success
+ * >0 on failure
+ */
+enum flashrom_wp_result flashrom_wp_read_cfg(struct flashrom_wp_cfg *cfg, struct flashrom_flashctx *flash);
+/**
+ * @brief Write a WP configuration to a flash chip.
+ *
+ * @param[in] flash The flash context used to access the chip.
+ * @param[in] cfg The WP configuration to write to the chip.
+ * @return 0 on success
+ * >0 on failure
+ */
+enum flashrom_wp_result flashrom_wp_write_cfg(struct flashrom_flashctx *flash, const struct flashrom_wp_cfg *cfg);
+
+/**
+ * @brief Get a list of protection ranges supported by the flash chip.
+ *
+ * @param[out] ranges Points to a pointer of type struct flashrom_wp_ranges
+ * that will be set if available ranges are found. Finding
+ * available ranges may not always be possible, even if the
+ * chip's protection range can be read or modified. *ranges
+ * must be freed using @ref flashrom_wp_ranges_release.
+ * @param[in] flash The flash context used to access the chip.
+ * @return 0 on success
+ * >0 on failure
+ */
+enum flashrom_wp_result flashrom_wp_get_available_ranges(struct flashrom_wp_ranges **ranges, struct flashrom_flashctx *flash);
+/**
+ * @brief Get a number of protection ranges in a range list.
+ *
+ * @param[in] ranges The range list to get the count from.
+ * @return Number of ranges in the list.
+ */
+size_t flashrom_wp_ranges_get_count(const struct flashrom_wp_ranges *ranges);
+/**
+ * @brief Get a protection range from a range list.
+ *
+ * @param[out] start Points to a size_t to write the range's start to.
+ * @param[out] len Points to a size_t to write the range's length to.
+ * @param[in] ranges The range list to get the range from.
+ * @param[in] index Index of the range to get.
+ * @return 0 on success
+ * >0 on failure
+ */
+enum flashrom_wp_result flashrom_wp_ranges_get_range(size_t *start, size_t *len, const struct flashrom_wp_ranges *ranges, unsigned int index);
+/**
+ * @brief Free a WP range list.
+ *
+ * @param[out] ranges Pointer to the flashrom_wp_ranges to free.
+ */
+void flashrom_wp_ranges_release(struct flashrom_wp_ranges *ranges);
+
+/** @} */ /* end flashrom-wp */
+
+#endif /* !__LIBFLASHROM_H__ */
diff --git a/include/platform.h b/include/platform.h
new file mode 100644
index 000000000..3cde2edae
--- /dev/null
+++ b/include/platform.h
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2022 secunet Security Networks AG
+ * (written by Thomas Heijligen <thomas.heijligen@secunet.com)
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+/*
+ * Header file for platform abstraction.
+ */
+
+#ifndef __PLATFORM_H__
+#define __PLATFORM_H__ 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* convert cpu native endian to little endian */
+uint8_t cpu_to_le8 (uint8_t value);
+uint16_t cpu_to_le16(uint16_t value);
+uint32_t cpu_to_le32(uint32_t value);
+uint64_t cpu_to_le64(uint64_t value);
+
+/* convert cpu native endian to big endian */
+uint8_t cpu_to_be8 (uint8_t value);
+uint16_t cpu_to_be16(uint16_t value);
+uint32_t cpu_to_be32(uint32_t value);
+uint64_t cpu_to_be64(uint64_t value);
+
+/* convert little endian to cpu native endian */
+uint8_t le_to_cpu8 (uint8_t value);
+uint16_t le_to_cpu16(uint16_t value);
+uint32_t le_to_cpu32(uint32_t value);
+uint64_t le_to_cpu64(uint64_t value);
+
+/* convert big endian to cpu native endian */
+uint8_t be_to_cpu8 (uint8_t value);
+uint16_t be_to_cpu16(uint16_t value);
+uint32_t be_to_cpu32(uint32_t value);
+uint64_t be_to_cpu64(uint64_t value);
+
+/* read value from base at offset in little endian */
+uint8_t read_le8 (const void *base, size_t offset);
+uint16_t read_le16(const void *base, size_t offset);
+uint32_t read_le32(const void *base, size_t offset);
+uint64_t read_le64(const void *base, size_t offset);
+
+/* read value from base at offset in big endian */
+uint8_t read_be8 (const void *base, size_t offset);
+uint16_t read_be16(const void *base, size_t offset);
+uint32_t read_be32(const void *base, size_t offset);
+uint64_t read_be64(const void *base, size_t offset);
+
+#endif /* !__PLATFORM_H__ */
diff --git a/include/platform/pci.h b/include/platform/pci.h
new file mode 100644
index 000000000..4ac108f26
--- /dev/null
+++ b/include/platform/pci.h
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2022 secunet Security Networks AG
+ * (written by Thomas Heijligen <thomas.heijligen@secunet.com)
+ *
+ * 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 __PLATFORM_PCI_H__
+#define __PLATFORM_PCI_H__
+
+/* Some NetBSDs are using an other include path for pci.h
+ * e.g. NetBSD 9.0 on sparc64 pciutils-3.7.0nb2.
+ * Other NetBSD platforms and versions uses the default path under pci/pci.h
+ */
+#if __has_include(<pciutils/pci.h>)
+#include <pciutils/pci.h>
+#else
+#include <pci/pci.h>
+#endif
+
+#endif /* __PLATFORM_PCI_H__ */
diff --git a/include/platform/swap.h b/include/platform/swap.h
new file mode 100644
index 000000000..12f310654
--- /dev/null
+++ b/include/platform/swap.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2022 secunet Security Networks AG
+ * (written by Thomas Heijligen <thomas.heijligen@secunet.com)
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+/*
+ * inline functions and macros shared by endian conversion functions
+ */
+
+#ifndef ___SWAP_H___
+#define ___SWAP_H___ 1
+
+#include <stdint.h>
+
+/* swap bytes */
+/* OpenBSD has conflicting definitions for swapX, _swap_X and __swapX */
+static inline uint8_t ___swap8(const uint8_t value)
+{
+ return (value & (uint8_t)0xffU);
+}
+
+static inline uint16_t ___swap16(const uint16_t value)
+{
+ return ((value & (uint16_t)0x00ffU) << 8) |
+ ((value & (uint16_t)0xff00U) >> 8);
+}
+
+static inline uint32_t ___swap32(const uint32_t value)
+{
+ return ((value & (uint32_t)0x000000ffUL) << 24) |
+ ((value & (uint32_t)0x0000ff00UL) << 8) |
+ ((value & (uint32_t)0x00ff0000UL) >> 8) |
+ ((value & (uint32_t)0xff000000UL) >> 24);
+}
+
+static inline uint64_t ___swap64(const uint64_t value)
+{
+ return ((value & (uint64_t)0x00000000000000ffULL) << 56) |
+ ((value & (uint64_t)0x000000000000ff00ULL) << 40) |
+ ((value & (uint64_t)0x0000000000ff0000ULL) << 24) |
+ ((value & (uint64_t)0x00000000ff000000ULL) << 8) |
+ ((value & (uint64_t)0x000000ff00000000ULL) >> 8) |
+ ((value & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+ ((value & (uint64_t)0x00ff000000000000ULL) >> 40) |
+ ((value & (uint64_t)0xff00000000000000ULL) >> 56);
+}
+
+/*
+ * macro to return the same value as passed.
+ *
+ * `___return_same(cpu_to_le, 8)`
+ * expands to
+ * `uint8_t cpu_to_le8 (const uint8_t value) { return value; }`
+ */
+#define ___return_same(name, bits) \
+ uint##bits##_t name##bits (const uint##bits##_t value) { return value; }
+
+/*
+ * macro to return the swapped value as passed.
+ *
+ * `___return_swapped(cpu_to_be, 8)`
+ * expands to
+ * `uint8_t cpu_to_be8 (const uint8_t value) { return ___swap8 (value); }`
+ */
+#define ___return_swapped(name, bits) \
+ uint##bits##_t name##bits (const uint##bits##_t value) { return ___swap##bits (value); }
+
+#endif /* !___SWAP_H___ */
diff --git a/programmer.h b/include/programmer.h
index 1c9ef38b0..562f58ad2 100644
--- a/programmer.h
+++ b/include/programmer.h
@@ -20,136 +20,21 @@
#ifndef __PROGRAMMER_H__
#define __PROGRAMMER_H__ 1
+#include <stdbool.h>
#include <stdint.h>
#include "flash.h" /* for chipaddr and flashctx */
-enum programmer {
-#if CONFIG_INTERNAL == 1
- PROGRAMMER_INTERNAL,
-#endif
-#if CONFIG_DUMMY == 1
- PROGRAMMER_DUMMY,
-#endif
-#if CONFIG_MEC1308 == 1
- PROGRAMMER_MEC1308,
-#endif
-#if CONFIG_NIC3COM == 1
- PROGRAMMER_NIC3COM,
-#endif
-#if CONFIG_NICREALTEK == 1
- PROGRAMMER_NICREALTEK,
-#endif
-#if CONFIG_NICNATSEMI == 1
- PROGRAMMER_NICNATSEMI,
-#endif
-#if CONFIG_GFXNVIDIA == 1
- PROGRAMMER_GFXNVIDIA,
-#endif
-#if CONFIG_RAIDEN_DEBUG_SPI == 1
- PROGRAMMER_RAIDEN_DEBUG_SPI,
-#endif
-#if CONFIG_DRKAISER == 1
- PROGRAMMER_DRKAISER,
-#endif
-#if CONFIG_SATASII == 1
- PROGRAMMER_SATASII,
-#endif
-#if CONFIG_ATAHPT == 1
- PROGRAMMER_ATAHPT,
-#endif
-#if CONFIG_ATAVIA == 1
- PROGRAMMER_ATAVIA,
-#endif
-#if CONFIG_ATAPROMISE == 1
- PROGRAMMER_ATAPROMISE,
-#endif
-#if CONFIG_IT8212 == 1
- PROGRAMMER_IT8212,
-#endif
-#if CONFIG_FT2232_SPI == 1
- PROGRAMMER_FT2232_SPI,
-#endif
-#if CONFIG_SERPROG == 1
- PROGRAMMER_SERPROG,
-#endif
-#if CONFIG_BUSPIRATE_SPI == 1
- PROGRAMMER_BUSPIRATE_SPI,
-#endif
-#if CONFIG_DEDIPROG == 1
- PROGRAMMER_DEDIPROG,
-#endif
-#if CONFIG_DEVELOPERBOX_SPI == 1
- PROGRAMMER_DEVELOPERBOX_SPI,
-#endif
-#if CONFIG_ENE_LPC == 1
- PROGRAMMER_ENE_LPC,
-#endif
-#if CONFIG_RAYER_SPI == 1
- PROGRAMMER_RAYER_SPI,
-#endif
-#if CONFIG_PONY_SPI == 1
- PROGRAMMER_PONY_SPI,
-#endif
-#if CONFIG_NICINTEL == 1
- PROGRAMMER_NICINTEL,
-#endif
-#if CONFIG_NICINTEL_SPI == 1
- PROGRAMMER_NICINTEL_SPI,
-#endif
-#if CONFIG_NICINTEL_EEPROM == 1
- PROGRAMMER_NICINTEL_EEPROM,
-#endif
-#if CONFIG_OGP_SPI == 1
- PROGRAMMER_OGP_SPI,
-#endif
-#if CONFIG_SATAMV == 1
- PROGRAMMER_SATAMV,
-#endif
-#if CONFIG_LINUX_MTD == 1
- PROGRAMMER_LINUX_MTD,
-#endif
-#if CONFIG_LINUX_SPI == 1
- PROGRAMMER_LINUX_SPI,
-#endif
-#if CONFIG_USBBLASTER_SPI == 1
- PROGRAMMER_USBBLASTER_SPI,
-#endif
-#if CONFIG_MSTARDDC_SPI == 1
- PROGRAMMER_MSTARDDC_SPI,
-#endif
-#if CONFIG_PICKIT2_SPI == 1
- PROGRAMMER_PICKIT2_SPI,
-#endif
-#if CONFIG_CH341A_SPI == 1
- PROGRAMMER_CH341A_SPI,
-#endif
-#if CONFIG_DIGILENT_SPI == 1
- PROGRAMMER_DIGILENT_SPI,
-#endif
-#if CONFIG_JLINK_SPI == 1
- PROGRAMMER_JLINK_SPI,
-#endif
-#if CONFIG_NI845X_SPI == 1
- PROGRAMMER_NI845X_SPI,
-#endif
-#if CONFIG_STLINKV3_SPI == 1
- PROGRAMMER_STLINKV3_SPI,
-#endif
-#if CONFIG_LSPCON_I2C_SPI == 1
- PROGRAMMER_LSPCON_I2C_SPI,
-#endif
-#if CONFIG_REALTEK_MST_I2C_SPI == 1
- PROGRAMMER_REALTEK_MST_I2C_SPI,
-#endif
- PROGRAMMER_INVALID /* This must always be the last entry. */
-};
-
enum programmer_type {
PCI = 1, /* to detect uninitialized values */
USB,
OTHER,
};
+struct board_cfg;
+struct programmer_cfg {
+ char *params;
+ struct board_cfg *bcfg;
+};
struct dev_entry {
uint16_t vendor_id;
@@ -167,43 +52,87 @@ struct programmer_entry {
const char *const note;
} devs;
- int (*init) (void);
-
- void *(*map_flash_region) (const char *descr, uintptr_t phys_addr, size_t len);
- void (*unmap_flash_region) (void *virt_addr, size_t len);
-
- void (*delay) (unsigned int usecs);
+ int (*init) (const struct programmer_cfg *cfg);
};
-extern const struct programmer_entry programmer_table[];
-
-int programmer_init(enum programmer prog, const char *param);
+extern const struct programmer_entry *const programmer_table[];
+extern const size_t programmer_table_size;
+
+/* programmer drivers */
+extern const struct programmer_entry programmer_asm106x;
+extern const struct programmer_entry programmer_atahpt;
+extern const struct programmer_entry programmer_atapromise;
+extern const struct programmer_entry programmer_atavia;
+extern const struct programmer_entry programmer_buspirate_spi;
+extern const struct programmer_entry programmer_ch341a_spi;
+extern const struct programmer_entry programmer_ch347_spi;
+extern const struct programmer_entry programmer_dediprog;
+extern const struct programmer_entry programmer_developerbox;
+extern const struct programmer_entry programmer_digilent_spi;
+extern const struct programmer_entry programmer_drkaiser;
+extern const struct programmer_entry programmer_dummy;
+extern const struct programmer_entry programmer_ft2232_spi;
+extern const struct programmer_entry programmer_gfxnvidia;
+extern const struct programmer_entry programmer_internal;
+extern const struct programmer_entry programmer_it8212;
+extern const struct programmer_entry programmer_jlink_spi;
+extern const struct programmer_entry programmer_linux_mtd;
+extern const struct programmer_entry programmer_linux_spi;
+extern const struct programmer_entry programmer_parade_lspcon;
+extern const struct programmer_entry programmer_mediatek_i2c_spi;
+extern const struct programmer_entry programmer_mstarddc_spi;
+extern const struct programmer_entry programmer_ni845x_spi;
+extern const struct programmer_entry programmer_nic3com;
+extern const struct programmer_entry programmer_nicintel;
+extern const struct programmer_entry programmer_nicintel_eeprom;
+extern const struct programmer_entry programmer_nicintel_spi;
+extern const struct programmer_entry programmer_nicnatsemi;
+extern const struct programmer_entry programmer_nicrealtek;
+extern const struct programmer_entry programmer_ogp_spi;
+extern const struct programmer_entry programmer_pickit2_spi;
+extern const struct programmer_entry programmer_pony_spi;
+extern const struct programmer_entry programmer_raiden_debug_spi;
+extern const struct programmer_entry programmer_rayer_spi;
+extern const struct programmer_entry programmer_realtek_mst_i2c_spi;
+extern const struct programmer_entry programmer_satamv;
+extern const struct programmer_entry programmer_satasii;
+extern const struct programmer_entry programmer_serprog;
+extern const struct programmer_entry programmer_stlinkv3_spi;
+extern const struct programmer_entry programmer_usbblaster_spi;
+extern const struct programmer_entry programmer_dirtyjtag_spi;
+
+int programmer_init(const struct programmer_entry *prog, const char *param);
int programmer_shutdown(void);
struct bitbang_spi_master {
/* Note that CS# is active low, so val=0 means the chip is active. */
- void (*set_cs) (int val);
- void (*set_sck) (int val);
- void (*set_mosi) (int val);
- int (*get_miso) (void);
- void (*request_bus) (void);
- void (*release_bus) (void);
+ void (*set_cs) (int val, void *spi_data);
+ void (*set_sck) (int val, void *spi_data);
+ void (*set_mosi) (int val, void *spi_data);
+ int (*get_miso) (void *spi_data);
+ void (*request_bus) (void *spi_data);
+ void (*release_bus) (void *spi_data);
/* optional functions to optimize xfers */
- void (*set_sck_set_mosi) (int sck, int mosi);
- int (*set_sck_get_miso) (int sck);
+ void (*set_sck_set_mosi) (int sck, int mosi, void *spi_data);
+ int (*set_sck_get_miso) (int sck, void *spi_data);
/* Length of half a clock period in usecs. */
unsigned int half_period;
};
-#if NEED_PCI == 1
struct pci_dev;
+struct pci_filter;
/* pcidev.c */
// FIXME: This needs to be local, not global(?)
extern struct pci_access *pacc;
int pci_init_common(void);
uintptr_t pcidev_readbar(struct pci_dev *dev, int bar);
-struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar);
+struct pci_dev *pcidev_init(const struct programmer_cfg *cfg, const struct dev_entry *devs, int bar);
+struct pci_dev *pcidev_scandev(struct pci_filter *filter, struct pci_dev *start);
+struct pci_dev *pcidev_getdevfn(struct pci_dev *dev, const int func);
+struct pci_dev *pcidev_find_vendorclass(uint16_t vendor, uint16_t devclass);
+struct pci_dev *pcidev_card_find(uint16_t vendor, uint16_t device, uint16_t card_vendor, uint16_t card_device);
+struct pci_dev *pcidev_find(uint16_t vendor, uint16_t device);
/* rpci_write_* are reversible writes. The original PCI config space register
* contents will be restored on shutdown.
* To clone the pci_dev instances internally, the `pacc` global
@@ -215,7 +144,6 @@ struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar);
int rpci_write_byte(struct pci_dev *dev, int reg, uint8_t data);
int rpci_write_word(struct pci_dev *dev, int reg, uint16_t data);
int rpci_write_long(struct pci_dev *dev, int reg, uint32_t data);
-#endif
#if CONFIG_INTERNAL == 1
struct penable {
@@ -225,7 +153,7 @@ struct penable {
const enum test_state status;
const char *vendor_name;
const char *device_name;
- int (*doit) (struct pci_dev *dev, const char *name);
+ int (*doit) (const struct programmer_cfg *cfg, struct pci_dev *dev, const char *name);
};
extern const struct penable chipset_enables[];
@@ -236,6 +164,11 @@ enum board_match_phase {
P3
};
+struct board_cfg {
+ int is_laptop;
+ bool laptop_ok;
+};
+
struct board_match {
/* Any device, but make it sensible, like the ISA bridge. */
uint16_t first_vendor;
@@ -265,10 +198,11 @@ struct board_match {
int max_rom_decode_parallel;
const enum test_state status;
- int (*enable) (void); /* May be NULL. */
+ int (*enable) (struct board_cfg *cfg); /* May be NULL. */
};
extern const struct board_match board_matches[];
+extern const size_t board_matches_size;
struct board_info {
const char *vendor;
@@ -288,7 +222,7 @@ extern const struct board_info laptops_known[];
void myusec_delay(unsigned int usecs);
void myusec_calibrate_delay(void);
void internal_sleep(unsigned int usecs);
-void internal_delay(unsigned int usecs);
+void default_delay(unsigned int usecs);
#if CONFIG_INTERNAL == 1
/* board_enable.c */
@@ -301,36 +235,26 @@ int it8705f_write_enable(uint8_t port);
uint8_t sio_read(uint16_t port, uint8_t reg);
void sio_write(uint16_t port, uint8_t reg, uint8_t data);
void sio_mask(uint16_t port, uint8_t reg, uint8_t data, uint8_t mask);
-void board_handle_before_superio(void);
-void board_handle_before_laptop(void);
-int board_flash_enable(const char *vendor, const char *model, const char *cb_vendor, const char *cb_model);
+void board_handle_before_superio(struct board_cfg *cfg, bool force_boardenable);
+void board_handle_before_laptop(struct board_cfg *cfg, bool force_boardenable);
+int board_flash_enable(struct board_cfg *cfg, const char *vendor, const char *model, const char *cb_vendor, const char *cb_model, bool force_boardenable);
/* chipset_enable.c */
-int chipset_flash_enable(void);
+int chipset_flash_enable(const struct programmer_cfg *cfg);
/* processor_enable.c */
int processor_flash_enable(void);
#endif
-/* physmap.c */
-void *physmap(const char *descr, uintptr_t phys_addr, size_t len);
-void *rphysmap(const char *descr, uintptr_t phys_addr, size_t len);
-void *physmap_ro(const char *descr, uintptr_t phys_addr, size_t len);
-void *physmap_ro_unaligned(const char *descr, uintptr_t phys_addr, size_t len);
-void physunmap(void *virt_addr, size_t len);
-void physunmap_unaligned(void *virt_addr, size_t len);
#if CONFIG_INTERNAL == 1
-int setup_cpu_msr(int cpu);
-void cleanup_cpu_msr(void);
-
/* cbtable.c */
int cb_parse_table(const char **vendor, const char **model);
int cb_check_image(const uint8_t *bios, unsigned int size);
/* dmi.c */
#if defined(__i386__) || defined(__x86_64__)
-extern int has_dmi_support;
-void dmi_init(void);
+void dmi_init(int *is_laptop);
+bool dmi_is_supported(void);
int dmi_match(const char *pattern);
#endif // defined(__i386__) || defined(__x86_64__)
@@ -346,258 +270,17 @@ extern int superio_count;
#define SUPERIO_VENDOR_ITE 0x1
#define SUPERIO_VENDOR_WINBOND 0x2
#endif
-#if NEED_PCI == 1
-struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t devclass);
-struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device);
-struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
- uint16_t card_vendor, uint16_t card_device);
-#endif
-int rget_io_perms(void);
+
#if CONFIG_INTERNAL == 1
-extern int is_laptop;
-extern int laptop_ok;
-extern int force_boardenable;
-extern int force_boardmismatch;
+extern bool force_boardmismatch;
void probe_superio(void);
int register_superio(struct superio s);
extern enum chipbustype internal_buses_supported;
-int internal_init(void);
-#endif
-
-/* hwaccess.c */
-void mmio_writeb(uint8_t val, void *addr);
-void mmio_writew(uint16_t val, void *addr);
-void mmio_writel(uint32_t val, void *addr);
-uint8_t mmio_readb(const void *addr);
-uint16_t mmio_readw(const void *addr);
-uint32_t mmio_readl(const void *addr);
-void mmio_readn(const void *addr, uint8_t *buf, size_t len);
-void mmio_le_writeb(uint8_t val, void *addr);
-void mmio_le_writew(uint16_t val, void *addr);
-void mmio_le_writel(uint32_t val, void *addr);
-uint8_t mmio_le_readb(const void *addr);
-uint16_t mmio_le_readw(const void *addr);
-uint32_t mmio_le_readl(const void *addr);
-#define pci_mmio_writeb mmio_le_writeb
-#define pci_mmio_writew mmio_le_writew
-#define pci_mmio_writel mmio_le_writel
-#define pci_mmio_readb mmio_le_readb
-#define pci_mmio_readw mmio_le_readw
-#define pci_mmio_readl mmio_le_readl
-void rmmio_writeb(uint8_t val, void *addr);
-void rmmio_writew(uint16_t val, void *addr);
-void rmmio_writel(uint32_t val, void *addr);
-void rmmio_le_writeb(uint8_t val, void *addr);
-void rmmio_le_writew(uint16_t val, void *addr);
-void rmmio_le_writel(uint32_t val, void *addr);
-#define pci_rmmio_writeb rmmio_le_writeb
-#define pci_rmmio_writew rmmio_le_writew
-#define pci_rmmio_writel rmmio_le_writel
-void rmmio_valb(void *addr);
-void rmmio_valw(void *addr);
-void rmmio_vall(void *addr);
-
-/* dummyflasher.c */
-#if CONFIG_DUMMY == 1
-int dummy_init(void);
-void *dummy_map(const char *descr, uintptr_t phys_addr, size_t len);
-void dummy_unmap(void *virt_addr, size_t len);
-#endif
-
-/* nic3com.c */
-#if CONFIG_NIC3COM == 1
-int nic3com_init(void);
-extern const struct dev_entry nics_3com[];
-#endif
-
-/* gfxnvidia.c */
-#if CONFIG_GFXNVIDIA == 1
-int gfxnvidia_init(void);
-extern const struct dev_entry gfx_nvidia[];
-#endif
-
-/* raiden_debug_spi.c */
-#if CONFIG_RAIDEN_DEBUG_SPI == 1
-int raiden_debug_spi_init(void);
-extern const struct dev_entry devs_raiden[];
-#endif
-
-/* drkaiser.c */
-#if CONFIG_DRKAISER == 1
-int drkaiser_init(void);
-extern const struct dev_entry drkaiser_pcidev[];
-#endif
-
-/* nicrealtek.c */
-#if CONFIG_NICREALTEK == 1
-int nicrealtek_init(void);
-extern const struct dev_entry nics_realtek[];
-#endif
-
-/* nicnatsemi.c */
-#if CONFIG_NICNATSEMI == 1
-int nicnatsemi_init(void);
-extern const struct dev_entry nics_natsemi[];
-#endif
-
-/* nicintel.c */
-#if CONFIG_NICINTEL == 1
-int nicintel_init(void);
-extern const struct dev_entry nics_intel[];
-#endif
-
-/* nicintel_spi.c */
-#if CONFIG_NICINTEL_SPI == 1
-int nicintel_spi_init(void);
-extern const struct dev_entry nics_intel_spi[];
-#endif
-
-/* nicintel_eeprom.c */
-#if CONFIG_NICINTEL_EEPROM == 1
-int nicintel_ee_init(void);
-extern const struct dev_entry nics_intel_ee[];
-#endif
-
-/* ogp_spi.c */
-#if CONFIG_OGP_SPI == 1
-int ogp_spi_init(void);
-extern const struct dev_entry ogp_spi[];
-#endif
-
-/* satamv.c */
-#if CONFIG_SATAMV == 1
-int satamv_init(void);
-extern const struct dev_entry satas_mv[];
-#endif
-
-/* satasii.c */
-#if CONFIG_SATASII == 1
-int satasii_init(void);
-extern const struct dev_entry satas_sii[];
-#endif
-
-/* atahpt.c */
-#if CONFIG_ATAHPT == 1
-int atahpt_init(void);
-extern const struct dev_entry ata_hpt[];
-#endif
-
-/* atavia.c */
-#if CONFIG_ATAVIA == 1
-int atavia_init(void);
-void *atavia_map(const char *descr, uintptr_t phys_addr, size_t len);
-extern const struct dev_entry ata_via[];
-#endif
-
-/* atapromise.c */
-#if CONFIG_ATAPROMISE == 1
-int atapromise_init(void);
-void *atapromise_map(const char *descr, uintptr_t phys_addr, size_t len);
-extern const struct dev_entry ata_promise[];
-#endif
-
-/* it8212.c */
-#if CONFIG_IT8212 == 1
-int it8212_init(void);
-extern const struct dev_entry devs_it8212[];
-#endif
-
-/* ft2232_spi.c */
-#if CONFIG_FT2232_SPI == 1
-int ft2232_spi_init(void);
-extern const struct dev_entry devs_ft2232spi[];
-#endif
-
-/* usbblaster_spi.c */
-#if CONFIG_USBBLASTER_SPI == 1
-int usbblaster_spi_init(void);
-extern const struct dev_entry devs_usbblasterspi[];
-#endif
-
-/* mstarddc_spi.c */
-#if CONFIG_MSTARDDC_SPI == 1
-int mstarddc_spi_init(void);
-#endif
-
-/* pickit2_spi.c */
-#if CONFIG_PICKIT2_SPI == 1
-int pickit2_spi_init(void);
-extern const struct dev_entry devs_pickit2_spi[];
-#endif
-
-/* stlinkv3_spi.c */
-#if CONFIG_STLINKV3_SPI == 1
-int stlinkv3_spi_init(void);
-extern const struct dev_entry devs_stlinkv3_spi[];
-#endif
-
-/* rayer_spi.c */
-#if CONFIG_RAYER_SPI == 1
-int rayer_spi_init(void);
-#endif
-
-/* pony_spi.c */
-#if CONFIG_PONY_SPI == 1
-int pony_spi_init(void);
#endif
/* bitbang_spi.c */
-int register_spi_bitbang_master(const struct bitbang_spi_master *master);
-
-/* buspirate_spi.c */
-#if CONFIG_BUSPIRATE_SPI == 1
-int buspirate_spi_init(void);
-#endif
+int register_spi_bitbang_master(const struct bitbang_spi_master *master, void *spi_data);
-/* linux_mtd.c */
-#if CONFIG_LINUX_MTD == 1
-int linux_mtd_init(void);
-#endif
-
-/* linux_spi.c */
-#if CONFIG_LINUX_SPI == 1
-int linux_spi_init(void);
-#endif
-
-/* dediprog.c */
-#if CONFIG_DEDIPROG == 1
-int dediprog_init(void);
-extern const struct dev_entry devs_dediprog[];
-#endif
-
-/* developerbox_spi.c */
-#if CONFIG_DEVELOPERBOX_SPI == 1
-int developerbox_spi_init(void);
-extern const struct dev_entry devs_developerbox_spi[];
-#endif
-
-/* ch341a_spi.c */
-#if CONFIG_CH341A_SPI == 1
-int ch341a_spi_init(void);
-void ch341a_spi_delay(unsigned int usecs);
-extern const struct dev_entry devs_ch341a_spi[];
-#endif
-
-/* digilent_spi.c */
-#if CONFIG_DIGILENT_SPI == 1
-int digilent_spi_init(void);
-extern const struct dev_entry devs_digilent_spi[];
-#endif
-
-/* ene_lpc.c */
-#if CONFIG_ENE_LPC == 1
-int ene_lpc_init(void);
-#endif
-
-/* jlink_spi.c */
-#if CONFIG_JLINK_SPI == 1
-int jlink_spi_init(void);
-#endif
-
-/* ni845x_spi.c */
-#if CONFIG_NI845X_SPI == 1
-int ni845x_spi_init(void);
-#endif
/* flashrom.c */
struct decode_sizes {
@@ -608,10 +291,9 @@ struct decode_sizes {
};
// FIXME: These need to be local, not global
extern struct decode_sizes max_rom_decode;
-extern int programmer_may_write;
-extern unsigned long flashbase;
-unsigned int count_max_decode_exceedings(const struct flashctx *flash);
-char *extract_programmer_param(const char *param_name);
+extern bool programmer_may_write;
+extern uintptr_t flashbase; /* used in programmer_enable.c */
+char *extract_programmer_param_str(const struct programmer_cfg *cfg, const char *param_name);
/* spi.c */
#define MAX_DATA_UNSPECIFIED 0
@@ -631,19 +313,22 @@ struct spi_master {
int (*multicommand)(const struct flashctx *flash, struct spi_command *cmds);
/* Optimized functions for this master */
+ void *(*map_flash_region) (const char *descr, uintptr_t phys_addr, size_t len);
+ void (*unmap_flash_region) (void *virt_addr, size_t len);
int (*read)(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
int (*write_256)(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
int (*write_aai)(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
+ int (*shutdown)(void *data);
+ bool (*probe_opcode)(const struct flashctx *flash, uint8_t opcode); /* NULL func implies true. */
+ void (*delay) (const struct flashctx *flash, unsigned int usecs);
+ void (*get_region)(const struct flashctx *flash, unsigned int addr, struct flash_region *region);
void *data;
};
-int default_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr, unsigned char *readarr);
-int default_spi_send_multicommand(const struct flashctx *flash, struct spi_command *cmds);
int default_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
int default_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
int default_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
-int register_spi_master(const struct spi_master *mst);
+int register_spi_master(const struct spi_master *mst, void *data);
/* The following enum is needed by ich_descriptor_tool and ich* code as well as in chipset_enable.c. */
enum ich_chipset {
@@ -670,47 +355,51 @@ enum ich_chipset {
CHIPSET_100_SERIES_SUNRISE_POINT, /* also 6th/7th gen Core i/o (LP) variants */
CHIPSET_C620_SERIES_LEWISBURG,
CHIPSET_300_SERIES_CANNON_POINT,
- CHIPSET_APOLLO_LAKE,
CHIPSET_400_SERIES_COMET_POINT,
+ CHIPSET_500_SERIES_TIGER_POINT,
+ CHIPSET_600_SERIES_ALDER_POINT,
+ CHIPSET_METEOR_LAKE,
+ CHIPSET_APOLLO_LAKE,
+ CHIPSET_GEMINI_LAKE,
+ CHIPSET_JASPER_LAKE,
+ CHIPSET_ELKHART_LAKE,
};
/* ichspi.c */
#if CONFIG_INTERNAL == 1
-int ich_init_spi(void *spibar, enum ich_chipset ich_generation);
+int ich_init_spi(const struct programmer_cfg *cfg, void *spibar, enum ich_chipset ich_generation);
int via_init_spi(uint32_t mmio_base);
/* amd_imc.c */
int amd_imc_shutdown(struct pci_dev *dev);
-/* it85spi.c */
-int it85xx_spi_init(struct superio s);
-
/* it87spi.c */
void enter_conf_mode_ite(uint16_t port);
void exit_conf_mode_ite(uint16_t port);
void probe_superio_ite(void);
-int init_superio_ite(void);
+int init_superio_ite(const struct programmer_cfg *cfg);
-#if CONFIG_LINUX_MTD == 1
/* trivial wrapper to avoid cluttering internal_init() with #if */
-static inline int try_mtd(void) { return linux_mtd_init(); };
+static inline int try_mtd(const struct programmer_cfg *cfg)
+{
+#if CONFIG_LINUX_MTD == 1
+ return programmer_linux_mtd.init(cfg);
#else
-static inline int try_mtd(void) { return 1; };
+ return 1;
#endif
+}
/* mcp6x_spi.c */
int mcp6x_spi_init(int want_spi);
-/* mec1308.c */
-#if CONFIG_MEC1308 == 1
-int mec1308_init(void);
-#endif
+/* internal_par.c */
+void internal_par_init(enum chipbustype buses);
/* sb600spi.c */
-int sb600_probe_spi(struct pci_dev *dev);
+int sb600_probe_spi(const struct programmer_cfg *cfg, struct pci_dev *dev);
/* wbsio_spi.c */
-int wbsio_check_for_spi(void);
+int wbsio_check_for_spi(struct board_cfg *);
#endif
/* opaque.c */
@@ -722,21 +411,28 @@ struct opaque_master {
int (*read) (struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len);
int (*write) (struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len);
int (*erase) (struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen);
+ /*
+ * Callbacks for accessing flash registers. An opaque programmer must
+ * provide these functions for writeprotect operations to be available,
+ * unless it provides custom wp operations instead.
+ */
+ int (*read_register)(const struct flashctx *flash, enum flash_reg reg, uint8_t *value);
+ int (*write_register)(const struct flashctx *flash, enum flash_reg reg, uint8_t value);
+ /* Callbacks for overiding default writeprotect operations with custom ones. */
+ enum flashrom_wp_result (*wp_write_cfg)(struct flashctx *, const struct flashrom_wp_cfg *);
+ enum flashrom_wp_result (*wp_read_cfg)(struct flashrom_wp_cfg *, struct flashctx *);
+ enum flashrom_wp_result (*wp_get_ranges)(struct flashrom_wp_ranges **, struct flashctx *);
+ void (*get_region)(const struct flashctx *flash, unsigned int addr, struct flash_region *region);
+ int (*shutdown)(void *data);
+ void (*delay) (const struct flashctx *flash, unsigned int usecs);
void *data;
};
-int register_opaque_master(const struct opaque_master *mst);
+int register_opaque_master(const struct opaque_master *mst, void *data);
-/* programmer.c */
-int noop_shutdown(void);
-void *fallback_map(const char *descr, uintptr_t phys_addr, size_t len);
-void fallback_unmap(void *virt_addr, size_t len);
-void fallback_chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr);
-void fallback_chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr);
-void fallback_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len);
-uint16_t fallback_chip_readw(const struct flashctx *flash, const chipaddr addr);
-uint32_t fallback_chip_readl(const struct flashctx *flash, const chipaddr addr);
-void fallback_chip_readn(const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len);
+/* parallel.c */
struct par_master {
+ void *(*map_flash_region) (const char *descr, uintptr_t phys_addr, size_t len);
+ void (*unmap_flash_region) (void *virt_addr, size_t len);
void (*chip_writeb) (const struct flashctx *flash, uint8_t val, chipaddr addr);
void (*chip_writew) (const struct flashctx *flash, uint16_t val, chipaddr addr);
void (*chip_writel) (const struct flashctx *flash, uint32_t val, chipaddr addr);
@@ -745,12 +441,16 @@ struct par_master {
uint16_t (*chip_readw) (const struct flashctx *flash, const chipaddr addr);
uint32_t (*chip_readl) (const struct flashctx *flash, const chipaddr addr);
void (*chip_readn) (const struct flashctx *flash, uint8_t *buf, const chipaddr addr, size_t len);
+ int (*shutdown)(void *data);
+ void (*delay) (const struct flashctx *flash, unsigned int usecs);
void *data;
};
-int register_par_master(const struct par_master *mst, const enum chipbustype buses);
+int register_par_master(const struct par_master *mst, const enum chipbustype buses, void *data);
+
+/* programmer.c */
struct registered_master {
enum chipbustype buses_supported;
- union {
+ struct {
struct par_master par;
struct spi_master spi;
struct opaque_master opaque;
@@ -760,12 +460,7 @@ extern struct registered_master registered_masters[];
extern int registered_master_count;
int register_master(const struct registered_master *mst);
-/* serprog.c */
-#if CONFIG_SERPROG == 1
-int serprog_init(void);
-void serprog_delay(unsigned int usecs);
-void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len);
-#endif
+
/* serial.c */
#if IS_WINDOWS
@@ -824,6 +519,12 @@ static inline bool spi_master_no_4ba_modes(const struct flashctx *const flash)
return flash->mst->buses_supported & BUS_SPI &&
flash->mst->spi.features & SPI_MASTER_NO_4BA_MODES;
}
+/* spi_chip feature checks */
+static inline bool spi_chip_4ba(const struct flashctx *const flash)
+{
+ return flash->chip->bustype == BUS_SPI &&
+ (flash->chip->feature_bits & (FEATURE_4BA_ENTER | FEATURE_4BA_ENTER_WREN | FEATURE_4BA_ENTER_EAR7));
+}
/* usbdev.c */
struct libusb_device_handle;
@@ -833,14 +534,5 @@ struct libusb_device_handle *usb_dev_get_by_vid_pid_serial(
struct libusb_device_handle *usb_dev_get_by_vid_pid_number(
struct libusb_context *usb_ctx, uint16_t vid, uint16_t pid, unsigned int num);
-/* lspcon_i2c_spi.c */
-#if CONFIG_LSPCON_I2C_SPI == 1
-int lspcon_i2c_spi_init(void);
-#endif
-
-/* realtek_mst_i2c_spi.c */
-#if CONFIG_REALTEK_MST_I2C_SPI == 1
-int realtek_mst_i2c_spi_init(void);
-#endif
#endif /* !__PROGRAMMER_H__ */
diff --git a/spi.h b/include/spi.h
index 09da5795c..505aecd01 100644
--- a/spi.h
+++ b/include/spi.h
@@ -131,6 +131,16 @@
#define JEDEC_RDSR_OUTSIZE 0x01
#define JEDEC_RDSR_INSIZE 0x01
+/* Read Status Register 2 */
+#define JEDEC_RDSR2 0x35
+#define JEDEC_RDSR2_OUTSIZE 0x01
+#define JEDEC_RDSR2_INSIZE 0x01
+
+/* Read Status Register 3 */
+#define JEDEC_RDSR3 0x15
+#define JEDEC_RDSR3_OUTSIZE 0x01
+#define JEDEC_RDSR3_INSIZE 0x01
+
/* Status Register Bits */
#define SPI_SR_WIP (0x01 << 0)
#define SPI_SR_WEL (0x01 << 1)
@@ -147,6 +157,31 @@
#define JEDEC_WRSR_OUTSIZE 0x02
#define JEDEC_WRSR_INSIZE 0x00
+/* Write Status Register 2 */
+#define JEDEC_WRSR2 0x31
+#define JEDEC_WRSR2_OUTSIZE 0x02
+#define JEDEC_WRSR2_INSIZE 0x00
+
+/* Write Status Register 3 */
+#define JEDEC_WRSR3 0x11
+#define JEDEC_WRSR3_OUTSIZE 0x02
+#define JEDEC_WRSR3_INSIZE 0x00
+
+/* Read Security Register */
+#define JEDEC_RDSCUR 0x2b
+#define JEDEC_RDSCUR_OUTSIZE 0x01
+#define JEDEC_RDSCUR_INSIZE 0x01
+
+/* Write Security Register */
+#define JEDEC_WRSCUR 0x2f
+#define JEDEC_WRSCUR_OUTSIZE 0x01
+#define JEDEC_WRSCUR_INSIZE 0x00
+
+/* Read Configuration Register */
+#define JEDEC_RDCR 0x15
+#define JEDEC_RDCR_OUTSIZE 0x01
+#define JEDEC_RDCR_INSIZE 0x01
+
/* Enter 4-byte Address Mode */
#define JEDEC_ENTER_4_BYTE_ADDR_MODE 0xB7
@@ -155,9 +190,11 @@
/* Write Extended Address Register */
#define JEDEC_WRITE_EXT_ADDR_REG 0xC5
+#define ALT_WRITE_EXT_ADDR_REG_17 0x17
/* Read Extended Address Register */
#define JEDEC_READ_EXT_ADDR_REG 0xC8
+#define ALT_READ_EXT_ADDR_REG_16 0x16
/* Read the memory */
#define JEDEC_READ 0x03
diff --git a/usb_device.h b/include/usb_device.h
index b2c7656e3..ed8187bb3 100644
--- a/usb_device.h
+++ b/include/usb_device.h
@@ -34,28 +34,28 @@
* flashrom recognizes. It does so without displaying an error code allowing us
* to compare error codes against the library enumeration values.
*/
-#define LIBUSB_ERROR(eror_code) (0x20000 | -eror_code)
+#define LIBUSB_ERROR(error_code) (0x20000 | -(error_code))
/*
* The LIBUSB macro converts a libusb failure code into an error code that
* flashrom recognizes. It also displays additional libusb specific
* information about the failure.
*/
-#define LIBUSB(expression) \
- ({ \
- int libusb_error__ = (expression); \
+#define LIBUSB(expression) \
+ ({ \
+ int libusb_error__ = (expression); \
\
- if (libusb_error__ < 0) { \
- msg_perr("libusb error: %s:%d %s\n", \
- __FILE__, \
- __LINE__, \
- libusb_error_name(libusb_error__)); \
+ if (libusb_error__ < 0) { \
+ msg_perr("libusb error: %s:%d %s\n", \
+ __FILE__, \
+ __LINE__, \
+ libusb_error_name(libusb_error__)); \
libusb_error__ = LIBUSB_ERROR(libusb_error__); \
- } else { \
- libusb_error__ = 0; \
- } \
+ } else { \
+ libusb_error__ = 0; \
+ } \
\
- libusb_error__; \
+ libusb_error__; \
})
/*
@@ -64,7 +64,7 @@
*/
static inline bool usb_device_is_libusb_error(int error_code)
{
- return (0x20000 <= error_code && error_code < 0x20064);
+ return (0x20000 <= error_code && error_code < 0x20064);
}
/*
@@ -99,10 +99,10 @@ struct usb_match {
* Initialize a usb_match structure so that each value's name matches the
* values name in the usb_match structure (so bus.name == "bus"...), and
* look for each value in the flashrom command line via
- * extract_programmer_param. If the value is found convert it to an integer
+ * extract_programmer_param_str. If the value is found convert it to an integer
* using strtol, accepting hex, decimal and octal encoding.
*/
-void usb_match_init(struct usb_match *match);
+void usb_match_init(const struct programmer_cfg *cfg, struct usb_match *match);
/*
* Add a default value to a usb_match_value. This must be done after calling
diff --git a/include/writeprotect.h b/include/writeprotect.h
new file mode 100644
index 000000000..7ceed0792
--- /dev/null
+++ b/include/writeprotect.h
@@ -0,0 +1,98 @@
+/*
+ * 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
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#include "libflashrom.h"
+
+#define MAX_BP_BITS 4
+
+/* Chip protection range: start address and length. */
+struct wp_range {
+ size_t start, len;
+};
+
+/* Generic description of a chip's write protection configuration. */
+struct flashrom_wp_cfg {
+ enum flashrom_wp_mode mode;
+ struct wp_range range;
+};
+
+/* Collection of multiple write protection ranges. */
+struct flashrom_wp_ranges {
+ struct wp_range *ranges;
+ size_t count;
+};
+
+/*
+ * Description of a chip's write protection configuration.
+ *
+ * It allows most WP code to store and manipulate a chip's configuration
+ * without knowing the exact layout of bits in the chip's status registers.
+ */
+struct wp_bits {
+ /* Status register protection bit (SRP) */
+ bool srp_bit_present;
+ uint8_t srp;
+
+ /* Status register lock bit (SRL) */
+ bool srl_bit_present;
+ uint8_t srl;
+
+ /* Complement bit (CMP) */
+ bool cmp_bit_present;
+ uint8_t cmp;
+
+ /* Sector/block protection bit (SEC) */
+ bool sec_bit_present;
+ uint8_t sec;
+
+ /* Top/bottom protection bit (TB) */
+ bool tb_bit_present;
+ uint8_t tb;
+
+ /* Block protection bits (BP) */
+ size_t bp_bit_count;
+ uint8_t bp[MAX_BP_BITS];
+};
+
+struct flashrom_flashctx;
+
+/* Write WP configuration to the chip */
+enum flashrom_wp_result wp_write_cfg(struct flashrom_flashctx *, const struct flashrom_wp_cfg *);
+
+/* Read WP configuration from the chip */
+enum flashrom_wp_result wp_read_cfg(struct flashrom_wp_cfg *, struct flashrom_flashctx *);
+
+/* Get a list of protection ranges supported by the chip */
+enum flashrom_wp_result wp_get_available_ranges(struct flashrom_wp_ranges **, struct flashrom_flashctx *);
+
+/* Checks if writeprotect functions can be used with the current flash/programmer */
+bool wp_operations_available(struct flashrom_flashctx *);
+
+/*
+ * Converts a writeprotect config to register values and masks that indicate which register bits affect WP state.
+ * reg_values, bit_masks, and write_masks must all have length of at least MAX_REGISTERS.
+ */
+enum flashrom_wp_result wp_cfg_to_reg_values(uint8_t *reg_values, uint8_t *bit_masks, uint8_t *write_masks, struct flashrom_flashctx *, const struct flashrom_wp_cfg *);
+
+#endif /* !__WRITEPROTECT_H__ */
diff --git a/internal.c b/internal.c
index bdbe32d4d..faeb46354 100644
--- a/internal.c
+++ b/internal.c
@@ -16,176 +16,38 @@
#include <strings.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
+
#include "flash.h"
-#include "platform.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "platform/pci.h"
-int is_laptop = 0;
-int laptop_ok = 0;
+#if defined(__i386__) || defined(__x86_64__)
+#include "hwaccess_x86_io.h"
+#endif
-int force_boardenable = 0;
-int force_boardmismatch = 0;
+bool force_boardmismatch = false;
enum chipbustype internal_buses_supported = BUS_NONE;
-struct pci_dev *pci_dev_find_vendorclass(uint16_t vendor, uint16_t devclass)
-{
- struct pci_dev *temp;
- struct pci_filter filter;
- uint16_t tmp2;
-
- pci_filter_init(NULL, &filter);
- filter.vendor = vendor;
-
- for (temp = pacc->devices; temp; temp = temp->next)
- if (pci_filter_match(&filter, temp)) {
- /* Read PCI class */
- tmp2 = pci_read_word(temp, 0x0a);
- if (tmp2 == devclass)
- return temp;
- }
-
- return NULL;
-}
-
-struct pci_dev *pci_dev_find(uint16_t vendor, uint16_t device)
-{
- struct pci_dev *temp;
- struct pci_filter filter;
-
- pci_filter_init(NULL, &filter);
- filter.vendor = vendor;
- filter.device = device;
-
- for (temp = pacc->devices; temp; temp = temp->next)
- if (pci_filter_match(&filter, temp))
- return temp;
-
- return NULL;
-}
-
-struct pci_dev *pci_card_find(uint16_t vendor, uint16_t device,
- uint16_t card_vendor, uint16_t card_device)
-{
- struct pci_dev *temp;
- struct pci_filter filter;
-
- pci_filter_init(NULL, &filter);
- filter.vendor = vendor;
- filter.device = device;
-
- for (temp = pacc->devices; temp; temp = temp->next)
- if (pci_filter_match(&filter, temp)) {
- if ((card_vendor ==
- pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID))
- && (card_device ==
- pci_read_word(temp, PCI_SUBSYSTEM_ID)))
- return temp;
- }
-
- return NULL;
-}
-
-#if IS_X86
-void probe_superio(void)
-{
- probe_superio_winbond();
- /* ITE probe causes SMSC LPC47N217 to power off the serial UART.
- * Always probe for SMSC first, and if a SMSC Super I/O is detected
- * at a given I/O port, do _not_ probe that port with the ITE probe.
- * This means SMSC probing must be done before ITE probing.
- */
- //probe_superio_smsc();
- probe_superio_ite();
-}
-
-int superio_count = 0;
-#define SUPERIO_MAX_COUNT 3
-
-struct superio superios[SUPERIO_MAX_COUNT];
-
-int register_superio(struct superio s)
-{
- if (superio_count == SUPERIO_MAX_COUNT)
- return 1;
- superios[superio_count++] = s;
- return 0;
-}
-
-#endif /* IS_X86 */
-
-static void internal_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- mmio_writeb(val, (void *) addr);
-}
-static void internal_chip_writew(const struct flashctx *flash, uint16_t val,
- chipaddr addr)
+static int get_params(const struct programmer_cfg *cfg,
+ bool *boardenable, bool *boardmismatch,
+ bool *force_laptop, bool *not_a_laptop,
+ char **board_vendor, char **board_model)
{
- mmio_writew(val, (void *) addr);
-}
-
-static void internal_chip_writel(const struct flashctx *flash, uint32_t val,
- chipaddr addr)
-{
- mmio_writel(val, (void *) addr);
-}
-
-static uint8_t internal_chip_readb(const struct flashctx *flash,
- const chipaddr addr)
-{
- return mmio_readb((void *) addr);
-}
-
-static uint16_t internal_chip_readw(const struct flashctx *flash,
- const chipaddr addr)
-{
- return mmio_readw((void *) addr);
-}
-
-static uint32_t internal_chip_readl(const struct flashctx *flash,
- const chipaddr addr)
-{
- return mmio_readl((void *) addr);
-}
-
-static void internal_chip_readn(const struct flashctx *flash, uint8_t *buf,
- const chipaddr addr, size_t len)
-{
- mmio_readn((void *)addr, buf, len);
- return;
-}
-
-static const struct par_master par_master_internal = {
- .chip_readb = internal_chip_readb,
- .chip_readw = internal_chip_readw,
- .chip_readl = internal_chip_readl,
- .chip_readn = internal_chip_readn,
- .chip_writeb = internal_chip_writeb,
- .chip_writew = internal_chip_writew,
- .chip_writel = internal_chip_writel,
- .chip_writen = fallback_chip_writen,
-};
-
-int internal_init(void)
-{
- int ret = 0;
- int force_laptop = 0;
- int not_a_laptop = 0;
- char *board_vendor = NULL;
- char *board_model = NULL;
-#if IS_X86
- const char *cb_vendor = NULL;
- const char *cb_model = NULL;
-#endif
char *arg;
- arg = extract_programmer_param("boardenable");
+ /* default values. */
+ *force_laptop = false;
+ *not_a_laptop = false;
+ *board_vendor = NULL;
+ *board_model = NULL;
+
+ arg = extract_programmer_param_str(cfg, "boardenable");
if (arg && !strcmp(arg,"force")) {
- force_boardenable = 1;
+ *boardenable = true;
} else if (arg && !strlen(arg)) {
msg_perr("Missing argument for boardenable.\n");
free(arg);
@@ -197,9 +59,9 @@ int internal_init(void)
}
free(arg);
- arg = extract_programmer_param("boardmismatch");
+ arg = extract_programmer_param_str(cfg, "boardmismatch");
if (arg && !strcmp(arg,"force")) {
- force_boardmismatch = 1;
+ *boardmismatch = true;
} else if (arg && !strlen(arg)) {
msg_perr("Missing argument for boardmismatch.\n");
free(arg);
@@ -211,11 +73,11 @@ int internal_init(void)
}
free(arg);
- arg = extract_programmer_param("laptop");
+ arg = extract_programmer_param_str(cfg, "laptop");
if (arg && !strcmp(arg, "force_I_want_a_brick"))
- force_laptop = 1;
+ *force_laptop = true;
else if (arg && !strcmp(arg, "this_is_not_a_laptop"))
- not_a_laptop = 1;
+ *not_a_laptop = true;
else if (arg && !strlen(arg)) {
msg_perr("Missing argument for laptop.\n");
free(arg);
@@ -227,9 +89,9 @@ int internal_init(void)
}
free(arg);
- arg = extract_programmer_param("mainboard");
+ arg = extract_programmer_param_str(cfg, "mainboard");
if (arg && strlen(arg)) {
- if (board_parse_parameter(arg, &board_vendor, &board_model)) {
+ if (board_parse_parameter(arg, board_vendor, board_model)) {
free(arg);
return 1;
}
@@ -240,10 +102,62 @@ int internal_init(void)
}
free(arg);
- if (rget_io_perms()) {
- ret = 1;
- goto internal_init_exit;
+ return 0;
+}
+
+static void report_nonwl_laptop_detected(const struct board_cfg *bcfg)
+{
+ const int is_laptop = bcfg->is_laptop;
+ const bool laptop_ok = bcfg->laptop_ok;
+
+ if (!is_laptop || laptop_ok)
+ return;
+
+ msg_pinfo("========================================================================\n");
+ if (is_laptop == 1) {
+ msg_pinfo("You seem to be running flashrom on an unknown laptop. Some\n"
+ "internal buses have been disabled for safety reasons.\n\n");
+ } else {
+ msg_pinfo("You may be running flashrom on an unknown laptop. We could not\n"
+ "detect this for sure because your vendor has not set up the SMBIOS\n"
+ "tables correctly. Some internal buses have been disabled for\n"
+ "safety reasons. You can enforce using all buses by adding\n"
+ " -p internal:laptop=this_is_not_a_laptop\n"
+ "to the command line, but please read the following warning if you\n"
+ "are not sure.\n\n");
}
+ msg_perr("Laptops, notebooks and netbooks are difficult to support and we\n"
+ "recommend to use the vendor flashing utility. The embedded controller\n"
+ "(EC) in these machines often interacts badly with flashing.\n"
+ "See the manpage and https://flashrom.org/Laptops for details.\n\n"
+ "If flash is shared with the EC, erase is guaranteed to brick your laptop\n"
+ "and write may brick your laptop.\n"
+ "Read and probe may irritate your EC and cause fan failure, backlight\n"
+ "failure and sudden poweroff.\n"
+ "You have been warned.\n"
+ "========================================================================\n");
+}
+
+static int internal_init(const struct programmer_cfg *cfg)
+{
+ int ret = 0;
+ bool force_laptop;
+ bool not_a_laptop;
+ char *board_vendor;
+ char *board_model;
+#if defined(__i386__) || defined(__x86_64__)
+ const char *cb_vendor = NULL;
+ const char *cb_model = NULL;
+#endif
+ bool force_boardenable = false;
+ struct board_cfg bcfg = {0};
+
+ ret = get_params(cfg,
+ &force_boardenable, &force_boardmismatch,
+ &force_laptop, &not_a_laptop,
+ &board_vendor, &board_model);
+ if (ret)
+ return ret;
/* Default to Parallel/LPC/FWH flash devices. If a known host controller
* is found, the host controller init routine sets the
@@ -251,7 +165,7 @@ int internal_init(void)
*/
internal_buses_supported = BUS_NONSPI;
- if (try_mtd() == 0) {
+ if (try_mtd(cfg) == 0) {
ret = 0;
goto internal_init_exit;
}
@@ -269,7 +183,12 @@ int internal_init(void)
goto internal_init_exit;
}
-#if IS_X86
+#if defined(__i386__) || defined(__x86_64__)
+ if (rget_io_perms()) {
+ ret = 1;
+ goto internal_init_exit;
+ }
+
if ((cb_parse_table(&cb_vendor, &cb_model) == 0) && (board_vendor != NULL) && (board_model != NULL)) {
if (strcasecmp(board_vendor, cb_vendor) || strcasecmp(board_model, cb_model)) {
msg_pwarn("Warning: The mainboard IDs set by -p internal:mainboard (%s:%s) do not\n"
@@ -283,12 +202,12 @@ int internal_init(void)
}
}
- is_laptop = 2; /* Assume that we don't know by default. */
+ bcfg.is_laptop = 2; /* Assume that we don't know by default. */
- dmi_init();
+ dmi_init(&bcfg.is_laptop);
/* In case Super I/O probing would cause pretty explosions. */
- board_handle_before_superio();
+ board_handle_before_superio(&bcfg, force_boardenable);
/* Probe for the Super I/O chip and fill global struct superio. */
probe_superio();
@@ -298,71 +217,49 @@ int internal_init(void)
* FIXME: Find a replacement for DMI on non-x86.
* FIXME: Enable Super I/O probing once port I/O is possible.
*/
-#endif /* IS_X86 */
+#endif
/* Check laptop whitelist. */
- board_handle_before_laptop();
+ board_handle_before_laptop(&bcfg, force_boardenable);
/*
* Disable all internal buses by default if we are not sure
* this isn't a laptop. Board-enables may override this,
* non-legacy buses (SPI and opaque atm) are probed anyway.
*/
- if (is_laptop && !(laptop_ok || force_laptop || (not_a_laptop && is_laptop == 2)))
+ if (bcfg.is_laptop && !(bcfg.laptop_ok || force_laptop || (not_a_laptop && bcfg.is_laptop == 2)))
internal_buses_supported = BUS_NONE;
/* try to enable it. Failure IS an option, since not all motherboards
* really need this to be done, etc., etc.
*/
- ret = chipset_flash_enable();
+ struct programmer_cfg icfg = *cfg;
+ icfg.bcfg = &bcfg;
+ ret = chipset_flash_enable(&icfg);
if (ret == -2) {
msg_perr("WARNING: No chipset found. Flash detection "
"will most likely fail.\n");
- } else if (ret == ERROR_FATAL) {
+ } else if (ret == ERROR_FLASHROM_FATAL) {
goto internal_init_exit;
}
-#if IS_X86
+#if defined(__i386__) || defined(__x86_64__)
/* Probe unconditionally for ITE Super I/O chips. This enables LPC->SPI translation on IT87* and
* parallel writes on IT8705F. Also, this handles the manual chip select for Gigabyte's DualBIOS. */
- init_superio_ite();
+ init_superio_ite(cfg);
- if (board_flash_enable(board_vendor, board_model, cb_vendor, cb_model)) {
+ if (board_flash_enable(&bcfg,
+ board_vendor, board_model, cb_vendor, cb_model, force_boardenable)) {
msg_perr("Aborting to be safe.\n");
ret = 1;
goto internal_init_exit;
}
-#endif /* IS_X86 */
+#endif
- if (internal_buses_supported & BUS_NONSPI)
- register_par_master(&par_master_internal, internal_buses_supported);
+ internal_par_init(internal_buses_supported);
/* Report if a non-whitelisted laptop is detected that likely uses a legacy bus. */
- if (is_laptop && !laptop_ok) {
- msg_pinfo("========================================================================\n");
- if (is_laptop == 1) {
- msg_pinfo("You seem to be running flashrom on an unknown laptop. Some\n"
- "internal buses have been disabled for safety reasons.\n\n");
- } else {
- msg_pinfo("You may be running flashrom on an unknown laptop. We could not\n"
- "detect this for sure because your vendor has not set up the SMBIOS\n"
- "tables correctly. Some internal buses have been disabled for\n"
- "safety reasons. You can enforce using all buses by adding\n"
- " -p internal:laptop=this_is_not_a_laptop\n"
- "to the command line, but please read the following warning if you\n"
- "are not sure.\n\n");
- }
- msg_perr("Laptops, notebooks and netbooks are difficult to support and we\n"
- "recommend to use the vendor flashing utility. The embedded controller\n"
- "(EC) in these machines often interacts badly with flashing.\n"
- "See the manpage and https://flashrom.org/Laptops for details.\n\n"
- "If flash is shared with the EC, erase is guaranteed to brick your laptop\n"
- "and write may brick your laptop.\n"
- "Read and probe may irritate your EC and cause fan failure, backlight\n"
- "failure and sudden poweroff.\n"
- "You have been warned.\n"
- "========================================================================\n");
- }
+ report_nonwl_laptop_detected(&bcfg);
ret = 0;
@@ -372,3 +269,10 @@ internal_init_exit:
return ret;
}
+
+const struct programmer_entry programmer_internal = {
+ .name = "internal",
+ .type = OTHER,
+ .devs.note = NULL,
+ .init = internal_init,
+};
diff --git a/internal_par.c b/internal_par.c
new file mode 100644
index 000000000..e8e387cad
--- /dev/null
+++ b/internal_par.c
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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 "programmer.h"
+#include "hwaccess_physmap.h"
+
+static void internal_chip_writeb(const struct flashctx *flash, uint8_t val,
+ chipaddr addr)
+{
+ mmio_writeb(val, (void *) addr);
+}
+
+static void internal_chip_writew(const struct flashctx *flash, uint16_t val,
+ chipaddr addr)
+{
+ mmio_writew(val, (void *) addr);
+}
+
+static void internal_chip_writel(const struct flashctx *flash, uint32_t val,
+ chipaddr addr)
+{
+ mmio_writel(val, (void *) addr);
+}
+
+static uint8_t internal_chip_readb(const struct flashctx *flash,
+ const chipaddr addr)
+{
+ return mmio_readb((void *) addr);
+}
+
+static uint16_t internal_chip_readw(const struct flashctx *flash,
+ const chipaddr addr)
+{
+ return mmio_readw((void *) addr);
+}
+
+static uint32_t internal_chip_readl(const struct flashctx *flash,
+ const chipaddr addr)
+{
+ return mmio_readl((void *) addr);
+}
+
+static void internal_chip_readn(const struct flashctx *flash, uint8_t *buf,
+ const chipaddr addr, size_t len)
+{
+ mmio_readn((void *)addr, buf, len);
+ return;
+}
+
+static const struct par_master par_master_internal = {
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .chip_readb = internal_chip_readb,
+ .chip_readw = internal_chip_readw,
+ .chip_readl = internal_chip_readl,
+ .chip_readn = internal_chip_readn,
+ .chip_writeb = internal_chip_writeb,
+ .chip_writew = internal_chip_writew,
+ .chip_writel = internal_chip_writel,
+};
+
+void internal_par_init(enum chipbustype buses)
+{
+ if (buses & BUS_NONSPI)
+ register_par_master(&par_master_internal, internal_buses_supported, NULL);
+}
diff --git a/it8212.c b/it8212.c
index ac53a6fcf..3c1161d60 100644
--- a/it8212.c
+++ b/it8212.c
@@ -17,13 +17,18 @@
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
-static uint8_t *it8212_bar = NULL;
+struct it8212_data {
+ struct pci_dev *dev;
+ uint8_t *bar;
+ uint32_t decode_access;
+};
#define PCI_VENDOR_ID_ITE 0x1283
-const struct dev_entry devs_it8212[] = {
+static const struct dev_entry devs_it8212[] = {
{PCI_VENDOR_ID_ITE, 0x8212, NT, "ITE", "8212F PATA RAID"},
{0},
@@ -32,25 +37,42 @@ const struct dev_entry devs_it8212[] = {
#define IT8212_MEMMAP_SIZE (128 * 1024)
#define IT8212_MEMMAP_MASK (IT8212_MEMMAP_SIZE - 1)
-static void it8212_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
-static uint8_t it8212_chip_readb(const struct flashctx *flash, const chipaddr addr);
+static void it8212_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
+{
+ const struct it8212_data *data = flash->mst->par.data;
+
+ pci_mmio_writeb(val, data->bar + (addr & IT8212_MEMMAP_MASK));
+}
+
+static uint8_t it8212_chip_readb(const struct flashctx *flash, const chipaddr addr)
+{
+ const struct it8212_data *data = flash->mst->par.data;
+
+ return pci_mmio_readb(data->bar + (addr & IT8212_MEMMAP_MASK));
+}
+
+static int it8212_shutdown(void *par_data)
+{
+ struct it8212_data *data = par_data;
+
+ /* Restore ROM BAR decode state. */
+ pci_write_long(data->dev, PCI_ROM_ADDRESS, data->decode_access);
+
+ free(par_data);
+ return 0;
+}
+
static const struct par_master par_master_it8212 = {
- .chip_readb = it8212_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = it8212_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
+ .chip_readb = it8212_chip_readb,
+ .chip_writeb = it8212_chip_writeb,
+ .shutdown = it8212_shutdown,
};
-int it8212_init(void)
+static int it8212_init(const struct programmer_cfg *cfg)
{
- if (rget_io_perms())
- return 1;
+ uint8_t *bar;
- struct pci_dev *dev = pcidev_init(devs_it8212, PCI_ROM_ADDRESS);
+ struct pci_dev *dev = pcidev_init(cfg, devs_it8212, PCI_ROM_ADDRESS);
if (!dev)
return 1;
@@ -59,24 +81,28 @@ int it8212_init(void)
if (!io_base_addr)
return 1;
- it8212_bar = rphysmap("IT8212F flash", io_base_addr, IT8212_MEMMAP_SIZE);
- if (it8212_bar == ERROR_PTR)
+ bar = rphysmap("IT8212F flash", io_base_addr, IT8212_MEMMAP_SIZE);
+ if (bar == ERROR_PTR)
return 1;
- /* Restore ROM BAR decode state automatically at shutdown. */
- rpci_write_long(dev, PCI_ROM_ADDRESS, io_base_addr | 0x01);
+ struct it8212_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
+ return 1;
+ }
+ data->dev = dev;
+ data->bar = bar;
- max_rom_decode.parallel = IT8212_MEMMAP_SIZE;
- register_par_master(&par_master_it8212, BUS_PARALLEL);
- return 0;
-}
+ /* Enable ROM BAR decoding. */
+ data->decode_access = pci_read_long(dev, PCI_ROM_ADDRESS);
+ pci_write_long(dev, PCI_ROM_ADDRESS, io_base_addr | 0x01);
-static void it8212_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
-{
- pci_mmio_writeb(val, it8212_bar + (addr & IT8212_MEMMAP_MASK));
-}
-
-static uint8_t it8212_chip_readb(const struct flashctx *flash, const chipaddr addr)
-{
- return pci_mmio_readb(it8212_bar + (addr & IT8212_MEMMAP_MASK));
+ max_rom_decode.parallel = IT8212_MEMMAP_SIZE;
+ return register_par_master(&par_master_it8212, BUS_PARALLEL, data);
}
+const struct programmer_entry programmer_it8212 = {
+ .name = "it8212",
+ .type = PCI,
+ .devs.dev = devs_it8212,
+ .init = it8212_init,
+};
diff --git a/it85spi.c b/it85spi.c
deleted file mode 100644
index 33e0b8498..000000000
--- a/it85spi.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger
- * Copyright (C) 2008 Ronald Hoogenboom <ronald@zonnet.nl>
- * Copyright (C) 2008 coresystems GmbH
- * 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; version 2 of the License.
- *
- * 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.
- */
-
-/*
- * Contains the ITE IT85* SPI specific routines
- */
-
-#if defined(__i386__) || defined(__x86_64__)
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "flash.h"
-#include "spi.h"
-#include "programmer.h"
-#include "hwaccess.h"
-
-#define MAX_TIMEOUT 100000
-#define MAX_TRY 5
-
-/* Constants for I/O ports */
-#define ITE_SUPERIO_PORT1 0x2e
-#define ITE_SUPERIO_PORT2 0x4e
-
-/* Legacy I/O */
-#define LEGACY_KBC_PORT_DATA 0x60
-#define LEGACY_KBC_PORT_CMD 0x64
-
-/* Constants for Logical Device registers */
-#define LDNSEL 0x07
-
-/* These are standard Super I/O 16-bit base address registers */
-#define SHM_IO_BAR0 0x60 /* big-endian, this is high bits */
-#define SHM_IO_BAR1 0x61
-
-/* The 8042 keyboard controller uses an input buffer and an output buffer to
- * communicate with the host CPU. Both buffers are 1-byte depth. That means
- * IBF is set to 1 when the host CPU sends a command to the input buffer
- * of the EC. IBF is cleared to 0 once the command is read by the EC.
- */
-#define KB_IBF (1 << 1) /* Input Buffer Full */
-#define KB_OBF (1 << 0) /* Output Buffer Full */
-
-/* IT8502 supports two access modes:
- * LPC_MEMORY: through the memory window in 0xFFFFFxxx (follow mode)
- * LPC_IO: through I/O port (so called indirect memory)
- */
-#undef LPC_MEMORY
-#define LPC_IO
-
-#ifdef LPC_IO
-/* macro to fill in indirect-access registers. */
-#define INDIRECT_A0(base, value) OUTB(value, (base) + 0) /* little-endian */
-#define INDIRECT_A1(base, value) OUTB(value, (base) + 1)
-#define INDIRECT_A2(base, value) OUTB(value, (base) + 2)
-#define INDIRECT_A3(base, value) OUTB(value, (base) + 3)
-#define INDIRECT_READ(base) INB((base) + 4)
-#define INDIRECT_WRITE(base, value) OUTB(value, (base) + 4)
-#endif /* LPC_IO */
-
-struct it85spi_data {
-#ifdef LPC_IO
- unsigned int shm_io_base;
-#endif
- unsigned char *ce_high, *ce_low;
- int it85xx_scratch_rom_reenter;
-};
-
-/* This function will poll the keyboard status register until either
- * an expected value shows up, or the timeout is reached.
- * timeout is in usec.
- *
- * Returns: 0 -- the expected value showed up.
- * 1 -- timeout.
- */
-static int wait_for(const unsigned int mask, const unsigned int expected_value,
- const int timeout, const char * error_message,
- const char * function_name, const int lineno)
-{
- int time_passed;
-
- for (time_passed = 0;; ++time_passed) {
- if ((INB(LEGACY_KBC_PORT_CMD) & mask) == expected_value)
- return 0;
- if (time_passed >= timeout)
- break;
- programmer_delay(1);
- }
- if (error_message)
- msg_perr("%s():%d %s", function_name, lineno, error_message);
- return 1;
-}
-
-/* IT8502 employs a scratch RAM when flash is being updated. Call the following
- * two functions before/after flash erase/program. */
-static void it85xx_enter_scratch_rom(struct it85spi_data *data)
-{
- int ret, tries;
-
- msg_pdbg("%s():%d was called ...\n", __func__, __LINE__);
- if (data->it85xx_scratch_rom_reenter > 0)
- return;
-
-#if 0
- /* FIXME: this a workaround for the bug that SMBus signal would
- * interfere the EC firmware update. Should be removed if
- * we find out the root cause. */
- ret = system("stop powerd >&2");
- if (ret)
- msg_perr("Cannot stop powerd.\n");
-#endif
-
- for (tries = 0; tries < MAX_TRY; ++tries) {
- /* Wait until IBF (input buffer) is not full. */
- if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
- "* timeout at waiting for IBF==0.\n",
- __func__, __LINE__))
- continue;
-
- /* Copy EC firmware to SRAM. */
- OUTB(0xb4, LEGACY_KBC_PORT_CMD);
-
- /* Confirm EC has taken away the command. */
- if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
- "* timeout at taking command.\n",
- __func__, __LINE__))
- continue;
-
- /* Waiting for OBF (output buffer) has data.
- * Note sometimes the replied command might be stolen by kernel
- * ISR so that it is okay as long as the command is 0xFA. */
- if (wait_for(KB_OBF, KB_OBF, MAX_TIMEOUT, NULL, NULL, 0))
- msg_pdbg("%s():%d * timeout at waiting for OBF.\n",
- __func__, __LINE__);
- if ((ret = INB(LEGACY_KBC_PORT_DATA)) == 0xFA) {
- break;
- } else {
- msg_perr("%s():%d * not run on SRAM ret=%d\n",
- __func__, __LINE__, ret);
- continue;
- }
- }
-
- if (tries < MAX_TRY) {
- /* EC already runs on SRAM */
- data->it85xx_scratch_rom_reenter++;
- msg_pdbg("%s():%d * SUCCESS.\n", __func__, __LINE__);
- } else {
- msg_perr("%s():%d * Max try reached.\n", __func__, __LINE__);
- }
-}
-
-static void it85xx_exit_scratch_rom(struct it85spi_data *data)
-{
-#if 0
- int ret;
-#endif
- int tries;
-
- msg_pdbg("%s():%d was called ...\n", __func__, __LINE__);
- if (data->it85xx_scratch_rom_reenter <= 0)
- return;
-
- for (tries = 0; tries < MAX_TRY; ++tries) {
- /* Wait until IBF (input buffer) is not full. */
- if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
- "* timeout at waiting for IBF==0.\n",
- __func__, __LINE__))
- continue;
-
- /* Exit SRAM. Run on flash. */
- OUTB(0xFE, LEGACY_KBC_PORT_CMD);
-
- /* Confirm EC has taken away the command. */
- if (wait_for(KB_IBF, 0, MAX_TIMEOUT,
- "* timeout at taking command.\n",
- __func__, __LINE__)) {
- /* We cannot ensure if EC has exited update mode.
- * If EC is in normal mode already, a further 0xFE
- * command will reboot system. So, exit loop here. */
- tries = MAX_TRY;
- break;
- }
-
- break;
- }
-
- if (tries < MAX_TRY) {
- data->it85xx_scratch_rom_reenter = 0;
- msg_pdbg("%s():%d * SUCCESS.\n", __func__, __LINE__);
- } else {
- msg_perr("%s():%d * Max try reached.\n", __func__, __LINE__);
- }
-
-#if 0
- /* FIXME: this a workaround for the bug that SMBus signal would
- * interfere the EC firmware update. Should be removed if
- * we find out the root cause. */
- ret = system("start powerd >&2");
- if (ret)
- msg_perr("Cannot start powerd again.\n");
-#endif
-}
-
-static int it85xx_shutdown(void *data)
-{
- msg_pdbg("%s():%d\n", __func__, __LINE__);
- it85xx_exit_scratch_rom(data);
- free(data);
-
- return 0; /* FIXME: Should probably return something meaningful */
-}
-
-/* According to ITE 8502 document, the procedure to follow mode is following:
- * 1. write 0x00 to LPC/FWH address 0xffff_fexxh (drive CE# high)
- * 2. write data to LPC/FWH address 0xffff_fdxxh (drive CE# low and MOSI
- * with data)
- * 3. read date from LPC/FWH address 0xffff_fdxxh (drive CE# low and get
- * data from MISO)
- */
-static int it85xx_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
-{
- unsigned int i;
- struct it85spi_data *data = flash->mst->spi.data;
-
- it85xx_enter_scratch_rom(data);
- /* Exit scratch ROM ONLY when programmer shuts down. Otherwise, the
- * temporary flash state may halt the EC.
- */
-
-#ifdef LPC_IO
- INDIRECT_A1(data->shm_io_base, (((unsigned long int)data->ce_high) >> 8) & 0xff);
- INDIRECT_WRITE(data->shm_io_base, 0xFF); /* Write anything to this address.*/
- INDIRECT_A1(data->shm_io_base, (((unsigned long int)data->ce_low) >> 8) & 0xff);
-#endif
-#ifdef LPC_MEMORY
- mmio_writeb(0, data->ce_high);
-#endif
- for (i = 0; i < writecnt; ++i) {
-#ifdef LPC_IO
- INDIRECT_WRITE(data->shm_io_base, writearr[i]);
-#endif
-#ifdef LPC_MEMORY
- mmio_writeb(writearr[i], data->ce_low);
-#endif
- }
- for (i = 0; i < readcnt; ++i) {
-#ifdef LPC_IO
- readarr[i] = INDIRECT_READ(data->shm_io_base);
-#endif
-#ifdef LPC_MEMORY
- readarr[i] = mmio_readb(data->ce_low);
-#endif
- }
-#ifdef LPC_IO
- INDIRECT_A1(data->shm_io_base, (((unsigned long int)data->ce_high) >> 8) & 0xff);
- INDIRECT_WRITE(data->shm_io_base, 0xFF); /* Write anything to this address.*/
-#endif
-#ifdef LPC_MEMORY
- mmio_writeb(0, data->ce_high);
-#endif
-
- return 0;
-}
-
-static struct spi_master spi_master_it85xx = {
- .max_data_read = 64,
- .max_data_write = 64,
- .command = it85xx_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
-};
-
-static int it85xx_spi_common_init(struct superio s)
-{
- chipaddr base;
-
- struct it85spi_data *data = calloc(1, sizeof(struct it85spi_data));
- if (!data) {
- msg_perr("Unable to allocate space for extra SPI master data.\n");
- return SPI_GENERIC_ERROR;
- }
-
- spi_master_it85xx.data = data;
-
- msg_pdbg("%s():%d superio.vendor=0x%02x\n", __func__, __LINE__,
- s.vendor);
-
- if (register_shutdown(it85xx_shutdown, data)) {
- free(data);
- return 1;
- }
-
-#ifdef LPC_IO
- /* Get LPCPNP of SHM. That's big-endian. */
- sio_write(s.port, LDNSEL, 0x0F); /* Set LDN to SHM (0x0F) */
- data->shm_io_base = (sio_read(s.port, SHM_IO_BAR0) << 8) +
- sio_read(s.port, SHM_IO_BAR1);
- msg_pdbg("%s():%d it85spi_data->shm_io_base=0x%04x\n", __func__, __LINE__,
- data->shm_io_base);
-
- /* These pointers are not used directly. They will be send to EC's
- * register for indirect access. */
- base = 0xFFFFF000;
- data->ce_high = ((unsigned char *)base) + 0xE00; /* 0xFFFFFE00 */
- data->ce_low = ((unsigned char *)base) + 0xD00; /* 0xFFFFFD00 */
-
- /* pre-set indirect-access registers since in most of cases they are
- * 0xFFFFxx00. */
- INDIRECT_A0(data->shm_io_base, base & 0xFF);
- INDIRECT_A2(data->shm_io_base, (base >> 16) & 0xFF);
- INDIRECT_A3(data->shm_io_base, (base >> 24));
-#endif
-#ifdef LPC_MEMORY
- /* FIXME: We should block accessing that region for anything else.
- * Major TODO here, and it will be a lot of work.
- */
- base = (chipaddr)physmap("it85 communication", 0xFFFFF000, 0x1000);
- if (base == (chipaddr)ERROR_PTR)
- return 1;
-
- msg_pdbg("%s():%d base=0x%08x\n", __func__, __LINE__,
- (unsigned int)base);
- data->ce_high = (unsigned char *)(base + 0xE00); /* 0xFFFFFE00 */
- data->ce_low = (unsigned char *)(base + 0xD00); /* 0xFFFFFD00 */
-#endif
-
- return 0;
-}
-
-int it85xx_spi_init(struct superio s)
-{
- int ret;
-
- if (!(internal_buses_supported & BUS_FWH)) {
- msg_pdbg("%s():%d buses not support FWH\n", __func__, __LINE__);
- return 1;
- }
- ret = it85xx_spi_common_init(s);
- msg_pdbg("FWH: %s():%d ret=%d\n", __func__, __LINE__, ret);
- if (!ret) {
- msg_pdbg("%s: internal_buses_supported=0x%x\n", __func__,
- internal_buses_supported);
- /* Check for FWH because IT85 listens to FWH cycles.
- * FIXME: The big question is whether FWH cycles are necessary
- * for communication even if LPC_IO is defined.
- */
- if (internal_buses_supported & BUS_FWH)
- msg_pdbg("Registering IT85 SPI.\n");
- /* FIXME: Really leave FWH enabled? We can't use this region
- * anymore since accessing it would mess up IT85 communication.
- * If we decide to disable FWH for this region, we should print
- * a debug message about it.
- */
- /* Set this as SPI controller. */
- register_spi_master(&spi_master_it85xx);
- }
- return ret;
-}
-
-#endif
diff --git a/it87spi.c b/it87spi.c
index 868b479a8..9c64659f1 100644
--- a/it87spi.c
+++ b/it87spi.c
@@ -19,15 +19,15 @@
* Contains the ITE IT87* SPI specific routines
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <errno.h>
#include "flash.h"
#include "chipdrivers.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "hwaccess_x86_io.h"
#include "spi.h"
#define ITE_SUPERIO_PORT1 0x2e
@@ -40,7 +40,7 @@
struct it8716f_spi_data {
uint16_t flashport;
/* use fast 33MHz SPI (<>0) or slow 16MHz (0) */
- int fast_spi;
+ bool fast_spi;
};
static int get_data_from_context(const struct flashctx *flash, struct it8716f_spi_data **data)
@@ -134,9 +134,20 @@ static int it8716f_spi_page_program(struct flashctx *flash, const uint8_t *buf,
OUTB(0, data->flashport);
/* Wait until the Write-In-Progress bit is cleared.
* This usually takes 1-10 ms, so wait in 1 ms steps.
+ *
+ * FIXME: This should timeout after some number of retries.
*/
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(1000);
+ while (true) {
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
+
+ if((status & SPI_SR_WIP) == 0)
+ return 0;
+
+ default_delay(1000);
+ }
return 0;
}
@@ -232,7 +243,7 @@ static int it8716f_spi_chip_read(struct flashctx *flash, uint8_t *buf,
if (get_data_from_context(flash, &data) < 0)
return SPI_GENERIC_ERROR;
- data->fast_spi = 0;
+ data->fast_spi = false;
/* FIXME: Check if someone explicitly requested to use IT87 SPI although
* the mainboard does not use IT87 SPI translation. This should be done
@@ -278,7 +289,10 @@ static int it8716f_spi_chip_write_256(struct flashctx *flash, const uint8_t *buf
}
while (len >= chip->page_size) {
- it8716f_spi_page_program(flash, buf, start);
+ int ret = it8716f_spi_page_program(flash, buf, start);
+ if (ret)
+ return ret;
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, chip->page_size - len, chip->page_size);
start += chip->page_size;
len -= chip->page_size;
buf += chip->page_size;
@@ -290,31 +304,32 @@ static int it8716f_spi_chip_write_256(struct flashctx *flash, const uint8_t *buf
return 0;
}
-static struct spi_master spi_master_it87xx = {
+static int it8716f_shutdown(void *data)
+{
+ free(data);
+ return 0;
+}
+
+static const struct spi_master spi_master_it87xx = {
.max_data_read = 3,
.max_data_write = MAX_DATA_UNSPECIFIED,
.command = it8716f_spi_send_command,
- .multicommand = default_spi_send_multicommand,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
.read = it8716f_spi_chip_read,
.write_256 = it8716f_spi_chip_write_256,
.write_aai = spi_chip_write_1,
+ .shutdown = it8716f_shutdown,
};
-
-static int it8716f_shutdown(void *data)
-{
- free(data);
- return 0;
-}
-
-static uint16_t it87spi_probe(uint16_t port)
+static uint16_t it87spi_probe(const struct programmer_cfg *cfg, uint16_t port)
{
uint8_t tmp = 0;
uint16_t flashport = 0;
enter_conf_mode_ite(port);
- char *param = extract_programmer_param("dualbiosindex");
+ char *param = extract_programmer_param_str(cfg, "dualbiosindex");
if (param != NULL) {
sio_write(port, 0x07, 0x07); /* Select GPIO LDN */
tmp = sio_read(port, 0xEF);
@@ -380,7 +395,7 @@ static uint16_t it87spi_probe(uint16_t port)
flashport |= sio_read(port, 0x65);
msg_pdbg("Serial flash port 0x%04x\n", flashport);
/* Non-default port requested? */
- param = extract_programmer_param("it87spiport");
+ param = extract_programmer_param_str(cfg, "it87spiport");
if (param) {
char *endptr = NULL;
unsigned long forced_flashport;
@@ -411,26 +426,22 @@ static uint16_t it87spi_probe(uint16_t port)
free(param);
exit_conf_mode_ite(port);
- struct it8716f_spi_data *data = calloc(1, sizeof(struct it8716f_spi_data));
+ struct it8716f_spi_data *data = calloc(1, sizeof(*data));
if (!data) {
msg_perr("Unable to allocate space for extra SPI master data.\n");
return SPI_GENERIC_ERROR;
}
data->flashport = flashport;
- data->fast_spi = 1;
- spi_master_it87xx.data = data;
-
- register_shutdown(it8716f_shutdown, data);
+ data->fast_spi = true;
if (internal_buses_supported & BUS_SPI)
msg_pdbg("Overriding chipset SPI with IT87 SPI.\n");
/* FIXME: Add the SPI bus or replace the other buses with it? */
- register_spi_master(&spi_master_it87xx);
- return 0;
+ return register_spi_master(&spi_master_it87xx, data);
}
-int init_superio_ite(void)
+int init_superio_ite(const struct programmer_cfg *cfg)
{
int i;
int ret = 0;
@@ -440,26 +451,15 @@ int init_superio_ite(void)
continue;
switch (superios[i].model) {
- case 0x8500:
- case 0x8502:
- case 0x8510:
- case 0x8511:
- case 0x8512:
- /* FIXME: This should be enabled, but we need a check
- * for laptop whitelisting due to the amount of things
- * which can go wrong if the EC firmware does not
- * implement the interface we want.
- */
- //it85xx_spi_init(superios[i]);
- break;
case 0x8705:
ret |= it8705f_write_enable(superios[i].port);
break;
+ case 0x8686:
case 0x8716:
case 0x8718:
case 0x8720:
case 0x8728:
- ret |= it87spi_probe(superios[i].port);
+ ret |= it87spi_probe(cfg, superios[i].port);
break;
default:
msg_pdbg2("Super I/O ID 0x%04hx is not on the list of flash-capable controllers.\n",
@@ -468,5 +468,3 @@ int init_superio_ite(void)
}
return ret;
}
-
-#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/jedec.c b/jedec.c
index 0709efa5e..2d18de7f3 100644
--- a/jedec.c
+++ b/jedec.c
@@ -38,14 +38,11 @@ uint8_t oddparity(uint8_t val)
static void toggle_ready_jedec_common(const struct flashctx *flash, chipaddr dst, unsigned int delay)
{
unsigned int i = 0;
- uint8_t tmp1, tmp2;
-
- tmp1 = chip_readb(flash, dst) & 0x40;
+ uint8_t tmp1 = chip_readb(flash, dst) & 0x40;
while (i++ < 0xFFFFFFF) {
- if (delay)
- programmer_delay(delay);
- tmp2 = chip_readb(flash, dst) & 0x40;
+ programmer_delay(flash, delay);
+ uint8_t tmp2 = chip_readb(flash, dst) & 0x40;
if (tmp1 == tmp2) {
break;
}
@@ -67,8 +64,9 @@ void toggle_ready_jedec(const struct flashctx *flash, chipaddr dst)
* Given that erase is slow on all chips, it is recommended to use
* toggle_ready_jedec_slow in erase functions.
*/
-static void toggle_ready_jedec_slow(const struct flashctx *flash, chipaddr dst)
+static void toggle_ready_jedec_slow(const struct flashctx *flash)
{
+ const chipaddr dst = flash->virtual_memory;
toggle_ready_jedec_common(flash, dst, 8 * 1000);
}
@@ -76,12 +74,11 @@ void data_polling_jedec(const struct flashctx *flash, chipaddr dst,
uint8_t data)
{
unsigned int i = 0;
- uint8_t tmp;
data &= 0x80;
while (i++ < 0xFFFFFFF) {
- tmp = chip_readb(flash, dst) & 0x80;
+ uint8_t tmp = chip_readb(flash, dst) & 0x80;
if (tmp == data) {
break;
}
@@ -109,10 +106,11 @@ static unsigned int getaddrmask(const struct flashchip *chip)
}
}
-static void start_program_jedec_common(const struct flashctx *flash, unsigned int mask)
+static void start_program_jedec_common(const struct flashctx *flash)
{
- chipaddr bios = flash->virtual_memory;
- bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
+ const chipaddr bios = flash->virtual_memory;
+ const bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
+ const unsigned int mask = getaddrmask(flash->chip);
chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
@@ -121,8 +119,8 @@ static void start_program_jedec_common(const struct flashctx *flash, unsigned in
int probe_jedec_29gl(struct flashctx *flash)
{
- unsigned int mask = getaddrmask(flash->chip);
- chipaddr bios = flash->virtual_memory;
+ const unsigned int mask = getaddrmask(flash->chip);
+ const chipaddr bios = flash->virtual_memory;
const struct flashchip *chip = flash->chip;
/* Reset chip to a clean slate */
@@ -143,7 +141,7 @@ int probe_jedec_29gl(struct flashctx *flash)
/* Issue JEDEC Product ID Exit command */
chip_writeb(flash, 0xF0, bios + (0x5555 & mask));
- msg_cdbg("%s: man_id 0x%02x, dev_id 0x%06x", __func__, man_id, dev_id);
+ msg_cdbg("%s: man_id 0x%02"PRIx32", dev_id 0x%06"PRIx32"", __func__, man_id, dev_id);
if (!oddparity(man_id))
msg_cdbg(", man_id parity violation");
@@ -165,59 +163,64 @@ int probe_jedec_29gl(struct flashctx *flash)
return 1;
}
-static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
+static int probe_timings(const struct flashchip *chip, unsigned int *tenter, unsigned int *texit)
{
- chipaddr bios = flash->virtual_memory;
+ if (chip->probe_timing > 0) {
+ *tenter = *texit = chip->probe_timing;
+ } else if (chip->probe_timing == TIMING_ZERO) { /* No delay. */
+ *tenter = *texit = 0;
+ } else if (chip->probe_timing == TIMING_FIXME) { /* == _IGNORED */
+ msg_cdbg("Chip lacks correct probe timing information, using default 10ms/40us. ");
+ *tenter = 10000;
+ *texit = 40;
+ } else {
+ msg_cerr("Chip has negative value in probe_timing, failing without chip access\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int probe_jedec(struct flashctx *flash)
+{
+ const chipaddr bios = flash->virtual_memory;
const struct flashchip *chip = flash->chip;
- bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
+ const bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
+ const unsigned int mask = getaddrmask(flash->chip);
uint8_t id1, id2;
uint32_t largeid1, largeid2;
uint32_t flashcontent1, flashcontent2;
unsigned int probe_timing_enter, probe_timing_exit;
- if (chip->probe_timing > 0)
- probe_timing_enter = probe_timing_exit = chip->probe_timing;
- else if (chip->probe_timing == TIMING_ZERO) { /* No delay. */
- probe_timing_enter = probe_timing_exit = 0;
- } else if (chip->probe_timing == TIMING_FIXME) { /* == _IGNORED */
- msg_cdbg("Chip lacks correct probe timing information, using default 10ms/40us. ");
- probe_timing_enter = 10000;
- probe_timing_exit = 40;
- } else {
- msg_cerr("Chip has negative value in probe_timing, failing without chip access\n");
+ if (probe_timings(chip, &probe_timing_enter, &probe_timing_exit) < 0)
return 0;
- }
/* Earlier probes might have been too fast for the chip to enter ID
* mode completely. Allow the chip to finish this before seeing a
* reset command.
*/
- if (probe_timing_enter)
- programmer_delay(probe_timing_enter);
+ programmer_delay(flash, probe_timing_enter);
/* Reset chip to a clean slate */
- if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
- {
+ if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET) {
chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
if (probe_timing_exit)
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
if (probe_timing_exit)
- programmer_delay(10);
+ programmer_delay(flash, 10);
}
chip_writeb(flash, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- if (probe_timing_exit)
- programmer_delay(probe_timing_exit);
+ programmer_delay(flash, probe_timing_exit);
/* Issue JEDEC Product ID Entry command */
chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
if (probe_timing_enter)
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
if (probe_timing_enter)
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0x90, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- if (probe_timing_enter)
- programmer_delay(probe_timing_enter);
+ programmer_delay(flash, probe_timing_enter);
/* Read product ID */
id1 = chip_readb(flash, bios + (0x00 << shifted));
@@ -238,20 +241,18 @@ static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
}
/* Issue JEDEC Product ID Exit command */
- if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET)
- {
+ if ((chip->feature_bits & FEATURE_RESET_MASK) == FEATURE_LONG_RESET) {
chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
if (probe_timing_exit)
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
if (probe_timing_exit)
- programmer_delay(10);
+ programmer_delay(flash, 10);
}
chip_writeb(flash, 0xF0, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- if (probe_timing_exit)
- programmer_delay(probe_timing_exit);
+ programmer_delay(flash, probe_timing_exit);
- msg_cdbg("%s: id1 0x%02x, id2 0x%02x", __func__, largeid1, largeid2);
+ msg_cdbg("%s: id1 0x%02"PRIx32", id2 0x%02"PRIx32"", __func__, largeid1, largeid2);
if (!oddparity(id1))
msg_cdbg(", id1 parity violation");
@@ -281,146 +282,107 @@ static int probe_jedec_common(struct flashctx *flash, unsigned int mask)
return 1;
}
-static int erase_sector_jedec_common(struct flashctx *flash, unsigned int page,
- unsigned int pagesize, unsigned int mask)
+static void issuecmd(const struct flashctx *flash, uint8_t op, unsigned int operand)
{
- chipaddr bios = flash->virtual_memory;
+ const chipaddr bios = flash->virtual_memory;
bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
- unsigned int delay_us = 0;
+ const unsigned int mask = getaddrmask(flash->chip);
+ unsigned int delay_us = (flash->chip->probe_timing == TIMING_ZERO) ? 0 : 10;
- if(flash->chip->probe_timing != TIMING_ZERO)
- delay_us = 10;
+ if (!operand)
+ operand = (shifted ? 0x2AAA : 0x5555) & mask;
- /* Issue the Sector Erase command */
chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
+ programmer_delay(flash, delay_us);
chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x80, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
+ programmer_delay(flash, delay_us);
+ chip_writeb(flash, op, bios + operand);
+ programmer_delay(flash, delay_us);
+}
- chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x30, bios + page);
- programmer_delay(delay_us);
+int erase_sector_jedec(struct flashctx *flash, unsigned int page, unsigned int size)
+{
+ /* Issue the Sector Erase command */
+ issuecmd(flash, 0x80, 0);
+ issuecmd(flash, 0x30, page);
- /* wait for Toggle bit ready */
- toggle_ready_jedec_slow(flash, bios);
+ /* Wait for Toggle bit ready */
+ toggle_ready_jedec_slow(flash);
/* FIXME: Check the status register for errors. */
return 0;
}
-static int erase_block_jedec_common(struct flashctx *flash, unsigned int block,
- unsigned int blocksize, unsigned int mask)
+int erase_block_jedec(struct flashctx *flash, unsigned int block, unsigned int size)
{
- chipaddr bios = flash->virtual_memory;
- bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
- unsigned int delay_us = 0;
-
- if(flash->chip->probe_timing != TIMING_ZERO)
- delay_us = 10;
+ /* Issue the Block Erase command */
+ issuecmd(flash, 0x80, 0);
+ issuecmd(flash, 0x50, block);
- /* Issue the Sector Erase command */
- chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x80, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
-
- chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x50, bios + block);
- programmer_delay(delay_us);
-
- /* wait for Toggle bit ready */
- toggle_ready_jedec_slow(flash, bios);
+ /* Wait for Toggle bit ready */
+ toggle_ready_jedec_slow(flash);
/* FIXME: Check the status register for errors. */
return 0;
}
-static int erase_chip_jedec_common(struct flashctx *flash, unsigned int mask)
+/* erase chip with block_erase() prototype */
+int erase_chip_block_jedec(struct flashctx *flash, unsigned int addr, unsigned int blocksize)
{
- chipaddr bios = flash->virtual_memory;
- bool shifted = (flash->chip->feature_bits & FEATURE_ADDR_SHIFTED);
- unsigned int delay_us = 0;
-
- if(flash->chip->probe_timing != TIMING_ZERO)
- delay_us = 10;
-
- /* Issue the JEDEC Chip Erase command */
- chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x80, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
+ if ((addr != 0) || (blocksize != flash->chip->total_size * 1024)) {
+ msg_cerr("%s called with incorrect arguments\n", __func__);
+ return -1;
+ }
- chip_writeb(flash, 0xAA, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x55, bios + ((shifted ? 0x5555 : 0x2AAA) & mask));
- programmer_delay(delay_us);
- chip_writeb(flash, 0x10, bios + ((shifted ? 0x2AAA : 0x5555) & mask));
- programmer_delay(delay_us);
+ /* Issue the JEDEC Chip Erase command */
+ issuecmd(flash, 0x80, 0);
+ issuecmd(flash, 0x10, 0);
- toggle_ready_jedec_slow(flash, bios);
+ toggle_ready_jedec_slow(flash);
/* FIXME: Check the status register for errors. */
return 0;
}
static int write_byte_program_jedec_common(const struct flashctx *flash, const uint8_t *src,
- chipaddr dst, unsigned int mask)
+ chipaddr dst)
{
- int tried = 0, failed = 0;
- chipaddr bios = flash->virtual_memory;
+ int tries = 0;
/* If the data is 0xFF, don't program it and don't complain. */
if (*src == 0xFF) {
return 0;
}
-retry:
- /* Issue JEDEC Byte Program command */
- start_program_jedec_common(flash, mask);
+ for (; tries < MAX_REFLASH_TRIES; tries++) {
+ const chipaddr bios = flash->virtual_memory;
+ /* Issue JEDEC Byte Program command */
+ start_program_jedec_common(flash);
- /* transfer data from source to destination */
- chip_writeb(flash, *src, dst);
- toggle_ready_jedec(flash, bios);
+ /* transfer data from source to destination */
+ chip_writeb(flash, *src, dst);
+ toggle_ready_jedec(flash, bios);
- if (chip_readb(flash, dst) != *src && tried++ < MAX_REFLASH_TRIES) {
- goto retry;
+ if (chip_readb(flash, dst) == *src)
+ break;
}
- if (tried >= MAX_REFLASH_TRIES)
- failed = 1;
-
- return failed;
+ return (tries >= MAX_REFLASH_TRIES) ? 1 : 0;
}
/* chunksize is 1 */
int write_jedec_1(struct flashctx *flash, const uint8_t *src, unsigned int start,
unsigned int len)
{
- unsigned int i;
int failed = 0;
chipaddr dst = flash->virtual_memory + start;
- chipaddr olddst;
- unsigned int mask;
-
- mask = getaddrmask(flash->chip);
+ const chipaddr olddst = dst;
- olddst = dst;
- for (i = 0; i < len; i++) {
- if (write_byte_program_jedec_common(flash, src, dst, mask))
+ for (unsigned int i = 0; i < len; i++) {
+ if (write_byte_program_jedec_common(flash, src, dst))
failed = 1;
dst++, src++;
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, len);
}
if (failed)
msg_cerr(" writing sector at 0x%" PRIxPTR " failed!\n", olddst);
@@ -428,45 +390,43 @@ int write_jedec_1(struct flashctx *flash, const uint8_t *src, unsigned int start
return failed;
}
-static int write_page_write_jedec_common(struct flashctx *flash, const uint8_t *src,
+static int jedec_write_page(struct flashctx *flash, const uint8_t *src,
unsigned int start, unsigned int page_size)
{
- unsigned int i;
- int tried = 0, failed;
+ int tries = 0, failed;
const uint8_t *s = src;
- chipaddr bios = flash->virtual_memory;
+ const chipaddr bios = flash->virtual_memory;
chipaddr dst = bios + start;
chipaddr d = dst;
- unsigned int mask;
-
- mask = getaddrmask(flash->chip);
-retry:
- /* Issue JEDEC Start Program command */
- start_program_jedec_common(flash, mask);
-
- /* transfer data from source to destination */
- for (i = 0; i < page_size; i++) {
- /* If the data is 0xFF, don't program it */
- if (*src != 0xFF)
- chip_writeb(flash, *src, dst);
- dst++;
- src++;
- }
+ for (; tries < MAX_REFLASH_TRIES; tries++) {
+ /* Issue JEDEC Start Program command */
+ start_program_jedec_common(flash);
+
+ /* transfer data from source to destination */
+ for (unsigned int i = 0; i < page_size; i++) {
+ /* If the data is 0xFF, don't program it */
+ if (*src != 0xFF)
+ chip_writeb(flash, *src, dst);
+ dst++;
+ src++;
+ }
- toggle_ready_jedec(flash, dst - 1);
+ toggle_ready_jedec(flash, dst - 1);
- dst = d;
- src = s;
- failed = verify_range(flash, src, start, page_size);
+ dst = d;
+ src = s;
+ failed = verify_range(flash, src, start, page_size);
+ if (!failed)
+ break;
- if (failed && tried++ < MAX_REFLASH_TRIES) {
msg_cerr("retrying.\n");
- goto retry;
}
+
if (failed) {
msg_cerr(" page 0x%" PRIxPTR " failed!\n", (d - bios) / page_size);
}
+
return failed;
}
@@ -480,13 +440,14 @@ retry:
int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start,
int unsigned len)
{
- unsigned int i, starthere, lenhere;
+ unsigned int starthere, lenhere;
/* FIXME: page_size is the wrong variable. We need max_writechunk_size
* in struct flashctx to do this properly. All chips using
* write_jedec have page_size set to max_writechunk_size, so
* we're OK for now.
*/
- unsigned int page_size = flash->chip->page_size;
+ const unsigned int page_size = flash->chip->page_size;
+ const unsigned int nwrites = (start + len - 1) / page_size;
/* Warning: This loop has a very unusual condition and body.
* The loop needs to go through each page with at least one affected
@@ -497,246 +458,17 @@ int write_jedec(struct flashctx *flash, const uint8_t *buf, unsigned int start,
* (start + len - 1) / page_size. Since we want to include that last
* page as well, the loop condition uses <=.
*/
- for (i = start / page_size; i <= (start + len - 1) / page_size; i++) {
+ for (unsigned int i = start / page_size; i <= nwrites; i++) {
/* Byte position of the first byte in the range in this page. */
/* starthere is an offset to the base address of the chip. */
starthere = max(start, i * page_size);
/* Length of bytes in the range in this page. */
lenhere = min(start + len, (i + 1) * page_size) - starthere;
- if (write_page_write_jedec_common(flash, buf + starthere - start, starthere, lenhere))
+ if (jedec_write_page(flash, buf + starthere - start, starthere, lenhere))
return 1;
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, nwrites + 1);
}
return 0;
}
-
-/* erase chip with block_erase() prototype */
-int erase_chip_block_jedec(struct flashctx *flash, unsigned int addr,
- unsigned int blocksize)
-{
- unsigned int mask;
-
- mask = getaddrmask(flash->chip);
- if ((addr != 0) || (blocksize != flash->chip->total_size * 1024)) {
- msg_cerr("%s called with incorrect arguments\n",
- __func__);
- return -1;
- }
- return erase_chip_jedec_common(flash, mask);
-}
-
-int probe_jedec(struct flashctx *flash)
-{
- unsigned int mask;
-
- mask = getaddrmask(flash->chip);
- return probe_jedec_common(flash, mask);
-}
-
-int erase_sector_jedec(struct flashctx *flash, unsigned int page,
- unsigned int size)
-{
- unsigned int mask;
-
- mask = getaddrmask(flash->chip);
- return erase_sector_jedec_common(flash, page, size, mask);
-}
-
-int erase_block_jedec(struct flashctx *flash, unsigned int page,
- unsigned int size)
-{
- unsigned int mask;
-
- mask = getaddrmask(flash->chip);
- return erase_block_jedec_common(flash, page, size, mask);
-}
-
-struct unlockblock {
- unsigned int size;
- unsigned int count;
-};
-
-typedef int (*unlockblock_func)(const struct flashctx *flash, chipaddr offset);
-static int regspace2_walk_unlockblocks(const struct flashctx *flash, const struct unlockblock *block, unlockblock_func func)
-{
- chipaddr off = flash->virtual_registers + 2;
- while (block->count != 0) {
- unsigned int j;
- for (j = 0; j < block->count; j++) {
- if (func(flash, off))
- return -1;
- off += block->size;
- }
- block++;
- }
- return 0;
-}
-
-#define REG2_RWLOCK ((1 << 2) | (1 << 0))
-#define REG2_LOCKDOWN (1 << 1)
-#define REG2_MASK (REG2_RWLOCK | REG2_LOCKDOWN)
-
-static int printlock_regspace2_block(const struct flashctx *flash, chipaddr lockreg)
-{
- uint8_t state = chip_readb(flash, lockreg);
- msg_cdbg("Lock status of block at 0x%0*" PRIxPTR " is ", PRIxPTR_WIDTH, lockreg);
- switch (state & REG2_MASK) {
- case 0:
- msg_cdbg("Full Access.\n");
- break;
- case 1:
- msg_cdbg("Write Lock (Default State).\n");
- break;
- case 2:
- msg_cdbg("Locked Open (Full Access, Locked Down).\n");
- break;
- case 3:
- msg_cdbg("Write Lock, Locked Down.\n");
- break;
- case 4:
- msg_cdbg("Read Lock.\n");
- break;
- case 5:
- msg_cdbg("Read/Write Lock.\n");
- break;
- case 6:
- msg_cdbg("Read Lock, Locked Down.\n");
- break;
- case 7:
- msg_cdbg("Read/Write Lock, Locked Down.\n");
- break;
- }
- return 0;
-}
-
-static int printlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
-{
- const unsigned int elems = flash->chip->total_size * 1024 / block_size;
- struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
- return regspace2_walk_unlockblocks(flash, blocks, &printlock_regspace2_block);
-}
-
-int printlock_regspace2_uniform_64k(struct flashctx *flash)
-{
- return printlock_regspace2_uniform(flash, 64 * 1024);
-}
-
-int printlock_regspace2_block_eraser_0(struct flashctx *flash)
-{
- // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
- const struct unlockblock *unlockblocks =
- (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
- return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
-}
-
-int printlock_regspace2_block_eraser_1(struct flashctx *flash)
-{
- // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
- const struct unlockblock *unlockblocks =
- (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
- return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
-}
-
-/* Try to change the lock register at address lockreg from cur to new.
- *
- * - Try to unlock the lock bit if requested and it is currently set (although this is probably futile).
- * - Try to change the read/write bits if requested.
- * - Try to set the lockdown bit if requested.
- * Return an error immediately if any of this fails. */
-static int changelock_regspace2_block(const struct flashctx *flash, chipaddr lockreg, uint8_t cur, uint8_t new)
-{
- /* Only allow changes to known read/write/lockdown bits */
- if (((cur ^ new) & ~REG2_MASK) != 0) {
- msg_cerr("Invalid lock change from 0x%02x to 0x%02x requested at 0x%0*" PRIxPTR "!\n"
- "Please report a bug at flashrom@flashrom.org\n",
- cur, new, PRIxPTR_WIDTH, lockreg);
- return -1;
- }
-
- /* Exit early if no change (of read/write/lockdown bits) was requested. */
- if (((cur ^ new) & REG2_MASK) == 0) {
- msg_cdbg2("Lock bits at 0x%0*" PRIxPTR " not changed.\n", PRIxPTR_WIDTH, lockreg);
- return 0;
- }
-
- /* Normally the lockdown bit can not be cleared. Try nevertheless if requested. */
- if ((cur & REG2_LOCKDOWN) && !(new & REG2_LOCKDOWN)) {
- chip_writeb(flash, cur & ~REG2_LOCKDOWN, lockreg);
- cur = chip_readb(flash, lockreg);
- if ((cur & REG2_LOCKDOWN) == REG2_LOCKDOWN) {
- msg_cwarn("Lockdown can't be removed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
- PRIxPTR_WIDTH, lockreg, cur);
- return -1;
- }
- }
-
- /* Change read and/or write bit */
- if ((cur ^ new) & REG2_RWLOCK) {
- /* Do not lockdown yet. */
- uint8_t wanted = (cur & ~REG2_RWLOCK) | (new & REG2_RWLOCK);
- chip_writeb(flash, wanted, lockreg);
- cur = chip_readb(flash, lockreg);
- if (cur != wanted) {
- msg_cerr("Changing lock bits failed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
- PRIxPTR_WIDTH, lockreg, cur);
- return -1;
- }
- msg_cdbg("Changed lock bits at 0x%0*" PRIxPTR " to 0x%02x.\n",
- PRIxPTR_WIDTH, lockreg, cur);
- }
-
- /* Eventually, enable lockdown if requested. */
- if (!(cur & REG2_LOCKDOWN) && (new & REG2_LOCKDOWN)) {
- chip_writeb(flash, new, lockreg);
- cur = chip_readb(flash, lockreg);
- if (cur != new) {
- msg_cerr("Enabling lockdown FAILED at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
- PRIxPTR_WIDTH, lockreg, cur);
- return -1;
- }
- msg_cdbg("Enabled lockdown at 0x%0*" PRIxPTR ".\n", PRIxPTR_WIDTH, lockreg);
- }
-
- return 0;
-}
-
-static int unlock_regspace2_block_generic(const struct flashctx *flash, chipaddr lockreg)
-{
- uint8_t old = chip_readb(flash, lockreg);
- /* We don't care for the lockdown bit as long as the RW locks are 0 after we're done */
- return changelock_regspace2_block(flash, lockreg, old, old & ~REG2_RWLOCK);
-}
-
-static int unlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
-{
- const unsigned int elems = flash->chip->total_size * 1024 / block_size;
- struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
- return regspace2_walk_unlockblocks(flash, blocks, &unlock_regspace2_block_generic);
-}
-
-int unlock_regspace2_uniform_64k(struct flashctx *flash)
-{
- return unlock_regspace2_uniform(flash, 64 * 1024);
-}
-
-int unlock_regspace2_uniform_32k(struct flashctx *flash)
-{
- return unlock_regspace2_uniform(flash, 32 * 1024);
-}
-
-int unlock_regspace2_block_eraser_0(struct flashctx *flash)
-{
- // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
- const struct unlockblock *unlockblocks =
- (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
- return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
-}
-
-int unlock_regspace2_block_eraser_1(struct flashctx *flash)
-{
- // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
- const struct unlockblock *unlockblocks =
- (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
- return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
-}
diff --git a/jlink_spi.c b/jlink_spi.c
index 36611bf04..447629cce 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
@@ -51,51 +51,74 @@
/* Minimum target voltage required for operation in mV. */
#define MIN_TARGET_VOLTAGE 1200
-static struct jaylink_context *jaylink_ctx;
-static struct jaylink_device_handle *jaylink_devh;
-static bool reset_cs;
+enum cs_wiring {
+ CS_RESET, /* nCS is wired to nRESET(pin 15) */
+ CS_TRST, /* nCS is wired to nTRST(pin 3) */
+ CS_TMS, /* nCS is wired to TMS/nCS(pin 7) */
+};
+
+struct jlink_spi_data {
+ struct jaylink_context *ctx;
+ struct jaylink_device_handle *devh;
+ enum cs_wiring cs;
+ bool enable_target_power;
+};
-static bool assert_cs(void)
+static bool assert_cs(struct jlink_spi_data *jlink_data)
{
int ret;
- if (reset_cs) {
- ret = jaylink_clear_reset(jaylink_devh);
+ if (jlink_data->cs == CS_RESET) {
+ ret = jaylink_clear_reset(jlink_data->devh);
if (ret != JAYLINK_OK) {
msg_perr("jaylink_clear_reset() failed: %s.\n", jaylink_strerror(ret));
return false;
}
- } else {
- ret = jaylink_jtag_clear_trst(jaylink_devh);
+ } else if (jlink_data->cs == CS_TRST) {
+ ret = jaylink_jtag_clear_trst(jlink_data->devh);
if (ret != JAYLINK_OK) {
msg_perr("jaylink_jtag_clear_trst() failed: %s.\n", jaylink_strerror(ret));
return false;
}
+ } else {
+ ret = jaylink_jtag_clear_tms(jlink_data->devh);
+
+ if (ret != JAYLINK_OK) {
+ msg_perr("jaylink_jtag_clear_tms() failed: %s.\n", jaylink_strerror(ret));
+ return false;
+ }
}
return true;
}
-static bool deassert_cs(void)
+static bool deassert_cs(struct jlink_spi_data *jlink_data)
{
int ret;
- if (reset_cs) {
- ret = jaylink_set_reset(jaylink_devh);
+ if (jlink_data->cs == CS_RESET) {
+ ret = jaylink_set_reset(jlink_data->devh);
if (ret != JAYLINK_OK) {
msg_perr("jaylink_set_reset() failed: %s.\n", jaylink_strerror(ret));
return false;
}
- } else {
- ret = jaylink_jtag_set_trst(jaylink_devh);
+ } else if (jlink_data->cs == CS_TRST) {
+ ret = jaylink_jtag_set_trst(jlink_data->devh);
if (ret != JAYLINK_OK) {
msg_perr("jaylink_jtag_set_trst() failed: %s.\n", jaylink_strerror(ret));
return false;
}
+ } else {
+ ret = jaylink_jtag_set_tms(jlink_data->devh);
+
+ if (ret != JAYLINK_OK) {
+ msg_perr("jaylink_jtag_set_tms() failed: %s.\n", jaylink_strerror(ret));
+ return false;
+ }
}
return true;
@@ -106,6 +129,8 @@ static int jlink_spi_send_command(const struct flashctx *flash, unsigned int wri
{
uint32_t length;
uint8_t *buffer;
+ static const uint8_t zeros[JTAG_MAX_TRANSFER_SIZE] = {0};
+ struct jlink_spi_data *jlink_data = flash->mst->spi.data;
length = writecnt + readcnt;
@@ -124,22 +149,26 @@ static int jlink_spi_send_command(const struct flashctx *flash, unsigned int wri
memset(buffer + writecnt, 0x00, readcnt);
- if (!assert_cs()) {
+ if (!assert_cs(jlink_data)) {
free(buffer);
return SPI_PROGRAMMER_ERROR;
}
+ /* If CS is wired to TMS, TMS should remain zero. */
+ const uint8_t *tms_buffer = jlink_data->cs == CS_TMS ? zeros : buffer;
+
int ret;
- ret = jaylink_jtag_io(jaylink_devh, buffer, buffer, buffer, length * 8, JAYLINK_JTAG_VERSION_2);
+ ret = jaylink_jtag_io(jlink_data->devh,
+ tms_buffer, buffer, buffer, length * 8, JAYLINK_JTAG_VERSION_2);
if (ret != JAYLINK_OK) {
- msg_perr("jaylink_jag_io() failed: %s.\n", jaylink_strerror(ret));
+ msg_perr("jaylink_jtag_io() failed: %s.\n", jaylink_strerror(ret));
free(buffer);
return SPI_PROGRAMMER_ERROR;
}
- if (!deassert_cs()) {
+ if (!deassert_cs(jlink_data)) {
free(buffer);
return SPI_PROGRAMMER_ERROR;
}
@@ -151,37 +180,51 @@ static int jlink_spi_send_command(const struct flashctx *flash, unsigned int wri
return 0;
}
+static int jlink_spi_shutdown(void *data)
+{
+ struct jlink_spi_data *jlink_data = data;
+
+ if (jlink_data->enable_target_power) {
+ int ret = jaylink_set_target_power(jlink_data->devh, false);
+
+ if (ret != JAYLINK_OK) {
+ msg_perr("jaylink_set_target_power() failed: %s.\n",
+ jaylink_strerror(ret));
+ }
+ }
+
+ if (jlink_data->devh)
+ jaylink_close(jlink_data->devh);
+
+ jaylink_exit(jlink_data->ctx);
+ /* jlink_data->ctx, jlink_data->devh are freed by jaylink_close and jaylink_exit */
+ free(jlink_data);
+ return 0;
+}
+
static const struct spi_master spi_master_jlink_spi = {
/* Maximum data read size in one go (excluding opcode+address). */
.max_data_read = JTAG_MAX_TRANSFER_SIZE - 5,
/* Maximum data write size in one go (excluding opcode+address). */
.max_data_write = JTAG_MAX_TRANSFER_SIZE - 5,
.command = jlink_spi_send_command,
- .multicommand = default_spi_send_multicommand,
.read = default_spi_read,
.write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
.features = SPI_MASTER_4BA,
+ .shutdown = jlink_spi_shutdown,
};
-static int jlink_spi_shutdown(void *data)
-{
- if (jaylink_devh)
- jaylink_close(jaylink_devh);
-
- jaylink_exit(jaylink_ctx);
-
- return 0;
-}
-
-int jlink_spi_init(void)
+static int jlink_spi_init(const struct programmer_cfg *cfg)
{
char *arg;
unsigned long speed = 0;
+ struct jaylink_context *jaylink_ctx = NULL;
+ struct jaylink_device_handle *jaylink_devh = NULL;
+ enum cs_wiring cs;
+ struct jlink_spi_data *jlink_data = NULL;
+ bool enable_target_power;
- register_shutdown(jlink_spi_shutdown, NULL);
-
- arg = extract_programmer_param("spispeed");
+ arg = extract_programmer_param_str(cfg, "spispeed");
if (arg) {
char *endptr;
@@ -208,11 +251,11 @@ int jlink_spi_init(void)
bool use_serial_number;
uint32_t serial_number;
- arg = extract_programmer_param("serial");
+ arg = extract_programmer_param_str(cfg, "serial");
if (arg) {
if (!strlen(arg)) {
- msg_perr("Emptpy serial number specified.\n");
+ msg_perr("Empty serial number specified.\n");
free(arg);
return 1;
}
@@ -236,14 +279,16 @@ int jlink_spi_init(void)
free(arg);
- reset_cs = true;
- arg = extract_programmer_param("cs");
+ cs = CS_RESET;
+ arg = extract_programmer_param_str(cfg, "cs");
if (arg) {
if (!strcasecmp(arg, "reset")) {
- reset_cs = true;
+ cs = CS_RESET;
} else if (!strcasecmp(arg, "trst")) {
- reset_cs = false;
+ cs = CS_TRST;
+ } else if (!strcasecmp(arg, "tms")) {
+ cs = CS_TMS;
} else {
msg_perr("Invalid chip select pin specified: '%s'.\n", arg);
free(arg);
@@ -253,10 +298,27 @@ int jlink_spi_init(void)
free(arg);
- if (reset_cs)
+ if (cs == CS_RESET)
msg_pdbg("Using RESET as chip select signal.\n");
- else
+ else if (cs == CS_TRST)
msg_pdbg("Using TRST as chip select signal.\n");
+ else
+ msg_pdbg("Using TMS/CS as chip select signal.\n");
+
+ enable_target_power = false;
+ arg = extract_programmer_param_str(cfg, "power");
+
+ if (arg) {
+ if (!strcasecmp(arg, "on")) {
+ enable_target_power = true;
+ } else {
+ msg_perr("Invalid value for 'power' argument: '%s'.\n", arg);
+ free(arg);
+ return 1;
+ }
+ }
+
+ free(arg);
ret = jaylink_init(&jaylink_ctx);
@@ -268,8 +330,8 @@ int jlink_spi_init(void)
ret = jaylink_discovery_scan(jaylink_ctx, 0);
if (ret != JAYLINK_OK) {
- msg_perr("jaylink_discover_scan() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ msg_perr("jaylink_discovery_scan() failed: %s.\n", jaylink_strerror(ret));
+ goto init_err;
}
struct jaylink_device **devs;
@@ -278,7 +340,7 @@ int jlink_spi_init(void)
if (ret != JAYLINK_OK) {
msg_perr("jaylink_get_devices() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ goto init_err;
}
if (!use_serial_number)
@@ -321,7 +383,7 @@ int jlink_spi_init(void)
if (!device_found) {
msg_perr("No J-Link device found.\n");
- return 1;
+ goto init_err;
}
size_t length;
@@ -332,7 +394,7 @@ int jlink_spi_init(void)
if (ret != JAYLINK_OK) {
msg_perr("jaylink_get_firmware_version() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ goto init_err;
} else if (length > 0) {
msg_pdbg("Firmware: %s\n", firmware_version);
free(firmware_version);
@@ -346,25 +408,31 @@ int jlink_spi_init(void)
msg_pdbg("S/N: N/A\n");
} else {
msg_perr("jaylink_device_get_serial_number() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ goto init_err;
}
- uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE];
+ uint8_t caps[JAYLINK_DEV_EXT_CAPS_SIZE] = { 0 };
- memset(caps, 0, sizeof(caps));
ret = jaylink_get_caps(jaylink_devh, caps);
if (ret != JAYLINK_OK) {
msg_perr("jaylink_get_caps() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ goto init_err;
}
if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_GET_EXT_CAPS)) {
ret = jaylink_get_extended_caps(jaylink_devh, caps);
if (ret != JAYLINK_OK) {
- msg_perr("jaylink_get_available_interfaces() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ msg_perr("jaylink_get_extended_caps() failed: %s.\n", jaylink_strerror(ret));
+ goto init_err;
+ }
+ }
+
+ if (enable_target_power) {
+ if (!jaylink_has_cap(caps, JAYLINK_DEV_CAP_SET_TARGET_POWER)) {
+ msg_perr("Device does not support target power.\n");
+ goto init_err;
}
}
@@ -374,19 +442,31 @@ int jlink_spi_init(void)
if (ret != JAYLINK_OK) {
msg_perr("jaylink_get_available_interfaces() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ goto init_err;
}
if (!(ifaces & (1 << JAYLINK_TIF_JTAG))) {
msg_perr("Device does not support JTAG interface.\n");
- return 1;
+ goto init_err;
}
ret = jaylink_select_interface(jaylink_devh, JAYLINK_TIF_JTAG, NULL);
if (ret != JAYLINK_OK) {
msg_perr("jaylink_select_interface() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ goto init_err;
+ }
+
+ if (enable_target_power) {
+ ret = jaylink_set_target_power(jaylink_devh, true);
+
+ if (ret != JAYLINK_OK) {
+ msg_perr("jaylink_set_target_power() failed: %s.\n", jaylink_strerror(ret));
+ goto init_err;
+ }
+
+ /* Wait some time until the target is powered up. */
+ internal_sleep(10000);
}
struct jaylink_hardware_status hwstat;
@@ -395,7 +475,7 @@ int jlink_spi_init(void)
if (ret != JAYLINK_OK) {
msg_perr("jaylink_get_hardware_status() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ goto init_err;
}
msg_pdbg("VTarget: %u.%03u V\n", hwstat.target_voltage / 1000,
@@ -404,7 +484,7 @@ int jlink_spi_init(void)
if (hwstat.target_voltage < MIN_TARGET_VOLTAGE) {
msg_perr("Target voltage is below %u.%03u V. You need to attach VTref to the I/O voltage of "
"the chip.\n", MIN_TARGET_VOLTAGE / 1000, MIN_TARGET_VOLTAGE % 1000);
- return 1;
+ goto init_err;
}
struct jaylink_speed device_speeds;
@@ -417,7 +497,7 @@ int jlink_spi_init(void)
if (ret != JAYLINK_OK) {
msg_perr("jaylink_get_speeds() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ goto init_err;
}
}
@@ -433,23 +513,52 @@ int jlink_spi_init(void)
if (speed > (device_speeds.freq / device_speeds.div)) {
msg_perr("Specified SPI speed of %lu kHz is too high. Maximum is %" PRIu32 " kHz.\n", speed,
device_speeds.freq / device_speeds.div);
- return 1;
+ goto init_err;
}
ret = jaylink_set_speed(jaylink_devh, speed);
if (ret != JAYLINK_OK) {
msg_perr("jaylink_set_speed() failed: %s.\n", jaylink_strerror(ret));
- return 1;
+ goto init_err;
}
msg_pdbg("SPI speed: %lu kHz\n", speed);
+ jlink_data = calloc(1, sizeof(*jlink_data));
+ if (!jlink_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ goto init_err;
+ }
+
+ /* jaylink_ctx, jaylink_devh are allocated by jaylink_init and jaylink_open */
+ jlink_data->ctx = jaylink_ctx;
+ jlink_data->devh = jaylink_devh;
+ jlink_data->cs = cs;
+ jlink_data->enable_target_power = enable_target_power;
+
/* Ensure that the CS signal is not active initially. */
- if (!deassert_cs())
- return 1;
+ if (!deassert_cs(jlink_data))
+ goto init_err;
- register_spi_master(&spi_master_jlink_spi);
+ return register_spi_master(&spi_master_jlink_spi, jlink_data);
- return 0;
+init_err:
+ if (jaylink_devh)
+ jaylink_close(jaylink_devh);
+
+ jaylink_exit(jaylink_ctx);
+
+ /* jaylink_ctx, jaylink_devh are freed by jaylink_close and jaylink_exit */
+ if (jlink_data)
+ free(jlink_data);
+
+ return 1;
}
+
+const struct programmer_entry programmer_jlink_spi = {
+ .name = "jlink_spi",
+ .type = OTHER,
+ .init = jlink_spi_init,
+ .devs.note = "SEGGER J-Link and compatible devices\n",
+};
diff --git a/known_boards.c b/known_boards.c
new file mode 100644
index 000000000..afc6992d0
--- /dev/null
+++ b/known_boards.c
@@ -0,0 +1,691 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2011-2013 Stefan Tauner
+ *
+ * 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 "programmer.h"
+
+
+#ifdef CONFIG_PRINT_WIKI
+#define B(vendor, name, status, url, note) { vendor, name, status, url, note }
+#else
+#define B(vendor, name, status, url, note) { vendor, name, status }
+#endif
+
+/* Please keep this list alphabetically ordered by vendor/board. */
+const struct board_info boards_known[] = {
+#if defined(__i386__) || defined(__x86_64__)
+ B("A-Trend", "ATC-6220", OK, "http://www.motherboard.cz/mb/atrend/atc6220.htm", NULL),
+ B("abit", "A-S78H", OK, NULL, NULL),
+ B("abit", "AN-M2", OK, NULL, NULL),
+ B("abit", "AV8", OK, NULL, NULL),
+ B("abit", "AX8", OK, NULL, NULL),
+ B("abit", "BF6", OK, NULL, NULL),
+ B("abit", "BM6", OK, NULL, NULL),
+ B("abit", "BX6 2.0", OK, NULL, NULL),
+ B("abit", "Fatal1ty F-I90HD", OK, NULL, NULL),
+ B("abit", "IC7", OK, NULL, NULL),
+ B("abit", "IP35", OK, NULL, NULL),
+ B("abit", "IP35 Pro", OK, NULL, NULL),
+ B("abit", "IS-10", BAD, NULL, "Reported by deejkuba@aol.com to flashrom@coreboot.org, no public archive. Missing board enable and/or M50FW040 unlocking. May work now."),
+ B("abit", "KN8 Ultra", OK, NULL, NULL),
+ B("abit", "KN9 Ultra", OK, NULL, NULL),
+ B("abit", "NF-M2 nView", OK, NULL, NULL),
+ B("abit", "NF-M2S", OK, NULL, NULL),
+ B("abit", "NF7-S", OK, NULL, NULL),
+ B("abit", "VA6", OK, NULL, NULL),
+ B("abit", "VT6X4", OK, NULL, NULL),
+ B("Acer", "V75-M", OK, NULL, "This is an OEM board used by IBM in e.g. Aptiva 2170-G"),
+ B("Acer", "EM61SM/EM61PM", OK, NULL, "Used in Acer Aspire T180 and E380. Seems to be an OEM variant of abit's NF-M2S."),
+ B("Acorp", "6A815EPD", OK, "http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp", NULL),
+ B("Acorp", "6M810C", OK, NULL, NULL),
+ B("ADLINK", "Express-HR", OK, "http://www.adlinktech.com/PD/web/PD_detail.php?pid=1012", NULL),
+ B("Advantech", "PCM-5820", OK, "http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm", NULL),
+ B("agami", "Aruma", OK, "http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series", NULL),
+ B("Albatron", "PM266A Pro", OK, "http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56", NULL), /* FIXME */
+ B("Alienware", "Aurora-R2", BAD, NULL, "Mainboard model is 0RV30W. Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("AOpen", "i945GMx-VFX", OK, NULL, "This is (also?) an OEM board from FSC (used in e.g. ESPRIMO Q5010 with designation D2544-B1)."),
+ B("AOpen", "UK79G-1394", OK, "http://global.aopen.com/products_detail.aspx?auno=9", "Used in EZ18 barebones"),
+ B("AOpen", "vKM400Am-S", OK, "http://global.aopen.com/products_detail.aspx?Auno=824", NULL),
+ B("Artec Group","DBE61", OK, "http://wiki.thincan.org/DBE61", NULL),
+ B("Artec Group","DBE62", OK, "http://wiki.thincan.org/DBE62", NULL),
+ B("ASI", "MB-5BLMP", OK, "http://www.hojerteknik.com/winnet.htm", "Used in the IGEL WinNET III thin client."),
+ B("ASRock", "4CoreDual-VSTA", OK, "http://www.asrock.com/mb/overview.asp?Model=4CoreDual-VSTA", "W39V040FB"),
+ B("ASRock", "775Dual-VSTA", OK, "http://www.asrock.com/mb/overview.asp?Model=775Dual-VSTA", NULL),
+ B("ASRock", "775i65G", OK, "http://www.asrock.com/mb/overview.asp?Model=775i65G", NULL),
+ B("ASRock", "880G Pro3", OK, "http://www.asrock.com/mb/overview.asp?Model=880G%20Pro3", NULL),
+ B("ASRock", "890GX Extreme3", OK, "http://www.asrock.com/mb/overview.asp?Model=890GX%20Extreme3", NULL),
+ B("ASRock", "939A785GMH/128M", OK, "http://www.asrock.com/mb/overview.asp?Model=939A785GMH/128M", NULL),
+ B("ASRock", "960GM-GS3 FX", OK, "http://www.asrock.com/mb/overview.asp?Model=960GM-GS3%20FX", NULL),
+ B("ASRock", "A330GC", OK, "http://www.asrock.com/mb/overview.asp?Model=A330GC", NULL),
+ B("ASRock", "A770CrossFire", OK, "http://www.asrock.com/mb/overview.asp?Model=A770CrossFire", NULL),
+ B("ASRock", "A780FullHD", OK, "http://www.asrock.com/mb/overview.asp?Model=A780FullHD", "While flashrom is working correctly, there might be problems with the firmware images themselves. Please see https://flashrom.org/pipermail/flashrom/2012-July/009600.html for details."),
+ B("ASRock", "ALiveNF6G-DVI", OK, "http://www.asrock.com/mb/overview.asp?Model=ALiveNF6G-DVI", NULL),
+ B("ASRock", "AM2NF6G-VSTA", OK, "http://www.asrock.com/mb/overview.asp?Model=AM2NF6G-VSTA", NULL),
+ B("ASRock", "AMCP7AION-HT", OK, "http://www.asrock.com/nettop/NVIDIA/ION%20330HT/", "Used in ION 330HT(-BD) barebones."),
+ B("ASRock", "ConRoeXFire-eSATA2", OK, "http://www.asrock.com/mb/overview.asp?model=conroexfire-esata2", NULL),
+ B("ASRock", "E350M1/USB3", OK, "http://www.asrock.com/mb/overview.asp?model=e350m1/usb3", "Vendor firmware writes to flash at shutdown. This probably corrupts the flash in case you write coreboot while running the vendor firmware. Simply updating the vendor firmware should be fine."),
+ B("ASRock", "Fatal1ty 970 Performance", OK, "http://www.asrock.com/mb/overview.asp?Model=Fatal1ty%20970%20Performance", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASRock", "Fatal1ty Z77 Performance", BAD, "http://www.asrock.com/mb/overview.asp?Model=Fatal1ty%20Z77%20Performance", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASRock", "G31M-GS", OK, "http://www.asrock.com/mb/overview.asp?Model=G31M-GS", NULL),
+ B("ASRock", "G31M-S rev 2.0", OK, "http://www.asrock.com/mb/overview.asp?model=G31M-S", NULL),
+ B("ASRock", "G41M-VS3", OK, "http://www.asrock.com/mb/overview.asp?Model=G41M-VS3", NULL),
+ B("ASRock", "H61M-ITX", BAD, "http://www.asrock.com/mb/overview.asp?Model=H61M-ITX", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASRock", "H67M", BAD, "http://www.asrock.com/mb/overview.asp?Model=H67M", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASRock", "IMB-180-H", OK, "http://www.asrock.com/ipc/overview.asp?Model=IMB-A180-H", NULL),
+ B("ASRock", "K7S41", OK, "http://www.asrock.com/mb/overview.asp?Model=K7S41", NULL),
+ B("ASRock", "K7S41GX", OK, "http://www.asrock.com/mb/overview.asp?Model=K7S41GX", NULL),
+ B("ASRock", "K7VT4A+", BAD, "http://www.asrock.com/mb/overview.asp?Model=K7VT4A%2b", "No chip found, probably due to flash translation. https://flashrom.org/pipermail/flashrom/2009-August/000393.html"),
+ B("ASRock", "K8S8X", OK, "http://www.asrock.com/mb/overview.asp?Model=K8S8X", NULL),
+ B("ASRock", "M3A790GXH/128M", OK, "http://www.asrock.com/mb/overview.asp?Model=M3A790GXH/128M", NULL),
+ B("ASRock", "N61P-S", OK, "http://www.asrock.com/mb/overview.asp?Model=N61P-S", NULL),
+ B("ASRock", "N68C-S UCC", OK, "http://www.asrock.com/mb/overview.asp?Model=N68C-S%20UCC", NULL),
+ B("ASRock", "P4i65G", OK, "http://www.asrock.com/mb/overview.asp?Model=P4i65G", NULL),
+ B("ASRock", "P4i65GV", OK, "http://www.asrock.com/mb/overview.asp?Model=P4i65GV", NULL),
+ B("ASRock", "Z68 Extreme4", BAD, "http://www.asrock.com/mb/overview.asp?Model=Z68%20Extreme4", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "A7N8X Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7N8X_Deluxe/", NULL),
+ B("ASUS", "A7N8X-E Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7N8XE_Deluxe/", NULL),
+ B("ASUS", "A7N8X-VM/400", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7N8XVM400/", NULL),
+ B("ASUS", "A7V133", OK, NULL, NULL),
+ B("ASUS", "A7V333", OK, NULL, NULL),
+ B("ASUS", "A7V400-MX", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V400MX/", NULL),
+ B("ASUS", "A7V600-X", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V600X/", NULL),
+ B("ASUS", "A7V8X", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V8X/", NULL),
+ B("ASUS", "A7V8X-MX", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V8XMX/", NULL),
+ B("ASUS", "A7V8X-MX SE", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V8XMX_SE/", NULL),
+ B("ASUS", "A7V8X-X", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V8XX/", NULL),
+ B("ASUS", "A8M2N-LA (NodusM3-GL8E)", OK, "http://h10010.www1.hp.com/ewfrf/wc/document?docname=c00757531&cc=us&dlc=en&lc=en", "This is an OEM board from HP, the HP name is NodusM3-GL8E."),
+ B("ASUS", "A8N-E", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NE/", NULL),
+ B("ASUS", "A8N-LA (Nagami-GL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?lc=en&cc=us&docname=c00647121&dlc=en", "This is an OEM board from HP, the HP name is Nagami-GL8E."),
+ B("ASUS", "A8N-SLI", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NSLI/", NULL),
+ B("ASUS", "A8N-SLI Deluxe", NT, NULL, "Should work out of the box since r1593."),
+ B("ASUS", "A8N-SLI Premium", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NSLI_Premium/", NULL),
+ B("ASUS", "A8N-VM", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NVM/", NULL),
+ B("ASUS", "A8N-VM CSM", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NVM_CSM/", NULL),
+ B("ASUS", "A8NE-FM/S", OK, "http://www.hardwareschotte.de/hardware/preise/proid_1266090/preis_ASUS+A8NE-FM", NULL),
+ B("ASUS", "A8V Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8V_Deluxe/", NULL),
+ B("ASUS", "A8V-E Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8VE_Deluxe/", NULL),
+ B("ASUS", "A8V-E SE", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8VE_SE/", "See http://www.coreboot.org/pipermail/coreboot/2007-October/026496.html"),
+ B("ASUS", "C60M1-I", OK, "https://www.asus.com/Motherboards/C60M1I/", "The MAC address of the onboard network card is stored in flash."),
+ B("ASUS", "Crosshair II Formula", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/Crosshair_II_Formula/", NULL),
+ B("ASUS", "Crosshair IV Extreme", OK, "https://www.asus.com/Motherboards/AMD_AM3/Crosshair_IV_Extreme/", NULL),
+ B("ASUS", "CUSL2-C", OK, NULL, "The image provided by ASUS is only 256 kB big and has to be written to the upper 256 kB of the 512 kB chip."),
+ B("ASUS", "DSAN-DX", NT, "https://www.asus.com/Server_Workstation/Server_Motherboards/DSANDX/", NULL),
+ B("ASUS", "E35M1-I DELUXE", OK, "https://www.asus.com/Motherboards/AMD_CPU_on_Board/E35M1I_DELUXE/", NULL),
+ B("ASUS", "F1A75-V PRO", OK, "https://www.asus.com/Motherboard/F1A75V_PRO/", NULL),
+ B("ASUS", "F2A85-M", DEP, "https://www.asus.com/Motherboards/F2A85M/", "UEFI builds v6404 and above disable access to some parts of the flash, cf. http://www.coreboot.org/ASUS_F2A85-M#UEFI_builds_that_allow_flash_chip_access"),
+ B("ASUS", "K8N", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8N/", NULL),
+ B("ASUS", "K8V", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8V/", NULL),
+ B("ASUS", "K8V SE Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8V_SE_Deluxe/", NULL),
+ B("ASUS", "K8V-X", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8VX/", NULL),
+ B("ASUS", "K8V-X SE", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8VX_SE/", NULL),
+ B("ASUS", "KFSN4-DRE/SAS", OK, "https://www.asus.com/Server_Workstation/Server_Motherboards/KFSN4DRESAS/", NULL),
+ B("ASUS", "M2A-MX", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2AMX/", NULL),
+ B("ASUS", "M2A-VM (HDMI)", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2AVM/", NULL),
+ B("ASUS", "M2N32-SLI Deluxe", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2N32SLI_DeluxeWireless_Edition/", NULL),
+ B("ASUS", "M2N68-VM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M2N68VM/", NULL),
+ B("ASUS", "M2NBP-VM CSM", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NBPVM_CSM/", NULL),
+ B("ASUS", "M2N-E", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NE/", "If the machine doesn't come up again after flashing, try resetting the NVRAM(CMOS). The MAC address of the onboard network card will change to the value stored in the new image, so backup the old address first. See https://flashrom.org/pipermail/flashrom/2009-November/000879.html"),
+ B("ASUS", "M2N-E SLI", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NE_SLI/", NULL),
+ B("ASUS", "M2N-MX SE Plus", OK, "https://www.asus.com/Motherboards/M2NMX_SE_Plus/", NULL),
+ B("ASUS", "M2NPV-VM", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NPVVM/", NULL),
+ B("ASUS", "M2N-SLI Deluxe", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NSLI_Deluxe/", NULL),
+ B("ASUS", "M2V", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2V/", NULL),
+ B("ASUS", "M2V-MX", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2VMX/", NULL),
+ B("ASUS", "M3A", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3A/", NULL),
+ B("ASUS", "M3A76-CM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3A76CM/", NULL),
+ B("ASUS", "M3A78-EH", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3A78EH/", NULL),
+ B("ASUS", "M3A78-EM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3A78EM/", NULL),
+ B("ASUS", "M3N78 PRO", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3N78_PRO/", NULL),
+ B("ASUS", "M3N78-VM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3N78VM/", NULL),
+ B("ASUS", "M3N-H/HDMI", OK, "https://www.asus.com/Motherboards/M3NHHDMI//", NULL),
+ B("ASUS", "M4A785TD-M EVO", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A785TDM_EVO/", NULL),
+ B("ASUS", "M4A785TD-V EVO", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A785TDV_EVO/", NULL),
+ B("ASUS", "M4A785T-M", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A785TM/", NULL),
+ B("ASUS", "M4A78-EM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M4A78EM/", NULL),
+ B("ASUS", "M4A78LT-M LE", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A78LTM_LE/", NULL),
+ B("ASUS", "M4A79T Deluxe", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A79T_Deluxe/", NULL),
+ B("ASUS", "M4A87TD/USB3", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A87TDUSB3/", NULL),
+ B("ASUS", "M4A89GTD PRO", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A89GTD_PRO/", NULL),
+ B("ASUS", "M4N68T V2", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4N68T_V2/", NULL),
+ B("ASUS", "M4N78 PRO", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M4N78_PRO/", NULL),
+ B("ASUS", "M4N78 SE", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M4N78_SE/", NULL),
+ B("ASUS", "M5A78L-M LX", OK, "https://www.asus.com/Motherboards/AMD_AM3Plus/M5A78LM_LX/", "The MAC address of the onboard LAN NIC is stored in flash, hence overwritten by flashrom; see https://flashrom.org/pipermail/flashrom/2012-May/009200.html"),
+ B("ASUS", "M5A97 (rev. 1.0)", OK, "https://www.asus.com/Motherboard/M5A97/", NULL),
+ B("ASUS", "M5A99X EVO", OK, "https://www.asus.com/Motherboards/AMD_AM3Plus/M5A99X_EVO/", NULL),
+ B("ASUS", "Maximus IV Extreme", BAD, "https://www.asus.com/Motherboards/Intel_Socket_1155/Maximus_IV_Extreme/", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "MEW-AM", BAD, NULL, "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
+ B("ASUS", "MEW-VM", BAD, "http://www.elhvb.com/mboards/OEM/HP/manual/ASUS%20MEW-VM.htm", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
+ B("ASUS", "OPLX-M", NT, NULL, "Untested board enable."),
+ B("ASUS", "P2B", OK, NULL, NULL),
+ B("ASUS", "P2B-D", OK, NULL, NULL),
+ B("ASUS", "P2B-DS", OK, NULL, NULL),
+ B("ASUS", "P2B-F", OK, NULL, NULL),
+ B("ASUS", "P2B-LS", OK, NULL, NULL),
+ B("ASUS", "P2B-N", OK, NULL, NULL),
+ B("ASUS", "P2E-M", OK, NULL, NULL),
+ B("ASUS", "P2L97-S", OK, NULL, NULL),
+ B("ASUS", "P3B-F", OK, NULL, "Owned by Uwe Hermann <uwe@hermann-uwe.de>."),
+ B("ASUS", "P4B266", OK, NULL, NULL),
+ B("ASUS", "P4B266-LM", OK, "http://esupport.sony.com/US/perl/swu-list.pl?mdl=PCVRX650", NULL),
+ B("ASUS", "P4B533-E", OK, NULL, NULL),
+ B("ASUS", "P4C800-E Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4C800E_Deluxe/", NULL),
+ B("ASUS", "P4GV-LA (Guppy)", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00363478", NULL),
+ B("ASUS", "P4P800", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4P800/", NULL),
+ B("ASUS", "P4P800-E Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4P800E_Deluxe/", NULL),
+ B("ASUS", "P4P800-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4P800VM/", NULL),
+ B("ASUS", "P4P800-X", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4P800X/", NULL),
+ B("ASUS", "P4P800SE", OK, "https://www.asus.com/supportonly/P4P800 SE/", NULL),
+ B("ASUS", "P4PE-X/TE", NT, "https://www.asus.com/999/html/events/mb/socket478/p4pe-x-te/overview.htm", NULL),
+ B("ASUS", "P4S533-X", OK, NULL, NULL),
+ B("ASUS", "P4S800-MX", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4S800MX/", NULL),
+ B("ASUS", "P4SC-E", OK, NULL, "Part of ASUS Terminator P4 533 barebone system"),
+ B("ASUS", "P4SD-LA", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00022505", NULL),
+ B("ASUS", "P5A", OK, NULL, NULL),
+ B("ASUS", "P5B", OK, NULL, NULL),
+ B("ASUS", "P5B-Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5B_Deluxe/", NULL),
+ B("ASUS", "P5B-VM", OK, NULL, NULL),
+ B("ASUS", "P5BV-M", BAD, NULL, "Reported by Bernhard M. Wiedemann <bernhard@uml12d.zq1.de> to flashrom@coreboot.org, no public archive. Missing board enable and/or SST49LF008A unlocking. May work now."),
+ B("ASUS", "P5BV-R", OK, "https://www.asus.com/Server_Workstation/Servers/RS120E5PA2/", "Used in RS120-E5/PA2 servers."),
+ B("ASUS", "P5GC-MX/1333", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GCMX1333/", NULL),
+ B("ASUS", "P5GD1 Pro", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GD1_PRO/", NULL),
+ B("ASUS", "P5GD1-VM/S", OK, NULL, "This is an OEM board from FSC. Although flashrom supports it and can probably not distinguish it from the P5GD1-VM, please note that the P5GD1-VM BIOS does not support the FSC variants completely."),
+ B("ASUS", "P5GD1(-VM)", NT, NULL, "Untested board enable."),
+ B("ASUS", "P5GD2 Premium", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GD2_Premium/", NULL),
+ B("ASUS", "P5GD2-X", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GD2X/", NULL),
+ B("ASUS", "P5GDC Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GDC_Deluxe/", NULL),
+ B("ASUS", "P5GDC-V Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GDCV_Deluxe/", NULL),
+ B("ASUS", "P5GD2/C variants", NT, NULL, "Untested board enable."),
+ B("ASUS", "P5K SE", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5K_SE/", NULL),
+ B("ASUS", "P5K-V", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KV/", NULL),
+ B("ASUS", "P5K-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KVM/", NULL),
+ B("ASUS", "P5KC", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KC/", NULL),
+ B("ASUS", "P5KPL-AM IN/GB", OK, "http://support.asus.com/download.aspx?SLanguage=en&m=P5KPL-AM+IN%2fGB&os=29", NULL),
+ B("ASUS", "P5KPL-CM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KPLCM/", NULL),
+ B("ASUS", "P5KPL-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KPLVM/", "Found in V3-P5G31."),
+ B("ASUS", "P5L-MX", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5LMX/", NULL),
+ B("ASUS", "P5L-VM 1394", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5LVM_1394/", NULL),
+ B("ASUS", "P5LD2", OK, NULL, NULL),
+ B("ASUS", "P5LD2-MQ", OK, "http://support.asus.com/download.aspx?SLanguage=en&p=8&s=12&m=Vintage-PH2&os=&hashedid=n/a", "Found in ASUS Vintage-PH2 barebones."),
+ B("ASUS", "P5LD2-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5LD2VM/", NULL),
+ B("ASUS", "P5LD2-VM DH", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5LD2VM_DH/", NULL),
+ B("ASUS", "P5LP-LE (Lithium-UL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00379616&tmp_task=prodinfoCategory&cc=us&dlc=en&lc=en&product=1159887", "This is an OEM board from HP."),
+ B("ASUS", "P5LP-LE (Epson OEM)", OK, NULL, "This is an OEM board from Epson (e.g. Endeavor MT7700)."),
+ B("ASUS", "P5LP-LE", NT, NULL, "This designation is used for OEM boards from HP, Epson and maybe others. The HP names vary and not all of them have been tested yet. Please report any success or failure, thanks."),
+ B("ASUS", "P5N-D", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5ND/", NULL),
+ B("ASUS", "P5N-E SLI", NT, "https://www.asus.com/Motherboards/Intel_Socket_775/P5NE_SLI/", "Untested board enable."),
+ B("ASUS", "P5N32-E SLI", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5N32E_SLI/", NULL),
+ B("ASUS", "P5N7A-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5N7AVM/", NULL),
+ B("ASUS", "P5ND2-SLI Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5ND2SLI_Deluxe/", NULL),
+ B("ASUS", "P5PE-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5PEVM/", NULL),
+ B("ASUS", "P5QPL-AM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5QPLAM/", NULL),
+ B("ASUS", "P5VD1-X", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5VD1X/", NULL),
+ B("ASUS", "P5VD2-MX", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5VD2MX/", "The MAC address of the onboard LAN NIC is stored in flash, hence overwritten by flashrom; see https://flashrom.org/pipermail/flashrom/2012-March/009014.html"),
+ B("ASUS", "P5W DH Deluxe", OK, "https://www.asus.com/SupportOnly/P5W_DH_Deluxe/HelpDesk_Knowledge/", NULL),
+ B("ASUS", "P6T SE", OK, "https://www.asus.com/Motherboards/Intel_Socket_1366/P6T_SE/", NULL),
+ B("ASUS", "P6T Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_1366/P6T_Deluxe/", NULL),
+ B("ASUS", "P6T Deluxe V2", OK, "https://www.asus.com/Motherboards/Intel_Socket_1366/P6T_Deluxe_V2/", NULL),
+ B("ASUS", "P7H57D-V EVO", OK, "https://www.asus.com/Motherboards/Intel_Socket_1156/P7H57DV_EVO/", NULL),
+ B("ASUS", "P7H55-M LX", BAD, NULL, "flashrom works correctly, but GbE LAN is nonworking (probably due to a missing/bogus MAC address; see https://flashrom.org/pipermail/flashrom/2011-July/007432.html and http://ubuntuforums.org/showthread.php?t=1534389 for a possible workaround)"),
+ B("ASUS", "P8B-E/4L", BAD, NULL, "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8B WS", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8B75-M LE", BAD, NULL, "Probing works (2x 8192 kB via hwseq), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8H61 PRO", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8H61-M LE/USB3", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8H67-M PRO", BAD, NULL, "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."), // some firmware versions apparently are not locked, see report by Marek Zakrzewski
+ B("ASUS", "P8H77-I", OK, "https://www.asus.com/Motherboards/P8H77I/", NULL),
+ B("ASUS", "P8H77-M", OK, "https://www.asus.com/Motherboards/P8H77M/", NULL),
+ B("ASUS", "P8H77-V LE", OK, "https://www.asus.com/Motherboards/P8H77V_LE/", NULL),
+ B("ASUS", "P8P67 (rev. 3.1)", BAD, NULL, "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8P67 LE (B2)", OK, NULL, NULL),
+ B("ASUS", "P8P67 LE (B3)", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8P67 PRO (rev. 3.0)", OK, "https://www.asus.com/Motherboards/Intel_Socket_1155/P8P67_PRO/", NULL),
+ B("ASUS", "P8P67-M PRO", BAD, NULL, "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8Z68-V", OK, "https://www.asus.com/Motherboards/Intel_Socket_1155/P8Z68V/", "Warning: MAC address of LOM is stored at 0x1000 - 0x1005 of the image."),
+ B("ASUS", "P8Z68-V LE", BAD, NULL, "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8Z68-V PRO", BAD, NULL, "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ASUS", "P8Z68-V PRO/GEN3", OK, "https://www.asus.com/Motherboards/Intel_Socket_1155/P8Z68V_PROGEN3/", "Warning: MAC address of LOM is stored at 0x1000 - 0x1005 of the image."),
+ B("ASUS", "RAMPAGE III GENE", OK, "https://www.asus.com/Motherboards/RAMPAGE_III_GENE/", "The MAC address of the onboard network card is stored in flash."),
+ B("ASUS", "SABERTOOTH 990FX", OK, "https://www.asus.com/Motherboards/AMD_AM3Plus/SABERTOOTH_990FX/", NULL),
+ B("ASUS", "SABERTOOTH 990FX R2.0", OK, "https://www.asus.com/Motherboards/AMD_AM3Plus/SABERTOOTH_990FX_R20/", NULL),
+ B("ASUS", "TUSL2-C", NT, "http://support.asus.com/download.aspx?SLanguage=en&p=1&s=4&m=TUSL2-C&os=&hashedid=n/a", "Untested board enable."),
+ B("ASUS", "Z8NA-D6C", OK, "https://www.asus.com/Server_Workstation/Server_Motherboards/Z8NAD6C/", NULL),
+ B("ASUS", "Z8PE-D12", OK, "https://www.asus.com/Server_Workstation/Server_Motherboards/Z8PED12/", NULL),
+ B("Attro", "G5G100-P", OK, "http://www.attro.com/motherboard/G5G100-P.htm", NULL),
+ B("Bachmann", "OT200", OK, "http://www.bachmann.info/produkte/bedien-und-beobachtungsgeraete/operator-terminals/", NULL),
+ B("BCOM", "WinNET100", OK, "http://www.coreboot.org/BCOM_WINNET100", "Used in the IGEL-316 thin client."),
+ B("Bifferos", "Bifferboard", OK, "http://bifferos.co.uk/", NULL),
+ B("Biostar", "H61MGC", BAD, NULL, "Probing works (Eon EN25Q32(A/B), 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Biostar", "H61MU3", BAD, NULL, "Probing works (Eon EN25Q32(A/B), 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Biostar", "M6TBA", BAD, "ftp://ftp.biostar-usa.com/manuals/M6TBA/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
+ B("Biostar", "M7NCD Pro", OK, "http://www.biostar.com.tw/app/en/mb/introduction.php?S_ID=260", NULL),
+ B("Biostar", "M7VIQ", NT, NULL, NULL),
+ B("Biostar", "N61PB-M2S", OK, NULL, NULL),
+ B("Biostar", "N68S3+", OK, NULL, NULL),
+ B("Biostar", "P4M80-M4", OK, "http://www.biostar-usa.com/mbdetails.asp?model=p4m80-m4", NULL),
+ B("Biostar", "TA780G M2+", OK, "http://www.biostar.com.tw/app/en/mb/introduction.php?S_ID=344", NULL),
+ B("Biostar", "TA790GX A3+", OK, "http://www.biostar.com.tw/app/en/mb/introduction.php?S_ID=395", NULL),
+ B("Boser", "HS-6637", BAD, "http://www.boser.com.tw/manual/HS-62376637v3.4.pdf", "Reported by Mark Robinson <mark@zl2tod.net> to flashrom@coreboot.org, no public archive. Missing board enable and/or F29C51002T unlocking. May work now."),
+ B("Congatec", "conga-X852", OK, "http://www.congatec.com/single_news+M57715f6263d.html?&L=1", NULL),
+ B("Dell", "Inspiron 580", BAD, "http://support.dell.com/support/edocs/systems/insp580/en/index.htm", "Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+ B("Dell", "OptiPlex 7010", BAD, NULL, "Mainboard model is 0KRC95. Probing works (Hardware Sequencing 4 + 8MB), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+ B("Dell", "OptiPlex GX1", OK, "http://support.dell.com/support/edocs/systems/ban_gx1/en/index.htm", NULL),
+ B("Dell", "PowerEdge 1850", OK, "http://support.dell.com/support/edocs/systems/pe1850/en/index.htm", NULL),
+ B("Dell", "PowerEdge C6220", BAD, NULL, "Mainboard model is 0HYFFG. Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and there are even overlapping PRs)."),
+ B("Dell", "Vostro 460", BAD, "http://support.dell.com/support/edocs/systems/vos460/en/index.htm", "Mainboard model is 0Y2MRG. Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+ B("DFI", "855GME-MGF", BAD, "http://www.dfi.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?action=e&downloadType=&windowstate=normal&mode=view&downloadFlag=false&itemId=433", "Probably needs a board enable. http://www.coreboot.org/pipermail/coreboot/2009-May/048549.html"),
+ B("DFI", "AD77", NT, NULL, "Untested board enable."),
+ B("DFI", "Blood-Iron P35 T2RL", OK, "http://lp.lanparty.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?itemId=516&downloadFlag=false&action=1", NULL),
+ B("Elitegroup", "848P-A7", OK, NULL, NULL),
+ B("Elitegroup", "GeForce6100PM-M2 (V3.0)", OK, NULL, NULL),
+ B("Elitegroup", "GeForce6100SM-M", OK, NULL, NULL),
+ B("Elitegroup", "GeForce7050M-M (V2.0)", OK, "http://www.ecs.com.tw/ECSWebSite/Product/Product_Detail.aspx?DetailID=865&MenuID=20&LanID=0", NULL),
+ B("Elitegroup", "GF7050VT-M", OK, NULL, NULL),
+ B("Elitegroup", "GF7100PVT-M3 (V1.0)", OK, NULL, NULL),
+ B("Elitegroup", "GF8200A", OK, NULL, NULL),
+ B("Elitegroup", "K7S5A", OK, NULL, NULL),
+ B("Elitegroup", "K7S6A", OK, NULL, NULL),
+ B("Elitegroup", "K7SEM (V1.0A)", OK, NULL, NULL),
+ B("Elitegroup", "K7VTA3", OK, NULL, NULL),
+ B("Elitegroup", "P4M800PRO-M (V1.0A, V2.0)", OK, NULL, NULL),
+ B("Elitegroup", "P4VXMS (V1.0A)", OK, NULL, NULL),
+ B("Elitegroup", "P6BAP-A+ (V2.2)", OK, NULL, NULL),
+ B("Elitegroup", "P6IWP-Fe", OK, NULL, NULL),
+ B("Elitegroup", "P6VAP-A+", OK, NULL, NULL),
+ B("Elitegroup", "RS485M-M", OK, NULL, NULL),
+ B("Emerson", "ATCA-7360", OK, "http://www.emerson.com/sites/Network_Power/en-US/Products/Product_Detail/Product1/Pages/EmbCompATCA-7360.aspx", NULL),
+ B("EPoX", "EP-3PTA", BAD, NULL, "Missing board enable (W83627HF/F/HG/G), see https://flashrom.org/pipermail/flashrom/2012-April/009043.html"),
+ B("EPoX", "EP-8K5A2", OK, "http://www.epox.com/product.asp?ID=EP-8K5A2", NULL),
+ B("EPoX", "EP-8NPA7I", OK, "http://www.epox.com/product.asp?ID=EP-8NPA7I", NULL),
+ B("EPoX", "EP-8RDA3+", OK, "http://www.epox.com/product.asp?ID=EP-8RDA3plus", NULL),
+ B("EPoX", "EP-9NPA7I", OK, "http://www.epox.com/product.asp?ID=EP-9NPA7I", NULL),
+ B("EPoX", "EP-BX3", OK, "http://www.epox.com/product.asp?ID=EP-BX3", NULL),
+ B("EVGA", "122-CK-NF68", OK, NULL, NULL),
+ B("EVGA", "132-CK-NF78", OK, "http://www.evga.com/articles/385.asp", NULL),
+ B("EVGA", "270-WS-W555-A2 (Classified SR-2)", OK, "http://www.evga.com/products/moreInfo.asp?pn=270-WS-W555-A2", NULL),
+ B("FIC", "VA-502", BAD, "ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. Seems the PCI subsystem IDs are identical with the Tekram P6Pro-A5. May work now."),
+ B("Foxconn", "6150K8MD-8EKRSH", OK, "http://www.foxconnchannel.com/ProductDetail.aspx?T=Motherboard&U=en-us0000157", NULL),
+ B("Foxconn", "A6VMX", OK, "http://www.foxconnchannel.com/ProductDetail.aspx?T=Motherboard&U=en-us0000346", NULL),
+ B("Foxconn", "P4M800P7MA-RS2", OK, "http://www.foxconnchannel.com/ProductDetail.aspx?T=Motherboard&U=en-us0000138", NULL),
+ B("Foxconn", "P55MX", OK, "http://www.foxconnchannel.com/ProductDetail.aspx?T=motherboard&U=en-us0000474", "Needs the MFG jumper to be set correctly before flashing to enable the Flash Descriptor Override Strap."),
+ B("Foxconn", "Q45M", BAD, "http://www.foxconnchannel.com/ProductDetail.aspx?T=Motherboard&U=en-us0000587", "Probing works (Hardware sequencing, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+ B("Freetech", "P6F91i", OK, "http://web.archive.org/web/20010417035034/http://www.freetech.com/prod/P6F91i.html", NULL),
+ B("Fujitsu", "D2724-A1x", OK, NULL, "Used in ESPRIMO E5625."),
+ B("Fujitsu", "D3041-A1x", OK, NULL, "Used in ESPRIMO P2560, contains an Atmel AT26DF081A."),
+ B("Fujitsu-Siemens", "CELSIUS W410", BAD, "ftp://ftp.ts.fujitsu.com/pub/mainboard-oem-sales/Products/Mainboards/Industrial&ExtendedLifetime/D3061&D3062/", "Mainboard model is D3062-A1. Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+ B("Fujitsu-Siemens", "ESPRIMO P5915", OK, "http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/professionalpc/ESPRIMO/P/EsprimoP5915-6.htm", "Mainboard model is D2312-A2."),
+ B("GIGABYTE", "GA-2761GXDK", OK, "http://www.computerbase.de/news/hardware/mainboards/amd-systeme/2007/mai/gigabyte_dtx-mainboard/", NULL),
+ B("GIGABYTE", "GA-6BXC", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1445", NULL),
+ B("GIGABYTE", "GA-6BXDU", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1429", NULL),
+ B("GIGABYTE", "GA-6IEM", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1379", NULL),
+ B("GIGABYTE", "GA-6VXE7+", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2410", NULL),
+ B("GIGABYTE", "GA-6ZMA", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1541", NULL),
+ B("GIGABYTE", "GA-770TA-UD3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3272", NULL),
+ B("GIGABYTE", "GA-7DXR", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1302", NULL),
+ B("GIGABYTE", "GA-7VT600", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1666", NULL),
+ B("GIGABYTE", "GA-7ZM", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1366", "Works fine if you remove jumper JP9 on the board and disable the flash protection BIOS option."),
+ B("GIGABYTE", "GA-880GMA-USB3 (rev. 3.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3817", NULL),
+ B("GIGABYTE", "GA-8I945GZME-RH", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2304", NULL),
+ B("GIGABYTE", "GA-8IP775", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1830", NULL),
+ B("GIGABYTE", "GA-8IRML", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1343", NULL),
+ B("GIGABYTE", "GA-8PE667 Ultra 2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1607", NULL),
+ B("GIGABYTE", "GA-8S648", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1674", NULL),
+ B("GIGABYTE", "GA-8SIMLFS 2.0", OK, NULL, "This is an OEM board used by Fujitsu."),
+ B("GIGABYTE", "GA-8SIMLH", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1399", NULL),
+ B("GIGABYTE", "GA-945GCM-S2 (rev. 3.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2466", NULL),
+ B("GIGABYTE", "GA-945GM-S2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2331", NULL),
+ B("GIGABYTE", "GA-945PL-S3P (rev. 6.6)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2541", NULL),
+ B("GIGABYTE", "GA-965GM-S2 (rev. 2.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2617", NULL),
+ B("GIGABYTE", "GA-965P-DS4", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2288", NULL),
+ B("GIGABYTE", "GA-965P-S3 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2321", NULL),
+ B("GIGABYTE", "GA-970A-D3P (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4642", NULL),
+ B("GIGABYTE", "GA-970A-UD3P (rev. 2.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=5194", "Primary flash chip is a Macronix MX25L3206E."),
+ B("GIGABYTE", "GA-990FXA-UD3 (rev. 4.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4672", NULL),
+ B("GIGABYTE", "GA-A75M-UD2H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3928", NULL),
+ B("GIGABYTE", "GA-B85M-D3H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4567", NULL),
+ B("GIGABYTE", "GA-EG43M-S2H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2878", NULL),
+ B("GIGABYTE", "GA-EP31-DS3L (rev. 1.0, 2.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2964", NULL),
+ B("GIGABYTE", "GA-EP35-DS3L", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2778", NULL),
+ B("GIGABYTE", "GA-EX58-UD4P", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2986", NULL),
+ B("GIGABYTE", "GA-G33M-S2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2557", NULL),
+ B("GIGABYTE", "GA-G33M-S2L", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2692", NULL),
+ B("GIGABYTE", "GA-G41MT-S2PT", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3960", NULL),
+ B("GIGABYTE", "GA-H55M-S2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3509", "8 MB (ME) + 1 MB (BIOS) flash chips - hardware sequencing required."),
+ B("GIGABYTE", "GA-H61M-D2-B3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3773", NULL),
+ B("GIGABYTE", "GA-H61M-D2H-USB3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4004", NULL),
+ B("GIGABYTE", "GA-H77-D3H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4141", "Does only work with -p internal:ich_spi_mode=hwseq due to an evil twin of MX25L6405 and ICH SPI lockdown."),
+ B("GIGABYTE", "GA-H77-DS3H (rev. 1.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4318", NULL),
+ B("GIGABYTE", "GA-H77M-D3H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4388", NULL),
+ B("GIGABYTE", "GA-J1900N-D3V", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4918", NULL),
+ B("GIGABYTE", "GA-K8N51GMF-9", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1939", NULL),
+ B("GIGABYTE", "GA-K8N51GMF", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1950", NULL),
+ B("GIGABYTE", "GA-K8N-SLI", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1928", NULL),
+ B("GIGABYTE", "GA-K8NS", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1784", NULL),
+ B("GIGABYTE", "GA-M56S-S3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2607", NULL),
+ B("GIGABYTE", "GA-M57SLI-S4", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2287", NULL),
+ B("GIGABYTE", "GA-M61P-S3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2434", NULL),
+ B("GIGABYTE", "GA-M720-US3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3006", NULL),
+ B("GIGABYTE", "GA-MA69VM-S2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2500", NULL),
+ B("GIGABYTE", "GA-MA74GM-S2H (rev. 3.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3152", NULL),
+ B("GIGABYTE", "GA-MA770-UD3 (rev. 2.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3302", NULL),
+ B("GIGABYTE", "GA-MA770T-UD3P", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3096", NULL),
+ B("GIGABYTE", "GA-MA780G-UD3H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3004", NULL),
+ B("GIGABYTE", "GA-MA785GMT-UD2H (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3156", NULL),
+ B("GIGABYTE", "GA-MA78G-DS3H (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2800", NULL),
+ B("GIGABYTE", "GA-MA78GM-S2H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2758", NULL), /* TODO: Rev. 1.BAD, 1.OK, or 2.x? */
+ B("GIGABYTE", "GA-MA78GPM-DS2H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2859", NULL),
+ B("GIGABYTE", "GA-MA790FX-DQ6", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2690", NULL),
+ B("GIGABYTE", "GA-MA790GP-DS4H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2887", NULL),
+ B("GIGABYTE", "GA-MA790XT-UD4P (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3010", NULL),
+ B("GIGABYTE", "GA-P31-DS3L", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2615", NULL),
+ B("GIGABYTE", "GA-P31-S3G", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2676", NULL),
+ B("GIGABYTE", "GA-P55-USB3 (rev. 2.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3440", NULL),
+ B("GIGABYTE", "GA-P55A-UD4 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3436", NULL),
+ B("GIGABYTE", "GA-P55A-UD7" , OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3324", NULL),
+ B("GIGABYTE", "GA-P67A-UD3P", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3649", NULL),
+ B("GIGABYTE", "GA-X58A-UD3R (rev. 2.0)", OK, NULL, NULL),
+ B("GIGABYTE", "GA-X58A-UD7 (rev. 2.0)", OK, NULL, NULL),
+ B("GIGABYTE", "GA-X79-UD5", OK, NULL, NULL),
+ B("GIGABYTE", "GA-X79-UD3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4050", "Contains a Macronix MX25L6406E."),
+ B("GIGABYTE", "GA-X79-UP4 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4288", NULL),
+ B("GIGABYTE", "GA-Z68MA-D2H-B3 (rev. 1.3)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3975", NULL),
+ B("GIGABYTE", "GA-Z68MX-UD2H-B (rev. 1.3)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3854", NULL),
+ B("GIGABYTE", "GA-Z68XP-UD3 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3892", NULL),
+ B("GIGABYTE", "GA-Z77MX-D3H", BAD, "http://www.gigabyte.com/products/product-page.aspx?pid=4145", "Uses MX25L6436E and requires a small patch (but works flawlessly with that)."),
+ B("GIGABYTE", "GA-Z87-HD3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4489", NULL),
+ B("HP", "8100 Elite CMT PC (304Bh)", BAD, NULL, "SPI lock down, PR, read-only descriptor, locked ME region."),
+ B("HP", "e-Vectra P2706T", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?lang=en&cc=us&prodSeriesId=77515&prodTypeId=12454", NULL),
+ B("HP", "Evans-GL6 (Pegatron IPMEL-AE)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?cc=us&lc=en&dlc=en&docname=c01925513", "Found in HP Pavilion Slimline s5220f."),
+ B("HP", "ProLiant DL145 G3", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00816835&lang=en&cc=us&taskId=101&prodSeriesId=3219755&prodTypeId=15351", NULL),
+ B("HP", "ProLiant DL165 G6", OK, "http://h10010.www1.hp.com/wwpc/us/en/sm/WF05a/15351-15351-3328412-241644-3328421-3955644.html", NULL),
+ B("HP", "ProLiant N40L", OK, NULL, NULL),
+ B("HP", "Puffer2-UL8E", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00300023", NULL),
+ B("HP", "dc7800", BAD, "http://h10010.www1.hp.com/wwpc/us/en/sm/WF06a/12454-12454-64287-321860-3328898-3459241.html?dnr=1", "ICH9DO with SPI lock down, BIOS lock, PR, read-only descriptor, locked ME region."),
+ B("HP", "Vectra VL400", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00060658&lang=en&cc=us", NULL),
+ B("HP", "Vectra VL420 SFF", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00060661&lang=en&cc=us", NULL),
+ B("HP", "xw4400 (0A68h)", BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00775230", "ICH7 with SPI lock down, BIOS lock, flash block detection (SST25VF080B); see http://paste.flashrom.org/view.php?id=686"),
+ B("HP", "xw6400", BAD, NULL, "No chip found, see https://flashrom.org/pipermail/flashrom/2012-March/009006.html"),
+ B("HP", "xw9300", BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?lang=en&cc=us&prodTypeId=12454&prodSeriesId=459226", "Missing board enable, see https://flashrom.org/pipermail/flashrom/2012-March/008885.html"),
+ B("HP", "xw9400", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?lang=en&cc=us&prodSeriesId=3211286&prodTypeId=12454", "Boot block is write protected unless the solder points next to F2 are shorted."),
+ B("HP", "Z400 Workstation (0AE4h)", BAD, NULL, "ICH10R with BIOS lock enable and a protected range PRBAD, see https://flashrom.org/pipermail/flashrom/2012-June/009350.html"),
+ B("IBASE", "MB899", OK, "http://www.ibase-i.com.tw/2009/mb899.html", NULL),
+ B("IBM", "x3455", OK, "http://www-03.ibm.com/systems/x/hardware/rack/x3455/index.html", NULL),
+ B("IEI", "PICOe-9452", OK, "http://www.ieiworld.com/product_groups/industrial/content.aspx?keyword=WSB&gid=00001000010000000001&cid=08125380291060861658&id=08142308605814597144", NULL),
+ B("Intel", "D201GLY", OK, "http://www.intel.com/support/motherboards/desktop/d201gly/index.htm", NULL),
+ B("Intel", "D2700MUD", BAD, "http://www.intel.com/cd/products/services/emea/eng/motherboards/desktop/D2700MUD/", "SMM protection enabled"),
+ B("Intel", "D425KT", BAD, "http://www.intel.com/content/www/us/en/motherboards/desktop-motherboards/desktop-board-d425kt.html", "NM10 with SPI lock down, BIOS lock, see https://flashrom.org/pipermail/flashrom/2012-January/008600.html"),
+ B("Intel", "D865GLC", BAD, NULL, "ICH5 with BIOS lock enable, see http://paste.flashrom.org/view.php?id=775"),
+ B("Intel", "D945GCNL", OK, NULL, NULL),
+ B("Intel", "DG45ID", BAD, "http://www.intel.com/products/desktop/motherboards/dg45id/dg45id-overview.htm", "Probing works (Winbond W25x32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
+ B("Intel", "DQ965GF", BAD, NULL, "Probing enables Hardware Sequencing (behind that hides a SST SST25VF016B, 2048 kB). Parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and the platform data region seems to be bogus)."),
+ B("Intel", "DG965OT", BAD, NULL, "Probing enables Hardware Sequencing (behind that hides a SST SST25VF080B, 1024 kB). Parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and the platform data region seems to be bogus)."),
+ B("Intel", "DH61AG ", BAD, NULL, "H61 with BIOS lock enable and locked ME region, see https://flashrom.org/pipermail/flashrom/2012-June/009417.html"),
+ B("Intel", "DH67CF", BAD, NULL, "H67 with BIOS lock enable and locked ME region, see https://flashrom.org/pipermail/flashrom/2011-September/007789.html"),
+ B("Intel", "DH67CL", BAD, NULL, "H67 with BIOS lock enable and locked ME region, see https://flashrom.org/pipermail/flashrom/2012-November/010112.html"),
+ B("Intel", "DN2800MT (Marshalltown)", BAD, NULL, "BIOS locked via BIOS_CNTL."),
+ B("Intel", "DQ45CB", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Intel", "DQ77MK", BAD, NULL, "Q77 with BIOS lock enable and locked ME region, see http://paste.flashrom.org/view.php?id=1603"),
+ B("Intel", "EP80759", OK, NULL, NULL),
+ B("Intel", "Foxhollow", OK, NULL, "Intel reference board."),
+ B("Intel", "Greencity", OK, NULL, "Intel reference board."),
+ B("Intel", "SE440BX-2", BAD, "http://downloadcenter.intel.com/SearchResult.aspx?lang=eng&ProductFamily=Desktop+Boards&ProductLine=Discontinued+Motherboards&ProductProduct=Intel%C2%AE+SE440BX-2+Motherboard", "Probably won't work, see http://www.coreboot.org/pipermail/flashrom/2010-July/003952.html"),
+ B("IWILL", "DK8-HTX", OK, "http://web.archive.org/web/20060507170150/http://www.iwill.net/product_2.asp?p_id=98", NULL),
+ B("Jetway", "J-7BXAN", OK, "http://www.jetway.com.tw/evisn/download/d7BXAS.htm", NULL),
+ B("Jetway", "J7F4K1G5D-PB", OK, "http://www.jetway.com.tw/jw/ipcboard_view.asp?productid=282&proname=J7F4K1G5D", NULL),
+ B("Jetway", "P4MDPT", OK, "https://www.jetwaycomputer.com/spec/p4mdpt.html", NULL),
+ B("Kontron", "986LCD-M", OK, "http://de.kontron.com/products/boards+and+mezzanines/embedded+motherboards/miniitx+motherboards/986lcdmmitx.html", NULL),
+ B("Lanner", "EM-8510C", OK, NULL, NULL),
+ B("Lenovo", "Tilapia CRB", OK, NULL, "Used in ThinkCentre M75e."),
+ B("Lex", "CV700A", OK, "http://www.lex.com.tw/product/CV700A-spec.htm", NULL),
+ B("Mitac", "6513WU", OK, "http://web.archive.org/web/20050313054828/http://www.mitac.com/micweb/products/tyan/6513wu/6513wu.htm", NULL),
+ B("MSC", "Q7-TCTC", OK, "http://www.msc-ge.com/en/produkte/com/moduls/overview/5779-www.html", NULL),
+ B("MSI", "MS-6153", OK, "http://www.msi.com/product/mb/MS-6153.html", NULL),
+ B("MSI", "MS-6156", OK, "http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/boards/Motherboards/MicroStar/Ms6156/MS6156.htm", NULL),
+ B("MSI", "MS-6163 (MS-6163 Pro)",OK, "http://www.msi.com/product/mb/MS-6163-Pro.html", NULL),
+ B("MSI", "MS-6178", BAD, "http://www.msi.com/product/mb/MS-6178.html", "Immediately powers off if you try to hot-plug the chip. However, this does '''not''' happen if you use coreboot. Owned by Uwe Hermann <uwe@hermann-uwe.de>."),
+ B("MSI", "MS-6330 (K7T Turbo)", OK, "http://www.msi.com/product/mb/K7T-Turbo.html", NULL),
+ B("MSI", "MS-6391 (845 Pro4)", OK, "http://www.msi.com/product/mb/845-Pro4.html", NULL),
+ B("MSI", "MS-6561 (745 Ultra)", OK, "http://www.msi.com/product/mb/745-Ultra.html", NULL),
+ B("MSI", "MS-6566 (845 Ultra-C)",OK, "http://www.msi.com/product/mb/845-Ultra-C.html", NULL),
+ B("MSI", "MS-6570 (K7N2)", OK, "http://www.msi.com/product/mb/K7N2.html", NULL),
+ B("MSI", "MS-6577 (Xenon)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?product=90390&lc=en&cc=us&dlc=en&docname=bph07843", "This is an OEM board from HP, the HP name is Xenon."),
+ B("MSI", "MS-6590 (KT4 Ultra)", OK, "http://www.msi.com/product/mb/KT4-Ultra.html", NULL),
+ //B("MSI", "MS-6702E (K8T Neo2-F/FIR)",OK, "http://www.msi.com/product/mb/K8T-Neo2-F--FIR.html", NULL), This was wrongly attributed to the MS-7094 board enable.
+ B("MSI", "MS-6704 (845PE Max2 PCB 1.0)", OK, "http://www.msi.com/product/mb/845PE-Max2.html", "Write protection must be disabled in the BIOS setup."),
+ B("MSI", "MS-6712 (KT4V)", OK, "http://www.msi.com/product/mb/KT4V---KT4V-L--v1-0-.html", NULL),
+ B("MSI", "MS-6787 (P4MAM-V/P4MAM-L)", OK, "http://www.msi.com/service/search/?kw=6787&type=product", NULL),
+ B("MSI", "MS-7005 (651M-L)", OK, "http://www.msi.com/product/mb/651M-L.html", NULL),
+ B("MSI", "MS-7025 (K8N Neo2 Platinum)", OK, "http://www.msi.com/product/mb/K8N-Neo2-Platinum.html", NULL),
+ B("MSI", "MS-7030 (K8N Neo Platinum)", OK, "http://www.msi.com/product/mb/K8N-Neo-Platinum.html", NULL),
+ B("MSI", "MS-7046", OK, "http://www.heimir.de/ms7046/", NULL),
+ B("MSI", "MS-7061 (KM4M-V/KM4AM-V)", OK, "http://www.msi.com/service/search/?kw=7061&type=product", NULL),
+ B("MSI", "MS-7065", OK, "http://browse.geekbench.ca/geekbench2/view/53114", NULL),
+ B("MSI", "MS-7094 (K8T Neo2-F V2.0)",OK, "http://www.msi.com/product/mb/K8T_Neo2F_V2.0.html", NULL),
+ B("MSI", "MS-7125 (K8N Neo4(-F/-FI/-FX/Platinum))", OK, "http://www.msi.com/product/mb/K8N_Neo4_Platinum_PCB_1.0.html", NULL),
+ B("MSI", "MS-7135 (K8N Neo3)", OK, "http://www.msi.com/product/mb/K8N-Neo3.html", NULL),
+ B("MSI", "MS-7142 (K8MM-V)", OK, "http://www.msi.com/product/mb/K8MM-V.html", NULL),
+ B("MSI", "MS-7168 (Orion)", OK, "http://support.packardbell.co.uk/uk/item/index.php?i=spec_orion&pi=platform_honeymoon_istart", NULL),
+ B("MSI", "MS-7207 (K8NGM2-L)", OK, "http://www.msi.com/product/mb/K8NGM2-FID--IL--L.html", NULL),
+ B("MSI", "MS-7211 (PM8M3-V)", OK, "http://www.msi.com/product/mb/PM8M3-V.html", NULL),
+ B("MSI", "MS-7236 (945PL Neo3)", OK, "http://www.msi.com/product/mb/945PL-Neo3.html", NULL),
+ B("MSI", "MS-7250 (K9N SLI (rev 2.1))", OK, "http://www.msi.com/product/mb/K9N--SLI.html", NULL),
+ B("MSI", "MS-7253 (K9VGM-V)", OK, "http://www.msi.com/product/mb/K9VGM-V.html", NULL),
+ B("MSI", "MS-7255 (P4M890M)", OK, "http://www.msi.com/product/mb/P4M890M-L-IL.html", NULL),
+ B("MSI", "MS-7260 (K9N Neo PCB 1.0)", BAD, "http://www.msi.com/product/mb/K9N-Neo--PCB-1-0-.html", "Interestingly flashrom does not work when the vendor BIOS is booted, but it ''does'' work flawlessly when the machine is booted with coreboot. Owned by Uwe Hermann <uwe@hermann-uwe.de>."),
+ B("MSI", "MS-7309 (K9N6SGM-V)", BAD, "http://www.msi.com/product/mb/K9N6SGM-V---K9N6PGM-FI---K9N6PGM-F.html", "Uses Fintek F71882F/F71883F/F71887 SPI-to-LPC translation."),
+ B("MSI", "MS-7309 (K9N6PGM2-V2)", OK, "http://www.msi.com/product/mb/K9N6PGM2-V2.html", NULL),
+ B("MSI", "MS-7312 (K9MM-V)", OK, "http://www.msi.com/product/mb/K9MM-V.html", NULL),
+ B("MSI", "MS-7336", OK, NULL, "Some non-essential DMI data (e.g. serial numbers) is overwritten when using flashrom. This is an OEM board used by HP (e.g. dx2300 Microtower)."),
+ B("MSI", "MS-7345 (P35 Neo2-FIR)", OK, "http://www.msi.com/product/mb/P35-Neo2-FR---FIR.html", NULL),
+ B("MSI", "MS-7357 (G33M)", OK, "http://www.msi.com/product/mb/G33M.html", NULL),
+ B("MSI", "MS-7368 (K9AG Neo2-Digital)", OK, "http://www.msi.com/product/mb/K9AG-Neo2-Digital.html", NULL),
+ B("MSI", "MS-7369 (K9N Neo V2)", OK, "http://www.msi.com/product/mb/K9N-Neo-V2.html", NULL),
+ B("MSI", "MS-7376 (K9A2 Platinum V1)", OK, "http://www.msi.com/product/mb/K9A2-Platinum.html", NULL),
+ B("MSI", "MS-7379 (G31M)", OK, "http://www.msi.com/product/mb/G31M.html", NULL),
+ B("MSI", "MS-7399 1.1 (Persian)", OK, "http://acersupport.com/acerpanam/desktop/0000/Acer/AspireM5640/AspireM5640sp2.shtml", "This is an OEM board used by Acer in e.g. Aspire M5640/M3640."),
+ B("MSI", "MS-7502", OK, NULL, "This is an OEM board used by Medion in e.g. Medion MD8833."),
+ B("MSI", "MS-7522 (MSI X58 Pro-E)", OK, "http://www.msi.com/product/mb/X58_ProE.html", NULL),
+ B("MSI", "MS-7529 (G31M3-L(S) V2)", OK, "http://www.msi.com/product/mb/G31M3-L-V2---G31M3-LS-V2.html", NULL),
+ B("MSI", "MS-7529 (G31TM-P21)", OK, "http://www.msi.com/product/mb/G31TM-P21.html", NULL),
+ B("MSI", "MS-7548 (Aspen-GL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c01635688&lc=en&cc=us&dlc=en", NULL),
+ B("MSI", "MS-7551 (KA780G)", OK, "http://www.msi.com/product/mb/KA780G.html", NULL),
+ B("MSI", "MS-7596 (785GM-E51)", OK, "http://www.msi.com/product/mb/785GM-E51.html", NULL),
+ B("MSI", "MS-7597 (GF615M-P33)", BAD, NULL, "Missing board enable/SIO support (Fintek F71889), see https://flashrom.org/pipermail/flashrom/2012-March/008956.html"),
+ B("MSI", "MS-7599 (870-C45)", OK, "http://www.msi.com/product/mb/870-C45.html", NULL),
+ B("MSI", "MS-7613 (Iona-GL8E)", BAD, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c02014355&lc=en&cc=dk&dlc=en&product=4348478", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("MSI", "MS-7635 (H55M-ED55)", BAD, "http://www.msi.com/product/mb/H55M-ED55.html", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("MSI", "MS-7640 (890FXA-GD70)",OK, "http://www.msi.com/product/mb/890FXA-GD70.html", NULL),
+ B("MSI", "MS-7642 (890GXM-G65)", OK, "http://www.msi.com/product/mb/890GXM-G65.html", NULL),
+ B("MSI", "MS-7676 (H67MA-ED55(B3))", OK, "http://www.msi.com/product/mb/H67MA-ED55--B3-.html", "Seems to work fine basically, but user reported (hopefully unrelated) buggy behavior of the board after a firmware upgrade. See https://flashrom.org/pipermail/flashrom/2012-January/008547.html"),
+ B("MSI", "MS-7676 (Z68MA-G45 (B3))", OK, "http://www.msi.com/product/mb/Z68MA-G45--B3-.html", NULL),
+ B("MSI", "MS-7696 (A75MA-G55)", OK, "http://www.msi.com/product/mb/A75MA-G55.html", NULL),
+ B("MSI", "MS-7698 (E350IA-E45)", OK, "http://www.msi.com/product/mb/E350IA-E45.html", NULL),
+ B("MSI", "MS-7740 (H61MA-E35(B3))", OK, "http://www.msi.com/product/mb/H61MA-E35--B3-.html", NULL),
+ B("MSI", "MS-7756 (H77MA-G43)", OK, "http://www.msi.com/product/mb/H77MA-G43.html", NULL),
+ B("MSI", "MS-7760 (X79A-GD45 (8D))", OK, "http://www.msi.com/product/mb/X79A-GD45-8D.html", NULL),
+ B("MSI", "MS-7808 (B75MA-E33)", OK, "http://www.msi.com/product/mb/B75MA-E33.html", NULL),
+ B("MSI", "MS-7816 (H87-G43)", OK, "http://www.msi.com/product/mb/H87-G43.html", NULL),
+ B("MSI", "MS-7817 (H81M-E33)", OK, "http://www.msi.com/product/mb/H81ME33.html", NULL),
+ B("MSI", "MS-9830 (IM-945GSE-A, A9830IMS)", OK, "http://www.msi.com/product/ipc/IM-945GSE-A.html", NULL),
+ B("NEC", "PowerMate 2000", OK, "http://support.necam.com/mobilesolutions/hardware/Desktops/pm2000/celeron/", NULL),
+ B("Nokia", "IP530", OK, NULL, NULL),
+ B("Palit", "N61S", OK, NULL, NULL),
+ B("PCCHIPS ", "M598LMR (V9.0)", OK, NULL, NULL),
+ B("PCCHIPS ", "M863G (V5.1A)", OK, "http://www.pcchips.com.tw/PCCWebSite/Products/ProductsDetail.aspx?CategoryID=1&DetailID=343&DetailName=Feature&MenuID=1&LanID=0", NULL),
+ B("PC Engines", "Alix.1c", OK, "http://pcengines.ch/alix1c.htm", NULL),
+ B("PC Engines", "Alix.2c2", OK, "http://pcengines.ch/alix2c2.htm", NULL),
+ B("PC Engines", "Alix.2c3", OK, "http://pcengines.ch/alix2c3.htm", NULL),
+ B("PC Engines", "Alix.2d3", OK, "http://pcengines.ch/alix2d3.htm", NULL),
+ B("PC Engines", "Alix.3c3", OK, "http://pcengines.ch/alix3c3.htm", NULL),
+ B("PC Engines", "Alix.3d3", OK, "http://pcengines.ch/alix3d3.htm", NULL),
+ B("PC Engines", "Alix.6f2", OK, "http://pcengines.ch/alix6f2.htm", NULL),
+ B("PC Engines", "APU", OK, "http://pcengines.ch/apu.htm", NULL),
+ B("PC Engines", "WRAP.2E", OK, "http://pcengines.ch/wrap2e1.htm", NULL),
+ B("PCWARE", "APM80-D3", OK, "http://www.pcwarebr.com.br/produtos_mb_apm80-d3.php", "Probably manufactured by ASUS"),
+ B("Pegatron", "IPP7A-CP", OK, NULL, NULL),
+ B("Portwell", "PEB-4700VLA", OK, "http://www.portwell.com/products/detail.asp?CUSTCHAR1=PEB-4700VLA", NULL),
+ B("RCA", "RM4100", OK, "http://www.settoplinux.org/index.php?title=RCA_RM4100", NULL),
+ B("Samsung", "Polaris 32", OK, NULL, NULL),
+ B("SAPPHIRE", "IPC-E350M1", OK, "http://www.sapphiretech.com/presentation/product/?pid=1034&lid=1", NULL),
+ B("Shuttle", "AB61", OK, "http://www.shuttle.eu/_archive/older/de/ab61.htm", NULL),
+ B("Shuttle", "AK31", OK, "http://www.motherboard.cz/mb/shuttle/AK31.htm", NULL),
+ B("Shuttle", "AK38N", OK, "http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/", NULL),
+ B("Shuttle", "AV11V30", OK, NULL, NULL),
+ B("Shuttle", "AV18E2", OK, "http://www.shuttle.eu/_archive/older/de/av18.htm", NULL),
+ B("Shuttle", "FB61", OK, "http://www.shuttle.eu/_archive/older/en/fb61.htm#mainboardfb6", "Used in SB61G2 systems."),
+ B("Shuttle", "FD37", OK, "http://www.shuttle.eu/products/discontinued/barebones/sd37p2/", NULL),
+ B("Shuttle", "FH67", OK, "http://www.shuttle.eu/products/mini-pc/sh67h3/specification/", NULL),
+ B("Shuttle", "FN25", OK, "http://www.shuttle.eu/products/discontinued/barebones/sn25p/?0=", NULL),
+ B("Shuttle", "FN78S", OK, "http://www.shuttle.eu/products/discontinued/barebones/sn78sh7/", NULL),
+ B("Shuttle", "X50/X50(B)", OK, "http://au.shuttle.com/product_detail_spec.jsp?PI=1241", NULL),
+ B("Soyo", "SY-5VD", BAD, "http://www.soyo.com/content/Downloads/163/&c=80&p=464&l=English", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
+ B("Soyo", "SY-6BA+ III", OK, "http://www.motherboard.cz/mb/soyo/SY-6BA+III.htm", NULL),
+ B("Soyo", "SY-7VCA", OK, "http://www.tomshardware.com/reviews/12-socket-370-motherboards,196-15.html", NULL),
+ B("Sun", "Blade x6250", OK, "http://www.sun.com/servers/blades/x6250/", NULL),
+ B("Sun", "Fire x4150", BAD, "http://www.sun.com/servers/x64/x4150/", "No public report found. May work now."),
+ B("Sun", "Fire x4200", BAD, "http://www.sun.com/servers/entry/x4200/", "No public report found. May work now."),
+ B("Sun", "Fire x4540", BAD, "http://www.sun.com/servers/x64/x4540/", "No public report found. May work now."),
+ B("Sun", "Fire x4600", BAD, "http://www.sun.com/servers/x64/x4600/", "No public report found. May work now."),
+ B("Sun", "Ultra 40 M2", OK, "http://download.oracle.com/docs/cd/E19127-01/ultra40.ws/820-0123-13/intro.html", NULL),
+ B("Supermicro", "A1SAi-2550F", OK, "http://www.supermicro.com/products/motherboard/Atom/X10/A1SAi-2550F.cfm", NULL),
+ B("Supermicro", "H8QC8", OK, "http://www.supermicro.com/Aplus/motherboard/Opteron/nforce/H8QC8.cfm", NULL),
+ B("Supermicro", "H8QME-2", OK, "http://www.supermicro.com/Aplus/motherboard/Opteron8000/MCP55/H8QME-2.cfm", NULL),
+ B("Supermicro", "X10SLM-F", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C220/X10SLM-F.cfm", "Probing works (Winbond W25Q128, 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked; SMM protection enabled."),
+ B("Supermicro", "X5DP8-G2", OK, "http://www.supermicro.com/products/motherboard/Xeon/E7501/X5DP8-G2.cfm", NULL),
+ B("Supermicro", "X7DBT-INF", OK, "http://www.supermicro.com/products/motherboard/Xeon1333/5000P/X7DBT-INF.cfm", NULL),
+ B("Supermicro", "X7DWT", OK, "http://www.supermicro.com/products/motherboard/Xeon1333/5400/X7DWT.cfm", "Used in Dell C6100 servers."),
+ B("Supermicro", "X7SPA-H(F)", OK, "http://www.supermicro.com/products/motherboard/ATOM/ICH9/X7SPA.cfm?typ=H", NULL),
+ B("Supermicro", "X7SPE-HF-D525", OK, "http://www.supermicro.com/products/motherboard/ATOM/ICH9/X7SPE-HF-D525.cfm", NULL),
+ B("Supermicro", "X8DT3", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DT3.cfm", NULL),
+ B("Supermicro", "X8DT6-F", OK, "http://www.supermicro.nl/products/motherboard/QPI/5500/X8DT6-F.cfm?IPMI=Y&SAS=Y", NULL),
+ B("Supermicro", "X8DTE-F", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DT6-F.cfm?IPMI=Y&SAS=N", NULL),
+ B("Supermicro", "X8DTG-D", OK, "http://www.supermicro.com/products/motherboard/qpi/5500/x8dtg-df.cfm", NULL),
+ B("Supermicro", "X8DTH-6F", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTH-6F.cfm", NULL),
+ B("Supermicro", "X8DTT-F", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTT-F.cfm", NULL),
+ B("Supermicro", "X8DTT-HIBQF", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTT-H.cfm", NULL),
+ B("Supermicro", "X8DTU-6TF+", BAD, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTU_.cfm?TYP=SAS&LAN=10", "Probing works (Atmel AT25DF321A, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Supermicro", "X8DTU-F", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTU-F.cfm", NULL),
+ B("Supermicro", "X8SAX", OK, "http://www.supermicro.com/products/motherboard/xeon3000/x58/x8sax.cfm", NULL),
+ B("Supermicro", "X8SIE(-F)", BAD, "http://www.supermicro.com/products/motherboard/Xeon3000/3400/X8SIE.cfm?IPMI=N&TYP=LN2", "Requires unlocking the ME although the registers are set up correctly by the descriptor/BIOS already (tested with swseq and hwseq)."),
+ B("Supermicro", "X8SIL-F", OK, "http://www.supermicro.com/products/motherboard/Xeon3000/3400/X8SIL.cfm", NULL),
+ B("Supermicro", "X8STi", OK, "http://www.supermicro.com/products/motherboard/Xeon3000/X58/X8STi.cfm", NULL),
+ B("Supermicro", "X9DR3-F", BAD, "http://www.supermicro.com/products/motherboard/xeon/c600/x9dr3-f.cfm", "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Supermicro", "X9DRD-7LN4F", BAD, "http://www.supermicro.com/products/motherboard/xeon/c600/x9drd-7ln4f.cfm", "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Supermicro", "X9DRT-HF+", BAD, NULL, "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked; SMM protection enabled."),
+ B("Supermicro", "X9DRW", BAD, NULL, "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Supermicro", "X9QRi-F+", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C600/X9QRi-F_.cfm", "Probing works (Macronix MX25L12805, 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked; SMM protection enabled."),
+ B("Supermicro", "X9SCA-F", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCA-F.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Supermicro", "X9SCE-F", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCE-F.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Supermicro", "X9SCL", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCL.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Supermicro", "X9SCM-F", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCM-F.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("T-Online", "S-100", OK, "http://wiki.freifunk-hannover.de/T-Online_S_100", NULL),
+ B("Tekram", "P6Pro-A5", OK, "http://www.motherboard.cz/mb/tekram/P6Pro-A5.htm", NULL),
+ B("Termtek", "TK-3370 (Rev:2.5B)", OK, NULL, NULL),
+ B("Thomson", "IP1000", OK, "http://www.settoplinux.org/index.php?title=Thomson_IP1000", NULL),
+ B("TriGem", "Anaheim-3", OK, "http://www.e4allupgraders.info/dir1/motherboards/socket370/anaheim3.shtml", NULL),
+ B("TriGem", "Lomita", OK, "http://www.e4allupgraders.info/dir1/motherboards/socket370/lomita.shtml", NULL),
+ B("Tyan", "S1846 (Tsunami ATX)", OK, "http://www.tyan.com/archive/products/html/tsunamiatx.html", NULL),
+ B("Tyan", "S2466 (Tiger MPX)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=461", NULL),
+ B("Tyan", "S2498 (Tomcat K7M)", OK, "http://www.tyan.com/archive/products/html/tomcatk7m.html", NULL),
+ B("Tyan", "S2723 (Tiger i7501)", OK, "http://www.tyan.com/archive/products/html/tigeri7501.html", NULL),
+ B("Tyan", "S2875 (Tiger K8W)", OK, "http://www.tyan.com/archive/products/html/tigerk8w.html", NULL),
+ B("Tyan", "S2881 (Thunder K8SR)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=115", NULL),
+ B("Tyan", "S2882-D (Thunder K8SD Pro)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=127", NULL),
+ B("Tyan", "S2882 (Thunder K8S Pro)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=121", NULL),
+ B("Tyan", "S2891 (Thunder K8SRE)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=144", NULL),
+ B("Tyan", "S2892 (Thunder K8SE)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=145", NULL),
+ B("Tyan", "S2895 (Thunder K8WE)", OK, "http://www.tyan.com/archive/products/html/thunderk8we.html", NULL),
+ B("Tyan", "S2912 (Thunder n3600R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=157", NULL),
+ B("Tyan", "S2915-E (Thunder n6650W)", OK, "http://tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=541&SKU=600000041", NULL),
+ B("Tyan", "S2915 (Thunder n6650W)", OK, "http://tyan.com/product_board_detail.aspx?pid=163", NULL),
+ B("Tyan", "S2933 (Thunder n3600S)", OK, "http://tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=478&SKU=600000063", NULL),
+ B("Tyan", "S3095 (Tomcat i945GM)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=181", NULL),
+ B("Tyan", "S3992 (Thunder h2000M)", OK, "http://tyan.com/product_board_detail.aspx?pid=235", NULL),
+ B("Tyan", "S4882 (Thunder K8QS Pro)", OK, "http://www.tyan.com/archive/products/html/thunderk8qspro.html", NULL),
+ B("Tyan", "S5180 (Toledo i965R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=456", NULL),
+ B("Tyan", "S5191 (Toledo i3000R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=343", NULL),
+ B("Tyan", "S5197 (Toledo i3010W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=349", NULL),
+ B("Tyan", "S5211-1U (Toledo i3200R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=593", NULL),
+ B("Tyan", "S5211 (Toledo i3210W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=591", NULL),
+ B("Tyan", "S5220 (Toledo q35T)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=597", NULL),
+ B("Tyan", "S5375-1U (Tempest i5100X)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=610", NULL),
+ B("Tyan", "S5375 (Tempest i5100X)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=566", NULL),
+ B("Tyan", "S5376 (Tempest i5100W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=605", "Both S5376G2NR and S5376WAG2NR should work."),
+ B("Tyan", "S5377 (Tempest i5100T)", OK, "http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=642&SKU=600000017", NULL),
+ B("Tyan", "S5382 (Tempest i5000PW)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=439", NULL),
+ B("Tyan", "S5397 (Tempest i5400PW)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=560", NULL),
+ B("Tyan", "S7066 (S7066WGM3NR)", BAD, "http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=790&SKU=600000330", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("VIA", "EITX-3000", OK, "http://www.viaembedded.com/en/products/boards/810/1/EITX-3000.html", NULL),
+ B("VIA", "EPIA M/MII/...", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=202", NULL), /* EPIA-MII link for now */
+ B("VIA", "EPIA SP", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=261", NULL),
+ B("VIA", "EPIA-CN", OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=400", NULL),
+ B("VIA", "EPIA EK", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?motherboard_id=420", NULL),
+ B("VIA", "EPIA-EX15000G", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=450", NULL),
+ B("VIA", "EPIA-LN", OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=473", NULL),
+ B("VIA", "EPIA-M700", OK, "http://via.com.tw/servlet/downloadSvl?motherboard_id=670&download_file_id=3700", NULL),
+ B("VIA", "EPIA-N/NL", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=221", NULL), /* EPIA-N link for now */
+ B("VIA", "EPIA-NX15000G", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=470", NULL),
+ B("VIA", "NAB74X0", OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=590", NULL),
+ B("VIA", "pc2500e", OK, "http://www.via.com.tw/en/initiatives/empowered/pc2500_mainboard/index.jsp", NULL),
+ B("VIA", "PC3500G", OK, "http://www.via.com.tw/en/initiatives/empowered/pc3500_mainboard/index.jsp", NULL),
+ B("VIA", "VB700X", OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=490", NULL),
+ B("ZOTAC", "Fusion-ITX WiFi (FUSION350-A-E)", OK, NULL, NULL),
+ B("ZOTAC", "GeForce 8200", OK, NULL, NULL),
+ B("ZOTAC", "H61-ITX WiFi (H61ITX-A-E)", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ZOTAC", "H67-ITX WiFi (H67ITX-C-E)", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("ZOTAC", "IONITX-A-E", OK, NULL, NULL),
+ B("ZOTAC", "IONITX-F-E", OK, NULL, NULL),
+ B("ZOTAC", "nForce 630i Supreme (N73U-Supreme)", OK, NULL, NULL),
+ B("ZOTAC", "ZBOX AD02 (PLUS)", OK, NULL, NULL),
+ B("ZOTAC", "ZBOX HD-ID11", OK, NULL, NULL),
+#endif
+
+ {0},
+};
+
+/* Please keep this list alphabetically ordered by vendor/board. */
+const struct board_info laptops_known[] = {
+#if defined(__i386__) || defined(__x86_64__)
+ B("Acer", "Aspire 1520", OK, "http://support.acer.com/us/en/acerpanam/notebook/0000/Acer/Aspire1520/Aspire1520nv.shtml", NULL),
+ B("Acer", "Aspire One", BAD, NULL, "http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html"),
+ B("ASUS", "A8Jm", OK, NULL, NULL),
+ B("ASUS", "Eee PC 701 4G", BAD, "https://www.asus.com/Eee/Eee_PC/Eee_PC_4G/", "It seems the chip (25X40) is behind some SPI flash translation layer (likely in the EC, the ENE KB3310)."),
+ B("ASUS", "M6Ne", NT, NULL, "Untested board enable."),
+ B("ASUS", "U38N", OK, NULL, NULL),
+ B("Clevo", "P150HM", BAD, "http://www.clevo.com.tw/en/products/prodinfo_2.asp?productid=307", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
+ B("Dell", "Latitude D630", OK, NULL, NULL),
+ B("Dell", "Inspiron 1420", OK, NULL, NULL),
+ B("Dell", "Latitude CPi A366XT", BAD, "http://www.coreboot.org/Dell_Latitude_CPi_A366XT", "The laptop immediately powers off if you try to hot-swap the chip. It's not yet tested if write/erase would work on this laptop."),
+ B("Dell", "Vostro 3700", BAD, NULL, "Locked ME, see https://flashrom.org/pipermail/flashrom/2012-May/009197.html."),
+ B("Dell", "Latitude E6520", BAD, NULL, "Locked ME, see https://flashrom.org/pipermail/flashrom/2012-June/009420.html."),
+ B("Elitegroup", "A928", OK, NULL, "Bootsector is locked and needs to be skipped with a layout file (writeable address range is 00000000:0003bfff)."),
+ B("Fujitsu", "Amilo Xi 3650", OK, NULL, NULL),
+ B("HP/Compaq", "EliteBook 8560p", BAD, NULL, "SPI lock down, SMM protection, PR in BIOS region, read-only descriptor, locked ME region."),
+ B("HP/Compaq", "nx9005", BAD, "http://h18000.www1.hp.com/products/quickspecs/11602_na/11602_na.HTML", "Shuts down when probing for a chip. https://flashrom.org/pipermail/flashrom/2010-May/003321.html"),
+ B("HP/Compaq", "nx9010", BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514", "Hangs upon '''flashrom -V''' (needs hard power-cycle then)."),
+ B("IBM/Lenovo", "ThinkPad T40p", BAD, "http://www.thinkwiki.org/wiki/Category:T40p", NULL),
+ B("IBM/Lenovo", "ThinkPad T410s", BAD, "http://www.thinkwiki.org/wiki/Category:T410s", "Probing works (Winbond W25X64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs) and ME is locked. Also, a Protected Range is locking the top range of the BIOS region (presumably the boot block)."),
+ B("IBM/Lenovo", "ThinkPad T420", BAD, "http://www.thinkwiki.org/wiki/Category:T420", "Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs) and ME is locked. Also, a Protected Range is locking the top range of the BIOS region (presumably the boot block)."),
+ B("IBM/Lenovo", "ThinkPad X1", BAD, "http://www.thinkwiki.org/wiki/Category:X1", "Probing works (ST M25PX64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs) and ME is locked. Also, a Protected Range is locking the top range of the BIOS region (presumably the boot block)."),
+ B("IBM/Lenovo", "ThinkPad T530", DEP, "http://www.thinkwiki.org/wiki/Category:T530", "Works fine but only with coreboot (due to locked regions and additional PR restrictions)."),
+ B("IBM/Lenovo", "ThinkPad 240", BAD, "http://www.stanford.edu/~bresnan//tp240.html", "Seems to (partially) work at first, but one block/sector cannot be written which then leaves you with a bricked laptop. Maybe this can be investigated and fixed in software later."),
+ B("IBM/Lenovo", "3000 V100 TF05Cxx", OK, "http://www5.pc.ibm.com/europe/products.nsf/products?openagent&brand=Lenovo3000Notebook&series=Lenovo+3000+V+Series#viewallmodelstop", NULL),
+ //B("MSI", "GT60-2OD", OK, "http://www.msi.com/product/nb/GT60_2OD.html", NULL), requires layout patches
+ B("Teclast", "X98 Air 3G", OK, NULL, NULL),
+#endif
+
+ {0},
+};
diff --git a/layout.c b/layout.c
index 272912c68..e46e61ae5 100644
--- a/layout.c
+++ b/layout.c
@@ -15,6 +15,7 @@
* GNU General Public License for more details.
*/
+#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@@ -24,35 +25,62 @@
#include "programmer.h"
#include "layout.h"
-static struct romentry entries[MAX_ROMLAYOUT];
-static struct flashrom_layout global_layout = { entries, 0 };
+struct flashrom_layout {
+ struct romentry *head;
+};
-struct flashrom_layout *get_global_layout(void)
+struct layout_include_args {
+ char *name;
+ char *file;
+ struct layout_include_args *next;
+};
+
+const struct flashrom_layout *get_default_layout(const struct flashrom_flashctx *const flashctx)
{
- return &global_layout;
+ return flashctx->default_layout;
}
const struct flashrom_layout *get_layout(const struct flashrom_flashctx *const flashctx)
{
- if (flashctx->layout && flashctx->layout->num_entries)
+ if (flashctx->layout)
return flashctx->layout;
else
- return &flashctx->fallback_layout.base;
+ return get_default_layout(flashctx);
+}
+
+static struct romentry *mutable_layout_next(
+ const struct flashrom_layout *const layout, struct romentry *iterator)
+{
+ return iterator ? iterator->next : layout->head;
+}
+
+static struct romentry *_layout_entry_by_name(
+ const struct flashrom_layout *const layout, const char *name)
+{
+ struct romentry *entry = NULL;
+ if (!layout || !name)
+ return NULL;
+ while ((entry = mutable_layout_next(layout, entry))) {
+ if (!strcmp(entry->region.name, name))
+ return entry;
+ }
+ return NULL;
}
#ifndef __LIBPAYLOAD__
-int read_romlayout(const char *name)
+int layout_from_file(struct flashrom_layout **layout, const char *name)
{
- struct flashrom_layout *const layout = get_global_layout();
FILE *romlayout;
char tempstr[256], tempname[256];
- unsigned int i;
int ret = 1;
+ if (flashrom_layout_new(layout))
+ return 1;
+
romlayout = fopen(name, "r");
if (!romlayout) {
- msg_gerr("ERROR: Could not open ROM layout (%s).\n",
+ msg_gerr("ERROR: Could not open layout file (%s).\n",
name);
return -1;
}
@@ -60,11 +88,6 @@ int read_romlayout(const char *name)
while (!feof(romlayout)) {
char *tstr1, *tstr2;
- if (layout->num_entries >= MAX_ROMLAYOUT) {
- msg_gerr("Maximum number of ROM images (%i) in layout "
- "file reached.\n", MAX_ROMLAYOUT);
- goto _close_ret;
- }
if (2 != fscanf(romlayout, "%255s %255s\n", tempstr, tempname))
continue;
#if 0
@@ -79,23 +102,10 @@ int read_romlayout(const char *name)
msg_gerr("Error parsing layout file. Offending string: \"%s\"\n", tempstr);
goto _close_ret;
}
- layout->entries[layout->num_entries].start = strtol(tstr1, (char **)NULL, 16);
- layout->entries[layout->num_entries].end = strtol(tstr2, (char **)NULL, 16);
- layout->entries[layout->num_entries].included = false;
- layout->entries[layout->num_entries].name = strdup(tempname);
- if (!layout->entries[layout->num_entries].name) {
- msg_gerr("Error adding layout entry: %s\n", strerror(errno));
+ if (flashrom_layout_add_region(*layout,
+ strtol(tstr1, NULL, 16), strtol(tstr2, NULL, 16), tempname))
goto _close_ret;
- }
- layout->num_entries++;
}
-
- for (i = 0; i < layout->num_entries; i++) {
- msg_gdbg("romlayout %08x - %08x named %s\n",
- layout->entries[i].start,
- layout->entries[i].end, layout->entries[i].name);
- }
-
ret = 0;
_close_ret:
@@ -104,45 +114,128 @@ _close_ret:
}
#endif
+static bool parse_include_args(const char *arg, char **name, char **file)
+{
+ char *colon;
+ char *tmp_name;
+ char *tmp_file = NULL; /* file is optional, so defaults to NULL */
+
+ if (arg == NULL) {
+ msg_gerr("<NULL> is a bad region name.\n");
+ return false;
+ }
+
+ /* -i <image>[:<file>] */
+ colon = strchr(arg, ':');
+ if (colon && !colon[1]) {
+ msg_gerr("Missing filename parameter in %s\n", arg);
+ return false;
+ }
+
+ if (colon) {
+ tmp_name = strndup(arg, colon - arg);
+ if (!tmp_name) {
+ msg_gerr("Out of memory\n");
+ goto error;
+ }
+
+ tmp_file = strdup(colon + 1);
+ if (!tmp_file) {
+ msg_gerr("Out of memory\n");
+ goto error;
+ }
+ } else {
+ tmp_name = strdup(arg);
+ }
+
+ *name = tmp_name;
+ *file = tmp_file;
+
+ return true;
+
+error:
+ free(tmp_name);
+ free(tmp_file);
+ return false;
+}
+
/* register an include argument (-i) for later processing */
-int register_include_arg(struct layout_include_args **args, char *name)
+int register_include_arg(struct layout_include_args **args, const char *arg)
{
struct layout_include_args *tmp;
- if (name == NULL) {
- msg_gerr("<NULL> is a bad region name.\n");
+ char *name;
+ char *file;
+
+ if (!parse_include_args(arg, &name, &file))
return 1;
- }
- tmp = *args;
- while (tmp) {
+ for (tmp = *args; tmp; tmp = tmp->next) {
if (!strcmp(tmp->name, name)) {
msg_gerr("Duplicate region name: \"%s\".\n", name);
- return 1;
+ goto error;
}
- tmp = tmp->next;
}
- tmp = malloc(sizeof(struct layout_include_args));
+ tmp = malloc(sizeof(*tmp));
if (tmp == NULL) {
- msg_gerr("Could not allocate memory");
- return 1;
+ msg_gerr("Out of memory\n");
+ goto error;
}
tmp->name = name;
+ tmp->file = file;
tmp->next = *args;
*args = tmp;
-
return 0;
+
+error:
+ free(name);
+ free(file);
+ return 1;
+}
+
+static char *sanitise_filename(char *filename)
+{
+ for (unsigned i = 0; filename[i]; i++) {
+ if (isspace((unsigned char)filename[i]))
+ filename[i] = '_';
+ }
+ return filename;
+}
+
+/* returns 0 to indicate success, 1 to indicate failure */
+static int include_region(struct flashrom_layout *const l, const char *name,
+ const char *file)
+{
+ struct romentry *const entry = _layout_entry_by_name(l, name);
+ if (entry) {
+ entry->included = true;
+ if (file)
+ entry->file = sanitise_filename(strdup(file));
+ return 0;
+ }
+ return 1;
+}
+
+/* returns 0 to indicate success, 1 to indicate failure */
+static int exclude_region(struct flashrom_layout *const l, const char *name)
+{
+ struct romentry *const entry = _layout_entry_by_name(l, name);
+ if (entry) {
+ entry->included = false;
+ return 0;
+ }
+ return 1;
}
/* returns -1 if an entry is not found, 0 if found. */
-static int find_romentry(struct flashrom_layout *const l, char *name)
+static int romentry_exists(struct flashrom_layout *const l, char *name, char *file)
{
- if (l->num_entries == 0)
+ if (!l->head)
return -1;
msg_gspew("Looking for region \"%s\"... ", name);
- if (flashrom_layout_include_region(l, name)) {
+ if (include_region(l, name, file)) {
msg_gspew("not found.\n");
return -1;
}
@@ -161,8 +254,8 @@ int process_include_args(struct flashrom_layout *l, const struct layout_include_
if (args == NULL)
return 0;
- /* User has specified an area, but no layout file is loaded. */
- if (l->num_entries == 0) {
+ /* User has specified an include argument, but no layout is loaded. */
+ if (!l || !l->head) {
msg_gerr("Region requested (with -i \"%s\"), "
"but no layout data is available.\n",
args->name);
@@ -171,7 +264,7 @@ int process_include_args(struct flashrom_layout *l, const struct layout_include_
tmp = args;
while (tmp) {
- if (find_romentry(l, tmp->name) < 0) {
+ if (romentry_exists(l, tmp->name, tmp->file) < 0) {
msg_gerr("Invalid region specified: \"%s\".\n",
tmp->name);
return 1;
@@ -180,10 +273,14 @@ int process_include_args(struct flashrom_layout *l, const struct layout_include_
found++;
}
- msg_ginfo("Using region%s:", found > 1 ? "s" : "");
+ msg_ginfo("Using region%s: ", found > 1 ? "s" : "");
tmp = args;
while (tmp) {
- msg_ginfo(" \"%s\"%s", tmp->name, found > 1 ? "," : "");
+ msg_ginfo("\"%s\"", tmp->name);
+ if (tmp->file)
+ msg_ginfo(":\"%s\"", tmp->file);
+ if (found > 1)
+ msg_ginfo(", ");
found--;
tmp = tmp->next;
}
@@ -191,43 +288,69 @@ int process_include_args(struct flashrom_layout *l, const struct layout_include_
return 0;
}
-void layout_cleanup(struct layout_include_args **args)
+/* returns boolean 1 if any regions overlap, 0 otherwise */
+int included_regions_overlap(const struct flashrom_layout *const l)
+{
+ const struct romentry *lhs = NULL;
+ int overlap_detected = 0;
+
+ while ((lhs = layout_next(l, lhs))) {
+ if (!lhs->included)
+ continue;
+
+ const struct romentry *rhs = lhs;
+ while ((rhs = layout_next(l, rhs))) {
+ if (!rhs->included)
+ continue;
+
+ const struct flash_region *rhsr = &rhs->region;
+ const struct flash_region *lhsr = &lhs->region;
+
+ if (lhsr->start > rhsr->end)
+ continue;
+
+ if (lhsr->end < rhsr->start)
+ continue;
+
+ msg_gwarn("Regions %s [0x%08"PRIx32"-0x%08"PRIx32"] and %s [0x%08"PRIx32"-0x%08"PRIx32"] overlap\n",
+ lhsr->name, lhsr->start, lhsr->end, rhsr->name, rhsr->start, rhsr->end);
+ overlap_detected = 1;
+ }
+ }
+ return overlap_detected;
+}
+
+void cleanup_include_args(struct layout_include_args **args)
{
- struct flashrom_layout *const layout = get_global_layout();
- unsigned int i;
struct layout_include_args *tmp;
while (*args) {
tmp = (*args)->next;
+ free((*args)->name);
+ free((*args)->file);
free(*args);
*args = tmp;
}
-
- for (i = 0; i < layout->num_entries; i++) {
- free(layout->entries[i].name);
- layout->entries[i].included = false;
- }
- layout->num_entries = 0;
}
-/* Validate and - if needed - normalize layout entries. */
-int normalize_romentries(const struct flashctx *flash)
+int layout_sanity_checks(const struct flashrom_flashctx *const flash)
{
- struct flashrom_layout *const layout = get_global_layout();
- chipsize_t total_size = flash->chip->total_size * 1024;
+ const struct flashrom_layout *const layout = get_layout(flash);
+ const chipsize_t total_size = flash->chip->total_size * 1024;
int ret = 0;
- unsigned int i;
- for (i = 0; i < layout->num_entries; i++) {
- if (layout->entries[i].start >= total_size || layout->entries[i].end >= total_size) {
- msg_gwarn("Warning: Address range of region \"%s\" exceeds the current chip's "
- "address space.\n", layout->entries[i].name);
- if (layout->entries[i].included)
+ const struct romentry *entry = NULL;
+ while ((entry = layout_next(layout, entry))) {
+ const struct flash_region *region = &entry->region;
+ if (region->start >= total_size || region->end >= total_size) {
+ msg_gwarn("Warning: Address range of region \"%s\" "
+ "exceeds the current chip's address space.\n", region->name);
+ if (entry->included)
ret = 1;
}
- if (layout->entries[i].start > layout->entries[i].end) {
+ if (region->start > region->end) {
msg_gerr("Error: Size of the address range of region \"%s\" is not positive.\n",
- layout->entries[i].name);
+ region->name);
ret = 1;
}
}
@@ -235,19 +358,31 @@ int normalize_romentries(const struct flashctx *flash)
return ret;
}
+void prepare_layout_for_extraction(struct flashctx *flash)
+{
+ const struct flashrom_layout *const l = get_layout(flash);
+ struct romentry *entry = NULL;
+
+ while ((entry = mutable_layout_next(l, entry))) {
+ entry->included = true;
+
+ if (!entry->file)
+ entry->file = sanitise_filename(strdup(entry->region.name));
+ }
+}
+
const struct romentry *layout_next_included_region(
const struct flashrom_layout *const l, const chipoff_t where)
{
- unsigned int i;
- const struct romentry *lowest = NULL;
+ const struct romentry *entry = NULL, *lowest = NULL;
- for (i = 0; i < l->num_entries; ++i) {
- if (!l->entries[i].included)
+ while ((entry = layout_next(l, entry))) {
+ if (!entry->included)
continue;
- if (l->entries[i].end < where)
+ if (entry->region.end < where)
continue;
- if (!lowest || lowest->start > l->entries[i].start)
- lowest = &l->entries[i];
+ if (!lowest || lowest->region.start > entry->region.start)
+ lowest = entry;
}
return lowest;
@@ -256,62 +391,96 @@ const struct romentry *layout_next_included_region(
const struct romentry *layout_next_included(
const struct flashrom_layout *const layout, const struct romentry *iterator)
{
- const struct romentry *const end = layout->entries + layout->num_entries;
+ while ((iterator = layout_next(layout, iterator))) {
+ if (iterator->included)
+ break;
+ }
+ return iterator;
+}
- if (iterator)
- ++iterator;
- else
- iterator = &layout->entries[0];
+const struct romentry *layout_next(
+ const struct flashrom_layout *const layout, const struct romentry *iterator)
+{
+ return iterator ? iterator->next : layout->head;
+}
- for (; iterator < end; ++iterator) {
- if (!iterator->included)
- continue;
- return iterator;
+int flashrom_layout_new(struct flashrom_layout **const layout)
+{
+ *layout = calloc(1, sizeof(**layout));
+ if (!*layout) {
+ msg_gerr("Error creating layout: %s\n", strerror(errno));
+ return 1;
}
- return NULL;
+
+ return 0;
}
-/**
- * @addtogroup flashrom-layout
- * @{
- */
+int flashrom_layout_add_region(
+ struct flashrom_layout *const layout,
+ const size_t start, const size_t end, const char *const name)
+{
+ struct romentry *const entry = malloc(sizeof(*entry));
+ if (!entry)
+ goto _err_ret;
+
+ const struct romentry tmp = {
+ .next = layout->head,
+ .included = false,
+ .file = NULL,
+ .region = {
+ .start = start,
+ .end = end,
+ .name = strdup(name),
+ },
+ };
+ *entry = tmp;
+ if (!entry->region.name)
+ goto _err_ret;
+
+ msg_gdbg("Added layout entry %08zx - %08zx named %s\n", start, end, name);
+ layout->head = entry;
+ return 0;
+
+_err_ret:
+ msg_gerr("Error adding layout entry: %s\n", strerror(errno));
+ free(entry);
+ return 1;
+}
-/**
- * @brief Mark given region as included.
- *
- * @param layout The layout to alter.
- * @param name The name of the region to include.
- *
- * @return 0 on success,
- * 1 if the given name can't be found.
- */
int flashrom_layout_include_region(struct flashrom_layout *const layout, const char *name)
{
- size_t i;
- for (i = 0; i < layout->num_entries; ++i) {
- if (!strcmp(layout->entries[i].name, name)) {
- layout->entries[i].included = true;
- return 0;
- }
+ return include_region(layout, name, NULL);
+}
+
+int flashrom_layout_exclude_region(struct flashrom_layout *const layout, const char *name)
+{
+ return exclude_region(layout, name);
+}
+
+int flashrom_layout_get_region_range(struct flashrom_layout *const l, const char *name,
+ unsigned int *start, unsigned int *len)
+{
+ const struct romentry *const entry = _layout_entry_by_name(l, name);
+ if (entry) {
+ const struct flash_region *region = &entry->region;
+ *start = region->start;
+ *len = region->end - region->start + 1;
+ return 0;
}
return 1;
}
-/**
- * @brief Free a layout.
- *
- * @param layout Layout to free.
- */
void flashrom_layout_release(struct flashrom_layout *const layout)
{
- unsigned int i;
-
- if (!layout || layout == get_global_layout())
+ if (!layout)
return;
- for (i = 0; i < layout->num_entries; ++i)
- free(layout->entries[i].name);
+ while (layout->head) {
+ struct romentry *const entry = layout->head;
+ layout->head = entry->next;
+ free(entry->file);
+ free(entry->region.name);
+ free(entry);
+ }
free(layout);
}
-
-/** @} */ /* end flashrom-layout */
diff --git a/libflashrom.c b/libflashrom.c
index ae2d33daa..4a59e2a12 100644
--- a/libflashrom.c
+++ b/libflashrom.c
@@ -14,11 +14,6 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
-/**
- * @mainpage
- *
- * Have a look at the Modules section for a function reference.
- */
#include <errno.h>
#include <stdlib.h>
@@ -29,24 +24,14 @@
#include "fmap.h"
#include "programmer.h"
#include "layout.h"
-#include "hwaccess.h"
#include "ich_descriptors.h"
#include "libflashrom.h"
+#include "writeprotect.h"
-/**
- * @defgroup flashrom-general General
- * @{
- */
/** Pointer to log callback function. */
static flashrom_log_callback *global_log_callback = NULL;
-/**
- * @brief Initialize libflashrom.
- *
- * @param perform_selfcheck If not zero, perform a self check.
- * @return 0 on success
- */
int flashrom_init(const int perform_selfcheck)
{
if (perform_selfcheck && selfcheck())
@@ -55,28 +40,13 @@ int flashrom_init(const int perform_selfcheck)
return 0;
}
-/**
- * @brief Shut down libflashrom.
- * @return 0 on success
- */
int flashrom_shutdown(void)
{
return 0; /* TODO: nothing to do? */
}
/* TODO: flashrom_set_loglevel()? do we need it?
- For now, let the user decide in his callback. */
-
-/**
- * @brief Set the log callback function.
- *
- * Set a callback function which will be invoked whenever libflashrom wants
- * to output messages. This allows frontends to do whatever they see fit with
- * such messages, e.g. write them to syslog, or to file, or print them in a
- * GUI window, etc.
- *
- * @param log_callback Pointer to the new log callback function.
- */
+ For now, let the user decide in their callback. */
void flashrom_set_log_callback(flashrom_log_callback *const log_callback)
{
global_log_callback = log_callback;
@@ -95,84 +65,61 @@ int print(const enum flashrom_log_level level, const char *const fmt, ...)
return 0;
}
-/** @} */ /* end flashrom-general */
-
-
-
-/**
- * @defgroup flashrom-query Querying
- * @{
- */
-
-/**
- * @brief Returns flashrom version
- * @return flashrom version
- */
-const char *flashrom_version_info(void)
+void flashrom_set_progress_callback(struct flashrom_flashctx *flashctx, flashrom_progress_callback *progress_callback, struct flashrom_progress *progress_state)
{
- return flashrom_version;
+ flashctx->progress_callback = progress_callback;
+ flashctx->progress_state = progress_state;
}
-
-/**
- * @brief Returns list of supported programmers
- * @return List of supported programmers, or NULL if an error occurred
- */
-const char **flashrom_supported_programmers(void)
+/** @private */
+void update_progress(struct flashrom_flashctx *flashctx, enum flashrom_progress_stage stage, size_t current, size_t total)
{
- enum programmer p = 0;
- const char **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");
- }
+ if (flashctx->progress_callback == NULL)
+ return;
+ if (current > total)
+ current = total;
+
+ flashctx->progress_state->stage = stage;
+ flashctx->progress_state->current = current;
+ flashctx->progress_state->total = total;
+ flashctx->progress_callback(flashctx);
+}
- return supported_programmers;
+const char *flashrom_version_info(void)
+{
+ return flashrom_version;
}
-/**
- * @brief Returns list of supported flash chips
- * @return List of supported flash chips, or NULL if an error occurred
- */
struct flashrom_flashchip_info *flashrom_supported_flash_chips(void)
{
- unsigned int i = 0;
struct flashrom_flashchip_info *supported_flashchips =
malloc(flashchips_size * sizeof(*supported_flashchips));
- 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 =
- (enum flashrom_test_state)flashchips[i].tested.erase;
- supported_flashchips[i].tested.probe =
- (enum flashrom_test_state)flashchips[i].tested.probe;
- supported_flashchips[i].tested.read =
- (enum flashrom_test_state)flashchips[i].tested.read;
- supported_flashchips[i].tested.write =
- (enum flashrom_test_state)flashchips[i].tested.write;
- supported_flashchips[i].total_size = flashchips[i].total_size;
- }
- } else {
+ if (!supported_flashchips) {
msg_gerr("Memory allocation error!\n");
+ return NULL;
+ }
+
+ for (unsigned int i = 0; i < flashchips_size; ++i) {
+ supported_flashchips[i].vendor = flashchips[i].vendor;
+ supported_flashchips[i].name = flashchips[i].name;
+ supported_flashchips[i].tested.erase =
+ (enum flashrom_test_state)flashchips[i].tested.erase;
+ supported_flashchips[i].tested.probe =
+ (enum flashrom_test_state)flashchips[i].tested.probe;
+ supported_flashchips[i].tested.read =
+ (enum flashrom_test_state)flashchips[i].tested.read;
+ supported_flashchips[i].tested.write =
+ (enum flashrom_test_state)flashchips[i].tested.write;
+ supported_flashchips[i].total_size = flashchips[i].total_size;
}
return supported_flashchips;
}
-/**
- * @brief Returns list of supported mainboards
- * @return List of supported mainboards, or NULL if an error occurred
- */
struct flashrom_board_info *flashrom_supported_boards(void)
{
#if CONFIG_INTERNAL == 1
int boards_known_size = 0;
- int i = 0;
const struct board_info *binfo = boards_known;
while ((binfo++)->vendor)
@@ -182,17 +129,18 @@ struct flashrom_board_info *flashrom_supported_boards(void)
++boards_known_size;
struct flashrom_board_info *supported_boards =
- malloc(boards_known_size * sizeof(struct 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 =
- (enum flashrom_test_state) binfo[i].working;
- }
- } else {
+ malloc(boards_known_size * sizeof(*supported_boards));
+
+ if (!supported_boards) {
msg_gerr("Memory allocation error!\n");
+ return NULL;
+ }
+
+ for (int i = 0; i < boards_known_size; ++i) {
+ supported_boards[i].vendor = binfo[i].vendor;
+ supported_boards[i].name = binfo[i].name;
+ supported_boards[i].working =
+ (enum flashrom_test_state) binfo[i].working;
}
return supported_boards;
@@ -201,15 +149,10 @@ struct flashrom_board_info *flashrom_supported_boards(void)
#endif
}
-/**
- * @brief Returns list of supported chipsets
- * @return List of supported chipsets, or NULL if an error occurred
- */
struct flashrom_chipset_info *flashrom_supported_chipsets(void)
{
#if CONFIG_INTERNAL == 1
int chipset_enables_size = 0;
- int i = 0;
const struct penable *chipset = chipset_enables;
while ((chipset++)->vendor_name)
@@ -221,17 +164,18 @@ struct flashrom_chipset_info *flashrom_supported_chipsets(void)
struct flashrom_chipset_info *supported_chipsets =
malloc(chipset_enables_size * sizeof(*supported_chipsets));
- 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 =
- (enum flashrom_test_state) chipset[i].status;
- }
- } else {
+ if (!supported_chipsets) {
msg_gerr("Memory allocation error!\n");
+ return NULL;
+ }
+
+ for (int i = 0; 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 =
+ (enum flashrom_test_state) chipset[i].status;
}
return supported_chipsets;
@@ -240,62 +184,29 @@ struct flashrom_chipset_info *flashrom_supported_chipsets(void)
#endif
}
-/**
- * @brief Frees memory allocated by libflashrom API
- * @param Pointer to block of memory which should be freed
- * @return 0 on success
- */
int flashrom_data_free(void *const p)
{
free(p);
return 0;
}
-/** @} */ /* end flashrom-query */
-
-
-
-/**
- * @defgroup flashrom-prog Programmers
- * @{
- */
-
-/**
- * @brief Initialize the specified programmer.
- *
- * Currently, only one programmer may be initialized at a time.
- *
- * @param[out] flashprog Points to a pointer of type struct flashrom_programmer
- * that will be set if programmer initialization succeeds.
- * *flashprog has to be shutdown by the caller with @ref
- * flashrom_programmer_shutdown.
- * @param[in] prog_name Name of the programmer to initialize.
- * @param[in] prog_param Pointer to programmer specific parameters.
- * @return 0 on success
- */
int flashrom_programmer_init(struct flashrom_programmer **const flashprog,
const char *const prog_name, const char *const prog_param)
{
unsigned prog;
- for (prog = 0; prog < PROGRAMMER_INVALID; prog++) {
- if (strcmp(prog_name, programmer_table[prog].name) == 0)
+ for (prog = 0; prog < programmer_table_size; prog++) {
+ if (strcmp(prog_name, programmer_table[prog]->name) == 0)
break;
}
- if (prog >= PROGRAMMER_INVALID) {
+ if (prog >= programmer_table_size) {
msg_ginfo("Error: Unknown programmer \"%s\". Valid choices are:\n", prog_name);
list_programmers_linebreak(0, 80, 0);
return 1;
}
- return programmer_init(prog, prog_param);
+ return programmer_init(programmer_table[prog], prog_param);
}
-/**
- * @brief Shut down the initialized programmer.
- *
- * @param flashprog The programmer to shut down.
- * @return 0 on success
- */
int flashrom_programmer_shutdown(struct flashrom_programmer *const flashprog)
{
return programmer_shutdown();
@@ -303,33 +214,6 @@ int flashrom_programmer_shutdown(struct flashrom_programmer *const flashprog)
/* TODO: flashrom_programmer_capabilities()? */
-/** @} */ /* end flashrom-prog */
-
-
-
-/**
- * @defgroup flashrom-flash Flash chips
- * @{
- */
-
-/**
- * @brief Probe for a flash chip.
- *
- * Probes for a flash chip and returns a flash context, that can be used
- * later with flash chip and @ref flashrom-ops "image operations", if
- * exactly one matching chip is found.
- *
- * @param[out] flashctx Points to a pointer of type struct flashrom_flashctx
- * that will be set if exactly one chip is found. *flashctx
- * has to be freed by the caller with @ref flashrom_flash_release.
- * @param[in] flashprog The flash programmer used to access the chip.
- * @param[in] chip_name Name of a chip to probe for, or NULL to probe for
- * all known chips.
- * @return 0 on success,
- * 3 if multiple chips were found,
- * 2 if no chip was found,
- * or 1 on any other error.
- */
int flashrom_flash_probe(struct flashrom_flashctx **const flashctx,
const struct flashrom_programmer *const flashprog,
const char *const chip_name)
@@ -337,8 +221,6 @@ int flashrom_flash_probe(struct flashrom_flashctx **const flashctx,
int i, ret = 2;
struct flashrom_flashctx second_flashctx = { 0, };
- chip_to_probe = chip_name; /* chip_to_probe is global in flashrom.c */
-
*flashctx = malloc(sizeof(**flashctx));
if (!*flashctx)
return 1;
@@ -346,130 +228,80 @@ int flashrom_flash_probe(struct flashrom_flashctx **const flashctx,
for (i = 0; i < registered_master_count; ++i) {
int flash_idx = -1;
- if (!ret || (flash_idx = probe_flash(&registered_masters[i], 0, *flashctx, 0)) != -1) {
+ if (!ret || (flash_idx = probe_flash(&registered_masters[i], 0, *flashctx, 0, chip_name)) != -1) {
ret = 0;
/* We found one chip, now check that there is no second match. */
- if (probe_flash(&registered_masters[i], flash_idx + 1, &second_flashctx, 0) != -1) {
+ if (probe_flash(&registered_masters[i], flash_idx + 1, &second_flashctx, 0, chip_name) != -1) {
+ flashrom_layout_release(second_flashctx.default_layout);
+ free(second_flashctx.chip);
ret = 3;
break;
}
}
}
if (ret) {
- free(*flashctx);
+ flashrom_flash_release(*flashctx);
*flashctx = NULL;
}
return ret;
}
-/**
- * @brief Returns the size of the specified flash chip in bytes.
- *
- * @param flashctx The queried flash context.
- * @return Size of flash chip in bytes.
- */
size_t flashrom_flash_getsize(const struct flashrom_flashctx *const flashctx)
{
return flashctx->chip->total_size * 1024;
}
-/**
- * @brief Free a flash context.
- *
- * @param flashctx Flash context to free.
- */
void flashrom_flash_release(struct flashrom_flashctx *const flashctx)
{
+ if (!flashctx)
+ return;
+
+ flashrom_layout_release(flashctx->default_layout);
+ free(flashctx->chip);
free(flashctx);
}
-/**
- * @brief Set a flag in the given flash context.
- *
- * @param flashctx Flash context to alter.
- * @param flag Flag that is to be set / cleared.
- * @param value Value to set.
- */
void flashrom_flag_set(struct flashrom_flashctx *const flashctx,
const enum flashrom_flag flag, const bool value)
{
switch (flag) {
- case FLASHROM_FLAG_FORCE: flashctx->flags.force = value; break;
- case FLASHROM_FLAG_FORCE_BOARDMISMATCH: flashctx->flags.force_boardmismatch = value; break;
- case FLASHROM_FLAG_VERIFY_AFTER_WRITE: flashctx->flags.verify_after_write = value; break;
- case FLASHROM_FLAG_VERIFY_WHOLE_CHIP: flashctx->flags.verify_whole_chip = value; break;
+ case FLASHROM_FLAG_FORCE: flashctx->flags.force = value; break;
+ case FLASHROM_FLAG_FORCE_BOARDMISMATCH: flashctx->flags.force_boardmismatch = value; break;
+ case FLASHROM_FLAG_VERIFY_AFTER_WRITE: flashctx->flags.verify_after_write = value; break;
+ case FLASHROM_FLAG_VERIFY_WHOLE_CHIP: flashctx->flags.verify_whole_chip = value; break;
+ case FLASHROM_FLAG_SKIP_UNREADABLE_REGIONS: flashctx->flags.skip_unreadable_regions = value; break;
+ case FLASHROM_FLAG_SKIP_UNWRITABLE_REGIONS: flashctx->flags.skip_unwritable_regions = value; break;
}
}
-/**
- * @brief Return the current value of a flag in the given flash context.
- *
- * @param flashctx Flash context to read from.
- * @param flag Flag to be read.
- * @return Current value of the flag.
- */
bool flashrom_flag_get(const struct flashrom_flashctx *const flashctx, const enum flashrom_flag flag)
{
switch (flag) {
- case FLASHROM_FLAG_FORCE: return flashctx->flags.force;
- case FLASHROM_FLAG_FORCE_BOARDMISMATCH: return flashctx->flags.force_boardmismatch;
- case FLASHROM_FLAG_VERIFY_AFTER_WRITE: return flashctx->flags.verify_after_write;
- case FLASHROM_FLAG_VERIFY_WHOLE_CHIP: return flashctx->flags.verify_whole_chip;
- default: return false;
+ case FLASHROM_FLAG_FORCE: return flashctx->flags.force;
+ case FLASHROM_FLAG_FORCE_BOARDMISMATCH: return flashctx->flags.force_boardmismatch;
+ case FLASHROM_FLAG_VERIFY_AFTER_WRITE: return flashctx->flags.verify_after_write;
+ case FLASHROM_FLAG_VERIFY_WHOLE_CHIP: return flashctx->flags.verify_whole_chip;
+ case FLASHROM_FLAG_SKIP_UNREADABLE_REGIONS: return flashctx->flags.skip_unreadable_regions;
+ case FLASHROM_FLAG_SKIP_UNWRITABLE_REGIONS: return flashctx->flags.skip_unwritable_regions;
+ default: return false;
}
}
-/** @} */ /* end flashrom-flash */
-
-
-
-/**
- * @defgroup flashrom-layout Layout handling
- * @{
- */
-
-/**
- * @brief Read a layout from the Intel ICH descriptor in the flash.
- *
- * Optionally verify that the layout matches the one in the given
- * descriptor dump.
- *
- * @param[out] layout Points to a struct flashrom_layout pointer that
- * gets set if the descriptor is read and parsed
- * successfully.
- * @param[in] flashctx Flash context to read the descriptor from flash.
- * @param[in] dump The descriptor dump to compare to or NULL.
- * @param[in] len The length of the descriptor dump.
- *
- * @return 0 on success,
- * 6 if descriptor parsing isn't implemented for the host,
- * 5 if the descriptors don't match,
- * 4 if the descriptor dump couldn't be parsed,
- * 3 if the descriptor on flash couldn't be parsed,
- * 2 if the descriptor on flash couldn't be read,
- * 1 on any other error.
- */
int flashrom_layout_read_from_ifd(struct flashrom_layout **const layout, struct flashctx *const flashctx,
const void *const dump, const size_t len)
{
#ifndef __FLASHROM_LITTLE_ENDIAN__
return 6;
#else
- struct ich_layout dump_layout;
+ struct flashrom_layout *dump_layout = NULL, *chip_layout = NULL;
int ret = 1;
void *const desc = malloc(0x1000);
- struct ich_layout *const chip_layout = malloc(sizeof(*chip_layout));
- if (!desc || !chip_layout) {
- msg_gerr("Out of memory!\n");
- goto _free_ret;
- }
-
if (prepare_flash_access(flashctx, true, false, false, false))
goto _free_ret;
msg_cinfo("Reading ich descriptor... ");
- if (flashctx->chip->read(flashctx, desc, 0, 0x1000)) {
+ if (read_flash(flashctx, desc, 0, 0x1000)) {
msg_cerr("Read operation failed!\n");
msg_cinfo("FAILED.\n");
ret = 2;
@@ -477,7 +309,7 @@ int flashrom_layout_read_from_ifd(struct flashrom_layout **const layout, struct
}
msg_cinfo("done.\n");
- if (layout_from_ich_descriptors(chip_layout, desc, 0x1000)) {
+ if (layout_from_ich_descriptors(&chip_layout, desc, 0x1000)) {
msg_cerr("Couldn't parse the descriptor!\n");
ret = 3;
goto _finalize_ret;
@@ -490,8 +322,14 @@ int flashrom_layout_read_from_ifd(struct flashrom_layout **const layout, struct
goto _finalize_ret;
}
- if (chip_layout->base.num_entries != dump_layout.base.num_entries ||
- memcmp(chip_layout->entries, dump_layout.entries, sizeof(dump_layout.entries))) {
+ const struct romentry *chip_entry = layout_next(chip_layout, NULL);
+ const struct romentry *dump_entry = layout_next(dump_layout, NULL);
+ while (chip_entry && dump_entry && !memcmp(chip_entry, dump_entry, sizeof(*chip_entry))) {
+ chip_entry = layout_next(chip_layout, chip_entry);
+ dump_entry = layout_next(dump_layout, dump_entry);
+ }
+ flashrom_layout_release(dump_layout);
+ if (chip_entry || dump_entry) {
msg_cerr("Descriptors don't match!\n");
ret = 5;
goto _finalize_ret;
@@ -505,7 +343,7 @@ _finalize_ret:
finalize_flash_access(flashctx);
_free_ret:
if (ret)
- free(chip_layout);
+ flashrom_layout_release(chip_layout);
free(desc);
return ret;
#endif
@@ -516,31 +354,29 @@ static int flashrom_layout_parse_fmap(struct flashrom_layout **layout,
struct flashctx *const flashctx, const struct fmap *const fmap)
{
int i;
- struct flashrom_layout *l = get_global_layout();
+ char name[FMAP_STRLEN + 1];
+ const struct fmap_area *area;
+ struct flashrom_layout *l;
- if (!fmap || !l)
+ if (!fmap || flashrom_layout_new(&l))
return 1;
- if (l->num_entries + fmap->nareas > MAX_ROMLAYOUT) {
- msg_gerr("Cannot add fmap entries to layout - Too many entries.\n");
- return 1;
- }
+ for (i = 0, area = fmap->areas; i < fmap->nareas; i++, area++) {
+ if (area->size == 0) {
+ /* Layout regions use inclusive upper and lower bounds,
+ * so it's impossible to represent a region with zero
+ * size although it's allowed in fmap. */
+ msg_gwarn("Ignoring zero-size fmap region \"%s\";"
+ " empty regions are unsupported.\n",
+ area->name);
+ continue;
+ }
- for (i = 0; i < fmap->nareas; i++) {
- l->entries[l->num_entries].start = fmap->areas[i].offset;
- l->entries[l->num_entries].end = fmap->areas[i].offset + fmap->areas[i].size - 1;
- l->entries[l->num_entries].included = false;
- l->entries[l->num_entries].name =
- strndup((const char *)fmap->areas[i].name, FMAP_STRLEN);
- if (!l->entries[l->num_entries].name) {
- msg_gerr("Error adding layout entry: %s\n", strerror(errno));
+ snprintf(name, sizeof(name), "%s", area->name);
+ if (flashrom_layout_add_region(l, area->offset, area->offset + area->size - 1, name)) {
+ flashrom_layout_release(l);
return 1;
}
- msg_gdbg("fmap %08x - %08x named %s\n",
- l->entries[l->num_entries].start,
- l->entries[l->num_entries].end,
- l->entries[l->num_entries].name);
- l->num_entries++;
}
*layout = l;
@@ -548,22 +384,8 @@ static int flashrom_layout_parse_fmap(struct flashrom_layout **layout,
}
#endif /* __FLASHROM_LITTLE_ENDIAN__ */
-/**
- * @brief Read a layout by searching the flash chip for fmap.
- *
- * @param[out] layout Points to a struct flashrom_layout pointer that
- * gets set if the fmap is read and parsed successfully.
- * @param[in] flashctx Flash context
- * @param[in] offset Offset to begin searching for fmap.
- * @param[in] offset Length of address space to search.
- *
- * @return 0 on success,
- * 3 if fmap parsing isn't implemented for the host,
- * 2 if the fmap couldn't be read,
- * 1 on any other error.
- */
int flashrom_layout_read_fmap_from_rom(struct flashrom_layout **const layout,
- struct flashctx *const flashctx, off_t offset, size_t len)
+ struct flashctx *const flashctx, size_t offset, size_t len)
{
#ifndef __FLASHROM_LITTLE_ENDIAN__
return 3;
@@ -588,20 +410,6 @@ int flashrom_layout_read_fmap_from_rom(struct flashrom_layout **const layout,
#endif
}
-/**
- * @brief Read a layout by searching buffer for fmap.
- *
- * @param[out] layout Points to a struct flashrom_layout pointer that
- * gets set if the fmap is read and parsed successfully.
- * @param[in] flashctx Flash context
- * @param[in] buffer Buffer to search in
- * @param[in] size Size of buffer to search
- *
- * @return 0 on success,
- * 3 if fmap parsing isn't implemented for the host,
- * 2 if the fmap couldn't be read,
- * 1 on any other error.
- */
int flashrom_layout_read_fmap_from_buffer(struct flashrom_layout **const layout,
struct flashctx *const flashctx, const uint8_t *const buf, size_t size)
{
@@ -634,18 +442,98 @@ _ret:
#endif
}
-/**
- * @brief Set the active layout for a flash context.
- *
- * Note: This just sets a pointer. The caller must not release the layout
- * as long as he uses it through the given flash context.
- *
- * @param flashctx Flash context whose layout will be set.
- * @param layout Layout to bet set.
- */
void flashrom_layout_set(struct flashrom_flashctx *const flashctx, const struct flashrom_layout *const layout)
{
flashctx->layout = layout;
}
-/** @} */ /* end flashrom-layout */
+enum flashrom_wp_result flashrom_wp_cfg_new(struct flashrom_wp_cfg **cfg)
+{
+ *cfg = calloc(1, sizeof(**cfg));
+ return *cfg ? 0 : FLASHROM_WP_ERR_OTHER;
+}
+
+void flashrom_wp_cfg_release(struct flashrom_wp_cfg *cfg)
+{
+ free(cfg);
+}
+
+void flashrom_wp_set_mode(struct flashrom_wp_cfg *cfg, enum flashrom_wp_mode mode)
+{
+ cfg->mode = mode;
+}
+
+enum flashrom_wp_mode flashrom_wp_get_mode(const struct flashrom_wp_cfg *cfg)
+{
+ return cfg->mode;
+}
+
+void flashrom_wp_set_range(struct flashrom_wp_cfg *cfg, size_t start, size_t len)
+{
+ cfg->range.start = start;
+ cfg->range.len = len;
+}
+
+void flashrom_wp_get_range(size_t *start, size_t *len, const struct flashrom_wp_cfg *cfg)
+{
+ *start = cfg->range.start;
+ *len = cfg->range.len;
+}
+
+enum flashrom_wp_result flashrom_wp_write_cfg(struct flashctx *flash, const struct flashrom_wp_cfg *cfg)
+{
+ if (flash->mst->buses_supported & BUS_PROG && flash->mst->opaque.wp_write_cfg)
+ return flash->mst->opaque.wp_write_cfg(flash, cfg);
+
+ if (wp_operations_available(flash))
+ return wp_write_cfg(flash, cfg);
+
+ return FLASHROM_WP_ERR_OTHER;
+}
+
+enum flashrom_wp_result flashrom_wp_read_cfg(struct flashrom_wp_cfg *cfg, struct flashctx *flash)
+{
+ if (flash->mst->buses_supported & BUS_PROG && flash->mst->opaque.wp_read_cfg)
+ return flash->mst->opaque.wp_read_cfg(cfg, flash);
+
+ if (wp_operations_available(flash))
+ return wp_read_cfg(cfg, flash);
+
+ return FLASHROM_WP_ERR_OTHER;
+}
+
+enum flashrom_wp_result flashrom_wp_get_available_ranges(struct flashrom_wp_ranges **list, struct flashrom_flashctx *flash)
+{
+ if (flash->mst->buses_supported & BUS_PROG && flash->mst->opaque.wp_get_ranges)
+ return flash->mst->opaque.wp_get_ranges(list, flash);
+
+ if (wp_operations_available(flash))
+ return wp_get_available_ranges(list, flash);
+
+ return FLASHROM_WP_ERR_OTHER;
+}
+
+size_t flashrom_wp_ranges_get_count(const struct flashrom_wp_ranges *list)
+{
+ return list->count;
+}
+
+enum flashrom_wp_result flashrom_wp_ranges_get_range(size_t *start, size_t *len, const struct flashrom_wp_ranges *list, unsigned int index)
+{
+ if (index >= list->count)
+ return FLASHROM_WP_ERR_OTHER;
+
+ *start = list->ranges[index].start;
+ *len = list->ranges[index].len;
+
+ return 0;
+}
+
+void flashrom_wp_ranges_release(struct flashrom_wp_ranges *list)
+{
+ if (!list)
+ return;
+
+ free(list->ranges);
+ free(list);
+}
diff --git a/libflashrom.h b/libflashrom.h
deleted file mode 100644
index d0d582616..000000000
--- a/libflashrom.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2012 secunet Security Networks AG
- * (Written by Nico Huber <nico.huber@secunet.com> for secunet)
- *
- * 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 __LIBFLASHROM_H__
-#define __LIBFLASHROM_H__ 1
-
-#include <sys/types.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdarg.h>
-
-int flashrom_init(int perform_selfcheck);
-int flashrom_shutdown(void);
-/** @ingroup flashrom-general */
-enum flashrom_log_level {
- FLASHROM_MSG_ERROR = 0,
- FLASHROM_MSG_WARN = 1,
- FLASHROM_MSG_INFO = 2,
- FLASHROM_MSG_DEBUG = 3,
- FLASHROM_MSG_DEBUG2 = 4,
- FLASHROM_MSG_SPEW = 5,
-};
-/** @ingroup flashrom-general */
-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 */
-enum flashrom_test_state {
- FLASHROM_TESTED_OK = 0,
- FLASHROM_TESTED_NT = 1,
- FLASHROM_TESTED_BAD = 2,
- FLASHROM_TESTED_DEP = 3,
- FLASHROM_TESTED_NA = 4,
-};
-
-struct flashrom_flashchip_info {
- const char *vendor;
- const char *name;
- unsigned int total_size;
- struct flashrom_tested {
- enum flashrom_test_state probe;
- enum flashrom_test_state read;
- enum flashrom_test_state erase;
- enum flashrom_test_state write;
- } tested;
-};
-
-struct flashrom_board_info {
- const char *vendor;
- const char *name;
- enum flashrom_test_state working;
-};
-
-struct flashrom_chipset_info {
- const char *vendor;
- const char *chipset;
- uint16_t vendor_id;
- uint16_t chipset_id;
- enum flashrom_test_state status;
-};
-
-const char *flashrom_version_info(void);
-void flashrom_system_info(void);
-const char **flashrom_supported_programmers(void);
-struct flashrom_flashchip_info *flashrom_supported_flash_chips(void);
-struct flashrom_board_info *flashrom_supported_boards(void);
-struct 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 *);
-
-struct flashrom_flashctx;
-int flashrom_flash_probe(struct flashrom_flashctx **, const struct flashrom_programmer *, const char *chip_name);
-size_t flashrom_flash_getsize(const struct flashrom_flashctx *);
-int flashrom_flash_erase(struct flashrom_flashctx *);
-void flashrom_flash_release(struct flashrom_flashctx *);
-
-/** @ingroup flashrom-flash */
-enum flashrom_flag {
- FLASHROM_FLAG_FORCE,
- FLASHROM_FLAG_FORCE_BOARDMISMATCH,
- FLASHROM_FLAG_VERIFY_AFTER_WRITE,
- FLASHROM_FLAG_VERIFY_WHOLE_CHIP,
-};
-void flashrom_flag_set(struct flashrom_flashctx *, enum flashrom_flag, bool value);
-bool flashrom_flag_get(const struct flashrom_flashctx *, enum flashrom_flag);
-
-int flashrom_image_read(struct flashrom_flashctx *, void *buffer, size_t buffer_len);
-int flashrom_image_write(struct flashrom_flashctx *, void *buffer, size_t buffer_len, const void *refbuffer);
-int flashrom_image_verify(struct flashrom_flashctx *, const void *buffer, size_t buffer_len);
-
-struct flashrom_layout;
-int flashrom_layout_read_from_ifd(struct flashrom_layout **, struct flashrom_flashctx *, const void *dump, size_t len);
-int flashrom_layout_read_fmap_from_rom(struct flashrom_layout **,
- struct flashrom_flashctx *, off_t offset, size_t length);
-int flashrom_layout_read_fmap_from_buffer(struct flashrom_layout **layout,
- struct flashrom_flashctx *, const uint8_t *buf, size_t len);
-int flashrom_layout_include_region(struct flashrom_layout *, const char *name);
-void flashrom_layout_release(struct flashrom_layout *);
-void flashrom_layout_set(struct flashrom_flashctx *, const struct flashrom_layout *);
-
-#endif /* !__LIBFLASHROM_H__ */
diff --git a/libflashrom.map b/libflashrom.map
index d6dd24d2c..77abf727d 100644
--- a/libflashrom.map
+++ b/libflashrom.map
@@ -5,16 +5,20 @@ LIBFLASHROM_1.0 {
flashrom_data_free;
flashrom_flag_get;
flashrom_flag_set;
- flashrom_flashchip_info;
flashrom_flash_erase;
flashrom_flash_getsize;
flashrom_flash_probe;
flashrom_flash_release;
+ flashrom_flashchip_info;
flashrom_image_read;
flashrom_image_verify;
flashrom_image_write;
flashrom_init;
+ flashrom_layout_add_region;
+ flashrom_layout_exclude_region;
+ flashrom_layout_get_region_range;
flashrom_layout_include_region;
+ flashrom_layout_new;
flashrom_layout_read_fmap_from_buffer;
flashrom_layout_read_fmap_from_rom;
flashrom_layout_read_from_ifd;
@@ -23,9 +27,23 @@ LIBFLASHROM_1.0 {
flashrom_programmer_init;
flashrom_programmer_shutdown;
flashrom_set_log_callback;
+ flashrom_set_progress_callback;
flashrom_shutdown;
- flashrom_supported_programmers;
- flashrom_system_info;
+ flashrom_supported_boards;
+ flashrom_supported_chipsets;
+ flashrom_supported_flash_chips;
flashrom_version_info;
+ flashrom_wp_cfg_new;
+ flashrom_wp_cfg_release;
+ flashrom_wp_get_available_ranges;
+ flashrom_wp_get_mode;
+ flashrom_wp_get_range;
+ flashrom_wp_ranges_get_count;
+ flashrom_wp_ranges_get_range;
+ flashrom_wp_ranges_release;
+ flashrom_wp_read_cfg;
+ flashrom_wp_set_mode;
+ flashrom_wp_set_range;
+ flashrom_wp_write_cfg;
local: *;
};
diff --git a/linux_mtd.c b/linux_mtd.c
index d2df95ef2..495db9a74 100644
--- a/linux_mtd.c
+++ b/linux_mtd.c
@@ -17,6 +17,7 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <mtd/mtd-user.h>
@@ -31,16 +32,16 @@
#define LINUX_DEV_ROOT "/dev"
#define LINUX_MTD_SYSFS_ROOT "/sys/class/mtd"
-static FILE *dev_fp = NULL;
-
-static int mtd_device_is_writeable;
-
-static int mtd_no_erase;
-
-/* Size info is presented in bytes in sysfs. */
-static unsigned long int mtd_total_size;
-static unsigned long int mtd_numeraseregions;
-static unsigned long int mtd_erasesize; /* only valid if numeraseregions is 0 */
+struct linux_mtd_data {
+ FILE *dev_fp;
+ bool device_is_writeable;
+ bool no_erase;
+ /* Size info is presented in bytes in sysfs. */
+ unsigned long int total_size;
+ unsigned long int numeraseregions;
+ /* only valid if numeraseregions is 0 */
+ unsigned long int erasesize;
+};
/* read a string from a sysfs file and sanitize it */
static int read_sysfs_string(const char *sysfs_path, const char *filename, char *buf, int len)
@@ -120,76 +121,80 @@ static int popcnt(unsigned int u)
}
/* returns 0 to indicate success, non-zero to indicate error */
-static int get_mtd_info(const char *sysfs_path)
+static int get_mtd_info(const char *sysfs_path, struct linux_mtd_data *data)
{
unsigned long int tmp;
- char mtd_device_name[32];
+ char device_name[32];
/* Flags */
if (read_sysfs_int(sysfs_path, "flags", &tmp))
return 1;
if (tmp & MTD_WRITEABLE) {
/* cache for later use by write function */
- mtd_device_is_writeable = 1;
+ data->device_is_writeable = true;
}
if (tmp & MTD_NO_ERASE) {
- mtd_no_erase = 1;
+ data->no_erase = true;
}
/* Device name */
- if (read_sysfs_string(sysfs_path, "name", mtd_device_name, sizeof(mtd_device_name)))
+ if (read_sysfs_string(sysfs_path, "name", device_name, sizeof(device_name)))
return 1;
/* Total size */
- if (read_sysfs_int(sysfs_path, "size", &mtd_total_size))
+ if (read_sysfs_int(sysfs_path, "size", &data->total_size))
return 1;
- if (popcnt(mtd_total_size) != 1) {
+ if (popcnt(data->total_size) != 1) {
msg_perr("MTD size is not a power of 2\n");
return 1;
}
/* Erase size */
- if (read_sysfs_int(sysfs_path, "erasesize", &mtd_erasesize))
+ if (read_sysfs_int(sysfs_path, "erasesize", &data->erasesize))
return 1;
- if (popcnt(mtd_erasesize) != 1) {
+ if (popcnt(data->erasesize) != 1) {
msg_perr("MTD erase size is not a power of 2\n");
return 1;
}
/* Erase regions */
- if (read_sysfs_int(sysfs_path, "numeraseregions", &mtd_numeraseregions))
+ if (read_sysfs_int(sysfs_path, "numeraseregions", &data->numeraseregions))
return 1;
- if (mtd_numeraseregions != 0) {
+ if (data->numeraseregions != 0) {
msg_perr("Non-uniform eraseblock size is unsupported.\n");
return 1;
}
msg_pdbg("%s: device_name: \"%s\", is_writeable: %d, "
"numeraseregions: %lu, total_size: %lu, erasesize: %lu\n",
- __func__, mtd_device_name, mtd_device_is_writeable,
- mtd_numeraseregions, mtd_total_size, mtd_erasesize);
+ __func__, device_name, data->device_is_writeable,
+ data->numeraseregions, data->total_size, data->erasesize);
return 0;
}
static int linux_mtd_probe(struct flashctx *flash)
{
- if (mtd_no_erase)
+ struct linux_mtd_data *data = flash->mst->opaque.data;
+
+ if (data->no_erase)
flash->chip->feature_bits |= FEATURE_NO_ERASE;
- flash->chip->tested = TEST_OK_PREW;
- flash->chip->total_size = mtd_total_size / 1024; /* bytes -> kB */
- flash->chip->block_erasers[0].eraseblocks[0].size = mtd_erasesize;
- flash->chip->block_erasers[0].eraseblocks[0].count = mtd_total_size / mtd_erasesize;
+ flash->chip->tested = TEST_OK_PREWB;
+ flash->chip->total_size = data->total_size / 1024; /* bytes -> kB */
+ flash->chip->block_erasers[0].eraseblocks[0].size = data->erasesize;
+ flash->chip->block_erasers[0].eraseblocks[0].count =
+ data->total_size / data->erasesize;
return 1;
}
static int linux_mtd_read(struct flashctx *flash, uint8_t *buf,
unsigned int start, unsigned int len)
{
+ struct linux_mtd_data *data = flash->mst->opaque.data;
unsigned int eb_size = flash->chip->block_erasers[0].eraseblocks[0].size;
unsigned int i;
- if (fseek(dev_fp, start, SEEK_SET) != 0) {
+ if (fseek(data->dev_fp, start, SEEK_SET) != 0) {
msg_perr("Cannot seek to 0x%06x: %s\n", start, strerror(errno));
return 1;
}
@@ -203,13 +208,14 @@ static int linux_mtd_read(struct flashctx *flash, uint8_t *buf,
unsigned int step = eb_size - ((start + i) % eb_size);
step = min(step, len - i);
- if (fread(buf + i, step, 1, dev_fp) != 1) {
+ if (fread(buf + i, step, 1, data->dev_fp) != 1) {
msg_perr("Cannot read 0x%06x bytes at 0x%06x: %s\n",
step, start + i, strerror(errno));
return 1;
}
i += step;
+ update_progress(flash, FLASHROM_PROGRESS_READ, i, len);
}
return 0;
@@ -219,13 +225,14 @@ static int linux_mtd_read(struct flashctx *flash, uint8_t *buf,
static int linux_mtd_write(struct flashctx *flash, const uint8_t *buf,
unsigned int start, unsigned int len)
{
+ struct linux_mtd_data *data = flash->mst->opaque.data;
unsigned int chunksize = flash->chip->block_erasers[0].eraseblocks[0].size;
unsigned int i;
- if (!mtd_device_is_writeable)
+ if (!data->device_is_writeable)
return 1;
- if (fseek(dev_fp, start, SEEK_SET) != 0) {
+ if (fseek(data->dev_fp, start, SEEK_SET) != 0) {
msg_perr("Cannot seek to 0x%06x: %s\n", start, strerror(errno));
return 1;
}
@@ -240,17 +247,18 @@ static int linux_mtd_write(struct flashctx *flash, const uint8_t *buf,
unsigned int step = chunksize - ((start + i) % chunksize);
step = min(step, len - i);
- if (fwrite(buf + i, step, 1, dev_fp) != 1) {
+ if (fwrite(buf + i, step, 1, data->dev_fp) != 1) {
msg_perr("Cannot write 0x%06x bytes at 0x%06x\n", step, start + i);
return 1;
}
- if (fflush(dev_fp) == EOF) {
+ if (fflush(data->dev_fp) == EOF) {
msg_perr("Failed to flush buffer: %s\n", strerror(errno));
return 1;
}
i += step;
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i, len);
}
return 0;
@@ -259,37 +267,169 @@ static int linux_mtd_write(struct flashctx *flash, const uint8_t *buf,
static int linux_mtd_erase(struct flashctx *flash,
unsigned int start, unsigned int len)
{
+ struct linux_mtd_data *data = flash->mst->opaque.data;
uint32_t u;
- if (mtd_no_erase) {
+ if (data->no_erase) {
msg_perr("%s: device does not support erasing. Please file a "
"bug report at flashrom@flashrom.org\n", __func__);
return 1;
}
- if (mtd_numeraseregions != 0) {
+ if (data->numeraseregions != 0) {
/* TODO: Support non-uniform eraseblock size using
use MEMGETREGIONCOUNT/MEMGETREGIONINFO ioctls */
- msg_perr("%s: mtd_numeraseregions must be 0\n", __func__);
+ msg_perr("%s: numeraseregions must be 0\n", __func__);
return 1;
}
- for (u = 0; u < len; u += mtd_erasesize) {
+ for (u = 0; u < len; u += data->erasesize) {
struct erase_info_user erase_info = {
.start = start + u,
- .length = mtd_erasesize,
+ .length = data->erasesize,
};
- if (ioctl(fileno(dev_fp), MEMERASE, &erase_info) == -1) {
- msg_perr("%s: ioctl: %s\n", __func__, strerror(errno));
- return 1;
+ int ret = ioctl(fileno(data->dev_fp), MEMERASE, &erase_info);
+ if (ret < 0) {
+ msg_perr("%s: MEMERASE ioctl call returned %d, error: %s\n",
+ __func__, ret, strerror(errno));
+ return 1;
}
+ update_progress(flash, FLASHROM_PROGRESS_ERASE, u + data->erasesize, len);
}
return 0;
}
-static struct opaque_master programmer_linux_mtd = {
+static int linux_mtd_shutdown(void *data)
+{
+ struct linux_mtd_data *mtd_data = data;
+ if (mtd_data->dev_fp != NULL) {
+ fclose(mtd_data->dev_fp);
+ }
+ free(data);
+
+ return 0;
+}
+
+static enum flashrom_wp_result linux_mtd_wp_read_cfg(struct flashrom_wp_cfg *cfg, struct flashctx *flash)
+{
+ struct linux_mtd_data *data = flash->mst->opaque.data;
+ bool start_found = false;
+ bool end_found = false;
+
+ cfg->mode = FLASHROM_WP_MODE_DISABLED;
+ cfg->range.start = 0;
+ cfg->range.len = 0;
+
+ /* Check protection status of each block */
+ for (size_t u = 0; u < data->total_size; u += data->erasesize) {
+ struct erase_info_user erase_info = {
+ .start = u,
+ .length = data->erasesize,
+ };
+
+ int ret = ioctl(fileno(data->dev_fp), MEMISLOCKED, &erase_info);
+ if (ret == 0) {
+ /* Block is unprotected. */
+
+ if (start_found) {
+ end_found = true;
+ }
+ } else if (ret == 1) {
+ /* Block is protected. */
+
+ if (end_found) {
+ /*
+ * We already found the end of another
+ * protection range, so this is the start of a
+ * new one.
+ */
+ return FLASHROM_WP_ERR_OTHER;
+ }
+ if (!start_found) {
+ cfg->range.start = erase_info.start;
+ cfg->mode = FLASHROM_WP_MODE_HARDWARE;
+ start_found = true;
+ }
+ cfg->range.len += data->erasesize;
+ } else {
+ msg_perr("%s: ioctl: %s\n", __func__, strerror(errno));
+ return FLASHROM_WP_ERR_READ_FAILED;
+ }
+
+ }
+
+ return FLASHROM_WP_OK;
+}
+
+static enum flashrom_wp_result linux_mtd_wp_write_cfg(struct flashctx *flash, const struct flashrom_wp_cfg *cfg)
+{
+ const struct linux_mtd_data *data = flash->mst->opaque.data;
+
+ const struct erase_info_user entire_chip = {
+ .start = 0,
+ .length = data->total_size,
+ };
+ const struct erase_info_user desired_range = {
+ .start = cfg->range.start,
+ .length = cfg->range.len,
+ };
+
+ /*
+ * MTD ioctls will enable hardware status register protection if and
+ * only if the protected region is non-empty. Return an error if the
+ * cfg cannot be activated using the MTD interface.
+ */
+ if ((cfg->range.len == 0) != (cfg->mode == FLASHROM_WP_MODE_DISABLED)) {
+ return FLASHROM_WP_ERR_OTHER;
+ }
+
+ /*
+ * MTD handles write-protection additively, so whatever new range is
+ * specified is added to the range which is currently protected. To
+ * just protect the requsted range, we need to disable the current
+ * write protection and then enable it for the desired range.
+ */
+ int ret = ioctl(fileno(data->dev_fp), MEMUNLOCK, &entire_chip);
+ if (ret < 0) {
+ msg_perr("%s: Failed to disable write-protection, MEMUNLOCK ioctl "
+ "retuned %d, error: %s\n", __func__, ret, strerror(errno));
+ return FLASHROM_WP_ERR_WRITE_FAILED;
+ }
+
+ if (cfg->range.len > 0) {
+ ret = ioctl(fileno(data->dev_fp), MEMLOCK, &desired_range);
+ if (ret < 0) {
+ msg_perr("%s: Failed to enable write-protection, "
+ "MEMLOCK ioctl retuned %d, error: %s\n",
+ __func__, ret, strerror(errno));
+ return FLASHROM_WP_ERR_WRITE_FAILED;
+ }
+ }
+
+ /* Verify */
+ struct flashrom_wp_cfg readback_cfg;
+ enum flashrom_wp_result read_ret = linux_mtd_wp_read_cfg(&readback_cfg, flash);
+ if (read_ret != FLASHROM_WP_OK)
+ return read_ret;
+
+ if (readback_cfg.mode != cfg->mode ||
+ readback_cfg.range.start != cfg->range.start ||
+ readback_cfg.range.len != cfg->range.len) {
+ return FLASHROM_WP_ERR_VERIFY_FAILED;
+ }
+
+ return FLASHROM_WP_OK;
+}
+
+static enum flashrom_wp_result linux_mtd_wp_get_available_ranges(struct flashrom_wp_ranges **list, struct flashctx *flash)
+{
+ /* Not supported by MTD interface. */
+ return FLASHROM_WP_ERR_RANGE_LIST_UNAVAILABLE;
+}
+
+static const struct opaque_master linux_mtd_opaque_master = {
/* max_data_{read,write} don't have any effect for this programmer */
.max_data_read = MAX_DATA_UNSPECIFIED,
.max_data_write = MAX_DATA_UNSPECIFIED,
@@ -297,10 +437,14 @@ static struct opaque_master programmer_linux_mtd = {
.read = linux_mtd_read,
.write = linux_mtd_write,
.erase = linux_mtd_erase,
+ .shutdown = linux_mtd_shutdown,
+ .wp_read_cfg = linux_mtd_wp_read_cfg,
+ .wp_write_cfg = linux_mtd_wp_write_cfg,
+ .wp_get_ranges = linux_mtd_wp_get_available_ranges,
};
/* Returns 0 if setup is successful, non-zero to indicate error */
-static int linux_mtd_setup(int dev_num)
+static int linux_mtd_setup(int dev_num, struct linux_mtd_data *data)
{
char sysfs_path[32];
int ret = 1;
@@ -309,8 +453,7 @@ static int linux_mtd_setup(int dev_num)
if (snprintf(sysfs_path, sizeof(sysfs_path), "%s/mtd%d/", LINUX_MTD_SYSFS_ROOT, dev_num) < 0)
goto linux_mtd_setup_exit;
- char buf[4];
- memset(buf, 0, sizeof(buf));
+ char buf[4] = { 0 };
if (read_sysfs_string(sysfs_path, "type", buf, sizeof(buf)))
return 1;
@@ -332,14 +475,18 @@ static int linux_mtd_setup(int dev_num)
/* so far so good, get more info from other files in this dir */
if (snprintf(sysfs_path, sizeof(sysfs_path), "%s/mtd%d/", LINUX_MTD_SYSFS_ROOT, dev_num) < 0)
goto linux_mtd_setup_exit;
- if (get_mtd_info(sysfs_path))
+ if (get_mtd_info(sysfs_path, data))
goto linux_mtd_setup_exit;
/* open file stream and go! */
- if ((dev_fp = fopen(dev_path, "r+")) == NULL) {
+ if ((data->dev_fp = fopen(dev_path, "r+")) == NULL) {
msg_perr("Cannot open file stream for %s\n", dev_path);
goto linux_mtd_setup_exit;
}
+ ret = setvbuf(data->dev_fp, NULL, _IONBF, 0);
+ if (ret)
+ msg_pwarn("Failed to set MTD device to unbuffered: %d\n", ret);
+
msg_pinfo("Opened %s successfully\n", dev_path);
ret = 0;
@@ -347,31 +494,22 @@ linux_mtd_setup_exit:
return ret;
}
-static int linux_mtd_shutdown(void *data)
-{
- if (dev_fp != NULL) {
- fclose(dev_fp);
- dev_fp = NULL;
- }
-
- return 0;
-}
-
-int linux_mtd_init(void)
+static int linux_mtd_init(const struct programmer_cfg *cfg)
{
- char *param;
+ char *param_str;
int dev_num = 0;
int ret = 1;
+ struct linux_mtd_data *data = NULL;
- param = extract_programmer_param("dev");
- if (param) {
+ param_str = extract_programmer_param_str(cfg, "dev");
+ if (param_str) {
char *endptr;
- dev_num = strtol(param, &endptr, 0);
+ dev_num = strtol(param_str, &endptr, 0);
if ((*endptr != '\0') || (dev_num < 0)) {
msg_perr("Invalid device number %s. Use flashrom -p "
"linux_mtd:dev=N where N is a valid MTD\n"
- "device number.\n", param);
+ "device number.\n", param_str);
goto linux_mtd_init_exit;
}
}
@@ -387,23 +525,36 @@ int linux_mtd_init(void)
struct stat s;
if (stat(sysfs_path, &s) < 0) {
- if (param)
+ if (param_str)
msg_perr("%s does not exist\n", sysfs_path);
else
msg_pdbg("%s does not exist\n", sysfs_path);
goto linux_mtd_init_exit;
}
+ free(param_str);
- if (linux_mtd_setup(dev_num))
- goto linux_mtd_init_exit;
+ data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate memory for linux_mtd_data\n");
+ return 1;
+ }
- if (register_shutdown(linux_mtd_shutdown, NULL))
- goto linux_mtd_init_exit;
+ /* Get MTD info and store it in `data` */
+ if (linux_mtd_setup(dev_num, data)) {
+ free(data);
+ return 1;
+ }
- register_opaque_master(&programmer_linux_mtd);
+ return register_opaque_master(&linux_mtd_opaque_master, data);
- ret = 0;
linux_mtd_init_exit:
- free(param);
+ free(param_str);
return ret;
}
+
+const struct programmer_entry programmer_linux_mtd = {
+ .name = "linux_mtd",
+ .type = OTHER,
+ .devs.note = "Device files /dev/mtd*\n",
+ .init = linux_mtd_init,
+};
diff --git a/linux_spi.c b/linux_spi.c
index 1ef8f2b72..ceca05f9a 100644
--- a/linux_spi.c
+++ b/linux_spi.c
@@ -13,8 +13,6 @@
* GNU General Public License for more details.
*/
-#if CONFIG_LINUX_SPI == 1
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -44,46 +42,144 @@
* HummingBoard
*/
-static int fd = -1;
#define BUF_SIZE_FROM_SYSFS "/sys/module/spidev/parameters/bufsiz"
-static size_t max_kernel_buf_size;
-static int linux_spi_shutdown(void *data);
+struct linux_spi_data {
+ int fd;
+ size_t max_kernel_buf_size;
+};
+
+static int linux_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+ struct linux_spi_data *spi_data = flash->mst->spi.data;
+ /* Older kernels use a single buffer for combined input and output
+ data. So account for longest possible command + address, too. */
+ return spi_read_chunked(flash, buf, start, len, spi_data->max_kernel_buf_size - 5);
+}
+
+static int linux_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
+{
+ struct linux_spi_data *spi_data = flash->mst->spi.data;
+ /* 5 bytes must be reserved for longest possible command + address. */
+ return spi_write_chunked(flash, buf, start, len, spi_data->max_kernel_buf_size - 5);
+}
+
+static int linux_spi_shutdown(void *data)
+{
+ struct linux_spi_data *spi_data = data;
+ close(spi_data->fd);
+ free(spi_data);
+ return 0;
+}
+
static int linux_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
unsigned int readcnt,
const unsigned char *txbuf,
- unsigned char *rxbuf);
-static int linux_spi_read(struct flashctx *flash, uint8_t *buf,
- unsigned int start, unsigned int len);
-static int linux_spi_write_256(struct flashctx *flash, const uint8_t *buf,
- unsigned int start, unsigned int len);
+ unsigned char *rxbuf)
+{
+ struct linux_spi_data *spi_data = flash->mst->spi.data;
+ int iocontrol_code;
+ struct spi_ioc_transfer msg[2] = {
+ {
+ .tx_buf = (uint64_t)(uintptr_t)txbuf,
+ .len = writecnt,
+ },
+ {
+ .rx_buf = (uint64_t)(uintptr_t)rxbuf,
+ .len = readcnt,
+ },
+ };
+
+ if (spi_data->fd == -1)
+ return -1;
+ /* The implementation currently does not support requests that
+ don't start with sending a command. */
+ if (writecnt == 0)
+ return SPI_INVALID_LENGTH;
+
+ /* Just submit the first (write) request in case there is nothing
+ to read. Otherwise submit both requests. */
+ if (readcnt == 0)
+ iocontrol_code = SPI_IOC_MESSAGE(1);
+ else
+ iocontrol_code = SPI_IOC_MESSAGE(2);
+
+ if (ioctl(spi_data->fd, iocontrol_code, msg) == -1) {
+ msg_cerr("%s: ioctl: %s\n", __func__, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
static const struct spi_master spi_master_linux = {
.features = SPI_MASTER_4BA,
.max_data_read = MAX_DATA_UNSPECIFIED, /* TODO? */
.max_data_write = MAX_DATA_UNSPECIFIED, /* TODO? */
.command = linux_spi_send_command,
- .multicommand = default_spi_send_multicommand,
.read = linux_spi_read,
.write_256 = linux_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .shutdown = linux_spi_shutdown,
};
-int linux_spi_init(void)
+/* Read max buffer size from sysfs, or use page size as fallback. */
+static size_t get_max_kernel_buf_size()
{
- char *p, *endp, *dev;
+ size_t result = 0;
+ FILE *fp;
+ fp = fopen(BUF_SIZE_FROM_SYSFS, "r");
+ if (!fp) {
+ msg_pwarn("Cannot open %s: %s.\n", BUF_SIZE_FROM_SYSFS, strerror(errno));
+ goto out;
+ }
+
+ char buf[10];
+ if (!fgets(buf, sizeof(buf), fp)) {
+ if (feof(fp))
+ msg_pwarn("Cannot read %s: file is empty.\n", BUF_SIZE_FROM_SYSFS);
+ else
+ msg_pwarn("Cannot read %s: %s.\n", BUF_SIZE_FROM_SYSFS, strerror(errno));
+ goto out;
+ }
+
+ long int tmp;
+ errno = 0;
+ tmp = strtol(buf, NULL, 0);
+ if ((tmp < 0) || errno) {
+ msg_pwarn("Buffer size %ld from %s seems wrong.\n", tmp, BUF_SIZE_FROM_SYSFS);
+ } else {
+ msg_pdbg("%s: Using value from %s as max buffer size.\n", __func__, BUF_SIZE_FROM_SYSFS);
+ result = (size_t)tmp;
+ }
+
+out:
+ if (fp)
+ fclose(fp);
+
+ if (!result) {
+ msg_pdbg("%s: Using page size as max buffer size.\n", __func__);
+ result = (size_t)getpagesize();
+ }
+ return result;
+}
+
+static int linux_spi_init(const struct programmer_cfg *cfg)
+{
+ char *param_str, *endp;
uint32_t speed_hz = 2 * 1000 * 1000;
/* FIXME: make the following configurable by CLI options. */
/* SPI mode 0 (beware this also includes: MSB first, CS active low and others */
const uint8_t mode = SPI_MODE_0;
const uint8_t bits = 8;
-
- p = extract_programmer_param("spispeed");
- if (p && strlen(p)) {
- speed_hz = (uint32_t)strtoul(p, &endp, 10) * 1000;
- if (p == endp || speed_hz == 0) {
- msg_perr("%s: invalid clock: %s kHz\n", __func__, p);
- free(p);
+ int fd;
+ size_t max_kernel_buf_size;
+ struct linux_spi_data *spi_data;
+
+ param_str = extract_programmer_param_str(cfg, "spispeed");
+ if (param_str && strlen(param_str)) {
+ speed_hz = (uint32_t)strtoul(param_str, &endp, 10) * 1000;
+ if (param_str == endp || speed_hz == 0) {
+ msg_perr("%s: invalid clock: %s kHz\n", __func__, param_str);
+ free(param_str);
return 1;
}
} else {
@@ -91,147 +187,65 @@ int linux_spi_init(void)
"kHz clock. Use 'spispeed' parameter to override.\n",
speed_hz / 1000);
}
- free(p);
+ free(param_str);
- dev = extract_programmer_param("dev");
- if (!dev || !strlen(dev)) {
+ param_str = extract_programmer_param_str(cfg, "dev");
+ if (!param_str || !strlen(param_str)) {
msg_perr("No SPI device given. Use flashrom -p "
"linux_spi:dev=/dev/spidevX.Y\n");
- free(dev);
+ free(param_str);
return 1;
}
- msg_pdbg("Using device %s\n", dev);
- if ((fd = open(dev, O_RDWR)) == -1) {
+ msg_pdbg("Using device %s\n", param_str);
+ if ((fd = open(param_str, O_RDWR)) == -1) {
msg_perr("%s: failed to open %s: %s\n", __func__,
- dev, strerror(errno));
- free(dev);
+ param_str, strerror(errno));
+ free(param_str);
return 1;
}
- free(dev);
-
- if (register_shutdown(linux_spi_shutdown, NULL))
- return 1;
- /* We rely on the shutdown function for cleanup from here on. */
+ free(param_str);
if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz) == -1) {
msg_perr("%s: failed to set speed to %"PRIu32"Hz: %s\n",
__func__, speed_hz, strerror(errno));
- return 1;
+ goto init_err;
}
msg_pdbg("Using %"PRIu32"kHz clock\n", speed_hz / 1000);
if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) {
msg_perr("%s: failed to set SPI mode to 0x%02x: %s\n",
__func__, mode, strerror(errno));
- return 1;
+ goto init_err;
}
if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) == -1) {
msg_perr("%s: failed to set the number of bits per SPI word to %u: %s\n",
__func__, bits == 0 ? 8 : bits, strerror(errno));
- return 1;
- }
-
- /* Read max buffer size from sysfs, or use page size as fallback. */
- FILE *fp;
- fp = fopen(BUF_SIZE_FROM_SYSFS, "r");
- if (!fp) {
- msg_pwarn("Cannot open %s: %s.\n", BUF_SIZE_FROM_SYSFS, strerror(errno));
- goto out;
- }
-
- char buf[10];
- if (!fgets(buf, sizeof(buf), fp)) {
- if (feof(fp))
- msg_pwarn("Cannot read %s: file is empty.\n", BUF_SIZE_FROM_SYSFS);
- else
- msg_pwarn("Cannot read %s: %s.\n", BUF_SIZE_FROM_SYSFS, strerror(errno));
- goto out;
- }
-
- long int tmp;
- errno = 0;
- tmp = strtol(buf, NULL, 0);
- if ((tmp < 0) || errno) {
- msg_pwarn("Buffer size %ld from %s seems wrong.\n", tmp, BUF_SIZE_FROM_SYSFS);
- } else {
- msg_pdbg("%s: Using value from %s as max buffer size.\n", __func__, BUF_SIZE_FROM_SYSFS);
- max_kernel_buf_size = (size_t)tmp;
- }
-
-out:
- if (fp)
- fclose(fp);
-
- if (!max_kernel_buf_size) {
- msg_pdbg("%s: Using page size as max buffer size.\n", __func__);
- max_kernel_buf_size = (size_t)getpagesize();
+ goto init_err;
}
+ max_kernel_buf_size = get_max_kernel_buf_size();
msg_pdbg("%s: max_kernel_buf_size: %zu\n", __func__, max_kernel_buf_size);
- register_spi_master(&spi_master_linux);
- return 0;
-}
-static int linux_spi_shutdown(void *data)
-{
- if (fd != -1) {
- close(fd);
- fd = -1;
+ spi_data = calloc(1, sizeof(*spi_data));
+ if (!spi_data) {
+ msg_perr("Unable to allocated space for SPI master data\n");
+ goto init_err;
}
- return 0;
-}
+ spi_data->fd = fd;
+ spi_data->max_kernel_buf_size = max_kernel_buf_size;
-static int linux_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *txbuf,
- unsigned char *rxbuf)
-{
- int iocontrol_code;
- struct spi_ioc_transfer msg[2] = {
- {
- .tx_buf = (uint64_t)(uintptr_t)txbuf,
- .len = writecnt,
- },
- {
- .rx_buf = (uint64_t)(uintptr_t)rxbuf,
- .len = readcnt,
- },
- };
+ return register_spi_master(&spi_master_linux, spi_data);
- if (fd == -1)
- return -1;
- /* The implementation currently does not support requests that
- don't start with sending a command. */
- if (writecnt == 0)
- return SPI_INVALID_LENGTH;
-
- /* Just submit the first (write) request in case there is nothing
- to read. Otherwise submit both requests. */
- if (readcnt == 0)
- iocontrol_code = SPI_IOC_MESSAGE(1);
- else
- iocontrol_code = SPI_IOC_MESSAGE(2);
-
- if (ioctl(fd, iocontrol_code, msg) == -1) {
- msg_cerr("%s: ioctl: %s\n", __func__, strerror(errno));
- return -1;
- }
- return 0;
+init_err:
+ close(fd);
+ return 1;
}
-static int linux_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
-{
- /* Older kernels use a single buffer for combined input and output
- data. So account for longest possible command + address, too. */
- return spi_read_chunked(flash, buf, start, len, max_kernel_buf_size - 5);
-}
-
-static int linux_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
-{
- /* 5 bytes must be reserved for longest possible command + address. */
- return spi_write_chunked(flash, buf, start, len, max_kernel_buf_size - 5);
-}
-
-#endif // CONFIG_LINUX_SPI == 1
+const struct programmer_entry programmer_linux_spi = {
+ .name = "linux_spi",
+ .type = OTHER,
+ .devs.note = "Device files /dev/spidev*.*\n",
+ .init = linux_spi_init,
+};
diff --git a/lspcon_i2c_spi.c b/lspcon_i2c_spi.c
deleted file mode 100644
index 7b9f1c099..000000000
--- a/lspcon_i2c_spi.c
+++ /dev/null
@@ -1,505 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2020 The Chromium OS Authors
- *
- * 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 <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <errno.h>
-
-#include "programmer.h"
-#include "spi.h"
-#include "i2c_helper.h"
-
-#define REGISTER_ADDRESS (0x94 >> 1)
-#define PAGE_ADDRESS (0x9e >> 1)
-#define PAGE_SIZE 256
-#define MAX_SPI_WAIT_RETRIES 1000
-
-#define CLT2_SPI 0x82
-#define SPIEDID_BASE_ADDR2 0x8d
-#define ROMADDR_BYTE1 0x8e
-#define ROMADDR_BYTE2 0x8f
-#define SWSPI_WDATA 0x90
- #define SWSPI_WDATA_CLEAR_STATUS 0x00
- #define SWSPI_WDATA_WRITE_REGISTER 0x01
- #define SWSPI_WDATA_READ_REGISTER 0x05
- #define SWSPI_WDATA_ENABLE_REGISTER 0x06
- #define SWSPI_WDATA_SECTOR_ERASE 0x20
- #define SWSPI_WDATA_PROTECT_BP 0x8c
-#define SWSPI_RDATA 0x91
-#define SWSPI_LEN 0x92
-#define SWSPICTL 0x93
- #define SWSPICTL_ACCESS_TRIGGER 1
- #define SWSPICTL_CLEAR_PTR (1 << 1)
- #define SWSPICTL_NO_READ (1 << 2)
- #define SWSPICTL_ENABLE_READBACK (1 << 3)
- #define SWSPICTL_MOT (1 << 4)
-#define SPISTATUS 0x9e
- #define SPISTATUS_BYTE_PROGRAM_FINISHED 0
- #define SPISTATUS_BYTE_PROGRAM_IN_IF 1
- #define SPISTATUS_BYTE_PROGRAM_SEND_DONE (1 << 1)
- #define SPISTATUS_SECTOR_ERASE_FINISHED 0
- #define SPISTATUS_SECTOR_ERASE_IN_IF (1 << 2)
- #define SPISTATUS_SECTOR_ERASE_SEND_DONE (1 << 3)
- #define SPISTATUS_CHIP_ERASE_FINISHED 0
- #define SPISTATUS_CHIP_ERASE_IN_IF (1 << 4)
- #define SPISTATUS_CHIP_ERASE_SEND_DONE (1 << 5)
- #define SPISTATUS_FW_UPDATE_ENABLE (1 << 6)
-#define WRITE_PROTECTION 0xb3
- #define WRITE_PROTECTION_ON 0
- #define WRITE_PROTECTION_OFF 0x10
-#define MPU 0xbc
-#define PAGE_HW_WRITE 0xda
- #define PAGE_HW_WRITE_DISABLE 0
- #define PAGE_HW_COFIG_REGISTER 0xaa
- #define PAGE_HW_WRITE_ENABLE 0x55
-
-struct lspcon_i2c_spi_data {
- int fd;
-};
-
-typedef struct {
- uint8_t command;
- const uint8_t *data;
- uint8_t data_size;
- uint8_t control;
-} packet_t;
-
-static int lspcon_i2c_spi_write_data(int fd, uint16_t addr, void *buf, uint16_t len)
-{
- i2c_buffer_t data;
- if (i2c_buffer_t_fill(&data, buf, len))
- return SPI_GENERIC_ERROR;
-
- return i2c_write(fd, addr, &data) == len ? 0 : SPI_GENERIC_ERROR;
-}
-
-static int lspcon_i2c_spi_read_data(int fd, uint16_t addr, void *buf, uint16_t len)
-{
- i2c_buffer_t data;
- if (i2c_buffer_t_fill(&data, buf, len))
- return SPI_GENERIC_ERROR;
-
- return i2c_read(fd, addr, &data) == len ? 0 : SPI_GENERIC_ERROR;
-}
-
-static int get_fd_from_context(const struct flashctx *flash)
-{
- if (!flash || !flash->mst || !flash->mst->spi.data) {
- msg_perr("Unable to extract fd from flash context.\n");
- return SPI_GENERIC_ERROR;
- }
- const struct lspcon_i2c_spi_data *data =
- (const struct lspcon_i2c_spi_data *)flash->mst->spi.data;
-
- return data->fd;
-}
-
-static int lspcon_i2c_spi_write_register(int fd, uint8_t i2c_register, uint8_t value)
-{
- uint8_t command[] = { i2c_register, value };
- return lspcon_i2c_spi_write_data(fd, REGISTER_ADDRESS, command, 2);
-}
-
-static int lspcon_i2c_spi_read_register(int fd, uint8_t i2c_register, uint8_t *value)
-{
- uint8_t command[] = { i2c_register };
- int ret = lspcon_i2c_spi_write_data(fd, REGISTER_ADDRESS, command, 1);
- ret |= lspcon_i2c_spi_read_data(fd, REGISTER_ADDRESS, value, 1);
-
- return ret ? SPI_GENERIC_ERROR : 0;
-}
-
-static int lspcon_i2c_spi_register_control(int fd, packet_t *packet)
-{
- int i;
- int ret = lspcon_i2c_spi_write_register(fd, SWSPI_WDATA, packet->command);
- if (ret)
- return ret;
-
- /* Higher 4 bits are read size. */
- int write_size = packet->data_size & 0x0f;
- for (i = 0; i < write_size; ++i) {
- ret |= lspcon_i2c_spi_write_register(fd, SWSPI_WDATA, packet->data[i]);
- }
-
- ret |= lspcon_i2c_spi_write_register(fd, SWSPI_LEN, packet->data_size);
- ret |= lspcon_i2c_spi_write_register(fd, SWSPICTL, packet->control);
-
- return ret;
-}
-
-static int lspcon_i2c_spi_wait_command_done(int fd, unsigned int offset, int mask)
-{
- uint8_t val;
- int tried = 0;
- int ret = 0;
- do {
- ret |= lspcon_i2c_spi_read_register(fd, offset, &val);
- } while (!ret && (val & mask) && ++tried < MAX_SPI_WAIT_RETRIES);
-
- if (tried == MAX_SPI_WAIT_RETRIES) {
- msg_perr("%s: Time out on sending command.\n", __func__);
- return -MAX_SPI_WAIT_RETRIES;
- }
-
- return (val & mask) ? SPI_GENERIC_ERROR : ret;
-}
-
-static int lspcon_i2c_spi_wait_rom_free(int fd)
-{
- uint8_t val;
- int tried = 0;
- int ret = 0;
- ret |= lspcon_i2c_spi_wait_command_done(fd, SPISTATUS,
- SPISTATUS_SECTOR_ERASE_IN_IF | SPISTATUS_SECTOR_ERASE_SEND_DONE);
- if (ret)
- return ret;
-
- do {
- packet_t packet = { SWSPI_WDATA_READ_REGISTER, NULL, 0, SWSPICTL_ACCESS_TRIGGER };
- ret |= lspcon_i2c_spi_register_control(fd, &packet);
- ret |= lspcon_i2c_spi_wait_command_done(fd, SWSPICTL, SWSPICTL_ACCESS_TRIGGER);
- ret |= lspcon_i2c_spi_read_register(fd, SWSPI_RDATA, &val);
- } while (!ret && (val & SWSPICTL_ACCESS_TRIGGER) && ++tried < MAX_SPI_WAIT_RETRIES);
-
- if (tried == MAX_SPI_WAIT_RETRIES) {
- msg_perr("%s: Time out on waiting ROM free.\n", __func__);
- return -MAX_SPI_WAIT_RETRIES;
- }
-
- return (val & SWSPICTL_ACCESS_TRIGGER) ? SPI_GENERIC_ERROR : ret;
-}
-
-static int lspcon_i2c_spi_toggle_register_protection(int fd, int toggle)
-{
- return lspcon_i2c_spi_write_register(fd, WRITE_PROTECTION,
- toggle ? WRITE_PROTECTION_OFF : WRITE_PROTECTION_ON);
-}
-
-static int lspcon_i2c_spi_enable_write_status_register(int fd)
-{
- int ret = lspcon_i2c_spi_toggle_register_protection(fd, 1);
- packet_t packet = {
- SWSPI_WDATA_ENABLE_REGISTER, NULL, 0, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ };
- ret |= lspcon_i2c_spi_register_control(fd, &packet);
- ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0);
-
- return ret;
-}
-
-static int lspcon_i2c_spi_enable_write_status_register_protection(int fd)
-{
- int ret = lspcon_i2c_spi_toggle_register_protection(fd, 1);
- uint8_t data[] = { SWSPI_WDATA_PROTECT_BP };
- packet_t packet = {
- SWSPI_WDATA_WRITE_REGISTER, data, 1, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ };
- ret |= lspcon_i2c_spi_register_control(fd, &packet);
- ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0);
-
- return ret;
-}
-
-static int lspcon_i2c_spi_disable_protection(int fd)
-{
- int ret = lspcon_i2c_spi_toggle_register_protection(fd, 1);
- uint8_t data[] = { SWSPI_WDATA_CLEAR_STATUS };
- packet_t packet = {
- SWSPI_WDATA_WRITE_REGISTER, data, 1, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ };
- ret |= lspcon_i2c_spi_register_control(fd, &packet);
- ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0);
-
- return ret;
-}
-
-static int lspcon_i2c_spi_disable_hw_write(int fd)
-{
- return lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, PAGE_HW_WRITE_DISABLE);
-}
-
-static int lspcon_i2c_spi_enable_write_protection(int fd)
-{
- int ret = lspcon_i2c_spi_enable_write_status_register(fd);
- ret |= lspcon_i2c_spi_enable_write_status_register_protection(fd);
- ret |= lspcon_i2c_spi_wait_rom_free(fd);
- ret |= lspcon_i2c_spi_disable_hw_write(fd);
-
- return ret;
-}
-
-static int lspcon_i2c_spi_disable_all_protection(int fd)
-{
- int ret = lspcon_i2c_spi_enable_write_status_register(fd);
- ret |= lspcon_i2c_spi_disable_protection(fd);
- ret |= lspcon_i2c_spi_wait_rom_free(fd);
-
- return ret;
-}
-
-static int lspcon_i2c_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
-{
- unsigned int i;
- if (writecnt > 16 || readcnt > 16 || writecnt == 0) {
- msg_perr("%s: Invalid read/write count for send command.\n",
- __func__);
- return SPI_GENERIC_ERROR;
- }
-
- int fd = get_fd_from_context(flash);
- if (fd < 0)
- return SPI_GENERIC_ERROR;
-
- int ret = lspcon_i2c_spi_disable_all_protection(fd);
- ret |= lspcon_i2c_spi_enable_write_status_register(fd);
- ret |= lspcon_i2c_spi_toggle_register_protection(fd, 1);
-
- /* First byte of writearr shuld be the command value, followed by the value to write.
- Read length occupies 4 bit and represents 16 level, thus if read 1 byte,
- read length should be set 0. */
- packet_t packet = {
- writearr[0], &writearr[1], (writecnt - 1) | ((readcnt - 1) << 4),
- SWSPICTL_ACCESS_TRIGGER | (readcnt ? 0 : SWSPICTL_NO_READ),
- };
-
- ret |= lspcon_i2c_spi_register_control(fd, &packet);
- ret |= lspcon_i2c_spi_wait_command_done(fd, SWSPICTL, SWSPICTL_ACCESS_TRIGGER);
- ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0);
- if (ret)
- return ret;
-
- for (i = 0; i < readcnt; ++i) {
- ret |= lspcon_i2c_spi_read_register(fd, SWSPI_RDATA, &readarr[i]);
- }
-
- ret |= lspcon_i2c_spi_wait_rom_free(fd);
-
- return ret;
-}
-
-static int lspcon_i2c_spi_enable_hw_write(int fd)
-{
- int ret = 0;
- ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, PAGE_HW_COFIG_REGISTER);
- ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, PAGE_HW_WRITE_ENABLE);
- ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x50);
- ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x41);
- ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x52);
- ret |= lspcon_i2c_spi_write_register(fd, PAGE_HW_WRITE, 0x44);
-
- return ret;
-}
-
-static int lspcon_i2c_clt2_spi_reset(int fd)
-{
- int ret = 0;
- ret |= lspcon_i2c_spi_write_register(fd, CLT2_SPI, 0x20);
- struct timespec wait_100ms = { 0, (unsigned)1e8 };
- nanosleep(&wait_100ms, NULL);
- ret |= lspcon_i2c_spi_write_register(fd, CLT2_SPI, 0x00);
-
- return ret;
-}
-
-static int lspcon_i2c_spi_reset_mpu_stop(int fd)
-{
- int ret = 0;
- ret |= lspcon_i2c_spi_write_register(fd, MPU, 0xc0); // cmd mode
- ret |= lspcon_i2c_spi_write_register(fd, MPU, 0x40); // stop mcu
-
- return ret;
-}
-
-static int lspcon_i2c_spi_map_page(int fd, unsigned int offset)
-{
- int ret = 0;
- /* Page number byte, need to / PAGE_SIZE. */
- ret |= lspcon_i2c_spi_write_register(fd, ROMADDR_BYTE1, (offset >> 8) & 0xff);
- ret |= lspcon_i2c_spi_write_register(fd, ROMADDR_BYTE2, (offset >> 16));
-
- return ret ? SPI_GENERIC_ERROR : 0;
-}
-
-static int lspcon_i2c_spi_read(struct flashctx *flash, uint8_t *buf,
- unsigned int start, unsigned int len)
-{
- unsigned int i;
- int ret = 0;
- if (start & 0xff)
- return default_spi_read(flash, buf, start, len);
-
- int fd = get_fd_from_context(flash);
- if (fd < 0)
- return SPI_GENERIC_ERROR;
-
- for (i = 0; i < len; i += PAGE_SIZE) {
- ret |= lspcon_i2c_spi_map_page(fd, start + i);
- ret |= lspcon_i2c_spi_read_data(fd, PAGE_ADDRESS, buf + i, min(len - i, PAGE_SIZE));
- }
-
- return ret;
-}
-
-static int lspcon_i2c_spi_write_page(int fd, const uint8_t *buf, unsigned int len)
-{
- /**
- * Using static buffer with maximum possible size,
- * extra byte is needed for prefixing zero at index 0.
- */
- uint8_t write_buffer[PAGE_SIZE + 1] = { 0 };
- if (len > PAGE_SIZE)
- return SPI_GENERIC_ERROR;
-
- /* First byte represents the writing offset and should always be zero. */
- memcpy(&write_buffer[1], buf, len);
-
- return lspcon_i2c_spi_write_data(fd, PAGE_ADDRESS, write_buffer, len + 1);
-}
-
-static int lspcon_i2c_spi_write_256(struct flashctx *flash, const uint8_t *buf,
- unsigned int start, unsigned int len)
-{
- int ret = 0;
- if (start & 0xff)
- return default_spi_write_256(flash, buf, start, len);
-
- int fd = get_fd_from_context(flash);
- if (fd < 0)
- return SPI_GENERIC_ERROR;
-
- ret |= lspcon_i2c_spi_disable_all_protection(fd);
- /* Enable hardware write and reset clt2SPI interface. */
- ret |= lspcon_i2c_spi_enable_hw_write(fd);
- ret |= lspcon_i2c_clt2_spi_reset(fd);
-
- for (unsigned int i = 0; i < len; i += PAGE_SIZE) {
- ret |= lspcon_i2c_spi_map_page(fd, start + i);
- ret |= lspcon_i2c_spi_write_page(fd, buf + i, min(len - i, PAGE_SIZE));
- }
-
- ret |= lspcon_i2c_spi_enable_write_protection(fd);
- ret |= lspcon_i2c_spi_disable_hw_write(fd);
-
- return ret;
-}
-
-static int lspcon_i2c_spi_write_aai(struct flashctx *flash, const uint8_t *buf,
- unsigned int start, unsigned int len)
-{
- msg_perr("%s: AAI write function is not supported.\n",
- __func__);
- return SPI_GENERIC_ERROR;
-}
-
-static struct spi_master spi_master_i2c_lspcon = {
- .max_data_read = 16,
- .max_data_write = 12,
- .command = lspcon_i2c_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = lspcon_i2c_spi_read,
- .write_256 = lspcon_i2c_spi_write_256,
- .write_aai = lspcon_i2c_spi_write_aai,
-};
-
-/* TODO: MPU still stopped at this point, probably need to reset it. */
-static int lspcon_i2c_spi_shutdown(void *data)
-{
- int ret = 0;
- struct lspcon_i2c_spi_data *lspcon_data =
- (struct lspcon_i2c_spi_data *)data;
- int fd = lspcon_data->fd;
- ret |= lspcon_i2c_spi_enable_write_protection(fd);
- ret |= lspcon_i2c_spi_toggle_register_protection(fd, 0);
- i2c_close(fd);
- free(data);
-
- return ret;
-}
-
-/* TODO: remove this out of the specific SPI master implementation. */
-static int get_bus(void)
-{
- char *bus_str = extract_programmer_param("bus");
- int ret = SPI_GENERIC_ERROR;
- if (bus_str) {
- char *bus_suffix;
- errno = 0;
- int bus = (int)strtol(bus_str, &bus_suffix, 10);
- if (errno != 0 || bus_str == bus_suffix) {
- msg_perr("%s: Could not convert 'bus'.\n", __func__);
- goto get_bus_done;
- }
-
- if (bus < 0 || bus > 255) {
- msg_perr("%s: Value for 'bus' is out of range(0-255).\n",
- __func__);
- goto get_bus_done;
- }
-
- if (strlen(bus_suffix) > 0) {
- msg_perr("%s: Garbage following 'bus' value.\n",
- __func__);
- goto get_bus_done;
- }
-
- msg_pinfo("Using i2c bus %i.\n", bus);
- ret = bus;
- goto get_bus_done;
- } else {
- msg_perr("%s: Bus number not specified.\n", __func__);
- }
-get_bus_done:
- if (bus_str)
- free(bus_str);
-
- return ret;
-}
-
-int lspcon_i2c_spi_init(void)
-{
- int lspcon_i2c_spi_bus = get_bus();
- if (lspcon_i2c_spi_bus < 0)
- return SPI_GENERIC_ERROR;
-
- int ret = 0;
- int fd = i2c_open(lspcon_i2c_spi_bus, REGISTER_ADDRESS, 0);
- if (fd < 0)
- return fd;
-
- ret |= lspcon_i2c_spi_reset_mpu_stop(fd);
- if (ret) {
- msg_perr("%s: call to reset_mpu_stop failed.\n", __func__);
- return ret;
- }
-
- struct lspcon_i2c_spi_data *data = calloc(1, sizeof(struct lspcon_i2c_spi_data));
- if (!data) {
- msg_perr("Unable to allocate space for extra SPI master data.\n");
- return SPI_GENERIC_ERROR;
- }
-
- data->fd = fd;
- spi_master_i2c_lspcon.data = data;
-
- ret |= register_shutdown(lspcon_i2c_spi_shutdown, data);
- ret |= register_spi_master(&spi_master_i2c_lspcon);
-
- return ret;
-}
diff --git a/mcp6x_spi.c b/mcp6x_spi.c
index b53d07bd4..165bca50f 100644
--- a/mcp6x_spi.c
+++ b/mcp6x_spi.c
@@ -19,13 +19,12 @@
* created by Michael Karcher.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <stdlib.h>
#include <ctype.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
/* Bit positions for each pin. */
@@ -36,75 +35,96 @@
#define MCP6X_SPI_REQUEST 0
#define MCP6X_SPI_GRANT 8
-static void *mcp6x_spibar = NULL;
-
-/* Cached value of last GPIO state. */
-static uint8_t mcp_gpiostate;
+struct mcp6x_spi_data {
+ void *spibar;
+ /* Cached value of last GPIO state. */
+ uint8_t gpiostate;
+};
-static void mcp6x_request_spibus(void)
+static void mcp6x_request_spibus(void *spi_data)
{
- mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
- mcp_gpiostate |= 1 << MCP6X_SPI_REQUEST;
- mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+ struct mcp6x_spi_data *data = spi_data;
+
+ data->gpiostate = mmio_readb(data->spibar + 0x530);
+ data->gpiostate |= 1 << MCP6X_SPI_REQUEST;
+ mmio_writeb(data->gpiostate, data->spibar + 0x530);
/* Wait until we are allowed to use the SPI bus. */
- while (!(mmio_readw(mcp6x_spibar + 0x530) & (1 << MCP6X_SPI_GRANT))) ;
+ while (!(mmio_readw(data->spibar + 0x530) & (1 << MCP6X_SPI_GRANT))) ;
/* Update the cache. */
- mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
+ data->gpiostate = mmio_readb(data->spibar + 0x530);
}
-static void mcp6x_release_spibus(void)
+static void mcp6x_release_spibus(void *spi_data)
{
- mcp_gpiostate &= ~(1 << MCP6X_SPI_REQUEST);
- mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+ struct mcp6x_spi_data *data = spi_data;
+
+ data->gpiostate &= ~(1 << MCP6X_SPI_REQUEST);
+ mmio_writeb(data->gpiostate, data->spibar + 0x530);
}
-static void mcp6x_bitbang_set_cs(int val)
+static void mcp6x_bitbang_set_cs(int val, void *spi_data)
{
- mcp_gpiostate &= ~(1 << MCP6X_SPI_CS);
- mcp_gpiostate |= (val << MCP6X_SPI_CS);
- mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+ struct mcp6x_spi_data *data = spi_data;
+
+ data->gpiostate &= ~(1 << MCP6X_SPI_CS);
+ data->gpiostate |= (val << MCP6X_SPI_CS);
+ mmio_writeb(data->gpiostate, data->spibar + 0x530);
}
-static void mcp6x_bitbang_set_sck(int val)
+static void mcp6x_bitbang_set_sck(int val, void *spi_data)
{
- mcp_gpiostate &= ~(1 << MCP6X_SPI_SCK);
- mcp_gpiostate |= (val << MCP6X_SPI_SCK);
- mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+ struct mcp6x_spi_data *data = spi_data;
+
+ data->gpiostate &= ~(1 << MCP6X_SPI_SCK);
+ data->gpiostate |= (val << MCP6X_SPI_SCK);
+ mmio_writeb(data->gpiostate, data->spibar + 0x530);
}
-static void mcp6x_bitbang_set_mosi(int val)
+static void mcp6x_bitbang_set_mosi(int val, void *spi_data)
{
- mcp_gpiostate &= ~(1 << MCP6X_SPI_MOSI);
- mcp_gpiostate |= (val << MCP6X_SPI_MOSI);
- mmio_writeb(mcp_gpiostate, mcp6x_spibar + 0x530);
+ struct mcp6x_spi_data *data = spi_data;
+
+ data->gpiostate &= ~(1 << MCP6X_SPI_MOSI);
+ data->gpiostate |= (val << MCP6X_SPI_MOSI);
+ mmio_writeb(data->gpiostate, data->spibar + 0x530);
}
-static int mcp6x_bitbang_get_miso(void)
+static int mcp6x_bitbang_get_miso(void *spi_data)
{
- mcp_gpiostate = mmio_readb(mcp6x_spibar + 0x530);
- return (mcp_gpiostate >> MCP6X_SPI_MISO) & 0x1;
+ struct mcp6x_spi_data *data = spi_data;
+
+ data->gpiostate = mmio_readb(data->spibar + 0x530);
+ return (data->gpiostate >> MCP6X_SPI_MISO) & 0x1;
}
static const struct bitbang_spi_master bitbang_spi_master_mcp6x = {
- .set_cs = mcp6x_bitbang_set_cs,
- .set_sck = mcp6x_bitbang_set_sck,
- .set_mosi = mcp6x_bitbang_set_mosi,
- .get_miso = mcp6x_bitbang_get_miso,
- .request_bus = mcp6x_request_spibus,
- .release_bus = mcp6x_release_spibus,
- .half_period = 0,
+ .set_cs = mcp6x_bitbang_set_cs,
+ .set_sck = mcp6x_bitbang_set_sck,
+ .set_mosi = mcp6x_bitbang_set_mosi,
+ .get_miso = mcp6x_bitbang_get_miso,
+ .request_bus = mcp6x_request_spibus,
+ .release_bus = mcp6x_release_spibus,
+ .half_period = 0,
};
+static int mcp6x_shutdown(void *spi_data)
+{
+ free(spi_data);
+ return 0;
+}
+
int mcp6x_spi_init(int want_spi)
{
uint16_t status;
uint32_t mcp6x_spibaraddr;
struct pci_dev *smbusdev;
+ void *mcp6x_spibar = NULL;
+ uint8_t mcp_gpiostate;
/* Look for the SMBus device (SMBus PCI class) */
- smbusdev = pci_dev_find_vendorclass(0x10de, 0x0c05);
+ smbusdev = pcidev_find_vendorclass(0x10de, 0x0c05);
if (!smbusdev) {
if (want_spi) {
msg_perr("ERROR: SMBus device not found. Not enabling "
@@ -126,7 +146,7 @@ int mcp6x_spi_init(int want_spi)
* 32-bit non-prefetchable memory BAR.
*/
mcp6x_spibaraddr &= ~0xffff;
- msg_pdbg("MCP SPI BAR is at 0x%08x\n", mcp6x_spibaraddr);
+ msg_pdbg("MCP SPI BAR is at 0x%08"PRIx32"\n", mcp6x_spibaraddr);
/* Accessing a NULL pointer BAR is evil. Don't do it. */
if (!mcp6x_spibaraddr && want_spi) {
@@ -151,7 +171,19 @@ int mcp6x_spi_init(int want_spi)
(status >> MCP6X_SPI_GRANT) & 0x1);
mcp_gpiostate = status & 0xff;
- if (register_spi_bitbang_master(&bitbang_spi_master_mcp6x)) {
+ struct mcp6x_spi_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ return 1;
+ }
+ data->spibar = mcp6x_spibar;
+ data->gpiostate = mcp_gpiostate;
+
+ if (register_shutdown(mcp6x_shutdown, data)) {
+ free(data);
+ return 1;
+ }
+ if (register_spi_bitbang_master(&bitbang_spi_master_mcp6x, data)) {
/* This should never happen. */
msg_perr("MCP6X bitbang SPI master init failed!\n");
return 1;
@@ -159,5 +191,3 @@ int mcp6x_spi_init(int want_spi)
return 0;
}
-
-#endif
diff --git a/mec1308.c b/mec1308.c
deleted file mode 100644
index c4b34f571..000000000
--- a/mec1308.c
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2010-2020, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2 as published by the Free
- * Software Foundation.
- */
-
-#if defined(__i386__) || defined(__x86_64__)
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "flash.h"
-#include "hwaccess.h"
-#include "chipdrivers.h"
-#include "programmer.h"
-#include "spi.h"
-
-#define MEC1308_SIO_PORT1 0x2e
-#define MEC1308_SIO_PORT2 0x4e
-#define MEC1308_SIO_ENTRY_KEY 0x55
-#define MEC1308_SIO_EXIT_KEY 0xaa
-
-#define MEC1308_SIOCFG_LDN 0x07 /* LDN Bank Selector */
-#define MEC1308_DEVICE_ID_REG 0x20 /* Device ID Register */
-#define MEC1308_DEVICE_ID_VAL 0x4d /* Device ID Value for MEC1308 */
-#define MEC1310_DEVICE_ID_VAL 0x04 /* Device ID Value for MEC1310 */
-#define MEC1308_DEVICE_REV 0x21 /* Device Revision ID Register */
-
-#define MEC1308_MBX_CMD 0x82 /* mailbox command register offset */
-#define MEC1308_MBX_EXT_CMD 0x83 /* mailbox ext. command reg offset */
-#define MEC1308_MBX_DATA_START 0x84 /* first mailbox data register offset */
-#define MEC1308_MBX_DATA_END 0x91 /* last mailbox data register offset */
-
-static unsigned int mbx_data; /* Mailbox register interface data address*/
-
-/*
- * These command codes depend on EC firmware. The ones listed below are input
- * using the mailbox interface, though others may be input using the ACPI
- * interface. Some commands also have an output value (ie pass/failure code)
- * which EC writes to the mailbox command register after completion.
- */
-#define MEC1308_CMD_SMI_ENABLE 0x84
-#define MEC1308_CMD_SMI_DISABLE 0x85
-#define MEC1308_CMD_ACPI_ENABLE 0x86
-#define MEC1308_CMD_ACPI_DISABLE 0x87
-
-/*
- * Passthru commands are also input using the mailbox interface. Passthru mode
- * enter/start/end commands are special since they require a command word to
- * be written to the data registers. Other passthru commands are performed
- * after passthru mode has been started.
- *
- * Multiple passthru mode commands may be issued before ending passthru mode.
- * You do not need to enter, start, and end passthru mode for each SPI
- * command. However, other mailbox commands might not work when passthru mode
- * is enabled. For example, you may read all SPI chip content while in passthru
- * mode, but you should exit passthru mode before performing other EC commands
- * such as reading fan speed.
- */
-#define MEC1308_CMD_PASSTHRU 0x55 /* force EC to process word */
-#define MEC1308_CMD_PASSTHRU_SUCCESS 0xaa /* success code for passthru */
-#define MEC1308_CMD_PASSTHRU_FAIL 0xfe /* failure code for passthru */
-#define MEC1308_CMD_PASSTHRU_ENTER "PathThruMode" /* not a typo... */
-#define MEC1308_CMD_PASSTHRU_START "Start"
-#define MEC1308_CMD_PASSTHRU_EXIT "End_Mode"
-#define MEC1308_CMD_PASSTHRU_CS_EN 0xf0 /* chip-select enable */
-#define MEC1308_CMD_PASSTHRU_CS_DIS 0xf1 /* chip-select disable */
-#define MEC1308_CMD_PASSTHRU_SEND 0xf2 /* send byte from data0 */
-#define MEC1308_CMD_PASSTHRU_READ 0xf3 /* read byte, place in data0 */
-
-typedef struct
-{
- unsigned int in_sio_cfgmode;
- unsigned int mbx_idx; /* Mailbox register interface index address */
- unsigned int mbx_data; /* Mailbox register interface data address*/
-} mec1308_data_t;
-
-static void mec1308_sio_enter(mec1308_data_t *ctx_data, uint16_t port)
-{
- if (ctx_data->in_sio_cfgmode)
- return;
-
- OUTB(MEC1308_SIO_ENTRY_KEY, port);
- ctx_data->in_sio_cfgmode = 1;
-}
-
-static void mec1308_sio_exit(mec1308_data_t *ctx_data, uint16_t port)
-{
- if (!ctx_data->in_sio_cfgmode)
- return;
-
- OUTB(MEC1308_SIO_EXIT_KEY, port);
- ctx_data->in_sio_cfgmode = 0;
-}
-
-/** probe for super i/o index
- * @port: allocated buffer to store port
- *
- * returns 0 to indicate success, <0 to indicate error
- */
-static int mec1308_get_sio_index(mec1308_data_t *ctx_data, uint16_t *port)
-{
- uint16_t ports[] = { MEC1308_SIO_PORT1,
- MEC1308_SIO_PORT2,
- };
- size_t i;
- static uint16_t port_internal, port_found = 0;
-
- if (port_found) {
- *port = port_internal;
- return 0;
- }
-
- if (rget_io_perms())
- return -1;
-
- for (i = 0; i < ARRAY_SIZE(ports); i++) {
- uint8_t tmp8;
-
- /*
- * Only after config mode has been successfully entered will the
- * index port will read back the last value written to it.
- * So we will attempt to enter config mode, set the index
- * register, and see if the index register retains the value.
- *
- * Note: It seems to work "best" when using a device ID register
- * as the index and reading from the data port before reading
- * the index port.
- */
- mec1308_sio_enter(ctx_data, ports[i]);
- OUTB(MEC1308_DEVICE_ID_REG, ports[i]);
- tmp8 = INB(ports[i] + 1);
- tmp8 = INB(ports[i]);
- if ((tmp8 != MEC1308_DEVICE_ID_REG)) {
- ctx_data->in_sio_cfgmode = 0;
- continue;
- }
-
- port_internal = ports[i];
- port_found = 1;
- break;
- }
-
- if (!port_found) {
- msg_cdbg("\nfailed to obtain super i/o index\n");
- return -1;
- }
-
- msg_cdbg("\nsuper i/o index = 0x%04x\n", port_internal);
- *port = port_internal;
- return 0;
-}
-
-static uint8_t mbx_read(mec1308_data_t *ctx_data, uint8_t idx)
-{
- OUTB(idx, ctx_data->mbx_idx);
- return INB(mbx_data);
-}
-
-static int mbx_wait(mec1308_data_t *ctx_data)
-{
- int i;
- int max_attempts = 10000;
- int rc = 0;
-
- for (i = 0; mbx_read(ctx_data, MEC1308_MBX_CMD); i++) {
- if (i == max_attempts) {
- rc = 1;
- break;
- }
- /* FIXME: This delay adds determinism to the delay period. It
- was chosen arbitrarily thru some experiments. */
- programmer_delay(2);
- }
-
- return rc;
-}
-
-static int mbx_write(mec1308_data_t *ctx_data, uint8_t idx, uint8_t data)
-{
- int rc = 0;
-
- if (idx == MEC1308_MBX_CMD && mbx_wait(ctx_data)) {
- msg_perr("%s: command register not clear\n", __func__);
- return 1;
- }
-
- OUTB(idx, ctx_data->mbx_idx);
- OUTB(data, mbx_data);
-
- if (idx == MEC1308_MBX_CMD)
- rc = mbx_wait(ctx_data);
-
- return rc;
-}
-
-static void mbx_clear(mec1308_data_t *ctx_data)
-{
- int reg;
-
- for (reg = MEC1308_MBX_DATA_START; reg < MEC1308_MBX_DATA_END; reg++)
- mbx_write(ctx_data, reg, 0x00);
- mbx_write(ctx_data, MEC1308_MBX_CMD, 0x00);
-}
-
-static int mec1308_exit_passthru_mode(mec1308_data_t *ctx_data)
-{
- uint8_t tmp8;
- size_t i;
-
- /* exit passthru mode */
- for (i = 0; i < strlen(MEC1308_CMD_PASSTHRU_EXIT); i++) {
- mbx_write(ctx_data, MEC1308_MBX_DATA_START + i,
- MEC1308_CMD_PASSTHRU_EXIT[i]);
- }
-
- if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU)) {
- msg_pdbg("%s(): exit passthru command timed out\n", __func__);
- return 1;
- }
-
- tmp8 = mbx_read(ctx_data, MEC1308_MBX_DATA_START);
- msg_pdbg("%s: result: 0x%02x ", __func__, tmp8);
- if (tmp8 == MEC1308_CMD_PASSTHRU_SUCCESS) {
- msg_pdbg("(exited passthru mode)\n");
- } else if (tmp8 == MEC1308_CMD_PASSTHRU_FAIL) {
- msg_pdbg("(failed to exit passthru mode)\n");
- }
-
- return 0;
-}
-
-static int enter_passthru_mode(mec1308_data_t *ctx_data)
-{
- uint8_t tmp8;
- size_t i;
-
- /*
- * Enter passthru mode. If the EC does not successfully enter passthru
- * mode the first time, we'll clear the mailbox and issue the "exit
- * passthru mode" command sequence up to 3 times or until it arrives in
- * a known state.
- *
- * Note: This workaround was developed experimentally.
- */
- for (i = 0; i < 3; i++) {
- size_t j;
-
- msg_pdbg("%s(): entering passthru mode, attempt %d out of 3\n",
- __func__, (int)(i + 1));
- for (j = 0; j < strlen(MEC1308_CMD_PASSTHRU_ENTER); j++) {
- mbx_write(ctx_data, MEC1308_MBX_DATA_START + j,
- MEC1308_CMD_PASSTHRU_ENTER[j]);
- }
-
- if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU))
- msg_pdbg("%s(): enter passthru command timed out\n",
- __func__);
-
- tmp8 = mbx_read(ctx_data, MEC1308_MBX_DATA_START);
- if (tmp8 == MEC1308_CMD_PASSTHRU_SUCCESS)
- break;
-
- msg_pdbg("%s(): command failed, clearing data registers and "
- "issuing full exit passthru command...\n", __func__);
- mbx_clear(ctx_data);
- mec1308_exit_passthru_mode(ctx_data);
- }
-
- if (tmp8 != MEC1308_CMD_PASSTHRU_SUCCESS) {
- msg_perr("%s(): failed to enter passthru mode, result=0x%02x\n",
- __func__, tmp8);
- return 1;
- }
-
- msg_pdbg("%s(): enter passthru mode return code: 0x%02x\n",
- __func__, tmp8);
-
- /* start passthru mode */
- for (i = 0; i < strlen(MEC1308_CMD_PASSTHRU_START); i++)
- mbx_write(ctx_data, MEC1308_MBX_DATA_START + i,
- MEC1308_CMD_PASSTHRU_START[i]);
- if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU)) {
- msg_pdbg("%s(): start passthru command timed out\n", __func__);
- return 1;
- }
- tmp8 = mbx_read(ctx_data, MEC1308_MBX_DATA_START);
- if (tmp8 != MEC1308_CMD_PASSTHRU_SUCCESS) {
- msg_perr("%s(): failed to enter passthru mode, result=%02x\n",
- __func__, tmp8);
- return 1;
- }
- msg_pdbg("%s(): start passthru mode return code: 0x%02x\n",
- __func__, tmp8);
-
- return 0;
-}
-
-static int mec1308_shutdown(void *data)
-{
- mec1308_data_t *ctx_data = (mec1308_data_t *)data;
-
- /* Exit passthru mode before performing commands which do not affect
- the SPI ROM */
- mec1308_exit_passthru_mode(ctx_data);
-
- /* Re-enable SMI and ACPI.
- FIXME: is there an ordering dependency? */
- if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_SMI_ENABLE))
- msg_pdbg("%s: unable to re-enable SMI\n", __func__);
- if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_ACPI_ENABLE))
- msg_pdbg("%s: unable to re-enable ACPI\n", __func__);
-
- free(data);
- return 0;
-}
-
-static int mec1308_chip_select(mec1308_data_t *ctx_data)
-{
- return mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_CS_EN);
-}
-
-static int mec1308_chip_deselect(mec1308_data_t *ctx_data)
-{
- return mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_CS_DIS);
-}
-
-/*
- * MEC1308 will not allow direct access to SPI chip from host if EC is
- * connected to LPC bus. This function will forward commands issued thru
- * mailbox interface to the SPI flash chip.
- */
-static int mec1308_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
-{
- int rc = 0;
- size_t i;
- mec1308_data_t *ctx_data = (mec1308_data_t *)flash->mst->spi.data;
-
- if (mec1308_chip_select(ctx_data))
- return 1;
-
- for (i = 0; i < writecnt; i++) {
- if (mbx_write(ctx_data, MEC1308_MBX_DATA_START, writearr[i]) ||
- mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_SEND)) {
- msg_pdbg("%s: failed to issue send command\n",__func__);
- rc = 1;
- goto mec1308_spi_send_command_exit;
- }
- }
-
- for (i = 0; i < readcnt; i++) {
- if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_PASSTHRU_READ)) {
- msg_pdbg("%s: failed to issue read command\n",__func__);
- rc = 1;
- goto mec1308_spi_send_command_exit;
- }
- readarr[i] = mbx_read(ctx_data, MEC1308_MBX_DATA_START);
- }
-
-mec1308_spi_send_command_exit:
- rc |= mec1308_chip_deselect(ctx_data);
- return rc;
-}
-
-static struct spi_master spi_master_mec1308 = {
- .max_data_read = 256, /* FIXME: should be MAX_DATA_READ_UNLIMITED? */
- .max_data_write = 256, /* FIXME: should be MAX_DATA_WRITE_UNLIMITED? */
- .command = mec1308_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
-};
-
-int mec1308_init(void)
-{
- uint16_t sio_port;
- uint8_t device_id;
- uint8_t tmp8;
- int ret = 0;
- char *p = NULL;
- mec1308_data_t *ctx_data = NULL;
-
- msg_pdbg("%s(): entered\n", __func__);
-
- ctx_data = calloc(1, sizeof(mec1308_data_t));
- if (!ctx_data) {
- msg_perr("Unable to allocate space for extra context data.\n");
- return 1;
- }
-
- p = extract_programmer_param("type");
- if (p && strcmp(p, "ec")) {
- msg_pdbg("mec1308 only supports \"ec\" type devices\n");
- ret = 1;
- goto mec1308_init_exit;
- }
-
- if (mec1308_get_sio_index(ctx_data, &sio_port) < 0) {
- msg_pdbg("MEC1308 not found (probe failed).\n");
- ret = 1;
- goto mec1308_init_exit;
- }
- device_id = sio_read(sio_port, MEC1308_DEVICE_ID_REG);
- switch(device_id) {
- case MEC1308_DEVICE_ID_VAL:
- msg_pdbg("Found EC: MEC1308 (ID:0x%02x,Rev:0x%02x) on "
- "sio_port:0x%x.\n", device_id,
- sio_read(sio_port, MEC1308_DEVICE_REV), sio_port);
- break;
- case MEC1310_DEVICE_ID_VAL:
- msg_pdbg("Found EC: MEC1310 (ID:0x%02x,Rev:0x%02x) on "
- "sio_port:0x%x.\n", device_id,
- sio_read(sio_port, MEC1308_DEVICE_REV), sio_port);
- break;
- default:
- msg_pdbg("MEC1308 not found\n");
- ret = 1;
- goto mec1308_init_exit;
- }
-
- /*
- * setup mailbox interface at LDN 9
- */
- sio_write(sio_port, MEC1308_SIOCFG_LDN, 0x09);
- tmp8 = sio_read(sio_port, 0x30);
- tmp8 |= 1;
- sio_write(sio_port, 0x30, tmp8); /* activate logical device */
-
- ctx_data->mbx_idx = (unsigned int)sio_read(sio_port, 0x60) << 8 |
- sio_read(sio_port, 0x61);
- mbx_data = ctx_data->mbx_idx + 1;
- msg_pdbg("%s: mbx_idx: 0x%04x, mbx_data: 0x%04x\n",
- __func__, ctx_data->mbx_idx, mbx_data);
-
- /* Exit Super I/O config mode */
- mec1308_sio_exit(ctx_data, sio_port);
-
- /* Now that we can read the mailbox, we will wait for any remaining
- * command to finish.*/
- if (mbx_wait(ctx_data) != 0) {
- msg_perr("%s: mailbox is not available\n", __func__);
- ret = 1;
- goto mec1308_init_exit;
- }
-
- /* Further setup -- disable SMI and ACPI.
- FIXME: is there an ordering dependency? */
- if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_ACPI_DISABLE)) {
- msg_pdbg("%s: unable to disable ACPI\n", __func__);
- ret = 1;
- goto mec1308_init_exit;
- }
-
- if (mbx_write(ctx_data, MEC1308_MBX_CMD, MEC1308_CMD_SMI_DISABLE)) {
- msg_pdbg("%s: unable to disable SMI\n", __func__);
- ret = 1;
- goto mec1308_init_exit;
- }
-
- if (register_shutdown(mec1308_shutdown, ctx_data)) {
- ret = 1;
- goto mec1308_init_exit;
- }
-
- /*
- * Enter SPI Pass-Thru Mode after commands which do not require access
- * to SPI ROM are complete. We'll start by doing the exit_passthru_mode
- * sequence, which is benign if the EC is already in passthru mode.
- */
- mec1308_exit_passthru_mode(ctx_data);
-
- if (enter_passthru_mode(ctx_data)) {
- ret = 1;
- goto mec1308_init_exit;
- }
-
- internal_buses_supported |= BUS_LPC; /* for LPC <--> SPI bridging */
- spi_master_mec1308.data = ctx_data;
- register_spi_master(&spi_master_mec1308);
- msg_pdbg("%s(): successfully initialized mec1308\n", __func__);
-
-mec1308_init_exit:
- free(p);
- if (ret)
- free(ctx_data);
- return ret;
-}
-#endif
diff --git a/mediatek_i2c_spi.c b/mediatek_i2c_spi.c
new file mode 100644
index 000000000..d28e47818
--- /dev/null
+++ b/mediatek_i2c_spi.c
@@ -0,0 +1,542 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2021 The Chromium OS Authors
+ *
+ * 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 <linux/i2c-dev.h>
+#include <linux/i2c.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "flash.h"
+#include "i2c_helper.h"
+#include "programmer.h"
+#include "spi.h"
+
+#define ISP_PORT (0x92 >> 1)
+#define DEBUG_PORT (0xb2 >> 1)
+
+#define MTK_CMD_WRITE 0x10
+#define MTK_CMD_READ 0x11
+#define MTK_CMD_END 0x12
+
+struct mediatek_data {
+ int fd;
+ unsigned long funcs;
+};
+
+// Returns null pointer on error.
+static const struct mediatek_data *get_data_from_context(
+ const struct flashctx *flash)
+{
+ if (!flash || !flash->mst || !flash->mst->spi.data) {
+ msg_pdbg("Unable to extract data from flash context\n");
+ return NULL;
+ }
+ return (const struct mediatek_data *)flash->mst->spi.data;
+}
+
+// Returns bytes read, negative value on error.
+static int read_raw(const struct mediatek_data *port, uint16_t addr,
+ uint8_t *buf, size_t len)
+{
+ int ret;
+
+ if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) {
+ msg_pdbg("Invalid length for read command: %zu\n", len);
+ return SPI_INVALID_LENGTH;
+ }
+
+ ret = ioctl(port->fd, I2C_SLAVE, addr);
+ if (ret) {
+ msg_pdbg("Failed to set slave address 0x%02x (%d)\n", addr, ret);
+ return ret;
+ }
+
+ if (port->funcs & I2C_FUNC_I2C) {
+ // Use raw I2C read.
+ uint8_t command = MTK_CMD_READ;
+ if (write(port->fd, &command, 1) != 1) {
+ return SPI_GENERIC_ERROR;
+ }
+ if (read(port->fd, buf, len) != (int)len) {
+ return SPI_GENERIC_ERROR;
+ }
+ return len;
+ }
+
+ union i2c_smbus_data data = {
+ .block[0] = len,
+ };
+ struct i2c_smbus_ioctl_data args = {
+ .read_write = I2C_SMBUS_READ,
+ .command = MTK_CMD_READ,
+ .size = I2C_SMBUS_I2C_BLOCK_DATA,
+ .data = &data,
+ };
+ ret = ioctl(port->fd, I2C_SMBUS, &args);
+ if (ret) {
+ msg_pdbg("Failed to read SMBus I2C block data\n");
+ return ret;
+ }
+ memcpy(buf, args.data->block + 1, len);
+ return args.data->block[0];
+}
+
+// Returns non-zero value on error.
+static int write_command(const struct mediatek_data *port, uint16_t addr,
+ uint8_t command, const uint8_t *buf, size_t len)
+{
+ int ret;
+
+ if (len > I2C_SMBUS_BLOCK_MAX) {
+ msg_pdbg("Invalid length for write command: %zu\n", len);
+ return SPI_INVALID_LENGTH;
+ }
+
+ ret = ioctl(port->fd, I2C_SLAVE, addr);
+ if (ret) {
+ msg_pdbg("Failed to set slave address: 0x%02x\n", addr);
+ return ret;
+ }
+
+ if (port->funcs & I2C_FUNC_I2C) {
+ // Use raw I2C write.
+ uint8_t raw_buffer[I2C_SMBUS_BLOCK_MAX + 1];
+ raw_buffer[0] = command;
+ if (len > 0) {
+ memcpy(raw_buffer + 1, buf, len);
+ }
+ if (write(port->fd, raw_buffer, len + 1) != (int)(len + 1)) {
+ return SPI_GENERIC_ERROR;
+ }
+ return 0;
+ }
+
+ union i2c_smbus_data data = {0};
+ struct i2c_smbus_ioctl_data args = {
+ .read_write = I2C_SMBUS_WRITE,
+ .command = command,
+ .data = &data,
+ };
+
+ // Special case single byte commands, as empty I2C block data commands
+ // failed on this component in practice.
+ if (len == 0) {
+ args.size = I2C_SMBUS_BYTE;
+ ret = ioctl(port->fd, I2C_SMBUS, &args);
+ if (ret) {
+ msg_pdbg("Failed to write SMBus byte: 0x%02x\n", command);
+ }
+ return ret;
+ }
+
+ args.size = I2C_SMBUS_I2C_BLOCK_DATA;
+ data.block[0] = len;
+ if (buf && len) {
+ memcpy(data.block + 1, buf, len);
+ }
+ ret = ioctl(port->fd, I2C_SMBUS, &args);
+ if (ret) {
+ msg_pdbg("Failed to write SMBus I2C block data: 0x%02x\n", command);
+ }
+ return ret;
+}
+
+// Returns non-zero value on error.
+static int write_raw(const struct mediatek_data *port, uint16_t addr,
+ const uint8_t *buf, size_t len)
+{
+ if (len < 1) {
+ msg_pdbg("Invalid write length: %zu\n", len);
+ return SPI_INVALID_LENGTH;
+ }
+ return write_command(port, addr, buf[0], buf + 1, len - 1);
+}
+
+// Read from a GPIO register via debug port. Returns non-zero value on error.
+static int mediatek_read_gpio(const struct mediatek_data *port,
+ uint16_t gpio_addr, uint8_t *value)
+{
+ int ret;
+
+ uint8_t data[2];
+ data[0] = gpio_addr >> 8;
+ data[1] = gpio_addr & 0xff;
+
+ ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE, data, ARRAY_SIZE(data));
+ if (ret) {
+ msg_pdbg("Failed to issue read GPIO command at address 0x%04x\n", gpio_addr);
+ return ret;
+ }
+
+ size_t len = 1;
+ ret = read_raw(port, DEBUG_PORT, value, len);
+ if (ret < 0) {
+ msg_pdbg("Failed to read GPIO register at address 0x%04x\n", gpio_addr);
+ return ret;
+ }
+
+ if (ret != 1) {
+ msg_pdbg("GPIO read returned improper length: %d\n", ret);
+ return SPI_INVALID_LENGTH;
+ }
+
+ return 0;
+}
+
+// Write to a GPIO register via the debug port. Returns non-zero value on error.
+static int mediatek_write_gpio(const struct mediatek_data *port,
+ uint16_t gpio_addr, uint8_t value)
+{
+ uint8_t data[3];
+ data[0] = gpio_addr >> 8;
+ data[1] = gpio_addr & 0xff;
+ data[2] = value;
+
+ return write_command(port, DEBUG_PORT, MTK_CMD_WRITE, data, ARRAY_SIZE(data));
+}
+
+// Write a single bit value to a GPIO register via the debug port. Returns
+// non-zero value on error.
+static int mediatek_set_gpio_bit(const struct mediatek_data *port,
+ uint16_t gpio_addr, int bit, int value)
+{
+ int ret;
+ uint8_t data;
+
+ ret = mediatek_read_gpio(port, gpio_addr, &data);
+ if (ret) {
+ msg_pdbg("Failed to read GPIO 0x%04x\n", gpio_addr);
+ return ret;
+ }
+
+ if (value) {
+ data |= (1 << bit);
+ } else {
+ data &= ~(1 << bit);
+ }
+
+ ret = mediatek_write_gpio(port, gpio_addr, data);
+ if (ret) {
+ msg_pdbg("Failed to set GPIO 0x%04x to 0x%02x\n", gpio_addr, data);
+ return ret;
+ }
+ return ret;
+}
+
+// Poke the GPIO line that goes to SPI WP# using the MST9U GPIO register
+// addresses. Returns non-zero value on error.
+static int mediatek_set_write_protect(const struct mediatek_data *port,
+ int protected)
+{
+ int ret;
+
+ ret = mediatek_set_gpio_bit(port, 0x426, 7, (protected == 0));
+ if (ret) {
+ msg_perr("Failed to set GPIO out value: %d\n", protected == 0);
+ return ret;
+ }
+
+ ret = mediatek_set_gpio_bit(port, 0x428, 7, (protected != 0));
+ if (ret) {
+ msg_perr("Failed to set GPIO enable value: %d\n", protected != 0);
+ return ret;
+ }
+
+ return 0;
+}
+
+// Enter serial debug mode using "Option 1" for MST9U and select I2C channel 0
+// to configure write protect GPIOs. Returns non-zero value on error.
+static int mediatek_enter_serial_debug_mode(const struct mediatek_data *port)
+{
+ int ret;
+
+ uint8_t enter_serial_debug[] = { 'S', 'E', 'R', 'D', 'B' };
+ ret = write_raw(port, DEBUG_PORT, enter_serial_debug,
+ ARRAY_SIZE(enter_serial_debug));
+ if (ret) {
+ msg_perr("Failed to send enter serial debug mode command\n");
+ return ret;
+ }
+
+ uint8_t enter_single_step_1[] = { 0xc0, 0xc1, 0x53 };
+ ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE,
+ enter_single_step_1, ARRAY_SIZE(enter_single_step_1));
+ if (ret) {
+ msg_perr("Failed to enter serial single step mode (part 1)\n");
+ return ret;
+ }
+
+ uint8_t enter_single_step_2[] = { 0x1f, 0xc1, 0x53 };
+ ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE, enter_single_step_2,
+ ARRAY_SIZE(enter_single_step_2));
+ if (ret) {
+ msg_perr("Failed to enter serial single step mode (part 2)\n");
+ return ret;
+ }
+
+ // Send each I2C channel 0 configuration byte individually.
+ uint8_t i2c_channel_0_config[] =
+ { 0x80, 0x82, 0x84, 0x51, 0x7f, 0x37, 0x61 };
+ for (size_t i = 0; i < ARRAY_SIZE(i2c_channel_0_config); ++i) {
+ ret = write_command(
+ port, DEBUG_PORT, i2c_channel_0_config[i], NULL, 0);
+ if (ret) {
+ msg_perr("Failed to configure i2c channel 0: 0x%02x\n",
+ i2c_channel_0_config[i]);
+ return ret;
+ }
+ }
+
+ uint8_t enter_single_step_3[] = { 0x00, 0x00, 0x00 };
+ ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE, enter_single_step_3,
+ ARRAY_SIZE(enter_single_step_3));
+ if (ret) {
+ msg_perr("Failed to enter serial single step mode (part 3)\n");
+ return ret;
+ }
+
+ ret = write_command(port, DEBUG_PORT, 0x35, NULL, 0);
+ if (ret) {
+ msg_perr("Failed to send serial debug command (part 1)\n");
+ return ret;
+ }
+
+ ret = write_command(port, DEBUG_PORT, 0x71, NULL, 0);
+ if (ret) {
+ msg_perr("Failed to send serial debug command (part 2)\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+// Returns non-zero value on error.
+static int mediatek_enter_isp(const struct mediatek_data *port)
+{
+ int ret;
+
+ ret = mediatek_enter_serial_debug_mode(port);
+ if (ret) {
+ msg_perr("Failed to enter serial debug mode\n");
+ return ret;
+ }
+
+ // MediaTek documentation says to do this twice just in case.
+ uint8_t enter_isp[] = { 'M', 'S', 'T', 'A', 'R' };
+ ret = write_raw(port, ISP_PORT, enter_isp, ARRAY_SIZE(enter_isp));
+ if (ret) {
+ msg_gwarn("Failed to enter ISP mode, trying again\n");
+ }
+ ret = write_raw(port, ISP_PORT, enter_isp, ARRAY_SIZE(enter_isp));
+ if (ret) {
+ msg_gwarn("Might already be in ISP mode, ignoring\n");
+ }
+
+ ret = mediatek_set_write_protect(port, 0);
+ if (ret) {
+ msg_perr("Failed to disable write protection\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+// Returns non-zero value on error.
+static int mediatek_exit_isp(const struct mediatek_data *port)
+{
+ int ret;
+
+ ret = mediatek_set_write_protect(port, 1);
+ if (ret) {
+ msg_perr("Failed to re-enable write protect\n");
+ return ret;
+ }
+
+ uint8_t exit_single_step[] = { 0xc0, 0xc1, 0xff };
+ ret = write_command(port, DEBUG_PORT, MTK_CMD_WRITE, exit_single_step,
+ ARRAY_SIZE(exit_single_step));
+ if (ret) {
+ msg_perr("Failed to exit single step mode\n");
+ return ret;
+ }
+
+ ret = write_command(port, DEBUG_PORT, 0x34, NULL, 0);
+ if (ret) {
+ msg_perr("Failed to exit serial debug mode (1), ignoring\n");
+ }
+
+ ret = write_command(port, DEBUG_PORT, 0x45, NULL, 0);
+ if (ret) {
+ msg_perr("Failed to exit serial debug mode (2), ignoring\n");
+ }
+
+ ret = write_command(port, ISP_PORT, 0x24, NULL, 0);
+ if (ret) {
+ msg_perr("Failed to exit ISP mode command, ignoring\n");
+ }
+
+ return 0;
+}
+
+static int mediatek_send_command(const struct flashctx *flash,
+ unsigned int writecnt, unsigned int readcnt,
+ const uint8_t *writearr, uint8_t *readarr)
+{
+ const struct mediatek_data *port = get_data_from_context(flash);
+ if (!port) {
+ msg_perr("Failed to extract chip data for ISP command\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ int ret;
+
+ if (writecnt) {
+ ret = write_command(port, ISP_PORT, MTK_CMD_WRITE,
+ writearr, writecnt);
+ if (ret) {
+ msg_perr("Failed to issue ISP write command\n");
+ return ret;
+ }
+ }
+
+ if (readcnt) {
+ size_t len = readcnt;
+ ret = read_raw(port, ISP_PORT, readarr, len);
+ if (ret < 0) {
+ msg_perr("Failed to read ISP command result\n");
+ return ret;
+ }
+
+ if (ret != (int)readcnt) {
+ msg_perr("Read length mismatched: expected %u got %d\n", readcnt, ret);
+ return SPI_INVALID_LENGTH;
+ }
+ }
+
+ // End the current command.
+ ret = write_command(port, ISP_PORT, MTK_CMD_END, NULL, 0);
+ if (ret) {
+ msg_perr("Failed to end ISP command\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int mediatek_shutdown(void *data)
+{
+ int ret = 0;
+ struct mediatek_data *port = (struct mediatek_data *)data;
+
+ ret |= mediatek_exit_isp(port);
+ i2c_close(port->fd);
+ free(data);
+
+ return ret;
+}
+
+static const struct spi_master spi_master_i2c_mediatek = {
+ .max_data_read = I2C_SMBUS_BLOCK_MAX,
+ // Leave room for 1-byte command and up to a 4-byte address.
+ .max_data_write = I2C_SMBUS_BLOCK_MAX - 5,
+ .command = mediatek_send_command,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = mediatek_shutdown,
+};
+
+static int get_params(const struct programmer_cfg *cfg, bool *allow_brick)
+{
+ char *brick_str = NULL;
+ int ret = 0;
+
+ *allow_brick = false; /* Default behaviour is to bail. */
+ brick_str = extract_programmer_param_str(cfg, "allow_brick");
+ if (brick_str) {
+ if (!strcmp(brick_str, "yes")) {
+ *allow_brick = true;
+ } else {
+ msg_perr("%s: Incorrect param format, allow_brick=yes.\n", __func__);
+ ret = SPI_GENERIC_ERROR;
+ }
+ }
+ free(brick_str);
+
+ return ret;
+}
+
+static int mediatek_init(const struct programmer_cfg *cfg)
+{
+ int ret;
+ bool allow_brick;
+
+ if (get_params(cfg, &allow_brick))
+ return SPI_GENERIC_ERROR;
+
+ /*
+ * TODO: Once board_enable can facilitate safe i2c allow listing
+ * then this can be removed.
+ */
+ if (!allow_brick) {
+ msg_perr("%s: For i2c drivers you must explicitly 'allow_brick=yes'. ", __func__);
+ msg_perr("There is currently no way to determine if the programmer works on a board "
+ "as i2c device address space can be overloaded. Set 'allow_brick=yes' if "
+ "you are sure you know what you are doing.\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ int fd = i2c_open_from_programmer_params(cfg, ISP_PORT, 0);
+ if (fd < 0) {
+ msg_perr("Failed to open i2c\n");
+ return fd;
+ }
+
+ struct mediatek_data *port = calloc(1, sizeof(*port));
+ if (!port) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ i2c_close(fd);
+ return SPI_GENERIC_ERROR;
+ }
+ port->fd = fd;
+
+ ret = ioctl(fd, I2C_FUNCS, &(port->funcs));
+ if (ret) {
+ msg_perr("Failed to fetch I2C bus functionality\n");
+ free(port);
+ i2c_close(fd);
+ return ret;
+ }
+
+ ret = mediatek_enter_isp(port);
+ if (ret) {
+ msg_perr("Failed to enter ISP mode\n");
+ free(port);
+ i2c_close(fd);
+ return ret;
+ }
+
+ return register_spi_master(&spi_master_i2c_mediatek, port);
+}
+
+const struct programmer_entry programmer_mediatek_i2c_spi = {
+ .name = "mediatek_i2c_spi",
+ .type = OTHER,
+ .devs.note = "Device files /dev/i2c-*\n",
+ .init = mediatek_init,
+};
diff --git a/meson.build b/meson.build
index 556183e5e..c85fdf4d0 100644
--- a/meson.build
+++ b/meson.build
@@ -1,18 +1,47 @@
project('flashromutils', 'c',
- version : run_command('util/getversion.sh', '-v').stdout().strip(),
+ version : run_command('cat', 'VERSION', check: true).stdout().strip(),
license : 'GPL-2.0',
- meson_version : '>=0.47.0',
- default_options : ['warning_level=2', 'c_std=c99'],
+ meson_version : '>=0.56.0',
+ default_options : [
+ 'warning_level=2',
+ 'c_std=c99',
+ 'werror=true',
+ 'optimization=s',
+ 'debug=false',
+ 'default_library=both'
+ ],
)
+fs = import('fs')
+
+if get_option('classic_cli').enabled() and get_option('default_library') == 'shared'
+ error('''
+ Cannot build cli_classic with shared libflashrom. Use \'-Dclassic_cli=disabled\' to disable the cli,
+ or use \'--default-library=both\' to also build the classic_cli
+ ''')
+endif
+
# libtool versioning
lt_current = '1'
lt_revision = '0'
lt_age = '0'
lt_version = '@0@.@1@.@2@'.format(lt_current, lt_age, lt_revision)
+flashrom_version = meson.project_version()
+git = find_program('git', native : true, required : false)
+if git.found()
+ version_git = run_command('git', 'describe', check : false)
+ if version_git.returncode() == 0
+ flashrom_version += ' (git:@0@)'.format(version_git.stdout().strip())
+ endif
+endif
+
+subdir('doc')
+
# hide/enable some warnings
warning_flags = [
+ '-Wshadow',
+ '-Wmissing-prototypes',
'-Wwrite-strings',
'-Wno-unused-parameter',
'-Wno-address-of-packed-member',
@@ -20,61 +49,63 @@ warning_flags = [
'-Wno-missing-braces',
]
-conf = configuration_data()
-
cc = meson.get_compiler('c')
add_project_arguments(cc.get_supported_arguments(warning_flags), language : 'c')
add_project_arguments('-D_DEFAULT_SOURCE', language : 'c')
add_project_arguments('-D_POSIX_C_SOURCE=200809L', language : 'c') # required for fileno, nanosleep, and strndup
add_project_arguments('-D_BSD_SOURCE', language : 'c') # required for glibc < v2.19
-add_project_arguments('-DFLASHROM_VERSION="' + meson.project_version() + '"', language : 'c')
+add_project_arguments('-D__BSD_VISIBLE', language : 'c') # required for u_char, u_int, u_long on FreeBSD
+add_project_arguments('-D__XSI_VISIBLE', language : 'c') # required for gettimeofday() on FreeBSD
+add_project_arguments('-D_NETBSD_SOURCE', language : 'c') # required for indirect include of strings.h on NetBSD
+add_project_arguments('-D_DARWIN_C_SOURCE', language : 'c') # required for indirect include of strings.h on MacOS
+add_project_arguments('-DFLASHROM_VERSION="' + flashrom_version + '"', language : 'c')
# get defaults from configure
-config_atahpt = get_option('config_atahpt')
-config_atapromise = get_option('config_atapromise')
-config_atavia = get_option('config_atavia')
-config_buspirate_spi = get_option('config_buspirate_spi')
-config_ch341a_spi = get_option('config_ch341a_spi')
-config_dediprog = get_option('config_dediprog')
-config_developerbox_spi = get_option('config_developerbox_spi')
-config_digilent_spi = get_option('config_digilent_spi')
-config_jlink_spi = get_option('config_jlink_spi')
-config_drkaiser = get_option('config_drkaiser')
-config_dummy = get_option('config_dummy')
-config_ene_lpc = get_option('config_ene_lpc')
-config_ft2232_spi = get_option('config_ft2232_spi')
-config_gfxnvidia = get_option('config_gfxnvidia')
-config_raiden = get_option('config_raiden')
-config_internal = get_option('config_internal')
-config_it8212 = get_option('config_it8212')
-config_linux_mtd = get_option('config_linux_mtd')
-config_linux_spi = get_option('config_linux_spi')
-config_mec1308 = get_option('config_mec1308')
-config_mstarddc_spi = get_option('config_mstarddc_spi')
-config_nic3com = get_option('config_nic3com')
-config_nicintel_eeprom = get_option('config_nicintel_eeprom')
-config_nicintel = get_option('config_nicintel')
-config_nicintel_spi = get_option('config_nicintel_spi')
-config_nicnatsemi = get_option('config_nicnatsemi')
-config_nicrealtek = get_option('config_nicrealtek')
-config_ogp_spi = get_option('config_ogp_spi')
-config_pickit2_spi = get_option('config_pickit2_spi')
-config_pony_spi = get_option('config_pony_spi')
-config_rayer_spi = get_option('config_rayer_spi')
-config_satamv = get_option('config_satamv')
-config_satasii = get_option('config_satasii')
-config_serprog = get_option('config_serprog')
-config_usbblaster_spi = get_option('config_usbblaster_spi')
-config_stlinkv3_spi = get_option('config_stlinkv3_spi')
-config_lspcon_i2c_spi = get_option('config_lspcon_i2c_spi')
-config_realtek_mst_i2c_spi = get_option('config_realtek_mst_i2c_spi')
+config_print_wiki= get_option('classic_cli_print_wiki')
+config_default_programmer_name = get_option('default_programmer_name')
+config_default_programmer_args = get_option('default_programmer_args')
cargs = []
+link_args = []
deps = []
-srcs = []
-
-need_raw_access = false
-need_serial = false
+srcs = files(
+ '82802ab.c',
+ 'at45db.c',
+ 'bitbang_spi.c',
+ 'edi.c',
+ 'en29lv640b.c',
+ 'erasure_layout.c',
+ 'flashchips.c',
+ 'flashrom.c',
+ 'fmap.c',
+ 'helpers.c',
+ 'helpers_fileio.c',
+ 'ich_descriptors.c',
+ 'jedec.c',
+ 'printlock.c',
+ 'layout.c',
+ 'libflashrom.c',
+ 'opaque.c',
+ 'parallel.c',
+ 'print.c',
+ 'programmer.c',
+ 'programmer_table.c',
+ 's25f.c',
+ 'sfdp.c',
+ 'spi25.c',
+ 'spi25_statusreg.c',
+ 'spi95.c',
+ 'spi.c',
+ 'sst28sf040.c',
+ 'sst49lfxxxc.c',
+ 'sst_fwhub.c',
+ 'stm50.c',
+ 'udelay.c',
+ 'w29ee011.c',
+ 'w39.c',
+ 'writeprotect.c',
+ 'writeprotect_ranges.c',
+)
# check for required symbols
if cc.has_function('clock_gettime')
@@ -86,302 +117,538 @@ endif
if cc.check_header('sys/utsname.h')
add_project_arguments('-DHAVE_UTSNAME=1', language : 'c')
endif
-
-# some programmers require libusb
-if get_option('usb')
- srcs += 'usbdev.c'
- srcs += 'usb_device.c'
- deps += dependency('libusb-1.0')
+if host_machine.system() in ['cygwin', 'windows']
+ add_project_arguments('-DIS_WINDOWS=1', language : 'c')
else
- config_ch341a_spi = false
- config_dediprog = false
- config_digilent_spi = false
- config_developerbox_spi = false
- config_pickit2_spi = false
+ add_project_arguments('-DIS_WINDOWS=0', language : 'c')
endif
-# some programmers require libpci
-if get_option('pciutils')
- srcs += 'pcidev.c'
- deps += dependency('libpci')
- cargs += '-DNEED_PCI=1'
+if host_machine.system() == 'linux'
+ custom_baud_c = 'custom_baud_linux.c'
+elif host_machine.system() == 'darwin'
+ custom_baud_c = 'custom_baud_darwin.c'
else
- config_atahpt = false
- config_atapromise = false
- config_atavia = false
- config_drkaiser = false
- config_gfxnvidia = false
- config_raiden = false
- config_internal = false
- config_it8212 = false
- config_nic3com = false
- config_nicintel_eeprom = false
- config_nicintel = false
- config_nicintel_spi = false
- config_nicnatsemi = false
- config_nicrealtek = false
- config_ogp_spi = false
- config_rayer_spi = false
- config_satamv = false
- config_satasii = false
+ custom_baud_c = 'custom_baud.c'
endif
-# set defines for configured programmers
-if config_atahpt
- srcs += 'atahpt.c'
- cargs += '-DCONFIG_ATAHPT=1'
-endif
-if config_atapromise
- srcs += 'atapromise.c'
- cargs += '-DCONFIG_ATAPROMISE=1'
-endif
-if config_atavia
- srcs += 'atavia.c'
- cargs += '-DCONFIG_ATAVIA=1'
-endif
-if config_buspirate_spi
- srcs += 'buspirate_spi.c'
- cargs += '-DCONFIG_BUSPIRATE_SPI=1'
- need_serial = true
-endif
-if config_ch341a_spi
- srcs += 'ch341a_spi.c'
- cargs += '-DCONFIG_CH341A_SPI=1'
-endif
-if config_dediprog
- srcs += 'dediprog.c'
- cargs += '-DCONFIG_DEDIPROG=1'
-endif
-if config_developerbox_spi
- srcs += 'developerbox_spi.c'
- cargs += '-DCONFIG_DEVELOPERBOX_SPI=1'
-endif
-if config_digilent_spi
- srcs += 'digilent_spi.c'
- cargs += '-DCONFIG_DIGILENT_SPI=1'
-endif
-if config_jlink_spi
- srcs += 'jlink_spi.c'
- cargs += '-DCONFIG_JLINK_SPI=1'
- deps += dependency('libjaylink')
-endif
-if config_drkaiser
- srcs += 'drkaiser.c'
- cargs += '-DCONFIG_DRKAISER=1'
-endif
-if config_dummy
- srcs += 'dummyflasher.c'
- cargs += '-DCONFIG_DUMMY=1'
-endif
-if config_ft2232_spi
- srcs += 'ft2232_spi.c'
- cargs += '-DCONFIG_FT2232_SPI=1'
- deps += dependency('libftdi1')
- cargs += '-DHAVE_FT232H=1'
-endif
-if config_gfxnvidia
- srcs += 'gfxnvidia.c'
- cargs += '-DCONFIG_GFXNVIDIA=1'
+systems_hwaccess = [ 'linux', 'openbsd', 'freebsd', 'dragonfly', 'netbsd', 'dos' ]
+systems_serial = [ 'linux', 'openbsd', 'freebsd', 'dragonfly', 'netbsd', 'darwin', 'windows' ]
+
+cpus_port_io = [ 'x86', 'x86_64' ]
+
+group_ftdi = get_option('programmer').contains('group_ftdi')
+group_pci = get_option('programmer').contains('group_pci')
+group_usb = get_option('programmer').contains('group_usb')
+group_i2c = get_option('programmer').contains('group_i2c')
+group_serial = get_option('programmer').contains('group_serial')
+group_jlink = get_option('programmer').contains('group_jlink')
+group_internal = get_option('programmer').contains('group_internal')
+group_external = get_option('programmer').contains('group_external')
+
+libpci = dependency('libpci', required : group_pci, version : '>=2.2.0',
+ static : (host_machine.system() == 'openbsd' ? true : false)) # On openbsd a static version of libpci is needed to get also -libz
+libusb1 = dependency('libusb-1.0', required : group_usb)
+libftdi1 = dependency('libftdi1', required : group_ftdi)
+libjaylink = dependency('libjaylink', required : group_jlink, version : '>=0.3.0')
+
+if host_machine.system() == 'windows'
+ # Specifying an include_path that doesn't exist is an error,
+ # but we only use this if the library is found in the same directory.
+ ni845x_search_path = get_option('ni845x_search_path')
+ if fs.is_dir(ni845x_search_path)
+ ni845x_include_path = [ni845x_search_path]
+ else
+ ni845x_include_path = []
+ endif
+
+ libni845x = declare_dependency(
+ dependencies : [
+ cc.find_library(
+ 'ni845x',
+ dirs : get_option('ni845x_search_path'),
+ required : get_option('programmer').contains('ni845x_spi')
+ ),
+ ],
+ include_directories : ni845x_include_path,
+ )
+else
+ libni845x = dependency('', required : false)
endif
-if config_raiden
- srcs += 'raiden_debug_spi.c'
- cargs += '-DCONFIG_RAIDEN_DEBUG_SPI=1'
+
+subdir('platform')
+
+if systems_hwaccess.contains(host_machine.system())
+ srcs += files('hwaccess_physmap.c')
+ if ['x86', 'x86_64'].contains(host_machine.cpu_family())
+ srcs += files('hwaccess_x86_msr.c', 'hwaccess_x86_io.c')
+ endif
endif
-if config_internal
- srcs += 'board_enable.c'
- srcs += 'cbtable.c'
- srcs += 'chipset_enable.c'
- srcs += 'internal.c'
- srcs += 'processor_enable.c'
- if target_machine.cpu_family() == 'x86' or target_machine.cpu_family() == 'x86_64'
- srcs += 'amd_imc.c'
- srcs += 'dmi.c'
- srcs += 'ichspi.c'
- srcs += 'it85spi.c'
- srcs += 'it87spi.c'
- srcs += 'mcp6x_spi.c'
- srcs += 'sb600spi.c'
- srcs += 'wbsio_spi.c'
+
+# Pseudo dependencies
+linux_headers = \
+ cc.has_header('linux/i2c.h') and \
+ cc.has_header('linux/i2c-dev.h') and \
+ cc.has_header('mtd/mtd-user.h') and \
+ cc.has_header('linux/spi/spidev.h') ? declare_dependency() : dependency('', required : false)
+
+# '<programmer_name>' : {
+# 'system' : list[string], # default: ['all']
+# 'cpu_families : list[string], # default: ['all']
+# 'deps' : list[dep], # default: []
+# 'groups : list[boolean], # default: []
+# 'srcs' : list[file], # default: []
+# 'flags' : list[string], # default: []
+# 'default' : boolean, # default: true
+# 'active' : boolean, # added on runtime
+# }
+programmer = {
+ 'asm106x' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('asm106x.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_ASM106X=1' ],
+ },
+ 'atahpt' : {
+ 'systems' : systems_hwaccess,
+ 'cpu_families' : cpus_port_io,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('atahpt.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_ATAHPT=1' ],
+ 'default' : false, # not yet working
+ },
+ 'atapromise' : {
+ 'systems' : systems_hwaccess,
+ 'cpu_families' : cpus_port_io,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('atapromise.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_ATAPROMISE=1' ],
+ 'default' : false,
+ },
+ 'atavia' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('atavia.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_ATAVIA=1' ],
+ },
+ 'buspirate_spi' : {
+ 'systems' : systems_serial,
+ 'groups' : [ group_serial, group_external ],
+ 'srcs' : files('buspirate_spi.c', 'serial.c', custom_baud_c),
+ 'flags' : [ '-DCONFIG_BUSPIRATE_SPI=1' ],
+ },
+ 'ch341a_spi' : {
+ 'deps' : [ libusb1 ],
+ 'groups' : [ group_usb, group_external ],
+ 'srcs' : files('ch341a_spi.c'),
+ 'test_srcs' : files('tests/ch341a_spi.c'),
+ 'flags' : [ '-DCONFIG_CH341A_SPI=1' ],
+ },
+ 'ch347_spi' : {
+ 'deps' : [ libusb1 ],
+ 'groups' : [ group_usb, group_external ],
+ 'srcs' : files('ch347_spi.c'),
+ 'flags' : [ '-DCONFIG_CH347_SPI=1' ],
+ },
+ 'dediprog' : {
+ 'deps' : [ libusb1 ],
+ 'groups' : [ group_usb, group_external ],
+ 'srcs' : files('dediprog.c', 'usbdev.c'),
+ 'test_srcs' : files('tests/dediprog.c'),
+ 'flags' : [ '-DCONFIG_DEDIPROG=1' ],
+ },
+ 'developerbox_spi' : {
+ 'deps' : [ libusb1 ],
+ 'groups' : [ group_usb, group_external ],
+ 'srcs' : files('developerbox_spi.c', 'usbdev.c'),
+ 'flags' : [ '-DCONFIG_DEVELOPERBOX_SPI=1' ],
+ },
+ 'digilent_spi' : {
+ 'deps' : [ libusb1 ],
+ 'groups' : [ group_usb, group_external ],
+ 'srcs' : files('digilent_spi.c'),
+ 'flags' : [ '-DCONFIG_DIGILENT_SPI=1' ],
+ },
+ 'dirtyjtag_spi' : {
+ 'deps' : [ libusb1 ],
+ 'groups' : [ group_usb, group_external ],
+ 'srcs' : files('dirtyjtag_spi.c'),
+ 'flags' : [ '-DCONFIG_DIRTYJTAG_SPI=1' ],
+ },
+ 'drkaiser' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('drkaiser.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_DRKAISER=1' ],
+ },
+ 'dummy' : {
+ 'srcs' : files('dummyflasher.c'),
+ 'test_srcs' : files('tests/dummyflasher.c'),
+ 'flags' : [ '-DCONFIG_DUMMY=1' ],
+ },
+ 'ft2232_spi' : {
+ 'deps' : [ libftdi1 ],
+ 'groups' : [ group_ftdi, group_external ],
+ 'srcs' : files('ft2232_spi.c' ),
+ 'flags' : [ '-DCONFIG_FT2232_SPI=1' ],
+ },
+ 'gfxnvidia' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('gfxnvidia.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_GFXNVIDIA=1' ],
+ },
+ 'internal' : {
+ 'systems' : systems_hwaccess + ['linux'],
+ 'cpu_families' : (host_machine.system() == 'linux' ? [host_machine.cpu_family()] : ['x86', 'x86_64']),
+ 'deps' : [ libpci ],
+ 'groups' : [ group_internal ],
+ 'srcs' : (host_machine.cpu_family() in ['x86', 'x86_64'] ? files(
+ 'processor_enable.c',
+ 'chipset_enable.c',
+ 'board_enable.c',
+ 'cbtable.c',
+ 'internal.c',
+ 'internal_par.c',
+ 'it87spi.c',
+ 'sb600spi.c',
+ 'superio.c',
+ 'amd_imc.c',
+ 'wbsio_spi.c',
+ 'mcp6x_spi.c',
+ 'ichspi.c',
+ 'dmi.c',
+ 'pcidev.c',
+ 'known_boards.c',
+ ) : files(
+ 'board_enable.c',
+ 'cbtable.c',
+ 'chipset_enable.c',
+ 'internal.c',
+ 'internal_par.c',
+ 'processor_enable.c',
+ 'pcidev.c',
+ 'known_boards.c',
+ )),
+ 'flags' : [
+ '-DCONFIG_INTERNAL=1',
+ '-DCONFIG_INTERNAL_DMI=' + (get_option('use_internal_dmi') ? '1' : '0'),
+ ]
+ },
+ 'it8212' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('it8212.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_IT8212=1' ],
+ },
+ 'jlink_spi' : {
+ 'deps' : [ libjaylink ],
+ 'groups' : [ group_jlink, group_external ],
+ 'srcs' : files('jlink_spi.c'),
+ 'flags' : [ '-DCONFIG_JLINK_SPI=1' ],
+ },
+ 'linux_mtd' : {
+ 'systems' : [ 'linux' ],
+ 'deps' : [ linux_headers ],
+ 'groups' : [ group_internal ],
+ 'srcs' : files('linux_mtd.c'),
+ 'test_srcs' : files('tests/linux_mtd.c'),
+ 'flags' : [ '-DCONFIG_LINUX_MTD=1' ],
+ },
+ 'linux_spi' : {
+ 'systems' : [ 'linux' ],
+ 'deps' : [ linux_headers ],
+ # internal / external?
+ 'srcs' : files('linux_spi.c'),
+ 'test_srcs' : files('tests/linux_spi.c'),
+ 'flags' : [ '-DCONFIG_LINUX_SPI=1' ],
+ },
+ 'parade_lspcon' : {
+ 'systems' : [ 'linux' ],
+ 'deps' : [ linux_headers ],
+ 'groups' : [ group_i2c ],
+ 'srcs' : files('parade_lspcon.c', 'i2c_helper_linux.c'),
+ 'test_srcs' : files('tests/parade_lspcon.c'),
+ 'flags' : [ '-DCONFIG_PARADE_LSPCON=1' ],
+ 'default' : false
+ },
+ 'mediatek_i2c_spi' : {
+ 'systems' : [ 'linux' ],
+ 'deps' : [ linux_headers ],
+ 'groups' : [ group_i2c ],
+ 'srcs' : files('mediatek_i2c_spi.c', 'i2c_helper_linux.c'),
+ 'test_srcs' : files('tests/mediatek_i2c_spi.c'),
+ 'flags' : [ '-DCONFIG_MEDIATEK_I2C_SPI=1' ],
+ 'default' : false,
+ },
+ 'mstarddc_spi' : {
+ 'systems' : [ 'linux' ],
+ 'deps' : [ linux_headers ],
+ 'groups' : [ group_i2c ],
+ 'srcs' : files('mstarddc_spi.c', 'i2c_helper_linux.c'),
+ 'flags' : [ '-DCONFIG_MSTARDDC_SPI=1' ],
+ 'default' : false
+ },
+ 'ni845x_spi' : {
+ 'systems' : [ 'windows' ],
+ 'cpu_families' : [ 'x86' ], # The required ni845x library is 32-bit only
+ 'deps' : [ libni845x ],
+ 'srcs' : files('ni845x_spi.c'),
+ 'flags' : [ '-DCONFIG_NI845X_SPI=1' ],
+ 'default' : false,
+ },
+ 'nic3com' : {
+ 'systems' : systems_hwaccess,
+ 'cpu_families' : cpus_port_io,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('nic3com.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_NIC3COM=1' ],
+ },
+ 'nicintel' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('nicintel.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_NICINTEL=1' ],
+ },
+ 'nicintel_eeprom' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('nicintel_eeprom.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_NICINTEL_EEPROM=1' ],
+ },
+ 'nicintel_spi' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('nicintel_spi.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_NICINTEL_SPI=1' ],
+ },
+ 'nicnatsemi' : {
+ 'systems' : systems_hwaccess,
+ 'cpu_families' : cpus_port_io,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('nicnatsemi.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_NICNATSEMI=1' ],
+ 'default' : false, # not complete nor tested
+ },
+ 'nicrealtek' : {
+ 'systems' : systems_hwaccess,
+ 'cpu_families' : cpus_port_io,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('nicrealtek.c', 'pcidev.c'),
+ 'test_srcs' : files('tests/nicrealtek.c'),
+ 'flags' : [ '-DCONFIG_NICREALTEK=1' ],
+ },
+ 'ogp_spi' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('ogp_spi.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_OGP_SPI=1' ],
+ },
+ 'pickit2_spi' : {
+ 'deps' : [ libusb1 ],
+ 'groups' : [ group_usb, group_external ],
+ 'srcs' : files('pickit2_spi.c'),
+ 'flags' : [ '-DCONFIG_PICKIT2_SPI=1' ],
+ },
+ 'pony_spi' : {
+ 'systems' : systems_serial,
+ 'groups' : [ group_serial, group_external ],
+ 'srcs' : files('pony_spi.c', 'serial.c', custom_baud_c),
+ 'flags' : [ '-DCONFIG_PONY_SPI=1' ],
+ },
+ 'raiden_debug_spi' : {
+ 'deps' : [ libusb1 ],
+ 'groups' : [ group_usb, group_external ],
+ 'srcs' : files('raiden_debug_spi.c', 'usb_device.c'),
+ 'test_srcs' : files('tests/raiden_debug_spi.c'),
+ 'flags' : [ '-DCONFIG_RAIDEN_DEBUG_SPI=1' ],
+ },
+ 'rayer_spi' : {
+ 'systems' : systems_hwaccess,
+ 'cpu_families' : cpus_port_io,
+ 'groups' : [ group_internal ],
+ 'srcs' : files('rayer_spi.c'),
+ 'flags' : [ '-DCONFIG_RAYER_SPI=1' ],
+ },
+ 'realtek_mst_i2c_spi' : {
+ 'systems' : [ 'linux' ],
+ 'deps' : [ linux_headers ],
+ 'groups' : [ group_i2c ],
+ 'srcs' : files('realtek_mst_i2c_spi.c', 'i2c_helper_linux.c'),
+ 'test_srcs' : files('tests/realtek_mst_i2c_spi.c'),
+ 'flags' : [ '-DCONFIG_REALTEK_MST_I2C_SPI=1' ],
+ 'default' : false,
+ },
+ 'satamv' : {
+ 'systems' : systems_hwaccess,
+ 'cpu_families' : cpus_port_io,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('satamv.c', 'pcidev.c'),
+ 'flags' : ['-DCONFIG_SATAMV=1'],
+ },
+ 'satasii' : {
+ 'systems' : systems_hwaccess,
+ 'deps' : [ libpci ],
+ 'groups' : [ group_pci, group_internal ],
+ 'srcs' : files('satasii.c', 'pcidev.c'),
+ 'flags' : [ '-DCONFIG_SATASII=1' ],
+ },
+ 'serprog' : {
+ 'systems' : systems_serial,
+ 'groups' : [ group_serial, group_external ],
+ 'srcs' : files('serprog.c', 'serial.c', custom_baud_c),
+ 'flags' : [ '-DCONFIG_SERPROG=1' ],
+ },
+ 'stlinkv3_spi' : {
+ 'deps' : [ libusb1 ],
+ 'groups' : [ group_usb, group_external ],
+ 'srcs' : files('stlinkv3_spi.c', 'usbdev.c'),
+ 'flags' : [ '-DCONFIG_STLINKV3_SPI=1' ],
+ },
+ 'usbblaster_spi' : {
+ 'deps' : [ libftdi1 ],
+ 'groups' : [ group_ftdi, group_external ],
+ 'srcs' : files('usbblaster_spi.c'),
+ 'flags' : [ '-DCONFIG_USBBLASTER_SPI=1' ],
+ },
+}
+
+active_programmer_count = 0
+foreach p_name, p_data : programmer
+ p_data += {
+ 'systems' : p_data.get('systems', ['all']),
+ 'cpu_families' : p_data.get('cpu_families', ['all']),
+ 'deps' : p_data.get('deps', []),
+ 'groups' : p_data.get('groups', []),
+ 'srcs' : p_data.get('srcs', []),
+ 'test_srcs': p_data.get('test_srcs', []),
+ 'flags' : p_data.get('flags', []),
+ 'default' : p_data.get('default', true),
+ }
+
+ active = false
+ deps_found = true
+ not_found_dep = ''
+ not_active_message = ''
+ selected_hard = p_name in get_option('programmer')
+ selected_soft = p_data.get('groups').contains(true) or \
+ 'all' in get_option('programmer') or \
+ 'auto' in get_option('programmer') and p_data.get('default')
+ available = (p_data.get('systems').contains('all') or p_data.get('systems').contains(host_machine.system())) \
+ and (p_data.get('cpu_families').contains('all') or p_data.get('cpu_families').contains(host_machine.cpu_family()))
+
+ foreach dep : p_data.get('deps')
+ if not dep.found()
+ deps_found = false
+ not_found_dep = dep.name()
+ break
+ endif
+ endforeach
+
+ if selected_hard
+ if not available
+ error('programmer @0@ was selected but is not supported on this platform (needs @1@/@2@, but system is @3@/@4@)'.format(
+ p_name,
+ p_data.get('systems'),
+ p_data.get('cpu_families'),
+ host_machine.system(),
+ host_machine.cpu_family()
+ ))
+ elif not deps_found
+ error(p_name + ' selected but dependency ' + not_found_dep +'not found')
+ else
+ active = true
+ endif
+ elif selected_soft
+ if not available
+ not_active_message = 'Not available on platform'
+ elif not deps_found
+ not_active_message = 'dependency ' + not_found_dep + ' not found'
+ else
+ active = true
+ endif
+ else
+ not_active_message = 'not selected'
endif
- config_bitbang_spi = true
- cargs += '-DCONFIG_INTERNAL=1'
- if get_option('config_internal_dmi')
- # Use internal DMI/SMBIOS decoder by default instead of relying on dmidecode.
- cargs += '-DCONFIG_INTERNAL_DMI=1'
+
+ p_data += {
+ 'active' : active,
+ 'summary' : not_active_message,
+ }
+ programmer += {p_name : p_data}
+ if active
+ active_programmer_count += 1
endif
-endif
-if config_ene_lpc
- srcs += 'ene_lpc.c'
- cargs += '-DCONFIG_ENE_LPC=1'
-endif
-if config_it8212
- srcs += 'it8212.c'
- cargs += '-DCONFIG_IT8212=1'
-endif
-if config_linux_mtd
- srcs += 'linux_mtd.c'
- cargs += '-DCONFIG_LINUX_MTD=1'
-endif
-if config_linux_spi
- srcs += 'linux_spi.c'
- cargs += '-DCONFIG_LINUX_SPI=1'
-endif
-if config_mec1308
- srcs += 'mec1308.c'
- cargs += '-DCONFIG_MEC1308=1'
-endif
-if config_mstarddc_spi
- srcs += 'mstarddc_spi.c'
- cargs += '-DCONFIG_MSTARDDC_SPI=1'
-endif
-if config_nic3com
- srcs += 'nic3com.c'
- cargs += '-DCONFIG_NIC3COM=1'
-endif
-if config_nicintel
- srcs += 'nicintel.c'
- cargs += '-DCONFIG_NICINTEL=1'
-endif
-if config_nicintel_eeprom
- srcs += 'nicintel_eeprom.c'
- cargs += '-DCONFIG_NICINTEL_EEPROM=1'
-endif
-if config_nicintel_spi
- srcs += 'nicintel_spi.c'
- config_bitbang_spi = true
- cargs += '-DCONFIG_NICINTEL_SPI=1'
-endif
-if config_nicnatsemi
- srcs += 'nicnatsemi.c'
- cargs += '-DCONFIG_NICNATSEMI=1'
-endif
-if config_nicrealtek
- srcs += 'nicrealtek.c'
- cargs += '-DCONFIG_NICREALTEK=1'
-endif
-if config_ogp_spi
- config_bitbang_spi = true
- srcs += 'ogp_spi.c'
- cargs += '-DCONFIG_OGP_SPI=1'
-endif
-if config_pickit2_spi
- srcs += 'pickit2_spi.c'
- cargs += '-DCONFIG_PICKIT2_SPI=1'
-endif
-if config_pony_spi
- srcs += 'pony_spi.c'
- need_serial = true
- config_bitbang_spi = true
- cargs += '-DCONFIG_PONY_SPI=1'
-endif
-if config_rayer_spi
- srcs += 'rayer_spi.c'
- config_bitbang_spi = true
- need_raw_access = true
- cargs += '-DCONFIG_RAYER_SPI=1'
-endif
-if config_satamv
- srcs += 'satamv.c'
- cargs += '-DCONFIG_SATAMV=1'
-endif
-if config_satasii
- srcs += 'satasii.c'
- cargs += '-DCONFIG_SATASII=1'
-endif
-if config_serprog
- srcs += 'serprog.c'
- cargs += '-DCONFIG_SERPROG=1'
- need_serial = true
-endif
-if config_usbblaster_spi
- srcs += 'usbblaster_spi.c'
- cargs += '-DCONFIG_USBBLASTER_SPI=1'
-endif
-if config_stlinkv3_spi
- srcs += 'stlinkv3_spi.c'
- cargs += '-DCONFIG_STLINKV3_SPI=1'
-endif
-if config_lspcon_i2c_spi
- srcs += 'lspcon_i2c_spi.c'
- cargs += '-DCONFIG_LSPCON_I2C_SPI=1'
-endif
-if config_realtek_mst_i2c_spi
- srcs += 'realtek_mst_i2c_spi.c'
- cargs += '-DCONFIG_REALTEK_MST_I2C_SPI=1'
-endif
+endforeach
-# bitbanging SPI infrastructure
-if config_bitbang_spi
- srcs += 'bitbang_spi.c'
- cargs += '-DCONFIG_BITBANG_SPI=1'
+if active_programmer_count == 0
+ error('At least one programmer must be selected')
endif
-if host_machine.system() == 'linux'
- srcs += 'i2c_helper_linux.c'
- cargs += '-DCONFIG_I2C_SUPPORT=1'
-endif
+# add srcs, cargs & deps from active programmer to global srcs, cargs & deps
+foreach p_name, p_data : programmer
+ if p_data.get('active')
+ srcs += p_data.get('srcs')
+ cargs += p_data.get('flags')
+ deps += p_data.get('deps')
+ endif
+endforeach
-# raw memory, MSR or PCI port I/O access
-if need_raw_access
- srcs += 'hwaccess.c'
- srcs += 'physmap.c'
- cargs += '-DNEED_RAW_ACCESS=1'
+if config_print_wiki.enabled()
+ if get_option('classic_cli').disabled()
+ error('`classic_cli_print_wiki` can not be enabled without `classic_cli`')
+ else
+ srcs += files('print_wiki.c')
+ cargs += '-DCONFIG_PRINT_WIKI=1'
+ endif
endif
-# raw serial IO
-if need_serial
- srcs += 'custom_baud.c'
- srcs += 'serial.c'
+if config_default_programmer_name != ''
+ cargs += '-DCONFIG_DEFAULT_PROGRAMMER_NAME=&programmer_' + config_default_programmer_name
+else
+ cargs += '-DCONFIG_DEFAULT_PROGRAMMER_NAME=NULL'
endif
-prefix = get_option('prefix')
-sbindir = join_paths(prefix, get_option('sbindir'))
-libdir = join_paths(prefix, get_option('libdir'))
-mandir = join_paths(prefix, get_option('mandir'))
+cargs += '-DCONFIG_DEFAULT_PROGRAMMER_ARGS="' + config_default_programmer_args + '"'
+
+if get_option('llvm_cov').enabled()
+ cargs += ['-fprofile-instr-generate', '-fcoverage-mapping']
+ link_args += ['-fprofile-instr-generate', '-fcoverage-mapping']
+endif
install_headers([
- 'libflashrom.h',
+ 'include/libflashrom.h',
],
)
-# core modules needed by both the library and the CLI
-srcs += '82802ab.c'
-srcs += 'at45db.c'
-srcs += 'edi.c'
-srcs += 'en29lv640b.c'
-srcs += 'flashchips.c'
-srcs += 'flashrom.c'
-srcs += 'fmap.c'
-srcs += 'helpers.c'
-srcs += 'ich_descriptors.c'
-srcs += 'jedec.c'
-srcs += 'layout.c'
-srcs += 'libflashrom.c'
-srcs += 'opaque.c'
-srcs += 'print.c'
-srcs += 'programmer.c'
-srcs += 's25f.c'
-srcs += 'sfdp.c'
-srcs += 'spi25.c'
-srcs += 'spi25_statusreg.c'
-srcs += 'spi95.c'
-srcs += 'spi.c'
-srcs += 'sst28sf040.c'
-srcs += 'sst49lfxxxc.c'
-srcs += 'sst_fwhub.c'
-srcs += 'stm50.c'
-srcs += 'udelay.c'
-srcs += 'w29ee011.c'
-srcs += 'w39.c'
-srcs += 'writeprotect.c'
+include_dir = include_directories('include')
mapfile = 'libflashrom.map'
-vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
-flashrom = shared_library(
+if host_machine.system() == 'darwin'
+ vflag = ''
+else
+ vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
+endif
+libflashrom = library(
'flashrom',
sources : [
srcs,
],
+ include_directories : include_dir,
soversion : lt_current,
version : lt_version,
dependencies : [
@@ -391,84 +658,129 @@ flashrom = shared_library(
cargs,
],
install : true,
- link_args : vflag,
+ link_args : link_args + [vflag],
link_depends : mapfile,
)
-version = meson.project_version()
-#strip leading characters
-if version.startswith('v')
- version = version.split('v')[1]
-endif
-if version.startswith('p')
- version = version.split('p')[1]
-endif
-
pkgg = import('pkgconfig')
pkgg.generate(
- libraries : flashrom,
- version : version,
+ libraries : libflashrom,
+ version : flashrom_version.split()[0], # cut off the git version
name : 'flashrom',
filebase : 'flashrom',
description : 'library to interact with flashrom',
)
-conf.set('VERSION', version)
-conf.set('MAN_DATE', run_command('util/getrevision.sh', '--date', 'flashrom.8.tmpl').stdout().strip())
-configure_file(
- input : 'flashrom.8.tmpl',
- output : 'flashrom.8',
- configuration : conf,
- install: true,
- install_dir: join_paths(mandir, 'man8'),
-)
-
-flashrom_dep = declare_dependency(
- link_with : flashrom,
- include_directories : include_directories('.'),
- dependencies : deps
-)
+if get_option('classic_cli').enabled() or get_option('classic_cli').auto() and not get_option('default_library') == 'shared'
-# we can't just link_with libflashrom as we require all the internal symbols...
-executable(
- 'flashrom',
- sources : [
- srcs,
+ cli_srcs = files(
'cli_classic.c',
'cli_common.c',
- 'cli_output.c',
- 'flashrom.c',
- ],
- dependencies : [
- deps,
- ],
- c_args : [
- cargs,
- '-DCONFIG_DEFAULT_PROGRAMMER=PROGRAMMER_INVALID',
- '-DCONFIG_DEFAULT_PROGRAMMER_ARGS=""',
- ],
- install : true,
- install_dir : sbindir,
-)
+ 'cli_output.c'
+ )
-subdir('util')
+ if not cc.has_function('getopt_long')
+ cli_srcs += files('cli_getopt.c')
+ endif
-# unit-test framework
-cmocka_dep = dependency(
- 'cmocka',
- fallback: ['cmocka', 'cmocka_dep']
-)
-flashrom_test_dep = declare_dependency(
- include_directories : include_directories('.'),
- sources : [
- srcs,
- 'cli_common.c',
- 'cli_output.c',
- 'flashrom.c',
- ],
- dependencies : [
- deps,
- ],
-)
+ classic_cli = executable(
+ 'flashrom',
+ cli_srcs,
+ c_args : cargs,
+ include_directories : include_dir,
+ install : true,
+ install_dir : get_option('sbindir'),
+ link_args : link_args,
+ # flashrom needs internal symbols of libflashrom
+ link_with : get_option('default_library') == 'static' ? libflashrom : libflashrom.get_static_lib(),
+ )
+ if get_option('llvm_cov').enabled()
+ run_target('llvm-cov-cli', command : ['scripts/llvm-cov', classic_cli])
+ endif
+endif
+
+if get_option('ich_descriptors_tool').auto() or get_option('ich_descriptors_tool').enabled()
+ subdir('util/ich_descriptors_tool')
+endif
+
+if get_option('bash_completion').auto() or get_option('bash_completion').enabled()
+ if get_option('classic_cli').disabled()
+ if get_option('bash_completion').enabled()
+ error('`bash_completion` can not be enabled without `classic_cli`')
+ endif
+ else
+ bash_comp = dependency('bash-completion', required : false)
+ if bash_comp.found()
+ bash_comp_install_dir = bash_comp.get_variable(
+ pkgconfig : 'completionsdir',
+ pkgconfig_define : ['datadir', get_option('datadir')]
+ )
+ else
+ bash_comp_install_dir = join_paths(get_option('datadir'), 'bash-completion', 'completions')
+ endif
+
+ programmer_names_active_str = ''
+ foreach p_name, p_data : programmer
+ if p_data.get('active')
+ programmer_names_active_str += p_name + ' '
+ endif
+ endforeach
+
+ configure_file(
+ input : 'util/flashrom.bash-completion.tmpl',
+ output : 'flashrom.bash',
+ configuration : {
+ 'PROGRAMMERS' : programmer_names_active_str,
+ },
+ install: true,
+ install_dir: bash_comp_install_dir,
+ )
+ endif
+endif
+
+# Use `.auto() or .enabled()` instead of `.allowed()` to keep the minimum meson version as low as possible.
+# `.allowed()` gets introduced in 0.59.0
+if get_option('tests').auto() or get_option('tests').enabled()
+ # unit-test framework
+ cmocka_dep = dependency(
+ 'cmocka',
+ fallback: ['cmocka', 'cmocka_dep'],
+ required : get_option('tests')
+ )
+
+ flashrom_test_dep = declare_dependency(
+ include_directories : include_dir,
+ sources : [
+ srcs,
+ 'cli_common.c',
+ 'cli_output.c',
+ 'flashrom.c',
+ ],
+ compile_args : [
+ '-includestdlib.h',
+ '-includeunittest_env.h',
+ ],
+ dependencies : [
+ deps,
+ ],
+ )
+
+ if cmocka_dep.found()
+ subdir('tests')
+ endif
+endif
+
+programmer_names_active = []
+programmer_names_not_active = []
+foreach p_name, p_data : programmer
+ if p_data.get('active')
+ programmer_names_active += p_name
+ else
+ programmer_names_not_active += p_name + ' (' + p_data.get('summary', '') + ')'
+ endif
+endforeach
-subdir('tests')
+summary({
+ 'active' : [programmer_names_active],
+ 'non active' : [programmer_names_not_active],
+}, section : 'Programmer')
diff --git a/meson_cross/i586_djgpp_dos.txt b/meson_cross/i586_djgpp_dos.txt
new file mode 100644
index 000000000..66d5ed0da
--- /dev/null
+++ b/meson_cross/i586_djgpp_dos.txt
@@ -0,0 +1,29 @@
+# This file is for cross compiling flashrom for DOS with DJGPP.
+#
+# Make sure the program names match your toolchain
+#
+# Make sure pkg-config can find your self compiles libpci
+# or add the path of your libpci.pc as 'pkg_config_libdir'
+# under [properies] below.
+
+[binaries]
+c = 'i586-pc-msdosdjgpp-gcc'
+ar = 'i586-pc-msdosdjgpp-ar'
+strip = 'i586-pc-msdosdjgpp-strip'
+pkgconfig = 'pkg-config'
+
+[host_machine]
+system = 'dos'
+cpu_family = 'x86'
+cpu = 'i586'
+endian = 'little'
+
+[built-in options]
+c_std = 'gnu99'
+default_library = 'static'
+
+[project options]
+tests = 'disabled'
+ich_descriptors_tool = 'disabled'
+
+[properties]
diff --git a/meson_options.txt b/meson_options.txt
index 89fcbee88..e62deb6ee 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,42 +1,24 @@
-option('pciutils', type : 'boolean', value : true, description : 'use pciutils')
-option('usb', type : 'boolean', value : true, description : 'use libusb1')
-
-option('config_atahpt', type : 'boolean', value : false, description : 'Highpoint (HPT) ATA/RAID controllers')
-option('config_atapromise', type : 'boolean', value : false, description : 'Promise ATA controller')
-option('config_atavia', type : 'boolean', value : true, description : 'VIA VT6421A LPC memory')
-option('config_buspirate_spi', type : 'boolean', value : true, description : 'Bus Pirate SPI')
-option('config_ch341a_spi', type : 'boolean', value : true, description : 'Winchiphead CH341A')
-option('config_dediprog', type : 'boolean', value : true, description : 'Dediprog SF100')
-option('config_developerbox_spi', type : 'boolean', value : true, description : 'Developerbox emergency recovery')
-option('config_digilent_spi', type : 'boolean', value : true, description : 'Digilent Development board JTAG')
-option('config_jlink_spi', type : 'boolean', value : false, description : 'SEGGER J-Link and compatible devices')
-option('config_drkaiser', type : 'boolean', value : true, description : 'Dr. Kaiser')
-option('config_dummy', type : 'boolean', value : true, description : 'dummy tracing')
-option('config_ene_lpc', type : 'boolean', value : true, description : 'ENE LPC interface keyboard controller')
-option('config_ft2232_spi', type : 'boolean', value : true, description : 'FT2232 SPI dongles')
-option('config_gfxnvidia', type : 'boolean', value : true, description : 'NVIDIA graphics cards')
-option('config_raiden', type : 'boolean', value : true, description : 'ChromiumOS Servo DUT debug board')
-option('config_internal', type : 'boolean', value : true, description : 'internal/onboard')
-option('config_internal_dmi', type : 'boolean', value : true, description : 'Use internal DMI parser')
-option('config_it8212', type : 'boolean', value : true, description : 'ITE IT8212F PATA')
-option('config_linux_mtd', type : 'boolean', value : true, description : 'Linux MTD interfaces')
-option('config_linux_spi', type : 'boolean', value : true, description : 'Linux spidev interfaces')
-option('config_mec1308', type : 'boolean', value : true, description : 'Microchip MEC1308 Embedded Controller')
-option('config_mstarddc_spi', type : 'boolean', value : false, description : 'MSTAR DDC support')
-option('config_nic3com', type : 'boolean', value : true, description : '3Com NICs')
-option('config_nicintel_eeprom', type : 'boolean', value : true, description : 'EEPROM on Intel NICs')
-option('config_nicintel_spi', type : 'boolean', value : true, description : 'SPI on Intel NICs')
-option('config_nicintel', type : 'boolean', value : true, description : 'Intel NICs')
-option('config_nicnatsemi', type : 'boolean', value : false, description : 'National Semiconductor NICs')
-option('config_nicrealtek', type : 'boolean', value : true, description : 'Realtek NICs')
-option('config_ogp_spi', type : 'boolean', value : true, description : 'SPI on OGP cards')
-option('config_pickit2_spi', type : 'boolean', value : true, description : 'PICkit2 SPI')
-option('config_pony_spi', type : 'boolean', value : true, description : 'PonyProg2000 SPI')
-option('config_rayer_spi', type : 'boolean', value : true, description : 'RayeR SPIPGM')
-option('config_satamv', type : 'boolean', value : true, description : 'Marvell SATA controllers')
-option('config_satasii', type : 'boolean', value : true, description : 'SiI SATA controllers')
-option('config_serprog', type : 'boolean', value : true, description : 'serprog')
-option('config_usbblaster_spi', type : 'boolean', value : true, description : 'Altera USB-Blaster dongles')
-option('config_stlinkv3_spi', type : 'boolean', value : true, description : 'STMicroelectronics STLINK-V3')
-option('config_lspcon_i2c_spi', type : 'boolean', value : false, description : 'Parade lspcon USB-C to HDMI protocol translator')
-option('config_realtek_mst_i2c_spi', type : 'boolean', value : true, description : 'Realtek MultiStream Transport MST')
+option('classic_cli', type : 'feature', value : 'enabled', description : 'classic flashrom cli binary')
+option('classic_cli_print_wiki', type : 'feature', value : 'disabled', description : 'Print Wiki')
+option('default_programmer_name', type : 'string', description : 'default programmer')
+option('default_programmer_args', type : 'string', description : 'default programmer arguments')
+option('ich_descriptors_tool', type : 'feature', value : 'auto', description : 'Build ich_descriptors_tool')
+option('bash_completion', type : 'feature', value : 'auto', description : 'Install bash completion')
+option('tests', type : 'feature', value : 'auto', description : 'Build unit tests')
+option('use_internal_dmi', type : 'boolean', value : true)
+option('programmer', type : 'array', value : ['auto'], choices : [
+ 'auto', 'all',
+ 'group_internal', 'group_external',
+ 'group_ftdi', 'group_i2c', 'group_jlink', 'group_pci', 'group_serial', 'group_usb',
+ 'asm106x', 'atahpt', 'atapromise', 'atavia', 'buspirate_spi', 'ch341a_spi', 'ch347_spi','dediprog',
+ 'developerbox_spi', 'digilent_spi', 'dirtyjtag_spi', 'drkaiser', 'dummy', 'ft2232_spi',
+ 'gfxnvidia', 'internal', 'it8212', 'jlink_spi', 'linux_mtd', 'linux_spi', 'mediatek_i2c_spi',
+ 'mstarddc_spi', 'ni845x_spi', 'nic3com', 'nicintel', 'nicintel_eeprom', 'nicintel_spi', 'nicnatsemi',
+ 'nicrealtek', 'ogp_spi', 'parade_lspcon', 'pickit2_spi', 'pony_spi', 'raiden_debug_spi',
+ 'rayer_spi', 'realtek_mst_i2c_spi', 'satamv', 'satasii', 'serprog', 'stlinkv3_spi', 'usbblaster_spi',
+], description: 'Active programmers')
+option('llvm_cov', type : 'feature', value : 'disabled', description : 'build for llvm code coverage')
+option('man-pages', type : 'feature', value : 'auto', description : 'build the man-page for classic_cli')
+option('documentation', type : 'feature', value : 'auto', description : 'build the html documentation')
+option('ni845x_search_path', type : 'string', value : 'C:\Program Files (x86)\National Instruments\Ni-845x\MS Visual C',
+ description : 'Path to search for the proprietary ni845x library and header (32-bit Windows only)')
diff --git a/mstarddc_spi.c b/mstarddc_spi.c
index 48d620454..44ebd0545 100644
--- a/mstarddc_spi.c
+++ b/mstarddc_spi.c
@@ -13,10 +13,9 @@
* GNU General Public License for more details.
*/
-#if CONFIG_MSTARDDC_SPI == 1
-
#include <stdio.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
@@ -31,11 +30,11 @@
#include "programmer.h"
#include "spi.h"
-static const struct spi_master spi_master_mstarddc;
-
-static int mstarddc_fd;
-static int mstarddc_addr;
-static int mstarddc_doreset = 1;
+struct mstarddc_spi_data {
+ int fd;
+ int addr;
+ bool doreset;
+};
// MSTAR DDC Commands
#define MSTARDDC_SPI_WRITE 0x10
@@ -46,10 +45,12 @@ static int mstarddc_doreset = 1;
/* Returns 0 upon success, a negative number upon errors. */
static int mstarddc_spi_shutdown(void *data)
{
+ struct mstarddc_spi_data *mstarddc_data = data;
+
// Reset, disables ISP mode
- if (mstarddc_doreset == 1) {
+ if (mstarddc_data->doreset) {
uint8_t cmd = MSTARDDC_SPI_RESET;
- if (write(mstarddc_fd, &cmd, 1) < 0) {
+ if (write(mstarddc_data->fd, &cmd, 1) < 0) {
msg_perr("Error sending reset command: errno %d.\n",
errno);
return -1;
@@ -60,20 +61,103 @@ static int mstarddc_spi_shutdown(void *data)
"or an error occurred.\n");
}
- if (close(mstarddc_fd) < 0) {
+ if (close(mstarddc_data->fd) < 0) {
msg_perr("Error closing device: errno %d.\n", errno);
return -1;
}
+
+ free(data);
return 0;
}
/* Returns 0 upon success, a negative number upon errors. */
-int mstarddc_spi_init(void)
+static int mstarddc_spi_send_command(const struct flashctx *flash,
+ unsigned int writecnt,
+ unsigned int readcnt,
+ const unsigned char *writearr,
+ unsigned char *readarr)
{
+ struct mstarddc_spi_data *mstarddc_data = flash->mst->spi.data;
int ret = 0;
+ uint8_t *cmd = malloc((writecnt + 1) * sizeof(uint8_t));
+ if (cmd == NULL) {
+ msg_perr("Error allocating memory: errno %d.\n", errno);
+ ret = -1;
+ }
+
+ if (!ret && writecnt) {
+ cmd[0] = MSTARDDC_SPI_WRITE;
+ memcpy(cmd + 1, writearr, writecnt);
+ if (write(mstarddc_data->fd, cmd, writecnt + 1) < 0) {
+ msg_perr("Error sending write command: errno %d.\n",
+ errno);
+ ret = -1;
+ }
+ }
+
+ if (!ret && readcnt) {
+ struct i2c_rdwr_ioctl_data i2c_data;
+ struct i2c_msg msg[2];
+
+ cmd[0] = MSTARDDC_SPI_READ;
+ i2c_data.nmsgs = 2;
+ i2c_data.msgs = msg;
+ i2c_data.msgs[0].addr = mstarddc_data->addr;
+ i2c_data.msgs[0].len = 1;
+ i2c_data.msgs[0].flags = 0;
+ i2c_data.msgs[0].buf = cmd;
+ i2c_data.msgs[1].addr = mstarddc_data->addr;
+ i2c_data.msgs[1].len = readcnt;
+ i2c_data.msgs[1].flags = I2C_M_RD;
+ i2c_data.msgs[1].buf = readarr;
+
+ if (ioctl(mstarddc_data->fd, I2C_RDWR, &i2c_data) < 0) {
+ msg_perr("Error sending read command: errno %d.\n",
+ errno);
+ ret = -1;
+ }
+ }
+
+ if (!ret && (writecnt || readcnt)) {
+ cmd[0] = MSTARDDC_SPI_END;
+ if (write(mstarddc_data->fd, cmd, 1) < 0) {
+ msg_perr("Error sending end command: errno %d.\n",
+ errno);
+ ret = -1;
+ }
+ }
+
+ /* Do not reset if something went wrong, as it might prevent from
+ * retrying flashing. */
+ if (ret != 0)
+ mstarddc_data->doreset = false;
+
+ if (cmd)
+ free(cmd);
+
+ return ret;
+}
+
+static const struct spi_master spi_master_mstarddc = {
+ .max_data_read = 256,
+ .max_data_write = 256,
+ .command = mstarddc_spi_send_command,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = mstarddc_spi_shutdown,
+};
+
+/* Returns 0 upon success, a negative number upon errors. */
+static int mstarddc_spi_init(const struct programmer_cfg *cfg)
+{
+ int ret = 0;
+ int mstarddc_fd = -1;
+ int mstarddc_addr;
+ bool mstarddc_doreset = true;
+ struct mstarddc_spi_data *mstarddc_data;
// Get device, address from command-line
- char *i2c_device = extract_programmer_param("dev");
+ char *i2c_device = extract_programmer_param_str(cfg, "dev");
if (i2c_device != NULL && strlen(i2c_device) > 0) {
char *i2c_address = strchr(i2c_device, ':');
if (i2c_address != NULL) {
@@ -96,9 +180,9 @@ int mstarddc_spi_init(void)
msg_pinfo("Info: Will try to use device %s and address 0x%02x.\n", i2c_device, mstarddc_addr);
// Get noreset=1 option from command-line
- char *noreset = extract_programmer_param("noreset");
+ char *noreset = extract_programmer_param_str(cfg, "noreset");
if (noreset != NULL && noreset[0] == '1')
- mstarddc_doreset = 0;
+ mstarddc_doreset = false;
free(noreset);
msg_pinfo("Info: Will %sreset the device at the end.\n", mstarddc_doreset ? "" : "NOT ");
// Open device
@@ -142,91 +226,30 @@ int mstarddc_spi_init(void)
goto out;
}
}
- // Register shutdown function
- register_shutdown(mstarddc_spi_shutdown, NULL);
- // Register programmer
- register_spi_master(&spi_master_mstarddc);
-out:
- free(i2c_device);
- return ret;
-}
-
-/* Returns 0 upon success, a negative number upon errors. */
-static int mstarddc_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt,
- unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
-{
- int ret = 0;
- uint8_t *cmd = malloc((writecnt + 1) * sizeof(uint8_t));
- if (cmd == NULL) {
- msg_perr("Error allocating memory: errno %d.\n", errno);
+ mstarddc_data = calloc(1, sizeof(*mstarddc_data));
+ if (!mstarddc_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
ret = -1;
+ goto out;
}
- if (!ret && writecnt) {
- cmd[0] = MSTARDDC_SPI_WRITE;
- memcpy(cmd + 1, writearr, writecnt);
- if (write(mstarddc_fd, cmd, writecnt + 1) < 0) {
- msg_perr("Error sending write command: errno %d.\n",
- errno);
- ret = -1;
- }
- }
-
- if (!ret && readcnt) {
- struct i2c_rdwr_ioctl_data i2c_data;
- struct i2c_msg msg[2];
-
- cmd[0] = MSTARDDC_SPI_READ;
- i2c_data.nmsgs = 2;
- i2c_data.msgs = msg;
- i2c_data.msgs[0].addr = mstarddc_addr;
- i2c_data.msgs[0].len = 1;
- i2c_data.msgs[0].flags = 0;
- i2c_data.msgs[0].buf = cmd;
- i2c_data.msgs[1].addr = mstarddc_addr;
- i2c_data.msgs[1].len = readcnt;
- i2c_data.msgs[1].flags = I2C_M_RD;
- i2c_data.msgs[1].buf = readarr;
-
- if (ioctl(mstarddc_fd, I2C_RDWR, &i2c_data) < 0) {
- msg_perr("Error sending read command: errno %d.\n",
- errno);
- ret = -1;
- }
- }
-
- if (!ret && (writecnt || readcnt)) {
- cmd[0] = MSTARDDC_SPI_END;
- if (write(mstarddc_fd, cmd, 1) < 0) {
- msg_perr("Error sending end command: errno %d.\n",
- errno);
- ret = -1;
- }
- }
-
- /* Do not reset if something went wrong, as it might prevent from
- * retrying flashing. */
- if (ret != 0)
- mstarddc_doreset = 0;
-
- if (cmd)
- free(cmd);
+ mstarddc_data->fd = mstarddc_fd;
+ mstarddc_data->addr = mstarddc_addr;
+ mstarddc_data->doreset = mstarddc_doreset;
+ // Register programmer
+ register_spi_master(&spi_master_mstarddc, mstarddc_data);
+out:
+ free(i2c_device);
+ if (ret && (mstarddc_fd >= 0))
+ close(mstarddc_fd);
return ret;
}
-static const struct spi_master spi_master_mstarddc = {
- .max_data_read = 256,
- .max_data_write = 256,
- .command = mstarddc_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+const struct programmer_entry programmer_mstarddc_spi = {
+ .name = "mstarddc_spi",
+ .type = OTHER,
+ .devs.note = "MSTAR DDC devices addressable via /dev/i2c-* on Linux.\n",
+ .init = mstarddc_spi_init,
};
-
-#endif
diff --git a/ni845x_spi.c b/ni845x_spi.c
index 7b2bea3e2..1948387bc 100644
--- a/ni845x_spi.c
+++ b/ni845x_spi.c
@@ -15,6 +15,13 @@
*
*/
+/* The ni845x header does need the WIN32 symbol to be defined and meson does not do it.
+ * Define it just here, since this driver will only work on 32-bit Windows.
+ */
+#ifndef WIN32
+#define WIN32
+#endif
+
#include <ctype.h>
#include <inttypes.h>
#include <string.h>
@@ -40,19 +47,14 @@ enum voltage_coerce_mode {
USE_HIGHER
};
-static const struct spi_master spi_programmer_ni845x;
-
-static unsigned char CS_number; // use chip select 0 as default
-static enum USB845x_type device_pid = Unknown_NI845X_Device;
-
-static uInt32 device_handle;
-static NiHandle configuration_handle;
-static uint16_t io_voltage_in_mV;
-static bool ignore_io_voltage_limits;
-
-static int ni845x_spi_shutdown(void *data);
-static int32 ni845x_spi_open_resource(char *resource_handle, uInt32 *opened_handle);
-static void ni845x_spi_print_available_devices(void);
+struct ni845x_spi_data {
+ unsigned char CS_number; // use chip select 0 as default
+ enum USB845x_type device_pid;
+ uInt32 device_handle;
+ NiHandle configuration_handle;
+ uint16_t io_voltage_in_mV;
+ bool ignore_io_voltage_limits;
+};
// USB-8452 supported voltages, keep this array in ascending order!
static const uint8_t usb8452_io_voltages_in_100mV[5] = {
@@ -129,23 +131,45 @@ static void ni845x_report_warning(const char *const func, const int32 err)
}
/**
+ * @brief ni845x_spi_open_resource
+ * @param resource_handle the resource handle returned by the ni845xFindDevice or ni845xFindDeviceNext
+ * @param opened_handle the opened handle from the ni845xOpen
+ * @return the 0 on successful competition, negative error code on failure positive code on warning
+ */
+static int32 ni845x_spi_open_resource(char *resource_handle, uInt32 *opened_handle, enum USB845x_type pid)
+{
+ // NI-845x driver loads the FPGA bitfile at the first time
+ // which can take couple seconds
+ if (pid == USB8452)
+ msg_pwarn("Opening NI-8452, this might take a while for the first time\n");
+
+ int32 tmp = ni845xOpen(resource_handle, opened_handle);
+
+ if (tmp < 0)
+ ni845x_report_error("ni845xOpen", tmp);
+ else if (tmp > 0)
+ ni845x_report_warning("ni845xOpen", tmp);
+ return tmp;
+}
+
+/**
* @param serial a null terminated string containing the serial number of the specific device or NULL
- * @return the 0 on successful completition, negative error code on failure
+ * @return the 0 on successful completion, negative error code on failure
*/
-static int ni845x_spi_open(const char *serial, uInt32 *return_handle)
+static int ni845x_spi_open(const char *serial, uInt32 *return_handle, enum USB845x_type *pid)
{
char resource_name[256];
NiHandle device_find_handle;
uInt32 found_devices_count = 0;
int32 tmp = 0;
- unsigned int vid, pid, usb_bus;
+ unsigned int vid, dev_pid, usb_bus;
unsigned long int serial_as_number;
int ret = -1;
tmp = ni845xFindDevice(resource_name, &device_find_handle, &found_devices_count);
if (tmp != 0) {
- // supress warning if no device found
+ // suppress warning if no device found
if (tmp != NI845x_FIND_DEVICE_NO_DEVICE_FOUND)
ni845x_report_error("ni845xFindDevice", tmp);
return -1;
@@ -159,7 +183,7 @@ static int ni845x_spi_open(const char *serial, uInt32 *return_handle)
// and the DEADBEEF is the serial of the device
if (sscanf(resource_name,
"USB%u::0x%04X::0x%04X::%08lX::RAW",
- &usb_bus, &vid, &pid, &serial_as_number) != 4) {
+ &usb_bus, &vid, &dev_pid, &serial_as_number) != 4) {
// malformed resource string detected
msg_pwarn("Warning: Unable to parse the %s NI-845x resource string.\n",
resource_name);
@@ -167,9 +191,9 @@ static int ni845x_spi_open(const char *serial, uInt32 *return_handle)
continue;
}
- device_pid = pid;
+ *pid = dev_pid;
- if (!serial || strtol(serial, NULL, 16) == serial_as_number)
+ if (!serial || strtoul(serial, NULL, 16) == serial_as_number)
break;
if (found_devices_count > 1) {
@@ -182,7 +206,7 @@ static int ni845x_spi_open(const char *serial, uInt32 *return_handle)
}
if (found_devices_count)
- ret = ni845x_spi_open_resource(resource_name, return_handle);
+ ret = ni845x_spi_open_resource(resource_name, return_handle, *pid);
_close_ret:
tmp = ni845xCloseFindDeviceHandle(device_find_handle);
@@ -194,46 +218,26 @@ _close_ret:
}
/**
- * @brief ni845x_spi_open_resource
- * @param resource_handle the resource handle returned by the ni845xFindDevice or ni845xFindDeviceNext
- * @param opened_handle the opened handle from the ni845xOpen
- * @return the 0 on successful competition, negative error code on failure positive code on warning
- */
-static int32 ni845x_spi_open_resource(char *resource_handle, uInt32 *opened_handle)
-{
- // NI-845x driver loads the FPGA bitfile at the first time
- // which can take couple seconds
- if (device_pid == USB8452)
- msg_pwarn("Opening NI-8452, this might take a while for the first time\n");
-
- int32 tmp = ni845xOpen(resource_handle, opened_handle);
-
- if (tmp < 0)
- ni845x_report_error("ni845xOpen", tmp);
- else if (tmp > 0)
- ni845x_report_warning("ni845xOpen", tmp);
- return tmp;
-}
-
-/**
* @brief usb8452_spi_set_io_voltage sets the IO voltage for the USB-8452 devices
* @param requested_io_voltage_mV the desired IO voltage in mVolts
* @param set_io_voltage_mV the IO voltage which was set in mVolts
* @param coerce_mode if set to USE_LOWER the closest supported IO voltage which is lower or equal to
- * the requested_io_voltage_mV will be selected. Otherwise the next closest supported voltage will be choosen
+ * the requested_io_voltage_mV will be selected. Otherwise the next closest supported voltage will be chosen
* which is higher or equal to the requested_io_voltage_mV.
* @return 0 on success, negative on error, positive on warning
*/
static int usb8452_spi_set_io_voltage(uint16_t requested_io_voltage_mV,
uint16_t *set_io_voltage_mV,
- enum voltage_coerce_mode coerce_mode)
+ enum voltage_coerce_mode coerce_mode,
+ enum USB845x_type pid,
+ uInt32 device_handle)
{
- int i = 0;
+ unsigned int i = 0;
uint8_t selected_voltage_100mV = 0;
uint8_t requested_io_voltage_100mV = 0;
- if (device_pid == USB8451) {
- io_voltage_in_mV = 3300;
+ if (pid == USB8451) {
+ *set_io_voltage_mV = 3300;
msg_pwarn("USB-8451 does not support the changing of the SPI IO voltage\n");
return 0;
}
@@ -306,7 +310,7 @@ static int usb8452_spi_set_io_voltage(uint16_t requested_io_voltage_mV,
* @param SCK_freq_in_KHz SCK speed in KHz
* @return
*/
-static int ni845x_spi_set_speed(uint16_t SCK_freq_in_KHz)
+static int ni845x_spi_set_speed(NiHandle configuration_handle, uint16_t SCK_freq_in_KHz)
{
int32 i = ni845xSpiConfigurationSetClockRate(configuration_handle, SCK_freq_in_KHz);
uInt16 clock_freq_read_KHz;
@@ -346,7 +350,7 @@ static void ni845x_spi_print_available_devices(void)
tmp = ni845xFindDevice(resource_handle, &device_find_handle, &found_devices_count);
if (tmp != 0) {
- // supress warning if no device found
+ // suppress warning if no device found
if (tmp != NI845x_FIND_DEVICE_NO_DEVICE_FOUND)
ni845x_report_error("ni845xFindDevice", tmp);
return;
@@ -389,193 +393,106 @@ static void ni845x_spi_print_available_devices(void)
ni845x_report_error("ni845xCloseFindDeviceHandle", tmp);
}
-int ni845x_spi_init(void)
-{
- char *speed_str = NULL;
- char *CS_str = NULL;
- char *voltage = NULL;
- char *endptr = NULL;
- int requested_io_voltage_mV = 1200; // default the IO voltage to 1.2V
- int spi_speed_KHz = 1000; // selecting 1 MHz SCK is a good bet
- char *serial_number = NULL; // by default open the first connected device
- char *ignore_io_voltage_limits_str = NULL;
- int32 tmp = 0;
-
- // read the cs parameter (which Chip select should we use)
- CS_str = extract_programmer_param("cs");
- if (CS_str) {
- CS_number = CS_str[0] - '0';
- free(CS_str);
- if (strlen(CS_str) > 1 || CS_number < 0 || 7 < CS_number) {
- msg_perr("Only CS 0-7 supported\n");
- return 1;
- }
- }
-
- voltage = extract_programmer_param("voltage");
- if (voltage != NULL) {
- requested_io_voltage_mV = parse_voltage(voltage);
- free(voltage);
- if (requested_io_voltage_mV < 0)
- return 1;
- }
-
- serial_number = extract_programmer_param("serial");
-
- speed_str = extract_programmer_param("spispeed");
- if (speed_str) {
- spi_speed_KHz = strtoul(speed_str, &endptr, 0);
- if (*endptr) {
- msg_perr("The spispeed parameter passed with invalid format: %s\n",
- speed_str);
- msg_perr("Please pass the parameter with a simple number in kHz\n");
- return 1;
- }
- free(speed_str);
- }
-
- ignore_io_voltage_limits = false;
- ignore_io_voltage_limits_str = extract_programmer_param("ignore_io_voltage_limits");
- if (ignore_io_voltage_limits_str
- && strcmp(ignore_io_voltage_limits_str, "yes") == 0) {
- ignore_io_voltage_limits = true;
- }
-
- if (ni845x_spi_open(serial_number, &device_handle)) {
- if (serial_number) {
- msg_pinfo("Could not find any connected NI USB-8451/8452 with serialnumber: %s!\n",
- serial_number);
- ni845x_spi_print_available_devices();
- msg_pinfo("Check the S/N field on the bottom of the device,\n"
- "or use 'lsusb -v -d 3923:7166 | grep Serial' for USB-8451\n"
- "or 'lsusb -v -d 3923:7514 | grep Serial' for USB-8452\n");
- free(serial_number);
- } else {
- msg_pinfo("Could not find any connected NI USB-845x device!\n");
- }
- return 1;
- }
- free(serial_number);
-
- // open the SPI config handle
- tmp = ni845xSpiConfigurationOpen(&configuration_handle);
- if (tmp != 0) {
- ni845x_report_error("ni845xSpiConfigurationOpen", tmp);
- ni845x_spi_shutdown(NULL);
- return 1;
- }
-
- if (usb8452_spi_set_io_voltage(requested_io_voltage_mV, &io_voltage_in_mV, USE_LOWER) < 0) {
- ni845x_spi_shutdown(NULL);
- return 1; // no alert here usb8452_spi_set_io_voltage already printed that
- }
-
- if (ni845x_spi_set_speed(spi_speed_KHz)) {
- msg_perr("Unable to set SPI speed\n");
- ni845x_spi_shutdown(NULL);
- return 1;
- }
-
- if (register_shutdown(ni845x_spi_shutdown, NULL)) {
- ni845x_spi_shutdown(NULL);
- return 1;
- }
-
- register_spi_master(&spi_programmer_ni845x);
-
- return 0;
-}
-
static int ni845x_spi_shutdown(void *data)
{
+ struct ni845x_spi_data *ni_data = data;
int32 ret = 0;
- if (configuration_handle != 0) {
- ret = ni845xSpiConfigurationClose(configuration_handle);
+ if (ni_data->configuration_handle != 0) {
+ ret = ni845xSpiConfigurationClose(ni_data->configuration_handle);
if (ret)
ni845x_report_error("ni845xSpiConfigurationClose", ret);
}
- if (device_handle != 0) {
- ret = ni845xClose(device_handle);
+ if (ni_data->device_handle != 0) {
+ ret = ni845xClose(ni_data->device_handle);
if (ret)
ni845x_report_error("ni845xClose", ret);
}
- return 0;
+
+ free(data);
+ return ret;
}
static void ni845x_warn_over_max_voltage(const struct flashctx *flash)
{
- if (device_pid == USB8451) {
+ const struct ni845x_spi_data *data = flash->mst->spi.data;
+
+ if (data->device_pid == USB8451) {
msg_pwarn("The %s chip maximum voltage is %.1fV, while the USB-8451 "
"IO voltage levels are 3.3V.\n"
"Ignoring this because ignore_io_voltage_limits parameter is set.\n",
flash->chip->name,
flash->chip->voltage.max / 1000.0f);
- } else if (device_pid == USB8452) {
+ } else if (data->device_pid == USB8452) {
msg_pwarn("The %s chip maximum voltage is %.1fV, while the USB-8452 "
"IO voltage is set to %.1fV.\n"
"Ignoring this because ignore_io_voltage_limits parameter is set.\n",
flash->chip->name,
flash->chip->voltage.max / 1000.0f,
- io_voltage_in_mV / 1000.0f);
+ data->io_voltage_in_mV / 1000.0f);
}
}
static int ni845x_spi_io_voltage_check(const struct flashctx *flash)
{
+ struct ni845x_spi_data *data = flash->mst->spi.data;
static bool first_transmit = true;
if (first_transmit && flash->chip) {
first_transmit = false;
- if (io_voltage_in_mV > flash->chip->voltage.max) {
- if (ignore_io_voltage_limits) {
+ if (data->io_voltage_in_mV > flash->chip->voltage.max) {
+ if (data->ignore_io_voltage_limits) {
ni845x_warn_over_max_voltage(flash);
return 0;
}
- if (device_pid == USB8451) {
+ if (data->device_pid == USB8451) {
msg_perr("The %s chip maximum voltage is %.1fV, while the USB-8451 "
"IO voltage levels are 3.3V.\nAborting operations\n",
flash->chip->name,
flash->chip->voltage.max / 1000.0f);
return -1;
- } else if (device_pid == USB8452) {
+ } else if (data->device_pid == USB8452) {
msg_perr("Lowering IO voltage because the %s chip maximum voltage is %.1fV, "
"(%.1fV was set)\n",
flash->chip->name,
flash->chip->voltage.max / 1000.0f,
- io_voltage_in_mV / 1000.0f);
+ data->io_voltage_in_mV / 1000.0f);
if (usb8452_spi_set_io_voltage(flash->chip->voltage.max,
- &io_voltage_in_mV,
- USE_LOWER)) {
+ &data->io_voltage_in_mV,
+ USE_LOWER,
+ data->device_pid,
+ data->device_handle)) {
msg_perr("Unable to lower the IO voltage below "
"the chip's maximum voltage\n");
return -1;
}
}
- } else if (io_voltage_in_mV < flash->chip->voltage.min) {
- if (device_pid == USB8451) {
+ } else if (data->io_voltage_in_mV < flash->chip->voltage.min) {
+ if (data->device_pid == USB8451) {
msg_pwarn("Flash operations might be unreliable, because the %s chip's "
"minimum voltage is %.1fV, while the USB-8451's "
"IO voltage levels are 3.3V.\n",
flash->chip->name,
flash->chip->voltage.min / 1000.0f);
- return ignore_io_voltage_limits ? 0 : -1;
- } else if (device_pid == USB8452) {
+ return data->ignore_io_voltage_limits ? 0 : -1;
+ } else if (data->device_pid == USB8452) {
msg_pwarn("Raising the IO voltage because the %s chip's "
"minimum voltage is %.1fV, "
"(%.1fV was set)\n",
flash->chip->name,
flash->chip->voltage.min / 1000.0f,
- io_voltage_in_mV / 1000.0f);
+ data->io_voltage_in_mV / 1000.0f);
if (usb8452_spi_set_io_voltage(flash->chip->voltage.min,
- &io_voltage_in_mV,
- USE_HIGHER)) {
+ &data->io_voltage_in_mV,
+ USE_HIGHER,
+ data->device_pid,
+ data->device_handle)) {
msg_pwarn("Unable to raise the IO voltage above the chip's "
"minimum voltage\n"
"Flash operations might be unreliable.\n");
- return ignore_io_voltage_limits ? 0 : -1;
+ return data->ignore_io_voltage_limits ? 0 : -1;
}
}
}
@@ -583,12 +500,13 @@ static int ni845x_spi_io_voltage_check(const struct flashctx *flash)
return 0;
}
-static int ni845x_spi_transmit(struct flashctx *flash,
+static int ni845x_spi_transmit(const struct flashctx *flash,
unsigned int write_cnt,
unsigned int read_cnt,
const unsigned char *write_arr,
unsigned char *read_arr)
{
+ const struct ni845x_spi_data *data = flash->mst->spi.data;
uInt32 read_size = 0;
uInt8 *transfer_buffer = NULL;
int32 ret = 0;
@@ -604,8 +522,8 @@ static int ni845x_spi_transmit(struct flashctx *flash,
memcpy(transfer_buffer, write_arr, write_cnt);
- ret = ni845xSpiWriteRead(device_handle,
- configuration_handle,
+ ret = ni845xSpiWriteRead(data->device_handle,
+ data->configuration_handle,
(write_cnt + read_cnt), transfer_buffer, &read_size, transfer_buffer);
if (ret < 0) {
// Negative specifies an error, meaning the function did not perform the expected behavior.
@@ -620,7 +538,7 @@ static int ni845x_spi_transmit(struct flashctx *flash,
if (read_cnt != 0 && read_arr != NULL) {
if ((read_cnt + write_cnt) != read_size) {
- msg_perr("%s: expected and returned read count mismatch: %u expected, %ld recieved\n",
+ msg_perr("%s: expected and returned read count mismatch: %u expected, %ld received\n",
__func__, read_cnt, read_size);
free(transfer_buffer);
return -1;
@@ -632,11 +550,124 @@ static int ni845x_spi_transmit(struct flashctx *flash,
}
static const struct spi_master spi_programmer_ni845x = {
- .max_data_read = MAX_DATA_READ_UNLIMITED,
- .max_data_write = MAX_DATA_WRITE_UNLIMITED,
- .command = ni845x_spi_transmit,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .max_data_read = MAX_DATA_READ_UNLIMITED,
+ .max_data_write = MAX_DATA_WRITE_UNLIMITED,
+ .command = ni845x_spi_transmit,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = ni845x_spi_shutdown,
+};
+
+static int ni845x_spi_init(const struct programmer_cfg *cfg)
+{
+ char *speed_str = NULL;
+ char *CS_str = NULL;
+ char *voltage = NULL;
+ char *endptr = NULL;
+ int requested_io_voltage_mV = 1200; // default the IO voltage to 1.2V
+ int spi_speed_KHz = 1000; // selecting 1 MHz SCK is a good bet
+ char *serial_number = NULL; // by default open the first connected device
+ char *ignore_io_voltage_limits_str = NULL;
+ bool ignore_io_voltage_limits;
+ unsigned char CS_number = 0;
+ enum USB845x_type device_pid = Unknown_NI845X_Device;
+ uInt32 device_handle;
+ int32 tmp = 0;
+
+ // read the cs parameter (which Chip select should we use)
+ CS_str = extract_programmer_param_str(cfg, "cs");
+ if (CS_str) {
+ CS_number = strtoul(CS_str, NULL, 10);
+ free(CS_str);
+ if (CS_number > 7) {
+ msg_perr("Only CS 0-7 supported\n");
+ return 1;
+ }
+ }
+
+ voltage = extract_programmer_param_str(cfg, "voltage");
+ if (voltage != NULL) {
+ requested_io_voltage_mV = parse_voltage(voltage);
+ free(voltage);
+ if (requested_io_voltage_mV < 0)
+ return 1;
+ }
+
+ serial_number = extract_programmer_param_str(cfg, "serial");
+
+ speed_str = extract_programmer_param_str(cfg, "spispeed");
+ if (speed_str) {
+ spi_speed_KHz = strtoul(speed_str, &endptr, 0);
+ if (*endptr) {
+ msg_perr("The spispeed parameter passed with invalid format: %s\n",
+ speed_str);
+ msg_perr("Please pass the parameter with a simple number in kHz\n");
+ return 1;
+ }
+ free(speed_str);
+ }
+
+ ignore_io_voltage_limits = false;
+ ignore_io_voltage_limits_str = extract_programmer_param_str(cfg, "ignore_io_voltage_limits");
+ if (ignore_io_voltage_limits_str
+ && strcmp(ignore_io_voltage_limits_str, "yes") == 0) {
+ ignore_io_voltage_limits = true;
+ }
+
+ if (ni845x_spi_open(serial_number, &device_handle, &device_pid)) {
+ if (serial_number) {
+ msg_pinfo("Could not find any connected NI USB-8451/8452 with serialnumber: %s!\n",
+ serial_number);
+ ni845x_spi_print_available_devices();
+ msg_pinfo("Check the S/N field on the bottom of the device,\n"
+ "or use 'lsusb -v -d 3923:7166 | grep Serial' for USB-8451\n"
+ "or 'lsusb -v -d 3923:7514 | grep Serial' for USB-8452\n");
+ free(serial_number);
+ } else {
+ msg_pinfo("Could not find any connected NI USB-845x device!\n");
+ }
+ return 1;
+ }
+ free(serial_number);
+
+ struct ni845x_spi_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ return 1;
+ }
+ data->CS_number = CS_number;
+ data->device_pid = device_pid;
+ data->device_handle = device_handle;
+ data->ignore_io_voltage_limits = ignore_io_voltage_limits;
+
+ // open the SPI config handle
+ tmp = ni845xSpiConfigurationOpen(&data->configuration_handle);
+ if (tmp != 0) {
+ ni845x_report_error("ni845xSpiConfigurationOpen", tmp);
+ goto err;
+ }
+
+ if (usb8452_spi_set_io_voltage(requested_io_voltage_mV, &data->io_voltage_in_mV,
+ USE_LOWER, data->device_pid, data->device_handle) < 0) {
+ // no alert here usb8452_spi_set_io_voltage already printed that
+ goto err;
+ }
+
+ if (ni845x_spi_set_speed(data->configuration_handle, spi_speed_KHz)) {
+ msg_perr("Unable to set SPI speed\n");
+ goto err;
+ }
+
+ return register_spi_master(&spi_programmer_ni845x, data);
+
+err:
+ ni845x_spi_shutdown(data);
+ return 1;
+}
+
+const struct programmer_entry programmer_ni845x_spi = {
+ .name = "ni845x_spi",
+ .type = OTHER, // choose other because NI-845x uses own USB implementation
+ .devs.note = "National Instruments USB-845x\n",
+ .init = ni845x_spi_init,
};
diff --git a/nic3com.c b/nic3com.c
index b7b967a44..a578d4853 100644
--- a/nic3com.c
+++ b/nic3com.c
@@ -14,12 +14,11 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_x86_io.h"
+#include "platform/pci.h"
#define BIOS_ROM_ADDR 0x04
#define BIOS_ROM_DATA 0x08
@@ -29,17 +28,19 @@
#define PCI_VENDOR_ID_3COM 0x10b7
-static uint32_t io_base_addr = 0;
-static uint32_t internal_conf;
-static uint16_t id;
+struct nic3com_data {
+ uint32_t io_base_addr;
+ uint32_t internal_conf;
+ uint16_t id;
+};
-const struct dev_entry nics_3com[] = {
+static const struct dev_entry nics_3com[] = {
/* 3C90xB */
{0x10b7, 0x9055, OK, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-TX"},
{0x10b7, 0x9001, NT, "3COM", "3C90xB: PCI 10/100 Mbps; shared 10BASE-T/100BASE-T4" },
{0x10b7, 0x9004, OK, "3COM", "3C90xB: PCI 10BASE-T (TPO)" },
{0x10b7, 0x9005, NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2/AUI (COMBO)" },
- {0x10b7, 0x9006, NT, "3COM", "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" },
+ {0x10b7, 0x9006, OK, "3COM", "3C90xB: PCI 10BASE-T/10BASE2 (TPC)" },
{0x10b7, 0x900a, NT, "3COM", "3C90xB: PCI 10BASE-FL" },
{0x10b7, 0x905a, NT, "3COM", "3C90xB: PCI 10BASE-FX" },
{0x10b7, 0x9058, OK, "3COM", "3C905B: Cyclone 10/100/BNC" },
@@ -54,41 +55,57 @@ const struct dev_entry nics_3com[] = {
};
static void nic3com_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr);
+ chipaddr addr)
+{
+ struct nic3com_data *data = flash->mst->par.data;
+
+ OUTL((uint32_t)addr, data->io_base_addr + BIOS_ROM_ADDR);
+ OUTB(val, data->io_base_addr + BIOS_ROM_DATA);
+}
+
static uint8_t nic3com_chip_readb(const struct flashctx *flash,
- const chipaddr addr);
-static const struct par_master par_master_nic3com = {
- .chip_readb = nic3com_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = nic3com_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
-};
+ const chipaddr addr)
+{
+ struct nic3com_data *data = flash->mst->par.data;
+
+ OUTL((uint32_t)addr, data->io_base_addr + BIOS_ROM_ADDR);
+ return INB(data->io_base_addr + BIOS_ROM_DATA);
+}
-static int nic3com_shutdown(void *data)
+static int nic3com_shutdown(void *par_data)
{
+ struct nic3com_data *data = par_data;
+ const uint16_t id = data->id;
+
/* 3COM 3C90xB cards need a special fixup. */
if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
|| id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
/* Select register window 3 and restore the receiver status. */
- OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
- OUTL(internal_conf, io_base_addr + INTERNAL_CONFIG);
+ OUTW(SELECT_REG_WINDOW + 3, data->io_base_addr + INT_STATUS);
+ OUTL(data->internal_conf, data->io_base_addr + INTERNAL_CONFIG);
}
+ free(data);
return 0;
}
-int nic3com_init(void)
+static const struct par_master par_master_nic3com = {
+ .chip_readb = nic3com_chip_readb,
+ .chip_writeb = nic3com_chip_writeb,
+ .shutdown = nic3com_shutdown,
+};
+
+static int nic3com_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
+ uint32_t io_base_addr = 0;
+ uint32_t internal_conf = 0;
+ uint16_t id;
if (rget_io_perms())
return 1;
- dev = pcidev_init(nics_3com, PCI_BASE_ADDRESS_0);
+ dev = pcidev_init(cfg, nics_3com, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -116,29 +133,33 @@ int nic3com_init(void)
*/
OUTW(SELECT_REG_WINDOW + 0, io_base_addr + INT_STATUS);
- if (register_shutdown(nic3com_shutdown, NULL))
- return 1;
+ struct nic3com_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
+ goto init_err_cleanup_exit;
+ }
+ data->io_base_addr = io_base_addr;
+ data->internal_conf = internal_conf;
+ data->id = id;
max_rom_decode.parallel = 128 * 1024;
- register_par_master(&par_master_nic3com, BUS_PARALLEL);
- return 0;
-}
-
-static void nic3com_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
- OUTB(val, io_base_addr + BIOS_ROM_DATA);
-}
+ return register_par_master(&par_master_nic3com, BUS_PARALLEL, data);
-static uint8_t nic3com_chip_readb(const struct flashctx *flash,
- const chipaddr addr)
-{
- OUTL((uint32_t)addr, io_base_addr + BIOS_ROM_ADDR);
- return INB(io_base_addr + BIOS_ROM_DATA);
+init_err_cleanup_exit:
+ /* 3COM 3C90xB cards need a special fixup. */
+ if (id == 0x9055 || id == 0x9001 || id == 0x9004 || id == 0x9005
+ || id == 0x9006 || id == 0x900a || id == 0x905a || id == 0x9058) {
+ /* Select register window 3 and restore the receiver status. */
+ OUTW(SELECT_REG_WINDOW + 3, io_base_addr + INT_STATUS);
+ OUTL(internal_conf, io_base_addr + INTERNAL_CONFIG);
+ }
+ return 1;
}
-#else
-#error PCI port I/O access is not supported on this architecture yet.
-#endif
+const struct programmer_entry programmer_nic3com = {
+ .name = "nic3com",
+ .type = PCI,
+ .devs.dev = nics_3com,
+ .init = nic3com_init,
+};
diff --git a/nicintel.c b/nicintel.c
index 4672890f7..feb07b663 100644
--- a/nicintel.c
+++ b/nicintel.c
@@ -18,12 +18,15 @@
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
-static uint8_t *nicintel_bar;
-static uint8_t *nicintel_control_bar;
+struct nicintel_data {
+ uint8_t *nicintel_bar;
+ uint8_t *nicintel_control_bar;
+};
-const struct dev_entry nics_intel[] = {
+static const struct dev_entry nics_intel[] = {
{PCI_VENDOR_ID_INTEL, 0x1209, NT, "Intel", "8255xER/82551IT Fast Ethernet Controller"},
{PCI_VENDOR_ID_INTEL, 0x1229, OK, "Intel", "82557/8/9/0/1 Ethernet Pro 100"},
@@ -41,33 +44,42 @@ const struct dev_entry nics_intel[] = {
#define CSR_FCR 0x0c
static void nicintel_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr);
+ chipaddr addr)
+{
+ const struct nicintel_data *data = flash->mst->par.data;
+
+ pci_mmio_writeb(val, data->nicintel_bar + (addr & NICINTEL_MEMMAP_MASK));
+}
+
static uint8_t nicintel_chip_readb(const struct flashctx *flash,
- const chipaddr addr);
+ const chipaddr addr)
+{
+ const struct nicintel_data *data = flash->mst->par.data;
+
+ return pci_mmio_readb(data->nicintel_bar + (addr & NICINTEL_MEMMAP_MASK));
+}
+
+static int nicintel_shutdown(void *par_data)
+{
+ free(par_data);
+ return 0;
+}
+
static const struct par_master par_master_nicintel = {
- .chip_readb = nicintel_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = nicintel_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
+ .chip_readb = nicintel_chip_readb,
+ .chip_writeb = nicintel_chip_writeb,
+ .shutdown = nicintel_shutdown,
};
-int nicintel_init(void)
+static int nicintel_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
uintptr_t addr;
-
- /* Needed only for PCI accesses on some platforms.
- * FIXME: Refactor that into get_mem_perms/rget_io_perms/get_pci_perms?
- */
- if (rget_io_perms())
- return 1;
+ uint8_t *bar;
+ uint8_t *control_bar;
/* FIXME: BAR2 is not available if the device uses the CardBus function. */
- dev = pcidev_init(nics_intel, PCI_BASE_ADDRESS_2);
+ dev = pcidev_init(cfg, nics_intel, PCI_BASE_ADDRESS_2);
if (!dev)
return 1;
@@ -75,16 +87,16 @@ int nicintel_init(void)
if (!addr)
return 1;
- nicintel_bar = rphysmap("Intel NIC flash", addr, NICINTEL_MEMMAP_SIZE);
- if (nicintel_bar == ERROR_PTR)
+ bar = rphysmap("Intel NIC flash", addr, NICINTEL_MEMMAP_SIZE);
+ if (bar == ERROR_PTR)
return 1;
addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0);
if (!addr)
return 1;
- nicintel_control_bar = rphysmap("Intel NIC control/status reg", addr, NICINTEL_CONTROL_MEMMAP_SIZE);
- if (nicintel_control_bar == ERROR_PTR)
+ control_bar = rphysmap("Intel NIC control/status reg", addr, NICINTEL_CONTROL_MEMMAP_SIZE);
+ if (control_bar == ERROR_PTR)
return 1;
/* FIXME: This register is pretty undocumented in all publicly available
@@ -96,22 +108,23 @@ int nicintel_init(void)
* what we should do with it. Write 0x0001 because we have nothing
* better to do with our time.
*/
- pci_rmmio_writew(0x0001, nicintel_control_bar + CSR_FCR);
-
- max_rom_decode.parallel = NICINTEL_MEMMAP_SIZE;
- register_par_master(&par_master_nicintel, BUS_PARALLEL);
+ pci_rmmio_writew(0x0001, control_bar + CSR_FCR);
- return 0;
-}
+ struct nicintel_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
+ return 1;
+ }
+ data->nicintel_bar = bar;
+ data->nicintel_control_bar = control_bar;
-static void nicintel_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- pci_mmio_writeb(val, nicintel_bar + (addr & NICINTEL_MEMMAP_MASK));
+ max_rom_decode.parallel = NICINTEL_MEMMAP_SIZE;
+ return register_par_master(&par_master_nicintel, BUS_PARALLEL, data);
}
-static uint8_t nicintel_chip_readb(const struct flashctx *flash,
- const chipaddr addr)
-{
- return pci_mmio_readb(nicintel_bar + (addr & NICINTEL_MEMMAP_MASK));
-}
+const struct programmer_entry programmer_nicintel = {
+ .name = "nicintel",
+ .type = PCI,
+ .devs.dev = nics_intel,
+ .init = nicintel_init,
+};
diff --git a/nicintel_eeprom.c b/nicintel_eeprom.c
index 4d45f7913..6a734b050 100644
--- a/nicintel_eeprom.c
+++ b/nicintel_eeprom.c
@@ -34,7 +34,8 @@
#include "flash.h"
#include "spi.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_INTEL 0x8086
#define MEMMAP_SIZE 0x1c /* Only EEC, EERD and EEWR are needed. */
@@ -68,27 +69,33 @@
#define EEWR_ADDR 2
#define EEWR_DATA 16
-#define BIT(x) (1<<x)
#define EE_PAGE_MASK 0x3f
-static uint8_t *nicintel_eebar;
-static struct pci_dev *nicintel_pci;
-static bool done_i20_write = false;
-
#define UNPROG_DEVICE 0x1509
+struct nicintel_eeprom_data {
+ struct pci_dev *nicintel_pci;
+ uint8_t *nicintel_eebar;
+
+ /* Intel 82580 variable(s) */
+ uint32_t eec;
+
+ /* Intel I210 variable(s) */
+ bool done_i210_write;
+};
+
/*
* Warning: is_i210() below makes assumptions on these PCI ids.
* It may have to be updated when this list is extended.
*/
-const struct dev_entry nics_intel_ee[] = {
+static const struct dev_entry nics_intel_ee[] = {
{PCI_VENDOR_ID_INTEL, 0x150e, OK, "Intel", "82580 Quad Gigabit Ethernet Controller (Copper)"},
{PCI_VENDOR_ID_INTEL, 0x150f, NT , "Intel", "82580 Quad Gigabit Ethernet Controller (Fiber)"},
{PCI_VENDOR_ID_INTEL, 0x1510, NT , "Intel", "82580 Quad Gigabit Ethernet Controller (Backplane)"},
{PCI_VENDOR_ID_INTEL, 0x1511, NT , "Intel", "82580 Quad Gigabit Ethernet Controller (Ext. PHY)"},
{PCI_VENDOR_ID_INTEL, 0x1511, NT , "Intel", "82580 Dual Gigabit Ethernet Controller (Copper)"},
{PCI_VENDOR_ID_INTEL, UNPROG_DEVICE, OK, "Intel", "Unprogrammed 82580 Quad/Dual Gigabit Ethernet Controller"},
- {PCI_VENDOR_ID_INTEL, 0x1531, NT, "Intel", "I210 Gigabit Network Connection Unprogrammed"},
+ {PCI_VENDOR_ID_INTEL, 0x1531, OK, "Intel", "I210 Gigabit Network Connection Unprogrammed"},
{PCI_VENDOR_ID_INTEL, 0x1532, NT, "Intel", "I211 Gigabit Network Connection Unprogrammed"},
{PCI_VENDOR_ID_INTEL, 0x1533, OK, "Intel", "I210 Gigabit Network Connection"},
{PCI_VENDOR_ID_INTEL, 0x1536, NT, "Intel", "I210 Gigabit Network Connection SERDES Fiber"},
@@ -108,8 +115,8 @@ static int nicintel_ee_probe_i210(struct flashctx *flash)
/* Emulated eeprom has a fixed size of 4 KB */
flash->chip->total_size = 4;
flash->chip->page_size = flash->chip->total_size * 1024;
- flash->chip->tested = TEST_OK_PREW;
- flash->chip->gran = write_gran_1byte_implicit_erase;
+ flash->chip->tested = TEST_OK_PREWB;
+ flash->chip->gran = WRITE_GRAN_1BYTE_IMPLICIT_ERASE;
flash->chip->block_erasers->eraseblocks[0].size = flash->chip->page_size;
flash->chip->block_erasers->eraseblocks[0].count = 1;
@@ -118,10 +125,12 @@ static int nicintel_ee_probe_i210(struct flashctx *flash)
static int nicintel_ee_probe_82580(struct flashctx *flash)
{
- if (nicintel_pci->device_id == UNPROG_DEVICE)
+ const struct nicintel_eeprom_data *data = flash->mst->opaque.data;
+
+ if (data->nicintel_pci->device_id == UNPROG_DEVICE)
flash->chip->total_size = 16; /* Fall back to minimum supported size. */
else {
- uint32_t tmp = pci_mmio_readl(nicintel_eebar + EEC);
+ uint32_t tmp = pci_mmio_readl(data->nicintel_eebar + EEC);
tmp = ((tmp >> EE_SIZE) & EE_SIZE_MASK);
switch (tmp) {
case 7:
@@ -131,14 +140,14 @@ static int nicintel_ee_probe_82580(struct flashctx *flash)
flash->chip->total_size = 32;
break;
default:
- msg_cerr("Unsupported chip size 0x%x\n", tmp);
+ msg_cerr("Unsupported chip size 0x%"PRIx32"\n", tmp);
return 0;
}
}
flash->chip->page_size = EE_PAGE_MASK + 1;
- flash->chip->tested = TEST_OK_PREW;
- flash->chip->gran = write_gran_1byte_implicit_erase;
+ flash->chip->tested = TEST_OK_PREWB;
+ flash->chip->gran = WRITE_GRAN_1BYTE_IMPLICIT_ERASE;
flash->chip->block_erasers->eraseblocks[0].size = (EE_PAGE_MASK + 1);
flash->chip->block_erasers->eraseblocks[0].count = (flash->chip->total_size * 1024) / (EE_PAGE_MASK + 1);
@@ -146,15 +155,15 @@ static int nicintel_ee_probe_82580(struct flashctx *flash)
}
#define MAX_ATTEMPTS 10000000
-static int nicintel_ee_read_word(unsigned int addr, uint16_t *data)
+static int nicintel_ee_read_word(uint8_t *eebar, unsigned int addr, uint16_t *data)
{
uint32_t tmp = BIT(EERD_START) | (addr << EERD_ADDR);
- pci_mmio_writel(tmp, nicintel_eebar + EERD);
+ pci_mmio_writel(tmp, eebar + EERD);
/* Poll done flag. 10.000.000 cycles seem to be enough. */
uint32_t i;
for (i = 0; i < MAX_ATTEMPTS; i++) {
- tmp = pci_mmio_readl(nicintel_eebar + EERD);
+ tmp = pci_mmio_readl(eebar + EERD);
if (tmp & BIT(EERD_DONE)) {
*data = (tmp >> EERD_DATA) & 0xffff;
return 0;
@@ -166,12 +175,13 @@ static int nicintel_ee_read_word(unsigned int addr, uint16_t *data)
static int nicintel_ee_read(struct flashctx *flash, uint8_t *buf, unsigned int addr, unsigned int len)
{
+ const struct nicintel_eeprom_data *opaque_data = flash->mst->opaque.data;
uint16_t data;
/* The NIC interface always reads 16 b words so we need to convert the address and handle odd address
* explicitly at the start (and also at the end in the loop below). */
if (addr & 1) {
- if (nicintel_ee_read_word(addr / 2, &data))
+ if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data))
return -1;
*buf++ = data & 0xff;
addr++;
@@ -179,7 +189,7 @@ static int nicintel_ee_read(struct flashctx *flash, uint8_t *buf, unsigned int a
}
while (len > 0) {
- if (nicintel_ee_read_word(addr / 2, &data))
+ if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data))
return -1;
*buf++ = data & 0xff;
addr++;
@@ -194,19 +204,19 @@ static int nicintel_ee_read(struct flashctx *flash, uint8_t *buf, unsigned int a
return 0;
}
-static int nicintel_ee_write_word_i210(unsigned int addr, uint16_t data)
+static int nicintel_ee_write_word_i210(uint8_t *eebar, unsigned int addr, uint16_t data)
{
uint32_t eewr;
eewr = addr << EEWR_ADDR;
eewr |= data << EEWR_DATA;
eewr |= BIT(EEWR_CMDV);
- pci_mmio_writel(eewr, nicintel_eebar + EEWR);
+ pci_mmio_writel(eewr, eebar + EEWR);
- programmer_delay(5);
+ default_delay(5);
int i;
for (i = 0; i < MAX_ATTEMPTS; i++)
- if (pci_mmio_readl(nicintel_eebar + EEWR) & BIT(EEWR_DONE))
+ if (pci_mmio_readl(eebar + EEWR) & BIT(EEWR_DONE))
return 0;
return -1;
}
@@ -214,12 +224,13 @@ static int nicintel_ee_write_word_i210(unsigned int addr, uint16_t data)
static int nicintel_ee_write_i210(struct flashctx *flash, const uint8_t *buf,
unsigned int addr, unsigned int len)
{
- done_i20_write = true;
+ struct nicintel_eeprom_data *opaque_data = flash->mst->opaque.data;
+ opaque_data->done_i210_write = true;
if (addr & 1) {
uint16_t data;
- if (nicintel_ee_read_word(addr / 2, &data)) {
+ if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data)) {
msg_perr("Timeout reading heading byte\n");
return -1;
}
@@ -227,7 +238,7 @@ static int nicintel_ee_write_i210(struct flashctx *flash, const uint8_t *buf,
data &= 0xff;
data |= (buf ? (buf[0]) : 0xff) << 8;
- if (nicintel_ee_write_word_i210(addr / 2, data)) {
+ if (nicintel_ee_write_word_i210(opaque_data->nicintel_eebar, addr / 2, data)) {
msg_perr("Timeout writing heading word\n");
return -1;
}
@@ -242,7 +253,7 @@ static int nicintel_ee_write_i210(struct flashctx *flash, const uint8_t *buf,
uint16_t data;
if (len == 1) {
- if (nicintel_ee_read_word(addr / 2, &data)) {
+ if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data)) {
msg_perr("Timeout reading tail byte\n");
return -1;
}
@@ -256,7 +267,7 @@ static int nicintel_ee_write_i210(struct flashctx *flash, const uint8_t *buf,
data = 0xffff;
}
- if (nicintel_ee_write_word_i210(addr / 2, data)) {
+ if (nicintel_ee_write_word_i210(opaque_data->nicintel_eebar, addr / 2, data)) {
msg_perr("Timeout writing Shadow RAM\n");
return -1;
}
@@ -278,35 +289,35 @@ static int nicintel_ee_erase_i210(struct flashctx *flash, unsigned int addr, uns
return nicintel_ee_write_i210(flash, NULL, addr, len);
}
-static int nicintel_ee_bitset(int reg, int bit, bool val)
+static int nicintel_ee_bitset(uint8_t *eebar, int reg, int bit, bool val)
{
uint32_t tmp;
- tmp = pci_mmio_readl(nicintel_eebar + reg);
+ tmp = pci_mmio_readl(eebar + reg);
if (val)
tmp |= BIT(bit);
else
tmp &= ~BIT(bit);
- pci_mmio_writel(tmp, nicintel_eebar + reg);
+ pci_mmio_writel(tmp, eebar + reg);
return -1;
}
/* Shifts one byte out while receiving another one by bitbanging (denoted "direct access" in the datasheet). */
-static int nicintel_ee_bitbang(uint8_t mosi, uint8_t *miso)
+static int nicintel_ee_bitbang(uint8_t *eebar, uint8_t mosi, uint8_t *miso)
{
uint8_t out = 0x0;
int i;
for (i = 7; i >= 0; i--) {
- nicintel_ee_bitset(EEC, EE_SI, mosi & BIT(i));
- nicintel_ee_bitset(EEC, EE_SCK, 1);
+ nicintel_ee_bitset(eebar, EEC, EE_SI, mosi & BIT(i));
+ nicintel_ee_bitset(eebar, EEC, EE_SCK, 1);
if (miso != NULL) {
- uint32_t tmp = pci_mmio_readl(nicintel_eebar + EEC);
+ uint32_t tmp = pci_mmio_readl(eebar + EEC);
if (tmp & BIT(EE_SO))
out |= BIT(i);
}
- nicintel_ee_bitset(EEC, EE_SCK, 0);
+ nicintel_ee_bitset(eebar, EEC, EE_SCK, 0);
}
if (miso != NULL)
@@ -316,18 +327,18 @@ static int nicintel_ee_bitbang(uint8_t mosi, uint8_t *miso)
}
/* Polls the WIP bit of the status register of the attached EEPROM via bitbanging. */
-static int nicintel_ee_ready(void)
+static int nicintel_ee_ready(uint8_t *eebar)
{
unsigned int i;
for (i = 0; i < 1000; i++) {
- nicintel_ee_bitset(EEC, EE_CS, 0);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 0);
- nicintel_ee_bitbang(JEDEC_RDSR, NULL);
+ nicintel_ee_bitbang(eebar, JEDEC_RDSR, NULL);
uint8_t rdsr;
- nicintel_ee_bitbang(0x00, &rdsr);
+ nicintel_ee_bitbang(eebar, 0x00, &rdsr);
- nicintel_ee_bitset(EEC, EE_CS, 1);
- programmer_delay(1);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 1);
+ default_delay(1);
if (!(rdsr & SPI_SR_WIP)) {
return 0;
}
@@ -336,57 +347,60 @@ static int nicintel_ee_ready(void)
}
/* Requests direct access to the SPI pins. */
-static int nicintel_ee_req(void)
+static int nicintel_ee_req(uint8_t *eebar)
{
uint32_t tmp;
- nicintel_ee_bitset(EEC, EE_REQ, 1);
+ nicintel_ee_bitset(eebar, EEC, EE_REQ, 1);
- tmp = pci_mmio_readl(nicintel_eebar + EEC);
+ tmp = pci_mmio_readl(eebar + EEC);
if (!(tmp & BIT(EE_GNT))) {
msg_perr("Enabling eeprom access failed.\n");
return 1;
}
- nicintel_ee_bitset(EEC, EE_SCK, 0);
+ nicintel_ee_bitset(eebar, EEC, EE_SCK, 0);
return 0;
}
static int nicintel_ee_write_82580(struct flashctx *flash, const uint8_t *buf, unsigned int addr, unsigned int len)
{
- if (nicintel_ee_req())
+ const struct nicintel_eeprom_data *opaque_data = flash->mst->opaque.data;
+ uint8_t *eebar = opaque_data->nicintel_eebar;
+
+ if (nicintel_ee_req(eebar))
return -1;
int ret = -1;
- if (nicintel_ee_ready())
+ if (nicintel_ee_ready(eebar))
goto out;
while (len > 0) {
/* WREN */
- nicintel_ee_bitset(EEC, EE_CS, 0);
- nicintel_ee_bitbang(JEDEC_WREN, NULL);
- nicintel_ee_bitset(EEC, EE_CS, 1);
- programmer_delay(1);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 0);
+ nicintel_ee_bitbang(eebar, JEDEC_WREN, NULL);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 1);
+ default_delay(1);
/* data */
- nicintel_ee_bitset(EEC, EE_CS, 0);
- nicintel_ee_bitbang(JEDEC_BYTE_PROGRAM, NULL);
- nicintel_ee_bitbang((addr >> 8) & 0xff, NULL);
- nicintel_ee_bitbang(addr & 0xff, NULL);
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 0);
+ nicintel_ee_bitbang(eebar, JEDEC_BYTE_PROGRAM, NULL);
+ nicintel_ee_bitbang(eebar, (addr >> 8) & 0xff, NULL);
+ nicintel_ee_bitbang(eebar, addr & 0xff, NULL);
while (len > 0) {
- nicintel_ee_bitbang((buf) ? *buf++ : 0xff, NULL);
+ nicintel_ee_bitbang(eebar, (buf) ? *buf++ : 0xff, NULL);
len--;
addr++;
if (!(addr & EE_PAGE_MASK))
break;
}
- nicintel_ee_bitset(EEC, EE_CS, 1);
- programmer_delay(1);
- if (nicintel_ee_ready())
+ nicintel_ee_bitset(eebar, EEC, EE_CS, 1);
+ default_delay(1);
+ if (nicintel_ee_ready(eebar))
goto out;
}
ret = 0;
out:
- nicintel_ee_bitset(EEC, EE_REQ, 0); /* Give up direct access. */
+ nicintel_ee_bitset(eebar, EEC, EE_REQ, 0); /* Give up direct access. */
return ret;
}
@@ -395,64 +409,83 @@ static int nicintel_ee_erase_82580(struct flashctx *flash, unsigned int addr, un
return nicintel_ee_write_82580(flash, NULL, addr, len);
}
-static const struct opaque_master opaque_master_nicintel_ee_82580 = {
- .probe = nicintel_ee_probe_82580,
- .read = nicintel_ee_read,
- .write = nicintel_ee_write_82580,
- .erase = nicintel_ee_erase_82580,
-};
-
-static const struct opaque_master opaque_master_nicintel_ee_i210 = {
- .probe = nicintel_ee_probe_i210,
- .read = nicintel_ee_read,
- .write = nicintel_ee_write_i210,
- .erase = nicintel_ee_erase_i210,
-};
-
-static int nicintel_ee_shutdown_i210(void *arg)
+static int nicintel_ee_shutdown_i210(void *opaque_data)
{
- if (!done_i20_write)
- return 0;
+ struct nicintel_eeprom_data *data = opaque_data;
+ int ret = 0;
- uint32_t flup = pci_mmio_readl(nicintel_eebar + EEC);
+ if (!data->done_i210_write)
+ goto out;
+
+ uint32_t flup = pci_mmio_readl(data->nicintel_eebar + EEC);
flup |= BIT(EE_FLUPD);
- pci_mmio_writel(flup, nicintel_eebar + EEC);
+ pci_mmio_writel(flup, data->nicintel_eebar + EEC);
int i;
for (i = 0; i < MAX_ATTEMPTS; i++)
- if (pci_mmio_readl(nicintel_eebar + EEC) & BIT(EE_FLUDONE))
- return 0;
+ if (pci_mmio_readl(data->nicintel_eebar + EEC) & BIT(EE_FLUDONE))
+ goto out;
+ ret = -1;
msg_perr("Flash update failed\n");
- return -1;
+out:
+ free(data);
+ return ret;
}
-static int nicintel_ee_shutdown_82580(void *eecp)
+static int nicintel_ee_shutdown_82580(void *opaque_data)
{
- uint32_t old_eec = *(uint32_t *)eecp;
- /* Request bitbanging and unselect the chip first to be safe. */
- if (nicintel_ee_req() || nicintel_ee_bitset(EEC, EE_CS, 1))
- return -1;
+ struct nicintel_eeprom_data *data = opaque_data;
+ uint8_t *eebar = data->nicintel_eebar;
+ int ret = 0;
+
+ if (data->nicintel_pci->device_id != UNPROG_DEVICE) {
+ uint32_t old_eec = data->eec;
+ /* Request bitbanging and unselect the chip first to be safe. */
+ if (nicintel_ee_req(eebar) || nicintel_ee_bitset(eebar, EEC, EE_CS, 1)) {
+ ret = -1;
+ goto out;
+ }
- /* Try to restore individual bits we care about. */
- int ret = nicintel_ee_bitset(EEC, EE_SCK, old_eec & BIT(EE_SCK));
- ret |= nicintel_ee_bitset(EEC, EE_SI, old_eec & BIT(EE_SI));
- ret |= nicintel_ee_bitset(EEC, EE_CS, old_eec & BIT(EE_CS));
- /* REQ will be cleared by hardware anyway after 2 seconds of inactivity on the SPI pins (3.3.2.1). */
- ret |= nicintel_ee_bitset(EEC, EE_REQ, old_eec & BIT(EE_REQ));
+ /* Try to restore individual bits we care about. */
+ ret = nicintel_ee_bitset(eebar, EEC, EE_SCK, old_eec & BIT(EE_SCK));
+ ret |= nicintel_ee_bitset(eebar, EEC, EE_SI, old_eec & BIT(EE_SI));
+ ret |= nicintel_ee_bitset(eebar, EEC, EE_CS, old_eec & BIT(EE_CS));
+ /* REQ will be cleared by hardware anyway after 2 seconds of inactivity
+ * on the SPI pins (3.3.2.1). */
+ ret |= nicintel_ee_bitset(eebar, EEC, EE_REQ, old_eec & BIT(EE_REQ));
+ }
- free(eecp);
+out:
+ free(data);
return ret;
}
-int nicintel_ee_init(void)
+static const struct opaque_master opaque_master_nicintel_ee_82580 = {
+ .probe = nicintel_ee_probe_82580,
+ .read = nicintel_ee_read,
+ .write = nicintel_ee_write_82580,
+ .erase = nicintel_ee_erase_82580,
+ .shutdown = nicintel_ee_shutdown_82580,
+};
+
+static const struct opaque_master opaque_master_nicintel_ee_i210 = {
+ .probe = nicintel_ee_probe_i210,
+ .read = nicintel_ee_read,
+ .write = nicintel_ee_write_i210,
+ .erase = nicintel_ee_erase_i210,
+ .shutdown = nicintel_ee_shutdown_i210,
+};
+
+static int nicintel_ee_init(const struct programmer_cfg *cfg)
{
- if (rget_io_perms())
- return 1;
+ const struct opaque_master *mst;
+ uint32_t eec = 0;
+ uint8_t *eebar;
- struct pci_dev *dev = pcidev_init(nics_intel_ee, PCI_BASE_ADDRESS_0);
+ struct pci_dev *dev = pcidev_init(cfg, nics_intel_ee, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -461,13 +494,12 @@ int nicintel_ee_init(void)
return 1;
if (!is_i210(dev->device_id)) {
- nicintel_eebar = rphysmap("Intel Gigabit NIC w/ SPI EEPROM", io_base_addr, MEMMAP_SIZE);
- if (!nicintel_eebar)
+ eebar = rphysmap("Intel Gigabit NIC w/ SPI EEPROM", io_base_addr, MEMMAP_SIZE);
+ if (!eebar)
return 1;
- nicintel_pci = dev;
- if ((dev->device_id != UNPROG_DEVICE)) {
- uint32_t eec = pci_mmio_readl(nicintel_eebar + EEC);
+ if (dev->device_id != UNPROG_DEVICE) {
+ eec = pci_mmio_readl(eebar + EEC);
/* C.f. 3.3.1.5 for the detection mechanism (maybe? contradicting
the EE_PRES definition),
@@ -476,28 +508,34 @@ int nicintel_ee_init(void)
msg_perr("Controller reports no EEPROM is present.\n");
return 1;
}
-
- uint32_t *eecp = malloc(sizeof(uint32_t));
- if (eecp == NULL)
- return 1;
- *eecp = eec;
-
- if (register_shutdown(nicintel_ee_shutdown_82580, eecp))
- return 1;
}
- return register_opaque_master(&opaque_master_nicintel_ee_82580);
+ mst = &opaque_master_nicintel_ee_82580;
} else {
- nicintel_eebar = rphysmap("Intel i210 NIC w/ emulated EEPROM",
+ eebar = rphysmap("Intel i210 NIC w/ emulated EEPROM",
io_base_addr + 0x12000, MEMMAP_SIZE);
- if (!nicintel_eebar)
+ if (!eebar)
return 1;
- if (register_shutdown(nicintel_ee_shutdown_i210, NULL))
- return 1;
+ mst = &opaque_master_nicintel_ee_i210;
+ }
- return register_opaque_master(&opaque_master_nicintel_ee_i210);
+ struct nicintel_eeprom_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for OPAQUE master data\n");
+ return 1;
}
+ data->nicintel_pci = dev;
+ data->nicintel_eebar = eebar;
+ data->eec = eec;
+ data->done_i210_write = false;
- return 1;
+ return register_opaque_master(mst, data);
}
+
+const struct programmer_entry programmer_nicintel_eeprom = {
+ .name = "nicintel_eeprom",
+ .type = PCI,
+ .devs.dev = nics_intel_ee,
+ .init = nicintel_ee_init,
+};
diff --git a/nicintel_spi.c b/nicintel_spi.c
index 1173ef772..2821d23a0 100644
--- a/nicintel_spi.c
+++ b/nicintel_spi.c
@@ -34,7 +34,8 @@
#include <unistd.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_INTEL 0x8086
#define MEMMAP_SIZE getpagesize()
@@ -73,11 +74,11 @@
// #define FL_BUSY 30
// #define FL_ER 31
-#define BIT(x) (1<<(x))
-
-static uint8_t *nicintel_spibar;
+struct nicintel_spi_data {
+ uint8_t *spibar;
+};
-const struct dev_entry nics_intel_spi[] = {
+static const struct dev_entry nics_intel_spi[] = {
{PCI_VENDOR_ID_INTEL, 0x105e, OK, "Intel", "82571EB Gigabit Ethernet Controller"},
{PCI_VENDOR_ID_INTEL, 0x1076, OK, "Intel", "82541GI Gigabit Ethernet Controller"},
{PCI_VENDOR_ID_INTEL, 0x107c, OK, "Intel", "82541PI Gigabit Ethernet Controller"},
@@ -107,90 +108,125 @@ const struct dev_entry nics_intel_spi[] = {
{0},
};
-static void nicintel_request_spibus(void)
+static void nicintel_request_spibus(void *spi_data)
{
+ struct nicintel_spi_data *data = spi_data;
uint32_t tmp;
- tmp = pci_mmio_readl(nicintel_spibar + FLA);
+ tmp = pci_mmio_readl(data->spibar + FLA);
tmp |= BIT(FL_REQ);
- pci_mmio_writel(tmp, nicintel_spibar + FLA);
+ pci_mmio_writel(tmp, data->spibar + FLA);
/* Wait until we are allowed to use the SPI bus. */
- while (!(pci_mmio_readl(nicintel_spibar + FLA) & BIT(FL_GNT))) ;
+ while (!(pci_mmio_readl(data->spibar + FLA) & BIT(FL_GNT))) ;
}
-static void nicintel_release_spibus(void)
+static void nicintel_release_spibus(void *spi_data)
{
+ struct nicintel_spi_data *data = spi_data;
uint32_t tmp;
- tmp = pci_mmio_readl(nicintel_spibar + FLA);
+ tmp = pci_mmio_readl(data->spibar + FLA);
tmp &= ~BIT(FL_REQ);
- pci_mmio_writel(tmp, nicintel_spibar + FLA);
+ pci_mmio_writel(tmp, data->spibar + FLA);
}
-static void nicintel_bitbang_set_cs(int val)
+static void nicintel_bitbang_set_cs(int val, void *spi_data)
{
+ struct nicintel_spi_data *data = spi_data;
uint32_t tmp;
- tmp = pci_mmio_readl(nicintel_spibar + FLA);
+ tmp = pci_mmio_readl(data->spibar + FLA);
tmp &= ~BIT(FL_CS);
tmp |= (val << FL_CS);
- pci_mmio_writel(tmp, nicintel_spibar + FLA);
+ pci_mmio_writel(tmp, data->spibar + FLA);
}
-static void nicintel_bitbang_set_sck(int val)
+static void nicintel_bitbang_set_sck(int val, void *spi_data)
{
+ struct nicintel_spi_data *data = spi_data;
uint32_t tmp;
- tmp = pci_mmio_readl(nicintel_spibar + FLA);
+ tmp = pci_mmio_readl(data->spibar + FLA);
tmp &= ~BIT(FL_SCK);
tmp |= (val << FL_SCK);
- pci_mmio_writel(tmp, nicintel_spibar + FLA);
+ pci_mmio_writel(tmp, data->spibar + FLA);
}
-static void nicintel_bitbang_set_mosi(int val)
+static void nicintel_bitbang_set_mosi(int val, void *spi_data)
{
+ struct nicintel_spi_data *data = spi_data;
uint32_t tmp;
- tmp = pci_mmio_readl(nicintel_spibar + FLA);
+ tmp = pci_mmio_readl(data->spibar + FLA);
tmp &= ~BIT(FL_SI);
tmp |= (val << FL_SI);
- pci_mmio_writel(tmp, nicintel_spibar + FLA);
+ pci_mmio_writel(tmp, data->spibar + FLA);
}
-static int nicintel_bitbang_get_miso(void)
+static void nicintel_bitbang_set_sck_set_mosi(int sck, int mosi, void *spi_data)
{
+ struct nicintel_spi_data *data = spi_data;
uint32_t tmp;
- tmp = pci_mmio_readl(nicintel_spibar + FLA);
+ tmp = pci_mmio_readl(data->spibar + FLA);
+ tmp &= ~BIT(FL_SCK);
+ tmp &= ~BIT(FL_SI);
+ tmp |= (sck << FL_SCK);
+ tmp |= (mosi << FL_SI);
+ pci_mmio_writel(tmp, data->spibar + FLA);
+}
+
+static int nicintel_bitbang_get_miso(void *spi_data)
+{
+ struct nicintel_spi_data *data = spi_data;
+ uint32_t tmp;
+
+ tmp = pci_mmio_readl(data->spibar + FLA);
tmp = (tmp >> FL_SO) & 0x1;
return tmp;
}
+static int nicintel_bitbang_set_sck_get_miso(int sck, void *spi_data)
+{
+ struct nicintel_spi_data *data = spi_data;
+ uint32_t tmp;
+
+ tmp = pci_mmio_readl(data->spibar + FLA);
+ tmp &= ~BIT(FL_SCK);
+ tmp |= (sck << FL_SCK);
+ pci_mmio_writel(tmp, data->spibar + FLA);
+ return (tmp >> FL_SO) & 0x1;
+}
+
static const struct bitbang_spi_master bitbang_spi_master_nicintel = {
- .set_cs = nicintel_bitbang_set_cs,
- .set_sck = nicintel_bitbang_set_sck,
- .set_mosi = nicintel_bitbang_set_mosi,
- .get_miso = nicintel_bitbang_get_miso,
- .request_bus = nicintel_request_spibus,
- .release_bus = nicintel_release_spibus,
- .half_period = 1,
+ .set_cs = nicintel_bitbang_set_cs,
+ .set_sck = nicintel_bitbang_set_sck,
+ .set_mosi = nicintel_bitbang_set_mosi,
+ .set_sck_set_mosi = nicintel_bitbang_set_sck_set_mosi,
+ .set_sck_get_miso = nicintel_bitbang_set_sck_get_miso,
+ .get_miso = nicintel_bitbang_get_miso,
+ .request_bus = nicintel_request_spibus,
+ .release_bus = nicintel_release_spibus,
+ .half_period = 1,
};
-static int nicintel_spi_shutdown(void *data)
+static int nicintel_spi_shutdown(void *spi_data)
{
+ struct nicintel_spi_data *data = spi_data;
uint32_t tmp;
/* Disable writes manually. See the comment about EECD in nicintel_spi_init() for details. */
- tmp = pci_mmio_readl(nicintel_spibar + EECD);
+ tmp = pci_mmio_readl(data->spibar + EECD);
tmp &= ~FLASH_WRITES_ENABLED;
tmp |= FLASH_WRITES_DISABLED;
- pci_mmio_writel(tmp, nicintel_spibar + EECD);
+ pci_mmio_writel(tmp, data->spibar + EECD);
+ free(data);
return 0;
}
-static int nicintel_spi_82599_enable_flash(void)
+static int nicintel_spi_82599_enable_flash(struct nicintel_spi_data *data)
{
uint32_t tmp;
@@ -199,56 +235,61 @@ static int nicintel_spi_82599_enable_flash(void)
* but other bits with side effects as well. Those other bits must be
* left untouched.
*/
- tmp = pci_mmio_readl(nicintel_spibar + EECD);
+ tmp = pci_mmio_readl(data->spibar + EECD);
tmp &= ~FLASH_WRITES_DISABLED;
tmp |= FLASH_WRITES_ENABLED;
- pci_mmio_writel(tmp, nicintel_spibar + EECD);
+ pci_mmio_writel(tmp, data->spibar + EECD);
/* test if FWE is really set to allow writes */
- tmp = pci_mmio_readl(nicintel_spibar + EECD);
+ tmp = pci_mmio_readl(data->spibar + EECD);
if ( (tmp & FLASH_WRITES_DISABLED) || !(tmp & FLASH_WRITES_ENABLED) ) {
msg_perr("Enabling flash write access failed.\n");
return 1;
}
- if (register_shutdown(nicintel_spi_shutdown, NULL))
+ if (register_shutdown(nicintel_spi_shutdown, data))
return 1;
return 0;
}
-static int nicintel_spi_i210_enable_flash(void)
+static int nicintel_spi_i210_shutdown(void *data)
+{
+ free(data);
+ return 0;
+}
+
+static int nicintel_spi_i210_enable_flash(struct nicintel_spi_data *data)
{
uint32_t tmp;
- tmp = pci_mmio_readl(nicintel_spibar + FLA);
+ tmp = pci_mmio_readl(data->spibar + FLA);
if (tmp & BIT(FL_LOCKED)) {
msg_perr("Flash is in Secure Mode. Abort.\n");
return 1;
}
- if (!(tmp & BIT(FL_ABORT)))
- return 0;
+ if (tmp & BIT(FL_ABORT)) {
+ tmp |= BIT(FL_CLR_ERR);
+ pci_mmio_writel(tmp, data->spibar + FLA);
+ tmp = pci_mmio_readl(data->spibar + FLA);
+ if (!(tmp & BIT(FL_ABORT))) {
+ msg_perr("Unable to clear Flash Access Error. Abort\n");
+ return 1;
+ }
+ }
- tmp |= BIT(FL_CLR_ERR);
- pci_mmio_writel(tmp, nicintel_spibar + FLA);
- tmp = pci_mmio_readl(nicintel_spibar + FLA);
- if (!(tmp & BIT(FL_ABORT))) {
- msg_perr("Unable to clear Flash Access Error. Abort\n");
+ if (register_shutdown(nicintel_spi_i210_shutdown, data))
return 1;
- }
return 0;
}
-int nicintel_spi_init(void)
+static int nicintel_spi_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
- if (rget_io_perms())
- return 1;
-
- dev = pcidev_init(nics_intel_spi, PCI_BASE_ADDRESS_0);
+ dev = pcidev_init(cfg, nics_intel_spi, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -256,25 +297,44 @@ int nicintel_spi_init(void)
if (!io_base_addr)
return 1;
+ struct nicintel_spi_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ return 1;
+ }
+
if ((dev->device_id & 0xfff0) == 0x1530) {
- nicintel_spibar = rphysmap("Intel I210 Gigabit w/ SPI flash", io_base_addr + 0x12000,
+ data->spibar = rphysmap("Intel I210 Gigabit w/ SPI flash", io_base_addr + 0x12000,
MEMMAP_SIZE);
- if (!nicintel_spibar || nicintel_spi_i210_enable_flash())
+ if (!data->spibar || nicintel_spi_i210_enable_flash(data)) {
+ free(data);
return 1;
+ }
} else if (dev->device_id < 0x10d8) {
- nicintel_spibar = rphysmap("Intel Gigabit NIC w/ SPI flash", io_base_addr,
+ data->spibar = rphysmap("Intel Gigabit NIC w/ SPI flash", io_base_addr,
MEMMAP_SIZE);
- if (!nicintel_spibar || nicintel_spi_82599_enable_flash())
+ if (!data->spibar || nicintel_spi_82599_enable_flash(data)) {
+ free(data);
return 1;
+ }
} else {
- nicintel_spibar = rphysmap("Intel 10 Gigabit NIC w/ SPI flash", io_base_addr + 0x10000,
+ data->spibar = rphysmap("Intel 10 Gigabit NIC w/ SPI flash", io_base_addr + 0x10000,
MEMMAP_SIZE);
- if (!nicintel_spibar || nicintel_spi_82599_enable_flash())
+ if (!data->spibar || nicintel_spi_82599_enable_flash(data)) {
+ free(data);
return 1;
+ }
}
- if (register_spi_bitbang_master(&bitbang_spi_master_nicintel))
- return 1;
+ if (register_spi_bitbang_master(&bitbang_spi_master_nicintel, data))
+ return 1; /* shutdown function does cleanup */
return 0;
}
+
+const struct programmer_entry programmer_nicintel_spi = {
+ .name = "nicintel_spi",
+ .type = PCI,
+ .devs.dev = nics_intel_spi,
+ .init = nicintel_spi_init,
+};
diff --git a/nicnatsemi.c b/nicnatsemi.c
index 085768d66..65377dc6f 100644
--- a/nicnatsemi.c
+++ b/nicnatsemi.c
@@ -14,20 +14,22 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_x86_io.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_NATSEMI 0x100b
#define BOOT_ROM_ADDR 0x50
#define BOOT_ROM_DATA 0x54
-static uint32_t io_base_addr = 0;
-const struct dev_entry nics_natsemi[] = {
+struct nicnatsemi_data {
+ uint32_t io_base_addr;
+};
+
+static const struct dev_entry nics_natsemi[] = {
{0x100b, 0x0020, NT, "National Semiconductor", "DP83815/DP83816"},
{0x100b, 0x0022, NT, "National Semiconductor", "DP83820"},
@@ -35,28 +37,60 @@ const struct dev_entry nics_natsemi[] = {
};
static void nicnatsemi_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr);
+ chipaddr addr)
+{
+ const struct nicnatsemi_data *data = flash->mst->par.data;
+
+ OUTL((uint32_t)addr & 0x0001FFFF, data->io_base_addr + BOOT_ROM_ADDR);
+ /*
+ * The datasheet requires 32 bit accesses to this register, but it seems
+ * that requirement might only apply if the register is memory mapped.
+ * Bits 8-31 of this register are apparently don't care, and if this
+ * register is I/O port mapped, 8 bit accesses to the lowest byte of the
+ * register seem to work fine. Due to that, we ignore the advice in the
+ * data sheet.
+ */
+ OUTB(val, data->io_base_addr + BOOT_ROM_DATA);
+}
+
static uint8_t nicnatsemi_chip_readb(const struct flashctx *flash,
- const chipaddr addr);
+ const chipaddr addr)
+{
+ const struct nicnatsemi_data *data = flash->mst->par.data;
+
+ OUTL(((uint32_t)addr & 0x0001FFFF), data->io_base_addr + BOOT_ROM_ADDR);
+ /*
+ * The datasheet requires 32 bit accesses to this register, but it seems
+ * that requirement might only apply if the register is memory mapped.
+ * Bits 8-31 of this register are apparently don't care, and if this
+ * register is I/O port mapped, 8 bit accesses to the lowest byte of the
+ * register seem to work fine. Due to that, we ignore the advice in the
+ * data sheet.
+ */
+ return INB(data->io_base_addr + BOOT_ROM_DATA);
+}
+
+static int nicnatsemi_shutdown(void *par_data)
+{
+ free(par_data);
+ return 0;
+}
+
static const struct par_master par_master_nicnatsemi = {
- .chip_readb = nicnatsemi_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = nicnatsemi_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
+ .chip_readb = nicnatsemi_chip_readb,
+ .chip_writeb = nicnatsemi_chip_writeb,
+ .shutdown = nicnatsemi_shutdown,
};
-int nicnatsemi_init(void)
+static int nicnatsemi_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
+ uint32_t io_base_addr;
if (rget_io_perms())
return 1;
- dev = pcidev_init(nics_natsemi, PCI_BASE_ADDRESS_0);
+ dev = pcidev_init(cfg, nics_natsemi, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -64,6 +98,13 @@ int nicnatsemi_init(void)
if (!io_base_addr)
return 1;
+ struct nicnatsemi_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
+ return 1;
+ }
+ data->io_base_addr = io_base_addr;
+
/* The datasheet shows address lines MA0-MA16 in one place and MA0-MA15
* in another. My NIC has MA16 connected to A16 on the boot ROM socket
* so I'm assuming it is accessible. If not then next line wants to be
@@ -71,41 +112,13 @@ int nicnatsemi_init(void)
* functions below wants to be 0x0000FFFF.
*/
max_rom_decode.parallel = 131072;
- register_par_master(&par_master_nicnatsemi, BUS_PARALLEL);
-
- return 0;
+ return register_par_master(&par_master_nicnatsemi, BUS_PARALLEL, data);
}
-static void nicnatsemi_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- OUTL((uint32_t)addr & 0x0001FFFF, io_base_addr + BOOT_ROM_ADDR);
- /*
- * The datasheet requires 32 bit accesses to this register, but it seems
- * that requirement might only apply if the register is memory mapped.
- * Bits 8-31 of this register are apparently don't care, and if this
- * register is I/O port mapped, 8 bit accesses to the lowest byte of the
- * register seem to work fine. Due to that, we ignore the advice in the
- * data sheet.
- */
- OUTB(val, io_base_addr + BOOT_ROM_DATA);
-}
-static uint8_t nicnatsemi_chip_readb(const struct flashctx *flash,
- const chipaddr addr)
-{
- OUTL(((uint32_t)addr & 0x0001FFFF), io_base_addr + BOOT_ROM_ADDR);
- /*
- * The datasheet requires 32 bit accesses to this register, but it seems
- * that requirement might only apply if the register is memory mapped.
- * Bits 8-31 of this register are apparently don't care, and if this
- * register is I/O port mapped, 8 bit accesses to the lowest byte of the
- * register seem to work fine. Due to that, we ignore the advice in the
- * data sheet.
- */
- return INB(io_base_addr + BOOT_ROM_DATA);
-}
-
-#else
-#error PCI port I/O access is not supported on this architecture yet.
-#endif
+const struct programmer_entry programmer_nicnatsemi = {
+ .name = "nicnatsemi",
+ .type = PCI,
+ .devs.dev = nics_natsemi,
+ .init = nicnatsemi_init,
+};
diff --git a/nicrealtek.c b/nicrealtek.c
index 5454b63af..5937e35ba 100644
--- a/nicrealtek.c
+++ b/nicrealtek.c
@@ -14,20 +14,22 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_x86_io.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_REALTEK 0x10ec
#define PCI_VENDOR_ID_SMC1211 0x1113
-static uint32_t io_base_addr = 0;
-static int bios_rom_addr, bios_rom_data;
+struct nicrealtek_data {
+ uint32_t io_base_addr;
+ int bios_rom_addr;
+ int bios_rom_data;
+};
-const struct dev_entry nics_realtek[] = {
+static const struct dev_entry nics_realtek[] = {
{0x10ec, 0x8139, OK, "Realtek", "RTL8139/8139C/8139C+"},
{0x10ec, 0x8169, NT, "Realtek", "RTL8169"},
{0x1113, 0x1211, OK, "SMC", "1211TX"}, /* RTL8139 clone */
@@ -35,33 +37,71 @@ const struct dev_entry nics_realtek[] = {
{0},
};
-static void nicrealtek_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
-static uint8_t nicrealtek_chip_readb(const struct flashctx *flash, const chipaddr addr);
-static const struct par_master par_master_nicrealtek = {
- .chip_readb = nicrealtek_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = nicrealtek_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
-};
+static void nicrealtek_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
+{
+ struct nicrealtek_data *data = flash->mst->par.data;
+
+ /* Output addr and data, set WE to 0, set OE to 1, set CS to 0,
+ * enable software access.
+ */
+ OUTL(((uint32_t)addr & 0x01FFFF) | 0x0A0000 | (val << 24),
+ data->io_base_addr + data->bios_rom_addr);
+ /* Output addr and data, set WE to 1, set OE to 1, set CS to 1,
+ * enable software access.
+ */
+ OUTL(((uint32_t)addr & 0x01FFFF) | 0x1E0000 | (val << 24),
+ data->io_base_addr + data->bios_rom_addr);
+}
+
+static uint8_t nicrealtek_chip_readb(const struct flashctx *flash, const chipaddr addr)
+{
+ struct nicrealtek_data *data = flash->mst->par.data;
+ uint8_t val;
+
+ /* FIXME: Can we skip reading the old data and simply use 0? */
+ /* Read old data. */
+ val = INB(data->io_base_addr + data->bios_rom_data);
+ /* Output new addr and old data, set WE to 1, set OE to 0, set CS to 0,
+ * enable software access.
+ */
+ OUTL(((uint32_t)addr & 0x01FFFF) | 0x060000 | (val << 24),
+ data->io_base_addr + data->bios_rom_addr);
+
+ /* Read new data. */
+ val = INB(data->io_base_addr + data->bios_rom_data);
+ /* Output addr and new data, set WE to 1, set OE to 1, set CS to 1,
+ * enable software access.
+ */
+ OUTL(((uint32_t)addr & 0x01FFFF) | 0x1E0000 | (val << 24),
+ data->io_base_addr + data->bios_rom_addr);
+
+ return val;
+}
static int nicrealtek_shutdown(void *data)
{
/* FIXME: We forgot to disable software access again. */
+ free(data);
return 0;
}
-int nicrealtek_init(void)
+static const struct par_master par_master_nicrealtek = {
+ .chip_readb = nicrealtek_chip_readb,
+ .chip_writeb = nicrealtek_chip_writeb,
+ .shutdown = nicrealtek_shutdown,
+};
+
+static int nicrealtek_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
+ uint32_t io_base_addr = 0;
+ int bios_rom_addr;
+ int bios_rom_data;
if (rget_io_perms())
return 1;
- dev = pcidev_init(nics_realtek, PCI_BASE_ADDRESS_0);
+ dev = pcidev_init(cfg, nics_realtek, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -83,52 +123,21 @@ int nicrealtek_init(void)
break;
}
- if (register_shutdown(nicrealtek_shutdown, NULL))
+ struct nicrealtek_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
return 1;
+ }
+ data->io_base_addr = io_base_addr;
+ data->bios_rom_addr = bios_rom_addr;
+ data->bios_rom_data = bios_rom_data;
- register_par_master(&par_master_nicrealtek, BUS_PARALLEL);
-
- return 0;
-}
-
-static void nicrealtek_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
-{
- /* Output addr and data, set WE to 0, set OE to 1, set CS to 0,
- * enable software access.
- */
- OUTL(((uint32_t)addr & 0x01FFFF) | 0x0A0000 | (val << 24),
- io_base_addr + bios_rom_addr);
- /* Output addr and data, set WE to 1, set OE to 1, set CS to 1,
- * enable software access.
- */
- OUTL(((uint32_t)addr & 0x01FFFF) | 0x1E0000 | (val << 24),
- io_base_addr + bios_rom_addr);
-}
-
-static uint8_t nicrealtek_chip_readb(const struct flashctx *flash, const chipaddr addr)
-{
- uint8_t val;
-
- /* FIXME: Can we skip reading the old data and simply use 0? */
- /* Read old data. */
- val = INB(io_base_addr + bios_rom_data);
- /* Output new addr and old data, set WE to 1, set OE to 0, set CS to 0,
- * enable software access.
- */
- OUTL(((uint32_t)addr & 0x01FFFF) | 0x060000 | (val << 24),
- io_base_addr + bios_rom_addr);
-
- /* Read new data. */
- val = INB(io_base_addr + bios_rom_data);
- /* Output addr and new data, set WE to 1, set OE to 1, set CS to 1,
- * enable software access.
- */
- OUTL(((uint32_t)addr & 0x01FFFF) | 0x1E0000 | (val << 24),
- io_base_addr + bios_rom_addr);
-
- return val;
+ return register_par_master(&par_master_nicrealtek, BUS_PARALLEL, data);
}
-#else
-#error PCI port I/O access is not supported on this architecture yet.
-#endif
+const struct programmer_entry programmer_nicrealtek = {
+ .name = "nicrealtek",
+ .type = PCI,
+ .devs.dev = nics_realtek,
+ .init = nicrealtek_init,
+};
diff --git a/ogp_spi.c b/ogp_spi.c
index e603edb8b..d85c82306 100644
--- a/ogp_spi.c
+++ b/ogp_spi.c
@@ -18,7 +18,8 @@
#include <string.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_OGP 0x1227
@@ -36,68 +37,87 @@
#define OGA1_XP10_CPROM_SCK 0x0058 /* W */
#define OGA1_XP10_CPROM_REG_SEL 0x005C /* W */
-static uint8_t *ogp_spibar;
+struct ogp_spi_data {
+ uint8_t *spibar;
-static uint32_t ogp_reg_sel;
-static uint32_t ogp_reg_siso;
-static uint32_t ogp_reg__ce;
-static uint32_t ogp_reg_sck;
+ uint32_t reg_sel;
+ uint32_t reg_siso;
+ uint32_t reg__ce;
+ uint32_t reg_sck;
+};
-const struct dev_entry ogp_spi[] = {
+static const struct dev_entry ogp_spi[] = {
{PCI_VENDOR_ID_OGP, 0x0000, OK, "Open Graphics Project", "Development Board OGD1"},
{0},
};
-static void ogp_request_spibus(void)
+static void ogp_request_spibus(void *spi_data)
{
- pci_mmio_writel(1, ogp_spibar + ogp_reg_sel);
+ struct ogp_spi_data *data = spi_data;
+ pci_mmio_writel(1, data->spibar + data->reg_sel);
}
-static void ogp_release_spibus(void)
+static void ogp_release_spibus(void *spi_data)
{
- pci_mmio_writel(0, ogp_spibar + ogp_reg_sel);
+ struct ogp_spi_data *data = spi_data;
+ pci_mmio_writel(0, data->spibar + data->reg_sel);
}
-static void ogp_bitbang_set_cs(int val)
+static void ogp_bitbang_set_cs(int val, void *spi_data)
{
- pci_mmio_writel(val, ogp_spibar + ogp_reg__ce);
+ struct ogp_spi_data *data = spi_data;
+ pci_mmio_writel(val, data->spibar + data->reg__ce);
}
-static void ogp_bitbang_set_sck(int val)
+static void ogp_bitbang_set_sck(int val, void *spi_data)
{
- pci_mmio_writel(val, ogp_spibar + ogp_reg_sck);
+ struct ogp_spi_data *data = spi_data;
+ pci_mmio_writel(val, data->spibar + data->reg_sck);
}
-static void ogp_bitbang_set_mosi(int val)
+static void ogp_bitbang_set_mosi(int val, void *spi_data)
{
- pci_mmio_writel(val, ogp_spibar + ogp_reg_siso);
+ struct ogp_spi_data *data = spi_data;
+ pci_mmio_writel(val, data->spibar + data->reg_siso);
}
-static int ogp_bitbang_get_miso(void)
+static int ogp_bitbang_get_miso(void *spi_data)
{
+ struct ogp_spi_data *data = spi_data;
uint32_t tmp;
- tmp = pci_mmio_readl(ogp_spibar + ogp_reg_siso);
+ tmp = pci_mmio_readl(data->spibar + data->reg_siso);
return tmp & 0x1;
}
static const struct bitbang_spi_master bitbang_spi_master_ogp = {
- .set_cs = ogp_bitbang_set_cs,
- .set_sck = ogp_bitbang_set_sck,
- .set_mosi = ogp_bitbang_set_mosi,
- .get_miso = ogp_bitbang_get_miso,
- .request_bus = ogp_request_spibus,
- .release_bus = ogp_release_spibus,
- .half_period = 0,
+ .set_cs = ogp_bitbang_set_cs,
+ .set_sck = ogp_bitbang_set_sck,
+ .set_mosi = ogp_bitbang_set_mosi,
+ .get_miso = ogp_bitbang_get_miso,
+ .request_bus = ogp_request_spibus,
+ .release_bus = ogp_release_spibus,
+ .half_period = 0,
};
-int ogp_spi_init(void)
+static int ogp_spi_shutdown(void *data)
+{
+ free(data);
+ return 0;
+}
+
+static int ogp_spi_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
char *type;
+ uint8_t *ogp_spibar;
+ uint32_t ogp_reg_sel;
+ uint32_t ogp_reg_siso;
+ uint32_t ogp_reg__ce;
+ uint32_t ogp_reg_sck;
- type = extract_programmer_param("rom");
+ type = extract_programmer_param_str(cfg, "rom");
if (!type) {
msg_perr("Please use flashrom -p ogp_spi:rom=... to specify "
@@ -120,10 +140,7 @@ int ogp_spi_init(void)
}
free(type);
- if (rget_io_perms())
- return 1;
-
- dev = pcidev_init(ogp_spi, PCI_BASE_ADDRESS_0);
+ dev = pcidev_init(cfg, ogp_spi, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -135,8 +152,30 @@ int ogp_spi_init(void)
if (ogp_spibar == ERROR_PTR)
return 1;
- if (register_spi_bitbang_master(&bitbang_spi_master_ogp))
+ struct ogp_spi_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ return 1;
+ }
+ data->spibar = ogp_spibar;
+ data->reg_sel = ogp_reg_sel;
+ data->reg_siso = ogp_reg_siso;
+ data->reg__ce = ogp_reg__ce;
+ data->reg_sck = ogp_reg_sck;
+ if (register_shutdown(ogp_spi_shutdown, data)) {
+ free(data);
+ return 1;
+ }
+
+ if (register_spi_bitbang_master(&bitbang_spi_master_ogp, data))
return 1;
return 0;
}
+
+const struct programmer_entry programmer_ogp_spi = {
+ .name = "ogp_spi",
+ .type = PCI,
+ .devs.dev = ogp_spi,
+ .init = ogp_spi_init,
+};
diff --git a/opaque.c b/opaque.c
index 276934fd1..7704ec7a7 100644
--- a/opaque.c
+++ b/opaque.c
@@ -46,9 +46,16 @@ int erase_opaque(struct flashctx *flash, unsigned int blockaddr, unsigned int bl
return flash->mst->opaque.erase(flash, blockaddr, blocklen);
}
-int register_opaque_master(const struct opaque_master *mst)
+int register_opaque_master(const struct opaque_master *mst, void *data)
{
- struct registered_master rmst;
+ struct registered_master rmst = {0};
+
+ if (mst->shutdown) {
+ if (register_shutdown(mst->shutdown, data)) {
+ mst->shutdown(data); /* cleanup */
+ return 1;
+ }
+ }
if (!mst->probe || !mst->read || !mst->write || !mst->erase) {
msg_perr("%s called with incomplete master definition. "
@@ -58,5 +65,7 @@ int register_opaque_master(const struct opaque_master *mst)
}
rmst.buses_supported = BUS_PROG;
rmst.opaque = *mst;
+ if (data)
+ rmst.opaque.data = data;
return register_master(&rmst);
}
diff --git a/parade_lspcon.c b/parade_lspcon.c
new file mode 100644
index 000000000..dfcf65962
--- /dev/null
+++ b/parade_lspcon.c
@@ -0,0 +1,508 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2020 The Chromium OS Authors
+ *
+ * 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 <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "programmer.h"
+#include "spi.h"
+#include "i2c_helper.h"
+
+#define REGISTER_ADDRESS (0x94 >> 1)
+#define PAGE_ADDRESS (0x9e >> 1)
+#define TUNNEL_PAGE_SIZE 256
+#define MAX_SPI_WAIT_RETRIES 1000
+
+#define CLT2_SPI 0x82
+#define SPIEDID_BASE_ADDR2 0x8d
+#define ROMADDR_BYTE1 0x8e
+#define ROMADDR_BYTE2 0x8f
+#define SWSPI_WDATA 0x90
+/* SWSPI_WDATA_* appear to be numerically the same as JEDEC commands. */
+ #define SWSPI_WDATA_CLEAR_STATUS 0x00
+ #define SWSPI_WDATA_WRITE_REGISTER 0x01 /* JEDEC_WRSR */
+ #define SWSPI_WDATA_READ_REGISTER 0x05 /* JEDEC_RDSR */
+ #define SWSPI_WDATA_ENABLE_REGISTER 0x06 /* JEDEC_WREN */
+ #define SWSPI_WDATA_PROTECT_BP 0x8c
+#define SWSPI_RDATA 0x91
+#define SWSPI_LEN 0x92
+#define SWSPICTL 0x93
+ #define SWSPICTL_ACCESS_TRIGGER BIT(0)
+ #define SWSPICTL_CLEAR_PTR BIT(1)
+ #define SWSPICTL_NO_READ BIT(2)
+ #define SWSPICTL_ENABLE_READBACK BIT(3)
+ #define SWSPICTL_MOT BIT(4)
+#define SPISTATUS 0x9e
+ #define SPISTATUS_BYTE_PROGRAM_FINISHED 0
+ #define SPISTATUS_BYTE_PROGRAM_IN_IF BIT(0)
+ #define SPISTATUS_BYTE_PROGRAM_SEND_DONE BIT(1)
+ #define SPISTATUS_SECTOR_ERASE_FINISHED 0
+ #define SPISTATUS_SECTOR_ERASE_IN_IF BIT(2)
+ #define SPISTATUS_SECTOR_ERASE_SEND_DONE BIT(3)
+ #define SPISTATUS_CHIP_ERASE_FINISHED 0
+ #define SPISTATUS_CHIP_ERASE_IN_IF BIT(4)
+ #define SPISTATUS_CHIP_ERASE_SEND_DONE BIT(5)
+ #define SPISTATUS_FW_UPDATE_ENABLE BIT(6)
+#define WRITE_PROTECTION 0xb3
+ #define WRITE_PROTECTION_ON 0
+ #define WRITE_PROTECTION_OFF 0x10
+#define MPU 0xbc
+#define PAGE_HW_WRITE 0xda
+ #define PAGE_HW_WRITE_DISABLE 0
+ #define PAGE_HW_COFIG_REGISTER 0xaa
+ #define PAGE_HW_WRITE_ENABLE 0x55
+
+struct parade_lspcon_data {
+ int fd;
+};
+
+typedef struct {
+ uint8_t command;
+ const uint8_t *data;
+ uint8_t data_size;
+ uint8_t control;
+} packet_t;
+
+static int parade_lspcon_write_data(int fd, uint16_t addr, void *buf, uint16_t len)
+{
+ i2c_buffer_t data;
+ if (i2c_buffer_t_fill(&data, buf, len))
+ return SPI_GENERIC_ERROR;
+
+ return i2c_write(fd, addr, &data) == len ? 0 : SPI_GENERIC_ERROR;
+}
+
+static int parade_lspcon_read_data(int fd, uint16_t addr, void *buf, uint16_t len)
+{
+ i2c_buffer_t data;
+ if (i2c_buffer_t_fill(&data, buf, len))
+ return SPI_GENERIC_ERROR;
+
+ return i2c_read(fd, addr, &data) == len ? 0 : SPI_GENERIC_ERROR;
+}
+
+static int get_fd_from_context(const struct flashctx *flash)
+{
+ if (!flash || !flash->mst || !flash->mst->spi.data) {
+ msg_perr("Unable to extract fd from flash context.\n");
+ return SPI_GENERIC_ERROR;
+ }
+ const struct parade_lspcon_data *data =
+ (const struct parade_lspcon_data *)flash->mst->spi.data;
+
+ return data->fd;
+}
+
+static int parade_lspcon_write_register(int fd, uint8_t i2c_register, uint8_t value)
+{
+ uint8_t command[] = { i2c_register, value };
+ return parade_lspcon_write_data(fd, REGISTER_ADDRESS, command, 2);
+}
+
+static int parade_lspcon_read_register(int fd, uint8_t i2c_register, uint8_t *value)
+{
+ uint8_t command[] = { i2c_register };
+ int ret = parade_lspcon_write_data(fd, REGISTER_ADDRESS, command, 1);
+ ret |= parade_lspcon_read_data(fd, REGISTER_ADDRESS, value, 1);
+
+ return ret ? SPI_GENERIC_ERROR : 0;
+}
+
+static int parade_lspcon_register_control(int fd, packet_t *packet)
+{
+ int i;
+ int ret = parade_lspcon_write_register(fd, SWSPI_WDATA, packet->command);
+ if (ret)
+ return ret;
+
+ /* Higher 4 bits are read size. */
+ int write_size = packet->data_size & 0x0f;
+ for (i = 0; i < write_size; ++i) {
+ ret |= parade_lspcon_write_register(fd, SWSPI_WDATA, packet->data[i]);
+ }
+
+ ret |= parade_lspcon_write_register(fd, SWSPI_LEN, packet->data_size);
+ ret |= parade_lspcon_write_register(fd, SWSPICTL, packet->control);
+
+ return ret;
+}
+
+static int parade_lspcon_wait_command_done(int fd, unsigned int offset, int mask)
+{
+ uint8_t val;
+ int tried = 0;
+ int ret = 0;
+ do {
+ ret |= parade_lspcon_read_register(fd, offset, &val);
+ } while (!ret && (val & mask) && ++tried < MAX_SPI_WAIT_RETRIES);
+
+ if (tried == MAX_SPI_WAIT_RETRIES) {
+ msg_perr("%s: Time out on sending command.\n", __func__);
+ return -MAX_SPI_WAIT_RETRIES;
+ }
+
+ return (val & mask) ? SPI_GENERIC_ERROR : ret;
+}
+
+static int parade_lspcon_wait_rom_free(int fd)
+{
+ uint8_t val;
+ int tried = 0;
+ int ret = 0;
+ ret |= parade_lspcon_wait_command_done(fd, SPISTATUS,
+ SPISTATUS_SECTOR_ERASE_IN_IF | SPISTATUS_SECTOR_ERASE_SEND_DONE);
+ if (ret)
+ return ret;
+
+ do {
+ packet_t packet = { SWSPI_WDATA_READ_REGISTER, NULL, 0, SWSPICTL_ACCESS_TRIGGER };
+ ret |= parade_lspcon_register_control(fd, &packet);
+ ret |= parade_lspcon_wait_command_done(fd, SWSPICTL, SWSPICTL_ACCESS_TRIGGER);
+ ret |= parade_lspcon_read_register(fd, SWSPI_RDATA, &val);
+ } while (!ret && (val & SWSPICTL_ACCESS_TRIGGER) && ++tried < MAX_SPI_WAIT_RETRIES);
+
+ if (tried == MAX_SPI_WAIT_RETRIES) {
+ msg_perr("%s: Time out on waiting ROM free.\n", __func__);
+ return -MAX_SPI_WAIT_RETRIES;
+ }
+
+ return (val & SWSPICTL_ACCESS_TRIGGER) ? SPI_GENERIC_ERROR : ret;
+}
+
+static int parade_lspcon_toggle_register_protection(int fd, int toggle)
+{
+ return parade_lspcon_write_register(fd, WRITE_PROTECTION,
+ toggle ? WRITE_PROTECTION_OFF : WRITE_PROTECTION_ON);
+}
+
+static int parade_lspcon_enable_write_status_register(int fd)
+{
+ int ret = parade_lspcon_toggle_register_protection(fd, 1);
+ packet_t packet = {
+ SWSPI_WDATA_ENABLE_REGISTER, NULL, 0, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ };
+ ret |= parade_lspcon_register_control(fd, &packet);
+ ret |= parade_lspcon_toggle_register_protection(fd, 0);
+
+ return ret;
+}
+
+static int parade_lspcon_enable_write_status_register_protection(int fd)
+{
+ int ret = parade_lspcon_toggle_register_protection(fd, 1);
+ uint8_t data[] = { SWSPI_WDATA_PROTECT_BP };
+ packet_t packet = {
+ SWSPI_WDATA_WRITE_REGISTER, data, 1, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ };
+ ret |= parade_lspcon_register_control(fd, &packet);
+ ret |= parade_lspcon_toggle_register_protection(fd, 0);
+
+ return ret;
+}
+
+static int parade_lspcon_disable_protection(int fd)
+{
+ int ret = parade_lspcon_toggle_register_protection(fd, 1);
+ uint8_t data[] = { SWSPI_WDATA_CLEAR_STATUS };
+ packet_t packet = {
+ SWSPI_WDATA_WRITE_REGISTER, data, 1, SWSPICTL_ACCESS_TRIGGER | SWSPICTL_NO_READ };
+ ret |= parade_lspcon_register_control(fd, &packet);
+ ret |= parade_lspcon_toggle_register_protection(fd, 0);
+
+ return ret;
+}
+
+static int parade_lspcon_disable_hw_write(int fd)
+{
+ return parade_lspcon_write_register(fd, PAGE_HW_WRITE, PAGE_HW_WRITE_DISABLE);
+}
+
+static int parade_lspcon_enable_write_protection(int fd)
+{
+ int ret = parade_lspcon_enable_write_status_register(fd);
+ ret |= parade_lspcon_enable_write_status_register_protection(fd);
+ ret |= parade_lspcon_wait_rom_free(fd);
+ ret |= parade_lspcon_disable_hw_write(fd);
+
+ return ret;
+}
+
+static int parade_lspcon_disable_all_protection(int fd)
+{
+ int ret = parade_lspcon_enable_write_status_register(fd);
+ ret |= parade_lspcon_disable_protection(fd);
+ ret |= parade_lspcon_wait_rom_free(fd);
+
+ return ret;
+}
+
+static int parade_lspcon_send_command(const struct flashctx *flash,
+ unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr,
+ unsigned char *readarr)
+{
+ unsigned int i;
+ if (writecnt > 16 || readcnt > 16 || writecnt == 0) {
+ msg_perr("%s: Invalid read/write count for send command.\n",
+ __func__);
+ return SPI_GENERIC_ERROR;
+ }
+
+ int fd = get_fd_from_context(flash);
+ if (fd < 0)
+ return SPI_GENERIC_ERROR;
+
+ int ret = parade_lspcon_disable_all_protection(fd);
+ ret |= parade_lspcon_enable_write_status_register(fd);
+ ret |= parade_lspcon_toggle_register_protection(fd, 1);
+
+ /* First byte of writearr should be the command value, followed by the value to write.
+ Read length occupies 4 bit and represents 16 level, thus if read 1 byte,
+ read length should be set 0. */
+ packet_t packet = {
+ writearr[0], &writearr[1], (writecnt - 1) | ((readcnt - 1) << 4),
+ SWSPICTL_ACCESS_TRIGGER | (readcnt ? 0 : SWSPICTL_NO_READ),
+ };
+
+ ret |= parade_lspcon_register_control(fd, &packet);
+ ret |= parade_lspcon_wait_command_done(fd, SWSPICTL, SWSPICTL_ACCESS_TRIGGER);
+ ret |= parade_lspcon_toggle_register_protection(fd, 0);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < readcnt; ++i) {
+ ret |= parade_lspcon_read_register(fd, SWSPI_RDATA, &readarr[i]);
+ }
+
+ ret |= parade_lspcon_wait_rom_free(fd);
+
+ return ret;
+}
+
+static int parade_lspcon_enable_hw_write(int fd)
+{
+ int ret = 0;
+ ret |= parade_lspcon_write_register(fd, PAGE_HW_WRITE, PAGE_HW_COFIG_REGISTER);
+ ret |= parade_lspcon_write_register(fd, PAGE_HW_WRITE, PAGE_HW_WRITE_ENABLE);
+ ret |= parade_lspcon_write_register(fd, PAGE_HW_WRITE, 0x50);
+ ret |= parade_lspcon_write_register(fd, PAGE_HW_WRITE, 0x41);
+ ret |= parade_lspcon_write_register(fd, PAGE_HW_WRITE, 0x52);
+ ret |= parade_lspcon_write_register(fd, PAGE_HW_WRITE, 0x44);
+
+ return ret;
+}
+
+static int parade_lspcon_i2c_clt2_spi_reset(int fd)
+{
+ int ret = 0;
+ ret |= parade_lspcon_write_register(fd, CLT2_SPI, 0x20);
+ struct timespec wait_100ms = { 0, (unsigned)1e8 };
+ nanosleep(&wait_100ms, NULL);
+ ret |= parade_lspcon_write_register(fd, CLT2_SPI, 0x00);
+
+ return ret;
+}
+
+static int parade_lspcon_set_mpu_active(int fd, int running)
+{
+ int ret = 0;
+ // Cmd mode
+ ret |= parade_lspcon_write_register(fd, MPU, 0xc0);
+ // Stop or release MPU
+ ret |= parade_lspcon_write_register(fd, MPU, running ? 0 : 0x40);
+
+ return ret;
+}
+
+static int parade_lspcon_map_page(int fd, unsigned int offset)
+{
+ int ret = 0;
+ /* Page number byte, need to / TUNNEL_PAGE_SIZE. */
+ ret |= parade_lspcon_write_register(fd, ROMADDR_BYTE1, (offset >> 8) & 0xff);
+ ret |= parade_lspcon_write_register(fd, ROMADDR_BYTE2, (offset >> 16));
+
+ return ret ? SPI_GENERIC_ERROR : 0;
+}
+
+static int parade_lspcon_read(struct flashctx *flash, uint8_t *buf,
+ unsigned int start, unsigned int len)
+{
+ unsigned int i;
+ int ret = 0;
+ if (start & 0xff)
+ return default_spi_read(flash, buf, start, len);
+
+ int fd = get_fd_from_context(flash);
+ if (fd < 0)
+ return SPI_GENERIC_ERROR;
+
+ for (i = 0; i < len; i += TUNNEL_PAGE_SIZE) {
+ ret |= parade_lspcon_map_page(fd, start + i);
+ ret |= parade_lspcon_read_data(fd, PAGE_ADDRESS, buf + i, min(len - i, TUNNEL_PAGE_SIZE));
+ update_progress(flash, FLASHROM_PROGRESS_READ, i + TUNNEL_PAGE_SIZE, len);
+ }
+
+ return ret;
+}
+
+static int parade_lspcon_write_page(int fd, const uint8_t *buf, unsigned int len)
+{
+ /**
+ * Using static buffer with maximum possible size,
+ * extra byte is needed for prefixing zero at index 0.
+ */
+ uint8_t write_buffer[TUNNEL_PAGE_SIZE + 1] = { 0 };
+ if (len > TUNNEL_PAGE_SIZE)
+ return SPI_GENERIC_ERROR;
+
+ /* First byte represents the writing offset and should always be zero. */
+ memcpy(&write_buffer[1], buf, len);
+
+ return parade_lspcon_write_data(fd, PAGE_ADDRESS, write_buffer, len + 1);
+}
+
+static int parade_lspcon_write_256(struct flashctx *flash, const uint8_t *buf,
+ unsigned int start, unsigned int len)
+{
+ int ret = 0;
+ if (start & 0xff)
+ return default_spi_write_256(flash, buf, start, len);
+
+ int fd = get_fd_from_context(flash);
+ if (fd < 0)
+ return SPI_GENERIC_ERROR;
+
+ ret |= parade_lspcon_disable_all_protection(fd);
+ /* Enable hardware write and reset clt2SPI interface. */
+ ret |= parade_lspcon_enable_hw_write(fd);
+ ret |= parade_lspcon_i2c_clt2_spi_reset(fd);
+
+ for (unsigned int i = 0; i < len; i += TUNNEL_PAGE_SIZE) {
+ ret |= parade_lspcon_map_page(fd, start + i);
+ ret |= parade_lspcon_write_page(fd, buf + i, min(len - i, TUNNEL_PAGE_SIZE));
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i + TUNNEL_PAGE_SIZE, len);
+ }
+
+ ret |= parade_lspcon_enable_write_protection(fd);
+ ret |= parade_lspcon_disable_hw_write(fd);
+
+ return ret;
+}
+
+static int parade_lspcon_write_aai(struct flashctx *flash, const uint8_t *buf,
+ unsigned int start, unsigned int len)
+{
+ msg_perr("%s: AAI write function is not supported.\n",
+ __func__);
+ return SPI_GENERIC_ERROR;
+}
+
+static int parade_lspcon_shutdown(void *data)
+{
+ int ret = 0;
+ struct parade_lspcon_data *parade_lspcon_data =
+ (struct parade_lspcon_data *)data;
+ int fd = parade_lspcon_data->fd;
+
+ ret |= parade_lspcon_enable_write_protection(fd);
+ ret |= parade_lspcon_toggle_register_protection(fd, 0);
+ ret |= parade_lspcon_set_mpu_active(fd, 1);
+ i2c_close(fd);
+ free(data);
+
+ return ret;
+}
+
+static const struct spi_master spi_master_parade_lspcon = {
+ .max_data_read = 16,
+ .max_data_write = 12,
+ .command = parade_lspcon_send_command,
+ .read = parade_lspcon_read,
+ .write_256 = parade_lspcon_write_256,
+ .write_aai = parade_lspcon_write_aai,
+ .shutdown = parade_lspcon_shutdown,
+};
+
+static int get_params(const struct programmer_cfg *cfg, bool *allow_brick)
+{
+ char *brick_str = NULL;
+ int ret = 0;
+
+ *allow_brick = false; /* Default behaviour is to bail. */
+ brick_str = extract_programmer_param_str(cfg, "allow_brick");
+ if (brick_str) {
+ if (!strcmp(brick_str, "yes")) {
+ *allow_brick = true;
+ } else {
+ msg_perr("%s: Incorrect param format, allow_brick=yes.\n", __func__);
+ ret = SPI_GENERIC_ERROR;
+ }
+ }
+ free(brick_str);
+
+ return ret;
+}
+
+static int parade_lspcon_init(const struct programmer_cfg *cfg)
+{
+ bool allow_brick;
+
+ if (get_params(cfg, &allow_brick))
+ return SPI_GENERIC_ERROR;
+
+ /*
+ * TODO: Once board_enable can facilitate safe i2c allow listing
+ * then this can be removed.
+ */
+ if (!allow_brick) {
+ msg_perr("%s: For i2c drivers you must explicitly 'allow_brick=yes'. ", __func__);
+ msg_perr("There is currently no way to determine if the programmer works on a board "
+ "as i2c device address space can be overloaded. Set 'allow_brick=yes' if "
+ "you are sure you know what you are doing.\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ int fd = i2c_open_from_programmer_params(cfg, REGISTER_ADDRESS, 0);
+ if (fd < 0)
+ return fd;
+
+ int ret = parade_lspcon_set_mpu_active(fd, 0);
+ if (ret) {
+ msg_perr("%s: call to set_mpu_active failed.\n", __func__);
+ i2c_close(fd);
+ return ret;
+ }
+
+ struct parade_lspcon_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for extra SPI master data.\n");
+ i2c_close(fd);
+ return SPI_GENERIC_ERROR;
+ }
+
+ data->fd = fd;
+
+ return register_spi_master(&spi_master_parade_lspcon, data);
+}
+
+const struct programmer_entry programmer_parade_lspcon = {
+ .name = "parade_lspcon",
+ .type = OTHER,
+ .devs.note = "Device files /dev/i2c-*.\n",
+ .init = parade_lspcon_init,
+};
diff --git a/parallel.c b/parallel.c
new file mode 100644
index 000000000..b19372302
--- /dev/null
+++ b/parallel.c
@@ -0,0 +1,165 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2004 Tyan Corp <yhlu@tyan.com>
+ * Copyright (C) 2005-2008 coresystems GmbH
+ * Copyright (C) 2008,2009 Carl-Daniel Hailfinger
+ * Copyright (C) 2016 secunet Security Networks AG
+ * (Written by Nico Huber <nico.huber@secunet.com> for secunet)
+ * Copyright (C) 2009,2010,2011 Carl-Daniel Hailfinger
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "flash.h"
+#include "programmer.h"
+
+void chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
+{
+ flash->mst->par.chip_writeb(flash, val, addr);
+}
+
+/* Little-endian fallback for drivers not supporting 16 bit accesses */
+static void fallback_chip_writew(const struct flashctx *flash, uint16_t val,
+ chipaddr addr)
+{
+ chip_writeb(flash, val & 0xff, addr);
+ chip_writeb(flash, (val >> 8) & 0xff, addr + 1);
+}
+
+void chip_writew(const struct flashctx *flash, uint16_t val, chipaddr addr)
+{
+ if (flash->mst->par.chip_writew)
+ flash->mst->par.chip_writew(flash, val, addr);
+ fallback_chip_writew(flash, val, addr);
+}
+
+/* Little-endian fallback for drivers not supporting 32 bit accesses */
+static void fallback_chip_writel(const struct flashctx *flash, uint32_t val,
+ chipaddr addr)
+{
+ chip_writew(flash, val & 0xffff, addr);
+ chip_writew(flash, (val >> 16) & 0xffff, addr + 2);
+}
+
+void chip_writel(const struct flashctx *flash, uint32_t val, chipaddr addr)
+{
+ if (flash->mst->par.chip_writel)
+ flash->mst->par.chip_writel(flash, val, addr);
+ fallback_chip_writel(flash, val, addr);
+}
+
+static void fallback_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
+{
+ size_t i;
+ for (i = 0; i < len; i++)
+ chip_writeb(flash, buf[i], addr + i);
+ return;
+}
+
+void chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
+{
+ if (flash->mst->par.chip_writen)
+ flash->mst->par.chip_writen(flash, buf, addr, len);
+ fallback_chip_writen(flash, buf, addr, len);
+}
+
+uint8_t chip_readb(const struct flashctx *flash, const chipaddr addr)
+{
+ return flash->mst->par.chip_readb(flash, addr);
+}
+
+/* Little-endian fallback for drivers not supporting 16 bit accesses */
+static uint16_t fallback_chip_readw(const struct flashctx *flash, const chipaddr addr)
+{
+ uint16_t val;
+ val = chip_readb(flash, addr);
+ val |= chip_readb(flash, addr + 1) << 8;
+ return val;
+}
+
+uint16_t chip_readw(const struct flashctx *flash, const chipaddr addr)
+{
+ if (flash->mst->par.chip_readw)
+ return flash->mst->par.chip_readw(flash, addr);
+ return fallback_chip_readw(flash, addr);
+}
+
+/* Little-endian fallback for drivers not supporting 32 bit accesses */
+static uint32_t fallback_chip_readl(const struct flashctx *flash, const chipaddr addr)
+{
+ uint32_t val;
+ val = chip_readw(flash, addr);
+ val |= chip_readw(flash, addr + 2) << 16;
+ return val;
+}
+
+uint32_t chip_readl(const struct flashctx *flash, const chipaddr addr)
+{
+ if (flash->mst->par.chip_readl)
+ return flash->mst->par.chip_readl(flash, addr);
+ return fallback_chip_readl(flash, addr);
+}
+
+static void fallback_chip_readn(const struct flashctx *flash, uint8_t *buf,
+ chipaddr addr, size_t len)
+{
+ size_t i;
+ for (i = 0; i < len; i++)
+ buf[i] = chip_readb(flash, addr + i);
+ return;
+}
+
+void chip_readn(const struct flashctx *flash, uint8_t *buf, chipaddr addr,
+ size_t len)
+{
+ if (flash->mst->par.chip_readn)
+ flash->mst->par.chip_readn(flash, buf, addr, len);
+ fallback_chip_readn(flash, buf, addr, len);
+}
+
+int register_par_master(const struct par_master *mst,
+ const enum chipbustype buses,
+ void *data)
+{
+ struct registered_master rmst = {0};
+
+ if (mst->shutdown) {
+ if (register_shutdown(mst->shutdown, data)) {
+ mst->shutdown(data); /* cleanup */
+ return 1;
+ }
+ }
+
+ /* Bus masters supporting FWH/LPC cannot use chip physical maps, distinct
+ * mappings are needed to support chips with FEATURE_REGISTERMAP
+ */
+ if ((buses & (BUS_FWH | BUS_LPC)) && !mst->map_flash_region) {
+ msg_perr("%s called with incomplete master definition. "
+ "FWH/LPC masters must provide memory mappings. "
+ "Please report a bug at flashrom@flashrom.org\n",
+ __func__);
+ return ERROR_FLASHROM_BUG;
+ }
+
+ if (!mst->chip_writeb || !mst->chip_readb) {
+ msg_perr("%s called with incomplete master definition. "
+ "Please report a bug at flashrom@flashrom.org\n",
+ __func__);
+ return ERROR_FLASHROM_BUG;
+ }
+
+ rmst.buses_supported = buses;
+ rmst.par = *mst;
+ if (data)
+ rmst.par.data = data;
+ return register_master(&rmst);
+}
diff --git a/pcidev.c b/pcidev.c
index 892f7b1cc..696510edc 100644
--- a/pcidev.c
+++ b/pcidev.c
@@ -19,7 +19,7 @@
#include <string.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "platform/pci.h"
struct pci_access *pacc;
@@ -148,6 +148,75 @@ uintptr_t pcidev_readbar(struct pci_dev *dev, int bar)
return (uintptr_t)addr;
}
+struct pci_dev *pcidev_scandev(struct pci_filter *filter, struct pci_dev *start)
+{
+ struct pci_dev *temp;
+ for (temp = start ? start->next : pacc->devices; temp; temp = temp->next) {
+ if (pci_filter_match(filter, temp)) {
+ pci_fill_info(temp, PCI_FILL_IDENT);
+ return temp;
+ }
+ }
+ return NULL;
+}
+
+struct pci_dev *pcidev_card_find(uint16_t vendor, uint16_t device,
+ uint16_t card_vendor, uint16_t card_device)
+{
+ struct pci_dev *temp = NULL;
+ struct pci_filter filter;
+
+ pci_filter_init(NULL, &filter);
+ filter.vendor = vendor;
+ filter.device = device;
+
+ while ((temp = pcidev_scandev(&filter, temp))) {
+ if ((card_vendor == pci_read_word(temp, PCI_SUBSYSTEM_VENDOR_ID))
+ && (card_device == pci_read_word(temp, PCI_SUBSYSTEM_ID)))
+ return temp;
+ }
+
+ return NULL;
+}
+
+struct pci_dev *pcidev_find(uint16_t vendor, uint16_t device)
+{
+ struct pci_filter filter;
+
+ pci_filter_init(NULL, &filter);
+ filter.vendor = vendor;
+ filter.device = device;
+
+ return pcidev_scandev(&filter, NULL);
+}
+
+struct pci_dev *pcidev_getdevfn(struct pci_dev *dev, const int func)
+{
+ struct pci_dev *const new = pci_get_dev(pacc, dev->domain, dev->bus, dev->dev, func);
+ if (new)
+ pci_fill_info(new, PCI_FILL_IDENT);
+ return new;
+}
+
+struct pci_dev *pcidev_find_vendorclass(uint16_t vendor, uint16_t devclass)
+{
+ struct pci_dev *temp = NULL;
+ struct pci_filter filter;
+ uint16_t tmp2;
+
+ pci_filter_init(NULL, &filter);
+ filter.vendor = vendor;
+
+ while ((temp = pcidev_scandev(&filter, temp))) {
+ /* Read PCI class */
+ tmp2 = pci_read_word(temp, PCI_CLASS_DEVICE);
+ if (tmp2 == devclass)
+ return temp;
+ }
+
+ return NULL;
+}
+
static int pcidev_shutdown(void *data)
{
if (pacc == NULL) {
@@ -180,7 +249,7 @@ int pci_init_common(void)
* also matches the specified bus:device.function.
* For convenience, this function also registers its own undo handlers.
*/
-struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar)
+struct pci_dev *pcidev_init(const struct programmer_cfg *cfg, const struct dev_entry *devs, int bar)
{
struct pci_dev *dev;
struct pci_dev *found_dev = NULL;
@@ -195,7 +264,7 @@ struct pci_dev *pcidev_init(const struct dev_entry *devs, int bar)
pci_filter_init(pacc, &filter);
/* Filter by bb:dd.f (if supplied by the user). */
- pcidev_bdf = extract_programmer_param("pci");
+ pcidev_bdf = extract_programmer_param_str(cfg, "pci");
if (pcidev_bdf != NULL) {
if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) {
msg_perr("Error: %s\n", msg);
@@ -296,7 +365,7 @@ static int undo_pci_write(void *p)
#define register_undo_pci_write(a, b, c) \
{ \
struct undo_pci_write_data *undo_pci_write_data; \
- undo_pci_write_data = malloc(sizeof(struct undo_pci_write_data)); \
+ undo_pci_write_data = malloc(sizeof(*undo_pci_write_data)); \
if (!undo_pci_write_data) { \
msg_gerr("Out of memory!\n"); \
exit(1); \
diff --git a/pickit2_spi.c b/pickit2_spi.c
index 0bc17afb8..a072a2059 100644
--- a/pickit2_spi.c
+++ b/pickit2_spi.c
@@ -32,8 +32,6 @@
* PICkit2 code: https://github.com/steve-m/avrdude/blob/master/pickit2.c
*/
-#include "platform.h"
-
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -46,13 +44,15 @@
#include "programmer.h"
#include "spi.h"
-const struct dev_entry devs_pickit2_spi[] = {
+static const struct dev_entry devs_pickit2_spi[] = {
{0x04D8, 0x0033, OK, "Microchip", "PICkit 2"},
{0}
};
-static libusb_device_handle *pickit2_handle;
+struct pickit2_spi_data {
+ libusb_device_handle *pickit2_handle;
+};
/* Default USB transaction timeout in ms */
#define DFLT_TIMEOUT 10000
@@ -89,20 +89,25 @@ static libusb_device_handle *pickit2_handle;
#define SCR_VDD_OFF 0xFE
#define SCR_VDD_ON 0xFF
-static int pickit2_get_firmware_version(void)
+static int pickit2_interrupt_transfer(libusb_device_handle *handle, unsigned char endpoint, unsigned char *data)
+{
+ int transferred;
+ return libusb_interrupt_transfer(handle, endpoint, data, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
+}
+
+static int pickit2_get_firmware_version(libusb_device_handle *pickit2_handle)
{
int ret;
uint8_t command[CMD_LENGTH] = {CMD_GET_VERSION, CMD_END_OF_BUFFER};
- int transferred;
- ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
+ ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command);
if (ret != 0) {
msg_perr("Command Get Firmware Version failed!\n");
return 1;
}
- ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_IN, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
+ ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_IN, command);
if (ret != 0) {
msg_perr("Command Get Firmware Version failed!\n");
@@ -113,7 +118,7 @@ static int pickit2_get_firmware_version(void)
return 0;
}
-static int pickit2_set_spi_voltage(int millivolt)
+static int pickit2_set_spi_voltage(libusb_device_handle *pickit2_handle, int millivolt)
{
double voltage_selector;
switch (millivolt) {
@@ -148,8 +153,7 @@ static int pickit2_set_spi_voltage(int millivolt)
voltage_selector * 13,
CMD_END_OF_BUFFER
};
- int transferred;
- int ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
+ int ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command);
if (ret != 0) {
msg_perr("Command Set Voltage failed!\n");
@@ -172,7 +176,7 @@ static const struct pickit2_spispeeds spispeeds[] = {
{ NULL, 0x0 },
};
-static int pickit2_set_spi_speed(unsigned int spispeed_idx)
+static int pickit2_set_spi_speed(libusb_device_handle *pickit2_handle, unsigned int spispeed_idx)
{
msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed_idx].name);
@@ -184,8 +188,7 @@ static int pickit2_set_spi_speed(unsigned int spispeed_idx)
CMD_END_OF_BUFFER
};
- int transferred;
- int ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
+ int ret = pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command);
if (ret != 0) {
msg_perr("Command Set SPI Speed failed!\n");
@@ -198,13 +201,15 @@ static int pickit2_set_spi_speed(unsigned int spispeed_idx)
static int pickit2_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr)
{
+ struct pickit2_spi_data *pickit2_data = flash->mst->spi.data;
+ const unsigned int total_packetsize = writecnt + readcnt + 20;
/* Maximum number of bytes per transaction (including command overhead) is 64. Lets play it safe
* and always assume the worst case scenario of 20 bytes command overhead.
*/
- if (writecnt + readcnt + 20 > CMD_LENGTH) {
- msg_perr("\nTotal packetsize (%i) is greater than 64 supported, aborting.\n",
- writecnt + readcnt + 20);
+ if (total_packetsize > CMD_LENGTH) {
+ msg_perr("\nTotal packetsize (%i) is greater than %i supported, aborting.\n",
+ total_packetsize, CMD_LENGTH);
return 1;
}
@@ -254,8 +259,7 @@ static int pickit2_spi_send_command(const struct flashctx *flash, unsigned int w
buf[i++] = CMD_UPLOAD_DATA;
buf[i++] = CMD_END_OF_BUFFER;
- int transferred;
- int ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, buf, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
+ int ret = pickit2_interrupt_transfer(pickit2_data->pickit2_handle, ENDPOINT_OUT, buf);
if (ret != 0) {
msg_perr("Send SPI failed!\n");
@@ -264,7 +268,8 @@ static int pickit2_spi_send_command(const struct flashctx *flash, unsigned int w
if (readcnt) {
int length = 0;
- ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_IN, buf, CMD_LENGTH, &length, DFLT_TIMEOUT);
+ ret = libusb_interrupt_transfer(pickit2_data->pickit2_handle,
+ ENDPOINT_IN, buf, CMD_LENGTH, &length, DFLT_TIMEOUT);
if (length == 0 || ret != 0) {
msg_perr("Receive SPI failed\n");
@@ -335,18 +340,10 @@ static int parse_voltage(char *voltage)
return millivolt;
}
-static const struct spi_master spi_master_pickit2 = {
- .max_data_read = 40,
- .max_data_write = 40,
- .command = pickit2_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
-};
-
static int pickit2_shutdown(void *data)
{
+ struct pickit2_spi_data *pickit2_data = data;
+
/* Set all pins to float and turn voltages off */
uint8_t command[CMD_LENGTH] = {
CMD_EXEC_SCRIPT,
@@ -362,23 +359,33 @@ static int pickit2_shutdown(void *data)
CMD_END_OF_BUFFER
};
- int transferred;
- int ret = libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, command, CMD_LENGTH, &transferred, DFLT_TIMEOUT);
+ int ret = pickit2_interrupt_transfer(pickit2_data->pickit2_handle, ENDPOINT_OUT, command);
if (ret != 0) {
msg_perr("Command Shutdown failed!\n");
ret = 1;
}
- if (libusb_release_interface(pickit2_handle, 0) != 0) {
+ if (libusb_release_interface(pickit2_data->pickit2_handle, 0) != 0) {
msg_perr("Could not release USB interface!\n");
ret = 1;
}
- libusb_close(pickit2_handle);
+ libusb_close(pickit2_data->pickit2_handle);
libusb_exit(NULL);
+
+ free(data);
return ret;
}
-int pickit2_spi_init(void)
+static const struct spi_master spi_master_pickit2 = {
+ .max_data_read = 40,
+ .max_data_write = 40,
+ .command = pickit2_spi_send_command,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = pickit2_shutdown,
+};
+
+static int pickit2_spi_init(const struct programmer_cfg *cfg)
{
uint8_t buf[CMD_LENGTH] = {
CMD_EXEC_SCRIPT,
@@ -397,30 +404,33 @@ int pickit2_spi_init(void)
CMD_END_OF_BUFFER
};
-
+ libusb_device_handle *pickit2_handle;
+ struct pickit2_spi_data *pickit2_data;
int spispeed_idx = 0;
- char *spispeed = extract_programmer_param("spispeed");
- if (spispeed != NULL) {
+ char *param_str;
+
+ param_str = extract_programmer_param_str(cfg, "spispeed");
+ if (param_str != NULL) {
int i = 0;
for (; spispeeds[i].name; i++) {
- if (strcasecmp(spispeeds[i].name, spispeed) == 0) {
+ if (strcasecmp(spispeeds[i].name, param_str) == 0) {
spispeed_idx = i;
break;
}
}
if (spispeeds[i].name == NULL) {
msg_perr("Error: Invalid 'spispeed' value.\n");
- free(spispeed);
+ free(param_str);
return 1;
}
- free(spispeed);
+ free(param_str);
}
int millivolt = 3500;
- char *voltage = extract_programmer_param("voltage");
- if (voltage != NULL) {
- millivolt = parse_voltage(voltage);
- free(voltage);
+ param_str = extract_programmer_param_str(cfg, "voltage");
+ if (param_str != NULL) {
+ millivolt = parse_voltage(param_str);
+ free(param_str);
if (millivolt < 0)
return 1;
}
@@ -458,34 +468,44 @@ int pickit2_spi_init(void)
return 1;
}
- if (register_shutdown(pickit2_shutdown, NULL) != 0) {
+ pickit2_data = calloc(1, sizeof(*pickit2_data));
+ if (!pickit2_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ libusb_close(pickit2_handle);
+ libusb_exit(NULL);
return 1;
}
+ pickit2_data->pickit2_handle = pickit2_handle;
- if (pickit2_get_firmware_version()) {
- return 1;
- }
+ if (pickit2_get_firmware_version(pickit2_handle))
+ goto init_err_cleanup_exit;
/* Command Set SPI Speed */
- if (pickit2_set_spi_speed(spispeed_idx)) {
- return 1;
- }
+ if (pickit2_set_spi_speed(pickit2_handle, spispeed_idx))
+ goto init_err_cleanup_exit;
/* Command Set SPI Voltage */
msg_pdbg("Setting voltage to %i mV.\n", millivolt);
- if (pickit2_set_spi_voltage(millivolt) != 0) {
- return 1;
- }
+ if (pickit2_set_spi_voltage(pickit2_handle, millivolt) != 0)
+ goto init_err_cleanup_exit;
/* Perform basic setup.
* Configure pin directions and logic levels, turn Vdd on, turn busy LED on and clear buffers. */
- int transferred;
- if (libusb_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, buf, CMD_LENGTH, &transferred, DFLT_TIMEOUT) != 0) {
+ if (pickit2_interrupt_transfer(pickit2_handle, ENDPOINT_OUT, buf) != 0) {
msg_perr("Command Setup failed!\n");
- return 1;
+ goto init_err_cleanup_exit;
}
- register_spi_master(&spi_master_pickit2);
+ return register_spi_master(&spi_master_pickit2, pickit2_data);
- return 0;
+init_err_cleanup_exit:
+ pickit2_shutdown(pickit2_data);
+ return 1;
}
+
+const struct programmer_entry programmer_pickit2_spi = {
+ .name = "pickit2_spi",
+ .type = USB,
+ .devs.dev = devs_pickit2_spi,
+ .init = pickit2_spi_init,
+};
diff --git a/platform/endian_big.c b/platform/endian_big.c
new file mode 100644
index 000000000..456553409
--- /dev/null
+++ b/platform/endian_big.c
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2022 secunet Security Networks AG
+ * (written by Thomas Heijligen <thomas.heijligen@secunet.com)
+ *
+ * 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 "platform.h"
+#include "platform/swap.h"
+
+/* convert cpu native endian to little endian */
+___return_swapped(cpu_to_le, 8)
+___return_swapped(cpu_to_le, 16)
+___return_swapped(cpu_to_le, 32)
+___return_swapped(cpu_to_le, 64)
+
+/* convert cpu native endian to big endian */
+___return_same(cpu_to_be, 8)
+___return_same(cpu_to_be, 16)
+___return_same(cpu_to_be, 32)
+___return_same(cpu_to_be, 64)
+
+/* convert little endian to cpu native endian */
+___return_swapped(le_to_cpu, 8)
+___return_swapped(le_to_cpu, 16)
+___return_swapped(le_to_cpu, 32)
+___return_swapped(le_to_cpu, 64)
+
+/* convert big endian to cpu native endian */
+___return_same(be_to_cpu, 8)
+___return_same(be_to_cpu, 16)
+___return_same(be_to_cpu, 32)
+___return_same(be_to_cpu, 64)
diff --git a/platform/endian_little.c b/platform/endian_little.c
new file mode 100644
index 000000000..690f3839f
--- /dev/null
+++ b/platform/endian_little.c
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2022 secunet Security Networks AG
+ * (written by Thomas Heijligen <thomas.heijligen@secunet.com)
+ *
+ * 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 "platform.h"
+#include "platform/swap.h"
+
+/* convert cpu native endian to little endian */
+___return_same(cpu_to_le, 8)
+___return_same(cpu_to_le, 16)
+___return_same(cpu_to_le, 32)
+___return_same(cpu_to_le, 64)
+
+/* convert cpu native endian to big endian */
+___return_swapped(cpu_to_be, 8)
+___return_swapped(cpu_to_be, 16)
+___return_swapped(cpu_to_be, 32)
+___return_swapped(cpu_to_be, 64)
+
+/* convert little endian to cpu native endian */
+___return_same(le_to_cpu, 8)
+___return_same(le_to_cpu, 16)
+___return_same(le_to_cpu, 32)
+___return_same(le_to_cpu, 64)
+
+/* convert big endian to cpu native endian */
+___return_swapped(be_to_cpu, 8)
+___return_swapped(be_to_cpu, 16)
+___return_swapped(be_to_cpu, 32)
+___return_swapped(be_to_cpu, 64)
diff --git a/platform/memaccess.c b/platform/memaccess.c
new file mode 100644
index 000000000..836812123
--- /dev/null
+++ b/platform/memaccess.c
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2016 secunet Security Networks AG
+ * (written by Thomas Heijligen <thomas.heijligen@secunet.com>)
+ *
+ * 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 "platform.h"
+
+/*
+ * macro to return endian aware read function
+ *
+ * `___read(le, 8)`
+ * expands to
+ * `uint8_t read_le8 (const void *const base, const size_t offset)
+ * { return le_to_cpu8 (*(uint8_t *)((uintptr_t)base + offset)); }`
+ */
+#define ___read(endian, bits) \
+ uint##bits##_t read_##endian##bits (const void *const base, const size_t offset) \
+ { return endian##_to_cpu##bits (*(uint##bits##_t *)((uintptr_t)base + offset)); }
+
+/* read value from base at offset in little endian */
+___read(le, 8)
+___read(le, 16)
+___read(le, 32)
+___read(le, 64)
+
+/* read value from base at offset in big endian */
+___read(be, 8)
+___read(be, 16)
+___read(be, 32)
+___read(be, 64)
diff --git a/platform/meson.build b/platform/meson.build
new file mode 100644
index 000000000..42e85eea4
--- /dev/null
+++ b/platform/meson.build
@@ -0,0 +1,42 @@
+srcs += files(
+ ('endian_' + host_machine.endian() + '.c'),
+ 'memaccess.c',
+)
+
+if host_machine.endian() == 'little'
+ add_project_arguments('-D__FLASHROM_LITTLE_ENDIAN__=1', language : 'c')
+endif
+if host_machine.endian() == 'big'
+ add_project_arguments('-D__FLASHROM_BIG_ENDIAN__=1', language : 'c')
+endif
+
+# OpenBSD requires libi386 or libamd64 for I/O port handling
+if host_machine.system() == 'openbsd'
+ if host_machine.cpu_family() == 'x86'
+ libi386 = cc.find_library('i386')
+ deps += libi386
+ elif host_machine.cpu_family() == 'x86_64'
+ libamd64 = cc.find_library('amd64')
+ deps += libamd64
+ endif
+endif
+
+# NetBSD requires libx86 or libx86_64 for I/O port handling
+if host_machine.system() == 'netbsd'
+ if host_machine.cpu_family() == 'x86'
+ libx86 = cc.find_library('x86')
+ deps += libx86
+ elif host_machine.cpu_family() == 'x86_64'
+ libx86_64 = cc.find_library('x86_64')
+ deps += libx86_64
+ endif
+endif
+
+
+# SunOS requires external libraries for network sockets
+# they are used to support serial devices via network
+if host_machine.system() == 'sunos'
+ libsocket = cc.find_library('socket')
+ libnsl = cc.find_library('nsl')
+ deps += [ libsocket, libnsl]
+endif
diff --git a/pony_spi.c b/pony_spi.c
index ed9d326c5..0647f9121 100644
--- a/pony_spi.c
+++ b/pony_spi.c
@@ -36,6 +36,7 @@
* DCE >-------> DSR
*/
+#include <stdbool.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
@@ -49,53 +50,62 @@ enum pony_type {
TYPE_AJAWE
};
-/* Pins for master->slave direction */
-static int pony_negate_cs = 1;
-static int pony_negate_sck = 0;
-static int pony_negate_mosi = 0;
-/* Pins for slave->master direction */
-static int pony_negate_miso = 0;
+struct pony_spi_data {
+ /* Pins for master->slave direction */
+ bool negate_cs;
+ bool negate_sck;
+ bool negate_mosi;
+ /* Pins for slave->master direction */
+ bool negate_miso;
+};
-static void pony_bitbang_set_cs(int val)
+static void pony_bitbang_set_cs(int val, void *spi_data)
{
- if (pony_negate_cs)
+ struct pony_spi_data *data = spi_data;
+
+ if (data->negate_cs)
val ^= 1;
sp_set_pin(PIN_TXD, val);
}
-static void pony_bitbang_set_sck(int val)
+static void pony_bitbang_set_sck(int val, void *spi_data)
{
- if (pony_negate_sck)
+ struct pony_spi_data *data = spi_data;
+
+ if (data->negate_sck)
val ^= 1;
sp_set_pin(PIN_RTS, val);
}
-static void pony_bitbang_set_mosi(int val)
+static void pony_bitbang_set_mosi(int val, void *spi_data)
{
- if (pony_negate_mosi)
+ struct pony_spi_data *data = spi_data;
+
+ if (data->negate_mosi)
val ^= 1;
sp_set_pin(PIN_DTR, val);
}
-static int pony_bitbang_get_miso(void)
+static int pony_bitbang_get_miso(void *spi_data)
{
+ struct pony_spi_data *data = spi_data;
int tmp = sp_get_pin(PIN_CTS);
- if (pony_negate_miso)
+ if (data->negate_miso)
tmp ^= 1;
return tmp;
}
static const struct bitbang_spi_master bitbang_spi_master_pony = {
- .set_cs = pony_bitbang_set_cs,
- .set_sck = pony_bitbang_set_sck,
- .set_mosi = pony_bitbang_set_mosi,
- .get_miso = pony_bitbang_get_miso,
- .half_period = 0,
+ .set_cs = pony_bitbang_set_cs,
+ .set_sck = pony_bitbang_set_sck,
+ .set_mosi = pony_bitbang_set_mosi,
+ .get_miso = pony_bitbang_get_miso,
+ .half_period = 0,
};
static int pony_spi_shutdown(void *data)
@@ -107,83 +117,109 @@ static int pony_spi_shutdown(void *data)
else
msg_pdbg("Pony SPI shutdown completed.\n");
+ free(data);
return ret;
}
-int pony_spi_init(void)
+static int get_params(const struct programmer_cfg *cfg, enum pony_type *type, bool *have_device)
{
- int i, data_out;
char *arg = NULL;
- enum pony_type type = TYPE_SI_PROG;
- const char *name;
- int have_device = 0;
- int have_prog = 0;
+ int ret = 0;
+
+ /* defaults */
+ *type = TYPE_SI_PROG;
+ *have_device = false;
/* The parameter is in format "dev=/dev/device,type=serbang" */
- arg = extract_programmer_param("dev");
+ arg = extract_programmer_param_str(cfg, "dev");
if (arg && strlen(arg)) {
sp_fd = sp_openserport(arg, 9600);
- if (sp_fd == SER_INV_FD) {
- free(arg);
- return 1;
- }
- if (register_shutdown(pony_spi_shutdown, NULL) != 0) {
- free(arg);
- serialport_shutdown(NULL);
- return 1;
- }
- have_device++;
+ if (sp_fd == SER_INV_FD)
+ ret = 1;
+ else
+ *have_device = true;
+ }
+ free(arg);
+
+ arg = extract_programmer_param_str(cfg, "type");
+ if (arg && !strcasecmp(arg, "serbang")) {
+ *type = TYPE_SERBANG;
+ } else if (arg && !strcasecmp(arg, "si_prog")) {
+ *type = TYPE_SI_PROG;
+ } else if (arg && !strcasecmp( arg, "ajawe")) {
+ *type = TYPE_AJAWE;
+ } else if (arg && !strlen(arg)) {
+ msg_perr("Error: Missing argument for programmer type.\n");
+ ret = 1;
+ } else if (arg) {
+ msg_perr("Error: Invalid programmer type specified.\n");
+ ret = 1;
}
free(arg);
+ return ret;
+}
+
+static int pony_spi_init(const struct programmer_cfg *cfg)
+{
+ int i, data_out;
+ enum pony_type type;
+ const char *name;
+ bool have_device;
+ bool have_prog = false;
+
+ if (get_params(cfg, &type, &have_device)) {
+ serialport_shutdown(NULL);
+ return 1;
+ }
if (!have_device) {
msg_perr("Error: No valid device specified.\n"
"Use flashrom -p pony_spi:dev=/dev/device[,type=name]\n");
+ serialport_shutdown(NULL);
return 1;
}
- arg = extract_programmer_param("type");
- if (arg && !strcasecmp(arg, "serbang")) {
- type = TYPE_SERBANG;
- } else if (arg && !strcasecmp(arg, "si_prog")) {
- type = TYPE_SI_PROG;
- } else if (arg && !strcasecmp( arg, "ajawe")) {
- type = TYPE_AJAWE;
- } else if (arg && !strlen(arg)) {
- msg_perr("Error: Missing argument for programmer type.\n");
- free(arg);
+ struct pony_spi_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ serialport_shutdown(NULL);
return 1;
- } else if (arg){
- msg_perr("Error: Invalid programmer type specified.\n");
- free(arg);
+ }
+ data->negate_cs = true;
+ data->negate_sck = false;
+ data->negate_mosi = false;
+ data->negate_miso = false;
+
+ if (register_shutdown(pony_spi_shutdown, data) != 0) {
+ free(data);
+ serialport_shutdown(NULL);
return 1;
}
- free(arg);
/*
* Configure the serial port pins, depending on the used programmer.
*/
switch (type) {
case TYPE_AJAWE:
- pony_negate_cs = 1;
- pony_negate_sck = 1;
- pony_negate_mosi = 1;
- pony_negate_miso = 1;
+ data->negate_cs = true;
+ data->negate_sck = true;
+ data->negate_mosi = true;
+ data->negate_miso = true;
name = "AJAWe";
break;
case TYPE_SERBANG:
- pony_negate_cs = 0;
- pony_negate_sck = 0;
- pony_negate_mosi = 0;
- pony_negate_miso = 1;
+ data->negate_cs = false;
+ data->negate_sck = false;
+ data->negate_mosi = false;
+ data->negate_miso = true;
name = "serbang";
break;
default:
case TYPE_SI_PROG:
- pony_negate_cs = 1;
- pony_negate_sck = 0;
- pony_negate_mosi = 0;
- pony_negate_miso = 0;
+ data->negate_cs = true;
+ data->negate_sck = false;
+ data->negate_mosi = false;
+ data->negate_miso = false;
name = "SI-Prog";
break;
}
@@ -192,27 +228,27 @@ int pony_spi_init(void)
/*
* Detect if there is a compatible hardware programmer connected.
*/
- pony_bitbang_set_cs(1);
- pony_bitbang_set_sck(1);
- pony_bitbang_set_mosi(1);
+ pony_bitbang_set_cs(1, data);
+ pony_bitbang_set_sck(1, data);
+ pony_bitbang_set_mosi(1, data);
switch (type) {
case TYPE_AJAWE:
- have_prog = 1;
+ have_prog = true;
break;
case TYPE_SI_PROG:
case TYPE_SERBANG:
default:
- have_prog = 1;
+ have_prog = true;
/* We toggle RTS/SCK a few times and see if DSR changes too. */
for (i = 1; i <= 10; i++) {
data_out = i & 1;
sp_set_pin(PIN_RTS, data_out);
- programmer_delay(1000);
+ default_delay(1000);
/* If DSR does not change, we are not connected to what we think */
if (data_out != sp_get_pin(PIN_DSR)) {
- have_prog = 0;
+ have_prog = false;
break;
}
}
@@ -224,8 +260,16 @@ int pony_spi_init(void)
return 1;
}
- if (register_spi_bitbang_master(&bitbang_spi_master_pony)) {
+ if (register_spi_bitbang_master(&bitbang_spi_master_pony, data))
return 1;
- }
+
return 0;
}
+
+const struct programmer_entry programmer_pony_spi = {
+ .name = "pony_spi",
+ .type = OTHER,
+ /* FIXME */
+ .devs.note = "Programmers compatible with SI-Prog, serbang or AJAWe\n",
+ .init = pony_spi_init,
+};
diff --git a/print.c b/print.c
index feca45ecd..0caa0da74 100644
--- a/print.c
+++ b/print.c
@@ -20,6 +20,15 @@
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
+#if HAVE_UTSNAME == 1
+#include <sys/utsname.h>
+#endif
+#if IS_WINDOWS
+#include <windows.h>
+#undef min
+#undef max
+#endif
+
#include "flash.h"
#include "programmer.h"
@@ -94,6 +103,10 @@ static int print_supported_chips(void)
} while (1);
s = flashbuses_to_text(chip->bustype);
+ if (s == NULL) {
+ msg_gerr("Out of memory!\n");
+ return 1;
+ }
maxtypelen = max(maxtypelen, strlen(s));
free(s);
}
@@ -256,6 +269,12 @@ static int print_supported_chips(void)
msg_ginfo(" ");
s = flashbuses_to_text(chip->bustype);
+ if (s == NULL) {
+ msg_gerr("Out of memory!\n");
+ free(ven);
+ free(dev);
+ return 1;
+ }
msg_ginfo("%s", s);
for (i = strlen(s); i < maxtypelen; i++)
msg_ginfo(" ");
@@ -425,10 +444,10 @@ static void print_supported_boards_helper(const struct board_info *boards,
}
#endif
-static void print_supported_devs(const struct programmer_entry prog, const char *const type)
+static void print_supported_devs(const struct programmer_entry *const prog, const char *const type)
{
- const struct dev_entry *const devs = prog.devs.dev;
- msg_ginfo("\nSupported %s devices for the %s programmer:\n", type, prog.name);
+ const struct dev_entry *const devs = prog->devs.dev;
+ msg_ginfo("\nSupported %s devices for the %s programmer:\n", type, prog->name);
unsigned int maxvendorlen = strlen("Vendor") + 1;
unsigned int maxdevlen = strlen("Device") + 1;
@@ -474,17 +493,16 @@ int print_supported(void)
list_programmers_linebreak(0, 80, 0);
msg_ginfo("\n");
#if CONFIG_INTERNAL == 1
- msg_ginfo("\nSupported devices for the %s programmer:\n\n",
- programmer_table[PROGRAMMER_INTERNAL].name);
+ msg_ginfo("\nSupported devices for the internal programmer:\n\n");
print_supported_chipsets();
msg_ginfo("\n");
print_supported_boards_helper(boards_known, "mainboards");
msg_ginfo("\n");
print_supported_boards_helper(laptops_known, "mobile devices");
#endif
- for (i = 0; i < PROGRAMMER_INVALID; i++) {
- const struct programmer_entry prog = programmer_table[i];
- switch (prog.type) {
+ for (i = 0; i < programmer_table_size; i++) {
+ const struct programmer_entry *const prog = programmer_table[i];
+ switch (prog->type) {
case USB:
print_supported_devs(prog, "USB");
break;
@@ -492,688 +510,97 @@ int print_supported(void)
print_supported_devs(prog, "PCI");
break;
case OTHER:
- if (prog.devs.note != NULL) {
- msg_ginfo("\nSupported devices for the %s programmer:\n", prog.name);
- msg_ginfo("%s", prog.devs.note);
+ if (prog->devs.note != NULL) {
+ msg_ginfo("\nSupported devices for the %s programmer:\n", prog->name);
+ msg_ginfo("%s", prog->devs.note);
}
break;
default:
msg_gerr("\n%s: %s: Uninitialized programmer type! Please report a bug at "
- "flashrom@flashrom.org\n", __func__, prog.name);
+ "flashrom@flashrom.org\n", __func__, prog->name);
break;
}
}
return 0;
}
-#if CONFIG_INTERNAL == 1
+static void print_sysinfo(void)
+{
+#if IS_WINDOWS
+ SYSTEM_INFO si = { 0 };
+ OSVERSIONINFOEX osvi = { 0 };
+
+ msg_ginfo(" on Windows");
+ /* Tell Windows which version of the structure we want. */
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ if (GetVersionEx((OSVERSIONINFO*) &osvi))
+ msg_ginfo(" %lu.%lu", (unsigned long)osvi.dwMajorVersion,
+ (unsigned long)osvi.dwMinorVersion);
+ else
+ msg_ginfo(" unknown version");
+ GetSystemInfo(&si);
+ switch (si.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_AMD64:
+ msg_ginfo(" (x86_64)");
+ break;
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ msg_ginfo(" (x86)");
+ break;
+ default:
+ msg_ginfo(" (unknown arch)");
+ break;
+ }
+#elif HAVE_UTSNAME == 1
+ struct utsname osinfo;
-#ifdef CONFIG_PRINT_WIKI
-#define B(vendor, name, status, url, note) { vendor, name, status, url, note }
+ uname(&osinfo);
+ msg_ginfo(" on %s %s (%s)", osinfo.sysname, osinfo.release,
+ osinfo.machine);
#else
-#define B(vendor, name, status, url, note) { vendor, name, status }
+ msg_ginfo(" on unknown machine");
#endif
+}
-/* Please keep this list alphabetically ordered by vendor/board. */
-const struct board_info boards_known[] = {
-#if defined(__i386__) || defined(__x86_64__)
- B("A-Trend", "ATC-6220", OK, "http://www.motherboard.cz/mb/atrend/atc6220.htm", NULL),
- B("abit", "A-S78H", OK, NULL, NULL),
- B("abit", "AN-M2", OK, NULL, NULL),
- B("abit", "AV8", OK, NULL, NULL),
- B("abit", "AX8", OK, NULL, NULL),
- B("abit", "BF6", OK, NULL, NULL),
- B("abit", "BM6", OK, NULL, NULL),
- B("abit", "BX6 2.0", OK, NULL, NULL),
- B("abit", "Fatal1ty F-I90HD", OK, NULL, NULL),
- B("abit", "IC7", OK, NULL, NULL),
- B("abit", "IP35", OK, NULL, NULL),
- B("abit", "IP35 Pro", OK, NULL, NULL),
- B("abit", "IS-10", BAD, NULL, "Reported by deejkuba@aol.com to flashrom@coreboot.org, no public archive. Missing board enable and/or M50FW040 unlocking. May work now."),
- B("abit", "KN8 Ultra", OK, NULL, NULL),
- B("abit", "KN9 Ultra", OK, NULL, NULL),
- B("abit", "NF-M2 nView", OK, NULL, NULL),
- B("abit", "NF-M2S", OK, NULL, NULL),
- B("abit", "NF7-S", OK, NULL, NULL),
- B("abit", "VA6", OK, NULL, NULL),
- B("abit", "VT6X4", OK, NULL, NULL),
- B("Acer", "V75-M", OK, NULL, "This is an OEM board used by IBM in e.g. Aptiva 2170-G"),
- B("Acer", "EM61SM/EM61PM", OK, NULL, "Used in Acer Aspire T180 and E380. Seems to be an OEM variant of abit's NF-M2S."),
- B("Acorp", "6A815EPD", OK, "http://web.archive.org/web/20021206163652/www.acorp.com.tw/English/default.asp", NULL),
- B("Acorp", "6M810C", OK, NULL, NULL),
- B("ADLINK", "Express-HR", OK, "http://www.adlinktech.com/PD/web/PD_detail.php?pid=1012", NULL),
- B("Advantech", "PCM-5820", OK, "http://www.emacinc.com/sbc_pc_compatible/pcm_5820.htm", NULL),
- B("agami", "Aruma", OK, "http://web.archive.org/web/20080212111524/http://www.agami.com/site/ais-6000-series", NULL),
- B("Albatron", "PM266A Pro", OK, "http://www.albatron.com.tw/English/Product/MB/pro_detail.asp?rlink=Overview&no=56", NULL), /* FIXME */
- B("Alienware", "Aurora-R2", BAD, NULL, "Mainboard model is 0RV30W. Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("AOpen", "i945GMx-VFX", OK, NULL, "This is (also?) an OEM board from FSC (used in e.g. ESPRIMO Q5010 with designation D2544-B1)."),
- B("AOpen", "UK79G-1394", OK, "http://global.aopen.com/products_detail.aspx?auno=9", "Used in EZ18 barebones"),
- B("AOpen", "vKM400Am-S", OK, "http://global.aopen.com/products_detail.aspx?Auno=824", NULL),
- B("Artec Group","DBE61", OK, "http://wiki.thincan.org/DBE61", NULL),
- B("Artec Group","DBE62", OK, "http://wiki.thincan.org/DBE62", NULL),
- B("ASI", "MB-5BLMP", OK, "http://www.hojerteknik.com/winnet.htm", "Used in the IGEL WinNET III thin client."),
- B("ASRock", "4CoreDual-VSTA", OK, "http://www.asrock.com/mb/overview.asp?Model=4CoreDual-VSTA", "W39V040FB"),
- B("ASRock", "775Dual-VSTA", OK, "http://www.asrock.com/mb/overview.asp?Model=775Dual-VSTA", NULL),
- B("ASRock", "775i65G", OK, "http://www.asrock.com/mb/overview.asp?Model=775i65G", NULL),
- B("ASRock", "880G Pro3", OK, "http://www.asrock.com/mb/overview.asp?Model=880G%20Pro3", NULL),
- B("ASRock", "890GX Extreme3", OK, "http://www.asrock.com/mb/overview.asp?Model=890GX%20Extreme3", NULL),
- B("ASRock", "939A785GMH/128M", OK, "http://www.asrock.com/mb/overview.asp?Model=939A785GMH/128M", NULL),
- B("ASRock", "960GM-GS3 FX", OK, "http://www.asrock.com/mb/overview.asp?Model=960GM-GS3%20FX", NULL),
- B("ASRock", "A330GC", OK, "http://www.asrock.com/mb/overview.asp?Model=A330GC", NULL),
- B("ASRock", "A770CrossFire", OK, "http://www.asrock.com/mb/overview.asp?Model=A770CrossFire", NULL),
- B("ASRock", "A780FullHD", OK, "http://www.asrock.com/mb/overview.asp?Model=A780FullHD", "While flashrom is working correctly, there might be problems with the firmware images themselves. Please see https://flashrom.org/pipermail/flashrom/2012-July/009600.html for details."),
- B("ASRock", "ALiveNF6G-DVI", OK, "http://www.asrock.com/mb/overview.asp?Model=ALiveNF6G-DVI", NULL),
- B("ASRock", "AM2NF6G-VSTA", OK, "http://www.asrock.com/mb/overview.asp?Model=AM2NF6G-VSTA", NULL),
- B("ASRock", "AMCP7AION-HT", OK, "http://www.asrock.com/nettop/NVIDIA/ION%20330HT/", "Used in ION 330HT(-BD) barebones."),
- B("ASRock", "ConRoeXFire-eSATA2", OK, "http://www.asrock.com/mb/overview.asp?model=conroexfire-esata2", NULL),
- B("ASRock", "E350M1/USB3", OK, "http://www.asrock.com/mb/overview.asp?model=e350m1/usb3", "Vendor firmware writes to flash at shutdown. This probably corrupts the flash in case you write coreboot while running the vendor firmware. Simply updating the vendor firmware should be fine."),
- B("ASRock", "Fatal1ty 970 Performance", OK, "http://www.asrock.com/mb/overview.asp?Model=Fatal1ty%20970%20Performance", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASRock", "Fatal1ty Z77 Performance", BAD, "http://www.asrock.com/mb/overview.asp?Model=Fatal1ty%20Z77%20Performance", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASRock", "G31M-GS", OK, "http://www.asrock.com/mb/overview.asp?Model=G31M-GS", NULL),
- B("ASRock", "G31M-S rev 2.0", OK, "http://www.asrock.com/mb/overview.asp?model=G31M-S", NULL),
- B("ASRock", "G41M-VS3", OK, "http://www.asrock.com/mb/overview.asp?Model=G41M-VS3", NULL),
- B("ASRock", "H61M-ITX", BAD, "http://www.asrock.com/mb/overview.asp?Model=H61M-ITX", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASRock", "H67M", BAD, "http://www.asrock.com/mb/overview.asp?Model=H67M", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASRock", "IMB-180-H", OK, "http://www.asrock.com/ipc/overview.asp?Model=IMB-A180-H", NULL),
- B("ASRock", "K7S41", OK, "http://www.asrock.com/mb/overview.asp?Model=K7S41", NULL),
- B("ASRock", "K7S41GX", OK, "http://www.asrock.com/mb/overview.asp?Model=K7S41GX", NULL),
- B("ASRock", "K7VT4A+", BAD, "http://www.asrock.com/mb/overview.asp?Model=K7VT4A%2b", "No chip found, probably due to flash translation. https://flashrom.org/pipermail/flashrom/2009-August/000393.html"),
- B("ASRock", "K8S8X", OK, "http://www.asrock.com/mb/overview.asp?Model=K8S8X", NULL),
- B("ASRock", "M3A790GXH/128M", OK, "http://www.asrock.com/mb/overview.asp?Model=M3A790GXH/128M", NULL),
- B("ASRock", "N61P-S", OK, "http://www.asrock.com/mb/overview.asp?Model=N61P-S", NULL),
- B("ASRock", "N68C-S UCC", OK, "http://www.asrock.com/mb/overview.asp?Model=N68C-S%20UCC", NULL),
- B("ASRock", "P4i65G", OK, "http://www.asrock.com/mb/overview.asp?Model=P4i65G", NULL),
- B("ASRock", "P4i65GV", OK, "http://www.asrock.com/mb/overview.asp?Model=P4i65GV", NULL),
- B("ASRock", "Z68 Extreme4", BAD, "http://www.asrock.com/mb/overview.asp?Model=Z68%20Extreme4", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "A7N8X Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7N8X_Deluxe/", NULL),
- B("ASUS", "A7N8X-E Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7N8XE_Deluxe/", NULL),
- B("ASUS", "A7N8X-VM/400", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7N8XVM400/", NULL),
- B("ASUS", "A7V133", OK, NULL, NULL),
- B("ASUS", "A7V333", OK, NULL, NULL),
- B("ASUS", "A7V400-MX", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V400MX/", NULL),
- B("ASUS", "A7V600-X", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V600X/", NULL),
- B("ASUS", "A7V8X", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V8X/", NULL),
- B("ASUS", "A7V8X-MX", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V8XMX/", NULL),
- B("ASUS", "A7V8X-MX SE", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V8XMX_SE/", NULL),
- B("ASUS", "A7V8X-X", OK, "https://www.asus.com/Motherboards/AMD_Socket_A/A7V8XX/", NULL),
- B("ASUS", "A8M2N-LA (NodusM3-GL8E)", OK, "http://h10010.www1.hp.com/ewfrf/wc/document?docname=c00757531&cc=us&dlc=en&lc=en", "This is an OEM board from HP, the HP name is NodusM3-GL8E."),
- B("ASUS", "A8N-E", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NE/", NULL),
- B("ASUS", "A8N-LA (Nagami-GL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?lc=en&cc=us&docname=c00647121&dlc=en", "This is an OEM board from HP, the HP name is Nagami-GL8E."),
- B("ASUS", "A8N-SLI", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NSLI/", NULL),
- B("ASUS", "A8N-SLI Deluxe", NT, NULL, "Should work out of the box since r1593."),
- B("ASUS", "A8N-SLI Premium", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NSLI_Premium/", NULL),
- B("ASUS", "A8N-VM", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NVM/", NULL),
- B("ASUS", "A8N-VM CSM", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8NVM_CSM/", NULL),
- B("ASUS", "A8NE-FM/S", OK, "http://www.hardwareschotte.de/hardware/preise/proid_1266090/preis_ASUS+A8NE-FM", NULL),
- B("ASUS", "A8V Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8V_Deluxe/", NULL),
- B("ASUS", "A8V-E Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8VE_Deluxe/", NULL),
- B("ASUS", "A8V-E SE", OK, "https://www.asus.com/Motherboards/AMD_Socket_939/A8VE_SE/", "See http://www.coreboot.org/pipermail/coreboot/2007-October/026496.html"),
- B("ASUS", "C60M1-I", OK, "https://www.asus.com/Motherboards/C60M1I/", "The MAC address of the onboard network card is stored in flash."),
- B("ASUS", "Crosshair II Formula", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/Crosshair_II_Formula/", NULL),
- B("ASUS", "Crosshair IV Extreme", OK, "https://www.asus.com/Motherboards/AMD_AM3/Crosshair_IV_Extreme/", NULL),
- B("ASUS", "CUSL2-C", OK, NULL, "The image provided by ASUS is only 256 kB big and has to be written to the upper 256 kB of the 512 kB chip."),
- B("ASUS", "DSAN-DX", NT, "https://www.asus.com/Server_Workstation/Server_Motherboards/DSANDX/", NULL),
- B("ASUS", "E35M1-I DELUXE", OK, "https://www.asus.com/Motherboards/AMD_CPU_on_Board/E35M1I_DELUXE/", NULL),
- B("ASUS", "F1A75-V PRO", OK, "https://www.asus.com/Motherboard/F1A75V_PRO/", NULL),
- B("ASUS", "F2A85-M", DEP, "https://www.asus.com/Motherboards/F2A85M/", "UEFI builds v6404 and above disable access to some parts of the flash, cf. http://www.coreboot.org/ASUS_F2A85-M#UEFI_builds_that_allow_flash_chip_access"),
- B("ASUS", "K8N", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8N/", NULL),
- B("ASUS", "K8V", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8V/", NULL),
- B("ASUS", "K8V SE Deluxe", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8V_SE_Deluxe/", NULL),
- B("ASUS", "K8V-X", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8VX/", NULL),
- B("ASUS", "K8V-X SE", OK, "https://www.asus.com/Motherboards/AMD_Socket_754/K8VX_SE/", NULL),
- B("ASUS", "KFSN4-DRE/SAS", OK, "https://www.asus.com/Server_Workstation/Server_Motherboards/KFSN4DRESAS/", NULL),
- B("ASUS", "M2A-MX", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2AMX/", NULL),
- B("ASUS", "M2A-VM (HDMI)", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2AVM/", NULL),
- B("ASUS", "M2N32-SLI Deluxe", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2N32SLI_DeluxeWireless_Edition/", NULL),
- B("ASUS", "M2N68-VM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M2N68VM/", NULL),
- B("ASUS", "M2NBP-VM CSM", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NBPVM_CSM/", NULL),
- B("ASUS", "M2N-E", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NE/", "If the machine doesn't come up again after flashing, try resetting the NVRAM(CMOS). The MAC address of the onboard network card will change to the value stored in the new image, so backup the old address first. See https://flashrom.org/pipermail/flashrom/2009-November/000879.html"),
- B("ASUS", "M2N-E SLI", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NE_SLI/", NULL),
- B("ASUS", "M2N-MX SE Plus", OK, "https://www.asus.com/Motherboards/M2NMX_SE_Plus/", NULL),
- B("ASUS", "M2NPV-VM", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NPVVM/", NULL),
- B("ASUS", "M2N-SLI Deluxe", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2NSLI_Deluxe/", NULL),
- B("ASUS", "M2V", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2V/", NULL),
- B("ASUS", "M2V-MX", OK, "https://www.asus.com/Motherboards/AMD_AM2/M2VMX/", NULL),
- B("ASUS", "M3A", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3A/", NULL),
- B("ASUS", "M3A76-CM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3A76CM/", NULL),
- B("ASUS", "M3A78-EH", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3A78EH/", NULL),
- B("ASUS", "M3A78-EM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3A78EM/", NULL),
- B("ASUS", "M3N78 PRO", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3N78_PRO/", NULL),
- B("ASUS", "M3N78-VM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M3N78VM/", NULL),
- B("ASUS", "M3N-H/HDMI", OK, "https://www.asus.com/Motherboards/M3NHHDMI//", NULL),
- B("ASUS", "M4A785TD-M EVO", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A785TDM_EVO/", NULL),
- B("ASUS", "M4A785TD-V EVO", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A785TDV_EVO/", NULL),
- B("ASUS", "M4A785T-M", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A785TM/", NULL),
- B("ASUS", "M4A78-EM", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M4A78EM/", NULL),
- B("ASUS", "M4A78LT-M LE", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A78LTM_LE/", NULL),
- B("ASUS", "M4A79T Deluxe", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A79T_Deluxe/", NULL),
- B("ASUS", "M4A87TD/USB3", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A87TDUSB3/", NULL),
- B("ASUS", "M4A89GTD PRO", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4A89GTD_PRO/", NULL),
- B("ASUS", "M4N68T V2", OK, "https://www.asus.com/Motherboards/AMD_AM3/M4N68T_V2/", NULL),
- B("ASUS", "M4N78 PRO", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M4N78_PRO/", NULL),
- B("ASUS", "M4N78 SE", OK, "https://www.asus.com/Motherboards/AMD_AM2Plus/M4N78_SE/", NULL),
- B("ASUS", "M5A78L-M LX", OK, "https://www.asus.com/Motherboards/AMD_AM3Plus/M5A78LM_LX/", "The MAC address of the onboard LAN NIC is stored in flash, hence overwritten by flashrom; see https://flashrom.org/pipermail/flashrom/2012-May/009200.html"),
- B("ASUS", "M5A97 (rev. 1.0)", OK, "https://www.asus.com/Motherboard/M5A97/", NULL),
- B("ASUS", "M5A99X EVO", OK, "https://www.asus.com/Motherboards/AMD_AM3Plus/M5A99X_EVO/", NULL),
- B("ASUS", "Maximus IV Extreme", BAD, "https://www.asus.com/Motherboards/Intel_Socket_1155/Maximus_IV_Extreme/", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "MEW-AM", BAD, NULL, "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
- B("ASUS", "MEW-VM", BAD, "http://www.elhvb.com/mboards/OEM/HP/manual/ASUS%20MEW-VM.htm", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
- B("ASUS", "OPLX-M", NT, NULL, "Untested board enable."),
- B("ASUS", "P2B", OK, NULL, NULL),
- B("ASUS", "P2B-D", OK, NULL, NULL),
- B("ASUS", "P2B-DS", OK, NULL, NULL),
- B("ASUS", "P2B-F", OK, NULL, NULL),
- B("ASUS", "P2B-LS", OK, NULL, NULL),
- B("ASUS", "P2B-N", OK, NULL, NULL),
- B("ASUS", "P2E-M", OK, NULL, NULL),
- B("ASUS", "P2L97-S", OK, NULL, NULL),
- B("ASUS", "P3B-F", OK, NULL, "Owned by Uwe Hermann <uwe@hermann-uwe.de>."),
- B("ASUS", "P4B266", OK, NULL, NULL),
- B("ASUS", "P4B266-LM", OK, "http://esupport.sony.com/US/perl/swu-list.pl?mdl=PCVRX650", NULL),
- B("ASUS", "P4B533-E", OK, NULL, NULL),
- B("ASUS", "P4C800-E Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4C800E_Deluxe/", NULL),
- B("ASUS", "P4GV-LA (Guppy)", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00363478", NULL),
- B("ASUS", "P4P800", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4P800/", NULL),
- B("ASUS", "P4P800-E Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4P800E_Deluxe/", NULL),
- B("ASUS", "P4P800-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4P800VM/", NULL),
- B("ASUS", "P4P800-X", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4P800X/", NULL),
- B("ASUS", "P4P800SE", OK, "https://www.asus.com/supportonly/P4P800 SE/", NULL),
- B("ASUS", "P4PE-X/TE", NT, "https://www.asus.com/999/html/events/mb/socket478/p4pe-x-te/overview.htm", NULL),
- B("ASUS", "P4S533-X", OK, NULL, NULL),
- B("ASUS", "P4S800-MX", OK, "https://www.asus.com/Motherboards/Intel_Socket_478/P4S800MX/", NULL),
- B("ASUS", "P4SC-E", OK, NULL, "Part of ASUS Terminator P4 533 barebone system"),
- B("ASUS", "P4SD-LA", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00022505", NULL),
- B("ASUS", "P5A", OK, NULL, NULL),
- B("ASUS", "P5B", OK, NULL, NULL),
- B("ASUS", "P5B-Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5B_Deluxe/", NULL),
- B("ASUS", "P5B-VM", OK, NULL, NULL),
- B("ASUS", "P5BV-M", BAD, NULL, "Reported by Bernhard M. Wiedemann <bernhard@uml12d.zq1.de> to flashrom@coreboot.org, no public archive. Missing board enable and/or SST49LF008A unlocking. May work now."),
- B("ASUS", "P5BV-R", OK, "https://www.asus.com/Server_Workstation/Servers/RS120E5PA2/", "Used in RS120-E5/PA2 servers."),
- B("ASUS", "P5GC-MX/1333", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GCMX1333/", NULL),
- B("ASUS", "P5GD1 Pro", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GD1_PRO/", NULL),
- B("ASUS", "P5GD1-VM/S", OK, NULL, "This is an OEM board from FSC. Although flashrom supports it and can probably not distinguish it from the P5GD1-VM, please note that the P5GD1-VM BIOS does not support the FSC variants completely."),
- B("ASUS", "P5GD1(-VM)", NT, NULL, "Untested board enable."),
- B("ASUS", "P5GD2 Premium", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GD2_Premium/", NULL),
- B("ASUS", "P5GD2-X", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GD2X/", NULL),
- B("ASUS", "P5GDC Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GDC_Deluxe/", NULL),
- B("ASUS", "P5GDC-V Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5GDCV_Deluxe/", NULL),
- B("ASUS", "P5GD2/C variants", NT, NULL, "Untested board enable."),
- B("ASUS", "P5K SE", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5K_SE/", NULL),
- B("ASUS", "P5K-V", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KV/", NULL),
- B("ASUS", "P5K-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KVM/", NULL),
- B("ASUS", "P5KC", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KC/", NULL),
- B("ASUS", "P5KPL-AM IN/GB", OK, "http://support.asus.com/download.aspx?SLanguage=en&m=P5KPL-AM+IN%2fGB&os=29", NULL),
- B("ASUS", "P5KPL-CM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KPLCM/", NULL),
- B("ASUS", "P5KPL-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5KPLVM/", "Found in V3-P5G31."),
- B("ASUS", "P5L-MX", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5LMX/", NULL),
- B("ASUS", "P5L-VM 1394", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5LVM_1394/", NULL),
- B("ASUS", "P5LD2", OK, NULL, NULL),
- B("ASUS", "P5LD2-MQ", OK, "http://support.asus.com/download.aspx?SLanguage=en&p=8&s=12&m=Vintage-PH2&os=&hashedid=n/a", "Found in ASUS Vintage-PH2 barebones."),
- B("ASUS", "P5LD2-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5LD2VM/", NULL),
- B("ASUS", "P5LD2-VM DH", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5LD2VM_DH/", NULL),
- B("ASUS", "P5LP-LE (Lithium-UL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00379616&tmp_task=prodinfoCategory&cc=us&dlc=en&lc=en&product=1159887", "This is an OEM board from HP."),
- B("ASUS", "P5LP-LE (Epson OEM)", OK, NULL, "This is an OEM board from Epson (e.g. Endeavor MT7700)."),
- B("ASUS", "P5LP-LE", NT, NULL, "This designation is used for OEM boards from HP, Epson and maybe others. The HP names vary and not all of them have been tested yet. Please report any success or failure, thanks."),
- B("ASUS", "P5N-D", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5ND/", NULL),
- B("ASUS", "P5N-E SLI", NT, "https://www.asus.com/Motherboards/Intel_Socket_775/P5NE_SLI/", "Untested board enable."),
- B("ASUS", "P5N32-E SLI", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5N32E_SLI/", NULL),
- B("ASUS", "P5N7A-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5N7AVM/", NULL),
- B("ASUS", "P5ND2-SLI Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5ND2SLI_Deluxe/", NULL),
- B("ASUS", "P5PE-VM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5PEVM/", NULL),
- B("ASUS", "P5QPL-AM", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5QPLAM/", NULL),
- B("ASUS", "P5VD1-X", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5VD1X/", NULL),
- B("ASUS", "P5VD2-MX", OK, "https://www.asus.com/Motherboards/Intel_Socket_775/P5VD2MX/", "The MAC address of the onboard LAN NIC is stored in flash, hence overwritten by flashrom; see https://flashrom.org/pipermail/flashrom/2012-March/009014.html"),
- B("ASUS", "P6T SE", OK, "https://www.asus.com/Motherboards/Intel_Socket_1366/P6T_SE/", NULL),
- B("ASUS", "P6T Deluxe", OK, "https://www.asus.com/Motherboards/Intel_Socket_1366/P6T_Deluxe/", NULL),
- B("ASUS", "P6T Deluxe V2", OK, "https://www.asus.com/Motherboards/Intel_Socket_1366/P6T_Deluxe_V2/", NULL),
- B("ASUS", "P7H57D-V EVO", OK, "https://www.asus.com/Motherboards/Intel_Socket_1156/P7H57DV_EVO/", NULL),
- B("ASUS", "P7H55-M LX", BAD, NULL, "flashrom works correctly, but GbE LAN is nonworking (probably due to a missing/bogus MAC address; see https://flashrom.org/pipermail/flashrom/2011-July/007432.html and http://ubuntuforums.org/showthread.php?t=1534389 for a possible workaround)"),
- B("ASUS", "P8B-E/4L", BAD, NULL, "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8B WS", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8B75-M LE", BAD, NULL, "Probing works (2x 8192 kB via hwseq), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8H61 PRO", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8H61-M LE/USB3", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8H67-M PRO", BAD, NULL, "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."), // some firmware versions apparently are not locked, see report by Marek Zakrzewski
- B("ASUS", "P8H77-I", OK, "https://www.asus.com/Motherboards/P8H77I/", NULL),
- B("ASUS", "P8H77-M", OK, "https://www.asus.com/Motherboards/P8H77M/", NULL),
- B("ASUS", "P8H77-V LE", OK, "https://www.asus.com/Motherboards/P8H77V_LE/", NULL),
- B("ASUS", "P8P67 (rev. 3.1)", BAD, NULL, "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8P67 LE (B2)", OK, NULL, NULL),
- B("ASUS", "P8P67 LE (B3)", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8P67 PRO (rev. 3.0)", OK, "https://www.asus.com/Motherboards/Intel_Socket_1155/P8P67_PRO/", NULL),
- B("ASUS", "P8P67-M PRO", BAD, NULL, "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8Z68-V", OK, "https://www.asus.com/Motherboards/Intel_Socket_1155/P8Z68V/", "Warning: MAC address of LOM is stored at 0x1000 - 0x1005 of the image."),
- B("ASUS", "P8Z68-V LE", BAD, NULL, "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8Z68-V PRO", BAD, NULL, "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ASUS", "P8Z68-V PRO/GEN3", OK, "https://www.asus.com/Motherboards/Intel_Socket_1155/P8Z68V_PROGEN3/", "Warning: MAC address of LOM is stored at 0x1000 - 0x1005 of the image."),
- B("ASUS", "RAMPAGE III GENE", OK, "https://www.asus.com/Motherboards/RAMPAGE_III_GENE/", "The MAC address of the onboard network card is stored in flash."),
- B("ASUS", "SABERTOOTH 990FX", OK, "https://www.asus.com/Motherboards/AMD_AM3Plus/SABERTOOTH_990FX/", NULL),
- B("ASUS", "SABERTOOTH 990FX R2.0", OK, "https://www.asus.com/Motherboards/AMD_AM3Plus/SABERTOOTH_990FX_R20/", NULL),
- B("ASUS", "TUSL2-C", NT, "http://support.asus.com/download.aspx?SLanguage=en&p=1&s=4&m=TUSL2-C&os=&hashedid=n/a", "Untested board enable."),
- B("ASUS", "Z8NA-D6C", OK, "https://www.asus.com/Server_Workstation/Server_Motherboards/Z8NAD6C/", NULL),
- B("ASUS", "Z8PE-D12", OK, "https://www.asus.com/Server_Workstation/Server_Motherboards/Z8PED12/", NULL),
- B("Attro", "G5G100-P", OK, "http://www.attro.com/motherboard/G5G100-P.htm", NULL),
- B("Bachmann", "OT200", OK, "http://www.bachmann.info/produkte/bedien-und-beobachtungsgeraete/operator-terminals/", NULL),
- B("BCOM", "WinNET100", OK, "http://www.coreboot.org/BCOM_WINNET100", "Used in the IGEL-316 thin client."),
- B("Bifferos", "Bifferboard", OK, "http://bifferos.co.uk/", NULL),
- B("Biostar", "H61MGC", BAD, NULL, "Probing works (Eon EN25Q32(A/B), 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Biostar", "H61MU3", BAD, NULL, "Probing works (Eon EN25Q32(A/B), 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Biostar", "M6TBA", BAD, "ftp://ftp.biostar-usa.com/manuals/M6TBA/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
- B("Biostar", "M7NCD Pro", OK, "http://www.biostar.com.tw/app/en/mb/introduction.php?S_ID=260", NULL),
- B("Biostar", "M7VIQ", NT, NULL, NULL),
- B("Biostar", "N61PB-M2S", OK, NULL, NULL),
- B("Biostar", "N68S3+", OK, NULL, NULL),
- B("Biostar", "P4M80-M4", OK, "http://www.biostar-usa.com/mbdetails.asp?model=p4m80-m4", NULL),
- B("Biostar", "TA780G M2+", OK, "http://www.biostar.com.tw/app/en/mb/introduction.php?S_ID=344", NULL),
- B("Biostar", "TA790GX A3+", OK, "http://www.biostar.com.tw/app/en/mb/introduction.php?S_ID=395", NULL),
- B("Boser", "HS-6637", BAD, "http://www.boser.com.tw/manual/HS-62376637v3.4.pdf", "Reported by Mark Robinson <mark@zl2tod.net> to flashrom@coreboot.org, no public archive. Missing board enable and/or F29C51002T unlocking. May work now."),
- B("Congatec", "conga-X852", OK, "http://www.congatec.com/single_news+M57715f6263d.html?&L=1", NULL),
- B("Dell", "Inspiron 580", BAD, "http://support.dell.com/support/edocs/systems/insp580/en/index.htm", "Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
- B("Dell", "OptiPlex 7010", BAD, NULL, "Mainboard model is 0KRC95. Probing works (Hardware Sequencing 4 + 8MB), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
- B("Dell", "OptiPlex GX1", OK, "http://support.dell.com/support/edocs/systems/ban_gx1/en/index.htm", NULL),
- B("Dell", "PowerEdge 1850", OK, "http://support.dell.com/support/edocs/systems/pe1850/en/index.htm", NULL),
- B("Dell", "PowerEdge C6220", BAD, NULL, "Mainboard model is 0HYFFG. Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and there are even overlapping PRs)."),
- B("Dell", "Vostro 460", BAD, "http://support.dell.com/support/edocs/systems/vos460/en/index.htm", "Mainboard model is 0Y2MRG. Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
- B("DFI", "855GME-MGF", BAD, "http://www.dfi.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?action=e&downloadType=&windowstate=normal&mode=view&downloadFlag=false&itemId=433", "Probably needs a board enable. http://www.coreboot.org/pipermail/coreboot/2009-May/048549.html"),
- B("DFI", "AD77", NT, NULL, "Untested board enable."),
- B("DFI", "Blood-Iron P35 T2RL", OK, "http://lp.lanparty.com.tw/portal/CM/cmproduct/XX_cmproddetail/XX_WbProdsWindow?itemId=516&downloadFlag=false&action=1", NULL),
- B("Elitegroup", "848P-A7", OK, NULL, NULL),
- B("Elitegroup", "GeForce6100PM-M2 (V3.0)", OK, NULL, NULL),
- B("Elitegroup", "GeForce6100SM-M", OK, NULL, NULL),
- B("Elitegroup", "GeForce7050M-M (V2.0)", OK, "http://www.ecs.com.tw/ECSWebSite/Product/Product_Detail.aspx?DetailID=865&MenuID=20&LanID=0", NULL),
- B("Elitegroup", "GF7050VT-M", OK, NULL, NULL),
- B("Elitegroup", "GF7100PVT-M3 (V1.0)", OK, NULL, NULL),
- B("Elitegroup", "GF8200A", OK, NULL, NULL),
- B("Elitegroup", "K7S5A", OK, NULL, NULL),
- B("Elitegroup", "K7S6A", OK, NULL, NULL),
- B("Elitegroup", "K7SEM (V1.0A)", OK, NULL, NULL),
- B("Elitegroup", "K7VTA3", OK, NULL, NULL),
- B("Elitegroup", "P4M800PRO-M (V1.0A, V2.0)", OK, NULL, NULL),
- B("Elitegroup", "P4VXMS (V1.0A)", OK, NULL, NULL),
- B("Elitegroup", "P6BAP-A+ (V2.2)", OK, NULL, NULL),
- B("Elitegroup", "P6IWP-Fe", OK, NULL, NULL),
- B("Elitegroup", "P6VAP-A+", OK, NULL, NULL),
- B("Elitegroup", "RS485M-M", OK, NULL, NULL),
- B("Emerson", "ATCA-7360", OK, "http://www.emerson.com/sites/Network_Power/en-US/Products/Product_Detail/Product1/Pages/EmbCompATCA-7360.aspx", NULL),
- B("EPoX", "EP-3PTA", BAD, NULL, "Missing board enable (W83627HF/F/HG/G), see https://flashrom.org/pipermail/flashrom/2012-April/009043.html"),
- B("EPoX", "EP-8K5A2", OK, "http://www.epox.com/product.asp?ID=EP-8K5A2", NULL),
- B("EPoX", "EP-8NPA7I", OK, "http://www.epox.com/product.asp?ID=EP-8NPA7I", NULL),
- B("EPoX", "EP-8RDA3+", OK, "http://www.epox.com/product.asp?ID=EP-8RDA3plus", NULL),
- B("EPoX", "EP-9NPA7I", OK, "http://www.epox.com/product.asp?ID=EP-9NPA7I", NULL),
- B("EPoX", "EP-BX3", OK, "http://www.epox.com/product.asp?ID=EP-BX3", NULL),
- B("EVGA", "122-CK-NF68", OK, NULL, NULL),
- B("EVGA", "132-CK-NF78", OK, "http://www.evga.com/articles/385.asp", NULL),
- B("EVGA", "270-WS-W555-A2 (Classified SR-2)", OK, "http://www.evga.com/products/moreInfo.asp?pn=270-WS-W555-A2", NULL),
- B("FIC", "VA-502", BAD, "ftp://ftp.fic.com.tw/motherboard/manual/socket7/va-502/", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. Seems the PCI subsystem IDs are identical with the Tekram P6Pro-A5. May work now."),
- B("Foxconn", "6150K8MD-8EKRSH", OK, "http://www.foxconnchannel.com/ProductDetail.aspx?T=Motherboard&U=en-us0000157", NULL),
- B("Foxconn", "A6VMX", OK, "http://www.foxconnchannel.com/ProductDetail.aspx?T=Motherboard&U=en-us0000346", NULL),
- B("Foxconn", "P4M800P7MA-RS2", OK, "http://www.foxconnchannel.com/ProductDetail.aspx?T=Motherboard&U=en-us0000138", NULL),
- B("Foxconn", "P55MX", OK, "http://www.foxconnchannel.com/ProductDetail.aspx?T=motherboard&U=en-us0000474", "Needs the MFG jumper to be set correctly before flashing to enable the Flash Descriptor Override Strap."),
- B("Foxconn", "Q45M", BAD, "http://www.foxconnchannel.com/ProductDetail.aspx?T=Motherboard&U=en-us0000587", "Probing works (Hardware sequencing, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
- B("Freetech", "P6F91i", OK, "http://web.archive.org/web/20010417035034/http://www.freetech.com/prod/P6F91i.html", NULL),
- B("Fujitsu", "D2724-A1x", OK, NULL, "Used in ESPRIMO E5625."),
- B("Fujitsu", "D3041-A1x", OK, NULL, "Used in ESPRIMO P2560, contains an Atmel AT26DF081A."),
- B("Fujitsu-Siemens", "CELSIUS W410", BAD, "ftp://ftp.ts.fujitsu.com/pub/mainboard-oem-sales/Products/Mainboards/Industrial&ExtendedLifetime/D3061&D3062/", "Mainboard model is D3062-A1. Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
- B("Fujitsu-Siemens", "ESPRIMO P5915", OK, "http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/professionalpc/ESPRIMO/P/EsprimoP5915-6.htm", "Mainboard model is D2312-A2."),
- B("GIGABYTE", "GA-2761GXDK", OK, "http://www.computerbase.de/news/hardware/mainboards/amd-systeme/2007/mai/gigabyte_dtx-mainboard/", NULL),
- B("GIGABYTE", "GA-6BXC", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1445", NULL),
- B("GIGABYTE", "GA-6BXDU", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1429", NULL),
- B("GIGABYTE", "GA-6IEM", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1379", NULL),
- B("GIGABYTE", "GA-6VXE7+", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2410", NULL),
- B("GIGABYTE", "GA-6ZMA", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1541", NULL),
- B("GIGABYTE", "GA-770TA-UD3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3272", NULL),
- B("GIGABYTE", "GA-7DXR", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1302", NULL),
- B("GIGABYTE", "GA-7VT600", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1666", NULL),
- B("GIGABYTE", "GA-7ZM", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1366", "Works fine if you remove jumper JP9 on the board and disable the flash protection BIOS option."),
- B("GIGABYTE", "GA-880GMA-USB3 (rev. 3.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3817", NULL),
- B("GIGABYTE", "GA-8I945GZME-RH", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2304", NULL),
- B("GIGABYTE", "GA-8IP775", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1830", NULL),
- B("GIGABYTE", "GA-8IRML", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1343", NULL),
- B("GIGABYTE", "GA-8PE667 Ultra 2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1607", NULL),
- B("GIGABYTE", "GA-8S648", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1674", NULL),
- B("GIGABYTE", "GA-8SIMLFS 2.0", OK, NULL, "This is an OEM board used by Fujitsu."),
- B("GIGABYTE", "GA-8SIMLH", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1399", NULL),
- B("GIGABYTE", "GA-945GCM-S2 (rev. 3.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2466", NULL),
- B("GIGABYTE", "GA-945GM-S2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2331", NULL),
- B("GIGABYTE", "GA-945PL-S3P (rev. 6.6)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2541", NULL),
- B("GIGABYTE", "GA-965GM-S2 (rev. 2.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2617", NULL),
- B("GIGABYTE", "GA-965P-DS4", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2288", NULL),
- B("GIGABYTE", "GA-965P-S3 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2321", NULL),
- B("GIGABYTE", "GA-970A-D3P (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4642", NULL),
- B("GIGABYTE", "GA-970A-UD3P (rev. 2.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=5194", "Primary flash chip is a Macronix MX25L3206E."),
- B("GIGABYTE", "GA-990FXA-UD3 (rev. 4.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4672", NULL),
- B("GIGABYTE", "GA-A75M-UD2H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3928", NULL),
- B("GIGABYTE", "GA-B85M-D3H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4567", NULL),
- B("GIGABYTE", "GA-EG43M-S2H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2878", NULL),
- B("GIGABYTE", "GA-EP31-DS3L (rev. 1.0, 2.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2964", NULL),
- B("GIGABYTE", "GA-EP35-DS3L", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2778", NULL),
- B("GIGABYTE", "GA-EX58-UD4P", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2986", NULL),
- B("GIGABYTE", "GA-G33M-S2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2557", NULL),
- B("GIGABYTE", "GA-G33M-S2L", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2692", NULL),
- B("GIGABYTE", "GA-G41MT-S2PT", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3960", NULL),
- B("GIGABYTE", "GA-H55M-S2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3509", "8 MB (ME) + 1 MB (BIOS) flash chips - hardware sequencing required."),
- B("GIGABYTE", "GA-H61M-D2-B3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3773", NULL),
- B("GIGABYTE", "GA-H61M-D2H-USB3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4004", NULL),
- B("GIGABYTE", "GA-H77-D3H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4141", "Does only work with -p internal:ich_spi_mode=hwseq due to an evil twin of MX25L6405 and ICH SPI lockdown."),
- B("GIGABYTE", "GA-H77-DS3H (rev. 1.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4318", NULL),
- B("GIGABYTE", "GA-H77M-D3H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4388", NULL),
- B("GIGABYTE", "GA-J1900N-D3V", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4918", NULL),
- B("GIGABYTE", "GA-K8N51GMF-9", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1939", NULL),
- B("GIGABYTE", "GA-K8N51GMF", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1950", NULL),
- B("GIGABYTE", "GA-K8N-SLI", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1928", NULL),
- B("GIGABYTE", "GA-K8NS", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=1784", NULL),
- B("GIGABYTE", "GA-M56S-S3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2607", NULL),
- B("GIGABYTE", "GA-M57SLI-S4", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2287", NULL),
- B("GIGABYTE", "GA-M61P-S3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2434", NULL),
- B("GIGABYTE", "GA-M720-US3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3006", NULL),
- B("GIGABYTE", "GA-MA69VM-S2", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2500", NULL),
- B("GIGABYTE", "GA-MA74GM-S2H (rev. 3.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3152", NULL),
- B("GIGABYTE", "GA-MA770-UD3 (rev. 2.1)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3302", NULL),
- B("GIGABYTE", "GA-MA770T-UD3P", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3096", NULL),
- B("GIGABYTE", "GA-MA780G-UD3H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3004", NULL),
- B("GIGABYTE", "GA-MA785GMT-UD2H (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3156", NULL),
- B("GIGABYTE", "GA-MA78G-DS3H (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2800", NULL),
- B("GIGABYTE", "GA-MA78GM-S2H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2758", NULL), /* TODO: Rev. 1.BAD, 1.OK, or 2.x? */
- B("GIGABYTE", "GA-MA78GPM-DS2H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2859", NULL),
- B("GIGABYTE", "GA-MA790FX-DQ6", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2690", NULL),
- B("GIGABYTE", "GA-MA790GP-DS4H", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2887", NULL),
- B("GIGABYTE", "GA-MA790XT-UD4P (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3010", NULL),
- B("GIGABYTE", "GA-P31-DS3L", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2615", NULL),
- B("GIGABYTE", "GA-P31-S3G", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=2676", NULL),
- B("GIGABYTE", "GA-P55-USB3 (rev. 2.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3440", NULL),
- B("GIGABYTE", "GA-P55A-UD4 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3436", NULL),
- B("GIGABYTE", "GA-P55A-UD7" , OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3324", NULL),
- B("GIGABYTE", "GA-P67A-UD3P", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3649", NULL),
- B("GIGABYTE", "GA-X58A-UD3R (rev. 2.0)", OK, NULL, NULL),
- B("GIGABYTE", "GA-X58A-UD7 (rev. 2.0)", OK, NULL, NULL),
- B("GIGABYTE", "GA-X79-UD5", OK, NULL, NULL),
- B("GIGABYTE", "GA-X79-UD3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4050", "Contains a Macronix MX25L6406E."),
- B("GIGABYTE", "GA-X79-UP4 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4288", NULL),
- B("GIGABYTE", "GA-Z68MA-D2H-B3 (rev. 1.3)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3975", NULL),
- B("GIGABYTE", "GA-Z68MX-UD2H-B (rev. 1.3)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3854", NULL),
- B("GIGABYTE", "GA-Z68XP-UD3 (rev. 1.0)", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=3892", NULL),
- B("GIGABYTE", "GA-Z77MX-D3H", BAD, "http://www.gigabyte.com/products/product-page.aspx?pid=4145", "Uses MX25L6436E and requires a small patch (but works flawlessly with that)."),
- B("GIGABYTE", "GA-Z87-HD3", OK, "http://www.gigabyte.com/products/product-page.aspx?pid=4489", NULL),
- B("HP", "8100 Elite CMT PC (304Bh)", BAD, NULL, "SPI lock down, PR, read-only descriptor, locked ME region."),
- B("HP", "e-Vectra P2706T", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?lang=en&cc=us&prodSeriesId=77515&prodTypeId=12454", NULL),
- B("HP", "Evans-GL6 (Pegatron IPMEL-AE)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?cc=us&lc=en&dlc=en&docname=c01925513", "Found in HP Pavilion Slimline s5220f."),
- B("HP", "ProLiant DL145 G3", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00816835&lang=en&cc=us&taskId=101&prodSeriesId=3219755&prodTypeId=15351", NULL),
- B("HP", "ProLiant DL165 G6", OK, "http://h10010.www1.hp.com/wwpc/us/en/sm/WF05a/15351-15351-3328412-241644-3328421-3955644.html", NULL),
- B("HP", "ProLiant N40L", OK, NULL, NULL),
- B("HP", "Puffer2-UL8E", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00300023", NULL),
- B("HP", "dc7800", BAD, "http://h10010.www1.hp.com/wwpc/us/en/sm/WF06a/12454-12454-64287-321860-3328898-3459241.html?dnr=1", "ICH9DO with SPI lock down, BIOS lock, PR, read-only descriptor, locked ME region."),
- B("HP", "Vectra VL400", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00060658&lang=en&cc=us", NULL),
- B("HP", "Vectra VL420 SFF", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00060661&lang=en&cc=us", NULL),
- B("HP", "xw4400 (0A68h)", BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c00775230", "ICH7 with SPI lock down, BIOS lock, flash block detection (SST25VF080B); see http://paste.flashrom.org/view.php?id=686"),
- B("HP", "xw6400", BAD, NULL, "No chip found, see https://flashrom.org/pipermail/flashrom/2012-March/009006.html"),
- B("HP", "xw9300", BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?lang=en&cc=us&prodTypeId=12454&prodSeriesId=459226", "Missing board enable, see https://flashrom.org/pipermail/flashrom/2012-March/008885.html"),
- B("HP", "xw9400", OK, "http://h20000.www2.hp.com/bizsupport/TechSupport/Home.jsp?lang=en&cc=us&prodSeriesId=3211286&prodTypeId=12454", "Boot block is write protected unless the solder points next to F2 are shorted."),
- B("HP", "Z400 Workstation (0AE4h)", BAD, NULL, "ICH10R with BIOS lock enable and a protected range PRBAD, see https://flashrom.org/pipermail/flashrom/2012-June/009350.html"),
- B("IBASE", "MB899", OK, "http://www.ibase-i.com.tw/2009/mb899.html", NULL),
- B("IBM", "x3455", OK, "http://www-03.ibm.com/systems/x/hardware/rack/x3455/index.html", NULL),
- B("IEI", "PICOe-9452", OK, "http://www.ieiworld.com/product_groups/industrial/content.aspx?keyword=WSB&gid=00001000010000000001&cid=08125380291060861658&id=08142308605814597144", NULL),
- B("Intel", "D201GLY", OK, "http://www.intel.com/support/motherboards/desktop/d201gly/index.htm", NULL),
- B("Intel", "D2700MUD", BAD, "http://www.intel.com/cd/products/services/emea/eng/motherboards/desktop/D2700MUD/", "SMM protection enabled"),
- B("Intel", "D425KT", BAD, "http://www.intel.com/content/www/us/en/motherboards/desktop-motherboards/desktop-board-d425kt.html", "NM10 with SPI lock down, BIOS lock, see https://flashrom.org/pipermail/flashrom/2012-January/008600.html"),
- B("Intel", "D865GLC", BAD, NULL, "ICH5 with BIOS lock enable, see http://paste.flashrom.org/view.php?id=775"),
- B("Intel", "D945GCNL", OK, NULL, NULL),
- B("Intel", "DG45ID", BAD, "http://www.intel.com/products/desktop/motherboards/dg45id/dg45id-overview.htm", "Probing works (Winbond W25x32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked."),
- B("Intel", "DQ965GF", BAD, NULL, "Probing enables Hardware Sequencing (behind that hides a SST SST25VF016B, 2048 kB). Parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and the platform data region seems to be bogus)."),
- B("Intel", "DG965OT", BAD, NULL, "Probing enables Hardware Sequencing (behind that hides a SST SST25VF080B, 1024 kB). Parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME is locked (and the platform data region seems to be bogus)."),
- B("Intel", "DH61AG ", BAD, NULL, "H61 with BIOS lock enable and locked ME region, see https://flashrom.org/pipermail/flashrom/2012-June/009417.html"),
- B("Intel", "DH67CF", BAD, NULL, "H67 with BIOS lock enable and locked ME region, see https://flashrom.org/pipermail/flashrom/2011-September/007789.html"),
- B("Intel", "DH67CL", BAD, NULL, "H67 with BIOS lock enable and locked ME region, see https://flashrom.org/pipermail/flashrom/2012-November/010112.html"),
- B("Intel", "DN2800MT (Marshalltown)", BAD, NULL, "BIOS locked via BIOS_CNTL."),
- B("Intel", "DQ45CB", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Intel", "DQ77MK", BAD, NULL, "Q77 with BIOS lock enable and locked ME region, see http://paste.flashrom.org/view.php?id=1603"),
- B("Intel", "EP80759", OK, NULL, NULL),
- B("Intel", "Foxhollow", OK, NULL, "Intel reference board."),
- B("Intel", "Greencity", OK, NULL, "Intel reference board."),
- B("Intel", "SE440BX-2", BAD, "http://downloadcenter.intel.com/SearchResult.aspx?lang=eng&ProductFamily=Desktop+Boards&ProductLine=Discontinued+Motherboards&ProductProduct=Intel%C2%AE+SE440BX-2+Motherboard", "Probably won't work, see http://www.coreboot.org/pipermail/flashrom/2010-July/003952.html"),
- B("IWILL", "DK8-HTX", OK, "http://web.archive.org/web/20060507170150/http://www.iwill.net/product_2.asp?p_id=98", NULL),
- B("Jetway", "J-7BXAN", OK, "http://www.jetway.com.tw/evisn/download/d7BXAS.htm", NULL),
- B("Jetway", "J7F4K1G5D-PB", OK, "http://www.jetway.com.tw/jw/ipcboard_view.asp?productid=282&proname=J7F4K1G5D", NULL),
- B("Kontron", "986LCD-M", OK, "http://de.kontron.com/products/boards+and+mezzanines/embedded+motherboards/miniitx+motherboards/986lcdmmitx.html", NULL),
- B("Lanner", "EM-8510C", OK, NULL, NULL),
- B("Lenovo", "Tilapia CRB", OK, NULL, "Used in ThinkCentre M75e."),
- B("Lex", "CV700A", OK, "http://www.lex.com.tw/product/CV700A-spec.htm", NULL),
- B("Mitac", "6513WU", OK, "http://web.archive.org/web/20050313054828/http://www.mitac.com/micweb/products/tyan/6513wu/6513wu.htm", NULL),
- B("MSC", "Q7-TCTC", OK, "http://www.msc-ge.com/en/produkte/com/moduls/overview/5779-www.html", NULL),
- B("MSI", "MS-6153", OK, "http://www.msi.com/product/mb/MS-6153.html", NULL),
- B("MSI", "MS-6156", OK, "http://uk.ts.fujitsu.com/rl/servicesupport/techsupport/boards/Motherboards/MicroStar/Ms6156/MS6156.htm", NULL),
- B("MSI", "MS-6163 (MS-6163 Pro)",OK, "http://www.msi.com/product/mb/MS-6163-Pro.html", NULL),
- B("MSI", "MS-6178", BAD, "http://www.msi.com/product/mb/MS-6178.html", "Immediately powers off if you try to hot-plug the chip. However, this does '''not''' happen if you use coreboot. Owned by Uwe Hermann <uwe@hermann-uwe.de>."),
- B("MSI", "MS-6330 (K7T Turbo)", OK, "http://www.msi.com/product/mb/K7T-Turbo.html", NULL),
- B("MSI", "MS-6391 (845 Pro4)", OK, "http://www.msi.com/product/mb/845-Pro4.html", NULL),
- B("MSI", "MS-6561 (745 Ultra)", OK, "http://www.msi.com/product/mb/745-Ultra.html", NULL),
- B("MSI", "MS-6566 (845 Ultra-C)",OK, "http://www.msi.com/product/mb/845-Ultra-C.html", NULL),
- B("MSI", "MS-6570 (K7N2)", OK, "http://www.msi.com/product/mb/K7N2.html", NULL),
- B("MSI", "MS-6577 (Xenon)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?product=90390&lc=en&cc=us&dlc=en&docname=bph07843", "This is an OEM board from HP, the HP name is Xenon."),
- B("MSI", "MS-6590 (KT4 Ultra)", OK, "http://www.msi.com/product/mb/KT4-Ultra.html", NULL),
- //B("MSI", "MS-6702E (K8T Neo2-F/FIR)",OK, "http://www.msi.com/product/mb/K8T-Neo2-F--FIR.html", NULL), This was wrongly attributed to the MS-7094 board enable.
- B("MSI", "MS-6704 (845PE Max2 PCB 1.0)", OK, "http://www.msi.com/product/mb/845PE-Max2.html", "Write protection must be disabled in the BIOS setup."),
- B("MSI", "MS-6712 (KT4V)", OK, "http://www.msi.com/product/mb/KT4V---KT4V-L--v1-0-.html", NULL),
- B("MSI", "MS-6787 (P4MAM-V/P4MAM-L)", OK, "http://www.msi.com/service/search/?kw=6787&type=product", NULL),
- B("MSI", "MS-7005 (651M-L)", OK, "http://www.msi.com/product/mb/651M-L.html", NULL),
- B("MSI", "MS-7025 (K8N Neo2 Platinum)", OK, "http://www.msi.com/product/mb/K8N-Neo2-Platinum.html", NULL),
- B("MSI", "MS-7030 (K8N Neo Platinum)", OK, "http://www.msi.com/product/mb/K8N-Neo-Platinum.html", NULL),
- B("MSI", "MS-7046", OK, "http://www.heimir.de/ms7046/", NULL),
- B("MSI", "MS-7061 (KM4M-V/KM4AM-V)", OK, "http://www.msi.com/service/search/?kw=7061&type=product", NULL),
- B("MSI", "MS-7065", OK, "http://browse.geekbench.ca/geekbench2/view/53114", NULL),
- B("MSI", "MS-7094 (K8T Neo2-F V2.0)",OK, "http://www.msi.com/product/mb/K8T_Neo2F_V2.0.html", NULL),
- B("MSI", "MS-7125 (K8N Neo4(-F/-FI/-FX/Platinum))", OK, "http://www.msi.com/product/mb/K8N_Neo4_Platinum_PCB_1.0.html", NULL),
- B("MSI", "MS-7135 (K8N Neo3)", OK, "http://www.msi.com/product/mb/K8N-Neo3.html", NULL),
- B("MSI", "MS-7142 (K8MM-V)", OK, "http://www.msi.com/product/mb/K8MM-V.html", NULL),
- B("MSI", "MS-7168 (Orion)", OK, "http://support.packardbell.co.uk/uk/item/index.php?i=spec_orion&pi=platform_honeymoon_istart", NULL),
- B("MSI", "MS-7207 (K8NGM2-L)", OK, "http://www.msi.com/product/mb/K8NGM2-FID--IL--L.html", NULL),
- B("MSI", "MS-7211 (PM8M3-V)", OK, "http://www.msi.com/product/mb/PM8M3-V.html", NULL),
- B("MSI", "MS-7236 (945PL Neo3)", OK, "http://www.msi.com/product/mb/945PL-Neo3.html", NULL),
- B("MSI", "MS-7250 (K9N SLI (rev 2.1))", OK, "http://www.msi.com/product/mb/K9N--SLI.html", NULL),
- B("MSI", "MS-7253 (K9VGM-V)", OK, "http://www.msi.com/product/mb/K9VGM-V.html", NULL),
- B("MSI", "MS-7255 (P4M890M)", OK, "http://www.msi.com/product/mb/P4M890M-L-IL.html", NULL),
- B("MSI", "MS-7260 (K9N Neo PCB 1.0)", BAD, "http://www.msi.com/product/mb/K9N-Neo--PCB-1-0-.html", "Interestingly flashrom does not work when the vendor BIOS is booted, but it ''does'' work flawlessly when the machine is booted with coreboot. Owned by Uwe Hermann <uwe@hermann-uwe.de>."),
- B("MSI", "MS-7309 (K9N6SGM-V)", BAD, "http://www.msi.com/product/mb/K9N6SGM-V---K9N6PGM-FI---K9N6PGM-F.html", "Uses Fintek F71882F/F71883F/F71887 SPI-to-LPC translation."),
- B("MSI", "MS-7309 (K9N6PGM2-V2)", OK, "http://www.msi.com/product/mb/K9N6PGM2-V2.html", NULL),
- B("MSI", "MS-7312 (K9MM-V)", OK, "http://www.msi.com/product/mb/K9MM-V.html", NULL),
- B("MSI", "MS-7336", OK, NULL, "Some non-essential DMI data (e.g. serial numbers) is overwritten when using flashrom. This is an OEM board used by HP (e.g. dx2300 Microtower)."),
- B("MSI", "MS-7345 (P35 Neo2-FIR)", OK, "http://www.msi.com/product/mb/P35-Neo2-FR---FIR.html", NULL),
- B("MSI", "MS-7357 (G33M)", OK, "http://www.msi.com/product/mb/G33M.html", NULL),
- B("MSI", "MS-7368 (K9AG Neo2-Digital)", OK, "http://www.msi.com/product/mb/K9AG-Neo2-Digital.html", NULL),
- B("MSI", "MS-7369 (K9N Neo V2)", OK, "http://www.msi.com/product/mb/K9N-Neo-V2.html", NULL),
- B("MSI", "MS-7376 (K9A2 Platinum V1)", OK, "http://www.msi.com/product/mb/K9A2-Platinum.html", NULL),
- B("MSI", "MS-7379 (G31M)", OK, "http://www.msi.com/product/mb/G31M.html", NULL),
- B("MSI", "MS-7399 1.1 (Persian)", OK, "http://acersupport.com/acerpanam/desktop/0000/Acer/AspireM5640/AspireM5640sp2.shtml", "This is an OEM board used by Acer in e.g. Aspire M5640/M3640."),
- B("MSI", "MS-7502", OK, NULL, "This is an OEM board used by Medion in e.g. Medion MD8833."),
- B("MSI", "MS-7522 (MSI X58 Pro-E)", OK, "http://www.msi.com/product/mb/X58_ProE.html", NULL),
- B("MSI", "MS-7529 (G31M3-L(S) V2)", OK, "http://www.msi.com/product/mb/G31M3-L-V2---G31M3-LS-V2.html", NULL),
- B("MSI", "MS-7529 (G31TM-P21)", OK, "http://www.msi.com/product/mb/G31TM-P21.html", NULL),
- B("MSI", "MS-7548 (Aspen-GL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c01635688&lc=en&cc=us&dlc=en", NULL),
- B("MSI", "MS-7551 (KA780G)", OK, "http://www.msi.com/product/mb/KA780G.html", NULL),
- B("MSI", "MS-7596 (785GM-E51)", OK, "http://www.msi.com/product/mb/785GM-E51.html", NULL),
- B("MSI", "MS-7597 (GF615M-P33)", BAD, NULL, "Missing board enable/SIO support (Fintek F71889), see https://flashrom.org/pipermail/flashrom/2012-March/008956.html"),
- B("MSI", "MS-7599 (870-C45)", OK, "http://www.msi.com/product/mb/870-C45.html", NULL),
- B("MSI", "MS-7613 (Iona-GL8E)", BAD, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c02014355&lc=en&cc=dk&dlc=en&product=4348478", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("MSI", "MS-7635 (H55M-ED55)", BAD, "http://www.msi.com/product/mb/H55M-ED55.html", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("MSI", "MS-7640 (890FXA-GD70)",OK, "http://www.msi.com/product/mb/890FXA-GD70.html", NULL),
- B("MSI", "MS-7642 (890GXM-G65)", OK, "http://www.msi.com/product/mb/890GXM-G65.html", NULL),
- B("MSI", "MS-7676 (H67MA-ED55(B3))", OK, "http://www.msi.com/product/mb/H67MA-ED55--B3-.html", "Seems to work fine basically, but user reported (hopefully unrelated) buggy behavior of the board after a firmware upgrade. See https://flashrom.org/pipermail/flashrom/2012-January/008547.html"),
- B("MSI", "MS-7676 (Z68MA-G45 (B3))", OK, "http://www.msi.com/product/mb/Z68MA-G45--B3-.html", NULL),
- B("MSI", "MS-7696 (A75MA-G55)", OK, "http://www.msi.com/product/mb/A75MA-G55.html", NULL),
- B("MSI", "MS-7698 (E350IA-E45)", OK, "http://www.msi.com/product/mb/E350IA-E45.html", NULL),
- B("MSI", "MS-7740 (H61MA-E35(B3))", OK, "http://www.msi.com/product/mb/H61MA-E35--B3-.html", NULL),
- B("MSI", "MS-7756 (H77MA-G43)", OK, "http://www.msi.com/product/mb/H77MA-G43.html", NULL),
- B("MSI", "MS-7760 (X79A-GD45 (8D))", OK, "http://www.msi.com/product/mb/X79A-GD45-8D.html", NULL),
- B("MSI", "MS-7808 (B75MA-E33)", OK, "http://www.msi.com/product/mb/B75MA-E33.html", NULL),
- B("MSI", "MS-7816 (H87-G43)", OK, "http://www.msi.com/product/mb/H87-G43.html", NULL),
- B("MSI", "MS-7817 (H81M-E33)", OK, "http://www.msi.com/product/mb/H81ME33.html", NULL),
- B("MSI", "MS-9830 (IM-945GSE-A, A9830IMS)", OK, "http://www.msi.com/product/ipc/IM-945GSE-A.html", NULL),
- B("NEC", "PowerMate 2000", OK, "http://support.necam.com/mobilesolutions/hardware/Desktops/pm2000/celeron/", NULL),
- B("Nokia", "IP530", OK, NULL, NULL),
- B("Palit", "N61S", OK, NULL, NULL),
- B("PCCHIPS ", "M598LMR (V9.0)", OK, NULL, NULL),
- B("PCCHIPS ", "M863G (V5.1A)", OK, "http://www.pcchips.com.tw/PCCWebSite/Products/ProductsDetail.aspx?CategoryID=1&DetailID=343&DetailName=Feature&MenuID=1&LanID=0", NULL),
- B("PC Engines", "Alix.1c", OK, "http://pcengines.ch/alix1c.htm", NULL),
- B("PC Engines", "Alix.2c2", OK, "http://pcengines.ch/alix2c2.htm", NULL),
- B("PC Engines", "Alix.2c3", OK, "http://pcengines.ch/alix2c3.htm", NULL),
- B("PC Engines", "Alix.2d3", OK, "http://pcengines.ch/alix2d3.htm", NULL),
- B("PC Engines", "Alix.3c3", OK, "http://pcengines.ch/alix3c3.htm", NULL),
- B("PC Engines", "Alix.3d3", OK, "http://pcengines.ch/alix3d3.htm", NULL),
- B("PC Engines", "Alix.6f2", OK, "http://pcengines.ch/alix6f2.htm", NULL),
- B("PC Engines", "APU", OK, "http://pcengines.ch/apu.htm", NULL),
- B("PC Engines", "WRAP.2E", OK, "http://pcengines.ch/wrap2e1.htm", NULL),
- B("PCWARE", "APM80-D3", OK, "http://www.pcwarebr.com.br/produtos_mb_apm80-d3.php", "Probably manufactured by ASUS"),
- B("Pegatron", "IPP7A-CP", OK, NULL, NULL),
- B("Portwell", "PEB-4700VLA", OK, "http://www.portwell.com/products/detail.asp?CUSTCHAR1=PEB-4700VLA", NULL),
- B("RCA", "RM4100", OK, "http://www.settoplinux.org/index.php?title=RCA_RM4100", NULL),
- B("Samsung", "Polaris 32", OK, NULL, NULL),
- B("SAPPHIRE", "IPC-E350M1", OK, "http://www.sapphiretech.com/presentation/product/?pid=1034&lid=1", NULL),
- B("Shuttle", "AB61", OK, "http://www.shuttle.eu/_archive/older/de/ab61.htm", NULL),
- B("Shuttle", "AK31", OK, "http://www.motherboard.cz/mb/shuttle/AK31.htm", NULL),
- B("Shuttle", "AK38N", OK, "http://eu.shuttle.com/en/desktopdefault.aspx/tabid-36/558_read-9889/", NULL),
- B("Shuttle", "AV11V30", OK, NULL, NULL),
- B("Shuttle", "AV18E2", OK, "http://www.shuttle.eu/_archive/older/de/av18.htm", NULL),
- B("Shuttle", "FB61", OK, "http://www.shuttle.eu/_archive/older/en/fb61.htm#mainboardfb6", "Used in SB61G2 systems."),
- B("Shuttle", "FD37", OK, "http://www.shuttle.eu/products/discontinued/barebones/sd37p2/", NULL),
- B("Shuttle", "FH67", OK, "http://www.shuttle.eu/products/mini-pc/sh67h3/specification/", NULL),
- B("Shuttle", "FN25", OK, "http://www.shuttle.eu/products/discontinued/barebones/sn25p/?0=", NULL),
- B("Shuttle", "FN78S", OK, "http://www.shuttle.eu/products/discontinued/barebones/sn78sh7/", NULL),
- B("Shuttle", "X50/X50(B)", OK, "http://au.shuttle.com/product_detail_spec.jsp?PI=1241", NULL),
- B("Soyo", "SY-5VD", BAD, "http://www.soyo.com/content/Downloads/163/&c=80&p=464&l=English", "No public report found. Owned by Uwe Hermann <uwe@hermann-uwe.de>. May work now."),
- B("Soyo", "SY-6BA+ III", OK, "http://www.motherboard.cz/mb/soyo/SY-6BA+III.htm", NULL),
- B("Soyo", "SY-7VCA", OK, "http://www.tomshardware.com/reviews/12-socket-370-motherboards,196-15.html", NULL),
- B("Sun", "Blade x6250", OK, "http://www.sun.com/servers/blades/x6250/", NULL),
- B("Sun", "Fire x4150", BAD, "http://www.sun.com/servers/x64/x4150/", "No public report found. May work now."),
- B("Sun", "Fire x4200", BAD, "http://www.sun.com/servers/entry/x4200/", "No public report found. May work now."),
- B("Sun", "Fire x4540", BAD, "http://www.sun.com/servers/x64/x4540/", "No public report found. May work now."),
- B("Sun", "Fire x4600", BAD, "http://www.sun.com/servers/x64/x4600/", "No public report found. May work now."),
- B("Sun", "Ultra 40 M2", OK, "http://download.oracle.com/docs/cd/E19127-01/ultra40.ws/820-0123-13/intro.html", NULL),
- B("Supermicro", "A1SAi-2550F", OK, "http://www.supermicro.com/products/motherboard/Atom/X10/A1SAi-2550F.cfm", NULL),
- B("Supermicro", "H8QC8", OK, "http://www.supermicro.com/Aplus/motherboard/Opteron/nforce/H8QC8.cfm", NULL),
- B("Supermicro", "H8QME-2", OK, "http://www.supermicro.com/Aplus/motherboard/Opteron8000/MCP55/H8QME-2.cfm", NULL),
- B("Supermicro", "X10SLM-F", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C220/X10SLM-F.cfm", "Probing works (Winbond W25Q128, 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked; SMM protection enabled."),
- B("Supermicro", "X5DP8-G2", OK, "http://www.supermicro.com/products/motherboard/Xeon/E7501/X5DP8-G2.cfm", NULL),
- B("Supermicro", "X7DBT-INF", OK, "http://www.supermicro.com/products/motherboard/Xeon1333/5000P/X7DBT-INF.cfm", NULL),
- B("Supermicro", "X7DWT", OK, "http://www.supermicro.com/products/motherboard/Xeon1333/5400/X7DWT.cfm", "Used in Dell C6100 servers."),
- B("Supermicro", "X7SPA-H(F)", OK, "http://www.supermicro.com/products/motherboard/ATOM/ICH9/X7SPA.cfm?typ=H", NULL),
- B("Supermicro", "X7SPE-HF-D525", OK, "http://www.supermicro.com/products/motherboard/ATOM/ICH9/X7SPE-HF-D525.cfm", NULL),
- B("Supermicro", "X8DT3", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DT3.cfm", NULL),
- B("Supermicro", "X8DT6-F", OK, "http://www.supermicro.nl/products/motherboard/QPI/5500/X8DT6-F.cfm?IPMI=Y&SAS=Y", NULL),
- B("Supermicro", "X8DTE-F", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DT6-F.cfm?IPMI=Y&SAS=N", NULL),
- B("Supermicro", "X8DTG-D", OK, "http://www.supermicro.com/products/motherboard/qpi/5500/x8dtg-df.cfm", NULL),
- B("Supermicro", "X8DTH-6F", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTH-6F.cfm", NULL),
- B("Supermicro", "X8DTT-F", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTT-F.cfm", NULL),
- B("Supermicro", "X8DTT-HIBQF", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTT-H.cfm", NULL),
- B("Supermicro", "X8DTU-6TF+", BAD, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTU_.cfm?TYP=SAS&LAN=10", "Probing works (Atmel AT25DF321A, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Supermicro", "X8DTU-F", OK, "http://www.supermicro.com/products/motherboard/QPI/5500/X8DTU-F.cfm", NULL),
- B("Supermicro", "X8SAX", OK, "http://www.supermicro.com/products/motherboard/xeon3000/x58/x8sax.cfm", NULL),
- B("Supermicro", "X8SIE(-F)", BAD, "http://www.supermicro.com/products/motherboard/Xeon3000/3400/X8SIE.cfm?IPMI=N&TYP=LN2", "Requires unlocking the ME although the registers are set up correctly by the descriptor/BIOS already (tested with swseq and hwseq)."),
- B("Supermicro", "X8SIL-F", OK, "http://www.supermicro.com/products/motherboard/Xeon3000/3400/X8SIL.cfm", NULL),
- B("Supermicro", "X8STi", OK, "http://www.supermicro.com/products/motherboard/Xeon3000/X58/X8STi.cfm", NULL),
- B("Supermicro", "X9DR3-F", BAD, "http://www.supermicro.com/products/motherboard/xeon/c600/x9dr3-f.cfm", "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Supermicro", "X9DRD-7LN4F", BAD, "http://www.supermicro.com/products/motherboard/xeon/c600/x9drd-7ln4f.cfm", "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Supermicro", "X9DRT-HF+", BAD, NULL, "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked; SMM protection enabled."),
- B("Supermicro", "X9DRW", BAD, NULL, "Probing works (Numonyx N25Q128 (supported by SFDP only atm), 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Supermicro", "X9QRi-F+", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C600/X9QRi-F_.cfm", "Probing works (Macronix MX25L12805, 16384 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked; SMM protection enabled."),
- B("Supermicro", "X9SCA-F", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCA-F.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Supermicro", "X9SCE-F", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCE-F.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Supermicro", "X9SCL", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCL.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Supermicro", "X9SCM-F", BAD, "http://www.supermicro.com/products/motherboard/Xeon/C202_C204/X9SCM-F.cfm", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("T-Online", "S-100", OK, "http://wiki.freifunk-hannover.de/T-Online_S_100", NULL),
- B("Tekram", "P6Pro-A5", OK, "http://www.motherboard.cz/mb/tekram/P6Pro-A5.htm", NULL),
- B("Termtek", "TK-3370 (Rev:2.5B)", OK, NULL, NULL),
- B("Thomson", "IP1000", OK, "http://www.settoplinux.org/index.php?title=Thomson_IP1000", NULL),
- B("TriGem", "Anaheim-3", OK, "http://www.e4allupgraders.info/dir1/motherboards/socket370/anaheim3.shtml", NULL),
- B("TriGem", "Lomita", OK, "http://www.e4allupgraders.info/dir1/motherboards/socket370/lomita.shtml", NULL),
- B("Tyan", "S1846 (Tsunami ATX)", OK, "http://www.tyan.com/archive/products/html/tsunamiatx.html", NULL),
- B("Tyan", "S2466 (Tiger MPX)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=461", NULL),
- B("Tyan", "S2498 (Tomcat K7M)", OK, "http://www.tyan.com/archive/products/html/tomcatk7m.html", NULL),
- B("Tyan", "S2723 (Tiger i7501)", OK, "http://www.tyan.com/archive/products/html/tigeri7501.html", NULL),
- B("Tyan", "S2875 (Tiger K8W)", OK, "http://www.tyan.com/archive/products/html/tigerk8w.html", NULL),
- B("Tyan", "S2881 (Thunder K8SR)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=115", NULL),
- B("Tyan", "S2882-D (Thunder K8SD Pro)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=127", NULL),
- B("Tyan", "S2882 (Thunder K8S Pro)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=121", NULL),
- B("Tyan", "S2891 (Thunder K8SRE)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=144", NULL),
- B("Tyan", "S2892 (Thunder K8SE)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=145", NULL),
- B("Tyan", "S2895 (Thunder K8WE)", OK, "http://www.tyan.com/archive/products/html/thunderk8we.html", NULL),
- B("Tyan", "S2912 (Thunder n3600R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=157", NULL),
- B("Tyan", "S2915-E (Thunder n6650W)", OK, "http://tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=541&SKU=600000041", NULL),
- B("Tyan", "S2915 (Thunder n6650W)", OK, "http://tyan.com/product_board_detail.aspx?pid=163", NULL),
- B("Tyan", "S2933 (Thunder n3600S)", OK, "http://tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=478&SKU=600000063", NULL),
- B("Tyan", "S3095 (Tomcat i945GM)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=181", NULL),
- B("Tyan", "S3992 (Thunder h2000M)", OK, "http://tyan.com/product_board_detail.aspx?pid=235", NULL),
- B("Tyan", "S4882 (Thunder K8QS Pro)", OK, "http://www.tyan.com/archive/products/html/thunderk8qspro.html", NULL),
- B("Tyan", "S5180 (Toledo i965R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=456", NULL),
- B("Tyan", "S5191 (Toledo i3000R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=343", NULL),
- B("Tyan", "S5197 (Toledo i3010W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=349", NULL),
- B("Tyan", "S5211-1U (Toledo i3200R)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=593", NULL),
- B("Tyan", "S5211 (Toledo i3210W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=591", NULL),
- B("Tyan", "S5220 (Toledo q35T)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=597", NULL),
- B("Tyan", "S5375-1U (Tempest i5100X)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=610", NULL),
- B("Tyan", "S5375 (Tempest i5100X)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=566", NULL),
- B("Tyan", "S5376 (Tempest i5100W)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=605", "Both S5376G2NR and S5376WAG2NR should work."),
- B("Tyan", "S5377 (Tempest i5100T)", OK, "http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=642&SKU=600000017", NULL),
- B("Tyan", "S5382 (Tempest i5000PW)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=439", NULL),
- B("Tyan", "S5397 (Tempest i5400PW)", OK, "http://www.tyan.com/product_board_detail.aspx?pid=560", NULL),
- B("Tyan", "S7066 (S7066WGM3NR)", BAD, "http://www.tyan.com/product_SKU_spec.aspx?ProductType=MB&pid=790&SKU=600000330", "Probing works (Winbond W25Q64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("VIA", "EITX-3000", OK, "http://www.viaembedded.com/en/products/boards/810/1/EITX-3000.html", NULL),
- B("VIA", "EPIA M/MII/...", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=202", NULL), /* EPIA-MII link for now */
- B("VIA", "EPIA SP", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=261", NULL),
- B("VIA", "EPIA-CN", OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=400", NULL),
- B("VIA", "EPIA EK", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?motherboard_id=420", NULL),
- B("VIA", "EPIA-EX15000G", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=450", NULL),
- B("VIA", "EPIA-LN", OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=473", NULL),
- B("VIA", "EPIA-M700", OK, "http://via.com.tw/servlet/downloadSvl?motherboard_id=670&download_file_id=3700", NULL),
- B("VIA", "EPIA-N/NL", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=221", NULL), /* EPIA-N link for now */
- B("VIA", "EPIA-NX15000G", OK, "http://www.via.com.tw/en/products/embedded/ProductDetail.jsp?productLine=1&motherboard_id=470", NULL),
- B("VIA", "NAB74X0", OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=590", NULL),
- B("VIA", "pc2500e", OK, "http://www.via.com.tw/en/initiatives/empowered/pc2500_mainboard/index.jsp", NULL),
- B("VIA", "PC3500G", OK, "http://www.via.com.tw/en/initiatives/empowered/pc3500_mainboard/index.jsp", NULL),
- B("VIA", "VB700X", OK, "http://www.via.com.tw/en/products/mainboards/motherboards.jsp?motherboard_id=490", NULL),
- B("ZOTAC", "Fusion-ITX WiFi (FUSION350-A-E)", OK, NULL, NULL),
- B("ZOTAC", "GeForce 8200", OK, NULL, NULL),
- B("ZOTAC", "H61-ITX WiFi (H61ITX-A-E)", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ZOTAC", "H67-ITX WiFi (H67ITX-C-E)", BAD, NULL, "Probing works (Winbond W25Q32, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("ZOTAC", "IONITX-A-E", OK, NULL, NULL),
- B("ZOTAC", "IONITX-F-E", OK, NULL, NULL),
- B("ZOTAC", "nForce 630i Supreme (N73U-Supreme)", OK, NULL, NULL),
- B("ZOTAC", "ZBOX AD02 (PLUS)", OK, NULL, NULL),
- B("ZOTAC", "ZBOX HD-ID11", OK, NULL, NULL),
+void print_buildinfo(void)
+{
+ msg_gdbg("flashrom was built with");
+#ifdef __clang__
+ msg_gdbg(" LLVM Clang");
+#ifdef __clang_version__
+ msg_gdbg(" %s,", __clang_version__);
+#else
+ msg_gdbg(" unknown version (before r102686),");
#endif
-
- {0},
-};
-
-/* Please keep this list alphabetically ordered by vendor/board. */
-const struct board_info laptops_known[] = {
-#if defined(__i386__) || defined(__x86_64__)
- B("Acer", "Aspire 1520", OK, "http://support.acer.com/us/en/acerpanam/notebook/0000/Acer/Aspire1520/Aspire1520nv.shtml", NULL),
- B("Acer", "Aspire One", BAD, NULL, "http://www.coreboot.org/pipermail/coreboot/2009-May/048041.html"),
- B("ASUS", "A8Jm", OK, NULL, NULL),
- B("ASUS", "Eee PC 701 4G", BAD, "https://www.asus.com/Eee/Eee_PC/Eee_PC_4G/", "It seems the chip (25X40) is behind some SPI flash translation layer (likely in the EC, the ENE KB3310)."),
- B("ASUS", "M6Ne", NT, NULL, "Untested board enable."),
- B("ASUS", "U38N", OK, NULL, NULL),
- B("Clevo", "P150HM", BAD, "http://www.clevo.com.tw/en/products/prodinfo_2.asp?productid=307", "Probing works (Macronix MX25L3205, 4096 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs), ME region is locked."),
- B("Dell", "Latitude D630", OK, NULL, NULL),
- B("Dell", "Inspiron 1420", OK, NULL, NULL),
- B("Dell", "Latitude CPi A366XT", BAD, "http://www.coreboot.org/Dell_Latitude_CPi_A366XT", "The laptop immediately powers off if you try to hot-swap the chip. It's not yet tested if write/erase would work on this laptop."),
- B("Dell", "Vostro 3700", BAD, NULL, "Locked ME, see https://flashrom.org/pipermail/flashrom/2012-May/009197.html."),
- B("Dell", "Latitude E6520", BAD, NULL, "Locked ME, see https://flashrom.org/pipermail/flashrom/2012-June/009420.html."),
- B("Elitegroup", "A928", OK, NULL, "Bootsector is locked and needs to be skipped with a layout file (writeable address range is 00000000:0003bfff)."),
- B("Fujitsu", "Amilo Xi 3650", OK, NULL, NULL),
- B("HP/Compaq", "EliteBook 8560p", BAD, NULL, "SPI lock down, SMM protection, PR in BIOS region, read-only descriptor, locked ME region."),
- B("HP/Compaq", "nx9005", BAD, "http://h18000.www1.hp.com/products/quickspecs/11602_na/11602_na.HTML", "Shuts down when probing for a chip. https://flashrom.org/pipermail/flashrom/2010-May/003321.html"),
- B("HP/Compaq", "nx9010", BAD, "http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?lang=en&cc=us&objectID=c00348514", "Hangs upon '''flashrom -V''' (needs hard power-cycle then)."),
- B("IBM/Lenovo", "ThinkPad T40p", BAD, "http://www.thinkwiki.org/wiki/Category:T40p", NULL),
- B("IBM/Lenovo", "ThinkPad T410s", BAD, "http://www.thinkwiki.org/wiki/Category:T410s", "Probing works (Winbond W25X64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs) and ME is locked. Also, a Protected Range is locking the top range of the BIOS region (presumably the boot block)."),
- B("IBM/Lenovo", "ThinkPad T420", BAD, "http://www.thinkwiki.org/wiki/Category:T420", "Probing works (Macronix MX25L6405, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs) and ME is locked. Also, a Protected Range is locking the top range of the BIOS region (presumably the boot block)."),
- B("IBM/Lenovo", "ThinkPad X1", BAD, "http://www.thinkwiki.org/wiki/Category:X1", "Probing works (ST M25PX64, 8192 kB, SPI), but parts of the flash are problematic: descriptor is r/o (conforming to ICH reqs) and ME is locked. Also, a Protected Range is locking the top range of the BIOS region (presumably the boot block)."),
- B("IBM/Lenovo", "ThinkPad T530", DEP, "http://www.thinkwiki.org/wiki/Category:T530", "Works fine but only with coreboot (due to locked regions and additional PR restrictions)."),
- B("IBM/Lenovo", "ThinkPad 240", BAD, "http://www.stanford.edu/~bresnan//tp240.html", "Seems to (partially) work at first, but one block/sector cannot be written which then leaves you with a bricked laptop. Maybe this can be investigated and fixed in software later."),
- B("IBM/Lenovo", "3000 V100 TF05Cxx", OK, "http://www5.pc.ibm.com/europe/products.nsf/products?openagent&brand=Lenovo3000Notebook&series=Lenovo+3000+V+Series#viewallmodelstop", NULL),
- //B("MSI", "GT60-2OD", OK, "http://www.msi.com/product/nb/GT60_2OD.html", NULL), requires layout patches
- B("Teclast", "X98 Air 3G", OK, NULL, NULL),
+#elif defined(__GNUC__)
+ msg_gdbg(" GCC");
+#ifdef __VERSION__
+ msg_gdbg(" %s,", __VERSION__);
+#else
+ msg_gdbg(" unknown version,");
#endif
-
- {0},
-};
+#else
+ msg_gdbg(" unknown compiler,");
+#endif
+#if defined (__FLASHROM_LITTLE_ENDIAN__)
+ msg_gdbg(" little endian");
+#elif defined (__FLASHROM_BIG_ENDIAN__)
+ msg_gdbg(" big endian");
+#else
+#error Endianness could not be determined
#endif
+ msg_gdbg("\n");
+}
+
+void print_version(void)
+{
+ msg_ginfo("flashrom %s", flashrom_version_info());
+ print_sysinfo();
+ msg_ginfo("\n");
+}
+
+void print_banner(void)
+{
+ msg_ginfo("flashrom is free software, get the source code at "
+ "https://flashrom.org\n");
+ msg_ginfo("\n");
+}
diff --git a/print_wiki.c b/print_wiki.c
index b2ac65c91..a0cade9c1 100644
--- a/print_wiki.c
+++ b/print_wiki.c
@@ -80,7 +80,7 @@ chip), or that they do not yet work at all. If they do not work, support may \
or may not be added later.\n\n\
Mainboards (or individual revisions) which don't appear in the list may or may \
not work (we don't know, someone has to give it a try). Please report any \
-further verified mainboards on the [[Mailinglist|mailing list]].\n";
+further verified mainboards on the [[Contact#Mailing_List|mailing list]].\n";
#endif
static const char chip_th[] = "\
@@ -325,7 +325,7 @@ static void print_supported_chips_wiki(int cols)
"|| %s || {{%s}} || {{%s}} || {{%s}} || {{%s}}"
"|| %s || %s\n",
(c == 1) ? "eeeeee" : "dddddd", f->vendor, f->name,
- f->total_size, s,
+ f->total_size, s ? s : "?",
test_state_to_template(f->tested.probe),
test_state_to_template(f->tested.read),
test_state_to_template(f->tested.erase),
@@ -355,11 +355,11 @@ static int count_supported_devs_wiki(const struct dev_entry *devs)
return count;
}
-static void print_supported_devs_wiki_helper(const struct programmer_entry prog)
+static void print_supported_devs_wiki_helper(const struct programmer_entry *const prog)
{
int i = 0;
static int c = 0;
- const struct dev_entry *devs = prog.devs.dev;
+ const struct dev_entry *devs = prog->devs.dev;
const unsigned int count = count_supported_devs_wiki(devs);
/* Alternate colors if the vendor changes. */
@@ -368,7 +368,7 @@ static void print_supported_devs_wiki_helper(const struct programmer_entry prog)
for (i = 0; devs[i].vendor_id != 0; i++) {
printf("|- bgcolor=\"#%s\"\n", (c) ? "eeeeee" : "dddddd");
if (i == 0)
- printf("| rowspan=\"%u\" | %s |", count, prog.name);
+ printf("| rowspan=\"%u\" | %s |", count, prog->name);
printf("| %s || %s || %04x:%04x || {{%s}}\n", devs[i].vendor_name, devs[i].device_name,
devs[i].vendor_id, devs[i].device_id, test_state_to_template(devs[i].status));
}
@@ -380,14 +380,14 @@ static void print_supported_devs_wiki()
unsigned int usb_count = 0;
unsigned int i;
- for (i = 0; i < PROGRAMMER_INVALID; i++) {
- const struct programmer_entry prog = programmer_table[i];
- switch (prog.type) {
+ for (i = 0; i < programmer_table_size; i++) {
+ const struct programmer_entry *const prog = programmer_table[i];
+ switch (prog->type) {
case USB:
- usb_count += count_supported_devs_wiki(prog.devs.dev);
+ usb_count += count_supported_devs_wiki(prog->devs.dev);
break;
case PCI:
- pci_count += count_supported_devs_wiki(prog.devs.dev);
+ pci_count += count_supported_devs_wiki(prog->devs.dev);
break;
case OTHER:
default:
@@ -399,9 +399,9 @@ static void print_supported_devs_wiki()
"Total amount of supported PCI devices flashrom can use as a programmer: '''%d'''\n\n"
"{%s%s", pci_count, th_start, programmer_th);
- for (i = 0; i < PROGRAMMER_INVALID; i++) {
- const struct programmer_entry prog = programmer_table[i];
- if (prog.type == PCI) {
+ for (i = 0; i < programmer_table_size; i++) {
+ const struct programmer_entry *const prog = programmer_table[i];
+ if (prog->type == PCI) {
print_supported_devs_wiki_helper(prog);
}
}
@@ -411,9 +411,9 @@ static void print_supported_devs_wiki()
"Total amount of supported USB devices flashrom can use as a programmer: '''%d'''\n\n"
"{%s%s", usb_count, th_start, programmer_th);
- for (i = 0; i < PROGRAMMER_INVALID; i++) {
- const struct programmer_entry prog = programmer_table[i];
- if (prog.type == USB) {
+ for (i = 0; i < programmer_table_size; i++) {
+ const struct programmer_entry *const prog = programmer_table[i];
+ if (prog->type == USB) {
print_supported_devs_wiki_helper(prog);
}
}
@@ -424,13 +424,13 @@ static void print_supported_devs_wiki()
printf("! align=\"left\" | Programmer\n"
"! align=\"left\" | Note\n\n");
- for (i = 0; i < PROGRAMMER_INVALID; i++) {
+ for (i = 0; i < programmer_table_size; i++) {
static int c = 0;
- const struct programmer_entry prog = programmer_table[i];
- if (prog.type == OTHER && prog.devs.note != NULL) {
+ const struct programmer_entry *const prog = programmer_table[i];
+ if (prog->type == OTHER && prog->devs.note != NULL) {
c = !c;
printf("|- bgcolor=\"#%s\"\n", (c) ? "eeeeee" : "dddddd");
- printf("| %s || %s", prog.name, prog.devs.note);
+ printf("| %s || %s", prog->name, prog->devs.note);
}
}
printf("\n|}\n\n|}\n");
diff --git a/printlock.c b/printlock.c
new file mode 100644
index 000000000..f6eea7f46
--- /dev/null
+++ b/printlock.c
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2000 Silicon Integrated System Corporation
+ * Copyright (C) 2006 Giampiero Giancipoli <gianci@email.it>
+ * Copyright (C) 2006 coresystems GmbH <info@coresystems.de>
+ * Copyright (C) 2007-2012 Carl-Daniel Hailfinger
+ * Copyright (C) 2009 Sean Nelson <audiohacked@gmail.com>
+ * Copyright (C) 2014 Stefan Tauner
+ *
+ * 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 "flash.h"
+#include "chipdrivers.h"
+
+
+struct unlockblock {
+ unsigned int size;
+ unsigned int count;
+};
+
+typedef int (*unlockblock_func)(const struct flashctx *flash, chipaddr offset);
+static int regspace2_walk_unlockblocks(const struct flashctx *flash, const struct unlockblock *block, unlockblock_func func)
+{
+ chipaddr off = flash->virtual_registers + 2;
+ while (block->count != 0) {
+ unsigned int j;
+ for (j = 0; j < block->count; j++) {
+ if (func(flash, off))
+ return -1;
+ off += block->size;
+ }
+ block++;
+ }
+ return 0;
+}
+
+#define REG2_RWLOCK ((1 << 2) | (1 << 0))
+#define REG2_LOCKDOWN (1 << 1)
+#define REG2_MASK (REG2_RWLOCK | REG2_LOCKDOWN)
+
+static int printlock_regspace2_block(const struct flashctx *flash, chipaddr lockreg)
+{
+ uint8_t state = chip_readb(flash, lockreg);
+ msg_cdbg("Lock status of block at 0x%0*" PRIxPTR " is ", PRIxPTR_WIDTH, lockreg);
+ switch (state & REG2_MASK) {
+ case 0:
+ msg_cdbg("Full Access.\n");
+ break;
+ case 1:
+ msg_cdbg("Write Lock (Default State).\n");
+ break;
+ case 2:
+ msg_cdbg("Locked Open (Full Access, Locked Down).\n");
+ break;
+ case 3:
+ msg_cdbg("Write Lock, Locked Down.\n");
+ break;
+ case 4:
+ msg_cdbg("Read Lock.\n");
+ break;
+ case 5:
+ msg_cdbg("Read/Write Lock.\n");
+ break;
+ case 6:
+ msg_cdbg("Read Lock, Locked Down.\n");
+ break;
+ case 7:
+ msg_cdbg("Read/Write Lock, Locked Down.\n");
+ break;
+ }
+ return 0;
+}
+
+static int printlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
+{
+ const unsigned int elems = flash->chip->total_size * 1024 / block_size;
+ struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
+ return regspace2_walk_unlockblocks(flash, blocks, &printlock_regspace2_block);
+}
+
+int printlock_regspace2_uniform_64k(struct flashctx *flash)
+{
+ return printlock_regspace2_uniform(flash, 64 * 1024);
+}
+
+int printlock_regspace2_block_eraser_0(struct flashctx *flash)
+{
+ // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
+ const struct unlockblock *unlockblocks =
+ (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
+ return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
+}
+
+int printlock_regspace2_block_eraser_1(struct flashctx *flash)
+{
+ // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
+ const struct unlockblock *unlockblocks =
+ (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
+ return regspace2_walk_unlockblocks(flash, unlockblocks, &printlock_regspace2_block);
+}
+
+/* Try to change the lock register at address lockreg from cur to new.
+ *
+ * - Try to unlock the lock bit if requested and it is currently set (although this is probably futile).
+ * - Try to change the read/write bits if requested.
+ * - Try to set the lockdown bit if requested.
+ * Return an error immediately if any of this fails. */
+static int changelock_regspace2_block(const struct flashctx *flash, chipaddr lockreg, uint8_t cur, uint8_t new)
+{
+ /* Only allow changes to known read/write/lockdown bits */
+ if (((cur ^ new) & ~REG2_MASK) != 0) {
+ msg_cerr("Invalid lock change from 0x%02x to 0x%02x requested at 0x%0*" PRIxPTR "!\n"
+ "Please report a bug at flashrom@flashrom.org\n",
+ cur, new, PRIxPTR_WIDTH, lockreg);
+ return -1;
+ }
+
+ /* Exit early if no change (of read/write/lockdown bits) was requested. */
+ if (((cur ^ new) & REG2_MASK) == 0) {
+ msg_cdbg2("Lock bits at 0x%0*" PRIxPTR " not changed.\n", PRIxPTR_WIDTH, lockreg);
+ return 0;
+ }
+
+ /* Normally the lockdown bit can not be cleared. Try nevertheless if requested. */
+ if ((cur & REG2_LOCKDOWN) && !(new & REG2_LOCKDOWN)) {
+ chip_writeb(flash, cur & ~REG2_LOCKDOWN, lockreg);
+ cur = chip_readb(flash, lockreg);
+ if ((cur & REG2_LOCKDOWN) == REG2_LOCKDOWN) {
+ msg_cwarn("Lockdown can't be removed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
+ PRIxPTR_WIDTH, lockreg, cur);
+ return -1;
+ }
+ }
+
+ /* Change read and/or write bit */
+ if ((cur ^ new) & REG2_RWLOCK) {
+ /* Do not lockdown yet. */
+ uint8_t wanted = (cur & ~REG2_RWLOCK) | (new & REG2_RWLOCK);
+ chip_writeb(flash, wanted, lockreg);
+ cur = chip_readb(flash, lockreg);
+ if (cur != wanted) {
+ msg_cerr("Changing lock bits failed at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
+ PRIxPTR_WIDTH, lockreg, cur);
+ return -1;
+ }
+ msg_cdbg("Changed lock bits at 0x%0*" PRIxPTR " to 0x%02x.\n",
+ PRIxPTR_WIDTH, lockreg, cur);
+ }
+
+ /* Eventually, enable lockdown if requested. */
+ if (!(cur & REG2_LOCKDOWN) && (new & REG2_LOCKDOWN)) {
+ chip_writeb(flash, new, lockreg);
+ cur = chip_readb(flash, lockreg);
+ if (cur != new) {
+ msg_cerr("Enabling lockdown FAILED at 0x%0*" PRIxPTR "! New value: 0x%02x.\n",
+ PRIxPTR_WIDTH, lockreg, cur);
+ return -1;
+ }
+ msg_cdbg("Enabled lockdown at 0x%0*" PRIxPTR ".\n", PRIxPTR_WIDTH, lockreg);
+ }
+
+ return 0;
+}
+
+static int unlock_regspace2_block_generic(const struct flashctx *flash, chipaddr lockreg)
+{
+ uint8_t old = chip_readb(flash, lockreg);
+ /* We don't care for the lockdown bit as long as the RW locks are 0 after we're done */
+ return changelock_regspace2_block(flash, lockreg, old, old & ~REG2_RWLOCK);
+}
+
+static int unlock_regspace2_uniform(struct flashctx *flash, unsigned long block_size)
+{
+ const unsigned int elems = flash->chip->total_size * 1024 / block_size;
+ struct unlockblock blocks[2] = {{.size = block_size, .count = elems}};
+ return regspace2_walk_unlockblocks(flash, blocks, &unlock_regspace2_block_generic);
+}
+
+static int unlock_regspace2_uniform_64k(struct flashctx *flash)
+{
+ return unlock_regspace2_uniform(flash, 64 * 1024);
+}
+
+static int unlock_regspace2_uniform_32k(struct flashctx *flash)
+{
+ return unlock_regspace2_uniform(flash, 32 * 1024);
+}
+
+static int unlock_regspace2_block_eraser_0(struct flashctx *flash)
+{
+ // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
+ const struct unlockblock *unlockblocks =
+ (const struct unlockblock *)flash->chip->block_erasers[0].eraseblocks;
+ return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
+}
+
+static int unlock_regspace2_block_eraser_1(struct flashctx *flash)
+{
+ // FIXME: this depends on the eraseblocks not to be filled up completely (i.e. to be null-terminated).
+ const struct unlockblock *unlockblocks =
+ (const struct unlockblock *)flash->chip->block_erasers[1].eraseblocks;
+ return regspace2_walk_unlockblocks(flash, unlockblocks, &unlock_regspace2_block_generic);
+}
+
+blockprotect_func_t *lookup_jedec_blockprotect_func_ptr(const struct flashchip *const chip)
+{
+ switch (chip->unlock) {
+ case UNLOCK_REGSPACE2_BLOCK_ERASER_0: return unlock_regspace2_block_eraser_0;
+ case UNLOCK_REGSPACE2_BLOCK_ERASER_1: return unlock_regspace2_block_eraser_1;
+ case UNLOCK_REGSPACE2_UNIFORM_32K: return unlock_regspace2_uniform_32k;
+ case UNLOCK_REGSPACE2_UNIFORM_64K: return unlock_regspace2_uniform_64k;
+ default: return NULL; /* fallthough */
+ };
+}
diff --git a/programmer.c b/programmer.c
index bee60e386..15fd1b88b 100644
--- a/programmer.c
+++ b/programmer.c
@@ -17,87 +17,6 @@
#include "flash.h"
#include "programmer.h"
-/* Fallback map() for programmers which don't need special handling */
-void *fallback_map(const char *descr, uintptr_t phys_addr, size_t len)
-{
- /* FIXME: Should return phys_addr. */
- return NULL;
-}
-
-/* No-op/fallback unmap() for programmers which don't need special handling */
-void fallback_unmap(void *virt_addr, size_t len)
-{
-}
-
-/* Little-endian fallback for drivers not supporting 16 bit accesses */
-void fallback_chip_writew(const struct flashctx *flash, uint16_t val,
- chipaddr addr)
-{
- chip_writeb(flash, val & 0xff, addr);
- chip_writeb(flash, (val >> 8) & 0xff, addr + 1);
-}
-
-/* Little-endian fallback for drivers not supporting 16 bit accesses */
-uint16_t fallback_chip_readw(const struct flashctx *flash, const chipaddr addr)
-{
- uint16_t val;
- val = chip_readb(flash, addr);
- val |= chip_readb(flash, addr + 1) << 8;
- return val;
-}
-
-/* Little-endian fallback for drivers not supporting 32 bit accesses */
-void fallback_chip_writel(const struct flashctx *flash, uint32_t val,
- chipaddr addr)
-{
- chip_writew(flash, val & 0xffff, addr);
- chip_writew(flash, (val >> 16) & 0xffff, addr + 2);
-}
-
-/* Little-endian fallback for drivers not supporting 32 bit accesses */
-uint32_t fallback_chip_readl(const struct flashctx *flash, const chipaddr addr)
-{
- uint32_t val;
- val = chip_readw(flash, addr);
- val |= chip_readw(flash, addr + 2) << 16;
- return val;
-}
-
-void fallback_chip_writen(const struct flashctx *flash, const uint8_t *buf, chipaddr addr, size_t len)
-{
- size_t i;
- for (i = 0; i < len; i++)
- chip_writeb(flash, buf[i], addr + i);
- return;
-}
-
-void fallback_chip_readn(const struct flashctx *flash, uint8_t *buf,
- chipaddr addr, size_t len)
-{
- size_t i;
- for (i = 0; i < len; i++)
- buf[i] = chip_readb(flash, addr + i);
- return;
-}
-
-int register_par_master(const struct par_master *mst,
- const enum chipbustype buses)
-{
- struct registered_master rmst;
- if (!mst->chip_writeb || !mst->chip_writew || !mst->chip_writel ||
- !mst->chip_writen || !mst->chip_readb || !mst->chip_readw ||
- !mst->chip_readl || !mst->chip_readn) {
- msg_perr("%s called with incomplete master definition. "
- "Please report a bug at flashrom@flashrom.org\n",
- __func__);
- return ERROR_FLASHROM_BUG;
- }
-
- rmst.buses_supported = buses;
- rmst.par = *mst;
- return register_master(&rmst);
-}
-
/* The limit of 4 is totally arbitrary. */
#define MASTERS_MAX 4
struct registered_master registered_masters[MASTERS_MAX];
diff --git a/programmer_table.c b/programmer_table.c
new file mode 100644
index 000000000..79acd7794
--- /dev/null
+++ b/programmer_table.c
@@ -0,0 +1,184 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * 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 "programmer.h"
+
+const struct programmer_entry *const programmer_table[] = {
+
+#if CONFIG_INTERNAL == 1
+ &programmer_internal,
+#endif
+
+#if CONFIG_DUMMY == 1
+ &programmer_dummy,
+#endif
+
+#if CONFIG_NIC3COM == 1
+ &programmer_nic3com,
+#endif
+
+#if CONFIG_NICREALTEK == 1
+ &programmer_nicrealtek,
+#endif
+
+#if CONFIG_NICNATSEMI == 1
+ &programmer_nicnatsemi,
+#endif
+
+#if CONFIG_GFXNVIDIA == 1
+ &programmer_gfxnvidia,
+#endif
+
+#if CONFIG_RAIDEN_DEBUG_SPI == 1
+ &programmer_raiden_debug_spi,
+#endif
+
+#if CONFIG_DRKAISER == 1
+ &programmer_drkaiser,
+#endif
+
+#if CONFIG_SATASII == 1
+ &programmer_satasii,
+#endif
+
+#if CONFIG_ASM106X == 1
+ &programmer_asm106x,
+#endif
+
+#if CONFIG_ATAHPT == 1
+ &programmer_atahpt,
+#endif
+
+#if CONFIG_ATAVIA == 1
+ &programmer_atavia,
+#endif
+
+#if CONFIG_ATAPROMISE == 1
+ &programmer_atapromise,
+#endif
+
+#if CONFIG_IT8212 == 1
+ &programmer_it8212,
+#endif
+
+#if CONFIG_FT2232_SPI == 1
+ &programmer_ft2232_spi,
+#endif
+
+#if CONFIG_SERPROG == 1
+ &programmer_serprog,
+#endif
+
+#if CONFIG_BUSPIRATE_SPI == 1
+ &programmer_buspirate_spi,
+#endif
+
+#if CONFIG_DEDIPROG == 1
+ &programmer_dediprog,
+#endif
+
+#if CONFIG_DEVELOPERBOX_SPI == 1
+ &programmer_developerbox,
+#endif
+
+#if CONFIG_RAYER_SPI == 1
+ &programmer_rayer_spi,
+#endif
+
+#if CONFIG_PONY_SPI == 1
+ &programmer_pony_spi,
+#endif
+
+#if CONFIG_NICINTEL == 1
+ &programmer_nicintel,
+#endif
+
+#if CONFIG_NICINTEL_SPI == 1
+ &programmer_nicintel_spi,
+#endif
+
+#if CONFIG_NICINTEL_EEPROM == 1
+ &programmer_nicintel_eeprom,
+#endif
+
+#if CONFIG_OGP_SPI == 1
+ &programmer_ogp_spi,
+#endif
+
+#if CONFIG_SATAMV == 1
+ &programmer_satamv,
+#endif
+
+#if CONFIG_LINUX_MTD == 1
+ &programmer_linux_mtd,
+#endif
+
+#if CONFIG_LINUX_SPI == 1
+ &programmer_linux_spi,
+#endif
+
+#if CONFIG_PARADE_LSPCON == 1
+ &programmer_parade_lspcon,
+#endif
+
+#if CONFIG_MEDIATEK_I2C_SPI == 1
+ &programmer_mediatek_i2c_spi,
+#endif
+
+#if CONFIG_REALTEK_MST_I2C_SPI == 1
+ &programmer_realtek_mst_i2c_spi,
+#endif
+
+#if CONFIG_USBBLASTER_SPI == 1
+ &programmer_usbblaster_spi,
+#endif
+
+#if CONFIG_MSTARDDC_SPI == 1
+ &programmer_mstarddc_spi,
+#endif
+
+#if CONFIG_PICKIT2_SPI == 1
+ &programmer_pickit2_spi,
+#endif
+
+#if CONFIG_CH341A_SPI == 1
+ &programmer_ch341a_spi,
+#endif
+
+#if CONFIG_CH347_SPI == 1
+ &programmer_ch347_spi,
+#endif
+
+#if CONFIG_DIGILENT_SPI == 1
+ &programmer_digilent_spi,
+#endif
+
+#if CONFIG_JLINK_SPI == 1
+ &programmer_jlink_spi,
+#endif
+
+#if CONFIG_NI845X_SPI == 1
+ &programmer_ni845x_spi,
+#endif
+
+#if CONFIG_STLINKV3_SPI == 1
+ &programmer_stlinkv3_spi,
+#endif
+
+#if CONFIG_DIRTYJTAG_SPI == 1
+ &programmer_dirtyjtag_spi,
+#endif
+};
+
+const size_t programmer_table_size = ARRAY_SIZE(programmer_table);
diff --git a/raiden_debug_spi.c b/raiden_debug_spi.c
index bd7c054de..c5642ff43 100644
--- a/raiden_debug_spi.c
+++ b/raiden_debug_spi.c
@@ -343,13 +343,19 @@
#include "usb_device.h"
#include <libusb.h>
+#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-/* FIXME: Add some programmer IDs here */
-const struct dev_entry devs_raiden[] = {
+/*
+ * Table is empty as raiden_debug_spi matches against the class and
+ * subclass of the connected USB devices, rather than looking for a
+ * device with a specific vid:pid.
+ */
+static const struct dev_entry devs_raiden[] = {
{0},
};
@@ -398,6 +404,10 @@ enum usb_spi_error {
USB_SPI_UNKNOWN_ERROR = 0x8000,
};
+/* Corresponds with 'enum usb_spi_request' in,
+ * platform/cr50/chip/g/usb_spi.h and,
+ * platform/ec/chip/stm32/usb_spi.h.
+ */
enum raiden_debug_spi_request {
RAIDEN_DEBUG_SPI_REQ_ENABLE = 0x0000,
RAIDEN_DEBUG_SPI_REQ_DISABLE = 0x0001,
@@ -441,6 +451,7 @@ struct raiden_debug_spi_data {
*/
uint16_t max_spi_write_count;
uint16_t max_spi_read_count;
+ struct spi_master *spi_config;
};
/*
* USB permits a maximum bulk transfer of 64B.
@@ -881,7 +892,7 @@ static int send_command_v1(const struct flashctx *flash,
/* Reattempting will not result in a recovery. */
return status;
}
- programmer_delay(RETRY_INTERVAL_US);
+ default_delay(RETRY_INTERVAL_US);
continue;
}
@@ -916,7 +927,7 @@ static int send_command_v1(const struct flashctx *flash,
/* Reattempting will not result in a recovery. */
return status;
}
- programmer_delay(RETRY_INTERVAL_US);
+ default_delay(RETRY_INTERVAL_US);
}
}
@@ -951,7 +962,7 @@ static int get_spi_config_v2(struct raiden_debug_spi_data *ctx_data)
" config attempt = %d\n"
" status = 0x%05x\n",
config_attempt + 1, status);
- programmer_delay(RETRY_INTERVAL_US);
+ default_delay(RETRY_INTERVAL_US);
continue;
}
@@ -961,7 +972,7 @@ static int get_spi_config_v2(struct raiden_debug_spi_data *ctx_data)
" config attempt = %d\n"
" status = 0x%05x\n",
config_attempt + 1, status);
- programmer_delay(RETRY_INTERVAL_US);
+ default_delay(RETRY_INTERVAL_US);
continue;
}
@@ -982,6 +993,22 @@ static int get_spi_config_v2(struct raiden_debug_spi_data *ctx_data)
return status;
}
+ /*
+ * Check if we received an error from the device. An error will have no
+ * response data, just the packet_id and status_code.
+ */
+ const size_t err_packet_size = sizeof(struct usb_spi_response_v2) -
+ USB_SPI_PAYLOAD_SIZE_V2_RESPONSE;
+ if (rsp_config.packet_size == err_packet_size &&
+ rsp_config.packet_v2.rsp_start.status_code !=
+ USB_SPI_SUCCESS) {
+ status = rsp_config.packet_v2.rsp_start.status_code;
+ if (status == USB_SPI_DISABLED) {
+ msg_perr("Raiden: Target SPI bridge is disabled (is WP enabled?)\n");
+ return status;
+ }
+ }
+
msg_perr("Raiden: Packet is not a valid config\n"
" config attempt = %d\n"
" packet id = %u\n"
@@ -989,7 +1016,7 @@ static int get_spi_config_v2(struct raiden_debug_spi_data *ctx_data)
config_attempt + 1,
rsp_config.packet_v2.packet_id,
rsp_config.packet_size);
- programmer_delay(RETRY_INTERVAL_US);
+ default_delay(RETRY_INTERVAL_US);
}
return USB_SPI_HOST_INIT_FAILURE;
}
@@ -1213,7 +1240,7 @@ static int send_command_v2(const struct flashctx *flash,
/* Reattempting will not result in a recovery. */
return status;
}
- programmer_delay(RETRY_INTERVAL_US);
+ default_delay(RETRY_INTERVAL_US);
continue;
}
for (read_attempt = 0; read_attempt < READ_RETRY_ATTEMPTS;
@@ -1250,22 +1277,52 @@ static int send_command_v2(const struct flashctx *flash,
}
/* Device needs to reset its transmit index. */
restart_response_v2(ctx_data);
- programmer_delay(RETRY_INTERVAL_US);
+ default_delay(RETRY_INTERVAL_US);
}
}
}
return status;
}
+static int raiden_debug_spi_shutdown(void * data)
+{
+ struct raiden_debug_spi_data *ctx_data = (struct raiden_debug_spi_data *)data;
+ struct spi_master *spi_config = ctx_data->spi_config;
+
+ int ret = LIBUSB(libusb_control_transfer(
+ ctx_data->dev->handle,
+ LIBUSB_ENDPOINT_OUT |
+ LIBUSB_REQUEST_TYPE_VENDOR |
+ LIBUSB_RECIPIENT_INTERFACE,
+ RAIDEN_DEBUG_SPI_REQ_DISABLE,
+ 0,
+ ctx_data->dev->interface_descriptor->bInterfaceNumber,
+ NULL,
+ 0,
+ TRANSFER_TIMEOUT_MS));
+ if (ret != 0) {
+ msg_perr("Raiden: Failed to disable SPI bridge\n");
+ free(ctx_data);
+ free(spi_config);
+ return ret;
+ }
+
+ usb_device_free(ctx_data->dev);
+ libusb_exit(NULL);
+ free(ctx_data);
+ free(spi_config);
+
+ return 0;
+}
+
static const struct spi_master spi_master_raiden_debug = {
- .features = SPI_MASTER_4BA,
- .max_data_read = 0,
- .max_data_write = 0,
- .command = NULL,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .features = SPI_MASTER_4BA,
+ .max_data_read = 0,
+ .max_data_write = 0,
+ .command = NULL,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = raiden_debug_spi_shutdown,
};
static int match_endpoint(struct libusb_endpoint_descriptor const *descriptor,
@@ -1316,15 +1373,14 @@ static int find_endpoints(struct usb_device *dev, uint8_t *in_ep, uint8_t *out_e
* is being used by the device USB SPI interface and if needed query the
* device for its capabilities.
*
- * @param spi_config Raiden SPI config which will be modified.
+ * @param ctx_data Raiden SPI data, data contains pointer to config which will be modified.
*
- * @returns Returns status code with 0 on success.
+ * @returns Returns status code with 0 on success.
*/
-static int configure_protocol(struct spi_master *spi_config)
+static int configure_protocol(struct raiden_debug_spi_data *ctx_data)
{
int status = 0;
- struct raiden_debug_spi_data *ctx_data =
- (struct raiden_debug_spi_data *)spi_config->data;
+ struct spi_master *spi_config = ctx_data->spi_config;
ctx_data->protocol_version =
ctx_data->dev->interface_descriptor->bInterfaceProtocol;
@@ -1375,46 +1431,16 @@ static int configure_protocol(struct spi_master *spi_config)
return 0;
}
-static int raiden_debug_spi_shutdown(void * data)
-{
- struct spi_master *spi_config = data;
- struct raiden_debug_spi_data *ctx_data =
- (struct raiden_debug_spi_data *)spi_config->data;
-
- int ret = LIBUSB(libusb_control_transfer(
- ctx_data->dev->handle,
- LIBUSB_ENDPOINT_OUT |
- LIBUSB_REQUEST_TYPE_VENDOR |
- LIBUSB_RECIPIENT_INTERFACE,
- RAIDEN_DEBUG_SPI_REQ_DISABLE,
- 0,
- ctx_data->dev->interface_descriptor->bInterfaceNumber,
- NULL,
- 0,
- TRANSFER_TIMEOUT_MS));
- if (ret != 0) {
- msg_perr("Raiden: Failed to disable SPI bridge\n");
- free(ctx_data);
- free(spi_config);
- return ret;
- }
-
- usb_device_free(ctx_data->dev);
- libusb_exit(NULL);
- free(ctx_data);
- free(spi_config);
-
- return 0;
-}
-
-static int get_ap_request_type(void)
+static int get_ap_request_type(const struct programmer_cfg *cfg)
{
int ap_request = RAIDEN_DEBUG_SPI_REQ_ENABLE_AP;
- char *custom_rst_str = extract_programmer_param("custom_rst");
+ char *custom_rst_str = extract_programmer_param_str(cfg, "custom_rst");
if (custom_rst_str) {
- if (!strcasecmp(custom_rst_str, "true"))
+ if (!strcasecmp(custom_rst_str, "true")) {
ap_request = RAIDEN_DEBUG_SPI_REQ_ENABLE_AP_CUSTOM;
- else {
+ } else if (!strcasecmp(custom_rst_str, "false")) {
+ ap_request = RAIDEN_DEBUG_SPI_REQ_ENABLE_AP;
+ } else {
msg_perr("Invalid custom rst param: %s\n",
custom_rst_str);
ap_request = -1;
@@ -1424,14 +1450,18 @@ static int get_ap_request_type(void)
return ap_request;
}
-static int get_target(void)
+static int get_target(const struct programmer_cfg *cfg)
{
+ /**
+ * REQ_ENABLE doesn't specify a target bus, and will be rejected
+ * by adapters that support more than one target.
+ */
int request_enable = RAIDEN_DEBUG_SPI_REQ_ENABLE;
- char *target_str = extract_programmer_param("target");
+ char *target_str = extract_programmer_param_str(cfg, "target");
if (target_str) {
if (!strcasecmp(target_str, "ap"))
- request_enable = get_ap_request_type();
+ request_enable = get_ap_request_type(cfg);
else if (!strcasecmp(target_str, "ec"))
request_enable = RAIDEN_DEBUG_SPI_REQ_ENABLE_EC;
else {
@@ -1454,22 +1484,22 @@ static void free_dev_list(struct usb_device **dev_lst)
dev = usb_device_free(dev);
}
-int raiden_debug_spi_init(void)
+static int raiden_debug_spi_init(const struct programmer_cfg *cfg)
{
struct usb_match match;
- char *serial = extract_programmer_param("serial");
+ char *serial = extract_programmer_param_str(cfg, "serial");
struct usb_device *current;
struct usb_device *device = NULL;
- int found = 0;
+ bool found = false;
int ret;
- int request_enable = get_target();
+ int request_enable = get_target(cfg);
if (request_enable < 0) {
free(serial);
return 1;
}
- usb_match_init(&match);
+ usb_match_init(cfg, &match);
usb_match_value_default(&match.vid, GOOGLE_VID);
usb_match_value_default(&match.class, LIBUSB_CLASS_VENDOR_SPEC);
@@ -1507,15 +1537,13 @@ int raiden_debug_spi_init(void)
}
if (!serial) {
- found = 1;
+ found = true;
goto loop_end;
} else {
- unsigned char dev_serial[32];
+ unsigned char dev_serial[32] = { 0 };
struct libusb_device_descriptor descriptor;
int rc;
- memset(dev_serial, 0, sizeof(dev_serial));
-
if (libusb_get_device_descriptor(device->device, &descriptor)) {
msg_pdbg("USB: Failed to get device descriptor.\n");
goto loop_end;
@@ -1534,7 +1562,7 @@ int raiden_debug_spi_init(void)
} else {
msg_pinfo("Raiden: Serial number %s matched device", serial);
usb_device_show(" ", current);
- found = 1;
+ found = true;
}
}
}
@@ -1579,31 +1607,31 @@ loop_end:
(request_enable == RAIDEN_DEBUG_SPI_REQ_ENABLE_EC))
usleep(50 * 1000);
- struct spi_master *spi_config = calloc(1, sizeof(struct spi_master));
+ struct spi_master *spi_config = calloc(1, sizeof(*spi_config));
if (!spi_config) {
msg_perr("Unable to allocate space for SPI master.\n");
return SPI_GENERIC_ERROR;
}
- struct raiden_debug_spi_data *data = calloc(1, sizeof(struct raiden_debug_spi_data));
+ struct raiden_debug_spi_data *data = calloc(1, sizeof(*data));
if (!data) {
free(spi_config);
msg_perr("Unable to allocate space for extra SPI master data.\n");
return SPI_GENERIC_ERROR;
}
- memcpy(spi_config, &spi_master_raiden_debug, sizeof(struct spi_master));
+ *spi_config = spi_master_raiden_debug;
data->dev = device;
data->in_ep = in_endpoint;
data->out_ep = out_endpoint;
+ data->spi_config = spi_config;
- spi_config->data = data;
/*
* The SPI master needs to be configured based on the device connected.
* Using the device protocol interrogation, we will set the limits on
* the write and read sizes and switch command functions.
*/
- ret = configure_protocol(spi_config);
+ ret = configure_protocol(data);
if (ret) {
msg_perr("Raiden: Error configuring protocol\n"
" protocol = %u\n"
@@ -1614,8 +1642,12 @@ loop_end:
return SPI_GENERIC_ERROR;
}
- register_spi_master(spi_config);
- register_shutdown(raiden_debug_spi_shutdown, spi_config);
-
- return 0;
+ return register_spi_master(spi_config, data);
}
+
+const struct programmer_entry programmer_raiden_debug_spi = {
+ .name = "raiden_debug_spi",
+ .type = USB,
+ .devs.dev = devs_raiden,
+ .init = raiden_debug_spi_init,
+};
diff --git a/rayer_spi.c b/rayer_spi.c
index 8e869e66d..27caf2be1 100644
--- a/rayer_spi.c
+++ b/rayer_spi.c
@@ -22,14 +22,13 @@
* most OS parport drivers will perform many unnecessary accesses although
* this driver just treats the parallel port as a GPIO set.
*/
-#if defined(__i386__) || defined(__x86_64__)
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_x86_io.h"
/* We have two sets of pins, out and in. The numbers for both sets are
* independent and are bitshift values, not real pin numbers.
@@ -48,10 +47,18 @@ struct rayer_pinout {
uint8_t sck_bit;
uint8_t mosi_bit;
uint8_t miso_bit;
- void (*preinit)(const void *);
+ void (*preinit)(void *);
int (*shutdown)(void *);
};
+struct rayer_spi_data {
+ uint16_t lpt_iobase;
+ /* Cached value of last byte sent. */
+ uint8_t lpt_outbyte;
+
+ const struct rayer_pinout *pinout;
+};
+
static const struct rayer_pinout rayer_spipgm = {
.cs_bit = 5,
.sck_bit = 6,
@@ -59,8 +66,28 @@ static const struct rayer_pinout rayer_spipgm = {
.miso_bit = 6,
};
-static void dlc5_preinit(const void *);
-static int dlc5_shutdown(void *);
+static void dlc5_preinit(void *spi_data)
+{
+ struct rayer_spi_data *data = spi_data;
+
+ msg_pdbg("dlc5_preinit\n");
+ /* Assert pin 6 to receive MISO. */
+ data->lpt_outbyte |= (1<<4);
+ OUTB(data->lpt_outbyte, data->lpt_iobase);
+}
+
+static int dlc5_shutdown(void *spi_data)
+{
+ struct rayer_spi_data *data = spi_data;
+
+ msg_pdbg("dlc5_shutdown\n");
+ /* De-assert pin 6 to force MISO low. */
+ data->lpt_outbyte &= ~(1<<4);
+ OUTB(data->lpt_outbyte, data->lpt_iobase);
+
+ free(data);
+ return 0;
+}
static const struct rayer_pinout xilinx_dlc5 = {
.cs_bit = 2,
@@ -71,8 +98,26 @@ static const struct rayer_pinout xilinx_dlc5 = {
.shutdown = dlc5_shutdown,
};
-static void byteblaster_preinit(const void *);
-static int byteblaster_shutdown(void *);
+static void byteblaster_preinit(void *spi_data)
+{
+ struct rayer_spi_data *data = spi_data;
+
+ msg_pdbg("byteblaster_preinit\n");
+ /* Assert #EN signal. */
+ OUTB(2, data->lpt_iobase + 2 );
+}
+
+static int byteblaster_shutdown(void *spi_data)
+{
+ struct rayer_spi_data *data = spi_data;
+
+ msg_pdbg("byteblaster_shutdown\n");
+ /* De-Assert #EN signal. */
+ OUTB(0, data->lpt_iobase + 2 );
+
+ free(data);
+ return 0;
+}
static const struct rayer_pinout altera_byteblastermv = {
.cs_bit = 1,
@@ -83,8 +128,28 @@ static const struct rayer_pinout altera_byteblastermv = {
.shutdown = byteblaster_shutdown,
};
-static void stk200_preinit(const void *);
-static int stk200_shutdown(void *);
+static void stk200_preinit(void *spi_data)
+{
+ struct rayer_spi_data *data = spi_data;
+
+ msg_pdbg("stk200_init\n");
+ /* Assert #EN signals, set LED signal. */
+ data->lpt_outbyte = (1 << 6) ;
+ OUTB(data->lpt_outbyte, data->lpt_iobase);
+}
+
+static int stk200_shutdown(void *spi_data)
+{
+ struct rayer_spi_data *data = spi_data;
+
+ msg_pdbg("stk200_shutdown\n");
+ /* Assert #EN signals, clear LED signal. */
+ data->lpt_outbyte = (1 << 2) | (1 << 3);
+ OUTB(data->lpt_outbyte, data->lpt_iobase);
+
+ free(data);
+ return 0;
+}
static const struct rayer_pinout atmel_stk200 = {
.cs_bit = 7,
@@ -109,72 +174,99 @@ static const struct rayer_pinout spi_tt = {
.miso_bit = 7,
};
-static const struct rayer_programmer rayer_spi_types[] = {
- {"rayer", NT, "RayeR SPIPGM", &rayer_spipgm},
- {"xilinx", NT, "Xilinx Parallel Cable III (DLC 5)", &xilinx_dlc5},
- {"byteblastermv", OK, "Altera ByteBlasterMV", &altera_byteblastermv},
- {"stk200", NT, "Atmel STK200/300 adapter", &atmel_stk200},
- {"wiggler", OK, "Wiggler LPT", &wiggler_lpt},
- {"spi_tt", NT, "SPI Tiny Tools (SPI_TT LPT)", &spi_tt},
- {0},
-};
-
-static const struct rayer_pinout *pinout = NULL;
-
-static uint16_t lpt_iobase;
-
-/* Cached value of last byte sent. */
-static uint8_t lpt_outbyte;
-
-static void rayer_bitbang_set_cs(int val)
+static void rayer_bitbang_set_cs(int val, void *spi_data)
{
- lpt_outbyte &= ~(1 << pinout->cs_bit);
- lpt_outbyte |= (val << pinout->cs_bit);
- OUTB(lpt_outbyte, lpt_iobase);
+ struct rayer_spi_data *data = spi_data;
+
+ data->lpt_outbyte &= ~(1 << data->pinout->cs_bit);
+ data->lpt_outbyte |= (val << data->pinout->cs_bit);
+ OUTB(data->lpt_outbyte, data->lpt_iobase);
}
-static void rayer_bitbang_set_sck(int val)
+static void rayer_bitbang_set_sck(int val, void *spi_data)
{
- lpt_outbyte &= ~(1 << pinout->sck_bit);
- lpt_outbyte |= (val << pinout->sck_bit);
- OUTB(lpt_outbyte, lpt_iobase);
+ struct rayer_spi_data *data = spi_data;
+
+ data->lpt_outbyte &= ~(1 << data->pinout->sck_bit);
+ data->lpt_outbyte |= (val << data->pinout->sck_bit);
+ OUTB(data->lpt_outbyte, data->lpt_iobase);
}
-static void rayer_bitbang_set_mosi(int val)
+static void rayer_bitbang_set_mosi(int val, void *spi_data)
{
- lpt_outbyte &= ~(1 << pinout->mosi_bit);
- lpt_outbyte |= (val << pinout->mosi_bit);
- OUTB(lpt_outbyte, lpt_iobase);
+ struct rayer_spi_data *data = spi_data;
+
+ data->lpt_outbyte &= ~(1 << data->pinout->mosi_bit);
+ data->lpt_outbyte |= (val << data->pinout->mosi_bit);
+ OUTB(data->lpt_outbyte, data->lpt_iobase);
}
-static int rayer_bitbang_get_miso(void)
+static int rayer_bitbang_get_miso(void *spi_data)
{
+ struct rayer_spi_data *data = spi_data;
uint8_t tmp;
- tmp = INB(lpt_iobase + 1) ^ 0x80; // bit.7 inverted
- tmp = (tmp >> pinout->miso_bit) & 0x1;
+ tmp = INB(data->lpt_iobase + 1) ^ 0x80; // bit.7 inverted
+ tmp = (tmp >> data->pinout->miso_bit) & 0x1;
return tmp;
}
+static int rayer_shutdown(void *spi_data)
+{
+ free(spi_data);
+ return 0;
+}
+
static const struct bitbang_spi_master bitbang_spi_master_rayer = {
- .set_cs = rayer_bitbang_set_cs,
- .set_sck = rayer_bitbang_set_sck,
- .set_mosi = rayer_bitbang_set_mosi,
- .get_miso = rayer_bitbang_get_miso,
- .half_period = 0,
+ .set_cs = rayer_bitbang_set_cs,
+ .set_sck = rayer_bitbang_set_sck,
+ .set_mosi = rayer_bitbang_set_mosi,
+ .get_miso = rayer_bitbang_get_miso,
+ .half_period = 0,
};
-int rayer_spi_init(void)
+static const struct rayer_programmer *find_progtype(const char *prog_type)
{
+ static const struct rayer_programmer rayer_spi_types[] = {
+ {"rayer", NT, "RayeR SPIPGM", &rayer_spipgm},
+ {"xilinx", NT, "Xilinx Parallel Cable III (DLC 5)", &xilinx_dlc5},
+ {"byteblastermv", OK, "Altera ByteBlasterMV", &altera_byteblastermv},
+ {"stk200", NT, "Atmel STK200/300 adapter", &atmel_stk200},
+ {"wiggler", OK, "Wiggler LPT", &wiggler_lpt},
+ {"spi_tt", NT, "SPI Tiny Tools (SPI_TT LPT)", &spi_tt},
+ {0},
+ };
+ if (!prog_type)
+ return &rayer_spi_types[0];
+
const struct rayer_programmer *prog = rayer_spi_types;
- char *arg = NULL;
+ for (; prog->type != NULL; prog++) {
+ if (strcasecmp(prog_type, prog->type) == 0) {
+ break;
+ }
+ }
+
+ if (!prog->type) {
+ msg_perr("Error: Invalid device type specified.\n");
+ return NULL;
+ }
+
+ return prog;
+}
+
+static int get_params(const struct programmer_cfg *cfg, uint16_t *lpt_iobase,
+ const struct rayer_programmer **prog)
+{
+ /* Pick a default value for the I/O base. */
+ *lpt_iobase = 0x378;
+ /* no programmer type specified. */
+ *prog = NULL;
/* Non-default port requested? */
- arg = extract_programmer_param("iobase");
+ char *arg = extract_programmer_param_str(cfg, "iobase");
if (arg) {
char *endptr = NULL;
- unsigned long tmp;
- tmp = strtoul(arg, &endptr, 0);
+ unsigned long tmp = strtoul(arg, &endptr, 0);
/* Port 0, port >0x10000, unaligned ports and garbage strings
* are rejected.
*/
@@ -188,98 +280,68 @@ int rayer_spi_init(void)
"given was invalid.\nIt must be a multiple of "
"0x4 and lie between 0x100 and 0xfffc.\n");
free(arg);
- return 1;
+ return -1;
} else {
- lpt_iobase = (uint16_t)tmp;
+ *lpt_iobase = (uint16_t)tmp;
msg_pinfo("Non-default I/O base requested. This will "
"not change the hardware settings.\n");
}
- } else {
- /* Pick a default value for the I/O base. */
- lpt_iobase = 0x378;
+ free(arg);
}
+
+ arg = extract_programmer_param_str(cfg, "type");
+ *prog = find_progtype(arg);
free(arg);
+ return *prog ? 0 : -1;
+}
+
+static int rayer_spi_init(const struct programmer_cfg *cfg)
+{
+ const struct rayer_programmer *prog;
+ struct rayer_pinout *pinout = NULL;
+ uint16_t lpt_iobase;
+
+ if (get_params(cfg, &lpt_iobase, &prog) < 0)
+ return 1;
+
msg_pdbg("Using address 0x%x as I/O base for parallel port access.\n",
lpt_iobase);
- arg = extract_programmer_param("type");
- if (arg) {
- for (; prog->type != NULL; prog++) {
- if (strcasecmp(arg, prog->type) == 0) {
- break;
- }
- }
- if (prog->type == NULL) {
- msg_perr("Error: Invalid device type specified.\n");
- free(arg);
- return 1;
- }
- free(arg);
- }
msg_pinfo("Using %s pinout.\n", prog->description);
pinout = (struct rayer_pinout *)prog->dev_data;
if (rget_io_perms())
return 1;
+ struct rayer_spi_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ return 1;
+ }
+ data->pinout = pinout;
+ data->lpt_iobase = lpt_iobase;
/* Get the initial value before writing to any line. */
- lpt_outbyte = INB(lpt_iobase);
+ data->lpt_outbyte = INB(lpt_iobase);
if (pinout->shutdown)
- register_shutdown(pinout->shutdown, (void*)pinout);
+ register_shutdown(pinout->shutdown, data);
+ else
+ register_shutdown(rayer_shutdown, data);
+
if (pinout->preinit)
- pinout->preinit(pinout);
+ pinout->preinit(data);
- if (register_spi_bitbang_master(&bitbang_spi_master_rayer))
+ if (register_spi_bitbang_master(&bitbang_spi_master_rayer, data))
return 1;
return 0;
}
-static void byteblaster_preinit(const void *data){
- msg_pdbg("byteblaster_preinit\n");
- /* Assert #EN signal. */
- OUTB(2, lpt_iobase + 2 );
-}
-
-static int byteblaster_shutdown(void *data){
- msg_pdbg("byteblaster_shutdown\n");
- /* De-Assert #EN signal. */
- OUTB(0, lpt_iobase + 2 );
- return 0;
-}
-
-static void stk200_preinit(const void *data) {
- msg_pdbg("stk200_init\n");
- /* Assert #EN signals, set LED signal. */
- lpt_outbyte = (1 << 6) ;
- OUTB(lpt_outbyte, lpt_iobase);
-}
-
-static int stk200_shutdown(void *data) {
- msg_pdbg("stk200_shutdown\n");
- /* Assert #EN signals, clear LED signal. */
- lpt_outbyte = (1 << 2) | (1 << 3);
- OUTB(lpt_outbyte, lpt_iobase);
- return 0;
-}
-
-static void dlc5_preinit(const void *data) {
- msg_pdbg("dlc5_preinit\n");
- /* Assert pin 6 to receive MISO. */
- lpt_outbyte |= (1<<4);
- OUTB(lpt_outbyte, lpt_iobase);
-}
-
-static int dlc5_shutdown(void *data) {
- msg_pdbg("dlc5_shutdown\n");
- /* De-assert pin 6 to force MISO low. */
- lpt_outbyte &= ~(1<<4);
- OUTB(lpt_outbyte, lpt_iobase);
- return 0;
-}
-
-#else
-#error PCI port I/O access is not supported on this architecture yet.
-#endif
+const struct programmer_entry programmer_rayer_spi = {
+ .name = "rayer_spi",
+ .type = OTHER,
+ /* FIXME */
+ .devs.note = "RayeR parallel port programmer\n",
+ .init = rayer_spi_init,
+};
diff --git a/realtek_mst_i2c_spi.c b/realtek_mst_i2c_spi.c
index a0cd7c6e6..57677ec67 100644
--- a/realtek_mst_i2c_spi.c
+++ b/realtek_mst_i2c_spi.c
@@ -26,9 +26,9 @@
#include "i2c_helper.h"
-#define MCU_I2C_SLAVE_ADDR 0x94
+#define MCU_I2C_SLAVE_ADDR 0x94
#define REGISTER_ADDRESS (0x94 >> 1)
-#define PAGE_SIZE 128
+#define RTK_PAGE_SIZE 128
#define MAX_SPI_WAIT_RETRIES 1000
#define MCU_MODE 0x6F
@@ -51,7 +51,7 @@
struct realtek_mst_i2c_spi_data {
int fd;
- int reset;
+ bool reset;
};
static int realtek_mst_i2c_spi_write_data(int fd, uint16_t addr, void *buf, uint16_t len)
@@ -78,7 +78,7 @@ static int get_fd_from_context(const struct flashctx *flash)
msg_perr("Unable to extract fd from flash context.\n");
return SPI_GENERIC_ERROR;
}
- const struct realtek_mst_i2c_spi_data *data =
+ const struct realtek_mst_i2c_spi_data *data =
(const struct realtek_mst_i2c_spi_data *)flash->mst->spi.data;
return data->fd;
@@ -191,8 +191,7 @@ static int realtek_mst_i2c_spi_read_indexed_register(int fd, uint16_t address, u
}
-/* Toggle the GPIO pin 88, this could be routed to different controls like write
- * protection or a led. */
+/* Toggle the GPIO pin 88, reserved for write protection pin of the external flash. */
static int realtek_mst_i2c_spi_toggle_gpio_88_strap(int fd, bool toggle)
{
int ret = 0;
@@ -310,8 +309,8 @@ static int realtek_mst_i2c_spi_write_page(int fd, uint8_t reg, const uint8_t *bu
* Using static buffer with maximum possible size,
* extra byte is needed for prefixing the data port register at index 0.
*/
- uint8_t wbuf[PAGE_SIZE + 1] = { MCU_DATA_PORT };
- if (len > PAGE_SIZE)
+ uint8_t wbuf[RTK_PAGE_SIZE + 1] = { MCU_DATA_PORT };
+ if (len > RTK_PAGE_SIZE)
return SPI_GENERIC_ERROR;
memcpy(&wbuf[1], buf, len);
@@ -352,9 +351,9 @@ static int realtek_mst_i2c_spi_read(struct flashctx *flash, uint8_t *buf,
uint8_t dummy;
realtek_mst_i2c_spi_read_register(fd, MCU_DATA_PORT, &dummy);
- for (i = 0; i < len; i += PAGE_SIZE) {
+ for (i = 0; i < len; i += RTK_PAGE_SIZE) {
ret |= realtek_mst_i2c_spi_read_data(fd, REGISTER_ADDRESS,
- buf + i, min(len - i, PAGE_SIZE));
+ buf + i, min(len - i, RTK_PAGE_SIZE));
if (ret)
return ret;
}
@@ -375,16 +374,12 @@ static int realtek_mst_i2c_spi_write_256(struct flashctx *flash, const uint8_t *
if (fd < 0)
return SPI_GENERIC_ERROR;
- ret = realtek_mst_i2c_spi_toggle_gpio_88_strap(fd, true);
- if (ret)
- return ret;
-
ret |= realtek_mst_i2c_spi_write_register(fd, 0x6D, 0x02); /* write opcode */
- ret |= realtek_mst_i2c_spi_write_register(fd, 0x71, (PAGE_SIZE - 1)); /* fit len=256 */
+ ret |= realtek_mst_i2c_spi_write_register(fd, 0x71, (RTK_PAGE_SIZE - 1)); /* fit len=256 */
- for (i = 0; i < len; i += PAGE_SIZE) {
- uint16_t page_len = min(len - i, PAGE_SIZE);
- if (len - i < PAGE_SIZE)
+ for (i = 0; i < len; i += RTK_PAGE_SIZE) {
+ uint16_t page_len = min(len - i, RTK_PAGE_SIZE);
+ if (len - i < RTK_PAGE_SIZE)
ret |= realtek_mst_i2c_spi_write_register(fd, 0x71, page_len-1);
ret |= realtek_mst_i2c_spi_map_page(fd, start + i);
if (ret)
@@ -402,10 +397,9 @@ static int realtek_mst_i2c_spi_write_256(struct flashctx *flash, const uint8_t *
ret |= realtek_mst_i2c_execute_write(fd);
if (ret)
break;
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i + RTK_PAGE_SIZE, len);
}
- ret |= realtek_mst_i2c_spi_toggle_gpio_88_strap(fd, false);
-
return ret;
}
@@ -416,26 +410,21 @@ static int realtek_mst_i2c_spi_write_aai(struct flashctx *flash, const uint8_t *
return SPI_GENERIC_ERROR;
}
-static struct spi_master spi_master_i2c_realtek_mst = {
- .max_data_read = 16,
- .max_data_write = 8,
- .command = realtek_mst_i2c_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = realtek_mst_i2c_spi_read,
- .write_256 = realtek_mst_i2c_spi_write_256,
- .write_aai = realtek_mst_i2c_spi_write_aai,
-};
-
static int realtek_mst_i2c_spi_shutdown(void *data)
{
int ret = 0;
- struct realtek_mst_i2c_spi_data *realtek_mst_data =
+ struct realtek_mst_i2c_spi_data *realtek_mst_data =
(struct realtek_mst_i2c_spi_data *)data;
int fd = realtek_mst_data->fd;
+ ret |= realtek_mst_i2c_spi_toggle_gpio_88_strap(fd, false);
if (realtek_mst_data->reset) {
- ret |= realtek_mst_i2c_spi_reset_mpu(fd);
- if (ret != 0)
- msg_perr("%s: MCU failed to reset on tear-down.\n", __func__);
+ /*
+ * Return value for reset mpu is not checked since
+ * the return value is not guaranteed to be 0 on a
+ * success reset. Currently there is no way to fix
+ * that. For more details see b:147402710.
+ */
+ realtek_mst_i2c_spi_reset_mpu(fd);
}
i2c_close(fd);
free(data);
@@ -443,82 +432,85 @@ static int realtek_mst_i2c_spi_shutdown(void *data)
return ret;
}
-static int get_params(int *i2c_bus, int *reset, int *enter_isp)
-{
- char *bus_str = NULL, *reset_str = NULL, *isp_str = NULL;
- int ret = SPI_GENERIC_ERROR;
-
- bus_str = extract_programmer_param("bus");
- if (bus_str) {
- char *bus_suffix;
- errno = 0;
- int bus = (int)strtol(bus_str, &bus_suffix, 10);
- if (errno != 0 || bus_str == bus_suffix) {
- msg_perr("%s: Could not convert 'bus'.\n", __func__);
- goto _get_params_failed;
- }
+static const struct spi_master spi_master_i2c_realtek_mst = {
+ .max_data_read = 16,
+ .max_data_write = 8,
+ .command = realtek_mst_i2c_spi_send_command,
+ .read = realtek_mst_i2c_spi_read,
+ .write_256 = realtek_mst_i2c_spi_write_256,
+ .write_aai = realtek_mst_i2c_spi_write_aai,
+ .shutdown = realtek_mst_i2c_spi_shutdown,
+};
- if (bus < 0 || bus > 255) {
- msg_perr("%s: Value for 'bus' is out of range(0-255).\n", __func__);
- goto _get_params_failed;
- }
+static int get_params(const struct programmer_cfg *cfg, bool *reset, bool *enter_isp, bool *allow_brick)
+{
+ char *param_str;
+ int ret = 0;
- if (strlen(bus_suffix) > 0) {
- msg_perr("%s: Garbage following 'bus' value.\n", __func__);
- goto _get_params_failed;
+ *allow_brick = false; /* Default behaviour is to bail. */
+ param_str = extract_programmer_param_str(cfg, "allow_brick");
+ if (param_str) {
+ if (!strcmp(param_str, "yes")) {
+ *allow_brick = true;
+ } else {
+ msg_perr("%s: Incorrect param format, allow_brick=yes.\n", __func__);
+ ret = SPI_GENERIC_ERROR;
}
-
- msg_pinfo("Using i2c bus %i.\n", bus);
- *i2c_bus = bus;
- ret = 0;
- } else {
- 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__);
+ free(param_str);
+
+ *reset = false; /* Default behaviour is no MCU reset on tear-down. */
+ param_str = extract_programmer_param_str(cfg, "reset_mcu");
+ if (param_str) {
+ if (param_str[0] == '1') {
+ *reset = true;
+ } else if (param_str[0] == '0') {
+ *reset = false;
+ } 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);
-
- 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__);
+ }
+ free(param_str);
+
+ *enter_isp = true; /* Default behaviour is enter ISP on setup. */
+ param_str = extract_programmer_param_str(cfg, "enter_isp");
+ if (param_str) {
+ if (param_str[0] == '1') {
+ *enter_isp = true;
+ } else if (param_str[0] == '0') {
+ *enter_isp = false;
+ } 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);
-
-_get_params_failed:
- if (bus_str)
- free(bus_str);
+ }
+ free(param_str);
return ret;
}
-int realtek_mst_i2c_spi_init(void)
+static int realtek_mst_i2c_spi_init(const struct programmer_cfg *cfg)
{
int ret = 0;
- int i2c_bus = 0, reset = 0, enter_isp = 0;
+ bool reset, enter_isp, allow_brick;
- if (get_params(&i2c_bus, &reset, &enter_isp))
+ if (get_params(cfg, &reset, &enter_isp, &allow_brick))
return SPI_GENERIC_ERROR;
- int fd = i2c_open(i2c_bus, REGISTER_ADDRESS, 0);
+ /*
+ * TODO: Once board_enable can facilitate safe i2c allow listing
+ * then this can be removed.
+ */
+ if (!allow_brick) {
+ msg_perr("%s: For i2c drivers you must explicitly 'allow_brick=yes'. ", __func__);
+ msg_perr("There is currently no way to determine if the programmer works on a board "
+ "as i2c device address space can be overloaded. Set 'allow_brick=yes' if "
+ "you are sure you know what you are doing.\n");
+ return SPI_GENERIC_ERROR;
+ }
+
+ int fd = i2c_open_from_programmer_params(cfg, REGISTER_ADDRESS, 0);
if (fd < 0)
return fd;
@@ -528,7 +520,13 @@ int realtek_mst_i2c_spi_init(void)
return ret;
}
- struct realtek_mst_i2c_spi_data *data = calloc(1, sizeof(struct realtek_mst_i2c_spi_data));
+ ret |= realtek_mst_i2c_spi_toggle_gpio_88_strap(fd, true);
+ if (ret) {
+ msg_perr("Unable to toggle gpio 88 strap to True.\n");
+ return ret;
+ }
+
+ struct realtek_mst_i2c_spi_data *data = calloc(1, sizeof(*data));
if (!data) {
msg_perr("Unable to allocate space for extra SPI master data.\n");
return SPI_GENERIC_ERROR;
@@ -536,10 +534,12 @@ int realtek_mst_i2c_spi_init(void)
data->fd = fd;
data->reset = reset;
- ret |= register_shutdown(realtek_mst_i2c_spi_shutdown, data);
-
- spi_master_i2c_realtek_mst.data = data;
- ret |= register_spi_master(&spi_master_i2c_realtek_mst);
-
- return ret;
+ return register_spi_master(&spi_master_i2c_realtek_mst, data);
}
+
+const struct programmer_entry programmer_realtek_mst_i2c_spi = {
+ .name = "realtek_mst_i2c_spi",
+ .type = OTHER,
+ .devs.note = "Device files /dev/i2c-*.\n",
+ .init = realtek_mst_i2c_spi_init,
+};
diff --git a/s25f.c b/s25f.c
index 32af53ef5..dd15efcdb 100644
--- a/s25f.c
+++ b/s25f.c
@@ -17,15 +17,15 @@
/*
* s25f.c - Helper functions for Spansion S25FL and S25FS SPI flash chips.
* Uses 24 bit addressing for the FS chips and 32 bit addressing for the FL
- * chips (which is required by the overlayed sector size devices).
+ * chips (which is required by the overlaid sector size devices).
* TODO: Implement fancy hybrid sector architecture helpers.
*/
+#include <stdlib.h>
#include <string.h>
#include "chipdrivers.h"
#include "spi.h"
-#include "writeprotect.h"
/*
* RDAR and WRAR are supported on chips which have more than one set of status
@@ -94,7 +94,7 @@ static int s25f_legacy_software_reset(const struct flashctx *flash)
/* Allow time for reset command to execute. The datasheet specifies
* Trph = 35us, double that to be safe. */
- programmer_delay(T_RPH * 2);
+ programmer_delay(flash, T_RPH * 2);
return 0;
}
@@ -127,16 +127,21 @@ static int s25fs_software_reset(struct flashctx *flash)
}
/* Allow time for reset command to execute. Double tRPH to be safe. */
- programmer_delay(T_RPH * 2);
+ programmer_delay(flash, T_RPH * 2);
return 0;
}
static int s25f_poll_status(const struct flashctx *flash)
{
- uint8_t tmp = spi_read_status_register(flash);
+ while (true) {
+ uint8_t tmp;
+ if (spi_read_register(flash, STATUS1, &tmp))
+ return -1;
+
+ if ((tmp & SPI_SR_WIP) == 0)
+ break;
- while (tmp & SPI_SR_WIP) {
/*
* The WIP bit on S25F chips remains set to 1 if erase or
* programming errors occur, so we must check for those
@@ -156,8 +161,7 @@ static int s25f_poll_status(const struct flashctx *flash)
return -1;
}
- programmer_delay(1000 * 10);
- tmp = spi_read_status_register(flash);
+ programmer_delay(flash, 1000 * 10);
}
return 0;
@@ -180,7 +184,7 @@ static int s25fs_read_cr(const struct flashctx *flash, uint32_t addr)
int result = spi_send_command(flash, sizeof(read_cr_cmd), 1, read_cr_cmd, &cfg);
if (result) {
- msg_cerr("%s failed during command execution at address 0x%x\n",
+ msg_cerr("%s failed during command execution at address 0x%"PRIx32"\n",
__func__, addr);
return -1;
}
@@ -218,27 +222,29 @@ static int s25fs_write_cr(const struct flashctx *flash,
int result = spi_send_multicommand(flash, cmds);
if (result) {
- msg_cerr("%s failed during command execution at address 0x%x\n",
+ msg_cerr("%s failed during command execution at address 0x%"PRIx32"\n",
__func__, addr);
return -1;
}
- programmer_delay(T_W);
+ programmer_delay(flash, T_W);
return s25f_poll_status(flash);
}
-static int s25fs_restore_cr3nv(struct flashctx *flash, uint8_t cfg)
+static int s25fs_restore_cr3nv(struct flashctx *flash, void *data)
{
int ret = 0;
+ uint8_t cfg = *(uint8_t *)data;
+ free(data);
+
msg_cdbg("Restoring CR3NV value to 0x%02x\n", cfg);
ret |= s25fs_write_cr(flash, CR3NV_ADDR, cfg);
ret |= s25fs_software_reset(flash);
return ret;
}
-int s25fs_block_erase_d8(struct flashctx *flash,
- uint32_t addr, uint32_t blocklen)
+int s25fs_block_erase_d8(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
{
static int cr3nv_checked = 0;
@@ -283,8 +289,15 @@ int s25fs_block_erase_d8(struct flashctx *flash,
msg_cdbg("\n%s: CR3NV updated (0x%02x -> 0x%02x)\n",
__func__, cfg,
s25fs_read_cr(flash, CR3NV_ADDR));
+
/* Restore CR3V when flashrom exits */
- register_chip_restore(s25fs_restore_cr3nv, flash, cfg);
+ uint8_t *data = calloc(sizeof(uint8_t), 1);
+ if (!data) {
+ msg_cerr("Out of memory!\n");
+ return 1;
+ }
+ *data = cfg;
+ register_chip_restore(s25fs_restore_cr3nv, flash, data);
}
cr3nv_checked = 1;
@@ -297,12 +310,11 @@ int s25fs_block_erase_d8(struct flashctx *flash,
return result;
}
- programmer_delay(S25FS_T_SE);
+ programmer_delay(flash, S25FS_T_SE);
return s25f_poll_status(flash);
}
-int s25fl_block_erase(struct flashctx *flash,
- uint32_t addr, uint32_t blocklen)
+int s25fl_block_erase(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
{
struct spi_command erase_cmds[] = {
{
@@ -336,7 +348,7 @@ int s25fl_block_erase(struct flashctx *flash,
return result;
}
- programmer_delay(S25FL_T_SE);
+ programmer_delay(flash, S25FL_T_SE);
return s25f_poll_status(flash);
}
@@ -367,7 +379,7 @@ int probe_spi_big_spansion(struct flashctx *flash)
* 04h 00h FS: 256-kB physical sectors
* 04h 01h FS: 64-kB physical sectors
* 04h 00h FL: 256-kB physical sectors
- * 04h 01h FL: Mix of 64-kB and 4KB overlayed sectors
+ * 04h 01h FL: Mix of 64-kB and 4KB overlaid sectors
* 05h 80h FL family
* 05h 81h FS family
*
@@ -379,10 +391,10 @@ int probe_spi_big_spansion(struct flashctx *flash)
*/
uint32_t model_id =
- dev_id[1] << 24 |
- dev_id[2] << 16 |
- dev_id[4] << 8 |
- dev_id[5] << 0;
+ (uint32_t)dev_id[1] << 24 |
+ (uint32_t)dev_id[2] << 16 |
+ (uint32_t)dev_id[4] << 8 |
+ (uint32_t)dev_id[5] << 0;
if (dev_id[0] == flash->chip->manufacture_id && model_id == flash->chip->model_id)
return 1;
diff --git a/satamv.c b/satamv.c
index 31265eab3..1b8640a84 100644
--- a/satamv.c
+++ b/satamv.c
@@ -15,17 +15,20 @@
*/
/* Datasheets are not public (yet?) */
-#if defined(__i386__) || defined(__x86_64__)
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_x86_io.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
-static uint8_t *mv_bar;
-static uint16_t mv_iobar;
+struct satamv_data {
+ uint8_t *bar;
+ uint16_t iobar;
+};
-const struct dev_entry satas_mv[] = {
+static const struct dev_entry satas_mv[] = {
/* 88SX6041 and 88SX6042 are the same according to the datasheet. */
{0x11ab, 0x7042, OK, "Marvell", "88SX7042 PCI-e 4-port SATA-II"},
@@ -38,19 +41,55 @@ const struct dev_entry satas_mv[] = {
#define PCI_BAR2_CONTROL 0x00c08
#define GPIO_PORT_CONTROL 0x104f0
+/* BAR2 (MEM) can map NVRAM and flash. We set it to flash in the init function.
+ * If BAR2 is disabled, it still can be accessed indirectly via BAR1 (I/O).
+ * This code only supports indirect accesses for now.
+ */
+
+/* Indirect access to via the I/O BAR1. */
+static void satamv_indirect_chip_writeb(uint8_t val, chipaddr addr, uint16_t iobar)
+{
+ /* 0x80000000 selects BAR2 for remapping. */
+ OUTL(((uint32_t)addr | 0x80000000) & 0xfffffffc, iobar);
+ OUTB(val, iobar + 0x80 + (addr & 0x3));
+}
+
+/* Indirect access to via the I/O BAR1. */
+static uint8_t satamv_indirect_chip_readb(const chipaddr addr, uint16_t iobar)
+{
+ /* 0x80000000 selects BAR2 for remapping. */
+ OUTL(((uint32_t)addr | 0x80000000) & 0xfffffffc, iobar);
+ return INB(iobar + 0x80 + (addr & 0x3));
+}
+
+/* FIXME: Prefer direct access to BAR2 if BAR2 is active. */
static void satamv_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr);
+ chipaddr addr)
+{
+ const struct satamv_data *data = flash->mst->par.data;
+
+ satamv_indirect_chip_writeb(val, addr, data->iobar);
+}
+
+/* FIXME: Prefer direct access to BAR2 if BAR2 is active. */
static uint8_t satamv_chip_readb(const struct flashctx *flash,
- const chipaddr addr);
+ const chipaddr addr)
+{
+ const struct satamv_data *data = flash->mst->par.data;
+
+ return satamv_indirect_chip_readb(addr, data->iobar);
+}
+
+static int satamv_shutdown(void *par_data)
+{
+ free(par_data);
+ return 0;
+}
+
static const struct par_master par_master_satamv = {
- .chip_readb = satamv_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = satamv_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
+ .chip_readb = satamv_chip_readb,
+ .chip_writeb = satamv_chip_writeb,
+ .shutdown = satamv_shutdown,
};
/*
@@ -69,17 +108,19 @@ static const struct par_master par_master_satamv = {
* 0xc08 PCI BAR2 (Flash/NVRAM) Control
* 0x1046c Flash Parameters
*/
-int satamv_init(void)
+static int satamv_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
uintptr_t addr;
uint32_t tmp;
+ uint16_t iobar;
+ uint8_t *bar;
if (rget_io_perms())
return 1;
/* BAR0 has all internal registers memory mapped. */
- dev = pcidev_init(satas_mv, PCI_BASE_ADDRESS_0);
+ dev = pcidev_init(cfg, satas_mv, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -87,51 +128,51 @@ int satamv_init(void)
if (!addr)
return 1;
- mv_bar = rphysmap("Marvell 88SX7042 registers", addr, 0x20000);
- if (mv_bar == ERROR_PTR)
+ bar = rphysmap("Marvell 88SX7042 registers", addr, 0x20000);
+ if (bar == ERROR_PTR)
return 1;
- tmp = pci_mmio_readl(mv_bar + FLASH_PARAM);
+ tmp = pci_mmio_readl(bar + FLASH_PARAM);
msg_pspew("Flash Parameters:\n");
- msg_pspew("TurnOff=0x%01x\n", (tmp >> 0) & 0x7);
- msg_pspew("Acc2First=0x%01x\n", (tmp >> 3) & 0xf);
- msg_pspew("Acc2Next=0x%01x\n", (tmp >> 7) & 0xf);
- msg_pspew("ALE2Wr=0x%01x\n", (tmp >> 11) & 0x7);
- msg_pspew("WrLow=0x%01x\n", (tmp >> 14) & 0x7);
- msg_pspew("WrHigh=0x%01x\n", (tmp >> 17) & 0x7);
- msg_pspew("Reserved[21:20]=0x%01x\n", (tmp >> 20) & 0x3);
- msg_pspew("TurnOffExt=0x%01x\n", (tmp >> 22) & 0x1);
- msg_pspew("Acc2FirstExt=0x%01x\n", (tmp >> 23) & 0x1);
- msg_pspew("Acc2NextExt=0x%01x\n", (tmp >> 24) & 0x1);
- msg_pspew("ALE2WrExt=0x%01x\n", (tmp >> 25) & 0x1);
- msg_pspew("WrLowExt=0x%01x\n", (tmp >> 26) & 0x1);
- msg_pspew("WrHighExt=0x%01x\n", (tmp >> 27) & 0x1);
- msg_pspew("Reserved[31:28]=0x%01x\n", (tmp >> 28) & 0xf);
-
- tmp = pci_mmio_readl(mv_bar + EXPANSION_ROM_BAR_CONTROL);
+ msg_pspew("TurnOff=0x%01"PRIx32"\n", (tmp >> 0) & 0x7);
+ msg_pspew("Acc2First=0x%01"PRIx32"\n", (tmp >> 3) & 0xf);
+ msg_pspew("Acc2Next=0x%01"PRIx32"\n", (tmp >> 7) & 0xf);
+ msg_pspew("ALE2Wr=0x%01"PRIx32"\n", (tmp >> 11) & 0x7);
+ msg_pspew("WrLow=0x%01"PRIx32"\n", (tmp >> 14) & 0x7);
+ msg_pspew("WrHigh=0x%01"PRIx32"\n", (tmp >> 17) & 0x7);
+ msg_pspew("Reserved[21:20]=0x%01"PRIx32"\n", (tmp >> 20) & 0x3);
+ msg_pspew("TurnOffExt=0x%01"PRIx32"\n", (tmp >> 22) & 0x1);
+ msg_pspew("Acc2FirstExt=0x%01"PRIx32"\n", (tmp >> 23) & 0x1);
+ msg_pspew("Acc2NextExt=0x%01"PRIx32"\n", (tmp >> 24) & 0x1);
+ msg_pspew("ALE2WrExt=0x%01"PRIx32"\n", (tmp >> 25) & 0x1);
+ msg_pspew("WrLowExt=0x%01"PRIx32"\n", (tmp >> 26) & 0x1);
+ msg_pspew("WrHighExt=0x%01"PRIx32"\n", (tmp >> 27) & 0x1);
+ msg_pspew("Reserved[31:28]=0x%01"PRIx32"\n", (tmp >> 28) & 0xf);
+
+ tmp = pci_mmio_readl(bar + EXPANSION_ROM_BAR_CONTROL);
msg_pspew("Expansion ROM BAR Control:\n");
- msg_pspew("ExpROMSz=0x%01x\n", (tmp >> 19) & 0x7);
+ msg_pspew("ExpROMSz=0x%01"PRIx32"\n", (tmp >> 19) & 0x7);
/* Enable BAR2 mapping to flash */
- tmp = pci_mmio_readl(mv_bar + PCI_BAR2_CONTROL);
+ tmp = pci_mmio_readl(bar + PCI_BAR2_CONTROL);
msg_pspew("PCI BAR2 (Flash/NVRAM) Control:\n");
- msg_pspew("Bar2En=0x%01x\n", (tmp >> 0) & 0x1);
- msg_pspew("BAR2TransAttr=0x%01x\n", (tmp >> 1) & 0x1f);
- msg_pspew("BAR2Sz=0x%01x\n", (tmp >> 19) & 0x7);
+ msg_pspew("Bar2En=0x%01"PRIx32"\n", (tmp >> 0) & 0x1);
+ msg_pspew("BAR2TransAttr=0x%01"PRIx32"\n", (tmp >> 1) & 0x1f);
+ msg_pspew("BAR2Sz=0x%01"PRIx32"\n", (tmp >> 19) & 0x7);
tmp &= 0xffffffc0;
tmp |= 0x0000001f;
- pci_rmmio_writel(tmp, mv_bar + PCI_BAR2_CONTROL);
+ pci_rmmio_writel(tmp, bar + PCI_BAR2_CONTROL);
/* Enable flash: GPIO Port Control Register 0x104f0 */
- tmp = pci_mmio_readl(mv_bar + GPIO_PORT_CONTROL);
- msg_pspew("GPIOPortMode=0x%01x\n", (tmp >> 0) & 0x3);
+ tmp = pci_mmio_readl(bar + GPIO_PORT_CONTROL);
+ msg_pspew("GPIOPortMode=0x%01"PRIx32"\n", (tmp >> 0) & 0x3);
if (((tmp >> 0) & 0x3) != 0x2)
msg_pinfo("Warning! Either the straps are incorrect or you "
"have no flash or someone overwrote the strap "
"values!\n");
tmp &= 0xfffffffc;
tmp |= 0x2;
- pci_rmmio_writel(tmp, mv_bar + GPIO_PORT_CONTROL);
+ pci_rmmio_writel(tmp, bar + GPIO_PORT_CONTROL);
/* Get I/O BAR location. */
addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2);
@@ -142,52 +183,26 @@ int satamv_init(void)
* FIXME: Check if the I/O BAR is actually reachable.
* This is an arch specific check.
*/
- mv_iobar = addr & 0xffff;
- msg_pspew("Activating I/O BAR at 0x%04x\n", mv_iobar);
+ iobar = addr & 0xffff;
+ msg_pspew("Activating I/O BAR at 0x%04x\n", iobar);
+
+ struct satamv_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
+ return 1;
+ }
+ data->bar = bar;
+ data->iobar = iobar;
/* 512 kByte with two 8-bit latches, and
* 4 MByte with additional 3-bit latch. */
max_rom_decode.parallel = 4 * 1024 * 1024;
- register_par_master(&par_master_satamv, BUS_PARALLEL);
-
- return 0;
-}
-
-/* BAR2 (MEM) can map NVRAM and flash. We set it to flash in the init function.
- * If BAR2 is disabled, it still can be accessed indirectly via BAR1 (I/O).
- * This code only supports indirect accesses for now.
- */
-
-/* Indirect access to via the I/O BAR1. */
-static void satamv_indirect_chip_writeb(uint8_t val, chipaddr addr)
-{
- /* 0x80000000 selects BAR2 for remapping. */
- OUTL(((uint32_t)addr | 0x80000000) & 0xfffffffc, mv_iobar);
- OUTB(val, mv_iobar + 0x80 + (addr & 0x3));
-}
-
-/* Indirect access to via the I/O BAR1. */
-static uint8_t satamv_indirect_chip_readb(const chipaddr addr)
-{
- /* 0x80000000 selects BAR2 for remapping. */
- OUTL(((uint32_t)addr | 0x80000000) & 0xfffffffc, mv_iobar);
- return INB(mv_iobar + 0x80 + (addr & 0x3));
-}
-
-/* FIXME: Prefer direct access to BAR2 if BAR2 is active. */
-static void satamv_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- satamv_indirect_chip_writeb(val, addr);
-}
-
-/* FIXME: Prefer direct access to BAR2 if BAR2 is active. */
-static uint8_t satamv_chip_readb(const struct flashctx *flash,
- const chipaddr addr)
-{
- return satamv_indirect_chip_readb(addr);
+ return register_par_master(&par_master_satamv, BUS_PARALLEL, data);
}
-#else
-#error PCI port I/O access is not supported on this architecture yet.
-#endif
+const struct programmer_entry programmer_satamv = {
+ .name = "satamv",
+ .type = PCI,
+ .devs.dev = satas_mv,
+ .init = satamv_init,
+};
diff --git a/satasii.c b/satasii.c
index 8a0938d68..ad872bfc9 100644
--- a/satasii.c
+++ b/satasii.c
@@ -16,17 +16,20 @@
/* Datasheets can be found on http://www.siliconimage.com. Great thanks! */
+#include <stdlib.h>
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "platform/pci.h"
#define PCI_VENDOR_ID_SII 0x1095
#define SATASII_MEMMAP_SIZE 0x100
-static uint8_t *sii_bar;
-static uint16_t id;
+struct satasii_data {
+ uint8_t *bar;
+};
-const struct dev_entry satas_sii[] = {
+static const struct dev_entry satas_sii[] = {
{0x1095, 0x0680, OK, "Silicon Image", "PCI0680 Ultra ATA-133 Host Ctrl"},
{0x1095, 0x3112, OK, "Silicon Image", "SiI 3112 [SATALink/SATARaid] SATA Ctrl"},
{0x1095, 0x3114, OK, "Silicon Image", "SiI 3114 [SATALink/SATARaid] SATA Ctrl"},
@@ -37,43 +40,73 @@ const struct dev_entry satas_sii[] = {
{0},
};
-static void satasii_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr);
-static uint8_t satasii_chip_readb(const struct flashctx *flash, const chipaddr addr);
-static const struct par_master par_master_satasii = {
- .chip_readb = satasii_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = fallback_chip_readn,
- .chip_writeb = satasii_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
-};
-
-static uint32_t satasii_wait_done(void)
+static uint32_t satasii_wait_done(const uint8_t *bar)
{
uint32_t ctrl_reg;
int i = 0;
- while ((ctrl_reg = pci_mmio_readl(sii_bar)) & (1 << 25)) {
+ while ((ctrl_reg = pci_mmio_readl(bar)) & (1 << 25)) {
if (++i > 10000) {
- msg_perr("%s: control register stuck at %08x, ignoring.\n",
- __func__, pci_mmio_readl(sii_bar));
+ msg_perr("%s: control register stuck at %08"PRIx32", ignoring.\n",
+ __func__, pci_mmio_readl(bar));
break;
}
}
return ctrl_reg;
}
-int satasii_init(void)
+static void satasii_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
+{
+ const struct satasii_data *data = flash->mst->par.data;
+ uint32_t data_reg;
+ uint32_t ctrl_reg = satasii_wait_done(data->bar);
+
+ /* Mask out unused/reserved bits, set writes and start transaction. */
+ ctrl_reg &= 0xfcf80000;
+ ctrl_reg |= (1 << 25) | (0 << 24) | ((uint32_t) addr & 0x7ffff);
+
+ data_reg = (pci_mmio_readl((data->bar + 4)) & ~0xff) | val;
+ pci_mmio_writel(data_reg, (data->bar + 4));
+ pci_mmio_writel(ctrl_reg, data->bar);
+
+ satasii_wait_done(data->bar);
+}
+
+static uint8_t satasii_chip_readb(const struct flashctx *flash, const chipaddr addr)
+{
+ const struct satasii_data *data = flash->mst->par.data;
+ uint32_t ctrl_reg = satasii_wait_done(data->bar);
+
+ /* Mask out unused/reserved bits, set reads and start transaction. */
+ ctrl_reg &= 0xfcf80000;
+ ctrl_reg |= (1 << 25) | (1 << 24) | ((uint32_t) addr & 0x7ffff);
+
+ pci_mmio_writel(ctrl_reg, data->bar);
+
+ satasii_wait_done(data->bar);
+
+ return (pci_mmio_readl(data->bar + 4)) & 0xff;
+}
+
+static int satasii_shutdown(void *par_data)
+{
+ free(par_data);
+ return 0;
+}
+
+static const struct par_master par_master_satasii = {
+ .chip_readb = satasii_chip_readb,
+ .chip_writeb = satasii_chip_writeb,
+ .shutdown = satasii_shutdown,
+};
+
+static int satasii_init(const struct programmer_cfg *cfg)
{
struct pci_dev *dev = NULL;
uint32_t addr;
- uint16_t reg_offset;
-
- if (rget_io_perms())
- return 1;
+ uint16_t reg_offset, id;
+ uint8_t *bar;
- dev = pcidev_init(satas_sii, PCI_BASE_ADDRESS_0);
+ dev = pcidev_init(cfg, satas_sii, PCI_BASE_ADDRESS_0);
if (!dev)
return 1;
@@ -91,47 +124,27 @@ int satasii_init(void)
reg_offset = 0x50;
}
- sii_bar = rphysmap("SATA SiI registers", addr, SATASII_MEMMAP_SIZE);
- if (sii_bar == ERROR_PTR)
+ bar = rphysmap("SATA SiI registers", addr, SATASII_MEMMAP_SIZE);
+ if (bar == ERROR_PTR)
return 1;
- sii_bar += reg_offset;
+ bar += reg_offset;
/* Check if ROM cycle are OK. */
- if ((id != 0x0680) && (!(pci_mmio_readl(sii_bar) & (1 << 26))))
+ if ((id != 0x0680) && (!(pci_mmio_readl(bar) & (1 << 26))))
msg_pwarn("Warning: Flash seems unconnected.\n");
- register_par_master(&par_master_satasii, BUS_PARALLEL);
-
- return 0;
-}
-
-static void satasii_chip_writeb(const struct flashctx *flash, uint8_t val, chipaddr addr)
-{
- uint32_t data_reg;
- uint32_t ctrl_reg = satasii_wait_done();
-
- /* Mask out unused/reserved bits, set writes and start transaction. */
- ctrl_reg &= 0xfcf80000;
- ctrl_reg |= (1 << 25) | (0 << 24) | ((uint32_t) addr & 0x7ffff);
-
- data_reg = (pci_mmio_readl((sii_bar + 4)) & ~0xff) | val;
- pci_mmio_writel(data_reg, (sii_bar + 4));
- pci_mmio_writel(ctrl_reg, sii_bar);
-
- satasii_wait_done();
-}
-
-static uint8_t satasii_chip_readb(const struct flashctx *flash, const chipaddr addr)
-{
- uint32_t ctrl_reg = satasii_wait_done();
-
- /* Mask out unused/reserved bits, set reads and start transaction. */
- ctrl_reg &= 0xfcf80000;
- ctrl_reg |= (1 << 25) | (1 << 24) | ((uint32_t) addr & 0x7ffff);
-
- pci_mmio_writel(ctrl_reg, sii_bar);
-
- satasii_wait_done();
+ struct satasii_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ msg_perr("Unable to allocate space for PAR master data\n");
+ return 1;
+ }
+ data->bar = bar;
- return (pci_mmio_readl(sii_bar + 4)) & 0xff;
+ return register_par_master(&par_master_satasii, BUS_PARALLEL, data);
}
+const struct programmer_entry programmer_satasii = {
+ .name = "satasii",
+ .type = PCI,
+ .devs.dev = satas_sii,
+ .init = satasii_init,
+};
diff --git a/sb600spi.c b/sb600spi.c
index ef9da4b1a..cec7e0a59 100644
--- a/sb600spi.c
+++ b/sb600spi.c
@@ -18,14 +18,14 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
+#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include "flash.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
#include "spi.h"
+#include "platform/pci.h"
/* This struct is unused, but helps visualize the SB600 SPI BAR layout.
*struct sb600_spi_controller {
@@ -40,7 +40,6 @@
*};
*/
-static uint8_t *sb600_spibar = NULL;
enum amd_chipset {
CHIPSET_AMD_UNKNOWN,
CHIPSET_SB6XX,
@@ -55,13 +54,18 @@ enum amd_chipset {
#define FIFO_SIZE_OLD 8
#define FIFO_SIZE_YANGTZE 71
+#define SPI100_CMD_CODE_REG 0x45
+#define SPI100_CMD_TRIGGER_REG 0x47
+#define SPI100_EXECUTE_CMD (1 << 7)
+
struct sb600spi_data {
struct flashctx *flash;
+ uint8_t *spibar;
};
static int find_smbus_dev_rev(uint16_t vendor, uint16_t device)
{
- struct pci_dev *smbus_dev = pci_dev_find(vendor, device);
+ struct pci_dev *smbus_dev = pcidev_find(vendor, device);
if (!smbus_dev) {
msg_pdbg("No SMBus device with ID %04X:%04X found.\n", vendor, device);
msg_perr("ERROR: SMBus device not found. Not enabling SPI.\n");
@@ -127,9 +131,9 @@ static enum amd_chipset determine_generation(struct pci_dev *dev)
* 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, 0x59, 0x61 & 0x71.
*/
- } else if (rev == 0x4b || rev == 0x51 || rev == 0x59 || rev == 0x61) {
+ } else if (rev == 0x4b || rev == 0x51 || rev == 0x59 || rev == 0x61 || rev == 0x71) {
msg_pdbg("Promontory (rev 0x%02x) detected.\n", rev);
return CHIPSET_PROMONTORY;
} else {
@@ -149,7 +153,7 @@ static enum amd_chipset determine_generation(struct pci_dev *dev)
return CHIPSET_AMD_UNKNOWN;
}
-static void reset_internal_fifo_pointer(void)
+static void reset_internal_fifo_pointer(uint8_t *sb600_spibar)
{
mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2);
@@ -158,7 +162,7 @@ static void reset_internal_fifo_pointer(void)
msg_pspew("reset\n");
}
-static int compare_internal_fifo_pointer(uint8_t want)
+static int compare_internal_fifo_pointer(uint8_t want, uint8_t *sb600_spibar)
{
uint8_t have = mmio_readb(sb600_spibar + 0xd) & 0x07;
want %= FIFO_SIZE_OLD;
@@ -192,7 +196,7 @@ static int check_readwritecnt(const struct flashctx *flash, unsigned int writecn
return 0;
}
-static void execute_command(void)
+static void execute_command(uint8_t *sb600_spibar)
{
msg_pspew("Executing... ");
mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2);
@@ -201,11 +205,23 @@ static void execute_command(void)
msg_pspew("done\n");
}
+static void execute_spi100_command(uint8_t *sb600_spibar)
+{
+ msg_pspew("Executing... ");
+ mmio_writeb(mmio_readb(sb600_spibar + SPI100_CMD_TRIGGER_REG) | SPI100_EXECUTE_CMD,
+ sb600_spibar + SPI100_CMD_TRIGGER_REG);
+ while (mmio_readb(sb600_spibar + SPI100_CMD_TRIGGER_REG) & SPI100_CMD_TRIGGER_REG)
+ ;
+ msg_pspew("done\n");
+}
+
static int sb600_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
unsigned int readcnt,
const unsigned char *writearr,
unsigned char *readarr)
{
+ struct sb600spi_data *sb600_data = flash->mst->spi.data;
+ uint8_t *sb600_spibar = sb600_data->spibar;
/* First byte is cmd which can not be sent through the FIFO. */
unsigned char cmd = *writearr++;
writecnt--;
@@ -226,7 +242,7 @@ static int sb600_spi_send_command(const struct flashctx *flash, unsigned int wri
uint8_t readwrite = (readcnt + readoffby1) << 4 | (writecnt);
mmio_writeb(readwrite, sb600_spibar + 1);
- reset_internal_fifo_pointer();
+ reset_internal_fifo_pointer(sb600_spibar);
msg_pspew("Filling FIFO: ");
unsigned int count;
for (count = 0; count < writecnt; count++) {
@@ -234,16 +250,16 @@ static int sb600_spi_send_command(const struct flashctx *flash, unsigned int wri
mmio_writeb(writearr[count], sb600_spibar + 0xC);
}
msg_pspew("\n");
- if (compare_internal_fifo_pointer(writecnt))
+ if (compare_internal_fifo_pointer(writecnt, sb600_spibar))
return SPI_PROGRAMMER_ERROR;
/*
* We should send the data in sequence, which means we need to reset
* the FIFO pointer to the first byte we want to send.
*/
- reset_internal_fifo_pointer();
- execute_command();
- if (compare_internal_fifo_pointer(writecnt + readcnt))
+ reset_internal_fifo_pointer(sb600_spibar);
+ execute_command(sb600_spibar);
+ if (compare_internal_fifo_pointer(writecnt + readcnt, sb600_spibar))
return SPI_PROGRAMMER_ERROR;
/*
@@ -257,7 +273,7 @@ static int sb600_spi_send_command(const struct flashctx *flash, unsigned int wri
* the opcode, the FIFO already stores the response from the chip.
* Usually, the chip will respond with 0x00 or 0xff.
*/
- reset_internal_fifo_pointer();
+ reset_internal_fifo_pointer(sb600_spibar);
/* Skip the bytes we sent. */
msg_pspew("Skipping: ");
@@ -265,7 +281,7 @@ static int sb600_spi_send_command(const struct flashctx *flash, unsigned int wri
msg_pspew("[%02x]", mmio_readb(sb600_spibar + 0xC));
}
msg_pspew("\n");
- if (compare_internal_fifo_pointer(writecnt))
+ if (compare_internal_fifo_pointer(writecnt, sb600_spibar))
return SPI_PROGRAMMER_ERROR;
msg_pspew("Reading FIFO: ");
@@ -274,7 +290,7 @@ static int sb600_spi_send_command(const struct flashctx *flash, unsigned int wri
msg_pspew("[%02x]", readarr[count]);
}
msg_pspew("\n");
- if (compare_internal_fifo_pointer(writecnt+readcnt))
+ if (compare_internal_fifo_pointer(writecnt+readcnt, sb600_spibar))
return SPI_PROGRAMMER_ERROR;
if (mmio_readb(sb600_spibar + 1) != readwrite) {
@@ -292,11 +308,13 @@ static int spi100_spi_send_command(const struct flashctx *flash, unsigned int wr
const unsigned char *writearr,
unsigned char *readarr)
{
+ struct sb600spi_data *sb600_data = flash->mst->spi.data;
+ uint8_t *sb600_spibar = sb600_data->spibar;
/* First byte is cmd which can not be sent through the buffer. */
unsigned char cmd = *writearr++;
writecnt--;
msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, cmd, writecnt, readcnt);
- mmio_writeb(cmd, sb600_spibar + 0);
+ mmio_writeb(cmd, sb600_spibar + SPI100_CMD_CODE_REG);
int ret = check_readwritecnt(flash, writecnt, readcnt);
if (ret != 0)
@@ -314,7 +332,7 @@ static int spi100_spi_send_command(const struct flashctx *flash, unsigned int wr
}
msg_pspew("\n");
- execute_command();
+ execute_spi100_command(sb600_spibar);
msg_pspew("Reading buffer: ");
for (count = 0; count < readcnt; count++) {
@@ -353,7 +371,7 @@ static const char* spireadmodes[] = {
"Fast Read",
};
-static int set_speed(struct pci_dev *dev, enum amd_chipset amd_gen, uint8_t speed)
+static int set_speed(struct pci_dev *dev, enum amd_chipset amd_gen, uint8_t speed, uint8_t *sb600_spibar)
{
bool success = false;
@@ -376,7 +394,7 @@ static int set_speed(struct pci_dev *dev, enum amd_chipset amd_gen, uint8_t spee
return 0;
}
-static int set_mode(struct pci_dev *dev, uint8_t mode)
+static int set_mode(struct pci_dev *dev, uint8_t mode, uint8_t *sb600_spibar)
{
msg_pdbg("Setting SPI read mode to %s (%i)... ", spireadmodes[mode], mode);
uint32_t tmp = mmio_readl(sb600_spibar + 0x00);
@@ -391,19 +409,19 @@ static int set_mode(struct pci_dev *dev, uint8_t mode)
return 0;
}
-static int handle_speed(struct pci_dev *dev, enum amd_chipset amd_gen)
+static int handle_speed(const struct programmer_cfg *cfg,
+ struct pci_dev *dev, enum amd_chipset amd_gen, uint8_t *sb600_spibar)
{
uint32_t tmp;
int16_t spispeed_idx = -1;
int16_t spireadmode_idx = -1;
- char *spispeed;
- char *spireadmode;
+ char *param_str;
- spispeed = extract_programmer_param("spispeed");
- if (spispeed != NULL) {
+ param_str = extract_programmer_param_str(cfg, "spispeed");
+ if (param_str != NULL) {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(spispeeds); i++) {
- if (strcasecmp(spispeeds[i], spispeed) == 0) {
+ if (strcasecmp(spispeeds[i], param_str) == 0) {
spispeed_idx = i;
break;
}
@@ -412,36 +430,36 @@ static int handle_speed(struct pci_dev *dev, enum amd_chipset amd_gen)
* Error out on speeds not present in the spispeeds array.
* Only Yangtze supports the second half of indices.
* No 66 MHz before SB8xx. */
- if ((strcasecmp(spispeed, "reserved") == 0) ||
+ if ((strcasecmp(param_str, "reserved") == 0) ||
(i == ARRAY_SIZE(spispeeds)) ||
(amd_gen < CHIPSET_YANGTZE && spispeed_idx > 3) ||
(amd_gen < CHIPSET_SB89XX && spispeed_idx == 0)) {
- msg_perr("Error: Invalid spispeed value: '%s'.\n", spispeed);
- free(spispeed);
+ msg_perr("Error: Invalid spispeed value: '%s'.\n", param_str);
+ free(param_str);
return 1;
}
- free(spispeed);
+ free(param_str);
}
- spireadmode = extract_programmer_param("spireadmode");
- if (spireadmode != NULL) {
+ param_str = extract_programmer_param_str(cfg, "spireadmode");
+ if (param_str != NULL) {
unsigned int i;
for (i = 0; i < ARRAY_SIZE(spireadmodes); i++) {
- if (strcasecmp(spireadmodes[i], spireadmode) == 0) {
+ if (strcasecmp(spireadmodes[i], param_str) == 0) {
spireadmode_idx = i;
break;
}
}
- if ((strcasecmp(spireadmode, "reserved") == 0) ||
+ if ((strcasecmp(param_str, "reserved") == 0) ||
(i == ARRAY_SIZE(spireadmodes))) {
- msg_perr("Error: Invalid spireadmode value: '%s'.\n", spireadmode);
- free(spireadmode);
+ msg_perr("Error: Invalid spireadmode value: '%s'.\n", param_str);
+ free(param_str);
return 1;
}
if (amd_gen < CHIPSET_BOLTON) {
msg_perr("Warning: spireadmode not supported for this chipset.");
}
- free(spireadmode);
+ free(param_str);
}
/* See the chipset support matrix for SPI Base_Addr below for an explanation of the symbols used.
@@ -456,10 +474,10 @@ static int handle_speed(struct pci_dev *dev, enum amd_chipset amd_gen)
msg_pdbg("SPI read mode is %s (%i)\n",
spireadmodes[read_mode], read_mode);
if (spireadmode_idx < 0) {
- msg_perr("Warning: spireadmode not set, "
- "leaving spireadmode unchanged.");
+ msg_pdbg("spireadmode is not set, "
+ "leaving SPI read mode unchanged.\n");
}
- else if (set_mode(dev, spireadmode_idx) != 0) {
+ else if (set_mode(dev, spireadmode_idx, sb600_spibar) != 0) {
return 1;
}
@@ -499,33 +517,33 @@ static int handle_speed(struct pci_dev *dev, enum amd_chipset amd_gen)
}
}
if (spispeed_idx < 0) {
- msg_perr("Warning: spispeed not set, leaving spispeed unchanged.");
+ msg_pdbg("spispeed is not set, leaving SPI speed unchanged.\n");
return 0;
}
- return set_speed(dev, amd_gen, spispeed_idx);
+ return set_speed(dev, amd_gen, spispeed_idx, sb600_spibar);
}
-static int handle_imc(struct pci_dev *dev, enum amd_chipset amd_gen)
+static int handle_imc(const struct programmer_cfg *cfg, struct pci_dev *dev, enum amd_chipset amd_gen)
{
/* Handle IMC everywhere but sb600 which does not have one. */
if (amd_gen == CHIPSET_SB6XX)
return 0;
bool amd_imc_force = false;
- char *arg = extract_programmer_param("amd_imc_force");
- if (arg && !strcmp(arg, "yes")) {
+ char *param_value = extract_programmer_param_str(cfg, "amd_imc_force");
+ if (param_value && !strcmp(param_value, "yes")) {
amd_imc_force = true;
msg_pspew("amd_imc_force enabled.\n");
- } else if (arg && !strlen(arg)) {
+ } else if (param_value && !strlen(param_value)) {
msg_perr("Missing argument for amd_imc_force.\n");
- free(arg);
+ free(param_value);
return 1;
- } else if (arg) {
- msg_perr("Unknown argument for amd_imc_force: \"%s\" (not \"yes\").\n", arg);
- free(arg);
+ } else if (param_value) {
+ msg_perr("Unknown argument for amd_imc_force: \"%s\" (not \"yes\").\n", param_value);
+ free(param_value);
return 1;
}
- free(arg);
+ free(param_value);
/* TODO: we should not only look at IntegratedImcPresent (LPC Dev 20, Func 3, 40h) but also at
* IMCEnable(Strap) and Override EcEnable(Strap) (sb8xx, sb9xx?, a50, Bolton: Misc_Reg: 80h-87h;
@@ -537,7 +555,7 @@ static int handle_imc(struct pci_dev *dev, enum amd_chipset amd_gen)
}
if (!amd_imc_force)
- programmer_may_write = 0;
+ programmer_may_write = false;
msg_pinfo("Writes have been disabled for safety reasons because the presence of the IMC\n"
"was detected and it could interfere with accessing flash memory. Flashrom will\n"
"try to disable it temporarily but even then this might not be safe:\n"
@@ -566,55 +584,61 @@ static int promontory_read_memmapped(struct flashctx *flash, uint8_t *buf,
return 0;
}
-static struct spi_master spi_master_sb600 = {
- .max_data_read = FIFO_SIZE_OLD,
- .max_data_write = FIFO_SIZE_OLD - 3,
- .command = sb600_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
-};
-
-static struct spi_master spi_master_yangtze = {
- .max_data_read = FIFO_SIZE_YANGTZE - 3, /* Apparently the big SPI 100 buffer is not a ring buffer. */
- .max_data_write = FIFO_SIZE_YANGTZE - 3,
- .command = spi100_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
-};
-
-static struct spi_master spi_master_promontory = {
- .max_data_read = MAX_DATA_READ_UNLIMITED,
- .max_data_write = FIFO_SIZE_YANGTZE - 3,
- .command = spi100_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = promontory_read_memmapped,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
-};
-
static int sb600spi_shutdown(void *data)
{
- struct flashctx *flash = ((struct sb600spi_data *)data)->flash;
+ struct sb600spi_data *sb600_data = data;
+ struct flashctx *flash = sb600_data->flash;
if (flash)
finalize_flash_access(flash);
+
free(data);
return 0;
}
-int sb600_probe_spi(struct pci_dev *dev)
+static const struct spi_master spi_master_sb600 = {
+ .max_data_read = FIFO_SIZE_OLD,
+ .max_data_write = FIFO_SIZE_OLD - 3,
+ .command = sb600_spi_send_command,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = sb600spi_shutdown,
+};
+
+static const struct spi_master spi_master_yangtze = {
+ .max_data_read = FIFO_SIZE_YANGTZE - 3, /* Apparently the big SPI 100 buffer is not a ring buffer. */
+ .max_data_write = FIFO_SIZE_YANGTZE - 3,
+ .command = spi100_spi_send_command,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = sb600spi_shutdown,
+};
+
+static const struct spi_master spi_master_promontory = {
+ .max_data_read = MAX_DATA_READ_UNLIMITED,
+ .max_data_write = FIFO_SIZE_YANGTZE - 3,
+ .command = spi100_spi_send_command,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = promontory_read_memmapped,
+ .write_256 = default_spi_write_256,
+ .shutdown = sb600spi_shutdown,
+};
+
+int sb600_probe_spi(const struct programmer_cfg *cfg, struct pci_dev *dev)
{
struct pci_dev *smbus_dev;
uint32_t tmp;
uint8_t reg;
+ uint8_t *sb600_spibar = NULL;
/* Read SPI_BaseAddr */
tmp = pci_read_long(dev, 0xa0);
tmp &= 0xffffffe0; /* remove bits 4-0 (reserved) */
- msg_pdbg("SPI base address is at 0x%x\n", tmp);
+ msg_pdbg("SPI base address is at 0x%"PRIx32"\n", tmp);
/* If the BAR has address 0, it is unlikely SPI is used. */
if (!tmp)
@@ -623,7 +647,7 @@ int sb600_probe_spi(struct pci_dev *dev)
/* Physical memory has to be mapped at page (4k) boundaries. */
sb600_spibar = rphysmap("SB600 SPI registers", tmp & 0xfffff000, 0x1000);
if (sb600_spibar == ERROR_PTR)
- return ERROR_FATAL;
+ return ERROR_FLASHROM_FATAL;
/* The low bits of the SPI base address are used as offset into
* the mapped page.
@@ -632,7 +656,7 @@ int sb600_probe_spi(struct pci_dev *dev)
enum amd_chipset amd_gen = determine_generation(dev);
if (amd_gen == CHIPSET_AMD_UNKNOWN)
- return ERROR_NONFATAL;
+ return ERROR_FLASHROM_NONFATAL;
/* How to read the following table and similar ones in this file:
* "?" means we have no datasheet for this chipset generation or it doesn't have any relevant info.
@@ -652,14 +676,14 @@ int sb600_probe_spi(struct pci_dev *dev)
*/
if (amd_gen >= CHIPSET_SB7XX) {
tmp = pci_read_long(dev, 0xa0);
- msg_pdbg("SpiRomEnable=%i", (tmp >> 1) & 0x1);
+ msg_pdbg("SpiRomEnable=%"PRIi32"", (tmp >> 1) & 0x1);
if (amd_gen == CHIPSET_SB7XX)
- msg_pdbg(", AltSpiCSEnable=%i, AbortEnable=%i", tmp & 0x1, (tmp >> 2) & 0x1);
+ msg_pdbg(", AltSpiCSEnable=%"PRIi32", AbortEnable=%"PRIi32"", tmp & 0x1, (tmp >> 2) & 0x1);
else if (amd_gen >= CHIPSET_YANGTZE)
- msg_pdbg(", RouteTpm2Sp=%i", (tmp >> 3) & 0x1);
+ msg_pdbg(", RouteTpm2Sp=%"PRIi32"", (tmp >> 3) & 0x1);
tmp = pci_read_byte(dev, 0xba);
- msg_pdbg(", PrefetchEnSPIFromIMC=%i", (tmp & 0x4) >> 2);
+ msg_pdbg(", PrefetchEnSPIFromIMC=%"PRIi32"", (tmp & 0x4) >> 2);
tmp = pci_read_byte(dev, 0xbb);
/* FIXME: Set bit 3,6,7 if not already set.
@@ -667,8 +691,8 @@ int sb600_probe_spi(struct pci_dev *dev)
* See doc 42413 AMD SB700/710/750 RPR.
*/
if (amd_gen == CHIPSET_SB7XX)
- msg_pdbg(", SpiOpEnInLpcMode=%i", (tmp >> 5) & 0x1);
- msg_pdbg(", PrefetchEnSPIFromHost=%i\n", tmp & 0x1);
+ msg_pdbg(", SpiOpEnInLpcMode=%"PRIi32"", (tmp >> 5) & 0x1);
+ msg_pdbg(", PrefetchEnSPIFromHost=%"PRIi32"\n", tmp & 0x1);
}
/* Chipset support matrix for SPI_Cntrl0 (spibar + 0x0)
@@ -690,49 +714,49 @@ int sb600_probe_spi(struct pci_dev *dev)
* <1> see handle_speed
*/
tmp = mmio_readl(sb600_spibar + 0x00);
- msg_pdbg("(0x%08" PRIx32 ") SpiArbEnable=%i", tmp, (tmp >> 19) & 0x1);
+ msg_pdbg("(0x%08" PRIx32 ") SpiArbEnable=%"PRIi32"", tmp, (tmp >> 19) & 0x1);
if (amd_gen >= CHIPSET_YANGTZE)
- msg_pdbg(", IllegalAccess=%i", (tmp >> 21) & 0x1);
+ msg_pdbg(", IllegalAccess=%"PRIi32"", (tmp >> 21) & 0x1);
- msg_pdbg(", SpiAccessMacRomEn=%i, SpiHostAccessRomEn=%i, ArbWaitCount=%i",
+ msg_pdbg(", SpiAccessMacRomEn=%"PRIi32", SpiHostAccessRomEn=%"PRIi32", ArbWaitCount=%"PRIi32"",
(tmp >> 22) & 0x1, (tmp >> 23) & 0x1, (tmp >> 24) & 0x7);
if (amd_gen < CHIPSET_YANGTZE)
- msg_pdbg(", SpiBridgeDisable=%i", (tmp >> 27) & 0x1);
+ msg_pdbg(", SpiBridgeDisable=%"PRIi32"", (tmp >> 27) & 0x1);
switch (amd_gen) {
case CHIPSET_SB7XX:
- msg_pdbg(", DropOneClkOnRd/SpiClkGate=%i", (tmp >> 28) & 0x1);
+ msg_pdbg(", DropOneClkOnRd/SpiClkGate=%"PRIi32"", (tmp >> 28) & 0x1);
/* Fall through. */
case CHIPSET_SB89XX:
case CHIPSET_HUDSON234:
case CHIPSET_YANGTZE:
case CHIPSET_PROMONTORY:
- msg_pdbg(", SpiBusy=%i", (tmp >> 31) & 0x1);
+ msg_pdbg(", SpiBusy=%"PRIi32"", (tmp >> 31) & 0x1);
default: break;
}
msg_pdbg("\n");
if (((tmp >> 22) & 0x1) == 0 || ((tmp >> 23) & 0x1) == 0) {
msg_perr("ERROR: State of SpiAccessMacRomEn or SpiHostAccessRomEn prohibits full access.\n");
- return ERROR_NONFATAL;
+ return ERROR_FLASHROM_NONFATAL;
}
if (amd_gen >= CHIPSET_SB89XX) {
tmp = mmio_readb(sb600_spibar + 0x1D);
- msg_pdbg("Using SPI_CS%d\n", tmp & 0x3);
+ msg_pdbg("Using SPI_CS%"PRId32"\n", tmp & 0x3);
/* FIXME: Handle SpiProtect* configuration on Yangtze. */
}
/* Look for the SMBus device. */
- smbus_dev = pci_dev_find(0x1002, 0x4385);
+ smbus_dev = pcidev_find(0x1002, 0x4385);
if (!smbus_dev)
- smbus_dev = pci_dev_find(0x1022, 0x780b); /* AMD FCH */
+ smbus_dev = pcidev_find(0x1022, 0x780b); /* AMD FCH */
if (!smbus_dev)
- smbus_dev = pci_dev_find(0x1022, 0x790b); /* AMD FP4 */
+ smbus_dev = pcidev_find(0x1022, 0x790b); /* AMD FP4 */
if (!smbus_dev) {
msg_perr("ERROR: SMBus device not found. Not enabling SPI.\n");
- return ERROR_NONFATAL;
+ return ERROR_FLASHROM_NONFATAL;
}
/* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */
@@ -764,35 +788,28 @@ int sb600_probe_spi(struct pci_dev *dev)
return 0;
}
- if (handle_speed(dev, amd_gen) != 0)
- return ERROR_FATAL;
+ if (handle_speed(cfg, dev, amd_gen, sb600_spibar) != 0)
+ return ERROR_FLASHROM_FATAL;
- if (handle_imc(dev, amd_gen) != 0)
- return ERROR_FATAL;
+ if (handle_imc(cfg, dev, amd_gen) != 0)
+ return ERROR_FLASHROM_FATAL;
- struct sb600spi_data *data = calloc(1, sizeof(struct sb600spi_data));
+ struct sb600spi_data *data = calloc(1, sizeof(*data));
if (!data) {
msg_perr("Unable to allocate space for extra SPI master data.\n");
return SPI_GENERIC_ERROR;
}
data->flash = NULL;
-
- register_shutdown(sb600spi_shutdown, data);
- spi_master_sb600.data = data;
- spi_master_yangtze.data = data;
- spi_master_promontory.data = data;
-
+ data->spibar = sb600_spibar;
/* Starting with Yangtze the SPI controller got a different interface with a much bigger buffer. */
if (amd_gen < CHIPSET_YANGTZE)
- register_spi_master(&spi_master_sb600);
+ register_spi_master(&spi_master_sb600, data);
else if (amd_gen == CHIPSET_YANGTZE)
- register_spi_master(&spi_master_yangtze);
+ register_spi_master(&spi_master_yangtze, data);
else
- register_spi_master(&spi_master_promontory);
+ register_spi_master(&spi_master_promontory, data);
return 0;
}
-
-#endif
diff --git a/scripts/llvm-cov b/scripts/llvm-cov
new file mode 100755
index 000000000..b512b3dee
--- /dev/null
+++ b/scripts/llvm-cov
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+cd "${MESON_BUILD_ROOT}"
+llvm-profdata merge -sparse default.profraw -o default.profdata
+llvm-cov show -instr-profile=default.profdata -format=html -output-dir=. "$@"
+echo "file://${MESON_BUILD_ROOT}/index.html"
diff --git a/serial.c b/serial.c
index 76d34a263..10d739a33 100644
--- a/serial.c
+++ b/serial.c
@@ -15,8 +15,6 @@
* GNU General Public License for more details.
*/
-#include "platform.h"
-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -49,6 +47,10 @@ fdtype sp_fd = SER_INV_FD;
* On Linux there is a non-standard way to use arbitrary baud rates that we use if there is no
* matching standard rate, see custom_baud.c
*
+ * On Darwin there is also a non-standard ioctl() to set arbitrary baud rates
+ * and any above 230400, see custom_baud_darwin.c and
+ * https://opensource.apple.com/source/IOSerialFamily/IOSerialFamily-91/tests/IOSerialTestLib.c.auto.html
+ *
* On Windows there exist similar macros (starting with CBR_ instead of B) but they are only defined for
* backwards compatibility and the API supports arbitrary baud rates in the same manner as the macros, see
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa363214(v=vs.85).aspx
@@ -181,6 +183,7 @@ int serialport_config(fdtype fd, int baud)
}
msg_pdbg("Baud rate is %ld.\n", dcb.BaudRate);
#else
+ int custom_baud = (baud >= 0 && use_custom_baud(baud, sp_baudtable));
struct termios wanted, observed;
if (tcgetattr(fd, &observed) != 0) {
msg_perr_strerror("Could not fetch original serial port configuration: ");
@@ -188,8 +191,8 @@ int serialport_config(fdtype fd, int baud)
}
wanted = observed;
if (baud >= 0) {
- if (use_custom_baud(baud, sp_baudtable)) {
- if (set_custom_baudrate(fd, baud)) {
+ if (custom_baud) {
+ if (set_custom_baudrate(fd, baud, BEFORE_FLAGS, NULL)) {
msg_perr_strerror("Could not set custom baudrate: ");
return 1;
}
@@ -200,7 +203,6 @@ int serialport_config(fdtype fd, int baud)
msg_perr_strerror("Could not fetch serial port configuration: ");
return 1;
}
- msg_pdbg("Using custom baud rate.\n");
} else {
const struct baudentry *entry = round_baud(baud);
if (cfsetispeed(&wanted, entry->flag) != 0 || cfsetospeed(&wanted, entry->flag) != 0) {
@@ -214,6 +216,10 @@ int serialport_config(fdtype fd, int baud)
wanted.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | IEXTEN);
wanted.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL | IGNCR | INLCR);
wanted.c_oflag &= ~OPOST;
+ if (custom_baud && set_custom_baudrate(fd, baud, WITH_FLAGS, &wanted)) {
+ msg_perr_strerror("Could not set custom baudrate: ");
+ return 1;
+ }
if (tcsetattr(fd, TCSANOW, &wanted) != 0) {
msg_perr_strerror("Could not change serial port configuration: ");
return 1;
@@ -238,6 +244,13 @@ int serialport_config(fdtype fd, int baud)
(long)observed.c_oflag, (long)wanted.c_oflag
);
}
+ if (custom_baud) {
+ if (set_custom_baudrate(fd, baud, AFTER_FLAGS, &wanted)) {
+ msg_perr_strerror("Could not set custom baudrate: ");
+ return 1;
+ }
+ msg_pdbg("Using custom baud rate.\n");
+ }
if (cfgetispeed(&observed) != cfgetispeed(&wanted) ||
cfgetospeed(&observed) != cfgetospeed(&wanted)) {
msg_pwarn("Could not set baud rates exactly.\n");
@@ -405,7 +418,7 @@ int serialport_write(const unsigned char *buf, unsigned int writecnt)
if (!tmp) {
msg_pdbg2("Empty write\n");
empty_writes--;
- internal_delay(500);
+ default_delay(500);
if (empty_writes == 0) {
msg_perr("Serial port is unresponsive!\n");
return 1;
@@ -512,7 +525,7 @@ int serialport_read_nonblock(unsigned char *c, unsigned int readcnt, unsigned in
ret = 0;
break;
}
- internal_delay(1000); /* 1ms units */
+ default_delay(1000); /* 1ms units */
}
if (really_read != NULL)
*really_read = rd_bytes;
@@ -598,7 +611,7 @@ int serialport_write_nonblock(const unsigned char *buf, unsigned int writecnt, u
break;
}
}
- internal_delay(1000); /* 1ms units */
+ default_delay(1000); /* 1ms units */
}
if (really_wrote != NULL)
*really_wrote = wr_bytes;
diff --git a/serprog.c b/serprog.c
index 1befce103..b51f0cfe3 100644
--- a/serprog.c
+++ b/serprog.c
@@ -15,8 +15,7 @@
* GNU General Public License for more details.
*/
-#include "platform.h"
-
+#include <stdbool.h>
#include <stdio.h>
#if ! IS_WINDOWS /* stuff (presumably) needed for sockets only */
#include <stdlib.h>
@@ -38,16 +37,34 @@
#include "flash.h"
#include "programmer.h"
#include "chipdrivers.h"
-#include "serprog.h"
-#define MSGHEADER "serprog: "
+/* According to Serial Flasher Protocol Specification - version 1 */
+#define S_ACK 0x06
+#define S_NAK 0x15
+#define S_CMD_NOP 0x00 /* No operation */
+#define S_CMD_Q_IFACE 0x01 /* Query interface version */
+#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */
+#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */
+#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */
+#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */
+#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */
+#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */
+#define S_CMD_Q_WRNMAXLEN 0x08 /* Query Write to opbuf: Write-N maximum length */
+#define S_CMD_R_BYTE 0x09 /* Read a single byte */
+#define S_CMD_R_NBYTES 0x0A /* Read n bytes */
+#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */
+#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */
+#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */
+#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */
+#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */
+#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */
+#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */
+#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */
+#define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */
+#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */
+#define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */
-/*
- * FIXME: This prototype was added to help reduce diffs for the shutdown
- * registration patch, which shifted many lines of code to place
- * serprog_shutdown() before serprog_init(). It should be removed soon.
- */
-static int serprog_shutdown(void *data);
+#define MSGHEADER "serprog: "
static uint16_t sp_device_serbuf_size = 16;
static uint16_t sp_device_opbuf_size = 300;
@@ -140,7 +157,7 @@ static int sp_synchronize(void)
goto err_out;
}
/* A second should be enough to get all the answers to the buffer */
- internal_delay(1000 * 1000);
+ default_delay(1000 * 1000);
sp_flush_incoming();
/* Then try up to 8 times to send syncnop and get the correct special *
@@ -275,7 +292,8 @@ static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms)
return 1;
}
sp[0] = cmd;
- memcpy(&(sp[1]), parms, parmlen);
+ if (parms)
+ memcpy(&(sp[1]), parms, parmlen);
if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) {
if (sp_flush_stream() != 0) {
@@ -295,51 +313,303 @@ static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms)
return 0;
}
+/* Move an in flashrom buffer existing write-n operation to the on-device operation buffer. */
+static int sp_pass_writen(void)
+{
+ unsigned char header[7];
+ msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr);
+ if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) {
+ if (sp_flush_stream() != 0) {
+ return 1;
+ }
+ }
+ /* In case it's just a single byte send it as a single write. */
+ if (sp_write_n_bytes == 1) {
+ sp_write_n_bytes = 0;
+ header[0] = (sp_write_n_addr >> 0) & 0xFF;
+ header[1] = (sp_write_n_addr >> 8) & 0xFF;
+ header[2] = (sp_write_n_addr >> 16) & 0xFF;
+ header[3] = sp_write_n_buf[0];
+ if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
+ return 1;
+ sp_opbuf_usage += 5;
+ return 0;
+ }
+ header[0] = S_CMD_O_WRITEN;
+ header[1] = (sp_write_n_bytes >> 0) & 0xFF;
+ header[2] = (sp_write_n_bytes >> 8) & 0xFF;
+ header[3] = (sp_write_n_bytes >> 16) & 0xFF;
+ header[4] = (sp_write_n_addr >> 0) & 0xFF;
+ header[5] = (sp_write_n_addr >> 8) & 0xFF;
+ header[6] = (sp_write_n_addr >> 16) & 0xFF;
+ if (serialport_write(header, 7) != 0) {
+ msg_perr(MSGHEADER "Error: cannot write write-n command\n");
+ return 1;
+ }
+ if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
+ msg_perr(MSGHEADER "Error: cannot write write-n data");
+ return 1;
+ }
+ sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
+ sp_streamed_transmit_ops += 1;
+ sp_opbuf_usage += 7 + sp_write_n_bytes;
+ sp_write_n_bytes = 0;
+ sp_prev_was_write = 0;
+ return 0;
+}
+
+static int sp_execute_opbuf_noflush(void)
+{
+ if ((sp_max_write_n) && (sp_write_n_bytes)) {
+ if (sp_pass_writen() != 0) {
+ msg_perr("Error: could not transfer write buffer\n");
+ return 1;
+ }
+ }
+ if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
+ msg_perr("Error: could not execute command buffer\n");
+ return 1;
+ }
+ msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
+ sp_opbuf_usage = 0;
+ sp_prev_was_write = 0;
+ return 0;
+}
+
+static int sp_execute_opbuf(void)
+{
+ if (sp_execute_opbuf_noflush() != 0)
+ return 1;
+ if (sp_flush_stream() != 0)
+ return 1;
+
+ return 0;
+}
+
static int serprog_spi_send_command(const struct flashctx *flash,
unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr,
- unsigned char *readarr);
+ unsigned char *readarr)
+{
+ unsigned char *parmbuf;
+ int ret;
+ msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
+ if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
+ if (sp_execute_opbuf() != 0) {
+ msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
+ return 1;
+ }
+ }
+
+ parmbuf = malloc(writecnt + 6);
+ if (!parmbuf) {
+ msg_perr("Error: could not allocate SPI send param buffer.\n");
+ return 1;
+ }
+ parmbuf[0] = (writecnt >> 0) & 0xFF;
+ parmbuf[1] = (writecnt >> 8) & 0xFF;
+ parmbuf[2] = (writecnt >> 16) & 0xFF;
+ parmbuf[3] = (readcnt >> 0) & 0xFF;
+ parmbuf[4] = (readcnt >> 8) & 0xFF;
+ parmbuf[5] = (readcnt >> 16) & 0xFF;
+ memcpy(parmbuf + 6, writearr, writecnt);
+ ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
+ readarr);
+ free(parmbuf);
+ return ret;
+}
+
+static int serprog_shutdown(void *data)
+{
+ if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+ if (sp_execute_opbuf() != 0)
+ msg_pwarn("Could not flush command buffer.\n");
+ if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
+ uint8_t dis = 0;
+ if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
+ msg_pdbg(MSGHEADER "Output drivers disabled\n");
+ else
+ msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
+ }
+ /* FIXME: fix sockets on windows(?), especially closing */
+ serialport_shutdown(&sp_fd);
+ if (sp_max_write_n)
+ free(sp_write_n_buf);
+ return 0;
+}
+
+static void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
+{
+ /* Serprog transmits 24 bits only and assumes the underlying implementation handles any remaining bits
+ * correctly (usually setting them to one either in software (for FWH/LPC) or relying on the fact that
+ * the hardware observes a subset of the address bits only). Combined with the standard mapping of
+ * flashrom this creates a 16 MB-wide window just below the 4 GB boundary where serprog can operate (as
+ * needed for non-SPI chips). Below we make sure that the requested range is within this window. */
+ if ((phys_addr & 0xFF000000) == 0xFF000000) {
+ return (void*)phys_addr;
+ }
+ msg_pwarn(MSGHEADER "requested mapping %s is incompatible: 0x%zx bytes at 0x%0*" PRIxPTR ".\n",
+ descr, len, PRIxPTR_WIDTH, phys_addr);
+ return NULL;
+}
+
+static void serprog_delay(const struct flashctx *flash, unsigned int usecs);
+
static struct spi_master spi_master_serprog = {
+ .map_flash_region = serprog_map,
.features = SPI_MASTER_4BA,
.max_data_read = MAX_DATA_READ_UNLIMITED,
.max_data_write = MAX_DATA_WRITE_UNLIMITED,
.command = serprog_spi_send_command,
- .multicommand = default_spi_send_multicommand,
.read = default_spi_read,
.write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .delay = serprog_delay,
};
+static int sp_check_opbuf_usage(int bytes_to_be_added)
+{
+ if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
+ /* If this happens in the middle of a page load the page load will probably fail. */
+ msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
+ if (sp_execute_opbuf() != 0)
+ return 1;
+ }
+ return 0;
+}
+
static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr);
+ chipaddr addr)
+{
+ msg_pspew("%s\n", __func__);
+ if (sp_max_write_n) {
+ if ((sp_prev_was_write)
+ && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
+ sp_write_n_buf[sp_write_n_bytes++] = val;
+ } else {
+ if ((sp_prev_was_write) && (sp_write_n_bytes))
+ sp_pass_writen();
+ sp_prev_was_write = 1;
+ sp_write_n_addr = addr;
+ sp_write_n_bytes = 1;
+ sp_write_n_buf[0] = val;
+ }
+ sp_check_opbuf_usage(7 + sp_write_n_bytes);
+ if (sp_write_n_bytes >= sp_max_write_n)
+ sp_pass_writen();
+ } else {
+ /* We will have to do single writeb ops. */
+ unsigned char writeb_parm[4];
+ sp_check_opbuf_usage(6);
+ writeb_parm[0] = (addr >> 0) & 0xFF;
+ writeb_parm[1] = (addr >> 8) & 0xFF;
+ writeb_parm[2] = (addr >> 16) & 0xFF;
+ writeb_parm[3] = val;
+ sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error
+ sp_opbuf_usage += 5;
+ }
+}
+
static uint8_t serprog_chip_readb(const struct flashctx *flash,
- const chipaddr addr);
-static void serprog_chip_readn(const struct flashctx *flash, uint8_t *buf,
- const chipaddr addr, size_t len);
+ const chipaddr addr)
+{
+ unsigned char c;
+ unsigned char buf[3];
+ /* Will stream the read operation - eg. add it to the stream buffer, *
+ * then flush the buffer, then read the read answer. */
+ if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+ sp_execute_opbuf_noflush();
+ buf[0] = ((addr >> 0) & 0xFF);
+ buf[1] = ((addr >> 8) & 0xFF);
+ buf[2] = ((addr >> 16) & 0xFF);
+ sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error
+ sp_flush_stream(); // FIXME: return error
+ if (serialport_read(&c, 1) != 0)
+ msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
+ msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
+ return c;
+}
+
+/* Local version that really does the job, doesn't care of max_read_n. */
+static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
+{
+ unsigned char sbuf[6];
+ msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len);
+ /* Stream the read-n -- as above. */
+ if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
+ sp_execute_opbuf_noflush();
+ sbuf[0] = ((addr >> 0) & 0xFF);
+ sbuf[1] = ((addr >> 8) & 0xFF);
+ sbuf[2] = ((addr >> 16) & 0xFF);
+ sbuf[3] = ((len >> 0) & 0xFF);
+ sbuf[4] = ((len >> 8) & 0xFF);
+ sbuf[5] = ((len >> 16) & 0xFF);
+ sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
+ if (sp_flush_stream() != 0)
+ return 1;
+ if (serialport_read(buf, len) != 0) {
+ msg_perr(MSGHEADER "Error: cannot read read-n data");
+ return 1;
+ }
+ return 0;
+}
+
+/* The externally called version that makes sure that max_read_n is obeyed. */
+static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
+ const chipaddr addr, size_t len)
+{
+ size_t lenm = len;
+ chipaddr addrm = addr;
+ while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
+ sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
+ addrm += sp_max_read_n;
+ lenm -= sp_max_read_n;
+ }
+ if (lenm)
+ sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
+}
+
+static void serprog_delay(const struct flashctx *flash, unsigned int usecs)
+{
+ unsigned char buf[4];
+ msg_pspew("%s usecs=%d\n", __func__, usecs);
+ if (!sp_check_commandavail(S_CMD_O_DELAY)) {
+ msg_pdbg2("serprog_delay used, but programmer doesn't support delays natively - emulating\n");
+ default_delay(usecs);
+ return;
+ }
+ if ((sp_max_write_n) && (sp_write_n_bytes))
+ sp_pass_writen();
+ sp_check_opbuf_usage(5);
+ buf[0] = ((usecs >> 0) & 0xFF);
+ buf[1] = ((usecs >> 8) & 0xFF);
+ buf[2] = ((usecs >> 16) & 0xFF);
+ buf[3] = ((usecs >> 24) & 0xFF);
+ sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
+ sp_opbuf_usage += 5;
+ sp_prev_was_write = 0;
+}
+
static const struct par_master par_master_serprog = {
- .chip_readb = serprog_chip_readb,
- .chip_readw = fallback_chip_readw,
- .chip_readl = fallback_chip_readl,
- .chip_readn = serprog_chip_readn,
- .chip_writeb = serprog_chip_writeb,
- .chip_writew = fallback_chip_writew,
- .chip_writel = fallback_chip_writel,
- .chip_writen = fallback_chip_writen,
+ .map_flash_region = serprog_map,
+ .chip_readb = serprog_chip_readb,
+ .chip_readn = serprog_chip_readn,
+ .chip_writeb = serprog_chip_writeb,
+ .delay = serprog_delay,
};
static enum chipbustype serprog_buses_supported = BUS_NONE;
-int serprog_init(void)
+static int serprog_init(const struct programmer_cfg *cfg)
{
uint16_t iface;
unsigned char pgmname[17];
unsigned char rbuf[3];
unsigned char c;
char *device;
- int have_device = 0;
+ bool have_device = false;
/* the parameter is either of format "dev=/dev/device[:baud]" or "ip=ip:port" */
- device = extract_programmer_param("dev");
+ device = extract_programmer_param_str(cfg, "dev");
if (device && strlen(device)) {
char *baud_str = strstr(device, ":");
if (baud_str != NULL) {
@@ -354,15 +624,16 @@ int serprog_init(void)
if (baud_str == NULL || *baud_str == '\0') {
baud = -1;
msg_pdbg("No baudrate specified, using the hardware's defaults.\n");
- } else
+ } else {
baud = atoi(baud_str); // FIXME: replace atoi with strtoul
+ }
if (strlen(device) > 0) {
sp_fd = sp_openserport(device, baud);
if (sp_fd == SER_INV_FD) {
free(device);
return 1;
}
- have_device++;
+ have_device = true;
}
}
@@ -375,7 +646,7 @@ int serprog_init(void)
}
free(device);
- device = extract_programmer_param("ip");
+ device = extract_programmer_param_str(cfg, "ip");
if (have_device && device) {
msg_perr("Error: Both host and device specified.\n"
"Please use either dev= or ip= but not both.\n");
@@ -401,7 +672,7 @@ int serprog_init(void)
free(device);
return 1;
}
- have_device++;
+ have_device = true;
}
}
if (device && !strlen(device)) {
@@ -425,33 +696,30 @@ int serprog_init(void)
return 1;
}
- if (register_shutdown(serprog_shutdown, NULL))
- return 1;
-
msg_pdbg(MSGHEADER "connected - attempting to synchronize\n");
sp_check_avail_automatic = 0;
if (sp_synchronize())
- return 1;
+ goto init_err_cleanup_exit;
msg_pdbg(MSGHEADER "Synchronized\n");
if (sp_docommand(S_CMD_Q_IFACE, 0, NULL, 2, &iface)) {
msg_perr("Error: NAK to query interface version\n");
- return 1;
+ goto init_err_cleanup_exit;
}
if (iface != 1) {
msg_perr("Error: Unknown interface version: %d\n", iface);
- return 1;
+ goto init_err_cleanup_exit;
}
msg_pdbg(MSGHEADER "Interface version ok.\n");
if (sp_docommand(S_CMD_Q_CMDMAP, 0, NULL, 32, sp_cmdmap)) {
msg_perr("Error: query command map not supported\n");
- return 1;
+ goto init_err_cleanup_exit;
}
sp_check_avail_automatic = 1;
@@ -478,10 +746,10 @@ int serprog_init(void)
if (sp_check_commandavail(S_CMD_O_SPIOP) == 0) {
msg_perr("Error: SPI operation not supported while the "
"bustype is SPI\n");
- return 1;
+ goto init_err_cleanup_exit;
}
if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
- return 1;
+ goto init_err_cleanup_exit;
/* Success of any of these commands is optional. We don't need
the programmer to tell us its limits, but if it doesn't, we
will assume stuff, so it's in the programmers best interest
@@ -506,7 +774,7 @@ int serprog_init(void)
spi_master_serprog.max_data_read = v;
msg_pdbg(MSGHEADER "Maximum read-n length is %d\n", v);
}
- spispeed = extract_programmer_param("spispeed");
+ spispeed = extract_programmer_param_str(cfg, "spispeed");
if (spispeed && strlen(spispeed)) {
uint32_t f_spi_req, f_spi;
uint8_t buf[4];
@@ -517,22 +785,22 @@ int serprog_init(void)
if (errno != 0 || spispeed == f_spi_suffix) {
msg_perr("Error: Could not convert 'spispeed'.\n");
free(spispeed);
- return 1;
+ goto init_err_cleanup_exit;
}
if (strlen(f_spi_suffix) == 1) {
- if (!strcasecmp(f_spi_suffix, "M"))
+ if (!strcasecmp(f_spi_suffix, "M")) {
f_spi_req *= 1000000;
- else if (!strcasecmp(f_spi_suffix, "k"))
+ } else if (!strcasecmp(f_spi_suffix, "k")) {
f_spi_req *= 1000;
- else {
+ } else {
msg_perr("Error: Garbage following 'spispeed' value.\n");
free(spispeed);
- return 1;
+ goto init_err_cleanup_exit;
}
} else if (strlen(f_spi_suffix) > 1) {
msg_perr("Error: Garbage following 'spispeed' value.\n");
free(spispeed);
- return 1;
+ goto init_err_cleanup_exit;
}
buf[0] = (f_spi_req >> (0 * 8)) & 0xFF;
@@ -540,53 +808,54 @@ int serprog_init(void)
buf[2] = (f_spi_req >> (2 * 8)) & 0xFF;
buf[3] = (f_spi_req >> (3 * 8)) & 0xFF;
- if (sp_check_commandavail(S_CMD_S_SPI_FREQ) == 0)
+ if (sp_check_commandavail(S_CMD_S_SPI_FREQ) == 0) {
msg_pwarn(MSGHEADER "Warning: Setting the SPI clock rate is not supported!\n");
- else if (sp_docommand(S_CMD_S_SPI_FREQ, 4, buf, 4, buf) == 0) {
+ } else if (sp_docommand(S_CMD_S_SPI_FREQ, 4, buf, 4, buf) == 0) {
f_spi = buf[0];
f_spi |= buf[1] << (1 * 8);
f_spi |= buf[2] << (2 * 8);
f_spi |= buf[3] << (3 * 8);
msg_pdbg(MSGHEADER "Requested to set SPI clock frequency to %u Hz. "
"It was actually set to %u Hz\n", f_spi_req, f_spi);
- } else
+ } else {
msg_pwarn(MSGHEADER "Setting SPI clock rate to %u Hz failed!\n", f_spi_req);
+ }
}
free(spispeed);
bt = serprog_buses_supported;
if (sp_docommand(S_CMD_S_BUSTYPE, 1, &bt, 0, NULL))
- return 1;
+ goto init_err_cleanup_exit;
}
if (serprog_buses_supported & BUS_NONSPI) {
if (sp_check_commandavail(S_CMD_O_INIT) == 0) {
msg_perr("Error: Initialize operation buffer "
"not supported\n");
- return 1;
+ goto init_err_cleanup_exit;
}
if (sp_check_commandavail(S_CMD_O_DELAY) == 0) {
msg_perr("Error: Write to opbuf: "
"delay not supported\n");
- return 1;
+ goto init_err_cleanup_exit;
}
/* S_CMD_O_EXEC availability checked later. */
if (sp_check_commandavail(S_CMD_R_BYTE) == 0) {
msg_perr("Error: Single byte read not supported\n");
- return 1;
+ goto init_err_cleanup_exit;
}
/* This could be translated to single byte reads (if missing),
* but now we don't support that. */
if (sp_check_commandavail(S_CMD_R_NBYTES) == 0) {
msg_perr("Error: Read n bytes not supported\n");
- return 1;
+ goto init_err_cleanup_exit;
}
if (sp_check_commandavail(S_CMD_O_WRITEB) == 0) {
msg_perr("Error: Write to opbuf: "
"write byte not supported\n");
- return 1;
+ goto init_err_cleanup_exit;
}
if (sp_docommand(S_CMD_Q_WRNMAXLEN, 0, NULL, 3, rbuf)) {
@@ -605,7 +874,7 @@ int serprog_init(void)
if (!sp_write_n_buf) {
msg_perr("Error: cannot allocate memory for "
"Write-n buffer\n");
- return 1;
+ goto init_err_cleanup_exit;
}
sp_write_n_bytes = 0;
}
@@ -643,12 +912,12 @@ int serprog_init(void)
if (sp_check_commandavail(S_CMD_O_EXEC) == 0) {
msg_perr("Error: Execute operation buffer not "
"supported\n");
- return 1;
+ goto init_err_cleanup_exit;
}
if (sp_docommand(S_CMD_O_INIT, 0, NULL, 0, NULL)) {
msg_perr("Error: NAK to initialize operation buffer\n");
- return 1;
+ goto init_err_cleanup_exit;
}
if (sp_docommand(S_CMD_Q_OPBUF, 0, NULL, 2,
@@ -663,281 +932,36 @@ int serprog_init(void)
uint8_t en = 1;
if (sp_docommand(S_CMD_S_PIN_STATE, 1, &en, 0, NULL) != 0) {
msg_perr("Error: could not enable output buffers\n");
- return 1;
- } else
+ goto init_err_cleanup_exit;
+ } else {
msg_pdbg(MSGHEADER "Output drivers enabled\n");
- } else
+ }
+ } else {
msg_pdbg(MSGHEADER "Warning: Programmer does not support toggling its output drivers\n");
+ }
+
sp_prev_was_write = 0;
sp_streamed_transmit_ops = 0;
sp_streamed_transmit_bytes = 0;
sp_opbuf_usage = 0;
+
+ if (register_shutdown(serprog_shutdown, NULL))
+ goto init_err_cleanup_exit;
if (serprog_buses_supported & BUS_SPI)
- register_spi_master(&spi_master_serprog);
+ register_spi_master(&spi_master_serprog, NULL);
if (serprog_buses_supported & BUS_NONSPI)
- register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI);
- return 0;
-}
-
-/* Move an in flashrom buffer existing write-n operation to the on-device operation buffer. */
-static int sp_pass_writen(void)
-{
- unsigned char header[7];
- msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr);
- if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) {
- if (sp_flush_stream() != 0) {
- return 1;
- }
- }
- /* In case it's just a single byte send it as a single write. */
- if (sp_write_n_bytes == 1) {
- sp_write_n_bytes = 0;
- header[0] = (sp_write_n_addr >> 0) & 0xFF;
- header[1] = (sp_write_n_addr >> 8) & 0xFF;
- header[2] = (sp_write_n_addr >> 16) & 0xFF;
- header[3] = sp_write_n_buf[0];
- if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0)
- return 1;
- sp_opbuf_usage += 5;
- return 0;
- }
- header[0] = S_CMD_O_WRITEN;
- header[1] = (sp_write_n_bytes >> 0) & 0xFF;
- header[2] = (sp_write_n_bytes >> 8) & 0xFF;
- header[3] = (sp_write_n_bytes >> 16) & 0xFF;
- header[4] = (sp_write_n_addr >> 0) & 0xFF;
- header[5] = (sp_write_n_addr >> 8) & 0xFF;
- header[6] = (sp_write_n_addr >> 16) & 0xFF;
- if (serialport_write(header, 7) != 0) {
- msg_perr(MSGHEADER "Error: cannot write write-n command\n");
- return 1;
- }
- if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) {
- msg_perr(MSGHEADER "Error: cannot write write-n data");
- return 1;
- }
- sp_streamed_transmit_bytes += 7 + sp_write_n_bytes;
- sp_streamed_transmit_ops += 1;
- sp_opbuf_usage += 7 + sp_write_n_bytes;
- sp_write_n_bytes = 0;
- sp_prev_was_write = 0;
- return 0;
-}
-
-static int sp_execute_opbuf_noflush(void)
-{
- if ((sp_max_write_n) && (sp_write_n_bytes)) {
- if (sp_pass_writen() != 0) {
- msg_perr("Error: could not transfer write buffer\n");
- return 1;
- }
- }
- if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) {
- msg_perr("Error: could not execute command buffer\n");
- return 1;
- }
- msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage);
- sp_opbuf_usage = 0;
- sp_prev_was_write = 0;
- return 0;
-}
-
-static int sp_execute_opbuf(void)
-{
- if (sp_execute_opbuf_noflush() != 0)
- return 1;
- if (sp_flush_stream() != 0)
- return 1;
-
- return 0;
-}
-
-static int serprog_shutdown(void *data)
-{
- if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
- if (sp_execute_opbuf() != 0)
- msg_pwarn("Could not flush command buffer.\n");
- if (sp_check_commandavail(S_CMD_S_PIN_STATE)) {
- uint8_t dis = 0;
- if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0)
- msg_pdbg(MSGHEADER "Output drivers disabled\n");
- else
- msg_pwarn(MSGHEADER "%s: Warning: could not disable output buffers\n", __func__);
- }
- /* FIXME: fix sockets on windows(?), especially closing */
- serialport_shutdown(&sp_fd);
- if (sp_max_write_n)
- free(sp_write_n_buf);
- return 0;
-}
-
-static int sp_check_opbuf_usage(int bytes_to_be_added)
-{
- if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) {
- /* If this happens in the middle of a page load the page load will probably fail. */
- msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n");
- if (sp_execute_opbuf() != 0)
- return 1;
- }
- return 0;
-}
-
-static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val,
- chipaddr addr)
-{
- msg_pspew("%s\n", __func__);
- if (sp_max_write_n) {
- if ((sp_prev_was_write)
- && (addr == (sp_write_n_addr + sp_write_n_bytes))) {
- sp_write_n_buf[sp_write_n_bytes++] = val;
- } else {
- if ((sp_prev_was_write) && (sp_write_n_bytes))
- sp_pass_writen();
- sp_prev_was_write = 1;
- sp_write_n_addr = addr;
- sp_write_n_bytes = 1;
- sp_write_n_buf[0] = val;
- }
- sp_check_opbuf_usage(7 + sp_write_n_bytes);
- if (sp_write_n_bytes >= sp_max_write_n)
- sp_pass_writen();
- } else {
- /* We will have to do single writeb ops. */
- unsigned char writeb_parm[4];
- sp_check_opbuf_usage(6);
- writeb_parm[0] = (addr >> 0) & 0xFF;
- writeb_parm[1] = (addr >> 8) & 0xFF;
- writeb_parm[2] = (addr >> 16) & 0xFF;
- writeb_parm[3] = val;
- sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error
- sp_opbuf_usage += 5;
- }
-}
-
-static uint8_t serprog_chip_readb(const struct flashctx *flash,
- const chipaddr addr)
-{
- unsigned char c;
- unsigned char buf[3];
- /* Will stream the read operation - eg. add it to the stream buffer, *
- * then flush the buffer, then read the read answer. */
- if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
- sp_execute_opbuf_noflush();
- buf[0] = ((addr >> 0) & 0xFF);
- buf[1] = ((addr >> 8) & 0xFF);
- buf[2] = ((addr >> 16) & 0xFF);
- sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error
- sp_flush_stream(); // FIXME: return error
- if (serialport_read(&c, 1) != 0)
- msg_perr(MSGHEADER "readb byteread"); // FIXME: return error
- msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c);
- return c;
-}
-
-/* Local version that really does the job, doesn't care of max_read_n. */
-static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len)
-{
- unsigned char sbuf[6];
- msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len);
- /* Stream the read-n -- as above. */
- if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes))
- sp_execute_opbuf_noflush();
- sbuf[0] = ((addr >> 0) & 0xFF);
- sbuf[1] = ((addr >> 8) & 0xFF);
- sbuf[2] = ((addr >> 16) & 0xFF);
- sbuf[3] = ((len >> 0) & 0xFF);
- sbuf[4] = ((len >> 8) & 0xFF);
- sbuf[5] = ((len >> 16) & 0xFF);
- sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf);
- if (sp_flush_stream() != 0)
- return 1;
- if (serialport_read(buf, len) != 0) {
- msg_perr(MSGHEADER "Error: cannot read read-n data");
- return 1;
- }
+ register_par_master(&par_master_serprog, serprog_buses_supported & BUS_NONSPI, NULL);
return 0;
-}
-
-/* The externally called version that makes sure that max_read_n is obeyed. */
-static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf,
- const chipaddr addr, size_t len)
-{
- size_t lenm = len;
- chipaddr addrm = addr;
- while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) {
- sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error
- addrm += sp_max_read_n;
- lenm -= sp_max_read_n;
- }
- if (lenm)
- sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error
-}
-void serprog_delay(unsigned int usecs)
-{
- unsigned char buf[4];
- msg_pspew("%s usecs=%d\n", __func__, usecs);
- if (!sp_check_commandavail(S_CMD_O_DELAY)) {
- msg_pdbg2("serprog_delay used, but programmer doesn't support delays natively - emulating\n");
- internal_delay(usecs);
- return;
- }
- if ((sp_max_write_n) && (sp_write_n_bytes))
- sp_pass_writen();
- sp_check_opbuf_usage(5);
- buf[0] = ((usecs >> 0) & 0xFF);
- buf[1] = ((usecs >> 8) & 0xFF);
- buf[2] = ((usecs >> 16) & 0xFF);
- buf[3] = ((usecs >> 24) & 0xFF);
- sp_stream_buffer_op(S_CMD_O_DELAY, 4, buf);
- sp_opbuf_usage += 5;
- sp_prev_was_write = 0;
-}
-
-static int serprog_spi_send_command(const struct flashctx *flash,
- unsigned int writecnt, unsigned int readcnt,
- const unsigned char *writearr,
- unsigned char *readarr)
-{
- unsigned char *parmbuf;
- int ret;
- msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
- if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) {
- if (sp_execute_opbuf() != 0) {
- msg_perr("Error: could not execute command buffer before sending SPI commands.\n");
- return 1;
- }
- }
-
- parmbuf = malloc(writecnt + 6);
- if (!parmbuf) {
- msg_perr("Error: could not allocate SPI send param buffer.\n");
- return 1;
- }
- parmbuf[0] = (writecnt >> 0) & 0xFF;
- parmbuf[1] = (writecnt >> 8) & 0xFF;
- parmbuf[2] = (writecnt >> 16) & 0xFF;
- parmbuf[3] = (readcnt >> 0) & 0xFF;
- parmbuf[4] = (readcnt >> 8) & 0xFF;
- parmbuf[5] = (readcnt >> 16) & 0xFF;
- memcpy(parmbuf + 6, writearr, writecnt);
- ret = sp_docommand(S_CMD_O_SPIOP, writecnt + 6, parmbuf, readcnt,
- readarr);
- free(parmbuf);
- return ret;
+init_err_cleanup_exit:
+ serprog_shutdown(NULL);
+ return 1;
}
-void *serprog_map(const char *descr, uintptr_t phys_addr, size_t len)
-{
- /* Serprog transmits 24 bits only and assumes the underlying implementation handles any remaining bits
- * correctly (usually setting them to one either in software (for FWH/LPC) or relying on the fact that
- * the hardware observes a subset of the address bits only). Combined with the standard mapping of
- * flashrom this creates a 16 MB-wide window just below the 4 GB boundary where serprog can operate (as
- * needed for non-SPI chips). Below we make sure that the requested range is within this window. */
- if ((phys_addr & 0xFF000000) == 0xFF000000) {
- return (void*)phys_addr;
- }
- msg_pwarn(MSGHEADER "requested mapping %s is incompatible: 0x%zx bytes at 0x%0*" PRIxPTR ".\n",
- descr, len, PRIxPTR_WIDTH, phys_addr);
- return NULL;
-}
+const struct programmer_entry programmer_serprog = {
+ .name = "serprog",
+ .type = OTHER,
+ /* FIXME */
+ .devs.note = "All programmer devices speaking the serprog protocol\n",
+ .init = serprog_init,
+};
diff --git a/serprog.h b/serprog.h
deleted file mode 100644
index b54aaeae2..000000000
--- a/serprog.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/* According to Serial Flasher Protocol Specification - version 1 */
-#define S_ACK 0x06
-#define S_NAK 0x15
-#define S_CMD_NOP 0x00 /* No operation */
-#define S_CMD_Q_IFACE 0x01 /* Query interface version */
-#define S_CMD_Q_CMDMAP 0x02 /* Query supported commands bitmap */
-#define S_CMD_Q_PGMNAME 0x03 /* Query programmer name */
-#define S_CMD_Q_SERBUF 0x04 /* Query Serial Buffer Size */
-#define S_CMD_Q_BUSTYPE 0x05 /* Query supported bustypes */
-#define S_CMD_Q_CHIPSIZE 0x06 /* Query supported chipsize (2^n format) */
-#define S_CMD_Q_OPBUF 0x07 /* Query operation buffer size */
-#define S_CMD_Q_WRNMAXLEN 0x08 /* Query Write to opbuf: Write-N maximum length */
-#define S_CMD_R_BYTE 0x09 /* Read a single byte */
-#define S_CMD_R_NBYTES 0x0A /* Read n bytes */
-#define S_CMD_O_INIT 0x0B /* Initialize operation buffer */
-#define S_CMD_O_WRITEB 0x0C /* Write opbuf: Write byte with address */
-#define S_CMD_O_WRITEN 0x0D /* Write to opbuf: Write-N */
-#define S_CMD_O_DELAY 0x0E /* Write opbuf: udelay */
-#define S_CMD_O_EXEC 0x0F /* Execute operation buffer */
-#define S_CMD_SYNCNOP 0x10 /* Special no-operation that returns NAK+ACK */
-#define S_CMD_Q_RDNMAXLEN 0x11 /* Query read-n maximum length */
-#define S_CMD_S_BUSTYPE 0x12 /* Set used bustype(s). */
-#define S_CMD_O_SPIOP 0x13 /* Perform SPI operation. */
-#define S_CMD_S_SPI_FREQ 0x14 /* Set SPI clock frequency */
-#define S_CMD_S_PIN_STATE 0x15 /* Enable/disable output drivers */
diff --git a/sfdp.c b/sfdp.c
index 97f562079..868377933 100644
--- a/sfdp.c
+++ b/sfdp.c
@@ -35,7 +35,7 @@ static int spi_sfdp_read_sfdp_chunk(struct flashctx *flash, uint32_t address, ui
*/
0
};
- msg_cspew("%s: addr=0x%x, len=%d, data:\n", __func__, address, len);
+ msg_cspew("%s: addr=0x%"PRIx32", len=%d, data:\n", __func__, address, len);
newbuf = malloc(len + 1);
if (!newbuf)
return SPI_PROGRAMMER_ERROR;
@@ -81,9 +81,9 @@ static int sfdp_add_uniform_eraser(struct flashchip *chip, uint8_t opcode, uint3
{
int i;
uint32_t total_size = chip->total_size * 1024;
- erasefunc_t *erasefn = spi_get_erasefn_from_opcode(opcode);
+ enum block_erase_func erasefn = spi25_get_erasefn_from_opcode(opcode);
- if (erasefn == NULL || total_size == 0 || block_size == 0 ||
+ if (erasefn == NO_BLOCK_ERASE_FUNC || total_size == 0 || block_size == 0 ||
total_size % block_size != 0) {
msg_cdbg("%s: invalid input, please report to "
"flashrom@flashrom.org\n", __func__);
@@ -96,12 +96,12 @@ static int sfdp_add_uniform_eraser(struct flashchip *chip, uint8_t opcode, uint3
if (eraser->eraseblocks[0].size == block_size &&
eraser->block_erase == erasefn) {
msg_cdbg2(" Tried to add a duplicate block eraser: "
- "%d x %d B with opcode 0x%02x.\n",
+ "%"PRId32" x %"PRId32" B with opcode 0x%02x.\n",
total_size/block_size, block_size, opcode);
return 1;
}
if (eraser->eraseblocks[0].size != 0 ||
- eraser->block_erase != NULL) {
+ eraser->block_erase != NO_BLOCK_ERASE_FUNC) {
msg_cspew(" Block Eraser %d is already occupied.\n",
i);
continue;
@@ -110,7 +110,7 @@ static int sfdp_add_uniform_eraser(struct flashchip *chip, uint8_t opcode, uint3
eraser->block_erase = erasefn;
eraser->eraseblocks[0].size = block_size;
eraser->eraseblocks[0].count = total_size/block_size;
- msg_cdbg2(" Block eraser %d: %d x %d B with opcode "
+ msg_cdbg2(" Block eraser %d: %"PRId32" x %"PRId32" B with opcode "
"0x%02x\n", i, total_size/block_size, block_size,
opcode);
return 0;
@@ -131,10 +131,6 @@ static int sfdp_fill_flash(struct flashchip *chip, uint8_t *buf, uint16_t len)
int j;
msg_cdbg("Parsing JEDEC flash parameter table... ");
- if (len != 9 * 4 && len != 4 * 4) {
- msg_cdbg("%s: len out of spec\n", __func__);
- return 1;
- }
msg_cdbg2("\n");
/* 1. double word */
@@ -183,11 +179,11 @@ static int sfdp_fill_flash(struct flashchip *chip, uint8_t *buf, uint16_t len)
if (tmp32 & (1 << 2)) {
msg_cdbg2("at least 64 B.\n");
chip->page_size = 64;
- chip->write = spi_chip_write_256;
+ chip->write = SPI_CHIP_WRITE256;
} else {
msg_cdbg2("1 B only.\n");
chip->page_size = 256;
- chip->write = spi_chip_write_1;
+ chip->write = SPI_CHIP_WRITE1;
}
if ((tmp32 & 0x3) == 0x1) {
@@ -278,7 +274,7 @@ int probe_spi_sfdp(struct flashctx *flash)
tmp32 |= ((unsigned int)buf[3]) << 24;
if (tmp32 != 0x50444653) {
- msg_cdbg2("Signature = 0x%08x (should be 0x50444653)\n", tmp32);
+ msg_cdbg2("Signature = 0x%08"PRIx32" (should be 0x50444653)\n", tmp32);
msg_cdbg("No SFDP signature found.\n");
return 0;
}
@@ -300,7 +296,7 @@ int probe_spi_sfdp(struct flashctx *flash)
/* Fetch all parameter headers, even if we don't use them all (yet). */
hbuf = malloc((nph + 1) * 8);
- hdrs = malloc((nph + 1) * sizeof(struct sfdp_tbl_hdr));
+ hdrs = malloc((nph + 1) * sizeof(*hdrs));
if (hbuf == NULL || hdrs == NULL ) {
msg_gerr("Out of memory!\n");
goto cleanup_hdrs;
@@ -324,7 +320,7 @@ int probe_spi_sfdp(struct flashctx *flash)
hdrs[i].v_major, hdrs[i].v_minor);
len = hdrs[i].len * 4;
tmp32 = hdrs[i].ptp;
- msg_cdbg2(" Length %d B, Parameter Table Pointer 0x%06x\n",
+ msg_cdbg2(" Length %d B, Parameter Table Pointer 0x%06"PRIx32"\n",
len, tmp32);
if (tmp32 + len >= (1 << 24)) {
@@ -349,7 +345,7 @@ int probe_spi_sfdp(struct flashctx *flash)
msg_cspew(" Parameter table contents:\n");
for (tmp32 = 0; tmp32 < len; tmp32++) {
if ((tmp32 % 8) == 0) {
- msg_cspew(" 0x%04x: ", tmp32);
+ msg_cspew(" 0x%04"PRIx32": ", tmp32);
}
msg_cspew(" %02x", tbuf[tmp32]);
if ((tmp32 % 8) == 7) {
@@ -373,7 +369,7 @@ int probe_spi_sfdp(struct flashctx *flash)
msg_cdbg("The chip contains an unknown "
"version of the JEDEC flash "
"parameters table, skipping it.\n");
- } else if (len != 9 * 4 && len != 4 * 4) {
+ } else if (len != 4 * 4 && len < 9 * 4) {
msg_cdbg("Length of the mandatory JEDEC SFDP "
"parameter table is wrong (%d B), "
"skipping it.\n", len);
diff --git a/spi.c b/spi.c
index aed2a927a..3e81da2a5 100644
--- a/spi.c
+++ b/spi.c
@@ -26,20 +26,7 @@
#include "programmer.h"
#include "spi.h"
-int spi_send_command(const struct flashctx *flash, unsigned int writecnt,
- unsigned int readcnt, const unsigned char *writearr,
- unsigned char *readarr)
-{
- return flash->mst->spi.command(flash, writecnt, readcnt, writearr,
- readarr);
-}
-
-int spi_send_multicommand(const struct flashctx *flash, struct spi_command *cmds)
-{
- return flash->mst->spi.multicommand(flash, cmds);
-}
-
-int default_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
+static int default_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
unsigned int readcnt,
const unsigned char *writearr,
unsigned char *readarr)
@@ -60,7 +47,7 @@ int default_spi_send_command(const struct flashctx *flash, unsigned int writecnt
return spi_send_multicommand(flash, cmd);
}
-int default_spi_send_multicommand(const struct flashctx *flash,
+static int default_spi_send_multicommand(const struct flashctx *flash,
struct spi_command *cmds)
{
int result = 0;
@@ -71,6 +58,22 @@ int default_spi_send_multicommand(const struct flashctx *flash,
return result;
}
+int spi_send_command(const struct flashctx *flash, unsigned int writecnt,
+ unsigned int readcnt, const unsigned char *writearr,
+ unsigned char *readarr)
+{
+ if (flash->mst->spi.command)
+ return flash->mst->spi.command(flash, writecnt, readcnt, writearr, readarr);
+ return default_spi_send_command(flash, writecnt, readcnt, writearr, readarr);
+}
+
+int spi_send_multicommand(const struct flashctx *flash, struct spi_command *cmds)
+{
+ if (flash->mst->spi.multicommand)
+ return flash->mst->spi.multicommand(flash, cmds);
+ return default_spi_send_multicommand(flash, cmds);
+}
+
int default_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
unsigned int len)
{
@@ -101,6 +104,8 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
{
int ret;
size_t to_read;
+ size_t start_address = start;
+ size_t end_address = len - start;
for (; len; len -= to_read, buf += to_read, start += to_read) {
/* Do not cross 16MiB boundaries in a single transfer.
This helps with
@@ -110,6 +115,7 @@ int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start,
ret = flash->mst->spi.read(flash, buf, start, to_read);
if (ret)
return ret;
+ update_progress(flash, FLASHROM_PROGRESS_READ, start - start_address + to_read, end_address);
}
return 0;
}
@@ -128,17 +134,30 @@ int spi_chip_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int
int spi_aai_write(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
{
- return flash->mst->spi.write_aai(flash, buf, start, len);
+ if (flash->mst->spi.write_aai)
+ return flash->mst->spi.write_aai(flash, buf, start, len);
+ return default_spi_write_aai(flash, buf, start, len);
}
-int register_spi_master(const struct spi_master *mst)
+bool spi_probe_opcode(const struct flashctx *flash, uint8_t opcode)
{
- struct registered_master rmst;
+ if (!flash->mst->spi.probe_opcode)
+ return true; /* no probe_opcode implies default of supported. */
+ return flash->mst->spi.probe_opcode(flash, opcode);
+}
+
+int register_spi_master(const struct spi_master *mst, void *data)
+{
+ struct registered_master rmst = {0};
+
+ if (mst->shutdown) {
+ if (register_shutdown(mst->shutdown, data)) {
+ mst->shutdown(data); /* cleanup */
+ return 1;
+ }
+ }
- if (!mst->write_aai || !mst->write_256 || !mst->read || !mst->command ||
- !mst->multicommand ||
- ((mst->command == default_spi_send_command) &&
- (mst->multicommand == default_spi_send_multicommand))) {
+ if (!mst->write_256 || !mst->read || (!mst->command && !mst->multicommand)) {
msg_perr("%s called with incomplete master definition. "
"Please report a bug at flashrom@flashrom.org\n",
__func__);
@@ -148,5 +167,69 @@ int register_spi_master(const struct spi_master *mst)
rmst.buses_supported = BUS_SPI;
rmst.spi = *mst;
+ if (data)
+ rmst.spi.data = data;
return register_master(&rmst);
}
+
+/*
+ * The following array has erasefn and opcode list pair. The opcode list pair is
+ * 0 termintated and must have size one more than the maximum number of opcodes
+ * used by any erasefn. Also the opcodes must be in increasing order.
+ */
+static const struct {
+ enum block_erase_func func;
+ uint8_t opcode[3];
+} function_opcode_list[] = {
+ {SPI_BLOCK_ERASE_20, {0x20}},
+ {SPI_BLOCK_ERASE_21, {0x21}},
+ {SPI_BLOCK_ERASE_50, {0x50}},
+ {SPI_BLOCK_ERASE_52, {0x52}},
+ {SPI_BLOCK_ERASE_53, {0x53}},
+ {SPI_BLOCK_ERASE_5C, {0x5c}},
+ {SPI_BLOCK_ERASE_60, {0x60}},
+ {SPI_BLOCK_ERASE_62, {0x62}},
+ {SPI_BLOCK_ERASE_81, {0x81}},
+ {SPI_BLOCK_ERASE_C4, {0xc4}},
+ {SPI_BLOCK_ERASE_C7, {0xc7}},
+ {SPI_BLOCK_ERASE_D7, {0xd7}},
+ {SPI_BLOCK_ERASE_D8, {0xd8}},
+ {SPI_BLOCK_ERASE_DB, {0xdb}},
+ {SPI_BLOCK_ERASE_DC, {0xdc}},
+ //AT45CS1282
+ {SPI_ERASE_AT45CS_SECTOR, {0x50, 0x7c, 0}},
+ //AT45DB**
+ {SPI_ERASE_AT45DB_PAGE, {0x81}},
+ {SPI_ERASE_AT45DB_BLOCK, {0x50}},
+ {SPI_ERASE_AT45DB_SECTOR, {0x7c}},
+ {SPI_ERASE_AT45DB_CHIP, {0xc7}},
+ //SF25F**
+ {S25FL_BLOCK_ERASE, {0xdc}},
+ {S25FS_BLOCK_ERASE_D8, {0xd8}},
+};
+
+/*
+ * @brief Get erase function pointer from passed opcode list.
+ *
+ * Get the pointer to the erase function which uses passed opcodes and is used
+ * by the passed flashcip. The passed opcode_list must have opcodes in
+ * increasing order.
+ *
+ * @param chip Pointer to the flashchip structure.
+ * @param opcode_list Pointer to the array of opcodes.
+ * @param opcode_count Number of opcodes in 'opcode_list'
+ *
+ * @result Pointer to erase function matching 'chip' and 'opcode_list' or NULL on failure
+ */
+const uint8_t *spi_get_opcode_from_erasefn(enum block_erase_func func)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(function_opcode_list); i++) {
+ if (function_opcode_list[i].func == func)
+ return function_opcode_list[i].opcode;
+ }
+ msg_cinfo("%s: unknown erase function (0x%d). Please report "
+ "this at flashrom@flashrom.org\n", __func__, func);
+ return NULL;
+}
+
diff --git a/spi25.c b/spi25.c
index 213273f21..6a6ee75da 100644
--- a/spi25.c
+++ b/spi25.c
@@ -37,7 +37,7 @@ enum id_type {
};
static struct {
- int is_cached;
+ bool is_cached;
unsigned char bytes[4]; /* enough to hold largest ID type */
} id_cache[NUM_ID_TYPES];
@@ -141,7 +141,7 @@ static int compare_id(const struct flashctx *flash, uint32_t id1, uint32_t id2)
{
const struct flashchip *chip = flash->chip;
- msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+ msg_cdbg("%s: id1 0x%02"PRIx32", id2 0x%02"PRIx32"\n", __func__, id1, id2);
if (id1 == chip->manufacture_id && id2 == chip->model_id)
return 1;
@@ -167,7 +167,7 @@ static int probe_spi_rdid_generic(struct flashctx *flash, int bytes)
msg_cinfo("%d byte RDID not supported on this SPI controller\n", bytes);
if (ret)
return 0;
- id_cache[idty].is_cached = 1;
+ id_cache[idty].is_cached = true;
}
rdid_get_ids(id_cache[idty].bytes, bytes, &id1, &id2);
@@ -191,7 +191,7 @@ int probe_spi_rems(struct flashctx *flash)
if (!id_cache[REMS].is_cached) {
if (spi_rems(flash, id_cache[REMS].bytes))
return 0;
- id_cache[REMS].is_cached = 1;
+ id_cache[REMS].is_cached = true;
}
id1 = id_cache[REMS].bytes[0];
@@ -232,7 +232,7 @@ int probe_spi_res1(struct flashctx *flash)
id2 = readarr[0];
- msg_cdbg("%s: id 0x%x\n", __func__, id2);
+ msg_cdbg("%s: id 0x%"PRIx32"\n", __func__, id2);
if (id2 != flash->chip->model_id)
return 0;
@@ -247,12 +247,12 @@ int probe_spi_res2(struct flashctx *flash)
if (!id_cache[RES2].is_cached) {
if (spi_res(flash, id_cache[RES2].bytes, 2))
return 0;
- id_cache[RES2].is_cached = 1;
+ id_cache[RES2].is_cached = true;
}
id1 = id_cache[RES2].bytes[0];
id2 = id_cache[RES2].bytes[1];
- msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
+ msg_cdbg("%s: id1 0x%"PRIx32", id2 0x%"PRIx32"\n", __func__, id1, id2);
if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
return 0;
@@ -267,12 +267,12 @@ int probe_spi_res3(struct flashctx *flash)
if (!id_cache[RES3].is_cached) {
if (spi_res(flash, id_cache[RES3].bytes, 3))
return 0;
- id_cache[RES3].is_cached = 1;
+ id_cache[RES3].is_cached = true;
}
id1 = (id_cache[RES3].bytes[0] << 8) | id_cache[RES3].bytes[1];
id2 = id_cache[RES3].bytes[3];
- msg_cdbg("%s: id1 0x%x, id2 0x%x\n", __func__, id1, id2);
+ msg_cdbg("%s: id1 0x%"PRIx32", id2 0x%"PRIx32"\n", __func__, id1, id2);
if (id1 != flash->chip->manufacture_id || id2 != flash->chip->model_id)
return 0;
@@ -294,7 +294,7 @@ int probe_spi_at25f(struct flashctx *flash)
id1 = readarr[0];
id2 = readarr[1];
- msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+ msg_cdbg("%s: id1 0x%02"PRIx32", id2 0x%02"PRIx32"\n", __func__, id1, id2);
if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
return 1;
@@ -304,12 +304,17 @@ int probe_spi_at25f(struct flashctx *flash)
static int spi_poll_wip(struct flashctx *const flash, const unsigned int poll_delay)
{
- /* FIXME: We can't tell if spi_read_status_register() failed. */
/* FIXME: We don't time out. */
- while (spi_read_status_register(flash) & SPI_SR_WIP)
- programmer_delay(poll_delay);
- /* FIXME: Check the status register for errors. */
- return 0;
+ while (true) {
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
+ if (!(status & SPI_SR_WIP))
+ return 0;
+
+ programmer_delay(flash, poll_delay);
+ }
}
/**
@@ -346,7 +351,16 @@ static int spi_simple_write_cmd(struct flashctx *const flash, const uint8_t op,
static int spi_write_extended_address_register(struct flashctx *const flash, const uint8_t regdata)
{
- const uint8_t op = flash->chip->wrea_override ? : JEDEC_WRITE_EXT_ADDR_REG;
+ uint8_t op;
+ if (flash->chip->feature_bits & FEATURE_4BA_EAR_C5C8) {
+ op = JEDEC_WRITE_EXT_ADDR_REG;
+ } else if (flash->chip->feature_bits & FEATURE_4BA_EAR_1716) {
+ op = ALT_WRITE_EXT_ADDR_REG_17;
+ } else {
+ msg_cerr("Flash misses feature flag for extended-address register.\n");
+ return -1;
+ }
+
struct spi_command cmds[] = {
{
.readarr = 0,
@@ -389,7 +403,7 @@ static int spi_prepare_address(struct flashctx *const flash, uint8_t cmd_buf[],
cmd_buf[4] = (addr >> 0) & 0xff;
return 4;
} else {
- if (flash->chip->feature_bits & FEATURE_4BA_EXT_ADDR) {
+ if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) {
if (spi_set_extended_address(flash, addr >> 24))
return -1;
} else if (addr >> 24) {
@@ -584,6 +598,13 @@ int spi_block_erase_21(struct flashctx *flash, unsigned int addr, unsigned int b
}
/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
+int spi_block_erase_53(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
+{
+ /* This usually takes 100-4000ms, so wait in 100ms steps. */
+ return spi_write_cmd(flash, 0x53, true, addr, NULL, 0, 100 * 1000);
+}
+
+/* Erase 32 KB of flash with 4-bytes address from ANY mode (3-bytes or 4-bytes) */
int spi_block_erase_5c(struct flashctx *flash, unsigned int addr, unsigned int blocklen)
{
/* This usually takes 100-4000ms, so wait in 100ms steps. */
@@ -597,46 +618,37 @@ int spi_block_erase_dc(struct flashctx *flash, unsigned int addr, unsigned int b
return spi_write_cmd(flash, 0xdc, true, addr, NULL, 0, 100 * 1000);
}
-erasefunc_t *spi_get_erasefn_from_opcode(uint8_t opcode)
-{
- switch(opcode){
- case 0xff:
- case 0x00:
- /* Not specified, assuming "not supported". */
- return NULL;
- case 0x20:
- return &spi_block_erase_20;
- case 0x21:
- return &spi_block_erase_21;
- case 0x50:
- return &spi_block_erase_50;
- case 0x52:
- return &spi_block_erase_52;
- case 0x5c:
- return &spi_block_erase_5c;
- case 0x60:
- return &spi_block_erase_60;
- case 0x62:
- return &spi_block_erase_62;
- case 0x81:
- return &spi_block_erase_81;
- case 0xc4:
- return &spi_block_erase_c4;
- case 0xc7:
- return &spi_block_erase_c7;
- case 0xd7:
- return &spi_block_erase_d7;
- case 0xd8:
- return &spi_block_erase_d8;
- case 0xdb:
- return &spi_block_erase_db;
- case 0xdc:
- return &spi_block_erase_dc;
- default:
- msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
- "this at flashrom@flashrom.org\n", __func__, opcode);
- return NULL;
+static const struct {
+ enum block_erase_func func;
+ uint8_t opcode;
+} spi25_function_opcode_list[] = {
+ {SPI_BLOCK_ERASE_20, 0x20},
+ {SPI_BLOCK_ERASE_21, 0x21},
+ {SPI_BLOCK_ERASE_50, 0x50},
+ {SPI_BLOCK_ERASE_52, 0x52},
+ {SPI_BLOCK_ERASE_53, 0x53},
+ {SPI_BLOCK_ERASE_5C, 0x5c},
+ {SPI_BLOCK_ERASE_60, 0x60},
+ {SPI_BLOCK_ERASE_62, 0x62},
+ {SPI_BLOCK_ERASE_81, 0x81},
+ {SPI_BLOCK_ERASE_C4, 0xc4},
+ {SPI_BLOCK_ERASE_C7, 0xc7},
+ {SPI_BLOCK_ERASE_D7, 0xd7},
+ {SPI_BLOCK_ERASE_D8, 0xd8},
+ {SPI_BLOCK_ERASE_DB, 0xdb},
+ {SPI_BLOCK_ERASE_DC, 0xdc},
+};
+
+enum block_erase_func spi25_get_erasefn_from_opcode(uint8_t opcode)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(spi25_function_opcode_list); i++) {
+ if (spi25_function_opcode_list[i].opcode == opcode)
+ return spi25_function_opcode_list[i].func;
}
+ msg_cinfo("%s: unknown erase opcode (0x%02x). Please report "
+ "this at flashrom@flashrom.org\n", __func__, opcode);
+ return NO_BLOCK_ERASE_FUNC;
}
static int spi_nbyte_program(struct flashctx *flash, unsigned int addr, const uint8_t *bytes, unsigned int len)
@@ -669,11 +681,14 @@ int spi_read_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start,
{
int ret;
size_t to_read;
+ size_t start_address = start;
+ size_t end_address = len - start;
for (; len; len -= to_read, buf += to_read, start += to_read) {
to_read = min(chunksize, len);
ret = spi_nbyte_read(flash, start, buf, to_read);
if (ret)
return ret;
+ update_progress(flash, FLASHROM_PROGRESS_READ, start - start_address + to_read, end_address);
}
return 0;
}
@@ -693,6 +708,8 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s
* we're OK for now.
*/
unsigned int page_size = flash->chip->page_size;
+ size_t start_address = start;
+ size_t end_address = len - start;
/* Warning: This loop has a very unusual condition and body.
* The loop needs to go through each page with at least one affected
@@ -717,6 +734,7 @@ int spi_write_chunked(struct flashctx *flash, const uint8_t *buf, unsigned int s
if (rc)
return rc;
}
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, start - start_address + lenhere, end_address);
}
return 0;
@@ -736,6 +754,7 @@ int spi_chip_write_1(struct flashctx *flash, const uint8_t *buf, unsigned int st
for (i = start; i < start + len; i++) {
if (spi_nbyte_program(flash, i, buf + i - start, 1))
return 1;
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i - start, len - start);
}
return 0;
}
diff --git a/spi25_statusreg.c b/spi25_statusreg.c
index a0b0fcf5e..bb56ee1a8 100644
--- a/spi25_statusreg.c
+++ b/spi25_statusreg.c
@@ -17,29 +17,146 @@
* GNU General Public License for more details.
*/
+#include <stdlib.h>
+
#include "flash.h"
#include "chipdrivers.h"
+#include "programmer.h"
#include "spi.h"
/* === Generic functions === */
-static int spi_write_status_register_flag(const struct flashctx *flash, int status, const unsigned char enable_opcode)
+
+/*
+ * Writing SR2 or higher with an extended WRSR command requires
+ * writing all lower SRx along with it, so just read the lower
+ * SRx and write them back.
+ */
+static int spi_prepare_wrsr_ext(
+ uint8_t write_cmd[4], size_t *const write_cmd_len,
+ const struct flashctx *const flash,
+ const enum flash_reg reg, const uint8_t value)
{
- int result;
- int i = 0;
+ enum flash_reg reg_it;
+ size_t i = 0;
+
+ write_cmd[i++] = JEDEC_WRSR;
+
+ for (reg_it = STATUS1; reg_it < reg; ++reg_it) {
+ uint8_t sr;
+
+ if (spi_read_register(flash, reg_it, &sr)) {
+ msg_cerr("Writing SR%d failed: failed to read SR%d for writeback.\n",
+ reg - STATUS1 + 1, reg_it - STATUS1 + 1);
+ return 1;
+ }
+ write_cmd[i++] = sr;
+ }
+
+ write_cmd[i++] = value;
+ *write_cmd_len = i;
+
+ return 0;
+}
+
+int spi_write_register(const struct flashctx *flash, enum flash_reg reg, uint8_t value)
+{
+ int feature_bits = flash->chip->feature_bits;
+
+ uint8_t write_cmd[4];
+ size_t write_cmd_len = 0;
+
/*
- * WRSR requires either EWSR or WREN depending on chip type.
- * The code below relies on the fact hat EWSR and WREN have the same
- * INSIZE and OUTSIZE.
+ * Create SPI write command sequence based on the destination register
+ * and the chip's supported command set.
*/
+ switch (reg) {
+ case STATUS1:
+ write_cmd[0] = JEDEC_WRSR;
+ write_cmd[1] = value;
+ write_cmd_len = JEDEC_WRSR_OUTSIZE;
+ break;
+ case STATUS2:
+ if (feature_bits & FEATURE_WRSR2) {
+ write_cmd[0] = JEDEC_WRSR2;
+ write_cmd[1] = value;
+ write_cmd_len = JEDEC_WRSR2_OUTSIZE;
+ break;
+ }
+ if (feature_bits & FEATURE_WRSR_EXT2) {
+ if (spi_prepare_wrsr_ext(write_cmd, &write_cmd_len, flash, reg, value))
+ return 1;
+ break;
+ }
+ msg_cerr("Cannot write SR2: unsupported by chip\n");
+ return 1;
+ case STATUS3:
+ if (feature_bits & FEATURE_WRSR3) {
+ write_cmd[0] = JEDEC_WRSR3;
+ write_cmd[1] = value;
+ write_cmd_len = JEDEC_WRSR3_OUTSIZE;
+ break;
+ }
+ if ((feature_bits & FEATURE_WRSR_EXT3) == FEATURE_WRSR_EXT3) {
+ if (spi_prepare_wrsr_ext(write_cmd, &write_cmd_len, flash, reg, value))
+ return 1;
+ break;
+ }
+ msg_cerr("Cannot write SR3: unsupported by chip\n");
+ return 1;
+ case SECURITY:
+ /*
+ * Security register doesn't have a normal write operation. Instead,
+ * there are separate commands that set individual OTP bits.
+ */
+ msg_cerr("Cannot write SECURITY: unsupported by design\n");
+ return 1;
+ case CONFIG:
+ /*
+ * This one is read via a separate command, but written as if it's SR2
+ * in FEATURE_WRSR_EXT2 case of WRSR command.
+ */
+ if (feature_bits & FEATURE_CFGR) {
+ write_cmd[0] = JEDEC_WRSR;
+ if (spi_read_register(flash, STATUS1, &write_cmd[1])) {
+ msg_cerr("Writing CONFIG failed: failed to read SR1 for writeback.\n");
+ return 1;
+ }
+ write_cmd[2] = value;
+ write_cmd_len = 3;
+ break;
+ }
+ msg_cerr("Cannot write CONFIG: unsupported by chip\n");
+ return 1;
+ default:
+ msg_cerr("Cannot write register: unknown register\n");
+ return 1;
+ }
+
+ if (!spi_probe_opcode(flash, write_cmd[0])) {
+ msg_pdbg("%s: write to register %d not supported by programmer, ignoring.\n", __func__, reg);
+ return SPI_INVALID_OPCODE;
+ }
+
+ uint8_t enable_cmd;
+ if (feature_bits & FEATURE_WRSR_WREN) {
+ enable_cmd = JEDEC_WREN;
+ } else if (feature_bits & FEATURE_WRSR_EWSR) {
+ enable_cmd = JEDEC_EWSR;
+ } else {
+ msg_cdbg("Missing status register write definition, assuming "
+ "EWSR is needed\n");
+ enable_cmd = JEDEC_EWSR;
+ }
+
struct spi_command cmds[] = {
{
.writecnt = JEDEC_WREN_OUTSIZE,
- .writearr = (const unsigned char[]){ enable_opcode },
+ .writearr = &enable_cmd,
.readcnt = 0,
.readarr = NULL,
}, {
- .writecnt = JEDEC_WRSR_OUTSIZE,
- .writearr = (const unsigned char[]){ JEDEC_WRSR, (unsigned char) status },
+ .writecnt = write_cmd_len,
+ .writearr = write_cmd,
.readcnt = 0,
.readarr = NULL,
}, {
@@ -49,69 +166,113 @@ static int spi_write_status_register_flag(const struct flashctx *flash, int stat
.readarr = NULL,
}};
- result = spi_send_multicommand(flash, cmds);
+ int result = spi_send_multicommand(flash, cmds);
if (result) {
msg_cerr("%s failed during command execution\n", __func__);
- /* No point in waiting for the command to complete if execution
- * failed.
- */
return result;
}
- /* WRSR performs a self-timed erase before the changes take effect.
+
+ /*
+ * WRSR performs a self-timed erase before the changes take effect.
* This may take 50-85 ms in most cases, and some chips apparently
* allow running RDSR only once. Therefore pick an initial delay of
* 100 ms, then wait in 10 ms steps until a total of 5 s have elapsed.
+ *
+ * Newer chips with multiple status registers (SR2 etc.) are unlikely
+ * to have problems with multiple RDSR commands, so only wait for the
+ * initial 100 ms if the register we wrote to was SR1.
*/
- programmer_delay(100 * 1000);
- while (spi_read_status_register(flash) & SPI_SR_WIP) {
- if (++i > 490) {
- msg_cerr("Error: WIP bit after WRSR never cleared\n");
- return TIMEOUT_ERROR;
- }
- programmer_delay(10 * 1000);
+ int delay_ms = 5000;
+ if (reg == STATUS1) {
+ programmer_delay(flash, 100 * 1000);
+ delay_ms -= 100;
}
- return 0;
+
+ for (; delay_ms > 0; delay_ms -= 10) {
+ uint8_t status;
+ result = spi_read_register(flash, STATUS1, &status);
+ if (result)
+ return result;
+ if ((status & SPI_SR_WIP) == 0)
+ return 0;
+ programmer_delay(flash, 10 * 1000);
+ }
+
+
+ msg_cerr("Error: WIP bit after WRSR never cleared\n");
+ return TIMEOUT_ERROR;
}
-int spi_write_status_register(const struct flashctx *flash, int status)
+int spi_read_register(const struct flashctx *flash, enum flash_reg reg, uint8_t *value)
{
int feature_bits = flash->chip->feature_bits;
- int ret = 1;
+ uint8_t read_cmd;
- if (!(feature_bits & (FEATURE_WRSR_WREN | FEATURE_WRSR_EWSR))) {
- msg_cdbg("Missing status register write definition, assuming "
- "EWSR is needed\n");
- feature_bits |= FEATURE_WRSR_EWSR;
+ switch (reg) {
+ case STATUS1:
+ read_cmd = JEDEC_RDSR;
+ break;
+ case STATUS2:
+ if (feature_bits & (FEATURE_WRSR_EXT2 | FEATURE_WRSR2)) {
+ read_cmd = JEDEC_RDSR2;
+ break;
+ }
+ msg_cerr("Cannot read SR2: unsupported by chip\n");
+ return 1;
+ case STATUS3:
+ if ((feature_bits & FEATURE_WRSR_EXT3) == FEATURE_WRSR_EXT3
+ || (feature_bits & FEATURE_WRSR3)) {
+ read_cmd = JEDEC_RDSR3;
+ break;
+ }
+ msg_cerr("Cannot read SR3: unsupported by chip\n");
+ return 1;
+ case SECURITY:
+ if (feature_bits & FEATURE_SCUR) {
+ read_cmd = JEDEC_RDSCUR;
+ break;
+ }
+ msg_cerr("Cannot read SECURITY: unsupported by chip\n");
+ return 1;
+ case CONFIG:
+ if (feature_bits & FEATURE_CFGR) {
+ read_cmd = JEDEC_RDCR;
+ break;
+ }
+ msg_cerr("Cannot read CONFIG: unsupported by chip\n");
+ return 1;
+ default:
+ msg_cerr("Cannot read register: unknown register\n");
+ return 1;
+ }
+
+ if (!spi_probe_opcode(flash, read_cmd)) {
+ msg_pdbg("%s: read from register %d not supported by programmer.\n", __func__, reg);
+ return SPI_INVALID_OPCODE;
}
- if (feature_bits & FEATURE_WRSR_WREN)
- ret = spi_write_status_register_flag(flash, status, JEDEC_WREN);
- if (ret && (feature_bits & FEATURE_WRSR_EWSR))
- ret = spi_write_status_register_flag(flash, status, JEDEC_EWSR);
- return ret;
-}
-uint8_t spi_read_status_register(const struct flashctx *flash)
-{
- static const unsigned char cmd[JEDEC_RDSR_OUTSIZE] = { JEDEC_RDSR };
/* FIXME: No workarounds for driver/hardware bugs in generic code. */
- unsigned char readarr[2]; /* JEDEC_RDSR_INSIZE=1 but wbsio needs 2 */
- int ret;
+ /* JEDEC_RDSR_INSIZE=1 but wbsio needs 2 */
+ uint8_t readarr[2];
- /* Read Status Register */
- ret = spi_send_command(flash, sizeof(cmd), sizeof(readarr), cmd, readarr);
+ int ret = spi_send_command(flash, sizeof(read_cmd), sizeof(readarr), &read_cmd, readarr);
if (ret) {
- msg_cerr("RDSR failed!\n");
- /* FIXME: We should propagate the error. */
- return 0;
+ msg_cerr("Register read failed!\n");
+ return ret;
}
- return readarr[0];
+ *value = readarr[0];
+ msg_cspew("%s: read_cmd 0x%02x returned 0x%02x\n", __func__, read_cmd, readarr[0]);
+ return 0;
}
-static int spi_restore_status(struct flashctx *flash, uint8_t status)
+static int spi_restore_status(struct flashctx *flash, void *data)
{
+ uint8_t status = *(uint8_t *)data;
+ free(data);
+
msg_cdbg("restoring chip status (0x%02x)\n", status);
- return spi_write_status_register(flash, status);
+ return spi_write_register(flash, STATUS1, status);
}
/* A generic block protection disable.
@@ -139,14 +300,23 @@ static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_m
uint8_t status;
int result;
- status = spi_read_status_register(flash);
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
+
if ((status & bp_mask) == 0) {
msg_cdbg2("Block protection is disabled.\n");
return 0;
}
/* Restore status register content upon exit in finalize_flash_access(). */
- register_chip_restore(spi_restore_status, flash, status);
+ uint8_t *data = calloc(sizeof(uint8_t), 1);
+ if (!data) {
+ msg_cerr("Out of memory!\n");
+ return 1;
+ }
+ *data = status;
+ register_chip_restore(spi_restore_status, flash, data);
msg_cdbg("Some block protection in effect, disabling... ");
if ((status & lock_mask) != 0) {
@@ -156,12 +326,16 @@ static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_m
return 1;
}
/* All bits except the register lock bit (often called SPRL, SRWD, WPEN) are readonly. */
- result = spi_write_status_register(flash, status & ~lock_mask);
+ result = spi_write_register(flash, STATUS1, status & ~lock_mask);
if (result) {
- msg_cerr("spi_write_status_register failed.\n");
+ msg_cerr("Could not write status register 1.\n");
return result;
}
- status = spi_read_status_register(flash);
+
+ ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
+
if ((status & lock_mask) != 0) {
msg_cerr("Unsetting lock bit(s) failed.\n");
return 1;
@@ -169,16 +343,21 @@ static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_m
msg_cdbg("done.\n");
}
/* Global unprotect. Make sure to mask the register lock bit as well. */
- result = spi_write_status_register(flash, status & ~(bp_mask | lock_mask) & unprotect_mask);
+ result = spi_write_register(flash, STATUS1, status & ~(bp_mask | lock_mask) & unprotect_mask);
if (result) {
- msg_cerr("spi_write_status_register failed.\n");
+ msg_cerr("Could not write status register 1.\n");
return result;
}
- status = spi_read_status_register(flash);
+
+ ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
+
if ((status & bp_mask) != 0) {
msg_cerr("Block protection could not be disabled!\n");
- if (flash->chip->printlock)
- flash->chip->printlock(flash);
+ printlockfunc_t *printlock = lookup_printlock_func_ptr(flash);
+ if (printlock)
+ printlock(flash);
return 1;
}
msg_cdbg("disabled.\n");
@@ -186,12 +365,12 @@ static int spi_disable_blockprotect_generic(struct flashctx *flash, uint8_t bp_m
}
/* A common block protection disable that tries to unset the status register bits masked by 0x3C. */
-int spi_disable_blockprotect(struct flashctx *flash)
+static int spi_disable_blockprotect(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x3C, 0, 0, 0xFF);
}
-int spi_disable_blockprotect_sst26_global_unprotect(struct flashctx *flash)
+static int spi_disable_blockprotect_sst26_global_unprotect(struct flashctx *flash)
{
int result = spi_write_enable(flash);
if (result)
@@ -206,7 +385,7 @@ int spi_disable_blockprotect_sst26_global_unprotect(struct flashctx *flash)
/* A common block protection disable that tries to unset the status register bits masked by 0x0C (BP0-1) and
* protected/locked by bit #7. Useful when bits 4-5 may be non-0). */
-int spi_disable_blockprotect_bp1_srwd(struct flashctx *flash)
+static int spi_disable_blockprotect_bp1_srwd(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 0, 0xFF);
}
@@ -214,21 +393,21 @@ int spi_disable_blockprotect_bp1_srwd(struct flashctx *flash)
/* A common block protection disable that tries to unset the status register bits masked by 0x1C (BP0-2) and
* protected/locked by bit #7. Useful when bit #5 is neither a protection bit nor reserved (and hence possibly
* non-0). */
-int spi_disable_blockprotect_bp2_srwd(struct flashctx *flash)
+static int spi_disable_blockprotect_bp2_srwd(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x1C, 1 << 7, 0, 0xFF);
}
/* A common block protection disable that tries to unset the status register bits masked by 0x3C (BP0-3) and
* protected/locked by bit #7. */
-int spi_disable_blockprotect_bp3_srwd(struct flashctx *flash)
+static int spi_disable_blockprotect_bp3_srwd(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x3C, 1 << 7, 0, 0xFF);
}
/* A common block protection disable that tries to unset the status register bits masked by 0x7C (BP0-4) and
* protected/locked by bit #7. */
-int spi_disable_blockprotect_bp4_srwd(struct flashctx *flash)
+static int spi_disable_blockprotect_bp4_srwd(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x7C, 1 << 7, 0, 0xFF);
}
@@ -293,17 +472,23 @@ void spi_prettyprint_status_register_bit(uint8_t status, int bit)
msg_cdbg("Chip status register: Bit %i is %sset\n", bit, (status & (1 << bit)) ? "" : "not ");
}
-int spi_prettyprint_status_register_plain(struct flashctx *flash)
+static int spi_prettyprint_status_register_plain(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
return 0;
}
/* Print the plain hex value and the welwip bits only. */
-int spi_prettyprint_status_register_default_welwip(struct flashctx *flash)
+static int spi_prettyprint_status_register_default_welwip(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_welwip(status);
@@ -314,9 +499,12 @@ int spi_prettyprint_status_register_default_welwip(struct flashctx *flash)
* AMIC A25L series
* and MX MX25L512
*/
-int spi_prettyprint_status_register_bp1_srwd(struct flashctx *flash)
+static int spi_prettyprint_status_register_bp1_srwd(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_srwd(status);
@@ -332,9 +520,12 @@ int spi_prettyprint_status_register_bp1_srwd(struct flashctx *flash)
* AMIC A25L series
* PMC Pm25LD series
*/
-int spi_prettyprint_status_register_bp2_srwd(struct flashctx *flash)
+static int spi_prettyprint_status_register_bp2_srwd(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_srwd(status);
@@ -349,9 +540,12 @@ int spi_prettyprint_status_register_bp2_srwd(struct flashctx *flash)
* ST M25P series
* MX MX25L series
*/
-int spi_prettyprint_status_register_bp3_srwd(struct flashctx *flash)
+static int spi_prettyprint_status_register_bp3_srwd(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_srwd(status);
@@ -361,9 +555,12 @@ int spi_prettyprint_status_register_bp3_srwd(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_bp4_srwd(struct flashctx *flash)
+static int spi_prettyprint_status_register_bp4_srwd(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_srwd(status);
@@ -372,9 +569,12 @@ int spi_prettyprint_status_register_bp4_srwd(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_bp2_bpl(struct flashctx *flash)
+static int spi_prettyprint_status_register_bp2_bpl(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_bpl(status);
@@ -385,9 +585,12 @@ int spi_prettyprint_status_register_bp2_bpl(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_bp2_tb_bpl(struct flashctx *flash)
+static int spi_prettyprint_status_register_bp2_tb_bpl(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_bpl(status);
@@ -407,9 +610,12 @@ int spi_prettyprint_status_register_bp2_tb_bpl(struct flashctx *flash)
* by the second status register.
*/
-int spi_prettyprint_status_register_amic_a25l032(struct flashctx *flash)
+static int spi_prettyprint_status_register_amic_a25l032(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_srwd(status);
@@ -463,9 +669,13 @@ static void spi_prettyprint_status_register_atmel_at25_swp(uint8_t status)
}
}
-int spi_prettyprint_status_register_at25df(struct flashctx *flash)
+static int spi_prettyprint_status_register_at25df(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
+
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_atmel_at25_srpl(status);
@@ -476,7 +686,7 @@ int spi_prettyprint_status_register_at25df(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_at25df_sec(struct flashctx *flash)
+static int spi_prettyprint_status_register_at25df_sec(struct flashctx *flash)
{
/* FIXME: We should check the security lockdown. */
msg_cdbg("Ignoring security lockdown (if present)\n");
@@ -485,11 +695,13 @@ int spi_prettyprint_status_register_at25df_sec(struct flashctx *flash)
}
/* used for AT25F512, AT25F1024(A), AT25F2048 */
-int spi_prettyprint_status_register_at25f(struct flashctx *flash)
+static int spi_prettyprint_status_register_at25f(struct flashctx *flash)
{
uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
- status = spi_read_status_register(flash);
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_atmel_at25_wpen(status);
@@ -501,11 +713,13 @@ int spi_prettyprint_status_register_at25f(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_at25f512a(struct flashctx *flash)
+static int spi_prettyprint_status_register_at25f512a(struct flashctx *flash)
{
uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
- status = spi_read_status_register(flash);
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_atmel_at25_wpen(status);
@@ -518,9 +732,12 @@ int spi_prettyprint_status_register_at25f512a(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_at25f512b(struct flashctx *flash)
+static int spi_prettyprint_status_register_at25f512b(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_atmel_at25_srpl(status);
@@ -532,11 +749,14 @@ int spi_prettyprint_status_register_at25f512b(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_at25f4096(struct flashctx *flash)
+static int spi_prettyprint_status_register_at25f4096(struct flashctx *flash)
{
uint8_t status;
- status = spi_read_status_register(flash);
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
+
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_atmel_at25_wpen(status);
@@ -547,9 +767,12 @@ int spi_prettyprint_status_register_at25f4096(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_at25fs010(struct flashctx *flash)
+static int spi_prettyprint_status_register_at25fs010(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_atmel_at25_wpen(status);
@@ -567,9 +790,12 @@ int spi_prettyprint_status_register_at25fs010(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_at25fs040(struct flashctx *flash)
+static int spi_prettyprint_status_register_at25fs040(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_atmel_at25_wpen(status);
@@ -579,9 +805,12 @@ int spi_prettyprint_status_register_at25fs040(struct flashctx *flash)
return 0;
}
-int spi_prettyprint_status_register_at26df081a(struct flashctx *flash)
+static int spi_prettyprint_status_register_at26df081a(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_atmel_at25_srpl(status);
@@ -598,48 +827,51 @@ int spi_prettyprint_status_register_at26df081a(struct flashctx *flash)
* sectors at once by writing 0 not only the protection bits (2 and 3) but also completely unrelated bits (4 and
* 5) which normally are not touched.
* Affected are all known Atmel chips matched by AT2[56]D[FLQ]..1A? but the AT26DF041. */
-int spi_disable_blockprotect_at2x_global_unprotect(struct flashctx *flash)
+static int spi_disable_blockprotect_at2x_global_unprotect(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 1 << 4, 0x00);
}
-int spi_disable_blockprotect_at2x_global_unprotect_sec(struct flashctx *flash)
+static int spi_disable_blockprotect_at2x_global_unprotect_sec(struct flashctx *flash)
{
/* FIXME: We should check the security lockdown. */
msg_cinfo("Ignoring security lockdown (if present)\n");
return spi_disable_blockprotect_at2x_global_unprotect(flash);
}
-int spi_disable_blockprotect_at25f(struct flashctx *flash)
+static int spi_disable_blockprotect_at25f(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x0C, 1 << 7, 0, 0xFF);
}
-int spi_disable_blockprotect_at25f512a(struct flashctx *flash)
+static int spi_disable_blockprotect_at25f512a(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x04, 1 << 7, 0, 0xFF);
}
-int spi_disable_blockprotect_at25f512b(struct flashctx *flash)
+static int spi_disable_blockprotect_at25f512b(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x04, 1 << 7, 1 << 4, 0xFF);
}
-int spi_disable_blockprotect_at25fs010(struct flashctx *flash)
+static int spi_disable_blockprotect_at25fs010(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x6C, 1 << 7, 0, 0xFF);
}
-int spi_disable_blockprotect_at25fs040(struct flashctx *flash)
+static int spi_disable_blockprotect_at25fs040(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x7C, 1 << 7, 0, 0xFF);
}
/* === Eon === */
-int spi_prettyprint_status_register_en25s_wp(struct flashctx *flash)
+static int spi_prettyprint_status_register_en25s_wp(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_srwd(status);
@@ -651,14 +883,17 @@ int spi_prettyprint_status_register_en25s_wp(struct flashctx *flash)
/* === Intel/Numonyx/Micron - Spansion === */
-int spi_disable_blockprotect_n25q(struct flashctx *flash)
+static int spi_disable_blockprotect_n25q(struct flashctx *flash)
{
return spi_disable_blockprotect_generic(flash, 0x5C, 1 << 7, 0, 0xFF);
}
-int spi_prettyprint_status_register_n25q(struct flashctx *flash)
+static int spi_prettyprint_status_register_n25q(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_srwd(status);
@@ -675,15 +910,59 @@ int spi_prettyprint_status_register_n25q(struct flashctx *flash)
/* Used by Intel/Numonyx S33 and Spansion S25FL-S chips */
/* TODO: Clear P_FAIL and E_FAIL with Clear SR Fail Flags Command (30h) here? */
-int spi_disable_blockprotect_bp2_ep_srwd(struct flashctx *flash)
+static int spi_disable_blockprotect_bp2_ep_srwd(struct flashctx *flash)
{
return spi_disable_blockprotect_bp2_srwd(flash);
}
+blockprotect_func_t *lookup_blockprotect_func_ptr(const struct flashchip *const chip)
+{
+ switch (chip->unlock) {
+ case SPI_DISABLE_BLOCKPROTECT: return spi_disable_blockprotect;
+ case SPI_DISABLE_BLOCKPROTECT_BP2_EP_SRWD: return spi_disable_blockprotect_bp2_ep_srwd;
+ case SPI_DISABLE_BLOCKPROTECT_BP1_SRWD: return spi_disable_blockprotect_bp1_srwd;
+ case SPI_DISABLE_BLOCKPROTECT_BP2_SRWD: return spi_disable_blockprotect_bp2_srwd;
+ case SPI_DISABLE_BLOCKPROTECT_BP3_SRWD: return spi_disable_blockprotect_bp3_srwd;
+ case SPI_DISABLE_BLOCKPROTECT_BP4_SRWD: return spi_disable_blockprotect_bp4_srwd;
+ case SPI_DISABLE_BLOCKPROTECT_AT45DB: return spi_disable_blockprotect_at45db; /* at45db.c */
+ case SPI_DISABLE_BLOCKPROTECT_AT25F: return spi_disable_blockprotect_at25f;
+ case SPI_DISABLE_BLOCKPROTECT_AT25FS010: return spi_disable_blockprotect_at25fs010;
+ case SPI_DISABLE_BLOCKPROTECT_AT25FS040: return spi_disable_blockprotect_at25fs040;
+ case SPI_DISABLE_BLOCKPROTECT_AT25F512A: return spi_disable_blockprotect_at25f512a;
+ case SPI_DISABLE_BLOCKPROTECT_AT25F512B: return spi_disable_blockprotect_at25f512b;
+ case SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT: return spi_disable_blockprotect_at2x_global_unprotect;
+ case SPI_DISABLE_BLOCKPROTECT_AT2X_GLOBAL_UNPROTECT_SEC: return spi_disable_blockprotect_at2x_global_unprotect_sec;
+ case SPI_DISABLE_BLOCKPROTECT_SST26_GLOBAL_UNPROTECT: return spi_disable_blockprotect_sst26_global_unprotect;
+ case SPI_DISABLE_BLOCKPROTECT_N25Q: return spi_disable_blockprotect_n25q;
+ /* fallthough to lookup_jedec_blockprotect_func_ptr() */
+ case UNLOCK_REGSPACE2_BLOCK_ERASER_0:
+ case UNLOCK_REGSPACE2_BLOCK_ERASER_1:
+ case UNLOCK_REGSPACE2_UNIFORM_32K:
+ case UNLOCK_REGSPACE2_UNIFORM_64K:
+ return lookup_jedec_blockprotect_func_ptr(chip);
+ /* fallthough to lookup_82802ab_blockprotect_func_ptr() */
+ case UNLOCK_28F004S5:
+ case UNLOCK_LH28F008BJT:
+ return lookup_82802ab_blockprotect_func_ptr(chip);
+ case UNLOCK_SST_FWHUB: return unlock_sst_fwhub; /* sst_fwhub.c */
+ case UNPROTECT_28SF040: return unprotect_28sf040; /* sst28sf040.c */
+ /* default: non-total function, 0 indicates no unlock function set.
+ * We explicitly do not want a default catch-all case in the switch
+ * to ensure unhandled enum's are compiler warnings.
+ */
+ case NO_BLOCKPROTECT_FUNC: return NULL;
+ };
+
+ return NULL;
+}
+
/* Used by Intel/Numonyx S33 and Spansion S25FL-S chips */
-int spi_prettyprint_status_register_bp2_ep_srwd(struct flashctx *flash)
+static int spi_prettyprint_status_register_bp2_ep_srwd(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_hex(status);
spi_prettyprint_status_register_srwd(status);
@@ -709,14 +988,17 @@ static void spi_prettyprint_status_register_sst25_common(uint8_t status)
spi_prettyprint_status_register_welwip(status);
}
-int spi_prettyprint_status_register_sst25(struct flashctx *flash)
+static int spi_prettyprint_status_register_sst25(struct flashctx *flash)
{
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_sst25_common(status);
return 0;
}
-int spi_prettyprint_status_register_sst25vf016(struct flashctx *flash)
+static int spi_prettyprint_status_register_sst25vf016(struct flashctx *flash)
{
static const char *const bpt[] = {
"none",
@@ -727,13 +1009,16 @@ int spi_prettyprint_status_register_sst25vf016(struct flashctx *flash)
"100000H-1FFFFFH",
"all", "all"
};
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_sst25_common(status);
msg_cdbg("Resulting block protection : %s\n", bpt[(status & 0x1c) >> 2]);
return 0;
}
-int spi_prettyprint_status_register_sst25vf040b(struct flashctx *flash)
+static int spi_prettyprint_status_register_sst25vf040b(struct flashctx *flash)
{
static const char *const bpt[] = {
"none",
@@ -742,8 +1027,66 @@ int spi_prettyprint_status_register_sst25vf040b(struct flashctx *flash)
"0x40000-0x7ffff",
"all blocks", "all blocks", "all blocks", "all blocks"
};
- uint8_t status = spi_read_status_register(flash);
+ uint8_t status;
+ int ret = spi_read_register(flash, STATUS1, &status);
+ if (ret)
+ return ret;
spi_prettyprint_status_register_sst25_common(status);
msg_cdbg("Resulting block protection : %s\n", bpt[(status & 0x1c) >> 2]);
return 0;
}
+
+printlockfunc_t *lookup_printlock_func_ptr(struct flashctx *flash)
+{
+ switch (flash->chip->printlock) {
+ case PRINTLOCK_AT49F: return &printlock_at49f;
+ case PRINTLOCK_REGSPACE2_BLOCK_ERASER_0: return &printlock_regspace2_block_eraser_0;
+ case PRINTLOCK_REGSPACE2_BLOCK_ERASER_1: return &printlock_regspace2_block_eraser_1;
+ case PRINTLOCK_SST_FWHUB: return &printlock_sst_fwhub;
+ case PRINTLOCK_W39F010: return &printlock_w39f010;
+ case PRINTLOCK_W39L010: return &printlock_w39l010;
+ case PRINTLOCK_W39L020: return &printlock_w39l020;
+ case PRINTLOCK_W39L040: return &printlock_w39l040;
+ case PRINTLOCK_W39V040A: return &printlock_w39v040a;
+ case PRINTLOCK_W39V040B: return &printlock_w39v040b;
+ case PRINTLOCK_W39V040C: return &printlock_w39v040c;
+ case PRINTLOCK_W39V040FA: return &printlock_w39v040fa;
+ case PRINTLOCK_W39V040FB: return &printlock_w39v040fb;
+ case PRINTLOCK_W39V040FC: return &printlock_w39v040fc;
+ case PRINTLOCK_W39V080A: return &printlock_w39v080a;
+ case PRINTLOCK_W39V080FA: return &printlock_w39v080fa;
+ case PRINTLOCK_W39V080FA_DUAL: return &printlock_w39v080fa_dual;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AMIC_A25L032: return &spi_prettyprint_status_register_amic_a25l032;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF: return &spi_prettyprint_status_register_at25df;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT25DF_SEC: return &spi_prettyprint_status_register_at25df_sec;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT25F: return &spi_prettyprint_status_register_at25f;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT25F4096: return &spi_prettyprint_status_register_at25f4096;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT25F512A: return &spi_prettyprint_status_register_at25f512a;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT25F512B: return &spi_prettyprint_status_register_at25f512b;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT25FS010: return &spi_prettyprint_status_register_at25fs010;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT25FS040: return &spi_prettyprint_status_register_at25fs040;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT26DF081A: return &spi_prettyprint_status_register_at26df081a;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_AT45DB: return &spi_prettyprint_status_register_at45db;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_BP1_SRWD: return &spi_prettyprint_status_register_bp1_srwd;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_BP2_BPL: return &spi_prettyprint_status_register_bp2_bpl;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_BP2_EP_SRWD: return &spi_prettyprint_status_register_bp2_ep_srwd;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_BP2_SRWD: return &spi_prettyprint_status_register_bp2_srwd;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_BP2_TB_BPL: return &spi_prettyprint_status_register_bp2_tb_bpl;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_BP3_SRWD: return &spi_prettyprint_status_register_bp3_srwd;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_BP4_SRWD: return &spi_prettyprint_status_register_bp4_srwd;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_DEFAULT_WELWIP: return &spi_prettyprint_status_register_default_welwip;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_EN25S_WP: return &spi_prettyprint_status_register_en25s_wp;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_N25Q: return &spi_prettyprint_status_register_n25q;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_PLAIN: return &spi_prettyprint_status_register_plain;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_SST25: return &spi_prettyprint_status_register_sst25;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_SST25VF016: return &spi_prettyprint_status_register_sst25vf016;
+ case SPI_PRETTYPRINT_STATUS_REGISTER_SST25VF040B: return &spi_prettyprint_status_register_sst25vf040b;
+ /* default: non-total function, 0 indicates no unlock function set.
+ * We explicitly do not want a default catch-all case in the switch
+ * to ensure unhandled enum's are compiler warnings.
+ */
+ case NO_PRINTLOCK_FUNC: return NULL;
+ };
+
+ return NULL;
+}
diff --git a/spi95.c b/spi95.c
index 976f99a11..d1f0ba130 100644
--- a/spi95.c
+++ b/spi95.c
@@ -46,7 +46,7 @@ int probe_spi_st95(struct flashctx *flash)
id1 = readarr[0]; // manufacture id
id2 = (readarr[1] << 8) | readarr[2]; // SPI family code + model id
- msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
+ msg_cdbg("%s: id1 0x%02"PRIx32", id2 0x%02"PRIx32"\n", __func__, id1, id2);
if (id1 == flash->chip->manufacture_id && id2 == flash->chip->model_id)
return 1;
diff --git a/sst28sf040.c b/sst28sf040.c
index 3da25f127..9080684b5 100644
--- a/sst28sf040.c
+++ b/sst28sf040.c
@@ -92,6 +92,7 @@ int write_28sf040(struct flashctx *flash, const uint8_t *src, unsigned int start
/* wait for Toggle bit ready */
toggle_ready_jedec(flash, bios);
+ update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, len);
}
return 0;
@@ -104,7 +105,7 @@ static int erase_28sf040(struct flashctx *flash)
chip_writeb(flash, CHIP_ERASE, bios);
chip_writeb(flash, CHIP_ERASE, bios);
- programmer_delay(10);
+ programmer_delay(flash, 10);
toggle_ready_jedec(flash, bios);
/* FIXME: Check the status register for errors. */
diff --git a/stlinkv3_spi.c b/stlinkv3_spi.c
index 7e8336e15..f9046df01 100644
--- a/stlinkv3_spi.c
+++ b/stlinkv3_spi.c
@@ -114,16 +114,22 @@ enum spi_nss_level {
#define USB_TIMEOUT_IN_MS 5000
-const struct dev_entry devs_stlinkv3_spi[] = {
- {0x0483, 0x374F, OK, "STMicroelectronics", "STLINK-V3"},
+static const struct dev_entry devs_stlinkv3_spi[] = {
+ {0x0483, 0x374E, NT, "STMicroelectronics", "STLINK-V3E"},
+ {0x0483, 0x374F, OK, "STMicroelectronics", "STLINK-V3S"},
+ {0x0483, 0x3753, OK, "STMicroelectronics", "STLINK-V3 dual VCP"},
+ {0x0483, 0x3754, NT, "STMicroelectronics", "STLINK-V3 no MSD"},
{0}
};
-static struct libusb_context *usb_ctx;
-static libusb_device_handle *stlinkv3_handle;
+struct stlinkv3_spi_data {
+ struct libusb_context *usb_ctx;
+ libusb_device_handle *handle;
+};
static int stlinkv3_command(uint8_t *command, size_t command_length,
- uint8_t *answer, size_t answer_length, const char *command_name)
+ uint8_t *answer, size_t answer_length, const char *command_name,
+ libusb_device_handle *stlinkv3_handle)
{
int actual_length = 0;
int rc = libusb_bulk_transfer(stlinkv3_handle, STLINK_EP_OUT,
@@ -151,21 +157,22 @@ static int stlinkv3_command(uint8_t *command, size_t command_length,
/**
* @param[out] bridge_input_clk Current input frequency in kHz of the given com.
*/
-static int stlinkv3_get_clk(uint32_t *bridge_input_clk)
+static int stlinkv3_get_clk(uint32_t *bridge_input_clk, libusb_device_handle *stlinkv3_handle)
{
- uint8_t command[16];
+ uint8_t command[16] = { 0 };
uint8_t answer[12];
if (bridge_input_clk == NULL)
return -1;
- memset(command, 0, sizeof(command));
-
command[0] = STLINK_BRIDGE_COMMAND;
command[1] = STLINK_BRIDGE_GET_CLOCK;
command[2] = STLINK_SPI_COM;
- if (stlinkv3_command(command, sizeof(command), answer, sizeof(answer), "STLINK_BRIDGE_GET_CLOCK") != 0)
+ if (stlinkv3_command(command, sizeof(command),
+ answer, sizeof(answer),
+ "STLINK_BRIDGE_GET_CLOCK",
+ stlinkv3_handle) != 0)
return -1;
*bridge_input_clk = (uint32_t)answer[4]
@@ -178,13 +185,14 @@ static int stlinkv3_get_clk(uint32_t *bridge_input_clk)
static int stlinkv3_spi_calc_prescaler(uint16_t reqested_freq_in_kHz,
enum spi_prescaler *prescaler,
- uint16_t *calculated_freq_in_kHz)
+ uint16_t *calculated_freq_in_kHz,
+ libusb_device_handle *stlinkv3_handle)
{
uint32_t bridge_clk_in_kHz;
uint32_t calculated_prescaler = 1;
uint16_t prescaler_value;
- if (stlinkv3_get_clk(&bridge_clk_in_kHz))
+ if (stlinkv3_get_clk(&bridge_clk_in_kHz, stlinkv3_handle))
return -1;
calculated_prescaler = bridge_clk_in_kHz/reqested_freq_in_kHz;
@@ -224,17 +232,18 @@ static int stlinkv3_spi_calc_prescaler(uint16_t reqested_freq_in_kHz,
return 0;
}
-static int stlinkv3_check_version(enum fw_version_check_result *result)
+static int stlinkv3_check_version(enum fw_version_check_result *result, libusb_device_handle *stlinkv3_handle)
{
uint8_t answer[12];
- uint8_t command[16];
-
- memset(command, 0, sizeof(command));
+ uint8_t command[16] = { 0 };
command[0] = ST_GETVERSION_EXT;
command[1] = 0x80;
- if (stlinkv3_command(command, sizeof(command), answer, sizeof(answer), "ST_GETVERSION_EXT") != 0)
+ if (stlinkv3_command(command, sizeof(command),
+ answer, sizeof(answer),
+ "ST_GETVERSION_EXT",
+ stlinkv3_handle) != 0)
return -1;
msg_pinfo("Connected to STLink V3 with bridge FW version: %d\n", answer[4]);
@@ -244,15 +253,15 @@ static int stlinkv3_check_version(enum fw_version_check_result *result)
return 0;
}
-static int stlinkv3_spi_open(uint16_t reqested_freq_in_kHz)
+static int stlinkv3_spi_open(uint16_t reqested_freq_in_kHz, libusb_device_handle *stlinkv3_handle)
{
- uint8_t command[16];
+ uint8_t command[16] = { 0 };
uint8_t answer[2];
uint16_t SCK_freq_in_kHz;
enum spi_prescaler prescaler;
enum fw_version_check_result fw_check_result;
- if (stlinkv3_check_version(&fw_check_result)) {
+ if (stlinkv3_check_version(&fw_check_result, stlinkv3_handle)) {
msg_perr("Failed to query FW version\n");
return -1;
}
@@ -267,14 +276,13 @@ static int stlinkv3_spi_open(uint16_t reqested_freq_in_kHz)
if (stlinkv3_spi_calc_prescaler(reqested_freq_in_kHz,
&prescaler,
- &SCK_freq_in_kHz)) {
+ &SCK_freq_in_kHz,
+ stlinkv3_handle)) {
msg_perr("Failed to calculate SPI clock prescaler\n");
return -1;
}
msg_pinfo("SCK frequency set to %d kHz\n", SCK_freq_in_kHz);
- memset(command, 0, sizeof(command));
-
command[0] = STLINK_BRIDGE_COMMAND;
command[1] = STLINK_BRIDGE_INIT_SPI;
command[2] = SPI_DIRECTION_2LINES_FULLDUPLEX;
@@ -286,40 +294,43 @@ static int stlinkv3_spi_open(uint16_t reqested_freq_in_kHz)
command[5] = SPI_NSS_SOFT;
command[6] = (uint8_t)prescaler;
- return stlinkv3_command(command, sizeof(command), answer, sizeof(answer), "STLINK_BRIDGE_INIT_SPI");
+ return stlinkv3_command(command, sizeof(command),
+ answer, sizeof(answer),
+ "STLINK_BRIDGE_INIT_SPI",
+ stlinkv3_handle);
}
-static int stlinkv3_get_last_readwrite_status(uint32_t *status)
+static int stlinkv3_get_last_readwrite_status(uint32_t *status, libusb_device_handle *stlinkv3_handle)
{
- uint8_t command[16];
+ uint8_t command[16] = { 0 };
uint16_t answer[4];
- memset(command, 0, sizeof(command));
-
command[0] = STLINK_BRIDGE_COMMAND;
command[1] = STLINK_BRIDGE_GET_RWCMD_STATUS;
if (stlinkv3_command(command, sizeof(command),
(uint8_t *)answer, sizeof(answer),
- "STLINK_BRIDGE_GET_RWCMD_STATUS") != 0)
+ "STLINK_BRIDGE_GET_RWCMD_STATUS",
+ stlinkv3_handle) != 0)
return -1;
*status = (uint32_t)answer[2] | (uint32_t)answer[3]<<16;
return 0;
}
-static int stlinkv3_spi_set_SPI_NSS(enum spi_nss_level nss_level)
+static int stlinkv3_spi_set_SPI_NSS(enum spi_nss_level nss_level, libusb_device_handle *stlinkv3_handle)
{
- uint8_t command[16];
+ uint8_t command[16] = { 0 };
uint8_t answer[2];
- memset(command, 0, sizeof(command));
-
command[0] = STLINK_BRIDGE_COMMAND;
command[1] = STLINK_BRIDGE_CS_SPI;
command[2] = (uint8_t) (nss_level);
- if (stlinkv3_command(command, sizeof(command), answer, sizeof(answer), "STLINK_BRIDGE_CS_SPI") != 0)
+ if (stlinkv3_command(command, sizeof(command),
+ answer, sizeof(answer),
+ "STLINK_BRIDGE_CS_SPI",
+ stlinkv3_handle) != 0)
return -1;
return 0;
}
@@ -330,19 +341,19 @@ static int stlinkv3_spi_transmit(const struct flashctx *flash,
const unsigned char *write_arr,
unsigned char *read_arr)
{
- uint8_t command[16];
+ struct stlinkv3_spi_data *stlinkv3_data = flash->mst->spi.data;
+ libusb_device_handle *stlinkv3_handle = stlinkv3_data->handle;
+ uint8_t command[16] = { 0 };
int rc = 0;
int actual_length = 0;
uint32_t rw_status = 0;
unsigned int i;
- if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_LOW)) {
+ if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_LOW, stlinkv3_handle)) {
msg_perr("Failed to set the NSS pin to low\n");
return -1;
}
- memset(command, 0, sizeof(command));
-
command[0] = STLINK_BRIDGE_COMMAND;
command[1] = STLINK_BRIDGE_WRITE_SPI;
command[2] = (uint8_t)write_cnt;
@@ -374,7 +385,7 @@ static int stlinkv3_spi_transmit(const struct flashctx *flash,
}
}
- if (stlinkv3_get_last_readwrite_status(&rw_status))
+ if (stlinkv3_get_last_readwrite_status(&rw_status, stlinkv3_handle))
return -1;
if (rw_status != 0) {
@@ -403,13 +414,13 @@ static int stlinkv3_spi_transmit(const struct flashctx *flash,
&actual_length,
USB_TIMEOUT_IN_MS);
if (rc != LIBUSB_TRANSFER_COMPLETED || (unsigned int)actual_length != read_cnt) {
- msg_perr("Failed to retrive the STLINK_BRIDGE_READ_SPI answer: '%s'\n",
+ msg_perr("Failed to retrieve the STLINK_BRIDGE_READ_SPI answer: '%s'\n",
libusb_error_name(rc));
goto transmit_err;
}
}
- if (stlinkv3_get_last_readwrite_status(&rw_status))
+ if (stlinkv3_get_last_readwrite_status(&rw_status, stlinkv3_handle))
goto transmit_err;
if (rw_status != 0) {
@@ -417,104 +428,130 @@ static int stlinkv3_spi_transmit(const struct flashctx *flash,
goto transmit_err;
}
- if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_HIGH)) {
+ if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_HIGH, stlinkv3_handle)) {
msg_perr("Failed to set the NSS pin to high\n");
return -1;
}
return 0;
transmit_err:
- if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_HIGH))
+ if (stlinkv3_spi_set_SPI_NSS(SPI_NSS_HIGH, stlinkv3_handle))
msg_perr("Failed to set the NSS pin to high\n");
return -1;
}
static int stlinkv3_spi_shutdown(void *data)
{
- uint8_t command[16];
+ struct stlinkv3_spi_data *stlinkv3_data = data;
+ uint8_t command[16] = { 0 };
uint8_t answer[2];
- memset(command, 0, sizeof(command));
-
command[0] = STLINK_BRIDGE_COMMAND;
command[1] = STLINK_BRIDGE_CLOSE;
command[2] = STLINK_SPI_COM;
- stlinkv3_command(command, sizeof(command), answer, sizeof(answer), "STLINK_BRIDGE_CLOSE");
+ stlinkv3_command(command, sizeof(command),
+ answer, sizeof(answer),
+ "STLINK_BRIDGE_CLOSE",
+ stlinkv3_data->handle);
- libusb_close(stlinkv3_handle);
- libusb_exit(usb_ctx);
+ libusb_close(stlinkv3_data->handle);
+ libusb_exit(stlinkv3_data->usb_ctx);
+ free(data);
return 0;
}
static const struct spi_master spi_programmer_stlinkv3 = {
- .max_data_read = UINT16_MAX,
- .max_data_write = UINT16_MAX,
- .command = stlinkv3_spi_transmit,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .max_data_read = UINT16_MAX,
+ .max_data_write = UINT16_MAX,
+ .command = stlinkv3_spi_transmit,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = stlinkv3_spi_shutdown,
};
-int stlinkv3_spi_init(void)
+static int stlinkv3_spi_init(const struct programmer_cfg *cfg)
{
uint16_t sck_freq_kHz = 1000; // selecting 1 MHz SCK is a good bet
- char *speed_str = NULL;
- char *serialno = NULL;
+ char *param_str;
char *endptr = NULL;
-
- libusb_init(&usb_ctx);
- if (!usb_ctx) {
+ int ret = 1;
+ int devIndex = 0;
+ struct libusb_context *usb_ctx;
+ /* Initialize stlinkv3_handle to NULL for suppressing scan-build false positive core.uninitialized.Branch */
+ libusb_device_handle *stlinkv3_handle = NULL;
+ struct stlinkv3_spi_data *stlinkv3_data;
+
+ if (libusb_init(&usb_ctx)) {
msg_perr("Could not initialize libusb!\n");
return 1;
}
- serialno = extract_programmer_param("serial");
- if (serialno)
- msg_pdbg("Opening STLINK-V3 with serial: %s\n", serialno);
- stlinkv3_handle = usb_dev_get_by_vid_pid_serial(usb_ctx,
- devs_stlinkv3_spi[0].vendor_id,
- devs_stlinkv3_spi[0].device_id,
- serialno);
+ param_str = extract_programmer_param_str(cfg, "serial");
+ if (param_str)
+ msg_pdbg("Opening STLINK-V3 with serial: %s\n", param_str);
+
+
+ while (devs_stlinkv3_spi[devIndex].vendor_id != 0) {
+ stlinkv3_handle = usb_dev_get_by_vid_pid_serial(usb_ctx,
+ devs_stlinkv3_spi[devIndex].vendor_id,
+ devs_stlinkv3_spi[devIndex].device_id,
+ param_str);
+ if (stlinkv3_handle)
+ break;
+ devIndex++;
+ }
if (!stlinkv3_handle) {
- if (serialno)
- msg_perr("No STLINK-V3 seems to be connected with serial %s\n", serialno);
+ if (param_str)
+ msg_perr("No STLINK-V3 seems to be connected with serial %s\n", param_str);
else
msg_perr("Could not find any connected STLINK-V3\n");
- free(serialno);
- goto err_exit;
+ free(param_str);
+ goto init_err_exit;
}
- free(serialno);
+ free(param_str);
- speed_str = extract_programmer_param("spispeed");
- if (speed_str) {
- sck_freq_kHz = strtoul(speed_str, &endptr, 0);
+ param_str = extract_programmer_param_str(cfg, "spispeed");
+ if (param_str) {
+ sck_freq_kHz = strtoul(param_str, &endptr, 0);
if (*endptr || sck_freq_kHz == 0) {
msg_perr("The spispeed parameter passed with invalid format: %s\n",
- speed_str);
+ param_str);
msg_perr("Please pass the parameter "
"with a simple non-zero number in kHz\n");
- free(speed_str);
- return -1;
+ free(param_str);
+ ret = -1;
+ goto init_err_exit;
}
- free(speed_str);
+ free(param_str);
}
- if (stlinkv3_spi_open(sck_freq_kHz))
- goto err_exit;
+ if (stlinkv3_spi_open(sck_freq_kHz, stlinkv3_handle))
+ goto init_err_exit;
- if (register_shutdown(stlinkv3_spi_shutdown, NULL))
- goto err_exit;
+ stlinkv3_data = calloc(1, sizeof(*stlinkv3_data));
+ if (!stlinkv3_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ goto init_err_exit;
+ }
- if (register_spi_master(&spi_programmer_stlinkv3))
- goto err_exit;
+ stlinkv3_data->usb_ctx = usb_ctx;
+ stlinkv3_data->handle = stlinkv3_handle;
- return 0;
+ return register_spi_master(&spi_programmer_stlinkv3, stlinkv3_data);
-err_exit:
+init_err_exit:
+ if (stlinkv3_handle)
+ libusb_close(stlinkv3_handle);
libusb_exit(usb_ctx);
- return 1;
+ return ret;
}
+
+const struct programmer_entry programmer_stlinkv3_spi = {
+ .name = "stlinkv3_spi",
+ .type = USB,
+ .devs.dev = devs_stlinkv3_spi,
+ .init = stlinkv3_spi_init,
+};
diff --git a/stm50.c b/stm50.c
index 37e560c05..d495e0954 100644
--- a/stm50.c
+++ b/stm50.c
@@ -34,7 +34,7 @@ static int stm50_erase_sector(struct flashctx *flash, unsigned int addr)
// now start it
chip_writeb(flash, 0x32, bios);
chip_writeb(flash, 0xd0, bios);
- programmer_delay(10);
+ programmer_delay(flash, 10);
uint8_t status = wait_82802ab(flash);
print_status_82802ab(status);
diff --git a/superio.c b/superio.c
new file mode 100644
index 000000000..3121578d9
--- /dev/null
+++ b/superio.c
@@ -0,0 +1,42 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2009 Carl-Daniel Hailfinger
+ *
+ * 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 "programmer.h"
+
+int superio_count = 0;
+#define SUPERIO_MAX_COUNT 3
+
+struct superio superios[SUPERIO_MAX_COUNT];
+
+int register_superio(struct superio s)
+{
+ if (superio_count == SUPERIO_MAX_COUNT)
+ return 1;
+ superios[superio_count++] = s;
+ return 0;
+}
+
+void probe_superio(void)
+{
+ probe_superio_winbond();
+ /* ITE probe causes SMSC LPC47N217 to power off the serial UART.
+ * Always probe for SMSC first, and if a SMSC Super I/O is detected
+ * at a given I/O port, do _not_ probe that port with the ITE probe.
+ * This means SMSC probing must be done before ITE probing.
+ */
+ //probe_superio_smsc();
+ probe_superio_ite();
+}
diff --git a/test_build.sh b/test_build.sh
index 0e43cd353..9b490dc3d 100755
--- a/test_build.sh
+++ b/test_build.sh
@@ -1,8 +1,78 @@
-#!/bin/sh
+#!/usr/bin/env sh
set -e
-make CONFIG_EVERYTHING=yes WARNERROR=yes
+# This script will only work on Linux with all dependencies installed.
-meson out
-(cd out && ninja)
-(cd out && ninja test)
+is_scan_build_env=0
+
+make_programmer_opts="INTERNAL INTERNAL_X86 SERPROG RAYER_SPI RAIDEN_DEBUG_SPI PONY_SPI NIC3COM \
+ GFXNVIDIA SATASII ATAHPT ATAVIA ATAPROMISE FT2232_SPI USBBLASTER_SPI MSTARDDC_SPI \
+ PICKIT2_SPI STLINKV3_SPI PARADE_LSPCON MEDIATEK_I2C_SPI REALTEK_MST_I2C_SPI DUMMY \
+ DRKAISER NICREALTEK NICNATSEMI NICINTEL NICINTEL_SPI NICINTEL_EEPROM OGP_SPI \
+ BUSPIRATE_SPI DEDIPROG DEVELOPERBOX_SPI SATAMV LINUX_MTD LINUX_SPI IT8212 \
+ CH341A_SPI CH347_SPI DIGILENT_SPI DIRTYJTAG_SPI JLINK_SPI ASM106X"
+
+meson_programmer_opts="all auto group_ftdi group_i2c group_jlink group_pci group_serial group_usb \
+ atahpt atapromise atavia buspirate_spi ch341a_spi ch347_spi dediprog \
+ developerbox_spi digilent_spi dirtyjtag_spi drkaiser dummy ft2232_spi \
+ gfxnvidia internal it8212 jlink_spi linux_mtd linux_spi parade_lspcon \
+ mediatek_i2c_spi mstarddc_spi nic3com nicintel nicintel_eeprom nicintel_spi \
+ nicnatsemi nicrealtek ogp_spi pickit2_spi pony_spi raiden_debug_spi rayer_spi \
+ realtek_mst_i2c_spi satamv satasii serprog stlinkv3_spi usbblaster_spi asm106x"
+
+
+if [ "$(basename "${CC}")" = "ccc-analyzer" ] || [ -n "${COVERITY_OUTPUT}" ]; then
+ is_scan_build_env=1
+fi
+
+
+run_linter() {
+ ./util/lint/lint-extended-020-signed-off-by
+}
+
+
+build_make () {
+ make clean
+ make -j $(nproc) CONFIG_EVERYTHING=yes
+
+ # In case of clang analyzer we don't want to run it on
+ # each programmer individually. Thus, just return here.
+ if [ ${is_scan_build_env} -eq 1 ]; then
+ return
+ fi
+
+ for option in ${make_programmer_opts}; do
+ echo "Building ${option}"
+ make clean
+ make -j $(nproc) CONFIG_NOTHING=yes CONFIG_${option}=yes
+ done
+}
+
+
+build_meson () {
+ build_dir=out
+ meson_opts="-Dtests=enabled"
+ ninja_opts="-j $(nproc)"
+
+ rm -rf ${build_dir}
+
+ for programmer in ${meson_programmer_opts}; do
+ programmer_dir="${build_dir}/${programmer}"
+
+ # In case of clang analyzer we don't want to run it on
+ # each programmer individually. Thus, just return here.
+ if [ ${is_scan_build_env} -eq 1 ] && [ "${programmer}" != "all" ]; then
+ return
+ fi
+
+ meson setup ${programmer_dir} ${meson_opts} -Dprogrammer=${programmer}
+ ninja ${ninja_opts} -C ${programmer_dir}
+ ninja ${ninja_opts} -C ${programmer_dir} test
+ done
+}
+
+
+run_linter
+
+build_make
+build_meson
diff --git a/tests/ch341a_spi.c b/tests/ch341a_spi.c
new file mode 100644
index 000000000..1cb265249
--- /dev/null
+++ b/tests/ch341a_spi.c
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2022 Alexander Goncharov <chat@joursoir.net>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_CH341A_SPI == 1
+
+/* Same macro as in ch341a_spi.c programmer. */
+#define WRITE_EP 0x02
+#define READ_EP 0x82
+
+struct ch341a_spi_io_state {
+ struct libusb_transfer *transfer_out;
+ /*
+ * Since the test transfers a data that fits in one CH341 packet, we
+ * don't need an array of these transfers (as is done in the driver code).
+ */
+ struct libusb_transfer *transfer_in;
+};
+
+static struct libusb_transfer *ch341a_libusb_alloc_transfer(void *state, int iso_packets)
+{
+ return calloc(1, sizeof(struct libusb_transfer));
+}
+
+/*
+ * The libusb code stores submitted transfers in their own context. But this
+ * function doesn't require a context pointer because libusb stores context
+ * pointers in libusb_transfer instances. Since our ch341 driver is using
+ * the default context, we store the transfer in our own.
+ */
+static int ch341a_libusb_submit_transfer(void *state, struct libusb_transfer *transfer)
+{
+ struct ch341a_spi_io_state *io_state = state;
+
+ assert_true(transfer->endpoint == WRITE_EP || transfer->endpoint == READ_EP);
+
+ if (transfer->endpoint == WRITE_EP) {
+ assert_null(io_state->transfer_out);
+ io_state->transfer_out = transfer;
+ } else if (transfer->endpoint == READ_EP) {
+ assert_null(io_state->transfer_in);
+ io_state->transfer_in = transfer;
+ }
+
+ return 0;
+}
+
+static void ch341a_libusb_free_transfer(void *state, struct libusb_transfer *transfer)
+{
+ free(transfer);
+}
+
+/*
+ * Handle submitted transfers by pretending that a transfer is completed and
+ * invoking its callback (that is the flashrom code).
+ */
+static int ch341a_libusb_handle_events_timeout(void *state, libusb_context *ctx, struct timeval *tv)
+{
+ struct ch341a_spi_io_state *io_state = state;
+
+ if (io_state->transfer_out) {
+ io_state->transfer_out->status = LIBUSB_TRANSFER_COMPLETED;
+ io_state->transfer_out->actual_length = io_state->transfer_out->length;
+ io_state->transfer_out->callback(io_state->transfer_out);
+ io_state->transfer_out = NULL;
+ }
+
+ if (io_state->transfer_in) {
+ io_state->transfer_in->buffer[1] = reverse_byte(0xEF); /* WINBOND_NEX_ID */
+ io_state->transfer_in->buffer[2] = reverse_byte(0x40); /* WINBOND_NEX_W25Q128_V left byte */
+ io_state->transfer_in->buffer[3] = reverse_byte(0x18); /* WINBOND_NEX_W25Q128_V right byte */
+
+ io_state->transfer_in->status = LIBUSB_TRANSFER_COMPLETED;
+ io_state->transfer_in->actual_length = io_state->transfer_in->length;
+ io_state->transfer_in->callback(io_state->transfer_in);
+ io_state->transfer_in = NULL;
+ }
+
+ return 0;
+}
+
+void ch341a_spi_basic_lifecycle_test_success(void **state)
+{
+ struct ch341a_spi_io_state ch341a_spi_io_state = { 0 };
+ struct io_mock_fallback_open_state ch341a_spi_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock ch341a_spi_io = {
+ .state = &ch341a_spi_io_state,
+ .libusb_alloc_transfer = &ch341a_libusb_alloc_transfer,
+ .libusb_submit_transfer = &ch341a_libusb_submit_transfer,
+ .libusb_free_transfer = &ch341a_libusb_free_transfer,
+ .libusb_handle_events_timeout = &ch341a_libusb_handle_events_timeout,
+ .fallback_open_state = &ch341a_spi_fallback_open_state,
+ };
+
+ run_basic_lifecycle(state, &ch341a_spi_io, &programmer_ch341a_spi, "");
+}
+
+void ch341a_spi_probe_lifecycle_test_success(void **state)
+{
+ struct ch341a_spi_io_state ch341a_spi_io_state = { 0 };
+ struct io_mock_fallback_open_state ch341a_spi_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock ch341a_spi_io = {
+ .state = &ch341a_spi_io_state,
+ .libusb_alloc_transfer = &ch341a_libusb_alloc_transfer,
+ .libusb_submit_transfer = &ch341a_libusb_submit_transfer,
+ .libusb_free_transfer = &ch341a_libusb_free_transfer,
+ .libusb_handle_events_timeout = &ch341a_libusb_handle_events_timeout,
+ .fallback_open_state = &ch341a_spi_fallback_open_state,
+ };
+
+ run_probe_lifecycle(state, &ch341a_spi_io, &programmer_ch341a_spi, "", "W25Q128.V");
+}
+
+#else
+ SKIP_TEST(ch341a_spi_basic_lifecycle_test_success)
+ SKIP_TEST(ch341a_spi_probe_lifecycle_test_success)
+#endif /* CONFIG_CH341A_SPI */
diff --git a/tests/chip.c b/tests/chip.c
new file mode 100644
index 000000000..96be7b108
--- /dev/null
+++ b/tests/chip.c
@@ -0,0 +1,580 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ *
+ * This file contains tests for operations on flash chip.
+ *
+ * Two flash chip test variants are used:
+ *
+ * 1) Mock chip state backed by `g_chip_state`.
+ * Example of test: erase_chip_test_success.
+ *
+ * 2) Mock chip operations backed by `dummyflasher` emulation.
+ * Dummyflasher controls chip state and emulates read/write/erase.
+ * `g_chip_state` is NOT used for this type of tests.
+ * Example of test: erase_chip_with_dummyflasher_test_success.
+ */
+
+#include <include/test.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "tests.h"
+#include "chipdrivers.h"
+#include "flash.h"
+#include "io_mock.h"
+#include "libflashrom.h"
+#include "programmer.h"
+
+#define MOCK_CHIP_SIZE (8*MiB)
+#define MOCK_CHIP_CONTENT 0xCC /* 0x00 is a zeroed heap and 0xFF is an erased chip. */
+
+static struct {
+ uint8_t buf[MOCK_CHIP_SIZE]; /* buffer of total size of chip, to emulate a chip */
+} g_chip_state = {
+ .buf = { 0 },
+};
+
+static int read_chip(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
+{
+ printf("Read chip called with start=0x%x, len=0x%x\n", start, len);
+
+ assert_in_range(start + len, 0, MOCK_CHIP_SIZE);
+
+ memcpy(buf, &g_chip_state.buf[start], len);
+ return 0;
+}
+
+static int write_chip(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
+{
+ printf("Write chip called with start=0x%x, len=0x%x\n", start, len);
+
+ assert_in_range(start + len, 0, MOCK_CHIP_SIZE);
+
+ memcpy(&g_chip_state.buf[start], buf, len);
+ return 0;
+}
+
+static int block_erase_chip(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen)
+{
+ printf("Block erase called with blockaddr=0x%x, blocklen=0x%x\n", blockaddr, blocklen);
+
+ assert_in_range(blockaddr + blocklen, 0, MOCK_CHIP_SIZE);
+
+ memset(&g_chip_state.buf[blockaddr], 0xff, blocklen);
+ return 0;
+}
+
+static void setup_chip(struct flashrom_flashctx *flashctx, struct flashrom_layout **layout,
+ struct flashchip *chip, const char *programmer_param, const struct io_mock *io)
+{
+ io_mock_register(io);
+
+ flashctx->chip = chip;
+
+ memset(g_chip_state.buf, MOCK_CHIP_CONTENT, sizeof(g_chip_state.buf));
+
+ printf("Creating layout with one included region... ");
+ assert_int_equal(0, flashrom_layout_new(layout));
+ /* One region which covers total size of chip. */
+ assert_int_equal(0, flashrom_layout_add_region(*layout, 0, chip->total_size * KiB - 1, "region"));
+ assert_int_equal(0, flashrom_layout_include_region(*layout, "region"));
+
+ flashrom_layout_set(flashctx, *layout);
+ printf("done\n");
+
+ /*
+ * We need some programmer (any), and dummy is a very good one,
+ * because it doesn't need any mocking. So no extra complexity
+ * from a programmer side, and test can focus on working with the chip.
+ */
+ printf("Dummyflasher initialising with param=\"%s\"... ", programmer_param);
+ assert_int_equal(0, programmer_init(&programmer_dummy, programmer_param));
+ /* Assignment below normally happens while probing, but this test is not probing. */
+ flashctx->mst = &registered_masters[0];
+ printf("done\n");
+}
+
+static void teardown(struct flashrom_layout **layout)
+{
+ printf("Dummyflasher shutdown... ");
+ assert_int_equal(0, programmer_shutdown());
+ printf("done\n");
+
+ printf("Releasing layout... ");
+ flashrom_layout_release(*layout);
+ printf("done\n");
+
+ io_mock_register(NULL);
+}
+
+extern write_func_t *g_test_write_injector;
+extern read_func_t *g_test_read_injector;
+extern erasefunc_t *g_test_erase_injector;
+
+static const struct flashchip chip_8MiB = {
+ .vendor = "aklm",
+ .total_size = MOCK_CHIP_SIZE / KiB,
+ .tested = TEST_OK_PREW,
+ .read = TEST_READ_INJECTOR,
+ .write = TEST_WRITE_INJECTOR,
+ .block_erasers =
+ {{
+ /* All blocks within total size of the chip. */
+ .eraseblocks = { {2 * MiB, 4} },
+ .block_erase = TEST_ERASE_INJECTOR,
+ }},
+};
+
+/* Setup the struct for W25Q128.V, all values come from flashchips.c */
+static const struct flashchip chip_W25Q128_V = {
+ .vendor = "aklm&dummyflasher",
+ .total_size = 16 * 1024,
+ .tested = TEST_OK_PREW,
+ .read = SPI_CHIP_READ,
+ .write = SPI_CHIP_WRITE256,
+ .page_size = 256,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 4096} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {16 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {16 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+};
+
+void erase_chip_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ static struct io_mock_fallback_open_state data = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock chip_io = {
+ .fallback_open_state = &data,
+ };
+
+ g_test_write_injector = write_chip;
+ g_test_read_injector = read_chip;
+ g_test_erase_injector = block_erase_chip;
+ struct flashrom_flashctx flashctx = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_8MiB;
+ const char *param = ""; /* Default values for all params. */
+
+ setup_chip(&flashctx, &layout, &mock_chip, param, &chip_io);
+
+ printf("Erase chip operation started.\n");
+ assert_int_equal(0, flashrom_flash_erase(&flashctx));
+ printf("Erase chip operation done.\n");
+
+ teardown(&layout);
+}
+
+void erase_chip_with_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ static struct io_mock_fallback_open_state data = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock chip_io = {
+ .fallback_open_state = &data,
+ };
+
+ struct flashrom_flashctx flashctx = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_W25Q128_V;
+ /*
+ * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
+ * Nothing to mock, dummy is taking care of this already.
+ */
+ const char *param_dup = "bus=spi,emulate=W25Q128FV";
+
+ setup_chip(&flashctx, &layout, &mock_chip, param_dup, &chip_io);
+
+ printf("Erase chip operation started.\n");
+ assert_int_equal(0, flashrom_flash_erase(&flashctx));
+ printf("Erase chip operation done.\n");
+
+ teardown(&layout);
+}
+
+void read_chip_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ static struct io_mock_fallback_open_state data = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock chip_io = {
+ .fallback_open_state = &data,
+ };
+
+ g_test_write_injector = write_chip;
+ g_test_read_injector = read_chip;
+ g_test_erase_injector = block_erase_chip;
+ struct flashrom_flashctx flashctx = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_8MiB;
+ const char *param = ""; /* Default values for all params. */
+
+ setup_chip(&flashctx, &layout, &mock_chip, param, &chip_io);
+
+ const char *const filename = "read_chip.test";
+ unsigned long size = mock_chip.total_size * 1024;
+ unsigned char *buf = calloc(size, sizeof(unsigned char));
+ assert_non_null(buf);
+
+ printf("Read chip operation started.\n");
+ assert_int_equal(0, flashrom_image_read(&flashctx, buf, size));
+ assert_int_equal(0, write_buf_to_file(buf, size, filename));
+ printf("Read chip operation done.\n");
+
+ teardown(&layout);
+
+ free(buf);
+}
+
+void read_chip_with_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ static struct io_mock_fallback_open_state data = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock chip_io = {
+ .fallback_open_state = &data,
+ };
+
+ struct flashrom_flashctx flashctx = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_W25Q128_V;
+ /*
+ * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
+ * Nothing to mock, dummy is taking care of this already.
+ */
+ const char *param_dup = "bus=spi,emulate=W25Q128FV";
+
+ setup_chip(&flashctx, &layout, &mock_chip, param_dup, &chip_io);
+
+ const char *const filename = "read_chip.test";
+ unsigned long size = mock_chip.total_size * 1024;
+ unsigned char *buf = calloc(size, sizeof(unsigned char));
+ assert_non_null(buf);
+
+ printf("Read chip operation started.\n");
+ assert_int_equal(0, flashrom_image_read(&flashctx, buf, size));
+ assert_int_equal(0, write_buf_to_file(buf, size, filename));
+ printf("Read chip operation done.\n");
+
+ teardown(&layout);
+
+ free(buf);
+}
+
+void write_chip_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ static struct io_mock_fallback_open_state data = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock chip_io = {
+ .fallback_open_state = &data,
+ };
+
+ g_test_write_injector = write_chip;
+ g_test_read_injector = read_chip;
+ g_test_erase_injector = block_erase_chip;
+ struct flashrom_flashctx flashctx = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_8MiB;
+ const char *param = ""; /* Default values for all params. */
+
+ setup_chip(&flashctx, &layout, &mock_chip, param, &chip_io);
+
+ /*
+ * Providing filename "-" means content is taken from standard input.
+ * This doesn't change much because all file operations are mocked.
+ * However filename "-" makes a difference for
+ * flashrom.c#read_buf_from_file and allows to avoid mocking
+ * image_stat.st_size.
+ *
+ * Now this does mean test covers successful path only, but this test
+ * is designed to cover only successful write operation anyway.
+ *
+ * To cover error path of image_stat.st_size != flash size, filename
+ * needs to be provided and image_stat.st_size needs to be mocked.
+ */
+ const char *const filename = "-";
+ unsigned long size = mock_chip.total_size * 1024;
+ uint8_t *const newcontents = malloc(size);
+ assert_non_null(newcontents);
+
+ printf("Write chip operation started.\n");
+ assert_int_equal(0, read_buf_from_file(newcontents, size, filename));
+ assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, size, NULL));
+ printf("Write chip operation done.\n");
+
+ teardown(&layout);
+
+ free(newcontents);
+}
+
+void write_chip_with_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ static struct io_mock_fallback_open_state data = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock chip_io = {
+ .fallback_open_state = &data,
+ };
+
+ struct flashrom_flashctx flashctx = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_W25Q128_V;
+ /*
+ * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
+ * Nothing to mock, dummy is taking care of this already.
+ */
+ const char *param_dup = "bus=spi,emulate=W25Q128FV";
+
+ setup_chip(&flashctx, &layout, &mock_chip, param_dup, &chip_io);
+
+ /* See comment in write_chip_test_success */
+ const char *const filename = "-";
+ unsigned long size = mock_chip.total_size * 1024;
+ uint8_t *const newcontents = malloc(size);
+ assert_non_null(newcontents);
+
+ printf("Write chip operation started.\n");
+ assert_int_equal(0, read_buf_from_file(newcontents, size, filename));
+ assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, size, NULL));
+ printf("Write chip operation done.\n");
+
+ teardown(&layout);
+
+ free(newcontents);
+}
+
+void write_nonaligned_region_with_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ static struct io_mock_fallback_open_state data = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock chip_io = {
+ .fallback_open_state = &data,
+ };
+
+ struct flashrom_flashctx flashctx = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_W25Q128_V;
+ const uint32_t mock_chip_size = mock_chip.total_size * KiB;
+ /*
+ * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
+ * Nothing to mock, dummy is taking care of this already.
+ */
+ const char *param_dup = "bus=spi,emulate=W25Q128FV";
+
+ /* FIXME: MOCK_CHIP_CONTENT is buggy within setup_chip, it should also
+ * not be either 0x00 or 0xFF as those are specific values related to
+ * either a erased chip or zero'ed heap thus ambigous.
+ */
+#define MOCK_CHIP_SUBREGION_CONTENTS 0xCC
+ /**
+ * Step 0 - Prepare newcontents as contiguous sample data bytes as follows:
+ * {MOCK_CHIP_SUBREGION_CONTENTS, [..]}.
+ */
+ uint8_t *newcontents = calloc(1, mock_chip_size);
+ assert_non_null(newcontents);
+ memset(newcontents, MOCK_CHIP_SUBREGION_CONTENTS, mock_chip_size);
+
+ setup_chip(&flashctx, &layout, &mock_chip, param_dup, &chip_io);
+ /* Expect to verify only the non-aligned write operation within the region. */
+ flashrom_flag_set(&flashctx, FLASHROM_FLAG_VERIFY_AFTER_WRITE, true);
+ flashrom_flag_set(&flashctx, FLASHROM_FLAG_VERIFY_WHOLE_CHIP, false);
+
+ /**
+ * Prepare mock chip content and release setup_chip() layout for our
+ * custom ones.
+ */
+ assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, mock_chip_size, NULL));
+ flashrom_layout_release(layout);
+
+ /**
+ * Create region smaller than erase granularity of chip.
+ */
+ printf("Creating custom region layout... ");
+ assert_int_equal(0, flashrom_layout_new(&layout));
+ printf("Adding and including region0... ");
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0, (1 * KiB), "region0"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "region0"));
+ flashrom_layout_set(&flashctx, layout);
+ printf("Subregion layout configuration done.\n");
+
+ /**
+ * Step 1 - Modify newcontents as non-contiguous sample data bytes as follows:
+ * 0xAA 0xAA {MOCK_CHIP_SUBREGION_CONTENTS}, [..]}.
+ */
+ printf("Subregion chip write op..\n");
+ memset(newcontents, 0xAA, 2);
+ assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, mock_chip_size, NULL));
+ printf("Subregion chip write op done.\n");
+
+ /**
+ * FIXME: A 'NULL' layout should indicate a default layout however this
+ * causes a crash for a unknown reason. For now prepare a new default
+ * layout of the entire chip. flashrom_layout_set(&flashctx, NULL); // use default layout.
+ */
+ flashrom_layout_release(layout);
+ assert_int_equal(0, flashrom_layout_new(&layout));
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0, mock_chip_size - 1, "entire"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "entire"));
+ flashrom_layout_set(&flashctx, layout);
+
+ /**
+ * Expect a verification pass that the previous content within the region, however
+ * outside the region write length, is untouched.
+ */
+ printf("Entire chip verify op..\n");
+ assert_int_equal(0, flashrom_image_verify(&flashctx, newcontents, mock_chip_size));
+ printf("Entire chip verify op done.\n");
+
+ teardown(&layout);
+ free(newcontents);
+}
+
+static size_t verify_chip_fread(void *state, void *buf, size_t size, size_t len, FILE *fp)
+{
+ /*
+ * Verify operation compares contents of the file vs contents on the chip.
+ * To emulate successful verification we emulate file contents to be the
+ * same as what is on the chip.
+ */
+ memset(buf, MOCK_CHIP_CONTENT, len);
+ return len;
+}
+
+void verify_chip_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ static struct io_mock_fallback_open_state data = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock verify_chip_io = {
+ .iom_fread = verify_chip_fread,
+ .fallback_open_state = &data,
+ };
+
+ g_test_write_injector = write_chip;
+ g_test_read_injector = read_chip;
+ g_test_erase_injector = block_erase_chip;
+ struct flashrom_flashctx flashctx = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_8MiB;
+ const char *param = ""; /* Default values for all params. */
+
+ setup_chip(&flashctx, &layout, &mock_chip, param, &verify_chip_io);
+
+ /* See comment in write_chip_test_success */
+ const char *const filename = "-";
+ unsigned long size = mock_chip.total_size * 1024;
+ uint8_t *const newcontents = malloc(size);
+ assert_non_null(newcontents);
+
+ printf("Verify chip operation started.\n");
+ assert_int_equal(0, read_buf_from_file(newcontents, size, filename));
+ assert_int_equal(0, flashrom_image_verify(&flashctx, newcontents, size));
+ printf("Verify chip operation done.\n");
+
+ teardown(&layout);
+
+ free(newcontents);
+}
+
+void verify_chip_with_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ static struct io_mock_fallback_open_state data = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock verify_chip_io = {
+ .iom_fread = verify_chip_fread,
+ .fallback_open_state = &data,
+ };
+
+ struct flashrom_flashctx flashctx = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_W25Q128_V;
+ /*
+ * Dummyflasher is capable to emulate W25Q128.V, so we ask it to do this.
+ * Nothing to mock, dummy is taking care of this already.
+ */
+ const char *param_dup = "bus=spi,emulate=W25Q128FV";
+
+ setup_chip(&flashctx, &layout, &mock_chip, param_dup, &verify_chip_io);
+
+ /* See comment in write_chip_test_success */
+ const char *const filename = "-";
+ unsigned long size = mock_chip.total_size * 1024;
+ uint8_t *const newcontents = malloc(size);
+ assert_non_null(newcontents);
+
+ /*
+ * Dummyflasher controls chip state and fully emulates reads and writes,
+ * so to set up initial chip state we need to write on chip. Write
+ * operation takes content from file and writes on chip. File content is
+ * emulated in verify_chip_fread mock.
+ */
+
+ printf("Write chip operation started.\n");
+ assert_int_equal(0, read_buf_from_file(newcontents, size, filename));
+ assert_int_equal(0, flashrom_image_write(&flashctx, newcontents, size, NULL));
+ printf("Write chip operation done.\n");
+
+ printf("Verify chip operation started.\n");
+ assert_int_equal(0, flashrom_image_verify(&flashctx, newcontents, size));
+ printf("Verify chip operation done.\n");
+
+ teardown(&layout);
+
+ free(newcontents);
+}
diff --git a/tests/chip_wp.c b/tests/chip_wp.c
new file mode 100644
index 000000000..1fa6bb9c8
--- /dev/null
+++ b/tests/chip_wp.c
@@ -0,0 +1,402 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2021 3mdeb Embedded Systems Consulting
+ *
+ * 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 <include/test.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "chipdrivers.h"
+#include "flash.h"
+#include "libflashrom.h"
+#include "programmer.h"
+#include "tests.h"
+
+static int unittest_print_cb(enum flashrom_log_level level, const char *fmt, va_list ap)
+{
+ if (level > FLASHROM_MSG_INFO) return 0;
+ return vfprintf(stderr, fmt, ap);
+}
+
+/*
+ * Tests in this file do not use any mocking, because using write-protect
+ * emulation in dummyflasher programmer is sufficient
+ */
+
+#define LAYOUT_TAIL_REGION_START 0x1000
+
+static void setup_chip(struct flashrom_flashctx *flash, struct flashrom_layout **layout,
+ struct flashchip *chip, const char *programmer_param)
+{
+ flash->chip = chip;
+
+ if (layout) {
+ const size_t tail_start = LAYOUT_TAIL_REGION_START;
+ const size_t tail_len = chip->total_size * KiB - 1;
+
+ assert_int_equal(0, flashrom_layout_new(layout));
+ assert_int_equal(0, flashrom_layout_add_region(*layout, 0, tail_start - 1, "head"));
+ assert_int_equal(0, flashrom_layout_add_region(*layout, tail_start, tail_len, "tail"));
+
+ flashrom_layout_set(flash, *layout);
+ }
+
+ flashrom_set_log_callback((flashrom_log_callback *)&unittest_print_cb);
+
+ assert_int_equal(0, programmer_init(&programmer_dummy, programmer_param));
+ /* Assignment below normally happens while probing, but this test is not probing. */
+ flash->mst = &registered_masters[0];
+}
+
+static void teardown(struct flashrom_layout **layout)
+{
+ assert_int_equal(0, programmer_shutdown());
+ if (layout)
+ flashrom_layout_release(*layout);
+}
+
+/* Setup the struct for W25Q128.V, all values come from flashchips.c */
+static const struct flashchip chip_W25Q128_V = {
+ .vendor = "aklm&dummyflasher",
+ .total_size = 16 * 1024,
+ .page_size = 1024,
+ .tested = TEST_OK_PREW,
+ .read = SPI_CHIP_READ,
+ .write = SPI_CHIP_WRITE256,
+ .unlock = SPI_DISABLE_BLOCKPROTECT,
+ .feature_bits = FEATURE_WRSR_WREN | FEATURE_OTP | FEATURE_WRSR_EXT2 | FEATURE_WRSR2 | FEATURE_WRSR3,
+ .block_erasers =
+ {
+ {
+ .eraseblocks = { {4 * 1024, 4096} },
+ .block_erase = SPI_BLOCK_ERASE_20,
+ }, {
+ .eraseblocks = { {32 * 1024, 512} },
+ .block_erase = SPI_BLOCK_ERASE_52,
+ }, {
+ .eraseblocks = { {64 * 1024, 256} },
+ .block_erase = SPI_BLOCK_ERASE_D8,
+ }, {
+ .eraseblocks = { {16 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_60,
+ }, {
+ .eraseblocks = { {16 * 1024 * 1024, 1} },
+ .block_erase = SPI_BLOCK_ERASE_C7,
+ }
+ },
+ .reg_bits =
+ {
+ .srp = {STATUS1, 7, RW},
+ .srl = {STATUS2, 0, RW},
+ .bp = {{STATUS1, 2, RW}, {STATUS1, 3, RW}, {STATUS1, 4, RW}},
+ .tb = {STATUS1, 5, RW},
+ .sec = {STATUS1, 6, RW},
+ .cmp = {STATUS2, 6, RW},
+ .wps = {STATUS3, 2, RW},
+ },
+ .decode_range = DECODE_RANGE_SPI25,
+};
+
+/* Trying to set an unsupported WP range fails */
+void invalid_wp_range_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ const char *param_dup = "bus=spi,emulate=W25Q128FV,hwwp=no";
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_W25Q128_V;
+ struct flashrom_wp_cfg *wp_cfg;
+
+ setup_chip(&flash, NULL, &mock_chip, param_dup);
+
+ assert_int_equal(0, flashrom_wp_cfg_new(&wp_cfg));
+ flashrom_wp_set_mode(wp_cfg, FLASHROM_WP_MODE_HARDWARE);
+ flashrom_wp_set_range(wp_cfg, 0x1000, 0x1000);
+
+ assert_int_equal(FLASHROM_WP_ERR_RANGE_UNSUPPORTED, flashrom_wp_write_cfg(&flash, wp_cfg));
+
+ teardown(NULL);
+
+ flashrom_wp_cfg_release(wp_cfg);
+}
+
+/* Enabling hardware WP with a valid range succeeds */
+void set_wp_range_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ const char *param_dup = "bus=spi,emulate=W25Q128FV,hwwp=no";
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_W25Q128_V;
+ struct flashrom_wp_cfg *wp_cfg;
+
+ size_t start;
+ size_t len;
+
+ setup_chip(&flash, NULL, &mock_chip, param_dup);
+
+ /* Use last 4 KiB for a range. */
+ assert_int_equal(0, flashrom_wp_cfg_new(&wp_cfg));
+ flashrom_wp_set_mode(wp_cfg, FLASHROM_WP_MODE_HARDWARE);
+ flashrom_wp_set_range(wp_cfg, mock_chip.total_size * KiB - 4 * KiB, 4 * KiB);
+
+ assert_int_equal(0, flashrom_wp_write_cfg(&flash, wp_cfg));
+
+ /* Check that range was set correctly. */
+ assert_int_equal(0, flashrom_wp_read_cfg(wp_cfg, &flash));
+ flashrom_wp_get_range(&start, &len, wp_cfg);
+ assert_int_equal(16 * MiB - 4 * KiB, start);
+ assert_int_equal(4 * KiB, len);
+
+ teardown(NULL);
+
+ flashrom_wp_cfg_release(wp_cfg);
+}
+
+/* Enable hardware WP and verify that it can not be unset */
+void switch_wp_mode_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ const char *param_dup = "bus=spi,emulate=W25Q128FV,hwwp=yes";
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_W25Q128_V;
+ struct flashrom_wp_cfg *wp_cfg;
+
+ setup_chip(&flash, NULL, &mock_chip, param_dup);
+
+ assert_int_equal(0, flashrom_wp_cfg_new(&wp_cfg));
+
+ /* Check initial mode. */
+ assert_int_equal(0, flashrom_wp_read_cfg(wp_cfg, &flash));
+ assert_int_equal(FLASHROM_WP_MODE_DISABLED, flashrom_wp_get_mode(wp_cfg));
+
+ /* Enable hardware protection, which can't be unset because simulated
+ HW WP pin is in active state. */
+ flashrom_wp_set_mode(wp_cfg, FLASHROM_WP_MODE_HARDWARE);
+ assert_int_equal(0, flashrom_wp_write_cfg(&flash, wp_cfg));
+ assert_int_equal(0, flashrom_wp_read_cfg(wp_cfg, &flash));
+ assert_int_equal(FLASHROM_WP_MODE_HARDWARE, flashrom_wp_get_mode(wp_cfg));
+
+ /* Check that write-protection mode can't be unset. */
+ flashrom_wp_set_mode(wp_cfg, FLASHROM_WP_MODE_DISABLED);
+ assert_int_equal(FLASHROM_WP_ERR_VERIFY_FAILED, flashrom_wp_write_cfg(&flash, wp_cfg));
+
+ /* Final mode should be "hardware". */
+ assert_int_equal(0, flashrom_wp_read_cfg(wp_cfg, &flash));
+ assert_int_equal(FLASHROM_WP_MODE_HARDWARE, flashrom_wp_get_mode(wp_cfg));
+
+ teardown(NULL);
+
+ flashrom_wp_cfg_release(wp_cfg);
+}
+
+/* WP state is decoded correctly from status registers */
+void wp_init_from_status_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ /*
+ * CMP (S14) = 1 (range complement)
+ * SRP1 (S8) = 1
+ * SRP0 (S7) = 1 (`SRP1 == 1 && SRP0 == 1` is permanent mode)
+ * SEC (S6) = 1 (base unit is a 4 KiB sector)
+ * TB (S5) = 1 (bottom up range)
+ * BP2 (S4) = 0
+ * BP1 (S3) = 1
+ * BP0 (S2) = 1 (bp: BP2-0 == 0b011 == 3)
+ *
+ * Range coefficient is `2 ** (bp - 1)`, which is 4 in this case.
+ * Multiplaying that by base unit gives 16 KiB protected region at the
+ * bottom (start of the chip), which is then complemented.
+ */
+ const char *param_dup = "bus=spi,emulate=W25Q128FV,spi_status=0x41ec";
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_W25Q128_V;
+ struct flashrom_wp_cfg *wp_cfg;
+
+ size_t start;
+ size_t len;
+
+ setup_chip(&flash, NULL, &mock_chip, param_dup);
+
+ assert_int_equal(0, flashrom_wp_cfg_new(&wp_cfg));
+
+ /* Verify that WP mode reflects SPI status */
+ assert_int_equal(0, flashrom_wp_read_cfg(wp_cfg, &flash));
+ assert_int_equal(FLASHROM_WP_MODE_PERMANENT, flashrom_wp_get_mode(wp_cfg));
+ flashrom_wp_get_range(&start, &len, wp_cfg);
+ assert_int_equal(0x004000, start);
+ assert_int_equal(0xffc000, len);
+
+ teardown(NULL);
+
+ flashrom_wp_cfg_release(wp_cfg);
+}
+
+/* Enabled WP makes full chip erasure fail */
+void full_chip_erase_with_wp_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_W25Q128_V;
+ struct flashrom_wp_cfg *wp_cfg;
+
+ const char *param_dup = "bus=spi,emulate=W25Q128FV,hwwp=yes";
+
+ setup_chip(&flash, &layout, &mock_chip, param_dup);
+ /* Layout regions are created by setup_chip(). */
+ assert_int_equal(0, flashrom_layout_include_region(layout, "head"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "tail"));
+
+ assert_int_equal(0, flashrom_wp_cfg_new(&wp_cfg));
+
+ /* Write protection takes effect only after changing SRP values, so at
+ this stage WP is not enabled and erase completes successfully. */
+ assert_int_equal(0, flashrom_flash_erase(&flash));
+
+ /* Write non-erased value to entire chip so that erase operations cannot
+ * be optimized away. */
+ unsigned long size = flashrom_flash_getsize(&flash);
+ uint8_t *const contents = malloc(size);
+ assert_non_null(contents);
+ memset(contents, UNERASED_VALUE(&flash), size);
+ assert_int_equal(0, flashrom_image_write(&flash, contents, size, NULL));
+ free(contents);
+
+ assert_int_equal(0, flashrom_wp_read_cfg(wp_cfg, &flash));
+
+ /* Hardware-protect first 4 KiB. */
+ flashrom_wp_set_range(wp_cfg, 0, 4 * KiB);
+ flashrom_wp_set_mode(wp_cfg, FLASHROM_WP_MODE_HARDWARE);
+
+ assert_int_equal(0, flashrom_wp_write_cfg(&flash, wp_cfg));
+
+ /* Try erasing the chip again. Now that WP is active, the first 4 KiB is
+ protected and we're trying to erase the whole chip, erase should
+ fail. */
+ assert_int_equal(1, flashrom_flash_erase(&flash));
+
+ teardown(&layout);
+
+ flashrom_wp_cfg_release(wp_cfg);
+}
+
+/* Enabled WP does not block erasing unprotected parts of the chip */
+void partial_chip_erase_with_wp_dummyflasher_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ struct flashrom_flashctx flash = { 0 };
+ struct flashrom_layout *layout;
+ struct flashchip mock_chip = chip_W25Q128_V;
+ struct flashrom_wp_cfg *wp_cfg;
+
+ const char *param_dup = "bus=spi,emulate=W25Q128FV,hwwp=yes";
+
+ setup_chip(&flash, &layout, &mock_chip, param_dup);
+ /* Layout region is created by setup_chip(). */
+ assert_int_equal(0, flashrom_layout_include_region(layout, "tail"));
+
+ assert_int_equal(0, flashrom_wp_cfg_new(&wp_cfg));
+
+ assert_int_equal(0, flashrom_wp_read_cfg(wp_cfg, &flash));
+
+ /* Hardware-protect head region. */
+ flashrom_wp_set_mode(wp_cfg, FLASHROM_WP_MODE_HARDWARE);
+ flashrom_wp_set_range(wp_cfg, 0, LAYOUT_TAIL_REGION_START);
+
+ assert_int_equal(0, flashrom_wp_write_cfg(&flash, wp_cfg));
+
+ /* First 4 KiB is the only protected part of the chip and the region
+ we included covers only unprotected part, so erase operation should
+ succeed. */
+ assert_int_equal(0, flashrom_flash_erase(&flash));
+
+ teardown(&layout);
+
+ flashrom_wp_cfg_release(wp_cfg);
+}
+
+/* Chip register values & masks are calculated correctly by WP */
+void wp_get_register_values_and_masks(void **state)
+{
+ (void) state; /* unused */
+
+ /*
+ * Test with range: start = 0x004000, lengh = 0xffc000
+ *
+ * WP should use these bit values:
+ * WPS (S17) = 0 (write protect scheme)
+ * CMP (S14) = 1 (range complement)
+ * SRP1 (S8) = 0
+ * SRP0 (S7) = 1 (`SRP1 == 1 && SRP0 == 1` is permanent mode)
+ * SEC (S6) = 1 (base unit is a 4 KiB sector)
+ * TB (S5) = 1 (bottom up range)
+ * BP2 (S4) = 0
+ * BP1 (S3) = 1
+ * BP0 (S2) = 1 (bp: BP2-0 == 0b011 == 3)
+ *
+ * Register values:
+ * SR1 = 0b11101100 = 0xec
+ * SR2 = 0b01000000 = 0x40
+ * SR3 = 0b00000000 = 0x00
+ *
+ * Masks for WP bits in registers:
+ * SR1: 0b11111100 = 0xfc
+ * SR2: 0b01000000 = 0x41
+ * SR3: 0b00000100 = 0x04
+ *
+ * All WP bits are RW so write masks should be the same as the bit masks.
+ *
+ */
+ struct flashrom_flashctx flash = { 0 };
+ struct flashchip mock_chip = chip_W25Q128_V;
+ struct flashrom_wp_cfg *wp_cfg;
+
+ uint8_t reg_values[MAX_REGISTERS];
+ uint8_t bit_masks[MAX_REGISTERS];
+ uint8_t write_masks[MAX_REGISTERS];
+
+ setup_chip(&flash, NULL, &mock_chip, "bus=spi,emulate=W25Q128FV");
+
+ assert_int_equal(0, flashrom_wp_cfg_new(&wp_cfg));
+ flashrom_wp_set_mode(wp_cfg, FLASHROM_WP_MODE_HARDWARE);
+ flashrom_wp_set_range(wp_cfg, 0x004000, 0xffc000);
+
+ assert_int_equal(0, wp_cfg_to_reg_values(reg_values, bit_masks, write_masks, &flash, wp_cfg));
+
+ assert_int_equal(0xec, reg_values[STATUS1]);
+ assert_int_equal(0x40, reg_values[STATUS2]);
+ assert_int_equal(0x00, reg_values[STATUS3]);
+
+ assert_int_equal(0xfc, bit_masks[STATUS1]);
+ assert_int_equal(0x41, bit_masks[STATUS2]);
+ assert_int_equal(0x04, bit_masks[STATUS3]);
+
+ assert_int_equal(0xfc, write_masks[STATUS1]);
+ assert_int_equal(0x41, write_masks[STATUS2]);
+ assert_int_equal(0x04, write_masks[STATUS3]);
+
+ teardown(NULL);
+
+ flashrom_wp_cfg_release(wp_cfg);
+}
diff --git a/tests/dediprog.c b/tests/dediprog.c
new file mode 100644
index 000000000..26b1e7512
--- /dev/null
+++ b/tests/dediprog.c
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_DEDIPROG == 1
+static int dediprog_libusb_init(void *state, libusb_context **ctx)
+{
+ *ctx = not_null();
+ return 0;
+}
+
+static int dediprog_libusb_control_transfer(void *state,
+ libusb_device_handle *devh,
+ uint8_t bmRequestType,
+ uint8_t bRequest,
+ uint16_t wValue,
+ uint16_t wIndex,
+ unsigned char *data,
+ uint16_t wLength,
+ unsigned int timeout)
+{
+ if (bRequest == 0x08 /* dediprog_cmds CMD_READ_PROG_INFO */) {
+ /* Provide dediprog Device String into data buffer */
+ memcpy(data, "SF600 V:7.2.2 ", wLength);
+ }
+ return wLength;
+}
+
+void dediprog_basic_lifecycle_test_success(void **state)
+{
+ struct io_mock_fallback_open_state dediprog_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock dediprog_io = {
+ .libusb_init = dediprog_libusb_init,
+ .libusb_control_transfer = dediprog_libusb_control_transfer,
+ .fallback_open_state = &dediprog_fallback_open_state,
+ };
+
+ run_basic_lifecycle(state, &dediprog_io, &programmer_dediprog, "voltage=3.5V");
+}
+#else
+ SKIP_TEST(dediprog_basic_lifecycle_test_success)
+#endif /* CONFIG_DEDIPROG */
diff --git a/tests/dummyflasher.c b/tests/dummyflasher.c
new file mode 100644
index 000000000..052938bec
--- /dev/null
+++ b/tests/dummyflasher.c
@@ -0,0 +1,153 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_DUMMY == 1
+void dummy_basic_lifecycle_test_success(void **state)
+{
+ struct io_mock_fallback_open_state dummy_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock dummy_io = {
+ .fallback_open_state = &dummy_fallback_open_state,
+ };
+
+ run_basic_lifecycle(state, &dummy_io, &programmer_dummy, "bus=parallel+lpc+fwh+spi+prog");
+}
+
+void dummy_probe_lifecycle_test_success(void **state)
+{
+ struct io_mock_fallback_open_state dummy_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock dummy_io = {
+ .fallback_open_state = &dummy_fallback_open_state,
+ };
+
+ run_probe_lifecycle(state, &dummy_io, &programmer_dummy, "bus=spi,emulate=W25Q128FV", "W25Q128.V");
+}
+
+void dummy_probe_variable_size_test_success(void **state)
+{
+ struct io_mock_fallback_open_state dummy_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock dummy_io = {
+ .fallback_open_state = &dummy_fallback_open_state,
+ };
+
+ run_probe_lifecycle(state, &dummy_io, &programmer_dummy, "size=8388608,emulate=VARIABLE_SIZE", "Opaque flash chip");
+}
+
+void dummy_init_fails_unhandled_param_test_success(void **state)
+{
+ struct io_mock_fallback_open_state dummy_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock dummy_io = {
+ .fallback_open_state = &dummy_fallback_open_state,
+ };
+
+ /*
+ * Programmer init should fail due to `dummy_init` failure caused by
+ * invalid value of `emulate` param. There is unhandled param left
+ * at the end of param string.
+ */
+ run_init_error_path(state, &dummy_io, &programmer_dummy, "bus=spi,emulate=INVALID,unhandled=value", 1);
+}
+
+void dummy_init_success_invalid_param_test_success(void **state)
+{
+ struct io_mock_fallback_open_state dummy_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock dummy_io = {
+ .fallback_open_state = &dummy_fallback_open_state,
+ };
+
+ /*
+ * Programmer init should fail despite of the fact that `dummy_init`
+ * is successful, due to invalid param at the end of param string.
+ */
+ run_init_error_path(state, &dummy_io, &programmer_dummy,
+ "bus=spi,emulate=W25Q128FV,invalid=value", ERROR_FLASHROM_FATAL);
+}
+
+void dummy_init_success_unhandled_param_test_success(void **state)
+{
+ struct io_mock_fallback_open_state dummy_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock dummy_io = {
+ .fallback_open_state = &dummy_fallback_open_state,
+ };
+
+ /*
+ * Programmer init should fail despite of the fact that `dummy_init`
+ * is successful, due to unhandled param at the end of param string.
+ * Unhandled param `voltage` is not used for dummyflasher.
+ */
+ run_init_error_path(state, &dummy_io, &programmer_dummy,
+ "bus=spi,emulate=W25Q128FV,voltage=3.5V", ERROR_FLASHROM_FATAL);
+}
+
+void dummy_null_prog_param_test_success(void **state)
+{
+ struct io_mock_fallback_open_state dummy_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock dummy_io = {
+ .fallback_open_state = &dummy_fallback_open_state,
+ };
+
+ run_basic_lifecycle(state, &dummy_io, &programmer_dummy, NULL);
+}
+
+void dummy_all_buses_test_success(void **state)
+{
+ struct io_mock_fallback_open_state dummy_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock dummy_io = {
+ .fallback_open_state = &dummy_fallback_open_state,
+ };
+
+ run_basic_lifecycle(state, &dummy_io, &programmer_dummy, "bus=lpc+fwh");
+ run_basic_lifecycle(state, &dummy_io, &programmer_dummy, "bus=spi");
+ run_basic_lifecycle(state, &dummy_io, &programmer_dummy, "bus=prog");
+ run_basic_lifecycle(state, &dummy_io, &programmer_dummy, "bus=parallel+fwh+prog");
+ run_basic_lifecycle(state, &dummy_io, &programmer_dummy, "bus=spi+prog");
+ run_basic_lifecycle(state, &dummy_io, &programmer_dummy, "bus=parallel+lpc+spi");
+}
+
+#else
+ SKIP_TEST(dummy_basic_lifecycle_test_success)
+ SKIP_TEST(dummy_probe_lifecycle_test_success)
+ SKIP_TEST(dummy_probe_variable_size_test_success)
+ SKIP_TEST(dummy_init_fails_unhandled_param_test_success)
+ SKIP_TEST(dummy_init_success_invalid_param_test_success)
+ SKIP_TEST(dummy_init_success_unhandled_param_test_success)
+ SKIP_TEST(dummy_null_prog_param_test_success)
+ SKIP_TEST(dummy_all_buses_test_success)
+#endif /* CONFIG_DUMMY */
diff --git a/tests/flashrom.c b/tests/flashrom.c
index 50464ddbf..cc8883132 100644
--- a/tests/flashrom.c
+++ b/tests/flashrom.c
@@ -14,38 +14,58 @@
*/
#include <include/test.h>
+#include "tests.h"
#include "programmer.h"
+#define assert_equal_and_free(text, expected) \
+ do { \
+ assert_string_equal(text, expected); \
+ free(text); \
+ } while (0)
+
+#define assert_not_equal_and_free(text, expected) \
+ do { \
+ assert_string_not_equal(text, expected); \
+ free(text); \
+ } while (0)
+
+
void flashbuses_to_text_test_success(void **state)
{
(void) state; /* unused */
enum chipbustype bustype;
+ char *text;
bustype = BUS_NONSPI;
- assert_string_equal(flashbuses_to_text(bustype), "Non-SPI");
+ text = flashbuses_to_text(bustype);
+ assert_equal_and_free(text, "Non-SPI");
bustype |= BUS_PARALLEL;
- assert_string_not_equal(flashbuses_to_text(bustype), "Non-SPI, Parallel");
+ text = flashbuses_to_text(bustype);
+ assert_not_equal_and_free(text, "Non-SPI, Parallel");
bustype = BUS_PARALLEL;
bustype |= BUS_LPC;
- assert_string_equal(flashbuses_to_text(bustype), "Parallel, LPC");
+ text = flashbuses_to_text(bustype);
+ assert_equal_and_free(text, "Parallel, LPC");
bustype |= BUS_FWH;
//BUS_NONSPI = BUS_PARALLEL | BUS_LPC | BUS_FWH,
- assert_string_equal(flashbuses_to_text(bustype), "Non-SPI");
+ text = flashbuses_to_text(bustype);
+ assert_equal_and_free(text, "Non-SPI");
bustype |= BUS_SPI;
- assert_string_equal(flashbuses_to_text(bustype), "Parallel, LPC, FWH, SPI");
+ text = flashbuses_to_text(bustype);
+ assert_equal_and_free(text, "Parallel, LPC, FWH, SPI");
bustype |= BUS_PROG;
- assert_string_equal(
- flashbuses_to_text(bustype),
- "Parallel, LPC, FWH, SPI, Programmer-specific"
- );
+ text = flashbuses_to_text(bustype);
+ assert_equal_and_free(text,
+ "Parallel, LPC, FWH, SPI, Programmer-specific");
bustype = BUS_NONE;
- assert_string_equal(flashbuses_to_text(bustype), "None");
+ text = flashbuses_to_text(bustype);
+ assert_equal_and_free(text, "None");
}
diff --git a/tests/helpers.c b/tests/helpers.c
index a920c1563..271fb4831 100644
--- a/tests/helpers.c
+++ b/tests/helpers.c
@@ -15,11 +15,10 @@
#include <include/test.h>
+#include "tests.h"
#include "flash.h"
#include <stdint.h>
-#include <stdlib.h>
-
void address_to_bits_test_success(void **state)
{
@@ -46,6 +45,7 @@ void strcat_realloc_test_success(void **state)
const char src0[] = "hello";
const char src1[] = " world";
char *dest = calloc(1, 1);
+ assert_non_null(dest);
dest = strcat_realloc(dest, src0);
dest = strcat_realloc(dest, src1);
assert_string_equal("hello world", dest);
diff --git a/tests/include/test.h b/tests/include/test.h
index 24fa963b4..ef0b9a6f6 100644
--- a/tests/include/test.h
+++ b/tests/include/test.h
@@ -27,4 +27,19 @@
#include <setjmp.h>
#include <cmocka.h>
+#define NON_ZERO (0xf000baaa)
+
+#define MOCK_FD (0x10ec)
+
+#define SKIP_TEST(name) \
+ void name (void **state) { skip(); }
+
+/*
+ * Having this as function allows to set a breakpoint on the address,
+ * as it has a named symbol associated with the address number.
+ */
+void *not_null(void);
+
+#define LOG_ME printf("%s is called\n", __func__)
+
#endif /* _TESTS_TEST_H */
diff --git a/tests/io_mock.c b/tests/io_mock.c
new file mode 100644
index 000000000..4828e53ca
--- /dev/null
+++ b/tests/io_mock.c
@@ -0,0 +1,31 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2021, Google Inc. All rights reserved.
+ *
+ * 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 "io_mock.h"
+
+static const struct io_mock *current_io = NULL;
+
+void io_mock_register(const struct io_mock *io)
+{
+ /* A test can either register its own mock open function or fallback_open_state. */
+ assert_true(io == NULL || io->iom_open == NULL || io->fallback_open_state == NULL);
+ current_io = io;
+}
+
+const struct io_mock *get_io(void)
+{
+ return current_io;
+}
diff --git a/tests/io_mock.h b/tests/io_mock.h
new file mode 100644
index 000000000..04b0ef528
--- /dev/null
+++ b/tests/io_mock.h
@@ -0,0 +1,134 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (c) 2021 Nico Huber <nico.h@gmx.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _IO_MOCK_H_
+#define _IO_MOCK_H_
+
+#include <include/test.h>
+
+/* Required for `FILE *` */
+#include <stdio.h>
+
+#include <stdint.h>
+
+/* Required for struct timeval and mode_t */
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "usb_unittests.h"
+
+/* Address value needs fit into uint8_t. */
+#define USB_DEVICE_ADDRESS 19
+
+/* Define struct pci_dev to avoid dependency on pci.h */
+struct pci_dev {
+ char padding[18];
+ unsigned int device_id;
+};
+
+/* Linux I2C interface constants, avoiding linux/i2c-dev.h */
+#define I2C_SLAVE 0x0703
+
+/* Always return success for tests. */
+#define S_ISREG(x) 0
+
+/* Maximum number of open calls to mock. This number is arbitrary. */
+#define MAX_MOCK_OPEN 4
+
+struct io_mock_fallback_open_state {
+ unsigned int noc;
+ const char *paths[MAX_MOCK_OPEN];
+ int flags[MAX_MOCK_OPEN];
+};
+
+struct io_mock {
+ void *state;
+
+ /* Port I/O */
+ void (*outb)(void *state, unsigned char value, unsigned short port);
+ unsigned char (*inb)(void *state, unsigned short port);
+
+ void (*outw)(void *state, unsigned short value, unsigned short port);
+ unsigned short (*inw)(void *state, unsigned short port);
+
+ void (*outl)(void *state, unsigned int value, unsigned short port);
+ unsigned int (*inl)(void *state, unsigned short port);
+
+ /* USB I/O */
+ int (*libusb_init)(void *state, libusb_context **ctx);
+ int (*libusb_control_transfer)(void *state,
+ libusb_device_handle *devh,
+ uint8_t bmRequestType,
+ uint8_t bRequest,
+ uint16_t wValue,
+ uint16_t wIndex,
+ unsigned char *data,
+ uint16_t wLength,
+ unsigned int timeout);
+ ssize_t (*libusb_get_device_list)(void *state, libusb_context *, libusb_device ***list);
+ void (*libusb_free_device_list)(void *state, libusb_device **list, int unref_devices);
+ int (*libusb_get_device_descriptor)(void *state, libusb_device *, struct libusb_device_descriptor *);
+ int (*libusb_get_config_descriptor)(void *state,
+ libusb_device *,
+ uint8_t config_index,
+ struct libusb_config_descriptor **);
+ void (*libusb_free_config_descriptor)(void *state, struct libusb_config_descriptor *);
+ struct libusb_transfer* (*libusb_alloc_transfer)(void *state, int iso_packets);
+ int (*libusb_submit_transfer)(void *state, struct libusb_transfer *transfer);
+ void (*libusb_free_transfer)(void *state, struct libusb_transfer *transfer);
+ int (*libusb_handle_events_timeout)(void *state, libusb_context *ctx, struct timeval *tv);
+
+ /* POSIX File I/O */
+ int (*iom_open)(void *state, const char *pathname, int flags, mode_t mode);
+ int (*iom_ioctl)(void *state, int fd, unsigned long request, va_list args);
+ int (*iom_read)(void *state, int fd, void *buf, size_t sz);
+ int (*iom_write)(void *state, int fd, const void *buf, size_t sz);
+
+ /* Standard I/O */
+ FILE* (*iom_fopen)(void *state, const char *pathname, const char *mode);
+ char* (*iom_fgets)(void *state, char *buf, int len, FILE *fp);
+ size_t (*iom_fread)(void *state, void *buf, size_t size, size_t len, FILE *fp);
+ size_t (*iom_fwrite)(void *state, const void *buf, size_t size, size_t len, FILE *fp);
+ int (*iom_fprintf)(void *state, FILE *fp, const char *fmt, va_list args);
+ int (*iom_fclose)(void *state, FILE *fp);
+ FILE *(*iom_fdopen)(void *state, int fd, const char *mode);
+
+ /*
+ * An alternative to custom open mock. A test can either register its
+ * own mock open function or fallback_open_state.
+ */
+ struct io_mock_fallback_open_state *fallback_open_state;
+};
+
+void io_mock_register(const struct io_mock *io);
+
+const struct io_mock *get_io(void);
+
+#endif
diff --git a/tests/io_real.c b/tests/io_real.c
new file mode 100644
index 000000000..429027fb5
--- /dev/null
+++ b/tests/io_real.c
@@ -0,0 +1,78 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2022 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "io_mock.h"
+#include "wraps.h"
+
+#include "io_real.h"
+#include <string.h>
+
+static int io_real_open(void *state, const char *pathname, int flags, mode_t mode)
+{
+ LOG_ME;
+ return __real_open(pathname, flags, mode);
+}
+
+static FILE *io_real_fopen(void *state, const char *pathname, const char *mode)
+{
+ LOG_ME;
+ return __real_fopen(pathname, mode);
+}
+
+static FILE *io_real_fdopen(void *state, int fd, const char *mode)
+{
+ LOG_ME;
+ return __real_fdopen(fd, mode);
+}
+
+static size_t io_real_fwrite(void *state, const void *ptr, size_t size, size_t nmemb, FILE *fp)
+{
+ return __real_fwrite(ptr, size, nmemb, fp);
+}
+
+static int io_real_fclose(void *state, FILE *fp)
+{
+ LOG_ME;
+ return __real_fclose(fp);
+}
+
+/* Mock ios that defer to the real io functions.
+ * These exist so that code coverage can print to real files on disk.
+ */
+static const struct io_mock real_io = {
+ .iom_open = io_real_open,
+ .iom_fopen = io_real_fopen,
+ .iom_fwrite = io_real_fwrite,
+ .iom_fdopen = io_real_fdopen,
+ .iom_fclose = io_real_fclose,
+};
+
+/* Return 0 if string ends with suffix. */
+static int check_suffix(const char *string, const char *suffix)
+{
+ int len_l = strlen(string);
+ int len_r = strlen(suffix);
+ if (len_l > len_r)
+ return strcmp(string + len_l - len_r, suffix);
+ return 1;
+}
+
+void maybe_unmock_io(const char *pathname)
+{
+ const char *gcov_suffix = ".gcda";
+ const char *llvm_cov_suffix = ".profraw";
+ if (!check_suffix(pathname, gcov_suffix) || !check_suffix(pathname, llvm_cov_suffix))
+ io_mock_register(&real_io);
+}
diff --git a/tests/io_real.h b/tests/io_real.h
new file mode 100644
index 000000000..f2491c3ab
--- /dev/null
+++ b/tests/io_real.h
@@ -0,0 +1,24 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2022 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 IO_REAL_H
+#define IO_REAL_H
+
+/* Detect file io that should not be mocked, for example code coverage writing
+ * gcda files. Call io_mock_register with functions that defer to real io.
+ */
+void maybe_unmock_io(const char* pathname);
+
+#endif /* IO_REAL_H */
diff --git a/tests/layout.c b/tests/layout.c
new file mode 100644
index 000000000..917d77e24
--- /dev/null
+++ b/tests/layout.c
@@ -0,0 +1,214 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 <include/test.h>
+#include <stdio.h>
+
+#include "tests.h"
+#include "flash.h"
+#include "layout.h"
+#include "libflashrom.h"
+
+void included_regions_dont_overlap_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ printf("Creating layout... ");
+ struct flashrom_layout *layout;
+ assert_int_equal(0, flashrom_layout_new(&layout));
+ printf("done\n");
+
+ printf("Adding and including first region... ");
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0x00021000, 0x00031000, "first region"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "first region"));
+ printf("done");
+
+ printf(", second (non-overlapping) region... ");
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0x00031001, 0x0023efc0, "second region"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "second region"));
+ printf("done\n");
+
+ printf("Asserting included regions do not overlap... ");
+ assert_int_equal(0, included_regions_overlap(layout));
+ printf("done\n");
+
+ printf("Releasing layout... ");
+ flashrom_layout_release(layout);
+ printf("done\n");
+}
+
+void included_regions_overlap_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ printf("Creating layout... ");
+ struct flashrom_layout *layout;
+ assert_int_equal(0, flashrom_layout_new(&layout));
+ printf("done\n");
+
+ printf("Adding and including first region... ");
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0x00021000, 0x00031000, "first region"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "first region"));
+ printf("done");
+
+ printf(", second (overlapping) region... ");
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0x00027100, 0x0023efc0, "second region"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "second region"));
+ printf("done\n");
+
+ printf("Asserting included regions overlap... ");
+ assert_int_equal(1, included_regions_overlap(layout));
+ printf("done\n");
+
+ printf("Releasing layout... ");
+ flashrom_layout_release(layout);
+ printf("done\n");
+}
+
+void region_not_included_overlap_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ printf("Creating layout... ");
+ struct flashrom_layout *layout;
+ assert_int_equal(0, flashrom_layout_new(&layout));
+ printf("done\n");
+
+ printf("Adding and including first region... ");
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0x00021000, 0x00031000, "first region"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "first region"));
+ printf("done");
+
+ printf(", second (overlapping) region, not included... ");
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0x00027100, 0x0023efc0, "second region"));
+ printf("done\n");
+
+ printf("Asserting included regions do not overlap... ");
+ assert_int_equal(0, included_regions_overlap(layout));
+ printf("done\n");
+
+ printf("Releasing layout... ");
+ flashrom_layout_release(layout);
+ printf("done\n");
+}
+
+void layout_pass_sanity_checks_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ unsigned int region_start = 0x00021000;
+ unsigned int region_end = 0x00031000;
+ unsigned int region2_start = 0x00041000;
+ unsigned int region2_end = 0x00051000;
+ unsigned int start = 0;
+ unsigned int len = 0;
+
+ struct flashrom_layout *layout;
+
+ printf("Creating layout with one included region... ");
+ assert_int_equal(0, flashrom_layout_new(&layout));
+ assert_int_equal(0, flashrom_layout_add_region(layout, region_start, region_end, "region"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "region"));
+ assert_int_equal(0, flashrom_layout_add_region(layout, region2_start, region2_end, "region2"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "region2"));
+ assert_int_equal(0, flashrom_layout_exclude_region(layout, "region2"));
+ printf("done\n");
+
+ printf("Asserting region range... ");
+ flashrom_layout_get_region_range(layout, "region", &start, &len);
+ assert_int_equal(start, region_start);
+ assert_int_equal(len, region_end - region_start + 1);
+ printf("done\n");
+
+ printf("Layout passes sanity checks... ");
+
+ struct flashchip chip = {
+ .total_size = 1024,
+ };
+ struct flashrom_flashctx flash = {
+ .chip = &chip,
+ };
+ flashrom_layout_set(&flash, layout);
+ assert_int_equal(0, layout_sanity_checks(&flash));
+
+ printf("done\n");
+
+ printf("Releasing layout... ");
+ flashrom_layout_release(layout);
+ printf("done\n");
+}
+
+void layout_region_invalid_address_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ struct flashrom_layout *layout;
+
+ printf("Creating layout with one included region... ");
+ assert_int_equal(0, flashrom_layout_new(&layout));
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0x60000000, 0x70000000, "region"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "region"));
+ printf("done\n");
+
+ printf("Layout does not pass sanity checks... ");
+
+ struct flashchip chip = {
+ /* Make sure layout region addresses exceed total size on chip. */
+ .total_size = 1,
+ };
+ struct flashrom_flashctx flash = {
+ .chip = &chip,
+ };
+ flashrom_layout_set(&flash, layout);
+ assert_int_equal(1, layout_sanity_checks(&flash));
+
+ printf("done\n");
+
+ printf("Releasing layout... ");
+ flashrom_layout_release(layout);
+ printf("done\n");
+}
+
+void layout_region_invalid_range_test_success(void **state)
+{
+ (void) state; /* unused */
+
+ struct flashrom_layout *layout;
+
+ printf("Creating layout with one included region... ");
+ assert_int_equal(0, flashrom_layout_new(&layout));
+ /* Make sure address range of region is not positive i.e. start > end. */
+ assert_int_equal(0, flashrom_layout_add_region(layout, 0x00000020, 0x00000010, "region"));
+ assert_int_equal(0, flashrom_layout_include_region(layout, "region"));
+ printf("done\n");
+
+ printf("Layout does not pass sanity checks... ");
+
+ struct flashchip chip = {
+ /* Make sure layout region addresses fit into total size on chip. */
+ .total_size = 1024,
+ };
+ struct flashrom_flashctx flash = {
+ .chip = &chip,
+ };
+ flashrom_layout_set(&flash, layout);
+ assert_int_equal(1, layout_sanity_checks(&flash));
+
+ printf("done\n");
+
+ printf("Releasing layout... ");
+ flashrom_layout_release(layout);
+ printf("done\n");
+}
diff --git a/tests/libusb_wraps.c b/tests/libusb_wraps.c
new file mode 100644
index 000000000..be990a12c
--- /dev/null
+++ b/tests/libusb_wraps.c
@@ -0,0 +1,222 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 <include/test.h>
+#include "io_mock.h"
+#include "libusb_wraps.h"
+
+void *__wrap_usb_dev_get_by_vid_pid_number(
+ libusb_context *usb_ctx, uint16_t vid, uint16_t pid, unsigned int num)
+{
+ LOG_ME;
+ return not_null();
+}
+
+int __wrap_libusb_init(libusb_context **ctx)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_init)
+ return get_io()->libusb_init(get_io()->state, ctx);
+ return 0;
+}
+
+void __wrap_libusb_set_debug(libusb_context *ctx, int level)
+{
+ LOG_ME;
+}
+
+int __wrap_libusb_set_option(libusb_context *ctx, int option, ...)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_libusb_open(libusb_device *dev, libusb_device_handle **devh)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_libusb_set_auto_detach_kernel_driver(libusb_device_handle *devh, int enable)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_libusb_detach_kernel_driver(libusb_device_handle *dev_handle, int interface_number)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_libusb_attach_kernel_driver(libusb_device_handle *dev_handle, int interface_number)
+{
+ LOG_ME;
+ return 0;
+}
+
+struct libusb_device_handle *__wrap_libusb_open_device_with_vid_pid(
+ libusb_context *ctx, uint16_t vendor_id, uint16_t product_id)
+{
+ LOG_ME;
+ return not_null();
+}
+
+libusb_device *__wrap_libusb_get_device(libusb_device_handle *dev_handle)
+{
+ LOG_ME;
+ return not_null();
+}
+
+ssize_t __wrap_libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_get_device_list)
+ return get_io()->libusb_get_device_list(get_io()->state, ctx, list);
+ return 0;
+}
+
+void __wrap_libusb_free_device_list(libusb_device **list, int unref_devices)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_free_device_list)
+ get_io()->libusb_free_device_list(get_io()->state, list, unref_devices);
+}
+
+uint8_t __wrap_libusb_get_bus_number(libusb_device *dev)
+{
+ LOG_ME;
+ return 0;
+}
+
+uint8_t __wrap_libusb_get_device_address(libusb_device *dev)
+{
+ LOG_ME;
+ return USB_DEVICE_ADDRESS;
+}
+
+int __wrap_libusb_get_device_descriptor(libusb_device *dev, struct libusb_device_descriptor *desc)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_get_device_descriptor)
+ return get_io()->libusb_get_device_descriptor(get_io()->state, dev, desc);
+ return 0;
+}
+
+int __wrap_libusb_get_config_descriptor(
+ libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_get_config_descriptor)
+ return get_io()->libusb_get_config_descriptor(get_io()->state, dev, config_index, config);
+ return 0;
+}
+
+void __wrap_libusb_free_config_descriptor(struct libusb_config_descriptor *config)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_free_config_descriptor)
+ return get_io()->libusb_free_config_descriptor(get_io()->state, config);
+ return;
+}
+
+int __wrap_libusb_get_configuration(libusb_device_handle *devh, int *config)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_libusb_set_configuration(libusb_device_handle *devh, int config)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_libusb_claim_interface(libusb_device_handle *devh, int interface_number)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_libusb_control_transfer(libusb_device_handle *devh, uint8_t bmRequestType,
+ uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data,
+ uint16_t wLength, unsigned int timeout)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_control_transfer)
+ return get_io()->libusb_control_transfer(get_io()->state,
+ devh, bmRequestType, bRequest, wValue, wIndex, data, wLength, timeout);
+ return 0;
+}
+
+int __wrap_libusb_release_interface(libusb_device_handle *devh, int interface_number)
+{
+ LOG_ME;
+ return 0;
+}
+
+void __wrap_libusb_close(libusb_device_handle *devh)
+{
+ LOG_ME;
+}
+
+libusb_device *__wrap_libusb_ref_device(libusb_device *dev)
+{
+ LOG_ME;
+ return NULL;
+}
+
+void __wrap_libusb_unref_device(libusb_device *dev)
+{
+ LOG_ME;
+}
+
+struct libusb_transfer *__wrap_libusb_alloc_transfer(int iso_packets)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_alloc_transfer)
+ return get_io()->libusb_alloc_transfer(get_io()->state, iso_packets);
+ return not_null();
+}
+
+int __wrap_libusb_submit_transfer(struct libusb_transfer *transfer)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_submit_transfer)
+ return get_io()->libusb_submit_transfer(get_io()->state, transfer);
+ return 0;
+}
+
+void __wrap_libusb_free_transfer(struct libusb_transfer *transfer)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_free_transfer)
+ get_io()->libusb_free_transfer(get_io()->state, transfer);
+}
+
+int __wrap_libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv)
+{
+ LOG_ME;
+ if (get_io() && get_io()->libusb_handle_events_timeout)
+ get_io()->libusb_handle_events_timeout(get_io()->state, ctx, tv);
+ return 0;
+}
+
+void __wrap_libusb_exit(libusb_context *ctx)
+{
+ LOG_ME;
+}
diff --git a/tests/libusb_wraps.h b/tests/libusb_wraps.h
new file mode 100644
index 000000000..8c3aa40a1
--- /dev/null
+++ b/tests/libusb_wraps.h
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2022 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 LIBUSB_WRAPS_H
+#define LIBUSB_WRAPS_H
+
+#include "usb_unittests.h"
+
+void *__wrap_usb_dev_get_by_vid_pid_number(
+ libusb_context *usb_ctx, uint16_t vid, uint16_t pid, unsigned int num);
+int __wrap_libusb_init(libusb_context **ctx);
+void __wrap_libusb_set_debug(libusb_context *ctx, int level);
+int __wrap_libusb_set_option(libusb_context *ctx, int option, ...);
+int __wrap_libusb_open(libusb_device *dev, libusb_device_handle **devh);
+int __wrap_libusb_set_auto_detach_kernel_driver(libusb_device_handle *devh, int enable);
+int __wrap_libusb_detach_kernel_driver(libusb_device_handle *dev_handle, int interface_number);
+int __wrap_libusb_attach_kernel_driver(libusb_device_handle *dev_handle, int interface_number);
+struct libusb_device_handle *__wrap_libusb_open_device_with_vid_pid(
+ libusb_context *ctx, uint16_t vendor_id, uint16_t product_id);
+libusb_device *__wrap_libusb_get_device(libusb_device_handle *dev_handle);
+ssize_t __wrap_libusb_get_device_list(libusb_context *ctx, libusb_device ***list);
+void __wrap_libusb_free_device_list(libusb_device **list, int unref_devices);
+uint8_t __wrap_libusb_get_bus_number(libusb_device *dev);
+uint8_t __wrap_libusb_get_device_address(libusb_device *dev);
+int __wrap_libusb_get_device_descriptor(libusb_device *dev, struct libusb_device_descriptor *desc);
+int __wrap_libusb_get_config_descriptor(
+ libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config);
+void __wrap_libusb_free_config_descriptor(struct libusb_config_descriptor *config);
+int __wrap_libusb_get_configuration(libusb_device_handle *devh, int *config);
+int __wrap_libusb_set_configuration(libusb_device_handle *devh, int config);
+int __wrap_libusb_claim_interface(libusb_device_handle *devh, int interface_number);
+int __wrap_libusb_control_transfer(libusb_device_handle *devh, uint8_t bmRequestType,
+ uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned char *data,
+ uint16_t wLength, unsigned int timeout);
+int __wrap_libusb_release_interface(libusb_device_handle *devh, int interface_number);
+void __wrap_libusb_close(libusb_device_handle *devh);
+libusb_device *__wrap_libusb_ref_device(libusb_device *dev);
+void __wrap_libusb_unref_device(libusb_device *dev);
+struct libusb_transfer *__wrap_libusb_alloc_transfer(int iso_packets);
+int __wrap_libusb_submit_transfer(struct libusb_transfer *transfer);
+void __wrap_libusb_free_transfer(struct libusb_transfer *transfer);
+int __wrap_libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv);
+void __wrap_libusb_exit(libusb_context *ctx);
+
+#endif /* LIBUSB_WRAPS_H */
diff --git a/tests/lifecycle.c b/tests/lifecycle.c
new file mode 100644
index 000000000..95c424969
--- /dev/null
+++ b/tests/lifecycle.c
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+static void probe_chip(const struct programmer_entry *prog,
+ struct flashrom_programmer *flashprog,
+ const char *const chip_name)
+{
+ struct flashrom_flashctx *flashctx;
+
+ printf("Testing flashrom_flash_probe for programmer=%s, chip=%s ... \n", prog->name, chip_name);
+ assert_int_equal(0, flashrom_flash_probe(&flashctx, flashprog, chip_name));
+ printf("... flashrom_flash_probe for programmer=%s successful\n", prog->name);
+
+ flashrom_flash_release(flashctx); /* cleanup */
+}
+
+static void run_lifecycle(void **state, const struct io_mock *io, const struct programmer_entry *prog,
+ const char *param, const char *const chip_name,
+ void (*action)(const struct programmer_entry *prog,
+ struct flashrom_programmer *flashprog,
+ const char *const chip_name))
+{
+ (void) state; /* unused */
+
+ io_mock_register(io);
+
+ struct flashrom_programmer *flashprog;
+
+ printf("Testing flashrom_programmer_init for programmer=%s ...\n", prog->name);
+ assert_int_equal(0, flashrom_programmer_init(&flashprog, prog->name, param));
+ printf("... flashrom_programmer_init for programmer=%s successful\n", prog->name);
+
+ if (action)
+ action(prog, flashprog, chip_name);
+
+ printf("Testing flashrom_programmer_shutdown for programmer=%s ...\n", prog->name);
+ assert_int_equal(0, flashrom_programmer_shutdown(flashprog));
+ printf("... flashrom_programmer_shutdown for programmer=%s successful\n", prog->name);
+
+ io_mock_register(NULL);
+}
+
+void run_basic_lifecycle(void **state, const struct io_mock *io,
+ const struct programmer_entry *prog, const char *param)
+{
+ /* Basic lifecycle only does init and shutdown,
+ * so neither chip name nor action is needed. */
+ run_lifecycle(state, io, prog, param, NULL /* chip_name */, NULL /* action */);
+}
+
+void run_probe_lifecycle(void **state, const struct io_mock *io,
+ const struct programmer_entry *prog, const char *param, const char *const chip_name)
+{
+ /* Each probe lifecycle should run independently, without cache. */
+ clear_spi_id_cache();
+ run_lifecycle(state, io, prog, param, chip_name, &probe_chip);
+}
+
+void run_init_error_path(void **state, const struct io_mock *io, const struct programmer_entry *prog,
+ const char *param, const int error_code)
+{
+ (void) state; /* unused */
+
+ io_mock_register(io);
+
+ struct flashrom_programmer *flashprog;
+
+ printf("Testing init error path for programmer=%s with params: %s ...\n", prog->name, param);
+ assert_int_equal(error_code, flashrom_programmer_init(&flashprog, prog->name, param));
+ printf("... init failed with error code %i as expected\n", error_code);
+
+ /*
+ * `flashrom_programmer_shutdown` runs only registered shutdown functions, which means
+ * if nothing has been registered then nothing runs.
+ * Since this is testing error path on initialisation and error can happen at different
+ * phases of init, we don't know whether shutdown function has already been registered
+ * or not yet. Running `flashrom_programmer_shutdown` covers both situations.
+ */
+ printf("Running programmer shutdown in case anything got registered...\n");
+ assert_int_equal(0, flashrom_programmer_shutdown(flashprog));
+ printf("... completed\n");
+
+ io_mock_register(NULL);
+}
diff --git a/tests/lifecycle.h b/tests/lifecycle.h
new file mode 100644
index 000000000..b4c2fbedd
--- /dev/null
+++ b/tests/lifecycle.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 __LIFECYCLE_H__
+#define __LIFECYCLE_H__
+
+#include <include/test.h>
+#include <string.h>
+#if defined(__linux__) && !defined(__ANDROID__)
+#include <linux/spi/spidev.h>
+#endif
+
+#include "tests.h"
+#include "libflashrom.h"
+#include "io_mock.h"
+#include "programmer.h"
+#include "spi.h"
+
+void run_basic_lifecycle(void **state, const struct io_mock *io,
+ const struct programmer_entry *prog, const char *param);
+
+void run_probe_lifecycle(void **state, const struct io_mock *io,
+ const struct programmer_entry *prog, const char *param, const char *const chip_name);
+
+void run_init_error_path(void **state, const struct io_mock *io,
+ const struct programmer_entry *prog, const char *param, const int error_code);
+#endif /* __LIFECYCLE_H__ */
diff --git a/tests/linux_mtd.c b/tests/linux_mtd.c
new file mode 100644
index 000000000..3aaa5abda
--- /dev/null
+++ b/tests/linux_mtd.c
@@ -0,0 +1,94 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_LINUX_MTD == 1
+struct linux_mtd_io_state {
+ char *fopen_path;
+};
+
+static FILE *linux_mtd_fopen(void *state, const char *pathname, const char *mode)
+{
+ struct linux_mtd_io_state *io_state = state;
+
+ io_state->fopen_path = strdup(pathname);
+
+ return not_null();
+}
+
+static size_t linux_mtd_fread(void *state, void *buf, size_t size, size_t len, FILE *fp)
+{
+ struct linux_mtd_fread_mock_entry {
+ const char *path;
+ const char *data;
+ };
+ const struct linux_mtd_fread_mock_entry fread_mock_map[] = {
+ { "/sys/class/mtd/mtd0//type", "nor" },
+ { "/sys/class/mtd/mtd0//name", "Device" },
+ { "/sys/class/mtd/mtd0//flags", "" },
+ { "/sys/class/mtd/mtd0//size", "1024" },
+ { "/sys/class/mtd/mtd0//erasesize", "512" },
+ { "/sys/class/mtd/mtd0//numeraseregions", "0" },
+ };
+
+ struct linux_mtd_io_state *io_state = state;
+ unsigned int i;
+
+ if (!io_state->fopen_path)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(fread_mock_map); i++) {
+ const struct linux_mtd_fread_mock_entry *entry = &fread_mock_map[i];
+
+ if (!strcmp(io_state->fopen_path, entry->path)) {
+ size_t data_len = min(size * len, strlen(entry->data));
+ memcpy(buf, entry->data, data_len);
+ return data_len;
+ }
+ }
+
+ return 0;
+}
+
+static int linux_mtd_fclose(void *state, FILE *fp)
+{
+ struct linux_mtd_io_state *io_state = state;
+
+ free(io_state->fopen_path);
+
+ return 0;
+}
+
+void linux_mtd_probe_lifecycle_test_success(void **state)
+{
+ struct linux_mtd_io_state linux_mtd_io_state = { NULL };
+ struct io_mock_fallback_open_state linux_mtd_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock linux_mtd_io = {
+ .state = &linux_mtd_io_state,
+ .iom_fopen = linux_mtd_fopen,
+ .iom_fread = linux_mtd_fread,
+ .iom_fclose = linux_mtd_fclose,
+ .fallback_open_state = &linux_mtd_fallback_open_state,
+ };
+
+ run_probe_lifecycle(state, &linux_mtd_io, &programmer_linux_mtd, "", "Opaque flash chip");
+}
+#else
+ SKIP_TEST(linux_mtd_probe_lifecycle_test_success)
+#endif /* CONFIG_LINUX_MTD */
diff --git a/tests/linux_spi.c b/tests/linux_spi.c
new file mode 100644
index 000000000..1b653fefd
--- /dev/null
+++ b/tests/linux_spi.c
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_LINUX_SPI == 1
+static int linux_spi_ioctl(void *state, int fd, unsigned long request, va_list args) {
+
+ if (request == SPI_IOC_MESSAGE(2)) { /* ioctl code for read request */
+ struct spi_ioc_transfer* msg = va_arg(args, struct spi_ioc_transfer*);
+
+ /* First message has write array and write count */
+ unsigned int writecnt = msg[0].len;
+ unsigned char *writearr = (unsigned char *)(uintptr_t)msg[0].tx_buf;
+ /* Second message has read array and read count */
+ unsigned int readcnt = msg[1].len;
+
+ /* Detect probing */
+ if (writecnt == 1 && writearr[0] == JEDEC_RDID && readcnt == 3) {
+ /* We need to populate read array. */
+ unsigned char *readarr = (unsigned char *)(uintptr_t)msg[1].rx_buf;
+ readarr[0] = 0xEF; /* WINBOND_NEX_ID */
+ readarr[1] = 0x40; /* WINBOND_NEX_W25Q128_V left byte */
+ readarr[2] = 0x18; /* WINBOND_NEX_W25Q128_V right byte */
+ }
+ }
+
+ return 0;
+}
+
+static char *linux_spi_fgets(void *state, char *buf, int len, FILE *fp)
+{
+ /* Emulate reading max buffer size from sysfs. */
+ const char *max_buf_size = "1048576";
+
+ return memcpy(buf, max_buf_size, min(len, strlen(max_buf_size) + 1));
+}
+
+void linux_spi_probe_lifecycle_test_success(void **state)
+{
+ /*
+ * Current implementation tests a particular path of the init procedure.
+ * Specifically, it is reading the buffer size from sysfs.
+ */
+ struct io_mock_fallback_open_state linux_spi_fallback_open_state = {
+ .noc = 0,
+ .paths = { "/dev/null", NULL },
+ .flags = { O_RDWR },
+ };
+ const struct io_mock linux_spi_io = {
+ .iom_fgets = linux_spi_fgets,
+ .iom_ioctl = linux_spi_ioctl,
+ .fallback_open_state = &linux_spi_fallback_open_state,
+ };
+
+ run_probe_lifecycle(state, &linux_spi_io, &programmer_linux_spi, "dev=/dev/null", "W25Q128.V");
+}
+#else
+ SKIP_TEST(linux_spi_probe_lifecycle_test_success)
+#endif /* CONFIG_LINUX_SPI */
diff --git a/tests/mediatek_i2c_spi.c b/tests/mediatek_i2c_spi.c
new file mode 100644
index 000000000..d2780bc96
--- /dev/null
+++ b/tests/mediatek_i2c_spi.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2022 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_MEDIATEK_I2C_SPI == 1
+
+void mediatek_i2c_spi_basic_lifecycle_test_success(void **state)
+{
+ struct io_mock_fallback_open_state mediatek_i2c_spi_fallback_open_state = {
+ .noc = 0,
+ .paths = { "/dev/i2c-254", NULL },
+ .flags = { O_RDWR },
+ };
+ const struct io_mock mediatek_i2c_spi_io = {
+ .fallback_open_state = &mediatek_i2c_spi_fallback_open_state,
+ };
+
+ run_basic_lifecycle(state, &mediatek_i2c_spi_io, &programmer_mediatek_i2c_spi, "bus=254,allow_brick=yes");
+}
+
+void mediatek_i2c_no_allow_brick_test_success(void **state)
+{
+ struct io_mock_fallback_open_state mediatek_i2c_spi_fallback_open_state = {
+ .noc = 0,
+ .paths = { "/dev/i2c-254", NULL },
+ .flags = { O_RDWR },
+ };
+ const struct io_mock mediatek_i2c_spi_io = {
+ .fallback_open_state = &mediatek_i2c_spi_fallback_open_state,
+ };
+
+ run_init_error_path(state, &mediatek_i2c_spi_io, &programmer_mediatek_i2c_spi,
+ "bus=254", SPI_GENERIC_ERROR);
+}
+
+#else
+ SKIP_TEST(mediatek_i2c_spi_basic_lifecycle_test_success)
+ SKIP_TEST(mediatek_i2c_no_allow_brick_test_success)
+#endif /* CONFIG_MEDIATEK_I2C_SPI */
diff --git a/tests/meson.build b/tests/meson.build
index f0cb76dd8..94f60e270 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -11,35 +11,124 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-root_includes = include_directories('../subprojects')
-
-srcs = [
+test_srcs = files(
+ 'io_mock.c',
'tests.c',
+ 'libusb_wraps.c',
'helpers.c',
'flashrom.c',
'spi25.c',
-]
+ 'lifecycle.c',
+ 'layout.c',
+ 'chip.c',
+ 'chip_wp.c',
+ 'selfcheck.c',
+ 'io_real.c',
+)
+
+if not programmer.get('dummy').get('active')
+ test_srcs += programmer.get('dummy').get('srcs')
+endif
+
+foreach p_name, p_data : programmer
+ test_srcs += p_data.get('test_srcs')
+endforeach
mocks = [
+ '-Wl,--wrap=strdup',
'-Wl,--wrap=physunmap',
'-Wl,--wrap=physmap',
+ '-Wl,--wrap=pcidev_init',
+ '-Wl,--wrap=pcidev_readbar',
'-Wl,--wrap=spi_send_command',
+ '-Wl,--wrap=sio_write',
+ '-Wl,--wrap=sio_read',
+ '-Wl,--wrap=open',
+ '-Wl,--wrap=open64',
+ '-Wl,--wrap=__open64_2',
+ '-Wl,--wrap=ioctl',
+ '-Wl,--wrap=read',
+ '-Wl,--wrap=write',
+ '-Wl,--wrap=fopen',
+ '-Wl,--wrap=fopen64',
+ '-Wl,--wrap=fdopen',
+ '-Wl,--wrap=fwrite',
+ '-Wl,--wrap=fflush',
+ '-Wl,--wrap=stat',
+ '-Wl,--wrap=stat64',
+ '-Wl,--wrap=__xstat',
+ '-Wl,--wrap=__xstat64',
+ '-Wl,--wrap=fstat',
+ '-Wl,--wrap=fstat64',
+ '-Wl,--wrap=__fstat50',
+ '-Wl,--wrap=__fxstat',
+ '-Wl,--wrap=__fxstat64',
+ '-Wl,--wrap=fileno',
+ '-Wl,--wrap=fsync',
+ '-Wl,--wrap=fread',
+ '-Wl,--wrap=fgets',
+ '-Wl,--wrap=fprintf',
+ '-Wl,--wrap=fclose',
+ '-Wl,--wrap=feof',
+ '-Wl,--wrap=ferror',
+ '-Wl,--wrap=clearerr',
+ '-Wl,--wrap=setvbuf',
+ '-Wl,--wrap=rget_io_perms',
+ '-Wl,--wrap=OUTB',
+ '-Wl,--wrap=INB',
+ '-Wl,--wrap=OUTW',
+ '-Wl,--wrap=INW',
+ '-Wl,--wrap=OUTL',
+ '-Wl,--wrap=INL',
+ '-Wl,--wrap=usb_dev_get_by_vid_pid_number',
+ '-Wl,--wrap=libusb_init',
+ '-Wl,--wrap=libusb_set_debug',
+ '-Wl,--wrap=libusb_set_option',
+ '-Wl,--wrap=libusb_open',
+ '-Wl,--wrap=libusb_set_auto_detach_kernel_driver',
+ '-Wl,--wrap=libusb_detach_kernel_driver',
+ '-Wl,--wrap=libusb_attach_kernel_driver',
+ '-Wl,--wrap=libusb_open_device_with_vid_pid',
+ '-Wl,--wrap=libusb_get_device',
+ '-Wl,--wrap=libusb_get_device_list',
+ '-Wl,--wrap=libusb_free_device_list',
+ '-Wl,--wrap=libusb_get_bus_number',
+ '-Wl,--wrap=libusb_get_device_address',
+ '-Wl,--wrap=libusb_get_device_descriptor',
+ '-Wl,--wrap=libusb_get_config_descriptor',
+ '-Wl,--wrap=libusb_free_config_descriptor',
+ '-Wl,--wrap=libusb_get_configuration',
+ '-Wl,--wrap=libusb_set_configuration',
+ '-Wl,--wrap=libusb_claim_interface',
+ '-Wl,--wrap=libusb_control_transfer',
+ '-Wl,--wrap=libusb_release_interface',
+ '-Wl,--wrap=libusb_ref_device',
+ '-Wl,--wrap=libusb_unref_device',
+ '-Wl,--wrap=libusb_close',
+ '-Wl,--wrap=libusb_alloc_transfer',
+ '-Wl,--wrap=libusb_submit_transfer',
+ '-Wl,--wrap=libusb_free_transfer',
+ '-Wl,--wrap=libusb_handle_events_timeout',
+ '-Wl,--wrap=libusb_exit',
'-Wl,--gc-sections',
]
+threads_dep = dependency('threads')
+
flashrom_tests = executable('flashrom_unit_tests',
- srcs,
- include_directories : root_includes,
+ test_srcs,
c_args : [
cargs,
'-ffunction-sections',
'-fdata-sections',
- # '-DSTANDALONE',
- '-DCONFIG_DEFAULT_PROGRAMMER=PROGRAMMER_DUMMY',
- '-DCONFIG_DEFAULT_PROGRAMMER_ARGS=""',
+ '-U_FORTIFY_SOURCE',
],
export_dynamic : true,
- link_args : mocks,
- dependencies : [cmocka_dep, flashrom_test_dep],
+ link_args : mocks + link_args,
+ dependencies : [cmocka_dep, flashrom_test_dep, threads_dep],
)
test('cmocka test flashrom', flashrom_tests)
+
+if get_option('llvm_cov').enabled()
+ run_target('llvm-cov-tests', command : ['../scripts/llvm-cov', flashrom_tests])
+endif
diff --git a/tests/nicrealtek.c b/tests/nicrealtek.c
new file mode 100644
index 000000000..2a7a9ffe1
--- /dev/null
+++ b/tests/nicrealtek.c
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_NICREALTEK == 1
+void nicrealtek_basic_lifecycle_test_success(void **state)
+{
+ struct io_mock_fallback_open_state nicrealtek_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock nicrealtek_io = {
+ .fallback_open_state = &nicrealtek_fallback_open_state,
+ };
+
+ run_basic_lifecycle(state, &nicrealtek_io, &programmer_nicrealtek, "");
+}
+#else
+ SKIP_TEST(nicrealtek_basic_lifecycle_test_success)
+#endif /* CONFIG_NICREALTEK */
diff --git a/tests/parade_lspcon.c b/tests/parade_lspcon.c
new file mode 100644
index 000000000..980e1280d
--- /dev/null
+++ b/tests/parade_lspcon.c
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2022 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_PARADE_LSPCON == 1
+
+/* Same macros as in parade_lspcon.c programmer. */
+/* FIXME(aklm): should driver register maps be defined in `include/drivers/` for sharing with tests? */
+#define REGISTER_ADDRESS 0x4a
+#define SPISTATUS 0x9e
+#define SPISTATUS_SECTOR_ERASE_FINISHED 0
+#define SWSPICTL 0x93
+#define SWSPICTL_ENABLE_READBACK 0x8
+#define SWSPI_RDATA 0x91
+/* Macros for test run. */
+#define DATA_TO_READ 0
+#define MAX_REG_BUF_LEN 2
+
+struct parade_lspcon_io_state {
+ unsigned long addr; /* Address to read and write */
+ uint8_t reg_buf[MAX_REG_BUF_LEN]; /* Last value written to the register address */
+};
+
+static int parade_lspcon_ioctl(void *state, int fd, unsigned long request, va_list args)
+{
+ struct parade_lspcon_io_state *io_state = state;
+ if (request == I2C_SLAVE)
+ /* Addr is the next (and the only) argument in the parameters list for this ioctl call. */
+ io_state->addr = va_arg(args, unsigned long);
+
+ return 0;
+}
+
+static int parade_lspcon_read(void *state, int fd, void *buf, size_t sz)
+{
+ struct parade_lspcon_io_state *io_state = state;
+
+ /*
+ * Parade_lspcon programmer has operations over register address and
+ * page address. In the current emulation for basic lifecycle we need
+ * to emulate operations over register address. Page address can do
+ * nothing for now, and just return successful return value.
+ *
+ * For future, if this unit test is upgraded to run probing lifecycle,
+ * page address operations might need to be fully emulated.
+ */
+ if (io_state->addr != REGISTER_ADDRESS)
+ return sz;
+
+ assert_int_equal(sz, 1);
+
+ switch (io_state->reg_buf[0]) {
+ case SPISTATUS:
+ memset(buf, SPISTATUS_SECTOR_ERASE_FINISHED, sz);
+ break;
+ case SWSPICTL:
+ memset(buf, SWSPICTL_ENABLE_READBACK, sz);
+ break;
+ case SWSPI_RDATA:
+ memset(buf, DATA_TO_READ, sz);
+ break;
+ default:
+ memset(buf, 0, sz);
+ break;
+ }
+
+ return sz;
+}
+
+static int parade_lspcon_write(void *state, int fd, const void *buf, size_t sz)
+{
+ struct parade_lspcon_io_state *io_state = state;
+
+ /*
+ * Only register address operations are needed to be emulated for basic lifecycle.
+ * See also comment in `parade_lspcon_read`.
+ */
+ if (io_state->addr != REGISTER_ADDRESS)
+ return sz;
+
+ assert_true(sz <= MAX_REG_BUF_LEN);
+
+ memcpy(io_state->reg_buf, buf, sz);
+
+ return sz;
+}
+
+void parade_lspcon_basic_lifecycle_test_success(void **state)
+{
+ struct parade_lspcon_io_state parade_lspcon_io_state = { 0 };
+ struct io_mock_fallback_open_state parade_lspcon_fallback_open_state = {
+ .noc = 0,
+ .paths = { "/dev/i2c-254", NULL },
+ .flags = { O_RDWR },
+ };
+ const struct io_mock parade_lspcon_io = {
+ .state = &parade_lspcon_io_state,
+ .iom_ioctl = parade_lspcon_ioctl,
+ .iom_read = parade_lspcon_read,
+ .iom_write = parade_lspcon_write,
+ .fallback_open_state = &parade_lspcon_fallback_open_state,
+ };
+
+ run_basic_lifecycle(state, &parade_lspcon_io, &programmer_parade_lspcon, "bus=254,allow_brick=yes");
+}
+
+void parade_lspcon_no_allow_brick_test_success(void **state)
+{
+ struct io_mock_fallback_open_state parade_lspcon_fallback_open_state = {
+ .noc = 0,
+ .paths = { "/dev/i2c-254", NULL },
+ .flags = { O_RDWR },
+ };
+ const struct io_mock parade_lspcon_io = {
+ .fallback_open_state = &parade_lspcon_fallback_open_state,
+ };
+
+ run_init_error_path(state, &parade_lspcon_io, &programmer_parade_lspcon,
+ "bus=254", SPI_GENERIC_ERROR);
+}
+
+#else
+ SKIP_TEST(parade_lspcon_basic_lifecycle_test_success)
+ SKIP_TEST(parade_lspcon_no_allow_brick_test_success)
+#endif /* CONFIG_PARADE_LSPCON */
diff --git a/tests/raiden_debug_spi.c b/tests/raiden_debug_spi.c
new file mode 100644
index 000000000..5c79a9095
--- /dev/null
+++ b/tests/raiden_debug_spi.c
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_RAIDEN_DEBUG_SPI == 1
+static ssize_t raiden_debug_libusb_get_device_list(void *state, libusb_context *ctx, libusb_device ***list)
+{
+ *list = calloc(1, sizeof(**list));
+ assert_non_null(*list);
+
+ /*
+ * libusb_device is opaque type, it is tossed around between libusb functions but always
+ * stays opaque to the caller.
+ * Given that all libusb functions are mocked in tests, and raiden_debug test is mocking
+ * only one device, we don't need to initialise libusb_device.
+ */
+ return 1;
+}
+
+static void raiden_debug_libusb_free_device_list(void *state, libusb_device **list, int unref_devices)
+{
+ free(list);
+}
+
+static int raiden_debug_libusb_get_device_descriptor(
+ void *state, libusb_device *dev, struct libusb_device_descriptor *desc)
+{
+ desc->idVendor = 0x18D1; /* GOOGLE_VID */
+ desc->idProduct = 0;
+ desc->bNumConfigurations = 1;
+
+ return 0;
+}
+
+static int raiden_debug_libusb_get_config_descriptor(
+ void *state, libusb_device *dev, uint8_t config_index, struct libusb_config_descriptor **config)
+{
+ *config = calloc(1, sizeof(**config));
+ assert_non_null(*config);
+
+ struct libusb_endpoint_descriptor *tmp_endpoint = calloc(2, sizeof(*tmp_endpoint));
+ assert_non_null(tmp_endpoint);
+ struct libusb_interface_descriptor *tmp_interface_desc = calloc(1, sizeof(*tmp_interface_desc));
+ assert_non_null(tmp_interface_desc);
+ struct libusb_interface *tmp_interface = calloc(1, sizeof(*tmp_interface));
+ assert_non_null(tmp_interface);
+
+ /* in endpoint */
+ tmp_endpoint[0].bEndpointAddress = 0x80;
+ tmp_endpoint[0].bmAttributes = 0x2;
+ /* out endpoint */
+ tmp_endpoint[1].bEndpointAddress = 0x0;
+ tmp_endpoint[1].bmAttributes = 0x2;
+
+ tmp_interface_desc->bInterfaceClass = 0xff; /* LIBUSB_CLASS_VENDOR_SPEC */
+ tmp_interface_desc->bInterfaceSubClass = 0x51; /* GOOGLE_RAIDEN_SPI_SUBCLASS */
+ tmp_interface_desc->bInterfaceProtocol = 0x01; /* GOOGLE_RAIDEN_SPI_PROTOCOL_V1 */
+ tmp_interface_desc->bNumEndpoints = 2; /* in_endpoint and out_endpoint */
+ tmp_interface_desc->endpoint = tmp_endpoint;
+
+ tmp_interface->num_altsetting = 1;
+ tmp_interface->altsetting = tmp_interface_desc;
+
+ (*config)->bConfigurationValue = 0;
+ (*config)->bNumInterfaces = 1;
+ (*config)->interface = tmp_interface;
+
+ return 0;
+}
+
+static void raiden_debug_libusb_free_config_descriptor(void *state, struct libusb_config_descriptor *config)
+{
+ free((void *)config->interface->altsetting->endpoint);
+ free((void *)config->interface->altsetting);
+ free((void *)config->interface);
+ free(config);
+}
+
+void raiden_debug_basic_lifecycle_test_success(void **state)
+{
+ struct io_mock_fallback_open_state raiden_debug_fallback_open_state = {
+ .noc = 0,
+ .paths = { NULL },
+ };
+ const struct io_mock raiden_debug_io = {
+ .libusb_get_device_list = raiden_debug_libusb_get_device_list,
+ .libusb_free_device_list = raiden_debug_libusb_free_device_list,
+ .libusb_get_device_descriptor = raiden_debug_libusb_get_device_descriptor,
+ .libusb_get_config_descriptor = raiden_debug_libusb_get_config_descriptor,
+ .libusb_free_config_descriptor = raiden_debug_libusb_free_config_descriptor,
+ .fallback_open_state = &raiden_debug_fallback_open_state,
+ };
+
+ /*
+ * 12 is the length of programmer param string for 3-digit address.
+ * Address can be max 3-digit because it needs to fit into uint8_t.
+ */
+ char raiden_debug_param[12];
+ snprintf(raiden_debug_param, 12, "address=%d", USB_DEVICE_ADDRESS);
+
+ run_basic_lifecycle(state, &raiden_debug_io, &programmer_raiden_debug_spi, raiden_debug_param);
+}
+#else
+ SKIP_TEST(raiden_debug_basic_lifecycle_test_success)
+#endif /* CONFIG_RAIDEN_DEBUG_SPI */
diff --git a/tests/realtek_mst_i2c_spi.c b/tests/realtek_mst_i2c_spi.c
new file mode 100644
index 000000000..753f06b91
--- /dev/null
+++ b/tests/realtek_mst_i2c_spi.c
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "lifecycle.h"
+
+#if CONFIG_REALTEK_MST_I2C_SPI == 1
+static int realtek_mst_ioctl(void *state, int fd, unsigned long request, va_list args)
+{
+ assert_int_equal(fd, MOCK_FD);
+ assert_int_equal(request, I2C_SLAVE);
+ /* Only access to I2C address 0x4a is expected */
+ unsigned long addr = va_arg(args, unsigned long);
+ assert_int_equal(addr, 0x4a);
+
+ return 0;
+}
+
+static int realtek_mst_read(void *state, int fd, void *buf, size_t sz)
+{
+ assert_int_equal(fd, MOCK_FD);
+ assert_int_equal(sz, 1);
+ return sz;
+}
+
+static int realtek_mst_write(void *state, int fd, const void *buf, size_t sz)
+{
+ assert_int_equal(fd, MOCK_FD);
+ const LargestIntegralType accepted_sizes[] = {1, 2};
+ assert_in_set(sz, accepted_sizes, ARRAY_SIZE(accepted_sizes));
+ return sz;
+}
+
+void realtek_mst_basic_lifecycle_test_success(void **state)
+{
+ struct io_mock_fallback_open_state realtek_mst_fallback_open_state = {
+ .noc = 0,
+ .paths = { "/dev/i2c-254", NULL },
+ .flags = { O_RDWR },
+ };
+ const struct io_mock realtek_mst_io = {
+ .iom_ioctl = realtek_mst_ioctl,
+ .iom_read = realtek_mst_read,
+ .iom_write = realtek_mst_write,
+ .fallback_open_state = &realtek_mst_fallback_open_state,
+ };
+
+ run_basic_lifecycle(state, &realtek_mst_io, &programmer_realtek_mst_i2c_spi, "bus=254,enter_isp=0,allow_brick=yes");
+}
+
+void realtek_mst_no_allow_brick_test_success(void **state)
+{
+ struct io_mock_fallback_open_state realtek_mst_fallback_open_state = {
+ .noc = 0,
+ .paths = { "/dev/i2c-254", NULL },
+ .flags = { O_RDWR },
+ };
+ const struct io_mock realtek_mst_io = {
+ .fallback_open_state = &realtek_mst_fallback_open_state,
+ };
+
+ run_init_error_path(state, &realtek_mst_io, &programmer_realtek_mst_i2c_spi,
+ "bus=254,enter_isp=0", SPI_GENERIC_ERROR);
+}
+#else
+ SKIP_TEST(realtek_mst_basic_lifecycle_test_success)
+ SKIP_TEST(realtek_mst_no_allow_brick_test_success)
+#endif /* CONFIG_REALTEK_MST_I2C_SPI */
diff --git a/tests/selfcheck.c b/tests/selfcheck.c
new file mode 100644
index 000000000..e235d8ef0
--- /dev/null
+++ b/tests/selfcheck.c
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2022 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 "flash.h"
+#include "string.h"
+
+#include "include/test.h"
+#include "programmer.h"
+#include "tests.h"
+#include <cmocka.h>
+
+
+#define assert_table(assertion, message, index, name) \
+ do { \
+ if (!(assertion)) \
+ fail_msg(message " for index:%zu name:%s", (index), (name) ? (name) : "unknown"); \
+ } while (0)
+
+
+void selfcheck_programmer_table(void **state)
+{
+ (void)state; /* unused */
+
+ size_t i;
+ for (i = 0; i < programmer_table_size; i++) {
+ const struct programmer_entry *const p = programmer_table[i];
+ assert_table(p, "programmer entry is null", i, "unknown");
+ assert_table(p->name, "programmer name is null", i, p->name);
+ bool type_good = false;
+ switch (p->type) {
+ case PCI:
+ case USB:
+ case OTHER:
+ type_good = true;
+ }
+ assert_table(type_good, "programmer type is invalid", i, p->name);
+ /* internal has its device list stored separately. */
+ if (strcmp("internal", p->name) != 0)
+ assert_table(p->devs.note, "programmer devs.note is null", i, p->name);
+ assert_table(p->init, "programmer init is null", i, p->name);
+ }
+}
+
+void selfcheck_flashchips_table(void **state)
+{
+ (void)state; /* unused */
+
+ size_t i;
+ assert_true(flashchips_size > 1);
+ assert_true(flashchips[flashchips_size - 1].name == NULL);
+ for (i = 0; i < flashchips_size - 1; i++) {
+ const struct flashchip *chip = &flashchips[i];
+ assert_table(chip->vendor, "chip vendor is null", i, chip->name);
+ assert_table(chip->name, "chip name is null", i, chip->name);
+ assert_table(chip->bustype != BUS_NONE, "chip bustype is BUS_NONE", i, chip->name);
+ }
+}
+
+void selfcheck_eraseblocks(void **state)
+{
+ (void)state; /* unused */
+
+ size_t chip_index;
+ for (chip_index = 0; chip_index < flashchips_size - 1; chip_index++) {
+ size_t i, j, k;
+ const struct flashchip *chip = &flashchips[chip_index];
+ unsigned int prev_eraseblock_count = chip->total_size * 1024;
+
+ for (k = 0; k < NUM_ERASEFUNCTIONS; k++) {
+ unsigned int done = 0;
+ struct block_eraser eraser = chip->block_erasers[k];
+ unsigned int curr_eraseblock_count = 0;
+
+ for (i = 0; i < NUM_ERASEREGIONS; i++) {
+ /* Blocks with zero size are bugs in flashchips.c. */
+ if (eraser.eraseblocks[i].count && !eraser.eraseblocks[i].size) {
+ fail_msg("Flash chip %s erase function %zu region %zu has size 0",
+ chip->name, k, i);
+ }
+ /* Blocks with zero count are bugs in flashchips.c. */
+ if (!eraser.eraseblocks[i].count && eraser.eraseblocks[i].size) {
+ fail_msg("Flash chip %s erase function %zu region %zu has count 0",
+ chip->name, k, i);
+ }
+ done += eraser.eraseblocks[i].count * eraser.eraseblocks[i].size;
+ curr_eraseblock_count += eraser.eraseblocks[i].count;
+ }
+ /* Empty eraseblock definition with erase function. */
+ if (!done && eraser.block_erase) {
+ printf("Strange: Empty eraseblock definition with non-empty erase function chip %s function %zu. Not an error.\n",
+ chip->name, k);
+ }
+
+ if (!done)
+ continue;
+ if (done != chip->total_size * 1024) {
+ fail_msg(
+ "Flash chip %s erase function %zu region walking resulted in 0x%06x bytes total, expected 0x%06x bytes.",
+ chip->name, k, done, chip->total_size * 1024);
+ assert_true(false);
+ }
+
+ if (!eraser.block_erase)
+ continue;
+ /* Check if there are identical erase functions for different
+ * layouts. That would imply "magic" erase functions. The
+ * easiest way to check this is with function pointers.
+ */
+ for (j = k + 1; j < NUM_ERASEFUNCTIONS; j++) {
+ if (eraser.block_erase == chip->block_erasers[j].block_erase) {
+ fail_msg("Flash chip %s erase function %zu and %zu are identical.",
+ chip->name, k, j);
+ }
+ }
+ if (curr_eraseblock_count > prev_eraseblock_count) {
+ fail_msg("Flash chip %s erase function %zu is not in order", chip->name, k);
+ }
+ prev_eraseblock_count = curr_eraseblock_count;
+ }
+ }
+}
+
+#if CONFIG_INTERNAL == 1
+void selfcheck_board_matches_table(void **state)
+{
+ (void)state; /* unused */
+
+ size_t i;
+
+ assert_true(board_matches_size > 0);
+ assert_true(board_matches[board_matches_size - 1].vendor_name == NULL);
+ for (i = 0; i < board_matches_size - 1; i++) {
+ const struct board_match *b = &board_matches[i];
+ assert_table(b->vendor_name, "board vendor_name is null", i, b->board_name);
+ assert_table(b->board_name, "board boad_name is null", i, b->board_name);
+ if ((!b->first_vendor || !b->first_device || !b->second_vendor || !b->second_device)
+ || ((!b->lb_vendor) ^ (!b->lb_part)) || (!b->max_rom_decode_parallel && !b->enable))
+ fail_msg("Board enable for %s %s is misdefined.\n", b->vendor_name, b->board_name);
+ }
+}
+
+#else
+ SKIP_TEST(selfcheck_board_matches_table)
+#endif /* CONFIG_INTERNAL */
diff --git a/tests/spi25.c b/tests/spi25.c
index 942fe6e57..872959341 100644
--- a/tests/spi25.c
+++ b/tests/spi25.c
@@ -15,15 +15,46 @@
#include <include/test.h>
+#include "wraps.h"
+#include "tests.h"
#include "programmer.h"
#include "flashchips.h"
#include "chipdrivers.h"
#include "spi.h"
+struct flashchip mock_chip = {
+ .vendor = "Generic",
+ .name = "unknown SPI chip (RDID)",
+ .bustype = BUS_SPI,
+ .manufacture_id = GENERIC_MANUF_ID,
+ .model_id = GENERIC_DEVICE_ID,
+ .total_size = 0,
+ .page_size = 256,
+ .tested = TEST_BAD_PREW,
+ .probe = PROBE_SPI_RDID,
+ .write = NO_WRITE_FUNC,
+};
+
+/*
+ * This declaration is needed for visibility, so that wrap below could
+ * redirect to real function.
+ */
+int __real_spi_send_command(const struct flashctx *flash,
+ unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr);
+
int __wrap_spi_send_command(const struct flashctx *flash,
unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr)
{
+ if (flash->chip != &mock_chip)
+ /*
+ * Caller is some other test, redirecting to real function.
+ * This test is the only one which uses wrap of spi_send_command,
+ * all other tests use real function.
+ */
+ return __real_spi_send_command(flash, writecnt, readcnt, writearr, readarr);
+
check_expected_ptr(flash);
assert_int_equal(writecnt, mock_type(int));
assert_int_equal(writearr[0], mock_type(int));
@@ -36,18 +67,64 @@ int __wrap_spi_send_command(const struct flashctx *flash,
return 0;
}
-struct flashchip mock_chip = {
- .vendor = "Generic",
- .name = "unknown SPI chip (RDID)",
- .bustype = BUS_SPI,
- .manufacture_id = GENERIC_MANUF_ID,
- .model_id = GENERIC_DEVICE_ID,
- .total_size = 0,
- .page_size = 256,
- .tested = TEST_BAD_PREW,
- .probe = probe_spi_rdid,
- .write = NULL,
-};
+static void spi_read_progress_cb(struct flashrom_flashctx *flashctx)
+{
+ struct flashrom_progress *progress_state = flashctx->progress_state;
+ uint32_t *cnt = (uint32_t *) progress_state->user_data;
+ assert_int_equal(0x300, progress_state->total);
+ switch (*cnt) {
+ case 0:
+ assert_int_equal(0x100, progress_state->current);
+ break;
+ case 1:
+ assert_int_equal(0x200, progress_state->current);
+ break;
+ case 2:
+ assert_int_equal(0x300, progress_state->current);
+ break;
+ case 3:
+ assert_int_equal(0x300, progress_state->current);
+ break;
+ case 4:
+ assert_int_equal(0x300, progress_state->current);
+ break;
+ default:
+ fail();
+ }
+ (*cnt)++;
+}
+
+void spi_read_chunked_test_success(void **state)
+{
+ (void) state; /* unused */
+ uint8_t buf[0x400] = { 0x0 };
+ uint32_t cnt = 0;
+ const unsigned int max_data_read = 0x100;
+ const unsigned int offset = 0x100;
+ struct registered_master mst = {
+ .spi.read = default_spi_read,
+ .spi.max_data_read = max_data_read
+ };
+
+ /* setup initial test state */
+ struct flashctx flashctx = {
+ .chip = &mock_chip,
+ .mst = &mst
+ };
+ struct flashrom_progress progress_state = {
+ .user_data = (void *) &cnt,
+ };
+ flashrom_set_progress_callback(&flashctx, spi_read_progress_cb, &progress_state);
+ for (int i = 0; i < 4; i++) {
+ expect_memory(__wrap_spi_send_command, flash,
+ &flashctx, sizeof(flashctx));
+ will_return(__wrap_spi_send_command, JEDEC_WRDI);
+ will_return(__wrap_spi_send_command, JEDEC_READ);
+ will_return(__wrap_spi_send_command, max_data_read);
+ }
+ assert_int_equal(0, spi_chip_read(&flashctx, buf, offset, sizeof(buf)));
+ assert_int_equal(5, cnt);
+}
void spi_write_enable_test_success(void **state)
{
diff --git a/tests/tests.c b/tests/tests.c
index 312460743..8b4ad037d 100644
--- a/tests/tests.c
+++ b/tests/tests.c
@@ -14,25 +14,404 @@
*/
#include <include/test.h>
+#include "io_mock.h"
#include "tests.h"
+#include "wraps.h"
+#include "io_real.h"
#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <pthread.h>
+
+void *not_null(void)
+{
+ return (void *)MOCK_FD;
+}
+
+/* Workaround for https://github.com/clibs/cmocka/issues/17 */
+char *__wrap_strdup(const char *s)
+{
+ size_t len = strlen(s) + 1;
+ void *new = malloc(len);
+ if (new == NULL)
+ return NULL;
+ return (char *)memcpy(new, s, len);
+}
-/* redefinitions/wrapping */
void __wrap_physunmap(void *virt_addr, size_t len)
{
- fprintf(stderr, "%s\n", __func__);
+ LOG_ME;
}
+
void *__wrap_physmap(const char *descr, uintptr_t phys_addr, size_t len)
{
- fprintf(stderr, "%s\n", __func__);
+ LOG_ME;
return NULL;
}
-int main(void)
+struct pci_dev mock_pci_dev = {
+ .device_id = NON_ZERO,
+};
+
+struct pci_dev *__wrap_pcidev_init(const struct programmer_cfg *cfg, void *devs, int bar)
+{
+ LOG_ME;
+ return &mock_pci_dev;
+}
+
+uintptr_t __wrap_pcidev_readbar(void *dev, int bar)
+{
+ LOG_ME;
+ return NON_ZERO;
+}
+
+void __wrap_sio_write(uint16_t port, uint8_t reg, uint8_t data)
+{
+ LOG_ME;
+}
+
+uint8_t __wrap_sio_read(uint16_t port, uint8_t reg)
+{
+ LOG_ME;
+ return (uint8_t)mock();
+}
+
+static int mock_open(const char *pathname, int flags, mode_t mode)
+{
+ maybe_unmock_io(pathname);
+ if (get_io() && get_io()->iom_open)
+ return get_io()->iom_open(get_io()->state, pathname, flags, mode);
+
+ if (get_io() && get_io()->fallback_open_state) {
+ struct io_mock_fallback_open_state *io_state;
+ unsigned int open_state_flags;
+
+ io_state = get_io()->fallback_open_state;
+ assert_true(io_state->noc < MAX_MOCK_OPEN);
+ assert_non_null(io_state->paths[io_state->noc]);
+ assert_string_equal(pathname, io_state->paths[io_state->noc]);
+ open_state_flags = io_state->flags[io_state->noc];
+ assert_int_equal(flags & open_state_flags, open_state_flags);
+ io_state->noc++; // proceed to the next path upon next call.
+ }
+
+ return MOCK_FD;
+}
+
+int __wrap_open(const char *pathname, int flags, ...)
+{
+ LOG_ME;
+ int mode = 0;
+ if (flags & O_CREAT) {
+ va_list ap;
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+ return mock_open(pathname, flags, (mode_t) mode);
+}
+
+int __wrap_open64(const char *pathname, int flags, ...)
+{
+ LOG_ME;
+ int mode = 0;
+ if (flags & O_CREAT) {
+ va_list ap;
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+ return mock_open(pathname, flags, (mode_t) mode);
+}
+
+int __wrap___open64_2(const char *pathname, int flags, ...)
+{
+ LOG_ME;
+ int mode = 0;
+ if (flags & O_CREAT) {
+ va_list ap;
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+ return mock_open(pathname, flags, (mode_t) mode);
+}
+
+int __wrap_ioctl(int fd, unsigned long int request, ...)
+{
+ LOG_ME;
+ if (get_io() && get_io()->iom_ioctl) {
+ va_list args;
+ int out;
+ va_start(args, request);
+ out = get_io()->iom_ioctl(get_io()->state, fd, request, args);
+ va_end(args);
+ return out;
+ }
+ return 0;
+}
+
+int __wrap_write(int fd, const void *buf, size_t sz)
+{
+ LOG_ME;
+ if (get_io() && get_io()->iom_write)
+ return get_io()->iom_write(get_io()->state, fd, buf, sz);
+ return sz;
+}
+
+int __wrap_read(int fd, void *buf, size_t sz)
+{
+ LOG_ME;
+ if (get_io() && get_io()->iom_read)
+ return get_io()->iom_read(get_io()->state, fd, buf, sz);
+ return sz;
+}
+
+FILE *__wrap_fopen(const char *pathname, const char *mode)
+{
+ LOG_ME;
+ maybe_unmock_io(pathname);
+ if (get_io() && get_io()->iom_fopen)
+ return get_io()->iom_fopen(get_io()->state, pathname, mode);
+ return not_null();
+}
+
+FILE *__wrap_fopen64(const char *pathname, const char *mode)
+{
+ LOG_ME;
+ maybe_unmock_io(pathname);
+ if (get_io() && get_io()->iom_fopen)
+ return get_io()->iom_fopen(get_io()->state, pathname, mode);
+ return not_null();
+}
+
+FILE *__wrap_fdopen(int fd, const char *mode)
+{
+ LOG_ME;
+ if (get_io() && get_io()->iom_fdopen)
+ return get_io()->iom_fdopen(get_io()->state, fd, mode);
+ return not_null();
+}
+
+int __wrap_stat(const char *path, void *buf)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_stat64(const char *path, void *buf)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap___xstat(const char *path, void *buf)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap___xstat64(const char *path, void *buf)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_fstat(int fd, void *buf)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_fstat64(int fd, void *buf)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap___fstat50(int fd, void *buf)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap___fxstat(int fd, void *buf)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap___fxstat64(int fd, void *buf)
+{
+ LOG_ME;
+ return 0;
+}
+
+char *__wrap_fgets(char *buf, int len, FILE *fp)
+{
+ LOG_ME;
+ if (get_io() && get_io()->iom_fgets)
+ return get_io()->iom_fgets(get_io()->state, buf, len, fp);
+ return NULL;
+}
+
+size_t __wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *fp)
+{
+ LOG_ME;
+ if (get_io() && get_io()->iom_fread)
+ return get_io()->iom_fread(get_io()->state, ptr, size, nmemb, fp);
+ return nmemb;
+}
+
+size_t __wrap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp)
+{
+ LOG_ME;
+ if (get_io() && get_io()->iom_fwrite)
+ return get_io()->iom_fwrite(get_io()->state, ptr, size, nmemb, fp);
+ return nmemb;
+}
+
+int __wrap_fflush(FILE *fp)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_fileno(FILE *fp)
+{
+ LOG_ME;
+ return MOCK_FD;
+}
+
+int __wrap_fsync(int fd)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_setvbuf(FILE *fp, char *buf, int type, size_t size)
+{
+ LOG_ME;
+ return 0;
+}
+
+int __wrap_fprintf(FILE *fp, const char *fmt, ...)
+{
+ LOG_ME;
+ if (get_io() && get_io()->iom_fprintf) {
+ va_list args;
+ int out;
+ va_start(args, fmt);
+ out = get_io()->iom_fprintf(get_io()->state, fp, fmt, args);
+ va_end(args);
+ return out;
+ }
+ return 0;
+}
+
+int __wrap_fclose(FILE *fp)
+{
+ LOG_ME;
+ if (get_io() && get_io()->iom_fclose)
+ return get_io()->iom_fclose(get_io()->state, fp);
+ return 0;
+}
+
+int __wrap_feof(FILE *fp)
+{
+ /* LOG_ME; */
+ return 0;
+}
+
+int __wrap_ferror(FILE *fp)
+{
+ /* LOG_ME; */
+ return 0;
+}
+void __wrap_clearerr(FILE *fp)
+{
+ /* LOG_ME; */
+ return;
+}
+
+int __wrap_rget_io_perms(void)
+{
+ LOG_ME;
+ return 0;
+}
+
+void __wrap_OUTB(unsigned char value, unsigned short port)
+{
+ /* LOG_ME; */
+ if (get_io() && get_io()->outb)
+ get_io()->outb(get_io()->state, value, port);
+}
+
+unsigned char __wrap_INB(unsigned short port)
+{
+ /* LOG_ME; */
+ if (get_io() && get_io()->inb)
+ return get_io()->inb(get_io()->state, port);
+ return 0;
+}
+
+void __wrap_OUTW(unsigned short value, unsigned short port)
+{
+ /* LOG_ME; */
+ if (get_io() && get_io()->outw)
+ get_io()->outw(get_io()->state, value, port);
+}
+
+unsigned short __wrap_INW(unsigned short port)
+{
+ /* LOG_ME; */
+ if (get_io() && get_io()->inw)
+ return get_io()->inw(get_io()->state, port);
+ return 0;
+}
+
+void __wrap_OUTL(unsigned int value, unsigned short port)
+{
+ /* LOG_ME; */
+ if (get_io() && get_io()->outl)
+ get_io()->outl(get_io()->state, value, port);
+}
+
+unsigned int __wrap_INL(unsigned short port)
+{
+ /* LOG_ME; */
+ if (get_io() && get_io()->inl)
+ return get_io()->inl(get_io()->state, port);
+ return 0;
+}
+
+static void *doing_nothing(void *vargp) {
+ return NULL;
+}
+
+int main(int argc, char *argv[])
{
int ret = 0;
+ if (argc > 1)
+ cmocka_set_test_filter(argv[1]);
+
+ cmocka_set_message_output(CM_OUTPUT_STDOUT);
+
+ /*
+ * Creating new thread which is doing nothing, to trigger __isthreaded being 1.
+ * This is a workaround for BSD family. In multi-threaded environment fileno
+ * macro is expanded into a function which is possible to mock in unit tests.
+ * Without this workaround, on a single-thread environment, fileno macro is
+ * expanded into an inline access of a private field of a file descriptor,
+ * which is impossible to mock.
+ *
+ * In other OSes this is just creating a thread which is doing nothing.
+ */
+ pthread_t thread_id;
+ pthread_create(&thread_id, NULL, doing_nothing, NULL);
+
const struct CMUnitTest helpers_tests[] = {
cmocka_unit_test(address_to_bits_test_success),
cmocka_unit_test(bitcount_test_success),
@@ -44,6 +423,15 @@ int main(void)
};
ret |= cmocka_run_group_tests_name("helpers.c tests", helpers_tests, NULL, NULL);
+ const struct CMUnitTest selfcheck[] = {
+ cmocka_unit_test(selfcheck_programmer_table),
+ cmocka_unit_test(selfcheck_flashchips_table),
+ cmocka_unit_test(selfcheck_eraseblocks),
+ cmocka_unit_test(selfcheck_board_matches_table),
+ };
+ ret |= cmocka_run_group_tests_name("selfcheck.c tests", selfcheck,
+ NULL, NULL);
+
const struct CMUnitTest flashrom_tests[] = {
cmocka_unit_test(flashbuses_to_text_test_success),
};
@@ -52,6 +440,7 @@ int main(void)
const struct CMUnitTest spi25_tests[] = {
cmocka_unit_test(spi_write_enable_test_success),
cmocka_unit_test(spi_write_disable_test_success),
+ cmocka_unit_test(spi_read_chunked_test_success),
cmocka_unit_test(probe_spi_rdid_test_success),
cmocka_unit_test(probe_spi_rdid4_test_success),
cmocka_unit_test(probe_spi_rems_test_success),
@@ -63,5 +452,64 @@ int main(void)
};
ret |= cmocka_run_group_tests_name("spi25.c tests", spi25_tests, NULL, NULL);
+ const struct CMUnitTest lifecycle_tests[] = {
+ cmocka_unit_test(dummy_basic_lifecycle_test_success),
+ cmocka_unit_test(dummy_probe_lifecycle_test_success),
+ cmocka_unit_test(dummy_probe_variable_size_test_success),
+ cmocka_unit_test(dummy_init_fails_unhandled_param_test_success),
+ cmocka_unit_test(dummy_init_success_invalid_param_test_success),
+ cmocka_unit_test(dummy_init_success_unhandled_param_test_success),
+ cmocka_unit_test(dummy_null_prog_param_test_success),
+ cmocka_unit_test(dummy_all_buses_test_success),
+ cmocka_unit_test(nicrealtek_basic_lifecycle_test_success),
+ cmocka_unit_test(raiden_debug_basic_lifecycle_test_success),
+ cmocka_unit_test(dediprog_basic_lifecycle_test_success),
+ cmocka_unit_test(linux_mtd_probe_lifecycle_test_success),
+ cmocka_unit_test(linux_spi_probe_lifecycle_test_success),
+ cmocka_unit_test(parade_lspcon_basic_lifecycle_test_success),
+ cmocka_unit_test(parade_lspcon_no_allow_brick_test_success),
+ cmocka_unit_test(mediatek_i2c_spi_basic_lifecycle_test_success),
+ cmocka_unit_test(mediatek_i2c_no_allow_brick_test_success),
+ cmocka_unit_test(realtek_mst_basic_lifecycle_test_success),
+ cmocka_unit_test(realtek_mst_no_allow_brick_test_success),
+ cmocka_unit_test(ch341a_spi_basic_lifecycle_test_success),
+ cmocka_unit_test(ch341a_spi_probe_lifecycle_test_success),
+ };
+ ret |= cmocka_run_group_tests_name("lifecycle.c tests", lifecycle_tests, NULL, NULL);
+
+ const struct CMUnitTest layout_tests[] = {
+ cmocka_unit_test(included_regions_dont_overlap_test_success),
+ cmocka_unit_test(included_regions_overlap_test_success),
+ cmocka_unit_test(region_not_included_overlap_test_success),
+ cmocka_unit_test(layout_pass_sanity_checks_test_success),
+ cmocka_unit_test(layout_region_invalid_address_test_success),
+ cmocka_unit_test(layout_region_invalid_range_test_success),
+ };
+ ret |= cmocka_run_group_tests_name("layout.c tests", layout_tests, NULL, NULL);
+
+ const struct CMUnitTest chip_tests[] = {
+ cmocka_unit_test(erase_chip_test_success),
+ cmocka_unit_test(erase_chip_with_dummyflasher_test_success),
+ cmocka_unit_test(read_chip_test_success),
+ cmocka_unit_test(read_chip_with_dummyflasher_test_success),
+ cmocka_unit_test(write_chip_test_success),
+ cmocka_unit_test(write_chip_with_dummyflasher_test_success),
+ cmocka_unit_test(write_nonaligned_region_with_dummyflasher_test_success),
+ cmocka_unit_test(verify_chip_test_success),
+ cmocka_unit_test(verify_chip_with_dummyflasher_test_success),
+ };
+ ret |= cmocka_run_group_tests_name("chip.c tests", chip_tests, NULL, NULL);
+
+ const struct CMUnitTest chip_wp_tests[] = {
+ cmocka_unit_test(invalid_wp_range_dummyflasher_test_success),
+ cmocka_unit_test(set_wp_range_dummyflasher_test_success),
+ cmocka_unit_test(switch_wp_mode_dummyflasher_test_success),
+ cmocka_unit_test(wp_init_from_status_dummyflasher_test_success),
+ cmocka_unit_test(full_chip_erase_with_wp_dummyflasher_test_success),
+ cmocka_unit_test(partial_chip_erase_with_wp_dummyflasher_test_success),
+ cmocka_unit_test(wp_get_register_values_and_masks),
+ };
+ ret |= cmocka_run_group_tests_name("chip_wp.c tests", chip_wp_tests, NULL, NULL);
+
return ret;
}
diff --git a/tests/tests.h b/tests/tests.h
index cb905fd6f..e273e1dbf 100644
--- a/tests/tests.h
+++ b/tests/tests.h
@@ -16,6 +16,8 @@
#ifndef TESTS_H
#define TESTS_H
+#include <fcntl.h>
+
/* helpers.c */
void address_to_bits_test_success(void **state);
void bitcount_test_success(void **state);
@@ -31,6 +33,7 @@ void flashbuses_to_text_test_success(void **state);
/* spi25.c */
void spi_write_enable_test_success(void **state);
void spi_write_disable_test_success(void **state);
+void spi_read_chunked_test_success(void **state);
void probe_spi_rdid_test_success(void **state);
void probe_spi_rdid4_test_success(void **state);
void probe_spi_rems_test_success(void **state);
@@ -40,4 +43,61 @@ void probe_spi_res3_test_success(void **state);
void probe_spi_at25f_test_success(void **state);
void probe_spi_st95_test_success(void **state); /* spi95.c */
+/* lifecycle.c */
+void dummy_basic_lifecycle_test_success(void **state);
+void dummy_probe_lifecycle_test_success(void **state);
+void dummy_probe_variable_size_test_success(void **state);
+void dummy_init_fails_unhandled_param_test_success(void **state);
+void dummy_init_success_invalid_param_test_success(void **state);
+void dummy_init_success_unhandled_param_test_success(void **state);
+void dummy_null_prog_param_test_success(void **state);
+void dummy_all_buses_test_success(void **state);
+void nicrealtek_basic_lifecycle_test_success(void **state);
+void raiden_debug_basic_lifecycle_test_success(void **state);
+void dediprog_basic_lifecycle_test_success(void **state);
+void linux_mtd_probe_lifecycle_test_success(void **state);
+void linux_spi_probe_lifecycle_test_success(void **state);
+void parade_lspcon_basic_lifecycle_test_success(void **state);
+void parade_lspcon_no_allow_brick_test_success(void **state);
+void mediatek_i2c_spi_basic_lifecycle_test_success(void **state);
+void mediatek_i2c_no_allow_brick_test_success(void **state);
+void realtek_mst_basic_lifecycle_test_success(void **state);
+void realtek_mst_no_allow_brick_test_success(void **state);
+void ch341a_spi_basic_lifecycle_test_success(void **state);
+void ch341a_spi_probe_lifecycle_test_success(void **state);
+
+/* layout.c */
+void included_regions_dont_overlap_test_success(void **state);
+void included_regions_overlap_test_success(void **state);
+void region_not_included_overlap_test_success(void **state);
+void layout_pass_sanity_checks_test_success(void **state);
+void layout_region_invalid_address_test_success(void **state);
+void layout_region_invalid_range_test_success(void **state);
+
+/* chip.c */
+void erase_chip_test_success(void **state);
+void erase_chip_with_dummyflasher_test_success(void **state);
+void read_chip_test_success(void **state);
+void read_chip_with_dummyflasher_test_success(void **state);
+void write_chip_test_success(void **state);
+void write_chip_with_dummyflasher_test_success(void **state);
+void write_nonaligned_region_with_dummyflasher_test_success(void **state);
+void verify_chip_test_success(void **state);
+void verify_chip_with_dummyflasher_test_success(void **state);
+
+/* chip_wp.c */
+void invalid_wp_range_dummyflasher_test_success(void **state);
+void set_wp_range_dummyflasher_test_success(void **state);
+void switch_wp_mode_dummyflasher_test_success(void **state);
+void wp_init_from_status_dummyflasher_test_success(void **state);
+void full_chip_erase_with_wp_dummyflasher_test_success(void **state);
+void partial_chip_erase_with_wp_dummyflasher_test_success(void **state);
+void wp_get_register_values_and_masks(void **state);
+
+/* selfcheck.c */
+void selfcheck_programmer_table(void **state);
+void selfcheck_flashchips_table(void **state);
+void selfcheck_eraseblocks(void **state);
+void selfcheck_board_matches_table(void **state);
+
#endif /* TESTS_H */
diff --git a/tests/unittest_env.h b/tests/unittest_env.h
new file mode 100644
index 000000000..9bd7509c9
--- /dev/null
+++ b/tests/unittest_env.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+/*
+ * This header is included in all files when they are built for unit test
+ * environment, for all the files to be covered by dynamic memory allocation
+ * checks (checks for memory leaks, buffer overflows and underflows).
+ *
+ * See flashrom_test_dep in meson.build for more details.
+ *
+ * https://api.cmocka.org/group__cmocka__alloc.html
+ */
+
+extern void* _test_malloc(const size_t size, const char* file, const int line);
+extern void* _test_realloc(void *ptr, const size_t size, const char* file, const int line);
+extern void* _test_calloc(const size_t number_of_elements, const size_t size,
+ const char* file, const int line);
+extern void _test_free(void* const ptr, const char* file, const int line);
+
+#ifdef malloc
+#undef malloc
+#endif
+#ifdef calloc
+#undef calloc
+#endif
+#ifdef realloc
+#undef realloc
+#endif
+#ifdef free
+#undef free
+#endif
+
+#define malloc(size) _test_malloc(size, __FILE__, __LINE__)
+#define realloc(ptr, size) _test_realloc(ptr, size, __FILE__, __LINE__)
+#define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__)
+#define free(ptr) _test_free(ptr, __FILE__, __LINE__)
diff --git a/tests/usb_unittests.h b/tests/usb_unittests.h
new file mode 100644
index 000000000..c81e18147
--- /dev/null
+++ b/tests/usb_unittests.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2022 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.
+ */
+
+/*
+ * This header provides a temporary solution to unblock build system
+ * work. The main goal is to remove unconditional dependency on libusb
+ * for unit tests. The dependency is still present, but now it is present
+ * only when it is needed and only when the header is present in the env.
+ *
+ * The contents of the file will be modified in a very near future.
+ */
+
+#ifndef _USB_UNITTESTS_H_
+#define _USB_UNITTESTS_H_
+
+#if CONFIG_RAIDEN_DEBUG_SPI == 1 || CONFIG_DEDIPROG == 1 || CONFIG_CH341A_SPI == 1
+
+#include <libusb.h>
+
+#else
+
+struct libusb_context;
+typedef struct libusb_context libusb_context;
+
+struct libusb_device_handle;
+typedef struct libusb_device_handle libusb_device_handle;
+
+struct libusb_device_descriptor;
+typedef struct libusb_device_descriptor libusb_device_descriptor;
+
+struct libusb_device;
+typedef struct libusb_device libusb_device;
+
+struct libusb_config_descriptor;
+typedef struct libusb_config_descriptor libusb_config_descriptor;
+
+struct libusb_interface;
+typedef struct libusb_interface libusb_interface;
+
+struct libusb_interface_descriptor;
+typedef struct libusb_interface_descriptor libusb_interface_descriptor;
+
+struct libusb_endpoint_descriptor;
+typedef struct libusb_endpoint_descriptor libusb_endpoint_descriptor;
+
+struct libusb_transfer;
+
+#endif
+
+#endif /* _USB_UNITTESTS_H_ */
diff --git a/tests/wraps.h b/tests/wraps.h
new file mode 100644
index 000000000..089d99274
--- /dev/null
+++ b/tests/wraps.h
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2022 Google LLC
+ *
+ * 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; version 2 of the License.
+ *
+ * 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 WRAPS_H
+#define WRAPS_H
+
+#include <stdio.h>
+#include "flash.h"
+
+struct programmer_cfg; /* defined in programmer.h */
+
+char *__wrap_strdup(const char *s);
+void __wrap_physunmap(void *virt_addr, size_t len);
+void *__wrap_physmap(const char *descr, uintptr_t phys_addr, size_t len);
+struct pci_dev *__wrap_pcidev_init(const struct programmer_cfg *cfg, void *devs, int bar);
+uintptr_t __wrap_pcidev_readbar(void *dev, int bar);
+void __wrap_sio_write(uint16_t port, uint8_t reg, uint8_t data);
+uint8_t __wrap_sio_read(uint16_t port, uint8_t reg);
+int __wrap_open(const char *pathname, int flags, ...);
+int __real_open(const char *pathname, int flags, ...);
+int __wrap_open64(const char *pathname, int flags, ...);
+int __wrap___open64_2(const char *pathname, int flags, ...);
+int __wrap_ioctl(int fd, unsigned long int request, ...);
+int __wrap_write(int fd, const void *buf, size_t sz);
+int __wrap_read(int fd, void *buf, size_t sz);
+FILE *__wrap_fopen(const char *pathname, const char *mode);
+FILE *__real_fopen(const char *pathname, const char *mode);
+FILE *__wrap_fopen64(const char *pathname, const char *mode);
+FILE *__wrap_fdopen(int fd, const char *mode);
+FILE *__real_fdopen(int fd, const char *mode);
+int __wrap_stat(const char *path, void *buf);
+int __wrap_stat64(const char *path, void *buf);
+int __wrap___xstat(const char *path, void *buf);
+int __wrap___xstat64(const char *path, void *buf);
+int __wrap_fstat(int fd, void *buf);
+int __wrap_fstat64(int fd, void *buf);
+int __wrap___fstat50(int fd, void *buf);
+int __wrap___fxstat(int fd, void *buf);
+int __wrap___fxstat64(int fd, void *buf);
+char *__wrap_fgets(char *buf, int len, FILE *fp);
+char *__wrap___fgets_chk(char *buf, int len, FILE *fp);
+size_t __wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *fp);
+size_t __wrap_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp);
+size_t __real_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp);
+int __wrap_fflush(FILE *fp);
+int __wrap_fileno(FILE *fp);
+int __wrap_fsync(int fd);
+int __wrap_setvbuf(FILE *fp, char *buf, int type, size_t size);
+int __wrap_fprintf(FILE *fp, const char *fmt, ...);
+int __wrap___vfprintf_chk(FILE *fp, const char *fmt, va_list args);
+int __wrap_fclose(FILE *fp);
+int __real_fclose(FILE *fp);
+int __wrap_feof(FILE *fp);
+int __wrap_ferror(FILE *fp);
+void __wrap_clearerr(FILE *fp);
+int __wrap_rget_io_perms(void);
+void __wrap_OUTB(unsigned char value, unsigned short port);
+unsigned char __wrap_INB(unsigned short port);
+void __wrap_OUTW(unsigned short value, unsigned short port);
+unsigned short __wrap_INW(unsigned short port);
+void __wrap_OUTL(unsigned int value, unsigned short port);
+unsigned int __wrap_INL(unsigned short port);
+int __wrap_spi_send_command(const struct flashctx *flash,
+ unsigned int writecnt, unsigned int readcnt,
+ const unsigned char *writearr, unsigned char *readarr);
+
+#endif /* WRAPS_H */
diff --git a/udelay.c b/udelay.c
index 6c0efc436..82ddcbd62 100644
--- a/udelay.c
+++ b/udelay.c
@@ -235,7 +235,7 @@ void internal_sleep(unsigned int usecs)
}
/* Precise delay. */
-void internal_delay(unsigned int usecs)
+void default_delay(unsigned int usecs)
{
/* If the delay is >1 s, use internal_sleep because timing does not need to be so precise. */
if (usecs > 1000000) {
@@ -255,7 +255,7 @@ void myusec_calibrate_delay(void)
get_cpu_speed();
}
-void internal_delay(unsigned int usecs)
+void default_delay(unsigned int usecs)
{
udelay(usecs);
}
diff --git a/usb_device.c b/usb_device.c
index 344c4cb90..0c8e3e215 100644
--- a/usb_device.c
+++ b/usb_device.c
@@ -28,10 +28,11 @@
* Possibly extract a programmer parameter and use it to initialize the given
* match value structure.
*/
-static void usb_match_value_init(struct usb_match_value *match,
+static void usb_match_value_init(const struct programmer_cfg *cfg,
+ struct usb_match_value *match,
char const *parameter)
{
- char *string = extract_programmer_param(parameter);
+ char *string = extract_programmer_param_str(cfg, parameter);
match->name = parameter;
@@ -45,21 +46,21 @@ static void usb_match_value_init(struct usb_match_value *match,
free(string);
}
-#define USB_MATCH_VALUE_INIT(NAME) \
- usb_match_value_init(&match->NAME, #NAME)
+#define USB_MATCH_VALUE_INIT(PPARAM, NAME) \
+ usb_match_value_init(PPARAM, &match->NAME, #NAME)
-void usb_match_init(struct usb_match *match)
+void usb_match_init(const struct programmer_cfg *cfg, struct usb_match *match)
{
- USB_MATCH_VALUE_INIT(vid);
- USB_MATCH_VALUE_INIT(pid);
- USB_MATCH_VALUE_INIT(bus);
- USB_MATCH_VALUE_INIT(address);
- USB_MATCH_VALUE_INIT(config);
- USB_MATCH_VALUE_INIT(interface);
- USB_MATCH_VALUE_INIT(altsetting);
- USB_MATCH_VALUE_INIT(class);
- USB_MATCH_VALUE_INIT(subclass);
- USB_MATCH_VALUE_INIT(protocol);
+ USB_MATCH_VALUE_INIT(cfg, vid);
+ USB_MATCH_VALUE_INIT(cfg, pid);
+ USB_MATCH_VALUE_INIT(cfg, bus);
+ USB_MATCH_VALUE_INIT(cfg, address);
+ USB_MATCH_VALUE_INIT(cfg, config);
+ USB_MATCH_VALUE_INIT(cfg, interface);
+ USB_MATCH_VALUE_INIT(cfg, altsetting);
+ USB_MATCH_VALUE_INIT(cfg, class);
+ USB_MATCH_VALUE_INIT(cfg, subclass);
+ USB_MATCH_VALUE_INIT(cfg, protocol);
}
void usb_match_value_default(struct usb_match_value *value,
@@ -99,7 +100,7 @@ static int check_match(struct usb_match_value const *match_value, int value)
static void add_device(struct usb_device *device,
struct usb_device **devices)
{
- struct usb_device *copy = malloc(sizeof(struct usb_device));
+ struct usb_device *copy = malloc(sizeof(*copy));
assert(copy != NULL);
@@ -224,12 +225,12 @@ int usb_device_find(struct usb_match const *match, struct usb_device **devices)
ret = LIBUSB(libusb_get_device_descriptor(list[i],
&descriptor));
- if (ret != 0) {
- msg_perr("USB: Failed to get device descriptor");
- free(*devices);
- *devices = NULL;
- return ret;
- }
+ if (ret != 0) {
+ msg_perr("USB: Failed to get device descriptor");
+ free(*devices);
+ *devices = NULL;
+ return ret;
+ }
if (check_match(&match->vid, descriptor.idVendor) &&
check_match(&match->pid, descriptor.idProduct) &&
@@ -279,8 +280,8 @@ int usb_device_show(char const *prefix, struct usb_device *device)
ret = usb_device_open(device);
if (ret != 0) {
- msg_perr("USB: Failed to open device\n");
- return ret;
+ msg_perr("USB: Failed to open device\n");
+ return ret;
}
ret = LIBUSB(libusb_get_device_descriptor(device->device, &descriptor));
@@ -341,9 +342,11 @@ int usb_device_claim(struct usb_device *device)
}
}
- ret = LIBUSB(libusb_set_auto_detach_kernel_driver(device->handle, 1));
- if (ret != 0) {
- msg_perr("USB: Failed to enable auto kernel driver detach\n");
+ ret = libusb_detach_kernel_driver(device->handle,
+ device->interface_descriptor->bInterfaceNumber);
+ if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND && ret != LIBUSB_ERROR_NOT_SUPPORTED) {
+ msg_perr("Cannot detach the existing usb driver. %s\n",
+ libusb_error_name(ret));
return ret;
}
@@ -354,6 +357,8 @@ int usb_device_claim(struct usb_device *device)
if (ret != 0) {
msg_perr("USB: Could not claim device interface %d\n",
device->interface_descriptor->bInterfaceNumber);
+ libusb_attach_kernel_driver(device->handle,
+ device->interface_descriptor->bInterfaceNumber);
return ret;
}
@@ -380,8 +385,13 @@ struct usb_device *usb_device_free(struct usb_device *device)
{
struct usb_device *next = device->next;
- if (device->handle != NULL)
+ if (device->handle != NULL) {
+ libusb_release_interface(device->handle,
+ device->interface_descriptor->bInterfaceNumber);
+ libusb_attach_kernel_driver(device->handle,
+ device->interface_descriptor->bInterfaceNumber);
libusb_close(device->handle);
+ }
/*
* This unref balances the ref added in the add_device function.
diff --git a/usbblaster_spi.c b/usbblaster_spi.c
index 58a8a0e3d..43acaad8e 100644
--- a/usbblaster_spi.c
+++ b/usbblaster_spi.c
@@ -30,8 +30,6 @@
* See also the USB-Blaster Download Cable User Guide: http://www.altera.com/literature/ug/ug_usb_blstr.pdf
*/
-#if CONFIG_USBBLASTER_SPI == 1
-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -45,15 +43,15 @@
#define ALTERA_VID 0x09fb
#define ALTERA_USBBLASTER_PID 0x6001
-const struct dev_entry devs_usbblasterspi[] = {
+static const struct dev_entry devs_usbblasterspi[] = {
{ALTERA_VID, ALTERA_USBBLASTER_PID, OK, "Altera", "USB-Blaster"},
{0}
};
-static const struct spi_master spi_master_usbblaster;
-
-static struct ftdi_context ftdic;
+struct usbblaster_spi_data {
+ struct ftdi_context ftdic;
+};
// command bytes
#define BIT_BYTE (1<<7) // byte mode (rather than bitbang)
@@ -72,56 +70,10 @@ static uint8_t reverse(uint8_t b)
return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
}
-
-/* Returns 0 upon success, a negative number upon errors. */
-int usbblaster_spi_init(void)
+static int send_write(unsigned int writecnt, const unsigned char *writearr, struct ftdi_context ftdic)
{
- uint8_t buf[BUF_SIZE + 1];
-
- if (ftdi_init(&ftdic) < 0)
- return -1;
-
- if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) {
- msg_perr("Failed to open USB-Blaster: %s\n", ftdic.error_str);
- return -1;
- }
-
- if (ftdi_usb_reset(&ftdic) < 0) {
- msg_perr("USB-Blaster reset failed\n");
- return -1;
- }
-
- if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
- msg_perr("USB-Blaster set latency timer failed\n");
- return -1;
- }
+ uint8_t buf[BUF_SIZE] = { 0 };
- if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 ||
- ftdi_read_data_set_chunksize(&ftdic, BUF_SIZE) < 0) {
- msg_perr("USB-Blaster set chunk size failed\n");
- return -1;
- }
-
- memset(buf, 0, sizeof(buf));
- buf[sizeof(buf)-1] = BIT_LED | BIT_CS;
- if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) {
- msg_perr("USB-Blaster reset write failed\n");
- return -1;
- }
- if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) {
- msg_perr("USB-Blaster reset read failed\n");
- return -1;
- }
-
- register_spi_master(&spi_master_usbblaster);
- return 0;
-}
-
-static int send_write(unsigned int writecnt, const unsigned char *writearr)
-{
- uint8_t buf[BUF_SIZE];
-
- memset(buf, 0, sizeof(buf));
while (writecnt) {
unsigned int i;
unsigned int n_write = min(writecnt, BUF_SIZE - 1);
@@ -142,12 +94,11 @@ static int send_write(unsigned int writecnt, const unsigned char *writearr)
return 0;
}
-static int send_read(unsigned int readcnt, unsigned char *readarr)
+static int send_read(unsigned int readcnt, unsigned char *readarr, struct ftdi_context ftdic)
{
int i;
unsigned int n_read;
- uint8_t buf[BUF_SIZE];
- memset(buf, 0, sizeof(buf));
+ uint8_t buf[BUF_SIZE] = { 0 };
n_read = readcnt;
while (n_read) {
@@ -182,23 +133,24 @@ static int send_read(unsigned int readcnt, unsigned char *readarr)
static int usbblaster_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr)
{
+ struct usbblaster_spi_data *usbblaster_data = flash->mst->spi.data;
uint8_t cmd;
int ret = 0;
cmd = BIT_LED; // asserts /CS
- if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
+ if (ftdi_write_data(&usbblaster_data->ftdic, &cmd, 1) < 0) {
msg_perr("USB-Blaster enable chip select failed\n");
ret = -1;
}
if (!ret && writecnt)
- ret = send_write(writecnt, writearr);
+ ret = send_write(writecnt, writearr, usbblaster_data->ftdic);
if (!ret && readcnt)
- ret = send_read(readcnt, readarr);
+ ret = send_read(readcnt, readarr, usbblaster_data->ftdic);
cmd = BIT_CS;
- if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
+ if (ftdi_write_data(&usbblaster_data->ftdic, &cmd, 1) < 0) {
msg_perr("USB-Blaster disable chip select failed\n");
ret = -1;
}
@@ -206,15 +158,75 @@ static int usbblaster_spi_send_command(const struct flashctx *flash, unsigned in
return ret;
}
+static int usbblaster_shutdown(void *data)
+{
+ free(data);
+ return 0;
+}
static const struct spi_master spi_master_usbblaster = {
.max_data_read = 256,
.max_data_write = 256,
.command = usbblaster_spi_send_command,
- .multicommand = default_spi_send_multicommand,
.read = default_spi_read,
.write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
+ .shutdown = usbblaster_shutdown,
};
-#endif
+/* Returns 0 upon success, a negative number upon errors. */
+static int usbblaster_spi_init(const struct programmer_cfg *cfg)
+{
+ uint8_t buf[BUF_SIZE + 1] = { 0 };
+ struct ftdi_context ftdic;
+ struct usbblaster_spi_data *usbblaster_data;
+
+ if (ftdi_init(&ftdic) < 0)
+ return -1;
+
+ if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) {
+ msg_perr("Failed to open USB-Blaster: %s\n", ftdic.error_str);
+ return -1;
+ }
+
+ if (ftdi_usb_reset(&ftdic) < 0) {
+ msg_perr("USB-Blaster reset failed\n");
+ return -1;
+ }
+
+ if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
+ msg_perr("USB-Blaster set latency timer failed\n");
+ return -1;
+ }
+
+ if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 ||
+ ftdi_read_data_set_chunksize(&ftdic, BUF_SIZE) < 0) {
+ msg_perr("USB-Blaster set chunk size failed\n");
+ return -1;
+ }
+
+ buf[sizeof(buf)-1] = BIT_LED | BIT_CS;
+ if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) {
+ msg_perr("USB-Blaster reset write failed\n");
+ return -1;
+ }
+ if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) {
+ msg_perr("USB-Blaster reset read failed\n");
+ return -1;
+ }
+
+ usbblaster_data = calloc(1, sizeof(*usbblaster_data));
+ if (!usbblaster_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
+ return -1;
+ }
+ usbblaster_data->ftdic = ftdic;
+
+ return register_spi_master(&spi_master_usbblaster, usbblaster_data);
+}
+
+const struct programmer_entry programmer_usbblaster_spi = {
+ .name = "usbblaster_spi",
+ .type = USB,
+ .devs.dev = devs_usbblasterspi,
+ .init = usbblaster_spi_init,
+};
diff --git a/util/docker/flashrom.org/Dockerfile b/util/docker/flashrom.org/Dockerfile
new file mode 100644
index 000000000..23f5f5040
--- /dev/null
+++ b/util/docker/flashrom.org/Dockerfile
@@ -0,0 +1,29 @@
+FROM alpine:3.8
+
+COPY makeSphinx.sh /makeSphinx.sh
+
+ADD https://sourceforge.net/projects/ditaa/files/ditaa/0.9/ditaa0_9.zip/download /tmp/ditaa.zip
+
+RUN apk add --no-cache python3 make bash git openjdk8-jre ttf-dejavu fontconfig \
+ && pip3 install --upgrade --no-cache-dir pip \
+ && pip3 install --no-cache-dir \
+ sphinx===1.8.3 \
+ sphinx_rtd_theme===0.4.2 \
+ recommonmark===0.5.0 \
+ sphinx_autobuild===0.7.1 \
+ sphinxcontrib-ditaa===0.6 \
+ && chmod 755 /makeSphinx.sh
+RUN cd /tmp \
+ && unzip ditaa.zip \
+ && mv ditaa0_9.jar /usr/lib
+ADD ditaa.sh /usr/bin/ditaa
+
+VOLUME /data-in /data-out
+
+# For Sphinx-autobuild
+# Port 8000 - HTTP server
+# Port 35729 - websockets connection to allow automatic browser reloads after each build
+EXPOSE 8000 35729
+
+ENTRYPOINT ["/bin/bash", "/makeSphinx.sh"]
+CMD []
diff --git a/util/docker/flashrom.org/README.md b/util/docker/flashrom.org/README.md
new file mode 100644
index 000000000..313d0d768
--- /dev/null
+++ b/util/docker/flashrom.org/README.md
@@ -0,0 +1,32 @@
+# doc.coreboot.org
+ Docker container for generating and developing documentation for doc.coreboot.org
+
+**NOTE**: All paths are from the base of the coreboot git repo.
+
+### Build
+
+```sh
+ docker build --force-rm -t "doc.flashrom.org" "$PWD/util/docker/flashrom.org/"
+```
+
+### Generating production HTML
+
+```sh
+# To ensure the output directory is given the correct permissions, make sure to
+# created it before running docker the first time.
+mkdir -p "$PWD/doc/_build/"
+
+docker run -it --rm \
+ --user "$(id -u):$(id -g)" \
+ -v "$PWD/:/data-in/:ro" \
+ -v "$PWD/doc/_build/:/data-out/" \
+ doc.flashrom.org
+```
+
+### live reloaded with web server
+On the host machine, open a browser to the address http://0.0.0.0:8000
+```sh
+docker run -it --rm \
+ --net=host -v "$PWD/:/data-in/:ro" \
+ doc.flashrom.org livehtml
+```
diff --git a/util/docker/flashrom.org/ditaa.sh b/util/docker/flashrom.org/ditaa.sh
new file mode 100755
index 000000000..637379f3e
--- /dev/null
+++ b/util/docker/flashrom.org/ditaa.sh
@@ -0,0 +1,2 @@
+#!/usr/bin/env sh
+exec java -jar /usr/lib/ditaa0_9.jar $*
diff --git a/util/docker/flashrom.org/makeSphinx.sh b/util/docker/flashrom.org/makeSphinx.sh
new file mode 100755
index 000000000..5b6ea0386
--- /dev/null
+++ b/util/docker/flashrom.org/makeSphinx.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+
+if [ "$1" == "livehtml" ]; then
+ echo "Starting live documentation build"
+ cd /data-in/ && sphinx-autobuild -b html doc /tmp/build/html
+else
+ echo "Starting production documentation build"
+ cd /data-in/ \
+ && sphinx-build -b html doc /tmp/build/html \
+ && rm -rf /data-out/* \
+ && mv /tmp/build/html/* /data-out/
+fi
diff --git a/util/flashrom.bash-completion.tmpl b/util/flashrom.bash-completion.tmpl
new file mode 100644
index 000000000..afb7ae98c
--- /dev/null
+++ b/util/flashrom.bash-completion.tmpl
@@ -0,0 +1,77 @@
+# Completion file for bash
+#
+# This file is part of the flashrom project.
+#
+# Copyright 2022 Alexander Goncharov <chat@joursoir.net>
+#
+# 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.
+#
+
+_flashrom()
+{
+ local cur prev OPTS
+ COMPREPLY=()
+ cur="${COMP_WORDS[COMP_CWORD]}"
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
+ case $prev in
+ '-r'|'--read'|'-w'|'--write'|'-v'|'--verify'|'-l'|'--layout'| \
+ '--fmap-file'|'-o'|'--output'|'--flash-contents')
+ local IFS=$'\n'
+ compopt -o filenames
+ COMPREPLY=( $(compgen -f -- $cur) )
+ return 0
+ ;;
+ '-c'|'--chip'|'--wp-range'|'--wp-region'|'-i'|'--include')
+ return 0
+ ;;
+ '-p'|'--programmer')
+ COMPREPLY=( $(compgen -W "@PROGRAMMERS@" -- $cur) )
+ return 0
+ ;;
+ '-h'|'--help'|'-R'|'--version'|'-L'|'--list-supported')
+ return 0
+ ;;
+ esac
+ OPTS="--help
+ --version
+ --read
+ --write
+ --verify
+ --erase
+ --verbose
+ --chip
+ --force
+ --noverify
+ --noverify-all
+ --extract
+ --layout
+ --wp-disable
+ --wp-enable
+ --wp-list
+ --wp-status
+ --wp-range
+ --wp-region
+ --flash-name
+ --flash-size
+ --fmap
+ --fmap-file
+ --ifd
+ --include
+ --output
+ --flash-contents
+ --list-supported
+ --progress
+ --programmer"
+ COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
+ return 0
+}
+
+complete -F _flashrom flashrom
diff --git a/util/flashrom_tester/.cargo/config.toml b/util/flashrom_tester/.cargo/config.toml
new file mode 100644
index 000000000..8af59dd8c
--- /dev/null
+++ b/util/flashrom_tester/.cargo/config.toml
@@ -0,0 +1,2 @@
+[env]
+RUST_TEST_THREADS = "1"
diff --git a/util/flashrom_tester/Cargo.toml b/util/flashrom_tester/Cargo.toml
index 50f2c4a7d..e6ed9c044 100644
--- a/util/flashrom_tester/Cargo.toml
+++ b/util/flashrom_tester/Cargo.toml
@@ -3,6 +3,8 @@ name = "flashrom_tester"
version = "1.6.0"
authors = ["Edward O'Callaghan <quasisec@chromium.org>",
"Peter Marheine <pmarheine@chromium.org>"]
+description = "A tool to verify flashrom and flash chip behaviour."
+license = "GPL-2.0-only"
edition = "2018"
build = "build.rs"
@@ -14,17 +16,22 @@ name = "flashrom_tester"
required-features = ["cli"]
[dependencies]
-built = { version = "0.3", default-features = false, features = ["serialized_time", "serialized_version"] }
+atty = "0.2"
+built = { version = "0.5", features = ["chrono"] }
chrono = { version = "0.4", optional = true }
clap = { version = "2.33", default-features = false, optional = true }
flashrom = { path = "flashrom/" }
+libc = "0.2"
log = { version = "0.4", features = ["std"] }
rand = "0.6.4"
serde_json = "1"
-sys-info = "0.5.7"
+sys-info = "0.9"
[build-dependencies]
-built = { version = "0.3", default-features = false, features = ["serialized_time", "serialized_version"] }
+built = { version = "0.5", features = ["chrono"] }
+
+[dev-dependencies]
+gag = "1"
[features]
# Features required to build the CLI binary but not the library
diff --git a/util/flashrom_tester/flashrom/Cargo.toml b/util/flashrom_tester/flashrom/Cargo.toml
index 27216cbde..4d4fc2fea 100644
--- a/util/flashrom_tester/flashrom/Cargo.toml
+++ b/util/flashrom_tester/flashrom/Cargo.toml
@@ -3,7 +3,10 @@ name = "flashrom"
version = "1.0.0"
authors = ["Edward O'Callaghan <quasisec@chromium.org>",
"Peter Marheine <pmarheine@chromium.org>"]
+description = "Flashrom abstraction for the flashrom_tester tool."
+license = "GPL-2.0-only"
edition = "2018"
[dependencies]
-log = "0.4" \ No newline at end of file
+log = "0.4"
+libflashrom = { path = "../../../bindings/rust/libflashrom" }
diff --git a/util/flashrom_tester/flashrom/src/cmd.rs b/util/flashrom_tester/flashrom/src/cmd.rs
index 3fd2ac04d..1f13a8ede 100644
--- a/util/flashrom_tester/flashrom/src/cmd.rs
+++ b/util/flashrom_tester/flashrom/src/cmd.rs
@@ -33,11 +33,57 @@
// Software Foundation.
//
-use crate::{FlashChip, FlashromError, FlashromOpt};
+use crate::{FlashChip, FlashromError};
-use std::process::Command;
+use std::{
+ ffi::{OsStr, OsString},
+ path::Path,
+ process::Command,
+};
-#[derive(PartialEq, Debug)]
+#[derive(Default)]
+pub struct FlashromOpt<'a> {
+ pub wp_opt: WPOpt,
+ pub io_opt: Option<IOOpt<'a>>,
+
+ pub flash_name: bool, // --flash-name
+ pub verbose: bool, // -V
+}
+
+#[derive(Default)]
+pub struct WPOpt {
+ pub range: Option<(i64, i64)>, // --wp-range x0 x1
+ pub status: bool, // --wp-status
+ pub list: bool, // --wp-list
+ pub enable: bool, // --wp-enable
+ pub disable: bool, // --wp-disable
+}
+
+pub enum OperationArgs<'a> {
+ /// The file is the whole chip.
+ EntireChip(&'a Path),
+ /// File is the size of the full chip, limited to a single named region.
+ ///
+ /// The required path is the file to use, and the optional path is a layout file
+ /// specifying how to locate regions (if unspecified, flashrom will attempt
+ /// to discover the layout itself).
+ FullFileRegion(&'a str, &'a Path, Option<&'a Path>),
+ /// File is the size of the single named region only.
+ ///
+ /// The required path is the file to use, and the optional path is a layout file
+ /// specifying how to locate regions (if unspecified, flashrom will attempt
+ /// to discover the layout itself).
+ RegionFileRegion(&'a str, &'a Path, Option<&'a Path>), // The file contains only the region
+}
+
+pub enum IOOpt<'a> {
+ Read(OperationArgs<'a>), // -r <file>
+ Write(OperationArgs<'a>), // -w <file>
+ Verify(OperationArgs<'a>), // -v <file>
+ Erase, // -E
+}
+
+#[derive(PartialEq, Eq, Debug)]
pub struct FlashromCmd {
pub path: String,
pub fc: FlashChip,
@@ -54,33 +100,204 @@ fn flashrom_extract_size(stdout: &str) -> Result<i64, FlashromError> {
.last()
.map(str::parse::<i64>)
{
- None => return Err("Found no purely-numeric lines in flashrom output".into()),
+ None => Err("Found no purely-numeric lines in flashrom output".into()),
Some(Err(e)) => {
- return Err(format!(
- "Failed to parse flashrom size output as integer: {}",
- e
- ))
+ Err(format!("Failed to parse flashrom size output as integer: {}", e).into())
}
Some(Ok(sz)) => Ok(sz),
}
}
+impl FlashromCmd {
+ fn dispatch(
+ &self,
+ fropt: FlashromOpt,
+ debug_name: &str,
+ ) -> Result<(String, String), FlashromError> {
+ let params = flashrom_decode_opts(fropt);
+ flashrom_dispatch(self.path.as_str(), &params, self.fc, debug_name)
+ }
+}
+
impl crate::Flashrom for FlashromCmd {
fn get_size(&self) -> Result<i64, FlashromError> {
- let (stdout, _) = flashrom_dispatch(self.path.as_str(), &["--flash-size"], self.fc)?;
- let sz = String::from_utf8_lossy(&stdout);
+ let (stdout, _) =
+ flashrom_dispatch(self.path.as_str(), &["--flash-size"], self.fc, "get_size")?;
+ flashrom_extract_size(&stdout)
+ }
+
+ fn name(&self) -> Result<(String, String), FlashromError> {
+ let opts = FlashromOpt {
+ flash_name: true,
+ ..Default::default()
+ };
+
+ let (stdout, _) = self.dispatch(opts, "name")?;
+ match extract_flash_name(&stdout) {
+ None => Err("Didn't find chip vendor/name in flashrom output".into()),
+ Some((vendor, name)) => Ok((vendor.into(), name.into())),
+ }
+ }
- flashrom_extract_size(&sz)
+ fn write_from_file_region(
+ &self,
+ path: &Path,
+ region: &str,
+ layout: &Path,
+ ) -> Result<bool, FlashromError> {
+ let opts = FlashromOpt {
+ io_opt: Some(IOOpt::Write(OperationArgs::FullFileRegion(
+ region,
+ path,
+ Some(layout),
+ ))),
+ ..Default::default()
+ };
+
+ self.dispatch(opts, "write_file_with_layout")?;
+ Ok(true)
}
- fn dispatch(&self, fropt: FlashromOpt) -> Result<(Vec<u8>, Vec<u8>), FlashromError> {
- let params = flashrom_decode_opts(fropt);
- flashrom_dispatch(self.path.as_str(), &params, self.fc)
+ fn wp_range(&self, range: (i64, i64), en: bool) -> Result<bool, FlashromError> {
+ let opts = FlashromOpt {
+ wp_opt: WPOpt {
+ enable: en,
+ disable: !en,
+ range: Some(range),
+ ..Default::default()
+ },
+ ..Default::default()
+ };
+
+ self.dispatch(opts, "wp_range")?;
+ Ok(true)
+ }
+
+ fn wp_list(&self) -> Result<String, FlashromError> {
+ let opts = FlashromOpt {
+ wp_opt: WPOpt {
+ list: true,
+ ..Default::default()
+ },
+ ..Default::default()
+ };
+
+ let (stdout, _) = self.dispatch(opts, "wp_list")?;
+ if stdout.is_empty() {
+ return Err(
+ "wp_list isn't supported on platforms using the Linux kernel SPI driver wp_list"
+ .into(),
+ );
+ }
+ Ok(stdout)
+ }
+
+ fn wp_status(&self, en: bool) -> Result<bool, FlashromError> {
+ let status = if en { "en" } else { "dis" };
+ info!("See if chip write protect is {}abled", status);
+
+ let opts = FlashromOpt {
+ wp_opt: WPOpt {
+ status: true,
+ ..Default::default()
+ },
+ ..Default::default()
+ };
+
+ let (stdout, _) = self.dispatch(opts, "wp_status")?;
+ let s = std::format!("write protect is {}abled", status);
+ Ok(stdout.contains(&s))
+ }
+
+ fn wp_toggle(&self, en: bool) -> Result<bool, FlashromError> {
+ let range = if en {
+ let rom_sz: i64 = self.get_size()?;
+ (0, rom_sz) // (start, len)
+ } else {
+ (0, 0)
+ };
+ self.wp_range(range, en)?;
+ let status = if en { "en" } else { "dis" };
+ match self.wp_status(true) {
+ Ok(_ret) => {
+ info!("Successfully {}abled write-protect", status);
+ Ok(true)
+ }
+ Err(e) => Err(format!("Cannot {}able write-protect: {}", status, e).into()),
+ }
+ }
+
+ fn read_into_file(&self, path: &Path) -> Result<(), FlashromError> {
+ let opts = FlashromOpt {
+ io_opt: Some(IOOpt::Read(OperationArgs::EntireChip(path))),
+ ..Default::default()
+ };
+
+ self.dispatch(opts, "read_into_file")?;
+ Ok(())
+ }
+
+ fn read_region_into_file(&self, path: &Path, region: &str) -> Result<(), FlashromError> {
+ let opts = FlashromOpt {
+ io_opt: Some(IOOpt::Read(OperationArgs::RegionFileRegion(
+ region, path, None,
+ ))),
+ ..Default::default()
+ };
+
+ self.dispatch(opts, "read_region_into_file")?;
+ Ok(())
+ }
+
+ fn write_from_file(&self, path: &Path) -> Result<(), FlashromError> {
+ let opts = FlashromOpt {
+ io_opt: Some(IOOpt::Write(OperationArgs::EntireChip(path))),
+ ..Default::default()
+ };
+
+ self.dispatch(opts, "write_from_file")?;
+ Ok(())
+ }
+
+ fn verify_from_file(&self, path: &Path) -> Result<(), FlashromError> {
+ let opts = FlashromOpt {
+ io_opt: Some(IOOpt::Verify(OperationArgs::EntireChip(path))),
+ ..Default::default()
+ };
+
+ self.dispatch(opts, "verify_from_file")?;
+ Ok(())
+ }
+
+ fn verify_region_from_file(&self, path: &Path, region: &str) -> Result<(), FlashromError> {
+ let opts = FlashromOpt {
+ io_opt: Some(IOOpt::Verify(OperationArgs::RegionFileRegion(
+ region, path, None,
+ ))),
+ ..Default::default()
+ };
+
+ self.dispatch(opts, "verify_region_from_file")?;
+ Ok(())
+ }
+
+ fn erase(&self) -> Result<(), FlashromError> {
+ let opts = FlashromOpt {
+ io_opt: Some(IOOpt::Erase),
+ ..Default::default()
+ };
+
+ self.dispatch(opts, "erase")?;
+ Ok(())
+ }
+
+ fn can_control_hw_wp(&self) -> bool {
+ self.fc.can_control_hw_wp()
}
}
-fn flashrom_decode_opts(opts: FlashromOpt) -> Vec<String> {
- let mut params = Vec::<String>::new();
+fn flashrom_decode_opts(opts: FlashromOpt) -> Vec<OsString> {
+ let mut params = Vec::<OsString>::new();
// ------------ WARNING !!! ------------
// each param must NOT contain spaces!
@@ -89,134 +306,144 @@ fn flashrom_decode_opts(opts: FlashromOpt) -> Vec<String> {
// wp_opt
if opts.wp_opt.range.is_some() {
let (x0, x1) = opts.wp_opt.range.unwrap();
- params.push("--wp-range".to_string());
- params.push(hex_string(x0));
- params.push(hex_string(x1));
+ params.push("--wp-range".into());
+ params.push(hex_range_string(x0, x1).into());
}
if opts.wp_opt.status {
- params.push("--wp-status".to_string());
+ params.push("--wp-status".into());
} else if opts.wp_opt.list {
- params.push("--wp-list".to_string());
+ params.push("--wp-list".into());
} else if opts.wp_opt.enable {
- params.push("--wp-enable".to_string());
+ params.push("--wp-enable".into());
} else if opts.wp_opt.disable {
- params.push("--wp-disable".to_string());
+ params.push("--wp-disable".into());
}
// io_opt
- if opts.io_opt.read.is_some() {
- params.push("-r".to_string());
- params.push(opts.io_opt.read.unwrap().to_string());
- } else if opts.io_opt.write.is_some() {
- params.push("-w".to_string());
- params.push(opts.io_opt.write.unwrap().to_string());
- } else if opts.io_opt.verify.is_some() {
- params.push("-v".to_string());
- params.push(opts.io_opt.verify.unwrap().to_string());
- } else if opts.io_opt.erase {
- params.push("-E".to_string());
- }
-
- // misc_opt
- if opts.layout.is_some() {
- params.push("-l".to_string());
- params.push(opts.layout.unwrap().to_string());
+ fn add_operation_args(opts: OperationArgs, params: &mut Vec<OsString>) {
+ let (file, region, layout) = match opts {
+ OperationArgs::EntireChip(file) => (Some(file), None, None),
+ OperationArgs::FullFileRegion(region, file, layout) => {
+ (Some(file), Some(region.to_string()), layout)
+ }
+ OperationArgs::RegionFileRegion(region, file, layout) => (
+ None,
+ Some(format!("{region}:{}", file.to_string_lossy())),
+ layout,
+ ),
+ };
+ if let Some(file) = file {
+ params.push(file.into())
+ }
+ if let Some(region) = region {
+ params.push("--include".into());
+ params.push(region.into())
+ }
+ if let Some(layout) = layout {
+ params.push("--layout".into());
+ params.push(layout.into())
+ }
}
- if opts.image.is_some() {
- params.push("-i".to_string());
- params.push(opts.image.unwrap().to_string());
+ if let Some(io) = opts.io_opt {
+ match io {
+ IOOpt::Read(args) => {
+ params.push("-r".into());
+ add_operation_args(args, &mut params);
+ }
+ IOOpt::Write(args) => {
+ params.push("-w".into());
+ add_operation_args(args, &mut params);
+ }
+ IOOpt::Verify(args) => {
+ params.push("-v".into());
+ add_operation_args(args, &mut params);
+ }
+ IOOpt::Erase => params.push("-E".into()),
+ }
}
+ // misc_opt
if opts.flash_name {
- params.push("--flash-name".to_string());
- }
- if opts.ignore_fmap {
- params.push("--ignore-fmap".to_string());
+ params.push("--flash-name".into());
}
if opts.verbose {
- params.push("-V".to_string());
+ params.push("-V".into());
}
params
}
-fn flashrom_dispatch<S: AsRef<str>>(
+fn flashrom_dispatch<S: AsRef<OsStr>>(
path: &str,
params: &[S],
fc: FlashChip,
-) -> Result<(Vec<u8>, Vec<u8>), FlashromError> {
+ debug_name: &str,
+) -> Result<(String, String), FlashromError> {
// from man page:
// ' -p, --programmer <name>[:parameter[,parameter[,parameter]]] '
- let mut args: Vec<&str> = vec!["-p", FlashChip::to(fc)];
+ let mut args: Vec<&OsStr> = vec![OsStr::new("-p"), OsStr::new(FlashChip::to(fc))];
args.extend(params.iter().map(S::as_ref));
info!("flashrom_dispatch() running: {} {:?}", path, args);
let output = match Command::new(path).args(&args).output() {
Ok(x) => x,
- Err(e) => return Err(format!("Failed to run flashrom: {}", e)),
+ Err(e) => return Err(format!("Failed to run flashrom: {}", e).into()),
};
+
+ let stdout = String::from_utf8_lossy(output.stdout.as_slice());
+ let stderr = String::from_utf8_lossy(output.stderr.as_slice());
+ debug!("{}()'stdout: {}.", debug_name, stdout);
+ debug!("{}()'stderr: {}.", debug_name, stderr);
+
if !output.status.success() {
// There is two cases on failure;
// i. ) A bad exit code,
// ii.) A SIG killed us.
match output.status.code() {
Some(code) => {
- return Err(format!(
- "{}\nExited with error code: {}",
- String::from_utf8_lossy(&output.stderr),
- code
- ));
+ return Err(format!("{}\nExited with error code: {}", stderr, code).into());
}
None => return Err("Process terminated by a signal".into()),
}
}
- Ok((output.stdout, output.stderr))
-}
-
-pub fn dut_ctrl_toggle_wp(en: bool) -> Result<(Vec<u8>, Vec<u8>), FlashromError> {
- let args = if en {
- ["fw_wp_en:off", "fw_wp:on"]
- } else {
- ["fw_wp_en:on", "fw_wp:off"]
- };
- dut_ctrl(&args)
+ Ok((stdout.into(), stderr.into()))
}
-pub fn dut_ctrl_servo_type() -> Result<(Vec<u8>, Vec<u8>), FlashromError> {
- let args = ["servo_type"];
- dut_ctrl(&args)
+fn hex_range_string(s: i64, l: i64) -> String {
+ format!("{:#08X},{:#08X}", s, l)
}
-fn dut_ctrl(args: &[&str]) -> Result<(Vec<u8>, Vec<u8>), FlashromError> {
- let output = match Command::new("dut-control").args(args).output() {
- Ok(x) => x,
- Err(e) => return Err(format!("Failed to run dut-control: {}", e)),
- };
- if !output.status.success() {
- // There is two cases on failure;
- // i. ) A bad exit code,
- // ii.) A SIG killed us.
- match output.status.code() {
- Some(code) => {
- return Err(format!("Exited with error code: {}", code).into());
- }
- None => return Err("Process terminated by a signal".into()),
+/// Get a flash vendor and name from the first matching line of flashrom output.
+///
+/// The target line looks like 'vendor="foo" name="bar"', as output by flashrom --flash-name.
+/// This is usually the last line of output.
+fn extract_flash_name(stdout: &str) -> Option<(&str, &str)> {
+ for line in stdout.lines() {
+ if !line.starts_with("vendor=\"") {
+ continue;
}
- }
- Ok((output.stdout, output.stderr))
-}
+ let tail = line.trim_start_matches("vendor=\"");
+ let mut split = tail.splitn(2, "\" name=\"");
+ let vendor = split.next();
+ let name = split.next().map(|s| s.trim_end_matches('"'));
-fn hex_string(v: i64) -> String {
- format!("{:#08X}", v).to_string()
+ match (vendor, name) {
+ (Some(v), Some(n)) => return Some((v, n)),
+ _ => continue,
+ }
+ }
+ None
}
#[cfg(test)]
mod tests {
+ use std::path::Path;
+
use super::flashrom_decode_opts;
- use crate::{FlashromOpt, IOOpt, WPOpt};
+ use super::{FlashromOpt, IOOpt, WPOpt};
#[test]
fn decode_wp_opt() {
@@ -237,7 +464,7 @@ mod tests {
status: true,
..Default::default()
},
- &["--wp-range", "0x000000", "0x0004D2", "--wp-status"],
+ &["--wp-range", "0x000000,0x0004D2", "--wp-status"],
);
test_wp_opt(
WPOpt {
@@ -267,7 +494,7 @@ mod tests {
fn test_io_opt(opts: IOOpt, expected: &[&str]) {
assert_eq!(
flashrom_decode_opts(FlashromOpt {
- io_opt: opts,
+ io_opt: Some(opts),
..Default::default()
}),
expected
@@ -275,62 +502,48 @@ mod tests {
}
test_io_opt(
- IOOpt {
- read: Some("foo.bin"),
- ..Default::default()
- },
+ IOOpt::Read(crate::cmd::OperationArgs::EntireChip(Path::new("foo.bin"))),
&["-r", "foo.bin"],
);
test_io_opt(
- IOOpt {
- write: Some("bar.bin"),
- ..Default::default()
- },
+ IOOpt::Write(crate::cmd::OperationArgs::EntireChip(Path::new("bar.bin"))),
&["-w", "bar.bin"],
);
test_io_opt(
- IOOpt {
- verify: Some("/tmp/baz.bin"),
- ..Default::default()
- },
- &["-v", "/tmp/baz.bin"],
+ IOOpt::Verify(crate::cmd::OperationArgs::EntireChip(Path::new("baz.bin"))),
+ &["-v", "baz.bin"],
);
+ test_io_opt(IOOpt::Erase, &["-E"]);
test_io_opt(
- IOOpt {
- erase: true,
- ..Default::default()
- },
- &["-E"],
+ IOOpt::Read(crate::cmd::OperationArgs::FullFileRegion(
+ "RO",
+ Path::new("foo.bin"),
+ Some(Path::new("baz.bin")),
+ )),
+ &["-r", "foo.bin", "--include", "RO", "--layout", "baz.bin"],
);
+
+ test_io_opt(
+ IOOpt::Read(crate::cmd::OperationArgs::RegionFileRegion(
+ "foo",
+ Path::new("bar.bin"),
+ None,
+ )),
+ &["-r", "--include", "foo:bar.bin"],
+ )
}
#[test]
fn decode_misc() {
//use Default::default;
- assert_eq!(
- flashrom_decode_opts(FlashromOpt {
- layout: Some("TestLayout"),
- ..Default::default()
- }),
- &["-l", "TestLayout"]
- );
-
- assert_eq!(
- flashrom_decode_opts(FlashromOpt {
- image: Some("TestImage"),
- ..Default::default()
- }),
- &["-i", "TestImage"]
- );
assert_eq!(
flashrom_decode_opts(FlashromOpt {
flash_name: true,
- ignore_fmap: true,
verbose: true,
..Default::default()
}),
- &["--flash-name", "--ignore-fmap", "-V"]
+ &["--flash-name", "-V"]
);
}
@@ -352,4 +565,26 @@ mod tests {
Err("Found no purely-numeric lines in flashrom output".into())
);
}
+
+ #[test]
+ fn extract_flash_name() {
+ use super::extract_flash_name;
+
+ assert_eq!(
+ extract_flash_name(
+ "coreboot table found at 0x7cc13000\n\
+ Found chipset \"Intel Braswell\". Enabling flash write... OK.\n\
+ vendor=\"Winbond\" name=\"W25Q64DW\"\n"
+ ),
+ Some(("Winbond", "W25Q64DW"))
+ );
+
+ assert_eq!(
+ extract_flash_name(
+ "vendor name is TEST\n\
+ Something failed!"
+ ),
+ None
+ )
+ }
}
diff --git a/util/flashrom_tester/flashrom/src/flashromlib.rs b/util/flashrom_tester/flashrom/src/flashromlib.rs
new file mode 100644
index 000000000..5e1747b1b
--- /dev/null
+++ b/util/flashrom_tester/flashrom/src/flashromlib.rs
@@ -0,0 +1,184 @@
+// Copyright 2022, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Alternatively, this software may be distributed under the terms of the
+// GNU General Public License ("GPL") version 2 as published by the Free
+// Software Foundation.
+//
+
+use libflashrom::{Chip, Programmer};
+
+use std::{cell::RefCell, convert::TryFrom, fs, path::Path};
+
+use crate::{FlashChip, FlashromError};
+
+#[derive(Debug)]
+pub struct FlashromLib {
+ // RefCell required here to keep Flashrom trait immutable.
+ // Cant make Flashrom methods mut because WriteProtectState
+ // and TestEnv both keep a reference.
+ pub flashrom: RefCell<Chip>,
+ pub fc: FlashChip,
+}
+
+impl FlashromLib {
+ pub fn new(fc: FlashChip, log_level: libflashrom::flashrom_log_level) -> FlashromLib {
+ libflashrom::set_log_level(Some(log_level));
+ let (programmer, options) = FlashChip::to_split(fc);
+ let flashrom = Chip::new(Programmer::new(programmer, options).unwrap(), None).unwrap();
+ FlashromLib {
+ flashrom: RefCell::new(flashrom),
+ fc,
+ }
+ }
+}
+
+impl crate::Flashrom for FlashromLib {
+ fn get_size(&self) -> Result<i64, FlashromError> {
+ Ok(self.flashrom.borrow().get_size() as i64)
+ }
+
+ fn name(&self) -> Result<(String, String), FlashromError> {
+ Ok(("not".to_string(), "implemented".to_string()))
+ }
+
+ fn wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result<bool, FlashromError> {
+ let mut cfg = libflashrom::WriteProtectCfg::new()?;
+ let start = usize::try_from(range.0).unwrap();
+ let len = usize::try_from(range.1).unwrap();
+ cfg.set_range::<std::ops::Range<usize>>(start..(start + len));
+ cfg.set_mode(if wp_enable {
+ libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_HARDWARE
+ } else {
+ libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED
+ });
+ self.flashrom.borrow_mut().set_wp(&cfg)?;
+ Ok(true)
+ }
+
+ fn wp_list(&self) -> Result<String, FlashromError> {
+ let ranges = self.flashrom.borrow_mut().get_wp_ranges()?;
+ Ok(format!("{:?}", ranges))
+ }
+
+ fn wp_status(&self, en: bool) -> Result<bool, FlashromError> {
+ let ret = self
+ .flashrom
+ .borrow_mut()
+ .get_wp()
+ .map_err(|e| format!("{:?}", e))?
+ .get_mode();
+ if en {
+ Ok(ret != libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED)
+ } else {
+ Ok(ret == libflashrom::flashrom_wp_mode::FLASHROM_WP_MODE_DISABLED)
+ }
+ }
+
+ fn wp_toggle(&self, en: bool) -> Result<bool, FlashromError> {
+ let range = if en { (0, self.get_size()?) } else { (0, 0) };
+ self.wp_range(range, en)
+ }
+
+ fn read_into_file(&self, path: &Path) -> Result<(), FlashromError> {
+ let buf = self.flashrom.borrow_mut().image_read(None)?;
+ fs::write(path, buf).map_err(|error| error.to_string())?;
+ Ok(())
+ }
+
+ fn read_region_into_file(&self, path: &Path, region: &str) -> Result<(), FlashromError> {
+ let mut layout = self.flashrom.borrow_mut().layout_read_fmap_from_rom()?;
+ layout.include_region(region)?;
+ let range = layout.get_region_range(region)?;
+ let buf = self.flashrom.borrow_mut().image_read(None)?;
+ fs::write(path, &buf[range]).map_err(|error| error.to_string())?;
+ Ok(())
+ }
+
+ fn write_from_file(&self, path: &Path) -> Result<(), FlashromError> {
+ let mut buf = fs::read(path).map_err(|error| error.to_string())?;
+ self.flashrom.borrow_mut().image_write(&mut buf, None)?;
+ Ok(())
+ }
+
+ fn write_from_file_region(
+ &self,
+ path: &Path,
+ region: &str,
+ layout: &Path,
+ ) -> Result<bool, FlashromError> {
+ let buf = fs::read(layout).map_err(|error| error.to_string())?;
+ let buf = String::from_utf8(buf).unwrap();
+ let mut layout: libflashrom::Layout = buf
+ .parse()
+ .map_err(|e: Box<dyn std::error::Error>| e.to_string())?;
+ layout.include_region(region)?;
+ let mut buf = fs::read(path).map_err(|error| error.to_string())?;
+ self.flashrom
+ .borrow_mut()
+ .image_write(&mut buf, Some(layout))?;
+ Ok(true)
+ }
+
+ fn verify_from_file(&self, path: &Path) -> Result<(), FlashromError> {
+ let buf = fs::read(path).map_err(|error| error.to_string())?;
+ self.flashrom.borrow_mut().image_verify(&buf, None)?;
+ Ok(())
+ }
+
+ fn verify_region_from_file(&self, path: &Path, region: &str) -> Result<(), FlashromError> {
+ let mut layout = self.flashrom.borrow_mut().layout_read_fmap_from_rom()?;
+ layout.include_region(region)?;
+ let range = layout.get_region_range(region)?;
+ let region_data = fs::read(path).map_err(|error| error.to_string())?;
+ if region_data.len() != range.len() {
+ return Err(format!(
+ "verify region range ({}) does not match provided file size ({})",
+ range.len(),
+ region_data.len()
+ )
+ .into());
+ }
+ let mut buf = vec![0; self.get_size()? as usize];
+ buf[range].copy_from_slice(&region_data);
+ self.flashrom
+ .borrow_mut()
+ .image_verify(&buf, Some(layout))?;
+ Ok(())
+ }
+
+ fn erase(&self) -> Result<(), FlashromError> {
+ self.flashrom.borrow_mut().erase()?;
+ Ok(())
+ }
+
+ fn can_control_hw_wp(&self) -> bool {
+ self.fc.can_control_hw_wp()
+ }
+}
diff --git a/util/flashrom_tester/flashrom/src/lib.rs b/util/flashrom_tester/flashrom/src/lib.rs
index 734e3ff4a..41393e841 100644
--- a/util/flashrom_tester/flashrom/src/lib.rs
+++ b/util/flashrom_tester/flashrom/src/lib.rs
@@ -37,36 +37,41 @@
extern crate log;
mod cmd;
+mod flashromlib;
-pub use cmd::{dut_ctrl_toggle_wp, FlashromCmd};
+use std::{error, fmt, path::Path};
-#[derive(Copy, Clone, PartialEq, Debug)]
+pub use cmd::FlashromCmd;
+pub use flashromlib::FlashromLib;
+
+pub use libflashrom::{
+ flashrom_log_level, FLASHROM_MSG_DEBUG, FLASHROM_MSG_DEBUG2, FLASHROM_MSG_ERROR,
+ FLASHROM_MSG_INFO, FLASHROM_MSG_SPEW, FLASHROM_MSG_WARN,
+};
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum FlashChip {
- EC,
HOST,
- SERVO,
- DEDIPROG,
}
impl FlashChip {
pub fn from(s: &str) -> Result<FlashChip, &str> {
- let r = match s {
- "ec" => Ok(FlashChip::EC),
+ match s {
"host" => Ok(FlashChip::HOST),
- "servo" => Ok(FlashChip::SERVO),
- "dediprog" => Ok(FlashChip::DEDIPROG),
_ => Err("cannot convert str to enum"),
- };
- return r;
+ }
}
pub fn to(fc: FlashChip) -> &'static str {
- let r = match fc {
- FlashChip::EC => "ec",
+ match fc {
FlashChip::HOST => "host",
- FlashChip::SERVO => "ft2231_spi:type=servo-v2",
- FlashChip::DEDIPROG => "dediprog",
- };
- return r;
+ }
+ }
+
+ /// Return the programmer string and optional programmer options
+ pub fn to_split(fc: FlashChip) -> (&'static str, Option<&'static str>) {
+ let programmer = FlashChip::to(fc);
+ let mut bits = programmer.splitn(2, ':');
+ (bits.next().unwrap(), bits.next())
}
/// Return whether the hardware write protect signal can be controlled.
@@ -75,307 +80,86 @@ impl FlashChip {
/// disabled.
pub fn can_control_hw_wp(&self) -> bool {
match self {
- FlashChip::HOST | FlashChip::EC => true,
- FlashChip::SERVO | FlashChip::DEDIPROG => false,
+ FlashChip::HOST => true,
}
}
}
-pub type FlashromError = String;
-
-#[derive(Default)]
-pub struct FlashromOpt<'a> {
- pub wp_opt: WPOpt,
- pub io_opt: IOOpt<'a>,
-
- pub layout: Option<&'a str>, // -l <file>
- pub image: Option<&'a str>, // -i <name>
-
- pub flash_name: bool, // --flash-name
- pub ignore_fmap: bool, // --ignore-fmap
- pub verbose: bool, // -V
-}
-
-#[derive(Default)]
-pub struct WPOpt {
- pub range: Option<(i64, i64)>, // --wp-range x0 x1
- pub status: bool, // --wp-status
- pub list: bool, // --wp-list
- pub enable: bool, // --wp-enable
- pub disable: bool, // --wp-disable
+#[derive(Debug, PartialEq, Eq)]
+pub struct FlashromError {
+ msg: String,
}
-#[derive(Default)]
-pub struct IOOpt<'a> {
- pub read: Option<&'a str>, // -r <file>
- pub write: Option<&'a str>, // -w <file>
- pub verify: Option<&'a str>, // -v <file>
- pub erase: bool, // -E
-}
-
-pub trait Flashrom {
- fn get_size(&self) -> Result<i64, FlashromError>;
- fn dispatch(&self, fropt: FlashromOpt) -> Result<(Vec<u8>, Vec<u8>), FlashromError>;
-}
-
-pub fn name(cmd: &cmd::FlashromCmd) -> Result<(String, String), FlashromError> {
- let opts = FlashromOpt {
- io_opt: IOOpt {
- ..Default::default()
- },
-
- flash_name: true,
-
- ..Default::default()
- };
-
- let (stdout, stderr) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
- let eoutput = String::from_utf8_lossy(stderr.as_slice());
- debug!("name()'stdout: {:#?}.", output);
- debug!("name()'stderr: {:#?}.", eoutput);
-
- match extract_flash_name(&output) {
- None => Err("Didn't find chip vendor/name in flashrom output".into()),
- Some((vendor, name)) => Ok((vendor.into(), name.into())),
- }
-}
-
-/// Get a flash vendor and name from the first matching line of flashrom output.
-///
-/// The target line looks like 'vendor="foo" name="bar"', as output by flashrom --flash-name.
-/// This is usually the last line of output.
-fn extract_flash_name(stdout: &str) -> Option<(&str, &str)> {
- for line in stdout.lines() {
- if !line.starts_with("vendor=\"") {
- continue;
- }
-
- let tail = line.trim_start_matches("vendor=\"");
- let mut split = tail.splitn(2, "\" name=\"");
- let vendor = split.next();
- let name = split.next().map(|s| s.trim_end_matches('"'));
-
- match (vendor, name) {
- (Some(v), Some(n)) => return Some((v, n)),
- _ => continue,
- }
+impl fmt::Display for FlashromError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", self.msg)
}
- None
-}
-
-pub struct ROMWriteSpecifics<'a> {
- pub layout_file: Option<&'a str>,
- pub write_file: Option<&'a str>,
- pub name_file: Option<&'a str>,
-}
-
-pub fn write_file_with_layout(
- cmd: &cmd::FlashromCmd,
- rws: &ROMWriteSpecifics,
-) -> Result<bool, FlashromError> {
- let opts = FlashromOpt {
- io_opt: IOOpt {
- write: rws.write_file,
- ..Default::default()
- },
-
- layout: rws.layout_file,
- image: rws.name_file,
-
- ignore_fmap: true,
-
- ..Default::default()
- };
-
- let (stdout, stderr) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
- let eoutput = String::from_utf8_lossy(stderr.as_slice());
- debug!("write_file_with_layout()'stdout:\n{}.", output);
- debug!("write_file_with_layout()'stderr:\n{}.", eoutput);
- Ok(true)
}
-pub fn wp_range(
- cmd: &cmd::FlashromCmd,
- range: (i64, i64),
- wp_enable: bool,
-) -> Result<bool, FlashromError> {
- let opts = FlashromOpt {
- wp_opt: WPOpt {
- range: Some(range),
- enable: wp_enable,
- ..Default::default()
- },
- ..Default::default()
- };
+impl error::Error for FlashromError {}
- let (stdout, stderr) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
- let eoutput = String::from_utf8_lossy(stderr.as_slice());
- debug!("wp_range()'stdout:\n{}.", output);
- debug!("wp_range()'stderr:\n{}.", eoutput);
- Ok(true)
-}
-
-pub fn wp_list(cmd: &cmd::FlashromCmd) -> Result<String, FlashromError> {
- let opts = FlashromOpt {
- wp_opt: WPOpt {
- list: true,
- ..Default::default()
- },
- ..Default::default()
- };
-
- let (stdout, _) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
- if output.len() == 0 {
- return Err(
- "wp_list isn't supported on platforms using the Linux kernel SPI driver wp_list".into(),
- );
+impl<T> From<T> for FlashromError
+where
+ T: Into<String>,
+{
+ fn from(msg: T) -> Self {
+ FlashromError { msg: msg.into() }
}
- Ok(output.to_string())
}
-pub fn wp_status(cmd: &cmd::FlashromCmd, en: bool) -> Result<bool, FlashromError> {
- let status = if en { "en" } else { "dis" };
- info!("See if chip write protect is {}abled", status);
-
- let opts = FlashromOpt {
- wp_opt: WPOpt {
- status: true,
- ..Default::default()
- },
- ..Default::default()
- };
-
- let (stdout, _) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
-
- debug!("wp_status():\n{}", output);
-
- let s = std::format!("write protect is {}abled", status);
- Ok(output.contains(&s))
-}
-
-pub fn wp_toggle(cmd: &cmd::FlashromCmd, en: bool) -> Result<bool, FlashromError> {
- let status = if en { "en" } else { "dis" };
-
- // For MTD, --wp-range and --wp-enable must be used simultaneously.
- let range = if en {
- let rom_sz: i64 = cmd.get_size()?;
- Some((0, rom_sz)) // (start, len)
- } else {
- None
- };
-
- let opts = FlashromOpt {
- wp_opt: WPOpt {
- range: range,
- enable: en,
- disable: !en,
- ..Default::default()
- },
- ..Default::default()
- };
-
- let (stdout, stderr) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
- let eoutput = String::from_utf8_lossy(stderr.as_slice());
+pub trait Flashrom {
+ /// Returns the size of the flash in bytes.
+ fn get_size(&self) -> Result<i64, FlashromError>;
- debug!("wp_toggle()'stdout:\n{}.", output);
- debug!("wp_toggle()'stderr:\n{}.", eoutput);
+ /// Returns the vendor name and the flash name.
+ fn name(&self) -> Result<(String, String), FlashromError>;
- match wp_status(&cmd, true) {
- Ok(_ret) => {
- info!("Successfully {}abled write-protect", status);
- Ok(true)
- }
- Err(e) => Err(format!("Cannot {}able write-protect: {}", status, e)),
- }
-}
+ /// Set write protect status and range.
+ fn wp_range(&self, range: (i64, i64), wp_enable: bool) -> Result<bool, FlashromError>;
-pub fn read(cmd: &cmd::FlashromCmd, path: &str) -> Result<(), FlashromError> {
- let opts = FlashromOpt {
- io_opt: IOOpt {
- read: Some(path),
- ..Default::default()
- },
- ..Default::default()
- };
+ /// Read the write protect regions for the flash.
+ fn wp_list(&self) -> Result<String, FlashromError>;
- let (stdout, _) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
- debug!("read():\n{}", output);
- Ok(())
-}
+ /// Return true if the flash write protect status matches `en`.
+ fn wp_status(&self, en: bool) -> Result<bool, FlashromError>;
-pub fn write(cmd: &cmd::FlashromCmd, path: &str) -> Result<(), FlashromError> {
- let opts = FlashromOpt {
- io_opt: IOOpt {
- write: Some(path),
- ..Default::default()
- },
- ..Default::default()
- };
+ /// Set write protect status.
+ /// If en=true sets wp_range to the whole chip (0,getsize()).
+ /// If en=false sets wp_range to (0,0).
+ /// This is due to the MTD driver, which requires wp enable to use a range
+ /// length != 0 and wp disable to have the range 0,0.
+ fn wp_toggle(&self, en: bool) -> Result<bool, FlashromError>;
- let (stdout, _) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
- debug!("write():\n{}", output);
- Ok(())
-}
+ /// Read the whole flash to the file specified by `path`.
+ fn read_into_file(&self, path: &Path) -> Result<(), FlashromError>;
-pub fn verify(cmd: &cmd::FlashromCmd, path: &str) -> Result<(), FlashromError> {
- let opts = FlashromOpt {
- io_opt: IOOpt {
- verify: Some(path),
- ..Default::default()
- },
- ..Default::default()
- };
+ /// Read only a region of the flash into the file specified by `path`. Note
+ /// the first byte written to the file is the first byte from the region.
+ fn read_region_into_file(&self, path: &Path, region: &str) -> Result<(), FlashromError>;
- let (stdout, _) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
- debug!("verify():\n{}", output);
- Ok(())
-}
+ /// Write the whole flash to the file specified by `path`.
+ fn write_from_file(&self, path: &Path) -> Result<(), FlashromError>;
-pub fn erase(cmd: &cmd::FlashromCmd) -> Result<(), FlashromError> {
- let opts = FlashromOpt {
- io_opt: IOOpt {
- erase: true,
- ..Default::default()
- },
- ..Default::default()
- };
+ /// Write only a region of the flash.
+ /// `path` is a file of the size of the whole flash.
+ /// The `region` name corresponds to a region name in the `layout` file, not the flash.
+ fn write_from_file_region(
+ &self,
+ path: &Path,
+ region: &str,
+ layout: &Path,
+ ) -> Result<bool, FlashromError>;
- let (stdout, _) = cmd.dispatch(opts)?;
- let output = String::from_utf8_lossy(stdout.as_slice());
- debug!("erase():\n{}", output);
- Ok(())
-}
+ /// Verify the whole flash against the file specified by `path`.
+ fn verify_from_file(&self, path: &Path) -> Result<(), FlashromError>;
-#[cfg(test)]
-mod tests {
- #[test]
- fn extract_flash_name() {
- use super::extract_flash_name;
+ /// Verify only the region against the file specified by `path`.
+ /// Note the first byte in the file is matched against the first byte of the region.
+ fn verify_region_from_file(&self, path: &Path, region: &str) -> Result<(), FlashromError>;
- assert_eq!(
- extract_flash_name(
- "coreboot table found at 0x7cc13000\n\
- Found chipset \"Intel Braswell\". Enabling flash write... OK.\n\
- vendor=\"Winbond\" name=\"W25Q64DW\"\n"
- ),
- Some(("Winbond", "W25Q64DW"))
- );
+ /// Erase the whole flash.
+ fn erase(&self) -> Result<(), FlashromError>;
- assert_eq!(
- extract_flash_name(
- "vendor name is TEST\n\
- Something failed!"
- ),
- None
- )
- }
+ /// Return true if the hardware write protect of this flash can be controlled.
+ fn can_control_hw_wp(&self) -> bool;
}
diff --git a/util/flashrom_tester/src/cros_sysinfo.rs b/util/flashrom_tester/src/cros_sysinfo.rs
index ddb080265..37e1ec659 100644
--- a/util/flashrom_tester/src/cros_sysinfo.rs
+++ b/util/flashrom_tester/src/cros_sysinfo.rs
@@ -34,7 +34,7 @@
//
use std::ffi::OsStr;
-use std::fmt::Debug;
+use std::fs;
use std::io::Result as IoResult;
use std::process::{Command, Stdio};
@@ -60,21 +60,11 @@ pub fn bios_info() -> IoResult<String> {
dmidecode_dispatch(&["-q", "-t0"])
}
-pub fn eventlog_list() -> Result<String, std::io::Error> {
- mosys_dispatch(&["eventlog", "list"])
-}
-
-fn mosys_dispatch<S: AsRef<OsStr> + Debug>(args: &[S]) -> IoResult<String> {
- info!("mosys_dispatch() running: /usr/sbin/mosys {:?}", args);
-
- let output = Command::new("/usr/sbin/mosys")
- .args(args)
- .stdin(Stdio::null())
- .output()?;
- if !output.status.success() {
- return Err(utils::translate_command_error(&output));
+pub fn release_description() -> IoResult<String> {
+ for l in fs::read_to_string("/etc/lsb-release")?.lines() {
+ if l.starts_with("CHROMEOS_RELEASE_DESCRIPTION") {
+ return Ok(l.to_string());
+ }
}
-
- let stdout = String::from_utf8_lossy(&output.stdout).into_owned();
- Ok(stdout)
+ Err(std::io::ErrorKind::NotFound.into())
}
diff --git a/util/flashrom_tester/src/logger.rs b/util/flashrom_tester/src/logger.rs
index e1c00f5de..c9c364066 100644
--- a/util/flashrom_tester/src/logger.rs
+++ b/util/flashrom_tester/src/logger.rs
@@ -35,105 +35,81 @@
use flashrom_tester::types;
use std::io::Write;
-use std::path::PathBuf;
-use std::sync::Mutex;
-struct Logger<W: Write + Send> {
+struct Logger {
level: log::LevelFilter,
- target: LogTarget<W>,
+ color: types::Color,
}
-enum LogTarget<W>
-where
- W: Write,
-{
- Terminal,
- Write(Mutex<W>),
-}
-
-impl<W: Write + Send> log::Log for Logger<W> {
+impl log::Log for Logger {
fn enabled(&self, metadata: &log::Metadata) -> bool {
metadata.level() <= self.level
}
fn log(&self, record: &log::Record) {
- fn log_internal<W: Write>(mut w: W, record: &log::Record) -> std::io::Result<()> {
- let now = chrono::Local::now();
- write!(w, "{}{} ", types::MAGENTA, now.format("%Y-%m-%dT%H:%M:%S"))?;
- write!(
- w,
- "{}[ {} ]{} ",
- types::YELLOW,
- record.level(),
- types::RESET
- )?;
- writeln!(w, "{}", record.args())
- }
-
// Write errors deliberately ignored
- let _ = match self.target {
- LogTarget::Terminal => {
- let stdout = std::io::stdout();
- let mut lock = stdout.lock();
- log_internal(&mut lock, record)
- }
- LogTarget::Write(ref mutex) => {
- let mut lock = mutex.lock().unwrap();
- log_internal(&mut *lock, record)
- }
- };
+ let stdout = std::io::stdout();
+ let mut lock = stdout.lock();
+ let now = chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Micros, true);
+ let _ = write!(lock, "{}{} ", self.color.magenta, now);
+ let _ = write!(
+ lock,
+ "{}[ {} ]{} ",
+ self.color.yellow,
+ record.level(),
+ self.color.reset
+ );
+ let _ = writeln!(lock, "{}", record.args());
}
fn flush(&self) {
// Flush errors deliberately ignored
- let _ = match self.target {
- LogTarget::Terminal => std::io::stdout().flush(),
- LogTarget::Write(ref w) => w.lock().unwrap().flush(),
- };
+ let _ = std::io::stdout().flush();
}
}
-pub fn init(to_file: Option<PathBuf>, debug: bool) {
+pub fn init(debug: bool) {
let mut logger = Logger {
level: log::LevelFilter::Info,
- target: LogTarget::Terminal,
+ color: if atty::is(atty::Stream::Stdout) {
+ types::COLOR
+ } else {
+ types::NOCOLOR
+ },
};
if debug {
logger.level = log::LevelFilter::Debug;
}
- if let Some(path) = to_file {
- logger.target = LogTarget::Write(Mutex::new(
- std::fs::File::create(path).expect("Unable to open log file for writing"),
- ));
- }
-
log::set_max_level(logger.level);
log::set_boxed_logger(Box::new(logger)).unwrap();
}
#[cfg(test)]
mod tests {
- use super::{LogTarget, Logger};
+ use std::io::Read;
+
+ use super::Logger;
+ use flashrom_tester::types;
use log::{Level, LevelFilter, Log, Record};
- use std::sync::Mutex;
fn run_records(records: &[Record]) -> String {
- let mut buf = Vec::<u8>::new();
+ let buf = gag::BufferRedirect::stdout().unwrap();
{
- let lock = Mutex::new(&mut buf);
let logger = Logger {
level: LevelFilter::Info,
- target: LogTarget::Write(lock),
+ color: types::COLOR,
};
for record in records {
if logger.enabled(record.metadata()) {
- logger.log(&record);
+ logger.log(record);
}
}
}
- String::from_utf8(buf).unwrap()
+ let mut ret = String::new();
+ buf.into_inner().read_to_string(&mut ret).unwrap();
+ ret
}
/// Log messages have the expected format
@@ -146,9 +122,10 @@ mod tests {
assert_eq!(&buf[..5], "\x1b[35m");
// Time is difficult to test, assume it's formatted okay
+ // Split on the UTC timezone char
assert_eq!(
- &buf[24..],
- " \x1b[33m[ INFO ]\x1b[0m Test message at INFO\n"
+ buf.split_once("Z ").unwrap().1,
+ "\x1b[33m[ INFO ]\x1b[0m Test message at INFO\n"
);
}
diff --git a/util/flashrom_tester/src/main.rs b/util/flashrom_tester/src/main.rs
index 1cc525e62..b8a2581ac 100644
--- a/util/flashrom_tester/src/main.rs
+++ b/util/flashrom_tester/src/main.rs
@@ -39,9 +39,9 @@ extern crate log;
mod logger;
use clap::{App, Arg};
-use flashrom::FlashChip;
+use flashrom::{FlashChip, Flashrom, FlashromCmd, FlashromLib};
use flashrom_tester::{tester, tests};
-use std::path::PathBuf;
+use std::sync::atomic::AtomicBool;
pub mod built_info {
include!(concat!(env!("OUT_DIR"), "/built.rs"));
@@ -64,11 +64,25 @@ fn main() {
built_info::BUILT_TIME_UTC,
built_info::RUSTC_VERSION,
))
- .arg(Arg::with_name("flashrom_binary").required(true))
+ .arg(
+ Arg::with_name("libflashrom")
+ .long("libflashrom")
+ .takes_value(false)
+ .help("Test the flashrom library instead of a binary"),
+ )
+ .arg(
+ Arg::with_name("flashrom_binary")
+ .long("flashrom_binary")
+ .short("b")
+ .takes_value(true)
+ .required_unless("libflashrom")
+ .conflicts_with("libflashrom")
+ .help("Path to flashrom binary to test"),
+ )
.arg(
Arg::with_name("ccd_target_type")
.required(true)
- .possible_values(&["host", "ec", "servo"]),
+ .possible_values(&["host"]),
)
.arg(
Arg::with_name("print-layout")
@@ -77,13 +91,6 @@ fn main() {
.help("Print the layout file's contents before running tests"),
)
.arg(
- Arg::with_name("log-file")
- .short("o")
- .long("log-file")
- .takes_value(true)
- .help("Write logs to a file rather than stdout"),
- )
- .arg(
Arg::with_name("log_debug")
.short("d")
.long("debug")
@@ -106,15 +113,13 @@ fn main() {
)
.get_matches();
- logger::init(
- matches.value_of_os("log-file").map(PathBuf::from),
- matches.is_present("log_debug"),
- );
+ logger::init(matches.is_present("log_debug"));
debug!("Args parsed and logging initialized OK");
- let flashrom_path = matches
- .value_of("flashrom_binary")
- .expect("flashrom_binary should be required");
+ debug!("Collecting crossystem info");
+ let crossystem =
+ flashrom_tester::utils::collect_crosssystem(&[]).expect("could not run crossystem");
+
let ccd_type = FlashChip::from(
matches
.value_of("ccd_target_type")
@@ -122,6 +127,25 @@ fn main() {
)
.expect("ccd_target_type should admit only known types");
+ let cmd: Box<dyn Flashrom> = if matches.is_present("libflashrom") {
+ Box::new(FlashromLib::new(
+ ccd_type,
+ if matches.is_present("log_debug") {
+ flashrom::FLASHROM_MSG_DEBUG
+ } else {
+ flashrom::FLASHROM_MSG_WARN
+ },
+ ))
+ } else {
+ Box::new(FlashromCmd {
+ path: matches
+ .value_of("flashrom_binary")
+ .expect("flashrom_binary is required")
+ .to_string(),
+ fc: ccd_type,
+ })
+ };
+
let print_layout = matches.is_present("print-layout");
let output_format = matches
.value_of("output-format")
@@ -131,13 +155,57 @@ fn main() {
let test_names = matches.values_of("test_name");
if let Err(e) = tests::generic(
- flashrom_path,
+ cmd.as_ref(),
ccd_type,
print_layout,
output_format,
test_names,
+ Some(handle_sigint()),
+ crossystem,
) {
eprintln!("Failed to run tests: {:?}", e);
std::process::exit(1);
}
}
+
+/// Catch exactly one SIGINT, printing a message in response and setting a flag.
+///
+/// The returned value is false by default, becoming true after a SIGINT is
+/// trapped.
+///
+/// Once a signal is trapped, the default behavior is restored (terminating
+/// the process) for future signals.
+fn handle_sigint() -> &'static AtomicBool {
+ use libc::c_int;
+ use std::sync::atomic::Ordering;
+
+ unsafe {
+ let _ = libc::signal(libc::SIGINT, sigint_handler as libc::sighandler_t);
+ }
+ static TERMINATE_FLAG: AtomicBool = AtomicBool::new(false);
+
+ extern "C" fn sigint_handler(_: c_int) {
+ const STDERR_FILENO: c_int = 2;
+ static MESSAGE: &[u8] = b"
+WARNING: terminating tests prematurely may leave Flash in an inconsistent state,
+rendering your machine unbootable. Testing will end on completion of the current
+test, or press ^C again to exit immediately (possibly bricking your machine).
+";
+
+ // Use raw write() because signal-safety is a very hard problem. Safe because this doesn't
+ // modify any memory.
+ let _ = unsafe {
+ libc::write(
+ STDERR_FILENO,
+ MESSAGE.as_ptr() as *const libc::c_void,
+ MESSAGE.len() as libc::size_t,
+ )
+ };
+ unsafe {
+ let _ = libc::signal(libc::SIGINT, libc::SIG_DFL);
+ }
+ TERMINATE_FLAG.store(true, Ordering::Release);
+ }
+
+ &TERMINATE_FLAG
+}
diff --git a/util/flashrom_tester/src/rand_util.rs b/util/flashrom_tester/src/rand_util.rs
index 51411d0d5..a040c89a3 100644
--- a/util/flashrom_tester/src/rand_util.rs
+++ b/util/flashrom_tester/src/rand_util.rs
@@ -36,15 +36,14 @@
use std::fs::File;
use std::io::prelude::*;
use std::io::BufWriter;
+use std::path::Path;
use rand::prelude::*;
-pub fn gen_rand_testdata(path: &str, size: usize) -> std::io::Result<()> {
+pub fn gen_rand_testdata(path: &Path, size: usize) -> std::io::Result<()> {
let mut buf = BufWriter::new(File::create(path)?);
- let mut a: Vec<u8> = Vec::with_capacity(size);
- // Pad out array to be filled in by Rng::fill().
- a.resize(size, 0b0);
+ let mut a: Vec<u8> = vec![0; size];
thread_rng().fill(a.as_mut_slice());
buf.write_all(a.as_slice())?;
@@ -60,8 +59,8 @@ mod tests {
fn gen_rand_testdata() {
use super::gen_rand_testdata;
- let path0 = "/tmp/idk_test00";
- let path1 = "/tmp/idk_test01";
+ let path0 = Path::new("/tmp/idk_test00");
+ let path1 = Path::new("/tmp/idk_test01");
let sz = 1024;
gen_rand_testdata(path0, sz).unwrap();
diff --git a/util/flashrom_tester/src/tester.rs b/util/flashrom_tester/src/tester.rs
index fbef2016e..4629c2eb7 100644
--- a/util/flashrom_tester/src/tester.rs
+++ b/util/flashrom_tester/src/tester.rs
@@ -36,10 +36,14 @@
use super::rand_util;
use super::types;
use super::utils::{self, LayoutSizes};
-use flashrom::{FlashChip, Flashrom, FlashromCmd};
+use flashrom::FlashromError;
+use flashrom::{FlashChip, Flashrom};
use serde_json::json;
-use std::mem::MaybeUninit;
-use std::sync::Mutex;
+use std::fs::File;
+use std::io::Write;
+use std::path::Path;
+use std::path::PathBuf;
+use std::sync::atomic::{AtomicBool, Ordering};
// type-signature comes from the return type of lib.rs workers.
type TestError = Box<dyn std::error::Error>;
@@ -51,33 +55,38 @@ pub struct TestEnv<'a> {
///
/// Where possible, prefer to use methods on the TestEnv rather than delegating
/// to the raw flashrom functions.
- pub cmd: &'a FlashromCmd,
+ pub cmd: &'a dyn Flashrom,
layout: LayoutSizes,
- pub wp: WriteProtectState<'a, 'static>,
+ pub wp: WriteProtectState<'a>,
/// The path to a file containing the flash contents at test start.
- // TODO(pmarheine) migrate this to a PathBuf for clarity
- original_flash_contents: String,
+ original_flash_contents: PathBuf,
/// The path to a file containing flash-sized random data
- // TODO(pmarheine) make this a PathBuf too
- random_data: String,
+ random_data: PathBuf,
+ /// The path to a file containing layout data.
+ pub layout_file: PathBuf,
}
impl<'a> TestEnv<'a> {
- pub fn create(chip_type: FlashChip, cmd: &'a FlashromCmd) -> Result<Self, String> {
+ pub fn create(
+ chip_type: FlashChip,
+ cmd: &'a dyn Flashrom,
+ print_layout: bool,
+ ) -> Result<Self, FlashromError> {
let rom_sz = cmd.get_size()?;
let out = TestEnv {
- chip_type: chip_type,
- cmd: cmd,
+ chip_type,
+ cmd,
layout: utils::get_layout_sizes(rom_sz)?,
- wp: WriteProtectState::from_hardware(cmd)?,
+ wp: WriteProtectState::from_hardware(cmd, chip_type)?,
original_flash_contents: "/tmp/flashrom_tester_golden.bin".into(),
random_data: "/tmp/random_content.bin".into(),
+ layout_file: create_layout_file(rom_sz, Path::new("/tmp/"), print_layout),
};
info!("Stashing golden image for verification/recovery on completion");
- flashrom::read(&out.cmd, &out.original_flash_contents)?;
- flashrom::verify(&out.cmd, &out.original_flash_contents)?;
+ out.cmd.read_into_file(&out.original_flash_contents)?;
+ out.cmd.verify_from_file(&out.original_flash_contents)?;
info!("Generating random flash-sized data");
rand_util::gen_rand_testdata(&out.random_data, rom_sz as usize)
@@ -87,19 +96,10 @@ impl<'a> TestEnv<'a> {
}
pub fn run_test<T: TestCase>(&mut self, test: T) -> TestResult {
- let use_dut_control = self.chip_type == FlashChip::SERVO;
- if use_dut_control && flashrom::dut_ctrl_toggle_wp(false).is_err() {
- error!("failed to dispatch dut_ctrl_toggle_wp()!");
- }
-
let name = test.get_name();
info!("Beginning test: {}", name);
let out = test.run(self);
info!("Completed test: {}; result {:?}", name, out);
-
- if use_dut_control && flashrom::dut_ctrl_toggle_wp(true).is_err() {
- error!("failed to dispatch dut_ctrl_toggle_wp()!");
- }
out
}
@@ -111,7 +111,7 @@ impl<'a> TestEnv<'a> {
/// Return the path to a file that contains random data and is the same size
/// as the flash chip.
- pub fn random_data_file(&self) -> &str {
+ pub fn random_data_file(&self) -> &Path {
&self.random_data
}
@@ -122,31 +122,36 @@ impl<'a> TestEnv<'a> {
/// Return true if the current Flash contents are the same as the golden image
/// that was present at the start of testing.
pub fn is_golden(&self) -> bool {
- flashrom::verify(&self.cmd, &self.original_flash_contents).is_ok()
+ self.cmd
+ .verify_from_file(&self.original_flash_contents)
+ .is_ok()
}
/// Do whatever is necessary to make the current Flash contents the same as they
/// were at the start of testing.
- pub fn ensure_golden(&mut self) -> Result<(), String> {
+ pub fn ensure_golden(&mut self) -> Result<(), FlashromError> {
self.wp.set_hw(false)?.set_sw(false)?;
- flashrom::write(&self.cmd, &self.original_flash_contents)
+ self.cmd.write_from_file(&self.original_flash_contents)?;
+ Ok(())
}
/// Attempt to erase the flash.
- pub fn erase(&self) -> Result<(), String> {
- flashrom::erase(self.cmd)
+ pub fn erase(&self) -> Result<(), FlashromError> {
+ self.cmd.erase()?;
+ Ok(())
}
/// Verify that the current Flash contents are the same as the file at the given
/// path.
///
/// Returns Err if they are not the same.
- pub fn verify(&self, contents_path: &str) -> Result<(), String> {
- flashrom::verify(self.cmd, contents_path)
+ pub fn verify(&self, contents_path: &Path) -> Result<(), FlashromError> {
+ self.cmd.verify_from_file(contents_path)?;
+ Ok(())
}
}
-impl Drop for TestEnv<'_> {
+impl<'a> Drop for TestEnv<'a> {
fn drop(&mut self) {
info!("Verifying flash remains unmodified");
if !self.is_golden() {
@@ -158,70 +163,41 @@ impl Drop for TestEnv<'_> {
}
}
+struct WriteProtect {
+ hw: bool,
+ sw: bool,
+}
+
/// RAII handle for setting write protect in either hardware or software.
///
/// Given an instance, the state of either write protect can be modified by calling
-/// `set` or `push`. When it goes out of scope, the write protects will be returned
+/// `set`. When it goes out of scope, the write protects will be returned
/// to the state they had then it was created.
-///
-/// The lifetime `'p` on this struct is the parent state it derives from; `'static`
-/// implies it is derived from hardware, while anything else is part of a stack
-/// created by `push`ing states. An initial state is always static, and the stack
-/// forms a lifetime chain `'static -> 'p -> 'p1 -> ... -> 'pn`.
-pub struct WriteProtectState<'a, 'p> {
- /// The parent state this derives from.
- ///
- /// If it's a root (gotten via `from_hardware`), then this is Hardware and the
- /// liveness flag will be reset on drop.
- initial: InitialState<'p>,
- // Tuples are (hardware, software)
- current: (bool, bool),
- cmd: &'a FlashromCmd,
-}
-
-enum InitialState<'p> {
- Hardware(bool, bool),
- Previous(&'p WriteProtectState<'p, 'p>),
-}
-
-impl InitialState<'_> {
- fn get_target(&self) -> (bool, bool) {
- match self {
- InitialState::Hardware(hw, sw) => (*hw, *sw),
- InitialState::Previous(s) => s.current,
- }
- }
+pub struct WriteProtectState<'a> {
+ current: WriteProtect,
+ initial: WriteProtect,
+ cmd: &'a dyn Flashrom,
+ fc: FlashChip,
}
-impl<'a> WriteProtectState<'a, 'static> {
+impl<'a> WriteProtectState<'a> {
/// Initialize a state from the current state of the hardware.
- ///
- /// Panics if there is already a live state derived from hardware. In such a situation the
- /// new state must be derived from the live one, or the live one must be dropped first.
- pub fn from_hardware(cmd: &'a FlashromCmd) -> Result<Self, String> {
- let mut lock = Self::get_liveness_lock()
- .lock()
- .expect("Somebody panicked during WriteProtectState init from hardware");
- if *lock {
- drop(lock); // Don't poison the lock
- panic!("Attempted to create a new WriteProtectState when one is already live");
- }
-
+ pub fn from_hardware(cmd: &'a dyn Flashrom, fc: FlashChip) -> Result<Self, FlashromError> {
let hw = Self::get_hw(cmd)?;
let sw = Self::get_sw(cmd)?;
- info!("Initial hardware write protect: HW={} SW={}", hw, sw);
+ info!("Initial write protect state: HW={} SW={}", hw, sw);
- *lock = true;
Ok(WriteProtectState {
- initial: InitialState::Hardware(hw, sw),
- current: (hw, sw),
+ current: WriteProtect { hw, sw },
+ initial: WriteProtect { hw, sw },
cmd,
+ fc,
})
}
/// Get the actual hardware write protect state.
- fn get_hw(cmd: &FlashromCmd) -> Result<bool, String> {
- if cmd.fc.can_control_hw_wp() {
+ fn get_hw(cmd: &dyn Flashrom) -> Result<bool, String> {
+ if cmd.can_control_hw_wp() {
super::utils::get_hardware_wp()
} else {
Ok(false)
@@ -229,98 +205,78 @@ impl<'a> WriteProtectState<'a, 'static> {
}
/// Get the actual software write protect state.
- fn get_sw(cmd: &FlashromCmd) -> Result<bool, String> {
- flashrom::wp_status(cmd, true)
+ fn get_sw(cmd: &dyn Flashrom) -> Result<bool, FlashromError> {
+ let b = cmd.wp_status(true)?;
+ Ok(b)
}
-}
-impl<'a, 'p> WriteProtectState<'a, 'p> {
/// Return true if the current programmer supports setting the hardware
/// write protect.
///
/// If false, calls to set_hw() will do nothing.
pub fn can_control_hw_wp(&self) -> bool {
- self.cmd.fc.can_control_hw_wp()
+ self.cmd.can_control_hw_wp()
}
- /// Set the software write protect.
+ /// Set the software write protect and check that the state is as expected.
pub fn set_sw(&mut self, enable: bool) -> Result<&mut Self, String> {
- info!("request={}, current={}", enable, self.current.1);
- if self.current.1 != enable {
- flashrom::wp_toggle(self.cmd, /* en= */ enable)?;
- self.current.1 = enable;
+ info!("set_sw request={}, current={}", enable, self.current.sw);
+ if self.current.sw != enable {
+ self.cmd
+ .wp_toggle(/* en= */ enable)
+ .map_err(|e| e.to_string())?;
}
- Ok(self)
- }
-
- /// Set the hardware write protect.
- pub fn set_hw(&mut self, enable: bool) -> Result<&mut Self, String> {
- if self.current.0 != enable {
- if self.can_control_hw_wp() {
- super::utils::toggle_hw_wp(/* dis= */ !enable)?;
- self.current.0 = enable;
- } else if enable {
- info!(
- "Ignoring attempt to enable hardware WP with {:?} programmer",
- self.cmd.fc
- );
- }
+ if Self::get_sw(self.cmd).map_err(|e| e.to_string())? != enable {
+ Err(format!(
+ "Software write protect did not change state to {} when requested",
+ enable
+ ))
+ } else {
+ self.current.sw = enable;
+ Ok(self)
}
- Ok(self)
}
- /// Stack a new write protect state on top of the current one.
- ///
- /// This is useful if you need to temporarily make a change to write protection:
- ///
- /// ```no_run
- /// # fn main() -> Result<(), String> {
- /// # let cmd: flashrom::FlashromCmd = unimplemented!();
- /// let wp = flashrom_tester::tester::WriteProtectState::from_hardware(&cmd)?;
- /// {
- /// let mut wp = wp.push();
- /// wp.set_sw(false)?;
- /// // Do something with software write protect disabled
- /// }
- /// // Now software write protect returns to its original state, even if
- /// // set_sw() failed.
- /// # Ok(())
- /// # }
- /// ```
- ///
- /// This returns a new state which restores the original when it is dropped- the new state
- /// refers to the old, so the compiler enforces that states are disposed of in the reverse
- /// order of their creation and correctly restore the original state.
- pub fn push<'p1>(&'p1 self) -> WriteProtectState<'a, 'p1> {
- WriteProtectState {
- initial: InitialState::Previous(self),
- current: self.current,
- cmd: self.cmd,
+ // Set software write protect with a custom range
+ pub fn set_range(&mut self, range: (i64, i64), enable: bool) -> Result<&mut Self, String> {
+ info!("set_range request={}, current={}", enable, self.current.sw);
+ self.cmd
+ .wp_range(range, enable)
+ .map_err(|e| e.to_string())?;
+ let actual_state = Self::get_sw(self.cmd).map_err(|e| e.to_string())?;
+ if actual_state != enable {
+ Err(format!(
+ "set_range request={}, real={}",
+ enable, actual_state
+ ))
+ } else {
+ self.current.sw = enable;
+ Ok(self)
}
}
- fn get_liveness_lock() -> &'static Mutex<bool> {
- static INIT: std::sync::Once = std::sync::Once::new();
- /// Value becomes true when there is a live WriteProtectState derived `from_hardware`,
- /// blocking duplicate initialization.
- ///
- /// This is required because hardware access is not synchronized; it's possible to leave the
- /// hardware in an unintended state by creating a state handle from it, modifying the state,
- /// creating another handle from the hardware then dropping the first handle- then on drop
- /// of the second handle it will restore the state to the modified one rather than the initial.
- ///
- /// This flag ensures that a duplicate root state cannot be created.
- ///
- /// This is a Mutex<bool> rather than AtomicBool because acquiring the flag needs to perform
- /// several operations that may themselves fail- acquisitions must be fully synchronized.
- static mut LIVE_FROM_HARDWARE: MaybeUninit<Mutex<bool>> = MaybeUninit::uninit();
-
- unsafe {
- INIT.call_once(|| {
- LIVE_FROM_HARDWARE.as_mut_ptr().write(Mutex::new(false));
- });
- &*LIVE_FROM_HARDWARE.as_ptr()
+ /// Set the hardware write protect if supported and check that the state is as expected.
+ pub fn set_hw(&mut self, enable: bool) -> Result<&mut Self, String> {
+ info!("set_hw request={}, current={}", enable, self.current.hw);
+ if self.can_control_hw_wp() {
+ if self.current.hw != enable {
+ super::utils::toggle_hw_wp(/* dis= */ !enable)?;
+ }
+ // toggle_hw_wp does check this, but we might not have called toggle_hw_wp so check again.
+ if Self::get_hw(self.cmd)? != enable {
+ return Err(format!(
+ "Hardware write protect did not change state to {} when requested",
+ enable
+ ));
+ }
+ } else {
+ info!(
+ "Ignoring attempt to set hardware WP with {:?} programmer",
+ self.fc
+ );
}
+ self.current.hw = enable;
+ Ok(self)
}
/// Reset the hardware to what it was when this state was created, reporting errors.
@@ -328,91 +284,30 @@ impl<'a, 'p> WriteProtectState<'a, 'p> {
/// This behaves exactly like allowing a state to go out of scope, but it can return
/// errors from that process rather than panicking.
pub fn close(mut self) -> Result<(), String> {
- unsafe {
- let out = self.drop_internal();
- // We just ran drop, don't do it again
- std::mem::forget(self);
- out
- }
+ let out = self.drop_internal();
+ // We just ran drop, don't do it again
+ std::mem::forget(self);
+ out
}
- /// Internal Drop impl.
- ///
- /// This is unsafe because it effectively consumes self when clearing the
- /// liveness lock. Callers must be able to guarantee that self will be forgotten
- /// if the state was constructed from hardware in order to uphold the liveness
- /// invariant (that only a single state constructed from hardware exists at any
- /// time).
- unsafe fn drop_internal(&mut self) -> Result<(), String> {
- let lock = match self.initial {
- InitialState::Hardware(_, _) => Some(
- Self::get_liveness_lock()
- .lock()
- .expect("Somebody panicked during WriteProtectState drop from hardware"),
- ),
- _ => None,
- };
- let (hw, sw) = self.initial.get_target();
-
- fn enable_str(enable: bool) -> &'static str {
- if enable {
- "en"
- } else {
- "dis"
- }
- }
-
+ /// Sets both write protects to the state they had when this state was created.
+ fn drop_internal(&mut self) -> Result<(), String> {
// Toggle both protects back to their initial states.
// Software first because we can't change it once hardware is enabled.
- if sw != self.current.1 {
- // Is the hw wp currently enabled?
- if self.current.0 {
- super::utils::toggle_hw_wp(/* dis= */ true).map_err(|e| {
- format!(
- "Failed to {}able hardware write protect: {}",
- enable_str(false),
- e
- )
- })?;
- }
- flashrom::wp_toggle(self.cmd, /* en= */ sw).map_err(|e| {
- format!(
- "Failed to {}able software write protect: {}",
- enable_str(sw),
- e
- )
- })?;
- }
-
- assert!(
- self.cmd.fc.can_control_hw_wp() || (!self.current.0 && !hw),
- "HW WP must be disabled if it cannot be controlled"
- );
- if hw != self.current.0 {
- super::utils::toggle_hw_wp(/* dis= */ !hw).map_err(|e| {
- format!(
- "Failed to {}able hardware write protect: {}",
- enable_str(hw),
- e
- )
- })?;
+ if self.set_sw(self.initial.sw).is_err() {
+ self.set_hw(false)?;
+ self.set_sw(self.initial.sw)?;
}
+ self.set_hw(self.initial.hw)?;
- if let Some(mut lock) = lock {
- // Initial state was constructed via from_hardware, now we can clear the liveness
- // lock since reset is complete.
- *lock = false;
- }
Ok(())
}
}
-impl<'a, 'p> Drop for WriteProtectState<'a, 'p> {
- /// Sets both write protects to the state they had when this state was created.
- ///
- /// Panics on error because there is no mechanism to report errors in Drop.
+impl<'a> Drop for WriteProtectState<'a> {
fn drop(&mut self) {
- unsafe { self.drop_internal() }.expect("Error while dropping WriteProtectState")
+ self.drop_internal()
+ .expect("Error while dropping WriteProtectState")
}
}
@@ -451,7 +346,7 @@ impl<T: TestCase + ?Sized> TestCase for &T {
}
#[allow(dead_code)]
-#[derive(Copy, Clone, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum TestConclusion {
Pass,
Fail,
@@ -462,6 +357,7 @@ pub enum TestConclusion {
pub struct ReportMetaData {
pub chip_name: String,
pub os_release: String,
+ pub cros_release: String,
pub system_info: String,
pub bios_info: String,
}
@@ -476,26 +372,55 @@ fn decode_test_result(res: TestResult, con: TestConclusion) -> (TestConclusion,
}
}
+fn create_layout_file(rom_sz: i64, tmp_dir: &Path, print_layout: bool) -> PathBuf {
+ info!("Calculate ROM partition sizes & Create the layout file.");
+ let layout_sizes = utils::get_layout_sizes(rom_sz).expect("Could not partition rom");
+
+ let layout_file = tmp_dir.join("layout.file");
+ let mut f = File::create(&layout_file).expect("Could not create layout file");
+ let mut buf: Vec<u8> = vec![];
+ utils::construct_layout_file(&mut buf, &layout_sizes).expect("Could not construct layout file");
+
+ f.write_all(&buf).expect("Writing layout file failed");
+ if print_layout {
+ info!(
+ "Dumping layout file as requested:\n{}",
+ String::from_utf8_lossy(&buf)
+ );
+ }
+ layout_file
+}
+
pub fn run_all_tests<T, TS>(
chip: FlashChip,
- cmd: &FlashromCmd,
+ cmd: &dyn Flashrom,
ts: TS,
+ terminate_flag: Option<&AtomicBool>,
+ print_layout: bool,
) -> Vec<(String, (TestConclusion, Option<TestError>))>
where
T: TestCase + Copy,
TS: IntoIterator<Item = T>,
{
- let mut env = TestEnv::create(chip, cmd).expect("Failed to set up test environment");
+ let mut env =
+ TestEnv::create(chip, cmd, print_layout).expect("Failed to set up test environment");
let mut results = Vec::new();
for t in ts {
+ if terminate_flag
+ .map(|b| b.load(Ordering::Acquire))
+ .unwrap_or(false)
+ {
+ break;
+ }
+
let result = decode_test_result(env.run_test(t), t.expected_result());
results.push((t.get_name().into(), result));
}
results
}
-#[derive(Debug, PartialEq, Clone, Copy)]
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum OutputFormat {
Pretty,
Json,
@@ -524,6 +449,11 @@ pub fn collate_all_test_runs(
) {
match format {
OutputFormat::Pretty => {
+ let color = if atty::is(atty::Stream::Stdout) {
+ types::COLOR
+ } else {
+ types::NOCOLOR
+ };
println!();
println!(" =============================");
println!(" ===== AVL qual RESULTS ====");
@@ -531,6 +461,7 @@ pub fn collate_all_test_runs(
println!();
println!(" %---------------------------%");
println!(" os release: {}", meta_data.os_release);
+ println!(" cros release: {}", meta_data.cros_release);
println!(" chip name: {}", meta_data.chip_name);
println!(" system info: \n{}", meta_data.system_info);
println!(" bios info: \n{}", meta_data.bios_info);
@@ -542,8 +473,8 @@ pub fn collate_all_test_runs(
if *result != TestConclusion::Pass {
println!(
" {} {}",
- style!(format!(" <+> {} test:", name), types::BOLD),
- style_dbg!(result, types::RED)
+ style!(format!(" <+> {} test:", name), color.bold, color),
+ style_dbg!(result, color.red, color)
);
match error {
None => {}
@@ -552,8 +483,8 @@ pub fn collate_all_test_runs(
} else {
println!(
" {} {}",
- style!(format!(" <+> {} test:", name), types::BOLD),
- style_dbg!(result, types::GREEN)
+ style!(format!(" <+> {} test:", name), color.bold, color),
+ style_dbg!(result, color.green, color)
);
}
}
diff --git a/util/flashrom_tester/src/tests.rs b/util/flashrom_tester/src/tests.rs
index dd756893d..721a789d5 100644
--- a/util/flashrom_tester/src/tests.rs
+++ b/util/flashrom_tester/src/tests.rs
@@ -36,12 +36,15 @@
use super::cros_sysinfo;
use super::tester::{self, OutputFormat, TestCase, TestEnv, TestResult};
use super::utils::{self, LayoutNames};
-use flashrom::{FlashChip, Flashrom, FlashromCmd};
+use flashrom::{FlashChip, Flashrom};
use std::collections::{HashMap, HashSet};
-use std::fs::File;
-use std::io::{BufRead, Write};
+use std::convert::TryInto;
+use std::fs::{self, File};
+use std::io::BufRead;
+use std::sync::atomic::AtomicBool;
-const LAYOUT_FILE: &'static str = "/tmp/layout.file";
+const ELOG_FILE: &str = "/tmp/elog.file";
+const FW_MAIN_B_PATH: &str = "/tmp/FW_MAIN_B.bin";
/// Iterate over tests, yielding only those tests with names matching filter_names.
///
@@ -76,49 +79,29 @@ fn filter_tests<'n, 't: 'n, T: TestCase>(
/// test_names is the case-insensitive names of tests to run; if None, then all
/// tests are run. Provided names that don't match any known test will be logged
/// as a warning.
+#[allow(clippy::or_fun_call)] // This is used for to_string here and we don't care.
pub fn generic<'a, TN: Iterator<Item = &'a str>>(
- path: &str,
+ cmd: &dyn Flashrom,
fc: FlashChip,
print_layout: bool,
output_format: OutputFormat,
test_names: Option<TN>,
+ terminate_flag: Option<&AtomicBool>,
+ crossystem: String,
) -> Result<(), Box<dyn std::error::Error>> {
- let p = path.to_string();
- let cmd = FlashromCmd { path: p, fc };
-
utils::ac_power_warning();
- info!("Calculate ROM partition sizes & Create the layout file.");
- let rom_sz: i64 = cmd.get_size()?;
- let layout_sizes = utils::get_layout_sizes(rom_sz)?;
- {
- let mut f = File::create(LAYOUT_FILE)?;
- let mut buf: Vec<u8> = vec![];
- utils::construct_layout_file(&mut buf, &layout_sizes)?;
-
- f.write_all(&buf)?;
- if print_layout {
- info!(
- "Dumping layout file as requested:\n{}",
- String::from_utf8_lossy(&buf)
- );
- }
- }
-
- info!(
- "Record crossystem information.\n{}",
- utils::collect_crosssystem()?
- );
+ info!("Record crossystem information.\n{}", crossystem);
// Register tests to run:
let tests: &[&dyn TestCase] = &[
&("Get_device_name", get_device_name_test),
&("Coreboot_ELOG_sanity", elog_sanity_test),
&("Host_is_ChromeOS", host_is_chrome_test),
- &("Toggle_WP", wp_toggle_test),
+ &("WP_Region_List", wp_region_list_test),
&("Erase_and_Write", erase_write_test),
&("Fail_to_verify", verify_fail_test),
- &("Lock", lock_test),
+ &("HWWP_Locks_SWWP", hwwp_locks_swwp_test),
&("Lock_top_quad", partial_lock_test(LayoutNames::TopQuad)),
&(
"Lock_bottom_quad",
@@ -133,59 +116,60 @@ pub fn generic<'a, TN: Iterator<Item = &'a str>>(
// Limit the tests to only those requested, unless none are requested
// in which case all tests are included.
- let mut filter_names: Option<HashSet<String>> = if let Some(names) = test_names {
- Some(names.map(|s| s.to_lowercase()).collect())
- } else {
- None
- };
+ let mut filter_names: Option<HashSet<String>> =
+ test_names.map(|names| names.map(|s| s.to_lowercase()).collect());
let tests = filter_tests(tests, &mut filter_names);
+ let chip_name = cmd
+ .name()
+ .map(|x| format!("vendor=\"{}\" name=\"{}\"", x.0, x.1))
+ .unwrap_or("<Unknown chip>".into());
+
// ------------------------.
// Run all the tests and collate the findings:
- let results = tester::run_all_tests(fc, &cmd, tests);
+ let results = tester::run_all_tests(fc, cmd, tests, terminate_flag, print_layout);
// Any leftover filtered names were specified to be run but don't exist
for leftover in filter_names.iter().flatten() {
warn!("No test matches filter name \"{}\"", leftover);
}
- let chip_name = flashrom::name(&cmd)
- .map(|x| format!("vendor=\"{}\" name=\"{}\"", x.0, x.1))
- .unwrap_or("<Unknown chip>".into());
- let os_rel = sys_info::os_release().unwrap_or("<Unknown OS>".to_string());
+ let os_release = sys_info::os_release().unwrap_or("<Unknown OS>".to_string());
+ let cros_release = cros_sysinfo::release_description()
+ .unwrap_or("<Unknown or not a ChromeOS release>".to_string());
let system_info = cros_sysinfo::system_info().unwrap_or("<Unknown System>".to_string());
let bios_info = cros_sysinfo::bios_info().unwrap_or("<Unknown BIOS>".to_string());
let meta_data = tester::ReportMetaData {
- chip_name: chip_name,
- os_release: os_rel,
- system_info: system_info,
- bios_info: bios_info,
+ chip_name,
+ os_release,
+ cros_release,
+ system_info,
+ bios_info,
};
tester::collate_all_test_runs(&results, meta_data, output_format);
Ok(())
}
+/// Query the programmer and chip name.
+/// Success means we got something back, which is good enough.
fn get_device_name_test(env: &mut TestEnv) -> TestResult {
- // Success means we got something back, which is good enough.
- flashrom::name(env.cmd)?;
+ env.cmd.name()?;
Ok(())
}
-fn wp_toggle_test(env: &mut TestEnv) -> TestResult {
- // NOTE: This is not strictly a 'test' as it is allowed to fail on some platforms.
- // However, we will warn when it does fail.
- // List the write-protected regions of flash.
- match flashrom::wp_list(env.cmd) {
+/// List the write-protectable regions of flash.
+/// NOTE: This is not strictly a 'test' as it is allowed to fail on some platforms.
+/// However, we will warn when it does fail.
+fn wp_region_list_test(env: &mut TestEnv) -> TestResult {
+ match env.cmd.wp_list() {
Ok(list_str) => info!("\n{}", list_str),
Err(e) => warn!("{}", e),
};
- // Fails if unable to set either one
- env.wp.set_hw(false)?;
- env.wp.set_sw(false)?;
Ok(())
}
+/// Verify that enabling hardware and software write protect prevents chip erase.
fn erase_write_test(env: &mut TestEnv) -> TestResult {
if !env.is_golden() {
info!("Memory has been modified; reflashing to ensure erasure can be detected");
@@ -212,47 +196,53 @@ fn erase_write_test(env: &mut TestEnv) -> TestResult {
Ok(())
}
-fn lock_test(env: &mut TestEnv) -> TestResult {
+/// Verify that enabling hardware write protect prevents disabling software write protect.
+fn hwwp_locks_swwp_test(env: &mut TestEnv) -> TestResult {
if !env.wp.can_control_hw_wp() {
return Err("Lock test requires ability to control hardware write protect".into());
}
env.wp.set_hw(false)?.set_sw(true)?;
- // Toggling software WP off should work when hardware is off.
- // Then enable again for another go.
- env.wp.push().set_sw(false)?;
+ // Toggling software WP off should work when hardware WP is off.
+ // Then enable software WP again for the next test.
+ env.wp.set_sw(false)?.set_sw(true)?;
+ // Toggling software WP off should not work when hardware WP is on.
env.wp.set_hw(true)?;
- // Clearing should fail when hardware is enabled
if env.wp.set_sw(false).is_ok() {
return Err("Software WP was reset despite hardware WP being enabled".into());
}
Ok(())
}
+/// Check that the elog contains *something*, as an indication that Coreboot
+/// is actually able to write to the Flash. This only makes sense for chips
+/// running Coreboot, which we assume is just host.
fn elog_sanity_test(env: &mut TestEnv) -> TestResult {
- // Check that the elog contains *something*, as an indication that Coreboot
- // is actually able to write to the Flash. Because this invokes mosys on the
- // host, it doesn't make sense to run for other chips.
if env.chip_type() != FlashChip::HOST {
info!("Skipping ELOG sanity check for non-host chip");
return Ok(());
}
- // mosys reads the flash, it should be back in the golden state
+ // flash should be back in the golden state
env.ensure_golden()?;
- // Output is one event per line, drop empty lines in the interest of being defensive.
- let event_count = cros_sysinfo::eventlog_list()?
- .lines()
- .filter(|l| !l.is_empty())
- .count();
-
- if event_count == 0 {
- Err("ELOG contained no events".into())
- } else {
- Ok(())
+
+ const ELOG_RW_REGION_NAME: &str = "RW_ELOG";
+ env.cmd
+ .read_region_into_file(ELOG_FILE.as_ref(), ELOG_RW_REGION_NAME)?;
+
+ // Just checking for the magic numer
+ // TODO: improve this test to read the events
+ if fs::metadata(ELOG_FILE)?.len() < 4 {
+ return Err("ELOG contained no data".into());
+ }
+ let data = fs::read(ELOG_FILE)?;
+ if u32::from_le_bytes(data[0..4].try_into()?) != 0x474f4c45 {
+ return Err("ELOG had bad magic number".into());
}
+ Ok(())
}
+/// Check that we are running ChromiumOS.
fn host_is_chrome_test(_env: &mut TestEnv) -> TestResult {
let release_info = if let Ok(f) = File::open("/etc/os-release") {
let buf = std::io::BufReader::new(f);
@@ -278,24 +268,27 @@ fn host_is_chrome_test(_env: &mut TestEnv) -> TestResult {
}
}
+/// Verify that software write protect for a range protects only the requested range.
fn partial_lock_test(section: LayoutNames) -> impl Fn(&mut TestEnv) -> TestResult {
move |env: &mut TestEnv| {
// Need a clean image for verification
env.ensure_golden()?;
- let (name, start, len) = utils::layout_section(env.layout(), section);
- // Disable software WP so we can do range protection, but hardware WP
- // must remain enabled for (most) range protection to do anything.
- env.wp.set_hw(false)?.set_sw(false)?;
- flashrom::wp_range(env.cmd, (start, len), true)?;
+ let (wp_section_name, start, len) = utils::layout_section(env.layout(), section);
+ // Disable hardware WP so we can modify the protected range.
+ env.wp.set_hw(false)?;
+ // Then enable software WP so the range is enforced and enable hardware
+ // WP so that flashrom does not disable software WP during the
+ // operation.
+ env.wp.set_range((start, len), true)?;
env.wp.set_hw(true)?;
- let rws = flashrom::ROMWriteSpecifics {
- layout_file: Some(LAYOUT_FILE),
- write_file: Some(env.random_data_file()),
- name_file: Some(name),
- };
- if flashrom::write_file_with_layout(env.cmd, &rws).is_ok() {
+ // Check that we cannot write to the protected region.
+ if env
+ .cmd
+ .write_from_file_region(env.random_data_file(), wp_section_name, &env.layout_file)
+ .is_ok()
+ {
return Err(
"Section should be locked, should not have been overwritable with random data"
.into(),
@@ -304,12 +297,32 @@ fn partial_lock_test(section: LayoutNames) -> impl Fn(&mut TestEnv) -> TestResul
if !env.is_golden() {
return Err("Section didn't lock, has been overwritten with random data!".into());
}
+
+ // Check that we can write to the non protected region.
+ let (non_wp_section_name, _, _) =
+ utils::layout_section(env.layout(), section.get_non_overlapping_section());
+ env.cmd.write_from_file_region(
+ env.random_data_file(),
+ non_wp_section_name,
+ &env.layout_file,
+ )?;
+
Ok(())
}
}
+/// Check that flashrom 'verify' will fail if the provided data does not match the chip data.
fn verify_fail_test(env: &mut TestEnv) -> TestResult {
- // Comparing the flash contents to random data says they're not the same.
+ env.ensure_golden()?;
+ // Verify that verify is Ok when the data matches. We verify only a region
+ // and not the whole chip because coprocessors or firmware may have written
+ // some data in other regions.
+ env.cmd
+ .read_region_into_file(FW_MAIN_B_PATH.as_ref(), "FW_MAIN_B")?;
+ env.cmd
+ .verify_region_from_file(FW_MAIN_B_PATH.as_ref(), "FW_MAIN_B")?;
+
+ // Verify that verify is false when the data does not match
match env.verify(env.random_data_file()) {
Ok(_) => Err("Verification says flash is full of random data".into()),
Err(_) => Ok(()),
diff --git a/util/flashrom_tester/src/types.rs b/util/flashrom_tester/src/types.rs
index b22ded2b4..9cefb27e9 100644
--- a/util/flashrom_tester/src/types.rs
+++ b/util/flashrom_tester/src/types.rs
@@ -33,21 +33,40 @@
// Software Foundation.
//
-pub const BOLD: &str = "\x1b[1m";
+pub struct Color {
+ pub bold: &'static str,
+ pub reset: &'static str,
+ pub magenta: &'static str,
+ pub yellow: &'static str,
+ pub green: &'static str,
+ pub red: &'static str,
+}
+
+pub const COLOR: Color = Color {
+ bold: "\x1b[1m",
+ reset: "\x1b[0m",
+ magenta: "\x1b[35m",
+ yellow: "\x1b[33m",
+ green: "\x1b[92m",
+ red: "\x1b[31m",
+};
-pub const RESET: &str = "\x1b[0m";
-pub const MAGENTA: &str = "\x1b[35m";
-pub const YELLOW: &str = "\x1b[33m";
-pub const GREEN: &str = "\x1b[92m";
-pub const RED: &str = "\x1b[31m";
+pub const NOCOLOR: Color = Color {
+ bold: "",
+ reset: "",
+ magenta: "",
+ yellow: "",
+ green: "",
+ red: "",
+};
macro_rules! style_dbg {
- ($s: expr, $c: expr) => {
- format!("{}{:?}{}", $c, $s, types::RESET)
+ ($s: expr, $c: expr, $col: expr) => {
+ format!("{}{:?}{}", $c, $s, $col.reset)
};
}
macro_rules! style {
- ($s: expr, $c: expr) => {
- format!("{}{}{}", $c, $s, types::RESET)
+ ($s: expr, $c: expr, $col: expr) => {
+ format!("{}{}{}", $c, $s, $col.reset)
};
}
diff --git a/util/flashrom_tester/src/utils.rs b/util/flashrom_tester/src/utils.rs
index d17480bcb..4e8dd7cce 100644
--- a/util/flashrom_tester/src/utils.rs
+++ b/util/flashrom_tester/src/utils.rs
@@ -44,6 +44,18 @@ pub enum LayoutNames {
BottomQuad,
}
+impl LayoutNames {
+ // Return a section that does not overlap
+ pub fn get_non_overlapping_section(&self) -> LayoutNames {
+ match self {
+ LayoutNames::TopQuad => LayoutNames::BottomQuad,
+ LayoutNames::TopHalf => LayoutNames::BottomHalf,
+ LayoutNames::BottomHalf => LayoutNames::TopHalf,
+ LayoutNames::BottomQuad => LayoutNames::TopQuad,
+ }
+ }
+}
+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct LayoutSizes {
half_sz: i64,
@@ -88,20 +100,20 @@ pub fn construct_layout_file<F: Write>(mut target: F, ls: &LayoutSizes) -> std::
}
pub fn toggle_hw_wp(dis: bool) -> Result<(), String> {
- // The easist way to toggle the harware write-protect is
+ // The easist way to toggle the hardware write-protect is
// to {dis}connect the battery (and/or open the WP screw).
let s = if dis { "dis" } else { "" };
- info!("Prompt for hardware WP {}able", s);
- eprintln!(" > {}connect the battery (and/or open the WP screw)", s);
- pause();
- let wp = get_hardware_wp()?;
- if wp && dis {
- eprintln!("Hardware write protect is still ENABLED!");
- return toggle_hw_wp(dis);
- }
- if !wp && !dis {
- eprintln!("Hardware write protect is still DISABLED!");
- return toggle_hw_wp(dis);
+ // Print a failure message, but not on the first try.
+ let mut fail_msg = None;
+ while dis == get_hardware_wp()? {
+ if let Some(msg) = fail_msg {
+ eprintln!("{msg}");
+ }
+ fail_msg = Some(format!("Hardware write protect is still {}!", !dis));
+ // The following message is read by the tast test. Do not modify.
+ info!("Prompt for hardware WP {}able", s);
+ eprintln!(" > {}connect the battery (and/or open the WP screw)", s);
+ pause();
}
Ok(())
}
@@ -114,21 +126,36 @@ pub fn ac_power_warning() {
}
fn pause() {
- let mut stdout = std::io::stdout();
- // We want the cursor to stay at the end of the line, so we print without a newline
- // and flush manually.
- stdout.write(b"Press any key to continue...").unwrap();
- stdout.flush().unwrap();
- std::io::stdin().read(&mut [0]).unwrap();
+ // The following message is read by the tast test. Do not modify.
+ println!("Press enter to continue...");
+ // Rust stdout is always LineBuffered at time of writing.
+ // But this is not guaranteed, so flush anyway.
+ std::io::stdout().flush().unwrap();
+ // This reads one line, there is no guarantee the line came
+ // after the above prompt. But it is good enough.
+ if std::io::stdin().read_line(&mut String::new()).unwrap() == 0 {
+ panic!("stdin closed");
+ }
}
pub fn get_hardware_wp() -> std::result::Result<bool, String> {
- let (_, wp) = parse_crosssystem(&collect_crosssystem()?)?;
- Ok(wp)
+ let wp_s_val = collect_crosssystem(&["wpsw_cur"])?.parse::<u32>();
+ match wp_s_val {
+ Ok(v) => {
+ if v == 1 {
+ Ok(true)
+ } else if v == 0 {
+ Ok(false)
+ } else {
+ Err("Unknown write protect value".into())
+ }
+ }
+ Err(_) => Err("Cannot parse write protect value".into()),
+ }
}
-pub fn collect_crosssystem() -> Result<String, String> {
- let cmd = match Command::new("crossystem").output() {
+pub fn collect_crosssystem(args: &[&str]) -> Result<String, String> {
+ let cmd = match Command::new("crossystem").args(args).output() {
Ok(x) => x,
Err(e) => return Err(format!("Failed to run crossystem: {}", e)),
};
@@ -140,39 +167,6 @@ pub fn collect_crosssystem() -> Result<String, String> {
Ok(String::from_utf8_lossy(&cmd.stdout).into_owned())
}
-fn parse_crosssystem(s: &str) -> Result<(Vec<&str>, bool), &'static str> {
- // grep -v 'fwid +=' | grep -v 'hwid +='
- let sysinfo = s
- .split_terminator("\n")
- .filter(|s| !s.contains("fwid +=") && !s.contains("hwid +="));
-
- let state_line = match sysinfo.clone().filter(|s| s.starts_with("wpsw_cur")).next() {
- None => return Err("No wpsw_cur in system info"),
- Some(line) => line,
- };
- let wp_s_val = state_line
- .trim_start_matches("wpsw_cur")
- .trim_start_matches(' ')
- .trim_start_matches('=')
- .trim_start_matches(' ')
- .get(..1)
- .unwrap()
- .parse::<u32>();
-
- match wp_s_val {
- Ok(v) => {
- if v == 1 {
- return Ok((sysinfo.collect(), true));
- } else if v == 0 {
- return Ok((sysinfo.collect(), false));
- } else {
- return Err("Unknown state value");
- }
- }
- Err(_) => return Err("Cannot parse state value"),
- }
-}
-
pub fn translate_command_error(output: &std::process::Output) -> std::io::Error {
use std::io::{Error, ErrorKind};
// There is two cases on failure;
@@ -244,55 +238,4 @@ mod tests {
}
);
}
-
- #[test]
- fn parse_crosssystem() {
- use super::parse_crosssystem;
-
- assert_eq!(
- parse_crosssystem("This is not the tool you are looking for").err(),
- Some("No wpsw_cur in system info")
- );
-
- assert_eq!(
- parse_crosssystem("wpsw_cur = ERROR").err(),
- Some("Cannot parse state value")
- );
-
- assert_eq!(
- parse_crosssystem("wpsw_cur = 3").err(),
- Some("Unknown state value")
- );
-
- assert_eq!(
- parse_crosssystem("wpsw_cur = 0"),
- Ok((vec!["wpsw_cur = 0"], false))
- );
-
- assert_eq!(
- parse_crosssystem("wpsw_cur = 1"),
- Ok((vec!["wpsw_cur = 1"], true))
- );
-
- assert_eq!(
- parse_crosssystem("wpsw_cur=1"),
- Ok((vec!["wpsw_cur=1"], true))
- );
-
- assert_eq!(
- parse_crosssystem(
- "fwid += 123wpsw_cur\n\
- hwid += aaaaa\n\
- wpsw_boot = 0 # [RO/int]\n\
- wpsw_cur = 1 # [RO/int]\n"
- ),
- Ok((
- vec![
- "wpsw_boot = 0 # [RO/int]",
- "wpsw_cur = 1 # [RO/int]"
- ],
- true
- ))
- );
- }
}
diff --git a/util/z60_flashrom.rules b/util/flashrom_udev.rules
index 59de68be7..9fd333082 100644
--- a/util/z60_flashrom.rules
+++ b/util/flashrom_udev.rules
@@ -62,6 +62,10 @@ ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5001", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5002", MODE="664", GROUP="plugdev"
ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="5003", MODE="664", GROUP="plugdev"
+# Kristech KT-LINK
+# https://kristech.pl/files/KT-LINK-UM-ENG.pdf
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bbe2", MODE="664", GROUP="plugdev"
+
# Olimex ARM-USB-OCD
# http://olimex.com/dev/arm-usb-ocd.html
ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="0003", MODE="664", GROUP="plugdev"
diff --git a/util/getrevision.sh b/util/getrevision.sh
deleted file mode 100755
index f7d6bf3b2..000000000
--- a/util/getrevision.sh
+++ /dev/null
@@ -1,238 +0,0 @@
-#!/bin/sh
-# NB: Supposed to be POSIX compatible but at least the usage of 'local' is not.
-#
-# This file is part of the flashrom project.
-#
-# Copyright (C) 2005 coresystems GmbH <stepan@coresystems.de>
-# Copyright (C) 2009,2010 Carl-Daniel Hailfinger
-# Copyright (C) 2010 Chromium OS Authors
-# Copyright (C) 2013-2016 Stefan Tauner
-#
-# 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.
-#
-
-EXIT_SUCCESS=0
-EXIT_FAILURE=1
-
-# Make sure we don't get translated output
-export LC_ALL=C
-# nor local times or dates
-export TZ=UTC0
-
-# Helper functions
-# First argument is the path to inspect (usually optional; without
-# it the whole repository will be considered)
-git_has_local_changes() {
- git update-index -q --refresh >/dev/null
- ! git diff-index --quiet HEAD -- "$1"
-}
-
-git_last_commit() {
- # git rev-parse --short HEAD would suffice if repository as a whole is of interest (no $1)
- git log --pretty=format:"%h" -1 -- "$1"
-}
-
-git_is_file_tracked() {
- git ls-files --error-unmatch -- "$1" >/dev/null 2>&1
-}
-
-is_file_tracked() {
- git_is_file_tracked "$1"
-}
-
-# Tries to find a remote source for the changes committed locally.
-# This includes the URL of the remote repository including the last commit and a suitable branch name.
-# Takes one optional argument: the path to inspect
-git_url() {
- last_commit=$(git_last_commit "$1")
- # get all remote branches containing the last commit (excluding origin/HEAD)
- branches=$(git branch -r --contains $last_commit | sed '/\//!d;/.*->.*/d;s/[\t ]*//')
- if [ -z "$branches" ] ; then
- echo "No remote branch contains a suitable commit">&2
- return
- fi
-
- # find "nearest" branch
- local mindiff=9000
- local target=
- for branch in $branches ; do
- curdiff=$(git rev-list --count $last_commit..$branch)
- if [ $curdiff -ge $mindiff ] ; then
- continue
- fi
- mindiff=$curdiff
- target=$branch
- done
-
- echo "$(git ls-remote --exit-code --get-url ${target%/*}) ${target#*/}"
-}
-
-# Returns a string indicating where others can get the current source code (excluding uncommitted changes).
-# Takes one optional argument: the path to inspect
-scm_url() {
- local url=
-
- if git_is_file_tracked "$1" ; then
- url="$(git_url "$1")"
- else
- return ${EXIT_FAILURE}
- fi
-
- echo "${url}"
-}
-
-# Retrieve timestamp since last modification. If the sources are pristine,
-# then the timestamp will match that of the SCM's most recent modification
-# date.
-timestamp() {
- local t
-
- # date syntaxes are manifold:
- # gnu date [-d input]... [+FORMAT]
- # netbsd date [-ajnu] [-d date] [-r seconds] [+format] [[[[[[CC]yy]mm]dd]HH]MM[.SS]]
- # freebsd date [-jnu] [-d dst] [-r seconds] [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] [...]
- # dragonflybsd date [-jnu] [-d dst] [-r seconds] [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] [...]
- # openbsd date [-aju] [-d dst] [-r seconds] [+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]] [...]
- if git_is_file_tracked "$2" ; then
- # are there local changes?
- if git_has_local_changes "$2" ; then
- t=$(date -u "${1}")
- else
- # No local changes, get date of the last commit
- case $(uname) in
- # Most BSD dates do not support parsing date values from user input with -d but all of
- # them support parsing epoch seconds with -r. Thanks to git we can easily use that:
- NetBSD|OpenBSD|DragonFly|FreeBSD)
- t=$(date -u -r "$(git log --pretty=format:%ct -1 -- $2)" "$1" 2>/dev/null);;
- *)
- t=$(date -d "$(git log --pretty=format:%cD -1 -- $2)" -u "$1" 2>/dev/null);;
- esac
- fi
- else
- t=$(date -u "$1")
- fi
-
- if [ -z "$t" ]; then
- echo "Warning: Could not determine timestamp." 2>/dev/null
- fi
- echo "${t}"
-}
-
-revision() {
- local r
- if git_is_file_tracked "$1" ; then
- r=$(git describe --always $(git_last_commit "$1"))
- if git_has_local_changes "$1" ; then
- r="$r-dirty"
- fi
- else
- r="unknown"
- fi
-
- echo "${r}"
-}
-
-is_tracked() {
- is_file_tracked "$1"
-}
-
-show_help() {
- echo "Usage:
- ${0} <command> [path]
-
-Commands
- -h or --help
- this message
- -c or --check
- test if path is under version control at all
- -r or --revision
- return unique revision information including an indicator for
- uncommitted changes
- -U or --url
- URL associated with the latest commit
- -d or --date
- date of most recent modification
- -t or --timestamp
- timestamp of most recent modification
-"
- return
-}
-
-check_action() {
- if [ -n "$action" ]; then
- echo "Error: Multiple actions given.">&2
- exit ${EXIT_FAILURE}
- fi
-}
-
-main() {
- local query_path=
- local action=
-
- # Argument parser loop
- while [ $# -gt 0 ];
- do
- case ${1} in
- -h|--help)
- action=show_help;
- shift;;
- -U|--url)
- check_action $1
- action=scm_url
- shift;;
- -d|--date)
- check_action $1
- action="timestamp +%Y-%m-%d" # refrain from suffixing 'Z' to indicate it's UTC
- shift;;
- -r|--revision)
- check_action $1
- action=revision
- shift;;
- -t|--timestamp)
- check_action $1
- action="timestamp +%Y-%m-%dT%H:%M:%SZ" # There is only one valid time format! ISO 8601
- shift;;
- -c|--check)
- check_action $1
- action=is_tracked
- shift;;
- -*)
- show_help;
- echo "Error: Invalid option: ${1}"
- exit ${EXIT_FAILURE};;
- *)
- if [ -z "$query_path" ] ; then
- if [ ! -e "$1" ] ; then
- echo "Error: Path \"${1}\" does not exist.">&2
- exit ${EXIT_FAILURE}
- fi
- query_path=$1
- else
- echo "Warning: Ignoring overabundant parameter: \"${1}\"">&2
- fi
- shift;;
- esac;
- done
-
- # default to current directory (usually equals the whole repository)
- if [ -z "$query_path" ] ; then
- query_path=.
- fi
- if [ -z "$action" ] ; then
- show_help
- echo "Error: No actions specified"
- exit ${EXIT_FAILURE}
- fi
-
- $action "$query_path"
-}
-
-main $@
diff --git a/util/getversion.sh b/util/getversion.sh
deleted file mode 100755
index d3810d29b..000000000
--- a/util/getversion.sh
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/bin/sh
-#
-# This file is part of the flashrom project.
-#
-# 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.
-#
-
-version() {
- if [ -r versioninfo.inc ]; then
- v=$(sed -n 's/^VERSION = //p' versioninfo.inc)
- else
- v=$($(dirname ${0})/getrevision.sh --revision)
- if [ $? -ne 0 ]; then
- v='unknown'
- fi
- fi
-
- echo ${v}
-}
-
-mandate() {
- if [ -r versioninfo.inc ]; then
- d=$(sed -n 's/^MAN_DATE = //p' versioninfo.inc)
- else
- d=$($(dirname ${0})/getrevision.sh --date flashrom.8.tmpl)
- if [ $? -ne 0 ]; then
- d='unknown'
- fi
- fi
-
- echo ${d}
-}
-
-show_help() {
- echo "Usage:
- ${0} <command>
-
-Commands
- -h or --help
- this message
- -v or --version
- return current/release flashrom version
- -m or --man-date
- return current/release date of the manual page
-"
-}
-
-if [ $# -ne 1 ]; then
- show_help
- echo "Error: Only exactly one command allowed.">&2
- exit 1
-fi
-
-case $1 in
- -h|--help) show_help;;
- -m|--man-date) mandate;;
- -v|--version) version;;
- *)
- show_help
- echo "Error: Invalid option: $1"
- exit 1
- ;;
-esac
diff --git a/util/git-hooks/commit-msg b/util/git-hooks/commit-msg
index d43eb4529..e2f5de512 100755
--- a/util/git-hooks/commit-msg
+++ b/util/git-hooks/commit-msg
@@ -196,6 +196,7 @@ _gen_ChangeId() {
test_signoff() {
if ! grep -qi '^[[:space:]]*\+Signed-off-by:' "$MSG"; then
+ cat "$MSG"
printf "\nError: No Signed-off-by line in the commit message.\n"
printf "See: ${DEV_GUIDELINES_URL}\n"
exit 1
@@ -206,6 +207,7 @@ test_signoff() {
test_duplicate_signoffs_acks() {
test "" = "$(grep -i '^(Signed-off-by|Acked-by): ' "$MSG" |
sort | uniq -c | sed -e '/^[[:space:]]*1[[:space:]]/d')" || {
+ cat "$MSG"
echo "Duplicate Signed-off-by or Acked-by lines." >&2
exit 1
}
diff --git a/util/ich_descriptors_tool/Makefile b/util/ich_descriptors_tool/Makefile
index c32e30be5..aa1b696c3 100644
--- a/util/ich_descriptors_tool/Makefile
+++ b/util/ich_descriptors_tool/Makefile
@@ -4,6 +4,8 @@
# This Makefile works standalone, but it is usually called from the main
# Makefile in the flashrom directory.
+include ../../Makefile.include
+
PROGRAM=ich_descriptors_tool
EXTRAINCDIRS = ../../ .
DEPPATH = .dep
@@ -16,31 +18,33 @@ WARNERROR ?= yes
SRC = $(wildcard *.c)
-CC ?= gcc
-
# If the user has specified custom CFLAGS, all CFLAGS settings below will be
# completely ignored by gnumake.
CFLAGS ?= -Os -Wall -Wshadow
+override CFLAGS += -I$(SHAREDSRCDIR)/include
+# Auto determine HOST_OS and TARGET_OS if they are not set as argument
HOST_OS ?= $(shell uname)
+TARGET_OS := $(call c_macro_test, ../../Makefile.d/os_test.h)
+
ifeq ($(findstring MINGW, $(HOST_OS)), MINGW)
# Explicitly set CC = gcc on MinGW, otherwise: "cc: command not found".
CC = gcc
-EXEC_SUFFIX := .exe
-# Some functions provided by Microsoft do not work as described in C99 specifications. This macro fixes that
-# for MinGW. See http://sourceforge.net/p/mingw-w64/wiki2/printf%20and%20scanf%20family/ */
-FLASHROM_CFLAGS += -D__USE_MINGW_ANSI_STDIO=1
endif
-override TARGET_OS := $(shell $(CC) $(CPPFLAGS) -E $(SHAREDSRCDIR)/os.h | grep -v '^\#' | grep '"' | \
- cut -f 2 -d'"')
-
ifeq ($(TARGET_OS), DOS)
EXEC_SUFFIX := .exe
# DJGPP has odd uint*_t definitions which cause lots of format string warnings.
CFLAGS += -Wno-format
endif
+ifeq ($(TARGET_OS), MinGW)
+EXEC_SUFFIX := .exe
+# Some functions provided by Microsoft do not work as described in C99 specifications. This macro fixes that
+# for MinGW. See http://sourceforge.net/p/mingw-w64/wiki2/printf%20and%20scanf%20family/
+CFLAGS += -D__USE_MINGW_ANSI_STDIO=1
+endif
+
ifeq ($(WARNERROR), yes)
CFLAGS += -Werror
endif
@@ -68,6 +72,7 @@ $(SHAREDOBJ): $(OBJATH)/%.o : $(SHAREDSRCDIR)/%.c
$(PROGRAM)$(EXEC_SUFFIX): $(OBJ) $(SHAREDOBJ)
$(CC) $(LDFLAGS) -o $(PROGRAM)$(EXEC_SUFFIX) $(OBJ) $(SHAREDOBJ)
+# We don't use EXEC_SUFFIX here because we want to clean everything.
clean:
rm -f $(PROGRAM) $(PROGRAM).exe
rm -rf $(DEPPATH) $(OBJATH)
diff --git a/util/ich_descriptors_tool/ich_descriptors_tool.c b/util/ich_descriptors_tool/ich_descriptors_tool.c
index 32eea12c9..a5a59ad29 100644
--- a/util/ich_descriptors_tool/ich_descriptors_tool.c
+++ b/util/ich_descriptors_tool/ich_descriptors_tool.c
@@ -46,7 +46,6 @@ static const char *const region_names[] = {
static void dump_file(const char *prefix, const uint32_t *dump, unsigned int len,
const struct ich_desc_region *const reg, unsigned int i)
{
- int ret;
char *fn;
const char *reg_name;
uint32_t file_len;
@@ -85,8 +84,8 @@ static void dump_file(const char *prefix, const uint32_t *dump, unsigned int len
}
free(fn);
- ret = write(fh, &dump[base >> 2], file_len);
- if (ret != file_len) {
+ const ssize_t ret = write(fh, &dump[base >> 2], file_len);
+ if (ret < 0 || ((size_t) ret) != file_len) {
fprintf(stderr, "FAILED.\n");
exit(1);
}
@@ -127,6 +126,9 @@ static void usage(char *argv[], const char *error)
"\t- \"ich10\",\n"
"\t- \"silvermont\" for chipsets from Intel's Silvermont architecture (e.g. Bay Trail),\n"
"\t- \"apollo\" for Intel's Apollo Lake SoC.\n"
+"\t- \"gemini\" for Intel's Gemini Lake SoC.\n"
+"\t- \"jasper\" for Intel's Jasper Lake SoC.\n"
+"\t- \"meteor\" for Intel's Meteor Lake SoC.\n"
"\t- \"5\" or \"ibex\" for Intel's 5 series chipsets,\n"
"\t- \"6\" or \"cougar\" for Intel's 6 series chipsets,\n"
"\t- \"7\" or \"panther\" for Intel's 7 series chipsets.\n"
@@ -134,6 +136,9 @@ static void usage(char *argv[], const char *error)
"\t- \"9\" or \"wildcat\" for Intel's 9 series chipsets.\n"
"\t- \"100\" or \"sunrise\" for Intel's 100 series chipsets.\n"
"\t- \"300\" or \"cannon\" for Intel's 300 series chipsets.\n"
+"\t- \"400\" or \"comet\" for Intel's 400 series chipsets.\n"
+"\t- \"500\" or \"tiger\" for Intel's 500 series chipsets.\n"
+"\t- \"600\" or \"alder\" for Intel's 600 series chipsets.\n"
"If '-d' is specified some regions such as the BIOS image as seen by the CPU or\n"
"the GbE blob that is required to initialize the GbE are also dumped to files.\n",
argv[0], argv[0]);
@@ -228,8 +233,21 @@ int main(int argc, char *argv[])
else if ((strcmp(csn, "400") == 0) ||
(strcmp(csn, "comet") == 0))
cs = CHIPSET_400_SERIES_COMET_POINT;
+ else if ((strcmp(csn, "500") == 0) ||
+ (strcmp(csn, "tiger") == 0))
+ cs = CHIPSET_500_SERIES_TIGER_POINT;
+ else if (strcmp(csn, "600") == 0)
+ cs = CHIPSET_600_SERIES_ALDER_POINT;
else if (strcmp(csn, "apollo") == 0)
cs = CHIPSET_APOLLO_LAKE;
+ else if (strcmp(csn, "gemini") == 0)
+ cs = CHIPSET_GEMINI_LAKE;
+ else if (strcmp(csn, "jasper") == 0)
+ cs = CHIPSET_JASPER_LAKE;
+ else if (strcmp(csn, "elkhart") == 0)
+ cs = CHIPSET_ELKHART_LAKE;
+ else if (strcmp(csn, "meteor") == 0)
+ cs = CHIPSET_METEOR_LAKE;
}
ret = read_ich_descriptors_from_dump(buf, len, &cs, &desc);
@@ -251,7 +269,8 @@ int main(int argc, char *argv[])
prettyprint_ich_descriptors(cs, &desc);
pMAC = (uint8_t *) &buf[ICH_FREG_BASE(desc.region.FLREGs[3]) >> 2];
- if (len >= ICH_FREG_BASE(desc.region.FLREGs[3]) + 6 && pMAC[0] != 0xff)
+ /* The case len < 0 is handled above as error. At this point len is non-negative. */
+ if (((size_t) len) >= ICH_FREG_BASE(desc.region.FLREGs[3]) + 6 && pMAC[0] != 0xff)
printf("The MAC address might be at offset 0x%x: "
"%02x:%02x:%02x:%02x:%02x:%02x\n",
ICH_FREG_BASE(desc.region.FLREGs[3]),
diff --git a/util/ich_descriptors_tool/meson.build b/util/ich_descriptors_tool/meson.build
index b5bf09ec9..80f4a521b 100644
--- a/util/ich_descriptors_tool/meson.build
+++ b/util/ich_descriptors_tool/meson.build
@@ -4,10 +4,7 @@ executable(
'ich_descriptors_tool.c',
'../../ich_descriptors.c',
],
- dependencies : [
- deps,
- ],
- include_directories : include_directories('../..'),
+ include_directories : include_dir,
c_args : [
'-DICH_DESCRIPTORS_FROM_DUMP_ONLY',
],
diff --git a/util/lint/helper_functions.sh b/util/lint/helper_functions.sh
new file mode 100644
index 000000000..7abdab861
--- /dev/null
+++ b/util/lint/helper_functions.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env sh
+#
+# SPDX-License-Identifier: GPL-2.0-only
+
+# This file is sourced by the linters so that each one doesn't have to
+# specify these routines individually
+
+LC_ALL=C export LC_ALL
+
+if [ -z "$GIT" ]; then
+ GIT="$(command -v git)"
+else
+ # If git is specified, Do a basic check that it runs and seems like
+ # it's actually git
+ if ! "${GIT}" --version | grep -q git; then
+ echo "Error: ${GIT} does not seem to be valid."
+ exit 1;
+ fi
+fi
+
+if [ "$(${GIT} rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ]; then
+ IN_GIT_TREE=1
+else
+ IN_GIT_TREE=0
+fi
+
+if [ "${IN_GIT_TREE}" -eq 1 ] && [ -z "${GIT}" ]; then
+ echo "This test needs git to run. Please install it, then run this test again."
+ exit 1
+fi
+
+# Use git ls-files if the code is in a git repo, otherwise use find.
+if [ "${IN_GIT_TREE}" -eq 1 ]; then
+ FIND_FILES="${GIT} ls-files"
+else
+ FIND_FILES="find "
+ FINDOPTS="-type f"
+fi
+
+# Use git grep if the code is in a git repo, otherwise use grep.
+if [ "${IN_GIT_TREE}" -eq 1 ]; then
+ GREP_FILES="${GIT} grep"
+else
+ GREP_FILES="grep -r"
+fi
diff --git a/util/lint/lint-extended-020-signed-off-by b/util/lint/lint-extended-020-signed-off-by
new file mode 100755
index 000000000..ef62a45a2
--- /dev/null
+++ b/util/lint/lint-extended-020-signed-off-by
@@ -0,0 +1,23 @@
+#!/usr/bin/env sh
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# DESCR: Check for a signed-off-by line on the latest commit
+
+
+LINTDIR="$(
+ cd -- "$(dirname "$0")" > /dev/null 2>&1 || return
+ pwd -P
+)"
+
+# shellcheck source=helper_functions.sh
+. "${LINTDIR}/helper_functions.sh"
+
+if [ "${IN_GIT_TREE}" -eq 0 ]; then
+ exit 0
+fi
+
+# This test is mainly for the jenkins server
+if ! ${GIT} log -n 1 | grep -q '[[:space:]]\+Signed-off-by: '; then
+ echo "No Signed-off-by line in commit message"
+ exit 1
+fi
diff --git a/util/manibuilder/Dockerfile.alpine b/util/manibuilder/Dockerfile.alpine
new file mode 100644
index 000000000..674b54512
--- /dev/null
+++ b/util/manibuilder/Dockerfile.alpine
@@ -0,0 +1,24 @@
+FROM manibase
+
+ARG PROTO=https
+RUN \
+ adduser -D mani mani && \
+ sed -i "s/https/${PROTO}/" /etc/apk/repositories && \
+ apk update && \
+ apk add ca-certificates build-base linux-headers git ccache \
+ pciutils-dev libusb-compat-dev libusb-dev
+
+# fix weird permissions in armhf-v3.11
+RUN [ -d /usr/share/git-core/templates ] && \
+ chmod -R a+r /usr/share/git-core/templates
+
+ENV GIT_SSL_NO_VERIFY=1
+USER mani
+RUN \
+ cd && \
+ mkdir .ccache && chown mani:mani .ccache && \
+ git clone https://review.coreboot.org/flashrom.git
+
+ENV DEVSHELL /bin/sh
+COPY mani-wrapper.sh /home/mani/
+ENTRYPOINT ["/bin/sh", "/home/mani/mani-wrapper.sh"]
diff --git a/util/manibuilder/Dockerfile.anita b/util/manibuilder/Dockerfile.anita
new file mode 100644
index 000000000..52befce00
--- /dev/null
+++ b/util/manibuilder/Dockerfile.anita
@@ -0,0 +1,65 @@
+FROM debian:bullseye
+
+ARG PKG_PATH=http://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/amd64/7.1/All
+ARG INST_IMG=http://ftp.de.netbsd.org/pub/NetBSD/NetBSD-7.1/amd64/
+
+RUN \
+ useradd -p locked -m mani && \
+ apt-get -qq update && \
+ apt-get -qq upgrade && \
+ apt-get -qqy install git python-is-python3 python3-pexpect \
+ python3-distutils genisoimage qemu-system && \
+ apt-get clean
+
+RUN git clone https://github.com/gson1703/anita.git
+RUN cd anita && python setup.py install
+
+ARG DISK_SIZE=1G
+ARG INSTALL_MEM=128M
+USER mani
+RUN cd && mkdir .ccache && chown mani:mani .ccache && \
+ anita --sets kern-GENERIC,modules,base,etc,comp \
+ --disk-size ${DISK_SIZE} --memory-size=${INSTALL_MEM} \
+ install ${INST_IMG} && \
+ rm -rf work-*/download
+
+ARG EXTRA_PKG=""
+ARG RUNTIME_MEM=128M
+RUN cd && anita --persist --memory-size=${RUNTIME_MEM} --run \
+"echo 'dhcpcd' >init && \
+ echo 'export PKG_PATH=${PKG_PATH}' >>init && \
+ . ./init && \
+ pkg_add gmake git-base ccache pciutils libusb1 libusb-compat libftdi \
+ ${EXTRA_PKG} && \
+ git config --global --add http.sslVerify false && \
+ git clone https://review.coreboot.org/flashrom.git" \
+ boot ${INST_IMG}
+
+RUN cd && dd if=/dev/zero bs=1M count=64 of=cache.img && \
+ anita --vmm-args '-hdb cache.img' --persist \
+ --memory-size=${RUNTIME_MEM} --run \
+"if [ \$(uname -m) = i386 -o \$(uname -m) = amd64 ]; then \
+ bdev=wd1d; \
+ else \
+ bdev=wd1c; \
+ fi; \
+ newfs -I \${bdev} && \
+ mkdir .ccache && \
+ mount /dev/\${bdev} .ccache && \
+ ccache -M 60M && \
+ umount .ccache && \
+ echo 'manitest() {' >>init && \
+ echo ' fsck -y -t ffs /dev/'\${bdev} >>init && \
+ echo ' mount /dev/'\${bdev}' ~/.ccache' >>init && \
+ echo ' (cd ~/flashrom && eval \" \$*\")' >>init && \
+ echo ' ret=\$?' >>init && \
+ echo ' umount ~/.ccache' >>init && \
+ echo ' return \$ret' >>init && \
+ echo '}' >>init" \
+ boot ${INST_IMG} && \
+ gzip cache.img
+
+COPY anita-wrapper.sh /home/mani/mani-wrapper.sh
+ENV INST_IMG ${INST_IMG}
+ENV MEM_SIZE ${RUNTIME_MEM}
+ENTRYPOINT ["/bin/sh", "/home/mani/mani-wrapper.sh"]
diff --git a/util/manibuilder/Dockerfile.centos b/util/manibuilder/Dockerfile.centos
new file mode 100644
index 000000000..aa28fc488
--- /dev/null
+++ b/util/manibuilder/Dockerfile.centos
@@ -0,0 +1,18 @@
+FROM manibase
+
+RUN \
+ useradd -p locked -m mani && \
+ yum install -q -y ca-certificates git gcc systemd-devel \
+ pciutils-devel libusb-devel libusbx-devel && \
+ yum clean -q -y all
+
+ENV GIT_SSL_NO_VERIFY=1
+USER mani
+RUN \
+ cd && \
+ mkdir .ccache && chown mani:mani .ccache && \
+ git clone https://review.coreboot.org/flashrom.git
+
+ENV DEVSHELL /bin/bash
+COPY mani-wrapper.sh /home/mani/
+ENTRYPOINT ["/bin/sh", "/home/mani/mani-wrapper.sh"]
diff --git a/util/manibuilder/Dockerfile.debian-debootstrap b/util/manibuilder/Dockerfile.debian-debootstrap
new file mode 100644
index 000000000..c9af0bf3a
--- /dev/null
+++ b/util/manibuilder/Dockerfile.debian-debootstrap
@@ -0,0 +1,21 @@
+FROM manibase
+
+RUN \
+ useradd -p locked -m mani && \
+ apt-get -qq update && \
+ apt-get -qq upgrade && \
+ 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
+
+ENV GIT_SSL_NO_VERIFY=1
+USER mani
+RUN \
+ cd && \
+ mkdir .ccache && chown mani:mani .ccache && \
+ git clone https://review.coreboot.org/flashrom.git
+
+ENV DEVSHELL /bin/bash
+COPY mani-wrapper.sh /home/mani/
+ENTRYPOINT ["/bin/sh", "/home/mani/mani-wrapper.sh"]
diff --git a/util/manibuilder/Dockerfile.djgpp b/util/manibuilder/Dockerfile.djgpp
new file mode 100644
index 000000000..7bd5c7bd6
--- /dev/null
+++ b/util/manibuilder/Dockerfile.djgpp
@@ -0,0 +1,30 @@
+FROM anibali/djgpp:6.1.0
+
+USER root
+RUN \
+ userdel appuser && \
+ useradd -p locked -m mani && \
+ zypper -q install -y tar make git ccache
+
+ENV GIT_SSL_NO_VERIFY=1
+USER mani
+RUN cd && \
+ mkdir .ccache && chown mani:users .ccache && \
+ git clone https://review.coreboot.org/flashrom.git && \
+ git clone https://git.kernel.org/pub/scm/utils/pciutils/pciutils.git && \
+ cd pciutils && \
+ git checkout v3.5.6 && \
+ curl --insecure https://flashrom.org/images/6/6a/Pciutils-3.5.6.patch.gz | zcat | git apply && \
+ make ZLIB=no DNS=no HOST=i386-djgpp-djgpp \
+ CROSS_COMPILE=i586-pc-msdosdjgpp- \
+ PREFIX=/ DESTDIR=$PWD/../ \
+ STRIP="--strip-program=i586-pc-msdosdjgpp-strip -s" \
+ install install-lib && \
+ cd ../ && \
+ curl --insecure https://flashrom.org/images/3/3d/Libgetopt.tar.gz | zcat | tar x && \
+ cd libgetopt && \
+ make && cp libgetopt.a ../lib/ && cp getopt.h ../include/
+
+ENV DEVSHELL /bin/bash
+COPY mani-wrapper.sh /home/mani/
+ENTRYPOINT ["/bin/sh", "/home/mani/mani-wrapper.sh"]
diff --git a/util/manibuilder/Dockerfile.fedora b/util/manibuilder/Dockerfile.fedora
new file mode 100644
index 000000000..79a939a16
--- /dev/null
+++ b/util/manibuilder/Dockerfile.fedora
@@ -0,0 +1,19 @@
+FROM manibase
+
+RUN \
+ useradd -p locked -m mani && \
+ dnf install -q -y ca-certificates git gcc ccache make systemd-devel \
+ pciutils-devel libusb-devel libusbx-devel libftdi-devel \
+ libjaylink-devel && \
+ dnf clean -q -y all
+
+ENV GIT_SSL_NO_VERIFY=1
+USER mani
+RUN \
+ cd && \
+ mkdir .ccache && chown mani:mani .ccache && \
+ git clone https://review.coreboot.org/flashrom.git
+
+ENV DEVSHELL /bin/bash
+COPY mani-wrapper.sh /home/mani/
+ENTRYPOINT ["/bin/sh", "/home/mani/mani-wrapper.sh"]
diff --git a/util/manibuilder/Dockerfile.qemu-user-static b/util/manibuilder/Dockerfile.qemu-user-static
new file mode 100644
index 000000000..b6de7eb26
--- /dev/null
+++ b/util/manibuilder/Dockerfile.qemu-user-static
@@ -0,0 +1,3 @@
+FROM multiarch/qemu-user-static:register
+
+RUN sed -i -e's/ mipsn32 mipsn32el / /' /qemu-binfmt-conf.sh
diff --git a/util/manibuilder/Dockerfile.ubuntu-debootstrap b/util/manibuilder/Dockerfile.ubuntu-debootstrap
new file mode 100644
index 000000000..62cc4615b
--- /dev/null
+++ b/util/manibuilder/Dockerfile.ubuntu-debootstrap
@@ -0,0 +1,34 @@
+FROM manibase
+
+RUN \
+ useradd -p locked -m mani && \
+ if grep -q main /etc/apt/sources.list; then \
+ if ! grep -q universe /etc/apt/sources.list; then \
+ sed -i -e 's/ main$/ main universe/' \
+ /etc/apt/sources.list || exit 1; \
+ fi; \
+ else \
+ url="http://ports.ubuntu.com/" && \
+ cn="$(sed -ne's/DISTRIB_CODENAME=//p' /etc/lsb-release)" && \
+ for t in "" "-updates" "-security"; do \
+ echo "deb ${url} ${cn}${t} main universe" \
+ >>/etc/apt/sources.list || exit 1; \
+ done; \
+ fi && \
+ apt-get -qq update && \
+ apt-get -qq upgrade && \
+ 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
+
+ENV GIT_SSL_NO_VERIFY=1
+USER mani
+RUN \
+ cd && \
+ mkdir .ccache && chown mani:mani .ccache && \
+ git clone https://review.coreboot.org/flashrom.git
+
+ENV DEVSHELL /bin/bash
+COPY mani-wrapper.sh /home/mani/
+ENTRYPOINT ["/bin/sh", "/home/mani/mani-wrapper.sh"]
diff --git a/util/manibuilder/Makefile b/util/manibuilder/Makefile
new file mode 100644
index 000000000..98ed30c96
--- /dev/null
+++ b/util/manibuilder/Makefile
@@ -0,0 +1,93 @@
+QUIET_TEST := @
+
+include Makefile.targets
+
+CC := ccache cc
+MAKECMD := make
+MAKEARGS := CONFIG_EVERYTHING=yes
+
+spc :=
+spc := $(spc) $(spc)
+
+stem = $(word 1,$(subst :,$(spc),$(subst \:,$(spc),$(1))))
+ident = $(subst :,_,$(subst \:,_,$(1)))
+
+include Makefile.anita
+
+define build_template
+Dockerfile.$(call ident,$(1)): Dockerfile.$(call stem,$(1)) mani-wrapper.sh
+ $(QUIET_SETUP)sed -e 's|^FROM manibase|FROM $(2)/$(1)|' $$< >$$@
+
+.INTERMEDIATE: Dockerfile.$(call ident,$(1))
+
+$(1)-build: Dockerfile.$(call ident,$(1))
+ $(QUIET_SETUP)docker build . -f $$< -t mani/$(1) $$(DOCKER_BUILD_ARGS)
+endef
+
+$(foreach tag,$(MULTIARCH_TAGS), \
+ $(eval $(call build_template,$(tag),multiarch)))
+
+$(addsuffix -build,$(filter alpine%v3.7 alpine%v3.8,$(MULTIARCH_TAGS))): \
+ DOCKER_BUILD_ARGS = --build-arg PROTO=http
+
+djgpp\:6.1.0-build: %-build: Dockerfile.djgpp mani-wrapper.sh
+ $(QUIET_SETUP)docker build . -f $< -t mani/$*
+
+$(addsuffix -check-build,$(ALL_TAGS)): %-check-build:
+ $(QUIET_SETUP)\
+ [ $$(docker image ls -q mani/$*) ] \
+ || $(MAKE) $*-build $(if $(QUIET_SETUP),>/dev/null 2>/dev/null)
+
+$(filter centos%,$(MULTIARCH_TAGS)) anita\:7.1-sparc: CC=cc
+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 CONFIG_JLINK_SPI=no
+$(ANITA_TAGS): MAKECMD=gmake
+$(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
+ $(QUIET_TEST)\
+ docker run \
+ --env IDENT=$(call ident,$*) \
+ --volume manicache:/home/mani/.ccache \
+ --name mani_$(call ident,$*) mani/$* \
+ "git fetch origin $${TEST_REVISION:-master} && \
+ git checkout FETCH_HEAD && \
+ $(MAKECMD) clean && $(MAKECMD) -j$${CPUS:-1} CC='$(CC)' \
+ $(if $(STRIP),STRIP='$(STRIP)') \
+ $(if $(LIBS_BASE),LIBS_BASE='$(LIBS_BASE)') \
+ $(MAKEARGS)" \
+ $(if $(QUIET_TEST),>/dev/null 2>&1) || echo $*: $$?
+
+$(addsuffix -shell,$(ALL_TAGS)): %-shell: %-check-build
+ $(QUIET_SETUP)\
+ if [ $$(docker ps -a -q -f name=mani_$(call ident,$*)) ]; then \
+ docker commit mani_$(call ident,$*) mani_run/$* && \
+ docker run --rm -it \
+ --env IDENT=$(call ident,$*) \
+ --volume manicache:/home/mani/.ccache \
+ --entrypoint /bin/sh mani_run/$* \
+ /home/mani/mani-wrapper.sh \
+ $(patsubst %,"%",$(SHELL_ARG)); \
+ docker image rm mani_run/$*; \
+ else \
+ docker run --rm -it \
+ --env IDENT=$(call ident,$*) \
+ --volume manicache:/home/mani/.ccache \
+ mani/$* $(patsubst %,"%",$(SHELL_ARG)); \
+ fi
+
+.PHONY: $(foreach s,-build -check-build -shell, $(addsuffix $(s),$(ALL_TAGS)))
+
+register:
+ docker build . \
+ -f Dockerfile.qemu-user-static \
+ -t mani/qemu-user-static:register
+ docker run --rm --privileged mani/qemu-user-static:register --reset
+
+.PHONY: register
diff --git a/util/manibuilder/Makefile.anita b/util/manibuilder/Makefile.anita
new file mode 100644
index 000000000..ba8c82d64
--- /dev/null
+++ b/util/manibuilder/Makefile.anita
@@ -0,0 +1,52 @@
+PKGSRC_MIRROR = http://cdn.netbsd.org/
+NETBSD_MIRROR = http://ftp.de.netbsd.org/
+
+anita\:9.1-sparc64-build: PKGSRC_PATH=pub/pkgsrc/packages/NetBSD/sparc64/9.1/All
+anita\:9.1-sparc64-build: NETBSD_IMAGE=pub/NetBSD/iso/9.1/NetBSD-9.1-sparc64.iso
+anita\:9.1-sparc64-build: QEMU_DISK_SIZE=2G
+anita\:9.1-sparc64-build: QEMU_INSTALL_MEM=192M
+anita\:9.1-sparc64-build: QEMU_RUNTIME_MEM=512M
+
+anita\:9.1-amd64-build: PKGSRC_PATH=pub/pkgsrc/packages/NetBSD/amd64/9.1/All
+anita\:9.1-amd64-build: NETBSD_IMAGE=pub/NetBSD/NetBSD-9.1/amd64/
+anita\:9.1-amd64-build: QEMU_DISK_SIZE=2G
+anita\:9.1-amd64-build: QEMU_INSTALL_MEM=192M
+anita\:9.1-amd64-build: QEMU_RUNTIME_MEM=512M
+
+anita\:9.1-i386-build: PKGSRC_PATH=pub/pkgsrc/packages/NetBSD/i386/9.1/All
+anita\:9.1-i386-build: NETBSD_IMAGE=pub/NetBSD/NetBSD-9.1/i386/
+anita\:9.1-i386-build: QEMU_DISK_SIZE=2G
+anita\:9.1-i386-build: QEMU_INSTALL_MEM=128M
+anita\:9.1-i386-build: QEMU_RUNTIME_MEM=256M
+
+anita\:8.2-amd64-build: PKGSRC_PATH=pub/pkgsrc/packages/NetBSD/amd64/8.2/All
+anita\:8.2-amd64-build: NETBSD_IMAGE=pub/NetBSD/NetBSD-8.2/amd64/
+anita\:8.2-amd64-build: QEMU_DISK_SIZE=2G
+anita\:8.2-amd64-build: QEMU_INSTALL_MEM=192M
+anita\:8.2-amd64-build: QEMU_RUNTIME_MEM=512M
+
+anita\:8.2-i386-build: PKGSRC_PATH=pub/pkgsrc/packages/NetBSD/i386/8.2/All
+anita\:8.2-i386-build: NETBSD_IMAGE=pub/NetBSD/NetBSD-8.2/i386/
+anita\:8.2-i386-build: QEMU_DISK_SIZE=2G
+anita\:8.2-i386-build: QEMU_INSTALL_MEM=128M
+anita\:8.2-i386-build: QEMU_RUNTIME_MEM=256M
+
+anita\:7.1-amd64-build: PKGSRC_PATH=pub/pkgsrc/packages/NetBSD/amd64/7.1/All
+anita\:7.1-amd64-build: NETBSD_IMAGE=pub/NetBSD/NetBSD-7.1/amd64/
+anita\:7.1-amd64-build: QEMU_DISK_SIZE=1G
+anita\:7.1-amd64-build: QEMU_INSTALL_MEM=192M
+anita\:7.1-amd64-build: QEMU_RUNTIME_MEM=512M
+
+anita\:7.1-i386-build: PKGSRC_PATH=pub/pkgsrc/packages/NetBSD/i386/7.1/All
+anita\:7.1-i386-build: NETBSD_IMAGE=pub/NetBSD/NetBSD-7.1/i386/
+anita\:7.1-i386-build: QEMU_DISK_SIZE=1G
+anita\:7.1-i386-build: QEMU_INSTALL_MEM=128M
+anita\:7.1-i386-build: QEMU_RUNTIME_MEM=256M
+
+$(addsuffix -build,$(ANITA_TAGS)): %-build: Dockerfile.anita anita-wrapper.sh
+ $(QUIET_SETUP)docker build . -f $< -t mani/$* \
+ --build-arg PKG_PATH=$(PKGSRC_MIRROR)$(PKGSRC_PATH) \
+ --build-arg INST_IMG=$(NETBSD_MIRROR)$(NETBSD_IMAGE) \
+ --build-arg DISK_SIZE=$(QEMU_DISK_SIZE) \
+ --build-arg INSTALL_MEM=$(QEMU_INSTALL_MEM) \
+ --build-arg RUNTIME_MEM=$(QEMU_RUNTIME_MEM)
diff --git a/util/manibuilder/Makefile.targets b/util/manibuilder/Makefile.targets
new file mode 100644
index 000000000..dff38797d
--- /dev/null
+++ b/util/manibuilder/Makefile.targets
@@ -0,0 +1,223 @@
+ANITA_TAGS := \
+ anita\:9.1-amd64 anita\:9.1-i386 anita\:9.1-sparc64 \
+ anita\:8.2-amd64 anita\:8.2-i386 \
+ anita\:7.1-amd64 anita\:7.1-i386 \
+
+MULTIARCH_TAGS := \
+ centos\:7.6-armhfp-clean centos\:7.6-amd64-clean \
+ centos\:7.3-aarch64-clean centos\:7.3-amd64-clean \
+ centos\:7.2-amd64-clean \
+ $(foreach a,x86_64 aarch64, \
+ $(foreach v,34 33 32 31 30 29 25 24, \
+ fedora\:$(v)-$(a))) \
+ $(foreach a,ppc64le, \
+ $(foreach v,34 33 29 25 24, \
+ fedora\:$(v)-$(a))) \
+ $(foreach a,s390x, \
+ $(foreach v,34 33 32 31 30 29, \
+ fedora\:$(v)-$(a))) \
+ fedora\:28-armhfp \
+ $(foreach a,ppc64el armhf mipsel amd64 i386, \
+ $(foreach v,bullseye buster stretch, \
+ debian-debootstrap\:$(a)-$(v))) \
+ $(foreach a,arm64 mips, \
+ $(foreach v,buster stretch, \
+ debian-debootstrap\:$(a)-$(v))) \
+ $(foreach a,ppc64el arm64 armhf amd64, \
+ $(foreach v,jammy focal bionic xenial, \
+ ubuntu-debootstrap\:$(a)-$(v))) \
+ $(foreach a,i386, \
+ $(foreach v,bionic xenial, \
+ ubuntu-debootstrap\:$(a)-$(v))) \
+ ubuntu-debootstrap\:powerpc-xenial \
+ $(foreach a,aarch64 armhf amd64 i386, \
+ $(foreach v,v3.14 v3.13 v3.12 v3.11 v3.10 v3.9 v3.8 v3.7 v3.6, \
+ alpine\:$(a)-$(v))) \
+
+OTHER_TAGS := djgpp\:6.1.0
+
+ALL_TAGS := $(ANITA_TAGS) $(MULTIARCH_TAGS) $(OTHER_TAGS)
+
+BROKEN_TAGS := anita\:7.1-amd64 anita\:7.1-i386 \
+ centos\:7.6-armhfp-clean \
+ fedora\:30-s390x fedora\:28-armhfp \
+
+WORKING_TAGS := $(filter-out $(BROKEN_TAGS),$(ALL_TAGS))
+
+arch_filter = $(sort \
+ $(foreach arch,$(1), \
+ $(filter-out $(subst $(arch),,$(MULTIARCH_TAGS)),$(MULTIARCH_TAGS))))
+
+machine_map = \
+ $(if $(filter i386 i686 x86,$(1)),i386 x86, \
+ $(if $(filter x86_64,$(1)),amd64 i386 x86, \
+ $(if $(filter armv7l armv6l,$(1)),armhf, \
+ $(if $(filter aarch64,$(1)),aarch64 arm64, \
+ $(if $(filter ppc64le,$(1)),ppc64le ppc64el, \
+ $(if $(filter ppc,$(1)),powerpc, \
+ $(if $(filter mips,$(1)),mips mipsel, \
+ $(1))))))))
+
+NATIVE_TAGS := $(call arch_filter,$(call machine_map,$(shell uname -m)))
+
+# rather arbitrary selection of images that seem to work (focus on amd64)
+DEFAULT_TAGS := \
+ anita\:9.1-sparc64 \
+ anita\:9.1-amd64 \
+ anita\:9.1-i386 \
+ anita\:8.2-amd64 \
+ djgpp\:6.1.0 \
+ fedora\:30-aarch64 \
+ fedora\:25-x86_64 \
+ fedora\:25-ppc64le \
+ fedora\:25-aarch64 \
+ fedora\:24-x86_64 \
+ centos\:7.3-aarch64-clean \
+ centos\:7.3-amd64-clean \
+ centos\:7.2-amd64-clean \
+ debian-debootstrap\:ppc64el-stretch \
+ debian-debootstrap\:armhf-stretch \
+ debian-debootstrap\:mips-stretch \
+ debian-debootstrap\:mipsel-stretch \
+ debian-debootstrap\:amd64-stretch \
+ debian-debootstrap\:i386-stretch \
+ ubuntu-debootstrap\:arm64-xenial \
+ ubuntu-debootstrap\:amd64-xenial \
+ ubuntu-debootstrap\:powerpc-xenial \
+ ubuntu-debootstrap\:amd64-bionic \
+ alpine\:aarch64-v3.9 \
+ alpine\:amd64-v3.8 \
+ alpine\:amd64-v3.7 \
+
+# also run all native tests by default
+DEFAULT_TAGS += $(filter-out $(DEFAULT_TAGS),$(NATIVE_TAGS))
+
+# original 1.0.x tags
+10X_TAGS := \
+ anita\:7.1-amd64 \
+ anita\:7.1-i386 \
+ djgpp\:6.1.0 \
+ alpine\:amd64-v3.6 \
+ alpine\:amd64-v3.7 \
+ alpine\:i386-v3.6 \
+ alpine\:i386-v3.7 \
+ centos\:7.2-amd64-clean \
+ centos\:7.3-aarch64-clean \
+ centos\:7.3-amd64-clean \
+ debian-debootstrap\:amd64-sid \
+ debian-debootstrap\:amd64-stretch \
+ debian-debootstrap\:armhf-stretch \
+ debian-debootstrap\:i386-sid \
+ debian-debootstrap\:i386-stretch \
+ debian-debootstrap\:mips-stretch \
+ debian-debootstrap\:mipsel-stretch \
+ debian-debootstrap\:powerpc-sid \
+ debian-debootstrap\:ppc64el-stretch \
+ fedora\:24-x86_64 \
+ fedora\:25-aarch64 \
+ fedora\:25-ppc64le \
+ fedora\:25-x86_64 \
+ ubuntu-debootstrap\:amd64-xenial \
+ ubuntu-debootstrap\:amd64-zesty \
+ ubuntu-debootstrap\:arm64-xenial \
+ ubuntu-debootstrap\:i386-xenial \
+ ubuntu-debootstrap\:i386-zesty \
+
+# additional tags added after initial release
+10X_TAGS += \
+ alpine\:aarch64-v3.8 \
+ alpine\:armhf-v3.8 \
+ alpine\:amd64-v3.8 \
+ alpine\:i386-v3.8 \
+ debian-debootstrap\:amd64-buster \
+ debian-debootstrap\:arm64-buster \
+ debian-debootstrap\:i386-buster \
+ ubuntu-debootstrap\:amd64-bionic \
+ ubuntu-debootstrap\:arm64-bionic \
+ ubuntu-debootstrap\:i386-bionic \
+
+# can only run what is still maintained
+10X_TAGS := $(filter $(10X_TAGS),$(ALL_TAGS))
+
+# original 1.1.x tags
+11X_TAGS := \
+ anita\:7.1-amd64 \
+ djgpp\:6.1.0 \
+ fedora\:30-x86_64 \
+ fedora\:30-aarch64 \
+ fedora\:29-x86_64 \
+ fedora\:25-x86_64 \
+ fedora\:25-ppc64le \
+ fedora\:25-aarch64 \
+ fedora\:24-x86_64 \
+ centos\:7.6-amd64-clean \
+ centos\:7.3-aarch64-clean \
+ centos\:7.3-amd64-clean \
+ centos\:7.2-amd64-clean \
+ debian-debootstrap\:ppc64el-stretch \
+ debian-debootstrap\:armhf-stretch \
+ debian-debootstrap\:mips-stretch \
+ debian-debootstrap\:mipsel-stretch \
+ debian-debootstrap\:amd64-stretch \
+ debian-debootstrap\:i386-stretch \
+ debian-debootstrap\:amd64-sid \
+ ubuntu-debootstrap\:arm64-xenial \
+ ubuntu-debootstrap\:amd64-xenial \
+ ubuntu-debootstrap\:powerpc-xenial \
+ ubuntu-debootstrap\:amd64-bionic \
+ alpine\:aarch64-v3.9 \
+ alpine\:amd64-v3.9 \
+ alpine\:amd64-v3.8 \
+ alpine\:amd64-v3.7 \
+ alpine\:amd64-v3.6 \
+ alpine\:armhf-v3.8 \
+ alpine\:i386-v3.9 \
+ alpine\:i386-v3.8 \
+ alpine\:i386-v3.7 \
+ alpine\:i386-v3.6 \
+ debian-debootstrap\:amd64-buster \
+ debian-debootstrap\:i386-buster \
+ debian-debootstrap\:i386-sid \
+ ubuntu-debootstrap\:armhf-xenial \
+ ubuntu-debootstrap\:i386-bionic \
+ ubuntu-debootstrap\:i386-xenial \
+ ubuntu-debootstrap\:ppc64el-xenial \
+
+# can only run what is still maintained
+11X_TAGS := $(filter $(11X_TAGS),$(ALL_TAGS))
+
+default: $(DEFAULT_TAGS)
+
+native: $(NATIVE_TAGS)
+
+working: $(WORKING_TAGS)
+
+all: $(ALL_TAGS)
+
+1.0.x: export TEST_REVISION=refs/heads/1.0.x
+1.0.x: $(10X_TAGS)
+
+1.1.x: export TEST_REVISION=refs/heads/1.1.x
+1.1.x: $(11X_TAGS)
+
+show-default:
+ @printf "%s\n" $(DEFAULT_TAGS)
+
+show-native:
+ @printf "%s\n" $(NATIVE_TAGS)
+
+show-working:
+ @printf "%s\n" $(WORKING_TAGS)
+
+show-all:
+ @printf "%s\n" $(ALL_TAGS)
+
+show-1.0.x:
+ @printf "%s\n" $(10X_TAGS)
+
+show-1.1.x:
+ @printf "%s\n" $(11X_TAGS)
+
+.PHONY: default native all 1.0.x 1.1.x
+.PHONY: show-default show-native show-all show-1.0.x show-1.1.x
+.PHONY: $(ALL_TAGS)
diff --git a/util/manibuilder/README.md b/util/manibuilder/README.md
new file mode 100644
index 000000000..b00d61818
--- /dev/null
+++ b/util/manibuilder/README.md
@@ -0,0 +1,72 @@
+Manibuilder
+===========
+
+Manibuilder is a set of Dockerfiles for manic build testing, held
+together by some make-foo. Most of the Dockerfiles make use of
+*multiarch* images. This way we can test building on many platforms
+supported by *Qemu*. The idea is to test in environments as close
+as possible to those of potential users, i.e. no cross-compiling
+(with some exceptions).
+
+Make targets
+------------
+
+For each supported target OS/version/architecture exists a *tag*
+target, for instance `alpine:amd64-v3.7`. These targets will
+automatically check for existence of their respective *Docker*
+images (sub target <tag>-check-build), and build them if necessary
+(<tag>-build). Finally, flashrom revision `$(TEST_REVISION)` is
+fetched and build tested.
+
+The results will be kept by *Docker* as stopped containers and
+can be accessed with the <tag>-shell target.
+
+There are some additional targets that form sets of the *tag*
+targets:
+
+* default: runs a preselected subset of all supported tags.
+* native: runs all tags native to the host architecture.
+* all: runs all supported tags.
+
+For each of these show-<set> lists the included *tags*.
+
+For preparation of *Qemu* for the *multiarch* images, there is the
+`register` target. It has to be run once per boot, though as it
+uses a privileged *Docker* container, that is kept as a manual step.
+
+Usage example
+-------------
+
+The most common use case may be testing the current upstream
+*master* branch which is the default for `$(TEST_REVISION)`.
+You'll need roughly 20GiB for the *Docker* images. Might look
+like this:
+
+ $ # have to register Qemu first:
+ $ make register
+ [...]
+ $ # run the default target:
+ $ make -j4
+ debian-debootstrap:mips-stretch: 2
+ debian-debootstrap:mips-sid: 2
+ debian-debootstrap:mips-buster: 2
+ ubuntu-debootstrap:powerpc-xenial: 2
+ djgpp:6.1.0: 2
+
+For each *tag* that returns with a non-zero exit code, the *tag*
+and actual exit code is printed. An exit code of `2` is most likely
+as that is what *make* returns on failure. Other exit codes might
+hint towards a problem in the setup. Failing *tags* can then be
+investigated individually with the <tag>-shell target, e.g.:
+
+ $ make debian-debootstrap:mips-sid-shell
+ [...]
+ mani@63536fc102a5:~/flashrom$ make
+ [...]
+ cc -MMD -Os -Wall -Wshadow -Werror -I/usr/include/libusb-1.0 -D'CONFIG_DEFAULT_PROGRAMMER=PROGRAMMER_INVALID' -D'CONFIG_DEFAULT_PROGRAMMER_ARGS="''"' -D'CONFIG_SERPROG=1' -D'CONFIG_PONY_SPI=1' -D'CONFIG_BITBANG_SPI=1' -D'CONFIG_GFXNVIDIA=1' -D'CONFIG_SATASII=1' -D'CONFIG_ATAVIA=1' -D'CONFIG_IT8212=1' -D'CONFIG_FT2232_SPI=1' -D'CONFIG_USBBLASTER_SPI=1' -D'CONFIG_PICKIT2_SPI=1' -D'HAVE_FT232H=1' -D'CONFIG_DUMMY=1' -D'CONFIG_DRKAISER=1' -D'CONFIG_NICINTEL=1' -D'CONFIG_NICINTEL_SPI=1' -D'CONFIG_NICINTEL_EEPROM=1' -D'CONFIG_OGP_SPI=1' -D'CONFIG_BUSPIRATE_SPI=1' -D'CONFIG_DEDIPROG=1' -D'CONFIG_DEVELOPERBOX_SPI=1' -D'CONFIG_LINUX_MTD=1' -D'CONFIG_LINUX_SPI=1' -D'CONFIG_CH341A_SPI=1' -D'CONFIG_DIGILENT_SPI=1' -D'NEED_PCI=1' -D'NEED_RAW_ACCESS=1' -D'NEED_LIBUSB0=1' -D'NEED_LIBUSB1=1' -D'HAVE_UTSNAME=1' -D'HAVE_CLOCK_GETTIME=1' -D'FLASHROM_VERSION="p1.0-141-g9cecc7e"' -o libflashrom.o -c libflashrom.c
+ libflashrom.c:386:12: error: 'flashrom_layout_parse_fmap' defined but not used [-Werror=unused-function]
+ static int flashrom_layout_parse_fmap(struct flashrom_layout **layout,
+ ^~~~~~~~~~~~~~~~~~~~~~~~~~
+ cc1: all warnings being treated as errors
+ make: *** [Makefile:1075: libflashrom.o] Error 1
+ $ # uh-huh, might be a problem with big-endian #if foo
diff --git a/util/manibuilder/anita-wrapper.sh b/util/manibuilder/anita-wrapper.sh
new file mode 100644
index 000000000..3ff9ee17b
--- /dev/null
+++ b/util/manibuilder/anita-wrapper.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+cd
+
+[ "${IDENT}" ] || IDENT=$(mktemp -u XXXXXXXX)
+
+CCACHE=.ccache/anita-${IDENT}.img
+
+[ -f ${CCACHE} ] || zcat cache.img.gz >${CCACHE}
+
+if [ $# -eq 0 ]; then
+ exec anita --vmm-args "-hdb ${CCACHE}" --memory-size=${MEM_SIZE} \
+ interact ${INST_IMG}
+else
+ exec anita --vmm-args "-hdb ${CCACHE}" --memory-size=${MEM_SIZE} \
+ --persist --run ". ./init && manitest \"$*\"" \
+ boot ${INST_IMG}
+fi
diff --git a/util/manibuilder/mani-wrapper.sh b/util/manibuilder/mani-wrapper.sh
new file mode 100644
index 000000000..c3f583401
--- /dev/null
+++ b/util/manibuilder/mani-wrapper.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+cd /home/mani/flashrom/
+
+if [ $# -eq 0 ]; then
+ exec "${DEVSHELL}"
+else
+ exec "${DEVSHELL}" -c "$*"
+fi
diff --git a/util/meson.build b/util/meson.build
deleted file mode 100644
index 24278d73f..000000000
--- a/util/meson.build
+++ /dev/null
@@ -1 +0,0 @@
-subdir('ich_descriptors_tool')
diff --git a/util/shell.nix b/util/shell.nix
new file mode 100644
index 000000000..987777c35
--- /dev/null
+++ b/util/shell.nix
@@ -0,0 +1,18 @@
+with import <nixpkgs> {};
+
+stdenv.mkDerivation {
+ name = "flashrom";
+
+ buildInputs = [
+ cmocka
+ gcc
+ gnumake
+ libftdi1
+ libjaylink
+ libusb1
+ meson
+ ninja
+ pciutils
+ pkg-config
+ ];
+}
diff --git a/util/ubertest/ubertest.sh b/util/ubertest/ubertest.sh
index e64daf7c3..009194d45 100755
--- a/util/ubertest/ubertest.sh
+++ b/util/ubertest/ubertest.sh
@@ -312,7 +312,7 @@ LOGS="logs"
# Setup temporary working directories:
# LOCAL_TMPDIR: Working directory on local host.
# REMOTE_TMPDIR: Working directory on remote host.
-# TMPDIR: The temporary directy in which we do most of the work. This is
+# TMPDIR: The temporary directory in which we do most of the work. This is
# convenient for commands that depend on $DO_REMOTE.
LOCAL_TMPDIR=$(mktemp -d --tmpdir flashrom_test.XXXXXXXX)
if [ $? -ne 0 ] ; then
@@ -827,7 +827,7 @@ partial_write_test()
return $EXIT_SUCCESS
}
-# Before anything else, check to see if Flashrom can succesfully probe
+# Before anything else, check to see if Flashrom can successfully probe
# for and find the flash chips. If not, we will abort.
flashrom_log_scmd $DO_REMOTE "$NEW_FLASHROM $PRIMARY_OPTS" "verify_probe"
if [ $? -ne 0 ]; then
diff --git a/w29ee011.c b/w29ee011.c
index a570bd6d1..234b865c8 100644
--- a/w29ee011.c
+++ b/w29ee011.c
@@ -15,9 +15,24 @@
*/
#include <string.h>
+#include <stdbool.h>
+
#include "flash.h"
#include "chipdrivers.h"
+bool w29ee011_can_override(const char *const chip_name, const char *const override_chip)
+{
+ if (!override_chip || strcmp(override_chip, chip_name)) {
+ msg_cdbg("Old Winbond W29* probe method disabled because "
+ "the probing sequence puts the AMIC A49LF040A in "
+ "a funky state. Use 'flashrom -c %s' if you "
+ "have a board with such a chip.\n", chip_name);
+ return false;
+ }
+
+ return true;
+}
+
/* According to the Winbond W29EE011, W29EE012, W29C010M, W29C011A
* datasheets this is the only valid probe function for those chips.
*/
@@ -26,27 +41,19 @@ int probe_w29ee011(struct flashctx *flash)
chipaddr bios = flash->virtual_memory;
uint8_t id1, id2;
- if (!chip_to_probe || strcmp(chip_to_probe, flash->chip->name)) {
- msg_cdbg("Old Winbond W29* probe method disabled because "
- "the probing sequence puts the AMIC A49LF040A in "
- "a funky state. Use 'flashrom -c %s' if you "
- "have a board with such a chip.\n", flash->chip->name);
- return 0;
- }
-
/* Issue JEDEC Product ID Entry command */
chip_writeb(flash, 0xAA, bios + 0x5555);
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0x55, bios + 0x2AAA);
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0x80, bios + 0x5555);
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0xAA, bios + 0x5555);
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0x55, bios + 0x2AAA);
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0x60, bios + 0x5555);
- programmer_delay(10);
+ programmer_delay(flash, 10);
/* Read product ID */
id1 = chip_readb(flash, bios);
@@ -54,11 +61,11 @@ int probe_w29ee011(struct flashctx *flash)
/* Issue JEDEC Product ID Exit command */
chip_writeb(flash, 0xAA, bios + 0x5555);
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0x55, bios + 0x2AAA);
- programmer_delay(10);
+ programmer_delay(flash, 10);
chip_writeb(flash, 0xF0, bios + 0x5555);
- programmer_delay(10);
+ programmer_delay(flash, 10);
msg_cdbg("%s: id1 0x%02x, id2 0x%02x\n", __func__, id1, id2);
diff --git a/w39.c b/w39.c
index f58c495d1..114d0b563 100644
--- a/w39.c
+++ b/w39.c
@@ -27,7 +27,7 @@ static uint8_t w39_idmode_readb(struct flashctx *flash, unsigned int offset)
chip_writeb(flash, 0xAA, bios + 0x5555);
chip_writeb(flash, 0x55, bios + 0x2AAA);
chip_writeb(flash, 0x90, bios + 0x5555);
- programmer_delay(10);
+ programmer_delay(flash, 10);
/* Read something, maybe hardware lock bits */
val = chip_readb(flash, bios + offset);
@@ -36,7 +36,7 @@ static uint8_t w39_idmode_readb(struct flashctx *flash, unsigned int offset)
chip_writeb(flash, 0xAA, bios + 0x5555);
chip_writeb(flash, 0x55, bios + 0x2AAA);
chip_writeb(flash, 0xF0, bios + 0x5555);
- programmer_delay(10);
+ programmer_delay(flash, 10);
return val;
}
diff --git a/wbsio_spi.c b/wbsio_spi.c
index 632ff72ae..9f33b18de 100644
--- a/wbsio_spi.c
+++ b/wbsio_spi.c
@@ -14,14 +14,13 @@
* GNU General Public License for more details.
*/
-#if defined(__i386__) || defined(__x86_64__)
-
#include <stdlib.h>
#include "flash.h"
#include "chipdrivers.h"
#include "programmer.h"
-#include "hwaccess.h"
+#include "hwaccess_physmap.h"
+#include "hwaccess_x86_io.h"
#include "spi.h"
#define WBSIO_PORT1 0x2e
@@ -156,7 +155,7 @@ static int wbsio_spi_send_command(const struct flashctx *flash, unsigned int wri
OUTB(writearr[0], data->spibase);
OUTB(mode, data->spibase + 1);
- programmer_delay(10);
+ default_delay(10);
if (!readcnt)
return 0;
@@ -177,23 +176,25 @@ static int wbsio_spi_read(struct flashctx *flash, uint8_t *buf,
return 0;
}
-static struct spi_master spi_master_wbsio = {
- .max_data_read = MAX_DATA_UNSPECIFIED,
- .max_data_write = MAX_DATA_UNSPECIFIED,
- .command = wbsio_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = wbsio_spi_read,
- .write_256 = spi_chip_write_1,
- .write_aai = spi_chip_write_1,
-};
-
static int wbsio_spi_shutdown(void *data)
{
free(data);
return 0;
}
-int wbsio_check_for_spi(void)
+static const struct spi_master spi_master_wbsio = {
+ .max_data_read = MAX_DATA_UNSPECIFIED,
+ .max_data_write = MAX_DATA_UNSPECIFIED,
+ .command = wbsio_spi_send_command,
+ .map_flash_region = physmap,
+ .unmap_flash_region = physunmap,
+ .read = wbsio_spi_read,
+ .write_256 = spi_chip_write_1,
+ .write_aai = spi_chip_write_1,
+ .shutdown = wbsio_spi_shutdown,
+};
+
+int wbsio_check_for_spi(struct board_cfg *cfg)
{
uint16_t wbsio_spibase = 0;
@@ -207,18 +208,12 @@ int wbsio_check_for_spi(void)
"1024 kB!\n", __func__);
max_rom_decode.spi = 1024 * 1024;
- struct wbsio_spi_data * data = calloc(1, sizeof(struct wbsio_spi_data));
+ struct wbsio_spi_data *data = calloc(1, sizeof(*data));
if (!data) {
msg_perr("Unable to allocate space for extra SPI master data.\n");
return SPI_GENERIC_ERROR;
}
data->spibase = wbsio_spibase;
- register_shutdown(wbsio_spi_shutdown, data);
- spi_master_wbsio.data = data;
- register_spi_master(&spi_master_wbsio);
-
- return 0;
+ return register_spi_master(&spi_master_wbsio, data);
}
-
-#endif /* defined(__i386__) || defined(__x86_64__) */
diff --git a/writeprotect.c b/writeprotect.c
index b26c121c5..411089def 100644
--- a/writeprotect.c
+++ b/writeprotect.c
@@ -15,380 +15,613 @@
*
*/
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <strings.h>
+#include "spi.h"
#include "flash.h"
-#include "flashchips.h"
+#include "libflashrom.h"
#include "chipdrivers.h"
-#include "spi.h"
#include "writeprotect.h"
+#include "programmer.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.
+ * Allow specialisation in opaque masters, such as ichspi hwseq, to r/w to status registers.
*/
+static int wp_write_register(const struct flashctx *flash, enum flash_reg reg, uint8_t value)
+{
+ int ret;
+ if ((flash->mst->buses_supported & BUS_PROG) && flash->mst->opaque.write_register) {
+ ret = flash->mst->opaque.write_register(flash, reg, value);
+ } else {
+ ret = spi_write_register(flash, reg, value);
+ }
-struct wp_range {
- unsigned int start; /* starting address */
- unsigned int len; /* len */
-};
+ /* Writing SR1 should always be supported, ignore errors for other registers. */
+ if (ret == SPI_INVALID_OPCODE && reg != STATUS1) {
+ msg_pdbg("%s: write to register %d not supported by programmer, ignoring.\n", __func__, reg);
+ ret = 0;
+ }
+ return ret;
+}
-enum bit_state {
- OFF = 0,
- ON = 1,
- X = -1 /* don't care. Must be bigger than max # of bp. */
-};
+static int wp_read_register(const struct flashctx *flash, enum flash_reg reg, uint8_t *value)
+{
+ int ret;
+ if ((flash->mst->buses_supported & BUS_PROG) && flash->mst->opaque.read_register) {
+ ret = flash->mst->opaque.read_register(flash, reg, value);
+ } else {
+ ret = spi_read_register(flash, reg, value);
+ }
-/*
- * 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.
- */
+ /* Reading SR1 should always be supported, ignore errors for other registers. */
+ if (ret == SPI_INVALID_OPCODE && reg != STATUS1) {
+ msg_pdbg("%s: read from register %d not is supported by programmer, "
+ "writeprotect operations will assume it contains 0x00.\n", __func__, reg);
+ *value = 0;
+ ret = 0;
+ }
+ return ret;
+}
-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 */
-};
+/** Read and extract a single bit from the chip's registers */
+static enum flashrom_wp_result read_bit(uint8_t *value, bool *present, struct flashctx *flash, struct reg_bit_info bit)
+{
+ *present = bit.reg != INVALID_REG;
+ if (*present) {
+ if (wp_read_register(flash, bit.reg, value))
+ return FLASHROM_WP_ERR_READ_FAILED;
+ *value = (*value >> bit.bit_index) & 1;
+ } else {
+ /* Zero bit, it may be used by compare_ranges(). */
+ *value = 0;
+ }
-/*
- * 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;
-};
+ return FLASHROM_WP_OK;
+}
-struct wp_context {
- struct status_register_layout sr1; /* status register 1 */
- struct wp_range_descriptor *descrs;
+/** Read all WP configuration bits from the chip's registers. */
+static enum flashrom_wp_result read_wp_bits(struct wp_bits *bits, struct flashctx *flash)
+{
+ /*
+ * For each WP bit that is included in the chip's register layout, read
+ * the register that contains it, extracts the bit's value, and assign
+ * it to the appropriate field in the wp_bits structure.
+ */
+ const struct reg_bit_map *bit_map = &flash->chip->reg_bits;
+ bool ignored;
+ size_t i;
+ enum flashrom_wp_result ret;
/*
- * 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.
+ * Write protection select bit (WPS) controls kind of write protection
+ * that is used by the chip. When set, BP bits are ignored and each
+ * block/sector has its own WP bit managed by special commands. When
+ * the bit is set and we can't change it, just bail out until
+ * implementation is extended to handle this kind of WP.
*/
- int (*get_modifier_bits)(const struct flashctx *flash,
- struct modifier_bits *m);
- int (*set_modifier_bits)(const struct flashctx *flash,
- struct modifier_bits *m);
-};
+ if (bit_map->wps.reg != INVALID_REG && bit_map->wps.writability != RW) {
+ bool wps_bit_present;
+ uint8_t wps;
-/*
- * 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)
+ ret = read_bit(&wps, &wps_bit_present, flash, bit_map->wps);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
-static uint8_t do_read_status(const struct flashctx *flash)
+ if (wps_bit_present && wps)
+ return FLASHROM_WP_ERR_UNSUPPORTED_STATE;
+ }
+
+ ret = read_bit(&bits->tb, &bits->tb_bit_present, flash, bit_map->tb);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ ret = read_bit(&bits->sec, &bits->sec_bit_present, flash, bit_map->sec);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ ret = read_bit(&bits->cmp, &bits->cmp_bit_present, flash, bit_map->cmp);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ ret = read_bit(&bits->srp, &bits->srp_bit_present, flash, bit_map->srp);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ ret = read_bit(&bits->srl, &bits->srl_bit_present, flash, bit_map->srl);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(bits->bp); i++) {
+ if (bit_map->bp[i].reg == INVALID_REG)
+ break;
+
+ bits->bp_bit_count = i + 1;
+ ret = read_bit(&bits->bp[i], &ignored, flash, bit_map->bp[i]);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+ }
+
+ return ret;
+}
+
+/** Helper function for get_wp_bits_reg_values(). */
+static void set_reg_bit(
+ uint8_t *reg_values, uint8_t *bit_masks, uint8_t *write_masks,
+ struct reg_bit_info bit, uint8_t value)
{
- if (flash->chip->read_status)
- return flash->chip->read_status(flash);
- else
- return spi_read_status_register(flash);
+ if (bit.reg != INVALID_REG) {
+ reg_values[bit.reg] |= value << bit.bit_index;
+ bit_masks[bit.reg] |= 1 << bit.bit_index;
+
+ /* Avoid RO and OTP bits causing a register update */
+ if (bit.writability == RW)
+ write_masks[bit.reg] |= 1 << bit.bit_index;
+ }
}
-static int do_write_status(const struct flashctx *flash, int status)
+/** Convert wp_bits to register values and write masks */
+static void get_wp_bits_reg_values(
+ uint8_t *reg_values, uint8_t *bit_masks, uint8_t *write_masks,
+ const struct reg_bit_map *reg_bits, struct wp_bits bits)
{
- if (flash->chip->write_status)
- return flash->chip->write_status(flash, status);
- else
- return spi_write_status_register(flash, status);
+ memset(reg_values, 0, sizeof(uint8_t) * MAX_REGISTERS);
+ memset(bit_masks, 0, sizeof(uint8_t) * MAX_REGISTERS);
+ memset(write_masks, 0, sizeof(uint8_t) * MAX_REGISTERS);
+
+ for (size_t i = 0; i < bits.bp_bit_count; i++)
+ set_reg_bit(reg_values, bit_masks, write_masks, reg_bits->bp[i], bits.bp[i]);
+
+ set_reg_bit(reg_values, bit_masks, write_masks, reg_bits->tb, bits.tb);
+ set_reg_bit(reg_values, bit_masks, write_masks, reg_bits->sec, bits.sec);
+ set_reg_bit(reg_values, bit_masks, write_masks, reg_bits->cmp, bits.cmp);
+ set_reg_bit(reg_values, bit_masks, write_masks, reg_bits->srp, bits.srp);
+ set_reg_bit(reg_values, bit_masks, write_masks, reg_bits->srl, bits.srl);
+ /* Note: always setting WPS bit to zero until its fully supported. */
+ set_reg_bit(reg_values, bit_masks, write_masks, reg_bits->wps, 0);
}
-enum wp_mode get_wp_mode(const char *mode_str)
+/** Write WP configuration bits to the flash's registers. */
+static enum flashrom_wp_result write_wp_bits(struct flashctx *flash, struct wp_bits bits)
{
- enum wp_mode wp_mode = WP_MODE_UNKNOWN;
+ uint8_t reg_values[MAX_REGISTERS];
+ uint8_t bit_masks[MAX_REGISTERS]; /* masks of valid bits */
+ uint8_t write_masks[MAX_REGISTERS]; /* masks of written bits */
+ get_wp_bits_reg_values(reg_values, bit_masks, write_masks, &flash->chip->reg_bits, bits);
+
+ /* Write each register whose value was updated */
+ for (enum flash_reg reg = STATUS1; reg < MAX_REGISTERS; reg++) {
+ if (!write_masks[reg])
+ continue;
+
+ uint8_t value;
+ if (wp_read_register(flash, reg, &value))
+ return FLASHROM_WP_ERR_READ_FAILED;
+
+ /* Skip unnecessary register writes */
+ uint8_t actual = value & write_masks[reg];
+ uint8_t expected = reg_values[reg] & write_masks[reg];
+ if (actual == expected)
+ continue;
+
+ value = (value & ~write_masks[reg]) | expected;
+
+ if (wp_write_register(flash, reg, value))
+ return FLASHROM_WP_ERR_WRITE_FAILED;
+ }
- 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;
+ enum flashrom_wp_result ret = FLASHROM_WP_OK;
+ /* Verify each register even if write to it was skipped */
+ for (enum flash_reg reg = STATUS1; reg < MAX_REGISTERS; reg++) {
+ if (!bit_masks[reg])
+ continue;
- return wp_mode;
-}
+ uint8_t value;
+ if (wp_read_register(flash, reg, &value))
+ return FLASHROM_WP_ERR_READ_FAILED;
-/* 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;
+ msg_cdbg2("%s: wp_verify reg:%u value:0x%x\n", __func__, reg, value);
+ uint8_t actual = value & bit_masks[reg];
+ uint8_t expected = reg_values[reg] & bit_masks[reg];
- switch (flash->chip->manufacture_id) {
- default:
- msg_cerr("%s: flash vendor (0x%x) not found, aborting\n",
- __func__, flash->chip->manufacture_id);
- return -1;
+ if (actual != expected) {
+ msg_cdbg("%s: wp_verify failed: reg:%u actual:0x%x expected:0x%x\n",
+ __func__, reg, actual, expected);
+ ret = FLASHROM_WP_ERR_VERIFY_FAILED;
+ }
}
- return 0;
+ return ret;
}
-static uint8_t generic_get_bp_mask(struct wp_context *wp)
+static decode_range_func_t *lookup_decode_range_func_ptr(const struct flashchip *chip)
{
- return ((1 << (wp->sr1.bp0_pos + wp->sr1.bp_bits)) - 1) ^ \
- ((1 << wp->sr1.bp0_pos) - 1);
+ switch (chip->decode_range) {
+ case DECODE_RANGE_SPI25: return &decode_range_spi25;
+ case DECODE_RANGE_SPI25_64K_BLOCK: return &decode_range_spi25_64k_block;
+ case DECODE_RANGE_SPI25_BIT_CMP: return &decode_range_spi25_bit_cmp;
+ case DECODE_RANGE_SPI25_2X_BLOCK: return &decode_range_spi25_2x_block;
+ /* default: total function, 0 indicates no decode range function set. */
+ case NO_DECODE_RANGE_FUNC: return NULL;
+ };
+
+ return NULL;
}
-static uint8_t generic_get_status_check_mask(struct wp_context *wp)
+
+/** Get the range selected by a WP configuration. */
+static enum flashrom_wp_result get_wp_range(struct wp_range *range, struct flashctx *flash, const struct wp_bits *bits)
{
- return generic_get_bp_mask(wp) | 1 << wp->sr1.srp_pos;
+ decode_range_func_t *decode_range = lookup_decode_range_func_ptr(flash->chip);
+ if (decode_range == NULL)
+ return FLASHROM_WP_ERR_OTHER;
+
+ decode_range(&range->start, &range->len, bits, flashrom_flash_getsize(flash));
+ return FLASHROM_WP_OK;
}
-/* 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)
+/** Write protect bit values and the range they will activate. */
+struct wp_range_and_bits {
+ struct wp_bits bits;
+ struct wp_range range;
+};
+
+/**
+ * Comparator used for sorting ranges in get_ranges_and_wp_bits().
+ *
+ * Ranges are ordered by these attributes, in decreasing significance:
+ * (range length, range start, cmp bit, sec bit, tb bit, bp bits)
+ */
+static int compare_ranges(const void *aa, const void *bb)
{
- 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;
- }
- }
+ const struct wp_range_and_bits
+ *a = (const struct wp_range_and_bits *)aa,
+ *b = (const struct wp_range_and_bits *)bb;
+
+ int ord = 0;
+
+ if (ord == 0)
+ ord = a->range.len - b->range.len;
- if (!range_found) {
- msg_cerr("%s: matching range not found\n", __func__);
- return -1;
+ if (ord == 0)
+ ord = a->range.start - b->range.start;
+
+ if (ord == 0)
+ ord = a->bits.cmp - b->bits.cmp;
+
+ if (ord == 0)
+ ord = a->bits.sec - b->bits.sec;
+
+ if (ord == 0)
+ ord = a->bits.tb - b->bits.tb;
+
+ for (int i = a->bits.bp_bit_count - 1; i >= 0; i--) {
+ if (ord == 0)
+ ord = a->bits.bp[i] - b->bits.bp[i];
}
- *check_mask = generic_get_status_check_mask(wp);
- return 0;
+ return ord;
}
-static int generic_status_to_range(const struct flashctx *flash,
- const uint8_t sr1, unsigned int *start, unsigned int *len)
+static bool can_write_bit(const struct reg_bit_info bit)
{
- struct wp_context *wp;
- struct wp_range_descriptor *r;
- int num_entries, i, status_found = 0;
- uint8_t sr1_bp;
- struct modifier_bits m;
+ /*
+ * TODO: check if the programmer supports writing the register that the
+ * bit is in. For example, some chipsets may only allow SR1 to be
+ * written.
+ */
+
+ return bit.reg != INVALID_REG && bit.writability == RW;
+}
+
+/**
+ * Enumerate all protection ranges that the chip supports and that are able to
+ * be activated, given limitations such as OTP bits or programmer-enforced
+ * restrictions. Returns a list of deduplicated wp_range_and_bits structures.
+ *
+ * Allocates a buffer that must be freed by the caller with free().
+ */
+static enum flashrom_wp_result get_ranges_and_wp_bits(struct flashctx *flash, struct wp_bits bits, struct wp_range_and_bits **ranges, size_t *count)
+{
+ const struct reg_bit_map *reg_bits = &flash->chip->reg_bits;
+ /*
+ * Create a list of bits that affect the chip's protection range in
+ * range_bits. Each element is a pointer to a member of the wp_bits
+ * structure that will be modified.
+ *
+ * Some chips have range bits that cannot be changed (e.g. MX25L6473E
+ * has a one-time programmable TB bit). Rather than enumerating all
+ * possible values for unwritable bits, just read their values from the
+ * chip to ensure we only enumerate ranges that are actually available.
+ */
+ uint8_t *range_bits[ARRAY_SIZE(bits.bp) + 1 /* TB */ + 1 /* SEC */ + 1 /* CMP */];
+ size_t bit_count = 0;
+
+ for (size_t i = 0; i < ARRAY_SIZE(bits.bp); i++) {
+ if (can_write_bit(reg_bits->bp[i]))
+ range_bits[bit_count++] = &bits.bp[i];
+ }
+
+ if (can_write_bit(reg_bits->tb))
+ range_bits[bit_count++] = &bits.tb;
- if (generic_range_table(flash, &wp, &num_entries))
- return -1;
+ if (can_write_bit(reg_bits->sec))
+ range_bits[bit_count++] = &bits.sec;
- /* 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;
+ if (can_write_bit(reg_bits->cmp))
+ range_bits[bit_count++] = &bits.cmp;
- sr1_bp = (sr1 >> wp->sr1.bp0_pos) & ((1 << wp->sr1.bp_bits) - 1);
+ /* Allocate output buffer */
+ *count = 1 << bit_count;
+ *ranges = calloc(*count, sizeof(struct wp_range_and_bits));
- 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;
+ /* TODO: take WPS bit into account. */
+
+ for (size_t range_index = 0; range_index < *count; range_index++) {
+ /*
+ * Extract bits from the range index and assign them to members
+ * of the wp_bits structure. The loop bounds ensure that all
+ * bit combinations will be enumerated.
+ */
+ for (size_t i = 0; i < bit_count; i++)
+ *range_bits[i] = (range_index >> i) & 1;
+
+ struct wp_range_and_bits *output = &(*ranges)[range_index];
+
+ output->bits = bits;
+ enum flashrom_wp_result ret = get_wp_range(&output->range, flash, &bits);
+ if (ret != FLASHROM_WP_OK) {
+ free(*ranges);
+ return ret;
}
- 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;
+
+ /* Debug: print range bits and range */
+ msg_gspew("Enumerated range: ");
+ if (bits.cmp_bit_present)
+ msg_gspew("CMP=%u ", bits.cmp);
+ if (bits.sec_bit_present)
+ msg_gspew("SEC=%u ", bits.sec);
+ if (bits.tb_bit_present)
+ msg_gspew("TB=%u ", bits.tb);
+ for (size_t i = 0; i < bits.bp_bit_count; i++) {
+ size_t j = bits.bp_bit_count - i - 1;
+ msg_gspew("BP%zu=%u ", j, bits.bp[j]);
}
+ msg_gspew(" start=0x%08zx length=0x%08zx\n",
+ output->range.start, output->range.len);
}
- if (!status_found) {
- msg_cerr("matching status not found\n");
- return -1;
+ /* Sort ranges. Ensures consistency if there are duplicate ranges. */
+ qsort(*ranges, *count, sizeof(struct wp_range_and_bits), compare_ranges);
+
+ /* Remove duplicates */
+ size_t output_index = 0;
+ struct wp_range *last_range = NULL;
+
+ for (size_t i = 0; i < *count; i++) {
+ bool different_to_last =
+ (last_range == NULL) ||
+ ((*ranges)[i].range.start != last_range->start) ||
+ ((*ranges)[i].range.len != last_range->len);
+
+ if (different_to_last) {
+ /* Move range to the next free position */
+ (*ranges)[output_index] = (*ranges)[i];
+ output_index++;
+ /* Keep track of last non-duplicate range */
+ last_range = &(*ranges)[i].range;
+ }
}
+ /* Reduce count to only include non-duplicate ranges */
+ *count = output_index;
+
+ return FLASHROM_WP_OK;
+}
- return 0;
+static bool ranges_equal(struct wp_range a, struct wp_range b)
+{
+ return (a.start == b.start) && (a.len == b.len);
}
-/* 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.
+/*
+ * Modify the range-related bits in a wp_bits structure so they select a given
+ * protection range. Bits that control the protection mode are not changed.
*/
-static int generic_set_range(const struct flashctx *flash,
- unsigned int start, unsigned int len)
+static int set_wp_range(struct wp_bits *bits, struct flashctx *flash, const struct wp_range range)
{
- uint8_t status, expected, check_mask;
+ struct wp_range_and_bits *ranges = NULL;
+ size_t count;
+
+ enum flashrom_wp_result ret = get_ranges_and_wp_bits(flash, *bits, &ranges, &count);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ /* Search for matching range */
+ ret = FLASHROM_WP_ERR_RANGE_UNSUPPORTED;
+ for (size_t i = 0; i < count; i++) {
+
+ if (ranges_equal(ranges[i].range, range)) {
+ *bits = ranges[i].bits;
+ ret = 0;
+ break;
+ }
+ }
- status = do_read_status(flash);
- msg_cdbg("%s: old status: 0x%02x\n", __func__, status);
+ free(ranges);
- expected = status; /* preserve non-bp bits */
- if (generic_range_to_status(flash, start, len, &expected, &check_mask))
- return -1;
+ return ret;
+}
- do_write_status(flash, expected);
+/** Get the mode selected by a WP configuration. */
+static int get_wp_mode(enum flashrom_wp_mode *mode, const struct wp_bits *bits)
+{
+ const enum flashrom_wp_mode wp_modes[2][2] = {
+ {
+ FLASHROM_WP_MODE_DISABLED, /* srl=0, srp=0 */
+ FLASHROM_WP_MODE_HARDWARE, /* srl=0, srp=1 */
+ }, {
+ FLASHROM_WP_MODE_POWER_CYCLE, /* srl=1, srp=0 */
+ FLASHROM_WP_MODE_PERMANENT, /* srl=1, srp=1 */
+ },
+ };
+
+ *mode = wp_modes[bits->srl][bits->srp];
+
+ return FLASHROM_WP_OK;
+}
- 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;
+/** Modify a wp_bits structure such that it will select a specified protection mode. */
+static int set_wp_mode(struct wp_bits *bits, const enum flashrom_wp_mode mode)
+{
+ switch (mode) {
+ case FLASHROM_WP_MODE_DISABLED:
+ bits->srl = 0;
+ bits->srp = 0;
+ return FLASHROM_WP_OK;
+
+ case FLASHROM_WP_MODE_HARDWARE:
+ if (!bits->srp_bit_present)
+ return FLASHROM_WP_ERR_CHIP_UNSUPPORTED;
+
+ bits->srl = 0;
+ bits->srp = 1;
+ return FLASHROM_WP_OK;
+
+ case FLASHROM_WP_MODE_POWER_CYCLE:
+ case FLASHROM_WP_MODE_PERMANENT:
+ default:
+ /*
+ * Don't try to enable power cycle or permanent protection for
+ * now. Those modes may be possible to activate on some chips,
+ * but they are usually unavailable by default or require special
+ * commands to activate.
+ */
+ return FLASHROM_WP_ERR_MODE_UNSUPPORTED;
}
- return 0;
}
-/* Set/clear the status regsiter write protect bit in SR1. */
-static int generic_set_srp0(const struct flashctx *flash, int enable)
+static bool chip_supported(struct flashctx *flash)
{
- uint8_t status, expected, check_mask;
- struct wp_context *wp;
- int num_entries;
+ return (flash->chip != NULL) && (flash->chip->decode_range != NO_DECODE_RANGE_FUNC);
+}
- 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);
+bool wp_operations_available(struct flashrom_flashctx *flash)
+{
+ return (flash->mst->buses_supported & BUS_SPI) ||
+ ((flash->mst->buses_supported & BUS_PROG) &&
+ flash->mst->opaque.read_register &&
+ flash->mst->opaque.write_register);
+}
- if (enable)
- expected |= 1 << wp->sr1.srp_pos;
- else
- expected &= ~(1 << wp->sr1.srp_pos);
+enum flashrom_wp_result wp_read_cfg(struct flashrom_wp_cfg *cfg, struct flashctx *flash)
+{
+ struct wp_bits bits;
+ enum flashrom_wp_result ret = FLASHROM_WP_OK;
- do_write_status(flash, expected);
+ if (!chip_supported(flash))
+ ret = FLASHROM_WP_ERR_CHIP_UNSUPPORTED;
- status = do_read_status(flash);
- msg_cdbg("%s: new status: 0x%02x\n", __func__, status);
+ if (ret == FLASHROM_WP_OK)
+ ret = read_wp_bits(&bits, flash);
- 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;
- }
+ if (ret == FLASHROM_WP_OK)
+ ret = get_wp_range(&cfg->range, flash, &bits);
+
+ if (ret == FLASHROM_WP_OK)
+ ret = get_wp_mode(&cfg->mode, &bits);
- return 0;
+ return ret;
}
-static int generic_enable_writeprotect(const struct flashctx *flash,
- enum wp_mode wp_mode)
+enum flashrom_wp_result wp_write_cfg(struct flashctx *flash, const struct flashrom_wp_cfg *cfg)
{
- int ret;
+ struct wp_bits bits;
+ enum flashrom_wp_result ret = FLASHROM_WP_OK;
- if (wp_mode != WP_MODE_HARDWARE) {
- msg_cerr("%s(): unsupported write-protect mode\n", __func__);
- return 1;
- }
+ if (!chip_supported(flash))
+ ret = FLASHROM_WP_ERR_CHIP_UNSUPPORTED;
+
+ if (ret == FLASHROM_WP_OK)
+ ret = read_wp_bits(&bits, flash);
- ret = generic_set_srp0(flash, 1);
- if (ret)
- msg_cerr("%s(): error=%d.\n", __func__, ret);
+ /* Set protection range */
+ if (ret == FLASHROM_WP_OK)
+ ret = set_wp_range(&bits, flash, cfg->range);
+ if (ret == FLASHROM_WP_OK)
+ ret = write_wp_bits(flash, bits);
+
+ /* Set protection mode */
+ if (ret == FLASHROM_WP_OK)
+ ret = set_wp_mode(&bits, cfg->mode);
+ if (ret == FLASHROM_WP_OK)
+ ret = write_wp_bits(flash, bits);
return ret;
}
-static int generic_disable_writeprotect(const struct flashctx *flash)
+enum flashrom_wp_result wp_get_available_ranges(struct flashrom_wp_ranges **list, struct flashrom_flashctx *flash)
{
- int ret;
+ struct wp_bits bits;
+ struct wp_range_and_bits *range_pairs = NULL;
+ size_t count;
- ret = generic_set_srp0(flash, 0);
- if (ret)
- msg_cerr("%s(): error=%d.\n", __func__, ret);
+ if (!chip_supported(flash))
+ return FLASHROM_WP_ERR_CHIP_UNSUPPORTED;
- return ret;
-}
+ enum flashrom_wp_result ret = read_wp_bits(&bits, flash);
+ if (ret != FLASHROM_WP_OK)
+ 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++;
- }
+ ret = get_ranges_and_wp_bits(flash, bits, &range_pairs, &count);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
- return 0;
-}
+ *list = calloc(1, sizeof(struct flashrom_wp_ranges));
+ struct wp_range *ranges = calloc(count, sizeof(struct wp_range));
-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);
+ if (!(*list) || !ranges) {
+ free(*list);
+ free(ranges);
+ ret = FLASHROM_WP_ERR_OTHER;
+ goto out;
}
+ (*list)->count = count;
+ (*list)->ranges = ranges;
+ for (size_t i = 0; i < count; i++)
+ ranges[i] = range_pairs[i].range;
+
+out:
+ free(range_pairs);
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,
-};
+enum flashrom_wp_result wp_cfg_to_reg_values(
+ uint8_t *reg_values, uint8_t *bit_masks, uint8_t *write_masks,
+ struct flashctx *flash, const struct flashrom_wp_cfg *cfg)
+{
+ struct wp_bits bits;
+
+ if (!chip_supported(flash))
+ return FLASHROM_WP_ERR_CHIP_UNSUPPORTED;
+
+ enum flashrom_wp_result ret = read_wp_bits(&bits, flash);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ /* Set protection range */
+ ret = set_wp_range(&bits, flash, cfg->range);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ /* Set protection mode */
+ ret = set_wp_mode(&bits, cfg->mode);
+ if (ret != FLASHROM_WP_OK)
+ return ret;
+
+ get_wp_bits_reg_values(reg_values, bit_masks, write_masks, &flash->chip->reg_bits, bits);
+
+ return FLASHROM_WP_OK;
+}
diff --git a/writeprotect.h b/writeprotect.h
deleted file mode 100644
index bded4c854..000000000
--- a/writeprotect.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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);
-};
-
-extern struct wp wp_generic;
-
-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__ */
diff --git a/writeprotect_ranges.c b/writeprotect_ranges.c
new file mode 100644
index 000000000..45678f22a
--- /dev/null
+++ b/writeprotect_ranges.c
@@ -0,0 +1,144 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright 2021 Google LLC
+ *
+ * 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 "writeprotect.h"
+#include "chipdrivers.h"
+
+static void decode_range_generic(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len,
+ bool fixed_block_len, bool apply_cmp_to_bp, int coeff_offset)
+{
+ const bool cmp = bits->cmp_bit_present && bits->cmp == 1;
+
+ /* Interpret BP bits as an integer */
+ size_t bp = 0;
+ size_t bp_max = 0;
+
+ for (size_t i = 0; i < bits->bp_bit_count; i++) {
+ bp |= bits->bp[i] << i;
+ bp_max |= 1 << i;
+ }
+
+ /*
+ * Most chips: the CMP bit only negates the range.
+ *
+ * Some MX chips: the CMP bit negates the BP bits and the range.
+ * (CMP bit is often the MSB BP bit in such chips.)
+ */
+ if (cmp && apply_cmp_to_bp)
+ bp ^= bp_max;
+
+ if (bp == 0) {
+ /* Special case: all BP bits are 0 => no write protection */
+ *len = 0;
+ } else if (bp == bp_max) {
+ /* Special case: all BP bits are 1 => full write protection */
+ *len = chip_len;
+ } else {
+ /*
+ * Usual case: the BP bits encode a coefficient in the form
+ * `coeff = 2 ** (bp - offset)` where `offset == 1`.
+ *
+ * The range's length is given by multiplying the coefficient
+ * by a base unit, usually a 4K sector or a 64K block.
+ */
+
+ size_t coeff = 1 << (bp - coeff_offset);
+ size_t max_coeff = 1 << (bp_max - coeff_offset - 1);
+
+ size_t sector_len = 4 * KiB;
+ size_t default_block_len = 64 * KiB;
+
+ if (bits->sec_bit_present && bits->sec == 1) {
+ /*
+ * SEC=1, protect 4K sectors. Flash chips clamp the
+ * protection length at 32K, probably to avoid overlap
+ * with the SEC=0 case.
+ */
+ *len = min(sector_len * coeff, default_block_len / 2);
+ } else {
+ /*
+ * SEC=0 or is not present, protect blocks.
+ */
+ size_t block_len = default_block_len;
+
+ /*
+ * With very large chips, the 'block' size can be
+ * larger than 64K. This occurs when a larger block
+ * size is needed so that half the chip can be
+ * protected by the maximum possible coefficient.
+ */
+ if (!fixed_block_len) {
+ size_t min_block_len = chip_len / 2 / max_coeff;
+ block_len = max(min_block_len, default_block_len);
+ }
+
+ *len = min(block_len * coeff, chip_len);
+ }
+ }
+
+ /* Apply TB bit */
+ bool protect_top = bits->tb_bit_present ? (bits->tb == 0) : 1;
+
+ /* Apply CMP bit */
+ if (cmp) {
+ *len = chip_len - *len;
+ protect_top = !protect_top;
+ }
+
+ /* Calculate start address, ensuring that empty ranges start at 0 */
+ if (protect_top && *len > 0)
+ *start = chip_len - *len;
+ else
+ *start = 0;
+}
+
+/*
+ * Protection range calculation that works with many common SPI flash chips.
+ */
+void decode_range_spi25(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len)
+{
+ decode_range_generic(start, len, bits, chip_len,
+ /*fixed_block_len=*/false, /*apply_cmp_to_bp=*/false, /*coeff_offset=*/1);
+}
+
+/*
+ * Do not adjust block size to be able to fill half of the chip.
+ */
+void decode_range_spi25_64k_block(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len)
+{
+ decode_range_generic(start, len, bits, chip_len,
+ /*fixed_block_len=*/true, /*apply_cmp_to_bp=*/false, /*coeff_offset=*/1);
+}
+
+/*
+ * Inverts BP bits when CMP is set and treats all ones in BP bits as a request to protect whole chip regardless
+ * of the CMP bit.
+ */
+void decode_range_spi25_bit_cmp(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len)
+{
+ decode_range_generic(start, len, bits, chip_len,
+ /*fixed_block_len=*/false, /*apply_cmp_to_bp=*/true, /*coeff_offset=*/1);
+}
+
+/*
+ * This multiplies coefficient by 2. To be used with chips which have more BP bits than needed, such that the
+ * most significant BP bit effectively acts as "protect whole chip" flag.
+ */
+void decode_range_spi25_2x_block(size_t *start, size_t *len, const struct wp_bits *bits, size_t chip_len)
+{
+ decode_range_generic(start, len, bits, chip_len,
+ /*fixed_block_len=*/false, /*apply_cmp_to_bp=*/false, /*coeff_offset=*/0);
+}