Commit 3ef6cadd authored by Federico Vaga's avatar Federico Vaga

drv: convert to platform

NOTE 1
Since we do not have any mechanism to set the parent device
for a platform one (we do not have device tree), we can't set
the DMA mask.

Perhaps what we should do is to have the actual dma engine to set
this value. Then the problem will move to the DMA engine: how to get
its parent device
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 8102b028
[submodule "zio"]
path = zio
url = git://ohwr.org/misc/zio.git
[submodule "fmc-bus"]
path = fmc-bus
url = git://ohwr.org/fmc-projects/fmc-bus.git
......@@ -6,7 +6,6 @@ REPO_PARENT ?= $(CURDIR)/..
all: kernel tools
FMC_BUS ?= fmc-bus
ZIO ?= zio
SVEC_SW ?= svec-sw
VMEBUS ?= $(REPO_PARENT)/vmebridge
......@@ -45,7 +44,7 @@ $(DIRS):
$(MAKE) -C $@ $(TARGET)
SUBMOD = $(FMC_BUS_ABS) $(ZIO_ABS)
SUBMOD = $(ZIO_ABS)
prereq_install_warn:
@test -f .prereq_installed || \
......@@ -55,13 +54,8 @@ prereq_install:
for d in $(SUBMOD); do $(MAKE) -C $$d modules_install || exit 1; done
touch .prereq_installed
$(FMC_BUS_ABS): fmc-bus-init_repo
$(ZIO_ABS): zio-init_repo
# init submodule if missing
fmc-bus-init_repo:
@test -d $(FMC_BUS_ABS)/doc || ( echo "Checking out submodule $(FMC_BUS_ABS)" && git submodule update --init $(FMC_BUS_ABS) )
# init submodule if missing
zio-init_repo:
@test -d $(ZIO_ABS)/doc || ( echo "Checking out submodule $(ZIO_ABS)" && git submodule update --init $(ZIO_ABS) )
fmc-bus @ eb86efcf
Subproject commit eb86efcf4e19a31a25471c4ddf3fd9fef8df02ec
......@@ -2,9 +2,7 @@ CONFIG_FMC_ADC_SVEC ?= CONFIG_VME
SVEC_SW_EXTRA_SYMBOLS-$(CONFIG_FMC_ADC_SVEC) := $(VMEBUS_ABS)/driver/Module.symvers
KBUILD_EXTRA_SYMBOLS := \
$(ZIO_ABS)/Module.symvers \
$(FMC_BUS_ABS)/kernel/Module.symvers \
$(SVEC_SW_EXTRA_SYMBOLS-y)
$(ZIO_ABS)/Module.symvers
# add versions of supermodule. It is useful when fine-delay-sw is included as sub-module
# of a bigger project that we want to track
......@@ -14,7 +12,6 @@ SUBMODULE_VERSIONS-y += MODULE_INFO(version_$(CONFIG_SUPER_REPO),\"$(CONFIG_SUPE
endif
endif
# add versions of used submodules
SUBMODULE_VERSIONS-y += MODULE_INFO(version_fmc_bus,\"$(FMC_BUS_VERSION)\");
SUBMODULE_VERSIONS-y += MODULE_INFO(version_zio,\"$(ZIO_VERSION)\");
ccflags-y += -DADDITIONAL_VERSIONS="$(SUBMODULE_VERSIONS-y)"
......@@ -25,12 +22,11 @@ LINUXINCLUDE := -I$(FMC_BUS_ABS)/kernel/include $(LINUXINCLUDE)
ccflags-y += -DGIT_VERSION=\"$(GIT_VERSION)\" \
-I$(ZIO_ABS)/include \
-I $(VMEBUS_ABS)/driver \
-I$(src)
ccflags-$(CONFIG_FMC_ADC_SVEC) += -I$(SVEC_SW_ABS)/kernel
ccflags-$(CONFIG_FMC_ADC_SVEC) += -I$(VMEBUS_ABS)/include
ccflags-$(CONFIG_FMC_ADC_DEBUG) += -DDEBUG
ccflags-$(CONFIG_FMC_ADC_SVEC) += -DCONFIG_FMC_ADC_SVEC
# Extract ZIO minimum compatible version
ccflags-y += -D__ZIO_MIN_MAJOR_VERSION=$(shell echo $(ZIO_VERSION) | cut -d '-' -f 2 | cut -d '.' -f 1; )
......@@ -48,7 +44,6 @@ fmc-adc-100m14b-y += fa-irq.o
fmc-adc-100m14b-y += fa-debug.o
fmc-adc-100m14b-y += onewire.o
fmc-adc-100m14b-y += spi.o
fmc-adc-100m14b-y += fmc-util.o
fmc-adc-100m14b-y += fa-spec-core.o
fmc-adc-100m14b-y += fa-spec-regtable.o
fmc-adc-100m14b-y += fa-spec-dma.o
......
......@@ -87,9 +87,10 @@ static void fa_endian_calib(struct fa_calib *calib)
void fa_read_eeprom_calib(struct fa_dev *fa)
{
/* Retrieve calibration data from the eeprom, then verify it */
memcpy(&fa->calib, fa->fmc->eeprom + FA_CAL_OFFSET, sizeof(fa->calib));
memcpy(&fa->calib, &fa_identity_calib, sizeof(fa->calib));
fa_endian_calib(&fa->calib);
fa_verify_calib(&fa->fmc->dev, &fa->calib, &fa_identity_calib);
fa_verify_calib(&fa->pdev->dev, &fa->calib, &fa_identity_calib);
dev_info(fa->msgdev, "%s succeeds.\n", __func__);
}
......@@ -99,8 +100,8 @@ static ssize_t fa_write_eeprom(struct file *file, struct kobject *kobj,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct fmc_device *fmc = to_fmc_device(dev);
struct fa_dev *fa = fmc_get_drvdata(fmc);
struct platform_device *pdev = to_platform_device(dev);
struct fa_dev *fa = platform_get_drvdata(pdev);
if (off >= (4 * 1024)) {
/*
......@@ -124,7 +125,7 @@ static ssize_t fa_write_eeprom(struct file *file, struct kobject *kobj,
struct bin_attribute dev_attr_eeprom = {
.attr = {
.name = "eeprom_config", /* TODO change to eeprom when platform */
.name = "eeprom",
.mode = S_IWUSR,
},
.size = (8 * 1024), /* 8 KiB */
......
......@@ -14,16 +14,18 @@
#include "fmc-adc-100m14b4cha.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_enable_test_data_fpga;
module_param_named(enable_test_data_fpga, fa_enable_test_data_fpga, int, 0444);
int fa_enable_test_data_adc = 0;
module_param_named(enable_test_data_adc, fa_enable_test_data_adc, int, 0444);
struct fa_memory_ops memops = {
.read = NULL,
.write = NULL,
};
static const int zfad_hw_range[] = {
[FA100M14B4C_RANGE_10V_CAL] = 0x44,
[FA100M14B4C_RANGE_1V_CAL] = 0x40,
......@@ -336,66 +338,17 @@ int zfad_fsm_command(struct fa_dev *fa, uint32_t 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;
int ret;
ret = fmc_scan_sdb_tree(fmc, 0);
if (ret == -EBUSY) {
/* Not a problem, it's already there. We assume that
it's the correct one */
ret = 0;
}
if (ret < 0) {
dev_err(fa->msgdev,
"%s: no SDB in the bitstream."
"Are you sure you've provided the correct one?\n",
KBUILD_MODNAME);
return ret;
}
/* 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 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(fa->msgdev, "32-bit DMA addressing not available\n");
return -EINVAL;
}
}
/* Retrieve calibration from the eeprom and validate*/
fa_read_eeprom_calib(fa);
//fa_read_eeprom_calib(fa);
fa->mshot_max_samples = fa_readl(fa, fa->fa_adc_csr_base,
&zfad_regs[ZFA_MULT_MAX_SAMP]);
......@@ -459,87 +412,128 @@ static struct fa_modlist mods[] = {
{"debug", fa_debug_init, fa_debug_exit},
};
static int fa_resource_validation(struct platform_device *pdev)
{
struct resource *r;
r = platform_get_resource(pdev, IORESOURCE_IRQ, ADC_IRQ_TRG);
if (!r) {
dev_err(&pdev->dev,
"The ADC needs an interrupt number for the IRQ\n");
return -ENXIO;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, ADC_MEM_BASE);
if (!r) {
dev_err(&pdev->dev,
"The ADC needs base address\n");
return -ENXIO;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, ADC_CARR_MEM_BASE);
if (!r) {
dev_err(&pdev->dev,
"The ADC needs the carrier base address\n");
return -ENXIO;
}
r = platform_get_resource(pdev, IORESOURCE_BUS, ADC_BUS_FMC_SLOT);
if (!r) {
dev_err(&pdev->dev,
"The ADC needs to be assigned to an FMC slot\n");
return -ENXIO;
}
/* Special Configurations */
switch (pdev->id_entry->driver_data) {
case ADC_VER_SPEC:
r = platform_get_resource(pdev, IORESOURCE_IRQ, ADC_IRQ_DMA);
if (!r) {
dev_err(&pdev->dev,
"The ADC needs an interrupt number for the DMA\n");
return -ENXIO;
}
r = platform_get_resource(pdev, IORESOURCE_MEM, ADC_CARR_DMA);
if (!r) {
dev_err(&pdev->dev,
"The ADC needs address to SPEC DMA engine\n");
return -ENXIO;
}
break;
case ADC_VER_SVEC:
r = platform_get_resource(pdev, IORESOURCE_BUS,
ADC_CARR_VME_ADDR);
if (!r) {
dev_err(&pdev->dev,
"The ADC needs a DMA ADDR register\n");
return -ENXIO;
}
break;
default:
break;
}
return 0;
}
/* probe and remove are called by fa-spec.c */
int fa_probe(struct fmc_device *fmc)
int fa_probe(struct platform_device *pdev)
{
struct fa_modlist *m = NULL;
struct fa_dev *fa;
struct resource *r;
int err, i = 0;
char *fwname;
/* Validate the new FMC device */
i = fmc_validate(fmc, &fa_dev_drv);
if (i < 0) {
dev_info(&fmc->dev, "not using \"%s\" according to "
"modparam\n", KBUILD_MODNAME);
return -ENODEV;
}
err = fa_resource_validation(pdev);
if (err)
return err;
/* Driver data */
fa = devm_kzalloc(&fmc->dev, sizeof(struct fa_dev), GFP_KERNEL);
fa = devm_kzalloc(&pdev->dev, sizeof(struct fa_dev), GFP_KERNEL);
if (!fa)
return -ENOMEM;
fmc_set_drvdata(fmc, fa);
fa->fmc = fmc;
fa->msgdev = &fa->fmc->dev;
/* apply carrier-specific hacks and workarounds */
fa->carrier_op = NULL;
if (!strcmp(fmc->carrier_name, "SPEC")) {
platform_set_drvdata(pdev, fa);
fa->pdev = pdev;
fa->msgdev = &fa->pdev->dev;
/* Assign IO operation */
switch (pdev->id_entry->driver_data) {
case ADC_VER_SPEC:
memops.read = ioread32;
memops.write = iowrite32;
fa->carrier_op = &fa_spec_op;
} else if (!strcmp(fmc->carrier_name, "SVEC")) {
#ifdef CONFIG_FMC_ADC_SVEC
break;
case ADC_VER_SVEC:
memops.read = ioread32be;
memops.write = iowrite32be;
fa->carrier_op = &fa_svec_op;
#endif
break;
default:
dev_err(fa->msgdev, "Unknow version %lu\n",
pdev->id_entry->driver_data);
return -EINVAL;
}
/*
* Check if carrier operations exists. Otherwise it means that the
* driver was compiled without enable any carrier, so it cannot work
*/
if (!fa->carrier_op) {
dev_err(fa->msgdev,
"This binary doesn't support the '%s' carrier\n",
fmc->carrier_name);
return -ENODEV;
}
fa_read_eeprom_calib(fa);
/*
* If the carrier is still using the golden bitstream or the user is
* asking for a particular one, then program our bistream, otherwise
* we already have our bitstream
*/
if (fmc->flags & FMC_DEVICE_HAS_GOLDEN || fa_dev_drv.gw_n) {
if (fa_dev_drv.gw_n)
fwname = ""; /* reprogram will pick from module parameter */
else
fwname = fa->carrier_op->get_gwname();
/* We first write a new binary (and lm32) within the carrier */
err = fmc_reprogram(fmc, &fa_dev_drv, fwname, 0x0);
if (err) {
dev_err(fa->msgdev, "write firmware \"%s\": error %i\n",
fwname, err);
goto out;
}
} else {
dev_info(fa->msgdev,
"Gateware already there. Set the \"gateware\" parameter to overwrite the current gateware\n");
}
r = platform_get_resource(pdev, IORESOURCE_MEM, ADC_MEM_BASE);
fa->fa_top_level = ioremap(r->start, resource_size(r));
fa->fa_adc_csr_base = fa->fa_top_level + 0x1000;
fa->fa_irq_adc_base = fa->fa_top_level + 0x1500;
fa->fa_ow_base = fa->fa_top_level + 0x1700;
fa->fa_spi_base = fa->fa_top_level + 0x1800;
fa->fa_utc_base = fa->fa_top_level + 0x1900;
/* Extract whisbone core base address fron SDB */
err = __fa_sdb_get_device(fa);
if (err < 0)
goto out;
r = platform_get_resource(fa->pdev, IORESOURCE_MEM, ADC_CARR_MEM_BASE);
fa->fa_carrier_csr_base = ioremap(r->start, resource_size(r));
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++) {
dev_dbg(fa->msgdev, "Calling init for \"%s\"\n", m->name);
......@@ -555,8 +549,7 @@ int fa_probe(struct fmc_device *fmc)
if (err < 0)
goto out;
err = device_create_bin_file(&fa->fmc->dev, &dev_attr_eeprom);
err = device_create_bin_file(&fa->pdev->dev, &dev_attr_eeprom);
if (err)
goto out_bin;
......@@ -564,16 +557,10 @@ int fa_probe(struct fmc_device *fmc)
if (err < 0)
goto out_irq;
/* Pin the carrier */
if (!try_module_get(fmc->owner))
goto out_mod;
return 0;
out_mod:
fa_free_irqs(fa);
out_irq:
device_remove_bin_file(&fa->fmc->dev, &dev_attr_eeprom);
device_remove_bin_file(&fa->pdev->dev, &dev_attr_eeprom);
out_bin:
out:
while (--m, --i >= 0)
......@@ -582,14 +569,14 @@ out:
return err;
}
int fa_remove(struct fmc_device *fmc)
int fa_remove(struct platform_device *pdev)
{
struct fa_dev *fa = fmc_get_drvdata(fmc);
struct fa_dev *fa = platform_get_drvdata(pdev);
struct fa_modlist *m;
int i = ARRAY_SIZE(mods);
fa_free_irqs(fa);
device_remove_bin_file(&fa->fmc->dev, &dev_attr_eeprom);
device_remove_bin_file(&fa->pdev->dev, &dev_attr_eeprom);
flush_workqueue(fa_workqueue);
while (--i >= 0) {
......@@ -600,27 +587,29 @@ int fa_remove(struct fmc_device *fmc)
fa->carrier_op->exit(fa);
/* Release the carrier */
module_put(fmc->owner);
return 0;
}
static struct fmc_fru_id fa_fru_id[] = {
static const struct platform_device_id fa_id[] = {
{
.product_name = "FmcAdc100m14b4cha",
.name = "adc-100m-spec",
.driver_data = ADC_VER_SPEC,
}, {
.name = "adc-100m-svec",
.driver_data = ADC_VER_SVEC,
},
/* TODO we should support different version */
};
static struct fmc_driver fa_dev_drv = {
.version = FMC_VERSION,
.driver.name = KBUILD_MODNAME,
static struct platform_driver fa_dev_drv = {
.driver = {
.name = KBUILD_MODNAME,
},
.probe = fa_probe,
.remove = fa_remove,
.id_table = {
.fru_id = fa_fru_id,
.fru_id_nr = ARRAY_SIZE(fa_fru_id),
},
.id_table = fa_id,
};
static int fa_init(void)
......@@ -648,7 +637,7 @@ static int fa_init(void)
goto out2;
/* Finally the fmc driver, whose probe instantiates zio devices */
ret = fmc_driver_register(&fa_dev_drv);
ret = platform_driver_register(&fa_dev_drv);
if (ret)
goto out3;
......@@ -666,7 +655,7 @@ out1:
static void fa_exit(void)
{
fmc_driver_unregister(&fa_dev_drv);
platform_driver_unregister(&fa_dev_drv);
fa_zio_unregister();
fa_trig_exit();
if (fa_workqueue != NULL)
......
......@@ -12,6 +12,7 @@
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include "fmc-adc-100m14b4cha.h"
#include "fa-spec.h"
......@@ -272,9 +273,6 @@ end:
dev_dbg(fa->msgdev, "Automatic start\n");
zfad_fsm_command(fa, FA100M14B4C_CMD_START);
}
/* ack the irq */
fmc_irq_ack(fa->fmc);
}
/*
......@@ -285,25 +283,23 @@ end:
* 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)
static void fa_get_irq_status(struct fa_dev *fa, uint32_t *irq_status)
{
/* Get current interrupts status */
*irq_status = fa_readl(fa, irq_core_base, &zfad_regs[ZFA_IRQ_ADC_SRC]);
*irq_status = fa_readl(fa, fa->fa_irq_adc_base, &zfad_regs[ZFA_IRQ_ADC_SRC]);
dev_dbg(fa->msgdev,
"IRQ 0x%x fired an interrupt. IRQ status register: 0x%x\n",
irq_core_base, *irq_status);
"IRQ fired an interrupt. IRQ status register: 0x%x\n",
*irq_status);
if (*irq_status)
/* Clear current interrupts status */
fa_writel(fa, irq_core_base, &zfad_regs[ZFA_IRQ_ADC_SRC],
fa_writel(fa, fa->fa_irq_adc_base, &zfad_regs[ZFA_IRQ_ADC_SRC],
*irq_status);
}
/*
* fa_irq_handler
* @irq:
* @ptr: pointer to fmc_device
* @arg: pointer to fa_dev
*
* The ADC svec firmware fires interrupt from a single wishbone core
* and throught the VIC ACQ_END and TRIG events. Note about "TRIG"
......@@ -315,22 +311,20 @@ static void fa_get_irq_status(struct fa_dev *fa, int irq_core_base,
* 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)
irqreturn_t fa_irq_handler(int irq, void *arg)
{
struct fmc_device *fmc = dev_id;
struct fa_dev *fa = fmc_get_drvdata(fmc);
struct fa_dev *fa = arg;
struct zio_cset *cset = fa->zdev->cset;
uint32_t status;
unsigned long flags;
struct zfad_block *zfad_block;
/* irq to handle */
fa_get_irq_status(fa, irq_core_base, &status);
fa_get_irq_status(fa, &status);
if (!status)
return IRQ_NONE; /* No interrupt fired by this mezzanine */
dev_dbg(fa->msgdev, "Handle ADC interrupts fmc slot: %d\n",
fmc->slot_id);
dev_dbg(fa->msgdev, "Handle ADC interrupts\n");
if (status & FA_IRQ_ADC_ACQ_END) {
/*
......@@ -353,14 +347,12 @@ irqreturn_t fa_irq_handler(int irq_core_base, void *dev_id)
queue_work(fa_workqueue, &fa->irq_work);
/* register the core firing the IRQ in order to */
/* check right IRQ seq.: ACQ_END followed by DMA_END */
fa->last_irq_core_src = irq_core_base;
} else /* current Acquiistion has been stopped */
fmc_irq_ack(fmc);
fa->last_irq_core_src = irq;
}
} else { /* unexpected interrupt we have to ack anyway */
dev_err(fa->msgdev,
"%s unexpected interrupt 0x%x\n",
__func__, status);
fmc_irq_ack(fmc);
}
return IRQ_HANDLED;
......@@ -369,31 +361,18 @@ irqreturn_t fa_irq_handler(int irq_core_base, void *dev_id)
int fa_setup_irqs(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
struct resource *r;
int err;
/* Request IRQ */
dev_dbg(fa->msgdev, "%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);
/* 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_irq_request(fmc, fa_irq_handler,
"fmc-adc-100m14b",
0 /*VIC is used */);
if (err) {
dev_err(fa->msgdev, "can't request irq %i (error %i)\n",
fa->fmc->irq, err);
dev_dbg(fa->msgdev, "Request irq\n");
r = platform_get_resource(fa->pdev, IORESOURCE_IRQ, ADC_IRQ_TRG);
err = request_any_context_irq(r->start, fa_irq_handler, 0,
r->name, fa);
if (err < 0) {
dev_err(fa->msgdev, "can't request irq %lli (error %i)\n",
r->start, err);
return err;
}
/* workqueue is required to execute DMA transaction */
......@@ -410,8 +389,6 @@ int fa_setup_irqs(struct fa_dev *fa)
int fa_free_irqs(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
/*
* When we unload the driver the FPGA is still running so it may
* rises interrupts. Disable IRQs in order to prevent spurious
......@@ -424,16 +401,14 @@ int fa_free_irqs(struct fa_dev *fa)
fa->carrier_op->free_irqs(fa);
/* Release ADC IRQs */
fmc->irq = fa->fa_irq_adc_base;
fmc_irq_free(fmc);
free_irq(platform_get_irq(fa->pdev, ADC_IRQ_TRG), fa);
return 0;
}
int fa_enable_irqs(struct fa_dev *fa)
{
dev_dbg(fa->msgdev, "%s Enable interrupts fmc slot:%d\n",
__func__, fa->fmc->slot_id);
dev_dbg(fa->msgdev, "Enable interrupts\n");
fa_writel(fa, fa->fa_irq_adc_base,
&zfad_regs[ZFA_IRQ_ADC_ENABLE_MASK],
......@@ -446,8 +421,7 @@ int fa_enable_irqs(struct fa_dev *fa)
int fa_disable_irqs(struct fa_dev *fa)
{
dev_dbg(fa->msgdev, "%s Disable interrupts fmc slot:%d\n",
__func__, fa->fmc->slot_id);
dev_dbg(fa->msgdev, "Disable interrupts\n");
fa_writel(fa, fa->fa_irq_adc_base,
&zfad_regs[ZFA_IRQ_ADC_DISABLE_MASK],
......
......@@ -14,31 +14,22 @@
#include "fmc-adc-100m14b4cha.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 resource *r;
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);
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:0x%x, dma_ctrl:0x%x, csr:0x%x\n",
"Spec Base addrs: irq_dmma: %p, dma_ctrl: %p, csr: %p\n",
cdata->fa_irq_dma_base, cdata->fa_dma_base,
fa->fa_carrier_csr_base);
......@@ -97,42 +88,40 @@ static void fa_spec_exit(struct fa_dev *fa)
}
/* 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,
}
};
/* 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 fmc_device *fmc = fa->fmc;
struct fa_spec_data *spec_data = fa->carrier_data;
struct resource *r;
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_irq_request(fmc, fa_spec_irq_handler,
"fmc-adc-100m14b", 0);
if (err) {
dev_err(fa->msgdev, "can't request irq 0x%x (error %i)\n",
fmc->irq, 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));
//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 */
......@@ -143,14 +132,10 @@ static int fa_spec_setup_irqs(struct fa_dev *fa)
static int fa_spec_free_irqs(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
struct fa_spec_data *spec_data = fa->carrier_data;
/* Release DMA IRQs */
fmc->irq = spec_data->fa_irq_dma_base;
fmc_irq_free(fmc);
free_irq(platform_get_irq(fa->pdev, ADC_IRQ_DMA), fa);
fmc_gpio_config(fmc, fa_gpio_off, ARRAY_SIZE(fa_gpio_off));
/* fmc_gpio_config(fmc, fa_gpio_off, ARRAY_SIZE(fa_gpio_off)); */
return 0;
}
......@@ -183,7 +168,6 @@ static int fa_spec_ack_irq(struct fa_dev *fa, int irq_id)
}
struct fa_carrier_op fa_spec_op = {
.get_gwname = fa_spec_get_gwname,
.init = fa_spec_init,
.reset_core = fa_spec_reset,
.exit = fa_spec_exit,
......
......@@ -95,7 +95,7 @@ int fa_spec_dma_start(struct zio_cset *cset)
for (i = 0; i < fa->n_shots; ++i)
blocks[i] = zfad_block[i].block;
fa->zdma = zio_dma_alloc_sg(interleave, fa->fmc->hwdev, blocks,
fa->zdma = zio_dma_alloc_sg(interleave, &fa->pdev->dev, blocks,
fa->n_shots, GFP_ATOMIC);
if (IS_ERR(fa->zdma))
return PTR_ERR(fa->zdma);
......
......@@ -26,18 +26,20 @@
* 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)
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, irq_core_base,
*irq_status = fa_readl(fa, cdata->fa_irq_dma_base,
&fa_spec_regs[ZFA_IRQ_DMA_SRC]);
dev_dbg(fa->msgdev,
"core DMA: 0x%x fired an interrupt. IRQ status register: 0x%x\n",
irq_core_base, *irq_status);
"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, irq_core_base,
fa_writel(fa, cdata->fa_irq_dma_base,
&fa_spec_regs[ZFA_IRQ_DMA_SRC], *irq_status);
}
......@@ -56,15 +58,14 @@ static void fa_get_irq_status(struct fa_dev *fa, int irq_core_base,
* 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)
irqreturn_t fa_spec_irq_handler(int irq, void *arg)
{
struct fmc_device *fmc = ptr;
struct fa_dev *fa = fmc_get_drvdata(fmc);
struct fa_dev *fa = arg;
struct zio_cset *cset = fa->zdev->cset;
uint32_t status;
/* irq to handle */
fa_get_irq_status(fa, irq_core_base, &status);
fa_get_irq_status(fa, &status);
if (!status)
return IRQ_NONE;
......@@ -82,15 +83,16 @@ irqreturn_t fa_spec_irq_handler(int irq_core_base, void *ptr)
goto out;
}
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;
}
/* 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");
......@@ -101,7 +103,8 @@ irqreturn_t fa_spec_irq_handler(int irq_core_base, void *ptr)
/* 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;
/* FIXME */
/* fa->last_irq_core_src = irq_core_base; */
out:
/*
......@@ -112,8 +115,5 @@ out:
cset->flags &= ~ZIO_CSET_HW_BUSY;
spin_unlock(&cset->lock);
/* ack the irq */
fmc_irq_ack(fa->fmc);
return IRQ_HANDLED;
}
......@@ -87,8 +87,8 @@ enum fa_spec_irq {
/* specific carrier data */
struct fa_spec_data {
/* DMA attributes */
unsigned int fa_dma_base;
unsigned int fa_irq_dma_base;
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 */
......
......@@ -11,51 +11,44 @@
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <svec.h>
#include "fmc-adc-100m14b4cha.h"
#include "fa-svec.h"
static char *fa_svec_get_gwname(void)
{
return FA_GATEWARE_SVEC;
}
static int fa_svec_init(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
struct fa_svec_data *cdata;
struct svec_dev *svec = fmc->carrier_data;
struct resource *r;
unsigned int res_i;
cdata = kzalloc(sizeof(struct fa_svec_data), GFP_KERNEL);
if (!cdata)
return -ENOMEM;
cdata->vme_base = svec->cfg_cur.vme_base;
fa->fa_carrier_csr_base = fmc_find_sdb_device(fmc->sdb, 0xce42,
0x6603, NULL);
cdata->fa_dma_ddr_addr = fmc_find_sdb_device_ext(fmc->sdb, 0xce42,
0x10006611,
fmc->slot_id, NULL);
cdata->fa_dma_ddr_data = fmc_find_sdb_device_ext(fmc->sdb, 0xce42,
0x10006610,
fmc->slot_id, NULL);
r = platform_get_resource(fa->pdev, IORESOURCE_BUS, ADC_CARR_VME_ADDR);
cdata->vme_ddr_data = r->start;
r = platform_get_resource(fa->pdev, IORESOURCE_BUS, ADC_BUS_FMC_SLOT);
switch(r->start) {
case 1:
res_i = FA_CAR_FMC0_RES;
break;
case 2:
res_i = FA_CAR_FMC1_RES;
break;
default:
return -EINVAL;
}
cdata->fa_dma_ddr_addr = fa->fa_top_level + 0x2000;
/* Reset the FMC slot*/
fa_writel(fa, fa->fa_carrier_csr_base,
&fa_svec_regfield[FA_CAR_FMC0_RES + fmc->slot_id], 1);
fa_writel(fa, fa->fa_carrier_csr_base, &fa_svec_regfield[res_i], 1);
mdelay(50);
fa_writel(fa, fa->fa_carrier_csr_base,
&fa_svec_regfield[FA_CAR_FMC0_RES + fmc->slot_id], 0);
fa_writel(fa, fa->fa_carrier_csr_base, &fa_svec_regfield[res_i], 0);
mdelay(50);
/* register carrier data */
fa->carrier_data = cdata;
return 0;
}
static int fa_svec_reset(struct fa_dev *fa)
{
return 0;
}
......@@ -65,9 +58,7 @@ static void fa_svec_exit(struct fa_dev *fa)
}
struct fa_carrier_op fa_svec_op = {
.get_gwname = fa_svec_get_gwname,
.init = fa_svec_init,
.reset_core = fa_svec_reset,
.exit = fa_svec_exit,
.dma_start = fa_svec_dma_start,
.dma_done = fa_svec_dma_done,
......
......@@ -87,9 +87,6 @@ int fa_svec_dma_start(struct zio_cset *cset)
struct zfad_block *fa_dma_block = interleave->priv_d;
int i;
struct vme_dma desc; /* Vme driver DMA structure */
unsigned long vme_addr;
vme_addr = svec_data->vme_base + svec_data->fa_dma_ddr_data;
/*
* write the data address in the ddr_addr register: this
......@@ -101,14 +98,18 @@ int fa_svec_dma_start(struct zio_cset *cset)
fa_writel(fa, svec_data->fa_dma_ddr_addr,
&fa_svec_regfield[FA_DMA_DDR_ADDR],
fa_dma_block[0].dev_mem_off/4);
pr_info("%s:%d 0x%x\n", __func__, __LINE__,
fa_dma_block[0].dev_mem_off/4);
/* Execute DMA shot by shot */
for (i = 0; i < fa->n_shots; ++i) {
dev_dbg(fa->msgdev,
dev_info(fa->msgdev,
"configure DMA descriptor shot %d "
"vme addr: 0x%llx destination address: 0x%p len: %d\n",
i, (long long)vme_addr, fa_dma_block[i].block->data,
i, (long long)svec_data->vme_ddr_data,
fa_dma_block[i].block->data,
(int)fa_dma_block[i].block->datalen);
build_dma_desc(&desc, vme_addr,
memset(fa_dma_block[i].block->data, 5, fa_dma_block[i].block->datalen);
build_dma_desc(&desc, svec_data->vme_ddr_data,
fa_dma_block[i].block->data,
fa_dma_block[i].block->datalen);
......
......@@ -34,9 +34,8 @@ enum fa_spec_regs_id {
/* specific carrier data */
struct fa_svec_data {
/* DMA attributes */
unsigned long vme_base;
unsigned int fa_dma_ddr_data; /* offset */
unsigned int fa_dma_ddr_addr; /* offset */
unsigned long vme_ddr_data; /* offset */
void *fa_dma_ddr_addr; /* offset */
unsigned int n_dma_err; /* statistics */
};
......
......@@ -170,7 +170,7 @@ static int zfad_conf_set(struct device *dev, struct zio_attribute *zattr,
uint32_t usr_val)
{
struct fa_dev *fa = get_zfadc(dev);
unsigned int baseoff = fa->fa_adc_csr_base;
void *baseoff = fa->fa_adc_csr_base;
struct zio_channel *chan;
int i, range, err = 0, reg_index;
......@@ -323,7 +323,7 @@ static int zfad_info_get(struct device *dev, struct zio_attribute *zattr,
uint32_t *usr_val)
{
struct fa_dev *fa = get_zfadc(dev);
unsigned int baseoff = fa->fa_adc_csr_base;
void *baseoff = fa->fa_adc_csr_base;
int i, reg_index;
i = FA100M14B4C_NCHAN;
......@@ -672,7 +672,7 @@ int fa_zio_init(struct fa_dev *fa)
/* Register the hardware zio_device */
err = zio_register_device(fa->hwzdev, "adc-100m14b",
fa->fmc->device_id);
fa->pdev->id);
if (err) {
dev_err(fa->msgdev, "Cannot register ZIO device fmc-adc-100m14b\n");
zio_free_device(fa->hwzdev);
......
......@@ -30,6 +30,10 @@
#define FA100M14B4C_TRG_POL_CH4 FA100M14B4C_TRG_SRC_CH4
#define FA100M14B4C_TRG_POL_CHx(_x) (FA100M14B4C_TRG_POL_CH1 << ((_x) - 1))
enum fa_versions {
ADC_VER_SPEC = 0,
ADC_VER_SVEC,
};
/*
* Trigger Extended Attribute Enumeration
......@@ -133,9 +137,8 @@ enum fa100m14b4c_fsm_state {
#include <linux/scatterlist.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
#include <linux/fmc.h>
#include <linux/fmc-sdb.h>
#include <linux/zio.h>
#include <linux/zio-dma.h>
#include <linux/zio-sysfs.h>
......@@ -146,6 +149,29 @@ enum fa100m14b4c_fsm_state {
extern int fa_enable_test_data_adc;
enum fa_irq_resource {
ADC_IRQ_TRG = 0,
ADC_IRQ_DMA,
};
enum fa_mem_resource {
ADC_MEM_BASE = 0,
ADC_CARR_MEM_BASE,
ADC_CARR_DMA, /* SPEC only, remove it when we support DMA engine */
};
enum fa_bus_resource {
ADC_BUS_FMC_SLOT = 0,
ADC_CARR_VME_ADDR,
};
struct fa_memory_ops {
u32 (*read)(void *addr);
void (*write)(u32 value, void *addr);
};
extern struct fa_memory_ops memops;
/*
* 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
......@@ -364,7 +390,7 @@ struct fa_calib {
/*
* fa_dev: is the descriptor of the FMC ADC mezzanine
*
* @fmc: the pointer to the fmc_device generic structure
* @pdev: the pointer to the fmc_device generic structure
* @zdev: is the pointer to the real zio_device in use
* @hwzdev: is the pointer to the fake zio_device, used to initialize and
* to remove a zio_device
......@@ -378,21 +404,22 @@ struct fa_calib {
*/
struct fa_dev {
struct device *msgdev; /**< device used to print messages */
/* the pointer to the fmc_device generic structure */
struct fmc_device *fmc;
/* the pointer to the platform_device generic structure */
struct platform_device *pdev;
/* the pointer to the real zio_device in use */
struct zio_device *zdev;
/* the pointer to the fake zio_device, used for init/remove */
struct zio_device *hwzdev;
/* carrier common base offset addresses obtained from SDB */
unsigned int fa_adc_csr_base;
unsigned int fa_spi_base;
unsigned int fa_ow_base;
unsigned int fa_carrier_csr_base;
unsigned int fa_irq_vic_base;
unsigned int fa_irq_adc_base;
unsigned int fa_utc_base;
void *fa_adc_csr_base;
void *fa_spi_base;
void *fa_ow_base;
void *fa_top_level;
void *fa_carrier_csr_base;
void *fa_irq_vic_base;
void *fa_irq_adc_base;
void *fa_utc_base;
/* DMA description */
struct zio_dma_sgt *zdma;
......@@ -488,23 +515,23 @@ static inline struct fa_dev *get_zfadc(struct device *dev)
return NULL;
}
static inline u32 fa_ioread(struct fa_dev *fa, unsigned long addr)
static inline u32 fa_ioread(struct fa_dev *fa, void *addr)
{
return fmc_readl(fa->fmc, addr);
return memops.read(addr);
}
static inline void fa_iowrite(struct fa_dev *fa, u32 value, unsigned long addr)
static inline void fa_iowrite(struct fa_dev *fa, u32 value, void *addr)
{
fmc_writel(fa->fmc, value, addr);
memops.write(value, addr);
}
static inline uint32_t fa_readl(struct fa_dev *fa,
unsigned int base_off,
void *base_off,
const struct zfa_field_desc *field)
{
uint32_t cur;
cur = fa_ioread(fa, base_off+field->offset);
cur = fa_ioread(fa, base_off + field->offset);
if (field->is_bitfield) {
/* apply mask and shift right accordlying to the mask */
cur &= field->mask;
......@@ -512,11 +539,12 @@ static inline uint32_t fa_readl(struct fa_dev *fa,
} else {
cur &= field->mask; /* bitwise and with the mask */
}
return cur;
}
static inline void fa_writel(struct fa_dev *fa,
unsigned int base_off,
void *base_off,
const struct zfa_field_desc *field,
uint32_t usr_val)
{
......@@ -531,12 +559,12 @@ static inline void fa_writel(struct fa_dev *fa,
val = usr_val * (field->mask & -(field->mask));
if (val & ~field->mask)
dev_warn(fa->msgdev,
"addr 0x%lx: value 0x%x doesn't fit mask 0x%x\n",
"addr %p: value 0x%x doesn't fit mask 0x%x\n",
base_off+field->offset, val, field->mask);
val &= field->mask;
val |= cur;
}
fa_iowrite(fa, val, base_off+field->offset);
fa_iowrite(fa, val, base_off + field->offset);
}
extern struct bin_attribute dev_attr_eeprom;
......@@ -596,11 +624,6 @@ extern int fa_spi_xfer(struct fa_dev *fa, int cs, int num_bits,
extern int fa_spi_init(struct fa_dev *fd);
extern void fa_spi_exit(struct fa_dev *fd);
/* 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])) {
/* FIXME: this index SHOULD be recursive, too */
res = fmc_find_sdb_device(tree->subtree[i],
vid, did, sz);
if (res >= 0 && ci++ == index)
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;
}
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