Commit d11fcb12 authored by Tristan Gingold's avatar Tristan Gingold

wrtd: finish fd modularization.

parent 5454ce71
......@@ -26,10 +26,17 @@ static void wrtd_local_output(struct wrtd_event *ev, unsigned ch);
static void wrtd_io(void);
static int wrtd_user_init(void);
static void wr_update_link(void);
static int wr_sync_timeout(void);
static void wr_enable_lock(int enable);
static int wr_time_ready(void);
static int wr_time_locked(void);
static int wr_link_up(void);
static struct wrtd_rule rules[NBR_RULES];
static struct wrtd_alarm alarms[NBR_ALARMS];
static uint32_t tai_start = 0;
static struct wrtd_root root =
{
.ver_major = WRTD_VERSION_MAJOR,
......@@ -54,6 +61,48 @@ static inline int wr_is_timing_ok(void)
return (root.wr_state == WR_LINK_SYNCED);
}
/**
* It updates the White-Rabbit link status
*/
static void wr_update_link(void)
{
switch (root.wr_state) {
case WR_LINK_OFFLINE:
if (wr_link_up())
root.wr_state = WR_LINK_ONLINE;
break;
case WR_LINK_ONLINE:
if (wr_time_ready()) {
root.wr_state = WR_LINK_SYNCING;
wr_enable_lock(1);
}
break;
case WR_LINK_SYNCING:
if (wr_time_locked()) {
pr_debug("rt-tdc: WR synced, waiting for TDC plumbing to catch up...\n\r");
root.wr_state = WR_LINK_WAIT;
tai_start = lr_readl(MT_CPU_LR_REG_TAI_SEC);
}
break;
case WR_LINK_WAIT:
if (wr_sync_timeout() == 0
|| (lr_readl(MT_CPU_LR_REG_TAI_SEC)
>= (tai_start + wr_sync_timeout()))) {
pr_debug("rt-tdc: WR TDC synced\n\r");
root.wr_state = WR_LINK_SYNCED;
}
break;
case WR_LINK_SYNCED:
break;
}
if (root.wr_state != WR_LINK_OFFLINE && !wr_link_up()) {
pr_error("rt-tdc: WR sync lost\n\r");
root.wr_state = WR_LINK_OFFLINE;
wr_enable_lock(0);
}
}
#if NBR_CPUS > 1
/* Number of entries; must be a power of 2. */
#define LOOPBACK_QUEUE_SIZE (1 << 3)
......
/*
* Copyright (C) 2013-2018 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <errno.h>
#include <string.h>
#include "mockturtle-rt.h"
#include <mockturtle-framework.h>
#include "wrtd-common.h"
#include "hw/fd_channel_regs.h"
#include "hw/fd_main_regs.h"
#include "wrtd-fd.h"
#define OUT_TIMEOUT 10
static inline int fd_wr_present(struct wrtd_fd_dev *fd)
{
return !!(fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_PRESENT);
}
static inline int fd_wr_link_up(struct wrtd_fd_dev *fd)
{
return fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_LINK;
}
static inline int fd_wr_time_locked(struct wrtd_fd_dev *fd)
{
return fd_readl(fd, FD_REG_TCR) & FD_TCR_WR_LOCKED;
}
static inline int fd_wr_time_ready(struct wrtd_fd_dev *fd)
{
return 1;
}
static inline int fd_wr_sync_timeout(void)
{
return 0;
}
static void fd_wr_enable_lock(struct wrtd_fd_dev *fd, int enable)
{
fd_writel(fd, enable ? FD_TCR_WR_ENABLE : 0, FD_REG_TCR);
}
/**
* Writes to FD output registers for output (out)
*/
static inline void fd_ch_writel(struct wrtd_fd_channel *out, uint32_t value,
uint32_t reg)
{
dp_writel(value, reg + out->channel_addr);
}
/**
* Reads from FD output registers for output (out)
*/
static inline uint32_t fd_ch_readl (struct wrtd_fd_channel *out, uint32_t reg)
{
return dp_readl(reg + out->channel_addr);
}
/**
* Initializes an empty pulse queue
*/
static void pulse_queue_init(struct lrt_pulse_queue *p)
{
p->head = 0;
p->tail = 0;
p->count = 0;
}
/**
* Requests a new entry in a pulse queue. Returns pointer to the ne
* entry or NULL if the queue is full.
*/
static struct wrtd_event *pulse_queue_push(struct lrt_pulse_queue *p)
{
struct wrtd_event *ev;
if (p->count == FD_MAX_QUEUE_PULSES)
return NULL;
ev = &p->events[p->head];
p->count++;
p->head++;
if (p->head == FD_MAX_QUEUE_PULSES)
p->head = 0;
return ev;
}
/**
* Returns non-0 if pulse queue p contains any pulses.
*/
static inline int pulse_queue_empty(struct lrt_pulse_queue *p)
{
return (p->count == 0);
}
/**
* Returns the oldest entry in the pulse queue (or NULL if empty).
*/
static struct wrtd_event *pulse_queue_front(struct lrt_pulse_queue *p)
{
if (!p->count)
return NULL;
return &p->events[p->tail];
}
/**
* Releases the oldest entry from the pulse queue.
*/
static void pulse_queue_pop(struct lrt_pulse_queue *p)
{
p->tail++;
if(p->tail == FD_MAX_QUEUE_PULSES)
p->tail = 0;
p->count--;
}
/**
* Checks if the timestamp of the last programmed pulse is lost because
* of timeout
*/
static int check_output_timeout (struct wrtd_fd_channel *out)
{
uint32_t now_sec;
uint32_t now_ns;
int delta;
/*
* Read the current WR time, order is important: first seconds,
* then cycles (cycles get latched on reading secs register.
*/
now_sec = lr_readl(MT_CPU_LR_REG_TAI_SEC);
now_ns = lr_readl(MT_CPU_LR_REG_TAI_CYCLES) * 8;
if(out->last_programmed_sec > now_sec + OUT_TIMEOUT) {
pr_error("Enqueued event very far in the future. Dropping.");
return 0;
}
/* Current time exceeds FD setpoint? */
delta = now_sec - out->last_programmed_sec;
if (delta != 0)
return delta > 0;
delta = now_ns - out->last_programmed_ns;
return (delta > 0);
}
/**
* Drop the given enqueued trigger
*/
static void drop_trigger(struct wrtd_fd_channel *out,
struct wrtd_event *ev,
struct lrt_pulse_queue *q, unsigned reason)
{
out->idle = 1;
if (pulse_queue_empty(q))
return;
/* Drop the pulse */
pulse_queue_pop(q);
/* Disarm the FD output */
fd_ch_writel(out, FD_DCR_MODE, FD_REG_DCR);
wrtd_log(WRTD_LOG_MSG_EV_DISCARDED, reason, ev, NULL);
}
/**
* Output driving function. Reads pulses from the output queue,
* programs the output and updates the output statistics.
*/
static void fd_output (struct wrtd_fd_dev *fd, unsigned channel)
{
struct wrtd_fd_channel *out = &fd->channels[channel];
struct lrt_pulse_queue *q = &out->queue;
struct wrtd_event *ev = pulse_queue_front(q);
uint32_t dcr = fd_ch_readl(out, FD_REG_DCR);
struct wrtd_tstamp *ts;
/* Check if the output has triggered */
if (!out->idle) {
if (!wr_is_timing_ok()) {
/* Timing has been lost. */
drop_trigger(out, ev, q, WRTD_LOG_DISCARD_NO_SYNC);
return;
}
if (!(dcr & FD_DCR_PG_TRIG)) {
/* Armed but still waiting for trigger */
if (check_output_timeout (out)) {
/* Will never trigger. Missed. */
drop_trigger(out, ev, q,
WRTD_LOG_DISCARD_TIMEOUT);
}
} else {
/* Has been triggered. */
wrtd_log(WRTD_LOG_MSG_EV_CONSUMED,
WRTD_LOG_CONSUMED_DONE, ev, NULL);
pulse_queue_pop(q);
out->idle = 1;
}
return;
}
/* Output is idle: check if there's something in the queue to execute */
if (pulse_queue_empty(q))
return;
ev = pulse_queue_front(q);
ts = &ev->ts;
if (!wr_is_timing_ok()) {
drop_trigger(out, ev, q, WRTD_LOG_DISCARD_NO_SYNC);
return;
}
/* Program the output start time */
fd_ch_writel(out, ts->seconds, FD_REG_U_STARTL);
fd_ch_writel(out, ts->ns / 8, FD_REG_C_START);
fd_ch_writel(out, ((ts->ns & 7) << 9) | (ts->frac >> (32 - 9)),
FD_REG_F_START);
/* Adjust pulse width and program the output end time */
ts_add2_ns(ts, out->width_ns);
fd_ch_writel(out, ts->seconds, FD_REG_U_ENDL);
fd_ch_writel(out, ts->ns / 8, FD_REG_C_END);
fd_ch_writel(out, ((ts->ns & 7) << 9) | (ts->frac >> (32 - 9)),
FD_REG_F_END);
fd_ch_writel(out, 0, FD_REG_RCR);
fd_ch_writel(out, FD_DCR_MODE, FD_REG_DCR);
fd_ch_writel(out, FD_DCR_MODE | FD_DCR_UPDATE, FD_REG_DCR);
fd_ch_writel(out, FD_DCR_MODE | FD_DCR_PG_ARM | FD_DCR_ENABLE,
FD_REG_DCR);
wrtd_log(WRTD_LOG_MSG_EV_CONSUMED, WRTD_LOG_CONSUMED_START, ev, NULL);
ts_add2_ns (ts, 8000);
/*
* Store the last programmed timestamp (+ some margin) and mark
* the output as busy
*/
out->last_programmed_sec = ts->seconds;
out->last_programmed_ns = ts->ns;
out->idle = 0;
}
static void fd_local_output(struct wrtd_fd_dev *fd,
struct wrtd_event *ev, unsigned ch)
{
struct wrtd_fd_channel *out = &fd->channels[ch];
struct wrtd_event *pq_ev;
pq_ev = pulse_queue_push(&out->queue);
if (!pq_ev) {
/* overflow.
FIXME: stats ? */
wrtd_log(WRTD_LOG_MSG_EV_DISCARDED, WRTD_LOG_DISCARD_OVERFLOW,
ev, NULL);
return;
}
*pq_ev = *ev;
}
static void fd_outputs(struct wrtd_fd_dev *fd)
{
int i;
for (i = 0;i < FD_NUM_CHANNELS; i++)
fd_output(fd, i);
}
#if 0
/**
* It disable the given channel and clear its internal queue
*/
static int wrtd_out_disable(struct trtl_fw_msg *msg_i,
struct trtl_fw_msg *msg_o)
{
uint32_t ch = ((uint32_t *)msg_i->payload)[0];
pulse_queue_init(&wrtd_out_channels[ch].queue);
fd_ch_writel(&wrtd_out_channels[ch], FD_DCR_MODE, FD_REG_DCR);
msg_o->header->msg_id = msg_i->header->msg_id;
return 0;
}
#endif
static void wrtd_fd_data_init(struct wrtd_fd_dev *fd)
{
unsigned i;
/* Channels */
for (i = 0; i < FD_NUM_CHANNELS; i++) {
memset(&fd->channels[i], 0, sizeof(struct wrtd_fd_channel));
fd->channels[i].channel_addr = fd->io_addr + 0x100 + i * 0x100;
pulse_queue_init(&fd->channels[i].queue);
fd->channels[i].idle = 1;
fd->channels[i].width_ns = 10000; // 10us
fd->channels[i].last_programmed_sec = 0;
fd->channels[i].last_programmed_ns = 0;
}
}
......@@ -35,305 +35,40 @@
#include "wrtd-rt-common.h"
#include "wrtd-fd.c"
struct wrtd_fd_dev fd0 = {
.io_addr = 0x0
};
static int wr_present(void)
{
return !!(dp_readl(FD_REG_TCR) & FD_TCR_WR_PRESENT);
return fd_wr_present(&fd0);
}
static int wr_link_up(void)
{
return dp_readl(FD_REG_TCR) & FD_TCR_WR_LINK;
return fd_wr_link_up(&fd0);
}
static int wr_time_locked(void)
{
return dp_readl(FD_REG_TCR) & FD_TCR_WR_LOCKED;
return fd_wr_time_locked(&fd0);
}
static int wr_time_ready(void)
{
return 1;
return fd_wr_time_ready(&fd0);
}
static void wr_enable_lock(int enable)
{
if(enable)
dp_writel(FD_TCR_WR_ENABLE, FD_REG_TCR);
else
dp_writel(0, FD_REG_TCR);
}
/**
* It updates the White-Rabbit link status
*/
static void wr_update_link(void)
{
switch(root.wr_state) {
case WR_LINK_OFFLINE:
if (wr_link_up())
root.wr_state = WR_LINK_ONLINE;
break;
case WR_LINK_ONLINE:
if (wr_time_ready()) {
root.wr_state = WR_LINK_SYNCING;
wr_enable_lock(1);
}
break;
case WR_LINK_SYNCING:
if (wr_time_locked()) {
pr_debug("WR link up!\n\r");
root.wr_state = WR_LINK_SYNCED;
}
break;
case WR_LINK_SYNCED:
case WR_LINK_WAIT:
break;
}
if(root.wr_state != WR_LINK_OFFLINE && !wr_link_up()) {
pr_error("rt-out: WR sync lost\n\r");
root.wr_state = WR_LINK_OFFLINE;
wr_enable_lock(0);
}
}
/**
* Writes to FD output registers for output (out)
*/
static inline void fd_ch_writel(struct wrtd_fd_channel *out, uint32_t value,
uint32_t reg)
{
dp_writel(value, reg + out->channel_addr);
}
/**
* Reads from FD output registers for output (out)
*/
static inline uint32_t fd_ch_readl (struct wrtd_fd_channel *out, uint32_t reg)
{
return dp_readl(reg + out->channel_addr);
}
/**
* Initializes an empty pulse queue
*/
static void pulse_queue_init(struct lrt_pulse_queue *p)
{
p->head = 0;
p->tail = 0;
p->count = 0;
}
/**
* Requests a new entry in a pulse queue. Returns pointer to the ne
* entry or NULL if the queue is full.
*/
static struct wrtd_event *pulse_queue_push(struct lrt_pulse_queue *p)
{
struct wrtd_event *ev;
if (p->count == FD_MAX_QUEUE_PULSES)
return NULL;
ev = &p->events[p->head];
p->count++;
p->head++;
if (p->head == FD_MAX_QUEUE_PULSES)
p->head = 0;
return ev;
}
/**
* Returns non-0 if pulse queue p contains any pulses.
*/
static inline int pulse_queue_empty(struct lrt_pulse_queue *p)
{
return (p->count == 0);
}
/**
* Returns the oldest entry in the pulse queue (or NULL if empty).
*/
static struct wrtd_event *pulse_queue_front(struct lrt_pulse_queue *p)
{
if (!p->count)
return NULL;
return &p->events[p->tail];
}
/**
* Releases the oldest entry from the pulse queue.
*/
static void pulse_queue_pop(struct lrt_pulse_queue *p)
{
p->tail++;
if(p->tail == FD_MAX_QUEUE_PULSES)
p->tail = 0;
p->count--;
}
/**
* Checks if the timestamp of the last programmed pulse is lost because
* of timeout
*/
static int check_output_timeout (struct wrtd_fd_channel *out)
{
uint32_t now_sec;
uint32_t now_ns;
int delta;
/*
* Read the current WR time, order is important: first seconds,
* then cycles (cycles get latched on reading secs register.
*/
now_sec = lr_readl(MT_CPU_LR_REG_TAI_SEC);
now_ns = lr_readl(MT_CPU_LR_REG_TAI_CYCLES) * 8;
if(out->last_programmed_sec > now_sec + OUT_TIMEOUT) {
pr_error("Enqueued event very far in the future. Dropping.");
return 0;
}
/* Current time exceeds FD setpoint? */
delta = now_sec - out->last_programmed_sec;
if (delta != 0)
return delta > 0;
delta = now_ns - out->last_programmed_ns;
return (delta > 0);
}
/**
* Drop the given enqueued trigger
*/
static void drop_trigger(struct wrtd_fd_channel *out,
struct wrtd_event *ev,
struct lrt_pulse_queue *q, unsigned reason)
{
out->idle = 1;
if (pulse_queue_empty(q))
return;
/* Drop the pulse */
pulse_queue_pop(q);
/* Disarm the FD output */
fd_ch_writel(out, FD_DCR_MODE, FD_REG_DCR);
wrtd_log(WRTD_LOG_MSG_EV_DISCARDED, reason, ev, NULL);
fd_wr_enable_lock(&fd0, enable);
}
/**
* Output driving function. Reads pulses from the output queue,
* programs the output and updates the output statistics.
*/
static void do_output (struct wrtd_fd_dev *fd, unsigned channel)
static inline int wr_sync_timeout(void)
{
struct wrtd_fd_channel *out = &fd->channels[channel];
struct lrt_pulse_queue *q = &out->queue;
struct wrtd_event *ev = pulse_queue_front(q);
uint32_t dcr = fd_ch_readl(out, FD_REG_DCR);
struct wrtd_tstamp *ts;
/* Check if the output has triggered */
if (!out->idle) {
if (!wr_is_timing_ok()) {
/* Timing has been lost. */
drop_trigger(out, ev, q, WRTD_LOG_DISCARD_NO_SYNC);
return;
}
if (!(dcr & FD_DCR_PG_TRIG)) {
/* Armed but still waiting for trigger */
if (check_output_timeout (out)) {
/* Will never trigger. Missed. */
drop_trigger(out, ev, q,
WRTD_LOG_DISCARD_TIMEOUT);
}
} else {
/* Has been triggered. */
wrtd_log(WRTD_LOG_MSG_EV_CONSUMED,
WRTD_LOG_CONSUMED_DONE, ev, NULL);
pulse_queue_pop(q);
out->idle = 1;
}
return;
}
/* Output is idle: check if there's something in the queue to execute */
if (pulse_queue_empty(q))
return;
ev = pulse_queue_front(q);
ts = &ev->ts;
if (!wr_is_timing_ok()) {
drop_trigger(out, ev, q, WRTD_LOG_DISCARD_NO_SYNC);
return;
}
/* Program the output start time */
fd_ch_writel(out, ts->seconds, FD_REG_U_STARTL);
fd_ch_writel(out, ts->ns / 8, FD_REG_C_START);
fd_ch_writel(out, ((ts->ns & 7) << 9) | (ts->frac >> (32 - 9)),
FD_REG_F_START);
/* Adjust pulse width and program the output end time */
ts_add2_ns(ts, out->width_ns);
fd_ch_writel(out, ts->seconds, FD_REG_U_ENDL);
fd_ch_writel(out, ts->ns / 8, FD_REG_C_END);
fd_ch_writel(out, ((ts->ns & 7) << 9) | (ts->frac >> (32 - 9)),
FD_REG_F_END);
fd_ch_writel(out, 0, FD_REG_RCR);
fd_ch_writel(out, FD_DCR_MODE, FD_REG_DCR);
fd_ch_writel(out, FD_DCR_MODE | FD_DCR_UPDATE, FD_REG_DCR);
fd_ch_writel(out, FD_DCR_MODE | FD_DCR_PG_ARM | FD_DCR_ENABLE,
FD_REG_DCR);
wrtd_log(WRTD_LOG_MSG_EV_CONSUMED, WRTD_LOG_CONSUMED_START, ev, NULL);
ts_add2_ns (ts, 8000);
/*
* Store the last programmed timestamp (+ some margin) and mark
* the output as busy
*/
out->last_programmed_sec = ts->seconds;
out->last_programmed_ns = ts->ns;
out->idle = 0;
}
static void fd_local_output(struct wrtd_fd_dev *fd,
struct wrtd_event *ev, unsigned ch)
{
struct wrtd_fd_channel *out = &fd->channels[ch];
struct wrtd_event *pq_ev;
pq_ev = pulse_queue_push(&out->queue);
if (!pq_ev) {
/* overflow.
FIXME: stats ? */
wrtd_log(WRTD_LOG_MSG_EV_DISCARDED, WRTD_LOG_DISCARD_OVERFLOW,
ev, NULL);
return;
}
*pq_ev = *ev;
return fd_wr_sync_timeout();
}
static void wrtd_local_output(struct wrtd_event *ev, unsigned ch)
......@@ -341,36 +76,6 @@ static void wrtd_local_output(struct wrtd_event *ev, unsigned ch)
fd_local_output(&fd0, ev, ch);
}
static void do_outputs(struct wrtd_fd_dev *fd)
{
int i;
for (i = 0;i < FD_NUM_CHANNELS; i++)
do_output(fd, i);
}
/*.
* WRTD Command Handlers
*/
#if 0
/**
* It disable the given channel and clear its internal queue
*/
static int wrtd_out_disable(struct trtl_fw_msg *msg_i,
struct trtl_fw_msg *msg_o)
{
uint32_t ch = ((uint32_t *)msg_i->payload)[0];
pulse_queue_init(&wrtd_out_channels[ch].queue);
fd_ch_writel(&wrtd_out_channels[ch], FD_DCR_MODE, FD_REG_DCR);
msg_o->header->msg_id = msg_i->header->msg_id;
return 0;
}
#endif
#ifdef SIMULATION
static int wrtd_o_sim_init(void)
{
......@@ -401,22 +106,6 @@ static int wrtd_o_sim_init(void)
#endif
static void wrtd_fd_data_init(struct wrtd_fd_dev *fd)
{
unsigned i;
/* Channels */
for (i = 0; i < FD_NUM_CHANNELS; i++) {
memset(&fd->channels[i], 0, sizeof(struct wrtd_fd_channel));
fd->channels[i].channel_addr = fd->io_addr + 0x100 + i * 0x100;
pulse_queue_init(&fd->channels[i].queue);
fd->channels[i].idle = 1;
fd->channels[i].width_ns = 10000; // 10us
fd->channels[i].last_programmed_sec = 0;
fd->channels[i].last_programmed_ns = 0;
}
}
/**
* Initialize data structures, RT application and variables
*/
......@@ -447,5 +136,5 @@ static int wrtd_user_init(void)
static void wrtd_io(void)
{
do_outputs(&fd0);
fd_outputs(&fd0);
}
......@@ -63,59 +63,24 @@ static inline void wr_enable_lock(int enable)
tdc_wr_enable_lock(&tdc0, enable);
}
static uint32_t tai_start = 0;
static void wrtd_local_output(struct wrtd_event *ev, unsigned ch)
static inline int wr_sync_timeout(void)
{
return;
#ifdef SIMULATION
return 0;
#else
return tdc_wr_sync_timeout();
#endif
}
/**
* It updates the White-Rabbit link status
*/
static void wr_update_link(void)
static void wrtd_local_output(struct wrtd_event *ev, unsigned ch)
{
switch (root.wr_state) {
case WR_LINK_OFFLINE:
if (wr_link_up())
root.wr_state = WR_LINK_ONLINE;
break;
case WR_LINK_ONLINE:
if (wr_time_ready()) {
root.wr_state = WR_LINK_SYNCING;
wr_enable_lock(1);
}
break;
case WR_LINK_SYNCING:
if (wr_time_locked()) {
pr_debug("rt-tdc: WR synced, waiting for TDC plumbing to catch up...\n\r");
root.wr_state = WR_LINK_WAIT;
tai_start = lr_readl(MT_CPU_LR_REG_TAI_SEC);
}
break;
case WR_LINK_WAIT:
if (is_simulation
|| (lr_readl(MT_CPU_LR_REG_TAI_SEC) >= (tai_start + 4))) {
pr_debug("rt-tdc: WR TDC synced\n\r");
root.wr_state = WR_LINK_SYNCED;
}
break;
case WR_LINK_SYNCED:
break;
}
if (root.wr_state != WR_LINK_OFFLINE && !wr_link_up()) {
pr_error("rt-tdc: WR sync lost\n\r");
root.wr_state = WR_LINK_OFFLINE;
wr_enable_lock(0);
}
return;
}
static int wrtd_i_sim_init(struct wrtd_tdc_dev *tdc)
{
#if 0
/* TODO: preconfigure the rules. */
int i;
for(i = 0; i < TDC_NUM_CHANNELS; i++) {
......
......@@ -26,6 +26,7 @@
struct wrtd_tdc_dev {
uint32_t io_addr;
/* FIXME: base channel (to create the event id). */
};
static inline void tdc_writel(const struct wrtd_tdc_dev *dev,
......@@ -236,6 +237,12 @@ static inline int tdc_wr_time_ready(struct wrtd_tdc_dev *tdc)
return tdc_readl(tdc, BASE_DP_TDC_REGS + TDC_REG_WR_STAT) & TDC_WR_STAT_TIME_VALID;
}
static inline int tdc_wr_sync_timeout(void)
{
/* Wait 4 seconds until the tcd is ready. */
return 4;
}
/**
* Handles input timestamps from all TDC channels.
*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment