2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
9 * $FreeBSD: src/sys/pci/xrpu.c,v 1.19.2.1 2000/08/02 22:19:57 peter Exp $
10 * $DragonFly: src/sys/dev/misc/xrpu/xrpu.c,v 1.13 2006/12/23 00:26:18 swildner Exp $
12 * A very simple device driver for PCI cards based on Xilinx 6200 series
13 * FPGA/RPU devices. Current Functionality is to allow you to open and
14 * mmap the entire thing into your program.
16 * Hardware currently supported:
17 * www.vcc.com HotWorks 1 6216 based card.
21 #include <sys/param.h>
22 #include <sys/systm.h>
24 #include <sys/device.h>
25 #include <sys/kernel.h>
26 #include <sys/malloc.h>
27 #include <sys/timepps.h>
28 #include <sys/xrpuio.h>
32 #include <bus/pci/pcireg.h>
33 #include <bus/pci/pcivar.h>
38 * Device driver initialization stuff
41 static d_open_t xrpu_open
;
42 static d_close_t xrpu_close
;
43 static d_ioctl_t xrpu_ioctl
;
44 static d_mmap_t xrpu_mmap
;
46 #define CDEV_MAJOR 100
47 static struct dev_ops xrpu_ops
= {
48 { "xrpu", CDEV_MAJOR
, 0 },
50 .d_close
= xrpu_close
,
51 .d_ioctl
= xrpu_ioctl
,
55 static MALLOC_DEFINE(M_XRPU
, "xrpu", "XRPU related");
57 static devclass_t xrpu_devclass
;
59 #define dev2unit(devt) (minor(devt) & 0xff)
60 #define dev2pps(devt) ((minor(devt) >> 16)-1)
63 enum { NORMAL
, TIMECOUNTER
} mode
;
64 vm_offset_t virbase
, physbase
;
67 struct timecounter tc
;
69 u_int
*trigger
, *latch
, dummy
;
70 struct pps_state pps
[XRPU_MAX_PPS
];
71 u_int
*assert[XRPU_MAX_PPS
], *clear
[XRPU_MAX_PPS
];
77 xrpu_get_timecount(struct timecounter
*tc
)
79 struct softc
*sc
= tc
->tc_priv
;
81 sc
->dummy
+= *sc
->trigger
;
82 return (*sc
->latch
& tc
->tc_counter_mask
);
86 xrpu_poll_pps(struct timecounter
*tc
)
88 struct softc
*sc
= tc
->tc_priv
;
90 unsigned count1
, ppscount
;
92 for (i
= 0; i
< XRPU_MAX_PPS
; i
++) {
94 ppscount
= *(sc
->assert[i
]) & tc
->tc_counter_mask
;
98 ppscount
= *(sc
->assert[i
]) & tc
->tc_counter_mask
;
99 } while (ppscount
!= count1
&& ++j
< 5);
100 pps_event(&sc
->pps
[i
], tc
, ppscount
, PPS_CAPTUREASSERT
);
104 ppscount
= *(sc
->clear
[i
]) & tc
->tc_counter_mask
;
107 ppscount
= *(sc
->clear
[i
]) & tc
->tc_counter_mask
;
108 } while (ppscount
!= count1
&& ++j
< 5);
109 pps_event(&sc
->pps
[i
], tc
, ppscount
, PPS_CAPTURECLEAR
);
117 xrpu_open(struct dev_open_args
*ap
)
119 cdev_t dev
= ap
->a_head
.a_dev
;
120 struct softc
*sc
= devclass_get_softc(xrpu_devclass
, dev2unit(dev
));
129 xrpu_close(struct dev_close_args
*ap
)
135 xrpu_mmap(struct dev_mmap_args
*ap
)
137 cdev_t dev
= ap
->a_head
.a_dev
;
138 struct softc
*sc
= dev
->si_drv1
;
140 if (ap
->a_offset
>= 0x1000000)
142 return (i386_btop(sc
->physbase
+ ap
->a_offset
));
146 xrpu_ioctl(struct dev_ioctl_args
*ap
)
148 cdev_t dev
= ap
->a_head
.a_dev
;
149 struct softc
*sc
= dev
->si_drv1
;
152 if (sc
->mode
== TIMECOUNTER
) {
154 if (i
< 0 || i
>= XRPU_MAX_PPS
)
156 error
= pps_ioctl(ap
->a_cmd
, ap
->a_data
, &sc
->pps
[i
]);
161 if (ap
->a_cmd
== XRPU_IOC_TIMECOUNTING
) {
162 struct xrpu_timecounting
*xt
= (struct xrpu_timecounting
*)ap
->a_data
;
164 /* Name SHALL be zero terminated */
165 xt
->xt_name
[sizeof xt
->xt_name
- 1] = '\0';
166 i
= strlen(xt
->xt_name
);
167 sc
->tc
.tc_name
= (char *)kmalloc(i
+ 1, M_XRPU
, M_WAITOK
);
168 strcpy(sc
->tc
.tc_name
, xt
->xt_name
);
169 sc
->tc
.tc_frequency
= xt
->xt_frequency
;
170 sc
->tc
.tc_get_timecount
= xrpu_get_timecount
;
171 sc
->tc
.tc_poll_pps
= xrpu_poll_pps
;
173 sc
->tc
.tc_counter_mask
= xt
->xt_mask
;
174 sc
->trigger
= sc
->virbase62
+ xt
->xt_addr_trigger
;
175 sc
->latch
= sc
->virbase62
+ xt
->xt_addr_latch
;
177 for (i
= 0; i
< XRPU_MAX_PPS
; i
++) {
178 if (xt
->xt_pps
[i
].xt_addr_assert
== 0
179 && xt
->xt_pps
[i
].xt_addr_clear
== 0)
181 make_dev(&xrpu_ops
, (i
+1)<<16,
182 UID_ROOT
, GID_WHEEL
, 0600, "xpps%d", i
);
183 sc
->pps
[i
].ppscap
= 0;
184 if (xt
->xt_pps
[i
].xt_addr_assert
) {
185 sc
->assert[i
] = sc
->virbase62
+ xt
->xt_pps
[i
].xt_addr_assert
;
186 sc
->pps
[i
].ppscap
|= PPS_CAPTUREASSERT
;
188 if (xt
->xt_pps
[i
].xt_addr_clear
) {
189 sc
->clear
[i
] = sc
->virbase62
+ xt
->xt_pps
[i
].xt_addr_clear
;
190 sc
->pps
[i
].ppscap
|= PPS_CAPTURECLEAR
;
192 pps_init(&sc
->pps
[i
]);
194 sc
->mode
= TIMECOUNTER
;
195 init_timecounter(&sc
->tc
);
204 * PCI initialization stuff
208 xrpu_probe(device_t self
)
213 switch (pci_get_devid(self
)) {
215 desc
= "VCC Hotworks-I xc6216";
221 device_set_desc(self
, desc
);
226 xrpu_attach(device_t self
)
229 struct resource
*res
;
232 unit
= device_get_unit(self
);
233 sc
= device_get_softc(self
);
236 res
= bus_alloc_resource(self
, SYS_RES_MEMORY
, &rid
,
237 0, ~0, 1, RF_ACTIVE
);
239 device_printf(self
, "Could not map memory\n");
242 sc
->virbase
= (vm_offset_t
)rman_get_virtual(res
);
243 sc
->physbase
= rman_get_start(res
);
244 sc
->virbase62
= (u_int
*)(sc
->virbase
+ 0x800000);
247 kprintf("Mapped physbase %#lx to virbase %#lx\n",
248 (u_long
)sc
->physbase
, (u_long
)sc
->virbase
);
250 dev_ops_add(&xrpu_ops
, -1, unit
);
251 make_dev(&xrpu_ops
, unit
, UID_ROOT
, GID_WHEEL
, 0600, "xrpu%d", unit
);
255 static device_method_t xrpu_methods
[] = {
256 /* Device interface */
257 DEVMETHOD(device_probe
, xrpu_probe
),
258 DEVMETHOD(device_attach
, xrpu_attach
),
259 DEVMETHOD(device_suspend
, bus_generic_suspend
),
260 DEVMETHOD(device_resume
, bus_generic_resume
),
261 DEVMETHOD(device_shutdown
, bus_generic_shutdown
),
266 static driver_t xrpu_driver
= {
273 DRIVER_MODULE(xrpu
, pci
, xrpu_driver
, xrpu_devclass
, 0, 0);