Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
26282 views
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 <[email protected]>
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
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
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
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
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
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
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
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
294