Commit 05bbebf8 authored by Federico Vaga's avatar Federico Vaga

Merge branch 'release/v6.0.0.rc1'

parents 2f6f18d7 8ce74dac
......@@ -26,6 +26,13 @@ cppcheck:
script:
- make -C software cppcheck
flawfinder:
stage: static-analysis
image:
name: gitlab-registry.cern.ch/coht/common-containers/static-analysis:latest
script:
- make -C software/tools flawfinder
documentation:
stage: build
image:
......
......@@ -6,6 +6,26 @@
Changelog
=========
6.0.0 - 2021-09-07
==================
Added
-----
- hdl: configurable auto byte swap in hardware, useful for SVEC to reduce software complexity
- hdl,sw: DMA data is always little-endian
- sw: software version validation against FPGA version
- bld: flawfinder check on software tools
Changed
-------
- sw: offsets are not anymore in uV but they are just raw values
Fixed
-----
- sw: security fixes detected by flawfinder
- sw: fixes detected by checkpatch.pl
- sw: style fixes detected by checkpatch.pl
- sw: improve compatibility with newer ( > 3.10) Linux kernel versions
5.0.4 - 2021-07-09
==================
Fixed
......
......@@ -377,7 +377,7 @@ Mezzanine 1-wire Master
~~~~~~~~~~~~~~~~~~~~~~~
.. note::
FIXME talk about the themometer core in general-cores
FIXME talk about the thermometer core in general-cores
Mezzanine I2C Master
~~~~~~~~~~~~~~~~~~~~
......@@ -470,8 +470,8 @@ register enables the sampling clock (Si570 chip), and the other
internal components. Also, in order to use the input offset DACs, the
``OFFSET_DAC_CLR_N`` field must be set to one.
The field ``MAN_BITSLIP`` allows to ’manually’ control the ADC data
alignment in the de-serialiser. The fields ``TRIG_LED`` and
The field ``SERDES_CALIB`` allows to ’manually’ restart the timing
calibration and alignment in the de-serialiser. The fields ``TRIG_LED`` and
``ACQ_LED`` allows to control the FMC front panel LEDs. Those four
fields are for test purpose only and must stay zero in normal
operation.
......@@ -1047,6 +1047,9 @@ state.
The start of an acquisition is prohibited if either the number of
shots or the number of post-trigger samples is equal to zero.
.. note::
Acquired data are always stored to be read in little endian.
Single-shot Mode
----------------
......
......@@ -195,16 +195,16 @@ chN-50ohm-term
turn on the termination resistor. Default is 0.
chN-offset
The user offset is an integer value in the range [-5000000,5000000], and
it represents microvolts. The offset represents the center-scale
of conversion for the input channel. Internally, a DAC is used to
The user offset is an integer value in the range [-5.000V, +4.999V]. It
follows the DAC data format, so the range is describe by 16bits from 0x0000
(-5.000V) to 0xFFFF (+4.999V). Internally, a DAC is used to
generate the requested voltage, which is then subtracted from the
input signal. DAC values are corrected according to the
calibration values retrieved from the FMC EEPROM. For this reason,
the offset may saturate at values less than +/- 5V.
chN-offset-zero
The necessary offset to to bring the signal to 0 in microvolts (it must be
The necessary offset to to bring the signal to 0 in Volts (it must be
withing the range of chN-offset).
chN-vref
......
......@@ -41,11 +41,9 @@ memory-map:
range: 3
description: Offset DACs clear (active low)
- field:
name: man_bitslip
name: serdes_calib
range: 4
description: Manual serdes bitslip (ignore on read)
x-hdl:
type: wire
description: Initial serdes calibration
- field:
name: trig_led
range: 6
......
......@@ -15,7 +15,7 @@ package fmc_adc_100ms_csr_pkg is
ctl_fsm_cmd : std_logic_vector(1 downto 0);
ctl_fmc_clk_oe : std_logic;
ctl_offset_dac_clr_n : std_logic;
ctl_man_bitslip : std_logic;
ctl_serdes_calib : std_logic;
ctl_trig_led : std_logic;
ctl_acq_led : std_logic;
ctl_clear_trig_stat : std_logic;
......@@ -47,7 +47,6 @@ package fmc_adc_100ms_csr_pkg is
type t_fmc_adc_100ms_csr_slave_out is record
ctl_fsm_cmd : std_logic_vector(1 downto 0);
ctl_man_bitslip : std_logic;
ctl_clear_trig_stat : std_logic;
ctl_calib_apply : std_logic;
sta_fsm : std_logic_vector(2 downto 0);
......@@ -120,6 +119,7 @@ architecture syn of fmc_adc_100ms_csr is
signal wb_wip : std_logic;
signal ctl_fmc_clk_oe_reg : std_logic;
signal ctl_offset_dac_clr_n_reg : std_logic;
signal ctl_serdes_calib_reg : std_logic;
signal ctl_trig_led_reg : std_logic;
signal ctl_acq_led_reg : std_logic;
signal ctl_wreq : std_logic;
......@@ -250,7 +250,7 @@ begin
fmc_adc_100ms_csr_o.ctl_fsm_cmd <= wr_dat_d0(1 downto 0);
fmc_adc_100ms_csr_o.ctl_fmc_clk_oe <= ctl_fmc_clk_oe_reg;
fmc_adc_100ms_csr_o.ctl_offset_dac_clr_n <= ctl_offset_dac_clr_n_reg;
fmc_adc_100ms_csr_o.ctl_man_bitslip <= wr_dat_d0(4);
fmc_adc_100ms_csr_o.ctl_serdes_calib <= ctl_serdes_calib_reg;
fmc_adc_100ms_csr_o.ctl_trig_led <= ctl_trig_led_reg;
fmc_adc_100ms_csr_o.ctl_acq_led <= ctl_acq_led_reg;
fmc_adc_100ms_csr_o.ctl_clear_trig_stat <= wr_dat_d0(8);
......@@ -260,6 +260,7 @@ begin
if rst_n_i = '0' then
ctl_fmc_clk_oe_reg <= '0';
ctl_offset_dac_clr_n_reg <= '0';
ctl_serdes_calib_reg <= '0';
ctl_trig_led_reg <= '0';
ctl_acq_led_reg <= '0';
ctl_wack <= '0';
......@@ -267,6 +268,7 @@ begin
if ctl_wreq = '1' then
ctl_fmc_clk_oe_reg <= wr_dat_d0(2);
ctl_offset_dac_clr_n_reg <= wr_dat_d0(3);
ctl_serdes_calib_reg <= wr_dat_d0(4);
ctl_trig_led_reg <= wr_dat_d0(6);
ctl_acq_led_reg <= wr_dat_d0(7);
end if;
......@@ -624,7 +626,7 @@ begin
end process;
-- Process for read requests.
process (rd_adr_d0, rd_req_d0, fmc_adc_100ms_csr_i.ctl_fsm_cmd, ctl_fmc_clk_oe_reg, ctl_offset_dac_clr_n_reg, fmc_adc_100ms_csr_i.ctl_man_bitslip, ctl_trig_led_reg, ctl_acq_led_reg, fmc_adc_100ms_csr_i.ctl_clear_trig_stat, fmc_adc_100ms_csr_i.ctl_calib_apply, fmc_adc_100ms_csr_i.sta_fsm, fmc_adc_100ms_csr_i.sta_serdes_pll, fmc_adc_100ms_csr_i.sta_serdes_synced, fmc_adc_100ms_csr_i.sta_acq_cfg, fmc_adc_100ms_csr_i.sta_fmc_nr, fmc_adc_100ms_csr_i.sta_calib_busy, fmc_adc_100ms_csr_i.trig_stat_ext, fmc_adc_100ms_csr_i.trig_stat_sw, fmc_adc_100ms_csr_i.trig_stat_time, fmc_adc_100ms_csr_i.trig_stat_ch1, fmc_adc_100ms_csr_i.trig_stat_ch2, fmc_adc_100ms_csr_i.trig_stat_ch3, fmc_adc_100ms_csr_i.trig_stat_ch4, trig_en_ext_reg, fmc_adc_100ms_csr_i.trig_en_sw, trig_en_time_reg, fmc_adc_100ms_csr_i.trig_en_aux_time, trig_en_ch1_reg, trig_en_ch2_reg, trig_en_ch3_reg, trig_en_ch4_reg, trig_pol_ext_reg, trig_pol_ch1_reg, trig_pol_ch2_reg, trig_pol_ch3_reg, trig_pol_ch4_reg, ext_trig_dly_reg, shots_nbr_reg, fmc_adc_100ms_csr_i.shots_remain, fmc_adc_100ms_csr_i.multi_depth, fmc_adc_100ms_csr_i.trig_pos, fmc_adc_100ms_csr_i.fs_freq, downsample_reg, pre_samples_reg, post_samples_reg, fmc_adc_100ms_csr_i.samples_cnt, fmc_adc_ch1_i.dat, fmc_adc_ch1_rack, fmc_adc_ch2_i.dat, fmc_adc_ch2_rack, fmc_adc_ch3_i.dat, fmc_adc_ch3_rack, fmc_adc_ch4_i.dat, fmc_adc_ch4_rack) begin
process (rd_adr_d0, rd_req_d0, fmc_adc_100ms_csr_i.ctl_fsm_cmd, ctl_fmc_clk_oe_reg, ctl_offset_dac_clr_n_reg, ctl_serdes_calib_reg, ctl_trig_led_reg, ctl_acq_led_reg, fmc_adc_100ms_csr_i.ctl_clear_trig_stat, fmc_adc_100ms_csr_i.ctl_calib_apply, fmc_adc_100ms_csr_i.sta_fsm, fmc_adc_100ms_csr_i.sta_serdes_pll, fmc_adc_100ms_csr_i.sta_serdes_synced, fmc_adc_100ms_csr_i.sta_acq_cfg, fmc_adc_100ms_csr_i.sta_fmc_nr, fmc_adc_100ms_csr_i.sta_calib_busy, fmc_adc_100ms_csr_i.trig_stat_ext, fmc_adc_100ms_csr_i.trig_stat_sw, fmc_adc_100ms_csr_i.trig_stat_time, fmc_adc_100ms_csr_i.trig_stat_ch1, fmc_adc_100ms_csr_i.trig_stat_ch2, fmc_adc_100ms_csr_i.trig_stat_ch3, fmc_adc_100ms_csr_i.trig_stat_ch4, trig_en_ext_reg, fmc_adc_100ms_csr_i.trig_en_sw, trig_en_time_reg, fmc_adc_100ms_csr_i.trig_en_aux_time, trig_en_ch1_reg, trig_en_ch2_reg, trig_en_ch3_reg, trig_en_ch4_reg, trig_pol_ext_reg, trig_pol_ch1_reg, trig_pol_ch2_reg, trig_pol_ch3_reg, trig_pol_ch4_reg, ext_trig_dly_reg, shots_nbr_reg, fmc_adc_100ms_csr_i.shots_remain, fmc_adc_100ms_csr_i.multi_depth, fmc_adc_100ms_csr_i.trig_pos, fmc_adc_100ms_csr_i.fs_freq, downsample_reg, pre_samples_reg, post_samples_reg, fmc_adc_100ms_csr_i.samples_cnt, fmc_adc_ch1_i.dat, fmc_adc_ch1_rack, fmc_adc_ch2_i.dat, fmc_adc_ch2_rack, fmc_adc_ch3_i.dat, fmc_adc_ch3_rack, fmc_adc_ch4_i.dat, fmc_adc_ch4_rack) begin
-- By default ack read requests
rd_dat_d0 <= (others => 'X');
fmc_adc_ch1_re <= '0';
......@@ -640,7 +642,7 @@ begin
rd_dat_d0(1 downto 0) <= fmc_adc_100ms_csr_i.ctl_fsm_cmd;
rd_dat_d0(2) <= ctl_fmc_clk_oe_reg;
rd_dat_d0(3) <= ctl_offset_dac_clr_n_reg;
rd_dat_d0(4) <= fmc_adc_100ms_csr_i.ctl_man_bitslip;
rd_dat_d0(4) <= ctl_serdes_calib_reg;
rd_dat_d0(5) <= '0';
rd_dat_d0(6) <= ctl_trig_led_reg;
rd_dat_d0(7) <= ctl_acq_led_reg;
......
......@@ -40,6 +40,8 @@ entity fmc_adc_100Ms_core is
g_TRIG_DELAY_SW : natural := 9;
-- FMC-ADC identification number
g_FMC_ADC_NR : natural := 0;
-- Data endianness. If set, swap memory data byte
g_BYTE_SWAP : boolean := false;
-- WB interface configuration
g_WB_CSR_MODE : t_wishbone_interface_mode := PIPELINED;
g_WB_CSR_GRANULARITY : t_wishbone_address_granularity := BYTE);
......@@ -71,7 +73,7 @@ entity fmc_adc_100Ms_core is
acq_stop_p_o : out std_logic;
acq_end_p_o : out std_logic;
-- Trigger time-tag inputs
-- Trigger time-tag inputs (sys_clk_i)
trigger_tag_i : in t_timetag;
time_trig_i : in std_logic;
aux_time_trig_i : in std_logic;
......@@ -151,8 +153,7 @@ architecture rtl of fmc_adc_100Ms_core is
-- SerDes
signal serdes_out_data : std_logic_vector(63 downto 0);
signal serdes_out_data_synced : std_logic_vector(63 downto 0);
signal serdes_man_bitslip : std_logic;
signal serdes_man_bitslip_sync : std_logic;
signal serdes_calib_sync : std_logic;
signal serdes_locked : std_logic;
signal serdes_locked_sync : std_logic;
signal serdes_synced : std_logic;
......@@ -293,6 +294,7 @@ architecture rtl of fmc_adc_100Ms_core is
-- Wishbone to DDR flowcontrol FIFO
signal wb_ddr_fifo_din : std_logic_vector(64 downto 0);
signal wb_ddr_fifo_dout : std_logic_vector(64 downto 0);
signal wb_ddr_fifo_dout2 : std_logic_vector(63 downto 0);
signal wb_ddr_fifo_empty : std_logic;
signal wb_ddr_fifo_full : std_logic;
signal wb_ddr_fifo_wr : std_logic;
......@@ -427,8 +429,8 @@ begin
port map (
clk_i => fs_clk,
rst_n_a_i => '1',
d_i => serdes_man_bitslip,
q_o => serdes_man_bitslip_sync);
d_i => csr_regout.ctl_serdes_calib,
q_o => serdes_calib_sync);
cmp_adc_serdes : entity work.ltc2174_2l16b_receiver
generic map (
......@@ -443,7 +445,7 @@ begin
adc_outb_p_i => adc_outb_p_i,
adc_outb_n_i => adc_outb_n_i,
serdes_arst_i => serdes_arst,
serdes_bslip_i => serdes_man_bitslip_sync,
serdes_calib_i => serdes_calib_sync,
serdes_locked_o => serdes_locked,
serdes_synced_o => serdes_synced,
adc_data_o => serdes_out_data,
......@@ -484,7 +486,6 @@ begin
fmc_adc_ch4_o => wb_channel_in(4));
csr_regin.ctl_fsm_cmd <= fsm_cmd;
csr_regin.ctl_man_bitslip <= serdes_man_bitslip;
csr_regin.ctl_clear_trig_stat <= trig_storage_clear;
csr_regin.ctl_calib_apply <= sync_calib_apply;
......@@ -530,12 +531,10 @@ begin
if rising_edge(sys_clk_i) then
if ctl_reg_wr = '1' then
fsm_cmd <= csr_regout.ctl_fsm_cmd;
serdes_man_bitslip <= csr_regout.ctl_man_bitslip;
trig_storage_clear <= csr_regout.ctl_clear_trig_stat;
sync_calib_apply <= csr_regout.ctl_calib_apply;
else
fsm_cmd <= (others => '0');
serdes_man_bitslip <= '0';
trig_storage_clear <= '0';
sync_calib_apply <= '0';
end if;
......@@ -1633,6 +1632,20 @@ begin
-- Convert to 32-bit word addressing for Wishbone
wb_ddr_skidpad_adr_in <= std_logic_vector(ram_addr_cnt);
gen_no_byte_swap: if not g_BYTE_SWAP generate
wb_ddr_fifo_dout2 <= wb_ddr_fifo_dout(63 downto 0);
end generate;
gen_byte_swap: if g_BYTE_SWAP generate
wb_ddr_fifo_dout2 (63 downto 32) <= ( wb_ddr_fifo_dout(39 downto 32)
& wb_ddr_fifo_dout(47 downto 40)
& wb_ddr_fifo_dout(55 downto 48)
& wb_ddr_fifo_dout(63 downto 56));
wb_ddr_fifo_dout2 (31 downto 0) <= ( wb_ddr_fifo_dout(7 downto 0)
& wb_ddr_fifo_dout(15 downto 8)
& wb_ddr_fifo_dout(23 downto 16)
& wb_ddr_fifo_dout(31 downto 24));
end generate;
inst_skidpad: entity work.wb_skidpad2
generic map (
g_adrbits => ram_addr_cnt'length,
......@@ -1644,7 +1657,7 @@ begin
stb_i => wb_ddr_skidpad_stb_in,
adr_i => wb_ddr_skidpad_adr_in,
dat_i => wb_ddr_fifo_dout(63 downto 0),
dat_i => wb_ddr_fifo_dout2,
sel_i => (others => '1'),
we_i => '1',
stall_o => wb_ddr_skidpad_stall,
......
......@@ -41,6 +41,8 @@ entity fmc_adc_mezzanine is
g_TAG_ADJUST : natural := 27;
-- FMC-ADC identification number
g_FMC_ADC_NR : natural := 0;
-- Data endianness. If set, swap memory data byte
g_BYTE_SWAP : boolean := false;
-- WB interface configuration
g_WB_MODE : t_wishbone_interface_mode := PIPELINED;
g_WB_GRANULARITY : t_wishbone_address_granularity := BYTE);
......@@ -67,11 +69,11 @@ entity fmc_adc_mezzanine is
acq_cfg_ok_o : out std_logic;
-- Auxiliary trigger input wishbone interface
wb_trigin_slave_i : in t_wishbone_slave_in;
wb_trigin_slave_i : in t_wishbone_slave_in := c_DUMMY_WB_SLAVE_IN;
wb_trigin_slave_o : out t_wishbone_slave_out;
-- Trigout wishbone interface
wb_trigout_slave_i : in t_wishbone_slave_in;
wb_trigout_slave_i : in t_wishbone_slave_in := c_DUMMY_WB_SLAVE_IN;
wb_trigout_slave_o : out t_wishbone_slave_out;
-- FMC interface
......@@ -309,6 +311,7 @@ begin
g_TRIG_DELAY_EXT => g_TRIG_DELAY_EXT,
g_TRIG_DELAY_SW => g_TRIG_DELAY_SW,
g_FMC_ADC_NR => g_FMC_ADC_NR,
g_BYTE_SWAP => g_BYTE_SWAP,
g_WB_CSR_MODE => PIPELINED,
g_WB_CSR_GRANULARITY => BYTE)
port map (
......
......@@ -10,8 +10,8 @@
`define FMC_ADC_100MS_CSR_CTL_FMC_CLK_OE 'h4
`define FMC_ADC_100MS_CSR_CTL_OFFSET_DAC_CLR_N_OFFSET 3
`define FMC_ADC_100MS_CSR_CTL_OFFSET_DAC_CLR_N 'h8
`define FMC_ADC_100MS_CSR_CTL_MAN_BITSLIP_OFFSET 4
`define FMC_ADC_100MS_CSR_CTL_MAN_BITSLIP 'h10
`define FMC_ADC_100MS_CSR_CTL_SERDES_CALIB_OFFSET 4
`define FMC_ADC_100MS_CSR_CTL_SERDES_CALIB 'h10
`define FMC_ADC_100MS_CSR_CTL_TRIG_LED_OFFSET 6
`define FMC_ADC_100MS_CSR_CTL_TRIG_LED 'h40
`define FMC_ADC_100MS_CSR_CTL_ACQ_LED_OFFSET 7
......
......@@ -531,10 +531,11 @@ begin -- architecture arch
d_i => fmc_irq(I),
q_o => irq_vector(I));
cmp_fmc_adc_mezzanine : fmc_adc_mezzanine
cmp_fmc_adc_mezzanine : entity work.fmc_adc_mezzanine
generic map (
g_MULTISHOT_RAM_SIZE => g_MULTISHOT_RAM_SIZE,
g_SPARTAN6_USE_PLL => TRUE,
g_BYTE_SWAP => TRUE,
g_FMC_ADC_NR => I,
g_WB_MODE => PIPELINED,
g_WB_GRANULARITY => BYTE)
......
......@@ -8,12 +8,16 @@ VMEBUS_EXTRA_SYMBOLS-$(CONFIG_FMC_ADC_SVEC) := $(VMEBUS_ABS)/driver/Module.symve
ZIO_VERSION = $(shell cd $(ZIO_ABS); git describe --always --dirty --long --tags)
VERSION = $(shell cd $(src); git describe --always --dirty --long --tags)
VER_MAJ := $(shell echo $(subst v,,$(VERSION)) | cut -d '.' -f 1)
VER_MIN := $(shell echo $(subst v,,$(VERSION)) | cut -d '.' -f 2)
FA_VERSION_BLD := $(shell printf "0x%02x%02x0000" $(VER_MAJ) $(VER_MIN))
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 += -DFA_VERSION_BLD=$(FA_VERSION_BLD)
ccflags-y += -DCONFIG_FMC_ADC_SVEC
ccflags-y += -I$(src)
ccflags-y += -I$(ZIO_ABS)/include
......
// SPDX-FileCopyrightText: 2020 CERN (home.cern)
//
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2020 CERN (home.cern)
/*
* EEPROM calibration block retreival code for fa-dev
......@@ -16,10 +15,10 @@
#include <linux/jiffies.h>
#include "fmc-adc-100m14b4cha-private.h"
static int fa_calib_temp_period = 0;
static int fa_calib_temp_period;
module_param_named(temp_calib_period, fa_calib_temp_period, int, 0444);
static int fa_calib_temp = 0;
static int fa_calib_temp;
module_param_named(temp_calib, fa_calib_temp, int, 0444);
/* This identity calibration is used as default */
......@@ -48,7 +47,7 @@ static int fa_calib_apply(struct fa_dev *fa)
return -EBUSY;
}
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_CTL_CALIB_APPLY], 1);
ndelay(100);
ndelay(100);
if (fa_calib_is_busy(fa)) {
dev_err(&fa->pdev->dev,
"%s Calibration value applied but still 'busy'\n",
......@@ -134,7 +133,7 @@ static const int64_t gain_dac_error_slope_fix[] = {
static int fa_calib_dac_gain_fix(int range, uint32_t gain_c,
int32_t delta_temp)
{
int64_t error;
int64_t error;
error = gain_dac_error_slope_fix[range] * delta_temp;
error /= 0x2000; /* see comment above for gain_dac_error_slope_fix */
......@@ -148,7 +147,7 @@ static bool fa_calib_is_compensation_on(struct fa_dev *fa)
if (unlikely((fa->flags & FA_DEV_F_PATTERN_DATA)))
return false;
if (unlikely(fa_calib_temp))
if (unlikely(fa_calib_temp))
return true;
return false;
......@@ -208,47 +207,52 @@ static int fa_dac_offset_set(struct fa_dev *fa, unsigned int chan,
return fa_spi_xfer(fa, FA_SPI_SS_DAC(chan), 16, val, NULL);
}
static int64_t fa_dac_offset_raw_get(int32_t offset)
static uint16_t fa_dac_offset_raw_calibrate(struct fa_dev *fa,
uint16_t raw_offset,
int gain, int offset)
{
int32_t signed_offset = raw_offset - 0x8000;
int64_t hwval;
hwval = offset * 0x8000LL / 5000000;
if (hwval == 0x8000)
hwval = 0x7fff; /* -32768 .. 32767 */
return hwval;
}
static int64_t fa_dac_offset_raw_calibrate(int32_t raw_offset,
int gain, int offset)
{
int64_t hwval;
hwval = ((signed_offset + offset) * gain) >> 15; /* signed */
hwval += 0x8000; /* offset binary */
dev_dbg(&fa->pdev->dev,
"Final DAC calibrated value: (0x%08x + 0x%08x) * 0x%08x = 0x%08llx\n",
signed_offset, offset, gain, hwval);
hwval = ((raw_offset + offset) * gain) >> 15; /* signed */
hwval += 0x8000; /* offset binary */
if (hwval < 0)
/* Saturate */
if (hwval < 0) {
hwval = 0;
if (hwval > 0xffff)
dev_warn(&fa->pdev->dev,
"Final DAC calibrated value: lower saturation, set 0x%04llx",
hwval);
}
if (hwval > 0xffff) {
hwval = 0xffff;
dev_warn(&fa->pdev->dev,
"Final DAC calibrated value: lower saturation, set 0x%04llx",
hwval);
}
return hwval;
}
static int fa_dac_offset_get(struct fa_dev *fa, unsigned int chan)
static int fa_dac_offset_get(struct fa_dev *fa, unsigned int chan, uint16_t *offset)
{
int32_t off_uv = fa->user_offset[chan] + fa->zero_offset[chan];
int32_t user = fa->user_offset[chan];
int32_t zero = fa->zero_offset[chan];
int32_t __offset = (user + zero) - 0x8000; /* Bring back to DAC format */
if (WARN(off_uv < DAC_SAT_LOW,
"DAC lower saturation %d < %d\n",
off_uv, DAC_SAT_LOW)) {
off_uv = DAC_SAT_LOW;
}
if (WARN(off_uv > DAC_SAT_UP,
"DAC upper saturation %d > %d\n",
off_uv, DAC_SAT_UP)) {
off_uv = DAC_SAT_UP;
if (__offset & ~DAC_VAL_MASK) {
dev_err(&fa->pdev->dev,
"DAC offset value overflows 16bits. {user: 0x%04x, zero: 0x%04x, sum: 0x%08x}\n",
user, zero, __offset);
return -EINVAL;
}
return off_uv;
*offset = __offset;
return 0;
}
/**
......@@ -262,12 +266,16 @@ static int fa_dac_offset_get(struct fa_dev *fa, unsigned int chan)
int fa_calib_dac_config_chan(struct fa_dev *fa, unsigned int chan,
int32_t temperature, unsigned int flags)
{
int32_t off_uv = fa_dac_offset_get(fa, chan);
int32_t off_uv_raw = fa_dac_offset_raw_get(off_uv);
int range = fa->range[chan];
struct fa_calib_stanza *cal = &fa->calib.dac[range];
uint16_t value;
int range = fa->range[chan];
struct fa_calib_stanza *cal = &fa->calib.dac[range];
int gain;
int hwval;
int err;
err = fa_dac_offset_get(fa, chan, &value);
if (err)
return err;
if (fa_calib_is_compensation_on(fa)) {
int32_t delta_temp;
......@@ -287,10 +295,10 @@ int fa_calib_dac_config_chan(struct fa_dev *fa, unsigned int chan,
__func__, chan, range, gain, cal->offset[chan]);
}
hwval = fa_dac_offset_raw_calibrate(off_uv_raw, gain,
hwval = fa_dac_offset_raw_calibrate(fa, value, gain,
cal->offset[chan]);
return fa_dac_offset_set(fa, chan, hwval);
return fa_dac_offset_set(fa, chan, hwval);
}
void fa_calib_config_chan(struct fa_dev *fa, unsigned int chan,
......@@ -311,6 +319,14 @@ void fa_calib_config(struct fa_dev *fa)
fa_calib_config_chan(fa, i, temperature, 0);
spin_unlock(&fa->zdev->cset->lock);
}
static void __fa_calib_gain_update(struct fa_dev *fa)
{
fa_calib_config(fa);
mod_timer(&fa->calib_timer, jiffies + HZ * fa_calib_temp_period);
}
/**
* Periodically update gain calibration values
* @fa: FMC ADC device
......@@ -320,14 +336,17 @@ void fa_calib_config(struct fa_dev *fa)
* linear behavior with respect to the temperature.
*
*/
#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE
static void fa_calib_gain_update(struct timer_list *timer)
{
__fa_calib_gain_update(from_timer(fa, timer, calib_timer));
}
#else
static void fa_calib_gain_update(unsigned long arg)
{
struct fa_dev *fa = (void *)arg;
fa_calib_config(fa);
mod_timer(&fa->calib_timer, jiffies + HZ * fa_calib_temp_period);
__fa_calib_gain_update((void *)arg);
}
#endif
/* Actual verification code */
static int fa_verify_calib_stanza(struct device *msgdev, char *name, int r,
struct fa_calib_stanza *cal)
......@@ -493,14 +512,19 @@ int fa_calib_init(struct fa_dev *fa)
fa_calib_write(fa, &calib);
/* First calibration.
The board has just been reset by the carrier before calling this
driver and reading the temperature read needs at least 350ms */
* The board has just been reset by the carrier before calling this
* driver and reading the temperature read needs at least 350ms
*/
msleep(400);
fa_calib_config(fa);
/* Prepare the timely recalibration */
if (fa_calib_is_compensation_on(fa) && fa_calib_temp_period) {
#if KERNEL_VERSION(4, 15, 0) <= LINUX_VERSION_CODE
timer_setup(&fa->calib_timer, fa_calib_gain_update, 0);
#else
setup_timer(&fa->calib_timer, fa_calib_gain_update, (unsigned long)fa);
#endif
mod_timer(&fa->calib_timer,
jiffies + HZ * fa_calib_temp_period);
}
......
......@@ -12,6 +12,7 @@
#include <linux/mod_devicetable.h>
#include <uapi/linux/ipmi/fru.h>
#include <linux/fmc.h>
#include <linux/io.h>
#include "fmc-adc-100m14b4cha-private.h"
#include <platform_data/fmc-adc-100m14b4cha.h>
......@@ -19,6 +20,12 @@
static int fa_enable_test_data_fpga;
module_param_named(enable_test_data_fpga, fa_enable_test_data_fpga, int, 0444);
static int version_ignore;
module_param(version_ignore, int, 0644);
MODULE_PARM_DESC(version_ignore,
"Ignore the version declared in the FPGA and force the driver to load all components (default 0)");
#define FA_EEPROM_TYPE "at24c64"
......@@ -36,6 +43,29 @@ static const int zfad_hw_range[] = {
struct workqueue_struct *fa_workqueue;
static int fa_sg_alloc_table_from_pages(struct sg_table *sgt,
struct page **pages,
unsigned int n_pages,
unsigned int offset,
unsigned long size,
unsigned int max_segment,
gfp_t gfp_mask)
{
#if KERNEL_VERSION(5, 10, 0) <= LINUX_VERSION_CODE
struct scatterlist *sg;
sg = __sg_alloc_table_from_pages(sgt, pages, n_pages, offset, size,
max_segment, NULL, 0, gfp_mask);
if (IS_ERR(sg))
return PTR_ERR(sg);
else
return 0;
#else
return __sg_alloc_table_from_pages(sgt, pages, n_pages, offset, size,
max_segment, gfp_mask);
#endif
}
/**
* Enable/Disable Data Output Randomizer
* @fa: the adc descriptor
......@@ -46,17 +76,20 @@ int fa_adc_output_randomizer_set(struct fa_dev *fa, bool enable)
uint32_t tx, rx;
int err;
tx = 0x8000;
/* Read register A1 */
tx = 0x8000;
tx |= (1 << 8);
err = fa_spi_xfer(fa, FA_SPI_SS_ADC, 16, tx, &rx);
if (err)
return err;
/* Set or clear RAND bit */
if (enable)
rx |= BIT(6);
else
rx &= ~BIT(6);
/* Write back A1 */
tx = 0x0000;
tx |= (1 << 8);
tx |= (rx & 0xFF);
......@@ -76,7 +109,8 @@ bool fa_adc_is_output_randomizer(struct fa_dev *fa)
uint32_t tx, rx;
int err;
tx = 0x8000;
/* Read register A1 */
tx = 0x8000;
tx |= (1 << 8);
err = fa_spi_xfer(fa, FA_SPI_SS_ADC, 16, tx, &rx);
if (err)
......@@ -127,13 +161,13 @@ int fa_trigger_software(struct fa_dev *fa)
return -EPERM;
}
/* Fire if nsamples!=0 */
/* Fire if nsamples!=0 */
if (!ti->nsamples) {
dev_info(&fa->pdev->dev, "pre + post = 0: cannot acquire\n");
return -EINVAL;
}
/*
/*
* We can do a software trigger if the FSM is not in
* the WAIT trigger status. Wait for it.
* Remember that: timeout is in us, a sample takes 10ns
......@@ -347,7 +381,7 @@ err:
* @enable 0 to disable, 1 to enable
*/
int fa_adc_data_pattern_get(struct fa_dev *fa, uint16_t *pattern,
unsigned int *enable)
unsigned int *enable)
{
uint32_t tx, rx;
int err;
......@@ -443,8 +477,7 @@ int zfad_fsm_command(struct fa_dev *fa, uint32_t command)
if (command == FA100M14B4C_CMD_START) {
if (!fa_adc_is_serdes_ready(fa)) {
dev_err(fa->msgdev,
"Cannot start acquisition: "
"SerDes PLL not locked or synchronized (0x%08x)\n",
"Cannot start acquisition: SerDes PLL not locked or synchronized (0x%08x)\n",
fa_ioread(fa, fa->fa_adc_csr_base + ADC_CSR_STA_REG_OFFSET));
return -EBUSY;
}
......@@ -459,8 +492,8 @@ int zfad_fsm_command(struct fa_dev *fa, uint32_t command)
* from zfat_arm_trigger() or zfad_input_cset()
*/
if (!(cset->ti->flags & ZIO_TI_ARMED)) {
dev_info(fa->msgdev, "Cannot start acquisition: "
"Trigger refuses to arm\n");
dev_info(fa->msgdev,
"Cannot start acquisition: Trigger refuses to arm\n");
return -EIO;
}
......@@ -484,7 +517,11 @@ static void fa_init_timetag(struct fa_dev *fa)
{
unsigned long seconds;
#if KERNEL_VERSION(5, 11, 0) <= LINUX_VERSION_CODE
seconds = ktime_get_real_seconds();
#else
seconds = get_seconds();
#endif
fa_writel(fa, fa->fa_utc_base, &zfad_regs[ZFA_UTC_SECONDS_U],
(seconds >> 32) & 0xFFFFFFFF);
fa_writel(fa, fa->fa_utc_base, &zfad_regs[ZFA_UTC_SECONDS_L],
......@@ -517,12 +554,8 @@ static int __fa_init(struct fa_dev *fa)
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_CTL_FMS_CMD],
FA100M14B4C_CMD_STOP);
/* Initialize channels to use 1V range */
for (i = 0; i < 4; ++i) {
for (i = 0; i < FA100M14B4C_NCHAN; ++i)
fa_adc_range_set(fa, &zdev->cset->chan[i], FA100M14B4C_RANGE_1V);
/* reset channel offset */
fa->user_offset[i] = 0;
fa->zero_offset[i] = 0;
}
/* Set decimation to minimum */