/*
* Intel SOC Telemetry debugfs Driver: Currently supports APL
* Copyright (c) 2015, Intel Corporation.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.
*
* This file provides the debugfs interfaces for telemetry.
* /sys/kernel/debug/telemetry/pss_info: Shows Primary Control Sub-Sys Counters
* /sys/kernel/debug/telemetry/ioss_info: Shows IO Sub-System Counters
* /sys/kernel/debug/telemetry/soc_states: Shows SoC State
* /sys/kernel/debug/telemetry/pss_trace_verbosity: Read and Change Tracing
* Verbosity via firmware
* /sys/kernel/debug/telemetry/ioss_race_verbosity: Write and Change Tracing
* Verbosity via firmware
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/pci.h>
#include <linux/suspend.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/intel_pmc_ipc.h>
#include <asm/intel_punit_ipc.h>
#include <asm/intel_telemetry.h>
#define DRIVER_NAME "telemetry_soc_debugfs"
#define DRIVER_VERSION "1.0.0"
/* ApolloLake SoC Event-IDs */
#define TELEM_APL_PSS_PSTATES_ID 0x2802
#define TELEM_APL_PSS_IDLE_ID 0x2806
#define TELEM_APL_PCS_IDLE_BLOCKED_ID 0x2C00
#define TELEM_APL_PCS_S0IX_BLOCKED_ID 0x2C01
#define TELEM_APL_PSS_WAKEUP_ID 0x2C02
#define TELEM_APL_PSS_LTR_BLOCKING_ID 0x2C03
#define TELEM_APL_S0IX_TOTAL_OCC_ID 0x4000
#define TELEM_APL_S0IX_SHLW_OCC_ID 0x4001
#define TELEM_APL_S0IX_DEEP_OCC_ID 0x4002
#define TELEM_APL_S0IX_TOTAL_RES_ID 0x4800
#define TELEM_APL_S0IX_SHLW_RES_ID 0x4801
#define TELEM_APL_S0IX_DEEP_RES_ID 0x4802
#define TELEM_APL_D0IX_ID 0x581A
#define TELEM_APL_D3_ID 0x5819
#define TELEM_APL_PG_ID 0x5818
#define TELEM_INFO_SRAMEVTS_MASK 0xFF00
#define TELEM_INFO_SRAMEVTS_SHIFT 0x8
#define TELEM_SSRAM_READ_TIMEOUT 10
#define TELEM_MASK_BIT 1
#define TELEM_MASK_BYTE 0xFF
#define BYTES_PER_LONG 8
#define TELEM_APL_MASK_PCS_STATE 0xF
/* Max events in bitmap to check for */
#define TELEM_PSS_IDLE_EVTS 25
#define TELEM_PSS_IDLE_BLOCKED_EVTS 20
#define TELEM_PSS_S0IX_BLOCKED_EVTS 20
#define TELEM_PSS_S0IX_WAKEUP_EVTS 20
#define TELEM_PSS_LTR_BLOCKING_EVTS 20
#define TELEM_IOSS_DX_D0IX_EVTS 25
#define TELEM_IOSS_PG_EVTS 30
#define TELEM_EVT_LEN(x) (sizeof(x)/sizeof((x)[0]))
#define TELEM_DEBUGFS_CPU(model, data) \
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&data}
#define TELEM_CHECK_AND_PARSE_EVTS(EVTID, EVTNUM, BUF, EVTLOG, EVTDAT, MASK) { \
if (evtlog[index].telem_evtid == (EVTID)) { \
for (idx = 0; idx < (EVTNUM); idx++) \
(BUF)[idx] = ((EVTLOG) >> (EVTDAT)[idx].bit_pos) & \
(MASK); \
continue; \
} \
}
#define TELEM_CHECK_AND_PARSE_CTRS(EVTID, CTR) { \
if (evtlog[index].telem_evtid == (EVTID)) { \
(CTR) = evtlog[index].telem_evtlog; \
continue; \
} \
}
static u8 suspend_prep_ok;
static u32 suspend_shlw_ctr_temp, suspend_deep_ctr_temp;
static u64 suspend_shlw_res_temp, suspend_deep_res_temp;
struct telemetry_susp_stats {
u32 shlw_swake_ctr;
u32 deep_swake_ctr;
u64 shlw_swake_res;
u64 deep_swake_res;
u32 shlw_ctr;
u32 deep_ctr;
u64 shlw_res;
u64 deep_res;
};
/* Bitmap definitions for default counters in APL */
struct telem_pss_idle_stateinfo {
const char *name;
u32 bit_pos;
};
static struct telem_pss_idle_stateinfo telem_apl_pss_idle_data[] = {
{"IA_CORE0_C1E", 0},
{"IA_CORE1_C1E", 1},
{"IA_CORE2_C1E", 2},
{"IA_CORE3_C1E", 3},
{"IA_CORE0_C6", 16},
{"IA_CORE1_C6", 17},
{"IA_CORE2_C6", 18},
{"IA_CORE3_C6", 19},
{"IA_MODULE0_C7", 32},
{"IA_MODULE1_C7", 33},
{"GT_RC6", 40},
{"IUNIT_PROCESSING_IDLE", 41},
{"FAR_MEM_IDLE", 43},
{"DISPLAY_IDLE", 44},
{"IUNIT_INPUT_SYSTEM_IDLE", 45},
{"PCS_STATUS", 60},
};
struct telem_pcs_blkd_info {
const char *name;
u32 bit_pos;
};
static struct telem_pcs_blkd_info telem_apl_pcs_idle_blkd_data[] = {
{"COMPUTE", 0},
{"MISC", 8},
{"MODULE_ACTIONS_PENDING", 16},
{"LTR", 24},
{"DISPLAY_WAKE", 32},
{"ISP_WAKE", 40},
{"PSF0_ACTIVE", 48},
};
static struct telem_pcs_blkd_info telem_apl_pcs_s0ix_blkd_data[] = {
{"LTR", 0},
{"IRTL", 8},
{"WAKE_DEADLINE_PENDING", 16},
{"DISPLAY", 24},
{"ISP", 32},
{"CORE", 40},
{"PMC", 48},
{"MISC", 56},
};
struct telem_pss_ltr_info {
const char *name;
u32 bit_pos;
};
static struct telem_pss_ltr_info telem_apl_pss_ltr_data[] = {
{"CORE_ACTIVE", 0},
{"MEM_UP", 8},
{"DFX", 16},
{"DFX_FORCE_LTR", 24},
{"DISPLAY", 32},
{"ISP", 40},
{"SOUTH", 48},
};
struct telem_pss_wakeup_info {
const char *name;
u32 bit_pos;
};
static struct telem_pss_wakeup_info telem_apl_pss_wakeup[] = {
{"IP_IDLE", 0},
{"DISPLAY_WAKE", 8},
{"VOLTAGE_REG_INT", 16},
{<