blob: b54da6a515fac01687703286eddcdd4d9ef78ae2 [file] [log] [blame]
/*
* BIF support for the Paintbox programmable IPU
*
* Copyright (C) 2018 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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 <linux/debugfs.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/pm_runtime.h>
#include <linux/seq_file.h>
#include <linux/types.h>
#include "ipu-bif-debug.h"
#include "ipu-client.h"
#include "ipu-debug.h"
#include "ipu-regs.h"
static const char *ipu_bif_reg_names[IO_AXI_NUM_REGS] = {
REG_NAME_ENTRY64(MMU_CTRL),
REG_NAME_ENTRY64(MMU_ENABLE_CTRL),
REG_NAME_ENTRY64(MMU_PREFETCH_CTRL),
REG_NAME_ENTRY64(MMU_TABLE_BASE),
REG_NAME_ENTRY64(MMU_ERR_BASE),
REG_NAME_ENTRY64(MMU_SYNC),
REG_NAME_ENTRY64(MMU_FLUSH_CHANNEL),
REG_NAME_ENTRY64(MMU_FLUSH_ADDRESS),
REG_NAME_ENTRY64(MMU_FLUSH_FIFO_STATUS),
REG_NAME_ENTRY64(MMU_ISR),
REG_NAME_ENTRY64(MMU_ITR),
REG_NAME_ENTRY64(MMU_IER),
REG_NAME_ENTRY64(MMU_IMR),
REG_NAME_ENTRY64(MMU_ISR_OVF),
REG_NAME_ENTRY64(MMU_ERR_LOG),
REG_NAME_ENTRY64(BIF_AXI_CTRL_DMA0),
REG_NAME_ENTRY64(BIF_AXI_CTRL_DMA1),
REG_NAME_ENTRY64(BIF_AXI_CTRL_DMA2),
REG_NAME_ENTRY64(BIF_AXI_CTRL_DMA3),
REG_NAME_ENTRY64(BIF_AXI_CTRL_DMA4),
REG_NAME_ENTRY64(BIF_AXI_CTRL_DMA5),
REG_NAME_ENTRY64(BIF_AXI_CTRL_DMA6),
REG_NAME_ENTRY64(BIF_AXI_CTRL_DMA7),
REG_NAME_ENTRY64(BIF_AXI_CTRL_MMU),
REG_NAME_ENTRY64(BIF_ISR),
REG_NAME_ENTRY64(BIF_ITR),
REG_NAME_ENTRY64(BIF_IER),
REG_NAME_ENTRY64(BIF_IMR),
REG_NAME_ENTRY64(BIF_ISR_OVF),
REG_NAME_ENTRY64(BIF_TO_ERR_CFG),
REG_NAME_ENTRY64(BIF_ERR_LOG),
REG_NAME_ENTRY64(BIF_ERR_LOG_BUS_ADDR),
REG_NAME_ENTRY64(BIF_PMON_CFG),
REG_NAME_ENTRY64(BIF_PMON_CNT_0_CFG),
REG_NAME_ENTRY64(BIF_PMON_CNT_0),
REG_NAME_ENTRY64(BIF_PMON_CNT_0_STS_ACC),
REG_NAME_ENTRY64(BIF_PMON_CNT_0_STS),
REG_NAME_ENTRY64(BIF_PMON_CNT_1_CFG),
REG_NAME_ENTRY64(BIF_PMON_CNT_1),
REG_NAME_ENTRY64(BIF_PMON_CNT_1_STS_ACC),
REG_NAME_ENTRY64(BIF_PMON_CNT_1_STS),
REG_NAME_ENTRY64(MMU_PMON_CFG),
REG_NAME_ENTRY64(MMU_PMON_CNT_0_CFG),
REG_NAME_ENTRY64(MMU_PMON_CNT_0),
REG_NAME_ENTRY64(MMU_PMON_CNT_0_STS_ACC),
REG_NAME_ENTRY64(MMU_PMON_CNT_0_STS),
REG_NAME_ENTRY64(MMU_PMON_CNT_1_CFG),
REG_NAME_ENTRY64(MMU_PMON_CNT_1),
REG_NAME_ENTRY64(MMU_PMON_CNT_1_STS_ACC),
REG_NAME_ENTRY64(MMU_PMON_CNT_1_STS),
REG_NAME_ENTRY64(AXI_SPARE)
};
static int ipu_bif_debug_read_registers(struct seq_file *s, void *data)
{
struct paintbox_data *pb = dev_get_drvdata(s->private);
unsigned int i;
int ret;
mutex_lock(&pb->lock);
if (ipu_reset_is_requested(pb)) {
mutex_unlock(&pb->lock);
return -ECONNRESET;
}
ret = ipu_jqs_get(pb);
if (ret < 0) {
mutex_unlock(&pb->lock);
return ret;
}
for (i = 0; i < IO_AXI_NUM_REGS; i++) {
unsigned int offset;
if (ipu_bif_reg_names[i] == NULL)
continue;
offset = i * IPU_REG_WIDTH_BYTES + IPU_CSR_AXI_OFFSET;
seq_printf(s, "0x%04lx: %-*s0x%016llx\n", offset,
REG_VALUE_COL_WIDTH, ipu_bif_reg_names[i],
ipu_readq(pb->dev, offset));
}
ret = ipu_jqs_put(pb);
mutex_unlock(&pb->lock);
return ret;
}
static int ipu_bif_debug_register_set(void *data, u64 val)
{
struct ipu_debug_register *reg = (struct ipu_debug_register *)data;
struct paintbox_data *pb = reg->pb;
int ret;
mutex_lock(&pb->lock);
if (ipu_reset_is_requested(pb)) {
mutex_unlock(&pb->lock);
return -ECONNRESET;
}
ret = ipu_jqs_get(pb);
if (ret < 0) {
mutex_unlock(&pb->lock);
return ret;
}
ipu_writeq(pb->dev, val, reg->offset);
ret = ipu_jqs_put(pb);
mutex_unlock(&pb->lock);
return ret;
}
static int ipu_bif_debug_register_get(void *data, u64 *val)
{
struct ipu_debug_register *reg = (struct ipu_debug_register *)data;
struct paintbox_data *pb = reg->pb;
int ret;
mutex_lock(&pb->lock);
if (ipu_reset_is_requested(pb)) {
mutex_unlock(&pb->lock);
return -ECONNRESET;
}
ret = ipu_jqs_get(pb);
if (ret < 0) {
mutex_unlock(&pb->lock);
return ret;
}
*val = ipu_readq(pb->dev, reg->offset);
ret = ipu_jqs_put(pb);
mutex_unlock(&pb->lock);
return ret;
}
DEFINE_SIMPLE_ATTRIBUTE(ipu_bif_debug_register_fops, ipu_bif_debug_register_get,
ipu_bif_debug_register_set, "%llx\n");
static void ipu_bif_debug_create_register_file(struct paintbox_data *pb,
struct ipu_debug_register *reg, const char *name,
unsigned int offset)
{
reg->offset = IPU_CSR_AXI_OFFSET + offset;
reg->pb = pb;
reg->dentry = debugfs_create_file(name, 0640, pb->bif_debug_dir, reg,
&ipu_bif_debug_register_fops);
if (WARN_ON(IS_ERR(reg->dentry)))
reg->dentry = NULL;
}
void ipu_bif_debug_init(struct paintbox_data *pb)
{
unsigned int i;
pb->bif_debug_dir = debugfs_create_dir("bif", pb->debug_root);
if (WARN_ON(IS_ERR_OR_NULL(pb->bif_debug_dir)))
return;
pb->bif_reg_dump = debugfs_create_devm_seqfile(pb->dev, "regs",
pb->bif_debug_dir, ipu_bif_debug_read_registers);
if (WARN_ON(IS_ERR_OR_NULL(pb->bif_reg_dump)))
return;
for (i = 0; i < IO_AXI_NUM_REGS; i++) {
if (!ipu_bif_reg_names[i])
continue;
ipu_bif_debug_create_register_file(pb,
&pb->bif_debug_registers[i],
ipu_bif_reg_names[i], i * IPU_REG_WIDTH_BYTES);
}
}
void ipu_bif_debug_remove(struct paintbox_data *pb)
{
debugfs_remove_recursive(pb->bif_debug_dir);
}