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