From 2cd7f47983a38397c32bdf4fefeb35cd13600edb Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 3 May 2020 22:19:46 +0800 Subject: thermal: Add thermal driver for i.MX8M The driver is ported form Linux Kernel and support driver model. Users need to provide the tmu node and sensors nodes in DTB. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/thermal/imx_tmu.c | 325 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 drivers/thermal/imx_tmu.c (limited to 'drivers/thermal/imx_tmu.c') diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c new file mode 100644 index 00000000000..f496ce03b65 --- /dev/null +++ b/drivers/thermal/imx_tmu.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2017~2020 NXP + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +#define SITES_MAX 16 + +#define TMR_DISABLE 0x0 +#define TMR_ME 0x80000000 +#define TMR_ALPF 0x0c000000 +#define TMTMIR_DEFAULT 0x00000002 +#define TIER_DISABLE 0x0 + +/* + * i.MX TMU Registers + */ +struct imx_tmu_site_regs { + u32 tritsr; /* Immediate Temperature Site Register */ + u32 tratsr; /* Average Temperature Site Register */ + u8 res0[0x8]; +}; + +struct imx_tmu_regs { + u32 tmr; /* Mode Register */ + u32 tsr; /* Status Register */ + u32 tmtmir; /* Temperature measurement interval Register */ + u8 res0[0x14]; + u32 tier; /* Interrupt Enable Register */ + u32 tidr; /* Interrupt Detect Register */ + u32 tiscr; /* Interrupt Site Capture Register */ + u32 ticscr; /* Interrupt Critical Site Capture Register */ + u8 res1[0x10]; + u32 tmhtcrh; /* High Temperature Capture Register */ + u32 tmhtcrl; /* Low Temperature Capture Register */ + u8 res2[0x8]; + u32 tmhtitr; /* High Temperature Immediate Threshold */ + u32 tmhtatr; /* High Temperature Average Threshold */ + u32 tmhtactr; /* High Temperature Average Crit Threshold */ + u8 res3[0x24]; + u32 ttcfgr; /* Temperature Configuration Register */ + u32 tscfgr; /* Sensor Configuration Register */ + u8 res4[0x78]; + struct imx_tmu_site_regs site[SITES_MAX]; + u8 res5[0x9f8]; + u32 ipbrr0; /* IP Block Revision Register 0 */ + u32 ipbrr1; /* IP Block Revision Register 1 */ + u8 res6[0x310]; + u32 ttr0cr; /* Temperature Range 0 Control Register */ + u32 ttr1cr; /* Temperature Range 1 Control Register */ + u32 ttr2cr; /* Temperature Range 2 Control Register */ + u32 ttr3cr; /* Temperature Range 3 Control Register */ +}; + +struct imx_tmu_plat { + int critical; + int alert; + int polling_delay; + int id; + bool zone_node; + struct imx_tmu_regs *regs; +}; + +static int read_temperature(struct udevice *dev, int *temp) +{ + struct imx_tmu_plat *pdata = dev_get_platdata(dev); + u32 val; + + do { + val = readl(&pdata->regs->site[pdata->id].tritsr); + } while (!(val & 0x80000000)); + + *temp = (val & 0xff) * 1000; + + return 0; +} + +int imx_tmu_get_temp(struct udevice *dev, int *temp) +{ + struct imx_tmu_plat *pdata = dev_get_platdata(dev); + int cpu_tmp = 0; + int ret; + + ret = read_temperature(dev, &cpu_tmp); + if (ret) + return ret; + + while (cpu_tmp >= pdata->alert) { + printf("CPU Temperature (%dC) has beyond alert (%dC), close to critical (%dC)", cpu_tmp, pdata->alert, pdata->critical); + puts(" waiting...\n"); + mdelay(pdata->polling_delay); + ret = read_temperature(dev, &cpu_tmp); + if (ret) + return ret; + } + + *temp = cpu_tmp / 1000; + + return 0; +} + +static const struct dm_thermal_ops imx_tmu_ops = { + .get_temp = imx_tmu_get_temp, +}; + +static int imx_tmu_calibration(struct udevice *dev) +{ + int i, val, len, ret; + u32 range[4]; + const fdt32_t *calibration; + struct imx_tmu_plat *pdata = dev_get_platdata(dev); + + debug("%s\n", __func__); + + ret = dev_read_u32_array(dev, "fsl,tmu-range", range, 4); + if (ret) { + printf("TMU: missing calibration range, ret = %d.\n", ret); + return ret; + } + + /* Init temperature range registers */ + writel(range[0], &pdata->regs->ttr0cr); + writel(range[1], &pdata->regs->ttr1cr); + writel(range[2], &pdata->regs->ttr2cr); + writel(range[3], &pdata->regs->ttr3cr); + + calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len); + if (!calibration || len % 8) { + printf("TMU: invalid calibration data.\n"); + return -ENODEV; + } + + for (i = 0; i < len; i += 8, calibration += 2) { + val = fdt32_to_cpu(*calibration); + writel(val, &pdata->regs->ttcfgr); + val = fdt32_to_cpu(*(calibration + 1)); + writel(val, &pdata->regs->tscfgr); + } + + return 0; +} + +static void imx_tmu_init(struct imx_tmu_plat *pdata) +{ + debug("%s\n", __func__); + + /* Disable monitoring */ + writel(TMR_DISABLE, &pdata->regs->tmr); + + /* Disable interrupt, using polling instead */ + writel(TIER_DISABLE, &pdata->regs->tier); + + /* Set update_interval */ + writel(TMTMIR_DEFAULT, &pdata->regs->tmtmir); +} + +static int imx_tmu_enable_msite(struct udevice *dev) +{ + struct imx_tmu_plat *pdata = dev_get_platdata(dev); + u32 reg; + + debug("%s\n", __func__); + + if (!pdata->regs) + return -EIO; + + /* Clear the ME before setting MSITE and ALPF*/ + reg = readl(&pdata->regs->tmr); + reg &= ~TMR_ME; + writel(reg, &pdata->regs->tmr); + + reg |= 1 << (15 - pdata->id); + reg |= TMR_ALPF; + writel(reg, &pdata->regs->tmr); + + /* Enable ME */ + reg |= TMR_ME; + writel(reg, &pdata->regs->tmr); + + return 0; +} + +static int imx_tmu_bind(struct udevice *dev) +{ + struct imx_tmu_plat *pdata = dev_get_platdata(dev); + int ret; + ofnode node, offset; + const char *name; + const void *prop; + + debug("%s dev name %s\n", __func__, dev->name); + + prop = dev_read_prop(dev, "compatible", NULL); + if (!prop) + return 0; + + pdata->zone_node = 1; + + node = ofnode_path("/thermal-zones"); + ofnode_for_each_subnode(offset, node) { + /* Bind the subnode to this driver */ + name = ofnode_get_name(offset); + + ret = device_bind_with_driver_data(dev, dev->driver, name, + dev->driver_data, offset, + NULL); + if (ret) + printf("Error binding driver '%s': %d\n", + dev->driver->name, ret); + } + + return 0; +} + +static int imx_tmu_parse_fdt(struct udevice *dev) +{ + struct imx_tmu_plat *pdata = dev_get_platdata(dev), *p_parent_data; + struct ofnode_phandle_args args; + ofnode trips_np; + int ret; + + debug("%s dev name %s\n", __func__, dev->name); + + if (pdata->zone_node) { + pdata->regs = (struct imx_tmu_regs *)dev_read_addr_ptr(dev); + + if (!pdata->regs) + return -EINVAL; + return 0; + } + + p_parent_data = dev_get_platdata(dev->parent); + if (p_parent_data->zone_node) + pdata->regs = p_parent_data->regs; + + ret = dev_read_phandle_with_args(dev, "thermal-sensors", + "#thermal-sensor-cells", + 0, 0, &args); + if (ret) + return ret; + + if (!ofnode_equal(args.node, dev_ofnode(dev->parent))) + return -EFAULT; + + if (args.args_count >= 1) + pdata->id = args.args[0]; + else + pdata->id = 0; + + debug("args.args_count %d, id %d\n", args.args_count, pdata->id); + + pdata->polling_delay = dev_read_u32_default(dev, "polling-delay", 1000); + + trips_np = ofnode_path("/thermal-zones/cpu-thermal/trips"); + ofnode_for_each_subnode(trips_np, trips_np) { + const char *type; + + type = ofnode_get_property(trips_np, "type", NULL); + if (!type) + continue; + if (!strcmp(type, "critical")) + pdata->critical = ofnode_read_u32_default(trips_np, "temperature", 85); + else if (strcmp(type, "passive") == 0) + pdata->alert = ofnode_read_u32_default(trips_np, "temperature", 80); + else + continue; + } + + debug("id %d polling_delay %d, critical %d, alert %d\n", + pdata->id, pdata->polling_delay, pdata->critical, pdata->alert); + + return 0; +} + +static int imx_tmu_probe(struct udevice *dev) +{ + struct imx_tmu_plat *pdata = dev_get_platdata(dev); + int ret; + + ret = imx_tmu_parse_fdt(dev); + if (ret) { + printf("Error in parsing TMU FDT %d\n", ret); + return ret; + } + + if (pdata->zone_node) { + imx_tmu_init(pdata); + imx_tmu_calibration(dev); + } else { + imx_tmu_enable_msite(dev); + } + + return 0; +} + +static const struct udevice_id imx_tmu_ids[] = { + { .compatible = "fsl,imx8mq-tmu", }, + { } +}; + +U_BOOT_DRIVER(imx_tmu) = { + .name = "imx_tmu", + .id = UCLASS_THERMAL, + .ops = &imx_tmu_ops, + .of_match = imx_tmu_ids, + .bind = imx_tmu_bind, + .probe = imx_tmu_probe, + .platdata_auto_alloc_size = sizeof(struct imx_tmu_plat), + .flags = DM_FLAG_PRE_RELOC, +}; -- cgit v1.2.3 From fc8657b7fb526b253c9d97f1fe34e40ceadc7c35 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 3 May 2020 22:19:47 +0800 Subject: thermal: imx_tmu: Add support for thermal sensor on iMX8MM The analog sensors on iMX8MM are new, used for 14LPP process. So the Temperature Sensor Monitoring Unit (TMU) has some change accordingly. We use version 2 in TMU driver to represent the new TMU, so the one driver can service for both i.MX8MQ/M. Signed-off-by: Peng Fan --- drivers/thermal/imx_tmu.c | 113 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 27 deletions(-) (limited to 'drivers/thermal/imx_tmu.c') diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c index f496ce03b65..df0b35b7ba3 100644 --- a/drivers/thermal/imx_tmu.c +++ b/drivers/thermal/imx_tmu.c @@ -20,6 +20,7 @@ DECLARE_GLOBAL_DATA_PTR; #define SITES_MAX 16 +#define FLAGS_VER2 0x1 #define TMR_DISABLE 0x0 #define TMR_ME 0x80000000 @@ -27,6 +28,8 @@ DECLARE_GLOBAL_DATA_PTR; #define TMTMIR_DEFAULT 0x00000002 #define TIER_DISABLE 0x0 +#define TER_EN 0x80000000 +#define TER_ADC_PD 0x40000000 /* * i.MX TMU Registers */ @@ -67,22 +70,47 @@ struct imx_tmu_regs { u32 ttr3cr; /* Temperature Range 3 Control Register */ }; +struct imx_tmu_regs_v2 { + u32 ter; /* TMU enable Register */ + u32 tsr; /* Status Register */ + u32 tier; /* Interrupt enable register */ + u32 tidr; /* Interrupt detect register */ + u32 tmhtitr; /* Monitor high temperature immediate threshold register */ + u32 tmhtatr; /* Monitor high temperature average threshold register */ + u32 tmhtactr; /* TMU monitor high temperature average critical threshold register */ + u32 tscr; /* Sensor value capture register */ + u32 tritsr; /* Report immediate temperature site register 0 */ + u32 tratsr; /* Report average temperature site register 0 */ + u32 tasr; /* Amplifier setting register */ + u32 ttmc; /* Test MUX control */ + u32 tcaliv; +}; + +union tmu_regs { + struct imx_tmu_regs regs_v1; + struct imx_tmu_regs_v2 regs_v2; +}; + struct imx_tmu_plat { int critical; int alert; int polling_delay; int id; bool zone_node; - struct imx_tmu_regs *regs; + union tmu_regs *regs; }; static int read_temperature(struct udevice *dev, int *temp) { struct imx_tmu_plat *pdata = dev_get_platdata(dev); + ulong drv_data = dev_get_driver_data(dev); u32 val; do { - val = readl(&pdata->regs->site[pdata->id].tritsr); + if (drv_data & FLAGS_VER2) { + val = readl(&pdata->regs->regs_v2.tritsr); + else + val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr); } while (!(val & 0x80000000)); *temp = (val & 0xff) * 1000; @@ -124,9 +152,13 @@ static int imx_tmu_calibration(struct udevice *dev) u32 range[4]; const fdt32_t *calibration; struct imx_tmu_plat *pdata = dev_get_platdata(dev); + ulong drv_data = dev_get_driver_data(dev); debug("%s\n", __func__); + if (drv_data & FLAGS_VER2) + return 0; + ret = dev_read_u32_array(dev, "fsl,tmu-range", range, 4); if (ret) { printf("TMU: missing calibration range, ret = %d.\n", ret); @@ -134,10 +166,10 @@ static int imx_tmu_calibration(struct udevice *dev) } /* Init temperature range registers */ - writel(range[0], &pdata->regs->ttr0cr); - writel(range[1], &pdata->regs->ttr1cr); - writel(range[2], &pdata->regs->ttr2cr); - writel(range[3], &pdata->regs->ttr3cr); + writel(range[0], &pdata->regs->regs_v1.ttr0cr); + writel(range[1], &pdata->regs->regs_v1.ttr1cr); + writel(range[2], &pdata->regs->regs_v1.ttr2cr); + writel(range[3], &pdata->regs->regs_v1.ttr3cr); calibration = dev_read_prop(dev, "fsl,tmu-calibration", &len); if (!calibration || len % 8) { @@ -147,31 +179,43 @@ static int imx_tmu_calibration(struct udevice *dev) for (i = 0; i < len; i += 8, calibration += 2) { val = fdt32_to_cpu(*calibration); - writel(val, &pdata->regs->ttcfgr); + writel(val, &pdata->regs->regs_v1.ttcfgr); val = fdt32_to_cpu(*(calibration + 1)); - writel(val, &pdata->regs->tscfgr); + writel(val, &pdata->regs->regs_v1.tscfgr); } return 0; } -static void imx_tmu_init(struct imx_tmu_plat *pdata) +static void imx_tmu_init(struct udevice *dev) { + struct imx_tmu_plat *pdata = dev_get_platdata(dev); + ulong drv_data = dev_get_driver_data(dev); + debug("%s\n", __func__); - /* Disable monitoring */ - writel(TMR_DISABLE, &pdata->regs->tmr); + if (drv_data & FLAGS_VER2) { + /* Disable monitoring */ + writel(0x0, &pdata->regs->regs_v2.ter); + + /* Disable interrupt, using polling instead */ + writel(0x0, &pdata->regs->regs_v2.tier); + } else { + /* Disable monitoring */ + writel(TMR_DISABLE, &pdata->regs->regs_v1.tmr); - /* Disable interrupt, using polling instead */ - writel(TIER_DISABLE, &pdata->regs->tier); + /* Disable interrupt, using polling instead */ + writel(TIER_DISABLE, &pdata->regs->regs_v1.tier); - /* Set update_interval */ - writel(TMTMIR_DEFAULT, &pdata->regs->tmtmir); + /* Set update_interval */ + writel(TMTMIR_DEFAULT, &pdata->regs->regs_v1.tmtmir); + } } static int imx_tmu_enable_msite(struct udevice *dev) { struct imx_tmu_plat *pdata = dev_get_platdata(dev); + ulong drv_data = dev_get_driver_data(dev); u32 reg; debug("%s\n", __func__); @@ -179,18 +223,32 @@ static int imx_tmu_enable_msite(struct udevice *dev) if (!pdata->regs) return -EIO; - /* Clear the ME before setting MSITE and ALPF*/ - reg = readl(&pdata->regs->tmr); - reg &= ~TMR_ME; - writel(reg, &pdata->regs->tmr); + if (drv_data & FLAGS_VER2) { + reg = readl(&pdata->regs->regs_v2.ter); + reg &= ~TER_EN; + writel(reg, &pdata->regs->regs_v2.ter); - reg |= 1 << (15 - pdata->id); - reg |= TMR_ALPF; - writel(reg, &pdata->regs->tmr); + reg &= ~TER_ALPF; + reg |= 0x1; + writel(reg, &pdata->regs->regs_v2.ter); - /* Enable ME */ - reg |= TMR_ME; - writel(reg, &pdata->regs->tmr); + /* Enable monitor */ + reg |= TER_EN; + writel(reg, &pdata->regs->regs_v2.ter); + } else { + /* Clear the ME before setting MSITE and ALPF*/ + reg = readl(&pdata->regs->regs_v1.tmr); + reg &= ~TMR_ME; + writel(reg, &pdata->regs->regs_v1.tmr); + + reg |= 1 << (15 - pdata->id); + reg |= TMR_ALPF; + writel(reg, &pdata->regs->regs_v1.tmr); + + /* Enable ME */ + reg |= TMR_ME; + writel(reg, &pdata->regs->regs_v1.tmr); + } return 0; } @@ -237,7 +295,7 @@ static int imx_tmu_parse_fdt(struct udevice *dev) debug("%s dev name %s\n", __func__, dev->name); if (pdata->zone_node) { - pdata->regs = (struct imx_tmu_regs *)dev_read_addr_ptr(dev); + pdata->regs = (union tmu_regs *)dev_read_addr_ptr(dev); if (!pdata->regs) return -EINVAL; @@ -299,7 +357,7 @@ static int imx_tmu_probe(struct udevice *dev) } if (pdata->zone_node) { - imx_tmu_init(pdata); + imx_tmu_init(dev); imx_tmu_calibration(dev); } else { imx_tmu_enable_msite(dev); @@ -310,6 +368,7 @@ static int imx_tmu_probe(struct udevice *dev) static const struct udevice_id imx_tmu_ids[] = { { .compatible = "fsl,imx8mq-tmu", }, + { .compatible = "fsl,imx8mm-tmu", .data = FLAGS_VER2, }, { } }; -- cgit v1.2.3 From 84897408c688e3d3962e8cd7e92f3ad99c17005d Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 3 May 2020 22:19:48 +0800 Subject: thermal: imx_tmu: support TMU arch level initialization i.MX8MM TMU needs to load some registers from fuse, this is arch dependent operation and may vary on different platforms. So add a interface for arch level initialization. Signed-off-by: Peng Fan --- drivers/thermal/imx_tmu.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/thermal/imx_tmu.c') diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c index df0b35b7ba3..049f32c39ea 100644 --- a/drivers/thermal/imx_tmu.c +++ b/drivers/thermal/imx_tmu.c @@ -187,6 +187,10 @@ static int imx_tmu_calibration(struct udevice *dev) return 0; } +void __weak imx_tmu_arch_init(void *reg_base) +{ +} + static void imx_tmu_init(struct udevice *dev) { struct imx_tmu_plat *pdata = dev_get_platdata(dev); @@ -210,6 +214,8 @@ static void imx_tmu_init(struct udevice *dev) /* Set update_interval */ writel(TMTMIR_DEFAULT, &pdata->regs->regs_v1.tmtmir); } + + imx_tmu_arch_init((void *)pdata->regs); } static int imx_tmu_enable_msite(struct udevice *dev) -- cgit v1.2.3 From b5447b98f24784459225ea0cc2729b1cdb1e3136 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 3 May 2020 22:19:49 +0800 Subject: thermal: imx_tmu: Fix for temperature out of range When the temperature is out of sensor's range, the Valid bit won't be set in TRITSR register. So the polling loop won't go out. Change the codes to retry 10 times with 100ms interval for the Valid bit. If the timeout, we give a warning for the invalid data. Modifed from Ye's NXP patch Signed-off-by: Peng Fan --- drivers/thermal/imx_tmu.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers/thermal/imx_tmu.c') diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c index 049f32c39ea..2a08d5085cf 100644 --- a/drivers/thermal/imx_tmu.c +++ b/drivers/thermal/imx_tmu.c @@ -105,15 +105,22 @@ static int read_temperature(struct udevice *dev, int *temp) struct imx_tmu_plat *pdata = dev_get_platdata(dev); ulong drv_data = dev_get_driver_data(dev); u32 val; + u32 retry = 10; do { - if (drv_data & FLAGS_VER2) { + mdelay(100); + retry--; + + if (drv_data & FLAGS_VER2) val = readl(&pdata->regs->regs_v2.tritsr); else val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr); - } while (!(val & 0x80000000)); + } while (!(val & 0x80000000) && retry > 0); - *temp = (val & 0xff) * 1000; + if (retry > 0) + *temp = (val & 0xff) * 1000; + else + return -EINVAL; return 0; } -- cgit v1.2.3 From 951bf19dae2198c7684e4bb3f1eae10ba60d3677 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 3 May 2020 22:19:50 +0800 Subject: thermal: imx_tmu: Check the TEMP range for iMX8MM On iMX8MM, the V flag in TRISTR register only reflect the state of SNSR value, not the calibrated TEMP value. So checking this flag is not reliable. Per IC suggestion, change to read the TEMP/AVG_TEMP directly and check whether it in valid range 10-125C. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/thermal/imx_tmu.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers/thermal/imx_tmu.c') diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c index 2a08d5085cf..c577b0bd6cd 100644 --- a/drivers/thermal/imx_tmu.c +++ b/drivers/thermal/imx_tmu.c @@ -106,16 +106,24 @@ static int read_temperature(struct udevice *dev, int *temp) ulong drv_data = dev_get_driver_data(dev); u32 val; u32 retry = 10; + u32 valid = 0; do { mdelay(100); retry--; - if (drv_data & FLAGS_VER2) + if (drv_data & FLAGS_VER2) { val = readl(&pdata->regs->regs_v2.tritsr); - else + /* + * Check if TEMP is in valid range, the V bit in TRITSR + * only reflects the RAW uncalibrated data + */ + valid = ((val & 0xff) < 10 || (val & 0xff) > 125) ? 0 : 1; + } else { val = readl(&pdata->regs->regs_v1.site[pdata->id].tritsr); - } while (!(val & 0x80000000) && retry > 0); + valid = val & 0x80000000; + } + } while (!valid && retry > 0); if (retry > 0) *temp = (val & 0xff) * 1000; -- cgit v1.2.3 From 634fe73eedb9551a13296f356afae67539583f17 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Sun, 3 May 2020 22:19:51 +0800 Subject: thermal: imx_tmu: support i.MX8MP Support i.MX8MP thermal which has two probes and supports temperature range from -40 to 125. Still uses default 1p HW calibration at 25C and loads calibration parameters from fuse. Signed-off-by: Ye Li Signed-off-by: Peng Fan --- drivers/thermal/imx_tmu.c | 76 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 7 deletions(-) (limited to 'drivers/thermal/imx_tmu.c') diff --git a/drivers/thermal/imx_tmu.c b/drivers/thermal/imx_tmu.c index c577b0bd6cd..4ca22089b8b 100644 --- a/drivers/thermal/imx_tmu.c +++ b/drivers/thermal/imx_tmu.c @@ -21,6 +21,7 @@ DECLARE_GLOBAL_DATA_PTR; #define SITES_MAX 16 #define FLAGS_VER2 0x1 +#define FLAGS_VER3 0x2 #define TMR_DISABLE 0x0 #define TMR_ME 0x80000000 @@ -30,6 +31,8 @@ DECLARE_GLOBAL_DATA_PTR; #define TER_EN 0x80000000 #define TER_ADC_PD 0x40000000 +#define TER_ALPF 0x3 + /* * i.MX TMU Registers */ @@ -86,9 +89,29 @@ struct imx_tmu_regs_v2 { u32 tcaliv; }; +struct imx_tmu_regs_v3 { + u32 ter; /* TMU enable Register */ + u32 tps; /* Status Register */ + u32 tier; /* Interrupt enable register */ + u32 tidr; /* Interrupt detect register */ + u32 tmhtitr; /* Monitor high temperature immediate threshold register */ + u32 tmhtatr; /* Monitor high temperature average threshold register */ + u32 tmhtactr; /* TMU monitor high temperature average critical threshold register */ + u32 tscr; /* Sensor value capture register */ + u32 tritsr; /* Report immediate temperature site register 0 */ + u32 tratsr; /* Report average temperature site register 0 */ + u32 tasr; /* Amplifier setting register */ + u32 ttmc; /* Test MUX control */ + u32 tcaliv0; + u32 tcaliv1; + u32 tcaliv_m40; + u32 trim; +}; + union tmu_regs { struct imx_tmu_regs regs_v1; struct imx_tmu_regs_v2 regs_v2; + struct imx_tmu_regs_v3 regs_v3; }; struct imx_tmu_plat { @@ -112,7 +135,10 @@ static int read_temperature(struct udevice *dev, int *temp) mdelay(100); retry--; - if (drv_data & FLAGS_VER2) { + if (drv_data & FLAGS_VER3) { + val = readl(&pdata->regs->regs_v3.tritsr); + valid = val & (1 << (30 + pdata->id)); + } else if (drv_data & FLAGS_VER2) { val = readl(&pdata->regs->regs_v2.tritsr); /* * Check if TEMP is in valid range, the V bit in TRITSR @@ -125,10 +151,23 @@ static int read_temperature(struct udevice *dev, int *temp) } } while (!valid && retry > 0); - if (retry > 0) - *temp = (val & 0xff) * 1000; - else + if (retry > 0) { + if (drv_data & FLAGS_VER3) { + val = (val >> (pdata->id * 16)) & 0xff; + if (val & 0x80) /* Negative */ + val = (~(val & 0x7f) + 1); + + *temp = val; + if (*temp < -40 || *temp > 125) /* Check the range */ + return -EINVAL; + + *temp *= 1000; + } else { + *temp = (val & 0xff) * 1000; + } + } else { return -EINVAL; + } return 0; } @@ -171,7 +210,7 @@ static int imx_tmu_calibration(struct udevice *dev) debug("%s\n", __func__); - if (drv_data & FLAGS_VER2) + if (drv_data & (FLAGS_VER2 | FLAGS_VER3)) return 0; ret = dev_read_u32_array(dev, "fsl,tmu-range", range, 4); @@ -213,7 +252,14 @@ static void imx_tmu_init(struct udevice *dev) debug("%s\n", __func__); - if (drv_data & FLAGS_VER2) { + if (drv_data & FLAGS_VER3) { + /* Disable monitoring */ + writel(0x0, &pdata->regs->regs_v3.ter); + + /* Disable interrupt, using polling instead */ + writel(0x0, &pdata->regs->regs_v3.tier); + + } else if (drv_data & FLAGS_VER2) { /* Disable monitoring */ writel(0x0, &pdata->regs->regs_v2.ter); @@ -244,7 +290,22 @@ static int imx_tmu_enable_msite(struct udevice *dev) if (!pdata->regs) return -EIO; - if (drv_data & FLAGS_VER2) { + if (drv_data & FLAGS_VER3) { + reg = readl(&pdata->regs->regs_v3.ter); + reg &= ~TER_EN; + writel(reg, &pdata->regs->regs_v3.ter); + + writel(pdata->id << 30, &pdata->regs->regs_v3.tps); + + reg &= ~TER_ALPF; + reg |= 0x1; + reg &= ~TER_ADC_PD; + writel(reg, &pdata->regs->regs_v3.ter); + + /* Enable monitor */ + reg |= TER_EN; + writel(reg, &pdata->regs->regs_v3.ter); + } else if (drv_data & FLAGS_VER2) { reg = readl(&pdata->regs->regs_v2.ter); reg &= ~TER_EN; writel(reg, &pdata->regs->regs_v2.ter); @@ -390,6 +451,7 @@ static int imx_tmu_probe(struct udevice *dev) static const struct udevice_id imx_tmu_ids[] = { { .compatible = "fsl,imx8mq-tmu", }, { .compatible = "fsl,imx8mm-tmu", .data = FLAGS_VER2, }, + { .compatible = "fsl,imx8mp-tmu", .data = FLAGS_VER3, }, { } }; -- cgit v1.2.3