This is an automated email from Gerrit. Steve Bollinger (mail4ste...@gmail.com) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/5718
-- gerrit commit a18303e995a3665b51c6d67cce382d49b91af8ad Author: Steve Bollinger <mail4ste...@gmail.com> Date: Mon Jun 8 09:55:06 2020 -0700 topic: Add support for rwwee bank in at91samd driver (which covers multiple parts). Modified driver to now add RWWEE section. Added bank definition in tcl as bank 1. Added rwwee info for every supported device that has an rwwee array. Added code to select proper write and erase commands for rwwee bank. Also supports user row as a bank but that functionality is not turned on and user row is a separate command as before. Changed name of main bank to main, new bank is rwwee. Use information from chip (PARAM register) to size RWWEE area instead of using value in structure. This could also be done for the main bank but I did not change that functionality. Updated Atmel names in documentation to Microchip (formerly Atmel). Fixed xref error in get-ref-field. Updated broken link to obsolete Atmel SAM-ICE product. Change-Id: I7678ff10ac46f9b4ea41487d4cf2ae191ee8c427 Signed-off-by: Steve Bollinger <mail4ste...@gmail.com> diff --git a/doc/openocd.texi b/doc/openocd.texi index 1ddf09f..3e6cd3d 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -458,7 +458,7 @@ AT91SAM764 internally. @item @b{SEGGER J-Link} @* Link: @url{http://www.segger.com/jlink.html} @item @b{Atmel SAM-ICE} (Only works with Atmel chips!) -@* Link: @url{http://www.atmel.com/tools/atmelsam-ice.aspx} +@* Link: @url{https://www.microchip.com/Developmenttools/ProductDetails/AT91SAM-ICE} @item @b{IAR J-Link} @end itemize @@ -909,7 +909,7 @@ in the current directory named @file{openocd.cfg} Here is an example @file{openocd.cfg} file for a setup using a Signalyzer FT2232-based JTAG adapter to talk to -a board with an Atmel AT91SAM7X256 microcontroller: +a board with an Microchip (formerly Atmel) AT91SAM7X256 microcontroller: @example source [find interface/ftdi/signalyzer.cfg] @@ -1706,7 +1706,7 @@ for taps. In the simplest case the chip has only one TAP, probably for a CPU or FPGA. -The config file for the Atmel AT91SAM7X256 +The config file for the Microchip (formerly Atmel) AT91SAM7X256 looks (in part) like this: @example @@ -2408,7 +2408,7 @@ Logs some status @deffn {Interface Driver} {at91rm9200} Supports bitbanged JTAG from the local system, -presuming that system is an Atmel AT91rm9200 +presuming that system is a Microchip (formerly Atmel) AT91rm9200 and a specific set of GPIOs is used. @c command: at91rm9200_device NAME @c chooses among list of bit configs ... only one option @@ -5602,14 +5602,24 @@ the flash. @deffn {Flash Driver} at91samd @cindex at91samd All members of the ATSAM D2x, D1x, D0x, ATSAMR, ATSAML and ATSAMC microcontroller -families from Atmel include internal flash and use ARM's Cortex-M0+ core. +families from Microchip (formerly Atmel) include internal flash and use ARM's +Cortex-M0+ core. Do not use for ATSAM D51 and E5x: use @xref{atsame5}. -The devices have one flash bank: +All of these devices have a main flash bank: @example -flash bank $_FLASHNAME at91samd 0x00000000 0 1 1 $_TARGETNAME +flash bank $_FLASHNAME.main at91samd 0x00000000 0 1 1 $_TARGETNAME +@end example + +Some of these devices have a second flash bank which can be separately programmed +and erased by code running from the main flash bank. This is called the "RWWEE" or +"RWW" bank. This bank is not always present and if present is much smaller than the +main bank. + +@example +flash bank $_FLASHNAME.rwwee at91samd 0x00400000 0 1 1 $_TARGETNAME @end example @deffn Command {at91samd chip-erase} @@ -5689,8 +5699,8 @@ NVMUSERROW: 0xFFFFFC5DD8E0C788 @anchor{at91sam3} @deffn {Flash Driver} at91sam3 @cindex at91sam3 -All members of the AT91SAM3 microcontroller family from -Atmel include internal flash and use ARM's Cortex-M3 core. The driver +All members of the AT91SAM3 microcontroller family from Microchip (formerly +Atmel) include internal flash and use ARM's Cortex-M3 core. The driver currently (6/22/09) recognizes the AT91SAM3U[1/2/4][C/E] chips. Note that the driver was orginaly developed and tested using the AT91SAM3U4E, using a SAM3U-EK eval board. Support for other chips in @@ -5753,15 +5763,15 @@ This command shows/sets the slow clock frequency used in the @deffn {Flash Driver} at91sam4 @cindex at91sam4 -All members of the AT91SAM4 microcontroller family from -Atmel include internal flash and use ARM's Cortex-M4 core. +All members of the AT91SAM4 microcontroller family from Microchip (formerly +Atmel) include internal flash and use ARM's Cortex-M4 core. This driver uses the same command names/syntax as @xref{at91sam3}. @end deffn @deffn {Flash Driver} at91sam4l @cindex at91sam4l -All members of the AT91SAM4L microcontroller family from -Atmel include internal flash and use ARM's Cortex-M4 core. +All members of the AT91SAM4L microcontroller family from Microchip (formerly +Atmel) include internal flash and use ARM's Cortex-M4 core. This driver uses the same command names/syntax as @xref{at91sam3}. The AT91SAM4L driver adds some additional commands: @@ -5776,7 +5786,7 @@ Command is used internally in event event reset-deassert-post. @deffn {Flash Driver} atsame5 @cindex atsame5 All members of the SAM E54, E53, E51 and D51 microcontroller -families from Microchip (former Atmel) include internal flash +families from Microchip (formerly Atmel) include internal flash and use ARM's Cortex-M4 core. The devices have two ECC flash banks with a swapping feature. @@ -5837,14 +5847,14 @@ USER PAGE: 0xAEECFF80FE9A9239 @deffn {Flash Driver} atsamv @cindex atsamv -All members of the ATSAMV7x, ATSAMS70, and ATSAME70 families from -Atmel include internal flash and use ARM's Cortex-M7 core. +All members of the ATSAMV7x, ATSAMS70, and ATSAME70 families from Microchip +(formerly Atmel) include internal flash and use ARM's Cortex-M7 core. This driver uses the same command names/syntax as @xref{at91sam3}. @end deffn @deffn {Flash Driver} at91sam7 -All members of the AT91SAM7 microcontroller family from Atmel include -internal flash and use ARM7TDMI cores. The driver automatically +All members of the AT91SAM7 microcontroller family from Microchip (formerly Atmel) +include internal flash and use ARM7TDMI cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. @@ -5890,7 +5900,7 @@ the appropriate at91sam7 target. @end deffn @deffn {Flash Driver} avr -The AVR 8-bit microcontrollers from Atmel integrate flash memory. +The AVR 8-bit microcontrollers from Microchip (formerly Atmel) integrate flash memory. @emph{The current implementation is incomplete.} @comment - defines mass_erase ... pointless given flash_erase_address @end deffn @@ -7553,8 +7563,8 @@ Some controllers also activate controller-specific commands. @deffn {NAND Driver} at91sam9 This driver handles the NAND controllers found on AT91SAM9 family chips from -Atmel. It takes two extra parameters: address of the NAND chip; -address of the ECC controller. +Microchip (formerly Atmel). It takes two extra parameters: address of the NAND +chip; address of the ECC controller. @example nand device $NANDFLASH at91sam9 $CHIPNAME 0x40000000 0xfffffe800 @end example @@ -9815,7 +9825,7 @@ startbit endbit}. @deffn {Command} {arc get-reg-field} reg-name field-name Returns value of bit-field in a register. Register must be ``struct'' register -type, @xref{add-reg-type-struct} command definition. +type command definition. @xref{add-reg-type-struct}. @end deffn @deffn {Command} {arc set-reg-exists} reg-names... @@ -10861,10 +10871,10 @@ Startup sequences are often problematic though, as are other situations where the CPU clock rate changes (perhaps to save power). -For example, Atmel AT91SAM chips start operation from reset with -a 32kHz system clock. Boot firmware may activate the main oscillator -and PLL before switching to a faster clock (perhaps that 500 MHz -ARM926 scenario). +For example, Microchip (formerly Atmel) AT91SAM chips start operation +from reset with a 32kHz system clock. Boot firmware may activate the +main oscillator and PLL before switching to a faster clock (perhaps +the above 500 MHz ARM926 scenario). If you're using JTAG to debug that startup sequence, you must slow the JTAG clock to sometimes 1 to 4kHz. After startup completes, JTAG can use a faster clock. diff --git a/src/flash/nor/at91samd.c b/src/flash/nor/at91samd.c index 6e89099..6205ef0 100644 --- a/src/flash/nor/at91samd.c +++ b/src/flash/nor/at91samd.c @@ -28,7 +28,8 @@ #define SAMD_NUM_PROT_BLOCKS 16 #define SAMD_PAGE_SIZE_MAX 1024 -#define SAMD_FLASH ((uint32_t)0x00000000) /* physical Flash memory */ +#define SAMD_MAIN_FLASH ((uint32_t)0x00000000) /* physical NVM Flash memory */ +#define SAMD_RWWEE ((uint32_t)0x00400000) /* physical RWWEE Flash memory */ #define SAMD_USER_ROW ((uint32_t)0x00804000) /* User Row of Flash */ #define SAMD_PAC1 0x41000000 /* Peripheral Access Control 1 */ #define SAMD_DSU 0x41002000 /* Device Service Unit */ @@ -50,17 +51,19 @@ #define SAMD_NVM_CMD(n) ((SAMD_CMDEX_KEY << 8) | (n & 0x7F)) /* NVMCTRL commands. See Table 20-4 in 42129F–SAM–10/2013 */ -#define SAMD_NVM_CMD_ER 0x02 /* Erase Row */ -#define SAMD_NVM_CMD_WP 0x04 /* Write Page */ -#define SAMD_NVM_CMD_EAR 0x05 /* Erase Auxilary Row */ -#define SAMD_NVM_CMD_WAP 0x06 /* Write Auxilary Page */ -#define SAMD_NVM_CMD_LR 0x40 /* Lock Region */ -#define SAMD_NVM_CMD_UR 0x41 /* Unlock Region */ -#define SAMD_NVM_CMD_SPRM 0x42 /* Set Power Reduction Mode */ -#define SAMD_NVM_CMD_CPRM 0x43 /* Clear Power Reduction Mode */ -#define SAMD_NVM_CMD_PBC 0x44 /* Page Buffer Clear */ -#define SAMD_NVM_CMD_SSB 0x45 /* Set Security Bit */ -#define SAMD_NVM_CMD_INVALL 0x46 /* Invalidate all caches */ +#define SAMD_NVM_CMD_ER 0x02 /* Erase Row */ +#define SAMD_NVM_CMD_WP 0x04 /* Write Page */ +#define SAMD_NVM_CMD_EAR 0x05 /* Erase Auxilary (User) Row */ +#define SAMD_NVM_CMD_WAP 0x06 /* Write Auxilary (User) Page */ +#define SAMD_NVM_CMD_RWWEEER 0x1A /* Erase RWWEE Row -- only in some parts */ +#define SAMD_NVM_CMD_RWWEEWP 0x1C /* Write RWEEE Page -- only in some parts */ +#define SAMD_NVM_CMD_LR 0x40 /* Lock Region */ +#define SAMD_NVM_CMD_UR 0x41 /* Unlock Region */ +#define SAMD_NVM_CMD_SPRM 0x42 /* Set Power Reduction Mode */ +#define SAMD_NVM_CMD_CPRM 0x43 /* Clear Power Reduction Mode */ +#define SAMD_NVM_CMD_PBC 0x44 /* Page Buffer Clear */ +#define SAMD_NVM_CMD_SSB 0x45 /* Set Security Bit */ +#define SAMD_NVM_CMD_INVALL 0x46 /* Invalidate all caches */ /* NVMCTRL bits */ #define SAMD_NVM_CTRLB_MANW 0x80 @@ -89,216 +92,240 @@ struct samd_part { uint8_t id; const char *name; - uint32_t flash_kb; + uint32_t main_flash_kb; + uint32_t rwwee_b; uint32_t ram_kb; }; +enum +{ + kFlashStorageAreaNVM = 0, + kFlashStorageAreaRWWEE = 1, // not present on all parts + kFlashStorageAreaUserRow = 2 // not presented as a bank +}; + +static const uint16_t region_write_page_commands[3] = { + SAMD_NVM_CMD_WP, + SAMD_NVM_CMD_RWWEEWP, + SAMD_NVM_CMD_WAP +}; + +static const uint16_t region_erase_row_commands[3] = { + SAMD_NVM_CMD_ER, + SAMD_NVM_CMD_RWWEEER, + SAMD_NVM_CMD_EAR +}; + +/* It is not clear why the sizes of memories in the devices must be stored + * in this table since the flash sizes can be determined from the PARAM + * register */ + /* Known SAMD09 parts. DID reset values missing in RM, see * https://github.com/avrxml/asf/blob/master/sam0/utils/cmsis/samd09/include/ */ static const struct samd_part samd09_parts[] = { - { 0x0, "SAMD09D14A", 16, 4 }, - { 0x7, "SAMD09C13A", 8, 4 }, + { 0x0, "SAMD09D14A", 16, 0, 4 }, + { 0x7, "SAMD09C13A", 8, 0, 4 }, }; /* Known SAMD10 parts */ static const struct samd_part samd10_parts[] = { - { 0x0, "SAMD10D14AMU", 16, 4 }, - { 0x1, "SAMD10D13AMU", 8, 4 }, - { 0x2, "SAMD10D12AMU", 4, 4 }, - { 0x3, "SAMD10D14ASU", 16, 4 }, - { 0x4, "SAMD10D13ASU", 8, 4 }, - { 0x5, "SAMD10D12ASU", 4, 4 }, - { 0x6, "SAMD10C14A", 16, 4 }, - { 0x7, "SAMD10C13A", 8, 4 }, - { 0x8, "SAMD10C12A", 4, 4 }, + { 0x0, "SAMD10D14AMU", 16, 0, 4 }, + { 0x1, "SAMD10D13AMU", 8, 0, 4 }, + { 0x2, "SAMD10D12AMU", 4, 0, 4 }, + { 0x3, "SAMD10D14ASU", 16, 0, 4 }, + { 0x4, "SAMD10D13ASU", 8, 0, 4 }, + { 0x5, "SAMD10D12ASU", 4, 0, 4 }, + { 0x6, "SAMD10C14A", 16, 0, 4 }, + { 0x7, "SAMD10C13A", 8, 0, 4 }, + { 0x8, "SAMD10C12A", 4, 0, 4 }, }; /* Known SAMD11 parts */ static const struct samd_part samd11_parts[] = { - { 0x0, "SAMD11D14AM", 16, 4 }, - { 0x1, "SAMD11D13AMU", 8, 4 }, - { 0x2, "SAMD11D12AMU", 4, 4 }, - { 0x3, "SAMD11D14ASS", 16, 4 }, - { 0x4, "SAMD11D13ASU", 8, 4 }, - { 0x5, "SAMD11D12ASU", 4, 4 }, - { 0x6, "SAMD11C14A", 16, 4 }, - { 0x7, "SAMD11C13A", 8, 4 }, - { 0x8, "SAMD11C12A", 4, 4 }, - { 0x9, "SAMD11D14AU", 16, 4 }, + { 0x0, "SAMD11D14AM", 16, 0, 4 }, + { 0x1, "SAMD11D13AMU", 8, 0, 4 }, + { 0x2, "SAMD11D12AMU", 4, 0, 4 }, + { 0x3, "SAMD11D14ASS", 16, 0, 4 }, + { 0x4, "SAMD11D13ASU", 8, 0, 4 }, + { 0x5, "SAMD11D12ASU", 4, 0, 4 }, + { 0x6, "SAMD11C14A", 16, 0, 4 }, + { 0x7, "SAMD11C13A", 8, 0, 4 }, + { 0x8, "SAMD11C12A", 4, 0, 4 }, + { 0x9, "SAMD11D14AU", 16, 0, 4 }, }; /* Known SAMD20 parts. See Table 12-8 in 42129F–SAM–10/2013 */ static const struct samd_part samd20_parts[] = { - { 0x0, "SAMD20J18A", 256, 32 }, - { 0x1, "SAMD20J17A", 128, 16 }, - { 0x2, "SAMD20J16A", 64, 8 }, - { 0x3, "SAMD20J15A", 32, 4 }, - { 0x4, "SAMD20J14A", 16, 2 }, - { 0x5, "SAMD20G18A", 256, 32 }, - { 0x6, "SAMD20G17A", 128, 16 }, - { 0x7, "SAMD20G16A", 64, 8 }, - { 0x8, "SAMD20G15A", 32, 4 }, - { 0x9, "SAMD20G14A", 16, 2 }, - { 0xA, "SAMD20E18A", 256, 32 }, - { 0xB, "SAMD20E17A", 128, 16 }, - { 0xC, "SAMD20E16A", 64, 8 }, - { 0xD, "SAMD20E15A", 32, 4 }, - { 0xE, "SAMD20E14A", 16, 2 }, + { 0x0, "SAMD20J18A", 256, 0, 32 }, + { 0x1, "SAMD20J17A", 128, 0, 16 }, + { 0x2, "SAMD20J16A", 64, 0, 8 }, + { 0x3, "SAMD20J15A", 32, 0, 4 }, + { 0x4, "SAMD20J14A", 16, 0, 2 }, + { 0x5, "SAMD20G18A", 256, 0, 32 }, + { 0x6, "SAMD20G17A", 128, 0, 16 }, + { 0x7, "SAMD20G16A", 64, 0, 8 }, + { 0x8, "SAMD20G15A", 32, 0, 4 }, + { 0x9, "SAMD20G14A", 16, 0, 2 }, + { 0xA, "SAMD20E18A", 256, 0, 32 }, + { 0xB, "SAMD20E17A", 128, 0, 16 }, + { 0xC, "SAMD20E16A", 64, 0, 8 }, + { 0xD, "SAMD20E15A", 32, 0, 4 }, + { 0xE, "SAMD20E14A", 16, 0, 2 }, }; /* Known SAMD21 parts. */ static const struct samd_part samd21_parts[] = { - { 0x0, "SAMD21J18A", 256, 32 }, - { 0x1, "SAMD21J17A", 128, 16 }, - { 0x2, "SAMD21J16A", 64, 8 }, - { 0x3, "SAMD21J15A", 32, 4 }, - { 0x4, "SAMD21J14A", 16, 2 }, - { 0x5, "SAMD21G18A", 256, 32 }, - { 0x6, "SAMD21G17A", 128, 16 }, - { 0x7, "SAMD21G16A", 64, 8 }, - { 0x8, "SAMD21G15A", 32, 4 }, - { 0x9, "SAMD21G14A", 16, 2 }, - { 0xA, "SAMD21E18A", 256, 32 }, - { 0xB, "SAMD21E17A", 128, 16 }, - { 0xC, "SAMD21E16A", 64, 8 }, - { 0xD, "SAMD21E15A", 32, 4 }, - { 0xE, "SAMD21E14A", 16, 2 }, + { 0x0, "SAMD21J18A", 256, 0, 32 }, + { 0x1, "SAMD21J17A", 128, 0, 16 }, + { 0x2, "SAMD21J16A", 64, 0, 8 }, + { 0x3, "SAMD21J15A", 32, 0, 4 }, + { 0x4, "SAMD21J14A", 16, 0, 2 }, + { 0x5, "SAMD21G18A", 256, 0, 32 }, + { 0x6, "SAMD21G17A", 128, 0, 16 }, + { 0x7, "SAMD21G16A", 64, 0, 8 }, + { 0x8, "SAMD21G15A", 32, 0, 4 }, + { 0x9, "SAMD21G14A", 16, 0, 2 }, + { 0xA, "SAMD21E18A", 256, 0, 32 }, + { 0xB, "SAMD21E17A", 128, 0, 16 }, + { 0xC, "SAMD21E16A", 64, 0, 8 }, + { 0xD, "SAMD21E15A", 32, 0, 4 }, + { 0xE, "SAMD21E14A", 16, 0, 2 }, /* SAMR21 parts have integrated SAMD21 with a radio */ - { 0x18, "SAMR21G19A", 256, 32 }, /* with 512k of serial flash */ - { 0x19, "SAMR21G18A", 256, 32 }, - { 0x1A, "SAMR21G17A", 128, 32 }, - { 0x1B, "SAMR21G16A", 64, 16 }, - { 0x1C, "SAMR21E18A", 256, 32 }, - { 0x1D, "SAMR21E17A", 128, 32 }, - { 0x1E, "SAMR21E16A", 64, 16 }, + { 0x18, "SAMR21G19A", 256, 0, 32 }, /* with 512k of serial flash */ + { 0x19, "SAMR21G18A", 256, 0, 32 }, + { 0x1A, "SAMR21G17A", 128, 0, 32 }, + { 0x1B, "SAMR21G16A", 64, 0, 16 }, + { 0x1C, "SAMR21E18A", 256, 0, 32 }, + { 0x1D, "SAMR21E17A", 128, 0, 32 }, + { 0x1E, "SAMR21E16A", 64, 0, 16 }, /* SAMD21 B Variants (Table 3-7 from rev I of datasheet) */ - { 0x20, "SAMD21J16B", 64, 8 }, - { 0x21, "SAMD21J15B", 32, 4 }, - { 0x23, "SAMD21G16B", 64, 8 }, - { 0x24, "SAMD21G15B", 32, 4 }, - { 0x26, "SAMD21E16B", 64, 8 }, - { 0x27, "SAMD21E15B", 32, 4 }, + { 0x20, "SAMD21J16B", 64, 1024, 8 }, + { 0x21, "SAMD21J15B", 32, 1024, 4 }, + { 0x23, "SAMD21G16B", 64, 1024, 8 }, + { 0x24, "SAMD21G15B", 32, 1024, 4 }, + { 0x26, "SAMD21E16B", 64, 1024, 8 }, + { 0x27, "SAMD21E15B", 32, 1024, 4 }, /* SAMD21 D and L Variants (from Errata) http://ww1.microchip.com/downloads/en/DeviceDoc/ SAM-D21-Family-Silicon-Errata-and-DataSheet-Clarification-DS80000760D.pdf */ - { 0x55, "SAMD21E16BU", 64, 8 }, - { 0x56, "SAMD21E15BU", 32, 4 }, - { 0x57, "SAMD21G16L", 64, 8 }, - { 0x3E, "SAMD21E16L", 64, 8 }, - { 0x3F, "SAMD21E15L", 32, 4 }, - { 0x62, "SAMD21E16CU", 64, 8 }, - { 0x63, "SAMD21E15CU", 32, 4 }, - { 0x92, "SAMD21J17D", 128, 16 }, - { 0x93, "SAMD21G17D", 128, 16 }, - { 0x94, "SAMD21E17D", 128, 16 }, - { 0x95, "SAMD21E17DU", 128, 16 }, - { 0x96, "SAMD21G17L", 128, 16 }, - { 0x97, "SAMD21E17L", 128, 16 }, + { 0x55, "SAMD21E16BU", 64, 1024, 8 }, + { 0x56, "SAMD21E15BU", 32, 1024, 4 }, + { 0x57, "SAMD21G16L", 64, 1024, 8 }, + { 0x3E, "SAMD21E16L", 64, 1024, 8 }, + { 0x3F, "SAMD21E15L", 32, 1024, 4 }, + { 0x62, "SAMD21E16CU", 64, 1024, 8 }, + { 0x63, "SAMD21E15CU", 32, 1024, 4 }, + { 0x92, "SAMD21J17D", 128, 1024, 16 }, + { 0x93, "SAMD21G17D", 128, 1024, 16 }, + { 0x94, "SAMD21E17D", 128, 1024, 16 }, + { 0x95, "SAMD21E17DU", 128, 1024, 16 }, + { 0x96, "SAMD21G17L", 128, 1024, 16 }, + { 0x97, "SAMD21E17L", 128, 1024, 16 }, /* Known SAMDA1 parts. SAMD-A1 series uses the same series identifier like the SAMD21 taken from http://ww1.microchip.com/downloads/en/DeviceDoc/40001895A.pdf (pages 14-17) */ - { 0x29, "SAMDA1J16A", 64, 8 }, - { 0x2A, "SAMDA1J15A", 32, 4 }, - { 0x2B, "SAMDA1J14A", 16, 4 }, - { 0x2C, "SAMDA1G16A", 64, 8 }, - { 0x2D, "SAMDA1G15A", 32, 4 }, - { 0x2E, "SAMDA1G14A", 16, 4 }, - { 0x2F, "SAMDA1E16A", 64, 8 }, - { 0x30, "SAMDA1E15A", 32, 4 }, - { 0x31, "SAMDA1E14A", 16, 4 }, - { 0x64, "SAMDA1J16B", 64, 8 }, - { 0x65, "SAMDA1J15B", 32, 4 }, - { 0x66, "SAMDA1J14B", 16, 4 }, - { 0x67, "SAMDA1G16B", 64, 8 }, - { 0x68, "SAMDA1G15B", 32, 4 }, - { 0x69, "SAMDA1G14B", 16, 4 }, - { 0x6A, "SAMDA1E16B", 64, 8 }, - { 0x6B, "SAMDA1E15B", 32, 4 }, - { 0x6C, "SAMDA1E14B", 16, 4 }, + { 0x29, "SAMDA1J16A", 64, 2048, 8 }, + { 0x2A, "SAMDA1J15A", 32, 1024, 4 }, + { 0x2B, "SAMDA1J14A", 16, 512, 4 }, + { 0x2C, "SAMDA1G16A", 64, 2048, 8 }, + { 0x2D, "SAMDA1G15A", 32, 1024, 4 }, + { 0x2E, "SAMDA1G14A", 16, 512, 4 }, + { 0x2F, "SAMDA1E16A", 64, 2048, 8 }, + { 0x30, "SAMDA1E15A", 32, 1024, 4 }, + { 0x31, "SAMDA1E14A", 16, 512, 4 }, + { 0x64, "SAMDA1J16B", 64, 2048, 8 }, + { 0x65, "SAMDA1J15B", 32, 1024, 4 }, + { 0x66, "SAMDA1J14B", 16, 512, 4 }, + { 0x67, "SAMDA1G16B", 64, 2048, 8 }, + { 0x68, "SAMDA1G15B", 32, 1024, 4 }, + { 0x69, "SAMDA1G14B", 16, 512, 4 }, + { 0x6A, "SAMDA1E16B", 64, 2048, 8 }, + { 0x6B, "SAMDA1E15B", 32, 1024, 4 }, + { 0x6C, "SAMDA1E14B", 16, 512, 4 }, }; /* Known SAML21 parts. */ static const struct samd_part saml21_parts[] = { - { 0x00, "SAML21J18A", 256, 32 }, - { 0x01, "SAML21J17A", 128, 16 }, - { 0x02, "SAML21J16A", 64, 8 }, - { 0x05, "SAML21G18A", 256, 32 }, - { 0x06, "SAML21G17A", 128, 16 }, - { 0x07, "SAML21G16A", 64, 8 }, - { 0x0A, "SAML21E18A", 256, 32 }, - { 0x0B, "SAML21E17A", 128, 16 }, - { 0x0C, "SAML21E16A", 64, 8 }, - { 0x0D, "SAML21E15A", 32, 4 }, - { 0x0F, "SAML21J18B", 256, 32 }, - { 0x10, "SAML21J17B", 128, 16 }, - { 0x11, "SAML21J16B", 64, 8 }, - { 0x14, "SAML21G18B", 256, 32 }, - { 0x15, "SAML21G17B", 128, 16 }, - { 0x16, "SAML21G16B", 64, 8 }, - { 0x19, "SAML21E18B", 256, 32 }, - { 0x1A, "SAML21E17B", 128, 16 }, - { 0x1B, "SAML21E16B", 64, 8 }, - { 0x1C, "SAML21E15B", 32, 4 }, + { 0x00, "SAML21J18A", 256, 0, 32 }, + { 0x01, "SAML21J17A", 128, 0, 16 }, + { 0x02, "SAML21J16A", 64, 0, 8 }, + { 0x05, "SAML21G18A", 256, 0, 32 }, + { 0x06, "SAML21G17A", 128, 0, 16 }, + { 0x07, "SAML21G16A", 64, 0, 8 }, + { 0x0A, "SAML21E18A", 256, 0, 32 }, + { 0x0B, "SAML21E17A", 128, 0, 16 }, + { 0x0C, "SAML21E16A", 64, 0, 8 }, + { 0x0D, "SAML21E15A", 32, 0, 4 }, + { 0x0F, "SAML21J18B", 256, 8192, 32 }, + { 0x10, "SAML21J17B", 128, 4096, 16 }, + { 0x11, "SAML21J16B", 64, 2048, 8 }, + { 0x14, "SAML21G18B", 256, 8192, 32 }, + { 0x15, "SAML21G17B", 128, 4096, 16 }, + { 0x16, "SAML21G16B", 64, 2048, 8 }, + { 0x19, "SAML21E18B", 256, 8192, 32 }, + { 0x1A, "SAML21E17B", 128, 4096, 16 }, + { 0x1B, "SAML21E16B", 64, 2048, 8 }, + { 0x1C, "SAML21E15B", 32, 1024, 4 }, /* SAMR30 parts have integrated SAML21 with a radio */ - { 0x1E, "SAMR30G18A", 256, 32 }, - { 0x1F, "SAMR30E18A", 256, 32 }, + { 0x1E, "SAMR30G18A", 256, 8192, 32 }, + { 0x1F, "SAMR30E18A", 256, 8192, 32 }, /* SAMR34/R35 parts have integrated SAML21 with a lora radio */ - { 0x28, "SAMR34J18", 256, 32 }, + { 0x28, "SAMR34J18", 256, 8192, 32 }, }; /* Known SAML22 parts. */ static const struct samd_part saml22_parts[] = { - { 0x00, "SAML22N18A", 256, 32 }, - { 0x01, "SAML22N17A", 128, 16 }, - { 0x02, "SAML22N16A", 64, 8 }, - { 0x05, "SAML22J18A", 256, 32 }, - { 0x06, "SAML22J17A", 128, 16 }, - { 0x07, "SAML22J16A", 64, 8 }, - { 0x0A, "SAML22G18A", 256, 32 }, - { 0x0B, "SAML22G17A", 128, 16 }, - { 0x0C, "SAML22G16A", 64, 8 }, + { 0x00, "SAML22N18A", 256, 8192, 32 }, + { 0x01, "SAML22N17A", 128, 4096, 16 }, + { 0x02, "SAML22N16A", 64, 2048, 8 }, + { 0x05, "SAML22J18A", 256, 8192, 32 }, + { 0x06, "SAML22J17A", 128, 4096, 16 }, + { 0x07, "SAML22J16A", 64, 2048, 8 }, + { 0x0A, "SAML22G18A", 256, 8192, 32 }, + { 0x0B, "SAML22G17A", 128, 4096, 16 }, + { 0x0C, "SAML22G16A", 64, 2048, 8 }, }; /* Known SAMC20 parts. */ static const struct samd_part samc20_parts[] = { - { 0x00, "SAMC20J18A", 256, 32 }, - { 0x01, "SAMC20J17A", 128, 16 }, - { 0x02, "SAMC20J16A", 64, 8 }, - { 0x03, "SAMC20J15A", 32, 4 }, - { 0x05, "SAMC20G18A", 256, 32 }, - { 0x06, "SAMC20G17A", 128, 16 }, - { 0x07, "SAMC20G16A", 64, 8 }, - { 0x08, "SAMC20G15A", 32, 4 }, - { 0x0A, "SAMC20E18A", 256, 32 }, - { 0x0B, "SAMC20E17A", 128, 16 }, - { 0x0C, "SAMC20E16A", 64, 8 }, - { 0x0D, "SAMC20E15A", 32, 4 }, - { 0x20, "SAMC20N18A", 256, 32 }, - { 0x21, "SAMC20N17A", 128, 16 }, + { 0x00, "SAMC20J18A", 256, 8192, 32 }, + { 0x01, "SAMC20J17A", 128, 4096, 16 }, + { 0x02, "SAMC20J16A", 64, 2048, 8 }, + { 0x03, "SAMC20J15A", 32, 1024, 4 }, + { 0x05, "SAMC20G18A", 256, 8192, 32 }, + { 0x06, "SAMC20G17A", 128, 4096, 16 }, + { 0x07, "SAMC20G16A", 64, 2048, 8 }, + { 0x08, "SAMC20G15A", 32, 1024, 4 }, + { 0x0A, "SAMC20E18A", 256, 8192, 32 }, + { 0x0B, "SAMC20E17A", 128, 4096, 16 }, + { 0x0C, "SAMC20E16A", 64, 2048, 8 }, + { 0x0D, "SAMC20E15A", 32, 1024, 4 }, + { 0x20, "SAMC20N18A", 256, 8192, 32 }, + { 0x21, "SAMC20N17A", 128, 4096, 16 }, }; /* Known SAMC21 parts. */ static const struct samd_part samc21_parts[] = { - { 0x00, "SAMC21J18A", 256, 32 }, - { 0x01, "SAMC21J17A", 128, 16 }, - { 0x02, "SAMC21J16A", 64, 8 }, - { 0x03, "SAMC21J15A", 32, 4 }, - { 0x05, "SAMC21G18A", 256, 32 }, - { 0x06, "SAMC21G17A", 128, 16 }, - { 0x07, "SAMC21G16A", 64, 8 }, - { 0x08, "SAMC21G15A", 32, 4 }, - { 0x0A, "SAMC21E18A", 256, 32 }, - { 0x0B, "SAMC21E17A", 128, 16 }, - { 0x0C, "SAMC21E16A", 64, 8 }, - { 0x0D, "SAMC21E15A", 32, 4 }, - { 0x20, "SAMC21N18A", 256, 32 }, - { 0x21, "SAMC21N17A", 128, 16 }, + { 0x00, "SAMC21J18A", 256, 8192, 32 }, + { 0x01, "SAMC21J17A", 128, 4096, 16 }, + { 0x02, "SAMC21J16A", 64, 2048, 8 }, + { 0x03, "SAMC21J15A", 32, 1024, 4 }, + { 0x05, "SAMC21G18A", 256, 8192, 32 }, + { 0x06, "SAMC21G17A", 128, 4096, 16 }, + { 0x07, "SAMC21G16A", 64, 2048, 8 }, + { 0x08, "SAMC21G15A", 32, 1024, 4 }, + { 0x0A, "SAMC21E18A", 256, 8192, 32 }, + { 0x0B, "SAMC21E17A", 128, 4096, 16 }, + { 0x0C, "SAMC21E16A", 64, 2048, 8 }, + { 0x0D, "SAMC21E15A", 32, 1024, 4 }, + { 0x20, "SAMC21N18A", 256, 8192, 32 }, + { 0x21, "SAMC21N17A", 128, 4096, 16 }, }; /* Each family of parts contains a parts table in the DEVSEL field of DID. The @@ -346,7 +373,9 @@ static const struct samd_family samd_families[] = { struct samd_info { uint32_t page_size; - int num_pages; + int num_nvm_pages; + int num_rwwee_pages; + uint32_t rwwee_start_address; int sector_size; int prot_block_size; @@ -401,20 +430,40 @@ static int samd_protect_check(struct flash_bank *bank) int res, prot_block; uint16_t lock; - res = target_read_u16(bank->target, - SAMD_NVMCTRL + SAMD_NVMCTRL_LOCK, &lock); - if (res != ERROR_OK) - return res; + // Avoid reading lock register if this bank doesn't support locking. + if (bank->num_prot_blocks != 0) + { + res = target_read_u16(bank->target, + SAMD_NVMCTRL + SAMD_NVMCTRL_LOCK, &lock); + if (res != ERROR_OK) + return res; - /* Lock bits are active-low */ - for (prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++) - bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block)); + /* Lock bits are active-low */ + for (prot_block = 0; prot_block < bank->num_prot_blocks; prot_block++) + bank->prot_blocks[prot_block].is_protected = !(lock & (1u<<prot_block)); + } return ERROR_OK; } +/* For the address presented, determine which flash region it falls into. + * Regions are not guaranteed to be the same as bank numbers. This code + * will identify data as falling into the user row, but the driver does + * not present the user row as a bank. */ +static int samd_determine_flash_region(const struct samd_info *info, uint32_t address) +{ + int flashregion = kFlashStorageAreaNVM; + + if (address == SAMD_USER_ROW) + flashregion = kFlashStorageAreaUserRow; + else if (info->rwwee_start_address != 0 && address >= info->rwwee_start_address) + flashregion = kFlashStorageAreaRWWEE; + + return flashregion; +} + static int samd_get_flash_page_info(struct target *target, - uint32_t *sizep, int *nump) + uint32_t *sizep, int *nvmnump, int *rwweenump) { int res; uint32_t param; @@ -425,9 +474,13 @@ static int samd_get_flash_page_info(struct target *target, * so 0 is 8KB and 7 is 1024KB. */ if (sizep) *sizep = (8 << ((param >> 16) & 0x7)); - /* The NVMP field (bits 15:0) indicates the total number of pages */ - if (nump) - *nump = param & 0xFFFF; + /* The NVMP field (bits 15:0) indicates the total number of NVM pages */ + if (nvmnump) + *nvmnump = param & 0xFFFF; + /* On some devices the RWWEEP field (bits 31:20) indicate the total */ + /* of RWWEE pages */ + if (rwweenump) + *rwweenump = (param >> 20) & 0xfff; } else { LOG_ERROR("Couldn't read NVM Parameters register"); } @@ -445,6 +498,15 @@ static int samd_probe(struct flash_bank *bank) if (chip->probed) return ERROR_OK; + /* At this point the chip has not been probed so the chip structure + * has been calloced but not filled in. This function should fill it + * in. The chip structure is only used by this bank in this driver, + * it is private data to this bank. */ + + /* Bank is filled in from a 'flash bank' declaration in a config file. + * This function should match the bank declaration to the chip + * parameters. Some parameters are auto determined. */ + res = target_read_u32(bank->target, SAMD_DSU + SAMD_DSU_DID, &id); if (res != ERROR_OK) { LOG_ERROR("Couldn't read Device ID register"); @@ -457,48 +519,117 @@ static int samd_probe(struct flash_bank *bank) return ERROR_FAIL; } - bank->size = part->flash_kb * 1024; + /* Read size of RWWEE area if the area exists on this part. + * If this part doesn't support it the values in these bits are + * reserved and thus cannot be trusted. Listed size of RWWEE + * area is not used. The size is determined from the number of + * pages in the PARAM register and the page size. */ + int *rwweepagesptr = 0; + if (part->rwwee_b != 0) + { + // Decode number of rwwee pages (otherwise not decoded) + rwweepagesptr = &(chip->num_rwwee_pages); + } + + /* Fill in rwwee info so we can find pointers in rww flash regions. + * This isn't completely appropriate because we're not sure this part + * actually has an rwwee section. But we want samd_determine_flash_region + * to indicate the address is in the rwwee region even if the chip doesn't + * have rwwee. */ + chip->rwwee_start_address = SAMD_RWWEE; + + const int regionnumber = samd_determine_flash_region(chip, bank->base); res = samd_get_flash_page_info(bank->target, &chip->page_size, - &chip->num_pages); + &chip->num_nvm_pages,rwweepagesptr); if (res != ERROR_OK) { LOG_ERROR("Couldn't determine Flash page size"); return res; } + int operativepages; + const char *bankname; + int protectionblocks = 0; + /* Sanity check: the total flash size in the DSU should match the page size * multiplied by the number of pages. */ - if (bank->size != chip->num_pages * chip->page_size) { - LOG_WARNING("SAMD: bank size doesn't match NVM parameters. " - "Identified %" PRIu32 "KB Flash but NVMCTRL reports %u %" PRIu32 "B pages", - part->flash_kb, chip->num_pages, chip->page_size); + switch (regionnumber) { + case kFlashStorageAreaNVM: { + operativepages = chip->num_nvm_pages; + bank->size = part->main_flash_kb * 1024; + bankname = "NVM"; + protectionblocks = SAMD_NUM_PROT_BLOCKS; // 16 protection blocks + } + break; + case kFlashStorageAreaRWWEE: { + operativepages = chip->num_rwwee_pages; + bank->size = operativepages * chip->page_size; + bankname = "RWWEE"; + // RWWEE has no protection blocks + } + break; + default: { + operativepages = 0; + bank->size = 0; + bankname = "<INVALID>"; + } + break; + } + + char sizeinkbstr[12]; + + if (sizeof(sizeinkbstr) == 1) + { + sizeinkbstr[0] = '\0'; + } + else if (bank->size >= 1024) { + snprintf(sizeinkbstr, sizeof(sizeinkbstr), "%u" , (unsigned int) (bank->size / 1024)); + } + else if (bank->size == 512) { + sizeinkbstr[sizeof(sizeinkbstr)-1] = '\0'; + strncpy(sizeinkbstr, "0.5", sizeof(sizeinkbstr)-1); + } + else if (sizeof(sizeinkbstr) > 1) { + sizeinkbstr[0] = '0'; + sizeinkbstr[1] = '\0'; + } + + /* Sanity check bank size */ + if (bank->size != operativepages * chip->page_size) { + LOG_WARNING("SAMD: bank size doesn't match %s parameters. " + "Identified %sKB Flash but NVMCTRL reports %u %" PRIu32 "B pages", + bankname, sizeinkbstr, operativepages, chip->page_size); } /* Erase granularity = 1 row = 4 pages */ chip->sector_size = chip->page_size * 4; /* Allocate the sector table */ - bank->num_sectors = chip->num_pages / 4; + bank->num_sectors = operativepages / 4; bank->sectors = alloc_block_array(0, chip->sector_size, bank->num_sectors); if (!bank->sectors) return ERROR_FAIL; - /* 16 protection blocks per device */ - chip->prot_block_size = bank->size / SAMD_NUM_PROT_BLOCKS; - /* Allocate the table of protection blocks */ - bank->num_prot_blocks = SAMD_NUM_PROT_BLOCKS; - bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, bank->num_prot_blocks); - if (!bank->prot_blocks) - return ERROR_FAIL; + bank->num_prot_blocks = protectionblocks; + if (protectionblocks != 0) { + // Calculate protection block size for this bank. + chip->prot_block_size = bank->size / SAMD_NUM_PROT_BLOCKS; + bank->prot_blocks = alloc_block_array(0, chip->prot_block_size, protectionblocks); + if (!bank->prot_blocks) + return ERROR_FAIL; + } + else { + bank->prot_blocks = NULL; + } samd_protect_check(bank); /* Done */ chip->probed = true; - LOG_INFO("SAMD MCU: %s (%" PRIu32 "KB Flash, %" PRIu32 "KB RAM)", part->name, - part->flash_kb, part->ram_kb); + LOG_INFO("SAMD MCU: %s (%sKB %s Flash, %" PRIu32 "KB RAM)", part->name, sizeinkbstr, + bankname, part->ram_kb); return ERROR_OK; } @@ -562,14 +693,14 @@ static int samd_issue_nvmctrl_command(struct target *target, uint16_t cmd) } /** - * Erases a flash-row at the given address. + * Erases the user row * @param target Pointer to the target structure. - * @param address The address of the row. * @return On success ERROR_OK, on failure an errorcode. */ -static int samd_erase_row(struct target *target, uint32_t address) +static int samd_erase_userrow(struct target *target) { int res; + uint32_t address = SAMD_USER_ROW; /* Set an address contained in the row to be erased */ res = target_write_u32(target, @@ -577,8 +708,40 @@ static int samd_erase_row(struct target *target, uint32_t address) /* Issue the Erase Row command to erase that row. */ if (res == ERROR_OK) - res = samd_issue_nvmctrl_command(target, - address == SAMD_USER_ROW ? SAMD_NVM_CMD_EAR : SAMD_NVM_CMD_ER); + res = samd_issue_nvmctrl_command(target, SAMD_NVM_CMD_EAR); + + if (res != ERROR_OK) { + LOG_ERROR("Failed to erase row containing %08" PRIx32, address); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +/** + * Erases a flash-row at the given address. + * @param target Pointer to the target structure. + * @param address The address of the row. + * @return On success ERROR_OK, on failure an errorcode. + */ +static int samd_erase_row(const struct flash_bank *bank, uint32_t address) +{ + if (bank == NULL || bank->target == NULL || bank->driver_priv == NULL) + return ERROR_FAIL; + + struct target *target = bank->target; + const struct samd_info *chip = (const struct samd_info *)bank->driver_priv; + const int flash_region = samd_determine_flash_region(chip, address); + const uint16_t erasecmd = region_erase_row_commands[flash_region]; + const uint32_t offset = address - bank->base; + + /* Set an address contained in the row to be erased */ + int res = target_write_u32(target, + SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, offset >> 1); + + /* Issue the appropriate erase row command to erase that row. */ + if (res == ERROR_OK) + res = samd_issue_nvmctrl_command(target, erasecmd); if (res != ERROR_OK) { LOG_ERROR("Failed to erase row containing %08" PRIx32, address); @@ -647,7 +810,7 @@ static int samd_modify_user_row_masked(struct target *target, /* Retrieve the MCU's page size, in bytes. This is also the size of the * entire User Row. */ uint32_t page_size; - res = samd_get_flash_page_info(target, &page_size, NULL); + res = samd_get_flash_page_info(target, &page_size, NULL, NULL); if (res != ERROR_OK) { LOG_ERROR("Couldn't determine Flash page size"); return res; @@ -673,7 +836,7 @@ static int samd_modify_user_row_masked(struct target *target, * position for which the current value had a '0'. Otherwise we can avoid * erasing. */ if ((~value_device) & value_new) { - res = samd_erase_row(target, SAMD_USER_ROW); + res = samd_erase_userrow(target); if (res != ERROR_OK) { LOG_ERROR("Couldn't erase user row"); return res; @@ -738,34 +901,41 @@ static int samd_protect(struct flash_bank *bank, int set, int first_prot_bl, int return ERROR_TARGET_NOT_HALTED; } - for (prot_block = first_prot_bl; prot_block <= last_prot_bl; prot_block++) { - if (set != bank->prot_blocks[prot_block].is_protected) { - /* Load an address that is within this protection block (we use offset 0) */ - res = target_write_u32(bank->target, - SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, - bank->prot_blocks[prot_block].offset >> 1); - if (res != ERROR_OK) - goto exit; + if (bank->prot_blocks) { + for (prot_block = first_prot_bl; prot_block <= last_prot_bl; prot_block++) { + if (set != bank->prot_blocks[prot_block].is_protected) { + /* Load an address that is within this protection block (we use offset 0) */ + res = target_write_u32(bank->target, + SAMD_NVMCTRL + SAMD_NVMCTRL_ADDR, + bank->prot_blocks[prot_block].offset >> 1); + if (res != ERROR_OK) + goto exit; - /* Tell the controller to lock that block */ - res = samd_issue_nvmctrl_command(bank->target, - set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR); + /* Tell the controller to lock that block */ + res = samd_issue_nvmctrl_command(bank->target, + set ? SAMD_NVM_CMD_LR : SAMD_NVM_CMD_UR); + if (res != ERROR_OK) + goto exit; + } + + /* We've now applied our changes, however they will be undone by the next + * reset unless we also apply them to the LOCK bits in the User Page. The + * LOCK bits start at bit 48, corresponding to Sector 0 and end with bit 63, + * corresponding to Sector 15. A '1' means unlocked and a '0' means + * locked. See Table 9-3 in the SAMD20 datasheet for more details. */ + + res = samd_modify_user_row(bank->target, + set ? (uint64_t)0 : (uint64_t)UINT64_MAX, + 48 + first_prot_bl, 48 + last_prot_bl); if (res != ERROR_OK) - goto exit; + LOG_WARNING("SAMD: protect settings were not made persistent!"); } } - - /* We've now applied our changes, however they will be undone by the next - * reset unless we also apply them to the LOCK bits in the User Page. The - * LOCK bits start at bit 48, corresponding to Sector 0 and end with bit 63, - * corresponding to Sector 15. A '1' means unlocked and a '0' means - * locked. See Table 9-3 in the SAMD20 datasheet for more details. */ - - res = samd_modify_user_row(bank->target, - set ? (uint64_t)0 : (uint64_t)UINT64_MAX, - 48 + first_prot_bl, 48 + last_prot_bl); - if (res != ERROR_OK) - LOG_WARNING("SAMD: protect settings were not made persistent!"); + else + { + res = ERROR_FLASH_OPER_UNSUPPORTED; + goto exit; + } res = ERROR_OK; @@ -793,9 +963,11 @@ static int samd_erase(struct flash_bank *bank, int first_sect, int last_sect) /* For each sector to be erased */ for (s = first_sect; s <= last_sect; s++) { - res = samd_erase_row(bank->target, bank->sectors[s].offset); + uint32_t eraseaddress = bank->base + bank->sectors[s].offset; + + res = samd_erase_row(bank, eraseaddress); if (res != ERROR_OK) { - LOG_ERROR("SAMD: failed to erase sector %d at 0x%08" PRIx32, s, bank->sectors[s].offset); + LOG_ERROR("SAMD: failed to erase sector %d at 0x%08" PRIx32, s, eraseaddress); return res; } } @@ -816,6 +988,8 @@ static int samd_write(struct flash_bank *bank, const uint8_t *buffer, struct samd_info *chip = (struct samd_info *)bank->driver_priv; uint8_t *pb = NULL; bool manual_wp; + const int flash_region = samd_determine_flash_region(chip, bank->base); + const uint16_t writecmd = region_write_page_commands[flash_region]; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -890,11 +1064,11 @@ static int samd_write(struct flash_bank *bank, const uint8_t *buffer, } /* Devices with errata 13134 have automatic page write enabled by default - * For other devices issue a write page CMD to the NVM + * For other devices issue a write page CMD to the NVMCTRL * If the page has not been written up to the last word - * then issue CMD_WP always */ + * then issue write page command` always */ if (manual_wp || pg_offset + 4 * nw < chip->page_size) { - res = samd_issue_nvmctrl_command(bank->target, SAMD_NVM_CMD_WP); + res = samd_issue_nvmctrl_command(bank->target, writecmd); } else { /* Access through AHB is stalled while flash is being programmed */ usleep(200); @@ -922,11 +1096,12 @@ free_pb: FLASH_BANK_COMMAND_HANDLER(samd_flash_bank_command) { - if (bank->base != SAMD_FLASH) { + if (bank->base != SAMD_MAIN_FLASH && + bank->base != SAMD_RWWEE) { LOG_ERROR("Address " TARGET_ADDR_FMT " invalid bank address (try 0x%08" PRIx32 "[at91samd series] )", - bank->base, SAMD_FLASH); + bank->base, SAMD_MAIN_FLASH); return ERROR_FAIL; } @@ -1142,7 +1317,7 @@ COMMAND_HANDLER(samd_handle_bootloader_command) /* Retrieve the MCU's page size, in bytes. */ uint32_t page_size; - res = samd_get_flash_page_info(target, &page_size, NULL); + res = samd_get_flash_page_info(target, &page_size, NULL, NULL); if (res != ERROR_OK) { LOG_ERROR("Couldn't determine Flash page size"); return res; diff --git a/tcl/target/at91samdXX.cfg b/tcl/target/at91samdXX.cfg index 9a396fa..88bedb1 100644 --- a/tcl/target/at91samdXX.cfg +++ b/tcl/target/at91samdXX.cfg @@ -80,4 +80,5 @@ if {![using_hla]} { } set _FLASHNAME $_CHIPNAME.flash -flash bank $_FLASHNAME at91samd 0x00000000 0 1 1 $_TARGETNAME +flash bank $_FLASHNAME.main at91samd 0x00000000 0 1 1 $_TARGETNAME +flash bank $_FLASHNAME.rwwee at91samd 0x00400000 0 1 1 $_TARGETNAME -- _______________________________________________ OpenOCD-devel mailing list OpenOCD-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openocd-devel