mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-26 12:14:56 +00:00
133 lines
4.7 KiB
C
133 lines
4.7 KiB
C
// Copyright (c) 2026 Cesanta Software Limited
|
|
// All rights reserved
|
|
#include "hal.h"
|
|
|
|
#define APP_BASE 0x70100000U // Should match link.ld
|
|
|
|
uint32_t SystemCoreClock;
|
|
void SystemInit(void) {
|
|
hal_system_init();
|
|
if (!hal_clock_init(HAL_SYS_FREQUENCY)) {
|
|
for (;;) (void) 0;
|
|
}
|
|
}
|
|
|
|
static void xip_init(void) {
|
|
enum {
|
|
XSPI_AF = 9U,
|
|
XSPI_FLASH_SIZE_BITS = 26U, // 64 MiB MX25UM51245G
|
|
XSPI_KERNEL_DIV = HAL_XSPI_IC3_DIV, // PLL1 / div, capped at 50 MHz
|
|
XSPI_CSHT_CYCLES = 3U,
|
|
XSPI_REQ2ACK_CYCLES = 1U,
|
|
XSPI_READ_OPCODE = 0x0CU, // JEDEC 4-byte fast read
|
|
XSPI_READ_DUMMY_CYCLES = 8U,
|
|
};
|
|
static const uint16_t xspi_pins[] = {
|
|
PIN('N', 4), PIN('N', 6), PIN('N', 8), PIN('N', 0),
|
|
PIN('N', 3), PIN('N', 5), PIN('N', 1), PIN('N', 9),
|
|
PIN('N', 2), PIN('N', 10), PIN('N', 11),
|
|
};
|
|
const uint32_t clear_flags =
|
|
XSPI_FCR_CTCF | XSPI_FCR_CTEF | XSPI_FCR_CSMF | XSPI_FCR_CTOF;
|
|
|
|
// Explicitly enable every clock this XIP path depends on.
|
|
RCC->AHB4ENSR = RCC_AHB4ENSR_PWRENS | RCC_AHB4ENSR_GPIONENS;
|
|
RCC->APB4ENSR2 = RCC_APB4ENSR2_SYSCFGENS;
|
|
(void) RCC->AHB4ENR;
|
|
(void) RCC->APB4ENR2;
|
|
|
|
RCC->AHB5RSTSR = RCC_AHB5RSTSR_XSPIMRSTS | RCC_AHB5RSTSR_XSPI2RSTS;
|
|
RCC->AHB5RSTCR = RCC_AHB5RSTCR_XSPIMRSTC | RCC_AHB5RSTCR_XSPI2RSTC;
|
|
RCC->AHB4RSTSR = RCC_AHB4RSTSR_GPIONRSTS;
|
|
RCC->AHB4RSTCR = RCC_AHB4RSTCR_GPIONRSTC;
|
|
|
|
PWR->SVMCR1 |= PWR_SVMCR1_VDDIO4SV;
|
|
PWR->SVMCR2 |= PWR_SVMCR2_VDDIO5SV;
|
|
PWR->SVMCR3 |= PWR_SVMCR3_VDDIO2SV | PWR_SVMCR3_VDDIO3SV;
|
|
|
|
SYSCFG->VDDIO2CCCR = SYSCFG_VDDIO2CCCR_CS | SYSCFG_VDDIO2CCCR_RAPSRC_3 |
|
|
SYSCFG_VDDIO2CCCR_RANSRC_0 | SYSCFG_VDDIO2CCCR_RANSRC_1 |
|
|
SYSCFG_VDDIO2CCCR_RANSRC_2;
|
|
SYSCFG->VDDIO3CCCR = SYSCFG_VDDIO3CCCR_CS | SYSCFG_VDDIO3CCCR_RAPSRC_3 |
|
|
SYSCFG_VDDIO3CCCR_RANSRC_0 | SYSCFG_VDDIO3CCCR_RANSRC_1 |
|
|
SYSCFG_VDDIO3CCCR_RANSRC_2;
|
|
SYSCFG->VDDIO4CCCR = SYSCFG_VDDIO4CCCR_CS | SYSCFG_VDDIO4CCCR_RAPSRC_3 |
|
|
SYSCFG_VDDIO4CCCR_RANSRC_0 | SYSCFG_VDDIO4CCCR_RANSRC_1 |
|
|
SYSCFG_VDDIO4CCCR_RANSRC_2;
|
|
SYSCFG->VDDIO5CCCR = SYSCFG_VDDIO5CCCR_CS | SYSCFG_VDDIO5CCCR_RAPSRC_3 |
|
|
SYSCFG_VDDIO5CCCR_RANSRC_0 | SYSCFG_VDDIO5CCCR_RANSRC_1 |
|
|
SYSCFG_VDDIO5CCCR_RANSRC_2;
|
|
SYSCFG->VDDCCCR = SYSCFG_VDDCCCR_CS | SYSCFG_VDDCCCR_RAPSRC_3 |
|
|
SYSCFG_VDDCCCR_RANSRC_0 | SYSCFG_VDDCCCR_RANSRC_1 |
|
|
SYSCFG_VDDCCCR_RANSRC_2;
|
|
|
|
// Mirror the Cube FSBL topology: XSPI2 kernel clock is IC3 fed from PLL1.
|
|
CLRSET(RCC->IC3CFGR, RCC_IC3CFGR_IC3SEL | RCC_IC3CFGR_IC3INT,
|
|
(((uint32_t) (XSPI_KERNEL_DIV - 1U) << RCC_IC3CFGR_IC3INT_Pos) &
|
|
RCC_IC3CFGR_IC3INT));
|
|
RCC->DIVENSR = RCC_DIVENSR_IC3ENS;
|
|
CLRSET(RCC->CCIPR6, RCC_CCIPR6_XSPI2SEL, RCC_CCIPR6_XSPI2SEL_1);
|
|
|
|
RCC->AHB5ENSR = RCC_AHB5ENSR_XSPIMENS | RCC_AHB5ENSR_XSPI2ENS;
|
|
(void) RCC->AHB5ENR;
|
|
|
|
for (size_t i = 0; i < sizeof(xspi_pins) / sizeof(xspi_pins[0]); i++) {
|
|
hal_gpio_init(xspi_pins[i], HAL_GPIO_MODE_AF, HAL_GPIO_OTYPE_PUSH_PULL,
|
|
HAL_GPIO_SPEED_VERY_HIGH, HAL_GPIO_PULL_NONE, XSPI_AF);
|
|
}
|
|
|
|
// Keep XIP bring-up small and predictable: fixed 1-1-1 JEDEC 4-byte read.
|
|
XSPI2->CR = (uint32_t) ((4U - 1U) << XSPI_CR_FTHRES_Pos);
|
|
XSPI2->DCR1 = ((uint32_t) XSPI_CSHT_CYCLES << XSPI_DCR1_CSHT_Pos) |
|
|
XSPI_DCR1_MTYP_0 |
|
|
((uint32_t) XSPI_FLASH_SIZE_BITS << XSPI_DCR1_DEVSIZE_Pos);
|
|
XSPI2->DCR2 = 0U;
|
|
XSPI2->DCR3 = 0U;
|
|
XSPI2->DCR4 = 0U;
|
|
XSPIM->CR = XSPIM_CR_CSSEL_OVR_EN |
|
|
((uint32_t) XSPI_REQ2ACK_CYCLES << XSPIM_CR_REQ2ACK_TIME_Pos);
|
|
XSPI2->CR |= XSPI_CR_EN;
|
|
XSPI2->TCR = XSPI_READ_DUMMY_CYCLES | XSPI_TCR_SSHIFT;
|
|
XSPI2->DLR = 0U;
|
|
XSPI2->CCR =
|
|
XSPI_CCR_IMODE_0 | XSPI_CCR_ADMODE_0 | XSPI_CCR_ADSIZE | XSPI_CCR_DMODE_0;
|
|
XSPI2->IR = XSPI_READ_OPCODE;
|
|
XSPI2->AR = 0U;
|
|
XSPI2->FCR = clear_flags;
|
|
|
|
// In reset topology XSPI2 is wired to XSPIM port 2 already.
|
|
CLRSET(XSPI2->CR, XSPI_CR_FMODE, XSPI_CR_FMODE);
|
|
}
|
|
|
|
static void jump_to_app(void) {
|
|
// Lit blue pin
|
|
hal_gpio_output(PIN('G', 8));
|
|
hal_gpio_write(PIN('G', 8), false);
|
|
|
|
// Read stack and app entry point from the app vector table
|
|
uint32_t sp = *(volatile uint32_t *) (APP_BASE + 0U);
|
|
uint32_t pc = *(volatile uint32_t *) (APP_BASE + 4U);
|
|
|
|
// Switch to the app's vector table only after the first XIP reads succeed.
|
|
SCB->VTOR = APP_BASE;
|
|
__DSB();
|
|
__ISB();
|
|
|
|
// Lit green pin
|
|
hal_gpio_output(PIN('G', 0));
|
|
hal_gpio_write(PIN('G', 0), false);
|
|
|
|
__set_MSP(sp);
|
|
((void (*)(void)) pc)(); // Jump to the application entry point
|
|
for (;;) (void) 0; // Hang
|
|
}
|
|
|
|
int main(void) {
|
|
xip_init();
|
|
jump_to_app();
|
|
return 0;
|
|
}
|
|
|
|
void _init(void) {
|
|
}
|