1*9fdf0c62Smpi /* $OpenBSD: imxgpc.c,v 1.10 2021/10/24 17:52:26 mpi Exp $ */
2242dcb92Spatrick /*
3242dcb92Spatrick * Copyright (c) 2016 Mark Kettenis
4242dcb92Spatrick *
5242dcb92Spatrick * Permission to use, copy, modify, and distribute this software for any
6242dcb92Spatrick * purpose with or without fee is hereby granted, provided that the above
7242dcb92Spatrick * copyright notice and this permission notice appear in all copies.
8242dcb92Spatrick *
9242dcb92Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10242dcb92Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11242dcb92Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12242dcb92Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13242dcb92Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14242dcb92Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15242dcb92Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16242dcb92Spatrick */
17242dcb92Spatrick
18242dcb92Spatrick #include <sys/param.h>
19242dcb92Spatrick #include <sys/systm.h>
20242dcb92Spatrick #include <sys/device.h>
214abb65b9Spatrick #include <sys/malloc.h>
22242dcb92Spatrick
234abb65b9Spatrick #if defined(__arm64__)
244abb65b9Spatrick #include <machine/cpufunc.h>
254abb65b9Spatrick #endif
26242dcb92Spatrick #include <machine/fdt.h>
27242dcb92Spatrick
28242dcb92Spatrick #include <dev/ofw/openfirm.h>
294abb65b9Spatrick #include <dev/ofw/ofw_power.h>
304abb65b9Spatrick
314abb65b9Spatrick #define FSL_SIP_GPC 0xc2000000
324abb65b9Spatrick #define FSL_SIP_CONFIG_GPC_PM_DOMAIN 0x03
33242dcb92Spatrick
34242dcb92Spatrick struct imxgpc_softc {
35242dcb92Spatrick struct device sc_dev;
36242dcb92Spatrick struct interrupt_controller sc_ic;
374abb65b9Spatrick
384abb65b9Spatrick int sc_npd;
394abb65b9Spatrick struct power_domain_device *sc_pd;
40242dcb92Spatrick };
41242dcb92Spatrick
42242dcb92Spatrick int imxgpc_match(struct device *, void *, void *);
43242dcb92Spatrick void imxgpc_attach(struct device *, struct device *, void *);
444abb65b9Spatrick void imxgpc_enable(void *, uint32_t *, int);
45242dcb92Spatrick
46*9fdf0c62Smpi const struct cfattach imxgpc_ca = {
47242dcb92Spatrick sizeof(struct imxgpc_softc), imxgpc_match, imxgpc_attach
48242dcb92Spatrick };
49242dcb92Spatrick
50242dcb92Spatrick struct cfdriver imxgpc_cd = {
51242dcb92Spatrick NULL, "imxgpc", DV_DULL
52242dcb92Spatrick };
53242dcb92Spatrick
54242dcb92Spatrick int
imxgpc_match(struct device * parent,void * match,void * aux)55242dcb92Spatrick imxgpc_match(struct device *parent, void *match, void *aux)
56242dcb92Spatrick {
57242dcb92Spatrick struct fdt_attach_args *faa = aux;
58242dcb92Spatrick
592c00674cSpatrick return (OF_is_compatible(faa->fa_node, "fsl,imx6q-gpc") ||
60db133697Skettenis OF_is_compatible(faa->fa_node, "fsl,imx7d-gpc") ||
61529b42b2Spatrick OF_is_compatible(faa->fa_node, "fsl,imx8mm-gpc") ||
62dcf7f918Spatrick OF_is_compatible(faa->fa_node, "fsl,imx8mp-gpc") ||
632c00674cSpatrick OF_is_compatible(faa->fa_node, "fsl,imx8mq-gpc"));
64242dcb92Spatrick }
65242dcb92Spatrick
66242dcb92Spatrick void
imxgpc_attach(struct device * parent,struct device * self,void * aux)67242dcb92Spatrick imxgpc_attach(struct device *parent, struct device *self, void *aux)
68242dcb92Spatrick {
69242dcb92Spatrick struct fdt_attach_args *faa = aux;
70242dcb92Spatrick struct imxgpc_softc *sc = (struct imxgpc_softc *)self;
714abb65b9Spatrick int i, node, list;
72242dcb92Spatrick
73242dcb92Spatrick sc->sc_ic.ic_node = faa->fa_node;
74242dcb92Spatrick sc->sc_ic.ic_cookie = &sc->sc_ic;
7570e69ae2Spatrick sc->sc_ic.ic_establish = fdt_intr_parent_establish;
7670e69ae2Spatrick sc->sc_ic.ic_disestablish = fdt_intr_parent_disestablish;
77452daaedSpatrick sc->sc_ic.ic_barrier = intr_barrier;
7870e69ae2Spatrick fdt_intr_register(&sc->sc_ic);
79242dcb92Spatrick
80242dcb92Spatrick printf("\n");
814abb65b9Spatrick
82529b42b2Spatrick if (OF_is_compatible(faa->fa_node, "fsl,imx8mm-gpc") ||
83dcf7f918Spatrick OF_is_compatible(faa->fa_node, "fsl,imx8mp-gpc") ||
84529b42b2Spatrick OF_is_compatible(faa->fa_node, "fsl,imx8mq-gpc")) {
854abb65b9Spatrick list = OF_child(faa->fa_node);
864abb65b9Spatrick if (!list)
874abb65b9Spatrick return;
884abb65b9Spatrick for (node = OF_child(list); node; node = OF_peer(node))
894abb65b9Spatrick sc->sc_npd++;
904abb65b9Spatrick if (!sc->sc_npd)
914abb65b9Spatrick return;
924abb65b9Spatrick sc->sc_pd = mallocarray(sc->sc_npd, sizeof(*sc->sc_pd),
934abb65b9Spatrick M_DEVBUF, M_WAITOK);
944abb65b9Spatrick for (node = OF_child(list), i = 0; node;
954abb65b9Spatrick node = OF_peer(node), i++){
964abb65b9Spatrick sc->sc_pd[i].pd_node = node;
974abb65b9Spatrick sc->sc_pd[i].pd_cookie = &sc->sc_pd[i];
984abb65b9Spatrick sc->sc_pd[i].pd_enable = imxgpc_enable;
994abb65b9Spatrick power_domain_register(&sc->sc_pd[i]);
1004abb65b9Spatrick }
1014abb65b9Spatrick }
1024abb65b9Spatrick }
1034abb65b9Spatrick
1044abb65b9Spatrick void
imxgpc_enable(void * cookie,uint32_t * cells,int on)1054abb65b9Spatrick imxgpc_enable(void *cookie, uint32_t *cells, int on)
1064abb65b9Spatrick {
1074abb65b9Spatrick #if defined(__arm64__)
1084abb65b9Spatrick struct power_domain_device *pd = cookie;
1094abb65b9Spatrick int domain;
1104abb65b9Spatrick
1113cc1f9efSpatrick power_domain_enable(pd->pd_node);
1123cc1f9efSpatrick
1134abb65b9Spatrick domain = OF_getpropint(pd->pd_node, "reg", 0);
1144abb65b9Spatrick
1154abb65b9Spatrick /* Set up power domain */
1164abb65b9Spatrick smc_call(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN,
1174abb65b9Spatrick domain, on);
1184abb65b9Spatrick #endif
119242dcb92Spatrick }
120