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

High-level Clock Generation Circuit driver. More...

#include "ra8_cgc_regs.h"
#include "ra8_err.h"
Include dependency graph for ra8_cgc.h:

Go to the source code of this file.

Typedefs

typedef void(* ra8_cgc_ostd_fn_t) (void *ctx)
 Oscillation-stop-detection callback.

Enumerations

enum  ra8_clock_id_t : uint8_t {
  k_ra8_clock_id_cpuclk0 = 0U ,
  k_ra8_clock_id_cpuclk1 = 1U ,
  k_ra8_clock_id_iclk = 2U ,
  k_ra8_clock_id_pclka = 3U ,
  k_ra8_clock_id_pclkb = 4U ,
  k_ra8_clock_id_pclkc = 5U ,
  k_ra8_clock_id_pclkd = 6U ,
  k_ra8_clock_id_pclke = 7U ,
  k_ra8_clock_id_fclk = 8U ,
  k_ra8_clock_id_mriclk = 9U
}
 Identifiers for the clock-tree frequencies queryable at runtime. More...

Functions

ra8_err_t ra8_cgc_init (void)
 Configure the clock tree to a safe default.
ra8_err_t ra8_cgc_use_hoco (void)
 Switch the system clock source to HOCO (20 MHz).
ra8_err_t ra8_cgc_get_clock_hz (ra8_clock_id_t id, uint32_t *out_hz)
 Query the current frequency of a clock-tree domain.
ra8_err_t ra8_cgc_switch_pll1_target (uint32_t new_cpuclk_hz)
 Retune PLL1 to a new CPUCLK0 target without a full deinit.
ra8_err_t ra8_cgc_enable_stop_detection (ra8_cgc_ostd_fn_t handler, void *ctx)
 Enable oscillation-stop detection on the main crystal.
ra8_err_t ra8_cgc_disable_stop_detection (void)
 Disable oscillation-stop detection.
ra8_err_t ra8_cgc_usbhs_pll_enable (void)
 Bring up the USBHS PHY reference clock + module clock.
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.
ra8_err_t ra8_cgc_pll2_enable (uint8_t mul_int, uint8_t mul_quarters, ra8_plodiv_t p_div_code)
 Bring up PLL2 with caller-supplied multiplier and P divider.
ra8_err_t ra8_cgc_usbfs_clock_enable (void)
 Bring up the USB-FS module clock (USBCKCR / USBCKDIVCR).
void ra8_cgc_fake_trigger_stop_detection (void)
 Test helper: invoke the registered OSTD callback.

Detailed Description

High-level Clock Generation Circuit driver.

Minimal clock-init surface for bring-up. The RA8D2 defaults to MOCO (~8 MHz) out of reset, which is enough to blink an LED and exercise the IOPORT block without touching CGC at all. Use the helpers here to move up to HOCO (20 MHz) or the full PLL1 path (CPUCLK0 up to 1 GHz) as the firmware grows.

Definition in file ra8_cgc.h.

Typedef Documentation

◆ ra8_cgc_ostd_fn_t

typedef void(* ra8_cgc_ostd_fn_t) (void *ctx)

Oscillation-stop-detection callback.

Parameters
[in]ctxUser-supplied context registered with the callback.
Note
Invoked from ISR context. Must return quickly. The ISR clears the latched OSTDSR flag before the callback runs.

Definition at line 114 of file ra8_cgc.h.

Enumeration Type Documentation

◆ ra8_clock_id_t

enum ra8_clock_id_t : uint8_t

Identifiers for the clock-tree frequencies queryable at runtime.

Enumerator
k_ra8_clock_id_cpuclk0 

Cortex-M85 CPUCLK0.

k_ra8_clock_id_cpuclk1 

Cortex-M33 CPUCLK1.

k_ra8_clock_id_iclk 

System ICLK.

k_ra8_clock_id_pclka 

PCLKA.

k_ra8_clock_id_pclkb 

PCLKB.

k_ra8_clock_id_pclkc 

PCLKC.

k_ra8_clock_id_pclkd 

PCLKD.

k_ra8_clock_id_pclke 

PCLKE.

k_ra8_clock_id_fclk 

Flash/MRAM interface clock.

k_ra8_clock_id_mriclk 

MRAM bus clock.

Definition at line 69 of file ra8_cgc.h.

Function Documentation

◆ ra8_cgc_disable_stop_detection()

ra8_err_t ra8_cgc_disable_stop_detection ( void )
nodiscard

Disable oscillation-stop detection.

Returns
ra8_err_t error code.
Return values
k_ra8_okDetector disabled.
Precondition
IRQs masked or single-threaded init context.
Postcondition
OSTDCR.OSTDE is clear.
Previously-registered callback is cleared.
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 874 of file ra8_cgc.c.

References k_ra8_ok, ra8_log_info, s_ostd_ctx, s_ostd_enabled, s_ostd_handler, and s_tag.

◆ ra8_cgc_enable_stop_detection()

ra8_err_t ra8_cgc_enable_stop_detection ( ra8_cgc_ostd_fn_t handler,
void * ctx )
nodiscard

Enable oscillation-stop detection on the main crystal.

Programmes OSTDCR to enable the OST detector and installs a callback that fires when the OSTDSR flag is set (oscillator has stopped unexpectedly). The callback runs from the CGC interrupt handler after the driver clears the latched flag.

Parameters
[in]handlerCallback invoked on oscillation-stop event. Must not be NULL.
[in]ctxStored context passed to the callback.
Returns
ra8_err_t error code.
Return values
k_ra8_okDetector armed.
k_ra8_err_null_ptrhandler was NULL.
Precondition
ra8_cgc_init has been called.
Postcondition
OSTDCR.OSTDE is set.
Callback will fire on the next detected stop event.
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 857 of file ra8_cgc.c.

References k_ra8_err_null_ptr, k_ra8_ok, ra8_log_info, s_ostd_ctx, s_ostd_enabled, s_ostd_handler, and s_tag.

◆ 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().

◆ ra8_cgc_fake_trigger_stop_detection()

void ra8_cgc_fake_trigger_stop_detection ( void )

Test helper: invoke the registered OSTD callback.

Unit tests call this to simulate a CGC oscillation-stop interrupt firing, verifying that the callback + context are correctly stored and that OSTDSR is cleared before the handler runs. Target builds use the real ICU / NVIC path plumbed through ra8_isr_dispatch instead.

Precondition
ra8_cgc_enable_stop_detection has been called.
Postcondition
OSTDSR is cleared.
The registered callback ran exactly once.
Note
Thread safety: not thread-safe.
Since
0.1.0
Precondition
Module state is consistent.

Definition at line 883 of file ra8_cgc.c.

References s_ostd_ctx, s_ostd_enabled, and s_ostd_handler.

◆ ra8_cgc_get_clock_hz()

ra8_err_t ra8_cgc_get_clock_hz ( ra8_clock_id_t id,
uint32_t * out_hz )
nodiscard

Query the current frequency of a clock-tree domain.

Returns the value last programmed by ra8_cgc_init() (or the reset default MOCO value if ra8_cgc_init() has not yet run). Drivers that need to compute baud rates or sampling periods should always go through this function rather than hard-coding values from ra8_time_constants.h.

Parameters
[in]idClock identifier.
[out]out_hzOn success, current frequency in Hz.
Returns
k_ra8_ok on success, k_ra8_err_invalid_arg if out_hz is NULL or id is out of range.
Since
0.1.0

Definition at line 132 of file ra8_cgc.c.

References k_ra8_err_invalid_arg, k_ra8_err_null_ptr, k_ra8_ok, and s_clock_hz.

Referenced by adc_diag_setup_or_halt(), al_setup_or_halt(), app_bringup_clocks(), blc_setup_or_halt(), bm_setup_or_halt(), bs_setup_or_halt(), c6_fwver_setup_or_halt(), c6_hosted_setup_or_halt(), c6_join_setup_or_halt(), c6_probe_clocks_or_halt(), c6_wifi_setup_or_halt(), cam_bringup(), cdc_setup_or_halt(), ch_setup_or_halt(), cm_bringup_clocks(), combo_clocks_or_halt(), crc_demo_setup_or_halt(), demo_setup_or_halt(), demo_setup_or_halt(), dfu_setup_or_halt(), drw_blend_setup_or_halt(), drw_demo_setup_or_halt(), dtc_arm_setup_or_halt(), dtc_demo_setup_or_halt(), ec_setup_or_halt(), ef_setup_or_halt(), ehb_setup_or_halt(), eoh_setup_or_halt(), eop_setup_or_halt(), ep_bringup_core(), ep_setup_or_halt(), er_try_load_font(), erb_setup_or_halt(), es_setup_or_halt(), est_setup_or_halt(), etoc_setup_or_halt(), ez_bringup_clocks(), fileops_setup_or_halt(), flash_journal_setup_or_halt(), fs_fmt_setup_or_halt(), gh_setup_or_halt(), gpt_ecc_clocks_or_halt(), gptp_setup_or_halt(), hid_setup_or_halt(), i3c_demo_clocks_or_halt(), iic_setup_or_halt(), imp_setup_or_halt(), imu_demo_clocks_or_halt(), internal_acmphs_demo_setup(), internal_agt_periodic_setup_or_halt(), internal_audio_loopback_init_clocks_and_led(), internal_bkup_demo_setup_or_halt(), internal_can_demo_setup_or_halt(), internal_canfd_demo_setup_or_halt(), internal_canfd_filter_setup_or_halt(), internal_clock_check_verify_all(), internal_clocks_or_halt(), internal_clocks_or_halt(), internal_dac_b_demo_setup_or_halt(), internal_dac_demo_setup_or_halt(), internal_demo_clocks_or_halt(), internal_demo_setup_or_halt(), internal_dotf_demo_setup_or_halt(), internal_eth_loopback_setup_or_halt(), internal_gpio_demo_setup_or_halt(), internal_gpt_3p_demo_setup_or_halt(), internal_gpt_irq_demo_setup_or_halt(), internal_gpt_pwm_demo_setup_or_halt(), internal_icu_extint_demo_setup_or_halt(), internal_iic_peripheral_setup_or_halt(), internal_kat_setup_or_halt(), internal_kint_demo_setup_or_halt(), internal_lcd_bringup_clocks(), internal_lpm_deep_setup_or_halt(), internal_lpm_demo_setup_or_halt(), internal_lpm_dpsby1_setup_or_halt(), internal_lpm_dpsby2_setup_or_halt(), internal_lpm_dpsby3_setup_or_halt(), internal_lpm_swstd_setup_or_halt(), internal_lpm_wake_setup_or_halt(), internal_lus_setup_or_halt(), internal_lvd_demo_setup_or_halt(), internal_mecc_setup_or_halt(), internal_motor_3phase_init_clocks_and_led(), internal_mpu_simple_setup_or_halt(), internal_pc_setup_or_halt(), internal_pdg_demo_setup_or_halt(), internal_poeg_demo_setup_or_halt(), internal_program_data_phase(), internal_rc_setup_or_halt(), internal_rcs_setup_or_halt(), internal_rng_demo_setup_or_halt(), internal_rtc_demo_setup_or_halt(), internal_sd_demo_setup_or_halt(), internal_setup_or_halt(), internal_ssie_loop_setup_or_halt(), internal_tc_setup_or_halt(), internal_td_setup_or_halt(), internal_uart_hello_setup_or_halt(), internal_usb_audio_clocks_or_halt(), internal_wdt_demo_setup_or_halt(), ipc_demo_setup_or_halt(), iu_setup_or_halt(), iv_setup_or_halt(), kat_setup_or_halt(), kb_setup_or_halt(), l3_setup_or_halt(), lcd_bringup_clocks(), lin_hil_setup_or_halt(), lk_setup_or_halt(), lpi_setup_or_halt(), main(), mem_setup_or_halt(), mg_bringup_clocks(), microsd_setup_or_halt(), mlun_setup_or_halt(), modem_clocks_or_halt(), ospirw_setup_or_halt(), pp_demo_clocks_or_halt(), priv_ra8_esp_hosted_rtos_init(), ra8_board_camera_xclk_start(), ra8_board_touch_open(), ra8_board_uart_console_init(), ra8_canfd_set_bitrate(), ra8_nsc_cgc_get_clock_hz(), ra8_pwr_get_clock_hz(), ra8_threadx_systick_retune(), riic_target_clocks_or_halt(), rot_setup_or_halt(), sb_setup_or_halt(), scb_demo_setup_or_halt(), sd_demo_setup_or_halt(), sd_setup_or_halt(), sdhi_card_setup_or_halt(), sdhi_demo_setup_or_halt(), sdmsc_setup_or_halt(), sdram_demo_setup_or_halt(), selftest_setup_or_halt(), sfr_bringup_clocks(), sh_sd_mount(), sh_setup_or_halt(), tb_setup_or_halt(), timer_demo_setup_or_halt(), tsn_setup_or_halt(), tx_application_define(), uart_irq_setup_or_halt(), wa_setup_or_halt(), wc_setup_or_halt(), wd_setup_or_halt(), wdt_rr_setup_or_halt(), wdt_window_demo_setup_or_halt(), webp_demo_setup_or_halt(), wifi_hal_setup_or_halt(), wk_setup_or_halt(), and wlun_setup_or_halt().

◆ ra8_cgc_init()

ra8_err_t ra8_cgc_init ( void )
nodiscard

Configure the clock tree to a safe default.

For v0.x bring-up this function is intentionally a no-op: the firmware runs on MOCO (8 MHz) until a real PLL bring-up lands. Returning k_ra8_ok lets main() keep the pattern:

// ... drivers ...
ra8_err_t ra8_cgc_init(void)
Configure the clock tree to a safe default.
Definition ra8_cgc.c:727
#define RA8_ERROR_CHECK(err)
Halt on fatal error.
Definition ra8_check.h:147
void ra8_infrastructure_init(void)
Run every piece of infrastructure init that a driver may assume.

which will automatically start using the real implementation once this function is filled out.

Returns
Always k_ra8_ok today. Will return clock-setup errors once a real PLL routine is wired in.
Since
0.1.0

Definition at line 727 of file ra8_cgc.c.

References internal_cgc_init_protected(), internal_clear_pfb(), internal_publish_clocks(), internal_route_sciclk(), internal_set_pfb(), k_ra8_ok, k_ra8_prcr_unlock_cgc, ra8_log_error_val, ra8_log_info, RA8_PROTECTED_WRITE, and s_tag.

Referenced by adc_diag_setup_or_halt(), al_setup_or_halt(), app_bringup_clocks(), app_launch_hil_console_init(), app_setup(), app_shell_hil_console_init(), blc_setup_or_halt(), bm_setup_or_halt(), bs_setup_or_halt(), c6_fwver_setup_or_halt(), c6_hosted_setup_or_halt(), c6_join_setup_or_halt(), c6_probe_clocks_or_halt(), c6_wifi_setup_or_halt(), cache_hal_setup(), cache_mpu_setup(), cam_bringup(), cdc_setup_or_halt(), ch_setup_or_halt(), cm_bringup_clocks(), combo_clocks_or_halt(), crc_demo_setup_or_halt(), demo_setup_or_halt(), demo_setup_or_halt(), dfu_setup_or_halt(), drw_blend_setup_or_halt(), drw_demo_setup_or_halt(), dtc_arm_setup_or_halt(), dtc_coh_setup_or_halt(), dtc_demo_setup_or_halt(), dualcore_bg_hil_console_init(), dualcore_mailbox_hil_console_init(), ec_setup_or_halt(), ef_setup_or_halt(), ehb_setup_or_halt(), eoh_setup_or_halt(), eop_setup_or_halt(), ep_bringup_core(), ep_setup_or_halt(), erb_setup_or_halt(), es_setup_or_halt(), est_setup_or_halt(), etoc_setup_or_halt(), ez_bringup_clocks(), fc_setup_or_halt(), fileops_setup_or_halt(), flash_journal_setup_or_halt(), fs_fmt_setup_or_halt(), gh_setup_or_halt(), gpt_ecc_clocks_or_halt(), gptp_setup_or_halt(), hid_setup_or_halt(), i3c_demo_clocks_or_halt(), iic_setup_or_halt(), imp_setup_or_halt(), imu_demo_clocks_or_halt(), internal_acmphs_demo_setup(), internal_agt_periodic_setup_or_halt(), internal_audio_loopback_init_clocks_and_led(), internal_bkup_demo_setup_or_halt(), internal_can_demo_setup_or_halt(), internal_canfd_demo_setup_or_halt(), internal_canfd_filter_setup_or_halt(), internal_clocks_or_halt(), internal_clocks_or_halt(), internal_console_init(), internal_dac_b_demo_setup_or_halt(), internal_dac_demo_setup_or_halt(), internal_demo_clocks_or_halt(), internal_demo_setup_or_halt(), internal_dotf_demo_setup_or_halt(), internal_eth_loopback_setup_or_halt(), internal_gpio_demo_setup_or_halt(), internal_gpt_3p_demo_setup_or_halt(), internal_gpt_irq_demo_setup_or_halt(), internal_gpt_pwm_demo_setup_or_halt(), internal_icu_extint_demo_setup_or_halt(), internal_iic_peripheral_setup_or_halt(), internal_kat_setup_or_halt(), internal_kint_demo_setup_or_halt(), internal_lcd_bringup_clocks(), internal_lpm_deep_setup_or_halt(), internal_lpm_demo_setup_or_halt(), internal_lpm_dpsby1_setup_or_halt(), internal_lpm_dpsby2_setup_or_halt(), internal_lpm_dpsby3_setup_or_halt(), internal_lpm_swstd_setup_or_halt(), internal_lpm_wake_setup_or_halt(), internal_lus_setup_or_halt(), internal_lvd_demo_setup_or_halt(), internal_mecc_setup_or_halt(), internal_motor_3phase_init_clocks_and_led(), internal_mpu_simple_setup_or_halt(), internal_npu_infer_setup_or_halt(), internal_npu_smoke_setup_or_halt(), internal_npu_vela_setup_or_halt(), internal_pc_setup_or_halt(), internal_pdg_demo_setup_or_halt(), internal_poeg_demo_setup_or_halt(), internal_rc_setup_or_halt(), internal_rcs_setup_or_halt(), internal_rng_demo_setup_or_halt(), internal_rtc_demo_setup_or_halt(), internal_sd_demo_setup_or_halt(), internal_setup_or_halt(), internal_ssie_loop_setup_or_halt(), internal_tc_setup_or_halt(), internal_td_setup_or_halt(), internal_uart_hello_setup_or_halt(), internal_usb_audio_clocks_or_halt(), internal_wdt_demo_setup_or_halt(), ipc_demo_setup_or_halt(), iu_setup_or_halt(), iv_setup_or_halt(), kat_setup_or_halt(), kb_setup_or_halt(), l3_setup_or_halt(), lcd_bringup_clocks(), lin_hil_setup_or_halt(), lk_setup_or_halt(), lpi_setup_or_halt(), main(), mem_setup_or_halt(), mg_bringup_clocks(), microsd_setup_or_halt(), mlun_setup_or_halt(), modem_clocks_or_halt(), mpu_boot_setup(), ospirw_setup_or_halt(), pp_demo_clocks_or_halt(), ra8_board_clocks_init(), riic_target_clocks_or_halt(), rot_setup_or_halt(), sb_setup_or_halt(), scb_demo_setup_or_halt(), sd_demo_setup_or_halt(), sd_setup_or_halt(), sdhi_card_setup_or_halt(), sdhi_demo_setup_or_halt(), sdmsc_setup_or_halt(), sdram_demo_setup_or_halt(), selftest_setup_or_halt(), sfr_bringup_clocks(), sh_setup_or_halt(), SystemInit(), tb_setup_or_halt(), timer_demo_setup_or_halt(), tsn_setup_or_halt(), uart_irq_setup_or_halt(), wa_setup_or_halt(), wc_setup_or_halt(), wd_setup_or_halt(), wdt_rr_setup_or_halt(), wdt_window_demo_setup_or_halt(), webp_demo_setup_or_halt(), wifi_hal_setup_or_halt(), wk_setup_or_halt(), and wlun_setup_or_halt().

◆ ra8_cgc_pll2_enable()

ra8_err_t ra8_cgc_pll2_enable ( uint8_t mul_int,
uint8_t mul_quarters,
ra8_plodiv_t p_div_code )
nodiscard

Bring up PLL2 with caller-supplied multiplier and P divider.

Sequence (mirrors FSP bsp_clocks.c PLL2 path and HUM Ch 9.2.10..12):

  1. PRCR-CGC unlock window.
  2. Stop PLL2 (PLL2CR.PLL2STP = 1) and wait OSCSF.PLL2SF = 0.
  3. Programme PLL2CCR (input divider, source, multiplier) and PLL2CCR2 (output dividers).
  4. Start PLL2 (PLL2CR.PLL2STP = 0) and wait OSCSF.PLL2SF = 1.
  5. PRCR re-lock.

The multiplier is encoded the same way PLL1 encodes it: the integer part goes in PLL2MUL[15:8] and the quarter-step fractional part in PLL2MULNF[7:6]. Caller passes the integer multiplier (1..255) and the quarter-steps (0..3) separately.

Output dividers use the standard ra8_plodiv_t code-to-ratio map (e.g. /4 = 3, /5 = 4, /6 = 5).

VCO frequency MUST land in the 960..2400 MHz range required by the RA8D2 silicon (per BSP_FEATURE_CGC_PLLCCR_VCO_*). PLL2 output frequency MUST land in 60..1200 MHz (BSP_FEATURE_CGC_PLL2_OUT_*). The driver does not enforce this; the caller is responsible.

Input source is fixed to the main XTAL on EK-RA8D2 (PL2SRCSEL = 0) and input divider is fixed to /2 so the PLL pre-scale lands at 12 MHz, matching what the FSP quickstart does for the 24 MHz crystal.

Parameters
[in]mul_intInteger multiplier (1..255). Effective multiplier is mul_int + (mul_quarters / 4).
[in]mul_quartersFractional quarter-steps (0..3).
[in]p_div_codeOutput divider P code from ra8_plodiv_t (e.g. k_ra8_plodiv_div4 for /4).
Returns
ra8_err_t error code.
Return values
k_ra8_okPLL2 locked.
k_ra8_err_invalid_argmul_int is 0 or mul_quarters > 3.
k_ra8_err_hw_timeoutPLL2SF stop or start handshake exhausted its spin budget.
Precondition
ra8_cgc_init has been called (main XTAL stable).
Single-threaded init context.
CPU is not currently sourced from PLL2.
Postcondition
On k_ra8_ok return, PLL2 is locked and ready to be selected as a USBCKCR source.
PRCR is re-locked.
Note
Not thread-safe.
Example:
// 24 MHz / 2 (fixed) * 80 = 960 MHz VCO; /4 -> 240 MHz PLL2P.
ra8_err_t ra8_cgc_pll2_enable(uint8_t mul_int, uint8_t mul_quarters, ra8_plodiv_t p_div_code)
Bring up PLL2 with caller-supplied multiplier and P divider.
@ k_ra8_plodiv_div4
PLL output divide by 4.
See also
ra8_cgc_usbfs_clock_enable
Since
0.1.0

Bring up PLL2 with caller-supplied multiplier and P divider.

Idempotent: if OSCSF.PLL2SF is already asserted on entry the function returns k_ra8_ok without touching PLL2CCR / PLL2CCR2 / PLL2CR. This lets the FS and HS USB bring-up paths (which both want the same 960 MHz VCO with PLL2P = /4 = 240 MHz) coexist on the same boot without re-programming a live PLL2 (HUM Ch 9 forbids writing PLL2CCR while PLL2 is running, and downstream consumers – including USBCKCR sourced from PLL2P after the FS path runs – would lose their clock during the re-program).

Stops PLL2 (with bounded poll on OSCSF.PLL2SF clear), programmes PLL2CCR + PLL2CCR2, then starts PLL2 (bounded poll on OSCSF.PLL2SF set). Input divider is hard-wired to /2 and source to main XTAL because that is the only configuration the EK-RA8D2 (24 MHz crystal) needs today; broaden the API once a second board lands.

Parameters
[in]mul_intInteger multiplier (1..255).
[in]mul_quartersQuarter-step fractional multiplier (0..3).
[in]p_div_codera8_plodiv_t code for the P output divider.
Returns
Result code.
Return values
k_ra8_okPLL2 locked.
k_ra8_err_invalid_argmul_int is 0 or mul_quarters > 3.
k_ra8_err_hw_timeoutPLL2SF stop or start handshake timed out.
Precondition
ra8_cgc_init has been called and main XTAL is stable.
Single-threaded init context; CPU not sourced from PLL2.
Postcondition
On k_ra8_ok: PLL2 is locked at the requested multiplier and output divider; PRCR is re-locked.
On any error path the PRCR window is closed by RA8_PROTECTED_WRITE.
Note
Not thread-safe.
Since
0.1.0

Definition at line 258 of file ra8_cgc_usb.c.

References internal_pll2_program_protected(), k_ra8_cgc_quarters_per_unit, k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_oscsf_bit_pll2sf, k_ra8_plidiv_div2, k_ra8_pll2_max_quarters, k_ra8_pll2ccr_mask_plidiv, k_ra8_pll2ccr_mask_quarters, k_ra8_pllccr2_shift_plodivp, k_ra8_pllccr2_shift_plodivq, k_ra8_pllccr2_shift_plodivr, k_ra8_pllccr_shift_plsrcsel, k_ra8_pllccr_shift_quarters, k_ra8_plodiv_div6, k_ra8_plsrcsel_main, ra8_log_info, ra8_log_info_val, ra8_sys_oscsf(), and s_tag.

Referenced by ra8_cgc_usbfs_clock_enable(), ra8_cgc_usbhs_pll_enable(), and ra8_nsc_cgc_pll2_enable().

◆ ra8_cgc_switch_pll1_target()

ra8_err_t ra8_cgc_switch_pll1_target ( uint32_t new_cpuclk_hz)
nodiscard

Retune PLL1 to a new CPUCLK0 target without a full deinit.

Walks through the safe transition sequence from HUM Ch 9.2 (p 317):

  1. Switch SCKSCR to MOCO so the CPU runs on a simple source while PLL1 is being reprogrammed.
  2. Stop PLL1 via PLLCR.PLLSTP.
  3. Compute the new PLLCCR / PLLCCR2 integer + fractional multipliers from new_cpuclk_hz.
  4. Start PLL1 and wait for OSCSF.PLL1SF.
  5. Switch SCKSCR back to PLL1.
  6. Republish the clock-tree frequencies so subsequent ra8_cgc_get_clock_hz calls see the new value.
Parameters
[in]new_cpuclk_hzTarget CPUCLK0 frequency in Hz. Must be a multiple of the crystal divided by 32 (the PLLCCR2 fractional step).
Returns
ra8_err_t error code.
Return values
k_ra8_okClock switched to the new target.
k_ra8_err_invalid_argnew_cpuclk_hz is 0.
k_ra8_err_hw_timeoutPLL lock or MOCO wait timed out.
Precondition
ra8_cgc_init has been called (PLL1 is the current source).
IRQs masked or single-threaded init context.
Postcondition
On success, SCKSCR == PLL1 and the reported CPUCLK0 frequency matches new_cpuclk_hz to within the PLL2 fractional resolution.
Note
Thread safety: not thread-safe.
Since
0.1.0

Definition at line 814 of file ra8_cgc.c.

References internal_program_and_start_pll1(), internal_publish_clocks(), internal_stop_pll1(), k_ra8_cksel_moco, k_ra8_cksel_pll1, k_ra8_clock_id_cpuclk0, k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_prcr_unlock_cgc, ra8_log_error_val, ra8_log_info_val, RA8_PROTECTED_WRITE, ra8_sys_sckscr(), s_clock_hz, and s_tag.

◆ ra8_cgc_usbfs_clock_enable()

ra8_err_t ra8_cgc_usbfs_clock_enable ( void )
nodiscard

Bring up the USB-FS module clock (USBCKCR / USBCKDIVCR).

On RA8D2 the USB-FS controller is not clocked merely by ungating MSTPCRB.MSTPB11 – the System Control block has a dedicated USBCKCR / USBCKDIVCR pair (HUM Ch 9, USBCKCR p 365) that selects the source clock for the controller's 48 MHz reference. After power-on reset USBCKCR reads as 0 (USBCKSEL = HOCO, ~20 MHz) which is not a valid USB-FS reference, and the SIE will never bus-reset a connected device. Symptom on EK-RA8D2: DVSTCTR0 stuck at 0x0002 (Powered, never Default), INTSTS0.CTRT = 0, no SETUP packet ever delivered.

Sequence per FSP bsp_clocks.c and HUM Ch 9 "Clock selection switching procedure" (canonical example: SPICKCR p 370):

  1. Force MSTPCRB.MSTPB11 = 1 (USBFS module-stopped). HUM step 1 requires this whenever USBCKDIVCR is moved off 1/1; we are programming /5 below, and a caller that has already released MSTPB11 (e.g. by invoking ra8_usb_device_init first) will otherwise hang the SREQ -> SRDY handshake silently.
  2. PRCR-CGC unlock window.
  3. USBCKCR.USBCKSREQ = 1, wait USBCKSRDY = 1 (clock gated).
  4. Write USBCKDIVCR.
  5. Write USBCKCR = src | USBCKSREQ.
  6. Write USBCKCR = src (drop the request bit).
  7. Wait USBCKSRDY = 0 (new clock running).
  8. PRCR re-lock.

Source picked here is PLL2P with USBCKDIVCR = /5 codepoint. PLL2 is brought up via ra8_cgc_pll2_enable to land on VCO = 24 MHz / 2 * 80 = 960 MHz, then PL2ODIVP = /4 -> PLL2P = 240 MHz. USBCKDIVCR = /5 then yields exactly 48.000 MHz, which is within the USB-FS spec (48 MHz +/- 2500 ppm = +/- 0.25 %).

Returns
ra8_err_t error code.
Return values
k_ra8_okUSB-FS module clock running.
k_ra8_err_hw_timeoutUSBCKSRDY handshake never completed.
Precondition
ra8_cgc_init has been called (PLL1 locked).
Single-threaded init context.
Should run BEFORE any caller releases MSTPB11 (USBFS) – the routine forces MSTPB11 = 1 internally for safety, but invoking this from main() before any USB driver init is the documented call order.
Postcondition
USBCKCR.USBCKSEL = k_ra8_usbcksel_pll2p.
USBCKDIVCR programmed for /5 (codepoint 6).
MSTPCRB.MSTPB11 = 1 (USBFS module-stopped); the USB driver must subsequently release it via ra8_mstp_enable / its ra8_usb_device_init wrapper.
PRCR is re-locked.
Note
Not thread-safe.
See also
ra8_cgc_usbhs_pll_enable
Since
0.1.0

Bring up the USB-FS module clock (USBCKCR / USBCKDIVCR).

  1. Enable PLL2 at 960 MHz VCO with PLL2P = /4 = 240 MHz.
  2. Force MSTPB11 = 1 (USBFS module-stop) before reprogramming USBCKDIVCR per HUM Ch 9 "Clock selection switching procedure".
  3. Run the SREQ / SRDY handshake to swap USBCKCR.SEL to PLL2P and USBCKDIVCR to /5, landing 48.000 MHz on USBCLK (0 ppm vs the USB-FS 48 MHz +/- 0.25 % spec).
Returns
ra8_err_t error code.
Return values
k_ra8_okUSB-FS clock running at exactly 48 MHz.
k_ra8_err_hw_init_failedPLL2 enable failed; see log.
k_ra8_err_hw_timeoutUSBCKCR SREQ/SRDY handshake timed out.
Precondition
Caller is single-threaded init context.
PLL1 / SCKSCR have already been programmed by ra8_cgc_init.
Postcondition
On k_ra8_ok PLL2 is locked, MSTPB11 is set, USBCKCR sources PLL2P / 5 = 48 MHz, and PRCR is re-locked.
On error the USB-FS clock is left in a quiesced state.
Note
Not thread-safe; init context only.
Since
0.1.0

Definition at line 364 of file ra8_cgc_usb.c.

References internal_usbckcr_switch_to_pll2p_div5(), k_ra8_hococr_hcstp, k_ra8_mstpb11_usbfs_mask, k_ra8_ok, k_ra8_oscsf_bit_hocosf, k_ra8_pll2_usbfs_mul, k_ra8_pll2_usbfs_quarters, k_ra8_plodiv_div4, k_ra8_prcr_unlock_cgc, r_mstp_regs_t::MSTPCRB, priv_ra8_cgc_wait_oscsf_set(), ra8_cgc_pll2_enable(), ra8_log_error, ra8_log_error_val, ra8_log_info, ra8_mstp(), RA8_PROTECTED_WRITE, ra8_sys_hococr(), and s_tag.

Referenced by blc_setup_or_halt(), cdc_setup_or_halt(), dfu_setup_or_halt(), fileops_setup_or_halt(), hid_setup_or_halt(), main(), microsd_setup_or_halt(), mlun_setup_or_halt(), ospirw_setup_or_halt(), ra8_nsc_cgc_usbfs_clock_enable(), sdmsc_setup_or_halt(), selftest_setup_or_halt(), and wlun_setup_or_halt().

◆ ra8_cgc_usbhs_pll_enable()

ra8_err_t ra8_cgc_usbhs_pll_enable ( void )
nodiscard

Bring up the USBHS PHY reference clock + module clock.

The RA8D2 USB 2.0 High-Speed controller drives an internal PHY whose 480 MHz CDR PLL needs a stable 12 MHz reference derived from the main XTAL (24 MHz / 2). The CGC-side gating for that path lives in the System Control block; the procedure (per HUM Ch 9 "Clock Generation Circuit", USBCKCR / USBCKDIVCR description, p 365) is:

  1. Verify the main oscillator is stable (OSCSF.MOSCSF = 1). The PHY cannot lock without a stable XTAL reference.
  2. Inside a PRCR-CGC unlock window, the USBHS module clock select is committed (USBCKCR.USBCKSREQ / USBCKSRDY handshake on silicon; plain RAM on the host fake).
  3. Re-lock PRCR.

After this returns k_ra8_ok the caller is free to invoke ra8_mstp_enable for k_ra8_mstp_usbhs (typically routed through ra8_usb_device_init / ra8_usb_host_init) and the controller's SYSCFG.USBE bit will see a clocked PHY underneath it.

Returns
ra8_err_t error code.
Return values
k_ra8_okUSBHS clock subsystem armed.
k_ra8_err_hw_timeoutMain XTAL never reported stable.
Precondition
ra8_cgc_init has been called (main XTAL has been started).
Caller is single-threaded init context.
Postcondition
OSCSF.MOSCSF = 1 (main XTAL still running).
USBHS clock subsystem is selected and ready for the MSTP ungate that follows.
Note
Not thread-safe.
Since
0.1.0

Bring up the USBHS PHY reference clock + module clock.

The USBHS PHY's internal 480 MHz CDR PLL requires a stable 12 MHz reference, derived inside the PHY from a /5 division of the 60 MHz USB60CLK. This routine programmes USB60CKCR / USB60CKDIVCR (HUM Ch 9 "Clock Generation Circuit") so USB60CLK = PLL2P / 4 = 60.000 MHz exactly (PLL2P = 240 MHz from the same configuration the FS path uses, see ra8_cgc_usbfs_clock_enable). Mirrors the canonical FSP bsp_clocks.c bsp_peripheral_clock_set SREQ/SRDY ordering.

Sequence:

  1. Wait OSCSF.MOSCSF (main XTAL stable).
  2. Enable PLL2 at 240 MHz on PLL2P.
  3. Force MSTPCRB.MSTPB12 = 1 (USBHS module-stop) before changing USB60CKDIVCR off 1/1, per HUM "Clock selection switching procedure".
  4. Ensure HOCO is running (USB60CKCR's reset-default source) so the SREQ -> SRDY synchronizer chain can drain.
  5. SREQ/SRDY handshake on USB60CKCR/USB60CKDIVCR, landing USB60CLK = PLL2P / 4 = 60 MHz exactly.
Returns
ra8_err_t error code.
Return values
k_ra8_okUSBHS 60 MHz clock running on PLL2P/4.
k_ra8_err_hw_timeoutMain XTAL, HOCO, or USB60CKSRDY handshake timed out.
k_ra8_err_invalid_argPLL2 mul/quarters out of range (propagated from ra8_cgc_pll2_enable).
Precondition
ra8_cgc_init has been called.
Caller is single-threaded init context; CPU not on PLL2.
Postcondition
On k_ra8_ok: PLL2 locked at 240 MHz on PLL2P, MSTPB12 = 1, USB60CKCR.USB60CKSEL = PLL2P, USB60CKDIVCR = /4.
PRCR is re-locked.
Note
Not thread-safe; init context only.
See also
ra8_cgc_usbfs_clock_enable
ra8_cgc_pll2_enable
Since
0.1.0

Definition at line 624 of file ra8_cgc_usb.c.

References internal_usb60ckcr_switch_to_pll2p_div4(), k_ra8_mstpb12_usbhs_mask, k_ra8_ok, k_ra8_oscsf_bit_moscsf, k_ra8_pll2_usbfs_mul, k_ra8_pll2_usbfs_quarters, k_ra8_plodiv_div4, r_mstp_regs_t::MSTPCRB, priv_ra8_cgc_ensure_hoco_running_for_usb_ck(), priv_ra8_cgc_wait_oscsf_set(), ra8_cgc_pll2_enable(), ra8_log_error, ra8_log_error_val, ra8_log_info, ra8_mstp(), and s_tag.

Referenced by cdc_setup_or_halt(), dfu_setup_or_halt(), fileops_setup_or_halt(), hid_setup_or_halt(), internal_usbhs_clock_and_mstp(), main(), microsd_setup_or_halt(), mlun_setup_or_halt(), ospirw_setup_or_halt(), selftest_setup_or_halt(), and wlun_setup_or_halt().

◆ ra8_cgc_use_hoco()

ra8_err_t ra8_cgc_use_hoco ( void )
nodiscard

Switch the system clock source to HOCO (20 MHz).

Starts the HOCO if it is stopped, waits for it to stabilise, then writes k_ra8_cksel_hoco to SCKSCR. Requires a PRCR unlock around the SCKSCR write.

Returns
ra8_err_t error code.
Return values
k_ra8_okClock switched.
k_ra8_err_hw_timeoutHOCO failed to report ready within the timeout window.
Since
0.1.0

Definition at line 763 of file ra8_cgc.c.

References k_ra8_cksel_hoco, k_ra8_hococr_hcstp, k_ra8_ok, k_ra8_oscsf_bit_hocosf, k_ra8_prcr_unlock_cgc, priv_ra8_cgc_wait_oscsf_set(), ra8_log_info, RA8_PROTECTED_WRITE, ra8_sys_hococr(), ra8_sys_sckscr(), and s_tag.