From d1f6bd47f0927b7ce73b86d3bf74fd92102dd515 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sun, 28 Jan 2024 03:46:58 +0000 Subject: [PATCH] mediatek: backport a hell of thermal commits Backport almost 50 commits from upstream Linux to improve thermal drivers for MediaTek SoCs and add new LVTS driver for MT7988. Signed-off-by: Daniel Golle --- ...mtk_thermal-Fix-kernel-doc-function-.patch | 37 + ...mtk_thermal-Use-devm_platform_get_an.patch | 37 + ...tk-Use-function-pointer-for-raw_to_.patch} | 12 +- ...tk-Add-support-for-MT7986-and-MT798.patch} | 32 +- ...mediatek-Relocate-driver-to-mediatek.patch | 2602 +++++++++++++++++ ...mediatek-Add-the-Low-Voltage-Thermal.patch | 1298 ++++++++ ...mal-mediatek-Add-LVTS-thermal-contro.patch | 186 ++ ...mal-mediatek-Add-AP-domain-to-LVTS-t.patch | 35 + ...-Add-a-thermal-zone-devdata-accessor.patch | 65 + ...-thermal_zone_device-structure-type-.patch | 55 + ...-the-thermal-zone-devdata-accessor-i.patch | 74 + ...e-the-right-device-for-devm_thermal_.patch | 201 ++ ...e-device-internal-thermal-zone-struc.patch | 79 + ...se-thermal_zone_device_type-accessor.patch | 62 + ...mediatek-Control-buffer-enablement-t.patch | 81 + ...-mediatek-Add-support-for-MT8365-SoC.patch | 123 + ...mediatek-Add-delay-after-thermal-ban.patch | 50 + ...mediatek-lvts_thermal-Fix-sensor-1-i.patch | 46 + ...mediatek-lvts_thermal-Add-AP-domain-.patch | 149 + ...rivers-mediatek-Add-delay-after-ther.patch | 53 + ...mediatek-Add-temperature-constraints.patch | 78 + ...mediatek-Use-devm_of_iomap-to-avoid-.patch | 53 + ...mediatek-Change-clk_prepare_enable-t.patch | 100 + ...-mediatek-Use-of_address_to_resource.patch | 36 + ...rivers-mediatek-Use-devm_of_iomap-to.patch | 57 + ...mediatek-lvts_thermal-Register-therm.patch | 37 + ...mediatek-lvts_thermal-Remove-redunda.patch | 28 + ...mediatek-lvts_thermal-Handle-IRQ-on-.patch | 40 + ...mediatek-lvts_thermal-Honor-sensors-.patch | 120 + ...mediatek-lvts_thermal-Use-offset-thr.patch | 77 + ...mediatek-lvts_thermal-Disable-undesi.patch | 51 + ...mediatek-lvts_thermal-Don-t-leave-th.patch | 70 + ...mediatek-lvts_thermal-Manage-thresho.patch | 156 + ...mediatek-lvts-Fix-parameter-check-in.patch | 29 + ...mediatek-Clean-up-redundant-dev_err_.patch | 33 + ...mediatek-lvts_thermal-Make-readings-.patch | 95 + ...mediatek-auxadc_thermal-Removed-call.patch | 30 + ...vert-to-platform-remove-callback-ret.patch | 58 + ...mediatek-lvts_thermal-Make-coeff-con.patch | 198 ++ ...mal-mediatek-Add-LVTS-thermal-sensor.patch | 35 + ...mediatek-lvts_thermal-Add-mt7988-sup.patch | 91 + ...mediatek-lvts_thermal-Fix-error-chec.patch | 30 + ...rs-mediatek-Fix-probe-for-THERMAL_V2.patch | 33 + ...mediatek-lvts_thermal-Add-suspend-an.patch | 83 + ...mal-mediatek-Add-LVTS-thermal-contro.patch | 49 + ...mediatek-lvts_thermal-Add-mt8192-sup.patch | 151 + ...mediatek-lvts_thermal-Update-calibra.patch | 70 + ...-control-buffer-enablement-on-MT7896.patch | 59 + 48 files changed, 7202 insertions(+), 22 deletions(-) create mode 100644 target/linux/mediatek/patches-6.1/830-v6.3-01-thermal-drivers-mtk_thermal-Fix-kernel-doc-function-.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.3-02-thermal-drivers-mtk_thermal-Use-devm_platform_get_an.patch rename target/linux/mediatek/patches-6.1/{805-v6.2-thermal-drivers-mtk-use-function-pointer-for-raw_to_.patch => 830-v6.3-03-thermal-drivers-mtk-Use-function-pointer-for-raw_to_.patch} (75%) rename target/linux/mediatek/patches-6.1/{806-v6.2-thermal-mediatek-add-support-for-MT7986-and-MT7981.patch => 830-v6.3-04-thermal-drivers-mtk-Add-support-for-MT7986-and-MT798.patch} (89%) create mode 100644 target/linux/mediatek/patches-6.1/830-v6.3-05-thermal-drivers-mediatek-Relocate-driver-to-mediatek.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.3-06-thermal-drivers-mediatek-Add-the-Low-Voltage-Thermal.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-07-dt-bindings-thermal-mediatek-Add-LVTS-thermal-contro.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-08-dt-bindings-thermal-mediatek-Add-AP-domain-to-LVTS-t.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-09-thermal-core-Add-a-thermal-zone-devdata-accessor.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-10-thermal-core-Add-thermal_zone_device-structure-type-.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-11-thermal-core-Use-the-thermal-zone-devdata-accessor-i.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-12-thermal-hwmon-Use-the-right-device-for-devm_thermal_.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-13-thermal-Don-t-use-device-internal-thermal-zone-struc.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-14-thermal-Use-thermal_zone_device_type-accessor.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-15-thermal-drivers-mediatek-Control-buffer-enablement-t.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-16-thermal-drivers-mediatek-Add-support-for-MT8365-SoC.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-17-thermal-drivers-mediatek-Add-delay-after-thermal-ban.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-18-thermal-drivers-mediatek-lvts_thermal-Fix-sensor-1-i.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-19-thermal-drivers-mediatek-lvts_thermal-Add-AP-domain-.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-20-Revert-thermal-drivers-mediatek-Add-delay-after-ther.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-21-thermal-drivers-mediatek-Add-temperature-constraints.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-22-thermal-drivers-mediatek-Use-devm_of_iomap-to-avoid-.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-23-thermal-drivers-mediatek-Change-clk_prepare_enable-t.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-24-thermal-drivers-mediatek-Use-of_address_to_resource.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-25-Revert-thermal-drivers-mediatek-Use-devm_of_iomap-to.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-26-thermal-drivers-mediatek-lvts_thermal-Register-therm.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-27-thermal-drivers-mediatek-lvts_thermal-Remove-redunda.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-29-thermal-drivers-mediatek-lvts_thermal-Handle-IRQ-on-.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-30-thermal-drivers-mediatek-lvts_thermal-Honor-sensors-.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-31-thermal-drivers-mediatek-lvts_thermal-Use-offset-thr.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-32-thermal-drivers-mediatek-lvts_thermal-Disable-undesi.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-33-thermal-drivers-mediatek-lvts_thermal-Don-t-leave-th.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-34-thermal-drivers-mediatek-lvts_thermal-Manage-thresho.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-35-thermal-drivers-mediatek-lvts-Fix-parameter-check-in.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-36-thermal-drivers-mediatek-Clean-up-redundant-dev_err_.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-37-thermal-drivers-mediatek-lvts_thermal-Make-readings-.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-38-thermal-drivers-mediatek-auxadc_thermal-Removed-call.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-39-thermal-lvts-Convert-to-platform-remove-callback-ret.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-40-thermal-drivers-mediatek-lvts_thermal-Make-coeff-con.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-41-dt-bindings-thermal-mediatek-Add-LVTS-thermal-sensor.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-42-thermal-drivers-mediatek-lvts_thermal-Add-mt7988-sup.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-43-thermal-drivers-mediatek-lvts_thermal-Fix-error-chec.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-44-thermal-drivers-mediatek-Fix-probe-for-THERMAL_V2.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.4-45-thermal-drivers-mediatek-lvts_thermal-Add-suspend-an.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.7-46-dt-bindings-thermal-mediatek-Add-LVTS-thermal-contro.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.7-47-thermal-drivers-mediatek-lvts_thermal-Add-mt8192-sup.patch create mode 100644 target/linux/mediatek/patches-6.1/830-v6.7-48-thermal-drivers-mediatek-lvts_thermal-Update-calibra.patch create mode 100644 target/linux/mediatek/patches-6.1/831-thermal-drivers-mediatek-Fix-control-buffer-enablement-on-MT7896.patch diff --git a/target/linux/mediatek/patches-6.1/830-v6.3-01-thermal-drivers-mtk_thermal-Fix-kernel-doc-function-.patch b/target/linux/mediatek/patches-6.1/830-v6.3-01-thermal-drivers-mtk_thermal-Fix-kernel-doc-function-.patch new file mode 100644 index 00000000000..694b73a2b1c --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.3-01-thermal-drivers-mtk_thermal-Fix-kernel-doc-function-.patch @@ -0,0 +1,37 @@ +From f167da186acf90847e1a6d3716e253825a6218ec Mon Sep 17 00:00:00 2001 +From: Randy Dunlap +Date: Thu, 12 Jan 2023 22:44:49 -0800 +Subject: [PATCH 01/42] thermal/drivers/mtk_thermal: Fix kernel-doc function + name + +Use the correct function name in a kernel-doc comment to prevent +a warning: + +drivers/thermal/mtk_thermal.c:562: warning: expecting prototype for raw_to_mcelsius(). Prototype was for raw_to_mcelsius_v1() instead + +Signed-off-by: Randy Dunlap +Cc: "Rafael J. Wysocki" +Cc: Daniel Lezcano +Cc: Amit Kucheria +Cc: Zhang Rui +Cc: Matthias Brugger +Cc: linux-pm@vger.kernel.org +Cc: linux-arm-kernel@lists.infradead.org +Cc: linux-mediatek@lists.infradead.org +Link: https://lore.kernel.org/r/20230113064449.15061-1-rdunlap@infradead.org +Signed-off-by: Daniel Lezcano +--- + drivers/thermal/mtk_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/thermal/mtk_thermal.c ++++ b/drivers/thermal/mtk_thermal.c +@@ -550,7 +550,7 @@ static const struct mtk_thermal_data mt8 + }; + + /** +- * raw_to_mcelsius - convert a raw ADC value to mcelsius ++ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius + * @mt: The thermal controller + * @sensno: sensor number + * @raw: raw ADC value diff --git a/target/linux/mediatek/patches-6.1/830-v6.3-02-thermal-drivers-mtk_thermal-Use-devm_platform_get_an.patch b/target/linux/mediatek/patches-6.1/830-v6.3-02-thermal-drivers-mtk_thermal-Use-devm_platform_get_an.patch new file mode 100644 index 00000000000..aaed9d7e90c --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.3-02-thermal-drivers-mtk_thermal-Use-devm_platform_get_an.patch @@ -0,0 +1,37 @@ +From 255509232417ee71fd606cb957d44cf6544f0c43 Mon Sep 17 00:00:00 2001 +From: ye xingchen +Date: Wed, 18 Jan 2023 16:37:47 +0800 +Subject: [PATCH 02/42] thermal/drivers/mtk_thermal: Use + devm_platform_get_and_ioremap_resource() + +Convert platform_get_resource(), devm_ioremap_resource() to a single +call to devm_platform_get_and_ioremap_resource(), as this is exactly +what this function does. + +Signed-off-by: ye xingchen +Link: https://lore.kernel.org/r/202301181637472073620@zte.com.cn +Signed-off-by: Daniel Lezcano +--- + drivers/thermal/mtk_thermal.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +--- a/drivers/thermal/mtk_thermal.c ++++ b/drivers/thermal/mtk_thermal.c +@@ -990,7 +990,6 @@ static int mtk_thermal_probe(struct plat + int ret, i, ctrl_id; + struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node; + struct mtk_thermal *mt; +- struct resource *res; + u64 auxadc_phys_base, apmixed_phys_base; + struct thermal_zone_device *tzdev; + void __iomem *apmixed_base, *auxadc_base; +@@ -1009,8 +1008,7 @@ static int mtk_thermal_probe(struct plat + if (IS_ERR(mt->clk_auxadc)) + return PTR_ERR(mt->clk_auxadc); + +- res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- mt->thermal_base = devm_ioremap_resource(&pdev->dev, res); ++ mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(mt->thermal_base)) + return PTR_ERR(mt->thermal_base); + diff --git a/target/linux/mediatek/patches-6.1/805-v6.2-thermal-drivers-mtk-use-function-pointer-for-raw_to_.patch b/target/linux/mediatek/patches-6.1/830-v6.3-03-thermal-drivers-mtk-Use-function-pointer-for-raw_to_.patch similarity index 75% rename from target/linux/mediatek/patches-6.1/805-v6.2-thermal-drivers-mtk-use-function-pointer-for-raw_to_.patch rename to target/linux/mediatek/patches-6.1/830-v6.3-03-thermal-drivers-mtk-Use-function-pointer-for-raw_to_.patch index c58ae96403a..215b0fd7dec 100644 --- a/target/linux/mediatek/patches-6.1/805-v6.2-thermal-drivers-mtk-use-function-pointer-for-raw_to_.patch +++ b/target/linux/mediatek/patches-6.1/830-v6.3-03-thermal-drivers-mtk-Use-function-pointer-for-raw_to_.patch @@ -1,7 +1,7 @@ -From 69c17529e8418da3eec703dde31e1b01e5b0f7e8 Mon Sep 17 00:00:00 2001 +From ca86dbd309ba03bef38ae91f037e2030bb671ab7 Mon Sep 17 00:00:00 2001 From: Daniel Golle -Date: Wed, 18 Jan 2023 02:48:41 +0000 -Subject: [PATCH 1/2] thermal/drivers/mtk: use function pointer for +Date: Wed, 18 Jan 2023 15:40:39 +0000 +Subject: [PATCH 03/42] thermal/drivers/mtk: Use function pointer for raw_to_mcelsius Instead of having if-else logic selecting either raw_to_mcelsius_v1 or @@ -9,7 +9,11 @@ raw_to_mcelsius_v2 in mtk_thermal_bank_temperature introduce a function pointer raw_to_mcelsius to struct mtk_thermal which is initialized in the probe function. +Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Daniel Golle +Reviewed-by: Matthias Brugger +Link: https://lore.kernel.org/r/69c17529e8418da3eec703dde31e1b01e5b0f7e8.1674055882.git.daniel@makrotopia.org +Signed-off-by: Daniel Lezcano --- drivers/thermal/mtk_thermal.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) @@ -42,7 +46,7 @@ Signed-off-by: Daniel Golle /* * The first read of a sensor often contains very high bogus -@@ -1075,6 +1073,11 @@ static int mtk_thermal_probe(struct plat +@@ -1073,6 +1071,11 @@ static int mtk_thermal_probe(struct plat mtk_thermal_release_periodic_ts(mt, auxadc_base); } diff --git a/target/linux/mediatek/patches-6.1/806-v6.2-thermal-mediatek-add-support-for-MT7986-and-MT7981.patch b/target/linux/mediatek/patches-6.1/830-v6.3-04-thermal-drivers-mtk-Add-support-for-MT7986-and-MT798.patch similarity index 89% rename from target/linux/mediatek/patches-6.1/806-v6.2-thermal-mediatek-add-support-for-MT7986-and-MT7981.patch rename to target/linux/mediatek/patches-6.1/830-v6.3-04-thermal-drivers-mtk-Add-support-for-MT7986-and-MT798.patch index 65311d5718d..ef2006775a3 100644 --- a/target/linux/mediatek/patches-6.1/806-v6.2-thermal-mediatek-add-support-for-MT7986-and-MT7981.patch +++ b/target/linux/mediatek/patches-6.1/830-v6.3-04-thermal-drivers-mtk-Add-support-for-MT7986-and-MT798.patch @@ -1,7 +1,7 @@ -From aa957c759b1182aee00cc35178667f849f941b42 Mon Sep 17 00:00:00 2001 +From aec1d89dccc7cba04fdb3e52dfda328f3302ba17 Mon Sep 17 00:00:00 2001 From: Daniel Golle -Date: Wed, 30 Nov 2022 13:19:39 +0000 -Subject: [PATCH 2/2] thermal: mediatek: add support for MT7986 and MT7981 +Date: Wed, 18 Jan 2023 15:40:58 +0000 +Subject: [PATCH 04/42] thermal/drivers/mtk: Add support for MT7986 and MT7981 Add support for V3 generation thermal found in MT7986 and MT7981 SoCs. Brings code to assign values from efuse as well as new function to @@ -9,10 +9,14 @@ convert raw temperature to millidegree celsius, as found in MediaTek's SDK sources (but cleaned up and de-duplicated) [1]: https://git01.mediatek.com/plugins/gitiles/openwrt/feeds/mtk-openwrt-feeds/+/baf36c7eef477aae1f8f2653b6c29e2caf48475b + Signed-off-by: Daniel Golle +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/2d341fc45266217249586eb4bd3be3ac4ca83a12.1674055882.git.daniel@makrotopia.org +Signed-off-by: Daniel Lezcano --- - drivers/thermal/mtk_thermal.c | 137 ++++++++++++++++++++++++++++++++-- - 1 file changed, 132 insertions(+), 5 deletions(-) + drivers/thermal/mtk_thermal.c | 128 ++++++++++++++++++++++++++++++++-- + 1 file changed, 124 insertions(+), 4 deletions(-) --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c @@ -117,7 +121,7 @@ Signed-off-by: Daniel Golle +}; + /** - * raw_to_mcelsius - convert a raw ADC value to mcelsius + * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius * @mt: The thermal controller @@ -605,6 +673,22 @@ static int raw_to_mcelsius_v2(struct mtk return (format_2 - tmp) * 100; @@ -210,7 +214,7 @@ Signed-off-by: Daniel Golle .compatible = "mediatek,mt8183-thermal", .data = (void *)&mt8183_thermal_data, }, { -@@ -1068,15 +1186,24 @@ static int mtk_thermal_probe(struct plat +@@ -1066,15 +1184,17 @@ static int mtk_thermal_probe(struct plat goto err_disable_clk_auxadc; } @@ -220,21 +224,13 @@ Signed-off-by: Daniel Golle mtk_thermal_release_periodic_ts(mt, auxadc_base); } -- if (mt->conf->version == MTK_THERMAL_V1) -+ switch (mt->conf->version) { -+ case MTK_THERMAL_V1: + if (mt->conf->version == MTK_THERMAL_V1) mt->raw_to_mcelsius = raw_to_mcelsius_v1; - else -+ break; -+ case MTK_THERMAL_V2: ++ else if (mt->conf->version == MTK_THERMAL_V2) mt->raw_to_mcelsius = raw_to_mcelsius_v2; -+ break; -+ case MTK_THERMAL_V3: ++ else + mt->raw_to_mcelsius = raw_to_mcelsius_v3; -+ break; -+ default: -+ break; -+ } for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++) for (i = 0; i < mt->conf->num_banks; i++) diff --git a/target/linux/mediatek/patches-6.1/830-v6.3-05-thermal-drivers-mediatek-Relocate-driver-to-mediatek.patch b/target/linux/mediatek/patches-6.1/830-v6.3-05-thermal-drivers-mediatek-Relocate-driver-to-mediatek.patch new file mode 100644 index 00000000000..e102a338cdc --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.3-05-thermal-drivers-mediatek-Relocate-driver-to-mediatek.patch @@ -0,0 +1,2602 @@ +From 5e3aac197a74914ccec2732a89c29d960730d28f Mon Sep 17 00:00:00 2001 +From: Balsam CHIHI +Date: Thu, 9 Feb 2023 11:56:23 +0100 +Subject: [PATCH 05/42] thermal/drivers/mediatek: Relocate driver to mediatek + folder + +Add MediaTek proprietary folder to upstream more thermal zone and cooler +drivers, relocate the original thermal controller driver to it, and rename it +as "auxadc_thermal.c" to show its purpose more clearly. + +Signed-off-by: Balsam CHIHI +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20230209105628.50294-2-bchihi@baylibre.com +Signed-off-by: Daniel Lezcano +Signed-off-by: Rafael J. Wysocki +--- + drivers/thermal/Kconfig | 14 ++++--------- + drivers/thermal/Makefile | 2 +- + drivers/thermal/mediatek/Kconfig | 21 +++++++++++++++++++ + drivers/thermal/mediatek/Makefile | 1 + + .../auxadc_thermal.c} | 2 +- + 5 files changed, 28 insertions(+), 12 deletions(-) + create mode 100644 drivers/thermal/mediatek/Kconfig + create mode 100644 drivers/thermal/mediatek/Makefile + rename drivers/thermal/{mtk_thermal.c => mediatek/auxadc_thermal.c} (99%) + +--- a/drivers/thermal/Kconfig ++++ b/drivers/thermal/Kconfig +@@ -412,16 +412,10 @@ config DA9062_THERMAL + zone. + Compatible with the DA9062 and DA9061 PMICs. + +-config MTK_THERMAL +- tristate "Temperature sensor driver for mediatek SoCs" +- depends on ARCH_MEDIATEK || COMPILE_TEST +- depends on HAS_IOMEM +- depends on NVMEM || NVMEM=n +- depends on RESET_CONTROLLER +- default y +- help +- Enable this option if you want to have support for thermal management +- controller present in Mediatek SoCs ++menu "Mediatek thermal drivers" ++depends on ARCH_MEDIATEK || COMPILE_TEST ++source "drivers/thermal/mediatek/Kconfig" ++endmenu + + config AMLOGIC_THERMAL + tristate "Amlogic Thermal Support" +--- a/drivers/thermal/Makefile ++++ b/drivers/thermal/Makefile +@@ -55,7 +55,7 @@ obj-y += st/ + obj-y += qcom/ + obj-y += tegra/ + obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o +-obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o ++obj-y += mediatek/ + obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o + obj-$(CONFIG_UNIPHIER_THERMAL) += uniphier_thermal.o + obj-$(CONFIG_AMLOGIC_THERMAL) += amlogic_thermal.o +--- /dev/null ++++ b/drivers/thermal/mediatek/Kconfig +@@ -0,0 +1,21 @@ ++config MTK_THERMAL ++ tristate "MediaTek thermal drivers" ++ depends on THERMAL_OF ++ help ++ This is the option for MediaTek thermal software solutions. ++ Please enable corresponding options to get temperature ++ information from thermal sensors or turn on throttle ++ mechaisms for thermal mitigation. ++ ++if MTK_THERMAL ++ ++config MTK_SOC_THERMAL ++ tristate "AUXADC temperature sensor driver for MediaTek SoCs" ++ depends on HAS_IOMEM ++ help ++ Enable this option if you want to get SoC temperature ++ information for MediaTek platforms. ++ This driver configures thermal controllers to collect ++ temperature via AUXADC interface. ++ ++endif +--- /dev/null ++++ b/drivers/thermal/mediatek/Makefile +@@ -0,0 +1 @@ ++obj-$(CONFIG_MTK_SOC_THERMAL) += auxadc_thermal.o +--- a/drivers/thermal/mtk_thermal.c ++++ /dev/null +@@ -1,1254 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only +-/* +- * Copyright (c) 2015 MediaTek Inc. +- * Author: Hanyi Wu +- * Sascha Hauer +- * Dawei Chien +- * Louis Yu +- */ +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#include "thermal_hwmon.h" +- +-/* AUXADC Registers */ +-#define AUXADC_CON1_SET_V 0x008 +-#define AUXADC_CON1_CLR_V 0x00c +-#define AUXADC_CON2_V 0x010 +-#define AUXADC_DATA(channel) (0x14 + (channel) * 4) +- +-#define APMIXED_SYS_TS_CON1 0x604 +- +-/* Thermal Controller Registers */ +-#define TEMP_MONCTL0 0x000 +-#define TEMP_MONCTL1 0x004 +-#define TEMP_MONCTL2 0x008 +-#define TEMP_MONIDET0 0x014 +-#define TEMP_MONIDET1 0x018 +-#define TEMP_MSRCTL0 0x038 +-#define TEMP_MSRCTL1 0x03c +-#define TEMP_AHBPOLL 0x040 +-#define TEMP_AHBTO 0x044 +-#define TEMP_ADCPNP0 0x048 +-#define TEMP_ADCPNP1 0x04c +-#define TEMP_ADCPNP2 0x050 +-#define TEMP_ADCPNP3 0x0b4 +- +-#define TEMP_ADCMUX 0x054 +-#define TEMP_ADCEN 0x060 +-#define TEMP_PNPMUXADDR 0x064 +-#define TEMP_ADCMUXADDR 0x068 +-#define TEMP_ADCENADDR 0x074 +-#define TEMP_ADCVALIDADDR 0x078 +-#define TEMP_ADCVOLTADDR 0x07c +-#define TEMP_RDCTRL 0x080 +-#define TEMP_ADCVALIDMASK 0x084 +-#define TEMP_ADCVOLTAGESHIFT 0x088 +-#define TEMP_ADCWRITECTRL 0x08c +-#define TEMP_MSR0 0x090 +-#define TEMP_MSR1 0x094 +-#define TEMP_MSR2 0x098 +-#define TEMP_MSR3 0x0B8 +- +-#define TEMP_SPARE0 0x0f0 +- +-#define TEMP_ADCPNP0_1 0x148 +-#define TEMP_ADCPNP1_1 0x14c +-#define TEMP_ADCPNP2_1 0x150 +-#define TEMP_MSR0_1 0x190 +-#define TEMP_MSR1_1 0x194 +-#define TEMP_MSR2_1 0x198 +-#define TEMP_ADCPNP3_1 0x1b4 +-#define TEMP_MSR3_1 0x1B8 +- +-#define PTPCORESEL 0x400 +- +-#define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff) +- +-#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff) << 16) +-#define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff) +- +-#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x) +- +-#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE BIT(0) +-#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE BIT(1) +- +-#define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5) +-#define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit) +- +-/* MT8173 thermal sensors */ +-#define MT8173_TS1 0 +-#define MT8173_TS2 1 +-#define MT8173_TS3 2 +-#define MT8173_TS4 3 +-#define MT8173_TSABB 4 +- +-/* AUXADC channel 11 is used for the temperature sensors */ +-#define MT8173_TEMP_AUXADC_CHANNEL 11 +- +-/* The total number of temperature sensors in the MT8173 */ +-#define MT8173_NUM_SENSORS 5 +- +-/* The number of banks in the MT8173 */ +-#define MT8173_NUM_ZONES 4 +- +-/* The number of sensing points per bank */ +-#define MT8173_NUM_SENSORS_PER_ZONE 4 +- +-/* The number of controller in the MT8173 */ +-#define MT8173_NUM_CONTROLLER 1 +- +-/* The calibration coefficient of sensor */ +-#define MT8173_CALIBRATION 165 +- +-/* +- * Layout of the fuses providing the calibration data +- * These macros could be used for MT8183, MT8173, MT2701, and MT2712. +- * MT8183 has 6 sensors and needs 6 VTS calibration data. +- * MT8173 has 5 sensors and needs 5 VTS calibration data. +- * MT2701 has 3 sensors and needs 3 VTS calibration data. +- * MT2712 has 4 sensors and needs 4 VTS calibration data. +- */ +-#define CALIB_BUF0_VALID_V1 BIT(0) +-#define CALIB_BUF1_ADC_GE_V1(x) (((x) >> 22) & 0x3ff) +-#define CALIB_BUF0_VTS_TS1_V1(x) (((x) >> 17) & 0x1ff) +-#define CALIB_BUF0_VTS_TS2_V1(x) (((x) >> 8) & 0x1ff) +-#define CALIB_BUF1_VTS_TS3_V1(x) (((x) >> 0) & 0x1ff) +-#define CALIB_BUF2_VTS_TS4_V1(x) (((x) >> 23) & 0x1ff) +-#define CALIB_BUF2_VTS_TS5_V1(x) (((x) >> 5) & 0x1ff) +-#define CALIB_BUF2_VTS_TSABB_V1(x) (((x) >> 14) & 0x1ff) +-#define CALIB_BUF0_DEGC_CALI_V1(x) (((x) >> 1) & 0x3f) +-#define CALIB_BUF0_O_SLOPE_V1(x) (((x) >> 26) & 0x3f) +-#define CALIB_BUF0_O_SLOPE_SIGN_V1(x) (((x) >> 7) & 0x1) +-#define CALIB_BUF1_ID_V1(x) (((x) >> 9) & 0x1) +- +-/* +- * Layout of the fuses providing the calibration data +- * These macros could be used for MT7622. +- */ +-#define CALIB_BUF0_ADC_OE_V2(x) (((x) >> 22) & 0x3ff) +-#define CALIB_BUF0_ADC_GE_V2(x) (((x) >> 12) & 0x3ff) +-#define CALIB_BUF0_DEGC_CALI_V2(x) (((x) >> 6) & 0x3f) +-#define CALIB_BUF0_O_SLOPE_V2(x) (((x) >> 0) & 0x3f) +-#define CALIB_BUF1_VTS_TS1_V2(x) (((x) >> 23) & 0x1ff) +-#define CALIB_BUF1_VTS_TS2_V2(x) (((x) >> 14) & 0x1ff) +-#define CALIB_BUF1_VTS_TSABB_V2(x) (((x) >> 5) & 0x1ff) +-#define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1) +-#define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1) +- +-/* +- * Layout of the fuses providing the calibration data +- * These macros can be used for MT7981 and MT7986. +- */ +-#define CALIB_BUF0_ADC_GE_V3(x) (((x) >> 0) & 0x3ff) +-#define CALIB_BUF0_DEGC_CALI_V3(x) (((x) >> 20) & 0x3f) +-#define CALIB_BUF0_O_SLOPE_V3(x) (((x) >> 26) & 0x3f) +-#define CALIB_BUF1_VTS_TS1_V3(x) (((x) >> 0) & 0x1ff) +-#define CALIB_BUF1_VTS_TS2_V3(x) (((x) >> 21) & 0x1ff) +-#define CALIB_BUF1_VTS_TSABB_V3(x) (((x) >> 9) & 0x1ff) +-#define CALIB_BUF1_VALID_V3(x) (((x) >> 18) & 0x1) +-#define CALIB_BUF1_O_SLOPE_SIGN_V3(x) (((x) >> 19) & 0x1) +-#define CALIB_BUF1_ID_V3(x) (((x) >> 20) & 0x1) +- +-enum { +- VTS1, +- VTS2, +- VTS3, +- VTS4, +- VTS5, +- VTSABB, +- MAX_NUM_VTS, +-}; +- +-enum mtk_thermal_version { +- MTK_THERMAL_V1 = 1, +- MTK_THERMAL_V2, +- MTK_THERMAL_V3, +-}; +- +-/* MT2701 thermal sensors */ +-#define MT2701_TS1 0 +-#define MT2701_TS2 1 +-#define MT2701_TSABB 2 +- +-/* AUXADC channel 11 is used for the temperature sensors */ +-#define MT2701_TEMP_AUXADC_CHANNEL 11 +- +-/* The total number of temperature sensors in the MT2701 */ +-#define MT2701_NUM_SENSORS 3 +- +-/* The number of sensing points per bank */ +-#define MT2701_NUM_SENSORS_PER_ZONE 3 +- +-/* The number of controller in the MT2701 */ +-#define MT2701_NUM_CONTROLLER 1 +- +-/* The calibration coefficient of sensor */ +-#define MT2701_CALIBRATION 165 +- +-/* MT2712 thermal sensors */ +-#define MT2712_TS1 0 +-#define MT2712_TS2 1 +-#define MT2712_TS3 2 +-#define MT2712_TS4 3 +- +-/* AUXADC channel 11 is used for the temperature sensors */ +-#define MT2712_TEMP_AUXADC_CHANNEL 11 +- +-/* The total number of temperature sensors in the MT2712 */ +-#define MT2712_NUM_SENSORS 4 +- +-/* The number of sensing points per bank */ +-#define MT2712_NUM_SENSORS_PER_ZONE 4 +- +-/* The number of controller in the MT2712 */ +-#define MT2712_NUM_CONTROLLER 1 +- +-/* The calibration coefficient of sensor */ +-#define MT2712_CALIBRATION 165 +- +-#define MT7622_TEMP_AUXADC_CHANNEL 11 +-#define MT7622_NUM_SENSORS 1 +-#define MT7622_NUM_ZONES 1 +-#define MT7622_NUM_SENSORS_PER_ZONE 1 +-#define MT7622_TS1 0 +-#define MT7622_NUM_CONTROLLER 1 +- +-/* The maximum number of banks */ +-#define MAX_NUM_ZONES 8 +- +-/* The calibration coefficient of sensor */ +-#define MT7622_CALIBRATION 165 +- +-/* MT8183 thermal sensors */ +-#define MT8183_TS1 0 +-#define MT8183_TS2 1 +-#define MT8183_TS3 2 +-#define MT8183_TS4 3 +-#define MT8183_TS5 4 +-#define MT8183_TSABB 5 +- +-/* AUXADC channel is used for the temperature sensors */ +-#define MT8183_TEMP_AUXADC_CHANNEL 11 +- +-/* The total number of temperature sensors in the MT8183 */ +-#define MT8183_NUM_SENSORS 6 +- +-/* The number of banks in the MT8183 */ +-#define MT8183_NUM_ZONES 1 +- +-/* The number of sensing points per bank */ +-#define MT8183_NUM_SENSORS_PER_ZONE 6 +- +-/* The number of controller in the MT8183 */ +-#define MT8183_NUM_CONTROLLER 2 +- +-/* The calibration coefficient of sensor */ +-#define MT8183_CALIBRATION 153 +- +-/* AUXADC channel 11 is used for the temperature sensors */ +-#define MT7986_TEMP_AUXADC_CHANNEL 11 +- +-/* The total number of temperature sensors in the MT7986 */ +-#define MT7986_NUM_SENSORS 1 +- +-/* The number of banks in the MT7986 */ +-#define MT7986_NUM_ZONES 1 +- +-/* The number of sensing points per bank */ +-#define MT7986_NUM_SENSORS_PER_ZONE 1 +- +-/* MT7986 thermal sensors */ +-#define MT7986_TS1 0 +- +-/* The number of controller in the MT7986 */ +-#define MT7986_NUM_CONTROLLER 1 +- +-/* The calibration coefficient of sensor */ +-#define MT7986_CALIBRATION 165 +- +-struct mtk_thermal; +- +-struct thermal_bank_cfg { +- unsigned int num_sensors; +- const int *sensors; +-}; +- +-struct mtk_thermal_bank { +- struct mtk_thermal *mt; +- int id; +-}; +- +-struct mtk_thermal_data { +- s32 num_banks; +- s32 num_sensors; +- s32 auxadc_channel; +- const int *vts_index; +- const int *sensor_mux_values; +- const int *msr; +- const int *adcpnp; +- const int cali_val; +- const int num_controller; +- const int *controller_offset; +- bool need_switch_bank; +- struct thermal_bank_cfg bank_data[MAX_NUM_ZONES]; +- enum mtk_thermal_version version; +-}; +- +-struct mtk_thermal { +- struct device *dev; +- void __iomem *thermal_base; +- +- struct clk *clk_peri_therm; +- struct clk *clk_auxadc; +- /* lock: for getting and putting banks */ +- struct mutex lock; +- +- /* Calibration values */ +- s32 adc_ge; +- s32 adc_oe; +- s32 degc_cali; +- s32 o_slope; +- s32 o_slope_sign; +- s32 vts[MAX_NUM_VTS]; +- +- const struct mtk_thermal_data *conf; +- struct mtk_thermal_bank banks[MAX_NUM_ZONES]; +- +- int (*raw_to_mcelsius)(struct mtk_thermal *mt, int sensno, s32 raw); +-}; +- +-/* MT8183 thermal sensor data */ +-static const int mt8183_bank_data[MT8183_NUM_SENSORS] = { +- MT8183_TS1, MT8183_TS2, MT8183_TS3, MT8183_TS4, MT8183_TS5, MT8183_TSABB +-}; +- +-static const int mt8183_msr[MT8183_NUM_SENSORS_PER_ZONE] = { +- TEMP_MSR0_1, TEMP_MSR1_1, TEMP_MSR2_1, TEMP_MSR1, TEMP_MSR0, TEMP_MSR3_1 +-}; +- +-static const int mt8183_adcpnp[MT8183_NUM_SENSORS_PER_ZONE] = { +- TEMP_ADCPNP0_1, TEMP_ADCPNP1_1, TEMP_ADCPNP2_1, +- TEMP_ADCPNP1, TEMP_ADCPNP0, TEMP_ADCPNP3_1 +-}; +- +-static const int mt8183_mux_values[MT8183_NUM_SENSORS] = { 0, 1, 2, 3, 4, 0 }; +-static const int mt8183_tc_offset[MT8183_NUM_CONTROLLER] = {0x0, 0x100}; +- +-static const int mt8183_vts_index[MT8183_NUM_SENSORS] = { +- VTS1, VTS2, VTS3, VTS4, VTS5, VTSABB +-}; +- +-/* MT8173 thermal sensor data */ +-static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = { +- { MT8173_TS2, MT8173_TS3 }, +- { MT8173_TS2, MT8173_TS4 }, +- { MT8173_TS1, MT8173_TS2, MT8173_TSABB }, +- { MT8173_TS2 }, +-}; +- +-static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = { +- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3 +-}; +- +-static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = { +- TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3 +-}; +- +-static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 }; +-static const int mt8173_tc_offset[MT8173_NUM_CONTROLLER] = { 0x0, }; +- +-static const int mt8173_vts_index[MT8173_NUM_SENSORS] = { +- VTS1, VTS2, VTS3, VTS4, VTSABB +-}; +- +-/* MT2701 thermal sensor data */ +-static const int mt2701_bank_data[MT2701_NUM_SENSORS] = { +- MT2701_TS1, MT2701_TS2, MT2701_TSABB +-}; +- +-static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = { +- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2 +-}; +- +-static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = { +- TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2 +-}; +- +-static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 }; +-static const int mt2701_tc_offset[MT2701_NUM_CONTROLLER] = { 0x0, }; +- +-static const int mt2701_vts_index[MT2701_NUM_SENSORS] = { +- VTS1, VTS2, VTS3 +-}; +- +-/* MT2712 thermal sensor data */ +-static const int mt2712_bank_data[MT2712_NUM_SENSORS] = { +- MT2712_TS1, MT2712_TS2, MT2712_TS3, MT2712_TS4 +-}; +- +-static const int mt2712_msr[MT2712_NUM_SENSORS_PER_ZONE] = { +- TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3 +-}; +- +-static const int mt2712_adcpnp[MT2712_NUM_SENSORS_PER_ZONE] = { +- TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3 +-}; +- +-static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 }; +-static const int mt2712_tc_offset[MT2712_NUM_CONTROLLER] = { 0x0, }; +- +-static const int mt2712_vts_index[MT2712_NUM_SENSORS] = { +- VTS1, VTS2, VTS3, VTS4 +-}; +- +-/* MT7622 thermal sensor data */ +-static const int mt7622_bank_data[MT7622_NUM_SENSORS] = { MT7622_TS1, }; +-static const int mt7622_msr[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, }; +-static const int mt7622_adcpnp[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, }; +-static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, }; +-static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 }; +-static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, }; +- +-/* MT7986 thermal sensor data */ +-static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, }; +-static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, }; +-static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, }; +-static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, }; +-static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 }; +-static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, }; +- +-/* +- * The MT8173 thermal controller has four banks. Each bank can read up to +- * four temperature sensors simultaneously. The MT8173 has a total of 5 +- * temperature sensors. We use each bank to measure a certain area of the +- * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple +- * areas, hence is used in different banks. +- * +- * The thermal core only gets the maximum temperature of all banks, so +- * the bank concept wouldn't be necessary here. However, the SVS (Smart +- * Voltage Scaling) unit makes its decisions based on the same bank +- * data, and this indeed needs the temperatures of the individual banks +- * for making better decisions. +- */ +-static const struct mtk_thermal_data mt8173_thermal_data = { +- .auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL, +- .num_banks = MT8173_NUM_ZONES, +- .num_sensors = MT8173_NUM_SENSORS, +- .vts_index = mt8173_vts_index, +- .cali_val = MT8173_CALIBRATION, +- .num_controller = MT8173_NUM_CONTROLLER, +- .controller_offset = mt8173_tc_offset, +- .need_switch_bank = true, +- .bank_data = { +- { +- .num_sensors = 2, +- .sensors = mt8173_bank_data[0], +- }, { +- .num_sensors = 2, +- .sensors = mt8173_bank_data[1], +- }, { +- .num_sensors = 3, +- .sensors = mt8173_bank_data[2], +- }, { +- .num_sensors = 1, +- .sensors = mt8173_bank_data[3], +- }, +- }, +- .msr = mt8173_msr, +- .adcpnp = mt8173_adcpnp, +- .sensor_mux_values = mt8173_mux_values, +- .version = MTK_THERMAL_V1, +-}; +- +-/* +- * The MT2701 thermal controller has one bank, which can read up to +- * three temperature sensors simultaneously. The MT2701 has a total of 3 +- * temperature sensors. +- * +- * The thermal core only gets the maximum temperature of this one bank, +- * so the bank concept wouldn't be necessary here. However, the SVS (Smart +- * Voltage Scaling) unit makes its decisions based on the same bank +- * data. +- */ +-static const struct mtk_thermal_data mt2701_thermal_data = { +- .auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL, +- .num_banks = 1, +- .num_sensors = MT2701_NUM_SENSORS, +- .vts_index = mt2701_vts_index, +- .cali_val = MT2701_CALIBRATION, +- .num_controller = MT2701_NUM_CONTROLLER, +- .controller_offset = mt2701_tc_offset, +- .need_switch_bank = true, +- .bank_data = { +- { +- .num_sensors = 3, +- .sensors = mt2701_bank_data, +- }, +- }, +- .msr = mt2701_msr, +- .adcpnp = mt2701_adcpnp, +- .sensor_mux_values = mt2701_mux_values, +- .version = MTK_THERMAL_V1, +-}; +- +-/* +- * The MT2712 thermal controller has one bank, which can read up to +- * four temperature sensors simultaneously. The MT2712 has a total of 4 +- * temperature sensors. +- * +- * The thermal core only gets the maximum temperature of this one bank, +- * so the bank concept wouldn't be necessary here. However, the SVS (Smart +- * Voltage Scaling) unit makes its decisions based on the same bank +- * data. +- */ +-static const struct mtk_thermal_data mt2712_thermal_data = { +- .auxadc_channel = MT2712_TEMP_AUXADC_CHANNEL, +- .num_banks = 1, +- .num_sensors = MT2712_NUM_SENSORS, +- .vts_index = mt2712_vts_index, +- .cali_val = MT2712_CALIBRATION, +- .num_controller = MT2712_NUM_CONTROLLER, +- .controller_offset = mt2712_tc_offset, +- .need_switch_bank = true, +- .bank_data = { +- { +- .num_sensors = 4, +- .sensors = mt2712_bank_data, +- }, +- }, +- .msr = mt2712_msr, +- .adcpnp = mt2712_adcpnp, +- .sensor_mux_values = mt2712_mux_values, +- .version = MTK_THERMAL_V1, +-}; +- +-/* +- * MT7622 have only one sensing point which uses AUXADC Channel 11 for raw data +- * access. +- */ +-static const struct mtk_thermal_data mt7622_thermal_data = { +- .auxadc_channel = MT7622_TEMP_AUXADC_CHANNEL, +- .num_banks = MT7622_NUM_ZONES, +- .num_sensors = MT7622_NUM_SENSORS, +- .vts_index = mt7622_vts_index, +- .cali_val = MT7622_CALIBRATION, +- .num_controller = MT7622_NUM_CONTROLLER, +- .controller_offset = mt7622_tc_offset, +- .need_switch_bank = true, +- .bank_data = { +- { +- .num_sensors = 1, +- .sensors = mt7622_bank_data, +- }, +- }, +- .msr = mt7622_msr, +- .adcpnp = mt7622_adcpnp, +- .sensor_mux_values = mt7622_mux_values, +- .version = MTK_THERMAL_V2, +-}; +- +-/* +- * The MT8183 thermal controller has one bank for the current SW framework. +- * The MT8183 has a total of 6 temperature sensors. +- * There are two thermal controller to control the six sensor. +- * The first one bind 2 sensor, and the other bind 4 sensors. +- * The thermal core only gets the maximum temperature of all sensor, so +- * the bank concept wouldn't be necessary here. However, the SVS (Smart +- * Voltage Scaling) unit makes its decisions based on the same bank +- * data, and this indeed needs the temperatures of the individual banks +- * for making better decisions. +- */ +-static const struct mtk_thermal_data mt8183_thermal_data = { +- .auxadc_channel = MT8183_TEMP_AUXADC_CHANNEL, +- .num_banks = MT8183_NUM_ZONES, +- .num_sensors = MT8183_NUM_SENSORS, +- .vts_index = mt8183_vts_index, +- .cali_val = MT8183_CALIBRATION, +- .num_controller = MT8183_NUM_CONTROLLER, +- .controller_offset = mt8183_tc_offset, +- .need_switch_bank = false, +- .bank_data = { +- { +- .num_sensors = 6, +- .sensors = mt8183_bank_data, +- }, +- }, +- +- .msr = mt8183_msr, +- .adcpnp = mt8183_adcpnp, +- .sensor_mux_values = mt8183_mux_values, +- .version = MTK_THERMAL_V1, +-}; +- +-/* +- * MT7986 uses AUXADC Channel 11 for raw data access. +- */ +-static const struct mtk_thermal_data mt7986_thermal_data = { +- .auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL, +- .num_banks = MT7986_NUM_ZONES, +- .num_sensors = MT7986_NUM_SENSORS, +- .vts_index = mt7986_vts_index, +- .cali_val = MT7986_CALIBRATION, +- .num_controller = MT7986_NUM_CONTROLLER, +- .controller_offset = mt7986_tc_offset, +- .need_switch_bank = true, +- .bank_data = { +- { +- .num_sensors = 1, +- .sensors = mt7986_bank_data, +- }, +- }, +- .msr = mt7986_msr, +- .adcpnp = mt7986_adcpnp, +- .sensor_mux_values = mt7986_mux_values, +- .version = MTK_THERMAL_V3, +-}; +- +-/** +- * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius +- * @mt: The thermal controller +- * @sensno: sensor number +- * @raw: raw ADC value +- * +- * This converts the raw ADC value to mcelsius using the SoC specific +- * calibration constants +- */ +-static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw) +-{ +- s32 tmp; +- +- raw &= 0xfff; +- +- tmp = 203450520 << 3; +- tmp /= mt->conf->cali_val + mt->o_slope; +- tmp /= 10000 + mt->adc_ge; +- tmp *= raw - mt->vts[sensno] - 3350; +- tmp >>= 3; +- +- return mt->degc_cali * 500 - tmp; +-} +- +-static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw) +-{ +- s32 format_1; +- s32 format_2; +- s32 g_oe; +- s32 g_gain; +- s32 g_x_roomt; +- s32 tmp; +- +- if (raw == 0) +- return 0; +- +- raw &= 0xfff; +- g_gain = 10000 + (((mt->adc_ge - 512) * 10000) >> 12); +- g_oe = mt->adc_oe - 512; +- format_1 = mt->vts[VTS2] + 3105 - g_oe; +- format_2 = (mt->degc_cali * 10) >> 1; +- g_x_roomt = (((format_1 * 10000) >> 12) * 10000) / g_gain; +- +- tmp = (((((raw - g_oe) * 10000) >> 12) * 10000) / g_gain) - g_x_roomt; +- tmp = tmp * 10 * 100 / 11; +- +- if (mt->o_slope_sign == 0) +- tmp = tmp / (165 - mt->o_slope); +- else +- tmp = tmp / (165 + mt->o_slope); +- +- return (format_2 - tmp) * 100; +-} +- +-static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw) +-{ +- s32 tmp; +- +- if (raw == 0) +- return 0; +- +- raw &= 0xfff; +- tmp = 100000 * 15 / 16 * 10000; +- tmp /= 4096 - 512 + mt->adc_ge; +- tmp /= 1490; +- tmp *= raw - mt->vts[sensno] - 2900; +- +- return mt->degc_cali * 500 - tmp; +-} +- +-/** +- * mtk_thermal_get_bank - get bank +- * @bank: The bank +- * +- * The bank registers are banked, we have to select a bank in the +- * PTPCORESEL register to access it. +- */ +-static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank) +-{ +- struct mtk_thermal *mt = bank->mt; +- u32 val; +- +- if (mt->conf->need_switch_bank) { +- mutex_lock(&mt->lock); +- +- val = readl(mt->thermal_base + PTPCORESEL); +- val &= ~0xf; +- val |= bank->id; +- writel(val, mt->thermal_base + PTPCORESEL); +- } +-} +- +-/** +- * mtk_thermal_put_bank - release bank +- * @bank: The bank +- * +- * release a bank previously taken with mtk_thermal_get_bank, +- */ +-static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank) +-{ +- struct mtk_thermal *mt = bank->mt; +- +- if (mt->conf->need_switch_bank) +- mutex_unlock(&mt->lock); +-} +- +-/** +- * mtk_thermal_bank_temperature - get the temperature of a bank +- * @bank: The bank +- * +- * The temperature of a bank is considered the maximum temperature of +- * the sensors associated to the bank. +- */ +-static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) +-{ +- struct mtk_thermal *mt = bank->mt; +- const struct mtk_thermal_data *conf = mt->conf; +- int i, temp = INT_MIN, max = INT_MIN; +- u32 raw; +- +- for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) { +- raw = readl(mt->thermal_base + conf->msr[i]); +- +- temp = mt->raw_to_mcelsius( +- mt, conf->bank_data[bank->id].sensors[i], raw); +- +- +- /* +- * The first read of a sensor often contains very high bogus +- * temperature value. Filter these out so that the system does +- * not immediately shut down. +- */ +- if (temp > 200000) +- temp = 0; +- +- if (temp > max) +- max = temp; +- } +- +- return max; +-} +- +-static int mtk_read_temp(struct thermal_zone_device *tz, int *temperature) +-{ +- struct mtk_thermal *mt = tz->devdata; +- int i; +- int tempmax = INT_MIN; +- +- for (i = 0; i < mt->conf->num_banks; i++) { +- struct mtk_thermal_bank *bank = &mt->banks[i]; +- +- mtk_thermal_get_bank(bank); +- +- tempmax = max(tempmax, mtk_thermal_bank_temperature(bank)); +- +- mtk_thermal_put_bank(bank); +- } +- +- *temperature = tempmax; +- +- return 0; +-} +- +-static const struct thermal_zone_device_ops mtk_thermal_ops = { +- .get_temp = mtk_read_temp, +-}; +- +-static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, +- u32 apmixed_phys_base, u32 auxadc_phys_base, +- int ctrl_id) +-{ +- struct mtk_thermal_bank *bank = &mt->banks[num]; +- const struct mtk_thermal_data *conf = mt->conf; +- int i; +- +- int offset = mt->conf->controller_offset[ctrl_id]; +- void __iomem *controller_base = mt->thermal_base + offset; +- +- bank->id = num; +- bank->mt = mt; +- +- mtk_thermal_get_bank(bank); +- +- /* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */ +- writel(TEMP_MONCTL1_PERIOD_UNIT(12), controller_base + TEMP_MONCTL1); +- +- /* +- * filt interval is 1 * 46.540us = 46.54us, +- * sen interval is 429 * 46.540us = 19.96ms +- */ +- writel(TEMP_MONCTL2_FILTER_INTERVAL(1) | +- TEMP_MONCTL2_SENSOR_INTERVAL(429), +- controller_base + TEMP_MONCTL2); +- +- /* poll is set to 10u */ +- writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768), +- controller_base + TEMP_AHBPOLL); +- +- /* temperature sampling control, 1 sample */ +- writel(0x0, controller_base + TEMP_MSRCTL0); +- +- /* exceed this polling time, IRQ would be inserted */ +- writel(0xffffffff, controller_base + TEMP_AHBTO); +- +- /* number of interrupts per event, 1 is enough */ +- writel(0x0, controller_base + TEMP_MONIDET0); +- writel(0x0, controller_base + TEMP_MONIDET1); +- +- /* +- * The MT8173 thermal controller does not have its own ADC. Instead it +- * uses AHB bus accesses to control the AUXADC. To do this the thermal +- * controller has to be programmed with the physical addresses of the +- * AUXADC registers and with the various bit positions in the AUXADC. +- * Also the thermal controller controls a mux in the APMIXEDSYS register +- * space. +- */ +- +- /* +- * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0) +- * automatically by hw +- */ +- writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCMUX); +- +- /* AHB address for auxadc mux selection */ +- writel(auxadc_phys_base + AUXADC_CON1_CLR_V, +- controller_base + TEMP_ADCMUXADDR); +- +- if (mt->conf->version == MTK_THERMAL_V1) { +- /* AHB address for pnp sensor mux selection */ +- writel(apmixed_phys_base + APMIXED_SYS_TS_CON1, +- controller_base + TEMP_PNPMUXADDR); +- } +- +- /* AHB value for auxadc enable */ +- writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN); +- +- /* AHB address for auxadc enable (channel 0 immediate mode selected) */ +- writel(auxadc_phys_base + AUXADC_CON1_SET_V, +- controller_base + TEMP_ADCENADDR); +- +- /* AHB address for auxadc valid bit */ +- writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel), +- controller_base + TEMP_ADCVALIDADDR); +- +- /* AHB address for auxadc voltage output */ +- writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel), +- controller_base + TEMP_ADCVOLTADDR); +- +- /* read valid & voltage are at the same register */ +- writel(0x0, controller_base + TEMP_RDCTRL); +- +- /* indicate where the valid bit is */ +- writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12), +- controller_base + TEMP_ADCVALIDMASK); +- +- /* no shift */ +- writel(0x0, controller_base + TEMP_ADCVOLTAGESHIFT); +- +- /* enable auxadc mux write transaction */ +- writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE, +- controller_base + TEMP_ADCWRITECTRL); +- +- for (i = 0; i < conf->bank_data[num].num_sensors; i++) +- writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]], +- mt->thermal_base + conf->adcpnp[i]); +- +- writel((1 << conf->bank_data[num].num_sensors) - 1, +- controller_base + TEMP_MONCTL0); +- +- writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE | +- TEMP_ADCWRITECTRL_ADC_MUX_WRITE, +- controller_base + TEMP_ADCWRITECTRL); +- +- mtk_thermal_put_bank(bank); +-} +- +-static u64 of_get_phys_base(struct device_node *np) +-{ +- u64 size64; +- const __be32 *regaddr_p; +- +- regaddr_p = of_get_address(np, 0, &size64, NULL); +- if (!regaddr_p) +- return OF_BAD_ADDR; +- +- return of_translate_address(np, regaddr_p); +-} +- +-static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf) +-{ +- int i; +- +- if (!(buf[0] & CALIB_BUF0_VALID_V1)) +- return -EINVAL; +- +- mt->adc_ge = CALIB_BUF1_ADC_GE_V1(buf[1]); +- +- for (i = 0; i < mt->conf->num_sensors; i++) { +- switch (mt->conf->vts_index[i]) { +- case VTS1: +- mt->vts[VTS1] = CALIB_BUF0_VTS_TS1_V1(buf[0]); +- break; +- case VTS2: +- mt->vts[VTS2] = CALIB_BUF0_VTS_TS2_V1(buf[0]); +- break; +- case VTS3: +- mt->vts[VTS3] = CALIB_BUF1_VTS_TS3_V1(buf[1]); +- break; +- case VTS4: +- mt->vts[VTS4] = CALIB_BUF2_VTS_TS4_V1(buf[2]); +- break; +- case VTS5: +- mt->vts[VTS5] = CALIB_BUF2_VTS_TS5_V1(buf[2]); +- break; +- case VTSABB: +- mt->vts[VTSABB] = +- CALIB_BUF2_VTS_TSABB_V1(buf[2]); +- break; +- default: +- break; +- } +- } +- +- mt->degc_cali = CALIB_BUF0_DEGC_CALI_V1(buf[0]); +- if (CALIB_BUF1_ID_V1(buf[1]) & +- CALIB_BUF0_O_SLOPE_SIGN_V1(buf[0])) +- mt->o_slope = -CALIB_BUF0_O_SLOPE_V1(buf[0]); +- else +- mt->o_slope = CALIB_BUF0_O_SLOPE_V1(buf[0]); +- +- return 0; +-} +- +-static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf) +-{ +- if (!CALIB_BUF1_VALID_V2(buf[1])) +- return -EINVAL; +- +- mt->adc_oe = CALIB_BUF0_ADC_OE_V2(buf[0]); +- mt->adc_ge = CALIB_BUF0_ADC_GE_V2(buf[0]); +- mt->degc_cali = CALIB_BUF0_DEGC_CALI_V2(buf[0]); +- mt->o_slope = CALIB_BUF0_O_SLOPE_V2(buf[0]); +- mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V2(buf[1]); +- mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V2(buf[1]); +- mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V2(buf[1]); +- mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V2(buf[1]); +- +- return 0; +-} +- +-static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf) +-{ +- if (!CALIB_BUF1_VALID_V3(buf[1])) +- return -EINVAL; +- +- mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]); +- mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]); +- mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]); +- mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]); +- mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]); +- mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]); +- mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]); +- +- if (CALIB_BUF1_ID_V3(buf[1]) == 0) +- mt->o_slope = 0; +- +- return 0; +-} +- +-static int mtk_thermal_get_calibration_data(struct device *dev, +- struct mtk_thermal *mt) +-{ +- struct nvmem_cell *cell; +- u32 *buf; +- size_t len; +- int i, ret = 0; +- +- /* Start with default values */ +- mt->adc_ge = 512; +- mt->adc_oe = 512; +- for (i = 0; i < mt->conf->num_sensors; i++) +- mt->vts[i] = 260; +- mt->degc_cali = 40; +- mt->o_slope = 0; +- +- cell = nvmem_cell_get(dev, "calibration-data"); +- if (IS_ERR(cell)) { +- if (PTR_ERR(cell) == -EPROBE_DEFER) +- return PTR_ERR(cell); +- return 0; +- } +- +- buf = (u32 *)nvmem_cell_read(cell, &len); +- +- nvmem_cell_put(cell); +- +- if (IS_ERR(buf)) +- return PTR_ERR(buf); +- +- if (len < 3 * sizeof(u32)) { +- dev_warn(dev, "invalid calibration data\n"); +- ret = -EINVAL; +- goto out; +- } +- +- switch (mt->conf->version) { +- case MTK_THERMAL_V1: +- ret = mtk_thermal_extract_efuse_v1(mt, buf); +- break; +- case MTK_THERMAL_V2: +- ret = mtk_thermal_extract_efuse_v2(mt, buf); +- break; +- case MTK_THERMAL_V3: +- ret = mtk_thermal_extract_efuse_v3(mt, buf); +- break; +- default: +- ret = -EINVAL; +- break; +- } +- +- if (ret) { +- dev_info(dev, "Device not calibrated, using default calibration values\n"); +- ret = 0; +- } +- +-out: +- kfree(buf); +- +- return ret; +-} +- +-static const struct of_device_id mtk_thermal_of_match[] = { +- { +- .compatible = "mediatek,mt8173-thermal", +- .data = (void *)&mt8173_thermal_data, +- }, +- { +- .compatible = "mediatek,mt2701-thermal", +- .data = (void *)&mt2701_thermal_data, +- }, +- { +- .compatible = "mediatek,mt2712-thermal", +- .data = (void *)&mt2712_thermal_data, +- }, +- { +- .compatible = "mediatek,mt7622-thermal", +- .data = (void *)&mt7622_thermal_data, +- }, +- { +- .compatible = "mediatek,mt7986-thermal", +- .data = (void *)&mt7986_thermal_data, +- }, +- { +- .compatible = "mediatek,mt8183-thermal", +- .data = (void *)&mt8183_thermal_data, +- }, { +- }, +-}; +-MODULE_DEVICE_TABLE(of, mtk_thermal_of_match); +- +-static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base) +-{ +- int tmp; +- +- tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1); +- tmp &= ~(0x37); +- tmp |= 0x1; +- writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1); +- udelay(200); +-} +- +-static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt, +- void __iomem *auxadc_base) +-{ +- int tmp; +- +- writel(0x800, auxadc_base + AUXADC_CON1_SET_V); +- writel(0x1, mt->thermal_base + TEMP_MONCTL0); +- tmp = readl(mt->thermal_base + TEMP_MSRCTL1); +- writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1); +-} +- +-static int mtk_thermal_probe(struct platform_device *pdev) +-{ +- int ret, i, ctrl_id; +- struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node; +- struct mtk_thermal *mt; +- u64 auxadc_phys_base, apmixed_phys_base; +- struct thermal_zone_device *tzdev; +- void __iomem *apmixed_base, *auxadc_base; +- +- mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL); +- if (!mt) +- return -ENOMEM; +- +- mt->conf = of_device_get_match_data(&pdev->dev); +- +- mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm"); +- if (IS_ERR(mt->clk_peri_therm)) +- return PTR_ERR(mt->clk_peri_therm); +- +- mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc"); +- if (IS_ERR(mt->clk_auxadc)) +- return PTR_ERR(mt->clk_auxadc); +- +- mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); +- if (IS_ERR(mt->thermal_base)) +- return PTR_ERR(mt->thermal_base); +- +- ret = mtk_thermal_get_calibration_data(&pdev->dev, mt); +- if (ret) +- return ret; +- +- mutex_init(&mt->lock); +- +- mt->dev = &pdev->dev; +- +- auxadc = of_parse_phandle(np, "mediatek,auxadc", 0); +- if (!auxadc) { +- dev_err(&pdev->dev, "missing auxadc node\n"); +- return -ENODEV; +- } +- +- auxadc_base = of_iomap(auxadc, 0); +- auxadc_phys_base = of_get_phys_base(auxadc); +- +- of_node_put(auxadc); +- +- if (auxadc_phys_base == OF_BAD_ADDR) { +- dev_err(&pdev->dev, "Can't get auxadc phys address\n"); +- return -EINVAL; +- } +- +- apmixedsys = of_parse_phandle(np, "mediatek,apmixedsys", 0); +- if (!apmixedsys) { +- dev_err(&pdev->dev, "missing apmixedsys node\n"); +- return -ENODEV; +- } +- +- apmixed_base = of_iomap(apmixedsys, 0); +- apmixed_phys_base = of_get_phys_base(apmixedsys); +- +- of_node_put(apmixedsys); +- +- if (apmixed_phys_base == OF_BAD_ADDR) { +- dev_err(&pdev->dev, "Can't get auxadc phys address\n"); +- return -EINVAL; +- } +- +- ret = device_reset_optional(&pdev->dev); +- if (ret) +- return ret; +- +- ret = clk_prepare_enable(mt->clk_auxadc); +- if (ret) { +- dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret); +- return ret; +- } +- +- ret = clk_prepare_enable(mt->clk_peri_therm); +- if (ret) { +- dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret); +- goto err_disable_clk_auxadc; +- } +- +- if (mt->conf->version != MTK_THERMAL_V1) { +- mtk_thermal_turn_on_buffer(apmixed_base); +- mtk_thermal_release_periodic_ts(mt, auxadc_base); +- } +- +- if (mt->conf->version == MTK_THERMAL_V1) +- mt->raw_to_mcelsius = raw_to_mcelsius_v1; +- else if (mt->conf->version == MTK_THERMAL_V2) +- mt->raw_to_mcelsius = raw_to_mcelsius_v2; +- else +- mt->raw_to_mcelsius = raw_to_mcelsius_v3; +- +- for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++) +- for (i = 0; i < mt->conf->num_banks; i++) +- mtk_thermal_init_bank(mt, i, apmixed_phys_base, +- auxadc_phys_base, ctrl_id); +- +- platform_set_drvdata(pdev, mt); +- +- tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt, +- &mtk_thermal_ops); +- if (IS_ERR(tzdev)) { +- ret = PTR_ERR(tzdev); +- goto err_disable_clk_peri_therm; +- } +- +- ret = devm_thermal_add_hwmon_sysfs(tzdev); +- if (ret) +- dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs"); +- +- return 0; +- +-err_disable_clk_peri_therm: +- clk_disable_unprepare(mt->clk_peri_therm); +-err_disable_clk_auxadc: +- clk_disable_unprepare(mt->clk_auxadc); +- +- return ret; +-} +- +-static int mtk_thermal_remove(struct platform_device *pdev) +-{ +- struct mtk_thermal *mt = platform_get_drvdata(pdev); +- +- clk_disable_unprepare(mt->clk_peri_therm); +- clk_disable_unprepare(mt->clk_auxadc); +- +- return 0; +-} +- +-static struct platform_driver mtk_thermal_driver = { +- .probe = mtk_thermal_probe, +- .remove = mtk_thermal_remove, +- .driver = { +- .name = "mtk-thermal", +- .of_match_table = mtk_thermal_of_match, +- }, +-}; +- +-module_platform_driver(mtk_thermal_driver); +- +-MODULE_AUTHOR("Michael Kao "); +-MODULE_AUTHOR("Louis Yu "); +-MODULE_AUTHOR("Dawei Chien "); +-MODULE_AUTHOR("Sascha Hauer "); +-MODULE_AUTHOR("Hanyi Wu "); +-MODULE_DESCRIPTION("Mediatek thermal driver"); +-MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -0,0 +1,1254 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2015 MediaTek Inc. ++ * Author: Hanyi Wu ++ * Sascha Hauer ++ * Dawei Chien ++ * Louis Yu ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "../thermal_hwmon.h" ++ ++/* AUXADC Registers */ ++#define AUXADC_CON1_SET_V 0x008 ++#define AUXADC_CON1_CLR_V 0x00c ++#define AUXADC_CON2_V 0x010 ++#define AUXADC_DATA(channel) (0x14 + (channel) * 4) ++ ++#define APMIXED_SYS_TS_CON1 0x604 ++ ++/* Thermal Controller Registers */ ++#define TEMP_MONCTL0 0x000 ++#define TEMP_MONCTL1 0x004 ++#define TEMP_MONCTL2 0x008 ++#define TEMP_MONIDET0 0x014 ++#define TEMP_MONIDET1 0x018 ++#define TEMP_MSRCTL0 0x038 ++#define TEMP_MSRCTL1 0x03c ++#define TEMP_AHBPOLL 0x040 ++#define TEMP_AHBTO 0x044 ++#define TEMP_ADCPNP0 0x048 ++#define TEMP_ADCPNP1 0x04c ++#define TEMP_ADCPNP2 0x050 ++#define TEMP_ADCPNP3 0x0b4 ++ ++#define TEMP_ADCMUX 0x054 ++#define TEMP_ADCEN 0x060 ++#define TEMP_PNPMUXADDR 0x064 ++#define TEMP_ADCMUXADDR 0x068 ++#define TEMP_ADCENADDR 0x074 ++#define TEMP_ADCVALIDADDR 0x078 ++#define TEMP_ADCVOLTADDR 0x07c ++#define TEMP_RDCTRL 0x080 ++#define TEMP_ADCVALIDMASK 0x084 ++#define TEMP_ADCVOLTAGESHIFT 0x088 ++#define TEMP_ADCWRITECTRL 0x08c ++#define TEMP_MSR0 0x090 ++#define TEMP_MSR1 0x094 ++#define TEMP_MSR2 0x098 ++#define TEMP_MSR3 0x0B8 ++ ++#define TEMP_SPARE0 0x0f0 ++ ++#define TEMP_ADCPNP0_1 0x148 ++#define TEMP_ADCPNP1_1 0x14c ++#define TEMP_ADCPNP2_1 0x150 ++#define TEMP_MSR0_1 0x190 ++#define TEMP_MSR1_1 0x194 ++#define TEMP_MSR2_1 0x198 ++#define TEMP_ADCPNP3_1 0x1b4 ++#define TEMP_MSR3_1 0x1B8 ++ ++#define PTPCORESEL 0x400 ++ ++#define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff) ++ ++#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff) << 16) ++#define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff) ++ ++#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x) ++ ++#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE BIT(0) ++#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE BIT(1) ++ ++#define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5) ++#define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit) ++ ++/* MT8173 thermal sensors */ ++#define MT8173_TS1 0 ++#define MT8173_TS2 1 ++#define MT8173_TS3 2 ++#define MT8173_TS4 3 ++#define MT8173_TSABB 4 ++ ++/* AUXADC channel 11 is used for the temperature sensors */ ++#define MT8173_TEMP_AUXADC_CHANNEL 11 ++ ++/* The total number of temperature sensors in the MT8173 */ ++#define MT8173_NUM_SENSORS 5 ++ ++/* The number of banks in the MT8173 */ ++#define MT8173_NUM_ZONES 4 ++ ++/* The number of sensing points per bank */ ++#define MT8173_NUM_SENSORS_PER_ZONE 4 ++ ++/* The number of controller in the MT8173 */ ++#define MT8173_NUM_CONTROLLER 1 ++ ++/* The calibration coefficient of sensor */ ++#define MT8173_CALIBRATION 165 ++ ++/* ++ * Layout of the fuses providing the calibration data ++ * These macros could be used for MT8183, MT8173, MT2701, and MT2712. ++ * MT8183 has 6 sensors and needs 6 VTS calibration data. ++ * MT8173 has 5 sensors and needs 5 VTS calibration data. ++ * MT2701 has 3 sensors and needs 3 VTS calibration data. ++ * MT2712 has 4 sensors and needs 4 VTS calibration data. ++ */ ++#define CALIB_BUF0_VALID_V1 BIT(0) ++#define CALIB_BUF1_ADC_GE_V1(x) (((x) >> 22) & 0x3ff) ++#define CALIB_BUF0_VTS_TS1_V1(x) (((x) >> 17) & 0x1ff) ++#define CALIB_BUF0_VTS_TS2_V1(x) (((x) >> 8) & 0x1ff) ++#define CALIB_BUF1_VTS_TS3_V1(x) (((x) >> 0) & 0x1ff) ++#define CALIB_BUF2_VTS_TS4_V1(x) (((x) >> 23) & 0x1ff) ++#define CALIB_BUF2_VTS_TS5_V1(x) (((x) >> 5) & 0x1ff) ++#define CALIB_BUF2_VTS_TSABB_V1(x) (((x) >> 14) & 0x1ff) ++#define CALIB_BUF0_DEGC_CALI_V1(x) (((x) >> 1) & 0x3f) ++#define CALIB_BUF0_O_SLOPE_V1(x) (((x) >> 26) & 0x3f) ++#define CALIB_BUF0_O_SLOPE_SIGN_V1(x) (((x) >> 7) & 0x1) ++#define CALIB_BUF1_ID_V1(x) (((x) >> 9) & 0x1) ++ ++/* ++ * Layout of the fuses providing the calibration data ++ * These macros could be used for MT7622. ++ */ ++#define CALIB_BUF0_ADC_OE_V2(x) (((x) >> 22) & 0x3ff) ++#define CALIB_BUF0_ADC_GE_V2(x) (((x) >> 12) & 0x3ff) ++#define CALIB_BUF0_DEGC_CALI_V2(x) (((x) >> 6) & 0x3f) ++#define CALIB_BUF0_O_SLOPE_V2(x) (((x) >> 0) & 0x3f) ++#define CALIB_BUF1_VTS_TS1_V2(x) (((x) >> 23) & 0x1ff) ++#define CALIB_BUF1_VTS_TS2_V2(x) (((x) >> 14) & 0x1ff) ++#define CALIB_BUF1_VTS_TSABB_V2(x) (((x) >> 5) & 0x1ff) ++#define CALIB_BUF1_VALID_V2(x) (((x) >> 4) & 0x1) ++#define CALIB_BUF1_O_SLOPE_SIGN_V2(x) (((x) >> 3) & 0x1) ++ ++/* ++ * Layout of the fuses providing the calibration data ++ * These macros can be used for MT7981 and MT7986. ++ */ ++#define CALIB_BUF0_ADC_GE_V3(x) (((x) >> 0) & 0x3ff) ++#define CALIB_BUF0_DEGC_CALI_V3(x) (((x) >> 20) & 0x3f) ++#define CALIB_BUF0_O_SLOPE_V3(x) (((x) >> 26) & 0x3f) ++#define CALIB_BUF1_VTS_TS1_V3(x) (((x) >> 0) & 0x1ff) ++#define CALIB_BUF1_VTS_TS2_V3(x) (((x) >> 21) & 0x1ff) ++#define CALIB_BUF1_VTS_TSABB_V3(x) (((x) >> 9) & 0x1ff) ++#define CALIB_BUF1_VALID_V3(x) (((x) >> 18) & 0x1) ++#define CALIB_BUF1_O_SLOPE_SIGN_V3(x) (((x) >> 19) & 0x1) ++#define CALIB_BUF1_ID_V3(x) (((x) >> 20) & 0x1) ++ ++enum { ++ VTS1, ++ VTS2, ++ VTS3, ++ VTS4, ++ VTS5, ++ VTSABB, ++ MAX_NUM_VTS, ++}; ++ ++enum mtk_thermal_version { ++ MTK_THERMAL_V1 = 1, ++ MTK_THERMAL_V2, ++ MTK_THERMAL_V3, ++}; ++ ++/* MT2701 thermal sensors */ ++#define MT2701_TS1 0 ++#define MT2701_TS2 1 ++#define MT2701_TSABB 2 ++ ++/* AUXADC channel 11 is used for the temperature sensors */ ++#define MT2701_TEMP_AUXADC_CHANNEL 11 ++ ++/* The total number of temperature sensors in the MT2701 */ ++#define MT2701_NUM_SENSORS 3 ++ ++/* The number of sensing points per bank */ ++#define MT2701_NUM_SENSORS_PER_ZONE 3 ++ ++/* The number of controller in the MT2701 */ ++#define MT2701_NUM_CONTROLLER 1 ++ ++/* The calibration coefficient of sensor */ ++#define MT2701_CALIBRATION 165 ++ ++/* MT2712 thermal sensors */ ++#define MT2712_TS1 0 ++#define MT2712_TS2 1 ++#define MT2712_TS3 2 ++#define MT2712_TS4 3 ++ ++/* AUXADC channel 11 is used for the temperature sensors */ ++#define MT2712_TEMP_AUXADC_CHANNEL 11 ++ ++/* The total number of temperature sensors in the MT2712 */ ++#define MT2712_NUM_SENSORS 4 ++ ++/* The number of sensing points per bank */ ++#define MT2712_NUM_SENSORS_PER_ZONE 4 ++ ++/* The number of controller in the MT2712 */ ++#define MT2712_NUM_CONTROLLER 1 ++ ++/* The calibration coefficient of sensor */ ++#define MT2712_CALIBRATION 165 ++ ++#define MT7622_TEMP_AUXADC_CHANNEL 11 ++#define MT7622_NUM_SENSORS 1 ++#define MT7622_NUM_ZONES 1 ++#define MT7622_NUM_SENSORS_PER_ZONE 1 ++#define MT7622_TS1 0 ++#define MT7622_NUM_CONTROLLER 1 ++ ++/* The maximum number of banks */ ++#define MAX_NUM_ZONES 8 ++ ++/* The calibration coefficient of sensor */ ++#define MT7622_CALIBRATION 165 ++ ++/* MT8183 thermal sensors */ ++#define MT8183_TS1 0 ++#define MT8183_TS2 1 ++#define MT8183_TS3 2 ++#define MT8183_TS4 3 ++#define MT8183_TS5 4 ++#define MT8183_TSABB 5 ++ ++/* AUXADC channel is used for the temperature sensors */ ++#define MT8183_TEMP_AUXADC_CHANNEL 11 ++ ++/* The total number of temperature sensors in the MT8183 */ ++#define MT8183_NUM_SENSORS 6 ++ ++/* The number of banks in the MT8183 */ ++#define MT8183_NUM_ZONES 1 ++ ++/* The number of sensing points per bank */ ++#define MT8183_NUM_SENSORS_PER_ZONE 6 ++ ++/* The number of controller in the MT8183 */ ++#define MT8183_NUM_CONTROLLER 2 ++ ++/* The calibration coefficient of sensor */ ++#define MT8183_CALIBRATION 153 ++ ++/* AUXADC channel 11 is used for the temperature sensors */ ++#define MT7986_TEMP_AUXADC_CHANNEL 11 ++ ++/* The total number of temperature sensors in the MT7986 */ ++#define MT7986_NUM_SENSORS 1 ++ ++/* The number of banks in the MT7986 */ ++#define MT7986_NUM_ZONES 1 ++ ++/* The number of sensing points per bank */ ++#define MT7986_NUM_SENSORS_PER_ZONE 1 ++ ++/* MT7986 thermal sensors */ ++#define MT7986_TS1 0 ++ ++/* The number of controller in the MT7986 */ ++#define MT7986_NUM_CONTROLLER 1 ++ ++/* The calibration coefficient of sensor */ ++#define MT7986_CALIBRATION 165 ++ ++struct mtk_thermal; ++ ++struct thermal_bank_cfg { ++ unsigned int num_sensors; ++ const int *sensors; ++}; ++ ++struct mtk_thermal_bank { ++ struct mtk_thermal *mt; ++ int id; ++}; ++ ++struct mtk_thermal_data { ++ s32 num_banks; ++ s32 num_sensors; ++ s32 auxadc_channel; ++ const int *vts_index; ++ const int *sensor_mux_values; ++ const int *msr; ++ const int *adcpnp; ++ const int cali_val; ++ const int num_controller; ++ const int *controller_offset; ++ bool need_switch_bank; ++ struct thermal_bank_cfg bank_data[MAX_NUM_ZONES]; ++ enum mtk_thermal_version version; ++}; ++ ++struct mtk_thermal { ++ struct device *dev; ++ void __iomem *thermal_base; ++ ++ struct clk *clk_peri_therm; ++ struct clk *clk_auxadc; ++ /* lock: for getting and putting banks */ ++ struct mutex lock; ++ ++ /* Calibration values */ ++ s32 adc_ge; ++ s32 adc_oe; ++ s32 degc_cali; ++ s32 o_slope; ++ s32 o_slope_sign; ++ s32 vts[MAX_NUM_VTS]; ++ ++ const struct mtk_thermal_data *conf; ++ struct mtk_thermal_bank banks[MAX_NUM_ZONES]; ++ ++ int (*raw_to_mcelsius)(struct mtk_thermal *mt, int sensno, s32 raw); ++}; ++ ++/* MT8183 thermal sensor data */ ++static const int mt8183_bank_data[MT8183_NUM_SENSORS] = { ++ MT8183_TS1, MT8183_TS2, MT8183_TS3, MT8183_TS4, MT8183_TS5, MT8183_TSABB ++}; ++ ++static const int mt8183_msr[MT8183_NUM_SENSORS_PER_ZONE] = { ++ TEMP_MSR0_1, TEMP_MSR1_1, TEMP_MSR2_1, TEMP_MSR1, TEMP_MSR0, TEMP_MSR3_1 ++}; ++ ++static const int mt8183_adcpnp[MT8183_NUM_SENSORS_PER_ZONE] = { ++ TEMP_ADCPNP0_1, TEMP_ADCPNP1_1, TEMP_ADCPNP2_1, ++ TEMP_ADCPNP1, TEMP_ADCPNP0, TEMP_ADCPNP3_1 ++}; ++ ++static const int mt8183_mux_values[MT8183_NUM_SENSORS] = { 0, 1, 2, 3, 4, 0 }; ++static const int mt8183_tc_offset[MT8183_NUM_CONTROLLER] = {0x0, 0x100}; ++ ++static const int mt8183_vts_index[MT8183_NUM_SENSORS] = { ++ VTS1, VTS2, VTS3, VTS4, VTS5, VTSABB ++}; ++ ++/* MT8173 thermal sensor data */ ++static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = { ++ { MT8173_TS2, MT8173_TS3 }, ++ { MT8173_TS2, MT8173_TS4 }, ++ { MT8173_TS1, MT8173_TS2, MT8173_TSABB }, ++ { MT8173_TS2 }, ++}; ++ ++static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = { ++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3 ++}; ++ ++static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = { ++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3 ++}; ++ ++static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 }; ++static const int mt8173_tc_offset[MT8173_NUM_CONTROLLER] = { 0x0, }; ++ ++static const int mt8173_vts_index[MT8173_NUM_SENSORS] = { ++ VTS1, VTS2, VTS3, VTS4, VTSABB ++}; ++ ++/* MT2701 thermal sensor data */ ++static const int mt2701_bank_data[MT2701_NUM_SENSORS] = { ++ MT2701_TS1, MT2701_TS2, MT2701_TSABB ++}; ++ ++static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = { ++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2 ++}; ++ ++static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = { ++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2 ++}; ++ ++static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 }; ++static const int mt2701_tc_offset[MT2701_NUM_CONTROLLER] = { 0x0, }; ++ ++static const int mt2701_vts_index[MT2701_NUM_SENSORS] = { ++ VTS1, VTS2, VTS3 ++}; ++ ++/* MT2712 thermal sensor data */ ++static const int mt2712_bank_data[MT2712_NUM_SENSORS] = { ++ MT2712_TS1, MT2712_TS2, MT2712_TS3, MT2712_TS4 ++}; ++ ++static const int mt2712_msr[MT2712_NUM_SENSORS_PER_ZONE] = { ++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR3 ++}; ++ ++static const int mt2712_adcpnp[MT2712_NUM_SENSORS_PER_ZONE] = { ++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3 ++}; ++ ++static const int mt2712_mux_values[MT2712_NUM_SENSORS] = { 0, 1, 2, 3 }; ++static const int mt2712_tc_offset[MT2712_NUM_CONTROLLER] = { 0x0, }; ++ ++static const int mt2712_vts_index[MT2712_NUM_SENSORS] = { ++ VTS1, VTS2, VTS3, VTS4 ++}; ++ ++/* MT7622 thermal sensor data */ ++static const int mt7622_bank_data[MT7622_NUM_SENSORS] = { MT7622_TS1, }; ++static const int mt7622_msr[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, }; ++static const int mt7622_adcpnp[MT7622_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, }; ++static const int mt7622_mux_values[MT7622_NUM_SENSORS] = { 0, }; ++static const int mt7622_vts_index[MT7622_NUM_SENSORS] = { VTS1 }; ++static const int mt7622_tc_offset[MT7622_NUM_CONTROLLER] = { 0x0, }; ++ ++/* MT7986 thermal sensor data */ ++static const int mt7986_bank_data[MT7986_NUM_SENSORS] = { MT7986_TS1, }; ++static const int mt7986_msr[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_MSR0, }; ++static const int mt7986_adcpnp[MT7986_NUM_SENSORS_PER_ZONE] = { TEMP_ADCPNP0, }; ++static const int mt7986_mux_values[MT7986_NUM_SENSORS] = { 0, }; ++static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 }; ++static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, }; ++ ++/* ++ * The MT8173 thermal controller has four banks. Each bank can read up to ++ * four temperature sensors simultaneously. The MT8173 has a total of 5 ++ * temperature sensors. We use each bank to measure a certain area of the ++ * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple ++ * areas, hence is used in different banks. ++ * ++ * The thermal core only gets the maximum temperature of all banks, so ++ * the bank concept wouldn't be necessary here. However, the SVS (Smart ++ * Voltage Scaling) unit makes its decisions based on the same bank ++ * data, and this indeed needs the temperatures of the individual banks ++ * for making better decisions. ++ */ ++static const struct mtk_thermal_data mt8173_thermal_data = { ++ .auxadc_channel = MT8173_TEMP_AUXADC_CHANNEL, ++ .num_banks = MT8173_NUM_ZONES, ++ .num_sensors = MT8173_NUM_SENSORS, ++ .vts_index = mt8173_vts_index, ++ .cali_val = MT8173_CALIBRATION, ++ .num_controller = MT8173_NUM_CONTROLLER, ++ .controller_offset = mt8173_tc_offset, ++ .need_switch_bank = true, ++ .bank_data = { ++ { ++ .num_sensors = 2, ++ .sensors = mt8173_bank_data[0], ++ }, { ++ .num_sensors = 2, ++ .sensors = mt8173_bank_data[1], ++ }, { ++ .num_sensors = 3, ++ .sensors = mt8173_bank_data[2], ++ }, { ++ .num_sensors = 1, ++ .sensors = mt8173_bank_data[3], ++ }, ++ }, ++ .msr = mt8173_msr, ++ .adcpnp = mt8173_adcpnp, ++ .sensor_mux_values = mt8173_mux_values, ++ .version = MTK_THERMAL_V1, ++}; ++ ++/* ++ * The MT2701 thermal controller has one bank, which can read up to ++ * three temperature sensors simultaneously. The MT2701 has a total of 3 ++ * temperature sensors. ++ * ++ * The thermal core only gets the maximum temperature of this one bank, ++ * so the bank concept wouldn't be necessary here. However, the SVS (Smart ++ * Voltage Scaling) unit makes its decisions based on the same bank ++ * data. ++ */ ++static const struct mtk_thermal_data mt2701_thermal_data = { ++ .auxadc_channel = MT2701_TEMP_AUXADC_CHANNEL, ++ .num_banks = 1, ++ .num_sensors = MT2701_NUM_SENSORS, ++ .vts_index = mt2701_vts_index, ++ .cali_val = MT2701_CALIBRATION, ++ .num_controller = MT2701_NUM_CONTROLLER, ++ .controller_offset = mt2701_tc_offset, ++ .need_switch_bank = true, ++ .bank_data = { ++ { ++ .num_sensors = 3, ++ .sensors = mt2701_bank_data, ++ }, ++ }, ++ .msr = mt2701_msr, ++ .adcpnp = mt2701_adcpnp, ++ .sensor_mux_values = mt2701_mux_values, ++ .version = MTK_THERMAL_V1, ++}; ++ ++/* ++ * The MT2712 thermal controller has one bank, which can read up to ++ * four temperature sensors simultaneously. The MT2712 has a total of 4 ++ * temperature sensors. ++ * ++ * The thermal core only gets the maximum temperature of this one bank, ++ * so the bank concept wouldn't be necessary here. However, the SVS (Smart ++ * Voltage Scaling) unit makes its decisions based on the same bank ++ * data. ++ */ ++static const struct mtk_thermal_data mt2712_thermal_data = { ++ .auxadc_channel = MT2712_TEMP_AUXADC_CHANNEL, ++ .num_banks = 1, ++ .num_sensors = MT2712_NUM_SENSORS, ++ .vts_index = mt2712_vts_index, ++ .cali_val = MT2712_CALIBRATION, ++ .num_controller = MT2712_NUM_CONTROLLER, ++ .controller_offset = mt2712_tc_offset, ++ .need_switch_bank = true, ++ .bank_data = { ++ { ++ .num_sensors = 4, ++ .sensors = mt2712_bank_data, ++ }, ++ }, ++ .msr = mt2712_msr, ++ .adcpnp = mt2712_adcpnp, ++ .sensor_mux_values = mt2712_mux_values, ++ .version = MTK_THERMAL_V1, ++}; ++ ++/* ++ * MT7622 have only one sensing point which uses AUXADC Channel 11 for raw data ++ * access. ++ */ ++static const struct mtk_thermal_data mt7622_thermal_data = { ++ .auxadc_channel = MT7622_TEMP_AUXADC_CHANNEL, ++ .num_banks = MT7622_NUM_ZONES, ++ .num_sensors = MT7622_NUM_SENSORS, ++ .vts_index = mt7622_vts_index, ++ .cali_val = MT7622_CALIBRATION, ++ .num_controller = MT7622_NUM_CONTROLLER, ++ .controller_offset = mt7622_tc_offset, ++ .need_switch_bank = true, ++ .bank_data = { ++ { ++ .num_sensors = 1, ++ .sensors = mt7622_bank_data, ++ }, ++ }, ++ .msr = mt7622_msr, ++ .adcpnp = mt7622_adcpnp, ++ .sensor_mux_values = mt7622_mux_values, ++ .version = MTK_THERMAL_V2, ++}; ++ ++/* ++ * The MT8183 thermal controller has one bank for the current SW framework. ++ * The MT8183 has a total of 6 temperature sensors. ++ * There are two thermal controller to control the six sensor. ++ * The first one bind 2 sensor, and the other bind 4 sensors. ++ * The thermal core only gets the maximum temperature of all sensor, so ++ * the bank concept wouldn't be necessary here. However, the SVS (Smart ++ * Voltage Scaling) unit makes its decisions based on the same bank ++ * data, and this indeed needs the temperatures of the individual banks ++ * for making better decisions. ++ */ ++static const struct mtk_thermal_data mt8183_thermal_data = { ++ .auxadc_channel = MT8183_TEMP_AUXADC_CHANNEL, ++ .num_banks = MT8183_NUM_ZONES, ++ .num_sensors = MT8183_NUM_SENSORS, ++ .vts_index = mt8183_vts_index, ++ .cali_val = MT8183_CALIBRATION, ++ .num_controller = MT8183_NUM_CONTROLLER, ++ .controller_offset = mt8183_tc_offset, ++ .need_switch_bank = false, ++ .bank_data = { ++ { ++ .num_sensors = 6, ++ .sensors = mt8183_bank_data, ++ }, ++ }, ++ ++ .msr = mt8183_msr, ++ .adcpnp = mt8183_adcpnp, ++ .sensor_mux_values = mt8183_mux_values, ++ .version = MTK_THERMAL_V1, ++}; ++ ++/* ++ * MT7986 uses AUXADC Channel 11 for raw data access. ++ */ ++static const struct mtk_thermal_data mt7986_thermal_data = { ++ .auxadc_channel = MT7986_TEMP_AUXADC_CHANNEL, ++ .num_banks = MT7986_NUM_ZONES, ++ .num_sensors = MT7986_NUM_SENSORS, ++ .vts_index = mt7986_vts_index, ++ .cali_val = MT7986_CALIBRATION, ++ .num_controller = MT7986_NUM_CONTROLLER, ++ .controller_offset = mt7986_tc_offset, ++ .need_switch_bank = true, ++ .bank_data = { ++ { ++ .num_sensors = 1, ++ .sensors = mt7986_bank_data, ++ }, ++ }, ++ .msr = mt7986_msr, ++ .adcpnp = mt7986_adcpnp, ++ .sensor_mux_values = mt7986_mux_values, ++ .version = MTK_THERMAL_V3, ++}; ++ ++/** ++ * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius ++ * @mt: The thermal controller ++ * @sensno: sensor number ++ * @raw: raw ADC value ++ * ++ * This converts the raw ADC value to mcelsius using the SoC specific ++ * calibration constants ++ */ ++static int raw_to_mcelsius_v1(struct mtk_thermal *mt, int sensno, s32 raw) ++{ ++ s32 tmp; ++ ++ raw &= 0xfff; ++ ++ tmp = 203450520 << 3; ++ tmp /= mt->conf->cali_val + mt->o_slope; ++ tmp /= 10000 + mt->adc_ge; ++ tmp *= raw - mt->vts[sensno] - 3350; ++ tmp >>= 3; ++ ++ return mt->degc_cali * 500 - tmp; ++} ++ ++static int raw_to_mcelsius_v2(struct mtk_thermal *mt, int sensno, s32 raw) ++{ ++ s32 format_1; ++ s32 format_2; ++ s32 g_oe; ++ s32 g_gain; ++ s32 g_x_roomt; ++ s32 tmp; ++ ++ if (raw == 0) ++ return 0; ++ ++ raw &= 0xfff; ++ g_gain = 10000 + (((mt->adc_ge - 512) * 10000) >> 12); ++ g_oe = mt->adc_oe - 512; ++ format_1 = mt->vts[VTS2] + 3105 - g_oe; ++ format_2 = (mt->degc_cali * 10) >> 1; ++ g_x_roomt = (((format_1 * 10000) >> 12) * 10000) / g_gain; ++ ++ tmp = (((((raw - g_oe) * 10000) >> 12) * 10000) / g_gain) - g_x_roomt; ++ tmp = tmp * 10 * 100 / 11; ++ ++ if (mt->o_slope_sign == 0) ++ tmp = tmp / (165 - mt->o_slope); ++ else ++ tmp = tmp / (165 + mt->o_slope); ++ ++ return (format_2 - tmp) * 100; ++} ++ ++static int raw_to_mcelsius_v3(struct mtk_thermal *mt, int sensno, s32 raw) ++{ ++ s32 tmp; ++ ++ if (raw == 0) ++ return 0; ++ ++ raw &= 0xfff; ++ tmp = 100000 * 15 / 16 * 10000; ++ tmp /= 4096 - 512 + mt->adc_ge; ++ tmp /= 1490; ++ tmp *= raw - mt->vts[sensno] - 2900; ++ ++ return mt->degc_cali * 500 - tmp; ++} ++ ++/** ++ * mtk_thermal_get_bank - get bank ++ * @bank: The bank ++ * ++ * The bank registers are banked, we have to select a bank in the ++ * PTPCORESEL register to access it. ++ */ ++static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank) ++{ ++ struct mtk_thermal *mt = bank->mt; ++ u32 val; ++ ++ if (mt->conf->need_switch_bank) { ++ mutex_lock(&mt->lock); ++ ++ val = readl(mt->thermal_base + PTPCORESEL); ++ val &= ~0xf; ++ val |= bank->id; ++ writel(val, mt->thermal_base + PTPCORESEL); ++ } ++} ++ ++/** ++ * mtk_thermal_put_bank - release bank ++ * @bank: The bank ++ * ++ * release a bank previously taken with mtk_thermal_get_bank, ++ */ ++static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank) ++{ ++ struct mtk_thermal *mt = bank->mt; ++ ++ if (mt->conf->need_switch_bank) ++ mutex_unlock(&mt->lock); ++} ++ ++/** ++ * mtk_thermal_bank_temperature - get the temperature of a bank ++ * @bank: The bank ++ * ++ * The temperature of a bank is considered the maximum temperature of ++ * the sensors associated to the bank. ++ */ ++static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) ++{ ++ struct mtk_thermal *mt = bank->mt; ++ const struct mtk_thermal_data *conf = mt->conf; ++ int i, temp = INT_MIN, max = INT_MIN; ++ u32 raw; ++ ++ for (i = 0; i < conf->bank_data[bank->id].num_sensors; i++) { ++ raw = readl(mt->thermal_base + conf->msr[i]); ++ ++ temp = mt->raw_to_mcelsius( ++ mt, conf->bank_data[bank->id].sensors[i], raw); ++ ++ ++ /* ++ * The first read of a sensor often contains very high bogus ++ * temperature value. Filter these out so that the system does ++ * not immediately shut down. ++ */ ++ if (temp > 200000) ++ temp = 0; ++ ++ if (temp > max) ++ max = temp; ++ } ++ ++ return max; ++} ++ ++static int mtk_read_temp(struct thermal_zone_device *tz, int *temperature) ++{ ++ struct mtk_thermal *mt = tz->devdata; ++ int i; ++ int tempmax = INT_MIN; ++ ++ for (i = 0; i < mt->conf->num_banks; i++) { ++ struct mtk_thermal_bank *bank = &mt->banks[i]; ++ ++ mtk_thermal_get_bank(bank); ++ ++ tempmax = max(tempmax, mtk_thermal_bank_temperature(bank)); ++ ++ mtk_thermal_put_bank(bank); ++ } ++ ++ *temperature = tempmax; ++ ++ return 0; ++} ++ ++static const struct thermal_zone_device_ops mtk_thermal_ops = { ++ .get_temp = mtk_read_temp, ++}; ++ ++static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, ++ u32 apmixed_phys_base, u32 auxadc_phys_base, ++ int ctrl_id) ++{ ++ struct mtk_thermal_bank *bank = &mt->banks[num]; ++ const struct mtk_thermal_data *conf = mt->conf; ++ int i; ++ ++ int offset = mt->conf->controller_offset[ctrl_id]; ++ void __iomem *controller_base = mt->thermal_base + offset; ++ ++ bank->id = num; ++ bank->mt = mt; ++ ++ mtk_thermal_get_bank(bank); ++ ++ /* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */ ++ writel(TEMP_MONCTL1_PERIOD_UNIT(12), controller_base + TEMP_MONCTL1); ++ ++ /* ++ * filt interval is 1 * 46.540us = 46.54us, ++ * sen interval is 429 * 46.540us = 19.96ms ++ */ ++ writel(TEMP_MONCTL2_FILTER_INTERVAL(1) | ++ TEMP_MONCTL2_SENSOR_INTERVAL(429), ++ controller_base + TEMP_MONCTL2); ++ ++ /* poll is set to 10u */ ++ writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768), ++ controller_base + TEMP_AHBPOLL); ++ ++ /* temperature sampling control, 1 sample */ ++ writel(0x0, controller_base + TEMP_MSRCTL0); ++ ++ /* exceed this polling time, IRQ would be inserted */ ++ writel(0xffffffff, controller_base + TEMP_AHBTO); ++ ++ /* number of interrupts per event, 1 is enough */ ++ writel(0x0, controller_base + TEMP_MONIDET0); ++ writel(0x0, controller_base + TEMP_MONIDET1); ++ ++ /* ++ * The MT8173 thermal controller does not have its own ADC. Instead it ++ * uses AHB bus accesses to control the AUXADC. To do this the thermal ++ * controller has to be programmed with the physical addresses of the ++ * AUXADC registers and with the various bit positions in the AUXADC. ++ * Also the thermal controller controls a mux in the APMIXEDSYS register ++ * space. ++ */ ++ ++ /* ++ * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0) ++ * automatically by hw ++ */ ++ writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCMUX); ++ ++ /* AHB address for auxadc mux selection */ ++ writel(auxadc_phys_base + AUXADC_CON1_CLR_V, ++ controller_base + TEMP_ADCMUXADDR); ++ ++ if (mt->conf->version == MTK_THERMAL_V1) { ++ /* AHB address for pnp sensor mux selection */ ++ writel(apmixed_phys_base + APMIXED_SYS_TS_CON1, ++ controller_base + TEMP_PNPMUXADDR); ++ } ++ ++ /* AHB value for auxadc enable */ ++ writel(BIT(conf->auxadc_channel), controller_base + TEMP_ADCEN); ++ ++ /* AHB address for auxadc enable (channel 0 immediate mode selected) */ ++ writel(auxadc_phys_base + AUXADC_CON1_SET_V, ++ controller_base + TEMP_ADCENADDR); ++ ++ /* AHB address for auxadc valid bit */ ++ writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel), ++ controller_base + TEMP_ADCVALIDADDR); ++ ++ /* AHB address for auxadc voltage output */ ++ writel(auxadc_phys_base + AUXADC_DATA(conf->auxadc_channel), ++ controller_base + TEMP_ADCVOLTADDR); ++ ++ /* read valid & voltage are at the same register */ ++ writel(0x0, controller_base + TEMP_RDCTRL); ++ ++ /* indicate where the valid bit is */ ++ writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12), ++ controller_base + TEMP_ADCVALIDMASK); ++ ++ /* no shift */ ++ writel(0x0, controller_base + TEMP_ADCVOLTAGESHIFT); ++ ++ /* enable auxadc mux write transaction */ ++ writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE, ++ controller_base + TEMP_ADCWRITECTRL); ++ ++ for (i = 0; i < conf->bank_data[num].num_sensors; i++) ++ writel(conf->sensor_mux_values[conf->bank_data[num].sensors[i]], ++ mt->thermal_base + conf->adcpnp[i]); ++ ++ writel((1 << conf->bank_data[num].num_sensors) - 1, ++ controller_base + TEMP_MONCTL0); ++ ++ writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE | ++ TEMP_ADCWRITECTRL_ADC_MUX_WRITE, ++ controller_base + TEMP_ADCWRITECTRL); ++ ++ mtk_thermal_put_bank(bank); ++} ++ ++static u64 of_get_phys_base(struct device_node *np) ++{ ++ u64 size64; ++ const __be32 *regaddr_p; ++ ++ regaddr_p = of_get_address(np, 0, &size64, NULL); ++ if (!regaddr_p) ++ return OF_BAD_ADDR; ++ ++ return of_translate_address(np, regaddr_p); ++} ++ ++static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf) ++{ ++ int i; ++ ++ if (!(buf[0] & CALIB_BUF0_VALID_V1)) ++ return -EINVAL; ++ ++ mt->adc_ge = CALIB_BUF1_ADC_GE_V1(buf[1]); ++ ++ for (i = 0; i < mt->conf->num_sensors; i++) { ++ switch (mt->conf->vts_index[i]) { ++ case VTS1: ++ mt->vts[VTS1] = CALIB_BUF0_VTS_TS1_V1(buf[0]); ++ break; ++ case VTS2: ++ mt->vts[VTS2] = CALIB_BUF0_VTS_TS2_V1(buf[0]); ++ break; ++ case VTS3: ++ mt->vts[VTS3] = CALIB_BUF1_VTS_TS3_V1(buf[1]); ++ break; ++ case VTS4: ++ mt->vts[VTS4] = CALIB_BUF2_VTS_TS4_V1(buf[2]); ++ break; ++ case VTS5: ++ mt->vts[VTS5] = CALIB_BUF2_VTS_TS5_V1(buf[2]); ++ break; ++ case VTSABB: ++ mt->vts[VTSABB] = ++ CALIB_BUF2_VTS_TSABB_V1(buf[2]); ++ break; ++ default: ++ break; ++ } ++ } ++ ++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V1(buf[0]); ++ if (CALIB_BUF1_ID_V1(buf[1]) & ++ CALIB_BUF0_O_SLOPE_SIGN_V1(buf[0])) ++ mt->o_slope = -CALIB_BUF0_O_SLOPE_V1(buf[0]); ++ else ++ mt->o_slope = CALIB_BUF0_O_SLOPE_V1(buf[0]); ++ ++ return 0; ++} ++ ++static int mtk_thermal_extract_efuse_v2(struct mtk_thermal *mt, u32 *buf) ++{ ++ if (!CALIB_BUF1_VALID_V2(buf[1])) ++ return -EINVAL; ++ ++ mt->adc_oe = CALIB_BUF0_ADC_OE_V2(buf[0]); ++ mt->adc_ge = CALIB_BUF0_ADC_GE_V2(buf[0]); ++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V2(buf[0]); ++ mt->o_slope = CALIB_BUF0_O_SLOPE_V2(buf[0]); ++ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V2(buf[1]); ++ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V2(buf[1]); ++ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V2(buf[1]); ++ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V2(buf[1]); ++ ++ return 0; ++} ++ ++static int mtk_thermal_extract_efuse_v3(struct mtk_thermal *mt, u32 *buf) ++{ ++ if (!CALIB_BUF1_VALID_V3(buf[1])) ++ return -EINVAL; ++ ++ mt->adc_ge = CALIB_BUF0_ADC_GE_V3(buf[0]); ++ mt->degc_cali = CALIB_BUF0_DEGC_CALI_V3(buf[0]); ++ mt->o_slope = CALIB_BUF0_O_SLOPE_V3(buf[0]); ++ mt->vts[VTS1] = CALIB_BUF1_VTS_TS1_V3(buf[1]); ++ mt->vts[VTS2] = CALIB_BUF1_VTS_TS2_V3(buf[1]); ++ mt->vts[VTSABB] = CALIB_BUF1_VTS_TSABB_V3(buf[1]); ++ mt->o_slope_sign = CALIB_BUF1_O_SLOPE_SIGN_V3(buf[1]); ++ ++ if (CALIB_BUF1_ID_V3(buf[1]) == 0) ++ mt->o_slope = 0; ++ ++ return 0; ++} ++ ++static int mtk_thermal_get_calibration_data(struct device *dev, ++ struct mtk_thermal *mt) ++{ ++ struct nvmem_cell *cell; ++ u32 *buf; ++ size_t len; ++ int i, ret = 0; ++ ++ /* Start with default values */ ++ mt->adc_ge = 512; ++ mt->adc_oe = 512; ++ for (i = 0; i < mt->conf->num_sensors; i++) ++ mt->vts[i] = 260; ++ mt->degc_cali = 40; ++ mt->o_slope = 0; ++ ++ cell = nvmem_cell_get(dev, "calibration-data"); ++ if (IS_ERR(cell)) { ++ if (PTR_ERR(cell) == -EPROBE_DEFER) ++ return PTR_ERR(cell); ++ return 0; ++ } ++ ++ buf = (u32 *)nvmem_cell_read(cell, &len); ++ ++ nvmem_cell_put(cell); ++ ++ if (IS_ERR(buf)) ++ return PTR_ERR(buf); ++ ++ if (len < 3 * sizeof(u32)) { ++ dev_warn(dev, "invalid calibration data\n"); ++ ret = -EINVAL; ++ goto out; ++ } ++ ++ switch (mt->conf->version) { ++ case MTK_THERMAL_V1: ++ ret = mtk_thermal_extract_efuse_v1(mt, buf); ++ break; ++ case MTK_THERMAL_V2: ++ ret = mtk_thermal_extract_efuse_v2(mt, buf); ++ break; ++ case MTK_THERMAL_V3: ++ ret = mtk_thermal_extract_efuse_v3(mt, buf); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ if (ret) { ++ dev_info(dev, "Device not calibrated, using default calibration values\n"); ++ ret = 0; ++ } ++ ++out: ++ kfree(buf); ++ ++ return ret; ++} ++ ++static const struct of_device_id mtk_thermal_of_match[] = { ++ { ++ .compatible = "mediatek,mt8173-thermal", ++ .data = (void *)&mt8173_thermal_data, ++ }, ++ { ++ .compatible = "mediatek,mt2701-thermal", ++ .data = (void *)&mt2701_thermal_data, ++ }, ++ { ++ .compatible = "mediatek,mt2712-thermal", ++ .data = (void *)&mt2712_thermal_data, ++ }, ++ { ++ .compatible = "mediatek,mt7622-thermal", ++ .data = (void *)&mt7622_thermal_data, ++ }, ++ { ++ .compatible = "mediatek,mt7986-thermal", ++ .data = (void *)&mt7986_thermal_data, ++ }, ++ { ++ .compatible = "mediatek,mt8183-thermal", ++ .data = (void *)&mt8183_thermal_data, ++ }, { ++ }, ++}; ++MODULE_DEVICE_TABLE(of, mtk_thermal_of_match); ++ ++static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base) ++{ ++ int tmp; ++ ++ tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1); ++ tmp &= ~(0x37); ++ tmp |= 0x1; ++ writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1); ++ udelay(200); ++} ++ ++static void mtk_thermal_release_periodic_ts(struct mtk_thermal *mt, ++ void __iomem *auxadc_base) ++{ ++ int tmp; ++ ++ writel(0x800, auxadc_base + AUXADC_CON1_SET_V); ++ writel(0x1, mt->thermal_base + TEMP_MONCTL0); ++ tmp = readl(mt->thermal_base + TEMP_MSRCTL1); ++ writel((tmp & (~0x10e)), mt->thermal_base + TEMP_MSRCTL1); ++} ++ ++static int mtk_thermal_probe(struct platform_device *pdev) ++{ ++ int ret, i, ctrl_id; ++ struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node; ++ struct mtk_thermal *mt; ++ u64 auxadc_phys_base, apmixed_phys_base; ++ struct thermal_zone_device *tzdev; ++ void __iomem *apmixed_base, *auxadc_base; ++ ++ mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL); ++ if (!mt) ++ return -ENOMEM; ++ ++ mt->conf = of_device_get_match_data(&pdev->dev); ++ ++ mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm"); ++ if (IS_ERR(mt->clk_peri_therm)) ++ return PTR_ERR(mt->clk_peri_therm); ++ ++ mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc"); ++ if (IS_ERR(mt->clk_auxadc)) ++ return PTR_ERR(mt->clk_auxadc); ++ ++ mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); ++ if (IS_ERR(mt->thermal_base)) ++ return PTR_ERR(mt->thermal_base); ++ ++ ret = mtk_thermal_get_calibration_data(&pdev->dev, mt); ++ if (ret) ++ return ret; ++ ++ mutex_init(&mt->lock); ++ ++ mt->dev = &pdev->dev; ++ ++ auxadc = of_parse_phandle(np, "mediatek,auxadc", 0); ++ if (!auxadc) { ++ dev_err(&pdev->dev, "missing auxadc node\n"); ++ return -ENODEV; ++ } ++ ++ auxadc_base = of_iomap(auxadc, 0); ++ auxadc_phys_base = of_get_phys_base(auxadc); ++ ++ of_node_put(auxadc); ++ ++ if (auxadc_phys_base == OF_BAD_ADDR) { ++ dev_err(&pdev->dev, "Can't get auxadc phys address\n"); ++ return -EINVAL; ++ } ++ ++ apmixedsys = of_parse_phandle(np, "mediatek,apmixedsys", 0); ++ if (!apmixedsys) { ++ dev_err(&pdev->dev, "missing apmixedsys node\n"); ++ return -ENODEV; ++ } ++ ++ apmixed_base = of_iomap(apmixedsys, 0); ++ apmixed_phys_base = of_get_phys_base(apmixedsys); ++ ++ of_node_put(apmixedsys); ++ ++ if (apmixed_phys_base == OF_BAD_ADDR) { ++ dev_err(&pdev->dev, "Can't get auxadc phys address\n"); ++ return -EINVAL; ++ } ++ ++ ret = device_reset_optional(&pdev->dev); ++ if (ret) ++ return ret; ++ ++ ret = clk_prepare_enable(mt->clk_auxadc); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(mt->clk_peri_therm); ++ if (ret) { ++ dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret); ++ goto err_disable_clk_auxadc; ++ } ++ ++ if (mt->conf->version != MTK_THERMAL_V1) { ++ mtk_thermal_turn_on_buffer(apmixed_base); ++ mtk_thermal_release_periodic_ts(mt, auxadc_base); ++ } ++ ++ if (mt->conf->version == MTK_THERMAL_V1) ++ mt->raw_to_mcelsius = raw_to_mcelsius_v1; ++ else if (mt->conf->version == MTK_THERMAL_V2) ++ mt->raw_to_mcelsius = raw_to_mcelsius_v2; ++ else ++ mt->raw_to_mcelsius = raw_to_mcelsius_v3; ++ ++ for (ctrl_id = 0; ctrl_id < mt->conf->num_controller ; ctrl_id++) ++ for (i = 0; i < mt->conf->num_banks; i++) ++ mtk_thermal_init_bank(mt, i, apmixed_phys_base, ++ auxadc_phys_base, ctrl_id); ++ ++ platform_set_drvdata(pdev, mt); ++ ++ tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt, ++ &mtk_thermal_ops); ++ if (IS_ERR(tzdev)) { ++ ret = PTR_ERR(tzdev); ++ goto err_disable_clk_peri_therm; ++ } ++ ++ ret = devm_thermal_add_hwmon_sysfs(tzdev); ++ if (ret) ++ dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs"); ++ ++ return 0; ++ ++err_disable_clk_peri_therm: ++ clk_disable_unprepare(mt->clk_peri_therm); ++err_disable_clk_auxadc: ++ clk_disable_unprepare(mt->clk_auxadc); ++ ++ return ret; ++} ++ ++static int mtk_thermal_remove(struct platform_device *pdev) ++{ ++ struct mtk_thermal *mt = platform_get_drvdata(pdev); ++ ++ clk_disable_unprepare(mt->clk_peri_therm); ++ clk_disable_unprepare(mt->clk_auxadc); ++ ++ return 0; ++} ++ ++static struct platform_driver mtk_thermal_driver = { ++ .probe = mtk_thermal_probe, ++ .remove = mtk_thermal_remove, ++ .driver = { ++ .name = "mtk-thermal", ++ .of_match_table = mtk_thermal_of_match, ++ }, ++}; ++ ++module_platform_driver(mtk_thermal_driver); ++ ++MODULE_AUTHOR("Michael Kao "); ++MODULE_AUTHOR("Louis Yu "); ++MODULE_AUTHOR("Dawei Chien "); ++MODULE_AUTHOR("Sascha Hauer "); ++MODULE_AUTHOR("Hanyi Wu "); ++MODULE_DESCRIPTION("Mediatek thermal driver"); ++MODULE_LICENSE("GPL v2"); diff --git a/target/linux/mediatek/patches-6.1/830-v6.3-06-thermal-drivers-mediatek-Add-the-Low-Voltage-Thermal.patch b/target/linux/mediatek/patches-6.1/830-v6.3-06-thermal-drivers-mediatek-Add-the-Low-Voltage-Thermal.patch new file mode 100644 index 00000000000..2ae3734e409 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.3-06-thermal-drivers-mediatek-Add-the-Low-Voltage-Thermal.patch @@ -0,0 +1,1298 @@ +From 325fadf27b21f7d79843c3cc282b7f3e6620ad3d Mon Sep 17 00:00:00 2001 +From: Balsam CHIHI +Date: Thu, 9 Feb 2023 11:56:26 +0100 +Subject: [PATCH 06/42] thermal/drivers/mediatek: Add the Low Voltage Thermal + Sensor driver + +The Low Voltage Thermal Sensor (LVTS) is a multiple sensors, multi +controllers contained in a thermal domain. + +A thermal domains can be the MCU or the AP. + +Each thermal domains contain up to seven controllers, each thermal +controller handle up to four thermal sensors. + +The LVTS has two Finite State Machines (FSM), one to handle the +functionin temperatures range like hot or cold temperature and another +one to handle monitoring trip point. The FSM notifies via interrupts +when a trip point is crossed. + +The interrupt is managed at the thermal controller level, so when an +interrupt occurs, the driver has to find out which sensor triggered +such an interrupt. + +The sampling of the thermal can be filtered or immediate. For the +former, the LVTS measures several points and applies a low pass +filter. + +Signed-off-by: Balsam CHIHI +Reviewed-by: AngeloGioacchino Del Regno + +On MT8195 Tomato Chromebook: + +Tested-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20230209105628.50294-5-bchihi@baylibre.com +Signed-off-by: Daniel Lezcano +Signed-off-by: Rafael J. Wysocki +--- + drivers/thermal/mediatek/Kconfig | 16 + + drivers/thermal/mediatek/Makefile | 1 + + drivers/thermal/mediatek/lvts_thermal.c | 1224 +++++++++++++++++++++++ + 3 files changed, 1241 insertions(+) + create mode 100644 drivers/thermal/mediatek/lvts_thermal.c + +--- a/drivers/thermal/mediatek/Kconfig ++++ b/drivers/thermal/mediatek/Kconfig +@@ -18,4 +18,20 @@ config MTK_SOC_THERMAL + This driver configures thermal controllers to collect + temperature via AUXADC interface. + ++config MTK_LVTS_THERMAL ++ tristate "LVTS Thermal Driver for MediaTek SoCs" ++ depends on HAS_IOMEM ++ help ++ Enable this option if you want to get SoC temperature ++ information for supported MediaTek platforms. ++ This driver configures LVTS (Low Voltage Thermal Sensor) ++ thermal controllers to collect temperatures via ASIF ++ (Analog Serial Interface). ++ ++config MTK_LVTS_THERMAL_DEBUGFS ++ bool "LVTS thermal debugfs" ++ depends on MTK_LVTS_THERMAL && DEBUG_FS ++ help ++ Enable this option to debug the internals of the device driver. ++ + endif +--- a/drivers/thermal/mediatek/Makefile ++++ b/drivers/thermal/mediatek/Makefile +@@ -1 +1,2 @@ + obj-$(CONFIG_MTK_SOC_THERMAL) += auxadc_thermal.o ++obj-$(CONFIG_MTK_LVTS_THERMAL) += lvts_thermal.o +--- /dev/null ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -0,0 +1,1224 @@ ++// SPDX-License-Identifier: GPL-2.0-only ++/* ++ * Copyright (c) 2023 MediaTek Inc. ++ * Author: Balsam CHIHI ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define LVTS_MONCTL0(__base) (__base + 0x0000) ++#define LVTS_MONCTL1(__base) (__base + 0x0004) ++#define LVTS_MONCTL2(__base) (__base + 0x0008) ++#define LVTS_MONINT(__base) (__base + 0x000C) ++#define LVTS_MONINTSTS(__base) (__base + 0x0010) ++#define LVTS_MONIDET0(__base) (__base + 0x0014) ++#define LVTS_MONIDET1(__base) (__base + 0x0018) ++#define LVTS_MONIDET2(__base) (__base + 0x001C) ++#define LVTS_MONIDET3(__base) (__base + 0x0020) ++#define LVTS_H2NTHRE(__base) (__base + 0x0024) ++#define LVTS_HTHRE(__base) (__base + 0x0028) ++#define LVTS_OFFSETH(__base) (__base + 0x0030) ++#define LVTS_OFFSETL(__base) (__base + 0x0034) ++#define LVTS_MSRCTL0(__base) (__base + 0x0038) ++#define LVTS_MSRCTL1(__base) (__base + 0x003C) ++#define LVTS_TSSEL(__base) (__base + 0x0040) ++#define LVTS_CALSCALE(__base) (__base + 0x0048) ++#define LVTS_ID(__base) (__base + 0x004C) ++#define LVTS_CONFIG(__base) (__base + 0x0050) ++#define LVTS_EDATA00(__base) (__base + 0x0054) ++#define LVTS_EDATA01(__base) (__base + 0x0058) ++#define LVTS_EDATA02(__base) (__base + 0x005C) ++#define LVTS_EDATA03(__base) (__base + 0x0060) ++#define LVTS_MSR0(__base) (__base + 0x0090) ++#define LVTS_MSR1(__base) (__base + 0x0094) ++#define LVTS_MSR2(__base) (__base + 0x0098) ++#define LVTS_MSR3(__base) (__base + 0x009C) ++#define LVTS_IMMD0(__base) (__base + 0x00A0) ++#define LVTS_IMMD1(__base) (__base + 0x00A4) ++#define LVTS_IMMD2(__base) (__base + 0x00A8) ++#define LVTS_IMMD3(__base) (__base + 0x00AC) ++#define LVTS_PROTCTL(__base) (__base + 0x00C0) ++#define LVTS_PROTTA(__base) (__base + 0x00C4) ++#define LVTS_PROTTB(__base) (__base + 0x00C8) ++#define LVTS_PROTTC(__base) (__base + 0x00CC) ++#define LVTS_CLKEN(__base) (__base + 0x00E4) ++ ++#define LVTS_PERIOD_UNIT ((118 * 1000) / (256 * 38)) ++#define LVTS_GROUP_INTERVAL 1 ++#define LVTS_FILTER_INTERVAL 1 ++#define LVTS_SENSOR_INTERVAL 1 ++#define LVTS_HW_FILTER 0x2 ++#define LVTS_TSSEL_CONF 0x13121110 ++#define LVTS_CALSCALE_CONF 0x300 ++#define LVTS_MONINT_CONF 0x9FBF7BDE ++ ++#define LVTS_INT_SENSOR0 0x0009001F ++#define LVTS_INT_SENSOR1 0X000881F0 ++#define LVTS_INT_SENSOR2 0x00247C00 ++#define LVTS_INT_SENSOR3 0x1FC00000 ++ ++#define LVTS_SENSOR_MAX 4 ++#define LVTS_GOLDEN_TEMP_MAX 62 ++#define LVTS_GOLDEN_TEMP_DEFAULT 50 ++#define LVTS_COEFF_A -250460 ++#define LVTS_COEFF_B 250460 ++ ++#define LVTS_MSR_IMMEDIATE_MODE 0 ++#define LVTS_MSR_FILTERED_MODE 1 ++ ++#define LVTS_HW_SHUTDOWN_MT8195 105000 ++ ++static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT; ++static int coeff_b = LVTS_COEFF_B; ++ ++struct lvts_sensor_data { ++ int dt_id; ++}; ++ ++struct lvts_ctrl_data { ++ struct lvts_sensor_data lvts_sensor[LVTS_SENSOR_MAX]; ++ int cal_offset[LVTS_SENSOR_MAX]; ++ int hw_tshut_temp; ++ int num_lvts_sensor; ++ int offset; ++ int mode; ++}; ++ ++struct lvts_data { ++ const struct lvts_ctrl_data *lvts_ctrl; ++ int num_lvts_ctrl; ++}; ++ ++struct lvts_sensor { ++ struct thermal_zone_device *tz; ++ void __iomem *msr; ++ void __iomem *base; ++ int id; ++ int dt_id; ++}; ++ ++struct lvts_ctrl { ++ struct lvts_sensor sensors[LVTS_SENSOR_MAX]; ++ u32 calibration[LVTS_SENSOR_MAX]; ++ u32 hw_tshut_raw_temp; ++ int num_lvts_sensor; ++ int mode; ++ void __iomem *base; ++}; ++ ++struct lvts_domain { ++ struct lvts_ctrl *lvts_ctrl; ++ struct reset_control *reset; ++ struct clk *clk; ++ int num_lvts_ctrl; ++ void __iomem *base; ++ size_t calib_len; ++ u8 *calib; ++#ifdef CONFIG_DEBUG_FS ++ struct dentry *dom_dentry; ++#endif ++}; ++ ++#ifdef CONFIG_MTK_LVTS_THERMAL_DEBUGFS ++ ++#define LVTS_DEBUG_FS_REGS(__reg) \ ++{ \ ++ .name = __stringify(__reg), \ ++ .offset = __reg(0), \ ++} ++ ++static const struct debugfs_reg32 lvts_regs[] = { ++ LVTS_DEBUG_FS_REGS(LVTS_MONCTL0), ++ LVTS_DEBUG_FS_REGS(LVTS_MONCTL1), ++ LVTS_DEBUG_FS_REGS(LVTS_MONCTL2), ++ LVTS_DEBUG_FS_REGS(LVTS_MONINT), ++ LVTS_DEBUG_FS_REGS(LVTS_MONINTSTS), ++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET0), ++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET1), ++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET2), ++ LVTS_DEBUG_FS_REGS(LVTS_MONIDET3), ++ LVTS_DEBUG_FS_REGS(LVTS_H2NTHRE), ++ LVTS_DEBUG_FS_REGS(LVTS_HTHRE), ++ LVTS_DEBUG_FS_REGS(LVTS_OFFSETH), ++ LVTS_DEBUG_FS_REGS(LVTS_OFFSETL), ++ LVTS_DEBUG_FS_REGS(LVTS_MSRCTL0), ++ LVTS_DEBUG_FS_REGS(LVTS_MSRCTL1), ++ LVTS_DEBUG_FS_REGS(LVTS_TSSEL), ++ LVTS_DEBUG_FS_REGS(LVTS_CALSCALE), ++ LVTS_DEBUG_FS_REGS(LVTS_ID), ++ LVTS_DEBUG_FS_REGS(LVTS_CONFIG), ++ LVTS_DEBUG_FS_REGS(LVTS_EDATA00), ++ LVTS_DEBUG_FS_REGS(LVTS_EDATA01), ++ LVTS_DEBUG_FS_REGS(LVTS_EDATA02), ++ LVTS_DEBUG_FS_REGS(LVTS_EDATA03), ++ LVTS_DEBUG_FS_REGS(LVTS_MSR0), ++ LVTS_DEBUG_FS_REGS(LVTS_MSR1), ++ LVTS_DEBUG_FS_REGS(LVTS_MSR2), ++ LVTS_DEBUG_FS_REGS(LVTS_MSR3), ++ LVTS_DEBUG_FS_REGS(LVTS_IMMD0), ++ LVTS_DEBUG_FS_REGS(LVTS_IMMD1), ++ LVTS_DEBUG_FS_REGS(LVTS_IMMD2), ++ LVTS_DEBUG_FS_REGS(LVTS_IMMD3), ++ LVTS_DEBUG_FS_REGS(LVTS_PROTCTL), ++ LVTS_DEBUG_FS_REGS(LVTS_PROTTA), ++ LVTS_DEBUG_FS_REGS(LVTS_PROTTB), ++ LVTS_DEBUG_FS_REGS(LVTS_PROTTC), ++ LVTS_DEBUG_FS_REGS(LVTS_CLKEN), ++}; ++ ++static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td) ++{ ++ struct debugfs_regset32 *regset; ++ struct lvts_ctrl *lvts_ctrl; ++ struct dentry *dentry; ++ char name[64]; ++ int i; ++ ++ lvts_td->dom_dentry = debugfs_create_dir(dev_name(dev), NULL); ++ if (!lvts_td->dom_dentry) ++ return 0; ++ ++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) { ++ ++ lvts_ctrl = &lvts_td->lvts_ctrl[i]; ++ ++ sprintf(name, "controller%d", i); ++ dentry = debugfs_create_dir(name, lvts_td->dom_dentry); ++ if (!dentry) ++ continue; ++ ++ regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL); ++ if (!regset) ++ continue; ++ ++ regset->base = lvts_ctrl->base; ++ regset->regs = lvts_regs; ++ regset->nregs = ARRAY_SIZE(lvts_regs); ++ ++ debugfs_create_regset32("registers", 0400, dentry, regset); ++ } ++ ++ return 0; ++} ++ ++static void lvts_debugfs_exit(struct lvts_domain *lvts_td) ++{ ++ debugfs_remove_recursive(lvts_td->dom_dentry); ++} ++ ++#else ++ ++static inline int lvts_debugfs_init(struct device *dev, ++ struct lvts_domain *lvts_td) ++{ ++ return 0; ++} ++ ++static void lvts_debugfs_exit(struct lvts_domain *lvts_td) { } ++ ++#endif ++ ++static int lvts_raw_to_temp(u32 raw_temp) ++{ ++ int temperature; ++ ++ temperature = ((s64)(raw_temp & 0xFFFF) * LVTS_COEFF_A) >> 14; ++ temperature += coeff_b; ++ ++ return temperature; ++} ++ ++static u32 lvts_temp_to_raw(int temperature) ++{ ++ u32 raw_temp = ((s64)(coeff_b - temperature)) << 14; ++ ++ raw_temp = div_s64(raw_temp, -LVTS_COEFF_A); ++ ++ return raw_temp; ++} ++ ++static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) ++{ ++ struct lvts_sensor *lvts_sensor = tz->devdata; ++ void __iomem *msr = lvts_sensor->msr; ++ u32 value; ++ ++ /* ++ * Measurement registers: ++ * ++ * LVTS_MSR[0-3] / LVTS_IMMD[0-3] ++ * ++ * Bits: ++ * ++ * 32-17: Unused ++ * 16 : Valid temperature ++ * 15-0 : Raw temperature ++ */ ++ value = readl(msr); ++ ++ /* ++ * As the thermal zone temperature will read before the ++ * hardware sensor is fully initialized, we have to check the ++ * validity of the temperature returned when reading the ++ * measurement register. The thermal controller will set the ++ * valid bit temperature only when it is totally initialized. ++ * ++ * Otherwise, we may end up with garbage values out of the ++ * functionning temperature and directly jump to a system ++ * shutdown. ++ */ ++ if (!(value & BIT(16))) ++ return -EAGAIN; ++ ++ *temp = lvts_raw_to_temp(value & 0xFFFF); ++ ++ return 0; ++} ++ ++static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) ++{ ++ struct lvts_sensor *lvts_sensor = tz->devdata; ++ void __iomem *base = lvts_sensor->base; ++ u32 raw_low = lvts_temp_to_raw(low); ++ u32 raw_high = lvts_temp_to_raw(high); ++ ++ /* ++ * Hot to normal temperature threshold ++ * ++ * LVTS_H2NTHRE ++ * ++ * Bits: ++ * ++ * 14-0 : Raw temperature for threshold ++ */ ++ if (low != -INT_MAX) { ++ dev_dbg(&tz->device, "Setting low limit temperature interrupt: %d\n", low); ++ writel(raw_low, LVTS_H2NTHRE(base)); ++ } ++ ++ /* ++ * Hot temperature threshold ++ * ++ * LVTS_HTHRE ++ * ++ * Bits: ++ * ++ * 14-0 : Raw temperature for threshold ++ */ ++ dev_dbg(&tz->device, "Setting high limit temperature interrupt: %d\n", high); ++ writel(raw_high, LVTS_HTHRE(base)); ++ ++ return 0; ++} ++ ++static irqreturn_t lvts_ctrl_irq_handler(struct lvts_ctrl *lvts_ctrl) ++{ ++ irqreturn_t iret = IRQ_NONE; ++ u32 value; ++ u32 masks[] = { ++ LVTS_INT_SENSOR0, ++ LVTS_INT_SENSOR1, ++ LVTS_INT_SENSOR2, ++ LVTS_INT_SENSOR3 ++ }; ++ int i; ++ ++ /* ++ * Interrupt monitoring status ++ * ++ * LVTS_MONINTST ++ * ++ * Bits: ++ * ++ * 31 : Interrupt for stage 3 ++ * 30 : Interrupt for stage 2 ++ * 29 : Interrupt for state 1 ++ * 28 : Interrupt using filter on sensor 3 ++ * ++ * 27 : Interrupt using immediate on sensor 3 ++ * 26 : Interrupt normal to hot on sensor 3 ++ * 25 : Interrupt high offset on sensor 3 ++ * 24 : Interrupt low offset on sensor 3 ++ * ++ * 23 : Interrupt hot threshold on sensor 3 ++ * 22 : Interrupt cold threshold on sensor 3 ++ * 21 : Interrupt using filter on sensor 2 ++ * 20 : Interrupt using filter on sensor 1 ++ * ++ * 19 : Interrupt using filter on sensor 0 ++ * 18 : Interrupt using immediate on sensor 2 ++ * 17 : Interrupt using immediate on sensor 1 ++ * 16 : Interrupt using immediate on sensor 0 ++ * ++ * 15 : Interrupt device access timeout interrupt ++ * 14 : Interrupt normal to hot on sensor 2 ++ * 13 : Interrupt high offset interrupt on sensor 2 ++ * 12 : Interrupt low offset interrupt on sensor 2 ++ * ++ * 11 : Interrupt hot threshold on sensor 2 ++ * 10 : Interrupt cold threshold on sensor 2 ++ * 9 : Interrupt normal to hot on sensor 1 ++ * 8 : Interrupt high offset interrupt on sensor 1 ++ * ++ * 7 : Interrupt low offset interrupt on sensor 1 ++ * 6 : Interrupt hot threshold on sensor 1 ++ * 5 : Interrupt cold threshold on sensor 1 ++ * 4 : Interrupt normal to hot on sensor 0 ++ * ++ * 3 : Interrupt high offset interrupt on sensor 0 ++ * 2 : Interrupt low offset interrupt on sensor 0 ++ * 1 : Interrupt hot threshold on sensor 0 ++ * 0 : Interrupt cold threshold on sensor 0 ++ * ++ * We are interested in the sensor(s) responsible of the ++ * interrupt event. We update the thermal framework with the ++ * thermal zone associated with the sensor. The framework will ++ * take care of the rest whatever the kind of interrupt, we ++ * are only interested in which sensor raised the interrupt. ++ * ++ * sensor 3 interrupt: 0001 1111 1100 0000 0000 0000 0000 0000 ++ * => 0x1FC00000 ++ * sensor 2 interrupt: 0000 0000 0010 0100 0111 1100 0000 0000 ++ * => 0x00247C00 ++ * sensor 1 interrupt: 0000 0000 0001 0001 0000 0011 1110 0000 ++ * => 0X000881F0 ++ * sensor 0 interrupt: 0000 0000 0000 1001 0000 0000 0001 1111 ++ * => 0x0009001F ++ */ ++ value = readl(LVTS_MONINTSTS(lvts_ctrl->base)); ++ ++ /* ++ * Let's figure out which sensors raised the interrupt ++ * ++ * NOTE: the masks array must be ordered with the index ++ * corresponding to the sensor id eg. index=0, mask for ++ * sensor0. ++ */ ++ for (i = 0; i < ARRAY_SIZE(masks); i++) { ++ ++ if (!(value & masks[i])) ++ continue; ++ ++ thermal_zone_device_update(lvts_ctrl->sensors[i].tz, ++ THERMAL_TRIP_VIOLATED); ++ iret = IRQ_HANDLED; ++ } ++ ++ /* ++ * Write back to clear the interrupt status (W1C) ++ */ ++ writel(value, LVTS_MONINTSTS(lvts_ctrl->base)); ++ ++ return iret; ++} ++ ++/* ++ * Temperature interrupt handler. Even if the driver supports more ++ * interrupt modes, we use the interrupt when the temperature crosses ++ * the hot threshold the way up and the way down (modulo the ++ * hysteresis). ++ * ++ * Each thermal domain has a couple of interrupts, one for hardware ++ * reset and another one for all the thermal events happening on the ++ * different sensors. ++ * ++ * The interrupt is configured for thermal events when crossing the ++ * hot temperature limit. At each interrupt, we check in every ++ * controller if there is an interrupt pending. ++ */ ++static irqreturn_t lvts_irq_handler(int irq, void *data) ++{ ++ struct lvts_domain *lvts_td = data; ++ irqreturn_t aux, iret = IRQ_NONE; ++ int i; ++ ++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) { ++ ++ aux = lvts_ctrl_irq_handler(lvts_td->lvts_ctrl); ++ if (aux != IRQ_HANDLED) ++ continue; ++ ++ iret = IRQ_HANDLED; ++ } ++ ++ return iret; ++} ++ ++static struct thermal_zone_device_ops lvts_ops = { ++ .get_temp = lvts_get_temp, ++ .set_trips = lvts_set_trips, ++}; ++ ++static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, ++ const struct lvts_ctrl_data *lvts_ctrl_data) ++{ ++ struct lvts_sensor *lvts_sensor = lvts_ctrl->sensors; ++ void __iomem *msr_regs[] = { ++ LVTS_MSR0(lvts_ctrl->base), ++ LVTS_MSR1(lvts_ctrl->base), ++ LVTS_MSR2(lvts_ctrl->base), ++ LVTS_MSR3(lvts_ctrl->base) ++ }; ++ ++ void __iomem *imm_regs[] = { ++ LVTS_IMMD0(lvts_ctrl->base), ++ LVTS_IMMD1(lvts_ctrl->base), ++ LVTS_IMMD2(lvts_ctrl->base), ++ LVTS_IMMD3(lvts_ctrl->base) ++ }; ++ ++ int i; ++ ++ for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) { ++ ++ int dt_id = lvts_ctrl_data->lvts_sensor[i].dt_id; ++ ++ /* ++ * At this point, we don't know which id matches which ++ * sensor. Let's set arbitrally the id from the index. ++ */ ++ lvts_sensor[i].id = i; ++ ++ /* ++ * The thermal zone registration will set the trip ++ * point interrupt in the thermal controller ++ * register. But this one will be reset in the ++ * initialization after. So we need to post pone the ++ * thermal zone creation after the controller is ++ * setup. For this reason, we store the device tree ++ * node id from the data in the sensor structure ++ */ ++ lvts_sensor[i].dt_id = dt_id; ++ ++ /* ++ * We assign the base address of the thermal ++ * controller as a back pointer. So it will be ++ * accessible from the different thermal framework ops ++ * as we pass the lvts_sensor pointer as thermal zone ++ * private data. ++ */ ++ lvts_sensor[i].base = lvts_ctrl->base; ++ ++ /* ++ * Each sensor has its own register address to read from. ++ */ ++ lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ? ++ imm_regs[i] : msr_regs[i]; ++ }; ++ ++ lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor; ++ ++ return 0; ++} ++ ++/* ++ * The efuse blob values follows the sensor enumeration per thermal ++ * controller. The decoding of the stream is as follow: ++ * ++ * <--?-> <----big0 ???---> <-sensor0-> <-0-> ++ * ------------------------------------------ ++ * index in the stream: : | 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | ++ * ------------------------------------------ ++ * ++ * <--sensor1--><-0-> <----big1 ???---> <-sen ++ * ------------------------------------------ ++ * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD | ++ * ------------------------------------------ ++ * ++ * sor0-> <-0-> <-sensor1-> <-0-> .......... ++ * ------------------------------------------ ++ * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD | ++ * ------------------------------------------ ++ * ++ * And so on ... ++ * ++ * The data description gives the offset of the calibration data in ++ * this bytes stream for each sensor. ++ * ++ * Each thermal controller can handle up to 4 sensors max, we don't ++ * care if there are less as the array of calibration is sized to 4 ++ * anyway. The unused sensor slot will be zeroed. ++ */ ++static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, ++ const struct lvts_ctrl_data *lvts_ctrl_data, ++ u8 *efuse_calibration) ++{ ++ int i; ++ ++ for (i = 0; i < lvts_ctrl_data->num_lvts_sensor; i++) ++ memcpy(&lvts_ctrl->calibration[i], ++ efuse_calibration + lvts_ctrl_data->cal_offset[i], 2); ++ ++ return 0; ++} ++ ++/* ++ * The efuse bytes stream can be split into different chunk of ++ * nvmems. This function reads and concatenate those into a single ++ * buffer so it can be read sequentially when initializing the ++ * calibration data. ++ */ ++static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td, ++ const struct lvts_data *lvts_data) ++{ ++ struct device_node *np = dev_of_node(dev); ++ struct nvmem_cell *cell; ++ struct property *prop; ++ const char *cell_name; ++ ++ of_property_for_each_string(np, "nvmem-cell-names", prop, cell_name) { ++ size_t len; ++ u8 *efuse; ++ ++ cell = of_nvmem_cell_get(np, cell_name); ++ if (IS_ERR(cell)) { ++ dev_err(dev, "Failed to get cell '%s'\n", cell_name); ++ return PTR_ERR(cell); ++ } ++ ++ efuse = nvmem_cell_read(cell, &len); ++ ++ nvmem_cell_put(cell); ++ ++ if (IS_ERR(efuse)) { ++ dev_err(dev, "Failed to read cell '%s'\n", cell_name); ++ return PTR_ERR(efuse); ++ } ++ ++ lvts_td->calib = devm_krealloc(dev, lvts_td->calib, ++ lvts_td->calib_len + len, GFP_KERNEL); ++ if (!lvts_td->calib) ++ return -ENOMEM; ++ ++ memcpy(lvts_td->calib + lvts_td->calib_len, efuse, len); ++ ++ lvts_td->calib_len += len; ++ ++ kfree(efuse); ++ } ++ ++ return 0; ++} ++ ++static int lvts_golden_temp_init(struct device *dev, u32 *value) ++{ ++ u32 gt; ++ ++ gt = (*value) >> 24; ++ ++ if (gt && gt < LVTS_GOLDEN_TEMP_MAX) ++ golden_temp = gt; ++ ++ coeff_b = golden_temp * 500 + LVTS_COEFF_B; ++ ++ return 0; ++} ++ ++static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td, ++ const struct lvts_data *lvts_data) ++{ ++ size_t size = sizeof(*lvts_td->lvts_ctrl) * lvts_data->num_lvts_ctrl; ++ struct lvts_ctrl *lvts_ctrl; ++ int i, ret; ++ ++ /* ++ * Create the calibration bytes stream from efuse data ++ */ ++ ret = lvts_calibration_read(dev, lvts_td, lvts_data); ++ if (ret) ++ return ret; ++ ++ /* ++ * The golden temp information is contained in the first chunk ++ * of efuse data. ++ */ ++ ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib); ++ if (ret) ++ return ret; ++ ++ lvts_ctrl = devm_kzalloc(dev, size, GFP_KERNEL); ++ if (!lvts_ctrl) ++ return -ENOMEM; ++ ++ for (i = 0; i < lvts_data->num_lvts_ctrl; i++) { ++ ++ lvts_ctrl[i].base = lvts_td->base + lvts_data->lvts_ctrl[i].offset; ++ ++ ret = lvts_sensor_init(dev, &lvts_ctrl[i], ++ &lvts_data->lvts_ctrl[i]); ++ if (ret) ++ return ret; ++ ++ ret = lvts_calibration_init(dev, &lvts_ctrl[i], ++ &lvts_data->lvts_ctrl[i], ++ lvts_td->calib); ++ if (ret) ++ return ret; ++ ++ /* ++ * The mode the ctrl will use to read the temperature ++ * (filtered or immediate) ++ */ ++ lvts_ctrl[i].mode = lvts_data->lvts_ctrl[i].mode; ++ ++ /* ++ * The temperature to raw temperature must be done ++ * after initializing the calibration. ++ */ ++ lvts_ctrl[i].hw_tshut_raw_temp = ++ lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp); ++ } ++ ++ /* ++ * We no longer need the efuse bytes stream, let's free it ++ */ ++ devm_kfree(dev, lvts_td->calib); ++ ++ lvts_td->lvts_ctrl = lvts_ctrl; ++ lvts_td->num_lvts_ctrl = lvts_data->num_lvts_ctrl; ++ ++ return 0; ++} ++ ++/* ++ * At this point the configuration register is the only place in the ++ * driver where we write multiple values. Per hardware constraint, ++ * each write in the configuration register must be separated by a ++ * delay of 2 us. ++ */ ++static void lvts_write_config(struct lvts_ctrl *lvts_ctrl, u32 *cmds, int nr_cmds) ++{ ++ int i; ++ ++ /* ++ * Configuration register ++ */ ++ for (i = 0; i < nr_cmds; i++) { ++ writel(cmds[i], LVTS_CONFIG(lvts_ctrl->base)); ++ usleep_range(2, 4); ++ } ++} ++ ++static int lvts_irq_init(struct lvts_ctrl *lvts_ctrl) ++{ ++ /* ++ * LVTS_PROTCTL : Thermal Protection Sensor Selection ++ * ++ * Bits: ++ * ++ * 19-18 : Sensor to base the protection on ++ * 17-16 : Strategy: ++ * 00 : Average of 4 sensors ++ * 01 : Max of 4 sensors ++ * 10 : Selected sensor with bits 19-18 ++ * 11 : Reserved ++ */ ++ writel(BIT(16), LVTS_PROTCTL(lvts_ctrl->base)); ++ ++ /* ++ * LVTS_PROTTA : Stage 1 temperature threshold ++ * LVTS_PROTTB : Stage 2 temperature threshold ++ * LVTS_PROTTC : Stage 3 temperature threshold ++ * ++ * Bits: ++ * ++ * 14-0: Raw temperature threshold ++ * ++ * writel(0x0, LVTS_PROTTA(lvts_ctrl->base)); ++ * writel(0x0, LVTS_PROTTB(lvts_ctrl->base)); ++ */ ++ writel(lvts_ctrl->hw_tshut_raw_temp, LVTS_PROTTC(lvts_ctrl->base)); ++ ++ /* ++ * LVTS_MONINT : Interrupt configuration register ++ * ++ * The LVTS_MONINT register layout is the same as the LVTS_MONINTSTS ++ * register, except we set the bits to enable the interrupt. ++ */ ++ writel(LVTS_MONINT_CONF, LVTS_MONINT(lvts_ctrl->base)); ++ ++ return 0; ++} ++ ++static int lvts_domain_reset(struct device *dev, struct reset_control *reset) ++{ ++ int ret; ++ ++ ret = reset_control_assert(reset); ++ if (ret) ++ return ret; ++ ++ return reset_control_deassert(reset); ++} ++ ++/* ++ * Enable or disable the clocks of a specified thermal controller ++ */ ++static int lvts_ctrl_set_enable(struct lvts_ctrl *lvts_ctrl, int enable) ++{ ++ /* ++ * LVTS_CLKEN : Internal LVTS clock ++ * ++ * Bits: ++ * ++ * 0 : enable / disable clock ++ */ ++ writel(enable, LVTS_CLKEN(lvts_ctrl->base)); ++ ++ return 0; ++} ++ ++static int lvts_ctrl_connect(struct device *dev, struct lvts_ctrl *lvts_ctrl) ++{ ++ u32 id, cmds[] = { 0xC103FFFF, 0xC502FF55 }; ++ ++ lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds)); ++ ++ /* ++ * LVTS_ID : Get ID and status of the thermal controller ++ * ++ * Bits: ++ * ++ * 0-5 : thermal controller id ++ * 7 : thermal controller connection is valid ++ */ ++ id = readl(LVTS_ID(lvts_ctrl->base)); ++ if (!(id & BIT(7))) ++ return -EIO; ++ ++ return 0; ++} ++ ++static int lvts_ctrl_initialize(struct device *dev, struct lvts_ctrl *lvts_ctrl) ++{ ++ /* ++ * Write device mask: 0xC1030000 ++ */ ++ u32 cmds[] = { ++ 0xC1030E01, 0xC1030CFC, 0xC1030A8C, 0xC103098D, 0xC10308F1, ++ 0xC10307A6, 0xC10306B8, 0xC1030500, 0xC1030420, 0xC1030300, ++ 0xC1030030, 0xC10300F6, 0xC1030050, 0xC1030060, 0xC10300AC, ++ 0xC10300FC, 0xC103009D, 0xC10300F1, 0xC10300E1 ++ }; ++ ++ lvts_write_config(lvts_ctrl, cmds, ARRAY_SIZE(cmds)); ++ ++ return 0; ++} ++ ++static int lvts_ctrl_calibrate(struct device *dev, struct lvts_ctrl *lvts_ctrl) ++{ ++ int i; ++ void __iomem *lvts_edata[] = { ++ LVTS_EDATA00(lvts_ctrl->base), ++ LVTS_EDATA01(lvts_ctrl->base), ++ LVTS_EDATA02(lvts_ctrl->base), ++ LVTS_EDATA03(lvts_ctrl->base) ++ }; ++ ++ /* ++ * LVTS_EDATA0X : Efuse calibration reference value for sensor X ++ * ++ * Bits: ++ * ++ * 20-0 : Efuse value for normalization data ++ */ ++ for (i = 0; i < LVTS_SENSOR_MAX; i++) ++ writel(lvts_ctrl->calibration[i], lvts_edata[i]); ++ ++ return 0; ++} ++ ++static int lvts_ctrl_configure(struct device *dev, struct lvts_ctrl *lvts_ctrl) ++{ ++ u32 value; ++ ++ /* ++ * LVTS_TSSEL : Sensing point index numbering ++ * ++ * Bits: ++ * ++ * 31-24: ADC Sense 3 ++ * 23-16: ADC Sense 2 ++ * 15-8 : ADC Sense 1 ++ * 7-0 : ADC Sense 0 ++ */ ++ value = LVTS_TSSEL_CONF; ++ writel(value, LVTS_TSSEL(lvts_ctrl->base)); ++ ++ /* ++ * LVTS_CALSCALE : ADC voltage round ++ */ ++ value = 0x300; ++ value = LVTS_CALSCALE_CONF; ++ ++ /* ++ * LVTS_MSRCTL0 : Sensor filtering strategy ++ * ++ * Filters: ++ * ++ * 000 : One sample ++ * 001 : Avg 2 samples ++ * 010 : 4 samples, drop min and max, avg 2 samples ++ * 011 : 6 samples, drop min and max, avg 4 samples ++ * 100 : 10 samples, drop min and max, avg 8 samples ++ * 101 : 18 samples, drop min and max, avg 16 samples ++ * ++ * Bits: ++ * ++ * 0-2 : Sensor0 filter ++ * 3-5 : Sensor1 filter ++ * 6-8 : Sensor2 filter ++ * 9-11 : Sensor3 filter ++ */ ++ value = LVTS_HW_FILTER << 9 | LVTS_HW_FILTER << 6 | ++ LVTS_HW_FILTER << 3 | LVTS_HW_FILTER; ++ writel(value, LVTS_MSRCTL0(lvts_ctrl->base)); ++ ++ /* ++ * LVTS_MSRCTL1 : Measurement control ++ * ++ * Bits: ++ * ++ * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3 ++ * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2 ++ * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1 ++ * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0 ++ * ++ * That configuration will ignore the filtering and the delays ++ * introduced below in MONCTL1 and MONCTL2 ++ */ ++ if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) { ++ value = BIT(9) | BIT(6) | BIT(5) | BIT(4); ++ writel(value, LVTS_MSRCTL1(lvts_ctrl->base)); ++ } ++ ++ /* ++ * LVTS_MONCTL1 : Period unit and group interval configuration ++ * ++ * The clock source of LVTS thermal controller is 26MHz. ++ * ++ * The period unit is a time base for all the interval delays ++ * specified in the registers. By default we use 12. The time ++ * conversion is done by multiplying by 256 and 1/26.10^6 ++ * ++ * An interval delay multiplied by the period unit gives the ++ * duration in seconds. ++ * ++ * - Filter interval delay is a delay between two samples of ++ * the same sensor. ++ * ++ * - Sensor interval delay is a delay between two samples of ++ * different sensors. ++ * ++ * - Group interval delay is a delay between different rounds. ++ * ++ * For example: ++ * If Period unit = C, filter delay = 1, sensor delay = 2, group delay = 1, ++ * and two sensors, TS1 and TS2, are in a LVTS thermal controller ++ * and then ++ * Period unit time = C * 1/26M * 256 = 12 * 38.46ns * 256 = 118.149us ++ * Filter interval delay = 1 * Period unit = 118.149us ++ * Sensor interval delay = 2 * Period unit = 236.298us ++ * Group interval delay = 1 * Period unit = 118.149us ++ * ++ * TS1 TS1 ... TS1 TS2 TS2 ... TS2 TS1... ++ * <--> Filter interval delay ++ * <--> Sensor interval delay ++ * <--> Group interval delay ++ * Bits: ++ * 29 - 20 : Group interval ++ * 16 - 13 : Send a single interrupt when crossing the hot threshold (1) ++ * or an interrupt everytime the hot threshold is crossed (0) ++ * 9 - 0 : Period unit ++ * ++ */ ++ value = LVTS_GROUP_INTERVAL << 20 | LVTS_PERIOD_UNIT; ++ writel(value, LVTS_MONCTL1(lvts_ctrl->base)); ++ ++ /* ++ * LVTS_MONCTL2 : Filtering and sensor interval ++ * ++ * Bits: ++ * ++ * 25-16 : Interval unit in PERIOD_UNIT between sample on ++ * the same sensor, filter interval ++ * 9-0 : Interval unit in PERIOD_UNIT between each sensor ++ * ++ */ ++ value = LVTS_FILTER_INTERVAL << 16 | LVTS_SENSOR_INTERVAL; ++ writel(value, LVTS_MONCTL2(lvts_ctrl->base)); ++ ++ return lvts_irq_init(lvts_ctrl); ++} ++ ++static int lvts_ctrl_start(struct device *dev, struct lvts_ctrl *lvts_ctrl) ++{ ++ struct lvts_sensor *lvts_sensors = lvts_ctrl->sensors; ++ struct thermal_zone_device *tz; ++ u32 sensor_map = 0; ++ int i; ++ ++ for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) { ++ ++ int dt_id = lvts_sensors[i].dt_id; ++ ++ tz = devm_thermal_of_zone_register(dev, dt_id, &lvts_sensors[i], ++ &lvts_ops); ++ if (IS_ERR(tz)) { ++ /* ++ * This thermal zone is not described in the ++ * device tree. It is not an error from the ++ * thermal OF code POV, we just continue. ++ */ ++ if (PTR_ERR(tz) == -ENODEV) ++ continue; ++ ++ return PTR_ERR(tz); ++ } ++ ++ /* ++ * The thermal zone pointer will be needed in the ++ * interrupt handler, we store it in the sensor ++ * structure. The thermal domain structure will be ++ * passed to the interrupt handler private data as the ++ * interrupt is shared for all the controller ++ * belonging to the thermal domain. ++ */ ++ lvts_sensors[i].tz = tz; ++ ++ /* ++ * This sensor was correctly associated with a thermal ++ * zone, let's set the corresponding bit in the sensor ++ * map, so we can enable the temperature monitoring in ++ * the hardware thermal controller. ++ */ ++ sensor_map |= BIT(i); ++ } ++ ++ /* ++ * Bits: ++ * 9: Single point access flow ++ * 0-3: Enable sensing point 0-3 ++ * ++ * The initialization of the thermal zones give us ++ * which sensor point to enable. If any thermal zone ++ * was not described in the device tree, it won't be ++ * enabled here in the sensor map. ++ */ ++ writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base)); ++ ++ return 0; ++} ++ ++static int lvts_domain_init(struct device *dev, struct lvts_domain *lvts_td, ++ const struct lvts_data *lvts_data) ++{ ++ struct lvts_ctrl *lvts_ctrl; ++ int i, ret; ++ ++ ret = lvts_ctrl_init(dev, lvts_td, lvts_data); ++ if (ret) ++ return ret; ++ ++ ret = lvts_domain_reset(dev, lvts_td->reset); ++ if (ret) { ++ dev_dbg(dev, "Failed to reset domain"); ++ return ret; ++ } ++ ++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) { ++ ++ lvts_ctrl = &lvts_td->lvts_ctrl[i]; ++ ++ /* ++ * Initialization steps: ++ * ++ * - Enable the clock ++ * - Connect to the LVTS ++ * - Initialize the LVTS ++ * - Prepare the calibration data ++ * - Select monitored sensors ++ * [ Configure sampling ] ++ * [ Configure the interrupt ] ++ * - Start measurement ++ */ ++ ret = lvts_ctrl_set_enable(lvts_ctrl, true); ++ if (ret) { ++ dev_dbg(dev, "Failed to enable LVTS clock"); ++ return ret; ++ } ++ ++ ret = lvts_ctrl_connect(dev, lvts_ctrl); ++ if (ret) { ++ dev_dbg(dev, "Failed to connect to LVTS controller"); ++ return ret; ++ } ++ ++ ret = lvts_ctrl_initialize(dev, lvts_ctrl); ++ if (ret) { ++ dev_dbg(dev, "Failed to initialize controller"); ++ return ret; ++ } ++ ++ ret = lvts_ctrl_calibrate(dev, lvts_ctrl); ++ if (ret) { ++ dev_dbg(dev, "Failed to calibrate controller"); ++ return ret; ++ } ++ ++ ret = lvts_ctrl_configure(dev, lvts_ctrl); ++ if (ret) { ++ dev_dbg(dev, "Failed to configure controller"); ++ return ret; ++ } ++ ++ ret = lvts_ctrl_start(dev, lvts_ctrl); ++ if (ret) { ++ dev_dbg(dev, "Failed to start controller"); ++ return ret; ++ } ++ } ++ ++ return lvts_debugfs_init(dev, lvts_td); ++} ++ ++static int lvts_probe(struct platform_device *pdev) ++{ ++ const struct lvts_data *lvts_data; ++ struct lvts_domain *lvts_td; ++ struct device *dev = &pdev->dev; ++ struct resource *res; ++ int irq, ret; ++ ++ lvts_td = devm_kzalloc(dev, sizeof(*lvts_td), GFP_KERNEL); ++ if (!lvts_td) ++ return -ENOMEM; ++ ++ lvts_data = of_device_get_match_data(dev); ++ ++ lvts_td->clk = devm_clk_get_enabled(dev, NULL); ++ if (IS_ERR(lvts_td->clk)) ++ return dev_err_probe(dev, PTR_ERR(lvts_td->clk), "Failed to retrieve clock\n"); ++ ++ res = platform_get_mem_or_io(pdev, 0); ++ if (!res) ++ return dev_err_probe(dev, (-ENXIO), "No IO resource\n"); ++ ++ lvts_td->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); ++ if (IS_ERR(lvts_td->base)) ++ return dev_err_probe(dev, PTR_ERR(lvts_td->base), "Failed to map io resource\n"); ++ ++ lvts_td->reset = devm_reset_control_get_by_index(dev, 0); ++ if (IS_ERR(lvts_td->reset)) ++ return dev_err_probe(dev, PTR_ERR(lvts_td->reset), "Failed to get reset control\n"); ++ ++ irq = platform_get_irq(pdev, 0); ++ if (irq < 0) ++ return dev_err_probe(dev, irq, "No irq resource\n"); ++ ++ ret = lvts_domain_init(dev, lvts_td, lvts_data); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to initialize the lvts domain\n"); ++ ++ /* ++ * At this point the LVTS is initialized and enabled. We can ++ * safely enable the interrupt. ++ */ ++ ret = devm_request_threaded_irq(dev, irq, NULL, lvts_irq_handler, ++ IRQF_ONESHOT, dev_name(dev), lvts_td); ++ if (ret) ++ return dev_err_probe(dev, ret, "Failed to request interrupt\n"); ++ ++ platform_set_drvdata(pdev, lvts_td); ++ ++ return 0; ++} ++ ++static int lvts_remove(struct platform_device *pdev) ++{ ++ struct lvts_domain *lvts_td; ++ int i; ++ ++ lvts_td = platform_get_drvdata(pdev); ++ ++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) ++ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false); ++ ++ lvts_debugfs_exit(lvts_td); ++ ++ return 0; ++} ++ ++static const struct lvts_ctrl_data mt8195_lvts_data_ctrl[] = { ++ { ++ .cal_offset = { 0x04, 0x07 }, ++ .lvts_sensor = { ++ { .dt_id = MT8195_MCU_BIG_CPU0 }, ++ { .dt_id = MT8195_MCU_BIG_CPU1 } ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x0, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, ++ }, ++ { ++ .cal_offset = { 0x0d, 0x10 }, ++ .lvts_sensor = { ++ { .dt_id = MT8195_MCU_BIG_CPU2 }, ++ { .dt_id = MT8195_MCU_BIG_CPU3 } ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x100, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, ++ }, ++ { ++ .cal_offset = { 0x16, 0x19, 0x1c, 0x1f }, ++ .lvts_sensor = { ++ { .dt_id = MT8195_MCU_LITTLE_CPU0 }, ++ { .dt_id = MT8195_MCU_LITTLE_CPU1 }, ++ { .dt_id = MT8195_MCU_LITTLE_CPU2 }, ++ { .dt_id = MT8195_MCU_LITTLE_CPU3 } ++ }, ++ .num_lvts_sensor = 4, ++ .offset = 0x200, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, ++ } ++}; ++ ++static const struct lvts_data mt8195_lvts_mcu_data = { ++ .lvts_ctrl = mt8195_lvts_data_ctrl, ++ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_data_ctrl), ++}; ++ ++static const struct of_device_id lvts_of_match[] = { ++ { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data }, ++ {}, ++}; ++MODULE_DEVICE_TABLE(of, lvts_of_match); ++ ++static struct platform_driver lvts_driver = { ++ .probe = lvts_probe, ++ .remove = lvts_remove, ++ .driver = { ++ .name = "mtk-lvts-thermal", ++ .of_match_table = lvts_of_match, ++ }, ++}; ++module_platform_driver(lvts_driver); ++ ++MODULE_AUTHOR("Balsam CHIHI "); ++MODULE_DESCRIPTION("MediaTek LVTS Thermal Driver"); ++MODULE_LICENSE("GPL"); diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-07-dt-bindings-thermal-mediatek-Add-LVTS-thermal-contro.patch b/target/linux/mediatek/patches-6.1/830-v6.4-07-dt-bindings-thermal-mediatek-Add-LVTS-thermal-contro.patch new file mode 100644 index 00000000000..b6a5f640901 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-07-dt-bindings-thermal-mediatek-Add-LVTS-thermal-contro.patch @@ -0,0 +1,186 @@ +From 498e2f7a6e69dcbca24715de2b4b97569fdfeff4 Mon Sep 17 00:00:00 2001 +From: Balsam CHIHI +Date: Thu, 9 Feb 2023 11:56:24 +0100 +Subject: [PATCH] dt-bindings: thermal: mediatek: Add LVTS thermal controllers + +Add LVTS thermal controllers dt-binding definition for mt8192 and mt8195. + +Signed-off-by: Balsam CHIHI +Reviewed-by: Rob Herring +Link: https://lore.kernel.org/r/20230209105628.50294-3-bchihi@baylibre.com +Signed-off-by: Daniel Lezcano +Signed-off-by: Rafael J. Wysocki +--- + .../thermal/mediatek,lvts-thermal.yaml | 142 ++++++++++++++++++ + .../thermal/mediatek,lvts-thermal.h | 19 +++ + 2 files changed, 161 insertions(+) + create mode 100644 Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml + create mode 100644 include/dt-bindings/thermal/mediatek,lvts-thermal.h + +--- /dev/null ++++ b/Documentation/devicetree/bindings/thermal/mediatek,lvts-thermal.yaml +@@ -0,0 +1,142 @@ ++# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/thermal/mediatek,lvts-thermal.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: MediaTek SoC Low Voltage Thermal Sensor (LVTS) ++ ++maintainers: ++ - Balsam CHIHI ++ ++description: | ++ LVTS is a thermal management architecture composed of three subsystems, ++ a Sensing device - Thermal Sensing Micro Circuit Unit (TSMCU), ++ a Converter - Low Voltage Thermal Sensor converter (LVTS), and ++ a Digital controller (LVTS_CTRL). ++ ++properties: ++ compatible: ++ enum: ++ - mediatek,mt8192-lvts-ap ++ - mediatek,mt8192-lvts-mcu ++ - mediatek,mt8195-lvts-ap ++ - mediatek,mt8195-lvts-mcu ++ ++ reg: ++ maxItems: 1 ++ ++ interrupts: ++ maxItems: 1 ++ ++ clocks: ++ maxItems: 1 ++ ++ resets: ++ maxItems: 1 ++ description: LVTS reset for clearing temporary data on AP/MCU. ++ ++ nvmem-cells: ++ minItems: 1 ++ items: ++ - description: Calibration eFuse data 1 for LVTS ++ - description: Calibration eFuse data 2 for LVTS ++ ++ nvmem-cell-names: ++ minItems: 1 ++ items: ++ - const: lvts-calib-data-1 ++ - const: lvts-calib-data-2 ++ ++ "#thermal-sensor-cells": ++ const: 1 ++ ++allOf: ++ - $ref: thermal-sensor.yaml# ++ ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - mediatek,mt8192-lvts-ap ++ - mediatek,mt8192-lvts-mcu ++ then: ++ properties: ++ nvmem-cells: ++ maxItems: 1 ++ ++ nvmem-cell-names: ++ maxItems: 1 ++ ++ - if: ++ properties: ++ compatible: ++ contains: ++ enum: ++ - mediatek,mt8195-lvts-ap ++ - mediatek,mt8195-lvts-mcu ++ then: ++ properties: ++ nvmem-cells: ++ minItems: 2 ++ ++ nvmem-cell-names: ++ minItems: 2 ++ ++required: ++ - compatible ++ - reg ++ - interrupts ++ - clocks ++ - resets ++ - nvmem-cells ++ - nvmem-cell-names ++ - "#thermal-sensor-cells" ++ ++additionalProperties: false ++ ++examples: ++ - | ++ #include ++ #include ++ #include ++ #include ++ ++ soc { ++ #address-cells = <2>; ++ #size-cells = <2>; ++ ++ lvts_mcu: thermal-sensor@11278000 { ++ compatible = "mediatek,mt8195-lvts-mcu"; ++ reg = <0 0x11278000 0 0x1000>; ++ interrupts = ; ++ clocks = <&infracfg_ao CLK_INFRA_AO_THERM>; ++ resets = <&infracfg_ao MT8195_INFRA_RST4_THERM_CTRL_MCU_SWRST>; ++ nvmem-cells = <&lvts_efuse_data1 &lvts_efuse_data2>; ++ nvmem-cell-names = "lvts-calib-data-1", "lvts-calib-data-2"; ++ #thermal-sensor-cells = <1>; ++ }; ++ }; ++ ++ thermal_zones: thermal-zones { ++ cpu0-thermal { ++ polling-delay = <1000>; ++ polling-delay-passive = <250>; ++ thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU0>; ++ ++ trips { ++ cpu0_alert: trip-alert { ++ temperature = <85000>; ++ hysteresis = <2000>; ++ type = "passive"; ++ }; ++ ++ cpu0_crit: trip-crit { ++ temperature = <100000>; ++ hysteresis = <2000>; ++ type = "critical"; ++ }; ++ }; ++ }; ++ }; +--- /dev/null ++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h +@@ -0,0 +1,19 @@ ++/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ ++/* ++ * Copyright (c) 2023 MediaTek Inc. ++ * Author: Balsam CHIHI ++ */ ++ ++#ifndef __MEDIATEK_LVTS_DT_H ++#define __MEDIATEK_LVTS_DT_H ++ ++#define MT8195_MCU_BIG_CPU0 0 ++#define MT8195_MCU_BIG_CPU1 1 ++#define MT8195_MCU_BIG_CPU2 2 ++#define MT8195_MCU_BIG_CPU3 3 ++#define MT8195_MCU_LITTLE_CPU0 4 ++#define MT8195_MCU_LITTLE_CPU1 5 ++#define MT8195_MCU_LITTLE_CPU2 6 ++#define MT8195_MCU_LITTLE_CPU3 7 ++ ++#endif /* __MEDIATEK_LVTS_DT_H */ diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-08-dt-bindings-thermal-mediatek-Add-AP-domain-to-LVTS-t.patch b/target/linux/mediatek/patches-6.1/830-v6.4-08-dt-bindings-thermal-mediatek-Add-AP-domain-to-LVTS-t.patch new file mode 100644 index 00000000000..efb0d8b64fb --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-08-dt-bindings-thermal-mediatek-Add-AP-domain-to-LVTS-t.patch @@ -0,0 +1,35 @@ +From 05aaa7fdb0736262e224369b9b9f1410320fc71b Mon Sep 17 00:00:00 2001 +From: Balsam CHIHI +Date: Tue, 7 Mar 2023 16:45:21 +0100 +Subject: [PATCH] dt-bindings: thermal: mediatek: Add AP domain to LVTS thermal + controllers for mt8195 + +Add AP Domain to LVTS thermal controllers dt-binding definition for mt8195. + +Signed-off-by: Balsam CHIHI +Acked-by: Rob Herring +Reviewed-by: AngeloGioacchino Del Regno +Tested-by: Chen-Yu Tsai +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230307154524.118541-2-bchihi@baylibre.com +--- + include/dt-bindings/thermal/mediatek,lvts-thermal.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h ++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h +@@ -16,4 +16,14 @@ + #define MT8195_MCU_LITTLE_CPU2 6 + #define MT8195_MCU_LITTLE_CPU3 7 + ++#define MT8195_AP_VPU0 8 ++#define MT8195_AP_VPU1 9 ++#define MT8195_AP_GPU0 10 ++#define MT8195_AP_GPU1 11 ++#define MT8195_AP_VDEC 12 ++#define MT8195_AP_IMG 13 ++#define MT8195_AP_INFRA 14 ++#define MT8195_AP_CAM0 15 ++#define MT8195_AP_CAM1 16 ++ + #endif /* __MEDIATEK_LVTS_DT_H */ diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-09-thermal-core-Add-a-thermal-zone-devdata-accessor.patch b/target/linux/mediatek/patches-6.1/830-v6.4-09-thermal-core-Add-a-thermal-zone-devdata-accessor.patch new file mode 100644 index 00000000000..c68969321e5 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-09-thermal-core-Add-a-thermal-zone-devdata-accessor.patch @@ -0,0 +1,65 @@ +From a6ff3c0021468721b96e84892a8cae24bde8d65f Mon Sep 17 00:00:00 2001 +From: Daniel Lezcano +Date: Wed, 1 Mar 2023 21:14:29 +0100 +Subject: [PATCH] thermal/core: Add a thermal zone 'devdata' accessor + +The thermal zone device structure is exposed to the different drivers +and obviously they access the internals while that should be +restricted to the core thermal code. + +In order to self-encapsulate the thermal core code, we need to prevent +the drivers accessing directly the thermal zone structure and provide +accessor functions to deal with. + +Provide an accessor to the 'devdata' structure and make use of it in +the different drivers. + +No functional changes intended. + +Signed-off-by: Daniel Lezcano +Acked-by: Rafael J. Wysocki +Acked-by: Mark Brown +Signed-off-by: Rafael J. Wysocki +--- + drivers/thermal/thermal_core.c | 6 ++++++ + include/linux/thermal.h | 7 +++++++ + 2 files changed, 13 insertions(+) + +--- a/drivers/thermal/thermal_core.c ++++ b/drivers/thermal/thermal_core.c +@@ -1346,6 +1346,12 @@ struct thermal_zone_device *thermal_zone + } + EXPORT_SYMBOL_GPL(thermal_zone_device_register); + ++void *thermal_zone_device_priv(struct thermal_zone_device *tzd) ++{ ++ return tzd->devdata; ++} ++EXPORT_SYMBOL_GPL(thermal_zone_device_priv); ++ + /** + * thermal_zone_device_unregister - removes the registered thermal zone device + * @tz: the thermal zone device to remove +--- a/include/linux/thermal.h ++++ b/include/linux/thermal.h +@@ -346,6 +346,8 @@ thermal_zone_device_register_with_trips( + void *, struct thermal_zone_device_ops *, + struct thermal_zone_params *, int, int); + ++void *thermal_zone_device_priv(struct thermal_zone_device *tzd); ++ + int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, + struct thermal_cooling_device *, + unsigned long, unsigned long, +@@ -417,6 +419,11 @@ static inline int thermal_zone_get_offse + struct thermal_zone_device *tz) + { return -ENODEV; } + ++static inline void *thermal_zone_device_priv(struct thermal_zone_device *tz) ++{ ++ return NULL; ++} ++ + static inline int thermal_zone_device_enable(struct thermal_zone_device *tz) + { return -ENODEV; } + diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-10-thermal-core-Add-thermal_zone_device-structure-type-.patch b/target/linux/mediatek/patches-6.1/830-v6.4-10-thermal-core-Add-thermal_zone_device-structure-type-.patch new file mode 100644 index 00000000000..66d3c9e3028 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-10-thermal-core-Add-thermal_zone_device-structure-type-.patch @@ -0,0 +1,55 @@ +From 072e35c98806100182c0a7263cf4cba09ce43463 Mon Sep 17 00:00:00 2001 +From: Daniel Lezcano +Date: Wed, 1 Mar 2023 21:14:38 +0100 +Subject: [PATCH] thermal/core: Add thermal_zone_device structure 'type' + accessor + +The thermal zone device structure is exposed via the exported +thermal.h header. This structure should stay private the thermal core +code. In order to encapsulate the structure, let's add an accessor to +get the 'type' of the thermal zone. + +Signed-off-by: Daniel Lezcano +Signed-off-by: Rafael J. Wysocki +--- + drivers/thermal/thermal_core.c | 6 ++++++ + include/linux/thermal.h | 6 ++++++ + 2 files changed, 12 insertions(+) + +--- a/drivers/thermal/thermal_core.c ++++ b/drivers/thermal/thermal_core.c +@@ -1352,6 +1352,12 @@ void *thermal_zone_device_priv(struct th + } + EXPORT_SYMBOL_GPL(thermal_zone_device_priv); + ++const char *thermal_zone_device_type(struct thermal_zone_device *tzd) ++{ ++ return tzd->type; ++} ++EXPORT_SYMBOL_GPL(thermal_zone_device_type); ++ + /** + * thermal_zone_device_unregister - removes the registered thermal zone device + * @tz: the thermal zone device to remove +--- a/include/linux/thermal.h ++++ b/include/linux/thermal.h +@@ -347,6 +347,7 @@ thermal_zone_device_register_with_trips( + struct thermal_zone_params *, int, int); + + void *thermal_zone_device_priv(struct thermal_zone_device *tzd); ++const char *thermal_zone_device_type(struct thermal_zone_device *tzd); + + int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, + struct thermal_cooling_device *, +@@ -423,6 +424,11 @@ static inline void *thermal_zone_device_ + { + return NULL; + } ++ ++static inline const char *thermal_zone_device_type(struct thermal_zone_device *tzd) ++{ ++ return NULL; ++} + + static inline int thermal_zone_device_enable(struct thermal_zone_device *tz) + { return -ENODEV; } diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-11-thermal-core-Use-the-thermal-zone-devdata-accessor-i.patch b/target/linux/mediatek/patches-6.1/830-v6.4-11-thermal-core-Use-the-thermal-zone-devdata-accessor-i.patch new file mode 100644 index 00000000000..57bc910d3e3 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-11-thermal-core-Use-the-thermal-zone-devdata-accessor-i.patch @@ -0,0 +1,74 @@ +From 7d78bab533eb9aa0e5240e25a204e8f416723ed6 Mon Sep 17 00:00:00 2001 +From: Daniel Lezcano +Date: Wed, 1 Mar 2023 21:14:30 +0100 +Subject: [PATCH 07/42] thermal/core: Use the thermal zone 'devdata' accessor + in thermal located drivers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The thermal zone device structure is exposed to the different drivers +and obviously they access the internals while that should be +restricted to the core thermal code. + +In order to self-encapsulate the thermal core code, we need to prevent +the drivers accessing directly the thermal zone structure and provide +accessor functions to deal with. + +Use the devdata accessor introduced in the previous patch. + +No functional changes intended. + +[skipped drivers not relevant for mediatek target] + +Signed-off-by: Daniel Lezcano +Reviewed-by: Niklas Söderlund #R-Car +Acked-by: Mark Brown +Reviewed-by: AngeloGioacchino Del Regno #MediaTek auxadc and lvts +Reviewed-by: Balsam CHIHI #Mediatek lvts +Reviewed-by: Adam Ward #da9062 +Reviewed-by: Baolin Wang #spread +Acked-by: Jernej Skrabec #sun8i_thermal +Acked-by: Rafael J. Wysocki +Acked-by: Florian Fainelli #Broadcom +Reviewed-by: Dhruva Gole # K3 bandgap +Acked-by: Linus Walleij +Acked-by: Heiko Stuebner #rockchip +Reviewed-by: Kunihiko Hayashi #uniphier +Signed-off-by: Rafael J. Wysocki +--- + drivers/thermal/mediatek/auxadc_thermal.c | 2 +- + drivers/thermal/mediatek/lvts_thermal.c | 4 ++-- + 43 files changed, 71 insertions(+), 73 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -763,7 +763,7 @@ static int mtk_thermal_bank_temperature( + + static int mtk_read_temp(struct thermal_zone_device *tz, int *temperature) + { +- struct mtk_thermal *mt = tz->devdata; ++ struct mtk_thermal *mt = thermal_zone_device_priv(tz); + int i; + int tempmax = INT_MIN; + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -252,7 +252,7 @@ static u32 lvts_temp_to_raw(int temperat + + static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) + { +- struct lvts_sensor *lvts_sensor = tz->devdata; ++ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); + void __iomem *msr = lvts_sensor->msr; + u32 value; + +@@ -290,7 +290,7 @@ static int lvts_get_temp(struct thermal_ + + static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) + { +- struct lvts_sensor *lvts_sensor = tz->devdata; ++ struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); + void __iomem *base = lvts_sensor->base; + u32 raw_low = lvts_temp_to_raw(low); + u32 raw_high = lvts_temp_to_raw(high); diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-12-thermal-hwmon-Use-the-right-device-for-devm_thermal_.patch b/target/linux/mediatek/patches-6.1/830-v6.4-12-thermal-hwmon-Use-the-right-device-for-devm_thermal_.patch new file mode 100644 index 00000000000..647b3b0eca1 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-12-thermal-hwmon-Use-the-right-device-for-devm_thermal_.patch @@ -0,0 +1,201 @@ +From cc9c60e9cfeeac45d63361fa8c085c43c4bdfe3a Mon Sep 17 00:00:00 2001 +From: Daniel Lezcano +Date: Wed, 1 Mar 2023 21:14:36 +0100 +Subject: [PATCH 08/42] thermal/hwmon: Use the right device for + devm_thermal_add_hwmon_sysfs() + +The devres variant of thermal_add_hwmon_sysfs() only takes the thermal +zone structure pointer as parameter. + +Actually, it uses the tz->device to add it in the devres list. + +It is preferable to use the device registering the thermal zone +instead of the thermal zone device itself. That prevents the driver +accessing the thermal zone structure internals and it is from my POV +more correct regarding how devm_ is used. + +[skipped imx thermal which did not apply cleanly and irrelevant on +mediatek target] + +Signed-off-by: Daniel Lezcano +Acked-by: Martin Blumenstingl #amlogic_thermal +Acked-by: Jernej Skrabec #sun8i_thermal +Reviewed-by: AngeloGioacchino Del Regno #MediaTek auxadc +Signed-off-by: Rafael J. Wysocki +--- + drivers/thermal/amlogic_thermal.c | 2 +- + drivers/thermal/imx_sc_thermal.c | 2 +- + drivers/thermal/k3_bandgap.c | 2 +- + drivers/thermal/mediatek/auxadc_thermal.c | 2 +- + drivers/thermal/qcom/qcom-spmi-adc-tm5.c | 2 +- + drivers/thermal/qcom/qcom-spmi-temp-alarm.c | 2 +- + drivers/thermal/qcom/tsens.c | 2 +- + drivers/thermal/qoriq_thermal.c | 2 +- + drivers/thermal/sun8i_thermal.c | 2 +- + drivers/thermal/tegra/tegra30-tsensor.c | 2 +- + drivers/thermal/thermal_hwmon.c | 4 ++-- + drivers/thermal/thermal_hwmon.h | 4 ++-- + drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +- + 13 files changed, 15 insertions(+), 15 deletions(-) + +--- a/drivers/thermal/amlogic_thermal.c ++++ b/drivers/thermal/amlogic_thermal.c +@@ -286,7 +286,7 @@ static int amlogic_thermal_probe(struct + return ret; + } + +- if (devm_thermal_add_hwmon_sysfs(pdata->tzd)) ++ if (devm_thermal_add_hwmon_sysfs(&pdev->dev, pdata->tzd)) + dev_warn(&pdev->dev, "Failed to add hwmon sysfs attributes\n"); + + ret = amlogic_thermal_initialize(pdata); +--- a/drivers/thermal/imx_sc_thermal.c ++++ b/drivers/thermal/imx_sc_thermal.c +@@ -120,7 +120,7 @@ static int imx_sc_thermal_probe(struct p + return ret; + } + +- if (devm_thermal_add_hwmon_sysfs(sensor->tzd)) ++ if (devm_thermal_add_hwmon_sysfs(&pdev->dev, sensor->tzd)) + dev_warn(&pdev->dev, "failed to add hwmon sysfs attributes\n"); + } + +--- a/drivers/thermal/k3_bandgap.c ++++ b/drivers/thermal/k3_bandgap.c +@@ -222,7 +222,7 @@ static int k3_bandgap_probe(struct platf + goto err_alloc; + } + +- if (devm_thermal_add_hwmon_sysfs(data[id].tzd)) ++ if (devm_thermal_add_hwmon_sysfs(dev, data[id].tzd)) + dev_warn(dev, "Failed to add hwmon sysfs attributes\n"); + } + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -1210,7 +1210,7 @@ static int mtk_thermal_probe(struct plat + goto err_disable_clk_peri_therm; + } + +- ret = devm_thermal_add_hwmon_sysfs(tzdev); ++ ret = devm_thermal_add_hwmon_sysfs(&pdev->dev, tzdev); + if (ret) + dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs"); + +--- a/drivers/thermal/qcom/qcom-spmi-adc-tm5.c ++++ b/drivers/thermal/qcom/qcom-spmi-adc-tm5.c +@@ -688,7 +688,7 @@ static int adc_tm5_register_tzd(struct a + return PTR_ERR(tzd); + } + adc_tm->channels[i].tzd = tzd; +- if (devm_thermal_add_hwmon_sysfs(tzd)) ++ if (devm_thermal_add_hwmon_sysfs(adc_tm->dev, tzd)) + dev_warn(adc_tm->dev, + "Failed to add hwmon sysfs attributes\n"); + } +--- a/drivers/thermal/qcom/qcom-spmi-temp-alarm.c ++++ b/drivers/thermal/qcom/qcom-spmi-temp-alarm.c +@@ -460,7 +460,7 @@ static int qpnp_tm_probe(struct platform + return ret; + } + +- if (devm_thermal_add_hwmon_sysfs(chip->tz_dev)) ++ if (devm_thermal_add_hwmon_sysfs(&pdev->dev, chip->tz_dev)) + dev_warn(&pdev->dev, + "Failed to add hwmon sysfs attributes\n"); + +--- a/drivers/thermal/qcom/tsens.c ++++ b/drivers/thermal/qcom/tsens.c +@@ -1056,7 +1056,7 @@ static int tsens_register(struct tsens_p + if (priv->ops->enable) + priv->ops->enable(priv, i); + +- if (devm_thermal_add_hwmon_sysfs(tzd)) ++ if (devm_thermal_add_hwmon_sysfs(priv->dev, tzd)) + dev_warn(priv->dev, + "Failed to add hwmon sysfs attributes\n"); + } +--- a/drivers/thermal/qoriq_thermal.c ++++ b/drivers/thermal/qoriq_thermal.c +@@ -158,7 +158,7 @@ static int qoriq_tmu_register_tmu_zone(s + return ret; + } + +- if (devm_thermal_add_hwmon_sysfs(tzd)) ++ if (devm_thermal_add_hwmon_sysfs(dev, tzd)) + dev_warn(dev, + "Failed to add hwmon sysfs attributes\n"); + +--- a/drivers/thermal/sun8i_thermal.c ++++ b/drivers/thermal/sun8i_thermal.c +@@ -468,7 +468,7 @@ static int sun8i_ths_register(struct ths + if (IS_ERR(tmdev->sensor[i].tzd)) + return PTR_ERR(tmdev->sensor[i].tzd); + +- if (devm_thermal_add_hwmon_sysfs(tmdev->sensor[i].tzd)) ++ if (devm_thermal_add_hwmon_sysfs(tmdev->dev, tmdev->sensor[i].tzd)) + dev_warn(tmdev->dev, + "Failed to add hwmon sysfs attributes\n"); + } +--- a/drivers/thermal/tegra/tegra30-tsensor.c ++++ b/drivers/thermal/tegra/tegra30-tsensor.c +@@ -530,7 +530,7 @@ static int tegra_tsensor_register_channe + return 0; + } + +- if (devm_thermal_add_hwmon_sysfs(tsc->tzd)) ++ if (devm_thermal_add_hwmon_sysfs(ts->dev, tsc->tzd)) + dev_warn(ts->dev, "failed to add hwmon sysfs attributes\n"); + + return 0; +--- a/drivers/thermal/thermal_hwmon.c ++++ b/drivers/thermal/thermal_hwmon.c +@@ -255,7 +255,7 @@ static void devm_thermal_hwmon_release(s + thermal_remove_hwmon_sysfs(*(struct thermal_zone_device **)res); + } + +-int devm_thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) ++int devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device *tz) + { + struct thermal_zone_device **ptr; + int ret; +@@ -272,7 +272,7 @@ int devm_thermal_add_hwmon_sysfs(struct + } + + *ptr = tz; +- devres_add(&tz->device, ptr); ++ devres_add(dev, ptr); + + return ret; + } +--- a/drivers/thermal/thermal_hwmon.h ++++ b/drivers/thermal/thermal_hwmon.h +@@ -17,7 +17,7 @@ + + #ifdef CONFIG_THERMAL_HWMON + int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz); +-int devm_thermal_add_hwmon_sysfs(struct thermal_zone_device *tz); ++int devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device *tz); + void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz); + #else + static inline int +@@ -27,7 +27,7 @@ thermal_add_hwmon_sysfs(struct thermal_z + } + + static inline int +-devm_thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) ++devm_thermal_add_hwmon_sysfs(struct device *dev, struct thermal_zone_device *tz) + { + return 0; + } +--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c ++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +@@ -182,7 +182,7 @@ int ti_thermal_expose_sensor(struct ti_b + ti_bandgap_set_sensor_data(bgp, id, data); + ti_bandgap_write_update_interval(bgp, data->sensor_id, interval); + +- if (devm_thermal_add_hwmon_sysfs(data->ti_thermal)) ++ if (devm_thermal_add_hwmon_sysfs(bgp->dev, data->ti_thermal)) + dev_warn(bgp->dev, "failed to add hwmon sysfs attributes\n"); + + return 0; diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-13-thermal-Don-t-use-device-internal-thermal-zone-struc.patch b/target/linux/mediatek/patches-6.1/830-v6.4-13-thermal-Don-t-use-device-internal-thermal-zone-struc.patch new file mode 100644 index 00000000000..9dedc2cb685 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-13-thermal-Don-t-use-device-internal-thermal-zone-struc.patch @@ -0,0 +1,79 @@ +From 5a72b8e4bac753e4dc74dc0a1335d120f63df97a Mon Sep 17 00:00:00 2001 +From: Daniel Lezcano +Date: Wed, 1 Mar 2023 21:14:37 +0100 +Subject: [PATCH 09/42] thermal: Don't use 'device' internal thermal zone + structure field + +Some drivers are directly using the thermal zone's 'device' structure +field. + +Use the driver device pointer instead of the thermal zone device when +it is available. + +Remove the traces when they are duplicate with the traces in the core +code. + +[again skipped imx_thermal.c] + +Cc: Jean Delvare +Cc: Guenter Roeck +Signed-off-by: Daniel Lezcano +Reviewed-by: Balsam CHIHI #Mediatek LVTS +Reviewed-by: AngeloGioacchino Del Regno #MediaTek LVTS +Signed-off-by: Rafael J. Wysocki +--- + drivers/thermal/mediatek/lvts_thermal.c | 4 ++-- + drivers/thermal/thermal_hwmon.c | 4 ++-- + drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +- + 3 files changed, 5 insertions(+), 5 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -305,7 +305,7 @@ static int lvts_set_trips(struct thermal + * 14-0 : Raw temperature for threshold + */ + if (low != -INT_MAX) { +- dev_dbg(&tz->device, "Setting low limit temperature interrupt: %d\n", low); ++ pr_debug("%s: Setting low limit temperature interrupt: %d\n", tz->type, low); + writel(raw_low, LVTS_H2NTHRE(base)); + } + +@@ -318,7 +318,7 @@ static int lvts_set_trips(struct thermal + * + * 14-0 : Raw temperature for threshold + */ +- dev_dbg(&tz->device, "Setting high limit temperature interrupt: %d\n", high); ++ pr_debug("%s: Setting high limit temperature interrupt: %d\n", tz->type, high); + writel(raw_high, LVTS_HTHRE(base)); + + return 0; +--- a/drivers/thermal/thermal_hwmon.c ++++ b/drivers/thermal/thermal_hwmon.c +@@ -220,14 +220,14 @@ void thermal_remove_hwmon_sysfs(struct t + hwmon = thermal_hwmon_lookup_by_type(tz); + if (unlikely(!hwmon)) { + /* Should never happen... */ +- dev_dbg(&tz->device, "hwmon device lookup failed!\n"); ++ dev_dbg(hwmon->device, "hwmon device lookup failed!\n"); + return; + } + + temp = thermal_hwmon_lookup_temp(hwmon, tz); + if (unlikely(!temp)) { + /* Should never happen... */ +- dev_dbg(&tz->device, "temperature input lookup failed!\n"); ++ dev_dbg(hwmon->device, "temperature input lookup failed!\n"); + return; + } + +--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c ++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +@@ -43,7 +43,7 @@ static void ti_thermal_work(struct work_ + + thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED); + +- dev_dbg(&data->ti_thermal->device, "updated thermal zone %s\n", ++ dev_dbg(data->bgp->dev, "updated thermal zone %s\n", + data->ti_thermal->type); + } + diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-14-thermal-Use-thermal_zone_device_type-accessor.patch b/target/linux/mediatek/patches-6.1/830-v6.4-14-thermal-Use-thermal_zone_device_type-accessor.patch new file mode 100644 index 00000000000..8cec9aba977 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-14-thermal-Use-thermal_zone_device_type-accessor.patch @@ -0,0 +1,62 @@ +From 66b3a292d3fc749e8ec7ac5278a17e8a5757ecbc Mon Sep 17 00:00:00 2001 +From: Daniel Lezcano +Date: Wed, 1 Mar 2023 21:14:41 +0100 +Subject: [PATCH 10/42] thermal: Use thermal_zone_device_type() accessor + +Replace the accesses to 'tz->type' by its accessor version in order to +self-encapsulate the thermal_zone_device structure. + +Signed-off-by: Daniel Lezcano +Reviewed-by: Ido Schimmel #mlxsw +Reviewed-by: AngeloGioacchino Del Regno #MediaTek LVTS +Signed-off-by: Rafael J. Wysocki +--- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 2 +- + drivers/thermal/mediatek/lvts_thermal.c | 6 ++++-- + drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 2 +- + 3 files changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -168,7 +168,7 @@ mlxsw_thermal_module_trips_update(struct + + if (crit_temp > emerg_temp) { + dev_warn(dev, "%s : Critical threshold %d is above emergency threshold %d\n", +- tz->tzdev->type, crit_temp, emerg_temp); ++ thermal_zone_device_type(tz->tzdev), crit_temp, emerg_temp); + return 0; + } + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -305,7 +305,8 @@ static int lvts_set_trips(struct thermal + * 14-0 : Raw temperature for threshold + */ + if (low != -INT_MAX) { +- pr_debug("%s: Setting low limit temperature interrupt: %d\n", tz->type, low); ++ pr_debug("%s: Setting low limit temperature interrupt: %d\n", ++ thermal_zone_device_type(tz), low); + writel(raw_low, LVTS_H2NTHRE(base)); + } + +@@ -318,7 +319,8 @@ static int lvts_set_trips(struct thermal + * + * 14-0 : Raw temperature for threshold + */ +- pr_debug("%s: Setting high limit temperature interrupt: %d\n", tz->type, high); ++ pr_debug("%s: Setting high limit temperature interrupt: %d\n", ++ thermal_zone_device_type(tz), high); + writel(raw_high, LVTS_HTHRE(base)); + + return 0; +--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c ++++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +@@ -44,7 +44,7 @@ static void ti_thermal_work(struct work_ + thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED); + + dev_dbg(data->bgp->dev, "updated thermal zone %s\n", +- data->ti_thermal->type); ++ thermal_zone_device_type(data->ti_thermal)); + } + + /** diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-15-thermal-drivers-mediatek-Control-buffer-enablement-t.patch b/target/linux/mediatek/patches-6.1/830-v6.4-15-thermal-drivers-mediatek-Control-buffer-enablement-t.patch new file mode 100644 index 00000000000..68f41fdd168 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-15-thermal-drivers-mediatek-Control-buffer-enablement-t.patch @@ -0,0 +1,81 @@ +From f6658c1c4ae98477d6be00495226c0617354fe76 Mon Sep 17 00:00:00 2001 +From: Markus Schneider-Pargmann +Date: Fri, 27 Jan 2023 16:44:43 +0100 +Subject: [PATCH 11/42] thermal/drivers/mediatek: Control buffer enablement + tweaks + +Add logic in order to be able to turn on the control buffer on MT8365. +This change now allows to have control buffer support for MTK_THERMAL_V1, +and it allows to define the register offset, and mask used to enable it. + +Signed-off-by: Markus Schneider-Pargmann +Signed-off-by: Fabien Parent +Signed-off-by: Amjad Ouled-Ameur +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20221018-up-i350-thermal-bringup-v9-2-55a1ae14af74@baylibre.com +Signed-off-by: Daniel Lezcano +--- + drivers/thermal/mediatek/auxadc_thermal.c | 28 +++++++++++++++-------- + 1 file changed, 19 insertions(+), 9 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -307,6 +307,9 @@ struct mtk_thermal_data { + bool need_switch_bank; + struct thermal_bank_cfg bank_data[MAX_NUM_ZONES]; + enum mtk_thermal_version version; ++ u32 apmixed_buffer_ctl_reg; ++ u32 apmixed_buffer_ctl_mask; ++ u32 apmixed_buffer_ctl_set; + }; + + struct mtk_thermal { +@@ -560,6 +563,9 @@ static const struct mtk_thermal_data mt7 + .adcpnp = mt7622_adcpnp, + .sensor_mux_values = mt7622_mux_values, + .version = MTK_THERMAL_V2, ++ .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON1, ++ .apmixed_buffer_ctl_mask = GENMASK(31, 6) | BIT(3), ++ .apmixed_buffer_ctl_set = BIT(0), + }; + + /* +@@ -1079,14 +1085,18 @@ static const struct of_device_id mtk_the + }; + MODULE_DEVICE_TABLE(of, mtk_thermal_of_match); + +-static void mtk_thermal_turn_on_buffer(void __iomem *apmixed_base) ++static void mtk_thermal_turn_on_buffer(struct mtk_thermal *mt, ++ void __iomem *apmixed_base) + { +- int tmp; ++ u32 tmp; ++ ++ if (!mt->conf->apmixed_buffer_ctl_reg) ++ return; + +- tmp = readl(apmixed_base + APMIXED_SYS_TS_CON1); +- tmp &= ~(0x37); +- tmp |= 0x1; +- writel(tmp, apmixed_base + APMIXED_SYS_TS_CON1); ++ tmp = readl(apmixed_base + mt->conf->apmixed_buffer_ctl_reg); ++ tmp &= mt->conf->apmixed_buffer_ctl_mask; ++ tmp |= mt->conf->apmixed_buffer_ctl_set; ++ writel(tmp, apmixed_base + mt->conf->apmixed_buffer_ctl_reg); + udelay(200); + } + +@@ -1184,10 +1194,10 @@ static int mtk_thermal_probe(struct plat + goto err_disable_clk_auxadc; + } + +- if (mt->conf->version != MTK_THERMAL_V1) { +- mtk_thermal_turn_on_buffer(apmixed_base); ++ mtk_thermal_turn_on_buffer(mt, apmixed_base); ++ ++ if (mt->conf->version != MTK_THERMAL_V2) + mtk_thermal_release_periodic_ts(mt, auxadc_base); +- } + + if (mt->conf->version == MTK_THERMAL_V1) + mt->raw_to_mcelsius = raw_to_mcelsius_v1; diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-16-thermal-drivers-mediatek-Add-support-for-MT8365-SoC.patch b/target/linux/mediatek/patches-6.1/830-v6.4-16-thermal-drivers-mediatek-Add-support-for-MT8365-SoC.patch new file mode 100644 index 00000000000..285c6f6a7b3 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-16-thermal-drivers-mediatek-Add-support-for-MT8365-SoC.patch @@ -0,0 +1,123 @@ +From c4eff784465f88218dc5eb51320320464db83d3f Mon Sep 17 00:00:00 2001 +From: Fabien Parent +Date: Fri, 27 Jan 2023 16:44:44 +0100 +Subject: [PATCH 12/42] thermal/drivers/mediatek: Add support for MT8365 SoC + +MT8365 is similar to the other SoCs supported by the driver. It has only +one bank and 3 actual sensors that can be multiplexed. There is another +one sensor that does not have usable data. + +Signed-off-by: Fabien Parent +Signed-off-by: Amjad Ouled-Ameur +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20221018-up-i350-thermal-bringup-v9-3-55a1ae14af74@baylibre.com +Signed-off-by: Daniel Lezcano +--- + drivers/thermal/mediatek/auxadc_thermal.c | 68 +++++++++++++++++++++++ + 1 file changed, 68 insertions(+) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -31,6 +31,7 @@ + #define AUXADC_CON2_V 0x010 + #define AUXADC_DATA(channel) (0x14 + (channel) * 4) + ++#define APMIXED_SYS_TS_CON0 0x600 + #define APMIXED_SYS_TS_CON1 0x604 + + /* Thermal Controller Registers */ +@@ -281,6 +282,17 @@ enum mtk_thermal_version { + /* The calibration coefficient of sensor */ + #define MT7986_CALIBRATION 165 + ++/* MT8365 */ ++#define MT8365_TEMP_AUXADC_CHANNEL 11 ++#define MT8365_CALIBRATION 164 ++#define MT8365_NUM_CONTROLLER 1 ++#define MT8365_NUM_BANKS 1 ++#define MT8365_NUM_SENSORS 3 ++#define MT8365_NUM_SENSORS_PER_ZONE 3 ++#define MT8365_TS1 0 ++#define MT8365_TS2 1 ++#define MT8365_TS3 2 ++ + struct mtk_thermal; + + struct thermal_bank_cfg { +@@ -435,6 +447,24 @@ static const int mt7986_mux_values[MT798 + static const int mt7986_vts_index[MT7986_NUM_SENSORS] = { VTS1 }; + static const int mt7986_tc_offset[MT7986_NUM_CONTROLLER] = { 0x0, }; + ++/* MT8365 thermal sensor data */ ++static const int mt8365_bank_data[MT8365_NUM_SENSORS] = { ++ MT8365_TS1, MT8365_TS2, MT8365_TS3 ++}; ++ ++static const int mt8365_msr[MT8365_NUM_SENSORS_PER_ZONE] = { ++ TEMP_MSR0, TEMP_MSR1, TEMP_MSR2 ++}; ++ ++static const int mt8365_adcpnp[MT8365_NUM_SENSORS_PER_ZONE] = { ++ TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2 ++}; ++ ++static const int mt8365_mux_values[MT8365_NUM_SENSORS] = { 0, 1, 2 }; ++static const int mt8365_tc_offset[MT8365_NUM_CONTROLLER] = { 0 }; ++ ++static const int mt8365_vts_index[MT8365_NUM_SENSORS] = { VTS1, VTS2, VTS3 }; ++ + /* + * The MT8173 thermal controller has four banks. Each bank can read up to + * four temperature sensors simultaneously. The MT8173 has a total of 5 +@@ -510,6 +540,40 @@ static const struct mtk_thermal_data mt2 + }; + + /* ++ * The MT8365 thermal controller has one bank, which can read up to ++ * four temperature sensors simultaneously. The MT8365 has a total of 3 ++ * temperature sensors. ++ * ++ * The thermal core only gets the maximum temperature of this one bank, ++ * so the bank concept wouldn't be necessary here. However, the SVS (Smart ++ * Voltage Scaling) unit makes its decisions based on the same bank ++ * data. ++ */ ++static const struct mtk_thermal_data mt8365_thermal_data = { ++ .auxadc_channel = MT8365_TEMP_AUXADC_CHANNEL, ++ .num_banks = MT8365_NUM_BANKS, ++ .num_sensors = MT8365_NUM_SENSORS, ++ .vts_index = mt8365_vts_index, ++ .cali_val = MT8365_CALIBRATION, ++ .num_controller = MT8365_NUM_CONTROLLER, ++ .controller_offset = mt8365_tc_offset, ++ .need_switch_bank = false, ++ .bank_data = { ++ { ++ .num_sensors = MT8365_NUM_SENSORS, ++ .sensors = mt8365_bank_data ++ }, ++ }, ++ .msr = mt8365_msr, ++ .adcpnp = mt8365_adcpnp, ++ .sensor_mux_values = mt8365_mux_values, ++ .version = MTK_THERMAL_V1, ++ .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON0, ++ .apmixed_buffer_ctl_mask = (u32) ~GENMASK(29, 28), ++ .apmixed_buffer_ctl_set = 0, ++}; ++ ++/* + * The MT2712 thermal controller has one bank, which can read up to + * four temperature sensors simultaneously. The MT2712 has a total of 4 + * temperature sensors. +@@ -1080,6 +1144,10 @@ static const struct of_device_id mtk_the + { + .compatible = "mediatek,mt8183-thermal", + .data = (void *)&mt8183_thermal_data, ++ }, ++ { ++ .compatible = "mediatek,mt8365-thermal", ++ .data = (void *)&mt8365_thermal_data, + }, { + }, + }; diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-17-thermal-drivers-mediatek-Add-delay-after-thermal-ban.patch b/target/linux/mediatek/patches-6.1/830-v6.4-17-thermal-drivers-mediatek-Add-delay-after-thermal-ban.patch new file mode 100644 index 00000000000..5c99aa80c1e --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-17-thermal-drivers-mediatek-Add-delay-after-thermal-ban.patch @@ -0,0 +1,50 @@ +From 4eead70db74922bc61e9d0b4591524369a335751 Mon Sep 17 00:00:00 2001 +From: Amjad Ouled-Ameur +Date: Fri, 27 Jan 2023 16:44:46 +0100 +Subject: [PATCH 13/42] thermal/drivers/mediatek: Add delay after thermal banks + initialization + +Thermal sensor reads performed immediately after thermal bank +initialization returns bogus values. This is currently tackled by returning +0 if the temperature is bogus (exceeding 200000). + +Instead, add a delay between the bank init and the thermal zone device +register to properly fix this. + +Signed-off-by: Michael Kao +Signed-off-by: Hsin-Yi Wang +Signed-off-by: Amjad Ouled-Ameur +Reviewed-by: AngeloGioacchino Del Regno +Link: https://lore.kernel.org/r/20221018-up-i350-thermal-bringup-v9-5-55a1ae14af74@baylibre.com +Signed-off-by: Daniel Lezcano +--- + drivers/thermal/mediatek/auxadc_thermal.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -816,14 +816,6 @@ static int mtk_thermal_bank_temperature( + mt, conf->bank_data[bank->id].sensors[i], raw); + + +- /* +- * The first read of a sensor often contains very high bogus +- * temperature value. Filter these out so that the system does +- * not immediately shut down. +- */ +- if (temp > 200000) +- temp = 0; +- + if (temp > max) + max = temp; + } +@@ -1281,6 +1273,9 @@ static int mtk_thermal_probe(struct plat + + platform_set_drvdata(pdev, mt); + ++ /* Delay for thermal banks to be ready */ ++ msleep(30); ++ + tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt, + &mtk_thermal_ops); + if (IS_ERR(tzdev)) { diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-18-thermal-drivers-mediatek-lvts_thermal-Fix-sensor-1-i.patch b/target/linux/mediatek/patches-6.1/830-v6.4-18-thermal-drivers-mediatek-lvts_thermal-Fix-sensor-1-i.patch new file mode 100644 index 00000000000..734f5c1e770 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-18-thermal-drivers-mediatek-lvts_thermal-Fix-sensor-1-i.patch @@ -0,0 +1,46 @@ +From ad9dc9e92367803a4f9576aea0dab110d03fc510 Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai +Date: Tue, 28 Mar 2023 11:10:17 +0800 +Subject: [PATCH 14/42] thermal/drivers/mediatek/lvts_thermal: Fix sensor 1 + interrupt status bitmask + +The binary representation for sensor 1 interrupt status was incorrectly +assembled, when compared to the full table given in the same comment +section. The conversion into hex was also incorrect, leading to +incorrect interrupt status bitmask for sensor 1. This would cause the +driver to incorrectly identify changes for sensor 1, when in fact it +was sensor 0, or a sensor access time out. + +Fix the binary and hex representations in the comments, and the actual +bitmask macro. + +Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230328031017.1360976-1-wenst@chromium.org +--- + drivers/thermal/mediatek/lvts_thermal.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -66,7 +66,7 @@ + #define LVTS_MONINT_CONF 0x9FBF7BDE + + #define LVTS_INT_SENSOR0 0x0009001F +-#define LVTS_INT_SENSOR1 0X000881F0 ++#define LVTS_INT_SENSOR1 0x001203E0 + #define LVTS_INT_SENSOR2 0x00247C00 + #define LVTS_INT_SENSOR3 0x1FC00000 + +@@ -395,8 +395,8 @@ static irqreturn_t lvts_ctrl_irq_handler + * => 0x1FC00000 + * sensor 2 interrupt: 0000 0000 0010 0100 0111 1100 0000 0000 + * => 0x00247C00 +- * sensor 1 interrupt: 0000 0000 0001 0001 0000 0011 1110 0000 +- * => 0X000881F0 ++ * sensor 1 interrupt: 0000 0000 0001 0010 0000 0011 1110 0000 ++ * => 0X001203E0 + * sensor 0 interrupt: 0000 0000 0000 1001 0000 0000 0001 1111 + * => 0x0009001F + */ diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-19-thermal-drivers-mediatek-lvts_thermal-Add-AP-domain-.patch b/target/linux/mediatek/patches-6.1/830-v6.4-19-thermal-drivers-mediatek-lvts_thermal-Add-AP-domain-.patch new file mode 100644 index 00000000000..d09c2055a3e --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-19-thermal-drivers-mediatek-lvts_thermal-Add-AP-domain-.patch @@ -0,0 +1,149 @@ +From 9aad43ad3285fc21158fb416830a6156a9a31fa5 Mon Sep 17 00:00:00 2001 +From: Balsam CHIHI +Date: Tue, 7 Mar 2023 16:45:22 +0100 +Subject: [PATCH 15/42] thermal/drivers/mediatek/lvts_thermal: Add AP domain + for mt8195 + +Add MT8195 AP Domain support to LVTS Driver. + +Take the opportunity to update the comments to show calibration data +information related to the new domain. + +[dlezcano]: Massaged a bit the changelog + +Signed-off-by: Balsam CHIHI +Tested-by: Chen-Yu Tsai +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230307154524.118541-3-bchihi@baylibre.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 94 +++++++++++++++++++------ + 1 file changed, 74 insertions(+), 20 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -530,29 +530,33 @@ static int lvts_sensor_init(struct devic + * The efuse blob values follows the sensor enumeration per thermal + * controller. The decoding of the stream is as follow: + * +- * <--?-> <----big0 ???---> <-sensor0-> <-0-> +- * ------------------------------------------ +- * index in the stream: : | 0x0 | 0x1 | 0x2 | 0x3 | 0x4 | 0x5 | 0x6 | +- * ------------------------------------------ ++ * stream index map for MCU Domain : + * +- * <--sensor1--><-0-> <----big1 ???---> <-sen +- * ------------------------------------------ +- * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD | +- * ------------------------------------------ ++ * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1-----> ++ * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 + * +- * sor0-> <-0-> <-sensor1-> <-0-> .......... +- * ------------------------------------------ +- * | 0x7 | 0x8 | 0x9 | 0xA | 0xB | OxC | OxD | +- * ------------------------------------------ ++ * <-----mcu-tc#1-----> <-----sensor#2-----> <-----sensor#3-----> ++ * 0x0A | 0x0B | 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12 + * +- * And so on ... ++ * <-----mcu-tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7-----> ++ * 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 ++ * ++ * stream index map for AP Domain : ++ * ++ * <-----ap--tc#0-----> <-----sensor#0-----> <-----sensor#1-----> ++ * 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A ++ * ++ * <-----ap--tc#1-----> <-----sensor#2-----> <-----sensor#3-----> ++ * 0x2B | 0x2C | 0x2D | 0x2E | 0x2F | 0x30 | 0x31 | 0x32 | 0x33 ++ * ++ * <-----ap--tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> ++ * 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3A | 0x3B | 0x3C | 0x3D | 0x3E | 0x3F ++ * ++ * <-----ap--tc#3-----> <-----sensor#7-----> <-----sensor#8-----> ++ * 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 | 0x48 + * + * The data description gives the offset of the calibration data in + * this bytes stream for each sensor. +- * +- * Each thermal controller can handle up to 4 sensors max, we don't +- * care if there are less as the array of calibration is sized to 4 +- * anyway. The unused sensor slot will be zeroed. + */ + static int lvts_calibration_init(struct device *dev, struct lvts_ctrl *lvts_ctrl, + const struct lvts_ctrl_data *lvts_ctrl_data, +@@ -1165,7 +1169,7 @@ static int lvts_remove(struct platform_d + return 0; + } + +-static const struct lvts_ctrl_data mt8195_lvts_data_ctrl[] = { ++static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = { + { + .cal_offset = { 0x04, 0x07 }, + .lvts_sensor = { +@@ -1200,13 +1204,63 @@ static const struct lvts_ctrl_data mt819 + } + }; + ++static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = { ++ { ++ .cal_offset = { 0x25, 0x28 }, ++ .lvts_sensor = { ++ { .dt_id = MT8195_AP_VPU0 }, ++ { .dt_id = MT8195_AP_VPU1 } ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x0, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, ++ }, ++ { ++ .cal_offset = { 0x2e, 0x31 }, ++ .lvts_sensor = { ++ { .dt_id = MT8195_AP_GPU0 }, ++ { .dt_id = MT8195_AP_GPU1 } ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x100, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, ++ }, ++ { ++ .cal_offset = { 0x37, 0x3a, 0x3d }, ++ .lvts_sensor = { ++ { .dt_id = MT8195_AP_VDEC }, ++ { .dt_id = MT8195_AP_IMG }, ++ { .dt_id = MT8195_AP_INFRA }, ++ }, ++ .num_lvts_sensor = 3, ++ .offset = 0x200, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, ++ }, ++ { ++ .cal_offset = { 0x43, 0x46 }, ++ .lvts_sensor = { ++ { .dt_id = MT8195_AP_CAM0 }, ++ { .dt_id = MT8195_AP_CAM1 } ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x300, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8195, ++ } ++}; ++ + static const struct lvts_data mt8195_lvts_mcu_data = { +- .lvts_ctrl = mt8195_lvts_data_ctrl, +- .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_data_ctrl), ++ .lvts_ctrl = mt8195_lvts_mcu_data_ctrl, ++ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl), ++}; ++ ++static const struct lvts_data mt8195_lvts_ap_data = { ++ .lvts_ctrl = mt8195_lvts_ap_data_ctrl, ++ .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl), + }; + + static const struct of_device_id lvts_of_match[] = { + { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data }, ++ { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data }, + {}, + }; + MODULE_DEVICE_TABLE(of, lvts_of_match); diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-20-Revert-thermal-drivers-mediatek-Add-delay-after-ther.patch b/target/linux/mediatek/patches-6.1/830-v6.4-20-Revert-thermal-drivers-mediatek-Add-delay-after-ther.patch new file mode 100644 index 00000000000..a48ea3742bb --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-20-Revert-thermal-drivers-mediatek-Add-delay-after-ther.patch @@ -0,0 +1,53 @@ +From 7105a86760bd9e4d107075cefc75016b693a5542 Mon Sep 17 00:00:00 2001 +From: AngeloGioacchino Del Regno +Date: Wed, 19 Apr 2023 08:11:45 +0200 +Subject: [PATCH 16/42] Revert "thermal/drivers/mediatek: Add delay after + thermal banks initialization" + +Some more testing revealed that this commit introduces a regression on some +MT8173 Chromebooks and at least on one MT6795 Sony Xperia M5 smartphone due +to the delay being apparently variable and machine specific. + +Another solution would be to delay for a bit more (~70ms) but this is not +feasible for two reasons: first of all, we're adding an even bigger delay +in a probe function; second, some machines need less, some may need even +more, making the msleep at probe solution highly suboptimal. + +This reverts commit 10debf8c2da8011c8009dd4b3f6d0ab85891c81b. + +Fixes: 10debf8c2da8 ("thermal/drivers/mediatek: Add delay after thermal banks initialization") +Reported-by: "kernelci.org bot" +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230419061146.22246-2-angelogioacchino.delregno@collabora.com +--- + drivers/thermal/mediatek/auxadc_thermal.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -816,6 +816,14 @@ static int mtk_thermal_bank_temperature( + mt, conf->bank_data[bank->id].sensors[i], raw); + + ++ /* ++ * The first read of a sensor often contains very high bogus ++ * temperature value. Filter these out so that the system does ++ * not immediately shut down. ++ */ ++ if (temp > 200000) ++ temp = 0; ++ + if (temp > max) + max = temp; + } +@@ -1273,9 +1281,6 @@ static int mtk_thermal_probe(struct plat + + platform_set_drvdata(pdev, mt); + +- /* Delay for thermal banks to be ready */ +- msleep(30); +- + tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt, + &mtk_thermal_ops); + if (IS_ERR(tzdev)) { diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-21-thermal-drivers-mediatek-Add-temperature-constraints.patch b/target/linux/mediatek/patches-6.1/830-v6.4-21-thermal-drivers-mediatek-Add-temperature-constraints.patch new file mode 100644 index 00000000000..aae87af5d1c --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-21-thermal-drivers-mediatek-Add-temperature-constraints.patch @@ -0,0 +1,78 @@ +From 681b652c9dfc4037d4a55b2733e091a4e1a5de18 Mon Sep 17 00:00:00 2001 +From: AngeloGioacchino Del Regno +Date: Wed, 19 Apr 2023 08:11:46 +0200 +Subject: [PATCH 17/42] thermal/drivers/mediatek: Add temperature constraints + to validate read +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The AUXADC thermal v1 allows reading temperature range between -20°C to +150°C and any value out of this range is invalid. + +Add new definitions for MT8173_TEMP_{MIN_MAX} and a new small helper +mtk_thermal_temp_is_valid() to check if new readings are in range: if +not, we tell to the API that the reading is invalid by returning +THERMAL_TEMP_INVALID. + +It was chosen to introduce the helper function because, even though this +temperature range is realistically ok for all, it comes from a downstream +kernel driver for version 1, but here we also support v2 and v3 which may +may have wider constraints. + +Signed-off-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230419061146.22246-3-angelogioacchino.delregno@collabora.com +--- + drivers/thermal/mediatek/auxadc_thermal.c | 24 +++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -116,6 +116,10 @@ + /* The calibration coefficient of sensor */ + #define MT8173_CALIBRATION 165 + ++/* Valid temperatures range */ ++#define MT8173_TEMP_MIN -20000 ++#define MT8173_TEMP_MAX 150000 ++ + /* + * Layout of the fuses providing the calibration data + * These macros could be used for MT8183, MT8173, MT2701, and MT2712. +@@ -689,6 +693,11 @@ static const struct mtk_thermal_data mt7 + .version = MTK_THERMAL_V3, + }; + ++static bool mtk_thermal_temp_is_valid(int temp) ++{ ++ return (temp >= MT8173_TEMP_MIN) && (temp <= MT8173_TEMP_MAX); ++} ++ + /** + * raw_to_mcelsius_v1 - convert a raw ADC value to mcelsius + * @mt: The thermal controller +@@ -815,14 +824,17 @@ static int mtk_thermal_bank_temperature( + temp = mt->raw_to_mcelsius( + mt, conf->bank_data[bank->id].sensors[i], raw); + +- + /* +- * The first read of a sensor often contains very high bogus +- * temperature value. Filter these out so that the system does +- * not immediately shut down. ++ * Depending on the filt/sen intervals and ADC polling time, ++ * we may need up to 60 milliseconds after initialization: this ++ * will result in the first reading containing an out of range ++ * temperature value. ++ * Validate the reading to both address the aforementioned issue ++ * and to eventually avoid bogus readings during runtime in the ++ * event that the AUXADC gets unstable due to high EMI, etc. + */ +- if (temp > 200000) +- temp = 0; ++ if (!mtk_thermal_temp_is_valid(temp)) ++ temp = THERMAL_TEMP_INVALID; + + if (temp > max) + max = temp; diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-22-thermal-drivers-mediatek-Use-devm_of_iomap-to-avoid-.patch b/target/linux/mediatek/patches-6.1/830-v6.4-22-thermal-drivers-mediatek-Use-devm_of_iomap-to-avoid-.patch new file mode 100644 index 00000000000..782684aacc6 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-22-thermal-drivers-mediatek-Use-devm_of_iomap-to-avoid-.patch @@ -0,0 +1,53 @@ +From 458fa1d508de3f17e49d974a0158d9aeff273a58 Mon Sep 17 00:00:00 2001 +From: Kang Chen +Date: Wed, 19 Apr 2023 10:07:48 +0800 +Subject: [PATCH 18/42] thermal/drivers/mediatek: Use devm_of_iomap to avoid + resource leak in mtk_thermal_probe + +Smatch reports: +1. mtk_thermal_probe() warn: 'apmixed_base' from of_iomap() not released. +2. mtk_thermal_probe() warn: 'auxadc_base' from of_iomap() not released. + +The original code forgets to release iomap resource when handling errors, +fix it by switch to devm_of_iomap. + +Fixes: 89945047b166 ("thermal: mediatek: Add tsensor support for V2 thermal system") +Signed-off-by: Kang Chen +Reviewed-by: Dongliang Mu +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230419020749.621257-1-void0red@hust.edu.cn +--- + drivers/thermal/mediatek/auxadc_thermal.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -1232,7 +1232,12 @@ static int mtk_thermal_probe(struct plat + return -ENODEV; + } + +- auxadc_base = of_iomap(auxadc, 0); ++ auxadc_base = devm_of_iomap(&pdev->dev, auxadc, 0, NULL); ++ if (IS_ERR(auxadc_base)) { ++ of_node_put(auxadc); ++ return PTR_ERR(auxadc_base); ++ } ++ + auxadc_phys_base = of_get_phys_base(auxadc); + + of_node_put(auxadc); +@@ -1248,7 +1253,12 @@ static int mtk_thermal_probe(struct plat + return -ENODEV; + } + +- apmixed_base = of_iomap(apmixedsys, 0); ++ apmixed_base = devm_of_iomap(&pdev->dev, apmixedsys, 0, NULL); ++ if (IS_ERR(apmixed_base)) { ++ of_node_put(apmixedsys); ++ return PTR_ERR(apmixed_base); ++ } ++ + apmixed_phys_base = of_get_phys_base(apmixedsys); + + of_node_put(apmixedsys); diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-23-thermal-drivers-mediatek-Change-clk_prepare_enable-t.patch b/target/linux/mediatek/patches-6.1/830-v6.4-23-thermal-drivers-mediatek-Change-clk_prepare_enable-t.patch new file mode 100644 index 00000000000..d7896dbd60a --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-23-thermal-drivers-mediatek-Change-clk_prepare_enable-t.patch @@ -0,0 +1,100 @@ +From 227d1856924ec00a4f5bdf5afcf77bc7f3f04e86 Mon Sep 17 00:00:00 2001 +From: Kang Chen +Date: Wed, 19 Apr 2023 10:07:49 +0800 +Subject: [PATCH 19/42] thermal/drivers/mediatek: Change clk_prepare_enable to + devm_clk_get_enabled in mtk_thermal_probe + +Use devm_clk_get_enabled to do automatic resource management. +Meanwhile, remove error handling labels in the probe function and +the whole remove function. + +Signed-off-by: Kang Chen +Reviewed-by: Dongliang Mu +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230419020749.621257-2-void0red@hust.edu.cn +--- + drivers/thermal/mediatek/auxadc_thermal.c | 44 +++++------------------ + 1 file changed, 9 insertions(+), 35 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -1206,14 +1206,6 @@ static int mtk_thermal_probe(struct plat + + mt->conf = of_device_get_match_data(&pdev->dev); + +- mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm"); +- if (IS_ERR(mt->clk_peri_therm)) +- return PTR_ERR(mt->clk_peri_therm); +- +- mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc"); +- if (IS_ERR(mt->clk_auxadc)) +- return PTR_ERR(mt->clk_auxadc); +- + mt->thermal_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(mt->thermal_base)) + return PTR_ERR(mt->thermal_base); +@@ -1272,16 +1264,18 @@ static int mtk_thermal_probe(struct plat + if (ret) + return ret; + +- ret = clk_prepare_enable(mt->clk_auxadc); +- if (ret) { ++ mt->clk_auxadc = devm_clk_get_enabled(&pdev->dev, "auxadc"); ++ if (IS_ERR(mt->clk_auxadc)) { ++ ret = PTR_ERR(mt->clk_auxadc); + dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret); + return ret; + } + +- ret = clk_prepare_enable(mt->clk_peri_therm); +- if (ret) { ++ mt->clk_peri_therm = devm_clk_get_enabled(&pdev->dev, "therm"); ++ if (IS_ERR(mt->clk_peri_therm)) { ++ ret = PTR_ERR(mt->clk_peri_therm); + dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret); +- goto err_disable_clk_auxadc; ++ return ret; + } + + mtk_thermal_turn_on_buffer(mt, apmixed_base); +@@ -1305,38 +1299,18 @@ static int mtk_thermal_probe(struct plat + + tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt, + &mtk_thermal_ops); +- if (IS_ERR(tzdev)) { +- ret = PTR_ERR(tzdev); +- goto err_disable_clk_peri_therm; +- } ++ if (IS_ERR(tzdev)) ++ return PTR_ERR(tzdev); + + ret = devm_thermal_add_hwmon_sysfs(&pdev->dev, tzdev); + if (ret) + dev_warn(&pdev->dev, "error in thermal_add_hwmon_sysfs"); + + return 0; +- +-err_disable_clk_peri_therm: +- clk_disable_unprepare(mt->clk_peri_therm); +-err_disable_clk_auxadc: +- clk_disable_unprepare(mt->clk_auxadc); +- +- return ret; +-} +- +-static int mtk_thermal_remove(struct platform_device *pdev) +-{ +- struct mtk_thermal *mt = platform_get_drvdata(pdev); +- +- clk_disable_unprepare(mt->clk_peri_therm); +- clk_disable_unprepare(mt->clk_auxadc); +- +- return 0; + } + + static struct platform_driver mtk_thermal_driver = { + .probe = mtk_thermal_probe, +- .remove = mtk_thermal_remove, + .driver = { + .name = "mtk-thermal", + .of_match_table = mtk_thermal_of_match, diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-24-thermal-drivers-mediatek-Use-of_address_to_resource.patch b/target/linux/mediatek/patches-6.1/830-v6.4-24-thermal-drivers-mediatek-Use-of_address_to_resource.patch new file mode 100644 index 00000000000..fd18a5365c0 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-24-thermal-drivers-mediatek-Use-of_address_to_resource.patch @@ -0,0 +1,36 @@ +From 655fe2533ac05323a07c19ba079bf2064e7741af Mon Sep 17 00:00:00 2001 +From: Rob Herring +Date: Sun, 19 Mar 2023 11:32:31 -0500 +Subject: [PATCH 20/42] thermal/drivers/mediatek: Use of_address_to_resource() + +Replace of_get_address() and of_translate_address() calls with single +call to of_address_to_resource(). + +Signed-off-by: Rob Herring +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230319163231.226738-1-robh@kernel.org +--- + drivers/thermal/mediatek/auxadc_thermal.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -979,14 +979,12 @@ static void mtk_thermal_init_bank(struct + + static u64 of_get_phys_base(struct device_node *np) + { +- u64 size64; +- const __be32 *regaddr_p; ++ struct resource res; + +- regaddr_p = of_get_address(np, 0, &size64, NULL); +- if (!regaddr_p) ++ if (of_address_to_resource(np, 0, &res)) + return OF_BAD_ADDR; + +- return of_translate_address(np, regaddr_p); ++ return res.start; + } + + static int mtk_thermal_extract_efuse_v1(struct mtk_thermal *mt, u32 *buf) diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-25-Revert-thermal-drivers-mediatek-Use-devm_of_iomap-to.patch b/target/linux/mediatek/patches-6.1/830-v6.4-25-Revert-thermal-drivers-mediatek-Use-devm_of_iomap-to.patch new file mode 100644 index 00000000000..c3ff17d5173 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-25-Revert-thermal-drivers-mediatek-Use-devm_of_iomap-to.patch @@ -0,0 +1,57 @@ +From 2c380d07215e6fce3ac66cc5af059bc2c2a69f7a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Ricardo=20Ca=C3=B1uelo?= +Date: Thu, 25 May 2023 14:18:11 +0200 +Subject: [PATCH 21/42] Revert "thermal/drivers/mediatek: Use devm_of_iomap to + avoid resource leak in mtk_thermal_probe" +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This reverts commit f05c7b7d9ea9477fcc388476c6f4ade8c66d2d26. + +That change was causing a regression in the generic-adc-thermal-probed +bootrr test as reported in the kernelci-results list [1]. +A proper rework will take longer, so revert it for now. + +[1] https://groups.io/g/kernelci-results/message/42660 + +Fixes: f05c7b7d9ea9 ("thermal/drivers/mediatek: Use devm_of_iomap to avoid resource leak in mtk_thermal_probe") +Signed-off-by: Ricardo Cañuelo +Suggested-by: AngeloGioacchino Del Regno +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230525121811.3360268-1-ricardo.canuelo@collabora.com +--- + drivers/thermal/mediatek/auxadc_thermal.c | 14 ++------------ + 1 file changed, 2 insertions(+), 12 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -1222,12 +1222,7 @@ static int mtk_thermal_probe(struct plat + return -ENODEV; + } + +- auxadc_base = devm_of_iomap(&pdev->dev, auxadc, 0, NULL); +- if (IS_ERR(auxadc_base)) { +- of_node_put(auxadc); +- return PTR_ERR(auxadc_base); +- } +- ++ auxadc_base = of_iomap(auxadc, 0); + auxadc_phys_base = of_get_phys_base(auxadc); + + of_node_put(auxadc); +@@ -1243,12 +1238,7 @@ static int mtk_thermal_probe(struct plat + return -ENODEV; + } + +- apmixed_base = devm_of_iomap(&pdev->dev, apmixedsys, 0, NULL); +- if (IS_ERR(apmixed_base)) { +- of_node_put(apmixedsys); +- return PTR_ERR(apmixed_base); +- } +- ++ apmixed_base = of_iomap(apmixedsys, 0); + apmixed_phys_base = of_get_phys_base(apmixedsys); + + of_node_put(apmixedsys); diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-26-thermal-drivers-mediatek-lvts_thermal-Register-therm.patch b/target/linux/mediatek/patches-6.1/830-v6.4-26-thermal-drivers-mediatek-lvts_thermal-Register-therm.patch new file mode 100644 index 00000000000..c4456529c1c --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-26-thermal-drivers-mediatek-lvts_thermal-Register-therm.patch @@ -0,0 +1,37 @@ +From 496f4b08981d8a788ad5a2073fa1c65a2af1862b Mon Sep 17 00:00:00 2001 +From: Chen-Yu Tsai +Date: Tue, 13 Jun 2023 17:13:16 +0800 +Subject: [PATCH 22/42] thermal/drivers/mediatek/lvts_thermal: Register thermal + zones as hwmon sensors + +Register thermal zones as hwmon sensors to let userspace read +temperatures using standard hwmon interface. + +Signed-off-by: Chen-Yu Tsai +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230613091317.1691247-1-wenst@chromium.org +--- + drivers/thermal/mediatek/lvts_thermal.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -19,6 +19,8 @@ + #include + #include + ++#include "../thermal_hwmon.h" ++ + #define LVTS_MONCTL0(__base) (__base + 0x0000) + #define LVTS_MONCTL1(__base) (__base + 0x0004) + #define LVTS_MONCTL2(__base) (__base + 0x0008) +@@ -996,6 +998,9 @@ static int lvts_ctrl_start(struct device + return PTR_ERR(tz); + } + ++ if (devm_thermal_add_hwmon_sysfs(dev, tz)) ++ dev_warn(dev, "zone %d: Failed to add hwmon sysfs attributes\n", dt_id); ++ + /* + * The thermal zone pointer will be needed in the + * interrupt handler, we store it in the sensor diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-27-thermal-drivers-mediatek-lvts_thermal-Remove-redunda.patch b/target/linux/mediatek/patches-6.1/830-v6.4-27-thermal-drivers-mediatek-lvts_thermal-Remove-redunda.patch new file mode 100644 index 00000000000..22e7a954ede --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-27-thermal-drivers-mediatek-lvts_thermal-Remove-redunda.patch @@ -0,0 +1,28 @@ +From 885b9768ce2a66ed5d250822aed53d5114c895da Mon Sep 17 00:00:00 2001 +From: Yangtao Li +Date: Tue, 20 Jun 2023 17:07:31 +0800 +Subject: [PATCH 23/42] thermal/drivers/mediatek/lvts_thermal: Remove redundant + msg in lvts_ctrl_start() + +The upper-layer devm_thermal_add_hwmon_sysfs() function can directly +print error information. + +Signed-off-by: Yangtao Li +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230620090732.50025-10-frank.li@vivo.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -998,8 +998,7 @@ static int lvts_ctrl_start(struct device + return PTR_ERR(tz); + } + +- if (devm_thermal_add_hwmon_sysfs(dev, tz)) +- dev_warn(dev, "zone %d: Failed to add hwmon sysfs attributes\n", dt_id); ++ devm_thermal_add_hwmon_sysfs(dev, tz); + + /* + * The thermal zone pointer will be needed in the diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-29-thermal-drivers-mediatek-lvts_thermal-Handle-IRQ-on-.patch b/target/linux/mediatek/patches-6.1/830-v6.4-29-thermal-drivers-mediatek-lvts_thermal-Handle-IRQ-on-.patch new file mode 100644 index 00000000000..bc67727423d --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-29-thermal-drivers-mediatek-lvts_thermal-Handle-IRQ-on-.patch @@ -0,0 +1,40 @@ +From 27b389d9f62c2174f95fe4002b11e77d4cb3ce80 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= + +Date: Thu, 6 Jul 2023 11:37:32 -0400 +Subject: [PATCH 25/42] thermal/drivers/mediatek/lvts_thermal: Handle IRQ on + all controllers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There is a single IRQ handler for each LVTS thermal domain, and it is +supposed to check each of its underlying controllers for the origin of +the interrupt and clear its status. However due to a typo, only the +first controller was ever being handled, which resulted in the interrupt +never being cleared when it happened on the other controllers. Add the +missing index so interrupts are handled for all controllers. + +Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") +Reviewed-by: Matthias Brugger +Reviewed-by: AngeloGioacchino Del Regno +Tested-by: Chen-Yu Tsai +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: Alexandre Mergnat +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230706153823.201943-2-nfraprado@collabora.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -451,7 +451,7 @@ static irqreturn_t lvts_irq_handler(int + + for (i = 0; i < lvts_td->num_lvts_ctrl; i++) { + +- aux = lvts_ctrl_irq_handler(lvts_td->lvts_ctrl); ++ aux = lvts_ctrl_irq_handler(&lvts_td->lvts_ctrl[i]); + if (aux != IRQ_HANDLED) + continue; + diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-30-thermal-drivers-mediatek-lvts_thermal-Honor-sensors-.patch b/target/linux/mediatek/patches-6.1/830-v6.4-30-thermal-drivers-mediatek-lvts_thermal-Honor-sensors-.patch new file mode 100644 index 00000000000..51d119c05b8 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-30-thermal-drivers-mediatek-lvts_thermal-Honor-sensors-.patch @@ -0,0 +1,120 @@ +From 6d827142643ee10c13ff9a1d90f38fb399aa9fff Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= + +Date: Thu, 6 Jul 2023 11:37:33 -0400 +Subject: [PATCH 26/42] thermal/drivers/mediatek/lvts_thermal: Honor sensors in + immediate mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Each controller can be configured to operate on immediate or filtered +mode. On filtered mode, the sensors are enabled by setting the +corresponding bits in MONCTL0, while on immediate mode, by setting +MSRCTL1. + +Previously, the code would set MSRCTL1 for all four sensors when +configured to immediate mode, but given that the controller might not +have all four sensors connected, this would cause interrupts to trigger +for non-existent sensors. Fix this by handling the MSRCTL1 register +analogously to the MONCTL0: only enable the sensors that were declared. + +Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") +Reviewed-by: AngeloGioacchino Del Regno +Tested-by: Chen-Yu Tsai +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: Alexandre Mergnat +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230706153823.201943-3-nfraprado@collabora.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 57 ++++++++++++++----------- + 1 file changed, 33 insertions(+), 24 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -897,24 +897,6 @@ static int lvts_ctrl_configure(struct de + writel(value, LVTS_MSRCTL0(lvts_ctrl->base)); + + /* +- * LVTS_MSRCTL1 : Measurement control +- * +- * Bits: +- * +- * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3 +- * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2 +- * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1 +- * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0 +- * +- * That configuration will ignore the filtering and the delays +- * introduced below in MONCTL1 and MONCTL2 +- */ +- if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) { +- value = BIT(9) | BIT(6) | BIT(5) | BIT(4); +- writel(value, LVTS_MSRCTL1(lvts_ctrl->base)); +- } +- +- /* + * LVTS_MONCTL1 : Period unit and group interval configuration + * + * The clock source of LVTS thermal controller is 26MHz. +@@ -979,6 +961,15 @@ static int lvts_ctrl_start(struct device + struct thermal_zone_device *tz; + u32 sensor_map = 0; + int i; ++ /* ++ * Bitmaps to enable each sensor on immediate and filtered modes, as ++ * described in MSRCTL1 and MONCTL0 registers below, respectively. ++ */ ++ u32 sensor_imm_bitmap[] = { BIT(4), BIT(5), BIT(6), BIT(9) }; ++ u32 sensor_filt_bitmap[] = { BIT(0), BIT(1), BIT(2), BIT(3) }; ++ ++ u32 *sensor_bitmap = lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE ? ++ sensor_imm_bitmap : sensor_filt_bitmap; + + for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) { + +@@ -1016,20 +1007,38 @@ static int lvts_ctrl_start(struct device + * map, so we can enable the temperature monitoring in + * the hardware thermal controller. + */ +- sensor_map |= BIT(i); ++ sensor_map |= sensor_bitmap[i]; + } + + /* +- * Bits: +- * 9: Single point access flow +- * 0-3: Enable sensing point 0-3 +- * + * The initialization of the thermal zones give us + * which sensor point to enable. If any thermal zone + * was not described in the device tree, it won't be + * enabled here in the sensor map. + */ +- writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base)); ++ if (lvts_ctrl->mode == LVTS_MSR_IMMEDIATE_MODE) { ++ /* ++ * LVTS_MSRCTL1 : Measurement control ++ * ++ * Bits: ++ * ++ * 9: Ignore MSRCTL0 config and do immediate measurement on sensor3 ++ * 6: Ignore MSRCTL0 config and do immediate measurement on sensor2 ++ * 5: Ignore MSRCTL0 config and do immediate measurement on sensor1 ++ * 4: Ignore MSRCTL0 config and do immediate measurement on sensor0 ++ * ++ * That configuration will ignore the filtering and the delays ++ * introduced in MONCTL1 and MONCTL2 ++ */ ++ writel(sensor_map, LVTS_MSRCTL1(lvts_ctrl->base)); ++ } else { ++ /* ++ * Bits: ++ * 9: Single point access flow ++ * 0-3: Enable sensing point 0-3 ++ */ ++ writel(sensor_map | BIT(9), LVTS_MONCTL0(lvts_ctrl->base)); ++ } + + return 0; + } diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-31-thermal-drivers-mediatek-lvts_thermal-Use-offset-thr.patch b/target/linux/mediatek/patches-6.1/830-v6.4-31-thermal-drivers-mediatek-lvts_thermal-Use-offset-thr.patch new file mode 100644 index 00000000000..bfbadee3503 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-31-thermal-drivers-mediatek-lvts_thermal-Use-offset-thr.patch @@ -0,0 +1,77 @@ +From 93bb11dd19bdcc1fc97c7ceababd0db9fde128ad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= + +Date: Thu, 6 Jul 2023 11:37:34 -0400 +Subject: [PATCH 27/42] thermal/drivers/mediatek/lvts_thermal: Use offset + threshold for IRQ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There are two kinds of temperature monitoring interrupts available: +* High Offset, Low Offset +* Hot, Hot to normal, Cold + +The code currently uses the hot/h2n/cold interrupts, however in a way +that doesn't work: the cold threshold is left uninitialized, which +prevents the other thresholds from ever triggering, and the h2n +interrupt is used as the lower threshold, which prevents the hot +interrupt from triggering again after the thresholds are updated by the +thermal framework, since a hot interrupt can only trigger again after +the hot to normal interrupt has been triggered. + +But better yet than addressing those issues, is to use the high/low +offset interrupts instead. This way only two thresholds need to be +managed, which have a simpler state machine, making them a better match +to the thermal framework's high and low thresholds. + +Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: Alexandre Mergnat +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230706153823.201943-4-nfraprado@collabora.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -298,9 +298,9 @@ static int lvts_set_trips(struct thermal + u32 raw_high = lvts_temp_to_raw(high); + + /* +- * Hot to normal temperature threshold ++ * Low offset temperature threshold + * +- * LVTS_H2NTHRE ++ * LVTS_OFFSETL + * + * Bits: + * +@@ -309,13 +309,13 @@ static int lvts_set_trips(struct thermal + if (low != -INT_MAX) { + pr_debug("%s: Setting low limit temperature interrupt: %d\n", + thermal_zone_device_type(tz), low); +- writel(raw_low, LVTS_H2NTHRE(base)); ++ writel(raw_low, LVTS_OFFSETL(base)); + } + + /* +- * Hot temperature threshold ++ * High offset temperature threshold + * +- * LVTS_HTHRE ++ * LVTS_OFFSETH + * + * Bits: + * +@@ -323,7 +323,7 @@ static int lvts_set_trips(struct thermal + */ + pr_debug("%s: Setting high limit temperature interrupt: %d\n", + thermal_zone_device_type(tz), high); +- writel(raw_high, LVTS_HTHRE(base)); ++ writel(raw_high, LVTS_OFFSETH(base)); + + return 0; + } diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-32-thermal-drivers-mediatek-lvts_thermal-Disable-undesi.patch b/target/linux/mediatek/patches-6.1/830-v6.4-32-thermal-drivers-mediatek-lvts_thermal-Disable-undesi.patch new file mode 100644 index 00000000000..1c35d0ad199 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-32-thermal-drivers-mediatek-lvts_thermal-Disable-undesi.patch @@ -0,0 +1,51 @@ +From 8f8cab9d3e90acf1db278ef44ad05f10aefb973f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= + +Date: Thu, 6 Jul 2023 11:37:35 -0400 +Subject: [PATCH 28/42] thermal/drivers/mediatek/lvts_thermal: Disable + undesired interrupts +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Out of the many interrupts supported by the hardware, the only ones of +interest to the driver currently are: +* The temperature went over the high offset threshold, for any of the + sensors +* The temperature went below the low offset threshold, for any of the + sensors +* The temperature went over the stage3 threshold + +These are the only thresholds configured by the driver through the +OFFSETH, OFFSETL, and PROTTC registers, respectively. + +The current interrupt mask in LVTS_MONINT_CONF, enables many more +interrupts, including data ready on sensors for both filtered and +immediate mode. These are not only not handled by the driver, but they +are also triggered too often, causing unneeded overhead. Disable these +unnecessary interrupts. + +The meaning of each bit can be seen in the comment describing +LVTS_MONINTST in the IRQ handler. + +Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Alexandre Mergnat +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230706153823.201943-5-nfraprado@collabora.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -65,7 +65,7 @@ + #define LVTS_HW_FILTER 0x2 + #define LVTS_TSSEL_CONF 0x13121110 + #define LVTS_CALSCALE_CONF 0x300 +-#define LVTS_MONINT_CONF 0x9FBF7BDE ++#define LVTS_MONINT_CONF 0x8300318C + + #define LVTS_INT_SENSOR0 0x0009001F + #define LVTS_INT_SENSOR1 0x001203E0 diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-33-thermal-drivers-mediatek-lvts_thermal-Don-t-leave-th.patch b/target/linux/mediatek/patches-6.1/830-v6.4-33-thermal-drivers-mediatek-lvts_thermal-Don-t-leave-th.patch new file mode 100644 index 00000000000..60942fdb895 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-33-thermal-drivers-mediatek-lvts_thermal-Don-t-leave-th.patch @@ -0,0 +1,70 @@ +From bd1ccf9408e6155564530af5e09b53ae497fe332 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= + +Date: Thu, 6 Jul 2023 11:37:36 -0400 +Subject: [PATCH 29/42] thermal/drivers/mediatek/lvts_thermal: Don't leave + threshold zeroed +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The thermal framework might leave the low threshold unset if there +aren't any lower trip points. This leaves the register zeroed, which +translates to a very high temperature for the low threshold. The +interrupt for this threshold is then immediately triggered, and the +state machine gets stuck, preventing any other temperature monitoring +interrupts to ever trigger. + +(The same happens by not setting the Cold or Hot to Normal thresholds +when using those) + +Set the unused threshold to a valid low value. This value was chosen so +that for any valid golden temperature read from the efuse, when the +value is converted to raw and back again to milliCelsius, the result +doesn't underflow. + +Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: Alexandre Mergnat +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230706153823.201943-6-nfraprado@collabora.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -83,6 +83,8 @@ + + #define LVTS_HW_SHUTDOWN_MT8195 105000 + ++#define LVTS_MINIMUM_THRESHOLD 20000 ++ + static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT; + static int coeff_b = LVTS_COEFF_B; + +@@ -294,7 +296,7 @@ static int lvts_set_trips(struct thermal + { + struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); + void __iomem *base = lvts_sensor->base; +- u32 raw_low = lvts_temp_to_raw(low); ++ u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD); + u32 raw_high = lvts_temp_to_raw(high); + + /* +@@ -306,11 +308,9 @@ static int lvts_set_trips(struct thermal + * + * 14-0 : Raw temperature for threshold + */ +- if (low != -INT_MAX) { +- pr_debug("%s: Setting low limit temperature interrupt: %d\n", +- thermal_zone_device_type(tz), low); +- writel(raw_low, LVTS_OFFSETL(base)); +- } ++ pr_debug("%s: Setting low limit temperature interrupt: %d\n", ++ thermal_zone_device_type(tz), low); ++ writel(raw_low, LVTS_OFFSETL(base)); + + /* + * High offset temperature threshold diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-34-thermal-drivers-mediatek-lvts_thermal-Manage-thresho.patch b/target/linux/mediatek/patches-6.1/830-v6.4-34-thermal-drivers-mediatek-lvts_thermal-Manage-thresho.patch new file mode 100644 index 00000000000..e99aa0cdfd9 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-34-thermal-drivers-mediatek-lvts_thermal-Manage-thresho.patch @@ -0,0 +1,156 @@ +From d4dd09968cab3249e6148e1c3fccb51824edb411 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= + +Date: Thu, 6 Jul 2023 11:37:37 -0400 +Subject: [PATCH 30/42] thermal/drivers/mediatek/lvts_thermal: Manage threshold + between sensors +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Each LVTS thermal controller can have up to four sensors, each capable +of triggering its own interrupt when its measured temperature crosses +the configured threshold. The threshold for each sensor is handled +separately by the thermal framework, since each one is registered with +its own thermal zone and trips. However, the temperature thresholds are +configured on the controller, and therefore are shared between all +sensors on that controller. + +When the temperature measured by the sensors is different enough to +cause the thermal framework to configure different thresholds for each +one, interrupts start triggering on sensors outside the last threshold +configured. + +To address the issue, track the thresholds required by each sensor and +only actually set the highest one in the hardware, and disable +interrupts for all sensors outside the current configured range. + +Fixes: f5f633b18234 ("thermal/drivers/mediatek: Add the Low Voltage Thermal Sensor driver") +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: Alexandre Mergnat +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230706153823.201943-7-nfraprado@collabora.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 69 +++++++++++++++++++++++++ + 1 file changed, 69 insertions(+) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -67,6 +67,11 @@ + #define LVTS_CALSCALE_CONF 0x300 + #define LVTS_MONINT_CONF 0x8300318C + ++#define LVTS_MONINT_OFFSET_SENSOR0 0xC ++#define LVTS_MONINT_OFFSET_SENSOR1 0x180 ++#define LVTS_MONINT_OFFSET_SENSOR2 0x3000 ++#define LVTS_MONINT_OFFSET_SENSOR3 0x3000000 ++ + #define LVTS_INT_SENSOR0 0x0009001F + #define LVTS_INT_SENSOR1 0x001203E0 + #define LVTS_INT_SENSOR2 0x00247C00 +@@ -112,6 +117,8 @@ struct lvts_sensor { + void __iomem *base; + int id; + int dt_id; ++ int low_thresh; ++ int high_thresh; + }; + + struct lvts_ctrl { +@@ -121,6 +128,8 @@ struct lvts_ctrl { + int num_lvts_sensor; + int mode; + void __iomem *base; ++ int low_thresh; ++ int high_thresh; + }; + + struct lvts_domain { +@@ -292,12 +301,66 @@ static int lvts_get_temp(struct thermal_ + return 0; + } + ++static void lvts_update_irq_mask(struct lvts_ctrl *lvts_ctrl) ++{ ++ u32 masks[] = { ++ LVTS_MONINT_OFFSET_SENSOR0, ++ LVTS_MONINT_OFFSET_SENSOR1, ++ LVTS_MONINT_OFFSET_SENSOR2, ++ LVTS_MONINT_OFFSET_SENSOR3, ++ }; ++ u32 value = 0; ++ int i; ++ ++ value = readl(LVTS_MONINT(lvts_ctrl->base)); ++ ++ for (i = 0; i < ARRAY_SIZE(masks); i++) { ++ if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh ++ && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh) ++ value |= masks[i]; ++ else ++ value &= ~masks[i]; ++ } ++ ++ writel(value, LVTS_MONINT(lvts_ctrl->base)); ++} ++ ++static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high) ++{ ++ int i; ++ ++ if (high > lvts_ctrl->high_thresh) ++ return true; ++ ++ for (i = 0; i < lvts_ctrl->num_lvts_sensor; i++) ++ if (lvts_ctrl->sensors[i].high_thresh == lvts_ctrl->high_thresh ++ && lvts_ctrl->sensors[i].low_thresh == lvts_ctrl->low_thresh) ++ return false; ++ ++ return true; ++} ++ + static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) + { + struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); ++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]); + void __iomem *base = lvts_sensor->base; + u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD); + u32 raw_high = lvts_temp_to_raw(high); ++ bool should_update_thresh; ++ ++ lvts_sensor->low_thresh = low; ++ lvts_sensor->high_thresh = high; ++ ++ should_update_thresh = lvts_should_update_thresh(lvts_ctrl, high); ++ if (should_update_thresh) { ++ lvts_ctrl->high_thresh = high; ++ lvts_ctrl->low_thresh = low; ++ } ++ lvts_update_irq_mask(lvts_ctrl); ++ ++ if (!should_update_thresh) ++ return 0; + + /* + * Low offset temperature threshold +@@ -521,6 +584,9 @@ static int lvts_sensor_init(struct devic + */ + lvts_sensor[i].msr = lvts_ctrl_data->mode == LVTS_MSR_IMMEDIATE_MODE ? + imm_regs[i] : msr_regs[i]; ++ ++ lvts_sensor[i].low_thresh = INT_MIN; ++ lvts_sensor[i].high_thresh = INT_MIN; + }; + + lvts_ctrl->num_lvts_sensor = lvts_ctrl_data->num_lvts_sensor; +@@ -688,6 +754,9 @@ static int lvts_ctrl_init(struct device + */ + lvts_ctrl[i].hw_tshut_raw_temp = + lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp); ++ ++ lvts_ctrl[i].low_thresh = INT_MIN; ++ lvts_ctrl[i].high_thresh = INT_MIN; + } + + /* diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-35-thermal-drivers-mediatek-lvts-Fix-parameter-check-in.patch b/target/linux/mediatek/patches-6.1/830-v6.4-35-thermal-drivers-mediatek-lvts-Fix-parameter-check-in.patch new file mode 100644 index 00000000000..9ce3eeb74b5 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-35-thermal-drivers-mediatek-lvts-Fix-parameter-check-in.patch @@ -0,0 +1,29 @@ +From 5af4904adc8b840987000724977c13c706d3b7d8 Mon Sep 17 00:00:00 2001 +From: Minjie Du +Date: Thu, 13 Jul 2023 12:24:12 +0800 +Subject: [PATCH 31/42] thermal/drivers/mediatek/lvts: Fix parameter check in + lvts_debugfs_init() + +The documentation says "If an error occurs, ERR_PTR(-ERROR) will be +returned" but the current code checks against a NULL pointer returned. + +Fix this by checking if IS_ERR(). + +Signed-off-by: Minjie Du +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230713042413.2519-1-duminjie@vivo.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -201,7 +201,7 @@ static int lvts_debugfs_init(struct devi + int i; + + lvts_td->dom_dentry = debugfs_create_dir(dev_name(dev), NULL); +- if (!lvts_td->dom_dentry) ++ if (IS_ERR(lvts_td->dom_dentry)) + return 0; + + for (i = 0; i < lvts_td->num_lvts_ctrl; i++) { diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-36-thermal-drivers-mediatek-Clean-up-redundant-dev_err_.patch b/target/linux/mediatek/patches-6.1/830-v6.4-36-thermal-drivers-mediatek-Clean-up-redundant-dev_err_.patch new file mode 100644 index 00000000000..48410549175 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-36-thermal-drivers-mediatek-Clean-up-redundant-dev_err_.patch @@ -0,0 +1,33 @@ +From 6186be80317d1dbda34d35c06c084a083938f2d3 Mon Sep 17 00:00:00 2001 +From: Chen Jiahao +Date: Wed, 2 Aug 2023 17:45:27 +0800 +Subject: [PATCH 32/42] thermal/drivers/mediatek: Clean up redundant + dev_err_probe() + +Referring to platform_get_irq()'s definition, the return value has +already been checked if ret < 0, and printed via dev_err_probe(). +Calling dev_err_probe() one more time outside platform_get_irq() +is obviously redundant. + +Removing dev_err_probe() outside platform_get_irq() to clean up +above problem. + +Signed-off-by: Chen Jiahao +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230802094527.988842-1-chenjiahao16@huawei.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -1216,7 +1216,7 @@ static int lvts_probe(struct platform_de + + irq = platform_get_irq(pdev, 0); + if (irq < 0) +- return dev_err_probe(dev, irq, "No irq resource\n"); ++ return irq; + + ret = lvts_domain_init(dev, lvts_td, lvts_data); + if (ret) diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-37-thermal-drivers-mediatek-lvts_thermal-Make-readings-.patch b/target/linux/mediatek/patches-6.1/830-v6.4-37-thermal-drivers-mediatek-lvts_thermal-Make-readings-.patch new file mode 100644 index 00000000000..c88bf984fa7 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-37-thermal-drivers-mediatek-lvts_thermal-Make-readings-.patch @@ -0,0 +1,95 @@ +From c2ab54ab0425388e65901a7af2fbf69ead968708 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?N=C3=ADcolas=20F=2E=20R=2E=20A=2E=20Prado?= + +Date: Thu, 13 Jul 2023 11:42:37 -0400 +Subject: [PATCH 33/42] thermal/drivers/mediatek/lvts_thermal: Make readings + valid in filtered mode +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently, when a controller is configured to use filtered mode, thermal +readings are valid only about 30% of the time. + +Upon testing, it was noticed that lowering any of the interval settings +resulted in an improved rate of valid data. The same was observed when +decreasing the number of samples for each sensor (which also results in +quicker measurements). + +Retrying the read with a timeout longer than the time it takes to +resample (about 344us with these settings and 4 sensors) also improves +the rate. + +Lower all timing settings to the minimum, configure the filtering to +single sample, and poll the measurement register for at least one period +to improve the data validity on filtered mode. With these changes in +place, out of 100000 reads, a single one failed, ie 99.999% of the data +was valid. + +Reviewed-by: Chen-Yu Tsai +Tested-by: Chen-Yu Tsai +Signed-off-by: Nícolas F. R. A. Prado +Reviewed-by: Alexandre Mergnat +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230713154743.611870-1-nfraprado@collabora.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -58,11 +58,11 @@ + #define LVTS_PROTTC(__base) (__base + 0x00CC) + #define LVTS_CLKEN(__base) (__base + 0x00E4) + +-#define LVTS_PERIOD_UNIT ((118 * 1000) / (256 * 38)) +-#define LVTS_GROUP_INTERVAL 1 +-#define LVTS_FILTER_INTERVAL 1 +-#define LVTS_SENSOR_INTERVAL 1 +-#define LVTS_HW_FILTER 0x2 ++#define LVTS_PERIOD_UNIT 0 ++#define LVTS_GROUP_INTERVAL 0 ++#define LVTS_FILTER_INTERVAL 0 ++#define LVTS_SENSOR_INTERVAL 0 ++#define LVTS_HW_FILTER 0x0 + #define LVTS_TSSEL_CONF 0x13121110 + #define LVTS_CALSCALE_CONF 0x300 + #define LVTS_MONINT_CONF 0x8300318C +@@ -86,6 +86,9 @@ + #define LVTS_MSR_IMMEDIATE_MODE 0 + #define LVTS_MSR_FILTERED_MODE 1 + ++#define LVTS_MSR_READ_TIMEOUT_US 400 ++#define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2) ++ + #define LVTS_HW_SHUTDOWN_MT8195 105000 + + #define LVTS_MINIMUM_THRESHOLD 20000 +@@ -268,6 +271,7 @@ static int lvts_get_temp(struct thermal_ + struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); + void __iomem *msr = lvts_sensor->msr; + u32 value; ++ int rc; + + /* + * Measurement registers: +@@ -280,7 +284,8 @@ static int lvts_get_temp(struct thermal_ + * 16 : Valid temperature + * 15-0 : Raw temperature + */ +- value = readl(msr); ++ rc = readl_poll_timeout(msr, value, value & BIT(16), ++ LVTS_MSR_READ_WAIT_US, LVTS_MSR_READ_TIMEOUT_US); + + /* + * As the thermal zone temperature will read before the +@@ -293,7 +298,7 @@ static int lvts_get_temp(struct thermal_ + * functionning temperature and directly jump to a system + * shutdown. + */ +- if (!(value & BIT(16))) ++ if (rc) + return -EAGAIN; + + *temp = lvts_raw_to_temp(value & 0xFFFF); diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-38-thermal-drivers-mediatek-auxadc_thermal-Removed-call.patch b/target/linux/mediatek/patches-6.1/830-v6.4-38-thermal-drivers-mediatek-auxadc_thermal-Removed-call.patch new file mode 100644 index 00000000000..994461cdb16 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-38-thermal-drivers-mediatek-auxadc_thermal-Removed-call.patch @@ -0,0 +1,30 @@ +From c864ff9de3b225b43bb8e08dedb223632323e059 Mon Sep 17 00:00:00 2001 +From: Andrei Coardos +Date: Fri, 11 Aug 2023 22:28:47 +0300 +Subject: [PATCH 34/42] thermal/drivers/mediatek/auxadc_thermal: Removed call + to platform_set_drvdata() + +This function call was found to be unnecessary as there is no equivalent +platform_get_drvdata() call to access the private data of the driver. Also, +the private data is defined in this driver, so there is no risk of it being +accessed outside of this driver file. + +Signed-off-by: Andrei Coardos +Reviewed-by: Alexandru Ardelean +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230811192847.3838-1-aboutphysycs@gmail.com +--- + drivers/thermal/mediatek/auxadc_thermal.c | 2 -- + 1 file changed, 2 deletions(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -1283,8 +1283,6 @@ static int mtk_thermal_probe(struct plat + mtk_thermal_init_bank(mt, i, apmixed_phys_base, + auxadc_phys_base, ctrl_id); + +- platform_set_drvdata(pdev, mt); +- + tzdev = devm_thermal_of_zone_register(&pdev->dev, 0, mt, + &mtk_thermal_ops); + if (IS_ERR(tzdev)) diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-39-thermal-lvts-Convert-to-platform-remove-callback-ret.patch b/target/linux/mediatek/patches-6.1/830-v6.4-39-thermal-lvts-Convert-to-platform-remove-callback-ret.patch new file mode 100644 index 00000000000..b3bfa37458c --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-39-thermal-lvts-Convert-to-platform-remove-callback-ret.patch @@ -0,0 +1,58 @@ +From 6cf96078969ec00b873db99bae4e47001290685e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= +Date: Wed, 27 Sep 2023 21:37:23 +0200 +Subject: [PATCH 35/42] thermal: lvts: Convert to platform remove callback + returning void +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The .remove() callback for a platform driver returns an int which makes +many driver authors wrongly assume it's possible to do error handling by +returning an error code. However the value returned is ignored (apart +from emitting a warning) and this typically results in resource leaks. + +To improve here there is a quest to make the remove callback return +void. In the first step of this quest all drivers are converted to +.remove_new(), which already returns void. Eventually after all drivers +are converted, .remove_new() will be renamed to .remove(). + +Trivially convert this driver from always returning zero in the remove +callback to the void returning variant. + +Signed-off-by: Uwe Kleine-König +Acked-by: Daniel Lezcano +Signed-off-by: Rafael J. Wysocki +--- + drivers/thermal/mediatek/lvts_thermal.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -1241,7 +1241,7 @@ static int lvts_probe(struct platform_de + return 0; + } + +-static int lvts_remove(struct platform_device *pdev) ++static void lvts_remove(struct platform_device *pdev) + { + struct lvts_domain *lvts_td; + int i; +@@ -1252,8 +1252,6 @@ static int lvts_remove(struct platform_d + lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false); + + lvts_debugfs_exit(lvts_td); +- +- return 0; + } + + static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = { +@@ -1354,7 +1352,7 @@ MODULE_DEVICE_TABLE(of, lvts_of_match); + + static struct platform_driver lvts_driver = { + .probe = lvts_probe, +- .remove = lvts_remove, ++ .remove_new = lvts_remove, + .driver = { + .name = "mtk-lvts-thermal", + .of_match_table = lvts_of_match, diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-40-thermal-drivers-mediatek-lvts_thermal-Make-coeff-con.patch b/target/linux/mediatek/patches-6.1/830-v6.4-40-thermal-drivers-mediatek-lvts_thermal-Make-coeff-con.patch new file mode 100644 index 00000000000..16a32f564bf --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-40-thermal-drivers-mediatek-lvts_thermal-Make-coeff-con.patch @@ -0,0 +1,198 @@ +From 26cc18a3d6d9eac21c4f4b4bb96147b2c6617c86 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 22 Sep 2023 07:50:19 +0200 +Subject: [PATCH 36/42] thermal/drivers/mediatek/lvts_thermal: Make coeff + configurable + +The upcoming mt7988 has different temperature coefficients so we +cannot use constants in the functions lvts_golden_temp_init, +lvts_golden_temp_init and lvts_raw_to_temp anymore. + +Add a field in the lvts_ctrl pointing to the lvts_data which now +contains the soc-specific temperature coefficents. + +To make the code better readable, rename static int coeff_b to +golden_temp_offset, COEFF_A to temp_factor and COEFF_B to temp_offset. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Tested-by: Daniel Golle +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230922055020.6436-4-linux@fw-web.de +--- + drivers/thermal/mediatek/lvts_thermal.c | 51 ++++++++++++++++--------- + 1 file changed, 34 insertions(+), 17 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -80,8 +80,8 @@ + #define LVTS_SENSOR_MAX 4 + #define LVTS_GOLDEN_TEMP_MAX 62 + #define LVTS_GOLDEN_TEMP_DEFAULT 50 +-#define LVTS_COEFF_A -250460 +-#define LVTS_COEFF_B 250460 ++#define LVTS_COEFF_A_MT8195 -250460 ++#define LVTS_COEFF_B_MT8195 250460 + + #define LVTS_MSR_IMMEDIATE_MODE 0 + #define LVTS_MSR_FILTERED_MODE 1 +@@ -94,7 +94,7 @@ + #define LVTS_MINIMUM_THRESHOLD 20000 + + static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT; +-static int coeff_b = LVTS_COEFF_B; ++static int golden_temp_offset; + + struct lvts_sensor_data { + int dt_id; +@@ -112,6 +112,8 @@ struct lvts_ctrl_data { + struct lvts_data { + const struct lvts_ctrl_data *lvts_ctrl; + int num_lvts_ctrl; ++ int temp_factor; ++ int temp_offset; + }; + + struct lvts_sensor { +@@ -126,6 +128,7 @@ struct lvts_sensor { + + struct lvts_ctrl { + struct lvts_sensor sensors[LVTS_SENSOR_MAX]; ++ const struct lvts_data *lvts_data; + u32 calibration[LVTS_SENSOR_MAX]; + u32 hw_tshut_raw_temp; + int num_lvts_sensor; +@@ -247,21 +250,21 @@ static void lvts_debugfs_exit(struct lvt + + #endif + +-static int lvts_raw_to_temp(u32 raw_temp) ++static int lvts_raw_to_temp(u32 raw_temp, int temp_factor) + { + int temperature; + +- temperature = ((s64)(raw_temp & 0xFFFF) * LVTS_COEFF_A) >> 14; +- temperature += coeff_b; ++ temperature = ((s64)(raw_temp & 0xFFFF) * temp_factor) >> 14; ++ temperature += golden_temp_offset; + + return temperature; + } + +-static u32 lvts_temp_to_raw(int temperature) ++static u32 lvts_temp_to_raw(int temperature, int temp_factor) + { +- u32 raw_temp = ((s64)(coeff_b - temperature)) << 14; ++ u32 raw_temp = ((s64)(golden_temp_offset - temperature)) << 14; + +- raw_temp = div_s64(raw_temp, -LVTS_COEFF_A); ++ raw_temp = div_s64(raw_temp, -temp_factor); + + return raw_temp; + } +@@ -269,6 +272,9 @@ static u32 lvts_temp_to_raw(int temperat + static int lvts_get_temp(struct thermal_zone_device *tz, int *temp) + { + struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); ++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, ++ sensors[lvts_sensor->id]); ++ const struct lvts_data *lvts_data = lvts_ctrl->lvts_data; + void __iomem *msr = lvts_sensor->msr; + u32 value; + int rc; +@@ -301,7 +307,7 @@ static int lvts_get_temp(struct thermal_ + if (rc) + return -EAGAIN; + +- *temp = lvts_raw_to_temp(value & 0xFFFF); ++ *temp = lvts_raw_to_temp(value & 0xFFFF, lvts_data->temp_factor); + + return 0; + } +@@ -348,10 +354,13 @@ static bool lvts_should_update_thresh(st + static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high) + { + struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz); +- struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]); ++ struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, ++ sensors[lvts_sensor->id]); ++ const struct lvts_data *lvts_data = lvts_ctrl->lvts_data; + void __iomem *base = lvts_sensor->base; +- u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD); +- u32 raw_high = lvts_temp_to_raw(high); ++ u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD, ++ lvts_data->temp_factor); ++ u32 raw_high = lvts_temp_to_raw(high, lvts_data->temp_factor); + bool should_update_thresh; + + lvts_sensor->low_thresh = low; +@@ -692,7 +701,7 @@ static int lvts_calibration_read(struct + return 0; + } + +-static int lvts_golden_temp_init(struct device *dev, u32 *value) ++static int lvts_golden_temp_init(struct device *dev, u32 *value, int temp_offset) + { + u32 gt; + +@@ -701,7 +710,7 @@ static int lvts_golden_temp_init(struct + if (gt && gt < LVTS_GOLDEN_TEMP_MAX) + golden_temp = gt; + +- coeff_b = golden_temp * 500 + LVTS_COEFF_B; ++ golden_temp_offset = golden_temp * 500 + temp_offset; + + return 0; + } +@@ -724,7 +733,7 @@ static int lvts_ctrl_init(struct device + * The golden temp information is contained in the first chunk + * of efuse data. + */ +- ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib); ++ ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib, lvts_data->temp_offset); + if (ret) + return ret; + +@@ -735,6 +744,7 @@ static int lvts_ctrl_init(struct device + for (i = 0; i < lvts_data->num_lvts_ctrl; i++) { + + lvts_ctrl[i].base = lvts_td->base + lvts_data->lvts_ctrl[i].offset; ++ lvts_ctrl[i].lvts_data = lvts_data; + + ret = lvts_sensor_init(dev, &lvts_ctrl[i], + &lvts_data->lvts_ctrl[i]); +@@ -758,7 +768,8 @@ static int lvts_ctrl_init(struct device + * after initializing the calibration. + */ + lvts_ctrl[i].hw_tshut_raw_temp = +- lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp); ++ lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp, ++ lvts_data->temp_factor); + + lvts_ctrl[i].low_thresh = INT_MIN; + lvts_ctrl[i].high_thresh = INT_MIN; +@@ -1223,6 +1234,8 @@ static int lvts_probe(struct platform_de + if (irq < 0) + return irq; + ++ golden_temp_offset = lvts_data->temp_offset; ++ + ret = lvts_domain_init(dev, lvts_td, lvts_data); + if (ret) + return dev_err_probe(dev, ret, "Failed to initialize the lvts domain\n"); +@@ -1336,11 +1349,15 @@ static const struct lvts_ctrl_data mt819 + static const struct lvts_data mt8195_lvts_mcu_data = { + .lvts_ctrl = mt8195_lvts_mcu_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl), ++ .temp_factor = LVTS_COEFF_A_MT8195, ++ .temp_offset = LVTS_COEFF_B_MT8195, + }; + + static const struct lvts_data mt8195_lvts_ap_data = { + .lvts_ctrl = mt8195_lvts_ap_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl), ++ .temp_factor = LVTS_COEFF_A_MT8195, ++ .temp_offset = LVTS_COEFF_B_MT8195, + }; + + static const struct of_device_id lvts_of_match[] = { diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-41-dt-bindings-thermal-mediatek-Add-LVTS-thermal-sensor.patch b/target/linux/mediatek/patches-6.1/830-v6.4-41-dt-bindings-thermal-mediatek-Add-LVTS-thermal-sensor.patch new file mode 100644 index 00000000000..1c2146f43f9 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-41-dt-bindings-thermal-mediatek-Add-LVTS-thermal-sensor.patch @@ -0,0 +1,35 @@ +From be2cc09bd5b46f13629d4fcdeac7ad1b18bb1a0b Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 22 Sep 2023 07:50:18 +0200 +Subject: [PATCH] dt-bindings: thermal: mediatek: Add LVTS thermal sensors for + mt7988 + +Add sensor constants for MT7988. + +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Acked-by: Conor Dooley +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230922055020.6436-3-linux@fw-web.de +--- + include/dt-bindings/thermal/mediatek,lvts-thermal.h | 9 +++++++++ + 1 file changed, 9 insertions(+) + +--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h ++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h +@@ -7,6 +7,15 @@ + #ifndef __MEDIATEK_LVTS_DT_H + #define __MEDIATEK_LVTS_DT_H + ++#define MT7988_CPU_0 0 ++#define MT7988_CPU_1 1 ++#define MT7988_ETH2P5G_0 2 ++#define MT7988_ETH2P5G_1 3 ++#define MT7988_TOPS_0 4 ++#define MT7988_TOPS_1 5 ++#define MT7988_ETHWARP_0 6 ++#define MT7988_ETHWARP_1 7 ++ + #define MT8195_MCU_BIG_CPU0 0 + #define MT8195_MCU_BIG_CPU1 1 + #define MT8195_MCU_BIG_CPU2 2 diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-42-thermal-drivers-mediatek-lvts_thermal-Add-mt7988-sup.patch b/target/linux/mediatek/patches-6.1/830-v6.4-42-thermal-drivers-mediatek-lvts_thermal-Add-mt7988-sup.patch new file mode 100644 index 00000000000..97c803a820b --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-42-thermal-drivers-mediatek-lvts_thermal-Add-mt7988-sup.patch @@ -0,0 +1,91 @@ +From 9924e9b91b43aaa1610a1d59c4caa43785948cf6 Mon Sep 17 00:00:00 2001 +From: Frank Wunderlich +Date: Fri, 22 Sep 2023 07:50:20 +0200 +Subject: [PATCH 37/42] thermal/drivers/mediatek/lvts_thermal: Add mt7988 + support + +Add Support for Mediatek Filogic 880/MT7988 LVTS. + +Signed-off-by: Frank Wunderlich +Tested-by: Daniel Golle +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230922055020.6436-5-linux@fw-web.de +--- + drivers/thermal/mediatek/lvts_thermal.c | 38 +++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -82,6 +82,8 @@ + #define LVTS_GOLDEN_TEMP_DEFAULT 50 + #define LVTS_COEFF_A_MT8195 -250460 + #define LVTS_COEFF_B_MT8195 250460 ++#define LVTS_COEFF_A_MT7988 -204650 ++#define LVTS_COEFF_B_MT7988 204650 + + #define LVTS_MSR_IMMEDIATE_MODE 0 + #define LVTS_MSR_FILTERED_MODE 1 +@@ -89,6 +91,7 @@ + #define LVTS_MSR_READ_TIMEOUT_US 400 + #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2) + ++#define LVTS_HW_SHUTDOWN_MT7988 105000 + #define LVTS_HW_SHUTDOWN_MT8195 105000 + + #define LVTS_MINIMUM_THRESHOLD 20000 +@@ -1267,6 +1270,33 @@ static void lvts_remove(struct platform_ + lvts_debugfs_exit(lvts_td); + } + ++static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = { ++ { ++ .cal_offset = { 0x00, 0x04, 0x08, 0x0c }, ++ .lvts_sensor = { ++ { .dt_id = MT7988_CPU_0 }, ++ { .dt_id = MT7988_CPU_1 }, ++ { .dt_id = MT7988_ETH2P5G_0 }, ++ { .dt_id = MT7988_ETH2P5G_1 } ++ }, ++ .num_lvts_sensor = 4, ++ .offset = 0x0, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988, ++ }, ++ { ++ .cal_offset = { 0x14, 0x18, 0x1c, 0x20 }, ++ .lvts_sensor = { ++ { .dt_id = MT7988_TOPS_0}, ++ { .dt_id = MT7988_TOPS_1}, ++ { .dt_id = MT7988_ETHWARP_0}, ++ { .dt_id = MT7988_ETHWARP_1} ++ }, ++ .num_lvts_sensor = 4, ++ .offset = 0x100, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988, ++ } ++}; ++ + static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = { + { + .cal_offset = { 0x04, 0x07 }, +@@ -1346,6 +1376,13 @@ static const struct lvts_ctrl_data mt819 + } + }; + ++static const struct lvts_data mt7988_lvts_ap_data = { ++ .lvts_ctrl = mt7988_lvts_ap_data_ctrl, ++ .num_lvts_ctrl = ARRAY_SIZE(mt7988_lvts_ap_data_ctrl), ++ .temp_factor = LVTS_COEFF_A_MT7988, ++ .temp_offset = LVTS_COEFF_B_MT7988, ++}; ++ + static const struct lvts_data mt8195_lvts_mcu_data = { + .lvts_ctrl = mt8195_lvts_mcu_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl), +@@ -1361,6 +1398,7 @@ static const struct lvts_data mt8195_lvt + }; + + static const struct of_device_id lvts_of_match[] = { ++ { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data }, + { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data }, + { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data }, + {}, diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-43-thermal-drivers-mediatek-lvts_thermal-Fix-error-chec.patch b/target/linux/mediatek/patches-6.1/830-v6.4-43-thermal-drivers-mediatek-lvts_thermal-Fix-error-chec.patch new file mode 100644 index 00000000000..5b212a2a372 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-43-thermal-drivers-mediatek-lvts_thermal-Fix-error-chec.patch @@ -0,0 +1,30 @@ +From fb1bbb5b63e4e3c788a978724749ced57d208054 Mon Sep 17 00:00:00 2001 +From: Minjie Du +Date: Thu, 21 Sep 2023 17:10:50 +0800 +Subject: [PATCH 38/42] thermal/drivers/mediatek/lvts_thermal: Fix error check + in lvts_debugfs_init() + +debugfs_create_dir() function returns an error value embedded in +the pointer (PTR_ERR). Evaluate the return value using IS_ERR +rather than checking for NULL. + +Signed-off-by: Minjie Du +Reviewed-by: Alexandre Mergnat +Reviewed-by: Chen-Yu Tsai +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230921091057.3812-1-duminjie@vivo.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -219,7 +219,7 @@ static int lvts_debugfs_init(struct devi + + sprintf(name, "controller%d", i); + dentry = debugfs_create_dir(name, lvts_td->dom_dentry); +- if (!dentry) ++ if (IS_ERR(dentry)) + continue; + + regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL); diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-44-thermal-drivers-mediatek-Fix-probe-for-THERMAL_V2.patch b/target/linux/mediatek/patches-6.1/830-v6.4-44-thermal-drivers-mediatek-Fix-probe-for-THERMAL_V2.patch new file mode 100644 index 00000000000..88f383c4aec --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-44-thermal-drivers-mediatek-Fix-probe-for-THERMAL_V2.patch @@ -0,0 +1,33 @@ +From e6f43063f2fe9f08b34797bc6d223f7d63b01910 Mon Sep 17 00:00:00 2001 +From: Markus Schneider-Pargmann +Date: Mon, 18 Sep 2023 12:07:06 +0200 +Subject: [PATCH 39/42] thermal/drivers/mediatek: Fix probe for THERMAL_V2 + +Fix the probe function to call mtk_thermal_release_periodic_ts for +everything != MTK_THERMAL_V1. This was accidentally changed from V1 +to V2 in the original patch. + +Reported-by: Frank Wunderlich +Closes: https://lore.kernel.org/lkml/B0B3775B-B8D1-4284-814F-4F41EC22F532@public-files.de/ +Reported-by: Daniel Lezcano +Closes: https://lore.kernel.org/lkml/07a569b9-e691-64ea-dd65-3b49842af33d@linaro.org/ +Fixes: 33140e668b10 ("thermal/drivers/mediatek: Control buffer enablement tweaks") +Signed-off-by: Markus Schneider-Pargmann +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20230918100706.1229239-1-msp@baylibre.com +--- + drivers/thermal/mediatek/auxadc_thermal.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -1268,7 +1268,7 @@ static int mtk_thermal_probe(struct plat + + mtk_thermal_turn_on_buffer(mt, apmixed_base); + +- if (mt->conf->version != MTK_THERMAL_V2) ++ if (mt->conf->version != MTK_THERMAL_V1) + mtk_thermal_release_periodic_ts(mt, auxadc_base); + + if (mt->conf->version == MTK_THERMAL_V1) diff --git a/target/linux/mediatek/patches-6.1/830-v6.4-45-thermal-drivers-mediatek-lvts_thermal-Add-suspend-an.patch b/target/linux/mediatek/patches-6.1/830-v6.4-45-thermal-drivers-mediatek-lvts_thermal-Add-suspend-an.patch new file mode 100644 index 00000000000..7b4b124b561 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.4-45-thermal-drivers-mediatek-lvts_thermal-Add-suspend-an.patch @@ -0,0 +1,83 @@ +From a1d874ef3376295ee8ed89b3b5315f4c840ff00b Mon Sep 17 00:00:00 2001 +From: Balsam CHIHI +Date: Tue, 17 Oct 2023 21:05:42 +0200 +Subject: [PATCH 40/42] thermal/drivers/mediatek/lvts_thermal: Add suspend and + resume +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add suspend and resume support to LVTS driver. + +Signed-off-by: Balsam CHIHI +[bero@baylibre.com: suspend/resume in noirq phase] +Co-developed-by: Bernhard Rosenkränzer +Signed-off-by: Bernhard Rosenkränzer +Reviewed-by: Matthias Brugger +Reviewed-by: Alexandre Mergnat +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20231017190545.157282-3-bero@baylibre.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 37 +++++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -1297,6 +1297,38 @@ static const struct lvts_ctrl_data mt798 + } + }; + ++static int lvts_suspend(struct device *dev) ++{ ++ struct lvts_domain *lvts_td; ++ int i; ++ ++ lvts_td = dev_get_drvdata(dev); ++ ++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) ++ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false); ++ ++ clk_disable_unprepare(lvts_td->clk); ++ ++ return 0; ++} ++ ++static int lvts_resume(struct device *dev) ++{ ++ struct lvts_domain *lvts_td; ++ int i, ret; ++ ++ lvts_td = dev_get_drvdata(dev); ++ ++ ret = clk_prepare_enable(lvts_td->clk); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < lvts_td->num_lvts_ctrl; i++) ++ lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], true); ++ ++ return 0; ++} ++ + static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = { + { + .cal_offset = { 0x04, 0x07 }, +@@ -1405,12 +1437,17 @@ static const struct of_device_id lvts_of + }; + MODULE_DEVICE_TABLE(of, lvts_of_match); + ++static const struct dev_pm_ops lvts_pm_ops = { ++ NOIRQ_SYSTEM_SLEEP_PM_OPS(lvts_suspend, lvts_resume) ++}; ++ + static struct platform_driver lvts_driver = { + .probe = lvts_probe, + .remove_new = lvts_remove, + .driver = { + .name = "mtk-lvts-thermal", + .of_match_table = lvts_of_match, ++ .pm = &lvts_pm_ops, + }, + }; + module_platform_driver(lvts_driver); diff --git a/target/linux/mediatek/patches-6.1/830-v6.7-46-dt-bindings-thermal-mediatek-Add-LVTS-thermal-contro.patch b/target/linux/mediatek/patches-6.1/830-v6.7-46-dt-bindings-thermal-mediatek-Add-LVTS-thermal-contro.patch new file mode 100644 index 00000000000..c278168610f --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.7-46-dt-bindings-thermal-mediatek-Add-LVTS-thermal-contro.patch @@ -0,0 +1,49 @@ +From 0bb4937b58ab712f158588376dbac97f8e9df68e Mon Sep 17 00:00:00 2001 +From: Balsam CHIHI +Date: Tue, 17 Oct 2023 21:05:41 +0200 +Subject: [PATCH] dt-bindings: thermal: mediatek: Add LVTS thermal controller + definition for mt8192 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add LVTS thermal controller definition for MT8192. + +Signed-off-by: Balsam CHIHI +Reviewed-by: AngeloGioacchino Del Regno +Acked-by: Krzysztof Kozlowski +Signed-off-by: Bernhard Rosenkränzer +Reviewed-by: Matthias Brugger +Reviewed-by: Alexandre Mergnat +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20231017190545.157282-2-bero@baylibre.com +--- + .../thermal/mediatek,lvts-thermal.h | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +--- a/include/dt-bindings/thermal/mediatek,lvts-thermal.h ++++ b/include/dt-bindings/thermal/mediatek,lvts-thermal.h +@@ -35,4 +35,23 @@ + #define MT8195_AP_CAM0 15 + #define MT8195_AP_CAM1 16 + ++#define MT8192_MCU_BIG_CPU0 0 ++#define MT8192_MCU_BIG_CPU1 1 ++#define MT8192_MCU_BIG_CPU2 2 ++#define MT8192_MCU_BIG_CPU3 3 ++#define MT8192_MCU_LITTLE_CPU0 4 ++#define MT8192_MCU_LITTLE_CPU1 5 ++#define MT8192_MCU_LITTLE_CPU2 6 ++#define MT8192_MCU_LITTLE_CPU3 7 ++ ++#define MT8192_AP_VPU0 8 ++#define MT8192_AP_VPU1 9 ++#define MT8192_AP_GPU0 10 ++#define MT8192_AP_GPU1 11 ++#define MT8192_AP_INFRA 12 ++#define MT8192_AP_CAM 13 ++#define MT8192_AP_MD0 14 ++#define MT8192_AP_MD1 15 ++#define MT8192_AP_MD2 16 ++ + #endif /* __MEDIATEK_LVTS_DT_H */ diff --git a/target/linux/mediatek/patches-6.1/830-v6.7-47-thermal-drivers-mediatek-lvts_thermal-Add-mt8192-sup.patch b/target/linux/mediatek/patches-6.1/830-v6.7-47-thermal-drivers-mediatek-lvts_thermal-Add-mt8192-sup.patch new file mode 100644 index 00000000000..6d68a6cd579 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.7-47-thermal-drivers-mediatek-lvts_thermal-Add-mt8192-sup.patch @@ -0,0 +1,151 @@ +From 7d8b3864b38d881cf105328ff8569f47446811ad Mon Sep 17 00:00:00 2001 +From: Balsam CHIHI +Date: Tue, 17 Oct 2023 21:05:43 +0200 +Subject: [PATCH 41/42] thermal/drivers/mediatek/lvts_thermal: Add mt8192 + support +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add LVTS Driver support for MT8192. + +Co-developed-by: Nícolas F. R. A. Prado +Signed-off-by: Nícolas F. R. A. Prado +Signed-off-by: Balsam CHIHI +Reviewed-by: Nícolas F. R. A. Prado +[bero@baylibre.com: cosmetic changes, rebase] +Signed-off-by: Bernhard Rosenkränzer +Reviewed-by: Matthias Brugger +Reviewed-by: Alexandre Mergnat +Reviewed-by: AngeloGioacchino Del Regno +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20231017190545.157282-4-bero@baylibre.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 95 +++++++++++++++++++++++++ + 1 file changed, 95 insertions(+) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -92,6 +92,7 @@ + #define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2) + + #define LVTS_HW_SHUTDOWN_MT7988 105000 ++#define LVTS_HW_SHUTDOWN_MT8192 105000 + #define LVTS_HW_SHUTDOWN_MT8195 105000 + + #define LVTS_MINIMUM_THRESHOLD 20000 +@@ -1329,6 +1330,88 @@ static int lvts_resume(struct device *de + return 0; + } + ++static const struct lvts_ctrl_data mt8192_lvts_mcu_data_ctrl[] = { ++ { ++ .cal_offset = { 0x04, 0x08 }, ++ .lvts_sensor = { ++ { .dt_id = MT8192_MCU_BIG_CPU0 }, ++ { .dt_id = MT8192_MCU_BIG_CPU1 } ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x0, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, ++ .mode = LVTS_MSR_FILTERED_MODE, ++ }, ++ { ++ .cal_offset = { 0x0c, 0x10 }, ++ .lvts_sensor = { ++ { .dt_id = MT8192_MCU_BIG_CPU2 }, ++ { .dt_id = MT8192_MCU_BIG_CPU3 } ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x100, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, ++ .mode = LVTS_MSR_FILTERED_MODE, ++ }, ++ { ++ .cal_offset = { 0x14, 0x18, 0x1c, 0x20 }, ++ .lvts_sensor = { ++ { .dt_id = MT8192_MCU_LITTLE_CPU0 }, ++ { .dt_id = MT8192_MCU_LITTLE_CPU1 }, ++ { .dt_id = MT8192_MCU_LITTLE_CPU2 }, ++ { .dt_id = MT8192_MCU_LITTLE_CPU3 } ++ }, ++ .num_lvts_sensor = 4, ++ .offset = 0x200, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, ++ .mode = LVTS_MSR_FILTERED_MODE, ++ } ++}; ++ ++static const struct lvts_ctrl_data mt8192_lvts_ap_data_ctrl[] = { ++ { ++ .cal_offset = { 0x24, 0x28 }, ++ .lvts_sensor = { ++ { .dt_id = MT8192_AP_VPU0 }, ++ { .dt_id = MT8192_AP_VPU1 } ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x0, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, ++ }, ++ { ++ .cal_offset = { 0x2c, 0x30 }, ++ .lvts_sensor = { ++ { .dt_id = MT8192_AP_GPU0 }, ++ { .dt_id = MT8192_AP_GPU1 } ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x100, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, ++ }, ++ { ++ .cal_offset = { 0x34, 0x38 }, ++ .lvts_sensor = { ++ { .dt_id = MT8192_AP_INFRA }, ++ { .dt_id = MT8192_AP_CAM }, ++ }, ++ .num_lvts_sensor = 2, ++ .offset = 0x200, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, ++ }, ++ { ++ .cal_offset = { 0x3c, 0x40, 0x44 }, ++ .lvts_sensor = { ++ { .dt_id = MT8192_AP_MD0 }, ++ { .dt_id = MT8192_AP_MD1 }, ++ { .dt_id = MT8192_AP_MD2 } ++ }, ++ .num_lvts_sensor = 3, ++ .offset = 0x300, ++ .hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192, ++ } ++}; ++ + static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = { + { + .cal_offset = { 0x04, 0x07 }, +@@ -1415,6 +1498,16 @@ static const struct lvts_data mt7988_lvt + .temp_offset = LVTS_COEFF_B_MT7988, + }; + ++static const struct lvts_data mt8192_lvts_mcu_data = { ++ .lvts_ctrl = mt8192_lvts_mcu_data_ctrl, ++ .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_mcu_data_ctrl), ++}; ++ ++static const struct lvts_data mt8192_lvts_ap_data = { ++ .lvts_ctrl = mt8192_lvts_ap_data_ctrl, ++ .num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_ap_data_ctrl), ++}; ++ + static const struct lvts_data mt8195_lvts_mcu_data = { + .lvts_ctrl = mt8195_lvts_mcu_data_ctrl, + .num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl), +@@ -1431,6 +1524,8 @@ static const struct lvts_data mt8195_lvt + + static const struct of_device_id lvts_of_match[] = { + { .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data }, ++ { .compatible = "mediatek,mt8192-lvts-mcu", .data = &mt8192_lvts_mcu_data }, ++ { .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data }, + { .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data }, + { .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data }, + {}, diff --git a/target/linux/mediatek/patches-6.1/830-v6.7-48-thermal-drivers-mediatek-lvts_thermal-Update-calibra.patch b/target/linux/mediatek/patches-6.1/830-v6.7-48-thermal-drivers-mediatek-lvts_thermal-Update-calibra.patch new file mode 100644 index 00000000000..c20c0b5f2e3 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/830-v6.7-48-thermal-drivers-mediatek-lvts_thermal-Update-calibra.patch @@ -0,0 +1,70 @@ +From 5d126a3c87cf7964b28bacf3826eea4266265bce Mon Sep 17 00:00:00 2001 +From: Balsam CHIHI +Date: Tue, 17 Oct 2023 21:05:45 +0200 +Subject: [PATCH 42/42] thermal/drivers/mediatek/lvts_thermal: Update + calibration data documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Update LVTS calibration data documentation for mt8192 and mt8195. + +Signed-off-by: Balsam CHIHI +Reviewed-by: Nícolas F. R. A. Prado +[bero@baylibre.com: Fix issues pointed out by Nícolas F. R. A. Prado ] +Signed-off-by: Bernhard Rosenkränzer +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Alexandre Mergnat +Signed-off-by: Daniel Lezcano +Link: https://lore.kernel.org/r/20231017190545.157282-6-bero@baylibre.com +--- + drivers/thermal/mediatek/lvts_thermal.c | 31 +++++++++++++++++++++++-- + 1 file changed, 29 insertions(+), 2 deletions(-) + +--- a/drivers/thermal/mediatek/lvts_thermal.c ++++ b/drivers/thermal/mediatek/lvts_thermal.c +@@ -616,7 +616,34 @@ static int lvts_sensor_init(struct devic + * The efuse blob values follows the sensor enumeration per thermal + * controller. The decoding of the stream is as follow: + * +- * stream index map for MCU Domain : ++ * MT8192 : ++ * Stream index map for MCU Domain mt8192 : ++ * ++ * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1-----> ++ * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B ++ * ++ * <-----sensor#2-----> <-----sensor#3-----> ++ * 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12 | 0x13 ++ * ++ * <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7-----> ++ * 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 | 0x22 | 0x23 ++ * ++ * Stream index map for AP Domain mt8192 : ++ * ++ * <-----sensor#0-----> <-----sensor#1-----> ++ * 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A | 0x2B ++ * ++ * <-----sensor#2-----> <-----sensor#3-----> ++ * 0x2C | 0x2D | 0x2E | 0x2F | 0x30 | 0x31 | 0x32 | 0x33 ++ * ++ * <-----sensor#4-----> <-----sensor#5-----> ++ * 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3A | 0x3B ++ * ++ * <-----sensor#6-----> <-----sensor#7-----> <-----sensor#8-----> ++ * 0x3C | 0x3D | 0x3E | 0x3F | 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47 ++ * ++ * MT8195 : ++ * Stream index map for MCU Domain mt8195 : + * + * <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1-----> + * 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 +@@ -627,7 +654,7 @@ static int lvts_sensor_init(struct devic + * <-----mcu-tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7-----> + * 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 + * +- * stream index map for AP Domain : ++ * Stream index map for AP Domain mt8195 : + * + * <-----ap--tc#0-----> <-----sensor#0-----> <-----sensor#1-----> + * 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A diff --git a/target/linux/mediatek/patches-6.1/831-thermal-drivers-mediatek-Fix-control-buffer-enablement-on-MT7896.patch b/target/linux/mediatek/patches-6.1/831-thermal-drivers-mediatek-Fix-control-buffer-enablement-on-MT7896.patch new file mode 100644 index 00000000000..fc173646e05 --- /dev/null +++ b/target/linux/mediatek/patches-6.1/831-thermal-drivers-mediatek-Fix-control-buffer-enablement-on-MT7896.patch @@ -0,0 +1,59 @@ +From patchwork Thu Sep 7 11:20:18 2023 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Frank Wunderlich +X-Patchwork-Id: 13376356 +From: Frank Wunderlich +To: linux-mediatek@lists.infradead.org +Subject: [PATCH] thermal/drivers/mediatek: Fix control buffer enablement on + MT7896 +Date: Thu, 7 Sep 2023 13:20:18 +0200 +Message-Id: <20230907112018.52811-1-linux@fw-web.de> +X-Mailer: git-send-email 2.34.1 +MIME-Version: 1.0 +X-Mail-ID: e7eeb8e1-00de-41f6-a5df-ce2e9164136e +X-BeenThere: linux-mediatek@lists.infradead.org +X-Mailman-Version: 2.1.34 +Precedence: list +List-Id: +Cc: Daniel Lezcano , + "Rafael J. Wysocki" , linux-pm@vger.kernel.org, + Amit Kucheria , Daniel Golle , + stable@vger.kernel.org, linux-kernel@vger.kernel.org, + Matthias Brugger , Zhang Rui , + linux-arm-kernel@lists.infradead.org, + AngeloGioacchino Del Regno +Sender: "Linux-mediatek" + +From: Frank Wunderlich + +Reading thermal sensor on mt7986 devices returns invalid temperature: + +bpi-r3 ~ # cat /sys/class/thermal/thermal_zone0/temp + -274000 + +Fix this by adding missing members in mtk_thermal_data struct which were +used in mtk_thermal_turn_on_buffer after commit 33140e668b10. + +Cc: stable@vger.kernel.org +Fixes: 33140e668b10 ("thermal/drivers/mediatek: Control buffer enablement tweaks") +Signed-off-by: Frank Wunderlich +Reviewed-by: AngeloGioacchino Del Regno +Reviewed-by: Markus Schneider-Pargmann +--- + drivers/thermal/mediatek/auxadc_thermal.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/thermal/mediatek/auxadc_thermal.c ++++ b/drivers/thermal/mediatek/auxadc_thermal.c +@@ -691,6 +691,9 @@ static const struct mtk_thermal_data mt7 + .adcpnp = mt7986_adcpnp, + .sensor_mux_values = mt7986_mux_values, + .version = MTK_THERMAL_V3, ++ .apmixed_buffer_ctl_reg = APMIXED_SYS_TS_CON1, ++ .apmixed_buffer_ctl_mask = GENMASK(31, 6) | BIT(3), ++ .apmixed_buffer_ctl_set = BIT(0), + }; + + static bool mtk_thermal_temp_is_valid(int temp) -- 2.30.2