Skip to content

Commit

Permalink
imxrt: Detect iMX RT variant and adjust FLEXSPI base address
Browse files Browse the repository at this point in the history
  • Loading branch information
tannewt committed Aug 10, 2023
1 parent a7131c4 commit 2ca5952
Showing 1 changed file with 151 additions and 26 deletions.
177 changes: 151 additions & 26 deletions src/target/imxrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <string.h>
#include "general.h"
#include "target.h"
#include "target_internal.h"
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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 */
Expand All @@ -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;
Expand Down Expand Up @@ -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)
{
/*
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit 2ca5952

Please sign in to comment.