18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * thermal support for the cell processor
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This module adds some sysfs attributes to cpu and spu nodes.
68c2ecf20Sopenharmony_ci * Base for measurements are the digital thermal sensors (DTS)
78c2ecf20Sopenharmony_ci * located on the chip.
88c2ecf20Sopenharmony_ci * The accuracy is 2 degrees, starting from 65 up to 125 degrees celsius
98c2ecf20Sopenharmony_ci * The attributes can be found under
108c2ecf20Sopenharmony_ci * /sys/devices/system/cpu/cpuX/thermal
118c2ecf20Sopenharmony_ci * /sys/devices/system/spu/spuX/thermal
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * The following attributes are added for each node:
148c2ecf20Sopenharmony_ci * temperature:
158c2ecf20Sopenharmony_ci *	contains the current temperature measured by the DTS
168c2ecf20Sopenharmony_ci * throttle_begin:
178c2ecf20Sopenharmony_ci *	throttling begins when temperature is greater or equal to
188c2ecf20Sopenharmony_ci *	throttle_begin. Setting this value to 125 prevents throttling.
198c2ecf20Sopenharmony_ci * throttle_end:
208c2ecf20Sopenharmony_ci *	throttling is being ceased, if the temperature is lower than
218c2ecf20Sopenharmony_ci *	throttle_end. Due to a delay between applying throttling and
228c2ecf20Sopenharmony_ci *	a reduced temperature this value should be less than throttle_begin.
238c2ecf20Sopenharmony_ci *	A value equal to throttle_begin provides only a very little hysteresis.
248c2ecf20Sopenharmony_ci * throttle_full_stop:
258c2ecf20Sopenharmony_ci *	If the temperatrue is greater or equal to throttle_full_stop,
268c2ecf20Sopenharmony_ci *	full throttling is applied to the cpu or spu. This value should be
278c2ecf20Sopenharmony_ci *	greater than throttle_begin and throttle_end. Setting this value to
288c2ecf20Sopenharmony_ci *	65 prevents the unit from running code at all.
298c2ecf20Sopenharmony_ci *
308c2ecf20Sopenharmony_ci * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * Author: Christian Krafft <krafft@de.ibm.com>
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/module.h>
368c2ecf20Sopenharmony_ci#include <linux/device.h>
378c2ecf20Sopenharmony_ci#include <linux/kernel.h>
388c2ecf20Sopenharmony_ci#include <linux/cpu.h>
398c2ecf20Sopenharmony_ci#include <linux/stringify.h>
408c2ecf20Sopenharmony_ci#include <asm/spu.h>
418c2ecf20Sopenharmony_ci#include <asm/io.h>
428c2ecf20Sopenharmony_ci#include <asm/prom.h>
438c2ecf20Sopenharmony_ci#include <asm/cell-regs.h>
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#include "spu_priv1_mmio.h"
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define TEMP_MIN 65
488c2ecf20Sopenharmony_ci#define TEMP_MAX 125
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define DEVICE_PREFIX_ATTR(_prefix,_name,_mode)			\
518c2ecf20Sopenharmony_cistruct device_attribute attr_ ## _prefix ## _ ## _name = {	\
528c2ecf20Sopenharmony_ci	.attr = { .name = __stringify(_name), .mode = _mode },	\
538c2ecf20Sopenharmony_ci	.show	= _prefix ## _show_ ## _name,			\
548c2ecf20Sopenharmony_ci	.store	= _prefix ## _store_ ## _name,			\
558c2ecf20Sopenharmony_ci};
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic inline u8 reg_to_temp(u8 reg_value)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	return ((reg_value & 0x3f) << 1) + TEMP_MIN;
608c2ecf20Sopenharmony_ci}
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic inline u8 temp_to_reg(u8 temp)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	return ((temp - TEMP_MIN) >> 1) & 0x3f;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic struct cbe_pmd_regs __iomem *get_pmd_regs(struct device *dev)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct spu *spu;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	spu = container_of(dev, struct spu, dev);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return cbe_get_pmd_regs(spu_devnode(spu));
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/* returns the value for a given spu in a given register */
778c2ecf20Sopenharmony_cistatic u8 spu_read_register_value(struct device *dev, union spe_reg __iomem *reg)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	union spe_reg value;
808c2ecf20Sopenharmony_ci	struct spu *spu;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	spu = container_of(dev, struct spu, dev);
838c2ecf20Sopenharmony_ci	value.val = in_be64(&reg->val);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return value.spe[spu->spe_id];
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic ssize_t spu_show_temp(struct device *dev, struct device_attribute *attr,
898c2ecf20Sopenharmony_ci			char *buf)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	u8 value;
928c2ecf20Sopenharmony_ci	struct cbe_pmd_regs __iomem *pmd_regs;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	pmd_regs = get_pmd_regs(dev);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	value = spu_read_register_value(dev, &pmd_regs->ts_ctsr1);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", reg_to_temp(value));
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic ssize_t show_throttle(struct cbe_pmd_regs __iomem *pmd_regs, char *buf, int pos)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	u64 value;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	value = in_be64(&pmd_regs->tm_tpr.val);
1068c2ecf20Sopenharmony_ci	/* access the corresponding byte */
1078c2ecf20Sopenharmony_ci	value >>= pos;
1088c2ecf20Sopenharmony_ci	value &= 0x3F;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", reg_to_temp(value));
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic ssize_t store_throttle(struct cbe_pmd_regs __iomem *pmd_regs, const char *buf, size_t size, int pos)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	u64 reg_value;
1168c2ecf20Sopenharmony_ci	unsigned int temp;
1178c2ecf20Sopenharmony_ci	u64 new_value;
1188c2ecf20Sopenharmony_ci	int ret;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	ret = sscanf(buf, "%u", &temp);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (ret != 1 || temp < TEMP_MIN || temp > TEMP_MAX)
1238c2ecf20Sopenharmony_ci		return -EINVAL;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	new_value = temp_to_reg(temp);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	reg_value = in_be64(&pmd_regs->tm_tpr.val);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	/* zero out bits for new value */
1308c2ecf20Sopenharmony_ci	reg_value &= ~(0xffull << pos);
1318c2ecf20Sopenharmony_ci	/* set bits to new value */
1328c2ecf20Sopenharmony_ci	reg_value |= new_value << pos;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	out_be64(&pmd_regs->tm_tpr.val, reg_value);
1358c2ecf20Sopenharmony_ci	return size;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic ssize_t spu_show_throttle_end(struct device *dev,
1398c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	return show_throttle(get_pmd_regs(dev), buf, 0);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic ssize_t spu_show_throttle_begin(struct device *dev,
1458c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	return show_throttle(get_pmd_regs(dev), buf, 8);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic ssize_t spu_show_throttle_full_stop(struct device *dev,
1518c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	return show_throttle(get_pmd_regs(dev), buf, 16);
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic ssize_t spu_store_throttle_end(struct device *dev,
1578c2ecf20Sopenharmony_ci			struct device_attribute *attr, const char *buf, size_t size)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	return store_throttle(get_pmd_regs(dev), buf, size, 0);
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic ssize_t spu_store_throttle_begin(struct device *dev,
1638c2ecf20Sopenharmony_ci			struct device_attribute *attr, const char *buf, size_t size)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	return store_throttle(get_pmd_regs(dev), buf, size, 8);
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic ssize_t spu_store_throttle_full_stop(struct device *dev,
1698c2ecf20Sopenharmony_ci			struct device_attribute *attr, const char *buf, size_t size)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	return store_throttle(get_pmd_regs(dev), buf, size, 16);
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic ssize_t ppe_show_temp(struct device *dev, char *buf, int pos)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	struct cbe_pmd_regs __iomem *pmd_regs;
1778c2ecf20Sopenharmony_ci	u64 value;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	pmd_regs = cbe_get_cpu_pmd_regs(dev->id);
1808c2ecf20Sopenharmony_ci	value = in_be64(&pmd_regs->ts_ctsr2);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	value = (value >> pos) & 0x3f;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", reg_to_temp(value));
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci/* shows the temperature of the DTS on the PPE,
1898c2ecf20Sopenharmony_ci * located near the linear thermal sensor */
1908c2ecf20Sopenharmony_cistatic ssize_t ppe_show_temp0(struct device *dev,
1918c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	return ppe_show_temp(dev, buf, 32);
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci/* shows the temperature of the second DTS on the PPE */
1978c2ecf20Sopenharmony_cistatic ssize_t ppe_show_temp1(struct device *dev,
1988c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	return ppe_show_temp(dev, buf, 0);
2018c2ecf20Sopenharmony_ci}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_cistatic ssize_t ppe_show_throttle_end(struct device *dev,
2048c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 32);
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic ssize_t ppe_show_throttle_begin(struct device *dev,
2108c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 40);
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_cistatic ssize_t ppe_show_throttle_full_stop(struct device *dev,
2168c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	return show_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, 48);
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic ssize_t ppe_store_throttle_end(struct device *dev,
2228c2ecf20Sopenharmony_ci			struct device_attribute *attr, const char *buf, size_t size)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 32);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic ssize_t ppe_store_throttle_begin(struct device *dev,
2288c2ecf20Sopenharmony_ci			struct device_attribute *attr, const char *buf, size_t size)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 40);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic ssize_t ppe_store_throttle_full_stop(struct device *dev,
2348c2ecf20Sopenharmony_ci			struct device_attribute *attr, const char *buf, size_t size)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	return store_throttle(cbe_get_cpu_pmd_regs(dev->id), buf, size, 48);
2378c2ecf20Sopenharmony_ci}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_cistatic struct device_attribute attr_spu_temperature = {
2418c2ecf20Sopenharmony_ci	.attr = {.name = "temperature", .mode = 0400 },
2428c2ecf20Sopenharmony_ci	.show = spu_show_temp,
2438c2ecf20Sopenharmony_ci};
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic DEVICE_PREFIX_ATTR(spu, throttle_end, 0600);
2468c2ecf20Sopenharmony_cistatic DEVICE_PREFIX_ATTR(spu, throttle_begin, 0600);
2478c2ecf20Sopenharmony_cistatic DEVICE_PREFIX_ATTR(spu, throttle_full_stop, 0600);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic struct attribute *spu_attributes[] = {
2518c2ecf20Sopenharmony_ci	&attr_spu_temperature.attr,
2528c2ecf20Sopenharmony_ci	&attr_spu_throttle_end.attr,
2538c2ecf20Sopenharmony_ci	&attr_spu_throttle_begin.attr,
2548c2ecf20Sopenharmony_ci	&attr_spu_throttle_full_stop.attr,
2558c2ecf20Sopenharmony_ci	NULL,
2568c2ecf20Sopenharmony_ci};
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic struct attribute_group spu_attribute_group = {
2598c2ecf20Sopenharmony_ci	.name	= "thermal",
2608c2ecf20Sopenharmony_ci	.attrs	= spu_attributes,
2618c2ecf20Sopenharmony_ci};
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic struct device_attribute attr_ppe_temperature0 = {
2648c2ecf20Sopenharmony_ci	.attr = {.name = "temperature0", .mode = 0400 },
2658c2ecf20Sopenharmony_ci	.show = ppe_show_temp0,
2668c2ecf20Sopenharmony_ci};
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic struct device_attribute attr_ppe_temperature1 = {
2698c2ecf20Sopenharmony_ci	.attr = {.name = "temperature1", .mode = 0400 },
2708c2ecf20Sopenharmony_ci	.show = ppe_show_temp1,
2718c2ecf20Sopenharmony_ci};
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic DEVICE_PREFIX_ATTR(ppe, throttle_end, 0600);
2748c2ecf20Sopenharmony_cistatic DEVICE_PREFIX_ATTR(ppe, throttle_begin, 0600);
2758c2ecf20Sopenharmony_cistatic DEVICE_PREFIX_ATTR(ppe, throttle_full_stop, 0600);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic struct attribute *ppe_attributes[] = {
2788c2ecf20Sopenharmony_ci	&attr_ppe_temperature0.attr,
2798c2ecf20Sopenharmony_ci	&attr_ppe_temperature1.attr,
2808c2ecf20Sopenharmony_ci	&attr_ppe_throttle_end.attr,
2818c2ecf20Sopenharmony_ci	&attr_ppe_throttle_begin.attr,
2828c2ecf20Sopenharmony_ci	&attr_ppe_throttle_full_stop.attr,
2838c2ecf20Sopenharmony_ci	NULL,
2848c2ecf20Sopenharmony_ci};
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cistatic struct attribute_group ppe_attribute_group = {
2878c2ecf20Sopenharmony_ci	.name	= "thermal",
2888c2ecf20Sopenharmony_ci	.attrs	= ppe_attributes,
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci/*
2928c2ecf20Sopenharmony_ci * initialize throttling with default values
2938c2ecf20Sopenharmony_ci */
2948c2ecf20Sopenharmony_cistatic int __init init_default_values(void)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	int cpu;
2978c2ecf20Sopenharmony_ci	struct cbe_pmd_regs __iomem *pmd_regs;
2988c2ecf20Sopenharmony_ci	struct device *dev;
2998c2ecf20Sopenharmony_ci	union ppe_spe_reg tpr;
3008c2ecf20Sopenharmony_ci	union spe_reg str1;
3018c2ecf20Sopenharmony_ci	u64 str2;
3028c2ecf20Sopenharmony_ci	union spe_reg cr1;
3038c2ecf20Sopenharmony_ci	u64 cr2;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	/* TPR defaults */
3068c2ecf20Sopenharmony_ci	/* ppe
3078c2ecf20Sopenharmony_ci	 *	1F - no full stop
3088c2ecf20Sopenharmony_ci	 *	08 - dynamic throttling starts if over 80 degrees
3098c2ecf20Sopenharmony_ci	 *	03 - dynamic throttling ceases if below 70 degrees */
3108c2ecf20Sopenharmony_ci	tpr.ppe = 0x1F0803;
3118c2ecf20Sopenharmony_ci	/* spe
3128c2ecf20Sopenharmony_ci	 *	10 - full stopped when over 96 degrees
3138c2ecf20Sopenharmony_ci	 *	08 - dynamic throttling starts if over 80 degrees
3148c2ecf20Sopenharmony_ci	 *	03 - dynamic throttling ceases if below 70 degrees
3158c2ecf20Sopenharmony_ci	 */
3168c2ecf20Sopenharmony_ci	tpr.spe = 0x100803;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* STR defaults */
3198c2ecf20Sopenharmony_ci	/* str1
3208c2ecf20Sopenharmony_ci	 *	10 - stop 16 of 32 cycles
3218c2ecf20Sopenharmony_ci	 */
3228c2ecf20Sopenharmony_ci	str1.val = 0x1010101010101010ull;
3238c2ecf20Sopenharmony_ci	/* str2
3248c2ecf20Sopenharmony_ci	 *	10 - stop 16 of 32 cycles
3258c2ecf20Sopenharmony_ci	 */
3268c2ecf20Sopenharmony_ci	str2 = 0x10;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* CR defaults */
3298c2ecf20Sopenharmony_ci	/* cr1
3308c2ecf20Sopenharmony_ci	 *	4 - normal operation
3318c2ecf20Sopenharmony_ci	 */
3328c2ecf20Sopenharmony_ci	cr1.val = 0x0404040404040404ull;
3338c2ecf20Sopenharmony_ci	/* cr2
3348c2ecf20Sopenharmony_ci	 *	4 - normal operation
3358c2ecf20Sopenharmony_ci	 */
3368c2ecf20Sopenharmony_ci	cr2 = 0x04;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	for_each_possible_cpu (cpu) {
3398c2ecf20Sopenharmony_ci		pr_debug("processing cpu %d\n", cpu);
3408c2ecf20Sopenharmony_ci		dev = get_cpu_device(cpu);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		if (!dev) {
3438c2ecf20Sopenharmony_ci			pr_info("invalid dev pointer for cbe_thermal\n");
3448c2ecf20Sopenharmony_ci			return -EINVAL;
3458c2ecf20Sopenharmony_ci		}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci		pmd_regs = cbe_get_cpu_pmd_regs(dev->id);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci		if (!pmd_regs) {
3508c2ecf20Sopenharmony_ci			pr_info("invalid CBE regs pointer for cbe_thermal\n");
3518c2ecf20Sopenharmony_ci			return -EINVAL;
3528c2ecf20Sopenharmony_ci		}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		out_be64(&pmd_regs->tm_str2, str2);
3558c2ecf20Sopenharmony_ci		out_be64(&pmd_regs->tm_str1.val, str1.val);
3568c2ecf20Sopenharmony_ci		out_be64(&pmd_regs->tm_tpr.val, tpr.val);
3578c2ecf20Sopenharmony_ci		out_be64(&pmd_regs->tm_cr1.val, cr1.val);
3588c2ecf20Sopenharmony_ci		out_be64(&pmd_regs->tm_cr2, cr2);
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	return 0;
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic int __init thermal_init(void)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	int rc = init_default_values();
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	if (rc == 0) {
3708c2ecf20Sopenharmony_ci		spu_add_dev_attr_group(&spu_attribute_group);
3718c2ecf20Sopenharmony_ci		cpu_add_dev_attr_group(&ppe_attribute_group);
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	return rc;
3758c2ecf20Sopenharmony_ci}
3768c2ecf20Sopenharmony_cimodule_init(thermal_init);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic void __exit thermal_exit(void)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	spu_remove_dev_attr_group(&spu_attribute_group);
3818c2ecf20Sopenharmony_ci	cpu_remove_dev_attr_group(&ppe_attribute_group);
3828c2ecf20Sopenharmony_ci}
3838c2ecf20Sopenharmony_cimodule_exit(thermal_exit);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
3868c2ecf20Sopenharmony_ciMODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
3878c2ecf20Sopenharmony_ci
388