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

sr_device.c (5303B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * OMAP3/OMAP4 smartreflex device file
      4 *
      5 * Author: Thara Gopinath	<thara@ti.com>
      6 *
      7 * Based originally on code from smartreflex.c
      8 * Copyright (C) 2010 Texas Instruments, Inc.
      9 * Thara Gopinath <thara@ti.com>
     10 *
     11 * Copyright (C) 2008 Nokia Corporation
     12 * Kalle Jokiniemi
     13 *
     14 * Copyright (C) 2007 Texas Instruments, Inc.
     15 * Lesly A M <x0080970@ti.com>
     16 */
     17#include <linux/power/smartreflex.h>
     18
     19#include <linux/err.h>
     20#include <linux/slab.h>
     21#include <linux/io.h>
     22
     23#include "soc.h"
     24#include "omap_device.h"
     25#include "voltage.h"
     26#include "control.h"
     27#include "pm.h"
     28
     29static bool sr_enable_on_init;
     30
     31/* Read EFUSE values from control registers for OMAP3430 */
     32static void __init sr_set_nvalues(struct omap_volt_data *volt_data,
     33				struct omap_sr_data *sr_data)
     34{
     35	struct omap_sr_nvalue_table *nvalue_table;
     36	int i, j, count = 0;
     37
     38	sr_data->nvalue_count = 0;
     39	sr_data->nvalue_table = NULL;
     40
     41	while (volt_data[count].volt_nominal)
     42		count++;
     43
     44	nvalue_table = kcalloc(count, sizeof(*nvalue_table), GFP_KERNEL);
     45	if (!nvalue_table)
     46		return;
     47
     48	for (i = 0, j = 0; i < count; i++) {
     49		u32 v;
     50
     51		/*
     52		 * In OMAP4 the efuse registers are 24 bit aligned.
     53		 * A readl_relaxed will fail for non-32 bit aligned address
     54		 * and hence the 8-bit read and shift.
     55		 */
     56		if (cpu_is_omap44xx()) {
     57			u16 offset = volt_data[i].sr_efuse_offs;
     58
     59			v = omap_ctrl_readb(offset) |
     60				omap_ctrl_readb(offset + 1) << 8 |
     61				omap_ctrl_readb(offset + 2) << 16;
     62		} else {
     63			v = omap_ctrl_readl(volt_data[i].sr_efuse_offs);
     64		}
     65
     66		/*
     67		 * Many OMAP SoCs don't have the eFuse values set.
     68		 * For example, pretty much all OMAP3xxx before
     69		 * ES3.something.
     70		 *
     71		 * XXX There needs to be some way for board files or
     72		 * userspace to add these in.
     73		 */
     74		if (v == 0)
     75			continue;
     76
     77		nvalue_table[j].nvalue = v;
     78		nvalue_table[j].efuse_offs = volt_data[i].sr_efuse_offs;
     79		nvalue_table[j].errminlimit = volt_data[i].sr_errminlimit;
     80		nvalue_table[j].volt_nominal = volt_data[i].volt_nominal;
     81
     82		j++;
     83	}
     84
     85	sr_data->nvalue_table = nvalue_table;
     86	sr_data->nvalue_count = j;
     87}
     88
     89extern struct omap_sr_data omap_sr_pdata[];
     90
     91static int __init sr_init_by_name(const char *name, const char *voltdm)
     92{
     93	struct omap_sr_data *sr_data = NULL;
     94	struct omap_volt_data *volt_data;
     95	static int i;
     96
     97	if (!strncmp(name, "smartreflex_mpu_iva", 20) ||
     98	    !strncmp(name, "smartreflex_mpu", 16))
     99		sr_data = &omap_sr_pdata[OMAP_SR_MPU];
    100	else if (!strncmp(name, "smartreflex_core", 17))
    101		sr_data = &omap_sr_pdata[OMAP_SR_CORE];
    102	else if (!strncmp(name, "smartreflex_iva", 16))
    103		sr_data = &omap_sr_pdata[OMAP_SR_IVA];
    104
    105	if (!sr_data) {
    106		pr_err("%s: Unknown instance %s\n", __func__, name);
    107		return -EINVAL;
    108	}
    109
    110	sr_data->name = name;
    111	if (cpu_is_omap343x())
    112		sr_data->ip_type = 1;
    113	else
    114		sr_data->ip_type = 2;
    115	sr_data->senn_mod = 0x1;
    116	sr_data->senp_mod = 0x1;
    117
    118	if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
    119		sr_data->err_weight = OMAP3430_SR_ERRWEIGHT;
    120		sr_data->err_maxlimit = OMAP3430_SR_ERRMAXLIMIT;
    121		sr_data->accum_data = OMAP3430_SR_ACCUMDATA;
    122		if (!(strcmp(sr_data->name, "smartreflex_mpu"))) {
    123			sr_data->senn_avgweight = OMAP3430_SR1_SENNAVGWEIGHT;
    124			sr_data->senp_avgweight = OMAP3430_SR1_SENPAVGWEIGHT;
    125		} else {
    126			sr_data->senn_avgweight = OMAP3430_SR2_SENNAVGWEIGHT;
    127			sr_data->senp_avgweight = OMAP3430_SR2_SENPAVGWEIGHT;
    128		}
    129	}
    130
    131	sr_data->voltdm = voltdm_lookup(voltdm);
    132	if (!sr_data->voltdm) {
    133		pr_err("%s: Unable to get voltage domain pointer for VDD %s\n",
    134			__func__, voltdm);
    135		goto exit;
    136	}
    137
    138	omap_voltage_get_volttable(sr_data->voltdm, &volt_data);
    139	if (!volt_data) {
    140		pr_err("%s: No Voltage table registered for VDD%d\n",
    141		       __func__, i + 1);
    142		goto exit;
    143	}
    144
    145	sr_set_nvalues(volt_data, sr_data);
    146
    147	sr_data->enable_on_init = sr_enable_on_init;
    148
    149exit:
    150	i++;
    151
    152	return 0;
    153}
    154
    155#ifdef CONFIG_OMAP_HWMOD
    156static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
    157{
    158	struct omap_smartreflex_dev_attr *sr_dev_attr;
    159
    160	sr_dev_attr = (struct omap_smartreflex_dev_attr *)oh->dev_attr;
    161	if (!sr_dev_attr || !sr_dev_attr->sensor_voltdm_name) {
    162		pr_err("%s: No voltage domain specified for %s. Cannot initialize\n",
    163		       __func__, oh->name);
    164		return 0;
    165	}
    166
    167	return sr_init_by_name(oh->name, sr_dev_attr->sensor_voltdm_name);
    168}
    169#else
    170static int __init sr_dev_init(struct omap_hwmod *oh, void *user)
    171{
    172	return -EINVAL;
    173}
    174#endif
    175
    176/*
    177 * API to be called from board files to enable smartreflex
    178 * autocompensation at init.
    179 */
    180void __init omap_enable_smartreflex_on_init(void)
    181{
    182	sr_enable_on_init = true;
    183}
    184
    185static const char * const omap4_sr_instances[] = {
    186	"mpu",
    187	"iva",
    188	"core",
    189};
    190
    191static const char * const dra7_sr_instances[] = {
    192	"mpu",
    193	"core",
    194};
    195
    196int __init omap_devinit_smartreflex(void)
    197{
    198	const char * const *sr_inst = NULL;
    199	int i, nr_sr = 0;
    200
    201	if (soc_is_omap44xx()) {
    202		sr_inst = omap4_sr_instances;
    203		nr_sr = ARRAY_SIZE(omap4_sr_instances);
    204
    205	} else if (soc_is_dra7xx()) {
    206		sr_inst = dra7_sr_instances;
    207		nr_sr = ARRAY_SIZE(dra7_sr_instances);
    208	}
    209
    210	if (nr_sr) {
    211		const char *name, *voltdm;
    212
    213		for (i = 0; i < nr_sr; i++) {
    214			name = kasprintf(GFP_KERNEL, "smartreflex_%s", sr_inst[i]);
    215			voltdm = sr_inst[i];
    216			sr_init_by_name(name, voltdm);
    217		}
    218
    219		return 0;
    220	}
    221
    222	return omap_hwmod_for_each_by_class("smartreflex", sr_dev_init, NULL);
    223}