blob: 23c32b9593e5f68fe147cc2ce00247c813167e5c [file] [log] [blame]
/*
* Copyright (C) 2018 MediaTek Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#include <asm/page.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/syscalls.h>
#include <linux/mm.h>
/* #include <asm/uaccess.h> */
#include <linux/uaccess.h>
#include <linux/hrtimer.h>
#include "met_drv.h"
#include "trace.h"
#include "core_plf_trace.h"
#include "core_plf_init.h"
/*define if the thermal sensor driver use its own timer to sampling the code , otherwise undefine it */
/*define it is better for sampling jitter if thermal sensor driver supports */
/* this define is phase out */
/* #define MET_USE_THERMALDRIVER_TIMER */
noinline void ms_th(const unsigned char cnt, unsigned int *value)
{
char *SOB, *EOB;
MET_TRACE_GETBUF(&SOB, &EOB);
EOB = ms_formatD_EOL(EOB, cnt, value);
MET_TRACE_PUTBUF(SOB, EOB);
}
static unsigned int CheckAvailableThermalSensor(unsigned int a_u4DoCheck)
{
static unsigned int u4AvailableSensor;
unsigned int u4Index;
if (!a_u4DoCheck)
return u4AvailableSensor;
/*Do check */
if (MTK_THERMAL_SENSOR_COUNT > 32)
return 0;
if (mtk_thermal_get_temp_symbol == NULL)
return 0;
u4AvailableSensor = 0;
for (u4Index = 0; u4Index < MTK_THERMAL_SENSOR_COUNT; u4Index++) {
if (mtk_thermal_get_temp_symbol(u4Index) == (-127000) || mtk_thermal_get_temp_symbol(u4Index) < 0)
u4AvailableSensor &= (~(1 << u4Index));
else
u4AvailableSensor |= (1 << u4Index);
}
return u4AvailableSensor;
}
static int do_thermal(void)
{
static int do_thermal = -1;
if (do_thermal != -1)
return do_thermal;
if (met_thermal.mode == 0)
do_thermal = 0;
else
do_thermal = met_thermal.mode;
return do_thermal;
}
static unsigned int get_thermal(unsigned int *value)
{
int j = -1;
int i;
unsigned int u4ValidSensors = 0;
/*Do check */
if (mtk_thermal_get_temp_symbol == NULL)
return 0;
u4ValidSensors = CheckAvailableThermalSensor(0);
for (i = 0; i < MTK_THERMAL_SENSOR_COUNT; i++) {
if (u4ValidSensors & (1 << i))
value[++j] = mtk_thermal_get_temp_symbol(i);
}
return j + 1;
}
static void wq_get_thermal(struct work_struct *work)
{
unsigned char count = 0;
unsigned int thermal_value[MTK_THERMAL_SENSOR_COUNT]; /*Note here */
int cpu;
cpu = smp_processor_id();
if (do_thermal()) {
count = get_thermal(thermal_value);
if (count)
ms_th(count, thermal_value);
}
}
#ifdef MET_USE_THERMALDRIVER_TIMER
static void thermal_start(void)
{
CheckAvailableThermalSensor(1);
/* get extern symbol by symbol_get */
if (mt_thermalsampler_registerCB_symbol)
mt_thermalsampler_registerCB_symbol(wq_get_thermal);
}
static void thermal_stop(void)
{
if (mt_thermalsampler_registerCB_symbol)
mt_thermalsampler_registerCB_symbol(NULL);
}
#else
struct delayed_work dwork;
static void thermal_start(void)
{
CheckAvailableThermalSensor(1);
/*pr_debug("Thermal Sample:0x%x\n",CheckAvailableThermalSensor(0)); */
INIT_DELAYED_WORK(&dwork, wq_get_thermal);
}
static void thermal_stop(void)
{
cancel_delayed_work_sync(&dwork);
}
static void thermal_polling(unsigned long long stamp, int cpu)
{
schedule_delayed_work(&dwork, 0);
}
#endif
static const char help[] = " --thermal monitor thermal\n";
static int thermal_print_help(char *buf, int len)
{
return snprintf(buf, PAGE_SIZE, help);
}
static const char g_pThermalHeader[] = "met-info [000] 0.0: thermal_header: ms_th";
static int thermal_print_header(char *buf, int len)
{
char buffer[256];
char ts_buf[8] = {0};
unsigned long u4Cnt = 0;
unsigned int u4ValidSensor = 0;
int i = 0, ts_sz = 0;
u4ValidSensor = CheckAvailableThermalSensor(0);
strncpy(buffer, g_pThermalHeader, 256 - 1);
ts_sz = sizeof(ts_buf);
for ( i = 0 ; i < MTK_THERMAL_SENSOR_COUNT ; i++) {
if ((1 << i) & u4ValidSensor) {
snprintf(ts_buf, ts_sz, ",tab_%d", (i + 1));
strncat(buffer, ts_buf, 256 - 1);
u4Cnt += 1;
}
memset(ts_buf, '\0', ts_sz);
}
strncat(buffer, "\n", 256 - 1);
return snprintf(buf, PAGE_SIZE, "%s", buffer);
}
struct metdevice met_thermal = {
.name = "thermal",
.owner = THIS_MODULE,
.type = MET_TYPE_BUS,
.cpu_related = 0,
.ondiemet_mode = 0,
.start = thermal_start,
.stop = thermal_stop,
#ifdef MET_USE_THERMALDRIVER_TIMER
#else
.polling_interval = 50, /* ms */
.timed_polling = thermal_polling,
.tagged_polling = thermal_polling,
#endif
.print_help = thermal_print_help,
.print_header = thermal_print_header,
};
/*CPU sensors */
static unsigned int CheckAvailableCPUThermalSensor(unsigned int a_u4DoCheck)
{
static unsigned int u4AvailableSensor;
unsigned int u4Index;
if (tscpu_get_cpu_temp_met_symbol == NULL)
return 0;
if (!a_u4DoCheck)
return u4AvailableSensor;
u4AvailableSensor = 0;
for (u4Index = 0; u4Index < MTK_THERMAL_SENSOR_CPU_COUNT; u4Index++) {
if (u4Index == ATM_GPU_LIMIT)
continue;
if (tscpu_get_cpu_temp_met_symbol(u4Index) == (-127000) || tscpu_get_cpu_temp_met_symbol(u4Index) < 0)
u4AvailableSensor &= (~(1 << u4Index));
else
u4AvailableSensor |= (1 << u4Index);
}
return u4AvailableSensor;
}
noinline void CPUTS(void)
{
unsigned int u4Index1 = 0, u4Index2 = 0;
unsigned int u4ValidSensors = 0;
int i4TSValue[MTK_THERMAL_SENSOR_CPU_COUNT];
int i = 0, len = 0, total_len = 0, sz;
char str_buff[128] = {0};
sz = sizeof(str_buff);
if (tscpu_get_cpu_temp_met_symbol == NULL)
return;
memset(i4TSValue, 0, sizeof(int) * MTK_THERMAL_SENSOR_CPU_COUNT);
u4ValidSensors = CheckAvailableCPUThermalSensor(0);
for (; u4Index1 < MTK_THERMAL_SENSOR_CPU_COUNT; u4Index1++) {
if (u4ValidSensors & (1 << u4Index1)) {
i4TSValue[u4Index2] = tscpu_get_cpu_temp_met_symbol(u4Index1);
u4Index2 += 1;
}
}
len = snprintf(str_buff + total_len, 8, "%d", i4TSValue[0]);
if (len >= 0 && len < sz)
total_len += len;
for (i = 1 ; i < u4Index2 ; i++) {
len = snprintf(str_buff + total_len, 8, ",%d", i4TSValue[i]);
if (len >= 0 && len < sz)
total_len += len;
}
MET_TRACE("%s\n", str_buff);
}
static void thermal_CPU_start(void)
{
CheckAvailableCPUThermalSensor(1);
/* get extern symbol by symbol_get */
if (mt_thermalsampler_registerCB_symbol)
mt_thermalsampler_registerCB_symbol(CPUTS);
}
static void thermal_CPU_stop(void)
{
/* release extern symbol by symbol_put */
if (mt_thermalsampler_registerCB_symbol)
mt_thermalsampler_registerCB_symbol(NULL);
}
static const char help_cpu[] = " --thermal-cpu monitor cpu temperature\n";
static int thermal_CPU_print_help(char *buf, int len)
{
return snprintf(buf, PAGE_SIZE, help_cpu);
}
static const char g_pCPUThermalHeader[] = "met-info [000] 0.0: thermal_cpu_header: CPUTS";
static int thermal_CPU_print_header(char *buf, int len)
{
char buffer[256];
char ts_buf[8] = {0} ;
unsigned long u4Cnt = 0;
unsigned int u4ValidSensor = 0;
int i = 0, ts_sz = 0;
u4ValidSensor = CheckAvailableCPUThermalSensor(0);
strncpy(buffer, g_pCPUThermalHeader, 256 - 1);
ts_sz = sizeof(ts_buf);
for ( i = 0 ; i < MTK_THERMAL_SENSOR_CPU_COUNT ; i++) {
if ((1 << i) & u4ValidSensor) {
snprintf(ts_buf, ts_sz, ",tab_%d", (i + 1));
strncat(buffer, ts_buf, 256 - 1);
u4Cnt += 1;
}
memset(ts_buf, '\0', ts_sz);
}
strncat(buffer, "\n", 256 - 1);
return snprintf(buf, PAGE_SIZE, "%s", buffer);
}
struct metdevice met_thermal_cpu = {
.name = "thermal-cpu",
.owner = THIS_MODULE,
.type = MET_TYPE_BUS,
.cpu_related = 0,
.start = thermal_CPU_start,
.stop = thermal_CPU_stop,
.print_help = thermal_CPU_print_help,
.print_header = thermal_CPU_print_header,
.ondiemet_mode = 0,
};