@@ -47,4 +47,16 @@ config LVTS_MT8192
configures LVTS thermal controllers to collect temperatures
via ASIF.
+config LVTS_MT8195
+ tristate "LVTS driver for MediaTek MT8195 SoC"
+ depends on HAS_IOMEM
+ depends on NVMEM
+ depends on RESET_TI_SYSCON
+ depends on MTK_SOC_THERMAL_LVTS
+ help
+ Enable this option if you want to get SoC temperature
+ information for MT8195. This driver
+ configures LVTS thermal controllers to collect temperatures
+ via ASIF.
+
endif
@@ -1,3 +1,4 @@
obj-$(CONFIG_MTK_SOC_THERMAL) += soc_temp.o
obj-$(CONFIG_MTK_SOC_THERMAL_LVTS) += soc_temp_lvts.o
obj-$(CONFIG_LVTS_MT8192) += lvts_mt8192.o
+obj-$(CONFIG_LVTS_MT8195) += lvts_mt8195.o
new file mode 100644
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ */
+
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include "soc_temp_lvts.h"
+
+enum mt8195_lvts_mcu_sensor_enum {
+ MT8195_TS1_0, // cpu_big1
+ MT8195_TS1_1, // cpu_big2
+ MT8195_TS2_0, // cpu_big3
+ MT8195_TS2_1, // cpu_big4
+ MT8195_TS3_0, // cpu_little1
+ MT8195_TS3_1, // cpu_little2
+ MT8195_TS3_2, // cpu_little3
+ MT8195_TS3_3, // cpu_little4
+ MT8195_NUM_TS_MCU
+};
+
+enum mt8195_lvts_ap_sensor_enum {
+ MT8195_TS4_0, // vpu1
+ MT8195_TS4_1, // vpu2
+ MT8195_TS5_0, // gpu1
+ MT8195_TS5_1, // gpu2
+ MT8195_TS6_0, // vdec
+ MT8195_TS6_1, // img
+ MT8195_TS6_2, // infra
+ MT8195_TS7_0, // cam1
+ MT8195_TS7_1, // cam2
+ MT8195_NUM_TS_AP
+};
+
+static void mt8195_mcu_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+ struct lvts_sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+ cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, lvts_data, 31, 24);
+
+ cal_data->count_r[MT8195_TS1_0] = GET_CAL_DATA_BITMASK(1, lvts_data, 23, 0);
+ cal_data->count_r[MT8195_TS1_1] = (GET_CAL_DATA_BITMASK(2, lvts_data, 15, 0) << 8) +
+ GET_CAL_DATA_BITMASK(1, lvts_data, 31, 24);
+ cal_data->count_r[MT8195_TS2_0] = GET_CAL_DATA_BITMASK(3, lvts_data, 31, 8);
+ cal_data->count_r[MT8195_TS2_1] = GET_CAL_DATA_BITMASK(4, lvts_data, 23, 0);
+ cal_data->count_r[MT8195_TS3_0] = (GET_CAL_DATA_BITMASK(6, lvts_data, 7, 0) << 16) +
+ GET_CAL_DATA_BITMASK(5, lvts_data, 31, 16);
+ cal_data->count_r[MT8195_TS3_1] = GET_CAL_DATA_BITMASK(6, lvts_data, 31, 8);
+ cal_data->count_r[MT8195_TS3_2] = GET_CAL_DATA_BITMASK(7, lvts_data, 23, 0);
+ cal_data->count_r[MT8195_TS3_3] = (GET_CAL_DATA_BITMASK(8, lvts_data, 15, 0) << 8) +
+ GET_CAL_DATA_BITMASK(7, lvts_data, 31, 24);
+
+ cal_data->count_rc[MT8195_TS1_0] = (GET_CAL_DATA_BITMASK(3, lvts_data, 7, 0) << 16) +
+ GET_CAL_DATA_BITMASK(2, lvts_data, 31, 16);
+ cal_data->count_rc[MT8195_TS2_0] = (GET_CAL_DATA_BITMASK(5, lvts_data, 15, 0) << 8) +
+ GET_CAL_DATA_BITMASK(4, lvts_data, 31, 24);
+ cal_data->count_rc[MT8195_TS3_0] = (GET_CAL_DATA_BITMASK(9, lvts_data, 7, 0) << 16) +
+ GET_CAL_DATA_BITMASK(8, lvts_data, 31, 16);
+}
+
+static void mt8195_ap_efuse_to_cal_data(struct lvts_data *lvts_data)
+{
+ struct lvts_sensor_cal_data *cal_data = &lvts_data->cal_data;
+
+ cal_data->golden_temp = GET_CAL_DATA_BITMASK(0, lvts_data, 31, 24);
+
+ cal_data->count_r[MT8195_TS4_0] = GET_CAL_DATA_BITMASK(9, lvts_data, 31, 8);
+ cal_data->count_r[MT8195_TS4_1] = GET_CAL_DATA_BITMASK(10, lvts_data, 23, 0);
+ cal_data->count_r[MT8195_TS5_0] = (GET_CAL_DATA_BITMASK(12, lvts_data, 7, 0) << 16) +
+ GET_CAL_DATA_BITMASK(11, lvts_data, 31, 16);
+ cal_data->count_r[MT8195_TS5_1] = GET_CAL_DATA_BITMASK(12, lvts_data, 31, 8);
+ cal_data->count_r[MT8195_TS6_0] = (GET_CAL_DATA_BITMASK(14, lvts_data, 15, 0) << 8) +
+ GET_CAL_DATA_BITMASK(13, lvts_data, 31, 24);
+ cal_data->count_r[MT8195_TS6_1] = (GET_CAL_DATA_BITMASK(15, lvts_data, 7, 0) << 16) +
+ GET_CAL_DATA_BITMASK(14, lvts_data, 31, 16);
+ cal_data->count_r[MT8195_TS6_2] = GET_CAL_DATA_BITMASK(15, lvts_data, 31, 8);
+ cal_data->count_r[MT8195_TS7_0] = (GET_CAL_DATA_BITMASK(17, lvts_data, 15, 0) << 8) +
+ GET_CAL_DATA_BITMASK(16, lvts_data, 31, 24);
+ cal_data->count_r[MT8195_TS7_1] = (GET_CAL_DATA_BITMASK(18, lvts_data, 7, 0) << 16) +
+ GET_CAL_DATA_BITMASK(17, lvts_data, 31, 16);
+
+ cal_data->count_rc[MT8195_TS4_0] = (GET_CAL_DATA_BITMASK(11, lvts_data, 15, 0) << 8) +
+ GET_CAL_DATA_BITMASK(10, lvts_data, 31, 24);
+ cal_data->count_rc[MT8195_TS5_0] = GET_CAL_DATA_BITMASK(13, lvts_data, 23, 0);
+ cal_data->count_rc[MT8195_TS6_0] = GET_CAL_DATA_BITMASK(16, lvts_data, 23, 0);
+ cal_data->count_rc[MT8195_TS7_0] = GET_CAL_DATA_BITMASK(18, lvts_data, 31, 8);
+}
+
+static struct lvts_speed_settings tc_speed_mt8195 = {
+ .period_unit = PERIOD_UNIT,
+ .group_interval_delay = GROUP_INTERVAL_DELAY,
+ .filter_interval_delay = FILTER_INTERVAL_DELAY,
+ .sensor_interval_delay = SENSOR_INTERVAL_DELAY,
+};
+
+static const struct lvts_tc_settings mt8195_tc_mcu_settings[] = {
+ [0] = {
+ .dev_id = 0x81,
+ .addr_offset = 0x0,
+ .num_sensor = 2,
+ .sensor_map = {MT8195_TS1_0, MT8195_TS1_1},
+ .tc_speed = &tc_speed_mt8195,
+ .hw_filter = LVTS_FILTER_2_OF_4,
+ .dominator_sensing_point = SENSING_POINT1,
+ .hw_reboot_trip_point = HW_REBOOT_TRIP_POINT,
+ .irq_bit = BIT(3),
+ },
+ [1] = {
+ .dev_id = 0x82,
+ .addr_offset = 0x100,
+ .num_sensor = 2,
+ .sensor_map = {MT8195_TS2_0, MT8195_TS2_1},
+ .tc_speed = &tc_speed_mt8195,
+ .hw_filter = LVTS_FILTER_2_OF_4,
+ .dominator_sensing_point = SENSING_POINT0,
+ .hw_reboot_trip_point = HW_REBOOT_TRIP_POINT,
+ .irq_bit = BIT(4),
+ },
+ [2] = {
+ .dev_id = 0x83,
+ .addr_offset = 0x200,
+ .num_sensor = 4,
+ .sensor_map = {MT8195_TS3_0, MT8195_TS3_1, MT8195_TS3_2, MT8195_TS3_3},
+ .tc_speed = &tc_speed_mt8195,
+ .hw_filter = LVTS_FILTER_2_OF_4,
+ .dominator_sensing_point = SENSING_POINT0,
+ .hw_reboot_trip_point = HW_REBOOT_TRIP_POINT,
+ .irq_bit = BIT(5),
+ }
+};
+
+static const struct lvts_tc_settings mt8195_tc_ap_settings[] = {
+ [0] = {
+ .dev_id = 0x84,
+ .addr_offset = 0x0,
+ .num_sensor = 2,
+ .sensor_map = {MT8195_TS4_0, MT8195_TS4_1},
+ .tc_speed = &tc_speed_mt8195,
+ .hw_filter = LVTS_FILTER_2_OF_4,
+ .dominator_sensing_point = SENSING_POINT0,
+ .hw_reboot_trip_point = HW_REBOOT_TRIP_POINT,
+ .irq_bit = BIT(3),
+ },
+ [1] = {
+ .dev_id = 0x85,
+ .addr_offset = 0x100,
+ .num_sensor = 2,
+ .sensor_map = {MT8195_TS5_0, MT8195_TS5_1},
+ .tc_speed = &tc_speed_mt8195,
+ .hw_filter = LVTS_FILTER_2_OF_4,
+ .dominator_sensing_point = SENSING_POINT1,
+ .hw_reboot_trip_point = HW_REBOOT_TRIP_POINT,
+ .irq_bit = BIT(4),
+ },
+ [2] = {
+ .dev_id = 0x86,
+ .addr_offset = 0x200,
+ .num_sensor = 3,
+ .sensor_map = {MT8195_TS6_0, MT8195_TS6_1, MT8195_TS6_2},
+ .tc_speed = &tc_speed_mt8195,
+ .hw_filter = LVTS_FILTER_2_OF_4,
+ .dominator_sensing_point = SENSING_POINT1,
+ .hw_reboot_trip_point = HW_REBOOT_TRIP_POINT,
+ .irq_bit = BIT(5),
+ },
+ [3] = {
+ .dev_id = 0x87,
+ .addr_offset = 0x300,
+ .num_sensor = 2,
+ .sensor_map = {MT8195_TS7_0, MT8195_TS7_1},
+ .tc_speed = &tc_speed_mt8195,
+ .hw_filter = LVTS_FILTER_2_OF_4,
+ .dominator_sensing_point = SENSING_POINT0,
+ .hw_reboot_trip_point = HW_REBOOT_TRIP_POINT,
+ .irq_bit = BIT(6),
+ }
+};
+
+static const struct lvts_data mt8195_lvts_mcu_data = {
+ .num_tc = (ARRAY_SIZE(mt8195_tc_mcu_settings)),
+ .tc = mt8195_tc_mcu_settings,
+ .num_sensor = MT8195_NUM_TS_MCU,
+ .ops = {
+ .efuse_to_cal_data = mt8195_mcu_efuse_to_cal_data,
+ .device_enable_and_init = lvts_device_enable_and_init_v4,
+ .device_enable_auto_rck = lvts_device_enable_auto_rck_v4,
+ .device_read_count_rc_n = lvts_device_read_count_rc_n_v4,
+ .set_cal_data = lvts_set_calibration_data_v4,
+ .init_controller = lvts_init_controller_v4,
+ },
+ .feature_bitmap = FEATURE_DEVICE_AUTO_RCK,
+ .num_efuse_addr = NUM_EFUSE_ADDR,
+ .num_efuse_block = NUM_EFUSE_BLOCK_MT8195,
+ .cal_data = {
+ .default_golden_temp = DEFAULT_GOLDEN_TEMP,
+ .default_count_r = DEFAULT_CUONT_R,
+ .default_count_rc = DEFAULT_CUONT_RC,
+ },
+ .coeff = {
+ .a = COEFF_A,
+ .b = COEFF_B,
+ },
+};
+
+static const struct lvts_data mt8195_lvts_ap_data = {
+ .num_tc = (ARRAY_SIZE(mt8195_tc_ap_settings)),
+ .tc = mt8195_tc_ap_settings,
+ .num_sensor = MT8195_NUM_TS_AP,
+ .ops = {
+ .efuse_to_cal_data = mt8195_ap_efuse_to_cal_data,
+ .device_enable_and_init = lvts_device_enable_and_init_v4,
+ .device_enable_auto_rck = lvts_device_enable_auto_rck_v4,
+ .device_read_count_rc_n = lvts_device_read_count_rc_n_v4,
+ .set_cal_data = lvts_set_calibration_data_v4,
+ .init_controller = lvts_init_controller_v4,
+ },
+ .feature_bitmap = FEATURE_DEVICE_AUTO_RCK,
+ .num_efuse_addr = NUM_EFUSE_ADDR,
+ .num_efuse_block = NUM_EFUSE_BLOCK_MT8195,
+ .cal_data = {
+ .default_golden_temp = DEFAULT_GOLDEN_TEMP,
+ .default_count_r = DEFAULT_CUONT_R,
+ .default_count_rc = DEFAULT_CUONT_RC,
+ },
+ .coeff = {
+ .a = COEFF_A,
+ .b = COEFF_B,
+ },
+};
+
+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);
+
+static struct platform_driver soc_temp_lvts = {
+ .probe = lvts_probe,
+ .remove = lvts_remove,
+ .suspend = lvts_suspend,
+ .resume = lvts_resume,
+ .driver = {
+ .name = "mtk-soc-temp-lvts-mt8195",
+ .of_match_table = lvts_of_match,
+ },
+};
+module_platform_driver(soc_temp_lvts);
+
+MODULE_AUTHOR("Yu-Chia Chang <ethan.chang@mediatek.com>");
+MODULE_AUTHOR("Michael Kao <michael.kao@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek soc temperature driver");
+MODULE_LICENSE("GPL v2");
@@ -16,6 +16,7 @@
#define FEATURE_DEVICE_AUTO_RCK BIT(0)
#define NUM_EFUSE_ADDR 22
#define NUM_EFUSE_BLOCK_MT8192 1
+#define NUM_EFUSE_BLOCK_MT8195 2
#define DEFAULT_GOLDEN_TEMP 50
#define DEFAULT_CUONT_R 35000
#define DEFAULT_CUONT_RC 2750