disp: msm: sde: Add debug bus dump support for LUTDMA
Add hooks to dump LUTDUMA debug bus status during dumping of system debug status. LUTDMA debug bus can be accessed from userspace via the "recovery_lutdma_dbgbus" debugfs node. Output control of the LUTDMA_dbbus is managed by the "reg_dma_dbgbus" node. Change-Id: Iea011279dd3806f0f594102ce7a5dc018a8d2b7c Signed-off-by: Christopher Braga <cbraga@codeaurora.org>
This commit is contained in:
166
msm/sde_dbg.c
166
msm/sde_dbg.c
@@ -26,6 +26,7 @@
|
||||
#define DEFAULT_DBGBUS_SDE SDE_DBG_DUMP_IN_MEM
|
||||
#define DEFAULT_DBGBUS_VBIFRT SDE_DBG_DUMP_IN_MEM
|
||||
#define DEFAULT_DBGBUS_DSI SDE_DBG_DUMP_IN_MEM
|
||||
#define DEFAULT_DBGBUS_LUTDMA SDE_DBG_DUMP_IN_MEM
|
||||
#define DEFAULT_BASE_REG_CNT DEFAULT_MDSS_HW_BLOCK_SIZE
|
||||
#define GROUP_BYTES 4
|
||||
#define ROW_BYTES 16
|
||||
@@ -38,6 +39,11 @@
|
||||
#define DBGBUS_NAME_SDE "sde"
|
||||
#define DBGBUS_NAME_VBIF_RT "vbif_rt"
|
||||
#define DBGBUS_NAME_DSI "dsi"
|
||||
#define DBGBUS_NAME_LUTDMA "reg_dma"
|
||||
|
||||
/* offsets from LUTDMA top address for the debug buses */
|
||||
#define DBGBUS_LUTDMA_0 0x1E8
|
||||
#define DBGBUS_LUTDMA_1 0x5E8
|
||||
|
||||
/* offsets from sde top address for the debug buses */
|
||||
#define DBGBUS_SSPP0 0x188
|
||||
@@ -164,6 +170,12 @@ struct dsi_debug_bus_entry {
|
||||
u32 sel;
|
||||
};
|
||||
|
||||
struct lutdma_debug_bus_entry {
|
||||
u32 wr_addr;
|
||||
bool read_engine;
|
||||
u32 indicies;
|
||||
};
|
||||
|
||||
struct sde_dbg_dsi_ctrl_list_entry {
|
||||
const char *name;
|
||||
void __iomem *base;
|
||||
@@ -197,6 +209,11 @@ struct sde_dbg_dsi_debug_bus {
|
||||
struct dsi_debug_bus_entry *entries;
|
||||
};
|
||||
|
||||
struct sde_dbg_lutdma_debug_bus {
|
||||
struct sde_dbg_debug_bus_common cmn;
|
||||
struct lutdma_debug_bus_entry *entries;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sde_dbg_regbuf - wraps buffer and tracking params for register dumps
|
||||
* @buf: pointer to allocated memory for storing register dumps in hw recovery
|
||||
@@ -228,6 +245,7 @@ struct sde_dbg_regbuf {
|
||||
* @enable_reg_dump: whether to dump registers into memory, kernel log, or both
|
||||
* @dbgbus_sde: debug bus structure for the sde
|
||||
* @dbgbus_vbif_rt: debug bus structure for the realtime vbif
|
||||
* @dbgbus_lutdma: debug bus structure for the lutdma hw
|
||||
* @dump_all: dump all entries in register dump
|
||||
* @dump_secure: dump entries excluding few as it is in secure-session
|
||||
* @dsi_dbg_bus: dump dsi debug bus register
|
||||
@@ -252,6 +270,7 @@ static struct sde_dbg_base {
|
||||
struct sde_dbg_sde_debug_bus dbgbus_sde;
|
||||
struct sde_dbg_vbif_debug_bus dbgbus_vbif_rt;
|
||||
struct sde_dbg_dsi_debug_bus dbgbus_dsi;
|
||||
struct sde_dbg_lutdma_debug_bus dbgbus_lutdma;
|
||||
bool dump_all;
|
||||
bool dump_secure;
|
||||
u32 debugfs_ctrl;
|
||||
@@ -4291,6 +4310,13 @@ static struct dsi_debug_bus_entry dsi_dbg_bus_kona[] = {
|
||||
{0, 0x3c}, {0, 0x3d}, {0, 0x3e}, {0, 0x3f},
|
||||
};
|
||||
|
||||
static struct lutdma_debug_bus_entry dbg_bus_lutdma_lahaina[] = {
|
||||
{ DBGBUS_LUTDMA_0, false, 1024 },
|
||||
{ DBGBUS_LUTDMA_0, true, 1024 },
|
||||
{ DBGBUS_LUTDMA_1, false, 1024 },
|
||||
{ DBGBUS_LUTDMA_1, true, 1024 },
|
||||
};
|
||||
|
||||
/**
|
||||
* _sde_power_check - check if power needs to enabled
|
||||
* @dump_mode: to check if power need to be enabled
|
||||
@@ -4960,6 +4986,103 @@ static void _sde_dbg_dump_dsi_dbg_bus(struct sde_dbg_dsi_debug_bus *bus)
|
||||
bus->cmn.name);
|
||||
}
|
||||
|
||||
static void _sde_dbg_dump_lutdma_dbg_bus(struct sde_dbg_lutdma_debug_bus *bus)
|
||||
{
|
||||
void __iomem *mem_base = NULL;
|
||||
struct sde_dbg_reg_base *reg_base;
|
||||
struct lutdma_debug_bus_entry *entries;
|
||||
bool dump_in_log, dump_in_mem;
|
||||
u32 **dump_mem = NULL;
|
||||
u32 *dump_addr = NULL;
|
||||
u32 i, j, entry_count, addr, count, val, engine_bit, dump_mem_size = 0;
|
||||
int rc;
|
||||
|
||||
if (!bus || !bus->cmn.entries_size)
|
||||
return;
|
||||
|
||||
list_for_each_entry(reg_base, &sde_dbg_base.reg_base_list,
|
||||
reg_base_head) {
|
||||
if (strlen(reg_base->name) &&
|
||||
!strcmp(reg_base->name, bus->cmn.name))
|
||||
mem_base = reg_base->base;
|
||||
}
|
||||
|
||||
if (!mem_base) {
|
||||
pr_err("unable to find mem_base for %s\n", bus->cmn.name);
|
||||
return;
|
||||
}
|
||||
|
||||
entries = bus->entries;
|
||||
entry_count = bus->cmn.entries_size;
|
||||
|
||||
dump_in_log = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_LOG);
|
||||
dump_in_mem = (bus->cmn.enable_mask & SDE_DBG_DUMP_IN_MEM);
|
||||
dump_mem = &bus->cmn.dumped_content;
|
||||
|
||||
if (!dump_in_log && !dump_in_mem)
|
||||
return;
|
||||
|
||||
rc = pm_runtime_get_sync(sde_dbg_base.dev);
|
||||
if (rc < 0) {
|
||||
pr_err("failed to enable power %d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
dev_info(sde_dbg_base.dev, "======== start %s dump =========\n",
|
||||
bus->cmn.name);
|
||||
|
||||
if (dump_in_mem) {
|
||||
if (*dump_mem == NULL) {
|
||||
for (i = 0; i < entry_count; i++)
|
||||
dump_mem_size += (entries[i].indicies *
|
||||
sizeof(u32));
|
||||
|
||||
//Ensure enough chunks for debugfs dumping
|
||||
dump_mem_size += dump_mem_size % (DUMP_CLMN_COUNT * 4);
|
||||
*dump_mem = devm_kzalloc(sde_dbg_base.dev,
|
||||
dump_mem_size, GFP_KERNEL);
|
||||
bus->cmn.content_size = dump_mem_size / sizeof(u32);
|
||||
}
|
||||
|
||||
if (*dump_mem) {
|
||||
dump_addr = *dump_mem;
|
||||
dev_info(sde_dbg_base.dev,
|
||||
"%s: start_addr:0x%pK len:0x%x\n",
|
||||
__func__, dump_addr, dump_mem_size);
|
||||
} else {
|
||||
dump_in_mem = false;
|
||||
pr_err("dump_mem: allocation fails\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < entry_count; i++) {
|
||||
addr = entries[i].wr_addr;
|
||||
count = entries[i].indicies;
|
||||
engine_bit = entries[i].read_engine ? BIT(14) : 0;
|
||||
|
||||
for (j = 0 ; j < count; j++) {
|
||||
val = (BIT(0) | engine_bit | (j << 1)) & 0xFFFF;
|
||||
writel_relaxed(val, mem_base + addr);
|
||||
wmb(); /* Ensure dbgbus setup occurs before read */
|
||||
val = readl_relaxed(mem_base + addr + 0x4);
|
||||
|
||||
if (dump_in_log)
|
||||
dev_info(sde_dbg_base.dev,
|
||||
"lutdma_waddr=0x%x index=0x%x val=0x%x\n",
|
||||
addr, j, val);
|
||||
|
||||
if (dump_in_mem)
|
||||
dump_addr[i * count + j] = val;
|
||||
}
|
||||
|
||||
//Disable debug bus when done
|
||||
writel_relaxed(0, mem_base + addr);
|
||||
}
|
||||
|
||||
dev_info(sde_dbg_base.dev, "======== end %s dump =========\n",
|
||||
bus->cmn.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* _sde_dump_array - dump array of register bases
|
||||
* @blk_arr: array of register base pointers
|
||||
@@ -5004,6 +5127,9 @@ static void _sde_dump_array(struct sde_dbg_reg_base *blk_arr[],
|
||||
if (dump_all || dump_dbgbus_dsi)
|
||||
_sde_dbg_dump_dsi_dbg_bus(&sde_dbg_base.dbgbus_dsi);
|
||||
|
||||
if (dump_all || dump_dbgbus_sde)
|
||||
_sde_dbg_dump_lutdma_dbg_bus(&sde_dbg_base.dbgbus_lutdma);
|
||||
|
||||
if (do_panic && sde_dbg_base.panic_on_err)
|
||||
panic(name);
|
||||
|
||||
@@ -5651,6 +5777,29 @@ static const struct file_operations sde_recovery_dsi_dbgbus_fops = {
|
||||
.read = sde_recovery_dbgbus_dump_read,
|
||||
};
|
||||
|
||||
|
||||
static int sde_recovery_lutdma_dbgbus_dump_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
if (!inode || !file)
|
||||
return -EINVAL;
|
||||
|
||||
/* non-seekable */
|
||||
file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
|
||||
file->private_data = (void *)&sde_dbg_base.dbgbus_lutdma.cmn;
|
||||
|
||||
mutex_lock(&sde_dbg_base.mutex);
|
||||
sde_dbg_base.dbgbus_lutdma.cmn.content_idx = 0;
|
||||
mutex_unlock(&sde_dbg_base.mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations sde_recovery_lutdma_dbgbus_fops = {
|
||||
.open = sde_recovery_lutdma_dbgbus_dump_open,
|
||||
.read = sde_recovery_dbgbus_dump_read,
|
||||
};
|
||||
|
||||
/**
|
||||
* sde_dbg_reg_base_release - release allocated reg dump file private data
|
||||
* @inode: debugfs inode
|
||||
@@ -6075,6 +6224,16 @@ int sde_dbg_debugfs_register(struct device *dev)
|
||||
&dbg->dbgbus_dsi.cmn.enable_mask);
|
||||
}
|
||||
|
||||
if (dbg->dbgbus_lutdma.entries) {
|
||||
debugfs_create_file("recovery_lutdma_dbgbus", 0400,
|
||||
debugfs_root, NULL,
|
||||
&sde_recovery_lutdma_dbgbus_fops);
|
||||
snprintf(debug_name, sizeof(debug_name), "%s_dbgbus",
|
||||
dbg->dbgbus_lutdma.cmn.name);
|
||||
debugfs_create_u32(debug_name, 0600, debugfs_root,
|
||||
&dbg->dbgbus_lutdma.cmn.enable_mask);
|
||||
}
|
||||
|
||||
list_for_each_entry(blk_base, &dbg->reg_base_list, reg_base_head) {
|
||||
snprintf(debug_name, sizeof(debug_name), "%s_off",
|
||||
blk_base->name);
|
||||
@@ -6120,6 +6279,13 @@ void sde_dbg_init_dbg_buses(u32 hwversion)
|
||||
ARRAY_SIZE(dsi_dbg_bus_kona);
|
||||
dbg->dbgbus_dsi.cmn.name = DBGBUS_NAME_DSI;
|
||||
dbg->dbgbus_dsi.cmn.enable_mask = DEFAULT_DBGBUS_DSI;
|
||||
|
||||
dbg->dbgbus_lutdma.entries = dbg_bus_lutdma_lahaina;
|
||||
dbg->dbgbus_lutdma.cmn.name = DBGBUS_NAME_LUTDMA;
|
||||
dbg->dbgbus_lutdma.cmn.entries_size =
|
||||
ARRAY_SIZE(dbg_bus_lutdma_lahaina);
|
||||
dbg->dbgbus_lutdma.cmn.enable_mask = DEFAULT_DBGBUS_LUTDMA;
|
||||
dbg->dbgbus_lutdma.cmn.include_in_deferred_work = true;
|
||||
} else if (SDE_HW_REV_MAJOR(hwversion) == 0x6) {
|
||||
dbg->dbgbus_sde.entries = dbg_bus_sde_kona;
|
||||
dbg->dbgbus_sde.cmn.entries_size =
|
||||
|
Reference in New Issue
Block a user