Commit bd5cab5a authored by Federico Vaga's avatar Federico Vaga

sw:drv: validate driver against FPGA

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent fe83df23
......@@ -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
......
......@@ -20,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 = 0;
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"
......@@ -685,6 +691,72 @@ static struct fmc_adc_platform_data fmc_adc_pdata_default = {
.calib_trig_internal = 0,
};
static int fa_metadata_get(struct fa_dev *fa)
{
struct resource *r;
void *mem;
int i;
r = platform_get_resource(fa->pdev, IORESOURCE_MEM, ADC_MEM_META);
if (r == NULL) {
dev_err(&fa->pdev->dev, "Can't inspect ADC device metadata: missing resource\n");
return -ENODEV;
}
mem = ioremap(r->start, resource_size(r));
if (!mem) {
dev_err(&fa->pdev->dev, "Can't inspect ADC device metadata: failed to map\n");
return -ENODEV;
}
/* Dump meta*/
for (i = 0; i < sizeof(fa->meta) / 4; ++i)
((uint32_t *)&fa->meta)[i] = fa_ioread(fa, mem + (i * 4));
iounmap(mem);
return 0;
}
static bool fa_is_fpga_version_valid(uint32_t expected, uint32_t found)
{
if (version_ignore)
return true;
if (FA_VERSION_MAJ(found) != FA_VERSION_MAJ(expected))
return false;
if (FA_VERSION_MIN(found) < FA_VERSION_MIN(expected))
return false;
return true;
}
static bool fa_is_fpga_valid(struct fa_dev *fa)
{
if (fa->meta.vendor != FA_META_VENDOR_ID) {
dev_err(&fa->pdev->dev,
"Unknow vendor ID: %08x\n", fa->meta.vendor);
return false;
}
switch (fa->meta.device) {
case FA_META_DEVICE_ID_SVEC_DBL_ADC:
break;
case FA_META_DEVICE_ID_SPEC:
break;
default:
dev_err(&fa->pdev->dev,
"Unknow device ID: %08x\n", fa->meta.device);
return false;
}
if (!fa_is_fpga_version_valid(FA_VERSION_DRV, fa->meta.version)) {
dev_err(&fa->pdev->dev,
"Invalid version: %08x, expected: %08x\n",
fa->meta.version, FA_VERSION_DRV);
return false;
}
return true;
}
/* probe and remove are called by fa-spec.c */
int fa_probe(struct platform_device *pdev)
{
......@@ -758,6 +830,13 @@ int fa_probe(struct platform_device *pdev)
goto err_fmc_link;
}
err = fa_metadata_get(fa);
if (err)
goto out_meta;
if (!fa_is_fpga_valid(fa))
goto out_valid;
err = fa_dma_request_channel(fa);
if (err)
goto out_dma;
......@@ -801,6 +880,8 @@ out_serdes:
fa_clock_disable(fa);
fa_dma_release_channel(fa);
out_dma:
out_valid:
out_meta:
sysfs_remove_link(&fa->pdev->dev.kobj, dev_name(&fa->slot->dev));
err_fmc_link:
out_fmc_err:
......
......@@ -12,6 +12,8 @@
#include "platform_data/fmc-adc-100m14b4cha.h"
enum fa_spec_dev_offsets {
FA_SPEC_DBL_ADC_META_START = 0x00000000,
FA_SPEC_DBL_ADC_META_END = 0x00000040,
FA_SPEC_ADC_MEM_START = 0x000002000,
FA_SPEC_ADC_MEM_END = 0x000003FFF,
};
......@@ -36,7 +38,14 @@ static int fa_spec_probe(struct platform_device *pdev) {
{
.name = "fmc-adc-irq",
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
}};
},
{
.name = "fmc-adc-meta",
.flags = IORESOURCE_MEM,
.start = FA_SPEC_DBL_ADC_META_START,
.end = FA_SPEC_DBL_ADC_META_END,
},
};
struct platform_device_info pdevinfo = {
.parent = &pdev->dev,
.name = "fmc-adc-100m",
......@@ -93,6 +102,8 @@ static int fa_spec_probe(struct platform_device *pdev) {
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;
fa_spec_fdt_res[3].start = rmem->start + FA_SPEC_DBL_ADC_META_START;
fa_spec_fdt_res[3].end = rmem->start + FA_SPEC_DBL_ADC_META_END;
pdev_child = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev_child))
......
......@@ -28,6 +28,8 @@
#define SVEC_FPGA_DDR5_DMA (0x3000)
enum fa_svec_dev_offsets {
FA_SVEC_DBL_ADC_META_START = 0x00000000,
FA_SVEC_DBL_ADC_META_END = 0x00000040,
FA_SVEC_ADC1_MEM_START = 0x00002000,
FA_SVEC_ADC1_MEM_END = 0x00003FFF,
FA_SVEC_ADC2_MEM_START = 0x00004000,
......@@ -93,6 +95,12 @@ static struct resource fa_svec_res1[] = {
.start = 0,
.end = 0,
},
{
.name = "fmc-adc-100m-meta.1",
.flags = IORESOURCE_MEM,
.start = FA_SVEC_DBL_ADC_META_START,
.end = FA_SVEC_DBL_ADC_META_END,
},
};
static struct resource fa_svec_res2[] = {
......@@ -112,6 +120,12 @@ static struct resource fa_svec_res2[] = {
.start = 1,
.end = 1,
},
{
.name = "fmc-adc-100m-meta.2",
.flags = IORESOURCE_MEM,
.start = FA_SVEC_DBL_ADC_META_START,
.end = FA_SVEC_DBL_ADC_META_END,
},
};
static struct resource *fa_svec_res[] = {
......@@ -173,6 +187,9 @@ static int fa_svec_probe(struct platform_device *pdev)
res[0].start += rmem->start;
res[0].end += rmem->start;
res[2].start += irq;
res[3].start = rmem->start + FA_SVEC_DBL_ADC_META_START;
res[3].end = rmem->start + FA_SVEC_DBL_ADC_META_END;
pdev_data->adc[i] = platform_device_register_resndata_mask(&pdev->dev,
"fmc-adc-100m",
PLATFORM_DEVID_AUTO,
......
......@@ -32,6 +32,20 @@ enum fa_versions {
ADC_VER = 0,
};
/**
* struct device_meta_id Metadata
*/
struct device_meta_id {
uint32_t vendor;
uint32_t device;
uint32_t version;
uint32_t bom;
uint32_t src[4];
uint32_t cap;
uint32_t uuid[4];
};
enum fa100m14b4c_trg_ext_attr_krn {
FA100M14B4C_TATTR_TRG_SU = __FA100M14B4C_TATTR_TRG_MAX,
FA100M14B4C_TATTR_TRG_SL,
......@@ -58,6 +72,7 @@ enum fa_irq_resource {
enum fa_mem_resource {
ADC_MEM_BASE = 0,
ADC_MEM_META,
};
enum fa_bus_resource {
......@@ -294,6 +309,8 @@ struct fa_dev {
struct fmc_slot *slot;
struct fa_memory_ops memops;
struct device_meta_id meta;
/* carrier common base offset addresses */
void *fa_adc_csr_base;
void *fa_spi_base;
......
......@@ -139,4 +139,15 @@ struct fa_calib {
struct fa_calib_stanza dac[FA_CALIB_STANZA_N]; /* For user offset, one per range */
};
#define FA_VERSION_DRV FA_VERSION_BLD
#define FA_VERSION_MAJ(_VER) ((_VER >> 24) & 0xFF)
#define FA_VERSION_MIN(_VER) ((_VER >> 16) & 0xFF)
#define FA_VERSION_PATCH(_VER) (_VER & 0xFFFF)
#define PCI_VENDOR_ID_CERN (0x10DC)
#define FA_META_VENDOR_ID PCI_VENDOR_ID_CERN
#define FA_META_DEVICE_ID_SPEC 0x41444301
#define FA_META_DEVICE_ID_SVEC_DBL_ADC 0x41444302
#endif /* FMC_ADC_H_ */
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