* @power: Optional power domain devices.
*
* On platforms with more than one power domain for the GPU, they are
- * stored here in @domain_devs, along with links between them in
- * @domain_links. The size of @domain_devs is given by @domain_count,
- * while the size of @domain_links is (2 * @domain_count) - 1.
+ * stored here in @domains, along with links between them in
+ * @domain_links. The size of @domain_links is one less than
+ * struct dev_pm_domain_list->num_pds in @domains.
*/
struct pvr_device_power {
- struct device **domain_devs;
+ struct dev_pm_domain_list *domains;
struct device_link **domain_links;
-
- u32 domain_count;
} power;
/**
int pvr_power_domains_init(struct pvr_device *pvr_dev)
{
- struct device *dev = from_pvr_device(pvr_dev)->dev;
+ static const char *const ROGUE_PD_NAMES[] = { "a", "b", "c", "d", "e" };
+
+ struct drm_device *drm_dev = from_pvr_device(pvr_dev);
+ struct device *dev = drm_dev->dev;
struct device_link **domain_links __free(kfree) = NULL;
- struct device **domain_devs __free(kfree) = NULL;
+ struct dev_pm_domain_list *domains = NULL;
int domain_count;
int link_count;
- char dev_name[2] = "a";
int err;
int i;
if (domain_count <= 1)
return 0;
- link_count = domain_count + (domain_count - 1);
+ if (domain_count > ARRAY_SIZE(ROGUE_PD_NAMES)) {
+ drm_err(drm_dev, "%s() only supports %zu domains on Rogue",
+ __func__, ARRAY_SIZE(ROGUE_PD_NAMES));
+ return -EOPNOTSUPP;
+ }
- domain_devs = kcalloc(domain_count, sizeof(*domain_devs), GFP_KERNEL);
- if (!domain_devs)
- return -ENOMEM;
+ link_count = domain_count - 1;
domain_links = kcalloc(link_count, sizeof(*domain_links), GFP_KERNEL);
if (!domain_links)
return -ENOMEM;
- for (i = 0; i < domain_count; i++) {
- struct device *domain_dev;
-
- dev_name[0] = 'a' + i;
- domain_dev = dev_pm_domain_attach_by_name(dev, dev_name);
- if (IS_ERR_OR_NULL(domain_dev)) {
- err = domain_dev ? PTR_ERR(domain_dev) : -ENODEV;
- goto err_detach;
- }
-
- domain_devs[i] = domain_dev;
- }
-
- for (i = 0; i < domain_count; i++) {
- struct device_link *link;
-
- link = device_link_add(dev, domain_devs[i], DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
- if (!link) {
- err = -ENODEV;
- goto err_unlink;
- }
+ const struct dev_pm_domain_attach_data pd_attach_data = {
+ .pd_names = ROGUE_PD_NAMES,
+ .num_pd_names = domain_count,
+ .pd_flags = 0,
+ };
- domain_links[i] = link;
- }
+ err = dev_pm_domain_attach_list(dev, &pd_attach_data, &domains);
+ if (err < 0)
+ return err;
- for (i = domain_count; i < link_count; i++) {
+ for (i = 0; i < link_count; i++) {
struct device_link *link;
- link = device_link_add(domain_devs[i - domain_count + 1],
- domain_devs[i - domain_count],
+ link = device_link_add(domains->pd_devs[i + 1],
+ domains->pd_devs[i],
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME);
if (!link) {
err = -ENODEV;
}
pvr_dev->power = (struct pvr_device_power){
- .domain_devs = no_free_ptr(domain_devs),
+ .domains = domains,
.domain_links = no_free_ptr(domain_links),
- .domain_count = domain_count,
};
return 0;
while (--i >= 0)
device_link_del(domain_links[i]);
- i = domain_count;
-
-err_detach:
- while (--i >= 0)
- dev_pm_domain_detach(domain_devs[i], true);
-
return err;
}
void pvr_power_domains_fini(struct pvr_device *pvr_dev)
{
- const int domain_count = pvr_dev->power.domain_count;
+ struct pvr_device_power *pvr_power = &pvr_dev->power;
- int i = domain_count + (domain_count - 1);
+ int i = (int)pvr_power->domains->num_pds - 1;
while (--i >= 0)
- device_link_del(pvr_dev->power.domain_links[i]);
-
- i = domain_count;
+ device_link_del(pvr_power->domain_links[i]);
- while (--i >= 0)
- dev_pm_domain_detach(pvr_dev->power.domain_devs[i], true);
+ dev_pm_domain_detach_list(pvr_power->domains);
- kfree(pvr_dev->power.domain_links);
- kfree(pvr_dev->power.domain_devs);
+ kfree(pvr_power->domain_links);
- pvr_dev->power = (struct pvr_device_power){ 0 };
+ *pvr_power = (struct pvr_device_power){ 0 };
}