1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
7 #include <linux/platform_device.h>
8 #include <linux/pm_domain.h>
9 #include <linux/slab.h>
10 #include <linux/version.h>
12 #include <soc/tegra/bpmp.h>
13 #include <soc/tegra/bpmp-abi.h>
15 struct tegra_powergate_info
{
20 struct tegra_powergate
{
21 struct generic_pm_domain genpd
;
22 struct tegra_bpmp
*bpmp
;
26 static inline struct tegra_powergate
*
27 to_tegra_powergate(struct generic_pm_domain
*genpd
)
29 return container_of(genpd
, struct tegra_powergate
, genpd
);
32 static int tegra_bpmp_powergate_set_state(struct tegra_bpmp
*bpmp
,
33 unsigned int id
, u32 state
)
35 struct mrq_pg_request request
;
36 struct tegra_bpmp_message msg
;
39 memset(&request
, 0, sizeof(request
));
40 request
.cmd
= CMD_PG_SET_STATE
;
42 request
.set_state
.state
= state
;
44 memset(&msg
, 0, sizeof(msg
));
46 msg
.tx
.data
= &request
;
47 msg
.tx
.size
= sizeof(request
);
49 err
= tegra_bpmp_transfer(bpmp
, &msg
);
52 else if (msg
.rx
.ret
< 0)
58 static int tegra_bpmp_powergate_get_state(struct tegra_bpmp
*bpmp
,
61 struct mrq_pg_response response
;
62 struct mrq_pg_request request
;
63 struct tegra_bpmp_message msg
;
66 memset(&request
, 0, sizeof(request
));
67 request
.cmd
= CMD_PG_GET_STATE
;
70 memset(&response
, 0, sizeof(response
));
72 memset(&msg
, 0, sizeof(msg
));
74 msg
.tx
.data
= &request
;
75 msg
.tx
.size
= sizeof(request
);
76 msg
.rx
.data
= &response
;
77 msg
.rx
.size
= sizeof(response
);
79 err
= tegra_bpmp_transfer(bpmp
, &msg
);
82 else if (msg
.rx
.ret
< 0)
85 return response
.get_state
.state
;
88 static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp
*bpmp
)
90 struct mrq_pg_response response
;
91 struct mrq_pg_request request
;
92 struct tegra_bpmp_message msg
;
95 memset(&request
, 0, sizeof(request
));
96 request
.cmd
= CMD_PG_GET_MAX_ID
;
98 memset(&response
, 0, sizeof(response
));
100 memset(&msg
, 0, sizeof(msg
));
102 msg
.tx
.data
= &request
;
103 msg
.tx
.size
= sizeof(request
);
104 msg
.rx
.data
= &response
;
105 msg
.rx
.size
= sizeof(response
);
107 err
= tegra_bpmp_transfer(bpmp
, &msg
);
110 else if (msg
.rx
.ret
< 0)
113 return response
.get_max_id
.max_id
;
116 static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp
*bpmp
,
119 struct mrq_pg_response response
;
120 struct mrq_pg_request request
;
121 struct tegra_bpmp_message msg
;
124 memset(&request
, 0, sizeof(request
));
125 request
.cmd
= CMD_PG_GET_NAME
;
128 memset(&response
, 0, sizeof(response
));
130 memset(&msg
, 0, sizeof(msg
));
132 msg
.tx
.data
= &request
;
133 msg
.tx
.size
= sizeof(request
);
134 msg
.rx
.data
= &response
;
135 msg
.rx
.size
= sizeof(response
);
137 err
= tegra_bpmp_transfer(bpmp
, &msg
);
138 if (err
< 0 || msg
.rx
.ret
< 0)
141 return kstrdup(response
.get_name
.name
, GFP_KERNEL
);
144 static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp
*bpmp
,
147 return tegra_bpmp_powergate_get_state(bpmp
, id
) != PG_STATE_OFF
;
150 static int tegra_powergate_power_on(struct generic_pm_domain
*domain
)
152 struct tegra_powergate
*powergate
= to_tegra_powergate(domain
);
153 struct tegra_bpmp
*bpmp
= powergate
->bpmp
;
155 return tegra_bpmp_powergate_set_state(bpmp
, powergate
->id
,
159 static int tegra_powergate_power_off(struct generic_pm_domain
*domain
)
161 struct tegra_powergate
*powergate
= to_tegra_powergate(domain
);
162 struct tegra_bpmp
*bpmp
= powergate
->bpmp
;
164 return tegra_bpmp_powergate_set_state(bpmp
, powergate
->id
,
168 static struct tegra_powergate
*
169 tegra_powergate_add(struct tegra_bpmp
*bpmp
,
170 const struct tegra_powergate_info
*info
)
172 struct tegra_powergate
*powergate
;
176 off
= !tegra_bpmp_powergate_is_powered(bpmp
, info
->id
);
178 powergate
= devm_kzalloc(bpmp
->dev
, sizeof(*powergate
), GFP_KERNEL
);
180 return ERR_PTR(-ENOMEM
);
182 powergate
->id
= info
->id
;
183 powergate
->bpmp
= bpmp
;
185 powergate
->genpd
.name
= kstrdup(info
->name
, GFP_KERNEL
);
186 powergate
->genpd
.power_on
= tegra_powergate_power_on
;
187 powergate
->genpd
.power_off
= tegra_powergate_power_off
;
189 err
= pm_genpd_init(&powergate
->genpd
, NULL
, off
);
191 kfree(powergate
->genpd
.name
);
198 static void tegra_powergate_remove(struct tegra_powergate
*powergate
)
200 struct generic_pm_domain
*genpd
= &powergate
->genpd
;
201 struct tegra_bpmp
*bpmp
= powergate
->bpmp
;
204 err
= pm_genpd_remove(genpd
);
206 dev_err(bpmp
->dev
, "failed to remove power domain %s: %d\n",
213 tegra_bpmp_probe_powergates(struct tegra_bpmp
*bpmp
,
214 struct tegra_powergate_info
**powergatesp
)
216 struct tegra_powergate_info
*powergates
;
217 unsigned int max_id
, id
, count
= 0;
218 unsigned int num_holes
= 0;
221 err
= tegra_bpmp_powergate_get_max_id(bpmp
);
227 dev_dbg(bpmp
->dev
, "maximum powergate ID: %u\n", max_id
);
229 powergates
= kcalloc(max_id
+ 1, sizeof(*powergates
), GFP_KERNEL
);
233 for (id
= 0; id
<= max_id
; id
++) {
234 struct tegra_powergate_info
*info
= &powergates
[count
];
236 info
->name
= tegra_bpmp_powergate_get_name(bpmp
, id
);
237 if (!info
->name
|| info
->name
[0] == '\0') {
246 dev_dbg(bpmp
->dev
, "holes: %u\n", num_holes
);
248 *powergatesp
= powergates
;
253 static int tegra_bpmp_add_powergates(struct tegra_bpmp
*bpmp
,
254 struct tegra_powergate_info
*powergates
,
257 struct genpd_onecell_data
*genpd
= &bpmp
->genpd
;
258 struct generic_pm_domain
**domains
;
259 struct tegra_powergate
*powergate
;
263 domains
= kcalloc(count
, sizeof(*domains
), GFP_KERNEL
);
267 for (i
= 0; i
< count
; i
++) {
268 powergate
= tegra_powergate_add(bpmp
, &powergates
[i
]);
269 if (IS_ERR(powergate
)) {
270 err
= PTR_ERR(powergate
);
274 dev_dbg(bpmp
->dev
, "added power domain %s\n",
275 powergate
->genpd
.name
);
276 domains
[i
] = &powergate
->genpd
;
279 genpd
->num_domains
= count
;
280 genpd
->domains
= domains
;
286 powergate
= to_tegra_powergate(domains
[i
]);
287 tegra_powergate_remove(powergate
);
290 kfree(genpd
->domains
);
294 static void tegra_bpmp_remove_powergates(struct tegra_bpmp
*bpmp
)
296 struct genpd_onecell_data
*genpd
= &bpmp
->genpd
;
297 unsigned int i
= genpd
->num_domains
;
298 struct tegra_powergate
*powergate
;
301 dev_dbg(bpmp
->dev
, "removing power domain %s\n",
302 genpd
->domains
[i
]->name
);
303 powergate
= to_tegra_powergate(genpd
->domains
[i
]);
304 tegra_powergate_remove(powergate
);
308 static struct generic_pm_domain
*
309 tegra_powergate_xlate(struct of_phandle_args
*spec
, void *data
)
311 struct generic_pm_domain
*domain
= ERR_PTR(-ENOENT
);
312 struct genpd_onecell_data
*genpd
= data
;
315 for (i
= 0; i
< genpd
->num_domains
; i
++) {
316 struct tegra_powergate
*powergate
;
318 powergate
= to_tegra_powergate(genpd
->domains
[i
]);
319 if (powergate
->id
== spec
->args
[0]) {
320 domain
= &powergate
->genpd
;
328 int tegra_bpmp_init_powergates(struct tegra_bpmp
*bpmp
)
330 struct device_node
*np
= bpmp
->dev
->of_node
;
331 struct tegra_powergate_info
*powergates
;
332 struct device
*dev
= bpmp
->dev
;
333 unsigned int count
, i
;
336 err
= tegra_bpmp_probe_powergates(bpmp
, &powergates
);
342 dev_dbg(dev
, "%u power domains probed\n", count
);
344 err
= tegra_bpmp_add_powergates(bpmp
, powergates
, count
);
348 bpmp
->genpd
.xlate
= tegra_powergate_xlate
;
350 err
= of_genpd_add_provider_onecell(np
, &bpmp
->genpd
);
352 dev_err(dev
, "failed to add power domain provider: %d\n", err
);
353 tegra_bpmp_remove_powergates(bpmp
);
357 for (i
= 0; i
< count
; i
++)
358 kfree(powergates
[i
].name
);