ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_mstp.c
Go to the documentation of this file.
1
21
22#include "ra8_mstp.h"
23
24#include <stdint.h>
25
26#include "ra8_attributes.h"
27#include "ra8_bit_constants.h"
28#include "ra8_check.h"
29#include "ra8_err.h"
30#include "ra8_hw_err.h"
31#include "ra8_log.h"
32#include "ra8_mstp_internal.h"
33#include "ra8_mstp_regs.h"
34
35/* =============================================================================
36 * Local constants
37 * =============================================================================
38 */
39
40static const char* s_tag = "MSTP";
41
46typedef enum : uint8_t {
50
61typedef enum : uint16_t {
64
79typedef enum : uint32_t {
80 k_ra8_mstp_all_stopped = 0xFFFFFFFFU,
83
102typedef enum : uintptr_t {
103 k_ra8_mstp_psarb_addr = 0x40204004U,
104 k_ra8_mstp_psarc_addr = 0x40204008U,
105 k_ra8_mstp_psard_addr = 0x4020400CU,
106 k_ra8_mstp_psare_addr = 0x40204010U,
108
109/* =============================================================================
110 * State
111 * =============================================================================
112 */
113
128
129/* =============================================================================
130 * Public id decoders (declared in ra8_mstp_regs.h)
131 * =============================================================================
132 */
133
138
140{
141 return (uint8_t)((uint16_t)id & k_ra8_mask_byte);
142}
143
144/* =============================================================================
145 * Internal helpers
146 * =============================================================================
147 */
148
167RA8_INTERNAL static bool internal_decode(ra8_mstp_t id, uint8_t* out_reg, uint8_t* out_bit)
168{
169 const ra8_mstp_reg_t reg_id = ra8_mstp_id_reg(id);
170 const uint8_t reg = (uint8_t)reg_id;
171 const uint8_t bit = ra8_mstp_id_bit(id);
172 if (reg >= k_ra8_mstp_reg_count) {
173 return false;
174 }
175 if (bit >= k_ra8_mstp_bit_count) {
176 return false;
177 }
178 *out_reg = reg;
179 *out_bit = bit;
180 return true;
181}
182
192RA8_INTERNAL static volatile uint32_t* internal_reg_ptr(uint8_t reg)
193{
194 return &(&ra8_mstp()->MSTPCRA)[reg];
195}
196
226internal_wait_readback(uint8_t reg, uint8_t bit, bool expected_stopped)
227{
228 volatile const uint32_t* p = internal_reg_ptr(reg);
229 const uint32_t mask = (uint32_t)1U << bit;
230 for (uint16_t i = 0U; i < k_ra8_mstp_readback_spin; ++i) {
231 const bool seen_stopped = (*p & mask) != 0U;
232 const bool settled = (seen_stopped == expected_stopped);
233#if defined(RA8_OFF_TARGET) && defined(UNIT_TEST)
234 /* Host MMIO fault seam, keyed on the polled MSTPCR register. */
235 if (ra8_fake_mmio_wait_eval(p, (uint32_t)i, settled)) {
236 return k_ra8_ok;
237 }
238#else
239 if (settled) {
240 return k_ra8_ok;
241 }
242#endif
243 }
245}
246
248ra8_err_t priv_ra8_mstp_wait_reg_settle_internal(uint8_t reg, uint32_t expect, uint32_t care_mask)
249{
250 volatile const uint32_t* p = internal_reg_ptr(reg);
251 for (uint16_t i = 0U; i < k_ra8_mstp_readback_spin; ++i) {
252 const bool settled = ((*p & care_mask) == (expect & care_mask));
253#if defined(RA8_OFF_TARGET) && defined(UNIT_TEST)
254 /* Host MMIO fault seam, keyed on the polled MSTPCR register. */
255 if (ra8_fake_mmio_wait_eval(p, (uint32_t)i, settled)) {
256 return k_ra8_ok;
257 }
258#else
259 if (settled) {
260 return k_ra8_ok;
261 }
262#endif
263 }
265}
266
269{
270 /* MSTPCRA has no PSAR: always fully Secure-owned. */
271 static const uintptr_t k_psar_addr[k_ra8_mstp_reg_count] = {
272 0U,
273 (uintptr_t)k_ra8_mstp_psarb_addr,
274 (uintptr_t)k_ra8_mstp_psarc_addr,
275 (uintptr_t)k_ra8_mstp_psard_addr,
276 (uintptr_t)k_ra8_mstp_psare_addr,
277 };
278 if (k_psar_addr[reg] == 0U) {
279 return 0U;
280 }
281 /* Read PSARB..PSARE (reg 1..4); the Non-secure-attributed bit mask.
282 * HUM Ch 51.8.1 "PSARB : Peripheral Security Attribution Register B" p 3284 */
283 return *(volatile const uint32_t*)k_psar_addr[reg];
284}
285
286/* =============================================================================
287 * Public API
288 * =============================================================================
289 */
290
292{
293 ra8_log_info(s_tag, "ra8_mstp_init -- gating all modules");
294
295 /* Reset every ref count. */
296 for (uint8_t reg = 0U; reg < k_ra8_mstp_reg_count; ++reg) {
297 for (uint8_t bit = 0U; bit < k_ra8_mstp_bit_count; ++bit) {
298 s_refcount[reg][bit] = 0U;
299 }
300 }
301
302 /* Stop all peripherals. MSTPCRA bits 0..3 (SRAM0..3) must stay 0
303 * (running) or the CPU stack becomes inaccessible and causes a
304 * BusFault. All other registers use the full all-stopped pattern.
305 * HUM Ch 11.2.6..10 p 443..449. */
306 static const uint32_t k_init_vals[k_ra8_mstp_reg_count] = {
307 (uint32_t)k_ra8_mstp_safe_stopped_a, /* MSTPCRA: SRAM0-3 kept running */
308 (uint32_t)k_ra8_mstp_all_stopped, /* MSTPCRB */
309 (uint32_t)k_ra8_mstp_all_stopped, /* MSTPCRC */
310 (uint32_t)k_ra8_mstp_all_stopped, /* MSTPCRD */
311 (uint32_t)k_ra8_mstp_all_stopped, /* MSTPCRE */
312 };
313 /* HUM Ch 11.2.6 "MSTPCRA : Module Stop Control Register A", p 443 */
314 *internal_reg_ptr(0U) = k_init_vals[0U];
315 /* HUM Ch 11.2.7 "MSTPCRB : Module Stop Control Register B", p 444 */
316 *internal_reg_ptr(1U) = k_init_vals[1U];
317 /* HUM Ch 11.2.8 "MSTPCRC : Module Stop Control Register C", p 446 */
318 *internal_reg_ptr(2U) = k_init_vals[2U];
319 /* HUM Ch 11.2.9 "MSTPCRD : Module Stop Control Register D", p 448 */
320 *internal_reg_ptr(3U) = k_init_vals[3U];
321 /* HUM Ch 11.2.10 "MSTPCRE : Module Stop Control Register E", p 449 */
322 *internal_reg_ptr(4U) = k_init_vals[4U];
323
324 /* Read-back: each register must settle to the value written, but only for
325 * the bits the Secure side actually owns. A Non-secure-attributed module
326 * (PSAR bit set -- e.g. a USB controller delegated to a Non-secure world)
327 * ignores the Secure module-stop write, so its bit will not read back the
328 * commanded state; requiring it would spuriously fail boot on every
329 * TrustZone system that delegates a peripheral. Masking the read-back by the
330 * Secure-owned bits keeps a genuine stuck Secure module a hard failure while
331 * tolerating the by-design Non-secure ones. On a non-TrustZone system the
332 * mask is all-ones, so the check stays fully strict. */
333 for (uint8_t reg = 0U; reg < k_ra8_mstp_reg_count; ++reg) {
334 const uint32_t care = ~priv_ra8_mstp_ns_mask_internal(reg);
335 if (priv_ra8_mstp_wait_reg_settle_internal(reg, k_init_vals[reg], care) != k_ra8_ok) {
336 ra8_log_error_val(s_tag, "init read-back failed reg", (uint32_t)reg);
338 }
339 }
340 return k_ra8_ok;
341}
342
344{
345 uint8_t reg = 0U;
346 uint8_t bit = 0U;
347 if (!internal_decode(id, &reg, &bit)) {
348 ra8_log_error_val(s_tag, "enable: invalid id", (uint32_t)id);
350 }
351
352 const uint8_t prev = s_refcount[reg][bit];
353 if (prev == UINT8_MAX) {
354 /* Defensive: 255 simultaneous users would mean a bug elsewhere. */
355 ra8_log_error_val(s_tag, "enable: refcount saturated", (uint32_t)id);
357 }
358 s_refcount[reg][bit] = (uint8_t)(prev + 1U);
359
360 if (prev != 0U) {
361 /* Already running. Nothing else to do. */
362 return k_ra8_ok;
363 }
364
365 /* HUM Ch 11.2.6 "MSTPCRA : Module Stop Control Register A", p 443
366 * -- bit clear == ungate the peripheral. */
367 volatile uint32_t* p = internal_reg_ptr(reg);
368 const uint32_t mask = (uint32_t)1U << bit;
369 *p = *p & ~mask;
370
371 const ra8_err_t err = internal_wait_readback(reg, bit, false);
372 if (err != k_ra8_ok) {
373 /* Roll the ref count back so a retry from the caller starts
374 * fresh rather than thinking the module is already on. */
375 s_refcount[reg][bit] = prev;
376 ra8_log_error_val(s_tag, "enable: read-back timeout id", (uint32_t)id);
377 return err;
378 }
379 return k_ra8_ok;
380}
381
383{
384 uint8_t reg = 0U;
385 uint8_t bit = 0U;
386 if (!internal_decode(id, &reg, &bit)) {
387 ra8_log_error_val(s_tag, "disable: invalid id", (uint32_t)id);
389 }
390
391 const uint8_t prev = s_refcount[reg][bit];
392 if (prev == 0U) {
393 ra8_log_error_val(s_tag, "disable: refcount underflow", (uint32_t)id);
395 }
396 s_refcount[reg][bit] = (uint8_t)(prev - 1U);
397
398 if (prev != 1U) {
399 /* Other users still active. Leave the bit cleared. */
400 return k_ra8_ok;
401 }
402
403 /* HUM Ch 11.2.6 "MSTPCRA : Module Stop Control Register A", p 443
404 * -- bit set == gate the peripheral. */
405 volatile uint32_t* p = internal_reg_ptr(reg);
406 const uint32_t mask = (uint32_t)1U << bit;
407 *p = *p | mask;
408
409 const ra8_err_t err = internal_wait_readback(reg, bit, true);
410 if (err != k_ra8_ok) {
411 /* Roll back so the next caller still sees the resource as in
412 * use and we don't lose track of pending ungates. */
413 s_refcount[reg][bit] = prev;
414 ra8_log_error_val(s_tag, "disable: read-back timeout id", (uint32_t)id);
415 return err;
416 }
417 return k_ra8_ok;
418}
419
421{
422 RA8_CHECK_NULL_PTR(out_ref, s_tag, "get_refcount: out_ref");
423 uint8_t reg = 0U;
424 uint8_t bit = 0U;
425 if (!internal_decode(id, &reg, &bit)) {
427 }
428 *out_ref = s_refcount[reg][bit];
429 return k_ra8_ok;
430}
431
433{
434 RA8_CHECK_NULL_PTR(out_stopped, s_tag, "is_stopped: out_stopped");
435 uint8_t reg = 0U;
436 uint8_t bit = 0U;
437 if (!internal_decode(id, &reg, &bit)) {
439 }
440 volatile const uint32_t* p = internal_reg_ptr(reg);
441 const uint32_t mask = (uint32_t)1U << bit;
442 *out_stopped = ((*p & mask) != 0U);
443 return k_ra8_ok;
444}
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).
Named Bit Positions and Masks for Register Manipulation.
@ k_ra8_mask_byte
Low 8 bits mask.
@ k_ra8_bits_per_byte
Bits in a byte.
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_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ 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
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.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error_val(tag, message, value)
RA8 log error val.
Definition ra8_log.h:337
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
static ra8_err_t internal_wait_readback(uint8_t reg, uint8_t bit, bool expected_stopped)
Read-back protocol from HUM 11.2.6 Note 2.
Definition ra8_mstp.c:226
ra8_mstp_dim_t
Dimensions of the ref-count table.
Definition ra8_mstp.c:46
@ k_ra8_mstp_reg_count
MSTPCRA..MSTPCRE.
Definition ra8_mstp.c:47
@ k_ra8_mstp_bit_count
32 bits per register.
Definition ra8_mstp.c:48
uint8_t ra8_mstp_id_bit(ra8_mstp_t id)
Extract the bit number from a packed MSTP id.
Definition ra8_mstp.c:139
ra8_err_t ra8_mstp_enable(ra8_mstp_t id)
Reference-counted "ungate this peripheral" request.
Definition ra8_mstp.c:343
ra8_err_t ra8_mstp_is_stopped(ra8_mstp_t id, bool *out_stopped)
Read the current MSTP bit value for an id.
Definition ra8_mstp.c:432
ra8_mstp_psar_t
R_PSCU Peripheral Security Attribution Register addresses (PSARB..E).
Definition ra8_mstp.c:102
@ k_ra8_mstp_psarb_addr
PSARB: MSTPCRB attribution.
Definition ra8_mstp.c:103
@ k_ra8_mstp_psard_addr
PSARD: MSTPCRD attribution.
Definition ra8_mstp.c:105
@ k_ra8_mstp_psarc_addr
PSARC: MSTPCRC attribution.
Definition ra8_mstp.c:104
@ k_ra8_mstp_psare_addr
PSARE: MSTPCRE attribution.
Definition ra8_mstp.c:106
ra8_mstp_reg_t ra8_mstp_id_reg(ra8_mstp_t id)
Extract the register index from a packed MSTP id.
Definition ra8_mstp.c:134
static uint8_t s_refcount[k_ra8_mstp_reg_count][k_ra8_mstp_bit_count]
Per-(register, bit) usage counter.
Definition ra8_mstp.c:127
ra8_err_t ra8_mstp_get_refcount(ra8_mstp_t id, uint8_t *out_ref)
Read the current ref count for an MSTP id.
Definition ra8_mstp.c:420
ra8_mstp_spin_t
Bounded spin budget for the read-back protocol (HUM 11.2.6 N2).
Definition ra8_mstp.c:61
@ k_ra8_mstp_readback_spin
RA8 mstp readback spin.
Definition ra8_mstp.c:62
ra8_err_t ra8_mstp_init(void)
Re-establish the ra8_mstp ref-count table from current hardware state.
Definition ra8_mstp.c:291
static volatile uint32_t * internal_reg_ptr(uint8_t reg)
Pointer to MSTPCRA..MSTPCRE indexed by register number.
Definition ra8_mstp.c:192
ra8_mstp_init_val_t
Per-register safe all-stopped patterns for MSTPCRA..MSTPCRE.
Definition ra8_mstp.c:79
@ k_ra8_mstp_all_stopped
RA8 mstp all stopped.
Definition ra8_mstp.c:80
@ k_ra8_mstp_safe_stopped_a
MSTPCRA: bits 0-3 (SRAM0-3) kept 0.
Definition ra8_mstp.c:81
static bool internal_decode(ra8_mstp_t id, uint8_t *out_reg, uint8_t *out_bit)
Decode an ra8_mstp_t id and validate its bit position.
Definition ra8_mstp.c:167
ra8_err_t priv_ra8_mstp_wait_reg_settle_internal(uint8_t reg, uint32_t expect, uint32_t care_mask)
Implementation of priv_ra8_mstp_wait_reg_settle_internal() – masked settle poll.
Definition ra8_mstp.c:248
uint32_t priv_ra8_mstp_ns_mask_internal(uint8_t reg)
Implementation of priv_ra8_mstp_ns_mask_internal() – reads PSARB..E.
Definition ra8_mstp.c:268
ra8_err_t ra8_mstp_disable(ra8_mstp_t id)
Reference-counted "gate this peripheral" request.
Definition ra8_mstp.c:382
Ref-counted Module Stop Control wrapper for the RA8D2.
Cross-TU surface for the ra8_mstp module-stop driver (test access).
Module Stop Control (MSTP) register layout for the Renesas RA8D2.
static volatile r_mstp_regs_t * ra8_mstp(void)
Get pointer to the MSTP register block.
ra8_mstp_t
Packed (reg << 8) | bit module-stop identifier.
ra8_mstp_reg_t
Which of MSTPCRA..MSTPCRE owns the bit.
volatile uint32_t MSTPCRA
Module Stop Control Register A (+0x00).