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