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