This is an automated email from Gerrit. "Benjamin Vernoux <bvern...@gmail.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7804
-- gerrit commit 38c8d789b66c25c455ed4f8be854e4eb308cf065 Author: Benjamin Vernoux <bvern...@gmail.com> Date: Thu Aug 31 12:48:00 2023 +0200 Add support of Zbit cx32l003 target and nor flash loader Note: Fully tested with Ebyte E220-900T22D which use a LoRa LLCC68 chip + CX32L003F8 MCU (Arm Cortex-M0+ 64KB Flash/4KB SRAM) Change-Id: Ibf5692be9db9e80e88442f3f1e349e02e9a1ff22 Signed-off-by: Benjamin Vernoux <bvern...@gmail.com> diff --git a/contrib/loaders/flash/cx32l003/Makefile b/contrib/loaders/flash/cx32l003/Makefile new file mode 100644 index 0000000000..9f53629fb6 --- /dev/null +++ b/contrib/loaders/flash/cx32l003/Makefile @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# +# Copyright (C) 2023 Benjamin VERNOUX 31 Aug 2023 (based on Makefile of npcx) +# +BIN2C = ../../../../src/helper/bin2char.sh + +# Toolchain used in makefile +CROSS_COMPILE ?= arm-none-eabi- +CC = $(CROSS_COMPILE)gcc +CPLUS = $(CROSS_COMPILE)g++ +CPP = $(CROSS_COMPILE)cpp +LD = $(CROSS_COMPILE)gcc +AS = $(CROSS_COMPILE)as +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +OBJSIZE = $(CROSS_COMPILE)size + +TARGET = cx32l003_algo +OBJS = entry_cx32l003.o cx32l003_flash.o +FLAGS = -mcpu=cortex-m0plus -mthumb -Os -ffunction-sections -fdata-sections -g -gdwarf-3 --specs=nano.specs +FLAGS += -gstrict-dwarf -Wall -fno-strict-aliasing --asm + +CFLAGS = -c -I. -mcpu=cortex-m0plus -mthumb -fpack-struct + +PRE_LD_FILE = cx32l003_flash.lds +LD_FILE = cx32l003_flash_generated.lds +LDFLAGS = -T$(LD_FILE) -Xlinker --gc-sections -Xlinker --print-memory-usage -Wl,-Map,"$(TARGET).map" -nostartfiles + +all: $(TARGET).inc + +# Implicit rules +%.o: %.c + -@ echo CC $@ from $< + @$(CC) $< $(FLAGS) $(CFLAGS) -o $@ + +%.o: %.S + -@ echo CC $@ from $< + @$(CC) $(FLAGS) $(CFLAGS) -x assembler -c -o "$@" "$<" + +$(LD_FILE): $(PRE_LD_FILE) + -@ echo Generate $@ from $< + -@$(CPP) $(PRE_LD_FILE) | grep -v '^#' >>$(LD_FILE) + +$(TARGET).elf: $(OBJS) $(LD_FILE) + -@ echo LD $@ from $(OBJS) + @$(CC) -o $@ $(FLAGS) $(LDFLAGS) $(OBJS) + +%.bin: %.elf + -@ echo OBJCOPY $@ from $< + -@ $(OBJCOPY) $< -O binary $@ + -@ $(OBJSIZE) $< --format=berkeley + +%.inc: %.bin + @echo 'Building target: $@' + @echo 'Invoking Bin2Char Script' + $(BIN2C) < $< > $@ + @echo 'Finished building target: $@' + @echo 'Cleanup files' + rm $< $*.elf $*.map *.o cx32l003_flash_generated.lds + @echo ' ' + +clean: + @echo 'Cleaning Targets and Build Artifacts' + rm -rf *.inc *.bin *.elf *.map + rm -rf *.o *.d + rm -rf $(LD_FILE) + @echo 'Finished clean' + @echo ' ' + +.PRECIOUS: %.bin + +.PHONY: all clean diff --git a/contrib/loaders/flash/cx32l003/cx32l003_algo.inc b/contrib/loaders/flash/cx32l003/cx32l003_algo.inc new file mode 100644 index 0000000000..46136f305e --- /dev/null +++ b/contrib/loaders/flash/cx32l003/cx32l003_algo.inc @@ -0,0 +1,66 @@ +/* Autogenerated with ../../../../src/helper/bin2char.sh */ +0x02,0x48,0x85,0x46,0x00,0xf0,0x24,0xf9,0xfe,0xe7,0x00,0x00,0x20,0x08,0x00,0x20, +0x70,0xb5,0x2d,0x4b,0x5a,0x68,0x52,0x07,0x05,0xd5,0x2c,0x4a,0x9a,0x61,0x2c,0x4a, +0x9a,0x60,0x2c,0x4a,0x9a,0x61,0x80,0x24,0x2b,0x4b,0x2c,0x4a,0x2c,0x49,0x24,0x02, +0xa0,0x42,0x26,0xd2,0x01,0x24,0x86,0x0a,0xb4,0x40,0xda,0x60,0xd9,0x60,0x1d,0x69, +0x2c,0x43,0x1c,0x61,0x02,0x24,0xda,0x60,0xd9,0x60,0x1c,0x60,0x00,0x24,0x04,0x25, +0x04,0x60,0x1e,0x68,0x34,0x00,0x2c,0x40,0x2e,0x42,0xfa,0xd1,0xff,0x26,0xda,0x60, +0xd9,0x60,0x1d,0x68,0xb5,0x43,0x1d,0x60,0x80,0x25,0x2d,0x02,0xa8,0x42,0x1a,0xd2, +0xda,0x60,0xd9,0x60,0x01,0x21,0x80,0x0a,0x81,0x40,0x1a,0x69,0x8a,0x43,0x1a,0x61, +0x70,0xbd,0x80,0x24,0x64,0x02,0xa0,0x42,0xdc,0xd2,0x16,0x4c,0xda,0x60,0x05,0x19, +0x01,0x24,0xad,0x0a,0xac,0x40,0xd9,0x60,0x5e,0x69,0x34,0x43,0x5c,0x61,0x00,0x24, +0xda,0x60,0xdc,0x60,0xce,0xe7,0x80,0x25,0x6d,0x02,0xa8,0x42,0xe8,0xd2,0x0d,0x4d, +0xda,0x60,0x40,0x19,0x01,0x25,0x80,0x0a,0x85,0x40,0xd9,0x60,0x59,0x69,0xa9,0x43, +0x59,0x61,0xda,0x60,0xdc,0x60,0xdb,0xe7,0x00,0x24,0x00,0x40,0x99,0x66,0xaa,0x55, +0xff,0xff,0x0f,0x00,0x98,0x66,0xaa,0x55,0x00,0x04,0x02,0x40,0x5a,0x5a,0x00,0x00, +0xa5,0xa5,0x00,0x00,0x00,0x80,0xff,0xff,0xf0,0xb5,0x3c,0x4b,0x85,0xb0,0x01,0x92, +0x5c,0x68,0x62,0x07,0x05,0xd5,0x3a,0x4c,0x9c,0x61,0x3a,0x4c,0x9c,0x60,0x3a,0x4c, +0x9c,0x61,0x43,0x18,0x02,0x93,0xff,0x23,0x01,0x25,0x9c,0x46,0x02,0x9b,0x98,0x42, +0x01,0xd1,0x05,0xb0,0xf0,0xbd,0x80,0x22,0x34,0x4b,0x35,0x49,0x35,0x4c,0x12,0x02, +0x90,0x42,0x32,0xd2,0x62,0x46,0x86,0x0a,0x16,0x40,0x2a,0x00,0xb2,0x40,0x16,0x00, +0xd9,0x60,0xdc,0x60,0x1f,0x69,0x3e,0x43,0x1e,0x61,0x62,0x46,0xd9,0x60,0xdc,0x60, +0x1e,0x68,0x96,0x43,0x1e,0x60,0xd9,0x60,0xdc,0x60,0x1e,0x68,0x2e,0x43,0x1e,0x60, +0x04,0x26,0x01,0x9a,0x12,0x68,0x02,0x60,0x1f,0x68,0x3a,0x00,0x32,0x40,0x03,0x92, +0x37,0x42,0xf9,0xd1,0x80,0x22,0x12,0x02,0x90,0x42,0x23,0xd2,0x62,0x46,0xd9,0x60, +0xdc,0x60,0x84,0x0a,0x14,0x40,0x2a,0x00,0xa2,0x40,0x19,0x69,0x91,0x43,0x19,0x61, +0x01,0x9b,0x04,0x30,0x04,0x33,0x01,0x93,0xc0,0xe7,0x80,0x22,0x52,0x02,0x90,0x42, +0xd3,0xd2,0x19,0x4a,0xd9,0x60,0x86,0x18,0x62,0x46,0xb6,0x0a,0x16,0x40,0x2a,0x00, +0xb2,0x40,0x16,0x00,0xdc,0x60,0x5f,0x69,0x3e,0x43,0x5e,0x61,0x00,0x26,0xd9,0x60, +0xde,0x60,0xc2,0xe7,0x80,0x22,0x52,0x02,0x90,0x42,0xe1,0xd2,0x0e,0x4a,0xd9,0x60, +0xdc,0x60,0x84,0x18,0x62,0x46,0xa4,0x0a,0x14,0x40,0x2a,0x00,0xa2,0x40,0x5e,0x69, +0x96,0x43,0x5e,0x61,0xd9,0x60,0x03,0x9a,0xda,0x60,0xd1,0xe7,0x00,0x24,0x00,0x40, +0x99,0x66,0xaa,0x55,0xff,0xff,0x0f,0x00,0x98,0x66,0xaa,0x55,0x00,0x04,0x02,0x40, +0x5a,0x5a,0x00,0x00,0xa5,0xa5,0x00,0x00,0x00,0x80,0xff,0xff,0x10,0xb5,0x10,0x22, +0x00,0x21,0x00,0xf0,0xf9,0xf8,0x00,0x20,0x10,0xbd,0x00,0x00,0x80,0x23,0x0a,0x4a, +0x5b,0x00,0x91,0x68,0x0b,0x43,0x93,0x60,0x08,0x4b,0x5a,0x68,0x52,0x07,0x05,0xd5, +0x07,0x4a,0x9a,0x61,0x07,0x4a,0x9a,0x60,0x07,0x4a,0x9a,0x61,0x04,0x23,0x07,0x49, +0x0a,0x68,0x1a,0x42,0xfc,0xd1,0x70,0x47,0x00,0x00,0x02,0x40,0x00,0x24,0x00,0x40, +0x99,0x66,0xaa,0x55,0xff,0xff,0x0f,0x00,0x98,0x66,0xaa,0x55,0x00,0x04,0x02,0x40, +0xf7,0xb5,0xff,0xf7,0xdb,0xff,0x59,0x4c,0x20,0x00,0xff,0xf7,0xcf,0xff,0x23,0x7b, +0x61,0x7b,0xa2,0x7b,0x09,0x02,0x19,0x43,0xe3,0x7b,0x12,0x04,0x11,0x43,0x1b,0x06, +0x0b,0x43,0x11,0xd0,0x20,0x7a,0x62,0x7a,0xa3,0x7a,0x12,0x02,0x02,0x43,0xe0,0x7a, +0x1b,0x04,0x1a,0x43,0x00,0x06,0x10,0x43,0x01,0x38,0x03,0x28,0x00,0xd9,0x88,0xe0, +0x00,0xf0,0xa8,0xf8,0x0d,0x2d,0x56,0x6f,0x49,0x4b,0x5a,0x68,0x52,0x07,0xde,0xd5, +0x48,0x4a,0x9a,0x61,0x48,0x4a,0x9a,0x60,0x48,0x4a,0x9a,0x61,0xd7,0xe7,0xf8,0x22, +0x47,0x4b,0x1a,0x70,0xf5,0x3a,0x5a,0x70,0x2f,0x32,0x9a,0x70,0x00,0x22,0xda,0x70, +0x44,0x4b,0x1a,0x60,0x43,0x4b,0x1b,0x68,0x00,0x2b,0x6d,0xd0,0xff,0x21,0x1a,0x00, +0x0a,0x40,0x20,0x7b,0x22,0x73,0x1a,0x0a,0x0a,0x40,0x60,0x7b,0x62,0x73,0x1a,0x0c, +0x0a,0x40,0x1b,0x0e,0xa1,0x7b,0xa2,0x73,0xe2,0x7b,0xe3,0x73,0xfe,0xe7,0x22,0x78, +0x63,0x78,0x39,0x4f,0x1b,0x02,0x13,0x43,0x3b,0x80,0xa2,0x78,0xe2,0x78,0x23,0x79, +0x61,0x79,0xa2,0x79,0x09,0x02,0x19,0x43,0xe3,0x79,0x12,0x04,0x33,0x4e,0x11,0x43, +0x1b,0x06,0x0b,0x43,0x33,0x60,0x35,0x68,0x00,0x2d,0x02,0xd1,0x00,0x22,0x2d,0x4b, +0xcf,0xe7,0x3b,0x88,0x18,0x00,0x01,0x93,0xff,0xf7,0x72,0xfe,0x80,0x22,0x92,0x00, +0x94,0x46,0x2b,0x4b,0xed,0x18,0x01,0x9b,0x35,0x60,0x63,0x44,0x3b,0x80,0xea,0xe7, +0x00,0x23,0x25,0x4f,0x25,0x4e,0x3b,0x80,0x80,0x23,0x5b,0x02,0x33,0x60,0x35,0x68, +0x00,0x2d,0xe3,0xd0,0x3b,0x88,0x18,0x00,0x01,0x93,0xff,0xf7,0x59,0xfe,0x80,0x22, +0x92,0x00,0x94,0x46,0x1e,0x4b,0xed,0x18,0x01,0x9b,0x35,0x60,0x63,0x44,0x3b,0x80, +0xed,0xe7,0x22,0x78,0x63,0x78,0xa0,0x78,0x1b,0x02,0x1a,0x43,0xe3,0x78,0x00,0x04, +0x10,0x43,0x1b,0x06,0x21,0x79,0x18,0x43,0x63,0x79,0xa2,0x79,0x1b,0x02,0x0b,0x43, +0xe1,0x79,0x12,0x04,0x13,0x43,0x09,0x06,0x0d,0x4a,0x19,0x43,0xff,0xf7,0xa4,0xfe, +0xbc,0xe7,0x01,0x22,0x0b,0x4b,0x8c,0xe7,0x22,0x7b,0x23,0x73,0x62,0x7b,0x63,0x73, +0xa2,0x7b,0xa3,0x73,0xe2,0x7b,0xe3,0x73,0x51,0xe7,0xc0,0x46,0x00,0x00,0x00,0x20, +0x00,0x24,0x00,0x40,0x99,0x66,0xaa,0x55,0xff,0xff,0x0f,0x00,0x98,0x66,0xaa,0x55, +0x10,0x00,0x00,0x20,0x20,0x06,0x00,0x20,0x18,0x06,0x00,0x20,0x1c,0x06,0x00,0x20, +0x00,0xfe,0xff,0xff,0x02,0xb4,0x71,0x46,0x49,0x08,0x49,0x00,0x09,0x5c,0x49,0x00, +0x8e,0x44,0x02,0xbc,0x70,0x47,0xc0,0x46,0x03,0x00,0x82,0x18,0x93,0x42,0x00,0xd1, +0x70,0x47,0x19,0x70,0x01,0x33,0xf9,0xe7, diff --git a/contrib/loaders/flash/cx32l003/cx32l003_flash.c b/contrib/loaders/flash/cx32l003/cx32l003_flash.c new file mode 100644 index 0000000000..32611e803c --- /dev/null +++ b/contrib/loaders/flash/cx32l003/cx32l003_flash.c @@ -0,0 +1,314 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2020 by Nuvoton Technology Corporation + * Mulin Chao <mlc...@nuvoton.com> + * Wealian Liao <whl...@nuvoton.com> + * + * Copyright (C) 2023 Benjamin VERNOUX 31 Aug 2023 (based on npcx_flash.c) + */ +#include <stdint.h> +#include <string.h> +#include "cx32l003_flash.h" + +/*---------------------------------------------------------------------------- + * CX32L003 Driver + *----------------------------------------------------------------------------*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/** + * @brief System RCC (RCC) + */ +typedef struct { /*!< (@ 0x40020000) RCC Structure */ + __IO uint32_t HCLKDIV; /*!< (@ 0x00000000) AHB CLK Prescale */ + __IO uint32_t PCLKDIV; /*!< (@ 0x00000004) APB CLK Prescale */ + __IO uint32_t HCLKEN; /*!< (@ 0x00000008) AHB Peripheral Model Clk Enable */ + __IO uint32_t PCLKEN; /*!< (@ 0x0000000C) APB Peripheral Model CLK Enable */ + __IO uint32_t MCOCR; /*!< (@ 0x00000010) Clock Output Control Register */ + __I uint32_t RESERVED; + __IO uint32_t RSTCR; /*!< (@ 0x00000018) System Reset Control */ + __IO uint32_t RSTSR; /*!< (@ 0x0000001C) Reset Status */ + __IO uint32_t SYSCLKCR; /*!< (@ 0x00000020) CLK Setting */ + __IO uint32_t SYSCLKSEL; /*!< (@ 0x00000024) System Clock Select */ + __IO uint32_t HIRCCR; /*!< (@ 0x00000028) HIRC Control */ + __IO uint32_t HXTCR; /*!< (@ 0x0000002C) HXT Control */ + __IO uint32_t LIRCCR; /*!< (@ 0x00000030) LIRC Control */ + __IO uint32_t LXTCR; /*!< (@ 0x00000034) LXT Control */ + __IO uint32_t IRQLATENCY; /*!< (@ 0x00000038) M0 IRQ Delay */ + __IO uint32_t STICKCR; /*!< (@ 0x0000003C) SysTick Timer Circle Adjust */ + __IO uint32_t SWDIOCR; /*!< (@ 0x00000040) Endpoint Function Select */ + __IO uint32_t PERIRST; /*!< (@ 0x00000044) Peripheral Model Control */ + __IO uint32_t RTCRST; /*!< (@ 0x00000048) RTC Control */ + __I uint32_t RESERVED1[5]; + __IO uint32_t UNLOCK; /*!< (@ 0x00000060) Register Protect */ +} RCC_TypeDef; /*!< Size = 100 (0x64) */ +#define RCC_BASE 0x40020000UL +#define RCC ((RCC_TypeDef*) RCC_BASE) + + /** + * @brief Independent Watch Dog (IWDG) + */ +typedef struct { /*!< (@ 0x40002400) IWDG Structure */ + __IO uint32_t CMDCR; /*!< (@ 0x00000000) IWDG Control Command Register */ + __IO uint32_t CFGR; /*!< (@ 0x00000004) IWDG Config Register */ + __IO uint32_t RLOAD; /*!< (@ 0x00000008) Count ReLoad Register */ + __IO uint32_t CNTVAL;/*!< (@ 0x0000000C) Count Value */ + __IO uint32_t SR; /*!< (@ 0x00000010) IWDG Interrupt Status Register */ + __IO uint32_t INTCLR;/*!< (@ 0x00000014) IWDG Interrupt Status Register */ + __IO uint32_t UNLOCK;/*!< (@ 0x00000018) IWDG register Writer Protect */ +} IWDG_TypeDef; /*!< Size = 28 (0x1c) */ +#define IWDG_BASE 0x40002400UL +#define IWDG ((IWDG_TypeDef*) IWDG_BASE) + +/** + * @brief Flash Controller (FLASH) + */ +typedef struct { /*!< (@ 0x40020400) FLASH Structure */ + __IO uint32_t CR; /*!< (@ 0x00000000) Control Register */ + __IO uint32_t IFR; /*!< (@ 0x00000004) Interrupt flag Register */ + __IO uint32_t ICLR; /*!< (@ 0x00000008) Interrupt Flag Clear Register */ + __IO uint32_t BYPASS; /*!< (@ 0x0000000C) 0X5A5A-0XA5A5 sequence Register */ + __IO uint32_t SLOCK0; /*!< (@ 0x00000010) Sector Write Protect Register0 */ + __IO uint32_t SLOCK1; /*!< (@ 0x00000014) Sector Write Protect Register1 */ + __IO uint32_t ISPCON; /*!< (@ 0x00000018) Flash ISP Control register */ +} FLASH_TypeDef; /*!< Size = 28 (0x1c) */ +#define FLASH_BASE 0x40020400UL +#define FLASH ((FLASH_TypeDef*) FLASH_BASE) + +void cx32l003_FlashEraseSector(uint32_t page_addr) +{ + uint32_t val; + /* If IWDG is running, reload it to max value about 27s */ + val = IWDG->CFGR; + if ((val & 4) == 4) { + IWDG->UNLOCK = 0x55aa6699; + IWDG->RLOAD = 0xfffff; + IWDG->UNLOCK = 0x55aa6698; + } + + if (page_addr < 0x8000) { + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->SLOCK0; + FLASH->SLOCK0 = val | 1 << (page_addr >> 10 & 0xff); + } else if (page_addr < 0x10000) { + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->SLOCK1; + FLASH->SLOCK1 = val | 1 << ((page_addr - 0x8000) >> 10 & 0xff); + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0; + } + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + FLASH->CR = 2; + /* Erase flash sector */ + *(uint32_t *)page_addr = 0; + + /* Wait for end of erase "idle state" */ + do { + val = FLASH->CR; + } while ((val & 4) == 4); + + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->CR; + FLASH->CR = val & 0xffffff00; + if (page_addr < 0x8000) { + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->SLOCK0; + FLASH->SLOCK0 = val & ~(1 << (page_addr >> 10 & 0xff)); + } else if (page_addr < 0x10000) { + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->SLOCK1; + FLASH->SLOCK1 = val & ~(1 << ((page_addr - 0x8000) >> 10 & 0xff)); + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0; + } +} + +void cx32l003_FlashProgram(uint32_t *flash_addr_dst,int size,uint32_t *ram_data_src) +{ + uint32_t val; + + /* If IWDG is running, reload it to max value about 27s */ + val = IWDG->CFGR; + if ((val & 4) == 4) { + IWDG->UNLOCK = 0x55aa6699; + IWDG->RLOAD = 0xfffff; + IWDG->UNLOCK = 0x55aa6698; + } + for (; size != 0; size = size-4) { + if (flash_addr_dst < (uint32_t *)0x8000) { + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->SLOCK0; + FLASH->SLOCK0 = val | 1 << ((uint32_t)flash_addr_dst >> 10 & 0xff); + } else if (flash_addr_dst < (uint32_t *)0x10000) { + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->SLOCK1; + FLASH->SLOCK1 = val | 1 << ((uint32_t)(flash_addr_dst - 0x2000) >> 10 & 0xff); + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0; + } + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->CR; + FLASH->CR = val & 0xffffff00; + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->CR; + FLASH->CR = val | 1; + + /* Program flash */ + *flash_addr_dst = *ram_data_src; + + /* Wait end of program "idle state" */ + do { + val = FLASH->CR; + } while ((val & 4) == 4); + + if (flash_addr_dst < (uint32_t *)0x8000) { + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->SLOCK0; + FLASH->SLOCK0 = val & ~(1 << ((uint32_t)flash_addr_dst >> 10 & 0xff)); + } else if (flash_addr_dst < (uint32_t *)0x10000) { + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0xa5a5; + val = FLASH->SLOCK1; + FLASH->SLOCK1 = val & ~(1 << ((uint32_t)(flash_addr_dst - 0x2000) >> 10 & 0xff)); + FLASH->BYPASS = 0x5a5a; + FLASH->BYPASS = 0; + } + flash_addr_dst = flash_addr_dst + 1; + ram_data_src = ram_data_src + 1; + } +} + +/*---------------------------------------------------------------------------- + * flash loader function + *----------------------------------------------------------------------------*/ +uint32_t flashloader_init(struct cx32l003_flash_params *params) +{ + /* Initialize params buffers */ + memset(params, 0, sizeof(struct cx32l003_flash_params)); + + return CX32L003_FLASH_STATUS_OK; +} + +/*---------------------------------------------------------------------------- + * Functions + *----------------------------------------------------------------------------*/ +/* flashloader parameter structure */ +__attribute__ ((section(".buffers.g_cfg"))) +volatile struct cx32l003_flash_params g_cfg; +/* data buffer */ +__attribute__ ((section(".buffers.g_buf"))) +uint8_t g_buf[CX32L003_FLASH_LOADER_BUFFER_SIZE]; + +static uint32_t val; +static int status; +static uint16_t address; +static uint32_t size; + +void Init(void) +{ + // RCC Unlock is done in openocd cx32l003.cfg + /* Flash controller block clock enable */ + val = RCC->HCLKEN; + RCC->HCLKEN = val | 0x100; + + /* If IWDG is running, reload it to max value about 27s */ + val = IWDG->CFGR; + if ((val & 4) == 4) { + IWDG->UNLOCK = 0x55aa6699; + IWDG->RLOAD = 0xfffff; + IWDG->UNLOCK = 0x55aa6698; + } + + /* Wait Flash "idle state" */ + do { + val = FLASH->CR; + } while ((val & 4) == 4); +} + +int main(void) +{ + Init(); + + /* set buffer */ + flashloader_init((struct cx32l003_flash_params *)&g_cfg); + + while (1) { + /* wait command*/ + while (g_cfg.sync == CX32L003_FLASH_LOADER_WAIT) + { + /* If IWDG is running, reload it to max value about 27s */ + val = IWDG->CFGR; + if ((val & 4) == 4) { + IWDG->UNLOCK = 0x55aa6699; + IWDG->RLOAD = 0xfffff; + IWDG->UNLOCK = 0x55aa6698; + } + } + + /* command handler */ + switch (g_cfg.cmd) { + case CX32L003_FLASH_CMD_GET_FLASH_ID: + /* Hard coded identifier 0x003203F8 for CX32L003F8 */ + g_buf[0] = 0xF8; /* LSB */ + g_buf[1] = 0x03; + g_buf[2] = 0x32; + g_buf[3] = 0x00; /* MSB */ + status = CX32L003_FLASH_STATUS_OK; + break; + case CX32L003_FLASH_CMD_ERASE_SECTORS: + /* Alignment has been checked in upper layer */ + address = g_cfg.addr; + size = g_cfg.len; + for (; size > 0; size -= CX32L003_FLASH_ERASE_SIZE, + address += CX32L003_FLASH_ERASE_SIZE) { + cx32l003_FlashEraseSector(address); + } + status = CX32L003_FLASH_STATUS_OK; + break; + case CX32L003_FLASH_CMD_ERASE_ALL: + address = 0x0; + size = 64 * 1024; /* 64KB */ + for (; size > 0; size -= CX32L003_FLASH_ERASE_SIZE, + address += CX32L003_FLASH_ERASE_SIZE) { + cx32l003_FlashEraseSector(address); + } + status = CX32L003_FLASH_STATUS_OK; + break; + case CX32L003_FLASH_CMD_PROGRAM: + cx32l003_FlashProgram((uint32_t *)g_cfg.addr, g_cfg.len, (uint32_t *)g_buf); + status = CX32L003_FLASH_STATUS_OK; + break; + default: + status = CX32L003_FLASH_STATUS_FAILED_UNKNOWN_COMMAND; + break; + } + + /* clear & set result for next command */ + if (status != CX32L003_FLASH_STATUS_OK) { + g_cfg.sync = status; + // Fatal error infinite loop + while (1) + ; + } else { + g_cfg.sync = CX32L003_FLASH_LOADER_WAIT; + } + } + + return 0; +} diff --git a/contrib/loaders/flash/cx32l003/cx32l003_flash.h b/contrib/loaders/flash/cx32l003/cx32l003_flash.h new file mode 100644 index 0000000000..58950bf387 --- /dev/null +++ b/contrib/loaders/flash/cx32l003/cx32l003_flash.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2020 by Nuvoton Technology Corporation + * Mulin Chao <mlc...@nuvoton.com> + * Wealian Liao <whl...@nuvoton.com> + * + * Copyright (C) 2023 Benjamin VERNOUX 31 Aug 2023 (based on npcx_flash.h) + */ +#ifndef OPENOCD_LOADERS_FLASH_CX32L003_H +#define OPENOCD_LOADERS_FLASH_CX32L003_H + +#include "cx32l003_flash_config.h" + +/* Flash loader parameters */ +struct __attribute__((__packed__)) cx32l003_flash_params { + uint32_t addr; /* Address in flash */ + uint32_t len; /* Number of bytes */ + uint32_t cmd; /* Command */ + uint32_t sync; /* Handshake signal */ +}; + +/* Flash trigger signal */ +enum cx32l003_flash_handshake { + CX32L003_FLASH_LOADER_WAIT = 0x0, /* Idle */ + CX32L003_FLASH_LOADER_EXECUTE = 0xFFFFFFFF /* Execute Command */ +}; + +/* Flash loader command */ +enum cx32l003_flash_commands { + CX32L003_FLASH_CMD_NO_ACTION = 0, /* No action, default value */ + CX32L003_FLASH_CMD_GET_FLASH_ID, /* Get the internal flash ID */ + CX32L003_FLASH_CMD_ERASE_SECTORS, /* Erase unprotected sectors */ + CX32L003_FLASH_CMD_ERASE_ALL, /* Erase all */ + CX32L003_FLASH_CMD_PROGRAM, /* Program data */ +}; + +/* Status */ +enum cx32l003_flash_status { + CX32L003_FLASH_STATUS_OK = 0, + CX32L003_FLASH_STATUS_FAILED_UNKNOWN_COMMAND, + CX32L003_FLASH_STATUS_FAILED, + CX32L003_FLASH_STATUS_FAILED_TIMEOUT, +}; + +#endif /* OPENOCD_LOADERS_FLASH_CX32L003_H */ diff --git a/contrib/loaders/flash/cx32l003/cx32l003_flash.lds b/contrib/loaders/flash/cx32l003/cx32l003_flash.lds new file mode 100644 index 0000000000..a620dc0cca --- /dev/null +++ b/contrib/loaders/flash/cx32l003/cx32l003_flash.lds @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* Copyright (C) 2023 Benjamin VERNOUX 31 Aug 2023 */ + +#include "cx32l003_flash_config.h" + +/* Application memory map */ +MEMORY { + /* buffer + parameters */ + BUFFER (RWX) : ORIGIN = CX32L003_FLASH_LOADER_PARAMS_ADDR, + LENGTH = CX32L003_FLASH_LOADER_PARAMS_SIZE + CX32L003_FLASH_LOADER_BUFFER_SIZE + + PROGRAM (RWX) : ORIGIN = CX32L003_FLASH_LOADER_PROGRAM_ADDR, + LENGTH = CX32L003_FLASH_LOADER_PROGRAM_SIZE +} + +/* Sections used for flashing */ +SECTIONS +{ + .buffers (NOLOAD) : + { + _buffers = .; + *(.buffers.g_cfg) + *(.buffers.g_buf) + *(.buffers*) + _ebuffers = .; + } > BUFFER + + .text : + { + _text = .; + KEEP(*(.entry*)) + KEEP(*(.text*)) + _etext = .; + } > PROGRAM + + .data : + { _data = .; + *(.rodata*) + *(.data*) + _edata = .; + } > PROGRAM + + .bss : + { + __bss_start__ = .; + _bss = .; + *(.bss*) + *(COMMON) + _ebss = .; + __bss_end__ = .; + } > PROGRAM + + .stack (NOLOAD) : + { + _stack = .; + . = . + CX32L003_FLASH_LOADER_STACK_SIZE; + *(.stack*) + _estack = .; + } > PROGRAM +} diff --git a/contrib/loaders/flash/cx32l003/cx32l003_flash_config.h b/contrib/loaders/flash/cx32l003/cx32l003_flash_config.h new file mode 100644 index 0000000000..803792290a --- /dev/null +++ b/contrib/loaders/flash/cx32l003/cx32l003_flash_config.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2021 by Nuvoton Technology Corporation + * Mulin Chao <mlc...@nuvoton.com> + * Wealian Liao <whl...@nuvoton.com> + * + * Copyright (C) 2023 Benjamin VERNOUX 31 Aug 2023 (based on cx32l003_flash.h) + */ +#ifndef OPENOCD_LOADERS_FLASH_CX32L003_CONFIG_H +#define OPENOCD_LOADERS_FLASH_CX32L003_CONFIG_H + +/* CX32L003 chip information */ +#define CX32L003_FLASH_ERASE_SIZE 512 + +/* CX32L003 flash loader information */ +#define CX32L003_FLASH_LOADER_WORKING_ADDR 0x20000000 +#define CX32L003_FLASH_LOADER_PARAMS_ADDR CX32L003_FLASH_LOADER_WORKING_ADDR +#define CX32L003_FLASH_LOADER_PARAMS_SIZE 16 +#define CX32L003_FLASH_LOADER_BUFFER_ADDR (CX32L003_FLASH_LOADER_PARAMS_ADDR + CX32L003_FLASH_LOADER_PARAMS_SIZE) +#define CX32L003_FLASH_LOADER_BUFFER_SIZE CX32L003_FLASH_ERASE_SIZE +#define CX32L003_FLASH_LOADER_PROGRAM_ADDR (CX32L003_FLASH_LOADER_BUFFER_ADDR + CX32L003_FLASH_LOADER_BUFFER_SIZE) +#define CX32L003_FLASH_LOADER_PROGRAM_SIZE 3568 + +/* Stack size in byte. 4 byte size alignment */ +#define CX32L003_FLASH_LOADER_STACK_SIZE 512 + +#endif /* OPENOCD_LOADERS_FLASH_CX32L003_CONFIG_H */ diff --git a/contrib/loaders/flash/cx32l003/entry_cx32l003.S b/contrib/loaders/flash/cx32l003/entry_cx32l003.S new file mode 100644 index 0000000000..dd3ae8408a --- /dev/null +++ b/contrib/loaders/flash/cx32l003/entry_cx32l003.S @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2023 Benjamin VERNOUX 31 Aug 2023 + */ + .syntax unified + .cpu cortex-m0plus + .thumb + + .section .entry + .weak entry + .type entry, %function +entry: + ldr r0, =_estack - 4 + mov sp, r0 /* set stack pointer */ + + bl main + +LoopForever: + b LoopForever diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 534a7a804e..3a0261d110 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -25,6 +25,7 @@ NOR_DRIVERS = \ %D%/cc3220sf.c \ %D%/cc26xx.c \ %D%/cfi.c \ + %D%/cx32l003.c \ %D%/dsp5680xx_flash.c \ %D%/efm32.c \ %D%/em357.c \ diff --git a/src/flash/nor/cx32l003.c b/src/flash/nor/cx32l003.c new file mode 100644 index 0000000000..d0937a1796 --- /dev/null +++ b/src/flash/nor/cx32l003.c @@ -0,0 +1,516 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2020 by Nuvoton Technology Corporation + * Mulin Chao <mlc...@nuvoton.com> + * Wealian Liao <whl...@nuvoton.com> + * + * Copyright (C) 2023 Benjamin VERNOUX 31 Aug 2023 (based on npcx.c) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include <helper/binarybuffer.h> +#include <helper/time_support.h> +#include <target/armv7m.h> +#include "../../../contrib/loaders/flash/cx32l003/cx32l003_flash.h" + +/* CX32L003 flash loader */ +static const uint8_t cx32l003_algo[] = { +#include "../../../contrib/loaders/flash/cx32l003/cx32l003_algo.inc" +}; + +#define CX32L003_FLASH_TIMEOUT_MS 10000 // Timeout 10s max +#define CX32L003_FLASH_BASE_ADDR 0x00000000 +#define CX32L003_FLASH_SECTOR_LENGTH (CX32L003_FLASH_ERASE_SIZE) + +/* flash list */ +enum cx32l003_flash_device_index { + CX32L003_FLASH_64KB = 0, + CX32L003_FLASH_UNKNOWN, +}; + +struct cx32l003_flash_bank { + const char *family_name; + uint32_t sector_length; + bool probed; + enum cx32l003_flash_device_index flash; + struct working_area *working_area; + struct armv7m_algorithm armv7m_info; + const uint8_t *algo_code; + uint32_t algo_size; + uint32_t algo_working_size; + uint32_t buffer_addr; + uint32_t params_addr; +}; + +struct cx32l003_flash_info { + char *name; + uint32_t id; + uint32_t size; +}; + +static const struct cx32l003_flash_info flash_info[] = { + [CX32L003_FLASH_64KB] = { + .name = "64KB Flash", + .id = 0x003203F8, + .size = 64 * 1024, + }, + [CX32L003_FLASH_UNKNOWN] = { + .name = "Unknown Flash", + .size = 0xFFFFFFFF, + }, +}; + +static int cx32l003_init(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + + /* Check for working area to use for flash helper algorithm */ + target_free_working_area(target, cx32l003_bank->working_area); + cx32l003_bank->working_area = NULL; + + int retval = target_alloc_working_area(target, cx32l003_bank->algo_working_size, + &cx32l003_bank->working_area); + if (retval != ERROR_OK) + return retval; + + /* Confirm the defined working address is the area we need to use */ + if (cx32l003_bank->working_area->address != CX32L003_FLASH_LOADER_WORKING_ADDR) { + LOG_ERROR("%s: Invalid working address", cx32l003_bank->family_name); + LOG_INFO("Hint: Use '-work-area-phys 0x%" PRIx32 "' in your target configuration", + CX32L003_FLASH_LOADER_WORKING_ADDR); + target_free_working_area(target, cx32l003_bank->working_area); + cx32l003_bank->working_area = NULL; + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + /* Write flash helper algorithm into target memory */ + retval = target_write_buffer(target, CX32L003_FLASH_LOADER_PROGRAM_ADDR, + cx32l003_bank->algo_size, cx32l003_bank->algo_code); + if (retval != ERROR_OK) { + LOG_ERROR("%s: Failed to load flash helper algorithm", + cx32l003_bank->family_name); + target_free_working_area(target, cx32l003_bank->working_area); + cx32l003_bank->working_area = NULL; + return retval; + } + + /* Initialize the ARMv7 specific info to run the algorithm */ + cx32l003_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + cx32l003_bank->armv7m_info.core_mode = ARM_MODE_THREAD; + + /* Begin executing the flash helper algorithm */ + retval = target_start_algorithm(target, 0, NULL, 0, NULL, + CX32L003_FLASH_LOADER_PROGRAM_ADDR, 0, + &cx32l003_bank->armv7m_info); + if (retval != ERROR_OK) { + LOG_ERROR("%s: Failed to start flash helper algorithm", + cx32l003_bank->family_name); + target_free_working_area(target, cx32l003_bank->working_area); + cx32l003_bank->working_area = NULL; + return retval; + } + /* + * At this point, the algorithm is running on the target and + * ready to receive commands and data to flash the target + */ + return retval; +} + +static int cx32l003_quit(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + + /* Regardless of the algo's status, attempt to halt the target */ + (void)target_halt(target); + + /* Now confirm target halted and clean up from flash helper algorithm */ + int retval = target_wait_algorithm(target, 0, NULL, 0, NULL, 0, + CX32L003_FLASH_TIMEOUT_MS, &cx32l003_bank->armv7m_info); + + target_free_working_area(target, cx32l003_bank->working_area); + cx32l003_bank->working_area = NULL; + + return retval; +} + +static int cx32l003_wait_algo_done(struct flash_bank *bank, uint32_t params_addr) +{ + struct target *target = bank->target; + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + uint32_t status_addr = params_addr + offsetof(struct cx32l003_flash_params, sync); + uint32_t status; + int64_t start_ms = timeval_ms(); + + do { + int retval = target_read_u32(target, status_addr, &status); + if (retval != ERROR_OK) + return retval; + + keep_alive(); + + int64_t elapsed_ms = timeval_ms() - start_ms; + if (elapsed_ms > CX32L003_FLASH_TIMEOUT_MS) + break; + } while (status == CX32L003_FLASH_LOADER_EXECUTE); + + if (status != CX32L003_FLASH_LOADER_WAIT) { + LOG_ERROR("%s: Flash operation failed, status=0x%" PRIx32, + cx32l003_bank->family_name, + status); + return ERROR_FAIL; + } + + return ERROR_OK; +} + +static enum cx32l003_flash_device_index cx32l003_get_flash_id(struct flash_bank *bank, uint32_t *flash_id) +{ + struct target *target = bank->target; + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + struct cx32l003_flash_params algo_params; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + int retval = cx32l003_init(bank); + if (retval != ERROR_OK) + return retval; + + /* Set up algorithm parameters for get flash ID command */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, CX32L003_FLASH_CMD_GET_FLASH_ID); + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, CX32L003_FLASH_LOADER_WAIT); + + /* Issue flash helper algorithm parameters for get flash ID */ + retval = target_write_buffer(target, cx32l003_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) { + (void)cx32l003_quit(bank); + return retval; + } + + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, CX32L003_FLASH_LOADER_EXECUTE); + retval = target_write_buffer(target, cx32l003_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + + /* If no error, wait for finishing */ + if (retval == ERROR_OK) { + retval = cx32l003_wait_algo_done(bank, cx32l003_bank->params_addr); + if (retval == ERROR_OK) + target_read_u32(target, CX32L003_FLASH_LOADER_BUFFER_ADDR, flash_id); + } + + /* Regardless of errors, try to close down algo */ + (void)cx32l003_quit(bank); + + return retval; +} + +static int cx32l003_get_flash(uint32_t flash_id) +{ + for (uint32_t i = 0; i < ARRAY_SIZE(flash_info) - 1; i++) { + if (flash_info[i].id == flash_id) + return i; + } + return CX32L003_FLASH_UNKNOWN; +} + +static int cx32l003_probe(struct flash_bank *bank) +{ + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + uint32_t sector_length = CX32L003_FLASH_ERASE_SIZE; + uint32_t flash_id; + + /* Set up appropriate flash helper algorithm */ + cx32l003_bank->algo_code = cx32l003_algo; + cx32l003_bank->algo_size = sizeof(cx32l003_algo); + cx32l003_bank->algo_working_size = CX32L003_FLASH_LOADER_PARAMS_SIZE + + CX32L003_FLASH_LOADER_BUFFER_SIZE + + CX32L003_FLASH_LOADER_PROGRAM_SIZE; + cx32l003_bank->buffer_addr = CX32L003_FLASH_LOADER_BUFFER_ADDR; + cx32l003_bank->params_addr = CX32L003_FLASH_LOADER_PARAMS_ADDR; + + int retval = cx32l003_get_flash_id(bank, &flash_id); + if (retval != ERROR_OK) + return retval; + + cx32l003_bank->flash = cx32l003_get_flash(flash_id); + if(cx32l003_bank->flash == CX32L003_FLASH_UNKNOWN) { + LOG_ERROR("cx32l003_bank->flash CX32L003_FLASH_UNKNOWN id=0x%08X bank id=%d", flash_id, cx32l003_bank->flash); + return ERROR_FAIL; + } + + unsigned int num_sectors = flash_info[cx32l003_bank->flash].size / sector_length; + LOG_INFO("cx32l003_get_flash_id size=%d bytes, sector_length=%d bytes num_sectors=%d", + flash_info[cx32l003_bank->flash].size, sector_length, num_sectors); + + bank->sectors = calloc(num_sectors, sizeof(struct flash_sector)); + if (!bank->sectors) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + bank->base = CX32L003_FLASH_BASE_ADDR; + bank->num_sectors = num_sectors; + bank->size = num_sectors * sector_length; + bank->write_start_alignment = 0; + bank->write_end_alignment = 0; + cx32l003_bank->sector_length = sector_length; + + for (unsigned int i = 0; i < num_sectors; i++) { + bank->sectors[i].offset = i * sector_length; + bank->sectors[i].size = sector_length; + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + /* We've successfully determined the stats on the flash bank */ + cx32l003_bank->probed = true; + + /* If we fall through to here, then all went well */ + return ERROR_OK; +} + +static int cx32l003_auto_probe(struct flash_bank *bank) +{ + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + int retval = ERROR_OK; + + if (!cx32l003_bank->probed) + retval = cx32l003_probe(bank); + + return retval; +} + +FLASH_BANK_COMMAND_HANDLER(cx32l003_flash_bank_command) +{ + struct cx32l003_flash_bank *cx32l003_bank; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + cx32l003_bank = calloc(1, sizeof(struct cx32l003_flash_bank)); + if (!cx32l003_bank) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + /* Initialize private flash information */ + cx32l003_bank->family_name = "cx32l003"; + cx32l003_bank->sector_length = CX32L003_FLASH_ERASE_SIZE; + + /* Finish initialization of bank */ + bank->driver_priv = cx32l003_bank; + bank->next = NULL; + + return ERROR_OK; +} + +static int cx32l003_chip_erase(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + struct cx32l003_flash_params algo_params; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Make sure we've probed the flash to get the device and size */ + int retval = cx32l003_auto_probe(bank); + if (retval != ERROR_OK) + return retval; + + retval = cx32l003_init(bank); + if (retval != ERROR_OK) + return retval; + + /* Set up algorithm parameters for chip erase command */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, CX32L003_FLASH_CMD_ERASE_ALL); + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, CX32L003_FLASH_LOADER_WAIT); + + /* Set algorithm parameters */ + retval = target_write_buffer(target, cx32l003_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) { + (void)cx32l003_quit(bank); + return retval; + } + + /* Issue flash helper algorithm parameters for chip erase */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, CX32L003_FLASH_LOADER_EXECUTE); + retval = target_write_buffer(target, cx32l003_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + + /* If no error, wait for chip erase finish */ + if (retval == ERROR_OK) + retval = cx32l003_wait_algo_done(bank, cx32l003_bank->params_addr); + + /* Regardless of errors, try to close down algo */ + (void)cx32l003_quit(bank); + + return retval; +} + +static int cx32l003_erase(struct flash_bank *bank, unsigned int first, + unsigned int last) +{ + struct target *target = bank->target; + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + struct cx32l003_flash_params algo_params; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if ((first == 0) && (last == (bank->num_sectors - 1))) { + /* Request chip erase */ + return cx32l003_chip_erase(bank); + } + + uint32_t address = first * cx32l003_bank->sector_length; + uint32_t length = (last - first + 1) * cx32l003_bank->sector_length; + + /* Make sure we've probed the flash to get the device and size */ + int retval = cx32l003_auto_probe(bank); + if (retval != ERROR_OK) + return retval; + + retval = cx32l003_init(bank); + if (retval != ERROR_OK) + return retval; + + /* Set up algorithm parameters for erase command */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address); + target_buffer_set_u32(target, (uint8_t *)&algo_params.len, length); + target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, CX32L003_FLASH_CMD_ERASE_SECTORS); + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, CX32L003_FLASH_LOADER_WAIT); + + /* Set algorithm parameters */ + retval = target_write_buffer(target, cx32l003_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) { + (void)cx32l003_quit(bank); + return retval; + } + + /* Issue flash helper algorithm parameters for erase */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, CX32L003_FLASH_LOADER_EXECUTE); + retval = target_write_buffer(target, cx32l003_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + + /* If no error, wait for erase to finish */ + if (retval == ERROR_OK) + retval = cx32l003_wait_algo_done(bank, cx32l003_bank->params_addr); + + /* Regardless of errors, try to close down algo */ + (void)cx32l003_quit(bank); + + return retval; +} + +static int cx32l003_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + struct cx32l003_flash_params algo_params; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* Make sure we've probed the flash to get the device and size */ + int retval = cx32l003_auto_probe(bank); + if (retval != ERROR_OK) + return retval; + + retval = cx32l003_init(bank); + if (retval != ERROR_OK) + return retval; + + /* Initialize algorithm parameters to default values */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.cmd, CX32L003_FLASH_CMD_PROGRAM); + + uint32_t address = offset; + + while (count > 0) { + uint32_t size = (count > CX32L003_FLASH_LOADER_BUFFER_SIZE) ? + CX32L003_FLASH_LOADER_BUFFER_SIZE : count; + + /* Put the data into buffer */ + retval = target_write_buffer(target, cx32l003_bank->buffer_addr, + size, buffer); + if (retval != ERROR_OK) { + LOG_ERROR("Unable to write data to target memory"); + break; + } + + /* Update algo parameters for flash write */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.addr, address); + target_buffer_set_u32(target, (uint8_t *)&algo_params.len, size); + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, CX32L003_FLASH_LOADER_WAIT); + + /* Set algorithm parameters */ + retval = target_write_buffer(target, cx32l003_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) + break; + + /* Issue flash helper algorithm parameters for flash write */ + target_buffer_set_u32(target, (uint8_t *)&algo_params.sync, CX32L003_FLASH_LOADER_EXECUTE); + retval = target_write_buffer(target, cx32l003_bank->params_addr, + sizeof(algo_params), (uint8_t *)&algo_params); + if (retval != ERROR_OK) + break; + + /* Wait for flash write finish */ + retval = cx32l003_wait_algo_done(bank, cx32l003_bank->params_addr); + if (retval != ERROR_OK) + break; + + count -= size; + buffer += size; + address += size; + } + + /* Regardless of errors, try to close down algo */ + (void)cx32l003_quit(bank); + + return retval; +} + +static int cx32l003_info(struct flash_bank *bank, struct command_invocation *cmd) +{ + struct cx32l003_flash_bank *cx32l003_bank = bank->driver_priv; + + command_print_sameline(cmd, "%s flash: %s\n", + cx32l003_bank->family_name, + flash_info[cx32l003_bank->flash].name); + + return ERROR_OK; +} + +const struct flash_driver cx32l003_flash = { + .name = "cx32l003", + .flash_bank_command = cx32l003_flash_bank_command, + .erase = cx32l003_erase, + .write = cx32l003_write, + .read = default_flash_read, + .probe = cx32l003_probe, + .auto_probe = cx32l003_auto_probe, + .erase_check = default_flash_blank_check, + .info = cx32l003_info, + .free_driver_priv = default_flash_free_driver_priv, +}; diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h index a63b72c8fa..22b76b019e 100644 --- a/src/flash/nor/driver.h +++ b/src/flash/nor/driver.h @@ -253,6 +253,7 @@ extern const struct flash_driver bluenrgx_flash; extern const struct flash_driver cc26xx_flash; extern const struct flash_driver cc3220sf_flash; extern const struct flash_driver cfi_flash; +extern const struct flash_driver cx32l003_flash; extern const struct flash_driver dsp5680xx_flash; extern const struct flash_driver efm32_flash; extern const struct flash_driver em357_flash; diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 3157bd3292..963c346379 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -30,6 +30,7 @@ static const struct flash_driver * const flash_drivers[] = { &cc3220sf_flash, &cc26xx_flash, &cfi_flash, + &cx32l003_flash, &dsp5680xx_flash, &efm32_flash, &em357_flash, diff --git a/tcl/target/cx32l003.cfg b/tcl/target/cx32l003.cfg new file mode 100644 index 0000000000..a061e389a0 --- /dev/null +++ b/tcl/target/cx32l003.cfg @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +# Based on stm32c0x.cfg +# script for CX32L003 family tested only with CX32L003F8 B.VERNOUX 31 Aug 2023 +# +# cx32l003 devices support SWD transports only. +# + +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME cx32l003 +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 4kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x1000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + # SWD IDCODE (single drop, arm) + set _CPUTAPID 0x0bc11477 +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID +dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap $_CHIPNAME.dap + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +flash bank $_CHIPNAME.flash cx32l003 0x00000000 0 0 0 $_TARGETNAME + +# CX32L003F8 based on ARM® Cortex®-M0+ / ARM® v6-M Architecture +# Mapping CX32L003F8 +# Name AdrSpace StartAdr EndAdr AccType +# Flash Memory 0x00000000 0x0000FFFF R +# ROM Memory 0x1FFFC800 0x1FFFFFFF R +# RAM Memory 0x20000000 0x20000FFF RW +# PeriphAPB Memory 0x40000000 0x40010000 W +# PeriphAHB Memory 0x40020000 0x40030000 W +# SystemSFR Memory 0xE0000000 0xE00FFFFF W + +# reasonable default +adapter speed 2000 + +adapter srst delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +#reset_config srst_nogate +reset_config trst_and_srst + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq + echo "sysresetreq ..." +} + +$_TARGETNAME configure -event examine-end { + # RCC_UNLOCK UNLOCK + mww 0x40020060 0x55AA6699 + # Enable RCC_PCLKEN |= DBGCKEN(bit20) | SYSCONCKEN(bit7) + mmw 0x4002000C 0x00100080 0 + + # SYSCON_UNLOCK UNLOCK + mww 0x40001C50 0x55AA6699 + # SYSCON_CFGR0 |= KEY(0x5A690000) | DBGDLSP_DIS(bit1) + mmw 0x40001C00 0x5A690002 0 + + # Stop watchdog counters during halt + # DBG_APBFZ |= KEY(0x5A690000) | WWDGDBGSTOP(bit10) | IWDGDBGSTOP(bit9) + mmw 0x40004C00 0x5A690600 0 + echo "Disabling watchdog..." +} --