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