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