* [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-06-30 3:08 ` Jia Hongtao 0 siblings, 0 replies; 18+ messages in thread From: Jia Hongtao @ 2016-06-30 3:08 UTC (permalink / raw) To: edubezval, rui.zhang, robh+dt, galak, scott.wood, shawnguo Cc: linux-pm, devicetree, linux-kernel, linuxppc-dev, linux-arm-kernel, hongtao.jia This driver add thermal management support by enabling TMU (Thermal Monitoring Unit) on QorIQ platform. It's based on thermal of framework: - Trip points defined in device tree. - Cpufreq as cooling device registered in qoriq cpufreq driver. Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> --- Changes of V2: * Add HAS_IOMEM dependency to fix build error on UM drivers/thermal/Kconfig | 10 ++ drivers/thermal/Makefile | 1 + drivers/thermal/qoriq_thermal.c | 328 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 drivers/thermal/qoriq_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 2d702ca..56ef30d 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -195,6 +195,16 @@ config IMX_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config QORIQ_THERMAL + tristate "QorIQ Thermal Monitoring Unit" + depends on THERMAL_OF + depends on HAS_IOMEM + help + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. + It supports one critical trip point and one passive trip point. The + cpufreq is used as the cooling device to throttle CPUs when the + passive trip is crossed. + config SPEAR_THERMAL tristate "SPEAr thermal sensor driver" depends on PLAT_SPEAR || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 10b07c1..6662232 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c new file mode 100644 index 0000000..644ba52 --- /dev/null +++ b/drivers/thermal/qoriq_thermal.c @@ -0,0 +1,328 @@ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/thermal.h> + +#include "thermal_core.h" + +#define SITES_MAX 16 + +/* + * QorIQ TMU Registers + */ +struct qoriq_tmu_site_regs { + u32 tritsr; /* Immediate Temperature Site Register */ + u32 tratsr; /* Average Temperature Site Register */ + u8 res0[0x8]; +}; + +struct qoriq_tmu_regs { + u32 tmr; /* Mode Register */ +#define TMR_DISABLE 0x0 +#define TMR_ME 0x80000000 +#define TMR_ALPF 0x0c000000 + u32 tsr; /* Status Register */ + u32 tmtmir; /* Temperature measurement interval Register */ +#define TMTMIR_DEFAULT 0x0000000f + u8 res0[0x14]; + u32 tier; /* Interrupt Enable Register */ +#define TIER_DISABLE 0x0 + 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 qoriq_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 */ +}; + +/* + * Thermal zone data + */ +struct qoriq_tmu_data { + struct thermal_zone_device *tz; + struct qoriq_tmu_regs __iomem *regs; + int sensor_id; + bool little_endian; +}; + +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem *addr) +{ + if (p->little_endian) + iowrite32(val, addr); + else + iowrite32be(val, addr); +} + +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) +{ + if (p->little_endian) + return ioread32(addr); + else + return ioread32be(addr); +} + +static int tmu_get_temp(void *p, int *temp) +{ + u32 val; + struct qoriq_tmu_data *data = p; + + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); + *temp = (val & 0xff) * 1000; + + return 0; +} + +static int qoriq_tmu_get_sensor_id(void) +{ + int ret, id; + struct of_phandle_args sensor_specs; + struct device_node *np, *sensor_np; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) + return -ENODEV; + + sensor_np = of_get_next_child(np, NULL); + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", + "#thermal-sensor-cells", + 0, &sensor_specs); + if (ret) { + of_node_put(np); + of_node_put(sensor_np); + return ret; + } + + if (sensor_specs.args_count >= 1) { + id = sensor_specs.args[0]; + WARN(sensor_specs.args_count > 1, + "%s: too many cells in sensor specifier %d\n", + sensor_specs.np->name, sensor_specs.args_count); + } else { + id = 0; + } + + of_node_put(np); + of_node_put(sensor_np); + + return id; +} + +static int qoriq_tmu_calibration(struct platform_device *pdev) +{ + int i, val, len; + u32 range[4]; + const u32 *calibration; + struct device_node *np = pdev->dev.of_node; + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { + dev_err(&pdev->dev, "missing calibration range.\n"); + return -ENODEV; + } + + /* Init temperature range registers */ + tmu_write(data, range[0], &data->regs->ttr0cr); + tmu_write(data, range[1], &data->regs->ttr1cr); + tmu_write(data, range[2], &data->regs->ttr2cr); + tmu_write(data, range[3], &data->regs->ttr3cr); + + calibration = of_get_property(np, "fsl,tmu-calibration", &len); + if (calibration == NULL || len % 8) { + dev_err(&pdev->dev, "invalid calibration data.\n"); + return -ENODEV; + } + + for (i = 0; i < len; i += 8, calibration += 2) { + val = of_read_number(calibration, 1); + tmu_write(data, val, &data->regs->ttcfgr); + val = of_read_number(calibration + 1, 1); + tmu_write(data, val, &data->regs->tscfgr); + } + + return 0; +} + +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) +{ + /* Disable interrupt, using polling instead */ + tmu_write(data, TIER_DISABLE, &data->regs->tier); + + /* Set update_interval */ + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); +} + +static struct thermal_zone_of_device_ops tmu_tz_ops = { + .get_temp = tmu_get_temp, +}; + +static int qoriq_tmu_probe(struct platform_device *pdev) +{ + int ret; + const struct thermal_trip *trip; + struct qoriq_tmu_data *data; + struct device_node *np = pdev->dev.of_node; + u32 site = 0; + + if (!np) { + dev_err(&pdev->dev, "Device OF-Node is NULL"); + return -ENODEV; + } + + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + platform_set_drvdata(pdev, data); + + data->little_endian = of_property_read_bool(np, "little-endian"); + + data->sensor_id = qoriq_tmu_get_sensor_id(); + if (data->sensor_id < 0) { + dev_err(&pdev->dev, "Failed to get sensor id\n"); + ret = -ENODEV; + goto err_iomap; + } + + data->regs = of_iomap(np, 0); + if (!data->regs) { + dev_err(&pdev->dev, "Failed to get memory region\n"); + ret = -ENODEV; + goto err_iomap; + } + + qoriq_tmu_init_device(data); /* TMU initialization */ + + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ + if (ret < 0) + goto err_tmu; + + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, + data, &tmu_tz_ops); + if (IS_ERR(data->tz)) { + ret = PTR_ERR(data->tz); + dev_err(&pdev->dev, + "Failed to register thermal zone device %d\n", ret); + goto err_tmu; + } + + trip = of_thermal_get_trip_points(data->tz); + + /* Enable monitoring */ + site |= 0x1 << (15 - data->sensor_id); + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); + + return 0; + +err_tmu: + iounmap(data->regs); + +err_iomap: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int qoriq_tmu_remove(struct platform_device *pdev) +{ + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); + + iounmap(data->regs); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int qoriq_tmu_suspend(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Disable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr &= ~TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} + +static int qoriq_tmu_resume(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Enable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr |= TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, + qoriq_tmu_suspend, qoriq_tmu_resume); + +static const struct of_device_id qoriq_tmu_match[] = { + { .compatible = "fsl,qoriq-tmu", }, + {}, +}; +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); + +static struct platform_driver qoriq_tmu = { + .driver = { + .name = "qoriq_thermal", + .pm = &qoriq_tmu_pm_ops, + .of_match_table = qoriq_tmu_match, + }, + .probe = qoriq_tmu_probe, + .remove = qoriq_tmu_remove, +}; +module_platform_driver(qoriq_tmu); + +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); +MODULE_LICENSE("GPL v2"); -- 2.1.0.27.g96db324 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-06-30 3:08 ` Jia Hongtao 0 siblings, 0 replies; 18+ messages in thread From: Jia Hongtao @ 2016-06-30 3:08 UTC (permalink / raw) To: linux-arm-kernel This driver add thermal management support by enabling TMU (Thermal Monitoring Unit) on QorIQ platform. It's based on thermal of framework: - Trip points defined in device tree. - Cpufreq as cooling device registered in qoriq cpufreq driver. Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> --- Changes of V2: * Add HAS_IOMEM dependency to fix build error on UM drivers/thermal/Kconfig | 10 ++ drivers/thermal/Makefile | 1 + drivers/thermal/qoriq_thermal.c | 328 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 drivers/thermal/qoriq_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 2d702ca..56ef30d 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -195,6 +195,16 @@ config IMX_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config QORIQ_THERMAL + tristate "QorIQ Thermal Monitoring Unit" + depends on THERMAL_OF + depends on HAS_IOMEM + help + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. + It supports one critical trip point and one passive trip point. The + cpufreq is used as the cooling device to throttle CPUs when the + passive trip is crossed. + config SPEAR_THERMAL tristate "SPEAr thermal sensor driver" depends on PLAT_SPEAR || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 10b07c1..6662232 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c new file mode 100644 index 0000000..644ba52 --- /dev/null +++ b/drivers/thermal/qoriq_thermal.c @@ -0,0 +1,328 @@ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/thermal.h> + +#include "thermal_core.h" + +#define SITES_MAX 16 + +/* + * QorIQ TMU Registers + */ +struct qoriq_tmu_site_regs { + u32 tritsr; /* Immediate Temperature Site Register */ + u32 tratsr; /* Average Temperature Site Register */ + u8 res0[0x8]; +}; + +struct qoriq_tmu_regs { + u32 tmr; /* Mode Register */ +#define TMR_DISABLE 0x0 +#define TMR_ME 0x80000000 +#define TMR_ALPF 0x0c000000 + u32 tsr; /* Status Register */ + u32 tmtmir; /* Temperature measurement interval Register */ +#define TMTMIR_DEFAULT 0x0000000f + u8 res0[0x14]; + u32 tier; /* Interrupt Enable Register */ +#define TIER_DISABLE 0x0 + 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 qoriq_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 */ +}; + +/* + * Thermal zone data + */ +struct qoriq_tmu_data { + struct thermal_zone_device *tz; + struct qoriq_tmu_regs __iomem *regs; + int sensor_id; + bool little_endian; +}; + +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem *addr) +{ + if (p->little_endian) + iowrite32(val, addr); + else + iowrite32be(val, addr); +} + +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) +{ + if (p->little_endian) + return ioread32(addr); + else + return ioread32be(addr); +} + +static int tmu_get_temp(void *p, int *temp) +{ + u32 val; + struct qoriq_tmu_data *data = p; + + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); + *temp = (val & 0xff) * 1000; + + return 0; +} + +static int qoriq_tmu_get_sensor_id(void) +{ + int ret, id; + struct of_phandle_args sensor_specs; + struct device_node *np, *sensor_np; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) + return -ENODEV; + + sensor_np = of_get_next_child(np, NULL); + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", + "#thermal-sensor-cells", + 0, &sensor_specs); + if (ret) { + of_node_put(np); + of_node_put(sensor_np); + return ret; + } + + if (sensor_specs.args_count >= 1) { + id = sensor_specs.args[0]; + WARN(sensor_specs.args_count > 1, + "%s: too many cells in sensor specifier %d\n", + sensor_specs.np->name, sensor_specs.args_count); + } else { + id = 0; + } + + of_node_put(np); + of_node_put(sensor_np); + + return id; +} + +static int qoriq_tmu_calibration(struct platform_device *pdev) +{ + int i, val, len; + u32 range[4]; + const u32 *calibration; + struct device_node *np = pdev->dev.of_node; + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { + dev_err(&pdev->dev, "missing calibration range.\n"); + return -ENODEV; + } + + /* Init temperature range registers */ + tmu_write(data, range[0], &data->regs->ttr0cr); + tmu_write(data, range[1], &data->regs->ttr1cr); + tmu_write(data, range[2], &data->regs->ttr2cr); + tmu_write(data, range[3], &data->regs->ttr3cr); + + calibration = of_get_property(np, "fsl,tmu-calibration", &len); + if (calibration == NULL || len % 8) { + dev_err(&pdev->dev, "invalid calibration data.\n"); + return -ENODEV; + } + + for (i = 0; i < len; i += 8, calibration += 2) { + val = of_read_number(calibration, 1); + tmu_write(data, val, &data->regs->ttcfgr); + val = of_read_number(calibration + 1, 1); + tmu_write(data, val, &data->regs->tscfgr); + } + + return 0; +} + +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) +{ + /* Disable interrupt, using polling instead */ + tmu_write(data, TIER_DISABLE, &data->regs->tier); + + /* Set update_interval */ + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); +} + +static struct thermal_zone_of_device_ops tmu_tz_ops = { + .get_temp = tmu_get_temp, +}; + +static int qoriq_tmu_probe(struct platform_device *pdev) +{ + int ret; + const struct thermal_trip *trip; + struct qoriq_tmu_data *data; + struct device_node *np = pdev->dev.of_node; + u32 site = 0; + + if (!np) { + dev_err(&pdev->dev, "Device OF-Node is NULL"); + return -ENODEV; + } + + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + platform_set_drvdata(pdev, data); + + data->little_endian = of_property_read_bool(np, "little-endian"); + + data->sensor_id = qoriq_tmu_get_sensor_id(); + if (data->sensor_id < 0) { + dev_err(&pdev->dev, "Failed to get sensor id\n"); + ret = -ENODEV; + goto err_iomap; + } + + data->regs = of_iomap(np, 0); + if (!data->regs) { + dev_err(&pdev->dev, "Failed to get memory region\n"); + ret = -ENODEV; + goto err_iomap; + } + + qoriq_tmu_init_device(data); /* TMU initialization */ + + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ + if (ret < 0) + goto err_tmu; + + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, + data, &tmu_tz_ops); + if (IS_ERR(data->tz)) { + ret = PTR_ERR(data->tz); + dev_err(&pdev->dev, + "Failed to register thermal zone device %d\n", ret); + goto err_tmu; + } + + trip = of_thermal_get_trip_points(data->tz); + + /* Enable monitoring */ + site |= 0x1 << (15 - data->sensor_id); + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); + + return 0; + +err_tmu: + iounmap(data->regs); + +err_iomap: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int qoriq_tmu_remove(struct platform_device *pdev) +{ + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); + + iounmap(data->regs); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int qoriq_tmu_suspend(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Disable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr &= ~TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} + +static int qoriq_tmu_resume(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Enable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr |= TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, + qoriq_tmu_suspend, qoriq_tmu_resume); + +static const struct of_device_id qoriq_tmu_match[] = { + { .compatible = "fsl,qoriq-tmu", }, + {}, +}; +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); + +static struct platform_driver qoriq_tmu = { + .driver = { + .name = "qoriq_thermal", + .pm = &qoriq_tmu_pm_ops, + .of_match_table = qoriq_tmu_match, + }, + .probe = qoriq_tmu_probe, + .remove = qoriq_tmu_remove, +}; +module_platform_driver(qoriq_tmu); + +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); +MODULE_LICENSE("GPL v2"); -- 2.1.0.27.g96db324 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-06-30 3:08 ` Jia Hongtao 0 siblings, 0 replies; 18+ messages in thread From: Jia Hongtao @ 2016-06-30 3:08 UTC (permalink / raw) To: edubezval, rui.zhang, robh+dt, galak, scott.wood, shawnguo Cc: devicetree, linux-pm, linux-kernel, hongtao.jia, linuxppc-dev, linux-arm-kernel This driver add thermal management support by enabling TMU (Thermal Monitoring Unit) on QorIQ platform. It's based on thermal of framework: - Trip points defined in device tree. - Cpufreq as cooling device registered in qoriq cpufreq driver. Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> --- Changes of V2: * Add HAS_IOMEM dependency to fix build error on UM drivers/thermal/Kconfig | 10 ++ drivers/thermal/Makefile | 1 + drivers/thermal/qoriq_thermal.c | 328 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 339 insertions(+) create mode 100644 drivers/thermal/qoriq_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 2d702ca..56ef30d 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -195,6 +195,16 @@ config IMX_THERMAL cpufreq is used as the cooling device to throttle CPUs when the passive trip is crossed. +config QORIQ_THERMAL + tristate "QorIQ Thermal Monitoring Unit" + depends on THERMAL_OF + depends on HAS_IOMEM + help + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. + It supports one critical trip point and one passive trip point. The + cpufreq is used as the cooling device to throttle CPUs when the + passive trip is crossed. + config SPEAR_THERMAL tristate "SPEAr thermal sensor driver" depends on PLAT_SPEAR || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 10b07c1..6662232 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c new file mode 100644 index 0000000..644ba52 --- /dev/null +++ b/drivers/thermal/qoriq_thermal.c @@ -0,0 +1,328 @@ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/thermal.h> + +#include "thermal_core.h" + +#define SITES_MAX 16 + +/* + * QorIQ TMU Registers + */ +struct qoriq_tmu_site_regs { + u32 tritsr; /* Immediate Temperature Site Register */ + u32 tratsr; /* Average Temperature Site Register */ + u8 res0[0x8]; +}; + +struct qoriq_tmu_regs { + u32 tmr; /* Mode Register */ +#define TMR_DISABLE 0x0 +#define TMR_ME 0x80000000 +#define TMR_ALPF 0x0c000000 + u32 tsr; /* Status Register */ + u32 tmtmir; /* Temperature measurement interval Register */ +#define TMTMIR_DEFAULT 0x0000000f + u8 res0[0x14]; + u32 tier; /* Interrupt Enable Register */ +#define TIER_DISABLE 0x0 + 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 qoriq_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 */ +}; + +/* + * Thermal zone data + */ +struct qoriq_tmu_data { + struct thermal_zone_device *tz; + struct qoriq_tmu_regs __iomem *regs; + int sensor_id; + bool little_endian; +}; + +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem *addr) +{ + if (p->little_endian) + iowrite32(val, addr); + else + iowrite32be(val, addr); +} + +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) +{ + if (p->little_endian) + return ioread32(addr); + else + return ioread32be(addr); +} + +static int tmu_get_temp(void *p, int *temp) +{ + u32 val; + struct qoriq_tmu_data *data = p; + + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); + *temp = (val & 0xff) * 1000; + + return 0; +} + +static int qoriq_tmu_get_sensor_id(void) +{ + int ret, id; + struct of_phandle_args sensor_specs; + struct device_node *np, *sensor_np; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) + return -ENODEV; + + sensor_np = of_get_next_child(np, NULL); + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", + "#thermal-sensor-cells", + 0, &sensor_specs); + if (ret) { + of_node_put(np); + of_node_put(sensor_np); + return ret; + } + + if (sensor_specs.args_count >= 1) { + id = sensor_specs.args[0]; + WARN(sensor_specs.args_count > 1, + "%s: too many cells in sensor specifier %d\n", + sensor_specs.np->name, sensor_specs.args_count); + } else { + id = 0; + } + + of_node_put(np); + of_node_put(sensor_np); + + return id; +} + +static int qoriq_tmu_calibration(struct platform_device *pdev) +{ + int i, val, len; + u32 range[4]; + const u32 *calibration; + struct device_node *np = pdev->dev.of_node; + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { + dev_err(&pdev->dev, "missing calibration range.\n"); + return -ENODEV; + } + + /* Init temperature range registers */ + tmu_write(data, range[0], &data->regs->ttr0cr); + tmu_write(data, range[1], &data->regs->ttr1cr); + tmu_write(data, range[2], &data->regs->ttr2cr); + tmu_write(data, range[3], &data->regs->ttr3cr); + + calibration = of_get_property(np, "fsl,tmu-calibration", &len); + if (calibration == NULL || len % 8) { + dev_err(&pdev->dev, "invalid calibration data.\n"); + return -ENODEV; + } + + for (i = 0; i < len; i += 8, calibration += 2) { + val = of_read_number(calibration, 1); + tmu_write(data, val, &data->regs->ttcfgr); + val = of_read_number(calibration + 1, 1); + tmu_write(data, val, &data->regs->tscfgr); + } + + return 0; +} + +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) +{ + /* Disable interrupt, using polling instead */ + tmu_write(data, TIER_DISABLE, &data->regs->tier); + + /* Set update_interval */ + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); +} + +static struct thermal_zone_of_device_ops tmu_tz_ops = { + .get_temp = tmu_get_temp, +}; + +static int qoriq_tmu_probe(struct platform_device *pdev) +{ + int ret; + const struct thermal_trip *trip; + struct qoriq_tmu_data *data; + struct device_node *np = pdev->dev.of_node; + u32 site = 0; + + if (!np) { + dev_err(&pdev->dev, "Device OF-Node is NULL"); + return -ENODEV; + } + + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + platform_set_drvdata(pdev, data); + + data->little_endian = of_property_read_bool(np, "little-endian"); + + data->sensor_id = qoriq_tmu_get_sensor_id(); + if (data->sensor_id < 0) { + dev_err(&pdev->dev, "Failed to get sensor id\n"); + ret = -ENODEV; + goto err_iomap; + } + + data->regs = of_iomap(np, 0); + if (!data->regs) { + dev_err(&pdev->dev, "Failed to get memory region\n"); + ret = -ENODEV; + goto err_iomap; + } + + qoriq_tmu_init_device(data); /* TMU initialization */ + + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ + if (ret < 0) + goto err_tmu; + + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, + data, &tmu_tz_ops); + if (IS_ERR(data->tz)) { + ret = PTR_ERR(data->tz); + dev_err(&pdev->dev, + "Failed to register thermal zone device %d\n", ret); + goto err_tmu; + } + + trip = of_thermal_get_trip_points(data->tz); + + /* Enable monitoring */ + site |= 0x1 << (15 - data->sensor_id); + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); + + return 0; + +err_tmu: + iounmap(data->regs); + +err_iomap: + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int qoriq_tmu_remove(struct platform_device *pdev) +{ + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); + + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); + + /* Disable monitoring */ + tmu_write(data, TMR_DISABLE, &data->regs->tmr); + + iounmap(data->regs); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int qoriq_tmu_suspend(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Disable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr &= ~TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} + +static int qoriq_tmu_resume(struct device *dev) +{ + u32 tmr; + struct qoriq_tmu_data *data = dev_get_drvdata(dev); + + /* Enable monitoring */ + tmr = tmu_read(data, &data->regs->tmr); + tmr |= TMR_ME; + tmu_write(data, tmr, &data->regs->tmr); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, + qoriq_tmu_suspend, qoriq_tmu_resume); + +static const struct of_device_id qoriq_tmu_match[] = { + { .compatible = "fsl,qoriq-tmu", }, + {}, +}; +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); + +static struct platform_driver qoriq_tmu = { + .driver = { + .name = "qoriq_thermal", + .pm = &qoriq_tmu_pm_ops, + .of_match_table = qoriq_tmu_match, + }, + .probe = qoriq_tmu_probe, + .remove = qoriq_tmu_remove, +}; +module_platform_driver(qoriq_tmu); + +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); +MODULE_LICENSE("GPL v2"); -- 2.1.0.27.g96db324 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support 2016-06-30 3:08 ` Jia Hongtao (?) (?) @ 2016-07-19 6:54 ` Hongtao Jia -1 siblings, 0 replies; 18+ messages in thread From: Hongtao Jia @ 2016-07-19 6:54 UTC (permalink / raw) To: edubezval, rui.zhang, Scott Wood Cc: linux-pm, devicetree, linux-kernel, linuxppc-dev, linux-arm-kernel Hi Eduardo, Any comments on this patch? Thanks. -Hongtao. > -----Original Message----- > From: Jia Hongtao [mailto:hongtao.jia@nxp.com] > Sent: Thursday, June 30, 2016 11:09 AM > To: edubezval@gmail.com; rui.zhang@intel.com; robh+dt@kernel.org; > galak@codeaurora.org; Scott Wood <scott.wood@nxp.com>; > shawnguo@kernel.org > Cc: linux-pm@vger.kernel.org; devicetree@vger.kernel.org; linux- > kernel@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; linux-arm- > kernel@lists.infradead.org; Hongtao Jia <hongtao.jia@nxp.com> > Subject: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > This driver add thermal management support by enabling TMU (Thermal > Monitoring Unit) on QorIQ platform. > > It's based on thermal of framework: > - Trip points defined in device tree. > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > --- > Changes of V2: > * Add HAS_IOMEM dependency to fix build error on UM > > drivers/thermal/Kconfig | 10 ++ > drivers/thermal/Makefile | 1 + > drivers/thermal/qoriq_thermal.c | 328 > ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 339 insertions(+) > create mode 100644 drivers/thermal/qoriq_thermal.c > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index > 2d702ca..56ef30d 100644 > --- a/drivers/thermal/Kconfig > +++ b/drivers/thermal/Kconfig > @@ -195,6 +195,16 @@ config IMX_THERMAL > cpufreq is used as the cooling device to throttle CPUs when the > passive trip is crossed. > > +config QORIQ_THERMAL > + tristate "QorIQ Thermal Monitoring Unit" > + depends on THERMAL_OF > + depends on HAS_IOMEM > + help > + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. > + It supports one critical trip point and one passive trip point. The > + cpufreq is used as the cooling device to throttle CPUs when the > + passive trip is crossed. > + > config SPEAR_THERMAL > tristate "SPEAr thermal sensor driver" > depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index > 10b07c1..6662232 100644 > --- a/drivers/thermal/Makefile > +++ b/drivers/thermal/Makefile > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c new > file mode 100644 index 0000000..644ba52 > --- /dev/null > +++ b/drivers/thermal/qoriq_thermal.c > @@ -0,0 +1,328 @@ > +/* > + * Copyright 2016 Freescale Semiconductor, Inc. > + * > + * This program is free software; you can redistribute it and/or modify > +it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but > +WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > +or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > +License for > + * more details. > + * > + */ > + > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > +#include <linux/thermal.h> > + > +#include "thermal_core.h" > + > +#define SITES_MAX 16 > + > +/* > + * QorIQ TMU Registers > + */ > +struct qoriq_tmu_site_regs { > + u32 tritsr; /* Immediate Temperature Site Register */ > + u32 tratsr; /* Average Temperature Site Register */ > + u8 res0[0x8]; > +}; > + > +struct qoriq_tmu_regs { > + u32 tmr; /* Mode Register */ > +#define TMR_DISABLE 0x0 > +#define TMR_ME 0x80000000 > +#define TMR_ALPF 0x0c000000 > + u32 tsr; /* Status Register */ > + u32 tmtmir; /* Temperature measurement interval Register */ > +#define TMTMIR_DEFAULT 0x0000000f > + u8 res0[0x14]; > + u32 tier; /* Interrupt Enable Register */ > +#define TIER_DISABLE 0x0 > + 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 qoriq_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 */ > +}; > + > +/* > + * Thermal zone data > + */ > +struct qoriq_tmu_data { > + struct thermal_zone_device *tz; > + struct qoriq_tmu_regs __iomem *regs; > + int sensor_id; > + bool little_endian; > +}; > + > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem > +*addr) { > + if (p->little_endian) > + iowrite32(val, addr); > + else > + iowrite32be(val, addr); > +} > + > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) { > + if (p->little_endian) > + return ioread32(addr); > + else > + return ioread32be(addr); > +} > + > +static int tmu_get_temp(void *p, int *temp) { > + u32 val; > + struct qoriq_tmu_data *data = p; > + > + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); > + *temp = (val & 0xff) * 1000; > + > + return 0; > +} > + > +static int qoriq_tmu_get_sensor_id(void) { > + int ret, id; > + struct of_phandle_args sensor_specs; > + struct device_node *np, *sensor_np; > + > + np = of_find_node_by_name(NULL, "thermal-zones"); > + if (!np) > + return -ENODEV; > + > + sensor_np = of_get_next_child(np, NULL); > + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", > + "#thermal-sensor-cells", > + 0, &sensor_specs); > + if (ret) { > + of_node_put(np); > + of_node_put(sensor_np); > + return ret; > + } > + > + if (sensor_specs.args_count >= 1) { > + id = sensor_specs.args[0]; > + WARN(sensor_specs.args_count > 1, > + "%s: too many cells in sensor specifier %d\n", > + sensor_specs.np->name, > sensor_specs.args_count); > + } else { > + id = 0; > + } > + > + of_node_put(np); > + of_node_put(sensor_np); > + > + return id; > +} > + > +static int qoriq_tmu_calibration(struct platform_device *pdev) { > + int i, val, len; > + u32 range[4]; > + const u32 *calibration; > + struct device_node *np = pdev->dev.of_node; > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { > + dev_err(&pdev->dev, "missing calibration range.\n"); > + return -ENODEV; > + } > + > + /* Init temperature range registers */ > + tmu_write(data, range[0], &data->regs->ttr0cr); > + tmu_write(data, range[1], &data->regs->ttr1cr); > + tmu_write(data, range[2], &data->regs->ttr2cr); > + tmu_write(data, range[3], &data->regs->ttr3cr); > + > + calibration = of_get_property(np, "fsl,tmu-calibration", &len); > + if (calibration == NULL || len % 8) { > + dev_err(&pdev->dev, "invalid calibration data.\n"); > + return -ENODEV; > + } > + > + for (i = 0; i < len; i += 8, calibration += 2) { > + val = of_read_number(calibration, 1); > + tmu_write(data, val, &data->regs->ttcfgr); > + val = of_read_number(calibration + 1, 1); > + tmu_write(data, val, &data->regs->tscfgr); > + } > + > + return 0; > +} > + > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) { > + /* Disable interrupt, using polling instead */ > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > + > + /* Set update_interval */ > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); } > + > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > + .get_temp = tmu_get_temp, > +}; > + > +static int qoriq_tmu_probe(struct platform_device *pdev) { > + int ret; > + const struct thermal_trip *trip; > + struct qoriq_tmu_data *data; > + struct device_node *np = pdev->dev.of_node; > + u32 site = 0; > + > + if (!np) { > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > + return -ENODEV; > + } > + > + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), > + GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, data); > + > + data->little_endian = of_property_read_bool(np, "little-endian"); > + > + data->sensor_id = qoriq_tmu_get_sensor_id(); > + if (data->sensor_id < 0) { > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + data->regs = of_iomap(np, 0); > + if (!data->regs) { > + dev_err(&pdev->dev, "Failed to get memory region\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + qoriq_tmu_init_device(data); /* TMU initialization */ > + > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ > + if (ret < 0) > + goto err_tmu; > + > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, > + data, &tmu_tz_ops); > + if (IS_ERR(data->tz)) { > + ret = PTR_ERR(data->tz); > + dev_err(&pdev->dev, > + "Failed to register thermal zone device %d\n", ret); > + goto err_tmu; > + } > + > + trip = of_thermal_get_trip_points(data->tz); > + > + /* Enable monitoring */ > + site |= 0x1 << (15 - data->sensor_id); > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > + > + return 0; > + > +err_tmu: > + iounmap(data->regs); > + > +err_iomap: > + platform_set_drvdata(pdev, NULL); > + > + return ret; > +} > + > +static int qoriq_tmu_remove(struct platform_device *pdev) { > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > + > + iounmap(data->regs); > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int qoriq_tmu_suspend(struct device *dev) { > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Disable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr &= ~TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > + > +static int qoriq_tmu_resume(struct device *dev) { > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Enable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr |= TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > +#endif > + > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > + qoriq_tmu_suspend, qoriq_tmu_resume); > + > +static const struct of_device_id qoriq_tmu_match[] = { > + { .compatible = "fsl,qoriq-tmu", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > + > +static struct platform_driver qoriq_tmu = { > + .driver = { > + .name = "qoriq_thermal", > + .pm = &qoriq_tmu_pm_ops, > + .of_match_table = qoriq_tmu_match, > + }, > + .probe = qoriq_tmu_probe, > + .remove = qoriq_tmu_remove, > +}; > +module_platform_driver(qoriq_tmu); > + > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > +MODULE_LICENSE("GPL v2"); > -- > 2.1.0.27.g96db324 ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-07-19 6:54 ` Hongtao Jia 0 siblings, 0 replies; 18+ messages in thread From: Hongtao Jia @ 2016-07-19 6:54 UTC (permalink / raw) To: linux-arm-kernel Hi Eduardo, Any comments on this patch? Thanks. -Hongtao. > -----Original Message----- > From: Jia Hongtao [mailto:hongtao.jia at nxp.com] > Sent: Thursday, June 30, 2016 11:09 AM > To: edubezval at gmail.com; rui.zhang at intel.com; robh+dt at kernel.org; > galak at codeaurora.org; Scott Wood <scott.wood@nxp.com>; > shawnguo at kernel.org > Cc: linux-pm at vger.kernel.org; devicetree at vger.kernel.org; linux- > kernel at vger.kernel.org; linuxppc-dev at lists.ozlabs.org; linux-arm- > kernel at lists.infradead.org; Hongtao Jia <hongtao.jia@nxp.com> > Subject: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > This driver add thermal management support by enabling TMU (Thermal > Monitoring Unit) on QorIQ platform. > > It's based on thermal of framework: > - Trip points defined in device tree. > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > --- > Changes of V2: > * Add HAS_IOMEM dependency to fix build error on UM > > drivers/thermal/Kconfig | 10 ++ > drivers/thermal/Makefile | 1 + > drivers/thermal/qoriq_thermal.c | 328 > ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 339 insertions(+) > create mode 100644 drivers/thermal/qoriq_thermal.c > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index > 2d702ca..56ef30d 100644 > --- a/drivers/thermal/Kconfig > +++ b/drivers/thermal/Kconfig > @@ -195,6 +195,16 @@ config IMX_THERMAL > cpufreq is used as the cooling device to throttle CPUs when the > passive trip is crossed. > > +config QORIQ_THERMAL > + tristate "QorIQ Thermal Monitoring Unit" > + depends on THERMAL_OF > + depends on HAS_IOMEM > + help > + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. > + It supports one critical trip point and one passive trip point. The > + cpufreq is used as the cooling device to throttle CPUs when the > + passive trip is crossed. > + > config SPEAR_THERMAL > tristate "SPEAr thermal sensor driver" > depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index > 10b07c1..6662232 100644 > --- a/drivers/thermal/Makefile > +++ b/drivers/thermal/Makefile > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c new > file mode 100644 index 0000000..644ba52 > --- /dev/null > +++ b/drivers/thermal/qoriq_thermal.c > @@ -0,0 +1,328 @@ > +/* > + * Copyright 2016 Freescale Semiconductor, Inc. > + * > + * This program is free software; you can redistribute it and/or modify > +it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but > +WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > +or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > +License for > + * more details. > + * > + */ > + > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > +#include <linux/thermal.h> > + > +#include "thermal_core.h" > + > +#define SITES_MAX 16 > + > +/* > + * QorIQ TMU Registers > + */ > +struct qoriq_tmu_site_regs { > + u32 tritsr; /* Immediate Temperature Site Register */ > + u32 tratsr; /* Average Temperature Site Register */ > + u8 res0[0x8]; > +}; > + > +struct qoriq_tmu_regs { > + u32 tmr; /* Mode Register */ > +#define TMR_DISABLE 0x0 > +#define TMR_ME 0x80000000 > +#define TMR_ALPF 0x0c000000 > + u32 tsr; /* Status Register */ > + u32 tmtmir; /* Temperature measurement interval Register */ > +#define TMTMIR_DEFAULT 0x0000000f > + u8 res0[0x14]; > + u32 tier; /* Interrupt Enable Register */ > +#define TIER_DISABLE 0x0 > + 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 qoriq_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 */ > +}; > + > +/* > + * Thermal zone data > + */ > +struct qoriq_tmu_data { > + struct thermal_zone_device *tz; > + struct qoriq_tmu_regs __iomem *regs; > + int sensor_id; > + bool little_endian; > +}; > + > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem > +*addr) { > + if (p->little_endian) > + iowrite32(val, addr); > + else > + iowrite32be(val, addr); > +} > + > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) { > + if (p->little_endian) > + return ioread32(addr); > + else > + return ioread32be(addr); > +} > + > +static int tmu_get_temp(void *p, int *temp) { > + u32 val; > + struct qoriq_tmu_data *data = p; > + > + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); > + *temp = (val & 0xff) * 1000; > + > + return 0; > +} > + > +static int qoriq_tmu_get_sensor_id(void) { > + int ret, id; > + struct of_phandle_args sensor_specs; > + struct device_node *np, *sensor_np; > + > + np = of_find_node_by_name(NULL, "thermal-zones"); > + if (!np) > + return -ENODEV; > + > + sensor_np = of_get_next_child(np, NULL); > + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", > + "#thermal-sensor-cells", > + 0, &sensor_specs); > + if (ret) { > + of_node_put(np); > + of_node_put(sensor_np); > + return ret; > + } > + > + if (sensor_specs.args_count >= 1) { > + id = sensor_specs.args[0]; > + WARN(sensor_specs.args_count > 1, > + "%s: too many cells in sensor specifier %d\n", > + sensor_specs.np->name, > sensor_specs.args_count); > + } else { > + id = 0; > + } > + > + of_node_put(np); > + of_node_put(sensor_np); > + > + return id; > +} > + > +static int qoriq_tmu_calibration(struct platform_device *pdev) { > + int i, val, len; > + u32 range[4]; > + const u32 *calibration; > + struct device_node *np = pdev->dev.of_node; > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { > + dev_err(&pdev->dev, "missing calibration range.\n"); > + return -ENODEV; > + } > + > + /* Init temperature range registers */ > + tmu_write(data, range[0], &data->regs->ttr0cr); > + tmu_write(data, range[1], &data->regs->ttr1cr); > + tmu_write(data, range[2], &data->regs->ttr2cr); > + tmu_write(data, range[3], &data->regs->ttr3cr); > + > + calibration = of_get_property(np, "fsl,tmu-calibration", &len); > + if (calibration == NULL || len % 8) { > + dev_err(&pdev->dev, "invalid calibration data.\n"); > + return -ENODEV; > + } > + > + for (i = 0; i < len; i += 8, calibration += 2) { > + val = of_read_number(calibration, 1); > + tmu_write(data, val, &data->regs->ttcfgr); > + val = of_read_number(calibration + 1, 1); > + tmu_write(data, val, &data->regs->tscfgr); > + } > + > + return 0; > +} > + > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) { > + /* Disable interrupt, using polling instead */ > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > + > + /* Set update_interval */ > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); } > + > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > + .get_temp = tmu_get_temp, > +}; > + > +static int qoriq_tmu_probe(struct platform_device *pdev) { > + int ret; > + const struct thermal_trip *trip; > + struct qoriq_tmu_data *data; > + struct device_node *np = pdev->dev.of_node; > + u32 site = 0; > + > + if (!np) { > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > + return -ENODEV; > + } > + > + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), > + GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, data); > + > + data->little_endian = of_property_read_bool(np, "little-endian"); > + > + data->sensor_id = qoriq_tmu_get_sensor_id(); > + if (data->sensor_id < 0) { > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + data->regs = of_iomap(np, 0); > + if (!data->regs) { > + dev_err(&pdev->dev, "Failed to get memory region\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + qoriq_tmu_init_device(data); /* TMU initialization */ > + > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ > + if (ret < 0) > + goto err_tmu; > + > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, > + data, &tmu_tz_ops); > + if (IS_ERR(data->tz)) { > + ret = PTR_ERR(data->tz); > + dev_err(&pdev->dev, > + "Failed to register thermal zone device %d\n", ret); > + goto err_tmu; > + } > + > + trip = of_thermal_get_trip_points(data->tz); > + > + /* Enable monitoring */ > + site |= 0x1 << (15 - data->sensor_id); > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > + > + return 0; > + > +err_tmu: > + iounmap(data->regs); > + > +err_iomap: > + platform_set_drvdata(pdev, NULL); > + > + return ret; > +} > + > +static int qoriq_tmu_remove(struct platform_device *pdev) { > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > + > + iounmap(data->regs); > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int qoriq_tmu_suspend(struct device *dev) { > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Disable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr &= ~TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > + > +static int qoriq_tmu_resume(struct device *dev) { > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Enable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr |= TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > +#endif > + > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > + qoriq_tmu_suspend, qoriq_tmu_resume); > + > +static const struct of_device_id qoriq_tmu_match[] = { > + { .compatible = "fsl,qoriq-tmu", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > + > +static struct platform_driver qoriq_tmu = { > + .driver = { > + .name = "qoriq_thermal", > + .pm = &qoriq_tmu_pm_ops, > + .of_match_table = qoriq_tmu_match, > + }, > + .probe = qoriq_tmu_probe, > + .remove = qoriq_tmu_remove, > +}; > +module_platform_driver(qoriq_tmu); > + > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > +MODULE_LICENSE("GPL v2"); > -- > 2.1.0.27.g96db324 ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-07-19 6:54 ` Hongtao Jia 0 siblings, 0 replies; 18+ messages in thread From: Hongtao Jia @ 2016-07-19 6:54 UTC (permalink / raw) To: edubezval, rui.zhang, Scott Wood Cc: linux-pm, devicetree, linux-kernel, linuxppc-dev, linux-arm-kernel Hi Eduardo, Any comments on this patch? Thanks. -Hongtao. > -----Original Message----- > From: Jia Hongtao [mailto:hongtao.jia@nxp.com] > Sent: Thursday, June 30, 2016 11:09 AM > To: edubezval@gmail.com; rui.zhang@intel.com; robh+dt@kernel.org; > galak@codeaurora.org; Scott Wood <scott.wood@nxp.com>; > shawnguo@kernel.org > Cc: linux-pm@vger.kernel.org; devicetree@vger.kernel.org; linux- > kernel@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; linux-arm- > kernel@lists.infradead.org; Hongtao Jia <hongtao.jia@nxp.com> > Subject: [PATCH V2 7/7] thermal: qoriq: Add thermal management support >=20 > This driver add thermal management support by enabling TMU (Thermal > Monitoring Unit) on QorIQ platform. >=20 > It's based on thermal of framework: > - Trip points defined in device tree. > - Cpufreq as cooling device registered in qoriq cpufreq driver. >=20 > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > --- > Changes of V2: > * Add HAS_IOMEM dependency to fix build error on UM >=20 > drivers/thermal/Kconfig | 10 ++ > drivers/thermal/Makefile | 1 + > drivers/thermal/qoriq_thermal.c | 328 > ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 339 insertions(+) > create mode 100644 drivers/thermal/qoriq_thermal.c >=20 > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index > 2d702ca..56ef30d 100644 > --- a/drivers/thermal/Kconfig > +++ b/drivers/thermal/Kconfig > @@ -195,6 +195,16 @@ config IMX_THERMAL > cpufreq is used as the cooling device to throttle CPUs when the > passive trip is crossed. >=20 > +config QORIQ_THERMAL > + tristate "QorIQ Thermal Monitoring Unit" > + depends on THERMAL_OF > + depends on HAS_IOMEM > + help > + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. > + It supports one critical trip point and one passive trip point. The > + cpufreq is used as the cooling device to throttle CPUs when the > + passive trip is crossed. > + > config SPEAR_THERMAL > tristate "SPEAr thermal sensor driver" > depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index > 10b07c1..6662232 100644 > --- a/drivers/thermal/Makefile > +++ b/drivers/thermal/Makefile > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) +=3D db8500_thermal.o > obj-$(CONFIG_ARMADA_THERMAL) +=3D armada_thermal.o > obj-$(CONFIG_TANGO_THERMAL) +=3D tango_thermal.o > obj-$(CONFIG_IMX_THERMAL) +=3D imx_thermal.o > +obj-$(CONFIG_QORIQ_THERMAL) +=3D qoriq_thermal.o > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) +=3D db8500_cpufreq_cooling.o > obj-$(CONFIG_INTEL_POWERCLAMP) +=3D intel_powerclamp.o > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) +=3D x86_pkg_temp_thermal.o > diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_ther= mal.c new > file mode 100644 index 0000000..644ba52 > --- /dev/null > +++ b/drivers/thermal/qoriq_thermal.c > @@ -0,0 +1,328 @@ > +/* > + * Copyright 2016 Freescale Semiconductor, Inc. > + * > + * This program is free software; you can redistribute it and/or modify > +it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but > +WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > +or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > +License for > + * more details. > + * > + */ > + > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > +#include <linux/thermal.h> > + > +#include "thermal_core.h" > + > +#define SITES_MAX 16 > + > +/* > + * QorIQ TMU Registers > + */ > +struct qoriq_tmu_site_regs { > + u32 tritsr; /* Immediate Temperature Site Register */ > + u32 tratsr; /* Average Temperature Site Register */ > + u8 res0[0x8]; > +}; > + > +struct qoriq_tmu_regs { > + u32 tmr; /* Mode Register */ > +#define TMR_DISABLE 0x0 > +#define TMR_ME 0x80000000 > +#define TMR_ALPF 0x0c000000 > + u32 tsr; /* Status Register */ > + u32 tmtmir; /* Temperature measurement interval Register */ > +#define TMTMIR_DEFAULT 0x0000000f > + u8 res0[0x14]; > + u32 tier; /* Interrupt Enable Register */ > +#define TIER_DISABLE 0x0 > + 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 qoriq_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 */ > +}; > + > +/* > + * Thermal zone data > + */ > +struct qoriq_tmu_data { > + struct thermal_zone_device *tz; > + struct qoriq_tmu_regs __iomem *regs; > + int sensor_id; > + bool little_endian; > +}; > + > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem > +*addr) { > + if (p->little_endian) > + iowrite32(val, addr); > + else > + iowrite32be(val, addr); > +} > + > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) { > + if (p->little_endian) > + return ioread32(addr); > + else > + return ioread32be(addr); > +} > + > +static int tmu_get_temp(void *p, int *temp) { > + u32 val; > + struct qoriq_tmu_data *data =3D p; > + > + val =3D tmu_read(data, &data->regs->site[data->sensor_id].tritsr); > + *temp =3D (val & 0xff) * 1000; > + > + return 0; > +} > + > +static int qoriq_tmu_get_sensor_id(void) { > + int ret, id; > + struct of_phandle_args sensor_specs; > + struct device_node *np, *sensor_np; > + > + np =3D of_find_node_by_name(NULL, "thermal-zones"); > + if (!np) > + return -ENODEV; > + > + sensor_np =3D of_get_next_child(np, NULL); > + ret =3D of_parse_phandle_with_args(sensor_np, "thermal-sensors", > + "#thermal-sensor-cells", > + 0, &sensor_specs); > + if (ret) { > + of_node_put(np); > + of_node_put(sensor_np); > + return ret; > + } > + > + if (sensor_specs.args_count >=3D 1) { > + id =3D sensor_specs.args[0]; > + WARN(sensor_specs.args_count > 1, > + "%s: too many cells in sensor specifier %d\n", > + sensor_specs.np->name, > sensor_specs.args_count); > + } else { > + id =3D 0; > + } > + > + of_node_put(np); > + of_node_put(sensor_np); > + > + return id; > +} > + > +static int qoriq_tmu_calibration(struct platform_device *pdev) { > + int i, val, len; > + u32 range[4]; > + const u32 *calibration; > + struct device_node *np =3D pdev->dev.of_node; > + struct qoriq_tmu_data *data =3D platform_get_drvdata(pdev); > + > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { > + dev_err(&pdev->dev, "missing calibration range.\n"); > + return -ENODEV; > + } > + > + /* Init temperature range registers */ > + tmu_write(data, range[0], &data->regs->ttr0cr); > + tmu_write(data, range[1], &data->regs->ttr1cr); > + tmu_write(data, range[2], &data->regs->ttr2cr); > + tmu_write(data, range[3], &data->regs->ttr3cr); > + > + calibration =3D of_get_property(np, "fsl,tmu-calibration", &len); > + if (calibration =3D=3D NULL || len % 8) { > + dev_err(&pdev->dev, "invalid calibration data.\n"); > + return -ENODEV; > + } > + > + for (i =3D 0; i < len; i +=3D 8, calibration +=3D 2) { > + val =3D of_read_number(calibration, 1); > + tmu_write(data, val, &data->regs->ttcfgr); > + val =3D of_read_number(calibration + 1, 1); > + tmu_write(data, val, &data->regs->tscfgr); > + } > + > + return 0; > +} > + > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) { > + /* Disable interrupt, using polling instead */ > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > + > + /* Set update_interval */ > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); } > + > +static struct thermal_zone_of_device_ops tmu_tz_ops =3D { > + .get_temp =3D tmu_get_temp, > +}; > + > +static int qoriq_tmu_probe(struct platform_device *pdev) { > + int ret; > + const struct thermal_trip *trip; > + struct qoriq_tmu_data *data; > + struct device_node *np =3D pdev->dev.of_node; > + u32 site =3D 0; > + > + if (!np) { > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > + return -ENODEV; > + } > + > + data =3D devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), > + GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, data); > + > + data->little_endian =3D of_property_read_bool(np, "little-endian"); > + > + data->sensor_id =3D qoriq_tmu_get_sensor_id(); > + if (data->sensor_id < 0) { > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > + ret =3D -ENODEV; > + goto err_iomap; > + } > + > + data->regs =3D of_iomap(np, 0); > + if (!data->regs) { > + dev_err(&pdev->dev, "Failed to get memory region\n"); > + ret =3D -ENODEV; > + goto err_iomap; > + } > + > + qoriq_tmu_init_device(data); /* TMU initialization */ > + > + ret =3D qoriq_tmu_calibration(pdev); /* TMU calibration */ > + if (ret < 0) > + goto err_tmu; > + > + data->tz =3D thermal_zone_of_sensor_register(&pdev->dev, data->sensor_i= d, > + data, &tmu_tz_ops); > + if (IS_ERR(data->tz)) { > + ret =3D PTR_ERR(data->tz); > + dev_err(&pdev->dev, > + "Failed to register thermal zone device %d\n", ret); > + goto err_tmu; > + } > + > + trip =3D of_thermal_get_trip_points(data->tz); > + > + /* Enable monitoring */ > + site |=3D 0x1 << (15 - data->sensor_id); > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > + > + return 0; > + > +err_tmu: > + iounmap(data->regs); > + > +err_iomap: > + platform_set_drvdata(pdev, NULL); > + > + return ret; > +} > + > +static int qoriq_tmu_remove(struct platform_device *pdev) { > + struct qoriq_tmu_data *data =3D platform_get_drvdata(pdev); > + > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > + > + iounmap(data->regs); > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int qoriq_tmu_suspend(struct device *dev) { > + u32 tmr; > + struct qoriq_tmu_data *data =3D dev_get_drvdata(dev); > + > + /* Disable monitoring */ > + tmr =3D tmu_read(data, &data->regs->tmr); > + tmr &=3D ~TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > + > +static int qoriq_tmu_resume(struct device *dev) { > + u32 tmr; > + struct qoriq_tmu_data *data =3D dev_get_drvdata(dev); > + > + /* Enable monitoring */ > + tmr =3D tmu_read(data, &data->regs->tmr); > + tmr |=3D TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > +#endif > + > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > + qoriq_tmu_suspend, qoriq_tmu_resume); > + > +static const struct of_device_id qoriq_tmu_match[] =3D { > + { .compatible =3D "fsl,qoriq-tmu", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > + > +static struct platform_driver qoriq_tmu =3D { > + .driver =3D { > + .name =3D "qoriq_thermal", > + .pm =3D &qoriq_tmu_pm_ops, > + .of_match_table =3D qoriq_tmu_match, > + }, > + .probe =3D qoriq_tmu_probe, > + .remove =3D qoriq_tmu_remove, > +}; > +module_platform_driver(qoriq_tmu); > + > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > +MODULE_LICENSE("GPL v2"); > -- > 2.1.0.27.g96db324 ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-07-19 6:54 ` Hongtao Jia 0 siblings, 0 replies; 18+ messages in thread From: Hongtao Jia @ 2016-07-19 6:54 UTC (permalink / raw) To: edubezval, rui.zhang, Scott Wood Cc: devicetree, linuxppc-dev, linux-kernel, linux-arm-kernel, linux-pm Hi Eduardo, Any comments on this patch? Thanks. -Hongtao. > -----Original Message----- > From: Jia Hongtao [mailto:hongtao.jia@nxp.com] > Sent: Thursday, June 30, 2016 11:09 AM > To: edubezval@gmail.com; rui.zhang@intel.com; robh+dt@kernel.org; > galak@codeaurora.org; Scott Wood <scott.wood@nxp.com>; > shawnguo@kernel.org > Cc: linux-pm@vger.kernel.org; devicetree@vger.kernel.org; linux- > kernel@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; linux-arm- > kernel@lists.infradead.org; Hongtao Jia <hongtao.jia@nxp.com> > Subject: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > This driver add thermal management support by enabling TMU (Thermal > Monitoring Unit) on QorIQ platform. > > It's based on thermal of framework: > - Trip points defined in device tree. > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > --- > Changes of V2: > * Add HAS_IOMEM dependency to fix build error on UM > > drivers/thermal/Kconfig | 10 ++ > drivers/thermal/Makefile | 1 + > drivers/thermal/qoriq_thermal.c | 328 > ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 339 insertions(+) > create mode 100644 drivers/thermal/qoriq_thermal.c > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index > 2d702ca..56ef30d 100644 > --- a/drivers/thermal/Kconfig > +++ b/drivers/thermal/Kconfig > @@ -195,6 +195,16 @@ config IMX_THERMAL > cpufreq is used as the cooling device to throttle CPUs when the > passive trip is crossed. > > +config QORIQ_THERMAL > + tristate "QorIQ Thermal Monitoring Unit" > + depends on THERMAL_OF > + depends on HAS_IOMEM > + help > + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. > + It supports one critical trip point and one passive trip point. The > + cpufreq is used as the cooling device to throttle CPUs when the > + passive trip is crossed. > + > config SPEAR_THERMAL > tristate "SPEAr thermal sensor driver" > depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index > 10b07c1..6662232 100644 > --- a/drivers/thermal/Makefile > +++ b/drivers/thermal/Makefile > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_thermal.o > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c new > file mode 100644 index 0000000..644ba52 > --- /dev/null > +++ b/drivers/thermal/qoriq_thermal.c > @@ -0,0 +1,328 @@ > +/* > + * Copyright 2016 Freescale Semiconductor, Inc. > + * > + * This program is free software; you can redistribute it and/or modify > +it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but > +WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > +or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > +License for > + * more details. > + * > + */ > + > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > +#include <linux/thermal.h> > + > +#include "thermal_core.h" > + > +#define SITES_MAX 16 > + > +/* > + * QorIQ TMU Registers > + */ > +struct qoriq_tmu_site_regs { > + u32 tritsr; /* Immediate Temperature Site Register */ > + u32 tratsr; /* Average Temperature Site Register */ > + u8 res0[0x8]; > +}; > + > +struct qoriq_tmu_regs { > + u32 tmr; /* Mode Register */ > +#define TMR_DISABLE 0x0 > +#define TMR_ME 0x80000000 > +#define TMR_ALPF 0x0c000000 > + u32 tsr; /* Status Register */ > + u32 tmtmir; /* Temperature measurement interval Register */ > +#define TMTMIR_DEFAULT 0x0000000f > + u8 res0[0x14]; > + u32 tier; /* Interrupt Enable Register */ > +#define TIER_DISABLE 0x0 > + 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 qoriq_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 */ > +}; > + > +/* > + * Thermal zone data > + */ > +struct qoriq_tmu_data { > + struct thermal_zone_device *tz; > + struct qoriq_tmu_regs __iomem *regs; > + int sensor_id; > + bool little_endian; > +}; > + > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem > +*addr) { > + if (p->little_endian) > + iowrite32(val, addr); > + else > + iowrite32be(val, addr); > +} > + > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) { > + if (p->little_endian) > + return ioread32(addr); > + else > + return ioread32be(addr); > +} > + > +static int tmu_get_temp(void *p, int *temp) { > + u32 val; > + struct qoriq_tmu_data *data = p; > + > + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); > + *temp = (val & 0xff) * 1000; > + > + return 0; > +} > + > +static int qoriq_tmu_get_sensor_id(void) { > + int ret, id; > + struct of_phandle_args sensor_specs; > + struct device_node *np, *sensor_np; > + > + np = of_find_node_by_name(NULL, "thermal-zones"); > + if (!np) > + return -ENODEV; > + > + sensor_np = of_get_next_child(np, NULL); > + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", > + "#thermal-sensor-cells", > + 0, &sensor_specs); > + if (ret) { > + of_node_put(np); > + of_node_put(sensor_np); > + return ret; > + } > + > + if (sensor_specs.args_count >= 1) { > + id = sensor_specs.args[0]; > + WARN(sensor_specs.args_count > 1, > + "%s: too many cells in sensor specifier %d\n", > + sensor_specs.np->name, > sensor_specs.args_count); > + } else { > + id = 0; > + } > + > + of_node_put(np); > + of_node_put(sensor_np); > + > + return id; > +} > + > +static int qoriq_tmu_calibration(struct platform_device *pdev) { > + int i, val, len; > + u32 range[4]; > + const u32 *calibration; > + struct device_node *np = pdev->dev.of_node; > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { > + dev_err(&pdev->dev, "missing calibration range.\n"); > + return -ENODEV; > + } > + > + /* Init temperature range registers */ > + tmu_write(data, range[0], &data->regs->ttr0cr); > + tmu_write(data, range[1], &data->regs->ttr1cr); > + tmu_write(data, range[2], &data->regs->ttr2cr); > + tmu_write(data, range[3], &data->regs->ttr3cr); > + > + calibration = of_get_property(np, "fsl,tmu-calibration", &len); > + if (calibration == NULL || len % 8) { > + dev_err(&pdev->dev, "invalid calibration data.\n"); > + return -ENODEV; > + } > + > + for (i = 0; i < len; i += 8, calibration += 2) { > + val = of_read_number(calibration, 1); > + tmu_write(data, val, &data->regs->ttcfgr); > + val = of_read_number(calibration + 1, 1); > + tmu_write(data, val, &data->regs->tscfgr); > + } > + > + return 0; > +} > + > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) { > + /* Disable interrupt, using polling instead */ > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > + > + /* Set update_interval */ > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); } > + > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > + .get_temp = tmu_get_temp, > +}; > + > +static int qoriq_tmu_probe(struct platform_device *pdev) { > + int ret; > + const struct thermal_trip *trip; > + struct qoriq_tmu_data *data; > + struct device_node *np = pdev->dev.of_node; > + u32 site = 0; > + > + if (!np) { > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > + return -ENODEV; > + } > + > + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), > + GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, data); > + > + data->little_endian = of_property_read_bool(np, "little-endian"); > + > + data->sensor_id = qoriq_tmu_get_sensor_id(); > + if (data->sensor_id < 0) { > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + data->regs = of_iomap(np, 0); > + if (!data->regs) { > + dev_err(&pdev->dev, "Failed to get memory region\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + qoriq_tmu_init_device(data); /* TMU initialization */ > + > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ > + if (ret < 0) > + goto err_tmu; > + > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, > + data, &tmu_tz_ops); > + if (IS_ERR(data->tz)) { > + ret = PTR_ERR(data->tz); > + dev_err(&pdev->dev, > + "Failed to register thermal zone device %d\n", ret); > + goto err_tmu; > + } > + > + trip = of_thermal_get_trip_points(data->tz); > + > + /* Enable monitoring */ > + site |= 0x1 << (15 - data->sensor_id); > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > + > + return 0; > + > +err_tmu: > + iounmap(data->regs); > + > +err_iomap: > + platform_set_drvdata(pdev, NULL); > + > + return ret; > +} > + > +static int qoriq_tmu_remove(struct platform_device *pdev) { > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > + > + iounmap(data->regs); > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int qoriq_tmu_suspend(struct device *dev) { > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Disable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr &= ~TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > + > +static int qoriq_tmu_resume(struct device *dev) { > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Enable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr |= TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > +#endif > + > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > + qoriq_tmu_suspend, qoriq_tmu_resume); > + > +static const struct of_device_id qoriq_tmu_match[] = { > + { .compatible = "fsl,qoriq-tmu", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > + > +static struct platform_driver qoriq_tmu = { > + .driver = { > + .name = "qoriq_thermal", > + .pm = &qoriq_tmu_pm_ops, > + .of_match_table = qoriq_tmu_match, > + }, > + .probe = qoriq_tmu_probe, > + .remove = qoriq_tmu_remove, > +}; > +module_platform_driver(qoriq_tmu); > + > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > +MODULE_LICENSE("GPL v2"); > -- > 2.1.0.27.g96db324 ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support 2016-07-19 6:54 ` Hongtao Jia (?) (?) @ 2016-08-05 6:26 ` Hongtao Jia -1 siblings, 0 replies; 18+ messages in thread From: Hongtao Jia @ 2016-08-05 6:26 UTC (permalink / raw) To: edubezval, rui.zhang, Scott Wood Cc: devicetree, linuxppc-dev, linux-kernel, linux-arm-kernel, linux-pm Hi Eduardo, If you have any comments please let me know. Thanks. -Hongtao. > -----Original Message----- > From: Linuxppc-dev [mailto:linuxppc-dev- > bounces+b38951=freescale.com@lists.ozlabs.org] On Behalf Of Hongtao Jia > Sent: Tuesday, July 19, 2016 2:54 PM > To: edubezval@gmail.com; rui.zhang@intel.com; Scott Wood > <scott.wood@nxp.com> > Cc: devicetree@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; linux- > kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux- > pm@vger.kernel.org > Subject: RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > Hi Eduardo, > > Any comments on this patch? > > Thanks. > -Hongtao. > > > -----Original Message----- > > From: Jia Hongtao [mailto:hongtao.jia@nxp.com] > > Sent: Thursday, June 30, 2016 11:09 AM > > To: edubezval@gmail.com; rui.zhang@intel.com; robh+dt@kernel.org; > > galak@codeaurora.org; Scott Wood <scott.wood@nxp.com>; > > shawnguo@kernel.org > > Cc: linux-pm@vger.kernel.org; devicetree@vger.kernel.org; linux- > > kernel@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; linux-arm- > > kernel@lists.infradead.org; Hongtao Jia <hongtao.jia@nxp.com> > > Subject: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > > > This driver add thermal management support by enabling TMU (Thermal > > Monitoring Unit) on QorIQ platform. > > > > It's based on thermal of framework: > > - Trip points defined in device tree. > > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > > --- > > Changes of V2: > > * Add HAS_IOMEM dependency to fix build error on UM > > > > drivers/thermal/Kconfig | 10 ++ > > drivers/thermal/Makefile | 1 + > > drivers/thermal/qoriq_thermal.c | 328 > > ++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 339 insertions(+) > > create mode 100644 drivers/thermal/qoriq_thermal.c > > > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index > > 2d702ca..56ef30d 100644 > > --- a/drivers/thermal/Kconfig > > +++ b/drivers/thermal/Kconfig > > @@ -195,6 +195,16 @@ config IMX_THERMAL > > cpufreq is used as the cooling device to throttle CPUs when the > > passive trip is crossed. > > > > +config QORIQ_THERMAL > > + tristate "QorIQ Thermal Monitoring Unit" > > + depends on THERMAL_OF > > + depends on HAS_IOMEM > > + help > > + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. > > + It supports one critical trip point and one passive trip point. The > > + cpufreq is used as the cooling device to throttle CPUs when the > > + passive trip is crossed. > > + > > config SPEAR_THERMAL > > tristate "SPEAr thermal sensor driver" > > depends on PLAT_SPEAR || COMPILE_TEST diff --git > > a/drivers/thermal/Makefile b/drivers/thermal/Makefile index > > 10b07c1..6662232 100644 > > --- a/drivers/thermal/Makefile > > +++ b/drivers/thermal/Makefile > > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += > db8500_thermal.o > > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o > > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > > diff --git a/drivers/thermal/qoriq_thermal.c > > b/drivers/thermal/qoriq_thermal.c new file mode 100644 index > > 0000000..644ba52 > > --- /dev/null > > +++ b/drivers/thermal/qoriq_thermal.c > > @@ -0,0 +1,328 @@ > > +/* > > + * Copyright 2016 Freescale Semiconductor, Inc. > > + * > > + * This program is free software; you can redistribute it and/or > > +modify it > > + * under the terms and conditions of the GNU General Public License, > > + * version 2, as published by the Free Software Foundation. > > + * > > + * This program is distributed in the hope it will be useful, but > > +WITHOUT > > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > > +or > > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > > +License for > > + * more details. > > + * > > + */ > > + > > +#include <linux/module.h> > > +#include <linux/platform_device.h> > > +#include <linux/err.h> > > +#include <linux/io.h> > > +#include <linux/of.h> > > +#include <linux/of_address.h> > > +#include <linux/thermal.h> > > + > > +#include "thermal_core.h" > > + > > +#define SITES_MAX 16 > > + > > +/* > > + * QorIQ TMU Registers > > + */ > > +struct qoriq_tmu_site_regs { > > + u32 tritsr; /* Immediate Temperature Site Register */ > > + u32 tratsr; /* Average Temperature Site Register */ > > + u8 res0[0x8]; > > +}; > > + > > +struct qoriq_tmu_regs { > > + u32 tmr; /* Mode Register */ > > +#define TMR_DISABLE 0x0 > > +#define TMR_ME 0x80000000 > > +#define TMR_ALPF 0x0c000000 > > + u32 tsr; /* Status Register */ > > + u32 tmtmir; /* Temperature measurement interval Register */ > > +#define TMTMIR_DEFAULT 0x0000000f > > + u8 res0[0x14]; > > + u32 tier; /* Interrupt Enable Register */ > > +#define TIER_DISABLE 0x0 > > + 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 qoriq_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 */ > > +}; > > + > > +/* > > + * Thermal zone data > > + */ > > +struct qoriq_tmu_data { > > + struct thermal_zone_device *tz; > > + struct qoriq_tmu_regs __iomem *regs; > > + int sensor_id; > > + bool little_endian; > > +}; > > + > > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem > > +*addr) { > > + if (p->little_endian) > > + iowrite32(val, addr); > > + else > > + iowrite32be(val, addr); > > +} > > + > > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) { > > + if (p->little_endian) > > + return ioread32(addr); > > + else > > + return ioread32be(addr); > > +} > > + > > +static int tmu_get_temp(void *p, int *temp) { > > + u32 val; > > + struct qoriq_tmu_data *data = p; > > + > > + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); > > + *temp = (val & 0xff) * 1000; > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_get_sensor_id(void) { > > + int ret, id; > > + struct of_phandle_args sensor_specs; > > + struct device_node *np, *sensor_np; > > + > > + np = of_find_node_by_name(NULL, "thermal-zones"); > > + if (!np) > > + return -ENODEV; > > + > > + sensor_np = of_get_next_child(np, NULL); > > + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", > > + "#thermal-sensor-cells", > > + 0, &sensor_specs); > > + if (ret) { > > + of_node_put(np); > > + of_node_put(sensor_np); > > + return ret; > > + } > > + > > + if (sensor_specs.args_count >= 1) { > > + id = sensor_specs.args[0]; > > + WARN(sensor_specs.args_count > 1, > > + "%s: too many cells in sensor specifier %d\n", > > + sensor_specs.np->name, > > sensor_specs.args_count); > > + } else { > > + id = 0; > > + } > > + > > + of_node_put(np); > > + of_node_put(sensor_np); > > + > > + return id; > > +} > > + > > +static int qoriq_tmu_calibration(struct platform_device *pdev) { > > + int i, val, len; > > + u32 range[4]; > > + const u32 *calibration; > > + struct device_node *np = pdev->dev.of_node; > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { > > + dev_err(&pdev->dev, "missing calibration range.\n"); > > + return -ENODEV; > > + } > > + > > + /* Init temperature range registers */ > > + tmu_write(data, range[0], &data->regs->ttr0cr); > > + tmu_write(data, range[1], &data->regs->ttr1cr); > > + tmu_write(data, range[2], &data->regs->ttr2cr); > > + tmu_write(data, range[3], &data->regs->ttr3cr); > > + > > + calibration = of_get_property(np, "fsl,tmu-calibration", &len); > > + if (calibration == NULL || len % 8) { > > + dev_err(&pdev->dev, "invalid calibration data.\n"); > > + return -ENODEV; > > + } > > + > > + for (i = 0; i < len; i += 8, calibration += 2) { > > + val = of_read_number(calibration, 1); > > + tmu_write(data, val, &data->regs->ttcfgr); > > + val = of_read_number(calibration + 1, 1); > > + tmu_write(data, val, &data->regs->tscfgr); > > + } > > + > > + return 0; > > +} > > + > > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) { > > + /* Disable interrupt, using polling instead */ > > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > > + > > + /* Set update_interval */ > > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); } > > + > > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > > + .get_temp = tmu_get_temp, > > +}; > > + > > +static int qoriq_tmu_probe(struct platform_device *pdev) { > > + int ret; > > + const struct thermal_trip *trip; > > + struct qoriq_tmu_data *data; > > + struct device_node *np = pdev->dev.of_node; > > + u32 site = 0; > > + > > + if (!np) { > > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > > + return -ENODEV; > > + } > > + > > + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), > > + GFP_KERNEL); > > + if (!data) > > + return -ENOMEM; > > + > > + platform_set_drvdata(pdev, data); > > + > > + data->little_endian = of_property_read_bool(np, "little-endian"); > > + > > + data->sensor_id = qoriq_tmu_get_sensor_id(); > > + if (data->sensor_id < 0) { > > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + data->regs = of_iomap(np, 0); > > + if (!data->regs) { > > + dev_err(&pdev->dev, "Failed to get memory region\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + qoriq_tmu_init_device(data); /* TMU initialization */ > > + > > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ > > + if (ret < 0) > > + goto err_tmu; > > + > > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, > > + data, &tmu_tz_ops); > > + if (IS_ERR(data->tz)) { > > + ret = PTR_ERR(data->tz); > > + dev_err(&pdev->dev, > > + "Failed to register thermal zone device %d\n", ret); > > + goto err_tmu; > > + } > > + > > + trip = of_thermal_get_trip_points(data->tz); > > + > > + /* Enable monitoring */ > > + site |= 0x1 << (15 - data->sensor_id); > > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > > + > > + return 0; > > + > > +err_tmu: > > + iounmap(data->regs); > > + > > +err_iomap: > > + platform_set_drvdata(pdev, NULL); > > + > > + return ret; > > +} > > + > > +static int qoriq_tmu_remove(struct platform_device *pdev) { > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > > + > > + iounmap(data->regs); > > + platform_set_drvdata(pdev, NULL); > > + > > + return 0; > > +} > > + > > +#ifdef CONFIG_PM_SLEEP > > +static int qoriq_tmu_suspend(struct device *dev) { > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Disable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr &= ~TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_resume(struct device *dev) { > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Enable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr |= TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > +#endif > > + > > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > > + qoriq_tmu_suspend, qoriq_tmu_resume); > > + > > +static const struct of_device_id qoriq_tmu_match[] = { > > + { .compatible = "fsl,qoriq-tmu", }, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > > + > > +static struct platform_driver qoriq_tmu = { > > + .driver = { > > + .name = "qoriq_thermal", > > + .pm = &qoriq_tmu_pm_ops, > > + .of_match_table = qoriq_tmu_match, > > + }, > > + .probe = qoriq_tmu_probe, > > + .remove = qoriq_tmu_remove, > > +}; > > +module_platform_driver(qoriq_tmu); > > + > > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > > +MODULE_LICENSE("GPL v2"); > > -- > > 2.1.0.27.g96db324 > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-08-05 6:26 ` Hongtao Jia 0 siblings, 0 replies; 18+ messages in thread From: Hongtao Jia @ 2016-08-05 6:26 UTC (permalink / raw) To: linux-arm-kernel Hi Eduardo, If you have any comments please let me know. Thanks. -Hongtao. > -----Original Message----- > From: Linuxppc-dev [mailto:linuxppc-dev- > bounces+b38951=freescale.com at lists.ozlabs.org] On Behalf Of Hongtao Jia > Sent: Tuesday, July 19, 2016 2:54 PM > To: edubezval at gmail.com; rui.zhang at intel.com; Scott Wood > <scott.wood@nxp.com> > Cc: devicetree at vger.kernel.org; linuxppc-dev at lists.ozlabs.org; linux- > kernel at vger.kernel.org; linux-arm-kernel at lists.infradead.org; linux- > pm at vger.kernel.org > Subject: RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > Hi Eduardo, > > Any comments on this patch? > > Thanks. > -Hongtao. > > > -----Original Message----- > > From: Jia Hongtao [mailto:hongtao.jia at nxp.com] > > Sent: Thursday, June 30, 2016 11:09 AM > > To: edubezval at gmail.com; rui.zhang at intel.com; robh+dt at kernel.org; > > galak at codeaurora.org; Scott Wood <scott.wood@nxp.com>; > > shawnguo at kernel.org > > Cc: linux-pm at vger.kernel.org; devicetree at vger.kernel.org; linux- > > kernel at vger.kernel.org; linuxppc-dev at lists.ozlabs.org; linux-arm- > > kernel at lists.infradead.org; Hongtao Jia <hongtao.jia@nxp.com> > > Subject: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > > > This driver add thermal management support by enabling TMU (Thermal > > Monitoring Unit) on QorIQ platform. > > > > It's based on thermal of framework: > > - Trip points defined in device tree. > > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > > --- > > Changes of V2: > > * Add HAS_IOMEM dependency to fix build error on UM > > > > drivers/thermal/Kconfig | 10 ++ > > drivers/thermal/Makefile | 1 + > > drivers/thermal/qoriq_thermal.c | 328 > > ++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 339 insertions(+) > > create mode 100644 drivers/thermal/qoriq_thermal.c > > > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index > > 2d702ca..56ef30d 100644 > > --- a/drivers/thermal/Kconfig > > +++ b/drivers/thermal/Kconfig > > @@ -195,6 +195,16 @@ config IMX_THERMAL > > cpufreq is used as the cooling device to throttle CPUs when the > > passive trip is crossed. > > > > +config QORIQ_THERMAL > > + tristate "QorIQ Thermal Monitoring Unit" > > + depends on THERMAL_OF > > + depends on HAS_IOMEM > > + help > > + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. > > + It supports one critical trip point and one passive trip point. The > > + cpufreq is used as the cooling device to throttle CPUs when the > > + passive trip is crossed. > > + > > config SPEAR_THERMAL > > tristate "SPEAr thermal sensor driver" > > depends on PLAT_SPEAR || COMPILE_TEST diff --git > > a/drivers/thermal/Makefile b/drivers/thermal/Makefile index > > 10b07c1..6662232 100644 > > --- a/drivers/thermal/Makefile > > +++ b/drivers/thermal/Makefile > > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += > db8500_thermal.o > > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o > > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > > diff --git a/drivers/thermal/qoriq_thermal.c > > b/drivers/thermal/qoriq_thermal.c new file mode 100644 index > > 0000000..644ba52 > > --- /dev/null > > +++ b/drivers/thermal/qoriq_thermal.c > > @@ -0,0 +1,328 @@ > > +/* > > + * Copyright 2016 Freescale Semiconductor, Inc. > > + * > > + * This program is free software; you can redistribute it and/or > > +modify it > > + * under the terms and conditions of the GNU General Public License, > > + * version 2, as published by the Free Software Foundation. > > + * > > + * This program is distributed in the hope it will be useful, but > > +WITHOUT > > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > > +or > > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > > +License for > > + * more details. > > + * > > + */ > > + > > +#include <linux/module.h> > > +#include <linux/platform_device.h> > > +#include <linux/err.h> > > +#include <linux/io.h> > > +#include <linux/of.h> > > +#include <linux/of_address.h> > > +#include <linux/thermal.h> > > + > > +#include "thermal_core.h" > > + > > +#define SITES_MAX 16 > > + > > +/* > > + * QorIQ TMU Registers > > + */ > > +struct qoriq_tmu_site_regs { > > + u32 tritsr; /* Immediate Temperature Site Register */ > > + u32 tratsr; /* Average Temperature Site Register */ > > + u8 res0[0x8]; > > +}; > > + > > +struct qoriq_tmu_regs { > > + u32 tmr; /* Mode Register */ > > +#define TMR_DISABLE 0x0 > > +#define TMR_ME 0x80000000 > > +#define TMR_ALPF 0x0c000000 > > + u32 tsr; /* Status Register */ > > + u32 tmtmir; /* Temperature measurement interval Register */ > > +#define TMTMIR_DEFAULT 0x0000000f > > + u8 res0[0x14]; > > + u32 tier; /* Interrupt Enable Register */ > > +#define TIER_DISABLE 0x0 > > + 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 qoriq_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 */ > > +}; > > + > > +/* > > + * Thermal zone data > > + */ > > +struct qoriq_tmu_data { > > + struct thermal_zone_device *tz; > > + struct qoriq_tmu_regs __iomem *regs; > > + int sensor_id; > > + bool little_endian; > > +}; > > + > > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem > > +*addr) { > > + if (p->little_endian) > > + iowrite32(val, addr); > > + else > > + iowrite32be(val, addr); > > +} > > + > > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) { > > + if (p->little_endian) > > + return ioread32(addr); > > + else > > + return ioread32be(addr); > > +} > > + > > +static int tmu_get_temp(void *p, int *temp) { > > + u32 val; > > + struct qoriq_tmu_data *data = p; > > + > > + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); > > + *temp = (val & 0xff) * 1000; > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_get_sensor_id(void) { > > + int ret, id; > > + struct of_phandle_args sensor_specs; > > + struct device_node *np, *sensor_np; > > + > > + np = of_find_node_by_name(NULL, "thermal-zones"); > > + if (!np) > > + return -ENODEV; > > + > > + sensor_np = of_get_next_child(np, NULL); > > + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", > > + "#thermal-sensor-cells", > > + 0, &sensor_specs); > > + if (ret) { > > + of_node_put(np); > > + of_node_put(sensor_np); > > + return ret; > > + } > > + > > + if (sensor_specs.args_count >= 1) { > > + id = sensor_specs.args[0]; > > + WARN(sensor_specs.args_count > 1, > > + "%s: too many cells in sensor specifier %d\n", > > + sensor_specs.np->name, > > sensor_specs.args_count); > > + } else { > > + id = 0; > > + } > > + > > + of_node_put(np); > > + of_node_put(sensor_np); > > + > > + return id; > > +} > > + > > +static int qoriq_tmu_calibration(struct platform_device *pdev) { > > + int i, val, len; > > + u32 range[4]; > > + const u32 *calibration; > > + struct device_node *np = pdev->dev.of_node; > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { > > + dev_err(&pdev->dev, "missing calibration range.\n"); > > + return -ENODEV; > > + } > > + > > + /* Init temperature range registers */ > > + tmu_write(data, range[0], &data->regs->ttr0cr); > > + tmu_write(data, range[1], &data->regs->ttr1cr); > > + tmu_write(data, range[2], &data->regs->ttr2cr); > > + tmu_write(data, range[3], &data->regs->ttr3cr); > > + > > + calibration = of_get_property(np, "fsl,tmu-calibration", &len); > > + if (calibration == NULL || len % 8) { > > + dev_err(&pdev->dev, "invalid calibration data.\n"); > > + return -ENODEV; > > + } > > + > > + for (i = 0; i < len; i += 8, calibration += 2) { > > + val = of_read_number(calibration, 1); > > + tmu_write(data, val, &data->regs->ttcfgr); > > + val = of_read_number(calibration + 1, 1); > > + tmu_write(data, val, &data->regs->tscfgr); > > + } > > + > > + return 0; > > +} > > + > > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) { > > + /* Disable interrupt, using polling instead */ > > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > > + > > + /* Set update_interval */ > > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); } > > + > > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > > + .get_temp = tmu_get_temp, > > +}; > > + > > +static int qoriq_tmu_probe(struct platform_device *pdev) { > > + int ret; > > + const struct thermal_trip *trip; > > + struct qoriq_tmu_data *data; > > + struct device_node *np = pdev->dev.of_node; > > + u32 site = 0; > > + > > + if (!np) { > > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > > + return -ENODEV; > > + } > > + > > + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), > > + GFP_KERNEL); > > + if (!data) > > + return -ENOMEM; > > + > > + platform_set_drvdata(pdev, data); > > + > > + data->little_endian = of_property_read_bool(np, "little-endian"); > > + > > + data->sensor_id = qoriq_tmu_get_sensor_id(); > > + if (data->sensor_id < 0) { > > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + data->regs = of_iomap(np, 0); > > + if (!data->regs) { > > + dev_err(&pdev->dev, "Failed to get memory region\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + qoriq_tmu_init_device(data); /* TMU initialization */ > > + > > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ > > + if (ret < 0) > > + goto err_tmu; > > + > > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, > > + data, &tmu_tz_ops); > > + if (IS_ERR(data->tz)) { > > + ret = PTR_ERR(data->tz); > > + dev_err(&pdev->dev, > > + "Failed to register thermal zone device %d\n", ret); > > + goto err_tmu; > > + } > > + > > + trip = of_thermal_get_trip_points(data->tz); > > + > > + /* Enable monitoring */ > > + site |= 0x1 << (15 - data->sensor_id); > > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > > + > > + return 0; > > + > > +err_tmu: > > + iounmap(data->regs); > > + > > +err_iomap: > > + platform_set_drvdata(pdev, NULL); > > + > > + return ret; > > +} > > + > > +static int qoriq_tmu_remove(struct platform_device *pdev) { > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > > + > > + iounmap(data->regs); > > + platform_set_drvdata(pdev, NULL); > > + > > + return 0; > > +} > > + > > +#ifdef CONFIG_PM_SLEEP > > +static int qoriq_tmu_suspend(struct device *dev) { > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Disable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr &= ~TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_resume(struct device *dev) { > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Enable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr |= TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > +#endif > > + > > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > > + qoriq_tmu_suspend, qoriq_tmu_resume); > > + > > +static const struct of_device_id qoriq_tmu_match[] = { > > + { .compatible = "fsl,qoriq-tmu", }, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > > + > > +static struct platform_driver qoriq_tmu = { > > + .driver = { > > + .name = "qoriq_thermal", > > + .pm = &qoriq_tmu_pm_ops, > > + .of_match_table = qoriq_tmu_match, > > + }, > > + .probe = qoriq_tmu_probe, > > + .remove = qoriq_tmu_remove, > > +}; > > +module_platform_driver(qoriq_tmu); > > + > > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > > +MODULE_LICENSE("GPL v2"); > > -- > > 2.1.0.27.g96db324 > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev at lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-08-05 6:26 ` Hongtao Jia 0 siblings, 0 replies; 18+ messages in thread From: Hongtao Jia @ 2016-08-05 6:26 UTC (permalink / raw) To: edubezval, rui.zhang, Scott Wood Cc: devicetree, linuxppc-dev, linux-kernel, linux-arm-kernel, linux-pm SGkgRWR1YXJkbywNCg0KSWYgeW91IGhhdmUgYW55IGNvbW1lbnRzIHBsZWFzZSBsZXQgbWUga25v dy4NCg0KVGhhbmtzLg0KLUhvbmd0YW8uIA0KDQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0t LS0NCj4gRnJvbTogTGludXhwcGMtZGV2IFttYWlsdG86bGludXhwcGMtZGV2LQ0KPiBib3VuY2Vz K2IzODk1MT1mcmVlc2NhbGUuY29tQGxpc3RzLm96bGFicy5vcmddIE9uIEJlaGFsZiBPZiBIb25n dGFvIEppYQ0KPiBTZW50OiBUdWVzZGF5LCBKdWx5IDE5LCAyMDE2IDI6NTQgUE0NCj4gVG86IGVk dWJlenZhbEBnbWFpbC5jb207IHJ1aS56aGFuZ0BpbnRlbC5jb207IFNjb3R0IFdvb2QNCj4gPHNj b3R0Lndvb2RAbnhwLmNvbT4NCj4gQ2M6IGRldmljZXRyZWVAdmdlci5rZXJuZWwub3JnOyBsaW51 eHBwYy1kZXZAbGlzdHMub3psYWJzLm9yZzsgbGludXgtDQo+IGtlcm5lbEB2Z2VyLmtlcm5lbC5v cmc7IGxpbnV4LWFybS1rZXJuZWxAbGlzdHMuaW5mcmFkZWFkLm9yZzsgbGludXgtDQo+IHBtQHZn ZXIua2VybmVsLm9yZw0KPiBTdWJqZWN0OiBSRTogW1BBVENIIFYyIDcvN10gdGhlcm1hbDogcW9y aXE6IEFkZCB0aGVybWFsIG1hbmFnZW1lbnQgc3VwcG9ydA0KPiANCj4gSGkgRWR1YXJkbywNCj4g DQo+IEFueSBjb21tZW50cyBvbiB0aGlzIHBhdGNoPw0KPiANCj4gVGhhbmtzLg0KPiAtSG9uZ3Rh by4NCj4gDQo+ID4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gPiBGcm9tOiBKaWEgSG9u Z3RhbyBbbWFpbHRvOmhvbmd0YW8uamlhQG54cC5jb21dDQo+ID4gU2VudDogVGh1cnNkYXksIEp1 bmUgMzAsIDIwMTYgMTE6MDkgQU0NCj4gPiBUbzogZWR1YmV6dmFsQGdtYWlsLmNvbTsgcnVpLnpo YW5nQGludGVsLmNvbTsgcm9iaCtkdEBrZXJuZWwub3JnOw0KPiA+IGdhbGFrQGNvZGVhdXJvcmEu b3JnOyBTY290dCBXb29kIDxzY290dC53b29kQG54cC5jb20+Ow0KPiA+IHNoYXduZ3VvQGtlcm5l bC5vcmcNCj4gPiBDYzogbGludXgtcG1Admdlci5rZXJuZWwub3JnOyBkZXZpY2V0cmVlQHZnZXIu a2VybmVsLm9yZzsgbGludXgtDQo+ID4ga2VybmVsQHZnZXIua2VybmVsLm9yZzsgbGludXhwcGMt ZGV2QGxpc3RzLm96bGFicy5vcmc7IGxpbnV4LWFybS0NCj4gPiBrZXJuZWxAbGlzdHMuaW5mcmFk ZWFkLm9yZzsgSG9uZ3RhbyBKaWEgPGhvbmd0YW8uamlhQG54cC5jb20+DQo+ID4gU3ViamVjdDog W1BBVENIIFYyIDcvN10gdGhlcm1hbDogcW9yaXE6IEFkZCB0aGVybWFsIG1hbmFnZW1lbnQgc3Vw cG9ydA0KPiA+DQo+ID4gVGhpcyBkcml2ZXIgYWRkIHRoZXJtYWwgbWFuYWdlbWVudCBzdXBwb3J0 IGJ5IGVuYWJsaW5nIFRNVSAoVGhlcm1hbA0KPiA+IE1vbml0b3JpbmcgVW5pdCkgb24gUW9ySVEg cGxhdGZvcm0uDQo+ID4NCj4gPiBJdCdzIGJhc2VkIG9uIHRoZXJtYWwgb2YgZnJhbWV3b3JrOg0K PiA+IC0gVHJpcCBwb2ludHMgZGVmaW5lZCBpbiBkZXZpY2UgdHJlZS4NCj4gPiAtIENwdWZyZXEg YXMgY29vbGluZyBkZXZpY2UgcmVnaXN0ZXJlZCBpbiBxb3JpcSBjcHVmcmVxIGRyaXZlci4NCj4g Pg0KPiA+IFNpZ25lZC1vZmYtYnk6IEppYSBIb25ndGFvIDxob25ndGFvLmppYUBueHAuY29tPg0K PiA+IC0tLQ0KPiA+IENoYW5nZXMgb2YgVjI6DQo+ID4gKiBBZGQgSEFTX0lPTUVNIGRlcGVuZGVu Y3kgdG8gZml4IGJ1aWxkIGVycm9yIG9uIFVNDQo+ID4NCj4gPiAgZHJpdmVycy90aGVybWFsL0tj b25maWcgICAgICAgICB8ICAxMCArKw0KPiA+ICBkcml2ZXJzL3RoZXJtYWwvTWFrZWZpbGUgICAg ICAgIHwgICAxICsNCj4gPiAgZHJpdmVycy90aGVybWFsL3FvcmlxX3RoZXJtYWwuYyB8IDMyOA0K PiA+ICsrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysNCj4gPiAgMyBmaWxl cyBjaGFuZ2VkLCAzMzkgaW5zZXJ0aW9ucygrKQ0KPiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJp dmVycy90aGVybWFsL3FvcmlxX3RoZXJtYWwuYw0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZl cnMvdGhlcm1hbC9LY29uZmlnIGIvZHJpdmVycy90aGVybWFsL0tjb25maWcgaW5kZXgNCj4gPiAy ZDcwMmNhLi41NmVmMzBkIDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvdGhlcm1hbC9LY29uZmln DQo+ID4gKysrIGIvZHJpdmVycy90aGVybWFsL0tjb25maWcNCj4gPiBAQCAtMTk1LDYgKzE5NSwx NiBAQCBjb25maWcgSU1YX1RIRVJNQUwNCj4gPiAgCSAgY3B1ZnJlcSBpcyB1c2VkIGFzIHRoZSBj b29saW5nIGRldmljZSB0byB0aHJvdHRsZSBDUFVzIHdoZW4gdGhlDQo+ID4gIAkgIHBhc3NpdmUg dHJpcCBpcyBjcm9zc2VkLg0KPiA+DQo+ID4gK2NvbmZpZyBRT1JJUV9USEVSTUFMDQo+ID4gKwl0 cmlzdGF0ZSAiUW9ySVEgVGhlcm1hbCBNb25pdG9yaW5nIFVuaXQiDQo+ID4gKwlkZXBlbmRzIG9u IFRIRVJNQUxfT0YNCj4gPiArCWRlcGVuZHMgb24gSEFTX0lPTUVNDQo+ID4gKwloZWxwDQo+ID4g KwkgIFN1cHBvcnQgZm9yIFRoZXJtYWwgTW9uaXRvcmluZyBVbml0IChUTVUpIGZvdW5kIG9uIFFv cklRIHBsYXRmb3Jtcy4NCj4gPiArCSAgSXQgc3VwcG9ydHMgb25lIGNyaXRpY2FsIHRyaXAgcG9p bnQgYW5kIG9uZSBwYXNzaXZlIHRyaXAgcG9pbnQuIFRoZQ0KPiA+ICsJICBjcHVmcmVxIGlzIHVz ZWQgYXMgdGhlIGNvb2xpbmcgZGV2aWNlIHRvIHRocm90dGxlIENQVXMgd2hlbiB0aGUNCj4gPiAr CSAgcGFzc2l2ZSB0cmlwIGlzIGNyb3NzZWQuDQo+ID4gKw0KPiA+ICBjb25maWcgU1BFQVJfVEhF Uk1BTA0KPiA+ICAJdHJpc3RhdGUgIlNQRUFyIHRoZXJtYWwgc2Vuc29yIGRyaXZlciINCj4gPiAg CWRlcGVuZHMgb24gUExBVF9TUEVBUiB8fCBDT01QSUxFX1RFU1QgZGlmZiAtLWdpdA0KPiA+IGEv ZHJpdmVycy90aGVybWFsL01ha2VmaWxlIGIvZHJpdmVycy90aGVybWFsL01ha2VmaWxlIGluZGV4 DQo+ID4gMTBiMDdjMS4uNjY2MjIzMiAxMDA2NDQNCj4gPiAtLS0gYS9kcml2ZXJzL3RoZXJtYWwv TWFrZWZpbGUNCj4gPiArKysgYi9kcml2ZXJzL3RoZXJtYWwvTWFrZWZpbGUNCj4gPiBAQCAtMzcs NiArMzcsNyBAQCBvYmotJChDT05GSUdfREI4NTAwX1RIRVJNQUwpCSs9DQo+IGRiODUwMF90aGVy bWFsLm8NCj4gPiAgb2JqLSQoQ09ORklHX0FSTUFEQV9USEVSTUFMKQkrPSBhcm1hZGFfdGhlcm1h bC5vDQo+ID4gIG9iai0kKENPTkZJR19UQU5HT19USEVSTUFMKQkrPSB0YW5nb190aGVybWFsLm8N Cj4gPiAgb2JqLSQoQ09ORklHX0lNWF9USEVSTUFMKQkrPSBpbXhfdGhlcm1hbC5vDQo+ID4gK29i ai0kKENPTkZJR19RT1JJUV9USEVSTUFMKQkrPSBxb3JpcV90aGVybWFsLm8NCj4gPiAgb2JqLSQo Q09ORklHX0RCODUwMF9DUFVGUkVRX0NPT0xJTkcpCSs9IGRiODUwMF9jcHVmcmVxX2Nvb2xpbmcu bw0KPiA+ICBvYmotJChDT05GSUdfSU5URUxfUE9XRVJDTEFNUCkJKz0gaW50ZWxfcG93ZXJjbGFt cC5vDQo+ID4gIG9iai0kKENPTkZJR19YODZfUEtHX1RFTVBfVEhFUk1BTCkJKz0geDg2X3BrZ190 ZW1wX3RoZXJtYWwubw0KPiA+IGRpZmYgLS1naXQgYS9kcml2ZXJzL3RoZXJtYWwvcW9yaXFfdGhl cm1hbC5jDQo+ID4gYi9kcml2ZXJzL3RoZXJtYWwvcW9yaXFfdGhlcm1hbC5jIG5ldyBmaWxlIG1v ZGUgMTAwNjQ0IGluZGV4DQo+ID4gMDAwMDAwMC4uNjQ0YmE1Mg0KPiA+IC0tLSAvZGV2L251bGwN Cj4gPiArKysgYi9kcml2ZXJzL3RoZXJtYWwvcW9yaXFfdGhlcm1hbC5jDQo+ID4gQEAgLTAsMCAr MSwzMjggQEANCj4gPiArLyoNCj4gPiArICogQ29weXJpZ2h0IDIwMTYgRnJlZXNjYWxlIFNlbWlj b25kdWN0b3IsIEluYy4NCj4gPiArICoNCj4gPiArICogVGhpcyBwcm9ncmFtIGlzIGZyZWUgc29m dHdhcmU7IHlvdSBjYW4gcmVkaXN0cmlidXRlIGl0IGFuZC9vcg0KPiA+ICttb2RpZnkgaXQNCj4g PiArICogdW5kZXIgdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQ dWJsaWMgTGljZW5zZSwNCj4gPiArICogdmVyc2lvbiAyLCBhcyBwdWJsaXNoZWQgYnkgdGhlIEZy ZWUgU29mdHdhcmUgRm91bmRhdGlvbi4NCj4gPiArICoNCj4gPiArICogVGhpcyBwcm9ncmFtIGlz IGRpc3RyaWJ1dGVkIGluIHRoZSBob3BlIGl0IHdpbGwgYmUgdXNlZnVsLCBidXQNCj4gPiArV0lU SE9VVA0KPiA+ICsgKiBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGllZCB3YXJy YW50eSBvZiBNRVJDSEFOVEFCSUxJVFkNCj4gPiArb3INCj4gPiArICogRklUTkVTUyBGT1IgQSBQ QVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYw0KPiA+ICtMaWNl bnNlIGZvcg0KPiA+ICsgKiBtb3JlIGRldGFpbHMuDQo+ID4gKyAqDQo+ID4gKyAqLw0KPiA+ICsN Cj4gPiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvcGxh dGZvcm1fZGV2aWNlLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9lcnIuaD4NCj4gPiArI2luY2x1 ZGUgPGxpbnV4L2lvLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9vZi5oPg0KPiA+ICsjaW5jbHVk ZSA8bGludXgvb2ZfYWRkcmVzcy5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvdGhlcm1hbC5oPg0K PiA+ICsNCj4gPiArI2luY2x1ZGUgInRoZXJtYWxfY29yZS5oIg0KPiA+ICsNCj4gPiArI2RlZmlu ZSBTSVRFU19NQVgJMTYNCj4gPiArDQo+ID4gKy8qDQo+ID4gKyAqIFFvcklRIFRNVSBSZWdpc3Rl cnMNCj4gPiArICovDQo+ID4gK3N0cnVjdCBxb3JpcV90bXVfc2l0ZV9yZWdzIHsNCj4gPiArCXUz MiB0cml0c3I7CQkvKiBJbW1lZGlhdGUgVGVtcGVyYXR1cmUgU2l0ZSBSZWdpc3RlciAqLw0KPiA+ ICsJdTMyIHRyYXRzcjsJCS8qIEF2ZXJhZ2UgVGVtcGVyYXR1cmUgU2l0ZSBSZWdpc3RlciAqLw0K PiA+ICsJdTggcmVzMFsweDhdOw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RydWN0IHFvcmlxX3Rt dV9yZWdzIHsNCj4gPiArCXUzMiB0bXI7CQkvKiBNb2RlIFJlZ2lzdGVyICovDQo+ID4gKyNkZWZp bmUgVE1SX0RJU0FCTEUJMHgwDQo+ID4gKyNkZWZpbmUgVE1SX01FCQkweDgwMDAwMDAwDQo+ID4g KyNkZWZpbmUgVE1SX0FMUEYJMHgwYzAwMDAwMA0KPiA+ICsJdTMyIHRzcjsJCS8qIFN0YXR1cyBS ZWdpc3RlciAqLw0KPiA+ICsJdTMyIHRtdG1pcjsJCS8qIFRlbXBlcmF0dXJlIG1lYXN1cmVtZW50 IGludGVydmFsIFJlZ2lzdGVyICovDQo+ID4gKyNkZWZpbmUgVE1UTUlSX0RFRkFVTFQJMHgwMDAw MDAwZg0KPiA+ICsJdTggcmVzMFsweDE0XTsNCj4gPiArCXUzMiB0aWVyOwkJLyogSW50ZXJydXB0 IEVuYWJsZSBSZWdpc3RlciAqLw0KPiA+ICsjZGVmaW5lIFRJRVJfRElTQUJMRQkweDANCj4gPiAr CXUzMiB0aWRyOwkJLyogSW50ZXJydXB0IERldGVjdCBSZWdpc3RlciAqLw0KPiA+ICsJdTMyIHRp c2NyOwkJLyogSW50ZXJydXB0IFNpdGUgQ2FwdHVyZSBSZWdpc3RlciAqLw0KPiA+ICsJdTMyIHRp Y3NjcjsJCS8qIEludGVycnVwdCBDcml0aWNhbCBTaXRlIENhcHR1cmUgUmVnaXN0ZXIgKi8NCj4g PiArCXU4IHJlczFbMHgxMF07DQo+ID4gKwl1MzIgdG1odGNyaDsJCS8qIEhpZ2ggVGVtcGVyYXR1 cmUgQ2FwdHVyZSBSZWdpc3RlciAqLw0KPiA+ICsJdTMyIHRtaHRjcmw7CQkvKiBMb3cgVGVtcGVy YXR1cmUgQ2FwdHVyZSBSZWdpc3RlciAqLw0KPiA+ICsJdTggcmVzMlsweDhdOw0KPiA+ICsJdTMy IHRtaHRpdHI7CQkvKiBIaWdoIFRlbXBlcmF0dXJlIEltbWVkaWF0ZSBUaHJlc2hvbGQgKi8NCj4g PiArCXUzMiB0bWh0YXRyOwkJLyogSGlnaCBUZW1wZXJhdHVyZSBBdmVyYWdlIFRocmVzaG9sZCAq Lw0KPiA+ICsJdTMyIHRtaHRhY3RyOwkvKiBIaWdoIFRlbXBlcmF0dXJlIEF2ZXJhZ2UgQ3JpdCBU aHJlc2hvbGQgKi8NCj4gPiArCXU4IHJlczNbMHgyNF07DQo+ID4gKwl1MzIgdHRjZmdyOwkJLyog VGVtcGVyYXR1cmUgQ29uZmlndXJhdGlvbiBSZWdpc3RlciAqLw0KPiA+ICsJdTMyIHRzY2ZncjsJ CS8qIFNlbnNvciBDb25maWd1cmF0aW9uIFJlZ2lzdGVyICovDQo+ID4gKwl1OCByZXM0WzB4Nzhd Ow0KPiA+ICsJc3RydWN0IHFvcmlxX3RtdV9zaXRlX3JlZ3Mgc2l0ZVtTSVRFU19NQVhdOw0KPiA+ ICsJdTggcmVzNVsweDlmOF07DQo+ID4gKwl1MzIgaXBicnIwOwkJLyogSVAgQmxvY2sgUmV2aXNp b24gUmVnaXN0ZXIgMCAqLw0KPiA+ICsJdTMyIGlwYnJyMTsJCS8qIElQIEJsb2NrIFJldmlzaW9u IFJlZ2lzdGVyIDEgKi8NCj4gPiArCXU4IHJlczZbMHgzMTBdOw0KPiA+ICsJdTMyIHR0cjBjcjsJ CS8qIFRlbXBlcmF0dXJlIFJhbmdlIDAgQ29udHJvbCBSZWdpc3RlciAqLw0KPiA+ICsJdTMyIHR0 cjFjcjsJCS8qIFRlbXBlcmF0dXJlIFJhbmdlIDEgQ29udHJvbCBSZWdpc3RlciAqLw0KPiA+ICsJ dTMyIHR0cjJjcjsJCS8qIFRlbXBlcmF0dXJlIFJhbmdlIDIgQ29udHJvbCBSZWdpc3RlciAqLw0K PiA+ICsJdTMyIHR0cjNjcjsJCS8qIFRlbXBlcmF0dXJlIFJhbmdlIDMgQ29udHJvbCBSZWdpc3Rl ciAqLw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArLyoNCj4gPiArICogVGhlcm1hbCB6b25lIGRhdGEN Cj4gPiArICovDQo+ID4gK3N0cnVjdCBxb3JpcV90bXVfZGF0YSB7DQo+ID4gKwlzdHJ1Y3QgdGhl cm1hbF96b25lX2RldmljZSAqdHo7DQo+ID4gKwlzdHJ1Y3QgcW9yaXFfdG11X3JlZ3MgX19pb21l bSAqcmVnczsNCj4gPiArCWludCBzZW5zb3JfaWQ7DQo+ID4gKwlib29sIGxpdHRsZV9lbmRpYW47 DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCB0bXVfd3JpdGUoc3RydWN0IHFvcmlx X3RtdV9kYXRhICpwLCB1MzIgdmFsLCB2b2lkIF9faW9tZW0NCj4gPiArKmFkZHIpIHsNCj4gPiAr CWlmIChwLT5saXR0bGVfZW5kaWFuKQ0KPiA+ICsJCWlvd3JpdGUzMih2YWwsIGFkZHIpOw0KPiA+ ICsJZWxzZQ0KPiA+ICsJCWlvd3JpdGUzMmJlKHZhbCwgYWRkcik7DQo+ID4gK30NCj4gPiArDQo+ ID4gK3N0YXRpYyB1MzIgdG11X3JlYWQoc3RydWN0IHFvcmlxX3RtdV9kYXRhICpwLCB2b2lkIF9f aW9tZW0gKmFkZHIpIHsNCj4gPiArCWlmIChwLT5saXR0bGVfZW5kaWFuKQ0KPiA+ICsJCXJldHVy biBpb3JlYWQzMihhZGRyKTsNCj4gPiArCWVsc2UNCj4gPiArCQlyZXR1cm4gaW9yZWFkMzJiZShh ZGRyKTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGludCB0bXVfZ2V0X3RlbXAodm9pZCAq cCwgaW50ICp0ZW1wKSB7DQo+ID4gKwl1MzIgdmFsOw0KPiA+ICsJc3RydWN0IHFvcmlxX3RtdV9k YXRhICpkYXRhID0gcDsNCj4gPiArDQo+ID4gKwl2YWwgPSB0bXVfcmVhZChkYXRhLCAmZGF0YS0+ cmVncy0+c2l0ZVtkYXRhLT5zZW5zb3JfaWRdLnRyaXRzcik7DQo+ID4gKwkqdGVtcCA9ICh2YWwg JiAweGZmKSAqIDEwMDA7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gK30NCj4gPiArDQo+ ID4gK3N0YXRpYyBpbnQgcW9yaXFfdG11X2dldF9zZW5zb3JfaWQodm9pZCkgew0KPiA+ICsJaW50 IHJldCwgaWQ7DQo+ID4gKwlzdHJ1Y3Qgb2ZfcGhhbmRsZV9hcmdzIHNlbnNvcl9zcGVjczsNCj4g PiArCXN0cnVjdCBkZXZpY2Vfbm9kZSAqbnAsICpzZW5zb3JfbnA7DQo+ID4gKw0KPiA+ICsJbnAg PSBvZl9maW5kX25vZGVfYnlfbmFtZShOVUxMLCAidGhlcm1hbC16b25lcyIpOw0KPiA+ICsJaWYg KCFucCkNCj4gPiArCQlyZXR1cm4gLUVOT0RFVjsNCj4gPiArDQo+ID4gKwlzZW5zb3JfbnAgPSBv Zl9nZXRfbmV4dF9jaGlsZChucCwgTlVMTCk7DQo+ID4gKwlyZXQgPSBvZl9wYXJzZV9waGFuZGxl X3dpdGhfYXJncyhzZW5zb3JfbnAsICJ0aGVybWFsLXNlbnNvcnMiLA0KPiA+ICsJCQkiI3RoZXJt YWwtc2Vuc29yLWNlbGxzIiwNCj4gPiArCQkJMCwgJnNlbnNvcl9zcGVjcyk7DQo+ID4gKwlpZiAo cmV0KSB7DQo+ID4gKwkJb2Zfbm9kZV9wdXQobnApOw0KPiA+ICsJCW9mX25vZGVfcHV0KHNlbnNv cl9ucCk7DQo+ID4gKwkJcmV0dXJuIHJldDsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlpZiAoc2Vu c29yX3NwZWNzLmFyZ3NfY291bnQgPj0gMSkgew0KPiA+ICsJCWlkID0gc2Vuc29yX3NwZWNzLmFy Z3NbMF07DQo+ID4gKwkJV0FSTihzZW5zb3Jfc3BlY3MuYXJnc19jb3VudCA+IDEsDQo+ID4gKwkJ CQkiJXM6IHRvbyBtYW55IGNlbGxzIGluIHNlbnNvciBzcGVjaWZpZXIgJWRcbiIsDQo+ID4gKwkJ CQlzZW5zb3Jfc3BlY3MubnAtPm5hbWUsDQo+ID4gc2Vuc29yX3NwZWNzLmFyZ3NfY291bnQpOw0K PiA+ICsJfSBlbHNlIHsNCj4gPiArCQlpZCA9IDA7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJb2Zf bm9kZV9wdXQobnApOw0KPiA+ICsJb2Zfbm9kZV9wdXQoc2Vuc29yX25wKTsNCj4gPiArDQo+ID4g KwlyZXR1cm4gaWQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgcW9yaXFfdG11X2Nh bGlicmF0aW9uKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpIHsNCj4gPiArCWludCBpLCB2 YWwsIGxlbjsNCj4gPiArCXUzMiByYW5nZVs0XTsNCj4gPiArCWNvbnN0IHUzMiAqY2FsaWJyYXRp b247DQo+ID4gKwlzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wID0gcGRldi0+ZGV2Lm9mX25vZGU7DQo+ ID4gKwlzdHJ1Y3QgcW9yaXFfdG11X2RhdGEgKmRhdGEgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0YShw ZGV2KTsNCj4gPiArDQo+ID4gKwlpZiAob2ZfcHJvcGVydHlfcmVhZF91MzJfYXJyYXkobnAsICJm c2wsdG11LXJhbmdlIiwgcmFuZ2UsIDQpKSB7DQo+ID4gKwkJZGV2X2VycigmcGRldi0+ZGV2LCAi bWlzc2luZyBjYWxpYnJhdGlvbiByYW5nZS5cbiIpOw0KPiA+ICsJCXJldHVybiAtRU5PREVWOw0K PiA+ICsJfQ0KPiA+ICsNCj4gPiArCS8qIEluaXQgdGVtcGVyYXR1cmUgcmFuZ2UgcmVnaXN0ZXJz ICovDQo+ID4gKwl0bXVfd3JpdGUoZGF0YSwgcmFuZ2VbMF0sICZkYXRhLT5yZWdzLT50dHIwY3Ip Ow0KPiA+ICsJdG11X3dyaXRlKGRhdGEsIHJhbmdlWzFdLCAmZGF0YS0+cmVncy0+dHRyMWNyKTsN Cj4gPiArCXRtdV93cml0ZShkYXRhLCByYW5nZVsyXSwgJmRhdGEtPnJlZ3MtPnR0cjJjcik7DQo+ ID4gKwl0bXVfd3JpdGUoZGF0YSwgcmFuZ2VbM10sICZkYXRhLT5yZWdzLT50dHIzY3IpOw0KPiA+ ICsNCj4gPiArCWNhbGlicmF0aW9uID0gb2ZfZ2V0X3Byb3BlcnR5KG5wLCAiZnNsLHRtdS1jYWxp YnJhdGlvbiIsICZsZW4pOw0KPiA+ICsJaWYgKGNhbGlicmF0aW9uID09IE5VTEwgfHwgbGVuICUg OCkgew0KPiA+ICsJCWRldl9lcnIoJnBkZXYtPmRldiwgImludmFsaWQgY2FsaWJyYXRpb24gZGF0 YS5cbiIpOw0KPiA+ICsJCXJldHVybiAtRU5PREVWOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCWZv ciAoaSA9IDA7IGkgPCBsZW47IGkgKz0gOCwgY2FsaWJyYXRpb24gKz0gMikgew0KPiA+ICsJCXZh bCA9IG9mX3JlYWRfbnVtYmVyKGNhbGlicmF0aW9uLCAxKTsNCj4gPiArCQl0bXVfd3JpdGUoZGF0 YSwgdmFsLCAmZGF0YS0+cmVncy0+dHRjZmdyKTsNCj4gPiArCQl2YWwgPSBvZl9yZWFkX251bWJl cihjYWxpYnJhdGlvbiArIDEsIDEpOw0KPiA+ICsJCXRtdV93cml0ZShkYXRhLCB2YWwsICZkYXRh LT5yZWdzLT50c2NmZ3IpOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCXJldHVybiAwOw0KPiA+ICt9 DQo+ID4gKw0KPiA+ICtzdGF0aWMgdm9pZCBxb3JpcV90bXVfaW5pdF9kZXZpY2Uoc3RydWN0IHFv cmlxX3RtdV9kYXRhICpkYXRhKSB7DQo+ID4gKwkvKiBEaXNhYmxlIGludGVycnVwdCwgdXNpbmcg cG9sbGluZyBpbnN0ZWFkICovDQo+ID4gKwl0bXVfd3JpdGUoZGF0YSwgVElFUl9ESVNBQkxFLCAm ZGF0YS0+cmVncy0+dGllcik7DQo+ID4gKw0KPiA+ICsJLyogU2V0IHVwZGF0ZV9pbnRlcnZhbCAq Lw0KPiA+ICsJdG11X3dyaXRlKGRhdGEsIFRNVE1JUl9ERUZBVUxULCAmZGF0YS0+cmVncy0+dG10 bWlyKTsNCj4gPiArDQo+ID4gKwkvKiBEaXNhYmxlIG1vbml0b3JpbmcgKi8NCj4gPiArCXRtdV93 cml0ZShkYXRhLCBUTVJfRElTQUJMRSwgJmRhdGEtPnJlZ3MtPnRtcik7IH0NCj4gPiArDQo+ID4g K3N0YXRpYyBzdHJ1Y3QgdGhlcm1hbF96b25lX29mX2RldmljZV9vcHMgdG11X3R6X29wcyA9IHsN Cj4gPiArCS5nZXRfdGVtcCA9IHRtdV9nZXRfdGVtcCwNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0 YXRpYyBpbnQgcW9yaXFfdG11X3Byb2JlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpIHsN Cj4gPiArCWludCByZXQ7DQo+ID4gKwljb25zdCBzdHJ1Y3QgdGhlcm1hbF90cmlwICp0cmlwOw0K PiA+ICsJc3RydWN0IHFvcmlxX3RtdV9kYXRhICpkYXRhOw0KPiA+ICsJc3RydWN0IGRldmljZV9u b2RlICpucCA9IHBkZXYtPmRldi5vZl9ub2RlOw0KPiA+ICsJdTMyIHNpdGUgPSAwOw0KPiA+ICsN Cj4gPiArCWlmICghbnApIHsNCj4gPiArCQlkZXZfZXJyKCZwZGV2LT5kZXYsICJEZXZpY2UgT0Yt Tm9kZSBpcyBOVUxMIik7DQo+ID4gKwkJcmV0dXJuIC1FTk9ERVY7DQo+ID4gKwl9DQo+ID4gKw0K PiA+ICsJZGF0YSA9IGRldm1fa3phbGxvYygmcGRldi0+ZGV2LCBzaXplb2Yoc3RydWN0IHFvcmlx X3RtdV9kYXRhKSwNCj4gPiArCQkJICAgIEdGUF9LRVJORUwpOw0KPiA+ICsJaWYgKCFkYXRhKQ0K PiA+ICsJCXJldHVybiAtRU5PTUVNOw0KPiA+ICsNCj4gPiArCXBsYXRmb3JtX3NldF9kcnZkYXRh KHBkZXYsIGRhdGEpOw0KPiA+ICsNCj4gPiArCWRhdGEtPmxpdHRsZV9lbmRpYW4gPSBvZl9wcm9w ZXJ0eV9yZWFkX2Jvb2wobnAsICJsaXR0bGUtZW5kaWFuIik7DQo+ID4gKw0KPiA+ICsJZGF0YS0+ c2Vuc29yX2lkID0gcW9yaXFfdG11X2dldF9zZW5zb3JfaWQoKTsNCj4gPiArCWlmIChkYXRhLT5z ZW5zb3JfaWQgPCAwKSB7DQo+ID4gKwkJZGV2X2VycigmcGRldi0+ZGV2LCAiRmFpbGVkIHRvIGdl dCBzZW5zb3IgaWRcbiIpOw0KPiA+ICsJCXJldCA9IC1FTk9ERVY7DQo+ID4gKwkJZ290byBlcnJf aW9tYXA7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJZGF0YS0+cmVncyA9IG9mX2lvbWFwKG5wLCAw KTsNCj4gPiArCWlmICghZGF0YS0+cmVncykgew0KPiA+ICsJCWRldl9lcnIoJnBkZXYtPmRldiwg IkZhaWxlZCB0byBnZXQgbWVtb3J5IHJlZ2lvblxuIik7DQo+ID4gKwkJcmV0ID0gLUVOT0RFVjsN Cj4gPiArCQlnb3RvIGVycl9pb21hcDsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlxb3JpcV90bXVf aW5pdF9kZXZpY2UoZGF0YSk7CS8qIFRNVSBpbml0aWFsaXphdGlvbiAqLw0KPiA+ICsNCj4gPiAr CXJldCA9IHFvcmlxX3RtdV9jYWxpYnJhdGlvbihwZGV2KTsJLyogVE1VIGNhbGlicmF0aW9uICov DQo+ID4gKwlpZiAocmV0IDwgMCkNCj4gPiArCQlnb3RvIGVycl90bXU7DQo+ID4gKw0KPiA+ICsJ ZGF0YS0+dHogPSB0aGVybWFsX3pvbmVfb2Zfc2Vuc29yX3JlZ2lzdGVyKCZwZGV2LT5kZXYsIGRh dGEtPnNlbnNvcl9pZCwNCj4gPiArCQkJCWRhdGEsICZ0bXVfdHpfb3BzKTsNCj4gPiArCWlmIChJ U19FUlIoZGF0YS0+dHopKSB7DQo+ID4gKwkJcmV0ID0gUFRSX0VSUihkYXRhLT50eik7DQo+ID4g KwkJZGV2X2VycigmcGRldi0+ZGV2LA0KPiA+ICsJCQkiRmFpbGVkIHRvIHJlZ2lzdGVyIHRoZXJt YWwgem9uZSBkZXZpY2UgJWRcbiIsIHJldCk7DQo+ID4gKwkJZ290byBlcnJfdG11Ow0KPiA+ICsJ fQ0KPiA+ICsNCj4gPiArCXRyaXAgPSBvZl90aGVybWFsX2dldF90cmlwX3BvaW50cyhkYXRhLT50 eik7DQo+ID4gKw0KPiA+ICsJLyogRW5hYmxlIG1vbml0b3JpbmcgKi8NCj4gPiArCXNpdGUgfD0g MHgxIDw8ICgxNSAtIGRhdGEtPnNlbnNvcl9pZCk7DQo+ID4gKwl0bXVfd3JpdGUoZGF0YSwgc2l0 ZSB8IFRNUl9NRSB8IFRNUl9BTFBGLCAmZGF0YS0+cmVncy0+dG1yKTsNCj4gPiArDQo+ID4gKwly ZXR1cm4gMDsNCj4gPiArDQo+ID4gK2Vycl90bXU6DQo+ID4gKwlpb3VubWFwKGRhdGEtPnJlZ3Mp Ow0KPiA+ICsNCj4gPiArZXJyX2lvbWFwOg0KPiA+ICsJcGxhdGZvcm1fc2V0X2RydmRhdGEocGRl diwgTlVMTCk7DQo+ID4gKw0KPiA+ICsJcmV0dXJuIHJldDsNCj4gPiArfQ0KPiA+ICsNCj4gPiAr c3RhdGljIGludCBxb3JpcV90bXVfcmVtb3ZlKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYp IHsNCj4gPiArCXN0cnVjdCBxb3JpcV90bXVfZGF0YSAqZGF0YSA9IHBsYXRmb3JtX2dldF9kcnZk YXRhKHBkZXYpOw0KPiA+ICsNCj4gPiArCXRoZXJtYWxfem9uZV9vZl9zZW5zb3JfdW5yZWdpc3Rl cigmcGRldi0+ZGV2LCBkYXRhLT50eik7DQo+ID4gKw0KPiA+ICsJLyogRGlzYWJsZSBtb25pdG9y aW5nICovDQo+ID4gKwl0bXVfd3JpdGUoZGF0YSwgVE1SX0RJU0FCTEUsICZkYXRhLT5yZWdzLT50 bXIpOw0KPiA+ICsNCj4gPiArCWlvdW5tYXAoZGF0YS0+cmVncyk7DQo+ID4gKwlwbGF0Zm9ybV9z ZXRfZHJ2ZGF0YShwZGV2LCBOVUxMKTsNCj4gPiArDQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0K PiA+ICsNCj4gPiArI2lmZGVmIENPTkZJR19QTV9TTEVFUA0KPiA+ICtzdGF0aWMgaW50IHFvcmlx X3RtdV9zdXNwZW5kKHN0cnVjdCBkZXZpY2UgKmRldikgew0KPiA+ICsJdTMyIHRtcjsNCj4gPiAr CXN0cnVjdCBxb3JpcV90bXVfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0YShkZXYpOw0KPiA+ ICsNCj4gPiArCS8qIERpc2FibGUgbW9uaXRvcmluZyAqLw0KPiA+ICsJdG1yID0gdG11X3JlYWQo ZGF0YSwgJmRhdGEtPnJlZ3MtPnRtcik7DQo+ID4gKwl0bXIgJj0gflRNUl9NRTsNCj4gPiArCXRt dV93cml0ZShkYXRhLCB0bXIsICZkYXRhLT5yZWdzLT50bXIpOw0KPiA+ICsNCj4gPiArCXJldHVy biAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IHFvcmlxX3RtdV9yZXN1bWUoc3Ry dWN0IGRldmljZSAqZGV2KSB7DQo+ID4gKwl1MzIgdG1yOw0KPiA+ICsJc3RydWN0IHFvcmlxX3Rt dV9kYXRhICpkYXRhID0gZGV2X2dldF9kcnZkYXRhKGRldik7DQo+ID4gKw0KPiA+ICsJLyogRW5h YmxlIG1vbml0b3JpbmcgKi8NCj4gPiArCXRtciA9IHRtdV9yZWFkKGRhdGEsICZkYXRhLT5yZWdz LT50bXIpOw0KPiA+ICsJdG1yIHw9IFRNUl9NRTsNCj4gPiArCXRtdV93cml0ZShkYXRhLCB0bXIs ICZkYXRhLT5yZWdzLT50bXIpOw0KPiA+ICsNCj4gPiArCXJldHVybiAwOw0KPiA+ICt9DQo+ID4g KyNlbmRpZg0KPiA+ICsNCj4gPiArc3RhdGljIFNJTVBMRV9ERVZfUE1fT1BTKHFvcmlxX3RtdV9w bV9vcHMsDQo+ID4gKwkJCSBxb3JpcV90bXVfc3VzcGVuZCwgcW9yaXFfdG11X3Jlc3VtZSk7DQo+ ID4gKw0KPiA+ICtzdGF0aWMgY29uc3Qgc3RydWN0IG9mX2RldmljZV9pZCBxb3JpcV90bXVfbWF0 Y2hbXSA9IHsNCj4gPiArCXsgLmNvbXBhdGlibGUgPSAiZnNsLHFvcmlxLXRtdSIsIH0sDQo+ID4g Kwl7fSwNCj4gPiArfTsNCj4gPiArTU9EVUxFX0RFVklDRV9UQUJMRShvZiwgcW9yaXFfdG11X21h dGNoKTsNCj4gPiArDQo+ID4gK3N0YXRpYyBzdHJ1Y3QgcGxhdGZvcm1fZHJpdmVyIHFvcmlxX3Rt dSA9IHsNCj4gPiArCS5kcml2ZXIJPSB7DQo+ID4gKwkJLm5hbWUJCT0gInFvcmlxX3RoZXJtYWwi LA0KPiA+ICsJCS5wbQkJPSAmcW9yaXFfdG11X3BtX29wcywNCj4gPiArCQkub2ZfbWF0Y2hfdGFi bGUJPSBxb3JpcV90bXVfbWF0Y2gsDQo+ID4gKwl9LA0KPiA+ICsJLnByb2JlCT0gcW9yaXFfdG11 X3Byb2JlLA0KPiA+ICsJLnJlbW92ZQk9IHFvcmlxX3RtdV9yZW1vdmUsDQo+ID4gK307DQo+ID4g K21vZHVsZV9wbGF0Zm9ybV9kcml2ZXIocW9yaXFfdG11KTsNCj4gPiArDQo+ID4gK01PRFVMRV9B VVRIT1IoIkppYSBIb25ndGFvIDxob25ndGFvLmppYUBueHAuY29tPiIpOw0KPiA+ICtNT0RVTEVf REVTQ1JJUFRJT04oIlFvcklRIFRoZXJtYWwgTW9uaXRvcmluZyBVbml0IGRyaXZlciIpOw0KPiA+ ICtNT0RVTEVfTElDRU5TRSgiR1BMIHYyIik7DQo+ID4gLS0NCj4gPiAyLjEuMC4yNy5nOTZkYjMy NA0KPiANCj4gX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18N Cj4gTGludXhwcGMtZGV2IG1haWxpbmcgbGlzdA0KPiBMaW51eHBwYy1kZXZAbGlzdHMub3psYWJz Lm9yZw0KPiBodHRwczovL2xpc3RzLm96bGFicy5vcmcvbGlzdGluZm8vbGludXhwcGMtZGV2DQo= ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-08-05 6:26 ` Hongtao Jia 0 siblings, 0 replies; 18+ messages in thread From: Hongtao Jia @ 2016-08-05 6:26 UTC (permalink / raw) To: edubezval, rui.zhang, Scott Wood Cc: devicetree, linuxppc-dev, linux-kernel, linux-arm-kernel, linux-pm Hi Eduardo, If you have any comments please let me know. Thanks. -Hongtao. > -----Original Message----- > From: Linuxppc-dev [mailto:linuxppc-dev- > bounces+b38951=freescale.com@lists.ozlabs.org] On Behalf Of Hongtao Jia > Sent: Tuesday, July 19, 2016 2:54 PM > To: edubezval@gmail.com; rui.zhang@intel.com; Scott Wood > <scott.wood@nxp.com> > Cc: devicetree@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; linux- > kernel@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux- > pm@vger.kernel.org > Subject: RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > Hi Eduardo, > > Any comments on this patch? > > Thanks. > -Hongtao. > > > -----Original Message----- > > From: Jia Hongtao [mailto:hongtao.jia@nxp.com] > > Sent: Thursday, June 30, 2016 11:09 AM > > To: edubezval@gmail.com; rui.zhang@intel.com; robh+dt@kernel.org; > > galak@codeaurora.org; Scott Wood <scott.wood@nxp.com>; > > shawnguo@kernel.org > > Cc: linux-pm@vger.kernel.org; devicetree@vger.kernel.org; linux- > > kernel@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; linux-arm- > > kernel@lists.infradead.org; Hongtao Jia <hongtao.jia@nxp.com> > > Subject: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > > > This driver add thermal management support by enabling TMU (Thermal > > Monitoring Unit) on QorIQ platform. > > > > It's based on thermal of framework: > > - Trip points defined in device tree. > > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > > --- > > Changes of V2: > > * Add HAS_IOMEM dependency to fix build error on UM > > > > drivers/thermal/Kconfig | 10 ++ > > drivers/thermal/Makefile | 1 + > > drivers/thermal/qoriq_thermal.c | 328 > > ++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 339 insertions(+) > > create mode 100644 drivers/thermal/qoriq_thermal.c > > > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index > > 2d702ca..56ef30d 100644 > > --- a/drivers/thermal/Kconfig > > +++ b/drivers/thermal/Kconfig > > @@ -195,6 +195,16 @@ config IMX_THERMAL > > cpufreq is used as the cooling device to throttle CPUs when the > > passive trip is crossed. > > > > +config QORIQ_THERMAL > > + tristate "QorIQ Thermal Monitoring Unit" > > + depends on THERMAL_OF > > + depends on HAS_IOMEM > > + help > > + Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. > > + It supports one critical trip point and one passive trip point. The > > + cpufreq is used as the cooling device to throttle CPUs when the > > + passive trip is crossed. > > + > > config SPEAR_THERMAL > > tristate "SPEAr thermal sensor driver" > > depends on PLAT_SPEAR || COMPILE_TEST diff --git > > a/drivers/thermal/Makefile b/drivers/thermal/Makefile index > > 10b07c1..6662232 100644 > > --- a/drivers/thermal/Makefile > > +++ b/drivers/thermal/Makefile > > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += > db8500_thermal.o > > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o > > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > > diff --git a/drivers/thermal/qoriq_thermal.c > > b/drivers/thermal/qoriq_thermal.c new file mode 100644 index > > 0000000..644ba52 > > --- /dev/null > > +++ b/drivers/thermal/qoriq_thermal.c > > @@ -0,0 +1,328 @@ > > +/* > > + * Copyright 2016 Freescale Semiconductor, Inc. > > + * > > + * This program is free software; you can redistribute it and/or > > +modify it > > + * under the terms and conditions of the GNU General Public License, > > + * version 2, as published by the Free Software Foundation. > > + * > > + * This program is distributed in the hope it will be useful, but > > +WITHOUT > > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > > +or > > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > > +License for > > + * more details. > > + * > > + */ > > + > > +#include <linux/module.h> > > +#include <linux/platform_device.h> > > +#include <linux/err.h> > > +#include <linux/io.h> > > +#include <linux/of.h> > > +#include <linux/of_address.h> > > +#include <linux/thermal.h> > > + > > +#include "thermal_core.h" > > + > > +#define SITES_MAX 16 > > + > > +/* > > + * QorIQ TMU Registers > > + */ > > +struct qoriq_tmu_site_regs { > > + u32 tritsr; /* Immediate Temperature Site Register */ > > + u32 tratsr; /* Average Temperature Site Register */ > > + u8 res0[0x8]; > > +}; > > + > > +struct qoriq_tmu_regs { > > + u32 tmr; /* Mode Register */ > > +#define TMR_DISABLE 0x0 > > +#define TMR_ME 0x80000000 > > +#define TMR_ALPF 0x0c000000 > > + u32 tsr; /* Status Register */ > > + u32 tmtmir; /* Temperature measurement interval Register */ > > +#define TMTMIR_DEFAULT 0x0000000f > > + u8 res0[0x14]; > > + u32 tier; /* Interrupt Enable Register */ > > +#define TIER_DISABLE 0x0 > > + 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 qoriq_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 */ > > +}; > > + > > +/* > > + * Thermal zone data > > + */ > > +struct qoriq_tmu_data { > > + struct thermal_zone_device *tz; > > + struct qoriq_tmu_regs __iomem *regs; > > + int sensor_id; > > + bool little_endian; > > +}; > > + > > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void __iomem > > +*addr) { > > + if (p->little_endian) > > + iowrite32(val, addr); > > + else > > + iowrite32be(val, addr); > > +} > > + > > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) { > > + if (p->little_endian) > > + return ioread32(addr); > > + else > > + return ioread32be(addr); > > +} > > + > > +static int tmu_get_temp(void *p, int *temp) { > > + u32 val; > > + struct qoriq_tmu_data *data = p; > > + > > + val = tmu_read(data, &data->regs->site[data->sensor_id].tritsr); > > + *temp = (val & 0xff) * 1000; > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_get_sensor_id(void) { > > + int ret, id; > > + struct of_phandle_args sensor_specs; > > + struct device_node *np, *sensor_np; > > + > > + np = of_find_node_by_name(NULL, "thermal-zones"); > > + if (!np) > > + return -ENODEV; > > + > > + sensor_np = of_get_next_child(np, NULL); > > + ret = of_parse_phandle_with_args(sensor_np, "thermal-sensors", > > + "#thermal-sensor-cells", > > + 0, &sensor_specs); > > + if (ret) { > > + of_node_put(np); > > + of_node_put(sensor_np); > > + return ret; > > + } > > + > > + if (sensor_specs.args_count >= 1) { > > + id = sensor_specs.args[0]; > > + WARN(sensor_specs.args_count > 1, > > + "%s: too many cells in sensor specifier %d\n", > > + sensor_specs.np->name, > > sensor_specs.args_count); > > + } else { > > + id = 0; > > + } > > + > > + of_node_put(np); > > + of_node_put(sensor_np); > > + > > + return id; > > +} > > + > > +static int qoriq_tmu_calibration(struct platform_device *pdev) { > > + int i, val, len; > > + u32 range[4]; > > + const u32 *calibration; > > + struct device_node *np = pdev->dev.of_node; > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, 4)) { > > + dev_err(&pdev->dev, "missing calibration range.\n"); > > + return -ENODEV; > > + } > > + > > + /* Init temperature range registers */ > > + tmu_write(data, range[0], &data->regs->ttr0cr); > > + tmu_write(data, range[1], &data->regs->ttr1cr); > > + tmu_write(data, range[2], &data->regs->ttr2cr); > > + tmu_write(data, range[3], &data->regs->ttr3cr); > > + > > + calibration = of_get_property(np, "fsl,tmu-calibration", &len); > > + if (calibration == NULL || len % 8) { > > + dev_err(&pdev->dev, "invalid calibration data.\n"); > > + return -ENODEV; > > + } > > + > > + for (i = 0; i < len; i += 8, calibration += 2) { > > + val = of_read_number(calibration, 1); > > + tmu_write(data, val, &data->regs->ttcfgr); > > + val = of_read_number(calibration + 1, 1); > > + tmu_write(data, val, &data->regs->tscfgr); > > + } > > + > > + return 0; > > +} > > + > > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) { > > + /* Disable interrupt, using polling instead */ > > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > > + > > + /* Set update_interval */ > > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); } > > + > > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > > + .get_temp = tmu_get_temp, > > +}; > > + > > +static int qoriq_tmu_probe(struct platform_device *pdev) { > > + int ret; > > + const struct thermal_trip *trip; > > + struct qoriq_tmu_data *data; > > + struct device_node *np = pdev->dev.of_node; > > + u32 site = 0; > > + > > + if (!np) { > > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > > + return -ENODEV; > > + } > > + > > + data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), > > + GFP_KERNEL); > > + if (!data) > > + return -ENOMEM; > > + > > + platform_set_drvdata(pdev, data); > > + > > + data->little_endian = of_property_read_bool(np, "little-endian"); > > + > > + data->sensor_id = qoriq_tmu_get_sensor_id(); > > + if (data->sensor_id < 0) { > > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + data->regs = of_iomap(np, 0); > > + if (!data->regs) { > > + dev_err(&pdev->dev, "Failed to get memory region\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + qoriq_tmu_init_device(data); /* TMU initialization */ > > + > > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration */ > > + if (ret < 0) > > + goto err_tmu; > > + > > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data->sensor_id, > > + data, &tmu_tz_ops); > > + if (IS_ERR(data->tz)) { > > + ret = PTR_ERR(data->tz); > > + dev_err(&pdev->dev, > > + "Failed to register thermal zone device %d\n", ret); > > + goto err_tmu; > > + } > > + > > + trip = of_thermal_get_trip_points(data->tz); > > + > > + /* Enable monitoring */ > > + site |= 0x1 << (15 - data->sensor_id); > > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > > + > > + return 0; > > + > > +err_tmu: > > + iounmap(data->regs); > > + > > +err_iomap: > > + platform_set_drvdata(pdev, NULL); > > + > > + return ret; > > +} > > + > > +static int qoriq_tmu_remove(struct platform_device *pdev) { > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > > + > > + iounmap(data->regs); > > + platform_set_drvdata(pdev, NULL); > > + > > + return 0; > > +} > > + > > +#ifdef CONFIG_PM_SLEEP > > +static int qoriq_tmu_suspend(struct device *dev) { > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Disable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr &= ~TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_resume(struct device *dev) { > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Enable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr |= TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > +#endif > > + > > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > > + qoriq_tmu_suspend, qoriq_tmu_resume); > > + > > +static const struct of_device_id qoriq_tmu_match[] = { > > + { .compatible = "fsl,qoriq-tmu", }, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > > + > > +static struct platform_driver qoriq_tmu = { > > + .driver = { > > + .name = "qoriq_thermal", > > + .pm = &qoriq_tmu_pm_ops, > > + .of_match_table = qoriq_tmu_match, > > + }, > > + .probe = qoriq_tmu_probe, > > + .remove = qoriq_tmu_remove, > > +}; > > +module_platform_driver(qoriq_tmu); > > + > > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > > +MODULE_LICENSE("GPL v2"); > > -- > > 2.1.0.27.g96db324 > > _______________________________________________ > Linuxppc-dev mailing list > Linuxppc-dev@lists.ozlabs.org > https://lists.ozlabs.org/listinfo/linuxppc-dev ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 7/7] thermal: qoriq: Add thermal management support 2016-06-30 3:08 ` Jia Hongtao (?) @ 2016-08-19 12:39 ` Zhang Rui -1 siblings, 0 replies; 18+ messages in thread From: Zhang Rui @ 2016-08-19 12:39 UTC (permalink / raw) To: Jia Hongtao, edubezval, robh+dt, galak, scott.wood, shawnguo Cc: linux-pm, devicetree, linux-kernel, linuxppc-dev, linux-arm-kernel On 四, 2016-06-30 at 11:08 +0800, Jia Hongtao wrote: > This driver add thermal management support by enabling TMU (Thermal > Monitoring Unit) on QorIQ platform. > > It's based on thermal of framework: > - Trip points defined in device tree. > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> The patch looks good to me. I only need to take this patch, right? thanks, rui > --- > Changes of V2: > * Add HAS_IOMEM dependency to fix build error on UM > > drivers/thermal/Kconfig | 10 ++ > drivers/thermal/Makefile | 1 + > drivers/thermal/qoriq_thermal.c | 328 > ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 339 insertions(+) > create mode 100644 drivers/thermal/qoriq_thermal.c > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig > index 2d702ca..56ef30d 100644 > --- a/drivers/thermal/Kconfig > +++ b/drivers/thermal/Kconfig > @@ -195,6 +195,16 @@ config IMX_THERMAL > cpufreq is used as the cooling device to throttle CPUs > when the > passive trip is crossed. > > +config QORIQ_THERMAL > + tristate "QorIQ Thermal Monitoring Unit" > + depends on THERMAL_OF > + depends on HAS_IOMEM > + help > + Support for Thermal Monitoring Unit (TMU) found on QorIQ > platforms. > + It supports one critical trip point and one passive trip > point. The > + cpufreq is used as the cooling device to throttle CPUs > when the > + passive trip is crossed. > + > config SPEAR_THERMAL > tristate "SPEAr thermal sensor driver" > depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile > index 10b07c1..6662232 100644 > --- a/drivers/thermal/Makefile > +++ b/drivers/thermal/Makefile > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += > db8500_thermal.o > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += > db8500_cpufreq_cooling.o > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > diff --git a/drivers/thermal/qoriq_thermal.c > b/drivers/thermal/qoriq_thermal.c > new file mode 100644 > index 0000000..644ba52 > --- /dev/null > +++ b/drivers/thermal/qoriq_thermal.c > @@ -0,0 +1,328 @@ > +/* > + * Copyright 2016 Freescale Semiconductor, Inc. > + * > + * This program is free software; you can redistribute it and/or > modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but > WITHOUT > + * ANY WARRANTY; without even the implied warranty of > MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > License for > + * more details. > + * > + */ > + > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > +#include <linux/thermal.h> > + > +#include "thermal_core.h" > + > +#define SITES_MAX 16 > + > +/* > + * QorIQ TMU Registers > + */ > +struct qoriq_tmu_site_regs { > + u32 tritsr; /* Immediate Temperature Site > Register */ > + u32 tratsr; /* Average Temperature Site > Register */ > + u8 res0[0x8]; > +}; > + > +struct qoriq_tmu_regs { > + u32 tmr; /* Mode Register */ > +#define TMR_DISABLE 0x0 > +#define TMR_ME 0x80000000 > +#define TMR_ALPF 0x0c000000 > + u32 tsr; /* Status Register */ > + u32 tmtmir; /* Temperature measurement > interval Register */ > +#define TMTMIR_DEFAULT 0x0000000f > + u8 res0[0x14]; > + u32 tier; /* Interrupt Enable Register */ > +#define TIER_DISABLE 0x0 > + 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 qoriq_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 */ > +}; > + > +/* > + * Thermal zone data > + */ > +struct qoriq_tmu_data { > + struct thermal_zone_device *tz; > + struct qoriq_tmu_regs __iomem *regs; > + int sensor_id; > + bool little_endian; > +}; > + > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void > __iomem *addr) > +{ > + if (p->little_endian) > + iowrite32(val, addr); > + else > + iowrite32be(val, addr); > +} > + > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) > +{ > + if (p->little_endian) > + return ioread32(addr); > + else > + return ioread32be(addr); > +} > + > +static int tmu_get_temp(void *p, int *temp) > +{ > + u32 val; > + struct qoriq_tmu_data *data = p; > + > + val = tmu_read(data, &data->regs->site[data- > >sensor_id].tritsr); > + *temp = (val & 0xff) * 1000; > + > + return 0; > +} > + > +static int qoriq_tmu_get_sensor_id(void) > +{ > + int ret, id; > + struct of_phandle_args sensor_specs; > + struct device_node *np, *sensor_np; > + > + np = of_find_node_by_name(NULL, "thermal-zones"); > + if (!np) > + return -ENODEV; > + > + sensor_np = of_get_next_child(np, NULL); > + ret = of_parse_phandle_with_args(sensor_np, "thermal- > sensors", > + "#thermal-sensor-cells", > + 0, &sensor_specs); > + if (ret) { > + of_node_put(np); > + of_node_put(sensor_np); > + return ret; > + } > + > + if (sensor_specs.args_count >= 1) { > + id = sensor_specs.args[0]; > + WARN(sensor_specs.args_count > 1, > + "%s: too many cells in sensor > specifier %d\n", > + sensor_specs.np->name, > sensor_specs.args_count); > + } else { > + id = 0; > + } > + > + of_node_put(np); > + of_node_put(sensor_np); > + > + return id; > +} > + > +static int qoriq_tmu_calibration(struct platform_device *pdev) > +{ > + int i, val, len; > + u32 range[4]; > + const u32 *calibration; > + struct device_node *np = pdev->dev.of_node; > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, > 4)) { > + dev_err(&pdev->dev, "missing calibration range.\n"); > + return -ENODEV; > + } > + > + /* Init temperature range registers */ > + tmu_write(data, range[0], &data->regs->ttr0cr); > + tmu_write(data, range[1], &data->regs->ttr1cr); > + tmu_write(data, range[2], &data->regs->ttr2cr); > + tmu_write(data, range[3], &data->regs->ttr3cr); > + > + calibration = of_get_property(np, "fsl,tmu-calibration", > &len); > + if (calibration == NULL || len % 8) { > + dev_err(&pdev->dev, "invalid calibration data.\n"); > + return -ENODEV; > + } > + > + for (i = 0; i < len; i += 8, calibration += 2) { > + val = of_read_number(calibration, 1); > + tmu_write(data, val, &data->regs->ttcfgr); > + val = of_read_number(calibration + 1, 1); > + tmu_write(data, val, &data->regs->tscfgr); > + } > + > + return 0; > +} > + > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) > +{ > + /* Disable interrupt, using polling instead */ > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > + > + /* Set update_interval */ > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > +} > + > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > + .get_temp = tmu_get_temp, > +}; > + > +static int qoriq_tmu_probe(struct platform_device *pdev) > +{ > + int ret; > + const struct thermal_trip *trip; > + struct qoriq_tmu_data *data; > + struct device_node *np = pdev->dev.of_node; > + u32 site = 0; > + > + if (!np) { > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > + return -ENODEV; > + } > + > + data = devm_kzalloc(&pdev->dev, sizeof(struct > qoriq_tmu_data), > + GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, data); > + > + data->little_endian = of_property_read_bool(np, "little- > endian"); > + > + data->sensor_id = qoriq_tmu_get_sensor_id(); > + if (data->sensor_id < 0) { > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + data->regs = of_iomap(np, 0); > + if (!data->regs) { > + dev_err(&pdev->dev, "Failed to get memory > region\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + qoriq_tmu_init_device(data); /* TMU initialization */ > + > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration > */ > + if (ret < 0) > + goto err_tmu; > + > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data- > >sensor_id, > + data, &tmu_tz_ops); > + if (IS_ERR(data->tz)) { > + ret = PTR_ERR(data->tz); > + dev_err(&pdev->dev, > + "Failed to register thermal zone device > %d\n", ret); > + goto err_tmu; > + } > + > + trip = of_thermal_get_trip_points(data->tz); > + > + /* Enable monitoring */ > + site |= 0x1 << (15 - data->sensor_id); > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > + > + return 0; > + > +err_tmu: > + iounmap(data->regs); > + > +err_iomap: > + platform_set_drvdata(pdev, NULL); > + > + return ret; > +} > + > +static int qoriq_tmu_remove(struct platform_device *pdev) > +{ > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > + > + iounmap(data->regs); > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int qoriq_tmu_suspend(struct device *dev) > +{ > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Disable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr &= ~TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > + > +static int qoriq_tmu_resume(struct device *dev) > +{ > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Enable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr |= TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > +#endif > + > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > + qoriq_tmu_suspend, qoriq_tmu_resume); > + > +static const struct of_device_id qoriq_tmu_match[] = { > + { .compatible = "fsl,qoriq-tmu", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > + > +static struct platform_driver qoriq_tmu = { > + .driver = { > + .name = "qoriq_thermal", > + .pm = &qoriq_tmu_pm_ops, > + .of_match_table = qoriq_tmu_match, > + }, > + .probe = qoriq_tmu_probe, > + .remove = qoriq_tmu_remove, > +}; > +module_platform_driver(qoriq_tmu); > + > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > +MODULE_LICENSE("GPL v2"); > -- > 2.1.0.27.g96db324 > ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-08-19 12:39 ` Zhang Rui 0 siblings, 0 replies; 18+ messages in thread From: Zhang Rui @ 2016-08-19 12:39 UTC (permalink / raw) To: linux-arm-kernel On ?, 2016-06-30 at 11:08 +0800, Jia Hongtao wrote: > This driver add thermal management support by enabling TMU (Thermal > Monitoring Unit) on QorIQ platform. > > It's based on thermal of framework: > - Trip points defined in device tree. > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> The patch looks good to me. I only need to take this patch, right? thanks, rui > --- > Changes of V2: > * Add HAS_IOMEM dependency to fix build error on UM > > ?drivers/thermal/Kconfig?????????|??10 ++ > ?drivers/thermal/Makefile????????|???1 + > ?drivers/thermal/qoriq_thermal.c | 328 > ++++++++++++++++++++++++++++++++++++++++ > ?3 files changed, 339 insertions(+) > ?create mode 100644 drivers/thermal/qoriq_thermal.c > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig > index 2d702ca..56ef30d 100644 > --- a/drivers/thermal/Kconfig > +++ b/drivers/thermal/Kconfig > @@ -195,6 +195,16 @@ config IMX_THERMAL > ? ??cpufreq is used as the cooling device to throttle CPUs > when the > ? ??passive trip is crossed. > > +config QORIQ_THERMAL > + tristate "QorIQ Thermal Monitoring Unit" > + depends on THERMAL_OF > + depends on HAS_IOMEM > + help > + ??Support for Thermal Monitoring Unit (TMU) found on QorIQ > platforms. > + ??It supports one critical trip point and one passive trip > point. The > + ??cpufreq is used as the cooling device to throttle CPUs > when the > + ??passive trip is crossed. > + > ?config SPEAR_THERMAL > ? tristate "SPEAr thermal sensor driver" > ? depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile > index 10b07c1..6662232 100644 > --- a/drivers/thermal/Makefile > +++ b/drivers/thermal/Makefile > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += > db8500_thermal.o > ?obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > ?obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > ?obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > ?obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += > db8500_cpufreq_cooling.o > ?obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > ?obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > diff --git a/drivers/thermal/qoriq_thermal.c > b/drivers/thermal/qoriq_thermal.c > new file mode 100644 > index 0000000..644ba52 > --- /dev/null > +++ b/drivers/thermal/qoriq_thermal.c > @@ -0,0 +1,328 @@ > +/* > + * Copyright 2016 Freescale Semiconductor, Inc. > + * > + * This program is free software; you can redistribute it and/or > modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but > WITHOUT > + * ANY WARRANTY; without even the implied warranty of > MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE.??See the GNU General Public > License for > + * more details. > + * > + */ > + > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > +#include <linux/thermal.h> > + > +#include "thermal_core.h" > + > +#define SITES_MAX 16 > + > +/* > + * QorIQ TMU Registers > + */ > +struct qoriq_tmu_site_regs { > + u32 tritsr; /* Immediate Temperature Site > Register */ > + u32 tratsr; /* Average Temperature Site > Register */ > + u8 res0[0x8]; > +}; > + > +struct qoriq_tmu_regs { > + u32 tmr; /* Mode Register */ > +#define TMR_DISABLE 0x0 > +#define TMR_ME 0x80000000 > +#define TMR_ALPF 0x0c000000 > + u32 tsr; /* Status Register */ > + u32 tmtmir; /* Temperature measurement > interval Register */ > +#define TMTMIR_DEFAULT 0x0000000f > + u8 res0[0x14]; > + u32 tier; /* Interrupt Enable Register */ > +#define TIER_DISABLE 0x0 > + 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 qoriq_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 */ > +}; > + > +/* > + * Thermal zone data > + */ > +struct qoriq_tmu_data { > + struct thermal_zone_device *tz; > + struct qoriq_tmu_regs __iomem *regs; > + int sensor_id; > + bool little_endian; > +}; > + > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void > __iomem *addr) > +{ > + if (p->little_endian) > + iowrite32(val, addr); > + else > + iowrite32be(val, addr); > +} > + > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) > +{ > + if (p->little_endian) > + return ioread32(addr); > + else > + return ioread32be(addr); > +} > + > +static int tmu_get_temp(void *p, int *temp) > +{ > + u32 val; > + struct qoriq_tmu_data *data = p; > + > + val = tmu_read(data, &data->regs->site[data- > >sensor_id].tritsr); > + *temp = (val & 0xff) * 1000; > + > + return 0; > +} > + > +static int qoriq_tmu_get_sensor_id(void) > +{ > + int ret, id; > + struct of_phandle_args sensor_specs; > + struct device_node *np, *sensor_np; > + > + np = of_find_node_by_name(NULL, "thermal-zones"); > + if (!np) > + return -ENODEV; > + > + sensor_np = of_get_next_child(np, NULL); > + ret = of_parse_phandle_with_args(sensor_np, "thermal- > sensors", > + "#thermal-sensor-cells", > + 0, &sensor_specs); > + if (ret) { > + of_node_put(np); > + of_node_put(sensor_np); > + return ret; > + } > + > + if (sensor_specs.args_count >= 1) { > + id = sensor_specs.args[0]; > + WARN(sensor_specs.args_count > 1, > + "%s: too many cells in sensor > specifier %d\n", > + sensor_specs.np->name, > sensor_specs.args_count); > + } else { > + id = 0; > + } > + > + of_node_put(np); > + of_node_put(sensor_np); > + > + return id; > +} > + > +static int qoriq_tmu_calibration(struct platform_device *pdev) > +{ > + int i, val, len; > + u32 range[4]; > + const u32 *calibration; > + struct device_node *np = pdev->dev.of_node; > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, > 4)) { > + dev_err(&pdev->dev, "missing calibration range.\n"); > + return -ENODEV; > + } > + > + /* Init temperature range registers */ > + tmu_write(data, range[0], &data->regs->ttr0cr); > + tmu_write(data, range[1], &data->regs->ttr1cr); > + tmu_write(data, range[2], &data->regs->ttr2cr); > + tmu_write(data, range[3], &data->regs->ttr3cr); > + > + calibration = of_get_property(np, "fsl,tmu-calibration", > &len); > + if (calibration == NULL || len % 8) { > + dev_err(&pdev->dev, "invalid calibration data.\n"); > + return -ENODEV; > + } > + > + for (i = 0; i < len; i += 8, calibration += 2) { > + val = of_read_number(calibration, 1); > + tmu_write(data, val, &data->regs->ttcfgr); > + val = of_read_number(calibration + 1, 1); > + tmu_write(data, val, &data->regs->tscfgr); > + } > + > + return 0; > +} > + > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) > +{ > + /* Disable interrupt, using polling instead */ > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > + > + /* Set update_interval */ > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > +} > + > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > + .get_temp = tmu_get_temp, > +}; > + > +static int qoriq_tmu_probe(struct platform_device *pdev) > +{ > + int ret; > + const struct thermal_trip *trip; > + struct qoriq_tmu_data *data; > + struct device_node *np = pdev->dev.of_node; > + u32 site = 0; > + > + if (!np) { > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > + return -ENODEV; > + } > + > + data = devm_kzalloc(&pdev->dev, sizeof(struct > qoriq_tmu_data), > + ????GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, data); > + > + data->little_endian = of_property_read_bool(np, "little- > endian"); > + > + data->sensor_id = qoriq_tmu_get_sensor_id(); > + if (data->sensor_id < 0) { > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + data->regs = of_iomap(np, 0); > + if (!data->regs) { > + dev_err(&pdev->dev, "Failed to get memory > region\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + qoriq_tmu_init_device(data); /* TMU initialization */ > + > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration > */ > + if (ret < 0) > + goto err_tmu; > + > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data- > >sensor_id, > + data, &tmu_tz_ops); > + if (IS_ERR(data->tz)) { > + ret = PTR_ERR(data->tz); > + dev_err(&pdev->dev, > + "Failed to register thermal zone device > %d\n", ret); > + goto err_tmu; > + } > + > + trip = of_thermal_get_trip_points(data->tz); > + > + /* Enable monitoring */ > + site |= 0x1 << (15 - data->sensor_id); > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > + > + return 0; > + > +err_tmu: > + iounmap(data->regs); > + > +err_iomap: > + platform_set_drvdata(pdev, NULL); > + > + return ret; > +} > + > +static int qoriq_tmu_remove(struct platform_device *pdev) > +{ > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > + > + iounmap(data->regs); > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int qoriq_tmu_suspend(struct device *dev) > +{ > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Disable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr &= ~TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > + > +static int qoriq_tmu_resume(struct device *dev) > +{ > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Enable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr |= TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > +#endif > + > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > + ?qoriq_tmu_suspend, qoriq_tmu_resume); > + > +static const struct of_device_id qoriq_tmu_match[] = { > + { .compatible = "fsl,qoriq-tmu", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > + > +static struct platform_driver qoriq_tmu = { > + .driver = { > + .name = "qoriq_thermal", > + .pm = &qoriq_tmu_pm_ops, > + .of_match_table = qoriq_tmu_match, > + }, > + .probe = qoriq_tmu_probe, > + .remove = qoriq_tmu_remove, > +}; > +module_platform_driver(qoriq_tmu); > + > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > +MODULE_LICENSE("GPL v2"); > -- > 2.1.0.27.g96db324 > ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-08-19 12:39 ` Zhang Rui 0 siblings, 0 replies; 18+ messages in thread From: Zhang Rui @ 2016-08-19 12:39 UTC (permalink / raw) To: Jia Hongtao, edubezval, robh+dt, galak, scott.wood, shawnguo Cc: linux-pm, devicetree, linux-kernel, linuxppc-dev, linux-arm-kernel On 四, 2016-06-30 at 11:08 +0800, Jia Hongtao wrote: > This driver add thermal management support by enabling TMU (Thermal > Monitoring Unit) on QorIQ platform. > > It's based on thermal of framework: > - Trip points defined in device tree. > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> The patch looks good to me. I only need to take this patch, right? thanks, rui > --- > Changes of V2: > * Add HAS_IOMEM dependency to fix build error on UM > > drivers/thermal/Kconfig | 10 ++ > drivers/thermal/Makefile | 1 + > drivers/thermal/qoriq_thermal.c | 328 > ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 339 insertions(+) > create mode 100644 drivers/thermal/qoriq_thermal.c > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig > index 2d702ca..56ef30d 100644 > --- a/drivers/thermal/Kconfig > +++ b/drivers/thermal/Kconfig > @@ -195,6 +195,16 @@ config IMX_THERMAL > cpufreq is used as the cooling device to throttle CPUs > when the > passive trip is crossed. > > +config QORIQ_THERMAL > + tristate "QorIQ Thermal Monitoring Unit" > + depends on THERMAL_OF > + depends on HAS_IOMEM > + help > + Support for Thermal Monitoring Unit (TMU) found on QorIQ > platforms. > + It supports one critical trip point and one passive trip > point. The > + cpufreq is used as the cooling device to throttle CPUs > when the > + passive trip is crossed. > + > config SPEAR_THERMAL > tristate "SPEAr thermal sensor driver" > depends on PLAT_SPEAR || COMPILE_TEST > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile > index 10b07c1..6662232 100644 > --- a/drivers/thermal/Makefile > +++ b/drivers/thermal/Makefile > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += > db8500_thermal.o > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += > db8500_cpufreq_cooling.o > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > diff --git a/drivers/thermal/qoriq_thermal.c > b/drivers/thermal/qoriq_thermal.c > new file mode 100644 > index 0000000..644ba52 > --- /dev/null > +++ b/drivers/thermal/qoriq_thermal.c > @@ -0,0 +1,328 @@ > +/* > + * Copyright 2016 Freescale Semiconductor, Inc. > + * > + * This program is free software; you can redistribute it and/or > modify it > + * under the terms and conditions of the GNU General Public License, > + * version 2, as published by the Free Software Foundation. > + * > + * This program is distributed in the hope it will be useful, but > WITHOUT > + * ANY WARRANTY; without even the implied warranty of > MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > License for > + * more details. > + * > + */ > + > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > +#include <linux/thermal.h> > + > +#include "thermal_core.h" > + > +#define SITES_MAX 16 > + > +/* > + * QorIQ TMU Registers > + */ > +struct qoriq_tmu_site_regs { > + u32 tritsr; /* Immediate Temperature Site > Register */ > + u32 tratsr; /* Average Temperature Site > Register */ > + u8 res0[0x8]; > +}; > + > +struct qoriq_tmu_regs { > + u32 tmr; /* Mode Register */ > +#define TMR_DISABLE 0x0 > +#define TMR_ME 0x80000000 > +#define TMR_ALPF 0x0c000000 > + u32 tsr; /* Status Register */ > + u32 tmtmir; /* Temperature measurement > interval Register */ > +#define TMTMIR_DEFAULT 0x0000000f > + u8 res0[0x14]; > + u32 tier; /* Interrupt Enable Register */ > +#define TIER_DISABLE 0x0 > + 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 qoriq_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 */ > +}; > + > +/* > + * Thermal zone data > + */ > +struct qoriq_tmu_data { > + struct thermal_zone_device *tz; > + struct qoriq_tmu_regs __iomem *regs; > + int sensor_id; > + bool little_endian; > +}; > + > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void > __iomem *addr) > +{ > + if (p->little_endian) > + iowrite32(val, addr); > + else > + iowrite32be(val, addr); > +} > + > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) > +{ > + if (p->little_endian) > + return ioread32(addr); > + else > + return ioread32be(addr); > +} > + > +static int tmu_get_temp(void *p, int *temp) > +{ > + u32 val; > + struct qoriq_tmu_data *data = p; > + > + val = tmu_read(data, &data->regs->site[data- > >sensor_id].tritsr); > + *temp = (val & 0xff) * 1000; > + > + return 0; > +} > + > +static int qoriq_tmu_get_sensor_id(void) > +{ > + int ret, id; > + struct of_phandle_args sensor_specs; > + struct device_node *np, *sensor_np; > + > + np = of_find_node_by_name(NULL, "thermal-zones"); > + if (!np) > + return -ENODEV; > + > + sensor_np = of_get_next_child(np, NULL); > + ret = of_parse_phandle_with_args(sensor_np, "thermal- > sensors", > + "#thermal-sensor-cells", > + 0, &sensor_specs); > + if (ret) { > + of_node_put(np); > + of_node_put(sensor_np); > + return ret; > + } > + > + if (sensor_specs.args_count >= 1) { > + id = sensor_specs.args[0]; > + WARN(sensor_specs.args_count > 1, > + "%s: too many cells in sensor > specifier %d\n", > + sensor_specs.np->name, > sensor_specs.args_count); > + } else { > + id = 0; > + } > + > + of_node_put(np); > + of_node_put(sensor_np); > + > + return id; > +} > + > +static int qoriq_tmu_calibration(struct platform_device *pdev) > +{ > + int i, val, len; > + u32 range[4]; > + const u32 *calibration; > + struct device_node *np = pdev->dev.of_node; > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, > 4)) { > + dev_err(&pdev->dev, "missing calibration range.\n"); > + return -ENODEV; > + } > + > + /* Init temperature range registers */ > + tmu_write(data, range[0], &data->regs->ttr0cr); > + tmu_write(data, range[1], &data->regs->ttr1cr); > + tmu_write(data, range[2], &data->regs->ttr2cr); > + tmu_write(data, range[3], &data->regs->ttr3cr); > + > + calibration = of_get_property(np, "fsl,tmu-calibration", > &len); > + if (calibration == NULL || len % 8) { > + dev_err(&pdev->dev, "invalid calibration data.\n"); > + return -ENODEV; > + } > + > + for (i = 0; i < len; i += 8, calibration += 2) { > + val = of_read_number(calibration, 1); > + tmu_write(data, val, &data->regs->ttcfgr); > + val = of_read_number(calibration + 1, 1); > + tmu_write(data, val, &data->regs->tscfgr); > + } > + > + return 0; > +} > + > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) > +{ > + /* Disable interrupt, using polling instead */ > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > + > + /* Set update_interval */ > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > +} > + > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > + .get_temp = tmu_get_temp, > +}; > + > +static int qoriq_tmu_probe(struct platform_device *pdev) > +{ > + int ret; > + const struct thermal_trip *trip; > + struct qoriq_tmu_data *data; > + struct device_node *np = pdev->dev.of_node; > + u32 site = 0; > + > + if (!np) { > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > + return -ENODEV; > + } > + > + data = devm_kzalloc(&pdev->dev, sizeof(struct > qoriq_tmu_data), > + GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + platform_set_drvdata(pdev, data); > + > + data->little_endian = of_property_read_bool(np, "little- > endian"); > + > + data->sensor_id = qoriq_tmu_get_sensor_id(); > + if (data->sensor_id < 0) { > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + data->regs = of_iomap(np, 0); > + if (!data->regs) { > + dev_err(&pdev->dev, "Failed to get memory > region\n"); > + ret = -ENODEV; > + goto err_iomap; > + } > + > + qoriq_tmu_init_device(data); /* TMU initialization */ > + > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration > */ > + if (ret < 0) > + goto err_tmu; > + > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data- > >sensor_id, > + data, &tmu_tz_ops); > + if (IS_ERR(data->tz)) { > + ret = PTR_ERR(data->tz); > + dev_err(&pdev->dev, > + "Failed to register thermal zone device > %d\n", ret); > + goto err_tmu; > + } > + > + trip = of_thermal_get_trip_points(data->tz); > + > + /* Enable monitoring */ > + site |= 0x1 << (15 - data->sensor_id); > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > + > + return 0; > + > +err_tmu: > + iounmap(data->regs); > + > +err_iomap: > + platform_set_drvdata(pdev, NULL); > + > + return ret; > +} > + > +static int qoriq_tmu_remove(struct platform_device *pdev) > +{ > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > + > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > + > + /* Disable monitoring */ > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > + > + iounmap(data->regs); > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +#ifdef CONFIG_PM_SLEEP > +static int qoriq_tmu_suspend(struct device *dev) > +{ > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Disable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr &= ~TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > + > +static int qoriq_tmu_resume(struct device *dev) > +{ > + u32 tmr; > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > + > + /* Enable monitoring */ > + tmr = tmu_read(data, &data->regs->tmr); > + tmr |= TMR_ME; > + tmu_write(data, tmr, &data->regs->tmr); > + > + return 0; > +} > +#endif > + > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > + qoriq_tmu_suspend, qoriq_tmu_resume); > + > +static const struct of_device_id qoriq_tmu_match[] = { > + { .compatible = "fsl,qoriq-tmu", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > + > +static struct platform_driver qoriq_tmu = { > + .driver = { > + .name = "qoriq_thermal", > + .pm = &qoriq_tmu_pm_ops, > + .of_match_table = qoriq_tmu_match, > + }, > + .probe = qoriq_tmu_probe, > + .remove = qoriq_tmu_remove, > +}; > +module_platform_driver(qoriq_tmu); > + > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > +MODULE_LICENSE("GPL v2"); > -- > 2.1.0.27.g96db324 > ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support 2016-08-19 12:39 ` Zhang Rui (?) (?) @ 2016-09-08 7:11 ` Troy Jia -1 siblings, 0 replies; 18+ messages in thread From: Troy Jia @ 2016-09-08 7:11 UTC (permalink / raw) To: Zhang Rui, edubezval, robh+dt, galak, Scott Wood, shawnguo Cc: linux-pm, devicetree, linux-kernel, linuxppc-dev, linux-arm-kernel > -----Original Message----- > From: Zhang Rui [mailto:rui.zhang@intel.com] > Sent: Friday, August 19, 2016 8:40 PM > To: Hongtao Jia <hongtao.jia@nxp.com>; edubezval@gmail.com; > robh+dt@kernel.org; galak@codeaurora.org; Scott Wood > <scott.wood@nxp.com>; shawnguo@kernel.org > Cc: linux-pm@vger.kernel.org; devicetree@vger.kernel.org; linux- > kernel@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; linux-arm- > kernel@lists.infradead.org > Subject: Re: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > On 四, 2016-06-30 at 11:08 +0800, Jia Hongtao wrote: > > This driver add thermal management support by enabling TMU (Thermal > > Monitoring Unit) on QorIQ platform. > > > > It's based on thermal of framework: > > - Trip points defined in device tree. > > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > > The patch looks good to me. > I only need to take this patch, right? > > thanks, > rui Yes. You just need to take this patch. Sorry for the late response. I was on my long vacation back then. Thanks, Hongtao. > > --- > > Changes of V2: > > * Add HAS_IOMEM dependency to fix build error on UM > > > > drivers/thermal/Kconfig | 10 ++ > > drivers/thermal/Makefile | 1 + > > drivers/thermal/qoriq_thermal.c | 328 > > ++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 339 insertions(+) > > create mode 100644 drivers/thermal/qoriq_thermal.c > > > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig > > index 2d702ca..56ef30d 100644 > > --- a/drivers/thermal/Kconfig > > +++ b/drivers/thermal/Kconfig > > @@ -195,6 +195,16 @@ config IMX_THERMAL > > cpufreq is used as the cooling device to throttle CPUs > > when the > > passive trip is crossed. > > > > +config QORIQ_THERMAL > > + tristate "QorIQ Thermal Monitoring Unit" > > + depends on THERMAL_OF > > + depends on HAS_IOMEM > > + help > > + Support for Thermal Monitoring Unit (TMU) found on QorIQ > > platforms. > > + It supports one critical trip point and one passive trip > > point. The > > + cpufreq is used as the cooling device to throttle CPUs > > when the > > + passive trip is crossed. > > + > > config SPEAR_THERMAL > > tristate "SPEAr thermal sensor driver" > > depends on PLAT_SPEAR || COMPILE_TEST > > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile > > index 10b07c1..6662232 100644 > > --- a/drivers/thermal/Makefile > > +++ b/drivers/thermal/Makefile > > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += > > db8500_thermal.o > > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += > > db8500_cpufreq_cooling.o > > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > > diff --git a/drivers/thermal/qoriq_thermal.c > > b/drivers/thermal/qoriq_thermal.c > > new file mode 100644 > > index 0000000..644ba52 > > --- /dev/null > > +++ b/drivers/thermal/qoriq_thermal.c > > @@ -0,0 +1,328 @@ > > +/* > > + * Copyright 2016 Freescale Semiconductor, Inc. > > + * > > + * This program is free software; you can redistribute it and/or > > modify it > > + * under the terms and conditions of the GNU General Public License, > > + * version 2, as published by the Free Software Foundation. > > + * > > + * This program is distributed in the hope it will be useful, but > > WITHOUT > > + * ANY WARRANTY; without even the implied warranty of > > MERCHANTABILITY or > > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > > License for > > + * more details. > > + * > > + */ > > + > > +#include <linux/module.h> > > +#include <linux/platform_device.h> > > +#include <linux/err.h> > > +#include <linux/io.h> > > +#include <linux/of.h> > > +#include <linux/of_address.h> > > +#include <linux/thermal.h> > > + > > +#include "thermal_core.h" > > + > > +#define SITES_MAX 16 > > + > > +/* > > + * QorIQ TMU Registers > > + */ > > +struct qoriq_tmu_site_regs { > > + u32 tritsr; /* Immediate Temperature Site > > Register */ > > + u32 tratsr; /* Average Temperature Site > > Register */ > > + u8 res0[0x8]; > > +}; > > + > > +struct qoriq_tmu_regs { > > + u32 tmr; /* Mode Register */ > > +#define TMR_DISABLE 0x0 > > +#define TMR_ME 0x80000000 > > +#define TMR_ALPF 0x0c000000 > > + u32 tsr; /* Status Register */ > > + u32 tmtmir; /* Temperature measurement > > interval Register */ > > +#define TMTMIR_DEFAULT 0x0000000f > > + u8 res0[0x14]; > > + u32 tier; /* Interrupt Enable Register */ > > +#define TIER_DISABLE 0x0 > > + 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 qoriq_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 */ > > +}; > > + > > +/* > > + * Thermal zone data > > + */ > > +struct qoriq_tmu_data { > > + struct thermal_zone_device *tz; > > + struct qoriq_tmu_regs __iomem *regs; > > + int sensor_id; > > + bool little_endian; > > +}; > > + > > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void > > __iomem *addr) > > +{ > > + if (p->little_endian) > > + iowrite32(val, addr); > > + else > > + iowrite32be(val, addr); > > +} > > + > > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) > > +{ > > + if (p->little_endian) > > + return ioread32(addr); > > + else > > + return ioread32be(addr); > > +} > > + > > +static int tmu_get_temp(void *p, int *temp) > > +{ > > + u32 val; > > + struct qoriq_tmu_data *data = p; > > + > > + val = tmu_read(data, &data->regs->site[data- > > >sensor_id].tritsr); > > + *temp = (val & 0xff) * 1000; > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_get_sensor_id(void) > > +{ > > + int ret, id; > > + struct of_phandle_args sensor_specs; > > + struct device_node *np, *sensor_np; > > + > > + np = of_find_node_by_name(NULL, "thermal-zones"); > > + if (!np) > > + return -ENODEV; > > + > > + sensor_np = of_get_next_child(np, NULL); > > + ret = of_parse_phandle_with_args(sensor_np, "thermal- > > sensors", > > + "#thermal-sensor-cells", > > + 0, &sensor_specs); > > + if (ret) { > > + of_node_put(np); > > + of_node_put(sensor_np); > > + return ret; > > + } > > + > > + if (sensor_specs.args_count >= 1) { > > + id = sensor_specs.args[0]; > > + WARN(sensor_specs.args_count > 1, > > + "%s: too many cells in sensor > > specifier %d\n", > > + sensor_specs.np->name, > > sensor_specs.args_count); > > + } else { > > + id = 0; > > + } > > + > > + of_node_put(np); > > + of_node_put(sensor_np); > > + > > + return id; > > +} > > + > > +static int qoriq_tmu_calibration(struct platform_device *pdev) > > +{ > > + int i, val, len; > > + u32 range[4]; > > + const u32 *calibration; > > + struct device_node *np = pdev->dev.of_node; > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, > > 4)) { > > + dev_err(&pdev->dev, "missing calibration range.\n"); > > + return -ENODEV; > > + } > > + > > + /* Init temperature range registers */ > > + tmu_write(data, range[0], &data->regs->ttr0cr); > > + tmu_write(data, range[1], &data->regs->ttr1cr); > > + tmu_write(data, range[2], &data->regs->ttr2cr); > > + tmu_write(data, range[3], &data->regs->ttr3cr); > > + > > + calibration = of_get_property(np, "fsl,tmu-calibration", > > &len); > > + if (calibration == NULL || len % 8) { > > + dev_err(&pdev->dev, "invalid calibration data.\n"); > > + return -ENODEV; > > + } > > + > > + for (i = 0; i < len; i += 8, calibration += 2) { > > + val = of_read_number(calibration, 1); > > + tmu_write(data, val, &data->regs->ttcfgr); > > + val = of_read_number(calibration + 1, 1); > > + tmu_write(data, val, &data->regs->tscfgr); > > + } > > + > > + return 0; > > +} > > + > > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) > > +{ > > + /* Disable interrupt, using polling instead */ > > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > > + > > + /* Set update_interval */ > > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > > +} > > + > > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > > + .get_temp = tmu_get_temp, > > +}; > > + > > +static int qoriq_tmu_probe(struct platform_device *pdev) > > +{ > > + int ret; > > + const struct thermal_trip *trip; > > + struct qoriq_tmu_data *data; > > + struct device_node *np = pdev->dev.of_node; > > + u32 site = 0; > > + > > + if (!np) { > > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > > + return -ENODEV; > > + } > > + > > + data = devm_kzalloc(&pdev->dev, sizeof(struct > > qoriq_tmu_data), > > + GFP_KERNEL); > > + if (!data) > > + return -ENOMEM; > > + > > + platform_set_drvdata(pdev, data); > > + > > + data->little_endian = of_property_read_bool(np, "little- > > endian"); > > + > > + data->sensor_id = qoriq_tmu_get_sensor_id(); > > + if (data->sensor_id < 0) { > > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + data->regs = of_iomap(np, 0); > > + if (!data->regs) { > > + dev_err(&pdev->dev, "Failed to get memory > > region\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + qoriq_tmu_init_device(data); /* TMU initialization */ > > + > > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration > > */ > > + if (ret < 0) > > + goto err_tmu; > > + > > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data- > > >sensor_id, > > + data, &tmu_tz_ops); > > + if (IS_ERR(data->tz)) { > > + ret = PTR_ERR(data->tz); > > + dev_err(&pdev->dev, > > + "Failed to register thermal zone device > > %d\n", ret); > > + goto err_tmu; > > + } > > + > > + trip = of_thermal_get_trip_points(data->tz); > > + > > + /* Enable monitoring */ > > + site |= 0x1 << (15 - data->sensor_id); > > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > > + > > + return 0; > > + > > +err_tmu: > > + iounmap(data->regs); > > + > > +err_iomap: > > + platform_set_drvdata(pdev, NULL); > > + > > + return ret; > > +} > > + > > +static int qoriq_tmu_remove(struct platform_device *pdev) > > +{ > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > > + > > + iounmap(data->regs); > > + platform_set_drvdata(pdev, NULL); > > + > > + return 0; > > +} > > + > > +#ifdef CONFIG_PM_SLEEP > > +static int qoriq_tmu_suspend(struct device *dev) > > +{ > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Disable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr &= ~TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_resume(struct device *dev) > > +{ > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Enable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr |= TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > +#endif > > + > > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > > + qoriq_tmu_suspend, qoriq_tmu_resume); > > + > > +static const struct of_device_id qoriq_tmu_match[] = { > > + { .compatible = "fsl,qoriq-tmu", }, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > > + > > +static struct platform_driver qoriq_tmu = { > > + .driver = { > > + .name = "qoriq_thermal", > > + .pm = &qoriq_tmu_pm_ops, > > + .of_match_table = qoriq_tmu_match, > > + }, > > + .probe = qoriq_tmu_probe, > > + .remove = qoriq_tmu_remove, > > +}; > > +module_platform_driver(qoriq_tmu); > > + > > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > > +MODULE_LICENSE("GPL v2"); > > -- > > 2.1.0.27.g96db324 > > ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-09-08 7:11 ` Troy Jia 0 siblings, 0 replies; 18+ messages in thread From: Troy Jia @ 2016-09-08 7:11 UTC (permalink / raw) To: linux-arm-kernel > -----Original Message----- > From: Zhang Rui [mailto:rui.zhang at intel.com] > Sent: Friday, August 19, 2016 8:40 PM > To: Hongtao Jia <hongtao.jia@nxp.com>; edubezval at gmail.com; > robh+dt at kernel.org; galak at codeaurora.org; Scott Wood > <scott.wood@nxp.com>; shawnguo at kernel.org > Cc: linux-pm at vger.kernel.org; devicetree at vger.kernel.org; linux- > kernel at vger.kernel.org; linuxppc-dev at lists.ozlabs.org; linux-arm- > kernel at lists.infradead.org > Subject: Re: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > On ?, 2016-06-30 at 11:08 +0800, Jia Hongtao wrote: > > This driver add thermal management support by enabling TMU (Thermal > > Monitoring Unit) on QorIQ platform. > > > > It's based on thermal of framework: > > - Trip points defined in device tree. > > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > > The patch looks good to me. > I only need to take this patch, right? > > thanks, > rui Yes. You just need to take this patch. Sorry for the late response. I was on my long vacation back then. Thanks, Hongtao. > > --- > > Changes of V2: > > * Add HAS_IOMEM dependency to fix build error on UM > > > > ?drivers/thermal/Kconfig?????????|??10 ++ > > ?drivers/thermal/Makefile????????|???1 + > > ?drivers/thermal/qoriq_thermal.c | 328 > > ++++++++++++++++++++++++++++++++++++++++ > > ?3 files changed, 339 insertions(+) > > ?create mode 100644 drivers/thermal/qoriq_thermal.c > > > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig > > index 2d702ca..56ef30d 100644 > > --- a/drivers/thermal/Kconfig > > +++ b/drivers/thermal/Kconfig > > @@ -195,6 +195,16 @@ config IMX_THERMAL > > ? ??cpufreq is used as the cooling device to throttle CPUs > > when the > > ? ??passive trip is crossed. > > > > +config QORIQ_THERMAL > > + tristate "QorIQ Thermal Monitoring Unit" > > + depends on THERMAL_OF > > + depends on HAS_IOMEM > > + help > > + ??Support for Thermal Monitoring Unit (TMU) found on QorIQ > > platforms. > > + ??It supports one critical trip point and one passive trip > > point. The > > + ??cpufreq is used as the cooling device to throttle CPUs > > when the > > + ??passive trip is crossed. > > + > > ?config SPEAR_THERMAL > > ? tristate "SPEAr thermal sensor driver" > > ? depends on PLAT_SPEAR || COMPILE_TEST > > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile > > index 10b07c1..6662232 100644 > > --- a/drivers/thermal/Makefile > > +++ b/drivers/thermal/Makefile > > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += > > db8500_thermal.o > > ?obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > > ?obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > > ?obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > > ?obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += > > db8500_cpufreq_cooling.o > > ?obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > > ?obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > > diff --git a/drivers/thermal/qoriq_thermal.c > > b/drivers/thermal/qoriq_thermal.c > > new file mode 100644 > > index 0000000..644ba52 > > --- /dev/null > > +++ b/drivers/thermal/qoriq_thermal.c > > @@ -0,0 +1,328 @@ > > +/* > > + * Copyright 2016 Freescale Semiconductor, Inc. > > + * > > + * This program is free software; you can redistribute it and/or > > modify it > > + * under the terms and conditions of the GNU General Public License, > > + * version 2, as published by the Free Software Foundation. > > + * > > + * This program is distributed in the hope it will be useful, but > > WITHOUT > > + * ANY WARRANTY; without even the implied warranty of > > MERCHANTABILITY or > > + * FITNESS FOR A PARTICULAR PURPOSE.??See the GNU General Public > > License for > > + * more details. > > + * > > + */ > > + > > +#include <linux/module.h> > > +#include <linux/platform_device.h> > > +#include <linux/err.h> > > +#include <linux/io.h> > > +#include <linux/of.h> > > +#include <linux/of_address.h> > > +#include <linux/thermal.h> > > + > > +#include "thermal_core.h" > > + > > +#define SITES_MAX 16 > > + > > +/* > > + * QorIQ TMU Registers > > + */ > > +struct qoriq_tmu_site_regs { > > + u32 tritsr; /* Immediate Temperature Site > > Register */ > > + u32 tratsr; /* Average Temperature Site > > Register */ > > + u8 res0[0x8]; > > +}; > > + > > +struct qoriq_tmu_regs { > > + u32 tmr; /* Mode Register */ > > +#define TMR_DISABLE 0x0 > > +#define TMR_ME 0x80000000 > > +#define TMR_ALPF 0x0c000000 > > + u32 tsr; /* Status Register */ > > + u32 tmtmir; /* Temperature measurement > > interval Register */ > > +#define TMTMIR_DEFAULT 0x0000000f > > + u8 res0[0x14]; > > + u32 tier; /* Interrupt Enable Register */ > > +#define TIER_DISABLE 0x0 > > + 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 qoriq_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 */ > > +}; > > + > > +/* > > + * Thermal zone data > > + */ > > +struct qoriq_tmu_data { > > + struct thermal_zone_device *tz; > > + struct qoriq_tmu_regs __iomem *regs; > > + int sensor_id; > > + bool little_endian; > > +}; > > + > > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void > > __iomem *addr) > > +{ > > + if (p->little_endian) > > + iowrite32(val, addr); > > + else > > + iowrite32be(val, addr); > > +} > > + > > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) > > +{ > > + if (p->little_endian) > > + return ioread32(addr); > > + else > > + return ioread32be(addr); > > +} > > + > > +static int tmu_get_temp(void *p, int *temp) > > +{ > > + u32 val; > > + struct qoriq_tmu_data *data = p; > > + > > + val = tmu_read(data, &data->regs->site[data- > > >sensor_id].tritsr); > > + *temp = (val & 0xff) * 1000; > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_get_sensor_id(void) > > +{ > > + int ret, id; > > + struct of_phandle_args sensor_specs; > > + struct device_node *np, *sensor_np; > > + > > + np = of_find_node_by_name(NULL, "thermal-zones"); > > + if (!np) > > + return -ENODEV; > > + > > + sensor_np = of_get_next_child(np, NULL); > > + ret = of_parse_phandle_with_args(sensor_np, "thermal- > > sensors", > > + "#thermal-sensor-cells", > > + 0, &sensor_specs); > > + if (ret) { > > + of_node_put(np); > > + of_node_put(sensor_np); > > + return ret; > > + } > > + > > + if (sensor_specs.args_count >= 1) { > > + id = sensor_specs.args[0]; > > + WARN(sensor_specs.args_count > 1, > > + "%s: too many cells in sensor > > specifier %d\n", > > + sensor_specs.np->name, > > sensor_specs.args_count); > > + } else { > > + id = 0; > > + } > > + > > + of_node_put(np); > > + of_node_put(sensor_np); > > + > > + return id; > > +} > > + > > +static int qoriq_tmu_calibration(struct platform_device *pdev) > > +{ > > + int i, val, len; > > + u32 range[4]; > > + const u32 *calibration; > > + struct device_node *np = pdev->dev.of_node; > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, > > 4)) { > > + dev_err(&pdev->dev, "missing calibration range.\n"); > > + return -ENODEV; > > + } > > + > > + /* Init temperature range registers */ > > + tmu_write(data, range[0], &data->regs->ttr0cr); > > + tmu_write(data, range[1], &data->regs->ttr1cr); > > + tmu_write(data, range[2], &data->regs->ttr2cr); > > + tmu_write(data, range[3], &data->regs->ttr3cr); > > + > > + calibration = of_get_property(np, "fsl,tmu-calibration", > > &len); > > + if (calibration == NULL || len % 8) { > > + dev_err(&pdev->dev, "invalid calibration data.\n"); > > + return -ENODEV; > > + } > > + > > + for (i = 0; i < len; i += 8, calibration += 2) { > > + val = of_read_number(calibration, 1); > > + tmu_write(data, val, &data->regs->ttcfgr); > > + val = of_read_number(calibration + 1, 1); > > + tmu_write(data, val, &data->regs->tscfgr); > > + } > > + > > + return 0; > > +} > > + > > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) > > +{ > > + /* Disable interrupt, using polling instead */ > > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > > + > > + /* Set update_interval */ > > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > > +} > > + > > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > > + .get_temp = tmu_get_temp, > > +}; > > + > > +static int qoriq_tmu_probe(struct platform_device *pdev) > > +{ > > + int ret; > > + const struct thermal_trip *trip; > > + struct qoriq_tmu_data *data; > > + struct device_node *np = pdev->dev.of_node; > > + u32 site = 0; > > + > > + if (!np) { > > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > > + return -ENODEV; > > + } > > + > > + data = devm_kzalloc(&pdev->dev, sizeof(struct > > qoriq_tmu_data), > > + ????GFP_KERNEL); > > + if (!data) > > + return -ENOMEM; > > + > > + platform_set_drvdata(pdev, data); > > + > > + data->little_endian = of_property_read_bool(np, "little- > > endian"); > > + > > + data->sensor_id = qoriq_tmu_get_sensor_id(); > > + if (data->sensor_id < 0) { > > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + data->regs = of_iomap(np, 0); > > + if (!data->regs) { > > + dev_err(&pdev->dev, "Failed to get memory > > region\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + qoriq_tmu_init_device(data); /* TMU initialization */ > > + > > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration > > */ > > + if (ret < 0) > > + goto err_tmu; > > + > > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data- > > >sensor_id, > > + data, &tmu_tz_ops); > > + if (IS_ERR(data->tz)) { > > + ret = PTR_ERR(data->tz); > > + dev_err(&pdev->dev, > > + "Failed to register thermal zone device > > %d\n", ret); > > + goto err_tmu; > > + } > > + > > + trip = of_thermal_get_trip_points(data->tz); > > + > > + /* Enable monitoring */ > > + site |= 0x1 << (15 - data->sensor_id); > > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > > + > > + return 0; > > + > > +err_tmu: > > + iounmap(data->regs); > > + > > +err_iomap: > > + platform_set_drvdata(pdev, NULL); > > + > > + return ret; > > +} > > + > > +static int qoriq_tmu_remove(struct platform_device *pdev) > > +{ > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > > + > > + iounmap(data->regs); > > + platform_set_drvdata(pdev, NULL); > > + > > + return 0; > > +} > > + > > +#ifdef CONFIG_PM_SLEEP > > +static int qoriq_tmu_suspend(struct device *dev) > > +{ > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Disable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr &= ~TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_resume(struct device *dev) > > +{ > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Enable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr |= TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > +#endif > > + > > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > > + ?qoriq_tmu_suspend, qoriq_tmu_resume); > > + > > +static const struct of_device_id qoriq_tmu_match[] = { > > + { .compatible = "fsl,qoriq-tmu", }, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > > + > > +static struct platform_driver qoriq_tmu = { > > + .driver = { > > + .name = "qoriq_thermal", > > + .pm = &qoriq_tmu_pm_ops, > > + .of_match_table = qoriq_tmu_match, > > + }, > > + .probe = qoriq_tmu_probe, > > + .remove = qoriq_tmu_remove, > > +}; > > +module_platform_driver(qoriq_tmu); > > + > > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > > +MODULE_LICENSE("GPL v2"); > > -- > > 2.1.0.27.g96db324 > > ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-09-08 7:11 ` Troy Jia 0 siblings, 0 replies; 18+ messages in thread From: Troy Jia @ 2016-09-08 7:11 UTC (permalink / raw) To: Zhang Rui, edubezval, robh+dt, galak, Scott Wood, shawnguo Cc: linux-pm, devicetree, linux-kernel, linuxppc-dev, linux-arm-kernel DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogWmhhbmcgUnVpIFttYWls dG86cnVpLnpoYW5nQGludGVsLmNvbV0NCj4gU2VudDogRnJpZGF5LCBBdWd1c3QgMTksIDIwMTYg ODo0MCBQTQ0KPiBUbzogSG9uZ3RhbyBKaWEgPGhvbmd0YW8uamlhQG54cC5jb20+OyBlZHViZXp2 YWxAZ21haWwuY29tOw0KPiByb2JoK2R0QGtlcm5lbC5vcmc7IGdhbGFrQGNvZGVhdXJvcmEub3Jn OyBTY290dCBXb29kDQo+IDxzY290dC53b29kQG54cC5jb20+OyBzaGF3bmd1b0BrZXJuZWwub3Jn DQo+IENjOiBsaW51eC1wbUB2Z2VyLmtlcm5lbC5vcmc7IGRldmljZXRyZWVAdmdlci5rZXJuZWwu b3JnOyBsaW51eC0NCj4ga2VybmVsQHZnZXIua2VybmVsLm9yZzsgbGludXhwcGMtZGV2QGxpc3Rz Lm96bGFicy5vcmc7IGxpbnV4LWFybS0NCj4ga2VybmVsQGxpc3RzLmluZnJhZGVhZC5vcmcNCj4g U3ViamVjdDogUmU6IFtQQVRDSCBWMiA3LzddIHRoZXJtYWw6IHFvcmlxOiBBZGQgdGhlcm1hbCBt YW5hZ2VtZW50IHN1cHBvcnQNCj4gDQo+IE9uIOWbmywgMjAxNi0wNi0zMCBhdCAxMTowOCArMDgw MCwgSmlhIEhvbmd0YW8gd3JvdGU6DQo+ID4gVGhpcyBkcml2ZXIgYWRkIHRoZXJtYWwgbWFuYWdl bWVudCBzdXBwb3J0IGJ5IGVuYWJsaW5nIFRNVSAoVGhlcm1hbA0KPiA+IE1vbml0b3JpbmcgVW5p dCkgb24gUW9ySVEgcGxhdGZvcm0uDQo+ID4NCj4gPiBJdCdzIGJhc2VkIG9uIHRoZXJtYWwgb2Yg ZnJhbWV3b3JrOg0KPiA+IC0gVHJpcCBwb2ludHMgZGVmaW5lZCBpbiBkZXZpY2UgdHJlZS4NCj4g PiAtIENwdWZyZXEgYXMgY29vbGluZyBkZXZpY2UgcmVnaXN0ZXJlZCBpbiBxb3JpcSBjcHVmcmVx IGRyaXZlci4NCj4gPg0KPiA+IFNpZ25lZC1vZmYtYnk6IEppYSBIb25ndGFvIDxob25ndGFvLmpp YUBueHAuY29tPg0KPiANCj4gVGhlIHBhdGNoIGxvb2tzIGdvb2QgdG8gbWUuDQo+IEkgb25seSBu ZWVkIHRvIHRha2UgdGhpcyBwYXRjaCwgcmlnaHQ/DQo+IA0KPiB0aGFua3MsDQo+IHJ1aQ0KDQpZ ZXMuIFlvdSBqdXN0IG5lZWQgdG8gdGFrZSB0aGlzIHBhdGNoLg0KU29ycnkgZm9yIHRoZSBsYXRl IHJlc3BvbnNlLiBJIHdhcyBvbiBteSBsb25nIHZhY2F0aW9uIGJhY2sgdGhlbi4NCg0KVGhhbmtz LA0KSG9uZ3Rhby4NCg0KPiA+IC0tLQ0KPiA+IENoYW5nZXMgb2YgVjI6DQo+ID4gKiBBZGQgSEFT X0lPTUVNIGRlcGVuZGVuY3kgdG8gZml4IGJ1aWxkIGVycm9yIG9uIFVNDQo+ID4NCj4gPiDCoGRy aXZlcnMvdGhlcm1hbC9LY29uZmlnwqDCoMKgwqDCoMKgwqDCoMKgfMKgwqAxMCArKw0KPiA+IMKg ZHJpdmVycy90aGVybWFsL01ha2VmaWxlwqDCoMKgwqDCoMKgwqDCoHzCoMKgwqAxICsNCj4gPiDC oGRyaXZlcnMvdGhlcm1hbC9xb3JpcV90aGVybWFsLmMgfCAzMjgNCj4gPiArKysrKysrKysrKysr KysrKysrKysrKysrKysrKysrKysrKysrKysrDQo+ID4gwqAzIGZpbGVzIGNoYW5nZWQsIDMzOSBp bnNlcnRpb25zKCspDQo+ID4gwqBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy90aGVybWFsL3Fv cmlxX3RoZXJtYWwuYw0KPiA+DQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdGhlcm1hbC9LY29u ZmlnIGIvZHJpdmVycy90aGVybWFsL0tjb25maWcNCj4gPiBpbmRleCAyZDcwMmNhLi41NmVmMzBk IDEwMDY0NA0KPiA+IC0tLSBhL2RyaXZlcnMvdGhlcm1hbC9LY29uZmlnDQo+ID4gKysrIGIvZHJp dmVycy90aGVybWFsL0tjb25maWcNCj4gPiBAQCAtMTk1LDYgKzE5NSwxNiBAQCBjb25maWcgSU1Y X1RIRVJNQUwNCj4gPiDCoAnCoMKgY3B1ZnJlcSBpcyB1c2VkIGFzIHRoZSBjb29saW5nIGRldmlj ZSB0byB0aHJvdHRsZSBDUFVzDQo+ID4gd2hlbiB0aGUNCj4gPiDCoAnCoMKgcGFzc2l2ZSB0cmlw IGlzIGNyb3NzZWQuDQo+ID4NCj4gPiArY29uZmlnIFFPUklRX1RIRVJNQUwNCj4gPiArCXRyaXN0 YXRlICJRb3JJUSBUaGVybWFsIE1vbml0b3JpbmcgVW5pdCINCj4gPiArCWRlcGVuZHMgb24gVEhF Uk1BTF9PRg0KPiA+ICsJZGVwZW5kcyBvbiBIQVNfSU9NRU0NCj4gPiArCWhlbHANCj4gPiArCcKg wqBTdXBwb3J0IGZvciBUaGVybWFsIE1vbml0b3JpbmcgVW5pdCAoVE1VKSBmb3VuZCBvbiBRb3JJ UQ0KPiA+IHBsYXRmb3Jtcy4NCj4gPiArCcKgwqBJdCBzdXBwb3J0cyBvbmUgY3JpdGljYWwgdHJp cCBwb2ludCBhbmQgb25lIHBhc3NpdmUgdHJpcA0KPiA+IHBvaW50LiBUaGUNCj4gPiArCcKgwqBj cHVmcmVxIGlzIHVzZWQgYXMgdGhlIGNvb2xpbmcgZGV2aWNlIHRvIHRocm90dGxlIENQVXMNCj4g PiB3aGVuIHRoZQ0KPiA+ICsJwqDCoHBhc3NpdmUgdHJpcCBpcyBjcm9zc2VkLg0KPiA+ICsNCj4g PiDCoGNvbmZpZyBTUEVBUl9USEVSTUFMDQo+ID4gwqAJdHJpc3RhdGUgIlNQRUFyIHRoZXJtYWwg c2Vuc29yIGRyaXZlciINCj4gPiDCoAlkZXBlbmRzIG9uIFBMQVRfU1BFQVIgfHwgQ09NUElMRV9U RVNUDQo+ID4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdGhlcm1hbC9NYWtlZmlsZSBiL2RyaXZlcnMv dGhlcm1hbC9NYWtlZmlsZQ0KPiA+IGluZGV4IDEwYjA3YzEuLjY2NjIyMzIgMTAwNjQ0DQo+ID4g LS0tIGEvZHJpdmVycy90aGVybWFsL01ha2VmaWxlDQo+ID4gKysrIGIvZHJpdmVycy90aGVybWFs L01ha2VmaWxlDQo+ID4gQEAgLTM3LDYgKzM3LDcgQEAgb2JqLSQoQ09ORklHX0RCODUwMF9USEVS TUFMKQkrPQ0KPiA+IGRiODUwMF90aGVybWFsLm8NCj4gPiDCoG9iai0kKENPTkZJR19BUk1BREFf VEhFUk1BTCkJKz0gYXJtYWRhX3RoZXJtYWwubw0KPiA+IMKgb2JqLSQoQ09ORklHX1RBTkdPX1RI RVJNQUwpCSs9IHRhbmdvX3RoZXJtYWwubw0KPiA+IMKgb2JqLSQoQ09ORklHX0lNWF9USEVSTUFM KQkrPSBpbXhfdGhlcm1hbC5vDQo+ID4gK29iai0kKENPTkZJR19RT1JJUV9USEVSTUFMKQkrPSBx b3JpcV90aGVybWFsLm8NCj4gPiDCoG9iai0kKENPTkZJR19EQjg1MDBfQ1BVRlJFUV9DT09MSU5H KQkrPQ0KPiA+IGRiODUwMF9jcHVmcmVxX2Nvb2xpbmcubw0KPiA+IMKgb2JqLSQoQ09ORklHX0lO VEVMX1BPV0VSQ0xBTVApCSs9IGludGVsX3Bvd2VyY2xhbXAubw0KPiA+IMKgb2JqLSQoQ09ORklH X1g4Nl9QS0dfVEVNUF9USEVSTUFMKQkrPSB4ODZfcGtnX3RlbXBfdGhlcm1hbC5vDQo+ID4gZGlm ZiAtLWdpdCBhL2RyaXZlcnMvdGhlcm1hbC9xb3JpcV90aGVybWFsLmMNCj4gPiBiL2RyaXZlcnMv dGhlcm1hbC9xb3JpcV90aGVybWFsLmMNCj4gPiBuZXcgZmlsZSBtb2RlIDEwMDY0NA0KPiA+IGlu ZGV4IDAwMDAwMDAuLjY0NGJhNTINCj4gPiAtLS0gL2Rldi9udWxsDQo+ID4gKysrIGIvZHJpdmVy cy90aGVybWFsL3FvcmlxX3RoZXJtYWwuYw0KPiA+IEBAIC0wLDAgKzEsMzI4IEBADQo+ID4gKy8q DQo+ID4gKyAqIENvcHlyaWdodCAyMDE2IEZyZWVzY2FsZSBTZW1pY29uZHVjdG9yLCBJbmMuDQo+ ID4gKyAqDQo+ID4gKyAqIFRoaXMgcHJvZ3JhbSBpcyBmcmVlIHNvZnR3YXJlOyB5b3UgY2FuIHJl ZGlzdHJpYnV0ZSBpdCBhbmQvb3INCj4gPiBtb2RpZnkgaXQNCj4gPiArICogdW5kZXIgdGhlIHRl cm1zIGFuZCBjb25kaXRpb25zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSwNCj4g PiArICogdmVyc2lvbiAyLCBhcyBwdWJsaXNoZWQgYnkgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRh dGlvbi4NCj4gPiArICoNCj4gPiArICogVGhpcyBwcm9ncmFtIGlzIGRpc3RyaWJ1dGVkIGluIHRo ZSBob3BlIGl0IHdpbGwgYmUgdXNlZnVsLCBidXQNCj4gPiBXSVRIT1VUDQo+ID4gKyAqIEFOWSBX QVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mDQo+ID4gTUVSQ0hB TlRBQklMSVRZIG9yDQo+ID4gKyAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFLsKg wqBTZWUgdGhlIEdOVSBHZW5lcmFsIFB1YmxpYw0KPiA+IExpY2Vuc2UgZm9yDQo+ID4gKyAqIG1v cmUgZGV0YWlscy4NCj4gPiArICoNCj4gPiArICovDQo+ID4gKw0KPiA+ICsjaW5jbHVkZSA8bGlu dXgvbW9kdWxlLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9wbGF0Zm9ybV9kZXZpY2UuaD4NCj4g PiArI2luY2x1ZGUgPGxpbnV4L2Vyci5oPg0KPiA+ICsjaW5jbHVkZSA8bGludXgvaW8uaD4NCj4g PiArI2luY2x1ZGUgPGxpbnV4L29mLmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC9vZl9hZGRyZXNz Lmg+DQo+ID4gKyNpbmNsdWRlIDxsaW51eC90aGVybWFsLmg+DQo+ID4gKw0KPiA+ICsjaW5jbHVk ZSAidGhlcm1hbF9jb3JlLmgiDQo+ID4gKw0KPiA+ICsjZGVmaW5lIFNJVEVTX01BWAkxNg0KPiA+ ICsNCj4gPiArLyoNCj4gPiArICogUW9ySVEgVE1VIFJlZ2lzdGVycw0KPiA+ICsgKi8NCj4gPiAr c3RydWN0IHFvcmlxX3RtdV9zaXRlX3JlZ3Mgew0KPiA+ICsJdTMyIHRyaXRzcjsJCS8qIEltbWVk aWF0ZSBUZW1wZXJhdHVyZSBTaXRlDQo+ID4gUmVnaXN0ZXIgKi8NCj4gPiArCXUzMiB0cmF0c3I7 CQkvKiBBdmVyYWdlIFRlbXBlcmF0dXJlIFNpdGUNCj4gPiBSZWdpc3RlciAqLw0KPiA+ICsJdTgg cmVzMFsweDhdOw0KPiA+ICt9Ow0KPiA+ICsNCj4gPiArc3RydWN0IHFvcmlxX3RtdV9yZWdzIHsN Cj4gPiArCXUzMiB0bXI7CQkvKiBNb2RlIFJlZ2lzdGVyICovDQo+ID4gKyNkZWZpbmUgVE1SX0RJ U0FCTEUJMHgwDQo+ID4gKyNkZWZpbmUgVE1SX01FCQkweDgwMDAwMDAwDQo+ID4gKyNkZWZpbmUg VE1SX0FMUEYJMHgwYzAwMDAwMA0KPiA+ICsJdTMyIHRzcjsJCS8qIFN0YXR1cyBSZWdpc3RlciAq Lw0KPiA+ICsJdTMyIHRtdG1pcjsJCS8qIFRlbXBlcmF0dXJlIG1lYXN1cmVtZW50DQo+ID4gaW50 ZXJ2YWwgUmVnaXN0ZXIgKi8NCj4gPiArI2RlZmluZSBUTVRNSVJfREVGQVVMVAkweDAwMDAwMDBm DQo+ID4gKwl1OCByZXMwWzB4MTRdOw0KPiA+ICsJdTMyIHRpZXI7CQkvKiBJbnRlcnJ1cHQgRW5h YmxlIFJlZ2lzdGVyICovDQo+ID4gKyNkZWZpbmUgVElFUl9ESVNBQkxFCTB4MA0KPiA+ICsJdTMy IHRpZHI7CQkvKiBJbnRlcnJ1cHQgRGV0ZWN0IFJlZ2lzdGVyICovDQo+ID4gKwl1MzIgdGlzY3I7 CQkvKiBJbnRlcnJ1cHQgU2l0ZSBDYXB0dXJlIFJlZ2lzdGVyDQo+ID4gKi8NCj4gPiArCXUzMiB0 aWNzY3I7CQkvKiBJbnRlcnJ1cHQgQ3JpdGljYWwgU2l0ZQ0KPiA+IENhcHR1cmUgUmVnaXN0ZXIg Ki8NCj4gPiArCXU4IHJlczFbMHgxMF07DQo+ID4gKwl1MzIgdG1odGNyaDsJCS8qIEhpZ2ggVGVt cGVyYXR1cmUgQ2FwdHVyZQ0KPiA+IFJlZ2lzdGVyICovDQo+ID4gKwl1MzIgdG1odGNybDsJCS8q IExvdyBUZW1wZXJhdHVyZSBDYXB0dXJlDQo+ID4gUmVnaXN0ZXIgKi8NCj4gPiArCXU4IHJlczJb MHg4XTsNCj4gPiArCXUzMiB0bWh0aXRyOwkJLyogSGlnaCBUZW1wZXJhdHVyZSBJbW1lZGlhdGUN Cj4gPiBUaHJlc2hvbGQgKi8NCj4gPiArCXUzMiB0bWh0YXRyOwkJLyogSGlnaCBUZW1wZXJhdHVy ZSBBdmVyYWdlDQo+ID4gVGhyZXNob2xkICovDQo+ID4gKwl1MzIgdG1odGFjdHI7CS8qIEhpZ2gg VGVtcGVyYXR1cmUgQXZlcmFnZSBDcml0DQo+ID4gVGhyZXNob2xkICovDQo+ID4gKwl1OCByZXMz WzB4MjRdOw0KPiA+ICsJdTMyIHR0Y2ZncjsJCS8qIFRlbXBlcmF0dXJlIENvbmZpZ3VyYXRpb24N Cj4gPiBSZWdpc3RlciAqLw0KPiA+ICsJdTMyIHRzY2ZncjsJCS8qIFNlbnNvciBDb25maWd1cmF0 aW9uIFJlZ2lzdGVyDQo+ID4gKi8NCj4gPiArCXU4IHJlczRbMHg3OF07DQo+ID4gKwlzdHJ1Y3Qg cW9yaXFfdG11X3NpdGVfcmVncyBzaXRlW1NJVEVTX01BWF07DQo+ID4gKwl1OCByZXM1WzB4OWY4 XTsNCj4gPiArCXUzMiBpcGJycjA7CQkvKiBJUCBCbG9jayBSZXZpc2lvbiBSZWdpc3RlciAwDQo+ ID4gKi8NCj4gPiArCXUzMiBpcGJycjE7CQkvKiBJUCBCbG9jayBSZXZpc2lvbiBSZWdpc3RlciAx DQo+ID4gKi8NCj4gPiArCXU4IHJlczZbMHgzMTBdOw0KPiA+ICsJdTMyIHR0cjBjcjsJCS8qIFRl bXBlcmF0dXJlIFJhbmdlIDAgQ29udHJvbA0KPiA+IFJlZ2lzdGVyICovDQo+ID4gKwl1MzIgdHRy MWNyOwkJLyogVGVtcGVyYXR1cmUgUmFuZ2UgMSBDb250cm9sDQo+ID4gUmVnaXN0ZXIgKi8NCj4g PiArCXUzMiB0dHIyY3I7CQkvKiBUZW1wZXJhdHVyZSBSYW5nZSAyIENvbnRyb2wNCj4gPiBSZWdp c3RlciAqLw0KPiA+ICsJdTMyIHR0cjNjcjsJCS8qIFRlbXBlcmF0dXJlIFJhbmdlIDMgQ29udHJv bA0KPiA+IFJlZ2lzdGVyICovDQo+ID4gK307DQo+ID4gKw0KPiA+ICsvKg0KPiA+ICsgKiBUaGVy bWFsIHpvbmUgZGF0YQ0KPiA+ICsgKi8NCj4gPiArc3RydWN0IHFvcmlxX3RtdV9kYXRhIHsNCj4g PiArCXN0cnVjdCB0aGVybWFsX3pvbmVfZGV2aWNlICp0ejsNCj4gPiArCXN0cnVjdCBxb3JpcV90 bXVfcmVncyBfX2lvbWVtICpyZWdzOw0KPiA+ICsJaW50IHNlbnNvcl9pZDsNCj4gPiArCWJvb2wg bGl0dGxlX2VuZGlhbjsNCj4gPiArfTsNCj4gPiArDQo+ID4gK3N0YXRpYyB2b2lkIHRtdV93cml0 ZShzdHJ1Y3QgcW9yaXFfdG11X2RhdGEgKnAsIHUzMiB2YWwsIHZvaWQNCj4gPiBfX2lvbWVtICph ZGRyKQ0KPiA+ICt7DQo+ID4gKwlpZiAocC0+bGl0dGxlX2VuZGlhbikNCj4gPiArCQlpb3dyaXRl MzIodmFsLCBhZGRyKTsNCj4gPiArCWVsc2UNCj4gPiArCQlpb3dyaXRlMzJiZSh2YWwsIGFkZHIp Ow0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgdTMyIHRtdV9yZWFkKHN0cnVjdCBxb3JpcV90 bXVfZGF0YSAqcCwgdm9pZCBfX2lvbWVtICphZGRyKQ0KPiA+ICt7DQo+ID4gKwlpZiAocC0+bGl0 dGxlX2VuZGlhbikNCj4gPiArCQlyZXR1cm4gaW9yZWFkMzIoYWRkcik7DQo+ID4gKwllbHNlDQo+ ID4gKwkJcmV0dXJuIGlvcmVhZDMyYmUoYWRkcik7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRp YyBpbnQgdG11X2dldF90ZW1wKHZvaWQgKnAsIGludCAqdGVtcCkNCj4gPiArew0KPiA+ICsJdTMy IHZhbDsNCj4gPiArCXN0cnVjdCBxb3JpcV90bXVfZGF0YSAqZGF0YSA9IHA7DQo+ID4gKw0KPiA+ ICsJdmFsID0gdG11X3JlYWQoZGF0YSwgJmRhdGEtPnJlZ3MtPnNpdGVbZGF0YS0NCj4gPiA+c2Vu c29yX2lkXS50cml0c3IpOw0KPiA+ICsJKnRlbXAgPSAodmFsICYgMHhmZikgKiAxMDAwOw0KPiA+ ICsNCj4gPiArCXJldHVybiAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IHFvcmlx X3RtdV9nZXRfc2Vuc29yX2lkKHZvaWQpDQo+ID4gK3sNCj4gPiArCWludCByZXQsIGlkOw0KPiA+ ICsJc3RydWN0IG9mX3BoYW5kbGVfYXJncyBzZW5zb3Jfc3BlY3M7DQo+ID4gKwlzdHJ1Y3QgZGV2 aWNlX25vZGUgKm5wLCAqc2Vuc29yX25wOw0KPiA+ICsNCj4gPiArCW5wID0gb2ZfZmluZF9ub2Rl X2J5X25hbWUoTlVMTCwgInRoZXJtYWwtem9uZXMiKTsNCj4gPiArCWlmICghbnApDQo+ID4gKwkJ cmV0dXJuIC1FTk9ERVY7DQo+ID4gKw0KPiA+ICsJc2Vuc29yX25wID0gb2ZfZ2V0X25leHRfY2hp bGQobnAsIE5VTEwpOw0KPiA+ICsJcmV0ID0gb2ZfcGFyc2VfcGhhbmRsZV93aXRoX2FyZ3Moc2Vu c29yX25wLCAidGhlcm1hbC0NCj4gPiBzZW5zb3JzIiwNCj4gPiArCQkJIiN0aGVybWFsLXNlbnNv ci1jZWxscyIsDQo+ID4gKwkJCTAsICZzZW5zb3Jfc3BlY3MpOw0KPiA+ICsJaWYgKHJldCkgew0K PiA+ICsJCW9mX25vZGVfcHV0KG5wKTsNCj4gPiArCQlvZl9ub2RlX3B1dChzZW5zb3JfbnApOw0K PiA+ICsJCXJldHVybiByZXQ7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJaWYgKHNlbnNvcl9zcGVj cy5hcmdzX2NvdW50ID49IDEpIHsNCj4gPiArCQlpZCA9IHNlbnNvcl9zcGVjcy5hcmdzWzBdOw0K PiA+ICsJCVdBUk4oc2Vuc29yX3NwZWNzLmFyZ3NfY291bnQgPiAxLA0KPiA+ICsJCQkJIiVzOiB0 b28gbWFueSBjZWxscyBpbiBzZW5zb3INCj4gPiBzcGVjaWZpZXIgJWRcbiIsDQo+ID4gKwkJCQlz ZW5zb3Jfc3BlY3MubnAtPm5hbWUsDQo+ID4gc2Vuc29yX3NwZWNzLmFyZ3NfY291bnQpOw0KPiA+ ICsJfSBlbHNlIHsNCj4gPiArCQlpZCA9IDA7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJb2Zfbm9k ZV9wdXQobnApOw0KPiA+ICsJb2Zfbm9kZV9wdXQoc2Vuc29yX25wKTsNCj4gPiArDQo+ID4gKwly ZXR1cm4gaWQ7DQo+ID4gK30NCj4gPiArDQo+ID4gK3N0YXRpYyBpbnQgcW9yaXFfdG11X2NhbGli cmF0aW9uKHN0cnVjdCBwbGF0Zm9ybV9kZXZpY2UgKnBkZXYpDQo+ID4gK3sNCj4gPiArCWludCBp LCB2YWwsIGxlbjsNCj4gPiArCXUzMiByYW5nZVs0XTsNCj4gPiArCWNvbnN0IHUzMiAqY2FsaWJy YXRpb247DQo+ID4gKwlzdHJ1Y3QgZGV2aWNlX25vZGUgKm5wID0gcGRldi0+ZGV2Lm9mX25vZGU7 DQo+ID4gKwlzdHJ1Y3QgcW9yaXFfdG11X2RhdGEgKmRhdGEgPSBwbGF0Zm9ybV9nZXRfZHJ2ZGF0 YShwZGV2KTsNCj4gPiArDQo+ID4gKwlpZiAob2ZfcHJvcGVydHlfcmVhZF91MzJfYXJyYXkobnAs ICJmc2wsdG11LXJhbmdlIiwgcmFuZ2UsDQo+ID4gNCkpIHsNCj4gPiArCQlkZXZfZXJyKCZwZGV2 LT5kZXYsICJtaXNzaW5nIGNhbGlicmF0aW9uIHJhbmdlLlxuIik7DQo+ID4gKwkJcmV0dXJuIC1F Tk9ERVY7DQo+ID4gKwl9DQo+ID4gKw0KPiA+ICsJLyogSW5pdCB0ZW1wZXJhdHVyZSByYW5nZSBy ZWdpc3RlcnMgKi8NCj4gPiArCXRtdV93cml0ZShkYXRhLCByYW5nZVswXSwgJmRhdGEtPnJlZ3Mt PnR0cjBjcik7DQo+ID4gKwl0bXVfd3JpdGUoZGF0YSwgcmFuZ2VbMV0sICZkYXRhLT5yZWdzLT50 dHIxY3IpOw0KPiA+ICsJdG11X3dyaXRlKGRhdGEsIHJhbmdlWzJdLCAmZGF0YS0+cmVncy0+dHRy MmNyKTsNCj4gPiArCXRtdV93cml0ZShkYXRhLCByYW5nZVszXSwgJmRhdGEtPnJlZ3MtPnR0cjNj cik7DQo+ID4gKw0KPiA+ICsJY2FsaWJyYXRpb24gPSBvZl9nZXRfcHJvcGVydHkobnAsICJmc2ws dG11LWNhbGlicmF0aW9uIiwNCj4gPiAmbGVuKTsNCj4gPiArCWlmIChjYWxpYnJhdGlvbiA9PSBO VUxMIHx8IGxlbiAlIDgpIHsNCj4gPiArCQlkZXZfZXJyKCZwZGV2LT5kZXYsICJpbnZhbGlkIGNh bGlicmF0aW9uIGRhdGEuXG4iKTsNCj4gPiArCQlyZXR1cm4gLUVOT0RFVjsNCj4gPiArCX0NCj4g PiArDQo+ID4gKwlmb3IgKGkgPSAwOyBpIDwgbGVuOyBpICs9IDgsIGNhbGlicmF0aW9uICs9IDIp IHsNCj4gPiArCQl2YWwgPSBvZl9yZWFkX251bWJlcihjYWxpYnJhdGlvbiwgMSk7DQo+ID4gKwkJ dG11X3dyaXRlKGRhdGEsIHZhbCwgJmRhdGEtPnJlZ3MtPnR0Y2Zncik7DQo+ID4gKwkJdmFsID0g b2ZfcmVhZF9udW1iZXIoY2FsaWJyYXRpb24gKyAxLCAxKTsNCj4gPiArCQl0bXVfd3JpdGUoZGF0 YSwgdmFsLCAmZGF0YS0+cmVncy0+dHNjZmdyKTsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlyZXR1 cm4gMDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIHZvaWQgcW9yaXFfdG11X2luaXRfZGV2 aWNlKHN0cnVjdCBxb3JpcV90bXVfZGF0YSAqZGF0YSkNCj4gPiArew0KPiA+ICsJLyogRGlzYWJs ZSBpbnRlcnJ1cHQsIHVzaW5nIHBvbGxpbmcgaW5zdGVhZCAqLw0KPiA+ICsJdG11X3dyaXRlKGRh dGEsIFRJRVJfRElTQUJMRSwgJmRhdGEtPnJlZ3MtPnRpZXIpOw0KPiA+ICsNCj4gPiArCS8qIFNl dCB1cGRhdGVfaW50ZXJ2YWwgKi8NCj4gPiArCXRtdV93cml0ZShkYXRhLCBUTVRNSVJfREVGQVVM VCwgJmRhdGEtPnJlZ3MtPnRtdG1pcik7DQo+ID4gKw0KPiA+ICsJLyogRGlzYWJsZSBtb25pdG9y aW5nICovDQo+ID4gKwl0bXVfd3JpdGUoZGF0YSwgVE1SX0RJU0FCTEUsICZkYXRhLT5yZWdzLT50 bXIpOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgc3RydWN0IHRoZXJtYWxfem9uZV9vZl9k ZXZpY2Vfb3BzIHRtdV90el9vcHMgPSB7DQo+ID4gKwkuZ2V0X3RlbXAgPSB0bXVfZ2V0X3RlbXAs DQo+ID4gK307DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IHFvcmlxX3RtdV9wcm9iZShzdHJ1Y3Qg cGxhdGZvcm1fZGV2aWNlICpwZGV2KQ0KPiA+ICt7DQo+ID4gKwlpbnQgcmV0Ow0KPiA+ICsJY29u c3Qgc3RydWN0IHRoZXJtYWxfdHJpcCAqdHJpcDsNCj4gPiArCXN0cnVjdCBxb3JpcV90bXVfZGF0 YSAqZGF0YTsNCj4gPiArCXN0cnVjdCBkZXZpY2Vfbm9kZSAqbnAgPSBwZGV2LT5kZXYub2Zfbm9k ZTsNCj4gPiArCXUzMiBzaXRlID0gMDsNCj4gPiArDQo+ID4gKwlpZiAoIW5wKSB7DQo+ID4gKwkJ ZGV2X2VycigmcGRldi0+ZGV2LCAiRGV2aWNlIE9GLU5vZGUgaXMgTlVMTCIpOw0KPiA+ICsJCXJl dHVybiAtRU5PREVWOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCWRhdGEgPSBkZXZtX2t6YWxsb2Mo JnBkZXYtPmRldiwgc2l6ZW9mKHN0cnVjdA0KPiA+IHFvcmlxX3RtdV9kYXRhKSwNCj4gPiArCQkJ wqDCoMKgwqBHRlBfS0VSTkVMKTsNCj4gPiArCWlmICghZGF0YSkNCj4gPiArCQlyZXR1cm4gLUVO T01FTTsNCj4gPiArDQo+ID4gKwlwbGF0Zm9ybV9zZXRfZHJ2ZGF0YShwZGV2LCBkYXRhKTsNCj4g PiArDQo+ID4gKwlkYXRhLT5saXR0bGVfZW5kaWFuID0gb2ZfcHJvcGVydHlfcmVhZF9ib29sKG5w LCAibGl0dGxlLQ0KPiA+IGVuZGlhbiIpOw0KPiA+ICsNCj4gPiArCWRhdGEtPnNlbnNvcl9pZCA9 IHFvcmlxX3RtdV9nZXRfc2Vuc29yX2lkKCk7DQo+ID4gKwlpZiAoZGF0YS0+c2Vuc29yX2lkIDwg MCkgew0KPiA+ICsJCWRldl9lcnIoJnBkZXYtPmRldiwgIkZhaWxlZCB0byBnZXQgc2Vuc29yIGlk XG4iKTsNCj4gPiArCQlyZXQgPSAtRU5PREVWOw0KPiA+ICsJCWdvdG8gZXJyX2lvbWFwOw0KPiA+ ICsJfQ0KPiA+ICsNCj4gPiArCWRhdGEtPnJlZ3MgPSBvZl9pb21hcChucCwgMCk7DQo+ID4gKwlp ZiAoIWRhdGEtPnJlZ3MpIHsNCj4gPiArCQlkZXZfZXJyKCZwZGV2LT5kZXYsICJGYWlsZWQgdG8g Z2V0IG1lbW9yeQ0KPiA+IHJlZ2lvblxuIik7DQo+ID4gKwkJcmV0ID0gLUVOT0RFVjsNCj4gPiAr CQlnb3RvIGVycl9pb21hcDsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlxb3JpcV90bXVfaW5pdF9k ZXZpY2UoZGF0YSk7CS8qIFRNVSBpbml0aWFsaXphdGlvbiAqLw0KPiA+ICsNCj4gPiArCXJldCA9 IHFvcmlxX3RtdV9jYWxpYnJhdGlvbihwZGV2KTsJLyogVE1VIGNhbGlicmF0aW9uDQo+ID4gKi8N Cj4gPiArCWlmIChyZXQgPCAwKQ0KPiA+ICsJCWdvdG8gZXJyX3RtdTsNCj4gPiArDQo+ID4gKwlk YXRhLT50eiA9IHRoZXJtYWxfem9uZV9vZl9zZW5zb3JfcmVnaXN0ZXIoJnBkZXYtPmRldiwgZGF0 YS0NCj4gPiA+c2Vuc29yX2lkLA0KPiA+ICsJCQkJZGF0YSwgJnRtdV90el9vcHMpOw0KPiA+ICsJ aWYgKElTX0VSUihkYXRhLT50eikpIHsNCj4gPiArCQlyZXQgPSBQVFJfRVJSKGRhdGEtPnR6KTsN Cj4gPiArCQlkZXZfZXJyKCZwZGV2LT5kZXYsDQo+ID4gKwkJCSJGYWlsZWQgdG8gcmVnaXN0ZXIg dGhlcm1hbCB6b25lIGRldmljZQ0KPiA+ICVkXG4iLCByZXQpOw0KPiA+ICsJCWdvdG8gZXJyX3Rt dTsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwl0cmlwID0gb2ZfdGhlcm1hbF9nZXRfdHJpcF9wb2lu dHMoZGF0YS0+dHopOw0KPiA+ICsNCj4gPiArCS8qIEVuYWJsZSBtb25pdG9yaW5nICovDQo+ID4g KwlzaXRlIHw9IDB4MSA8PCAoMTUgLSBkYXRhLT5zZW5zb3JfaWQpOw0KPiA+ICsJdG11X3dyaXRl KGRhdGEsIHNpdGUgfCBUTVJfTUUgfCBUTVJfQUxQRiwgJmRhdGEtPnJlZ3MtPnRtcik7DQo+ID4g Kw0KPiA+ICsJcmV0dXJuIDA7DQo+ID4gKw0KPiA+ICtlcnJfdG11Og0KPiA+ICsJaW91bm1hcChk YXRhLT5yZWdzKTsNCj4gPiArDQo+ID4gK2Vycl9pb21hcDoNCj4gPiArCXBsYXRmb3JtX3NldF9k cnZkYXRhKHBkZXYsIE5VTEwpOw0KPiA+ICsNCj4gPiArCXJldHVybiByZXQ7DQo+ID4gK30NCj4g PiArDQo+ID4gK3N0YXRpYyBpbnQgcW9yaXFfdG11X3JlbW92ZShzdHJ1Y3QgcGxhdGZvcm1fZGV2 aWNlICpwZGV2KQ0KPiA+ICt7DQo+ID4gKwlzdHJ1Y3QgcW9yaXFfdG11X2RhdGEgKmRhdGEgPSBw bGF0Zm9ybV9nZXRfZHJ2ZGF0YShwZGV2KTsNCj4gPiArDQo+ID4gKwl0aGVybWFsX3pvbmVfb2Zf c2Vuc29yX3VucmVnaXN0ZXIoJnBkZXYtPmRldiwgZGF0YS0+dHopOw0KPiA+ICsNCj4gPiArCS8q IERpc2FibGUgbW9uaXRvcmluZyAqLw0KPiA+ICsJdG11X3dyaXRlKGRhdGEsIFRNUl9ESVNBQkxF LCAmZGF0YS0+cmVncy0+dG1yKTsNCj4gPiArDQo+ID4gKwlpb3VubWFwKGRhdGEtPnJlZ3MpOw0K PiA+ICsJcGxhdGZvcm1fc2V0X2RydmRhdGEocGRldiwgTlVMTCk7DQo+ID4gKw0KPiA+ICsJcmV0 dXJuIDA7DQo+ID4gK30NCj4gPiArDQo+ID4gKyNpZmRlZiBDT05GSUdfUE1fU0xFRVANCj4gPiAr c3RhdGljIGludCBxb3JpcV90bXVfc3VzcGVuZChzdHJ1Y3QgZGV2aWNlICpkZXYpDQo+ID4gK3sN Cj4gPiArCXUzMiB0bXI7DQo+ID4gKwlzdHJ1Y3QgcW9yaXFfdG11X2RhdGEgKmRhdGEgPSBkZXZf Z2V0X2RydmRhdGEoZGV2KTsNCj4gPiArDQo+ID4gKwkvKiBEaXNhYmxlIG1vbml0b3JpbmcgKi8N Cj4gPiArCXRtciA9IHRtdV9yZWFkKGRhdGEsICZkYXRhLT5yZWdzLT50bXIpOw0KPiA+ICsJdG1y ICY9IH5UTVJfTUU7DQo+ID4gKwl0bXVfd3JpdGUoZGF0YSwgdG1yLCAmZGF0YS0+cmVncy0+dG1y KTsNCj4gPiArDQo+ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsNCj4gPiArc3RhdGljIGlu dCBxb3JpcV90bXVfcmVzdW1lKHN0cnVjdCBkZXZpY2UgKmRldikNCj4gPiArew0KPiA+ICsJdTMy IHRtcjsNCj4gPiArCXN0cnVjdCBxb3JpcV90bXVfZGF0YSAqZGF0YSA9IGRldl9nZXRfZHJ2ZGF0 YShkZXYpOw0KPiA+ICsNCj4gPiArCS8qIEVuYWJsZSBtb25pdG9yaW5nICovDQo+ID4gKwl0bXIg PSB0bXVfcmVhZChkYXRhLCAmZGF0YS0+cmVncy0+dG1yKTsNCj4gPiArCXRtciB8PSBUTVJfTUU7 DQo+ID4gKwl0bXVfd3JpdGUoZGF0YSwgdG1yLCAmZGF0YS0+cmVncy0+dG1yKTsNCj4gPiArDQo+ ID4gKwlyZXR1cm4gMDsNCj4gPiArfQ0KPiA+ICsjZW5kaWYNCj4gPiArDQo+ID4gK3N0YXRpYyBT SU1QTEVfREVWX1BNX09QUyhxb3JpcV90bXVfcG1fb3BzLA0KPiA+ICsJCQnCoHFvcmlxX3RtdV9z dXNwZW5kLCBxb3JpcV90bXVfcmVzdW1lKTsNCj4gPiArDQo+ID4gK3N0YXRpYyBjb25zdCBzdHJ1 Y3Qgb2ZfZGV2aWNlX2lkIHFvcmlxX3RtdV9tYXRjaFtdID0gew0KPiA+ICsJeyAuY29tcGF0aWJs ZSA9ICJmc2wscW9yaXEtdG11IiwgfSwNCj4gPiArCXt9LA0KPiA+ICt9Ow0KPiA+ICtNT0RVTEVf REVWSUNFX1RBQkxFKG9mLCBxb3JpcV90bXVfbWF0Y2gpOw0KPiA+ICsNCj4gPiArc3RhdGljIHN0 cnVjdCBwbGF0Zm9ybV9kcml2ZXIgcW9yaXFfdG11ID0gew0KPiA+ICsJLmRyaXZlcgk9IHsNCj4g PiArCQkubmFtZQkJPSAicW9yaXFfdGhlcm1hbCIsDQo+ID4gKwkJLnBtCQk9ICZxb3JpcV90bXVf cG1fb3BzLA0KPiA+ICsJCS5vZl9tYXRjaF90YWJsZQk9IHFvcmlxX3RtdV9tYXRjaCwNCj4gPiAr CX0sDQo+ID4gKwkucHJvYmUJPSBxb3JpcV90bXVfcHJvYmUsDQo+ID4gKwkucmVtb3ZlCT0gcW9y aXFfdG11X3JlbW92ZSwNCj4gPiArfTsNCj4gPiArbW9kdWxlX3BsYXRmb3JtX2RyaXZlcihxb3Jp cV90bXUpOw0KPiA+ICsNCj4gPiArTU9EVUxFX0FVVEhPUigiSmlhIEhvbmd0YW8gPGhvbmd0YW8u amlhQG54cC5jb20+Iik7DQo+ID4gK01PRFVMRV9ERVNDUklQVElPTigiUW9ySVEgVGhlcm1hbCBN b25pdG9yaW5nIFVuaXQgZHJpdmVyIik7DQo+ID4gK01PRFVMRV9MSUNFTlNFKCJHUEwgdjIiKTsN Cj4gPiAtLQ0KPiA+IDIuMS4wLjI3Lmc5NmRiMzI0DQo+ID4NCg== ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH V2 7/7] thermal: qoriq: Add thermal management support @ 2016-09-08 7:11 ` Troy Jia 0 siblings, 0 replies; 18+ messages in thread From: Troy Jia @ 2016-09-08 7:11 UTC (permalink / raw) To: Zhang Rui, edubezval, robh+dt, galak, Scott Wood, shawnguo Cc: devicetree, linuxppc-dev, linux-kernel, linux-arm-kernel, linux-pm > -----Original Message----- > From: Zhang Rui [mailto:rui.zhang@intel.com] > Sent: Friday, August 19, 2016 8:40 PM > To: Hongtao Jia <hongtao.jia@nxp.com>; edubezval@gmail.com; > robh+dt@kernel.org; galak@codeaurora.org; Scott Wood > <scott.wood@nxp.com>; shawnguo@kernel.org > Cc: linux-pm@vger.kernel.org; devicetree@vger.kernel.org; linux- > kernel@vger.kernel.org; linuxppc-dev@lists.ozlabs.org; linux-arm- > kernel@lists.infradead.org > Subject: Re: [PATCH V2 7/7] thermal: qoriq: Add thermal management support > > On 四, 2016-06-30 at 11:08 +0800, Jia Hongtao wrote: > > This driver add thermal management support by enabling TMU (Thermal > > Monitoring Unit) on QorIQ platform. > > > > It's based on thermal of framework: > > - Trip points defined in device tree. > > - Cpufreq as cooling device registered in qoriq cpufreq driver. > > > > Signed-off-by: Jia Hongtao <hongtao.jia@nxp.com> > > The patch looks good to me. > I only need to take this patch, right? > > thanks, > rui Yes. You just need to take this patch. Sorry for the late response. I was on my long vacation back then. Thanks, Hongtao. > > --- > > Changes of V2: > > * Add HAS_IOMEM dependency to fix build error on UM > > > > drivers/thermal/Kconfig | 10 ++ > > drivers/thermal/Makefile | 1 + > > drivers/thermal/qoriq_thermal.c | 328 > > ++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 339 insertions(+) > > create mode 100644 drivers/thermal/qoriq_thermal.c > > > > diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig > > index 2d702ca..56ef30d 100644 > > --- a/drivers/thermal/Kconfig > > +++ b/drivers/thermal/Kconfig > > @@ -195,6 +195,16 @@ config IMX_THERMAL > > cpufreq is used as the cooling device to throttle CPUs > > when the > > passive trip is crossed. > > > > +config QORIQ_THERMAL > > + tristate "QorIQ Thermal Monitoring Unit" > > + depends on THERMAL_OF > > + depends on HAS_IOMEM > > + help > > + Support for Thermal Monitoring Unit (TMU) found on QorIQ > > platforms. > > + It supports one critical trip point and one passive trip > > point. The > > + cpufreq is used as the cooling device to throttle CPUs > > when the > > + passive trip is crossed. > > + > > config SPEAR_THERMAL > > tristate "SPEAr thermal sensor driver" > > depends on PLAT_SPEAR || COMPILE_TEST > > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile > > index 10b07c1..6662232 100644 > > --- a/drivers/thermal/Makefile > > +++ b/drivers/thermal/Makefile > > @@ -37,6 +37,7 @@ obj-$(CONFIG_DB8500_THERMAL) += > > db8500_thermal.o > > obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o > > obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o > > obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o > > +obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o > > obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += > > db8500_cpufreq_cooling.o > > obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o > > obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o > > diff --git a/drivers/thermal/qoriq_thermal.c > > b/drivers/thermal/qoriq_thermal.c > > new file mode 100644 > > index 0000000..644ba52 > > --- /dev/null > > +++ b/drivers/thermal/qoriq_thermal.c > > @@ -0,0 +1,328 @@ > > +/* > > + * Copyright 2016 Freescale Semiconductor, Inc. > > + * > > + * This program is free software; you can redistribute it and/or > > modify it > > + * under the terms and conditions of the GNU General Public License, > > + * version 2, as published by the Free Software Foundation. > > + * > > + * This program is distributed in the hope it will be useful, but > > WITHOUT > > + * ANY WARRANTY; without even the implied warranty of > > MERCHANTABILITY or > > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public > > License for > > + * more details. > > + * > > + */ > > + > > +#include <linux/module.h> > > +#include <linux/platform_device.h> > > +#include <linux/err.h> > > +#include <linux/io.h> > > +#include <linux/of.h> > > +#include <linux/of_address.h> > > +#include <linux/thermal.h> > > + > > +#include "thermal_core.h" > > + > > +#define SITES_MAX 16 > > + > > +/* > > + * QorIQ TMU Registers > > + */ > > +struct qoriq_tmu_site_regs { > > + u32 tritsr; /* Immediate Temperature Site > > Register */ > > + u32 tratsr; /* Average Temperature Site > > Register */ > > + u8 res0[0x8]; > > +}; > > + > > +struct qoriq_tmu_regs { > > + u32 tmr; /* Mode Register */ > > +#define TMR_DISABLE 0x0 > > +#define TMR_ME 0x80000000 > > +#define TMR_ALPF 0x0c000000 > > + u32 tsr; /* Status Register */ > > + u32 tmtmir; /* Temperature measurement > > interval Register */ > > +#define TMTMIR_DEFAULT 0x0000000f > > + u8 res0[0x14]; > > + u32 tier; /* Interrupt Enable Register */ > > +#define TIER_DISABLE 0x0 > > + 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 qoriq_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 */ > > +}; > > + > > +/* > > + * Thermal zone data > > + */ > > +struct qoriq_tmu_data { > > + struct thermal_zone_device *tz; > > + struct qoriq_tmu_regs __iomem *regs; > > + int sensor_id; > > + bool little_endian; > > +}; > > + > > +static void tmu_write(struct qoriq_tmu_data *p, u32 val, void > > __iomem *addr) > > +{ > > + if (p->little_endian) > > + iowrite32(val, addr); > > + else > > + iowrite32be(val, addr); > > +} > > + > > +static u32 tmu_read(struct qoriq_tmu_data *p, void __iomem *addr) > > +{ > > + if (p->little_endian) > > + return ioread32(addr); > > + else > > + return ioread32be(addr); > > +} > > + > > +static int tmu_get_temp(void *p, int *temp) > > +{ > > + u32 val; > > + struct qoriq_tmu_data *data = p; > > + > > + val = tmu_read(data, &data->regs->site[data- > > >sensor_id].tritsr); > > + *temp = (val & 0xff) * 1000; > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_get_sensor_id(void) > > +{ > > + int ret, id; > > + struct of_phandle_args sensor_specs; > > + struct device_node *np, *sensor_np; > > + > > + np = of_find_node_by_name(NULL, "thermal-zones"); > > + if (!np) > > + return -ENODEV; > > + > > + sensor_np = of_get_next_child(np, NULL); > > + ret = of_parse_phandle_with_args(sensor_np, "thermal- > > sensors", > > + "#thermal-sensor-cells", > > + 0, &sensor_specs); > > + if (ret) { > > + of_node_put(np); > > + of_node_put(sensor_np); > > + return ret; > > + } > > + > > + if (sensor_specs.args_count >= 1) { > > + id = sensor_specs.args[0]; > > + WARN(sensor_specs.args_count > 1, > > + "%s: too many cells in sensor > > specifier %d\n", > > + sensor_specs.np->name, > > sensor_specs.args_count); > > + } else { > > + id = 0; > > + } > > + > > + of_node_put(np); > > + of_node_put(sensor_np); > > + > > + return id; > > +} > > + > > +static int qoriq_tmu_calibration(struct platform_device *pdev) > > +{ > > + int i, val, len; > > + u32 range[4]; > > + const u32 *calibration; > > + struct device_node *np = pdev->dev.of_node; > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + if (of_property_read_u32_array(np, "fsl,tmu-range", range, > > 4)) { > > + dev_err(&pdev->dev, "missing calibration range.\n"); > > + return -ENODEV; > > + } > > + > > + /* Init temperature range registers */ > > + tmu_write(data, range[0], &data->regs->ttr0cr); > > + tmu_write(data, range[1], &data->regs->ttr1cr); > > + tmu_write(data, range[2], &data->regs->ttr2cr); > > + tmu_write(data, range[3], &data->regs->ttr3cr); > > + > > + calibration = of_get_property(np, "fsl,tmu-calibration", > > &len); > > + if (calibration == NULL || len % 8) { > > + dev_err(&pdev->dev, "invalid calibration data.\n"); > > + return -ENODEV; > > + } > > + > > + for (i = 0; i < len; i += 8, calibration += 2) { > > + val = of_read_number(calibration, 1); > > + tmu_write(data, val, &data->regs->ttcfgr); > > + val = of_read_number(calibration + 1, 1); > > + tmu_write(data, val, &data->regs->tscfgr); > > + } > > + > > + return 0; > > +} > > + > > +static void qoriq_tmu_init_device(struct qoriq_tmu_data *data) > > +{ > > + /* Disable interrupt, using polling instead */ > > + tmu_write(data, TIER_DISABLE, &data->regs->tier); > > + > > + /* Set update_interval */ > > + tmu_write(data, TMTMIR_DEFAULT, &data->regs->tmtmir); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > > +} > > + > > +static struct thermal_zone_of_device_ops tmu_tz_ops = { > > + .get_temp = tmu_get_temp, > > +}; > > + > > +static int qoriq_tmu_probe(struct platform_device *pdev) > > +{ > > + int ret; > > + const struct thermal_trip *trip; > > + struct qoriq_tmu_data *data; > > + struct device_node *np = pdev->dev.of_node; > > + u32 site = 0; > > + > > + if (!np) { > > + dev_err(&pdev->dev, "Device OF-Node is NULL"); > > + return -ENODEV; > > + } > > + > > + data = devm_kzalloc(&pdev->dev, sizeof(struct > > qoriq_tmu_data), > > + GFP_KERNEL); > > + if (!data) > > + return -ENOMEM; > > + > > + platform_set_drvdata(pdev, data); > > + > > + data->little_endian = of_property_read_bool(np, "little- > > endian"); > > + > > + data->sensor_id = qoriq_tmu_get_sensor_id(); > > + if (data->sensor_id < 0) { > > + dev_err(&pdev->dev, "Failed to get sensor id\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + data->regs = of_iomap(np, 0); > > + if (!data->regs) { > > + dev_err(&pdev->dev, "Failed to get memory > > region\n"); > > + ret = -ENODEV; > > + goto err_iomap; > > + } > > + > > + qoriq_tmu_init_device(data); /* TMU initialization */ > > + > > + ret = qoriq_tmu_calibration(pdev); /* TMU calibration > > */ > > + if (ret < 0) > > + goto err_tmu; > > + > > + data->tz = thermal_zone_of_sensor_register(&pdev->dev, data- > > >sensor_id, > > + data, &tmu_tz_ops); > > + if (IS_ERR(data->tz)) { > > + ret = PTR_ERR(data->tz); > > + dev_err(&pdev->dev, > > + "Failed to register thermal zone device > > %d\n", ret); > > + goto err_tmu; > > + } > > + > > + trip = of_thermal_get_trip_points(data->tz); > > + > > + /* Enable monitoring */ > > + site |= 0x1 << (15 - data->sensor_id); > > + tmu_write(data, site | TMR_ME | TMR_ALPF, &data->regs->tmr); > > + > > + return 0; > > + > > +err_tmu: > > + iounmap(data->regs); > > + > > +err_iomap: > > + platform_set_drvdata(pdev, NULL); > > + > > + return ret; > > +} > > + > > +static int qoriq_tmu_remove(struct platform_device *pdev) > > +{ > > + struct qoriq_tmu_data *data = platform_get_drvdata(pdev); > > + > > + thermal_zone_of_sensor_unregister(&pdev->dev, data->tz); > > + > > + /* Disable monitoring */ > > + tmu_write(data, TMR_DISABLE, &data->regs->tmr); > > + > > + iounmap(data->regs); > > + platform_set_drvdata(pdev, NULL); > > + > > + return 0; > > +} > > + > > +#ifdef CONFIG_PM_SLEEP > > +static int qoriq_tmu_suspend(struct device *dev) > > +{ > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Disable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr &= ~TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > + > > +static int qoriq_tmu_resume(struct device *dev) > > +{ > > + u32 tmr; > > + struct qoriq_tmu_data *data = dev_get_drvdata(dev); > > + > > + /* Enable monitoring */ > > + tmr = tmu_read(data, &data->regs->tmr); > > + tmr |= TMR_ME; > > + tmu_write(data, tmr, &data->regs->tmr); > > + > > + return 0; > > +} > > +#endif > > + > > +static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, > > + qoriq_tmu_suspend, qoriq_tmu_resume); > > + > > +static const struct of_device_id qoriq_tmu_match[] = { > > + { .compatible = "fsl,qoriq-tmu", }, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, qoriq_tmu_match); > > + > > +static struct platform_driver qoriq_tmu = { > > + .driver = { > > + .name = "qoriq_thermal", > > + .pm = &qoriq_tmu_pm_ops, > > + .of_match_table = qoriq_tmu_match, > > + }, > > + .probe = qoriq_tmu_probe, > > + .remove = qoriq_tmu_remove, > > +}; > > +module_platform_driver(qoriq_tmu); > > + > > +MODULE_AUTHOR("Jia Hongtao <hongtao.jia@nxp.com>"); > > +MODULE_DESCRIPTION("QorIQ Thermal Monitoring Unit driver"); > > +MODULE_LICENSE("GPL v2"); > > -- > > 2.1.0.27.g96db324 > > _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2016-09-08 7:27 UTC | newest] Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-06-30 3:08 [PATCH V2 7/7] thermal: qoriq: Add thermal management support Jia Hongtao 2016-06-30 3:08 ` Jia Hongtao 2016-06-30 3:08 ` Jia Hongtao 2016-07-19 6:54 ` Hongtao Jia 2016-07-19 6:54 ` Hongtao Jia 2016-07-19 6:54 ` Hongtao Jia 2016-07-19 6:54 ` Hongtao Jia 2016-08-05 6:26 ` Hongtao Jia 2016-08-05 6:26 ` Hongtao Jia 2016-08-05 6:26 ` Hongtao Jia 2016-08-05 6:26 ` Hongtao Jia 2016-08-19 12:39 ` Zhang Rui 2016-08-19 12:39 ` Zhang Rui 2016-08-19 12:39 ` Zhang Rui 2016-09-08 7:11 ` Troy Jia 2016-09-08 7:11 ` Troy Jia 2016-09-08 7:11 ` Troy Jia 2016-09-08 7:11 ` Troy Jia
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.