xref: /netbsd-src/sys/dev/fdt/fdt_powerdomain.c (revision dfaf16335cddfdb9162ac707a635a674fc96af5d)
1*dfaf1633Srin /* $NetBSD: fdt_powerdomain.c,v 1.2 2024/06/12 06:39:28 rin Exp $ */
2f80fe797Sskrll 
3f80fe797Sskrll /*-
4f80fe797Sskrll  * Copyright (c) 2022 The NetBSD Foundation, Inc.
5f80fe797Sskrll  * All rights reserved.
6f80fe797Sskrll  *
7f80fe797Sskrll  * This code is derived from software contributed to The NetBSD Foundation
8f80fe797Sskrll  * by Nick Hudson
9f80fe797Sskrll  *
10f80fe797Sskrll  * Redistribution and use in source and binary forms, with or without
11f80fe797Sskrll  * modification, are permitted provided that the following conditions
12f80fe797Sskrll  * are met:
13f80fe797Sskrll  * 1. Redistributions of source code must retain the above copyright
14f80fe797Sskrll  *    notice, this list of conditions and the following disclaimer.
15f80fe797Sskrll  * 2. Redistributions in binary form must reproduce the above copyright
16f80fe797Sskrll  *    notice, this list of conditions and the following disclaimer in the
17f80fe797Sskrll  *    documentation and/or other materials provided with the distribution.
18f80fe797Sskrll  *
19f80fe797Sskrll  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20f80fe797Sskrll  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21f80fe797Sskrll  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22f80fe797Sskrll  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23f80fe797Sskrll  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24f80fe797Sskrll  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25f80fe797Sskrll  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26f80fe797Sskrll  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27f80fe797Sskrll  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28f80fe797Sskrll  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29f80fe797Sskrll  * POSSIBILITY OF SUCH DAMAGE.
30f80fe797Sskrll  */
31f80fe797Sskrll 
32f80fe797Sskrll #include <sys/cdefs.h>
33*dfaf1633Srin __KERNEL_RCSID(0, "$NetBSD: fdt_powerdomain.c,v 1.2 2024/06/12 06:39:28 rin Exp $");
34f80fe797Sskrll 
35f80fe797Sskrll #include <sys/param.h>
36f80fe797Sskrll 
37f80fe797Sskrll #include <sys/bus.h>
38f80fe797Sskrll #include <sys/kmem.h>
39f80fe797Sskrll #include <sys/queue.h>
40f80fe797Sskrll 
41f80fe797Sskrll #include <libfdt.h>
42f80fe797Sskrll #include <dev/fdt/fdtvar.h>
43f80fe797Sskrll 
44f80fe797Sskrll 
45f80fe797Sskrll struct fdtbus_powerdomain_controller {
46f80fe797Sskrll 	device_t pdc_dev;
47f80fe797Sskrll 	int pdc_phandle;
48f80fe797Sskrll 
49f80fe797Sskrll 	void *pdc_cookie;
50f80fe797Sskrll 
51f80fe797Sskrll 	int pdc_cells;
52f80fe797Sskrll 
53f80fe797Sskrll 	const struct fdtbus_powerdomain_controller_func *pdc_funcs;
54f80fe797Sskrll 
55f80fe797Sskrll 	LIST_ENTRY(fdtbus_powerdomain_controller) pdc_next;
56f80fe797Sskrll };
57f80fe797Sskrll 
58f80fe797Sskrll static LIST_HEAD(, fdtbus_powerdomain_controller) fdtbus_powerdomain_controllers =
59f80fe797Sskrll     LIST_HEAD_INITIALIZER(fdtbus_powerdomain_controllers);
60f80fe797Sskrll 
61f80fe797Sskrll int
fdtbus_register_powerdomain_controller(device_t dev,int phandle,const struct fdtbus_powerdomain_controller_func * funcs)62f80fe797Sskrll fdtbus_register_powerdomain_controller(device_t dev, int phandle,
63f80fe797Sskrll     const struct fdtbus_powerdomain_controller_func *funcs)
64f80fe797Sskrll {
65f80fe797Sskrll 	struct fdtbus_powerdomain_controller *pdc;
66f80fe797Sskrll 
67f80fe797Sskrll 	uint32_t cells;
68f80fe797Sskrll 	if (of_getprop_uint32(phandle, "#power-domain-cells", &cells) != 0) {
69f80fe797Sskrll 		aprint_debug_dev(dev, "missing #power-domain-cells");
70f80fe797Sskrll 		return EINVAL;
71f80fe797Sskrll 	}
72f80fe797Sskrll 
73f80fe797Sskrll 	pdc = kmem_alloc(sizeof(*pdc), KM_SLEEP);
74f80fe797Sskrll 	pdc->pdc_dev = dev;
75f80fe797Sskrll 	pdc->pdc_phandle = phandle;
76f80fe797Sskrll 	pdc->pdc_funcs = funcs;
77f80fe797Sskrll 	pdc->pdc_cells = cells;
78f80fe797Sskrll 
79f80fe797Sskrll 	LIST_INSERT_HEAD(&fdtbus_powerdomain_controllers, pdc, pdc_next);
80f80fe797Sskrll 
81f80fe797Sskrll 	return 0;
82f80fe797Sskrll }
83f80fe797Sskrll 
84f80fe797Sskrll static struct fdtbus_powerdomain_controller *
fdtbus_powerdomain_lookup(int phandle)85f80fe797Sskrll fdtbus_powerdomain_lookup(int phandle)
86f80fe797Sskrll {
87f80fe797Sskrll 	struct fdtbus_powerdomain_controller *pdc;
88f80fe797Sskrll 
89f80fe797Sskrll 	LIST_FOREACH(pdc, &fdtbus_powerdomain_controllers, pdc_next) {
90f80fe797Sskrll 		if (pdc->pdc_phandle == phandle)
91f80fe797Sskrll 			return pdc;
92f80fe797Sskrll 	}
93f80fe797Sskrll 
94f80fe797Sskrll 	return NULL;
95f80fe797Sskrll }
96f80fe797Sskrll 
97f80fe797Sskrll static int
fdtbus_powerdomain_enable_internal(int phandle,int index,bool enable)98f80fe797Sskrll fdtbus_powerdomain_enable_internal(int phandle, int index, bool enable)
99f80fe797Sskrll {
100f80fe797Sskrll 	int len;
101f80fe797Sskrll 	const uint32_t *pds = fdtbus_get_prop(phandle, "power-domains", &len);
102f80fe797Sskrll 
103f80fe797Sskrll 	if (pds == NULL)
104f80fe797Sskrll 		return EINVAL;
105f80fe797Sskrll 
106*dfaf1633Srin 	for (const uint32_t *pd = pds; pd < pds + len / sizeof(*pd); index--) {
107f80fe797Sskrll 		uint32_t pd_node =
108f80fe797Sskrll 		   fdtbus_get_phandle_from_native(be32toh(pd[0]));
109f80fe797Sskrll 		struct fdtbus_powerdomain_controller *pdc =
110f80fe797Sskrll 		    fdtbus_powerdomain_lookup(pd_node);
111f80fe797Sskrll 
112f80fe797Sskrll 		if (pdc == NULL)
113f80fe797Sskrll 			return ENXIO;
114f80fe797Sskrll 
115f80fe797Sskrll 		if (index < 0 || index == 0)
116f80fe797Sskrll 			pdc->pdc_funcs->pdc_enable(pdc->pdc_dev, pd, enable);
117f80fe797Sskrll 		if (index == 0)
118f80fe797Sskrll 			break;
119f80fe797Sskrll 
120f80fe797Sskrll 		pd += pdc->pdc_cells + 1;
121f80fe797Sskrll 	}
122f80fe797Sskrll 
123f80fe797Sskrll 	return 0;
124f80fe797Sskrll }
125f80fe797Sskrll 
126f80fe797Sskrll int
fdtbus_powerdomain_enable_index(int phandle,int index)127f80fe797Sskrll fdtbus_powerdomain_enable_index(int phandle, int index)
128f80fe797Sskrll {
129f80fe797Sskrll 	return fdtbus_powerdomain_enable_internal(phandle, index, true);
130f80fe797Sskrll }
131f80fe797Sskrll 
132f80fe797Sskrll int
fdtbus_powerdomain_disable_index(int phandle,int index)133f80fe797Sskrll fdtbus_powerdomain_disable_index(int phandle, int index)
134f80fe797Sskrll {
135f80fe797Sskrll 	return fdtbus_powerdomain_enable_internal(phandle, index, false);
136f80fe797Sskrll }
137f80fe797Sskrll 
138f80fe797Sskrll int
fdtbus_powerdomain_enable(int node)139f80fe797Sskrll fdtbus_powerdomain_enable(int node)
140f80fe797Sskrll {
141f80fe797Sskrll 	return fdtbus_powerdomain_enable_index(node, -1);
142f80fe797Sskrll }
143f80fe797Sskrll 
144f80fe797Sskrll int
fdtbus_powerdomain_disable(int node)145f80fe797Sskrll fdtbus_powerdomain_disable(int node)
146f80fe797Sskrll {
147f80fe797Sskrll 	return fdtbus_powerdomain_disable_index(node, -1);
148f80fe797Sskrll }
149