Commit aba8d387 authored by Federico Vaga's avatar Federico Vaga

Merge branch 'fmc-tdc-hacks'

This merge a set of hacky patches to make this driver working
together with the fine-delay driver.

I'm merging this patch into the master because we need this now
and the proper solution is not ready yet (Maybe it will be ready
in october/november 2014 with the new SDB software layer)
parents bfb46984 e6104def
......@@ -232,9 +232,10 @@ struct zio_channel;
int ft_read_sw_fifo(struct fmctdc_dev *ft, int channel,
struct zio_channel *chan);
int ft_enable_termination(struct fmctdc_dev *ft, int channel, int enable);
signed long fmc_find_sdb_device_ext(struct sdb_array *tree,
uint64_t vid, uint32_t did, int index,
unsigned long *sz);
signed long fmc_sdb_find_nth_device (struct sdb_array *tree, uint64_t vid,
uint32_t did, int *ordinal,
uint32_t *size );
#endif // __KERNEL__
......
/*
* Some utility functions not supported in the current version of fmc-bus.
*
* Copyright (C) 2012-2013 CERN (www.cern.ch)
* Copyright (C) 2012-2014 CERN (www.cern.ch)
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* Author: Alessandro Rubini <rubini@gnudd.com>
*
......@@ -18,18 +18,17 @@
#include "fmc-tdc.h"
/* Finds index-th SDB device that matches (vid/did) pair. */
signed long fmc_find_sdb_device_ext(struct sdb_array *tree,
uint64_t vid, uint32_t did, int index,
unsigned long *sz)
typedef int (*sdb_traverse_cb) (uint32_t address, uint32_t size, uint64_t vid, uint32_t did);
static int traverse_sdb_devices(struct sdb_array *tree,
sdb_traverse_cb cb)
{
signed long res = -ENODEV;
union sdb_record *r;
struct sdb_product *p;
struct sdb_component *c;
int i, n = tree->len;
uint64_t last, first;
int ci = 0;
int i, n = tree->len, rv;
uint64_t last, first, vid;
uint32_t did, size;
/* FIXME: what if the first interconnect is not at zero? */
for (i = 0; i < n; i++) {
......@@ -38,26 +37,66 @@ signed long fmc_find_sdb_device_ext(struct sdb_array *tree,
p = &c->product;
if (!IS_ERR(tree->subtree[i]))
res = fmc_find_sdb_device(tree->subtree[i],
vid, did, sz);
/* FIXME: this index SHOULD be recursive, too */
if (ci == index && res >= 0)
return res + tree->baseaddr;
{
rv = traverse_sdb_devices ( tree->subtree[i], cb );
if(rv > 0)
return 1;
}
if (r->empty.record_type != sdb_type_device)
continue;
if (__be64_to_cpu(p->vendor_id) != vid)
continue;
if (__be32_to_cpu(p->device_id) != did)
continue;
/* found */
/* record is a device?*/
last = __be64_to_cpu(c->addr_last);
first = __be64_to_cpu(c->addr_first);
if (sz)
*sz = (typeof(*sz)) (last + 1 - first);
if (ci == index)
return first + tree->baseaddr;
ci++;
vid = __be64_to_cpu(p->vendor_id);
did = __be32_to_cpu(p->device_id);
size = (uint32_t) (last + 1 - first);
if (cb (first + tree->baseaddr, size, vid, did))
return 1;
}
return res;
return 0;
}
/* Finds the Nth SDB device that matches (vid/did) pair, where N <= *ordinal.
If N < *ordinal, the value of N is stored at *ordinal.
This magic is used to handle hybrid bistreams (with two or more different
mezzanines). */
signed long fmc_sdb_find_nth_device (struct sdb_array *tree, uint64_t vid, uint32_t did, int *ordinal, uint32_t *size )
{
int n = -1;
uint32_t current_address;
uint32_t current_size;
int callback (uint32_t address, uint32_t size, uint64_t vid_, uint32_t did_)
{
if(vid_ == vid && did_ == did)
{
n++;
current_address = address;
current_size = size;
if(!ordinal || n == *ordinal)
{
return 1;
}
}
return 0; /* continue scanning */
}
traverse_sdb_devices (tree, callback);
if (n >= 0)
{
if(size)
*size = current_size;
if(ordinal)
*ordinal = n;
return current_address;
}
return -ENODEV;
}
\ No newline at end of file
......@@ -199,7 +199,8 @@ int ft_probe(struct fmc_device *fmc)
struct fmctdc_dev *ft;
struct device *dev = fmc->hwdev;
char *fwname;
int i, index, ret;
int i, index, ret, ord;
signed long addr;
ft = kzalloc(sizeof(struct fmctdc_dev), GFP_KERNEL);
if (!ft) {
......@@ -269,24 +270,12 @@ int ft_probe(struct fmc_device *fmc)
fmc_show_sdb_tree(fmc);
/* Now use SDB to find the base addresses */
ft->ft_core_base =
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x604, fmc->slot_id,
NULL);
ft->ft_carrier_base =
fmc_find_sdb_device(fmc->sdb, 0xce42, 0x603, NULL);
ft->ft_irq_base =
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x605, fmc->slot_id,
NULL);
/* the 0th onewire controller is the carrier one */
ft->ft_owregs_base =
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x602, fmc->slot_id + 1,
NULL);
ft->ft_buffer_base =
fmc_find_sdb_device_ext(fmc->sdb, 0xce42, 0x601, fmc->slot_id,
NULL);
ord = fmc->slot_id;
ft->ft_core_base = fmc_sdb_find_nth_device(fmc->sdb, 0xce42, 0x604, &ord, NULL);
ft->ft_irq_base = ft->ft_core_base + TDC_MEZZ_EIC_OFFSET;
ft->ft_owregs_base = ft->ft_core_base + TDC_MEZZ_ONEWIRE_OFFSET;
ft->ft_buffer_base = ft->ft_core_base + TDC_MEZZ_MEM_OFFSET;
if (ft_verbose) {
dev_info(dev,
......
......@@ -22,12 +22,6 @@ static int ft_spec_reset(struct fmctdc_dev *ft)
{
struct spec_dev *spec = (struct spec_dev *)ft->fmc->carrier_data;
dev_info(&ft->fmc->dev, "%s: resetting TDC core through Gennum.\n",
__func__);
/* set local bus clock to 160 MHz. The FPGA can't handle more. */
gennum_writel(spec, 0xE001F04C, 0x808);
/* it takes a while for the PLL to bootstrap.... or not!
We have no possibility to check, as the PLL status register is driven
by the clock from this PLL :( */
......
......@@ -33,51 +33,13 @@ static int ft_svec_reset(struct fmctdc_dev *ft)
if (ft->fmc->slot_id != 0)
return 0;
dev_info(&ft->fmc->dev, "Resetting FMCs...\n");
fmc_writel(ft->fmc, TDC_CARRIER_CTL1_RSTN_FMC0 |
TDC_CARRIER_CTL1_RSTN_FMC1,
TDC_SVEC_CARRIER_BASE + TDC_REG_CARRIER_CTL1);
dev_info(&ft->fmc->dev, "Un-resetting FMCs...\n");
tmo = jiffies + 2 * HZ;
while (time_before(jiffies, tmo)) {
uint32_t stat;
stat = fmc_readl(ft->fmc,
TDC_SVEC_CARRIER_BASE + TDC_REG_CARRIER_CTL0);
if ((stat & TDC_CARRIER_CTL0_PLL_STAT_FMC0) &&
(stat & TDC_CARRIER_CTL0_PLL_STAT_FMC1))
return 0;
msleep(10);
}
dev_err(&ft->fmc->dev, "PLL lock timeout.\n");
return -EIO;
}
#if 0
static int ft_svec_copy_timestamps(struct fmctdc_dev *ft, int base_addr,
int size, void *dst)
{
int i;
uint32_t addr;
uint32_t *dptr;
/* no unaligned reads, please. */
if (unlikely(size & 3 || base_addr & 3))
return -EIO;
/* FIXME: use SDB to determine buffer base address
(after fixing the HDL) */
addr = ft->ft_buffer_base + base_addr;
for (i = 0, dptr = (uint32_t *) dst; i < size / 4; i++, dptr++)
*dptr = fmc_readl(ft->fmc, addr + i * 4);
fmc_writel(ft->fmc, 0xff, TDC_SVEC_CARRIER_BASE + TDC_REG_CARRIER_RST);
msleep(3000);
return 0;
}
#endif
struct ft_carrier_specific ft_carrier_svec = {
FT_GATEWARE_SVEC,
......
......@@ -73,9 +73,10 @@
#define TDC_REG_CARRIER_CTL0 0x0 /* a.k.a. Carrier revision/PCB id reg */
#define TDC_REG_CARRIER_STATUS 0x4
#define TDC_REG_CARRIER_CTL1 0x8
#define TDC_REG_CARRIER_RST 0xc
#define TDC_CARRIER_CTL0_PLL_STAT_FMC0 BIT(4)
#define TDC_CARRIER_CTL0_PLL_STAT_FMC1 BIT(5)
#define TDC_CARRIER_CTL0_PLL_STAT_FMC0 BIT(5)
#define TDC_CARRIER_CTL0_PLL_STAT_FMC1 BIT(6)
#define TDC_CARRIER_CTL1_RSTN_FMC0 BIT(3)
#define TDC_CARRIER_CTL1_RSTN_FMC1 BIT(4)
......@@ -98,4 +99,12 @@
#define TDC_SVEC_CARRIER_BASE 0x20000
/* TDC core submodule offsets (wrs to the TDC control registers block) */
#define TDC_MEZZ_I2C_OFFSET (0x2000)
#define TDC_MEZZ_ONEWIRE_OFFSET (-0x1000)
#define TDC_MEZZ_EIC_OFFSET (0x1000)
#define TDC_MEZZ_MEM_OFFSET (0x3000)
#endif /* __TDC_REGISTERS_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