xref: /openbsd-src/sys/dev/fdt/imxgpc.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: imxgpc.c,v 1.8 2020/07/17 08:07:34 patrick 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 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
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,imx8mq-gpc"));
63 }
64 
65 void
66 imxgpc_attach(struct device *parent, struct device *self, void *aux)
67 {
68 	struct fdt_attach_args *faa = aux;
69 	struct imxgpc_softc *sc = (struct imxgpc_softc *)self;
70 	int i, node, list;
71 
72 	sc->sc_ic.ic_node = faa->fa_node;
73 	sc->sc_ic.ic_cookie = &sc->sc_ic;
74 	sc->sc_ic.ic_establish = fdt_intr_parent_establish;
75 	sc->sc_ic.ic_disestablish = fdt_intr_parent_disestablish;
76 	sc->sc_ic.ic_barrier = intr_barrier;
77 	fdt_intr_register(&sc->sc_ic);
78 
79 	printf("\n");
80 
81 	if (OF_is_compatible(faa->fa_node, "fsl,imx8mm-gpc") ||
82 	    OF_is_compatible(faa->fa_node, "fsl,imx8mq-gpc")) {
83 		list = OF_child(faa->fa_node);
84 		if (!list)
85 			return;
86 		for (node = OF_child(list); node; node = OF_peer(node))
87 			sc->sc_npd++;
88 		if (!sc->sc_npd)
89 			return;
90 		sc->sc_pd = mallocarray(sc->sc_npd, sizeof(*sc->sc_pd),
91 		    M_DEVBUF, M_WAITOK);
92 		for (node = OF_child(list), i = 0; node;
93 		    node = OF_peer(node), i++){
94 			sc->sc_pd[i].pd_node = node;
95 			sc->sc_pd[i].pd_cookie = &sc->sc_pd[i];
96 			sc->sc_pd[i].pd_enable = imxgpc_enable;
97 			power_domain_register(&sc->sc_pd[i]);
98 		}
99 	}
100 }
101 
102 void
103 imxgpc_enable(void *cookie, uint32_t *cells, int on)
104 {
105 #if defined(__arm64__)
106 	struct power_domain_device *pd = cookie;
107 	int domain;
108 
109 	power_domain_enable(pd->pd_node);
110 
111 	domain = OF_getpropint(pd->pd_node, "reg", 0);
112 
113 	/* Set up power domain */
114 	smc_call(FSL_SIP_GPC, FSL_SIP_CONFIG_GPC_PM_DOMAIN,
115 	    domain, on);
116 #endif
117 }
118