Skip to content
Snippets Groups Projects
Commit 48f8acdd authored by Ding Wei's avatar Ding Wei Committed by Detlev Casanova
Browse files

video: rockchip: mpp: rk3576: hack for decoder


when pd on or resume, need run hack code first.

Change-Id: Ic61a301ec7b34a29b2fb3fe09b557dad4fab8dc7
Signed-off-by: default avatarDing Wei <leo.ding@rock-chips.com>
Signed-off-by: default avatarTao Huang <huangtao@rock-chips.com>
parent 58514fb2
No related branches found
No related tags found
No related merge requests found
......@@ -11,6 +11,6 @@ MPP_REVISION := $(subst ",\\\",$(MPP_REVISION_0))
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_RKVDEC2) += mpp_rkvdec2.o mpp_rkvdec2_link.o
rk_vcodec-$(CONFIG_ROCKCHIP_MPP_RKVDEC2) += mpp_rkvdec2.o mpp_rkvdec2_link.o hack/mpp_hack_rk3576.o
obj-$(CONFIG_ROCKCHIP_MPP_SERVICE) += rk_vcodec.o
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2024 Rockchip Electronics Co., Ltd
*
* author:
* Ding Wei <leo.ding@rock-chips.com>
*/
#include <linux/delay.h>
#include "../mpp_rkvdec2.h"
#include "../mpp_rkvdec2_link.h"
#include "mpp_hack_rk3576.h"
#define RK3576_HACK_DATA_RLC_OFFSET (0)
#define RK3576_HACK_DATA_PPS_OFFSET (RK3576_HACK_DATA_RLC_OFFSET + 64)
#define RK3576_HACK_DATA_RPS_OFFSET (RK3576_HACK_DATA_PPS_OFFSET + 256)
#define RK3576_HACK_DATA_RCB_STRMD_OFFSET (RK3576_HACK_DATA_RPS_OFFSET + 256)
#define RK3576_HACK_DATA_RCB_INTRA_OFFSET (RK3576_HACK_DATA_RCB_STRMD_OFFSET + 256)
#define RK3576_HACK_DATA_OUT_OFFSET (RK3576_HACK_DATA_RCB_INTRA_OFFSET + 512)
#define RK3576_HACK_DATA_COLMV_OFFSET (RK3576_HACK_DATA_OUT_OFFSET + 1536)
#define RK3576_HACK_REGS_OFFSET (4096)
#define RK3576_HACK_REG_NODE_OFFSET (RK3576_HACK_REGS_OFFSET)
#define RK3576_HACK_REG_SEG0_OFFSET (RK3576_HACK_REGS_OFFSET + 32)
#define RK3576_HACK_REG_SEG1_OFFSET (RK3576_HACK_REGS_OFFSET + 256)
#define RK3576_HACK_REG_SEG2_OFFSET (RK3576_HACK_REGS_OFFSET + 512)
#define RK3576_HACK_REG_DEBUG_OFFSET (RK3576_HACK_REGS_OFFSET + 1024)
static const char rk3576_hack_h264_rlc_data[] = {
0x00, 0x00, 0x01, 0x65,
0x88, 0x82, 0x0b, 0x01,
0x2f, 0x08, 0xc5, 0x00,
0x01, 0x51, 0x78, 0xe0,
0x00, 0x24, 0xf7, 0x1c,
0x00, 0x04, 0xcc, 0xeb,
0x89, 0xd7, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00,
};
static const char rk3576_hack_h264_pps_data[] = {
0x40, 0x26, 0x00, 0x10,
0x04, 0x08, 0x00, 0x08,
0x80, 0x01, 0x00, 0x00,
0x00, 0x40, 0x01, 0xd8,
0x07, 0x7c, 0x7a, 0x00,
0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00,
};
int rk3576_workaround_init(struct mpp_dev *mpp)
{
struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
u32 *reg;
/* alloc buffer for node */
dec->fix = mpp_dma_alloc(mpp->dev, 2 * PAGE_SIZE);
if (!dec->fix) {
dev_err(mpp->dev, "failed to create buffer for hack\n");
return -ENOMEM;
}
memset(dec->fix->vaddr, 0, dec->fix->size);
/* set rlc_in */
memcpy(dec->fix->vaddr + RK3576_HACK_DATA_RLC_OFFSET,
rk3576_hack_h264_rlc_data, sizeof(rk3576_hack_h264_rlc_data));
/* set sps_pps */
memcpy(dec->fix->vaddr + RK3576_HACK_DATA_PPS_OFFSET,
rk3576_hack_h264_pps_data, sizeof(rk3576_hack_h264_pps_data));
/* set core registers */
reg = dec->fix->vaddr + RK3576_HACK_REGS_OFFSET;
reg[8] = 0x00000001; // dec_mode
reg[13] = 0x0000ffff; // core time out
reg[16] = 0x00000101; // disable error proc
reg[20] = 0xffffffff; // cabac error low bits
reg[21] = 0x3ff3ffff; // cabac error high bits
reg[64] = RK3576_HACK_MAGIC; // magic number
reg[65] = 0x00000000; // stream start bit
reg[66] = 0x00000020; // stream_len
reg[67] = 0x000000a8; // global_len
reg[68] = 0x00000002; // hor_virstride
reg[69] = 0x00000002; // ver_virstride
reg[70] = 0x00000040; // y_virstride
reg[128] = dec->fix->iova + RK3576_HACK_DATA_RLC_OFFSET; // rlc_base
reg[129] = dec->fix->iova + RK3576_HACK_DATA_RPS_OFFSET; // rps_base
reg[131] = dec->fix->iova + RK3576_HACK_DATA_PPS_OFFSET; // pps_base
reg[140] = dec->fix->iova + RK3576_HACK_DATA_RCB_STRMD_OFFSET; // streamd_rcb
reg[141] = 0x000000c0;
reg[148] = dec->fix->iova + RK3576_HACK_DATA_RCB_INTRA_OFFSET; // intra_rcb
reg[149] = 0x00000200;
reg[168] = dec->fix->iova + RK3576_HACK_DATA_OUT_OFFSET; // decout_base
reg[216] = dec->fix->iova + RK3576_HACK_DATA_COLMV_OFFSET; // colmv_base
/* set link node */
reg = dec->fix->vaddr + RK3576_HACK_REG_NODE_OFFSET;
reg[0] = dec->fix->iova + RK3576_HACK_DATA_OUT_OFFSET; // next link node
reg[1] = 0x76543212; // table info
reg[2] = dec->fix->iova + RK3576_HACK_REG_DEBUG_OFFSET; // debug regs
reg[3] = dec->fix->iova + RK3576_HACK_REG_SEG0_OFFSET; // seg0 regs
reg[4] = dec->fix->iova + RK3576_HACK_REG_SEG1_OFFSET; // seg1 regs
reg[5] = dec->fix->iova + RK3576_HACK_REG_SEG2_OFFSET; // seg2 regs
return 0;
}
int rk3576_workaround_exit(struct mpp_dev *mpp)
{
struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
if (dec->fix)
mpp_dma_free(dec->fix);
return 0;
}
int rk3576_workaround_run(struct mpp_dev *mpp)
{
struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
struct rkvdec_link_dev *link = dec->link_dec;
int ret;
u32 irq_val, status;
if (!dec->fix || !link)
return 0;
/* disable hardware irq */
writel_relaxed(0x00008000, link->reg_base + 0x58);
/* set link registers */
writel_relaxed(0x0007ffff, link->reg_base + 0x54); // set ip time out
writel_relaxed(0x00010001, link->reg_base + 0x00); // ccu mode
writel_relaxed(dec->fix->iova + RK3576_HACK_REG_NODE_OFFSET, link->reg_base + 0x4); // addr
writel_relaxed(0x00000001, link->reg_base + 0x08); // link mode
writel_relaxed(0x00000001, link->reg_base + 0x18); // link en
/* enable hardware */
wmb();
writel(0x01, link->reg_base + 0x0c); // config link
/* wait hardware */
ret = readl_relaxed_poll_timeout_atomic(link->reg_base + 0x48, irq_val, irq_val, 1, 500);
if (ret == -ETIMEDOUT) {
pr_err("%s timeout.\n", __func__);
// return ret;
} else {
status = readl(link->reg_base + 0x4c);
if (status & 0x3fe)
pr_err("%s not ready, status %08x.\n", __func__, status);
}
/* clear irq and status */
writel_relaxed(0xffff0000, link->reg_base + 0x48);
writel_relaxed(0xffff0000, link->reg_base + 0x4c);
/* reset register */
writel_relaxed(0x00000000, link->reg_base + 0x00); // ccu mode
writel_relaxed(0x00000000, link->reg_base + 0x08); // link mode
writel_relaxed(0x00000000, link->reg_base + 0x18); // link en
/* enable irq */
writel(0x00000000, link->reg_base + 0x58);
udelay(5);
return ret;
}
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2024 Rockchip Electronics Co., Ltd
*
* author:
* Ding Wei <leo.ding@rock-chips.com>
*/
#ifndef __ROCKCHIP_MPP_HACK_RK3576_H__
#define __ROCKCHIP_MPP_HACK_RK3576_H__
#define RK3576_HACK_MAGIC (0x76543210)
int rk3576_workaround_init(struct mpp_dev *mpp);
int rk3576_workaround_exit(struct mpp_dev *mpp);
int rk3576_workaround_run(struct mpp_dev *mpp);
#endif
......@@ -253,6 +253,7 @@ struct mpp_hw_info {
int reg_fmt;
u32 reg_ret_status;
void *link_info;
u32 magic_base;
};
struct mpp_trans_info {
......
......@@ -16,6 +16,8 @@
#include "mpp_rkvdec2_link.h"
#include "hack/mpp_hack_rk3576.h"
#include <soc/rockchip/rockchip_iommu.h>
/*
......@@ -62,6 +64,7 @@ static struct mpp_hw_info rkvdec_vdpu383_hw_info = {
.reg_en = 16,
.reg_fmt = 8,
.reg_ret_status = 15,
.magic_base = 0x100,
.link_info = &rkvdec_link_vdpu383_hw_info,
};
......@@ -557,6 +560,7 @@ static int rkvdec_vdpu383_irq(struct mpp_dev *mpp)
/* read and clear status */
mpp->irq_status = readl_relaxed(link->reg_base + link->info->status_base);
writel(link->info->status_mask, link->reg_base + link->info->status_base);
/* wake isr to handle current task */
if (mpp->irq_status & status_bits)
return IRQ_WAKE_THREAD;
......@@ -1030,6 +1034,26 @@ static int rkvdec2_init(struct mpp_dev *mpp)
return ret;
}
static int rkvdec2_rk3576_init(struct mpp_dev *mpp)
{
int ret;
rk3576_workaround_init(mpp);
ret = rkvdec2_init(mpp);
return ret;
}
static int rkvdec2_rk3576_exit(struct mpp_dev *mpp)
{
rkvdec2_devfreq_remove(mpp);
rk3576_workaround_exit(mpp);
return 0;
}
static int rkvdec2_clk_on(struct mpp_dev *mpp)
{
struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
......@@ -1214,8 +1238,9 @@ static struct mpp_hw_ops rkvdec_rk3588_hw_ops = {
.reset = rkvdec2_sip_reset,
};
static struct mpp_hw_ops rkvdec_vdpu383_hw_ops = {
.init = rkvdec2_init,
static struct mpp_hw_ops rkvdec_rk3576_hw_ops = {
.init = rkvdec2_rk3576_init,
.exit = rkvdec2_rk3576_exit,
.clk_on = rkvdec2_clk_on,
.clk_off = rkvdec2_clk_off,
.get_freq = rkvdec2_get_freq,
......@@ -1283,7 +1308,7 @@ static const struct mpp_dev_var rkvdec_rk3576_data = {
.device_type = MPP_DEVICE_RKVDEC,
.hw_info = &rkvdec_vdpu383_hw_info,
.trans_info = rkvdec_vdpu383_trans,
.hw_ops = &rkvdec_vdpu383_hw_ops,
.hw_ops = &rkvdec_rk3576_hw_ops,
.dev_ops = &rkvdec_vdpu383_dev_ops,
};
......@@ -1735,6 +1760,7 @@ static int __maybe_unused rkvdec2_runtime_resume(struct device *dev)
mpp_clk_safe_enable(ccu->aclk_info.clk);
} else {
struct mpp_dev *mpp = dev_get_drvdata(dev);
struct rkvdec2_dev *dec = to_rkvdec2_dev(mpp);
if (mpp->hw_ops->clk_on)
mpp->hw_ops->clk_on(mpp);
......@@ -1745,7 +1771,9 @@ static int __maybe_unused rkvdec2_runtime_resume(struct device *dev)
if (mpp->iommu_info && mpp->iommu_info->got_irq)
enable_irq(mpp->iommu_info->irq);
}
/* work workaround */
if (dec->fix)
rk3576_workaround_run(mpp);
}
return 0;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment