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

imx8mm_thermal.c (5523B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright 2020 NXP.
      4 *
      5 * Author: Anson Huang <Anson.Huang@nxp.com>
      6 */
      7
      8#include <linux/bitfield.h>
      9#include <linux/clk.h>
     10#include <linux/err.h>
     11#include <linux/io.h>
     12#include <linux/module.h>
     13#include <linux/of.h>
     14#include <linux/of_device.h>
     15#include <linux/platform_device.h>
     16#include <linux/thermal.h>
     17
     18#include "thermal_core.h"
     19
     20#define TER			0x0	/* TMU enable */
     21#define TPS			0x4
     22#define TRITSR			0x20	/* TMU immediate temp */
     23
     24#define TER_ADC_PD		BIT(30)
     25#define TER_EN			BIT(31)
     26#define TRITSR_TEMP0_VAL_MASK	0xff
     27#define TRITSR_TEMP1_VAL_MASK	0xff0000
     28
     29#define PROBE_SEL_ALL		GENMASK(31, 30)
     30
     31#define probe_status_offset(x)	(30 + x)
     32#define SIGN_BIT		BIT(7)
     33#define TEMP_VAL_MASK		GENMASK(6, 0)
     34
     35#define VER1_TEMP_LOW_LIMIT	10000
     36#define VER2_TEMP_LOW_LIMIT	-40000
     37#define VER2_TEMP_HIGH_LIMIT	125000
     38
     39#define TMU_VER1		0x1
     40#define TMU_VER2		0x2
     41
     42struct thermal_soc_data {
     43	u32 num_sensors;
     44	u32 version;
     45	int (*get_temp)(void *, int *);
     46};
     47
     48struct tmu_sensor {
     49	struct imx8mm_tmu *priv;
     50	u32 hw_id;
     51	struct thermal_zone_device *tzd;
     52};
     53
     54struct imx8mm_tmu {
     55	void __iomem *base;
     56	struct clk *clk;
     57	const struct thermal_soc_data *socdata;
     58	struct tmu_sensor sensors[];
     59};
     60
     61static int imx8mm_tmu_get_temp(void *data, int *temp)
     62{
     63	struct tmu_sensor *sensor = data;
     64	struct imx8mm_tmu *tmu = sensor->priv;
     65	u32 val;
     66
     67	val = readl_relaxed(tmu->base + TRITSR) & TRITSR_TEMP0_VAL_MASK;
     68	*temp = val * 1000;
     69	if (*temp < VER1_TEMP_LOW_LIMIT)
     70		return -EAGAIN;
     71
     72	return 0;
     73}
     74
     75static int imx8mp_tmu_get_temp(void *data, int *temp)
     76{
     77	struct tmu_sensor *sensor = data;
     78	struct imx8mm_tmu *tmu = sensor->priv;
     79	unsigned long val;
     80	bool ready;
     81
     82	val = readl_relaxed(tmu->base + TRITSR);
     83	ready = test_bit(probe_status_offset(sensor->hw_id), &val);
     84	if (!ready)
     85		return -EAGAIN;
     86
     87	val = sensor->hw_id ? FIELD_GET(TRITSR_TEMP1_VAL_MASK, val) :
     88	      FIELD_GET(TRITSR_TEMP0_VAL_MASK, val);
     89	if (val & SIGN_BIT) /* negative */
     90		val = (~(val & TEMP_VAL_MASK) + 1);
     91
     92	*temp = val * 1000;
     93	if (*temp < VER2_TEMP_LOW_LIMIT || *temp > VER2_TEMP_HIGH_LIMIT)
     94		return -EAGAIN;
     95
     96	return 0;
     97}
     98
     99static int tmu_get_temp(void *data, int *temp)
    100{
    101	struct tmu_sensor *sensor = data;
    102	struct imx8mm_tmu *tmu = sensor->priv;
    103
    104	return tmu->socdata->get_temp(data, temp);
    105}
    106
    107static struct thermal_zone_of_device_ops tmu_tz_ops = {
    108	.get_temp = tmu_get_temp,
    109};
    110
    111static void imx8mm_tmu_enable(struct imx8mm_tmu *tmu, bool enable)
    112{
    113	u32 val;
    114
    115	val = readl_relaxed(tmu->base + TER);
    116	val = enable ? (val | TER_EN) : (val & ~TER_EN);
    117	if (tmu->socdata->version == TMU_VER2)
    118		val = enable ? (val & ~TER_ADC_PD) : (val | TER_ADC_PD);
    119	writel_relaxed(val, tmu->base + TER);
    120}
    121
    122static void imx8mm_tmu_probe_sel_all(struct imx8mm_tmu *tmu)
    123{
    124	u32 val;
    125
    126	val = readl_relaxed(tmu->base + TPS);
    127	val |= PROBE_SEL_ALL;
    128	writel_relaxed(val, tmu->base + TPS);
    129}
    130
    131static int imx8mm_tmu_probe(struct platform_device *pdev)
    132{
    133	const struct thermal_soc_data *data;
    134	struct imx8mm_tmu *tmu;
    135	int ret;
    136	int i;
    137
    138	data = of_device_get_match_data(&pdev->dev);
    139
    140	tmu = devm_kzalloc(&pdev->dev, struct_size(tmu, sensors,
    141			   data->num_sensors), GFP_KERNEL);
    142	if (!tmu)
    143		return -ENOMEM;
    144
    145	tmu->socdata = data;
    146
    147	tmu->base = devm_platform_ioremap_resource(pdev, 0);
    148	if (IS_ERR(tmu->base))
    149		return PTR_ERR(tmu->base);
    150
    151	tmu->clk = devm_clk_get(&pdev->dev, NULL);
    152	if (IS_ERR(tmu->clk))
    153		return dev_err_probe(&pdev->dev, PTR_ERR(tmu->clk),
    154				     "failed to get tmu clock\n");
    155
    156	ret = clk_prepare_enable(tmu->clk);
    157	if (ret) {
    158		dev_err(&pdev->dev, "failed to enable tmu clock: %d\n", ret);
    159		return ret;
    160	}
    161
    162	/* disable the monitor during initialization */
    163	imx8mm_tmu_enable(tmu, false);
    164
    165	for (i = 0; i < data->num_sensors; i++) {
    166		tmu->sensors[i].priv = tmu;
    167		tmu->sensors[i].tzd =
    168			devm_thermal_zone_of_sensor_register(&pdev->dev, i,
    169							     &tmu->sensors[i],
    170							     &tmu_tz_ops);
    171		if (IS_ERR(tmu->sensors[i].tzd)) {
    172			ret = PTR_ERR(tmu->sensors[i].tzd);
    173			dev_err(&pdev->dev,
    174				"failed to register thermal zone sensor[%d]: %d\n",
    175				i, ret);
    176			goto disable_clk;
    177		}
    178		tmu->sensors[i].hw_id = i;
    179	}
    180
    181	platform_set_drvdata(pdev, tmu);
    182
    183	/* enable all the probes for V2 TMU */
    184	if (tmu->socdata->version == TMU_VER2)
    185		imx8mm_tmu_probe_sel_all(tmu);
    186
    187	/* enable the monitor */
    188	imx8mm_tmu_enable(tmu, true);
    189
    190	return 0;
    191
    192disable_clk:
    193	clk_disable_unprepare(tmu->clk);
    194	return ret;
    195}
    196
    197static int imx8mm_tmu_remove(struct platform_device *pdev)
    198{
    199	struct imx8mm_tmu *tmu = platform_get_drvdata(pdev);
    200
    201	/* disable TMU */
    202	imx8mm_tmu_enable(tmu, false);
    203
    204	clk_disable_unprepare(tmu->clk);
    205	platform_set_drvdata(pdev, NULL);
    206
    207	return 0;
    208}
    209
    210static struct thermal_soc_data imx8mm_tmu_data = {
    211	.num_sensors = 1,
    212	.version = TMU_VER1,
    213	.get_temp = imx8mm_tmu_get_temp,
    214};
    215
    216static struct thermal_soc_data imx8mp_tmu_data = {
    217	.num_sensors = 2,
    218	.version = TMU_VER2,
    219	.get_temp = imx8mp_tmu_get_temp,
    220};
    221
    222static const struct of_device_id imx8mm_tmu_table[] = {
    223	{ .compatible = "fsl,imx8mm-tmu", .data = &imx8mm_tmu_data, },
    224	{ .compatible = "fsl,imx8mp-tmu", .data = &imx8mp_tmu_data, },
    225	{ },
    226};
    227MODULE_DEVICE_TABLE(of, imx8mm_tmu_table);
    228
    229static struct platform_driver imx8mm_tmu = {
    230	.driver = {
    231		.name	= "i.mx8mm_thermal",
    232		.of_match_table = imx8mm_tmu_table,
    233	},
    234	.probe = imx8mm_tmu_probe,
    235	.remove = imx8mm_tmu_remove,
    236};
    237module_platform_driver(imx8mm_tmu);
    238
    239MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>");
    240MODULE_DESCRIPTION("i.MX8MM Thermal Monitor Unit driver");
    241MODULE_LICENSE("GPL v2");