elan-mmcr.c revision 201223
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: head/sys/i386/i386/elan-mmcr.c 201223 2009-12-29 21:51:28Z rnoland $");
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
69static char gpio_config[33];
70
71static volatile uint16_t *mmcrptr;
72volatile struct elan_mmcr *elan_mmcr;
73
74#ifdef CPU_ELAN_PPS
75static struct pps_state elan_pps;
76static volatile uint16_t *pps_ap[3];
77static u_int	pps_a, pps_d;
78static u_int	echo_a, echo_d;
79#endif /* CPU_ELAN_PPS */
80
81#ifdef CPU_SOEKRIS
82
83static 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
95static u_int	led_cookie[32];
96static struct cdev *led_dev[32];
97
98static void
99gpio_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
111static int
112sysctl_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
221SYSCTL_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
225static void
226elan_poll_pps(struct timecounter *tc)
227{
228	static int state;
229	int i;
230	uint16_t u, x, y, z;
231	u_long eflags;
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	eflags = read_eflags();
239	disable_intr();
240	x = *pps_ap[0];	/* state, must be first, see below */
241	y = *pps_ap[1]; /* timer2 */
242	z = *pps_ap[2]; /* timer1 */
243	write_eflags(eflags);
244
245	/*
246	 * Order is important here.  We need to check the state of the GPIO
247	 * pin first, in order to avoid reading timer 1 right before the
248	 * state change.  Technically pps_a may be zero in which case we
249	 * harmlessly read the REVID register and the contents of pps_d is
250	 * of no concern.
251	 */
252
253	i = x & pps_d;
254
255	/* If state did not change or we don't have a GPIO pin, return */
256	if (i == state || pps_a == 0)
257		return;
258
259	state = i;
260
261	/* If the state is "low", flip the echo GPIO and return.  */
262	if (!i) {
263		if (echo_a)
264			mmcrptr[(echo_a ^ 0xc) / 2] = echo_d;
265		return;
266	}
267
268	/*
269	 * Subtract timer1 from timer2 to compensate for time from the
270	 * edge until we read the counters.
271	 */
272	u = y - z;
273
274	pps_capture(&elan_pps);
275	elan_pps.capcount = u;
276	pps_event(&elan_pps, PPS_CAPTUREASSERT);
277
278	/* Twiddle echo bit */
279	if (echo_a)
280		mmcrptr[echo_a / 2] = echo_d;
281}
282#endif /* CPU_ELAN_PPS */
283
284static unsigned
285elan_get_timecount(struct timecounter *tc)
286{
287
288	/* Read timer2, end of story */
289	return (elan_mmcr->GPTMR2CNT);
290}
291
292/*
293 * The Elan CPU can be run from a number of clock frequencies, this
294 * allows you to override the default 33.3 MHZ.
295 */
296#ifndef CPU_ELAN_XTAL
297#define CPU_ELAN_XTAL 33333333
298#endif
299
300static struct timecounter elan_timecounter = {
301	elan_get_timecount,
302	NULL,
303	0xffff,
304	CPU_ELAN_XTAL / 4,
305	"ELAN",
306	1000
307};
308
309static int
310sysctl_machdep_elan_freq(SYSCTL_HANDLER_ARGS)
311{
312	u_int f;
313	int error;
314
315	f = elan_timecounter.tc_frequency * 4;
316	error = sysctl_handle_int(oidp, &f, 0, req);
317	if (error == 0 && req->newptr != NULL)
318		elan_timecounter.tc_frequency = (f + 3) / 4;
319	return (error);
320}
321
322SYSCTL_PROC(_machdep, OID_AUTO, elan_freq, CTLTYPE_UINT | CTLFLAG_RW,
323    0, sizeof (u_int), sysctl_machdep_elan_freq, "IU", "");
324
325/*
326 * Positively identifying the Elan can only be done through the PCI id of
327 * the host-bridge, this function is called from i386/pci/pci_bus.c.
328 */
329void
330init_AMD_Elan_sc520(void)
331{
332	u_int new;
333	int i;
334
335	mmcrptr = pmap_mapdev(0xfffef000, 0x1000);
336	elan_mmcr = (volatile struct elan_mmcr *)mmcrptr;
337
338	/*-
339	 * The i8254 is driven with a nonstandard frequency which is
340	 * derived thusly:
341	 *   f = 32768 * 45 * 25 / 31 = 1189161.29...
342	 * We use the sysctl to get the i8254 (timecounter etc) into whack.
343	 */
344
345	new = 1189161;
346	i = kernel_sysctlbyname(&thread0, "machdep.i8254_freq",
347	    NULL, 0, &new, sizeof new, NULL, 0);
348	if (bootverbose || 1)
349		printf("sysctl machdep.i8254_freq=%d returns %d\n", new, i);
350
351	/* Start GP timer #2 and use it as timecounter, hz permitting */
352	elan_mmcr->GPTMR2MAXCMPA = 0;
353	elan_mmcr->GPTMR2CTL = 0xc001;
354
355#ifdef CPU_ELAN_PPS
356	/* Set up GP timer #1 as pps counter */
357	elan_mmcr->CSPFS &= ~0x10;
358	elan_mmcr->GPTMR1CTL = 0x8000 | 0x4000 | 0x10 | 0x1;
359	elan_mmcr->GPTMR1MAXCMPA = 0x0;
360	elan_mmcr->GPTMR1MAXCMPB = 0x0;
361	elan_pps.ppscap |= PPS_CAPTUREASSERT;
362	pps_init(&elan_pps);
363#endif
364	tc_init(&elan_timecounter);
365}
366
367static void
368elan_watchdog(void *foo __unused, u_int spec, int *error)
369{
370	u_int u, v, w;
371	static u_int cur;
372
373	u = spec & WD_INTERVAL;
374	if (u > 0 && u <= 35) {
375		u = imax(u - 5, 24);
376		v = 2 << (u - 24);
377		v |= 0xc000;
378
379		/*
380		 * There is a bug in some silicon which prevents us from
381		 * writing to the WDTMRCTL register if the GP echo mode is
382		 * enabled.  GP echo mode on the other hand is desirable
383		 * for other reasons.  Save and restore the GP echo mode
384		 * around our hardware tom-foolery.
385		 */
386		w = elan_mmcr->GPECHO;
387		elan_mmcr->GPECHO = 0;
388		if (v != cur) {
389			/* Clear the ENB bit */
390			elan_mmcr->WDTMRCTL = 0x3333;
391			elan_mmcr->WDTMRCTL = 0xcccc;
392			elan_mmcr->WDTMRCTL = 0;
393
394			/* Set new value */
395			elan_mmcr->WDTMRCTL = 0x3333;
396			elan_mmcr->WDTMRCTL = 0xcccc;
397			elan_mmcr->WDTMRCTL = v;
398			cur = v;
399		} else {
400			/* Just reset timer */
401			elan_mmcr->WDTMRCTL = 0xaaaa;
402			elan_mmcr->WDTMRCTL = 0x5555;
403		}
404		elan_mmcr->GPECHO = w;
405		*error = 0;
406	} else {
407		w = elan_mmcr->GPECHO;
408		elan_mmcr->GPECHO = 0;
409		elan_mmcr->WDTMRCTL = 0x3333;
410		elan_mmcr->WDTMRCTL = 0xcccc;
411		elan_mmcr->WDTMRCTL = 0x4080;
412		elan_mmcr->WDTMRCTL = w;		/* XXX What does this statement do? */
413		elan_mmcr->GPECHO = w;
414		cur = 0;
415	}
416}
417
418static int
419elan_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
420    int nprot, vm_memattr_t *memattr)
421{
422
423	if (offset >= 0x1000)
424		return (-1);
425	*paddr = 0xfffef000;
426	return (0);
427}
428static int
429elan_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct  thread *tdr)
430{
431	int error;
432
433	error = ENOIOCTL;
434
435#ifdef CPU_ELAN_PPS
436	if (pps_a != 0)
437		error = pps_ioctl(cmd, arg, &elan_pps);
438	/*
439	 * We only want to incur the overhead of the PPS polling if we
440	 * are actually asked to timestamp.
441	 */
442	if (elan_pps.ppsparam.mode & PPS_CAPTUREASSERT) {
443		elan_timecounter.tc_poll_pps = elan_poll_pps;
444	} else {
445		elan_timecounter.tc_poll_pps = NULL;
446	}
447	if (error != ENOIOCTL)
448		return (error);
449#endif
450
451	return(error);
452}
453
454static struct cdevsw elan_cdevsw = {
455	.d_version =	D_VERSION,
456	.d_flags =	D_NEEDGIANT,
457	.d_ioctl =	elan_ioctl,
458	.d_mmap =	elan_mmap,
459	.d_name =	"elan",
460};
461
462static void
463elan_drvinit(void)
464{
465
466#ifdef CPU_SOEKRIS
467#define BIOS_OEM_MAXLEN 72
468        static u_char bios_oem[BIOS_OEM_MAXLEN] = "\0";
469#endif /* CPU_SOEKRIS */
470
471	/* If no elan found, just return */
472	if (mmcrptr == NULL)
473		return;
474
475	printf("Elan-mmcr driver: MMCR at %p.%s\n",
476	    mmcrptr,
477#ifdef CPU_ELAN_PPS
478	    " PPS support."
479#else
480	    ""
481#endif
482	    );
483
484	make_dev(&elan_cdevsw, 0,
485	    UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
486
487#ifdef CPU_SOEKRIS
488	if ( bios_oem_strings(&bios_soekris, bios_oem, BIOS_OEM_MAXLEN) > 0 )
489		printf("Elan-mmcr %s\n", bios_oem);
490
491	/* Create the error LED on GPIO9 */
492	led_cookie[9] = 0x02000c34;
493	led_dev[9] = led_create(gpio_led, &led_cookie[9], "error");
494
495	/* Disable the unavailable GPIO pins */
496	strcpy(gpio_config, "-----....--..--------..---------");
497#else /* !CPU_SOEKRIS */
498	/* We don't know which pins are available so enable them all */
499	strcpy(gpio_config, "................................");
500#endif /* CPU_SOEKRIS */
501
502	EVENTHANDLER_REGISTER(watchdog_list, elan_watchdog, NULL, 0);
503}
504
505SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL);
506
507