1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
3
4 #include <linux/seq_file.h>
5 #include "mtk_wed.h"
6 #include "mtk_wed_regs.h"
7
8 struct reg_dump {
9 const char *name;
10 u16 offset;
11 u8 type;
12 u8 base;
13 };
14
15 enum {
16 DUMP_TYPE_STRING,
17 DUMP_TYPE_WED,
18 DUMP_TYPE_WDMA,
19 DUMP_TYPE_WPDMA_TX,
20 DUMP_TYPE_WPDMA_TXFREE,
21 };
22
23 #define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING }
24 #define DUMP_REG(_reg, ...) { #_reg, MTK_##_reg, __VA_ARGS__ }
25 #define DUMP_RING(_prefix, _base, ...) \
26 { _prefix " BASE", _base, __VA_ARGS__ }, \
27 { _prefix " CNT", _base + 0x4, __VA_ARGS__ }, \
28 { _prefix " CIDX", _base + 0x8, __VA_ARGS__ }, \
29 { _prefix " DIDX", _base + 0xc, __VA_ARGS__ }
30
31 #define DUMP_WED(_reg) DUMP_REG(_reg, DUMP_TYPE_WED)
32 #define DUMP_WED_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WED)
33
34 #define DUMP_WDMA(_reg) DUMP_REG(_reg, DUMP_TYPE_WDMA)
35 #define DUMP_WDMA_RING(_base) DUMP_RING(#_base, MTK_##_base, DUMP_TYPE_WDMA)
36
37 #define DUMP_WPDMA_TX_RING(_n) DUMP_RING("WPDMA_TX" #_n, 0, DUMP_TYPE_WPDMA_TX, _n)
38 #define DUMP_WPDMA_TXFREE_RING DUMP_RING("WPDMA_RX1", 0, DUMP_TYPE_WPDMA_TXFREE)
39
40 static void
print_reg_val(struct seq_file * s,const char * name,u32 val)41 print_reg_val(struct seq_file *s, const char *name, u32 val)
42 {
43 seq_printf(s, "%-32s %08x\n", name, val);
44 }
45
46 static void
dump_wed_regs(struct seq_file * s,struct mtk_wed_device * dev,const struct reg_dump * regs,int n_regs)47 dump_wed_regs(struct seq_file *s, struct mtk_wed_device *dev,
48 const struct reg_dump *regs, int n_regs)
49 {
50 const struct reg_dump *cur;
51 u32 val;
52
53 for (cur = regs; cur < ®s[n_regs]; cur++) {
54 switch (cur->type) {
55 case DUMP_TYPE_STRING:
56 seq_printf(s, "%s======== %s:\n",
57 cur > regs ? "\n" : "",
58 cur->name);
59 continue;
60 case DUMP_TYPE_WED:
61 val = wed_r32(dev, cur->offset);
62 break;
63 case DUMP_TYPE_WDMA:
64 val = wdma_r32(dev, cur->offset);
65 break;
66 case DUMP_TYPE_WPDMA_TX:
67 val = wpdma_tx_r32(dev, cur->base, cur->offset);
68 break;
69 case DUMP_TYPE_WPDMA_TXFREE:
70 val = wpdma_txfree_r32(dev, cur->offset);
71 break;
72 }
73 print_reg_val(s, cur->name, val);
74 }
75 }
76
77
78 static int
wed_txinfo_show(struct seq_file * s,void * data)79 wed_txinfo_show(struct seq_file *s, void *data)
80 {
81 static const struct reg_dump regs[] = {
82 DUMP_STR("WED TX"),
83 DUMP_WED(WED_TX_MIB(0)),
84 DUMP_WED_RING(WED_RING_TX(0)),
85
86 DUMP_WED(WED_TX_MIB(1)),
87 DUMP_WED_RING(WED_RING_TX(1)),
88
89 DUMP_STR("WPDMA TX"),
90 DUMP_WED(WED_WPDMA_TX_MIB(0)),
91 DUMP_WED_RING(WED_WPDMA_RING_TX(0)),
92 DUMP_WED(WED_WPDMA_TX_COHERENT_MIB(0)),
93
94 DUMP_WED(WED_WPDMA_TX_MIB(1)),
95 DUMP_WED_RING(WED_WPDMA_RING_TX(1)),
96 DUMP_WED(WED_WPDMA_TX_COHERENT_MIB(1)),
97
98 DUMP_STR("WPDMA TX"),
99 DUMP_WPDMA_TX_RING(0),
100 DUMP_WPDMA_TX_RING(1),
101
102 DUMP_STR("WED WDMA RX"),
103 DUMP_WED(WED_WDMA_RX_MIB(0)),
104 DUMP_WED_RING(WED_WDMA_RING_RX(0)),
105 DUMP_WED(WED_WDMA_RX_THRES(0)),
106 DUMP_WED(WED_WDMA_RX_RECYCLE_MIB(0)),
107 DUMP_WED(WED_WDMA_RX_PROCESSED_MIB(0)),
108
109 DUMP_WED(WED_WDMA_RX_MIB(1)),
110 DUMP_WED_RING(WED_WDMA_RING_RX(1)),
111 DUMP_WED(WED_WDMA_RX_THRES(1)),
112 DUMP_WED(WED_WDMA_RX_RECYCLE_MIB(1)),
113 DUMP_WED(WED_WDMA_RX_PROCESSED_MIB(1)),
114
115 DUMP_STR("WDMA RX"),
116 DUMP_WDMA(WDMA_GLO_CFG),
117 DUMP_WDMA_RING(WDMA_RING_RX(0)),
118 DUMP_WDMA_RING(WDMA_RING_RX(1)),
119
120 DUMP_STR("TX FREE"),
121 DUMP_WED(WED_RX_MIB(0)),
122 };
123 struct mtk_wed_hw *hw = s->private;
124 struct mtk_wed_device *dev = hw->wed_dev;
125
126 if (!dev)
127 return 0;
128
129 dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
130
131 return 0;
132 }
133 DEFINE_SHOW_ATTRIBUTE(wed_txinfo);
134
135
136 static int
mtk_wed_reg_set(void * data,u64 val)137 mtk_wed_reg_set(void *data, u64 val)
138 {
139 struct mtk_wed_hw *hw = data;
140
141 regmap_write(hw->regs, hw->debugfs_reg, val);
142
143 return 0;
144 }
145
146 static int
mtk_wed_reg_get(void * data,u64 * val)147 mtk_wed_reg_get(void *data, u64 *val)
148 {
149 struct mtk_wed_hw *hw = data;
150 unsigned int regval;
151 int ret;
152
153 ret = regmap_read(hw->regs, hw->debugfs_reg, ®val);
154 if (ret)
155 return ret;
156
157 *val = regval;
158
159 return 0;
160 }
161
162 DEFINE_DEBUGFS_ATTRIBUTE(fops_regval, mtk_wed_reg_get, mtk_wed_reg_set,
163 "0x%08llx\n");
164
mtk_wed_hw_add_debugfs(struct mtk_wed_hw * hw)165 void mtk_wed_hw_add_debugfs(struct mtk_wed_hw *hw)
166 {
167 struct dentry *dir;
168
169 snprintf(hw->dirname, sizeof(hw->dirname), "wed%d", hw->index);
170 dir = debugfs_create_dir(hw->dirname, NULL);
171 if (!dir)
172 return;
173
174 hw->debugfs_dir = dir;
175 debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg);
176 debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval);
177 debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops);
178 }
179