Commit 7035a37a authored by Federico Vaga's avatar Federico Vaga

sw:drv: re-apply lost changes in sw|hdl merge

something was defentivelly wrong during the merge and I missed it.
This patch re-apply the good code
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent d36a4c14
......@@ -7,13 +7,37 @@ endif
endif
# add versions of used submodules
CONFIG_FPGA_MGR_BACKPORT_INCLUDE := -I$(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)/include
CONFIG_FPGA_MGR_BACKPORT_INCLUDE += -I$(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)/include/linux
ccflags-y += -DADDITIONAL_VERSIONS="$(SUBMODULE_VERSIONS)"
ccflags-y += -DGIT_VERSION=\"$(GIT_VERSION)\"
ccflags-y += -I$(VMEBRIDGE_ABS)/include -I$(FPGA_MGR_ABS)/include
ccflags-y += -DVERSION=\"$(VERSION)\"
ccflags-y += -Wall -Werror
ccflags-y += -I$(VMEBRIDGE_ABS)/include
ccflags-y += -I$(FPGA_MGR_ABS)/include
ccflags-$(CONFIG_FPGA_MGR_BACKPORT) += -DCONFIG_FPGA_MGR_BACKPORT
ccflags-$(CONFIG_FPGA_MGR_BACKPORT) += $(CONFIG_FPGA_MGR_BACKPORT_INCLUDE)
ccflags-y += -I$(FMC_ABS)/include
ccflags-y += -I$(I2C_ABS)/include
# priority to I2C headers from our sources
LINUXINCLUDE := -I$(FMC_ABS)/include -I$(FMC_ABS)/include/linux -I$(I2C_ABS)/include -I$(I2C_ABS)/include/linux $(LINUXINCLUDE)
ifeq ($(CONFIG_FPGA_MGR_BACKPORT), y)
LINUXINCLUDE := $(CONFIG_FPGA_MGR_BACKPORT_INCLUDE) $(LINUXINCLUDE)
KBUILD_EXTRA_SYMBOLS += $(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS)/drivers/fpga/Module.symvers
endif
KBUILD_EXTRA_SYMBOLS += $(FMC_ABS)/drivers/fmc/Module.symvers
KBUILD_EXTRA_SYMBOLS += $(VMEBRIDGE_ABS)/driver/Module.symvers
KBUILD_EXTRA_SYMBOLS += $(FPGA_MGR_ABS)/drivers/fpga/Module.symvers
KBUILD_EXTRA_SYMBOLS += $(FMC_ABS)/drivers/fmc/Module.symvers
KBUILD_EXTRA_SYMBOLS += $(I2C_BUS)/drivers/i2c/busses/Module.symvers
obj-m := svec.o
obj-m := svec-fmc-carrier.o
svec-objs := svec-core.o
svec-fmc-carrier-objs := svec-core.o
svec-fmc-carrier-objs += svec-core-fpga.o
svec-fmc-carrier-objs += svec-compat.o
-include Makefile.specific
# include parent_common.mk for buildsystem's defines
#use absolute path for REPO_PARENT
REPO_PARENT ?= $(shell /bin/pwd)/../..
-include $(REPO_PARENT)/parent_common.mk
LINUX ?= /lib/modules/$(shell uname -r)/build
KVERSION ?= $(shell uname -r)
LINUX ?= /lib/modules/$(KVERSION)/build
VMEBRIDGE_ABS ?= $(abspath $(VMEBRIDGE))
CONFIG_FPGA_MGR_BACKPORT_PATH_ABS ?= $(abspath $(CONFIG_FPGA_MGR_BACKPORT_PATH))
VMEBRIDGE_ABS ?= $(abspath $(VMEBRIDGE))
FPGA_MGR_ABS ?= $(abspath $(FPGA_MGR))
FMC_ABS ?= $(abspath $(FMC))
I2C_ABS ?= $(abspath $(I2C))
GIT_VERSION = $(shell git describe --dirty --long --tags)
export GIT_VERSION
VERSION = $(shell git describe --dirty --long --tags)
all: modules
.PHONY: all modules clean help install modules_install
modules help install modules_install:
$(MAKE) -C $(LINUX) M=$(shell pwd) GIT_VERSION=$(GIT_VERSION) VMEBRIDGE_ABS=$(VMEBRIDGE_ABS) FPGA_MGR_ABS=$(FPGA_MGR_ABS) $@
$(MAKE) -C $(LINUX) M=$(shell pwd) \
VERSION=$(VERSION) \
VMEBRIDGE_ABS=$(VMEBRIDGE_ABS) \
CONFIG_FPGA_MGR_BACKPORT_PATH_ABS=$(CONFIG_FPGA_MGR_BACKPORT_PATH_ABS) \
CONFIG_FPGA_MGR_BACKPORT=$(CONFIG_FPGA_MGR_BACKPORT) \
FMC_ABS=$(FMC_ABS) \
I2C_ABS=$(I2C_ABS) \
$@
# be able to run the "clean" rule even if $(LINUX) is not valid
clean:
......
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/fpga/fpga-mgr.h>
#include <linux/version.h>
#include "svec-compat.h"
#if KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE && !defined(CONFIG_FPGA_MGR_BACKPORT)
struct fpga_manager *__fpga_mgr_get(struct device *dev)
{
struct fpga_manager *mgr;
int ret = -ENODEV;
mgr = to_fpga_manager(dev);
if (!mgr)
goto err_dev;
/* Get exclusive use of fpga manager */
if (!mutex_trylock(&mgr->ref_mutex)) {
ret = -EBUSY;
goto err_dev;
}
if (!try_module_get(dev->parent->driver->owner))
goto err_ll_mod;
return mgr;
err_ll_mod:
mutex_unlock(&mgr->ref_mutex);
err_dev:
put_device(dev);
return ERR_PTR(ret);
}
static int fpga_mgr_dev_match(struct device *dev, const void *data)
{
return dev->parent == data;
}
/**
* fpga_mgr_get - get an exclusive reference to a fpga mgr
* @dev:parent device that fpga mgr was registered with
*
* Given a device, get an exclusive reference to a fpga mgr.
*
* Return: fpga manager struct or IS_ERR() condition containing error code.
*/
struct fpga_manager *fpga_mgr_get(struct device *dev)
{
struct class *fpga_mgr_class = (struct class *) kallsyms_lookup_name("fpga_mgr_class");
struct device *mgr_dev;
mgr_dev = class_find_device(fpga_mgr_class, NULL, dev, fpga_mgr_dev_match);
if (!mgr_dev)
return ERR_PTR(-ENODEV);
return __fpga_mgr_get(mgr_dev);
}
#endif
static int __compat_svec_fw_load(struct fpga_manager *mgr, const char *name)
{
#if KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE && !defined(CONFIG_FPGA_MGR_BACKPORT)
#if KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE
return fpga_mgr_firmware_load(mgr, 0, name);
#else
struct fpga_image_info image;
memset(&image, 0, sizeof(image));
return fpga_mgr_firmware_load(mgr, &image, name);
#endif
#else
struct fpga_image_info image;
memset(&image, 0, sizeof(image));
image.firmware_name = (char *)name;
image.dev = mgr->dev.parent;
return fpga_mgr_load(mgr, &image);
#endif
}
int compat_svec_fw_load(struct svec_dev *svec_dev, const char *name)
{
struct fpga_manager *mgr;
int err;
mgr = fpga_mgr_get(&svec_dev->vdev->dev);
if (IS_ERR(mgr))
return -ENODEV;
err = fpga_mgr_lock(mgr);
if (err)
goto out;
err = __compat_svec_fw_load(mgr, name);
fpga_mgr_unlock(mgr);
out:
fpga_mgr_put(mgr);
return err;
}
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#ifndef __SVEC_COMPAT_H__
#define __SVEC_COMPAT_H__
#include <linux/fpga/fpga-mgr.h>
#include <linux/types.h>
#include <linux/version.h>
#include "svec.h"
#if KERNEL_VERSION(4, 10, 0) <= LINUX_VERSION_CODE
#if KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE
/* So that we select the buffer size because smaller */
#define compat_fpga_ops_initial_header_size .initial_header_size = 0xFFFFFFFF,
#else
#define compat_fpga_ops_initial_header_size .initial_header_size = 0,
#endif
#else
#define compat_fpga_ops_initial_header_size
#endif
#if KERNEL_VERSION(4, 16, 0) > LINUX_VERSION_CODE && !defined(CONFIG_FPGA_MGR_BACKPORT)
#define compat_fpga_ops_groups
#else
#define compat_fpga_ops_groups .groups = NULL,
#endif
#if KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE && !defined(CONFIG_FPGA_MGR_BACKPORT)
struct fpga_image_info;
#endif
int compat_svec_fw_load(struct svec_dev *svec_dev, const char *name);
#if KERNEL_VERSION(3, 11, 0) > LINUX_VERSION_CODE
#define __ATTR_RW(_name) __ATTR(_name, (S_IWUSR | S_IRUGO), \
_name##_show, _name##_store)
#define __ATTR_WO(_name) { \
.attr = { .name = __stringify(_name), .mode = S_IWUSR }, \
.store = _name##_store, \
}
#define DEVICE_ATTR_RW(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
#define DEVICE_ATTR_RO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
#define DEVICE_ATTR_WO(_name) \
struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
#endif
#endif /* __SVEC_COMPAT_H__ */
This diff is collapsed.
#ifndef __CHEBY__SVEC_TEMPLATE_REGS__H__
#define __CHEBY__SVEC_TEMPLATE_REGS__H__
#define SVEC_TEMPLATE_REGS_SIZE 8192
/* a ROM containing the carrier metadata */
#define SVEC_TEMPLATE_REGS_METADATA 0x0UL
#define SVEC_TEMPLATE_REGS_METADATA_SIZE 64
/* carrier and fmc status and control */
#define SVEC_TEMPLATE_REGS_CSR 0x40UL
#define SVEC_TEMPLATE_REGS_CSR_SIZE 32
/* offset to the application metadata */
#define SVEC_TEMPLATE_REGS_CSR_APP_OFFSET 0x40UL
/* global and application resets */
#define SVEC_TEMPLATE_REGS_CSR_RESETS 0x44UL
#define SVEC_TEMPLATE_REGS_CSR_RESETS_GLOBAL 0x1UL
#define SVEC_TEMPLATE_REGS_CSR_RESETS_APPL 0x2UL
/* presence lines for the fmcs */
#define SVEC_TEMPLATE_REGS_CSR_FMC_PRESENCE 0x48UL
/* status of gennum */
#define SVEC_TEMPLATE_REGS_CSR_GN4124_STATUS 0x4cUL
/* status of the ddr3 controller */
#define SVEC_TEMPLATE_REGS_CSR_DDR_STATUS 0x50UL
#define SVEC_TEMPLATE_REGS_CSR_DDR_STATUS_CALIB_DONE 0x1UL
/* pcb revision */
#define SVEC_TEMPLATE_REGS_CSR_PCB_REV 0x54UL
#define SVEC_TEMPLATE_REGS_CSR_PCB_REV_REV_MASK 0xfUL
#define SVEC_TEMPLATE_REGS_CSR_PCB_REV_REV_SHIFT 0
/* Thermometer and unique id */
#define SVEC_TEMPLATE_REGS_THERM_ID 0x70UL
#define SVEC_TEMPLATE_REGS_THERM_ID_SIZE 16
/* i2c controllers to the fmcs */
#define SVEC_TEMPLATE_REGS_FMC_I2C 0x80UL
#define SVEC_TEMPLATE_REGS_FMC_I2C_SIZE 32
/* spi controller to the flash */
#define SVEC_TEMPLATE_REGS_FLASH_SPI 0xa0UL
#define SVEC_TEMPLATE_REGS_FLASH_SPI_SIZE 32
/* dma registers for the gennum core */
#define SVEC_TEMPLATE_REGS_DMA 0xc0UL
#define SVEC_TEMPLATE_REGS_DMA_SIZE 64
/* vector interrupt controller */
#define SVEC_TEMPLATE_REGS_VIC 0x100UL
#define SVEC_TEMPLATE_REGS_VIC_SIZE 256
/* a ROM containing build information */
#define SVEC_TEMPLATE_REGS_BUILDINFO 0x200UL
#define SVEC_TEMPLATE_REGS_BUILDINFO_SIZE 256
/* white-rabbit core registers */
#define SVEC_TEMPLATE_REGS_WRC_REGS 0x1000UL
#define SVEC_TEMPLATE_REGS_WRC_REGS_SIZE 4096
struct svec_template_regs {
/* [0x0]: SUBMAP a ROM containing the carrier metadata */
uint32_t metadata[16];
/* [0x40]: BLOCK carrier and fmc status and control */
struct csr {
/* [0x0]: REG (ro) offset to the application metadata */
uint32_t app_offset;
/* [0x4]: REG (rw) global and application resets */
uint32_t resets;
/* [0x8]: REG (ro) presence lines for the fmcs */
uint32_t fmc_presence;
/* [0xc]: REG (ro) status of gennum */
uint32_t gn4124_status;
/* [0x10]: REG (ro) status of the ddr3 controller */
uint32_t ddr_status;
/* [0x14]: REG (ro) pcb revision */
uint32_t pcb_rev;
/* padding to: 5 words */
uint32_t __padding_0[2];
} csr;
/* padding to: 28 words */
uint32_t __padding_0[4];
/* [0x70]: SUBMAP Thermometer and unique id */
uint32_t therm_id[4];
/* [0x80]: SUBMAP i2c controllers to the fmcs */
uint32_t fmc_i2c[8];
/* [0xa0]: SUBMAP spi controller to the flash */
uint32_t flash_spi[8];
/* [0xc0]: SUBMAP dma registers for the gennum core */
uint32_t dma[16];
/* [0x100]: SUBMAP vector interrupt controller */
uint32_t vic[64];
/* [0x200]: SUBMAP a ROM containing build information */
uint32_t buildinfo[64];
/* padding to: 1024 words */
uint32_t __padding_1[832];
/* [0x1000]: SUBMAP white-rabbit core registers */
uint32_t wrc_regs[1024];
};
#endif /* __CHEBY__SVEC_TEMPLATE_REGS__H__ */
......@@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/fmc.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/jhash.h>
......@@ -31,12 +32,10 @@
#include <linux/fpga/fpga-mgr.h>
#include <vmebus.h>
#include "svec.h"
#include "svec-compat.h"
#include "hw/xloader_regs.h"
#define SVEC_BASE_LOADER 0x70000
static void svec_csr_write(u8 value, void *base, u32 offset)
{
offset -= offset % 4;
......@@ -44,36 +43,147 @@ static void svec_csr_write(u8 value, void *base, u32 offset)
}
/**
* Byte sequence to unlock and clear the Application FPGA
* Load FPGA code
* @svec: SVEC device
* @name: FPGA bitstream file name
*
* Return: 0 on success, otherwise a negative error number
*/
static const uint32_t boot_unlock_sequence[8] = {
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe
static int svec_fw_load(struct svec_dev *svec_dev, const char *name)
{
int err;
err = svec_fpga_exit(svec_dev);
if (err) {
dev_err(&svec_dev->vdev->dev,
"Cannot remove FPGA device instances. Try to remove them manually and to reload this device instance\n");
return err;
}
mutex_lock(&svec_dev->mtx);
err = compat_svec_fw_load(svec_dev, name);
if (err)
goto out;
err = svec_fpga_init(svec_dev, SVEC_FUNC_NR);
if (err)
dev_warn(&svec_dev->vdev->dev,
"FPGA incorrectly programmed %d\n", err);
out:
mutex_unlock(&svec_dev->mtx);
return err;
}
static ssize_t svec_dbg_fw_write(struct file *file,
const char __user *buf,
size_t count, loff_t *ppos)
{
struct svec_dev *svec_dev = file->private_data;
int err;
err = svec_fw_load(svec_dev, buf);
if (err)
return err;
return count;
}
static int svec_dbg_fw_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static const struct file_operations svec_dbg_fw_ops = {
.owner = THIS_MODULE,
.open = svec_dbg_fw_open,
.write = svec_dbg_fw_write,
};
static int svec_dbg_meta(struct seq_file *s, void *offset)
{
struct svec_dev *svec_dev = s->private;
struct svec_meta_id *meta;
meta = &svec_dev->meta;
seq_printf(s, "'%s':\n", dev_name(&svec_dev->vdev->dev));
seq_puts(s, "Metadata:\n");
seq_printf(s, " - Vendor: 0x%08x\n", meta->vendor);
seq_printf(s, " - Device: 0x%08x\n", meta->device);
seq_printf(s, " - Version: 0x%08x\n", meta->version);
seq_printf(s, " - BOM: 0x%08x\n", meta->bom);
seq_printf(s, " - SourceID: 0x%08x%08x%08x%08x\n",
meta->src[0],
meta->src[1],
meta->src[2],
meta->src[3]);
seq_printf(s, " - CapabilityMask: 0x%08x\n", meta->cap);
seq_printf(s, " - VendorUUID: 0x%08x%08x%08x%08x\n",
meta->uuid[0],
meta->uuid[1],
meta->uuid[2],
meta->uuid[3]);
/**
* struct svec_dev - SVEC instance
* It describes a SVEC device instance.
* @vdev VME device instance
* @bitstream_last_word last data to write into the FPGA
* @bistream_last_word_size last data size to write in the FPGA. This is a dirty
* and ugly hack in order to properly handle a dirty
* and ugly interface. The SVEC bootloader does not
* accept emtpy transfers and neither to declare the
* transmission over without sending data.
* @fpgA_status state of the Application FPGA
* The user must lock the spinlock `lock` when using the following variables in
* this data structure: flags.
*/
struct svec_dev {
struct vme_dev *vdev;
char name[8];
return 0;
}
static int svec_dbg_meta_open(struct inode *inode, struct file *file)
{
struct svec_dev *svec = inode->i_private;
return single_open(file, svec_dbg_meta, svec);
}
uint32_t bitstream_last_word;
uint32_t bitstream_last_word_size;
enum fpga_mgr_states fpga_status;
static const struct file_operations svec_dbg_meta_ops = {
.owner = THIS_MODULE,
.open = svec_dbg_meta_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int svec_dbg_init(struct svec_dev *svec_dev)
{
struct device *dev = &svec_dev->vdev->dev;
svec_dev->dbg_dir = debugfs_create_dir(dev_name(dev), NULL);
if (IS_ERR_OR_NULL(svec_dev->dbg_dir)) {
dev_err(dev, "Cannot create debugfs directory (%ld)\n",
PTR_ERR(svec_dev->dbg_dir));
return PTR_ERR(svec_dev->dbg_dir);
}
svec_dev->dbg_fw = debugfs_create_file(SVEC_DBG_FW_NAME, 0200,
svec_dev->dbg_dir,
svec_dev,
&svec_dbg_fw_ops);
if (IS_ERR_OR_NULL(svec_dev->dbg_fw)) {
dev_err(dev, "Cannot create debugfs file \"%s\" (%ld)\n",
SVEC_DBG_FW_NAME, PTR_ERR(svec_dev->dbg_fw));
return PTR_ERR(svec_dev->dbg_fw);
}
svec_dev->dbg_meta = debugfs_create_file(SVEC_DBG_META_NAME, 0200,
svec_dev->dbg_dir,
svec_dev,
&svec_dbg_meta_ops);
if (IS_ERR_OR_NULL(svec_dev->dbg_meta)) {
dev_err(dev, "Cannot create debugfs file \"%s\" (%ld)\n",
SVEC_DBG_META_NAME, PTR_ERR(svec_dev->dbg_meta));
return PTR_ERR(svec_dev->dbg_meta);
}
return 0;
}
static void svec_dbg_exit(struct svec_dev *svec_dev)
{
debugfs_remove_recursive(svec_dev->dbg_dir);
}
/**
* Writes a "magic" unlock sequence, activating the System FPGA bootloader
......@@ -167,7 +277,7 @@ static int svec_fpga_write_word(struct fpga_manager *mgr,
/**
* It starts the programming procedure
* Start programming procedure
* It is usable only when there is a valid CR/CSR space mapped
* @mgr FPGA manager instance
* Return 0 on success, otherwise a negative errno number.
......@@ -206,7 +316,7 @@ err_reset:
/**
* It starts the programming procedure.
* Stop programming procedure.
* It is usable only when there is a valid CR/CSR space mapped
* @mgr FPGA manager instance
* Return 0 on success, otherwise a negative errno number
......@@ -233,7 +343,11 @@ static int svec_fpga_write_stop(struct fpga_manager *mgr,
svec->bitstream_last_word_size = -1;
/* Two seconds later */
timeout = get_jiffies_64() + usecs_to_jiffies(info->config_complete_timeout_us);
timeout = get_jiffies_64();
if (info->config_complete_timeout_us)
timeout += usecs_to_jiffies(info->config_complete_timeout_us);
else
timeout += usecs_to_jiffies(100);
while (time_before64(get_jiffies_64(), timeout)) {
rval = ioread32be(loader_addr + XLDR_REG_CSR);
if (rval & XLDR_CSR_DONE)
......@@ -357,7 +471,7 @@ static int svec_vme_init(struct svec_dev *svec)
struct vme_dev *vdev = svec->vdev;
int err;
err = vme_csr_enable(vdev, 0);
err = vme_disable_device(vdev);
if (err)
return err;
/* Configure the SVEC VME interface */
......@@ -366,17 +480,14 @@ static int svec_vme_init(struct svec_dev *svec)
svec_csr_write(vdev->irq_level, vdev->map_cr.kernel_va,
SVEC_USER_CSR_INT_LEVEL);
err = vme_csr_enable(vdev, 1);
if (err)
return err;
return 0;
return vme_enable_device(vdev);
}
/**
* It initialize a new SVEC instance
* @pdev correspondend Linux device instance
* @ndev (Deprecated) device number
*
* Return: 0 on success, otherwise a negative number correspondent to an errno
*/
static int svec_probe(struct device *dev, unsigned int ndev)
......@@ -390,36 +501,61 @@ static int svec_probe(struct device *dev, unsigned int ndev)
err = -ENOMEM;
goto err;
}
mutex_init(&svec->mtx);
svec->vdev = vdev;
dev_set_drvdata(dev, svec);
svec_vme_init(svec);
svec->fpga_status = FPGA_MGR_STATE_UNKNOWN;
svec->mgr = fpga_mgr_create(dev, dev_name(dev),
&svec_fpga_ops, svec);
if (!svec->mgr) {
err = -EPERM;
goto err_fpga_new;
}
snprintf(svec->name, 8, "svec.%d", vdev->slot);
err = fpga_mgr_register(&svec->vdev->dev, svec->name,
&svec_fpga_ops, svec);
err = fpga_mgr_register(svec->mgr);
if (err)
goto err_fpga_reg;
svec_vme_init(svec);
svec_dbg_init(svec);
err = svec_fpga_init(svec, SVEC_FUNC_NR);
if (err)
dev_warn(&vdev->dev,
"FPGA incorrectly programmed or empty (%d)\n", err);
return 0;
err_fpga_reg:
fpga_mgr_free(svec->mgr);
err_fpga_new:
dev_set_drvdata(dev, NULL);
kfree(svec);
err:
dev_err(dev, "Failed to register SVEC device\n");
return err;
}
/**
* It removes a SVEC device instance
* @vdev Linux device pointer
* @ndev DEPRECATED Device instance
* Return: 0 on success, otherwise a negative errno number
*/
static int svec_remove(struct device *vdev, unsigned int ndev)
static int svec_remove(struct device *dev, unsigned int ndev)
{
fpga_mgr_unregister(vdev);
struct svec_dev *svec = dev_get_drvdata(dev);
svec_fpga_exit(svec);
svec_dbg_exit(svec);
fpga_mgr_unregister(svec->mgr);
fpga_mgr_free(svec->mgr);
dev_set_drvdata(dev, NULL);
vme_disable_device(svec->vdev);
kfree(svec);
return 0;
}
......@@ -444,7 +580,8 @@ static struct vme_driver svec_driver = {
.probe = svec_probe,
.remove = svec_remove,
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
.name = "svec-fmc-carrier",
},
.id_table = svec_id_table,
};
......@@ -464,9 +601,10 @@ module_init(svec_init);
module_exit(svec_exit);
MODULE_AUTHOR("Federico Vaga <federico.vaga@cern.ch>");
MODULE_AUTHOR("Juan David Gonzalez Cobas <dcobas@cern.ch>");
MODULE_LICENSE("GPL v2");
MODULE_VERSION(GIT_VERSION);
MODULE_DESCRIPTION("svec driver");
MODULE_VERSION(VERSION);
MODULE_DESCRIPTION("Driver for the 'Simple VME FMC Carrier' a.k.a. SVEC");
MODULE_SOFTDEP("pre: htvic i2c_mux i2c_ohwr spi-ocores");
ADDITIONAL_VERSIONS;
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2019 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@cern.ch>
*/
#ifndef __SVEC_H__
#define __SVEC_H__
#include <linux/bitmap.h>
#include <linux/debugfs.h>
#include <linux/platform_device.h>
#include <linux/fmc.h>
#include <vmebus.h>
#include "svec-core-fpga.h"
#define PCI_VENDOR_ID_CERN (0x10DC)
#define SVEC_BASE_LOADER 0x70000
#define SVEC_FMC_SLOTS 2
/* On FPGA components */
#define SVEC_GOLDEN_ADDR 0x10000
#define SVEC_I2C_SIZE 32
#define SVEC_I2C_ADDR_START 0x14000
#define SVEC_I2C_ADDR_END ((SVEC_I2C_ADDR_START + SVEC_I2C_SIZE) - 1)
/**
* Byte sequence to unlock and clear the Application FPGA
*/
static const uint32_t boot_unlock_sequence[8] = {
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe
};
enum svec_dev_flags {
SVEC_DEV_F_APP = BIT(0),
};
enum {
/* Metadata */
FPGA_META_VENDOR = 0x00,
FPGA_META_DEVICE = 0x04,
FPGA_META_VERSION = 0x08,
FPGA_META_BOM = 0x0C,
FPGA_META_SRC = 0x10,
FPGA_META_CAP = 0x20,
FPGA_META_UUID = 0x30,
};
enum {
/* Metadata */
SVEC_META_BASE = SVEC_TEMPLATE_REGS_METADATA,
SVEC_META_VENDOR = SVEC_META_BASE + FPGA_META_VENDOR,
SVEC_META_DEVICE = SVEC_META_BASE + FPGA_META_DEVICE,
SVEC_META_VERSION = SVEC_META_BASE + FPGA_META_VERSION,
SVEC_META_BOM = SVEC_META_BASE + FPGA_META_BOM,
SVEC_META_SRC = SVEC_META_BASE + FPGA_META_SRC,
SVEC_META_CAP = SVEC_META_BASE + FPGA_META_CAP,
SVEC_META_UUID = SVEC_META_BASE + FPGA_META_UUID,
};
#define SVEC_META_VENDOR_ID PCI_VENDOR_ID_CERN
#define SVEC_META_DEVICE_ID 0x53564543
//#define SVEC_META_BOM_BE 0xFEFF0000
#define SVEC_META_BOM_BE 0xFFFE0000 /* FIXME */
#define SVEC_META_BOM_END_MASK 0xFFFF0000
#define SVEC_META_BOM_VER_MASK 0x0000FFFF
#define SVEC_META_VERSION_MASK 0xFFFF0000
#define SVEC_META_VERSION_1_4 0x01040000
/**
* struct svec_meta_id Metadata
*/
struct svec_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];
};
#define SVEC_FUNC_NR 1
#define SVEC_FMC_SLOTS 2
struct svec_fpga {
struct device dev;
unsigned int function_nr;
void __iomem *fpga;
struct platform_device *vic_pdev;
struct platform_device *app_pdev;
struct fmc_slot_info slot_info[SVEC_FMC_SLOTS];
struct dentry *dbg_dir;
#define SVEC_DBG_CSR_NAME "csr_regs"
struct dentry *dbg_csr;
struct debugfs_regset32 dbg_csr_reg;
#define SVEC_DBG_BLD_INFO_NAME "build_info"
struct dentry *dbg_bld_info;
};
static inline struct svec_fpga *to_svec_fpga(struct device *_dev)
{
return container_of(_dev, struct svec_fpga, dev);
}
/**
* struct svec_dev - SVEC instance
* It describes a SVEC device instance.
* @vdev VME device instance
* @flags: flags
* @mgr FPGA manager instance
* @bitstream_last_word last data to write into the FPGA
* @bistream_last_word_size last data size to write in the FPGA. This is a dirty
* and ugly hack in order to properly handle a dirty
* and ugly interface. The SVEC bootloader does not
* accept emtpy transfers and neither to declare the
* transmission over without sending data.
* @fpga_status state of the Application FPGA
* @i2c_adapter the I2C adapter to access the FMC EEPROMs
* The user must lock the spinlock `lock` when using the following variables in
* this data structure: flags.
* @mem: ioremapped memory
*/
struct svec_dev {
struct vme_dev *vdev;
char name[8];
unsigned long flags;
struct svec_meta_id meta;
struct mutex mtx;
struct fpga_manager *mgr;
uint32_t bitstream_last_word;
uint32_t bitstream_last_word_size;
enum fpga_mgr_states fpga_status;
struct platform_device *i2c_pdev;
struct i2c_adapter *i2c_adapter;
struct fmc_slot_info slot_info[SVEC_FMC_SLOTS];
void *mem;
struct dentry *dbg_dir;
#define SVEC_DBG_FW_NAME "fpga_firmware"
struct dentry *dbg_fw;
#define SVEC_DBG_META_NAME "fpga_device_metadata"
struct dentry *dbg_meta;
struct svec_fpga *svec_fpga;
};
extern int svec_fpga_init(struct svec_dev *svec_dev, unsigned int function_nr);
extern int svec_fpga_exit(struct svec_dev *svec_dev);
#endif /* __SVEC_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