0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/err.h>
0013 #include <linux/list.h>
0014 #include <linux/module.h>
0015 #include <linux/of_platform.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/pm_domain.h>
0018 #include <linux/slab.h>
0019
0020 #include <linux/firmware/xlnx-zynqmp.h>
0021
0022 #define ZYNQMP_NUM_DOMAINS (100)
0023
0024 static int min_capability;
0025
0026
0027
0028
0029
0030
0031
0032 struct zynqmp_pm_domain {
0033 struct generic_pm_domain gpd;
0034 u32 node_id;
0035 bool requested;
0036 };
0037
0038 #define to_zynqmp_pm_domain(pm_domain) \
0039 container_of(pm_domain, struct zynqmp_pm_domain, gpd)
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 static int zynqmp_gpd_is_active_wakeup_path(struct device *dev, void *not_used)
0053 {
0054 int may_wakeup;
0055
0056 may_wakeup = device_may_wakeup(dev);
0057 if (may_wakeup)
0058 return may_wakeup;
0059
0060 return device_for_each_child(dev, NULL,
0061 zynqmp_gpd_is_active_wakeup_path);
0062 }
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073 static int zynqmp_gpd_power_on(struct generic_pm_domain *domain)
0074 {
0075 struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
0076 int ret;
0077
0078 ret = zynqmp_pm_set_requirement(pd->node_id,
0079 ZYNQMP_PM_CAPABILITY_ACCESS,
0080 ZYNQMP_PM_MAX_QOS,
0081 ZYNQMP_PM_REQUEST_ACK_BLOCKING);
0082 if (ret) {
0083 dev_err(&domain->dev,
0084 "failed to set requirement to 0x%x for PM node id %d: %d\n",
0085 ZYNQMP_PM_CAPABILITY_ACCESS, pd->node_id, ret);
0086 return ret;
0087 }
0088
0089 dev_dbg(&domain->dev, "set requirement to 0x%x for PM node id %d\n",
0090 ZYNQMP_PM_CAPABILITY_ACCESS, pd->node_id);
0091
0092 return 0;
0093 }
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 static int zynqmp_gpd_power_off(struct generic_pm_domain *domain)
0105 {
0106 struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
0107 int ret;
0108 struct pm_domain_data *pdd, *tmp;
0109 u32 capabilities = min_capability;
0110 bool may_wakeup;
0111
0112
0113 if (!pd->requested) {
0114 dev_dbg(&domain->dev, "PM node id %d is already released\n",
0115 pd->node_id);
0116 return 0;
0117 }
0118
0119 list_for_each_entry_safe(pdd, tmp, &domain->dev_list, list_node) {
0120
0121 may_wakeup = zynqmp_gpd_is_active_wakeup_path(pdd->dev, NULL);
0122 if (may_wakeup) {
0123 dev_dbg(pdd->dev, "device is in wakeup path in %s\n",
0124 domain->name);
0125 capabilities = ZYNQMP_PM_CAPABILITY_WAKEUP;
0126 break;
0127 }
0128 }
0129
0130 ret = zynqmp_pm_set_requirement(pd->node_id, capabilities, 0,
0131 ZYNQMP_PM_REQUEST_ACK_NO);
0132 if (ret) {
0133 dev_err(&domain->dev,
0134 "failed to set requirement to 0x%x for PM node id %d: %d\n",
0135 capabilities, pd->node_id, ret);
0136 return ret;
0137 }
0138
0139 dev_dbg(&domain->dev, "set requirement to 0x%x for PM node id %d\n",
0140 capabilities, pd->node_id);
0141
0142 return 0;
0143 }
0144
0145
0146
0147
0148
0149
0150
0151
0152 static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain,
0153 struct device *dev)
0154 {
0155 struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
0156 struct device_link *link;
0157 int ret;
0158
0159 link = device_link_add(dev, &domain->dev, DL_FLAG_SYNC_STATE_ONLY);
0160 if (!link)
0161 dev_dbg(&domain->dev, "failed to create device link for %s\n",
0162 dev_name(dev));
0163
0164
0165 if (domain->device_count)
0166 return 0;
0167
0168 ret = zynqmp_pm_request_node(pd->node_id, 0, 0,
0169 ZYNQMP_PM_REQUEST_ACK_BLOCKING);
0170 if (ret) {
0171 dev_err(&domain->dev, "%s request failed for node %d: %d\n",
0172 domain->name, pd->node_id, ret);
0173 return ret;
0174 }
0175
0176 pd->requested = true;
0177
0178 dev_dbg(&domain->dev, "%s requested PM node id %d\n",
0179 dev_name(dev), pd->node_id);
0180
0181 return 0;
0182 }
0183
0184
0185
0186
0187
0188
0189 static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain,
0190 struct device *dev)
0191 {
0192 struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain);
0193 int ret;
0194
0195
0196 if (domain->device_count)
0197 return;
0198
0199 ret = zynqmp_pm_release_node(pd->node_id);
0200 if (ret) {
0201 dev_err(&domain->dev, "failed to release PM node id %d: %d\n",
0202 pd->node_id, ret);
0203 return;
0204 }
0205
0206 pd->requested = false;
0207
0208 dev_dbg(&domain->dev, "%s released PM node id %d\n",
0209 dev_name(dev), pd->node_id);
0210 }
0211
0212 static struct generic_pm_domain *zynqmp_gpd_xlate
0213 (struct of_phandle_args *genpdspec, void *data)
0214 {
0215 struct genpd_onecell_data *genpd_data = data;
0216 unsigned int i, idx = genpdspec->args[0];
0217 struct zynqmp_pm_domain *pd;
0218
0219 pd = to_zynqmp_pm_domain(genpd_data->domains[0]);
0220
0221 if (genpdspec->args_count != 1)
0222 return ERR_PTR(-EINVAL);
0223
0224
0225 for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++) {
0226 if (pd[i].node_id == idx)
0227 goto done;
0228 }
0229
0230
0231
0232
0233
0234 for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++) {
0235 if (pd[i].node_id == 0) {
0236 pd[i].node_id = idx;
0237 break;
0238 }
0239 }
0240
0241 done:
0242 if (!genpd_data->domains[i] || i == ZYNQMP_NUM_DOMAINS)
0243 return ERR_PTR(-ENOENT);
0244
0245 return genpd_data->domains[i];
0246 }
0247
0248 static int zynqmp_gpd_probe(struct platform_device *pdev)
0249 {
0250 int i;
0251 struct genpd_onecell_data *zynqmp_pd_data;
0252 struct generic_pm_domain **domains;
0253 struct zynqmp_pm_domain *pd;
0254 struct device *dev = &pdev->dev;
0255
0256 pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL);
0257 if (!pd)
0258 return -ENOMEM;
0259
0260 zynqmp_pd_data = devm_kzalloc(dev, sizeof(*zynqmp_pd_data), GFP_KERNEL);
0261 if (!zynqmp_pd_data)
0262 return -ENOMEM;
0263
0264 zynqmp_pd_data->xlate = zynqmp_gpd_xlate;
0265
0266 domains = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*domains),
0267 GFP_KERNEL);
0268 if (!domains)
0269 return -ENOMEM;
0270
0271 if (!of_device_is_compatible(dev->parent->of_node,
0272 "xlnx,zynqmp-firmware"))
0273 min_capability = ZYNQMP_PM_CAPABILITY_UNUSABLE;
0274
0275 for (i = 0; i < ZYNQMP_NUM_DOMAINS; i++, pd++) {
0276 pd->node_id = 0;
0277 pd->gpd.name = kasprintf(GFP_KERNEL, "domain%d", i);
0278 pd->gpd.power_off = zynqmp_gpd_power_off;
0279 pd->gpd.power_on = zynqmp_gpd_power_on;
0280 pd->gpd.attach_dev = zynqmp_gpd_attach_dev;
0281 pd->gpd.detach_dev = zynqmp_gpd_detach_dev;
0282
0283 domains[i] = &pd->gpd;
0284
0285
0286 pm_genpd_init(&pd->gpd, NULL, true);
0287 }
0288
0289 zynqmp_pd_data->domains = domains;
0290 zynqmp_pd_data->num_domains = ZYNQMP_NUM_DOMAINS;
0291 of_genpd_add_provider_onecell(dev->parent->of_node, zynqmp_pd_data);
0292
0293 return 0;
0294 }
0295
0296 static int zynqmp_gpd_remove(struct platform_device *pdev)
0297 {
0298 of_genpd_del_provider(pdev->dev.parent->of_node);
0299
0300 return 0;
0301 }
0302
0303 static void zynqmp_gpd_sync_state(struct device *dev)
0304 {
0305 int ret;
0306
0307 ret = zynqmp_pm_init_finalize();
0308 if (ret)
0309 dev_warn(dev, "failed to release power management to firmware\n");
0310 }
0311
0312 static struct platform_driver zynqmp_power_domain_driver = {
0313 .driver = {
0314 .name = "zynqmp_power_controller",
0315 .sync_state = zynqmp_gpd_sync_state,
0316 },
0317 .probe = zynqmp_gpd_probe,
0318 .remove = zynqmp_gpd_remove,
0319 };
0320 module_platform_driver(zynqmp_power_domain_driver);
0321
0322 MODULE_ALIAS("platform:zynqmp_power_controller");