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