From: kettenis Date: Thu, 13 Jan 2022 08:59:10 +0000 (+0000) Subject: Implement powerdown. This involves writing a magic bit somewhere in the X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=a5505455aa34289baf431f3db58b1893b79fc8b6;p=openbsd Implement powerdown. This involves writing a magic bit somewhere in the address space of the SPMI PMU to prevent the machine from immediately starting up again. The implementaton makes aplpmu(4) provide powerdownfn(), which sets the magic bit and then chains into cpuresetfn(). It also makes aplsmc(4) provide cpuresetfn() to reset the machine via the SMC. Resetting via the watchdog works as well (and will powerdown the machine if the magic bit is set) but letting the SMC handle things might do some other required steps. ok patrick@ --- diff --git a/sys/arch/arm64/dev/apldog.c b/sys/arch/arm64/dev/apldog.c index 0de95db6c43..94d116aaa40 100644 --- a/sys/arch/arm64/dev/apldog.c +++ b/sys/arch/arm64/dev/apldog.c @@ -1,4 +1,4 @@ -/* $OpenBSD: apldog.c,v 1.2 2021/11/13 23:24:24 kettenis Exp $ */ +/* $OpenBSD: apldog.c,v 1.3 2022/01/13 08:59:10 kettenis Exp $ */ /* * Copyright (c) 2021 Mark Kettenis * @@ -100,7 +100,8 @@ apldog_attach(struct device *parent, struct device *self, void *aux) HWRITE4(sc, WDT_SYS_CTL, 0); apldog_sc = sc; - cpuresetfn = apldog_reset; + if (cpuresetfn == NULL) + cpuresetfn = apldog_reset; } void diff --git a/sys/arch/arm64/dev/aplpmu.c b/sys/arch/arm64/dev/aplpmu.c index 943d2bc5372..e0d175ede79 100644 --- a/sys/arch/arm64/dev/aplpmu.c +++ b/sys/arch/arm64/dev/aplpmu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aplpmu.c,v 1.2 2021/05/27 08:10:12 kettenis Exp $ */ +/* $OpenBSD: aplpmu.c,v 1.3 2022/01/13 08:59:10 kettenis Exp $ */ /* * Copyright (c) 2021 Mark Kettenis * @@ -27,6 +27,9 @@ #include #include +extern void (*cpuresetfn)(void); +extern void (*powerdownfn)(void); + /* * This driver is based on preliminary device tree bindings and will * almost certainly need changes once the official bindings land in @@ -45,6 +48,9 @@ #define SERA_TIME_OFFSET 0xd100 #define SERA_TIME_LEN 6 +#define SERA_POWERDOWN 0x9f0f +#define SERA_POWERDOWN_MAGIC 0x08 + struct aplpmu_softc { struct device sc_dev; spmi_tag_t sc_tag; @@ -54,6 +60,8 @@ struct aplpmu_softc { uint64_t sc_offset; }; +struct aplpmu_softc *aplpmu_sc; + int aplpmu_match(struct device *, void *, void *); void aplpmu_attach(struct device *, struct device *, void *); @@ -67,6 +75,7 @@ struct cfdriver aplpmu_cd = { int aplpmu_gettime(struct todr_chip_handle *, struct timeval *); int aplpmu_settime(struct todr_chip_handle *, struct timeval *); +void aplpmu_powerdown(void); int aplpmu_match(struct device *parent, void *match, void *aux) @@ -101,6 +110,9 @@ aplpmu_attach(struct device *parent, struct device *self, void *aux) sc->sc_todr.todr_gettime = aplpmu_gettime; sc->sc_todr.todr_settime = aplpmu_settime; todr_attach(&sc->sc_todr); + + aplpmu_sc = sc; + powerdownfn = aplpmu_powerdown; } int @@ -143,3 +155,15 @@ aplpmu_settime(struct todr_chip_handle *handle, struct timeval *tv) return spmi_cmd_write(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_WRITEL, SERA_TIME_OFFSET, &data, SERA_TIME_LEN); } + +void +aplpmu_powerdown(void) +{ + struct aplpmu_softc *sc = aplpmu_sc; + uint8_t data = SERA_POWERDOWN_MAGIC; + + spmi_cmd_write(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_WRITEL, + SERA_POWERDOWN, &data, sizeof(data)); + + cpuresetfn(); +} diff --git a/sys/arch/arm64/dev/aplsmc.c b/sys/arch/arm64/dev/aplsmc.c index 80f9f52a4c8..b7f1aa4d5bf 100644 --- a/sys/arch/arm64/dev/aplsmc.c +++ b/sys/arch/arm64/dev/aplsmc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aplsmc.c,v 1.5 2022/01/12 15:05:38 robert Exp $ */ +/* $OpenBSD: aplsmc.c,v 1.6 2022/01/13 08:59:10 kettenis Exp $ */ /* * Copyright (c) 2021 Mark Kettenis * @@ -33,6 +33,8 @@ #include "apm.h" +extern void (*cpuresetfn)(void); + #define SMC_EP 32 #define SMC_READ_KEY 0x10 @@ -85,7 +87,9 @@ struct aplsmc_softc { struct ksensor sc_sensors[APLSMC_MAX_SENSORS]; int sc_nsensors; struct ksensordev sc_sensordev; -} *aplsmc_sc; +}; + +struct aplsmc_softc *aplsmc_sc; struct aplsmc_sensor aplsmc_sensors[] = { { "ACDI", "ui16", SENSOR_INDICATOR, 1, "power supply" }, @@ -182,6 +186,7 @@ int aplsmc_send_cmd(struct aplsmc_softc *, uint16_t, uint32_t, uint16_t); int aplsmc_wait_cmd(struct aplsmc_softc *sc); int aplsmc_read_key(struct aplsmc_softc *, uint32_t, void *, size_t); void aplsmc_refresh_sensors(void *); +void aplsmc_reset(void); int aplsmc_match(struct device *parent, void *match, void *aux) @@ -286,6 +291,7 @@ aplsmc_attach(struct device *parent, struct device *self, void *aux) sensor_task_register(sc, aplsmc_refresh_sensors, 5); aplsmc_sc = sc; + cpuresetfn = aplsmc_reset; #if NAPM > 0 apm_setinfohook(aplsmc_apminfo); @@ -423,3 +429,18 @@ aplsmc_refresh_sensors(void *arg) hw_power = (value > 0); } } + +void +aplsmc_reset(void) +{ + struct aplsmc_softc *sc = aplsmc_sc; + uint32_t key = SMC_KEY("MBSE"); + uint32_t data = SMC_KEY("off1"); + + bus_space_write_region_1(sc->sc_iot, sc->sc_sram_ioh, 0, + (uint8_t *)&data, sizeof(data)); + bus_space_barrier(sc->sc_iot, sc->sc_sram_ioh, 0, sizeof(data), + BUS_SPACE_BARRIER_WRITE); + aplsmc_send_cmd(sc, SMC_WRITE_KEY, key, sizeof(data)); + aplsmc_wait_cmd(sc); +}