video: rockchip: mpp: rkvdec2: Add link mode flow

rkvdec2 link mode use a new serialized work flow.

This process is for link mode decoder in RK356x.
The new flow run async with hardware and use multiple trigger event to
run the work thread. All task operation, power operation and reset
operation are serialzed in one thread with certain order.
This is mainly for runtime debug and it will simplify the system design.

rkvdec2 link mode use two sets of counters to control the hardware io:
1. write / read task for preparing link mode task to ddr.
2. send / recv task for sending / receiving task from hardware.

All the operations are serialized in single work thread. So only a few
of lock and atomic is required.

The decoded counter and total counter are the synchronization method
between driver and hardware.

NOTE:
1. link mode reset should use sip_reset.
2. link mode should not change hardware frequency or power off when
there is still task running.
3. link mode should not access hardware when there is an error happen.
4. link mode should reserve a stuff task for H.264 decode task.

Signed-off-by: Herman Chen <herman.chen@rock-chips.com>
Change-Id: I7736d54a64225089cd6d1b6522f660ce4481d437
This commit is contained in:
Herman Chen
2021-08-05 19:00:36 +08:00
committed by Tao Huang
parent 832f54d650
commit 9fb6c91e42
8 changed files with 2056 additions and 209 deletions

View File

@@ -12,7 +12,7 @@ rk_vcodec-objs := mpp_service.o mpp_common.o mpp_iommu.o
CFLAGS_mpp_service.o += -DMPP_VERSION="\"$(MPP_REVISION)\""
rk_vcodec-$(CONFIG_ROCKCHIP_MPP_RKVDEC) += mpp_rkvdec.o
rk_vcodec-$(CONFIG_ROCKCHIP_MPP_RKVDEC2) += mpp_rkvdec2.o
rk_vcodec-$(CONFIG_ROCKCHIP_MPP_RKVDEC2) += mpp_rkvdec2.o mpp_rkvdec2_link.o
rk_vcodec-$(CONFIG_ROCKCHIP_MPP_RKVENC) += mpp_rkvenc.o
rk_vcodec-$(CONFIG_ROCKCHIP_MPP_VDPU1) += mpp_vdpu1.o
rk_vcodec-$(CONFIG_ROCKCHIP_MPP_VEPU1) += mpp_vepu1.o

View File

@@ -0,0 +1,213 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd
*
* author:
* Herman Chen <herman.chen@rock-chips.com>
*/
#define FIX_RK3568_BUF_SIZE (2 * PAGE_SIZE)
#define RKDEC_HACK_DATA_RPS_OFFSET (128 * 1)
#define RKDEC_HACK_DATA_PPS_OFFSET (128 * 2)
#define RKDEC_HACK_DATA_RLC_OFFSET (128 * 3)
#define RKDEC_HACK_DATA_OUT_OFFSET (128 * 4)
#define RKDEC_HACK_DATA_COLMV_OFFSET (128 * 5)
static u32 rkvdec2_3568_hack_link[] = {
0x00000000, /* 0x0020 */
0x00000001, /* 0x0024 */
0x00000001, /* 0x0028 */
0x00000072, /* 0x002c */
0x00000182, /* 0x0030 */
0x01040201, /* 0x0034 */
0x00000000, /* 0x0038 */
0x00000001, /* 0x003c */
0x00000030, /* 0x0040 */
0x00003fff, /* 0x0044 */
0x00000001, /* 0x0048 */
0x00000001, /* 0x004c */
0x00000010, /* 0x0050 */
0x00000006, /* 0x0054 */
0x00000000, /* 0x0058 */
0x00000000, /* 0x005c */
0xffffdfff, /* 0x0060 */
0x3ffbfbff, /* 0x0064 */
0x800fffff, /* 0x0068 */
0x00000000, /* 0x006C */
0x00000000, /* 0x0100 */
0x00000000, /* 0x0104 */
0x00000000, /* 0x0108 */
0x00000000, /* 0x010c */
0x00000000, /* 0x0110 */
0x00000000, /* 0x0114 */
0x00000000, /* 0x0118 */
0x00000000, /* 0x011c */
0x00000000, /* 0x0120 */
0x00000000, /* 0x0124 */
0x00000000, /* 0x0128 */
0x00000000, /* 0x012c */
0x00000000, /* 0x0130 */
0x00000000, /* 0x0134 */
0x00000000, /* 0x0138 */
0x00000000, /* 0x013c */
0x00000000, /* 0x0140 */
0x00000000, /* 0x0144 */
0x00000000, /* 0x0148 */
0x00000000, /* 0x014c */
0x00000000, /* 0x0150 */
0x00000000, /* 0x0154 */
0x00000000, /* 0x0158 */
0x00000000, /* 0x015c */
0x00000000, /* 0x0160 */
0x00000000, /* 0x0164 */
0x00000000, /* 0x0168 */
0x00000000, /* 0x016c */
0x00000000, /* 0x0170 */
0x00000000, /* 0x0174 */
0x00000000, /* 0x0178 */
0x00000000, /* 0x017c */
0x00000000, /* 0x0180 */
0x00000000, /* 0x0184 */
0x00000000, /* 0x0188 */
0x00000000, /* 0x018c */
0x00000000, /* 0x0190 */
0x00000000, /* 0x0194 */
0x00000000, /* 0x0198 */
0x00000000, /* 0x019c */
0x00000000, /* 0x01a0 */
0x00000000, /* 0x01a4 */
0x00000000, /* 0x01a8 */
0x00000000, /* 0x01ac */
0x00000000, /* 0x01b0 */
0x00000000, /* 0x01b4 */
0x00000000, /* 0x01b8 */
0x00000000, /* 0x01bc */
0x00000000, /* 0x01c0 */
0x00000000, /* 0x01c4 */
0x00000000, /* 0x01c8 */
0x00000000, /* 0x01cc */
0x00000000, /* 0x0200 */
0x00000000, /* 0x0204 */
0x00000000, /* 0x0208 */
0x00000000, /* 0x020c */
0x00000000, /* 0x0210 */
0x100001c0, /* 0x0214 */
0x100001c0, /* 0x0218 */
0x100001c0, /* 0x021c */
0x100001c0, /* 0x0220 */
0x10000340, /* 0x0224 */
0x10000340, /* 0x0228 */
0x10000000, /* 0x022c */
0x10000000, /* 0x0230 */
0x10000000, /* 0x0234 */
0x10000000, /* 0x0238 */
0x10000000, /* 0x023c */
0x00000000, /* 0x0280 */
0x00000000, /* 0x0284 */
0x00000000, /* 0x0288 */
0x00000000, /* 0x028c */
0x00000000, /* 0x0290 */
0x00000000, /* 0x0294 */
0x00000000, /* 0x0298 */
0x00000000, /* 0x029c */
0x00000000, /* 0x02a0 */
0x00000000, /* 0x02a4 */
0x00000000, /* 0x02a8 */
0x00000000, /* 0x02ac */
0x00000000, /* 0x02b0 */
0x00000000, /* 0x02b4 */
0x00000000, /* 0x02b8 */
0x00000000, /* 0x02bc */
0x00000000, /* 0x02c0 */
0x00000000, /* 0x02c4 */
0x00000000, /* 0x02c8 */
0x00000000, /* 0x02cc */
0x00000000, /* 0x02d0 */
0x00000000, /* 0x02d4 */
0x00000000, /* 0x02d8 */
0x00000000, /* 0x02dc */
0x00000000, /* 0x02e0 */
0x00000000, /* 0x02e4 */
0x00000000, /* 0x02e8 */
0x00000000, /* 0x02ec */
0x00000000, /* 0x02f0 */
0x00000000, /* 0x02f4 */
0x00000000, /* 0x02f8 */
0x00000000, /* 0x02fc */
0x00000000, /* 0x0300 */
0x00000000, /* 0x0304 */
0x00000000, /* 0x0308 */
0x00000000, /* 0x030c */
0x00000000, /* 0x0310 */
0x00000000, /* 0x0314 */
0x00000000, /* 0x0318 */
0x00000000, /* 0x031c */
0x00000000, /* 0x0380 */
0x00000000, /* 0x0384 */
0x00000000, /* 0x0388 */
0x00000000, /* 0x038c */
0x00000000, /* 0x0390 */
0x00000000, /* 0x0394 */
0x00000000, /* 0x0398 */
0x00000000, /* 0x039c */
0x00000000, /* 0x03a0 */
0x00000000, /* 0x03a4 */
0x00000000, /* 0x03a8 */
0x00000000, /* 0x03ac */
0x00000000, /* 0x03b0 */
0x00000000, /* 0x03b4 */
0x00000000, /* 0x03b8 */
0x00000000, /* 0x03bc */
0x00000000, /* 0x0400 */
0x00000000, /* 0x0404 */
0x00000000, /* 0x0408 */
0x00000000, /* 0x040c */
0x00000000, /* 0x0410 */
0x00000000, /* 0x0414 */
0x00000000, /* 0x0418 */
0x00000000, /* 0x041c */
0x00000000, /* 0x0420 */
0x00000000, /* 0x0424 */
0x00000000, /* 0x0428 */
0x00000000, /* 0x042c */
0x00000000, /* 0x0430 */
0x00000000, /* 0x0434 */
0x00000000, /* 0x0438 */
0x00000000, /* 0x043c */
};
void rkvdec2_3568_hack_fix_link(void *buf)
{
memcpy(buf, rkvdec2_3568_hack_link, sizeof(rkvdec2_3568_hack_link));
}
void rkvdec2_link_hack_data_setup(struct mpp_dma_buffer *fix)
{
u32 iova = fix->iova;
u32 i;
/* input stream */
rkvdec2_3568_hack_link[72] = iova;
/* error info */
rkvdec2_3568_hack_link[73] = iova + RKDEC_HACK_DATA_RLC_OFFSET;
/* output frame */
rkvdec2_3568_hack_link[74] = iova + RKDEC_HACK_DATA_OUT_OFFSET;
/* colmv out */
rkvdec2_3568_hack_link[75] = iova + 128 * 6;
/* error ref */
rkvdec2_3568_hack_link[76] = iova + 128 * 4;
/* rps in */
rkvdec2_3568_hack_link[89] = iova + RKDEC_HACK_DATA_PPS_OFFSET;
/* pps in */
rkvdec2_3568_hack_link[91] = iova + RKDEC_HACK_DATA_RPS_OFFSET;
for (i = 0; i < 33; i++)
rkvdec2_3568_hack_link[92 + i] = iova + RKDEC_HACK_DATA_COLMV_OFFSET;
rkvdec2_3568_hack_link[125] = iova + PAGE_SIZE;
}

View File

@@ -348,7 +348,7 @@ static void mpp_session_detach_workqueue(struct mpp_session *session)
mutex_lock(&queue->session_lock);
list_del_init(&session->session_link);
list_add_tail(&session->session_link, &queue->session_detach);
atomic_inc(&queue->detach_count);
queue->detach_count++;
mutex_unlock(&queue->session_lock);
mpp_taskqueue_trigger_work(session->mpp);
@@ -732,21 +732,20 @@ static void mpp_task_try_run(struct kthread_work *work_s)
}
done:
if (atomic_read(&queue->detach_count)) {
mutex_lock(&queue->session_lock);
if (queue->detach_count) {
struct mpp_session *session = NULL, *n;
mpp_dbg_session("%s detach count %d\n", dev_name(mpp->dev),
atomic_read(&queue->detach_count));
queue->detach_count);
mutex_lock(&queue->session_lock);
list_for_each_entry_safe(session, n, &queue->session_detach,
session_link) {
if (!mpp_session_deinit(session))
atomic_dec(&queue->detach_count);
queue->detach_count--;
}
mutex_unlock(&queue->session_lock);
}
mutex_unlock(&queue->session_lock);
}
static int mpp_wait_result_default(struct mpp_session *session,
@@ -935,7 +934,6 @@ struct mpp_taskqueue *mpp_taskqueue_init(struct device *dev)
INIT_LIST_HEAD(&queue->mmu_list);
INIT_LIST_HEAD(&queue->dev_list);
atomic_set(&queue->detach_count, 0);
/* default taskqueue has max 16 task capacity */
queue->task_capacity = MPP_MAX_TASK_CAPACITY;
@@ -1640,6 +1638,7 @@ int mpp_task_init(struct mpp_session *session,
INIT_LIST_HEAD(&task->pending_link);
INIT_LIST_HEAD(&task->queue_link);
INIT_LIST_HEAD(&task->mem_region_list);
task->state = 0;
task->mem_count = 0;
task->session = session;
@@ -1814,11 +1813,17 @@ int mpp_dev_probe(struct mpp_dev *mpp,
/* read link table capacity */
ret = of_property_read_u32(np, "rockchip,task-capacity",
&mpp->task_capacity);
if (ret)
if (ret) {
mpp->task_capacity = 1;
else
/* power domain autosuspend delay 2s */
pm_runtime_set_autosuspend_delay(dev, 2000);
pm_runtime_use_autosuspend(dev);
} else {
dev_info(dev, "%d task capacity link mode detected\n",
mpp->task_capacity);
/* do not setup autosuspend on multi task device */
}
kthread_init_work(&mpp->work, mpp->dev_ops->task_worker ?
mpp->dev_ops->task_worker : mpp_task_try_run);
@@ -1829,9 +1834,6 @@ int mpp_dev_probe(struct mpp_dev *mpp,
atomic_set(&mpp->task_index, 0);
device_init_wakeup(dev, true);
/* power domain autosuspend delay 2s */
pm_runtime_set_autosuspend_delay(dev, 2000);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);
mpp->irq = platform_get_irq(pdev, 0);

View File

@@ -424,7 +424,7 @@ struct mpp_taskqueue {
struct list_head session_attach;
/* link to session session_link for detached sessions */
struct list_head session_detach;
atomic_t detach_count;
u32 detach_count;
/* lock for pending list */
struct mutex pending_lock;

View File

@@ -7,192 +7,14 @@
* Ding Wei, leo.ding@rock-chips.com
*
*/
#include <asm/cacheflush.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/devfreq.h>
#include <linux/devfreq_cooling.h>
#include <linux/dma-iommu.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/regmap.h>
#include <linux/kernel.h>
#include <linux/thermal.h>
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/nospec.h>
#include <linux/rockchip/rockchip_sip.h>
#include <linux/regulator/consumer.h>
#include <soc/rockchip/pm_domains.h>
#include <soc/rockchip/rockchip_sip.h>
#include "mpp_debug.h"
#include "mpp_common.h"
#include "mpp_iommu.h"
#include "mpp_rkvdec2_link.h"
#include "hack/mpp_rkvdec2_hack_rk3568.c"
#define RKVDEC_DRIVER_NAME "mpp_rkvdec2"
#define RKVDEC_SESSION_MAX_BUFFERS 40
/* The maximum registers number of all the version */
#define RKVDEC_REG_NUM 278
#define RKVDEC_REG_HW_ID_INDEX 0
#define RKVDEC_REG_START_INDEX 0
#define RKVDEC_REG_END_INDEX 277
#define REVDEC_GET_PROD_NUM(x) (((x) >> 16) & 0xffff)
#define RKVDEC_REG_FORMAT_INDEX 9
#define RKVDEC_GET_FORMAT(x) ((x) & 0x3ff)
#define RKVDEC_REG_START_EN_BASE 0x28
#define RKVDEC_REG_START_EN_INDEX 10
#define RKVDEC_START_EN BIT(0)
#define RKVDEC_REG_YSTRIDE_INDEX 20
#define RKVDEC_REG_RLC_BASE 0x200
#define RKVDEC_REG_RLC_BASE_INDEX (128)
#define RKVDEC_REG_INT_EN 0x380
#define RKVDEC_REG_INT_EN_INDEX (224)
#define RKVDEC_SOFT_RESET_READY BIT(9)
#define RKVDEC_CABAC_END_STA BIT(8)
#define RKVDEC_COLMV_REF_ERR_STA BIT(7)
#define RKVDEC_BUF_EMPTY_STA BIT(6)
#define RKVDEC_TIMEOUT_STA BIT(5)
#define RKVDEC_ERROR_STA BIT(4)
#define RKVDEC_BUS_STA BIT(3)
#define RKVDEC_READY_STA BIT(2)
#define RKVDEC_IRQ_RAW BIT(1)
#define RKVDEC_IRQ BIT(0)
#define RKVDEC_INT_ERROR_MASK (RKVDEC_COLMV_REF_ERR_STA |\
RKVDEC_BUF_EMPTY_STA |\
RKVDEC_TIMEOUT_STA |\
RKVDEC_ERROR_STA)
/* perf sel reference register */
#define RKVDEC_PERF_SEL_OFFSET 0x20000
#define RKVDEC_PERF_SEL_NUM 64
#define RKVDEC_PERF_SEL_BASE 0x424
#define RKVDEC_SEL_VAL0_BASE 0x428
#define RKVDEC_SEL_VAL1_BASE 0x42c
#define RKVDEC_SEL_VAL2_BASE 0x430
#define RKVDEC_SET_PERF_SEL(a, b, c) ((a) | ((b) << 8) | ((c) << 16))
/* cache reference register */
#define RKVDEC_REG_CACHE0_SIZE_BASE 0x51c
#define RKVDEC_REG_CACHE1_SIZE_BASE 0x55c
#define RKVDEC_REG_CACHE2_SIZE_BASE 0x59c
#define RKVDEC_REG_CLR_CACHE0_BASE 0x510
#define RKVDEC_REG_CLR_CACHE1_BASE 0x550
#define RKVDEC_REG_CLR_CACHE2_BASE 0x590
#define RKVDEC_CACHE_PERMIT_CACHEABLE_ACCESS BIT(0)
#define RKVDEC_CACHE_PERMIT_READ_ALLOCATE BIT(1)
#define RKVDEC_CACHE_LINE_SIZE_64_BYTES BIT(4)
#define RKVDEC_FORMAT_H264 0X1
#define to_rkvdec2_task(task) \
container_of(task, struct rkvdec2_task, mpp_task)
#define to_rkvdec2_dev(dev) \
container_of(dev, struct rkvdec2_dev, mpp)
enum RKVDEC_FMT {
RKVDEC_FMT_H265D = 0,
RKVDEC_FMT_H264D = 1,
RKVDEC_FMT_VP9D = 2,
RKVDEC_FMT_AVS2 = 3,
};
#define RKVDEC_MAX_RCB_NUM (16)
struct rcb_info_elem {
u32 index;
u32 size;
};
struct rkvdec2_rcb_info {
u32 cnt;
struct rcb_info_elem elem[RKVDEC_MAX_RCB_NUM];
};
struct rkvdec2_task {
struct mpp_task mpp_task;
enum MPP_CLOCK_MODE clk_mode;
u32 reg[RKVDEC_REG_NUM];
struct reg_offset_info off_inf;
/* perf sel data back */
u32 reg_sel[RKVDEC_PERF_SEL_NUM];
u32 strm_addr;
u32 irq_status;
/* req for current task */
u32 w_req_cnt;
struct mpp_request w_reqs[MPP_MAX_MSG_NUM];
u32 r_req_cnt;
struct mpp_request r_reqs[MPP_MAX_MSG_NUM];
/* image info */
u32 width;
u32 height;
u32 pixels;
u32 need_hack;
};
struct rkvdec2_session_priv {
/* codec info from user */
struct {
/* show mode */
u32 flag;
/* item data */
u64 val;
} codec_info[DEC_INFO_BUTT];
/* rcb_info for sram */
struct rkvdec2_rcb_info rcb_inf;
};
struct rkvdec2_dev {
struct mpp_dev mpp;
/* sip smc reset lock */
struct mutex sip_reset_lock;
struct mpp_clk_info aclk_info;
struct mpp_clk_info hclk_info;
struct mpp_clk_info core_clk_info;
struct mpp_clk_info cabac_clk_info;
struct mpp_clk_info hevc_cabac_clk_info;
u32 default_max_load;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *procfs;
#endif
struct reset_control *rst_a;
struct reset_control *rst_h;
struct reset_control *rst_niu_a;
struct reset_control *rst_niu_h;
struct reset_control *rst_core;
struct reset_control *rst_cabac;
struct reset_control *rst_hevc_cabac;
/* internal rcb-memory */
u32 sram_size;
u32 rcb_size;
dma_addr_t rcb_iova;
struct page *rcb_page;
u32 rcb_min_width;
struct mpp_dma_buffer *fix;
};
/*
* hardware information
*/
@@ -366,8 +188,8 @@ done:
return 0;
}
static void *rkvdec2_alloc_task(struct mpp_session *session,
struct mpp_task_msgs *msgs)
void *rkvdec2_alloc_task(struct mpp_session *session,
struct mpp_task_msgs *msgs)
{
int ret;
struct mpp_task *mpp_task = NULL;
@@ -403,6 +225,8 @@ static void *rkvdec2_alloc_task(struct mpp_session *session,
mpp_set_rcbbuf(mpp, session, task);
task->strm_addr = task->reg[RKVDEC_REG_RLC_BASE_INDEX];
task->clk_mode = CLK_MODE_NORMAL;
task->slot_idx = -1;
init_waitqueue_head(&task->wait);
/* get resolution info */
if (session->priv) {
struct rkvdec2_session_priv *priv = session->priv;
@@ -442,7 +266,7 @@ static void *rkvdec2_rk3568_alloc_task(struct mpp_session *session,
task = to_rkvdec2_task(mpp_task);
fmt = RKVDEC_GET_FORMAT(task->reg[RKVDEC_REG_FORMAT_INDEX]);
/* workaround for rk356x, fix the hw bug of cabac/cavlc switch only in h264d */
task->need_hack = (fmt == RKVDEC_FORMAT_H264);
task->need_hack = (fmt == RKVDEC_FMT_H264D);
return mpp_task;
}
@@ -621,9 +445,8 @@ static int rkvdec2_finish(struct mpp_dev *mpp, struct mpp_task *mpp_task)
return 0;
}
static int rkvdec2_result(struct mpp_dev *mpp,
struct mpp_task *mpp_task,
struct mpp_task_msgs *msgs)
int rkvdec2_result(struct mpp_dev *mpp, struct mpp_task *mpp_task,
struct mpp_task_msgs *msgs)
{
u32 i;
struct mpp_request *req;
@@ -654,8 +477,7 @@ static int rkvdec2_result(struct mpp_dev *mpp,
return 0;
}
static int rkvdec2_free_task(struct mpp_session *session,
struct mpp_task *mpp_task)
int rkvdec2_free_task(struct mpp_session *session, struct mpp_task *mpp_task)
{
struct rkvdec2_task *task = to_rkvdec2_task(mpp_task);
@@ -707,7 +529,7 @@ static int rkvdec2_control(struct mpp_session *session, struct mpp_request *req)
return 0;
}
static int rkvdec2_free_session(struct mpp_session *session)
int rkvdec2_free_session(struct mpp_session *session)
{
if (session && session->priv) {
kfree(session->priv);
@@ -1027,6 +849,7 @@ static struct mpp_dev_ops rkvdec_rk3568_dev_ops = {
.ioctl = rkvdec2_control,
.init_session = rkvdec2_init_session,
.free_session = rkvdec2_free_session,
.dump_dev = rkvdec_link_dump,
};
static const struct mpp_dev_var rkvdec_v2_data = {
@@ -1186,17 +1009,31 @@ static int rkvdec2_probe(struct platform_device *pdev)
return ret;
}
ret = devm_request_threaded_irq(dev, mpp->irq,
mpp_dev_irq, mpp_dev_isr_sched,
IRQF_SHARED, dev_name(dev), mpp);
rkvdec2_alloc_rcbbuf(pdev, dec);
rkvdec2_link_init(pdev, dec);
if (dec->link_dec) {
ret = devm_request_threaded_irq(dev, mpp->irq,
rkvdec2_link_irq_proc, NULL,
IRQF_SHARED, dev_name(dev), mpp);
mpp->dev_ops->process_task = rkvdec2_link_process_task;
mpp->dev_ops->wait_result = rkvdec2_link_wait_result;
mpp->dev_ops->task_worker = rkvdec2_link_worker;
mpp->dev_ops->deinit = rkvdec2_link_session_deinit;
kthread_init_work(&mpp->work, rkvdec2_link_worker);
} else {
ret = devm_request_threaded_irq(dev, mpp->irq,
mpp_dev_irq, mpp_dev_isr_sched,
IRQF_SHARED, dev_name(dev), mpp);
}
if (ret) {
dev_err(dev, "register interrupter runtime failed\n");
return -EINVAL;
}
rkvdec2_alloc_rcbbuf(pdev, dec);
mpp->session_max_buffers = RKVDEC_SESSION_MAX_BUFFERS;
rkvdec2_procfs_init(mpp);
rkvdec2_link_procfs_init(mpp);
dev_info(dev, "probing finish\n");
return 0;
@@ -1228,6 +1065,7 @@ static int rkvdec2_remove(struct platform_device *pdev)
rkvdec2_free_rcbbuf(pdev, dec);
mpp_dev_remove(&dec->mpp);
rkvdec2_procfs_remove(&dec->mpp);
rkvdec2_link_remove(&dec->mpp, dec->link_dec);
return 0;
}

View File

@@ -0,0 +1,205 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd
*
* author:
* Herman Chen <herman.chen@rock-chips.com>
*
*/
#ifndef __ROCKCHIP_MPP_RKVDEC2_H__
#define __ROCKCHIP_MPP_RKVDEC2_H__
#include <linux/dma-iommu.h>
#include <linux/iopoll.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/regmap.h>
#include <linux/kernel.h>
#include <linux/thermal.h>
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/nospec.h>
#include <linux/rockchip/rockchip_sip.h>
#include <linux/regulator/consumer.h>
#include <soc/rockchip/pm_domains.h>
#include <soc/rockchip/rockchip_sip.h>
#include "mpp_debug.h"
#include "mpp_common.h"
#include "mpp_iommu.h"
#define RKVDEC_DRIVER_NAME "mpp_rkvdec2"
#define RKVDEC_SESSION_MAX_BUFFERS 40
/* The maximum registers number of all the version */
#define RKVDEC_REG_NUM 278
#define RKVDEC_REG_HW_ID_INDEX 0
#define RKVDEC_REG_START_INDEX 0
#define RKVDEC_REG_END_INDEX 277
#define REVDEC_GET_PROD_NUM(x) (((x) >> 16) & 0xffff)
#define RKVDEC_REG_FORMAT_INDEX 9
#define RKVDEC_GET_FORMAT(x) ((x) & 0x3ff)
#define RKVDEC_REG_START_EN_BASE 0x28
#define RKVDEC_REG_START_EN_INDEX 10
#define RKVDEC_START_EN BIT(0)
#define RKVDEC_REG_YSTRIDE_INDEX 20
#define RKVDEC_REG_RLC_BASE 0x200
#define RKVDEC_REG_RLC_BASE_INDEX (128)
#define RKVDEC_REG_INT_EN 0x380
#define RKVDEC_REG_INT_EN_INDEX (224)
#define RKVDEC_SOFT_RESET_READY BIT(9)
#define RKVDEC_CABAC_END_STA BIT(8)
#define RKVDEC_COLMV_REF_ERR_STA BIT(7)
#define RKVDEC_BUF_EMPTY_STA BIT(6)
#define RKVDEC_TIMEOUT_STA BIT(5)
#define RKVDEC_ERROR_STA BIT(4)
#define RKVDEC_BUS_STA BIT(3)
#define RKVDEC_READY_STA BIT(2)
#define RKVDEC_IRQ_RAW BIT(1)
#define RKVDEC_IRQ BIT(0)
#define RKVDEC_INT_ERROR_MASK (RKVDEC_COLMV_REF_ERR_STA |\
RKVDEC_BUF_EMPTY_STA |\
RKVDEC_TIMEOUT_STA |\
RKVDEC_ERROR_STA)
/* perf sel reference register */
#define RKVDEC_PERF_SEL_OFFSET 0x20000
#define RKVDEC_PERF_SEL_NUM 64
#define RKVDEC_PERF_SEL_BASE 0x424
#define RKVDEC_SEL_VAL0_BASE 0x428
#define RKVDEC_SEL_VAL1_BASE 0x42c
#define RKVDEC_SEL_VAL2_BASE 0x430
#define RKVDEC_SET_PERF_SEL(a, b, c) ((a) | ((b) << 8) | ((c) << 16))
/* cache reference register */
#define RKVDEC_REG_CACHE0_SIZE_BASE 0x51c
#define RKVDEC_REG_CACHE1_SIZE_BASE 0x55c
#define RKVDEC_REG_CACHE2_SIZE_BASE 0x59c
#define RKVDEC_REG_CLR_CACHE0_BASE 0x510
#define RKVDEC_REG_CLR_CACHE1_BASE 0x550
#define RKVDEC_REG_CLR_CACHE2_BASE 0x590
#define RKVDEC_CACHE_PERMIT_CACHEABLE_ACCESS BIT(0)
#define RKVDEC_CACHE_PERMIT_READ_ALLOCATE BIT(1)
#define RKVDEC_CACHE_LINE_SIZE_64_BYTES BIT(4)
#define to_rkvdec2_task(task) \
container_of(task, struct rkvdec2_task, mpp_task)
#define to_rkvdec2_dev(dev) \
container_of(dev, struct rkvdec2_dev, mpp)
enum RKVDEC_FMT {
RKVDEC_FMT_H265D = 0,
RKVDEC_FMT_H264D = 1,
RKVDEC_FMT_VP9D = 2,
RKVDEC_FMT_AVS2 = 3,
};
#define RKVDEC_MAX_RCB_NUM (16)
struct rcb_info_elem {
u32 index;
u32 size;
};
struct rkvdec2_rcb_info {
u32 cnt;
struct rcb_info_elem elem[RKVDEC_MAX_RCB_NUM];
};
struct rkvdec2_task {
struct mpp_task mpp_task;
enum MPP_CLOCK_MODE clk_mode;
u32 reg[RKVDEC_REG_NUM];
struct reg_offset_info off_inf;
/* perf sel data back */
u32 reg_sel[RKVDEC_PERF_SEL_NUM];
u32 strm_addr;
u32 irq_status;
/* req for current task */
u32 w_req_cnt;
struct mpp_request w_reqs[MPP_MAX_MSG_NUM];
u32 r_req_cnt;
struct mpp_request r_reqs[MPP_MAX_MSG_NUM];
/* image info */
u32 width;
u32 height;
u32 pixels;
/* task index for link table rnunning list */
int slot_idx;
u32 need_hack;
/* event for task wait timeout or session timeout */
wait_queue_head_t wait;
};
struct rkvdec2_session_priv {
/* codec info from user */
struct {
/* show mode */
u32 flag;
/* item data */
u64 val;
} codec_info[DEC_INFO_BUTT];
/* rcb_info for sram */
struct rkvdec2_rcb_info rcb_inf;
};
struct rkvdec2_dev {
struct mpp_dev mpp;
/* sip smc reset lock */
struct mutex sip_reset_lock;
struct mpp_clk_info aclk_info;
struct mpp_clk_info hclk_info;
struct mpp_clk_info core_clk_info;
struct mpp_clk_info cabac_clk_info;
struct mpp_clk_info hevc_cabac_clk_info;
u32 default_max_load;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *procfs;
#endif
struct reset_control *rst_a;
struct reset_control *rst_h;
struct reset_control *rst_niu_a;
struct reset_control *rst_niu_h;
struct reset_control *rst_core;
struct reset_control *rst_cabac;
struct reset_control *rst_hevc_cabac;
/* internal rcb-memory */
u32 sram_size;
u32 rcb_size;
dma_addr_t rcb_iova;
struct page *rcb_page;
u32 rcb_min_width;
/* for link mode */
struct rkvdec_link_dev *link_dec;
struct mpp_dma_buffer *fix;
};
void *rkvdec2_alloc_task(struct mpp_session *session,
struct mpp_task_msgs *msgs);
int rkvdec2_free_task(struct mpp_session *session, struct mpp_task *mpp_task);
int rkvdec2_free_session(struct mpp_session *session);
int rkvdec2_result(struct mpp_dev *mpp, struct mpp_task *mpp_task,
struct mpp_task_msgs *msgs);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,118 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2021 Rockchip Electronics Co., Ltd
*
* author:
* Herman Chen <herman.chen@rock-chips.com>
*/
#ifndef __ROCKCHIP_MPP_RKVDEC2_LINK_H__
#define __ROCKCHIP_MPP_RKVDEC2_LINK_H__
#include "mpp_rkvdec2.h"
#define RKVDEC_REG_SECOND_EN_BASE 0x30
#define RKVDEC_REG_SECOND_EN_INDEX 12
#define RKVDEC_WAIT_RESET_EN BIT(7)
/* define for link hardware */
#define RKVDEC_LINK_ADD_CFG_NUM 1
#define RKVDEC_LINK_IRQ_BASE 0x000
#define RKVDEC_LINK_BIT_IRQ_DIS BIT(2)
#define RKVDEC_LINK_BIT_IRQ BIT(8)
#define RKVDEC_LINK_BIT_IRQ_RAW BIT(9)
#define RKVDEC_LINK_CFG_ADDR_BASE 0x004
#define RKVDEC_LINK_MODE_BASE 0x008
#define RKVDEC_LINK_BIT_ADD_MODE BIT(31)
#define RKVDEC_LINK_CFG_CTRL_BASE 0x00c
#define RKVDEC_LINK_BIT_CFG_DONE BIT(0)
#define RKVDEC_LINK_DEC_NUM_BASE 0x010
#define RKVDEC_LINK_BIT_DEC_ERROR BIT(31)
#define RKVDEC_LINK_GET_DEC_NUM(x) ((x) & 0x3fffffff)
#define RKVDEC_LINK_TOTAL_NUM_BASE 0x014
#define RKVDEC_LINK_EN_BASE 0x018
#define RKVDEC_LINK_BIT_EN BIT(0)
#define RKVDEC_LINK_NEXT_ADDR_BASE 0x01c
#define RKVDEC_LINK_REG_CYCLE_CNT 179
struct rkvdec_link_dev {
struct device *dev;
struct mpp_dev *mpp;
void __iomem *reg_base;
u32 enabled;
u32 link_mode;
u32 decoded_status;
u32 irq_status;
u32 iova_curr;
u32 iova_next;
u32 decoded;
u32 total;
u32 error;
u32 stuff_err;
u32 stuff_total;
u32 stuff_on_error;
struct rkvdec_link_info *info;
struct mpp_dma_buffer *table;
u32 link_node_size;
u32 link_reg_count;
struct mpp_task **tasks_hw;
u32 task_capacity;
s32 task_total;
s32 task_decoded;
s32 task_size;
s32 task_count;
s32 task_write;
s32 task_read;
s32 task_send;
s32 task_recv;
/* taskqueue variables */
u32 task_running;
u32 task_prepared;
s32 task_to_run;
u32 task_on_timeout;
/* taskqueue trigger variables */
u32 task_irq;
u32 task_irq_prev;
/* timeout can be trigger in different thread so atomic is needed */
atomic_t task_timeout;
u32 task_timeout_prev;
/* link mode hardware status */
atomic_t power_enabled;
u32 irq_enabled;
/* debug variable */
u32 statistic_count;
u64 task_cycle_sum;
u32 task_cnt;
u64 stuff_cycle_sum;
u32 stuff_cnt;
};
int rkvdec_link_dump(struct mpp_dev *mpp);
int rkvdec2_link_init(struct platform_device *pdev, struct rkvdec2_dev *dec);
int rkvdec2_link_procfs_init(struct mpp_dev *mpp);
int rkvdec2_link_remove(struct mpp_dev *mpp, struct rkvdec_link_dev *link_dec);
irqreturn_t rkvdec2_link_irq_proc(int irq, void *param);
int rkvdec2_link_process_task(struct mpp_session *session,
struct mpp_task_msgs *msgs);
int rkvdec2_link_wait_result(struct mpp_session *session,
struct mpp_task_msgs *msgs);
void rkvdec2_link_worker(struct kthread_work *work_s);
void rkvdec2_link_session_deinit(struct mpp_session *session);
#endif