1 /* $OpenBSD: mbg.c,v 1.29 2010/04/08 00:23:53 tedu Exp $ */ 2 3 /* 4 * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/param.h> 21 #include <sys/device.h> 22 #include <sys/kernel.h> 23 #include <sys/timeout.h> 24 #include <sys/systm.h> 25 #include <sys/sensors.h> 26 #include <sys/syslog.h> 27 #include <sys/time.h> 28 29 #include <machine/bus.h> 30 31 #include <dev/pci/pcivar.h> 32 #include <dev/pci/pcireg.h> 33 #include <dev/pci/pcidevs.h> 34 35 struct mbg_softc { 36 struct device sc_dev; 37 bus_space_tag_t sc_iot; 38 bus_space_handle_t sc_ioh; 39 40 /* 41 * I/O region used by the AMCC S5920 found on the PCI509 card 42 * used to access the data. 43 */ 44 bus_space_tag_t sc_iot_s5920; 45 bus_space_handle_t sc_ioh_s5920; 46 47 struct ksensor sc_timedelta; 48 struct ksensor sc_signal; 49 struct ksensordev sc_sensordev; 50 struct timeout sc_timeout; /* invalidate sensor */ 51 int sc_trust; /* trust time in seconds */ 52 53 int (*sc_read)(struct mbg_softc *, int cmd, 54 char *buf, size_t len, 55 struct timespec *tstamp); 56 }; 57 58 struct mbg_time { 59 u_int8_t hundreds; 60 u_int8_t sec; 61 u_int8_t min; 62 u_int8_t hour; 63 u_int8_t mday; 64 u_int8_t wday; /* 1 (monday) - 7 (sunday) */ 65 u_int8_t mon; 66 u_int8_t year; /* 0 - 99 */ 67 u_int8_t status; 68 u_int8_t signal; 69 int8_t utc_off; 70 }; 71 72 struct mbg_time_hr { 73 u_int32_t sec; /* always UTC */ 74 u_int32_t frac; /* fractions of second */ 75 int32_t utc_off; /* informal only, in seconds */ 76 u_int16_t status; 77 u_int8_t signal; 78 }; 79 80 /* mbg_time.status bits */ 81 #define MBG_FREERUN 0x01 /* clock running on xtal */ 82 #define MBG_DST_ENA 0x02 /* DST enabled */ 83 #define MBG_SYNC 0x04 /* clock synced at least once */ 84 #define MBG_DST_CHG 0x08 /* DST change announcement */ 85 #define MBG_UTC 0x10 /* special UTC firmware is installed */ 86 #define MBG_LEAP 0x20 /* announcement of a leap second */ 87 #define MBG_IFTM 0x40 /* current time was set from host */ 88 #define MBG_INVALID 0x80 /* time invalid, batt. was disconn. */ 89 90 /* AMCC S5920 registers */ 91 #define AMCC_DATA 0x00 /* data register, on 2nd IO region */ 92 #define AMCC_OMB 0x0c /* outgoing mailbox */ 93 #define AMCC_IMB 0x1c /* incoming mailbox */ 94 95 /* AMCC S5933 registers */ 96 #define AMCC_OMB1 0x00 /* outgoing mailbox 1 */ 97 #define AMCC_IMB4 0x1c /* incoming mailbox 4 */ 98 #define AMCC_FIFO 0x20 /* FIFO register */ 99 #define AMCC_INTCSR 0x38 /* interrupt control/status register */ 100 #define AMCC_MCSR 0x3c /* master control/status register */ 101 102 /* ASIC registers */ 103 #define ASIC_CFG 0x00 104 #define ASIC_FEATURES 0x08 /* r/o */ 105 #define ASIC_STATUS 0x10 106 #define ASIC_CTLSTATUS 0x14 107 #define ASIC_DATA 0x18 108 #define ASIC_RES1 0x1c 109 #define ASIC_ADDON 0x20 110 111 /* commands */ 112 #define MBG_GET_TIME 0x00 113 #define MBG_GET_SYNC_TIME 0x02 114 #define MBG_GET_TIME_HR 0x03 115 #define MBG_SET_TIME 0x10 116 #define MBG_GET_TZCODE 0x32 117 #define MBG_SET_TZCODE 0x33 118 #define MBG_GET_FW_ID_1 0x40 119 #define MBG_GET_FW_ID_2 0x41 120 #define MBG_GET_SERNUM 0x42 121 122 /* timezone codes (for MBG_{GET|SET}_TZCODE) */ 123 #define MBG_TZCODE_CET_CEST 0x00 124 #define MBG_TZCODE_CET 0x01 125 #define MBG_TZCODE_UTC 0x02 126 #define MBG_TZCODE_EET_EEST 0x03 127 128 /* misc. constants */ 129 #define MBG_FIFO_LEN 16 130 #define MBG_ID_LEN (2 * MBG_FIFO_LEN + 1) 131 #define MBG_BUSY 0x01 132 #define MBG_SIG_BIAS 55 133 #define MBG_SIG_MAX 68 134 #define NSECPERSEC 1000000000LL /* nanoseconds per second */ 135 #define HRDIVISOR 0x100000000LL /* for hi-res timestamp */ 136 137 int mbg_probe(struct device *, void *, void *); 138 void mbg_attach(struct device *, struct device *, void *); 139 void mbg_task(void *); 140 void mbg_task_hr(void *); 141 void mbg_update_sensor(struct mbg_softc *sc, struct timespec *tstamp, 142 int64_t timedelta, u_int8_t rsignal, u_int16_t status); 143 int mbg_read_amcc_s5920(struct mbg_softc *, int cmd, char *buf, size_t len, 144 struct timespec *tstamp); 145 int mbg_read_amcc_s5933(struct mbg_softc *, int cmd, char *buf, size_t len, 146 struct timespec *tstamp); 147 int mbg_read_asic(struct mbg_softc *, int cmd, char *buf, size_t len, 148 struct timespec *tstamp); 149 void mbg_timeout(void *); 150 151 struct cfattach mbg_ca = { 152 sizeof(struct mbg_softc), mbg_probe, mbg_attach 153 }; 154 155 struct cfdriver mbg_cd = { 156 NULL, "mbg", DV_DULL 157 }; 158 159 const struct pci_matchid mbg_devices[] = { 160 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_GPS170PCI }, 161 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI32 }, 162 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI509 }, 163 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PCI511 }, 164 { PCI_VENDOR_MEINBERG, PCI_PRODUCT_MEINBERG_PEX511 } 165 }; 166 167 int 168 mbg_probe(struct device *parent, void *match, void *aux) 169 { 170 return pci_matchbyid((struct pci_attach_args *)aux, mbg_devices, 171 nitems(mbg_devices)); 172 } 173 174 void 175 mbg_attach(struct device *parent, struct device *self, void *aux) 176 { 177 struct mbg_softc *sc = (struct mbg_softc *)self; 178 struct pci_attach_args *const pa = (struct pci_attach_args *)aux; 179 struct mbg_time tframe; 180 pcireg_t memtype; 181 bus_size_t iosize, iosize2; 182 int bar = PCI_MAPREG_START, signal, t_trust; 183 const char *desc; 184 #ifdef MBG_DEBUG 185 char fw_id[MBG_ID_LEN]; 186 #endif 187 188 timeout_set(&sc->sc_timeout, mbg_timeout, sc); 189 190 /* for the PEX511 use BAR2 instead of BAR0*/ 191 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_MEINBERG_PEX511) 192 bar += 0x08; 193 194 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, bar); 195 if (pci_mapreg_map(pa, bar, memtype, 0, &sc->sc_iot, 196 &sc->sc_ioh, NULL, &iosize, 0)) { 197 printf(": PCI %s region not found\n", 198 memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory"); 199 return; 200 } 201 202 if ((desc = pci_findproduct(pa->pa_id)) == NULL) 203 desc = "Radio clock"; 204 strlcpy(sc->sc_timedelta.desc, desc, sizeof(sc->sc_timedelta.desc)); 205 206 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 207 sizeof(sc->sc_sensordev.xname)); 208 209 sc->sc_timedelta.type = SENSOR_TIMEDELTA; 210 sc->sc_timedelta.status = SENSOR_S_UNKNOWN; 211 sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta); 212 213 sc->sc_signal.type = SENSOR_PERCENT; 214 sc->sc_signal.status = SENSOR_S_UNKNOWN; 215 strlcpy(sc->sc_signal.desc, "Signal", sizeof(sc->sc_signal.desc)); 216 sensor_attach(&sc->sc_sensordev, &sc->sc_signal); 217 218 t_trust = 12 * 60 * 60; /* twelve hours */ 219 220 switch (PCI_PRODUCT(pa->pa_id)) { 221 case PCI_PRODUCT_MEINBERG_PCI32: 222 sc->sc_read = mbg_read_amcc_s5933; 223 sensor_task_register(sc, mbg_task, 10); 224 break; 225 case PCI_PRODUCT_MEINBERG_PCI509: 226 /* 227 * map the second I/O region needed in addition to the first 228 * to get at the actual data. 229 */ 230 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, 231 PCI_MAPREG_START + 0x04); 232 if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x04, memtype, 0, 233 &sc->sc_iot_s5920, &sc->sc_ioh_s5920, NULL, &iosize2, 0)) { 234 printf(": PCI2 %s region not found\n", 235 memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory"); 236 237 /* unmap first mapped region as well if we fail */ 238 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 239 return; 240 } 241 sc->sc_read = mbg_read_amcc_s5920; 242 sensor_task_register(sc, mbg_task, 10); 243 break; 244 case PCI_PRODUCT_MEINBERG_PCI511: 245 case PCI_PRODUCT_MEINBERG_PEX511: 246 sc->sc_read = mbg_read_asic; 247 sensor_task_register(sc, mbg_task, 10); 248 break; 249 case PCI_PRODUCT_MEINBERG_GPS170PCI: 250 t_trust = 4 * 24 * 60 * 60; /* four days */ 251 sc->sc_read = mbg_read_asic; 252 sensor_task_register(sc, mbg_task_hr, 1); 253 break; 254 default: 255 /* this can not normally happen, but then there is murphy */ 256 panic(": unsupported product 0x%04x", PCI_PRODUCT(pa->pa_id)); 257 break; 258 } 259 260 sc->sc_trust = t_trust; 261 262 if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, 263 sizeof(struct mbg_time), NULL)) { 264 printf(": unknown status"); 265 sc->sc_signal.status = SENSOR_S_CRIT; 266 } else { 267 sc->sc_signal.status = SENSOR_S_OK; 268 signal = tframe.signal - MBG_SIG_BIAS; 269 if (signal < 0) 270 signal = 0; 271 else if (signal > MBG_SIG_MAX) 272 signal = MBG_SIG_MAX; 273 sc->sc_signal.value = signal; 274 275 if (tframe.status & MBG_SYNC) 276 printf(": synchronized"); 277 else 278 printf(": not synchronized"); 279 if (tframe.status & MBG_FREERUN) { 280 sc->sc_signal.status = SENSOR_S_WARN; 281 printf(", free running"); 282 } 283 if (tframe.status & MBG_IFTM) 284 printf(", time set from host"); 285 } 286 #ifdef MBG_DEBUG 287 if (sc->sc_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) || 288 sc->sc_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN, 289 NULL)) 290 printf(", firmware unknown"); 291 else { 292 fw_id[MBG_ID_LEN - 1] = '\0'; 293 printf(", firmware %s", fw_id); 294 } 295 #endif 296 printf("\n"); 297 sensordev_install(&sc->sc_sensordev); 298 timeout_add_sec(&sc->sc_timeout, sc->sc_trust); 299 } 300 301 /* 302 * mbg_task() reads a timestamp from cards that to not provide a high 303 * resolution timestamp. The precision is limited to 1/100 sec. 304 */ 305 void 306 mbg_task(void *arg) 307 { 308 struct mbg_softc *sc = (struct mbg_softc *)arg; 309 struct mbg_time tframe; 310 struct clock_ymdhms ymdhms; 311 struct timespec tstamp; 312 int64_t timedelta; 313 time_t trecv; 314 315 if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, sizeof(tframe), 316 &tstamp)) { 317 sc->sc_signal.status = SENSOR_S_CRIT; 318 return; 319 } 320 if (tframe.status & MBG_INVALID) { 321 sc->sc_signal.status = SENSOR_S_CRIT; 322 return; 323 } 324 ymdhms.dt_year = tframe.year + 2000; 325 ymdhms.dt_mon = tframe.mon; 326 ymdhms.dt_day = tframe.mday; 327 ymdhms.dt_hour = tframe.hour; 328 ymdhms.dt_min = tframe.min; 329 ymdhms.dt_sec = tframe.sec; 330 trecv = clock_ymdhms_to_secs(&ymdhms) - tframe.utc_off * 3600; 331 332 timedelta = (int64_t)((tstamp.tv_sec - trecv) * 100 333 - tframe.hundreds) * 10000000LL + tstamp.tv_nsec; 334 335 mbg_update_sensor(sc, &tstamp, timedelta, tframe.signal, 336 (u_int16_t)tframe.status); 337 } 338 339 /* 340 * mbg_task_hr() reads a timestamp from cards that do provide a high 341 * resolution timestamp. 342 */ 343 void 344 mbg_task_hr(void *arg) 345 { 346 struct mbg_softc *sc = (struct mbg_softc *)arg; 347 struct mbg_time_hr tframe; 348 struct timespec tstamp; 349 int64_t tlocal, trecv; 350 351 if (sc->sc_read(sc, MBG_GET_TIME_HR, (char *)&tframe, sizeof(tframe), 352 &tstamp)) { 353 sc->sc_signal.status = SENSOR_S_CRIT; 354 return; 355 } 356 if (tframe.status & MBG_INVALID) { 357 sc->sc_signal.status = SENSOR_S_CRIT; 358 return; 359 } 360 361 tlocal = tstamp.tv_sec * NSECPERSEC + tstamp.tv_nsec; 362 trecv = letoh32(tframe.sec) * NSECPERSEC + 363 (letoh32(tframe.frac) * NSECPERSEC >> 32); 364 365 mbg_update_sensor(sc, &tstamp, tlocal - trecv, tframe.signal, 366 letoh16(tframe.status)); 367 } 368 369 /* update the sensor value, common to all cards */ 370 void 371 mbg_update_sensor(struct mbg_softc *sc, struct timespec *tstamp, 372 int64_t timedelta, u_int8_t rsignal, u_int16_t status) 373 { 374 int signal; 375 376 sc->sc_timedelta.value = timedelta; 377 sc->sc_timedelta.tv.tv_sec = tstamp->tv_sec; 378 sc->sc_timedelta.tv.tv_usec = tstamp->tv_nsec / 1000; 379 380 signal = rsignal - MBG_SIG_BIAS; 381 if (signal < 0) 382 signal = 0; 383 else if (signal > MBG_SIG_MAX) 384 signal = MBG_SIG_MAX; 385 386 sc->sc_signal.value = signal * 100000 / MBG_SIG_MAX; 387 sc->sc_signal.status = status & MBG_FREERUN ? 388 SENSOR_S_WARN : SENSOR_S_OK; 389 sc->sc_signal.tv.tv_sec = sc->sc_timedelta.tv.tv_sec; 390 sc->sc_signal.tv.tv_usec = sc->sc_timedelta.tv.tv_usec; 391 if (!(status & MBG_FREERUN)) { 392 sc->sc_timedelta.status = SENSOR_S_OK; 393 timeout_add_sec(&sc->sc_timeout, sc->sc_trust); 394 } 395 } 396 397 /* 398 * send a command and read back results to an AMCC S5920 based card 399 * (e.g. the PCI509 DCF77 radio clock) 400 */ 401 int 402 mbg_read_amcc_s5920(struct mbg_softc *sc, int cmd, char *buf, size_t len, 403 struct timespec *tstamp) 404 { 405 long timer, tmax; 406 size_t quot, rem; 407 u_int32_t ul; 408 int n; 409 u_int8_t status; 410 411 quot = len / 4; 412 rem = len % 4; 413 414 /* write the command, optionally taking a timestamp */ 415 if (tstamp) 416 nanotime(tstamp); 417 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB, cmd); 418 419 /* wait for the BUSY flag to go low (approx 70 us on i386) */ 420 timer = 0; 421 tmax = cold ? 50 : hz / 10; 422 do { 423 if (cold) 424 delay(20); 425 else 426 tsleep(tstamp, 0, "mbg", 1); 427 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 428 AMCC_IMB4 + 3); 429 } while ((status & MBG_BUSY) && timer++ < tmax); 430 431 if (status & MBG_BUSY) 432 return -1; 433 434 /* read data from the device */ 435 if (len) { 436 for (n = 0; n < quot; n++) { 437 *(u_int32_t *)buf = bus_space_read_4(sc->sc_iot_s5920, 438 sc->sc_ioh_s5920, AMCC_DATA); 439 buf += sizeof(u_int32_t); 440 } 441 if (rem) { 442 ul = bus_space_read_4(sc->sc_iot_s5920, 443 sc->sc_ioh_s5920, AMCC_DATA); 444 for (n = 0; n < rem; n++) 445 *buf++ = *((char *)&ul + n); 446 } 447 } else 448 bus_space_read_4(sc->sc_iot_s5920, sc->sc_ioh_s5920, AMCC_DATA); 449 return 0; 450 } 451 452 /* 453 * send a command and read back results to an AMCC S5933 based card 454 * (e.g. the PCI32 DCF77 radio clock) 455 */ 456 int 457 mbg_read_amcc_s5933(struct mbg_softc *sc, int cmd, char *buf, size_t len, 458 struct timespec *tstamp) 459 { 460 long timer, tmax; 461 size_t n; 462 u_int8_t status; 463 464 /* reset inbound mailbox and clear FIFO status */ 465 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_MCSR + 3, 0x0c); 466 467 /* set FIFO */ 468 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_INTCSR + 3, 0x3c); 469 470 /* write the command, optionally taking a timestamp */ 471 if (tstamp) 472 nanotime(tstamp); 473 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB1, cmd); 474 475 /* wait for the BUSY flag to go low (approx 70 us on i386) */ 476 timer = 0; 477 tmax = cold ? 50 : hz / 10; 478 do { 479 if (cold) 480 delay(20); 481 else 482 tsleep(tstamp, 0, "mbg", 1); 483 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 484 AMCC_IMB4 + 3); 485 } while ((status & MBG_BUSY) && timer++ < tmax); 486 487 if (status & MBG_BUSY) 488 return -1; 489 490 /* read data from the device FIFO */ 491 for (n = 0; n < len; n++) { 492 if (bus_space_read_2(sc->sc_iot, sc->sc_ioh, AMCC_MCSR) 493 & 0x20) { 494 return -1; 495 } 496 buf[n] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 497 AMCC_FIFO + (n % 4)); 498 } 499 return 0; 500 } 501 502 /* 503 * send a command and read back results to an ASIC based card 504 * (e.g. the PCI511 DCF77 radio clock) 505 */ 506 int 507 mbg_read_asic(struct mbg_softc *sc, int cmd, char *buf, size_t len, 508 struct timespec *tstamp) 509 { 510 long timer, tmax; 511 size_t n; 512 u_int32_t data; 513 u_int16_t port; 514 char *p = buf; 515 u_int8_t status; 516 int s; 517 518 /* write the command, optionally taking a timestamp */ 519 if (tstamp) { 520 s = splhigh(); 521 nanotime(tstamp); 522 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd); 523 splx(s); 524 } else 525 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd); 526 527 /* wait for the BUSY flag to go low */ 528 timer = 0; 529 tmax = cold ? 50 : hz / 10; 530 do { 531 if (cold) 532 delay(20); 533 else 534 tsleep(tstamp, 0, "mbg", 1); 535 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASIC_STATUS); 536 } while ((status & MBG_BUSY) && timer++ < tmax); 537 538 if (status & MBG_BUSY) 539 return -1; 540 541 /* read data from the device FIFO */ 542 port = ASIC_ADDON; 543 for (n = 0; n < len / 4; n++) { 544 data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port); 545 *(u_int32_t *)p = data; 546 p += sizeof(data); 547 port += sizeof(data); 548 } 549 550 if (len % 4) { 551 data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port); 552 for (n = 0; n < len % 4; n++) { 553 *p++ = data & 0xff; 554 data >>= 8; 555 } 556 } 557 return 0; 558 } 559 560 /* 561 * degrade the sensor state if we are feerunning for more than 562 * sc->sc_trust seconds. 563 */ 564 void 565 mbg_timeout(void *xsc) 566 { 567 struct mbg_softc *sc = xsc; 568 569 if (sc->sc_timedelta.status == SENSOR_S_OK) { 570 sc->sc_timedelta.status = SENSOR_S_WARN; 571 /* 572 * further degrade in sc->sc_trust seconds if no new valid 573 * time data can be read from the device. 574 */ 575 timeout_add_sec(&sc->sc_timeout, sc->sc_trust); 576 } else 577 sc->sc_timedelta.status = SENSOR_S_CRIT; 578 } 579