From dbd4741e685de3b3aafd465c125108defd510c6b Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Thu, 9 May 2024 10:52:59 +0800 Subject: [PATCH] video: rockchip: rga3: add 'reset' debug node Signed-off-by: Yu Qiaowei Change-Id: I5839cd60c4d5d95fc01a23fc9461f40a23b78fa8 --- drivers/video/rockchip/rga3/include/rga_job.h | 1 + drivers/video/rockchip/rga3/rga_debugger.c | 62 +++++++++++++++++++ drivers/video/rockchip/rga3/rga_job.c | 40 ++++++++++++ 3 files changed, 103 insertions(+) diff --git a/drivers/video/rockchip/rga3/include/rga_job.h b/drivers/video/rockchip/rga3/include/rga_job.h index 0fc776173f16..2b297432532d 100644 --- a/drivers/video/rockchip/rga3/include/rga_job.h +++ b/drivers/video/rockchip/rga3/include/rga_job.h @@ -35,6 +35,7 @@ struct rga_request *rga_request_lookup(struct rga_pending_request_manager *reque uint32_t id); int rga_request_commit(struct rga_request *user_request); +void rga_request_scheduler_abort(struct rga_scheduler_t *scheduler); void rga_request_session_destroy_abort(struct rga_session *session); int rga_request_put(struct rga_request *request); void rga_request_get(struct rga_request *request); diff --git a/drivers/video/rockchip/rga3/rga_debugger.c b/drivers/video/rockchip/rga3/rga_debugger.c index 39464725dc5f..45a69193fd6d 100644 --- a/drivers/video/rockchip/rga3/rga_debugger.c +++ b/drivers/video/rockchip/rga3/rga_debugger.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ #include "rga_drv.h" #include "rga_mm.h" #include "rga_common.h" +#include "rga_job.h" #define RGA_DEBUGGER_ROOT_NAME "rkrga" @@ -462,6 +464,65 @@ static int rga_hardware_show(struct seq_file *m, void *data) return 0; } +static int rga_reset_show(struct seq_file *m, void *data) +{ + struct rga_scheduler_t *scheduler = NULL; + int i; + + seq_puts(m, "help:\n"); + seq_puts(m, " 'echo > reset' to reset hardware.\n"); + + seq_puts(m, "core:\n"); + for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { + scheduler = rga_drvdata->scheduler[i]; + + seq_printf(m, " %s core <%d>\n", + dev_driver_string(scheduler->dev), scheduler->core); + } + + return 0; +} + +static ssize_t rga_reset_write(struct file *file, const char __user *ubuf, + size_t len, loff_t *offp) +{ + char buf[14]; + int i, ret; + int reset_core = 0; + int reset_done = false; + struct rga_scheduler_t *scheduler = NULL; + + if (len > sizeof(buf) - 1) + return -EINVAL; + if (copy_from_user(buf, ubuf, len)) + return -EFAULT; + buf[len - 1] = '\0'; + + ret = kstrtoint(buf, 10, &reset_core); + if (ret < 0 || reset_core <= 0) { + pr_err("invalid core! failed to reset hardware, data = %s len = %zu.\n", buf, len); + return -EINVAL; + } + + for (i = 0; i < rga_drvdata->num_of_scheduler; i++) { + scheduler = rga_drvdata->scheduler[i]; + + if (scheduler->core == reset_core) { + reset_done = true; + pr_info("reset hardware core[%d]!\n", reset_core); + + rga_request_scheduler_abort(scheduler); + + break; + } + } + + if (!reset_done) + pr_err("cannot find core[%d]\n", reset_core); + + return len; +} + static struct rga_debugger_list rga_debugger_root_list[] = { {"debug", rga_debug_show, rga_debug_write, NULL}, {"driver_version", rga_version_show, NULL, NULL}, @@ -474,6 +535,7 @@ static struct rga_debugger_list rga_debugger_root_list[] = { {"dump_image", rga_dump_image_show, rga_dump_image_write, NULL}, #endif {"hardware", rga_hardware_show, NULL, NULL}, + {"reset", rga_reset_show, rga_reset_write, NULL}, }; static ssize_t rga_debugger_write(struct file *file, const char __user *ubuf, diff --git a/drivers/video/rockchip/rga3/rga_job.c b/drivers/video/rockchip/rga3/rga_job.c index ae78578c3479..07a2c697f0e1 100644 --- a/drivers/video/rockchip/rga3/rga_job.c +++ b/drivers/video/rockchip/rga3/rga_job.c @@ -651,6 +651,46 @@ struct rga_request *rga_request_lookup(struct rga_pending_request_manager *manag return request; } +void rga_request_scheduler_abort(struct rga_scheduler_t *scheduler) +{ + struct rga_job *job; + unsigned long flags; + + rga_power_enable(scheduler); + + spin_lock_irqsave(&scheduler->irq_lock, flags); + + job = scheduler->running_job; + if (job) { + scheduler->running_job = NULL; + scheduler->status = RGA_SCHEDULER_ABORT; + scheduler->ops->soft_reset(scheduler); + + spin_unlock_irqrestore(&scheduler->irq_lock, flags); + + rga_mm_unmap_job_info(job); + + job->ret = -EBUSY; + rga_request_release_signal(scheduler, job); + + rga_job_next(scheduler); + + /* + * Since the running job was abort, turn off the power here that + * should have been turned off after job done (corresponds to + * power_enable in rga_job_run()). + */ + rga_power_disable(scheduler); + } else { + scheduler->status = RGA_SCHEDULER_ABORT; + scheduler->ops->soft_reset(scheduler); + + spin_unlock_irqrestore(&scheduler->irq_lock, flags); + } + + rga_power_disable(scheduler); +} + static int rga_request_scheduler_job_abort(struct rga_request *request) { int i;