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$"); 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; 231214346Sjhb register_t saveintr; 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 */ 238214346Sjhb saveintr = intr_disable(); 239127039Sphk x = *pps_ap[0]; /* state, must be first, see below */ 240127039Sphk y = *pps_ap[1]; /* timer2 */ 241127039Sphk z = *pps_ap[2]; /* timer1 */ 242214346Sjhb intr_restore(saveintr); 243127039Sphk 244127039Sphk /* 245123015Sphk * Order is important here. We need to check the state of the GPIO 246123015Sphk * pin first, in order to avoid reading timer 1 right before the 247123015Sphk * state change. Technically pps_a may be zero in which case we 248123015Sphk * harmlessly read the REVID register and the contents of pps_d is 249123015Sphk * of no concern. 250123015Sphk */ 251123015Sphk 252127039Sphk i = x & pps_d; 253123015Sphk 254123015Sphk /* If state did not change or we don't have a GPIO pin, return */ 255123015Sphk if (i == state || pps_a == 0) 256109327Sphk return; 257123015Sphk 258109327Sphk state = i; 259123015Sphk 260123015Sphk /* If the state is "low", flip the echo GPIO and return. */ 261123015Sphk if (!i) { 262123015Sphk if (echo_a) 263124144Sphk mmcrptr[(echo_a ^ 0xc) / 2] = echo_d; 264109327Sphk return; 265123015Sphk } 266123015Sphk 267127039Sphk /* 268127039Sphk * Subtract timer1 from timer2 to compensate for time from the 269127039Sphk * edge until we read the counters. 270127039Sphk */ 271127039Sphk u = y - z; 272127039Sphk 273109327Sphk pps_capture(&elan_pps); 274127039Sphk elan_pps.capcount = u; 275109327Sphk pps_event(&elan_pps, PPS_CAPTUREASSERT); 276123015Sphk 277123015Sphk /* Twiddle echo bit */ 278123015Sphk if (echo_a) 279124144Sphk mmcrptr[echo_a / 2] = echo_d; 280109327Sphk} 281123015Sphk#endif /* CPU_ELAN_PPS */ 282109327Sphk 283102935Sphkstatic unsigned 284102935Sphkelan_get_timecount(struct timecounter *tc) 285102935Sphk{ 286123015Sphk 287123015Sphk /* Read timer2, end of story */ 288124144Sphk return (elan_mmcr->GPTMR2CNT); 289102935Sphk} 290102935Sphk 291109327Sphk/* 292109327Sphk * The Elan CPU can be run from a number of clock frequencies, this 293109327Sphk * allows you to override the default 33.3 MHZ. 294109327Sphk */ 295123015Sphk#ifndef CPU_ELAN_XTAL 296123015Sphk#define CPU_ELAN_XTAL 33333333 297109327Sphk#endif 298109327Sphk 299102935Sphkstatic struct timecounter elan_timecounter = { 300102935Sphk elan_get_timecount, 301109327Sphk NULL, 302102935Sphk 0xffff, 303123015Sphk CPU_ELAN_XTAL / 4, 304119715Sphk "ELAN", 305119715Sphk 1000 306102935Sphk}; 307102935Sphk 308109327Sphkstatic int 309109327Sphksysctl_machdep_elan_freq(SYSCTL_HANDLER_ARGS) 310109327Sphk{ 311109327Sphk u_int f; 312109327Sphk int error; 313109327Sphk 314109327Sphk f = elan_timecounter.tc_frequency * 4; 315170289Sdwmalone error = sysctl_handle_int(oidp, &f, 0, req); 316109327Sphk if (error == 0 && req->newptr != NULL) 317109327Sphk elan_timecounter.tc_frequency = (f + 3) / 4; 318109327Sphk return (error); 319109327Sphk} 320109327Sphk 321109327SphkSYSCTL_PROC(_machdep, OID_AUTO, elan_freq, CTLTYPE_UINT | CTLFLAG_RW, 322109327Sphk 0, sizeof (u_int), sysctl_machdep_elan_freq, "IU", ""); 323109327Sphk 324123015Sphk/* 325123015Sphk * Positively identifying the Elan can only be done through the PCI id of 326123015Sphk * the host-bridge, this function is called from i386/pci/pci_bus.c. 327123015Sphk */ 328102934Sphkvoid 329102934Sphkinit_AMD_Elan_sc520(void) 330102934Sphk{ 331102934Sphk u_int new; 332102934Sphk int i; 333102934Sphk 334124144Sphk mmcrptr = pmap_mapdev(0xfffef000, 0x1000); 335124144Sphk elan_mmcr = (volatile struct elan_mmcr *)mmcrptr; 336102934Sphk 337102934Sphk /*- 338102934Sphk * The i8254 is driven with a nonstandard frequency which is 339102934Sphk * derived thusly: 340102934Sphk * f = 32768 * 45 * 25 / 31 = 1189161.29... 341123015Sphk * We use the sysctl to get the i8254 (timecounter etc) into whack. 342102934Sphk */ 343102934Sphk 344102934Sphk new = 1189161; 345102934Sphk i = kernel_sysctlbyname(&thread0, "machdep.i8254_freq", 346136419Sphk NULL, 0, &new, sizeof new, NULL, 0); 347123015Sphk if (bootverbose || 1) 348103168Ssam printf("sysctl machdep.i8254_freq=%d returns %d\n", new, i); 349102935Sphk 350102935Sphk /* Start GP timer #2 and use it as timecounter, hz permitting */ 351124144Sphk elan_mmcr->GPTMR2MAXCMPA = 0; 352124144Sphk elan_mmcr->GPTMR2CTL = 0xc001; 353109327Sphk 354123015Sphk#ifdef CPU_ELAN_PPS 355109327Sphk /* Set up GP timer #1 as pps counter */ 356124144Sphk elan_mmcr->CSPFS &= ~0x10; 357124144Sphk elan_mmcr->GPTMR1CTL = 0x8000 | 0x4000 | 0x10 | 0x1; 358124144Sphk elan_mmcr->GPTMR1MAXCMPA = 0x0; 359124144Sphk elan_mmcr->GPTMR1MAXCMPB = 0x0; 360109327Sphk elan_pps.ppscap |= PPS_CAPTUREASSERT; 361109327Sphk pps_init(&elan_pps); 362109327Sphk#endif 363102935Sphk tc_init(&elan_timecounter); 364102934Sphk} 365102934Sphk 366103482Sphkstatic void 367126370Sphkelan_watchdog(void *foo __unused, u_int spec, int *error) 368101225Sphk{ 369165260Sn_hibma u_int u, v, w; 370111647Sphk static u_int cur; 371111647Sphk 372126370Sphk u = spec & WD_INTERVAL; 373165260Sn_hibma if (u > 0 && u <= 35) { 374111647Sphk u = imax(u - 5, 24); 375111647Sphk v = 2 << (u - 24); 376111647Sphk v |= 0xc000; 377111647Sphk 378111647Sphk /* 379111647Sphk * There is a bug in some silicon which prevents us from 380111647Sphk * writing to the WDTMRCTL register if the GP echo mode is 381111647Sphk * enabled. GP echo mode on the other hand is desirable 382111647Sphk * for other reasons. Save and restore the GP echo mode 383111647Sphk * around our hardware tom-foolery. 384111647Sphk */ 385165260Sn_hibma w = elan_mmcr->GPECHO; 386124144Sphk elan_mmcr->GPECHO = 0; 387111647Sphk if (v != cur) { 388111647Sphk /* Clear the ENB bit */ 389124144Sphk elan_mmcr->WDTMRCTL = 0x3333; 390124144Sphk elan_mmcr->WDTMRCTL = 0xcccc; 391124144Sphk elan_mmcr->WDTMRCTL = 0; 392111647Sphk 393111647Sphk /* Set new value */ 394124144Sphk elan_mmcr->WDTMRCTL = 0x3333; 395124144Sphk elan_mmcr->WDTMRCTL = 0xcccc; 396124144Sphk elan_mmcr->WDTMRCTL = v; 397111647Sphk cur = v; 398111647Sphk } else { 399111647Sphk /* Just reset timer */ 400124144Sphk elan_mmcr->WDTMRCTL = 0xaaaa; 401124144Sphk elan_mmcr->WDTMRCTL = 0x5555; 402111647Sphk } 403165260Sn_hibma elan_mmcr->GPECHO = w; 404126370Sphk *error = 0; 405126370Sphk } else { 406165260Sn_hibma w = elan_mmcr->GPECHO; 407124144Sphk elan_mmcr->GPECHO = 0; 408124144Sphk elan_mmcr->WDTMRCTL = 0x3333; 409124144Sphk elan_mmcr->WDTMRCTL = 0xcccc; 410124144Sphk elan_mmcr->WDTMRCTL = 0x4080; 411165260Sn_hibma elan_mmcr->WDTMRCTL = w; /* XXX What does this statement do? */ 412165260Sn_hibma elan_mmcr->GPECHO = w; 413111647Sphk cur = 0; 414111647Sphk } 415111647Sphk} 416111647Sphk 417111647Sphkstatic int 418201223Srnolandelan_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 419201223Srnoland int nprot, vm_memattr_t *memattr) 420126370Sphk{ 421126370Sphk 422126370Sphk if (offset >= 0x1000) 423126370Sphk return (-1); 424126370Sphk *paddr = 0xfffef000; 425126370Sphk return (0); 426126370Sphk} 427126370Sphkstatic int 428130585Sphkelan_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr) 429101225Sphk{ 430109327Sphk int error; 431109327Sphk 432126370Sphk error = ENOIOCTL; 433123015Sphk 434123015Sphk#ifdef CPU_ELAN_PPS 435123015Sphk if (pps_a != 0) 436123015Sphk error = pps_ioctl(cmd, arg, &elan_pps); 437109327Sphk /* 438109327Sphk * We only want to incur the overhead of the PPS polling if we 439109327Sphk * are actually asked to timestamp. 440109327Sphk */ 441123015Sphk if (elan_pps.ppsparam.mode & PPS_CAPTUREASSERT) { 442109327Sphk elan_timecounter.tc_poll_pps = elan_poll_pps; 443123015Sphk } else { 444109327Sphk elan_timecounter.tc_poll_pps = NULL; 445123015Sphk } 446126370Sphk if (error != ENOIOCTL) 447109327Sphk return (error); 448123015Sphk#endif 449109327Sphk 450109327Sphk return(error); 451101225Sphk} 452101225Sphk 453126370Sphkstatic struct cdevsw elan_cdevsw = { 454126370Sphk .d_version = D_VERSION, 455126370Sphk .d_flags = D_NEEDGIANT, 456126370Sphk .d_ioctl = elan_ioctl, 457126370Sphk .d_mmap = elan_mmap, 458126370Sphk .d_name = "elan", 459126370Sphk}; 460126370Sphk 461126370Sphkstatic void 462126370Sphkelan_drvinit(void) 463126370Sphk{ 464126370Sphk 465148231Sphk#ifdef CPU_SOEKRIS 466148231Sphk#define BIOS_OEM_MAXLEN 72 467148231Sphk static u_char bios_oem[BIOS_OEM_MAXLEN] = "\0"; 468148231Sphk#endif /* CPU_SOEKRIS */ 469148231Sphk 470126370Sphk /* If no elan found, just return */ 471126370Sphk if (mmcrptr == NULL) 472126370Sphk return; 473126370Sphk 474126370Sphk printf("Elan-mmcr driver: MMCR at %p.%s\n", 475126370Sphk mmcrptr, 476126370Sphk#ifdef CPU_ELAN_PPS 477126370Sphk " PPS support." 478126370Sphk#else 479126370Sphk "" 480126370Sphk#endif 481126370Sphk ); 482126370Sphk 483126370Sphk make_dev(&elan_cdevsw, 0, 484126370Sphk UID_ROOT, GID_WHEEL, 0600, "elan-mmcr"); 485126370Sphk 486126370Sphk#ifdef CPU_SOEKRIS 487148231Sphk if ( bios_oem_strings(&bios_soekris, bios_oem, BIOS_OEM_MAXLEN) > 0 ) 488148231Sphk printf("Elan-mmcr %s\n", bios_oem); 489148231Sphk 490126370Sphk /* Create the error LED on GPIO9 */ 491126370Sphk led_cookie[9] = 0x02000c34; 492126370Sphk led_dev[9] = led_create(gpio_led, &led_cookie[9], "error"); 493126370Sphk 494126370Sphk /* Disable the unavailable GPIO pins */ 495126370Sphk strcpy(gpio_config, "-----....--..--------..---------"); 496126370Sphk#else /* !CPU_SOEKRIS */ 497126370Sphk /* We don't know which pins are available so enable them all */ 498126370Sphk strcpy(gpio_config, "................................"); 499126370Sphk#endif /* CPU_SOEKRIS */ 500126370Sphk 501126370Sphk EVENTHANDLER_REGISTER(watchdog_list, elan_watchdog, NULL, 0); 502126370Sphk} 503126370Sphk 504126370SphkSYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL); 505126370Sphk 506