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 69static char gpio_config[33]; 70 71static volatile uint16_t *mmcrptr; 72volatile struct elan_mmcr *elan_mmcr; 73 74#ifdef CPU_ELAN_PPS 75static struct pps_state elan_pps; 76static volatile uint16_t *pps_ap[3]; 77static u_int pps_a, pps_d; 78static u_int echo_a, echo_d; 79#endif /* CPU_ELAN_PPS */ 80 81#ifdef CPU_SOEKRIS 82 83static 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 95static u_int led_cookie[32]; 96static struct cdev *led_dev[32]; 97 98static void 99gpio_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 111static int 112sysctl_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 221SYSCTL_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 225static void 226elan_poll_pps(struct timecounter *tc) 227{ 228 static int state; 229 int i; 230 uint16_t u, x, y, z; 231 register_t saveintr; 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 saveintr = intr_disable(); 239 x = *pps_ap[0]; /* state, must be first, see below */ 240 y = *pps_ap[1]; /* timer2 */ 241 z = *pps_ap[2]; /* timer1 */ 242 intr_restore(saveintr); 243 244 /* 245 * Order is important here. We need to check the state of the GPIO 246 * pin first, in order to avoid reading timer 1 right before the 247 * state change. Technically pps_a may be zero in which case we 248 * harmlessly read the REVID register and the contents of pps_d is 249 * of no concern. 250 */ 251 252 i = x & pps_d; 253 254 /* If state did not change or we don't have a GPIO pin, return */ 255 if (i == state || pps_a == 0) 256 return; 257 258 state = i; 259 260 /* If the state is "low", flip the echo GPIO and return. */ 261 if (!i) { 262 if (echo_a) 263 mmcrptr[(echo_a ^ 0xc) / 2] = echo_d; 264 return; 265 } 266 267 /* 268 * Subtract timer1 from timer2 to compensate for time from the 269 * edge until we read the counters. 270 */ 271 u = y - z; 272 273 pps_capture(&elan_pps); 274 elan_pps.capcount = u; 275 pps_event(&elan_pps, PPS_CAPTUREASSERT); 276 277 /* Twiddle echo bit */ 278 if (echo_a) 279 mmcrptr[echo_a / 2] = echo_d; 280} 281#endif /* CPU_ELAN_PPS */ 282 283static unsigned 284elan_get_timecount(struct timecounter *tc) 285{ 286 287 /* Read timer2, end of story */ 288 return (elan_mmcr->GPTMR2CNT); 289} 290 291/* 292 * The Elan CPU can be run from a number of clock frequencies, this 293 * allows you to override the default 33.3 MHZ. 294 */ 295#ifndef CPU_ELAN_XTAL 296#define CPU_ELAN_XTAL 33333333 297#endif 298 299static struct timecounter elan_timecounter = { 300 elan_get_timecount, 301 NULL, 302 0xffff, 303 CPU_ELAN_XTAL / 4, 304 "ELAN", 305 1000 306}; 307 308static int 309sysctl_machdep_elan_freq(SYSCTL_HANDLER_ARGS) 310{ 311 u_int f; 312 int error; 313 314 f = elan_timecounter.tc_frequency * 4; 315 error = sysctl_handle_int(oidp, &f, 0, req); 316 if (error == 0 && req->newptr != NULL) 317 elan_timecounter.tc_frequency = (f + 3) / 4; 318 return (error); 319} 320 321SYSCTL_PROC(_machdep, OID_AUTO, elan_freq, CTLTYPE_UINT | CTLFLAG_RW, 322 0, sizeof (u_int), sysctl_machdep_elan_freq, "IU", ""); 323 324/* 325 * Positively identifying the Elan can only be done through the PCI id of 326 * the host-bridge, this function is called from i386/pci/pci_bus.c. 327 */ 328void 329init_AMD_Elan_sc520(void) 330{ 331 u_int new; 332 int i; 333 334 mmcrptr = pmap_mapdev(0xfffef000, 0x1000); 335 elan_mmcr = (volatile struct elan_mmcr *)mmcrptr; 336 337 /*- 338 * The i8254 is driven with a nonstandard frequency which is 339 * derived thusly: 340 * f = 32768 * 45 * 25 / 31 = 1189161.29... 341 * We use the sysctl to get the i8254 (timecounter etc) into whack. 342 */ 343 344 new = 1189161; 345 i = kernel_sysctlbyname(&thread0, "machdep.i8254_freq", 346 NULL, 0, &new, sizeof new, NULL, 0); 347 if (bootverbose || 1) 348 printf("sysctl machdep.i8254_freq=%d returns %d\n", new, i); 349 350 /* Start GP timer #2 and use it as timecounter, hz permitting */ 351 elan_mmcr->GPTMR2MAXCMPA = 0; 352 elan_mmcr->GPTMR2CTL = 0xc001; 353 354#ifdef CPU_ELAN_PPS 355 /* Set up GP timer #1 as pps counter */ 356 elan_mmcr->CSPFS &= ~0x10; 357 elan_mmcr->GPTMR1CTL = 0x8000 | 0x4000 | 0x10 | 0x1; 358 elan_mmcr->GPTMR1MAXCMPA = 0x0; 359 elan_mmcr->GPTMR1MAXCMPB = 0x0; 360 elan_pps.ppscap |= PPS_CAPTUREASSERT; 361 pps_init(&elan_pps); 362#endif 363 tc_init(&elan_timecounter); 364} 365 366static void 367elan_watchdog(void *foo __unused, u_int spec, int *error) 368{ 369 u_int u, v, w; 370 static u_int cur; 371 372 u = spec & WD_INTERVAL; 373 if (u > 0 && u <= 35) { 374 u = imax(u - 5, 24); 375 v = 2 << (u - 24); 376 v |= 0xc000; 377 378 /* 379 * There is a bug in some silicon which prevents us from 380 * writing to the WDTMRCTL register if the GP echo mode is 381 * enabled. GP echo mode on the other hand is desirable 382 * for other reasons. Save and restore the GP echo mode 383 * around our hardware tom-foolery. 384 */ 385 w = elan_mmcr->GPECHO; 386 elan_mmcr->GPECHO = 0; 387 if (v != cur) { 388 /* Clear the ENB bit */ 389 elan_mmcr->WDTMRCTL = 0x3333; 390 elan_mmcr->WDTMRCTL = 0xcccc; 391 elan_mmcr->WDTMRCTL = 0; 392 393 /* Set new value */ 394 elan_mmcr->WDTMRCTL = 0x3333; 395 elan_mmcr->WDTMRCTL = 0xcccc; 396 elan_mmcr->WDTMRCTL = v; 397 cur = v; 398 } else { 399 /* Just reset timer */ 400 elan_mmcr->WDTMRCTL = 0xaaaa; 401 elan_mmcr->WDTMRCTL = 0x5555; 402 } 403 elan_mmcr->GPECHO = w; 404 *error = 0; 405 } else { 406 w = elan_mmcr->GPECHO; 407 elan_mmcr->GPECHO = 0; 408 elan_mmcr->WDTMRCTL = 0x3333; 409 elan_mmcr->WDTMRCTL = 0xcccc; 410 elan_mmcr->WDTMRCTL = 0x4080; 411 elan_mmcr->WDTMRCTL = w; /* XXX What does this statement do? */ 412 elan_mmcr->GPECHO = w; 413 cur = 0; 414 } 415} 416 417static int 418elan_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 419 int nprot, vm_memattr_t *memattr) 420{ 421 422 if (offset >= 0x1000) 423 return (-1); 424 *paddr = 0xfffef000; 425 return (0); 426} 427static int 428elan_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr) 429{ 430 int error; 431 432 error = ENOIOCTL; 433 434#ifdef CPU_ELAN_PPS 435 if (pps_a != 0) 436 error = pps_ioctl(cmd, arg, &elan_pps); 437 /* 438 * We only want to incur the overhead of the PPS polling if we 439 * are actually asked to timestamp. 440 */ 441 if (elan_pps.ppsparam.mode & PPS_CAPTUREASSERT) { 442 elan_timecounter.tc_poll_pps = elan_poll_pps; 443 } else { 444 elan_timecounter.tc_poll_pps = NULL; 445 } 446 if (error != ENOIOCTL) 447 return (error); 448#endif 449 450 return(error); 451} 452 453static struct cdevsw elan_cdevsw = { 454 .d_version = D_VERSION, 455 .d_flags = D_NEEDGIANT, 456 .d_ioctl = elan_ioctl, 457 .d_mmap = elan_mmap, 458 .d_name = "elan", 459}; 460 461static void 462elan_drvinit(void) 463{ 464 465#ifdef CPU_SOEKRIS 466#define BIOS_OEM_MAXLEN 72 467 static u_char bios_oem[BIOS_OEM_MAXLEN] = "\0"; 468#endif /* CPU_SOEKRIS */ 469 470 /* If no elan found, just return */ 471 if (mmcrptr == NULL) 472 return; 473 474 printf("Elan-mmcr driver: MMCR at %p.%s\n", 475 mmcrptr, 476#ifdef CPU_ELAN_PPS 477 " PPS support." 478#else 479 "" 480#endif 481 ); 482 483 make_dev(&elan_cdevsw, 0, 484 UID_ROOT, GID_WHEEL, 0600, "elan-mmcr"); 485 486#ifdef CPU_SOEKRIS 487 if ( bios_oem_strings(&bios_soekris, bios_oem, BIOS_OEM_MAXLEN) > 0 ) 488 printf("Elan-mmcr %s\n", bios_oem); 489 490 /* Create the error LED on GPIO9 */ 491 led_cookie[9] = 0x02000c34; 492 led_dev[9] = led_create(gpio_led, &led_cookie[9], "error"); 493 494 /* Disable the unavailable GPIO pins */ 495 strcpy(gpio_config, "-----....--..--------..---------"); 496#else /* !CPU_SOEKRIS */ 497 /* We don't know which pins are available so enable them all */ 498 strcpy(gpio_config, "................................"); 499#endif /* CPU_SOEKRIS */ 500 501 EVENTHANDLER_REGISTER(watchdog_list, elan_watchdog, NULL, 0); 502} 503 504SYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL); 505 506