ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_xspi_flash.c
Go to the documentation of this file.
1
39
40#include <stdint.h>
41
42#include "ra8_attributes.h"
43#include "ra8_check.h"
44#include "ra8_err.h"
45#include "ra8_hw_err.h"
46#include "ra8_ospi_regs.h"
47#include "ra8_xspi.h"
48#include "ra8_xspi_internal.h"
49
51static const char* s_tag = "XSPI";
52
54typedef enum : uint32_t {
57
70
79
93typedef enum : uint32_t {
96
101typedef enum : uint8_t {
104
130static uint32_t internal_make_cdt(uint8_t opcode,
131 uint8_t cmd_bytes,
132 uint8_t addr_bytes,
133 uint8_t data_bytes,
134 uint8_t is_write)
135{
136 /* CMD is a 16-bit field at CDT[31:16]. The command-manual engine
137 * transmits CMDSIZE bytes MSB-first starting at bit 31, so an
138 * N-byte command must be LEFT-justified inside the 16-bit field:
139 * a 1-byte opcode belongs at bits [31:24], a 2-byte opcode pair at
140 * [31:16]. Placing a 1-byte opcode at [23:16] (a bare ``opcode <<
141 * 16``) makes the controller clock out the zero byte at [31:24]
142 * instead -- the flash then sees command 0x00 for every 0x9F /
143 * 0x05 / 0x06 / 0x02 / 0x20 op, never answers, and RDID floats to
144 * 0x00FFFFFF even though CMDCMP fires. Mirrors FSP
145 * ``r_ospi_b_direct_transfer`` which stores ``command`` already
146 * left-aligned in the 16-bit CMD field. HUM Ch 44 p 2986. */
147 const uint8_t cmd_shift = (uint8_t)(8U * (2U - (cmd_bytes & k_ra8_xspi_cdt_mask_cmdsize)));
148 const uint32_t cmd_word = ((uint32_t)opcode << cmd_shift) & (uint32_t)k_ra8_xspi_cdt_mask_cmd;
149 return (((uint32_t)cmd_bytes & k_ra8_xspi_cdt_mask_cmdsize) << k_ra8_xspi_cdt_pos_cmdsize) |
150 (((uint32_t)addr_bytes & k_ra8_xspi_cdt_mask_addsize) << k_ra8_xspi_cdt_pos_addsize) |
151 (((uint32_t)data_bytes & k_ra8_xspi_cdt_mask_datasize) << k_ra8_xspi_cdt_pos_datasize) |
152 (((uint32_t)is_write & k_ra8_xspi_cdt_mask_trtype) << k_ra8_xspi_cdt_pos_trtype) |
153 (cmd_word << k_ra8_xspi_cdt_pos_cmd);
154}
155
175
205static ra8_err_t internal_flash_range_check(uint32_t flash_addr, uint32_t len)
206{
207 if (flash_addr >= (uint32_t)k_ra8_xspi_addr_space_3byte) {
209 }
210 if (len > ((uint32_t)k_ra8_xspi_addr_space_3byte - flash_addr)) {
212 }
213 return k_ra8_ok;
214}
215
247{
249 for (uint32_t i = 0U; i < (uint32_t)k_ra8_xspi_cmd_spin; i++) {
250 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
251 const bool cmdcmp = ((reg->INTS & (uint32_t)k_ra8_xspi_ints_mask_cmdcmp) != 0U);
252#if defined(RA8_OFF_TARGET) && defined(UNIT_TEST)
253 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
254 if (ra8_fake_mmio_poll(&reg->INTS, i, cmdcmp)) {
255#else
256 if (cmdcmp) {
257#endif
258 wait = k_ra8_ok;
259 break;
260 }
261 }
262 if (wait != k_ra8_ok) {
263 return wait;
264 }
265 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
266 /* FSP r_ospi_b_direct_transfer clears every pending status bit at the
267 * end of a manual command via ``INTC = INTS``. */
268 reg->INTC = reg->INTS;
269 return k_ra8_ok;
270}
271
273{
274 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
276 return internal_wait_command_done(reg);
277}
278
280{
281 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
282 /* Populate CDBUF slot 0 per FSP ``r_ospi_b_direct_transfer``:
283 * CDT carries opcode + size encoding, CDA/CDD0/CDD1 are zeroed
284 * because there is no address phase and no payload. CDCTL1/CDCTL2
285 * are periodic-mode fields (PEREXP / PERMSK in FSP) -- leave
286 * them at zero for one-shot manual commands. */
290 0U,
292 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
296 return priv_ra8_xspi_kick_command(reg);
297}
298
323static ra8_err_t
324internal_issue_read_opcode(volatile r_xspi_regs_t* reg, uint8_t opcode, uint8_t resp_bytes)
325{
326 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
330 resp_bytes,
332 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
336 return priv_ra8_xspi_kick_command(reg);
337}
338
362 uint8_t opcode,
363 uint32_t addr,
364 uint8_t data_bytes,
365 uint8_t is_write)
366{
367 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
371 data_bytes,
372 is_write);
373 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
374 reg->CDBUF[k_ra8_xspi_cdbuf_idx_addr] = addr;
375}
376
407 uint32_t flash_addr,
408 uint8_t* buf,
409 uint32_t chunk)
410{
413 flash_addr,
414 (uint8_t)chunk,
416 const ra8_err_t wait = priv_ra8_xspi_kick_command(reg);
417 if (wait != k_ra8_ok) {
418 return wait;
419 }
420 for (uint32_t i = 0U; i < chunk; i++) {
421 const uint8_t cdbuf_word_idx =
422 (i < 4U) ? (uint8_t)k_ra8_xspi_cdbuf_idx_data0 : (uint8_t)k_ra8_xspi_cdbuf_idx_data1;
423 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
424 /* CDBUF data words: bytes 0..3 in CDD0, bytes 4..7 in CDD1. */
425 const uint32_t word = reg->CDBUF[cdbuf_word_idx];
426 buf[i] = (uint8_t)(word >> ((i % 4U) * 8U));
427 }
428 return k_ra8_ok;
429}
430
431ra8_err_t ra8_xspi_flash_read(uint8_t instance, uint32_t flash_addr, uint8_t* buf, uint32_t len)
432{
433 RA8_CHECK_NULL_PTR(buf, s_tag, "buf must not be nullptr");
434 if ((len == 0U) || (len > k_ra8_xspi_max_xfer)) {
436 }
437 volatile r_xspi_regs_t* reg = ra8_xspi(instance);
438 RA8_CHECK_NULL_PTR(reg, s_tag, "instance out of range");
439 const ra8_err_t rng = internal_flash_range_check(flash_addr, len);
440 if (rng != k_ra8_ok) {
441 return rng;
442 }
443
444 /* The manual-command engine carries only k_ra8_xspi_cdt_max_data_bytes
445 * (8) data bytes per transfer, so walk the request in 8-byte chunks.
446 * (HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986.) */
447 uint32_t off = 0U;
448 while (off < len) {
449 uint32_t chunk = len - off;
450 if (chunk > (uint32_t)k_ra8_xspi_cdt_max_data_bytes) {
451 chunk = (uint32_t)k_ra8_xspi_cdt_max_data_bytes;
452 }
453 const ra8_err_t e = internal_flash_read_chunk(reg, flash_addr + off, &buf[off], chunk);
454 if (e != k_ra8_ok) {
455 return e;
456 }
457 off += chunk;
458 }
459 return k_ra8_ok;
460}
461
507static ra8_err_t
508internal_flash_stage_program(volatile r_xspi_regs_t* reg, uint32_t flash_addr, uint32_t len)
509{
511 if (wren != k_ra8_ok) {
512 return wren;
513 }
514 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
515 /* Programme a JEDEC 0x02 page-program with 3-byte address. The
516 * outgoing byte count is encoded in CDT.DATASIZE (FSP semantics);
517 * leaving the periodic-mode CDCTL1/CDCTL2 PEREXP/PERMSK fields
518 * untouched. The kick (TRREQ) is deferred to the caller so that
519 * CDBUF[CDD0]/CDBUF[CDD1] can be loaded with the payload first --
520 * see this helper's @details for the rationale. */
521 const uint8_t chunk =
522 (len > (uint32_t)k_ra8_xspi_cdt_max_data_bytes) ? k_ra8_xspi_cdt_max_data_bytes : (uint8_t)len;
525 flash_addr,
526 chunk,
528 return k_ra8_ok;
529}
530
559static ra8_err_t internal_poll_wip_clear(uint8_t instance)
560{
561 for (uint32_t i = 0U; i < (uint32_t)k_ra8_flash_program_timeout_us; i++) {
562 uint8_t status = 0U;
563 const ra8_err_t e = ra8_xspi_flash_read_status(instance, &status);
564 if (e != k_ra8_ok) {
565 return e;
566 }
567 const bool wip_clear = ((status & (uint8_t)(1U << (uint8_t)k_ra8_flash_status_bit_wip)) == 0U);
568 if (wip_clear) {
569 return k_ra8_ok;
570 }
571 }
572 return k_ra8_err_timeout;
573}
574
607static void
608internal_xspi_stage_payload(volatile r_xspi_regs_t* reg, const uint8_t* data, uint32_t len)
609{
610 uint32_t data_lo = 0U;
611 uint32_t data_hi = 0U;
612 for (uint32_t i = 0U; i < len; i++) {
613 const uint32_t shift = (uint32_t)((i % 4U) * 8U);
614 if (i < 4U) {
615 data_lo |= ((uint32_t)data[i]) << shift;
616 } else {
617 data_hi |= ((uint32_t)data[i]) << shift;
618 }
619 }
620 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
621 reg->CDBUF[(uint8_t)k_ra8_xspi_cdbuf_idx_data0] = data_lo;
622 reg->CDBUF[(uint8_t)k_ra8_xspi_cdbuf_idx_data1] = data_hi;
623}
624
666 uint8_t instance,
667 uint32_t flash_addr,
668 const uint8_t* data,
669 uint32_t chunk)
670{
671 const ra8_err_t p = internal_flash_stage_program(reg, flash_addr, chunk);
672 if (p != k_ra8_ok) {
673 return p;
674 }
675 /* Stage CDD0/CDD1 BEFORE TRREQ (cf. internal_xspi_stage_payload). */
676 internal_xspi_stage_payload(reg, data, chunk);
677 const ra8_err_t kick = priv_ra8_xspi_kick_command(reg);
678 if (kick != k_ra8_ok) {
679 return kick;
680 }
681 return internal_poll_wip_clear(instance);
682}
683
685ra8_xspi_flash_program(uint8_t instance, uint32_t flash_addr, const uint8_t* data, uint32_t len)
686{
687 RA8_CHECK_NULL_PTR(data, s_tag, "data must not be nullptr");
688 if ((len == 0U) || (len > k_ra8_xspi_max_xfer)) {
690 }
691 volatile r_xspi_regs_t* reg = ra8_xspi(instance);
692 RA8_CHECK_NULL_PTR(reg, s_tag, "instance out of range");
693 const ra8_err_t rng = internal_flash_range_check(flash_addr, len);
694 if (rng != k_ra8_ok) {
695 return rng;
696 }
697
698 /* Each manual-command page-program carries <= 8 data bytes and a
699 * single PP must not cross a 256-byte NOR page boundary, so walk the
700 * payload in chunks clamped to both limits (HUM Ch 44 p 2986). This
701 * is what makes a 512-byte LevelX sector write round-trip instead of
702 * persisting only the first 8 bytes. */
703 uint32_t off = 0U;
704 while (off < len) {
705 const uint32_t addr = flash_addr + off;
706 const uint32_t page_left =
707 (uint32_t)k_ra8_xspi_page_len - (addr & ((uint32_t)k_ra8_xspi_page_len - 1U));
708 uint32_t chunk = len - off;
709 if (chunk > (uint32_t)k_ra8_xspi_cdt_max_data_bytes) {
710 chunk = (uint32_t)k_ra8_xspi_cdt_max_data_bytes;
711 }
712 if (chunk > page_left) {
713 chunk = page_left;
714 }
715 const ra8_err_t e = internal_flash_program_chunk(reg, instance, addr, &data[off], chunk);
716 if (e != k_ra8_ok) {
717 return e;
718 }
719 off += chunk;
720 }
721 return k_ra8_ok;
722}
723
724ra8_err_t ra8_xspi_flash_erase_sector(uint8_t instance, uint32_t flash_addr)
725{
726 volatile r_xspi_regs_t* reg = ra8_xspi(instance);
727 RA8_CHECK_NULL_PTR(reg, s_tag, "instance out of range");
728 const ra8_err_t rng = internal_flash_range_check(flash_addr, 0U);
729 if (rng != k_ra8_ok) {
730 return rng;
731 }
732
734 if (wren != k_ra8_ok) {
735 return wren;
736 }
737
738 /* Programme a JEDEC 0x20 sector-erase with 3-byte address.
739 * Erase has no payload, so DATASIZE=0 and TRTYPE=write. */
742 flash_addr,
743 0U,
745
746 const ra8_err_t wait = priv_ra8_xspi_kick_command(reg);
747 if (wait != k_ra8_ok) {
748 return wait;
749 }
750 return internal_poll_wip_clear(instance);
751}
752
753ra8_err_t ra8_xspi_flash_read_status(uint8_t instance, uint8_t* out_status)
754{
755 RA8_CHECK_NULL_PTR(out_status, s_tag, "out_status must not be nullptr");
756 volatile r_xspi_regs_t* reg = ra8_xspi(instance);
757 RA8_CHECK_NULL_PTR(reg, s_tag, "instance out of range");
758
759 /* RDSR returns 1 status byte; DATASIZE must be 1, not 0, or the
760 * controller never clocks the response and CDD0 stays stale. See
761 * IS25LX512M datasheet Ch 8.6. */
765 if (e != k_ra8_ok) {
766 return e;
767 }
768 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
769 *out_status = (uint8_t)(reg->CDBUF[(uint8_t)k_ra8_xspi_cdbuf_idx_data0] & k_xspi_byte_mask);
770 return k_ra8_ok;
771}
772
773ra8_err_t ra8_xspi_flash_read_id(uint8_t instance, uint32_t* out_id)
774{
775 RA8_CHECK_NULL_PTR(out_id, s_tag, "out_id must not be nullptr");
776 volatile r_xspi_regs_t* reg = ra8_xspi(instance);
777 RA8_CHECK_NULL_PTR(reg, s_tag, "instance out of range");
778
779 /* RDID returns 3 JEDEC bytes (MFR/TYPE/CAP); DATASIZE must be 3.
780 * IS25LX512M datasheet Ch 8.13 "Read Identification (RDID)". */
784 if (e != k_ra8_ok) {
785 return e;
786 }
787 /* HUM Ch 44 "Octal Serial Peripheral Interface (OSPI)" p 2986 */
788 /* JEDEC 0x9F returns MFR, MEMTYPE, CAPACITY in that byte order.
789 * Repack into ``(mfr << 16) | (type << 8) | cap`` as documented
790 * in the public API header. */
791 const uint32_t word = reg->CDBUF[(uint8_t)k_ra8_xspi_cdbuf_idx_data0];
792 *out_id = ((word & k_xspi_byte_mask) << 16U) | (((word >> 8U) & k_xspi_byte_mask) << 8U) |
793 ((word >> 16U) & k_xspi_byte_mask);
794 return k_ra8_ok;
795}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_hw_timeout
Hardware timed out waiting for a flag or handshake.
Definition ra8_err.h:304
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_timeout
Operation exceeded its time budget.
Definition ra8_err.h:188
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Bounded wait-flag primitives for RA8D2 HAL drivers.
xSPI / Octo-SPI controller register layout for the Renesas RA8D2
@ k_ra8_xspi_cdt_trtype_read
Read transaction (host samples).
@ k_ra8_xspi_cdt_trtype_write
Write transaction (host drives).
@ k_ra8_xspi_ints_mask_cmdcmp
CMDCMP – command complete.
@ k_ra8_xspi_cdt_addsize_3
3-byte address (24-bit JEDEC).
@ k_ra8_xspi_cdt_addsize_0
No address phase (e.g.
@ k_ra8_xspi_cdt_pos_datasize
DATASIZE[8..5] data bytes.
@ k_ra8_xspi_cdt_pos_cmd
CMD[31..16] JEDEC opcode.
@ k_ra8_xspi_cdt_pos_cmdsize
CMDSIZE[1..0] command bytes.
@ k_ra8_xspi_cdt_pos_trtype
TRTYPE[15] 0=read 1=write.
@ k_ra8_xspi_cdt_pos_addsize
ADDSIZE[4..2] address bytes.
@ k_ra8_xspi_cdt_mask_addsize
ADDSIZE field is 3 bits.
@ k_ra8_xspi_cdt_mask_datasize
DATASIZE field is 4 bits.
@ k_ra8_xspi_cdt_mask_trtype
TRTYPE field is 1 bit.
@ k_ra8_xspi_cdt_mask_cmdsize
CMDSIZE field is 2 bits.
@ k_ra8_xspi_cdt_mask_cmd
CMD[31..16] is a 16-bit field.
@ k_ra8_xspi_cdctl0_mask_trreq
TRREQ (kick off xfer).
static volatile r_xspi_regs_t * ra8_xspi(uint8_t instance)
Get pointer to xSPI instance N (0..1).
@ k_ra8_xspi_page_len
Page size of standard NOR flash parts.
@ k_ra8_xspi_max_xfer
Maximum bytes per flash read/program call.
@ k_ra8_xspi_cdt_cmdsize_1
1-byte command (standard SPI).
xSPI / Octo-SPI driver (flash read/program/erase + ID/status)
static ra8_err_t internal_flash_stage_program(volatile r_xspi_regs_t *reg, uint32_t flash_addr, uint32_t len)
Stage WREN + page-program header (CDT + CDA only) without kicking.
ra8_spi_flash_resp_bytes_t
Per-opcode response-byte counts for read-direction commands.
@ k_ra8_xspi_resp_bytes_jedec
RDID returns MFR+TYPE+CAP.
@ k_ra8_xspi_resp_bytes_status
RDSR returns 1 status byte.
static void internal_build_chunk_header(volatile r_xspi_regs_t *reg, uint8_t opcode, uint32_t addr, uint8_t data_bytes, uint8_t is_write)
Build CDBUF[0] for a single CDD0/CDD1 chunk of an opcode + addr.
ra8_err_t priv_ra8_xspi_kick_command(volatile r_xspi_regs_t *reg)
Kick a prepared manual-command transfer by raising TRREQ.
static ra8_err_t internal_poll_wip_clear(uint8_t instance)
Poll the SPI-flash Status Register until Write-In-Progress clears.
ra8_err_t ra8_xspi_flash_program(uint8_t instance, uint32_t flash_addr, const uint8_t *data, uint32_t len)
Program (write) len bytes at flash_addr.
static void internal_xspi_stage_payload(volatile r_xspi_regs_t *reg, const uint8_t *data, uint32_t len)
Stage the page-program payload into CDBUF[CDD0] / CDBUF[CDD1].
xspi_mask_t
Low-byte mask for status/JEDEC-id extraction.
@ k_xspi_byte_mask
XSPI byte mask.
static ra8_err_t internal_wait_command_done(volatile r_xspi_regs_t *reg)
Wait for a manual XSPI command to retire, then clear its status bits.
ra8_err_t priv_ra8_xspi_issue_simple_opcode(volatile r_xspi_regs_t *reg, uint8_t opcode)
Build CDBUF[0] for a 1-byte opcode with no address / no data.
ra8_xspi_cdt_limits_t
Per-transaction byte-size limits encodable in CDT.
@ k_ra8_xspi_cdt_max_data_bytes
CDD0 + CDD1 = 8 bytes per slot.
ra8_spi_flash_op_t
Standard JEDEC NOR-flash command opcodes used by this driver.
@ k_ra8_spi_flash_op_page_program
0x02 page program.
@ k_ra8_spi_flash_op_read_id
0x9F JEDEC ID read.
@ k_ra8_spi_flash_op_read_status
0x05 read status reg.
@ k_ra8_spi_flash_op_read
0x03 normal read.
@ k_ra8_spi_flash_op_erase_sector
0x20 sector erase.
@ k_ra8_spi_flash_op_write_enable
0x06 WREN.
ra8_err_t ra8_xspi_flash_read(uint8_t instance, uint32_t flash_addr, uint8_t *buf, uint32_t len)
Read len bytes from external flash into buf.
static ra8_err_t internal_issue_read_opcode(volatile r_xspi_regs_t *reg, uint8_t opcode, uint8_t resp_bytes)
Issue a 1-byte opcode that returns 1..8 response data bytes.
static ra8_err_t internal_flash_program_chunk(volatile r_xspi_regs_t *reg, uint8_t instance, uint32_t flash_addr, const uint8_t *data, uint32_t chunk)
Program one page-program slot (<= 8 bytes) at flash_addr.
ra8_err_t ra8_xspi_flash_read_status(uint8_t instance, uint8_t *out_status)
Read the flash Status Register (opcode 0x05).
ra8_flash_status_bit_t
Bit positions in the SPI flash Status Register.
@ k_ra8_flash_status_bit_wip
Write-In-Progress (busy).
@ k_ra8_flash_status_bit_wel
Write Enable Latch.
ra8_xspi_addr_space_t
Reachable flash address space for the 3-byte JEDEC commands.
@ k_ra8_xspi_addr_space_3byte
2^24: 3-byte address limit.
ra8_err_t ra8_xspi_flash_erase_sector(uint8_t instance, uint32_t flash_addr)
Erase the 4 KiB sector containing flash_addr.
static ra8_err_t internal_flash_read_chunk(volatile r_xspi_regs_t *reg, uint32_t flash_addr, uint8_t *buf, uint32_t chunk)
Read one manual-command slot (<= 8 bytes) from flash into buf.
static ra8_err_t internal_flash_range_check(uint32_t flash_addr, uint32_t len)
Validate a [flash_addr, flash_addr + len) window against the 3-byte JEDEC address space.
ra8_err_t ra8_xspi_flash_read_id(uint8_t instance, uint32_t *out_id)
Read the JEDEC ID (opcode 0x9F), returning 24 bits in a uint32_t.
static uint32_t internal_make_cdt(uint8_t opcode, uint8_t cmd_bytes, uint8_t addr_bytes, uint8_t data_bytes, uint8_t is_write)
Encode a manual-command CDT word (opcode + size/type fields).
Module-private seam shared between the ra8_xspi translation units.
@ k_ra8_xspi_cdbuf_idx_data1
CDBUF[3] CDD1 – data bytes 4..7.
@ k_ra8_xspi_cdbuf_idx_data0
CDBUF[2] CDD0 – data bytes 0..3.
@ k_ra8_xspi_cdbuf_idx_cdt
CDBUF[0] CDT – type/opcode word.
@ k_ra8_xspi_cdbuf_idx_addr
CDBUF[1] CDA – flash address.
@ k_ra8_xspi_cmd_spin
CMDCMP poll budget for a single manual-command transfer.
@ k_ra8_flash_program_timeout_us
WIP-poll iteration cap for program / erase finish.
xSPI per-instance register window.
volatile uint32_t INTC
+0x194 Interrupt clear (W1C).
volatile uint32_t INTS
+0x190 Interrupt status (CMDCMP=b0).
volatile uint32_t CDCTL0
+0x070 Manual cmd ctl 0 (TRREQ/CSSEL)
volatile uint32_t CDBUF[16]
+0x080..+0x0BC Command buf (4x4 u32).