Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lenovo ThinkCentre M920q — Coreboot Flash Guide

Tested and verified guide for flashing coreboot on the Lenovo ThinkCentre M920q. Should also work on the M720q, M920x, and ThinkStation P330 Tiny (same board, untested).

Overview

FeatureValue
CPUIntel Core 8th/9th Gen (Coffee Lake / Coffee Lake Refresh)
ChipsetIntel Q370 (Cannon Lake PCH-H)
DRAM2× SO-DIMM DDR4-2400/2666, max 64 GB
ME versionv12
Super I/ONCT6686D-L (Nuvoton)
TPMInfineon SLB 9670VQ2.0 (TPM 2.0)
Boot GuardNot fused — direct external flash works
SoC coreboot directorysoc/intel/cannonlake

What Works

  • USB 3.0 / 2.0 (front and rear)
  • USB-C (charging and data)
  • Gigabit Ethernet
  • SATA and NVMe
  • HDMI
  • WiFi slot
  • TPM 2.0
  • Internal speaker
  • COM1 serial (via daughter board)
  • PCIe x8 riser slot (tested with BA7H70 Rev 1.2 riser + Intel X540-T2 10GbE)
  • S3 suspend/resume
  • PXE boot (via edk2 built-in UEFI network stack)

Known Issues

  • Non-T (65W+) CPUs do not boot under coreboot on M920q — The M920q VRM lacks a power phase (PU404) present on the M920x/P330 Tiny. Non-T CPUs (i7-8700, i9-9900, etc.) fail during early FSP init due to insufficient VRM current delivery. The stock Lenovo BIOS has vendor-specific workarounds; coreboot uses Intel reference FSP values which expect spec-compliant VRM. Use T-series (35W) CPUs only (i3-8100T, i5-8500T, i7-8700T, i9-9900T, etc.). See the M920x/P330 section below for 65W support
  • Front audio jacks do not work (upstream coreboot bug)
  • DIMM2 slot does not workcoreboot bug #592. Only DIMM1 is usable. Use a single larger SO-DIMM if more RAM is needed
  • ME Communication Controller (PCI 16.0) remains visible with HAP bit set — this is normal hardware enumeration, the ME firmware is disabled

Board Variants — M720q / M920q / M920x / P330 Tiny

The M920q, M920x, M720q, and ThinkStation P330 Tiny all share the same base motherboard (EQ370 NM-B551 / IQ3X0IL) with different SMD component populations. The same coreboot ROM should work on all four variants. Only the M920q has been tested — the others should work in principle but are unconfirmed.

The M920x and P330 Tiny have an additional VRM phase (PU404) and associated passives that allow 65W non-T CPU operation. The M720q has the same VRM limitation as the M920q — T-series CPUs only.

VariantVRM65W CPUCoreboot Tested
M920qStandardNo — T-series onlyYes
M720qStandardNo — T-series onlyNo (should work)
M920xExtra phase (PU404)YesNo (should work)
P330 TinyExtra phase (PU404)YesNo (should work)

Flash Chips

The M920q has two SOIC-8 SPI flash chips, both 3.3V, soldered (not socketed):

ChipBoard LabelModelSizeflashprog -c stringPull-up Notes
BIOS1U31W25Q128JV16 MiBW25Q128.VBoard has on-board pull-ups — do not hold /WP or /HOLD high. If reads/writes fail, see Tools — /WP and /HOLD Troubleshooting
BIOS2U32W25Q64JV8 MiBW25Q64JV-.QNo on-board pull-ups — /WP (pin 3) and /HOLD (pin 7) must be held HIGH manually

Total ROM size: 24 MiB (16 + 8).


Prerequisites

Hardware

  • Raspberry Pi (3/4/5) or Raspberry Pi Pico (RP2040) — see Tools — SPI Programmers for setup, wiring, and flashprog installation
  • SOIC-8 test clip (Pomona 5250 or equivalent)
  • Dupont jumper wires (include a splitter from any RPi 3.3V pin to Pomona clip pins 3 and 7 for BIOS2 /WP and /HOLD pull-ups)

Important: Disconnect the M920q power adapter before attaching the programmer. Do not supply mains power while flashing.


Step 1: Read Original Firmware

Triple-read each chip — see Tools — Triple-Read Methodology. All three SHA256 checksums must match before proceeding. If they don’t, reseat the clip and read again.

BIOS1 (16 MiB)

Do not hold /WP or /HOLD high — the board has on-board pull-ups for this chip. If reads fail, see Tools — /WP and /HOLD Troubleshooting.

sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q128.V" -r m920q_bios1_dump1.bin
sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q128.V" -r m920q_bios1_dump2.bin
sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q128.V" -r m920q_bios1_dump3.bin

sha256sum m920q_bios1_dump*.bin

BIOS2 (8 MiB)

Move clip to BIOS2. Hold /WP (pin 3) and /HOLD (pin 7) HIGH (split a Dupont wire from any RPi 3.3V pin to both pins on the Pomona clip).

sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q64JV-.Q" -r m920q_bios2_dump1.bin
sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q64JV-.Q" -r m920q_bios2_dump2.bin
sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q64JV-.Q" -r m920q_bios2_dump3.bin

sha256sum m920q_bios2_dump*.bin

Troubleshooting: If BIOS2 is not detected, check that /WP and /HOLD are held HIGH — unlike BIOS1, BIOS2 has no on-board pull-ups. You may also try lowering spispeed to 512 if detection is unreliable. For general /WP and /HOLD troubleshooting, see Tools — /WP and /HOLD Troubleshooting.

Combine and Back Up

cat m920q_bios1_dump1.bin m920q_bios2_dump1.bin > m920q_original_24mb.bin

ls -la m920q_original_24mb.bin
# Must be exactly 25165824 bytes (24 MiB)

Back up all dump files to a safe off-machine location. These are your recovery lifeline.


Step 2: Extract Regions and Set HAP Bit

Perform these steps on your build machine. Build ifdtool if you haven’t already — see Tools — ifdtool.

Extract Regions

util/ifdtool/ifdtool -p cnl -x /path/to/m920q_original_24mb.bin

The -p cnl flag specifies Cannon Lake platform. This produces:

Output FileContents
flashregion_0_flashdescriptor.binIntel Flash Descriptor
flashregion_1_bios.binBIOS region (coreboot replaces this — not needed)
flashregion_2_intel_me.binIntel CSME firmware
flashregion_3_gbe.binGigabit Ethernet NVM (contains MAC address)

Set HAP Bit on Descriptor

The HAP (High Assurance Platform) bit tells the ME to enter a graceful disabled state after early initialisation.

Do NOT use me_cleaner on this platform. The M920q uses ME v12. Stripping ME modules with me_cleaner puts ME v12 into an error state and can prevent boot. The coreboot project recommends using the HAP bit rather than me_cleaner.

util/ifdtool/ifdtool -p cnl -M 1 flashregion_0_flashdescriptor.bin
mv flashregion_0_flashdescriptor.bin flashregion_0_flashdescriptor.bin.orig
mv flashregion_0_flashdescriptor.bin.new flashregion_0_flashdescriptor.bin

Place Blobs

mkdir -p 3rdparty/blobs/mainboard/lenovo/m720q_m920q

cp flashregion_0_flashdescriptor.bin \
   3rdparty/blobs/mainboard/lenovo/m720q_m920q/descriptor.bin

cp flashregion_2_intel_me.bin \
   3rdparty/blobs/mainboard/lenovo/m720q_m920q/me.bin

cp flashregion_3_gbe.bin \
   3rdparty/blobs/mainboard/lenovo/m720q_m920q/gbe.bin

The ME binary must be the original unmodified version extracted from your dump. The VBT (data.vbt) is already bundled in the coreboot source tree at src/mainboard/lenovo/m720q_m920q/data.vbt. The FSP binaries are fetched automatically via git submodules (3rdparty/fsp/CoffeeLakeFspBinPkg/).


Step 3: Configure and Build

Install build dependencies and cross-compiler if not done already — see Tools — Build Dependencies and Tools — Cross-Compiler.

Using the Provided defconfig

Save the following as defconfig in your coreboot root directory. It configures:

  • edk2 payload (MrChromebox fork) with PXE, UEFI Shell, TPM 2.0, Secure Boot
  • SMMStore v2 for persistent UEFI NVRAM
  • libgfxinit for native graphics initialisation
  • Serial console on COM1 at 115200 baud
CONFIG_VENDOR_LENOVO=y
CONFIG_BOARD_LENOVO_M920Q=y
CONFIG_IFD_BIN_PATH="3rdparty/blobs/mainboard/lenovo/m720q_m920q/descriptor.bin"
CONFIG_ME_BIN_PATH="3rdparty/blobs/mainboard/lenovo/m720q_m920q/me.bin"
CONFIG_GBE_BIN_PATH="3rdparty/blobs/mainboard/lenovo/m720q_m920q/gbe.bin"
# CONFIG_USE_ME_CLEANER is not set
CONFIG_PAYLOAD_EDK2=y
CONFIG_EDK2_REPO_MRCHROMEBOX=y
CONFIG_EDK2_UEFIPAYLOAD=y
CONFIG_SMMSTORE=y
CONFIG_SMMSTORE_V2=y
# iPXE network boot — adds "Network Boot" to edk2 boot menu
CONFIG_EDK2_ENABLE_IPXE=y
CONFIG_EDK2_IPXE_OPTION_NAME="Network Boot"
# CONFIG_RUN_FSP_GOP is not set
CONFIG_CONSOLE_SERIAL=y
CONFIG_TTYS0_BAUD=115200
CONFIG_DEFAULT_CONSOLE_LOGLEVEL=7

Then build:

make distclean
cp defconfig .config
make olddefconfig
make -j$(nproc)

Verify Output

ls -la build/coreboot.rom
# Must be 25165824 bytes (24 MiB)

./build/cbfstool build/coreboot.rom print
# Should list: bootblock, romstage, ramstage, dsdt.aml, payload (edk2),
# cpu_microcode_blob.bin, vbt.bin, fspm.bin, fsps.bin, etc.

Step 4: Split and Flash

Split the ROM

The 24 MiB ROM must be split to match the two physical flash chips:

dd if=build/coreboot.rom of=build/coreboot_bios1.rom bs=1M count=16
dd if=build/coreboot.rom of=build/coreboot_bios2.rom bs=8M skip=2

# Sanity check — recombine and compare
cat build/coreboot_bios1.rom build/coreboot_bios2.rom > build/coreboot_recombined.rom
sha256sum build/coreboot.rom build/coreboot_recombined.rom
# Must match

Flash BIOS1 (16 MiB)

Do not hold /WP or /HOLD high.

sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q128.V" -w coreboot_bios1.rom

# Verify
sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q128.V" -r verify_bios1.bin
sha256sum coreboot_bios1.rom verify_bios1.bin

Flash BIOS2 (8 MiB)

Move clip to BIOS2. Hold /WP (pin 3) and /HOLD (pin 7) HIGH (same 3.3V splitter as reading).

sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q64JV-.Q" -w coreboot_bios2.rom

# Verify
sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q64JV-.Q" -r verify_bios2.bin
sha256sum coreboot_bios2.rom verify_bios2.bin

Step 5: First Boot

  1. Install RAM in DIMM1 only — DIMM2 does not work under coreboot (bug #592)
  2. Connect a display via HDMI (try DisplayPort if no output on HDMI)
  3. Power on and wait up to 2 minutes — the first boot performs memory training with no display output. Subsequent boots are fast (MRC cache)
  4. The edk2 splash screen (coreboot hare) should appear. Press Esc to enter the boot menu

If It Doesn’t Boot

  • Verify RAM is in DIMM1 only
  • Try both display outputs (HDMI and DisplayPort)
  • Wait the full 2 minutes — memory training can be slow
  • If still no output, flash your original backup dumps to restore stock firmware (see Recovery below) and review your build configuration

Step 6: Post-Boot Verification

ME Status

sudo dmesg | grep -i mei

With HAP bit set, you should see only mei_hdcp binding for HDCP content protection via the i915 graphics driver:

mei_hdcp 0000:00:16.0-b638ab7e-94e2-4ea2-a552-d1c54b627f04: bound 0000:00:02.0 (ops i915 hdcp_ops [i915])

There should be no mei_me driver initialising and no AMT-related messages. The HECI controller at 00:16.0 will still appear in lspci as Communication controller: Intel Corporation Cannon Lake PCH HECI Controller — this is normal hardware enumeration. HAP prevents the ME firmware from actively running while the PCH hardware remains visible on the PCI bus.


Recovery

If the machine doesn’t boot, flash your original backup dumps externally:

# BIOS1 (do not hold /WP or /HOLD high)
sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q128.V" -w m920q_bios1_dump1.bin

# BIOS2 (hold /WP and /HOLD HIGH)
sudo flashprog -p linux_spi:dev=/dev/spidev0.0,spispeed=1000 \
  -c "W25Q64JV-.Q" -w m920q_bios2_dump1.bin

Internal Flashing (Subsequent Updates)

See Tools — Internal Re-Flashing. For the M920q, use the BIOS-region-only method:

sudo flashrom -p internal -N -w coreboot.rom --ifd -i bios

This writes only the BIOS region, leaving the descriptor, ME, and GbE regions untouched. No need to split the ROM for internal flashing.



Quick Reference

ItemDetails
ROM size24 MiB (two chips: 16 + 8)
BIOS1 splitdd if=coreboot.rom of=bios1.rom bs=1M count=16
BIOS2 splitdd if=coreboot.rom of=bios2.rom bs=8M skip=2
BIOS2 quirk/WP + /HOLD must be held HIGH externally
HAP bitifdtool -p cnl -M 1 descriptor.bin
DIMMSlot 1 only (bug #592)
CPUT-series (35W) only on M920q — 65W CPUs fail under coreboot (VRM limitation)
65W CPU supportUse M920x or P330 Tiny (extra VRM phase — untested with coreboot)
iPXE / PXE bootCONFIG_EDK2_ENABLE_IPXE=y in defconfig
Boot GuardNot fused — no deguard needed
ME disableHAP bit only — do NOT use me_cleaner (ME v12)
Same board familyM720q, M920q (tested), M920x, P330 Tiny — all EQ370 NM-B551

References

License

This guide is released under CC BY-SA 4.0.