Merge from vendor branch CVS:
[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.8 2004/05/19 22:52:45 dillon 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/kernel.h>
25 #include <sys/malloc.h>
26 #include <sys/timepps.h>
27 #include <sys/xrpuio.h>
28 #include <sys/bus.h>
29 #include <machine/bus.h>
30 #include <sys/rman.h>
31 #include <machine/resource.h>
32 #include <bus/pci/pcireg.h>
33 #include <bus/pci/pcivar.h>
34 #include "pci_if.h"
35
36 /*
37  * Device driver initialization stuff
38  */
39
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;
44
45 #define CDEV_MAJOR 100
46 static struct cdevsw xrpu_cdevsw = {
47         /* name */      "xrpu",
48         /* maj */       CDEV_MAJOR,
49         /* flags */     0,
50         /* port */      NULL,
51         /* clone */     NULL,
52
53         /* open */      xrpu_open,
54         /* close */     xrpu_close,
55         /* read */      noread,
56         /* write */     nowrite,
57         /* ioctl */     xrpu_ioctl,
58         /* poll */      nopoll,
59         /* mmap */      xrpu_mmap,
60         /* strategy */  nostrategy,
61         /* dump */      nodump,
62         /* psize */     nopsize
63 };
64
65 static MALLOC_DEFINE(M_XRPU, "xrpu", "XRPU related");
66
67 static devclass_t xrpu_devclass;
68
69 #define dev2unit(devt) (minor(devt) & 0xff)
70 #define dev2pps(devt) ((minor(devt) >> 16)-1)
71
72 struct softc {
73         enum { NORMAL, TIMECOUNTER } mode;
74         vm_offset_t virbase, physbase;
75         u_int   *virbase62;
76 #if 0
77         struct timecounter tc;
78 #endif
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];
82 };
83
84 #if 0
85
86 static unsigned         
87 xrpu_get_timecount(struct timecounter *tc)
88 {               
89         struct softc *sc = tc->tc_priv;
90
91         sc->dummy += *sc->trigger;
92         return (*sc->latch & tc->tc_counter_mask);
93 }        
94
95 static void            
96 xrpu_poll_pps(struct timecounter *tc)
97 {               
98         struct softc *sc = tc->tc_priv;
99         int i, j;
100         unsigned count1, ppscount; 
101                 
102         for (i = 0; i < XRPU_MAX_PPS; i++) {
103                 if (sc->assert[i]) {
104                         ppscount = *(sc->assert[i]) & tc->tc_counter_mask;
105                         j = 0;
106                         do {
107                                 count1 = ppscount;
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);
111                 }
112                 if (sc->clear[i]) {
113                         j = 0;
114                         ppscount = *(sc->clear[i]) & tc->tc_counter_mask;
115                         do {
116                                 count1 = ppscount;
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);
120                 }
121         }
122 }
123
124 #endif
125
126 static int
127 xrpu_open(dev_t dev, int flag, int mode, struct thread *td)
128 {
129         struct softc *sc = devclass_get_softc(xrpu_devclass, dev2unit(dev));
130
131         if (!sc)
132                 return (ENXIO);
133         dev->si_drv1 = sc;
134         return (0);
135 }
136
137 static int
138 xrpu_close(dev_t dev, int flag, int mode, struct thread *td)
139
140         return (0);
141 }
142
143 static int
144 xrpu_mmap(dev_t dev, vm_offset_t offset, int nprot)
145 {
146         struct softc *sc = dev->si_drv1;
147         if (offset >= 0x1000000) 
148                 return (-1);
149         return (i386_btop(sc->physbase + offset));
150 }
151
152 static int
153 xrpu_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td)
154 {
155         struct softc *sc = dev->si_drv1;
156         int i, error;
157
158         if (sc->mode == TIMECOUNTER) {
159                 i = dev2pps(dev);
160                 if (i < 0 || i >= XRPU_MAX_PPS)
161                         return ENODEV;
162                 error =  pps_ioctl(cmd, arg, &sc->pps[i]);
163                 return (error);
164         }
165                 
166 #if 0
167         if (cmd == XRPU_IOC_TIMECOUNTING) {
168                 struct xrpu_timecounting *xt = (struct xrpu_timecounting *)arg;
169
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;
178                 sc->tc.tc_priv = sc;
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;
182
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)
186                                 continue;
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;
193                         }
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;
197                         }
198                         pps_init(&sc->pps[i]);
199                 }
200                 sc->mode = TIMECOUNTER;
201                 init_timecounter(&sc->tc);
202                 return (0);
203         }
204 #endif
205         error = ENOTTY;
206         return (error);
207 }
208
209 /*
210  * PCI initialization stuff
211  */
212
213 static int
214 xrpu_probe(device_t self)
215 {
216         char *desc;
217
218         desc = NULL;
219         switch (pci_get_devid(self)) {
220         case 0x6216133e:
221                 desc = "VCC Hotworks-I xc6216";
222                 break;
223         }
224         if (desc == NULL)
225                 return ENXIO;
226
227         device_set_desc(self, desc);
228         return 0;
229 }
230
231 static int
232 xrpu_attach(device_t self)
233 {
234         struct softc *sc;
235         struct resource *res;
236         int rid, unit;
237
238         unit = device_get_unit(self);
239         sc = device_get_softc(self);
240         sc->mode = NORMAL;
241         rid = PCIR_MAPS;
242         res = bus_alloc_resource(self, SYS_RES_MEMORY, &rid,
243                                  0, ~0, 1, RF_ACTIVE);
244         if (res == NULL) {
245                 device_printf(self, "Could not map memory\n");
246                 return ENXIO;
247         }
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);
251
252         if (bootverbose)
253                 printf("Mapped physbase %#lx to virbase %#lx\n",
254                     (u_long)sc->physbase, (u_long)sc->virbase);
255
256         cdevsw_add(&xrpu_cdevsw, -1, unit);
257         make_dev(&xrpu_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600, "xrpu%d", unit);
258         return 0;
259 }
260
261 static device_method_t xrpu_methods[] = {
262         /* Device interface */
263         DEVMETHOD(device_probe,         xrpu_probe),
264         DEVMETHOD(device_attach,        xrpu_attach),
265         DEVMETHOD(device_suspend,       bus_generic_suspend),
266         DEVMETHOD(device_resume,        bus_generic_resume),
267         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
268
269         {0, 0}
270 };
271  
272 static driver_t xrpu_driver = {
273         "xrpu",
274         xrpu_methods,
275         sizeof(struct softc)
276 };
277  
278  
279 DRIVER_MODULE(xrpu, pci, xrpu_driver, xrpu_devclass, 0, 0);