250 lines · c
1// SPDX-License-Identifier: (GPL-2.0+ OR MIT)2/*3 * Rockchip ISP1 Driver - Base driver4 *5 * Copyright (C) 2019 Collabora, Ltd.6 *7 * Based on Rockchip ISP1 driver by Rockchip Electronics Co., Ltd.8 * Copyright (C) 2017 Rockchip Electronics Co., Ltd.9 */10 11#include <linux/debugfs.h>12#include <linux/delay.h>13#include <linux/device.h>14#include <linux/minmax.h>15#include <linux/pm_runtime.h>16#include <linux/seq_file.h>17#include <linux/string.h>18 19#include "rkisp1-common.h"20#include "rkisp1-regs.h"21 22struct rkisp1_debug_register {23 u32 reg;24 u32 shd;25 const char * const name;26};27 28#define RKISP1_DEBUG_REG(name) { RKISP1_CIF_##name, 0, #name }29#define RKISP1_DEBUG_SHD_REG(name) { \30 RKISP1_CIF_##name, RKISP1_CIF_##name##_SHD, #name \31}32 33/* Keep this up-to-date when adding new registers. */34#define RKISP1_MAX_REG_LENGTH 2135 36static int rkisp1_debug_dump_regs(struct rkisp1_device *rkisp1,37 struct seq_file *m, unsigned int offset,38 const struct rkisp1_debug_register *regs)39{40 const int width = RKISP1_MAX_REG_LENGTH;41 u32 val, shd;42 int ret;43 44 ret = pm_runtime_get_if_in_use(rkisp1->dev);45 if (ret <= 0)46 return ret ? : -ENODATA;47 48 for (; regs->name; ++regs) {49 val = rkisp1_read(rkisp1, offset + regs->reg);50 51 if (regs->shd) {52 shd = rkisp1_read(rkisp1, offset + regs->shd);53 seq_printf(m, "%*s: 0x%08x/0x%08x\n", width, regs->name,54 val, shd);55 } else {56 seq_printf(m, "%*s: 0x%08x\n", width, regs->name, val);57 }58 }59 60 pm_runtime_put(rkisp1->dev);61 62 return 0;63}64 65static int rkisp1_debug_dump_core_regs_show(struct seq_file *m, void *p)66{67 static const struct rkisp1_debug_register registers[] = {68 RKISP1_DEBUG_REG(VI_CCL),69 RKISP1_DEBUG_REG(VI_ICCL),70 RKISP1_DEBUG_REG(VI_IRCL),71 RKISP1_DEBUG_REG(VI_DPCL),72 RKISP1_DEBUG_REG(MI_CTRL),73 RKISP1_DEBUG_REG(MI_BYTE_CNT),74 RKISP1_DEBUG_REG(MI_CTRL_SHD),75 RKISP1_DEBUG_REG(MI_RIS),76 RKISP1_DEBUG_REG(MI_STATUS),77 RKISP1_DEBUG_REG(MI_DMA_CTRL),78 RKISP1_DEBUG_REG(MI_DMA_STATUS),79 { /* Sentinel */ },80 };81 struct rkisp1_device *rkisp1 = m->private;82 83 return rkisp1_debug_dump_regs(rkisp1, m, 0, registers);84}85DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_core_regs);86 87static int rkisp1_debug_dump_isp_regs_show(struct seq_file *m, void *p)88{89 static const struct rkisp1_debug_register registers[] = {90 RKISP1_DEBUG_REG(ISP_CTRL),91 RKISP1_DEBUG_REG(ISP_ACQ_PROP),92 RKISP1_DEBUG_REG(ISP_FLAGS_SHD),93 RKISP1_DEBUG_REG(ISP_RIS),94 RKISP1_DEBUG_REG(ISP_ERR),95 RKISP1_DEBUG_SHD_REG(ISP_IS_H_OFFS),96 RKISP1_DEBUG_SHD_REG(ISP_IS_V_OFFS),97 RKISP1_DEBUG_SHD_REG(ISP_IS_H_SIZE),98 RKISP1_DEBUG_SHD_REG(ISP_IS_V_SIZE),99 { /* Sentinel */ },100 };101 struct rkisp1_device *rkisp1 = m->private;102 103 return rkisp1_debug_dump_regs(rkisp1, m, 0, registers);104}105DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_isp_regs);106 107static int rkisp1_debug_dump_rsz_regs_show(struct seq_file *m, void *p)108{109 static const struct rkisp1_debug_register registers[] = {110 RKISP1_DEBUG_SHD_REG(RSZ_CTRL),111 RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HY),112 RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCB),113 RKISP1_DEBUG_SHD_REG(RSZ_SCALE_HCR),114 RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VY),115 RKISP1_DEBUG_SHD_REG(RSZ_SCALE_VC),116 RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HY),117 RKISP1_DEBUG_SHD_REG(RSZ_PHASE_HC),118 RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VY),119 RKISP1_DEBUG_SHD_REG(RSZ_PHASE_VC),120 { /* Sentinel */ },121 };122 struct rkisp1_resizer *rsz = m->private;123 124 return rkisp1_debug_dump_regs(rsz->rkisp1, m, rsz->regs_base, registers);125}126DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_rsz_regs);127 128static int rkisp1_debug_dump_mi_mp_show(struct seq_file *m, void *p)129{130 static const struct rkisp1_debug_register registers[] = {131 RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT),132 RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_INIT2),133 RKISP1_DEBUG_REG(MI_MP_Y_BASE_AD_SHD),134 RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT),135 RKISP1_DEBUG_REG(MI_MP_Y_SIZE_INIT),136 RKISP1_DEBUG_REG(MI_MP_Y_SIZE_SHD),137 RKISP1_DEBUG_REG(MI_MP_Y_OFFS_CNT_SHD),138 { /* Sentinel */ },139 };140 struct rkisp1_device *rkisp1 = m->private;141 142 return rkisp1_debug_dump_regs(rkisp1, m, 0, registers);143}144DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_dump_mi_mp);145 146#define RKISP1_DEBUG_DATA_COUNT_BINS 32147#define RKISP1_DEBUG_DATA_COUNT_STEP (4096 / RKISP1_DEBUG_DATA_COUNT_BINS)148 149static int rkisp1_debug_input_status_show(struct seq_file *m, void *p)150{151 struct rkisp1_device *rkisp1 = m->private;152 u16 data_count[RKISP1_DEBUG_DATA_COUNT_BINS] = { };153 unsigned int hsync_count = 0;154 unsigned int vsync_count = 0;155 unsigned int i;156 u32 data;157 u32 val;158 int ret;159 160 ret = pm_runtime_get_if_in_use(rkisp1->dev);161 if (ret <= 0)162 return ret ? : -ENODATA;163 164 /* Sample the ISP input port status 10000 times with a 1µs interval. */165 for (i = 0; i < 10000; ++i) {166 val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_FLAGS_SHD);167 168 data = (val & RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_MASK)169 >> RKISP1_CIF_ISP_FLAGS_SHD_S_DATA_SHIFT;170 data_count[data / RKISP1_DEBUG_DATA_COUNT_STEP]++;171 172 if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_HSYNC)173 hsync_count++;174 if (val & RKISP1_CIF_ISP_FLAGS_SHD_S_VSYNC)175 vsync_count++;176 177 udelay(1);178 }179 180 pm_runtime_put(rkisp1->dev);181 182 seq_printf(m, "vsync: %u, hsync: %u\n", vsync_count, hsync_count);183 seq_puts(m, "data:\n");184 for (i = 0; i < ARRAY_SIZE(data_count); ++i)185 seq_printf(m, "- [%04u:%04u]: %u\n",186 i * RKISP1_DEBUG_DATA_COUNT_STEP,187 (i + 1) * RKISP1_DEBUG_DATA_COUNT_STEP - 1,188 data_count[i]);189 190 return 0;191}192DEFINE_SHOW_ATTRIBUTE(rkisp1_debug_input_status);193 194void rkisp1_debug_init(struct rkisp1_device *rkisp1)195{196 struct rkisp1_debug *debug = &rkisp1->debug;197 struct dentry *regs_dir;198 199 debug->debugfs_dir = debugfs_create_dir(dev_name(rkisp1->dev), NULL);200 201 debugfs_create_ulong("data_loss", 0444, debug->debugfs_dir,202 &debug->data_loss);203 debugfs_create_ulong("outform_size_err", 0444, debug->debugfs_dir,204 &debug->outform_size_error);205 debugfs_create_ulong("img_stabilization_size_error", 0444,206 debug->debugfs_dir,207 &debug->img_stabilization_size_error);208 debugfs_create_ulong("inform_size_error", 0444, debug->debugfs_dir,209 &debug->inform_size_error);210 debugfs_create_ulong("irq_delay", 0444, debug->debugfs_dir,211 &debug->irq_delay);212 debugfs_create_ulong("mipi_error", 0444, debug->debugfs_dir,213 &debug->mipi_error);214 debugfs_create_ulong("stats_error", 0444, debug->debugfs_dir,215 &debug->stats_error);216 debugfs_create_ulong("mp_stop_timeout", 0444, debug->debugfs_dir,217 &debug->stop_timeout[RKISP1_MAINPATH]);218 debugfs_create_ulong("sp_stop_timeout", 0444, debug->debugfs_dir,219 &debug->stop_timeout[RKISP1_SELFPATH]);220 debugfs_create_ulong("mp_frame_drop", 0444, debug->debugfs_dir,221 &debug->frame_drop[RKISP1_MAINPATH]);222 debugfs_create_ulong("sp_frame_drop", 0444, debug->debugfs_dir,223 &debug->frame_drop[RKISP1_SELFPATH]);224 debugfs_create_ulong("complete_frames", 0444, debug->debugfs_dir,225 &debug->complete_frames);226 debugfs_create_file("input_status", 0444, debug->debugfs_dir, rkisp1,227 &rkisp1_debug_input_status_fops);228 229 regs_dir = debugfs_create_dir("regs", debug->debugfs_dir);230 231 debugfs_create_file("core", 0444, regs_dir, rkisp1,232 &rkisp1_debug_dump_core_regs_fops);233 debugfs_create_file("isp", 0444, regs_dir, rkisp1,234 &rkisp1_debug_dump_isp_regs_fops);235 debugfs_create_file("mrsz", 0444, regs_dir,236 &rkisp1->resizer_devs[RKISP1_MAINPATH],237 &rkisp1_debug_dump_rsz_regs_fops);238 debugfs_create_file("srsz", 0444, regs_dir,239 &rkisp1->resizer_devs[RKISP1_SELFPATH],240 &rkisp1_debug_dump_rsz_regs_fops);241 242 debugfs_create_file("mi_mp", 0444, regs_dir, rkisp1,243 &rkisp1_debug_dump_mi_mp_fops);244}245 246void rkisp1_debug_cleanup(struct rkisp1_device *rkisp1)247{248 debugfs_remove_recursive(rkisp1->debug.debugfs_dir);249}250