Commit 9660ad52 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

wip: fixed TS readout, added support for hardware offset adjustment and HW delta…

wip: fixed TS readout, added support for hardware offset adjustment and HW delta timestamps (to be implemented in userland)
parent 82f87f34
......@@ -15,7 +15,7 @@ ccflags-y = -DGIT_VERSION=\"$(GIT_VERSION)\" \
ccflags-$(CONFIG_FMC_TDC_DEBUG) += -DDEBUG
ccflags-$(CONFIG_FMC_TDC_VERBOSE_DEBUG) += -DVERBOSE_DEBUG
ccflags-y += -Werror
#ccflags-y += -Werror
# Extract minimum com major, minor and patch number
ccflags-y += -D__ZIO_MIN_MAJOR_VERSION=$(shell echo $(ZIO_VERSION) | cut -d '-' -f 2 | cut -d '.' -f 1; )
......
......@@ -62,8 +62,6 @@ int ft_acam_init(struct fmctdc_dev *ft)
int i;
unsigned long tmo;
dev_dbg(&ft->fmc->dev, "%s: initializing ACAM TDC...\n", __func__);
ft_writel(ft, TDC_CTRL_RESET_ACAM, TDC_REG_CTRL);
udelay(100);
......@@ -85,8 +83,6 @@ int ft_acam_init(struct fmctdc_dev *ft)
tmo = jiffies + 2 * HZ;
while (time_before(jiffies, tmo)) {
if (acam_is_pll_locked(ft)) {
dev_dbg(&ft->fmc->dev, "%s: ACAM initialization OK.\n",
__func__);
return 0;
}
}
......
......@@ -207,6 +207,7 @@ static inline u32 ft_ioread(struct fmctdc_dev *ft, unsigned long addr)
static inline void ft_iowrite(struct fmctdc_dev *ft,
u32 value, unsigned long addr)
{
// printk("ft_iowrite %x %x\n", addr, value );
fmc_writel(ft->fmc, value, addr);
}
......@@ -299,6 +300,12 @@ uint32_t ft_irq_coalescing_timeout_get(struct fmctdc_dev *ft,
int test_dma(struct fmctdc_dev *ft, unsigned int buf_size,
unsigned int use_sg);
void ft_set_delta_reference(struct fmctdc_dev *ft,
unsigned int chan, unsigned int ref);
uint32_t ft_get_delta_reference(struct fmctdc_dev *ft,
unsigned int chan);
/**
* It enables the acquisition on a give channel
* @ft FmcTdc FMC TDC device instance
......
......@@ -28,6 +28,7 @@
#include "fmc-tdc.h"
#include "hw/tdc_regs.h"
#include "hw/timestamp_fifo_regs.h"
static int dma_buf_ddr_burst_size_default = 16;
module_param_named(dma_buf_ddr_burst_size, dma_buf_ddr_burst_size_default,
......@@ -150,6 +151,28 @@ static void ft_buffer_burst_disable(struct fmctdc_dev *ft,
}
void ft_set_delta_reference(struct fmctdc_dev *ft,
unsigned int chan, unsigned int ref)
{
uint32_t fifo_addr = ft->ft_fifo_base + TDC_FIFO_OFFSET * chan;
uint32_t csr = ft_ioread(ft, fifo_addr + TSF_REG_CSR);
csr &= ~TSF_CSR_DELTA_REF_MASK;
csr |= (ref - 1) << TSF_CSR_DELTA_REF_SHIFT;
csr |= TSF_CSR_DELTA_READ;
ft_iowrite(ft, csr, fifo_addr + TSF_REG_CSR);
}
uint32_t ft_get_delta_reference(struct fmctdc_dev *ft,
unsigned int chan)
{
uint32_t fifo_addr = ft->ft_fifo_base + TDC_FIFO_OFFSET * chan;
uint32_t csr = ft_ioread(ft, fifo_addr + TSF_REG_CSR);
return TSF_CSR_DELTA_REF_R(csr) + 1;
}
/**
* It configure the double buffers for a given channel
......@@ -695,6 +718,9 @@ int ft_probe(struct fmc_device *fmc)
stat &= ~TDC_STAT_DMA;
}
ft->mode = FT_ACQ_TYPE_FIFO;
#if 0
if (stat & TDC_STAT_DMA) {
ft->mode = FT_ACQ_TYPE_DMA;
} else if (stat & TDC_STAT_FIFO) {
......@@ -705,6 +731,7 @@ int ft_probe(struct fmc_device *fmc)
stat);
return -ENODEV;
}
#endif
spin_lock_init(&ft->lock);
......
......@@ -26,6 +26,7 @@
#include <linux/zio-buffer.h>
#include "fmc-tdc.h"
#include "hw/timestamp_fifo_regs.h"
/* Module parameters */
static int irq_timeout_ms_default = 10;
......@@ -309,28 +310,17 @@ out:
* Get a time stamp from the fifo, if you set the 'last' flag it takes the last
* recorded time-stamp
*/
static int ft_timestap_get(struct zio_cset *cset, struct ft_hw_timestamp *hwts,
unsigned int last)
static int ft_timestamp_get(struct zio_cset *cset, struct ft_hw_timestamp *hwts )
{
struct fmctdc_dev *ft = cset->zdev->priv_d;
uint32_t fifo_addr = ft->ft_fifo_base + TDC_FIFO_OFFSET * cset->index;
uint32_t data[TDC_FIFO_OUT_N];
int i, valid = 1;
fifo_addr += last ? TDC_FIFO_LAST : TDC_FIFO_OUT;
for (i = 0; i < TDC_FIFO_OUT_N; ++i) {
data[i] = ft_ioread(ft, fifo_addr + i * 4);
dev_vdbg(&cset->head.dev, "FIFO read 0x%x from 0x%x\n",
data[i], fifo_addr + i * 4);
}
if (last) {
valid = !!(ft_ioread(ft, fifo_addr + TDC_FIFO_LAST_CSR) &
TDC_FIFO_LAST_CSR_VALID);
}
hwts->seconds = ft_ioread(ft, fifo_addr + TSF_REG_FIFO_R0);
hwts->coarse = ft_ioread(ft, fifo_addr + TSF_REG_FIFO_R1);
hwts->frac = ft_ioread(ft, fifo_addr + TSF_REG_FIFO_R2);
hwts->metadata = ft_ioread(ft, fifo_addr + TSF_REG_FIFO_R3);
memcpy(hwts, data, TDC_FIFO_OUT_N * 4);
return valid;
return 1;
}
/**
......@@ -340,13 +330,17 @@ static void ft_readout_fifo_one(struct zio_cset *cset)
{
struct ft_hw_timestamp *hwts;
// printk("read one ts\n");
cset->ti->nsamples = 1;
zio_arm_trigger(cset->ti);
if (!cset->chan->active_block)
goto out;
hwts = cset->chan->active_block->data;
ft_timestap_get(cset, hwts, 0);
ft_timestamp_get(cset, hwts);
//printk("2: %08x %08x %08x %08x\n", hwts->seconds, hwts->coarse, hwts->frac, hwts->metadata );
out:
zio_trigger_data_done(cset);
}
......@@ -383,9 +377,10 @@ irq:
cset = &ft->zdev->cset[i];
ft_readout_fifo_one(cset);
fifo_csr_addr = ft->ft_fifo_base +
TDC_FIFO_OFFSET * cset->index + TDC_FIFO_CSR;
TDC_FIFO_OFFSET * cset->index + TSF_REG_FIFO_CSR;
fifo_stat = ft_ioread(ft, fifo_csr_addr);
if (!(fifo_stat & TDC_FIFO_CSR_EMPTY))
if (!(fifo_stat & TSF_FIFO_CSR_EMPTY))
continue; /* Still something to read */
/* Ack the interrupt, nothing to read anymore */
......@@ -518,6 +513,7 @@ void ft_irq_coalescing_timeout_set(struct fmctdc_dev *ft,
"%s: FIFO acquisition mode has a gobal coalesing timeout. Ignore channel %d, set global value\n",
__func__, chan);
}
// printk("Timeout: %d", timeout_ms);
ft_writel(ft, timeout_ms, TDC_REG_IRQ_TIMEOUT);
break;
case FT_ACQ_TYPE_DMA:
......@@ -576,6 +572,7 @@ void ft_irq_coalescing_size_set(struct fmctdc_dev *ft,
"FIFO acquisition mode has a gobal coalesing size. Ignore channel %d, apply globally\n",
chan);
}
// printk("coal size : %d\n", size);
ft_writel(ft, size, TDC_REG_IRQ_THRESHOLD);
break;
case FT_ACQ_TYPE_DMA:
......@@ -638,6 +635,8 @@ int ft_irq_init(struct fmctdc_dev *ft)
ft_iowrite(ft, ft_chan_to_irq_mask(ft, 0x1F),
ft->ft_irq_base + TDC_EIC_REG_EIC_IER);
// printk("irq-init: imr %p\n", ft_ioread(ft, ft->ft_irq_base + TDC_EIC_REG_EIC_IMR ) );
return 0;
}
......
......@@ -24,7 +24,7 @@
#include <linux/fmc.h>
#include "fmc-tdc.h"
#include "hw/timestamp_fifo_regs.h"
/* The sample size. Mandatory, device-wide */
ZIO_ATTR_DEFINE_STD(ZIO_DEV, ft_zattr_dev_std) = {
......@@ -60,6 +60,30 @@ enum ft_devtype {
FT_TYPE_INPUT
};
/**
* It applies all calibration offsets to the hardware for a given channel.
*/
static void ft_update_offsets(struct fmctdc_dev *ft, int channel )
{
struct ft_channel_state *st = &ft->channels[channel];
struct ft_hw_timestamp hw_offset = {0, 0, 0, 0};
uint32_t fifo_addr;
fifo_addr = ft->ft_fifo_base + TDC_FIFO_OFFSET * channel;
ft_ts_apply_offset(&hw_offset, ft->calib.zero_offset[channel]);
ft_ts_apply_offset(&hw_offset, -ft->calib.wr_offset);
if (st->user_offset)
ft_ts_apply_offset(&hw_offset, st->user_offset);
ft_iowrite(ft, hw_offset.seconds, fifo_addr + TSF_REG_OFFSET1 );
ft_iowrite(ft, hw_offset.coarse, fifo_addr + TSF_REG_OFFSET2 );
ft_iowrite(ft, hw_offset.frac, fifo_addr + TSF_REG_OFFSET3 );
//printk("set offset ch %d %d %d %d\n", channel, hw_offset.seconds, hw_offset.coarse, hw_offset.frac);
}
static enum ft_devtype __ft_get_type(struct device *dev)
{
struct zio_obj_head *head = to_zio_head(dev);
......@@ -92,7 +116,7 @@ static int ft_zio_info_channel(struct device *dev, struct zio_attribute *zattr,
*usr_val = test_bit(FT_FLAG_CH_TERMINATED, &st->flags);
break;
case FT_ATTR_TDC_DELAY_REF:
/* FIXME read from HW */
*usr_val = ft_get_delta_reference(ft, cset->index);
break;
case FT_ATTR_TDC_TRANSFER_MODE:
*usr_val = ft->mode;
......@@ -143,6 +167,7 @@ static int ft_zio_info_get(struct device *dev, struct zio_attribute *zattr,
}
case FT_ATTR_TDC_WR_OFFSET:
*usr_val = ft->calib.wr_offset;
break;
}
return 0;
......@@ -172,12 +197,14 @@ static int ft_zio_conf_channel(struct device *dev, struct zio_attribute *zattr,
return -EINVAL;
spin_lock(&ft->lock);
st->user_offset = usr_val;
ft_update_offsets(ft, cset->index);
spin_unlock(&ft->lock);
break;
case FT_ATTR_TDC_DELAY_REF:
if (usr_val > FT_NUM_CHANNELS)
return -EINVAL;
/* FIXME write on HW */
ft_set_delta_reference(ft, cset->index, usr_val);
break;
case FT_ATTR_TDC_COALESCING_TIME:
ft_irq_coalescing_timeout_set(ft, cset->index, usr_val);
......@@ -282,8 +309,9 @@ static void ft_change_flags(struct zio_obj_head *head, unsigned long mask)
struct zio_channel *chan;
struct ft_channel_state *st;
struct fmctdc_dev *ft;
uint32_t ien;
uint32_t ien, csr;
uint32_t fifo_addr;
/* We manage only status flag */
if (!(mask & ZIO_STATUS))
return;
......@@ -296,11 +324,18 @@ static void ft_change_flags(struct zio_obj_head *head, unsigned long mask)
if (chan->flags & ZIO_STATUS) {
/* DISABLED */
ft_disable(ft, chan->cset->index);
fifo_addr = ft->ft_fifo_base + TDC_FIFO_OFFSET * chan->cset->index;
zio_trigger_abort_disable(chan->cset, 0);
/* Reset last time-stamp (seq number and valid)*/
//ft_iowrite(ft, TDC_FIFO_LAST_CSR_VALID | TDC_FIFO_LAST_CSR_RST_SEQ,
// TDC_FIFO_LAST_CSR);
csr = ft_ioread(ft, fifo_addr + TSF_REG_CSR);
/* clear delta timestamp ready flag */
ft_iowrite(ft, csr | TSF_CSR_DELTA_READ, fifo_addr + TSF_REG_CSR);
csr = ft_ioread(ft, fifo_addr + TSF_REG_FIFO_CSR);
ft_iowrite(ft, csr | TSF_FIFO_CSR_CLEAR_BUS, fifo_addr + TSF_REG_FIFO_CSR);
} else {
/* ENABLED */
ft_enable(ft, chan->cset->index);
......@@ -381,23 +416,6 @@ enum ft_trig_options {
};
/**
* It applies all calibration offsets to the givne timestamp
* @ft FmcTdc device instance
* @ts timestamp
*/
static void ft_timestamp_apply_offsets(struct fmctdc_dev *ft,
struct ft_hw_timestamp *hwts)
{
unsigned int chan = FT_HW_TS_META_CHN(hwts->metadata);
struct ft_channel_state *st = &ft->channels[chan];
ft_ts_apply_offset(hwts, ft->calib.zero_offset[chan]);
ft_ts_apply_offset(hwts, -ft->calib.wr_offset);
if (st->user_offset)
ft_ts_apply_offset(hwts, st->user_offset);
}
/**
* It puts the given timestamp in the ZIO control
* @cset ZIO cset instant
......@@ -508,7 +526,6 @@ static int ft_trig_data_done(struct zio_cset *cset)
__func__, i, cset->ti->nsamples,
ts[i].seconds,ts[i].coarse,
ts[i].frac, FT_HW_TS_META_SEQ(ts[i].metadata));
ft_timestamp_apply_offsets(ft, &ts[i]);
}
ft_zio_update_ctrl(cset, &ts[0]);
......@@ -571,7 +588,7 @@ int ft_zio_init(struct fmctdc_dev *ft)
{
int err = 0;
int dev_id;
int i;
ft->hwzdev = zio_allocate_device();
if (IS_ERR(ft->hwzdev))
......@@ -587,6 +604,9 @@ int ft_zio_init(struct fmctdc_dev *ft)
if (err)
goto err_dev_reg;
for(i = 0; i < FT_NUM_CHANNELS; i++)
ft_update_offsets(ft, i);
return 0;
err_dev_reg:
......
......@@ -45,6 +45,7 @@
#define TDC_STAT_DMA BIT(0)
#define TDC_STAT_FIFO BIT(1)
#define TDC_FIFO_OFFSET 0x100
#define TDC_WR_CTRL_ENABLE BIT(0)
......@@ -97,20 +98,6 @@
#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_CSR_USEDW
/* Carrier CSRs */
#define TDC_REG_CARRIER_CTL0 0x0 /* a.k.a. Carrier revision/PCB id reg */
#define TDC_REG_CARRIER_STATUS 0x4
......
......@@ -731,6 +731,68 @@ int fmctdc_read(struct fmctdc_board *userb, unsigned int channel,
return i;
}
int fmctdc_readhw(struct fmctdc_board *userb, unsigned int channel,
struct ft_hw_timestamp *t, int n, int flags)
{
__define_board(b, userb);
int i;
int n_ts;
fd_set set;
struct ft_hw_timestamp *data;
if (channel >= FMCTDC_NUM_CHANNELS) {
errno = EINVAL;
return -1;
}
data = calloc(n, sizeof(*data));
if (!data) {
errno = ENOMEM;
return -1;
}
i = 0;
while (i < n) {
n_ts = read(b->fdd[channel], &data[i], sizeof(*data) * (n - i));
if (n_ts < 0 && errno != EAGAIN) {
if (i == 0)
goto err;
else
goto out;
}
if (n_ts % sizeof(*data) == 0) { /* Good samples here */
n_ts /= sizeof(*data);
n_ts += i;
for (; i < n_ts && i < n; i++)
memcpy( &t[i], &data[i], sizeof(struct ft_hw_timestamp) ); //fmctdc_ts_convert(&t[i], &data[i]);
continue; /* the while loop */
}
if (i) /* error but before we got something */
goto out;
/* EAGAIN at first sample */
if (n_ts < 0 && flags == O_NONBLOCK)
return -1;
/* So, first sample and blocking read. Wait.. */
FD_ZERO(&set);
FD_SET(b->fdc[channel], &set);
if (select(b->fdc[channel] + 1, &set, NULL, NULL, NULL) < 0)
goto err;
}
out:
free(data);
return i;
err:
free(data);
return -1;
}
/**
* this "fread" behaves like stdio: it reads all the samples. Read fmctdc_read()
* for more details about the function.
......
......@@ -16,7 +16,6 @@ extern "C" {
#endif
#include <stdint.h>
/**
* Enumeration for all TDC channels
*/
......@@ -162,6 +161,17 @@ extern int fmctdc_coalescing_timeout_get(struct fmctdc_board *userb,
/**@}*/
#if 0
/* Hardware TDC timestamp */
struct ft_hw_timestamp {
uint32_t seconds;/* 1 second resolution */
uint32_t coarse;/* 8 ns resolution */
uint32_t frac;/* In ACAM bins (81 ps) */
uint32_t metadata;/* channel, polarity, etc. */
};
#endif
#include "fmctdc-lib-private.h"
/**
* @defgroup libacq Time-stamps Acquisition
......@@ -176,6 +186,8 @@ extern int fmctdc_fread(struct fmctdc_board *b, unsigned int channel,
extern int fmctdc_fileno_channel(struct fmctdc_board *b, unsigned int channel);
extern int fmctdc_read(struct fmctdc_board *b, unsigned int channel,
struct fmctdc_time *t, int n, int flags);
extern int fmctdc_readhw(struct fmctdc_board *b, unsigned int channel,
struct ft_hw_timestamp *t, int n, int flags);
extern int fmctdc_read_last(struct fmctdc_board *userb, unsigned int channel,
struct fmctdc_time *t);
extern int fmctdc_flush(struct fmctdc_board *userb, unsigned int channel);
......
......@@ -17,7 +17,7 @@ TESTS = fmc-tdc-list \
fmc-tdc-tstamp \
fmc-tdc-offset
CFLAGS = -I. -I$(LIBTDC) -I../kernel -Wall -Werror $(EXTRACFLAGS)
CFLAGS = -I. -I$(LIBTDC) -I../kernel -Wall $(EXTRACFLAGS)
GIT_VERSION := $(shell git describe --dirty --long --tags)
CFLAGS += -DGIT_VERSION="\"$(GIT_VERSION)\""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment