xref: /freebsd/sys/i386/i386/elan-mmcr.c (revision 636d90fc)
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 	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 
284 static unsigned
285 elan_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 
300 static struct timecounter elan_timecounter = {
301 	elan_get_timecount,
302 	NULL,
303 	0xffff,
304 	CPU_ELAN_XTAL / 4,
305 	"ELAN",
306 	1000
307 };
308 
309 static int
310 sysctl_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, sizeof(f), req);
317 	if (error == 0 && req->newptr != NULL)
318 		elan_timecounter.tc_frequency = (f + 3) / 4;
319 	return (error);
320 }
321 
322 SYSCTL_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  */
329 void
330 init_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 
367 static void
368 elan_watchdog(void *foo __unused, u_int spec, int *error)
369 {
370 	u_int u, v;
371 	static u_int cur;
372 
373 	u = spec & WD_INTERVAL;
374 	if (spec && 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 		u = 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 = u;
405 		*error = 0;
406 		return;
407 	} else {
408 		u = elan_mmcr->GPECHO;
409 		elan_mmcr->GPECHO = 0;
410 		elan_mmcr->WDTMRCTL = 0x3333;
411 		elan_mmcr->WDTMRCTL = 0xcccc;
412 		elan_mmcr->WDTMRCTL = 0x4080;
413 		elan_mmcr->WDTMRCTL = u;
414 		elan_mmcr->GPECHO = u;
415 		cur = 0;
416 		return;
417 	}
418 }
419 
420 static int
421 elan_mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
422 {
423 
424 	if (offset >= 0x1000)
425 		return (-1);
426 	*paddr = 0xfffef000;
427 	return (0);
428 }
429 static int
430 elan_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct  thread *tdr)
431 {
432 	int error;
433 
434 	error = ENOIOCTL;
435 
436 #ifdef CPU_ELAN_PPS
437 	if (pps_a != 0)
438 		error = pps_ioctl(cmd, arg, &elan_pps);
439 	/*
440 	 * We only want to incur the overhead of the PPS polling if we
441 	 * are actually asked to timestamp.
442 	 */
443 	if (elan_pps.ppsparam.mode & PPS_CAPTUREASSERT) {
444 		elan_timecounter.tc_poll_pps = elan_poll_pps;
445 	} else {
446 		elan_timecounter.tc_poll_pps = NULL;
447 	}
448 	if (error != ENOIOCTL)
449 		return (error);
450 #endif
451 
452 	return(error);
453 }
454 
455 static struct cdevsw elan_cdevsw = {
456 	.d_version =	D_VERSION,
457 	.d_flags =	D_NEEDGIANT,
458 	.d_ioctl =	elan_ioctl,
459 	.d_mmap =	elan_mmap,
460 	.d_name =	"elan",
461 };
462 
463 static void
464 elan_drvinit(void)
465 {
466 
467 #ifdef CPU_SOEKRIS
468 #define BIOS_OEM_MAXLEN 72
469         static u_char bios_oem[BIOS_OEM_MAXLEN] = "\0";
470 #endif /* CPU_SOEKRIS */
471 
472 	/* If no elan found, just return */
473 	if (mmcrptr == NULL)
474 		return;
475 
476 	printf("Elan-mmcr driver: MMCR at %p.%s\n",
477 	    mmcrptr,
478 #ifdef CPU_ELAN_PPS
479 	    " PPS support."
480 #else
481 	    ""
482 #endif
483 	    );
484 
485 	make_dev(&elan_cdevsw, 0,
486 	    UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
487 
488 #ifdef CPU_SOEKRIS
489 	if ( bios_oem_strings(&bios_soekris, bios_oem, BIOS_OEM_MAXLEN) > 0 )
490 		printf("Elan-mmcr %s\n", bios_oem);
491 
492 	/* Create the error LED on GPIO9 */
493 	led_cookie[9] = 0x02000c34;
494 	led_dev[9] = led_create(gpio_led, &led_cookie[9], "error");
495 
496 	/* Disable the unavailable GPIO pins */
497 	strcpy(gpio_config, "-----....--..--------..---------");
498 #else /* !CPU_SOEKRIS */
499 	/* We don't know which pins are available so enable them all */
500 	strcpy(gpio_config, "................................");
501 #endif /* CPU_SOEKRIS */
502 
503 	EVENTHANDLER_REGISTER(watchdog_list, elan_watchdog, NULL, 0);
504 }
505 
506 SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL);
507 
508