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