Commit 1598de1a authored by Michel Arruat's avatar Michel Arruat Committed by Federico Vaga

driver: major rewrite, with carrier dma-ops and other things

This is a major change, work of Michel Arruat, then re-committed as a
single commit by Alessandro.  The original development happened mainly
on the SVEC carrier, and support for SPEC (PCI) was added back at a
later time.  I (Alessandro) chose to pick individual changes one at
a time, for better documentation and later "git blame", up to this point.

Now, this is a big commit that completely changes the driver,
mainly in the following places:

  - split carrier-specific from generic code, like the TDC driver is now
    (this is mainly the dma-specific and irq-specific code)
  - use of SDB to get base addresses (with new fmc-util file)
  - use the VIC core to manage interrupts, relying on carrier support
  - change the field-desc table for the better
  - add carrier-specific init, reset, exit
  - split irq and adc-specific stuff out of zio-drv.c
  - DMA data and interrupt is now different: the timestamp is at end-of-data,
    thus we don't have the "trigger-happened" interrupt any more
  - use a work queue for interrupt management, instead of a tasklet, this
    allows sleeping, which is needed by this code base
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 8a06eff4
......@@ -24,14 +24,18 @@ subdirs-ccflags-y = $(ccflags-y)
obj-m := fmc-adc-100m14b.o
fmc-adc-100m14b-objs = fa-core.o
fmc-adc-100m14b-objs += fa-spec-core.o
fmc-adc-100m14b-objs += fa-zio-drv.o
fmc-adc-100m14b-objs += fa-calibration.o
fmc-adc-100m14b-objs += fa-regtable.o
fmc-adc-100m14b-objs += fa-spec-regtable.o
fmc-adc-100m14b-objs += fa-zio-trg.o
fmc-adc-100m14b-objs += fa-spec-dma.o
fmc-adc-100m14b-objs += fa-irq.o
fmc-adc-100m14b-objs += fa-irq.o fa-spec-irq.o
fmc-adc-100m14b-objs += onewire.o
fmc-adc-100m14b-objs += spi.o
fmc-adc-100m14b-objs += fmc-util.o
all modules:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) modules
......
......@@ -12,13 +12,22 @@
#include <linux/init.h>
#include <linux/fmc.h>
#include <linux/fmc-sdb.h>
#include "fmc-adc.h"
/* Module parameters */
static struct fmc_driver fa_dev_drv;
FMC_PARAM_BUSID(fa_dev_drv);
FMC_PARAM_GATEWARE(fa_dev_drv);
static int fa_show_sdb;
module_param_named(show_sdb, fa_show_sdb, int, 0444);
MODULE_PARM_DESC(show_sdb, "Print a dump of the gateware's SDB tree.");
static int fa_enable_test_data = 0;
module_param_named(enable_test_data, fa_enable_test_data, int, 0444);
static const int zfad_hw_range[] = {
[ZFA_RANGE_10V] = 0x45,
[ZFA_RANGE_1V] = 0x11,
......@@ -73,7 +82,7 @@ int zfad_apply_user_offset(struct fa_dev *fa, struct zio_channel *chan,
return -EINVAL;
i = zfad_get_chx_index(ZFA_CHx_CTL_RANGE, chan);
zfa_hardware_read(fa, i, &range_reg);
range_reg = fa_readl(fa, fa->fa_adc_csr_base, &zfad_regs[i]);
range = zfad_convert_hw_range(range_reg);
if (range < 0)
......@@ -131,7 +140,7 @@ int zfad_set_range(struct fa_dev *fa, struct zio_channel *chan,
/* Actually set the range */
i = zfad_get_chx_index(ZFA_CHx_CTL_RANGE, chan);
zfa_hardware_write(fa, i, zfad_hw_range[range]);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[i], zfad_hw_range[range]);
if (range == ZFA_RANGE_OPEN) {
offset = FA_CAL_NO_OFFSET;
......@@ -147,9 +156,10 @@ int zfad_set_range(struct fa_dev *fa, struct zio_channel *chan,
}
i = zfad_get_chx_index(ZFA_CHx_OFFSET, chan);
zfa_hardware_write(fa, i, offset & 0xffff); /* prevent warning */
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[i],
offset & 0xffff /* prevent warning */ );
i = zfad_get_chx_index(ZFA_CHx_GAIN, chan);
zfa_hardware_write(fa, i, gain);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[i], gain);
/* recalculate user offset for the new range */
zfad_apply_user_offset(fa, chan, fa->user_offset[chan->index]);
......@@ -157,7 +167,6 @@ int zfad_set_range(struct fa_dev *fa, struct zio_channel *chan,
return 0;
}
/*
* zfad_fsm_command
* @fa: the fmc-adc descriptor
......@@ -201,14 +210,16 @@ int zfad_fsm_command(struct fa_dev *fa, uint32_t command)
/* If START, check if we can start */
if (command == ZFA_START) {
/* Verify that SerDes PLL is lockes */
zfa_hardware_read(fa, ZFA_STA_SERDES_PLL, &val);
val = fa_readl(fa, fa->fa_adc_csr_base,
&zfad_regs[ZFA_STA_SERDES_PLL]);
if (!val) {
dev_info(dev, "Cannot start acquisition: "
"SerDes PLL not locked\n");
return -EBUSY;
}
/* Verify that SerDes is synched */
zfa_hardware_read(fa, ZFA_STA_SERDES_SYNCED, &val);
val = fa_readl(fa, fa->fa_adc_csr_base,
&zfad_regs[ZFA_STA_SERDES_SYNCED]);
if (!val) {
dev_info(dev, "Cannot start acquisition: "
"SerDes not synchronized\n");
......@@ -231,13 +242,125 @@ int zfad_fsm_command(struct fa_dev *fa, uint32_t command)
}
dev_dbg(dev, "FSM START Command, Enable interrupts\n");
zfa_hardware_write(fa, ZFA_IRQ_MASK, ZFAT_ALL);
fa_enable_irqs(fa);
} else {
dev_dbg(dev, "FSM STOP Command, Disable interrupts\n");
zfa_hardware_write(fa, ZFA_IRQ_MASK, ZFAT_NONE);
fa_disable_irqs(fa);
}
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_CTL_FMS_CMD],
command);
return 0;
}
/* Extract from SDB the base address of the core components */
/* which are not carrier specific */
static int __fa_sdb_get_device(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
struct device *dev = fmc->hwdev;
int ret;
ret = fmc_scan_sdb_tree(fmc, 0);
if (ret < 0) {
dev_err(dev,
"%s: no SDB in the bitstream."
"Are you sure you've provided the correct one?\n",
KBUILD_MODNAME);
return ret;
}
/* FIXME: this is obsoleted by fmc-bus internal parameters */
if (fa_show_sdb)
fmc_show_sdb_tree(fmc);
/* Now use SDB to find the base addresses */
fa->fa_irq_vic_base = fmc_find_sdb_device(fmc->sdb, 0xce42,
0x13, NULL);
fa->fa_adc_csr_base = fmc_find_sdb_device_ext(fmc->sdb, 0xce42,
0x608,
fmc->slot_id, NULL);
fa->fa_irq_adc_base = fmc_find_sdb_device_ext(fmc->sdb, 0xce42,
0x26ec6086,
fmc->slot_id, NULL);
fa->fa_utc_base = fmc_find_sdb_device_ext(fmc->sdb, 0xce42,
0x604, fmc->slot_id, NULL);
fa->fa_spi_base = fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0xe503947e,
fmc->slot_id, NULL);
fa->fa_ow_base = fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x779c5443,
fmc->slot_id, NULL);
return ret;
}
/*
* Specific check and init
*/
static int __fa_init(struct fa_dev *fa)
{
struct device *hwdev = fa->fmc->hwdev;
struct device *msgdev = &fa->fmc->dev;
struct zio_device *zdev = fa->zdev;
int i, addr;
/* Check if hardware supports 64-bit DMA */
if (dma_set_mask(hwdev, DMA_BIT_MASK(64))) {
/* Check if hardware supports 32-bit DMA */
if (dma_set_mask(hwdev, DMA_BIT_MASK(32))) {
dev_err(msgdev, "32-bit DMA addressing not available\n");
return -EINVAL;
}
}
/* Retrieve calibration from the eeprom and validate*/
fa_read_eeprom_calib(fa);
/* Force stop FSM to prevent early trigger fire */
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_CTL_FMS_CMD],
ZFA_STOP);
/* Initialize channels to use 1V range */
for (i = 0; i < 4; ++i) {
addr = zfad_get_chx_index(ZFA_CHx_CTL_RANGE,
&zdev->cset->chan[i]);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[addr],
ZFA_RANGE_1V);
zfad_set_range(fa, &zdev->cset->chan[i], ZFA_RANGE_1V);
}
zfad_reset_offset(fa);
/* Enable mezzanine clock */
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_CTL_CLK_EN], 1);
/* Set decimation to minimum */
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_SR_DECI], 1);
/* Set test data register */
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_CTL_TEST_DATA_EN],
fa_enable_test_data);
/* Set to single shot mode by default */
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_SHOTS_NB], 1);
if (zdev->cset->ti->cset->trig == &zfat_type) {
/* Select external trigger (index 0) */
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_HW_SEL],
1);
zdev->cset->ti->zattr_set.ext_zattr[0].value = 1;
} else {
/* Enable Software trigger*/
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_SW_EN],
1);
/* Disable Hardware trigger*/
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_HW_EN],
0);
}
zfa_hardware_write(fa, ZFA_CTL_FMS_CMD, command);
/* Zero offsets and release the DAC clear */
zfad_reset_offset(fa);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_CTL_DAC_CLR_N], 1);
/* Set UTC seconds from the kernel seconds */
fa_writel(fa, fa->fa_utc_base, &zfad_regs[ZFA_UTC_SECONDS],
get_seconds());
/* disable auto_start */
fa->enable_auto_start = 0;
return 0;
}
......@@ -277,10 +400,18 @@ int fa_probe(struct fmc_device *fmc)
fmc_set_drvdata(fmc, fa);
fa->fmc = fmc;
/* apply carrier-specific hacks and workarounds */
if (!strcmp(fmc->carrier_name, "SPEC"))
fa->carrier_op = &fa_spec_op;
else {
dev_err(fmc->hwdev, "unsupported carrier\n");
return -ENODEV;
}
if (fa_dev_drv.gw_n)
fwname = ""; /* reprogram will pick from module parameter */
else
fwname = FA_GATEWARE_DEFAULT_NAME;
fwname = fa->carrier_op->get_gwname();
dev_info(fmc->hwdev, "Gateware (%s)\n", fwname);
/* We first write a new binary (and lm32) within the carrier */
err = fmc->op->reprogram(fmc, &fa_dev_drv, fwname);
......@@ -291,13 +422,18 @@ int fa_probe(struct fmc_device *fmc)
}
dev_info(fmc->hwdev, "Gateware successfully loaded\n");
/* Mark base addresses (will come from sdb, later) */
//fa->fa_irq_vic_base -- not existent yet in this gateware
//fa->fa_adc_csr_base = CHx_GAIN;
//fa->fa_irq_adc_base = ENABLE_MASK;
fa->fa_utc_base = FA_UTC_MEM_OFF;
fa->fa_spi_base = FA_SPI_MEM_OFF;
fa->fa_ow_base = FA_OWI_MEM_OFF;
/* Extract whisbone core base address fron SDB */
err = __fa_sdb_get_device(fa);
if (err < 0)
goto out;
err = fa->carrier_op->init(fa);
if (err < 0)
goto out;
err = fa->carrier_op->reset_core(fa);
if (err < 0)
goto out;
/* init all subsystems */
for (i = 0, m = mods; i < ARRAY_SIZE(mods); i++, m++) {
......@@ -307,28 +443,42 @@ int fa_probe(struct fmc_device *fmc)
dev_err(&fmc->dev, "error initializing %s\n", m->name);
goto out;
}
}
/* time to execute specific driver init */
err = __fa_init(fa);
if (err < 0)
goto out;
err = fa_setup_irqs(fa);
if (err < 0)
goto out;
return 0;
out:
while (--m, --i >= 0)
if (m->exit)
m->exit(fa);
return err;
}
int fa_remove(struct fmc_device *fmc)
{
struct fa_dev *fa = fmc_get_drvdata(fmc);
struct fa_modlist *m;
int i = ARRAY_SIZE(mods);
fa_free_irqs(fa);
while (--i >= 0) {
m = mods + i;
if (m->exit)
m->exit(fa);
}
fa->carrier_op->exit(fa);
return 0;
}
......
......@@ -16,6 +16,7 @@
#include <linux/zio-trigger.h>
#include "fmc-adc.h"
#include "fa-spec.h"
/**
* It maps the ZIO blocks with an sg table, then it starts the DMA transfer
......@@ -23,21 +24,17 @@
*
* @param cset
*/
void zfad_dma_start(struct zio_cset *cset)
int zfad_dma_start(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;
int err;
/* Map ZIO block for DMA acquisition */
err = zfad_map_dma(cset, zfad_block, fa->n_shots);
dev_dbg(&fa->fmc->dev, "Start DMA transfer\n");
err = fa->carrier_op->dma_start(cset);
if (err)
return;
return err;
/* Start DMA transefer */
zfa_hardware_write(fa, ZFA_DMA_CTL_START, 1);
dev_dbg(&fa->fmc->dev, "Start DMA transfer\n");
return 0;
}
/**
......@@ -54,16 +51,47 @@ 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 zio_control *ctrl = NULL;
struct zio_ti *ti = cset->ti;
struct zio_block *block;
int i;
uint32_t *trig_timetag;
zfad_unmap_dma(cset, zfad_block);
fa->carrier_op->dma_done(cset);
/* for each shot, set the timetag of each ctrl block by reading the
* trig-timetag appended after the samples
*/
for (i = 0; i < fa->n_shots; ++i) {
block = zfad_block[i].block;
ctrl = zio_get_ctrl(block);
trig_timetag = (uint32_t *)(block->data + block->datalen
- FA_TRIG_TIMETAG_BYTES);
/* Timetag marker (metadata) used for debugging */
dev_dbg(&fa->fmc->dev, "trig_timetag metadata of the shot %d"
" (expected value: 0x6fc8ad2d): 0x%x\n",
i, *trig_timetag);
ctrl->tstamp.secs = *(++trig_timetag);
ctrl->tstamp.ticks = *(++trig_timetag);
ctrl->tstamp.bins = *(++trig_timetag);
/* resize the datalen and clear stamp from data block */
block->datalen -= FA_TRIG_TIMETAG_BYTES;
memset(block->data+block->datalen, 0, FA_TRIG_TIMETAG_BYTES);
/* update seq num */
ctrl->seq_num = 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;
/*
* All DMA transfers done! Inform the trigger about this, so
* it can store blocks into the buffer
*/
zio_trigger_data_done(cset);
dev_dbg(&fa->fmc->dev, "%i blocks transfered\n", fa->n_shots);
zio_trigger_data_done(cset);
/*
* we can safely re-enable triggers.
......@@ -74,13 +102,14 @@ void zfad_dma_done(struct zio_cset *cset)
* trigger.
*/
if (cset->trig == &zfat_type) {
zfa_hardware_write(fa, ZFAT_CFG_HW_EN,
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_HW_EN],
(ti->flags & ZIO_STATUS ? 0 : 1));
zfa_hardware_write(fa, ZFAT_CFG_SW_EN,
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_SW_EN],
ti->zattr_set.ext_zattr[5].value);
} else {
dev_dbg(&fa->fmc->dev, "Software acquisition over\n");
zfa_hardware_write(fa, ZFAT_CFG_SW_EN, 1);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_SW_EN],
1);
}
/* Automatic start next acquisition */
......@@ -90,6 +119,7 @@ void zfad_dma_done(struct zio_cset *cset)
}
}
/**
* It handles the error condition of a DMA transfer.
* The function turn off the state machine by sending the STOP command
......@@ -102,24 +132,19 @@ void zfad_dma_error(struct zio_cset *cset)
struct zio_bi *bi = cset->interleave->bi;
struct zfad_block *zfad_block = cset->interleave->priv_d;
int i;
uint32_t val;
zfad_unmap_dma(cset, zfad_block);
fa->carrier_op->dma_error(cset);
zfa_hardware_read(fa, ZFA_DMA_STA, &val);
dev_err(&fa->fmc->dev,
"DMA error (status 0x%x). All acquisition lost\n", val);
zfad_fsm_command(fa, ZFA_STOP);
fa->n_dma_err++;
if (fa->n_fires == 0)
dev_err(&fa->fmc->dev,
"DMA error (status 0x%x) occurs but no block was acquired\n", val);
"DMA error occurs but no block was acquired\n");
/* Remove invalid blocks */
for (i = 0; i < fa->n_shots; ++i) {
for (i = 0; i < fa->n_shots; ++i)
bi->b_op->store_block(bi, zfad_block[i].block);
}
kfree(zfad_block);
cset->interleave->priv_d = NULL;
}
......@@ -134,23 +159,40 @@ void zfad_dma_error(struct zio_cset *cset)
void zfat_irq_acq_end(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
uint32_t val;
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;
dev_dbg(&fa->fmc->dev, "Acquisition done\n");
/*FIXME: because the driver doesn't listen anymore trig-event
* we agreed that the HW will provide a dedicated register
* to check the real number of shots in order to compare it
* with the requested one.
* This ultimate check is not crucial because the HW implements
* a solid state machine and acq-end can happens only after
* the execution of the n requested shots.
*/
/*
fa->n_fires = fa_readl(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_NSHOTS...);
if (fa->n_fires != fa->n_shots) {
dev_err(&fa->fmc->dev,
"Expected %i trigger fires, but %i occurs\n",
fa->n_shots, fa->n_fires);
}
*/
/* for the time being let assume n_shots have been executed */
fa->n_fires = fa->n_shots;
/*
* All programmed triggers fire, so the acquisition is ended.
* If the state machine is _idle_ we can start the DMA transfer.
* If the state machine it is not idle, try again 5 times
*/
do {
zfa_hardware_read(fa, ZFA_STA_FSM, &val);
} while (try-- && val != ZFA_STATE_IDLE);
while (try-- && val != ZFA_STATE_IDLE) {
//udelay(2);
val = fa_readl(fa, fa->fa_adc_csr_base,
&zfad_regs[ZFA_STA_FSM]);
}
if (val != ZFA_STATE_IDLE) {
/* we can't DMA if the state machine is not idle */
......@@ -165,9 +207,218 @@ void zfat_irq_acq_end(struct zio_cset *cset)
* Disable all triggers to prevent fires between
* different DMA transfers required for multi-shots
*/
zfa_hardware_write(fa, ZFAT_CFG_HW_EN, 0);
zfa_hardware_write(fa, ZFAT_CFG_SW_EN, 0);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_HW_EN], 0);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_SW_EN], 0);
/* Fix dev_mem_addr in single-shot mode */
if (fa->n_shots == 1) {
int nchan = FA_NCHAN;
struct zio_control *ctrl = cset->chan[FA_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->fmc->dev,
"Trigger @ 0x%08x, pre_samp %i, offset 0x%08x\n",
trg_pos, pre_samp, dev_mem_off);
/* Start the DMA transfer */
zfad_dma_start(cset);
zfad_block[0].dev_mem_off = dev_mem_off;
}
}
/*
* job executed within a work thread
* Depending of the carrier the job slightly differs:
* SVEC: dma_start() blocks till the the DMA ends
* (fully managed by the vmebus driver)
* Therefore the DMA outcome can be processed immediately
* SPEC: dma_start() launch the job an returns immediately.
* An interrupt DMA_DONE or ERROR is expecting to signal the end
* of the DMA transaction
* (See fa-spec-irq.c::fa-spec_irq_handler)
*/
static void fa_irq_work(struct work_struct *work)
{
struct fa_dev *fa = container_of(work, struct fa_dev, irq_work);
struct zio_cset *cset = fa->zdev->cset;
int res;
res = zfad_dma_start(cset);
if (res)
zfad_dma_error(cset);
/*
* No error.
* If there is not an IRQ DMA src to notify the ends of the DMA,
* process data immediately.
* Otherwhise this job is delayed till an IRQ DMA occurs
*/
else if (!(fa->irq_src & FA_IRQ_SRC_DMA))
zfad_dma_done(cset);
/* ack the irq */
fa->fmc->op->irq_ack(fa->fmc);
}
/*
* fat_get_irq_status
* @fa: adc descriptor
* @irq_status: destination of irq status
*
* Get irq and clear the register. To clear an interrupt we have to write 1
* on the handled interrupt. We handle all interrupt so we clear all interrupts
*/
static void fa_get_irq_status(struct fa_dev *fa, int irq_core_base,
uint32_t *irq_status)
{
/* Get current interrupts status */
*irq_status = fa_readl(fa, irq_core_base, &zfad_regs[ZFA_IRQ_ADC_SRC]);
dev_dbg(&fa->fmc->dev, "core ADC: 0x%x fired an interrupt. IRQ status register: 0x%x\n",
irq_core_base, *irq_status);
if (*irq_status)
/* Clear current interrupts status */
fa_writel(fa, irq_core_base, &zfad_regs[ZFA_IRQ_ADC_SRC],
*irq_status);
}
/*
* fa_irq_handler
* @irq:
* @ptr: pointer to fmc_device
*
* The ADC svec firmware fires interrupt from a single wishbone core
* and throught the VIC ACQ_END and TRIG events. Note about "TRIG"
* event: the main reason to listen this interrupt was to read the
* intermediate time stamps in case of multishots.
* With the new firmware (>=3.0) the stamps come with the data,
* therefore the driver doesn't have to listen "TRIG" event. This
* enhancement remove completely the risk of loosing interrupt in case
* of small number of samples and makes the retry loop in the hanlder
* obsolete.
*/
irqreturn_t fa_irq_handler(int irq_core_base, void *dev_id)
{
struct fmc_device *fmc = dev_id;
struct fa_dev *fa = fmc_get_drvdata(fmc);
struct zio_cset *cset = fa->zdev->cset;
uint32_t status;
/* irq to handle */
fa_get_irq_status(fa, irq_core_base, &status);
if (!status)
return IRQ_NONE; /* No interrupt fired by this mezzanine */
dev_dbg(&fa->fmc->dev, "Handle ADC interrupts fmc slot: %d\n",
fmc->slot_id);
if (status & FA_IRQ_ADC_ACQ_END) {
zfat_irq_acq_end(cset);
/* Job delegated to the workqueue: */
/* Start DMA and acknowledge of the irq on the carrier */
schedule_work(&fa->irq_work);
/* register the core which just fired the IRQ */
/* check proper sequence of IRQ for multi IRQ (ACQ + DMA)*/
fa->last_irq_core_src = irq_core_base;
} else { /* unexpected interrupt we have to ack anyway */
dev_err(&fa->fmc->dev,
"%s unexpected interrupt 0x%x\n",
__func__, status);
fmc->op->irq_ack(fmc);
}
return IRQ_HANDLED;
}
int fa_setup_irqs(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
int err;
/* Request IRQ */
dev_dbg(&fa->fmc->dev, "%s request irq fmc slot: %d\n",
__func__, fa->fmc->slot_id);
/* VIC svec setup */
fa_writel(fa, fa->fa_irq_vic_base,
&zfad_regs[ZFA_IRQ_VIC_CTRL],
0x3);
fa_writel(fa, fa->fa_irq_vic_base,
&zfad_regs[ZFA_IRQ_VIC_ENABLE_MASK],
0x3);
fa_writel(fa, fa->fa_irq_vic_base,
&zfad_regs[ZFA_IRQ_VIC_MASK_STATUS],
0x3);
/* trick : vic needs the base address of teh core firing the irq
* It cannot provided throught irq_request() call therefore the trick
* is to set it by means of the field irq provided by the fmc device
*/
fmc->irq = fa->fa_irq_adc_base;
err = fmc->op->irq_request(fmc, fa_irq_handler,
"fmc-adc-100m14b",
0 /*VIC is used */);
if (err) {
dev_err(&fa->fmc->dev, "can't request irq %i (error %i)\n",
fa->fmc->irq, err);
return err;
}
/* workqueue is required to execute DMA transaction */
INIT_WORK(&fa->irq_work, fa_irq_work);
/* set IRQ sources to listen */
fa->irq_src = FA_IRQ_SRC_ACQ;
if (fa->carrier_op->setup_irqs)
err = fa->carrier_op->setup_irqs(fa);
return err;
}
int fa_free_irqs(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
if (fa->carrier_op->free_irqs)
fa->carrier_op->free_irqs(fa);
fmc->op->irq_free(fmc);
return 0;
}
int fa_enable_irqs(struct fa_dev *fa)
{
dev_dbg(&fa->fmc->dev, "%s Enable interrupts fmc slot:%d\n",
__func__, fa->fmc->slot_id);
fa_writel(fa, fa->fa_irq_adc_base,
&zfad_regs[ZFA_IRQ_ADC_ENABLE_MASK],
FA_IRQ_ADC_ACQ_END);
if (fa->carrier_op->enable_irqs)
fa->carrier_op->enable_irqs(fa);
return 0;
}
int fa_disable_irqs(struct fa_dev *fa)
{
dev_dbg(&fa->fmc->dev, "%s Disable interrupts fmc slot:%d\n",
__func__, fa->fmc->slot_id);
fa_writel(fa, fa->fa_irq_adc_base,
&zfad_regs[ZFA_IRQ_ADC_DISABLE_MASK],
FA_IRQ_ADC_ACQ_END);
if (fa->carrier_op->disable_irqs)
fa->carrier_op->disable_irqs(fa);
return 0;
}
int fa_ack_irq(struct fa_dev *fa, int irq_id)
{
return 0;
}
......@@ -6,107 +6,94 @@
*/
#include "fmc-adc.h"
/* Definition of the fmc-adc registers address - mask - mask offset */
/* Definition of the fmc-adc registers fields: offset - mask - isbitfield */
const struct zfa_field_desc zfad_regs[] = {
/* Control registers */
[ZFA_CTL_FMS_CMD] = {FA_ADC_MEM_OFF + 0x00, 0x0003, 0},
[ZFA_CTL_CLK_EN] = {FA_ADC_MEM_OFF + 0x00, 0x0001, 2},
[ZFA_CTL_DAC_CLR_N] = {FA_ADC_MEM_OFF + 0x00, 0x0001, 3},
[ZFA_CTL_BSLIP] = {FA_ADC_MEM_OFF + 0x00, 0x0001, 4},
[ZFA_CTL_TEST_DATA_EN] = {FA_ADC_MEM_OFF + 0x00, 0x0001, 5},
[ZFA_CTL_TRIG_LED] = {FA_ADC_MEM_OFF + 0x00, 0x0001, 6},
[ZFA_CTL_ACQ_LED] = {FA_ADC_MEM_OFF + 0x00, 0x0001, 7},
[ZFA_CTL_FMS_CMD] = {0x00, 0x00000003, 1},
[ZFA_CTL_CLK_EN] = {0x00, 0x00000004, 1},
[ZFA_CTL_DAC_CLR_N] = {0x00, 0x00000008, 1},
[ZFA_CTL_BSLIP] = {0x00, 0x00000010, 1},
[ZFA_CTL_TEST_DATA_EN] = {0x00, 0x00000020, 1},
[ZFA_CTL_TRIG_LED] = {0x00, 0x00000040, 1},
[ZFA_CTL_ACQ_LED] = {0x00, 0x00000080, 1},
/* Status registers */
[ZFA_STA_FSM] = {FA_ADC_MEM_OFF + 0x04, 0x0007, 0},
[ZFA_STA_SERDES_PLL] = {FA_ADC_MEM_OFF + 0x04, 0x0001, 3},
[ZFA_STA_SERDES_SYNCED] = {FA_ADC_MEM_OFF + 0x04, 0x0001, 4},
[ZFA_STA_FSM] = {0x04, 0x00000007, 1},
[ZFA_STA_SERDES_PLL] = {0x04, 0x00000008, 1},
[ZFA_STA_SERDES_SYNCED] = {0x04, 0x00000010, 1},
/* Trigger */
/* Config register */
[ZFAT_CFG_HW_SEL] = {FA_ADC_MEM_OFF + 0x08, 0x00000001, 0},
[ZFAT_CFG_HW_POL] = {FA_ADC_MEM_OFF + 0x08, 0x00000001, 1},
[ZFAT_CFG_HW_EN] = {FA_ADC_MEM_OFF + 0x08, 0x00000001, 2},
[ZFAT_CFG_SW_EN] = {FA_ADC_MEM_OFF + 0x08, 0x00000001, 3},
[ZFAT_CFG_INT_SEL] = {FA_ADC_MEM_OFF + 0x08, 0x00000003, 4},
[ZFAT_CFG_THRES] = {FA_ADC_MEM_OFF + 0x08, 0x0000FFFF, 16},
[ZFAT_CFG_HW_SEL] = {0x08, 0x00000001, 1},
[ZFAT_CFG_HW_POL] = {0x08, 0x00000002, 1},
[ZFAT_CFG_HW_EN] = {0x08, 0x00000004, 1},
[ZFAT_CFG_SW_EN] = {0x08, 0x00000008, 1},
[ZFAT_CFG_INT_SEL] = {0x08, 0x00000070, 1},
[ZFAT_CFG_THRES] = {0x08, 0xFFFF0000, 1},
/* Delay */
[ZFAT_DLY] = {FA_ADC_MEM_OFF + 0x0C, 0xFFFFFFFF, 0},
[ZFAT_DLY] = {0x0C, 0xFFFFFFFF, 0},
/* Software */
[ZFAT_SW] = {FA_ADC_MEM_OFF + 0x10, 0xFFFFFFFF, 0},
[ZFAT_SW] = {0x10, 0xFFFFFFFF, 0},
/* Number of shots */
[ZFAT_SHOTS_NB] = {FA_ADC_MEM_OFF + 0x14, 0x0000FFFF, 0},
[ZFAT_SHOTS_NB] = {0x14, 0x0000FFFF, 0},
/* Sample rate */
[ZFAT_SR_DECI] = {FA_ADC_MEM_OFF + 0x1C, 0xFFFF, 0},
[ZFAT_SR_DECI] = {0x1C, 0x0000FFFF, 0},
/* Position address */
[ZFAT_POS] = {FA_ADC_MEM_OFF + 0x18, 0xFFFFFFFF, 0},
[ZFAT_POS] = {0x18, 0xFFFFFFFF, 0},
/* Pre-sample */
[ZFAT_PRE] = {FA_ADC_MEM_OFF + 0x20, 0xFFFFFFFF, 0},
[ZFAT_PRE] = {0x20, 0xFFFFFFFF, 0},
/* Post-sample */
[ZFAT_POST] = {FA_ADC_MEM_OFF + 0x24, 0xFFFFFFFF, 0},
[ZFAT_POST] = {0x24, 0xFFFFFFFF, 0},
/* Sample counter */
[ZFAT_CNT] = {FA_ADC_MEM_OFF + 0x28, 0xFFFFFFFF, 0},
[ZFAT_CNT] = {0x28, 0xFFFFFFFF, 0},
/* Channel 1 */
[ZFA_CH1_CTL_RANGE] = {FA_ADC_MEM_OFF + 0x2C, 0x0077, 0},
[ZFA_CH1_STA] = {FA_ADC_MEM_OFF + 0x30, 0xFFFF, 0},
[ZFA_CH1_GAIN] = {FA_ADC_MEM_OFF + 0x34, 0xFFFF, 0},
[ZFA_CH1_OFFSET] = {FA_ADC_MEM_OFF + 0x38, 0xFFFF, 0},
[ZFA_CH1_CTL_TERM] = {FA_ADC_MEM_OFF + 0x2C, 0x0001, 3},
[ZFA_CH1_CTL_RANGE] = {0x2C, 0x00000077, 1},
[ZFA_CH1_CTL_TERM] = {0x2C, 0x00000008, 1},
[ZFA_CH1_STA] = {0x30, 0x0000FFFF, 0},
[ZFA_CH1_GAIN] = {0x34, 0x0000FFFF, 0},
[ZFA_CH1_OFFSET] = {0x38, 0x0000FFFF, 0},
/* Channel 2 */
[ZFA_CH2_CTL_RANGE] = {FA_ADC_MEM_OFF + 0x3C, 0x0077, 0},
[ZFA_CH2_STA] = {FA_ADC_MEM_OFF + 0x40, 0xFFFF, 0},
[ZFA_CH2_GAIN] = {FA_ADC_MEM_OFF + 0x44, 0xFFFF, 0},
[ZFA_CH2_OFFSET] = {FA_ADC_MEM_OFF + 0x48, 0xFFFF, 0},
[ZFA_CH2_CTL_TERM] = {FA_ADC_MEM_OFF + 0x3C, 0x0001, 3},
[ZFA_CH2_CTL_RANGE] = {0x3C, 0x00000077, 1},
[ZFA_CH2_CTL_TERM] = {0x3C, 0x00000008, 1},
[ZFA_CH2_STA] = {0x40, 0x0000FFFF, 0},
[ZFA_CH2_GAIN] = {0x44, 0x0000FFFF, 0},
[ZFA_CH2_OFFSET] = {0x48, 0x0000FFFF, 0},
/* Channel 3 */
[ZFA_CH3_CTL_RANGE] = {FA_ADC_MEM_OFF + 0x4C, 0x0077, 0},
[ZFA_CH3_STA] = {FA_ADC_MEM_OFF + 0x50, 0xFFFF, 0},
[ZFA_CH3_GAIN] = {FA_ADC_MEM_OFF + 0x54, 0xFFFF, 0},
[ZFA_CH3_OFFSET] = {FA_ADC_MEM_OFF + 0x58, 0xFFFF, 0},
[ZFA_CH3_CTL_TERM] = {FA_ADC_MEM_OFF + 0x4C, 0x0001, 3},
[ZFA_CH3_CTL_RANGE] = {0x4C, 0x00000077, 1},
[ZFA_CH3_CTL_TERM] = {0x4C, 0x00000008, 1},
[ZFA_CH3_STA] = {0x50, 0x0000FFFF, 0},
[ZFA_CH3_GAIN] = {0x54, 0x0000FFFF, 0},
[ZFA_CH3_OFFSET] = {0x58, 0x0000FFFF, 0},
/* Channel 4 */
[ZFA_CH4_CTL_RANGE] = {FA_ADC_MEM_OFF + 0x5C, 0x0077, 0},
[ZFA_CH4_STA] = {FA_ADC_MEM_OFF + 0x60, 0xFFFF, 0},
[ZFA_CH4_GAIN] = {FA_ADC_MEM_OFF + 0x64, 0xFFFF, 0},
[ZFA_CH4_OFFSET] = {FA_ADC_MEM_OFF + 0x68, 0xFFFF, 0},
[ZFA_CH4_CTL_TERM] = {FA_ADC_MEM_OFF + 0x5C, 0x0001, 3},
/* DMA */
[ZFA_DMA_CTL_SWP] = {FA_DMA_MEM_OFF + 0x00, 0x0003, 2},
[ZFA_DMA_CTL_ABORT] = {FA_DMA_MEM_OFF + 0x00, 0x0001, 1},
[ZFA_DMA_CTL_START] = {FA_DMA_MEM_OFF + 0x00, 0x0001, 0},
[ZFA_DMA_STA] = {FA_DMA_MEM_OFF + 0x04, 0x0007, 0},
[ZFA_DMA_ADDR] = {FA_DMA_MEM_OFF + 0x08, 0xFFFFFFFF, 0},
[ZFA_DMA_ADDR_L] = {FA_DMA_MEM_OFF + 0x0C, 0xFFFFFFFF, 0},
[ZFA_DMA_ADDR_H] = {FA_DMA_MEM_OFF + 0x10, 0xFFFFFFFF, 0},
[ZFA_DMA_LEN] = {FA_DMA_MEM_OFF + 0x14, 0xFFFFFFFF, 0},
[ZFA_DMA_NEXT_L] = {FA_DMA_MEM_OFF + 0x18, 0xFFFFFFFF, 0},
[ZFA_DMA_NEXT_H] = {FA_DMA_MEM_OFF + 0x1C, 0xFFFFFFFF, 0},
[ZFA_DMA_BR_DIR] = {FA_DMA_MEM_OFF + 0x20, 0x0001, 1},
[ZFA_DMA_BR_LAST] = {FA_DMA_MEM_OFF + 0x20, 0x0001, 0},
[ZFA_CH4_CTL_RANGE] = {0x5C, 0x00000077, 1},
[ZFA_CH4_CTL_TERM] = {0x5C, 0x00000008, 1},
[ZFA_CH4_STA] = {0x60, 0x0000FFFF, 0},
[ZFA_CH4_GAIN] = {0x64, 0x0000FFFF, 0},
[ZFA_CH4_OFFSET] = {0x68, 0x0000FFFF, 0},
/* IRQ */
[ZFA_IRQ_MULTI] = {FA_IRQ_MEM_OFF + 0x00, 0x000F, 0},
[ZFA_IRQ_SRC] = {FA_IRQ_MEM_OFF + 0x04, 0x000F, 0},
[ZFA_IRQ_MASK] = {FA_IRQ_MEM_OFF + 0x08, 0x000F, 0},
[ZFA_IRQ_ADC_DISABLE_MASK] = {0x00, 0x00000003, 0},
[ZFA_IRQ_ADC_ENABLE_MASK] = {0x04, 0x00000003, 0},
[ZFA_IRQ_ADC_MASK_STATUS] = {0x08, 0x00000003, 0},
[ZFA_IRQ_ADC_SRC] = {0x0C, 0x00000003, 0},
[ZFA_IRQ_VIC_CTRL] = {0x00, 0x000FFFFF, 0},
[ZFA_IRQ_VIC_ENABLE_MASK] = {0x08, 0x00000003, 0},
[ZFA_IRQ_VIC_DISABLE_MASK] = {0x0C, 0x00000003, 0},
[ZFA_IRQ_VIC_MASK_STATUS] = {0x10, 0x00000003, 0},
/* UTC */
[ZFA_UTC_SECONDS] = {FA_UTC_MEM_OFF + 0x00, ~0x0, 0},
[ZFA_UTC_COARSE] = {FA_UTC_MEM_OFF + 0x04, ~0x0, 0},
[ZFA_UTC_TRIG_META] = {FA_UTC_MEM_OFF + 0x08, ~0x0, 0},
[ZFA_UTC_TRIG_SECONDS] = {FA_UTC_MEM_OFF + 0x0C, ~0x0, 0},
[ZFA_UTC_TRIG_COARSE] = {FA_UTC_MEM_OFF + 0x10, ~0x0, 0},
[ZFA_UTC_TRIG_FINE] = {FA_UTC_MEM_OFF + 0x14, ~0x0, 0},
[ZFA_UTC_ACQ_START_META] {FA_UTC_MEM_OFF + 0x18, ~0x0, 0},
[ZFA_UTC_ACQ_START_SECONDS] = {FA_UTC_MEM_OFF + 0x1C, ~0x0, 0},
[ZFA_UTC_ACQ_START_COARSE] = {FA_UTC_MEM_OFF + 0x20, ~0x0, 0},
[ZFA_UTC_ACQ_START_FINE] = {FA_UTC_MEM_OFF + 0x24, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_META] = {FA_UTC_MEM_OFF + 0x28, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_SECONDS] = {FA_UTC_MEM_OFF + 0x2C, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_COARSE] = {FA_UTC_MEM_OFF + 0x30, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_FINE] = {FA_UTC_MEM_OFF + 0x34, ~0x0, 0},
[ZFA_UTC_ACQ_END_META] = {FA_UTC_MEM_OFF + 0x38, ~0x0, 0},
[ZFA_UTC_ACQ_END_SECONDS] = {FA_UTC_MEM_OFF + 0x3C, ~0x0, 0},
[ZFA_UTC_ACQ_END_COARSE] = {FA_UTC_MEM_OFF + 0x40, ~0x0, 0},
[ZFA_UTC_ACQ_END_FINE] = {FA_UTC_MEM_OFF + 0x44, ~0x0, 0},
/* Carrier CSR */
[ZFA_CAR_FMC_PRES] = {FA_CAR_MEM_OFF + 0x04, 0x1, 0},
[ZFA_CAR_P2L_PLL] = {FA_CAR_MEM_OFF + 0x04, 0x1, 1},
[ZFA_CAR_SYS_PLL] = {FA_CAR_MEM_OFF + 0x04, 0x1, 2},
[ZFA_CAR_DDR_CAL] = {FA_CAR_MEM_OFF + 0x04, 0x1, 3},
[ZFA_UTC_SECONDS] = {0x00, ~0x0, 0},
[ZFA_UTC_COARSE] = {0x04, ~0x0, 0},
[ZFA_UTC_TRIG_META] = {0x08, ~0x0, 0},
[ZFA_UTC_TRIG_SECONDS] = {0x0C, ~0x0, 0},
[ZFA_UTC_TRIG_COARSE] = {0x10, ~0x0, 0},
[ZFA_UTC_TRIG_FINE] = {0x14, ~0x0, 0},
[ZFA_UTC_ACQ_START_META] = {0x18, ~0x0, 0},
[ZFA_UTC_ACQ_START_SECONDS] = {0x1C, ~0x0, 0},
[ZFA_UTC_ACQ_START_COARSE] = {0x20, ~0x0, 0},
[ZFA_UTC_ACQ_START_FINE] = {0x24, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_META] = {0x28, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_SECONDS] = {0x2C, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_COARSE] = {0x30, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_FINE] = {0x34, ~0x0, 0},
[ZFA_UTC_ACQ_END_META] = {0x38, ~0x0, 0},
[ZFA_UTC_ACQ_END_SECONDS] = {0x3C, ~0x0, 0},
[ZFA_UTC_ACQ_END_COARSE] = {0x40, ~0x0, 0},
[ZFA_UTC_ACQ_END_FINE] = {0x44, ~0x0, 0},
};
/*
* core-spec fmc-adc-100m14b driver
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
* Copied from fine-delay
*
*/
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/fmc.h>
#include <linux/fmc-sdb.h>
#include "fmc-adc.h"
#include "fa-spec.h"
static char *fa_spec_get_gwname(void)
{
return FA_GATEWARE_SPEC;
}
static int fa_spec_init(struct fa_dev *fa)
{
struct device *msgdev = &fa->fmc->dev;
struct fa_spec_data *cdata;
uint32_t val;
fa->fa_carrier_csr_base = fmc_find_sdb_device(fa->fmc->sdb, 0xce42,
0x603, NULL);
cdata = kzalloc(sizeof(struct fa_spec_data), GFP_KERNEL);
if (!cdata)
return -ENOMEM;
/* SDB carrier specific */
cdata->fa_dma_base =
fmc_find_sdb_device(fa->fmc->sdb, 0xce42, 0x601, NULL);
cdata->fa_irq_dma_base =
fmc_find_sdb_device(fa->fmc->sdb, 0xce42, 0xd5735ab4, NULL);
dev_info(msgdev,
"Spec Base addrs: irq_dmma:0x%x, dma_ctrl:0x%x, csr:0x%x \n",
cdata->fa_irq_dma_base, cdata->fa_dma_base,
fa->fa_carrier_csr_base);
/* Wait 50ms, so device has time to calibrate */
mdelay(50);
/* set FMC0 in normal FMC operation */
fa_writel(fa, fa->fa_carrier_csr_base,
&fa_spec_regs[ZFA_CAR_FMC_RES], 1);
/* Verify that the FMC is plugged (0 is plugged) */
val = fa_readl(fa, fa->fa_carrier_csr_base,
&fa_spec_regs[ZFA_CAR_FMC_PRES]);
if (val) {
dev_err(msgdev, "No FCM ADC plugged\n");
return -ENODEV;
}
/* Verify that system PLL is locked (1 is calibrated) */
val = fa_readl(fa, fa->fa_carrier_csr_base,
&fa_spec_regs[ZFA_CAR_SYS_PLL]);
if (!val) {
dev_err(msgdev, "System PLL not locked\n");
return -ENODEV;
}
/* Verify that DDR3 calibration is done (1 is calibrated) */
val = fa_readl(fa, fa->fa_carrier_csr_base,
&fa_spec_regs[ZFA_CAR_DDR_CAL]);
if (!val) {
dev_err(msgdev, "DDR3 Calibration not done\n");
return -ENODEV;
}
/* Set DMA to transfer data from device to host */
fa_writel(fa, cdata->fa_dma_base,
&fa_spec_regs[ZFA_DMA_BR_DIR], 0);
/* register carrier data */
fa->carrier_data = cdata;
dev_info(msgdev, "spec::%s successfully executed\n", __func__);
return 0;
}
static int fa_spec_reset(struct fa_dev *fa)
{
// struct spec_dev *spec = fa->fmc->carrier_data;
dev_info(&fa->fmc->dev, "%s: resetting TDC core through Gennum.\n",
__func__);
return 0;
}
static void fa_spec_exit(struct fa_dev *fa)
{
kfree(fa->carrier_data);
}
/* Unfortunately, on the spec this is GPIO9, i.e. IRQ(1) */
static struct fmc_gpio fa_gpio_on[] = {
{
.gpio = FMC_GPIO_IRQ(0),
.mode = GPIOF_DIR_IN,
.irqmode = IRQF_TRIGGER_RISING,
}
};
static struct fmc_gpio fa_gpio_off[] = {
{
.gpio = FMC_GPIO_IRQ(0),
.mode = GPIOF_DIR_IN,
.irqmode = 0,
}
};
static int fa_spec_setup_irqs(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
struct fa_spec_data *spec_data = fa->carrier_data;
int err;
/* Request IRQ
* trick : vic needs the base address of teh core firing the irq
* It cannot provided throught irq_request() call therefore the trick
* is to set it by means of the field irq provided by the fmc device
*/
fmc->irq = spec_data->fa_irq_dma_base;
err = fmc->op->irq_request(fmc, fa_spec_irq_handler,
"fmc-adc-100m14b", 0);
if (err) {
dev_err(&fmc->dev, "can't request irq 0x%x (error %i)\n",
fmc->irq, err);
return err;
}
fmc->op->gpio_config(fmc, fa_gpio_on, ARRAY_SIZE(fa_gpio_on));
dev_info(&fmc->dev, "spec::%s successfully executed\n", __func__);
/* Add SPEC specific IRQ sources to listen */
fa->irq_src |= FA_IRQ_SRC_DMA;
return 0;
}
static int fa_spec_free_irqs(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
fmc->op->gpio_config(fmc, fa_gpio_off, ARRAY_SIZE(fa_gpio_off));
return 0;
}
static int fa_spec_enable_irqs(struct fa_dev *fa)
{
struct fa_spec_data *spec_data = fa->carrier_data;
fa_writel(fa, spec_data->fa_irq_dma_base,
&fa_spec_regs[ZFA_IRQ_DMA_ENABLE_MASK],
FA_SPEC_IRQ_DMA_ALL);
return 0;
}
static int fa_spec_disable_irqs(struct fa_dev *fa)
{
struct fa_spec_data *spec_data = fa->carrier_data;
fa_writel(fa, spec_data->fa_irq_dma_base,
&fa_spec_regs[ZFA_IRQ_DMA_DISABLE_MASK],
FA_SPEC_IRQ_DMA_NONE);
return 0;
}
static int fa_spec_ack_irq(struct fa_dev *fa, int irq_id)
{
return 0;
}
struct fa_carrier_op fa_spec_op = {
fa_spec_get_gwname,
fa_spec_init,
fa_spec_reset,
fa_spec_exit,
fa_spec_setup_irqs,
fa_spec_free_irqs,
fa_spec_enable_irqs,
fa_spec_disable_irqs,
fa_spec_ack_irq,
fa_spec_dma_start,
fa_spec_dma_done,
fa_spec_dma_error,
};
......@@ -21,7 +21,7 @@
#include <linux/zio-trigger.h>
#include "fmc-adc.h"
#include "fa-spec.h"
/*
* zfat_calculate_nents
......@@ -62,6 +62,7 @@ static void zfad_setup_dma_scatter(struct fa_dev *fa,
struct zfad_block *zfad_block,
unsigned int n_blocks)
{
struct fa_spec_data *spec_data = fa->carrier_data;
struct scatterlist *sg;
int bytesleft = 0;
void *bufp = NULL;
......@@ -72,7 +73,7 @@ static void zfad_setup_dma_scatter(struct fa_dev *fa,
zfad_block->block->datalen);
i_blk = 0;
for_each_sg(fa->sgt.sgl, sg, fa->sgt.nents, i) {
for_each_sg(spec_data->sgt.sgl, sg, spec_data->sgt.nents, i) {
if (i_blk < n_blocks && i == zfad_block[i_blk].first_nent) {
WARN(bytesleft, "unmapped byte in block %i\n",
i_blk - 1);
......@@ -125,10 +126,11 @@ static void zfad_setup_dma_scatter(struct fa_dev *fa,
* The DMA controller can store a single item, but more then one transfer
* could be necessary
*/
int zfad_map_dma(struct zio_cset *cset, struct zfad_block *zfad_block,
static int zfad_map_dma(struct zio_cset *cset, struct zfad_block *zfad_block,
unsigned int n_blocks)
{
struct fa_dev *fa = cset->zdev->priv_d;
struct fa_spec_data *spec_data = fa->carrier_data;
struct device *dev = &fa->fmc->dev;
struct scatterlist *sg;
struct fa_dma_item *items;
......@@ -147,30 +149,30 @@ int zfad_map_dma(struct zio_cset *cset, struct zfad_block *zfad_block,
pages, n_blocks);
/* Create sglists for the transfers */
err = sg_alloc_table(&fa->sgt, pages, GFP_ATOMIC);
err = sg_alloc_table(&spec_data->sgt, pages, GFP_ATOMIC);
if (err) {
dev_err(dev, "cannot allocate sg table (%i pages)\n", pages);
goto out;
}
/* Limited to 32-bit (kernel limit) */
size = sizeof(*items) * fa->sgt.nents;
size = sizeof(*items) * spec_data->sgt.nents;
items = kzalloc(size, GFP_ATOMIC);
if (!items) {
dev_err(fa->fmc->hwdev, "cannot allocate coherent dma memory\n");
goto out_mem;
}
fa->items = items;
fa->dma_list_item = dma_map_single(fa->fmc->hwdev, items, size,
spec_data->items = items;
spec_data->dma_list_item = dma_map_single(fa->fmc->hwdev, items, size,
DMA_TO_DEVICE);
if (!fa->dma_list_item) {
if (!spec_data->dma_list_item)
goto out_free;
}
/* Setup the scatter list for the provided block */
zfad_setup_dma_scatter(fa, zfad_block, n_blocks);
/* Map DMA buffers */
sglen = dma_map_sg(fa->fmc->hwdev, fa->sgt.sgl,
fa->sgt.nents, DMA_FROM_DEVICE);
sglen = dma_map_sg(fa->fmc->hwdev, spec_data->sgt.sgl,
spec_data->sgt.nents, DMA_FROM_DEVICE);
if (!sglen) {
dev_err(dev, "cannot map dma memory\n");
goto out_map;
......@@ -178,7 +180,7 @@ int zfad_map_dma(struct zio_cset *cset, struct zfad_block *zfad_block,
/* Configure DMA items */
i_blk = 0;
for_each_sg(fa->sgt.sgl, sg, fa->sgt.nents, i) {
for_each_sg(spec_data->sgt.sgl, sg, spec_data->sgt.nents, i) {
if (i_blk < n_blocks && i == zfad_block[i_blk].first_nent) {
/*
* FIXME if we trust our configuration, dev_mem_off is
......@@ -201,8 +203,8 @@ int zfad_map_dma(struct zio_cset *cset, struct zfad_block *zfad_block,
dev_mem_off += items[i].dma_len;
if (!sg_is_last(sg)) {/* more transfers */
/* uint64_t so it works on 32 and 64 bit */
tmp = fa->dma_list_item;
tmp += (sizeof(struct fa_dma_item) * ( i+ 1 ));
tmp = spec_data->dma_list_item;
tmp += (sizeof(struct fa_dma_item) * (i+ 1));
items[i].next_addr_l = ((uint64_t)tmp) & 0xFFFFFFFF;
items[i].next_addr_h = ((uint64_t)tmp) >> 32;
items[i].attribute = 0x1; /* more items */
......@@ -212,26 +214,33 @@ int zfad_map_dma(struct zio_cset *cset, struct zfad_block *zfad_block,
pr_debug("configure DMA item %d "
"(addr: 0x%llx len: %d)(dev off: 0x%x)"
"(next item: 0x%x)",
"(next item: 0x%x)\n",
i, (long long)sg_dma_address(sg),
sg_dma_len(sg), dev_mem_off, items[i].next_addr_l);
/* The first item is written on the device */
if (i == 0) {
zfa_hardware_write(fa, ZFA_DMA_ADDR,
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_ADDR],
items[i].start_addr);
zfa_hardware_write(fa, ZFA_DMA_ADDR_L,
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_ADDR_L],
items[i].dma_addr_l);
zfa_hardware_write(fa, ZFA_DMA_ADDR_H,
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_ADDR_H],
items[i].dma_addr_h);
zfa_hardware_write(fa, ZFA_DMA_LEN,
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_LEN],
items[i].dma_len);
zfa_hardware_write(fa, ZFA_DMA_NEXT_L,
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_NEXT_L],
items[i].next_addr_l);
zfa_hardware_write(fa, ZFA_DMA_NEXT_H,
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_NEXT_H],
items[i].next_addr_h);
/* Set that there is a next item */
zfa_hardware_write(fa, ZFA_DMA_BR_LAST,
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_BR_LAST],
items[i].attribute);
}
}
......@@ -239,17 +248,16 @@ int zfad_map_dma(struct zio_cset *cset, struct zfad_block *zfad_block,
return 0;
out_map:
dma_unmap_single(fa->fmc->hwdev, fa->dma_list_item, size,
dma_unmap_single(fa->fmc->hwdev, spec_data->dma_list_item, size,
DMA_TO_DEVICE);
out_free:
kfree(fa->items);
kfree(spec_data->items);
out_mem:
sg_free_table(&fa->sgt);
sg_free_table(&spec_data->sgt);
out:
return -ENOMEM;
}
/*
* zfad_unmap_dma
* @cset: channel set
......@@ -257,20 +265,58 @@ out:
*
* It unmaps a blocks
*/
void zfad_unmap_dma(struct zio_cset *cset, struct zfad_block *zfad_block)
static void zfad_unmap_dma(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
unsigned int size;
struct fa_spec_data *spec_data = fa->carrier_data;
dev_dbg(fa->fmc->hwdev, "unmap DMA\n");
size = sizeof(struct fa_dma_item) * fa->sgt.nents;
dma_unmap_single(fa->fmc->hwdev, fa->dma_list_item, size,
size = sizeof(struct fa_dma_item) * spec_data->sgt.nents;
dma_unmap_single(fa->fmc->hwdev, spec_data->dma_list_item, size,
DMA_TO_DEVICE);
dma_unmap_sg(fa->fmc->hwdev, fa->sgt.sgl, fa->sgt.nents,
dma_unmap_sg(fa->fmc->hwdev, spec_data->sgt.sgl, spec_data->sgt.nents,
DMA_FROM_DEVICE);
kfree(fa->items);
fa->items = NULL;
fa->dma_list_item = 0;
sg_free_table(&fa->sgt);
kfree(spec_data->items);
spec_data->items = NULL;
spec_data->dma_list_item = 0;
sg_free_table(&spec_data->sgt);
}
int fa_spec_dma_start(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
struct fa_spec_data *spec_data = fa->carrier_data;
struct zio_channel *interleave = cset->interleave;
struct zfad_block *zfad_block = interleave->priv_d;
int res;
res = zfad_map_dma(cset, zfad_block, fa->n_shots);
if (res)
return res;
/* Start DMA transfer */
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_CTL_START], 1);
return 0;
}
void fa_spec_dma_done(struct zio_cset *cset)
{
zfad_unmap_dma(cset);
}
void fa_spec_dma_error(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
struct fa_spec_data *spec_data = fa->carrier_data;
uint32_t val;
zfad_unmap_dma(cset);
val = fa_readl(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_STA]);
if (val)
dev_err(&fa->fmc->dev,
"DMA error (status 0x%x). All acquisition lost\n", val);
}
/*
* Copyright CERN 2012
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* IRQ function handler
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/zio.h>
#include <linux/zio-trigger.h>
#include "fmc-adc.h"
#include "fa-spec.h"
/*
* fa_get_irq_status
* @fa: adc descriptor
* @irq_status: destination of irq status
* @irq_multi: destination of irq multi
*
* Get irq and clear the register. To clear an interrupt we have to write 1
* on the handled interrupt. We handle all interrupt so we clear all interrupts
*/
static void fa_get_irq_status(struct fa_dev *fa, int irq_core_base,
uint32_t *irq_status)
{
/* Get current interrupts status */
*irq_status = fa_readl(fa, irq_core_base,
&fa_spec_regs[ZFA_IRQ_DMA_SRC]);
dev_dbg(&fa->fmc->dev, "core DMA: 0x%x fired an interrupt. IRQ status register: 0x%x\n",
irq_core_base, *irq_status);
if (*irq_status)
/* Clear current interrupts status */
fa_writel(fa, irq_core_base,
&fa_spec_regs[ZFA_IRQ_DMA_SRC], *irq_status);
}
/*
* zfad_irq
* @irq:
* @ptr: pointer to fmc_device
*
* The ADC svec firmware fires interrupt from a single wishbone core
* and throught the VIC ACQ_END and TRIG events. Note about "TRIG"
* event: the main reason to listen this interrupt was to read the
* intermediate time stamps in case of multishots.
* With the new firmware (>=3.0) the stamps come with the data,
* therefore the driver doesn't have to listen "TRIG" event. This
* enhancement remove completely the risk of loosing interrupt in case
* of small number of samples and makes the retry loop in the hanlder
* obsolete.
*/
irqreturn_t fa_spec_irq_handler(int irq_core_base, void *ptr)
{
struct fmc_device *fmc = ptr;
struct fa_dev *fa = fmc_get_drvdata(fmc);
struct zio_cset *cset = fa->zdev->cset;
uint32_t status;
if (unlikely(fa->last_irq_core_src == irq_core_base)) {
WARN(1, "Cannot handle two consecutives %s interrupt."
"The ADC doesn't behave properly\n",
(irq_core_base == fa->fa_irq_adc_base) ? "ACQ" : "DMA");
/* Stop Acquisition, ADC it is not working properly */
zfad_fsm_command(fa, ZFA_STOP);
fa->last_irq_core_src = FA_SPEC_IRQ_SRC_NONE;
return IRQ_HANDLED;
}
/* irq to handle */
fa_get_irq_status(fa, irq_core_base, &status);
if (!status)
return IRQ_NONE;
dev_dbg(&fa->fmc->dev, "Handle ADC interrupts\n");
if (status & FA_SPEC_IRQ_DMA_DONE)
zfad_dma_done(cset);
else if (unlikely(status & FA_SPEC_IRQ_DMA_ERR))
zfad_dma_error(cset);
/* register the core which just fired the IRQ */
/* check proper sequence of IRQ in case of multi IRQ (ACQ + DMA)*/
fa->last_irq_core_src = irq_core_base;
/* ack the irq */
fa->fmc->op->irq_ack(fa->fmc);
return IRQ_HANDLED;
}
/*
* Copyright CERN 2012
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* Table of register masks, used by driver functions
*/
#include "fa-spec.h"
/* Definition of the fa spec registers field: offset - mask - isbitfield */
const struct zfa_field_desc fa_spec_regs[] = {
/* Carrier CSR */
[ZFA_CAR_FMC_PRES] = {0x04, 0x1, 1},
[ZFA_CAR_P2L_PLL] = {0x04, 0x2, 1},
[ZFA_CAR_SYS_PLL] = {0x04, 0x4, 1},
[ZFA_CAR_DDR_CAL] = {0x04, 0x8, 1},
[ZFA_CAR_FMC_RES] = {0x0c, 0x1, 1},
/* IRQ */
[ZFA_IRQ_DMA_DISABLE_MASK] = {0x00, 0x00000003, 0},
[ZFA_IRQ_DMA_ENABLE_MASK] = {0x04, 0x00000003, 0},
[ZFA_IRQ_DMA_MASK_STATUS] = {0x08, 0x00000003, 0},
[ZFA_IRQ_DMA_SRC] = {0x0C, 0x00000003, 0},
/* DMA */
[ZFA_DMA_CTL_SWP] = {0x00, 0x0000000C, 1},
[ZFA_DMA_CTL_ABORT] = {0x00, 0x00000002, 1},
[ZFA_DMA_CTL_START] = {0x00, 0x00000001, 1},
[ZFA_DMA_STA] = {0x04, 0x00000007, 0},
[ZFA_DMA_ADDR] = {0x08, 0xFFFFFFFF, 0},
[ZFA_DMA_ADDR_L] = {0x0C, 0xFFFFFFFF, 0},
[ZFA_DMA_ADDR_H] = {0x10, 0xFFFFFFFF, 0},
[ZFA_DMA_LEN] = {0x14, 0xFFFFFFFF, 0},
[ZFA_DMA_NEXT_L] = {0x18, 0xFFFFFFFF, 0},
[ZFA_DMA_NEXT_H] = {0x1C, 0xFFFFFFFF, 0},
[ZFA_DMA_BR_DIR] = {0x20, 0x00000002, 1},
[ZFA_DMA_BR_LAST] = {0x20, 0x00000001, 1},
};
/*
* Copyright CERN 2012
*
* Header for the fmc-adc-100m14b spec driver
*
*/
#ifndef __FA_SPEC_CORE_H__
#define __FA_SPEC_CORE_H__
#include <linux/scatterlist.h>
#include <linux/irqreturn.h>
#include "fmc-adc.h"
#include "field-desc.h"
/* default spec gateware */
#define FA_GATEWARE_SPEC "fmc/spec-fmc-adc-100m14b.bin"
/* Should be replaced by an sdb query */
#define SPEC_FA_DMA_MEM_OFF 0x01000
/*
* fa_dma_item: The information about a DMA transfer
* @start_addr: pointer where start to retrieve data from device memory
* @dma_addr_l: low 32bit of the dma address on host memory
* @dma_addr_h: high 32bit of the dma address on host memory
* @dma_len: number of bytes to transfer from device to host
* @next_addr_l: low 32bit of the address of the next memory area to use
* @next_addr_h: high 32bit of the address of the next memory area to use
* @attribute: dma information about data transferm. At the moment it is used
* only to provide the "last item" bit, direction is fixed to
* device->host
*/
struct fa_dma_item {
uint32_t start_addr; /* 0x00 */
uint32_t dma_addr_l; /* 0x04 */
uint32_t dma_addr_h; /* 0x08 */
uint32_t dma_len; /* 0x0C */
uint32_t next_addr_l; /* 0x10 */
uint32_t next_addr_h; /* 0x14 */
uint32_t attribute; /* 0x18 */
uint32_t reserved; /* ouch */
};
/* SPEC CSR */
enum fa_spec_regs_id {
/* CSR */
ZFA_CAR_FMC_PRES,
ZFA_CAR_P2L_PLL,
ZFA_CAR_SYS_PLL,
ZFA_CAR_DDR_CAL,
ZFA_CAR_FMC_RES,
/* IRQ DMA: DMA spec specific irq controller */
ZFA_IRQ_DMA_DISABLE_MASK,
ZFA_IRQ_DMA_ENABLE_MASK,
ZFA_IRQ_DMA_MASK_STATUS,
ZFA_IRQ_DMA_SRC,
/* DMA */
ZFA_DMA_CTL_SWP,
ZFA_DMA_CTL_ABORT,
ZFA_DMA_CTL_START,
ZFA_DMA_STA,
ZFA_DMA_ADDR,
ZFA_DMA_ADDR_L,
ZFA_DMA_ADDR_H,
ZFA_DMA_LEN,
ZFA_DMA_NEXT_L,
ZFA_DMA_NEXT_H,
ZFA_DMA_BR_DIR,
ZFA_DMA_BR_LAST,
};
/* SPEC ADC have to listen two IRQ sources managed by two different cores */
#define FA_SPEC_IRQ_SRC_NONE 0
#define FA_SPEC_IRQ_SRC_ACQ 1
#define FA_SPEC_IRQ_SRC_DMA 2
/* DMA spec specific IRQ values */
enum fa_spec_irq {
FA_SPEC_IRQ_DMA_NONE = 0x0,
FA_SPEC_IRQ_DMA_DONE = 0x1,
FA_SPEC_IRQ_DMA_ERR = 0x2,
FA_SPEC_IRQ_DMA_ALL = 0x3,
};
/* specific carrier data */
struct fa_spec_data {
/* DMA attributes */
unsigned int fa_dma_base;
unsigned int fa_irq_dma_base;
struct sg_table sgt;
struct fa_dma_item *items;
dma_addr_t dma_list_item;
unsigned int n_dma_err; /* statistics */
};
/* spec specific hardware registers */
extern const struct zfa_field_desc fa_spec_regs[];
/* spec irq handler */
extern irqreturn_t fa_spec_irq_handler(int irq, void *dev_id);
/* functions exported by fa-dma.c */
extern int fa_spec_dma_start(struct zio_cset *cset);
extern void fa_spec_dma_done(struct zio_cset *cset);
extern void fa_spec_dma_error(struct zio_cset *cset);
#endif /* __FA_SPEC_CORE_H__*/
......@@ -23,10 +23,6 @@
#include "fmc-adc.h"
static int enable_test_data = 0;
module_param(enable_test_data, int, 0444);
/*
* zio device attributes
*/
......@@ -241,7 +237,8 @@ static int zfad_conf_set(struct device *dev, struct zio_attribute *zattr,
return zfad_fsm_command(fa, usr_val);
}
return zfa_hardware_write(fa, reg_index, usr_val);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[reg_index], usr_val);
return 0;
}
/*
......@@ -293,7 +290,8 @@ static int zfad_info_get(struct device *dev, struct zio_attribute *zattr,
case ZFA_CHx_STA:
reg_index = zfad_get_chx_index(zattr->id, to_zio_chan(dev));
zfa_hardware_read(fa, reg_index, usr_val);
*usr_val = fa_readl(fa, fa->fa_adc_csr_base,
&zfad_regs[reg_index]);
i = (int16_t)(*usr_val); /* now signed integer */
*usr_val = i;
break;
......@@ -301,7 +299,7 @@ static int zfad_info_get(struct device *dev, struct zio_attribute *zattr,
reg_index = zattr->id;
}
zfa_hardware_read(fa, reg_index, usr_val);
*usr_val = fa_readl(fa, fa->fa_adc_csr_base, &zfad_regs[reg_index]);
return 0;
}
static const struct zio_sysfs_operations zfad_s_op = {
......@@ -338,13 +336,14 @@ static int zfad_input_cset_software(struct fa_dev *fa, struct zio_cset *cset)
tmp->dev_mem_off = 0; /* Always the first block */
/* Configure post samples */
zfa_hardware_write(fa, ZFAT_POST, cset->ti->nsamples);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_POST],
cset->ti->nsamples);
/* Start the acquisition */
zfad_fsm_command(fa, ZFA_START);
fa->n_shots = 1;
/* Fire software trigger */
zfa_hardware_write(fa, ZFAT_SW, 1);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_SW], 1);
return -EAGAIN;
}
......@@ -371,9 +370,8 @@ static int zfad_input_cset(struct zio_cset *cset)
}
/* If not the fmc-adc-trg, then is a ZIO software trigger */
if (unlikely(cset->trig != &zfat_type)) {
if (unlikely(cset->trig != &zfat_type))
return zfad_input_cset_software(fa, cset);
}
return -EAGAIN; /* data_done on DMA_DONE interrupt */
}
......@@ -383,221 +381,25 @@ static int zfad_input_cset(struct zio_cset *cset)
* @cset: channel set to stop
*
* Stop an acquisition, reset indexes and disable interrupts. This function
* not used when using our internal trigger, which offers t_op->abort:
* only if the trigger misses its own abort, ZIO calls cset->stop_io.
* is useful only if the driver is using a software trigger.
*/
static void zfad_stop_cset(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
if (cset->trig == &zfat_type) /* paranoid (see above comment) */
return;
/* Force the acquisition to stop */
zfad_fsm_command(fa, ZFA_STOP);
/* Release zfad_block */
kfree(cset->interleave->priv_d);
cset->interleave->priv_d = NULL;
/* Clear active block */
cset->interleave->active_block = NULL;
}
/* * * * * * * * * * * * * IRQ functions handler * * * * * * * * * * * * * * */
/*
* zfat_get_irq_status
* @fa: adc descriptor
* @irq_status: destination of irq status
* @irq_multi: destination of irq multi
*
* Get irq and clear the register. To clear an interrupt we have to write 1
* on the handled interrupt. We handle all interrupt so we clear all interrupts
*/
static void zfat_get_irq_status(struct fa_dev *fa,
uint32_t *irq_status, uint32_t *irq_multi)
{
/* Get current interrupts status */
zfa_hardware_read(fa, ZFA_IRQ_SRC, irq_status);
zfa_hardware_read(fa, ZFA_IRQ_MULTI, irq_multi);
dev_dbg(&fa->fmc->dev, "irq status = 0x%x multi = 0x%x\n",
*irq_status, *irq_multi);
/* Clear current interrupts status */
zfa_hardware_write(fa, ZFA_IRQ_SRC, *irq_status);
zfa_hardware_write(fa, ZFA_IRQ_MULTI, *irq_multi);
}
/*
* zfat_get_time_stamp
*
* Get the last trigger time-stamp from device
*/
static void zfat_get_time_stamp(struct fa_dev *fa, struct zio_timestamp *ts)
{
uint32_t val;
/* We can't read directly to ts->, as they are 64-bit values */
zfa_hardware_read(fa, ZFA_UTC_TRIG_SECONDS, &val); ts->secs = val;
zfa_hardware_read(fa, ZFA_UTC_TRIG_COARSE, &val); ts->ticks = val;
zfa_hardware_read(fa, ZFA_UTC_TRIG_FINE, &val); ts->bins = val;
}
/*
* zfat_irq_trg_fire
* @fa: fmc-adc descriptor
*
* Trigger fires. This function stores the time-stamp in the current_ctrl and
* in the pre-allocated block. Then it increments the sequence number both in
* current_ctrl and in the pre-allocated block.
*
* If the device is working in single-shot mode, once the trigger fire
* interrupt occurs we must fix the dev_mem_addr of the block.
*/
static void zfat_irq_trg_fire(struct zio_cset *cset)
{
struct zio_channel *interleave = cset->interleave;
struct fa_dev *fa = cset->zdev->priv_d;
struct zfad_block *zfad_block = interleave->priv_d;
struct zio_control *ctrl;
uint32_t dev_mem_off, trg_pos, pre_samp;
dev_dbg(&fa->fmc->dev, "Trigger fire %i/%i\n",
fa->n_fires + 1, fa->n_shots);
if (fa->n_fires >= fa->n_shots) {
WARN(1, "Invalid Fire, STOP acquisition");
/* If the user is using a software trigger */
if (cset->trig != &zfat_type) {
/* Force the acquisition to stop */
zfad_fsm_command(fa, ZFA_STOP);
return;
/* Release zfad_block */
kfree(cset->interleave->priv_d);
cset->interleave->priv_d = NULL;
/* Clear active block */
cset->interleave->active_block = NULL;
}
/* Fix dev_mem_addr in single-shot mode */
if (fa->n_shots == 1) {
int nchan = FA_NCHAN;
struct zio_control *ctrl = cset->chan[FA_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 */
zfa_hardware_read(fa, ZFAT_POS, &trg_pos);
/* translate from sample count to memory offset */
dev_mem_off = (trg_pos - pre_samp) * cset->ssize * nchan;
dev_dbg(&fa->fmc->dev,
"Trigger @ 0x%08x, pre %i, offset 0x%08x\n",
trg_pos, pre_samp, dev_mem_off);
zfad_block[fa->n_fires].dev_mem_off = dev_mem_off;
}
/* Get control from pre-allocated block */
ctrl = zio_get_ctrl(zfad_block[fa->n_fires].block);
/* Update timestamp */
zfat_get_time_stamp(fa, &interleave->current_ctrl->tstamp);
memcpy(&ctrl->tstamp, &interleave->current_ctrl->tstamp,
sizeof(struct zio_timestamp));
/* Update sequence number */
interleave->current_ctrl->seq_num++;
ctrl->seq_num = interleave->current_ctrl->seq_num;
/* Count fire */
fa->n_fires++;
}
/*
* zfad_irq
* @irq:
* @ptr: pointer to fmc_device
*
* The different irq status are handled in different if statement. At the end
* of the if statement we don't call return because it is possible that there
* are others irq to handle. The order of irq handlers is based on the
* possibility to have many irq rised at the same time. It is possible that
* ZFAT_TRG_FIRE and ZFAT_ACQ_END happens simultaneously, so we handle FIRE
* before END. It should be impossible to have simultaneously both DMA
* interrupts and acquisition interrupts active at the same time.
*/
static irqreturn_t zfad_irq(int irq, void *ptr)
{
struct fmc_device *fmc = ptr;
struct fa_dev *fa = fmc_get_drvdata(fmc);
struct zio_cset *cset = fa->zdev->cset;
uint32_t status, multi;
int max_try = 10;
/* irq to handle */
zfat_get_irq_status(fa, &status, &multi);
if (!status)
return IRQ_NONE;
irq_handler:
dev_dbg(&fa->fmc->dev, "Handle ADC interrupts\n");
if (unlikely((status & (ZFAT_DMA_DONE | ZFAT_DMA_ERR)) &&
(status & (ZFAT_TRG_FIRE | ZFAT_ACQ_END)))) {
WARN(1, "Cannot handle trigger interrupt and DMA interrupt at "
"the same time\n");
/* Stop Acquisition, ADC it is not working properly */
zfad_fsm_command(fa, ZFA_STOP);
return IRQ_HANDLED;
}
/*
* It cannot happen that DMA_DONE is in the multi register.
* It should not happen ...
*/
if (status & ZFAT_DMA_DONE) {
zfad_dma_done(cset);
}
if (unlikely((status | multi) & ZFAT_DMA_ERR)) {
zfad_dma_error(cset);
}
/* Fire the trigger for each interrupt */
if (status & ZFAT_TRG_FIRE)
zfat_irq_trg_fire(cset);
if (multi & ZFAT_TRG_FIRE)
zfat_irq_trg_fire(cset);
/*
* If it is too fast the ACQ_END interrupt can be in the
* multi register.
*/
if ((status | multi) & ZFAT_ACQ_END)
zfat_irq_acq_end(cset);
/* ack the irq */
fa->fmc->op->irq_ack(fa->fmc);
/*
* Read again the interrupt status. It can happen that an interrupt
* is raised while we was processing a previous interrupt. If there
* are new active interrupts, then handle them.
* This handler cannot monopolize the processor, so it check for
* new interrupts only 'max_try' times.
*/
zfat_get_irq_status(fa, &status, &multi);
if ((status || multi) && --max_try)
goto irq_handler;
return IRQ_HANDLED;
}
/*
* zfat_gpio_cfg
*
* GPIO configuration for FMC ADC. It configure only the interrupt GPIO
*/
struct fmc_gpio zfat_gpio_cfg[] = {
{
.gpio = FMC_GPIO_IRQ(0),
.mode = GPIOF_DIR_IN,
.irqmode = IRQF_TRIGGER_RISING,
}
};
/* * * * * * * * * * * * * * * * Initialization * * * * * * * * * * * * * * */
/*
* zfad_zio_probe
* @zdev: the real zio device
......@@ -608,66 +410,13 @@ struct fmc_gpio zfat_gpio_cfg[] = {
static int zfad_zio_probe(struct zio_device *zdev)
{
struct fa_dev *fa = zdev->priv_d;
int err = 0, i, addr;
dev_dbg(&zdev->head.dev, "%s:%d\n", __func__, __LINE__);
/* Save also the pointer to the real zio_device */
fa->zdev = zdev;
/* Retrieve calibration data from the eeprom, then verify it */
fa_read_eeprom_calib(fa);
/* Configure GPIO for IRQ */
fa->fmc->op->gpio_config(fa->fmc, zfat_gpio_cfg,
ARRAY_SIZE(zfat_gpio_cfg));
/* Request IRQ */
err = fa->fmc->op->irq_request(fa->fmc, zfad_irq, "fmc-adc-100m14b",
IRQF_SHARED);
if (err)
dev_err(&fa->fmc->dev, "can't request irq %i (error %i)\n",
fa->fmc->irq, err);
/* Force stop FSM to prevent early trigger fire */
zfa_hardware_write(fa, ZFA_CTL_FMS_CMD, ZFA_STOP);
/* Initialize channels to use 1V range */
for (i = 0; i < 4; ++i) {
addr = zfad_get_chx_index(ZFA_CHx_CTL_RANGE,
&zdev->cset->chan[i]);
zfa_hardware_write(fa, addr, ZFA_RANGE_1V);
zfad_set_range(fa, &zdev->cset->chan[i], ZFA_RANGE_1V);
}
zfad_reset_offset(fa);
/* Enable mezzanine clock */
zfa_hardware_write(fa, ZFA_CTL_CLK_EN, 1);
/* Set DMA to transfer data from device to host */
zfa_hardware_write(fa, ZFA_DMA_BR_DIR, 0);
/* Set decimation to minimum */
zfa_hardware_write(fa, ZFAT_SR_DECI, 1);
/* Set test data register */
zfa_hardware_write(fa, ZFA_CTL_TEST_DATA_EN, enable_test_data);
/* Set to single shot mode by default */
zfa_hardware_write(fa, ZFAT_SHOTS_NB, 1);
if (zdev->cset->ti->cset->trig == &zfat_type) {
/* Select external trigger (index 0) */
zfa_hardware_write(fa, ZFAT_CFG_HW_SEL, 1);
zdev->cset->ti->zattr_set.ext_zattr[0].value = 1;
} else {
/* Enable Software trigger*/
zfa_hardware_write(fa, ZFAT_CFG_SW_EN, 1);
/* Disable Hardware trigger*/
zfa_hardware_write(fa, ZFAT_CFG_HW_EN, 0);
}
/* Zero offsets and release the DAC clear */
zfad_reset_offset(fa);
zfa_hardware_write(fa, ZFA_CTL_DAC_CLR_N, 1);
/* Set UTC seconds from the kernel seconds */
zfa_hardware_write(fa, ZFA_UTC_SECONDS, get_seconds());
return err;
/* We don't have csets at this point, so don't do anything more */
return 0;
}
/*
......@@ -678,9 +427,6 @@ static int zfad_zio_probe(struct zio_device *zdev)
*/
static int zfad_zio_remove(struct zio_device *zdev)
{
struct fa_dev *fa = zdev->priv_d;
fa->fmc->op->irq_free(fa->fmc);
return 0;
}
......@@ -774,46 +520,15 @@ void fa_zio_unregister(void)
*/
int fa_zio_init(struct fa_dev *fa)
{
struct device *hwdev = fa->fmc->hwdev;
struct device *msgdev = &fa->fmc->dev;
uint32_t val;
int err;
/* Check if hardware supports 64-bit DMA */
if(dma_set_mask(hwdev, DMA_BIT_MASK(64))) {
/* Check if hardware supports 32-bit DMA */
if(dma_set_mask(hwdev, DMA_BIT_MASK(32))) {
dev_err(msgdev, "32-bit DMA addressing not available\n");
return -EINVAL;
}
}
/* Wait 50ms, so device has time to calibrate */
mdelay(50);
/* Verify that the FMC is plugged (0 is plugged) */
zfa_hardware_read(fa, ZFA_CAR_FMC_PRES, &val);
if (val) {
dev_err(msgdev, "No FCM ADC plugged\n");
return -ENODEV;
}
/* Verify that system PLL is locked (1 is calibrated) */
zfa_hardware_read(fa, ZFA_CAR_SYS_PLL, &val);
if (!val) {
dev_err(msgdev, "System PLL not locked\n");
return -ENODEV;
}
/* Verify that DDR3 calibration is done (1 is calibrated) */
zfa_hardware_read(fa, ZFA_CAR_DDR_CAL, &val);
if (!val) {
dev_err(msgdev, "DDR3 Calibration not done\n");
return -ENODEV;
}
/* Allocate the hardware zio_device for registration */
fa->hwzdev = zio_allocate_device();
if (IS_ERR(fa->hwzdev)) {
dev_err(msgdev, "Cannot allocate ZIO device\n");
err = PTR_ERR(fa->hwzdev);
goto out_allocate;
return PTR_ERR(fa->hwzdev);
}
/* Mandatory fields */
......@@ -825,13 +540,8 @@ int fa_zio_init(struct fa_dev *fa)
fa->fmc->device_id);
if (err) {
dev_err(msgdev, "Cannot register ZIO device fmc-adc-100m14b\n");
goto out_dev;
zio_free_device(fa->hwzdev);
}
return 0;
out_dev:
zio_free_device(fa->hwzdev);
out_allocate:
return err;
}
......
......@@ -36,7 +36,7 @@ static ZIO_ATTR_DEFINE_STD(ZIO_TRG, zfat_std_zattr) = {
/* Number of shots */
ZIO_ATTR(trig, ZIO_ATTR_TRIG_N_SHOTS, ZIO_RW_PERM, ZFAT_SHOTS_NB, 1),
ZIO_ATTR(trig, ZIO_ATTR_TRIG_PRE_SAMP, ZIO_RW_PERM, ZFAT_PRE, 0),
ZIO_ATTR(trig, ZIO_ATTR_TRIG_POST_SAMP, ZIO_RW_PERM, ZFAT_POST, 0),
ZIO_ATTR(trig, ZIO_ATTR_TRIG_POST_SAMP, ZIO_RW_PERM, ZFAT_POST, 1),
};
static struct zio_attribute zfat_ext_zattr[] = {
/* Config register */
......@@ -95,8 +95,29 @@ static int zfat_conf_set(struct device *dev, struct zio_attribute *zattr,
dev_err(dev, "nshots cannot be 0\n");
return -EINVAL;
}
case ZFAT_PRE:
if (tmp_val > 1) { /* multishot restricts samples count */
err = zfat_overflow_detection(ti, zattr->id, tmp_val);
if (err)
return err;
}
break;
case ZFAT_POST:
/*
* actually the HW adds systematically a sample
* corresponding to the trigger itself. therefore the
* client ask pre-samp+post-samp and the HW returns
* pre-samp+1+post-samp To make this behaviour
* invisible from the user we consider that the sample
* corresponding to the trigger is part of the post
* samples. Therefore the value written in the HW is
* post-samples-1 and value 0 is excluded
*/
if (!tmp_val) {
dev_err(dev, "post samples cannot be 0 (minimum 1)\n");
return -EINVAL;
}
tmp_val -= 1;
case ZFAT_PRE:
err = zfat_overflow_detection(ti, zattr->id, tmp_val);
if (err)
return err;
......@@ -120,7 +141,8 @@ static int zfat_conf_set(struct device *dev, struct zio_attribute *zattr,
break;
}
return zfa_hardware_write(fa, zattr->id, tmp_val);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[zattr->id], tmp_val);
return 0;
}
......@@ -133,7 +155,14 @@ static int zfat_info_get(struct device *dev, struct zio_attribute *zattr,
{
struct fa_dev *fa = get_zfadc(dev);
zfa_hardware_read(fa, zattr->id, usr_val);
*usr_val = fa_readl(fa, fa->fa_adc_csr_base, &zfad_regs[zattr->id]);
/*
* See in zfat-conf-set explanations (just above)
* Post sample value read from the HW is incrmented by 1
*/
if (zattr->id == ZFAT_POST)
*usr_val += 1;
return 0;
}
......@@ -162,9 +191,9 @@ static struct zio_ti *zfat_create(struct zio_trigger_type *trig,
return ERR_PTR(-ENOMEM);
/* Disable Software trigger*/
zfa_hardware_write(fa, ZFAT_CFG_SW_EN, 0);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_SW_EN], 0);
/* Enable Hardware trigger*/
zfa_hardware_write(fa, ZFAT_CFG_HW_EN, 1);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_HW_EN], 1);
zfat->fa = fa;
zfat->ti.cset = cset;
......@@ -178,15 +207,15 @@ static void zfat_destroy(struct zio_ti *ti)
struct zfat_instance *zfat = to_zfat_instance(ti);
/* Enable Software trigger */
zfa_hardware_write(fa, ZFAT_CFG_SW_EN, 1);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_SW_EN], 1);
/* Disable Hardware trigger */
zfa_hardware_write(fa, ZFAT_CFG_HW_EN, 0);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_HW_EN], 0);
/* Other triggers cannot use pre-samples */
zfa_hardware_write(fa, ZFAT_PRE, 0);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_PRE], 0);
/* Reset post samples */
zfa_hardware_write(fa, ZFAT_POST, 0);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_POST], 0);
/* Other triggers can handle only 1 shot */
zfa_hardware_write(fa, ZFAT_SHOTS_NB, 1);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_SHOTS_NB], 1);
kfree(zfat);
}
......@@ -201,7 +230,7 @@ static void zfat_change_status(struct zio_ti *ti, unsigned int status)
{
struct fa_dev *fa = ti->cset->zdev->priv_d;
zfa_hardware_write(fa, ZFAT_CFG_HW_EN, !status);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_HW_EN], !status);
}
/*
......@@ -228,7 +257,7 @@ static int zfat_data_done(struct zio_cset *cset)
return 0;
/* Store blocks */
for(i = 0; i < fa->n_shots; ++i)
for (i = 0; i < fa->n_shots; ++i)
if (likely(i < fa->n_fires)) {/* Store filled blocks */
dev_dbg(&fa->fmc->dev, "Store Block %i/%i\n",
i + 1, fa->n_shots);
......@@ -292,12 +321,25 @@ static int zfat_arm_trigger(struct zio_ti *ti)
interleave->priv_d = zfad_block;
/*
* Calculate the required size to store all channels.
* This is an interleaved acquisition, so nsamples represents the
* Calculate the required size to store all channels. This is
* an interleaved acquisition, so nsamples represents the
* number of sample on all channels (n_chan * chan_samples)
* Trig time stamp are appended after the post samples
* (4*32bits word) size should be 32bits word aligned
* ti->nsamples is the sum of (pre-samp+ post-samp)*4chan
* because it's the interleave channel.
*/
size = interleave->current_ctrl->ssize * ti->nsamples;
size = (interleave->current_ctrl->ssize * ti->nsamples)
+ FA_TRIG_TIMETAG_BYTES;
/* check if size is 32 bits word aligned: should be always the case */
if (size % 4) {
/* should never happen: increase the size accordling */
dev_warn(msgdev,
"\nzio data block size should 32bit word aligned."
"original size:%d was increased by %d bytes\n",
size, size%4);
size += size % 4;
}
dev_mem_off = 0;
/* Allocate ZIO blocks */
for (i = 0; i < fa->n_shots; ++i) {
......@@ -305,7 +347,7 @@ static int zfat_arm_trigger(struct zio_ti *ti)
block = zbuf->b_op->alloc_block(interleave->bi, size, gfp);
if (!block) {
dev_err(msgdev,
"arm trigger fail, cannot allocate block\n");
"\narm trigger fail, cannot allocate block\n");
err = -ENOMEM;
goto out_allocate;
}
......@@ -327,7 +369,7 @@ static int zfat_arm_trigger(struct zio_ti *ti)
return err;
out_allocate:
while((--i) >= 0)
while ((--i) >= 0)
zbuf->b_op->free_block(interleave->bi, zfad_block[i].block);
kfree(zfad_block);
interleave->priv_d = NULL;
......@@ -351,7 +393,7 @@ static void zfat_abort(struct zio_ti *ti)
dev_dbg(&fa->fmc->dev, "Aborting trigger\n");
/* Free all blocks */
for(i = 0; i < fa->n_shots; ++i)
for (i = 0; i < fa->n_shots; ++i)
bi->b_op->free_block(bi, zfad_block[i].block);
kfree(zfad_block);
cset->interleave->priv_d = NULL;
......
......@@ -8,35 +8,16 @@
#ifndef _FIELD_DESC_H_
#define _FIELD_DESC_H_
#include <linux/types.h>
/*
* zfa_field_desc is a field register descriptor. By using address, mask
* and shift the driver can describe every fields in registers.
*/
struct zfa_field_desc {
unsigned long addr; /* address of the register, or base offset */
unsigned long offset; /* related to its component base */
uint32_t mask; /* bit mask a register field */
uint32_t shift; /* shift of the mask into the register */
int is_bitfield; /* whether it maps full register or a field */
};
/*
* Get a field from a register value. You read a register from your device,
* then you use this function to get a filed defined with zfa_field_desc
* from the read value
*/
static inline uint32_t zfa_get_field(const struct zfa_field_desc *fld,
uint32_t fld_val)
{
return (fld_val & (fld->mask << fld->shift)) >> fld->shift;
}
/*
* Set a field to a register value. You read a register from your device,
* then you use this function to set a field defined with zfa_field_desc
* into the read value. Then you can write the register
*/
static inline uint32_t zfa_set_field(const struct zfa_field_desc *fld,
uint32_t fld_val, uint32_t usr_val)
{
return (fld_val & (~(fld->mask << fld->shift))) |
(usr_val << fld->shift);
}
#endif /* _FIELD_DESC_H_ */
......@@ -7,38 +7,32 @@
#ifndef FMC_ADC_H_ /* too generic, maybe */
#define FMC_ADC_H_
#include <linux/scatterlist.h>
#include <linux/workqueue.h>
#include <linux/fmc.h>
#include <linux/zio.h>
#include "field-desc.h"
#define FA_GATEWARE_DEFAULT_NAME "fmc/adc-100m14b.bin"
#define FA_NCHAN 4 /* We have 4 of them,no way out of it */
/* ADC register offset */
#define FA_DMA_MEM_OFF 0x01000
#define FA_CAR_MEM_OFF 0x01300
#define FA_UTC_MEM_OFF 0x01400
#define FA_IRQ_MEM_OFF 0x01500
#define FA_SPI_MEM_OFF 0x01700
#define FA_ADC_MEM_OFF 0x01900
#define FA_OWI_MEM_OFF 0X01A00 /* one-wire */
/* ADC DDR memory */
#define FA_MAX_ACQ_BYTE 0x10000000 /* 256MB */
enum fa_input_range {
ZFA_RANGE_10V = 0x0,
ZFA_RANGE_1V,
ZFA_RANGE_100mV,
ZFA_RANGE_OPEN, /* Channel disconnected from ADC */
/* Carrier-specific operations (gateware does not fully decouple
carrier specific stuff, such as DMA or resets, from
mezzanine-specific operations). */
struct fa_dev; /* forward declaration */
struct fa_carrier_op {
char* (*get_gwname)(void);
int (*init) (struct fa_dev *);
int (*reset_core) (struct fa_dev *);
void (*exit) (struct fa_dev *);
int (*setup_irqs) (struct fa_dev *);
int (*free_irqs) (struct fa_dev *);
int (*enable_irqs) (struct fa_dev *);
int (*disable_irqs) (struct fa_dev *);
int (*ack_irq) (struct fa_dev *, int irq_id);
int (*dma_start)(struct zio_cset *cset);
void (*dma_done)(struct zio_cset *cset);
void (*dma_error)(struct zio_cset *cset);
};
#define ZFA_RANGE_MIN 0 /* 10V above */
#define ZFA_RANGE_MAX 2 /* 100mV above */
/* ADC and DAC Calibration, from EEPROM */
struct fa_calib_stanza {
......@@ -52,29 +46,6 @@ struct fa_calib {
struct fa_calib_stanza dac[3]; /* For user offset, one per range */
};
/*
* fa_dma_item: The information about a DMA transfer
* @start_addr: pointer where start to retrieve data from device memory
* @dma_addr_l: low 32bit of the dma address on host memory
* @dma_addr_h: high 32bit of the dma address on host memory
* @dma_len: number of bytes to transfer from device to host
* @next_addr_l: low 32bit of the address of the next memory area to use
* @next_addr_h: high 32bit of the address of the next memory area to use
* @attribute: dma information about data transferm. At the moment it is used
* only to provide the "last item" bit, direction is fixed to
* device->host
*/
struct fa_dma_item {
uint32_t start_addr; /* 0x00 */
uint32_t dma_addr_l; /* 0x04 */
uint32_t dma_addr_h; /* 0x08 */
uint32_t dma_len; /* 0x0C */
uint32_t next_addr_l; /* 0x10 */
uint32_t next_addr_h; /* 0x14 */
uint32_t attribute; /* 0x18 */
uint32_t reserved; /* ouch */
};
/*
* fa_dev: is the descriptor of the FMC ADC mezzanine
*
......@@ -88,9 +59,6 @@ struct fa_dma_item {
*
* @n_dma_err: number of errors
*
* @sgt is the scatter/gather table that describe the DMA acquisition
* @item a list on fa_dma_item to describe
* @dma_list_item is a DMA address pointer to the fa_dma_item list
*/
struct fa_dev {
/* the pointer to the fmc_device generic structure */
......@@ -109,6 +77,18 @@ struct fa_dev {
unsigned int fa_irq_adc_base;
unsigned int fa_utc_base;
/* carrier specific functions (init/exit/reset/readout/irq handling) */
struct fa_carrier_op *carrier_op;
/* carrier private data */
void *carrier_data;
int irq_src; /* list of irq sources to listen */
struct work_struct irq_work;
/*
* keep last core having fired an IRQ
* Used to check irq sequence: ACQ followed by DMA
*/
int last_irq_core_src;
/* Acquisition */
unsigned int n_shots;
unsigned int n_fires;
......@@ -129,31 +109,8 @@ struct fa_dev {
/* flag */
int enable_auto_start;
/* DMA attributes */
struct sg_table sgt;
struct fa_dma_item *items;
dma_addr_t dma_list_item;
};
/*
* zfad_block
* @block is zio_block which contains data and metadata from a single shot
* @dev_mem_off is the offset in ADC internal memory. It points to the first
* sample of the stored shot
* @first_nent is the index of the first nent used for this block
*/
struct zfad_block {
struct zio_block *block;
uint32_t dev_mem_off;
unsigned int first_nent;
};
extern int zfad_map_dma(struct zio_cset *cset,
struct zfad_block *zfad_block,
unsigned int n_blocks);
extern void zfad_unmap_dma(struct zio_cset *cset,
struct zfad_block *zfad_block);
/* Device registers */
enum zfadc_dregs_enum {
......@@ -193,53 +150,53 @@ enum zfadc_dregs_enum {
ZFAT_POST,
/* Sample counter */
ZFAT_CNT,
/* start:declaration block requiring some order */
/* Channel 1 */
ZFA_CH1_CTL_RANGE,
ZFA_CH1_CTL_TERM,
ZFA_CH1_STA,
ZFA_CH1_GAIN,
ZFA_CH1_OFFSET,
ZFA_CH1_CTL_TERM,
/* Channel 2 */
ZFA_CH2_CTL_RANGE,
ZFA_CH2_CTL_TERM,
ZFA_CH2_STA,
ZFA_CH2_GAIN,
ZFA_CH2_OFFSET,
ZFA_CH2_CTL_TERM,
/* Channel 3 */
ZFA_CH3_CTL_RANGE,
ZFA_CH3_CTL_TERM,
ZFA_CH3_STA,
ZFA_CH3_GAIN,
ZFA_CH3_OFFSET,
ZFA_CH3_CTL_TERM,
/* Channel 4 */
ZFA_CH4_CTL_RANGE,
ZFA_CH4_CTL_TERM,
ZFA_CH4_STA,
ZFA_CH4_GAIN,
ZFA_CH4_OFFSET,
ZFA_CH4_CTL_TERM,
/* Other*/
/*
* CHx__ are specifc ids used by some internal arithmetic
* Be carefull: the arithmetic expects
* that ch1 to ch4 are declared in the enum just above
* in the right order and grouped.
* Don't insert any other id in this area
*/
ZFA_CHx_CTL_RANGE,
ZFA_CHx_CTL_TERM,
ZFA_CHx_STA,
ZFA_CHx_GAIN,
ZFA_CHx_OFFSET,
ZFA_CHx_CTL_TERM,
/* DMA */
ZFA_DMA_CTL_SWP,
ZFA_DMA_CTL_ABORT,
ZFA_DMA_CTL_START,
ZFA_DMA_STA,
ZFA_DMA_ADDR,
ZFA_DMA_ADDR_L,
ZFA_DMA_ADDR_H,
ZFA_DMA_LEN,
ZFA_DMA_NEXT_L,
ZFA_DMA_NEXT_H,
ZFA_DMA_BR_DIR,
ZFA_DMA_BR_LAST,
/* IRQ */
ZFA_IRQ_MULTI,
ZFA_IRQ_SRC,
ZFA_IRQ_MASK,
/* end:declaration block requiring some order */
/* two wishbone core for IRQ: VIC, ADC */
ZFA_IRQ_ADC_DISABLE_MASK,
ZFA_IRQ_ADC_ENABLE_MASK,
ZFA_IRQ_ADC_MASK_STATUS,
ZFA_IRQ_ADC_SRC,
ZFA_IRQ_VIC_CTRL,
ZFA_IRQ_VIC_DISABLE_MASK,
ZFA_IRQ_VIC_ENABLE_MASK,
ZFA_IRQ_VIC_MASK_STATUS,
/* UTC core */
ZFA_UTC_SECONDS,
ZFA_UTC_COARSE,
......@@ -259,25 +216,48 @@ enum zfadc_dregs_enum {
ZFA_UTC_ACQ_END_SECONDS,
ZFA_UTC_ACQ_END_COARSE,
ZFA_UTC_ACQ_END_FINE,
/* Carrier CSR */
ZFA_CAR_FMC_PRES,
ZFA_CAR_P2L_PLL,
ZFA_CAR_SYS_PLL,
ZFA_CAR_DDR_CAL,
/* Other "address" */
ZFA_SW_R_NOADDRES_NBIT,
ZFA_HW_PARAM_COMMON_LAST,
};
/*
* ADC parameter id not mapped to Hw register
* Id is used as zio attribute id
*/
enum fa_sw_param_id {
/* to guarantee unique zio attr id */
ZFA_SW_R_NOADDRES_NBIT = ZFA_HW_PARAM_COMMON_LAST,
ZFA_SW_R_NOADDRES_TEMP,
ZFA_SW_R_NOADDERS_AUTO,
ZFA_SW_PARAM_COMMON_LAST,
};
/* Registers lists used in fd-zio-drv.c */
extern const struct zfa_field_desc zfad_regs[];
/* trigger timestamp block size in bytes */
/* This block is added after the post trigger samples */
/* in the DDR and contains the trigger timestamp */
#define FA_TRIG_TIMETAG_BYTES 0x10
#define FA_NCHAN 4 /* We have 4 of them,no way out of it */
/*
* ZFA_CHx_MULT
* ZFA_CHx_MULT : the trick which requires channel regs id grouped and ordered
* address offset between two registers of the same type on consecutive channel
*/
#define ZFA_CHx_MULT 5
/* ADC DDR memory */
#define FA_MAX_ACQ_BYTE 0x10000000 /* 256MB */
/* In Multi shot mode samples go through a dpram which has a limited size */
#define FA_MAX_MSHOT_ACQ_BYTE 0x3FE8 /* 2045 samples (2045*8 bytes) */
enum fa_input_range {
ZFA_RANGE_10V = 0x0,
ZFA_RANGE_1V,
ZFA_RANGE_100mV,
ZFA_RANGE_OPEN, /* Channel disconnected from ADC */
};
#define ZFA_RANGE_MIN 0 /* 10V above */
#define ZFA_RANGE_MAX 2 /* 100mV above */
enum zfa_fsm_cmd {
ZFA_NONE = 0x0,
ZFA_START = 0x1,
......@@ -291,14 +271,22 @@ enum zfa_fsm_state {
ZFA_STATE_WAIT,
ZFA_STATE_DECR,
};
/* All possible interrupt available */
enum zfat_irq {
ZFAT_NONE = 0x0,
ZFAT_DMA_DONE = 0x1,
ZFAT_DMA_ERR = 0x2,
ZFAT_TRG_FIRE = 0x4,
ZFAT_ACQ_END = 0x8,
ZFAT_ALL = 0xF,
/*
* Bit pattern used in order to factorize code between SVEC and SPEC
* Depending of the carrier, ADC may have to listen vaious IRQ sources
* SVEC: only ACQ irq source (end DMA irq is manged by vmebus driver)
* SPEC: ACQ and DMA irq source
*/
enum fa_irq_src {
FA_IRQ_SRC_ACQ = 0x1,
FA_IRQ_SRC_DMA = 0x2,
};
/* adc IRQ values */
enum fa_irq_adc {
FA_IRQ_ADC_NONE = 0x0,
FA_IRQ_ADC_ACQ_END = 0x2,
};
#ifdef __KERNEL__ /* All the rest is only of kernel users */
......@@ -307,6 +295,19 @@ enum zfat_irq {
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
/*
* zfad_block
* @block is zio_block which contains data and metadata from a single shot
* @dev_mem_off is the offset in ADC internal memory. It points to the first
* sample of the stored shot
* @first_nent is the index of the first nent used for this block
*/
struct zfad_block {
struct zio_block *block;
uint32_t dev_mem_off;
unsigned int first_nent;
};
#define FA_CAL_OFFSET 0x0100 /* Offset in EEPROM */
#define FA_CAL_NO_OFFSET ((int16_t)0x0000)
......@@ -324,7 +325,7 @@ static inline int zfat_overflow_detection(struct zio_ti *ti, unsigned int addr,
{
struct zio_attribute *ti_zattr = ti->zattr_set.std_zattr;
uint32_t pre_t, post_t, nshot_t;
size_t size;
size_t shot_size;
if (!addr)
return 0;
......@@ -339,11 +340,20 @@ static inline int zfat_overflow_detection(struct zio_ti *ti, unsigned int addr,
nshot_t = addr == ZFAT_SHOTS_NB ? val :
ti_zattr[ZIO_ATTR_TRIG_N_SHOTS].value;
size = ((pre_t + post_t) * ti->cset->ssize * nshot_t) * FA_NCHAN;
if (size >= FA_MAX_ACQ_BYTE) {
shot_size = ((pre_t + post_t + 1) * ti->cset->ssize) * FA_NCHAN;
if ( (shot_size * nshot_t) >= FA_MAX_ACQ_BYTE ) {
dev_err(&ti->head.dev, "Cannot acquire, dev memory overflow\n");
return -ENOMEM;
}
/* in case of multi shot, each shot cannot exceed the dpram size */
if ( (nshot_t > 1) &&
(shot_size >= FA_MAX_MSHOT_ACQ_BYTE) ) {
dev_err(&ti->head.dev, "Cannot acquire such amount of samples "
"(shot_size: %d pre-samp:%d post-samp:%d) in multi shot mode."
"dev memory overflow\n",
(int)shot_size, pre_t, post_t);
return -ENOMEM;
}
return 0;
}
......@@ -364,38 +374,51 @@ static inline struct fa_dev *get_zfadc(struct device *dev)
return NULL;
}
/* Hardware filed-based access */
static inline int zfa_hardware_write(struct fa_dev *fa,
enum zfadc_dregs_enum index,
uint32_t usr_val)
static inline uint32_t fa_readl(struct fa_dev *fa,
unsigned int base_off,
const struct zfa_field_desc *field)
{
uint32_t cur, val;
uint32_t cur;
if ((usr_val & (~zfad_regs[index].mask))) {
dev_info(&fa->fmc->dev, "value 0x%x must fit mask 0x%x\n",
usr_val, zfad_regs[index].mask);
return -EINVAL;
cur = fmc_readl(fa->fmc, base_off+field->offset);
if (field->is_bitfield) {
/* apply mask and shift right accordlying to the mask */
cur &= field->mask;
cur /= (field->mask & -(field->mask));
} else {
cur &= field->mask; /* bitwise and with the mask */
}
/* Read current register*/
cur = fmc_readl(fa->fmc, zfad_regs[index].addr);
val = zfa_set_field(&zfad_regs[index], cur, usr_val);
/* FIXME re-write usr_val when possible (zio need a patch) */
/* If the attribute has a valid address */
fmc_writel(fa->fmc, val, zfad_regs[index].addr);
return 0;
return cur;
}
static inline void zfa_hardware_read(struct fa_dev *fa,
enum zfadc_dregs_enum index,
uint32_t *usr_val)
static inline void fa_writel(struct fa_dev *fa,
unsigned int base_off,
const struct zfa_field_desc *field,
uint32_t usr_val)
{
uint32_t cur;
uint32_t cur, val;
/* Read current register*/
cur = fmc_readl(fa->fmc, zfad_regs[index].addr);
/* Return the value */
*usr_val = zfa_get_field(&zfad_regs[index], cur);
val = usr_val;
/* Read current register value first if it's a bitfield */
if (field->is_bitfield) {
cur = fmc_readl(fa->fmc, base_off+field->offset);
/* */
cur &= ~field->mask; /* clear bits according to the mask */
val = usr_val * (field->mask & -(field->mask));
val |= cur;
}
fmc_writel(fa->fmc, val, base_off+field->offset);
}
/* Global variable exported by fa-spec.c */
extern struct fa_carrier_op fa_spec_op;
/* Global variable exported by fa-svec.c */
extern struct fa_carrier_op fa_svec_op;
/* Global variable exported by fa-regfield.c */
extern const struct zfa_field_desc zfad_regs[];
/* Functions exported by fa-core.c */
extern int zfad_fsm_command(struct fa_dev *fa, uint32_t command);
extern int zfad_apply_user_offset(struct fa_dev *fa, struct zio_channel *chan,
......@@ -416,28 +439,32 @@ extern void fa_zio_exit(struct fa_dev *fa);
extern int fa_trig_init(void);
extern void fa_trig_exit(void);
/* Functions exported by fa-spec.c */
extern int fa_spec_init(void);
extern void fa_spec_exit(void);
/* Functions exported by fa-irq.c */
extern int zfad_dma_start(struct zio_cset *cset);
extern void zfad_dma_done(struct zio_cset *cset);
extern void zfad_dma_error(struct zio_cset *cset);
extern void zfat_irq_trg_fire(struct zio_cset *cset);
extern void zfat_irq_acq_end(struct zio_cset *cset);
extern int fa_setup_irqs(struct fa_dev *fa);
extern int fa_free_irqs(struct fa_dev *fa);
extern int fa_enable_irqs(struct fa_dev *fa);
extern int fa_disable_irqs(struct fa_dev *fa);
/* Functions exported by onewire.c */
extern int fa_onewire_init(struct fa_dev *fa);
extern void fa_onewire_exit(struct fa_dev *fa);
extern int fa_read_temp(struct fa_dev *fa, int verbose);
/* Functions exported by fa-irq.c */
extern void zfad_dma_start(struct zio_cset *cset);
extern void zfad_dma_done(struct zio_cset *cset);
extern void zfad_dma_error(struct zio_cset *cset);
extern void zfat_irq_acq_end(struct zio_cset *cset);
/* functions exported by spi.c */
extern int fa_spi_xfer(struct fa_dev *fa, int cs, int num_bits,
uint32_t tx, uint32_t *rx);
extern int fa_spi_init(struct fa_dev *fd);
extern void fa_spi_exit(struct fa_dev *fd);
/* function in fa-zio-drv.c */
extern int zfad_fsm_command(struct fa_dev *fa, uint32_t command);
/* fmc extended function */
signed long fmc_find_sdb_device_ext(struct sdb_array *tree,
uint64_t vid, uint32_t did, int index,
unsigned long *sz);
/* function exporetd by fa-calibration.c */
extern void fa_read_eeprom_calib(struct fa_dev *fa);
......
/*
* Some utility functions not supported in the current version of fmc-bus.
*
* Copyright (C) 2012-2013 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/fmc.h>
#include <linux/fmc-sdb.h>
#include <linux/err.h>
#include <asm/byteorder.h>
/* Finds index-th SDB device that matches (vid/did) pair. */
signed long fmc_find_sdb_device_ext(struct sdb_array *tree,
uint64_t vid, uint32_t did, int index,
unsigned long *sz)
{
signed long res = -ENODEV;
union sdb_record *r;
struct sdb_product *p;
struct sdb_component *c;
int i, n = tree->len;
uint64_t last, first;
int ci = 0;
/* FIXME: what if the first interconnect is not at zero? */
for (i = 0; i < n; i++) {
r = &tree->record[i];
c = &r->dev.sdb_component;
p = &c->product;
if (!IS_ERR(tree->subtree[i]))
res = fmc_find_sdb_device(tree->subtree[i],
vid, did, sz);
/* FIXME: this index SHOULD be recursive, too */
if (ci == index && res >= 0)
return res + tree->baseaddr;
if (r->empty.record_type != sdb_type_device)
continue;
if (__be64_to_cpu(p->vendor_id) != vid)
continue;
if (__be32_to_cpu(p->device_id) != did)
continue;
/* found */
last = __be64_to_cpu(c->addr_last);
first = __be64_to_cpu(c->addr_first);
if (sz)
*sz = (typeof(*sz)) (last + 1 - first);
if (ci == index)
return first + tree->baseaddr;
ci++;
}
return res;
}
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