summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2021-12-09 11:38:28 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2021-12-09 11:38:28 +0000
commite846909d6f222c0607c89e54a31962989ff556bc (patch)
tree6390cf1400fce7ea04d43b5150ce77167f44f43f /sys
parent473c1f4b40cf51d15220e6bc594106da03817ee8 (diff)
Add aplpmgr(4), a driver for the power management controller found on
various Apple SoCs. ok patrick@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/arm64/conf/GENERIC3
-rw-r--r--sys/arch/arm64/conf/RAMDISK3
-rw-r--r--sys/arch/arm64/conf/files.arm646
-rw-r--r--sys/arch/arm64/dev/aplns.c5
-rw-r--r--sys/arch/arm64/dev/aplpcie.c4
-rw-r--r--sys/arch/arm64/dev/aplpmgr.c160
6 files changed, 176 insertions, 5 deletions
diff --git a/sys/arch/arm64/conf/GENERIC b/sys/arch/arm64/conf/GENERIC
index 81c61fb9737..f231c2bb2e3 100644
--- a/sys/arch/arm64/conf/GENERIC
+++ b/sys/arch/arm64/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.215 2021/12/03 19:16:29 uaa Exp $
+# $OpenBSD: GENERIC,v 1.216 2021/12/09 11:38:26 kettenis Exp $
#
# GENERIC machine description file
#
@@ -145,6 +145,7 @@ aplintc* at fdt? early 1
aplpcie* at fdt?
pci* at aplpcie?
aplpinctrl* at fdt? early 1
+aplpmgr* at fdt? early 1
aplspi* at fdt?
aplhidev* at spi?
aplkbd* at aplhidev?
diff --git a/sys/arch/arm64/conf/RAMDISK b/sys/arch/arm64/conf/RAMDISK
index d63ade906b6..46ec65e080e 100644
--- a/sys/arch/arm64/conf/RAMDISK
+++ b/sys/arch/arm64/conf/RAMDISK
@@ -1,4 +1,4 @@
-# $OpenBSD: RAMDISK,v 1.161 2021/11/22 20:25:50 kettenis Exp $
+# $OpenBSD: RAMDISK,v 1.162 2021/12/09 11:38:26 kettenis Exp $
machine arm64
maxusers 4
@@ -109,6 +109,7 @@ aplintc* at fdt? early 1
aplpcie* at fdt?
pci* at aplpcie?
aplpinctrl* at fdt? early 1
+aplpmgr* at fdt? early 1
aplspi* at fdt?
aplhidev* at spi?
aplkbd* at aplhidev?
diff --git a/sys/arch/arm64/conf/files.arm64 b/sys/arch/arm64/conf/files.arm64
index 139df931cca..be12fd6edd9 100644
--- a/sys/arch/arm64/conf/files.arm64
+++ b/sys/arch/arm64/conf/files.arm64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.arm64,v 1.46 2021/11/01 09:02:46 kettenis Exp $
+# $OpenBSD: files.arm64,v 1.47 2021/12/09 11:38:26 kettenis Exp $
maxpartitions 16
maxusers 2 8 128
@@ -168,6 +168,10 @@ device aplpinctrl
attach aplpinctrl at fdt
file arch/arm64/dev/aplpinctrl.c aplpinctrl
+device aplpmgr
+attach aplpmgr at fdt
+file arch/arm64/dev/aplpmgr.c aplpmgr
+
# Apple NVME Storage
device aplns {}
attach aplns at fdt
diff --git a/sys/arch/arm64/dev/aplns.c b/sys/arch/arm64/dev/aplns.c
index 52cb2a63f45..11c16805e36 100644
--- a/sys/arch/arm64/dev/aplns.c
+++ b/sys/arch/arm64/dev/aplns.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aplns.c,v 1.5 2021/08/29 11:23:29 kettenis Exp $ */
+/* $OpenBSD: aplns.c,v 1.6 2021/12/09 11:38:27 kettenis Exp $ */
/*
* Copyright (c) 2014, 2021 David Gwynne <dlg@openbsd.org>
*
@@ -31,6 +31,7 @@
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_misc.h>
+#include <dev/ofw/ofw_power.h>
#include <dev/ofw/fdt.h>
#include <scsi/scsi_all.h>
@@ -165,6 +166,8 @@ nvme_ans_attach(struct device *parent, struct device *self, void *aux)
return;
}
+ power_domain_enable(faa->fa_node);
+
sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
nvme_intr, sc, sc->sc_dev.dv_xname);
if (sc->sc_ih == NULL) {
diff --git a/sys/arch/arm64/dev/aplpcie.c b/sys/arch/arm64/dev/aplpcie.c
index 69d43d0f259..7480307646b 100644
--- a/sys/arch/arm64/dev/aplpcie.c
+++ b/sys/arch/arm64/dev/aplpcie.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aplpcie.c,v 1.8 2021/11/01 20:22:12 kettenis Exp $ */
+/* $OpenBSD: aplpcie.c,v 1.9 2021/12/09 11:38:27 kettenis Exp $ */
/*
* Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
*
@@ -32,6 +32,7 @@
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_misc.h>
#include <dev/ofw/ofw_pinctrl.h>
+#include <dev/ofw/ofw_power.h>
#include <dev/ofw/fdt.h>
/*
@@ -174,6 +175,7 @@ aplpcie_attach(struct device *parent, struct device *self, void *aux)
sc->sc_dmat = faa->fa_dmat;
sc->sc_node = faa->fa_node;
+ power_domain_enable(sc->sc_node);
pinctrl_byname(sc->sc_node, "default");
sc->sc_msi_doorbell =
diff --git a/sys/arch/arm64/dev/aplpmgr.c b/sys/arch/arm64/dev/aplpmgr.c
new file mode 100644
index 00000000000..b858b028d5b
--- /dev/null
+++ b/sys/arch/arm64/dev/aplpmgr.c
@@ -0,0 +1,160 @@
+/* $OpenBSD: aplpmgr.c,v 1.1 2021/12/09 11:38:27 kettenis Exp $ */
+/*
+ * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <machine/fdt.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_misc.h>
+#include <dev/ofw/ofw_power.h>
+#include <dev/ofw/fdt.h>
+
+#define PMGR_PS_TARGET_MASK 0x0000000f
+#define PMGR_PS_TARGET_SHIFT 0
+#define PMGR_PS_ACTUAL_MASK 0x000000f0
+#define PMGR_PS_ACTUAL_SHIFT 4
+#define PMGR_PS_ACTIVE 0xf
+#define PMGR_PS_PWRGATE 0x0
+
+#define HREAD4(sc, reg) \
+ (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+
+struct aplpmgr_softc;
+
+struct aplpmgr_pwrstate {
+ struct aplpmgr_softc *ps_sc;
+ struct power_domain_device ps_pd;
+ bus_size_t ps_offset;
+};
+
+struct aplpmgr_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+
+ struct aplpmgr_pwrstate *sc_pwrstate;
+ int sc_npwrstate;
+};
+
+int aplpmgr_match(struct device *, void *, void *);
+void aplpmgr_attach(struct device *, struct device *, void *);
+
+const struct cfattach aplpmgr_ca = {
+ sizeof (struct aplpmgr_softc), aplpmgr_match, aplpmgr_attach
+};
+
+struct cfdriver aplpmgr_cd = {
+ NULL, "aplpmgr", DV_DULL
+};
+
+void aplpmgr_enable(void *, uint32_t *, int);
+
+int
+aplpmgr_match(struct device *parent, void *match, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ if (OF_is_compatible(faa->fa_node, "apple,pmgr"))
+ return 10; /* Must beat syscon(4). */
+
+ return 0;
+}
+
+void
+aplpmgr_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct aplpmgr_softc *sc = (struct aplpmgr_softc *)self;
+ struct fdt_attach_args *faa = aux;
+ struct aplpmgr_pwrstate *ps;
+ uint32_t reg[2];
+ int node;
+
+ if (faa->fa_nreg < 1) {
+ printf(": no registers\n");
+ return;
+ }
+
+ sc->sc_iot = faa->fa_iot;
+ if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
+ faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
+ printf(": can't map registers\n");
+ return;
+ }
+
+ printf("\n");
+
+ for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) {
+ if (OF_is_compatible(node, "apple,pmgr-pwrstate"))
+ sc->sc_npwrstate++;
+ }
+
+ sc->sc_pwrstate = mallocarray(sc->sc_npwrstate,
+ sizeof(*sc->sc_pwrstate), M_DEVBUF, M_WAITOK | M_ZERO);
+
+ ps = sc->sc_pwrstate;
+ for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) {
+ if (!OF_is_compatible(node, "apple,pmgr-pwrstate"))
+ continue;
+
+ if (OF_getpropintarray(node, "reg", reg,
+ sizeof(reg)) != sizeof(reg)) {
+ printf("%s: invalid reg property\n",
+ sc->sc_dev.dv_xname);
+ continue;
+ }
+
+ ps->ps_sc = sc;
+ ps->ps_offset = reg[0];
+ ps->ps_pd.pd_node = node;
+ ps->ps_pd.pd_cookie = ps;
+ ps->ps_pd.pd_enable = aplpmgr_enable;
+ power_domain_register(&ps->ps_pd);
+ ps++;
+ }
+}
+
+void
+aplpmgr_enable(void *cookie, uint32_t *cells, int on)
+{
+ struct aplpmgr_pwrstate *ps = cookie;
+ struct aplpmgr_softc *sc = ps->ps_sc;
+ uint32_t pstate = on ? PMGR_PS_ACTIVE : PMGR_PS_PWRGATE;
+ uint32_t val;
+ int timo;
+
+ power_domain_enable_all(ps->ps_pd.pd_node);
+
+ val = HREAD4(sc, ps->ps_offset);
+ val &= ~PMGR_PS_TARGET_MASK;
+ val |= (pstate << PMGR_PS_TARGET_SHIFT);
+ HWRITE4(sc, ps->ps_offset, val);
+
+ for (timo = 0; timo < 100; timo++) {
+ val = HREAD4(sc, ps->ps_offset);
+ val &= PMGR_PS_ACTUAL_MASK;
+ if ((val >> PMGR_PS_ACTUAL_SHIFT) == pstate)
+ break;
+ delay(1);
+ }
+}