Commit b39ea9b1 authored by Federico Vaga's avatar Federico Vaga

drv: remove carrier operations

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent f8dc04c1
......@@ -41,8 +41,3 @@ fmc-adc-100m14b4ch-y += fa-debug.o
fmc-adc-100m14b4ch-y += fa-dma.o
fmc-adc-100m14b4ch-y += onewire.o
fmc-adc-100m14b4ch-y += spi.o
fmc-adc-100m14b4ch-y += fa-spec-core.o
fmc-adc-100m14b4ch-y += fa-spec-regtable.o
fmc-adc-100m14b4ch-y += fa-spec-irq.o
fmc-adc-100m14b4ch-$(CONFIG_FMC_ADC_SVEC) += fa-svec-core.o
fmc-adc-100m14b4ch-$(CONFIG_FMC_ADC_SVEC) += fa-svec-regtable.o
......@@ -517,13 +517,11 @@ int fa_probe(struct platform_device *pdev)
case ADC_VER_SPEC:
memops.read = ioread32;
memops.write = iowrite32;
fa->carrier_op = &fa_spec_op;
fa->sg_alloc_table_from_pages = sg_alloc_table_from_pages;
break;
case ADC_VER_SVEC:
memops.read = ioread32be;
memops.write = iowrite32be;
fa->carrier_op = &fa_svec_op;
fa->sg_alloc_table_from_pages = sg_alloc_table_from_pages_no_squash;
break;
default:
......@@ -540,10 +538,6 @@ int fa_probe(struct platform_device *pdev)
fa->fa_spi_base = fa->fa_top_level + 0x1800;
fa->fa_utc_base = fa->fa_top_level + 0x1900;
err = fa->carrier_op->init(fa);
if (err < 0)
goto out;
/* init all subsystems */
for (i = 0, m = mods; i < ARRAY_SIZE(mods); i++, m++) {
dev_dbg(fa->msgdev, "Calling init for \"%s\"\n", m->name);
......@@ -588,8 +582,6 @@ int fa_remove(struct platform_device *pdev)
m->exit(fa);
}
fa->carrier_op->exit(fa);
return 0;
}
......
......@@ -121,9 +121,6 @@ int fa_setup_irqs(struct fa_dev *fa)
/* 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;
}
......@@ -136,10 +133,6 @@ int fa_free_irqs(struct fa_dev *fa)
*/
fa_disable_irqs(fa);
/* Release carrier IRQs (if any) */
if (fa->carrier_op->free_irqs)
fa->carrier_op->free_irqs(fa);
/* Release ADC IRQs */
free_irq(platform_get_irq(fa->pdev, ADC_IRQ_TRG), fa);
......@@ -153,9 +146,6 @@ int fa_enable_irqs(struct fa_dev *fa)
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;
}
......@@ -167,8 +157,6 @@ int fa_disable_irqs(struct fa_dev *fa)
&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;
}
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
*/
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include "fmc-adc-100m14b4cha.h"
#include "fa-spec.h"
static int fa_spec_init(struct fa_dev *fa)
{
struct resource *r;
struct fa_spec_data *cdata;
cdata = kzalloc(sizeof(struct fa_spec_data), GFP_KERNEL);
if (!cdata)
return -ENOMEM;
r = platform_get_resource(fa->pdev, IORESOURCE_MEM, ADC_CARR_DMA);
cdata->fa_dma_base = ioremap(r->start, resource_size(r));
cdata->fa_irq_dma_base = cdata->fa_dma_base + 0x0200;
dev_info(fa->msgdev,
"Spec Base addrs: irq_dmma: %p, dma_ctrl: %p\n",
cdata->fa_irq_dma_base, cdata->fa_dma_base);
/* 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(fa->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->msgdev, "%s: resetting ADC 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) */
/* FIXME find a way to get rid of fmc here
* This is used only by the SPEC design, is it not possible to avoid it
* and let the VHDL configure the GPIO?
*/
/* 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 resource *r;
int err;
r = platform_get_resource(fa->pdev, IORESOURCE_IRQ, ADC_IRQ_DMA);
err = request_any_context_irq(r->start, fa_spec_irq_handler, 0,
r->name, fa);
if (err < 0) {
dev_err(fa->msgdev, "can't request irq 0x%llx (error %i)\n",
r->start, err);
return err;
}
//fmc_gpio_config(fmc, fa_gpio_on, ARRAY_SIZE(fa_gpio_on));
dev_info(fa->msgdev, "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)
{
/* Release DMA IRQs */
free_irq(platform_get_irq(fa->pdev, ADC_IRQ_DMA), fa);
/* fmc_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 = {
.init = fa_spec_init,
.reset_core = fa_spec_reset,
.exit = fa_spec_exit,
.setup_irqs = fa_spec_setup_irqs,
.free_irqs = fa_spec_free_irqs,
.enable_irqs = fa_spec_enable_irqs,
.disable_irqs = fa_spec_disable_irqs,
.ack_irq = fa_spec_ack_irq,
};
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012-2019
* Author: Federico Vaga <federico.vaga@gmail.com>
*/
#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 "fmc-adc-100m14b4cha.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, uint32_t *irq_status)
{
struct fa_spec_data *cdata = fa->carrier_data;
/* Get current interrupts status */
*irq_status = fa_readl(fa, cdata->fa_irq_dma_base,
&fa_spec_regs[ZFA_IRQ_DMA_SRC]);
dev_dbg(fa->msgdev,
"core DMA: %p fired an interrupt. IRQ status register: 0x%x\n",
cdata->fa_irq_dma_base, *irq_status);
if (*irq_status)
/* Clear current interrupts status */
fa_writel(fa, cdata->fa_irq_dma_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, void *arg)
{
struct fa_dev *fa = arg;
struct zio_cset *cset = fa->zdev->cset;
uint32_t status;
/* irq to handle */
fa_get_irq_status(fa, &status);
if (!status)
return IRQ_NONE;
if (unlikely(!fa->n_shots || !cset->interleave->priv_d)) {
/*
* Mainly this may happen when you are playing with DMA with
* an user-space program or another driver. 99% of the time
* is for debugging purpose. So, if you are seriusly working
* with DMA with two different programs/drivers ... well *you*
* have a problem and this driver may crash badly.
*/
dev_err(fa->msgdev,
"No programmed shot, implies no DMA to perform\n");
goto out;
}
/* FIXME handle it better */
/* 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, FA100M14B4C_CMD_STOP); */
/* fa->last_irq_core_src = FA_SPEC_IRQ_SRC_NONE; */
/* goto out; */
/* } */
dev_dbg(fa->msgdev, "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)*/
/* FIXME */
/* fa->last_irq_core_src = irq_core_base; */
out:
/*
* DMA transaction is finished
* we can safely lower CSET_BUSY
*/
spin_lock(&cset->lock);
cset->flags &= ~ZIO_CSET_HW_BUSY;
spin_unlock(&cset->lock);
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},
};
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012-2019
*/
#ifndef __FA_SPEC_CORE_H__
#define __FA_SPEC_CORE_H__
#include <linux/scatterlist.h>
#include <linux/irqreturn.h>
#include "fmc-adc-100m14b4cha.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 gncore_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 */
void *fa_dma_base;
void *fa_irq_dma_base;
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__*/
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2012-2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "fmc-adc-100m14b4cha.h"
#include "fa-svec.h"
static int fa_svec_init(struct fa_dev *fa)
{
struct fa_svec_data *cdata;
struct resource *r;
cdata = kzalloc(sizeof(struct fa_svec_data), GFP_KERNEL);
if (!cdata)
return -ENOMEM;
r = platform_get_resource(fa->pdev, IORESOURCE_BUS, ADC_CARR_VME_ADDR);
cdata->vme_ddr_data = r->start;
cdata->fa_dma_ddr_addr = fa->fa_top_level + 0x2000;
/* register carrier data */
fa->carrier_data = cdata;
return 0;
}
static void fa_svec_exit(struct fa_dev *fa)
{
kfree(fa->carrier_data);
}
struct fa_carrier_op fa_svec_op = {
.init = fa_svec_init,
.exit = fa_svec_exit,
};
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012-2019
* Author: Federico Vaga <federico.vaga@gmail.com>
*/
#include "fa-svec.h"
/* fa svec specific registers field: offset - mask - isbitfield */
const struct zfa_field_desc fa_svec_regfield[] = {
[FA_DMA_DDR_ADDR] = {0x0000, 0x00FFFFFF, 0},
[FA_DMA_DDR_DATA] = {0x0000, 0x00FFFFFF, 0},
/* CSR */
[FA_CAR_FMC0_PRES] = {0x0004, 0x00000001, 1},
[FA_CAR_FMC1_PRES] = {0x0004, 0x00000002, 1},
[FA_CAR_SYS_PLL] = {0x0004, 0x00000004, 1},
[FA_CAR_DDR0_CAL] = {0x0004, 0x00000008, 1},
[FA_CAR_DDR1_CAL] = {0x0004, 0x00000010, 1},
[FA_CAR_FMC0_RES] = {0x000C, 0x00000001, 1},
[FA_CAR_FMC1_RES] = {0x000C, 0x00000002, 1},
};
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012-2019
*/
#ifndef __FA_SVEC_CORE_H__
#define __FA_SVEC_CORE_H__
#include <linux/irqreturn.h>
#include "fmc-adc-100m14b4cha.h"
#include "field-desc.h"
/* default spec gateware */
#define FA_GATEWARE_SVEC "fmc/svec-fmc-adc-100m14b.bin"
/* SPEC CSR */
enum fa_spec_regs_id {
/* DMA */
FA_DMA_DDR_ADDR = 0,
FA_DMA_DDR_DATA,
/* CSR */
FA_CAR_FMC0_PRES,
FA_CAR_FMC1_PRES,
FA_CAR_SYS_PLL,
FA_CAR_DDR0_CAL,
FA_CAR_DDR1_CAL,
FA_CAR_FMC0_RES,
FA_CAR_FMC1_RES,
};
/* specific carrier data */
struct fa_svec_data {
/* DMA attributes */
unsigned long vme_ddr_data; /* offset */
void *fa_dma_ddr_addr; /* offset */
unsigned int n_dma_err; /* statistics */
};
/* svec specific hardware registers */
extern const struct zfa_field_desc fa_svec_regfield[];
/* svec irq handler */
extern irqreturn_t fa_svec_irq_handler(int irq, void *dev_id);
/* functions exported by fa-svec-dma.c */
extern int fa_svec_dma_start(struct zio_cset *cset);
extern void fa_svec_dma_done(struct zio_cset *cset);
extern void fa_svec_dma_error(struct zio_cset *cset);
#endif /* __FA_SVEC_CORE_H__*/
......@@ -375,17 +375,6 @@ enum fa_irq_adc {
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);
};
/*
* fa_dev: is the descriptor of the FMC ADC mezzanine
......@@ -424,10 +413,6 @@ struct fa_dev {
struct zio_dma_sgt *zdma;
struct sg_table sgt;
/* 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;
/*
......@@ -589,12 +574,6 @@ extern struct bin_attribute dev_attr_calibration;
/* Global variable exported by fa-core.c */
extern struct workqueue_struct *fa_workqueue;
/* 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[];
......
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