2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 #include <linux/platform_device.h>
16 #include <linux/pm_domain.h>
17 #include <linux/slab.h>
18 #include <linux/version.h>
20 #include <soc/tegra/bpmp.h>
21 #include <soc/tegra/bpmp-abi.h>
23 struct tegra_powergate_info
{
28 struct tegra_powergate
{
29 struct generic_pm_domain genpd
;
30 struct tegra_bpmp
*bpmp
;
34 static inline struct tegra_powergate
*
35 to_tegra_powergate(struct generic_pm_domain
*genpd
)
37 return container_of(genpd
, struct tegra_powergate
, genpd
);
40 static int tegra_bpmp_powergate_set_state(struct tegra_bpmp
*bpmp
,
41 unsigned int id
, u32 state
)
43 struct mrq_pg_request request
;
44 struct tegra_bpmp_message msg
;
47 memset(&request
, 0, sizeof(request
));
48 request
.cmd
= CMD_PG_SET_STATE
;
50 request
.set_state
.state
= state
;
52 memset(&msg
, 0, sizeof(msg
));
54 msg
.tx
.data
= &request
;
55 msg
.tx
.size
= sizeof(request
);
57 err
= tegra_bpmp_transfer(bpmp
, &msg
);
60 else if (msg
.rx
.ret
< 0)
66 static int tegra_bpmp_powergate_get_state(struct tegra_bpmp
*bpmp
,
69 struct mrq_pg_response response
;
70 struct mrq_pg_request request
;
71 struct tegra_bpmp_message msg
;
74 memset(&request
, 0, sizeof(request
));
75 request
.cmd
= CMD_PG_GET_STATE
;
78 memset(&response
, 0, sizeof(response
));
80 memset(&msg
, 0, sizeof(msg
));
82 msg
.tx
.data
= &request
;
83 msg
.tx
.size
= sizeof(request
);
84 msg
.rx
.data
= &response
;
85 msg
.rx
.size
= sizeof(response
);
87 err
= tegra_bpmp_transfer(bpmp
, &msg
);
90 else if (msg
.rx
.ret
< 0)
93 return response
.get_state
.state
;
96 static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp
*bpmp
)
98 struct mrq_pg_response response
;
99 struct mrq_pg_request request
;
100 struct tegra_bpmp_message msg
;
103 memset(&request
, 0, sizeof(request
));
104 request
.cmd
= CMD_PG_GET_MAX_ID
;
106 memset(&response
, 0, sizeof(response
));
108 memset(&msg
, 0, sizeof(msg
));
110 msg
.tx
.data
= &request
;
111 msg
.tx
.size
= sizeof(request
);
112 msg
.rx
.data
= &response
;
113 msg
.rx
.size
= sizeof(response
);
115 err
= tegra_bpmp_transfer(bpmp
, &msg
);
118 else if (msg
.rx
.ret
< 0)
121 return response
.get_max_id
.max_id
;
124 static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp
*bpmp
,
127 struct mrq_pg_response response
;
128 struct mrq_pg_request request
;
129 struct tegra_bpmp_message msg
;
132 memset(&request
, 0, sizeof(request
));
133 request
.cmd
= CMD_PG_GET_NAME
;
136 memset(&response
, 0, sizeof(response
));
138 memset(&msg
, 0, sizeof(msg
));
140 msg
.tx
.data
= &request
;
141 msg
.tx
.size
= sizeof(request
);
142 msg
.rx
.data
= &response
;
143 msg
.rx
.size
= sizeof(response
);
145 err
= tegra_bpmp_transfer(bpmp
, &msg
);
146 if (err
< 0 || msg
.rx
.ret
< 0)
149 return kstrdup(response
.get_name
.name
, GFP_KERNEL
);
152 static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp
*bpmp
,
155 return tegra_bpmp_powergate_get_state(bpmp
, id
) != PG_STATE_OFF
;
158 static int tegra_powergate_power_on(struct generic_pm_domain
*domain
)
160 struct tegra_powergate
*powergate
= to_tegra_powergate(domain
);
161 struct tegra_bpmp
*bpmp
= powergate
->bpmp
;
163 return tegra_bpmp_powergate_set_state(bpmp
, powergate
->id
,
167 static int tegra_powergate_power_off(struct generic_pm_domain
*domain
)
169 struct tegra_powergate
*powergate
= to_tegra_powergate(domain
);
170 struct tegra_bpmp
*bpmp
= powergate
->bpmp
;
172 return tegra_bpmp_powergate_set_state(bpmp
, powergate
->id
,
176 static struct tegra_powergate
*
177 tegra_powergate_add(struct tegra_bpmp
*bpmp
,
178 const struct tegra_powergate_info
*info
)
180 struct tegra_powergate
*powergate
;
184 off
= !tegra_bpmp_powergate_is_powered(bpmp
, info
->id
);
186 powergate
= devm_kzalloc(bpmp
->dev
, sizeof(*powergate
), GFP_KERNEL
);
188 return ERR_PTR(-ENOMEM
);
190 powergate
->id
= info
->id
;
191 powergate
->bpmp
= bpmp
;
193 powergate
->genpd
.name
= kstrdup(info
->name
, GFP_KERNEL
);
194 powergate
->genpd
.power_on
= tegra_powergate_power_on
;
195 powergate
->genpd
.power_off
= tegra_powergate_power_off
;
197 err
= pm_genpd_init(&powergate
->genpd
, NULL
, off
);
199 kfree(powergate
->genpd
.name
);
206 static void tegra_powergate_remove(struct tegra_powergate
*powergate
)
208 struct generic_pm_domain
*genpd
= &powergate
->genpd
;
209 struct tegra_bpmp
*bpmp
= powergate
->bpmp
;
212 err
= pm_genpd_remove(genpd
);
214 dev_err(bpmp
->dev
, "failed to remove power domain %s: %d\n",
221 tegra_bpmp_probe_powergates(struct tegra_bpmp
*bpmp
,
222 struct tegra_powergate_info
**powergatesp
)
224 struct tegra_powergate_info
*powergates
;
225 unsigned int max_id
, id
, count
= 0;
226 unsigned int num_holes
= 0;
229 err
= tegra_bpmp_powergate_get_max_id(bpmp
);
235 dev_dbg(bpmp
->dev
, "maximum powergate ID: %u\n", max_id
);
237 powergates
= kcalloc(max_id
+ 1, sizeof(*powergates
), GFP_KERNEL
);
241 for (id
= 0; id
<= max_id
; id
++) {
242 struct tegra_powergate_info
*info
= &powergates
[count
];
244 info
->name
= tegra_bpmp_powergate_get_name(bpmp
, id
);
245 if (!info
->name
|| info
->name
[0] == '\0') {
254 dev_dbg(bpmp
->dev
, "holes: %u\n", num_holes
);
256 *powergatesp
= powergates
;
261 static int tegra_bpmp_add_powergates(struct tegra_bpmp
*bpmp
,
262 struct tegra_powergate_info
*powergates
,
265 struct genpd_onecell_data
*genpd
= &bpmp
->genpd
;
266 struct generic_pm_domain
**domains
;
267 struct tegra_powergate
*powergate
;
271 domains
= kcalloc(count
, sizeof(*domains
), GFP_KERNEL
);
275 for (i
= 0; i
< count
; i
++) {
276 powergate
= tegra_powergate_add(bpmp
, &powergates
[i
]);
277 if (IS_ERR(powergate
)) {
278 err
= PTR_ERR(powergate
);
282 dev_dbg(bpmp
->dev
, "added power domain %s\n",
283 powergate
->genpd
.name
);
284 domains
[i
] = &powergate
->genpd
;
287 genpd
->num_domains
= count
;
288 genpd
->domains
= domains
;
294 powergate
= to_tegra_powergate(domains
[i
]);
295 tegra_powergate_remove(powergate
);
298 kfree(genpd
->domains
);
302 static void tegra_bpmp_remove_powergates(struct tegra_bpmp
*bpmp
)
304 struct genpd_onecell_data
*genpd
= &bpmp
->genpd
;
305 unsigned int i
= genpd
->num_domains
;
306 struct tegra_powergate
*powergate
;
309 dev_dbg(bpmp
->dev
, "removing power domain %s\n",
310 genpd
->domains
[i
]->name
);
311 powergate
= to_tegra_powergate(genpd
->domains
[i
]);
312 tegra_powergate_remove(powergate
);
316 static struct generic_pm_domain
*
317 tegra_powergate_xlate(struct of_phandle_args
*spec
, void *data
)
319 struct generic_pm_domain
*domain
= ERR_PTR(-ENOENT
);
320 struct genpd_onecell_data
*genpd
= data
;
323 for (i
= 0; i
< genpd
->num_domains
; i
++) {
324 struct tegra_powergate
*powergate
;
326 powergate
= to_tegra_powergate(genpd
->domains
[i
]);
327 if (powergate
->id
== spec
->args
[0]) {
328 domain
= &powergate
->genpd
;
336 int tegra_bpmp_init_powergates(struct tegra_bpmp
*bpmp
)
338 struct device_node
*np
= bpmp
->dev
->of_node
;
339 struct tegra_powergate_info
*powergates
;
340 struct device
*dev
= bpmp
->dev
;
341 unsigned int count
, i
;
344 err
= tegra_bpmp_probe_powergates(bpmp
, &powergates
);
350 dev_dbg(dev
, "%u power domains probed\n", count
);
352 err
= tegra_bpmp_add_powergates(bpmp
, powergates
, count
);
356 bpmp
->genpd
.xlate
= tegra_powergate_xlate
;
358 err
= of_genpd_add_provider_onecell(np
, &bpmp
->genpd
);
360 dev_err(dev
, "failed to add power domain provider: %d\n", err
);
361 tegra_bpmp_remove_powergates(bpmp
);
365 for (i
= 0; i
< count
; i
++)
366 kfree(powergates
[i
].name
);