root/drivers/soc/qcom/rpmpd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rpmpd_send_enable
  2. rpmpd_send_corner
  3. to_active_sleep
  4. rpmpd_aggregate_corner
  5. rpmpd_power_on
  6. rpmpd_power_off
  7. rpmpd_set_performance
  8. rpmpd_get_performance
  9. rpmpd_probe
  10. rpmpd_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
   3 
   4 #include <linux/err.h>
   5 #include <linux/init.h>
   6 #include <linux/kernel.h>
   7 #include <linux/mutex.h>
   8 #include <linux/pm_domain.h>
   9 #include <linux/of.h>
  10 #include <linux/of_device.h>
  11 #include <linux/platform_device.h>
  12 #include <linux/pm_opp.h>
  13 #include <linux/soc/qcom/smd-rpm.h>
  14 
  15 #include <dt-bindings/power/qcom-rpmpd.h>
  16 
  17 #define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
  18 
  19 /* Resource types:
  20  * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
  21 #define RPMPD_SMPA 0x61706d73
  22 #define RPMPD_LDOA 0x616f646c
  23 #define RPMPD_RWCX 0x78637772
  24 #define RPMPD_RWMX 0x786d7772
  25 #define RPMPD_RWLC 0x636c7772
  26 #define RPMPD_RWLM 0x6d6c7772
  27 #define RPMPD_RWSC 0x63737772
  28 #define RPMPD_RWSM 0x6d737772
  29 
  30 /* Operation Keys */
  31 #define KEY_CORNER              0x6e726f63 /* corn */
  32 #define KEY_ENABLE              0x6e657773 /* swen */
  33 #define KEY_FLOOR_CORNER        0x636676   /* vfc */
  34 #define KEY_FLOOR_LEVEL         0x6c6676   /* vfl */
  35 #define KEY_LEVEL               0x6c766c76 /* vlvl */
  36 
  37 #define MAX_8996_RPMPD_STATE    6
  38 
  39 #define DEFINE_RPMPD_PAIR(_platform, _name, _active, r_type, r_key,     \
  40                           r_id)                                         \
  41         static struct rpmpd _platform##_##_active;                      \
  42         static struct rpmpd _platform##_##_name = {                     \
  43                 .pd = { .name = #_name, },                              \
  44                 .peer = &_platform##_##_active,                         \
  45                 .res_type = RPMPD_##r_type,                             \
  46                 .res_id = r_id,                                         \
  47                 .key = KEY_##r_key,                                     \
  48         };                                                              \
  49         static struct rpmpd _platform##_##_active = {                   \
  50                 .pd = { .name = #_active, },                            \
  51                 .peer = &_platform##_##_name,                           \
  52                 .active_only = true,                                    \
  53                 .res_type = RPMPD_##r_type,                             \
  54                 .res_id = r_id,                                         \
  55                 .key = KEY_##r_key,                                     \
  56         }
  57 
  58 #define DEFINE_RPMPD_CORNER(_platform, _name, r_type, r_id)             \
  59         static struct rpmpd _platform##_##_name = {                     \
  60                 .pd = { .name = #_name, },                              \
  61                 .res_type = RPMPD_##r_type,                             \
  62                 .res_id = r_id,                                         \
  63                 .key = KEY_CORNER,                                      \
  64         }
  65 
  66 #define DEFINE_RPMPD_LEVEL(_platform, _name, r_type, r_id)              \
  67         static struct rpmpd _platform##_##_name = {                     \
  68                 .pd = { .name = #_name, },                              \
  69                 .res_type = RPMPD_##r_type,                             \
  70                 .res_id = r_id,                                         \
  71                 .key = KEY_LEVEL,                                       \
  72         }
  73 
  74 #define DEFINE_RPMPD_VFC(_platform, _name, r_type, r_id)                \
  75         static struct rpmpd _platform##_##_name = {                     \
  76                 .pd = { .name = #_name, },                              \
  77                 .res_type = RPMPD_##r_type,                             \
  78                 .res_id = r_id,                                         \
  79                 .key = KEY_FLOOR_CORNER,                                \
  80         }
  81 
  82 #define DEFINE_RPMPD_VFL(_platform, _name, r_type, r_id)                \
  83         static struct rpmpd _platform##_##_name = {                     \
  84                 .pd = { .name = #_name, },                              \
  85                 .res_type = RPMPD_##r_type,                             \
  86                 .res_id = r_id,                                         \
  87                 .key = KEY_FLOOR_LEVEL,                                 \
  88         }
  89 
  90 struct rpmpd_req {
  91         __le32 key;
  92         __le32 nbytes;
  93         __le32 value;
  94 };
  95 
  96 struct rpmpd {
  97         struct generic_pm_domain pd;
  98         struct rpmpd *peer;
  99         const bool active_only;
 100         unsigned int corner;
 101         bool enabled;
 102         const char *res_name;
 103         const int res_type;
 104         const int res_id;
 105         struct qcom_smd_rpm *rpm;
 106         unsigned int max_state;
 107         __le32 key;
 108 };
 109 
 110 struct rpmpd_desc {
 111         struct rpmpd **rpmpds;
 112         size_t num_pds;
 113         unsigned int max_state;
 114 };
 115 
 116 static DEFINE_MUTEX(rpmpd_lock);
 117 
 118 /* msm8996 RPM Power domains */
 119 DEFINE_RPMPD_PAIR(msm8996, vddcx, vddcx_ao, SMPA, CORNER, 1);
 120 DEFINE_RPMPD_PAIR(msm8996, vddmx, vddmx_ao, SMPA, CORNER, 2);
 121 DEFINE_RPMPD_CORNER(msm8996, vddsscx, LDOA, 26);
 122 
 123 DEFINE_RPMPD_VFC(msm8996, vddcx_vfc, SMPA, 1);
 124 DEFINE_RPMPD_VFC(msm8996, vddsscx_vfc, LDOA, 26);
 125 
 126 static struct rpmpd *msm8996_rpmpds[] = {
 127         [MSM8996_VDDCX] =       &msm8996_vddcx,
 128         [MSM8996_VDDCX_AO] =    &msm8996_vddcx_ao,
 129         [MSM8996_VDDCX_VFC] =   &msm8996_vddcx_vfc,
 130         [MSM8996_VDDMX] =       &msm8996_vddmx,
 131         [MSM8996_VDDMX_AO] =    &msm8996_vddmx_ao,
 132         [MSM8996_VDDSSCX] =     &msm8996_vddsscx,
 133         [MSM8996_VDDSSCX_VFC] = &msm8996_vddsscx_vfc,
 134 };
 135 
 136 static const struct rpmpd_desc msm8996_desc = {
 137         .rpmpds = msm8996_rpmpds,
 138         .num_pds = ARRAY_SIZE(msm8996_rpmpds),
 139         .max_state = MAX_8996_RPMPD_STATE,
 140 };
 141 
 142 /* msm8998 RPM Power domains */
 143 DEFINE_RPMPD_PAIR(msm8998, vddcx, vddcx_ao, RWCX, LEVEL, 0);
 144 DEFINE_RPMPD_VFL(msm8998, vddcx_vfl, RWCX, 0);
 145 
 146 DEFINE_RPMPD_PAIR(msm8998, vddmx, vddmx_ao, RWMX, LEVEL, 0);
 147 DEFINE_RPMPD_VFL(msm8998, vddmx_vfl, RWMX, 0);
 148 
 149 DEFINE_RPMPD_LEVEL(msm8998, vdd_ssccx, RWSC, 0);
 150 DEFINE_RPMPD_VFL(msm8998, vdd_ssccx_vfl, RWSC, 0);
 151 
 152 DEFINE_RPMPD_LEVEL(msm8998, vdd_sscmx, RWSM, 0);
 153 DEFINE_RPMPD_VFL(msm8998, vdd_sscmx_vfl, RWSM, 0);
 154 
 155 static struct rpmpd *msm8998_rpmpds[] = {
 156         [MSM8998_VDDCX] =               &msm8998_vddcx,
 157         [MSM8998_VDDCX_AO] =            &msm8998_vddcx_ao,
 158         [MSM8998_VDDCX_VFL] =           &msm8998_vddcx_vfl,
 159         [MSM8998_VDDMX] =               &msm8998_vddmx,
 160         [MSM8998_VDDMX_AO] =            &msm8998_vddmx_ao,
 161         [MSM8998_VDDMX_VFL] =           &msm8998_vddmx_vfl,
 162         [MSM8998_SSCCX] =               &msm8998_vdd_ssccx,
 163         [MSM8998_SSCCX_VFL] =           &msm8998_vdd_ssccx_vfl,
 164         [MSM8998_SSCMX] =               &msm8998_vdd_sscmx,
 165         [MSM8998_SSCMX_VFL] =           &msm8998_vdd_sscmx_vfl,
 166 };
 167 
 168 static const struct rpmpd_desc msm8998_desc = {
 169         .rpmpds = msm8998_rpmpds,
 170         .num_pds = ARRAY_SIZE(msm8998_rpmpds),
 171         .max_state = RPM_SMD_LEVEL_BINNING,
 172 };
 173 
 174 /* qcs404 RPM Power domains */
 175 DEFINE_RPMPD_PAIR(qcs404, vddmx, vddmx_ao, RWMX, LEVEL, 0);
 176 DEFINE_RPMPD_VFL(qcs404, vddmx_vfl, RWMX, 0);
 177 
 178 DEFINE_RPMPD_LEVEL(qcs404, vdd_lpicx, RWLC, 0);
 179 DEFINE_RPMPD_VFL(qcs404, vdd_lpicx_vfl, RWLC, 0);
 180 
 181 DEFINE_RPMPD_LEVEL(qcs404, vdd_lpimx, RWLM, 0);
 182 DEFINE_RPMPD_VFL(qcs404, vdd_lpimx_vfl, RWLM, 0);
 183 
 184 static struct rpmpd *qcs404_rpmpds[] = {
 185         [QCS404_VDDMX] = &qcs404_vddmx,
 186         [QCS404_VDDMX_AO] = &qcs404_vddmx_ao,
 187         [QCS404_VDDMX_VFL] = &qcs404_vddmx_vfl,
 188         [QCS404_LPICX] = &qcs404_vdd_lpicx,
 189         [QCS404_LPICX_VFL] = &qcs404_vdd_lpicx_vfl,
 190         [QCS404_LPIMX] = &qcs404_vdd_lpimx,
 191         [QCS404_LPIMX_VFL] = &qcs404_vdd_lpimx_vfl,
 192 };
 193 
 194 static const struct rpmpd_desc qcs404_desc = {
 195         .rpmpds = qcs404_rpmpds,
 196         .num_pds = ARRAY_SIZE(qcs404_rpmpds),
 197         .max_state = RPM_SMD_LEVEL_BINNING,
 198 };
 199 
 200 static const struct of_device_id rpmpd_match_table[] = {
 201         { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
 202         { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc },
 203         { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
 204         { }
 205 };
 206 
 207 static int rpmpd_send_enable(struct rpmpd *pd, bool enable)
 208 {
 209         struct rpmpd_req req = {
 210                 .key = KEY_ENABLE,
 211                 .nbytes = cpu_to_le32(sizeof(u32)),
 212                 .value = cpu_to_le32(enable),
 213         };
 214 
 215         return qcom_rpm_smd_write(pd->rpm, QCOM_SMD_RPM_ACTIVE_STATE,
 216                                   pd->res_type, pd->res_id, &req, sizeof(req));
 217 }
 218 
 219 static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner)
 220 {
 221         struct rpmpd_req req = {
 222                 .key = pd->key,
 223                 .nbytes = cpu_to_le32(sizeof(u32)),
 224                 .value = cpu_to_le32(corner),
 225         };
 226 
 227         return qcom_rpm_smd_write(pd->rpm, state, pd->res_type, pd->res_id,
 228                                   &req, sizeof(req));
 229 };
 230 
 231 static void to_active_sleep(struct rpmpd *pd, unsigned int corner,
 232                             unsigned int *active, unsigned int *sleep)
 233 {
 234         *active = corner;
 235 
 236         if (pd->active_only)
 237                 *sleep = 0;
 238         else
 239                 *sleep = *active;
 240 }
 241 
 242 static int rpmpd_aggregate_corner(struct rpmpd *pd)
 243 {
 244         int ret;
 245         struct rpmpd *peer = pd->peer;
 246         unsigned int active_corner, sleep_corner;
 247         unsigned int this_active_corner = 0, this_sleep_corner = 0;
 248         unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
 249 
 250         to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner);
 251 
 252         if (peer && peer->enabled)
 253                 to_active_sleep(peer, peer->corner, &peer_active_corner,
 254                                 &peer_sleep_corner);
 255 
 256         active_corner = max(this_active_corner, peer_active_corner);
 257 
 258         ret = rpmpd_send_corner(pd, QCOM_SMD_RPM_ACTIVE_STATE, active_corner);
 259         if (ret)
 260                 return ret;
 261 
 262         sleep_corner = max(this_sleep_corner, peer_sleep_corner);
 263 
 264         return rpmpd_send_corner(pd, QCOM_SMD_RPM_SLEEP_STATE, sleep_corner);
 265 }
 266 
 267 static int rpmpd_power_on(struct generic_pm_domain *domain)
 268 {
 269         int ret;
 270         struct rpmpd *pd = domain_to_rpmpd(domain);
 271 
 272         mutex_lock(&rpmpd_lock);
 273 
 274         ret = rpmpd_send_enable(pd, true);
 275         if (ret)
 276                 goto out;
 277 
 278         pd->enabled = true;
 279 
 280         if (pd->corner)
 281                 ret = rpmpd_aggregate_corner(pd);
 282 
 283 out:
 284         mutex_unlock(&rpmpd_lock);
 285 
 286         return ret;
 287 }
 288 
 289 static int rpmpd_power_off(struct generic_pm_domain *domain)
 290 {
 291         int ret;
 292         struct rpmpd *pd = domain_to_rpmpd(domain);
 293 
 294         mutex_lock(&rpmpd_lock);
 295 
 296         ret = rpmpd_send_enable(pd, false);
 297         if (!ret)
 298                 pd->enabled = false;
 299 
 300         mutex_unlock(&rpmpd_lock);
 301 
 302         return ret;
 303 }
 304 
 305 static int rpmpd_set_performance(struct generic_pm_domain *domain,
 306                                  unsigned int state)
 307 {
 308         int ret = 0;
 309         struct rpmpd *pd = domain_to_rpmpd(domain);
 310 
 311         if (state > pd->max_state)
 312                 state = pd->max_state;
 313 
 314         mutex_lock(&rpmpd_lock);
 315 
 316         pd->corner = state;
 317 
 318         /* Always send updates for vfc and vfl */
 319         if (!pd->enabled && pd->key != KEY_FLOOR_CORNER &&
 320             pd->key != KEY_FLOOR_LEVEL)
 321                 goto out;
 322 
 323         ret = rpmpd_aggregate_corner(pd);
 324 
 325 out:
 326         mutex_unlock(&rpmpd_lock);
 327 
 328         return ret;
 329 }
 330 
 331 static unsigned int rpmpd_get_performance(struct generic_pm_domain *genpd,
 332                                           struct dev_pm_opp *opp)
 333 {
 334         return dev_pm_opp_get_level(opp);
 335 }
 336 
 337 static int rpmpd_probe(struct platform_device *pdev)
 338 {
 339         int i;
 340         size_t num;
 341         struct genpd_onecell_data *data;
 342         struct qcom_smd_rpm *rpm;
 343         struct rpmpd **rpmpds;
 344         const struct rpmpd_desc *desc;
 345 
 346         rpm = dev_get_drvdata(pdev->dev.parent);
 347         if (!rpm) {
 348                 dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n");
 349                 return -ENODEV;
 350         }
 351 
 352         desc = of_device_get_match_data(&pdev->dev);
 353         if (!desc)
 354                 return -EINVAL;
 355 
 356         rpmpds = desc->rpmpds;
 357         num = desc->num_pds;
 358 
 359         data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 360         if (!data)
 361                 return -ENOMEM;
 362 
 363         data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains),
 364                                      GFP_KERNEL);
 365         data->num_domains = num;
 366 
 367         for (i = 0; i < num; i++) {
 368                 if (!rpmpds[i]) {
 369                         dev_warn(&pdev->dev, "rpmpds[] with empty entry at index=%d\n",
 370                                  i);
 371                         continue;
 372                 }
 373 
 374                 rpmpds[i]->rpm = rpm;
 375                 rpmpds[i]->max_state = desc->max_state;
 376                 rpmpds[i]->pd.power_off = rpmpd_power_off;
 377                 rpmpds[i]->pd.power_on = rpmpd_power_on;
 378                 rpmpds[i]->pd.set_performance_state = rpmpd_set_performance;
 379                 rpmpds[i]->pd.opp_to_performance_state = rpmpd_get_performance;
 380                 pm_genpd_init(&rpmpds[i]->pd, NULL, true);
 381 
 382                 data->domains[i] = &rpmpds[i]->pd;
 383         }
 384 
 385         return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
 386 }
 387 
 388 static struct platform_driver rpmpd_driver = {
 389         .driver = {
 390                 .name = "qcom-rpmpd",
 391                 .of_match_table = rpmpd_match_table,
 392                 .suppress_bind_attrs = true,
 393         },
 394         .probe = rpmpd_probe,
 395 };
 396 
 397 static int __init rpmpd_init(void)
 398 {
 399         return platform_driver_register(&rpmpd_driver);
 400 }
 401 core_initcall(rpmpd_init);

/* [<][>][^][v][top][bottom][index][help] */