162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Rockchip ISP1 Driver - Base driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2019 Collabora, Ltd.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.
862306a36Sopenharmony_ci * Copyright (C) 2017 Rockchip Electronics Co., Ltd.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/debugfs.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci#include <linux/device.h>
1462306a36Sopenharmony_ci#include <linux/minmax.h>
1562306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1662306a36Sopenharmony_ci#include <linux/seq_file.h>
1762306a36Sopenharmony_ci#include <linux/string.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "rkisp1-common.h"
2062306a36Sopenharmony_ci#include "rkisp1-regs.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct rkisp1_debug_register {
2362306a36Sopenharmony_ci	u32 reg;
2462306a36Sopenharmony_ci	u32 shd;
2562306a36Sopenharmony_ci	const char * const name;
2662306a36Sopenharmony_ci};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define RKISP1_DEBUG_REG(name)		{ RKISP1_CIF_##name, 0, #name }
2962306a36Sopenharmony_ci#define RKISP1_DEBUG_SHD_REG(name) { \
3062306a36Sopenharmony_ci	RKISP1_CIF_##name, RKISP1_CIF_##name##_SHD, #name \
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/* Keep this up-to-date when adding new registers. */
3462306a36Sopenharmony_ci#define RKISP1_MAX_REG_LENGTH		21
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int rkisp1_debug_dump_regs(struct rkisp1_device *rkisp1,
3762306a36Sopenharmony_ci				  struct seq_file *m, unsigned int offset,
3862306a36Sopenharmony_ci				  const struct rkisp1_debug_register *regs)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	const int width = RKISP1_MAX_REG_LENGTH;
4162306a36Sopenharmony_ci	u32 val, shd;
4262306a36Sopenharmony_ci	int ret;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	ret = pm_runtime_get_if_in_use(rkisp1->dev);
4562306a36Sopenharmony_ci	if (ret <= 0)
4662306a36Sopenharmony_ci		return ret ? : -ENODATA;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	for (; regs->name; ++regs) {
4962306a36Sopenharmony_ci		val = rkisp1_read(rkisp1, offset + regs->reg);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci		if (regs->shd) {
5262306a36Sopenharmony_ci			shd = rkisp1_read(rkisp1, offset + regs->shd);
5362306a36Sopenharmony_ci			seq_printf(m, "%*s: 0x%08x/0x%08x\n", width, regs->name,
5462306a36Sopenharmony_ci				   val, shd);
5562306a36Sopenharmony_ci		} else {
5662306a36Sopenharmony_ci			seq_printf(m, "%*s: 0x%08x\n", width, regs->name, val);
5762306a36Sopenharmony_ci		}
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	pm_runtime_put(rkisp1->dev);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	return 0;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic int rkisp1_debug_dump_core_regs_show(struct seq_file *m, void *p)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	static const struct rkisp1_debug_register registers[] = {
6862306a36Sopenharmony_ci		RKISP1_DEBUG_REG(VI_CCL),
6962306a36Sopenharmony_ci		RKISP1_DEBUG_REG(VI_ICCL),
7062306a36Sopenharmony_ci		RKISP1_DEBUG_REG(VI_IRCL),
7162306a36Sopenharmony_ci		RKISP1_DEBUG_REG(VI_DPCL),
7262306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_CTRL),
7362306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_BYTE_CNT),
7462306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_CTRL_SHD),
7562306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_RIS),
7662306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_STATUS),
7762306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_DMA_CTRL),
7862306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_DMA_STATUS),
7962306a36Sopenharmony_ci		{ /* Sentinel */ },
8062306a36Sopenharmony_ci	};
8162306a36Sopenharmony_ci	struct rkisp1_device *rkisp1 = m->private;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return rkisp1_debug_dump_regs(rkisp1, m, 0, registers);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_core_regs);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int rkisp1_debug_dump_isp_regs_show(struct seq_file *m, void *p)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	static const struct rkisp1_debug_register registers[] = {
9062306a36Sopenharmony_ci		RKISP1_DEBUG_REG(ISP_CTRL),
9162306a36Sopenharmony_ci		RKISP1_DEBUG_REG(ISP_ACQ_PROP),
9262306a36Sopenharmony_ci		RKISP1_DEBUG_REG(ISP_FLAGS_SHD),
9362306a36Sopenharmony_ci		RKISP1_DEBUG_REG(ISP_RIS),
9462306a36Sopenharmony_ci		RKISP1_DEBUG_REG(ISP_ERR),
9562306a36Sopenharmony_ci		{ /* Sentinel */ },
9662306a36Sopenharmony_ci	};
9762306a36Sopenharmony_ci	struct rkisp1_device *rkisp1 = m->private;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	return rkisp1_debug_dump_regs(rkisp1, m, 0, registers);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_isp_regs);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic int rkisp1_debug_dump_rsz_regs_show(struct seq_file *m, void *p)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	static const struct rkisp1_debug_register registers[] = {
10662306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_CTRL),
10762306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HY),
10862306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCB),
10962306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCR),
11062306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VY),
11162306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VC),
11262306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HY),
11362306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HC),
11462306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VY),
11562306a36Sopenharmony_ci		RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VC),
11662306a36Sopenharmony_ci		{ /* Sentinel */ },
11762306a36Sopenharmony_ci	};
11862306a36Sopenharmony_ci	struct rkisp1_resizer *rsz = m->private;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return rkisp1_debug_dump_regs(rsz->rkisp1, m, rsz->regs_base, registers);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_rsz_regs);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int rkisp1_debug_dump_mi_mp_show(struct seq_file *m, void *p)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	static const struct rkisp1_debug_register registers[] = {
12762306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT),
12862306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT2),
12962306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_SHD),
13062306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT),
13162306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT),
13262306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_MP_Y_SIZE_SHD),
13362306a36Sopenharmony_ci		RKISP1_DEBUG_REG(MI_MP_Y_OFFS_CNT_SHD),
13462306a36Sopenharmony_ci		{ /* Sentinel */ },
13562306a36Sopenharmony_ci	};
13662306a36Sopenharmony_ci	struct rkisp1_device *rkisp1 = m->private;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return rkisp1_debug_dump_regs(rkisp1, m, 0, registers);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_mi_mp);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#define RKISP1_DEBUG_DATA_COUNT_BINS	32
14362306a36Sopenharmony_ci#define RKISP1_DEBUG_DATA_COUNT_STEP	(4096 / RKISP1_DEBUG_DATA_COUNT_BINS)
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistatic int rkisp1_debug_input_status_show(struct seq_file *m, void *p)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct rkisp1_device *rkisp1 = m->private;
14862306a36Sopenharmony_ci	u16 data_count[RKISP1_DEBUG_DATA_COUNT_BINS] = { };
14962306a36Sopenharmony_ci	unsigned int hsync_count = 0;
15062306a36Sopenharmony_ci	unsigned int vsync_count = 0;
15162306a36Sopenharmony_ci	unsigned int i;
15262306a36Sopenharmony_ci	u32 data;
15362306a36Sopenharmony_ci	u32 val;
15462306a36Sopenharmony_ci	int ret;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	ret = pm_runtime_get_if_in_use(rkisp1->dev);
15762306a36Sopenharmony_ci	if (ret <= 0)
15862306a36Sopenharmony_ci		return ret ? : -ENODATA;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/* Sample the ISP input port status 10000 times with a 1µs interval. */
16162306a36Sopenharmony_ci	for (i = 0; i < 10000; ++i) {
16262306a36Sopenharmony_ci		val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_FLAGS_SHD);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		data = (val & RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_MASK)
16562306a36Sopenharmony_ci		     >> RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_SHIFT;
16662306a36Sopenharmony_ci		data_count[data / RKISP1_DEBUG_DATA_COUNT_STEP]++;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci		if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_HSYNC)
16962306a36Sopenharmony_ci			hsync_count++;
17062306a36Sopenharmony_ci		if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_VSYNC)
17162306a36Sopenharmony_ci			vsync_count++;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		udelay(1);
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	pm_runtime_put(rkisp1->dev);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	seq_printf(m, "vsync: %u, hsync: %u\n", vsync_count, hsync_count);
17962306a36Sopenharmony_ci	seq_puts(m, "data:\n");
18062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(data_count); ++i)
18162306a36Sopenharmony_ci		seq_printf(m, "- [%04u:%04u]: %u\n",
18262306a36Sopenharmony_ci			   i * RKISP1_DEBUG_DATA_COUNT_STEP,
18362306a36Sopenharmony_ci			   (i + 1) * RKISP1_DEBUG_DATA_COUNT_STEP - 1,
18462306a36Sopenharmony_ci			   data_count[i]);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return 0;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(rkisp1_debug_input_status);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_civoid rkisp1_debug_init(struct rkisp1_device *rkisp1)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct rkisp1_debug *debug = &rkisp1->debug;
19362306a36Sopenharmony_ci	struct dentry *regs_dir;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	debug->debugfs_dir = debugfs_create_dir(dev_name(rkisp1->dev), NULL);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir,
19862306a36Sopenharmony_ci			     &debug->data_loss);
19962306a36Sopenharmony_ci	debugfs_create_ulong("outform_size_err", 0444,  debug->debugfs_dir,
20062306a36Sopenharmony_ci			     &debug->outform_size_error);
20162306a36Sopenharmony_ci	debugfs_create_ulong("img_stabilization_size_error", 0444,
20262306a36Sopenharmony_ci			     debug->debugfs_dir,
20362306a36Sopenharmony_ci			     &debug->img_stabilization_size_error);
20462306a36Sopenharmony_ci	debugfs_create_ulong("inform_size_error", 0444,  debug->debugfs_dir,
20562306a36Sopenharmony_ci			     &debug->inform_size_error);
20662306a36Sopenharmony_ci	debugfs_create_ulong("irq_delay", 0444,  debug->debugfs_dir,
20762306a36Sopenharmony_ci			     &debug->irq_delay);
20862306a36Sopenharmony_ci	debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir,
20962306a36Sopenharmony_ci			     &debug->mipi_error);
21062306a36Sopenharmony_ci	debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir,
21162306a36Sopenharmony_ci			     &debug->stats_error);
21262306a36Sopenharmony_ci	debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir,
21362306a36Sopenharmony_ci			     &debug->stop_timeout[RKISP1_MAINPATH]);
21462306a36Sopenharmony_ci	debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir,
21562306a36Sopenharmony_ci			     &debug->stop_timeout[RKISP1_SELFPATH]);
21662306a36Sopenharmony_ci	debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir,
21762306a36Sopenharmony_ci			     &debug->frame_drop[RKISP1_MAINPATH]);
21862306a36Sopenharmony_ci	debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir,
21962306a36Sopenharmony_ci			     &debug->frame_drop[RKISP1_SELFPATH]);
22062306a36Sopenharmony_ci	debugfs_create_file("input_status", 0444, debug->debugfs_dir, rkisp1,
22162306a36Sopenharmony_ci			    &rkisp1_debug_input_status_fops);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	regs_dir = debugfs_create_dir("regs", debug->debugfs_dir);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	debugfs_create_file("core", 0444, regs_dir, rkisp1,
22662306a36Sopenharmony_ci			    &rkisp1_debug_dump_core_regs_fops);
22762306a36Sopenharmony_ci	debugfs_create_file("isp", 0444, regs_dir, rkisp1,
22862306a36Sopenharmony_ci			    &rkisp1_debug_dump_isp_regs_fops);
22962306a36Sopenharmony_ci	debugfs_create_file("mrsz", 0444, regs_dir,
23062306a36Sopenharmony_ci			    &rkisp1->resizer_devs[RKISP1_MAINPATH],
23162306a36Sopenharmony_ci			    &rkisp1_debug_dump_rsz_regs_fops);
23262306a36Sopenharmony_ci	debugfs_create_file("srsz", 0444, regs_dir,
23362306a36Sopenharmony_ci			    &rkisp1->resizer_devs[RKISP1_SELFPATH],
23462306a36Sopenharmony_ci			    &rkisp1_debug_dump_rsz_regs_fops);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	debugfs_create_file("mi_mp", 0444, regs_dir, rkisp1,
23762306a36Sopenharmony_ci			    &rkisp1_debug_dump_mi_mp_fops);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_civoid rkisp1_debug_cleanup(struct rkisp1_device *rkisp1)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	debugfs_remove_recursive(rkisp1->debug.debugfs_dir);
24362306a36Sopenharmony_ci}
244