video: rockchip: dvbm: support dvbm module

Signed-off-by: Yandong Lin <yandong.lin@rock-chips.com>
Change-Id: I165a7b0eebb56da76ddc3ab82cb455aee28c0ffe
This commit is contained in:
Yandong Lin
2022-02-08 14:39:05 +08:00
committed by Tao Huang
parent 9ab8c6cff6
commit 5d269355f0
7 changed files with 944 additions and 0 deletions

View File

@@ -5,3 +5,4 @@ source "drivers/video/rockchip/rga3/Kconfig"
source "drivers/video/rockchip/rve/Kconfig"
source "drivers/video/rockchip/iep/Kconfig"
source "drivers/video/rockchip/mpp/Kconfig"
source "drivers/video/rockchip/dvbm/Kconfig"

View File

@@ -5,3 +5,4 @@ obj-$(CONFIG_ROCKCHIP_MULTI_RGA) += rga3/
obj-$(CONFIG_ROCKCHIP_RVE) += rve/
obj-$(CONFIG_IEP) += iep/
obj-$(CONFIG_ROCKCHIP_MPP_SERVICE) += mpp/
obj-$(CONFIG_ROCKCHIP_DVBM) += dvbm/

View File

@@ -0,0 +1,18 @@
# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
menuconfig ROCKCHIP_DVBM
tristate "RK Direct Video Buffer Manager driver"
depends on ARCH_ROCKCHIP
help
rockchip dvbm module.
if ROCKCHIP_DVBM
config ROCKCHIP_DVBM_PROC_FS
bool "enable dvbm procfs"
depends on PROC_FS
default y
help
rockchip dvbm procfs.
endif

View File

@@ -0,0 +1,5 @@
# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
rk_dvbm-objs := rockchip_dvbm.o
obj-$(CONFIG_ROCKCHIP_DVBM) += rk_dvbm.o

View File

@@ -0,0 +1,585 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd
*
* author:
* Yandong Lin, yandong.lin@rock-chips.com
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/proc_fs.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <soc/rockchip/rockchip_dvbm.h>
#include "rockchip_dvbm.h"
#define RK_DVBM "rk_dvbm"
unsigned int dvbm_debug;
module_param(dvbm_debug, uint, 0644);
MODULE_PARM_DESC(dvbm_debug, "bit switch for dvbm debug information");
static struct dvbm_ctx *g_ctx;
#define DVBM_LINK_WAIT_TIMEOUT_MS (1000)
#define DVBM_DEBUG 0x00000001
#define DVBM_DEBUG_IRQ 0x00000002
#define DVBM_DEBUG_REG 0x00000004
#define dvbm_debug(fmt, args...) \
do { \
if (unlikely(dvbm_debug & (DVBM_DEBUG))) \
pr_info(fmt, ##args); \
} while (0)
#define dvbm_debug_reg(fmt, args...) \
do { \
if (unlikely(dvbm_debug & (DVBM_DEBUG_REG))) \
pr_info(fmt, ##args); \
} while (0)
#define dvbm_debug_irq(fmt, args...) \
do { \
if (unlikely(dvbm_debug & (DVBM_DEBUG_IRQ))) \
pr_info(fmt, ##args); \
} while (0)
#define dvbm_err(fmt, args...) \
pr_err(fmt, ##args)
enum dvbm_flow {
ISP_CFG = 1,
ISP_CONNECT = 2,
VEPU_CFG = 3,
VEPU_CONNECT = 4,
};
/* dvbm status reg bit value define */
#define BUF_OVERFLOW BIT(0)
#define RESYNC_FINISH BIT(1)
#define ISP_CNCT_TIMEOUT BIT(2)
#define VEPU_CNCT_TIMEOUT BIT(3)
#define VEPU_HANDSHAKE_TIMEOUT BIT(4)
#define ISP_CNCT BIT(5)
#define ISP_DISCNCT BIT(6)
#define VEPU_CNCT BIT(7)
#define VEPU_DISCNCT BIT(8)
/* dvbm reg addr define */
#define DVBM_VERSION 0x0
#define DVBM_ISP_CNCT 0x4
#define DVBM_VEPU_CNCT 0x8
/* cfg regs */
#define DVBM_CFG 0xC
#define DVBM_WDG_CFG0 0x10
#define DVBM_WDG_CFG1 0x14
#define DVBM_WDG_CFG2 0x18
/* interrupt regs */
#define DVBM_INT_EN 0x1c
#define DVBM_INT_MSK 0x20
#define DVBM_INT_CLR 0x24
#define DVBM_INT_ST 0x28
/* addr regs */
#define DVBM_YBUF_BOT 0x2c
#define DVBM_YBUF_TOP 0x30
#define DVBM_YBUF_SADR 0x34
#define DVBM_YBUF_LSTD 0x38
#define DVBM_YBUF_FSTD 0x3c
#define DVBM_CBUF_BOT 0x40
#define DVBM_CBUF_TOP 0x44
#define DVBM_CBUF_SADR 0x48
#define DVBM_CBUF_LSTD 0x4c
#define DVBM_CBUF_FSTD 0x50
#define DVBM_AFUL_THDY 0x54
#define DVBM_AFUL_THDC 0x58
#define DVBM_OVFL_THDY 0x5c
#define DVBM_OVFL_THDC 0x60
/* status regs */
#define DVBM_ST 0x80
#define DVBM_OVFL_ST 0x84
static void rk_dvbm_set_reg(struct dvbm_ctx *ctx, u32 offset, u32 val)
{
dvbm_debug_reg("write reg[%d] 0x%x = 0x%08x\n", offset >> 2, offset, val);
writel(val, ctx->reg_base + offset);
}
static u32 rk_dvbm_read_reg(struct dvbm_ctx *ctx, u32 offset)
{
u32 val = readl(ctx->reg_base + offset);
dvbm_debug_reg("read reg[%d] 0x%x = 0x%08x\n", offset >> 2, offset, val);
return val;
}
static struct dvbm_ctx *port_to_ctx(struct dvbm_port *port)
{
struct dvbm_ctx *ctx = NULL;
if (IS_ERR_OR_NULL(port))
return g_ctx;
if (port->dir == DVBM_ISP_PORT)
ctx = container_of(port, struct dvbm_ctx, port_isp);
else if (port->dir == DVBM_VEPU_PORT)
ctx = container_of(port, struct dvbm_ctx, port_vepu);
return ctx;
}
static void dvbm2enc_callback(struct dvbm_ctx *ctx, enum dvbm_cb_event event, void *arg)
{
struct dvbm_cb *callback = &ctx->vepu_cb;
dvbm_callback cb = callback->cb;
if (cb)
cb(callback->ctx, event, arg);
}
static void rk_dvbm_dump_regs(struct dvbm_ctx *ctx)
{
u32 start = 0x4;
u32 end = 0xb8;
u32 i;
for (i = start; i <= end; i += 4)
dvbm_debug("reg[0x%0x] = 0x%08x\n", i, readl(ctx->reg_base + i));
}
struct dvbm_port *rk_dvbm_get_port(struct platform_device *pdev,
enum dvbm_port_dir dir)
{
struct dvbm_ctx *ctx = NULL;
struct dvbm_port *port = NULL;
if (WARN_ON(!pdev))
return NULL;
ctx = (struct dvbm_ctx *)platform_get_drvdata(pdev);
WARN_ON(!ctx);
dvbm_debug("%s dir %d\n", __func__, dir);
if (dir == DVBM_ISP_PORT)
port = &ctx->port_isp;
else if (dir == DVBM_VEPU_PORT)
port = &ctx->port_vepu;
return port;
}
EXPORT_SYMBOL(rk_dvbm_get_port);
int rk_dvbm_put(struct dvbm_port *port)
{
struct dvbm_ctx *ctx = NULL;
if (WARN_ON(!port))
return -EINVAL;
ctx = port_to_ctx(port);
if (!ctx)
return -EINVAL;
return 0;
}
EXPORT_SYMBOL(rk_dvbm_put);
int rk_dvbm_link(struct dvbm_port *port)
{
struct dvbm_ctx *ctx;
enum dvbm_port_dir dir;
struct rk_dvbm_regs *reg;
int ret;
if (WARN_ON(!port))
return -EINVAL;
ctx = port_to_ctx(port);
dir = port->dir;
reg = &ctx->regs;
if (dir == DVBM_ISP_PORT) {
if (port->linked) {
rk_dvbm_unlink(port);
udelay(5);
}
reg->isp_cnct.isp_cnct = 1;
rk_dvbm_set_reg(ctx, DVBM_ISP_CNCT, 0x1);
} else if (dir == DVBM_VEPU_PORT) {
reg->vepu_cnct.vepu_cnct = 1;
rk_dvbm_set_reg(ctx, DVBM_VEPU_CNCT, 0x1);
}
ret = wait_event_timeout(ctx->link_wait, port->linked,
msecs_to_jiffies(DVBM_LINK_WAIT_TIMEOUT_MS));
if (ret > 0)
dvbm_debug("%s connect frm_cnt[%d : %d]\n",
dir == DVBM_ISP_PORT ? "isp" : "vepu",
ctx->isp_frm_start, ctx->isp_frm_end);
else
dvbm_err("%s connect timeout!!! frm cnt[%d : %d]\n",
dir == DVBM_ISP_PORT ? "isp" : "vepu",
ctx->isp_frm_start, ctx->isp_frm_end);
return ret;
}
EXPORT_SYMBOL(rk_dvbm_link);
int rk_dvbm_unlink(struct dvbm_port *port)
{
struct dvbm_ctx *ctx;
enum dvbm_port_dir dir;
struct rk_dvbm_regs *reg;
if (WARN_ON(!port))
return -EINVAL;
ctx = port_to_ctx(port);
dir = port->dir;
reg = &ctx->regs;
if (dir == DVBM_ISP_PORT) {
reg->isp_cnct.isp_cnct = 0;
rk_dvbm_set_reg(ctx, DVBM_ISP_CNCT, 0);
} else if (dir == DVBM_VEPU_PORT) {
reg->vepu_cnct.vepu_cnct = 0;
rk_dvbm_set_reg(ctx, DVBM_VEPU_CNCT, 0);
if (!ctx->regs.dvbm_cfg.auto_resyn) {
u32 connect = 0;
dvbm2enc_callback(ctx, DVBM_VEPU_REQ_CONNECT, &connect);
}
}
dvbm_debug("%s disconnect\n", dir == DVBM_ISP_PORT ? "isp" : "vepu");
return 0;
}
EXPORT_SYMBOL(rk_dvbm_unlink);
int rk_dvbm_set_cb(struct dvbm_port *port, struct dvbm_cb *cb)
{
struct dvbm_ctx *ctx;
enum dvbm_port_dir dir;
if (WARN_ON(!port) || WARN_ON(!cb))
return -EINVAL;
ctx = port_to_ctx(port);
dir = port->dir;
if (dir == DVBM_ISP_PORT) {
} else if (dir == DVBM_VEPU_PORT) {
ctx->vepu_cb.cb = cb->cb;
ctx->vepu_cb.ctx = cb->ctx;
}
return 0;
}
EXPORT_SYMBOL(rk_dvbm_set_cb);
int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg)
{
struct dvbm_ctx *ctx;
struct rk_dvbm_regs *reg;
if (WARN_ON(!port) || WARN_ON(!arg))
return -EINVAL;
if ((cmd < DVBM_ISP_CMD_BASE) || (cmd > DVBM_VEPU_CMD_BUTT)) {
dvbm_err("%s input cmd invalid\n", __func__);
return -EINVAL;
}
ctx = port_to_ctx(port);
reg = &ctx->regs;
switch (cmd) {
case DVBM_ISP_SET_CFG: {
struct dvbm_isp_cfg_t *cfg = (struct dvbm_isp_cfg_t *)arg;
struct rk_dvbm_base *addr_base = &reg->addr_base;
addr_base->ybuf_bot = cfg->dma_addr + cfg->ybuf_bot;
addr_base->ybuf_top = cfg->dma_addr + cfg->ybuf_top;
addr_base->ybuf_sadr = cfg->dma_addr + cfg->ybuf_bot;
addr_base->ybuf_fstd = cfg->ybuf_fstd;
addr_base->ybuf_lstd = cfg->ybuf_lstd;
addr_base->cbuf_bot = cfg->dma_addr + cfg->cbuf_bot;
addr_base->cbuf_top = cfg->dma_addr + cfg->cbuf_top;
addr_base->cbuf_sadr = cfg->dma_addr + cfg->cbuf_bot;
addr_base->cbuf_fstd = cfg->cbuf_fstd;
addr_base->cbuf_lstd = cfg->cbuf_lstd;
addr_base->aful_thdy = cfg->ybuf_lstd;
addr_base->aful_thdc = cfg->ybuf_lstd;
addr_base->oful_thdy = cfg->ybuf_lstd;
addr_base->oful_thdc = cfg->ybuf_lstd;
dvbm_debug("dma_addr 0x%08x y_lstd %d y_fstd %d\n",
cfg->dma_addr, cfg->ybuf_lstd, cfg->ybuf_fstd);
dvbm_debug("ybot 0x%x top 0x%x cbuf bot 0x%x top 0x%x\n",
addr_base->ybuf_bot, addr_base->ybuf_top,
addr_base->cbuf_bot, addr_base->cbuf_top);
{
u32 *data = (u32 *)&reg->addr_base;
u32 i;
for (i = 0; i < sizeof(struct rk_dvbm_base) / sizeof(u32); i++)
rk_dvbm_set_reg(ctx, i * sizeof(u32), data[i]);
}
} break;
case DVBM_ISP_FRM_START: {
ctx->isp_frm_start = *(u32 *)arg;
dvbm_debug("isp frame start[%d : %d]\n",
ctx->isp_frm_start, ctx->isp_frm_end);
dvbm2enc_callback(ctx, DVBM_VEPU_NOTIFY_FRM_STR, &ctx->isp_frm_start);
} break;
case DVBM_ISP_FRM_END: {
u64 ns;
ns = ktime_get_ns();
ctx->isp_frm_end = *(u32 *)arg;
if (ctx->isp_frm_ns) {
u64 interval = ns - ctx->isp_frm_ns;
dvbm_debug("isp frame end[%d : %d] times %lld ns\n",
ctx->isp_frm_start, ctx->isp_frm_end, interval);
}
ctx->isp_frm_ns = ns;
dvbm2enc_callback(ctx, DVBM_VEPU_NOTIFY_FRM_END, &ctx->isp_frm_end);
} break;
case DVBM_VEPU_GET_ADR: {
struct dvbm_addr_cfg *dvbm_adr = (struct dvbm_addr_cfg *)arg;
struct rk_dvbm_base *addr_base = &reg->addr_base;
dvbm_adr->ybuf_top = addr_base->ybuf_top;
dvbm_adr->ybuf_bot = addr_base->ybuf_bot;
dvbm_adr->cbuf_top = addr_base->cbuf_top;
dvbm_adr->cbuf_bot = addr_base->cbuf_bot;
} break;
case DVBM_VEPU_GET_CUR_ID: {
*(u32 *)arg = ctx->isp_frm_start;
} break;
case DVBM_VEPU_SET_RESYNC: {
reg->dvbm_cfg.auto_resyn = *(u32 *)arg;
dev_info(ctx->dev, "change resync %s\n",
reg->dvbm_cfg.auto_resyn ? "auto" : "soft");
rk_dvbm_set_reg(ctx, DVBM_CFG, ((u32 *)&reg->dvbm_cfg)[0]);
} break;
case DVBM_VEPU_DUMP_REGS: {
rk_dvbm_dump_regs(ctx);
} break;
default: {
} break;
}
return 0;
}
EXPORT_SYMBOL(rk_dvbm_ctrl);
static void rk_dvbm_reg_init(struct dvbm_ctx *ctx)
{
struct rk_dvbm_regs *reg = &ctx->regs;
u32 *val = (u32 *)reg;
reg->int_en.buf_ovfl = 1;
reg->int_en.isp_cnct = 1;
reg->int_en.vepu_cnct = 1;
reg->int_en.vepu_discnct = 1;
reg->int_en.isp_discnct = 1;
reg->int_en.resync_finish = 1;
reg->int_en.isp_cnct_timeout = 1;
reg->int_en.vepu_cnct_timeout = 1;
reg->int_en.vepu_handshake_timeout = 1;
reg->dvbm_cfg.fmt = 0;
reg->dvbm_cfg.auto_resyn = 0;
reg->dvbm_cfg.ignore_vepu_cnct_ack = 0;
reg->dvbm_cfg.start_point_after_vepu_cnct = 0;
reg->wdg_cfg0.wdg_isp_cnct_timeout = 0xfffff;
reg->wdg_cfg1.wdg_vepu_cnct_timeout = 0xfffff;
reg->wdg_cfg2.wdg_vepu_handshake_timeout = 0xfffff;
rk_dvbm_set_reg(ctx, DVBM_WDG_CFG0, val[DVBM_WDG_CFG0 >> 2]);
rk_dvbm_set_reg(ctx, DVBM_WDG_CFG1, val[DVBM_WDG_CFG1 >> 2]);
rk_dvbm_set_reg(ctx, DVBM_WDG_CFG2, val[DVBM_WDG_CFG2 >> 2]);
rk_dvbm_set_reg(ctx, DVBM_CFG, val[DVBM_CFG >> 2]);
rk_dvbm_set_reg(ctx, DVBM_INT_EN, val[DVBM_INT_EN >> 2]);
}
static void dvbm_check_irq(struct dvbm_ctx *ctx)
{
u32 irq_st = ctx->irq_status;
u32 cur_st = ctx->dvbm_status;
if (irq_st & ISP_CNCT) {
dvbm_debug_irq("%s isp connect success! st 0x%08x\n",
__func__, cur_st);
ctx->port_isp.linked = 1;
wake_up(&ctx->link_wait);
}
if (irq_st & ISP_DISCNCT) {
dvbm_debug_irq("%s isp disconnect success!\n", __func__);
ctx->port_isp.linked = 0;
}
if (irq_st & VEPU_CNCT) {
dvbm_debug_irq("%s vepu connect success! st 0x%08x\n",
__func__, cur_st);
ctx->port_vepu.linked = 1;
wake_up(&ctx->link_wait);
}
if (irq_st & VEPU_DISCNCT) {
dvbm_debug_irq("%s vepu disconnect success! st 0x%08x\n", __func__, cur_st);
ctx->port_vepu.linked = 0;
}
if (irq_st & BUF_OVERFLOW) {
dvbm_debug_irq("%s buffer overflow st 0x%08x auto_resync %d\n",
__func__, cur_st, ctx->regs.dvbm_cfg.auto_resyn);
if (!ctx->regs.dvbm_cfg.auto_resyn)
rk_dvbm_unlink(&ctx->port_vepu);
}
if (irq_st & (ISP_CNCT_TIMEOUT | VEPU_CNCT_TIMEOUT))
rk_dvbm_dump_regs(ctx);
}
static irqreturn_t rk_dvbm_irq(int irq, void *param)
{
struct dvbm_ctx *ctx = param;
u32 irq_st = 0;
u32 cur_st = 0;
if (ctx->reg_base) {
/* read irq st */
irq_st = rk_dvbm_read_reg(ctx, DVBM_INT_ST);
cur_st = rk_dvbm_read_reg(ctx, DVBM_ST);
/* clr irq */
rk_dvbm_set_reg(ctx, DVBM_INT_CLR, irq_st);
rk_dvbm_set_reg(ctx, DVBM_INT_ST, 0);
}
ctx->irq_status = irq_st;
ctx->dvbm_status = cur_st;
dvbm_debug_irq("%s irq status 0x%08x\n", __func__, irq_st);
return IRQ_WAKE_THREAD;
}
static irqreturn_t rk_dvbm_isr(int irq, void *param)
{
struct dvbm_ctx *ctx = param;
dvbm_check_irq(ctx);
return IRQ_HANDLED;
}
static int rk_dvbm_probe(struct platform_device *pdev)
{
int ret;
struct dvbm_ctx *ctx = NULL;
struct device *dev = &pdev->dev;
struct resource *res = NULL;
dev_info(dev, "probe start\n");
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
dev_info(dev, "dvbm ctx %p\n", ctx);
ctx->dev = dev;
atomic_set(&ctx->isp_ref, 0);
atomic_set(&ctx->vepu_ref, 0);
ctx->port_isp.dir = DVBM_ISP_PORT;
ctx->port_vepu.dir = DVBM_VEPU_PORT;
platform_set_drvdata(pdev, ctx);
pm_runtime_enable(dev);
/* get irq */
ctx->irq = platform_get_irq(pdev, 0);
if (ctx->irq < 0) {
dev_err(&pdev->dev, "no interrupt resource found\n");
ret = -ENODEV;
goto failed;
}
/* get mem resource */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no memory resource defined\n");
ret = -ENODEV;
goto failed;
}
ctx->reg_base = devm_ioremap_resource(dev, res);
if (!ctx->reg_base) {
dev_err(dev, "ioremap failed for resource %pR\n", res);
ret = -ENOMEM;
goto failed;
}
g_ctx = ctx;
rk_dvbm_reg_init(ctx);
init_waitqueue_head(&ctx->link_wait);
ret = devm_request_threaded_irq(dev, ctx->irq,
rk_dvbm_irq, rk_dvbm_isr,
IRQF_ONESHOT, dev_name(dev), ctx);
if (ret) {
dev_err(dev, "register interrupter failed\n");
goto failed;
}
dev_info(dev, "probe success\n");
return 0;
failed:
pm_runtime_disable(dev);
return ret;
}
static int rk_dvbm_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
dev_info(dev, "remove device\n");
pm_runtime_disable(dev);
return 0;
}
static const struct of_device_id rk_dvbm_dt_ids[] = {
{
.compatible = "rockchip,rk-dvbm",
},
{ },
};
static struct platform_driver rk_dvbm_driver = {
.probe = rk_dvbm_probe,
.remove = rk_dvbm_remove,
.driver = {
.name = "rk_dvbm",
.of_match_table = of_match_ptr(rk_dvbm_dt_ids),
},
};
static int __init rk_dvbm_init(void)
{
return platform_driver_register(&rk_dvbm_driver);
}
static __exit void rk_dvbm_exit(void)
{
platform_driver_unregister(&rk_dvbm_driver);
}
subsys_initcall(rk_dvbm_init);
module_exit(rk_dvbm_exit);
MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Yandong Lin yandong.lin@rock-chips.com");
MODULE_DESCRIPTION("Rockchip dvbm driver");

View File

@@ -0,0 +1,205 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd
*/
#ifndef __ROCKCHIP_DVBM_H__
#define __ROCKCHIP_DVBM_H__
struct rk_dvbm_base {
/* 0x2c */
u32 ybuf_bot;
/* 0x30 */
u32 ybuf_top;
/* 0x34 */
u32 ybuf_sadr;
/* 0x38 */
u32 ybuf_lstd;
/* 0x3c */
u32 ybuf_fstd;
/* 0x40 */
u32 cbuf_bot;
/* 0x44 */
u32 cbuf_top;
/* 0x48 */
u32 cbuf_sadr;
/* 0x4c */
u32 cbuf_lstd;
/* 0x50 */
u32 cbuf_fstd;
/* 0x54 */
u32 aful_thdy;
/* 0x58 */
u32 aful_thdc;
/* 0x5c */
u32 oful_thdy;
/* 0x60 */
u32 oful_thdc;
};
struct rk_dvbm_regs {
/* 0x0 */
u32 version;
/* 0x4 */
struct {
u32 isp_cnct : 1;
u32 reserved : 31;
} isp_cnct;
/* 0x8 */
struct {
u32 vepu_cnct : 1;
u32 reserved : 31;
} vepu_cnct;
/* 0xc */
struct {
u32 auto_resyn : 1;
u32 ignore_vepu_cnct_ack : 1;
/*
* 1b0 : the current ISP frame
* 1b1 : the next ISP frame
*/
u32 start_point_after_vepu_cnct : 1;
u32 reserved0 : 5;
/* only support yuv420sp 4'h0 */
u32 fmt : 4;
u32 reserved1 : 20;
} dvbm_cfg;
/* 0x10 */
struct {
u32 wdg_isp_cnct_timeout : 22;
u32 reserved : 10;
} wdg_cfg0;
/* 0x14 */
struct {
u32 wdg_vepu_cnct_timeout : 22;
u32 reserved : 10;
} wdg_cfg1;
/* 0x18 */
struct {
u32 wdg_vepu_handshake_timeout : 22;
u32 reserved : 10;
} wdg_cfg2;
/* 0x1c */
struct {
u32 buf_ovfl : 1;
u32 resync_finish : 1;
u32 isp_cnct_timeout : 1;
u32 vepu_cnct_timeout : 1;
u32 vepu_handshake_timeout : 1;
u32 isp_cnct : 1;
u32 isp_discnct : 1;
u32 vepu_cnct : 1;
u32 vepu_discnct : 1;
u32 reserved : 23;
} int_en;
/* 0x20 */
struct {
u32 buf_ovfl : 1;
u32 resync_finish : 1;
u32 isp_cnct_timeout : 1;
u32 vepu_cnct_timeout : 1;
u32 vepu_handshake_timeout : 1;
u32 isp_cnct : 1;
u32 isp_discnct : 1;
u32 vepu_cnct : 1;
u32 vepu_discnct : 1;
u32 reserved : 23;
} int_msk;
/* 0x24 */
struct {
u32 buf_ovfl : 1;
u32 resync_finish : 1;
u32 isp_cnct_timeout : 1;
u32 vepu_cnct_timeout : 1;
u32 vepu_handshake_timeout : 1;
u32 isp_cnct : 1;
u32 isp_discnct : 1;
u32 vepu_cnct : 1;
u32 vepu_discnct : 1;
u32 reserved : 23;
} int_clr;
/* 0x28 */
struct {
u32 buf_ovfl : 1;
u32 resync_finish : 1;
u32 isp_cnct_timeout : 1;
u32 vepu_cnct_timeout : 1;
u32 vepu_handshake_timeout : 1;
u32 isp_cnct : 1;
u32 isp_discnct : 1;
u32 vepu_cnct : 1;
u32 vepu_discnct : 1;
u32 reserved : 23;
} int_st;
struct rk_dvbm_base addr_base;
/* 0x64 - 0x7c */
u32 reserved[7];
/* 0x80 */
struct {
u32 isp_connection : 1;
u32 vepu_connection : 1;
u32 resynchronization : 1;
u32 y_buf_ovfl : 1;
u32 c_buf_ovfl : 1;
u32 reserved : 27;
} dvbm_st;
/* 0x84 */
u32 ovfl_st;
};
struct dvbm_ctx {
struct device *dev;
void __iomem *reg_base;
struct rk_dvbm_regs regs;
u32 isp_connet;
u32 vepu_connet;
u32 buf_overflow;
u32 irq_status;
u32 dvbm_status;
int irq;
struct dvbm_port port_isp;
struct dvbm_port port_vepu;
atomic_t isp_ref;
atomic_t vepu_ref;
atomic_t isp_link;
atomic_t vepu_link;
struct dvbm_cb vepu_cb;
struct dvbm_cb isp_cb;
u32 isp_frm_start;
u32 isp_frm_end;
u64 isp_frm_ns;
wait_queue_head_t link_wait;
#ifdef CONFIG_ROCKCHIP_MPP_PROC_FS
struct proc_dir_entry *procfs;
#endif
};
#endif

View File

@@ -0,0 +1,129 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd
*/
#ifndef __SOC_ROCKCHIP_DVBM_H
#define __SOC_ROCKCHIP_DVBM_H
#include <linux/dma-buf.h>
#include <linux/platform_device.h>
enum dvbm_port_dir {
DVBM_ISP_PORT,
DVBM_VEPU_PORT,
};
enum dvbm_cmd {
DVBM_ISP_CMD_BASE = 0,
DVBM_ISP_SET_CFG,
DVBM_ISP_FRM_START,
DVBM_ISP_FRM_END,
DVBM_ISP_CMD_BUTT,
DVBM_VEPU_CMD_BASE = 0x10,
DVBM_VEPU_SET_RESYNC,
DVBM_VEPU_GET_ADR,
DVBM_VEPU_GET_CUR_ID,
DVBM_VEPU_DUMP_REGS,
DVBM_VEPU_CMD_BUTT,
};
enum dvbm_cb_event {
DVBM_ISP_EVENT_BASE = 0,
DVBM_ISP_EVENT_BUTT,
DVBM_VEPU_EVENT_BASE = 0x10,
DVBM_VEPU_NOTIFY_ADDR,
DVBM_VEPU_REQ_CONNECT,
DVBM_VEPU_NOTIFY_FRM_STR,
DVBM_VEPU_NOTIFY_FRM_END,
DVBM_VEPU_EVENT_BUTT,
};
struct dvbm_port {
enum dvbm_port_dir dir;
u32 linked;
};
struct dvbm_isp_cfg_t {
u32 fmt;
u32 timeout;
struct dmabuf *buf;
dma_addr_t dma_addr;
u32 ybuf_top;
u32 ybuf_bot;
u32 ybuf_lstd;
u32 ybuf_fstd;
u32 cbuf_top;
u32 cbuf_bot;
u32 cbuf_lstd;
u32 cbuf_fstd;
};
struct dvbm_isp_frm_cfg {
s32 frm_idx;
u32 ybuf_start;
u32 cbuf_start;
};
struct dvbm_addr_cfg {
u32 ybuf_top;
u32 ybuf_bot;
u32 cbuf_top;
u32 cbuf_bot;
};
typedef int (*dvbm_callback)(void *ctx, enum dvbm_cb_event event, void *arg);
struct dvbm_cb {
dvbm_callback cb;
void *ctx;
int event;
};
#if IS_ENABLED(CONFIG_ROCKCHIP_DVBM)
struct dvbm_port *rk_dvbm_get_port(struct platform_device *pdev,
enum dvbm_port_dir dir);
int rk_dvbm_put(struct dvbm_port *port);
int rk_dvbm_link(struct dvbm_port *port);
int rk_dvbm_unlink(struct dvbm_port *port);
int rk_dvbm_set_cb(struct dvbm_port *port, struct dvbm_cb *cb);
int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg);
#else
static inline struct dvbm_port *rk_dvbm_get_port(struct platform_device *pdev,
enum dvbm_port_dir dir)
{
return ERR_PTR(-ENODEV);
}
static inline int rk_dvbm_put(struct dvbm_port *port)
{
return -ENODEV;
}
static inline int rk_dvbm_link(struct dvbm_port *port)
{
return -ENODEV;
}
static inline int rk_dvbm_unlink(struct dvbm_port *port)
{
return -ENODEV;
}
static inline int rk_dvbm_set_cb(struct dvbm_port *port, struct dvbm_cb *cb)
{
return -ENODEV;
}
static inline int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg)
{
return -ENODEV;
}
#endif
#endif