xref: /openbsd-src/sys/dev/fdt/imxgpc.c (revision 9fdf0c627b1fec102f212f847a6f7676c1829e65)
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