1 /* $OpenBSD: imxgpc.c,v 1.10 2021/10/24 17:52:26 mpi Exp $ */
2 /*
3 * Copyright (c) 2016 Mark Kettenis
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/malloc.h>
22
23 #if defined(__arm64__)
24 #include <machine/cpufunc.h>
25 #endif
26 #include <machine/fdt.h>
27
28 #include <dev/ofw/openfirm.h>
29 #include <dev/ofw/ofw_power.h>
30
31 #define FSL_SIP_GPC 0xc2000000
32 #define FSL_SIP_CONFIG_GPC_PM_DOMAIN 0x03
33
34 struct imxgpc_softc {
35 struct device sc_dev;
36 struct interrupt_controller sc_ic;
37
38 int sc_npd;
39 struct power_domain_device *sc_pd;
40 };
41
42 int imxgpc_match(struct device *, void *, void *);
43 void imxgpc_attach(struct device *, struct device *, void *);
44 void imxgpc_enable(void *, uint32_t *, int);
45
46 const struct cfattach imxgpc_ca = {
47 sizeof(struct imxgpc_softc), imxgpc_match, imxgpc_attach
48 };
49
50 struct cfdriver imxgpc_cd = {
51 NULL, "imxgpc", DV_DULL
52 };
53
54 int
imxgpc_match(struct device * parent,void * match,void * aux)55 imxgpc_match(struct device *parent, void *match, void *aux)
56 {
57 struct fdt_attach_args *faa = aux;
58
59 return (OF_is_compatible(faa->fa_node, "fsl,imx6q-gpc") ||
60 OF_is_compatible(faa->fa_node, "fsl,imx7d-gpc") ||
61 OF_is_compatible(faa->fa_node, "fsl,imx8mm-gpc") ||
62 OF_is_compatible(faa->fa_node, "fsl,imx8mp-gpc") ||
63 OF_is_compatible(faa->fa_node, "fsl,imx8mq-gpc"));
64 }
65
66 void
imxgpc_attach(struct device * parent,struct device * self,void * aux)67 imxgpc_attach(struct device *parent, struct device *self, void *aux)
68 {
69 struct fdt_attach_args *faa = aux;
70 struct imxgpc_softc *sc = (struct imxgpc_softc *)self;
71 int i, node, list;
72
73 sc->sc_ic.ic_node = faa->fa_node;
74 sc->sc_ic.ic_cookie = &sc->sc_ic;
75 sc->sc_ic.ic_establish = fdt_intr_parent_establish;
76 sc->sc_ic.ic_disestablish = fdt_intr_parent_disestablish;
77 sc->sc_ic.ic_barrier = intr_barrier;
78 fdt_intr_register(&sc->sc_ic);
79
80 printf("\n");
81
82 if (OF_is_compatible(faa->fa_node, "fsl,imx8mm-gpc") ||
83 OF_is_compatible(faa->fa_node, "fsl,imx8mp-gpc") ||
84 OF_is_compatible(faa->fa_node, "fsl,imx8mq-gpc")) {
85 list = OF_child(faa->fa_node);
86 if (!list)
87 return;
88 for (node = OF_child(list); node; node = OF_peer(node))
89 sc->sc_npd++;
90 if (!sc->sc_npd)
91 return;
92 sc->sc_pd = mallocarray(sc->sc_npd, sizeof(*sc->sc_pd),
93 M_DEVBUF, M_WAITOK);
94 for (node = OF_child(list), i = 0; node;
95 node = OF_peer(node), i++){
96 sc->sc_pd[i].pd_node = node;
97 sc->sc_pd[i].pd_cookie = &sc->sc_pd[i];
98 sc->sc_pd[i].pd_enable = imxgpc_enable;
99 power_domain_register(&sc->sc_pd[i]);
100 }
101 }
102 }
103
104 void
imxgpc_enable(void * cookie,uint32_t * cells,int on)105 imxgpc_enable(void *cookie, uint32_t *cells, int on)
106 {
107 #if defined(__arm64__)
108 struct power_domain_device *pd = cookie;
109 int domain;
110
111 power_domain_enable(pd->pd_node);
112
113 domain = OF_getpropint(pd->pd_node, "reg", 0);
114
115 /* Set up power domain */
116 smc_call(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN,
117 domain, on);
118 #endif
119 }
120