ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_eth_gwca.c
Go to the documentation of this file.
1
20
21#include "ra8_eth_gwca.h"
22
23#include <stdint.h>
24#include <string.h>
25
26#include "ra8_attributes.h"
27#include "ra8_check.h"
28#include "ra8_err.h"
30#include "ra8_ether_regs.h"
31#include "ra8_hw_err.h"
32#include "ra8_log.h"
33#include "ra8_mstp.h"
34#include "ra8_mstp_regs.h"
35
36static const char* s_tag = "ETHGWC";
37
39static void* s_gwca_ctx;
40
56
58{
59 /* HUM Ch 11.2.8 "MSTPCRC : Module Stop Control Register C" p 446 */
61 RA8_RETURN_ON_ERROR(mst_err, s_tag, "gwca_init: mstp enable");
62
63 volatile r_gwca_regs_t* reg = ra8_gwca();
64 /* HUM Ch 34 "Ethernet CPU Agent (GWCA)" p 1787 */
65 reg->GWCA_CTRL = 0U;
66 reg->GWCA_STS = 0U;
67 reg->GWCA_IE = 0U;
68 reg->GWCA_ICLR = 0U;
69
70 /* Enable extended descriptor format on each agent before any GWCA
71 * mode transition. Without this the AXI init handshake (GWARIRM.ARR)
72 * never asserts. Mirrors FSP r_layer3_switch open path. */
73 /* HUM Ch 30 "Ethernet Message Forwarding Engine (MFWD)" p 1321 */
74 volatile uint32_t* const fwpc10 =
75 (volatile uint32_t*)(k_ra8_mfwd_base_addr + (uintptr_t)k_ra8_mfwd_off_fwpc10);
76 volatile uint32_t* const fwpc11 =
77 (volatile uint32_t*)(k_ra8_mfwd_base_addr + (uintptr_t)k_ra8_mfwd_off_fwpc11);
78 volatile uint32_t* const fwpc12 =
79 (volatile uint32_t*)(k_ra8_mfwd_base_addr + (uintptr_t)k_ra8_mfwd_off_fwpc12);
80 *fwpc10 = (*fwpc10 & ~(uint32_t)k_ra8_mfwd_fwpc_dde) | (uint32_t)k_ra8_mfwd_fwpc_dde;
81 *fwpc11 = (*fwpc11 & ~(uint32_t)k_ra8_mfwd_fwpc_dde) | (uint32_t)k_ra8_mfwd_fwpc_dde;
82 *fwpc12 = (*fwpc12 & ~(uint32_t)k_ra8_mfwd_fwpc_dde) | (uint32_t)k_ra8_mfwd_fwpc_dde;
83
84 ra8_log_info(s_tag, "gwca_init");
85 return k_ra8_ok;
86}
87
89{
90 volatile r_gwca_regs_t* reg = ra8_gwca();
91 /* HUM Ch 34 "Ethernet CPU Agent (GWCA)" p 1787 */
92 reg->GWCA_CTRL = 0U;
93 reg->GWCA_IE = 0U;
94 s_gwca_fn = nullptr;
95 s_gwca_ctx = nullptr;
97}
98
100{
101 RA8_CHECK_NULL_PTR(out_mask, s_tag, "out_mask must not be nullptr");
102 /* HUM Ch 34 "Ethernet CPU Agent (GWCA)" p 1787 */
103 *out_mask = ra8_gwca()->GWCA_STS;
104 return k_ra8_ok;
105}
106
108{
109 volatile r_gwca_regs_t* reg = ra8_gwca();
110 /* HUM Ch 34 "Ethernet CPU Agent (GWCA)" p 1787 */
111 reg->GWCA_ICLR = mask;
112 reg->GWCA_STS = reg->GWCA_STS & ~mask;
113 return k_ra8_ok;
114}
115
117{
118 s_gwca_fn = fn;
119 s_gwca_ctx = ctx;
120 return k_ra8_ok;
121}
122
125{
126 volatile r_gwca_regs_t* reg = ra8_gwca();
127 /* HUM Ch 34 "Ethernet CPU Agent (GWCA)" p 1787 */
128 const uint32_t mask = reg->GWCA_STS;
130 void* const ctx = s_gwca_ctx;
131 reg->GWCA_ICLR = mask;
132 reg->GWCA_STS = 0U;
133 if (fn != nullptr) {
134 fn(ctx, mask);
135 }
136}
137
139{
140 /* HUM Ch 34 "Ethernet CPU Agent (GWCA)" p 1787 */
141 ra8_gwca()->GWCA_CTRL = 0U;
143}
144
149
164volatile uint32_t g_ra8_eth_gwca_open_step;
165
181volatile uint32_t g_ra8_eth_gwca_pre_step;
182
200
201/* GWMC.OPC field at bits [1:0], GWMS.OPS field at bits [1:0]. The
202 * full register layout matches FSP R_GWCA0_Type from the cloned
203 * Renesas FSP source. */
204
229{
230 if ((uint32_t)mode > (uint32_t)k_ra8_gwmc_opc_mask) {
232 }
233 /* HUM Ch 34.3.1 "GWMC : Mode Configuration Register" p 1792 */
234 volatile uint32_t* const gwmc =
235 (volatile uint32_t*)(k_ra8_gwca0_base_addr + (uintptr_t)k_ra8_gwca_off_gwmc);
236
237 const uint32_t opc = (uint32_t)mode & (uint32_t)k_ra8_gwmc_opc_mask;
238 const uint32_t cur = *gwmc & ~(uint32_t)k_ra8_gwmc_opc_mask;
239 *gwmc = cur | opc;
240
241 /* HUM Ch 34.3.2 "GWMS : Mode Status Register" p 1792 */
242 volatile const uint32_t* const gwms =
243 (volatile uint32_t*)(k_ra8_gwca0_base_addr + (uintptr_t)k_ra8_gwca_off_gwms);
244 /* GWMS.OPS converges to a specific 2-bit value (opc), not a single-mask
245 * set/clear, so the ra8_hw_wait_flag_* helpers do not fit -- run the real
246 * poll inline and route the host unit-test build through the ra8_fake_mmio
247 * seam so the poll/timeout legs execute rather than short-circuit (T1-01). */
248 for (uint32_t i = 0U; i < k_ra8_eth_gwca_mode_spin; ++i) {
249#if defined(RA8_OFF_TARGET) && defined(UNIT_TEST)
250 if (ra8_fake_mmio_wait_eval(gwms, i, ((*gwms & (uint32_t)k_ra8_gwmc_opc_mask) == opc))) {
251 return k_ra8_ok;
252 }
253#else
254 if ((*gwms & (uint32_t)k_ra8_gwmc_opc_mask) == opc) {
255 return k_ra8_ok;
256 }
257#endif
258 }
259 ra8_log_error(s_tag, "set_operation_mode: GWMS.OPS never converged");
261}
262
283{
284 /* HUM Ch 34.3.x "GWARIRM" -- the AXI Manager (vendor name uses
285 * the older M-word) Initialization Request register. ARIOG bit is
286 * the request, ARR bit is the response. Sequence per FSP
287 * r_layer3_switch_initialize_gwca: set ARIOG=1, poll ARR until 1. */
288 enum : uint32_t {
289 k_ra8_gwarirm_ariog = 1UL << 0,
290 k_ra8_gwarirm_arr = 1UL << 1,
291 };
292 volatile uint32_t* const gwarirm =
293 (volatile uint32_t*)(k_ra8_gwca0_base_addr + (uintptr_t)k_ra8_gwca_off_gwarirm);
294 *gwarirm = k_ra8_gwarirm_ariog;
295
296 /* Wait for GWARIRM.ARR to set. The ra8_hw_wait_flag_set32 loop runs on every
297 * build -- including the host unit test, where it is consulted by the
298 * ra8_fake_mmio seam -- so the poll/timeout legs execute rather than compile
299 * out behind an RA8_OFF_TARGET short-circuit (T1-01). */
300 const ra8_err_t err = ra8_hw_wait_flag_set32(gwarirm,
301 (uint32_t)k_ra8_gwarirm_arr,
302 (uint32_t)k_ra8_eth_gwca_mode_spin);
303 if (err != k_ra8_ok) {
304 ra8_log_error(s_tag, "axi_init: GWARIRM.ARR never asserted");
305 }
306 return err;
307}
308
334 uint32_t entry_count)
335{
336 RA8_CHECK_NULL_PTR(linkfix_table, s_tag, "install_linkfix: table must not be null");
337 enum : uint32_t {
338 k_ra8_gwca_linkfix_max_entries = 32U
339 };
340 if (entry_count == 0U || entry_count > k_ra8_gwca_linkfix_max_entries) {
341 ra8_log_error(s_tag, "install_linkfix: entry_count out of range");
343 }
344
345 /* Initialize every entry to LEMPTY (queue disabled). The chip
346 * walks the LINKFIX table at queue-activation time, so any entry
347 * not explicitly populated with a real chain head must look
348 * disabled instead of pointing at random memory. */
349 (void)memset(linkfix_table, 0, (size_t)entry_count * sizeof(ra8_gwca_basic_descriptor_t));
350 for (uint32_t i = 0U; i < entry_count; ++i) {
351 linkfix_table[i].dt = (uint8_t)k_ra8_gwdcc_dt_lempty;
352 }
353
354 /* HUM Ch 34.3.7.2 / 34.3.7.3 GWDCBAC0/1: split the table's
355 * 40-bit address into PTR[39:32] (GWDCBAC0.DCBAU) and PTR[31:0]
356 * (GWDCBAC1.DCBAL). On this 32-bit MCU the upper byte is always
357 * zero, but the bit-field exists for the device family that uses
358 * 40-bit addresses. */
359 const uintptr_t addr = (uintptr_t)linkfix_table;
360 enum : uintptr_t {
361 k_ra8_linkfix_upper_shift = 32U,
362 k_ra8_linkfix_upper_mask = 0xFFULL,
363 k_ra8_linkfix_lower_mask = 0xFFFFFFFFULL,
364 };
365 const uint32_t upper =
366 (uint32_t)((uint64_t)addr >> k_ra8_linkfix_upper_shift) & k_ra8_linkfix_upper_mask;
367 const uint32_t lower = (uint32_t)addr & k_ra8_linkfix_lower_mask;
368 volatile uint32_t* const gwdcbac0 =
369 (volatile uint32_t*)(k_ra8_gwca0_base_addr + (uintptr_t)k_ra8_gwca_off_gwdcbac0);
370 volatile uint32_t* const gwdcbac1 =
371 (volatile uint32_t*)(k_ra8_gwca0_base_addr + (uintptr_t)k_ra8_gwca_off_gwdcbac1);
372 *gwdcbac0 = upper;
373 *gwdcbac1 = lower;
374 return k_ra8_ok;
375}
376
434
462{
464 const ra8_err_t phase1_err = internal_bring_up_to_config(linkfix_table, entry_count);
465 if (phase1_err != k_ra8_ok) {
466 return phase1_err;
467 }
469 if (dis_err != k_ra8_ok) {
471 return dis_err;
472 }
475 if (op_err != k_ra8_ok) {
477 return op_err;
478 }
480 return k_ra8_ok;
481}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_ISR_SAFE
The function is callable from interrupt context.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#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
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
ra8_err_t ra8_eth_gwca_axi_init(void)
Request the GWCA AXI bridge to initialize via GWARIRM.ARIOG.
void ra8_eth_gwca_dispatch(void)
Dispatch a GWCA event.
ra8_err_t ra8_eth_gwca_install_linkfix(ra8_gwca_basic_descriptor_t *linkfix_table, uint32_t entry_count)
Install a fresh LINKFIX table at GWDCBAC0/1.
volatile uint32_t g_ra8_eth_gwca_pre_step
Bench-side debug trail bumped inside internal_default_open_pre.
ra8_err_t ra8_eth_gwca_bring_up(ra8_gwca_basic_descriptor_t *linkfix_table, uint32_t entry_count)
Six-step GWCA bring-up: RESET -> DISABLE -> CONFIG -> AXI -> install_linkfix -> DISABLE -> OPERATION.
ra8_err_t ra8_eth_gwca_enter_stop(void)
Put GWCA into MSTP-gated stop.
volatile uint32_t g_ra8_eth_gwca_bring_up_step
Bench-side debug trail bumped inside ra8_eth_gwca_bring_up.
static void * s_gwca_ctx
ra8_err_t ra8_eth_gwca_clear_status(uint32_t mask)
Clear GWCA_STS bits via GWCA_ICLR.
ra8_err_t ra8_eth_gwca_deinit(void)
Tear down GWCA.
static ra8_eth_gwca_event_fn_t s_gwca_fn
ra8_err_t ra8_eth_gwca_get_status(uint32_t *out_mask)
Read GWCA_STS.
ra8_err_t ra8_eth_gwca_exit_stop(void)
Exit MSTP-gated stop.
static ra8_err_t internal_bring_up_to_config(ra8_gwca_basic_descriptor_t *linkfix_table, uint32_t entry_count)
DISABLE -> CONFIG -> axi_init -> install_linkfix bring-up phase.
volatile uint32_t g_ra8_eth_gwca_open_step
Bench-side debug trail bumped by ra8_eth_gwca_default_open.
ra8_err_t ra8_eth_gwca_init(void)
Initialise GWCA.
ra8_err_t ra8_eth_gwca_set_operation_mode(ra8_gwmc_opc_t mode)
Transition the GWCA / ESWM state machine to a new OPC mode.
ra8_err_t ra8_eth_gwca_attach_handler(ra8_eth_gwca_event_fn_t fn, void *ctx)
Attach the shared event handler.
ra8_eth_gwca_init_layout_t
MFWD FWPC10/11/12 offsets used to enable extended descriptors.
@ k_ra8_mfwd_fwpc_dde
DDE bit position 0.
@ k_ra8_mfwd_off_fwpc10
FWPC10 (GWCA agent).
@ k_ra8_mfwd_off_fwpc12
FWPC12 (ETHA1 agent).
@ k_ra8_mfwd_off_fwpc11
FWPC11 (ETHA0 agent).
Ethernet CPU Agent (GWCA) driver.
void(* ra8_eth_gwca_event_fn_t)(void *ctx, uint32_t status_mask)
GWCA event callback.
Cross-TU shared surface for the ra8_eth_gwca driver split.
@ k_ra8_eth_gwca_mode_spin
GWMS.OPS / GWARIRM.ARR poll budget.
@ k_ra8_eth_gwca_step_fail_6
RA8 Ethernet gwca step fail 6.
@ k_ra8_eth_gwca_step_fail_2
RA8 Ethernet gwca step fail 2.
@ k_ra8_eth_gwca_step_fail_5
RA8 Ethernet gwca step fail 5.
@ k_ra8_eth_gwca_step_ok_6
RA8 Ethernet gwca step ok 6.
@ k_ra8_eth_gwca_step_ok_3
RA8 Ethernet gwca step ok 3.
@ k_ra8_eth_gwca_step_fail_4
RA8 Ethernet gwca step fail 4.
@ k_ra8_eth_gwca_step_ok_2
RA8 Ethernet gwca step ok 2.
@ k_ra8_eth_gwca_step_ok_5
RA8 Ethernet gwca step ok 5.
@ k_ra8_eth_gwca_step_fail_1
RA8 Ethernet gwca step fail 1.
@ k_ra8_eth_gwca_step_ok_4
RA8 Ethernet gwca step ok 4.
@ k_ra8_eth_gwca_step_fail_3
RA8 Ethernet gwca step fail 3.
@ k_ra8_eth_gwca_step_ok_1
RA8 Ethernet gwca step ok 1.
Ethernet controller base addresses for the Renesas RA8D2.
@ k_ra8_gwca_off_gwmc
Mode Configuration.
@ k_ra8_gwca_off_gwdcbac1
Descriptor chain base addr 1 (lower).
@ k_ra8_gwca_off_gwms
Mode Status.
@ k_ra8_gwca_off_gwdcbac0
Descriptor chain base addr 0 (upper).
@ k_ra8_gwca_off_gwarirm
AXI RAM Init Req Monitoring (FSP-confirmed offset).
@ k_ra8_gwdcc_dt_lempty
LEMPTY – queue disabled.
@ k_ra8_mfwd_base_addr
RA8 mfwd base address.
@ k_ra8_gwca0_base_addr
RA8 gwca0 base address.
static volatile r_gwca_regs_t * ra8_gwca(void)
Get pointer to the GWCA register block.
ra8_gwmc_opc_t
GWMC.OPC operation-mode values (HUM Ch 34.3.1 "GWMC" p 1797).
@ k_ra8_gwmc_opc_disable
DR: Disable request.
@ k_ra8_gwmc_opc_mask
RA8 gwmc opc mask.
@ k_ra8_gwmc_opc_config
CR: Config request – LINKFIX writable here.
@ k_ra8_gwmc_opc_operation
OR: Operation request – frames flow.
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
Bounded wait-flag primitives for RA8D2 HAL drivers.
static ra8_err_t ra8_hw_wait_flag_set32(volatile const uint32_t *reg, uint32_t mask, uint32_t budget)
Spin until (*reg & mask) != 0 or budget runs out.
Definition ra8_hw_err.h:309
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
Ref-counted Module Stop Control wrapper for the RA8D2.
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_disable(ra8_mstp_t id)
Reference-counted "gate this peripheral" request.
Definition ra8_mstp.c:382
Module Stop Control (MSTP) register layout for the Renesas RA8D2.
@ k_ra8_mstp_eswm
MSTPC30 ESWM.
Minimal CPU Agent (GWCA) register window.
volatile uint32_t GWCA_IE
+0x08 reserved – misnamed as "IE".
volatile uint32_t GWCA_STS
+0x04 GWMS (Mode Status) – misnamed.
volatile uint32_t GWCA_ICLR
+0x0C reserved – misnamed as "ICLR".
volatile uint32_t GWCA_CTRL
+0x00 GWMC (Mode Configuration) – misnamed.
8-byte basic descriptor (HUM Ch 34.5.1.2 "General Formats").
volatile uint8_t dt
20..23 Descriptor type (ra8_gwdcc_dt_t).