]> Git Repo - J-u-boot.git/blame - drivers/power/domain/imx8-power-domain-legacy.c
Merge tag 'u-boot-amlogic-20200511' of https://gitlab.denx.de/u-boot/custodians/u...
[J-u-boot.git] / drivers / power / domain / imx8-power-domain-legacy.c
CommitLineData
d526f340
PF
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2017 NXP
4 */
5
6#include <common.h>
7#include <dm.h>
336d4615 8#include <malloc.h>
d526f340
PF
9#include <power-domain-uclass.h>
10#include <asm/io.h>
11#include <asm/arch/power-domain.h>
12#include <dm/device-internal.h>
13#include <dm/device.h>
231401de 14#include <dm/uclass-internal.h>
d526f340
PF
15#include <asm/arch/sci/sci.h>
16
17DECLARE_GLOBAL_DATA_PTR;
18
19struct imx8_power_domain_priv {
20 bool state_on;
21};
22
231401de
PF
23static bool check_device_power_off(struct udevice *dev,
24 const char *permanent_on_devices[],
25 int size)
26{
27 int i;
28
29 for (i = 0; i < size; i++) {
30 if (!strcmp(dev->name, permanent_on_devices[i]))
31 return false;
32 }
33
34 return true;
35}
36
37void imx8_power_off_pd_devices(const char *permanent_on_devices[], int size)
38{
39 struct udevice *dev;
40 struct power_domain pd;
41
42 for (uclass_find_first_device(UCLASS_POWER_DOMAIN, &dev); dev;
43 uclass_find_next_device(&dev)) {
44 if (!device_active(dev))
45 continue;
46 /*
47 * Power off active pd devices except the permanent
48 * power on devices
49 */
50 if (check_device_power_off(dev, permanent_on_devices, size)) {
51 pd.dev = dev;
52 power_domain_off(&pd);
53 }
54 }
55}
56
8c0a1c6d
PF
57int imx8_power_domain_lookup_name(const char *name,
58 struct power_domain *power_domain)
59{
60 struct udevice *dev;
61 struct power_domain_ops *ops;
62 int ret;
63
64 debug("%s(power_domain=%p name=%s)\n", __func__, power_domain, name);
65
66 ret = uclass_get_device_by_name(UCLASS_POWER_DOMAIN, name, &dev);
67 if (ret) {
68 printf("%s fail: %s, ret = %d\n", __func__, name, ret);
69 return ret;
70 }
71
72 ops = (struct power_domain_ops *)dev->driver->ops;
73 power_domain->dev = dev;
74 ret = ops->request(power_domain);
75 if (ret) {
76 debug("ops->request() failed: %d\n", ret);
77 return ret;
78 }
79
80 debug("%s ok: %s\n", __func__, dev->name);
81
82 return 0;
83}
84
d526f340
PF
85static int imx8_power_domain_request(struct power_domain *power_domain)
86{
87 debug("%s(power_domain=%p)\n", __func__, power_domain);
88
89 return 0;
90}
91
92static int imx8_power_domain_free(struct power_domain *power_domain)
93{
94 debug("%s(power_domain=%p)\n", __func__, power_domain);
95
96 return 0;
97}
98
99static int imx8_power_domain_on(struct power_domain *power_domain)
100{
101 struct udevice *dev = power_domain->dev;
102 struct imx8_power_domain_platdata *pdata;
103 struct imx8_power_domain_priv *ppriv;
104 sc_err_t ret;
105 int err;
106
107 struct power_domain parent_domain;
108 struct udevice *parent = dev_get_parent(dev);
109
110 /* Need to power on parent node first */
111 if (device_get_uclass_id(parent) == UCLASS_POWER_DOMAIN) {
112 parent_domain.dev = parent;
113 err = imx8_power_domain_on(&parent_domain);
114 if (err)
115 return err;
116 }
117
118 pdata = (struct imx8_power_domain_platdata *)dev_get_platdata(dev);
119 ppriv = (struct imx8_power_domain_priv *)dev_get_priv(dev);
120
121 debug("%s(power_domain=%s) resource_id %d\n", __func__, dev->name,
122 pdata->resource_id);
123
124 /* Already powered on */
125 if (ppriv->state_on)
126 return 0;
127
6fcb2ee7 128 if (pdata->resource_id != SC_R_NONE) {
1074af51
YL
129 if (!sc_rm_is_resource_owned(-1, pdata->resource_id))
130 printf("%s [%d] not owned by curr partition\n", dev->name, pdata->resource_id);
131
d526f340
PF
132 ret = sc_pm_set_resource_power_mode(-1, pdata->resource_id,
133 SC_PM_PW_MODE_ON);
134 if (ret) {
135 printf("Error: %s Power up failed! (error = %d)\n",
136 dev->name, ret);
137 return -EIO;
138 }
139 }
140
141 ppriv->state_on = true;
142 debug("%s is powered on\n", dev->name);
143
144 return 0;
145}
146
147static int imx8_power_domain_off_node(struct power_domain *power_domain)
148{
149 struct udevice *dev = power_domain->dev;
150 struct udevice *child;
151 struct imx8_power_domain_priv *ppriv;
152 struct imx8_power_domain_priv *child_ppriv;
153 struct imx8_power_domain_platdata *pdata;
154 sc_err_t ret;
155
156 ppriv = dev_get_priv(dev);
157 pdata = dev_get_platdata(dev);
158
159 debug("%s, %s, state_on %d\n", __func__, dev->name, ppriv->state_on);
160
161 /* Already powered off */
162 if (!ppriv->state_on)
163 return 0;
164
165 /* Check if all subnodes are off */
166 for (device_find_first_child(dev, &child);
167 child;
168 device_find_next_child(&child)) {
169 if (device_active(child)) {
170 child_ppriv =
171 (struct imx8_power_domain_priv *)dev_get_priv(child);
172 if (child_ppriv->state_on)
173 return -EPERM;
174 }
175 }
176
6fcb2ee7 177 if (pdata->resource_id != SC_R_NONE) {
d526f340
PF
178 ret = sc_pm_set_resource_power_mode(-1, pdata->resource_id,
179 SC_PM_PW_MODE_OFF);
180 if (ret) {
e8f8b5cc
PF
181 if (!sc_rm_is_resource_owned(-1, pdata->resource_id)) {
182 printf("%s not owned by curr partition %d\n", dev->name, pdata->resource_id);
183 return 0;
184 }
d526f340
PF
185 printf("Error: %s Power off failed! (error = %d)\n",
186 dev->name, ret);
187 return -EIO;
188 }
189 }
190
191 ppriv->state_on = false;
192 debug("%s is powered off\n", dev->name);
193
194 return 0;
195}
196
197static int imx8_power_domain_off_parentnodes(struct power_domain *power_domain)
198{
199 struct udevice *dev = power_domain->dev;
200 struct udevice *parent = dev_get_parent(dev);
201 struct udevice *child;
202 struct imx8_power_domain_priv *ppriv;
203 struct imx8_power_domain_priv *child_ppriv;
204 struct imx8_power_domain_platdata *pdata;
205 sc_err_t ret;
206 struct power_domain parent_pd;
207
208 if (device_get_uclass_id(parent) == UCLASS_POWER_DOMAIN) {
209 pdata =
210 (struct imx8_power_domain_platdata *)dev_get_platdata(parent);
211 ppriv = (struct imx8_power_domain_priv *)dev_get_priv(parent);
212
213 debug("%s, %s, state_on %d\n", __func__, parent->name,
214 ppriv->state_on);
215
216 /* Already powered off */
217 if (!ppriv->state_on)
218 return 0;
219
220 /*
221 * Check if all sibling nodes are off. If yes,
222 * power off parent
223 */
224 for (device_find_first_child(parent, &child); child;
225 device_find_next_child(&child)) {
226 if (device_active(child)) {
227 child_ppriv = (struct imx8_power_domain_priv *)
228 dev_get_priv(child);
229 /* Find a power on sibling */
230 if (child_ppriv->state_on) {
231 debug("sibling %s, state_on %d\n",
232 child->name,
233 child_ppriv->state_on);
234 return 0;
235 }
236 }
237 }
238
239 /* power off parent */
6fcb2ee7 240 if (pdata->resource_id != SC_R_NONE) {
d526f340
PF
241 ret = sc_pm_set_resource_power_mode(-1,
242 pdata->resource_id,
243 SC_PM_PW_MODE_OFF);
244 if (ret) {
245 printf("%s Power off failed! (error = %d)\n",
246 parent->name, ret);
247 return -EIO;
248 }
249 }
250
251 ppriv->state_on = false;
252 debug("%s is powered off\n", parent->name);
253
254 parent_pd.dev = parent;
255 imx8_power_domain_off_parentnodes(&parent_pd);
256 }
257
258 return 0;
259}
260
261static int imx8_power_domain_off(struct power_domain *power_domain)
262{
263 int ret;
264
265 debug("%s(power_domain=%p)\n", __func__, power_domain);
266
267 /* Turn off the node */
268 ret = imx8_power_domain_off_node(power_domain);
269 if (ret) {
270 debug("Can't power off the node of dev %s, ret = %d\n",
271 power_domain->dev->name, ret);
272 return ret;
273 }
274
275 /* Turn off parent nodes, if sibling nodes are all off */
276 ret = imx8_power_domain_off_parentnodes(power_domain);
277 if (ret) {
278 printf("Failed to power off parent nodes of dev %s, ret = %d\n",
279 power_domain->dev->name, ret);
280 return ret;
281 }
282
283 return 0;
284}
285
286static int imx8_power_domain_of_xlate(struct power_domain *power_domain,
287 struct ofnode_phandle_args *args)
288{
289 debug("%s(power_domain=%p)\n", __func__, power_domain);
290
291 /* Do nothing to the xlate, since we don't have args used */
292
293 return 0;
294}
295
296static int imx8_power_domain_bind(struct udevice *dev)
297{
298 int offset;
299 const char *name;
300 int ret = 0;
301
302 debug("%s(dev=%p)\n", __func__, dev);
303
304 offset = dev_of_offset(dev);
305 for (offset = fdt_first_subnode(gd->fdt_blob, offset); offset > 0;
306 offset = fdt_next_subnode(gd->fdt_blob, offset)) {
307 /* Bind the subnode to this driver */
308 name = fdt_get_name(gd->fdt_blob, offset, NULL);
309
310 ret = device_bind_with_driver_data(dev, dev->driver, name,
311 dev->driver_data,
312 offset_to_ofnode(offset),
313 NULL);
314
315 if (ret == -ENODEV)
316 printf("Driver '%s' refuses to bind\n",
317 dev->driver->name);
318
319 if (ret)
320 printf("Error binding driver '%s': %d\n",
321 dev->driver->name, ret);
322 }
323
324 return 0;
325}
326
327static int imx8_power_domain_probe(struct udevice *dev)
328{
329 struct imx8_power_domain_priv *ppriv;
330
331 debug("%s(dev=%s)\n", __func__, dev->name);
332
333 ppriv = (struct imx8_power_domain_priv *)dev_get_priv(dev);
334
335 /* Set default to power off */
336 if (ppriv)
337 ppriv->state_on = false;
338
339 return 0;
340}
341
342static int imx8_power_domain_ofdata_to_platdata(struct udevice *dev)
343{
344 int reg;
345 struct imx8_power_domain_platdata *pdata = dev_get_platdata(dev);
346
347 reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "reg", -1);
348 if (reg == -1) {
349 debug("%s: Invalid resource id %d\n", __func__, reg);
350 return -EINVAL;
351 }
352 pdata->resource_id = (sc_rsrc_t)reg;
353
354 debug("%s resource_id %d\n", __func__, pdata->resource_id);
355
356 return 0;
357}
358
359static const struct udevice_id imx8_power_domain_ids[] = {
360 { .compatible = "nxp,imx8-pd" },
361 { }
362};
363
364struct power_domain_ops imx8_power_domain_ops = {
365 .request = imx8_power_domain_request,
4f51188e 366 .rfree = imx8_power_domain_free,
d526f340
PF
367 .on = imx8_power_domain_on,
368 .off = imx8_power_domain_off,
369 .of_xlate = imx8_power_domain_of_xlate,
370};
371
372U_BOOT_DRIVER(imx8_power_domain) = {
373 .name = "imx8_power_domain",
374 .id = UCLASS_POWER_DOMAIN,
375 .of_match = imx8_power_domain_ids,
376 .bind = imx8_power_domain_bind,
377 .probe = imx8_power_domain_probe,
378 .ofdata_to_platdata = imx8_power_domain_ofdata_to_platdata,
379 .platdata_auto_alloc_size = sizeof(struct imx8_power_domain_platdata),
380 .priv_auto_alloc_size = sizeof(struct imx8_power_domain_priv),
381 .ops = &imx8_power_domain_ops,
ca0c5271 382 .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
d526f340 383};
This page took 0.151112 seconds and 4 git commands to generate.