From: kettenis Date: Wed, 2 Mar 2022 12:35:14 +0000 (+0000) Subject: Add nvmem support and make this available on all Apple SPMI PMUs. Restrict X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=fe3bed6a4f7a91b1e4fef86d254056375d52d1ae;p=openbsd Add nvmem support and make this available on all Apple SPMI PMUs. Restrict the RTC interface to the "sera" PMU found on Apple M1 systems. ok patrick@ --- diff --git a/sys/arch/arm64/dev/aplpmu.c b/sys/arch/arm64/dev/aplpmu.c index e0d175ede79..32794c61ab7 100644 --- a/sys/arch/arm64/dev/aplpmu.c +++ b/sys/arch/arm64/dev/aplpmu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aplpmu.c,v 1.3 2022/01/13 08:59:10 kettenis Exp $ */ +/* $OpenBSD: aplpmu.c,v 1.4 2022/03/02 12:35:14 kettenis Exp $ */ /* * Copyright (c) 2021 Mark Kettenis * @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ #include #include #include +#include #include extern void (*cpuresetfn)(void); @@ -51,6 +53,13 @@ extern void (*powerdownfn)(void); #define SERA_POWERDOWN 0x9f0f #define SERA_POWERDOWN_MAGIC 0x08 +struct aplpmu_nvmem { + struct aplpmu_softc *an_sc; + struct nvmem_device an_nd; + bus_addr_t an_base; + bus_size_t an_size; +}; + struct aplpmu_softc { struct device sc_dev; spmi_tag_t sc_tag; @@ -76,13 +85,16 @@ 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_nvmem_read(void *, bus_addr_t, void *, bus_size_t); +int aplpmu_nvmem_write(void *, bus_addr_t, const void *, bus_size_t); int aplpmu_match(struct device *parent, void *match, void *aux) { struct spmi_attach_args *sa = aux; - return OF_is_compatible(sa->sa_node, "apple,sera-pmu"); + return OF_is_compatible(sa->sa_node, "apple,sera-pmu") || + OF_is_compatible(sa->sa_node, "apple,spmi-pmu"); } void @@ -91,28 +103,53 @@ aplpmu_attach(struct device *parent, struct device *self, void *aux) struct aplpmu_softc *sc = (struct aplpmu_softc *)self; struct spmi_attach_args *sa = aux; uint8_t data[8] = {}; - int error; + int error, node; sc->sc_tag = sa->sa_tag; sc->sc_sid = sa->sa_sid; - error = spmi_cmd_read(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_READL, - SERA_TIME_OFFSET, &data, SERA_TIME_LEN); - if (error) { - printf(": can't read offset\n"); - return; + if (OF_is_compatible(sa->sa_node, "apple,sera-pmu")) { + error = spmi_cmd_read(sc->sc_tag, sc->sc_sid, + SPMI_CMD_EXT_READL, SERA_TIME_OFFSET, + &data, SERA_TIME_LEN); + if (error) { + printf(": can't read offset\n"); + return; + } + sc->sc_offset = lemtoh64(data); + + sc->sc_todr.cookie = sc; + 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; } - sc->sc_offset = lemtoh64(data); printf("\n"); - sc->sc_todr.cookie = sc; - 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; + for (node = OF_child(sa->sa_node); node; node = OF_peer(node)) { + struct aplpmu_nvmem *an; + uint32_t reg[2]; + + if (!OF_is_compatible(node, "apple,spmi-pmu-nvmem")) + continue; + + if (OF_getpropintarray(node, "reg", reg, + sizeof(reg)) != sizeof(reg)) + continue; + + an = malloc(sizeof(*an), M_DEVBUF, M_WAITOK); + an->an_sc = sc; + an->an_base = reg[0]; + an->an_size = reg[1]; + an->an_nd.nd_node = node; + an->an_nd.nd_cookie = an; + an->an_nd.nd_read = aplpmu_nvmem_read; + an->an_nd.nd_write = aplpmu_nvmem_write; + nvmem_register(&an->an_nd); + } } int @@ -167,3 +204,30 @@ aplpmu_powerdown(void) cpuresetfn(); } + +int +aplpmu_nvmem_read(void *cookie, bus_addr_t addr, void *data, bus_size_t size) +{ + struct aplpmu_nvmem *an = cookie; + struct aplpmu_softc *sc = an->an_sc; + + if (addr >= an->an_size || addr + size > an->an_size) + return EINVAL; + + return spmi_cmd_read(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_READL, + an->an_base + addr, data, size); +} + +int +aplpmu_nvmem_write(void *cookie, bus_addr_t addr, const void *data, + bus_size_t size) +{ + struct aplpmu_nvmem *an = cookie; + struct aplpmu_softc *sc = an->an_sc; + + if (addr >= an->an_size || addr + size > an->an_size) + return EINVAL; + + return spmi_cmd_write(sc->sc_tag, sc->sc_sid, SPMI_CMD_EXT_WRITEL, + an->an_base + addr, data, size); +}