Commit ac355f2a authored by Federico Vaga's avatar Federico Vaga

Merge branch 'release/v5.0.0.rc5' into master

parents ec1583c6 b70f2816
......@@ -6,6 +6,7 @@
*.order
*.symvers
*.mod.c
*.mod
*.o.d
*.tmp
*.lof
......
[submodule "zio"]
path = zio
url = https://ohwr.org/project/zio.git
[submodule "fmc-bus"]
path = fmc-bus
url = https://ohwr.org/project/fmc-bus.git
# include parent_common.mk for buildsystem's defines
# use absolute path for REPO_PARENT
CURDIR:=$(shell /bin/pwd)
REPO_PARENT ?= $(CURDIR)/..
-include $(REPO_PARENT)/parent_common.mk
all: kernel tools
FMC_BUS ?= fmc-bus
ZIO ?= zio
SVEC_SW ?= svec-sw
VMEBUS ?= $(REPO_PARENT)/vmebridge
# Use the absolute path so it can be used by submodule
# 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) )
VMEBUS_ABS ?= $(abspath $(VMEBUS) )
export FMC_BUS_ABS
export ZIO_ABS
export SVEC_SW_ABS
export VMEBUS_ABS
DIRS = $(FMC_BUS_ABS) $(ZIO_ABS) kernel tools
kernel: $(FMC_BUS_ABS) $(ZIO_ABS)
DIRS =kernel tools
.PHONY: all clean modules install modules_install $(DIRS)
.PHONY: gitmodules prereq_install prereq_install_warn
install modules_install: prereq_install_warn
install modules_install:
all clean modules install modules_install: $(DIRS)
......@@ -43,25 +20,3 @@ modules_install: TARGET = modules_install
$(DIRS):
$(MAKE) -C $@ $(TARGET)
SUBMOD = $(FMC_BUS_ABS) $(ZIO_ABS)
prereq_install_warn:
@test -f .prereq_installed || \
echo -e "\n\n\tWARNING: Consider \"make prereq_install\"\n"
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
Subproject commit eb86efcf4e19a31a25471c4ddf3fd9fef8df02ec
CONFIG_FMC_ADC_SVEC ?= CONFIG_VME
VMEBUS_EXTRA_SYMBOLS-$(CONFIG_FMC_ADC_SVEC) := $(VMEBUS_ABS)/driver/Module.symvers
KBUILD_EXTRA_SYMBOLS := \
$(ZIO_ABS)/Module.symvers \
$(FMC_BUS_ABS)/kernel/Module.symvers \
$(VMEBUS_EXTRA_SYMBOLS-y)
ZIO_VERSION = $(shell cd $(ZIO_ABS); git describe --always --dirty --long --tags)
VERSION = $(shell cd $(src); git describe --always --dirty --long --tags)
KBUILD_EXTRA_SYMBOLS += $(ZIO_EXTRA_SYMBOLS-y)
KBUILD_EXTRA_SYMBOLS += $(FMC_EXTRA_SYMBOLS-y)
KBUILD_EXTRA_SYMBOLS += $(VMEBUS_EXTRA_SYMBOLS-y)
ccflags-y = -DVERSION=\"$(VERSION)\"
ccflags-y += -I$(src)
ccflags-y += -I$(ZIO_ABS)/include
ccflags-y += -I$(FMC_ABS)/include
ccflags-y += -I$(VMEBUS_ABS)/driver
ccflags-$(CONFIG_FMC_ADC_SVEC) += -I$(VMEBUS_ABS)/include
ccflags-$(CONFIG_FMC_ADC_DEBUG) += -DDEBUG
# Extract ZIO minimum compatible version
ccflags-y += -D__ZIO_MIN_MAJOR_VERSION=$(shell echo $(ZIO_VERSION) | cut -d '-' -f 1 | cut -d '.' -f 1 | tr -d 'v'; )
ccflags-y += -D__ZIO_MIN_MINOR_VERSION=$(shell echo $(ZIO_VERSION) | cut -d '-' -f 1 | cut -d '.' -f 2; )
# 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,45 +30,26 @@ 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)
LINUXINCLUDE := -I$(FMC_ABS)/include $(LINUXINCLUDE)
ccflags-y += -DGIT_VERSION=\"$(GIT_VERSION)\" \
-I$(ZIO_ABS)/include \
-I$(src)
ccflags-y += -DADDITIONAL_VERSIONS="$(SUBMODULE_VERSIONS-y)"
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
subdirs-ccflags-y = $(ccflags-y)
# Extract ZIO minimum compatible version
ccflags-y += -D__ZIO_MIN_MAJOR_VERSION=$(shell echo $(ZIO_VERSION) | cut -d '-' -f 2 | cut -d '.' -f 1; )
ccflags-y += -D__ZIO_MIN_MINOR_VERSION=$(shell echo $(ZIO_VERSION) | cut -d '-' -f 2 | cut -d '.' -f 2; )
obj-m := fmc-adc-100m14b4ch.o
obj-m += fmc-adc-100m14b4ch-spec.o
subdirs-ccflags-y = $(ccflags-y)
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 += fa-dma.o
fmc-adc-100m14b4ch-y += spi.o
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
fmc-adc-100m14b4ch-spec-objs := fmc-adc-100m14b4ch-spec-core.o
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright (C) 2019 CERN
-include Makefile.specific
# include parent_common.mk for buildsystem's defines
# use absolute path for REPO_PARENT
CURDIR:=$(shell /bin/pwd)
REPO_PARENT ?= $(CURDIR)/../..
-include $(REPO_PARENT)/parent_common.mk
CPPCHECK ?= cppcheck
DKMS ?= 0
CURDIR := $(shell /bin/pwd)
KVERSION ?= $(shell uname -r)
LINUX ?= /lib/modules/$(KVERSION)/build
FMC_BUS ?= ../fmc-bus
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) )
VMEBUS_ABS ?= $(abspath $(VMEBUS) )
GIT_VERSION = $(shell git describe --always --dirty --long --tags)
export GIT_VERSION
ifdef REPO_PARENT
ZIO ?= $(REPO_PARENT)/fmc/zio
FMC ?= $(REPO_PARENT)/fmc-sw
VMEBUS ?= $(REPO_PARENT)/vmebridge-ng
endif
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
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)
ifndef ZIO
$(error "Missing ZIO environment variable")
endif
ifndef FMC
$(error "Missing FMC environment variable")
endif
ifndef VMEBUS
$(error "Missing VMEBUS environment variable")
endif
export FMC_BUS_VERSION
export ZIO_VERSION
ZIO_ABS ?= $(abspath $(ZIO))
ZIO_EXTRA_SYMBOLS-y = $(ZIO_ABS)/drivers/zio/Module.symvers
ZIO_VERSION ?= $(shell cd $(ZIO_ABS); git describe --always --dirty --long --tags)
FMC_ABS ?= $(abspath $(FMC))
FMC_EXTRA_SYMBOLS-y = $(FMC_ABS)/drivers/fmc/Module.symvers
endif
VMEBUS_ABS ?= $(abspath $(VMEBUS) )
GIT_VERSION = $(shell git describe --always --dirty --long --tags)
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) FMC_ABS=$(FMC_ABS) \
ZIO_EXTRA_SYMBOLS-y=$(ZIO_EXTRA_SYMBOLS-y) \
FMC_EXTRA_SYMBOLS-y=$(FMC_EXTRA_SYMBOLS-y) \
ZIO_VERSION=$(ZIO_VERSION) \
GIT_VERSION=$(GIT_VERSION) \
VMEBUS_ABS=$(VMEBUS_ABS) modules
install modules_install: modules
......@@ -40,3 +63,6 @@ install modules_install: modules
clean:
rm -rf *.o *~ .*.cmd *.ko *.mod.c .tmp_versions Module.symvers \
Module.markers modules.order
cppcheck:
$(CPPCHECK) -q -I. -I$(ZIO_ABS)/include -I$(FMC_BUS_ABS)/ --enable=all *.c *.h
This diff is collapsed.
This diff is collapsed.
......@@ -6,6 +6,116 @@
#include "fmc-adc-100m14b4cha.h"
#define FA_DBG_REG32_CH(_n) \
{.name = "ADC-CSR:ch"#_n"_ctl", .offset = ADC_CSR_OFF + 0x080 + ((_n - 1) * 0x40)}, \
{.name = "ADC-CSR:ch"#_n"_sta", .offset = ADC_CSR_OFF + 0x084 + ((_n - 1) * 0x40)}, \
{.name = "ADC-CSR:ch"#_n"_cal_nb", .offset = ADC_CSR_OFF + 0x088 + ((_n - 1) * 0x40)}, \
{.name = "ADC-CSR:ch"#_n"_sat", .offset = ADC_CSR_OFF + 0x08C + ((_n - 1) * 0x40)}, \
{.name = "ADC-CSR:ch"#_n"_trig_thres", .offset = ADC_CSR_OFF + 0x090 + ((_n - 1) * 0x40)}, \
{.name = "ADC-CSR:ch"#_n"_trig_dly", .offset = ADC_CSR_OFF + 0x094 + ((_n - 1) * 0x40)}
#define FA_DBG_REG32_TIM(_name, _off) \
{ \
.name = "TIME-TAG:"#_name"_seconds_upper", \
.offset = ADC_UTC_OFF + _off \
}, { \
.name = "TIME-TAG:"#_name"_seconds_lower", \
.offset = ADC_UTC_OFF + _off + 0x4, \
}, { \
.name = "TIME-TAG:"#_name"_coarse", \
.offset = ADC_UTC_OFF + _off + 0x8, \
}
static const struct debugfs_reg32 fa_debugfs_reg32[] = {
{
.name = "ADC-CSR:ctl",
.offset = ADC_CSR_OFF + 0x000,
},
{
.name = "ADC-CSR:sta",
.offset = ADC_CSR_OFF + 0x004,
},
{
.name = "ADC-CSR:trig_stat",
.offset = ADC_CSR_OFF + 0x008,
},
{
.name = "ADC-CSR:trig_en",
.offset = ADC_CSR_OFF + 0x00C,
},
{
.name = "ADC-CSR:trig_pol",
.offset = ADC_CSR_OFF + 0x010,
},
{
.name = "ADC-CSR:ext_trig_dly",
.offset = ADC_CSR_OFF + 0x014,
},
{
.name = "ADC-CSR:sw_trig",
.offset = ADC_CSR_OFF + 0x018,
},
{
.name = "ADC-CSR:shots",
.offset = ADC_CSR_OFF + 0x01C,
},
{
.name = "ADC-CSR:multi_depth",
.offset = ADC_CSR_OFF + 0x020,
},
{
.name = "ADC-CSR:trig_pos",
.offset = ADC_CSR_OFF + 0x024,
},
{
.name = "ADC-CSR:fs_freq",
.offset = ADC_CSR_OFF + 0x028,
},
{
.name = "ADC-CSR:downsample",
.offset = ADC_CSR_OFF + 0x02C,
},
{
.name = "ADC-CSR:pre_samples",
.offset = ADC_CSR_OFF + 0x030,
},
{
.name = "ADC-CSR:post_samples",
.offset = ADC_CSR_OFF + 0x034,
},
{
.name = "ADC-CSR:samples_cnt",
.offset = ADC_CSR_OFF + 0x038,
},
FA_DBG_REG32_CH(1),
FA_DBG_REG32_CH(2),
FA_DBG_REG32_CH(3),
FA_DBG_REG32_CH(4),
{
.name = "ADC-EIC:disable_mask",
.offset = ADC_EIC_OFF + 0x0,
},
{
.name = "ADC-EIC:enable_mask",
.offset = ADC_EIC_OFF + 0x4,
},
{
.name = "ADC-EIC:status_mask",
.offset = ADC_EIC_OFF + 0x8,
},
{
.name = "ADC-EIC:source",
.offset = ADC_EIC_OFF + 0xC,
},
FA_DBG_REG32_TIM(base_time, 0x00),
FA_DBG_REG32_TIM(time_trig, 0x0C),
FA_DBG_REG32_TIM(trig_tag, 0x18),
FA_DBG_REG32_TIM(acq_start_tag, 0x24),
FA_DBG_REG32_TIM(acq_stop_tag, 0x30),
FA_DBG_REG32_TIM(acq_end_tag, 0x3C),
};
static void fa_regdump_seq_read_spi(struct fa_dev *fa, struct seq_file *s)
{
......@@ -53,20 +163,155 @@ static const struct file_operations fa_regdump_ops = {
};
static ssize_t fa_trg_sw_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct fa_dev *fa = file->private_data;
int err;
err = fa_trigger_software(fa);
return err ? err : count;
}
static const struct file_operations fa_trg_sw_ops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = fa_trg_sw_write,
};
#define FA_ADC_DATA_PATTERN_CMD_SIZE 16UL
static int fa_data_pattern_adc_write(struct fa_dev *fa, const char __user *buf,
size_t count)
{
char buf_l[FA_ADC_DATA_PATTERN_CMD_SIZE];
int err;
memset(buf_l, 0, FA_ADC_DATA_PATTERN_CMD_SIZE);
err = copy_from_user(buf_l, buf, min(count,
FA_ADC_DATA_PATTERN_CMD_SIZE));
if (err)
return -EFAULT;
if ((count == 1 || count == 2)&& buf_l[0] == '0') {
err = fa_adc_data_pattern_set(fa, 0, 0);
fa_calib_init(fa);
return err;
} else if (count > 2 && buf_l[0] == '1' && buf_l[1] == ' ') {
uint16_t pattern = 0;
err = kstrtou16(buf_l + 2, 0, &pattern);
if (err)
return err;
err = fa_adc_data_pattern_set(fa, pattern & 0x3FFF, 1);
fa_calib_exit(fa);
return err;
} else {
return -EINVAL;
}
}
static ssize_t fa_data_pattern_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct fa_dev *fa = file->private_data;
if (strncmp(buf, "adc ", 4) == 0) {
int err;
err = fa_data_pattern_adc_write(fa, buf + 4, count - 4);
return err ? err : count;
} else {
dev_err(&fa->pdev->dev, "Unknown command \"%s\"\n", buf);
return -EINVAL;
}
}
static ssize_t fa_data_pattern_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct fa_dev *fa = file->private_data;
char buf_l[FA_ADC_DATA_PATTERN_CMD_SIZE];
uint16_t pattern;
unsigned int enable;
int err;
if (*ppos > 0)
return 0;
err = fa_adc_data_pattern_get(fa, &pattern, &enable);
if (err)
return err;
snprintf(buf_l, FA_ADC_DATA_PATTERN_CMD_SIZE, "adc %d 0x%02x\n",
enable, pattern);
count = min(count, strlen(buf_l));
err = copy_to_user(buf, buf_l, count);
*ppos += count;
return err ? err : count;
}
static const struct file_operations fa_data_pattern_ops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = fa_data_pattern_write,
.read = fa_data_pattern_read,
};
int fa_debug_init(struct fa_dev *fa)
{
fa->reg_dump = debugfs_create_file(dev_name(&fa->zdev->head.dev), 0444,
NULL, fa, &fa_regdump_ops);
if (IS_ERR_OR_NULL(fa->reg_dump)) {
dev_err(fa->msgdev,
int err;
fa->dbg_dir = debugfs_create_dir(dev_name(&fa->zdev->head.dev), NULL);
if (IS_ERR_OR_NULL(fa->dbg_dir)) {
err = PTR_ERR(fa->dbg_dir);
dev_err(&fa->zdev->head.dev,
"Cannot create debugfs directory \"%s\" (%d)\n",
dev_name(&fa->zdev->head.dev), err);
return err;
}
fa->dbg_reg32.regs = fa_debugfs_reg32;
fa->dbg_reg32.nregs = ARRAY_SIZE(fa_debugfs_reg32);
fa->dbg_reg32.base = fa->fa_top_level;
fa->dbg_reg = debugfs_create_regset32("regs", 0200, fa->dbg_dir,
&fa->dbg_reg32);
if (IS_ERR_OR_NULL(fa->dbg_reg)) {
err = PTR_ERR(fa->dbg_reg);
dev_warn(fa->msgdev,
"Cannot create debugfs file \"regs\" (%d)\n",
err);
}
fa->dbg_reg_spi = debugfs_create_file("spi-regs", 0444,
fa->dbg_dir, fa,
&fa_regdump_ops);
if (IS_ERR_OR_NULL(fa->dbg_reg_spi)) {
dev_warn(fa->msgdev,
"Cannot create regdump debugfs file\n");
}
fa->dbg_trg_sw = debugfs_create_file("trigger_software", 0200,
fa->dbg_dir, fa,
&fa_trg_sw_ops);
if (IS_ERR_OR_NULL(fa->dbg_trg_sw)) {
dev_warn(&fa->pdev->dev,
"Cannot create software trigger file\n");
}
fa->dbg_data_pattern = debugfs_create_file("data_pattern", 0644,
fa->dbg_dir, fa,
&fa_data_pattern_ops);
if (IS_ERR_OR_NULL(fa->dbg_data_pattern)) {
dev_warn(&fa->pdev->dev,
"Cannot create ADC data pattern file\n");
}
return 0;
}
void fa_debug_exit(struct fa_dev *fa)
{
debugfs_remove_recursive(fa->reg_dump);
debugfs_remove_recursive(fa->dbg_dir);
}
This diff is collapsed.
This diff is collapsed.
......@@ -18,10 +18,13 @@ const struct zfa_field_desc zfad_regs[] = {
[ZFA_CTL_TRIG_LED] = {0x00, 0x00000040, 1},
[ZFA_CTL_ACQ_LED] = {0x00, 0x00000080, 1},
[ZFA_CTL_RST_TRG_STA] = {0x00, 0x00000100, 1},
[ZFA_CTL_CALIB_APPLY] = {0x00, 0x00008000, 1},
/* Status registers */
[ZFA_STA_FSM] = {0x04, 0x00000007, 1},
[ZFA_STA_SERDES_PLL] = {0x04, 0x00000008, 1},
[ZFA_STA_SERDES_SYNCED] = {0x04, 0x00000010, 1},
[ZFA_STA_FMC_NR] = {0x04, 0x000000c0, 1},
[ZFA_STA_CALIB_BUSY] = {0x04, 0x00008000, 1},
/* Trigger */
/* Config register */
[ZFAT_CFG_STA] = {0x08, 0xFFFFFFFF, 0},
......@@ -32,67 +35,67 @@ const struct zfa_field_desc zfad_regs[] = {
/* Software */
[ZFAT_SW] = {0x18, 0xFFFFFFFF, 0},
/* Number of shots */
[ZFAT_SHOTS_NB] = {0x1C, 0x0000FFFF, 0},
[ZFAT_SHOTS_NB] = {0x1C, 0x0000FFFF, 1},
/* Remaining shots counter */
[ZFAT_SHOTS_REM] = {0x1C, 0xFFFF0000, 1},
/* Multishot max samples*/
[ZFA_MULT_MAX_SAMP] = {0x20, 0xFFFFFFFF, 0},
/* Remaining shots counter */
[ZFAT_SHOTS_REM] = {0x24, 0x0000FFFF, 0},
/* Position address */
[ZFAT_POS] = {0x28, 0xFFFFFFFF, 0},
[ZFAT_POS] = {0x24, 0xFFFFFFFF, 0},
/* Sampling clock frequency */
[ZFAT_SAMPLING_HZ] = {0x2C, 0xFFFFFFFF, 0},
[ZFAT_SAMPLING_HZ] = {0x28, 0xFFFFFFFF, 0},
/* Sample rate */
[ZFAT_SR_UNDER] = {0x30, 0xFFFFFFFF, 0},
[ZFAT_SR_UNDER] = {0x2C, 0xFFFFFFFF, 0},
/* Pre-sample */
[ZFAT_PRE] = {0x34, 0xFFFFFFFF, 0},
[ZFAT_PRE] = {0x30, 0xFFFFFFFF, 0},
/* Post-sample */
[ZFAT_POST] = {0x38, 0xFFFFFFFF, 0},
[ZFAT_POST] = {0x34, 0xFFFFFFFF, 0},
/* Sample counter */
[ZFAT_CNT] = {0x3C, 0xFFFFFFFF, 0},
[ZFAT_CNT] = {0x38, 0xFFFFFFFF, 0},
/* Channel 1 */
[ZFA_CH1_CTL_RANGE] = {0x80, 0x00000077, 1},
[ZFA_CH1_CTL_TERM] = {0x80, 0x00000008, 1},
[ZFA_CH1_STA] = {0x84, 0x0000FFFF, 0},
[ZFA_CH1_GAIN] = {0x88, 0x0000FFFF, 0},
[ZFA_CH1_OFFSET] = {0x8C, 0x0000FFFF, 0},
[ZFA_CH1_SAT] = {0x90, 0x00007FFF, 0},
[ZFA_CH1_HYST] = {0x94, 0xFFFF0000, 1},
[ZFA_CH1_THRES] = {0x94, 0x0000FFFF, 1},
[ZFA_CH1_DLY] = {0x98, 0xFFFFFFFF, 0},
[ZFA_CH1_GAIN] = {0x88, 0x0000FFFF, 1},
[ZFA_CH1_OFFSET] = {0x88, 0xFFFF0000, 1},
[ZFA_CH1_SAT] = {0x8C, 0x00007FFF, 0},
[ZFA_CH1_HYST] = {0x90, 0xFFFF0000, 1},
[ZFA_CH1_THRES] = {0x90, 0x0000FFFF, 1},
[ZFA_CH1_DLY] = {0x94, 0xFFFFFFFF, 0},
/* Channel 2 */
[ZFA_CH2_CTL_RANGE] = {0x100, 0x00000077, 1},
[ZFA_CH2_CTL_TERM] = {0x100, 0x00000008, 1},
[ZFA_CH2_STA] = {0x104, 0x0000FFFF, 0},
[ZFA_CH2_GAIN] = {0x108, 0x0000FFFF, 0},
[ZFA_CH2_OFFSET] = {0x10C, 0x0000FFFF, 0},
[ZFA_CH2_SAT] = {0x110, 0x00007FFF, 0},
[ZFA_CH2_HYST] = {0x114, 0xFFFF0000, 1},
[ZFA_CH2_THRES] = {0x114, 0x0000FFFF, 1},
[ZFA_CH2_DLY] = {0x118, 0xFFFFFFFF, 0},
[ZFA_CH2_CTL_RANGE] = {0xC0, 0x00000077, 1},
[ZFA_CH2_CTL_TERM] = {0xC0, 0x00000008, 1},
[ZFA_CH2_STA] = {0xC4, 0x0000FFFF, 0},
[ZFA_CH2_GAIN] = {0xC8, 0x0000FFFF, 1},
[ZFA_CH2_OFFSET] = {0xC8, 0xFFFF0000, 1},
[ZFA_CH2_SAT] = {0xCC, 0x00007FFF, 0},
[ZFA_CH2_HYST] = {0xD0, 0xFFFF0000, 1},
[ZFA_CH2_THRES] = {0xD0, 0x0000FFFF, 1},
[ZFA_CH2_DLY] = {0xD4, 0xFFFFFFFF, 0},
/* Channel 3 */
[ZFA_CH3_CTL_RANGE] = {0x180, 0x00000077, 1},
[ZFA_CH3_CTL_TERM] = {0x180, 0x00000008, 1},
[ZFA_CH3_STA] = {0x184, 0x0000FFFF, 0},
[ZFA_CH3_GAIN] = {0x188, 0x0000FFFF, 0},
[ZFA_CH3_OFFSET] = {0x18C, 0x0000FFFF, 0},
[ZFA_CH3_SAT] = {0x190, 0x00007FFF, 0},
[ZFA_CH3_HYST] = {0x194, 0xFFFF0000, 1},
[ZFA_CH3_THRES] = {0x194, 0x0000FFFF, 1},
[ZFA_CH3_DLY] = {0x198, 0xFFFFFFFF, 0},
[ZFA_CH3_CTL_RANGE] = {0x100, 0x00000077, 1},
[ZFA_CH3_CTL_TERM] = {0x100, 0x00000008, 1},
[ZFA_CH3_STA] = {0x104, 0x0000FFFF, 0},
[ZFA_CH3_GAIN] = {0x108, 0x0000FFFF, 1},
[ZFA_CH3_OFFSET] = {0x108, 0xFFFF0000, 1},
[ZFA_CH3_SAT] = {0x10C, 0x00007FFF, 0},
[ZFA_CH3_HYST] = {0x110, 0xFFFF0000, 1},
[ZFA_CH3_THRES] = {0x110, 0x0000FFFF, 1},
[ZFA_CH3_DLY] = {0x114, 0xFFFFFFFF, 0},
/* Channel 4 */
[ZFA_CH4_CTL_RANGE] = {0x200, 0x00000077, 1},
[ZFA_CH4_CTL_TERM] = {0x200, 0x00000008, 1},
[ZFA_CH4_STA] = {0x204, 0x0000FFFF, 0},
[ZFA_CH4_GAIN] = {0x208, 0x0000FFFF, 0},
[ZFA_CH4_OFFSET] = {0x20C, 0x0000FFFF, 0},
[ZFA_CH4_SAT] = {0x210, 0x00007FFF, 0},
[ZFA_CH4_HYST] = {0x214, 0xFFFF0000, 1},
[ZFA_CH4_THRES] = {0x214, 0x0000FFFF, 1},
[ZFA_CH4_DLY] = {0x218, 0xFFFFFFFF, 0},
[ZFA_CH4_CTL_RANGE] = {0x140, 0x00000077, 1},
[ZFA_CH4_CTL_TERM] = {0x140, 0x00000008, 1},
[ZFA_CH4_STA] = {0x144, 0x0000FFFF, 0},
[ZFA_CH4_GAIN] = {0x148, 0x0000FFFF, 1},
[ZFA_CH4_OFFSET] = {0x148, 0xFFFF0000, 1},
[ZFA_CH4_SAT] = {0x14C, 0x00007FFF, 0},
[ZFA_CH4_HYST] = {0x150, 0xFFFF0000, 1},
[ZFA_CH4_THRES] = {0x150, 0x0000FFFF, 1},
[ZFA_CH4_DLY] = {0x154, 0xFFFFFFFF, 0},
/* IRQ */
[ZFA_IRQ_ADC_DISABLE_MASK] = {0x00, 0x00000003, 0},
......@@ -104,23 +107,29 @@ const struct zfa_field_desc zfad_regs[] = {
[ZFA_IRQ_VIC_DISABLE_MASK] = {0x0C, 0x00000003, 0},
[ZFA_IRQ_VIC_MASK_STATUS] = {0x10, 0x00000003, 0},
/* DS18B20 UID/Temperature */
[ZFA_DS18B20_ID_U] = {0x00, 0xFFFFFFFF, 0},
[ZFA_DS18B20_ID_L] = {0x04, 0xFFFFFFFF, 0},
[ZFA_DS18B20_TEMP] = {0x08, 0x0000FFFF, 0},
[ZFA_DS18B20_STAT] = {0x0C, 0x00000003, 0},
/* UTC */
[ZFA_UTC_SECONDS] = {0x00, ~0x0, 0},
[ZFA_UTC_COARSE] = {0x04, ~0x0, 0},
[ZFA_UTC_TRIG_META] = {0x08, ~0x0, 0},
[ZFA_UTC_TRIG_SECONDS] = {0x0C, ~0x0, 0},
[ZFA_UTC_TRIG_COARSE] = {0x10, ~0x0, 0},
[ZFA_UTC_TRIG_FINE] = {0x14, ~0x0, 0},
[ZFA_UTC_ACQ_START_META] = {0x18, ~0x0, 0},
[ZFA_UTC_ACQ_START_SECONDS] = {0x1C, ~0x0, 0},
[ZFA_UTC_ACQ_START_COARSE] = {0x20, ~0x0, 0},
[ZFA_UTC_ACQ_START_FINE] = {0x24, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_META] = {0x28, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_SECONDS] = {0x2C, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_COARSE] = {0x30, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_FINE] = {0x34, ~0x0, 0},
[ZFA_UTC_ACQ_END_META] = {0x38, ~0x0, 0},
[ZFA_UTC_ACQ_END_SECONDS] = {0x3C, ~0x0, 0},
[ZFA_UTC_ACQ_END_COARSE] = {0x40, ~0x0, 0},
[ZFA_UTC_ACQ_END_FINE] = {0x44, ~0x0, 0},
[ZFA_UTC_SECONDS_U] = {0x00, ~0x0, 0},
[ZFA_UTC_SECONDS_L] = {0x04, ~0x0, 0},
[ZFA_UTC_COARSE] = {0x08, ~0x0, 0},
[ZFA_UTC_TRIG_TIME_SECONDS_U] = {0x0C, ~0x0, 0},
[ZFA_UTC_TRIG_TIME_SECONDS_L] = {0x10, ~0x0, 0},
[ZFA_UTC_TRIG_TIME_COARSE] = {0x14, ~0x0, 0},
[ZFA_UTC_TRIG_SECONDS_U] = {0x18, ~0x0, 0},
[ZFA_UTC_TRIG_SECONDS_L] = {0x1C, ~0x0, 0},
[ZFA_UTC_TRIG_COARSE] = {0x20, ~0x0, 0},
[ZFA_UTC_ACQ_START_SECONDS_U] = {0x24, ~0x0, 0},
[ZFA_UTC_ACQ_START_SECONDS_L] = {0x28, ~0x0, 0},
[ZFA_UTC_ACQ_START_COARSE] = {0x2C, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_SECONDS_U] = {0x30, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_SECONDS_L] = {0x34, ~0x0, 0},
[ZFA_UTC_ACQ_STOP_COARSE] = {0x38, ~0x0, 0},
[ZFA_UTC_ACQ_END_SECONDS_U] = {0x3C, ~0x0, 0},
[ZFA_UTC_ACQ_END_SECONDS_L] = {0x40, ~0x0, 0},
[ZFA_UTC_ACQ_END_COARSE] = {0x44, ~0x0, 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 char *fa_spec_get_gwname(void)
{
return FA_GATEWARE_SPEC;
}
static int fa_spec_init(struct fa_dev *fa)
{
struct fa_spec_data *cdata;
uint32_t val;
fa->fa_carrier_csr_base = fmc_find_sdb_device(fa->fmc->sdb, 0xce42,
0x603, NULL);
cdata = kzalloc(sizeof(struct fa_spec_data), GFP_KERNEL);
if (!cdata)
return -ENOMEM;
/* SDB carrier specific */
cdata->fa_dma_base =
fmc_find_sdb_device(fa->fmc->sdb, 0xce42, 0x601, NULL);
cdata->fa_irq_dma_base =
fmc_find_sdb_device(fa->fmc->sdb, 0xce42, 0xd5735ab4, NULL);
dev_info(fa->msgdev,
"Spec Base addrs: irq_dmma:0x%x, dma_ctrl:0x%x, csr:0x%x\n",
cdata->fa_irq_dma_base, cdata->fa_dma_base,
fa->fa_carrier_csr_base);
/* Reset the FMC slot */
fa_writel(fa, fa->fa_carrier_csr_base,
&fa_spec_regs[ZFA_CAR_FMC_RES], 1);
mdelay(50);
fa_writel(fa, fa->fa_carrier_csr_base,
&fa_spec_regs[ZFA_CAR_FMC_RES], 0);
mdelay(50);
/* Verify that the FMC is plugged (0 is plugged) */
val = fa_readl(fa, fa->fa_carrier_csr_base,
&fa_spec_regs[ZFA_CAR_FMC_PRES]);
if (val) {
dev_err(fa->msgdev, "No FCM ADC plugged\n");
return -ENODEV;
}
/* Verify that system PLL is locked (1 is calibrated) */
val = fa_readl(fa, fa->fa_carrier_csr_base,
&fa_spec_regs[ZFA_CAR_SYS_PLL]);
if (!val) {
dev_err(fa->msgdev, "System PLL not locked\n");
return -ENODEV;
}
/* Verify that DDR3 calibration is done (1 is calibrated) */
val = fa_readl(fa, fa->fa_carrier_csr_base,
&fa_spec_regs[ZFA_CAR_DDR_CAL]);
if (!val) {
dev_err(fa->msgdev, "DDR3 Calibration not done\n");
return -ENODEV;
}
/* Set DMA to transfer data from device to host */
fa_writel(fa, cdata->fa_dma_base,
&fa_spec_regs[ZFA_DMA_BR_DIR], 0);
/* register carrier data */
fa->carrier_data = cdata;
dev_info(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) */
static struct fmc_gpio fa_gpio_on[] = {
{
.gpio = FMC_GPIO_IRQ(0),
.mode = GPIOF_DIR_IN,
.irqmode = IRQF_TRIGGER_RISING,
}
};
static struct fmc_gpio fa_gpio_off[] = {
{
.gpio = FMC_GPIO_IRQ(0),
.mode = GPIOF_DIR_IN,
.irqmode = 0,
}
};
static int fa_spec_setup_irqs(struct fa_dev *fa)
{
struct fmc_device *fmc = fa->fmc;
struct fa_spec_data *spec_data = fa->carrier_data;
int err;
/* Request IRQ
* trick : vic needs the base address of teh core firing the irq
* It cannot provided throught irq_request() call therefore the trick
* is to set it by means of the field irq provided by the fmc device
*/
fmc->irq = spec_data->fa_irq_dma_base;
err = fmc_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);
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)
{
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);
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 = {
.get_gwname = fa_spec_get_gwname,
.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,
.dma_start = fa_spec_dma_start,
.dma_done = fa_spec_dma_done,
.dma_error = fa_spec_dma_error,
};
// 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/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/mm.h>
#include "fmc-adc-100m14b4cha.h"
#include "fa-spec.h"
static int gncore_dma_fill(struct zio_dma_sg *zsg)
{
struct gncore_dma_item *item = (struct gncore_dma_item *)zsg->page_desc;
struct scatterlist *sg = zsg->sg;
struct zio_channel *chan = zsg->zsgt->chan;
struct fa_dev *fa = chan->cset->zdev->priv_d;
struct fa_spec_data *spec_data = fa->carrier_data;
dma_addr_t tmp;
/* Prepare DMA item */
item->start_addr = zsg->dev_mem_off;
item->dma_addr_l = sg_dma_address(sg) & 0xFFFFFFFF;
item->dma_addr_h = (uint64_t)sg_dma_address(sg) >> 32;
item->dma_len = sg_dma_len(sg);
if (!sg_is_last(sg)) {/* more transfers */
/* uint64_t so it works on 32 and 64 bit */
tmp = zsg->zsgt->dma_page_desc_pool;
tmp += (zsg->zsgt->page_desc_size * (zsg->page_idx + 1));
item->next_addr_l = ((uint64_t)tmp) & 0xFFFFFFFF;
item->next_addr_h = ((uint64_t)tmp) >> 32;
item->attribute = 0x1; /* more items */
} else {
item->attribute = 0x0; /* last item */
}
/* The first item is written on the device */
if (zsg->page_idx == 0) {
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_ADDR], item->start_addr);
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_ADDR_L], item->dma_addr_l);
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_ADDR_H], item->dma_addr_h);
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_LEN], item->dma_len);
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_NEXT_L], item->next_addr_l);
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_NEXT_H], item->next_addr_h);
/* Set that there is a next item */
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_BR_LAST], item->attribute);
}
dev_dbg(fa->msgdev, "DMA item %d (block %d)\n"
" addr 0x%x\n"
" addr_l 0x%x\n"
" addr_h 0x%x\n"
" length %d\n"
" next_l 0x%x\n"
" next_h 0x%x\n"
" last 0x%x\n",
zsg->page_idx, zsg->block_idx,
item->start_addr, item->dma_addr_l, item->dma_addr_h,
item->dma_len, item->next_addr_l, item->next_addr_h,
item->attribute);
return 0;
}
int fa_spec_dma_start(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
struct fa_spec_data *spec_data = fa->carrier_data;
struct zio_channel *interleave = cset->interleave;
struct zfad_block *zfad_block = interleave->priv_d;
struct zio_block *blocks[fa->n_shots];
int i, err;
/*
* FIXME very inefficient because arm trigger already prepare
* something like zio_block_sg. In the future ZIO can alloc more
* than 1 block at time
*/
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->n_shots, GFP_ATOMIC);
if (IS_ERR(fa->zdma))
return PTR_ERR(fa->zdma);
/* Fix block memory offset
* FIXME when official ZIO has multishot and DMA
*/
for (i = 0; i < fa->zdma->n_blocks; ++i)
fa->zdma->sg_blocks[i].dev_mem_off = zfad_block[i].dev_mem_off;
err = zio_dma_map_sg(fa->zdma, sizeof(struct gncore_dma_item),
gncore_dma_fill);
if (err)
goto out_map_sg;
/* Start DMA transfer */
fa_writel(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_CTL_START], 1);
return 0;
out_map_sg:
zio_dma_free_sg(fa->zdma);
return err;
}
void fa_spec_dma_done(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
zio_dma_unmap_sg(fa->zdma);
zio_dma_free_sg(fa->zdma);
}
void fa_spec_dma_error(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
struct fa_spec_data *spec_data = fa->carrier_data;
uint32_t val;
fa_spec_dma_done(cset);
val = fa_readl(fa, spec_data->fa_dma_base,
&fa_spec_regs[ZFA_DMA_STA]);
if (val)
dev_err(fa->msgdev,
"DMA error (status 0x%x). All acquisition lost\n", val);
}
// 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, int irq_core_base,
uint32_t *irq_status)
{
/* Get current interrupts status */
*irq_status = fa_readl(fa, irq_core_base,
&fa_spec_regs[ZFA_IRQ_DMA_SRC]);
dev_dbg(fa->msgdev,
"core DMA: 0x%x fired an interrupt. IRQ status register: 0x%x\n",
irq_core_base, *irq_status);
if (*irq_status)
/* Clear current interrupts status */
fa_writel(fa, irq_core_base,
&fa_spec_regs[ZFA_IRQ_DMA_SRC], *irq_status);
}
/*
* zfad_irq
* @irq:
* @ptr: pointer to fmc_device
*
* The ADC svec firmware fires interrupt from a single wishbone core
* and throught the VIC ACQ_END and TRIG events. Note about "TRIG"
* event: the main reason to listen this interrupt was to read the
* intermediate time stamps in case of multishots.
* With the new firmware (>=3.0) the stamps come with the data,
* therefore the driver doesn't have to listen "TRIG" event. This
* enhancement remove completely the risk of loosing interrupt in case
* of small number of samples and makes the retry loop in the hanlder
* obsolete.
*/
irqreturn_t fa_spec_irq_handler(int irq_core_base, void *ptr)
{
struct fmc_device *fmc = ptr;
struct fa_dev *fa = fmc_get_drvdata(fmc);
struct zio_cset *cset = fa->zdev->cset;
uint32_t status;
/* irq to handle */
fa_get_irq_status(fa, irq_core_base, &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;
}
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)*/
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);
/* ack the irq */
fmc_irq_ack(fa->fmc);
return IRQ_HANDLED;
}
/*
* Copyright CERN 2012
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* Table of register masks, used by driver functions
*/
#include "fa-spec.h"
/* Definition of the fa spec registers field: offset - mask - isbitfield */
const struct zfa_field_desc fa_spec_regs[] = {
/* Carrier CSR */
[ZFA_CAR_FMC_PRES] = {0x04, 0x1, 1},
[ZFA_CAR_P2L_PLL] = {0x04, 0x2, 1},
[ZFA_CAR_SYS_PLL] = {0x04, 0x4, 1},
[ZFA_CAR_DDR_CAL] = {0x04, 0x8, 1},
[ZFA_CAR_FMC_RES] = {0x0c, 0x1, 1},
/* IRQ */
[ZFA_IRQ_DMA_DISABLE_MASK] = {0x00, 0x00000003, 0},
[ZFA_IRQ_DMA_ENABLE_MASK] = {0x04, 0x00000003, 0},
[ZFA_IRQ_DMA_MASK_STATUS] = {0x08, 0x00000003, 0},
[ZFA_IRQ_DMA_SRC] = {0x0C, 0x00000003, 0},
/* DMA */
[ZFA_DMA_CTL_SWP] = {0x00, 0x0000000C, 1},
[ZFA_DMA_CTL_ABORT] = {0x00, 0x00000002, 1},
[ZFA_DMA_CTL_START] = {0x00, 0x00000001, 1},
[ZFA_DMA_STA] = {0x04, 0x00000007, 0},
[ZFA_DMA_ADDR] = {0x08, 0xFFFFFFFF, 0},
[ZFA_DMA_ADDR_L] = {0x0C, 0xFFFFFFFF, 0},
[ZFA_DMA_ADDR_H] = {0x10, 0xFFFFFFFF, 0},
[ZFA_DMA_LEN] = {0x14, 0xFFFFFFFF, 0},
[ZFA_DMA_NEXT_L] = {0x18, 0xFFFFFFFF, 0},
[ZFA_DMA_NEXT_H] = {0x1C, 0xFFFFFFFF, 0},
[ZFA_DMA_BR_DIR] = {0x20, 0x00000002, 1},
[ZFA_DMA_BR_LAST] = {0x20, 0x00000001, 1},
};
// 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 */
unsigned int fa_dma_base;
unsigned int 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 <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;
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);
mdelay(50);
fa_writel(fa, fa->fa_carrier_csr_base,
&fa_svec_regfield[FA_CAR_FMC0_RES + fmc->slot_id], 0);
mdelay(50);
/* register carrier data */
fa->carrier_data = cdata;
return 0;
}
static int fa_svec_reset(struct fa_dev *fa)
{
return 0;
}
static void fa_svec_exit(struct fa_dev *fa)
{
kfree(fa->carrier_data);
}
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,
.dma_error = fa_svec_dma_error,
};
// 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>
#include "fmc-adc-100m14b4cha.h"
#include "fa-svec.h"
#include "vmebus.h"
#define VME_NO_ADDR_INCREMENT 1
/* FIXME: move to include again */
#ifndef lower_32_bits
#define lower_32_bits(n) ((u32)(n))
#endif /* lower_32_bits */
static void build_dma_desc(struct vme_dma *desc, unsigned long vme_addr,
void *addr_dest, ssize_t len)
{
struct vme_dma_attr *vme;
struct vme_dma_attr *pci;
memset(desc, 0, sizeof(struct vme_dma));
vme = &desc->src;
pci = &desc->dst;
desc->dir = VME_DMA_FROM_DEVICE;
desc->length = len;
desc->novmeinc = VME_NO_ADDR_INCREMENT;
desc->ctrl.pci_block_size = VME_DMA_BSIZE_4096;
desc->ctrl.pci_backoff_time = VME_DMA_BACKOFF_0;
desc->ctrl.vme_block_size = VME_DMA_BSIZE_4096;
desc->ctrl.vme_backoff_time = VME_DMA_BACKOFF_0;
vme->data_width = VME_D32;
vme->am = VME_A24_USER_DATA_SCT;
/*vme->am = VME_A24_USER_MBLT;*/
vme->addru = upper_32_bits(vme_addr);
vme->addrl = lower_32_bits(vme_addr);
pci->addru = upper_32_bits((unsigned long)addr_dest);
pci->addrl = lower_32_bits((unsigned long)addr_dest);
}
/* Endianess */
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN 0
#endif
#ifndef BIG_ENDIAN
#define BIG_ENDIAN 1
#endif
static int __get_endian(void)
{
int i = 1;
char *p = (char *)&i;
if (p[0] == 1)
return LITTLE_ENDIAN;
else
return BIG_ENDIAN;
}
static void __endianness(unsigned int byte_length, void *buffer)
{
int i, size;
uint32_t *ptr;
/* CPU may be little endian, VME is big endian */
if (__get_endian() == LITTLE_ENDIAN) {
ptr = buffer;
/* swap samples and trig timetag all seen as 32bits words */
size = byte_length/4;
for (i = 0; i < size; ++i, ++ptr)
*ptr = __be32_to_cpu(*ptr);
}
}
int fa_svec_dma_start(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
struct fa_svec_data *svec_data = fa->carrier_data;
struct zio_channel *interleave = cset->interleave;
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
* address has been computed after ACQ_END by looking to the
* trigger position see fa-irq.c::irq_acq_end.
* Be careful: the SVEC HW version expects an address of 32bits word
* therefore mem-offset in byte is translated into 32bit word
**/
fa_writel(fa, svec_data->fa_dma_ddr_addr,
&fa_svec_regfield[FA_DMA_DDR_ADDR],
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,
"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,
(int)fa_dma_block[i].block->datalen);
build_dma_desc(&desc, vme_addr,
fa_dma_block[i].block->data,
fa_dma_block[i].block->datalen);
if (vme_do_dma_kernel(&desc))
return -1;
__endianness(fa_dma_block[i].block->datalen,
fa_dma_block[i].block->data);
}
return 0;
}
void fa_svec_dma_done(struct zio_cset *cset)
{
/* nothing special to do */
}
void fa_svec_dma_error(struct zio_cset *cset)
{
struct fa_dev *fa = cset->zdev->priv_d;
dev_err(fa->msgdev,
"DMA error. All acquisition lost\n");
}
// 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_base;
unsigned int fa_dma_ddr_data; /* offset */
unsigned int 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__*/
This diff is collapsed.
......@@ -77,6 +77,19 @@ static struct zio_attribute zfat_ext_zattr[] = {
[FA100M14B4C_TATTR_CH4_DLY] = ZIO_ATTR_EXT("ch3-delay",
ZIO_RW_PERM,
ZFA_CH4_DLY, 0),
/* Time Trigger */
[FA100M14B4C_TATTR_TRG_TIM_SU] = ZIO_ATTR_EXT("trg-time-su",
ZIO_RW_PERM,
ZFA_UTC_TRIG_TIME_SECONDS_U,
0),
[FA100M14B4C_TATTR_TRG_TIM_SL] = ZIO_ATTR_EXT("trg-time-sl",
ZIO_RW_PERM,
ZFA_UTC_TRIG_TIME_SECONDS_L,
0),
[FA100M14B4C_TATTR_TRG_TIM_C] = ZIO_ATTR_EXT("trg-time-t",
ZIO_RW_PERM,
ZFA_UTC_TRIG_TIME_COARSE,
0),
/*
* Delay to apply on the trigger in sampling clock period. The default
......@@ -85,19 +98,27 @@ static struct zio_attribute zfat_ext_zattr[] = {
[FA100M14B4C_TATTR_EXT_DLY] = ZIO_ATTR_EXT("ext-delay", ZIO_RW_PERM,
ZFAT_EXT_DLY, 0),
/* Software Trigger */
[FA100M14B4C_TATTR_SW_FIRE] = ZIO_PARAM_EXT("sw-trg-fire", ZIO_WO_PERM,
ZFAT_SW, 0),
/* last trigger time stamp */
[FA100M14B4C_TATTR_TRG_S] = ZIO_PARAM_EXT("tstamp-trg-lst-s",
ZIO_RO_PERM, ZFA_UTC_TRIG_SECONDS, 0),
[FA100M14B4C_TATTR_TRG_SU] = ZIO_PARAM_EXT("tstamp-trg-lst-su",
ZIO_RO_PERM,
ZFA_UTC_TRIG_SECONDS_U, 0),
[FA100M14B4C_TATTR_TRG_SL] = ZIO_PARAM_EXT("tstamp-trg-lst-sl",
ZIO_RO_PERM,
ZFA_UTC_TRIG_SECONDS_L, 0),
[FA100M14B4C_TATTR_TRG_C] = ZIO_PARAM_EXT("tstamp-trg-lst-t",
ZIO_RO_PERM, ZFA_UTC_TRIG_COARSE, 0),
[FA100M14B4C_TATTR_TRG_F] = ZIO_PARAM_EXT("tstamp-trg-lst-b",
ZIO_RO_PERM, ZFA_UTC_TRIG_FINE, 0),
ZIO_RO_PERM,
ZFA_UTC_TRIG_COARSE, 0),
};
/*
* Reset to default value
*/
void zfat_trigger_source_reset(struct fa_dev *fa)
{
fa_writel(fa, fa->fa_adc_csr_base,
&zfad_regs[ZFAT_CFG_SRC],
FA100M14B4C_TRG_SRC_SW | FA100M14B4C_TRG_SRC_ALT);
}
/*
* zfat_conf_set
......@@ -108,9 +129,13 @@ static int zfat_conf_set(struct device *dev, struct zio_attribute *zattr,
uint32_t usr_val)
{
struct fa_dev *fa = get_zfadc(dev);
struct zio_ti *ti = to_zio_ti(dev);
void *baseoff = fa->fa_adc_csr_base;
uint32_t tmp_val = usr_val;
if (zattr->id >= ZFA_UTC_SECONDS_U &&
zattr->id <= ZFA_UTC_ACQ_END_COARSE)
baseoff = fa->fa_utc_base;
switch (zattr->id) {
case ZFAT_SHOTS_NB:
if (!tmp_val) {
......@@ -125,24 +150,6 @@ static int zfat_conf_set(struct device *dev, struct zio_attribute *zattr,
}
tmp_val--; /* Remove one sample for the trigger */
break;
case ZFAT_SW:
/* Fire if software trigger is enabled (index 5) */
if (!(ti->zattr_set.ext_zattr[FA100M14B4C_TATTR_SRC].value &
FA100M14B4C_TRG_SRC_SW)) {
dev_info(fa->msgdev, "sw trigger is not enabled\n");
return -EPERM;
}
/* Fire if nsamples!=0 */
if (!ti->nsamples) {
dev_info(fa->msgdev, "pre + post = 0: cannot acquire\n");
return -EINVAL;
}
/*
* The software trigger will be fired to force
* acquisition, so we don't care about current
* acquisition or other problems:
*/
break;
case ZFAT_CFG_SRC:
/*
* Do not copy to hardware when globally disabled
......@@ -155,7 +162,7 @@ static int zfat_conf_set(struct device *dev, struct zio_attribute *zattr,
return 0;
}
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[zattr->id], tmp_val);
fa_writel(fa, baseoff, &zfad_regs[zattr->id], tmp_val);
return 0;
}
......@@ -168,6 +175,11 @@ static int zfat_info_get(struct device *dev, struct zio_attribute *zattr,
uint32_t *usr_val)
{
struct fa_dev *fa = get_zfadc(dev);
void *baseoff = fa->fa_adc_csr_base;
if (zattr->id >= ZFA_UTC_SECONDS_U &&
zattr->id <= ZFA_UTC_ACQ_END_COARSE)
baseoff = fa->fa_utc_base;
switch (zattr->id) {
case ZFAT_CFG_SRC:
......@@ -178,7 +190,7 @@ static int zfat_info_get(struct device *dev, struct zio_attribute *zattr,
return 0;
}
*usr_val = fa_readl(fa, fa->fa_adc_csr_base, &zfad_regs[zattr->id]);
*usr_val = fa_readl(fa, baseoff, &zfad_regs[zattr->id]);
switch (zattr->id) {
case ZFAT_POST:
(*usr_val)++; /* add the trigger sample */
......@@ -296,6 +308,12 @@ static int zfat_data_done(struct zio_cset *cset)
kfree(zfad_block);
cset->interleave->priv_d = NULL;
/*
* Reset trigger source to avoid clean up the register for the next
* acquisition
*/
zfat_trigger_source_reset(fa);
return 0;
}
......@@ -313,7 +331,7 @@ static int zfat_arm_trigger(struct zio_ti *ti)
struct zio_block *block;
struct zfad_block *zfad_block;
unsigned int size;
uint32_t dev_mem_off, trg_src;
uint32_t dev_mem_off;
int i, err = 0;
dev_dbg(fa->msgdev, "Arming trigger\n");
......@@ -378,20 +396,13 @@ static int zfat_arm_trigger(struct zio_ti *ti)
zio_control_size(interleave));
/* Add to the vector of prepared blocks */
zfad_block[i].block = block;
zfad_block[i].dev_mem_off = dev_mem_off;
dev_mem_off += size;
dev_dbg(fa->msgdev, "next dev_mem_off 0x%x (+%d)\n",
dev_mem_off, size);
zfad_block[i].cset = ti->cset;
}
err = ti->cset->raw_io(ti->cset);
if (err != -EAGAIN && err != 0)
goto out_allocate;
/* Everything looks fine for the time being, enable the trigger sources */
trg_src = ti->zattr_set.ext_zattr[FA100M14B4C_TATTR_SRC].value;
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFAT_CFG_SRC], trg_src);
return err;
out_allocate:
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2020 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "platform_data/fmc-adc-100m14b4cha.h"
enum fa_spec_dev_offsets {
FA_SPEC_ADC_MEM_START = 0x000002000,
FA_SPEC_ADC_MEM_END = 0x000003FFF,
};
static const struct fmc_adc_platform_data fmc_adc_pdata = {
.flags = 0,
.calib_trig_time = 0,
.calib_trig_threshold = 0,
.calib_trig_internal = 0,
};
static int fa_spec_probe(struct platform_device *pdev) {
static struct resource fa_spec_fdt_res[] = {
{
.name = "fmc-adc-mem",
.flags = IORESOURCE_MEM,
},
{
.name = "fmc-adc-dma",
.flags = IORESOURCE_DMA,
},
{
.name = "fmc-adc-irq",
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
}};
struct platform_device_info pdevinfo = {
.parent = &pdev->dev,
.name = "fmc-adc-100m",
.id = PLATFORM_DEVID_AUTO,
.res = fa_spec_fdt_res,
.num_res = ARRAY_SIZE(fa_spec_fdt_res),
.data = &fmc_adc_pdata,
.size_data = sizeof(fmc_adc_pdata),
.dma_mask = DMA_BIT_MASK(32),
};
struct platform_device *pdev_child;
struct resource *rmem;
struct resource *r;
int irq;
int dma_dev_chan;
rmem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!rmem) {
dev_err(&pdev->dev, "Missing memory resource\n");
return -EINVAL;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "Missing IRQ number\n");
return -EINVAL;
}
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r) {
dev_err(&pdev->dev, "Missing DMA engine\n");
return -EINVAL;
}
dma_dev_chan = r->start;
fa_spec_fdt_res[0].parent = rmem;
fa_spec_fdt_res[0].start = rmem->start + FA_SPEC_ADC_MEM_START;
fa_spec_fdt_res[0].end = rmem->start + FA_SPEC_ADC_MEM_END;
fa_spec_fdt_res[1].start = dma_dev_chan;
fa_spec_fdt_res[2].start = irq;
pdev_child = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev_child))
return PTR_ERR(pdev_child);
platform_set_drvdata(pdev, pdev_child);
return 0;
}
static int fa_spec_remove(struct platform_device *pdev) {
struct platform_device *pdev_child = platform_get_drvdata(pdev);
platform_device_unregister(pdev_child);
return 0;
}
/**
* List of supported platform
*/
enum fa_spec_version {
FA_SPEC_VER = 0,
};
static const struct platform_device_id fa_spec_id_table[] = {
{
.name = "fmc-adc-100m-spec",
.driver_data = FA_SPEC_VER,
},
{
.name = "id:000010DC41444301",
.driver_data = FA_SPEC_VER,
},
{
.name = "id:000010dc41444301",
.driver_data = FA_SPEC_VER,
},
{},
};
static struct platform_driver fa_spec_driver = {
.driver =
{
.name = "fmc-adc-spec",
.owner = THIS_MODULE,
},
.id_table = fa_spec_id_table,
.probe = fa_spec_probe,
.remove = fa_spec_remove,
};
module_platform_driver(fa_spec_driver);
MODULE_AUTHOR("Federico Vaga <federico.vaga@cern.ch>");
MODULE_LICENSE("GPL");
MODULE_VERSION(VERSION);
MODULE_DESCRIPTION("Driver for the SPEC ADC 100 MSamples 14 bits 4 Channels");
MODULE_DEVICE_TABLE(platform, fa_spec_id_table);
MODULE_SOFTDEP("pre: spec_fmc_carrier fmc-adc-100m14b4ch");
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Some utility functions not supported in the current version of fmc-bus.
*
* Copyright (C) 2012-2019 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*/
#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;
}
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2020 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#ifndef __FMC_ADC_PDATA_H__
#define __FMC_ADC_PDATA_H__
#define FMC_ADC_BIG_ENDIAN BIT(0)
#define FMC_ADC_NOSQUASH_SCATTERLIST BIT(1)
/*
* In principle this should not be necessary. The two variants should
* be as close as possible to each other. But this is not the case, the DMA
* interface is different and we need to distinguish between SPEC and SVEC.
* NOTE any other carrier is not supported!
*/
#define FMC_ADC_SVEC BIT(3)
struct fmc_adc_platform_data {
unsigned long flags;
uint8_t calib_trig_time;
uint8_t calib_trig_threshold;
uint8_t calib_trig_internal;
};
#endif
......@@ -50,7 +50,8 @@ int fa_spi_xfer(struct fa_dev *fa, int cs, int num_bits,
while (fa_ioread(fa, fa->fa_spi_base + FA_SPI_CTRL)
& FA_SPI_CTRL_BUSY) {
if (jiffies > j) {
dev_err(fa->msgdev, "SPI transfer error\n");
dev_err(fa->msgdev, "SPI transfer error cs:%d, ctrl: 0x%x\n",
cs, fa_ioread(fa, fa->fa_spi_base + FA_SPI_CTRL));
err = -EIO;
goto out;
}
......
......@@ -11,7 +11,7 @@ REPO_PARENT ?= ../..
DESTDIR ?= /usr/local
GIT_VERSION := $(shell git describe --dirty --long --tags)
CFLAGS += -I../kernel -Wno-trigraphs -Wall -ggdb -O2 $(EXTRACFLAGS)
CFLAGS += -I../kernel -Wno-trigraphs -Wall -Werror -ggdb -O2 $(EXTRACFLAGS)
CFLAGS += -DGIT_VERSION="\"$(GIT_VERSION)\""
CC ?= $(CROSS_COMPILE)gcc
......
This diff is collapsed.
......@@ -53,7 +53,7 @@ const char *attribute[] = {
/* Write a sysfs attribute */
int fau_write_attribute(enum fau_attribute attr, uint32_t val)
{
int fd;
int ret, fd;
char buf[buf_len], fullpath[200];
/* convert val to string */
......@@ -66,9 +66,9 @@ int fau_write_attribute(enum fau_attribute attr, uint32_t val)
fd = open(fullpath, O_WRONLY);
if (fd < 0)
return -ENOENT;
write(fd, buf, strlen(buf));
ret = write(fd, buf, strlen(buf));
close(fd);
return 0;
return ret;
}
static void fau_help()
......
......@@ -41,7 +41,7 @@ static void print_version(char *pname)
int main(int argc, char **argv)
{
int fd, addr, count, usec;
int fd, addr, count, usec, ret;
int64_t tics;
if ((argc == 2) &&
......@@ -83,15 +83,15 @@ int main(int argc, char **argv)
char b[]={0x00, 0xff};
lseek(fd, addr, SEEK_SET);
write(fd, b + 1, 1);
ret = write(fd, b + 1, 1);
lseek(fd, addr, SEEK_SET);
write(fd, b + 0, 1);
ret = write(fd, b + 0, 1);
if (count > 1) {
tics += usec;
delay_to(tics);
}
} while (--count);
return 0;
return ret;
}
Subproject commit d8bef4d89361194c2e5644e751add9bd9ffa106d
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