xref: /openbsd/sys/dev/fdt/amlpwrc.c (revision 4bdff4be)
1 /*	$OpenBSD: amlpwrc.c,v 1.4 2022/04/06 18:59:28 naddy Exp $	*/
2 /*
3  * Copyright (c) 2020 Mark Kettenis <kettenis@openbsd.org>
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 
22 #include <machine/intr.h>
23 #include <machine/bus.h>
24 #include <machine/fdt.h>
25 
26 #include <dev/ofw/openfirm.h>
27 #include <dev/ofw/ofw_power.h>
28 #include <dev/ofw/ofw_misc.h>
29 #include <dev/ofw/fdt.h>
30 
31 /* Power domain IDs */
32 #define PWRC_G12A_ETH_ID	1
33 #define PWRC_SM1_USB_ID		2
34 #define PWRC_SM1_PCIE_ID	3
35 #define PWRC_SM1_ETH_ID		6
36 
37 /* Registers */
38 #define AO_RTI_GEN_PWR_SLEEP0		0x3a
39 #define AO_RTI_GEN_PWR_ISO0		0x3b
40 #define  AO_RTI_GEN_PWR_PCIE_MASK	(1 << 18)
41 #define  AO_RTI_GEN_PWR_USB_MASK	(1 << 17)
42 #define HHI_MEM_PD_REG0			0x40
43 #define  HHI_MEM_PD_USB_MASK		(0x3 << 30)
44 #define  HHI_MEM_PD_PCIE_MASK		(0xf << 26)
45 #define  HHI_MEM_PD_ETH_MASK		(0x3 << 2)
46 
47 #define HREAD4(sc, reg)							\
48 	(regmap_read_4((sc)->sc_rm, (reg) << 2))
49 #define HWRITE4(sc, reg, val)						\
50 	regmap_write_4((sc)->sc_rm, (reg) << 2, (val))
51 #define HSET4(sc, reg, bits)						\
52 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
53 #define HCLR4(sc, reg, bits)						\
54 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
55 
56 struct amlpwrc_softc {
57 	struct device		sc_dev;
58 	struct regmap		*sc_rm_hhi;
59 	struct regmap		*sc_rm_ao;
60 	uint32_t		sc_ao;
61 	int			sc_node;
62 
63 	struct power_domain_device sc_pd;
64 };
65 
66 int amlpwrc_match(struct device *, void *, void *);
67 void amlpwrc_attach(struct device *, struct device *, void *);
68 
69 const struct cfattach amlpwrc_ca = {
70 	sizeof (struct amlpwrc_softc), amlpwrc_match, amlpwrc_attach
71 };
72 
73 struct cfdriver amlpwrc_cd = {
74 	NULL, "amlpwrc", DV_DULL
75 };
76 
77 void	amlpwrc_g12a_enable(void *, uint32_t *, int);
78 void	amlpwrc_sm1_enable(void *, uint32_t *, int);
79 
80 int
81 amlpwrc_match(struct device *parent, void *match, void *aux)
82 {
83 	struct fdt_attach_args *faa = aux;
84 
85 	return (OF_is_compatible(faa->fa_node, "amlogic,meson-g12a-pwrc") ||
86 	    OF_is_compatible(faa->fa_node, "amlogic,meson-sm1-pwrc"));
87 }
88 
89 void
90 amlpwrc_attach(struct device *parent, struct device *self, void *aux)
91 {
92 	struct amlpwrc_softc *sc = (struct amlpwrc_softc *)self;
93 	struct fdt_attach_args *faa = aux;
94 
95 	/*
96 	 * We can't lookup the AO regmap at this point since the
97 	 * syscon(4) instance that provides it attaches after us.
98 	 */
99 	sc->sc_rm_hhi = regmap_bynode(OF_parent(faa->fa_node));
100 	sc->sc_ao = OF_getpropint(faa->fa_node, "amlogic,ao-sysctrl", 0);
101 	if (sc->sc_rm_hhi == NULL || sc->sc_ao == 0) {
102 		printf(": no registers\n");
103 		return;
104 	}
105 
106 	sc->sc_node = faa->fa_node;
107 	printf("\n");
108 
109 	sc->sc_pd.pd_node = faa->fa_node;
110 	sc->sc_pd.pd_cookie = sc;
111 	if (OF_is_compatible(faa->fa_node, "amlogic,meson-g12a-pwrc"))
112 		sc->sc_pd.pd_enable = amlpwrc_g12a_enable;
113 	else if (OF_is_compatible(faa->fa_node, "amlogic,meson-sm1-pwrc"))
114 		sc->sc_pd.pd_enable = amlpwrc_sm1_enable;
115 	power_domain_register(&sc->sc_pd);
116 }
117 
118 static inline void
119 amlpwrc_toggle(struct regmap *rm, bus_size_t reg, uint32_t mask, int on)
120 {
121 	uint32_t val;
122 
123 	val = regmap_read_4(rm, reg << 2);
124 	if (on)
125 		val &= ~mask;
126 	else
127 		val |= mask;
128 	regmap_write_4(rm, reg << 2, val);
129 }
130 
131 void
132 amlpwrc_g12a_enable(void *cookie, uint32_t *cells, int on)
133 {
134 	struct amlpwrc_softc *sc = cookie;
135 	uint32_t idx = cells[0];
136 
137 	sc->sc_rm_ao = regmap_byphandle(sc->sc_ao);
138 	KASSERT(sc->sc_rm_ao);
139 
140 	switch (idx) {
141 	case PWRC_G12A_ETH_ID:
142 		amlpwrc_toggle(sc->sc_rm_hhi, HHI_MEM_PD_REG0,
143 		    HHI_MEM_PD_ETH_MASK, on);
144 		delay(20);
145 		return;
146 	}
147 
148 	printf("%s: 0x%08x\n", __func__, idx);
149 }
150 
151 void
152 amlpwrc_sm1_enable(void *cookie, uint32_t *cells, int on)
153 {
154 	struct amlpwrc_softc *sc = cookie;
155 	uint32_t idx = cells[0];
156 
157 	sc->sc_rm_ao = regmap_byphandle(sc->sc_ao);
158 	KASSERT(sc->sc_rm_ao);
159 
160 	switch (idx) {
161 	case PWRC_SM1_USB_ID:
162 		amlpwrc_toggle(sc->sc_rm_ao, AO_RTI_GEN_PWR_SLEEP0,
163 		    AO_RTI_GEN_PWR_USB_MASK, on);
164 		delay(20);
165 		amlpwrc_toggle(sc->sc_rm_hhi, HHI_MEM_PD_REG0,
166 		    HHI_MEM_PD_USB_MASK, on);
167 		delay(20);
168 		amlpwrc_toggle(sc->sc_rm_ao, AO_RTI_GEN_PWR_ISO0,
169 		    AO_RTI_GEN_PWR_USB_MASK, on);
170 		return;
171 	case PWRC_SM1_PCIE_ID:
172 		amlpwrc_toggle(sc->sc_rm_ao, AO_RTI_GEN_PWR_SLEEP0,
173 		    AO_RTI_GEN_PWR_PCIE_MASK, on);
174 		delay(20);
175 		amlpwrc_toggle(sc->sc_rm_hhi, HHI_MEM_PD_REG0,
176 		    HHI_MEM_PD_PCIE_MASK, on);
177 		delay(20);
178 		amlpwrc_toggle(sc->sc_rm_ao, AO_RTI_GEN_PWR_ISO0,
179 		    AO_RTI_GEN_PWR_PCIE_MASK, on);
180 		return;
181 	case PWRC_SM1_ETH_ID:
182 		amlpwrc_toggle(sc->sc_rm_hhi, HHI_MEM_PD_REG0,
183 		    HHI_MEM_PD_ETH_MASK, on);
184 		delay(20);
185 		return;
186 	}
187 
188 	printf("%s: 0x%08x\n", __func__, idx);
189 }
190