293 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.4 * Synopsys DesignWare eDMA v0 core5 *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(dw, name) \17 ({ \18 struct dw_edma_v0_regs __iomem *__regs = (dw)->chip->reg_base; \19 \20 (void __iomem *)&__regs->name; \21 })22 23#define REGS_CH_ADDR(dw, name, _dir, _ch) \24 ({ \25 struct dw_edma_v0_ch_regs __iomem *__ch_regs; \26 \27 if ((dw)->chip->mf == EDMA_MF_EDMA_LEGACY) \28 __ch_regs = REGS_ADDR(dw, type.legacy.ch); \29 else if (_dir == EDMA_DIR_READ) \30 __ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].rd); \31 else \32 __ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].wr); \33 \34 (void __iomem *)&__ch_regs->name; \35 })36 37#define REGISTER(dw, name) \38 { dw, #name, REGS_ADDR(dw, name) }39 40#define CTX_REGISTER(dw, name, dir, ch) \41 { dw, #name, REGS_CH_ADDR(dw, name, dir, ch), dir, ch }42 43#define WR_REGISTER(dw, name) \44 { dw, #name, REGS_ADDR(dw, wr_##name) }45#define RD_REGISTER(dw, name) \46 { dw, #name, REGS_ADDR(dw, rd_##name) }47 48#define WR_REGISTER_LEGACY(dw, name) \49 { dw, #name, REGS_ADDR(dw, type.legacy.wr_##name) }50#define RD_REGISTER_LEGACY(name) \51 { dw, #name, REGS_ADDR(dw, type.legacy.rd_##name) }52 53#define WR_REGISTER_UNROLL(dw, name) \54 { dw, #name, REGS_ADDR(dw, type.unroll.wr_##name) }55#define RD_REGISTER_UNROLL(dw, name) \56 { dw, #name, REGS_ADDR(dw, type.unroll.rd_##name) }57 58#define WRITE_STR "write"59#define READ_STR "read"60#define CHANNEL_STR "channel"61#define REGISTERS_STR "registers"62 63struct dw_edma_debugfs_entry {64 struct dw_edma *dw;65 const char *name;66 void __iomem *reg;67 enum dw_edma_dir dir;68 u16 ch;69};70 71static int dw_edma_debugfs_u32_get(void *data, u64 *val)72{73 struct dw_edma_debugfs_entry *entry = data;74 struct dw_edma *dw = entry->dw;75 void __iomem *reg = entry->reg;76 77 if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&78 reg >= REGS_ADDR(dw, type.legacy.ch)) {79 unsigned long flags;80 u32 viewport_sel;81 82 viewport_sel = entry->dir == EDMA_DIR_READ ? BIT(31) : 0;83 viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, entry->ch);84 85 raw_spin_lock_irqsave(&dw->lock, flags);86 87 writel(viewport_sel, REGS_ADDR(dw, type.legacy.viewport_sel));88 *val = readl(reg);89 90 raw_spin_unlock_irqrestore(&dw->lock, flags);91 } else {92 *val = readl(reg);93 }94 95 return 0;96}97DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");98 99static void dw_edma_debugfs_create_x32(struct dw_edma *dw,100 const struct dw_edma_debugfs_entry ini[],101 int nr_entries, struct dentry *dent)102{103 struct dw_edma_debugfs_entry *entries;104 int i;105 106 entries = devm_kcalloc(dw->chip->dev, nr_entries, sizeof(*entries),107 GFP_KERNEL);108 if (!entries)109 return;110 111 for (i = 0; i < nr_entries; i++) {112 entries[i] = ini[i];113 114 debugfs_create_file_unsafe(entries[i].name, 0444, dent,115 &entries[i], &fops_x32);116 }117}118 119static void dw_edma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir dir,120 u16 ch, struct dentry *dent)121{122 struct dw_edma_debugfs_entry debugfs_regs[] = {123 CTX_REGISTER(dw, ch_control1, dir, ch),124 CTX_REGISTER(dw, ch_control2, dir, ch),125 CTX_REGISTER(dw, transfer_size, dir, ch),126 CTX_REGISTER(dw, sar.lsb, dir, ch),127 CTX_REGISTER(dw, sar.msb, dir, ch),128 CTX_REGISTER(dw, dar.lsb, dir, ch),129 CTX_REGISTER(dw, dar.msb, dir, ch),130 CTX_REGISTER(dw, llp.lsb, dir, ch),131 CTX_REGISTER(dw, llp.msb, dir, ch),132 };133 int nr_entries;134 135 nr_entries = ARRAY_SIZE(debugfs_regs);136 dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, dent);137}138 139static noinline_for_stack void140dw_edma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dent)141{142 const struct dw_edma_debugfs_entry debugfs_regs[] = {143 /* eDMA global registers */144 WR_REGISTER(dw, engine_en),145 WR_REGISTER(dw, doorbell),146 WR_REGISTER(dw, ch_arb_weight.lsb),147 WR_REGISTER(dw, ch_arb_weight.msb),148 /* eDMA interrupts registers */149 WR_REGISTER(dw, int_status),150 WR_REGISTER(dw, int_mask),151 WR_REGISTER(dw, int_clear),152 WR_REGISTER(dw, err_status),153 WR_REGISTER(dw, done_imwr.lsb),154 WR_REGISTER(dw, done_imwr.msb),155 WR_REGISTER(dw, abort_imwr.lsb),156 WR_REGISTER(dw, abort_imwr.msb),157 WR_REGISTER(dw, ch01_imwr_data),158 WR_REGISTER(dw, ch23_imwr_data),159 WR_REGISTER(dw, ch45_imwr_data),160 WR_REGISTER(dw, ch67_imwr_data),161 WR_REGISTER(dw, linked_list_err_en),162 };163 const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {164 /* eDMA channel context grouping */165 WR_REGISTER_UNROLL(dw, engine_chgroup),166 WR_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),167 WR_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),168 WR_REGISTER_UNROLL(dw, ch0_pwr_en),169 WR_REGISTER_UNROLL(dw, ch1_pwr_en),170 WR_REGISTER_UNROLL(dw, ch2_pwr_en),171 WR_REGISTER_UNROLL(dw, ch3_pwr_en),172 WR_REGISTER_UNROLL(dw, ch4_pwr_en),173 WR_REGISTER_UNROLL(dw, ch5_pwr_en),174 WR_REGISTER_UNROLL(dw, ch6_pwr_en),175 WR_REGISTER_UNROLL(dw, ch7_pwr_en),176 };177 struct dentry *regs_dent, *ch_dent;178 int nr_entries, i;179 char name[32];180 181 regs_dent = debugfs_create_dir(WRITE_STR, dent);182 183 nr_entries = ARRAY_SIZE(debugfs_regs);184 dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dent);185 186 if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {187 nr_entries = ARRAY_SIZE(debugfs_unroll_regs);188 dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,189 regs_dent);190 }191 192 for (i = 0; i < dw->wr_ch_cnt; i++) {193 snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);194 195 ch_dent = debugfs_create_dir(name, regs_dent);196 197 dw_edma_debugfs_regs_ch(dw, EDMA_DIR_WRITE, i, ch_dent);198 }199}200 201static noinline_for_stack void dw_edma_debugfs_regs_rd(struct dw_edma *dw,202 struct dentry *dent)203{204 const struct dw_edma_debugfs_entry debugfs_regs[] = {205 /* eDMA global registers */206 RD_REGISTER(dw, engine_en),207 RD_REGISTER(dw, doorbell),208 RD_REGISTER(dw, ch_arb_weight.lsb),209 RD_REGISTER(dw, ch_arb_weight.msb),210 /* eDMA interrupts registers */211 RD_REGISTER(dw, int_status),212 RD_REGISTER(dw, int_mask),213 RD_REGISTER(dw, int_clear),214 RD_REGISTER(dw, err_status.lsb),215 RD_REGISTER(dw, err_status.msb),216 RD_REGISTER(dw, linked_list_err_en),217 RD_REGISTER(dw, done_imwr.lsb),218 RD_REGISTER(dw, done_imwr.msb),219 RD_REGISTER(dw, abort_imwr.lsb),220 RD_REGISTER(dw, abort_imwr.msb),221 RD_REGISTER(dw, ch01_imwr_data),222 RD_REGISTER(dw, ch23_imwr_data),223 RD_REGISTER(dw, ch45_imwr_data),224 RD_REGISTER(dw, ch67_imwr_data),225 };226 const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {227 /* eDMA channel context grouping */228 RD_REGISTER_UNROLL(dw, engine_chgroup),229 RD_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),230 RD_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),231 RD_REGISTER_UNROLL(dw, ch0_pwr_en),232 RD_REGISTER_UNROLL(dw, ch1_pwr_en),233 RD_REGISTER_UNROLL(dw, ch2_pwr_en),234 RD_REGISTER_UNROLL(dw, ch3_pwr_en),235 RD_REGISTER_UNROLL(dw, ch4_pwr_en),236 RD_REGISTER_UNROLL(dw, ch5_pwr_en),237 RD_REGISTER_UNROLL(dw, ch6_pwr_en),238 RD_REGISTER_UNROLL(dw, ch7_pwr_en),239 };240 struct dentry *regs_dent, *ch_dent;241 int nr_entries, i;242 char name[32];243 244 regs_dent = debugfs_create_dir(READ_STR, dent);245 246 nr_entries = ARRAY_SIZE(debugfs_regs);247 dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dent);248 249 if (dw->chip->mf == EDMA_MF_HDMA_COMPAT) {250 nr_entries = ARRAY_SIZE(debugfs_unroll_regs);251 dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,252 regs_dent);253 }254 255 for (i = 0; i < dw->rd_ch_cnt; i++) {256 snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);257 258 ch_dent = debugfs_create_dir(name, regs_dent);259 260 dw_edma_debugfs_regs_ch(dw, EDMA_DIR_READ, i, ch_dent);261 }262}263 264static void dw_edma_debugfs_regs(struct dw_edma *dw)265{266 const struct dw_edma_debugfs_entry debugfs_regs[] = {267 REGISTER(dw, ctrl_data_arb_prior),268 REGISTER(dw, ctrl),269 };270 struct dentry *regs_dent;271 int nr_entries;272 273 regs_dent = debugfs_create_dir(REGISTERS_STR, dw->dma.dbg_dev_root);274 275 nr_entries = ARRAY_SIZE(debugfs_regs);276 dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dent);277 278 dw_edma_debugfs_regs_wr(dw, regs_dent);279 dw_edma_debugfs_regs_rd(dw, regs_dent);280}281 282void dw_edma_v0_debugfs_on(struct dw_edma *dw)283{284 if (!debugfs_initialized())285 return;286 287 debugfs_create_u32("mf", 0444, dw->dma.dbg_dev_root, &dw->chip->mf);288 debugfs_create_u16("wr_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->wr_ch_cnt);289 debugfs_create_u16("rd_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->rd_ch_cnt);290 291 dw_edma_debugfs_regs(dw);292}293