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
1394f372
Commit
1394f372
authored
Jun 17, 2019
by
Dimitris Lampridis
Committed by
Dimitris Lampridis
Jun 26, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
sw: wip cleanup and comments
parent
1f2cd1f6
Hide whitespace changes
Inline
Side-by-side
Showing
37 changed files
with
2328 additions
and
2052 deletions
+2328
-2052
Makefile
doc/Makefile
+13
-0
dictionary.md
doc/dictionary.md
+0
-13
introduction.md
doc/introduction.md
+0
-9
Makefile
software/firmware/Makefile
+0
-1
mt_defconfig
software/firmware/adc/configs/mt_defconfig
+0
-1
wrtd-adcin.c
software/firmware/adc/wrtd-adcin.c
+24
-23
wrtd-adcout.c
software/firmware/adc/wrtd-adcout.c
+86
-86
wrtd-rt-adc.c
software/firmware/adc/wrtd-rt-adc.c
+29
-30
acam_gpx.h
software/firmware/common/hw/acam_gpx.h
+5
-7
out_queue.h
software/firmware/common/out_queue.h
+51
-45
trtl-memory.ld
software/firmware/common/trtl-memory.ld
+8
-1
wrtd-rt-common.h
software/firmware/common/wrtd-rt-common.h
+141
-135
mt_defconfig
software/firmware/fd/configs/mt_defconfig
+0
-1
fd-acam.c
software/firmware/fd/fd-acam.c
+238
-235
fd-calibrate.c
software/firmware/fd/fd-calibrate.c
+83
-83
fd-gpio.c
software/firmware/fd/fd-gpio.c
+61
-60
fd-i2c.c
software/firmware/fd/fd-i2c.c
+89
-88
fd-init.c
software/firmware/fd/fd-init.c
+64
-61
fd-pll.c
software/firmware/fd/fd-pll.c
+155
-152
pll_config.h
software/firmware/fd/hw/pll_config.h
+86
-79
wrtd-fd.c
software/firmware/fd/wrtd-fd.c
+118
-118
wrtd-fd.h
software/firmware/fd/wrtd-fd.h
+38
-30
wrtd-rt-fd.c
software/firmware/fd/wrtd-rt-fd.c
+12
-12
mt_defconfig
software/firmware/tdc/configs/mt_defconfig
+0
-1
tdc_regs.h
software/firmware/tdc/hw/tdc_regs.h
+90
-94
wrtd-rt-tdc.c
software/firmware/tdc/wrtd-rt-tdc.c
+7
-8
wrtd-tdc.c
software/firmware/tdc/wrtd-tdc.c
+117
-117
wrtd-common.h
software/include/wrtd-common.h
+10
-7
libwrtd-attributes.c
software/lib/libwrtd-attributes.c
+29
-6
libwrtd-internal.c
software/lib/libwrtd-internal.c
+7
-9
libwrtd-private.h
software/lib/libwrtd-private.h
+2
-7
libwrtd.c
software/lib/libwrtd.c
+381
-146
libwrtd.h
software/lib/libwrtd.h
+157
-118
wrtd-config.c
software/tools/wrtd-config.c
+74
-83
wrtd-inout-common.c
software/tools/wrtd-inout-common.c
+107
-118
wrtd-internal.h
software/tools/wrtd-internal.h
+7
-18
wrtd-logging.c
software/tools/wrtd-logging.c
+39
-50
No files found.
doc/Makefile
View file @
1394f372
...
...
@@ -44,3 +44,16 @@ else
GIT_VERSION
=
$(GIT_VERSION)
EXCLUDE_FILES
=
$(EXCLUDE_FILES)
BRIEF
=
$(BRIEF)
\
OUTPUT
=
$(DOXY_OUT)
doxygen ./doxygen-wrtd-config
endif
# List of Doxygen folders to consider
DOXINPUT
:=
../software/lib
DOXINPUT
+=
../software/include
DOXINPUT
+=
../software/firmware/common
DOXEXCL
:=
""
# List of actual Doxygen source files
DOXSRC
=
$(
shell
find
$(DOXINPUT)
-type
f
-name
'*.[chS]'
)
.doxystamp
:
$(DOXSRC)
GIT_VERSION
=
$(GIT_VERSION)
DOXINPUT
=
"
$(DOXINPUT)
"
DOXEXCL
=
"
$(DOXEXCL)
"
doxygen ./doxygen-wrtd-config
@
touch
.doxystamp
doc/dictionary.md
deleted
100644 → 0
View file @
1f2cd1f6
Dictionary
==========
The main purpose of this dictionary is to explain the
White-Rabbit Trigger-Distribution terminology.
channel
dead time
delay
input
output
pulse
trigger
trigger condition
\ No newline at end of file
doc/introduction.md
deleted
100644 → 0
View file @
1f2cd1f6
Introduction
============
`Hello`
*there*
[
link
](
https://ohwr.org
)
-
item 1
-
item 2
[
dictionary
](
dictionary.md
)
software/firmware/Makefile
View file @
1394f372
-include
Makefile.specific
DIRS
:=
tdc fd adc
all clean cleanall modules install modules_install
:
$(DIRS)
clean
:
TARGET = clean
...
...
software/firmware/adc/configs/mt_defconfig
View file @
1394f372
#
# Automatically generated file; DO NOT EDIT.
# fmc-svec-carrier fw-01 demo configuration
#
#
...
...
software/firmware/adc/wrtd-adcin.c
View file @
1394f372
/*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Dimitris Lampridis <dimitris.lampridis@cern.ch>
/**
* @file wrtd-adcin.c
*
* ADCIN: trigger coming from the ADC mezzanine.
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
/* ADCIN: trigger coming from the ADC mezzanine. */
#include "mockturtle-rt.h"
#define ADCIN_NUM_CHANNELS 5
...
...
@@ -17,39 +18,39 @@ struct wrtd_adcin_dev {
};
static
inline
void
adcin_writel
(
const
struct
wrtd_adcin_dev
*
dev
,
uint32_t
value
,
uint32_t
reg
)
uint32_t
value
,
uint32_t
reg
)
{
dp_writel
(
value
,
dev
->
io_addr
+
reg
);
dp_writel
(
value
,
dev
->
io_addr
+
reg
);
}
static
inline
uint32_t
adcin_readl
(
const
struct
wrtd_adcin_dev
*
dev
,
uint32_t
reg
)
{
return
dp_readl
(
dev
->
io_addr
+
reg
);
return
dp_readl
(
dev
->
io_addr
+
reg
);
}
static
inline
int
adcin_wr_link_up
(
struct
wrtd_adcin_dev
*
adcin
)
{
return
adcin_readl
(
adcin
,
ALT_TRIGOUT_STATUS
)
&
ALT_TRIGOUT_WR_LINK
;
return
adcin_readl
(
adcin
,
ALT_TRIGOUT_STATUS
)
&
ALT_TRIGOUT_WR_LINK
;
}
static
inline
int
adcin_wr_time_locked
(
struct
wrtd_adcin_dev
*
adcin
)
{
return
1
;
return
1
;
}
static
void
adcin_wr_enable_lock
(
struct
wrtd_adcin_dev
*
dev
,
int
enable
)
{
return
;
return
;
}
static
inline
int
adcin_wr_time_ready
(
struct
wrtd_adcin_dev
*
adcin
)
{
return
adcin_readl
(
adcin
,
ALT_TRIGOUT_STATUS
)
&
ALT_TRIGOUT_WR_VALID
;
return
adcin_readl
(
adcin
,
ALT_TRIGOUT_STATUS
)
&
ALT_TRIGOUT_WR_VALID
;
}
static
inline
int
adcin_wr_sync_timeout
(
void
)
{
return
0
;
return
0
;
}
/**
...
...
@@ -68,7 +69,7 @@ static void adcin_input(struct wrtd_adcin_dev *adcin)
/* Poll the FIFO and read the timestamp */
if
(
!
(
status
&
ALT_TRIGOUT_TS_PRESENT
))
return
;
return
;
mask
=
adcin_readl
(
adcin
,
ALT_TRIGOUT_TS_MASK_SEC
+
0
);
ev
.
ts
.
seconds
=
adcin_readl
(
adcin
,
ALT_TRIGOUT_TS_MASK_SEC
+
4
);
...
...
@@ -77,13 +78,13 @@ static void adcin_input(struct wrtd_adcin_dev *adcin)
for
(
i
=
0
;
i
<
ADCIN_NUM_CHANNELS
;
i
++
)
{
/* The last channel is the ext trigger with a different mask */
if
(
i
==
ADCIN_NUM_CHANNELS
-
1
)
{
if
(
!
(
mask
&
(
ALT_TRIGOUT_EXT_MASK
>>
32
)))
continue
;
}
else
if
(
!
(
mask
&
((
ALT_TRIGOUT_CH1_MASK
>>
32
)
<<
i
)))
continue
;
/* The last channel is the ext trigger with a different mask */
if
(
i
==
ADCIN_NUM_CHANNELS
-
1
)
{
if
(
!
(
mask
&
(
ALT_TRIGOUT_EXT_MASK
>>
32
)))
continue
;
}
else
if
(
!
(
mask
&
((
ALT_TRIGOUT_CH1_MASK
>>
32
)
<<
i
)))
continue
;
memset
(
ev
.
id
,
0
,
WRTD_ID_LEN
);
ev
.
id
[
0
]
=
'L'
;
...
...
@@ -104,7 +105,7 @@ static void adcin_input(struct wrtd_adcin_dev *adcin)
static
int
adcin_init
(
struct
wrtd_adcin_dev
*
adcin
)
{
pr_debug
(
"adcin initialization complete
\n\r
"
);
pr_debug
(
"adcin initialization complete
\n\r
"
);
return
0
;
return
0
;
}
software/firmware/adc/wrtd-adcout.c
View file @
1394f372
/*
* Copyright (C) 2013-2018 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
/**
* @file wrtd-adcin.c
*
* ADCout: trigger ADC sampling. Output from the WRTD pov.
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
/* ADCout: trigger ADC sampling. Output from the WRTD pov. */
#include <errno.h>
#include <string.h>
...
...
@@ -30,44 +30,44 @@ struct wrtd_adcout_dev {
static
inline
int
adcout_wr_present
(
struct
wrtd_adcout_dev
*
fd
)
{
return
1
;
return
1
;
}
static
inline
int
adcout_wr_link_up
(
struct
wrtd_adcout_dev
*
fd
)
{
return
1
;
return
1
;
}
static
inline
int
adcout_wr_time_locked
(
struct
wrtd_adcout_dev
*
fd
)
{
return
1
;
return
1
;
}
static
inline
int
adcout_wr_time_ready
(
struct
wrtd_adcout_dev
*
fd
)
{
return
1
;
return
1
;
}
static
inline
int
adcout_wr_sync_timeout
(
void
)
{
return
0
;
return
0
;
}
static
void
adcout_wr_enable_lock
(
struct
wrtd_adcout_dev
*
fd
,
int
enable
)
{
return
;
return
;
}
static
inline
void
adcout_writel
(
struct
wrtd_adcout_dev
*
dev
,
uint32_t
value
,
uint32_t
reg
)
uint32_t
reg
)
{
dp_writel
(
value
,
dev
->
io_addr
+
reg
);
dp_writel
(
value
,
dev
->
io_addr
+
reg
);
}
static
inline
uint32_t
adcout_readl
(
struct
wrtd_adcout_dev
*
dev
,
uint32_t
reg
)
{
return
dp_readl
(
dev
->
io_addr
+
reg
);
return
dp_readl
(
dev
->
io_addr
+
reg
);
}
...
...
@@ -76,24 +76,24 @@ static inline uint32_t adcout_readl (struct wrtd_adcout_dev *dev, uint32_t reg)
* Drop the given enqueued trigger
*/
static
void
adcout_drop_trigger
(
struct
wrtd_adcout_dev
*
dev
,
struct
wrtd_event
*
ev
,
unsigned
reason
,
struct
wrtd_tstamp
*
now
)
struct
wrtd_event
*
ev
,
unsigned
reason
,
struct
wrtd_tstamp
*
now
)
{
struct
adcout_out_queue
*
q
=
&
dev
->
queue
;
dev
->
idle
=
1
;
struct
adcout_out_queue
*
q
=
&
dev
->
queue
;
dev
->
idle
=
1
;
if
(
adcout_out_queue_empty
(
q
))
{
/* Should never happen. */
return
;
}
if
(
adcout_out_queue_empty
(
q
))
{
/* Should never happen. */
return
;
}
/* Drop the pulse */
adcout_out_queue_pop
(
q
);
/* Drop the pulse */
adcout_out_queue_pop
(
q
);
/* Disarm the ADC output */
adcout_writel
(
dev
,
0
,
ALT_TRIGIN_CTRL
);
/* Disarm the ADC output */
adcout_writel
(
dev
,
0
,
ALT_TRIGIN_CTRL
);
wrtd_log
(
WRTD_LOG_MSG_EV_DISCARDED
,
reason
,
NULL
,
ev
,
now
);
wrtd_log
(
WRTD_LOG_MSG_EV_DISCARDED
,
reason
,
NULL
,
ev
,
now
);
}
...
...
@@ -103,91 +103,91 @@ static void adcout_drop_trigger(struct wrtd_adcout_dev *dev,
*/
static
void
adcout_output
(
struct
wrtd_adcout_dev
*
dev
)
{
struct
adcout_out_queue
*
q
=
&
dev
->
queue
;
struct
wrtd_event
*
ev
=
adcout_out_queue_front
(
q
);
uint32_t
ctrl
=
adcout_readl
(
dev
,
ALT_TRIGIN_CTRL
);
struct
wrtd_tstamp
*
ts
;
struct
adcout_out_queue
*
q
=
&
dev
->
queue
;
struct
wrtd_event
*
ev
=
adcout_out_queue_front
(
q
);
uint32_t
ctrl
=
adcout_readl
(
dev
,
ALT_TRIGIN_CTRL
);
struct
wrtd_tstamp
*
ts
;
/* Check if the output has triggered */
if
(
!
dev
->
idle
)
{
/* Check if the output has triggered */
if
(
!
dev
->
idle
)
{
#if 0
if (!wr_is_timing_ok()) {
/* Timing has been lost. */
drop_trigger(out, ev, q, WRTD_LOG_DISCARD_NO_SYNC);
return;
}
if (!wr_is_timing_ok()) {
/* Timing has been lost. */
drop_trigger(out, ev, q, WRTD_LOG_DISCARD_NO_SYNC);
return;
}
#endif
if
(
ctrl
&
ALT_TRIGIN_CTRL_ENABLE
)
{
/* Armed but still waiting for trigger */
struct
wrtd_tstamp
now
;
ts_now
(
&
now
);
if
(
adcout_out_queue_check_timeout
(
q
,
&
now
))
{
/* Will never trigger. Missed. */
adcout_drop_trigger
(
dev
,
ev
,
WRTD_LOG_DISCARD_TIMEOUT
,
&
now
);
}
}
else
{
/* Has been triggered. */
wrtd_log
(
WRTD_LOG_MSG_EV_CONSUMED
,
if
(
ctrl
&
ALT_TRIGIN_CTRL_ENABLE
)
{
/* Armed but still waiting for trigger */
struct
wrtd_tstamp
now
;
ts_now
(
&
now
);
if
(
adcout_out_queue_check_timeout
(
q
,
&
now
))
{
/* Will never trigger. Missed. */
adcout_drop_trigger
(
dev
,
ev
,
WRTD_LOG_DISCARD_TIMEOUT
,
&
now
);
}
}
else
{
/* Has been triggered. */
wrtd_log
(
WRTD_LOG_MSG_EV_CONSUMED
,
WRTD_LOG_CONSUMED_DONE
,
NULL
,
ev
,
NULL
);
adcout_out_queue_pop
(
q
);
dev
->
idle
=
1
;
}
return
;
}
adcout_out_queue_pop
(
q
);
dev
->
idle
=
1
;
}
return
;
}
/* Output is idle: check if there's something in the queue to execute */
if
(
adcout_out_queue_empty
(
q
))
return
;
/* Output is idle: check if there's something in the queue to execute */
if
(
adcout_out_queue_empty
(
q
))
return
;
ev
=
adcout_out_queue_front
(
q
);
ts
=
&
ev
->
ts
;
ev
=
adcout_out_queue_front
(
q
);
ts
=
&
ev
->
ts
;
if
(
!
wr_is_timing_ok
())
{
adcout_drop_trigger
(
dev
,
ev
,
WRTD_LOG_DISCARD_NO_SYNC
,
NULL
);
return
;
}
if
(
!
wr_is_timing_ok
())
{
adcout_drop_trigger
(
dev
,
ev
,
WRTD_LOG_DISCARD_NO_SYNC
,
NULL
);
return
;
}
/* Program the output start time */
adcout_writel
(
dev
,
0
,
ALT_TRIGIN_SECONDS
+
0
);
adcout_writel
(
dev
,
ts
->
seconds
,
ALT_TRIGIN_SECONDS
+
4
);
adcout_writel
(
dev
,
ts
->
ns
/
8
,
ALT_TRIGIN_CYCLES
);
adcout_writel
(
dev
,
ALT_TRIGIN_CTRL_ENABLE
,
ALT_TRIGIN_CTRL
);
/* Program the output start time */
adcout_writel
(
dev
,
0
,
ALT_TRIGIN_SECONDS
+
0
);
adcout_writel
(
dev
,
ts
->
seconds
,
ALT_TRIGIN_SECONDS
+
4
);
adcout_writel
(
dev
,
ts
->
ns
/
8
,
ALT_TRIGIN_CYCLES
);
adcout_writel
(
dev
,
ALT_TRIGIN_CTRL_ENABLE
,
ALT_TRIGIN_CTRL
);
wrtd_log
(
WRTD_LOG_MSG_EV_CONSUMED
,
WRTD_LOG_CONSUMED_START
,
wrtd_log
(
WRTD_LOG_MSG_EV_CONSUMED
,
WRTD_LOG_CONSUMED_START
,
NULL
,
ev
,
NULL
);
ts_add2_ns
(
ts
,
8000
);
ts_add2_ns
(
ts
,
8000
);
/*
* Store the last programmed timestamp (+ some margin) and mark
* the output as busy
*/
q
->
last_programmed_sec
=
ts
->
seconds
;
q
->
last_programmed_ns
=
ts
->
ns
;
dev
->
idle
=
0
;
/*
* Store the last programmed timestamp (+ some margin) and mark
* the output as busy
*/
q
->
last_programmed_sec
=
ts
->
seconds
;
q
->
last_programmed_ns
=
ts
->
ns
;
dev
->
idle
=
0
;
}
static
int
adcout_local_output
(
struct
wrtd_adcout_dev
*
dev
,
struct
wrtd_event
*
ev
,
unsigned
ch
)
{
struct
wrtd_event
*
pq_ev
;
struct
wrtd_event
*
pq_ev
;
pq_ev
=
adcout_out_queue_push
(
&
dev
->
queue
);
if
(
!
pq_ev
)
{
pq_ev
=
adcout_out_queue_push
(
&
dev
->
queue
);
if
(
!
pq_ev
)
{
return
-
EOVERFLOW
;
}
}
*
pq_ev
=
*
ev
;
*
pq_ev
=
*
ev
;
return
0
;
}
static
void
adcout_init
(
struct
wrtd_adcout_dev
*
dev
)
{
adcout_out_queue_init
(
&
dev
->
queue
);
dev
->
idle
=
1
;
adcout_out_queue_init
(
&
dev
->
queue
);
dev
->
idle
=
1
;
pr_debug
(
"adcout initialization complete
\n\r
"
);
pr_debug
(
"adcout initialization complete
\n\r
"
);
}
software/firmware/adc/wrtd-rt-adc.c
View file @
1394f372
/*
*
Copyright (C) 2013-2018 CERN (www.cern.ch)
*
Author: Federico Vaga <federico.vaga@cern.ch>
*
Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
/*
*
*
@file wrtd-rt-adc.c
*
*
Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "mockturtle-rt.h"
#include <mockturtle-framework.h>
#include "wrtd-common.h"
...
...
@@ -44,35 +43,35 @@ static struct wrtd_adcout_dev adcout0 =
static
inline
int
wr_link_up
(
void
)
{
if
(
!
adcin_wr_link_up
(
&
adcin0
))
return
0
;
if
(
!
adcin_wr_link_up
(
&
adcin0
))
return
0
;
if
(
!
adcout_wr_link_up
(
&
adcout0
))
return
0
;
return
1
;
return
0
;
return
1
;
}
static
inline
int
wr_time_locked
(
void
)
{
if
(
!
adcin_wr_time_locked
(
&
adcin0
))
return
0
;
if
(
!
adcin_wr_time_locked
(
&
adcin0
))
return
0
;
if
(
!
adcout_wr_time_locked
(
&
adcout0
))
return
0
;
return
1
;
return
0
;
return
1
;
}
static
inline
int
wr_time_ready
(
void
)
{
if
(
!
adcin_wr_time_ready
(
&
adcin0
))
return
0
;
if
(
!
adcin_wr_time_ready
(
&
adcin0
))
return
0
;
if
(
!
adcout_wr_time_ready
(
&
adcout0
))
return
0
;
return
1
;
return
0
;
return
1
;
}
static
inline
void
wr_enable_lock
(
int
enable
)
{
adcin_wr_enable_lock
(
&
adcin0
,
enable
);
adcout_wr_enable_lock
(
&
adcout0
,
enable
);
adcin_wr_enable_lock
(
&
adcin0
,
enable
);
adcout_wr_enable_lock
(
&
adcout0
,
enable
);
}
static
inline
int
wr_sync_timeout
(
void
)
...
...
@@ -80,14 +79,14 @@ static inline int wr_sync_timeout(void)
#ifdef SIMULATION
return
0
;
#else
int
res
,
val
;
res
=
0
;
int
res
,
val
;
res
=
0
;
val
=
adcin_wr_sync_timeout
();
res
=
val
>
res
?
val
:
res
;
val
=
adcin_wr_sync_timeout
();
res
=
val
>
res
?
val
:
res
;
val
=
adcout_wr_sync_timeout
();
res
=
val
>
res
?
val
:
res
;
val
=
adcout_wr_sync_timeout
();
res
=
val
>
res
?
val
:
res
;
return
res
;
#endif
}
...
...
@@ -99,18 +98,18 @@ static int wrtd_local_output(struct wrtd_event *ev, unsigned ch)
static
int
wrtd_user_init
(
void
)
{
adcin_init
(
&
adcin0
);
adcin_init
(
&
adcin0
);
adcout_init
(
&
adcout0
);
wr_enable_lock
(
0
);
wr_enable_lock
(
0
);
pr_debug
(
"rt-adc firmware initialized.
\n\r
"
);
pr_debug
(
"rt-adc firmware initialized.
\n\r
"
);
return
0
;
return
0
;
}
static
void
wrtd_io
(
void
)
{
adcin_input
(
&
adcin0
);
adcin_input
(
&
adcin0
);
adcout_output
(
&
adcout0
);
}
software/firmware/common/hw/acam_gpx.h
View file @
1394f372
/*
* acam_gpx.h
/*
*
*
@file
acam_gpx.h
*
* Copyright (c) 2012-2013 CERN (http://www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
*
This program is free software; you can redistribute it and/or modify it
*
under the terms of the GNU General Public License as published by the Free
* S
oftware Foundation; version 2 of the License.
*
Copyright (c) 2012-2019 CERN (home.cern)
*
* S
PDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __ACAM_GPX_H
...
...
@@ -102,4 +101,3 @@
#define AR12_StartNU (1<<26)
#endif
software/firmware/common/out_queue.h
View file @
1394f372
/* Generic output queue.
User needs to define:
OUT_QUEUE_PREFIX: the prefix (ends with an '_')
OUT_QUEUE_SIZE: max length of the queue
OUT_QUEUE_MAXTIME: maximum time in advance.
*/
/**
* @file out_queue.h
*
* Generic output queue. Users need to define:
* - `OUT_QUEUE_PREFIX` : the prefix (must end with an '_')
* - `OUT_QUEUE_SIZE` : max length of the queue
* - `OUT_QUEUE_MAXTIME`: maximum time in advance.
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef OUT_QUEUE_PREFIX
#error "OUT_QUEUE_PREFIX not defined"
...
...
@@ -15,12 +21,12 @@
#define OUT_QUEUE_STRUCT OUT_QUEUE_NAME(out_queue)
struct
OUT_QUEUE_STRUCT
{
struct
wrtd_event
events
[
OUT_QUEUE_SIZE
];
int
head
,
tail
,
count
;
struct
wrtd_event
events
[
OUT_QUEUE_SIZE
];
int
head
,
tail
,
count
;
/* Last timestamp value written to output config. */
uint32_t
last_programmed_sec
;
uint32_t
last_programmed_ns
;
/* Last timestamp value written to output config. */
uint32_t
last_programmed_sec
;
uint32_t
last_programmed_ns
;
};
/**
...
...
@@ -28,12 +34,12 @@ struct OUT_QUEUE_STRUCT {
*/
static
void
OUT_QUEUE_NAME
(
out_queue_init
)(
struct
OUT_QUEUE_STRUCT
*
p
)
{
p
->
head
=
0
;
p
->
tail
=
0
;
p
->
count
=
0
;
p
->
head
=
0
;
p
->
tail
=
0
;
p
->
count
=
0
;
p
->
last_programmed_sec
=
0
;
p
->
last_programmed_ns
=
0
;
p
->
last_programmed_sec
=
0
;
p
->
last_programmed_ns
=
0
;
}
...
...
@@ -43,19 +49,19 @@ static void OUT_QUEUE_NAME(out_queue_init)(struct OUT_QUEUE_STRUCT *p)
*/
static
struct
wrtd_event
*
OUT_QUEUE_NAME
(
out_queue_push
)(
struct
OUT_QUEUE_STRUCT
*
p
)
{
struct
wrtd_event
*
ev
;
struct
wrtd_event
*
ev
;
if
(
p
->
count
==
OUT_QUEUE_SIZE
)
return
NULL
;
if
(
p
->
count
==
OUT_QUEUE_SIZE
)
return
NULL
;
ev
=
&
p
->
events
[
p
->
head
];
p
->
count
++
;
p
->
head
++
;
ev
=
&
p
->
events
[
p
->
head
];
p
->
count
++
;
p
->
head
++
;
if
(
p
->
head
==
OUT_QUEUE_SIZE
)
p
->
head
=
0
;
if
(
p
->
head
==
OUT_QUEUE_SIZE
)
p
->
head
=
0
;
return
ev
;
return
ev
;
}
...
...
@@ -64,7 +70,7 @@ static struct wrtd_event *OUT_QUEUE_NAME(out_queue_push)(struct OUT_QUEUE_STRUCT
*/
static
inline
int
OUT_QUEUE_NAME
(
out_queue_empty
)(
struct
OUT_QUEUE_STRUCT
*
p
)
{
return
(
p
->
count
==
0
);
return
(
p
->
count
==
0
);
}
...
...
@@ -73,9 +79,9 @@ static inline int OUT_QUEUE_NAME(out_queue_empty)(struct OUT_QUEUE_STRUCT *p)
*/
static
struct
wrtd_event
*
OUT_QUEUE_NAME
(
out_queue_front
)(
struct
OUT_QUEUE_STRUCT
*
p
)
{
if
(
!
p
->
count
)
return
NULL
;
return
&
p
->
events
[
p
->
tail
];
if
(
!
p
->
count
)
return
NULL
;
return
&
p
->
events
[
p
->
tail
];
}
...
...
@@ -84,11 +90,11 @@ static struct wrtd_event *OUT_QUEUE_NAME(out_queue_front)(struct OUT_QUEUE_STRUC
*/
static
void
OUT_QUEUE_NAME
(
out_queue_pop
)(
struct
OUT_QUEUE_STRUCT
*
p
)
{
p
->
tail
++
;
p
->
tail
++
;
if
(
p
->
tail
==
OUT_QUEUE_SIZE
)
p
->
tail
=
0
;
p
->
count
--
;
if
(
p
->
tail
==
OUT_QUEUE_SIZE
)
p
->
tail
=
0
;
p
->
count
--
;
}
/**
...
...
@@ -96,23 +102,23 @@ static void OUT_QUEUE_NAME(out_queue_pop)(struct OUT_QUEUE_STRUCT *p)
* of timeout
*/
static
int
OUT_QUEUE_NAME
(
out_queue_check_timeout
)
(
struct
OUT_QUEUE_STRUCT
*
q
,
struct
wrtd_tstamp
*
now
)
struct
wrtd_tstamp
*
now
)
{
int
delta
;
int
delta
;
if
(
q
->
last_programmed_sec
>
now
->
seconds
+
OUT_QUEUE_MAXTIME
)
{
pr_error
(
"Enqueued event very far in the future. Dropping."
);
return
0
;
}
if
(
q
->
last_programmed_sec
>
now
->
seconds
+
OUT_QUEUE_MAXTIME
)
{
pr_error
(
"Enqueued event very far in the future. Dropping."
);
return
0
;
}
/* Current time exceeds FD setpoint? */
/* Current time exceeds FD setpoint? */
delta
=
now
->
seconds
-
q
->
last_programmed_sec
;
if
(
delta
!=
0
)
return
delta
>
0
;
delta
=
now
->
seconds
-
q
->
last_programmed_sec
;
if
(
delta
!=
0
)
return
delta
>
0
;
delta
=
now
->
ns
-
q
->
last_programmed_ns
;
return
(
delta
>
0
);
delta
=
now
->
ns
-
q
->
last_programmed_ns
;
return
(
delta
>
0
);
}
#undef OUT_QUEUE_STRUCT
...
...
software/firmware/common/trtl-memory.ld
View file @
1394f372
/* This is a basic linker configuration for WRTD.
/**
* @file trtl-memory.ld
*
* This is a basic linker configuration for WRTD.
*
* It expects that every MT CPU has at least 32KB
* of memory, as well as 2KB of shared memory for
* all CPUS.
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
MEMORY
...
...
software/firmware/common/wrtd-rt-common.h
View file @
1394f372
/* Code to insert inside the firmware:
#define NBR_CPUS xxx
#define CPU_IDX xxx
#define NBR_RULES xxx
#define NBR_DEVICES xxx
#define NBR_ALARMS xxx
#define DEVICES_NBR_CHS { xxx, 0, 0, 0}
#define DEVICES_CHS_DIR { WRTD_CH_DIR_IN, 0, 0, 0}
#define APP_ID WRTD_APP_xxx
#define APP_VER RT_VERSION(xxx, 0)
#define APP_NAME xxx
#define WRTD_NET_RX x // 1 = enabled, 0 = disabled
#define WRTD_NET_TX x
#define WRTD_LOCAL_RX x
#define WRTD_LOCAL_TX x
#include "wrtd-rt-common.h"
*/
/**
* @file wrtd-rt-common.h
*
* This is the common part that should be included
* by every WRTD firmware application.
*
* In order for it to work, the firmware application
* must declare the following definitions and includes:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* #define NBR_CPUS xxx
* #define CPU_IDX xxx
* #define NBR_RULES xxx
* #define NBR_DEVICES xxx
* #define NBR_ALARMS xxx
* #define DEVICES_NBR_CHS { xxx, 0, 0, 0}
* #define DEVICES_CHS_DIR { WRTD_CH_DIR_IN, 0, 0, 0}
* #define APP_ID WRTD_APP_xxx
* #define APP_VER RT_VERSION(xxx, 0)
* #define APP_NAME xxx
* #define WRTD_NET_RX x // 1 = enabled, 0 = disabled
* #define WRTD_NET_TX x
* #define WRTD_LOCAL_RX x
* #define WRTD_LOCAL_TX x
* #include "wrtd-rt-common.h"
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
/* Remote message queue for network. */
#define WRTD_RMQ 0
...
...
@@ -49,7 +61,7 @@ static struct wrtd_root root =
.
ver_major
=
WRTD_VERSION_MAJOR
,
.
ver_minor
=
WRTD_VERSION_MINOR
,
.
fw_id
=
APP_ID
,
.
fw_id
=
APP_ID
,
.
nbr_devices
=
NBR_DEVICES
,
.
nbr_alarms
=
NBR_ALARMS
,
...
...
@@ -73,7 +85,7 @@ static struct wrtd_root root =
static
inline
int
wr_is_timing_ok
(
void
)
{
return
(
root
.
wr_state
==
WR_LINK_SYNCED
);
return
(
root
.
wr_state
==
WR_LINK_SYNCED
);
}
/**
...
...
@@ -81,41 +93,41 @@ static inline int wr_is_timing_ok(void)
*/
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
(
"sync detected, waiting for plumbing to catch up...
\n\r
"
);
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
(
"sync detected, waiting for 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
}
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
(
"WR 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
(
"WR sync lost
\n\r
"
);
root
.
wr_state
=
WR_LINK_OFFLINE
;
wr_enable_lock
(
0
);
}
pr_debug
(
"WR 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
(
"WR sync lost
\n\r
"
);
root
.
wr_state
=
WR_LINK_OFFLINE
;
wr_enable_lock
(
0
);
}
}
#if NBR_CPUS > 1
...
...
@@ -168,8 +180,8 @@ static void wrtd_recv_loopback(void)
volatile
struct
loopback_queue
*
q
=
&
lqueues
[
CPU_IDX
];
volatile
struct
wrtd_loopback_event
*
e
;
if
(
q
->
count
==
0
)
return
;
/* No entry */
if
(
q
->
count
==
0
)
return
;
/* No entry */
e
=
&
q
->
buf
[
q
->
read_idx
];
...
...
@@ -181,14 +193,14 @@ static void wrtd_recv_loopback(void)
wrtd_local_output
((
struct
wrtd_event
*
)
&
e
->
ev
,
e
->
ch
);
q
->
read_idx
=
(
q
->
read_idx
+
1
)
&
(
LOOPBACK_QUEUE_SIZE
-
1
);
smem_atomic_add
(
&
q
->
count
,
-
1
);
smem_atomic_add
(
&
q
->
count
,
-
1
);
}
#endif
#endif
// NBR_CPUS
static
inline
void
ts_add2_ns
(
struct
wrtd_tstamp
*
ts
,
uint32_t
ns
)
{
ts
->
ns
+=
ns
;
if
(
ts
->
ns
>=
1000000000
)
{
if
(
ts
->
ns
>=
1000000000
)
{
ts
->
ns
-=
1000000000
;
ts
->
seconds
++
;
}
...
...
@@ -200,7 +212,7 @@ static inline void ts_add3_ns(struct wrtd_tstamp *dest,
dest
->
seconds
=
src
->
seconds
;
dest
->
ns
=
src
->
ns
+
ns
;
dest
->
frac
=
src
->
frac
;
if
(
dest
->
ns
>=
1000000000
)
{
if
(
dest
->
ns
>=
1000000000
)
{
dest
->
ns
-=
1000000000
;
dest
->
seconds
++
;
}
...
...
@@ -225,10 +237,10 @@ static inline int ts_cmp(const struct wrtd_tstamp *l, const struct wrtd_tstamp *
static
void
ts_now
(
struct
wrtd_tstamp
*
now
)
{
/*
* Read the current WR time, order is important: first seconds,
* then cycles (cycles get latched on reading secs register).
*/
/*
* Read the current WR time, order is important: first seconds,
* then cycles (cycles get latched on reading secs register).
*/
now
->
seconds
=
lr_readl
(
MT_CPU_LR_REG_TAI_SEC
);
now
->
ns
=
lr_readl
(
MT_CPU_LR_REG_TAI_CYCLES
)
*
8
;
now
->
frac
=
0
;
...
...
@@ -241,7 +253,6 @@ static void wrtd_log(uint32_t type, uint32_t reason,
{
struct
wrtd_log_entry
*
log
;
struct
trtl_fw_msg
msg
;
struct
wrtd_tstamp
now
;
int
ret
;
/* First, handle statistics */
...
...
@@ -270,32 +281,30 @@ static void wrtd_log(uint32_t type, uint32_t reason,
return
;
}
ret
=
mq_claim
(
TRTL_HMQ
,
WRTD_HMQ
);
if
(
ret
==
-
EBUSY
)
{
ret
=
mq_claim
(
TRTL_HMQ
,
WRTD_HMQ
);
if
(
ret
==
-
EBUSY
)
{
root
.
log_nbr_busy
++
;
return
;
return
;
}
if
(
ts
==
NULL
)
ts_now
(
&
now
);
else
now
=
*
ts
;
mq_map_out_message
(
TRTL_HMQ
,
WRTD_HMQ
,
&
msg
);
msg
.
header
->
flags
=
0
;
msg
.
header
->
msg_id
=
WRTD_ACTION_LOG
;
msg
.
header
->
len
=
sizeof
(
struct
wrtd_log_entry
)
/
4
;
msg
.
header
->
flags
=
0
;
msg
.
header
->
msg_id
=
WRTD_ACTION_LOG
;
msg
.
header
->
len
=
sizeof
(
struct
wrtd_log_entry
)
/
4
;
log
=
(
struct
wrtd_log_entry
*
)
msg
.
payload
;
log
->
type
=
type
;
log
=
(
struct
wrtd_log_entry
*
)
msg
.
payload
;
log
->
type
=
type
;
log
->
reason
=
reason
;
if
(
ev
!=
NULL
)
log
->
event
=
*
ev
;
else
memset
(
&
log
->
event
,
0
,
sizeof
(
struct
wrtd_event
));
log
->
ts
=
now
;
if
(
ts
!=
NULL
)
log
->
ts
=
*
ts
;
else
memset
(
&
log
->
ts
,
0
,
sizeof
(
struct
wrtd_tstamp
));
mq_send
(
TRTL_HMQ
,
WRTD_HMQ
);
...
...
@@ -305,17 +314,17 @@ static void wrtd_log(uint32_t type, uint32_t reason,
#if WRTD_NET_TX > 0
static
void
wrtd_init_tx
(
void
)
{
static
const
struct
trtl_ep_eth_address
addr
=
{
.
type
=
TRTL_EP_FRAME_UDP
,
.
dst_mac
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
},
.
dst_ip
=
0xFFFFFFFF
,
/* broadcast on 255.255.255.255 */
.
src_ip
=
0xC0A85A11
,
.
dst_port
=
WRTD_UDP_PORT
,
.
src_port
=
WRTD_UDP_PORT
,
.
ethertype
=
0x800
,
/* IPv4 */
.
filter
=
0
/* only the TX path of the endpoint is used */
};
rmq_bind_out
(
WRTD_RMQ
,
TRTL_EP_ETH
,
&
addr
);
static
const
struct
trtl_ep_eth_address
addr
=
{
.
type
=
TRTL_EP_FRAME_UDP
,
.
dst_mac
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
},
.
dst_ip
=
0xFFFFFFFF
,
/* broadcast on 255.255.255.255 */
.
src_ip
=
0xC0A85A11
,
.
dst_port
=
WRTD_UDP_PORT
,
.
src_port
=
WRTD_UDP_PORT
,
.
ethertype
=
0x800
,
/* IPv4 */
.
filter
=
0
/* only the TX path of the endpoint is used */
};
rmq_bind_out
(
WRTD_RMQ
,
TRTL_EP_ETH
,
&
addr
);
}
static
int
wrtd_send_network
(
struct
wrtd_event
*
ev
)
...
...
@@ -357,7 +366,7 @@ static int wrtd_send_network(struct wrtd_event *ev)
return
0
;
}
#endif
#endif
// WRTD_NET_TX
static
void
wrtd_route
(
struct
wrtd_rule
*
rule
,
const
struct
wrtd_event
*
ev
)
{
...
...
@@ -365,12 +374,8 @@ static void wrtd_route(struct wrtd_rule *rule, const struct wrtd_event *ev)
struct
wrtd_tstamp
now
;
uint32_t
lat_ns
;
/* Event was received. */
rule
->
stat
.
rx_events
++
;
rule
->
stat
.
rx_last
=
ev
->
ts
;
/* Check hold-off.
Note: this also exclude events that came before the last
Note: this also exclude
s
events that came before the last
one. */
if
(
rule
->
conf
.
hold_off_ns
)
{
if
(
ts_cmp
(
&
ev
->
ts
,
&
rule
->
stat
.
hold_off
)
<
0
)
{
...
...
@@ -385,14 +390,18 @@ static void wrtd_route(struct wrtd_rule *rule, const struct wrtd_event *ev)
&
ev
->
ts
,
rule
->
conf
.
hold_off_ns
);
}
/* Event was received. */
rule
->
stat
.
rx_events
++
;
rule
->
stat
.
rx_last
=
ev
->
ts
;
ts_now
(
&
now
);
/* Compute latency. */
do
{
lat_ns
=
now
.
ns
-
ev
->
ts
.
ns
;
if
(
lat_ns
>>
31
)
{
/* Result is negati
f, possible only if differ by
1 sec. */
/* Result is negati
ve, possible only if
timestamps differ by
1 sec. */
if
(
ev
->
ts
.
seconds
+
1
==
now
.
seconds
)
lat_ns
+=
1000000000
;
else
...
...
@@ -521,24 +530,24 @@ static void wrtd_route_in(struct wrtd_event *ev)
#if WRTD_NET_RX > 0
static
void
wrtd_init_rx
(
void
)
{
static
const
struct
trtl_ep_eth_address
addr
=
{
.
type
=
TRTL_EP_FRAME_UDP
,
.
dst_mac
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
},
.
dst_port
=
WRTD_UDP_PORT
,
.
ethertype
=
0x800
,
/* IPv4 */
.
filter
=
(
TRTL_EP_FILTER_UDP
static
const
struct
trtl_ep_eth_address
addr
=
{
.
type
=
TRTL_EP_FRAME_UDP
,
.
dst_mac
=
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
},
.
dst_port
=
WRTD_UDP_PORT
,
.
ethertype
=
0x800
,
/* IPv4 */
.
filter
=
(
TRTL_EP_FILTER_UDP
|
TRTL_EP_FILTER_DST_PORT
|
TRTL_EP_FILTER_ENABLE
)
};
rmq_bind_in
(
WRTD_RMQ
,
TRTL_EP_ETH
,
&
addr
);
};
rmq_bind_in
(
WRTD_RMQ
,
TRTL_EP_ETH
,
&
addr
);
}
static
void
wrtd_recv_network
(
void
)
{
volatile
struct
wrtd_message
*
msg
;
volatile
struct
wrtd_message
*
msg
;
struct
wrtd_event
ev
;
if
(
!
mq_poll_in
(
TRTL_RMQ
,
1
<<
WRTD_RMQ
))
{
if
(
!
mq_poll_in
(
TRTL_RMQ
,
1
<<
WRTD_RMQ
))
{
/* No packet. */
return
;
}
...
...
@@ -559,7 +568,7 @@ static void wrtd_recv_network(void)
wrtd_route_in
(
&
ev
);
}
#endif
#endif
//WRTD_NET_RX
#if NBR_ALARMS > 0
static
void
wrtd_alarms
(
void
)
...
...
@@ -601,7 +610,7 @@ static void wrtd_alarms(void)
ts_add2_ns
(
&
al
->
event
.
ts
,
al
->
period_ns
);
}
}
#endif
#endif
// NBR_ALARMS
static
int
wrtd_action_readw
(
struct
trtl_fw_msg
*
msg_i
,
struct
trtl_fw_msg
*
msg_o
)
...
...
@@ -612,9 +621,9 @@ static int wrtd_action_readw(struct trtl_fw_msg *msg_i,
uint32_t
len
;
unsigned
int
i
;
/* Verify that the size is correct */
if
(
msg_i
->
header
->
len
!=
sizeof
(
struct
wrtd_io_msg
)
/
4
)
return
-
EINVAL
;
/* Verify that the size is correct */
if
(
msg_i
->
header
->
len
!=
sizeof
(
struct
wrtd_io_msg
)
/
4
)
return
-
EINVAL
;
imsg
=
(
volatile
struct
wrtd_io_msg
*
)
msg_i
->
payload
;
odata
=
(
volatile
uint32_t
*
)
msg_o
->
payload
;
...
...
@@ -631,7 +640,6 @@ static int wrtd_action_readw(struct trtl_fw_msg *msg_i,
return
0
;
}
static
int
wrtd_action_writew
(
struct
trtl_fw_msg
*
msg_i
,
struct
trtl_fw_msg
*
msg_o
)
{
...
...
@@ -640,9 +648,9 @@ static int wrtd_action_writew(struct trtl_fw_msg *msg_i,
uint32_t
len
;
unsigned
int
i
;
/* Verify that the size is correct */
if
(
msg_i
->
header
->
len
*
4
<
sizeof
(
uint32_t
))
return
-
EINVAL
;
/* Verify that the size is correct */
if
(
msg_i
->
header
->
len
*
4
<
sizeof
(
uint32_t
))
return
-
EINVAL
;
idata
=
(
volatile
uint32_t
*
)
msg_i
->
payload
;
addr
=
(
volatile
uint32_t
*
)
idata
[
0
];
...
...
@@ -658,15 +666,14 @@ static int wrtd_action_writew(struct trtl_fw_msg *msg_i,
return
0
;
}
static
int
wrtd_action_get_config
(
struct
trtl_fw_msg
*
msg_i
,
struct
trtl_fw_msg
*
msg_o
)
{
struct
wrtd_config_msg
*
cfg
;
/* Verify that the size is correct */
if
(
msg_i
->
header
->
len
*
4
!=
0
)
return
-
EINVAL
;
/* Verify that the size is correct */
if
(
msg_i
->
header
->
len
*
4
!=
0
)
return
-
EINVAL
;
cfg
=
(
struct
wrtd_config_msg
*
)
msg_o
->
payload
;
cfg
->
root_addr
=
(
uint32_t
)
&
root
;
...
...
@@ -678,7 +685,6 @@ static int wrtd_action_get_config(struct trtl_fw_msg *msg_i,
return
0
;
}
static
trtl_fw_action_t
*
wrtd_actions
[]
=
{
[
WRTD_ACTION_GET_CONFIG
]
=
wrtd_action_get_config
,
[
WRTD_ACTION_READW
]
=
wrtd_action_readw
,
...
...
@@ -687,7 +693,7 @@ static trtl_fw_action_t *wrtd_actions[] = {
static
int
wrtd_main
(
void
)
{
while
(
1
)
{
while
(
1
)
{
if
(
!
root
.
freeze_flag
)
{
wrtd_io
();
#if WRTD_NET_RX > 0
...
...
@@ -701,11 +707,11 @@ static int wrtd_main(void)
wrtd_alarms
();
#endif
}
trtl_fw_mq_action_dispatch
(
TRTL_HMQ
,
WRTD_HMQ
);
wr_update_link
();
}
trtl_fw_mq_action_dispatch
(
TRTL_HMQ
,
WRTD_HMQ
);
wr_update_link
();
}
return
0
;
return
0
;
}
static
int
wrtd_sys_init
(
void
)
...
...
@@ -722,17 +728,17 @@ static int wrtd_sys_init(void)
}
struct
trtl_fw_application
app
=
{
.
name
=
APP_NAME
,
.
version
=
{
.
name
=
APP_NAME
,
.
version
=
{
.
rt_id
=
APP_ID
,
.
rt_version
=
APP_VER
,
.
git_version
=
GIT_VERSION
},
.
rt_version
=
APP_VER
,
.
git_version
=
GIT_VERSION
},
.
actions
=
wrtd_actions
,
.
n_actions
=
ARRAY_SIZE
(
wrtd_actions
),
.
actions
=
wrtd_actions
,
.
n_actions
=
ARRAY_SIZE
(
wrtd_actions
),
.
init
=
wrtd_sys_init
,
.
main
=
wrtd_main
,
.
exit
=
NULL
,
.
init
=
wrtd_sys_init
,
.
main
=
wrtd_main
,
.
exit
=
NULL
,
};
software/firmware/fd/configs/mt_defconfig
View file @
1394f372
#
# Automatically generated file; DO NOT EDIT.
# fmc-svec-carrier fw-01 demo configuration
#
#
...
...
software/firmware/fd/fd-acam.c
View file @
1394f372
/*
/**
* @file fd_acam.c
*
* Accessing the ACAM chip and configuring it.
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
* Author: Dimitris Lampridis <dimitris.lampridis@cern.ch>
*
* Copyright (c) 2012-2019 CERN (home.cern)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "mockturtle-rt.h"
...
...
@@ -23,312 +24,314 @@
* We know the bin is small, but the Tref is several nanos so we need 64 bits
* (although our current values fit in 32 bits after the division)
*/
#define ACAM_FP_BIN
((int)(ACAM_DESIRED_BIN * (1 << 16)))
#define ACAM_FP_TREF
(((1000LL * 1000 * 1000) << 16) / ACAM_CLOCK_FREQ_KHZ)
#define ACAM_FP_BIN
((int)(ACAM_DESIRED_BIN * (1 << 16)))
#define ACAM_FP_TREF
(((1000LL * 1000 * 1000) << 16) / ACAM_CLOCK_FREQ_KHZ)
/* Default values of control registers for the ACAM TDC working in G-Mode
(eeprom values are obsolete) */
#define ACAM_GMODE_START_OFFSET
10000
#define ACAM_GMODE_ASOR
17000
#define ACAM_GMODE_ATMCR
(26 | (1500 << 8))
#define ACAM_GMODE_ADSFR
84977
#define ACAM_GMODE_START_OFFSET
10000
#define ACAM_GMODE_ASOR
17000
#define ACAM_GMODE_ATMCR
(26 | (1500 << 8))
#define ACAM_GMODE_ADSFR
84977
static
int
acam_calc_pll
(
uint64_t
tref
,
int
bin
,
int
*
hsdiv_out
,
int
*
refdiv_out
)
int
*
refdiv_out
)
{
uint64_t
tmpll
;
int
x
,
refdiv
,
hsdiv
;
/*
* Tbin(I-mode) = (Tref << refdiv) / (216 * hsdiv)
*
* so, calling X the value "hsdiv >> refdiv" we have
*
* X = Tref / (216 * Tbin)
*
* Then, we can choose refdiv == 7 to have the best bits,
* and then shift out the zeros to get smaller values.
*
*/
if
(
0
)
{
x
=
(
tref
<<
16
)
/
216
/
bin
;
//printf("x = %lf\n", (double)x / (1<<16));
}
else
{
/* We can't divide 64 bits in kernel space */
tmpll
=
div_u64
(
tref
<<
16
,
216
);
x
=
div_u64
(
tmpll
,
bin
);
}
/* Now, shift out the max bits (usually 7) and drop decimal part */
refdiv
=
ACAM_MAX_REFDIV
;
hsdiv
=
(
x
<<
refdiv
)
>>
16
;
/* Check the first decimal bit and approximate */
if
((
x
<<
refdiv
)
&
(
1
<<
15
))
hsdiv
++
;
/* until we have zeroes as LSB, shift out to decrease pll quotient */
while
(
refdiv
>
0
&&
!
(
hsdiv
&
1
))
{
refdiv
--
;
hsdiv
>>=
1
;
}
*
hsdiv_out
=
hsdiv
;
*
refdiv_out
=
refdiv
;
/* Finally, calculate what we really have */
if
(
0
)
{
bin
=
(
tref
<<
refdiv
)
/
216
/
hsdiv
;
}
else
{
tmpll
=
div_u64
(
tref
<<
refdiv
,
216
);
bin
=
div_u64
(
tmpll
,
hsdiv
);
}
return
(
bin
+
1
);
/* We always return the bin size in the I mode. Other modes should scale it appropriately. */
uint64_t
tmpll
;
int
x
,
refdiv
,
hsdiv
;
/*
* Tbin(I-mode) = (Tref << refdiv) / (216 * hsdiv)
*
* so, calling X the value "hsdiv >> refdiv" we have
*
* X = Tref / (216 * Tbin)
*
* Then, we can choose refdiv == 7 to have the best bits,
* and then shift out the zeros to get smaller values.
*
*/
if
(
0
)
{
x
=
(
tref
<<
16
)
/
216
/
bin
;
//printf("x = %lf\n", (double)x / (1<<16));
}
else
{
/* We can't divide 64 bits in kernel space */
tmpll
=
div_u64
(
tref
<<
16
,
216
);
x
=
div_u64
(
tmpll
,
bin
);
}
/* Now, shift out the max bits (usually 7) and drop decimal part */
refdiv
=
ACAM_MAX_REFDIV
;
hsdiv
=
(
x
<<
refdiv
)
>>
16
;
/* Check the first decimal bit and approximate */
if
((
x
<<
refdiv
)
&
(
1
<<
15
))
hsdiv
++
;
/* until we have zeroes as LSB, shift out to decrease pll quotient */
while
(
refdiv
>
0
&&
!
(
hsdiv
&
1
))
{
refdiv
--
;
hsdiv
>>=
1
;
}
*
hsdiv_out
=
hsdiv
;
*
refdiv_out
=
refdiv
;
/* Finally, calculate what we really have */
if
(
0
)
{
bin
=
(
tref
<<
refdiv
)
/
216
/
hsdiv
;
}
else
{
tmpll
=
div_u64
(
tref
<<
refdiv
,
216
);
bin
=
div_u64
(
tmpll
,
hsdiv
);
}
/* We always return the bin size in the I mode.
Other modes should scale it appropriately. */
return
(
bin
+
1
);
}
static
void
acam_set_address
(
struct
wrtd_fd_dev
*
fd
,
int
addr
)
{
if
(
fd
->
fd_acam_addr
==
addr
)
return
;
if
(
fd
->
fd_acam_addr
==
addr
)
return
;
if
(
fd
->
fd_acam_addr
==
-
1
)
{
/* first time */
if
(
fd
->
fd_acam_addr
==
-
1
)
{
/* first time */
fd_gpio_dir
(
fd
,
0xf00
,
FD_GPIO_OUT
);
}
fd_gpio_val
(
fd
,
0xf00
,
addr
<<
8
);
fd
->
fd_acam_addr
=
addr
;
}
fd_gpio_val
(
fd
,
0xf00
,
addr
<<
8
);
fd
->
fd_acam_addr
=
addr
;
}
/* Warning: acam_readl and acam_writel only work if GCR.BYPASS is set */
uint32_t
acam_readl
(
struct
wrtd_fd_dev
*
fd
,
int
reg
)
{
acam_set_address
(
fd
,
reg
);
fd_writel
(
fd
,
FD_TDCSR_READ
,
FD_REG_TDCSR
);
return
fd_readl
(
fd
,
FD_REG_TDR
)
&
ACAM_MASK
;
acam_set_address
(
fd
,
reg
);
fd_writel
(
fd
,
FD_TDCSR_READ
,
FD_REG_TDCSR
);
return
fd_readl
(
fd
,
FD_REG_TDR
)
&
ACAM_MASK
;
}
void
acam_writel
(
struct
wrtd_fd_dev
*
fd
,
int
val
,
int
reg
)
{
acam_set_address
(
fd
,
reg
);
fd_writel
(
fd
,
val
,
FD_REG_TDR
);
fd_writel
(
fd
,
FD_TDCSR_WRITE
,
FD_REG_TDCSR
);
acam_set_address
(
fd
,
reg
);
fd_writel
(
fd
,
val
,
FD_REG_TDR
);
fd_writel
(
fd
,
FD_TDCSR_WRITE
,
FD_REG_TDCSR
);
}
static
void
acam_set_bypass
(
struct
wrtd_fd_dev
*
fd
,
int
on
)
{
/* warning: this clears the "input enable" bit: call at init only */
fd_writel
(
fd
,
on
?
FD_GCR_BYPASS
:
0
,
FD_REG_GCR
);
/* warning: this clears the "input enable" bit: call at init only */
fd_writel
(
fd
,
on
?
FD_GCR_BYPASS
:
0
,
FD_REG_GCR
);
}
static
inline
int
acam_is_pll_locked
(
struct
wrtd_fd_dev
*
fd
)
{
return
!
(
acam_readl
(
fd
,
12
)
&
AR12_NotLocked
);
return
!
(
acam_readl
(
fd
,
12
)
&
AR12_NotLocked
);
}
/* Two test functions to verify the bus is working -- Tom */
static
int
acam_test_addr_bit
(
struct
wrtd_fd_dev
*
fd
,
int
base
,
int
bit
,
int
data
)
{
int
addr1
=
base
;
int
addr2
=
base
+
(
1
<<
bit
);
int
reg
;
reg
=
acam_readl
(
fd
,
addr1
)
&
~
data
;
acam_writel
(
fd
,
reg
,
addr1
);
/* zero the data mask */
reg
=
acam_readl
(
fd
,
addr2
)
|
data
;
acam_writel
(
fd
,
reg
,
addr2
);
/* set the data mask */
if
((
acam_readl
(
fd
,
addr1
)
&
data
)
!=
0
)
goto
out
;
if
((
acam_readl
(
fd
,
addr2
)
&
data
)
!=
data
)
goto
out
;
/* the other way around */
reg
=
acam_readl
(
fd
,
addr2
)
&
~
data
;
acam_writel
(
fd
,
reg
,
addr2
);
/* zero the data mask */
reg
=
acam_readl
(
fd
,
addr1
)
|
data
;
acam_writel
(
fd
,
reg
,
addr1
);
/* set the data mask */
if
((
acam_readl
(
fd
,
addr2
)
&
data
)
!=
0
)
goto
out
;
if
((
acam_readl
(
fd
,
addr1
)
&
data
)
!=
data
)
goto
out
;
return
0
;
int
addr1
=
base
;
int
addr2
=
base
+
(
1
<<
bit
);
int
reg
;
reg
=
acam_readl
(
fd
,
addr1
)
&
~
data
;
acam_writel
(
fd
,
reg
,
addr1
);
/* zero the data mask */
reg
=
acam_readl
(
fd
,
addr2
)
|
data
;
acam_writel
(
fd
,
reg
,
addr2
);
/* set the data mask */
if
((
acam_readl
(
fd
,
addr1
)
&
data
)
!=
0
)
goto
out
;
if
((
acam_readl
(
fd
,
addr2
)
&
data
)
!=
data
)
goto
out
;
/* the other way around */
reg
=
acam_readl
(
fd
,
addr2
)
&
~
data
;
acam_writel
(
fd
,
reg
,
addr2
);
/* zero the data mask */
reg
=
acam_readl
(
fd
,
addr1
)
|
data
;
acam_writel
(
fd
,
reg
,
addr1
);
/* set the data mask */
if
((
acam_readl
(
fd
,
addr2
)
&
data
)
!=
0
)
goto
out
;
if
((
acam_readl
(
fd
,
addr1
)
&
data
)
!=
data
)
goto
out
;
return
0
;
out:
pr_error
(
"ACAM address bit %d failure
\n
"
,
bit
);
return
-
EIO
;
pr_error
(
"ACAM address bit %d failure
\n
"
,
bit
);
return
-
EIO
;
}
static
int
acam_test_bus
(
struct
wrtd_fd_dev
*
fd
)
{
int
err
=
0
,
i
,
v
;
/* Use register 5 to checke the data bits */
for
(
i
=
0
;
i
&
ACAM_MASK
;
i
<<=
1
)
{
acam_writel
(
fd
,
i
,
5
);
acam_readl
(
fd
,
0
);
v
=
acam_readl
(
fd
,
5
);
if
(
v
!=
i
)
goto
out
;
acam_writel
(
fd
,
~
i
&
ACAM_MASK
,
5
);
acam_readl
(
fd
,
0
);
v
=
acam_readl
(
fd
,
5
);
if
(
v
!=
(
~
i
&
ACAM_MASK
))
goto
out
;
}
err
+=
acam_test_addr_bit
(
fd
,
0
,
0
,
0x000001
);
err
+=
acam_test_addr_bit
(
fd
,
1
,
1
,
0x000008
);
err
+=
acam_test_addr_bit
(
fd
,
0
,
2
,
0x000001
);
err
+=
acam_test_addr_bit
(
fd
,
3
,
3
,
0x010000
);
if
(
err
)
return
-
EIO
;
return
0
;
int
err
=
0
,
i
,
v
;
/* Use register 5 to checke the data bits */
for
(
i
=
0
;
i
&
ACAM_MASK
;
i
<<=
1
)
{
acam_writel
(
fd
,
i
,
5
);
acam_readl
(
fd
,
0
);
v
=
acam_readl
(
fd
,
5
);
if
(
v
!=
i
)
goto
out
;
acam_writel
(
fd
,
~
i
&
ACAM_MASK
,
5
);
acam_readl
(
fd
,
0
);
v
=
acam_readl
(
fd
,
5
);
if
(
v
!=
(
~
i
&
ACAM_MASK
))
goto
out
;
}
err
+=
acam_test_addr_bit
(
fd
,
0
,
0
,
0x000001
);
err
+=
acam_test_addr_bit
(
fd
,
1
,
1
,
0x000008
);
err
+=
acam_test_addr_bit
(
fd
,
0
,
2
,
0x000001
);
err
+=
acam_test_addr_bit
(
fd
,
3
,
3
,
0x010000
);
if
(
err
)
return
-
EIO
;
return
0
;
out:
pp_printf
(
"Error: ACAM data bit 0x%06x failure
\n
"
,
i
);
return
-
EIO
;
pp_printf
(
"Error: ACAM data bit 0x%06x failure
\n
"
,
i
);
return
-
EIO
;
}
/* We need to write come static configuration in the registers */
struct
acam_init_data
{
int
addr
;
int
val
;
int
addr
;
int
val
;
};
/* Commented values are not constant, they are added at runtime (see later) */
static
struct
acam_init_data
acam_init_regs_gmode
[]
=
{
{
0
,
AR0_ROsc
|
AR0_RiseEn0
|
AR0_RiseEn1
|
AR0_HQSel
},
{
1
,
AR1_Adj
(
0
,
0
)
|
AR1_Adj
(
1
,
0
)
|
AR1_Adj
(
2
,
5
)
|
AR1_Adj
(
3
,
0
)
|
AR1_Adj
(
4
,
5
)
|
AR1_Adj
(
5
,
0
)
|
AR1_Adj
(
6
,
5
)},
{
2
,
AR2_GMode
|
AR2_Adj
(
7
,
0
)
|
AR2_Adj
(
8
,
5
)
|
AR2_DelRise1
(
0
)
|
AR2_DelFall1
(
0
)
|
AR2_DelRise2
(
0
)
|
AR2_DelFall2
(
0
)},
{
3
,
AR3_DelTx
(
1
,
3
)
|
AR3_DelTx
(
2
,
3
)
|
AR3_DelTx
(
3
,
3
)
|
AR3_DelTx
(
4
,
3
)
|
AR3_DelTx
(
5
,
3
)
|
AR3_DelTx
(
6
,
3
)
|
AR3_DelTx
(
7
,
3
)
|
AR3_DelTx
(
8
,
3
)
|
AR3_RaSpeed
(
0
,
3
)
|
AR3_RaSpeed
(
1
,
3
)
|
AR3_RaSpeed
(
2
,
3
)},
{
4
,
AR4_EFlagHiZN
|
AR4_RaSpeed
(
3
,
3
)
|
AR4_RaSpeed
(
4
,
3
)
|
AR4_RaSpeed
(
5
,
3
)
|
AR4_RaSpeed
(
6
,
3
)
|
AR4_RaSpeed
(
7
,
3
)
|
AR4_RaSpeed
(
8
,
3
)},
{
5
,
AR5_StartRetrig
|
0
/* AR5_StartOff1(hw->calib.acam_start_offset) */
|
AR5_MasterAluTrig
},
{
6
,
AR6_Fill
(
200
)
|
AR6_PowerOnECL
},
{
7
,
/* AR7_HSDiv(hsdiv) | AR7_RefClkDiv(refdiv) */
0
|
AR7_ResAdj
|
AR7_NegPhase
},
{
11
,
0x7ff0000
},
{
12
,
0x0000000
},
{
14
,
0
},
/* finally, reset */
{
4
,
AR4_EFlagHiZN
|
AR4_MasterReset
|
AR4_StartTimer
(
0
)},
{
0
,
AR0_ROsc
|
AR0_RiseEn0
|
AR0_RiseEn1
|
AR0_HQSel
},
{
1
,
AR1_Adj
(
0
,
0
)
|
AR1_Adj
(
1
,
0
)
|
AR1_Adj
(
2
,
5
)
|
AR1_Adj
(
3
,
0
)
|
AR1_Adj
(
4
,
5
)
|
AR1_Adj
(
5
,
0
)
|
AR1_Adj
(
6
,
5
)},
{
2
,
AR2_GMode
|
AR2_Adj
(
7
,
0
)
|
AR2_Adj
(
8
,
5
)
|
AR2_DelRise1
(
0
)
|
AR2_DelFall1
(
0
)
|
AR2_DelRise2
(
0
)
|
AR2_DelFall2
(
0
)},
{
3
,
AR3_DelTx
(
1
,
3
)
|
AR3_DelTx
(
2
,
3
)
|
AR3_DelTx
(
3
,
3
)
|
AR3_DelTx
(
4
,
3
)
|
AR3_DelTx
(
5
,
3
)
|
AR3_DelTx
(
6
,
3
)
|
AR3_DelTx
(
7
,
3
)
|
AR3_DelTx
(
8
,
3
)
|
AR3_RaSpeed
(
0
,
3
)
|
AR3_RaSpeed
(
1
,
3
)
|
AR3_RaSpeed
(
2
,
3
)},
{
4
,
AR4_EFlagHiZN
|
AR4_RaSpeed
(
3
,
3
)
|
AR4_RaSpeed
(
4
,
3
)
|
AR4_RaSpeed
(
5
,
3
)
|
AR4_RaSpeed
(
6
,
3
)
|
AR4_RaSpeed
(
7
,
3
)
|
AR4_RaSpeed
(
8
,
3
)},
{
5
,
AR5_StartRetrig
|
0
/* AR5_StartOff1(hw->calib.acam_start_offset) */
|
AR5_MasterAluTrig
},
{
6
,
AR6_Fill
(
200
)
|
AR6_PowerOnECL
},
{
7
,
/* AR7_HSDiv(hsdiv) | AR7_RefClkDiv(refdiv) */
0
|
AR7_ResAdj
|
AR7_NegPhase
},
{
11
,
0x7ff0000
},
{
12
,
0x0000000
},
{
14
,
0
},
/* finally, reset */
{
4
,
AR4_EFlagHiZN
|
AR4_MasterReset
|
AR4_StartTimer
(
0
)},
};
static
struct
acam_init_data
acam_init_regs_imode
[]
=
{
{
0
,
AR0_TRiseEn
(
0
)
|
AR0_HQSel
|
AR0_ROsc
},
{
2
,
AR2_IMode
},
{
5
,
AR5_StartOff1
(
3000
)
|
AR5_MasterAluTrig
},
{
6
,
0
},
{
7
,
/* AR7_HSDiv(hsdiv) | AR7_RefClkDiv(refdiv) */
0
|
AR7_ResAdj
|
AR7_NegPhase
},
{
11
,
0x7ff0000
},
{
12
,
0x0000000
},
{
14
,
0
},
/* finally, reset */
{
4
,
AR4_EFlagHiZN
|
AR4_MasterReset
|
AR4_StartTimer
(
0
)},
{
0
,
AR0_TRiseEn
(
0
)
|
AR0_HQSel
|
AR0_ROsc
},
{
2
,
AR2_IMode
},
{
5
,
AR5_StartOff1
(
3000
)
|
AR5_MasterAluTrig
},
{
6
,
0
},
{
7
,
/* AR7_HSDiv(hsdiv) | AR7_RefClkDiv(refdiv) */
0
|
AR7_ResAdj
|
AR7_NegPhase
},
{
11
,
0x7ff0000
},
{
12
,
0x0000000
},
{
14
,
0
},
/* finally, reset */
{
4
,
AR4_EFlagHiZN
|
AR4_MasterReset
|
AR4_StartTimer
(
0
)},
};
static
int
acam_configure
(
struct
wrtd_fd_dev
*
fd
,
enum
fd_acam_modes
mode
,
const
struct
acam_init_data
*
regs
,
int
n_regs
)
{
int
i
,
hsdiv
,
refdiv
,
reg7val
;
const
struct
acam_init_data
*
p
;
uint32_t
regval
;
int
locked
=
0
;
int
i
,
hsdiv
,
refdiv
,
reg7val
;
const
struct
acam_init_data
*
p
;
uint32_t
regval
;
int
locked
=
0
;
fd
->
fd_bin_size
=
acam_calc_pll
(
ACAM_FP_TREF
,
ACAM_FP_BIN
,
fd
->
fd_bin_size
=
acam_calc_pll
(
ACAM_FP_TREF
,
ACAM_FP_BIN
,
&
hsdiv
,
&
refdiv
);
reg7val
=
AR7_HSDiv
(
hsdiv
)
|
AR7_RefClkDiv
(
refdiv
);
reg7val
=
AR7_HSDiv
(
hsdiv
)
|
AR7_RefClkDiv
(
refdiv
);
pr_debug
(
"ACAM config: mode %d bin 0x%x, hsdiv %i, refdiv %i
\n
"
,
pr_debug
(
"ACAM config: mode %d bin 0x%x, hsdiv %i, refdiv %i
\n
"
,
mode
,
fd
->
fd_bin_size
,
hsdiv
,
refdiv
);
/* Disable TDC inputs prior to configuring */
fd_writel
(
fd
,
FD_TDCSR_STOP_DIS
|
FD_TDCSR_START_DIS
,
FD_REG_TDCSR
);
/* Disable the ACAM PLL for a while to make sure it is reset */
acam_writel
(
fd
,
0
,
0
);
acam_writel
(
fd
,
7
,
0
);
mdelay
(
100
);
for
(
p
=
regs
,
i
=
0
;
i
<
n_regs
;
p
++
,
i
++
)
{
regval
=
p
->
val
;
if
(
p
->
addr
==
7
)
regval
|=
reg7val
;
if
(
p
->
addr
==
5
&&
mode
==
ACAM_GMODE
)
regval
|=
AR5_StartOff1
(
ACAM_GMODE_START_OFFSET
);
if
(
p
->
addr
==
6
&&
mode
==
ACAM_GMODE
)
regval
|=
AR6_StartOff2
(
ACAM_GMODE_START_OFFSET
);
acam_writel
(
fd
,
regval
,
p
->
addr
);
}
for
(
i
=
0
;
i
<
20
;
i
++
)
{
if
(
acam_is_pll_locked
(
fd
))
{
locked
=
1
;
break
;
}
mdelay
(
100
);
}
if
(
!
locked
)
{
pp_printf
(
"Error: ACAM PLL doesn't lock.
\n
"
);
return
-
1
;
}
/* after config, set the FIFO address for further reads */
acam_set_address
(
fd
,
8
);
return
0
;
/* Disable TDC inputs prior to configuring */
fd_writel
(
fd
,
FD_TDCSR_STOP_DIS
|
FD_TDCSR_START_DIS
,
FD_REG_TDCSR
);
/* Disable the ACAM PLL for a while to make sure it is reset */
acam_writel
(
fd
,
0
,
0
);
acam_writel
(
fd
,
7
,
0
);
mdelay
(
100
);
for
(
p
=
regs
,
i
=
0
;
i
<
n_regs
;
p
++
,
i
++
)
{
regval
=
p
->
val
;
if
(
p
->
addr
==
7
)
regval
|=
reg7val
;
if
(
p
->
addr
==
5
&&
mode
==
ACAM_GMODE
)
regval
|=
AR5_StartOff1
(
ACAM_GMODE_START_OFFSET
);
if
(
p
->
addr
==
6
&&
mode
==
ACAM_GMODE
)
regval
|=
AR6_StartOff2
(
ACAM_GMODE_START_OFFSET
);
acam_writel
(
fd
,
regval
,
p
->
addr
);
}
for
(
i
=
0
;
i
<
20
;
i
++
)
{
if
(
acam_is_pll_locked
(
fd
))
{
locked
=
1
;
break
;
}
mdelay
(
100
);
}
if
(
!
locked
)
{
pp_printf
(
"Error: ACAM PLL doesn't lock.
\n
"
);
return
-
1
;
}
/* after config, set the FIFO address for further reads */
acam_set_address
(
fd
,
8
);
return
0
;
}
int
fd_acam_init
(
struct
wrtd_fd_dev
*
fd
)
{
int
ret
;
fd
->
fd_acam_addr
=
-
1
;
/* First time must be activated */
int
ret
;
fd
->
fd_acam_addr
=
-
1
;
/* First time must be activated */
acam_set_bypass
(
fd
,
1
);
/* Driven by host, not core */
acam_set_bypass
(
fd
,
1
);
/* Driven by host, not core */
if
(
(
ret
=
acam_test_bus
(
fd
))
)
return
ret
;
if
(
(
ret
=
acam_test_bus
(
fd
))
)
return
ret
;
if
(
(
ret
=
acam_configure
(
fd
,
ACAM_IMODE
,
acam_init_regs_imode
,
ARRAY_SIZE
(
acam_init_regs_imode
)))
)
return
ret
;
if
(
(
ret
=
acam_configure
(
fd
,
ACAM_IMODE
,
acam_init_regs_imode
,
ARRAY_SIZE
(
acam_init_regs_imode
)))
)
return
ret
;
if
(
(
ret
=
fd_calibrate_outputs
(
fd
))
)
return
ret
;
if
(
(
ret
=
fd_calibrate_outputs
(
fd
))
)
return
ret
;
if
(
(
ret
=
acam_configure
(
fd
,
ACAM_GMODE
,
acam_init_regs_gmode
,
ARRAY_SIZE
(
acam_init_regs_gmode
)))
)
return
ret
;
if
(
(
ret
=
acam_configure
(
fd
,
ACAM_GMODE
,
acam_init_regs_gmode
,
ARRAY_SIZE
(
acam_init_regs_gmode
)))
)
return
ret
;
acam_set_bypass
(
fd
,
0
);
/* Driven by core, not host */
acam_set_bypass
(
fd
,
0
);
/* Driven by core, not host */
/* Clear and disable the timestamp readout buffer */
fd_writel
(
fd
,
FD_TSBCR_PURGE
|
FD_TSBCR_RST_SEQ
,
FD_REG_TSBCR
);
/* Clear and disable the timestamp readout buffer */
fd_writel
(
fd
,
FD_TSBCR_PURGE
|
FD_TSBCR_RST_SEQ
,
FD_REG_TSBCR
);
/*
* Program the ACAM-specific TS registers w pre-defined calib values:
* - bin -> internal timebase scalefactor (ADSFR),
* - Start offset (must be consistent with value in ACAM reg 4)
* - timestamp merging control register (ATMCR)
* GMode fix: we no longer use the values from the EEPROM (they are fixed anyway)
*/
/*
* Program the ACAM-specific TS registers w pre-defined calib values:
* - bin -> internal timebase scalefactor (ADSFR),
* - Start offset (must be consistent with value in ACAM reg 4)
* - timestamp merging control register (ATMCR)
* GMode fix: we no longer use the values from the EEPROM (they are fixed anyway)
*/
fd_writel
(
fd
,
ACAM_GMODE_ADSFR
,
FD_REG_ADSFR
);
fd_writel
(
fd
,
ACAM_GMODE_ASOR
,
FD_REG_ASOR
);
fd_writel
(
fd
,
ACAM_GMODE_ATMCR
,
FD_REG_ATMCR
);
fd_writel
(
fd
,
ACAM_GMODE_ADSFR
,
FD_REG_ADSFR
);
fd_writel
(
fd
,
ACAM_GMODE_ASOR
,
FD_REG_ASOR
);
fd_writel
(
fd
,
ACAM_GMODE_ATMCR
,
FD_REG_ATMCR
);
return
0
;
return
0
;
}
software/firmware/fd/fd-calibrate.c
View file @
1394f372
/*
/**
* @file fd_calibrate.c
*
* Calibrate the output path.
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
* Author: Dimitris Lampridis <dimitris.lampridis@cern.ch>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
* Copyright (c) 2012-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "mockturtle-rt.h"
...
...
@@ -21,10 +22,9 @@
/* This is the same as in ./acam.c: use only at init time */
static
void
acam_set_bypass
(
struct
wrtd_fd_dev
*
fd
,
int
on
)
{
fd_writel
(
fd
,
on
?
FD_GCR_BYPASS
:
0
,
FD_REG_GCR
);
fd_writel
(
fd
,
on
?
FD_GCR_BYPASS
:
0
,
FD_REG_GCR
);
}
/*
* Measures the the FPGA-generated TDC start and the output of one of
* the fine delay chips (channel) at a pre-defined number of taps
...
...
@@ -36,80 +36,80 @@ static void acam_set_bypass(struct wrtd_fd_dev *fd, int on)
/* Note: channel is the "internal" one: 0..3 */
static
uint64_t
output_delay_ps
(
struct
wrtd_fd_dev
*
fd
,
int
ch
,
int
fine
,
int
n
)
{
int
i
;
uint64_t
acc
=
0
;
int
i
;
uint64_t
acc
=
0
;
/* Disable the output for the channel being calibrated */
fd_gpio_clr
(
fd
,
FD_GPIO_OUTPUT_EN
(
FD_CH_EXT
(
ch
)));
/* Disable the output for the channel being calibrated */
fd_gpio_clr
(
fd
,
FD_GPIO_OUTPUT_EN
(
FD_CH_EXT
(
ch
)));
/* Enable the stop input in ACAM for the channel being calibrated */
acam_writel
(
fd
,
AR0_TRiseEn
(
0
)
|
AR0_TRiseEn
(
FD_CH_EXT
(
ch
))
|
AR0_HQSel
|
AR0_ROsc
,
0
);
/* Enable the stop input in ACAM for the channel being calibrated */
acam_writel
(
fd
,
AR0_TRiseEn
(
0
)
|
AR0_TRiseEn
(
FD_CH_EXT
(
ch
))
|
AR0_HQSel
|
AR0_ROsc
,
0
);
/* Program the output delay line setpoint */
fd_drv_ch_writel
(
fd
,
ch
,
fine
,
FD_REG_FRR
);
fd_drv_ch_writel
(
fd
,
ch
,
FD_DCR_ENABLE
|
FD_DCR_MODE
|
FD_DCR_UPDATE
,
/* Program the output delay line setpoint */
fd_drv_ch_writel
(
fd
,
ch
,
fine
,
FD_REG_FRR
);
fd_drv_ch_writel
(
fd
,
ch
,
FD_DCR_ENABLE
|
FD_DCR_MODE
|
FD_DCR_UPDATE
,
FD_REG_DCR
);
fd_drv_ch_writel
(
fd
,
ch
,
FD_DCR_FORCE_DLY
|
FD_DCR_ENABLE
,
FD_REG_DCR
);
/*
* Set the calibration pulse mask to genrate calibration
* pulses only on one channel at a time. This minimizes the
* crosstalk in the output buffer which can severely decrease
* the accuracy of calibration measurements
*/
fd_writel
(
fd
,
FD_CALR_PSEL_W
(
1
<<
ch
),
FD_REG_CALR
);
udelay
(
1
);
/* Do n_avgs single measurements and average */
for
(
i
=
0
;
i
<
n
;
i
++
)
{
uint32_t
fr
;
/* Re-arm the ACAM (it's working in a single-shot mode) */
fd_writel
(
fd
,
FD_TDCSR_ALUTRIG
,
FD_REG_TDCSR
);
udelay
(
1
);
/* Produce a calib pulse on the TDC start and the output ch */
fd_writel
(
fd
,
FD_CALR_CAL_PULSE
|
FD_CALR_PSEL_W
(
1
<<
ch
),
FD_REG_CALR
);
udelay
(
1
);
/* read the tag, convert to picoseconds (fixed point: 16.16) */
fr
=
acam_readl
(
fd
,
8
/* fifo */
)
&
0x1ffff
;
//pp_printf("i %d fr %x\n\r", i, fr);
acc
+=
fr
*
fd
->
fd_bin_size
;
}
fd_drv_ch_writel
(
fd
,
ch
,
0
,
FD_REG_DCR
);
/* Calculate avg, min max */
acc
=
div_u64
((
acc
+
n
/
2
),
n
);
//pp_printf("ch %d avg %08x%08x\n\r", ch, (uint32_t)(acc>>32), (uint32_t)acc);
return
acc
;
fd_drv_ch_writel
(
fd
,
ch
,
FD_DCR_FORCE_DLY
|
FD_DCR_ENABLE
,
FD_REG_DCR
);
/*
* Set the calibration pulse mask to genrate calibration
* pulses only on one channel at a time. This minimizes the
* crosstalk in the output buffer which can severely decrease
* the accuracy of calibration measurements
*/
fd_writel
(
fd
,
FD_CALR_PSEL_W
(
1
<<
ch
),
FD_REG_CALR
);
udelay
(
1
);
/* Do n_avgs single measurements and average */
for
(
i
=
0
;
i
<
n
;
i
++
)
{
uint32_t
fr
;
/* Re-arm the ACAM (it's working in a single-shot mode) */
fd_writel
(
fd
,
FD_TDCSR_ALUTRIG
,
FD_REG_TDCSR
);
udelay
(
1
);
/* Produce a calib pulse on the TDC start and the output ch */
fd_writel
(
fd
,
FD_CALR_CAL_PULSE
|
FD_CALR_PSEL_W
(
1
<<
ch
),
FD_REG_CALR
);
udelay
(
1
);
/* read the tag, convert to picoseconds (fixed point: 16.16) */
fr
=
acam_readl
(
fd
,
8
/* fifo */
)
&
0x1ffff
;
//pp_printf("i %d fr %x\n\r", i, fr);
acc
+=
fr
*
fd
->
fd_bin_size
;
}
fd_drv_ch_writel
(
fd
,
ch
,
0
,
FD_REG_DCR
);
/* Calculate avg, min max */
acc
=
div_u64
((
acc
+
n
/
2
),
n
);
//pp_printf("ch %d avg %08x%08x\n\r", ch, (uint32_t)(acc>>32), (uint32_t)acc);
return
acc
;
}
static
int
fd_find_8ns_tap
(
struct
wrtd_fd_dev
*
fd
,
int
ch
)
{
int
l
=
0
,
mid
,
r
=
FD_NUM_TAPS
-
1
;
uint64_t
bias
,
dly
;
/*
* Measure the delay at zero setting, so it can be further
* subtracted to get only the delay part introduced by the
* delay line (ingoring the TDC, FPGA and routing delays).
* Use a binary search of the delay value.
*/
bias
=
output_delay_ps
(
fd
,
ch
,
0
,
FD_CAL_STEPS
);
while
(
r
-
l
>
1
)
{
mid
=
(
l
+
r
)
/
2
;
dly
=
output_delay_ps
(
fd
,
ch
,
mid
,
FD_CAL_STEPS
)
-
bias
;
if
(
dly
<
8000
<<
16
)
l
=
mid
;
else
r
=
mid
;
}
return
l
;
int
l
=
0
,
mid
,
r
=
FD_NUM_TAPS
-
1
;
uint64_t
bias
,
dly
;
/*
* Measure the delay at zero setting, so it can be further
* subtracted to get only the delay part introduced by the
* delay line (ingoring the TDC, FPGA and routing delays).
* Use a binary search of the delay value.
*/
bias
=
output_delay_ps
(
fd
,
ch
,
0
,
FD_CAL_STEPS
);
while
(
r
-
l
>
1
)
{
mid
=
(
l
+
r
)
/
2
;
dly
=
output_delay_ps
(
fd
,
ch
,
mid
,
FD_CAL_STEPS
)
-
bias
;
if
(
dly
<
8000
<<
16
)
l
=
mid
;
else
r
=
mid
;
}
return
l
;
}
...
...
@@ -121,17 +121,17 @@ static int fd_find_8ns_tap(struct wrtd_fd_dev *fd, int ch)
*/
int
fd_calibrate_outputs
(
struct
wrtd_fd_dev
*
fd
)
{
int
ch
;
int
measured
;
int
ch
;
int
measured
;
acam_set_bypass
(
fd
,
1
);
/* not useful */
fd_writel
(
fd
,
FD_TDCSR_START_EN
|
FD_TDCSR_STOP_EN
,
FD_REG_TDCSR
);
acam_set_bypass
(
fd
,
1
);
/* not useful */
fd_writel
(
fd
,
FD_TDCSR_START_EN
|
FD_TDCSR_STOP_EN
,
FD_REG_TDCSR
);
for
(
ch
=
0
;
ch
<
FD_NUM_CHANNELS
;
ch
++
)
{
for
(
ch
=
0
;
ch
<
FD_NUM_CHANNELS
;
ch
++
)
{
measured
=
fd_find_8ns_tap
(
fd
,
ch
);
fd_drv_ch_writel
(
fd
,
ch
,
measured
,
FD_REG_FRR
);
fd_drv_ch_writel
(
fd
,
ch
,
measured
,
FD_REG_FRR
);
pr_debug
(
"Channel %d: 8ns @ %i taps.
\n\r
"
,
ch
+
1
,
measured
);
}
return
0
;
pr_debug
(
"Channel %d: 8ns @ %i taps.
\n\r
"
,
ch
+
1
,
measured
);
}
return
0
;
}
software/firmware/fd/fd-gpio.c
View file @
1394f372
/*
/**
* @file fd_gpio.c
*
* SPI access to fine-delay internals
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
* Author: Dimitris Lampridis <dimitris.lampridis@cern.ch>
*
* Copyright (c) 2012-2019 CERN (home.cern)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "mockturtle-rt.h"
...
...
@@ -22,58 +23,58 @@ int gpio_writel(struct wrtd_fd_dev *fd, int val, int reg)
int
rval
=
fd_spi_xfer
(
fd
,
FD_CS_GPIO
,
24
,
0x4e0000
|
(
reg
<<
8
)
|
val
,
NULL
);
return
rval
;
return
rval
;
}
static
int
gpio_readl
(
struct
wrtd_fd_dev
*
fd
,
int
reg
)
{
uint32_t
ret
;
int
err
;
uint32_t
ret
;
int
err
;
err
=
fd_spi_xfer
(
fd
,
FD_CS_GPIO
,
24
,
0x4f0000
|
(
reg
<<
8
),
&
ret
);
err
=
fd_spi_xfer
(
fd
,
FD_CS_GPIO
,
24
,
0x4f0000
|
(
reg
<<
8
),
&
ret
);
if
(
err
<
0
)
return
err
;
return
ret
&
0xff
;
if
(
err
<
0
)
return
err
;
return
ret
&
0xff
;
}
static
int
gpio_writel_with_retry
(
struct
wrtd_fd_dev
*
fd
,
int
val
,
int
reg
)
{
int
retries
=
SPI_RETRIES
,
rv
;
while
(
retries
--
)
{
gpio_writel
(
fd
,
val
,
reg
);
rv
=
gpio_readl
(
fd
,
reg
);
if
(
rv
>=
0
&&
(
rv
==
val
))
{
if
(
SPI_RETRIES
-
1
-
retries
>
0
)
pr_debug
(
"gpio_writel_with_retry: succeded after %d retries
\n
"
,
SPI_RETRIES
-
1
-
retries
);
return
0
;
}
}
return
-
EIO
;
int
retries
=
SPI_RETRIES
,
rv
;
while
(
retries
--
)
{
gpio_writel
(
fd
,
val
,
reg
);
rv
=
gpio_readl
(
fd
,
reg
);
if
(
rv
>=
0
&&
(
rv
==
val
))
{
if
(
SPI_RETRIES
-
1
-
retries
>
0
)
pr_debug
(
"gpio_writel_with_retry: succeded after %d retries
\n
"
,
SPI_RETRIES
-
1
-
retries
);
return
0
;
}
}
return
-
EIO
;
}
void
fd_gpio_dir
(
struct
wrtd_fd_dev
*
fd
,
int
mask
,
int
dir
)
{
fd
->
fd_mcp_iodir
&=
~
mask
;
if
(
dir
==
FD_GPIO_IN
)
fd
->
fd_mcp_iodir
|=
mask
;
fd
->
fd_mcp_iodir
&=
~
mask
;
if
(
dir
==
FD_GPIO_IN
)
fd
->
fd_mcp_iodir
|=
mask
;
gpio_writel_with_retry
(
fd
,
(
fd
->
fd_mcp_iodir
&
0xff
),
FD_MCP_IODIR
);
gpio_writel_with_retry
(
fd
,
(
fd
->
fd_mcp_iodir
>>
8
),
FD_MCP_IODIR
+
1
);
gpio_writel_with_retry
(
fd
,
(
fd
->
fd_mcp_iodir
&
0xff
),
FD_MCP_IODIR
);
gpio_writel_with_retry
(
fd
,
(
fd
->
fd_mcp_iodir
>>
8
),
FD_MCP_IODIR
+
1
);
}
void
fd_gpio_val
(
struct
wrtd_fd_dev
*
fd
,
int
mask
,
int
values
)
{
fd
->
fd_mcp_olat
&=
~
mask
;
fd
->
fd_mcp_olat
|=
values
;
fd
->
fd_mcp_olat
&=
~
mask
;
fd
->
fd_mcp_olat
|=
values
;
gpio_writel_with_retry
(
fd
,
(
fd
->
fd_mcp_olat
&
0xff
),
FD_MCP_OLAT
);
gpio_writel_with_retry
(
fd
,
(
fd
->
fd_mcp_olat
>>
8
),
FD_MCP_OLAT
+
1
);
gpio_writel_with_retry
(
fd
,
(
fd
->
fd_mcp_olat
&
0xff
),
FD_MCP_OLAT
);
gpio_writel_with_retry
(
fd
,
(
fd
->
fd_mcp_olat
>>
8
),
FD_MCP_OLAT
+
1
);
}
void
fd_gpio_set_clr
(
struct
wrtd_fd_dev
*
fd
,
int
mask
,
int
set
)
...
...
@@ -83,28 +84,28 @@ void fd_gpio_set_clr(struct wrtd_fd_dev *fd, int mask, int set)
int
fd_gpio_init
(
struct
wrtd_fd_dev
*
fd
)
{
int
i
,
val
;
fd
->
fd_mcp_iodir
=
0xffff
;
fd
->
fd_mcp_olat
=
0
;
if
(
gpio_writel
(
fd
,
0x00
,
FD_MCP_IOCON
)
<
0
)
goto
out
;
/* Try to read and write a register to test the SPI connection */
for
(
val
=
0xaa
;
val
>=
0
;
val
-=
0x11
)
{
if
(
gpio_writel
(
fd
,
val
,
FD_MCP_IPOL
)
<
0
)
goto
out
;
i
=
gpio_readl
(
fd
,
FD_MCP_IPOL
);
if
(
i
<
0
)
goto
out
;
if
(
i
!=
val
)
{
pr_error
(
"GPIO comm error (got 0x%x, expected 0x%x)
\n
"
,
i
,
val
);
return
-
EIO
;
}
}
/* last time we wrote 0, ok */
return
0
;
int
i
,
val
;
fd
->
fd_mcp_iodir
=
0xffff
;
fd
->
fd_mcp_olat
=
0
;
if
(
gpio_writel
(
fd
,
0x00
,
FD_MCP_IOCON
)
<
0
)
goto
out
;
/* Try to read and write a register to test the SPI connection */
for
(
val
=
0xaa
;
val
>=
0
;
val
-=
0x11
)
{
if
(
gpio_writel
(
fd
,
val
,
FD_MCP_IPOL
)
<
0
)
goto
out
;
i
=
gpio_readl
(
fd
,
FD_MCP_IPOL
);
if
(
i
<
0
)
goto
out
;
if
(
i
!=
val
)
{
pr_error
(
"GPIO comm error (got 0x%x, expected 0x%x)
\n
"
,
i
,
val
);
return
-
EIO
;
}
}
/* last time we wrote 0, ok */
return
0
;
out:
return
-
EIO
;
return
-
EIO
;
}
software/firmware/fd/fd-i2c.c
View file @
1394f372
/*
/**
* @file fd_i2c.c
*
* I2C access (on-board EEPROM)
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
* Author: Dimitris Lampridis <dimitris.lampridis@cern.ch>
*
* Copyright (c) 2012-2019 CERN (home.cern)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2 as published by the Free Software Foundation or, at your
* option, any later version.
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "mockturtle-rt.h"
...
...
@@ -18,24 +19,24 @@
static
void
set_sda
(
struct
wrtd_fd_dev
*
fd
,
int
val
)
{
uint32_t
reg
;
uint32_t
reg
;
reg
=
fd_readl
(
fd
,
FD_REG_I2CR
)
&
~
FD_I2CR_SDA_OUT
;
if
(
val
)
reg
|=
FD_I2CR_SDA_OUT
;
fd_writel
(
fd
,
reg
,
FD_REG_I2CR
);
udelay
(
3
);
reg
=
fd_readl
(
fd
,
FD_REG_I2CR
)
&
~
FD_I2CR_SDA_OUT
;
if
(
val
)
reg
|=
FD_I2CR_SDA_OUT
;
fd_writel
(
fd
,
reg
,
FD_REG_I2CR
);
udelay
(
3
);
}
static
void
set_scl
(
struct
wrtd_fd_dev
*
fd
,
int
val
)
{
uint32_t
reg
;
uint32_t
reg
;
reg
=
fd_readl
(
fd
,
FD_REG_I2CR
)
&
~
FD_I2CR_SCL_OUT
;
if
(
val
)
reg
|=
FD_I2CR_SCL_OUT
;
fd_writel
(
fd
,
reg
,
FD_REG_I2CR
);
udelay
(
3
);
reg
=
fd_readl
(
fd
,
FD_REG_I2CR
)
&
~
FD_I2CR_SCL_OUT
;
if
(
val
)
reg
|=
FD_I2CR_SCL_OUT
;
fd_writel
(
fd
,
reg
,
FD_REG_I2CR
);
udelay
(
3
);
}
static
int
get_sda
(
struct
wrtd_fd_dev
*
fd
)
...
...
@@ -46,105 +47,105 @@ static int get_sda(struct wrtd_fd_dev *fd)
static
void
mi2c_start
(
struct
wrtd_fd_dev
*
fd
)
{
set_sda
(
fd
,
0
);
set_scl
(
fd
,
0
);
set_scl
(
fd
,
0
);
}
static
void
mi2c_stop
(
struct
wrtd_fd_dev
*
fd
)
{
set_sda
(
fd
,
0
);
set_scl
(
fd
,
1
);
set_sda
(
fd
,
1
);
set_sda
(
fd
,
0
);
set_scl
(
fd
,
1
);
set_sda
(
fd
,
1
);
}
int
mi2c_put_byte
(
struct
wrtd_fd_dev
*
fd
,
int
data
)
{
int
i
;
int
ack
;
int
i
;
int
ack
;
for
(
i
=
0
;
i
<
8
;
i
++
,
data
<<=
1
)
{
set_sda
(
fd
,
data
&
0x80
);
set_scl
(
fd
,
1
);
set_scl
(
fd
,
0
);
}
for
(
i
=
0
;
i
<
8
;
i
++
,
data
<<=
1
)
{
set_sda
(
fd
,
data
&
0x80
);
set_scl
(
fd
,
1
);
set_scl
(
fd
,
0
);
}
set_sda
(
fd
,
1
);
set_scl
(
fd
,
1
);
set_sda
(
fd
,
1
);
set_scl
(
fd
,
1
);
ack
=
get_sda
(
fd
);
ack
=
get_sda
(
fd
);
set_scl
(
fd
,
0
);
set_sda
(
fd
,
0
);
set_scl
(
fd
,
0
);
set_sda
(
fd
,
0
);
return
ack
?
-
EIO
:
0
;
/* ack low == success */
return
ack
?
-
EIO
:
0
;
/* ack low == success */
}
int
mi2c_get_byte
(
struct
wrtd_fd_dev
*
fd
,
unsigned
char
*
data
,
int
sendack
)
{
int
i
;
int
indata
=
0
;
/* assert: scl is low */
set_scl
(
fd
,
0
);
set_sda
(
fd
,
1
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
set_scl
(
fd
,
1
);
indata
<<=
1
;
if
(
get_sda
(
fd
))
indata
|=
0x01
;
set_scl
(
fd
,
0
);
}
set_sda
(
fd
,
(
sendack
?
0
:
1
));
set_scl
(
fd
,
1
);
set_scl
(
fd
,
0
);
set_sda
(
fd
,
0
);
*
data
=
indata
;
return
0
;
int
i
;
int
indata
=
0
;
/* assert: scl is low */
set_scl
(
fd
,
0
);
set_sda
(
fd
,
1
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
set_scl
(
fd
,
1
);
indata
<<=
1
;
if
(
get_sda
(
fd
))
indata
|=
0x01
;
set_scl
(
fd
,
0
);
}
set_sda
(
fd
,
(
sendack
?
0
:
1
));
set_scl
(
fd
,
1
);
set_scl
(
fd
,
0
);
set_sda
(
fd
,
0
);
*
data
=
indata
;
return
0
;
}
void
mi2c_init
(
struct
wrtd_fd_dev
*
fd
)
{
set_scl
(
fd
,
1
);
set_sda
(
fd
,
1
);
set_scl
(
fd
,
1
);
set_sda
(
fd
,
1
);
}
void
mi2c_scan
(
struct
wrtd_fd_dev
*
fd
)
{
int
i
;
for
(
i
=
0
;
i
<
256
;
i
+=
2
)
{
mi2c_start
(
fd
);
if
(
!
mi2c_put_byte
(
fd
,
i
))
pr_debug
(
"Found i2c device at 0x%x
\n
"
,
i
>>
1
);
mi2c_stop
(
fd
);
}
int
i
;
for
(
i
=
0
;
i
<
256
;
i
+=
2
)
{
mi2c_start
(
fd
);
if
(
!
mi2c_put_byte
(
fd
,
i
))
pr_debug
(
"Found i2c device at 0x%x
\n
"
,
i
>>
1
);
mi2c_stop
(
fd
);
}
}
/* FIXME: this is very inefficient: read several bytes in a row instead */
int
fd_eeprom_read
(
struct
wrtd_fd_dev
*
fd
,
int
i2c_addr
,
uint32_t
offset
,
void
*
buf
,
size_t
size
)
{
int
i
;
uint8_t
*
buf8
=
buf
;
unsigned
char
c
;
for
(
i
=
0
;
i
<
size
;
i
++
)
{
mi2c_start
(
fd
);
if
(
mi2c_put_byte
(
fd
,
i2c_addr
<<
1
)
<
0
)
{
mi2c_stop
(
fd
);
return
-
EIO
;
}
mi2c_put_byte
(
fd
,
(
offset
>>
8
)
&
0xff
);
mi2c_put_byte
(
fd
,
offset
&
0xff
);
offset
++
;
mi2c_stop
(
fd
);
mi2c_start
(
fd
);
mi2c_put_byte
(
fd
,
(
i2c_addr
<<
1
)
|
1
);
mi2c_get_byte
(
fd
,
&
c
,
0
);
*
buf8
++
=
c
;
mi2c_stop
(
fd
);
}
return
size
;
int
i
;
uint8_t
*
buf8
=
buf
;
unsigned
char
c
;
for
(
i
=
0
;
i
<
size
;
i
++
)
{
mi2c_start
(
fd
);
if
(
mi2c_put_byte
(
fd
,
i2c_addr
<<
1
)
<
0
)
{
mi2c_stop
(
fd
);
return
-
EIO
;
}
mi2c_put_byte
(
fd
,
(
offset
>>
8
)
&
0xff
);
mi2c_put_byte
(
fd
,
offset
&
0xff
);
offset
++
;
mi2c_stop
(
fd
);
mi2c_start
(
fd
);
mi2c_put_byte
(
fd
,
(
i2c_addr
<<
1
)
|
1
);
mi2c_get_byte
(
fd
,
&
c
,
0
);
*
buf8
++
=
c
;
mi2c_stop
(
fd
);
}
return
size
;
}
software/firmware/fd/fd-init.c
View file @
1394f372
/*
* Copyright (C) 2018 CERN (www.cern.ch)
/**
* @file fd_init.c
*
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Dimitris Lampridis <dimitris.lampridis@cern.ch>
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <errno.h>
#include <string.h>
...
...
@@ -36,102 +39,102 @@
*/
static
void
fd_do_reset
(
struct
wrtd_fd_dev
*
fd
,
int
hw_reset
)
{
if
(
hw_reset
)
{
/* clear RSTS_RST_FMC bit, set RSTS_RST_CORE bit*/
fd_writel
(
fd
,
FD_RSTR_LOCK_W
(
0xdead
)
|
FD_RSTR_RST_CORE_MASK
,
if
(
hw_reset
)
{
/* clear RSTS_RST_FMC bit, set RSTS_RST_CORE bit*/
fd_writel
(
fd
,
FD_RSTR_LOCK_W
(
0xdead
)
|
FD_RSTR_RST_CORE_MASK
,
FD_REG_RSTR
);
UDELAY
(
10000
);
fd_writel
(
fd
,
FD_RSTR_LOCK_W
(
0xdead
)
|
FD_RSTR_RST_CORE_MASK
UDELAY
(
10000
);
fd_writel
(
fd
,
FD_RSTR_LOCK_W
(
0xdead
)
|
FD_RSTR_RST_CORE_MASK
|
FD_RSTR_RST_FMC_MASK
,
FD_REG_RSTR
);
/* TPS3307 supervisor needs time to de-assert master reset */
MDELAY
(
600
);
return
;
}
/* clear RSTS_RST_CORE bit, set RSTS_RST_FMC bit */
fd_writel
(
fd
,
FD_RSTR_LOCK_W
(
0xdead
)
|
FD_RSTR_RST_FMC_MASK
,
FD_REG_RSTR
);
UDELAY
(
1000
);
fd_writel
(
fd
,
FD_RSTR_LOCK_W
(
0xdead
)
|
FD_RSTR_RST_FMC_MASK
|
FD_RSTR_RST_CORE_MASK
,
FD_REG_RSTR
);
UDELAY
(
1000
);
/* TPS3307 supervisor needs time to de-assert master reset */
MDELAY
(
600
);
return
;
}
/* clear RSTS_RST_CORE bit, set RSTS_RST_FMC bit */
fd_writel
(
fd
,
FD_RSTR_LOCK_W
(
0xdead
)
|
FD_RSTR_RST_FMC_MASK
,
FD_REG_RSTR
);
UDELAY
(
1000
);
fd_writel
(
fd
,
FD_RSTR_LOCK_W
(
0xdead
)
|
FD_RSTR_RST_FMC_MASK
|
FD_RSTR_RST_CORE_MASK
,
FD_REG_RSTR
);
UDELAY
(
1000
);
}
/* Some init procedures to be intermixed with subsystems */
int
fd_gpio_defaults
(
struct
wrtd_fd_dev
*
fd
)
{
fd_gpio_dir
(
fd
,
FD_GPIO_TRIG_INTERNAL
,
FD_GPIO_OUT
);
fd_gpio_set
(
fd
,
FD_GPIO_TRIG_INTERNAL
);
fd_gpio_dir
(
fd
,
FD_GPIO_TRIG_INTERNAL
,
FD_GPIO_OUT
);
fd_gpio_set
(
fd
,
FD_GPIO_TRIG_INTERNAL
);
fd_gpio_set
(
fd
,
FD_GPIO_OUTPUT_MASK
);
fd_gpio_dir
(
fd
,
FD_GPIO_OUTPUT_MASK
,
FD_GPIO_OUT
);
fd_gpio_set
(
fd
,
FD_GPIO_OUTPUT_MASK
);
fd_gpio_dir
(
fd
,
FD_GPIO_OUTPUT_MASK
,
FD_GPIO_OUT
);
fd_gpio_dir
(
fd
,
FD_GPIO_TERM_EN
,
FD_GPIO_OUT
);
fd_gpio_clr
(
fd
,
FD_GPIO_TERM_EN
);
return
0
;
fd_gpio_dir
(
fd
,
FD_GPIO_TERM_EN
,
FD_GPIO_OUT
);
fd_gpio_clr
(
fd
,
FD_GPIO_TERM_EN
);
return
0
;
}
int
fd_reset_again
(
struct
wrtd_fd_dev
*
fd
)
{
/* Reset the FD core once we have proper reference/TDC clocks */
fd_do_reset
(
fd
,
0
/* not hw */
);
/* Reset the FD core once we have proper reference/TDC clocks */
fd_do_reset
(
fd
,
0
/* not hw */
);
MDELAY
(
10
);
MDELAY
(
10
);
if
(
!
(
fd_readl
(
fd
,
FD_REG_GCR
)
&
FD_GCR_DDR_LOCKED
)
)
{
pr_error
(
"timeout waiting for GCR lock bit
\n
"
);
return
-
EIO
;
}
if
(
!
(
fd_readl
(
fd
,
FD_REG_GCR
)
&
FD_GCR_DDR_LOCKED
)
)
{
pr_error
(
"timeout waiting for GCR lock bit
\n
"
);
return
-
EIO
;
}
fd_do_reset
(
fd
,
0
/* not hw */
);
return
0
;
fd_do_reset
(
fd
,
0
/* not hw */
);
return
0
;
}
/* FIXME missing all calibration */
int
fd_init
(
struct
wrtd_fd_dev
*
fd
)
{
int
err
,
ch
;
int
err
,
ch
;
pr_debug
(
"Initializing the Fine Delay board...
\n
"
);
pr_debug
(
"Initializing the Fine Delay board...
\n
"
);
fd_do_reset
(
fd
,
1
);
fd_do_reset
(
fd
,
1
);
err
=
fd_gpio_init
(
fd
);
if
(
err
)
return
err
;
err
=
fd_gpio_init
(
fd
);
if
(
err
)
return
err
;
err
=
fd_pll_init
(
fd
);
if
(
err
)
return
err
;
err
=
fd_pll_init
(
fd
);
if
(
err
)
return
err
;
fd_gpio_defaults
(
fd
);
fd_gpio_defaults
(
fd
);
err
=
fd_reset_again
(
fd
);
if
(
err
)
return
err
;
err
=
fd_reset_again
(
fd
);
if
(
err
)
return
err
;
err
=
fd_acam_init
(
fd
);
if
(
err
)
return
err
;
err
=
fd_acam_init
(
fd
);
if
(
err
)
return
err
;
for
(
ch
=
1
;
ch
<=
FD_NUM_CHANNELS
;
ch
++
)
fd_gpio_set
(
fd
,
FD_GPIO_OUTPUT_EN
(
ch
));
for
(
ch
=
1
;
ch
<=
FD_NUM_CHANNELS
;
ch
++
)
fd_gpio_set
(
fd
,
FD_GPIO_OUTPUT_EN
(
ch
));
// todo: read offsets from the EEPROM. I2C should be working OK.
// todo: read offsets from the EEPROM. I2C should be working OK.
return
0
;
return
0
;
}
#ifdef SIMULATION
int
fd_sim_init
(
struct
wrtd_fd_dev
*
fd
)
{
int
err
;
int
err
;
pr_debug
(
"Initializing the Fine Delay board...
\n
"
);
pr_debug
(
"Initializing the Fine Delay board...
\n
"
);
fd_do_reset
(
fd
,
1
);
fd_do_reset
(
fd
,
1
);
return
0
;
return
0
;
}
#endif
software/firmware/fd/fd-pll.c
View file @
1394f372
/*
* Copyright (C) 2018 CERN (www.cern.ch)
/**
* @file fd_pll.c
*
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Dimitris Lampridis <dimitris.lampridis@cern.ch>
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <errno.h>
#include <string.h>
...
...
@@ -18,138 +21,138 @@
#include "wrtd-fd.h"
struct
ad9516_reg
{
unsigned
short
reg
;
unsigned
short
reg
;
unsigned
char
val
;
};
static
const
struct
ad9516_reg
__9516_regs
[]
=
{
{
0x0000
,
0x99
},
/* Config SPI */
{
0x0001
,
0x00
},
{
0x0002
,
0x10
},
{
0x0003
,
0xC3
},
{
0x0004
,
0x00
},
/* PLL */
{
0x0010
,
0x7C
},
/* PFD and charge pump */
{
0x0011
,
0x05
},
/* R divider (1) */
{
0x0012
,
0x00
},
/* R divider (2) */
{
0x0013
,
0x0C
},
/* A counter */
{
0x0014
,
0x12
},
/* B counter (1) */
{
0x0015
,
0x00
},
/* B counter (2) */
{
0x0016
,
0x05
},
/* PLL control (1) */
{
0x0017
,
0xb4
},
/* PLL control (2) PLL_STATUS = Lock Detect */
{
0x0018
,
0x07
},
/* PLL control (3) */
{
0x0019
,
0x00
},
/* PLL control (4) */
{
0x001A
,
0x00
},
/* PLL control (5) */
{
0x001B
,
0xE0
},
/* PLL control (6) */
{
0x001C
,
0x02
},
/* PLL control (7) */
{
0x001D
,
0x00
},
/* PLL control (8) */
{
0x001E
,
0x00
},
/* PLL control (9) */
{
0x001F
,
0x0E
},
/* PLL readback */
/* Fine Delay */
{
0x00A0
,
0x01
},
/* OUT6 Delay bypass */
{
0x00A1
,
0x00
},
/* OUT6 Delay full-scale */
{
0x00A2
,
0x00
},
/* OUT6 Delay fraction */
{
0x00A3
,
0x01
},
/* OUT7 Delay bypass */
{
0x00A4
,
0x00
},
/* OUT7 Delay full-scale */
{
0x00A5
,
0x00
},
/* OUT7 Delay fraction */
{
0x00A6
,
0x01
},
/* OUT8 Delay bypass */
{
0x00A7
,
0x00
},
/* OUT8 Delay full-scale */
{
0x00A8
,
0x00
},
/* OUT8 Delay fraction */
{
0x00A9
,
0x01
},
/* OUT9 Delay bypass */
{
0x00AA
,
0x00
},
/* OUT9 Delay full-scale */
{
0x00AB
,
0x00
},
/* OUT9 Delay fraction */
/* LVPECL */
{
0x00F0
,
0x08
},
/* OUT0 */
{
0x00F1
,
0x08
},
/* OUT1 */
{
0x00F2
,
0x08
},
/* OUT2 */
{
0x00F3
,
0x18
},
/* OUT3, inverted */
{
0x00F4
,
0x00
},
/* OUT4 */
{
0x00F5
,
0x08
},
/* OUT5 */
/* LVDS/CMOS */
{
0x0140
,
0x5A
},
/* OUT6 */
{
0x0141
,
0x5A
},
/* OUT7 */
{
0x0142
,
0x5B
},
/* OUT8 */
{
0x0143
,
0x42
},
/* OUT9 */
/* LVPECL Channel divider */
{
0x0190
,
0x00
},
/* Divider 0 (1) */
{
0x0191
,
0x80
},
/* Divider 0 (2) */
{
0x0192
,
0x00
},
/* Divider 0 (3) */
{
0x0193
,
0x00
},
/* Divider 1 (1) */
{
0x0194
,
0x80
},
/* Divider 1 (2) */
{
0x0195
,
0x00
},
/* Divider 1 (3) */
{
0x0196
,
0xFF
},
/* Divider 2 (1) */
{
0x0197
,
0x00
},
/* Divider 2 (2) */
{
0x0198
,
0x00
},
/* Divider 2 (3) */
/* LVDS/CMOS Channel divider */
{
0x0199
,
0x33
},
/* Divider 3 (1) */
{
0x019A
,
0x00
},
/* Divider 3 (2) */
{
0x019B
,
0x11
},
/* Divider 3 (3) */
{
0x019C
,
0x20
},
/* Divider 3 (4) */
{
0x019D
,
0x00
},
/* Divider 3 (5) */
{
0x019E
,
0x00
},
/* Divider 4 (1) */
{
0x019F
,
0x00
},
/* Divider 4 (2) */
{
0x01A0
,
0x11
},
/* Divider 4 (3) */
{
0x01A1
,
0x20
},
/* Divider 4 (4) */
{
0x01A2
,
0x00
},
/* Divider 4 (5) */
{
0x01A3
,
0x00
},
/* VCO Divider and CLK Input */
{
0x01E0
,
0x04
},
/* VCO divider VCODIV = 6 */
{
0x01E1
,
0x02
},
/* Input Clock */
/* System */
{
0x0230
,
0x00
},
/* Power down and sync */
{
0x0231
,
0x00
},
/* Update All registers */
{
0x0232
,
0x00
},
/* Update All registers */
{
0x0000
,
0x99
},
/* Config SPI */
{
0x0001
,
0x00
},
{
0x0002
,
0x10
},
{
0x0003
,
0xC3
},
{
0x0004
,
0x00
},
/* PLL */
{
0x0010
,
0x7C
},
/* PFD and charge pump */
{
0x0011
,
0x05
},
/* R divider (1) */
{
0x0012
,
0x00
},
/* R divider (2) */
{
0x0013
,
0x0C
},
/* A counter */
{
0x0014
,
0x12
},
/* B counter (1) */
{
0x0015
,
0x00
},
/* B counter (2) */
{
0x0016
,
0x05
},
/* PLL control (1) */
{
0x0017
,
0xb4
},
/* PLL control (2) PLL_STATUS = Lock Detect */
{
0x0018
,
0x07
},
/* PLL control (3) */
{
0x0019
,
0x00
},
/* PLL control (4) */
{
0x001A
,
0x00
},
/* PLL control (5) */
{
0x001B
,
0xE0
},
/* PLL control (6) */
{
0x001C
,
0x02
},
/* PLL control (7) */
{
0x001D
,
0x00
},
/* PLL control (8) */
{
0x001E
,
0x00
},
/* PLL control (9) */
{
0x001F
,
0x0E
},
/* PLL readback */
/* Fine Delay */
{
0x00A0
,
0x01
},
/* OUT6 Delay bypass */
{
0x00A1
,
0x00
},
/* OUT6 Delay full-scale */
{
0x00A2
,
0x00
},
/* OUT6 Delay fraction */
{
0x00A3
,
0x01
},
/* OUT7 Delay bypass */
{
0x00A4
,
0x00
},
/* OUT7 Delay full-scale */
{
0x00A5
,
0x00
},
/* OUT7 Delay fraction */
{
0x00A6
,
0x01
},
/* OUT8 Delay bypass */
{
0x00A7
,
0x00
},
/* OUT8 Delay full-scale */
{
0x00A8
,
0x00
},
/* OUT8 Delay fraction */
{
0x00A9
,
0x01
},
/* OUT9 Delay bypass */
{
0x00AA
,
0x00
},
/* OUT9 Delay full-scale */
{
0x00AB
,
0x00
},
/* OUT9 Delay fraction */
/* LVPECL */
{
0x00F0
,
0x08
},
/* OUT0 */
{
0x00F1
,
0x08
},
/* OUT1 */
{
0x00F2
,
0x08
},
/* OUT2 */
{
0x00F3
,
0x18
},
/* OUT3, inverted */
{
0x00F4
,
0x00
},
/* OUT4 */
{
0x00F5
,
0x08
},
/* OUT5 */
/* LVDS/CMOS */
{
0x0140
,
0x5A
},
/* OUT6 */
{
0x0141
,
0x5A
},
/* OUT7 */
{
0x0142
,
0x5B
},
/* OUT8 */
{
0x0143
,
0x42
},
/* OUT9 */
/* LVPECL Channel divider */
{
0x0190
,
0x00
},
/* Divider 0 (1) */
{
0x0191
,
0x80
},
/* Divider 0 (2) */
{
0x0192
,
0x00
},
/* Divider 0 (3) */
{
0x0193
,
0x00
},
/* Divider 1 (1) */
{
0x0194
,
0x80
},
/* Divider 1 (2) */
{
0x0195
,
0x00
},
/* Divider 1 (3) */
{
0x0196
,
0xFF
},
/* Divider 2 (1) */
{
0x0197
,
0x00
},
/* Divider 2 (2) */
{
0x0198
,
0x00
},
/* Divider 2 (3) */
/* LVDS/CMOS Channel divider */
{
0x0199
,
0x33
},
/* Divider 3 (1) */
{
0x019A
,
0x00
},
/* Divider 3 (2) */
{
0x019B
,
0x11
},
/* Divider 3 (3) */
{
0x019C
,
0x20
},
/* Divider 3 (4) */
{
0x019D
,
0x00
},
/* Divider 3 (5) */
{
0x019E
,
0x00
},
/* Divider 4 (1) */
{
0x019F
,
0x00
},
/* Divider 4 (2) */
{
0x01A0
,
0x11
},
/* Divider 4 (3) */
{
0x01A1
,
0x20
},
/* Divider 4 (4) */
{
0x01A2
,
0x00
},
/* Divider 4 (5) */
{
0x01A3
,
0x00
},
/* VCO Divider and CLK Input */
{
0x01E0
,
0x04
},
/* VCO divider VCODIV = 6 */
{
0x01E1
,
0x02
},
/* Input Clock */
/* System */
{
0x0230
,
0x00
},
/* Power down and sync */
{
0x0231
,
0x00
},
/* Update All registers */
{
0x0232
,
0x00
},
/* Update All registers */
};
int
fd_spi_xfer
(
struct
wrtd_fd_dev
*
fd
,
int
ss
,
int
num_bits
,
uint32_t
in
,
uint32_t
*
out
)
{
uint32_t
scr
=
0
,
r
;
unsigned
long
timeout
;
uint32_t
scr
=
0
,
r
;
unsigned
long
timeout
;
scr
=
FD_SCR_DATA_W
(
in
)
|
FD_SCR_CPOL
;
if
(
ss
==
FD_CS_PLL
)
scr
|=
FD_SCR_SEL_PLL
;
else
if
(
ss
==
FD_CS_GPIO
)
scr
|=
FD_SCR_SEL_GPIO
;
scr
=
FD_SCR_DATA_W
(
in
)
|
FD_SCR_CPOL
;
if
(
ss
==
FD_CS_PLL
)
scr
|=
FD_SCR_SEL_PLL
;
else
if
(
ss
==
FD_CS_GPIO
)
scr
|=
FD_SCR_SEL_GPIO
;
fd_writel
(
fd
,
scr
,
FD_REG_SCR
);
fd_writel
(
fd
,
scr
|
FD_SCR_START
,
FD_REG_SCR
);
fd_writel
(
fd
,
scr
,
FD_REG_SCR
);
fd_writel
(
fd
,
scr
|
FD_SCR_START
,
FD_REG_SCR
);
timeout
=
trtl_get_runtime_milliseconds
()
+
1000
;
while
(
!
(
fd_readl
(
fd
,
FD_REG_SCR
)
&
FD_SCR_READY
))
if
(
trtl_get_runtime_milliseconds
()
>
timeout
)
break
;
if
(
!
(
fd_readl
(
fd
,
FD_REG_SCR
)
&
FD_SCR_READY
))
return
-
EIO
;
scr
=
fd_readl
(
fd
,
FD_REG_SCR
);
r
=
FD_SCR_DATA_R
(
scr
);
if
(
out
)
*
out
=
r
;
timeout
=
trtl_get_runtime_milliseconds
()
+
1000
;
while
(
!
(
fd_readl
(
fd
,
FD_REG_SCR
)
&
FD_SCR_READY
))
if
(
trtl_get_runtime_milliseconds
()
>
timeout
)
break
;
if
(
!
(
fd_readl
(
fd
,
FD_REG_SCR
)
&
FD_SCR_READY
))
return
-
EIO
;
scr
=
fd_readl
(
fd
,
FD_REG_SCR
);
r
=
FD_SCR_DATA_R
(
scr
);
if
(
out
)
*
out
=
r
;
udelay
(
100
);
/* FIXME: check */
udelay
(
100
);
/* FIXME: check */
return
0
;
return
0
;
}
static
int
fd_pll_writel
(
struct
wrtd_fd_dev
*
fd
,
int
val
,
int
reg
)
{
return
fd_spi_xfer
(
fd
,
FD_CS_PLL
,
24
,
(
reg
<<
8
)
|
val
,
NULL
);
return
fd_spi_xfer
(
fd
,
FD_CS_PLL
,
24
,
(
reg
<<
8
)
|
val
,
NULL
);
}
static
int
fd_pll_readl
(
struct
wrtd_fd_dev
*
fd
,
int
reg
)
{
uint32_t
ret
;
int
err
;
uint32_t
ret
;
int
err
;
err
=
fd_spi_xfer
(
fd
,
FD_CS_PLL
,
24
,
(
reg
<<
8
)
|
(
1
<<
23
),
&
ret
);
if
(
err
<
0
)
return
err
;
err
=
fd_spi_xfer
(
fd
,
FD_CS_PLL
,
24
,
(
reg
<<
8
)
|
(
1
<<
23
),
&
ret
);
if
(
err
<
0
)
return
err
;
return
ret
&
0xff
;
return
ret
&
0xff
;
}
/* Just check the id register of the pll.
...
...
@@ -158,54 +161,54 @@ static int fd_pll_check(struct wrtd_fd_dev *fd)
{
int
id
;
id
=
fd_pll_readl
(
fd
,
0x003
);
if
(
id
<
0
)
id
=
fd_pll_readl
(
fd
,
0x003
);
if
(
id
<
0
)
return
-
EIO
;
if
(
id
!=
0xc3
)
{
pr_error
(
"Error in PLL communication
\n
"
" (got 0x%x, expected 0xc3)
\n
"
,
id
);
return
-
EIO
;
if
(
id
!=
0xc3
)
{
pr_error
(
"Error in PLL communication
\n
"
" (got 0x%x, expected 0xc3)
\n
"
,
id
);
return
-
EIO
;
}
}
return
0
;
}
int
fd_pll_init
(
struct
wrtd_fd_dev
*
fd
)
{
int
i
,
ret
;
unsigned
long
timeout
;
const
struct
ad9516_reg
*
r
;
int
i
,
ret
;
unsigned
long
timeout
;
const
struct
ad9516_reg
*
r
;
if
(
fd_pll_writel
(
fd
,
0x99
,
0x000
)
<
0
)
if
(
fd_pll_writel
(
fd
,
0x99
,
0x000
)
<
0
)
return
-
EIO
;
if
(
fd_pll_writel
(
fd
,
0x01
,
0x232
)
<
0
)
if
(
fd_pll_writel
(
fd
,
0x01
,
0x232
)
<
0
)
return
-
EIO
;
if
(
fd_pll_check
(
fd
)
<
0
)
return
-
EIO
;
/* Write the magic config */
for
(
i
=
0
,
r
=
__9516_regs
;
i
<
ARRAY_SIZE
(
__9516_regs
);
i
++
,
r
++
)
{
/* Write the magic config */
for
(
i
=
0
,
r
=
__9516_regs
;
i
<
ARRAY_SIZE
(
__9516_regs
);
i
++
,
r
++
)
{
if
(
fd_pll_writel
(
fd
,
r
->
val
,
r
->
reg
)
<
0
)
{
pr_error
(
"Error in configuring PLL (step %i)
\n
"
,
i
);
return
-
EIO
;
}
}
pr_error
(
"Error in configuring PLL (step %i)
\n
"
,
i
);
return
-
EIO
;
}
}
/* Enable the new config. */
if
(
fd_pll_writel
(
fd
,
0x01
,
0x232
)
<
0
)
if
(
fd_pll_writel
(
fd
,
0x01
,
0x232
)
<
0
)
return
-
EIO
;
if
(
fd_pll_check
(
fd
)
<
0
)
return
-
EIO
;
/* Wait (at most 500ms) for it to lock */
timeout
=
trtl_get_runtime_milliseconds
()
+
500
;
do
{
ret
=
fd_pll_readl
(
fd
,
0x1f
);
if
(
ret
<
0
)
return
-
EIO
;
if
(
ret
&
0x1
)
break
;
}
while
(
trtl_get_runtime_milliseconds
()
<
timeout
);
/* Wait (at most 500ms) for it to lock */
timeout
=
trtl_get_runtime_milliseconds
()
+
500
;
do
{
ret
=
fd_pll_readl
(
fd
,
0x1f
);
if
(
ret
<
0
)
return
-
EIO
;
if
(
ret
&
0x1
)
break
;
}
while
(
trtl_get_runtime_milliseconds
()
<
timeout
);
if
(
!
(
ret
&
0x1
))
return
-
EIO
;
...
...
@@ -213,19 +216,19 @@ int fd_pll_init(struct wrtd_fd_dev *fd)
if
(
fd_pll_check
(
fd
)
<
0
)
return
-
EIO
;
/*
* Synchronize the phase of all clock outputs
* (this is critical for the accuracy!)
*/
if
(
fd_pll_writel
(
fd
,
0x01
,
0x230
)
<
0
)
return
-
EIO
;
if
(
fd_pll_writel
(
fd
,
0x01
,
0x232
)
<
0
)
return
-
EIO
;
if
(
fd_pll_writel
(
fd
,
0x00
,
0x230
)
<
0
)
return
-
EIO
;
if
(
fd_pll_writel
(
fd
,
0x01
,
0x232
)
<
0
)
return
-
EIO
;
return
0
;
/*
* Synchronize the phase of all clock outputs
* (this is critical for the accuracy!)
*/
if
(
fd_pll_writel
(
fd
,
0x01
,
0x230
)
<
0
)
return
-
EIO
;
if
(
fd_pll_writel
(
fd
,
0x01
,
0x232
)
<
0
)
return
-
EIO
;
if
(
fd_pll_writel
(
fd
,
0x00
,
0x230
)
<
0
)
return
-
EIO
;
if
(
fd_pll_writel
(
fd
,
0x01
,
0x232
)
<
0
)
return
-
EIO
;
return
0
;
}
software/firmware/fd/hw/pll_config.h
View file @
1394f372
/**
* @file pll_config.h
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
struct
ad9516_reg
{
int
reg
;
int
val
;
int
reg
;
int
val
;
};
const
struct
ad9516_reg
__9516_regs
[]
=
{
{
0x0000
,
0x99
},
/* Config SPI */
{
0x0001
,
0x00
},
{
0x0002
,
0x10
},
{
0x0003
,
0xC3
},
{
0x0004
,
0x00
},
/* PLL */
{
0x0010
,
0x7C
},
/* PFD and charge pump */
{
0x0011
,
0x05
},
/* R divider (1) */
{
0x0012
,
0x00
},
/* R divider (2) */
{
0x0013
,
0x0C
},
/* A counter */
{
0x0014
,
0x12
},
/* B counter (1) */
{
0x0015
,
0x00
},
/* B counter (2) */
{
0x0016
,
0x05
},
/* PLL control (1) */
{
0x0017
,
0xb4
},
/* PLL control (2) PLL_STATUS = Lock Detect */
{
0x0018
,
0x07
},
/* PLL control (3) */
{
0x0019
,
0x00
},
/* PLL control (4) */
{
0x001A
,
0x00
},
/* PLL control (5) */
{
0x001B
,
0xE0
},
/* PLL control (6) */
{
0x001C
,
0x02
},
/* PLL control (7) */
{
0x001D
,
0x00
},
/* PLL control (8) */
{
0x001E
,
0x00
},
/* PLL control (9) */
{
0x001F
,
0x0E
},
/* PLL readback */
/* Fine Delay */
{
0x00A0
,
0x01
},
/* OUT6 Delay bypass */
{
0x00A1
,
0x00
},
/* OUT6 Delay full-scale */
{
0x00A2
,
0x00
},
/* OUT6 Delay fraction */
{
0x00A3
,
0x01
},
/* OUT7 Delay bypass */
{
0x00A4
,
0x00
},
/* OUT7 Delay full-scale */
{
0x00A5
,
0x00
},
/* OUT7 Delay fraction */
{
0x00A6
,
0x01
},
/* OUT8 Delay bypass */
{
0x00A7
,
0x00
},
/* OUT8 Delay full-scale */
{
0x00A8
,
0x00
},
/* OUT8 Delay fraction */
{
0x00A9
,
0x01
},
/* OUT9 Delay bypass */
{
0x00AA
,
0x00
},
/* OUT9 Delay full-scale */
{
0x00AB
,
0x00
},
/* OUT9 Delay fraction */
/* LVPECL */
{
0x00F0
,
0x08
},
/* OUT0 */
{
0x00F1
,
0x08
},
/* OUT1 */
{
0x00F2
,
0x08
},
/* OUT2 */
{
0x00F3
,
0x18
},
/* OUT3, inverted */
{
0x00F4
,
0x00
},
/* OUT4 */
{
0x00F5
,
0x08
},
/* OUT5 */
/* LVDS/CMOS */
{
0x0140
,
0x5A
},
/* OUT6 */
{
0x0141
,
0x5A
},
/* OUT7 */
{
0x0142
,
0x5B
},
/* OUT8 */
{
0x0143
,
0x42
},
/* OUT9 */
/* LVPECL Channel divider */
{
0x0190
,
0x00
},
/* Divider 0 (1) */
{
0x0191
,
0x80
},
/* Divider 0 (2) */
{
0x0192
,
0x00
},
/* Divider 0 (3) */
{
0x0193
,
0x00
},
/* Divider 1 (1) */
{
0x0194
,
0x80
},
/* Divider 1 (2) */
{
0x0195
,
0x00
},
/* Divider 1 (3) */
{
0x0196
,
0xFF
},
/* Divider 2 (1) */
{
0x0197
,
0x00
},
/* Divider 2 (2) */
{
0x0198
,
0x00
},
/* Divider 2 (3) */
/* LVDS/CMOS Channel divider */
{
0x0199
,
0x33
},
/* Divider 3 (1) */
{
0x019A
,
0x00
},
/* Divider 3 (2) */
{
0x019B
,
0x11
},
/* Divider 3 (3) */
{
0x019C
,
0x20
},
/* Divider 3 (4) */
{
0x019D
,
0x00
},
/* Divider 3 (5) */
{
0x019E
,
0x00
},
/* Divider 4 (1) */
{
0x019F
,
0x00
},
/* Divider 4 (2) */
{
0x01A0
,
0x11
},
/* Divider 4 (3) */
{
0x01A1
,
0x20
},
/* Divider 4 (4) */
{
0x01A2
,
0x00
},
/* Divider 4 (5) */
{
0x01A3
,
0x00
},
/* VCO Divider and CLK Input */
{
0x01E0
,
0x04
},
/* VCO divider VCODIV = 6 */
{
0x01E1
,
0x02
},
/* Input Clock */
/* System */
{
0x0230
,
0x00
},
/* Power down and sync */
{
0x0231
,
0x00
},
/* Update All registers */
{
0x0232
,
0x00
},
/* Update All registers */
{
0x0000
,
0x99
},
/* Config SPI */
{
0x0001
,
0x00
},
{
0x0002
,
0x10
},
{
0x0003
,
0xC3
},
{
0x0004
,
0x00
},
/* PLL */
{
0x0010
,
0x7C
},
/* PFD and charge pump */
{
0x0011
,
0x05
},
/* R divider (1) */
{
0x0012
,
0x00
},
/* R divider (2) */
{
0x0013
,
0x0C
},
/* A counter */
{
0x0014
,
0x12
},
/* B counter (1) */
{
0x0015
,
0x00
},
/* B counter (2) */
{
0x0016
,
0x05
},
/* PLL control (1) */
{
0x0017
,
0xb4
},
/* PLL control (2) PLL_STATUS = Lock Detect */
{
0x0018
,
0x07
},
/* PLL control (3) */
{
0x0019
,
0x00
},
/* PLL control (4) */
{
0x001A
,
0x00
},
/* PLL control (5) */
{
0x001B
,
0xE0
},
/* PLL control (6) */
{
0x001C
,
0x02
},
/* PLL control (7) */
{
0x001D
,
0x00
},
/* PLL control (8) */
{
0x001E
,
0x00
},
/* PLL control (9) */
{
0x001F
,
0x0E
},
/* PLL readback */
/* Fine Delay */
{
0x00A0
,
0x01
},
/* OUT6 Delay bypass */
{
0x00A1
,
0x00
},
/* OUT6 Delay full-scale */
{
0x00A2
,
0x00
},
/* OUT6 Delay fraction */
{
0x00A3
,
0x01
},
/* OUT7 Delay bypass */
{
0x00A4
,
0x00
},
/* OUT7 Delay full-scale */
{
0x00A5
,
0x00
},
/* OUT7 Delay fraction */
{
0x00A6
,
0x01
},
/* OUT8 Delay bypass */
{
0x00A7
,
0x00
},
/* OUT8 Delay full-scale */
{
0x00A8
,
0x00
},
/* OUT8 Delay fraction */
{
0x00A9
,
0x01
},
/* OUT9 Delay bypass */
{
0x00AA
,
0x00
},
/* OUT9 Delay full-scale */
{
0x00AB
,
0x00
},
/* OUT9 Delay fraction */
/* LVPECL */
{
0x00F0
,
0x08
},
/* OUT0 */
{
0x00F1
,
0x08
},
/* OUT1 */
{
0x00F2
,
0x08
},
/* OUT2 */
{
0x00F3
,
0x18
},
/* OUT3, inverted */
{
0x00F4
,
0x00
},
/* OUT4 */
{
0x00F5
,
0x08
},
/* OUT5 */
/* LVDS/CMOS */
{
0x0140
,
0x5A
},
/* OUT6 */
{
0x0141
,
0x5A
},
/* OUT7 */
{
0x0142
,
0x5B
},
/* OUT8 */
{
0x0143
,
0x42
},
/* OUT9 */
/* LVPECL Channel divider */
{
0x0190
,
0x00
},
/* Divider 0 (1) */
{
0x0191
,
0x80
},
/* Divider 0 (2) */
{
0x0192
,
0x00
},
/* Divider 0 (3) */
{
0x0193
,
0x00
},
/* Divider 1 (1) */
{
0x0194
,
0x80
},
/* Divider 1 (2) */
{
0x0195
,
0x00
},
/* Divider 1 (3) */
{
0x0196
,
0xFF
},
/* Divider 2 (1) */
{
0x0197
,
0x00
},
/* Divider 2 (2) */
{
0x0198
,
0x00
},
/* Divider 2 (3) */
/* LVDS/CMOS Channel divider */
{
0x0199
,
0x33
},
/* Divider 3 (1) */
{
0x019A
,
0x00
},
/* Divider 3 (2) */
{
0x019B
,
0x11
},
/* Divider 3 (3) */
{
0x019C
,
0x20
},
/* Divider 3 (4) */
{
0x019D
,
0x00
},
/* Divider 3 (5) */
{
0x019E
,
0x00
},
/* Divider 4 (1) */
{
0x019F
,
0x00
},
/* Divider 4 (2) */
{
0x01A0
,
0x11
},
/* Divider 4 (3) */
{
0x01A1
,
0x20
},
/* Divider 4 (4) */
{
0x01A2
,
0x00
},
/* Divider 4 (5) */
{
0x01A3
,
0x00
},
/* VCO Divider and CLK Input */
{
0x01E0
,
0x04
},
/* VCO divider VCODIV = 6 */
{
0x01E1
,
0x02
},
/* Input Clock */
/* System */
{
0x0230
,
0x00
},
/* Power down and sync */
{
0x0231
,
0x00
},
/* Update All registers */
{
0x0232
,
0x00
},
/* Update All registers */
};
software/firmware/fd/wrtd-fd.c
View file @
1394f372
/*
*
Copyright (C) 2013-2018 CERN (www.cern.ch)
*
Author: Federico Vaga <federico.vaga@cern.ch>
*
Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
/*
*
*
@file wrtd-fd.c
*
*
Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
...
...
@@ -26,17 +26,17 @@ static inline int fd_wr_present(struct wrtd_fd_dev *fd)
static
inline
int
fd_wr_link_up
(
struct
wrtd_fd_dev
*
fd
)
{
return
fd_readl
(
fd
,
FD_REG_TCR
)
&
FD_TCR_WR_LINK
;
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
;
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
;
return
1
;
}
static
inline
int
fd_wr_sync_timeout
(
void
)
...
...
@@ -54,9 +54,9 @@ static void fd_wr_enable_lock(struct wrtd_fd_dev *fd, int enable)
* 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
)
uint32_t
reg
)
{
dp_writel
(
value
,
reg
+
out
->
channel_addr
);
dp_writel
(
value
,
reg
+
out
->
channel_addr
);
}
...
...
@@ -65,7 +65,7 @@ static inline void fd_ch_writel(struct wrtd_fd_channel *out, uint32_t value,
*/
static
inline
uint32_t
fd_ch_readl
(
struct
wrtd_fd_channel
*
out
,
uint32_t
reg
)
{
return
dp_readl
(
reg
+
out
->
channel_addr
);
return
dp_readl
(
reg
+
out
->
channel_addr
);
}
...
...
@@ -74,9 +74,9 @@ static inline uint32_t fd_ch_readl (struct wrtd_fd_channel *out, uint32_t reg)
*/
static
void
pulse_queue_init
(
struct
lrt_pulse_queue
*
p
)
{
p
->
head
=
0
;
p
->
tail
=
0
;
p
->
count
=
0
;
p
->
head
=
0
;
p
->
tail
=
0
;
p
->
count
=
0
;
}
...
...
@@ -86,19 +86,19 @@ static void pulse_queue_init(struct lrt_pulse_queue *p)
*/
static
struct
wrtd_event
*
pulse_queue_push
(
struct
lrt_pulse_queue
*
p
)
{
struct
wrtd_event
*
ev
;
struct
wrtd_event
*
ev
;
if
(
p
->
count
==
FD_MAX_QUEUE_PULSES
)
return
NULL
;
if
(
p
->
count
==
FD_MAX_QUEUE_PULSES
)
return
NULL
;
ev
=
&
p
->
events
[
p
->
head
];
p
->
count
++
;
p
->
head
++
;
ev
=
&
p
->
events
[
p
->
head
];
p
->
count
++
;
p
->
head
++
;
if
(
p
->
head
==
FD_MAX_QUEUE_PULSES
)
p
->
head
=
0
;
if
(
p
->
head
==
FD_MAX_QUEUE_PULSES
)
p
->
head
=
0
;
return
ev
;
return
ev
;
}
...
...
@@ -107,7 +107,7 @@ static struct wrtd_event *pulse_queue_push(struct lrt_pulse_queue *p)
*/
static
inline
int
pulse_queue_empty
(
struct
lrt_pulse_queue
*
p
)
{
return
(
p
->
count
==
0
);
return
(
p
->
count
==
0
);
}
...
...
@@ -116,9 +116,9 @@ static inline int pulse_queue_empty(struct lrt_pulse_queue *p)
*/
static
struct
wrtd_event
*
pulse_queue_front
(
struct
lrt_pulse_queue
*
p
)
{
if
(
!
p
->
count
)
return
NULL
;
return
&
p
->
events
[
p
->
tail
];
if
(
!
p
->
count
)
return
NULL
;
return
&
p
->
events
[
p
->
tail
];
}
...
...
@@ -127,11 +127,11 @@ static struct wrtd_event *pulse_queue_front(struct lrt_pulse_queue *p)
*/
static
void
pulse_queue_pop
(
struct
lrt_pulse_queue
*
p
)
{
p
->
tail
++
;
p
->
tail
++
;
if
(
p
->
tail
==
FD_MAX_QUEUE_PULSES
)
p
->
tail
=
0
;
p
->
count
--
;
if
(
p
->
tail
==
FD_MAX_QUEUE_PULSES
)
p
->
tail
=
0
;
p
->
count
--
;
}
/**
...
...
@@ -142,47 +142,47 @@ static int check_output_timeout (struct wrtd_fd_channel *out)
{
uint32_t
now_sec
;
uint32_t
now_ns
;
int
delta
;
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
;
/*
* 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."
);
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? */
/* 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
);
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
)
struct
wrtd_event
*
ev
,
struct
lrt_pulse_queue
*
q
,
unsigned
reason
)
{
out
->
idle
=
1
;
out
->
idle
=
1
;
if
(
pulse_queue_empty
(
q
))
return
;
if
(
pulse_queue_empty
(
q
))
return
;
/* Drop the pulse */
pulse_queue_pop
(
q
);
/* Drop the pulse */
pulse_queue_pop
(
q
);
/* Disarm the FD output */
fd_ch_writel
(
out
,
FD_DCR_MODE
,
FD_REG_DCR
);
/* Disarm the FD output */
fd_ch_writel
(
out
,
FD_DCR_MODE
,
FD_REG_DCR
);
wrtd_log
(
WRTD_LOG_MSG_EV_DISCARDED
,
reason
,
NULL
,
ev
,
NULL
);
}
...
...
@@ -195,118 +195,118 @@ static void drop_trigger(struct wrtd_fd_channel *out,
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
())
{
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
);
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
))
{
}
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
,
drop_trigger
(
out
,
ev
,
q
,
WRTD_LOG_DISCARD_TIMEOUT
);
}
}
else
{
}
else
{
/* Has been triggered. */
wrtd_log
(
WRTD_LOG_MSG_EV_CONSUMED
,
WRTD_LOG_CONSUMED_DONE
,
NULL
,
ev
,
NULL
);
pulse_queue_pop
(
q
);
out
->
idle
=
1
;
}
return
;
}
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
;
/* 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
;
ev
=
pulse_queue_front
(
q
);
ts
=
&
ev
->
ts
;
if
(
!
wr_is_timing_ok
())
{
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
)),
/* 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 */
/* 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_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
);
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
,
NULL
,
ev
,
NULL
);
ts_add2_ns
(
ts
,
8000
);
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
;
/*
* 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
int
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
;
struct
wrtd_fd_channel
*
out
=
&
fd
->
channels
[
ch
];
struct
wrtd_event
*
pq_ev
;
pq_ev
=
pulse_queue_push
(
&
out
->
queue
);
if
(
!
pq_ev
)
{
return
-
EOVERFLOW
;
}
pq_ev
=
pulse_queue_push
(
&
out
->
queue
);
if
(
!
pq_ev
)
{
return
-
EOVERFLOW
;
}
*
pq_ev
=
*
ev
;
*
pq_ev
=
*
ev
;
return
0
;
}
static
void
fd_outputs
(
struct
wrtd_fd_dev
*
fd
)
{
int
i
;
int
i
;
for
(
i
=
0
;
i
<
FD_NUM_CHANNELS
;
i
++
)
fd_output
(
fd
,
i
);
for
(
i
=
0
;
i
<
FD_NUM_CHANNELS
;
i
++
)
fd_output
(
fd
,
i
);
}
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
;
/* 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
;
}
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-fd.h
View file @
1394f372
/**
* @file wrtd-fd.h
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __FINE_DELAY_WRAPPER_H
#define __FINE_DELAY_WRAPPER_H
#include "wrtd-common.h"
/* Channels are called 1..4 in all docs. Internally it's 0..3 */
#define FD_CH_1
0
#define FD_CH_LAST
3
#define FD_CH_1
0
#define FD_CH_LAST
3
#define FD_NUM_CHANNELS 4
#define FD_CH_EXT(i)
((i) + 1)
#define FD_CH_EXT(i)
((i) + 1)
#define FD_NUM_TAPS
1024
/* This is an hardware feature of SY89295U */
#define FD_CAL_STEPS
1024
/* This is a parameter: must be power of 2 */
#define FD_NUM_TAPS
1024
/* This is an hardware feature of SY89295U */
#define FD_CAL_STEPS
1024
/* This is a parameter: must be power of 2 */
#define FD_MAGIC_FPGA 0xf19ede1a
/* FD_REG_IDR content */
...
...
@@ -20,17 +28,17 @@
/* ACAM TDC operation modes */
enum
fd_acam_modes
{
ACAM_RMODE
,
ACAM_IMODE
,
ACAM_GMODE
ACAM_RMODE
,
ACAM_IMODE
,
ACAM_GMODE
};
#define FD_GPIO_TERM_EN
0x0001
/* Input terminator enable */
#define FD_GPIO_OUTPUT_EN(x)
\
(1 << (6-(x)))
/* Output driver enable */
#define FD_GPIO_OUTPUT_MASK
0x003c
/* Output driver enable */
#define FD_GPIO_TRIG_INTERNAL
0x0040
/* TDC trig (1=in, 1=fpga) */
#define FD_GPIO_CAL_DISABLE
0x0080
/* 0 enables calibration */
#define FD_GPIO_TERM_EN
0x0001
/* Input terminator enable */
#define FD_GPIO_OUTPUT_EN(x)
\
(1 << (6-(x)))
/* Output driver enable */
#define FD_GPIO_OUTPUT_MASK
0x003c
/* Output driver enable */
#define FD_GPIO_TRIG_INTERNAL
0x0040
/* TDC trig (1=in, 1=fpga) */
#define FD_GPIO_CAL_DISABLE
0x0080
/* 0 enables calibration */
/*
...
...
@@ -42,23 +50,23 @@ enum fd_acam_modes {
#define ACAM_MASK ((1<<29) - 1)
/* 28 bits */
/* SPI Bus chip selects */
#define FD_CS_DAC
0
/* DAC for VCXO */
#define FD_CS_PLL
1
/* AD9516 PLL */
#define FD_CS_GPIO
2
/* MCP23S17 GPIO */
#define FD_CS_DAC
0
/* DAC for VCXO */
#define FD_CS_PLL
1
/* AD9516 PLL */
#define FD_CS_GPIO
2
/* MCP23S17 GPIO */
/* MCP23S17 register addresses (only ones which are used by the lib) */
#define FD_MCP_IODIR
0x00
#define FD_MCP_IPOL
0x01
#define FD_MCP_IOCON
0x0a
#define FD_MCP_GPIO
0x12
#define FD_MCP_OLAT
0x14
#define FD_MCP_IODIR
0x00
#define FD_MCP_IPOL
0x01
#define FD_MCP_IOCON
0x0a
#define FD_MCP_GPIO
0x12
#define FD_MCP_OLAT
0x14
#define FD_MAX_QUEUE_PULSES 4
/* Pulse FIFO for a single Fine Delay output */
struct
lrt_pulse_queue
{
struct
wrtd_event
events
[
FD_MAX_QUEUE_PULSES
];
int
head
,
tail
,
count
;
struct
wrtd_event
events
[
FD_MAX_QUEUE_PULSES
];
int
head
,
tail
,
count
;
};
struct
wrtd_fd_channel
{
...
...
@@ -109,8 +117,8 @@ int fd_sim_init(struct wrtd_fd_dev *fd);
#define fd_gpio_set(fd, pin) fd_gpio_set_clr(fd, (pin), 1)
#define fd_gpio_clr(fd, pin) fd_gpio_set_clr(fd, (pin), 0)
#define FD_GPIO_IN
0
#define FD_GPIO_OUT
1
#define FD_GPIO_IN
0
#define FD_GPIO_OUT
1
static
inline
void
fd_writel
(
struct
wrtd_fd_dev
*
fd
,
uint32_t
val
,
uint32_t
reg
)
{
...
...
@@ -119,24 +127,24 @@ static inline void fd_writel(struct wrtd_fd_dev *fd, uint32_t val, uint32_t reg)
static
inline
uint32_t
fd_readl
(
struct
wrtd_fd_dev
*
fd
,
uint32_t
reg
)
{
return
dp_readl
(
fd
->
io_addr
+
reg
);
return
dp_readl
(
fd
->
io_addr
+
reg
);
}
static
inline
uint32_t
fd_drv_ch_readl
(
struct
wrtd_fd_dev
*
fd
,
int
ch
,
unsigned
long
reg
)
{
return
fd_readl
(
fd
,
0x100
+
ch
*
0x100
+
reg
);
return
fd_readl
(
fd
,
0x100
+
ch
*
0x100
+
reg
);
}
static
inline
void
fd_drv_ch_writel
(
struct
wrtd_fd_dev
*
fd
,
int
ch
,
uint32_t
v
,
unsigned
long
reg
)
{
fd_writel
(
fd
,
v
,
0x100
+
ch
*
0x100
+
reg
);
fd_writel
(
fd
,
v
,
0x100
+
ch
*
0x100
+
reg
);
}
static
inline
uint64_t
div_u64
(
uint64_t
dividend
,
uint32_t
divisor
)
{
return
dividend
/
divisor
;
return
dividend
/
divisor
;
}
...
...
software/firmware/fd/wrtd-rt-fd.c
View file @
1394f372
/*
*
Copyright (C) 2013-2018 CERN (www.cern.ch)
*
Author: Federico Vaga <federico.vaga@cern.ch>
*
Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
/*
*
*
@file wrtd-rt-fd.c
*
*
Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
...
...
@@ -74,14 +74,14 @@ static int wrtd_local_output(struct wrtd_event *ev, unsigned ch)
*/
static
int
wrtd_user_init
(
void
)
{
if
(
!
fd_wr_present
(
&
fd0
))
{
pr_error
(
"WhiteRabbit not found
\n\r
"
);
return
-
EINVAL
;
}
if
(
!
fd_wr_present
(
&
fd0
))
{
pr_error
(
"WhiteRabbit not found
\n\r
"
);
return
-
EINVAL
;
}
wr_enable_lock
(
0
);
wr_enable_lock
(
0
);
/* Channels */
/* Channels */
wrtd_fd_data_init
(
&
fd0
);
#ifdef SIMULATION
...
...
@@ -90,9 +90,9 @@ static int wrtd_user_init(void)
fd_init
(
&
fd0
);
#endif
pr_debug
(
"rt-output firmware initialized.
\n\r
"
);
pr_debug
(
"rt-output firmware initialized.
\n\r
"
);
return
0
;
return
0
;
}
static
void
wrtd_io
(
void
)
...
...
software/firmware/tdc/configs/mt_defconfig
View file @
1394f372
#
# Automatically generated file; DO NOT EDIT.
# fmc-svec-carrier fw-01 demo configuration
#
#
...
...
software/firmware/tdc/hw/tdc_regs.h
View file @
1394f372
/*
*
tdc_register
s.h
/*
*
*
@file tdc_reg
s.h
*
* Copyright (c) 2012 CERN (http://www.cern.ch)
* Author: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
* Copyright (c) 2012-2019 CERN (home.cern)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; version 2 of the License.
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __TDC_REGISTERS_H
...
...
@@ -20,116 +17,115 @@
#define TDC_REG_ACAM_CONFIG(index) (0x0000 + (index * 4))
/* TDC core registers */
#define TDC_REG_START_UTC
0x0080
#define TDC_REG_INPUT_ENABLE
0x0084
#define TDC_REG_IRQ_THRESHOLD 0x0090
#define TDC_REG_IRQ_TIMEOUT 0x0094
#define TDC_REG_DAC_TUNE 0x0098
#define TDC_REG_CURRENT_UTC 0x00a0
#define TDC_REG_BUFFER_PTR 0x00a8
#define TDC_REG_CTRL 0x00fc
#define TDC_REG_WR_CTRL 0x00b4
#define TDC_REG_WR_STAT 0x00b0
#define TDC_WR_CTRL_ENABLE
BIT(0)
#define TDC_WR_STAT_ENABLED
BIT(6)
#define TDC_WR_STAT_LINK
BIT(2)
#define TDC_WR_STAT_TIME_VALID
BIT(8)
#define TDC_WR_STAT_AUX_LOCKED
BIT(4)
#define TDC_REG_START_UTC
0x0080
#define TDC_REG_INPUT_ENABLE
0x0084
#define TDC_REG_IRQ_THRESHOLD
0x0090
#define TDC_REG_IRQ_TIMEOUT
0x0094
#define TDC_REG_DAC_TUNE
0x0098
#define TDC_REG_CURRENT_UTC
0x00a0
#define TDC_REG_BUFFER_PTR
0x00a8
#define TDC_REG_CTRL
0x00fc
#define TDC_REG_WR_CTRL
0x00b4
#define TDC_REG_WR_STAT
0x00b0
#define TDC_WR_CTRL_ENABLE
BIT(0)
#define TDC_WR_STAT_ENABLED
BIT(6)
#define TDC_WR_STAT_LINK
BIT(2)
#define TDC_WR_STAT_TIME_VALID
BIT(8)
#define TDC_WR_STAT_AUX_LOCKED
BIT(4)
/* TDC_REG_CTRL bits */
#define TDC_CTRL_EN_ACQ
BIT(0)
#define TDC_CTRL_DIS_ACQ
BIT(1)
#define TDC_CTRL_LOAD_ACAM_CFG
BIT(2)
#define TDC_CTRL_READ_ACAM_CFG
BIT(3)
#define TDC_CTRL_READ_ACAM_STAT
BIT(4)
#define TDC_CTRL_READ_ACAM_IFIFO1
BIT(5)
#define TDC_CTRL_READ_ACAM_IFIFO2
BIT(6)
#define TDC_CTRL_READ_ACAM_START01_R
BIT(7)
#define TDC_CTRL_RESET_ACAM
BIT(8)
#define TDC_CTRL_LOAD_UTC
BIT(9)
#define TDC_CTRL_CLEAR_DACAPO_FLAG
BIT(10)
#define TDC_CTRL_CONFIG_DAC
BIT(11)
#define TDC_CTRL_EN_ACQ
BIT(0)
#define TDC_CTRL_DIS_ACQ
BIT(1)
#define TDC_CTRL_LOAD_ACAM_CFG
BIT(2)
#define TDC_CTRL_READ_ACAM_CFG
BIT(3)
#define TDC_CTRL_READ_ACAM_STAT
BIT(4)
#define TDC_CTRL_READ_ACAM_IFIFO1
BIT(5)
#define TDC_CTRL_READ_ACAM_IFIFO2
BIT(6)
#define TDC_CTRL_READ_ACAM_START01_R
BIT(7)
#define TDC_CTRL_RESET_ACAM
BIT(8)
#define TDC_CTRL_LOAD_UTC
BIT(9)
#define TDC_CTRL_CLEAR_DACAPO_FLAG
BIT(10)
#define TDC_CTRL_CONFIG_DAC
BIT(11)
/* TDC_REG_INPUT_ENABLE bits */
#define TDC_INPUT_ENABLE_FLAG BIT(7)
#define TDC_INPUT_ENABLE_CH1 BIT(16)
#define TDC_INPUT_ENABLE_CH2 BIT(17)
#define TDC_INPUT_ENABLE_CH3 BIT(18)
#define TDC_INPUT_ENABLE_CH4 BIT(19)
#define TDC_INPUT_ENABLE_CH5 BIT(20)
#define TDC_INPUT_ENABLE_FLAG
BIT(7)
#define TDC_INPUT_ENABLE_CH1
BIT(16)
#define TDC_INPUT_ENABLE_CH2
BIT(17)
#define TDC_INPUT_ENABLE_CH3
BIT(18)
#define TDC_INPUT_ENABLE_CH4
BIT(19)
#define TDC_INPUT_ENABLE_CH5
BIT(20)
#define TDC_INPUT_ENABLE_CH_ALL (TDC_INPUT_ENABLE_CH1 | \
TDC_INPUT_ENABLE_CH2 | \
TDC_INPUT_ENABLE_CH3 | \
TDC_INPUT_ENABLE_CH4 | \
TDC_INPUT_ENABLE_CH5)
TDC_INPUT_ENABLE_CH2 | \
TDC_INPUT_ENABLE_CH3 | \
TDC_INPUT_ENABLE_CH4 | \
TDC_INPUT_ENABLE_CH5)
/* IRQ controler registers */
#define TDC_REG_EIC_IDR
0x0
#define TDC_REG_EIC_IER
0x4
#define TDC_REG_EIC_IMR
0x8
#define TDC_REG_EIC_ISR
0xc
#define TDC_REG_EIC_IDR
0x0
#define TDC_REG_EIC_IER
0x4
#define TDC_REG_EIC_IMR
0x8
#define TDC_REG_EIC_ISR
0xc
/* IRQ status/enable bits */
#define TDC_IRQ_TDC_TSTAMP
BIT(0)
#define TDC_IRQ_TDC_TIME
BIT(1)
#define TDC_IRQ_TDC_TSTAMP
BIT(0)
#define TDC_IRQ_TDC_TIME
BIT(1)
#define TDC_EVENT_BUFFER_SIZE
256
#define TDC_EVENT_CHANNEL_MASK
0xF
#define TDC_EVENT_SLOPE_MASK
0xF0
#define TDC_EVENT_FIFO_LF_MASK
0xF00
#define TDC_EVENT_FIFO_EF_MASK
0xF000
#define TDC_EVENT_DACAPO_FLAG
BIT(0)
#define TDC_EVENT_BUFFER_SIZE
256
#define TDC_EVENT_CHANNEL_MASK
0xF
#define TDC_EVENT_SLOPE_MASK
0xF0
#define TDC_EVENT_FIFO_LF_MASK
0xF00
#define TDC_EVENT_FIFO_EF_MASK
0xF000
#define TDC_EVENT_DACAPO_FLAG
BIT(0)
/* FIFO registers */
#define TDC_FIFO_OFFSET
0x100
#define TDC_FIFO_LAST
0x0
#define TDC_FIFO_LAST_N
4
#define TDC_FIFO_LAST_CSR
0x10
#define TDC_FIFO_LAST_CSR_VALID
BIT(0)
#define TDC_FIFO_LAST_CSR_RST_SEQ
BIT(1)
#define TDC_FIFO_OUT
0x14
#define TDC_FIFO_OUT_N
4
#define TDC_FIFO_CSR
0x24
#define TDC_FIFO_CSR_EMPTY
BIT(17)
#define TDC_FIFO_CSR_FULL
BIT(16)
#define TDC_FIFO_OFFSET
0x100
#define TDC_FIFO_LAST
0x0
#define TDC_FIFO_LAST_N
4
#define TDC_FIFO_LAST_CSR
0x10
#define TDC_FIFO_LAST_CSR_VALID
BIT(0)
#define TDC_FIFO_LAST_CSR_RST_SEQ
BIT(1)
#define TDC_FIFO_OUT
0x14
#define TDC_FIFO_OUT_N
4
#define TDC_FIFO_CSR
0x24
#define TDC_FIFO_CSR_EMPTY
BIT(17)
#define TDC_FIFO_CSR_FULL
BIT(16)
#define TDC_FIFO_CSR_USEDW
/* Carrier CSRs */
#define TDC_REG_CARRIER_CTL0
0x0
/* a.k.a. Carrier revision/PCB id reg */
#define TDC_REG_CARRIER_STATUS
0x4
#define TDC_REG_CARRIER_CTL1
0x8
#define TDC_REG_CARRIER_RST
0xc
#define TDC_REG_CARRIER_CTL0
0x0
/* a.k.a. Carrier revision/PCB id reg */
#define TDC_REG_CARRIER_STATUS
0x4
#define TDC_REG_CARRIER_CTL1
0x8
#define TDC_REG_CARRIER_RST
0xc
#define TDC_CARRIER_CTL0_PLL_STAT_FMC0
BIT(5)
#define TDC_CARRIER_CTL0_PLL_STAT_FMC1
BIT(6)
#define TDC_CARRIER_CTL0_PLL_STAT_FMC0 BIT(5)
#define TDC_CARRIER_CTL0_PLL_STAT_FMC1 BIT(6)
#define TDC_CARRIER_CTL1_RSTN_FMC0
BIT(3)
#define TDC_CARRIER_CTL1_RSTN_FMC1
BIT(4)
#define TDC_CARRIER_CTL1_RSTN_FMC0
BIT(3)
#define TDC_CARRIER_CTL1_RSTN_FMC1
BIT(4)
/* Gennum DMA registers (not defined in the SPEC driver headers) */
#define TDC_REG_DMA_CTRL 0x0
#define TDC_REG_DMA_STAT 0x4
#define TDC_REG_DMA_C_START 0x8
#define TDC_REG_DMA_H_START_L 0x0c
#define TDC_REG_DMA_H_START_H 0x10
#define TDC_REG_DMA_NEXT_L 0x18
#define TDC_REG_DMA_NEXT_H 0x1c
#define TDC_REG_DMA_LEN 0x14
#define TDC_REG_DMA_ATTRIB 0x20
#define TDC_REG_DMA_CTRL
0x0
#define TDC_REG_DMA_STAT
0x4
#define TDC_REG_DMA_C_START
0x8
#define TDC_REG_DMA_H_START_L
0x0c
#define TDC_REG_DMA_H_START_H
0x10
#define TDC_REG_DMA_NEXT_L
0x18
#define TDC_REG_DMA_NEXT_H
0x1c
#define TDC_REG_DMA_LEN
0x14
#define TDC_REG_DMA_ATTRIB
0x20
/* TDC_REG_DMA_STAT bits */
#define TDC_DMA_STAT_MASK 0x7
#define TDC_DMA_STAT_DONE 0x1
#define TDC_DMA_STAT_ERROR 0x3
#define TDC_DMA_STAT_MASK
0x7
#define TDC_DMA_STAT_DONE
0x1
#define TDC_DMA_STAT_ERROR
0x3
/* TDC core submodule offsets (wrs to the TDC control registers block) */
#define TDC_MEZZ_ONEWIRE_OFFSET (-0x1000)
#define TDC_MEZZ_EIC_OFFSET (0x1000)
#define TDC_MEZZ_I2C_OFFSET (0x2000)
#define TDC_MEZZ_MEM_OFFSET (0x3000)
#define TDC_MEZZ_ONEWIRE_OFFSET -0x1000
#define TDC_MEZZ_EIC_OFFSET 0x1000
#define TDC_MEZZ_I2C_OFFSET 0x2000
#define TDC_MEZZ_MEM_OFFSET 0x3000
#endif
/* __TDC_REGISTERS_H */
software/firmware/tdc/wrtd-rt-tdc.c
View file @
1394f372
/*
*
Copyright (C) 2013-2018 CERN (www.cern.ch)
*
Author: Federico Vaga <federico.vaga@cern.ch>
*
Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
/*
*
*
@file wrtd-rt-tdc.c
*
*
Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include "mockturtle-rt.h"
#include <mockturtle-framework.h>
#include "wrtd-common.h"
...
...
@@ -75,11 +74,11 @@ static int wrtd_user_init(void)
{
tdc_init
(
&
tdc0
);
wr_enable_lock
(
0
);
wr_enable_lock
(
0
);
pr_debug
(
"rt-tdc firmware initialized.
\n\r
"
);
pr_debug
(
"rt-tdc firmware initialized.
\n\r
"
);
return
0
;
return
0
;
}
static
void
wrtd_io
(
void
)
...
...
software/firmware/tdc/wrtd-tdc.c
View file @
1394f372
/*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Dimitris Lampridis <dimitris.lampridis@cern.ch>
/**
* @file wrtd-tdc.c
*
* Copyright (c) 2018-2019 CERN (home.cern)
*
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
...
...
@@ -22,7 +23,6 @@
#define DEFAULT_DEAD_TIME (80000/16)
struct
wrtd_tdc_dev
{
uint32_t
io_addr
;
/* FIXME: base channel (to create the event id). */
...
...
@@ -31,202 +31,202 @@ struct wrtd_tdc_dev {
static
inline
void
tdc_writel
(
const
struct
wrtd_tdc_dev
*
dev
,
uint32_t
value
,
uint32_t
reg
)
{
dp_writel
(
value
,
dev
->
io_addr
+
reg
);
dp_writel
(
value
,
dev
->
io_addr
+
reg
);
}
static
inline
uint32_t
tdc_readl
(
const
struct
wrtd_tdc_dev
*
dev
,
uint32_t
reg
)
{
return
dp_readl
(
dev
->
io_addr
+
reg
);
return
dp_readl
(
dev
->
io_addr
+
reg
);
}
static
const
struct
{
uint32_t
reg
;
uint32_t
value
;
uint32_t
reg
;
uint32_t
value
;
}
acam_config
[
NB_ACAM_REGS
]
=
{
{
0
,
AR0_ROsc
|
AR0_HQSel
|
AR0_TRiseEn
(
0
)
|
AR0_TRiseEn
(
1
)
|
AR0_TRiseEn
(
2
)
|
AR0_TRiseEn
(
3
)
|
AR0_TRiseEn
(
4
)
|
AR0_TRiseEn
(
5
)
|
AR0_TFallEn
(
1
)
|
AR0_TFallEn
(
2
)
|
AR0_TFallEn
(
3
)
|
AR0_TFallEn
(
4
)
|
AR0_TFallEn
(
5
)},
{
1
,
0
},
{
2
,
AR2_IMode
|
AR2_Disable
(
6
)
|
AR2_Disable
(
7
)
|
AR2_Disable
(
8
)},
{
3
,
0
},
{
4
,
AR4_StartTimer
(
15
)
|
AR4_EFlagHiZN
},
{
5
,
AR5_StartOff1
(
2000
)},
{
6
,
AR6_Fill
(
0xfc
)},
{
7
,
AR7_RefClkDiv
(
7
)
|
AR7_HSDiv
(
234
)
|
AR7_NegPhase
|
AR7_ResAdj
},
{
11
,
AR11_HFifoErrU
(
0
)
|
AR11_HFifoErrU
(
1
)
|
AR11_HFifoErrU
(
2
)
|
AR11_HFifoErrU
(
3
)
|
AR11_HFifoErrU
(
4
)
|
AR11_HFifoErrU
(
5
)
|
AR11_HFifoErrU
(
6
)
|
AR11_HFifoErrU
(
7
)},
{
12
,
AR12_StartNU
|
AR12_HFifoE
},
{
14
,
0
}
{
0
,
AR0_ROsc
|
AR0_HQSel
|
AR0_TRiseEn
(
0
)
|
AR0_TRiseEn
(
1
)
|
AR0_TRiseEn
(
2
)
|
AR0_TRiseEn
(
3
)
|
AR0_TRiseEn
(
4
)
|
AR0_TRiseEn
(
5
)
|
AR0_TFallEn
(
1
)
|
AR0_TFallEn
(
2
)
|
AR0_TFallEn
(
3
)
|
AR0_TFallEn
(
4
)
|
AR0_TFallEn
(
5
)},
{
1
,
0
},
{
2
,
AR2_IMode
|
AR2_Disable
(
6
)
|
AR2_Disable
(
7
)
|
AR2_Disable
(
8
)},
{
3
,
0
},
{
4
,
AR4_StartTimer
(
15
)
|
AR4_EFlagHiZN
},
{
5
,
AR5_StartOff1
(
2000
)},
{
6
,
AR6_Fill
(
0xfc
)},
{
7
,
AR7_RefClkDiv
(
7
)
|
AR7_HSDiv
(
234
)
|
AR7_NegPhase
|
AR7_ResAdj
},
{
11
,
AR11_HFifoErrU
(
0
)
|
AR11_HFifoErrU
(
1
)
|
AR11_HFifoErrU
(
2
)
|
AR11_HFifoErrU
(
3
)
|
AR11_HFifoErrU
(
4
)
|
AR11_HFifoErrU
(
5
)
|
AR11_HFifoErrU
(
6
)
|
AR11_HFifoErrU
(
7
)},
{
12
,
AR12_StartNU
|
AR12_HFifoE
},
{
14
,
0
}
};
static
inline
int
acam_is_pll_locked
(
struct
wrtd_tdc_dev
*
dev
)
{
uint32_t
status
;
uint32_t
status
;
tdc_writel
(
dev
,
TDC_CTRL_READ_ACAM_CFG
,
tdc_writel
(
dev
,
TDC_CTRL_READ_ACAM_CFG
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
udelay
(
100
);
udelay
(
100
);
status
=
tdc_readl
(
dev
,
BASE_DP_TDC_REGS
+
TDC_REG_ACAM_READBACK
(
12
));
status
=
tdc_readl
(
dev
,
BASE_DP_TDC_REGS
+
TDC_REG_ACAM_READBACK
(
12
));
return
!
(
status
&
AR12_NotLocked
);
return
!
(
status
&
AR12_NotLocked
);
}
int
tdc_acam_init
(
struct
wrtd_tdc_dev
*
dev
)
{
int
i
;
int
i
;
pr_debug
(
"%s: initializing ACAM TDC...
\n
"
,
__func__
);
pr_debug
(
"%s: initializing ACAM TDC...
\n
"
,
__func__
);
tdc_writel
(
dev
,
TDC_CTRL_RESET_ACAM
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
udelay
(
100
);
tdc_writel
(
dev
,
TDC_CTRL_RESET_ACAM
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
udelay
(
100
);
for
(
i
=
0
;
i
<
NB_ACAM_REGS
;
i
++
)
{
tdc_writel
(
dev
,
acam_config
[
i
].
value
,
for
(
i
=
0
;
i
<
NB_ACAM_REGS
;
i
++
)
{
tdc_writel
(
dev
,
acam_config
[
i
].
value
,
BASE_DP_TDC_REGS
+
TDC_REG_ACAM_CONFIG
(
acam_config
[
i
].
reg
));
}
}
/* commit ACAM config regs */
tdc_writel
(
dev
,
TDC_CTRL_LOAD_ACAM_CFG
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
udelay
(
100
);
/* commit ACAM config regs */
tdc_writel
(
dev
,
TDC_CTRL_LOAD_ACAM_CFG
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
udelay
(
100
);
/* and reset the chip (keeps configuration) */
tdc_writel
(
dev
,
TDC_CTRL_RESET_ACAM
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
udelay
(
100
);
/* and reset the chip (keeps configuration) */
tdc_writel
(
dev
,
TDC_CTRL_RESET_ACAM
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
udelay
(
100
);
/* wait for the ACAM's PLL to lock (2 seconds) */
mdelay
(
2000
);
if
(
acam_is_pll_locked
(
dev
))
{
pr_debug
(
"%s: ACAM initialization OK.
\n
"
,
__func__
);
return
0
;
}
/* wait for the ACAM's PLL to lock (2 seconds) */
mdelay
(
2000
);
if
(
acam_is_pll_locked
(
dev
))
{
pr_debug
(
"%s: ACAM initialization OK.
\n
"
,
__func__
);
return
0
;
}
pr_error
(
"%s: ACAM PLL doesn't lock
\n
"
,
__func__
);
return
-
EIO
;
pr_error
(
"%s: ACAM PLL doesn't lock
\n
"
,
__func__
);
return
-
EIO
;
}
static
int
tdc_time_init
(
struct
wrtd_tdc_dev
*
dev
)
{
/* program the VCXO DAC to the default calibration value */
tdc_writel
(
dev
,
TDC_VCXO_DEFAULT_TUNE
,
BASE_DP_TDC_REGS
+
TDC_REG_DAC_TUNE
);
tdc_writel
(
dev
,
TDC_CTRL_CONFIG_DAC
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
/* program the VCXO DAC to the default calibration value */
tdc_writel
(
dev
,
TDC_VCXO_DEFAULT_TUNE
,
BASE_DP_TDC_REGS
+
TDC_REG_DAC_TUNE
);
tdc_writel
(
dev
,
TDC_CTRL_CONFIG_DAC
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
/* set TAI time to zero */
tdc_writel
(
dev
,
0
,
BASE_DP_TDC_REGS
+
TDC_REG_START_UTC
);
tdc_writel
(
dev
,
TDC_CTRL_LOAD_UTC
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
/* set TAI time to zero */
tdc_writel
(
dev
,
0
,
BASE_DP_TDC_REGS
+
TDC_REG_START_UTC
);
tdc_writel
(
dev
,
TDC_CTRL_LOAD_UTC
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
return
0
;
return
0
;
}
static
int
tdc_enable_termination
(
struct
wrtd_tdc_dev
*
tdc
,
int
channel
,
int
enable
)
{
uint32_t
ien
;
uint32_t
ien
;
ien
=
tdc_readl
(
tdc
,
BASE_DP_TDC_REGS
+
TDC_REG_INPUT_ENABLE
);
ien
=
tdc_readl
(
tdc
,
BASE_DP_TDC_REGS
+
TDC_REG_INPUT_ENABLE
);
if
(
enable
)
ien
|=
(
1
<<
channel
);
else
ien
&=
~
(
1
<<
channel
);
if
(
enable
)
ien
|=
(
1
<<
channel
);
else
ien
&=
~
(
1
<<
channel
);
tdc_writel
(
tdc
,
ien
,
BASE_DP_TDC_REGS
+
TDC_REG_INPUT_ENABLE
);
tdc_writel
(
tdc
,
ien
,
BASE_DP_TDC_REGS
+
TDC_REG_INPUT_ENABLE
);
return
0
;
return
0
;
}
static
int
tdc_channels_init
(
struct
wrtd_tdc_dev
*
tdc
)
{
int
i
;
int
i
;
for
(
i
=
0
;
i
<
TDC_NUM_CHANNELS
;
i
++
)
{
/* termination is off by default */
tdc_enable_termination
(
tdc
,
i
,
0
);
}
for
(
i
=
0
;
i
<
TDC_NUM_CHANNELS
;
i
++
)
{
/* termination is off by default */
tdc_enable_termination
(
tdc
,
i
,
0
);
}
return
0
;
return
0
;
}
static
void
tdc_enable_acquisition
(
struct
wrtd_tdc_dev
*
tdc
,
int
enable
)
{
uint32_t
ien
;
ien
=
tdc_readl
(
tdc
,
BASE_DP_TDC_REGS
+
TDC_REG_INPUT_ENABLE
);
if
(
enable
)
{
/* Enable TDC acquisition */
tdc_writel
(
tdc
,
ien
|
TDC_INPUT_ENABLE_CH_ALL
|
TDC_INPUT_ENABLE_FLAG
,
BASE_DP_TDC_REGS
+
TDC_REG_INPUT_ENABLE
);
/* Enable ACAM acquisition */
tdc_writel
(
tdc
,
TDC_CTRL_EN_ACQ
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
}
else
{
/* Disable ACAM acquisition */
tdc_writel
(
tdc
,
TDC_CTRL_DIS_ACQ
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
/* Disable TDC acquisition */
tdc_writel
(
tdc
,
ien
&
~
(
TDC_INPUT_ENABLE_CH_ALL
|
TDC_INPUT_ENABLE_FLAG
),
uint32_t
ien
;
ien
=
tdc_readl
(
tdc
,
BASE_DP_TDC_REGS
+
TDC_REG_INPUT_ENABLE
);
if
(
enable
)
{
/* Enable TDC acquisition */
tdc_writel
(
tdc
,
ien
|
TDC_INPUT_ENABLE_CH_ALL
|
TDC_INPUT_ENABLE_FLAG
,
BASE_DP_TDC_REGS
+
TDC_REG_INPUT_ENABLE
);
/* Enable ACAM acquisition */
tdc_writel
(
tdc
,
TDC_CTRL_EN_ACQ
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
}
else
{
/* Disable ACAM acquisition */
tdc_writel
(
tdc
,
TDC_CTRL_DIS_ACQ
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
/* Disable TDC acquisition */
tdc_writel
(
tdc
,
ien
&
~
(
TDC_INPUT_ENABLE_CH_ALL
|
TDC_INPUT_ENABLE_FLAG
),
BASE_DP_TDC_REGS
+
TDC_REG_INPUT_ENABLE
);
}
}
}
/* FIXME missing all calibration */
static
int
tdc_init
(
struct
wrtd_tdc_dev
*
tdc
)
{
int
err
;
int
err
;
pr_debug
(
"%s: Initializing the TDC...
\n\r
"
,
__func__
);
pr_debug
(
"%s: Initializing the TDC...
\n\r
"
,
__func__
);
/* Initialize the TDC FIFO (channels disabled, default dead time) */
tdc_writel
(
tdc
,
0x0
,
BASE_DP_TDC_DIRECT
+
DR_REG_CHAN_ENABLE
);
tdc_writel
(
tdc
,
DEFAULT_DEAD_TIME
,
BASE_DP_TDC_DIRECT
+
DR_REG_DEAD_TIME
);
/* Initialize the TDC FIFO (channels disabled, default dead time) */
tdc_writel
(
tdc
,
0x0
,
BASE_DP_TDC_DIRECT
+
DR_REG_CHAN_ENABLE
);
tdc_writel
(
tdc
,
DEFAULT_DEAD_TIME
,
BASE_DP_TDC_DIRECT
+
DR_REG_DEAD_TIME
);
#ifndef SIMULATION
tdc_enable_acquisition
(
tdc
,
0
);
tdc_enable_acquisition
(
tdc
,
0
);
err
=
tdc_acam_init
(
tdc
);
if
(
err
)
return
err
;
err
=
tdc_acam_init
(
tdc
);
if
(
err
)
return
err
;
err
=
tdc_time_init
(
tdc
);
if
(
err
)
return
err
;
err
=
tdc_time_init
(
tdc
);
if
(
err
)
return
err
;
err
=
tdc_channels_init
(
tdc
);
if
(
err
)
return
err
;
err
=
tdc_channels_init
(
tdc
);
if
(
err
)
return
err
;
tdc_enable_acquisition
(
tdc
,
1
);
tdc_enable_acquisition
(
tdc
,
1
);
#endif
pr_debug
(
"%s: TDC initialization complete
\n\r
"
,
__func__
);
pr_debug
(
"%s: TDC initialization complete
\n\r
"
,
__func__
);
return
0
;
return
0
;
}
static
inline
int
tdc_wr_link_up
(
struct
wrtd_tdc_dev
*
tdc
)
{
return
tdc_readl
(
tdc
,
BASE_DP_TDC_REGS
+
TDC_REG_WR_STAT
)
&
TDC_WR_STAT_LINK
;
return
tdc_readl
(
tdc
,
BASE_DP_TDC_REGS
+
TDC_REG_WR_STAT
)
&
TDC_WR_STAT_LINK
;
}
static
inline
int
tdc_wr_time_locked
(
struct
wrtd_tdc_dev
*
tdc
)
{
return
tdc_readl
(
tdc
,
BASE_DP_TDC_REGS
+
TDC_REG_WR_STAT
)
&
TDC_WR_STAT_AUX_LOCKED
;
return
tdc_readl
(
tdc
,
BASE_DP_TDC_REGS
+
TDC_REG_WR_STAT
)
&
TDC_WR_STAT_AUX_LOCKED
;
}
static
void
tdc_wr_enable_lock
(
struct
wrtd_tdc_dev
*
tdc
,
int
enable
)
{
tdc_writel
(
tdc
,
TDC_CTRL_DIS_ACQ
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
tdc_writel
(
tdc
,
TDC_CTRL_DIS_ACQ
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
tdc_writel
(
tdc
,
enable
?
TDC_WR_CTRL_ENABLE
:
0
,
BASE_DP_TDC_REGS
+
TDC_REG_WR_CTRL
);
tdc_writel
(
tdc
,
TDC_CTRL_EN_ACQ
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
tdc_writel
(
tdc
,
TDC_CTRL_EN_ACQ
,
BASE_DP_TDC_REGS
+
TDC_REG_CTRL
);
}
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
;
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
)
...
...
@@ -256,11 +256,11 @@ static void tdc_input(struct wrtd_tdc_dev *tdc)
ev
.
ts
.
ns
=
tdc_readl
(
tdc
,
BASE_DP_TDC_DIRECT
+
DR_REG_FIFO_R1
)
*
8
;
meta
=
tdc_readl
(
tdc
,
BASE_DP_TDC_DIRECT
+
DR_REG_FIFO_R2
);
/* Conversion from ACAM TDC bins to WR already done in gateware
(including overflow checks), result is in 2e-9 ns ticks */
/* Conversion from ACAM TDC bins to WR already done in gateware
(including overflow checks), result is in 2e-9 ns ticks */
uint32_t
frac
=
meta
&
0x3ffff
;
/* Change frac resolution from 2e-9 ns to 2e-32 ns */
/* Change frac resolution from 2e-9 ns to 2e-32 ns */
ev
.
ts
.
frac
=
frac
<<
(
32
-
9
);
int
channel
=
(
meta
>>
19
)
&
0x7
;
...
...
@@ -269,7 +269,7 @@ static void tdc_input(struct wrtd_tdc_dev *tdc)
ev
.
id
[
0
]
=
'L'
;
ev
.
id
[
1
]
=
'C'
;
ev
.
id
[
2
]
=
'-'
;
ev
.
id
[
3
]
=
'I'
;
ev
.
id
[
3
]
=
'I'
;
ev
.
id
[
4
]
=
'1'
+
channel
;
/* channel starts from 0. */
ev
.
flags
=
0
;
...
...
software/include/wrtd-common.h
View file @
1394f372
...
...
@@ -23,24 +23,27 @@
/**
* WRTD timestamp format
*/
struct
wrtd_tstamp
{
// TODO: maybe distinguish between UTC and TAI
// TODO: maybe distinguish between UTC and TAI
typedef
struct
wrtd_tstamp
{
/** TAI seconds since 1/1/1970 (Unix Epoch Time). */
uint32_t
seconds
;
/** Number of nanoseconds. Wraps at 10e9. */
uint32_t
ns
;
/** Number of fractional nanoseconds. Unit is 2e-32 ns. */
uint32_t
frac
;
};
}
wrtd_tstamp
;
struct
wrtd_event
{
/* Time of the event. */
/*
*
Time of the event. */
struct
wrtd_tstamp
ts
;
/* Event id. */
/*
*
Event id. */
char
id
[
WRTD_ID_LEN
];
/* Sequence number. */
/*
*
Sequence number. */
uint32_t
seq
;
/* Associated flags. */
/*
*
Associated flags. */
unsigned
char
flags
;
};
...
...
software/lib/libwrtd-attributes.c
View file @
1394f372
...
...
@@ -38,7 +38,7 @@ enum wrtd_status wrtd_attr_set_alarm_period(struct wrtd_dev *wrtd,
if
(
value
->
seconds
!=
0
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INVALID_VALUE
,
"Invalid value (%d) for function %s, \
"Invalid value (%d) for function %s, \
parameter value.seconds"
,
value
->
seconds
,
__func__
);
...
...
@@ -153,7 +153,7 @@ enum wrtd_status wrtd_attr_set_alarm_repeat_count(struct wrtd_dev *wrtd,
if
(
value
<
0
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INVALID_VALUE
,
"Invalid value (%d) for function %s, \
"Invalid value (%d) for function %s, \
parameter value"
,
value
,
__func__
);
status
=
wrtd_find_alarm
(
wrtd
,
rep_cap_id
,
&
idx
,
__func__
);
...
...
@@ -194,7 +194,7 @@ enum wrtd_status wrtd_attr_set_rule_repeat_count(struct wrtd_dev *wrtd,
if
(
value
<
0
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INVALID_VALUE
,
"Invalid value (%d) for function %s, \
"Invalid value (%d) for function %s, \
parameter value"
,
value
,
__func__
);
status
=
wrtd_find_rule
(
wrtd
,
rep_cap_id
,
&
idx
,
__func__
);
...
...
@@ -409,7 +409,7 @@ enum wrtd_status wrtd_attr_set_rule_delay(struct wrtd_dev *wrtd,
if
(
value
->
seconds
!=
0
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INVALID_VALUE
,
"Invalid value (%d) for function %s, \
"Invalid value (%d) for function %s, \
parameter value.seconds"
,
value
->
seconds
,
__func__
);
...
...
@@ -452,7 +452,7 @@ enum wrtd_status wrtd_attr_set_rule_holdoff(struct wrtd_dev *wrtd,
if
(
value
->
seconds
!=
0
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INVALID_VALUE
,
"Invalid value (%d) for function %s, \
"Invalid value (%d) for function %s, \
parameter value.seconds"
,
value
->
seconds
,
__func__
);
...
...
@@ -495,7 +495,7 @@ enum wrtd_status wrtd_attr_set_rule_resync_period(struct wrtd_dev *wrtd,
if
(
value
->
seconds
!=
0
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INVALID_VALUE
,
"Invalid value (%d) for function %s, \
"Invalid value (%d) for function %s, \
parameter value.seconds"
,
value
->
seconds
,
__func__
);
...
...
@@ -850,6 +850,29 @@ enum wrtd_status wrtd_attr_get_rule_send_late(struct wrtd_dev *wrtd,
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_attr_get_sys_time
(
struct
wrtd_dev
*
wrtd
,
struct
wrtd_tstamp
*
value
)
{
enum
wrtd_status
status
;
struct
wrtd_config_msg
msg
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
/* Always use CPU #0 (it does exist!). */
status
=
wrtd_msg_get_config
(
wrtd
,
0
,
&
msg
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
*
value
=
msg
.
now
;
return
WRTD_SUCCESS
;
}
/**
*@} End group Time
*/
enum
wrtd_status
wrtd_attr_global
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
{
...
...
software/lib/libwrtd-internal.c
View file @
1394f372
...
...
@@ -123,7 +123,7 @@ enum wrtd_status wrtd_log_read(struct wrtd_dev *wrtd,
}
/* Clean up errno to be able to distinguish between error cases and
normal behaviour when the function return less messages
normal behaviour when the function return
s
less messages
than expected */
errno
=
0
;
...
...
@@ -135,7 +135,7 @@ enum wrtd_status wrtd_log_read(struct wrtd_dev *wrtd,
}
if
(
ret
<
0
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INTERNAL
,
"%s/%s: %s"
,
(
wrtd
,
WRTD_ERROR_INTERNAL
,
"%s/%s
(poll)
: %s"
,
caller_func
,
__func__
,
trtl_strerror
(
errno
));
for
(
i
=
0
;
i
<
wrtd
->
nbr_cpus
;
++
i
)
{
...
...
@@ -144,7 +144,7 @@ enum wrtd_status wrtd_log_read(struct wrtd_dev *wrtd,
ret
=
trtl_msg_async_recv
(
wrtd
->
trtl
,
i
,
WRTD_HMQ
,
&
msg
,
1
);
if
(
ret
<=
0
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INTERNAL
,
"%s/%s: %s"
,
(
wrtd
,
WRTD_ERROR_INTERNAL
,
"%s/%s
(recv)
: %s"
,
caller_func
,
__func__
,
trtl_strerror
(
errno
));
memcpy
(
log
,
msg
.
data
,
sizeof
(
struct
wrtd_log_entry
));
...
...
@@ -321,17 +321,16 @@ enum wrtd_status wrtd_fill_roots(struct wrtd_dev *wrtd, const char *caller_func)
if
(
status
!=
WRTD_SUCCESS
)
return
status
;
if
(
wrtd
->
roots
[
cpu
].
ver_major
!=
WRTD_VERSION_MAJOR
)
{
status
=
wrtd_return_error
/* Invalidate root. */
wrtd
->
roots
[
cpu
].
ver_major
=
0
;
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_VERSION_MISMATCH
,
"%s/%s: incorrect major version (%d instead of %d)"
,
caller_func
,
__func__
,
wrtd
->
roots
[
cpu
].
ver_major
,
WRTD_VERSION_MAJOR
);
/* Invalidate root. */
wrtd
->
roots
[
cpu
].
ver_major
=
0
;
return
status
;
}
if
(
wrtd
->
roots
[
cpu
].
ver_minor
!=
WRTD_VERSION_MINOR
)
{
if
(
wrtd
->
roots
[
cpu
].
ver_minor
>
WRTD_VERSION_MINOR
)
{
/* Invalidate root. */
wrtd
->
roots
[
cpu
].
ver_major
=
0
;
return
wrtd_return_error
...
...
@@ -621,4 +620,3 @@ inline enum wrtd_status wrtd_rule_check_disabled(struct wrtd_dev *wrtd, unsigned
caller_func
,
__func__
);
return
WRTD_SUCCESS
;
}
software/lib/libwrtd-private.h
View file @
1394f372
...
...
@@ -11,13 +11,6 @@
#define WRTD_RETURN_IF_ERROR(status) if(status != WRTD_SUCCESS) return status
/* A complete log entry needs 35+1+35+1+9+1+8=90 + 1 for null termination.
1st field: log tstamp in YYYY-MM-DD,hh:mm:ss.xxx.yyy.zzz+fff format.
2nd field: event tstamp in YYYY-MM-DD,hh:mm:ss.xxx.yyy.zzz+fff format.
3rd field: log type, padded with spaces to 9 characters.
4th field: log reason, padded with spaces to 8 characters. */
#define WRTD_LOG_ENTRY_SIZE 91
#define WRTD_DEFAULT_TIMEOUT 1000
/* Add nanoseconds to an existing wrtd timestamp */
...
...
@@ -302,6 +295,8 @@ enum wrtd_status wrtd_attr_set_rule_send_late(struct wrtd_dev *wrtd,
enum
wrtd_status
wrtd_attr_get_rule_send_late
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
bool
*
value
);
enum
wrtd_status
wrtd_attr_get_sys_time
(
struct
wrtd_dev
*
wrtd
,
struct
wrtd_tstamp
*
value
);
enum
wrtd_status
wrtd_attr_global
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
...
...
software/lib/libwrtd.c
View file @
1394f372
...
...
@@ -20,21 +20,31 @@
* @{
*/
enum
wrtd_status
wrtd_init
(
const
char
*
resource_name
,
bool
reset
,
const
char
*
options_str
,
struct
wrtd_dev
**
dev
)
/**
* Initialize the WRTD device and obtain the WRTD device token.
*
* @param[in] resource_name Underlying MockTurtle device ID in
* the form of **MTxxx** or **trtl-xxxx**.
* @param[in] reset Reserved for future use.
* @param[in] options_str Reserved for future use.
* @param[out] wrtd Pointer to WRTD device token.
* @return #wrtd_status
*/
wrtd_status
wrtd_init
(
const
char
*
resource_name
,
bool
reset
,
const
char
*
options_str
,
wrtd_dev
**
wrtd
)
{
int
i
;
struct
trtl_dev
*
trtl
;
const
struct
trtl_config_rom
*
cfgrom
;
struct
wrtd_config_msg
msg
;
enum
wrtd_status
status
;
wrtd_status
status
;
static
int
initialized
;
/* In case of error... */
*
dev
=
NULL
;
*
wrtd
=
NULL
;
/* Initialize (only once).*/
if
(
!
initialized
)
{
...
...
@@ -62,9 +72,9 @@ enum wrtd_status wrtd_init(const char *resource_name,
if
(
trtl
==
NULL
)
return
WRTD_ERROR_RESOURCE_UNKNOWN
;
struct
wrtd_dev
*
res
;
wrtd_dev
*
res
;
res
=
malloc
(
sizeof
(
struct
wrtd_dev
));
res
=
malloc
(
sizeof
(
wrtd_dev
));
if
(
res
==
NULL
)
return
WRTD_ERROR_OUT_OF_MEMORY
;
memset
(
res
,
0
,
sizeof
(
*
res
));
...
...
@@ -92,32 +102,55 @@ enum wrtd_status wrtd_init(const char *resource_name,
res
->
nbr_cpus
=
cfgrom
->
n_cpu
;
*
dev
=
res
;
*
wrtd
=
res
;
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_close
(
struct
wrtd_dev
*
dev
)
/**
* Close a WRTD device and release all resources.
*
* @param[in] wrtd Device token.
* @return #wrtd_status
*/
wrtd_status
wrtd_close
(
wrtd_dev
*
wrtd
)
{
if
(
dev
==
NULL
){
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
trtl_close
(
dev
->
trtl
);
trtl_close
(
wrtd
->
trtl
);
free
(
dev
->
alarms
);
free
(
dev
->
rules
);
free
(
dev
);
free
(
wrtd
->
alarms
);
free
(
wrtd
->
rules
);
free
(
wrtd
);
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_reset
(
struct
wrtd_dev
*
dev
)
/**
* Reset a WRTD device. This will remove all defined Alarms and Rules.
*
* @param[in] wrtd Device token.
* @return #wrtd_status
*/
wrtd_status
wrtd_reset
(
wrtd_dev
*
wrtd
)
{
if
(
dev
==
NULL
){
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
status
=
wrtd_disable_all_alarms
(
wrtd
);
WRTD_RETURN_IF_ERROR
(
status
);
status
=
wrtd_disable_all_rules
(
wrtd
);
WRTD_RETURN_IF_ERROR
(
status
);
status
=
wrtd_remove_all_alarms
(
wrtd
);
WRTD_RETURN_IF_ERROR
(
status
);
status
=
wrtd_remove_all_rules
(
wrtd
);
WRTD_RETURN_IF_ERROR
(
status
);
return
WRTD_SUCCESS
;
}
...
...
@@ -131,17 +164,17 @@ enum wrtd_status wrtd_reset(struct wrtd_dev *dev)
* buffer overflow.
*
* @param[in] wrtd Device token.
* @param[out] error_code #wrtd_status pointer to return the error code.
* @param[out] error_code #wrtd_status pointer to return the error code.
Ignored if NULL.
* @param[in] error_description_buffer_size Size of pre-allocated `error_description` buffer.
* @param[out] error_description Buffer to store the detailed error message string.
* @return #wrtd_status. See also IVI-3.2, section 3.1.2.1.
*/
enum
wrtd_status
wrtd_get_error
(
struct
wrtd_dev
*
wrtd
,
enum
wrtd_status
*
error_code
,
int32_t
error_description_buffer_size
,
char
*
error_description
)
wrtd_status
wrtd_get_error
(
wrtd_dev
*
wrtd
,
wrtd_status
*
error_code
,
int32_t
error_description_buffer_size
,
char
*
error_description
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
int
ret
;
if
(
wrtd
==
NULL
){
...
...
@@ -200,21 +233,25 @@ enum wrtd_status wrtd_get_error(struct wrtd_dev *wrtd,
* Convert a #wrtd_status error code to a string. Modelled after the IVI-C
* ErrorMessage function.
*
* @param[in] wrtd Device token.
* @param[in] wrtd Device token. Can be NULL to allow calling this function
* even when initialisation has failed.
* @param[in] err_code #wrtd_status error code to convert.
* @param[out] err_message Buffer of at least 256 bytes to store the resulting string.
* @return #wrtd_status
*/
enum
wrtd_status
wrtd_error_message
(
struct
wrtd_dev
*
wrtd
,
enum
wrtd_status
err_code
,
char
*
err_message
)
wrtd_status
wrtd_error_message
(
wrtd_dev
*
wrtd
,
wrtd_status
err_code
,
char
*
err_message
)
{
if
(
err_message
==
NULL
){
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_NULL_POINTER
,
"Null pointer passed for function %s, \
parameter err_message"
,
__func__
);
if
(
err_message
==
NULL
)
{
if
(
wrtd
!=
NULL
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_NULL_POINTER
,
"Null pointer passed for function %s, \
parameter err_message"
,
__func__
);
return
WRTD_ERROR_NULL_POINTER
;
}
switch
(
err_code
){
...
...
@@ -287,10 +324,13 @@ enum wrtd_status wrtd_error_message(struct wrtd_dev *wrtd,
break
;
default:
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INVALID_VALUE
,
"Invalid value (%d) for function %s, \
parameter err_code"
,
err_code
,
__func__
);
if
(
wrtd
!=
NULL
)
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_INVALID_VALUE
,
"Invalid value (%d) for function %s, \
parameter err_code"
,
err_code
,
__func__
);
return
WRTD_ERROR_INVALID_VALUE
;
}
return
WRTD_SUCCESS
;
...
...
@@ -317,12 +357,16 @@ enum wrtd_status wrtd_error_message(struct wrtd_dev *wrtd,
* @param[in] value Value to write to the attribute.
* @return #wrtd_status
*/
enum
wrtd_status
wrtd_set_attr_bool
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
bool
value
)
wrtd_status
wrtd_set_attr_bool
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
bool
value
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
status
=
wrtd_validate_id
(
wrtd
,
rep_cap_id
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
...
...
@@ -366,16 +410,27 @@ enum wrtd_status wrtd_set_attr_bool(struct wrtd_dev *wrtd,
* @param[out] value Retrieved attribute value.
* @return #wrtd_status
*/
enum
wrtd_status
wrtd_get_attr_bool
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
bool
*
value
)
wrtd_status
wrtd_get_attr_bool
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
bool
*
value
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
status
=
wrtd_validate_id
(
wrtd
,
rep_cap_id
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
if
(
value
==
NULL
){
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_NULL_POINTER
,
"Null pointer passed for function %s, \
parameter value"
,
__func__
);
}
switch
(
id
)
{
case
WRTD_ATTR_EVENT_LOG_ENABLED
:
status
=
wrtd_attr_global
...
...
@@ -422,12 +477,16 @@ enum wrtd_status wrtd_get_attr_bool(struct wrtd_dev *wrtd,
* @param[in] value Value to write to the attribute.
* @return #wrtd_status
*/
enum
wrtd_status
wrtd_set_attr_int32
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
int32_t
value
)
wrtd_status
wrtd_set_attr_int32
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
int32_t
value
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
status
=
wrtd_validate_id
(
wrtd
,
rep_cap_id
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
...
...
@@ -473,16 +532,27 @@ enum wrtd_status wrtd_set_attr_int32(struct wrtd_dev *wrtd,
* @param[out] value Retrieved attribute value.
* @return #wrtd_status
*/
enum
wrtd_status
wrtd_get_attr_int32
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
int32_t
*
value
)
wrtd_status
wrtd_get_attr_int32
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
int32_t
*
value
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
status
=
wrtd_validate_id
(
wrtd
,
rep_cap_id
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
if
(
value
==
NULL
){
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_NULL_POINTER
,
"Null pointer passed for function %s, \
parameter value"
,
__func__
);
}
switch
(
id
)
{
case
WRTD_MAJOR_VERSION
:
status
=
wrtd_attr_global
...
...
@@ -557,12 +627,16 @@ enum wrtd_status wrtd_get_attr_int32(struct wrtd_dev *wrtd,
* @param[in] value Value to write to the attribute.
* @return #wrtd_status
*/
enum
wrtd_status
wrtd_set_attr_string
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
const
char
*
value
)
wrtd_status
wrtd_set_attr_string
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
const
char
*
value
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
status
=
wrtd_validate_id
(
wrtd
,
rep_cap_id
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
...
...
@@ -598,17 +672,28 @@ enum wrtd_status wrtd_set_attr_string(struct wrtd_dev *wrtd,
* @param[out] value Retrieved attribute value.
* @return #wrtd_status. See also IVI-3.2, section 3.1.2.1.
*/
enum
wrtd_status
wrtd_get_attr_string
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
int32_t
value_buffer_size
,
char
*
value
)
wrtd_status
wrtd_get_attr_string
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
int32_t
value_buffer_size
,
char
*
value
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
status
=
wrtd_validate_id
(
wrtd
,
rep_cap_id
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
if
(
value
==
NULL
){
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_NULL_POINTER
,
"Null pointer passed for function %s, \
parameter value"
,
__func__
);
}
switch
(
id
)
{
case
WRTD_ATTR_RULE_SOURCE
:
return
wrtd_attr_get_rule_source
...
...
@@ -634,16 +719,27 @@ enum wrtd_status wrtd_get_attr_string(struct wrtd_dev *wrtd,
* @param[in] value Value to write to the attribute.
* @return #wrtd_status
*/
enum
wrtd_status
wrtd_set_attr_tstamp
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
const
struc
t
wrtd_tstamp
*
value
)
wrtd_status
wrtd_set_attr_tstamp
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
cons
t
wrtd_tstamp
*
value
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
status
=
wrtd_validate_id
(
wrtd
,
rep_cap_id
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
if
(
value
==
NULL
){
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_NULL_POINTER
,
"Null pointer passed for function %s, \
parameter value"
,
__func__
);
}
switch
(
id
)
{
case
WRTD_ATTR_ALARM_TIME
:
return
wrtd_attr_set_alarm_time
...
...
@@ -660,6 +756,7 @@ enum wrtd_status wrtd_set_attr_tstamp(struct wrtd_dev *wrtd,
case
WRTD_ATTR_RULE_RESYNC_PERIOD
:
return
wrtd_attr_set_rule_resync_period
(
wrtd
,
rep_cap_id
,
value
);
case
WRTD_ATTR_SYS_TIME
:
case
WRTD_ATTR_STAT_RULE_RX_LAST
:
case
WRTD_ATTR_STAT_RULE_TX_LAST
:
case
WRTD_ATTR_STAT_RULE_MISSED_LAST
:
...
...
@@ -688,17 +785,34 @@ enum wrtd_status wrtd_set_attr_tstamp(struct wrtd_dev *wrtd,
* @param[out] value Retrieved attribute value.
* @return #wrtd_status
*/
enum
wrtd_status
wrtd_get_attr_tstamp
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
struct
wrtd_tstamp
*
value
)
wrtd_status
wrtd_get_attr_tstamp
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
wrtd_tstamp
*
value
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
status
=
wrtd_validate_id
(
wrtd
,
rep_cap_id
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
if
(
value
==
NULL
){
return
wrtd_return_error
(
wrtd
,
WRTD_ERROR_NULL_POINTER
,
"Null pointer passed for function %s, \
parameter value"
,
__func__
);
}
switch
(
id
)
{
case
WRTD_ATTR_SYS_TIME
:
status
=
wrtd_attr_global
(
wrtd
,
rep_cap_id
);
WRTD_RETURN_IF_ERROR
(
status
);
return
wrtd_attr_get_sys_time
(
wrtd
,
value
);
case
WRTD_ATTR_ALARM_TIME
:
return
wrtd_attr_get_alarm_time
(
wrtd
,
rep_cap_id
,
value
);
...
...
@@ -746,35 +860,6 @@ enum wrtd_status wrtd_get_attr_tstamp(struct wrtd_dev *wrtd,
*@} End group Attributes
*/
/**
* @defgroup Time
* Time-related functions.
* @{
*/
enum
wrtd_status
wrtd_get_sys_time
(
struct
wrtd_dev
*
wrtd
,
struct
wrtd_tstamp
*
time
)
{
struct
wrtd_config_msg
msg
;
enum
wrtd_status
status
;
if
(
wrtd
==
NULL
){
return
WRTD_ERROR_NOT_INITIALIZED
;
}
/* Always use CPU #0 (it does exist!). */
status
=
wrtd_msg_get_config
(
wrtd
,
0
,
&
msg
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
*
time
=
msg
.
now
;
return
WRTD_SUCCESS
;
}
/**
*@} End group Time
*/
/**
* @defgroup Event Log
* Functions to retrieve and clear entries from the event log.
...
...
@@ -790,17 +875,51 @@ enum wrtd_status wrtd_get_sys_time(struct wrtd_dev *wrtd,
* the buffer_size < 0 case, which produces an error instead of allowing a potential
* buffer overflow.
*
* Event log entries use the format `log tstamp|event tstamp|log type|log reason`, where:
* - `log tstamp` is the timestamp of when the event was logged. This can be zero (1/1/1970)
* for some time-critical events which favour speed over logging information.
* - `event tstamp` is the timestamp of when the event happened.
* - `log type` is the type of the event.
* - `log tstamp` is the specific reason for this type of event.
*
* All event log entries have a fixed length of #WRTD_LOG_ENTRY_SIZE.
*
* Timestamps are represented using the format `YYYY-MM-DD,hh:mm:ss.mmm.uuu.nnn+fff`, where:
* - `YYYY-MM-DD` is the year, month and day.
* - `hh:mm:ss` is hours, minutes and seconds.
* - `mmm.uuu.nnn` is milliseconds, microseconds and nanoseconds.
* - `fff` is fractional nanoseconds. The unit is 2e-9 nanoseconds.
*
* Log types and reasons can be one of the following (in the form `type|reason`):
* - `GENERATED|ALARM` : An Event was generated because of an Alarm.
* - `GENERATED|DEVICE_x`: An Event was generated from device x.
* - `CONSUMED|START` : An Event with a local channel output as destination has been
* forwarded and scheduled to execute. The exact meaning of this log type is
* application-specific.
* - `CONSUMED|DONE` : An Event with a local channel output as destination has
* finished executing. The exact meaning of this log type is application-specific.
* - `DISCARDED|NO SYNC` : An Event was discarded because the device was not syncrhonized
to White Rabbit. See also #WRTD_ATTR_STAT_RULE_MISSED_NOSYNC.
* - `DISCARDED|HOLD OFF`: An Event was discarded because violated the programmed hold-off
* value. See also #WRTD_ATTR_STAT_RULE_MISSED_HOLDOFF.
* - `DISCARDED|TIME OUT`: An Event was discarded because it arrived too late. See also
* #WRTD_ATTR_STAT_RULE_MISSED_LATE.
* - `DISCARDED|OVERFLOW`: An Event was discarded because of internal buffer overflows.
* This may happen if the Event rate is too high. See also #WRTD_ATTR_STAT_RULE_MISSED_OVERFLOW.
* - `NETWORK|TX` : An Event was sent over the White Rabbit network.
* - `NETWORK|RX` : An Event was received over the White Rabbit network.
*
* @param[in] wrtd Device token.
* @param[in] log_entry_buffer_size Size of pre-allocated `log_entry` buffer.
* @param[out] log_entry Buffer to store the log message string.
* @return #wrtd_status. See also IVI-3.2, section 3.1.2.1.
*/
enum
wrtd_status
wrtd_get_next_event_log_entry
(
struct
wrtd_dev
*
wrtd
,
int32_t
log_entry_buffer_size
,
char
*
log_entry
)
wrtd_status
wrtd_get_next_event_log_entry
(
wrtd_dev
*
wrtd
,
int32_t
log_entry_buffer_size
,
char
*
log_entry
)
{
struct
wrtd_log_entry
log
;
enum
wrtd_status
status
;
wrtd_status
status
;
struct
tm
*
tm
;
if
(
wrtd
==
NULL
){
...
...
@@ -961,7 +1080,14 @@ enum wrtd_status wrtd_get_next_event_log_entry(struct wrtd_dev *wrtd,
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_clear_event_log_entries
(
struct
wrtd_dev
*
wrtd
)
/**
* Clear all entries from the Event Log. Modelled after the IVI-C
* ClearEventLog function (from IVI-3.15).
*
* @param[in] wrtd Device token.
* @return #wrtd_status.
*/
wrtd_status
wrtd_clear_event_log_entries
(
wrtd_dev
*
wrtd
)
{
int
ret
,
i
;
...
...
@@ -990,10 +1116,18 @@ enum wrtd_status wrtd_clear_event_log_entries(struct wrtd_dev *wrtd)
* @{
*/
enum
wrtd_status
wrtd_add_alarm
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
/**
* Create a new Alarm. Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* @param[in] wrtd Device token.
* @param[in] rep_cap_id Name for the new Alarm.
* @return #wrtd_status
*/
wrtd_status
wrtd_add_alarm
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
unsigned
int
i
;
int
idx
;
struct
wrtd_alarm
*
alarm
;
...
...
@@ -1040,10 +1174,20 @@ enum wrtd_status wrtd_add_alarm(struct wrtd_dev *wrtd,
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_disable_all_alarms
(
struct
wrtd_dev
*
wrtd
)
/**
* Disable all defined Alarms. Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* See also, #WRTD_ATTR_ALARM_ENABLED and #wrtd_set_attr_bool
* for disabling a single Alarm.
*
* @param[in] wrtd Device token.
* @return #wrtd_status
*/
wrtd_status
wrtd_disable_all_alarms
(
wrtd_dev
*
wrtd
)
{
unsigned
idx
;
enum
wrtd_status
status
;
wrtd_status
status
;
struct
wrtd_alarm
*
alarm
;
int
changed
=
0
;
...
...
@@ -1069,10 +1213,19 @@ enum wrtd_status wrtd_disable_all_alarms(struct wrtd_dev *wrtd)
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_remove_alarm
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
/**
* Remove an Alarm. The Alarm must not be enabled.
* Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* @param[in] wrtd Device token.
* @param[in] rep_cap_id Name of the Alarm to remove.
* @return #wrtd_status
*/
wrtd_status
wrtd_remove_alarm
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
unsigned
idx
;
struct
wrtd_alarm
*
alarm
;
...
...
@@ -1097,9 +1250,17 @@ enum wrtd_status wrtd_remove_alarm(struct wrtd_dev *wrtd,
return
WRTD_SUCCESS
;
}
extern
enum
wrtd_status
wrtd_remove_all_alarms
(
struct
wrtd_dev
*
wrtd
)
/**
* Remove all defined Alarms. The Alarms must not be enabled.
* Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* @param[in] wrtd Device token.
* @return #wrtd_status
*/
extern
wrtd_status
wrtd_remove_all_alarms
(
wrtd_dev
*
wrtd
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
unsigned
idx
;
struct
wrtd_alarm
*
alarm
;
...
...
@@ -1128,12 +1289,28 @@ extern enum wrtd_status wrtd_remove_all_alarms(struct wrtd_dev *wrtd)
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_get_alarm_name
(
struct
wrtd_dev
*
wrtd
,
int32_t
index
,
int32_t
name_buffer_size
,
char
*
rep_cap_id
)
/**
* Retrieve the name of an Alarm, based on the provided index.
* Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* This function complies with IVI-3.2, section 3.1.2.1 (Additional Compliance Rules
* for C Functions with ViChar Array Output Parameters), with the exception of
* the buffer_size < 0 case, which produces an error instead of allowing a potential
* buffer overflow.
*
* @param[in] wrtd Device token.
* @param[in] index index of the Alarm.
* @param[in] name_buffer_size Size of pre-allocated `name` buffer.
* @param[out] name Buffer to store the retrieved Alarm name.
* @return #wrtd_status. See also IVI-3.2, section 3.1.2.1.
*/
wrtd_status
wrtd_get_alarm_name
(
wrtd_dev
*
wrtd
,
int32_t
index
,
int32_t
name_buffer_size
,
char
*
name
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
unsigned
i
;
unsigned
n
;
...
...
@@ -1152,7 +1329,7 @@ enum wrtd_status wrtd_get_alarm_name(struct wrtd_dev *wrtd,
continue
;
if
(
n
==
index
)
{
status
=
wrtd_id_copy_buf
(
wrtd
,
rep_cap_id
,
name_buffer_size
,
aid
,
__func__
);
(
wrtd
,
name
,
name_buffer_size
,
aid
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
return
WRTD_SUCCESS
;
}
...
...
@@ -1174,10 +1351,18 @@ enum wrtd_status wrtd_get_alarm_name(struct wrtd_dev *wrtd,
* @{
*/
enum
wrtd_status
wrtd_add_rule
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
/**
* Create a new Rule. Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* @param[in] wrtd Device token.
* @param[in] rep_cap_id Name for the new Rule.
* @return #wrtd_status
*/
wrtd_status
wrtd_add_rule
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
unsigned
int
i
;
int
idx
;
struct
wrtd_rule
*
rule
;
...
...
@@ -1226,10 +1411,20 @@ enum wrtd_status wrtd_add_rule(struct wrtd_dev *wrtd,
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_disable_all_rules
(
struct
wrtd_dev
*
wrtd
)
/**
* Disable all defined Rules. Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* See also, #WRTD_ATTR_RULE_ENABLED and #wrtd_set_attr_bool
* for disabling a single Rule.
*
* @param[in] wrtd Device token.
* @return #wrtd_status
*/
wrtd_status
wrtd_disable_all_rules
(
wrtd_dev
*
wrtd
)
{
unsigned
idx
;
enum
wrtd_status
status
;
wrtd_status
status
;
struct
wrtd_lib_rule
*
r
;
int
changed
=
0
;
...
...
@@ -1254,10 +1449,19 @@ enum wrtd_status wrtd_disable_all_rules(struct wrtd_dev *wrtd)
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_remove_rule
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
/**
* Remove a Rule. The Rule must not be enabled.
* Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* @param[in] wrtd Device token.
* @param[in] rep_cap_id Name of the Rule to remove.
* @return #wrtd_status
*/
wrtd_status
wrtd_remove_rule
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
unsigned
idx
;
struct
wrtd_rule
*
rule
;
...
...
@@ -1282,9 +1486,17 @@ enum wrtd_status wrtd_remove_rule(struct wrtd_dev *wrtd,
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_remove_all_rules
(
struct
wrtd_dev
*
wrtd
)
/**
* Remove all defined Rules. The Rules must not be enabled.
* Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* @param[in] wrtd Device token.
* @return #wrtd_status
*/
wrtd_status
wrtd_remove_all_rules
(
wrtd_dev
*
wrtd
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
unsigned
idx
;
struct
wrtd_rule
*
rule
;
...
...
@@ -1315,12 +1527,28 @@ enum wrtd_status wrtd_remove_all_rules(struct wrtd_dev *wrtd)
return
WRTD_SUCCESS
;
}
enum
wrtd_status
wrtd_get_rule_name
(
struct
wrtd_dev
*
wrtd
,
int32_t
index
,
int32_t
name_buffer_size
,
char
*
rep_cap_id
)
/**
* Retrieve the name of a Rule, based on the provided index.
* Complies with the IVI "Parameter style"
* for repeated capabilities (see IVI-3.4, section 12).
*
* This function complies with IVI-3.2, section 3.1.2.1 (Additional Compliance Rules
* for C Functions with ViChar Array Output Parameters), with the exception of
* the buffer_size < 0 case, which produces an error instead of allowing a potential
* buffer overflow.
*
* @param[in] wrtd Device token.
* @param[in] index index of the Rule.
* @param[in] name_buffer_size Size of pre-allocated `name` buffer.
* @param[out] name Buffer to store the retrieved Rule name.
* @return #wrtd_status. See also IVI-3.2, section 3.1.2.1.
*/
wrtd_status
wrtd_get_rule_name
(
wrtd_dev
*
wrtd
,
int32_t
index
,
int32_t
name_buffer_size
,
char
*
name
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
unsigned
i
;
unsigned
n
;
...
...
@@ -1339,7 +1567,7 @@ enum wrtd_status wrtd_get_rule_name(struct wrtd_dev *wrtd,
continue
;
if
(
n
==
index
)
{
status
=
wrtd_id_copy_buf
(
wrtd
,
rep_cap_id
,
name_buffer_size
,
aid
,
__func__
);
(
wrtd
,
name
,
name_buffer_size
,
aid
,
__func__
);
WRTD_RETURN_IF_ERROR
(
status
);
return
WRTD_SUCCESS
;
}
...
...
@@ -1351,10 +1579,17 @@ enum wrtd_status wrtd_get_rule_name(struct wrtd_dev *wrtd,
parameter index."
,
index
,
__func__
);
}
enum
wrtd_status
wrtd_reset_rule_stats
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
/**
* Reset all statistics for the given rule. The Rule must not be enabled.
*
* @param[in] wrtd Device token.
* @param[in] rep_cap_id Name of the Rule to reset its statistics.
* @return #wrtd_status
*/
wrtd_status
wrtd_reset_rule_stats
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
)
{
enum
wrtd_status
status
;
wrtd_status
status
;
unsigned
idx
;
struct
wrtd_rule
*
rule
;
...
...
software/lib/libwrtd.h
View file @
1394f372
...
...
@@ -18,7 +18,7 @@ extern "C" {
#include "wrtd-common.h"
// NOTE: corresponds roughly to IVI ViSession
struct
wrtd_dev
;
typedef
struct
wrtd_dev
wrtd_dev
;
/**
* @enum wrtd_status
...
...
@@ -28,7 +28,7 @@ struct wrtd_dev;
* the #wrtd_error_message function. The latest error can
* be retrieved with the #wrtd_get_error function.
*/
enum
wrtd_status
{
typedef
enum
wrtd_status
{
/** No error. */
WRTD_SUCCESS
=
0
,
...
...
@@ -86,14 +86,14 @@ enum wrtd_status {
/** always last entry in this enum */
__WRTD_ERROR_MAX_NUMBER
,
};
}
wrtd_status
;
/**
* @enum wrtd_attr
* White Rabbit Trigger Distribution attributes.
* Names and values inspired by IVI-3.2 and IVI-3.15.
*
* Attributes can be of type `bool`, `int32`, `string`, or `t
imestamp`
.
* Attributes can be of type `bool`, `int32`, `string`, or `t
stamp` (#wrtd_tstamp)
.
* Access can be `RW` (read/write), `RO` (read-only) or `WO` (write-only).
* Furthermore an attribute can be `local` (related to a specific Alarm/Rule)
* or `global` (it applies to the whole device).
...
...
@@ -109,13 +109,15 @@ enum wrtd_status {
* - #wrtd_set_attr_tstamp
* - #wrtd_get_attr_tstamp
*/
enum
wrtd_attr
{
typedef
enum
wrtd_attr
{
/** Same as *IVI_INSTR_SPECIFIC_ATTR_BASE*. */
__WRTD_ATTR_BASE
=
1150000
,
/** `RO` `int32` `global` Major part of WRTD version supported by the device. */
/** `RO` `int32` `global` Major part of WRTD version supported by the device.
It must be equal to the major version of the WRTD library. */
WRTD_MAJOR_VERSION
=
__WRTD_ATTR_BASE
+
0x00
,
/** `RO` `int32` `global` Minor part of WRTD version supported by the device. */
/** `RO` `int32` `global` Minor part of WRTD version supported by the device.
It must be less than or equal to the minor version of the WRTD library. */
WRTD_MINOR_VERSION
=
__WRTD_ATTR_BASE
+
0x01
,
/** `RO` `bool` `global` True if the Event Log is empty. */
WRTD_ATTR_EVENT_LOG_EMPTY
=
__WRTD_ATTR_BASE
+
0x02
,
...
...
@@ -123,184 +125,221 @@ enum wrtd_attr {
WRTD_ATTR_EVENT_LOG_ENABLED
=
__WRTD_ATTR_BASE
+
0x03
,
/** `RO` `bool` `global` True if the device is synchronized to White Rabbit time. */
WRTD_ATTR_IS_TIME_SYNCHRONIZED
=
__WRTD_ATTR_BASE
+
0x04
,
/** `RO` `tstamp` `global` Current system time. */
WRTD_ATTR_SYS_TIME
=
__WRTD_ATTR_BASE
+
0x05
,
/** `RO` `int32` `global` Number of defined Alarms. */
WRTD_ATTR_ALARM_COUNT
=
__WRTD_ATTR_BASE
+
0x
05
,
WRTD_ATTR_ALARM_COUNT
=
__WRTD_ATTR_BASE
+
0x
10
,
/** `RW` `bool` `local` Enable/disable an Alarm. */
WRTD_ATTR_ALARM_ENABLED
=
__WRTD_ATTR_BASE
+
0x
06
,
WRTD_ATTR_ALARM_ENABLED
=
__WRTD_ATTR_BASE
+
0x
11
,
/** `RW` `tstamp` `local` Specifies at what time to trigger an Alarm. */
WRTD_ATTR_ALARM_TIME
=
__WRTD_ATTR_BASE
+
0x
07
,
WRTD_ATTR_ALARM_TIME
=
__WRTD_ATTR_BASE
+
0x
12
,
/** `RW` `tstamp` `local` Specifies the Alarm period. 0 means no repetitions. */
WRTD_ATTR_ALARM_PERIOD
=
__WRTD_ATTR_BASE
+
0x
08
,
WRTD_ATTR_ALARM_PERIOD
=
__WRTD_ATTR_BASE
+
0x
13
,
/** `RW` `int32` `local` Specifies the number of times an Alarm will occur at the
period specified by #WRTD_ATTR_ALARM_PERIOD, before becoming automatically disabled.
0 means infinite repetitions. When read, it returns the remaining repetitions. */
WRTD_ATTR_ALARM_REPEAT_COUNT
=
__WRTD_ATTR_BASE
+
0x
09
,
WRTD_ATTR_ALARM_REPEAT_COUNT
=
__WRTD_ATTR_BASE
+
0x
14
,
/** `RO` `int32` `global` Number of defined Rules. */
WRTD_ATTR_RULE_COUNT
=
__WRTD_ATTR_BASE
+
0x
0A
,
WRTD_ATTR_RULE_COUNT
=
__WRTD_ATTR_BASE
+
0x
20
,
/** `RW` `bool` `local` Enable/disable a Rule. */
WRTD_ATTR_RULE_ENABLED
=
__WRTD_ATTR_BASE
+
0x
0B
,
WRTD_ATTR_RULE_ENABLED
=
__WRTD_ATTR_BASE
+
0x
21
,
/** `RW` `int32` `local` Specifies the number of times a Rule will fire before
becoming automatically disabled. 0 means infinite. When read, it returns the
remaining repetitions. */
WRTD_ATTR_RULE_REPEAT_COUNT
=
__WRTD_ATTR_BASE
+
0x
0C
,
WRTD_ATTR_RULE_REPEAT_COUNT
=
__WRTD_ATTR_BASE
+
0x
22
,
/** `RW` `string` `local` Get/set Rule source. Rule sources can be:
- Local source Event IDs (in the form of **LCI-x**)
- Alarm IDs (any ID with an **alarm** prefix)
- Any other string which will be interpreted as a network message Event ID. */
WRTD_ATTR_RULE_SOURCE
=
__WRTD_ATTR_BASE
+
0x
0D
,
WRTD_ATTR_RULE_SOURCE
=
__WRTD_ATTR_BASE
+
0x
23
,
/** `RW` `string` `local` Get/set Rule destinations. Rule destinations can be:
- Local destination Event IDs (in the form of **LCO-x**)
- Any other string which will be interpreted as a network message Event ID. */
WRTD_ATTR_RULE_DESTINATION
=
__WRTD_ATTR_BASE
+
0x
0E
,
WRTD_ATTR_RULE_DESTINATION
=
__WRTD_ATTR_BASE
+
0x
24
,
/** `RW` `bool` `local` If true, events that arrive late (with a timestamp in
the past) will still be executed; otherwise they are logged and discarded. */
WRTD_ATTR_RULE_SEND_LATE
=
__WRTD_ATTR_BASE
+
0x
0F
,
WRTD_ATTR_RULE_SEND_LATE
=
__WRTD_ATTR_BASE
+
0x
25
,
/** `RW` `tstamp` `local` Specifies the delay to add to the timestamp of the source
Event before forwarding it to its destination. The provided value must be less
than 1 second. */
WRTD_ATTR_RULE_DELAY
=
__WRTD_ATTR_BASE
+
0x
10
,
WRTD_ATTR_RULE_DELAY
=
__WRTD_ATTR_BASE
+
0x
26
,
/** `RW` `tstamp` `local` Specifies the "dead time" between two source Events. Any
new event that arrives during this time, will be logged and discarded. The provided
value must be less than 1 second. */
WRTD_ATTR_RULE_HOLDOFF
=
__WRTD_ATTR_BASE
+
0x
11
,
WRTD_ATTR_RULE_HOLDOFF
=
__WRTD_ATTR_BASE
+
0x
27
,
/** `RW` `tstamp` `local` Re-align the source Event timestamp to a multiple
of this value. As an example, if the Event timestamp is **00:00:12.000.123.456**
and RESYNC_PERIOD is **00:00:00.000.005.000** (5us), the Event timestamp will
be re-aligned to **00:00:12.000.125.000**. This calculation is done after applying
the delay defined by #WRTD_ATTR_RULE_DELAY. The provided value must be less than
1 second. */
WRTD_ATTR_RULE_RESYNC_PERIOD
=
__WRTD_ATTR_BASE
+
0x
12
,
WRTD_ATTR_RULE_RESYNC_PERIOD
=
__WRTD_ATTR_BASE
+
0x
28
,
/** `RW` `int32` `local` Further re-align the source Event timestamp to a multiple
of #WRTD_ATTR_RULE_RESYNC_PERIOD. As an example, if RESYNC_PERIOD
is 5us and the provided value is 10, 50us will be added to the Event timestamp,
after applying #WRTD_ATTR_RULE_DELAY and re-aligning it to the RESYNC_PERIOD. */
WRTD_ATTR_RULE_RESYNC_FACTOR
=
__WRTD_ATTR_BASE
+
0x
13
,
WRTD_ATTR_RULE_RESYNC_FACTOR
=
__WRTD_ATTR_BASE
+
0x
29
,
/** `RO` `int32` `local` Number of received Events for a Rule. */
WRTD_ATTR_STAT_RULE_RX_EVENTS
=
__WRTD_ATTR_BASE
+
0x
14
,
WRTD_ATTR_STAT_RULE_RX_EVENTS
=
__WRTD_ATTR_BASE
+
0x
30
,
/** `RO` `tstamp` `local` Timestamp of most recently received Event for a Rule. */
WRTD_ATTR_STAT_RULE_RX_LAST
=
__WRTD_ATTR_BASE
+
0x
15
,
WRTD_ATTR_STAT_RULE_RX_LAST
=
__WRTD_ATTR_BASE
+
0x
31
,
/** `RO` `int32` `local` Number of transmitted Events for a Rule. */
WRTD_ATTR_STAT_RULE_TX_EVENTS
=
__WRTD_ATTR_BASE
+
0x
16
,
WRTD_ATTR_STAT_RULE_TX_EVENTS
=
__WRTD_ATTR_BASE
+
0x
32
,
/** `RO` `tstamp` `local` Timestamp of most recently transmitted Event for a Rule. */
WRTD_ATTR_STAT_RULE_TX_LAST
=
__WRTD_ATTR_BASE
+
0x
17
,
WRTD_ATTR_STAT_RULE_TX_LAST
=
__WRTD_ATTR_BASE
+
0x
33
,
/** `RO` `int32` `local` Number of received Events that arrived too late.
See also #WRTD_ATTR_RULE_SEND_LATE. */
WRTD_ATTR_STAT_RULE_MISSED_LATE
=
__WRTD_ATTR_BASE
+
0x
18
,
WRTD_ATTR_STAT_RULE_MISSED_LATE
=
__WRTD_ATTR_BASE
+
0x
34
,
/** `RO` `int32` `local` Number of received Events that arrived during hold-off.
See also #WRTD_ATTR_RULE_HOLDOFF. */
WRTD_ATTR_STAT_RULE_MISSED_HOLDOFF
=
__WRTD_ATTR_BASE
+
0x
19
,
WRTD_ATTR_STAT_RULE_MISSED_HOLDOFF
=
__WRTD_ATTR_BASE
+
0x
35
,
/** `RO` `int32` `local` Number of received Events that were discarded because the
device was not synchronized to White Rabbit.
See also #WRTD_ATTR_IS_TIME_SYNCHRONIZED. */
WRTD_ATTR_STAT_RULE_MISSED_NOSYNC
=
__WRTD_ATTR_BASE
+
0x
1A
,
WRTD_ATTR_STAT_RULE_MISSED_NOSYNC
=
__WRTD_ATTR_BASE
+
0x
36
,
/** `RO` `int32` `local` Number of received Events that were discarded because of
internal buffer overflows. This may happen if the Event rate is too high. */
WRTD_ATTR_STAT_RULE_MISSED_OVERFLOW
=
__WRTD_ATTR_BASE
+
0x
1B
,
WRTD_ATTR_STAT_RULE_MISSED_OVERFLOW
=
__WRTD_ATTR_BASE
+
0x
37
,
/** `RO` `tstamp` `local` Timestamp of most recently missed Event. */
WRTD_ATTR_STAT_RULE_MISSED_LAST
=
__WRTD_ATTR_BASE
+
0x
1C
,
WRTD_ATTR_STAT_RULE_MISSED_LAST
=
__WRTD_ATTR_BASE
+
0x
38
,
/** `RO` `tstamp` `local` Minimum latency between the Event timestamp and its
reception by WRTD. */
WRTD_ATTR_STAT_RULE_RX_LATENCY_MIN
=
__WRTD_ATTR_BASE
+
0x
1D
,
reception by WRTD. */
WRTD_ATTR_STAT_RULE_RX_LATENCY_MIN
=
__WRTD_ATTR_BASE
+
0x
39
,
/** `RO` `tstamp` `local` Maximum latency between the Event timestamp and its
reception by WRTD. */
WRTD_ATTR_STAT_RULE_RX_LATENCY_MAX
=
__WRTD_ATTR_BASE
+
0x
1E
,
reception by WRTD. */
WRTD_ATTR_STAT_RULE_RX_LATENCY_MAX
=
__WRTD_ATTR_BASE
+
0x
3A
,
/** `RO` `tstamp` `local` Average latency between the Event timestamp and its
reception by WRTD. */
WRTD_ATTR_STAT_RULE_RX_LATENCY_AVG
=
__WRTD_ATTR_BASE
+
0x
1F
,
reception by WRTD. */
WRTD_ATTR_STAT_RULE_RX_LATENCY_AVG
=
__WRTD_ATTR_BASE
+
0x
3B
,
/** `RO` `tstamp` `local` Average period for source Events. */
WRTD_ATTR_STAT_RULE_RX_PERIOD_AVG
=
__WRTD_ATTR_BASE
+
0x
20
,
WRTD_ATTR_STAT_RULE_RX_PERIOD_AVG
=
__WRTD_ATTR_BASE
+
0x
3C
,
/** Always last entry in this enum */
__WRTD_ATTR_MAX_NUMBER
,
};
}
wrtd_attr
;
/** A repeated capability identifier for global attributes. */
#define WRTD_GLOBAL_REP_CAP_ID "WGRCI"
/** Size (in characters, including null termination) of an event log enty. */
#define WRTD_LOG_ENTRY_SIZE 91
/* ------------------------------------------------------------------- */
/* Function prototypes for the official WRTD API. Documented in wrtd.c */
enum
wrtd_status
wrtd_init
(
const
char
*
resource_name
,
bool
reset
,
const
char
*
options_str
,
struct
wrtd_dev
**
wrtd
);
enum
wrtd_status
wrtd_close
(
struct
wrtd_dev
*
wrtd
);
enum
wrtd_status
wrtd_reset
(
struct
wrtd_dev
*
wrtd
);
enum
wrtd_status
wrtd_get_error
(
struct
wrtd_dev
*
wrtd
,
enum
wrtd_status
*
error_code
,
int32_t
error_description_buffer_size
,
char
*
error_description
);
enum
wrtd_status
wrtd_error_message
(
struct
wrtd_dev
*
wrtd
,
enum
wrtd_status
err_code
,
char
*
err_message
);
enum
wrtd_status
wrtd_set_attr_bool
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
bool
value
);
enum
wrtd_status
wrtd_get_attr_bool
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
bool
*
value
);
enum
wrtd_status
wrtd_set_attr_int32
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
int32_t
value
);
enum
wrtd_status
wrtd_get_attr_int32
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
int32_t
*
value
);
enum
wrtd_status
wrtd_set_attr_string
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
const
char
*
value
);
enum
wrtd_status
wrtd_get_attr_string
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
int32_t
value_buf_size
,
char
*
value
);
enum
wrtd_status
wrtd_set_attr_tstamp
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
const
struct
wrtd_tstamp
*
value
);
enum
wrtd_status
wrtd_get_attr_tstamp
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
enum
wrtd_attr
id
,
struct
wrtd_tstamp
*
value
);
enum
wrtd_status
wrtd_get_sys_time
(
struct
wrtd_dev
*
wrtd
,
struct
wrtd_tstamp
*
time
);
enum
wrtd_status
wrtd_clear_event_log_entries
(
struct
wrtd_dev
*
wrtd
);
enum
wrtd_status
wrtd_get_next_event_log_entry
(
struct
wrtd_dev
*
wrtd
,
int32_t
log_entry_buffer_size
,
char
*
log_entry
);
enum
wrtd_status
wrtd_add_alarm
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
enum
wrtd_status
wrtd_disable_all_alarms
(
struct
wrtd_dev
*
wrtd
);
enum
wrtd_status
wrtd_remove_alarm
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
enum
wrtd_status
wrtd_remove_all_alarms
(
struct
wrtd_dev
*
wrtd
);
enum
wrtd_status
wrtd_get_alarm_name
(
struct
wrtd_dev
*
wrtd
,
int32_t
index
,
int32_t
name_buffer_size
,
char
*
rep_cap_id
);
enum
wrtd_status
wrtd_add_rule
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
enum
wrtd_status
wrtd_disable_all_rules
(
struct
wrtd_dev
*
wrtd
);
enum
wrtd_status
wrtd_remove_rule
(
struct
wrtd_dev
*
wrtd
,
/* ------------------------------------------------------------------- */
/* Initialisation */
wrtd_status
wrtd_init
(
const
char
*
resource_name
,
bool
reset
,
const
char
*
options_str
,
wrtd_dev
**
wrtd
);
wrtd_status
wrtd_close
(
wrtd_dev
*
wrtd
);
wrtd_status
wrtd_reset
(
wrtd_dev
*
wrtd
);
/* Errors */
wrtd_status
wrtd_get_error
(
wrtd_dev
*
wrtd
,
wrtd_status
*
error_code
,
int32_t
error_description_buffer_size
,
char
*
error_description
);
wrtd_status
wrtd_error_message
(
wrtd_dev
*
wrtd
,
wrtd_status
err_code
,
char
*
err_message
);
/* Attributes */
wrtd_status
wrtd_set_attr_bool
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
bool
value
);
wrtd_status
wrtd_get_attr_bool
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
bool
*
value
);
wrtd_status
wrtd_set_attr_int32
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
int32_t
value
);
wrtd_status
wrtd_get_attr_int32
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
int32_t
*
value
);
wrtd_status
wrtd_set_attr_string
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
const
char
*
value
);
wrtd_status
wrtd_get_attr_string
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
int32_t
value_buf_size
,
char
*
value
);
wrtd_status
wrtd_set_attr_tstamp
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
const
wrtd_tstamp
*
value
);
wrtd_status
wrtd_get_attr_tstamp
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
,
wrtd_attr
id
,
wrtd_tstamp
*
value
);
/* Event Log */
wrtd_status
wrtd_clear_event_log_entries
(
wrtd_dev
*
wrtd
);
wrtd_status
wrtd_get_next_event_log_entry
(
wrtd_dev
*
wrtd
,
int32_t
log_entry_buffer_size
,
char
*
log_entry
);
/* Alarms */
wrtd_status
wrtd_add_alarm
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
wrtd_status
wrtd_disable_all_alarms
(
wrtd_dev
*
wrtd
);
wrtd_status
wrtd_remove_alarm
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
wrtd_status
wrtd_remove_all_alarms
(
wrtd_dev
*
wrtd
);
wrtd_status
wrtd_get_alarm_name
(
wrtd_dev
*
wrtd
,
int32_t
index
,
int32_t
name_buffer_size
,
char
*
name
);
/* Rules */
wrtd_status
wrtd_add_rule
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
wrtd_status
wrtd_disable_all_rules
(
wrtd_dev
*
wrtd
);
wrtd_status
wrtd_remove_rule
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
wrtd_status
wrtd_remove_all_rules
(
wrtd_dev
*
wrtd
);
wrtd_status
wrtd_get_rule_name
(
wrtd_dev
*
wrtd
,
int32_t
index
,
int32_t
name_buffer_size
,
char
*
name
);
wrtd_status
wrtd_reset_rule_stats
(
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
enum
wrtd_status
wrtd_remove_all_rules
(
struct
wrtd_dev
*
wrtd
);
enum
wrtd_status
wrtd_get_rule_name
(
struct
wrtd_dev
*
wrtd
,
int32_t
index
,
int32_t
name_buffer_size
,
char
*
rep_cap_id
);
enum
wrtd_status
wrtd_reset_rule_stats
(
struct
wrtd_dev
*
wrtd
,
const
char
*
rep_cap_id
);
#ifdef __cplusplus
};
...
...
software/tools/wrtd-config.c
View file @
1394f372
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
/**
* @file wrtd-config.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
* Copyright (c) 2018-2019 CERN (home.cern)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <stdint.h>
...
...
@@ -118,11 +107,11 @@ static void disp_rule_conf(const struct wrtd_rule *rule, unsigned nbr_rules)
disp_id
(
cfg
->
dest_id
);
printf
(
"
\n
"
" dest_cpu: %u"
,
cfg
->
dest_cpu
);
if
(
cfg
->
dest_cpu
==
WRTD_DEST_CPU_LOCAL
)
printf
(
" (local)"
);
else
if
(
cfg
->
dest_cpu
==
WRTD_DEST_CH_NET
)
printf
(
" (net)"
);
printf
(
"
\n
"
);
if
(
cfg
->
dest_cpu
==
WRTD_DEST_CPU_LOCAL
)
printf
(
" (local)"
);
else
if
(
cfg
->
dest_cpu
==
WRTD_DEST_CH_NET
)
printf
(
" (net)"
);
printf
(
"
\n
"
);
printf
(
" dest_ch: %u
\n
"
,
cfg
->
dest_ch
);
printf
(
" enabled: %d
\n
"
,
cfg
->
enabled
);
printf
(
" hash: %u, hash_chain: %d
\n
"
,
...
...
@@ -367,7 +356,8 @@ static enum wrtd_status wrtd_cmd_sys_time(struct wrtd_dev *wrtd,
struct
wrtd_tstamp
t
;
enum
wrtd_status
res
;
res
=
wrtd_get_sys_time
(
wrtd
,
&
t
);
res
=
wrtd_get_attr_tstamp
(
wrtd
,
WRTD_GLOBAL_REP_CAP_ID
,
WRTD_ATTR_SYS_TIME
,
&
t
);
WRTD_RETURN_IF_ERROR
(
res
);
print_ts
(
&
t
);
...
...
@@ -481,7 +471,8 @@ static enum wrtd_status wrtd_cmd_set_alarm(struct wrtd_dev *wrtd,
/* Set time. */
status
=
wrtd_get_sys_time
(
wrtd
,
&
ts
);
status
=
wrtd_get_attr_tstamp
(
wrtd
,
WRTD_GLOBAL_REP_CAP_ID
,
WRTD_ATTR_SYS_TIME
,
&
ts
);
WRTD_RETURN_IF_ERROR
(
status
);
ts_add_ps
(
&
ts
,
delay
);
...
...
@@ -700,7 +691,7 @@ static enum wrtd_status wrtd_cmd_enable_rule(struct wrtd_dev *wrtd,
}
static
enum
wrtd_status
wrtd_cmd_disable_rule
(
struct
wrtd_dev
*
wrtd
,
int
argc
,
char
*
argv
[])
int
argc
,
char
*
argv
[])
{
return
wrtd_cmd_enable_disable_rule
(
wrtd
,
argc
,
argv
,
false
);
}
...
...
@@ -866,78 +857,78 @@ static struct wrtd_commands cmds[] = {
{
"clear-log"
,
""
,
"clear pending log entries"
,
wrtd_cmd_clear_log
},
#if 0
{ "state", "", "shows input state",
wrtd_cmd_state },
{ "enable", "", "enable the input",
wrtd_cmd_enable },
{ "disable", "", "disable the input",
wrtd_cmd_disable },
{ "deadtime", "<number>", "sets the dead time in pico-seconds",
wrtd_cmd_set_dead_time },
{ "delay", "<number>", "sets the input delay in pico-seconds",
wrtd_cmd_set_delay },
{ "mode", "<mode>", "sets triggering mode (see Trigger Modes)",
wrtd_cmd_set_mode },
{ "assign", "<trig-id>", "assigns a trigger (see Trigger ID)",
wrtd_cmd_assign },
{ "unassign", "", "un-assigns the currently assigned trigger",
wrtd_cmd_unassign },
{ "arm", "", "arms the input",
wrtd_cmd_arm },
{ "disarm", "", "disarms the input",
wrtd_cmd_disarm },
{ "reset", "", "resets statistics counters",
wrtd_cmd_reset },
{ "global_reset", "", "resets global statistics counters",
wrtd_cmd_global_reset },
{ "swtrig", "", "sends a software trigger",
wrtd_cmd_sw_trigger },
{ "log_level", "<level>", "set logging level (see Log Levels)",
wrtd_cmd_log_level },
{ "state", "", "shows input state",
wrtd_cmd_state },
{ "enable", "", "enable the input",
wrtd_cmd_enable },
{ "disable", "", "disable the input",
wrtd_cmd_disable },
{ "deadtime", "<number>", "sets the dead time in pico-seconds",
wrtd_cmd_set_dead_time },
{ "delay", "<number>", "sets the input delay in pico-seconds",
wrtd_cmd_set_delay },
{ "mode", "<mode>", "sets triggering mode (see Trigger Modes)",
wrtd_cmd_set_mode },
{ "assign", "<trig-id>", "assigns a trigger (see Trigger ID)",
wrtd_cmd_assign },
{ "unassign", "", "un-assigns the currently assigned trigger",
wrtd_cmd_unassign },
{ "arm", "", "arms the input",
wrtd_cmd_arm },
{ "disarm", "", "disarms the input",
wrtd_cmd_disarm },
{ "reset", "", "resets statistics counters",
wrtd_cmd_reset },
{ "global_reset", "", "resets global statistics counters",
wrtd_cmd_global_reset },
{ "swtrig", "", "sends a software trigger",
wrtd_cmd_sw_trigger },
{ "log_level", "<level>", "set logging level (see Log Levels)",
wrtd_cmd_log_level },
#endif
{
NULL
}
{
NULL
}
};
static
void
help
(
void
)
{
fprintf
(
stderr
,
"wrtd-config -D DEVICE -- COMMAND [cmd-options]
\n\n
"
);
fprintf
(
stderr
,
"It configures a White-Rabbit Trigger-Distribution node
\n\n
"
);
fprintf
(
stderr
,
"-D
\t
device id
\n
"
);
help_commands
(
cmds
);
exit
(
1
);
fprintf
(
stderr
,
"wrtd-config -D DEVICE -- COMMAND [cmd-options]
\n\n
"
);
fprintf
(
stderr
,
"It configures a White-Rabbit Trigger-Distribution node
\n\n
"
);
fprintf
(
stderr
,
"-D
\t
device id
\n
"
);
help_commands
(
cmds
);
exit
(
1
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
struct
wrtd_dev
*
wrtd
;
struct
wrtd_dev
*
wrtd
;
const
char
*
dev_name
=
NULL
;
enum
wrtd_status
status
;
char
*
cmd
=
NULL
;
char
*
cmd
=
NULL
;
char
c
;
int
i
;
char
error_description
[
256
];
enum
wrtd_status
error_code
;
while
((
c
=
getopt
(
argc
,
argv
,
"+hD:c:"
))
!=
-
1
)
{
switch
(
c
)
{
case
'h'
:
case
'?'
:
help
();
break
;
case
'D'
:
int
i
;
char
error_description
[
256
];
enum
wrtd_status
error_code
;
while
((
c
=
getopt
(
argc
,
argv
,
"+hD:c:"
))
!=
-
1
)
{
switch
(
c
)
{
case
'h'
:
case
'?'
:
help
();
break
;
case
'D'
:
dev_name
=
optarg
;
break
;
}
}
break
;
}
}
if
(
dev_name
==
NULL
||
optind
==
argc
)
{
help
();
exit
(
1
);
}
if
(
dev_name
==
NULL
||
optind
==
argc
)
{
help
();
exit
(
1
);
}
/* Find command. */
cmd
=
argv
[
optind
++
];
for
(
i
=
0
;
cmds
[
i
].
handler
;
i
++
)
{
for
(
i
=
0
;
cmds
[
i
].
handler
;
i
++
)
{
if
(
!
strcmp
(
cmds
[
i
].
name
,
cmd
))
break
;
}
...
...
@@ -947,13 +938,13 @@ int main(int argc, char *argv[])
}
/* Open. */
status
=
wrtd_init
(
dev_name
,
0
,
NULL
,
&
wrtd
);
if
(
status
!=
WRTD_SUCCESS
)
{
fprintf
(
stderr
,
status
=
wrtd_init
(
dev_name
,
0
,
NULL
,
&
wrtd
);
if
(
status
!=
WRTD_SUCCESS
)
{
fprintf
(
stderr
,
"Cannot open WRTD %s, status=0x%08x (errno=%s)
\n
"
,
dev_name
,
status
,
strerror
(
errno
));
return
1
;
}
}
status
=
cmds
[
i
].
handler
(
wrtd
,
argc
-
optind
,
argv
+
optind
);
if
(
status
!=
WRTD_SUCCESS
)
{
...
...
@@ -963,7 +954,7 @@ int main(int argc, char *argv[])
cmd
,
error_description
);
}
wrtd_close
(
wrtd
);
wrtd_close
(
wrtd
);
return
0
;
}
software/tools/wrtd-inout-common.c
View file @
1394f372
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
/**
* @file wrtd-inout-common.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
* Copyright (c) 2018-2019 CERN (home.cern)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <stdint.h>
...
...
@@ -46,137 +35,137 @@ void print_ts(const struct wrtd_tstamp *ts)
void
help_commands
(
struct
wrtd_commands
*
cmds
)
{
int
i
;
int
i
;
fprintf
(
stderr
,
"Available commands:
\n
"
);
for
(
i
=
0
;
cmds
[
i
].
handler
;
i
++
)
{
fprintf
(
stderr
,
" %s %s
\n\t
%s
\n\n
"
,
cmds
[
i
].
name
,
cmds
[
i
].
parm
,
cmds
[
i
].
desc
);
}
fprintf
(
stderr
,
"Available commands:
\n
"
);
for
(
i
=
0
;
cmds
[
i
].
handler
;
i
++
)
{
fprintf
(
stderr
,
" %s %s
\n\t
%s
\n\n
"
,
cmds
[
i
].
name
,
cmds
[
i
].
parm
,
cmds
[
i
].
desc
);
}
}
#if 0
void help_log_level()
{
fprintf(stderr, "Log Levels\n");
fprintf(stderr, "You can set more than one log level. Here the list of valid log level strings:\n\n");
fprintf(stderr, "\toff, Raw, Sent, Promiscious, Executed, Missed.\n\n");
fprintf(stderr, "For details about their meaning refer, for example, to the library documentation.\n\n");
fprintf(stderr, "Log Levels\n");
fprintf(stderr, "You can set more than one log level. Here the list of valid log level strings:\n\n");
fprintf(stderr, "\toff, Raw, Sent, Promiscious, Executed, Missed.\n\n");
fprintf(stderr, "For details about their meaning refer, for example, to the library documentation.\n\n");
}
void help_trig_mode()
{
fprintf(stderr, "Trigger Modes\n");
fprintf(stderr, "You can active only one trigger mode at time. Following the list of valid trigger mode strings:\n\n");
fprintf(stderr, "\tauto, single\n\n");
fprintf(stderr, "For details about their meaning refer, for example, to the library documentation.\n\n");
fprintf(stderr, "Trigger Modes\n");
fprintf(stderr, "You can active only one trigger mode at time. Following the list of valid trigger mode strings:\n\n");
fprintf(stderr, "\tauto, single\n\n");
fprintf(stderr, "For details about their meaning refer, for example, to the library documentation.\n\n");
}
void help_trig_id()
{
fprintf(stderr, "Trigger ID\n");
fprintf(stderr, "The trigger Id is made of 3 number separated by a colon\n\n");
fprintf(stderr, "\t<number>:<number>:<number>\n\n");
fprintf(stderr, "Looking at them from their semantic point of view:\n\n");
fprintf(stderr, "\t<system>:<port>:<trigger>\n\n");
fprintf(stderr, "For details about their meaning refer, for example, to the library documentation.\n\n");
fprintf(stderr, "Trigger ID\n");
fprintf(stderr, "The trigger Id is made of 3 number separated by a colon\n\n");
fprintf(stderr, "\t<number>:<number>:<number>\n\n");
fprintf(stderr, "Looking at them from their semantic point of view:\n\n");
fprintf(stderr, "\t<system>:<port>:<trigger>\n\n");
fprintf(stderr, "For details about their meaning refer, for example, to the library documentation.\n\n");
}
void decode_flags(char *buf, uint32_t flags)
{
int l;
strcpy(buf,"");
if( flags & WRTD_ENABLED )
strcat(buf, "Enabled ");
if( flags & WRTD_TRIGGER_ASSIGNED )
strcat(buf, "TrigAssigned ");
if( flags & WRTD_LAST_VALID )
strcat(buf, "LastTimestampValid ");
if( flags & WRTD_ARMED )
strcat(buf, "Armed ");
if( flags & WRTD_TRIGGERED )
strcat(buf, "Triggered ");
if( flags & WRTD_NO_WR )
strcat(buf, "NoWRTiming ");
l = strlen(buf);
if(l)
buf[l-1] = 0;
int l;
strcpy(buf,"");
if( flags & WRTD_ENABLED )
strcat(buf, "Enabled ");
if( flags & WRTD_TRIGGER_ASSIGNED )
strcat(buf, "TrigAssigned ");
if( flags & WRTD_LAST_VALID )
strcat(buf, "LastTimestampValid ");
if( flags & WRTD_ARMED )
strcat(buf, "Armed ");
if( flags & WRTD_TRIGGERED )
strcat(buf, "Triggered ");
if( flags & WRTD_NO_WR )
strcat(buf, "NoWRTiming ");
l = strlen(buf);
if(l)
buf[l-1] = 0;
}
void decode_mode(char *buf, int mode)
{
switch(mode)
{
switch(mode)
{
case WRTD_TRIGGER_MODE_AUTO:
strcpy(buf, "Auto");
break;
strcpy(buf, "Auto");
break;
case WRTD_TRIGGER_MODE_SINGLE:
strcpy(buf, "Single shot");
break;
strcpy(buf, "Single shot");
break;
default:
strcpy(buf,"?");
break;
}
strcpy(buf,"?");
break;
}
}
void format_ts(char *buf, struct wr_timestamp ts, int with_seconds)
{
uint64_t picoseconds = (uint64_t) ts.ticks * 8000 + (uint64_t)ts.frac * 8000ULL / 4096ULL;
if(with_seconds)
{
sprintf (buf, "%llu:%03llu,%03llu,%03llu ns + %3llu ps",
(long long)(ts.seconds),
(picoseconds / (1000LL * 1000 * 1000)),
(picoseconds / (1000LL * 1000) % 1000),
(picoseconds / (1000LL) % 1000),
(picoseconds % 1000LL));
} else {
sprintf (buf, "%03llu,%03llu,%03llu ns + %3llu ps",
(picoseconds / (1000LL * 1000 * 1000)),
(picoseconds / (1000LL * 1000) % 1000),
(picoseconds / (1000LL) % 1000),
(picoseconds % 1000LL));
}
uint64_t picoseconds = (uint64_t) ts.ticks * 8000 + (uint64_t)ts.frac * 8000ULL / 4096ULL;
if(with_seconds)
{
sprintf (buf, "%llu:%03llu,%03llu,%03llu ns + %3llu ps",
(long long)(ts.seconds),
(picoseconds / (1000LL * 1000 * 1000)),
(picoseconds / (1000LL * 1000) % 1000),
(picoseconds / (1000LL) % 1000),
(picoseconds % 1000LL));
} else {
sprintf (buf, "%03llu,%03llu,%03llu ns + %3llu ps",
(picoseconds / (1000LL * 1000 * 1000)),
(picoseconds / (1000LL * 1000) % 1000),
(picoseconds / (1000LL) % 1000),
(picoseconds % 1000LL));
}
}
void format_ago(char *buf, struct wr_timestamp ts, struct wr_timestamp current)
{
uint64_t delta = current.seconds - ts.seconds;
char when[16];
if (delta < 0)
{
sprintf(when, "future");
delta = -delta;
} else {
sprintf(when, "past");
}
if(delta < 60)
sprintf(buf, "%lu seconds in the %s", delta, when);
else if (delta < 3600)
sprintf(buf, "%lu minutes in the %s", delta/60, when);
else if (delta < 3600*24)
sprintf(buf, "%lu hours in the %s", delta/3600, when);
else
sprintf(buf, "%lu days in the %s", delta/(24*3600), when);
uint64_t delta = current.seconds - ts.seconds;
char when[16];
if (delta < 0)
{
sprintf(when, "future");
delta = -delta;
} else {
sprintf(when, "past");
}
if(delta < 60)
sprintf(buf, "%lu seconds in the %s", delta, when);
else if (delta < 3600)
sprintf(buf, "%lu minutes in the %s", delta/60, when);
else if (delta < 3600*24)
sprintf(buf, "%lu hours in the %s", delta/3600, when);
else
sprintf(buf, "%lu days in the %s", delta/(24*3600), when);
}
void format_id(char *buf, struct wrtd_trig_id id)
{
sprintf( buf, "%04x:%04x:%08x", id.system, id.source_port,id.trigger);
sprintf( buf, "%04x:%04x:%08x", id.system, id.source_port,id.trigger);
}
uint64_t ts_to_picos(struct wr_timestamp ts)
{
return (uint64_t) ts.seconds * 1000LL * 1000 * 1000 * 1000
+ (uint64_t) ts.ticks * 8000ULL +
+ (uint64_t) ts.frac * 8000LL / 4096LL;
return (uint64_t) ts.seconds * 1000LL * 1000 * 1000 * 1000
+ (uint64_t) ts.ticks * 8000ULL +
+ (uint64_t) ts.frac * 8000LL / 4096LL;
}
#endif
...
...
@@ -195,11 +184,11 @@ int parse_delay(char *dly, uint64_t *delay_ps)
mult
=
1
;
switch
(
last
)
{
case
'm'
:
mult
=
1000ULL
*
1000
*
1000
;
l
--
;
break
;
case
'u'
:
mult
=
1000ULL
*
1000
;
l
--
;
break
;
case
'n'
:
mult
=
1000ULL
;
l
--
;
break
;
case
'p'
:
mult
=
1
;
l
--
;
break
;
default:
mult
=
1
;
break
;
case
'm'
:
mult
=
1000ULL
*
1000
*
1000
;
l
--
;
break
;
case
'u'
:
mult
=
1000ULL
*
1000
;
l
--
;
break
;
case
'n'
:
mult
=
1000ULL
;
l
--
;
break
;
case
'p'
:
mult
=
1
;
l
--
;
break
;
default:
mult
=
1
;
break
;
}
dly
[
l
]
=
0
;
...
...
@@ -269,19 +258,19 @@ void ts_sub_ps(struct wrtd_tstamp *ts, uint64_t ps)
#if 0
int parse_mode (char *mode_str, enum wrtd_trigger_mode *mode)
{
if(!strcmp(mode_str, "auto"))
*mode = WRTD_TRIGGER_MODE_AUTO;
else if(!strcmp(mode_str, "single"))
*mode = WRTD_TRIGGER_MODE_SINGLE;
else
return -1;
return 0;
if(!strcmp(mode_str, "auto"))
*mode = WRTD_TRIGGER_MODE_AUTO;
else if(!strcmp(mode_str, "single"))
*mode = WRTD_TRIGGER_MODE_SINGLE;
else
return -1;
return 0;
}
int parse_trigger_id(const char *str, struct wrtd_trig_id *id)
{
return (sscanf(str,"%x:%x:%x", &id->system, &id->source_port, &id->trigger) == 3 ? 0 : -1);
return (sscanf(str,"%x:%x:%x", &id->system, &id->source_port, &id->trigger) == 3 ? 0 : -1);
}
int parse_log_level (char *list[], int count, int *log_level)
...
...
software/tools/wrtd-internal.h
View file @
1394f372
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
/**
* @file wrtd-internal.h
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* Copyright (c) 2018-2019 CERN (home.cern)
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#ifndef __WRTD_TOOLS_INTERNAL_H__
...
...
@@ -24,9 +13,9 @@
#include <libwrtd.h>
struct
wrtd_commands
{
const
char
*
name
;
const
char
*
parm
;
const
char
*
desc
;
const
char
*
name
;
const
char
*
parm
;
const
char
*
desc
;
enum
wrtd_status
(
*
handler
)(
struct
wrtd_dev
*
wrtd
,
int
argc
,
char
**
argv
);
};
...
...
software/tools/wrtd-logging.c
View file @
1394f372
/*
* Copyright (C) 2014-2016 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
/**
* @file wrtd-logging.c
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
* Copyright (c) 2018-2019 CERN (home.cern)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
#include <stdint.h>
...
...
@@ -29,21 +19,20 @@
static
void
help
(
void
)
{
fprintf
(
stderr
,
"wrtd-logging -D <device>
\n
"
);
fprintf
(
stderr
,
"It shows logging information coming from Real-Time applications
\n
"
);
fprintf
(
stderr
,
"-D device id
\n
"
);
fprintf
(
stderr
,
"-n number of messages to read (0 means infinite)
\n
"
);
exit
(
1
);
fprintf
(
stderr
,
"wrtd-logging -D <device>
\n
"
);
fprintf
(
stderr
,
"It shows logging information coming from Real-Time applications
\n
"
);
fprintf
(
stderr
,
"-D device id
\n
"
);
fprintf
(
stderr
,
"-n number of messages to read (0 means infinite)
\n
"
);
exit
(
1
);
}
static
void
print_logging
(
struct
wrtd_dev
*
wrtd
,
int
n_read
)
{
char
log_entry
[
WRTD_LOG_ENTRY_SIZE
];
enum
wrtd_status
status
;
unsigned
int
i
;
for
(
i
=
0
;
i
<
n_read
||
n_read
==
0
;
i
++
)
{
for
(
i
=
0
;
i
<
n_read
||
n_read
==
0
;
i
++
)
{
do
{
status
=
wrtd_get_next_event_log_entry
(
wrtd
,
WRTD_LOG_ENTRY_SIZE
,
log_entry
);
...
...
@@ -63,48 +52,48 @@ static void print_logging (struct wrtd_dev *wrtd, int n_read)
int
main
(
int
argc
,
char
*
argv
[])
{
struct
wrtd_dev
*
wrtd
;
struct
wrtd_dev
*
wrtd
;
const
char
*
dev_name
=
NULL
;
enum
wrtd_status
status
;
char
*
endptr
;
int
n_read
=
0
;
char
c
;
int
n_read
=
0
;
char
c
;
while
((
c
=
getopt
(
argc
,
argv
,
"hD:n:"
))
!=
-
1
)
{
switch
(
c
)
{
default:
help
();
break
;
case
'D'
:
while
((
c
=
getopt
(
argc
,
argv
,
"hD:n:"
))
!=
-
1
)
{
switch
(
c
)
{
default:
help
();
break
;
case
'D'
:
dev_name
=
optarg
;
break
;
case
'n'
:
n_read
=
strtoul
(
optarg
,
&
endptr
,
0
);
if
(
*
endptr
!=
0
)
{
fprintf
(
stderr
,
"bad value for -n"
);
exit
(
1
);
}
break
;
}
}
break
;
case
'n'
:
n_read
=
strtoul
(
optarg
,
&
endptr
,
0
);
if
(
*
endptr
!=
0
)
{
fprintf
(
stderr
,
"bad value for -n"
);
exit
(
1
);
}
break
;
}
}
if
(
dev_name
==
NULL
)
{
help
();
exit
(
1
);
}
if
(
dev_name
==
NULL
)
{
help
();
exit
(
1
);
}
/* Open. */
status
=
wrtd_init
(
dev_name
,
0
,
NULL
,
&
wrtd
);
if
(
status
!=
WRTD_SUCCESS
)
{
status
=
wrtd_init
(
dev_name
,
0
,
NULL
,
&
wrtd
);
if
(
status
!=
WRTD_SUCCESS
)
{
char
error_message
[
256
];
enum
wrtd_status
error_status
;
wrtd_get_error
(
wrtd
,
&
error_status
,
256
,
error_message
);
fprintf
(
stderr
,
"Cannot open WRTD: %s
\n
"
,
error_message
);
return
1
;
}
}
print_logging
(
wrtd
,
n_read
);
print_logging
(
wrtd
,
n_read
);
wrtd_close
(
wrtd
);
exit
(
0
);
wrtd_close
(
wrtd
);
exit
(
0
);
}
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