|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Ethernet Generic PTP Timer driver implementation. More...
#include "ra8_eth_gptp.h"#include <stdint.h>#include "ra8_attributes.h"#include "ra8_check.h"#include "ra8_err.h"#include "ra8_ether_regs.h"#include "ra8_log.h"#include "ra8_mstp.h"#include "ra8_mstp_regs.h"Go to the source code of this file.
Enumerations | |
| enum | gptp_field_t : uint32_t { k_gptp_subns_shift = 27UL , k_gptp_round_half = 2UL , k_gptp_mask_nsec = 0x3FFFFFFFUL , k_gptp_mask_sec_u = 0x0000FFFFUL , k_gptp_shift_sec_u = 32UL } |
| Bit widths, shifts and masks of the GPTP timer registers. More... | |
Functions | |
| static volatile r_gptp_timer_regs_t * | internal_timer (ra8_gptp_timer_idx_t timer) |
| Point at one timer unit's register block. | |
| static void | internal_stop (ra8_gptp_timer_idx_t timer) |
| Stop one timer unit without validating its index. | |
| static void | internal_stop_all (void) |
| Stop every timer unit in the block. | |
| static void | internal_write_offset (ra8_gptp_timer_idx_t timer, uint64_t sec, uint32_t nsec) |
| Write the 78-bit offset of one timer unit in the mandated order. | |
| ra8_err_t | ra8_eth_gptp_tiv_from_hz (uint32_t clk_hz, uint32_t *out_tiv) |
| Derive PTPTIVCt.TIV from a clk frequency. | |
| ra8_err_t | ra8_eth_gptp_init (const ra8_eth_gptp_cfg_t *cfg) |
| Power up the GPTP block and programme both timers' increment. | |
| ra8_err_t | ra8_eth_gptp_deinit (void) |
| Stop both timers, clear their configuration and gate the block off. | |
| ra8_err_t | ra8_eth_gptp_ip_version (uint32_t *out_version) |
| Read the read-only PTPIPV IP-version word. | |
| ra8_err_t | ra8_eth_gptp_timer_enable (ra8_gptp_timer_idx_t timer) |
| Start one timer unit (PTPTMEC.TEq). | |
| ra8_err_t | ra8_eth_gptp_timer_disable (ra8_gptp_timer_idx_t timer) |
| Stop one timer unit (PTPTMDC.TDq). | |
| ra8_err_t | ra8_eth_gptp_timer_is_enabled (ra8_gptp_timer_idx_t timer, bool *out_enabled) |
| Report whether one timer unit is enabled. | |
| ra8_err_t | ra8_eth_gptp_set_increment (ra8_gptp_timer_idx_t timer, uint32_t tiv) |
| Write one timer unit's increment register PTPTIVCt. | |
| ra8_err_t | ra8_eth_gptp_get_increment (ra8_gptp_timer_idx_t timer, uint32_t *out_tiv) |
| Read one timer unit's increment register PTPTIVCt. | |
| ra8_err_t | ra8_eth_gptp_set_offset (ra8_gptp_timer_idx_t timer, uint64_t sec, uint32_t nsec) |
| Load one timer unit's additive 78-bit offset. | |
| ra8_err_t | ra8_eth_gptp_get_time (ra8_gptp_timer_idx_t timer, uint64_t *out_sec, uint32_t *out_nsec) |
| Read one timer unit's 78-bit GPTP time. | |
| ra8_err_t | ra8_eth_gptp_get_avtp_ns (ra8_gptp_timer_idx_t timer, uint64_t *out_ns) |
| Read one timer unit's 64-bit AVTP nanosecond counter. | |
| ra8_err_t | ra8_eth_gptp_enter_stop (void) |
| Stop both timers and assert the ESWM module-stop gate. | |
| ra8_err_t | ra8_eth_gptp_exit_stop (void) |
| Release the ESWM module-stop gate again. | |
Variables | |
| static const char * | s_tag = "ETHGPT" |
| Log tag for this driver. | |
| static bool | s_gptp_configured = false |
| True once ra8_eth_gptp_init has programmed the block. | |
Ethernet Generic PTP Timer driver implementation.
Implements the timer surface of HUM Ch 35 "Ethernet Generic PTP Timer (GPTP)" p 1925-1964. Every register touched here appears in HUM Table 35.3 p 1926 and carries the citation of its own subsection, not the chapter-opening page.
Definition in file ra8_eth_gptp.c.
| enum gptp_field_t : uint32_t |
Bit widths, shifts and masks of the GPTP timer registers.
PTPTIVCt.TIV is 5.27 fixed point (HUM 35.3.2.3 p 1928): the top five bits are whole nanoseconds and the low 27 are the sub-nanosecond part, so the sub-nanosecond scale is 2^27. The GPTP time is 78 bits with the nanosecond part in bits [29:0] and the seconds split 32 + 16 across the M and U registers (HUM 35.3.3.3 to 35.3.3.5 p 1931-1932).
Definition at line 82 of file ra8_eth_gptp.c.
|
static |
Stop one timer unit without validating its index.
Writes PTPTMDC.TDq, which clears PTPTMEC.TEq in hardware.
| [in] | timer | Timer index, already validated by the caller. |
Definition at line 128 of file ra8_eth_gptp.c.
References r_gptp_regs_t::PTPTMDC, and ra8_gptp().
Referenced by internal_stop_all(), ra8_eth_gptp_deinit(), ra8_eth_gptp_init(), and ra8_eth_gptp_timer_disable().
|
static |
Stop every timer unit in the block.
Loops k_ra8_gptp_timer_count times over internal_stop.
Definition at line 146 of file ra8_eth_gptp.c.
References internal_stop(), and k_ra8_gptp_timer_count.
Referenced by ra8_eth_gptp_enter_stop().
|
inlinestatic |
Point at one timer unit's register block.
Resolves base + 0x0020 + 0x40 * timer through r_gptp_regs_t.
| [in] | timer | Timer index, already validated by the caller. |
| &ra8_gptp()->TIMER[timer] | Always – timer is pre-validated by the caller, so the accessor has no failure path and never yields nullptr. |
Definition at line 108 of file ra8_eth_gptp.c.
References ra8_gptp(), and r_gptp_regs_t::TIMER.
Referenced by internal_write_offset(), ra8_eth_gptp_deinit(), ra8_eth_gptp_get_avtp_ns(), ra8_eth_gptp_get_increment(), ra8_eth_gptp_get_time(), ra8_eth_gptp_init(), and ra8_eth_gptp_set_increment().
|
static |
Write the 78-bit offset of one timer unit in the mandated order.
PTPTOVCtU then PTPTOVCtM then PTPTOVCtL; the L write is what commits the offset (HUM 35.4.1.3.1 Figure 35.4 p 1944-1945).
| [in] | timer | Timer index, already validated by the caller. |
| [in] | sec | Seconds part, already range-checked by the caller. |
| [in] | nsec | Nanoseconds part, already range-checked by the caller. |
Definition at line 171 of file ra8_eth_gptp.c.
References internal_timer(), k_gptp_mask_nsec, k_gptp_mask_sec_u, k_gptp_shift_sec_u, r_gptp_timer_regs_t::PTPTOVCL, r_gptp_timer_regs_t::PTPTOVCM, and r_gptp_timer_regs_t::PTPTOVCU.
Referenced by ra8_eth_gptp_deinit(), ra8_eth_gptp_init(), and ra8_eth_gptp_set_offset().
|
nodiscard |
Stop both timers, clear their configuration and gate the block off.
The full teardown: writes both PTPTMDC.TD bits, restores the reset value of PTPTIVCt and of the 78-bit offset for both units, then re-asserts the ESWM module stop. Use ra8_eth_gptp_enter_stop instead when the configuration should survive the power transition.
| k_ra8_ok | Timers stopped and the gate re-asserted. |
| k_ra8_err_hw_timeout | The module-stop assert did not settle. |
| k_ra8_err_invalid_state | The ESWM module-stop refcount was already 0 (no matching ra8_eth_gptp_init). |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 227 of file ra8_eth_gptp.c.
References internal_stop(), internal_timer(), internal_write_offset(), k_ra8_gptp_timer_count, k_ra8_mstp_eswm, r_gptp_timer_regs_t::PTPTIVC, ra8_mstp_disable(), RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
|
nodiscard |
Stop both timers and assert the ESWM module-stop gate.
The low-power entry path. Unlike ra8_eth_gptp_deinit this leaves PTPTIVCt and the 78-bit offset intact – a module stop is a clock gate, not a reset – so ra8_eth_gptp_exit_stop followed by ra8_eth_gptp_timer_enable resumes on the same configuration.
| k_ra8_ok | Timers stopped, gate asserted. |
| k_ra8_err_hw_timeout | The module-stop assert did not settle. |
| k_ra8_err_invalid_state | The ESWM module-stop refcount was already 0 (no matching ra8_eth_gptp_init). |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 372 of file ra8_eth_gptp.c.
References internal_stop_all(), k_ra8_mstp_eswm, ra8_mstp_disable(), RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
|
nodiscard |
Release the ESWM module-stop gate again.
Leaves both timers stopped and their configuration as ra8_eth_gptp_enter_stop left it; call ra8_eth_gptp_timer_enable to resume counting.
| k_ra8_ok | Gate released. |
| k_ra8_err_hw_timeout | The module-stop release did not settle. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 379 of file ra8_eth_gptp.c.
References k_ra8_mstp_eswm, ra8_mstp_enable(), RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
|
nodiscard |
Read one timer unit's 64-bit AVTP nanosecond counter.
Reads PTPAVTPTMtL first, which latches PTPAVTPTMtU (HUM 35.4.1.3.3 Figure 35.6 p 1945-1946). The AVTP view is the same clock as ra8_eth_gptp_get_time flattened to nanoseconds modulo 2^64 (HUM 35.5.1.2 p 1952) and is what an AVB talker stamps into presentation times.
| [in] | timer | Timer index, below k_ra8_gptp_timer_count. |
| [out] | out_ns | Receives the 64-bit nanosecond count. Must not be nullptr. |
| k_ra8_ok | Counter copied out. |
| k_ra8_err_null_ptr | out_ns == nullptr. |
| k_ra8_err_invalid_arg | timer out of range. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 354 of file ra8_eth_gptp.c.
References internal_timer(), k_gptp_shift_sec_u, k_ra8_err_invalid_arg, k_ra8_gptp_timer_count, k_ra8_ok, r_gptp_timer_regs_t::PTPAVTPTML, r_gptp_timer_regs_t::PTPAVTPTMU, RA8_CHECK_NULL_PTR, RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
|
nodiscard |
Read one timer unit's increment register PTPTIVCt.
Reads back whatever ra8_eth_gptp_set_increment last wrote, or the value ra8_eth_gptp_init derived from clk_hz, in the 5.27 fixed-point encoding of HUM 35.3.2.3 p 1928. A software servo reads its current correction through this call before computing the next one.
| [in] | timer | Timer index, below k_ra8_gptp_timer_count. |
| [out] | out_tiv | Receives PTPTIVCt.TIV. Must not be nullptr. |
| k_ra8_ok | Increment copied out. |
| k_ra8_err_null_ptr | out_tiv == nullptr. |
| k_ra8_err_invalid_arg | timer out of range. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 302 of file ra8_eth_gptp.c.
References internal_timer(), k_ra8_err_invalid_arg, k_ra8_gptp_timer_count, k_ra8_ok, r_gptp_timer_regs_t::PTPTIVC, RA8_CHECK_NULL_PTR, RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
|
nodiscard |
Read one timer unit's 78-bit GPTP time.
Reads PTPGPTPTMtL first: that read latches PTPGPTPTMtM and PTPGPTPTMtU, so the following two reads belong to the same instant (HUM 35.4.1.3.4 Figure 35.7 p 1946). While the unit is disabled every field reads 0 (HUM 35.3.2.1 p 1927), so a stopped timer is reported as time zero rather than as an error.
*out_nsec is masked to the register's 30 bits, which is wider than the one-second range the counter should ever hold. A value at or above 1e9 is therefore passed through rather than rejected: on a healthy block it cannot occur, and on a faulted one the caller is better served seeing the raw reading than a synthesised error.
| [in] | timer | Timer index, below k_ra8_gptp_timer_count. |
| [out] | out_sec | Receives the 48-bit seconds part. Must not be nullptr. |
| [out] | out_nsec | Receives the 30-bit nanoseconds part. Must not be nullptr. |
| k_ra8_ok | Time copied out. |
| k_ra8_err_null_ptr | Either output pointer is nullptr. |
| k_ra8_err_invalid_arg | timer out of range. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 331 of file ra8_eth_gptp.c.
References internal_timer(), k_gptp_mask_nsec, k_gptp_mask_sec_u, k_gptp_shift_sec_u, k_ra8_err_invalid_arg, k_ra8_gptp_timer_count, k_ra8_ok, r_gptp_timer_regs_t::PTPGPTPTML, r_gptp_timer_regs_t::PTPGPTPTMM, r_gptp_timer_regs_t::PTPGPTPTMU, RA8_CHECK_NULL_PTR, RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
Referenced by gptp_measure(), and tsn_check_time_base().
|
nodiscard |
Power up the GPTP block and programme both timers' increment.
Releases the ESWM module-stop gate (the GPTP window is inside the Layer-3 Ethernet Switch domain, MSTPC30), then for each of the two timer units: stops it via PTPTMDC, writes the derived PTPTIVCt and clears the 78-bit offset. Timers are left stopped; call ra8_eth_gptp_timer_enable to start counting.
| [in] | cfg | Static configuration. Must not be nullptr; clk_hz must be greater than 31250000 (see ra8_eth_gptp_cfg_t). |
| k_ra8_ok | Block powered, both timers programmed. |
| k_ra8_err_null_ptr | cfg == nullptr. |
| k_ra8_err_invalid_arg | cfg->clk_hz == 0. |
| k_ra8_err_out_of_range | cfg->clk_hz too low for a 32-bit TIV. |
| k_ra8_err_hw_timeout | The ESWM module-stop release did not settle. |
Definition at line 202 of file ra8_eth_gptp.c.
References ra8_eth_gptp_cfg_t::clk_hz, internal_stop(), internal_timer(), internal_write_offset(), k_ra8_gptp_timer_count, k_ra8_mstp_eswm, k_ra8_ok, r_gptp_timer_regs_t::PTPTIVC, RA8_CHECK_NULL_PTR, ra8_eth_gptp_tiv_from_hz(), ra8_log_info, ra8_mstp_enable(), RA8_RETURN_ON_ERROR, s_gptp_configured, and s_tag.
Referenced by gptp_arm(), and tsn_arm_time_base().
|
nodiscard |
Read the read-only PTPIPV IP-version word.
PTPIPV (HUM 35.3.1.1 p 1927) is the only register in the GPTP window with a nonzero reset value, so a nonzero read is positive evidence that the aperture really is the GPTP block rather than a reserved region echoing back writes.
| [out] | out_version | Receives PTPIPV.IPV. Must not be nullptr. |
| k_ra8_ok | Version word copied out. |
| k_ra8_err_null_ptr | out_version == nullptr. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 242 of file ra8_eth_gptp.c.
References k_ra8_ok, r_gptp_regs_t::PTPIPV, RA8_CHECK_NULL_PTR, ra8_gptp(), RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
Referenced by gptp_probe_presence().
|
nodiscard |
Write one timer unit's increment register PTPTIVCt.
PTPTIVCt is writable at any time (HUM Table 35.4 p 1946-1947), which is how a software servo applies a frequency correction: nudging TIV away from ra8_eth_gptp_tiv_from_hz makes the counter run fast or slow.
| [in] | timer | Timer index, below k_ra8_gptp_timer_count. |
| [in] | tiv | Nanoseconds per clk in 5.27 fixed point. |
| k_ra8_ok | Increment written. |
| k_ra8_err_invalid_arg | timer out of range, or tiv == 0. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 287 of file ra8_eth_gptp.c.
References internal_timer(), k_ra8_err_invalid_arg, k_ra8_gptp_timer_count, k_ra8_ok, r_gptp_timer_regs_t::PTPTIVC, RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
|
nodiscard |
Load one timer unit's additive 78-bit offset.
Writes PTPTOVCtU, then PTPTOVCtM, then PTPTOVCtL – the order is load-bearing, because writing the L register is what commits the whole offset to the timer (HUM 35.4.1.3.1 Figure 35.4 p 1944-1945). The reported time is offset + free-running counter (HUM 35.5.1.1 p 1951), so this is the coarse "step" half of a software clock servo.
| [in] | timer | Timer index, below k_ra8_gptp_timer_count. |
| [in] | sec | Seconds part, at most k_ra8_gptp_sec_max. |
| [in] | nsec | Nanoseconds part, at most k_ra8_gptp_nsec_max. |
| k_ra8_ok | Offset committed. |
| k_ra8_err_invalid_arg | timer, sec or nsec out of range. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 315 of file ra8_eth_gptp.c.
References internal_write_offset(), k_ra8_err_invalid_arg, k_ra8_gptp_nsec_max, k_ra8_gptp_sec_max, k_ra8_gptp_timer_count, k_ra8_ok, RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
Referenced by gptp_arm().
|
nodiscard |
Stop one timer unit (PTPTMDC.TDq).
Per HUM 35.3.2.1 p 1927 a disabled unit's counters are fixed at 0, so a stop is also a clear.
| [in] | timer | Timer index, below k_ra8_gptp_timer_count. |
| k_ra8_ok | Timer disabled. |
| k_ra8_err_invalid_arg | timer out of range. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 264 of file ra8_eth_gptp.c.
References internal_stop(), k_ra8_err_invalid_arg, k_ra8_gptp_timer_count, k_ra8_ok, RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
|
nodiscard |
Start one timer unit (PTPTMEC.TEq).
Writes 1 to PTPTMEC.TEq (HUM 35.3.2.1 p 1927). The register is write-1-to-set, so the sibling unit's enable bit is untouched. Counting resumes from the next clk edge at the unit's current PTPTIVCt, on top of whatever 78-bit offset ra8_eth_gptp_set_offset last committed.
| [in] | timer | Timer index, below k_ra8_gptp_timer_count. |
| k_ra8_ok | Timer enabled. |
| k_ra8_err_invalid_arg | timer out of range. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 252 of file ra8_eth_gptp.c.
References k_ra8_err_invalid_arg, k_ra8_gptp_timer_count, k_ra8_ok, r_gptp_regs_t::PTPTMEC, ra8_gptp(), RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
Referenced by gptp_arm(), and tsn_arm_time_base().
|
nodiscard |
Report whether one timer unit is enabled.
Reads PTPTMEC once and extracts bit timer (HUM 35.3.2.1 p 1927). PTPTMDC is write-only and reads as 0, so PTPTMEC is the single authority on whether a unit is running: a unit stopped through PTPTMDC reads back 0 here.
| [in] | timer | Timer index, below k_ra8_gptp_timer_count. |
| [out] | out_enabled | Receives PTPTMEC.TE[timer]. Must not be nullptr. |
| k_ra8_ok | State copied out. |
| k_ra8_err_null_ptr | out_enabled == nullptr. |
| k_ra8_err_invalid_arg | timer out of range. |
| k_ra8_err_not_initialized | ra8_eth_gptp_init has not run. |
Definition at line 274 of file ra8_eth_gptp.c.
References k_ra8_err_invalid_arg, k_ra8_gptp_timer_count, k_ra8_ok, r_gptp_regs_t::PTPTMEC, RA8_CHECK_NULL_PTR, ra8_gptp(), RA8_VALIDATE_INIT, s_gptp_configured, and s_tag.
|
nodiscard |
Derive PTPTIVCt.TIV from a clk frequency.
TIV is the nanoseconds-per-clk increment in 5.27 fixed point: TIV[31:27] is the whole-nanosecond part and TIV[26:0] the sub-nanosecond part (HUM 35.3.2.3 p 1928), so TIV = round(1e9 * 2^27 / clk_hz). The HUM's worked examples (0xA000_0000 / 0x5000_0000 / 0x2800_0000 / 0x2000_0000 for 50 / 100 / 200 / 250 MHz) fall out of that expression exactly.
This is a pure function – it touches no hardware – so an application can sanity-check its clock tree before powering the block on.
| [in] | clk_hz | clk frequency in Hz. Must be nonzero and above 31250000, below which TIV would not fit in 32 bits. |
| [out] | out_tiv | Receives the computed increment. Must not be nullptr. |
| k_ra8_ok | Increment computed. |
| k_ra8_err_null_ptr | out_tiv == nullptr. |
| k_ra8_err_invalid_arg | clk_hz == 0. |
| k_ra8_err_out_of_range | Computed TIV exceeds 32 bits. |
Definition at line 185 of file ra8_eth_gptp.c.
References k_gptp_round_half, k_gptp_subns_shift, k_ra8_err_invalid_arg, k_ra8_err_out_of_range, k_ra8_gptp_ns_per_sec, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.
Referenced by ra8_eth_gptp_init().
|
static |
True once ra8_eth_gptp_init has programmed the block.
Every other entry point documents "``ra8_eth_gptp_init`` has released the module-stop gate" as a precondition, and violating it is not a benign mistake: the GPTP window is inside the ESWM domain, so a read or write with MSTPC30 still asserted takes a bus fault. This flag turns that prose precondition into an enforced one. It stays true across ra8_eth_gptp_enter_stop / ra8_eth_gptp_exit_stop, because a module stop is a clock gate rather than a reset and PTPTIVCt plus the 78-bit offset survive it; only ra8_eth_gptp_deinit clears it.
Definition at line 59 of file ra8_eth_gptp.c.
Referenced by ra8_eth_gptp_deinit(), ra8_eth_gptp_enter_stop(), ra8_eth_gptp_exit_stop(), ra8_eth_gptp_get_avtp_ns(), ra8_eth_gptp_get_increment(), ra8_eth_gptp_get_time(), ra8_eth_gptp_init(), ra8_eth_gptp_ip_version(), ra8_eth_gptp_set_increment(), ra8_eth_gptp_set_offset(), ra8_eth_gptp_timer_disable(), ra8_eth_gptp_timer_enable(), and ra8_eth_gptp_timer_is_enabled().
|
static |
Log tag for this driver.
Passed to every ra8_log_* and RA8_CHECK_* call below.
Definition at line 39 of file ra8_eth_gptp.c.