#include "smc.h"
static int
apple_smc_mmio_wait(device_t dev)
{
struct apple_smc_softc *sc = device_get_softc(dev);
int i, delay_us = 10;
uint8_t status;
for (i = 0; i < ASMC_MMIO_MAX_WAIT; i++) {
status = bus_read_1(sc->sc_iomem, ASMC_MMIO_STATUS);
if (status & ASMC_MMIO_STATUS_READY)
return (0);
DELAY(delay_us);
if (delay_us < 3200)
delay_us *= 2;
}
return (ETIMEDOUT);
}
int
apple_smc_mmio_key_read(device_t dev, const char *key,
uint8_t *buf, uint8_t len)
{
struct apple_smc_softc *sc = device_get_softc(dev);
uint32_t key_int;
int error, i;
uint8_t cmd_result, rlen;
if (len > ASMC_MAXVAL)
return (EINVAL);
SMC_LOCK(sc);
if (bus_read_1(sc->sc_iomem, ASMC_MMIO_STATUS))
bus_write_1(sc->sc_iomem, ASMC_MMIO_STATUS, 0);
memcpy(&key_int, key, 4);
bus_write_4(sc->sc_iomem, ASMC_MMIO_KEY_NAME, key_int);
bus_write_1(sc->sc_iomem, ASMC_MMIO_SMC_ID, 0);
bus_write_1(sc->sc_iomem, ASMC_MMIO_CMD, ASMC_CMDREAD);
error = apple_smc_mmio_wait(dev);
if (error != 0) {
SMC_UNLOCK(sc);
return (error);
}
cmd_result = bus_read_1(sc->sc_iomem, ASMC_MMIO_CMD);
if (cmd_result != 0) {
SMC_UNLOCK(sc);
return (EIO);
}
rlen = bus_read_1(sc->sc_iomem, ASMC_MMIO_DATA_LEN);
if (rlen > len) rlen = len;
for (i = 0; i < rlen; i++)
buf[i] = bus_read_1(sc->sc_iomem, ASMC_MMIO_DATA + i);
SMC_UNLOCK(sc);
return (0);
}
int
apple_smc_mmio_key_write(device_t dev, const char *key,
uint8_t *buf, uint8_t len)
{
struct apple_smc_softc *sc = device_get_softc(dev);
uint32_t key_int;
int error, i;
uint8_t cmd_result;
if (len > ASMC_MAXVAL)
return (EINVAL);
SMC_LOCK(sc);
bus_write_1(sc->sc_iomem, ASMC_MMIO_STATUS, 0);
for (i = 0; i < len; i++)
bus_write_1(sc->sc_iomem, ASMC_MMIO_DATA + i, buf[i]);
memcpy(&key_int, key, 4);
bus_write_4(sc->sc_iomem, ASMC_MMIO_KEY_NAME, key_int);
bus_write_1(sc->sc_iomem, ASMC_MMIO_DATA_LEN, len);
bus_write_1(sc->sc_iomem, ASMC_MMIO_SMC_ID, 0);
bus_write_1(sc->sc_iomem, ASMC_MMIO_CMD, ASMC_CMDWRITE);
error = apple_smc_mmio_wait(dev);
if (error != 0) {
SMC_UNLOCK(sc);
return (error);
}
cmd_result = bus_read_1(sc->sc_iomem, ASMC_MMIO_CMD);
SMC_UNLOCK(sc);
return (cmd_result == 0 ? 0 : EIO);
}
int
apple_smc_mmio_key_getinfo(device_t dev, const char *key,
uint8_t *len, char *type)
{
struct apple_smc_softc *sc = device_get_softc(dev);
uint32_t key_int;
int error, i;
uint8_t cmd_result;
SMC_LOCK(sc);
bus_write_1(sc->sc_iomem, ASMC_MMIO_STATUS, 0);
memcpy(&key_int, key, 4);
bus_write_4(sc->sc_iomem, ASMC_MMIO_KEY_NAME, key_int);
bus_write_1(sc->sc_iomem, ASMC_MMIO_SMC_ID, 0);
bus_write_1(sc->sc_iomem, ASMC_MMIO_CMD, ASMC_CMDGETINFO);
error = apple_smc_mmio_wait(dev);
if (error != 0) {
SMC_UNLOCK(sc);
return (error);
}
cmd_result = bus_read_1(sc->sc_iomem, ASMC_MMIO_CMD);
if (cmd_result != 0) {
SMC_UNLOCK(sc);
return (EIO);
}
if (type != NULL) {
for (i = 0; i < ASMC_TYPELEN; i++)
type[i] = bus_read_1(sc->sc_iomem, ASMC_MMIO_DATA + i);
type[ASMC_TYPELEN] = '\0';
}
if (len != NULL)
*len = bus_read_1(sc->sc_iomem, ASMC_MMIO_DATA + 5);
SMC_UNLOCK(sc);
return (0);
}
int
apple_smc_mmio_key_getbyindex(device_t dev, int index, char *key)
{
struct apple_smc_softc *sc = device_get_softc(dev);
uint32_t idx_val;
int error, i;
uint8_t cmd_result;
SMC_LOCK(sc);
bus_write_1(sc->sc_iomem, ASMC_MMIO_STATUS, 0);
idx_val = htobe32(index);
bus_write_4(sc->sc_iomem, ASMC_MMIO_KEY_NAME, idx_val);
bus_write_1(sc->sc_iomem, ASMC_MMIO_SMC_ID, 0);
bus_write_1(sc->sc_iomem, ASMC_MMIO_CMD, ASMC_CMDGETBYINDEX);
error = apple_smc_mmio_wait(dev);
if (error != 0) {
SMC_UNLOCK(sc);
return (error);
}
cmd_result = bus_read_1(sc->sc_iomem, ASMC_MMIO_CMD);
if (cmd_result != 0) {
SMC_UNLOCK(sc);
return (EIO);
}
for (i = 0; i < ASMC_KEYLEN; i++)
key[i] = bus_read_1(sc->sc_iomem, ASMC_MMIO_DATA + i);
key[ASMC_KEYLEN] = '\0';
SMC_UNLOCK(sc);
return (0);
}
int
apple_smc_try_enable_mmio(device_t dev)
{
struct apple_smc_softc *sc = device_get_softc(dev);
u_long size;
uint8_t status, ldkn, rgen;
int error;
size = rman_get_size(sc->sc_iomem);
if (size < ASMC_MMIO_MIN_SIZE)
return (ENXIO);
status = bus_read_1(sc->sc_iomem, ASMC_MMIO_STATUS);
if (status == 0xFF)
return (ENXIO);
error = apple_smc_mmio_key_read(dev, ASMC_KEY_LDKN, &ldkn, 1);
if (error != 0)
return (ENXIO);
rgen = 0;
error = apple_smc_mmio_key_read(dev, ASMC_KEY_RGEN, &rgen, 1);
if (error != 0) {
device_printf(dev, "MMIO: failed to read RGEN: %d\n", error);
}
sc->sc_is_t2 = (rgen == 3);
device_printf(dev, "MMIO: LDKN=%d%s\n", ldkn,
sc->sc_is_t2 ? ", T2 detected" : "");
return (0);
}