From 2ca5952fc295c873e408dd5b7bb7cce9823c11c5 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 10 Aug 2023 11:53:54 -0700 Subject: [PATCH] imxrt: Detect iMX RT variant and adjust FLEXSPI base address --- src/target/imxrt.c | 177 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 151 insertions(+), 26 deletions(-) diff --git a/src/target/imxrt.c b/src/target/imxrt.c index e17c933c35a..b68e007f859 100644 --- a/src/target/imxrt.c +++ b/src/target/imxrt.c @@ -31,7 +31,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include "general.h" #include "target.h" #include "target_internal.h" @@ -59,21 +58,57 @@ #define IMXRT_MPU_BASE UINT32_C(0xe000ed90) #define IMXRT_MPU_CTRL (IMXRT_MPU_BASE + 0x04U) -#define IMXRT_CCM_ANALOG_BASE UINT32_C(0x400d8000) -#define IMXRT_CCM_ANALOG_PLL3_PFD (IMXRT_CCM_ANALOG_BASE + 0x0f0U) +#define IMXRT_10XX_CCM_ANALOG_BASE UINT32_C(0x400d8000) +#define IMXRT_10XX_CCM_ANALOG_PLL3_PFD (IMXRT_10XX_CCM_ANALOG_BASE + 0x0f0U) -#define IMXRT_CCM_ANALOG_PLL_PFD0_FRAC_MASK 0xffffffc0 +#define IMXRT_10XX_CCM_ANALOG_PLL_PFD0_FRAC_MASK 0xffffffc0 -#define IMXRT_CCM_BASE UINT32_C(0x400fc000) -#define IMXRT_CCM_CSCM1 (IMXRT_CCM_BASE + 0x01cU) -#define IMXRT_CCM_CCG6 (IMXRT_CCM_BASE + 0x080U) +#define IMXRT_10XX_CCM_BASE UINT32_C(0x400fc000) +#define IMXRT_10XX_CCM_CSCM1 (IMXRT_10XX_CCM_BASE + 0x01cU) +#define IMXRT_10XX_CCM_CCG6 (IMXRT_10XX_CCM_BASE + 0x080U) -#define IMXRT_CCM_CSCM1_FLEXSPI_CLK_SEL_MASK 0xfc7fffffU -#define IMXRT_CCM_CSCM1_FLEXSPI_CLK_SEL_PLL3_PFD0 0x03800000U -#define IMXRT_CCM_CCG6_FLEXSPI_CLK_MASK 0xfffff3ffU -#define IMXRT_CCM_CCG6_FLEXSPI_CLK_ENABLE 0x00000c00U +#define IMXRT_10XX_CCM_CSCM1_FLEXSPI_CLK_SEL_MASK 0xfc7fffffU +#define IMXRT_10XX_CCM_CSCM1_FLEXSPI_CLK_SEL_PLL3_PFD0 0x03800000U +#define IMXRT_10XX_CCM_CCG6_FLEXSPI_CLK_MASK 0xfffff3ffU +#define IMXRT_10XX_CCM_CCG6_FLEXSPI_CLK_ENABLE 0x00000c00U + +#define IMXRT_11XX_CCM_BASE UINT32_C(0x40cc0000) +#define IMXRT_11XX_CCM_CLOCK_ROOT20_CONTROL (IMXRT_11XX_CCM_BASE + 0x0 + (20 * 0x80)) +#define IMXRT_11XX_CCM_CLOCK_ROOT20_CONTROL_PLL_480M (0x7 << 8) +#define IMXRT_11XX_CCM_CLOCK_ROOT20_CONTROL_OSC400M (0x2 << 8) +#define IMXRT_11XX_CCM_CLOCK_ROOT20_CONTROL_DIV(divisor) ((divisor - 1) << 0) +#define IMXRT_11XX_CCM_LPCG28 (IMXRT_11XX_CCM_BASE + 0x6000 + (28 * 0x20)) + +#define IMXRT_FP_FLAG UINT32_C(0x0000fffc) +#define IMXRT_11XX_FP_FLAG UINT32_C(0x5aa60ff0) + +#define IMXRT_X00_ROM_FINGERPRINT_ADDR 0x0301a000u +#define IMXRT_10XX_ROM_FINGERPRINT_ADDR 0x0020a000u +#define IMXRT_11XX_ROM_FINGERPRINT_ADDR 0x0021a000u + +#define IMXRT_5XX_ROM_FINGERPRINT UINT32_C(0x669ff643) +#define IMXRT_6XX_ROM_FINGERPRINT UINT32_C(0xf2406510) + +#define IMXRT_1011_ROM_FINGERPRINT UINT32_C(0xf88d10c9) +#define IMXRT_102X_ROM_FINGERPRINT UINT32_C(0xe9dd9a03) +#define IMXRT_105X_ROM_FINGERPRINT UINT32_C(0x2101eb10) +#define IMXRT_106X_ROM_FINGERPRINT UINT32_C(0x80dbf000) + +#define IMXRT_117X_ROM_FINGERPRINT UINT32_C(0x9909a810) + +#define IMXRT_5XX_FLEXSPI1_BASE UINT32_C(0x4013c000) +#define IMXRT_6XX_FLEXSPI1_BASE UINT32_C(0x40134000) +#define IMXRT_1011_FLEXSPI1_BASE UINT32_C(0x400a0000) +#define IMXRT_102X_FLEXSPI1_BASE UINT32_C(0x402a8000) +#define IMXRT_104X_FLEXSPI1_BASE UINT32_C(0x402a8000) +#define IMXRT_105X_FLEXSPI1_BASE UINT32_C(0x402a8000) +#define IMXRT_106X_FLEXSPI1_BASE UINT32_C(0x402a8000) +#define IMXRT_116X_FLEXSPI1_BASE UINT32_C(0x400cc000) +#define IMXRT_117X_FLEXSPI1_BASE UINT32_C(0x400cc000) + +/* The root address varies across the 10xx line. We store it on target info. */ +#define IMXRT_FLEXSPI1_BASE priv->flexspi_root -#define IMXRT_FLEXSPI1_BASE UINT32_C(0x402a8000) /* We only carry definitions for FlexSPI1 Flash controller A1. */ #define IMXRT_FLEXSPI1_MOD_CTRL0 (IMXRT_FLEXSPI1_BASE + 0x000U) #define IMXRT_FLEXSPI1_INT (IMXRT_FLEXSPI1_BASE + 0x014U) @@ -140,10 +175,14 @@ typedef struct imxrt_flexspi_lut_insn { typedef struct imxrt_priv { imxrt_boot_src_e boot_source; + uint16_t chip_id; + uint32_t flexspi_root; uint32_t mpu_state; uint32_t flexspi_lut_state; uint16_t flexspi_cached_commands[4]; imxrt_flexspi_lut_insn_s flexspi_prg_seq_state[4][8]; + bool flash_in_package; + char variant_string[16]; } imxrt_priv_s; static imxrt_boot_src_e imxrt_boot_source(uint32_t boot_cfg); @@ -154,14 +193,14 @@ static void imxrt_spi_read(target_s *target, uint16_t command, target_addr_t add static void imxrt_spi_write( target_s *target, uint16_t command, target_addr_t address, const void *buffer, size_t length); static void imxrt_spi_run_command(target_s *target, uint16_t command, target_addr_t address); +static void imxrt_id_chip(target_s *target, imxrt_priv_s *priv); bool imxrt_probe(target_s *const target) { /* If the part number fails to match, instantly return. */ - if (target->part_id != 0x88cU) + if (target->part_id != 0x88cU && target->part_id != 0x88c6U) { return false; - - /* XXX: Would really like to find some way to have a more positive identification on the part */ + } imxrt_priv_s *priv = calloc(1, sizeof(imxrt_priv_s)); if (!priv) { /* calloc faled: heap exhaustion */ @@ -170,7 +209,11 @@ bool imxrt_probe(target_s *const target) } target->target_storage = priv; target->target_options |= CORTEXM_TOPT_INHIBIT_NRST; - target->driver = "i.MXRT10xx"; + + imxrt_id_chip(target, priv); + + snprintf(priv->variant_string, sizeof(priv->variant_string), "i.MXRT%d", priv->chip_id); + target->driver = priv->variant_string; #if defined(ENABLE_DEBUG) && (PC_HOSTED == 1 || defined(ESP_LOGD)) const uint8_t boot_mode = (target_mem_read32(target, IMXRT_SRC_BOOT_MODE2) >> 24U) & 3U; @@ -227,6 +270,68 @@ bool imxrt_probe(target_s *const target) return true; } +static void imxrt_id_chip(target_s *target, imxrt_priv_s *priv) +{ + // The iMX RT series doesn't have a device id register. Instead, the NXP universal flash loader + // uses known ROM values at a particular address to differentiate the devices. That code uses + // three locations but only one location is actually needed. + // https://github.com/nxp-mcuxpresso/i.mxrt-ufl/blob/main/src/ufl_find_target.c + uint32_t rom_location = 0; + const uint16_t cpuid_partno = target->cpuid & CPUID_PARTNO_MASK; + if (cpuid_partno == CORTEX_M33) + rom_location = IMXRT_X00_ROM_FINGERPRINT_ADDR; + else if (cpuid_partno == CORTEX_M7) + if (target->part_id == 0x88c6U) + rom_location = IMXRT_11XX_ROM_FINGERPRINT_ADDR; + else + rom_location = IMXRT_10XX_ROM_FINGERPRINT_ADDR; + else + DEBUG_ERROR("Unknown core %04x\n", cpuid_partno); + + uint32_t fingerprint = target_mem_read32(target, rom_location); + switch (fingerprint) { + case IMXRT_5XX_ROM_FINGERPRINT: + priv->chip_id = 500; + priv->flexspi_root = IMXRT_5XX_FLEXSPI1_BASE; + break; + case IMXRT_6XX_ROM_FINGERPRINT: + priv->chip_id = 600; + priv->flexspi_root = IMXRT_6XX_FLEXSPI1_BASE; + break; + + case IMXRT_1011_ROM_FINGERPRINT: + priv->chip_id = 1011; + priv->flexspi_root = IMXRT_1011_FLEXSPI1_BASE; + break; + case IMXRT_102X_ROM_FINGERPRINT: + // The 1015 is actually a 1021. + priv->chip_id = 1021; + priv->flexspi_root = IMXRT_102X_FLEXSPI1_BASE; + break; + case IMXRT_105X_ROM_FINGERPRINT: + priv->chip_id = 1052; + priv->flexspi_root = IMXRT_105X_FLEXSPI1_BASE; + break; + case IMXRT_106X_ROM_FINGERPRINT: + // The 1042 is actually a 1062. + priv->chip_id = 1062; + priv->flexspi_root = IMXRT_106X_FLEXSPI1_BASE; + break; + + case IMXRT_117X_ROM_FINGERPRINT: + priv->chip_id = 1176; + priv->flexspi_root = IMXRT_117X_FLEXSPI1_BASE; + break; + default: + DEBUG_TARGET("Unknown ROM fingerprint at %08x = %08x\n", rom_location, fingerprint); + break; + } + + DEBUG_TARGET("Chip id: %d\n", priv->chip_id); + + // TODO: Check for in package flash. +} + static imxrt_boot_src_e imxrt_boot_source(const uint32_t boot_cfg) { /* @@ -258,15 +363,32 @@ static bool imxrt_enter_flash_mode(target_s *const target) /* Start by stepping the clocks to ~50MHz and putting the controller in a known state */ target_mem_write32(target, IMXRT_FLEXSPI1_MOD_CTRL0, target_mem_read32(target, IMXRT_FLEXSPI1_MOD_CTRL0) | IMXRT_FLEXSPI1_MOD_CTRL0_SUSPEND); - target_mem_write32( - target, IMXRT_CCM_CCG6, target_mem_read32(target, IMXRT_CCM_CCG6) & IMXRT_CCM_CCG6_FLEXSPI_CLK_MASK); - target_mem_write32(target, IMXRT_CCM_CSCM1, - (target_mem_read32(target, IMXRT_CCM_CSCM1) & IMXRT_CCM_CSCM1_FLEXSPI_CLK_SEL_MASK) | - IMXRT_CCM_CSCM1_FLEXSPI_CLK_SEL_PLL3_PFD0); - target_mem_write32(target, IMXRT_CCM_ANALOG_PLL3_PFD, - (target_mem_read32(target, IMXRT_CCM_ANALOG_PLL3_PFD) & IMXRT_CCM_ANALOG_PLL_PFD0_FRAC_MASK) | 0x16U); - target_mem_write32( - target, IMXRT_CCM_CCG6, target_mem_read32(target, IMXRT_CCM_CCG6) | IMXRT_CCM_CCG6_FLEXSPI_CLK_ENABLE); + if (1000 <= priv->chip_id && priv->chip_id < 1100) { + // Gate the clock to FLEXSPI while we change it. + target_mem_write32(target, IMXRT_10XX_CCM_CCG6, + target_mem_read32(target, IMXRT_10XX_CCM_CCG6) & IMXRT_10XX_CCM_CCG6_FLEXSPI_CLK_MASK); + + target_mem_write32(target, IMXRT_10XX_CCM_CSCM1, + (target_mem_read32(target, IMXRT_10XX_CCM_CSCM1) & IMXRT_10XX_CCM_CSCM1_FLEXSPI_CLK_SEL_MASK) | + IMXRT_10XX_CCM_CSCM1_FLEXSPI_CLK_SEL_PLL3_PFD0); + // PLL3 is 480 mhz and PFD0 is set to 0x16 which is 480 * (18 / 0x16) = 392 which is then divided by 2. + target_mem_write32(target, IMXRT_10XX_CCM_ANALOG_PLL3_PFD, + (target_mem_read32(target, IMXRT_10XX_CCM_ANALOG_PLL3_PFD) & IMXRT_10XX_CCM_ANALOG_PLL_PFD0_FRAC_MASK) | + 0x16U); + + // Ungate the clock. + target_mem_write32(target, IMXRT_10XX_CCM_CCG6, + target_mem_read32(target, IMXRT_10XX_CCM_CCG6) | IMXRT_10XX_CCM_CCG6_FLEXSPI_CLK_ENABLE); + } else if (1100 <= priv->chip_id && priv->chip_id < 1200) { + // Gate the clock to FLEXSPI1 while we change it. + target_mem_write32(target, IMXRT_11XX_CCM_LPCG28, 0); + // PLL3 480 Mhz / 4 -> 120 Mhz + target_mem_read32(target, IMXRT_11XX_CCM_CLOCK_ROOT20_CONTROL); + target_mem_write32(target, IMXRT_11XX_CCM_CLOCK_ROOT20_CONTROL, + IMXRT_11XX_CCM_CLOCK_ROOT20_CONTROL_PLL_480M | IMXRT_11XX_CCM_CLOCK_ROOT20_CONTROL_DIV(4)); + // Ungate the clock. + target_mem_write32(target, IMXRT_11XX_CCM_LPCG28, 1); + } target_mem_write32(target, IMXRT_FLEXSPI1_MOD_CTRL0, target_mem_read32(target, IMXRT_FLEXSPI1_MOD_CTRL0) & ~IMXRT_FLEXSPI1_MOD_CTRL0_SUSPEND); /* Clear all outstanding interrupts so we can consume their status cleanly */ @@ -351,7 +473,7 @@ static uint8_t imxrt_spi_build_insn_sequence(target_s *const target, const uint1 sequence[offset++].value = 0; } /* Because sequence gets 0 initalised above when it's declared, the STOP entry is already present */ - DEBUG_TARGET("Writing new instruction seqeunce to slot %u\n", slot); + DEBUG_TARGET("Writing new instruction sequence to slot %u\n", slot); for (size_t idx = 0; idx < 8U; ++idx) DEBUG_TARGET("%zu: %02x %02x\n", idx, sequence[idx].opcode_mode, sequence[idx].value); @@ -379,6 +501,7 @@ static void imxrt_spi_exec_sequence( static void imxrt_spi_wait_complete(target_s *const target) { + const imxrt_priv_s *const priv = (imxrt_priv_s *)target->target_storage; /* Wait till it finishes */ while (!(target_mem_read32(target, IMXRT_FLEXSPI1_INT) & IMXRT_FLEXSPI1_INT_PRG_CMD_DONE)) continue; @@ -404,6 +527,7 @@ static void imxrt_spi_wait_complete(target_s *const target) static void imxrt_spi_read(target_s *const target, const uint16_t command, const target_addr_t address, void *const buffer, const size_t length) { + const imxrt_priv_s *const priv = (imxrt_priv_s *)target->target_storage; /* Configure the programmable sequence LUT and execute the read */ const uint8_t slot = imxrt_spi_build_insn_sequence(target, command, length); imxrt_spi_exec_sequence(target, slot, address, length); @@ -418,6 +542,7 @@ static void imxrt_spi_read(target_s *const target, const uint16_t command, const static void imxrt_spi_write(target_s *const target, const uint16_t command, const target_addr_t address, const void *const buffer, const size_t length) { + const imxrt_priv_s *const priv = (imxrt_priv_s *)target->target_storage; /* Configure the programmable sequence LUT */ const uint8_t slot = imxrt_spi_build_insn_sequence(target, command, length); imxrt_spi_exec_sequence(target, slot, address, length);