0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/debugfs.h>
0010 #include <linux/bitfield.h>
0011
0012 #include "dw-edma-v0-debugfs.h"
0013 #include "dw-edma-v0-regs.h"
0014 #include "dw-edma-core.h"
0015
0016 #define REGS_ADDR(name) \
0017 ((void __force *)®s->name)
0018 #define REGISTER(name) \
0019 { #name, REGS_ADDR(name) }
0020
0021 #define WR_REGISTER(name) \
0022 { #name, REGS_ADDR(wr_##name) }
0023 #define RD_REGISTER(name) \
0024 { #name, REGS_ADDR(rd_##name) }
0025
0026 #define WR_REGISTER_LEGACY(name) \
0027 { #name, REGS_ADDR(type.legacy.wr_##name) }
0028 #define RD_REGISTER_LEGACY(name) \
0029 { #name, REGS_ADDR(type.legacy.rd_##name) }
0030
0031 #define WR_REGISTER_UNROLL(name) \
0032 { #name, REGS_ADDR(type.unroll.wr_##name) }
0033 #define RD_REGISTER_UNROLL(name) \
0034 { #name, REGS_ADDR(type.unroll.rd_##name) }
0035
0036 #define WRITE_STR "write"
0037 #define READ_STR "read"
0038 #define CHANNEL_STR "channel"
0039 #define REGISTERS_STR "registers"
0040
0041 static struct dw_edma *dw;
0042 static struct dw_edma_v0_regs __iomem *regs;
0043
0044 static struct {
0045 void __iomem *start;
0046 void __iomem *end;
0047 } lim[2][EDMA_V0_MAX_NR_CH];
0048
0049 struct debugfs_entries {
0050 const char *name;
0051 dma_addr_t *reg;
0052 };
0053
0054 static int dw_edma_debugfs_u32_get(void *data, u64 *val)
0055 {
0056 void __iomem *reg = (void __force __iomem *)data;
0057 if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
0058 reg >= (void __iomem *)®s->type.legacy.ch) {
0059 void __iomem *ptr = ®s->type.legacy.ch;
0060 u32 viewport_sel = 0;
0061 unsigned long flags;
0062 u16 ch;
0063
0064 for (ch = 0; ch < dw->wr_ch_cnt; ch++)
0065 if (lim[0][ch].start >= reg && reg < lim[0][ch].end) {
0066 ptr += (reg - lim[0][ch].start);
0067 goto legacy_sel_wr;
0068 }
0069
0070 for (ch = 0; ch < dw->rd_ch_cnt; ch++)
0071 if (lim[1][ch].start >= reg && reg < lim[1][ch].end) {
0072 ptr += (reg - lim[1][ch].start);
0073 goto legacy_sel_rd;
0074 }
0075
0076 return 0;
0077 legacy_sel_rd:
0078 viewport_sel = BIT(31);
0079 legacy_sel_wr:
0080 viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
0081
0082 raw_spin_lock_irqsave(&dw->lock, flags);
0083
0084 writel(viewport_sel, ®s->type.legacy.viewport_sel);
0085 *val = readl(ptr);
0086
0087 raw_spin_unlock_irqrestore(&dw->lock, flags);
0088 } else {
0089 *val = readl(reg);
0090 }
0091
0092 return 0;
0093 }
0094 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
0095
0096 static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
0097 int nr_entries, struct dentry *dir)
0098 {
0099 int i;
0100
0101 for (i = 0; i < nr_entries; i++) {
0102 if (!debugfs_create_file_unsafe(entries[i].name, 0444, dir,
0103 entries[i].reg, &fops_x32))
0104 break;
0105 }
0106 }
0107
0108 static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
0109 struct dentry *dir)
0110 {
0111 int nr_entries;
0112 const struct debugfs_entries debugfs_regs[] = {
0113 REGISTER(ch_control1),
0114 REGISTER(ch_control2),
0115 REGISTER(transfer_size),
0116 REGISTER(sar.lsb),
0117 REGISTER(sar.msb),
0118 REGISTER(dar.lsb),
0119 REGISTER(dar.msb),
0120 REGISTER(llp.lsb),
0121 REGISTER(llp.msb),
0122 };
0123
0124 nr_entries = ARRAY_SIZE(debugfs_regs);
0125 dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
0126 }
0127
0128 static void dw_edma_debugfs_regs_wr(struct dentry *dir)
0129 {
0130 const struct debugfs_entries debugfs_regs[] = {
0131
0132 WR_REGISTER(engine_en),
0133 WR_REGISTER(doorbell),
0134 WR_REGISTER(ch_arb_weight.lsb),
0135 WR_REGISTER(ch_arb_weight.msb),
0136
0137 WR_REGISTER(int_status),
0138 WR_REGISTER(int_mask),
0139 WR_REGISTER(int_clear),
0140 WR_REGISTER(err_status),
0141 WR_REGISTER(done_imwr.lsb),
0142 WR_REGISTER(done_imwr.msb),
0143 WR_REGISTER(abort_imwr.lsb),
0144 WR_REGISTER(abort_imwr.msb),
0145 WR_REGISTER(ch01_imwr_data),
0146 WR_REGISTER(ch23_imwr_data),
0147 WR_REGISTER(ch45_imwr_data),
0148 WR_REGISTER(ch67_imwr_data),
0149 WR_REGISTER(linked_list_err_en),
0150 };
0151 const struct debugfs_entries debugfs_unroll_regs[] = {
0152
0153 WR_REGISTER_UNROLL(engine_chgroup),
0154 WR_REGISTER_UNROLL(engine_hshake_cnt.lsb),
0155 WR_REGISTER_UNROLL(engine_hshake_cnt.msb),
0156 WR_REGISTER_UNROLL(ch0_pwr_en),
0157 WR_REGISTER_UNROLL(ch1_pwr_en),
0158 WR_REGISTER_UNROLL(ch2_pwr_en),
0159 WR_REGISTER_UNROLL(ch3_pwr_en),
0160 WR_REGISTER_UNROLL(ch4_pwr_en),
0161 WR_REGISTER_UNROLL(ch5_pwr_en),
0162 WR_REGISTER_UNROLL(ch6_pwr_en),
0163 WR_REGISTER_UNROLL(ch7_pwr_en),
0164 };
0165 struct dentry *regs_dir, *ch_dir;
0166 int nr_entries, i;
0167 char name[16];
0168
0169 regs_dir = debugfs_create_dir(WRITE_STR, dir);
0170 if (!regs_dir)
0171 return;
0172
0173 nr_entries = ARRAY_SIZE(debugfs_regs);
0174 dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
0175
0176 if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
0177 nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
0178 dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
0179 regs_dir);
0180 }
0181
0182 for (i = 0; i < dw->wr_ch_cnt; i++) {
0183 snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
0184
0185 ch_dir = debugfs_create_dir(name, regs_dir);
0186 if (!ch_dir)
0187 return;
0188
0189 dw_edma_debugfs_regs_ch(®s->type.unroll.ch[i].wr, ch_dir);
0190
0191 lim[0][i].start = ®s->type.unroll.ch[i].wr;
0192 lim[0][i].end = ®s->type.unroll.ch[i].padding_1[0];
0193 }
0194 }
0195
0196 static void dw_edma_debugfs_regs_rd(struct dentry *dir)
0197 {
0198 const struct debugfs_entries debugfs_regs[] = {
0199
0200 RD_REGISTER(engine_en),
0201 RD_REGISTER(doorbell),
0202 RD_REGISTER(ch_arb_weight.lsb),
0203 RD_REGISTER(ch_arb_weight.msb),
0204
0205 RD_REGISTER(int_status),
0206 RD_REGISTER(int_mask),
0207 RD_REGISTER(int_clear),
0208 RD_REGISTER(err_status.lsb),
0209 RD_REGISTER(err_status.msb),
0210 RD_REGISTER(linked_list_err_en),
0211 RD_REGISTER(done_imwr.lsb),
0212 RD_REGISTER(done_imwr.msb),
0213 RD_REGISTER(abort_imwr.lsb),
0214 RD_REGISTER(abort_imwr.msb),
0215 RD_REGISTER(ch01_imwr_data),
0216 RD_REGISTER(ch23_imwr_data),
0217 RD_REGISTER(ch45_imwr_data),
0218 RD_REGISTER(ch67_imwr_data),
0219 };
0220 const struct debugfs_entries debugfs_unroll_regs[] = {
0221
0222 RD_REGISTER_UNROLL(engine_chgroup),
0223 RD_REGISTER_UNROLL(engine_hshake_cnt.lsb),
0224 RD_REGISTER_UNROLL(engine_hshake_cnt.msb),
0225 RD_REGISTER_UNROLL(ch0_pwr_en),
0226 RD_REGISTER_UNROLL(ch1_pwr_en),
0227 RD_REGISTER_UNROLL(ch2_pwr_en),
0228 RD_REGISTER_UNROLL(ch3_pwr_en),
0229 RD_REGISTER_UNROLL(ch4_pwr_en),
0230 RD_REGISTER_UNROLL(ch5_pwr_en),
0231 RD_REGISTER_UNROLL(ch6_pwr_en),
0232 RD_REGISTER_UNROLL(ch7_pwr_en),
0233 };
0234 struct dentry *regs_dir, *ch_dir;
0235 int nr_entries, i;
0236 char name[16];
0237
0238 regs_dir = debugfs_create_dir(READ_STR, dir);
0239 if (!regs_dir)
0240 return;
0241
0242 nr_entries = ARRAY_SIZE(debugfs_regs);
0243 dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
0244
0245 if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {
0246 nr_entries = ARRAY_SIZE(debugfs_unroll_regs);
0247 dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries,
0248 regs_dir);
0249 }
0250
0251 for (i = 0; i < dw->rd_ch_cnt; i++) {
0252 snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
0253
0254 ch_dir = debugfs_create_dir(name, regs_dir);
0255 if (!ch_dir)
0256 return;
0257
0258 dw_edma_debugfs_regs_ch(®s->type.unroll.ch[i].rd, ch_dir);
0259
0260 lim[1][i].start = ®s->type.unroll.ch[i].rd;
0261 lim[1][i].end = ®s->type.unroll.ch[i].padding_2[0];
0262 }
0263 }
0264
0265 static void dw_edma_debugfs_regs(void)
0266 {
0267 const struct debugfs_entries debugfs_regs[] = {
0268 REGISTER(ctrl_data_arb_prior),
0269 REGISTER(ctrl),
0270 };
0271 struct dentry *regs_dir;
0272 int nr_entries;
0273
0274 regs_dir = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
0275 if (!regs_dir)
0276 return;
0277
0278 nr_entries = ARRAY_SIZE(debugfs_regs);
0279 dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
0280
0281 dw_edma_debugfs_regs_wr(regs_dir);
0282 dw_edma_debugfs_regs_rd(regs_dir);
0283 }
0284
0285 void dw_edma_v0_debugfs_on(struct dw_edma *_dw)
0286 {
0287 dw = _dw;
0288 if (!dw)
0289 return;
0290
0291 regs = dw->chip->reg_base;
0292 if (!regs)
0293 return;
0294
0295 dw->debugfs = debugfs_create_dir(dw->name, NULL);
0296 if (!dw->debugfs)
0297 return;
0298
0299 debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
0300 debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
0301 debugfs_create_u16("rd_ch_cnt", 0444, dw->debugfs, &dw->rd_ch_cnt);
0302
0303 dw_edma_debugfs_regs();
0304 }
0305
0306 void dw_edma_v0_debugfs_off(struct dw_edma *_dw)
0307 {
0308 dw = _dw;
0309 if (!dw)
0310 return;
0311
0312 debugfs_remove_recursive(dw->debugfs);
0313 dw->debugfs = NULL;
0314 }