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