...
 
Commits (7)
[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
url = https://ohwr.org/project/zio.git
This diff is collapsed.
This diff is collapsed.
......@@ -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) )
build/
\ No newline at end of file
TOP_DIR ?= ..
DRIVER_NAME := fmc-adc-100m14b4ch
VERSION := $(shell git describe --abbrev=0)
DIR_NAME := $(DRIVER_NAME)-$(VERSION)
KEEP_TEMP ?= n
BUILD ?= $(abspath build)
BUILD_DKMS := $(BUILD)/dkms
BUILD_DKMSSOURCE := $(BUILD_DKMS)/source
BUILD_DKMSTREE := $(BUILD_DKMS)/tree
DKMS_OPT := --dkmstree $(BUILD_DKMSTREE) -m $(DRIVER_NAME)/$(VERSION)
all: kernel
kernel: dkms-tar dkms-rpm
dkms-tree:
@mkdir -p $(BUILD_DKMSSOURCE)
@mkdir -p $(BUILD_DKMSTREE)
dkms-src: dkms-tree
$(eval $@_dir := $(BUILD_DKMSSOURCE)/$(DRIVER_NAME)-$(VERSION))
$(eval $@_src := $(shell git ls-tree -r --name-only HEAD $(TOP_DIR)/kernel/))
@mkdir -p $($@_dir)
@cp $(TOP_DIR)/distribution/dkms.conf $($@_dir)
@cp $(TOP_DIR)/distribution/fmc-adc-100m14b4ch-dkms-mkrpm.spec $($@_dir)
@cp $($@_src) $($@_dir)
@cp $(TOP_DIR)/LICENSES/GPL-2.0-or-later.txt $($@_dir)/LICENSE
@sed -r -i -e "s/^GIT_VERSION\s=\s.*/GIT_VERSION = $(VERSION)/" $($@_dir)/Makefile
@sed -r -i -e "s/@PKGVER@/$(VERSION)/g" -e "s/@PKGNAME@/$(DRIVER_NAME)/g" $($@_dir)/dkms.conf
dkms-add: dkms-src
@dkms add $(DKMS_OPT) --sourcetree $(BUILD_DKMSSOURCE)
dkms-tar: dkms-add
@dkms mktarball $(DKMS_OPT) --source-only
dkms-rpm: dkms-add
@dkms mkrpm $(DKMS_OPT) --source-only
clean:
@rm -rf $(BUILD)
.PHONY: dkmstree dkms-add kernel-dkms-tar
PACKAGE_NAME="@PKGNAME@"
PACKAGE_VERSION="@PKGVER@"
CLEAN="make KVERSION=$kernelver DKMSTREE=$dkms_tree DKMS=1 clean"
MAKE[0]="make KVERSION=$kernelver DKMSTREE=$dkms_tree DKMS=1"
BUILT_MODULE_NAME[0]="@PKGNAME@"
DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes"
BUILD_DEPENDS[0]="zio"
\ No newline at end of file
# Mainline copied from the template, added requirements
%{?!module_name: %{error: You did not specify a module name (%%module_name)}}
%{?!version: %{error: You did not specify a module version (%%version)}}
%{?!kernel_versions: %{error: You did not specify kernel versions (%%kernel_version)}}
%{?!packager: %define packager DKMS <dkms-devel@lists.us.dell.com>}
%{?!license: %define license Unknown}
%{?!_dkmsdir: %define _dkmsdir /var/lib/dkms}
%{?!_srcdir: %define _srcdir %_prefix/src}
%{?!_datarootdir: %define _datarootdir %{_datadir}}
Summary: %{module_name} %{version} dkms package
Name: %{module_name}
Version: %{version}
License: %license
Release: 1dkms
BuildArch: noarch
Group: System/Kernel
Requires: dkms >= 1.95, zio >= 1.4
BuildRequires: dkms
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root/
%description
Kernel modules for %{module_name} %{version} in a DKMS wrapper.
%prep
if [ "%mktarball_line" != "none" ]; then
/usr/sbin/dkms mktarball -m %module_name -v %version %mktarball_line --archive `basename %{module_name}-%{version}.dkms.tar.gz`
cp -af %{_dkmsdir}/%{module_name}/%{version}/tarball/`basename %{module_name}-%{version}.dkms.tar.gz` %{module_name}-%{version}.dkms.tar.gz
fi
%install
if [ "$RPM_BUILD_ROOT" != "/" ]; then
rm -rf $RPM_BUILD_ROOT
fi
mkdir -p $RPM_BUILD_ROOT/%{_srcdir}
mkdir -p $RPM_BUILD_ROOT/%{_datarootdir}/%{module_name}
if [ -d %{_sourcedir}/%{module_name}-%{version} ]; then
cp -Lpr %{_sourcedir}/%{module_name}-%{version} $RPM_BUILD_ROOT/%{_srcdir}
fi
if [ -f %{module_name}-%{version}.dkms.tar.gz ]; then
install -m 644 %{module_name}-%{version}.dkms.tar.gz $RPM_BUILD_ROOT/%{_datarootdir}/%{module_name}
fi
if [ -f %{_sourcedir}/common.postinst ]; then
install -m 755 %{_sourcedir}/common.postinst $RPM_BUILD_ROOT/%{_datarootdir}/%{module_name}/postinst
fi
%clean
if [ "$RPM_BUILD_ROOT" != "/" ]; then
rm -rf $RPM_BUILD_ROOT
fi
%post
for POSTINST in %{_prefix}/lib/dkms/common.postinst %{_datarootdir}/%{module_name}/postinst; do
if [ -f $POSTINST ]; then
$POSTINST %{module_name} %{version} %{_datarootdir}/%{module_name}
exit $?
fi
echo "WARNING: $POSTINST does not exist."
done
echo -e "ERROR: DKMS version is too old and %{module_name} was not"
echo -e "built with legacy DKMS support."
echo -e "You must either rebuild %{module_name} with legacy postinst"
echo -e "support or upgrade DKMS to a more current version."
exit 1
%preun
echo -e
echo -e "Uninstall of %{module_name} module (version %{version}) beginning:"
dkms remove -m %{module_name} -v %{version} --all --rpm_safe_upgrade
exit 0
%files
%defattr(-,root,root)
%{_srcdir}
%{_datarootdir}/%{module_name}/
%changelog
* %(date "+%a %b %d %Y") %packager %{version}-%{release}
- Automatic build by DKMS
fmc-bus @ eb86efcf
Subproject commit eb86efcf4e19a31a25471c4ddf3fd9fef8df02ec
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)
VMEBUS_EXTRA_SYMBOLS-$(CONFIG_FMC_ADC_SVEC) := $(VMEBUS_ABS)/driver/Module.symvers
KBUILD_EXTRA_SYMBOLS += $(ZIO_EXTRA_SYMBOLS-y)
KBUILD_EXTRA_SYMBOLS += $(VMEBUS_EXTRA_SYMBOLS-y)
# 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,23 +13,16 @@ 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)"
# The library includes <sdb.h>, so point -I directtly there
# include our header before to avoid conflicts with the kernel
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; )
......@@ -38,21 +30,20 @@ ccflags-y += -D__ZIO_MIN_MINOR_VERSION=$(shell echo $(ZIO_VERSION) | cut -d '-'
subdirs-ccflags-y = $(ccflags-y)
obj-m := fmc-adc-100m14b.o
fmc-adc-100m14b-y = fa-core.o
fmc-adc-100m14b-y += fa-zio-drv.o
fmc-adc-100m14b-y += fa-calibration.o
fmc-adc-100m14b-y += fa-regtable.o
fmc-adc-100m14b-y += fa-zio-trg.o
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
fmc-adc-100m14b-y += fa-spec-irq.o
fmc-adc-100m14b-$(CONFIG_FMC_ADC_SVEC) += fa-svec-core.o
fmc-adc-100m14b-$(CONFIG_FMC_ADC_SVEC) += fa-svec-regtable.o
fmc-adc-100m14b-$(CONFIG_FMC_ADC_SVEC) += fa-svec-dma.o
obj-m := fmc-adc-100m14b4ch.o
fmc-adc-100m14b4ch-y = fa-core.o
fmc-adc-100m14b4ch-y += fa-zio-drv.o
fmc-adc-100m14b4ch-y += fa-calibration.o
fmc-adc-100m14b4ch-y += fa-regtable.o
fmc-adc-100m14b4ch-y += fa-zio-trg.o
fmc-adc-100m14b4ch-y += fa-irq.o
fmc-adc-100m14b4ch-y += fa-debug.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-dma.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
fmc-adc-100m14b4ch-$(CONFIG_FMC_ADC_SVEC) += fa-svec-dma.o
......@@ -5,31 +5,34 @@ CURDIR:=$(shell /bin/pwd)
REPO_PARENT ?= $(CURDIR)/../..
-include $(REPO_PARENT)/parent_common.mk
LINUX ?= /lib/modules/$(shell uname -r)/build
FMC_BUS ?= ../fmc-bus
DKMS ?= 0
KVERSION ?= $(shell uname -r)
LINUX ?= /lib/modules/$(KVERSION)/build
ZIO ?= ../zio
SVEC_SW ?= ../svec-sw
VMEBUS ?= $(REPO_PARENT)/../vmebridge
# FMC_BUS_ABS and ZIO_ABS has to be absolut path,
# due to beeing passed to the Kbuild
FMC_BUS_ABS ?= $(abspath $(FMC_BUS) )
ZIO_ABS ?= $(abspath $(ZIO) )
SVEC_SW_ABS ?= $(abspath $(SVEC_SW) )
ifeq ($(DKMS), 1)
# Take last installed version (if installed using RPM it should be OK)
ZIO_VERSION ?= $(shell basename $(shell ls -d $(DKMSTREE)/zio/* | grep -E "\/[0-9]+\.[0-9]+\.[0-9]+" | sort -V | tail -n 1))
ZIO_ABS ?= $(DKMSTREE)/zio/$(ZIO_VERSION)/source
ZIO_EXTRA_SYMBOLS-y = $(DKMSTREE)/zio/kernel-$(KVERSION)-$(shell uname -p)/module/Module.symvers
else
ZIO_ABS ?= $(abspath $(ZIO))
ZIO_EXTRA_SYMBOLS-y = $(ZIO_ABS)/Module.symvers
ZIO_VERSION ?= $(shell cd $(ZIO_ABS); git describe --always --dirty --long --tags)
endif
VMEBUS_ABS ?= $(abspath $(VMEBUS) )
GIT_VERSION = $(shell git describe --always --dirty --long --tags)
export GIT_VERSION
FMC_BUS_VERSION ?= $(shell cd $(FMC_BUS_ABS); git describe --always --dirty --long --tags)
ZIO_VERSION ?= $(shell cd $(ZIO_ABS); git describe --always --dirty --long --tags)
export FMC_BUS_VERSION
export ZIO_VERSION
all modules:
$(MAKE) -C $(LINUX) M=$(CURDIR) FMC_BUS_ABS=$(FMC_BUS_ABS) \
ZIO_ABS=$(ZIO_ABS) SVEC_SW_ABS=$(SVEC_SW_ABS) \
$(MAKE) -C $(LINUX) M=$(CURDIR) ZIO_ABS=$(ZIO_ABS) \
ZIO_EXTRA_SYMBOLS-y=$(ZIO_EXTRA_SYMBOLS-y) \
VMEBUS_ABS=$(VMEBUS_ABS) modules
install modules_install: modules
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* EEPROM calibration block retreival code for fa-dev
*
* 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 "fmc-adc-100m14b4cha.h"
......@@ -101,12 +98,13 @@ static void fa_calib_cpu_to_le16s(struct fa_calib *calib)
cpu_to_le16s(p + i); /* s == in situ */
}
void fa_read_eeprom_calib(struct fa_dev *fa)
void fa_identity_calib_set(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_calib_le16_to_cpus(&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__);
}
/**
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* core fmc-adc-100m14b driver
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Copyright (C) 2012-2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
* Copied from fine-delay fd-core.c
*
*/
#include <linux/kernel.h>
......@@ -14,16 +11,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 +335,27 @@ 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))) {
if (dma_set_mask(fa->pdev->dev.parent, 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");
if (dma_set_mask(fa->pdev->dev.parent, DMA_BIT_MASK(32))) {
dev_err(fa->msgdev,
"32-bit DMA addressing not available\n");
return -EINVAL;
}
}
/* Use identity calibration */
fa_read_eeprom_calib(fa);
fa_identity_calib_set(fa);
fa->mshot_max_samples = fa_readl(fa, fa->fa_adc_csr_base,
&zfad_regs[ZFA_MULT_MAX_SAMP]);
......@@ -459,87 +419,130 @@ 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;
#ifdef CONFIG_FMC_ADC_SVEC
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;
#endif
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")) {
break;
#ifdef CONFIG_FMC_ADC_SVEC
case ADC_VER_SVEC:
memops.read = ioread32be;
memops.write = iowrite32be;
fa->carrier_op = &fa_svec_op;
break;
#endif
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;
}
/*
* 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);
......@@ -559,14 +562,8 @@ 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:
out:
while (--m, --i >= 0)
......@@ -575,9 +572,9 @@ 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);
......@@ -592,27 +589,31 @@ 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[] = {
{
.name = "adc-100m-spec",
.driver_data = ADC_VER_SPEC,
},
#ifdef CONFIG_FMC_ADC_SVEC
{
.product_name = "FmcAdc100m14b4cha",
.name = "adc-100m-svec",
.driver_data = ADC_VER_SVEC,
},
#endif
/* 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)
......@@ -640,7 +641,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;
......@@ -658,7 +659,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)
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2018
* Copyright CERN 2018-2019
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012
* Copyright CERN 2012-2019
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* IRQ-related code
*/
#include <linux/kernel.h>
......@@ -12,6 +11,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 +272,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 +282,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 +310,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 +346,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 +360,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 +388,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 +400,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 +420,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],
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012
* Copyright CERN 2012-2019
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* Table of register masks, used by driver functions
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* core-spec fmc-adc-100m14b driver
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Copyright (C) 2012-2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
* Copied from fine-delay
*
*/
#include <linux/time.h>
......@@ -14,31 +11,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 +85,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 +129,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 +165,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,
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012
* Copyright CERN 2012-2019
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* handle DMA mapping
*/
#include <linux/kernel.h>
......@@ -95,7 +94,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.parent, blocks,
fa->n_shots, GFP_ATOMIC);
if (IS_ERR(fa->zdma))
return PTR_ERR(fa->zdma);
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012
* Copyright CERN 2012-2019
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* IRQ function handler
*/
......@@ -26,18 +25,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 +57,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 +82,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 +102,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 +114,5 @@ out:
cset->flags &= ~ZIO_CSET_HW_BUSY;
spin_unlock(&cset->lock);
/* ack the irq */
fmc_irq_ack(fa->fmc);
return IRQ_HANDLED;
}
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012
*
* Header for the fmc-adc-100m14b spec driver
*
* Copyright CERN 2012-2019
*/
#ifndef __FA_SPEC_CORE_H__
......@@ -87,8 +85,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 */
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* core-spec fmc-adc-100m14b driver
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Copyright (C) 2012-2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
* Copied from fine-delay
*
*/
#include <linux/module.h>
#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);
/* Reset the FMC slot*/
fa_writel(fa, fa->fa_carrier_csr_base,
&fa_svec_regfield[FA_CAR_FMC0_RES + fmc->slot_id], 1);
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;
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 +55,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,
......
// 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/kernel.h>
#include <asm/byteorder.h>
......@@ -87,9 +93,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 +104,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);
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012
* Copyright CERN 2012-2019
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* Table of register masks, used by driver functions
*/
#include "fa-svec.h"
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012
*
* Header for the fmc-adc-100m14b spec driver
*
* Copyright CERN 2012-2019
*/
#ifndef __FA_SVEC_CORE_H__
......@@ -34,9 +32,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 */
};
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012
* Copyright CERN 2012-2019
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* Driver for the mezzanine ADC for the SPEC
*/
#include <linux/kernel.h>
#include <linux/module.h>
......@@ -170,7 +169,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 +322,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;
......@@ -678,7 +677,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);
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012, author Federico Vaga
*
* Trigger for the driver of the mezzanine ADC
* Copyright CERN 2012-2019
* Author: Federico Vaga
*/
#include <linux/kernel.h>
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2012 Federico Vaga
*
* GNU GPLv2 or later
* Copyright 2012-2019 Federico Vaga
*/
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright CERN 2012
* Copyright CERN 2012-2019
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* Header for the mezzanine ADC for the SPEC
*/
#ifndef FMC_ADC_100M14B4C_H_
......@@ -37,6 +36,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
......@@ -151,9 +154,8 @@ struct fa_calib {
#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>
......@@ -164,6 +166,29 @@ struct fa_calib {
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
......@@ -370,7 +395,7 @@ struct fa_carrier_op {
/*
* 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
......@@ -384,21 +409,22 @@ struct fa_carrier_op {
*/
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;
......@@ -494,23 +520,23 @@ static inline struct fa_dev *get_zfadc(struct device *dev)
return NULL;