cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vp.c (7563B)


      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}