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/Attic/xrpu.c,v 1.6 2004/01/30 05:42:15 dillon 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/kernel.h>
25 #include <sys/malloc.h>
26 #include <sys/timepps.h>
27 #include <sys/xrpuio.h>
29 #include <machine/bus.h>
31 #include <machine/resource.h>
32 #include <bus/pci/pcireg.h>
33 #include <bus/pci/pcivar.h>
37 * Device driver initialization stuff
40 static d_open_t xrpu_open;
41 static d_close_t xrpu_close;
42 static d_ioctl_t xrpu_ioctl;
43 static d_mmap_t xrpu_mmap;
45 #define CDEV_MAJOR 100
46 static struct cdevsw xrpu_cdevsw = {
54 /* close */ xrpu_close,
57 /* ioctl */ xrpu_ioctl,
60 /* strategy */ nostrategy,
65 static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related");
67 static devclass_t xrpu_devclass;
69 #define dev2unit(devt) (minor(devt) & 0xff)
70 #define dev2pps(devt) ((minor(devt) >> 16)-1)
73 enum { NORMAL, TIMECOUNTER } mode;
74 vm_offset_t virbase, physbase;
77 struct timecounter tc;
79 u_int *trigger, *latch, dummy;
80 struct pps_state pps[XRPU_MAX_PPS];
81 u_int *assert[XRPU_MAX_PPS], *clear[XRPU_MAX_PPS];
87 xrpu_get_timecount(struct timecounter *tc)
89 struct softc *sc = tc->tc_priv;
91 sc->dummy += *sc->trigger;
92 return (*sc->latch & tc->tc_counter_mask);
96 xrpu_poll_pps(struct timecounter *tc)
98 struct softc *sc = tc->tc_priv;
100 unsigned count1, ppscount;
102 for (i = 0; i < XRPU_MAX_PPS; i++) {
104 ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
108 ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
109 } while (ppscount != count1 && ++j < 5);
110 pps_event(&sc->pps[i], tc, ppscount, PPS_CAPTUREASSERT);
114 ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
117 ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
118 } while (ppscount != count1 && ++j < 5);
119 pps_event(&sc->pps[i], tc, ppscount, PPS_CAPTURECLEAR);
127 xrpu_open(dev_t dev, int flag, int mode, struct thread *td)
129 struct softc *sc = devclass_get_softc(xrpu_devclass, dev2unit(dev));
138 xrpu_close(dev_t dev, int flag, int mode, struct thread *td)
144 xrpu_mmap(dev_t dev, vm_offset_t offset, int nprot)
146 struct softc *sc = dev->si_drv1;
147 if (offset >= 0x1000000)
149 return (i386_btop(sc->physbase + offset));
153 xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
155 struct softc *sc = dev->si_drv1;
158 if (sc->mode == TIMECOUNTER) {
160 if (i < 0 || i >= XRPU_MAX_PPS)
162 error = pps_ioctl(cmd, arg, &sc->pps[i]);
167 if (cmd == XRPU_IOC_TIMECOUNTING) {
168 struct xrpu_timecounting *xt = (struct xrpu_timecounting *)arg;
170 /* Name SHALL be zero terminated */
171 xt->xt_name[sizeof xt->xt_name - 1] = '\0';
172 i = strlen(xt->xt_name);
173 sc->tc.tc_name = (char *)malloc(i + 1, M_XRPU, M_WAITOK);
174 strcpy(sc->tc.tc_name, xt->xt_name);
175 sc->tc.tc_frequency = xt->xt_frequency;
176 sc->tc.tc_get_timecount = xrpu_get_timecount;
177 sc->tc.tc_poll_pps = xrpu_poll_pps;
179 sc->tc.tc_counter_mask = xt->xt_mask;
180 sc->trigger = sc->virbase62 + xt->xt_addr_trigger;
181 sc->latch = sc->virbase62 + xt->xt_addr_latch;
183 for (i = 0; i < XRPU_MAX_PPS; i++) {
184 if (xt->xt_pps[i].xt_addr_assert == 0
185 && xt->xt_pps[i].xt_addr_clear == 0)
187 make_dev(&xrpu_cdevsw, (i+1)<<16,
188 UID_ROOT, GID_WHEEL, 0600, "xpps%d", i);
189 sc->pps[i].ppscap = 0;
190 if (xt->xt_pps[i].xt_addr_assert) {
191 sc->assert[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_assert;
192 sc->pps[i].ppscap |= PPS_CAPTUREASSERT;
194 if (xt->xt_pps[i].xt_addr_clear) {
195 sc->clear[i] = sc->virbase62 + xt->xt_pps[i].xt_addr_clear;
196 sc->pps[i].ppscap |= PPS_CAPTURECLEAR;
198 pps_init(&sc->pps[i]);
200 sc->mode = TIMECOUNTER;
201 init_timecounter(&sc->tc);
210 * PCI initialization stuff
214 xrpu_probe(device_t self)
219 switch (pci_get_devid(self)) {
221 desc = "VCC Hotworks-I xc6216";
227 device_set_desc(self, desc);
232 xrpu_attach(device_t self)
235 struct resource *res;
238 unit = device_get_unit(self);
239 sc = device_get_softc(self);
242 res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
243 0, ~0, 1, RF_ACTIVE);
245 device_printf(self, "Could not map memory\n");
248 sc->virbase = (vm_offset_t)rman_get_virtual(res);
249 sc->physbase = rman_get_start(res);
250 sc->virbase62 = (u_int *)(sc->virbase + 0x800000);
253 printf("Mapped physbase %#lx to virbase %#lx\n",
254 (u_long)sc->physbase, (u_long)sc->virbase);
256 make_dev(&xrpu_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "xrpu%d", unit);
260 static device_method_t xrpu_methods[] = {
261 /* Device interface */
262 DEVMETHOD(device_probe, xrpu_probe),
263 DEVMETHOD(device_attach, xrpu_attach),
264 DEVMETHOD(device_suspend, bus_generic_suspend),
265 DEVMETHOD(device_resume, bus_generic_resume),
266 DEVMETHOD(device_shutdown, bus_generic_shutdown),
271 static driver_t xrpu_driver = {
278 DRIVER_MODULE(xrpu, pci, xrpu_driver, xrpu_devclass, 0, 0);