mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 11:26:02 +09:00
video: rockchip: rga3: Support pm_runtime
Add enable/disable pd on rga_job_schedule/done Signed-off-by: Li Huang <putin.li@rock-chips.com> Change-Id: Iaf3c19027c599ecc5f8ffdbd3ef7da44a4049381
This commit is contained in:
@@ -42,6 +42,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/wakelock.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
@@ -212,6 +213,8 @@ struct rga_scheduler_t {
|
||||
struct clk *clks[RGA_MAX_BUS_CLK];
|
||||
int num_clks;
|
||||
|
||||
struct kref pd_refcount;
|
||||
|
||||
struct rga_job *running_job;
|
||||
struct list_head todo_list;
|
||||
spinlock_t irq_lock;
|
||||
@@ -230,8 +233,6 @@ struct rga_drvdata_t {
|
||||
|
||||
struct rga_fence_context *fence_ctx;
|
||||
|
||||
struct mutex mutex; // mutex
|
||||
|
||||
/* used by rga2's mmu lock */
|
||||
struct mutex lock;
|
||||
|
||||
@@ -271,4 +272,8 @@ static inline void rga_write(int value, int offset, struct rga_scheduler_t *rga_
|
||||
writel(value, rga_scheduler->rga_base + offset);
|
||||
}
|
||||
|
||||
int rga_power_enable(struct rga_scheduler_t *rga_scheduler);
|
||||
int rga_power_disable(struct rga_scheduler_t *rga_scheduler);
|
||||
void rga_kref_disable_power(struct kref *ref);
|
||||
|
||||
#endif /* __LINUX_RGA_FENCE_H_ */
|
||||
|
||||
@@ -23,4 +23,10 @@ int rga_commit(struct rga_req *rga_command_base, int flags);
|
||||
int rga_kernel_commit(struct rga_req *rga_command_base,
|
||||
struct rga_mpi_job_t *mpi_job, int flags);
|
||||
|
||||
struct rga_job *
|
||||
rga_scheduler_get_pending_job_list(struct rga_scheduler_t *scheduler);
|
||||
|
||||
struct rga_job *
|
||||
rga_scheduler_get_running_job(struct rga_scheduler_t *scheduler);
|
||||
|
||||
#endif /* __LINUX_RKRGA_JOB_H_ */
|
||||
|
||||
@@ -15,11 +15,6 @@
|
||||
#include "rga_fence.h"
|
||||
#include "rga_hw_config.h"
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#endif
|
||||
|
||||
#include "rga2_mmu_info.h"
|
||||
#include "rga_debugger.h"
|
||||
|
||||
@@ -56,17 +51,13 @@ int rga_mpi_commit(struct rga_req *cmd, struct rga_mpi_job_t *mpi_job)
|
||||
EXPORT_SYMBOL_GPL(rga_mpi_commit);
|
||||
|
||||
#ifndef CONFIG_ROCKCHIP_FPGA
|
||||
static int rga_power_enable(struct rga_scheduler_t *rga_scheduler)
|
||||
int rga_power_enable(struct rga_scheduler_t *rga_scheduler)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
int i;
|
||||
|
||||
ret = pm_runtime_get_sync(rga_scheduler->dev);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to get pm runtime, ret = %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
pm_runtime_get_sync(rga_scheduler->dev);
|
||||
pm_stay_awake(rga_scheduler->dev);
|
||||
|
||||
for (i = 0; i < rga_scheduler->num_clks; i++) {
|
||||
if (!IS_ERR(rga_scheduler->clks[i])) {
|
||||
@@ -83,10 +74,13 @@ err_enable_clk:
|
||||
if (!IS_ERR(rga_scheduler->clks[i]))
|
||||
clk_disable_unprepare(rga_scheduler->clks[i]);
|
||||
|
||||
pm_relax(rga_scheduler->dev);
|
||||
pm_runtime_put_sync_suspend(rga_scheduler->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rga_power_disable(struct rga_scheduler_t *rga_scheduler)
|
||||
int rga_power_disable(struct rga_scheduler_t *rga_scheduler)
|
||||
{
|
||||
int i;
|
||||
|
||||
@@ -94,10 +88,21 @@ static int rga_power_disable(struct rga_scheduler_t *rga_scheduler)
|
||||
if (!IS_ERR(rga_scheduler->clks[i]))
|
||||
clk_disable_unprepare(rga_scheduler->clks[i]);
|
||||
|
||||
pm_runtime_put(rga_scheduler->dev);
|
||||
pm_relax(rga_scheduler->dev);
|
||||
pm_runtime_put_sync_suspend(rga_scheduler->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rga_kref_disable_power(struct kref *ref)
|
||||
{
|
||||
struct rga_scheduler_t *rga_scheduler = NULL;
|
||||
|
||||
rga_scheduler = container_of(ref, struct rga_scheduler_t, pd_refcount);
|
||||
|
||||
rga_power_disable(rga_scheduler);
|
||||
}
|
||||
|
||||
#endif //CONFIG_ROCKCHIP_FPGA
|
||||
|
||||
static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
|
||||
@@ -562,13 +567,28 @@ static int rga_drv_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, rga_scheduler);
|
||||
|
||||
device_init_wakeup(dev, true);
|
||||
|
||||
/* PM init */
|
||||
#ifndef CONFIG_ROCKCHIP_FPGA
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
ret = rga_power_enable(rga_scheduler);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = pm_runtime_get_sync(rga_scheduler->dev);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to get pm runtime, ret = %d\n",
|
||||
ret);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i = 0; i < rga_scheduler->num_clks; i++) {
|
||||
if (!IS_ERR(rga_scheduler->clks[i])) {
|
||||
ret = clk_prepare_enable(rga_scheduler->clks[i]);
|
||||
if (ret < 0) {
|
||||
pr_err("failed to enable clk\n");
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //CONFIG_ROCKCHIP_FPGA
|
||||
|
||||
rga_scheduler->ops->get_version(rga_scheduler);
|
||||
@@ -579,19 +599,27 @@ static int rga_drv_probe(struct platform_device *pdev)
|
||||
|
||||
data->num_of_scheduler++;
|
||||
|
||||
for (i = rga_scheduler->num_clks - 1; i >= 0; i--)
|
||||
if (!IS_ERR(rga_scheduler->clks[i]))
|
||||
clk_disable_unprepare(rga_scheduler->clks[i]);
|
||||
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
||||
pr_err("probe successfully\n");
|
||||
|
||||
return 0;
|
||||
|
||||
failed:
|
||||
device_init_wakeup(dev, false);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rga_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rga_scheduler_t *rga_scheduler =
|
||||
platform_get_drvdata(pdev);
|
||||
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
#ifndef CONFIG_ROCKCHIP_FPGA
|
||||
rga_power_disable(rga_scheduler);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
#endif //CONFIG_ROCKCHIP_FPGA
|
||||
|
||||
@@ -673,7 +701,6 @@ static int __init rga_init(void)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_init(&rga_drvdata->mutex);
|
||||
mutex_init(&rga_drvdata->lock);
|
||||
|
||||
wake_lock_init(&rga_drvdata->wake_lock, WAKE_LOCK_SUSPEND, "rga");
|
||||
|
||||
@@ -13,6 +13,37 @@
|
||||
#include "rga_hw_config.h"
|
||||
#include "rga2_mmu_info.h"
|
||||
|
||||
struct rga_job *
|
||||
rga_scheduler_get_pending_job_list(struct rga_scheduler_t *scheduler)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct rga_job *job;
|
||||
|
||||
spin_lock_irqsave(&scheduler->irq_lock, flags);
|
||||
|
||||
job = list_first_entry_or_null(&scheduler->todo_list,
|
||||
struct rga_job, head);
|
||||
|
||||
spin_unlock_irqrestore(&scheduler->irq_lock, flags);
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
struct rga_job *
|
||||
rga_scheduler_get_running_job(struct rga_scheduler_t *scheduler)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct rga_job *job;
|
||||
|
||||
spin_lock_irqsave(&scheduler->irq_lock, flags);
|
||||
|
||||
job = scheduler->running_job;
|
||||
|
||||
spin_unlock_irqrestore(&scheduler->irq_lock, flags);
|
||||
|
||||
return job;
|
||||
}
|
||||
|
||||
static struct rga_scheduler_t *get_scheduler(struct rga_job *job)
|
||||
{
|
||||
struct rga_scheduler_t *scheduler = NULL;
|
||||
@@ -82,25 +113,26 @@ static int rga_job_run(struct rga_job *job, struct rga_scheduler_t *scheduler)
|
||||
ret = rga_dma_get_info(job);
|
||||
if (ret < 0) {
|
||||
pr_err("dma buf get failed");
|
||||
return ret;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ret = scheduler->ops->init_reg(job);
|
||||
if (ret < 0) {
|
||||
pr_err("init reg failed");
|
||||
return ret;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ret = scheduler->ops->set_reg(job, scheduler);
|
||||
if (ret < 0) {
|
||||
pr_err("set reg failed");
|
||||
return ret;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* for debug */
|
||||
if (RGA_DEBUG_MSG)
|
||||
print_job_info(job);
|
||||
|
||||
failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -172,10 +204,14 @@ void rga_job_done(struct rga_scheduler_t *rga_scheduler, int ret)
|
||||
pr_err("%s use time = %lld\n", __func__,
|
||||
ktime_to_us(ktime_sub(now, job->timestamp)));
|
||||
|
||||
rga2_dma_flush_cache_for_virtual_address(&job->vir_page_table, rga_scheduler);
|
||||
if (job->core == RGA2_SCHEDULER_CORE0)
|
||||
rga2_dma_flush_cache_for_virtual_address(&job->vir_page_table,
|
||||
rga_scheduler);
|
||||
|
||||
rga_dma_put_info(job);
|
||||
|
||||
kref_put(&rga_scheduler->pd_refcount, rga_kref_disable_power);
|
||||
|
||||
if (job->out_fence)
|
||||
dma_fence_signal(job->out_fence);
|
||||
|
||||
@@ -496,6 +532,8 @@ static struct rga_scheduler_t *rga_job_schedule(struct rga_job *job)
|
||||
struct rga_scheduler_t *scheduler = NULL;
|
||||
struct rga_job *job_pos;
|
||||
bool first_match = 0;
|
||||
bool first_open_pd = false;
|
||||
int ret = 0;
|
||||
|
||||
if (rga_drvdata->num_of_scheduler > 1) {
|
||||
job->core = rga_job_assign(job);
|
||||
@@ -515,6 +553,13 @@ static struct rga_scheduler_t *rga_job_schedule(struct rga_job *job)
|
||||
|
||||
spin_lock_irqsave(&scheduler->irq_lock, flags);
|
||||
|
||||
if (list_empty(&scheduler->todo_list) && !scheduler->running_job) {
|
||||
kref_init(&scheduler->pd_refcount);
|
||||
first_open_pd = true;
|
||||
} else {
|
||||
kref_get(&scheduler->pd_refcount);
|
||||
}
|
||||
|
||||
/* priority policy set by userspace */
|
||||
if (list_empty(&scheduler->todo_list)
|
||||
|| (job->priority == RGA_SCHED_PRIORITY_DEFAULT)) {
|
||||
@@ -543,6 +588,15 @@ static struct rga_scheduler_t *rga_job_schedule(struct rga_job *job)
|
||||
|
||||
spin_unlock_irqrestore(&scheduler->irq_lock, flags);
|
||||
|
||||
/* enable power */
|
||||
if (first_open_pd) {
|
||||
ret = rga_power_enable(scheduler);
|
||||
if (ret < 0) {
|
||||
pr_err("power enable failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
rga_job_next(scheduler);
|
||||
|
||||
return scheduler;
|
||||
@@ -644,7 +698,7 @@ int rga_commit(struct rga_req *rga_command_base, int flags)
|
||||
job->flags |= RGA_JOB_ASYNC;
|
||||
rga_command_base->out_fence_fd = rga_out_fence_get_fd(job);
|
||||
|
||||
//TODO: job timeout clean
|
||||
//TODO: job timeout clean, need add pd disable
|
||||
|
||||
if (RGA_DEBUG_MSG)
|
||||
pr_err("in_fence_fd = %d",
|
||||
|
||||
Reference in New Issue
Block a user