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

Clock Generation Circuit driver – Ethernet-switch (ESWCLK) path. More...

#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_cgc.h"
#include "ra8_cgc_internal.h"
#include "ra8_cgc_regs.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_hw_err.h"
#include "ra8_log.h"
#include "ra8_mstp.h"
#include "ra8_register_protection.h"
#include "ra8_system_regs.h"
#include "ra8_time_constants.h"
Include dependency graph for ra8_cgc_eswclk.c:

Go to the source code of this file.

Enumerations

enum  ra8_cgc_eswckdivcr_t : uint8_t {
  k_ra8_eswckdivcr_div1 = 0U ,
  k_ra8_eswckdivcr_div2 = 1U ,
  k_ra8_eswckdivcr_div4 = 2U ,
  k_ra8_eswckdivcr_div8 = 3U ,
  k_ra8_eswckdivcr_div16 = 4U ,
  k_ra8_eswckdivcr_div32 = 5U ,
  k_ra8_eswckdivcr_div64 = 6U
}
enum  ra8_cgc_eswclk_const_t : uint32_t {
  k_ra8_cgc_eswclk_target_hz = 250000000UL ,
  k_ra8_cgc_eswphyclk_target_hz = 500000000UL ,
  k_ra8_cgc_eswclk_poll_limit = 200000U
}
 Constants used by the ESWCLK bring-up path. More...

Functions

static ra8_err_t internal_wait_cksrdy (volatile const uint8_t *ckcr_reg, uint8_t expected)
 Spin-wait for a peripheral clock control register's CKSRDY bit to match expected.
static ra8_err_t internal_switch_eswcr_to_pll1p (volatile uint8_t *ckcr_reg, volatile uint8_t *divcr_reg, uint8_t div_code)
 Switch one ESW-family peripheral clock to PLL1P with the given divider code.
static ra8_err_t internal_wait_pdctreswm_clear (uint8_t bit)
 Wait for a PDCTRESWM status bit to clear within a bounded budget.
static ra8_err_t internal_eswclk_power_on_domain (void)
 Power on the ESWM peripheral domain via PDCTRESWM.
static ra8_err_t internal_eswclk_program_cks (void)
 Switch ESWCLK + ESWPHYCLK to PLL1P (250 MHz + 500 MHz).
ra8_err_t ra8_cgc_eswclk_init (void)
 Bring up the Ethernet Switch Module (ESWM / RMAC) clock.
ra8_err_t ra8_cgc_eswclk_hz (uint32_t *out_hz)
 Query the current ESWCLK (Ethernet Switch clock) frequency.

Variables

static const char * s_tag = "CGC"
static uint32_t s_eswclk_hz = 0U
 Live ESWCLK frequency, published by ra8_cgc_eswclk_init.

Detailed Description

Clock Generation Circuit driver – Ethernet-switch (ESWCLK) path.

Split out of ra8_cgc.c. Powers on the ESWM peripheral domain and routes the Ethernet-switch clocks off PLL1P:

  • ESWCLK = PLL1P / 4 = 250 MHz (ESWM core clock).
  • ESWPHYCLK = PLL1P / 2 = 500 MHz (Ethernet-PHY interface clock).

Drives the canonical FSP bsp_peripheral_clock_set SREQ/SRDY handshake on ESWCKCR then ESWPCKCR. HOCO must be running before the handshake (the SREQ -> SRDY synchronizer crosses into the CURRENT source domain, which is HOCO at reset); this file reuses priv_ra8_cgc_ensure_hoco_running_for_usb_ck defined in ra8_cgc_usb.c. Every protected-register write is wrapped in RA8_PROTECTED_WRITE so the PRCR re-lock always happens.

Tag ring/world:
Ring 1 (HAL), World S (secure-callable). Same ring/world as the parent ra8_cgc.c.
Since
0.1.0

Definition in file ra8_cgc_eswclk.c.

Enumeration Type Documentation

◆ ra8_cgc_eswckdivcr_t

enum ra8_cgc_eswckdivcr_t : uint8_t
Enumerator
k_ra8_eswckdivcr_div1 

/1

k_ra8_eswckdivcr_div2 

/2 – PLL1P/2 = 500 MHz (ESWPHYCLK target).

k_ra8_eswckdivcr_div4 

/4 – PLL1P/4 = 250 MHz (ESWCLK target).

k_ra8_eswckdivcr_div8 

/8

k_ra8_eswckdivcr_div16 

/16

k_ra8_eswckdivcr_div32 

/32

k_ra8_eswckdivcr_div64 

/64

Definition at line 45 of file ra8_cgc_eswclk.c.

◆ ra8_cgc_eswclk_const_t

enum ra8_cgc_eswclk_const_t : uint32_t

Constants used by the ESWCLK bring-up path.

ESWCKDIVCR.CKDIV is a 4-bit field. Code 0 = /1, code 1 = /2, ... code 6 = /64 (the FSP encoding table). 125 MHz = PLL1P (1 GHz) / 8; the matching code is k_ra8_eswckdivcr_div8 (= 3 in the standard FSP "log2 ratio" map).

Enumerator
k_ra8_cgc_eswclk_target_hz 

ESWCLK = PLL1P / 4.

k_ra8_cgc_eswphyclk_target_hz 

ESWPHYCLK = PLL1P / 2.

k_ra8_cgc_eswclk_poll_limit 

CKSRDY spin budget.

Definition at line 65 of file ra8_cgc_eswclk.c.

Function Documentation

◆ internal_eswclk_power_on_domain()

ra8_err_t internal_eswclk_power_on_domain ( void )
static

Power on the ESWM peripheral domain via PDCTRESWM.

After power-on reset the ESWM domain is gated – every per-port RMAC / ETHA register read returns 0 and writes are silently dropped until PDCTRESWM.PDDE = 0. PRCR group 1 (LPC + battery backup) protects this register. Mirrors FSP r_layer3_switch_module_start.

Returns
k_ra8_ok if PDCSF / PDPGSF both clear within the spin budget.
Return values
k_ra8_err_hw_timeoutPDCSF or PDPGSF stuck high after PDDE=0.
Precondition
PRCR-CGC is locked at entry.
Single-threaded init context.
Postcondition
On k_ra8_ok the ESWM peripheral domain is powered.
PRCR is re-locked.
Note
Not thread-safe.
Since
0.1.0

Definition at line 233 of file ra8_cgc_eswclk.c.

References internal_wait_pdctreswm_clear(), k_ra8_ok, k_ra8_pdctr_bit_pdcsf, k_ra8_pdctr_bit_pdde, k_ra8_pdctr_bit_pdpgsf, k_ra8_prcr_unlock_lpm, RA8_INTERNAL, ra8_log_error, RA8_PROTECTED_WRITE, ra8_sys_pdctreswm(), and s_tag.

Referenced by ra8_cgc_eswclk_init().

◆ internal_eswclk_program_cks()

ra8_err_t internal_eswclk_program_cks ( void )
static

Switch ESWCLK + ESWPHYCLK to PLL1P (250 MHz + 500 MHz).

Drives the canonical FSP SREQ/SRDY handshake on ESWCKCR (CKSEL=PLL1P, CKDIV=/4 -> 250 MHz) then ESWPCKCR (CKSEL=PLL1P, CKDIV=/2 -> 500 MHz). Matches the EK-RA8D2 FSP example project ethernet_ek_ra8d2_ep.

Returns
k_ra8_ok if both handshakes complete.
Return values
k_ra8_err_hw_timeoutCKSRDY transition stuck on either reg.
Precondition
HOCO is running (caller invoked priv_ra8_cgc_ensure_hoco_running_for_usb_ck).
Single-threaded init context.
Postcondition
On k_ra8_ok ESWCLK = 250 MHz, ESWPHYCLK = 500 MHz.
PRCR is re-locked.
Note
Not thread-safe.
Since
0.1.0

Definition at line 280 of file ra8_cgc_eswclk.c.

References internal_switch_eswcr_to_pll1p(), k_ra8_eswckdivcr_div2, k_ra8_eswckdivcr_div4, k_ra8_ok, k_ra8_prcr_unlock_cgc, RA8_INTERNAL, ra8_log_error, RA8_PROTECTED_WRITE, ra8_sys_eswckcr(), ra8_sys_eswckdivcr(), ra8_sys_eswpckcr(), ra8_sys_eswpckdivcr(), and s_tag.

Referenced by ra8_cgc_eswclk_init().

◆ internal_switch_eswcr_to_pll1p()

ra8_err_t internal_switch_eswcr_to_pll1p ( volatile uint8_t * ckcr_reg,
volatile uint8_t * divcr_reg,
uint8_t div_code )
static

Switch one ESW-family peripheral clock to PLL1P with the given divider code.

Both ESWCKCR (ESWM core clock) and ESWPCKCR (Ethernet-PHY interface clock) share the same SREQ/SRDY handshake protocol – the canonical FSP bsp_peripheral_clock_set sequence. Factoring this helper keeps ra8_cgc_eswclk_init short and lets the same logic configure both clocks without duplicating six MMIO writes per peripheral.

Parameters
[in]ckcr_regPointer to the 8-bit CKCR (source-select) reg.
[in]divcr_regPointer to the 8-bit CKDIVCR (divider) reg.
[in]div_codeDivider code from ra8_cgc_eswckdivcr_t.
Returns
ra8_err_t error code.
Return values
k_ra8_okClock switched.
k_ra8_err_hw_timeoutCKSRDY handshake exhausted spin budget.
Precondition
PRCR-CGC is unlocked (caller holds the RA8_PROTECTED_WRITE window).
HOCO is running (the SREQ->SRDY synchronizer chain crosses into the CURRENT source domain, which is HOCO at reset).
Postcondition
On k_ra8_ok, the targeted clock is sourced from PLL1P with the requested divider; both SREQ and SRDY read 0.
On failure CKSREQ may be left asserted; caller must reset the handshake before retrying.
Note
Not thread-safe.
Since
0.1.0

Definition at line 157 of file ra8_cgc_eswclk.c.

References internal_wait_cksrdy(), k_ra8_eswckcr_bit_srdy, k_ra8_eswckcr_bit_sreq, k_ra8_eswckcr_mask_sel, k_ra8_eswcksel_pll1p, k_ra8_ok, and RA8_INTERNAL.

Referenced by internal_eswclk_program_cks().

◆ internal_wait_cksrdy()

ra8_err_t internal_wait_cksrdy ( volatile const uint8_t * ckcr_reg,
uint8_t expected )
static

Spin-wait for a peripheral clock control register's CKSRDY bit to match expected.

Both ESWCKCR and ESWPCKCR share the same CKSRDY layout (bit 7), so one helper drains the SREQ/SRDY handshake for both peripherals.

Parameters
[in]ckcr_regPointer to the 8-bit peripheral clock control reg (ESWCKCR or ESWPCKCR; both have an identical CKSRDY layout at bit k_ra8_eswckcr_bit_srdy).
[in]expected0 or 1.
Returns
k_ra8_ok if CKSRDY reaches the expected level; otherwise k_ra8_err_hw_timeout.
Return values
k_ra8_okCKSRDY observed at the expected level.
k_ra8_err_hw_timeoutPoll budget exhausted.
Precondition
Caller holds the PRCR-CGC unlock window if this is run during a clock switch.
ckcr_reg points to a live ESWCKCR / ESWPCKCR register.
Postcondition
No state changes other than the implicit MMIO read.
The poll count never exceeds k_ra8_cgc_eswclk_poll_limit.
Note
Not thread-safe.
Since
0.1.0

Definition at line 113 of file ra8_cgc_eswclk.c.

References k_ra8_cgc_eswclk_poll_limit, k_ra8_eswckcr_bit_srdy, ra8_hw_wait_flag_clear8(), ra8_hw_wait_flag_set8(), and RA8_INTERNAL.

Referenced by internal_switch_eswcr_to_pll1p().

◆ internal_wait_pdctreswm_clear()

ra8_err_t internal_wait_pdctreswm_clear ( uint8_t bit)
static

Wait for a PDCTRESWM status bit to clear within a bounded budget.

Polls PDCTRESWM at the requested bit position until it reads 0 or the spin budget is exhausted. Used during the ESWM power-domain power-on sequence to confirm PDCSF / PDPGSF have settled.

Parameters
[in]bitBit position (PDCSF or PDPGSF) to poll.
Returns
k_ra8_ok if the bit clears, k_ra8_err_hw_timeout otherwise.
Return values
k_ra8_okPolled bit observed at 0.
k_ra8_err_hw_timeoutPoll budget exhausted with bit still 1.
Precondition
Caller is single-threaded init context.
bit is a valid PDCTRESWM read-only flag position.
Postcondition
No state changes other than the implicit MMIO read.
The poll count never exceeds k_ra8_cgc_eswclk_poll_limit.
Note
Not thread-safe.
Since
0.1.0

Definition at line 205 of file ra8_cgc_eswclk.c.

References k_ra8_cgc_eswclk_poll_limit, ra8_hw_wait_flag_clear8(), RA8_INTERNAL, and ra8_sys_pdctreswm().

Referenced by internal_eswclk_power_on_domain().

◆ ra8_cgc_eswclk_hz()

ra8_err_t ra8_cgc_eswclk_hz ( uint32_t * out_hz)
nodiscard

Query the current ESWCLK (Ethernet Switch clock) frequency.

Computed from the most recent ra8_cgc_eswclk_init call. Returns 0 if the ESWCLK has not been configured. Used by ra8_rmac_init (callers fill ra8_rmac_config_t.eswclk_hz from this value) to compute the MPIC.PSMCS divider code.

Parameters
[out]out_hzOn success, the live ESWCLK frequency in Hz.
Returns
ra8_err_t error code.
Return values
k_ra8_okESWCLK frequency written to *out_hz.
k_ra8_err_null_ptrout_hz is nullptr.
Precondition
out_hz is a valid 32-bit pointer.
Postcondition
On k_ra8_ok, *out_hz holds the live ESWCLK frequency (0 if ra8_cgc_eswclk_init has not yet succeeded).
Note
Thread-safe (read-only access to a published value).
Since
0.1.0

Definition at line 336 of file ra8_cgc_eswclk.c.

References k_ra8_err_null_ptr, k_ra8_ok, and s_eswclk_hz.

Referenced by gptp_arm(), priv_ra8_board_eth_eswm_bring_up(), and tsn_arm_time_base().

◆ ra8_cgc_eswclk_init()

ra8_err_t ra8_cgc_eswclk_init ( void )
nodiscard

Bring up the Ethernet Switch Module (ESWM / RMAC) clock.

On RA8D2 the RMAC PHY-station-management hardware (MPSM/MPIC) is fed by ESWCLK, a dedicated peripheral clock with its own source- select (ESWCKCR) and divider (ESWCKDIVCR) registers. After power-on reset ESWCKCR reads as 0 (ESWCKSEL = HOCO ~20 MHz) which is fine for MDC but the source-select handshake (CKSREQ -> CKSRDY) must still be exercised for the divider write to take effect. Symptom on a chip where this routine has not run: ra8_rmac_mdio_c22_read returns k_ra8_err_hw_timeout for every PHY address even though the wire is physically connected and the PHY is out of reset.

Sequence per FSP bsp_peripheral_clock_set and the HUM Ch 9 "Clock selection switching procedure":

  1. PRCR-CGC unlock window.
  2. ESWCKCR.CKSREQ = 1, wait CKSRDY = 1 (clock gated, switchable).
  3. Write ESWCKDIVCR.
  4. Write ESWCKCR = source | CKSREQ.
  5. Write ESWCKCR = source (drop the request bit).
  6. Wait CKSRDY = 0 (new clock running).
  7. PRCR re-lock.

This implementation picks PLL1P / 8 = 125 MHz as the ESWCLK source, matching what every FSP example for the EK-RA8D2 ships with. The resulting 125 MHz fans out to:

  • ESWM's per-port descriptor-ring logic.
  • The MPIC.PSMCS divider chain (-> 1 MHz MDC after ra8_rmac_init).

The same eswclk_hz value is what the caller passes via ra8_rmac_config_t::eswclk_hz so internal_calc_psmcs can compute the right MPIC.PSMCS divider code.

Returns
ra8_err_t error code.
Return values
k_ra8_okESWCLK selected and running.
k_ra8_err_hw_timeoutCKSRDY handshake never completed.
Precondition
ra8_cgc_init has been called (PLL1 locked).
Single-threaded init context.
Postcondition
ESWCKCR.CKSEL = k_ra8_eswcksel_pll1p, ESWCKDIVCR = /1.
Subsequent ra8_rmac_init calls will see a live ESWCLK.
PRCR is re-locked.
Note
Not thread-safe.
Since
0.1.0

Definition at line 303 of file ra8_cgc_eswclk.c.

References internal_eswclk_power_on_domain(), internal_eswclk_program_cks(), k_ra8_cgc_eswclk_target_hz, k_ra8_mstp_ethphyclk, k_ra8_ok, priv_ra8_cgc_ensure_hoco_running_for_usb_ck(), ra8_log_error, ra8_log_info, ra8_mstp_enable(), s_eswclk_hz, and s_tag.

Referenced by ehb_run_once(), gptp_setup_or_halt(), priv_ra8_board_eth_eswm_bring_up(), and tsn_setup_or_halt().

Variable Documentation

◆ s_eswclk_hz

uint32_t s_eswclk_hz = 0U
static

Live ESWCLK frequency, published by ra8_cgc_eswclk_init.

Set to k_ra8_cgc_eswclk_target_hz on a successful bring-up; remains 0 until then. Callers query the value via ra8_cgc_eswclk_hz so ra8_rmac_init can fill ra8_rmac_config_t.eswclk_hz without the application having to know the PLL configuration.

Note
Mutated only under PRCR-CGC unlock from ra8_cgc_eswclk_init.
Since
0.1.0

Definition at line 84 of file ra8_cgc_eswclk.c.

Referenced by ra8_cgc_eswclk_hz(), and ra8_cgc_eswclk_init().

◆ s_tag

const char* s_tag = "CGC"
static

Definition at line 43 of file ra8_cgc_eswclk.c.