1*f702326eSkettenis /* $OpenBSD: ofw_power.c,v 1.2 2021/11/26 11:44:01 kettenis Exp $ */
21eacba6cSpatrick /*
31eacba6cSpatrick * Copyright (c) 2016 Mark Kettenis
41eacba6cSpatrick * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
51eacba6cSpatrick *
61eacba6cSpatrick * Permission to use, copy, modify, and distribute this software for any
71eacba6cSpatrick * purpose with or without fee is hereby granted, provided that the above
81eacba6cSpatrick * copyright notice and this permission notice appear in all copies.
91eacba6cSpatrick *
101eacba6cSpatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
111eacba6cSpatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
121eacba6cSpatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
131eacba6cSpatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
141eacba6cSpatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
151eacba6cSpatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
161eacba6cSpatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
171eacba6cSpatrick */
181eacba6cSpatrick
191eacba6cSpatrick #include <sys/types.h>
201eacba6cSpatrick #include <sys/systm.h>
211eacba6cSpatrick #include <sys/malloc.h>
221eacba6cSpatrick
231eacba6cSpatrick #include <dev/ofw/openfirm.h>
241eacba6cSpatrick #include <dev/ofw/ofw_power.h>
251eacba6cSpatrick
261eacba6cSpatrick LIST_HEAD(, power_domain_device) power_domain_devices =
271eacba6cSpatrick LIST_HEAD_INITIALIZER(power_domain_devices);
281eacba6cSpatrick
291eacba6cSpatrick void
power_domain_register(struct power_domain_device * pd)301eacba6cSpatrick power_domain_register(struct power_domain_device *pd)
311eacba6cSpatrick {
321eacba6cSpatrick pd->pd_cells = OF_getpropint(pd->pd_node, "#power-domain-cells", 0);
331eacba6cSpatrick pd->pd_phandle = OF_getpropint(pd->pd_node, "phandle", 0);
341eacba6cSpatrick if (pd->pd_phandle == 0)
351eacba6cSpatrick return;
361eacba6cSpatrick
371eacba6cSpatrick LIST_INSERT_HEAD(&power_domain_devices, pd, pd_list);
381eacba6cSpatrick }
391eacba6cSpatrick
401eacba6cSpatrick void
power_domain_enable_cells(uint32_t * cells,int on)411eacba6cSpatrick power_domain_enable_cells(uint32_t *cells, int on)
421eacba6cSpatrick {
431eacba6cSpatrick struct power_domain_device *pd;
441eacba6cSpatrick uint32_t phandle = cells[0];
451eacba6cSpatrick
461eacba6cSpatrick LIST_FOREACH(pd, &power_domain_devices, pd_list) {
471eacba6cSpatrick if (pd->pd_phandle == phandle)
481eacba6cSpatrick break;
491eacba6cSpatrick }
501eacba6cSpatrick
511eacba6cSpatrick if (pd && pd->pd_enable)
521eacba6cSpatrick pd->pd_enable(pd->pd_cookie, &cells[1], on);
531eacba6cSpatrick }
541eacba6cSpatrick
551eacba6cSpatrick uint32_t *
power_domain_next_domain(uint32_t * cells)561eacba6cSpatrick power_domain_next_domain(uint32_t *cells)
571eacba6cSpatrick {
581eacba6cSpatrick uint32_t phandle = cells[0];
591eacba6cSpatrick int node, ncells;
601eacba6cSpatrick
611eacba6cSpatrick node = OF_getnodebyphandle(phandle);
621eacba6cSpatrick if (node == 0)
631eacba6cSpatrick return NULL;
641eacba6cSpatrick
651eacba6cSpatrick ncells = OF_getpropint(node, "#power-domain-cells", 0);
661eacba6cSpatrick return cells + ncells + 1;
671eacba6cSpatrick }
681eacba6cSpatrick
691eacba6cSpatrick void
power_domain_do_enable_idx(int node,int idx,int on)701eacba6cSpatrick power_domain_do_enable_idx(int node, int idx, int on)
711eacba6cSpatrick {
721eacba6cSpatrick uint32_t *domains;
731eacba6cSpatrick uint32_t *domain;
741eacba6cSpatrick int len;
751eacba6cSpatrick
761eacba6cSpatrick len = OF_getproplen(node, "power-domains");
771eacba6cSpatrick if (len <= 0)
781eacba6cSpatrick return;
791eacba6cSpatrick
801eacba6cSpatrick domains = malloc(len, M_TEMP, M_WAITOK);
811eacba6cSpatrick OF_getpropintarray(node, "power-domains", domains, len);
821eacba6cSpatrick
831eacba6cSpatrick domain = domains;
841eacba6cSpatrick while (domain && domain < domains + (len / sizeof(uint32_t))) {
851eacba6cSpatrick if (idx <= 0)
861eacba6cSpatrick power_domain_enable_cells(domain, on);
871eacba6cSpatrick if (idx == 0)
881eacba6cSpatrick break;
891eacba6cSpatrick domain = power_domain_next_domain(domain);
901eacba6cSpatrick idx--;
911eacba6cSpatrick }
921eacba6cSpatrick
931eacba6cSpatrick free(domains, M_TEMP, len);
941eacba6cSpatrick }
951eacba6cSpatrick
961eacba6cSpatrick void
power_domain_enable_idx(int node,int idx)97*f702326eSkettenis power_domain_enable_idx(int node, int idx)
98*f702326eSkettenis {
99*f702326eSkettenis power_domain_do_enable_idx(node, idx, 1);
100*f702326eSkettenis }
101*f702326eSkettenis
102*f702326eSkettenis void
power_domain_enable(int node)1031eacba6cSpatrick power_domain_enable(int node)
1041eacba6cSpatrick {
1051eacba6cSpatrick power_domain_do_enable_idx(node, 0, 1);
1061eacba6cSpatrick }
1071eacba6cSpatrick
1081eacba6cSpatrick void
power_domain_disable_idx(int node,int idx)109*f702326eSkettenis power_domain_disable_idx(int node, int idx)
110*f702326eSkettenis {
111*f702326eSkettenis power_domain_do_enable_idx(node, idx, 0);
112*f702326eSkettenis }
113*f702326eSkettenis
114*f702326eSkettenis void
power_domain_disable(int node)1151eacba6cSpatrick power_domain_disable(int node)
1161eacba6cSpatrick {
1171eacba6cSpatrick power_domain_do_enable_idx(node, 0, 0);
1181eacba6cSpatrick }
119