Commit 3f02983e authored by Federico Vaga's avatar Federico Vaga

drv: add FMC mezzanine validation

Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 3f0ea302
KBUILD_EXTRA_SYMBOLS += $(ZIO_EXTRA_SYMBOLS-y)
KBUILD_EXTRA_SYMBOLS += $(FMC_EXTRA_SYMBOLS-y)
# add versions of supermodule. It is useful when fine-delay-sw is included as sub-module
# of a bigger project that we want to track
......@@ -16,6 +17,7 @@ ccflags-y += -DADDITIONAL_VERSIONS="$(SUBMODULE_VERSIONS)"
ccflags-y += \
-I$(ZIO_ABS)/include \
-I$(FMC_ABS)/include \
-I$(src)
ccflags-y += -DVERSION=\"$(VERSION)\"
......
......@@ -6,19 +6,23 @@ REPO_PARENT ?= $(shell /bin/pwd)/../..
LINUX ?= /lib/modules/$(shell uname -r)/build
FMC ?=
ZIO ?= ../zio
ZIO_ABS ?= $(abspath $(ZIO) )
ZIO_EXTRA_SYMBOLS-y = $(ZIO_ABS)/Module.symvers
FMC_ABS ?= $(abspath $(FMC))
FMC_EXTRA_SYMBOLS-y = $(FMC_ABS)/drivers/fmc/Module.symvers
GIT_VERSION = $(shell git describe --dirty --long --tags)
ZIO_VERSION ?= $(shell cd $(ZIO_ABS); git describe --always --dirty --long --tags)
all modules:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) \
ZIO_ABS=$(ZIO_ABS) \
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) \
VERSION=$(GIT_VERSION) \
modules
......
......@@ -22,6 +22,8 @@
#include <linux/list.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/ipmi-fru.h>
#include <linux/fmc.h>
#include "fine-delay.h"
#include "hw/fd_main_regs.h"
......@@ -35,6 +37,8 @@ struct memory_ops memops = {
static int fd_verbose = 0;
module_param_named(verbose, fd_verbose, int, 0444);
#define FA_EEPROM_TYPE "at24c64"
/* FIXME: add parameters "file=" and "wrc=" like wr-nic-core does */
/**
......@@ -156,6 +160,47 @@ static int fd_resource_validation(struct platform_device *pdev)
return 0;
}
#define FD_FMC_NAME "FmcDelay1ns4cha"
static bool fd_fmc_slot_is_valid(struct fd_dev *fd)
{
int ret;
void *fru = NULL;
char *fmc_name = NULL;
if (!fmc_slot_fru_valid(fd->slot)) {
dev_err(&fd->pdev->dev, "Can't identify FMC card: invalid FRU\n");
return -EINVAL;
}
fru = kmalloc(FRU_SIZE_MAX, GFP_KERNEL);
if (!fru)
return -ENOMEM;
ret = fmc_slot_eeprom_read(fd->slot, fru, 0x0, FRU_SIZE_MAX);
if (ret != FRU_SIZE_MAX) {
dev_err(&fd->pdev->dev, "Failed to read FRU header\n");
goto err;
}
fmc_name = fru_get_product_name(fru);
ret = strcmp(fmc_name, FD_FMC_NAME);
if (ret) {
dev_err(&fd->pdev->dev,
"Invalid FMC card: expectd '%s', found '%s'\n",
FD_FMC_NAME, fmc_name);
goto err;
}
kfree(fmc_name);
kfree(fru);
return true;
err:
kfree(fmc_name);
kfree(fru);
return false;
}
/* probe and remove are called by the FMC bus core */
int fd_probe(struct platform_device *pdev)
......@@ -163,13 +208,20 @@ int fd_probe(struct platform_device *pdev)
struct fd_modlist *m;
struct fd_dev *fd;
struct device *dev = &pdev->dev;
int i, ret, ch, err;
int i, ret, ch, err, slot_nr;
struct resource *r;
err = fd_resource_validation(pdev);
if (err)
return err;
fd = devm_kzalloc(&pdev->dev, sizeof(*fd), GFP_KERNEL);
if (!fd)
return -ENOMEM;
platform_set_drvdata(pdev, fd);
fd->pdev = pdev;
/* Assign IO operation */
switch (pdev->id_entry->driver_data) {
case FD_VER_SPEC:
......@@ -186,29 +238,51 @@ int fd_probe(struct platform_device *pdev)
return -EINVAL;
}
fd = devm_kzalloc(&pdev->dev, sizeof(*fd), GFP_KERNEL);
if (!fd) {
dev_err(dev, "can't allocate device\n");
return -ENOMEM;
}
platform_set_drvdata(pdev, fd);
fd->pdev = pdev;
fd->verbose = fd_verbose;
r = platform_get_resource(pdev, IORESOURCE_MEM, FD_MEM_BASE);
fd->fd_regs_base = ioremap(r->start, resource_size(r));
fd->fd_owregs_base = fd->fd_regs_base + 0x500;
spin_lock_init(&fd->lock);
/* Check the binary is there */
if (fd_readl(fd, FD_REG_IDR) != FD_MAGIC_FPGA) {
dev_err(dev, "wrong gateware\n");
return -ENODEV;
}
slot_nr = fd_readl(fd, FD_REG_FMC_SLOT_ID) + 1;
fd->slot = fmc_slot_get(pdev->dev.parent->parent, slot_nr);
if (IS_ERR(fd->slot)) {
dev_err(&fd->pdev->dev,
"Can't find FMC slot %d err: %ld\n",
slot_nr, PTR_ERR(fd->slot));
goto out_fmc;
}
if (!fmc_slot_present(fd->slot)) {
dev_err(&fd->pdev->dev,
"Can't identify FMC card: missing card\n");
goto out_fmc_pre;
}
if (strcmp(fmc_slot_eeprom_type_get(fd->slot), FA_EEPROM_TYPE)) {
dev_warn(&fd->pdev->dev,
"use non standard EERPOM type \"%s\"\n",
FA_EEPROM_TYPE);
err = fmc_slot_eeprom_type_set(fd->slot, FA_EEPROM_TYPE);
if (err) {
dev_err(&fd->pdev->dev,
"Failed to change EEPROM type to \"%s\"",
FA_EEPROM_TYPE);
goto out_fmc_eeprom;
}
}
if(!fd_fmc_slot_is_valid(fd))
goto out_fmc_err;
/* Retrieve calibration from the eeprom, and validate */
ret = fd_handle_calibration(fd, NULL);
if (ret < 0)
......@@ -265,6 +339,11 @@ err:
while (--m, --i >= 0)
if (m->exit)
m->exit(fd);
out_fmc_err:
out_fmc_eeprom:
out_fmc_pre:
fmc_slot_put(fd->slot);
out_fmc:
return ret;
}
......@@ -285,6 +364,7 @@ int fd_remove(struct platform_device *pdev)
if (m->exit)
m->exit(fd);
}
fmc_slot_put(fd->slot);
return 0;
}
......
......@@ -131,6 +131,7 @@ struct fd_time {
#include <linux/platform_device.h>
#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/fmc.h>
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25)
#include <linux/math64.h>
#else
......@@ -217,6 +218,7 @@ struct fd_dev {
struct tasklet_struct tlet;
struct fd_calibration calib; /* a copy of what we have in flash */
struct fd_ch ch[FD_CH_NUMBER];
struct fmc_slot *slot;
uint32_t bin;
int acam_addr; /* cache of currently active addr */
uint8_t ds18_id[8];
......
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