From 3f386f9333ffec9e0bf67874757c0a5475ef65c0 Mon Sep 17 00:00:00 2001 From: Eunseok Choi Date: Thu, 4 May 2017 17:50:03 +0900 Subject: [PATCH] [COMMON] thermal: samsung: support ACPM TMU plugin add include/linux/sched/clock.h Change-Id: Ia4e795d45ca2aac5ddd9d59242764ba57f2021e4 Signed-off-by: Eunseok Choi --- drivers/thermal/samsung/Kconfig | 7 + drivers/thermal/samsung/Makefile | 4 +- drivers/thermal/samsung/exynos_acpm_tmu.c | 235 ++++++++++++++++++++++ drivers/thermal/samsung/exynos_acpm_tmu.h | 117 +++++++++++ 4 files changed, 361 insertions(+), 2 deletions(-) create mode 100644 drivers/thermal/samsung/exynos_acpm_tmu.c create mode 100644 drivers/thermal/samsung/exynos_acpm_tmu.h diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig index 222e644169f0..b79c19a3a497 100644 --- a/drivers/thermal/samsung/Kconfig +++ b/drivers/thermal/samsung/Kconfig @@ -8,3 +8,10 @@ config EXYNOS_THERMAL the TMU, reports temperature and handles cooling action if defined. This driver uses the Exynos core thermal APIs and TMU configuration data from the supported SoCs. + +config EXYNOS_ACPM_THERMAL + bool + prompt "Exynos ACPM TMU plug-in support" + depends on EXYNOS_THERMAL + help + This feature supports ACPM TMU plug-in for Exynos thermal driver. diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile index 1e47d0d89ce0..aba173d43cf5 100644 --- a/drivers/thermal/samsung/Makefile +++ b/drivers/thermal/samsung/Makefile @@ -1,5 +1,5 @@ # # Samsung thermal specific Makefile # -obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o -exynos_thermal-y := exynos_tmu.o +obj-$(CONFIG_EXYNOS_THERMAL) += exynos_tmu.o +obj-$(CONFIG_EXYNOS_ACPM_THERMAL) += exynos_acpm_tmu.o diff --git a/drivers/thermal/samsung/exynos_acpm_tmu.c b/drivers/thermal/samsung/exynos_acpm_tmu.c new file mode 100644 index 000000000000..6bb47304d105 --- /dev/null +++ b/drivers/thermal/samsung/exynos_acpm_tmu.c @@ -0,0 +1,235 @@ +/* + * exynos_acpm_tmu.c - ACPM TMU plugin interface + * + * Copyright (C) 2017 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "exynos_acpm_tmu.h" + +static bool cold_comp; +static unsigned int acpm_tmu_ch_num, acpm_tmu_size; + +#define acpm_ipc_err_check() \ + do { \ + if (ret < 0) { \ + pr_warn("[acpm_tmu] IPC error! type 0x%02x latency %llu ns ret %d\n", \ + message.req.type, latency, ret); \ + return -1; \ + } \ + } while (0) + +#define acpm_ipc_latency_check() \ + do { \ + if (latency > 2000000) { \ + pr_info("[acpm_tmu] type 0x%02x latency %llu ns ret %d\n", \ + message.req.type, latency, ret); \ + } \ + } while (0) + +/* + * TMU_IPC_INIT + */ +int exynos_acpm_tmu_set_init(struct acpm_tmu_cap *cap) +{ + struct ipc_config config; + union tmu_ipc_message message; + unsigned long long before, after, latency; + int ret; + + memset(&message, 0, sizeof(message)); + + message.req.type = TMU_IPC_INIT; + + config.cmd = message.data; + config.response = true; + config.indirection = false; + + before = sched_clock(); + ret = acpm_ipc_send_data(acpm_tmu_ch_num, &config); + after = sched_clock(); + latency = after - before; + + acpm_ipc_err_check(); + acpm_ipc_latency_check(); + + memcpy(message.data, config.cmd, sizeof(message.data)); + + if (message.resp.ret & CAP_APM_IRQ) + cap->acpm_irq = true; + + if (message.resp.ret & CAP_APM_DIVIDER) + cap->acpm_divider = true; + + return 0; +} + +/* + * TMU_IPC_READ_TEMP + * + * - tz: thermal zone index registered in device tree + */ +int exynos_acpm_tmu_set_read_temp(int tz, int *cur_temp) +{ + struct ipc_config config; + union tmu_ipc_message message; + unsigned long long before, after, latency; + int ret; + + *cur_temp = 0; + + memset(&message, 0, sizeof(message)); + + message.req.type = TMU_IPC_READ_TEMP; + message.req.tzid = tz; + + config.cmd = message.data; + config.response = true; + config.indirection = false; + + before = sched_clock(); + ret = acpm_ipc_send_data(acpm_tmu_ch_num, &config); + after = sched_clock(); + latency = after - before; + + acpm_ipc_err_check(); + acpm_ipc_latency_check(); + + memcpy(message.data, config.cmd, sizeof(message.data)); + + cold_comp = message.resp.cold; + *cur_temp = message.resp.temp; + + return 0; +} + +/* + * TMU_IPC_AP_SUSPEND + */ +int exynos_acpm_tmu_set_suspend(void) +{ + struct ipc_config config; + union tmu_ipc_message message; + unsigned long long before, after, latency; + int ret; + + memset(&message, 0, sizeof(message)); + + message.req.type = TMU_IPC_AP_SUSPEND; + + config.cmd = message.data; + config.response = true; + config.indirection = false; + + before = sched_clock(); + ret = acpm_ipc_send_data(acpm_tmu_ch_num, &config); + after = sched_clock(); + latency = after - before; + + acpm_ipc_err_check(); + acpm_ipc_latency_check(); + + memcpy(message.data, config.cmd, sizeof(message.data)); + + cold_comp = message.resp.cold; + + return 0; +} + +/* + * TMU_IPC_CP_CALL + */ +int exynos_acpm_tmu_set_cp_call(void) +{ + struct ipc_config config; + union tmu_ipc_message message; + unsigned long long before, after, latency; + int ret; + + memset(&message, 0, sizeof(message)); + + message.req.type = TMU_IPC_CP_CALL; + + config.cmd = message.data; + config.response = true; + config.indirection = false; + + before = sched_clock(); + ret = acpm_ipc_send_data(acpm_tmu_ch_num, &config); + after = sched_clock(); + latency = after - before; + + acpm_ipc_err_check(); + acpm_ipc_latency_check(); + + memcpy(&message.data, config.cmd, sizeof(message.data)); + + return 0; +} + +/* + * TMU_IPC_AP_RESUME + */ +int exynos_acpm_tmu_set_resume(void) +{ + struct ipc_config config; + union tmu_ipc_message message; + unsigned long long before, after, latency; + int ret; + + memset(&message, 0, sizeof(message)); + + message.req.type = TMU_IPC_AP_RESUME; + + config.cmd = message.data; + config.response = true; + config.indirection = false; + + before = sched_clock(); + ret = acpm_ipc_send_data(acpm_tmu_ch_num, &config); + after = sched_clock(); + latency = after - before; + + acpm_ipc_err_check(); + acpm_ipc_latency_check(); + + memcpy(&message.data, config.cmd, sizeof(message.data)); + + return 0; +} + +static int __init exynos_acpm_tmu_init(void) +{ + struct device_node *np; + + np = of_find_node_by_name(NULL, "acpm_tmu"); + if (!np) + return -ENODEV; + + return acpm_ipc_request_channel(np, NULL, &acpm_tmu_ch_num, &acpm_tmu_size); +} +fs_initcall(exynos_acpm_tmu_init); diff --git a/drivers/thermal/samsung/exynos_acpm_tmu.h b/drivers/thermal/samsung/exynos_acpm_tmu.h new file mode 100644 index 000000000000..a7cee98b85cd --- /dev/null +++ b/drivers/thermal/samsung/exynos_acpm_tmu.h @@ -0,0 +1,117 @@ +/* + * exynos_acpm_tmu.h - ACPM TMU plugin interface + * + * Copyright (C) 2017 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __EXYNOS_ACPM_TMU_H__ +#define __EXYNOS_ACPM_TMU_H__ + +/* Return values */ +#define RET_SUCCESS 0 +#define RET_FAIL -1 +#define RET_OK RET_SUCCESS +#define RET_NOK RET_FAIL + +/* Return values - error types (minus) */ +#define ERR_REQ_TYPE 2 +#define ERR_TZ_ID 3 +#define ERR_TEMP 4 +#define ERR_APM_IRQ 5 +#define ERR_APM_DIVIDER 6 + +/* Return values - capabilities */ +#define CAP_APM_IRQ 0x1 +#define CAP_APM_DIVIDER 0x2 + +/* IPC Request Types */ +#define TMU_IPC_INIT 0x01 +#define TMU_IPC_READ_TEMP 0x02 +#define TMU_IPC_AP_SUSPEND 0x04 +#define TMU_IPC_CP_CALL 0x08 +#define TMU_IPC_AP_RESUME 0x10 + +/* + * 16-byte TMU IPC message format (REQ) + * (MSB) 3 2 1 0 + * --------------------------------------------- + * | fw_use | ctx | + * --------------------------------------------- + * | | tzid | | type | + * --------------------------------------------- + * | | | | | + * --------------------------------------------- + * | | | | | + * --------------------------------------------- + */ +struct tmu_ipc_request { + u16 ctx; /* LSB */ + u16 fw_use; /* MSB */ + u8 type; + u8 rsvd; + u8 tzid; + u8 rsvd2; + u32 reserved; + u32 reserved2; +}; + +/* + * 16-byte TMU IPC message format (RESP) + * (MSB) 3 2 1 0 + * --------------------------------------------- + * | fw_use | ctx | + * --------------------------------------------- + * | temp | tz_id | ret | type | + * --------------------------------------------- + * | | | | cold | + * --------------------------------------------- + * | | | | | + * --------------------------------------------- + */ +struct tmu_ipc_response { + u16 ctx; /* LSB */ + u16 fw_use; /* MSB */ + u8 type; + s8 ret; + u8 tzid; + u8 temp; + u8 cold; + u8 rsvd; + u8 rsvd2; + u8 rsvd3; + u32 reserved; +}; + +union tmu_ipc_message { + u32 data[4]; + struct tmu_ipc_request req; + struct tmu_ipc_response resp; +}; + +struct acpm_tmu_cap { + bool acpm_irq; + bool acpm_divider; +}; + +int exynos_acpm_tmu_set_init(struct acpm_tmu_cap *cap); +int exynos_acpm_tmu_set_read_temp(int tz, int *temp); +int exynos_acpm_tmu_set_suspend(void); +int exynos_acpm_tmu_set_cp_call(void); +int exynos_acpm_tmu_set_resume(void); +void exynos_acpm_tmu_set_test_mode(bool mode); + +#endif /* __EXYNOS_ACPM_TMU_H__ */ -- 2.20.1