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

qoriq_thermal.c (9714B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Copyright 2016 Freescale Semiconductor, Inc.
      4
      5#include <linux/clk.h>
      6#include <linux/err.h>
      7#include <linux/io.h>
      8#include <linux/module.h>
      9#include <linux/of.h>
     10#include <linux/platform_device.h>
     11#include <linux/regmap.h>
     12#include <linux/sizes.h>
     13#include <linux/thermal.h>
     14#include <linux/units.h>
     15
     16#include "thermal_core.h"
     17#include "thermal_hwmon.h"
     18
     19#define SITES_MAX		16
     20#define TMR_DISABLE		0x0
     21#define TMR_ME			0x80000000
     22#define TMR_ALPF		0x0c000000
     23#define TMR_ALPF_V2		0x03000000
     24#define TMTMIR_DEFAULT	0x0000000f
     25#define TIER_DISABLE	0x0
     26#define TEUMR0_V2		0x51009c00
     27#define TMSARA_V2		0xe
     28#define TMU_VER1		0x1
     29#define TMU_VER2		0x2
     30
     31#define REGS_TMR	0x000	/* Mode Register */
     32#define TMR_DISABLE	0x0
     33#define TMR_ME		0x80000000
     34#define TMR_ALPF	0x0c000000
     35#define TMR_MSITE_ALL	GENMASK(15, 0)
     36
     37#define REGS_TMTMIR	0x008	/* Temperature measurement interval Register */
     38#define TMTMIR_DEFAULT	0x0000000f
     39
     40#define REGS_V2_TMSR	0x008	/* monitor site register */
     41
     42#define REGS_V2_TMTMIR	0x00c	/* Temperature measurement interval Register */
     43
     44#define REGS_TIER	0x020	/* Interrupt Enable Register */
     45#define TIER_DISABLE	0x0
     46
     47
     48#define REGS_TTCFGR	0x080	/* Temperature Configuration Register */
     49#define REGS_TSCFGR	0x084	/* Sensor Configuration Register */
     50
     51#define REGS_TRITSR(n)	(0x100 + 16 * (n)) /* Immediate Temperature
     52					    * Site Register
     53					    */
     54#define TRITSR_V	BIT(31)
     55#define REGS_V2_TMSAR(n)	(0x304 + 16 * (n))	/* TMU monitoring
     56						* site adjustment register
     57						*/
     58#define REGS_TTRnCR(n)	(0xf10 + 4 * (n)) /* Temperature Range n
     59					   * Control Register
     60					   */
     61#define REGS_IPBRR(n)		(0xbf8 + 4 * (n)) /* IP Block Revision
     62						   * Register n
     63						   */
     64#define REGS_V2_TEUMR(n)	(0xf00 + 4 * (n))
     65
     66/*
     67 * Thermal zone data
     68 */
     69struct qoriq_sensor {
     70	int				id;
     71};
     72
     73struct qoriq_tmu_data {
     74	int ver;
     75	struct regmap *regmap;
     76	struct clk *clk;
     77	struct qoriq_sensor	sensor[SITES_MAX];
     78};
     79
     80static struct qoriq_tmu_data *qoriq_sensor_to_data(struct qoriq_sensor *s)
     81{
     82	return container_of(s, struct qoriq_tmu_data, sensor[s->id]);
     83}
     84
     85static int tmu_get_temp(void *p, int *temp)
     86{
     87	struct qoriq_sensor *qsensor = p;
     88	struct qoriq_tmu_data *qdata = qoriq_sensor_to_data(qsensor);
     89	u32 val;
     90	/*
     91	 * REGS_TRITSR(id) has the following layout:
     92	 *
     93	 * For TMU Rev1:
     94	 * 31  ... 7 6 5 4 3 2 1 0
     95	 *  V          TEMP
     96	 *
     97	 * Where V bit signifies if the measurement is ready and is
     98	 * within sensor range. TEMP is an 8 bit value representing
     99	 * temperature in Celsius.
    100
    101	 * For TMU Rev2:
    102	 * 31  ... 8 7 6 5 4 3 2 1 0
    103	 *  V          TEMP
    104	 *
    105	 * Where V bit signifies if the measurement is ready and is
    106	 * within sensor range. TEMP is an 9 bit value representing
    107	 * temperature in KelVin.
    108	 */
    109	if (regmap_read_poll_timeout(qdata->regmap,
    110				     REGS_TRITSR(qsensor->id),
    111				     val,
    112				     val & TRITSR_V,
    113				     USEC_PER_MSEC,
    114				     10 * USEC_PER_MSEC))
    115		return -ENODATA;
    116
    117	if (qdata->ver == TMU_VER1)
    118		*temp = (val & GENMASK(7, 0)) * MILLIDEGREE_PER_DEGREE;
    119	else
    120		*temp = kelvin_to_millicelsius(val & GENMASK(8, 0));
    121
    122	return 0;
    123}
    124
    125static const struct thermal_zone_of_device_ops tmu_tz_ops = {
    126	.get_temp = tmu_get_temp,
    127};
    128
    129static int qoriq_tmu_register_tmu_zone(struct device *dev,
    130				       struct qoriq_tmu_data *qdata)
    131{
    132	int id;
    133
    134	if (qdata->ver == TMU_VER1) {
    135		regmap_write(qdata->regmap, REGS_TMR,
    136			     TMR_MSITE_ALL | TMR_ME | TMR_ALPF);
    137	} else {
    138		regmap_write(qdata->regmap, REGS_V2_TMSR, TMR_MSITE_ALL);
    139		regmap_write(qdata->regmap, REGS_TMR, TMR_ME | TMR_ALPF_V2);
    140	}
    141
    142	for (id = 0; id < SITES_MAX; id++) {
    143		struct thermal_zone_device *tzd;
    144		struct qoriq_sensor *sensor = &qdata->sensor[id];
    145		int ret;
    146
    147		sensor->id = id;
    148
    149		tzd = devm_thermal_zone_of_sensor_register(dev, id,
    150							   sensor,
    151							   &tmu_tz_ops);
    152		ret = PTR_ERR_OR_ZERO(tzd);
    153		if (ret) {
    154			if (ret == -ENODEV)
    155				continue;
    156
    157			regmap_write(qdata->regmap, REGS_TMR, TMR_DISABLE);
    158			return ret;
    159		}
    160
    161		if (devm_thermal_add_hwmon_sysfs(tzd))
    162			dev_warn(dev,
    163				 "Failed to add hwmon sysfs attributes\n");
    164
    165	}
    166
    167	return 0;
    168}
    169
    170static int qoriq_tmu_calibration(struct device *dev,
    171				 struct qoriq_tmu_data *data)
    172{
    173	int i, val, len;
    174	u32 range[4];
    175	const u32 *calibration;
    176	struct device_node *np = dev->of_node;
    177
    178	len = of_property_count_u32_elems(np, "fsl,tmu-range");
    179	if (len < 0 || len > 4) {
    180		dev_err(dev, "invalid range data.\n");
    181		return len;
    182	}
    183
    184	val = of_property_read_u32_array(np, "fsl,tmu-range", range, len);
    185	if (val != 0) {
    186		dev_err(dev, "failed to read range data.\n");
    187		return val;
    188	}
    189
    190	/* Init temperature range registers */
    191	for (i = 0; i < len; i++)
    192		regmap_write(data->regmap, REGS_TTRnCR(i), range[i]);
    193
    194	calibration = of_get_property(np, "fsl,tmu-calibration", &len);
    195	if (calibration == NULL || len % 8) {
    196		dev_err(dev, "invalid calibration data.\n");
    197		return -ENODEV;
    198	}
    199
    200	for (i = 0; i < len; i += 8, calibration += 2) {
    201		val = of_read_number(calibration, 1);
    202		regmap_write(data->regmap, REGS_TTCFGR, val);
    203		val = of_read_number(calibration + 1, 1);
    204		regmap_write(data->regmap, REGS_TSCFGR, val);
    205	}
    206
    207	return 0;
    208}
    209
    210static void qoriq_tmu_init_device(struct qoriq_tmu_data *data)
    211{
    212	int i;
    213
    214	/* Disable interrupt, using polling instead */
    215	regmap_write(data->regmap, REGS_TIER, TIER_DISABLE);
    216
    217	/* Set update_interval */
    218
    219	if (data->ver == TMU_VER1) {
    220		regmap_write(data->regmap, REGS_TMTMIR, TMTMIR_DEFAULT);
    221	} else {
    222		regmap_write(data->regmap, REGS_V2_TMTMIR, TMTMIR_DEFAULT);
    223		regmap_write(data->regmap, REGS_V2_TEUMR(0), TEUMR0_V2);
    224		for (i = 0; i < SITES_MAX; i++)
    225			regmap_write(data->regmap, REGS_V2_TMSAR(i), TMSARA_V2);
    226	}
    227
    228	/* Disable monitoring */
    229	regmap_write(data->regmap, REGS_TMR, TMR_DISABLE);
    230}
    231
    232static const struct regmap_range qoriq_yes_ranges[] = {
    233	regmap_reg_range(REGS_TMR, REGS_TSCFGR),
    234	regmap_reg_range(REGS_TTRnCR(0), REGS_TTRnCR(3)),
    235	regmap_reg_range(REGS_V2_TEUMR(0), REGS_V2_TEUMR(2)),
    236	regmap_reg_range(REGS_V2_TMSAR(0), REGS_V2_TMSAR(15)),
    237	regmap_reg_range(REGS_IPBRR(0), REGS_IPBRR(1)),
    238	/* Read only registers below */
    239	regmap_reg_range(REGS_TRITSR(0), REGS_TRITSR(15)),
    240};
    241
    242static const struct regmap_access_table qoriq_wr_table = {
    243	.yes_ranges	= qoriq_yes_ranges,
    244	.n_yes_ranges	= ARRAY_SIZE(qoriq_yes_ranges) - 1,
    245};
    246
    247static const struct regmap_access_table qoriq_rd_table = {
    248	.yes_ranges	= qoriq_yes_ranges,
    249	.n_yes_ranges	= ARRAY_SIZE(qoriq_yes_ranges),
    250};
    251
    252static void qoriq_tmu_action(void *p)
    253{
    254	struct qoriq_tmu_data *data = p;
    255
    256	regmap_write(data->regmap, REGS_TMR, TMR_DISABLE);
    257	clk_disable_unprepare(data->clk);
    258}
    259
    260static int qoriq_tmu_probe(struct platform_device *pdev)
    261{
    262	int ret;
    263	u32 ver;
    264	struct qoriq_tmu_data *data;
    265	struct device_node *np = pdev->dev.of_node;
    266	struct device *dev = &pdev->dev;
    267	const bool little_endian = of_property_read_bool(np, "little-endian");
    268	const enum regmap_endian format_endian =
    269		little_endian ? REGMAP_ENDIAN_LITTLE : REGMAP_ENDIAN_BIG;
    270	const struct regmap_config regmap_config = {
    271		.reg_bits		= 32,
    272		.val_bits		= 32,
    273		.reg_stride		= 4,
    274		.rd_table		= &qoriq_rd_table,
    275		.wr_table		= &qoriq_wr_table,
    276		.val_format_endian	= format_endian,
    277		.max_register		= SZ_4K,
    278	};
    279	void __iomem *base;
    280
    281	data = devm_kzalloc(dev, sizeof(struct qoriq_tmu_data),
    282			    GFP_KERNEL);
    283	if (!data)
    284		return -ENOMEM;
    285
    286	base = devm_platform_ioremap_resource(pdev, 0);
    287	ret = PTR_ERR_OR_ZERO(base);
    288	if (ret) {
    289		dev_err(dev, "Failed to get memory region\n");
    290		return ret;
    291	}
    292
    293	data->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
    294	ret = PTR_ERR_OR_ZERO(data->regmap);
    295	if (ret) {
    296		dev_err(dev, "Failed to init regmap (%d)\n", ret);
    297		return ret;
    298	}
    299
    300	data->clk = devm_clk_get_optional(dev, NULL);
    301	if (IS_ERR(data->clk))
    302		return PTR_ERR(data->clk);
    303
    304	ret = clk_prepare_enable(data->clk);
    305	if (ret) {
    306		dev_err(dev, "Failed to enable clock\n");
    307		return ret;
    308	}
    309
    310	ret = devm_add_action_or_reset(dev, qoriq_tmu_action, data);
    311	if (ret)
    312		return ret;
    313
    314	/* version register offset at: 0xbf8 on both v1 and v2 */
    315	ret = regmap_read(data->regmap, REGS_IPBRR(0), &ver);
    316	if (ret) {
    317		dev_err(&pdev->dev, "Failed to read IP block version\n");
    318		return ret;
    319	}
    320	data->ver = (ver >> 8) & 0xff;
    321
    322	qoriq_tmu_init_device(data);	/* TMU initialization */
    323
    324	ret = qoriq_tmu_calibration(dev, data);	/* TMU calibration */
    325	if (ret < 0)
    326		return ret;
    327
    328	ret = qoriq_tmu_register_tmu_zone(dev, data);
    329	if (ret < 0) {
    330		dev_err(dev, "Failed to register sensors\n");
    331		return ret;
    332	}
    333
    334	platform_set_drvdata(pdev, data);
    335
    336	return 0;
    337}
    338
    339static int __maybe_unused qoriq_tmu_suspend(struct device *dev)
    340{
    341	struct qoriq_tmu_data *data = dev_get_drvdata(dev);
    342	int ret;
    343
    344	ret = regmap_update_bits(data->regmap, REGS_TMR, TMR_ME, 0);
    345	if (ret)
    346		return ret;
    347
    348	clk_disable_unprepare(data->clk);
    349
    350	return 0;
    351}
    352
    353static int __maybe_unused qoriq_tmu_resume(struct device *dev)
    354{
    355	int ret;
    356	struct qoriq_tmu_data *data = dev_get_drvdata(dev);
    357
    358	ret = clk_prepare_enable(data->clk);
    359	if (ret)
    360		return ret;
    361
    362	/* Enable monitoring */
    363	return regmap_update_bits(data->regmap, REGS_TMR, TMR_ME, TMR_ME);
    364}
    365
    366static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
    367			 qoriq_tmu_suspend, qoriq_tmu_resume);
    368
    369static const struct of_device_id qoriq_tmu_match[] = {
    370	{ .compatible = "fsl,qoriq-tmu", },
    371	{ .compatible = "fsl,imx8mq-tmu", },
    372	{},
    373};
    374MODULE_DEVICE_TABLE(of, qoriq_tmu_match);
    375
    376static struct platform_driver qoriq_tmu = {
    377	.driver	= {
    378		.name		= "qoriq_thermal",
    379		.pm		= &qoriq_tmu_pm_ops,
    380		.of_match_table	= qoriq_tmu_match,
    381	},
    382	.probe	= qoriq_tmu_probe,
    383};
    384module_platform_driver(qoriq_tmu);
    385
    386MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>");
    387MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver");
    388MODULE_LICENSE("GPL v2");