elan-mmcr.c revision 201223
1119452Sobrien/*-
2101225Sphk * ----------------------------------------------------------------------------
3101225Sphk * "THE BEER-WARE LICENSE" (Revision 42):
4101225Sphk * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5101225Sphk * can do whatever you want with this stuff. If we meet some day, and you think
6101225Sphk * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7101225Sphk * ----------------------------------------------------------------------------
8101225Sphk *
9101225Sphk *
10102934Sphk * The AMD Elan sc520 is a system-on-chip gadget which is used in embedded
11102934Sphk * kind of things, see www.soekris.com for instance, and it has a few quirks
12102934Sphk * we need to deal with.
13102934Sphk * Unfortunately we cannot identify the gadget by CPUID output because it
14102934Sphk * depends on strapping options and only the stepping field may be useful
15102934Sphk * and those are undocumented from AMDs side.
16102934Sphk *
17102934Sphk * So instead we recognize the on-chip host-PCI bridge and call back from
18102934Sphk * sys/i386/pci/pci_bus.c to here if we find it.
19109327Sphk *
20123015Sphk * #ifdef CPU_ELAN_PPS
21123015Sphk *   The Elan has three general purpose counters, and when two of these
22123015Sphk *   are used just right they can hardware timestamp external events with
23123015Sphk *   approx 125 nsec resolution and +/- 125 nsec precision.
24123015Sphk *
25123015Sphk *   Connect the signal to TMR1IN and a GPIO pin, and configure the GPIO pin
26123015Sphk *   with a 'P' in sysctl machdep.elan_gpio_config.
27123015Sphk *
28123015Sphk *   The rising edge of the signal will start timer 1 counting up from
29123015Sphk *   zero, and when the timecounter polls for PPS, both counter 1 & 2 is
30123015Sphk *   read, as well as the GPIO bit.  If a rising edge has happened, the
31123015Sphk *   contents of timer 1 which is how long time ago the edge happened,
32123015Sphk *   is subtracted from timer 2 to give us a "true time stamp".
33123015Sphk *
34123015Sphk *   Echoing the PPS signal on any GPIO pin is supported (set it to 'e'
35123015Sphk *   or 'E' (inverted) in the sysctl)  The echo signal should only be
36123015Sphk *   used as a visual indication, not for calibration since it suffers
37123015Sphk *   from 1/hz (or more) jitter which the timestamps are compensated for.
38123015Sphk * #endif CPU_ELAN_PPS
39101225Sphk */
40102934Sphk
41115683Sobrien#include <sys/cdefs.h>
42115683Sobrien__FBSDID("$FreeBSD: head/sys/i386/i386/elan-mmcr.c 201223 2009-12-29 21:51:28Z rnoland $");
43115683Sobrien
44111138Sphk#include "opt_cpu.h"
45101225Sphk#include <sys/param.h>
46101225Sphk#include <sys/systm.h>
47101225Sphk#include <sys/kernel.h>
48101225Sphk#include <sys/conf.h>
49102934Sphk#include <sys/sysctl.h>
50123015Sphk#include <sys/syslog.h>
51102934Sphk#include <sys/timetc.h>
52102934Sphk#include <sys/proc.h>
53103482Sphk#include <sys/uio.h>
54103482Sphk#include <sys/lock.h>
55103482Sphk#include <sys/mutex.h>
56103482Sphk#include <sys/malloc.h>
57109327Sphk#include <sys/sysctl.h>
58109327Sphk#include <sys/timepps.h>
59111647Sphk#include <sys/watchdog.h>
60101225Sphk
61121944Sphk#include <dev/led/led.h>
62101225Sphk#include <machine/md_var.h>
63124144Sphk#include <machine/elan_mmcr.h>
64148231Sphk#include <machine/pc/bios.h>
65101225Sphk
66102934Sphk#include <vm/vm.h>
67102934Sphk#include <vm/pmap.h>
68102934Sphk
69123015Sphkstatic char gpio_config[33];
70123015Sphk
71124144Sphkstatic volatile uint16_t *mmcrptr;
72127039Sphkvolatile struct elan_mmcr *elan_mmcr;
73102934Sphk
74123015Sphk#ifdef CPU_ELAN_PPS
75109327Sphkstatic struct pps_state elan_pps;
76127039Sphkstatic volatile uint16_t *pps_ap[3];
77127039Sphkstatic u_int	pps_a, pps_d;
78127039Sphkstatic u_int	echo_a, echo_d;
79123015Sphk#endif /* CPU_ELAN_PPS */
80127039Sphk
81148231Sphk#ifdef CPU_SOEKRIS
82148231Sphk
83148231Sphkstatic struct bios_oem bios_soekris = {
84148231Sphk	{ 0xf0000, 0xf1000 },
85148231Sphk	{
86148231Sphk		{ "Soekris", 0, 8 },	/* Soekris Engineering. */
87148231Sphk		{ "net4", 0, 8 },	/* net45xx */
88148231Sphk		{ "comBIOS", 0, 54 },	/* comBIOS ver. 1.26a  20040819 ... */
89148231Sphk		{ NULL, 0, 0 },
90148231Sphk	}
91148231Sphk};
92148231Sphk
93148231Sphk#endif
94148231Sphk
95127039Sphkstatic u_int	led_cookie[32];
96130585Sphkstatic struct cdev *led_dev[32];
97109327Sphk
98109327Sphkstatic void
99123015Sphkgpio_led(void *cookie, int state)
100123015Sphk{
101123015Sphk	u_int u, v;
102123015Sphk
103123015Sphk	u = *(int *)cookie;
104123015Sphk	v = u & 0xffff;
105123015Sphk	u >>= 16;
106123015Sphk	if (!state)
107123015Sphk		v ^= 0xc;
108124144Sphk	mmcrptr[v / 2] = u;
109123015Sphk}
110123015Sphk
111123015Sphkstatic int
112123015Sphksysctl_machdep_elan_gpio_config(SYSCTL_HANDLER_ARGS)
113123015Sphk{
114123015Sphk	u_int u, v;
115123015Sphk	int i, np, ne;
116123015Sphk	int error;
117126762Sjb	char buf[32];
118126762Sjb	char tmp[10];
119123015Sphk
120123015Sphk	error = SYSCTL_OUT(req, gpio_config, 33);
121123015Sphk	if (error != 0 || req->newptr == NULL)
122123015Sphk		return (error);
123123015Sphk	if (req->newlen != 32)
124123015Sphk		return (EINVAL);
125123015Sphk	error = SYSCTL_IN(req, buf, 32);
126123015Sphk	if (error != 0)
127123015Sphk		return (error);
128123015Sphk	/* Disallow any disabled pins and count pps and echo */
129123015Sphk	np = ne = 0;
130123015Sphk	for (i = 0; i < 32; i++) {
131127801Sphk		if (gpio_config[i] == '-' && buf[i] == '.')
132127801Sphk			buf[i] = gpio_config[i];
133127801Sphk		if (gpio_config[i] == '-' && buf[i] != '-')
134123015Sphk			return (EPERM);
135123015Sphk		if (buf[i] == 'P') {
136123015Sphk			np++;
137123015Sphk			if (np > 1)
138123015Sphk				return (EINVAL);
139123015Sphk		}
140123015Sphk		if (buf[i] == 'e' || buf[i] == 'E') {
141123015Sphk			ne++;
142123015Sphk			if (ne > 1)
143123015Sphk				return (EINVAL);
144123015Sphk		}
145123015Sphk		if (buf[i] != 'L' && buf[i] != 'l'
146123015Sphk#ifdef CPU_ELAN_PPS
147123015Sphk		    && buf[i] != 'P' && buf[i] != 'E' && buf[i] != 'e'
148123015Sphk#endif /* CPU_ELAN_PPS */
149123015Sphk		    && buf[i] != '.' && buf[i] != '-')
150123015Sphk			return (EINVAL);
151123015Sphk	}
152123015Sphk#ifdef CPU_ELAN_PPS
153123015Sphk	if (np == 0)
154123015Sphk		pps_a = pps_d = 0;
155123015Sphk	if (ne == 0)
156123015Sphk		echo_a = echo_d = 0;
157123015Sphk#endif
158123015Sphk	for (i = 0; i < 32; i++) {
159123015Sphk		u = 1 << (i & 0xf);
160123015Sphk		if (i >= 16)
161123015Sphk			v = 2;
162123015Sphk		else
163123015Sphk			v = 0;
164126762Sjb#ifdef CPU_SOEKRIS
165127801Sphk		if (i == 9)
166127801Sphk			;
167127801Sphk		else
168127801Sphk#endif
169123015Sphk		if (buf[i] != 'l' && buf[i] != 'L' && led_dev[i] != NULL) {
170123015Sphk			led_destroy(led_dev[i]);
171123015Sphk			led_dev[i] = NULL;
172124144Sphk			mmcrptr[(0xc2a + v) / 2] &= ~u;
173123015Sphk		}
174123015Sphk		switch (buf[i]) {
175123015Sphk#ifdef CPU_ELAN_PPS
176123015Sphk		case 'P':
177123015Sphk			pps_d = u;
178123015Sphk			pps_a = 0xc30 + v;
179127039Sphk			pps_ap[0] = &mmcrptr[pps_a / 2];
180127039Sphk			pps_ap[1] = &elan_mmcr->GPTMR2CNT;
181127039Sphk			pps_ap[2] = &elan_mmcr->GPTMR1CNT;
182124144Sphk			mmcrptr[(0xc2a + v) / 2] &= ~u;
183123015Sphk			gpio_config[i] = buf[i];
184123015Sphk			break;
185123015Sphk		case 'e':
186123015Sphk		case 'E':
187123015Sphk			echo_d = u;
188123015Sphk			if (buf[i] == 'E')
189123015Sphk				echo_a = 0xc34 + v;
190123015Sphk			else
191123015Sphk				echo_a = 0xc38 + v;
192124144Sphk			mmcrptr[(0xc2a + v) / 2] |= u;
193123015Sphk			gpio_config[i] = buf[i];
194123015Sphk			break;
195123015Sphk#endif /* CPU_ELAN_PPS */
196123015Sphk		case 'l':
197123015Sphk		case 'L':
198123015Sphk			if (buf[i] == 'L')
199123015Sphk				led_cookie[i] = (0xc34 + v) | (u << 16);
200123015Sphk			else
201123015Sphk				led_cookie[i] = (0xc38 + v) | (u << 16);
202123015Sphk			if (led_dev[i])
203123015Sphk				break;
204123015Sphk			sprintf(tmp, "gpio%d", i);
205128677Sphk			mmcrptr[(0xc2a + v) / 2] |= u;
206128677Sphk			gpio_config[i] = buf[i];
207123015Sphk			led_dev[i] =
208123015Sphk			    led_create(gpio_led, &led_cookie[i], tmp);
209123015Sphk			break;
210123015Sphk		case '.':
211123015Sphk			gpio_config[i] = buf[i];
212123015Sphk			break;
213123015Sphk		case '-':
214123015Sphk		default:
215123015Sphk			break;
216123015Sphk		}
217123015Sphk	}
218123015Sphk	return (0);
219123015Sphk}
220123015Sphk
221123015SphkSYSCTL_OID(_machdep, OID_AUTO, elan_gpio_config, CTLTYPE_STRING | CTLFLAG_RW,
222123015Sphk    NULL, 0, sysctl_machdep_elan_gpio_config, "A", "Elan CPU GPIO pin config");
223123015Sphk
224123015Sphk#ifdef CPU_ELAN_PPS
225123015Sphkstatic void
226109327Sphkelan_poll_pps(struct timecounter *tc)
227109327Sphk{
228109327Sphk	static int state;
229109327Sphk	int i;
230127039Sphk	uint16_t u, x, y, z;
231127039Sphk	u_long eflags;
232109327Sphk
233123015Sphk	/*
234127039Sphk	 * Grab the HW state as quickly and compactly as we can.  Disable
235127039Sphk	 * interrupts to avoid measuring our interrupt service time on
236127039Sphk	 * hw with quality clock sources.
237127039Sphk	 */
238127039Sphk	eflags = read_eflags();
239127039Sphk	disable_intr();
240127039Sphk	x = *pps_ap[0];	/* state, must be first, see below */
241127039Sphk	y = *pps_ap[1]; /* timer2 */
242127039Sphk	z = *pps_ap[2]; /* timer1 */
243127039Sphk	write_eflags(eflags);
244127039Sphk
245127039Sphk	/*
246123015Sphk	 * Order is important here.  We need to check the state of the GPIO
247123015Sphk	 * pin first, in order to avoid reading timer 1 right before the
248123015Sphk	 * state change.  Technically pps_a may be zero in which case we
249123015Sphk	 * harmlessly read the REVID register and the contents of pps_d is
250123015Sphk	 * of no concern.
251123015Sphk	 */
252123015Sphk
253127039Sphk	i = x & pps_d;
254123015Sphk
255123015Sphk	/* If state did not change or we don't have a GPIO pin, return */
256123015Sphk	if (i == state || pps_a == 0)
257109327Sphk		return;
258123015Sphk
259109327Sphk	state = i;
260123015Sphk
261123015Sphk	/* If the state is "low", flip the echo GPIO and return.  */
262123015Sphk	if (!i) {
263123015Sphk		if (echo_a)
264124144Sphk			mmcrptr[(echo_a ^ 0xc) / 2] = echo_d;
265109327Sphk		return;
266123015Sphk	}
267123015Sphk
268127039Sphk	/*
269127039Sphk	 * Subtract timer1 from timer2 to compensate for time from the
270127039Sphk	 * edge until we read the counters.
271127039Sphk	 */
272127039Sphk	u = y - z;
273127039Sphk
274109327Sphk	pps_capture(&elan_pps);
275127039Sphk	elan_pps.capcount = u;
276109327Sphk	pps_event(&elan_pps, PPS_CAPTUREASSERT);
277123015Sphk
278123015Sphk	/* Twiddle echo bit */
279123015Sphk	if (echo_a)
280124144Sphk		mmcrptr[echo_a / 2] = echo_d;
281109327Sphk}
282123015Sphk#endif /* CPU_ELAN_PPS */
283109327Sphk
284102935Sphkstatic unsigned
285102935Sphkelan_get_timecount(struct timecounter *tc)
286102935Sphk{
287123015Sphk
288123015Sphk	/* Read timer2, end of story */
289124144Sphk	return (elan_mmcr->GPTMR2CNT);
290102935Sphk}
291102935Sphk
292109327Sphk/*
293109327Sphk * The Elan CPU can be run from a number of clock frequencies, this
294109327Sphk * allows you to override the default 33.3 MHZ.
295109327Sphk */
296123015Sphk#ifndef CPU_ELAN_XTAL
297123015Sphk#define CPU_ELAN_XTAL 33333333
298109327Sphk#endif
299109327Sphk
300102935Sphkstatic struct timecounter elan_timecounter = {
301102935Sphk	elan_get_timecount,
302109327Sphk	NULL,
303102935Sphk	0xffff,
304123015Sphk	CPU_ELAN_XTAL / 4,
305119715Sphk	"ELAN",
306119715Sphk	1000
307102935Sphk};
308102935Sphk
309109327Sphkstatic int
310109327Sphksysctl_machdep_elan_freq(SYSCTL_HANDLER_ARGS)
311109327Sphk{
312109327Sphk	u_int f;
313109327Sphk	int error;
314109327Sphk
315109327Sphk	f = elan_timecounter.tc_frequency * 4;
316170289Sdwmalone	error = sysctl_handle_int(oidp, &f, 0, req);
317109327Sphk	if (error == 0 && req->newptr != NULL)
318109327Sphk		elan_timecounter.tc_frequency = (f + 3) / 4;
319109327Sphk	return (error);
320109327Sphk}
321109327Sphk
322109327SphkSYSCTL_PROC(_machdep, OID_AUTO, elan_freq, CTLTYPE_UINT | CTLFLAG_RW,
323109327Sphk    0, sizeof (u_int), sysctl_machdep_elan_freq, "IU", "");
324109327Sphk
325123015Sphk/*
326123015Sphk * Positively identifying the Elan can only be done through the PCI id of
327123015Sphk * the host-bridge, this function is called from i386/pci/pci_bus.c.
328123015Sphk */
329102934Sphkvoid
330102934Sphkinit_AMD_Elan_sc520(void)
331102934Sphk{
332102934Sphk	u_int new;
333102934Sphk	int i;
334102934Sphk
335124144Sphk	mmcrptr = pmap_mapdev(0xfffef000, 0x1000);
336124144Sphk	elan_mmcr = (volatile struct elan_mmcr *)mmcrptr;
337102934Sphk
338102934Sphk	/*-
339102934Sphk	 * The i8254 is driven with a nonstandard frequency which is
340102934Sphk	 * derived thusly:
341102934Sphk	 *   f = 32768 * 45 * 25 / 31 = 1189161.29...
342123015Sphk	 * We use the sysctl to get the i8254 (timecounter etc) into whack.
343102934Sphk	 */
344102934Sphk
345102934Sphk	new = 1189161;
346102934Sphk	i = kernel_sysctlbyname(&thread0, "machdep.i8254_freq",
347136419Sphk	    NULL, 0, &new, sizeof new, NULL, 0);
348123015Sphk	if (bootverbose || 1)
349103168Ssam		printf("sysctl machdep.i8254_freq=%d returns %d\n", new, i);
350102935Sphk
351102935Sphk	/* Start GP timer #2 and use it as timecounter, hz permitting */
352124144Sphk	elan_mmcr->GPTMR2MAXCMPA = 0;
353124144Sphk	elan_mmcr->GPTMR2CTL = 0xc001;
354109327Sphk
355123015Sphk#ifdef CPU_ELAN_PPS
356109327Sphk	/* Set up GP timer #1 as pps counter */
357124144Sphk	elan_mmcr->CSPFS &= ~0x10;
358124144Sphk	elan_mmcr->GPTMR1CTL = 0x8000 | 0x4000 | 0x10 | 0x1;
359124144Sphk	elan_mmcr->GPTMR1MAXCMPA = 0x0;
360124144Sphk	elan_mmcr->GPTMR1MAXCMPB = 0x0;
361109327Sphk	elan_pps.ppscap |= PPS_CAPTUREASSERT;
362109327Sphk	pps_init(&elan_pps);
363109327Sphk#endif
364102935Sphk	tc_init(&elan_timecounter);
365102934Sphk}
366102934Sphk
367103482Sphkstatic void
368126370Sphkelan_watchdog(void *foo __unused, u_int spec, int *error)
369101225Sphk{
370165260Sn_hibma	u_int u, v, w;
371111647Sphk	static u_int cur;
372111647Sphk
373126370Sphk	u = spec & WD_INTERVAL;
374165260Sn_hibma	if (u > 0 && u <= 35) {
375111647Sphk		u = imax(u - 5, 24);
376111647Sphk		v = 2 << (u - 24);
377111647Sphk		v |= 0xc000;
378111647Sphk
379111647Sphk		/*
380111647Sphk		 * There is a bug in some silicon which prevents us from
381111647Sphk		 * writing to the WDTMRCTL register if the GP echo mode is
382111647Sphk		 * enabled.  GP echo mode on the other hand is desirable
383111647Sphk		 * for other reasons.  Save and restore the GP echo mode
384111647Sphk		 * around our hardware tom-foolery.
385111647Sphk		 */
386165260Sn_hibma		w = elan_mmcr->GPECHO;
387124144Sphk		elan_mmcr->GPECHO = 0;
388111647Sphk		if (v != cur) {
389111647Sphk			/* Clear the ENB bit */
390124144Sphk			elan_mmcr->WDTMRCTL = 0x3333;
391124144Sphk			elan_mmcr->WDTMRCTL = 0xcccc;
392124144Sphk			elan_mmcr->WDTMRCTL = 0;
393111647Sphk
394111647Sphk			/* Set new value */
395124144Sphk			elan_mmcr->WDTMRCTL = 0x3333;
396124144Sphk			elan_mmcr->WDTMRCTL = 0xcccc;
397124144Sphk			elan_mmcr->WDTMRCTL = v;
398111647Sphk			cur = v;
399111647Sphk		} else {
400111647Sphk			/* Just reset timer */
401124144Sphk			elan_mmcr->WDTMRCTL = 0xaaaa;
402124144Sphk			elan_mmcr->WDTMRCTL = 0x5555;
403111647Sphk		}
404165260Sn_hibma		elan_mmcr->GPECHO = w;
405126370Sphk		*error = 0;
406126370Sphk	} else {
407165260Sn_hibma		w = elan_mmcr->GPECHO;
408124144Sphk		elan_mmcr->GPECHO = 0;
409124144Sphk		elan_mmcr->WDTMRCTL = 0x3333;
410124144Sphk		elan_mmcr->WDTMRCTL = 0xcccc;
411124144Sphk		elan_mmcr->WDTMRCTL = 0x4080;
412165260Sn_hibma		elan_mmcr->WDTMRCTL = w;		/* XXX What does this statement do? */
413165260Sn_hibma		elan_mmcr->GPECHO = w;
414111647Sphk		cur = 0;
415111647Sphk	}
416111647Sphk}
417111647Sphk
418111647Sphkstatic int
419201223Srnolandelan_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
420201223Srnoland    int nprot, vm_memattr_t *memattr)
421126370Sphk{
422126370Sphk
423126370Sphk	if (offset >= 0x1000)
424126370Sphk		return (-1);
425126370Sphk	*paddr = 0xfffef000;
426126370Sphk	return (0);
427126370Sphk}
428126370Sphkstatic int
429130585Sphkelan_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct  thread *tdr)
430101225Sphk{
431109327Sphk	int error;
432109327Sphk
433126370Sphk	error = ENOIOCTL;
434123015Sphk
435123015Sphk#ifdef CPU_ELAN_PPS
436123015Sphk	if (pps_a != 0)
437123015Sphk		error = pps_ioctl(cmd, arg, &elan_pps);
438109327Sphk	/*
439109327Sphk	 * We only want to incur the overhead of the PPS polling if we
440109327Sphk	 * are actually asked to timestamp.
441109327Sphk	 */
442123015Sphk	if (elan_pps.ppsparam.mode & PPS_CAPTUREASSERT) {
443109327Sphk		elan_timecounter.tc_poll_pps = elan_poll_pps;
444123015Sphk	} else {
445109327Sphk		elan_timecounter.tc_poll_pps = NULL;
446123015Sphk	}
447126370Sphk	if (error != ENOIOCTL)
448109327Sphk		return (error);
449123015Sphk#endif
450109327Sphk
451109327Sphk	return(error);
452101225Sphk}
453101225Sphk
454126370Sphkstatic struct cdevsw elan_cdevsw = {
455126370Sphk	.d_version =	D_VERSION,
456126370Sphk	.d_flags =	D_NEEDGIANT,
457126370Sphk	.d_ioctl =	elan_ioctl,
458126370Sphk	.d_mmap =	elan_mmap,
459126370Sphk	.d_name =	"elan",
460126370Sphk};
461126370Sphk
462126370Sphkstatic void
463126370Sphkelan_drvinit(void)
464126370Sphk{
465126370Sphk
466148231Sphk#ifdef CPU_SOEKRIS
467148231Sphk#define BIOS_OEM_MAXLEN 72
468148231Sphk        static u_char bios_oem[BIOS_OEM_MAXLEN] = "\0";
469148231Sphk#endif /* CPU_SOEKRIS */
470148231Sphk
471126370Sphk	/* If no elan found, just return */
472126370Sphk	if (mmcrptr == NULL)
473126370Sphk		return;
474126370Sphk
475126370Sphk	printf("Elan-mmcr driver: MMCR at %p.%s\n",
476126370Sphk	    mmcrptr,
477126370Sphk#ifdef CPU_ELAN_PPS
478126370Sphk	    " PPS support."
479126370Sphk#else
480126370Sphk	    ""
481126370Sphk#endif
482126370Sphk	    );
483126370Sphk
484126370Sphk	make_dev(&elan_cdevsw, 0,
485126370Sphk	    UID_ROOT, GID_WHEEL, 0600, "elan-mmcr");
486126370Sphk
487126370Sphk#ifdef CPU_SOEKRIS
488148231Sphk	if ( bios_oem_strings(&bios_soekris, bios_oem, BIOS_OEM_MAXLEN) > 0 )
489148231Sphk		printf("Elan-mmcr %s\n", bios_oem);
490148231Sphk
491126370Sphk	/* Create the error LED on GPIO9 */
492126370Sphk	led_cookie[9] = 0x02000c34;
493126370Sphk	led_dev[9] = led_create(gpio_led, &led_cookie[9], "error");
494126370Sphk
495126370Sphk	/* Disable the unavailable GPIO pins */
496126370Sphk	strcpy(gpio_config, "-----....--..--------..---------");
497126370Sphk#else /* !CPU_SOEKRIS */
498126370Sphk	/* We don't know which pins are available so enable them all */
499126370Sphk	strcpy(gpio_config, "................................");
500126370Sphk#endif /* CPU_SOEKRIS */
501126370Sphk
502126370Sphk	EVENTHANDLER_REGISTER(watchdog_list, elan_watchdog, NULL, 0);
503126370Sphk}
504126370Sphk
505126370SphkSYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL);
506126370Sphk
507