7171#define W25Q_CMD_READ_STATUS1 0x05
7272#define W25Q_CMD_PAGE_PROGRAM 0x02
7373#define W25Q_CMD_SECTOR_ERASE 0x20 /* 4KB sector erase */
74- #define W25Q_CMD_FAST_READ_QUAD 0x6B /* Quad output fast read */
74+ #define W25Q_CMD_FAST_READ_QUAD_IO 0xEB /* Quad I/O fast read */
7575
7676/* W25Q status register bits */
7777#define W25Q_STATUS_BUSY 0x01
@@ -101,16 +101,167 @@ static uint8_t flash_page_cache[FLASH_PAGE_SIZE];
101101 SPIFI_CMD_FRAMEFORM(FRAMEFORM_OPCODE_3ADDR) | \
102102 SPIFI_CMD_OPCODE(W25Q_CMD_PAGE_PROGRAM))
103103
104- /* Memory-mode command: quad output fast read with 1 intermediate (dummy) byte */
104+ /* Memory-mode command: Quad I/O fast read (0xEB) — must match boot ROM config.
105+ * Boot ROM MCMD = 0xEB930000:
106+ * opcode 0xEB, FRAMEFORM=4 (opcode+3addr), FIELDFORM=2 (addr+data quad),
107+ * INTLEN=3 (3 intermediate/dummy bytes in quad mode) */
105108#define MCMD_READ_QUAD \
106- (SPIFI_CMD_INTLEN(1 ) | SPIFI_CMD_FIELDFORM(FIELDFORM_DATA_QUAD) | \
109+ (SPIFI_CMD_INTLEN(3 ) | SPIFI_CMD_FIELDFORM(FIELDFORM_DATA_QUAD) | \
107110 SPIFI_CMD_FRAMEFORM(FRAMEFORM_OPCODE_3ADDR) | \
108- SPIFI_CMD_OPCODE(W25Q_CMD_FAST_READ_QUAD ))
111+ SPIFI_CMD_OPCODE(W25Q_CMD_FAST_READ_QUAD_IO ))
109112
110113#ifdef NVM_FLASH_WRITEONCE
111114# error "wolfBoot LPC54S018M HAL: WRITEONCE not supported on SPIFI flash."
112115#endif
113116
117+ /* -------------------------------------------------------------------------- */
118+ /* UART via Flexcomm0 (bare-metal, no SDK) */
119+ /* -------------------------------------------------------------------------- */
120+ #ifdef DEBUG_UART
121+
122+ /* SYSCON registers for clock gating and peripheral reset */
123+ #define SYSCON_BASE 0x40000000
124+ #define SYSCON_AHBCLKCTRL0 (*(volatile uint32_t *)(SYSCON_BASE + 0x200))
125+ #define SYSCON_AHBCLKCTRL1 (*(volatile uint32_t *)(SYSCON_BASE + 0x204))
126+ #define SYSCON_PRESETCTRL1 (*(volatile uint32_t *)(SYSCON_BASE + 0x104))
127+ #define SYSCON_FCLKSEL0 (*(volatile uint32_t *)(SYSCON_BASE + 0x2B0))
128+
129+ #define AHBCLKCTRL0_IOCON (1UL << 13)
130+ #define AHBCLKCTRL1_FC0 (1UL << 11)
131+ #define PRESETCTRL1_FC0 (1UL << 11)
132+
133+ /* IOCON pin mux registers */
134+ #define IOCON_BASE 0x40001000
135+ #define IOCON_PIO0_29 (*(volatile uint32_t *)(IOCON_BASE + 0x074))
136+ #define IOCON_PIO0_30 (*(volatile uint32_t *)(IOCON_BASE + 0x078))
137+ #define IOCON_FUNC1 1U
138+ #define IOCON_DIGITAL_EN (1U << 8)
139+
140+ /* Flexcomm0 USART registers */
141+ #define FC0_BASE 0x40086000
142+ #define FC0_CFG (*(volatile uint32_t *)(FC0_BASE + 0x000))
143+ #define FC0_BRG (*(volatile uint32_t *)(FC0_BASE + 0x020))
144+ #define FC0_OSR (*(volatile uint32_t *)(FC0_BASE + 0x028))
145+ #define FC0_FIFOCFG (*(volatile uint32_t *)(FC0_BASE + 0xE00))
146+ #define FC0_FIFOSTAT (*(volatile uint32_t *)(FC0_BASE + 0xE04))
147+ #define FC0_FIFOWR (*(volatile uint32_t *)(FC0_BASE + 0xE20))
148+ #define FC0_PSELID (*(volatile uint32_t *)(FC0_BASE + 0xFF8))
149+
150+ /* USART CFG bits */
151+ #define USART_CFG_ENABLE (1U << 0)
152+ #define USART_CFG_DATALEN8 (1U << 2) /* 8-bit data */
153+
154+ /* FIFO bits */
155+ #define FIFOCFG_ENABLETX (1U << 0)
156+ #define FIFOCFG_ENABLERX (1U << 1)
157+ #define FIFOCFG_EMPTYTX (1U << 16)
158+ #define FIFOCFG_EMPTYRX (1U << 17)
159+ #define FIFOSTAT_TXEMPTY (1U << 3)
160+ #define FIFOSTAT_TXNOTFULL (1U << 4)
161+
162+ /* Baud rate: FRO 12 MHz / (13 * 8) = 115384 (0.16% error from 115200) */
163+ #define UART_OSR_VAL 12 /* oversampling = OSR + 1 = 13 */
164+ #define UART_BRG_VAL 7 /* divisor = BRG + 1 = 8 */
165+
166+ /* Timeout for UART FIFO polling */
167+ #define UART_TX_TIMEOUT 100000
168+
169+ /* SYSCON SET/CLR registers for atomic bit manipulation */
170+ #define SYSCON_PRESETCTRLSET1 (*(volatile uint32_t *)(SYSCON_BASE + 0x124))
171+ #define SYSCON_PRESETCTRLCLR1 (*(volatile uint32_t *)(SYSCON_BASE + 0x144))
172+ #define SYSCON_AHBCLKCTRLSET1 (*(volatile uint32_t *)(SYSCON_BASE + 0x224))
173+
174+ static int uart_ready ;
175+
176+ void uart_init (void )
177+ {
178+ volatile int i ;
179+
180+ uart_ready = 0 ;
181+
182+ /* Enable IOCON clock */
183+ SYSCON_AHBCLKCTRL0 |= AHBCLKCTRL0_IOCON ;
184+
185+ /* Pin mux: P0_29 = FC0_RXD, P0_30 = FC0_TXD (function 1, digital) */
186+ IOCON_PIO0_29 = IOCON_FUNC1 | IOCON_DIGITAL_EN ;
187+ IOCON_PIO0_30 = IOCON_FUNC1 | IOCON_DIGITAL_EN ;
188+
189+ /* Select FRO 12 MHz as Flexcomm0 clock source */
190+ SYSCON_FCLKSEL0 = 0 ;
191+
192+ /* Enable Flexcomm0 clock (use atomic SET register) */
193+ SYSCON_AHBCLKCTRLSET1 = AHBCLKCTRL1_FC0 ;
194+
195+ /* Reset Flexcomm0 using atomic CLR/SET registers (NXP SDK pattern) */
196+ SYSCON_PRESETCTRLCLR1 = PRESETCTRL1_FC0 ; /* Assert reset */
197+ while (SYSCON_PRESETCTRL1 & PRESETCTRL1_FC0 ) /* Wait for assert */
198+ ;
199+ SYSCON_PRESETCTRLSET1 = PRESETCTRL1_FC0 ; /* Deassert reset */
200+ while (!(SYSCON_PRESETCTRL1 & PRESETCTRL1_FC0 )) /* Wait for deassert */
201+ ;
202+
203+ /* Small delay after reset deassertion for peripheral to stabilize */
204+ for (i = 0 ; i < 100 ; i ++ )
205+ ;
206+
207+ /* Select USART mode */
208+ FC0_PSELID = 1 ;
209+
210+ /* Verify Flexcomm0 is accessible — if PSELID reads 0, peripheral is
211+ * not responding (observed on some LPC54S018M boards). Skip UART. */
212+ if ((FC0_PSELID & 0x71 ) == 0 ) {
213+ return ;
214+ }
215+
216+ /* Configure 8N1 (disabled initially) */
217+ FC0_CFG = USART_CFG_DATALEN8 ;
218+
219+ /* Set baud rate */
220+ FC0_OSR = UART_OSR_VAL ;
221+ FC0_BRG = UART_BRG_VAL ;
222+
223+ /* Enable and flush FIFOs */
224+ FC0_FIFOCFG = FIFOCFG_ENABLETX | FIFOCFG_ENABLERX |
225+ FIFOCFG_EMPTYTX | FIFOCFG_EMPTYRX ;
226+
227+ /* Enable USART */
228+ FC0_CFG |= USART_CFG_ENABLE ;
229+
230+ uart_ready = 1 ;
231+ }
232+
233+ void uart_write (const char * buf , unsigned int sz )
234+ {
235+ unsigned int i ;
236+ uint32_t timeout ;
237+
238+ if (!uart_ready )
239+ return ;
240+
241+ for (i = 0 ; i < sz ; i ++ ) {
242+ if (buf [i ] == '\n' ) {
243+ timeout = UART_TX_TIMEOUT ;
244+ while (!(FC0_FIFOSTAT & FIFOSTAT_TXNOTFULL ) && -- timeout )
245+ ;
246+ if (timeout == 0 )
247+ return ;
248+ FC0_FIFOWR = '\r' ;
249+ }
250+ timeout = UART_TX_TIMEOUT ;
251+ while (!(FC0_FIFOSTAT & FIFOSTAT_TXNOTFULL ) && -- timeout )
252+ ;
253+ if (timeout == 0 )
254+ return ;
255+ FC0_FIFOWR = (uint32_t )buf [i ];
256+ }
257+ /* Wait for transmit to complete */
258+ timeout = UART_TX_TIMEOUT ;
259+ while (!(FC0_FIFOSTAT & FIFOSTAT_TXEMPTY ) && -- timeout )
260+ ;
261+ }
262+
263+ #endif /* DEBUG_UART */
264+
114265/* -------------------------------------------------------------------------- */
115266/* Boot-time initialization (runs from flash / XIP) */
116267/* -------------------------------------------------------------------------- */
@@ -136,6 +287,10 @@ void hal_init(void)
136287 * The flash erase/write paths (all RAMFUNCTION) handle SPIFI mode
137288 * switching as needed.
138289 */
290+ #ifdef DEBUG_UART
291+ uart_init ();
292+ uart_write ("wolfBoot HAL init\n" , 18 );
293+ #endif
139294}
140295
141296void hal_prepare_boot (void )
@@ -154,11 +309,17 @@ void hal_prepare_boot(void)
154309 */
155310static void RAMFUNCTION spifi_set_cmd (uint32_t cmd_val )
156311{
157- /* If in memory mode (MCINIT set), reset to exit */
312+ /* If in memory mode (MCINIT set), reset to exit.
313+ * The SPIFI reset clears CTRL and CLIMIT — save and restore
314+ * the boot ROM's configuration. */
158315 if (SPIFI_STAT & SPIFI_STAT_MCINIT ) {
316+ uint32_t ctrl = SPIFI_CTRL ;
317+ uint32_t climit = SPIFI_CLIMIT ;
159318 SPIFI_STAT = SPIFI_STAT_RESET ;
160319 while (SPIFI_STAT & SPIFI_STAT_RESET )
161320 ;
321+ SPIFI_CTRL = ctrl ;
322+ SPIFI_CLIMIT = climit ;
162323 }
163324
164325 /* Wait for any active command to complete */
@@ -173,15 +334,29 @@ static void RAMFUNCTION spifi_set_cmd(uint32_t cmd_val)
173334 */
174335static void RAMFUNCTION spifi_enter_memmode (void )
175336{
176- /* Wait for any active command */
337+ uint32_t ctrl = SPIFI_CTRL ;
338+ uint32_t climit = SPIFI_CLIMIT ;
339+
340+ /* Wait for any active command to complete */
177341 while (SPIFI_STAT & SPIFI_STAT_CMD )
178342 ;
179343
344+ /* Reset to clear stale command/POLL state, restore config, enter
345+ * memory mode. */
346+ SPIFI_STAT = SPIFI_STAT_RESET ;
347+ while (SPIFI_STAT & SPIFI_STAT_RESET )
348+ ;
349+ SPIFI_CTRL = ctrl ;
350+ SPIFI_CLIMIT = climit ;
351+
180352 SPIFI_MCMD = MCMD_READ_QUAD ;
181353
182354 /* Wait for memory mode to initialize */
183355 while (!(SPIFI_STAT & SPIFI_STAT_MCINIT ))
184356 ;
357+
358+ __asm__ volatile ("dsb" );
359+ __asm__ volatile ("isb" );
185360}
186361
187362static void RAMFUNCTION spifi_write_enable (void )
@@ -191,13 +366,55 @@ static void RAMFUNCTION spifi_write_enable(void)
191366
192367static void RAMFUNCTION spifi_wait_busy (void )
193368{
194- uint8_t status ;
369+ /* Use SPIFI POLL mode with properly configured IDATA/CLIMIT.
370+ *
371+ * The boot ROM leaves CLIMIT[7:0]=0x00 which makes the POLL comparison
372+ * always succeed immediately. We must set CLIMIT[7:0] to mask the BUSY
373+ * bit and IDATA[7:0] to the expected value (0 = not busy).
374+ *
375+ * CLIMIT also serves as the cache limit register (upper bits), so we
376+ * preserve those bits and only modify the lower byte used for POLL mask.
377+ */
378+ uint32_t saved_climit = SPIFI_CLIMIT ;
379+
380+ SPIFI_IDATA = 0x00 ; /* expect BUSY=0 */
381+ SPIFI_CLIMIT = (saved_climit & 0xFFFFFF00 ) | W25Q_STATUS_BUSY ; /* mask bit 0 */
382+
383+ spifi_set_cmd (CMD_READ_STATUS ); /* POLL mode command */
384+
385+ /* SPIFI hardware polls flash status internally.
386+ * CMD bit clears when (status & mask) == (IDATA & mask). */
387+ while (SPIFI_STAT & SPIFI_STAT_CMD )
388+ ;
389+
390+ SPIFI_CLIMIT = saved_climit ; /* restore cache limit */
391+ }
392+
393+ /*
394+ * Minimal SPIFI mode-switch test: exit memory mode, immediately re-enter.
395+ * Used to verify the basic exit/enter cycle works before testing flash ops.
396+ */
397+ void RAMFUNCTION spifi_test_mode_switch (void )
398+ {
399+ uint32_t ctrl = SPIFI_CTRL ;
400+ uint32_t climit = SPIFI_CLIMIT ;
401+
402+ /* Exit memory mode */
403+ SPIFI_STAT = SPIFI_STAT_RESET ;
404+ while (SPIFI_STAT & SPIFI_STAT_RESET )
405+ ;
406+
407+ /* Restore all config */
408+ SPIFI_CTRL = ctrl ;
409+ SPIFI_CLIMIT = climit ;
410+
411+ /* Re-enter memory mode */
412+ SPIFI_MCMD = MCMD_READ_QUAD ;
413+ while (!(SPIFI_STAT & SPIFI_STAT_MCINIT ))
414+ ;
195415
196- /* Issue read-status command in poll mode */
197- spifi_set_cmd (CMD_READ_STATUS );
198- do {
199- status = * (volatile uint8_t * )& SPIFI_DATA ;
200- } while (status & W25Q_STATUS_BUSY );
416+ __asm__ volatile ("dsb" );
417+ __asm__ volatile ("isb" );
201418}
202419
203420/*
0 commit comments