Commit 85bc40be authored by Jorge Machado's avatar Jorge Machado

Adapt kernel sources to the new structure

parent a3efe86e
......@@ -20,7 +20,10 @@ ccflags-y += -DGIT_VERSION=\"$(GIT_VERSION)\"
obj-m += wr-dio.o
wr-dio-y = fmc-dio.o
wr-dio-y = ./hw/wr-dio-regs.o
wr-dio-y += ./hw/wr-dio-regs_v1.o
wr-dio-y += ./hw/wr-dio-regs_v2.o
wr-dio-y += fmc-dio.o
wr-dio-y += fmc-dio-internal.o
wr-dio-y += fmc-dio-mdev.o
wr-dio-y += fmc-dio-gpio.o
\ No newline at end of file
......@@ -32,75 +32,23 @@
#define fmc_dio_stat 0
#endif
/* We need a clear mapping for the registers of the various bits */
struct regmap {
int trig_l;
int trig_h;
int cycle;
int pulse;
int fifo_tai_l;
int fifo_tai_h;
int fifo_cycle;
int fifo_status;
};
#define R(x) (offsetof(struct DIO_WB, x))
static struct regmap regmap[] = {
{
.trig_l = R(TRIG0),
.trig_h = R(TRIGH0),
.cycle = R(CYC0),
.pulse = R(PROG0_PULSE),
.fifo_tai_l = R(TSF0_R0),
.fifo_tai_h = R(TSF0_R1),
.fifo_cycle = R(TSF0_R2),
.fifo_status = R(TSF0_CSR),
}, {
.trig_l = R(TRIG1),
.trig_h = R(TRIGH1),
.cycle = R(CYC1),
.pulse = R(PROG1_PULSE),
.fifo_tai_l = R(TSF1_R0),
.fifo_tai_h = R(TSF1_R1),
.fifo_cycle = R(TSF1_R2),
.fifo_status = R(TSF1_CSR),
}, {
.trig_l = R(TRIG2),
.trig_h = R(TRIGH2),
.cycle = R(CYC2),
.pulse = R(PROG2_PULSE),
.fifo_tai_l = R(TSF2_R0),
.fifo_tai_h = R(TSF2_R1),
.fifo_cycle = R(TSF2_R2),
.fifo_status = R(TSF2_CSR),
}, {
.trig_l = R(TRIG3),
.trig_h = R(TRIGH3),
.cycle = R(CYC3),
.pulse = R(PROG3_PULSE),
.fifo_tai_l = R(TSF3_R0),
.fifo_tai_h = R(TSF3_R1),
.fifo_cycle = R(TSF3_R2),
.fifo_status = R(TSF3_CSR),
}, {
.trig_l = R(TRIG4),
.trig_h = R(TRIGH4),
.cycle = R(CYC4),
.pulse = R(PROG4_PULSE),
.fifo_tai_l = R(TSF4_R0),
.fifo_tai_h = R(TSF4_R1),
.fifo_cycle = R(TSF4_R2),
.fifo_status = R(TSF4_CSR),
}
};
#define CHANNEL_5_IRQ_EN_MASK 0x100000
#define FMC_DIO_IRQ_MASK \
(DIO_EIC_ISR_NEMPTY_0 \
| DIO_EIC_ISR_NEMPTY_1 \
| DIO_EIC_ISR_NEMPTY_2 \
| DIO_EIC_ISR_NEMPTY_1\
| DIO_EIC_ISR_NEMPTY_2\
| DIO_EIC_ISR_NEMPTY_3\
| DIO_EIC_ISR_NEMPTY_4)
#define FMC_DIO_IRQ_MASK_V2 \
(DIO_EIC_ISR_NEMPTY_0 \
| DIO_EIC_ISR_NEMPTY_1\
| DIO_EIC_ISR_NEMPTY_2\
| DIO_EIC_ISR_NEMPTY_3\
| DIO_EIC_ISR_NEMPTY_4\
| DIO_EIC_ISR_NEMPTY_5)
/* This is the structure we need to manage interrupts and loop internally */
#define FMC_DIO_BUFFER_LEN 512
struct dio_channel {
......@@ -115,7 +63,7 @@ struct dio_channel {
};
struct dio_device {
struct dio_channel ch[5];
struct dio_channel ch[6];
};
/* Instead of timespec_sub, just subtract the nanos */
......@@ -128,25 +76,27 @@ static inline void fmc_dio_int_ts_sub(struct timespec *ts, int nano)
static void __fmc_dio_int_new_pulse(struct fmc_dio *dev, int ch,
struct timespec *ts)
{
struct DIO_WB __iomem *dio = dev->dio;
void __iomem *base = dio;
void __iomem *base = dev->dio;
struct regmap *map;
map = regmap + ch;
struct regmap_common dio;
dio = get_regmap_common(dev->version);
map = get_regmap(dev->version);
map += ch;
fmc_dio_int_ts_sub(ts, 8); /* 1 cycle, to account for output latencies */
writel(ts->tv_nsec / 8, base + map->cycle);
writel(GET_HI32(ts->tv_sec), base + map->trig_h);
writel(ts->tv_sec, base + map->trig_l);
writel(1 << ch, &dio->R_LATCH);
writel(1 << ch, base + dio.latch_reg);
}
static int fmc_dio_int_cmd_pulse(struct fmc_dio *dev,
struct wr_dio_cmd *cmd)
{
struct DIO_WB __iomem *dio = dev->dio;
void __iomem *base = dio;
void __iomem *base = dev->dio;
struct PPSG_WB __iomem *ppsg = dev->ppsg;
struct dio_device *d = dev->priv;
struct dio_channel *c;
......@@ -154,31 +104,45 @@ static int fmc_dio_int_cmd_pulse(struct fmc_dio *dev,
struct timespec *ts;
uint32_t reg;
int ch;
struct regmap_common dio;
dio = get_regmap_common(dev->version);
ch = cmd->channel;
if (ch > 4)
return -EINVAL; /* mask not supported */
c = d->ch + ch;
map = regmap + ch;
map = get_regmap(dev->version);
map += ch;
ts = cmd->t;
/* First, configure this bit as DIO output */
reg = readl(&dio->IOMODE);
writel(reg | (1 << 4*ch), &dio->IOMODE);
reg = readl(base + dio.iomode_reg);
writel(reg | (1 << 4*ch), base + dio.iomode_reg);
writel(ts[1].tv_nsec / 8, base + map->pulse); /* width */
if (cmd->flags & WR_DIO_F_NOW) {
/* Generate a pulse train from current time in V2 DIO version*/
if(dev->version == 1) {
if (cmd->flags & WR_DIO_F_LOOP && cmd->value != 1) {
writel(ts[2].tv_nsec / 8, base + map->pulse_per);
c->target_channel = ch;
if (cmd->value > 1) {
cmd->value-=2;
}
atomic_set(&c->count, cmd->value);
}
}
/* if "now" we are done */
writel(1 << ch, &dio->PULSE);
writel(1 << ch, base + dio.pulse_reg);
return 0;
}
/* if relative, add current 40-bit second to timespec */
if (cmd->flags & WR_DIO_F_REL) {
uint32_t h1, l, h2;
unsigned long now;
h1 = readl(&ppsg->CNTR_UTCHI);
l = readl(&ppsg->CNTR_UTCLO);
h2 = readl(&ppsg->CNTR_UTCHI);
......@@ -189,15 +153,24 @@ static int fmc_dio_int_cmd_pulse(struct fmc_dio *dev,
ts->tv_sec += now;
}
if (cmd->flags & WR_DIO_F_LOOP) {
if (cmd->flags & WR_DIO_F_LOOP && cmd->value != 1) {
c->target_channel = ch;
if(dev->version == 0) {
c->delay = ts[2];
/* c->count is used after the pulse, so remove the first */
if (cmd->value > 0)
cmd->value--;
}
else {
writel(ts[2].tv_nsec / 8, base + map->pulse_per);
if (cmd->value > 1) {
cmd->value-=2;
}
}
atomic_set(&c->count, cmd->value);
c->prevts = ts[0]; /* our current setpoint */
c->delay = ts[2];
}
__fmc_dio_int_new_pulse(dev, ch, ts);
......@@ -221,7 +194,10 @@ static int fmc_dio_int_cmd_stamp(struct fmc_dio *dev,
again:
if (cmd->flags & WR_DIO_F_MASK) {
ch = 0;
if(dev->version == 0)
last = 4;
else
last = 5;
mask = cmd->channel;
} else {
ch = cmd->channel;
......@@ -233,7 +209,10 @@ again:
for (; ch <= last; ch++, c++) {
if (((1 << ch) & mask) == 0)
continue;
map = regmap + ch;
map = get_regmap(dev->version);
map += ch;
while (1) {
if (nstamp == WR_DIO_N_STAMP)
break;
......@@ -270,10 +249,13 @@ again:
static int fmc_dio_int_cmd_inout(struct fmc_dio *dev,
struct wr_dio_cmd *cmd)
{
struct DIO_WB __iomem *dio = dev->dio;
struct fmc_dio_gpio_block __iomem *gpio = dev->gpio;
int mask, ch, last, bits;
uint32_t reg, iomode;
void __iomem *base = dev->dio;
struct regmap_common dio;
dio = get_regmap_common(dev->version);
if (cmd->flags & WR_DIO_F_MASK) {
ch = 0;
......@@ -294,7 +276,7 @@ static int fmc_dio_int_cmd_inout(struct fmc_dio *dev,
bits = cmd->value >> ch;
/* Obtain the current value in iomode */
reg = readl(&dio->IOMODE) & ~(0xF << 4*ch);
reg = readl(base + dio.iomode_reg) & ~(0xF << 4*ch);
/* Select IO mode */
if (bits & WR_DIO_INOUT_DIO) {
......@@ -315,11 +297,91 @@ static int fmc_dio_int_cmd_inout(struct fmc_dio *dev,
/* Appends to iomode TERM and OUTPUT_ENABLE_N bits */
iomode |= (((bits & WR_DIO_INOUT_TERM) != 0) << 3)
| (((bits & WR_DIO_INOUT_OUTPUT) == 0) << 2);
writel(reg | (iomode << 4*ch), &dio->IOMODE);
writel(reg | (iomode << 4*ch), base + dio.iomode_reg);
}
return 0;
}
static int fmc_dio_int_cmd_irq(struct fmc_dio *dev,
struct wr_dio_cmd *cmd)
{
void __iomem *base = dev->dio;
struct PPSG_WB __iomem *ppsg = dev->ppsg;
struct dio_device *d = dev->priv;
struct dio_channel *c;
struct regmap *map;
struct timespec *ts;
uint32_t reg;
int ch;
struct regmap_common dio;
if(dev->version != 1)
return -ENOTSUPP;
dio = get_regmap_common(dev->version);
ch = 5;
c = d->ch + ch;
map = get_regmap(dev->version);
map += ch;
ts = cmd->t;
/* First, configure the IRQ channel */
reg = readl(base + dio.iomode_reg);
writel((reg | CHANNEL_5_IRQ_EN_MASK), base + dio.iomode_reg);
writel(100, base + map->pulse); /* width */
if (cmd->flags & WR_DIO_F_NOW) {
/* Generate a pulse train from current time*/
if (cmd->flags & WR_DIO_F_LOOP && cmd->value != 1) {
writel(ts[1].tv_nsec / 8, base + map->pulse_per);
c->target_channel = ch;
if (cmd->value > 1) {
cmd->value-=2;
}
atomic_set(&c->count, cmd->value);
}
writel(1 << ch, base + dio.pulse_reg);
return 0;
}
/* if relative, add current 40-bit second to timespec */
if (cmd->flags & WR_DIO_F_REL) {
uint32_t h1, l, h2;
unsigned long now;
h1 = readl(&ppsg->CNTR_UTCHI);
l = readl(&ppsg->CNTR_UTCLO);
h2 = readl(&ppsg->CNTR_UTCHI);
if (h2 != h1)
l = readl(&ppsg->CNTR_UTCLO);
now = l;
SET_HI32(now, h2);
ts->tv_sec += now;
}
if (cmd->flags & WR_DIO_F_LOOP && cmd->value != 1) {
c->target_channel = ch;
writel(ts[1].tv_nsec / 8, base + map->pulse_per);
if (cmd->value > 1) {
cmd->value-=2;
}
atomic_set(&c->count, cmd->value);
c->prevts = ts[0]; /* our current setpoint */
}
__fmc_dio_int_new_pulse(dev, ch, ts);
return 0;
}
int fmc_dio_int_ioctl(struct fmc_dio *dev, unsigned int ioctlcmd,
unsigned long arg)
......@@ -359,6 +421,9 @@ int fmc_dio_int_ioctl(struct fmc_dio *dev, unsigned int ioctlcmd,
case WR_DIO_CMD_DAC:
ret = -ENOTSUPP;
goto out;
case WR_DIO_CMD_IRQ:
ret = fmc_dio_int_cmd_irq(dev, cmd);
break;
default:
ret = -EINVAL;
goto out;
......@@ -397,7 +462,6 @@ static void fmc_dio_int_trig_next_pulse(struct fmc_dio *dev, int ch,
irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
{
struct DIO_WB __iomem *dio = dev->dio;
struct fmc_device *fmc = dev->fmc;
void __iomem *base = dev->dio;
struct dio_device *d = dev->priv;
......@@ -409,10 +473,13 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
uint32_t mask, reg;
int ch, chm;
struct regmap_common dio;
dio = get_regmap_common(dev->version);
if (unlikely(!fmc->eeprom)) {
dev_err(fmc->hwdev, "WR-DIO: No mezzanine, disabling irqs\n");
writel(~0, &dio->EIC_IDR);
writel(~0, &dio->EIC_ISR);
writel(~0, base + dio.eic_idr_reg);
writel(~0, base + dio.eic_isr_reg);
return IRQ_NONE;
}
......@@ -439,7 +506,10 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
}
}
mask = readl(&dio->EIC_ISR) & FMC_DIO_IRQ_MASK;
if(dev->version == 0)
mask = readl(base + dio.eic_isr_reg) & FMC_DIO_IRQ_MASK;
else
mask = readl(base + dio.eic_isr_reg) & FMC_DIO_IRQ_MASK_V2;
/* Three indexes: channel, channel-mask, channel pointer */
for (ch = 0, chm = 1, c = d->ch; mask; ch++, chm <<= 1, c++) {
......@@ -450,7 +520,9 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
mask &= ~chm;
/* Pull the FIFOs to the device structure */
map = regmap + ch;
map = get_regmap(dev->version);
map += ch;
ts = NULL;
while (1) {
reg = readl(base + map->fifo_status);
......@@ -472,10 +544,31 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
/* subtract 5 cycles lost in input sync circuits */
fmc_dio_int_ts_sub(ts, 40);
}
writel(chm, &dio->EIC_ISR); /* ack */
if (ts && atomic_read(&c->count) != 0) {
writel(chm, base + dio.eic_isr_reg); /* ack */
if(dev->version == 0) {
if (ts && atomic_read(&c->count) != 0 ) {
/* Only program new pulse if we are on the DIO V1 */
fmc_dio_int_trig_next_pulse(dev, ch, c, ts);
}
}
else
{
if(atomic_read(&c->count) == 0) {
/* If we are on the DIO V2, clear pulse period register
* when all the pulses have been generated
*/
writel(0, base + map->pulse_per);
writel(1 << ch, base + dio.latch_reg);
}
else {
/* If the count is not-infinite, decrement it */
if (atomic_read(&c->count) > 0)
atomic_dec(&c->count);
}
}
wake_up_interruptible(&c->q);
}
t_end = ktime_get();
......@@ -485,10 +578,13 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
/* Init and exit below are called when a netdevice is created/destroyed */
int fmc_dio_internal_create(struct fmc_dio *dev)
{
struct DIO_WB __iomem *dio = dev->dio;
struct dio_device *d;
void __iomem *base = dev->dio;
int i;
struct regmap_common dio;
dio = get_regmap_common(dev->version);
/* Allocate the data structure and enable interrupts for stamping */
d = kzalloc(sizeof(*d), GFP_KERNEL);
if (!d)
......@@ -501,15 +597,21 @@ int fmc_dio_internal_create(struct fmc_dio *dev)
* Enable interrupts for FIFO, if there's no mezzanine the
* handler will notice and disable the interrupts
*/
writel(FMC_DIO_IRQ_MASK, &dio->EIC_IER);
if(dev->version == 0)
writel(FMC_DIO_IRQ_MASK, base + dio.eic_ier_reg);
else
writel(FMC_DIO_IRQ_MASK_V2, base + dio.eic_ier_reg);
return 0;
}
void fmc_dio_internal_destroy(struct fmc_dio *dev)
{
struct DIO_WB __iomem *dio = dev->dio;
struct regmap_common dio;
void __iomem *base = dev->dio;
dio = get_regmap_common(dev->version);
writel(~0, &dio->EIC_IDR);
writel(~0, base + dio.eic_idr_reg);
if (dev->priv)
kfree(dev->priv);
}
......
......@@ -55,7 +55,7 @@ static int fmc_dio_resource_map(struct fmc_dio *dio)
{
int i,err;
struct platform_device *dev = dio->pdev;
struct fmc_device *fmc = dio->fmc;
//struct fmc_device *fmc = dio->fmc;
struct resource *r;
void __iomem *mem;
......@@ -171,6 +171,18 @@ static int fmc_dio_pl_probe(struct platform_device *dev)
dio->board = dev->id_entry->driver_data;
dio->pdev = dev;
dio->version = dio->board;
if(dio->version == FMC_DIO_BOARD_SPEC) {
printk("DIO driver. Detected DIO V1");
}
else if(dio->version == FMC_DIOv2_BOARD_SPEC) {
printk("DIO driver. Detected DIO V2");
}
else{
printk("DIO driver. DIO not detected");
}
/* Map the resources for the FMC DIO */
ret = fmc_dio_resource_map(dio);
if(ret)
......@@ -239,6 +251,10 @@ static const struct platform_device_id fmc_dio_id_table[] = {
.name = "fmc-dio-spec",
.driver_data = FMC_DIO_BOARD_SPEC,
},
{ /* SPEC compatible */
.name = "fmc-diov2-spec",
.driver_data = FMC_DIOv2_BOARD_SPEC,
},
{},
};
......
......@@ -52,6 +52,7 @@ struct fmc_dio_gpio_block {
/* Board constants */
#define FMC_DIO_BOARD_SPEC 0
#define FMC_DIOv2_BOARD_SPEC 1
/**
* @brief FMC DIO structure
......@@ -74,6 +75,8 @@ struct fmc_dio {
int board; /**< Board info */
int version; //*< HDL version */
void *priv; /**< Private data for FMC DIO */
};
......@@ -104,6 +107,7 @@ enum wr_dio_cmd_name {
WR_DIO_CMD_STAMP,
WR_DIO_CMD_DAC,
WR_DIO_CMD_INOUT,
WR_DIO_CMD_IRQ,
};
/*
......
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