ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
lx_nor_driver_ra8_xspi.c File Reference

LevelX NOR driver implementation backed by the RA8 ra8_xspi HAL. More...

#include "lx_nor_driver_ra8_xspi.h"
#include <stdint.h>
#include "lx_api.h"
#include "ra8_attributes.h"
#include "ra8_board_ek_ra8d2.h"
#include "ra8_err.h"
#include "ra8_log.h"
#include "ra8_pfs_regs.h"
#include "ra8_port_constants.h"
#include "ra8_time.h"
#include "ra8_xspi.h"
Include dependency graph for lx_nor_driver_ra8_xspi.c:

Go to the source code of this file.

Data Structures

struct  ra8_xspi_rdid_observation_t
 JLink-readable snapshot of the most recent RDID probe. More...
struct  ra8_xspi_pin_observation_t
 One row per OCTA pin captured AFTER ra8_board_xspi_pins_init. More...
struct  ra8_xspi_pin_ref_t
 Board-side reference (port, pin) for the 12 OCTA pad slots. More...

Enumerations

enum  ra8_lx_jedec_id_t : uint32_t {
  k_ra8_lx_jedec_mfr = 0x9DU ,
  k_ra8_lx_jedec_type = 0x5AU ,
  k_ra8_lx_jedec_capacity = 0x1AU ,
  k_ra8_lx_jedec_expected = 0x9D5A1AUL
}
 Expected JEDEC ID triplet for the EK-RA8D2 IS25LX512M-JHLE chip. More...
enum  ra8_lx_nor_constants_t : uint32_t {
  k_ra8_lx_xspi_instance = 0U ,
  k_ra8_lx_nor_total_blocks = 64U ,
  k_ra8_lx_nor_block_bytes = 4096U ,
  k_ra8_lx_nor_words_per_block = 1024U ,
  k_ra8_lx_nor_word_bytes = 4U
}
 Compile-time constants for the xSPI <-> LevelX bridge. More...
enum  ra8_lx_nor_base_t : uintptr_t { k_ra8_lx_nor_base_addr = 0x10000000U }
 Synthetic flash base address handed to LevelX. More...
enum  ra8_xspi_stage_t : uint32_t {
  k_ra8_xspi_stage_pins = 1U ,
  k_ra8_xspi_stage_init_8d = 2U ,
  k_ra8_xspi_stage_reset_8d = 3U ,
  k_ra8_xspi_stage_init_1s = 4U ,
  k_ra8_xspi_stage_reset_1s = 5U ,
  k_ra8_xspi_stage_rdid = 6U ,
  k_ra8_xspi_stage_done = 7U
}
 Bring-up stage markers stamped into g_ra8_xspi_rdid_observed.stage. More...
enum  ra8_xspi_rdid_magic_t : uint32_t { k_ra8_xspi_rdid_magic = 0x44494452UL }
 Sentinel value distinguishing a written observation from cold-boot zero / stale RAM. More...
enum  ra8_xspi_pin_count_t : uint8_t { k_ra8_xspi_pin_count = 12U }
 Number of OCTA bus pin slots in g_ra8_xspi_pin_observed. More...
enum  ra8_lx_pin_diag_t : uint8_t {
  k_ra8_lx_pin_unobserved = 0xFFU ,
  k_ra8_lx_pfs_psel_mask = 0x1FU
}
 Constants for the diagnostic xSPI pin-state capture. More...
enum  ra8_xspi_reset_timing_t : uint32_t { k_ra8_xspi_reset_settle_ms = 1U }
 Post-software-reset settle time required by the IS25LX512M. More...
enum  ra8_xspi_reset_form_t : uint8_t {
  k_ra8_xspi_reset_form_1s = 1U ,
  k_ra8_xspi_reset_form_8d = 2U
}
 Width of the opcode pair shipped to ra8_xspi_software_reset. More...

Functions

static uint32_t internal_flash_offset_bytes (ULONG *flash_address)
static UINT internal_nor_read (ULONG *flash_address, ULONG *destination, ULONG words)
 LevelX read callback: copy words ULONGs from flash to RAM.
static UINT internal_nor_write (ULONG *flash_address, ULONG *source, ULONG words)
 LevelX write callback: program words ULONGs from RAM to flash.
static UINT internal_nor_block_erase (ULONG block, ULONG erase_count)
 LevelX block-erase callback: erase one 4 KiB sector by index.
static UINT internal_nor_block_erased_verify (ULONG block)
 LevelX block-erased-verify callback: confirm a sector is 0xFF.
static void internal_capture_xspi_pin_state (void)
 Capture the post-init PFS state of every OCTA pin.
static void internal_stamp_observed_start (void)
 Stamp the observation breadcrumb at the start of a bring-up call.
static UINT internal_reset_phase_8d (void)
 Phase A – punch the IS25LX512M out of any 8D-OPI mode.
static UINT internal_reset_phase_1s (void)
 Phase B – switch the controller to 1S-1S-1S and reset again.
static UINT internal_probe_rdid (void)
 Probe RDID and confirm the IS25LX512M is responsive.
static UINT internal_bus_init_once (void)
 Bring the OCTA bus up (pins + controller) on first call.
UINT lx_nor_driver_ra8_xspi_initialize (LX_NOR_FLASH *nor_flash)
 LevelX NOR driver-initialise entry point bridging onto ra8_xspi.

Variables

static const char * s_lx_xspi_tag = "LX_XSPI"
 Logging tag for the LevelX <-> ra8_xspi bridge.
static ULONG s_ra8_lx_nor_sector_buffer [LX_NOR_SECTOR_SIZE]
 Per-driver scratch buffer LevelX uses for sector mapping reads.
ra8_xspi_rdid_observation_t g_ra8_xspi_rdid_observed
 JLink-readable observation of the last RDID probe.
ra8_xspi_pin_observation_t g_ra8_xspi_pin_observed [k_ra8_xspi_pin_count]
 JLink-readable PSEL readback for the 12 OCTA pin slots.
static const ra8_xspi_pin_ref_t s_ra8_xspi_pin_refs [k_ra8_xspi_pin_count]
 Static reference list of OCTA (port, pin) pairs.
static bool s_xspi_bus_ready = false
 One-shot guard so we only run the bus bring-up once.

Detailed Description

LevelX NOR driver implementation backed by the RA8 ra8_xspi HAL.

Tag
[Ring 4 / PORT] {World: NS}

Implements lx_nor_driver_ra8_xspi_initialize and the four LevelX NOR driver callbacks (read / write / block_erase / block_erased_verify) by translating each LevelX ULONG-word request into a matching byte-oriented call into libs/ra8_hal/inc/ra8_xspi.h running against the on-board EK-RA8D2 ISSI IS25LX512M octal-SPI flash chip.

Address translation:

LevelX hands the read / write callbacks a ULONG *flash_address which is a pointer into lx_nor_flash_base_address. We pick a non-zero synthetic base (k_ra8_lx_nor_base) so that LevelX can use the pointer as an opaque cookie, then convert back to a flash byte offset via (addr - base) * sizeof(ULONG) in the read / write paths and block * 4 KiB in the block-erase path.

Sector / block geometry:

  • LevelX physical sector size = LX_NOR_SECTOR_SIZE * sizeof(ULONG) = 512 bytes (LevelX default).
  • LevelX block size = IS25LX512M erase-sector size = 4 KiB.
  • Words per block = 4096 / sizeof(ULONG) = 1024.
  • We expose k_ra8_lx_nor_total_blocks blocks (256 KiB total) – the first 256 KiB of the 64 MiB flash is reserved for LevelX's wear-levelled partition. The remainder of the chip stays untouched for XIP code or other firmware uses.

Definition in file lx_nor_driver_ra8_xspi.c.

Enumeration Type Documentation

◆ ra8_lx_jedec_id_t

enum ra8_lx_jedec_id_t : uint32_t

Expected JEDEC ID triplet for the EK-RA8D2 IS25LX512M-JHLE chip.

The IS25LX512M datasheet Ch 8.13 "Read Identification (RDID)" lists:

  • manufacturer ID = 0x9D (ISSI)
  • memory type = 0x5A (IS25LX family)
  • capacity code = 0x1A (512 Mbit) The ra8_xspi_flash_read_id helper packs these as (mfr << 16) | (type << 8) | cap, giving 0x9D5A1A. We assert on the packed value during bring-up and surface the actual value over the log so a wrong-chip / wrong-protocol bring-up is loud rather than a silent LX_ERROR from lx_nor_flash_format.
Enumerator
k_ra8_lx_jedec_mfr 

ISSI manufacturer ID.

k_ra8_lx_jedec_type 

IS25LX memory-type code.

k_ra8_lx_jedec_capacity 

512 Mbit capacity code.

k_ra8_lx_jedec_expected 

Packed RDID expected.

Definition at line 71 of file lx_nor_driver_ra8_xspi.c.

◆ ra8_lx_nor_base_t

enum ra8_lx_nor_base_t : uintptr_t

Synthetic flash base address handed to LevelX.

LevelX treats lx_nor_flash_base_address as an opaque pointer cookie – it adds offsets to it in word units when computing the flash_address argument to the driver callbacks, but never dereferences it directly. We therefore pick an arbitrary non-NULL value (the first 256 KiB of the chip is the partition we reserve for LevelX) and recover the byte offset inside each callback via (addr - base) * sizeof(ULONG).

Enumerator
k_ra8_lx_nor_base_addr 

Synthetic base for LevelX-managed window inside the flash.

Definition at line 116 of file lx_nor_driver_ra8_xspi.c.

◆ ra8_lx_nor_constants_t

enum ra8_lx_nor_constants_t : uint32_t

Compile-time constants for the xSPI <-> LevelX bridge.

Enumerator
k_ra8_lx_xspi_instance 

xSPI instance routed to the EK-RA8D2 IS25LX512M flash chip.

k_ra8_lx_nor_total_blocks 

Number of LevelX blocks exposed to wear-levelling.

64 blocks * 4 KiB/block = 256 KiB partition. Sized to be small enough that lx_nor_flash_format() finishes quickly during the demo and large enough that LX_NOR_SECTOR_MAPPING_CACHE_SIZE (16) does not dominate.

k_ra8_lx_nor_block_bytes 

IS25LX512M erase-sector size (opcode 0x20 / sector erase).

k_ra8_lx_nor_words_per_block 

LevelX words per block (= block_bytes / sizeof(ULONG)).

k_ra8_lx_nor_word_bytes 

Bytes per ULONG word (LevelX uses 4-byte ULONGs on this target).

Definition at line 81 of file lx_nor_driver_ra8_xspi.c.

◆ ra8_lx_pin_diag_t

enum ra8_lx_pin_diag_t : uint8_t

Constants for the diagnostic xSPI pin-state capture.

Enumerator
k_ra8_lx_pin_unobserved 

Sentinel before PFS is read.

k_ra8_lx_pfs_psel_mask 

PSEL is the low 5 bits of the PFS.

Definition at line 564 of file lx_nor_driver_ra8_xspi.c.

◆ ra8_xspi_pin_count_t

enum ra8_xspi_pin_count_t : uint8_t

Number of OCTA bus pin slots in g_ra8_xspi_pin_observed.

11 active rows (CS, CK, DQS, DQ0..DQ7) plus one reserved sentinel row so the array size matches the comment in ra8_board_ek_ra8d2.c::s_xspi_octa_pins. RESET_L is excluded – it is plain GPIO, not a peripheral function.

Enumerator
k_ra8_xspi_pin_count 

CS + CK + DQS + DQ0..DQ7 + 1 spare.

Definition at line 459 of file lx_nor_driver_ra8_xspi.c.

◆ ra8_xspi_rdid_magic_t

enum ra8_xspi_rdid_magic_t : uint32_t

Sentinel value distinguishing a written observation from cold-boot zero / stale RAM.

Picked to be ASCII "RDID" (little-endian read order) so the operator can recognise the field in a mem32 dump at a glance.

Enumerator
k_ra8_xspi_rdid_magic 

'R','D','I','D' little-endian.

Definition at line 414 of file lx_nor_driver_ra8_xspi.c.

◆ ra8_xspi_reset_form_t

enum ra8_xspi_reset_form_t : uint8_t

Width of the opcode pair shipped to ra8_xspi_software_reset.

IS25LX512M Ch 7.3 "Operating Protocols" p 27 – 1S-1S-1S accepts 1-byte JEDEC opcodes; 8D-8D-8D OPI requires the opcode followed by its 1's-complement (so the device sees 2 bytes per "opcode" on the 8 DQ lines on both clock edges).

Enumerator
k_ra8_xspi_reset_form_1s 

1-byte opcode for 1S-1S-1S.

k_ra8_xspi_reset_form_8d 

Opcode + complement for 8D-8D-8D.

Definition at line 652 of file lx_nor_driver_ra8_xspi.c.

◆ ra8_xspi_reset_timing_t

enum ra8_xspi_reset_timing_t : uint32_t

Post-software-reset settle time required by the IS25LX512M.

IS25LX512M datasheet Ch 8.21 "Reset (RST)" p 39 specifies tRPH (reset processing time) = 50 us max before the next chip-select is allowed. We use a 1 ms ra8_delay_ms because that is the smallest delay primitive available in ra8_core/ra8_time.h and 1 ms >> 50 us with 20x headroom.

Enumerator
k_ra8_xspi_reset_settle_ms 

>= tRPH (50 us).

Definition at line 638 of file lx_nor_driver_ra8_xspi.c.

◆ ra8_xspi_stage_t

enum ra8_xspi_stage_t : uint32_t

Bring-up stage markers stamped into g_ra8_xspi_rdid_observed.stage.

Lets a JLink operator tell at a glance how far the bring-up made it before either succeeding (k_ra8_xspi_stage_done) or returning an error.

Enumerator
k_ra8_xspi_stage_pins 

Pin routing in progress.

k_ra8_xspi_stage_init_8d 

xSPI init in 8D mode.

k_ra8_xspi_stage_reset_8d 

Software reset in 8D.

k_ra8_xspi_stage_init_1s 

xSPI init in 1S mode.

k_ra8_xspi_stage_reset_1s 

Software reset in 1S.

k_ra8_xspi_stage_rdid 

RDID probe in flight.

k_ra8_xspi_stage_done 

Bring-up succeeded.

Definition at line 395 of file lx_nor_driver_ra8_xspi.c.

Function Documentation

◆ internal_bus_init_once()

UINT internal_bus_init_once ( void )
static

Bring the OCTA bus up (pins + controller) on first call.

Idempotent: the first call routes the OCTA pins, ungates the xSPI module-stop bit, walks the IS25LX512M reset sequence and confirms the device with an RDID probe, then latches s_xspi_bus_ready. Every later call returns LX_SUCCESS immediately, so each LevelX entry point can open with this guard without tracking bring-up itself.

Returns
LX_SUCCESS if the bus is ready, LX_ERROR otherwise.
Return values
LX_SUCCESSBus ready – either just brought up, or already up.
LX_ERRORPin routing, reset or the RDID probe failed; the ready latch stays clear so a later call retries.
Precondition
ra8_infrastructure_init has run (pin validator alive).
Called from a single bring-up context (no concurrent LevelX entry).
Postcondition
On success the IS25LX512M is out of reset, OCTA pins are routed to PSEL=0x1C, the xSPI controller MSTP gate is open, LIOCFGCS[0] is in 1S-1S-1S mode, and the chip has reported the expected RDID triplet 0x9D 0x5A 0x1A.
On success s_xspi_bus_ready is set, so later calls short-circuit.
Note
Not thread-safe; LevelX drives this from a single context.
Since
0.1.0

Definition at line 844 of file lx_nor_driver_ra8_xspi.c.

References g_ra8_xspi_rdid_observed, internal_capture_xspi_pin_state(), internal_probe_rdid(), internal_reset_phase_1s(), internal_reset_phase_8d(), internal_stamp_observed_start(), k_ra8_ok, k_ra8_xspi_stage_done, ra8_board_xspi_pins_init(), RA8_INTERNAL, ra8_log_error, s_lx_xspi_tag, and s_xspi_bus_ready.

Referenced by lx_nor_driver_ra8_xspi_initialize().

◆ internal_capture_xspi_pin_state()

void internal_capture_xspi_pin_state ( void )
static

Capture the post-init PFS state of every OCTA pin.

Iterates s_ra8_xspi_pin_refs and reads each pin's PmnPFS register, extracting the 5-bit PSEL field and the PMR bit. Called AFTER ra8_board_xspi_pins_init so any mis-routed pin where PSEL != 0x1C is recorded for JLink readout.

Precondition
ra8_board_xspi_pins_init has been called.
IOPORT module clock is on.
Postcondition
g_ra8_xspi_pin_observed[0..k_ra8_xspi_pin_count-1] filled.
No state outside that array is modified.
Note
Not thread-safe; called once from boot.
Since
0.1.0

Definition at line 588 of file lx_nor_driver_ra8_xspi.c.

References g_ra8_xspi_pin_observed, k_ra8_lx_pfs_psel_mask, k_ra8_lx_pin_unobserved, k_ra8_pfs_bit_psel0, k_ra8_pfs_mask_pmr, k_ra8_pin_max, k_ra8_port_max, k_ra8_xspi_pin_count, pin, RA8_INTERNAL, ra8_pfs_pmn(), and s_ra8_xspi_pin_refs.

Referenced by internal_bus_init_once().

◆ internal_flash_offset_bytes()

uint32_t internal_flash_offset_bytes ( ULONG * flash_address)
static

Definition at line 138 of file lx_nor_driver_ra8_xspi.c.

References k_ra8_lx_nor_base_addr, and RA8_INTERNAL.

Referenced by internal_nor_read(), and internal_nor_write().

◆ internal_nor_block_erase()

UINT internal_nor_block_erase ( ULONG block,
ULONG erase_count )
static

LevelX block-erase callback: erase one 4 KiB sector by index.

LevelX numbers blocks 0..(lx_nor_flash_total_blocks - 1). We convert the block index to a flash byte offset by multiplying by the IS25LX512M sector size (4 KiB) and call ra8_xspi_flash_erase_sector. The HAL handles WREN -> SE -> WIP-poll internally. The erase_count argument is ignored – LevelX only uses it for its own bookkeeping in higher layers.

Parameters
[in]blockBlock index (0..k_ra8_lx_nor_total_blocks - 1).
[in]erase_countLevelX-side erase counter (unused here).
Returns
LX_SUCCESS on success, LX_ERROR on xSPI failure.
Precondition
block < k_ra8_lx_nor_total_blocks.
Postcondition
On success the targeted 4 KiB sector reads as 0xFF on the next call.
Note
Not thread-safe; LevelX serialises driver calls.
Since
0.1.0
Return values
0Success or default value.
Precondition
Module has been initialized.
Postcondition
Side effects bounded to documented state.

Definition at line 267 of file lx_nor_driver_ra8_xspi.c.

References k_ra8_lx_nor_block_bytes, k_ra8_lx_nor_total_blocks, k_ra8_lx_xspi_instance, k_ra8_ok, RA8_INTERNAL, and ra8_xspi_flash_erase_sector().

Referenced by lx_nor_driver_ra8_xspi_initialize().

◆ internal_nor_block_erased_verify()

UINT internal_nor_block_erased_verify ( ULONG block)
static

LevelX block-erased-verify callback: confirm a sector is 0xFF.

Reads the block back through ra8_xspi_flash_read in k_ra8_xspi_max_xfer chunks (one full sector fits in a single 4 KiB transfer) into the per-driver scratch buffer and checks every ULONG word equals LX_ALL_ONES (0xFFFFFFFF). Returns LX_SUCCESS only if every word verifies erased.

Parameters
[in]blockBlock index to verify.
Returns
LX_SUCCESS if the block is fully erased, otherwise LX_ERROR.
Precondition
block < k_ra8_lx_nor_total_blocks.
Postcondition
On success the entire block reads as 0xFFFFFFFF.
Note
Not thread-safe; LevelX serialises driver calls.
Since
0.1.0
Return values
0Success or default value.
Precondition
Module has been initialized.
Postcondition
Side effects bounded to documented state.

Definition at line 308 of file lx_nor_driver_ra8_xspi.c.

References k_ra8_lx_nor_block_bytes, k_ra8_lx_nor_total_blocks, k_ra8_lx_nor_word_bytes, k_ra8_lx_nor_words_per_block, k_ra8_lx_xspi_instance, k_ra8_ok, RA8_INTERNAL, ra8_xspi_flash_read(), and s_ra8_lx_nor_sector_buffer.

Referenced by lx_nor_driver_ra8_xspi_initialize().

◆ internal_nor_read()

UINT internal_nor_read ( ULONG * flash_address,
ULONG * destination,
ULONG words )
static

LevelX read callback: copy words ULONGs from flash to RAM.

Translates the word-oriented LevelX request into a single byte-wise call to ra8_xspi_flash_read. ra8_xspi_flash_read caps each call at k_ra8_xspi_max_xfer (4096 bytes); LevelX never asks for more than one block (4 KiB) per callback, so the cap is never exceeded.

Parameters
[in]flash_addressSource address (LevelX cookie).
[out]destinationDestination RAM buffer.
[in]wordsNumber of ULONG words to copy.
Returns
LX_SUCCESS on success, LX_ERROR on xSPI failure.
Precondition
flash_address != NULL and destination != NULL.
words > 0.
Postcondition
On success the destination buffer holds words * 4 bytes of flash data.
Note
Not thread-safe; LevelX serialises driver calls.
Since
0.1.0
Return values
0Success or default value.
Postcondition
Side effects bounded to documented state.

Definition at line 178 of file lx_nor_driver_ra8_xspi.c.

References internal_flash_offset_bytes(), k_ra8_lx_nor_word_bytes, k_ra8_lx_xspi_instance, k_ra8_ok, RA8_INTERNAL, and ra8_xspi_flash_read().

Referenced by lx_nor_driver_ra8_xspi_initialize().

◆ internal_nor_write()

UINT internal_nor_write ( ULONG * flash_address,
ULONG * source,
ULONG words )
static

LevelX write callback: program words ULONGs from RAM to flash.

Forwards the word-oriented LevelX request to ra8_xspi_flash_program. The HAL handles the JEDEC write-enable -> page-program -> WIP-poll dance internally and chunks arbitrary lengths into per-page (256-byte) manual-command transfers, so a full LX_NOR_SECTOR_SIZE * sizeof(ULONG) = 512-byte sector write (two pages) round-trips intact; LevelX's 4-byte metadata writes are a single chunk.

Parameters
[in]flash_addressDestination address (LevelX cookie).
[in]sourceSource RAM buffer.
[in]wordsNumber of ULONG words to program.
Returns
LX_SUCCESS on success, LX_ERROR on xSPI failure.
Precondition
flash_address != NULL and source != NULL.
words > 0.
Postcondition
On success the targeted byte range has been programmed.
Note
Not thread-safe; LevelX serialises driver calls.
Since
0.1.0
Return values
0Success or default value.
Postcondition
Side effects bounded to documented state.

Definition at line 223 of file lx_nor_driver_ra8_xspi.c.

References internal_flash_offset_bytes(), k_ra8_lx_nor_word_bytes, k_ra8_lx_xspi_instance, k_ra8_ok, RA8_INTERNAL, and ra8_xspi_flash_program().

Referenced by lx_nor_driver_ra8_xspi_initialize().

◆ internal_probe_rdid()

UINT internal_probe_rdid ( void )
static

Probe RDID and confirm the IS25LX512M is responsive.

Reads the JEDEC triplet. If the controller still cannot read it back after the dual-mode software reset, every downstream WREN / PP / SE will also fail – so we bail loudly. The expected value for the IS25LX512M-JHLE on EK-RA8D2 v1 is {0x9D, 0x5A, 0x1A} per datasheet Ch 8.13 p 36. A mismatch usually means a pin-routing issue (CS / DQ not actually on PSEL=0x1C).

Returns
LX_SUCCESS if RDID matches; LX_ERROR otherwise.
Return values
LX_SUCCESSJEDEC ID equals k_ra8_lx_jedec_expected.
LX_ERRORra8_xspi_flash_read_id failed or ID mismatched.
Precondition
Controller is in 1S-1S-1S mode (Phase B completed).
IS25LX512M had at least k_ra8_xspi_reset_settle_ms to settle.
Postcondition
g_ra8_xspi_rdid_observed.{rid_err,jedec_id} are updated.
On success, the chip is confirmed responsive and ready for erase/program/read opcodes.
Note
Not thread-safe; bus owner serialises all calls.
Since
0.1.0

Definition at line 799 of file lx_nor_driver_ra8_xspi.c.

References g_ra8_xspi_rdid_observed, k_ra8_lx_jedec_expected, k_ra8_lx_xspi_instance, k_ra8_ok, k_ra8_xspi_stage_rdid, RA8_INTERNAL, ra8_log_error_val, ra8_log_info_val, ra8_xspi_flash_read_id(), and s_lx_xspi_tag.

Referenced by internal_bus_init_once().

◆ internal_reset_phase_1s()

UINT internal_reset_phase_1s ( void )
static

Phase B – switch the controller to 1S-1S-1S and reset again.

Restores the chip's power-on default protocol (the one the rest of the driver uses) and issues the 1-byte RSTEN/RST pair. After this any chip that survived Phase A in 1S mode is also in a known reset state.

Returns
LX_SUCCESS if both the controller switch and the reset opcodes succeeded; LX_ERROR if ra8_xspi_init failed.
Return values
LX_SUCCESSController is in 1S mode; reset opcodes dispatched.
LX_ERRORra8_xspi_init rejected the 1S protocol switch.
Precondition
Phase A (internal_reset_phase_8d) has been attempted.
XSPI pins are configured (ra8_board_xspi_pins_init succeeded).
Postcondition
g_ra8_xspi_rdid_observed.reset_1s_err records the HAL outcome.
Controller is left in 1S-1S-1S protocol mode.
Note
Not thread-safe; bus owner serialises all calls.
Since
0.1.0

Definition at line 759 of file lx_nor_driver_ra8_xspi.c.

References g_ra8_xspi_rdid_observed, k_ra8_lx_xspi_instance, k_ra8_ok, k_ra8_xspi_lio_1s1s1s, k_ra8_xspi_reset_form_1s, k_ra8_xspi_reset_settle_ms, k_ra8_xspi_stage_init_1s, k_ra8_xspi_stage_reset_1s, ra8_delay_ms(), RA8_INTERNAL, ra8_log_error, ra8_xspi_init(), ra8_xspi_software_reset(), and s_lx_xspi_tag.

Referenced by internal_bus_init_once().

◆ internal_reset_phase_8d()

UINT internal_reset_phase_8d ( void )
static

Phase A – punch the IS25LX512M out of any 8D-OPI mode.

The volatile-config register that selects 8D mode survives a Cortex-M85 warm-reset because power was never removed, so even after the PFS reset pulse the chip may still be in OPI. The only opcode it understands in that state is the 8D RSTEN/RST pair (0x66 0x99 0x99 0x66). Sending those first with the controller in 8D mode recovers an OPI-stuck chip; a chip that was in 1S simply ignores the garbage and gets recovered by Phase B.

Returns
LX_SUCCESS if the controller switched to 8D and the reset opcodes were dispatched; LX_ERROR if ra8_xspi_init rejected the 8D mode switch.
Return values
LX_SUCCESSController is in 8D mode; reset opcodes dispatched.
LX_ERRORra8_xspi_init rejected the 8D protocol switch.
Precondition
internal_stamp_observed_start has been called for this bring-up.
XSPI pins are configured (ra8_board_xspi_pins_init succeeded).
Postcondition
g_ra8_xspi_rdid_observed.reset_8d_err records the HAL outcome.
Controller is left in 8D mode regardless of the reset result.
Note
ra8_xspi_software_reset may legitimately time out here when the chip is actually in 1S; we tolerate the failure and record it in reset_8d_err instead of bailing.
Not thread-safe; bus owner serialises all calls.
Since
0.1.0

Definition at line 718 of file lx_nor_driver_ra8_xspi.c.

References g_ra8_xspi_rdid_observed, k_ra8_lx_xspi_instance, k_ra8_ok, k_ra8_xspi_lio_8d8d8d, k_ra8_xspi_reset_form_8d, k_ra8_xspi_reset_settle_ms, k_ra8_xspi_stage_init_8d, k_ra8_xspi_stage_reset_8d, ra8_delay_ms(), RA8_INTERNAL, ra8_log_error, ra8_xspi_init(), ra8_xspi_software_reset(), and s_lx_xspi_tag.

Referenced by internal_bus_init_once().

◆ internal_stamp_observed_start()

void internal_stamp_observed_start ( void )
static

Stamp the observation breadcrumb at the start of a bring-up call.

Writes the magic word, bumps call_count, and zeroes the sub-stage error fields BEFORE any HAL call so a JLink memory dump can show exactly how far the bring-up progressed even if the controller hangs mid-step.

Precondition
g_ra8_xspi_rdid_observed is accessible (always; static SRAM).
Called from the bus-init path before any HAL XSPI call.
Postcondition
g_ra8_xspi_rdid_observed.stage == k_ra8_xspi_stage_pins.
g_ra8_xspi_rdid_observed.magic == k_ra8_xspi_rdid_magic and call_count is incremented by one.
Note
Not thread-safe; the LevelX NOR driver serialises all bus accesses through a single owner task.
Since
0.1.0

Definition at line 677 of file lx_nor_driver_ra8_xspi.c.

References g_ra8_xspi_rdid_observed, k_ra8_ok, k_ra8_xspi_rdid_magic, k_ra8_xspi_stage_pins, and RA8_INTERNAL.

Referenced by internal_bus_init_once().

◆ lx_nor_driver_ra8_xspi_initialize()

UINT lx_nor_driver_ra8_xspi_initialize ( LX_NOR_FLASH * nor_flash)

LevelX NOR driver-initialise entry point bridging onto ra8_xspi.

Pass this function as the nor_driver_initialize argument to lx_nor_flash_open() or lx_nor_flash_format(). LevelX invokes it exactly once per open / format call to discover the geometry of the flash and to populate the four lx_nor_flash_driver_* function pointers in the supplied control block.

Driver mapping:

LevelX callback Action
lx_nor_flash_driver_read ra8_xspi_flash_read(0, off, buf, words*4)
lx_nor_flash_driver_write ra8_xspi_flash_program(0, off, buf, w*4)
lx_nor_flash_driver_block_erase ra8_xspi_flash_erase_sector(0, off)
lx_nor_flash_driver_block_erased_verify read sector and check 0xFFFFFFFF
Parameters
[in,out]nor_flashLevelX NOR-flash control block. The driver writes lx_nor_flash_base_address, lx_nor_flash_total_blocks, lx_nor_flash_words_per_block, lx_nor_flash_sector_buffer and the four lx_nor_flash_driver_* function pointers.
Returns
LX_SUCCESS on success.
Return values
LX_SUCCESSDriver registered, geometry programmed.
Precondition
nor_flash != LX_NULL.
ra8_xspi_init(0, k_ra8_xspi_lio_1s1s1s) has been called.
Postcondition
All four lx_nor_flash_driver_* pointers are non-NULL.
nor_flash->lx_nor_flash_total_blocks > 0.
Note
Not thread-safe; intended for single-threaded bring-up. LevelX serialises the call through its own state machine, so the driver itself does not need additional locking.
Since
0.1.0

Definition at line 886 of file lx_nor_driver_ra8_xspi.c.

References internal_bus_init_once(), internal_nor_block_erase(), internal_nor_block_erased_verify(), internal_nor_read(), internal_nor_write(), k_ra8_lx_nor_base_addr, k_ra8_lx_nor_total_blocks, k_ra8_lx_nor_words_per_block, and s_ra8_lx_nor_sector_buffer.

Referenced by demo_lx_format_or_panic(), demo_lx_open(), and demo_lx_open_or_panic().

Variable Documentation

◆ g_ra8_xspi_pin_observed

JLink-readable PSEL readback for the 12 OCTA pin slots.

Updated unconditionally by internal_bus_init_once immediately after ra8_board_xspi_pins_init returns. Cold-boot value is all-zero (.bss). Look up the address with::

arm-none-eabi-nm <app>.elf | grep g_ra8_xspi_pin_observed

Then in JLinkExe::

mem32 <addr> 24

to dump 12 rows (2 words / 8 bytes per row). Each row's psel_observed byte should equal 0x1C and pmr_observed should equal 1; any deviation flags a BSP enum error.

Note
Not static – exported for nm / JLink lookup.
Warning
Direct modification by other modules is forbidden.
Since
0.1.0

Definition at line 513 of file lx_nor_driver_ra8_xspi.c.

Referenced by internal_capture_xspi_pin_state().

◆ g_ra8_xspi_rdid_observed

ra8_xspi_rdid_observation_t g_ra8_xspi_rdid_observed

JLink-readable observation of the last RDID probe.

Lives in normal .bss (zero-initialized by the C runtime), so on cold boot the magic field reads 0 and the operator knows the global has not yet been written. Updated unconditionally inside internal_bus_init_once before any error-return path so that even an immediate ra8_log_error -> demo_panic_halt sequence leaves the actual JEDEC triplet visible in SRAM.

Look up its address with::

arm-none-eabi-nm build/.../<app>.elf | grep g_ra8_xspi_rdid_observed

Then in JLinkExe / Ozone::

mem32 <addr> 4

to dump {magic, call_count, rid_err, jedec_id}.

Note
Not static – exported deliberately so external tools (arm-none-eabi-nm, JLink ELF symbol view) can locate it.
Warning
Direct modification by other modules is forbidden; only internal_bus_init_once writes this global.
Since
0.1.0

Definition at line 447 of file lx_nor_driver_ra8_xspi.c.

Referenced by internal_bus_init_once(), internal_probe_rdid(), internal_reset_phase_1s(), internal_reset_phase_8d(), and internal_stamp_observed_start().

◆ s_lx_xspi_tag

const char* s_lx_xspi_tag = "LX_XSPI"
static

Logging tag for the LevelX <-> ra8_xspi bridge.

Definition at line 54 of file lx_nor_driver_ra8_xspi.c.

Referenced by internal_bus_init_once(), internal_probe_rdid(), internal_reset_phase_1s(), and internal_reset_phase_8d().

◆ s_ra8_lx_nor_sector_buffer

ULONG s_ra8_lx_nor_sector_buffer[LX_NOR_SECTOR_SIZE]
static

Per-driver scratch buffer LevelX uses for sector mapping reads.

LevelX requires lx_nor_flash_sector_buffer to point to RAM at least LX_NOR_SECTOR_SIZE * sizeof(ULONG) (512 bytes) wide. We give it a 4-byte-aligned static buffer so it lines up with the ULONG word stride LevelX expects.

Note
Static-storage; not thread-safe but LevelX serialises driver calls itself.
Since
0.1.0

Definition at line 135 of file lx_nor_driver_ra8_xspi.c.

Referenced by internal_nor_block_erased_verify(), and lx_nor_driver_ra8_xspi_initialize().

◆ s_ra8_xspi_pin_refs

const ra8_xspi_pin_ref_t s_ra8_xspi_pin_refs[k_ra8_xspi_pin_count]
static
Initial value:
= {
{(uint8_t)k_ra8_port_1, (uint8_t)k_ra8_pin_4},
{(uint8_t)k_ra8_port_8, (uint8_t)k_ra8_pin_8},
{(uint8_t)k_ra8_port_8, (uint8_t)k_ra8_pin_1},
{(uint8_t)k_ra8_port_1, (uint8_t)k_ra8_pin_0},
{(uint8_t)k_ra8_port_8, (uint8_t)k_ra8_pin_3},
{(uint8_t)k_ra8_port_1, (uint8_t)k_ra8_pin_3},
{(uint8_t)k_ra8_port_1, (uint8_t)k_ra8_pin_1},
{(uint8_t)k_ra8_port_1, (uint8_t)k_ra8_pin_2},
{(uint8_t)k_ra8_port_8, (uint8_t)k_ra8_pin_0},
{(uint8_t)k_ra8_port_8, (uint8_t)k_ra8_pin_2},
{(uint8_t)k_ra8_port_8, (uint8_t)k_ra8_pin_4},
{0xFFU, 0xFFU},
}
@ k_ra8_port_8
RA8 port 8.
@ k_ra8_port_1
RA8 port 1.
@ k_ra8_pin_4
RA8 pin 4.
@ k_ra8_pin_1
RA8 pin 1.
@ k_ra8_pin_2
RA8 pin 2.
@ k_ra8_pin_8
RA8 pin 8.
@ k_ra8_pin_0
RA8 pin 0.
@ k_ra8_pin_3
RA8 pin 3.

Static reference list of OCTA (port, pin) pairs.

Indexed by row 0..11 of g_ra8_xspi_pin_observed. The 12th slot is a sentinel (0xFF, 0xFF) reserved for parity with the BSP table.

Note
File-scope; read-only.
Since
0.1.0

Definition at line 548 of file lx_nor_driver_ra8_xspi.c.

Referenced by internal_capture_xspi_pin_state().

◆ s_xspi_bus_ready

bool s_xspi_bus_ready = false
static

One-shot guard so we only run the bus bring-up once.

LevelX calls lx_nor_driver_ra8_xspi_initialize on every lx_nor_flash_format and every lx_nor_flash_open. Pin routing and ra8_xspi_init must run exactly once – a second ra8_pfs_route_peripheral would trip the validator and return k_ra8_err_gpio_conflict. This file-static latches once the first call succeeds.

Definition at line 625 of file lx_nor_driver_ra8_xspi.c.

Referenced by internal_bus_init_once().