Commit 7651e986 authored by Michel Arruat's avatar Michel Arruat Committed by Federico Vaga

driver: add SVEC support

This is work of Michel Arruat, recommitted by Alessandro.  These
svec-specific files match what the previous commit did for spec code.
We are thus using the new register table, sdb support, and
carrier-provided VIC support for interrupts.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 1598de1a
......@@ -25,17 +25,19 @@ subdirs-ccflags-y = $(ccflags-y)
obj-m := fmc-adc-100m14b.o
fmc-adc-100m14b-objs = fa-core.o
fmc-adc-100m14b-objs += fa-spec-core.o
fmc-adc-100m14b-objs += fa-svec-core.o
fmc-adc-100m14b-objs += fa-zio-drv.o
fmc-adc-100m14b-objs += fa-calibration.o
fmc-adc-100m14b-objs += fa-regtable.o
fmc-adc-100m14b-objs += fa-spec-regtable.o
fmc-adc-100m14b-objs += fa-svec-regtable.o
fmc-adc-100m14b-objs += fa-zio-trg.o
fmc-adc-100m14b-objs += fa-spec-dma.o
fmc-adc-100m14b-objs += fa-svec-dma.o
fmc-adc-100m14b-objs += fa-irq.o fa-spec-irq.o
fmc-adc-100m14b-objs += onewire.o
fmc-adc-100m14b-objs += spi.o
fmc-adc-100m14b-objs += fmc-util.o
fmc-adc-100m14b-objs += fmc-util.o
all modules:
$(MAKE) -C $(LINUX) M=$(shell /bin/pwd) modules
......
......@@ -403,6 +403,8 @@ int fa_probe(struct fmc_device *fmc)
/* apply carrier-specific hacks and workarounds */
if (!strcmp(fmc->carrier_name, "SPEC"))
fa->carrier_op = &fa_spec_op;
else if (!strcmp(fmc->carrier_name, "SVEC"))
fa->carrier_op = &fa_svec_op;
else {
dev_err(fmc->hwdev, "unsupported carrier\n");
return -ENODEV;
......
/*
* core-spec fmc-adc-100m14b driver
*
* Copyright (C) 2012 CERN (www.cern.ch)
* Author: Federico Vaga <federico.vaga@gmail.com>
* Copied from fine-delay
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fmc.h>
#include <linux/fmc-sdb.h>
#include <svec.h>
#include "fmc-adc.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);
if (fmc->slot_id == 0)
/* set FMC0 in normal FMC operation */
fa_writel(fa, fa->fa_carrier_csr_base,
&fa_svec_regfield[FA_CAR_FMC0_RES], 1);
else if (fmc->slot_id == 1)
/* set FMC1 in normal FMC operation */
fa_writel(fa, fa->fa_carrier_csr_base,
&fa_svec_regfield[FA_CAR_FMC1_RES], 1);
/* 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 = {
fa_svec_get_gwname,
fa_svec_init,
fa_svec_reset,
fa_svec_exit,
NULL,
NULL,
NULL,
NULL,
NULL,
fa_svec_dma_start,
fa_svec_dma_done,
fa_svec_dma_error,
};
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/byteorder.h>
#include "fmc-adc.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) {
pr_debug("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->fmc->dev,
"DMA error. All acquisition lost\n");
}
/*
* Copyright CERN 2012
* Author: Federico Vaga <federico.vaga@gmail.com>
*
* Table of register masks, used by driver functions
*/
#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},
};
/*
* Copyright CERN 2012
*
* Header for the fmc-adc-100m14b spec driver
*
*/
#ifndef __FA_SVEC_CORE_H__
#define __FA_SVEC_CORE_H__
#include <linux/irqreturn.h>
#include "fmc-adc.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__*/
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