ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_io_blockdev_xspi.c
Go to the documentation of this file.
1
20
22
23#include <stddef.h>
24#include <stdint.h>
25#include <string.h>
26
27#include "ra8_attributes.h"
28#include "ra8_check.h"
29#include "ra8_err.h"
30#include "ra8_io_blockdev.h"
32#include "ra8_ospi_regs.h"
33#include "ra8_xspi.h"
34
36static const char* const s_tag = "ra8_io_blockdev_xspi";
37
51
54
81internal_xspi_bounds(const ra8_io_blockdev_xspi_state_t* st, uint32_t lba, uint32_t count)
82{
83 if (count > st->block_count) {
85 }
86 if (lba > st->block_count - count) {
88 }
89 return k_ra8_ok;
90}
91
121internal_xspi_read_chunked(uint8_t instance, uint32_t flash_addr, uint8_t* buf, uint32_t len)
122{
123 RA8_CHECK_NULL_PTR(buf, s_tag, "buf must not be nullptr");
124 uint32_t done = k_xspi_zero_blocks;
125 while (done < len) {
126 const uint32_t remaining = len - done;
127 const uint32_t chunk =
128 (remaining > (uint32_t)k_ra8_xspi_max_xfer) ? (uint32_t)k_ra8_xspi_max_xfer : remaining;
129 const ra8_err_t e = ra8_xspi_flash_read(instance, flash_addr + done, &buf[done], chunk);
130 if (e != k_ra8_ok) {
131 return e;
132 }
133 done += chunk;
134 }
135 return k_ra8_ok;
136}
137
168 uint32_t flash_addr,
169 const uint8_t* data,
170 uint32_t len)
171{
172 RA8_CHECK_NULL_PTR(data, s_tag, "data must not be nullptr");
173 uint32_t done = k_xspi_zero_blocks;
174 while (done < len) {
175 const uint32_t remaining = len - done;
176 const uint32_t chunk =
177 (remaining > (uint32_t)k_ra8_xspi_max_xfer) ? (uint32_t)k_ra8_xspi_max_xfer : remaining;
178 const ra8_err_t e = ra8_xspi_flash_program(instance, flash_addr + done, &data[done], chunk);
179 if (e != k_ra8_ok) {
180 return e;
181 }
182 done += chunk;
183 }
184 return k_ra8_ok;
185}
186
219 uint32_t sector_lba,
220 uint32_t first_blk,
221 uint32_t n_blocks,
222 const uint8_t* src)
223{
224 RA8_CHECK_NULL_PTR(st, s_tag, "st must not be nullptr");
225 RA8_CHECK_NULL_PTR(src, s_tag, "src must not be nullptr");
226 const uint32_t sec_addr = st->base_off + (sector_lba * (uint32_t)k_ra8_io_block_size_bytes);
227 const ra8_err_t r =
229 if (r != k_ra8_ok) {
230 return r;
231 }
232 const size_t dst_off = (size_t)first_blk * (size_t)k_ra8_io_block_size_bytes;
233 const size_t n_bytes = (size_t)n_blocks * (size_t)k_ra8_io_block_size_bytes;
234 (void)memcpy(&s_sector[dst_off], src, n_bytes);
235 const ra8_err_t e = ra8_xspi_flash_erase_sector(st->instance, sec_addr);
236 if (e != k_ra8_ok) {
237 return e;
238 }
240 sec_addr,
241 s_sector,
242 (uint32_t)k_xspi_sector_bytes);
243}
244
274internal_xspi_read(void* ctx, uint32_t lba, uint32_t count, uint8_t* buf)
275{
276 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
277 RA8_CHECK_NULL_PTR(buf, s_tag, "buf must not be nullptr");
279 const ra8_err_t b = internal_xspi_bounds(st, lba, count);
280 if (b != k_ra8_ok) {
281 return b;
282 }
283 const uint32_t addr = st->base_off + (lba * (uint32_t)k_ra8_io_block_size_bytes);
284 const uint32_t len = count * (uint32_t)k_ra8_io_block_size_bytes;
285 return internal_xspi_read_chunked(st->instance, addr, buf, len);
286}
287
320internal_xspi_write(void* ctx, uint32_t lba, uint32_t count, const uint8_t* buf)
321{
322 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
323 RA8_CHECK_NULL_PTR(buf, s_tag, "buf must not be nullptr");
325 if (st->read_only) {
327 }
328 const ra8_err_t b = internal_xspi_bounds(st, lba, count);
329 if (b != k_ra8_ok) {
330 return b;
331 }
332 uint32_t done = k_xspi_zero_blocks;
333 while (done < count) {
334 const uint32_t blk = lba + done;
335 const uint32_t first_blk = blk % (uint32_t)k_xspi_blocks_per_sector;
336 const uint32_t sector_lba = blk - first_blk;
337 const uint32_t room = (uint32_t)k_xspi_blocks_per_sector - first_blk;
338 const uint32_t left = count - done;
339 const uint32_t n_blocks = (left < room) ? left : room;
340 const uint8_t* src = &buf[(size_t)done * (size_t)k_ra8_io_block_size_bytes];
341 const ra8_err_t e = internal_write_one_sector(st, sector_lba, first_blk, n_blocks, src);
342 if (e != k_ra8_ok) {
343 return e;
344 }
345 done += n_blocks;
346 }
347 return k_ra8_ok;
348}
349
380/* cppcheck-suppress constParameterCallback -- ra8_io_blockdev_ops_t fixes this callback's context type as void*. */
381static ra8_err_t internal_xspi_erase(void* ctx, uint32_t lba, uint32_t count)
382{
383 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
385 if (st->read_only) {
387 }
388 if ((lba % (uint32_t)k_xspi_blocks_per_sector) != k_xspi_zero_blocks) {
390 }
391 if ((count % (uint32_t)k_xspi_blocks_per_sector) != k_xspi_zero_blocks) {
393 }
394 const ra8_err_t b = internal_xspi_bounds(st, lba, count);
395 if (b != k_ra8_ok) {
396 return b;
397 }
398 uint32_t blk = lba;
399 while (blk < lba + count) {
400 const uint32_t addr = st->base_off + (blk * (uint32_t)k_ra8_io_block_size_bytes);
402 if (e != k_ra8_ok) {
403 return e;
404 }
405 blk += (uint32_t)k_xspi_blocks_per_sector;
406 }
407 return k_ra8_ok;
408}
409
435{
436 RA8_CHECK_NULL_PTR(ctx, s_tag, "ctx must not be nullptr");
437 RA8_CHECK_NULL_PTR(out, s_tag, "out must not be nullptr");
439 out->block_count = st->block_count;
444 out->must_erase_before_write = true;
445 out->read_only = st->read_only;
446 return k_ra8_ok;
447}
448
451 .read = internal_xspi_read,
452 .write = internal_xspi_write,
453 .erase = internal_xspi_erase,
454 .get_caps = internal_xspi_get_caps,
455 .sync = nullptr,
456};
457
484internal_xspi_check_geom(uint8_t instance, uint32_t base_off, uint32_t block_count)
485{
486 if (instance >= (uint8_t)k_ra8_xspi_instance_count) {
488 }
489 if ((base_off % (uint32_t)k_xspi_sector_bytes) != k_xspi_zero_blocks) {
491 }
492 if (block_count == k_xspi_zero_blocks) {
494 }
495 if ((block_count % (uint32_t)k_xspi_blocks_per_sector) != k_xspi_zero_blocks) {
497 }
498 return k_ra8_ok;
499}
500
503 uint8_t instance,
504 uint32_t base_off,
505 uint32_t block_count,
506 bool read_only)
507{
508 RA8_CHECK_NULL_PTR(bd, s_tag, "bd must not be nullptr");
509 RA8_CHECK_NULL_PTR(state, s_tag, "state must not be nullptr");
510 const ra8_err_t g = internal_xspi_check_geom(instance, base_off, block_count);
511 if (g != k_ra8_ok) {
512 return g;
513 }
514 state->instance = instance;
515 state->base_off = base_off;
516 state->block_count = block_count;
517 state->read_only = read_only;
518 bd->iface = &s_xspi_iface;
519 bd->ctx = state;
520 return k_ra8_ok;
521}
522
523static_assert((uint32_t)k_xspi_sector_bytes ==
525 "sector must equal blocks_per_sector * logical block size");
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_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_err_out_of_range
Sensor or peripheral output out of valid range.
Definition ra8_err.h:337
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
ra8_io block-device fabric – one LBA vtable across every storage medium.
struct ra8_io_blockdev_iface ra8_io_blockdev_iface_t
@ k_ra8_io_erase_value_ones
Block reads back as 0xFF after erase.
@ k_ra8_io_block_size_bytes
Bytes per logical block (the only size).
Backend implementation contract for the ra8_io block-device fabric.
static ra8_err_t internal_xspi_get_caps(const void *ctx, ra8_io_blockdev_caps_t *out)
xSPI backend: report medium capabilities.
static ra8_err_t internal_xspi_program_chunked(uint8_t instance, uint32_t flash_addr, const uint8_t *data, uint32_t len)
Program len flash bytes at flash_addr, chunked to the HAL limit.
static ra8_err_t internal_xspi_write(void *ctx, uint32_t lba, uint32_t count, const uint8_t *buf)
xSPI backend: write count blocks from buf at lba.
static ra8_err_t internal_write_one_sector(const ra8_io_blockdev_xspi_state_t *st, uint32_t sector_lba, uint32_t first_blk, uint32_t n_blocks, const uint8_t *src)
Read-modify-write one 4 KiB sector, overlaying the touched blocks.
static ra8_err_t internal_xspi_read(void *ctx, uint32_t lba, uint32_t count, uint8_t *buf)
xSPI backend: read count blocks at lba into buf.
static ra8_err_t internal_xspi_erase(void *ctx, uint32_t lba, uint32_t count)
xSPI backend: erase sector-aligned count blocks at lba.
static const ra8_io_blockdev_iface_t s_xspi_iface
OSPI NOR backend vtable.
static ra8_err_t internal_xspi_read_chunked(uint8_t instance, uint32_t flash_addr, uint8_t *buf, uint32_t len)
Read len flash bytes at flash_addr, chunked to the HAL limit.
ra8_io_xspi_const_t
OSPI NOR backend layout constants.
@ k_xspi_zero_blocks
Sentinel for an empty block range.
@ k_xspi_blocks_per_sector
512-byte blocks per 4 KiB sector.
@ k_xspi_sector_bytes
Erase sector size in bytes.
@ k_xspi_min_instance
Lowest valid xSPI instance index.
@ k_xspi_program_bytes
NOR page-program granularity in bytes.
static ra8_err_t internal_xspi_bounds(const ra8_io_blockdev_xspi_state_t *st, uint32_t lba, uint32_t count)
Reject an out-of-range [lba, lba+count) block range.
ra8_err_t ra8_io_blockdev_xspi_init(ra8_io_blockdev_t *bd, ra8_io_blockdev_xspi_state_t *state, uint8_t instance, uint32_t base_off, uint32_t block_count, bool read_only)
Bind an OSPI NOR block-device backend into a caller-owned handle.
static uint8_t s_sector[k_xspi_sector_bytes]
Whole-sector read-modify-write scratch (zero-malloc, NASA Rule 3).
static ra8_err_t internal_xspi_check_geom(uint8_t instance, uint32_t base_off, uint32_t block_count)
Validate the window geometry for ra8_io_blockdev_xspi_init.
ra8_io block-device backend over OSPI NOR flash via ra8_xspi.
xSPI / Octo-SPI controller register layout for the Renesas RA8D2
@ k_ra8_xspi_max_xfer
Maximum bytes per flash read/program call.
@ k_ra8_xspi_instance_count
XSPI0 and XSPI1.
xSPI / Octo-SPI driver (flash read/program/erase + ID/status)
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.
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.
ra8_err_t ra8_xspi_flash_erase_sector(uint8_t instance, uint32_t flash_addr)
Erase the 4 KiB sector containing flash_addr.
Static properties a backend reports about its medium.
uint32_t erase_unit_blocks
Erase granularity, in logical blocks.
uint32_t block_count
Total addressable logical blocks.
bool must_erase_before_write
true => program needs a prior erase.
bool read_only
true => writes/erases are rejected.
uint8_t erase_value
Post-erase byte (ra8_io_erase_value_t).
uint16_t logical_block_bytes
Logical block size (always 512).
uint32_t program_size_bytes
Minimum program granularity in bytes.
Caller-allocated block-device handle binding a backend to its context.
const ra8_io_blockdev_iface_t * iface
Bound backend vtable (private).
void * ctx
Backend-private context (private).
Caller-owned private state for an OSPI NOR block device.
uint32_t base_off
Flash byte offset of logical block 0 (private).
bool read_only
true => writes and erases are rejected (private).
uint32_t block_count
Number of 512-byte logical blocks (private).
uint8_t instance
xSPI HAL instance index, 0 or 1 (private).