Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
W
White Rabbit Trigger Distribution
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
White Rabbit Trigger Distribution
Commits
d11fcb12
Commit
d11fcb12
authored
Oct 26, 2018
by
Tristan Gingold
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
wrtd: finish fd modularization.
parent
5454ce71
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
405 additions
and
365 deletions
+405
-365
wrtd-rt-common.h
software/firmware/common/wrtd-rt-common.h
+49
-0
wrtd-fd.c
software/firmware/fd/wrtd-fd.c
+330
-0
wrtd-rt-fd.c
software/firmware/fd/wrtd-rt-fd.c
+10
-321
wrtd-rt-tdc.c
software/firmware/tdc/wrtd-rt-tdc.c
+9
-44
wrtd-tdc.c
software/firmware/tdc/wrtd-tdc.c
+7
-0
No files found.
software/firmware/common/wrtd-rt-common.h
View file @
d11fcb12
...
...
@@ -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)
...
...
software/firmware/fd/wrtd-fd.c
0 → 100644
View file @
d11fcb12
/*
* 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
;
}
}
software/firmware/fd/wrtd-rt-fd.c
View file @
d11fcb12
...
...
@@ -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
);
}
software/firmware/tdc/wrtd-rt-tdc.c
View file @
d11fcb12
...
...
@@ -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++) {
...
...
software/firmware/tdc/wrtd-tdc.c
View file @
d11fcb12
...
...
@@ -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.
*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment