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
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
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 < &regs[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
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
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
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, &regval);
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 
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