[COMMON] thermal: samsung: support ACPM TMU plugin
authorEunseok Choi <es10.choi@samsung.com>
Thu, 4 May 2017 08:50:03 +0000 (17:50 +0900)
committerChungwoo Park <cww.park@samsung.com>
Mon, 21 May 2018 08:18:45 +0000 (17:18 +0900)
add include/linux/sched/clock.h

Change-Id: Ia4e795d45ca2aac5ddd9d59242764ba57f2021e4
Signed-off-by: Eunseok Choi <es10.choi@samsung.com>
drivers/thermal/samsung/Kconfig
drivers/thermal/samsung/Makefile
drivers/thermal/samsung/exynos_acpm_tmu.c [new file with mode: 0644]
drivers/thermal/samsung/exynos_acpm_tmu.h [new file with mode: 0644]

index 222e644169f015ae83978b7dcd90d51e30c4465c..b79c19a3a497c65bf3daa3886201d330b321c0dc 100644 (file)
@@ -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.
index 1e47d0d89ce06ed28c1202616345a058dd0f7386..aba173d43cf59b29d94323ef9d2453459c8123b6 100644 (file)
@@ -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 (file)
index 0000000..6bb4730
--- /dev/null
@@ -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 <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/debugfs.h>
+#include <linux/sched/clock.h>
+#include <soc/samsung/acpm_ipc_ctrl.h>
+#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 (file)
index 0000000..a7cee98
--- /dev/null
@@ -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__ */