a3fc4f8d22bb7f700ea19ff949930e00f3bf9b11
[dragonfly.git] / sys / dev / misc / xrpu / xrpu.c
1 /*
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  * ----------------------------------------------------------------------------
8  *
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.13 2006/12/22 23:26:18 swildner Exp $
11  *
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.
15  *
16  * Hardware currently supported:
17  *      www.vcc.com HotWorks 1 6216 based card.
18  *
19  */
20
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/conf.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>
29 #include <sys/bus.h>
30 #include <sys/rman.h>
31
32 #include <bus/pci/pcireg.h>
33 #include <bus/pci/pcivar.h>
34
35 #include "pci_if.h"
36
37 /*
38  * Device driver initialization stuff
39  */
40
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;
45
46 #define CDEV_MAJOR 100
47 static struct dev_ops xrpu_ops = {
48         { "xrpu", CDEV_MAJOR, 0 },
49         .d_open =       xrpu_open,
50         .d_close =      xrpu_close,
51         .d_ioctl =      xrpu_ioctl,
52         .d_mmap =       xrpu_mmap,
53 };
54
55 static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related");
56
57 static devclass_t xrpu_devclass;
58
59 #define dev2unit(devt) (minor(devt) & 0xff)
60 #define dev2pps(devt) ((minor(devt) >> 16)-1)
61
62 struct softc {
63         enum { NORMAL, TIMECOUNTER } mode;
64         vm_offset_t virbase, physbase;
65         u_int   *virbase62;
66 #if 0
67         struct timecounter tc;
68 #endif
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];
72 };
73
74 #if 0
75
76 static unsigned         
77 xrpu_get_timecount(struct timecounter *tc)
78 {               
79         struct softc *sc = tc->tc_priv;
80
81         sc->dummy += *sc->trigger;
82         return (*sc->latch & tc->tc_counter_mask);
83 }        
84
85 static void            
86 xrpu_poll_pps(struct timecounter *tc)
87 {               
88         struct softc *sc = tc->tc_priv;
89         int i, j;
90         unsigned count1, ppscount; 
91                 
92         for (i = 0; i < XRPU_MAX_PPS; i++) {
93                 if (sc->assert[i]) {
94                         ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
95                         j = 0;
96                         do {
97                                 count1 = ppscount;
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);
101                 }
102                 if (sc->clear[i]) {
103                         j = 0;
104                         ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
105                         do {
106                                 count1 = ppscount;
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);
110                 }
111         }
112 }
113
114 #endif
115
116 static int
117 xrpu_open(struct dev_open_args *ap)
118 {
119         cdev_t dev = ap->a_head.a_dev;
120         struct softc *sc = devclass_get_softc(xrpu_devclass, dev2unit(dev));
121
122         if (!sc)
123                 return (ENXIO);
124         dev->si_drv1 = sc;
125         return (0);
126 }
127
128 static int
129 xrpu_close(struct dev_close_args *ap)
130 {
131         return (0);
132 }
133
134 static int
135 xrpu_mmap(struct dev_mmap_args *ap)
136 {
137         cdev_t dev = ap->a_head.a_dev;
138         struct softc *sc = dev->si_drv1;
139
140         if (ap->a_offset >= 0x1000000) 
141                 return (-1);
142         return (i386_btop(sc->physbase + ap->a_offset));
143 }
144
145 static int
146 xrpu_ioctl(struct dev_ioctl_args *ap)
147 {
148         cdev_t dev = ap->a_head.a_dev;
149         struct softc *sc = dev->si_drv1;
150         int i, error;
151
152         if (sc->mode == TIMECOUNTER) {
153                 i = dev2pps(dev);
154                 if (i < 0 || i >= XRPU_MAX_PPS)
155                         return ENODEV;
156                 error =  pps_ioctl(ap->a_cmd, ap->a_data, &sc->pps[i]);
157                 return (error);
158         }
159                 
160 #if 0
161         if (ap->a_cmd == XRPU_IOC_TIMECOUNTING) {
162                 struct xrpu_timecounting *xt = (struct xrpu_timecounting *)ap->a_data;
163
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;
172                 sc->tc.tc_priv = sc;
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;
176
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)
180                                 continue;
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;
187                         }
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;
191                         }
192                         pps_init(&sc->pps[i]);
193                 }
194                 sc->mode = TIMECOUNTER;
195                 init_timecounter(&sc->tc);
196                 return (0);
197         }
198 #endif
199         error = ENOTTY;
200         return (error);
201 }
202
203 /*
204  * PCI initialization stuff
205  */
206
207 static int
208 xrpu_probe(device_t self)
209 {
210         char *desc;
211
212         desc = NULL;
213         switch (pci_get_devid(self)) {
214         case 0x6216133e:
215                 desc = "VCC Hotworks-I xc6216";
216                 break;
217         }
218         if (desc == NULL)
219                 return ENXIO;
220
221         device_set_desc(self, desc);
222         return 0;
223 }
224
225 static int
226 xrpu_attach(device_t self)
227 {
228         struct softc *sc;
229         struct resource *res;
230         int rid, unit;
231
232         unit = device_get_unit(self);
233         sc = device_get_softc(self);
234         sc->mode = NORMAL;
235         rid = PCIR_MAPS;
236         res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
237                                  0, ~0, 1, RF_ACTIVE);
238         if (res == NULL) {
239                 device_printf(self, "Could not map memory\n");
240                 return ENXIO;
241         }
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);
245
246         if (bootverbose)
247                 kprintf("Mapped physbase %#lx to virbase %#lx\n",
248                     (u_long)sc->physbase, (u_long)sc->virbase);
249
250         dev_ops_add(&xrpu_ops, -1, unit);
251         make_dev(&xrpu_ops, unit, UID_ROOT, GID_WHEEL, 0600, "xrpu%d", unit);
252         return 0;
253 }
254
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),
262
263         {0, 0}
264 };
265  
266 static driver_t xrpu_driver = {
267         "xrpu",
268         xrpu_methods,
269         sizeof(struct softc)
270 };
271  
272  
273 DRIVER_MODULE(xrpu, pci, xrpu_driver, xrpu_devclass, 0, 0);