elan-mmcr.c revision 123015
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 123015 2003-11-27 20:27:29Z phk $"); 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> 63101225Sphk 64102934Sphk#include <vm/vm.h> 65102934Sphk#include <vm/pmap.h> 66102934Sphk 67123015Sphkstatic char gpio_config[33]; 68123015Sphk 69102934Sphkuint16_t *elan_mmcr; 70102934Sphk 71123015Sphk#ifdef CPU_ELAN_PPS 72109327Sphkstatic struct pps_state elan_pps; 73123015Sphku_int pps_a, pps_d; 74123015Sphku_int echo_a, echo_d; 75123015Sphk#endif /* CPU_ELAN_PPS */ 76123015Sphku_int led_cookie[32]; 77123015Sphkdev_t led_dev[32]; 78109327Sphk 79109327Sphkstatic void 80123015Sphkgpio_led(void *cookie, int state) 81123015Sphk{ 82123015Sphk u_int u, v; 83123015Sphk 84123015Sphk u = *(int *)cookie; 85123015Sphk v = u & 0xffff; 86123015Sphk u >>= 16; 87123015Sphk if (!state) 88123015Sphk v ^= 0xc; 89123015Sphk elan_mmcr[v / 2] = u; 90123015Sphk} 91123015Sphk 92123015Sphkstatic int 93123015Sphksysctl_machdep_elan_gpio_config(SYSCTL_HANDLER_ARGS) 94123015Sphk{ 95123015Sphk u_int u, v; 96123015Sphk int i, np, ne; 97123015Sphk int error; 98123015Sphk char buf[32], tmp[10]; 99123015Sphk 100123015Sphk error = SYSCTL_OUT(req, gpio_config, 33); 101123015Sphk if (error != 0 || req->newptr == NULL) 102123015Sphk return (error); 103123015Sphk if (req->newlen != 32) 104123015Sphk return (EINVAL); 105123015Sphk error = SYSCTL_IN(req, buf, 32); 106123015Sphk if (error != 0) 107123015Sphk return (error); 108123015Sphk /* Disallow any disabled pins and count pps and echo */ 109123015Sphk np = ne = 0; 110123015Sphk for (i = 0; i < 32; i++) { 111123015Sphk if (gpio_config[i] == '-' && (buf[i] != '-' && buf[i] != '.')) 112123015Sphk return (EPERM); 113123015Sphk if (buf[i] == 'P') { 114123015Sphk np++; 115123015Sphk if (np > 1) 116123015Sphk return (EINVAL); 117123015Sphk } 118123015Sphk if (buf[i] == 'e' || buf[i] == 'E') { 119123015Sphk ne++; 120123015Sphk if (ne > 1) 121123015Sphk return (EINVAL); 122123015Sphk } 123123015Sphk if (buf[i] != 'L' && buf[i] != 'l' 124123015Sphk#ifdef CPU_ELAN_PPS 125123015Sphk && buf[i] != 'P' && buf[i] != 'E' && buf[i] != 'e' 126123015Sphk#endif /* CPU_ELAN_PPS */ 127123015Sphk && buf[i] != '.' && buf[i] != '-') 128123015Sphk return (EINVAL); 129123015Sphk } 130123015Sphk#ifdef CPU_ELAN_PPS 131123015Sphk if (np == 0) 132123015Sphk pps_a = pps_d = 0; 133123015Sphk if (ne == 0) 134123015Sphk echo_a = echo_d = 0; 135123015Sphk#endif 136123015Sphk for (i = 0; i < 32; i++) { 137123015Sphk u = 1 << (i & 0xf); 138123015Sphk if (i >= 16) 139123015Sphk v = 2; 140123015Sphk else 141123015Sphk v = 0; 142123015Sphk if (buf[i] != 'l' && buf[i] != 'L' && led_dev[i] != NULL) { 143123015Sphk led_destroy(led_dev[i]); 144123015Sphk led_dev[i] = NULL; 145123015Sphk elan_mmcr[(0xc2a + v) / 2] &= ~u; 146123015Sphk } 147123015Sphk switch (buf[i]) { 148123015Sphk#ifdef CPU_ELAN_PPS 149123015Sphk case 'P': 150123015Sphk pps_d = u; 151123015Sphk pps_a = 0xc30 + v; 152123015Sphk elan_mmcr[(0xc2a + v) / 2] &= ~u; 153123015Sphk gpio_config[i] = buf[i]; 154123015Sphk break; 155123015Sphk case 'e': 156123015Sphk case 'E': 157123015Sphk echo_d = u; 158123015Sphk if (buf[i] == 'E') 159123015Sphk echo_a = 0xc34 + v; 160123015Sphk else 161123015Sphk echo_a = 0xc38 + v; 162123015Sphk elan_mmcr[(0xc2a + v) / 2] |= u; 163123015Sphk gpio_config[i] = buf[i]; 164123015Sphk break; 165123015Sphk#endif /* CPU_ELAN_PPS */ 166123015Sphk case 'l': 167123015Sphk case 'L': 168123015Sphk if (buf[i] == 'L') 169123015Sphk led_cookie[i] = (0xc34 + v) | (u << 16); 170123015Sphk else 171123015Sphk led_cookie[i] = (0xc38 + v) | (u << 16); 172123015Sphk if (led_dev[i]) 173123015Sphk break; 174123015Sphk sprintf(tmp, "gpio%d", i); 175123015Sphk led_dev[i] = 176123015Sphk led_create(gpio_led, &led_cookie[i], tmp); 177123015Sphk elan_mmcr[(0xc2a + v) / 2] |= u; 178123015Sphk gpio_config[i] = buf[i]; 179123015Sphk break; 180123015Sphk case '.': 181123015Sphk gpio_config[i] = buf[i]; 182123015Sphk break; 183123015Sphk case '-': 184123015Sphk default: 185123015Sphk break; 186123015Sphk } 187123015Sphk } 188123015Sphk return (0); 189123015Sphk} 190123015Sphk 191123015SphkSYSCTL_OID(_machdep, OID_AUTO, elan_gpio_config, CTLTYPE_STRING | CTLFLAG_RW, 192123015Sphk NULL, 0, sysctl_machdep_elan_gpio_config, "A", "Elan CPU GPIO pin config"); 193123015Sphk 194123015Sphk#ifdef CPU_ELAN_PPS 195123015Sphkstatic void 196109327Sphkelan_poll_pps(struct timecounter *tc) 197109327Sphk{ 198109327Sphk static int state; 199109327Sphk int i; 200123015Sphk u_int u; 201109327Sphk 202123015Sphk /* 203123015Sphk * Order is important here. We need to check the state of the GPIO 204123015Sphk * pin first, in order to avoid reading timer 1 right before the 205123015Sphk * state change. Technically pps_a may be zero in which case we 206123015Sphk * harmlessly read the REVID register and the contents of pps_d is 207123015Sphk * of no concern. 208123015Sphk */ 209123015Sphk i = elan_mmcr[pps_a / 2] & pps_d; 210123015Sphk 211123015Sphk /* 212123015Sphk * Subtract timer1 from timer2 to compensate for time from the 213123015Sphk * edge until now. 214123015Sphk */ 215123015Sphk u = elan_mmcr[0xc84 / 2] - elan_mmcr[0xc7c / 2]; 216123015Sphk 217123015Sphk /* If state did not change or we don't have a GPIO pin, return */ 218123015Sphk if (i == state || pps_a == 0) 219109327Sphk return; 220123015Sphk 221109327Sphk state = i; 222123015Sphk 223123015Sphk /* If the state is "low", flip the echo GPIO and return. */ 224123015Sphk if (!i) { 225123015Sphk if (echo_a) 226123015Sphk elan_mmcr[(echo_a ^ 0xc) / 2] = echo_d; 227109327Sphk return; 228123015Sphk } 229123015Sphk 230123015Sphk /* State is "high", record the pps data */ 231109327Sphk pps_capture(&elan_pps); 232123015Sphk elan_pps.capcount = u & 0xffff; 233109327Sphk pps_event(&elan_pps, PPS_CAPTUREASSERT); 234123015Sphk 235123015Sphk /* Twiddle echo bit */ 236123015Sphk if (echo_a) 237123015Sphk elan_mmcr[echo_a / 2] = echo_d; 238109327Sphk} 239123015Sphk#endif /* CPU_ELAN_PPS */ 240109327Sphk 241102935Sphkstatic unsigned 242102935Sphkelan_get_timecount(struct timecounter *tc) 243102935Sphk{ 244123015Sphk 245123015Sphk /* Read timer2, end of story */ 246102935Sphk return (elan_mmcr[0xc84 / 2]); 247102935Sphk} 248102935Sphk 249109327Sphk/* 250109327Sphk * The Elan CPU can be run from a number of clock frequencies, this 251109327Sphk * allows you to override the default 33.3 MHZ. 252109327Sphk */ 253123015Sphk#ifndef CPU_ELAN_XTAL 254123015Sphk#define CPU_ELAN_XTAL 33333333 255109327Sphk#endif 256109327Sphk 257102935Sphkstatic struct timecounter elan_timecounter = { 258102935Sphk elan_get_timecount, 259109327Sphk NULL, 260102935Sphk 0xffff, 261123015Sphk CPU_ELAN_XTAL / 4, 262119715Sphk "ELAN", 263119715Sphk 1000 264102935Sphk}; 265102935Sphk 266109327Sphkstatic int 267109327Sphksysctl_machdep_elan_freq(SYSCTL_HANDLER_ARGS) 268109327Sphk{ 269109327Sphk u_int f; 270109327Sphk int error; 271109327Sphk 272109327Sphk f = elan_timecounter.tc_frequency * 4; 273109327Sphk error = sysctl_handle_int(oidp, &f, sizeof(f), req); 274109327Sphk if (error == 0 && req->newptr != NULL) 275109327Sphk elan_timecounter.tc_frequency = (f + 3) / 4; 276109327Sphk return (error); 277109327Sphk} 278109327Sphk 279109327SphkSYSCTL_PROC(_machdep, OID_AUTO, elan_freq, CTLTYPE_UINT | CTLFLAG_RW, 280109327Sphk 0, sizeof (u_int), sysctl_machdep_elan_freq, "IU", ""); 281109327Sphk 282123015Sphk/* 283123015Sphk * Positively identifying the Elan can only be done through the PCI id of 284123015Sphk * the host-bridge, this function is called from i386/pci/pci_bus.c. 285123015Sphk */ 286102934Sphkvoid 287102934Sphkinit_AMD_Elan_sc520(void) 288102934Sphk{ 289102934Sphk u_int new; 290102934Sphk int i; 291102934Sphk 292102934Sphk elan_mmcr = pmap_mapdev(0xfffef000, 0x1000); 293102934Sphk 294102934Sphk /*- 295102934Sphk * The i8254 is driven with a nonstandard frequency which is 296102934Sphk * derived thusly: 297102934Sphk * f = 32768 * 45 * 25 / 31 = 1189161.29... 298123015Sphk * We use the sysctl to get the i8254 (timecounter etc) into whack. 299102934Sphk */ 300102934Sphk 301102934Sphk new = 1189161; 302102934Sphk i = kernel_sysctlbyname(&thread0, "machdep.i8254_freq", 303123015Sphk NULL, 0, &new, sizeof new, NULL); 304123015Sphk if (bootverbose || 1) 305103168Ssam printf("sysctl machdep.i8254_freq=%d returns %d\n", new, i); 306102935Sphk 307102935Sphk /* Start GP timer #2 and use it as timecounter, hz permitting */ 308123015Sphk elan_mmcr[0xc8e / 2] = 0x0; 309102935Sphk elan_mmcr[0xc82 / 2] = 0xc001; 310109327Sphk 311123015Sphk#ifdef CPU_ELAN_PPS 312109327Sphk /* Set up GP timer #1 as pps counter */ 313109327Sphk elan_mmcr[0xc24 / 2] &= ~0x10; 314109327Sphk elan_mmcr[0xc7a / 2] = 0x8000 | 0x4000 | 0x10 | 0x1; 315123015Sphk elan_mmcr[0xc7e / 2] = 0x0; 316123015Sphk elan_mmcr[0xc80 / 2] = 0x0; 317109327Sphk elan_pps.ppscap |= PPS_CAPTUREASSERT; 318109327Sphk pps_init(&elan_pps); 319109327Sphk#endif 320102935Sphk tc_init(&elan_timecounter); 321102934Sphk} 322102934Sphk 323101225Sphkstatic d_ioctl_t elan_ioctl; 324101225Sphkstatic d_mmap_t elan_mmap; 325101225Sphk 326101225Sphkstatic struct cdevsw elan_cdevsw = { 327111815Sphk .d_ioctl = elan_ioctl, 328111815Sphk .d_mmap = elan_mmap, 329111815Sphk .d_name = "elan", 330101225Sphk}; 331101225Sphk 332103482Sphkstatic void 333103482Sphkelan_drvinit(void) 334101225Sphk{ 335103482Sphk 336123015Sphk /* If no elan found, just return */ 337103482Sphk if (elan_mmcr == NULL) 338103482Sphk return; 339123015Sphk 340123015Sphk printf("Elan-mmcr driver: MMCR at %p.%s\n", 341123015Sphk elan_mmcr, 342123015Sphk#ifdef CPU_ELAN_PPS 343123015Sphk " PPS support." 344123015Sphk#else 345123015Sphk "" 346123015Sphk#endif 347123015Sphk ); 348123015Sphk 349123015Sphk make_dev(&elan_cdevsw, 0, 350103482Sphk UID_ROOT, GID_WHEEL, 0600, "elan-mmcr"); 351121944Sphk 352121944Sphk#ifdef CPU_SOEKRIS 353123015Sphk /* Create the error LED on GPIO9 */ 354123015Sphk led_cookie[9] = 0x02000c34; 355123015Sphk led_dev[9] = led_create(gpio_led, &led_cookie[9], "error"); 356123015Sphk 357123015Sphk /* Disable the unavailable GPIO pins */ 358123015Sphk strcpy(gpio_config, "-----....--..--------..---------"); 359123015Sphk#else /* !CPU_SOEKRIS */ 360123015Sphk /* We don't know which pins are available so enable them all */ 361123015Sphk strcpy(gpio_config, "................................"); 362121944Sphk#endif /* CPU_SOEKRIS */ 363101225Sphk} 364101225Sphk 365121942SphkSYSINIT(elan, SI_SUB_PSEUDO, SI_ORDER_MIDDLE, elan_drvinit, NULL); 366103482Sphk 367101225Sphkstatic int 368112569Sjakeelan_mmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot) 369101225Sphk{ 370103482Sphk 371101225Sphk if (offset >= 0x1000) 372101225Sphk return (-1); 373111462Smux *paddr = 0xfffef000; 374111462Smux return (0); 375101225Sphk} 376101225Sphk 377101225Sphkstatic int 378111647Sphkelan_watchdog(u_int spec) 379111647Sphk{ 380111647Sphk u_int u, v; 381111647Sphk static u_int cur; 382111647Sphk 383111647Sphk if (spec & ~__WD_LEGAL) 384111647Sphk return (EINVAL); 385111647Sphk switch (spec & (WD_ACTIVE|WD_PASSIVE)) { 386111647Sphk case WD_ACTIVE: 387111647Sphk u = spec & WD_INTERVAL; 388111647Sphk if (u > 35) 389111647Sphk return (EINVAL); 390111647Sphk u = imax(u - 5, 24); 391111647Sphk v = 2 << (u - 24); 392111647Sphk v |= 0xc000; 393111647Sphk 394111647Sphk /* 395111647Sphk * There is a bug in some silicon which prevents us from 396111647Sphk * writing to the WDTMRCTL register if the GP echo mode is 397111647Sphk * enabled. GP echo mode on the other hand is desirable 398111647Sphk * for other reasons. Save and restore the GP echo mode 399111647Sphk * around our hardware tom-foolery. 400111647Sphk */ 401111647Sphk u = elan_mmcr[0xc00 / 2]; 402111647Sphk elan_mmcr[0xc00 / 2] = 0; 403111647Sphk if (v != cur) { 404111647Sphk /* Clear the ENB bit */ 405111647Sphk elan_mmcr[0xcb0 / 2] = 0x3333; 406111647Sphk elan_mmcr[0xcb0 / 2] = 0xcccc; 407111647Sphk elan_mmcr[0xcb0 / 2] = 0; 408111647Sphk 409111647Sphk /* Set new value */ 410111647Sphk elan_mmcr[0xcb0 / 2] = 0x3333; 411111647Sphk elan_mmcr[0xcb0 / 2] = 0xcccc; 412111647Sphk elan_mmcr[0xcb0 / 2] = v; 413111647Sphk cur = v; 414111647Sphk } else { 415111647Sphk /* Just reset timer */ 416111647Sphk elan_mmcr[0xcb0 / 2] = 0xaaaa; 417111647Sphk elan_mmcr[0xcb0 / 2] = 0x5555; 418111647Sphk } 419111647Sphk elan_mmcr[0xc00 / 2] = u; 420111647Sphk return (0); 421111647Sphk case WD_PASSIVE: 422111647Sphk return (EOPNOTSUPP); 423111647Sphk case 0: 424111647Sphk u = elan_mmcr[0xc00 / 2]; 425111647Sphk elan_mmcr[0xc00 / 2] = 0; 426111647Sphk elan_mmcr[0xcb0 / 2] = 0x3333; 427111647Sphk elan_mmcr[0xcb0 / 2] = 0xcccc; 428111647Sphk elan_mmcr[0xcb0 / 2] = 0x4080; 429111647Sphk elan_mmcr[0xc00 / 2] = u; 430111647Sphk cur = 0; 431111647Sphk return (0); 432111647Sphk default: 433111647Sphk return (EINVAL); 434111647Sphk } 435111647Sphk 436111647Sphk} 437111647Sphk 438111647Sphkstatic int 439101225Sphkelan_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *tdr) 440101225Sphk{ 441109327Sphk int error; 442109327Sphk 443109327Sphk error = ENOTTY; 444123015Sphk 445123015Sphk#ifdef CPU_ELAN_PPS 446123015Sphk if (pps_a != 0) 447123015Sphk error = pps_ioctl(cmd, arg, &elan_pps); 448109327Sphk /* 449109327Sphk * We only want to incur the overhead of the PPS polling if we 450109327Sphk * are actually asked to timestamp. 451109327Sphk */ 452123015Sphk if (elan_pps.ppsparam.mode & PPS_CAPTUREASSERT) { 453109327Sphk elan_timecounter.tc_poll_pps = elan_poll_pps; 454123015Sphk } else { 455109327Sphk elan_timecounter.tc_poll_pps = NULL; 456123015Sphk } 457109327Sphk if (error != ENOTTY) 458109327Sphk return (error); 459123015Sphk#endif 460109327Sphk 461111647Sphk if (cmd == WDIOCPATPAT) 462111647Sphk return elan_watchdog(*((u_int*)arg)); 463111647Sphk 464109327Sphk /* Other future ioctl handling here */ 465109327Sphk return(error); 466101225Sphk} 467101225Sphk 468