flash/nor: add support for NXP QN908x
This patch adds support for the NXP QN908x family of Bluetooth microcontrollers, such as the QN9080. This chip features a Cortex-M4F with 512 KiB of flash on all the available versions, although the documentation suggests that there might be 256 kB versions as well. The initial support allows to read, erase and write the whole user flash area. Three new sub-commands under the new "qn908x" command are added in this patch as well: disable_wdog to disabled the watchdog, mass_erase to perform a mass erase and allow_brick to allow programming images that disable the SWD interface. Disabling the watchdog is required after a "reset halt" in order to run the CRC algorithm from RAM when verifying the chip. However, this is not done automatically on probing or other initialization since disabling the watchdog might interfere with debugging real applications. The "mass_erase" command allows to erase the whole flash without probing it, since in some scenarios the chip can be locked such that no flash or ram can be accessed from the SWD interface, allowing only to run a mass_erase to be able to flash the program. The flashing process allows to compute a checksum, similar to the lpc2000 driver "calc_checksum" but done over a different region of the memory. This checksum is required to be present for the QN908x bootloader ROM to boot, and otherwise is useless. As with the lpc2000 design, verification when using "calc_checksum" is expected to fail if the checksum was not valid in the image being verified. This was manually tested on a QN9080, including the scan-view, AddressSanitizer/UBSan and test coverage configurations. Change-Id: Ibd6d8f3608654294795085fcaaffb448b77cc58b Co-developed-by: Marian Buschsieweke <marian.buschsieweke@ovgu.de> Signed-off-by: Marian Buschsieweke <marian.buschsieweke@ovgu.de> Signed-off-by: iosabi <iosabi@protonmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/5584 Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com> Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
parent
24b656bff5
commit
370bf43fb1
110
doc/openocd.texi
110
doc/openocd.texi
|
@ -7341,6 +7341,116 @@ Note: only Main and Work flash regions support Erase operation.
|
||||||
@end deffn
|
@end deffn
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Flash Driver} {qn908x}
|
||||||
|
The NXP QN908x microcontrollers feature a Cortex-M4F with integrated Bluetooth
|
||||||
|
LE 5 support and an internal flash of up to 512 KiB. These chips only support
|
||||||
|
the SWD interface.
|
||||||
|
|
||||||
|
The @var{qn908x} driver uses the internal "Flash Memory Controller" block via
|
||||||
|
SWD to erase, program and read the internal flash. This driver does not
|
||||||
|
support the ISP (In-System Programming) mode which is an alternate way to
|
||||||
|
program the flash via UART, SPI or USB.
|
||||||
|
|
||||||
|
The internal flash is 512 KiB in size in all released chips and it starts at
|
||||||
|
the address 0x01000000, although it can be mapped to address 0 and it is
|
||||||
|
aliased to other addresses. This driver only recognizes the bank starting at
|
||||||
|
address 0x01000000.
|
||||||
|
|
||||||
|
The internal bootloader stored in ROM is in charge of loading and verifying
|
||||||
|
the image from flash, or enter ISP mode. The programmed image must start at
|
||||||
|
the beginning of the flash and contain a valid header and a matching CRC32
|
||||||
|
checksum. Additionally, the image header contains a "Code Read Protection"
|
||||||
|
(CRP) word which indicates whether SWD access is enabled, as well as whether
|
||||||
|
ISP mode is enabled. Therefore, it is possible to program an image that
|
||||||
|
disables SWD and ISP making it impossible to program another image in the
|
||||||
|
future through these interfaces, or even debug the current image. While this is
|
||||||
|
a valid use case for production deployments where the chips are locked down, by
|
||||||
|
default this driver doesn't allow such images that disable the SWD interface.
|
||||||
|
To program such images see the @command{qn908x allow_brick} command.
|
||||||
|
|
||||||
|
Apart from the CRP field which is located in the image header, the last page
|
||||||
|
of the flash memory contains a "Flash lock and protect" descriptor which allows
|
||||||
|
to individually protect each 2 KiB page, as well as disabling SWD access to the
|
||||||
|
flash and RAM. If this access is disabled it is not possible to read, erase or
|
||||||
|
program individual pages from the SWD interface or even access the read-only
|
||||||
|
"Flash information page" with information about the bootloader version and
|
||||||
|
flash size. However when this protection is in place, it is still possible to
|
||||||
|
mass erase the whole chip and then program a new image, for which you can use
|
||||||
|
the @command{qn908x mass_erase}.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@example
|
||||||
|
flash bank $FLASHNAME qn908x 0x01000000 0 0 0 $TARGETNAME calc_checksum
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
@itemize
|
||||||
|
@item @option{calc_checksum} optional parameter to compute the required
|
||||||
|
checksum of the first bytes in the vector table.
|
||||||
|
@quotation Note
|
||||||
|
If the checksum in the header of your image is invalid and you don't provide the
|
||||||
|
@option{calc_checksum} option the boot ROM will not boot your image and it may
|
||||||
|
render the flash inaccessible. On the other hand, if you use this option to
|
||||||
|
compute the checksum keep in mind that @command{verify_image} will fail on
|
||||||
|
those four bytes of the checksum since those bytes in the flash will have the
|
||||||
|
updated checksum.
|
||||||
|
@end quotation
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@deffn {Command} {qn908x allow_brick}
|
||||||
|
Allow the qn908x driver to program images with a "Code Read Protection" byte
|
||||||
|
that disables the SWD access. Programming such image will cause OpenOCD to
|
||||||
|
not be able to reach the target over SWD anymore after the new image is
|
||||||
|
programmed and its configuration takes effect, e.g. after a reboot. After
|
||||||
|
executing @command{qn908x allow_brick} these images will be allowed to be
|
||||||
|
programmed when writing to the flash.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {qn908x disable_wdog}
|
||||||
|
Disable the watchdog timer (WDT) by resetting its CTRL field. The WDT starts
|
||||||
|
enabled after a @command{reset halt} and it doesn't run while the target is
|
||||||
|
halted. However, the verification process in this driver uses the generic
|
||||||
|
Cortex-M verification process which executes a payload in RAM and thus
|
||||||
|
requires the watchdog to be disabled before running @command{verify_image}
|
||||||
|
after a reset halt or any other condition where the watchdog is running.
|
||||||
|
Note that this is not done automatically and you must run this command in
|
||||||
|
those scenarios.
|
||||||
|
@end deffn
|
||||||
|
|
||||||
|
@deffn {Command} {qn908x mass_erase}
|
||||||
|
Erases the complete flash using the mass_erase method. Mass erase is only
|
||||||
|
allowed if enabled in the Lock Status Register 8 (LOCK_STAT_8) which is read
|
||||||
|
from the last sector of the flash on boot. However, this mass_erase lock
|
||||||
|
protection can be bypassed and this command does so automatically.
|
||||||
|
|
||||||
|
In the same LOCK_STAT_8 the flash and RAM access from SWD can be disabled by
|
||||||
|
setting two bits in this register. After a mass_erase, all the bits of the
|
||||||
|
flash would be set, making it the default to restrict SWD access to the flash
|
||||||
|
and RAM regions. This new after erase LOCK_STAT_8 value only takes effect after
|
||||||
|
being read from flash on the next reboot for example. After a mass_erase the
|
||||||
|
LOCK_STAT_8 register is changed by the hardware to allow access to flash and
|
||||||
|
RAM regardless of the value on flash, but only right after a mass_erase and
|
||||||
|
until the next boot. Therefore it is possible to perform a mass_erase, program
|
||||||
|
a new image, verify it and then reboot to a valid image that's locked from the
|
||||||
|
SWD access.
|
||||||
|
|
||||||
|
The @command{qn908x mass_erase} command clears the bits that would be loaded
|
||||||
|
from the flash into LOCK_STAT_8 after erasing the whole chip to allow SWD
|
||||||
|
access for debugging or re-flashing an image without a mass_erase by default.
|
||||||
|
If the image being programmed also programs the last page of the flash with its
|
||||||
|
own settings, this mass_erase behavior will interfere with that write since a
|
||||||
|
new erase of at least the last page would need to be performed before writing
|
||||||
|
to it again. For this reason the optional @option{keep_lock} argument can be
|
||||||
|
used to leave the flash and RAM lock set. For development environments, the
|
||||||
|
default behavior is desired.
|
||||||
|
|
||||||
|
The mass erase locking mechanism is independent from the individual page
|
||||||
|
locking bits, so it is possible that you can't erase a given page that is
|
||||||
|
locked and you can't unprotect that page because the locking bits are also
|
||||||
|
locked, but can still mass erase the whole flash.
|
||||||
|
@end deffn
|
||||||
|
@end deffn
|
||||||
|
|
||||||
@deffn {Flash Driver} {rp2040}
|
@deffn {Flash Driver} {rp2040}
|
||||||
Supports RP2040 "Raspberry Pi Pico" microcontroller.
|
Supports RP2040 "Raspberry Pi Pico" microcontroller.
|
||||||
RP2040 is a dual-core device with two CM0+ cores. Both cores share the same
|
RP2040 is a dual-core device with two CM0+ cores. Both cores share the same
|
||||||
|
|
|
@ -54,6 +54,7 @@ NOR_DRIVERS = \
|
||||||
%D%/psoc4.c \
|
%D%/psoc4.c \
|
||||||
%D%/psoc5lp.c \
|
%D%/psoc5lp.c \
|
||||||
%D%/psoc6.c \
|
%D%/psoc6.c \
|
||||||
|
%D%/qn908x.c \
|
||||||
%D%/renesas_rpchf.c \
|
%D%/renesas_rpchf.c \
|
||||||
%D%/rp2040.c \
|
%D%/rp2040.c \
|
||||||
%D%/rsl10.c \
|
%D%/rsl10.c \
|
||||||
|
|
|
@ -284,6 +284,7 @@ extern const struct flash_driver psoc5lp_eeprom_flash;
|
||||||
extern const struct flash_driver psoc5lp_flash;
|
extern const struct flash_driver psoc5lp_flash;
|
||||||
extern const struct flash_driver psoc5lp_nvl_flash;
|
extern const struct flash_driver psoc5lp_nvl_flash;
|
||||||
extern const struct flash_driver psoc6_flash;
|
extern const struct flash_driver psoc6_flash;
|
||||||
|
extern const struct flash_driver qn908x_flash;
|
||||||
extern const struct flash_driver renesas_rpchf_flash;
|
extern const struct flash_driver renesas_rpchf_flash;
|
||||||
extern const struct flash_driver rp2040_flash;
|
extern const struct flash_driver rp2040_flash;
|
||||||
extern const struct flash_driver rsl10_flash;
|
extern const struct flash_driver rsl10_flash;
|
||||||
|
|
|
@ -61,6 +61,7 @@ static const struct flash_driver * const flash_drivers[] = {
|
||||||
&psoc5lp_eeprom_flash,
|
&psoc5lp_eeprom_flash,
|
||||||
&psoc5lp_nvl_flash,
|
&psoc5lp_nvl_flash,
|
||||||
&psoc6_flash,
|
&psoc6_flash,
|
||||||
|
&qn908x_flash,
|
||||||
&renesas_rpchf_flash,
|
&renesas_rpchf_flash,
|
||||||
&rp2040_flash,
|
&rp2040_flash,
|
||||||
&sh_qspi_flash,
|
&sh_qspi_flash,
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
# NXP QN908x Cortex-M4F with 128 KiB SRAM
|
||||||
|
|
||||||
|
source [find target/swj-dp.tcl]
|
||||||
|
|
||||||
|
set CHIPNAME qn908x
|
||||||
|
set CHIPSERIES qn9080
|
||||||
|
if { ![info exists WORKAREASIZE] } {
|
||||||
|
set WORKAREASIZE 0x20000
|
||||||
|
}
|
||||||
|
|
||||||
|
# SWD IDCODE (Cortex M4).
|
||||||
|
set CPUTAPID 0x2ba01477
|
||||||
|
|
||||||
|
swj_newdap $CHIPNAME cpu -irlen 4 -expected-id $CPUTAPID
|
||||||
|
dap create $CHIPNAME.dap -chain-position $CHIPNAME.cpu
|
||||||
|
|
||||||
|
set TARGETNAME $CHIPNAME.cpu
|
||||||
|
target create $TARGETNAME cortex_m -dap $CHIPNAME.dap
|
||||||
|
|
||||||
|
# SRAM is mapped at 0x04000000.
|
||||||
|
$TARGETNAME configure -work-area-phys 0x04000000 -work-area-size $WORKAREASIZE
|
||||||
|
|
||||||
|
# flash bank <name> qn908x <base> <size> 0 0 <target#> [calc_checksum]
|
||||||
|
# The base must be set as 0x01000000, and the size parameter is unused.
|
||||||
|
set FLASHNAME $CHIPNAME.flash
|
||||||
|
flash bank $FLASHNAME qn908x 0x01000000 0 0 0 $TARGETNAME calc_checksum
|
||||||
|
|
||||||
|
# We write directly to flash memory over this adapter interface. For debugging
|
||||||
|
# this could in theory be faster (the Core clock on reset is normally at 32MHz),
|
||||||
|
# but for flashing 1MHz is more reliable.
|
||||||
|
adapter speed 1000
|
||||||
|
|
||||||
|
# Delay on reset line.
|
||||||
|
adapter srst delay 200
|
||||||
|
|
||||||
|
cortex_m reset_config sysresetreq
|
Loading…
Reference in New Issue