elan-mmcr.c revision 127801
132742Sjkh/*-
275328Sobrien * ----------------------------------------------------------------------------
375328Sobrien * "THE BEER-WARE LICENSE" (Revision 42):
475328Sobrien * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
532742Sjkh * can do whatever you want with this stuff. If we meet some day, and you think
632742Sjkh * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
795327Sobrien * ----------------------------------------------------------------------------
895327Sobrien *
932742Sjkh *
1095327Sobrien * The AMD Elan sc520 is a system-on-chip gadget which is used in embedded
1132742Sjkh * 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 127801 2004-04-03 18:42:52Z phk $");
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
65#include <vm/vm.h>
66#include <vm/pmap.h>
67
68static char gpio_config[33];
69
70static volatile uint16_t *mmcrptr;
71volatile struct elan_mmcr *elan_mmcr;
72
73#ifdef CPU_ELAN_PPS
74static struct pps_state elan_pps;
75static volatile uint16_t *pps_ap[3];
76static u_int	pps_a, pps_d;
77static u_int	echo_a, echo_d;
78#endif /* CPU_ELAN_PPS */
79
80static u_int	led_cookie[32];
81static dev_t	led_dev[32];
82
83static void
84gpio_led(void *cookie, int state)
85{
86	u_int u, v;
87
88	u = *(int *)cookie;
89	v = u & 0xffff;
90	u >>= 16;
91	if (!state)
92		v ^= 0xc;
93	mmcrptr[v / 2] = u;
94}
95
96static int
97sysctl_machdep_elan_gpio_config(SYSCTL_HANDLER_ARGS)
98{
99	u_int u, v;
100	int i, np, ne;
101	int error;
102	char buf[32];
103#ifdef CPU_SOEKRIS
104	char tmp[10];
105#endif
106
107	error = SYSCTL_OUT(req, gpio_config, 33);
108	if (error != 0 || req->newptr == NULL)
109		return (error);
110	if (req->newlen != 32)
111		return (EINVAL);
112	error = SYSCTL_IN(req, buf, 32);
113	if (error != 0)
114		return (error);
115	/* Disallow any disabled pins and count pps and echo */
116	np = ne = 0;
117	for (i = 0; i < 32; i++) {
118		if (gpio_config[i] == '-' && buf[i] == '.')
119			buf[i] = gpio_config[i];
120		if (gpio_config[i] == '-' && buf[i] != '-')
121			return (EPERM);
122		if (buf[i] == 'P') {
123			np++;
124			if (np > 1)
125				return (EINVAL);
126		}
127		if (buf[i] == 'e' || buf[i] == 'E') {
128			ne++;
129			if (ne > 1)
130				return (EINVAL);
131		}
132		if (buf[i] != 'L' && buf[i] != 'l'
133#ifdef CPU_ELAN_PPS
134		    && buf[i] != 'P' && buf[i] != 'E' && buf[i] != 'e'
135#endif /* CPU_ELAN_PPS */
136		    && buf[i] != '.' && buf[i] != '-')
137			return (EINVAL);
138	}
139#ifdef CPU_ELAN_PPS
140	if (np == 0)
141		pps_a = pps_d = 0;
142	if (ne == 0)
143		echo_a = echo_d = 0;
144#endif
145	for (i = 0; i < 32; i++) {
146		u = 1 << (i & 0xf);
147		if (i >= 16)
148			v = 2;
149		else
150			v = 0;
151#ifdef CPU_SOEKRIS
152		if (i == 9)
153			;
154		else
155#endif
156		if (buf[i] != 'l' && buf[i] != 'L' && led_dev[i] != NULL) {
157			led_destroy(led_dev[i]);
158			led_dev[i] = NULL;
159			mmcrptr[(0xc2a + v) / 2] &= ~u;
160		}
161		switch (buf[i]) {
162#ifdef CPU_ELAN_PPS
163		case 'P':
164			pps_d = u;
165			pps_a = 0xc30 + v;
166			pps_ap[0] = &mmcrptr[pps_a / 2];
167			pps_ap[1] = &elan_mmcr->GPTMR2CNT;
168			pps_ap[2] = &elan_mmcr->GPTMR1CNT;
169			mmcrptr[(0xc2a + v) / 2] &= ~u;
170			gpio_config[i] = buf[i];
171			break;
172		case 'e':
173		case 'E':
174			echo_d = u;
175			if (buf[i] == 'E')
176				echo_a = 0xc34 + v;
177			else
178				echo_a = 0xc38 + v;
179			mmcrptr[(0xc2a + v) / 2] |= u;
180			gpio_config[i] = buf[i];
181			break;
182#endif /* CPU_ELAN_PPS */
183		case 'l':
184		case 'L':
185			if (buf[i] == 'L')
186				led_cookie[i] = (0xc34 + v) | (u << 16);
187			else
188				led_cookie[i] = (0xc38 + v) | (u << 16);
189			if (led_dev[i])
190				break;
191			sprintf(tmp, "gpio%d", i);
192			led_dev[i] =
193			    led_create(gpio_led, &led_cookie[i], tmp);
194			mmcrptr[(0xc2a + v) / 2] |= u;
195			gpio_config[i] = buf[i];
196			break;
197		case '.':
198			gpio_config[i] = buf[i];
199			break;
200		case '-':
201		default:
202			break;
203		}
204	}
205	return (0);
206}
207
208SYSCTL_OID(_machdep, OID_AUTO, elan_gpio_config, CTLTYPE_STRING | CTLFLAG_RW,
209    NULL, 0, sysctl_machdep_elan_gpio_config, "A", "Elan CPU GPIO pin config");
210
211#ifdef CPU_ELAN_PPS
212static void
213elan_poll_pps(struct timecounter *tc)
214{
215	static int state;
216	int i;
217	uint16_t u, x, y, z;
218	u_long eflags;
219
220	/*
221	 * Grab the HW state as quickly and compactly as we can.  Disable
222	 * interrupts to avoid measuring our interrupt service time on
223	 * hw with quality clock sources.
224	 */
225	eflags = read_eflags();
226	disable_intr();
227	x = *pps_ap[0];	/* state, must be first, see below */
228	y = *pps_ap[1]; /* timer2 */
229	z = *pps_ap[2]; /* timer1 */
230	write_eflags(eflags);
231
232	/*
233	 * Order is important here.  We need to check the state of the GPIO
234	 * pin first, in order to avoid reading timer 1 right before the
235	 * state change.  Technically pps_a may be zero in which case we
236	 * harmlessly read the REVID register and the contents of pps_d is
237	 * of no concern.
238	 */
239
240	i = x & pps_d;
241
242	/* If state did not change or we don't have a GPIO pin, return */
243	if (i == state || pps_a == 0)
244		return;
245
246	state = i;
247
248	/* If the state is "low", flip the echo GPIO and return.  */
249	if (!i) {
250		if (echo_a)
251			mmcrptr[(echo_a ^ 0xc) / 2] = echo_d;
252		return;
253	}
254
255	/*
256	 * Subtract timer1 from timer2 to compensate for time from the
257	 * edge until we read the counters.
258	 */
259	u = y - z;
260
261	pps_capture(&elan_pps);
262	elan_pps.capcount = u;
263	pps_event(&elan_pps, PPS_CAPTUREASSERT);
264
265	/* Twiddle echo bit */
266	if (echo_a)
267		mmcrptr[echo_a / 2] = echo_d;
268}
269#endif /* CPU_ELAN_PPS */
270
271static unsigned
272elan_get_timecount(struct timecounter *tc)
273{
274
275	/* Read timer2, end of story */
276	return (elan_mmcr->GPTMR2CNT);
277}
278
279/*
280 * The Elan CPU can be run from a number of clock frequencies, this
281 * allows you to override the default 33.3 MHZ.
282 */
283#ifndef CPU_ELAN_XTAL
284#define CPU_ELAN_XTAL 33333333
285#endif
286
287static struct timecounter elan_timecounter = {
288	elan_get_timecount,
289	NULL,
290	0xffff,
291	CPU_ELAN_XTAL / 4,
292	"ELAN",
293	1000
294};
295
296static int
297sysctl_machdep_elan_freq(SYSCTL_HANDLER_ARGS)
298{
299	u_int f;
300	int error;
301
302	f = elan_timecounter.tc_frequency * 4;
303	error = sysctl_handle_int(oidp, &f, sizeof(f), req);
304	if (error == 0 && req->newptr != NULL)
305		elan_timecounter.tc_frequency = (f + 3) / 4;
306	return (error);
307}
308
309SYSCTL_PROC(_machdep, OID_AUTO, elan_freq, CTLTYPE_UINT | CTLFLAG_RW,
310    0, sizeof (u_int), sysctl_machdep_elan_freq, "IU", "");
311
312/*
313 * Positively identifying the Elan can only be done through the PCI id of
314 * the host-bridge, this function is called from i386/pci/pci_bus.c.
315 */
316void
317init_AMD_Elan_sc520(void)
318{
319	u_int new;
320	int i;
321
322	mmcrptr = pmap_mapdev(0xfffef000, 0x1000);
323	elan_mmcr = (volatile struct elan_mmcr *)mmcrptr;
324
325	/*-
326	 * The i8254 is driven with a nonstandard frequency which is
327	 * derived thusly:
328	 *   f = 32768 * 45 * 25 / 31 = 1189161.29...
329	 * We use the sysctl to get the i8254 (timecounter etc) into whack.
330	 */
331
332	new = 1189161;
333	i = kernel_sysctlbyname(&thread0, "machdep.i8254_freq",
334	    NULL, 0, &new, sizeof new, NULL);
335	if (bootverbose || 1)
336		printf("sysctl machdep.i8254_freq=%d returns %d\n", new, i);
337
338	/* Start GP timer #2 and use it as timecounter, hz permitting */
339	elan_mmcr->GPTMR2MAXCMPA = 0;
340	elan_mmcr->GPTMR2CTL = 0xc001;
341
342#ifdef CPU_ELAN_PPS
343	/* Set up GP timer #1 as pps counter */
344	elan_mmcr->CSPFS &= ~0x10;
345	elan_mmcr->GPTMR1CTL = 0x8000 | 0x4000 | 0x10 | 0x1;
346	elan_mmcr->GPTMR1MAXCMPA = 0x0;
347	elan_mmcr->GPTMR1MAXCMPB = 0x0;
348	elan_pps.ppscap |= PPS_CAPTUREASSERT;
349	pps_init(&elan_pps);
350#endif
351	tc_init(&elan_timecounter);
352}
353
354static void
355elan_watchdog(void *foo __unused, u_int spec, int *error)
356{
357	u_int u, v;
358	static u_int cur;
359
360	u = spec & WD_INTERVAL;
361	if (spec && u <= 35) {
362		u = imax(u - 5, 24);
363		v = 2 << (u - 24);
364		v |= 0xc000;
365
366		/*
367		 * There is a bug in some silicon which prevents us from
368		 * writing to the WDTMRCTL register if the GP echo mode is
369		 * enabled.  GP echo mode on the other hand is desirable
370		 * for other reasons.  Save and restore the GP echo mode
371		 * around our hardware tom-foolery.
372		 */
373		u = elan_mmcr->GPECHO;
374		elan_mmcr->GPECHO = 0;
375		if (v != cur) {
376			/* Clear the ENB bit */
377			elan_mmcr->WDTMRCTL = 0x3333;
378			elan_mmcr->WDTMRCTL = 0xcccc;
379			elan_mmcr->WDTMRCTL = 0;
380
381			/* Set new value */
382			elan_mmcr->WDTMRCTL = 0x3333;
383			elan_mmcr->WDTMRCTL = 0xcccc;
384			elan_mmcr->WDTMRCTL = v;
385			cur = v;
386		} else {
387			/* Just reset timer */
388			elan_mmcr->WDTMRCTL = 0xaaaa;
389			elan_mmcr->WDTMRCTL = 0x5555;
390		}
391		elan_mmcr->GPECHO = u;
392		*error = 0;
393		return;
394	} else {
395		u = elan_mmcr->GPECHO;
396		elan_mmcr->GPECHO = 0;
397		elan_mmcr->WDTMRCTL = 0x3333;
398		elan_mmcr->WDTMRCTL = 0xcccc;
399		elan_mmcr->WDTMRCTL = 0x4080;
400		elan_mmcr->WDTMRCTL = u;
401		elan_mmcr->GPECHO = u;
402		cur = 0;
403		return;
404	}
405}
406
407static int
408elan_mmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
409{
410
411	if (offset >= 0x1000)
412		return (-1);
413	*paddr = 0xfffef000;
414	return (0);
415}
416static int
417elan_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct  thread *tdr)
418{
419	int error;
420
421	error = ENOIOCTL;
422
423#ifdef CPU_ELAN_PPS
424	if (pps_a != 0)
425		error = pps_ioctl(cmd, arg, &elan_pps);
426	/*
427	 * We only want to incur the overhead of the PPS polling if we
428	 * are actually asked to timestamp.
429	 */
430	if (elan_pps.ppsparam.mode & PPS_CAPTUREASSERT) {
431		elan_timecounter.tc_poll_pps = elan_poll_pps;
432	} else {
433		elan_timecounter.tc_poll_pps = NULL;
434	}
435	if (error != ENOIOCTL)
436		return (error);
437#endif
438
439	return(error);
440}
441
442static struct cdevsw elan_cdevsw = {
443	.d_version =	D_VERSION,
444	.d_flags =	D_NEEDGIANT,
445	.d_ioctl =	elan_ioctl,
446	.d_mmap =	elan_mmap,
447	.d_name =	"elan",
448};
449
450static void
451elan_drvinit(void)
452{
453
454	/* If no elan found, just return */
455	if (mmcrptr == NULL)
456		return;
457
458	printf("Elan-mmcr driver: MMCR at %p.%s\n",
459	    mmcrptr,
460#ifdef CPU_ELAN_PPS
461	    " PPS support."
462#else
463	    ""
464#endif
465	    );
466
467	make_dev(&elan_cdevsw, 0,
468	    UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
469
470#ifdef CPU_SOEKRIS
471	/* Create the error LED on GPIO9 */
472	led_cookie[9] = 0x02000c34;
473	led_dev[9] = led_create(gpio_led, &led_cookie[9], "error");
474
475	/* Disable the unavailable GPIO pins */
476	strcpy(gpio_config, "-----....--..--------..---------");
477#else /* !CPU_SOEKRIS */
478	/* We don't know which pins are available so enable them all */
479	strcpy(gpio_config, "................................");
480#endif /* CPU_SOEKRIS */
481
482	EVENTHANDLER_REGISTER(watchdog_list, elan_watchdog, NULL, 0);
483}
484
485SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL);
486
487