linux/arch/arm/mach-omap2/vp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/kernel.h>
   3#include <linux/init.h>
   4
   5#include "common.h"
   6
   7#include "voltage.h"
   8#include "vp.h"
   9#include "prm-regbits-34xx.h"
  10#include "prm-regbits-44xx.h"
  11#include "prm44xx.h"
  12
  13static u32 _vp_set_init_voltage(struct voltagedomain *voltdm, u32 volt)
  14{
  15        struct omap_vp_instance *vp = voltdm->vp;
  16        u32 vpconfig;
  17        char vsel;
  18
  19        vsel = voltdm->pmic->uv_to_vsel(volt);
  20
  21        vpconfig = voltdm->read(vp->vpconfig);
  22        vpconfig &= ~(vp->common->vpconfig_initvoltage_mask |
  23                      vp->common->vpconfig_forceupdate |
  24                      vp->common->vpconfig_initvdd);
  25        vpconfig |= vsel << __ffs(vp->common->vpconfig_initvoltage_mask);
  26        voltdm->write(vpconfig, vp->vpconfig);
  27
  28        /* Trigger initVDD value copy to voltage processor */
  29        voltdm->write((vpconfig | vp->common->vpconfig_initvdd),
  30                       vp->vpconfig);
  31
  32        /* Clear initVDD copy trigger bit */
  33        voltdm->write(vpconfig, vp->vpconfig);
  34
  35        return vpconfig;
  36}
  37
  38/* Generic voltage init functions */
  39void __init omap_vp_init(struct voltagedomain *voltdm)
  40{
  41        struct omap_vp_instance *vp = voltdm->vp;
  42        u32 val, sys_clk_rate, timeout, waittime;
  43        u32 vddmin, vddmax, vstepmin, vstepmax;
  44
  45        if (!voltdm->pmic || !voltdm->pmic->uv_to_vsel) {
  46                pr_err("%s: No PMIC info for vdd_%s\n", __func__, voltdm->name);
  47                return;
  48        }
  49
  50        if (!voltdm->read || !voltdm->write) {
  51                pr_err("%s: No read/write API for accessing vdd_%s regs\n",
  52                        __func__, voltdm->name);
  53                return;
  54        }
  55
  56        vp->enabled = false;
  57
  58        /* Divide to avoid overflow */
  59        sys_clk_rate = voltdm->sys_clk.rate / 1000;
  60
  61        timeout = (sys_clk_rate * voltdm->pmic->vp_timeout_us) / 1000;
  62        vddmin = max(voltdm->vp_param->vddmin, voltdm->pmic->vddmin);
  63        vddmax = min(voltdm->vp_param->vddmax, voltdm->pmic->vddmax);
  64        vddmin = voltdm->pmic->uv_to_vsel(vddmin);
  65        vddmax = voltdm->pmic->uv_to_vsel(vddmax);
  66
  67        waittime = DIV_ROUND_UP(voltdm->pmic->step_size * sys_clk_rate,
  68                                1000 * voltdm->pmic->slew_rate);
  69        vstepmin = voltdm->pmic->vp_vstepmin;
  70        vstepmax = voltdm->pmic->vp_vstepmax;
  71
  72        /*
  73         * VP_CONFIG: error gain is not set here, it will be updated
  74         * on each scale, based on OPP.
  75         */
  76        val = (voltdm->pmic->vp_erroroffset <<
  77               __ffs(voltdm->vp->common->vpconfig_erroroffset_mask)) |
  78                vp->common->vpconfig_timeouten;
  79        voltdm->write(val, vp->vpconfig);
  80
  81        /* VSTEPMIN */
  82        val = (waittime << vp->common->vstepmin_smpswaittimemin_shift) |
  83                (vstepmin <<  vp->common->vstepmin_stepmin_shift);
  84        voltdm->write(val, vp->vstepmin);
  85
  86        /* VSTEPMAX */
  87        val = (vstepmax << vp->common->vstepmax_stepmax_shift) |
  88                (waittime << vp->common->vstepmax_smpswaittimemax_shift);
  89        voltdm->write(val, vp->vstepmax);
  90
  91        /* VLIMITTO */
  92        val = (vddmax << vp->common->vlimitto_vddmax_shift) |
  93                (vddmin << vp->common->vlimitto_vddmin_shift) |
  94                (timeout <<  vp->common->vlimitto_timeout_shift);
  95        voltdm->write(val, vp->vlimitto);
  96}
  97
  98int omap_vp_update_errorgain(struct voltagedomain *voltdm,
  99                             unsigned long target_volt)
 100{
 101        struct omap_volt_data *volt_data;
 102
 103        if (!voltdm->vp)
 104                return -EINVAL;
 105
 106        /* Get volt_data corresponding to target_volt */
 107        volt_data = omap_voltage_get_voltdata(voltdm, target_volt);
 108        if (IS_ERR(volt_data))
 109                return -EINVAL;
 110
 111        /* Setting vp errorgain based on the voltage */
 112        voltdm->rmw(voltdm->vp->common->vpconfig_errorgain_mask,
 113                    volt_data->vp_errgain <<
 114                    __ffs(voltdm->vp->common->vpconfig_errorgain_mask),
 115                    voltdm->vp->vpconfig);
 116
 117        return 0;
 118}
 119
 120/* VP force update method of voltage scaling */
 121int omap_vp_forceupdate_scale(struct voltagedomain *voltdm,
 122                              unsigned long target_volt)
 123{
 124        struct omap_vp_instance *vp = voltdm->vp;
 125        u32 vpconfig;
 126        u8 target_vsel, current_vsel;
 127        int ret, timeout = 0;
 128
 129        ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, &current_vsel);
 130        if (ret)
 131                return ret;
 132
 133        /*
 134         * Clear all pending TransactionDone interrupt/status. Typical latency
 135         * is <3us
 136         */
 137        while (timeout++ < VP_TRANXDONE_TIMEOUT) {
 138                vp->common->ops->clear_txdone(vp->id);
 139                if (!vp->common->ops->check_txdone(vp->id))
 140                        break;
 141                udelay(1);
 142        }
 143        if (timeout >= VP_TRANXDONE_TIMEOUT) {
 144                pr_warn("%s: vdd_%s TRANXDONE timeout exceeded. Voltage change aborted\n",
 145                        __func__, voltdm->name);
 146                return -ETIMEDOUT;
 147        }
 148
 149        vpconfig = _vp_set_init_voltage(voltdm, target_volt);
 150
 151        /* Force update of voltage */
 152        voltdm->write(vpconfig | vp->common->vpconfig_forceupdate,
 153                      voltdm->vp->vpconfig);
 154
 155        /*
 156         * Wait for TransactionDone. Typical latency is <200us.
 157         * Depends on SMPSWAITTIMEMIN/MAX and voltage change
 158         */
 159        timeout = 0;
 160        omap_test_timeout(vp->common->ops->check_txdone(vp->id),
 161                          VP_TRANXDONE_TIMEOUT, timeout);
 162        if (timeout >= VP_TRANXDONE_TIMEOUT)
 163                pr_err("%s: vdd_%s TRANXDONE timeout exceeded. TRANXDONE never got set after the voltage update\n",
 164                       __func__, voltdm->name);
 165
 166        omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel);
 167
 168        /*
 169         * Disable TransactionDone interrupt , clear all status, clear
 170         * control registers
 171         */
 172        timeout = 0;
 173        while (timeout++ < VP_TRANXDONE_TIMEOUT) {
 174                vp->common->ops->clear_txdone(vp->id);
 175                if (!vp->common->ops->check_txdone(vp->id))
 176                        break;
 177                udelay(1);
 178        }
 179
 180        if (timeout >= VP_TRANXDONE_TIMEOUT)
 181                pr_warn("%s: vdd_%s TRANXDONE timeout exceeded while trying to clear the TRANXDONE status\n",
 182                        __func__, voltdm->name);
 183
 184        /* Clear force bit */
 185        voltdm->write(vpconfig, vp->vpconfig);
 186
 187        return 0;
 188}
 189
 190/**
 191 * omap_vp_enable() - API to enable a particular VP
 192 * @voltdm:     pointer to the VDD whose VP is to be enabled.
 193 *
 194 * This API enables a particular voltage processor. Needed by the smartreflex
 195 * class drivers.
 196 */
 197void omap_vp_enable(struct voltagedomain *voltdm)
 198{
 199        struct omap_vp_instance *vp;
 200        u32 vpconfig, volt;
 201
 202        if (!voltdm || IS_ERR(voltdm)) {
 203                pr_warn("%s: VDD specified does not exist!\n", __func__);
 204                return;
 205        }
 206
 207        vp = voltdm->vp;
 208        if (!voltdm->read || !voltdm->write) {
 209                pr_err("%s: No read/write API for accessing vdd_%s regs\n",
 210                        __func__, voltdm->name);
 211                return;
 212        }
 213
 214        /* If VP is already enabled, do nothing. Return */
 215        if (vp->enabled)
 216                return;
 217
 218        volt = voltdm_get_voltage(voltdm);
 219        if (!volt) {
 220                pr_warn("%s: unable to find current voltage for %s\n",
 221                        __func__, voltdm->name);
 222                return;
 223        }
 224
 225        vpconfig = _vp_set_init_voltage(voltdm, volt);
 226
 227        /* Enable VP */
 228        vpconfig |= vp->common->vpconfig_vpenable;
 229        voltdm->write(vpconfig, vp->vpconfig);
 230
 231        vp->enabled = true;
 232}
 233
 234/**
 235 * omap_vp_disable() - API to disable a particular VP
 236 * @voltdm:     pointer to the VDD whose VP is to be disabled.
 237 *
 238 * This API disables a particular voltage processor. Needed by the smartreflex
 239 * class drivers.
 240 */
 241void omap_vp_disable(struct voltagedomain *voltdm)
 242{
 243        struct omap_vp_instance *vp;
 244        u32 vpconfig;
 245        int timeout;
 246
 247        if (!voltdm || IS_ERR(voltdm)) {
 248                pr_warn("%s: VDD specified does not exist!\n", __func__);
 249                return;
 250        }
 251
 252        vp = voltdm->vp;
 253        if (!voltdm->read || !voltdm->write) {
 254                pr_err("%s: No read/write API for accessing vdd_%s regs\n",
 255                        __func__, voltdm->name);
 256                return;
 257        }
 258
 259        /* If VP is already disabled, do nothing. Return */
 260        if (!vp->enabled) {
 261                pr_warn("%s: Trying to disable VP for vdd_%s when it is already disabled\n",
 262                        __func__, voltdm->name);
 263                return;
 264        }
 265
 266        /* Disable VP */
 267        vpconfig = voltdm->read(vp->vpconfig);
 268        vpconfig &= ~vp->common->vpconfig_vpenable;
 269        voltdm->write(vpconfig, vp->vpconfig);
 270
 271        /*
 272         * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
 273         */
 274        omap_test_timeout((voltdm->read(vp->vstatus)),
 275                          VP_IDLE_TIMEOUT, timeout);
 276
 277        if (timeout >= VP_IDLE_TIMEOUT)
 278                pr_warn("%s: vdd_%s idle timedout\n", __func__, voltdm->name);
 279
 280        vp->enabled = false;
 281
 282        return;
 283}
 284