xref: /openbmc/linux/drivers/dma/dw-edma/dw-edma-v0-debugfs.c (revision d0152168538ea05695a403bc424da3e65aca67f3)
1305aebefSGustavo Pimentel // SPDX-License-Identifier: GPL-2.0
2305aebefSGustavo Pimentel /*
3305aebefSGustavo Pimentel  * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
4305aebefSGustavo Pimentel  * Synopsys DesignWare eDMA v0 core
5305aebefSGustavo Pimentel  *
6305aebefSGustavo Pimentel  * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
7305aebefSGustavo Pimentel  */
8305aebefSGustavo Pimentel 
9305aebefSGustavo Pimentel #include <linux/debugfs.h>
10305aebefSGustavo Pimentel #include <linux/bitfield.h>
11305aebefSGustavo Pimentel 
12305aebefSGustavo Pimentel #include "dw-edma-v0-debugfs.h"
13305aebefSGustavo Pimentel #include "dw-edma-v0-regs.h"
14305aebefSGustavo Pimentel #include "dw-edma-core.h"
15305aebefSGustavo Pimentel 
16*d0152168SSerge Semin #define REGS_ADDR(dw, name)						       \
17*d0152168SSerge Semin 	({								       \
18*d0152168SSerge Semin 		struct dw_edma_v0_regs __iomem *__regs = (dw)->chip->reg_base; \
19*d0152168SSerge Semin 									       \
20*d0152168SSerge Semin 		(void __iomem *)&__regs->name;				       \
21*d0152168SSerge Semin 	})
2200498167SSerge Semin 
23*d0152168SSerge Semin #define REGS_CH_ADDR(dw, name, _dir, _ch)				       \
2400498167SSerge Semin 	({								       \
2500498167SSerge Semin 		struct dw_edma_v0_ch_regs __iomem *__ch_regs;		       \
2600498167SSerge Semin 									       \
2700498167SSerge Semin 		if ((dw)->chip->mf == EDMA_MF_EDMA_LEGACY)		       \
28*d0152168SSerge Semin 			__ch_regs = REGS_ADDR(dw, type.legacy.ch);	       \
2900498167SSerge Semin 		else if (_dir == EDMA_DIR_READ)				       \
30*d0152168SSerge Semin 			__ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].rd);     \
3100498167SSerge Semin 		else							       \
32*d0152168SSerge Semin 			__ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].wr);     \
3300498167SSerge Semin 									       \
3400498167SSerge Semin 		(void __iomem *)&__ch_regs->name;			       \
3500498167SSerge Semin 	})
3600498167SSerge Semin 
37*d0152168SSerge Semin #define REGISTER(dw, name) \
38*d0152168SSerge Semin 	{ dw, #name, REGS_ADDR(dw, name) }
39305aebefSGustavo Pimentel 
40*d0152168SSerge Semin #define CTX_REGISTER(dw, name, dir, ch) \
41*d0152168SSerge Semin 	{ dw, #name, REGS_CH_ADDR(dw, name, dir, ch), dir, ch }
4200498167SSerge Semin 
43*d0152168SSerge Semin #define WR_REGISTER(dw, name) \
44*d0152168SSerge Semin 	{ dw, #name, REGS_ADDR(dw, wr_##name) }
45*d0152168SSerge Semin #define RD_REGISTER(dw, name) \
46*d0152168SSerge Semin 	{ dw, #name, REGS_ADDR(dw, rd_##name) }
47305aebefSGustavo Pimentel 
48*d0152168SSerge Semin #define WR_REGISTER_LEGACY(dw, name) \
49*d0152168SSerge Semin 	{ dw, #name, REGS_ADDR(dw, type.legacy.wr_##name) }
50305aebefSGustavo Pimentel #define RD_REGISTER_LEGACY(name) \
51*d0152168SSerge Semin 	{ dw, #name, REGS_ADDR(dw, type.legacy.rd_##name) }
52305aebefSGustavo Pimentel 
53*d0152168SSerge Semin #define WR_REGISTER_UNROLL(dw, name) \
54*d0152168SSerge Semin 	{ dw, #name, REGS_ADDR(dw, type.unroll.wr_##name) }
55*d0152168SSerge Semin #define RD_REGISTER_UNROLL(dw, name) \
56*d0152168SSerge Semin 	{ dw, #name, REGS_ADDR(dw, type.unroll.rd_##name) }
57305aebefSGustavo Pimentel 
58305aebefSGustavo Pimentel #define WRITE_STR				"write"
59305aebefSGustavo Pimentel #define READ_STR				"read"
60305aebefSGustavo Pimentel #define CHANNEL_STR				"channel"
61305aebefSGustavo Pimentel #define REGISTERS_STR				"registers"
62305aebefSGustavo Pimentel 
63345e3a95SSerge Semin struct dw_edma_debugfs_entry {
64*d0152168SSerge Semin 	struct dw_edma				*dw;
65f0414087SArnd Bergmann 	const char				*name;
667ca9f025SSerge Semin 	void __iomem				*reg;
6700498167SSerge Semin 	enum dw_edma_dir			dir;
6800498167SSerge Semin 	u16					ch;
69305aebefSGustavo Pimentel };
70305aebefSGustavo Pimentel 
71305aebefSGustavo Pimentel static int dw_edma_debugfs_u32_get(void *data, u64 *val)
72305aebefSGustavo Pimentel {
73782536aaSSerge Semin 	struct dw_edma_debugfs_entry *entry = data;
74*d0152168SSerge Semin 	struct dw_edma *dw = entry->dw;
75782536aaSSerge Semin 	void __iomem *reg = entry->reg;
767ca9f025SSerge Semin 
7720318457SFrank Li 	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
78*d0152168SSerge Semin 	    reg >= REGS_ADDR(dw, type.legacy.ch)) {
79305aebefSGustavo Pimentel 		unsigned long flags;
8000498167SSerge Semin 		u32 viewport_sel;
81305aebefSGustavo Pimentel 
8200498167SSerge Semin 		viewport_sel = entry->dir == EDMA_DIR_READ ? BIT(31) : 0;
8300498167SSerge Semin 		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, entry->ch);
84305aebefSGustavo Pimentel 
85305aebefSGustavo Pimentel 		raw_spin_lock_irqsave(&dw->lock, flags);
86305aebefSGustavo Pimentel 
87*d0152168SSerge Semin 		writel(viewport_sel, REGS_ADDR(dw, type.legacy.viewport_sel));
8800498167SSerge Semin 		*val = readl(reg);
89305aebefSGustavo Pimentel 
90305aebefSGustavo Pimentel 		raw_spin_unlock_irqrestore(&dw->lock, flags);
91305aebefSGustavo Pimentel 	} else {
92756c3ef9SArnd Bergmann 		*val = readl(reg);
93305aebefSGustavo Pimentel 	}
94305aebefSGustavo Pimentel 
95305aebefSGustavo Pimentel 	return 0;
96305aebefSGustavo Pimentel }
97305aebefSGustavo Pimentel DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
98305aebefSGustavo Pimentel 
99*d0152168SSerge Semin static void dw_edma_debugfs_create_x32(struct dw_edma *dw,
100*d0152168SSerge Semin 				       const struct dw_edma_debugfs_entry ini[],
10195c55b78SSerge Semin 				       int nr_entries, struct dentry *dent)
102305aebefSGustavo Pimentel {
103782536aaSSerge Semin 	struct dw_edma_debugfs_entry *entries;
104305aebefSGustavo Pimentel 	int i;
105305aebefSGustavo Pimentel 
106782536aaSSerge Semin 	entries = devm_kcalloc(dw->chip->dev, nr_entries, sizeof(*entries),
107782536aaSSerge Semin 			       GFP_KERNEL);
108782536aaSSerge Semin 	if (!entries)
109782536aaSSerge Semin 		return;
110782536aaSSerge Semin 
111305aebefSGustavo Pimentel 	for (i = 0; i < nr_entries; i++) {
112782536aaSSerge Semin 		entries[i] = ini[i];
113782536aaSSerge Semin 
11495c55b78SSerge Semin 		debugfs_create_file_unsafe(entries[i].name, 0444, dent,
115782536aaSSerge Semin 					   &entries[i], &fops_x32);
116305aebefSGustavo Pimentel 	}
117305aebefSGustavo Pimentel }
118305aebefSGustavo Pimentel 
119*d0152168SSerge Semin static void dw_edma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir dir,
120*d0152168SSerge Semin 				    u16 ch, struct dentry *dent)
121305aebefSGustavo Pimentel {
12200498167SSerge Semin 	struct dw_edma_debugfs_entry debugfs_regs[] = {
123*d0152168SSerge Semin 		CTX_REGISTER(dw, ch_control1, dir, ch),
124*d0152168SSerge Semin 		CTX_REGISTER(dw, ch_control2, dir, ch),
125*d0152168SSerge Semin 		CTX_REGISTER(dw, transfer_size, dir, ch),
126*d0152168SSerge Semin 		CTX_REGISTER(dw, sar.lsb, dir, ch),
127*d0152168SSerge Semin 		CTX_REGISTER(dw, sar.msb, dir, ch),
128*d0152168SSerge Semin 		CTX_REGISTER(dw, dar.lsb, dir, ch),
129*d0152168SSerge Semin 		CTX_REGISTER(dw, dar.msb, dir, ch),
130*d0152168SSerge Semin 		CTX_REGISTER(dw, llp.lsb, dir, ch),
131*d0152168SSerge Semin 		CTX_REGISTER(dw, llp.msb, dir, ch),
132305aebefSGustavo Pimentel 	};
133345e3a95SSerge Semin 	int nr_entries;
134305aebefSGustavo Pimentel 
135305aebefSGustavo Pimentel 	nr_entries = ARRAY_SIZE(debugfs_regs);
136*d0152168SSerge Semin 	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, dent);
137305aebefSGustavo Pimentel }
138305aebefSGustavo Pimentel 
139*d0152168SSerge Semin static noinline_for_stack void
140*d0152168SSerge Semin dw_edma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent)
141305aebefSGustavo Pimentel {
142345e3a95SSerge Semin 	const struct dw_edma_debugfs_entry debugfs_regs[] = {
143305aebefSGustavo Pimentel 		/* eDMA global registers */
144*d0152168SSerge Semin 		WR_REGISTER(dw, engine_en),
145*d0152168SSerge Semin 		WR_REGISTER(dw, doorbell),
146*d0152168SSerge Semin 		WR_REGISTER(dw, ch_arb_weight.lsb),
147*d0152168SSerge Semin 		WR_REGISTER(dw, ch_arb_weight.msb),
148305aebefSGustavo Pimentel 		/* eDMA interrupts registers */
149*d0152168SSerge Semin 		WR_REGISTER(dw, int_status),
150*d0152168SSerge Semin 		WR_REGISTER(dw, int_mask),
151*d0152168SSerge Semin 		WR_REGISTER(dw, int_clear),
152*d0152168SSerge Semin 		WR_REGISTER(dw, err_status),
153*d0152168SSerge Semin 		WR_REGISTER(dw, done_imwr.lsb),
154*d0152168SSerge Semin 		WR_REGISTER(dw, done_imwr.msb),
155*d0152168SSerge Semin 		WR_REGISTER(dw, abort_imwr.lsb),
156*d0152168SSerge Semin 		WR_REGISTER(dw, abort_imwr.msb),
157*d0152168SSerge Semin 		WR_REGISTER(dw, ch01_imwr_data),
158*d0152168SSerge Semin 		WR_REGISTER(dw, ch23_imwr_data),
159*d0152168SSerge Semin 		WR_REGISTER(dw, ch45_imwr_data),
160*d0152168SSerge Semin 		WR_REGISTER(dw, ch67_imwr_data),
161*d0152168SSerge Semin 		WR_REGISTER(dw, linked_list_err_en),
162305aebefSGustavo Pimentel 	};
163345e3a95SSerge Semin 	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
164305aebefSGustavo Pimentel 		/* eDMA channel context grouping */
165*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, engine_chgroup),
166*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),
167*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),
168*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, ch0_pwr_en),
169*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, ch1_pwr_en),
170*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, ch2_pwr_en),
171*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, ch3_pwr_en),
172*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, ch4_pwr_en),
173*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, ch5_pwr_en),
174*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, ch6_pwr_en),
175*d0152168SSerge Semin 		WR_REGISTER_UNROLL(dw, ch7_pwr_en),
176305aebefSGustavo Pimentel 	};
17795c55b78SSerge Semin 	struct dentry *regs_dent, *ch_dent;
178305aebefSGustavo Pimentel 	int nr_entries, i;
179305aebefSGustavo Pimentel 	char name[16];
180305aebefSGustavo Pimentel 
18195c55b78SSerge Semin 	regs_dent = debugfs_create_dir(WRITE_STR, dent);
182305aebefSGustavo Pimentel 
183305aebefSGustavo Pimentel 	nr_entries = ARRAY_SIZE(debugfs_regs);
184*d0152168SSerge Semin 	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dent);
185305aebefSGustavo Pimentel 
18620318457SFrank Li 	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
187305aebefSGustavo Pimentel 		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
188*d0152168SSerge Semin 		dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,
18995c55b78SSerge Semin 					   regs_dent);
190305aebefSGustavo Pimentel 	}
191305aebefSGustavo Pimentel 
192305aebefSGustavo Pimentel 	for (i = 0; i < dw->wr_ch_cnt; i++) {
193305aebefSGustavo Pimentel 		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
194305aebefSGustavo Pimentel 
19595c55b78SSerge Semin 		ch_dent = debugfs_create_dir(name, regs_dent);
196305aebefSGustavo Pimentel 
197*d0152168SSerge Semin 		dw_edma_debugfs_regs_ch(dw, EDMA_DIR_WRITE, i, ch_dent);
198305aebefSGustavo Pimentel 	}
199305aebefSGustavo Pimentel }
200305aebefSGustavo Pimentel 
201*d0152168SSerge Semin static noinline_for_stack void dw_edma_debugfs_regs_rd(struct dw_edma *dw,
202*d0152168SSerge Semin 						       struct dentry *dent)
203305aebefSGustavo Pimentel {
204345e3a95SSerge Semin 	const struct dw_edma_debugfs_entry debugfs_regs[] = {
205305aebefSGustavo Pimentel 		/* eDMA global registers */
206*d0152168SSerge Semin 		RD_REGISTER(dw, engine_en),
207*d0152168SSerge Semin 		RD_REGISTER(dw, doorbell),
208*d0152168SSerge Semin 		RD_REGISTER(dw, ch_arb_weight.lsb),
209*d0152168SSerge Semin 		RD_REGISTER(dw, ch_arb_weight.msb),
210305aebefSGustavo Pimentel 		/* eDMA interrupts registers */
211*d0152168SSerge Semin 		RD_REGISTER(dw, int_status),
212*d0152168SSerge Semin 		RD_REGISTER(dw, int_mask),
213*d0152168SSerge Semin 		RD_REGISTER(dw, int_clear),
214*d0152168SSerge Semin 		RD_REGISTER(dw, err_status.lsb),
215*d0152168SSerge Semin 		RD_REGISTER(dw, err_status.msb),
216*d0152168SSerge Semin 		RD_REGISTER(dw, linked_list_err_en),
217*d0152168SSerge Semin 		RD_REGISTER(dw, done_imwr.lsb),
218*d0152168SSerge Semin 		RD_REGISTER(dw, done_imwr.msb),
219*d0152168SSerge Semin 		RD_REGISTER(dw, abort_imwr.lsb),
220*d0152168SSerge Semin 		RD_REGISTER(dw, abort_imwr.msb),
221*d0152168SSerge Semin 		RD_REGISTER(dw, ch01_imwr_data),
222*d0152168SSerge Semin 		RD_REGISTER(dw, ch23_imwr_data),
223*d0152168SSerge Semin 		RD_REGISTER(dw, ch45_imwr_data),
224*d0152168SSerge Semin 		RD_REGISTER(dw, ch67_imwr_data),
225305aebefSGustavo Pimentel 	};
226345e3a95SSerge Semin 	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
227305aebefSGustavo Pimentel 		/* eDMA channel context grouping */
228*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, engine_chgroup),
229*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),
230*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),
231*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, ch0_pwr_en),
232*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, ch1_pwr_en),
233*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, ch2_pwr_en),
234*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, ch3_pwr_en),
235*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, ch4_pwr_en),
236*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, ch5_pwr_en),
237*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, ch6_pwr_en),
238*d0152168SSerge Semin 		RD_REGISTER_UNROLL(dw, ch7_pwr_en),
239305aebefSGustavo Pimentel 	};
24095c55b78SSerge Semin 	struct dentry *regs_dent, *ch_dent;
241305aebefSGustavo Pimentel 	int nr_entries, i;
242305aebefSGustavo Pimentel 	char name[16];
243305aebefSGustavo Pimentel 
24495c55b78SSerge Semin 	regs_dent = debugfs_create_dir(READ_STR, dent);
245305aebefSGustavo Pimentel 
246305aebefSGustavo Pimentel 	nr_entries = ARRAY_SIZE(debugfs_regs);
247*d0152168SSerge Semin 	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dent);
248305aebefSGustavo Pimentel 
24920318457SFrank Li 	if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
250305aebefSGustavo Pimentel 		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
251*d0152168SSerge Semin 		dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,
25295c55b78SSerge Semin 					   regs_dent);
253305aebefSGustavo Pimentel 	}
254305aebefSGustavo Pimentel 
255305aebefSGustavo Pimentel 	for (i = 0; i < dw->rd_ch_cnt; i++) {
256305aebefSGustavo Pimentel 		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
257305aebefSGustavo Pimentel 
25895c55b78SSerge Semin 		ch_dent = debugfs_create_dir(name, regs_dent);
259305aebefSGustavo Pimentel 
260*d0152168SSerge Semin 		dw_edma_debugfs_regs_ch(dw, EDMA_DIR_READ, i, ch_dent);
261305aebefSGustavo Pimentel 	}
262305aebefSGustavo Pimentel }
263305aebefSGustavo Pimentel 
264*d0152168SSerge Semin static void dw_edma_debugfs_regs(struct dw_edma *dw)
265305aebefSGustavo Pimentel {
266345e3a95SSerge Semin 	const struct dw_edma_debugfs_entry debugfs_regs[] = {
267*d0152168SSerge Semin 		REGISTER(dw, ctrl_data_arb_prior),
268*d0152168SSerge Semin 		REGISTER(dw, ctrl),
269305aebefSGustavo Pimentel 	};
27095c55b78SSerge Semin 	struct dentry *regs_dent;
271305aebefSGustavo Pimentel 	int nr_entries;
272305aebefSGustavo Pimentel 
27395c55b78SSerge Semin 	regs_dent = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
274305aebefSGustavo Pimentel 
275305aebefSGustavo Pimentel 	nr_entries = ARRAY_SIZE(debugfs_regs);
276*d0152168SSerge Semin 	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dent);
277305aebefSGustavo Pimentel 
278*d0152168SSerge Semin 	dw_edma_debugfs_regs_wr(dw, regs_dent);
279*d0152168SSerge Semin 	dw_edma_debugfs_regs_rd(dw, regs_dent);
280305aebefSGustavo Pimentel }
281305aebefSGustavo Pimentel 
282*d0152168SSerge Semin void dw_edma_v0_debugfs_on(struct dw_edma *dw)
283305aebefSGustavo Pimentel {
28437d058aaSSerge Semin 	if (!debugfs_initialized())
28537d058aaSSerge Semin 		return;
28637d058aaSSerge Semin 
2875244ac2eSGustavo Pimentel 	dw->debugfs = debugfs_create_dir(dw->name, NULL);
288305aebefSGustavo Pimentel 
28920318457SFrank Li 	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
2905244ac2eSGustavo Pimentel 	debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
2915244ac2eSGustavo Pimentel 	debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
292305aebefSGustavo Pimentel 
293*d0152168SSerge Semin 	dw_edma_debugfs_regs(dw);
294305aebefSGustavo Pimentel }
295305aebefSGustavo Pimentel 
296*d0152168SSerge Semin void dw_edma_v0_debugfs_off(struct dw_edma *dw)
297305aebefSGustavo Pimentel {
2985244ac2eSGustavo Pimentel 	debugfs_remove_recursive(dw->debugfs);
2995244ac2eSGustavo Pimentel 	dw->debugfs = NULL;
300305aebefSGustavo Pimentel }
301