|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Clock Generation Circuit driver – PLL2 + USB-FS / USB-HS clocks. 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_mstp_regs.h"#include "ra8_register_protection.h"#include "ra8_system_regs.h"#include "ra8_time_constants.h"Go to the source code of this file.
Enumerations | |
| enum | ra8_usbfs_clock_local_t : uint32_t { k_ra8_usbfs_srdy_poll_limit = 200000U , k_ra8_usbfs_div5_code = 6U , k_ra8_usbfs_div8_code = 4U } |
| Local sentinels for the USBCKSRDY handshake and divider codes. More... | |
| enum | ra8_usbfs_mstp_local_t : uint32_t { k_ra8_mstpb11_usbfs_mask = (uint32_t)(1UL << 11) } |
| Local sentinels for the USBFS module-stop pre-step. More... | |
| enum | ra8_pll2_local_t : uint16_t { k_ra8_pll2_max_quarters = 3U , k_ra8_pll2_usbfs_mul = 80U , k_ra8_pll2_usbfs_quarters = 0U } |
| Local constants for the PLL2 bring-up path. More... | |
| enum | ra8_usbhs_clock_local_t : uint32_t { k_ra8_usbhs_srdy_poll_limit = 200000U , k_ra8_usbhs_div4_code = 2U } |
| Local sentinels for the USB60CKCR SREQ/SRDY handshake. More... | |
| enum | ra8_usbhs_mstp_local_t : uint32_t { k_ra8_mstpb12_usbhs_mask = (uint32_t)(1UL << 12) } |
| Local sentinels for the USBHS module-stop pre-step. More... | |
Functions | |
| static ra8_err_t | internal_wait_usbcksrdy (uint8_t expected) |
| Spin until USBCKCR.USBCKSRDY matches the expected value. | |
| static ra8_err_t | internal_pll2_program_protected (uint32_t pll2ccr, uint16_t pll2ccr2) |
| PRCR-protected stop+program+restart body of 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) |
| Implementation of ra8_cgc_pll2_enable(). | |
| static ra8_err_t | internal_usbckcr_switch_to_pll2p_div5 (void) |
| PRCR-protected USBCKCR / USBCKDIVCR handshake body. | |
| ra8_err_t | ra8_cgc_usbfs_clock_enable (void) |
| Bring up the 48 MHz USB-FS clock from PLL2P / 5. | |
| static ra8_err_t | internal_wait_usb60cksrdy (uint8_t expected) |
| Spin until USB60CKCR.USB60CKSRDY matches the expected value. | |
| static ra8_err_t | internal_usb60ckcr_switch_to_pll2p_div4 (void) |
| PRCR-protected USB60CKCR / USB60CKDIVCR handshake body. | |
| ra8_err_t | priv_ra8_cgc_ensure_hoco_running_for_usb_ck (void) |
| Ensure HOCO is running so a USBCKCR/USB60CKCR/ESWCKCR SREQ->SRDY handshake can drain. | |
| ra8_err_t | ra8_cgc_usbhs_pll_enable (void) |
| Bring up the USBHS PHY 60 MHz reference clock + module clock path. | |
Variables | |
| static const char * | s_tag = "CGC" |
| static volatile uint8_t | s_usb60ckcr_probe = 0U |
| Last value read back from R_SYSTEM->USB60CKCR at the end of internal_usb60ckcr_switch_to_pll2p_div4. | |
| static volatile uint8_t | s_pll2_status_probe = 0U |
| Last value read back from R_SYSTEM->OSCSF at the end of internal_usb60ckcr_switch_to_pll2p_div4. | |
Clock Generation Circuit driver – PLL2 + USB-FS / USB-HS clocks.
Split out of ra8_cgc.c. Brings up PLL2 (960 MHz VCO, PLL2P = 240 MHz on the EK-RA8D2 24 MHz crystal) and routes the two USB controller clocks off it:
Every protected-register write is wrapped in RA8_PROTECTED_WRITE so the PRCR re-lock always happens, even on early-return paths. The bounded OSCSF poll helpers and the shared PLL-multiplier scale factor live in ra8_cgc_internal.h; priv_ra8_cgc_ensure_hoco_running_for_usb_ck is defined here and reused by ra8_cgc_eswclk.c.
Definition in file ra8_cgc_usb.c.
| enum ra8_pll2_local_t : uint16_t |
Local constants for the PLL2 bring-up path.
The EK-RA8D2 board fits a 24 MHz crystal (per the schematic and the existing PLL1 setup). For USB-FS we want a /5 divider downstream so PLL2P needs to be 240 MHz, which means a 960 MHz VCO (the silicon minimum). PL2IDIV = /2 -> 12 MHz pre-scale. PLL2MUL = 80 (integer) with PLL2MULNF = 0 (no quarter steps) -> 12 * 80 = 960 MHz. PL2ODIVP = /4 -> 240 MHz at PLL2P. USBCKDIVCR = /5 -> 48 MHz exactly.
Spec compliance: USBCKCR source 240 MHz * (1/5) = 48.000 MHz (0 ppm error vs the USB-FS spec target of 48 MHz +/- 2500 ppm = +/- 0.25 %). PASS.
| Enumerator | |
|---|---|
| k_ra8_pll2_max_quarters | Max value of PLL2MULNF[7:6]. |
| k_ra8_pll2_usbfs_mul | Integer multiplier for PLL2 USBFS path. |
| k_ra8_pll2_usbfs_quarters | Fractional quarter-steps (none). |
Definition at line 144 of file ra8_cgc_usb.c.
| enum ra8_usbfs_clock_local_t : uint32_t |
Local sentinels for the USBCKSRDY handshake and divider codes.
USBCKDIVCR uses a non-linear code-to-ratio map (FSP bsp_clocks.c): /1=0, /2=1, /3=5, /4=2, /5=6, /6=3, /8=4, /10=7, /16=8. We expose only the divisors this driver actually uses.
| Enumerator | |
|---|---|
| k_ra8_usbfs_srdy_poll_limit | Iterations before timeout. |
| k_ra8_usbfs_div5_code | USBCKDIVCR codepoint for /5. |
| k_ra8_usbfs_div8_code | USBCKDIVCR codepoint for /8. |
Definition at line 94 of file ra8_cgc_usb.c.
| enum ra8_usbfs_mstp_local_t : uint32_t |
Local sentinels for the USBFS module-stop pre-step.
HUM Ch 9 – the entire xCKCR / xCKDIVCR family ("Clock Selection Switching Procedure") requires the dependent module to be in the module-stop state (MSTP = 1) BEFORE asserting xCKSREQ when changing the divider from 1/n where n != 1. Since this routine programmes USBCKDIVCR from reset (1/1) to /5, that precondition applies. Pages 367 (ADCCKDIVCR), 370 (SPICKCR), 373 (GPTCKDIVCR), 378 (ETHPCKDIVCR), and 381 (ESWPCKCR) all give the same instruction. If the caller has already released MSTPB11 (USBFS) before us the SREQ -> SRDY handshake silently hangs – the symptom we observed on real silicon was USBCKCR == 0x40 (SREQ=1, SRDY=0) and the host never seeing the device. Force the module-stop bit back to 1 inside the PRCR window so the routine is robust to call ordering.
| Enumerator | |
|---|---|
| k_ra8_mstpb11_usbfs_mask | MSTPCRB.MSTPB11 (USBFS0). |
Definition at line 124 of file ra8_cgc_usb.c.
| enum ra8_usbhs_clock_local_t : uint32_t |
Local sentinels for the USB60CKCR SREQ/SRDY handshake.
USB60CKCR shares the bit layout of USBCKCR (HUM Ch 9; CMSIS R7KA8D2KF_core0.h – R_SYSTEM->USB60CKCR_b mirrors USBCKCR_b with USB60CKSEL[3:0], USB60CKSREQ@bit6, USB60CKSRDY@bit7). USB60CKDIVCR uses the same non-linear codepoint map as USBCKDIVCR (FSP bsp_clocks.c): /1=0, /2=1, /3=5, /4=2, /5=6, /6=3, /8=4, /10=7, /16=8. For the EK-RA8D2 USBHS PHY we land 60.000 MHz on USB60CLK from PLL2P (240 MHz) / 4 = 60.000 MHz, matching the HUM Ch 37.3.3 "Supplying the Clock" requirement: "A 60-MHz clock must be supplied ... USB60CLK is the operating clock for the USBHS module" (HUM p 2102, line 85433). The PHY then internally divides USB60CLK to derive its USBMCLK reference; the PHYSET CLKSEL[1:0] field selects the after-division frequency (12 / 20 / 24 / 48 MHz; HUM Ch 37.2.17 PHYSET, p 2080). The earlier "USB60CLK = 48 MHz, CLKSEL=48" configuration violated the named-rate contract on the register and made macOS issue ~43 USB resets without RHST ever advancing past 000 (chirp limbo). PLL2 is configured at 960 MHz VCO with PL2ODIVP=/4 -> PLL2P=240 MHz, the same setup the FS path uses (see ra8_cgc_usbfs_clock_enable).
Codepoint table from HUM Ch 9 USB60CKDIVCR (matches USBCKDIVCR): /1=0, /2=1, /3=5, /4=2, /5=6, /6=3, /8=4, /10=7, /16=8.
| Enumerator | |
|---|---|
| k_ra8_usbhs_srdy_poll_limit | Iterations before timeout. |
| k_ra8_usbhs_div4_code | USB60CKDIVCR codepoint /4. |
Definition at line 451 of file ra8_cgc_usb.c.
| enum ra8_usbhs_mstp_local_t : uint32_t |
Local sentinels for the USBHS module-stop pre-step.
Mirrors the FS path's MSTPB11 pre-step. HUM Ch 9 "Clock Selection Switching Procedure" requires the dependent module to be in module- stop state (MSTP=1) BEFORE asserting SREQ when changing the divider from 1/n with n!=1. We programme USB60CKDIVCR from reset (1/1) to /4, so this precondition applies. If the caller has already released MSTPB12 (USBHS) the SREQ->SRDY handshake silently hangs.
| Enumerator | |
|---|---|
| k_ra8_mstpb12_usbhs_mask | MSTPCRB.MSTPB12 (USBHS). |
Definition at line 468 of file ra8_cgc_usb.c.
|
static |
PRCR-protected stop+program+restart body of ra8_cgc_pll2_enable.
See implementation; mirrors internal_cgc_init_protected.
| [in] | pll2ccr | Pre-computed PLL2CCR value. |
| [in] | pll2ccr2 | Pre-computed PLL2CCR2 value. |
| k_ra8_ok | PLL2 stopped, re-programmed, and re-locked. |
| k_ra8_err_hw_timeout | PLL2SF stop or lock wait exceeded. |
Definition at line 192 of file ra8_cgc_usb.c.
References k_ra8_ok, k_ra8_oscsf_bit_pll2sf, k_ra8_pll2cr_run, k_ra8_pll2cr_stop, k_ra8_prcr_unlock_cgc, priv_ra8_cgc_wait_oscsf_clear(), priv_ra8_cgc_wait_oscsf_set(), RA8_INTERNAL, ra8_log_error, RA8_PROTECTED_WRITE, ra8_sys_pll2ccr(), ra8_sys_pll2ccr2(), ra8_sys_pll2cr(), and s_tag.
Referenced by ra8_cgc_pll2_enable().
|
static |
PRCR-protected USB60CKCR / USB60CKDIVCR handshake body.
Mirror of internal_usbckcr_switch_to_pll2p_div5 for the USBHS 60 MHz path: SREQ=1, wait SRDY=1, write USB60CKDIVCR=/4, write USB60CKCR=src|SREQ, write USB60CKCR=src, wait SRDY=0. HUM Ch 9 "Clock Generation Circuit", USB60CKCR description (USBHS 60 MHz source select). FSP bsp_clocks.c ::bsp_peripheral_clock_set is the canonical reference for the SREQ/SRDY ordering.
| k_ra8_ok | USBHS 60 MHz clock running on PLL2P/4. |
| k_ra8_err_hw_timeout | SRDY=1 or SRDY=0 wait exceeded. |
Definition at line 517 of file ra8_cgc_usb.c.
References internal_wait_usb60cksrdy(), k_ra8_ok, k_ra8_prcr_unlock_cgc, k_ra8_usbckcr_bit_srdy, k_ra8_usbckcr_bit_sreq, k_ra8_usbckcr_mask_sel, k_ra8_usbcksel_pll2p, k_ra8_usbhs_div4_code, RA8_INTERNAL, ra8_log_error, RA8_PROTECTED_WRITE, ra8_sys_oscsf(), ra8_sys_usb60ckcr(), ra8_sys_usb60ckdivcr(), s_pll2_status_probe, s_tag, and s_usb60ckcr_probe.
Referenced by ra8_cgc_usbhs_pll_enable().
|
static |
PRCR-protected USBCKCR / USBCKDIVCR handshake body.
Steps 3..7 of the HUM "Clock selection switching procedure" inside the CGC-PRCR window: SREQ=1, wait SRDY=1, write USBCKDIVCR, write USBCKCR=src|SREQ, write USBCKCR=src, wait SRDY=0.
| k_ra8_ok | Handshake completed; USBCLK on PLL2P/5 = 48 MHz. |
| k_ra8_err_hw_timeout | SRDY=1 or SRDY=0 wait exceeded. |
Definition at line 314 of file ra8_cgc_usb.c.
References internal_wait_usbcksrdy(), k_ra8_ok, k_ra8_prcr_unlock_cgc, k_ra8_usbckcr_bit_sreq, k_ra8_usbckcr_mask_sel, k_ra8_usbcksel_pll2p, k_ra8_usbfs_div5_code, RA8_INTERNAL, ra8_log_error, RA8_PROTECTED_WRITE, ra8_sys_usbckcr(), ra8_sys_usbckdivcr(), and s_tag.
Referenced by ra8_cgc_usbfs_clock_enable().
|
static |
Spin until USB60CKCR.USB60CKSRDY matches the expected value.
See implementation.
| [in] | expected | Expected value for USB60CKSRDY (0 or 1). |
| k_ra8_ok | USB60CKSRDY reached the expected level. |
| k_ra8_err_hw_timeout | Polling exceeded the iteration cap. |
Definition at line 486 of file ra8_cgc_usb.c.
References k_ra8_usbckcr_bit_srdy, k_ra8_usbhs_srdy_poll_limit, ra8_hw_wait_flag_clear8(), ra8_hw_wait_flag_set8(), RA8_INTERNAL, and ra8_sys_usb60ckcr().
Referenced by internal_usb60ckcr_switch_to_pll2p_div4().
|
static |
Spin until USBCKCR.USBCKSRDY matches the expected value.
See implementation.
| [in] | expected | Expected value for USBCKSRDY (0 or 1). |
| k_ra8_ok | USBCKSRDY reached the expected level. |
| k_ra8_err_hw_timeout | Polling exceeded the iteration cap. |
Definition at line 164 of file ra8_cgc_usb.c.
References k_ra8_usbckcr_bit_srdy, k_ra8_usbfs_srdy_poll_limit, ra8_hw_wait_flag_clear8(), ra8_hw_wait_flag_set8(), RA8_INTERNAL, and ra8_sys_usbckcr().
Referenced by internal_usbckcr_switch_to_pll2p_div5().
| ra8_err_t priv_ra8_cgc_ensure_hoco_running_for_usb_ck | ( | void | ) |
Ensure HOCO is running so a USBCKCR/USB60CKCR/ESWCKCR SREQ->SRDY handshake can drain.
USBCKCR / USB60CKCR / ESWCKCR all share HOCO as their reset-default source. The SREQ -> SRDY synchronizer chain crosses from ICLK into the CURRENT clock source's domain (HOCO at boot). If HOCO is stopped (HCSTP = 1) the handshake never completes. ra8_cgc_init leaves HOCO stopped because it switches SCKSCR to PLL1, so this helper restarts HOCO under a PRCR-CGC unlock window (HOCOCR IS PRCR-protected; writes outside the window are silently dropped) and then waits OSCSF.HOCOSF outside the PRCR window (read-only). Defined in ra8_cgc_usb.c and reused by ra8_cgc_eswclk.c.
| k_ra8_ok | HOCO running, OSCSF.HOCOSF asserted. |
| k_ra8_err_hw_timeout | HOCOSF never asserted. |
Definition at line 564 of file ra8_cgc_usb.c.
References k_ra8_hococr_hcstp, k_ra8_oscsf_bit_hocosf, k_ra8_prcr_unlock_cgc, priv_ra8_cgc_wait_oscsf_set(), RA8_PROTECTED_WRITE, and ra8_sys_hococr().
Referenced by ra8_cgc_eswclk_init(), and ra8_cgc_usbhs_pll_enable().
|
nodiscard |
Implementation of ra8_cgc_pll2_enable().
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.
| [in] | mul_int | Integer multiplier (1..255). |
| [in] | mul_quarters | Quarter-step fractional multiplier (0..3). |
| [in] | p_div_code | ra8_plodiv_t code for the P output divider. |
| k_ra8_ok | PLL2 locked. |
| k_ra8_err_invalid_arg | mul_int is 0 or mul_quarters > 3. |
| k_ra8_err_hw_timeout | PLL2SF stop or start handshake timed out. |
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().
|
nodiscard |
Bring up the 48 MHz USB-FS clock from PLL2P / 5.
Bring up the USB-FS module clock (USBCKCR / USBCKDIVCR).
| k_ra8_ok | USB-FS clock running at exactly 48 MHz. |
| k_ra8_err_hw_init_failed | PLL2 enable failed; see log. |
| k_ra8_err_hw_timeout | USBCKCR SREQ/SRDY handshake timed out. |
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().
|
nodiscard |
Bring up the USBHS PHY 60 MHz reference clock + module clock path.
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:
| k_ra8_ok | USBHS 60 MHz clock running on PLL2P/4. |
| k_ra8_err_hw_timeout | Main XTAL, HOCO, or USB60CKSRDY handshake timed out. |
| k_ra8_err_invalid_arg | PLL2 mul/quarters out of range (propagated from ra8_cgc_pll2_enable). |
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().
|
static |
Last value read back from R_SYSTEM->OSCSF at the end of internal_usb60ckcr_switch_to_pll2p_div4.
Bit 6 (PLL2SF) must be 1 for the USB60CKCR clock-switch handshake to make forward progress. JLink-readable witness used in tandem with s_usb60ckcr_probe to disambiguate "PLL2 never locked" from "SREQ/SRDY ordering wrong".
Resolve the runtime address from the per-app .map file.
Definition at line 83 of file ra8_cgc_usb.c.
Referenced by internal_usb60ckcr_switch_to_pll2p_div4().
|
static |
Definition at line 46 of file ra8_cgc_usb.c.
|
static |
Last value read back from R_SYSTEM->USB60CKCR at the end of internal_usb60ckcr_switch_to_pll2p_div4.
JLink-readable witness for the USBHS 60 MHz clock-source SREQ/SRDY handshake. After a successful handshake we expect: USB60CKCR = 0x06 (USB60CKSEL=PLL2P, USB60CKSREQ=0, USB60CKSRDY=0). On timeout the value captured here pins down which step of the handshake stalled.
Resolve the runtime address from the per-app .map file.
Definition at line 65 of file ra8_cgc_usb.c.
Referenced by internal_usb60ckcr_switch_to_pll2p_div4().