Commit 467c3470 authored by Federico Vaga's avatar Federico Vaga

drv: split dma code in smaller functions

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 4102bbde
......@@ -7,20 +7,17 @@
#include <linux/errno.h>
#include "fmc-adc-100m14b4cha.h"
/**
* It maps the ZIO blocks with an sg table, then it starts the DMA transfer
* from the ADC to the host memory.
*
* @param cset
*/
int zfad_dma_start(struct zio_cset *cset)
struct zfad_timetag {
uint32_t sec_low;
uint32_t sec_high;
uint32_t ticks;
uint32_t status;
};
static int zfad_wait_idle(struct fa_dev *fa)
{
struct fa_dev *fa = cset->zdev->priv_d;
struct zfad_block *zfad_block = cset->interleave->priv_d;
uint32_t dev_mem_off, trg_pos, pre_samp;
uint32_t val = 0;
int try = 5, err;
int try = 5;
/*
* All programmed triggers fire, so the acquisition is ended.
......@@ -33,12 +30,51 @@ int zfad_dma_start(struct zio_cset *cset)
&zfad_regs[ZFA_STA_FSM]);
}
if (val != FA100M14B4C_STATE_IDLE) {
/* we can't DMA if the state machine is not idle */
return val != FA100M14B4C_STATE_IDLE ? -EBUSY : 0;
}
static uint32_t zfad_dev_mem_offset(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
uint32_t dev_mem_off, trg_pos, pre_samp;
int nchan = FA100M14B4C_NCHAN;
struct zio_control *ctrl = cset->chan[nchan].current_ctrl;
/* get pre-samples from the current control (interleave chan) */
pre_samp = ctrl->attr_trigger.std_val[ZIO_ATTR_TRIG_PRE_SAMP];
/* Get trigger position in DDR */
trg_pos = fa_readl(fa, fa->fa_adc_csr_base,
&zfad_regs[ZFAT_POS]);
/*
* compute mem offset (in bytes): pre-samp is converted to
* bytes
*/
dev_mem_off = trg_pos - (pre_samp * cset->ssize * nchan);
dev_dbg(fa->msgdev,
"Trigger @ 0x%08x, pre_samp %i, offset 0x%08x\n",
trg_pos, pre_samp, dev_mem_off);
return dev_mem_off;
}
/**
* It maps the ZIO blocks with an sg table, then it starts the DMA transfer
* from the ADC to the host memory.
*
* @param cset
*/
int zfad_dma_start(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
struct zfad_block *zfad_block = cset->interleave->priv_d;
int err;
err = zfad_wait_idle(fa);
if (err) {
dev_warn(fa->msgdev,
"Can't start DMA on the last acquisition, "
"State Machine is not IDLE (status:%d)\n", val);
return -EBUSY;
"State Machine is not IDLE\n");
return err;
}
/*
......@@ -48,26 +84,8 @@ int zfad_dma_start(struct zio_cset *cset)
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_SRC], 0);
/* Fix dev_mem_addr in single-shot mode */
if (fa->n_shots == 1) {
int nchan = FA100M14B4C_NCHAN;
struct zio_control *ctrl = cset->chan[nchan].current_ctrl;
/* get pre-samples from the current control (interleave chan) */
pre_samp = ctrl->attr_trigger.std_val[ZIO_ATTR_TRIG_PRE_SAMP];
/* Get trigger position in DDR */
trg_pos = fa_readl(fa, fa->fa_adc_csr_base,
&zfad_regs[ZFAT_POS]);
/*
* compute mem offset (in bytes): pre-samp is converted to
* bytes
*/
dev_mem_off = trg_pos - (pre_samp * cset->ssize * nchan);
dev_dbg(fa->msgdev,
"Trigger @ 0x%08x, pre_samp %i, offset 0x%08x\n",
trg_pos, pre_samp, dev_mem_off);
zfad_block[0].dev_mem_off = dev_mem_off;
}
if (fa->n_shots == 1)
zfad_block[0].dev_mem_off = zfad_dev_mem_offset(cset);
dev_dbg(fa->msgdev, "Start DMA transfer\n");
err = fa->carrier_op->dma_start(cset);
......@@ -77,6 +95,85 @@ int zfad_dma_start(struct zio_cset *cset)
return 0;
}
static void zfad_tstamp_start_get(struct fa_dev *fa,
struct zio_timestamp *ztstamp)
{
ztstamp->secs = fa_readl(fa, fa->fa_utc_base,
&zfad_regs[ZFA_UTC_ACQ_START_SECONDS]);
ztstamp->ticks = fa_readl(fa, fa->fa_utc_base,
&zfad_regs[ZFA_UTC_ACQ_START_COARSE]);
ztstamp->bins = fa_readl(fa, fa->fa_utc_base,
&zfad_regs[ZFA_UTC_ACQ_START_FINE]);
}
static int zfad_block_timetag_extract(struct zio_block *block,
struct zfad_timetag *timetag)
{
struct zfad_timetag *tg;
tg = block->data + block->datalen - FA_TRIG_TIMETAG_BYTES;
if (unlikely((tg->sec_high >> 8) != 0xACCE55))
return -EINVAL;
/* resize the datalen, by removing the trigger tstamp */
block->datalen = block->datalen - FA_TRIG_TIMETAG_BYTES;
memcpy(timetag, tg, sizeof(*timetag));
return 0;
}
static void zfad_block_ctrl_tstamp_update(struct zio_block *block,
struct zfad_timetag *timetag)
{
struct zio_control *ctrl = zio_get_ctrl(block);
struct zio_timestamp *ztstamp = &ctrl->tstamp;
ztstamp->secs = ((uint64_t)timetag->sec_high & 0xFF) << 32;
ztstamp->secs |= timetag->sec_low;
ztstamp->ticks = timetag->ticks;
ztstamp->bins = 0;
}
static void zfad_block_ctrl_attr_update(struct zio_block *block,
struct zfad_timetag *timetag,
unsigned int seq_num)
{
struct zio_control *ctrl = zio_get_ctrl(block);
uint32_t *ext_val = ctrl->attr_channel.ext_val;
ext_val[FA100M14B4C_TATTR_STA]= timetag->status;
ctrl->seq_num = seq_num;
}
static void zfad_block_ctrl_tstamp_start_update(struct zio_block *block,
struct zio_timestamp *ztstamp)
{
struct zio_control *ctrl = zio_get_ctrl(block);
uint32_t *ext_val;
ext_val = ctrl->attr_channel.ext_val;
ext_val[FA100M14B4C_DATTR_ACQ_START_S] = ztstamp->secs;
ext_val[FA100M14B4C_DATTR_ACQ_START_C] = ztstamp->ticks;
ext_val[FA100M14B4C_DATTR_ACQ_START_F] = ztstamp->bins;
}
static void zfad_curr_ctrl_sync(struct zio_cset *cset,
struct zio_block *block)
{
struct zio_channel *interleave = cset->interleave;
struct zio_control *ctrl;
if (WARN(!block, "Missing block\n"))
return;
ctrl = zio_get_ctrl(block);
/* Sync the channel current control with the last ctrl block*/
memcpy(&interleave->current_ctrl->tstamp,
&ctrl->tstamp, sizeof(struct zio_timestamp));
interleave->current_ctrl->seq_num = ctrl->seq_num;
}
/**
* It completes a DMA transfer.
* It tells to the ZIO framework that all blocks are done. Then, it re-enable
......@@ -89,14 +186,12 @@ int zfad_dma_start(struct zio_cset *cset)
void zfad_dma_done(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
struct zio_channel *interleave = cset->interleave;
struct zfad_block *zfad_block = interleave->priv_d;
struct zfad_block *zfad_block = cset->interleave->priv_d;
struct zio_control *ctrl = NULL;
struct zio_ti *ti = cset->ti;
struct zio_block *block;
struct zio_block *block = NULL;
struct zio_timestamp ztstamp;
int i;
uint32_t *trig_timetag;
fa->carrier_op->dma_done(cset);
......@@ -104,47 +199,20 @@ void zfad_dma_done(struct zio_cset *cset)
* trig-timetag appended after the samples. Set also the acquisition
* start timetag on every blocks
*/
ztstamp.secs = fa_readl(fa, fa->fa_utc_base,
&zfad_regs[ZFA_UTC_ACQ_START_SECONDS]);
ztstamp.ticks = fa_readl(fa, fa->fa_utc_base,
&zfad_regs[ZFA_UTC_ACQ_START_COARSE]);
ztstamp.bins = fa_readl(fa, fa->fa_utc_base,
&zfad_regs[ZFA_UTC_ACQ_START_FINE]);
zfad_tstamp_start_get(fa, &ztstamp);
for (i = 0; i < fa->n_shots; ++i) {
struct zfad_timetag timetag;
int err;
block = zfad_block[i].block;
ctrl = zio_get_ctrl(block);
trig_timetag = (uint32_t *)(block->data + block->datalen
- FA_TRIG_TIMETAG_BYTES);
if (unlikely((*(trig_timetag + 1) >> 8) != 0xACCE55))
dev_err(fa->msgdev,
"Wrong acquisition TAG, expected 0xACCE55 but got 0x%X (0x%X)\n",
(*(trig_timetag + 1) >> 8), *trig_timetag);
ctrl->tstamp.secs = ((uint64_t)*(trig_timetag + 1) & 0xFF) << 32;
ctrl->tstamp.secs |= *(trig_timetag);
ctrl->tstamp.ticks = *(trig_timetag + 2);
ctrl->tstamp.bins = 0;
ctrl->attr_trigger.ext_val[FA100M14B4C_TATTR_STA]= *(trig_timetag + 3);
/* Acquisition start Timetag */
ctrl->attr_channel.ext_val[FA100M14B4C_DATTR_ACQ_START_S] =
ztstamp.secs;
ctrl->attr_channel.ext_val[FA100M14B4C_DATTR_ACQ_START_C] =
ztstamp.ticks;
ctrl->attr_channel.ext_val[FA100M14B4C_DATTR_ACQ_START_F] =
ztstamp.bins;
/* resize the datalen, by removing the trigger tstamp */
block->datalen = block->datalen - FA_TRIG_TIMETAG_BYTES;
/* update seq num */
ctrl->seq_num = i;
err = zfad_block_timetag_extract(block, &timetag);
if (err)
memset(&timetag, 0, sizeof(timetag));
zfad_block_ctrl_tstamp_start_update(block, &ztstamp);
zfad_block_ctrl_tstamp_update(block, &timetag);
zfad_block_ctrl_attr_update(block, &timetag, i);
}
/* Sync the channel current control with the last ctrl block*/
memcpy(&interleave->current_ctrl->tstamp,
&ctrl->tstamp, sizeof(struct zio_timestamp));
/* Update sequence number */
interleave->current_ctrl->seq_num = ctrl->seq_num;
zfad_curr_ctrl_sync(cset, block);
/*
* All DMA transfers done! Inform the trigger about this, so
......
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