Dear Akshay, On 06/02/13 22:18, Akshay Saraswat wrote: > Adding Exynos Thermal Management Unit driver to monitor SOC > temperature and take actions corresponding to states of TMU. > > Signed-off-by: Akshay Saraswat <aksha...@samsung.com> > Acked-by: Simon Glass <s...@chromium.org> > --- > Changes since v8: > - None. > > arch/arm/include/asm/arch-exynos/exynos-tmu.h | 58 +++++ > drivers/power/Makefile | 1 + > drivers/power/exynos-tmu.c | 302 > +++++++++++++++++++++++++ > include/tmu.h | 46 ++++ > 4 files changed, 407 insertions(+) > create mode 100644 arch/arm/include/asm/arch-exynos/exynos-tmu.h > create mode 100644 drivers/power/exynos-tmu.c > create mode 100644 include/tmu.h > > diff --git a/arch/arm/include/asm/arch-exynos/exynos-tmu.h > b/arch/arm/include/asm/arch-exynos/exynos-tmu.h > new file mode 100644 > index 0000000..c79a520 > --- /dev/null > +++ b/arch/arm/include/asm/arch-exynos/exynos-tmu.h
just tmu.h please. > @@ -0,0 +1,58 @@ > +/* > + * Copyright (c) 2012 Samsung Electronics Co., Ltd. > + * http://www.samsung.com > + * Akshay Saraswat <aksha...@samsung.com> > + * > + * EXYNOS - Thermal Management Unit > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, > + * MA 02111-1307 USA > + */ > + > +#ifndef __ASM_ARCH_TMU_H > +#define __ASM_ARCH_TMU_H > + > +struct tmu_reg { is it for exynos5? or exynos4? or both? > + unsigned triminfo; > + unsigned rsvd1; > + unsigned rsvd2; > + unsigned rsvd3; > + unsigned rsvd4; > + unsigned triminfo_control; > + unsigned rsvd5; > + unsigned rsvd6; > + unsigned tmu_control; > + unsigned rsvd7; > + unsigned tmu_status; > + unsigned sampling_internal; > + unsigned counter_value0; > + unsigned counter_value1; > + unsigned rsvd8; > + unsigned rsvd9; > + unsigned current_temp; > + unsigned rsvd10; > + unsigned rsvd11; > + unsigned rsvd12; > + unsigned threshold_temp_rise; > + unsigned threshold_temp_fall; > + unsigned rsvd13; > + unsigned rsvd14; > + unsigned past_temp3_0; > + unsigned past_temp7_4; > + unsigned past_temp11_8; > + unsigned past_temp15_12; > + unsigned inten; > + unsigned intstat; > + unsigned intclear; > + unsigned rsvd15; > + unsigned emul_con; > +}; > +#endif /* __ASM_ARCH_THERMAL_H */ > diff --git a/drivers/power/Makefile b/drivers/power/Makefile > index 8c71901..1dac16a 100644 > --- a/drivers/power/Makefile > +++ b/drivers/power/Makefile > @@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk > > LIB := $(obj)libpower.o > > +COBJS-$(CONFIG_EXYNOS_TMU) += exynos-tmu.o > COBJS-$(CONFIG_FTPMU010_POWER) += ftpmu010.o > COBJS-$(CONFIG_TPS6586X_POWER) += tps6586x.o > COBJS-$(CONFIG_TWL4030_POWER) += twl4030.o > diff --git a/drivers/power/exynos-tmu.c b/drivers/power/exynos-tmu.c > new file mode 100644 > index 0000000..b010883 > --- /dev/null > +++ b/drivers/power/exynos-tmu.c > @@ -0,0 +1,302 @@ > +/* > + * Copyright (c) 2012 Samsung Electronics Co., Ltd. > + * http://www.samsung.com > + * Akshay Saraswat <aksha...@samsung.com> > + * > + * EXYNOS - Thermal Management Unit > + * > + * See file CREDITS for list of people who contributed to this > + * project. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, > + * MA 02111-1307 USA > + */ > + > +#include <common.h> > +#include <errno.h> > +#include <fdtdec.h> > +#include <tmu.h> > +#include <asm/arch/exynos-tmu.h> > + > +#define TRIMINFO_RELOAD 1 > +#define CORE_EN 1 > + > +#define INTEN_RISE0 1 > +#define INTEN_RISE1 (1 << 4) > +#define INTEN_RISE2 (1 << 8) > +#define INTEN_FALL0 (1 << 16) > +#define INTEN_FALL1 (1 << 20) > +#define INTEN_FALL2 (1 << 24) > + > +#define TRIM_INFO_MASK 0xff > + > +#define INTCLEAR_RISE0 1 > +#define INTCLEAR_RISE1 (1 << 4) > +#define INTCLEAR_RISE2 (1 << 8) > +#define INTCLEAR_FALL0 (1 << 16) > +#define INTCLEAR_FALL1 (1 << 20) > +#define INTCLEAR_FALL2 (1 << 24) > +#define INTCLEARALL (INTCLEAR_RISE0 | INTCLEAR_RISE1 | \ > + INTCLEAR_RISE2 | INTCLEAR_FALL0 | \ > + INTCLEAR_FALL1 | INTCLEAR_FALL2) > + > +/* Tmeperature threshold values for various thermal events */ > +struct temperature_params { > + /* minimum value in temperature code range */ > + unsigned int min_val; > + /* maximum value in temperature code range */ > + unsigned int max_val; > + /* temperature threshold to start warning */ > + unsigned int start_warning; > + /* temperature threshold CPU tripping */ > + unsigned int start_tripping; > +}; > + > +/* Pre-defined values and thresholds for calibration of current temperature > */ > +struct tmu_data { > + /* pre-defined temperature thresholds */ > + struct temperature_params ts; > + /* pre-defined efuse range minimum value */ > + unsigned int efuse_min_value; > + /* pre-defined efuse value for temperature calibration */ > + unsigned int efuse_value; > + /* pre-defined efuse range maximum value */ > + unsigned int efuse_max_value; > + /* current temperature sensing slope */ > + unsigned int slope; > +}; > + > +/* TMU device specific details and status */ > +struct tmu_info { > + /* base Address for the TMU */ > + unsigned tmu_base; > + /* pre-defined values for calibration and thresholds */ > + struct tmu_data data; > + /* value required for triminfo_25 calibration */ > + unsigned int te1; > + /* value required for triminfo_85 calibration */ > + unsigned int te2; > + /* Value for measured data calibration */ > + int dc_value; > + /* enum value indicating status of the TMU */ > + int tmu_state; > +}; > + > +/* Global struct tmu_info variable to store init values */ > +static struct tmu_info gbl_info; > + > +/* > + * Get current temperature code from register, > + * then calculate and calibrate it's value > + * in degree celsius. > + * > + * @return current temperature of the chip as sensed by TMU > + */ > +int get_cur_temp(struct tmu_info *info) static? > +{ > + int cur_temp; > + struct tmu_reg *reg = (struct tmu_reg *)info->tmu_base; > + > + /* > + * Temperature code range between min 25 and max 125. > + * May run more than once for first call as initial sensing > + * has not yet happened. > + */ > + do { > + cur_temp = readl(®->current_temp) & 0xff; > + } while (cur_temp == 0 && info->tmu_state == TMU_STATUS_NORMAL); > + > + /* Calibrate current temperature */ > + cur_temp = cur_temp - info->te1 + info->dc_value; > + > + return cur_temp; > +} > + > +/* > + * Monitors status of the TMU device and exynos temperature > + * > + * @param temp pointer to the current temperature value > + * @return enum tmu_status_t value, code indicating event to execute > + */ > +enum tmu_status_t tmu_monitor(int *temp) > +{ > + if (gbl_info.tmu_state == TMU_STATUS_INIT) > + return TMU_STATUS_INIT; > + > + int cur_temp; > + struct tmu_data *data = &gbl_info.data; please move this declaration to start of function. > + > + /* Read current temperature of the SOC */ > + cur_temp = get_cur_temp(&gbl_info); > + *temp = cur_temp; > + > + /* Temperature code lies between min 25 and max 125 */ > + if (cur_temp >= data->ts.start_tripping && > + cur_temp <= data->ts.max_val) { > + return TMU_STATUS_TRIPPED; > + } else if (cur_temp >= data->ts.start_warning) { > + return TMU_STATUS_WARNING; > + } else if (cur_temp < data->ts.start_warning && > + cur_temp >= data->ts.min_val) { > + return TMU_STATUS_NORMAL; > + /* Temperature code does not lie between min 25 and max 125 */ is this comment for what? please move this comment to correct position. > + } else { > + gbl_info.tmu_state = TMU_STATUS_INIT; > + debug("EXYNOS_TMU: Thermal reading failed\n"); > + return TMU_STATUS_INIT; > + } > +} > + > +/* > + * Get TMU specific pre-defined values from FDT > + * > + * @param info pointer to the tmu_info struct > + * @param blob FDT blob > + * @return int value, 0 for success > + */ > +int get_tmu_fdt_values(struct tmu_info *info, const void *blob) static? > +{ #ifdef CONFIG_OF_CONTROL? > + int node; > + int error = 0; > + > + /* Get the node from FDT for TMU */ > + node = fdtdec_next_compatible(blob, 0, > + COMPAT_SAMSUNG_EXYNOS_TMU); > + if (node < 0) { > + debug("EXYNOS_TMU: No node for tmu in device tree\n"); > + return -1; > + } > + > + /* > + * Get the pre-defined TMU specific values from FDT. > + * All of these are expected to be correct otherwise > + * miscalculation of register values in tmu_setup_parameters > + * may result in misleading current temperature. > + */ > + info->tmu_base = fdtdec_get_addr(blob, node, "reg"); > + if (info->tmu_base == FDT_ADDR_T_NONE) { > + debug("%s: Missing tmu-base\n", __func__); > + return -1; > + } > + info->data.ts.min_val = fdtdec_get_int(blob, > + node, "samsung,min-temp", -1); > + error |= info->data.ts.min_val; > + info->data.ts.max_val = fdtdec_get_int(blob, > + node, "samsung,max-temp", -1); > + error |= info->data.ts.max_val; > + info->data.ts.start_warning = fdtdec_get_int(blob, > + node, "samsung,start-warning", -1); > + error |= info->data.ts.start_warning; > + info->data.ts.start_tripping = fdtdec_get_int(blob, > + node, "samsung,start-tripping", -1); > + error |= info->data.ts.start_tripping; > + info->data.efuse_min_value = fdtdec_get_int(blob, > + node, "samsung,efuse-min-value", -1); > + error |= info->data.efuse_min_value; > + info->data.efuse_value = fdtdec_get_int(blob, > + node, "samsung,efuse-value", -1); > + error |= info->data.efuse_value; > + info->data.efuse_max_value = fdtdec_get_int(blob, > + node, "samsung,efuse-max-value", -1); > + error |= info->data.efuse_max_value; > + info->data.slope = fdtdec_get_int(blob, > + node, "samsung,slope", -1); > + error |= info->data.slope; > + info->dc_value = fdtdec_get_int(blob, > + node, "samsung,dc-value", -1); > + error |= info->dc_value; > + > + if (error == -1) { > + debug("fail to get tmu node properties\n"); > + return -1; > + } > + > + return 0; > +} > + > +/* > + * Calibrate and calculate threshold values and > + * enable interrupt levels > + * > + * @param info pointer to the tmu_info struct > + */ > +void tmu_setup_parameters(struct tmu_info *info) static? > +{ > + unsigned int te_code, con; > + unsigned int warning_code, trip_code; > + unsigned int cooling_temp; > + unsigned int rising_value; > + struct tmu_data *data = &info->data; > + struct tmu_reg *reg = (struct tmu_reg *)info->tmu_base; > + > + /* Must reload for reading efuse value from triminfo register */ > + writel(TRIMINFO_RELOAD, ®->triminfo_control); > + > + /* Get the compensation parameter */ > + te_code = readl(®->triminfo); > + info->te1 = te_code & TRIM_INFO_MASK; > + info->te2 = ((te_code >> 8) & TRIM_INFO_MASK); > + > + if ((data->efuse_min_value > info->te1) || > + (info->te1 > data->efuse_max_value) > + || (info->te2 != 0)) > + info->te1 = data->efuse_value; > + > + /* Get RISING & FALLING Threshold value */ > + warning_code = data->ts.start_warning > + + info->te1 - info->dc_value; > + trip_code = data->ts.start_tripping > + + info->te1 - info->dc_value; > + cooling_temp = 0; > + > + rising_value = ((warning_code << 8) | (trip_code << 16)); > + > + /* Set interrupt level */ > + writel(rising_value, ®->threshold_temp_rise); > + writel(cooling_temp, ®->threshold_temp_fall); > + > + /* > + * Init TMU control tuning parameters > + * [28:24] VREF - Voltage reference > + * [15:13] THERM_TRIP_MODE - Tripping mode > + * [12] THERM_TRIP_EN - Thermal tripping enable > + * [11:8] BUF_SLOPE_SEL - Gain of amplifier > + * [6] THERM_TRIP_BY_TQ_EN - Tripping by TQ pin > + */ > + writel(data->slope, ®->tmu_control); > + > + writel(INTCLEARALL, ®->intclear); > + > + /* TMU core enable */ > + con = readl(®->tmu_control); > + con |= CORE_EN; > + > + writel(con, ®->tmu_control); > + > + /* LEV0 LEV1 LEV2 interrupt enable */ > + writel(INTEN_RISE0 | INTEN_RISE1 | INTEN_RISE2, ®->inten); > +} > + > +/* > + * Initialize TMU device > + * > + * @param blob FDT blob > + * @return int value, 0 for success > + */ > +int tmu_init(const void *blob) > +{ > + gbl_info.tmu_state = TMU_STATUS_INIT; > + if (get_tmu_fdt_values(&gbl_info, blob) < 0) > + return -1; > + > + tmu_setup_parameters(&gbl_info); > + gbl_info.tmu_state = TMU_STATUS_NORMAL; > + debug("EXYNOS_TMU: Available\n"); > + > + return 0; > +} Thanks, Minkyu Kang. _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot