ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_eth_gptp.c
Go to the documentation of this file.
1
17
18#include "ra8_eth_gptp.h"
19
20#include <stdint.h>
21
22#include "ra8_attributes.h"
23#include "ra8_check.h"
24#include "ra8_err.h"
25#include "ra8_ether_regs.h"
26#include "ra8_log.h"
27#include "ra8_mstp.h"
28#include "ra8_mstp_regs.h"
29
39static const char* s_tag = "ETHGPT";
40
59static bool s_gptp_configured = false;
60
82typedef enum : uint32_t {
85 k_gptp_mask_nsec = 0x3FFFFFFFUL,
86 k_gptp_mask_sec_u = 0x0000FFFFUL,
89
109{
110 /* HUM Ch 35.2 "gPTP Register List" Table 35.3 p 1926 -- per-timer block at
111 * offset 0x0020 + 0x40 x t. */
112 return &ra8_gptp()->TIMER[timer];
113}
114
129{
130 /* HUM Ch 35.3.2.2 "PTPTMDC : Timer Disable Configuration Register" p 1928 */
131 ra8_gptp()->PTPTMDC = 1U << (uint32_t)timer;
132}
133
146static void internal_stop_all(void)
147{
148 for (uint8_t t = 0U; t < (uint8_t)k_ra8_gptp_timer_count; ++t) {
150 }
151}
152
171static void internal_write_offset(ra8_gptp_timer_idx_t timer, uint64_t sec, uint32_t nsec)
172{
173 volatile r_gptp_timer_regs_t* reg = internal_timer(timer);
174 /* HUM Ch 35.3.2.6 "PTPTOVCtU : Timer t Offset Value Configuration Register U"
175 * p 1930 -- seconds [47:32]. */
176 reg->PTPTOVCU = (uint32_t)(sec >> (uint64_t)k_gptp_shift_sec_u) & (uint32_t)k_gptp_mask_sec_u;
177 /* HUM Ch 35.3.2.5 "PTPTOVCMt : Timer t Offset Value Configuration Register M"
178 * p 1929 -- seconds [31:0]. */
179 reg->PTPTOVCM = (uint32_t)sec;
180 /* HUM Ch 35.3.2.4 "PTPTOVCtL : Timer t Offset Value Configuration Register L"
181 * p 1929 -- nanoseconds; this write commits the whole 78-bit offset. */
182 reg->PTPTOVCL = nsec & (uint32_t)k_gptp_mask_nsec;
183}
184
185ra8_err_t ra8_eth_gptp_tiv_from_hz(uint32_t clk_hz, uint32_t* out_tiv)
186{
187 RA8_CHECK_NULL_PTR(out_tiv, s_tag, "out_tiv must not be nullptr");
188 if (clk_hz == 0U) {
190 }
191 /* TIV = round(1e9 ns * 2^27 / clk_hz) -- HUM Ch 35.3.2.3 p 1928. */
192 const uint64_t scaled = (uint64_t)k_ra8_gptp_ns_per_sec << (uint64_t)k_gptp_subns_shift;
193 const uint64_t half = (uint64_t)clk_hz / (uint64_t)k_gptp_round_half;
194 const uint64_t tiv = (scaled + half) / (uint64_t)clk_hz;
195 if (tiv > (uint64_t)UINT32_MAX) {
197 }
198 *out_tiv = (uint32_t)tiv;
199 return k_ra8_ok;
200}
201
203{
204 RA8_CHECK_NULL_PTR(cfg, s_tag, "cfg must not be nullptr");
205 uint32_t tiv = 0U;
206 const ra8_err_t tiv_err = ra8_eth_gptp_tiv_from_hz(cfg->clk_hz, &tiv);
207 RA8_RETURN_ON_ERROR(tiv_err, s_tag, "gptp_init: clk_hz");
208
209 /* HUM Ch 11.2.8 "MSTPCRC : Module Stop Control Register C" p 446 -- MSTPC30
210 * gates the Layer-3 Ethernet Switch domain that contains GPTP. */
212 RA8_RETURN_ON_ERROR(mst_err, s_tag, "gptp_init: mstp enable");
213
214 for (uint8_t t = 0U; t < (uint8_t)k_ra8_gptp_timer_count; ++t) {
216 internal_stop(timer);
217 /* HUM Ch 35.3.2.3 "PTPTIVCt : Timer t Increment Value Configuration
218 * Register (t = 0, 1)" p 1928 */
219 internal_timer(timer)->PTPTIVC = tiv;
220 internal_write_offset(timer, 0ULL, 0U);
221 }
222 s_gptp_configured = true;
223 ra8_log_info(s_tag, "gptp_init");
224 return k_ra8_ok;
225}
226
228{
229 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
230 for (uint8_t t = 0U; t < (uint8_t)k_ra8_gptp_timer_count; ++t) {
232 internal_stop(timer);
233 /* HUM Ch 35.3.2.3 "PTPTIVCt : Timer t Increment Value Configuration
234 * Register (t = 0, 1)" p 1928 -- restore the 0 reset value. */
235 internal_timer(timer)->PTPTIVC = 0UL;
236 internal_write_offset(timer, 0ULL, 0U);
237 }
238 s_gptp_configured = false;
240}
241
242ra8_err_t ra8_eth_gptp_ip_version(uint32_t* out_version)
243{
244 RA8_CHECK_NULL_PTR(out_version, s_tag, "out_version must not be nullptr");
245 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
246 /* HUM Ch 35.3.1.1 "PTPIPV : IP Version Register" p 1927 -- read-only, reset
247 * value nonzero. */
248 *out_version = ra8_gptp()->PTPIPV;
249 return k_ra8_ok;
250}
251
253{
254 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
255 if (timer >= k_ra8_gptp_timer_count) {
257 }
258 /* HUM Ch 35.3.2.1 "PTPTMEC : Timer Enable Configuration Register" p 1927 --
259 * writing 1 to bit q sets TEq; other bits are unaffected. */
260 ra8_gptp()->PTPTMEC = 1U << (uint32_t)timer;
261 return k_ra8_ok;
262}
263
265{
266 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
267 if (timer >= k_ra8_gptp_timer_count) {
269 }
270 internal_stop(timer);
271 return k_ra8_ok;
272}
273
275{
276 RA8_CHECK_NULL_PTR(out_enabled, s_tag, "out_enabled must not be nullptr");
277 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
278 if (timer >= k_ra8_gptp_timer_count) {
280 }
281 /* HUM Ch 35.3.2.1 "PTPTMEC : Timer Enable Configuration Register" p 1927 */
282 const uint32_t tmec = ra8_gptp()->PTPTMEC;
283 *out_enabled = ((tmec >> (uint32_t)timer) & 1U) != 0U;
284 return k_ra8_ok;
285}
286
288{
289 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
290 if (timer >= k_ra8_gptp_timer_count) {
292 }
293 if (tiv == 0U) {
295 }
296 /* HUM Ch 35.3.2.3 "PTPTIVCt : Timer t Increment Value Configuration Register
297 * (t = 0, 1)" p 1928 -- writable at any time (Table 35.4 p 1946-1947). */
298 internal_timer(timer)->PTPTIVC = tiv;
299 return k_ra8_ok;
300}
301
303{
304 RA8_CHECK_NULL_PTR(out_tiv, s_tag, "out_tiv must not be nullptr");
305 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
306 if (timer >= k_ra8_gptp_timer_count) {
308 }
309 /* HUM Ch 35.3.2.3 "PTPTIVCt : Timer t Increment Value Configuration Register
310 * (t = 0, 1)" p 1928 */
311 *out_tiv = internal_timer(timer)->PTPTIVC;
312 return k_ra8_ok;
313}
314
315ra8_err_t ra8_eth_gptp_set_offset(ra8_gptp_timer_idx_t timer, uint64_t sec, uint32_t nsec)
316{
317 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
318 if (timer >= k_ra8_gptp_timer_count) {
320 }
321 if (sec > (uint64_t)k_ra8_gptp_sec_max) {
323 }
324 if (nsec > (uint32_t)k_ra8_gptp_nsec_max) {
326 }
327 internal_write_offset(timer, sec, nsec);
328 return k_ra8_ok;
329}
330
331ra8_err_t ra8_eth_gptp_get_time(ra8_gptp_timer_idx_t timer, uint64_t* out_sec, uint32_t* out_nsec)
332{
333 RA8_CHECK_NULL_PTR(out_sec, s_tag, "out_sec must not be nullptr");
334 RA8_CHECK_NULL_PTR(out_nsec, s_tag, "out_nsec must not be nullptr");
335 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
336 if (timer >= k_ra8_gptp_timer_count) {
338 }
339 volatile r_gptp_timer_regs_t* reg = internal_timer(timer);
340 /* HUM Ch 35.4.1.3.4 "GPTP Timer t Reading Flow" Figure 35.7 p 1946 -- read L
341 * first: that read latches M and U to the same instant. */
342 const uint32_t nsec = reg->PTPGPTPTML & (uint32_t)k_gptp_mask_nsec;
343 /* HUM Ch 35.3.3.4 "PTPGPTPTMtM : GPTP Timer t Monitoring Register M
344 * (t = 0, 1)" p 1931 -- seconds [31:0]. */
345 const uint64_t sec_lo = (uint64_t)reg->PTPGPTPTMM;
346 /* HUM Ch 35.3.3.5 "PTPGPTPTMtU : GPTP Timer t Monitoring Register U
347 * (t = 0, 1)" p 1932 -- seconds [47:32]. */
348 const uint64_t sec_hi = (uint64_t)(reg->PTPGPTPTMU & (uint32_t)k_gptp_mask_sec_u);
349 *out_sec = (sec_hi << (uint64_t)k_gptp_shift_sec_u) | sec_lo;
350 *out_nsec = nsec;
351 return k_ra8_ok;
352}
353
355{
356 RA8_CHECK_NULL_PTR(out_ns, s_tag, "out_ns must not be nullptr");
357 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
358 if (timer >= k_ra8_gptp_timer_count) {
360 }
361 volatile r_gptp_timer_regs_t* reg = internal_timer(timer);
362 /* HUM Ch 35.4.1.3.3 "64-bit AVTP Timer t Reading Flow" Figure 35.6
363 * p 1945-1946 -- read L first: that read latches U. */
364 const uint64_t lo = (uint64_t)reg->PTPAVTPTML;
365 /* HUM Ch 35.3.3.2 "PTPAVTPTMtU : AVTP Timer t Monitoring Register U
366 * (t = 0, 1)" p 1931 */
367 const uint64_t hi = (uint64_t)reg->PTPAVTPTMU;
368 *out_ns = (hi << (uint64_t)k_gptp_shift_sec_u) | lo;
369 return k_ra8_ok;
370}
371
373{
374 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
377}
378
380{
381 RA8_VALIDATE_INIT(s_gptp_configured, s_tag, "ra8_eth_gptp_init has not run");
383}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_HW_REGISTER_ACCESS
Mark an MMIO accessor function (returns volatile register pointer).
#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_VALIDATE_INIT(initialized, tag, message)
Precondition: module must be initialized.
Definition ra8_check.h:334
#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_out_of_range
Sensor or peripheral output out of valid range.
Definition ra8_err.h:337
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ 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_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_get_increment(ra8_gptp_timer_idx_t timer, uint32_t *out_tiv)
Read one timer unit's increment register PTPTIVCt.
static volatile r_gptp_timer_regs_t * internal_timer(ra8_gptp_timer_idx_t timer)
Point at one timer unit's register block.
ra8_err_t ra8_eth_gptp_ip_version(uint32_t *out_version)
Read the read-only PTPIPV IP-version word.
static bool s_gptp_configured
True once ra8_eth_gptp_init has programmed the block.
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_timer_enable(ra8_gptp_timer_idx_t timer)
Start one timer unit (PTPTMEC.TEq).
static void internal_stop_all(void)
Stop every timer unit in the block.
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_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_set_offset(ra8_gptp_timer_idx_t timer, uint64_t sec, uint32_t nsec)
Load one timer unit's additive 78-bit offset.
gptp_field_t
Bit widths, shifts and masks of the GPTP timer registers.
@ k_gptp_subns_shift
5.27 fixed-point scale of TIV.
@ k_gptp_mask_nsec
Mask for GPTPL / TOVL [29:0].
@ k_gptp_shift_sec_u
Seconds upper part starts at 2^32.
@ k_gptp_round_half
Round-to-nearest divisor for TIV.
@ k_gptp_mask_sec_u
Mask for GPTPU / TOVU [15:0].
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_get_avtp_ns(ra8_gptp_timer_idx_t timer, uint64_t *out_ns)
Read one timer unit's 64-bit AVTP nanosecond counter.
static void internal_stop(ra8_gptp_timer_idx_t timer)
Stop one timer unit without validating its index.
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_deinit(void)
Stop both timers, clear their configuration and gate the block off.
ra8_err_t ra8_eth_gptp_exit_stop(void)
Release the ESWM module-stop gate again.
ra8_err_t ra8_eth_gptp_init(const ra8_eth_gptp_cfg_t *cfg)
Power up the GPTP block and programme both timers' increment.
Ethernet Generic PTP Timer (GPTP) driver – HUM Ch 35.
@ k_ra8_gptp_sec_max
Largest 48-bit seconds value.
@ k_ra8_gptp_ns_per_sec
Nanoseconds in one second.
@ k_ra8_gptp_nsec_max
Largest legal PTPTOVCtL.TOVL.
Ethernet controller base addresses for the Renesas RA8D2.
ra8_gptp_timer_idx_t
GPTP timer instance index (HUM Table 35.3 lists t = 0, 1).
@ k_ra8_gptp_timer_count
Number of timer units on this part.
static volatile r_gptp_regs_t * ra8_gptp(void)
Get pointer to the GPTP register block.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
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.
volatile r_gptp_timer_regs_t TIMER[k_ra8_gptp_timer_count]
+0x0020 + 0x40 x t Per-timer blocks.
volatile uint32_t PTPTMDC
+0x0014 Timer Disable Configuration.
volatile uint32_t PTPTMEC
+0x0010 Timer Enable Configuration.
volatile uint32_t PTPIPV
+0x0000 IP Version (read-only).
One GPTP timer unit's register block (HUM Ch 35.3.2 / 35.3.3).
volatile uint32_t PTPAVTPTMU
+0x24 AVTP Timer Monitoring U.
volatile uint32_t PTPAVTPTML
+0x20 AVTP Timer Monitoring L.
volatile uint32_t PTPGPTPTMU
+0x38 GPTP Timer Monitoring U.
volatile uint32_t PTPTOVCU
+0x18 Timer Offset Value Cfg U.
volatile uint32_t PTPTOVCM
+0x14 Timer Offset Value Cfg M.
volatile uint32_t PTPGPTPTMM
+0x34 GPTP Timer Monitoring M.
volatile uint32_t PTPTIVC
+0x00 Timer Increment Value Cfg.
volatile uint32_t PTPTOVCL
+0x10 Timer Offset Value Cfg L.
volatile uint32_t PTPGPTPTML
+0x30 GPTP Timer Monitoring L.
Static configuration for ra8_eth_gptp_init.
uint32_t clk_hz
ESWCLK frequency in Hz feeding the GPTP counter.