Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC DEL 1ns 4cha - Software
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
FMC DEL 1ns 4cha - Software
Commits
f7f60598
Commit
f7f60598
authored
Apr 25, 2012
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
calibrate: now in a separate file (still not working)
parent
8779d604
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
215 additions
and
51 deletions
+215
-51
Makefile
Makefile
+1
-1
acam.c
acam.c
+6
-48
calibrate.c
calibrate.c
+179
-0
fine-delay.h
fine-delay.h
+29
-2
No files found.
Makefile
View file @
f7f60598
...
...
@@ -13,7 +13,7 @@ obj-m := spec-fine-delay.o
spec-fine-delay-objs
=
fd-zio.o fd-spec.o fd-core.o
spec-fine-delay-objs
+=
onewire.o spi.o i2c.o gpio.o
spec-fine-delay-objs
+=
acam.o pll.o time.o
spec-fine-delay-objs
+=
acam.o
calibrate.o
pll.o time.o
all
:
modules
...
...
acam.c
View file @
f7f60598
...
...
@@ -92,14 +92,14 @@ static void acam_set_address(struct spec_fd *fd, int addr)
}
/* Warning: acam_readl and acam_writel only work if GCR.BYPASS is set */
static
uint32_t
acam_readl
(
struct
spec_fd
*
fd
,
int
reg
)
uint32_t
acam_readl
(
struct
spec_fd
*
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
;
}
static
void
acam_writel
(
struct
spec_fd
*
fd
,
int
val
,
int
reg
)
void
acam_writel
(
struct
spec_fd
*
fd
,
int
val
,
int
reg
)
{
acam_set_address
(
fd
,
reg
);
fd_writel
(
fd
,
val
,
FD_REG_TDR
);
...
...
@@ -183,48 +183,6 @@ out:
return
-
EIO
;
}
static
int
acam_test_delay_transfer_function
(
struct
spec_fd
*
fd
)
{
/* FIXME */
return
0
;
}
/* Evaluates 2nd order polynomial. Coefs have 32 fractional bits. */
static
int
fd_eval_polynomial
(
struct
spec_fd
*
fd
)
{
int64_t
x
=
fd
->
temp
;
int64_t
*
coef
=
fd
->
calib
.
frr_poly
;
return
(
coef
[
0
]
*
x
*
x
+
coef
[
1
]
*
x
+
coef
[
2
])
>>
32
;
}
static
int
fd_find_8ns_tap
(
struct
spec_fd
*
fd
,
int
ch
)
{
/* FIXME */
return
0
;
}
static
int
acam_calibrate_outputs
(
struct
spec_fd
*
fd
)
{
int
ret
,
ch
;
int
measured
,
fitted
;
if
((
ret
=
acam_test_delay_transfer_function
(
fd
))
<
0
)
return
ret
;
fitted
=
fd_eval_polynomial
(
fd
);
for
(
ch
=
FD_CH_1
;
ch
<=
FD_CH_LAST
;
ch
++
)
{
fd_read_temp
(
fd
,
0
);
measured
=
fd_find_8ns_tap
(
fd
,
ch
);
fd
->
ch
[
ch
].
frr_cur
=
measured
;
fd
->
ch
[
ch
].
frr_offset
=
measured
-
fitted
;
pr_info
(
"%s: ch %i: 8ns @ %i (f %i, offset %i, t %i.%02i)
\n
"
,
__func__
,
FD_CH_EXT
(
ch
),
fd
->
ch
[
ch
].
frr_cur
,
fitted
,
fd
->
ch
[
ch
].
frr_offset
,
fd
->
temp
/
16
,
(
fd
->
temp
&
0xf
)
*
100
/
16
);
}
return
0
;
}
/* We need to write come static configuration in the registers */
struct
acam_init_data
{
...
...
@@ -288,16 +246,16 @@ static struct acam_mode_setup fd_acam_table[] = {
/* To configure the thing, follow the table, but treat 5 and 7 as special */
static
int
__acam_config
(
struct
spec_fd
*
fd
,
struct
acam_mode_setup
*
s
)
{
int
i
,
bin
,
hsdiv
,
refdiv
,
reg7val
;
int
i
,
hsdiv
,
refdiv
,
reg7val
;
struct
acam_init_data
*
p
;
uint32_t
regval
;
unsigned
long
j
;
bin
=
acam_calc_pll
(
ACAM_FP_TREF
,
ACAM_FP_BIN
,
&
hsdiv
,
&
refdiv
);
fd
->
bin
=
acam_calc_pll
(
ACAM_FP_TREF
,
ACAM_FP_BIN
,
&
hsdiv
,
&
refdiv
);
reg7val
=
AR7_HSDiv
(
hsdiv
)
|
AR7_RefClkDiv
(
refdiv
);
pr_debug
(
"%s: config for %s-mode (bin 0x%x, hsdiv %i, refdiv %i)
\n
"
,
__func__
,
s
->
name
,
bin
,
hsdiv
,
refdiv
);
__func__
,
s
->
name
,
fd
->
bin
,
hsdiv
,
refdiv
);
/* Disable TDC inputs prior to configuring */
fd_writel
(
fd
,
FD_TDCSR_STOP_DIS
|
FD_TDCSR_START_DIS
,
FD_REG_TDCSR
);
...
...
@@ -352,7 +310,7 @@ int fd_acam_init(struct spec_fd *fd)
if
(
(
ret
=
fd_acam_config
(
fd
,
ACAM_IMODE
))
)
return
ret
;
if
(
(
ret
=
acam
_calibrate_outputs
(
fd
))
)
if
(
(
ret
=
fd
_calibrate_outputs
(
fd
))
)
return
ret
;
if
(
(
ret
=
fd_acam_config
(
fd
,
ACAM_RMODE
))
)
...
...
calibrate.c
0 → 100644
View file @
f7f60598
/*
* Calibrate the output path.
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/delay.h>
#include "fine-delay.h"
#include "hw/fd_main_regs.h"
#include "hw/acam_gpx.h"
#include "hw/fd_channel_regs.h"
/* TEMP! */
static
void
acam_set_bypass
(
struct
spec_fd
*
fd
,
int
on
)
{
/* FIXME: this zeroes all other GCR bits */
fd_writel
(
fd
,
on
?
FD_GCR_BYPASS
:
0
,
FD_REG_GCR
);
}
static
int
acam_test_delay_transfer_function
(
struct
spec_fd
*
fd
)
{
/* FIXME */
return
0
;
}
/* Evaluates 2nd order polynomial. Coefs have 32 fractional bits. */
static
int
fd_eval_polynomial
(
struct
spec_fd
*
fd
)
{
int64_t
x
=
fd
->
temp
;
int64_t
*
coef
=
fd
->
calib
.
frr_poly
;
return
(
coef
[
0
]
*
x
*
x
+
coef
[
1
]
*
x
+
coef
[
2
])
>>
32
;
}
/*
* 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
* (fine). Retuns the delay in picoseconds. The measurement is
* repeated and averaged (n_avgs) times. Also, the standard deviation
* of the result can be written to (sdev) if it's not NULL.
*/
struct
delay_stats
{
uint32_t
avg
;
uint32_t
min
;
uint32_t
max
;
};
/* Note: channel is the "internal" one: 0..3 */
static
uint32_t
output_delay_ps
(
struct
spec_fd
*
fd
,
int
ch
,
int
fine
,
int
n
,
struct
delay_stats
*
stats
)
{
int
i
;
uint32_t
res
,
*
results
;
uint64_t
acc
=
0
;
results
=
kmalloc
(
n
*
sizeof
(
*
results
),
GFP_KERNEL
);
if
(
!
results
)
return
-
ENOMEM
;
/* 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
);
/* Program the output delay line setpoint */
fd_ch_writel
(
fd
,
ch
,
fine
,
FD_REG_FRR
);
fd_ch_writel
(
fd
,
ch
,
FD_DCR_ENABLE
|
FD_DCR_MODE
|
FD_DCR_UPDATE
,
FD_REG_DCR
);
fd_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
(
100
);
/* 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
(
100
);
/* 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
(
10000
);
/* read the tag, convert to picoseconds (fixed point: 16.16) */
fr
=
acam_readl
(
fd
,
8
/* fifo */
);
res
=
fr
&
0x1ffff
*
fd
->
bin
*
3
;
/* bin is 16.16 already */
printk
(
"%i: %08x, 0x%08x
\n
"
,
fine
,
fr
,
res
);
results
[
i
]
=
res
;
acc
+=
res
;
}
fd_ch_writel
(
fd
,
ch
,
0
,
FD_REG_DCR
);
/* Calculate avg, min max */
acc
=
(
acc
+
n
/
2
)
/
n
;
if
(
stats
)
{
stats
->
avg
=
acc
;
stats
->
min
=
~
0
;
stats
->
max
=
0
;
for
(
i
=
0
;
i
<
n
;
i
++
)
{
if
(
results
[
i
]
>
stats
->
max
)
stats
->
max
=
results
[
i
];
if
(
results
[
i
]
<
stats
->
min
)
stats
->
min
=
results
[
i
];
}
}
kfree
(
results
);
return
acc
;
}
static
int
fd_find_8ns_tap
(
struct
spec_fd
*
fd
,
int
ch
)
{
int
l
=
0
,
mid
,
r
=
FD_NUM_TAPS
-
1
;
uint32_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).
*/
bias
=
output_delay_ps
(
fd
,
ch
,
0
,
FD_CAL_STEPS
,
NULL
);
while
(
r
-
l
>
1
)
{
mid
=
(
l
+
r
)
/
2
;
dly
=
output_delay_ps
(
fd
,
ch
,
mid
,
FD_CAL_STEPS
,
NULL
)
-
bias
;
printk
(
"%i %i %i %08xx (bias %08x)
\n
"
,
l
,
r
,
mid
,
dly
,
bias
);
if
(
dly
<
8000
<<
16
)
l
=
mid
;
else
r
=
mid
;
}
return
l
;
}
int
fd_calibrate_outputs
(
struct
spec_fd
*
fd
)
{
int
ret
,
ch
;
int
measured
,
fitted
;
acam_set_bypass
(
fd
,
1
);
/* not useful */
fd_writel
(
fd
,
FD_TDCSR_START_EN
|
FD_TDCSR_STOP_EN
,
FD_REG_TDCSR
);
if
((
ret
=
acam_test_delay_transfer_function
(
fd
))
<
0
)
return
ret
;
fitted
=
fd_eval_polynomial
(
fd
);
for
(
ch
=
FD_CH_1
;
ch
<=
FD_CH_LAST
;
ch
++
)
{
fd_read_temp
(
fd
,
0
);
measured
=
fd_find_8ns_tap
(
fd
,
ch
);
fd
->
ch
[
ch
].
frr_cur
=
measured
;
fd
->
ch
[
ch
].
frr_offset
=
measured
-
fitted
;
pr_info
(
"%s: ch %i: 8ns @ %i (f %i, offset %i, t %i.%02i)
\n
"
,
__func__
,
FD_CH_EXT
(
ch
),
fd
->
ch
[
ch
].
frr_cur
,
fitted
,
fd
->
ch
[
ch
].
frr_offset
,
fd
->
temp
/
16
,
(
fd
->
temp
&
0xf
)
*
100
/
16
);
}
return
0
;
}
fine-delay.h
View file @
f7f60598
...
...
@@ -20,6 +20,9 @@ struct fd_calib {
#define FD_CH_INT(i) ((i) - 1)
#define FD_CH_EXT(i) ((i) + 1)
#define FD_NUM_TAPS 1024
#define FD_CAL_STEPS 16 //1024
struct
fd_ch
{
/* Offset between FRR measured at known T at startup and poly-fitted */
uint32_t
frr_offset
;
...
...
@@ -36,6 +39,7 @@ struct spec_fd {
unsigned
char
__iomem
*
base
;
/* regs files are byte-oriented */
unsigned
char
__iomem
*
regs
;
unsigned
char
__iomem
*
ow_regs
;
uint32_t
bin
;
int
acam_addr
;
/* cache of currently active addr */
uint8_t
ds18_id
[
8
];
unsigned
long
next_t
;
...
...
@@ -61,6 +65,26 @@ static inline void fd_writel(struct spec_fd *fd, uint32_t v, unsigned long reg)
writel
(
v
,
fd
->
regs
+
reg
);
}
static
inline
void
__check_chan
(
int
x
)
{
BUG_ON
(
x
<
0
||
x
>
3
);
}
static
inline
uint32_t
fd_ch_readl
(
struct
spec_fd
*
fd
,
int
ch
,
unsigned
long
reg
)
{
__check_chan
(
ch
);
return
fd_readl
(
fd
,
0x100
+
ch
*
0x100
+
reg
);
}
static
inline
void
fd_ch_writel
(
struct
spec_fd
*
fd
,
int
ch
,
uint32_t
v
,
unsigned
long
reg
)
{
__check_chan
(
ch
);
fd_writel
(
fd
,
v
,
0x100
+
ch
*
0x100
+
reg
);
}
#define FD_REGS_OFFSET 0x84000
#define FD_MAGIC_FPGA 0xf19ede1a
/* FD_REG_IDR content */
...
...
@@ -134,6 +158,11 @@ extern int fd_read_temp(struct spec_fd *fd, int verbose);
/* Functions exported by acam.c */
extern
int
fd_acam_init
(
struct
spec_fd
*
fd
);
extern
void
fd_acam_exit
(
struct
spec_fd
*
fd
);
extern
uint32_t
acam_readl
(
struct
spec_fd
*
fd
,
int
reg
);
extern
void
acam_writel
(
struct
spec_fd
*
fd
,
int
val
,
int
reg
);
/* Functions exported by calibrate.c, called within acam.c */
extern
int
fd_calibrate_outputs
(
struct
spec_fd
*
fd
);
/* Functions exported by gpio.c */
extern
int
fd_gpio_init
(
struct
spec_fd
*
fd
);
...
...
@@ -152,8 +181,6 @@ extern int fd_time_set(struct spec_fd *fd, struct fd_time *t,
extern
int
fd_time_get
(
struct
spec_fd
*
fd
,
struct
fd_time
*
t
,
struct
timespec
*
ts
);
/* Functions exported by fd-zio.c */
extern
int
fd_zio_register
(
void
);
extern
void
fd_zio_unregister
(
void
);
...
...
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