/* * Retrieve the raw value from OPAL. This will be cooked by the sysctl handler. */ static int opal_sensor_get_val(uint32_t key, uint64_t *val) { struct opal_msg msg; uint32_t val32; int i, rv; rv = opal_call(OPAL_SENSOR_READ, key, key, vtophys(&val32)); if (rv == OPAL_ASYNC_COMPLETION) { /* Sleep a little to let things settle. */ DELAY(100); bzero(&msg, sizeof(msg)); i = 0; do { rv = opal_call(OPAL_CHECK_ASYNC_COMPLETION, vtophys(&msg), sizeof(msg), key); /* Sleep for ~100us if necessary. */ if (rv == OPAL_BUSY) DELAY(100); } while (rv == OPAL_BUSY && ++i < 10); if (rv != OPAL_SUCCESS) return (EIO); val32 = msg.params[0]; } if (rv != OPAL_SUCCESS) return (EIO); *val = val32; return (0); }
static int opal_settime(device_t dev, struct timespec *ts) { int rv; struct clocktime ct; uint32_t ymd = 0; uint64_t hmsm = 0; clock_ts_to_ct(ts, &ct); ymd |= (uint32_t)bin2bcd(ct.day); ymd |= ((uint32_t)bin2bcd(ct.mon) << 8); ymd |= ((uint32_t)bin2bcd32(ct.year) << 16); hmsm |= ((uint64_t)bin2bcd32(ct.nsec/1000) << 16); hmsm |= ((uint64_t)bin2bcd(ct.sec) << 40); hmsm |= ((uint64_t)bin2bcd(ct.min) << 48); hmsm |= ((uint64_t)bin2bcd(ct.hour) << 56); hmsm = htobe64(hmsm); ymd = htobe32(ymd); do { rv = opal_call(OPAL_RTC_WRITE, vtophys(&ymd), vtophys(&hmsm)); if (rv == OPAL_BUSY_EVENT) { rv = opal_call(OPAL_POLL_EVENTS, 0); pause("opalrtc", 1); } } while (rv == OPAL_BUSY_EVENT); if (rv != OPAL_SUCCESS) return (ENXIO); return (0); }
static int opal_gettime(device_t dev, struct timespec *ts) { int rv; struct clocktime ct; uint32_t ymd; uint64_t hmsm; do { rv = opal_call(OPAL_RTC_READ, vtophys(&ymd), vtophys(&hmsm)); if (rv == OPAL_BUSY_EVENT) { rv = opal_call(OPAL_POLL_EVENTS, 0); pause("opalrtc", 1); } } while (rv == OPAL_BUSY_EVENT); if (rv != OPAL_SUCCESS) return (ENXIO); hmsm = be64toh(hmsm); ymd = be32toh(ymd); ct.nsec = bcd2bin32((hmsm & 0x000000ffffff0000) >> 16) * 1000; ct.sec = bcd2bin((hmsm & 0x0000ff0000000000) >> 40); ct.min = bcd2bin((hmsm & 0x00ff000000000000) >> 48); ct.hour = bcd2bin((hmsm & 0xff00000000000000) >> 56); ct.day = bcd2bin((ymd & 0x000000ff) >> 0); ct.mon = bcd2bin((ymd & 0x0000ff00) >> 8); ct.year = bcd2bin32((ymd & 0xffff0000) >> 16); return (clock_ct_to_ts(&ct, ts)); }
static void opal_shutdown(void *arg, int howto) { if (howto & RB_HALT) opal_call(OPAL_CEC_POWER_DOWN, 0 /* Normal power off */); else opal_call(OPAL_CEC_REBOOT); opal_call(OPAL_RETURN_CPU); }
static int opaldev_attach(device_t dev) { phandle_t child; device_t cdev; uint64_t junk; int i, rv; struct ofw_bus_devinfo *dinfo; struct resource *irq; /* Test for RTC support and register clock if it works */ rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); do { rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); if (rv == OPAL_BUSY_EVENT) rv = opal_call(OPAL_POLL_EVENTS, 0); } while (rv == OPAL_BUSY_EVENT); if (rv == OPAL_SUCCESS) clock_register(dev, 2000); EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL, SHUTDOWN_PRI_LAST); /* Bind to interrupts */ for (i = 0; (irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE)) != NULL; i++) bus_setup_intr(dev, irq, INTR_TYPE_TTY | INTR_MPSAFE | INTR_ENTROPY, NULL, opal_intr, (void *)rman_get_start(irq), NULL); for (child = OF_child(ofw_bus_get_node(dev)); child != 0; child = OF_peer(child)) { dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_WAITOK | M_ZERO); if (ofw_bus_gen_setup_devinfo(dinfo, child) != 0) { free(dinfo, M_DEVBUF); continue; } cdev = device_add_child(dev, NULL, -1); if (cdev == NULL) { device_printf(dev, "<%s>: device_add_child failed\n", dinfo->obd_name); ofw_bus_gen_destroy_devinfo(dinfo); free(dinfo, M_DEVBUF); continue; } device_set_ivars(cdev, dinfo); } return (bus_generic_attach(dev)); }
static int opalflash_erase(struct opalflash_softc *sc, off_t off, off_t count) { struct opal_msg msg; int rv, token; /* Ensure we write aligned to a full block size. */ if (off % sc->sc_disk->d_stripesize != 0 || count % sc->sc_disk->d_stripesize != 0) return (EIO); token = opal_alloc_async_token(); rv = opal_call(OPAL_FLASH_ERASE, sc->sc_opal_id, off, count, token); if (rv == OPAL_ASYNC_COMPLETION) { rv = opal_wait_completion(&msg, sizeof(msg), token); if (rv == OPAL_SUCCESS) rv = msg.params[1]; } opal_free_async_token(token); if (rv == OPAL_SUCCESS) rv = 0; else rv = EIO; return (rv); }
static void opal_intr(void *xintr) { uint64_t events = 0; opal_call(OPAL_HANDLE_INTERRUPT, (uint32_t)(uint64_t)xintr, vtophys(&events)); /* XXX: do something useful with this information */ }
static int opalflash_write(struct opalflash_softc *sc, off_t off, caddr_t data, off_t count) { struct opal_msg msg; int rv, size, token; /* Ensure we write aligned to a full block size. */ if (off % sc->sc_disk->d_sectorsize != 0 || count % sc->sc_disk->d_sectorsize != 0) return (EIO); if (sc->sc_erase) { /* Erase the full block first, then write in page chunks. */ rv = opalflash_erase(sc, off, count); if (rv != 0) return (rv); } token = opal_alloc_async_token(); /* * Write one page at a time. It's not guaranteed that the buffer is * physically contiguous. */ while (count > 0) { size = MIN(count, PAGE_SIZE); size = MIN(size, PAGE_SIZE - ((u_long)data & PAGE_MASK)); rv = opal_call(OPAL_FLASH_WRITE, sc->sc_opal_id, off, vtophys(data), size, token); if (rv == OPAL_ASYNC_COMPLETION) { rv = opal_wait_completion(&msg, sizeof(msg), token); if (rv == OPAL_SUCCESS) rv = msg.params[1]; } if (rv != OPAL_SUCCESS) break; count -= size; off += size; data += size; } opal_free_async_token(token); if (rv == OPAL_SUCCESS) rv = 0; else rv = EIO; return (rv); }