xref: /openbmc/linux/drivers/dma/dw-edma/dw-edma-v0-debugfs.c (revision 305aebeff8795cbf03b3f117e74bb702c130ae4c)
1*305aebefSGustavo Pimentel // SPDX-License-Identifier: GPL-2.0
2*305aebefSGustavo Pimentel /*
3*305aebefSGustavo Pimentel  * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
4*305aebefSGustavo Pimentel  * Synopsys DesignWare eDMA v0 core
5*305aebefSGustavo Pimentel  *
6*305aebefSGustavo Pimentel  * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
7*305aebefSGustavo Pimentel  */
8*305aebefSGustavo Pimentel 
9*305aebefSGustavo Pimentel #include <linux/debugfs.h>
10*305aebefSGustavo Pimentel #include <linux/bitfield.h>
11*305aebefSGustavo Pimentel 
12*305aebefSGustavo Pimentel #include "dw-edma-v0-debugfs.h"
13*305aebefSGustavo Pimentel #include "dw-edma-v0-regs.h"
14*305aebefSGustavo Pimentel #include "dw-edma-core.h"
15*305aebefSGustavo Pimentel 
16*305aebefSGustavo Pimentel #define REGS_ADDR(name) \
17*305aebefSGustavo Pimentel 	((dma_addr_t *)&regs->name)
18*305aebefSGustavo Pimentel #define REGISTER(name) \
19*305aebefSGustavo Pimentel 	{ #name, REGS_ADDR(name) }
20*305aebefSGustavo Pimentel 
21*305aebefSGustavo Pimentel #define WR_REGISTER(name) \
22*305aebefSGustavo Pimentel 	{ #name, REGS_ADDR(wr_##name) }
23*305aebefSGustavo Pimentel #define RD_REGISTER(name) \
24*305aebefSGustavo Pimentel 	{ #name, REGS_ADDR(rd_##name) }
25*305aebefSGustavo Pimentel 
26*305aebefSGustavo Pimentel #define WR_REGISTER_LEGACY(name) \
27*305aebefSGustavo Pimentel 	{ #name, REGS_ADDR(type.legacy.wr_##name) }
28*305aebefSGustavo Pimentel #define RD_REGISTER_LEGACY(name) \
29*305aebefSGustavo Pimentel 	{ #name, REGS_ADDR(type.legacy.rd_##name) }
30*305aebefSGustavo Pimentel 
31*305aebefSGustavo Pimentel #define WR_REGISTER_UNROLL(name) \
32*305aebefSGustavo Pimentel 	{ #name, REGS_ADDR(type.unroll.wr_##name) }
33*305aebefSGustavo Pimentel #define RD_REGISTER_UNROLL(name) \
34*305aebefSGustavo Pimentel 	{ #name, REGS_ADDR(type.unroll.rd_##name) }
35*305aebefSGustavo Pimentel 
36*305aebefSGustavo Pimentel #define WRITE_STR				"write"
37*305aebefSGustavo Pimentel #define READ_STR				"read"
38*305aebefSGustavo Pimentel #define CHANNEL_STR				"channel"
39*305aebefSGustavo Pimentel #define REGISTERS_STR				"registers"
40*305aebefSGustavo Pimentel 
41*305aebefSGustavo Pimentel static struct dentry				*base_dir;
42*305aebefSGustavo Pimentel static struct dw_edma				*dw;
43*305aebefSGustavo Pimentel static struct dw_edma_v0_regs			*regs;
44*305aebefSGustavo Pimentel 
45*305aebefSGustavo Pimentel static struct {
46*305aebefSGustavo Pimentel 	void					*start;
47*305aebefSGustavo Pimentel 	void					*end;
48*305aebefSGustavo Pimentel } lim[2][EDMA_V0_MAX_NR_CH];
49*305aebefSGustavo Pimentel 
50*305aebefSGustavo Pimentel struct debugfs_entries {
51*305aebefSGustavo Pimentel 	char					name[24];
52*305aebefSGustavo Pimentel 	dma_addr_t				*reg;
53*305aebefSGustavo Pimentel };
54*305aebefSGustavo Pimentel 
55*305aebefSGustavo Pimentel static int dw_edma_debugfs_u32_get(void *data, u64 *val)
56*305aebefSGustavo Pimentel {
57*305aebefSGustavo Pimentel 	if (dw->mode == EDMA_MODE_LEGACY &&
58*305aebefSGustavo Pimentel 	    data >= (void *)&regs->type.legacy.ch) {
59*305aebefSGustavo Pimentel 		void *ptr = (void *)&regs->type.legacy.ch;
60*305aebefSGustavo Pimentel 		u32 viewport_sel = 0;
61*305aebefSGustavo Pimentel 		unsigned long flags;
62*305aebefSGustavo Pimentel 		u16 ch;
63*305aebefSGustavo Pimentel 
64*305aebefSGustavo Pimentel 		for (ch = 0; ch < dw->wr_ch_cnt; ch++)
65*305aebefSGustavo Pimentel 			if (lim[0][ch].start >= data && data < lim[0][ch].end) {
66*305aebefSGustavo Pimentel 				ptr += (data - lim[0][ch].start);
67*305aebefSGustavo Pimentel 				goto legacy_sel_wr;
68*305aebefSGustavo Pimentel 			}
69*305aebefSGustavo Pimentel 
70*305aebefSGustavo Pimentel 		for (ch = 0; ch < dw->rd_ch_cnt; ch++)
71*305aebefSGustavo Pimentel 			if (lim[1][ch].start >= data && data < lim[1][ch].end) {
72*305aebefSGustavo Pimentel 				ptr += (data - lim[1][ch].start);
73*305aebefSGustavo Pimentel 				goto legacy_sel_rd;
74*305aebefSGustavo Pimentel 			}
75*305aebefSGustavo Pimentel 
76*305aebefSGustavo Pimentel 		return 0;
77*305aebefSGustavo Pimentel legacy_sel_rd:
78*305aebefSGustavo Pimentel 		viewport_sel = BIT(31);
79*305aebefSGustavo Pimentel legacy_sel_wr:
80*305aebefSGustavo Pimentel 		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
81*305aebefSGustavo Pimentel 
82*305aebefSGustavo Pimentel 		raw_spin_lock_irqsave(&dw->lock, flags);
83*305aebefSGustavo Pimentel 
84*305aebefSGustavo Pimentel 		writel(viewport_sel, &regs->type.legacy.viewport_sel);
85*305aebefSGustavo Pimentel 		*val = readl(ptr);
86*305aebefSGustavo Pimentel 
87*305aebefSGustavo Pimentel 		raw_spin_unlock_irqrestore(&dw->lock, flags);
88*305aebefSGustavo Pimentel 	} else {
89*305aebefSGustavo Pimentel 		*val = readl(data);
90*305aebefSGustavo Pimentel 	}
91*305aebefSGustavo Pimentel 
92*305aebefSGustavo Pimentel 	return 0;
93*305aebefSGustavo Pimentel }
94*305aebefSGustavo Pimentel DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
95*305aebefSGustavo Pimentel 
96*305aebefSGustavo Pimentel static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
97*305aebefSGustavo Pimentel 				       int nr_entries, struct dentry *dir)
98*305aebefSGustavo Pimentel {
99*305aebefSGustavo Pimentel 	int i;
100*305aebefSGustavo Pimentel 
101*305aebefSGustavo Pimentel 	for (i = 0; i < nr_entries; i++) {
102*305aebefSGustavo Pimentel 		if (!debugfs_create_file_unsafe(entries[i].name, 0444, dir,
103*305aebefSGustavo Pimentel 						entries[i].reg,	&fops_x32))
104*305aebefSGustavo Pimentel 			break;
105*305aebefSGustavo Pimentel 	}
106*305aebefSGustavo Pimentel }
107*305aebefSGustavo Pimentel 
108*305aebefSGustavo Pimentel static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs *regs,
109*305aebefSGustavo Pimentel 				    struct dentry *dir)
110*305aebefSGustavo Pimentel {
111*305aebefSGustavo Pimentel 	int nr_entries;
112*305aebefSGustavo Pimentel 	const struct debugfs_entries debugfs_regs[] = {
113*305aebefSGustavo Pimentel 		REGISTER(ch_control1),
114*305aebefSGustavo Pimentel 		REGISTER(ch_control2),
115*305aebefSGustavo Pimentel 		REGISTER(transfer_size),
116*305aebefSGustavo Pimentel 		REGISTER(sar_low),
117*305aebefSGustavo Pimentel 		REGISTER(sar_high),
118*305aebefSGustavo Pimentel 		REGISTER(dar_low),
119*305aebefSGustavo Pimentel 		REGISTER(dar_high),
120*305aebefSGustavo Pimentel 		REGISTER(llp_low),
121*305aebefSGustavo Pimentel 		REGISTER(llp_high),
122*305aebefSGustavo Pimentel 	};
123*305aebefSGustavo Pimentel 
124*305aebefSGustavo Pimentel 	nr_entries = ARRAY_SIZE(debugfs_regs);
125*305aebefSGustavo Pimentel 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
126*305aebefSGustavo Pimentel }
127*305aebefSGustavo Pimentel 
128*305aebefSGustavo Pimentel static void dw_edma_debugfs_regs_wr(struct dentry *dir)
129*305aebefSGustavo Pimentel {
130*305aebefSGustavo Pimentel 	const struct debugfs_entries debugfs_regs[] = {
131*305aebefSGustavo Pimentel 		/* eDMA global registers */
132*305aebefSGustavo Pimentel 		WR_REGISTER(engine_en),
133*305aebefSGustavo Pimentel 		WR_REGISTER(doorbell),
134*305aebefSGustavo Pimentel 		WR_REGISTER(ch_arb_weight_low),
135*305aebefSGustavo Pimentel 		WR_REGISTER(ch_arb_weight_high),
136*305aebefSGustavo Pimentel 		/* eDMA interrupts registers */
137*305aebefSGustavo Pimentel 		WR_REGISTER(int_status),
138*305aebefSGustavo Pimentel 		WR_REGISTER(int_mask),
139*305aebefSGustavo Pimentel 		WR_REGISTER(int_clear),
140*305aebefSGustavo Pimentel 		WR_REGISTER(err_status),
141*305aebefSGustavo Pimentel 		WR_REGISTER(done_imwr_low),
142*305aebefSGustavo Pimentel 		WR_REGISTER(done_imwr_high),
143*305aebefSGustavo Pimentel 		WR_REGISTER(abort_imwr_low),
144*305aebefSGustavo Pimentel 		WR_REGISTER(abort_imwr_high),
145*305aebefSGustavo Pimentel 		WR_REGISTER(ch01_imwr_data),
146*305aebefSGustavo Pimentel 		WR_REGISTER(ch23_imwr_data),
147*305aebefSGustavo Pimentel 		WR_REGISTER(ch45_imwr_data),
148*305aebefSGustavo Pimentel 		WR_REGISTER(ch67_imwr_data),
149*305aebefSGustavo Pimentel 		WR_REGISTER(linked_list_err_en),
150*305aebefSGustavo Pimentel 	};
151*305aebefSGustavo Pimentel 	const struct debugfs_entries debugfs_unroll_regs[] = {
152*305aebefSGustavo Pimentel 		/* eDMA channel context grouping */
153*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(engine_chgroup),
154*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(engine_hshake_cnt_low),
155*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(engine_hshake_cnt_high),
156*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(ch0_pwr_en),
157*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(ch1_pwr_en),
158*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(ch2_pwr_en),
159*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(ch3_pwr_en),
160*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(ch4_pwr_en),
161*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(ch5_pwr_en),
162*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(ch6_pwr_en),
163*305aebefSGustavo Pimentel 		WR_REGISTER_UNROLL(ch7_pwr_en),
164*305aebefSGustavo Pimentel 	};
165*305aebefSGustavo Pimentel 	struct dentry *regs_dir, *ch_dir;
166*305aebefSGustavo Pimentel 	int nr_entries, i;
167*305aebefSGustavo Pimentel 	char name[16];
168*305aebefSGustavo Pimentel 
169*305aebefSGustavo Pimentel 	regs_dir = debugfs_create_dir(WRITE_STR, dir);
170*305aebefSGustavo Pimentel 	if (!regs_dir)
171*305aebefSGustavo Pimentel 		return;
172*305aebefSGustavo Pimentel 
173*305aebefSGustavo Pimentel 	nr_entries = ARRAY_SIZE(debugfs_regs);
174*305aebefSGustavo Pimentel 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
175*305aebefSGustavo Pimentel 
176*305aebefSGustavo Pimentel 	if (dw->mode == EDMA_MODE_UNROLL) {
177*305aebefSGustavo Pimentel 		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
178*305aebefSGustavo Pimentel 		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
179*305aebefSGustavo Pimentel 					   regs_dir);
180*305aebefSGustavo Pimentel 	}
181*305aebefSGustavo Pimentel 
182*305aebefSGustavo Pimentel 	for (i = 0; i < dw->wr_ch_cnt; i++) {
183*305aebefSGustavo Pimentel 		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
184*305aebefSGustavo Pimentel 
185*305aebefSGustavo Pimentel 		ch_dir = debugfs_create_dir(name, regs_dir);
186*305aebefSGustavo Pimentel 		if (!ch_dir)
187*305aebefSGustavo Pimentel 			return;
188*305aebefSGustavo Pimentel 
189*305aebefSGustavo Pimentel 		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
190*305aebefSGustavo Pimentel 
191*305aebefSGustavo Pimentel 		lim[0][i].start = &regs->type.unroll.ch[i].wr;
192*305aebefSGustavo Pimentel 		lim[0][i].end = &regs->type.unroll.ch[i].padding_1[0];
193*305aebefSGustavo Pimentel 	}
194*305aebefSGustavo Pimentel }
195*305aebefSGustavo Pimentel 
196*305aebefSGustavo Pimentel static void dw_edma_debugfs_regs_rd(struct dentry *dir)
197*305aebefSGustavo Pimentel {
198*305aebefSGustavo Pimentel 	const struct debugfs_entries debugfs_regs[] = {
199*305aebefSGustavo Pimentel 		/* eDMA global registers */
200*305aebefSGustavo Pimentel 		RD_REGISTER(engine_en),
201*305aebefSGustavo Pimentel 		RD_REGISTER(doorbell),
202*305aebefSGustavo Pimentel 		RD_REGISTER(ch_arb_weight_low),
203*305aebefSGustavo Pimentel 		RD_REGISTER(ch_arb_weight_high),
204*305aebefSGustavo Pimentel 		/* eDMA interrupts registers */
205*305aebefSGustavo Pimentel 		RD_REGISTER(int_status),
206*305aebefSGustavo Pimentel 		RD_REGISTER(int_mask),
207*305aebefSGustavo Pimentel 		RD_REGISTER(int_clear),
208*305aebefSGustavo Pimentel 		RD_REGISTER(err_status_low),
209*305aebefSGustavo Pimentel 		RD_REGISTER(err_status_high),
210*305aebefSGustavo Pimentel 		RD_REGISTER(linked_list_err_en),
211*305aebefSGustavo Pimentel 		RD_REGISTER(done_imwr_low),
212*305aebefSGustavo Pimentel 		RD_REGISTER(done_imwr_high),
213*305aebefSGustavo Pimentel 		RD_REGISTER(abort_imwr_low),
214*305aebefSGustavo Pimentel 		RD_REGISTER(abort_imwr_high),
215*305aebefSGustavo Pimentel 		RD_REGISTER(ch01_imwr_data),
216*305aebefSGustavo Pimentel 		RD_REGISTER(ch23_imwr_data),
217*305aebefSGustavo Pimentel 		RD_REGISTER(ch45_imwr_data),
218*305aebefSGustavo Pimentel 		RD_REGISTER(ch67_imwr_data),
219*305aebefSGustavo Pimentel 	};
220*305aebefSGustavo Pimentel 	const struct debugfs_entries debugfs_unroll_regs[] = {
221*305aebefSGustavo Pimentel 		/* eDMA channel context grouping */
222*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(engine_chgroup),
223*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(engine_hshake_cnt_low),
224*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(engine_hshake_cnt_high),
225*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(ch0_pwr_en),
226*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(ch1_pwr_en),
227*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(ch2_pwr_en),
228*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(ch3_pwr_en),
229*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(ch4_pwr_en),
230*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(ch5_pwr_en),
231*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(ch6_pwr_en),
232*305aebefSGustavo Pimentel 		RD_REGISTER_UNROLL(ch7_pwr_en),
233*305aebefSGustavo Pimentel 	};
234*305aebefSGustavo Pimentel 	struct dentry *regs_dir, *ch_dir;
235*305aebefSGustavo Pimentel 	int nr_entries, i;
236*305aebefSGustavo Pimentel 	char name[16];
237*305aebefSGustavo Pimentel 
238*305aebefSGustavo Pimentel 	regs_dir = debugfs_create_dir(READ_STR, dir);
239*305aebefSGustavo Pimentel 	if (!regs_dir)
240*305aebefSGustavo Pimentel 		return;
241*305aebefSGustavo Pimentel 
242*305aebefSGustavo Pimentel 	nr_entries = ARRAY_SIZE(debugfs_regs);
243*305aebefSGustavo Pimentel 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
244*305aebefSGustavo Pimentel 
245*305aebefSGustavo Pimentel 	if (dw->mode == EDMA_MODE_UNROLL) {
246*305aebefSGustavo Pimentel 		nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
247*305aebefSGustavo Pimentel 		dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
248*305aebefSGustavo Pimentel 					   regs_dir);
249*305aebefSGustavo Pimentel 	}
250*305aebefSGustavo Pimentel 
251*305aebefSGustavo Pimentel 	for (i = 0; i < dw->rd_ch_cnt; i++) {
252*305aebefSGustavo Pimentel 		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
253*305aebefSGustavo Pimentel 
254*305aebefSGustavo Pimentel 		ch_dir = debugfs_create_dir(name, regs_dir);
255*305aebefSGustavo Pimentel 		if (!ch_dir)
256*305aebefSGustavo Pimentel 			return;
257*305aebefSGustavo Pimentel 
258*305aebefSGustavo Pimentel 		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
259*305aebefSGustavo Pimentel 
260*305aebefSGustavo Pimentel 		lim[1][i].start = &regs->type.unroll.ch[i].rd;
261*305aebefSGustavo Pimentel 		lim[1][i].end = &regs->type.unroll.ch[i].padding_2[0];
262*305aebefSGustavo Pimentel 	}
263*305aebefSGustavo Pimentel }
264*305aebefSGustavo Pimentel 
265*305aebefSGustavo Pimentel static void dw_edma_debugfs_regs(void)
266*305aebefSGustavo Pimentel {
267*305aebefSGustavo Pimentel 	const struct debugfs_entries debugfs_regs[] = {
268*305aebefSGustavo Pimentel 		REGISTER(ctrl_data_arb_prior),
269*305aebefSGustavo Pimentel 		REGISTER(ctrl),
270*305aebefSGustavo Pimentel 	};
271*305aebefSGustavo Pimentel 	struct dentry *regs_dir;
272*305aebefSGustavo Pimentel 	int nr_entries;
273*305aebefSGustavo Pimentel 
274*305aebefSGustavo Pimentel 	regs_dir = debugfs_create_dir(REGISTERS_STR, base_dir);
275*305aebefSGustavo Pimentel 	if (!regs_dir)
276*305aebefSGustavo Pimentel 		return;
277*305aebefSGustavo Pimentel 
278*305aebefSGustavo Pimentel 	nr_entries = ARRAY_SIZE(debugfs_regs);
279*305aebefSGustavo Pimentel 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
280*305aebefSGustavo Pimentel 
281*305aebefSGustavo Pimentel 	dw_edma_debugfs_regs_wr(regs_dir);
282*305aebefSGustavo Pimentel 	dw_edma_debugfs_regs_rd(regs_dir);
283*305aebefSGustavo Pimentel }
284*305aebefSGustavo Pimentel 
285*305aebefSGustavo Pimentel void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
286*305aebefSGustavo Pimentel {
287*305aebefSGustavo Pimentel 	dw = chip->dw;
288*305aebefSGustavo Pimentel 	if (!dw)
289*305aebefSGustavo Pimentel 		return;
290*305aebefSGustavo Pimentel 
291*305aebefSGustavo Pimentel 	regs = (struct dw_edma_v0_regs *)dw->rg_region.vaddr;
292*305aebefSGustavo Pimentel 	if (!regs)
293*305aebefSGustavo Pimentel 		return;
294*305aebefSGustavo Pimentel 
295*305aebefSGustavo Pimentel 	base_dir = debugfs_create_dir(dw->name, 0);
296*305aebefSGustavo Pimentel 	if (!base_dir)
297*305aebefSGustavo Pimentel 		return;
298*305aebefSGustavo Pimentel 
299*305aebefSGustavo Pimentel 	debugfs_create_u32("version", 0444, base_dir, &dw->version);
300*305aebefSGustavo Pimentel 	debugfs_create_u32("mode", 0444, base_dir, &dw->mode);
301*305aebefSGustavo Pimentel 	debugfs_create_u16("wr_ch_cnt", 0444, base_dir, &dw->wr_ch_cnt);
302*305aebefSGustavo Pimentel 	debugfs_create_u16("rd_ch_cnt", 0444, base_dir, &dw->rd_ch_cnt);
303*305aebefSGustavo Pimentel 
304*305aebefSGustavo Pimentel 	dw_edma_debugfs_regs();
305*305aebefSGustavo Pimentel }
306*305aebefSGustavo Pimentel 
307*305aebefSGustavo Pimentel void dw_edma_v0_debugfs_off(void)
308*305aebefSGustavo Pimentel {
309*305aebefSGustavo Pimentel 	debugfs_remove_recursive(base_dir);
310*305aebefSGustavo Pimentel }
311