aplpmgr.c revision 1.1
138136Sdfr/* $OpenBSD: aplpmgr.c,v 1.1 2021/12/09 11:38:27 kettenis Exp $ */ 238136Sdfr/* 338136Sdfr * Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org> 438136Sdfr * 538136Sdfr * Permission to use, copy, modify, and distribute this software for any 638136Sdfr * purpose with or without fee is hereby granted, provided that the above 738136Sdfr * copyright notice and this permission notice appear in all copies. 838136Sdfr * 938136Sdfr * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1038136Sdfr * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1138136Sdfr * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1238136Sdfr * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1338136Sdfr * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1438136Sdfr * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1538136Sdfr * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1638136Sdfr */ 1738136Sdfr 1838136Sdfr#include <sys/param.h> 1938136Sdfr#include <sys/systm.h> 2038136Sdfr#include <sys/device.h> 2138136Sdfr#include <sys/malloc.h> 2238136Sdfr 2338136Sdfr#include <machine/bus.h> 2438136Sdfr#include <machine/fdt.h> 2538136Sdfr 2638136Sdfr#include <dev/ofw/openfirm.h> 2738136Sdfr#include <dev/ofw/ofw_misc.h> 2838136Sdfr#include <dev/ofw/ofw_power.h> 2938136Sdfr#include <dev/ofw/fdt.h> 3038136Sdfr 3138136Sdfr#define PMGR_PS_TARGET_MASK 0x0000000f 3238136Sdfr#define PMGR_PS_TARGET_SHIFT 0 3338136Sdfr#define PMGR_PS_ACTUAL_MASK 0x000000f0 3438136Sdfr#define PMGR_PS_ACTUAL_SHIFT 4 3538136Sdfr#define PMGR_PS_ACTIVE 0xf 3638136Sdfr#define PMGR_PS_PWRGATE 0x0 3742333Syokota 3838136Sdfr#define HREAD4(sc, reg) \ 3938136Sdfr (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 4038136Sdfr#define HWRITE4(sc, reg, val) \ 4138136Sdfr bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 4238136Sdfr 4338136Sdfrstruct aplpmgr_softc; 4438136Sdfr 4538136Sdfrstruct aplpmgr_pwrstate { 4638136Sdfr struct aplpmgr_softc *ps_sc; 4738136Sdfr struct power_domain_device ps_pd; 4838136Sdfr bus_size_t ps_offset; 4938136Sdfr}; 5038136Sdfr 5138136Sdfrstruct aplpmgr_softc { 5238136Sdfr struct device sc_dev; 5338136Sdfr bus_space_tag_t sc_iot; 5438136Sdfr bus_space_handle_t sc_ioh; 5538136Sdfr 5638136Sdfr struct aplpmgr_pwrstate *sc_pwrstate; 5738136Sdfr int sc_npwrstate; 5838136Sdfr}; 5938136Sdfr 6038136Sdfrint aplpmgr_match(struct device *, void *, void *); 6138136Sdfrvoid aplpmgr_attach(struct device *, struct device *, void *); 6238136Sdfr 6338136Sdfrconst struct cfattach aplpmgr_ca = { 6438136Sdfr sizeof (struct aplpmgr_softc), aplpmgr_match, aplpmgr_attach 6538136Sdfr}; 6638136Sdfr 6738136Sdfrstruct cfdriver aplpmgr_cd = { 6838136Sdfr NULL, "aplpmgr", DV_DULL 6938136Sdfr}; 7038136Sdfr 7138136Sdfrvoid aplpmgr_enable(void *, uint32_t *, int); 7238136Sdfr 7338136Sdfrint 7438136Sdfraplpmgr_match(struct device *parent, void *match, void *aux) 7538136Sdfr{ 7638136Sdfr struct fdt_attach_args *faa = aux; 7738136Sdfr 7838136Sdfr if (OF_is_compatible(faa->fa_node, "apple,pmgr")) 7938136Sdfr return 10; /* Must beat syscon(4). */ 8038136Sdfr 8138136Sdfr return 0; 8238136Sdfr} 8338136Sdfr 8438136Sdfrvoid 8538136Sdfraplpmgr_attach(struct device *parent, struct device *self, void *aux) 8638136Sdfr{ 8738136Sdfr struct aplpmgr_softc *sc = (struct aplpmgr_softc *)self; 8838136Sdfr struct fdt_attach_args *faa = aux; 8938136Sdfr struct aplpmgr_pwrstate *ps; 9038136Sdfr uint32_t reg[2]; 9138136Sdfr int node; 9238136Sdfr 9338136Sdfr if (faa->fa_nreg < 1) { 9438136Sdfr printf(": no registers\n"); 9538136Sdfr return; 9638136Sdfr } 9738136Sdfr 9838136Sdfr sc->sc_iot = faa->fa_iot; 9938136Sdfr if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 10038136Sdfr faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 10138136Sdfr printf(": can't map registers\n"); 10238136Sdfr return; 10338136Sdfr } 10438136Sdfr 10538136Sdfr printf("\n"); 10638136Sdfr 10738136Sdfr for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) { 10838136Sdfr if (OF_is_compatible(node, "apple,pmgr-pwrstate")) 10938136Sdfr sc->sc_npwrstate++; 11038136Sdfr } 11138136Sdfr 11238136Sdfr sc->sc_pwrstate = mallocarray(sc->sc_npwrstate, 11338136Sdfr sizeof(*sc->sc_pwrstate), M_DEVBUF, M_WAITOK | M_ZERO); 11438136Sdfr 11538136Sdfr ps = sc->sc_pwrstate; 11638136Sdfr for (node = OF_child(faa->fa_node); node; node = OF_peer(node)) { 11738136Sdfr if (!OF_is_compatible(node, "apple,pmgr-pwrstate")) 11838136Sdfr continue; 11938136Sdfr 12038136Sdfr if (OF_getpropintarray(node, "reg", reg, 12138136Sdfr sizeof(reg)) != sizeof(reg)) { 12238136Sdfr printf("%s: invalid reg property\n", 12338136Sdfr sc->sc_dev.dv_xname); 12438136Sdfr continue; 12538136Sdfr } 12638136Sdfr 12738136Sdfr ps->ps_sc = sc; 12838136Sdfr ps->ps_offset = reg[0]; 12938136Sdfr ps->ps_pd.pd_node = node; 13038136Sdfr ps->ps_pd.pd_cookie = ps; 13138136Sdfr ps->ps_pd.pd_enable = aplpmgr_enable; 13238136Sdfr power_domain_register(&ps->ps_pd); 13338136Sdfr ps++; 13438136Sdfr } 13538136Sdfr} 13638136Sdfr 13738136Sdfrvoid 13838136Sdfraplpmgr_enable(void *cookie, uint32_t *cells, int on) 13938136Sdfr{ 14038136Sdfr struct aplpmgr_pwrstate *ps = cookie; 14138136Sdfr struct aplpmgr_softc *sc = ps->ps_sc; 14238136Sdfr uint32_t pstate = on ? PMGR_PS_ACTIVE : PMGR_PS_PWRGATE; 14338136Sdfr uint32_t val; 14438136Sdfr int timo; 14538136Sdfr 14638136Sdfr power_domain_enable_all(ps->ps_pd.pd_node); 14738136Sdfr 14838136Sdfr val = HREAD4(sc, ps->ps_offset); 14938136Sdfr val &= ~PMGR_PS_TARGET_MASK; 15042333Syokota val |= (pstate << PMGR_PS_TARGET_SHIFT); 15138136Sdfr HWRITE4(sc, ps->ps_offset, val); 15238136Sdfr 15338136Sdfr for (timo = 0; timo < 100; timo++) { 15438136Sdfr val = HREAD4(sc, ps->ps_offset); 15538136Sdfr val &= PMGR_PS_ACTUAL_MASK; 15638136Sdfr if ((val >> PMGR_PS_ACTUAL_SHIFT) == pstate) 15738136Sdfr break; 15838136Sdfr delay(1); 15938136Sdfr } 16038136Sdfr} 16142333Syokota