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