]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/i386/i386/elan-mmcr.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / i386 / i386 / elan-mmcr.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  *
10  * The AMD Elan sc520 is a system-on-chip gadget which is used in embedded
11  * kind of things, see www.soekris.com for instance, and it has a few quirks
12  * we need to deal with.
13  * Unfortunately we cannot identify the gadget by CPUID output because it
14  * depends on strapping options and only the stepping field may be useful
15  * and those are undocumented from AMDs side.
16  *
17  * So instead we recognize the on-chip host-PCI bridge and call back from
18  * sys/i386/pci/pci_bus.c to here if we find it.
19  *
20  * #ifdef CPU_ELAN_PPS
21  *   The Elan has three general purpose counters, and when two of these
22  *   are used just right they can hardware timestamp external events with
23  *   approx 125 nsec resolution and +/- 125 nsec precision.
24  *
25  *   Connect the signal to TMR1IN and a GPIO pin, and configure the GPIO pin
26  *   with a 'P' in sysctl machdep.elan_gpio_config.
27  *
28  *   The rising edge of the signal will start timer 1 counting up from
29  *   zero, and when the timecounter polls for PPS, both counter 1 & 2 is
30  *   read, as well as the GPIO bit.  If a rising edge has happened, the
31  *   contents of timer 1 which is how long time ago the edge happened,
32  *   is subtracted from timer 2 to give us a "true time stamp".
33  *
34  *   Echoing the PPS signal on any GPIO pin is supported (set it to 'e'
35  *   or 'E' (inverted) in the sysctl)  The echo signal should only be
36  *   used as a visual indication, not for calibration since it suffers
37  *   from 1/hz (or more) jitter which the timestamps are compensated for.
38  * #endif CPU_ELAN_PPS
39  */
40
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 #include "opt_cpu.h"
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/conf.h>
49 #include <sys/sysctl.h>
50 #include <sys/syslog.h>
51 #include <sys/timetc.h>
52 #include <sys/proc.h>
53 #include <sys/uio.h>
54 #include <sys/lock.h>
55 #include <sys/mutex.h>
56 #include <sys/malloc.h>
57 #include <sys/sysctl.h>
58 #include <sys/timepps.h>
59 #include <sys/watchdog.h>
60
61 #include <dev/led/led.h>
62 #include <machine/md_var.h>
63 #include <machine/elan_mmcr.h>
64 #include <machine/pc/bios.h>
65
66 #include <vm/vm.h>
67 #include <vm/pmap.h>
68
69 static char gpio_config[33];
70
71 static volatile uint16_t *mmcrptr;
72 volatile struct elan_mmcr *elan_mmcr;
73
74 #ifdef CPU_ELAN_PPS
75 static struct pps_state elan_pps;
76 static volatile uint16_t *pps_ap[3];
77 static u_int    pps_a, pps_d;
78 static u_int    echo_a, echo_d;
79 #endif /* CPU_ELAN_PPS */
80
81 #ifdef CPU_SOEKRIS
82
83 static struct bios_oem bios_soekris = {
84         { 0xf0000, 0xf1000 },
85         {
86                 { "Soekris", 0, 8 },    /* Soekris Engineering. */
87                 { "net4", 0, 8 },       /* net45xx */
88                 { "comBIOS", 0, 54 },   /* comBIOS ver. 1.26a  20040819 ... */
89                 { NULL, 0, 0 },
90         }
91 };
92
93 #endif
94
95 static u_int    led_cookie[32];
96 static struct cdev *led_dev[32];
97
98 static void
99 gpio_led(void *cookie, int state)
100 {
101         u_int u, v;
102
103         u = *(int *)cookie;
104         v = u & 0xffff;
105         u >>= 16;
106         if (!state)
107                 v ^= 0xc;
108         mmcrptr[v / 2] = u;
109 }
110
111 static int
112 sysctl_machdep_elan_gpio_config(SYSCTL_HANDLER_ARGS)
113 {
114         u_int u, v;
115         int i, np, ne;
116         int error;
117         char buf[32];
118         char tmp[10];
119
120         error = SYSCTL_OUT(req, gpio_config, 33);
121         if (error != 0 || req->newptr == NULL)
122                 return (error);
123         if (req->newlen != 32)
124                 return (EINVAL);
125         error = SYSCTL_IN(req, buf, 32);
126         if (error != 0)
127                 return (error);
128         /* Disallow any disabled pins and count pps and echo */
129         np = ne = 0;
130         for (i = 0; i < 32; i++) {
131                 if (gpio_config[i] == '-' && buf[i] == '.')
132                         buf[i] = gpio_config[i];
133                 if (gpio_config[i] == '-' && buf[i] != '-')
134                         return (EPERM);
135                 if (buf[i] == 'P') {
136                         np++;
137                         if (np > 1)
138                                 return (EINVAL);
139                 }
140                 if (buf[i] == 'e' || buf[i] == 'E') {
141                         ne++;
142                         if (ne > 1)
143                                 return (EINVAL);
144                 }
145                 if (buf[i] != 'L' && buf[i] != 'l'
146 #ifdef CPU_ELAN_PPS
147                     && buf[i] != 'P' && buf[i] != 'E' && buf[i] != 'e'
148 #endif /* CPU_ELAN_PPS */
149                     && buf[i] != '.' && buf[i] != '-')
150                         return (EINVAL);
151         }
152 #ifdef CPU_ELAN_PPS
153         if (np == 0)
154                 pps_a = pps_d = 0;
155         if (ne == 0)
156                 echo_a = echo_d = 0;
157 #endif
158         for (i = 0; i < 32; i++) {
159                 u = 1 << (i & 0xf);
160                 if (i >= 16)
161                         v = 2;
162                 else
163                         v = 0;
164 #ifdef CPU_SOEKRIS
165                 if (i == 9)
166                         ;
167                 else
168 #endif
169                 if (buf[i] != 'l' && buf[i] != 'L' && led_dev[i] != NULL) {
170                         led_destroy(led_dev[i]);        
171                         led_dev[i] = NULL;
172                         mmcrptr[(0xc2a + v) / 2] &= ~u;
173                 }
174                 switch (buf[i]) {
175 #ifdef CPU_ELAN_PPS
176                 case 'P':
177                         pps_d = u;
178                         pps_a = 0xc30 + v;
179                         pps_ap[0] = &mmcrptr[pps_a / 2];
180                         pps_ap[1] = &elan_mmcr->GPTMR2CNT;
181                         pps_ap[2] = &elan_mmcr->GPTMR1CNT;
182                         mmcrptr[(0xc2a + v) / 2] &= ~u;
183                         gpio_config[i] = buf[i];
184                         break;
185                 case 'e':
186                 case 'E':
187                         echo_d = u;
188                         if (buf[i] == 'E')
189                                 echo_a = 0xc34 + v;
190                         else
191                                 echo_a = 0xc38 + v;
192                         mmcrptr[(0xc2a + v) / 2] |= u;
193                         gpio_config[i] = buf[i];
194                         break;
195 #endif /* CPU_ELAN_PPS */
196                 case 'l':
197                 case 'L':
198                         if (buf[i] == 'L')
199                                 led_cookie[i] = (0xc34 + v) | (u << 16);
200                         else
201                                 led_cookie[i] = (0xc38 + v) | (u << 16);
202                         if (led_dev[i])
203                                 break;
204                         sprintf(tmp, "gpio%d", i);
205                         mmcrptr[(0xc2a + v) / 2] |= u;
206                         gpio_config[i] = buf[i];
207                         led_dev[i] =
208                             led_create(gpio_led, &led_cookie[i], tmp);
209                         break;
210                 case '.':
211                         gpio_config[i] = buf[i];
212                         break;
213                 case '-':
214                 default:
215                         break;
216                 }
217         }
218         return (0);
219 }
220
221 SYSCTL_OID(_machdep, OID_AUTO, elan_gpio_config, CTLTYPE_STRING | CTLFLAG_RW,
222     NULL, 0, sysctl_machdep_elan_gpio_config, "A", "Elan CPU GPIO pin config");
223
224 #ifdef CPU_ELAN_PPS
225 static void
226 elan_poll_pps(struct timecounter *tc)
227 {
228         static int state;
229         int i;
230         uint16_t u, x, y, z;
231         register_t saveintr;
232
233         /*
234          * Grab the HW state as quickly and compactly as we can.  Disable
235          * interrupts to avoid measuring our interrupt service time on
236          * hw with quality clock sources.
237          */
238         saveintr = intr_disable();
239         x = *pps_ap[0]; /* state, must be first, see below */
240         y = *pps_ap[1]; /* timer2 */
241         z = *pps_ap[2]; /* timer1 */
242         intr_restore(saveintr);
243
244         /*
245          * Order is important here.  We need to check the state of the GPIO
246          * pin first, in order to avoid reading timer 1 right before the
247          * state change.  Technically pps_a may be zero in which case we
248          * harmlessly read the REVID register and the contents of pps_d is
249          * of no concern.
250          */
251
252         i = x & pps_d;
253
254         /* If state did not change or we don't have a GPIO pin, return */
255         if (i == state || pps_a == 0)
256                 return;
257
258         state = i;
259
260         /* If the state is "low", flip the echo GPIO and return.  */
261         if (!i) {
262                 if (echo_a)
263                         mmcrptr[(echo_a ^ 0xc) / 2] = echo_d;
264                 return;
265         }
266
267         /*
268          * Subtract timer1 from timer2 to compensate for time from the
269          * edge until we read the counters.
270          */
271         u = y - z;
272
273         pps_capture(&elan_pps);
274         elan_pps.capcount = u;
275         pps_event(&elan_pps, PPS_CAPTUREASSERT);
276
277         /* Twiddle echo bit */
278         if (echo_a)
279                 mmcrptr[echo_a / 2] = echo_d;
280 }
281 #endif /* CPU_ELAN_PPS */
282
283 static unsigned
284 elan_get_timecount(struct timecounter *tc)
285 {
286
287         /* Read timer2, end of story */
288         return (elan_mmcr->GPTMR2CNT);
289 }
290
291 /*
292  * The Elan CPU can be run from a number of clock frequencies, this
293  * allows you to override the default 33.3 MHZ.
294  */
295 #ifndef CPU_ELAN_XTAL
296 #define CPU_ELAN_XTAL 33333333
297 #endif
298
299 static struct timecounter elan_timecounter = {
300         elan_get_timecount,
301         NULL,
302         0xffff,
303         CPU_ELAN_XTAL / 4,
304         "ELAN",
305         1000
306 };
307
308 static int
309 sysctl_machdep_elan_freq(SYSCTL_HANDLER_ARGS)
310 {
311         u_int f;
312         int error;
313
314         f = elan_timecounter.tc_frequency * 4;
315         error = sysctl_handle_int(oidp, &f, 0, req);
316         if (error == 0 && req->newptr != NULL) 
317                 elan_timecounter.tc_frequency = (f + 3) / 4;
318         return (error);
319 }
320
321 SYSCTL_PROC(_machdep, OID_AUTO, elan_freq, CTLTYPE_UINT | CTLFLAG_RW,
322     0, sizeof (u_int), sysctl_machdep_elan_freq, "IU", "");
323
324 /*
325  * Positively identifying the Elan can only be done through the PCI id of
326  * the host-bridge, this function is called from i386/pci/pci_bus.c.
327  */
328 void
329 init_AMD_Elan_sc520(void)
330 {
331         u_int new;
332         int i;
333
334         mmcrptr = pmap_mapdev(0xfffef000, 0x1000);
335         elan_mmcr = (volatile struct elan_mmcr *)mmcrptr;
336
337         /*-
338          * The i8254 is driven with a nonstandard frequency which is
339          * derived thusly:
340          *   f = 32768 * 45 * 25 / 31 = 1189161.29...
341          * We use the sysctl to get the i8254 (timecounter etc) into whack.
342          */
343         
344         new = 1189161;
345         i = kernel_sysctlbyname(&thread0, "machdep.i8254_freq", 
346             NULL, 0, &new, sizeof new, NULL, 0);
347         if (bootverbose || 1)
348                 printf("sysctl machdep.i8254_freq=%d returns %d\n", new, i);
349
350         /* Start GP timer #2 and use it as timecounter, hz permitting */
351         elan_mmcr->GPTMR2MAXCMPA = 0;
352         elan_mmcr->GPTMR2CTL = 0xc001;
353
354 #ifdef CPU_ELAN_PPS
355         /* Set up GP timer #1 as pps counter */
356         elan_mmcr->CSPFS &= ~0x10;
357         elan_mmcr->GPTMR1CTL = 0x8000 | 0x4000 | 0x10 | 0x1;
358         elan_mmcr->GPTMR1MAXCMPA = 0x0;
359         elan_mmcr->GPTMR1MAXCMPB = 0x0;
360         elan_pps.ppscap |= PPS_CAPTUREASSERT;
361         pps_init(&elan_pps);
362 #endif
363         tc_init(&elan_timecounter);
364 }
365
366 static void
367 elan_watchdog(void *foo __unused, u_int spec, int *error)
368 {
369         u_int u, v, w;
370         static u_int cur;
371
372         u = spec & WD_INTERVAL;
373         if (u > 0 && u <= 35) {
374                 u = imax(u - 5, 24);
375                 v = 2 << (u - 24);
376                 v |= 0xc000;
377
378                 /*
379                  * There is a bug in some silicon which prevents us from
380                  * writing to the WDTMRCTL register if the GP echo mode is
381                  * enabled.  GP echo mode on the other hand is desirable
382                  * for other reasons.  Save and restore the GP echo mode
383                  * around our hardware tom-foolery.
384                  */
385                 w = elan_mmcr->GPECHO;
386                 elan_mmcr->GPECHO = 0;
387                 if (v != cur) {
388                         /* Clear the ENB bit */
389                         elan_mmcr->WDTMRCTL = 0x3333;
390                         elan_mmcr->WDTMRCTL = 0xcccc;
391                         elan_mmcr->WDTMRCTL = 0;
392
393                         /* Set new value */
394                         elan_mmcr->WDTMRCTL = 0x3333;
395                         elan_mmcr->WDTMRCTL = 0xcccc;
396                         elan_mmcr->WDTMRCTL = v;
397                         cur = v;
398                 } else {
399                         /* Just reset timer */
400                         elan_mmcr->WDTMRCTL = 0xaaaa;
401                         elan_mmcr->WDTMRCTL = 0x5555;
402                 }
403                 elan_mmcr->GPECHO = w;
404                 *error = 0;
405         } else {
406                 w = elan_mmcr->GPECHO;
407                 elan_mmcr->GPECHO = 0;
408                 elan_mmcr->WDTMRCTL = 0x3333;
409                 elan_mmcr->WDTMRCTL = 0xcccc;
410                 elan_mmcr->WDTMRCTL = 0x4080;
411                 elan_mmcr->WDTMRCTL = w;                /* XXX What does this statement do? */
412                 elan_mmcr->GPECHO = w;
413                 cur = 0;
414         }
415 }
416
417 static int
418 elan_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
419     int nprot, vm_memattr_t *memattr)
420 {
421
422         if (offset >= 0x1000) 
423                 return (-1);
424         *paddr = 0xfffef000;
425         return (0);
426 }
427 static int
428 elan_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct  thread *tdr)
429 {
430         int error;
431
432         error = ENOIOCTL;
433
434 #ifdef CPU_ELAN_PPS
435         if (pps_a != 0)
436                 error = pps_ioctl(cmd, arg, &elan_pps);
437         /*
438          * We only want to incur the overhead of the PPS polling if we
439          * are actually asked to timestamp.
440          */
441         if (elan_pps.ppsparam.mode & PPS_CAPTUREASSERT) {
442                 elan_timecounter.tc_poll_pps = elan_poll_pps;
443         } else {
444                 elan_timecounter.tc_poll_pps = NULL;
445         }
446         if (error != ENOIOCTL)
447                 return (error);
448 #endif
449
450         return(error);
451 }
452
453 static struct cdevsw elan_cdevsw = {
454         .d_version =    D_VERSION,
455         .d_flags =      D_NEEDGIANT,
456         .d_ioctl =      elan_ioctl,
457         .d_mmap =       elan_mmap,
458         .d_name =       "elan",
459 };
460
461 static void
462 elan_drvinit(void)
463 {
464
465 #ifdef CPU_SOEKRIS
466 #define BIOS_OEM_MAXLEN 72
467         static u_char bios_oem[BIOS_OEM_MAXLEN] = "\0";
468 #endif /* CPU_SOEKRIS */
469
470         /* If no elan found, just return */
471         if (mmcrptr == NULL)
472                 return;
473
474         printf("Elan-mmcr driver: MMCR at %p.%s\n", 
475             mmcrptr,
476 #ifdef CPU_ELAN_PPS
477             " PPS support."
478 #else
479             ""
480 #endif
481             );
482
483         make_dev(&elan_cdevsw, 0,
484             UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
485
486 #ifdef CPU_SOEKRIS
487         if ( bios_oem_strings(&bios_soekris, bios_oem, BIOS_OEM_MAXLEN) > 0 )
488                 printf("Elan-mmcr %s\n", bios_oem);
489
490         /* Create the error LED on GPIO9 */
491         led_cookie[9] = 0x02000c34;
492         led_dev[9] = led_create(gpio_led, &led_cookie[9], "error");
493         
494         /* Disable the unavailable GPIO pins */
495         strcpy(gpio_config, "-----....--..--------..---------");
496 #else /* !CPU_SOEKRIS */
497         /* We don't know which pins are available so enable them all */
498         strcpy(gpio_config, "................................");
499 #endif /* CPU_SOEKRIS */
500
501         EVENTHANDLER_REGISTER(watchdog_list, elan_watchdog, NULL, 0);
502 }
503
504 SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL);
505