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 * ----------------------------------------------------------------------------
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.
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.
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.
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.
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".
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.
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
49 #include <sys/sysctl.h>
50 #include <sys/syslog.h>
51 #include <sys/timetc.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>
61 #include <dev/led/led.h>
62 #include <machine/md_var.h>
63 #include <machine/elan_mmcr.h>
64 #include <machine/pc/bios.h>
69 static char gpio_config[33];
71 static volatile uint16_t *mmcrptr;
72 volatile struct elan_mmcr *elan_mmcr;
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 */
83 static struct bios_oem bios_soekris = {
86 { "Soekris", 0, 8 }, /* Soekris Engineering. */
87 { "net4", 0, 8 }, /* net45xx */
88 { "comBIOS", 0, 54 }, /* comBIOS ver. 1.26a 20040819 ... */
95 static u_int led_cookie[32];
96 static struct cdev *led_dev[32];
99 gpio_led(void *cookie, int state)
112 sysctl_machdep_elan_gpio_config(SYSCTL_HANDLER_ARGS)
120 error = SYSCTL_OUT(req, gpio_config, 33);
121 if (error != 0 || req->newptr == NULL)
123 if (req->newlen != 32)
125 error = SYSCTL_IN(req, buf, 32);
128 /* Disallow any disabled pins and count pps and echo */
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] != '-')
140 if (buf[i] == 'e' || buf[i] == 'E') {
145 if (buf[i] != 'L' && buf[i] != 'l'
147 && buf[i] != 'P' && buf[i] != 'E' && buf[i] != 'e'
148 #endif /* CPU_ELAN_PPS */
149 && buf[i] != '.' && buf[i] != '-')
158 for (i = 0; i < 32; i++) {
169 if (buf[i] != 'l' && buf[i] != 'L' && led_dev[i] != NULL) {
170 led_destroy(led_dev[i]);
172 mmcrptr[(0xc2a + v) / 2] &= ~u;
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];
192 mmcrptr[(0xc2a + v) / 2] |= u;
193 gpio_config[i] = buf[i];
195 #endif /* CPU_ELAN_PPS */
199 led_cookie[i] = (0xc34 + v) | (u << 16);
201 led_cookie[i] = (0xc38 + v) | (u << 16);
204 sprintf(tmp, "gpio%d", i);
205 mmcrptr[(0xc2a + v) / 2] |= u;
206 gpio_config[i] = buf[i];
208 led_create(gpio_led, &led_cookie[i], tmp);
211 gpio_config[i] = buf[i];
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");
226 elan_poll_pps(struct timecounter *tc)
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.
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);
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
254 /* If state did not change or we don't have a GPIO pin, return */
255 if (i == state || pps_a == 0)
260 /* If the state is "low", flip the echo GPIO and return. */
263 mmcrptr[(echo_a ^ 0xc) / 2] = echo_d;
268 * Subtract timer1 from timer2 to compensate for time from the
269 * edge until we read the counters.
273 pps_capture(&elan_pps);
274 elan_pps.capcount = u;
275 pps_event(&elan_pps, PPS_CAPTUREASSERT);
277 /* Twiddle echo bit */
279 mmcrptr[echo_a / 2] = echo_d;
281 #endif /* CPU_ELAN_PPS */
284 elan_get_timecount(struct timecounter *tc)
287 /* Read timer2, end of story */
288 return (elan_mmcr->GPTMR2CNT);
292 * The Elan CPU can be run from a number of clock frequencies, this
293 * allows you to override the default 33.3 MHZ.
295 #ifndef CPU_ELAN_XTAL
296 #define CPU_ELAN_XTAL 33333333
299 static struct timecounter elan_timecounter = {
309 sysctl_machdep_elan_freq(SYSCTL_HANDLER_ARGS)
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;
321 SYSCTL_PROC(_machdep, OID_AUTO, elan_freq, CTLTYPE_UINT | CTLFLAG_RW,
322 0, sizeof (u_int), sysctl_machdep_elan_freq, "IU", "");
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.
329 init_AMD_Elan_sc520(void)
334 mmcrptr = pmap_mapdev(0xfffef000, 0x1000);
335 elan_mmcr = (volatile struct elan_mmcr *)mmcrptr;
338 * The i8254 is driven with a nonstandard frequency which is
340 * f = 32768 * 45 * 25 / 31 = 1189161.29...
341 * We use the sysctl to get the i8254 (timecounter etc) into whack.
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);
350 /* Start GP timer #2 and use it as timecounter, hz permitting */
351 elan_mmcr->GPTMR2MAXCMPA = 0;
352 elan_mmcr->GPTMR2CTL = 0xc001;
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;
363 tc_init(&elan_timecounter);
367 elan_watchdog(void *foo __unused, u_int spec, int *error)
372 u = spec & WD_INTERVAL;
373 if (u > 0 && u <= 35) {
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.
385 w = elan_mmcr->GPECHO;
386 elan_mmcr->GPECHO = 0;
388 /* Clear the ENB bit */
389 elan_mmcr->WDTMRCTL = 0x3333;
390 elan_mmcr->WDTMRCTL = 0xcccc;
391 elan_mmcr->WDTMRCTL = 0;
394 elan_mmcr->WDTMRCTL = 0x3333;
395 elan_mmcr->WDTMRCTL = 0xcccc;
396 elan_mmcr->WDTMRCTL = v;
399 /* Just reset timer */
400 elan_mmcr->WDTMRCTL = 0xaaaa;
401 elan_mmcr->WDTMRCTL = 0x5555;
403 elan_mmcr->GPECHO = w;
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;
418 elan_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
419 int nprot, vm_memattr_t *memattr)
422 if (offset >= 0x1000)
428 elan_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr)
436 error = pps_ioctl(cmd, arg, &elan_pps);
438 * We only want to incur the overhead of the PPS polling if we
439 * are actually asked to timestamp.
441 if (elan_pps.ppsparam.mode & PPS_CAPTUREASSERT) {
442 elan_timecounter.tc_poll_pps = elan_poll_pps;
444 elan_timecounter.tc_poll_pps = NULL;
446 if (error != ENOIOCTL)
453 static struct cdevsw elan_cdevsw = {
454 .d_version = D_VERSION,
455 .d_flags = D_NEEDGIANT,
456 .d_ioctl = elan_ioctl,
466 #define BIOS_OEM_MAXLEN 72
467 static u_char bios_oem[BIOS_OEM_MAXLEN] = "\0";
468 #endif /* CPU_SOEKRIS */
470 /* If no elan found, just return */
474 printf("Elan-mmcr driver: MMCR at %p.%s\n",
483 make_dev(&elan_cdevsw, 0,
484 UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
487 if ( bios_oem_strings(&bios_soekris, bios_oem, BIOS_OEM_MAXLEN) > 0 )
488 printf("Elan-mmcr %s\n", bios_oem);
490 /* Create the error LED on GPIO9 */
491 led_cookie[9] = 0x02000c34;
492 led_dev[9] = led_create(gpio_led, &led_cookie[9], "error");
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 */
501 EVENTHANDLER_REGISTER(watchdog_list, elan_watchdog, NULL, 0);
504 SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL);