summaryrefslogtreecommitdiff
path: root/arch/arm/cpu/armv7/mx6/soc.c
diff options
context:
space:
mode:
authorNitin Garg <nitin.garg@freescale.com>2014-05-27 08:34:28 -0500
committerNitin Garg <nitin.garg@freescale.com>2014-05-27 08:34:28 -0500
commita8302d300097a6c17921efda37a500e2a35540dd (patch)
treedc608126b54d32f725595cfedf5cd9452f35dde4 /arch/arm/cpu/armv7/mx6/soc.c
parentdda0dbfc69f3d560c87f5be85f127ed862ea6721 (diff)
downloadu-boot-imx-a8302d300097a6c17921efda37a500e2a35540dd.zip
u-boot-imx-a8302d300097a6c17921efda37a500e2a35540dd.tar.gz
u-boot-imx-a8302d300097a6c17921efda37a500e2a35540dd.tar.bz2
ENGR00315499-1: Add i.MX6 CPU temperature sensor support
Support CPU temperature sensors on i.MX6 SoC. Signed-off-by: Nitin Garg <nitin.garg@freescale.com>
Diffstat (limited to 'arch/arm/cpu/armv7/mx6/soc.c')
-rw-r--r--arch/arm/cpu/armv7/mx6/soc.c137
1 files changed, 136 insertions, 1 deletions
diff --git a/arch/arm/cpu/armv7/mx6/soc.c b/arch/arm/cpu/armv7/mx6/soc.c
index 1725279..b29973f 100644
--- a/arch/arm/cpu/armv7/mx6/soc.c
+++ b/arch/arm/cpu/armv7/mx6/soc.c
@@ -2,7 +2,7 @@
* (C) Copyright 2007
* Sascha Hauer, Pengutronix
*
- * (C) Copyright 2009 Freescale Semiconductor, Inc.
+ * (C) Copyright 2009-2014 Freescale Semiconductor, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -35,6 +35,18 @@ struct scu_regs {
u32 fpga_rev;
};
+#define TEMPERATURE_MIN -40
+#define TEMPERATURE_HOT 80
+#define TEMPERATURE_MAX 125
+#define FACTOR1 15976
+#define FACTOR2 4297157
+#define MEASURE_FREQ 327
+
+#define REG_VALUE_TO_CEL(ratio, raw) \
+ ((raw_n40c - raw) * 100 / ratio - 40)
+
+static unsigned int fuse = ~0;
+
u32 get_cpu_rev(void)
{
struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
@@ -187,6 +199,129 @@ static void imx_set_wdog_powerdown(bool enable)
writew(enable, &wdog2->wmcr);
}
+static int read_cpu_temperature(void)
+{
+ int temperature;
+ unsigned int ccm_ccgr2;
+ unsigned int reg, tmp;
+ unsigned int raw_25c, raw_n40c, ratio;
+ struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
+ struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+ struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
+ struct fuse_bank *bank = &ocotp->bank[1];
+ struct fuse_bank1_regs *fuse_bank1 =
+ (struct fuse_bank1_regs *)bank->fuse_regs;
+
+ /* need to make sure pll3 is enabled for thermal sensor */
+ if ((readl(&anatop->usb1_pll_480_ctrl) &
+ BM_ANADIG_USB1_PLL_480_CTRL_LOCK) == 0) {
+ /* enable pll's power */
+ writel(BM_ANADIG_USB1_PLL_480_CTRL_POWER,
+ &anatop->usb1_pll_480_ctrl_set);
+ writel(0x80, &anatop->ana_misc2_clr);
+ /* wait for pll lock */
+ while ((readl(&anatop->usb1_pll_480_ctrl) &
+ BM_ANADIG_USB1_PLL_480_CTRL_LOCK) == 0)
+ ;
+ /* disable bypass */
+ writel(BM_ANADIG_USB1_PLL_480_CTRL_BYPASS,
+ &anatop->usb1_pll_480_ctrl_clr);
+ /* enable pll output */
+ writel(BM_ANADIG_USB1_PLL_480_CTRL_ENABLE,
+ &anatop->usb1_pll_480_ctrl_set);
+ }
+
+ ccm_ccgr2 = readl(&mxc_ccm->CCGR2);
+ /* enable OCOTP_CTRL clock in CCGR2 */
+ writel(ccm_ccgr2 | MXC_CCM_CCGR2_OCOTP_CTRL_MASK, &mxc_ccm->CCGR2);
+ fuse = readl(&fuse_bank1->ana1);
+
+ /* restore CCGR2 */
+ writel(ccm_ccgr2, &mxc_ccm->CCGR2);
+
+ if (fuse == 0 || fuse == 0xffffffff || (fuse & 0xfff00000) == 0)
+ return TEMPERATURE_MIN;
+
+ /*
+ * fuse data layout:
+ * [31:20] sensor value @ 25C
+ * [19:8] sensor value of hot
+ * [7:0] hot temperature value
+ */
+ raw_25c = fuse >> 20;
+
+ /*
+ * The universal equation for thermal sensor
+ * is slope = 0.4297157 - (0.0015976 * 25C fuse),
+ * here we convert them to integer to make them
+ * easy for counting, FACTOR1 is 15976,
+ * FACTOR2 is 4297157. Our ratio = -100 * slope
+ */
+ ratio = ((FACTOR1 * raw_25c - FACTOR2) + 50000) / 100000;
+
+ debug("Thermal sensor with ratio = %d\n", ratio);
+
+ raw_n40c = raw_25c + (13 * ratio) / 20;
+
+ /*
+ * now we only use single measure, every time we read
+ * the temperature, we will power on/down anadig thermal
+ * module
+ */
+ writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_clr);
+ writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set);
+
+ /* write measure freq */
+ reg = readl(&anatop->tempsense1);
+ reg &= ~BM_ANADIG_TEMPSENSE1_MEASURE_FREQ;
+ reg |= MEASURE_FREQ;
+ writel(reg, &anatop->tempsense1);
+
+ writel(BM_ANADIG_TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_clr);
+ writel(BM_ANADIG_TEMPSENSE0_FINISHED, &anatop->tempsense0_clr);
+ writel(BM_ANADIG_TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_set);
+
+ while ((readl(&anatop->tempsense0) &
+ BM_ANADIG_TEMPSENSE0_FINISHED) == 0)
+ udelay(10000);
+
+ reg = readl(&anatop->tempsense0);
+ tmp = (reg & BM_ANADIG_TEMPSENSE0_TEMP_VALUE)
+ >> BP_ANADIG_TEMPSENSE0_TEMP_VALUE;
+ writel(BM_ANADIG_TEMPSENSE0_FINISHED, &anatop->tempsense0_clr);
+
+ if (tmp <= raw_n40c)
+ temperature = REG_VALUE_TO_CEL(ratio, tmp);
+ else
+ temperature = TEMPERATURE_MIN;
+ /* power down anatop thermal sensor */
+ writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_set);
+ writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_clr);
+
+ return temperature;
+}
+
+void check_cpu_temperature(void)
+{
+ int cpu_tmp = 0;
+
+ cpu_tmp = read_cpu_temperature();
+ while (cpu_tmp > TEMPERATURE_MIN && cpu_tmp < TEMPERATURE_MAX) {
+ if (cpu_tmp >= TEMPERATURE_HOT) {
+ printf("CPU is %d C, too hot to boot, waiting...\n",
+ cpu_tmp);
+ udelay(5000000);
+ cpu_tmp = read_cpu_temperature();
+ } else
+ break;
+ }
+ if (cpu_tmp > TEMPERATURE_MIN && cpu_tmp < TEMPERATURE_MAX)
+ printf("CPU: Temperature %d C, calibration data: 0x%x\n",
+ cpu_tmp, fuse);
+ else
+ printf("CPU: Temperature: can't get valid data!\n");
+}
+
static void set_ahb_rate(u32 val)
{
struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;