Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC DIO 5ch TTL a
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
6
Issues
6
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
FMC DIO 5ch TTL a
Commits
8cd60f90
Commit
8cd60f90
authored
May 05, 2020
by
Jorge Machado
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for new version in fmc-dio-internal.c
parent
821f8f8a
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
235 additions
and
42 deletions
+235
-42
fmc-dio-internal.c
sw/kernel/fmc-dio-internal.c
+235
-42
No files found.
sw/kernel/fmc-dio-internal.c
View file @
8cd60f90
...
...
@@ -32,8 +32,10 @@
#define fmc_dio_stat 0
#endif
#define CHANNEL_5_IRQ_EN_MASK 0x100000
/* We need a clear mapping for the registers of the various bits */
struct
regmap
{
/*
struct regmap {
int trig_l;
int trig_h;
int cycle;
...
...
@@ -92,15 +94,23 @@ static struct regmap regmap[] = {
.fifo_cycle = R(TSF4_R2),
.fifo_status = R(TSF4_CSR),
}
};
};
*/
#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 +125,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 +138,30 @@ 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
;
//
struct DIO_WB __iomem *dio = dev->dio;
void
__iomem
*
base
=
d
ev
->
d
io
;
struct
regmap
*
map
;
map
=
regmap
+
ch
;
struct
regmap_common
dio
;
dio
=
get_regmap_common
(
dev
->
version
);
//map = regmap + ch;
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
;
//
struct DIO_WB __iomem *dio = dev->dio;
void
__iomem
*
base
=
d
ev
->
d
io
;
struct
PPSG_WB
__iomem
*
ppsg
=
dev
->
ppsg
;
struct
dio_device
*
d
=
dev
->
priv
;
struct
dio_channel
*
c
;
...
...
@@ -154,31 +169,51 @@ static int fmc_dio_int_cmd_pulse(struct fmc_dio *dev,
struct
timespec
*
ts
;
uint32_t
reg
;
int
ch
;
struct
regmap_common
dio
;
printk
(
"PULSE"
);
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 = 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
)
{
printk
(
"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
)
{
printk
(
"loop enabled %lu, %d"
,
ts
[
2
].
tv_nsec
,
cmd
->
value
);
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
;
printk
(
"with relative time"
);
h1
=
readl
(
&
ppsg
->
CNTR_UTCHI
);
l
=
readl
(
&
ppsg
->
CNTR_UTCLO
);
h2
=
readl
(
&
ppsg
->
CNTR_UTCHI
);
...
...
@@ -189,15 +224,26 @@ 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
)
{
printk
(
"loop enabled"
);
c
->
target_channel
=
ch
;
printk
(
"%d times"
,
cmd
->
value
);
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 +267,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 +282,12 @@ again:
for
(;
ch
<=
last
;
ch
++
,
c
++
)
{
if
(((
1
<<
ch
)
&
mask
)
==
0
)
continue
;
map
=
regmap
+
ch
;
printk
(
"Getting timestamps of channel %d"
,
ch
);
//map = regmap + ch;
map
=
get_regmap
(
dev
->
version
);
map
+=
ch
;
while
(
1
)
{
if
(
nstamp
==
WR_DIO_N_STAMP
)
break
;
...
...
@@ -270,10 +324,14 @@ 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 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 +352,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 +373,99 @@ 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
;
printk
(
"IRQ"
);
dio
=
get_regmap_common
(
dev
->
version
);
ch
=
5
;
c
=
d
->
ch
+
ch
;
//map = regmap + 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
)
{
printk
(
"NOW"
);
/* Generate a pulse train from current time*/
if
(
cmd
->
flags
&
WR_DIO_F_LOOP
&&
cmd
->
value
!=
1
)
{
printk
(
"loop enabled %lu, %d"
,
ts
[
1
].
tv_nsec
,
cmd
->
value
);
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
);
}
printk
(
"writing %d in 0x%08x"
,
1
<<
ch
,
dio
.
pulse_reg
);
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
;
printk
(
"with relative time"
);
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
)
{
printk
(
"loop enabled"
);
c
->
target_channel
=
ch
;
printk
(
"%d times"
,
cmd
->
value
);
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 +505,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 +546,7 @@ 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 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 +558,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 +591,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,12 +605,16 @@ irqreturn_t fmc_dio_int_interrupt(struct fmc_dio *dev)
mask
&=
~
chm
;
/* Pull the FIFOs to the device structure */
map
=
regmap
+
ch
;
//map = regmap + ch;
map
=
get_regmap
(
dev
->
version
);
map
+=
ch
;
ts
=
NULL
;
while
(
1
)
{
reg
=
readl
(
base
+
map
->
fifo_status
);
if
(
reg
&
0x20000
)
/* empty */
break
;
printk
(
"channel %d not empty"
,
ch
);
h
=
c
->
bhead
;
ts
=
c
->
tsbuf
+
h
;
c
->
bhead
=
(
h
+
1
)
%
FMC_DIO_BUFFER_LEN
;
...
...
@@ -472,10 +631,32 @@ 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
{
printk
(
"channel %d %d"
,
ch
,
atomic_read
(
&
c
->
count
));
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 +666,14 @@ 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_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 +686,23 @@ 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
);
//writel(FMC_DIO_IRQ_MASK, base + dio.eic_ier_reg);
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 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
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment