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