]> Git Repo - u-boot.git/blob - drivers/power/domain/scmi-power-domain.c
imx8mp: power-domain: Add PCIe support
[u-boot.git] / drivers / power / domain / scmi-power-domain.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * SCMI Power domain driver
4  *
5  * Copyright (C) 2023 Linaro Limited
6  *              author: AKASHI Takahiro <[email protected]>
7  */
8
9 #include <dm.h>
10 #include <malloc.h>
11 #include <power-domain.h>
12 #include <power-domain-uclass.h>
13 #include <scmi_agent.h>
14 #include <scmi_protocols.h>
15 #include <dm/device_compat.h>
16
17 /**
18  * struct scmi_pwd_properties
19  * @attributes: Power domain attributes
20  * @name:       Name of the domain
21  */
22 struct scmi_pwd_properties {
23         u32 attributes;
24         u8 *name; /* not used now */
25 };
26
27 /**
28  * struct scmi_power_domain_priv
29  * @num_pwdoms: Number of power domains
30  * @prop:       Pointer to domain's properties
31  * @stats_addr: Address of statistics memory region
32  * @stats_len:  Length of statistics memory region
33  */
34 struct scmi_power_domain_priv {
35         int num_pwdoms;
36         struct scmi_pwd_properties *prop;
37         u64 stats_addr;
38         size_t stats_len;
39 };
40
41 /**
42  * async_is_supported - check asynchronous transition
43  * @attributes: Power domain attributes
44  *
45  * Determine if the power transition can be done asynchronously.
46  *
47  * Return: true if supported, false if not
48  */
49 static bool async_is_supported(u32 attributes)
50 {
51         if (attributes & SCMI_PWD_ATTR_PSTATE_ASYNC)
52                 return true;
53
54         /* TODO: check attributes && SCMI_PWD_ATTR_PSTATE_SYNC */
55         return false;
56 }
57
58 /**
59  * scmi_power_domain_on - Enable the power domain
60  * @power_domain:       Power domain
61  *
62  * Turn on the power domain.
63  *
64  * Return: 0 on success, error code on failure
65  */
66 static int scmi_power_domain_on(struct power_domain *power_domain)
67 {
68         struct scmi_power_domain_priv *priv = dev_get_priv(power_domain->dev);
69         u32 flags, pstate;
70         int ret;
71
72         if (power_domain->id > priv->num_pwdoms)
73                 return -EINVAL;
74
75         if (async_is_supported(priv->prop[power_domain->id].attributes))
76                 flags = SCMI_PWD_SET_FLAGS_ASYNC;
77         else
78                 flags = 0;
79
80         /* ON */
81         pstate = 0;
82
83         ret = scmi_pwd_state_set(power_domain->dev, flags, power_domain->id,
84                                  pstate);
85         if (ret) {
86                 dev_err(power_domain->dev, "failed to set the state on (%d)\n",
87                         ret);
88                 return ret;
89         }
90
91         return 0;
92 }
93
94 /**
95  * scmi_power_domain_off - Disable the power domain
96  * @power_domain:       Power domain
97  *
98  * Turn off the power domain.
99  *
100  * Return: 0 on success, error code on failure
101  */
102 static int scmi_power_domain_off(struct power_domain *power_domain)
103 {
104         struct scmi_power_domain_priv *priv = dev_get_priv(power_domain->dev);
105         u32 flags, pstate;
106         int ret;
107
108         if (power_domain->id > priv->num_pwdoms)
109                 return -EINVAL;
110
111         if (async_is_supported(priv->prop[power_domain->id].attributes))
112                 flags = SCMI_PWD_SET_FLAGS_ASYNC;
113         else
114                 flags = 0;
115
116         /* OFF */
117         pstate = SCMI_PWD_PSTATE_TYPE_LOST;
118
119         ret = scmi_pwd_state_set(power_domain->dev, flags, power_domain->id,
120                                  pstate);
121         if (ret) {
122                 dev_err(power_domain->dev, "failed to set the state off (%d)\n",
123                         ret);
124                 return ret;
125         }
126
127         return 0;
128 }
129
130 /**
131  * scmi_power_domain_probe - Probe the power domain
132  * @dev:        Power domain device
133  *
134  * Probe the power domain and initialize the properties.
135  *
136  * Return: 0 on success, error code on failure
137  */
138 static int scmi_power_domain_probe(struct udevice *dev)
139 {
140         struct scmi_power_domain_priv *priv = dev_get_priv(dev);
141         u32 version;
142         int i, ret;
143
144         ret = devm_scmi_of_get_channel(dev);
145         if (ret) {
146                 dev_err(dev, "failed to get channel (%d)\n", ret);
147                 return ret;
148         }
149
150         ret = scmi_generic_protocol_version(dev, SCMI_PROTOCOL_ID_POWER_DOMAIN,
151                                             &version);
152
153         ret = scmi_pwd_protocol_attrs(dev, &priv->num_pwdoms, &priv->stats_addr,
154                                       &priv->stats_len);
155         if (ret) {
156                 dev_err(dev, "failed to get protocol attributes (%d)\n", ret);
157                 return ret;
158         }
159
160         priv->prop = calloc(sizeof(*priv->prop), priv->num_pwdoms);
161         if (!priv->prop)
162                 return -ENOMEM;
163
164         for (i = 0; i < priv->num_pwdoms; i++) {
165                 ret = scmi_pwd_attrs(dev, i, &priv->prop[i].attributes,
166                                      &priv->prop[i].name);
167                 if (ret) {
168                         dev_err(dev, "failed to get attributes pwd:%d (%d)\n",
169                                 i, ret);
170                         for (i--; i >= 0; i--)
171                                 free(priv->prop[i].name);
172                         free(priv->prop);
173
174                         return ret;
175                 }
176         }
177
178         return 0;
179 }
180
181 struct power_domain_ops scmi_power_domain_ops = {
182         .on = scmi_power_domain_on,
183         .off = scmi_power_domain_off,
184 };
185
186 U_BOOT_DRIVER(scmi_power_domain) = {
187         .name = "scmi_power_domain",
188         .id = UCLASS_POWER_DOMAIN,
189         .ops = &scmi_power_domain_ops,
190         .probe = scmi_power_domain_probe,
191         .priv_auto = sizeof(struct scmi_power_domain_priv),
192 };
This page took 0.042515 seconds and 4 git commands to generate.