18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates. 48c2ecf20Sopenharmony_ci * Synopsys DesignWare eDMA v0 core 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 108c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "dw-edma-v0-debugfs.h" 138c2ecf20Sopenharmony_ci#include "dw-edma-v0-regs.h" 148c2ecf20Sopenharmony_ci#include "dw-edma-core.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define REGS_ADDR(name) \ 178c2ecf20Sopenharmony_ci ((void __force *)®s->name) 188c2ecf20Sopenharmony_ci#define REGISTER(name) \ 198c2ecf20Sopenharmony_ci { #name, REGS_ADDR(name) } 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define WR_REGISTER(name) \ 228c2ecf20Sopenharmony_ci { #name, REGS_ADDR(wr_##name) } 238c2ecf20Sopenharmony_ci#define RD_REGISTER(name) \ 248c2ecf20Sopenharmony_ci { #name, REGS_ADDR(rd_##name) } 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define WR_REGISTER_LEGACY(name) \ 278c2ecf20Sopenharmony_ci { #name, REGS_ADDR(type.legacy.wr_##name) } 288c2ecf20Sopenharmony_ci#define RD_REGISTER_LEGACY(name) \ 298c2ecf20Sopenharmony_ci { #name, REGS_ADDR(type.legacy.rd_##name) } 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define WR_REGISTER_UNROLL(name) \ 328c2ecf20Sopenharmony_ci { #name, REGS_ADDR(type.unroll.wr_##name) } 338c2ecf20Sopenharmony_ci#define RD_REGISTER_UNROLL(name) \ 348c2ecf20Sopenharmony_ci { #name, REGS_ADDR(type.unroll.rd_##name) } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define WRITE_STR "write" 378c2ecf20Sopenharmony_ci#define READ_STR "read" 388c2ecf20Sopenharmony_ci#define CHANNEL_STR "channel" 398c2ecf20Sopenharmony_ci#define REGISTERS_STR "registers" 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic struct dentry *base_dir; 428c2ecf20Sopenharmony_cistatic struct dw_edma *dw; 438c2ecf20Sopenharmony_cistatic struct dw_edma_v0_regs __iomem *regs; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic struct { 468c2ecf20Sopenharmony_ci void __iomem *start; 478c2ecf20Sopenharmony_ci void __iomem *end; 488c2ecf20Sopenharmony_ci} lim[2][EDMA_V0_MAX_NR_CH]; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct debugfs_entries { 518c2ecf20Sopenharmony_ci const char *name; 528c2ecf20Sopenharmony_ci dma_addr_t *reg; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int dw_edma_debugfs_u32_get(void *data, u64 *val) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci void __iomem *reg = (void __force __iomem *)data; 588c2ecf20Sopenharmony_ci if (dw->mode == EDMA_MODE_LEGACY && 598c2ecf20Sopenharmony_ci reg >= (void __iomem *)®s->type.legacy.ch) { 608c2ecf20Sopenharmony_ci void __iomem *ptr = ®s->type.legacy.ch; 618c2ecf20Sopenharmony_ci u32 viewport_sel = 0; 628c2ecf20Sopenharmony_ci unsigned long flags; 638c2ecf20Sopenharmony_ci u16 ch; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci for (ch = 0; ch < dw->wr_ch_cnt; ch++) 668c2ecf20Sopenharmony_ci if (lim[0][ch].start >= reg && reg < lim[0][ch].end) { 678c2ecf20Sopenharmony_ci ptr += (reg - lim[0][ch].start); 688c2ecf20Sopenharmony_ci goto legacy_sel_wr; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci for (ch = 0; ch < dw->rd_ch_cnt; ch++) 728c2ecf20Sopenharmony_ci if (lim[1][ch].start >= reg && reg < lim[1][ch].end) { 738c2ecf20Sopenharmony_ci ptr += (reg - lim[1][ch].start); 748c2ecf20Sopenharmony_ci goto legacy_sel_rd; 758c2ecf20Sopenharmony_ci } 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return 0; 788c2ecf20Sopenharmony_cilegacy_sel_rd: 798c2ecf20Sopenharmony_ci viewport_sel = BIT(31); 808c2ecf20Sopenharmony_cilegacy_sel_wr: 818c2ecf20Sopenharmony_ci viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&dw->lock, flags); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci writel(viewport_sel, ®s->type.legacy.viewport_sel); 868c2ecf20Sopenharmony_ci *val = readl(ptr); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&dw->lock, flags); 898c2ecf20Sopenharmony_ci } else { 908c2ecf20Sopenharmony_ci *val = readl(reg); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n"); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[], 988c2ecf20Sopenharmony_ci int nr_entries, struct dentry *dir) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci int i; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci for (i = 0; i < nr_entries; i++) { 1038c2ecf20Sopenharmony_ci if (!debugfs_create_file_unsafe(entries[i].name, 0444, dir, 1048c2ecf20Sopenharmony_ci entries[i].reg, &fops_x32)) 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs, 1108c2ecf20Sopenharmony_ci struct dentry *dir) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci int nr_entries; 1138c2ecf20Sopenharmony_ci const struct debugfs_entries debugfs_regs[] = { 1148c2ecf20Sopenharmony_ci REGISTER(ch_control1), 1158c2ecf20Sopenharmony_ci REGISTER(ch_control2), 1168c2ecf20Sopenharmony_ci REGISTER(transfer_size), 1178c2ecf20Sopenharmony_ci REGISTER(sar_low), 1188c2ecf20Sopenharmony_ci REGISTER(sar_high), 1198c2ecf20Sopenharmony_ci REGISTER(dar_low), 1208c2ecf20Sopenharmony_ci REGISTER(dar_high), 1218c2ecf20Sopenharmony_ci REGISTER(llp_low), 1228c2ecf20Sopenharmony_ci REGISTER(llp_high), 1238c2ecf20Sopenharmony_ci }; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci nr_entries = ARRAY_SIZE(debugfs_regs); 1268c2ecf20Sopenharmony_ci dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir); 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void dw_edma_debugfs_regs_wr(struct dentry *dir) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci const struct debugfs_entries debugfs_regs[] = { 1328c2ecf20Sopenharmony_ci /* eDMA global registers */ 1338c2ecf20Sopenharmony_ci WR_REGISTER(engine_en), 1348c2ecf20Sopenharmony_ci WR_REGISTER(doorbell), 1358c2ecf20Sopenharmony_ci WR_REGISTER(ch_arb_weight_low), 1368c2ecf20Sopenharmony_ci WR_REGISTER(ch_arb_weight_high), 1378c2ecf20Sopenharmony_ci /* eDMA interrupts registers */ 1388c2ecf20Sopenharmony_ci WR_REGISTER(int_status), 1398c2ecf20Sopenharmony_ci WR_REGISTER(int_mask), 1408c2ecf20Sopenharmony_ci WR_REGISTER(int_clear), 1418c2ecf20Sopenharmony_ci WR_REGISTER(err_status), 1428c2ecf20Sopenharmony_ci WR_REGISTER(done_imwr_low), 1438c2ecf20Sopenharmony_ci WR_REGISTER(done_imwr_high), 1448c2ecf20Sopenharmony_ci WR_REGISTER(abort_imwr_low), 1458c2ecf20Sopenharmony_ci WR_REGISTER(abort_imwr_high), 1468c2ecf20Sopenharmony_ci WR_REGISTER(ch01_imwr_data), 1478c2ecf20Sopenharmony_ci WR_REGISTER(ch23_imwr_data), 1488c2ecf20Sopenharmony_ci WR_REGISTER(ch45_imwr_data), 1498c2ecf20Sopenharmony_ci WR_REGISTER(ch67_imwr_data), 1508c2ecf20Sopenharmony_ci WR_REGISTER(linked_list_err_en), 1518c2ecf20Sopenharmony_ci }; 1528c2ecf20Sopenharmony_ci const struct debugfs_entries debugfs_unroll_regs[] = { 1538c2ecf20Sopenharmony_ci /* eDMA channel context grouping */ 1548c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(engine_chgroup), 1558c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(engine_hshake_cnt_low), 1568c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(engine_hshake_cnt_high), 1578c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(ch0_pwr_en), 1588c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(ch1_pwr_en), 1598c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(ch2_pwr_en), 1608c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(ch3_pwr_en), 1618c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(ch4_pwr_en), 1628c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(ch5_pwr_en), 1638c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(ch6_pwr_en), 1648c2ecf20Sopenharmony_ci WR_REGISTER_UNROLL(ch7_pwr_en), 1658c2ecf20Sopenharmony_ci }; 1668c2ecf20Sopenharmony_ci struct dentry *regs_dir, *ch_dir; 1678c2ecf20Sopenharmony_ci int nr_entries, i; 1688c2ecf20Sopenharmony_ci char name[16]; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci regs_dir = debugfs_create_dir(WRITE_STR, dir); 1718c2ecf20Sopenharmony_ci if (!regs_dir) 1728c2ecf20Sopenharmony_ci return; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci nr_entries = ARRAY_SIZE(debugfs_regs); 1758c2ecf20Sopenharmony_ci dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (dw->mode == EDMA_MODE_UNROLL) { 1788c2ecf20Sopenharmony_ci nr_entries = ARRAY_SIZE(debugfs_unroll_regs); 1798c2ecf20Sopenharmony_ci dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries, 1808c2ecf20Sopenharmony_ci regs_dir); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci for (i = 0; i < dw->wr_ch_cnt; i++) { 1848c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci ch_dir = debugfs_create_dir(name, regs_dir); 1878c2ecf20Sopenharmony_ci if (!ch_dir) 1888c2ecf20Sopenharmony_ci return; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci dw_edma_debugfs_regs_ch(®s->type.unroll.ch[i].wr, ch_dir); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci lim[0][i].start = ®s->type.unroll.ch[i].wr; 1938c2ecf20Sopenharmony_ci lim[0][i].end = ®s->type.unroll.ch[i].padding_1[0]; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void dw_edma_debugfs_regs_rd(struct dentry *dir) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci const struct debugfs_entries debugfs_regs[] = { 2008c2ecf20Sopenharmony_ci /* eDMA global registers */ 2018c2ecf20Sopenharmony_ci RD_REGISTER(engine_en), 2028c2ecf20Sopenharmony_ci RD_REGISTER(doorbell), 2038c2ecf20Sopenharmony_ci RD_REGISTER(ch_arb_weight_low), 2048c2ecf20Sopenharmony_ci RD_REGISTER(ch_arb_weight_high), 2058c2ecf20Sopenharmony_ci /* eDMA interrupts registers */ 2068c2ecf20Sopenharmony_ci RD_REGISTER(int_status), 2078c2ecf20Sopenharmony_ci RD_REGISTER(int_mask), 2088c2ecf20Sopenharmony_ci RD_REGISTER(int_clear), 2098c2ecf20Sopenharmony_ci RD_REGISTER(err_status_low), 2108c2ecf20Sopenharmony_ci RD_REGISTER(err_status_high), 2118c2ecf20Sopenharmony_ci RD_REGISTER(linked_list_err_en), 2128c2ecf20Sopenharmony_ci RD_REGISTER(done_imwr_low), 2138c2ecf20Sopenharmony_ci RD_REGISTER(done_imwr_high), 2148c2ecf20Sopenharmony_ci RD_REGISTER(abort_imwr_low), 2158c2ecf20Sopenharmony_ci RD_REGISTER(abort_imwr_high), 2168c2ecf20Sopenharmony_ci RD_REGISTER(ch01_imwr_data), 2178c2ecf20Sopenharmony_ci RD_REGISTER(ch23_imwr_data), 2188c2ecf20Sopenharmony_ci RD_REGISTER(ch45_imwr_data), 2198c2ecf20Sopenharmony_ci RD_REGISTER(ch67_imwr_data), 2208c2ecf20Sopenharmony_ci }; 2218c2ecf20Sopenharmony_ci const struct debugfs_entries debugfs_unroll_regs[] = { 2228c2ecf20Sopenharmony_ci /* eDMA channel context grouping */ 2238c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(engine_chgroup), 2248c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(engine_hshake_cnt_low), 2258c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(engine_hshake_cnt_high), 2268c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(ch0_pwr_en), 2278c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(ch1_pwr_en), 2288c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(ch2_pwr_en), 2298c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(ch3_pwr_en), 2308c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(ch4_pwr_en), 2318c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(ch5_pwr_en), 2328c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(ch6_pwr_en), 2338c2ecf20Sopenharmony_ci RD_REGISTER_UNROLL(ch7_pwr_en), 2348c2ecf20Sopenharmony_ci }; 2358c2ecf20Sopenharmony_ci struct dentry *regs_dir, *ch_dir; 2368c2ecf20Sopenharmony_ci int nr_entries, i; 2378c2ecf20Sopenharmony_ci char name[16]; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci regs_dir = debugfs_create_dir(READ_STR, dir); 2408c2ecf20Sopenharmony_ci if (!regs_dir) 2418c2ecf20Sopenharmony_ci return; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci nr_entries = ARRAY_SIZE(debugfs_regs); 2448c2ecf20Sopenharmony_ci dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (dw->mode == EDMA_MODE_UNROLL) { 2478c2ecf20Sopenharmony_ci nr_entries = ARRAY_SIZE(debugfs_unroll_regs); 2488c2ecf20Sopenharmony_ci dw_edma_debugfs_create_x32(debugfs_unroll_regs, nr_entries, 2498c2ecf20Sopenharmony_ci regs_dir); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci for (i = 0; i < dw->rd_ch_cnt; i++) { 2538c2ecf20Sopenharmony_ci snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ch_dir = debugfs_create_dir(name, regs_dir); 2568c2ecf20Sopenharmony_ci if (!ch_dir) 2578c2ecf20Sopenharmony_ci return; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci dw_edma_debugfs_regs_ch(®s->type.unroll.ch[i].rd, ch_dir); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci lim[1][i].start = ®s->type.unroll.ch[i].rd; 2628c2ecf20Sopenharmony_ci lim[1][i].end = ®s->type.unroll.ch[i].padding_2[0]; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic void dw_edma_debugfs_regs(void) 2678c2ecf20Sopenharmony_ci{ 2688c2ecf20Sopenharmony_ci const struct debugfs_entries debugfs_regs[] = { 2698c2ecf20Sopenharmony_ci REGISTER(ctrl_data_arb_prior), 2708c2ecf20Sopenharmony_ci REGISTER(ctrl), 2718c2ecf20Sopenharmony_ci }; 2728c2ecf20Sopenharmony_ci struct dentry *regs_dir; 2738c2ecf20Sopenharmony_ci int nr_entries; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci regs_dir = debugfs_create_dir(REGISTERS_STR, base_dir); 2768c2ecf20Sopenharmony_ci if (!regs_dir) 2778c2ecf20Sopenharmony_ci return; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci nr_entries = ARRAY_SIZE(debugfs_regs); 2808c2ecf20Sopenharmony_ci dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci dw_edma_debugfs_regs_wr(regs_dir); 2838c2ecf20Sopenharmony_ci dw_edma_debugfs_regs_rd(regs_dir); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_civoid dw_edma_v0_debugfs_on(struct dw_edma_chip *chip) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci dw = chip->dw; 2898c2ecf20Sopenharmony_ci if (!dw) 2908c2ecf20Sopenharmony_ci return; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci regs = dw->rg_region.vaddr; 2938c2ecf20Sopenharmony_ci if (!regs) 2948c2ecf20Sopenharmony_ci return; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci base_dir = debugfs_create_dir(dw->name, NULL); 2978c2ecf20Sopenharmony_ci if (!base_dir) 2988c2ecf20Sopenharmony_ci return; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci debugfs_create_u32("version", 0444, base_dir, &dw->version); 3018c2ecf20Sopenharmony_ci debugfs_create_u32("mode", 0444, base_dir, &dw->mode); 3028c2ecf20Sopenharmony_ci debugfs_create_u16("wr_ch_cnt", 0444, base_dir, &dw->wr_ch_cnt); 3038c2ecf20Sopenharmony_ci debugfs_create_u16("rd_ch_cnt", 0444, base_dir, &dw->rd_ch_cnt); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci dw_edma_debugfs_regs(); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_civoid dw_edma_v0_debugfs_off(void) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci debugfs_remove_recursive(base_dir); 3118c2ecf20Sopenharmony_ci} 312