From edff2dd81cf9a806e92f02e05d36e49b65e6d188 Mon Sep 17 00:00:00 2001 From: kettenis Date: Thu, 10 Nov 2022 11:44:06 +0000 Subject: [PATCH] iWe must be careful to only disable power domains that are no longer in use by a device. So maintainer a counter and only disable the power domain if it drops to zero. ok deraadt@, tobhe@ --- sys/arch/arm64/dev/aplpmgr.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/sys/arch/arm64/dev/aplpmgr.c b/sys/arch/arm64/dev/aplpmgr.c index 6b8d46c8d1c..2525a447e6c 100644 --- a/sys/arch/arm64/dev/aplpmgr.c +++ b/sys/arch/arm64/dev/aplpmgr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aplpmgr.c,v 1.2 2022/11/09 16:23:51 kettenis Exp $ */ +/* $OpenBSD: aplpmgr.c,v 1.3 2022/11/10 11:44:06 kettenis Exp $ */ /* * Copyright (c) 2021 Mark Kettenis * @@ -50,6 +50,7 @@ struct aplpmgr_softc; struct aplpmgr_pwrstate { struct aplpmgr_softc *ps_sc; bus_size_t ps_offset; + int ps_enablecount; struct power_domain_device ps_pd; struct reset_device ps_rd; }; @@ -65,6 +66,7 @@ struct aplpmgr_softc { int aplpmgr_match(struct device *, void *, void *); void aplpmgr_attach(struct device *, struct device *, void *); +int aplpmgr_activate(struct device *, int act); const struct cfattach aplpmgr_ca = { sizeof (struct aplpmgr_softc), aplpmgr_match, aplpmgr_attach @@ -133,6 +135,8 @@ aplpmgr_attach(struct device *parent, struct device *self, void *aux) ps->ps_sc = sc; ps->ps_offset = reg[0]; + if (OF_getpropbool(node, "apple,always-on")) + ps->ps_enablecount = 1; ps->ps_pd.pd_node = node; ps->ps_pd.pd_cookie = ps; @@ -157,7 +161,25 @@ aplpmgr_enable(void *cookie, uint32_t *cells, int on) uint32_t val; int timo; - power_domain_enable_all(ps->ps_pd.pd_node); + KASSERT(on || ps->ps_enablecount > 0); + KASSERT(!on || ps->ps_enablecount < INT_MAX); + + if (on && ps->ps_enablecount > 0) { + power_domain_enable_all(ps->ps_pd.pd_node); + ps->ps_enablecount++; + return; + } + if (!on && ps->ps_enablecount > 1) { + power_domain_disable_all(ps->ps_pd.pd_node); + ps->ps_enablecount--; + return; + } + + /* Enable parents before enabling ourselves. */ + if (on) { + power_domain_enable_all(ps->ps_pd.pd_node); + ps->ps_enablecount++; + } val = HREAD4(sc, ps->ps_offset); val &= ~PMGR_PS_TARGET_MASK; @@ -171,6 +193,12 @@ aplpmgr_enable(void *cookie, uint32_t *cells, int on) break; delay(1); } + + /* Disable parents after disabling ourselves. */ + if (!on) { + power_domain_disable_all(ps->ps_pd.pd_node); + ps->ps_enablecount--; + } } void -- 2.20.1