thermal: tsens: Add IPC logging support for TSENS

Add IPC logging support for TSENS. Dump all TSENS registers
into IPC when TSENS reset occurs without recovery by
self-reset.

Change-Id: I379a521ffd2a65a87bd69b6ef37c71b779345183
Signed-off-by: Jishnu Prakash <jprakash@codeaurora.org>
This commit is contained in:
Jishnu Prakash 2019-03-04 18:59:41 +05:30
parent 6e9f8d3097
commit 684df7009f
4 changed files with 130 additions and 18 deletions

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/err.h>
@ -157,6 +157,8 @@ static int get_device_tree_data(struct platform_device *pdev,
return PTR_ERR(tmdev->tsens_tm_addr);
}
tmdev->phys_addr_tm = res_tsens_mem->start;
/* TSENS eeprom register region */
res_tsens_mem = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "tsens_eeprom_physical");
@ -224,6 +226,7 @@ int tsens_tm_probe(struct platform_device *pdev)
{
struct tsens_device *tmdev = NULL;
int rc;
char tsens_name[40];
if (!(pdev->dev.of_node))
return -ENODEV;
@ -260,6 +263,33 @@ int tsens_tm_probe(struct platform_device *pdev)
return rc;
}
snprintf(tsens_name, sizeof(tsens_name), "tsens_%pa_0",
&tmdev->phys_addr_tm);
tmdev->ipc_log0 = ipc_log_context_create(IPC_LOGPAGES,
tsens_name, 0);
if (!tmdev->ipc_log0)
pr_err("%s : unable to create IPC Logging 0 for tsens %pa\n",
__func__, &tmdev->phys_addr_tm);
snprintf(tsens_name, sizeof(tsens_name), "tsens_%pa_1",
&tmdev->phys_addr_tm);
tmdev->ipc_log1 = ipc_log_context_create(IPC_LOGPAGES,
tsens_name, 0);
if (!tmdev->ipc_log1)
pr_err("%s : unable to create IPC Logging 1 for tsens %pa\n",
__func__, &tmdev->phys_addr_tm);
snprintf(tsens_name, sizeof(tsens_name), "tsens_%pa_2",
&tmdev->phys_addr_tm);
tmdev->ipc_log2 = ipc_log_context_create(IPC_LOGPAGES,
tsens_name, 0);
if (!tmdev->ipc_log2)
pr_err("%s : unable to create IPC Logging 2 for tsens %pa\n",
__func__, &tmdev->phys_addr_tm);
list_add_tail(&tmdev->list, &tsens_device_list);
platform_set_drvdata(pdev, tmdev);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*/
#include <asm/arch_timer.h>
@ -244,6 +244,8 @@ static int tsens_dbg_log_temp_reads(struct tsens_device *data, u32 id,
idx++;
tmdev->tsens_dbg.sensor_dbg_info[sensor->hw_id].idx = idx;
TSENS_DBG(tmdev, "Sensor_id: %d temp: %d\n", id, *temp);
return 0;
}
@ -291,7 +293,7 @@ static int tsens_dbg_log_bus_id_data(struct tsens_device *data,
srot_addr = TSENS_CTRL_ADDR(tmdev->tsens_srot_addr);
cntrl_id = readl_relaxed(controller_id_addr);
pr_err("Controller_id: 0x%x\n", cntrl_id);
TSENS_DUMP(tmdev, "TSENS Controller_id: 0x%x\n", cntrl_id);
loop = 0;
i = 0;
@ -304,8 +306,11 @@ static int tsens_dbg_log_bus_id_data(struct tsens_device *data,
r2 = readl_relaxed(debug_data_addr);
r3 = readl_relaxed(debug_data_addr);
r4 = readl_relaxed(debug_data_addr);
pr_err("cntrl:%d, bus-id:%d value:0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
TSENS_DUMP(tmdev,
"ctl:%d, bus-id:%d val:0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
cntrl_id, i, debug_dump, r1, r2, r3, r4);
loop++;
}
@ -317,8 +322,9 @@ static int tsens_dbg_log_bus_id_data(struct tsens_device *data,
TSENS_DEBUG_CONTROL(tmdev->tsens_tm_addr));
while (loop < TSENS_DEBUG_LOOP_COUNT) {
debug_dump = readl_relaxed(debug_data_addr);
pr_err("cntrl:%d, bus-id:%d with value: 0x%x\n",
cntrl_id, i, debug_dump);
TSENS_DUMP(tmdev,
"cntrl:%d, bus-id:%d with value: 0x%x\n",
cntrl_id, i, debug_dump);
if (i == TSENS_DBG_BUS_ID_2)
usleep_range(
TSENS_DEBUG_BUS_ID2_MIN_CYCLE,
@ -327,7 +333,9 @@ static int tsens_dbg_log_bus_id_data(struct tsens_device *data,
}
}
pr_err("Start of TSENS TM dump\n");
TSENS_DUMP(tmdev, "Start of TSENS TM dump for ctr 0x%x\n",
cntrl_id);
for (i = 0; i < TSENS_DEBUG_OFFSET_RANGE; i++) {
r1 = readl_relaxed(controller_id_addr + offset);
r2 = readl_relaxed(controller_id_addr + (offset +
@ -337,13 +345,16 @@ static int tsens_dbg_log_bus_id_data(struct tsens_device *data,
r4 = readl_relaxed(controller_id_addr + (offset +
TSENS_DEBUG_OFFSET_WORD3));
pr_err("ctrl:%d:0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
cntrl_id, offset, r1, r2, r3, r4);
TSENS_DUMP(tmdev,
"ctrl:%d:0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
cntrl_id, offset, r1, r2, r3, r4);
offset += TSENS_DEBUG_OFFSET_ROW;
}
offset = 0;
pr_err("Start of TSENS SROT dump\n");
TSENS_DUMP(tmdev, "Start of TSENS SROT dump for ctr 0x%x\n",
cntrl_id);
for (i = 0; i < TSENS_DEBUG_OFFSET_RANGE; i++) {
r1 = readl_relaxed(srot_addr + offset);
r2 = readl_relaxed(srot_addr + (offset +
@ -353,8 +364,9 @@ static int tsens_dbg_log_bus_id_data(struct tsens_device *data,
r4 = readl_relaxed(srot_addr + (offset +
TSENS_DEBUG_OFFSET_WORD3));
pr_err("ctrl:%d:0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
cntrl_id, offset, r1, r2, r3, r4);
TSENS_DUMP(tmdev,
"ctrl:%d:0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
cntrl_id, offset, r1, r2, r3, r4);
offset += TSENS_DEBUG_OFFSET_ROW;
}
@ -362,7 +374,8 @@ static int tsens_dbg_log_bus_id_data(struct tsens_device *data,
while (loop < TSENS_DEBUG_LOOP_COUNT) {
offset = TSENS_DEBUG_OFFSET_ROW *
TSENS_DEBUG_STATUS_REG_START;
pr_err("Start of TSENS TM dump %d\n", loop);
TSENS_DUMP(tmdev, "Start of TSENS TM dump %d\n",
loop);
/* Limited dump of the registers for the temperature */
for (i = 0; i < TSENS_DEBUG_LOOP_COUNT; i++) {
r1 = readl_relaxed(controller_id_addr + offset);
@ -373,8 +386,9 @@ static int tsens_dbg_log_bus_id_data(struct tsens_device *data,
r4 = readl_relaxed(controller_id_addr +
(offset + TSENS_DEBUG_OFFSET_WORD3));
pr_err("ctrl:%d:0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
cntrl_id, offset, r1, r2, r3, r4);
TSENS_DUMP(tmdev,
"ctrl:%d:0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
cntrl_id, offset, r1, r2, r3, r4);
offset += TSENS_DEBUG_OFFSET_ROW;
}
loop++;

View File

@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __QCOM_TSENS_H__
@ -13,6 +13,7 @@
#include <linux/workqueue.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/ipc_logging.h>
#define DEBUG_SIZE 10
#define TSENS_MAX_SENSORS 16
@ -29,6 +30,8 @@
#define SLOPE_FACTOR 1000
#define SLOPE_DEFAULT 3200
#define IPC_LOGPAGES 10
enum tsens_dbg_type {
TSENS_DBG_POLL,
TSENS_DBG_LOG_TEMP_READS,
@ -42,6 +45,54 @@ enum tsens_dbg_type {
struct tsens_device;
#ifdef CONFIG_DEBUG_FS
#define TSENS_IPC(idx, dev, msg, args...) do { \
if (dev) { \
if ((idx == 0) && (dev)->ipc_log0) \
ipc_log_string((dev)->ipc_log0, \
"%s: " msg, __func__, args); \
else if ((idx == 1) && (dev)->ipc_log1) \
ipc_log_string((dev)->ipc_log1, \
"%s: " msg, __func__, args); \
else if ((idx == 2) && (dev)->ipc_log2) \
ipc_log_string((dev)->ipc_log2, \
"%s: " msg, __func__, args); \
else \
pr_debug("tsens: invalid logging index\n"); \
} \
} while (0)
#define TSENS_DUMP(dev, msg, args...) do { \
TSENS_IPC(2, dev, msg, args); \
pr_info(msg, ##args); \
} while (0)
#define TSENS_ERR(dev, msg, args...) do { \
pr_err(msg, ##args); \
TSENS_IPC(1, dev, msg, args); \
} while (0)
#define TSENS_INFO(dev, msg, args...) do { \
pr_info(msg, ##args); \
TSENS_IPC(1, dev, msg, args); \
} while (0)
#define TSENS_DBG(dev, msg, args...) do { \
pr_debug(msg, ##args); \
if (dev) { \
TSENS_IPC(0, dev, msg, args); \
} \
} while (0)
#define TSENS_DBG1(dev, msg, args...) do { \
pr_debug(msg, ##args); \
if (dev) { \
TSENS_IPC(1, dev, msg, args); \
} \
} while (0)
#else
#define TSENS_DBG1(x...) pr_debug(x)
#define TSENS_DBG(x...) pr_debug(x)
#define TSENS_INFO(x...) pr_info(x)
#define TSENS_ERR(x...) pr_err(x)
#define TSENS_DUMP(x...) pr_info(x)
#endif
#if defined(CONFIG_THERMAL_TSENS)
int tsens2xxx_dbg(struct tsens_device *data, u32 id, u32 dbg_type, int *temp);
#else
@ -147,11 +198,16 @@ struct tsens_device {
void __iomem *tsens_tm_addr;
void __iomem *tsens_calib_addr;
const struct tsens_ops *ops;
void *ipc_log0;
void *ipc_log1;
void *ipc_log2;
phys_addr_t phys_addr_tm;
struct tsens_dbg_context tsens_dbg;
spinlock_t tsens_crit_lock;
spinlock_t tsens_upp_low_lock;
const struct tsens_data *ctrl_data;
struct tsens_mtc_sysfs mtcsys;
int trdy_fail_ctr;
struct tsens_sensor sensor[0];
};

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/module.h>
@ -88,10 +88,22 @@ static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp)
code = readl_relaxed_no_log(trdy);
if (!((code & TSENS_TM_TRDY_FIRST_ROUND_COMPLETE) >>
TSENS_TM_TRDY_FIRST_ROUND_COMPLETE_SHIFT)) {
pr_err("TSENS device first round not complete0x%x\n", code);
pr_err("tsens device first round not complete0x%x, ctr is %d\n",
code, tmdev->trdy_fail_ctr);
tmdev->trdy_fail_ctr++;
if (tmdev->trdy_fail_ctr >= 50) {
if (tmdev->ops->dbg)
tmdev->ops->dbg(tmdev, 0,
TSENS_DBG_LOG_BUS_ID_DATA, NULL);
BUG();
}
return -ENODATA;
}
tmdev->trdy_fail_ctr = 0;
code = readl_relaxed_no_log(sensor_addr +
(sensor->hw_id << TSENS_STATUS_ADDR_OFFSET));
last_temp = code & TSENS_TM_SN_LAST_TEMP_MASK;