162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2023 Cai Huoqing
462306a36Sopenharmony_ci * Synopsys DesignWare HDMA v0 debugfs
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Author: Cai Huoqing <cai.huoqing@linux.dev>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/debugfs.h>
1062306a36Sopenharmony_ci#include <linux/bitfield.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "dw-hdma-v0-debugfs.h"
1362306a36Sopenharmony_ci#include "dw-hdma-v0-regs.h"
1462306a36Sopenharmony_ci#include "dw-edma-core.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define REGS_ADDR(dw, name)						       \
1762306a36Sopenharmony_ci	({								       \
1862306a36Sopenharmony_ci		struct dw_hdma_v0_regs __iomem *__regs = (dw)->chip->reg_base; \
1962306a36Sopenharmony_ci									       \
2062306a36Sopenharmony_ci		(void __iomem *)&__regs->name;				       \
2162306a36Sopenharmony_ci	})
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define REGS_CH_ADDR(dw, name, _dir, _ch)				       \
2462306a36Sopenharmony_ci	({								       \
2562306a36Sopenharmony_ci		struct dw_hdma_v0_ch_regs __iomem *__ch_regs;		       \
2662306a36Sopenharmony_ci									       \
2762306a36Sopenharmony_ci		if (_dir == EDMA_DIR_READ)				       \
2862306a36Sopenharmony_ci			__ch_regs = REGS_ADDR(dw, ch[_ch].rd);		       \
2962306a36Sopenharmony_ci		else							       \
3062306a36Sopenharmony_ci			__ch_regs = REGS_ADDR(dw, ch[_ch].wr);		       \
3162306a36Sopenharmony_ci									       \
3262306a36Sopenharmony_ci		(void __iomem *)&__ch_regs->name;			       \
3362306a36Sopenharmony_ci	})
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define CTX_REGISTER(dw, name, dir, ch) \
3662306a36Sopenharmony_ci	{#name, REGS_CH_ADDR(dw, name, dir, ch)}
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define WRITE_STR				"write"
3962306a36Sopenharmony_ci#define READ_STR				"read"
4062306a36Sopenharmony_ci#define CHANNEL_STR				"channel"
4162306a36Sopenharmony_ci#define REGISTERS_STR				"registers"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistruct dw_hdma_debugfs_entry {
4462306a36Sopenharmony_ci	const char				*name;
4562306a36Sopenharmony_ci	void __iomem				*reg;
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic int dw_hdma_debugfs_u32_get(void *data, u64 *val)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct dw_hdma_debugfs_entry *entry = data;
5162306a36Sopenharmony_ci	void __iomem *reg = entry->reg;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	*val = readl(reg);
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	return 0;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_hdma_debugfs_u32_get, NULL, "0x%08llx\n");
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void dw_hdma_debugfs_create_x32(struct dw_edma *dw,
6062306a36Sopenharmony_ci				       const struct dw_hdma_debugfs_entry ini[],
6162306a36Sopenharmony_ci				       int nr_entries, struct dentry *dent)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	struct dw_hdma_debugfs_entry *entries;
6462306a36Sopenharmony_ci	int i;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	entries = devm_kcalloc(dw->chip->dev, nr_entries, sizeof(*entries),
6762306a36Sopenharmony_ci			       GFP_KERNEL);
6862306a36Sopenharmony_ci	if (!entries)
6962306a36Sopenharmony_ci		return;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	for (i = 0; i < nr_entries; i++) {
7262306a36Sopenharmony_ci		entries[i] = ini[i];
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci		debugfs_create_file_unsafe(entries[i].name, 0444, dent,
7562306a36Sopenharmony_ci					   &entries[i], &fops_x32);
7662306a36Sopenharmony_ci	}
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic void dw_hdma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir dir,
8062306a36Sopenharmony_ci				    u16 ch, struct dentry *dent)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	const struct dw_hdma_debugfs_entry debugfs_regs[] = {
8362306a36Sopenharmony_ci		CTX_REGISTER(dw, ch_en, dir, ch),
8462306a36Sopenharmony_ci		CTX_REGISTER(dw, doorbell, dir, ch),
8562306a36Sopenharmony_ci		CTX_REGISTER(dw, prefetch, dir, ch),
8662306a36Sopenharmony_ci		CTX_REGISTER(dw, handshake, dir, ch),
8762306a36Sopenharmony_ci		CTX_REGISTER(dw, llp.lsb, dir, ch),
8862306a36Sopenharmony_ci		CTX_REGISTER(dw, llp.msb, dir, ch),
8962306a36Sopenharmony_ci		CTX_REGISTER(dw, cycle_sync, dir, ch),
9062306a36Sopenharmony_ci		CTX_REGISTER(dw, transfer_size, dir, ch),
9162306a36Sopenharmony_ci		CTX_REGISTER(dw, sar.lsb, dir, ch),
9262306a36Sopenharmony_ci		CTX_REGISTER(dw, sar.msb, dir, ch),
9362306a36Sopenharmony_ci		CTX_REGISTER(dw, dar.lsb, dir, ch),
9462306a36Sopenharmony_ci		CTX_REGISTER(dw, dar.msb, dir, ch),
9562306a36Sopenharmony_ci		CTX_REGISTER(dw, watermark_en, dir, ch),
9662306a36Sopenharmony_ci		CTX_REGISTER(dw, control1, dir, ch),
9762306a36Sopenharmony_ci		CTX_REGISTER(dw, func_num, dir, ch),
9862306a36Sopenharmony_ci		CTX_REGISTER(dw, qos, dir, ch),
9962306a36Sopenharmony_ci		CTX_REGISTER(dw, ch_stat, dir, ch),
10062306a36Sopenharmony_ci		CTX_REGISTER(dw, int_stat, dir, ch),
10162306a36Sopenharmony_ci		CTX_REGISTER(dw, int_setup, dir, ch),
10262306a36Sopenharmony_ci		CTX_REGISTER(dw, int_clear, dir, ch),
10362306a36Sopenharmony_ci		CTX_REGISTER(dw, msi_stop.lsb, dir, ch),
10462306a36Sopenharmony_ci		CTX_REGISTER(dw, msi_stop.msb, dir, ch),
10562306a36Sopenharmony_ci		CTX_REGISTER(dw, msi_watermark.lsb, dir, ch),
10662306a36Sopenharmony_ci		CTX_REGISTER(dw, msi_watermark.msb, dir, ch),
10762306a36Sopenharmony_ci		CTX_REGISTER(dw, msi_abort.lsb, dir, ch),
10862306a36Sopenharmony_ci		CTX_REGISTER(dw, msi_abort.msb, dir, ch),
10962306a36Sopenharmony_ci		CTX_REGISTER(dw, msi_msgdata, dir, ch),
11062306a36Sopenharmony_ci	};
11162306a36Sopenharmony_ci	int nr_entries = ARRAY_SIZE(debugfs_regs);
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	dw_hdma_debugfs_create_x32(dw, debugfs_regs, nr_entries, dent);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic void dw_hdma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	struct dentry *regs_dent, *ch_dent;
11962306a36Sopenharmony_ci	char name[32];
12062306a36Sopenharmony_ci	int i;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	regs_dent = debugfs_create_dir(WRITE_STR, dent);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	for (i = 0; i < dw->wr_ch_cnt; i++) {
12562306a36Sopenharmony_ci		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		ch_dent = debugfs_create_dir(name, regs_dent);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci		dw_hdma_debugfs_regs_ch(dw, EDMA_DIR_WRITE, i, ch_dent);
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic void dw_hdma_debugfs_regs_rd(struct dw_edma *dw, struct dentry *dent)
13462306a36Sopenharmony_ci{
13562306a36Sopenharmony_ci	struct dentry *regs_dent, *ch_dent;
13662306a36Sopenharmony_ci	char name[32];
13762306a36Sopenharmony_ci	int i;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	regs_dent = debugfs_create_dir(READ_STR, dent);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	for (i = 0; i < dw->rd_ch_cnt; i++) {
14262306a36Sopenharmony_ci		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		ch_dent = debugfs_create_dir(name, regs_dent);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci		dw_hdma_debugfs_regs_ch(dw, EDMA_DIR_READ, i, ch_dent);
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cistatic void dw_hdma_debugfs_regs(struct dw_edma *dw)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct dentry *regs_dent;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	regs_dent = debugfs_create_dir(REGISTERS_STR, dw->dma.dbg_dev_root);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	dw_hdma_debugfs_regs_wr(dw, regs_dent);
15762306a36Sopenharmony_ci	dw_hdma_debugfs_regs_rd(dw, regs_dent);
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_civoid dw_hdma_v0_debugfs_on(struct dw_edma *dw)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	if (!debugfs_initialized())
16362306a36Sopenharmony_ci		return;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	debugfs_create_u32("mf", 0444, dw->dma.dbg_dev_root, &dw->chip->mf);
16662306a36Sopenharmony_ci	debugfs_create_u16("wr_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->wr_ch_cnt);
16762306a36Sopenharmony_ci	debugfs_create_u16("rd_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->rd_ch_cnt);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	dw_hdma_debugfs_regs(dw);
17062306a36Sopenharmony_ci}
171