diff --git a/src/target/cortexm.c b/src/target/cortexm.c index b09758c3eb3..7cd16fa342b 100644 --- a/src/target/cortexm.c +++ b/src/target/cortexm.c @@ -601,8 +601,8 @@ bool cortexm_probe(adiv5_access_port_s *ap) switch (t->designer_code) { case JEP106_MANUFACTURER_FREESCALE: - PROBE(kinetis_probe); PROBE(imxrt_probe); + PROBE(kinetis_probe); break; case JEP106_MANUFACTURER_GIGADEVICE: PROBE(gd32f1_probe); diff --git a/src/target/imxrt.c b/src/target/imxrt.c index dc46a703ca1..eeba517c0fa 100644 --- a/src/target/imxrt.c +++ b/src/target/imxrt.c @@ -31,8 +31,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include "general.h" +#include #include "target.h" #include "target_internal.h" #include "cortexm.h" @@ -59,39 +59,75 @@ #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_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_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_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) -#define IMXRT_FLEXSPI1_LUT_KEY (IMXRT_FLEXSPI1_BASE + 0x018U) -#define IMXRT_FLEXSPI1_LUT_CTRL (IMXRT_FLEXSPI1_BASE + 0x01cU) -#define IMXRT_FLEXSPI1_CTRL0 (IMXRT_FLEXSPI1_BASE + 0x060U) -#define IMXRT_FLEXSPI1_CTRL1 (IMXRT_FLEXSPI1_BASE + 0x070U) -#define IMXRT_FLEXSPI1_CTRL2 (IMXRT_FLEXSPI1_BASE + 0x080U) -#define IMXRT_FLEXSPI1_PRG_CTRL0 (IMXRT_FLEXSPI1_BASE + 0x0a0U) -#define IMXRT_FLEXSPI1_PRG_CTRL1 (IMXRT_FLEXSPI1_BASE + 0x0a4U) -#define IMXRT_FLEXSPI1_PRG_CMD (IMXRT_FLEXSPI1_BASE + 0x0b0U) -#define IMXRT_FLEXSPI1_PRG_READ_FIFO_CTRL (IMXRT_FLEXSPI1_BASE + 0x0b8U) -#define IMXRT_FLEXSPI1_PRG_WRITE_FIFO_CTRL (IMXRT_FLEXSPI1_BASE + 0x0bcU) -#define IMXRT_FLEXSPI1_STAT1 (IMXRT_FLEXSPI1_BASE + 0x0e4U) -#define IMXRT_FLEXSPI1_PRG_WRITE_FIFO_STATUS (IMXRT_FLEXSPI1_BASE + 0x0f4U) -#define IMXRT_FLEXSPI1_PRG_READ_FIFO (IMXRT_FLEXSPI1_BASE + 0x100U) -#define IMXRT_FLEXSPI1_PRG_WRITE_FIFO (IMXRT_FLEXSPI1_BASE + 0x180U) -#define IMXRT_FLEXSPI1_LUT_BASE (IMXRT_FLEXSPI1_BASE + 0x200U) +#define IMXRT10xx_CCM_ANALOG_BASE UINT32_C(0x400d8000) +#define IMXRT10xx_CCM_ANALOG_PLL3_PFD (IMXRT10xx_CCM_ANALOG_BASE + 0x0f0U) + +#define IMXRT10xx_CCM_ANALOG_PLL_PFD0_FRAC_MASK 0xffffffc0 + +#define IMXRT10xx_CCM_BASE UINT32_C(0x400fc000) +#define IMXRT10xx_CCM_CSCM1 (IMXRT10xx_CCM_BASE + 0x01cU) +#define IMXRT10xx_CCM_CCG6 (IMXRT10xx_CCM_BASE + 0x080U) + +#define IMXRT10xx_CCM_CSCM1_FLEXSPI_CLK_SEL_MASK 0xfc7fffffU +#define IMXRT10xx_CCM_CSCM1_FLEXSPI_CLK_SEL_PLL3_PFD0 0x03800000U +#define IMXRT10xx_CCM_CCG6_FLEXSPI_CLK_MASK 0xfffff3ffU +#define IMXRT10xx_CCM_CCG6_FLEXSPI_CLK_ENABLE 0x00000c00U + +#define IMXRT11xx_CCM_BASE UINT32_C(0x40cc0000) +#define IMXRT11xx_CCM_CLOCK_ROOT20_CONTROL (IMXRT11xx_CCM_BASE + 0x0 + (20 * 0x80)) +#define IMXRT11xx_CCM_CLOCK_ROOT20_CONTROL_PLL_480M (0x7 << 8) +#define IMXRT11xx_CCM_CLOCK_ROOT20_CONTROL_OSC400M (0x2 << 8) +#define IMXRT11xx_CCM_CLOCK_ROOT20_CONTROL_DIV(divisor) ((divisor - 1) << 0) +#define IMXRT11xx_CCM_LPCG28 (IMXRT11xx_CCM_BASE + 0x6000 + (28 * 0x20)) + +#define IMXRT_FP_FLAG UINT32_C(0x0000fffc) +#define IMXRT11xx_FP_FLAG UINT32_C(0x5aa60ff0) + +#define IMXRTx00_ROM_FINGERPRINT_ADDR 0x0301a000u +#define IMXRT10xx_ROM_FINGERPRINT_ADDR 0x0020a000u +#define IMXRT11xx_ROM_FINGERPRINT_ADDR 0x0021a000u + +#define IMXRT5xx_ROM_FINGERPRINT UINT32_C(0x669ff643) +#define IMXRT6xx_ROM_FINGERPRINT UINT32_C(0xf2406510) + +#define IMXRT1011_ROM_FINGERPRINT UINT32_C(0xf88d10c9) +#define IMXRT102x_ROM_FINGERPRINT UINT32_C(0xe9dd9a03) +#define IMXRT105x_ROM_FINGERPRINT UINT32_C(0x2101eb10) +#define IMXRT106x_ROM_FINGERPRINT UINT32_C(0x80dbf000) + +#define IMXRT117x_ROM_FINGERPRINT UINT32_C(0x9909a810) + +#define IMXRT5xx_FLEXSPI1_BASE UINT32_C(0x4013c000) +#define IMXRT6xx_FLEXSPI1_BASE UINT32_C(0x40134000) +#define IMXRT1011_FLEXSPI1_BASE UINT32_C(0x400a0000) +#define IMXRT102x_FLEXSPI1_BASE UINT32_C(0x402a8000) +#define IMXRT104x_FLEXSPI1_BASE UINT32_C(0x402a8000) +#define IMXRT105x_FLEXSPI1_BASE UINT32_C(0x402a8000) +#define IMXRT106x_FLEXSPI1_BASE UINT32_C(0x402a8000) +#define IMXRT116x_FLEXSPI1_BASE UINT32_C(0x400cc000) +#define IMXRT117x_FLEXSPI1_BASE UINT32_C(0x400cc000) + +/* + * We only carry definitions for FlexSPI1 Flash controller A1. + * The base address varies across the 10xx line. We store it in the private structure. + */ +#define IMXRT_FLEXSPI1_MOD_CTRL0(priv) ((priv)->flexspi_base + 0x000U) +#define IMXRT_FLEXSPI1_INT(priv) ((priv)->flexspi_base + 0x014U) +#define IMXRT_FLEXSPI1_LUT_KEY(priv) ((priv)->flexspi_base + 0x018U) +#define IMXRT_FLEXSPI1_LUT_CTRL(priv) ((priv)->flexspi_base + 0x01cU) +#define IMXRT_FLEXSPI1_CTRL0(priv) ((priv)->flexspi_base + 0x060U) +#define IMXRT_FLEXSPI1_CTRL1(priv) ((priv)->flexspi_base + 0x070U) +#define IMXRT_FLEXSPI1_CTRL2(priv) ((priv)->flexspi_base + 0x080U) +#define IMXRT_FLEXSPI1_PRG_CTRL0(priv) ((priv)->flexspi_base + 0x0a0U) +#define IMXRT_FLEXSPI1_PRG_CTRL1(priv) ((priv)->flexspi_base + 0x0a4U) +#define IMXRT_FLEXSPI1_PRG_CMD(priv) ((priv)->flexspi_base + 0x0b0U) +#define IMXRT_FLEXSPI1_PRG_READ_FIFO_CTRL(priv) ((priv)->flexspi_base + 0x0b8U) +#define IMXRT_FLEXSPI1_PRG_WRITE_FIFO_CTRL(priv) ((priv)->flexspi_base + 0x0bcU) +#define IMXRT_FLEXSPI1_STAT1(priv) ((priv)->flexspi_base + 0x0e4U) +#define IMXRT_FLEXSPI1_PRG_WRITE_FIFO_STATUS(priv) ((priv)->flexspi_base + 0x0f4U) +#define IMXRT_FLEXSPI1_PRG_READ_FIFO(priv) ((priv)->flexspi_base + 0x100U) +#define IMXRT_FLEXSPI1_PRG_WRITE_FIFO(priv) ((priv)->flexspi_base + 0x180U) +#define IMXRT_FLEXSPI1_LUT_BASE(priv) ((priv)->flexspi_base + 0x200U) #define IMXRT_FLEXSPI1_MOD_CTRL0_SUSPEND 0x00000002U #define IMXRT_FLEXSPI1_INT_PRG_CMD_DONE 0x00000001U @@ -125,6 +161,8 @@ #define IMXRT_FLEXSPI_LUT_OP_READ 0x09U #define IMXRT_FLEXSPI_LUT_OP_WRITE 0x08U +#define IMXRT_NAME_MAX_LENGTH 12 + typedef enum imxrt_boot_src { BOOT_FLEX_SPI, boot_sd_card, @@ -140,10 +178,14 @@ typedef struct imxrt_flexspi_lut_insn { typedef struct imxrt_priv { imxrt_boot_src_e boot_source; + uint16_t chip_id; + uint32_t flexspi_base; 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 name[IMXRT_NAME_MAX_LENGTH]; } imxrt_priv_s; static imxrt_boot_src_e imxrt_boot_source(uint32_t boot_cfg); @@ -154,15 +196,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 bool imxrt_ident_device(target_s *target); 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 */ DEBUG_WARN("calloc: failed in %s\n", __func__); @@ -170,7 +211,12 @@ bool imxrt_probe(target_s *const target) } target->target_storage = priv; target->target_options |= CORTEXM_TOPT_INHIBIT_NRST; - target->driver = "i.MXRT10xx"; + + if (!imxrt_ident_device(target)) + return false; + + snprintf(priv->name, IMXRT_NAME_MAX_LENGTH, "i.MXRT%u", priv->chip_id); + target->driver = priv->name; #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 +273,74 @@ bool imxrt_probe(target_s *const target) return true; } +static bool imxrt_ident_device(target_s *const target) +{ + imxrt_priv_s *const priv = (imxrt_priv_s *)target->target_storage; + /* + * The iMXRT 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 & CORTEX_CPUID_PARTNO_MASK; + if (cpuid_partno == CORTEX_M33) + rom_location = IMXRTx00_ROM_FINGERPRINT_ADDR; + else if (cpuid_partno == CORTEX_M7) { + if (target->part_id == 0x88c6U) + rom_location = IMXRT11xx_ROM_FINGERPRINT_ADDR; + else + rom_location = IMXRT10xx_ROM_FINGERPRINT_ADDR; + } else { + DEBUG_ERROR("Unknown core %04x\n", cpuid_partno); + return false; + } + + const uint32_t fingerprint = target_mem_read32(target, rom_location); + switch (fingerprint) { + case IMXRT5xx_ROM_FINGERPRINT: + priv->chip_id = 500; + priv->flexspi_base = IMXRT5xx_FLEXSPI1_BASE; + break; + case IMXRT6xx_ROM_FINGERPRINT: + priv->chip_id = 600; + priv->flexspi_base = IMXRT6xx_FLEXSPI1_BASE; + break; + + case IMXRT1011_ROM_FINGERPRINT: + priv->chip_id = 1011; + priv->flexspi_base = IMXRT1011_FLEXSPI1_BASE; + break; + case IMXRT102x_ROM_FINGERPRINT: + // The 1015 is actually a 1021. + priv->chip_id = 1021; + priv->flexspi_base = IMXRT102x_FLEXSPI1_BASE; + break; + case IMXRT105x_ROM_FINGERPRINT: + priv->chip_id = 1052; + priv->flexspi_base = IMXRT105x_FLEXSPI1_BASE; + break; + case IMXRT106x_ROM_FINGERPRINT: + // The 1042 is actually a 1062. + priv->chip_id = 1062; + priv->flexspi_base = IMXRT106x_FLEXSPI1_BASE; + break; + + case IMXRT117x_ROM_FINGERPRINT: + priv->chip_id = 1176; + priv->flexspi_base = IMXRT117x_FLEXSPI1_BASE; + break; + default: + DEBUG_TARGET("Unknown ROM fingerprint at %08x = %08x\n", rom_location, fingerprint); + break; + } + + DEBUG_TARGET("%s: %u\n", __func__, priv->chip_id); + + /* TODO: Check for in package flash. */ + return true; +} + static imxrt_boot_src_e imxrt_boot_source(const uint32_t boot_cfg) { /* @@ -256,35 +370,53 @@ static bool imxrt_enter_flash_mode(target_s *const target) priv->mpu_state = target_mem_read32(target, IMXRT_MPU_CTRL); target_mem_write32(target, IMXRT_MPU_CTRL, 0); /* 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); - 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_FLEXSPI1_MOD_CTRL0(priv), + target_mem_read32(target, IMXRT_FLEXSPI1_MOD_CTRL0(priv)) | IMXRT_FLEXSPI1_MOD_CTRL0_SUSPEND); + if (1000 <= priv->chip_id && priv->chip_id < 1100) { + // Gate the clock to FLEXSPI while we change it. + target_mem_write32(target, IMXRT10xx_CCM_CCG6, + target_mem_read32(target, IMXRT10xx_CCM_CCG6) & IMXRT10xx_CCM_CCG6_FLEXSPI_CLK_MASK); + + target_mem_write32(target, IMXRT10xx_CCM_CSCM1, + (target_mem_read32(target, IMXRT10xx_CCM_CSCM1) & IMXRT10xx_CCM_CSCM1_FLEXSPI_CLK_SEL_MASK) | + IMXRT10xx_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, IMXRT10xx_CCM_ANALOG_PLL3_PFD, + (target_mem_read32(target, IMXRT10xx_CCM_ANALOG_PLL3_PFD) & IMXRT10xx_CCM_ANALOG_PLL_PFD0_FRAC_MASK) | + 0x16U); + + // Ungate the clock. + target_mem_write32(target, IMXRT10xx_CCM_CCG6, + target_mem_read32(target, IMXRT10xx_CCM_CCG6) | IMXRT10xx_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, IMXRT11xx_CCM_LPCG28, 0); + // PLL3 480 Mhz / 4 -> 120 Mhz + target_mem_read32(target, IMXRT11xx_CCM_CLOCK_ROOT20_CONTROL); + target_mem_write32(target, IMXRT11xx_CCM_CLOCK_ROOT20_CONTROL, + IMXRT11xx_CCM_CLOCK_ROOT20_CONTROL_PLL_480M | IMXRT11xx_CCM_CLOCK_ROOT20_CONTROL_DIV(4)); + // Ungate the clock. + target_mem_write32(target, IMXRT11xx_CCM_LPCG28, 1); + } + target_mem_write32(target, IMXRT_FLEXSPI1_MOD_CTRL0(priv), + target_mem_read32(target, IMXRT_FLEXSPI1_MOD_CTRL0(priv)) & ~IMXRT_FLEXSPI1_MOD_CTRL0_SUSPEND); /* Clear all outstanding interrupts so we can consume their status cleanly */ - target_mem_write32(target, IMXRT_FLEXSPI1_INT, target_mem_read32(target, IMXRT_FLEXSPI1_INT)); + target_mem_write32(target, IMXRT_FLEXSPI1_INT(priv), target_mem_read32(target, IMXRT_FLEXSPI1_INT(priv))); /* Tell the controller we want to use the entire read FIFO */ - target_mem_write32(target, IMXRT_FLEXSPI1_PRG_READ_FIFO_CTRL, + target_mem_write32(target, IMXRT_FLEXSPI1_PRG_READ_FIFO_CTRL(priv), IMXRT_FLEXSPI1_PRG_FIFO_CTRL_WATERMARK(128) | IMXRT_FLEXSPI1_PRG_FIFO_CTRL_CLR); /* Tell the controller we want to use the entire write FIFO */ - target_mem_write32(target, IMXRT_FLEXSPI1_PRG_WRITE_FIFO_CTRL, + target_mem_write32(target, IMXRT_FLEXSPI1_PRG_WRITE_FIFO_CTRL(priv), IMXRT_FLEXSPI1_PRG_FIFO_CTRL_WATERMARK(128) | IMXRT_FLEXSPI1_PRG_FIFO_CTRL_CLR); /* Then unlock the sequence LUT so we can use it to to run Flash commands */ - priv->flexspi_lut_state = target_mem_read32(target, IMXRT_FLEXSPI1_LUT_CTRL); + priv->flexspi_lut_state = target_mem_read32(target, IMXRT_FLEXSPI1_LUT_CTRL(priv)); if (priv->flexspi_lut_state != IMXRT_FLEXSPI1_LUT_CTRL_UNLOCK) { - target_mem_write32(target, IMXRT_FLEXSPI1_LUT_KEY, IMXRT_FLEXSPI1_LUT_KEY_VALUE); - target_mem_write32(target, IMXRT_FLEXSPI1_LUT_CTRL, IMXRT_FLEXSPI1_LUT_CTRL_UNLOCK); + target_mem_write32(target, IMXRT_FLEXSPI1_LUT_KEY(priv), IMXRT_FLEXSPI1_LUT_KEY_VALUE); + target_mem_write32(target, IMXRT_FLEXSPI1_LUT_CTRL(priv), IMXRT_FLEXSPI1_LUT_CTRL_UNLOCK); } /* Save the current state of the LUT the SPI Flash routines will use */ - target_mem_read(target, priv->flexspi_prg_seq_state, IMXRT_FLEXSPI1_LUT_BASE, sizeof(priv->flexspi_prg_seq_state)); + target_mem_read( + target, priv->flexspi_prg_seq_state, IMXRT_FLEXSPI1_LUT_BASE(priv), sizeof(priv->flexspi_prg_seq_state)); /* Clear the sequence microcode cache state */ memset(priv->flexspi_cached_commands, 0, sizeof(priv->flexspi_cached_commands)); return true; @@ -294,10 +426,11 @@ static bool imxrt_exit_flash_mode(target_s *const target) { const imxrt_priv_s *const priv = (imxrt_priv_s *)target->target_storage; /* To leave Flash mode, we do things in the opposite order to entering. */ - target_mem_write(target, IMXRT_FLEXSPI1_LUT_BASE, priv->flexspi_prg_seq_state, sizeof(priv->flexspi_prg_seq_state)); + target_mem_write( + target, IMXRT_FLEXSPI1_LUT_BASE(priv), priv->flexspi_prg_seq_state, sizeof(priv->flexspi_prg_seq_state)); if (priv->flexspi_lut_state != IMXRT_FLEXSPI1_LUT_CTRL_UNLOCK) { - target_mem_write32(target, IMXRT_FLEXSPI1_LUT_KEY, IMXRT_FLEXSPI1_LUT_KEY_VALUE); - target_mem_write32(target, IMXRT_FLEXSPI1_LUT_CTRL, priv->flexspi_lut_state); + target_mem_write32(target, IMXRT_FLEXSPI1_LUT_KEY(priv), IMXRT_FLEXSPI1_LUT_KEY_VALUE); + target_mem_write32(target, IMXRT_FLEXSPI1_LUT_CTRL(priv), priv->flexspi_lut_state); } /* But we don't bother restoring the clocks as the boot ROM'll do that if needed */ target_mem_write32(target, IMXRT_MPU_CTRL, priv->mpu_state); @@ -351,12 +484,13 @@ 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); /* Write the new sequence to the programmable sequence LUT */ - target_mem_write(target, IMXRT_FLEXSPI1_LUT_BASE + IMXRT_FLEXSI_SLOT_OFFSET(slot), sequence, sizeof(sequence)); + target_mem_write( + target, IMXRT_FLEXSPI1_LUT_BASE(priv) + IMXRT_FLEXSI_SLOT_OFFSET(slot), sequence, sizeof(sequence)); /* Update the cache information */ priv->flexspi_cached_commands[slot] = command; return slot; @@ -369,31 +503,32 @@ static void imxrt_spi_exec_sequence( const uint32_t command = priv->flexspi_cached_commands[slot]; /* Write the address, if any, to the sequence address register */ if ((command & SPI_FLASH_OPCODE_MODE_MASK) == SPI_FLASH_OPCODE_3B_ADDR) - target_mem_write32(target, IMXRT_FLEXSPI1_PRG_CTRL0, address); + target_mem_write32(target, IMXRT_FLEXSPI1_PRG_CTRL0(priv), address); /* Write the command data length and instruction sequence index */ target_mem_write32( - target, IMXRT_FLEXSPI1_PRG_CTRL1, IMXRT_FLEXSPI1_PRG_SEQ_INDEX(slot) | IMXRT_FLEXSPI1_PRG_LENGTH(length)); + target, IMXRT_FLEXSPI1_PRG_CTRL1(priv), IMXRT_FLEXSPI1_PRG_SEQ_INDEX(slot) | IMXRT_FLEXSPI1_PRG_LENGTH(length)); /* Execute the sequence */ - target_mem_write32(target, IMXRT_FLEXSPI1_PRG_CMD, IMXRT_FLEXSPI1_PRG_RUN); + target_mem_write32(target, IMXRT_FLEXSPI1_PRG_CMD(priv), IMXRT_FLEXSPI1_PRG_RUN); } 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)) + while (!(target_mem_read32(target, IMXRT_FLEXSPI1_INT(priv)) & IMXRT_FLEXSPI1_INT_PRG_CMD_DONE)) continue; /* Then clear the interrupt bit it sets. */ - target_mem_write32(target, IMXRT_FLEXSPI1_INT, IMXRT_FLEXSPI1_INT_PRG_CMD_DONE); + target_mem_write32(target, IMXRT_FLEXSPI1_INT(priv), IMXRT_FLEXSPI1_INT_PRG_CMD_DONE); /* Check if any errors occured */ - if (target_mem_read32(target, IMXRT_FLEXSPI1_INT) & IMXRT_FLEXSPI1_INT_CMD_ERR) { + if (target_mem_read32(target, IMXRT_FLEXSPI1_INT(priv)) & IMXRT_FLEXSPI1_INT_CMD_ERR) { #if defined(ENABLE_DEBUG) && PC_HOSTED == 1 /* Read out the status code and display it */ - const uint32_t status = target_mem_read32(target, IMXRT_FLEXSPI1_STAT1); + const uint32_t status = target_mem_read32(target, IMXRT_FLEXSPI1_STAT1(priv)); DEBUG_TARGET("Error executing sequence, offset %u, error code %u\n", (uint8_t)(status >> 16U) & 0xfU, (uint8_t)(status >> 24U) & 0xfU); #endif /* Now clear the error (this clears the status field bits too) */ - target_mem_write32(target, IMXRT_FLEXSPI1_INT, IMXRT_FLEXSPI1_INT_CMD_ERR); + target_mem_write32(target, IMXRT_FLEXSPI1_INT(priv), IMXRT_FLEXSPI1_INT_CMD_ERR); } } @@ -404,34 +539,36 @@ 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); imxrt_spi_wait_complete(target); /* Transfer the resulting data into the target buffer */ uint32_t data[32]; - target_mem_read(target, data, IMXRT_FLEXSPI1_PRG_READ_FIFO, 128); + target_mem_read(target, data, IMXRT_FLEXSPI1_PRG_READ_FIFO(priv), 128); memcpy(buffer, data, length); - target_mem_write32(target, IMXRT_FLEXSPI1_INT, IMXRT_FLEXSPI1_INT_READ_FIFO_FULL); + target_mem_write32(target, IMXRT_FLEXSPI1_INT(priv), IMXRT_FLEXSPI1_INT_READ_FIFO_FULL); } 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); /* Transfer the data into the transmit FIFO in blocks */ for (uint16_t offset = 0; offset < length; offset += 128U) { - while ( - target_mem_read32(target, IMXRT_FLEXSPI1_PRG_WRITE_FIFO_STATUS) & IMXRT_FLEXSPI1_PRG_WRITE_FIFO_STATUS_FILL) + while (target_mem_read32(target, IMXRT_FLEXSPI1_PRG_WRITE_FIFO_STATUS(priv)) & + IMXRT_FLEXSPI1_PRG_WRITE_FIFO_STATUS_FILL) continue; const uint16_t amount = MIN(128U, (uint16_t)(length - offset)); uint32_t data[32] = {0}; memcpy(data, (const char *)buffer + offset, amount); - target_mem_write(target, IMXRT_FLEXSPI1_PRG_WRITE_FIFO, data, (amount + 3U) & ~3U); + target_mem_write(target, IMXRT_FLEXSPI1_PRG_WRITE_FIFO(priv), data, (amount + 3U) & ~3U); /* Tell the controller we've filled the write FIFO */ - target_mem_write32(target, IMXRT_FLEXSPI1_INT, IMXRT_FLEXSPI1_INT_WRITE_FIFO_EMPTY); + target_mem_write32(target, IMXRT_FLEXSPI1_INT(priv), IMXRT_FLEXSPI1_INT_WRITE_FIFO_EMPTY); } /* Now wait for the FlexSPI controller to indicate the command completed we're done */ imxrt_spi_wait_complete(target); diff --git a/src/target/sfdp.c b/src/target/sfdp.c index 1eb22fac933..e73a706e73e 100644 --- a/src/target/sfdp.c +++ b/src/target/sfdp.c @@ -65,12 +65,14 @@ static inline size_t sfdp_memory_density_to_capacity_bits(const uint8_t *const d return SFDP_DENSITY_VALUE(density) + 1U; } -static spi_parameters_s sfdp_read_basic_parameter_table( - target_s *const target, const uint32_t address, const size_t length, const spi_read_func spi_read) +static spi_parameters_s sfdp_read_basic_parameter_table(target_s *const target, + const sfdp_parameter_table_header_s *const header, const uint32_t address, const size_t length, + const spi_read_func spi_read) { sfdp_basic_parameter_table_s parameter_table; const size_t table_length = MIN(sizeof(sfdp_basic_parameter_table_s), length); spi_read(target, SPI_FLASH_CMD_READ_SFDP, address, ¶meter_table, table_length); + sfdp_debug_print(address, ¶meter_table, table_length); spi_parameters_s result = {0}; result.capacity = sfdp_memory_density_to_capacity_bits(parameter_table.memory_density) >> 3U; @@ -82,7 +84,13 @@ static spi_parameters_s sfdp_read_basic_parameter_table( break; } } - result.page_size = SFDP_PAGE_SIZE(parameter_table); + // The timing and page size DWORD was added in JESD216A. It is marked as + // version 1.5. + if (header->version_major > 1 || (header->version_major == 1 && header->version_minor >= 5)) + result.page_size = SFDP_PAGE_SIZE(parameter_table); + else + result.page_size = 256; + return result; } @@ -103,7 +111,7 @@ bool sfdp_read_parameters(target_s *const target, spi_parameters_s *params, cons if (jedec_parameter_id == SFDP_BASIC_SPI_PARAMETER_TABLE) { const uint32_t table_address = SFDP_TABLE_ADDRESS(table_header); const uint16_t table_length = table_header.table_length_in_u32s * 4U; - *params = sfdp_read_basic_parameter_table(target, table_address, table_length, spi_read); + *params = sfdp_read_basic_parameter_table(target, &table_header, table_address, table_length, spi_read); return true; } } diff --git a/src/target/spi.c b/src/target/spi.c index 95459c40145..63d38dbe8b2 100644 --- a/src/target/spi.c +++ b/src/target/spi.c @@ -121,6 +121,7 @@ spi_flash_s *bmp_spi_add_flash(target_s *const target, const target_addr_t begin spi_parameters.sector_size = 4096U; spi_parameters.capacity = length; spi_parameters.sector_erase_opcode = SPI_FLASH_OPCODE_SECTOR_ERASE; + DEBUG_WARN("SFDP read failed. Using best guess.\n"); } DEBUG_INFO("Flash size: %" PRIu32 "MiB\n", (uint32_t)spi_parameters.capacity / (1024U * 1024U));