From 0fca7d2e8f668fb0ca79757eb7f94f985158774f Mon Sep 17 00:00:00 2001 From: Felipe Guedes Date: Sun, 31 Jan 2021 23:00:29 +0000 Subject: [PATCH] Added SmartEEPROM Support --- mdloader_common.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++ mdloader_common.h | 62 ++++++++++++++++++- 2 files changed, 213 insertions(+), 1 deletion(-) diff --git a/mdloader_common.c b/mdloader_common.c index e3cd2f1..7f5ddf0 100644 --- a/mdloader_common.c +++ b/mdloader_common.c @@ -31,6 +31,7 @@ char first_device; int restart_after_program; int hex_cols; int hex_colw; +int force_smarteeprom_config; //SAM-BA Settings mailbox_t initparams; @@ -382,6 +383,137 @@ int test_mcu(char silent) return 1; } +// SmartEEPROM NVMCTRL section +int write_user_row(uint32_t* data) +{ + //Read the current state of NVMCTRL.CTRLA + NVMCTRL_CTRLA_Type ctrla; + ctrla.reg = read_half_word(NVMCTRL_CTRLA); + + if (verbose) + { + printf("NVMCTRL.CTRLA: 0x%04x\n\tAUTOWS: 0x%01x\n\tSUSPEN: 0x%01x\n\tWMODE: 0x%02x\n\tPRM: 0x%02x\n\tRWS: 0x%04x\n\tAHBNS0: 0x%01x\n\tAHBNS1: 0x%01x\n\tCACHEDIS0: 0x%01x\n\tCACHEDIS1: 0x%01x\n", ctrla.reg, ctrla.bit.AUTOWS, ctrla.bit.SUSPEN, ctrla.bit.WMODE, ctrla.bit.PRM, ctrla.bit.RWS, ctrla.bit.AHBNS0, ctrla.bit.AHBNS1, ctrla.bit.CACHEDIS0, ctrla.bit.CACHEDIS1); + } + + printf("Configuring SmartEEPROM... "); + + //Set WMODE to Manual + ctrla.bit.WMODE = NVMCTRL_CTRLA_WMODE_MAN; + if (!write_half_word(NVMCTRL_CTRLA, ctrla.reg)) + { + printf("Error setting NVMCTRL.CTRLA.WMODE to Manual.\n"); + return 0; + } + slp(SLEEP_BETWEEN_WRITES); + + // Set user row address + if (!write_word(NVMCTRL_ADDR, NVMCTRL_USER)) + { + printf("Error setting NVMCTRL_ADDR to NVMCTRL_USER (1).\n"); + return 0; + } + + // Erase page + NVMCTRL_CTRLB_Type ctrlb; + ctrlb.reg = 0; + ctrlb.bit.CMD = NVMCTRL_CTRLB_CMD_EP; + ctrlb.bit.CMDEX = NVMCTRL_CTRLB_CMDEX_KEY; + if (!write_half_word(NVMCTRL_CTRLB, ctrlb.reg)) + { + printf("Error setting NVMCTRL_CTRLB to 0x%04x (Erase page).\n", ctrlb.reg); + return 0; + } + slp(SLEEP_BETWEEN_WRITES); + + // Page buffer clear + ctrlb.reg = 0; + ctrlb.bit.CMD = NVMCTRL_CTRLB_CMD_PBC; + ctrlb.bit.CMDEX = NVMCTRL_CTRLB_CMDEX_KEY; + if (!write_half_word(NVMCTRL_CTRLB, ctrlb.reg)) + { + printf("Error setting NVMCTRL_CTRLB to 0x%04x (Page buffer clear).\n", ctrlb.reg); + return 0; + } + slp(SLEEP_BETWEEN_WRITES); + + // Write in the write buffer + for (int i = 0; i < 4; i++) + { + if (!write_word(NVMCTRL_USER + i * 4, data[i])) + { + printf("Error: Unable to write NVMCTRL_USER page %i.\n", i); + return 0; + } + slp(SLEEP_BETWEEN_WRITES); + } + + if (!write_word(NVMCTRL_ADDR, NVMCTRL_USER)) + { + printf("Error setting NVMCTRL_ADDR to NVMCTRL_USER (2).\n"); + return 0; + } + slp(SLEEP_BETWEEN_WRITES); + + // Write quad word (128bits) + ctrlb.reg = 0; + ctrlb.bit.CMD = NVMCTRL_CTRLB_CMD_WQW; + ctrlb.bit.CMDEX = NVMCTRL_CTRLB_CMDEX_KEY; + if (!write_half_word(NVMCTRL_CTRLB, ctrlb.reg)) + { + printf("Error setting NVMCTRL_CTRLB to 0x%04x (Write Quad Word).\n", ctrlb.reg); + return 0; + } + + printf("Success!\n"); + return 1; +} + +void configure_smarteeprom(void) +{ + uint32_t user_row[4]; + for (int i = 0; i < 4; i++) + { + user_row[i] = read_word(NVMCTRL_USER + i * 4); + } + + if (verbose) + { + printf("user row: "); + for (int i = 0; i < 4; i++) + { + printf("0x%08x ", user_row[i]); + } + printf("\n"); + } + + + NVMCTRL_USER_ROW_MAPPING1_Type* puser_row1 = (NVMCTRL_USER_ROW_MAPPING1_Type*)(&user_row[1]); + + // Check current status and proceed accordingly. + if (puser_row1->bit.SBLK == 0 && puser_row1->bit.PSZ == 0) + { + printf("SmartEEPROM not configured, proceed.\n"); + } + else + { + printf("SmartEEPROM is already configured - SBLK: 0x%04x - PSZ: 0x%03x.\n", puser_row1->bit.SBLK, puser_row1->bit.PSZ); + if (force_smarteeprom_config) + { + printf("--forceeep enabled, reconfiguring SmartEEPROM.\n"); + } + else + { + printf("Use --forceeep to force SmartEEPROM reconfiguration.\n"); + return; + } + } + + // Set SmartEEPROM Virtual Size to 1024 bytes. Specs in DS60001507E, page 653. + puser_row1->bit.SBLK = 0x1; // 1 block + puser_row1->bit.PSZ = 0x1; // 8 bytes + write_user_row(user_row); +} + //Upper case any lower case characters in a string void strlower(char *str) { @@ -495,6 +627,8 @@ void display_help(void) printf(" -s --size size Read firmware size of \n"); printf(" -D --download file Write firmware from into device\n"); printf(" -t --test Test mode (download/upload writes disabled, upload outputs data to stdout, restart disabled)\n"); + printf(" --smarteep Enable Smart EEPROM MCU feature\n"); + printf(" --forceeep Force re-configuration of Smart EEPROM MCU feature. Requires --smarteep.\n"); printf(" --cols count Hex listing column count [%i]\n", COLS); printf(" --colw width Hex listing column width [%i]\n", COLW); printf(" --restart Restart device after successful programming\n"); @@ -503,11 +637,13 @@ void display_help(void) #define SW_COLS 1000 #define SW_COLW 1001 +#define SW_SMARTEEP 1002 //Program command line options struct option long_options[] = { //Flags { "restart", no_argument, &restart_after_program, 1 }, + { "forceeep", no_argument, &force_smarteeprom_config, 1 }, //Other { "verbose", no_argument, 0, 'v' }, { "help", no_argument, 0, 'h' }, @@ -520,6 +656,7 @@ struct option long_options[] = { { "addr", required_argument, 0, 'a' }, { "size", required_argument, 0, 's' }, { "test", no_argument, 0, 't' }, + { "smarteep", no_argument, 0, SW_SMARTEEP }, { "cols", required_argument, 0, SW_COLS }, { "colw", required_argument, 0, SW_COLW }, { 0, 0, 0, 0 } @@ -533,6 +670,7 @@ int main(int argc, char *argv[]) restart_after_program = 0; hex_cols = COLS; hex_colw = COLW; + force_smarteeprom_config = 0; display_version(); display_copyright(); @@ -633,6 +771,10 @@ int main(int argc, char *argv[]) testmode = 1; break; + case SW_SMARTEEP: + command = CMD_CONFIG_SMARTEEPROM; + break; + case SW_COLS: hex_cols = atoi(optarg); if (hex_cols < 1) @@ -754,7 +896,17 @@ int main(int argc, char *argv[]) printf("Found MCU: %s\n", mcu->name); print_bootloader_version(); + if (verbose) printf("Device ID: %08X\n", mcu->cidr); + if (command == CMD_CONFIG_SMARTEEPROM) + { + configure_smarteeprom(); + + if (restart_after_program) + jump_application(); + + goto exitProgram; + } memcpy(&appinfo, applet_data + applet_size - sizeof(appinfo_t), sizeof(appinfo_t)); diff --git a/mdloader_common.h b/mdloader_common.h index 0bd8575..c264682 100644 --- a/mdloader_common.h +++ b/mdloader_common.h @@ -144,7 +144,8 @@ enum command { CMD_DOWNLOAD, CMD_UPLOAD, CMD_TEST, - CMD_ABORT + CMD_ABORT, + CMD_CONFIG_SMARTEEPROM }; extern struct option long_options[]; @@ -183,6 +184,65 @@ int write_data(int addr, int writesize, int data); void list_devices(char *first); void strupper(char *str); void strlower(char *str); +void configure_smarteeprom(void); + +// Smart EEPROM specific +#define NVMCTRL 0x41004000 +#define NVMCTRL_CTRLA (NVMCTRL) +#define NVMCTRL_CTRLB (NVMCTRL + 4) +#define NVMCTRL_ADDR (NVMCTRL + 0x14) + +#define NVMCTRL_CTRLA_WMODE_MAN 0x0 +#define NVMCTRL_CTRLB_CMDEX_KEY 0xA5 +#define NVMCTRL_CTRLB_CMD_WQW 0x4 +#define NVMCTRL_CTRLB_CMD_PBC 0x15 +#define NVMCTRL_CTRLB_CMD_EP 0x0 + +#define NVMCTRL_USER 0x00804000 + +#define SLEEP_BETWEEN_WRITES 200 + +typedef union { + struct { + uint32_t SBLK : 4; /* bit: 35:32 - Number of NVM Blocks composing a SmartEEPROM sector */ + uint32_t PSZ : 3; /* bit: 38:36 - SmartEEPROM Page Size */ + uint32_t RAM_ECCDIS : 1; /* bit: 39 - RAM ECC Disable */ + uint32_t : 8; /* bit: 47:40 - Factory settings - do not change */ + uint32_t WDT_ENABLE : 1; /* bit: 48 - WDT Enable at power-on */ + uint32_t WDT_ALWAYS_ON : 1; /* bit: 49 - WDT Always-On at power-on */ + uint32_t WDT_PERIOD : 4; /* bit: 53:50 - WDT Period at power-on */ + uint32_t WDT_WINDOW : 4; /* bit: 57:54 - WDT Window mode time-out at power - on */ + uint32_t WDT_EWOFFSET : 4; /* bit: 61:58 - WDT Early Warning Interrupt Time Offset at power - on */ + uint32_t WDT_WEN : 1; /* bit: 62 - WDT Window Mode Enable at power - on */ + uint32_t : 1; /* bit: 63 - Factory settings - do not change */ + } bit; + uint32_t reg; +} NVMCTRL_USER_ROW_MAPPING1_Type; + +typedef union { + struct { + uint16_t : 2; /* bit: 1:0 Reserved */ + uint16_t AUTOWS : 1; /* bit: 2 Auto Wait State Enable */ + uint16_t SUSPEN : 1; /* bit: 3 Suspend Enable */ + uint16_t WMODE : 2; /* bit: 5:4 Write Mode */ + uint16_t PRM : 2; /* bit: 7:6 Power Reduction Mode during Sleep */ + uint16_t RWS : 4; /* bit: 11:8 NVM Read Wait States */ + uint16_t AHBNS0 : 1; /* bit: 12 Force AHB0 access to NONSEQ, burst transfers are continuously rearbitrated */ + uint16_t AHBNS1 : 1; /* bit: 13 Force AHB1 access to NONSEQ, burst transfers are continuously rearbitrated */ + uint16_t CACHEDIS0 : 1; /* bit: 14 AHB0 Cache Disable */ + uint16_t CACHEDIS1 : 1; /* bit: 15 AHB1 Cache Disable */ + } bit; + uint16_t reg; +} NVMCTRL_CTRLA_Type; + +typedef union { + struct { + uint16_t CMD : 7; /* bit: 6:0 Command */ + uint16_t : 1; /* bit: 7 Reserved */ + uint16_t CMDEX : 8; /* bit: 15:8 Command Execution */ + } bit; + uint16_t reg; +} NVMCTRL_CTRLB_Type; #endif //_MDLOADER_COMMON_H