Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
0004  */
0005 
0006 #include <linux/of.h>
0007 #include <linux/platform_device.h>
0008 #include <linux/pm_domain.h>
0009 #include <linux/slab.h>
0010 
0011 #include <soc/tegra/bpmp.h>
0012 #include <soc/tegra/bpmp-abi.h>
0013 
0014 struct tegra_powergate_info {
0015     unsigned int id;
0016     char *name;
0017 };
0018 
0019 struct tegra_powergate {
0020     struct generic_pm_domain genpd;
0021     struct tegra_bpmp *bpmp;
0022     unsigned int id;
0023 };
0024 
0025 static inline struct tegra_powergate *
0026 to_tegra_powergate(struct generic_pm_domain *genpd)
0027 {
0028     return container_of(genpd, struct tegra_powergate, genpd);
0029 }
0030 
0031 static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp,
0032                       unsigned int id, u32 state)
0033 {
0034     struct mrq_pg_request request;
0035     struct tegra_bpmp_message msg;
0036     int err;
0037 
0038     memset(&request, 0, sizeof(request));
0039     request.cmd = CMD_PG_SET_STATE;
0040     request.id = id;
0041     request.set_state.state = state;
0042 
0043     memset(&msg, 0, sizeof(msg));
0044     msg.mrq = MRQ_PG;
0045     msg.tx.data = &request;
0046     msg.tx.size = sizeof(request);
0047 
0048     err = tegra_bpmp_transfer(bpmp, &msg);
0049     if (err < 0)
0050         return err;
0051     else if (msg.rx.ret < 0)
0052         return -EINVAL;
0053 
0054     return 0;
0055 }
0056 
0057 static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp,
0058                       unsigned int id)
0059 {
0060     struct mrq_pg_response response;
0061     struct mrq_pg_request request;
0062     struct tegra_bpmp_message msg;
0063     int err;
0064 
0065     memset(&request, 0, sizeof(request));
0066     request.cmd = CMD_PG_GET_STATE;
0067     request.id = id;
0068 
0069     memset(&response, 0, sizeof(response));
0070 
0071     memset(&msg, 0, sizeof(msg));
0072     msg.mrq = MRQ_PG;
0073     msg.tx.data = &request;
0074     msg.tx.size = sizeof(request);
0075     msg.rx.data = &response;
0076     msg.rx.size = sizeof(response);
0077 
0078     err = tegra_bpmp_transfer(bpmp, &msg);
0079     if (err < 0)
0080         return PG_STATE_OFF;
0081     else if (msg.rx.ret < 0)
0082         return -EINVAL;
0083 
0084     return response.get_state.state;
0085 }
0086 
0087 static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp)
0088 {
0089     struct mrq_pg_response response;
0090     struct mrq_pg_request request;
0091     struct tegra_bpmp_message msg;
0092     int err;
0093 
0094     memset(&request, 0, sizeof(request));
0095     request.cmd = CMD_PG_GET_MAX_ID;
0096 
0097     memset(&response, 0, sizeof(response));
0098 
0099     memset(&msg, 0, sizeof(msg));
0100     msg.mrq = MRQ_PG;
0101     msg.tx.data = &request;
0102     msg.tx.size = sizeof(request);
0103     msg.rx.data = &response;
0104     msg.rx.size = sizeof(response);
0105 
0106     err = tegra_bpmp_transfer(bpmp, &msg);
0107     if (err < 0)
0108         return err;
0109     else if (msg.rx.ret < 0)
0110         return -EINVAL;
0111 
0112     return response.get_max_id.max_id;
0113 }
0114 
0115 static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
0116                        unsigned int id)
0117 {
0118     struct mrq_pg_response response;
0119     struct mrq_pg_request request;
0120     struct tegra_bpmp_message msg;
0121     int err;
0122 
0123     memset(&request, 0, sizeof(request));
0124     request.cmd = CMD_PG_GET_NAME;
0125     request.id = id;
0126 
0127     memset(&response, 0, sizeof(response));
0128 
0129     memset(&msg, 0, sizeof(msg));
0130     msg.mrq = MRQ_PG;
0131     msg.tx.data = &request;
0132     msg.tx.size = sizeof(request);
0133     msg.rx.data = &response;
0134     msg.rx.size = sizeof(response);
0135 
0136     err = tegra_bpmp_transfer(bpmp, &msg);
0137     if (err < 0 || msg.rx.ret < 0)
0138         return NULL;
0139 
0140     return kstrdup(response.get_name.name, GFP_KERNEL);
0141 }
0142 
0143 static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp,
0144                            unsigned int id)
0145 {
0146     return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF;
0147 }
0148 
0149 static int tegra_powergate_power_on(struct generic_pm_domain *domain)
0150 {
0151     struct tegra_powergate *powergate = to_tegra_powergate(domain);
0152     struct tegra_bpmp *bpmp = powergate->bpmp;
0153 
0154     return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
0155                           PG_STATE_ON);
0156 }
0157 
0158 static int tegra_powergate_power_off(struct generic_pm_domain *domain)
0159 {
0160     struct tegra_powergate *powergate = to_tegra_powergate(domain);
0161     struct tegra_bpmp *bpmp = powergate->bpmp;
0162 
0163     return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
0164                           PG_STATE_OFF);
0165 }
0166 
0167 static struct tegra_powergate *
0168 tegra_powergate_add(struct tegra_bpmp *bpmp,
0169             const struct tegra_powergate_info *info)
0170 {
0171     struct tegra_powergate *powergate;
0172     bool off;
0173     int err;
0174 
0175     off = !tegra_bpmp_powergate_is_powered(bpmp, info->id);
0176 
0177     powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL);
0178     if (!powergate)
0179         return ERR_PTR(-ENOMEM);
0180 
0181     powergate->id = info->id;
0182     powergate->bpmp = bpmp;
0183 
0184     powergate->genpd.name = kstrdup(info->name, GFP_KERNEL);
0185     powergate->genpd.power_on = tegra_powergate_power_on;
0186     powergate->genpd.power_off = tegra_powergate_power_off;
0187 
0188     err = pm_genpd_init(&powergate->genpd, NULL, off);
0189     if (err < 0) {
0190         kfree(powergate->genpd.name);
0191         return ERR_PTR(err);
0192     }
0193 
0194     return powergate;
0195 }
0196 
0197 static void tegra_powergate_remove(struct tegra_powergate *powergate)
0198 {
0199     struct generic_pm_domain *genpd = &powergate->genpd;
0200     struct tegra_bpmp *bpmp = powergate->bpmp;
0201     int err;
0202 
0203     err = pm_genpd_remove(genpd);
0204     if (err < 0)
0205         dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
0206             genpd->name, err);
0207 
0208     kfree(genpd->name);
0209 }
0210 
0211 static int
0212 tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
0213                 struct tegra_powergate_info **powergatesp)
0214 {
0215     struct tegra_powergate_info *powergates;
0216     unsigned int max_id, id, count = 0;
0217     unsigned int num_holes = 0;
0218     int err;
0219 
0220     err = tegra_bpmp_powergate_get_max_id(bpmp);
0221     if (err < 0)
0222         return err;
0223 
0224     max_id = err;
0225 
0226     dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
0227 
0228     powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL);
0229     if (!powergates)
0230         return -ENOMEM;
0231 
0232     for (id = 0; id <= max_id; id++) {
0233         struct tegra_powergate_info *info = &powergates[count];
0234 
0235         info->name = tegra_bpmp_powergate_get_name(bpmp, id);
0236         if (!info->name || info->name[0] == '\0') {
0237             num_holes++;
0238             continue;
0239         }
0240 
0241         info->id = id;
0242         count++;
0243     }
0244 
0245     dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
0246 
0247     *powergatesp = powergates;
0248 
0249     return count;
0250 }
0251 
0252 static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
0253                      struct tegra_powergate_info *powergates,
0254                      unsigned int count)
0255 {
0256     struct genpd_onecell_data *genpd = &bpmp->genpd;
0257     struct generic_pm_domain **domains;
0258     struct tegra_powergate *powergate;
0259     unsigned int i;
0260     int err;
0261 
0262     domains = kcalloc(count, sizeof(*domains), GFP_KERNEL);
0263     if (!domains)
0264         return -ENOMEM;
0265 
0266     for (i = 0; i < count; i++) {
0267         powergate = tegra_powergate_add(bpmp, &powergates[i]);
0268         if (IS_ERR(powergate)) {
0269             err = PTR_ERR(powergate);
0270             goto remove;
0271         }
0272 
0273         dev_dbg(bpmp->dev, "added power domain %s\n",
0274             powergate->genpd.name);
0275         domains[i] = &powergate->genpd;
0276     }
0277 
0278     genpd->num_domains = count;
0279     genpd->domains = domains;
0280 
0281     return 0;
0282 
0283 remove:
0284     while (i--) {
0285         powergate = to_tegra_powergate(domains[i]);
0286         tegra_powergate_remove(powergate);
0287     }
0288 
0289     kfree(genpd->domains);
0290     return err;
0291 }
0292 
0293 static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
0294 {
0295     struct genpd_onecell_data *genpd = &bpmp->genpd;
0296     unsigned int i = genpd->num_domains;
0297     struct tegra_powergate *powergate;
0298 
0299     while (i--) {
0300         dev_dbg(bpmp->dev, "removing power domain %s\n",
0301             genpd->domains[i]->name);
0302         powergate = to_tegra_powergate(genpd->domains[i]);
0303         tegra_powergate_remove(powergate);
0304     }
0305 }
0306 
0307 static struct generic_pm_domain *
0308 tegra_powergate_xlate(struct of_phandle_args *spec, void *data)
0309 {
0310     struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
0311     struct genpd_onecell_data *genpd = data;
0312     unsigned int i;
0313 
0314     for (i = 0; i < genpd->num_domains; i++) {
0315         struct tegra_powergate *powergate;
0316 
0317         powergate = to_tegra_powergate(genpd->domains[i]);
0318         if (powergate->id == spec->args[0]) {
0319             domain = &powergate->genpd;
0320             break;
0321         }
0322     }
0323 
0324     return domain;
0325 }
0326 
0327 int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
0328 {
0329     struct device_node *np = bpmp->dev->of_node;
0330     struct tegra_powergate_info *powergates;
0331     struct device *dev = bpmp->dev;
0332     unsigned int count, i;
0333     int err;
0334 
0335     err = tegra_bpmp_probe_powergates(bpmp, &powergates);
0336     if (err < 0)
0337         return err;
0338 
0339     count = err;
0340 
0341     dev_dbg(dev, "%u power domains probed\n", count);
0342 
0343     err = tegra_bpmp_add_powergates(bpmp, powergates, count);
0344     if (err < 0)
0345         goto free;
0346 
0347     bpmp->genpd.xlate = tegra_powergate_xlate;
0348 
0349     err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
0350     if (err < 0) {
0351         dev_err(dev, "failed to add power domain provider: %d\n", err);
0352         tegra_bpmp_remove_powergates(bpmp);
0353     }
0354 
0355 free:
0356     for (i = 0; i < count; i++)
0357         kfree(powergates[i].name);
0358 
0359     kfree(powergates);
0360     return err;
0361 }