1 /* $OpenBSD: mbg.c,v 1.27 2008/11/23 14:19:40 mbalmer 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/proc.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 sc->sc_timedelta.value = 0LL; 212 sc->sc_timedelta.flags = 0; 213 sensor_attach(&sc->sc_sensordev, &sc->sc_timedelta); 214 215 sc->sc_signal.type = SENSOR_PERCENT; 216 sc->sc_signal.status = SENSOR_S_UNKNOWN; 217 sc->sc_signal.value = 0LL; 218 sc->sc_signal.flags = 0; 219 strlcpy(sc->sc_signal.desc, "Signal", sizeof(sc->sc_signal.desc)); 220 sensor_attach(&sc->sc_sensordev, &sc->sc_signal); 221 222 t_trust = 12 * 60 * 60; /* twelve hours */ 223 224 switch (PCI_PRODUCT(pa->pa_id)) { 225 case PCI_PRODUCT_MEINBERG_PCI32: 226 sc->sc_read = mbg_read_amcc_s5933; 227 sensor_task_register(sc, mbg_task, 10); 228 break; 229 case PCI_PRODUCT_MEINBERG_PCI509: 230 /* 231 * map the second I/O region needed in addition to the first 232 * to get at the actual data. 233 */ 234 memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, 235 PCI_MAPREG_START + 0x04); 236 if (pci_mapreg_map(pa, PCI_MAPREG_START + 0x04, memtype, 0, 237 &sc->sc_iot_s5920, &sc->sc_ioh_s5920, NULL, &iosize2, 0)) { 238 printf(": PCI2 %s region not found\n", 239 memtype == PCI_MAPREG_TYPE_IO ? "I/O" : "memory"); 240 241 /* unmap first mapped region as well if we fail */ 242 bus_space_unmap(sc->sc_iot, sc->sc_ioh, iosize); 243 return; 244 } 245 sc->sc_read = mbg_read_amcc_s5920; 246 sensor_task_register(sc, mbg_task, 10); 247 break; 248 case PCI_PRODUCT_MEINBERG_PCI511: 249 case PCI_PRODUCT_MEINBERG_PEX511: 250 sc->sc_read = mbg_read_asic; 251 sensor_task_register(sc, mbg_task, 10); 252 break; 253 case PCI_PRODUCT_MEINBERG_GPS170PCI: 254 t_trust = 4 * 24 * 60 * 60; /* four days */ 255 sc->sc_read = mbg_read_asic; 256 sensor_task_register(sc, mbg_task_hr, 1); 257 break; 258 default: 259 /* this can not normally happen, but then there is murphy */ 260 panic(": unsupported product 0x%04x", PCI_PRODUCT(pa->pa_id)); 261 break; 262 } 263 264 sc->sc_trust = t_trust; 265 266 if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, 267 sizeof(struct mbg_time), NULL)) { 268 printf(": unknown status"); 269 sc->sc_signal.status = SENSOR_S_CRIT; 270 } else { 271 sc->sc_signal.status = SENSOR_S_OK; 272 signal = tframe.signal - MBG_SIG_BIAS; 273 if (signal < 0) 274 signal = 0; 275 else if (signal > MBG_SIG_MAX) 276 signal = MBG_SIG_MAX; 277 sc->sc_signal.value = signal; 278 279 if (tframe.status & MBG_SYNC) 280 printf(": synchronized"); 281 else 282 printf(": not synchronized"); 283 if (tframe.status & MBG_FREERUN) { 284 sc->sc_signal.status = SENSOR_S_WARN; 285 printf(", free running"); 286 } 287 if (tframe.status & MBG_IFTM) 288 printf(", time set from host"); 289 } 290 #ifdef MBG_DEBUG 291 if (sc->sc_read(sc, MBG_GET_FW_ID_1, fw_id, MBG_FIFO_LEN, NULL) || 292 sc->sc_read(sc, MBG_GET_FW_ID_2, &fw_id[MBG_FIFO_LEN], MBG_FIFO_LEN, 293 NULL)) 294 printf(", firmware unknown"); 295 else { 296 fw_id[MBG_ID_LEN - 1] = '\0'; 297 printf(", firmware %s", fw_id); 298 } 299 #endif 300 printf("\n"); 301 sensordev_install(&sc->sc_sensordev); 302 timeout_add_sec(&sc->sc_timeout, sc->sc_trust); 303 } 304 305 /* 306 * mbg_task() reads a timestamp from cards that to not provide a high 307 * resolution timestamp. The precision is limited to 1/100 sec. 308 */ 309 void 310 mbg_task(void *arg) 311 { 312 struct mbg_softc *sc = (struct mbg_softc *)arg; 313 struct mbg_time tframe; 314 struct clock_ymdhms ymdhms; 315 struct timespec tstamp; 316 int64_t timedelta; 317 time_t trecv; 318 319 if (sc->sc_read(sc, MBG_GET_TIME, (char *)&tframe, sizeof(tframe), 320 &tstamp)) { 321 sc->sc_signal.status = SENSOR_S_CRIT; 322 return; 323 } 324 if (tframe.status & MBG_INVALID) { 325 sc->sc_signal.status = SENSOR_S_CRIT; 326 return; 327 } 328 ymdhms.dt_year = tframe.year + 2000; 329 ymdhms.dt_mon = tframe.mon; 330 ymdhms.dt_day = tframe.mday; 331 ymdhms.dt_hour = tframe.hour; 332 ymdhms.dt_min = tframe.min; 333 ymdhms.dt_sec = tframe.sec; 334 trecv = clock_ymdhms_to_secs(&ymdhms) - tframe.utc_off * 3600; 335 336 timedelta = (int64_t)((tstamp.tv_sec - trecv) * 100 337 - tframe.hundreds) * 10000000LL + tstamp.tv_nsec; 338 339 mbg_update_sensor(sc, &tstamp, timedelta, tframe.signal, 340 (u_int16_t)tframe.status); 341 } 342 343 /* 344 * mbg_task_hr() reads a timestamp from cards that do provide a high 345 * resolution timestamp. 346 */ 347 void 348 mbg_task_hr(void *arg) 349 { 350 struct mbg_softc *sc = (struct mbg_softc *)arg; 351 struct mbg_time_hr tframe; 352 struct timespec tstamp; 353 int64_t tlocal, trecv; 354 355 if (sc->sc_read(sc, MBG_GET_TIME_HR, (char *)&tframe, sizeof(tframe), 356 &tstamp)) { 357 sc->sc_signal.status = SENSOR_S_CRIT; 358 return; 359 } 360 if (tframe.status & MBG_INVALID) { 361 sc->sc_signal.status = SENSOR_S_CRIT; 362 return; 363 } 364 365 tlocal = tstamp.tv_sec * NSECPERSEC + tstamp.tv_nsec; 366 trecv = letoh32(tframe.sec) * NSECPERSEC + 367 (letoh32(tframe.frac) * NSECPERSEC >> 32); 368 369 mbg_update_sensor(sc, &tstamp, tlocal - trecv, tframe.signal, 370 letoh16(tframe.status)); 371 } 372 373 /* update the sensor value, common to all cards */ 374 void 375 mbg_update_sensor(struct mbg_softc *sc, struct timespec *tstamp, 376 int64_t timedelta, u_int8_t rsignal, u_int16_t status) 377 { 378 int signal; 379 380 sc->sc_timedelta.value = timedelta; 381 sc->sc_timedelta.tv.tv_sec = tstamp->tv_sec; 382 sc->sc_timedelta.tv.tv_usec = tstamp->tv_nsec / 1000; 383 384 signal = rsignal - MBG_SIG_BIAS; 385 if (signal < 0) 386 signal = 0; 387 else if (signal > MBG_SIG_MAX) 388 signal = MBG_SIG_MAX; 389 390 sc->sc_signal.value = signal * 100000 / MBG_SIG_MAX; 391 sc->sc_signal.status = status & MBG_FREERUN ? 392 SENSOR_S_WARN : SENSOR_S_OK; 393 sc->sc_signal.tv.tv_sec = sc->sc_timedelta.tv.tv_sec; 394 sc->sc_signal.tv.tv_usec = sc->sc_timedelta.tv.tv_usec; 395 if (!(status & MBG_FREERUN)) { 396 sc->sc_timedelta.status = SENSOR_S_OK; 397 timeout_add_sec(&sc->sc_timeout, sc->sc_trust); 398 } 399 } 400 401 /* 402 * send a command and read back results to an AMCC S5920 based card 403 * (e.g. the PCI509 DCF77 radio clock) 404 */ 405 int 406 mbg_read_amcc_s5920(struct mbg_softc *sc, int cmd, char *buf, size_t len, 407 struct timespec *tstamp) 408 { 409 long timer, tmax; 410 size_t quot, rem; 411 u_int32_t ul; 412 int n; 413 u_int8_t status; 414 415 quot = len / 4; 416 rem = len % 4; 417 418 /* write the command, optionally taking a timestamp */ 419 if (tstamp) 420 nanotime(tstamp); 421 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB, cmd); 422 423 /* wait for the BUSY flag to go low (approx 70 us on i386) */ 424 timer = 0; 425 tmax = cold ? 50 : hz / 10; 426 do { 427 if (cold) 428 delay(20); 429 else 430 tsleep(tstamp, 0, "mbg", 1); 431 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 432 AMCC_IMB4 + 3); 433 } while ((status & MBG_BUSY) && timer++ < tmax); 434 435 if (status & MBG_BUSY) 436 return -1; 437 438 /* read data from the device */ 439 if (len) { 440 for (n = 0; n < quot; n++) { 441 *(u_int32_t *)buf = bus_space_read_4(sc->sc_iot_s5920, 442 sc->sc_ioh_s5920, AMCC_DATA); 443 buf += sizeof(u_int32_t); 444 } 445 if (rem) { 446 ul = bus_space_read_4(sc->sc_iot_s5920, 447 sc->sc_ioh_s5920, AMCC_DATA); 448 for (n = 0; n < rem; n++) 449 *buf++ = *((char *)&ul + n); 450 } 451 } else 452 bus_space_read_4(sc->sc_iot_s5920, sc->sc_ioh_s5920, AMCC_DATA); 453 return 0; 454 } 455 456 /* 457 * send a command and read back results to an AMCC S5933 based card 458 * (e.g. the PCI32 DCF77 radio clock) 459 */ 460 int 461 mbg_read_amcc_s5933(struct mbg_softc *sc, int cmd, char *buf, size_t len, 462 struct timespec *tstamp) 463 { 464 long timer, tmax; 465 size_t n; 466 u_int8_t status; 467 468 /* reset inbound mailbox and clear FIFO status */ 469 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_MCSR + 3, 0x0c); 470 471 /* set FIFO */ 472 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_INTCSR + 3, 0x3c); 473 474 /* write the command, optionally taking a timestamp */ 475 if (tstamp) 476 nanotime(tstamp); 477 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMCC_OMB1, cmd); 478 479 /* wait for the BUSY flag to go low (approx 70 us on i386) */ 480 timer = 0; 481 tmax = cold ? 50 : hz / 10; 482 do { 483 if (cold) 484 delay(20); 485 else 486 tsleep(tstamp, 0, "mbg", 1); 487 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 488 AMCC_IMB4 + 3); 489 } while ((status & MBG_BUSY) && timer++ < tmax); 490 491 if (status & MBG_BUSY) 492 return -1; 493 494 /* read data from the device FIFO */ 495 for (n = 0; n < len; n++) { 496 if (bus_space_read_2(sc->sc_iot, sc->sc_ioh, AMCC_MCSR) 497 & 0x20) { 498 return -1; 499 } 500 buf[n] = bus_space_read_1(sc->sc_iot, sc->sc_ioh, 501 AMCC_FIFO + (n % 4)); 502 } 503 return 0; 504 } 505 506 /* 507 * send a command and read back results to an ASIC based card 508 * (e.g. the PCI511 DCF77 radio clock) 509 */ 510 int 511 mbg_read_asic(struct mbg_softc *sc, int cmd, char *buf, size_t len, 512 struct timespec *tstamp) 513 { 514 long timer, tmax; 515 size_t n; 516 u_int32_t data; 517 u_int16_t port; 518 char *p = buf; 519 u_int8_t status; 520 int s; 521 522 /* write the command, optionally taking a timestamp */ 523 if (tstamp) { 524 s = splhigh(); 525 nanotime(tstamp); 526 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd); 527 splx(s); 528 } else 529 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ASIC_DATA, cmd); 530 531 /* wait for the BUSY flag to go low */ 532 timer = 0; 533 tmax = cold ? 50 : hz / 10; 534 do { 535 if (cold) 536 delay(20); 537 else 538 tsleep(tstamp, 0, "mbg", 1); 539 status = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ASIC_STATUS); 540 } while ((status & MBG_BUSY) && timer++ < tmax); 541 542 if (status & MBG_BUSY) 543 return -1; 544 545 /* read data from the device FIFO */ 546 port = ASIC_ADDON; 547 for (n = 0; n < len / 4; n++) { 548 data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port); 549 *(u_int32_t *)p = data; 550 p += sizeof(data); 551 port += sizeof(data); 552 } 553 554 if (len % 4) { 555 data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, port); 556 for (n = 0; n < len % 4; n++) { 557 *p++ = data & 0xff; 558 data >>= 8; 559 } 560 } 561 return 0; 562 } 563 564 /* 565 * degrade the sensor state if we are feerunning for more than 566 * sc->sc_trust seconds. 567 */ 568 void 569 mbg_timeout(void *xsc) 570 { 571 struct mbg_softc *sc = xsc; 572 573 if (sc->sc_timedelta.status == SENSOR_S_OK) { 574 sc->sc_timedelta.status = SENSOR_S_WARN; 575 /* 576 * further degrade in sc->sc_trust seconds if no new valid 577 * time data can be read from the device. 578 */ 579 timeout_add_sec(&sc->sc_timeout, sc->sc_trust); 580 } else 581 sc->sc_timedelta.status = SENSOR_S_CRIT; 582 } 583