mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
video: rockchip: dvbm: support soft dvbm
Signed-off-by: Yandong Lin <yandong.lin@rock-chips.com> Change-Id: I7585e59fbc8fac053e0d03fddc3f23e974c19508
This commit is contained in:
@@ -110,10 +110,14 @@ enum dvbm_flow {
|
||||
|
||||
#define DVBM_REG_OFFSET 0x2c
|
||||
|
||||
#define SOFT_DVBM
|
||||
|
||||
static void rk_dvbm_set_reg(struct dvbm_ctx *ctx, u32 offset, u32 val)
|
||||
{
|
||||
#ifndef SOFT_DVBM
|
||||
dvbm_debug_reg("write reg[%d] 0x%x = 0x%08x\n", offset >> 2, offset, val);
|
||||
writel(val, ctx->reg_base + offset);
|
||||
#endif
|
||||
}
|
||||
|
||||
static u32 rk_dvbm_read_reg(struct dvbm_ctx *ctx, u32 offset)
|
||||
@@ -143,6 +147,8 @@ static void dvbm2enc_callback(struct dvbm_ctx *ctx, enum dvbm_cb_event event, vo
|
||||
struct dvbm_cb *callback = &ctx->vepu_cb;
|
||||
dvbm_callback cb = callback->cb;
|
||||
|
||||
if (!ctx->port_vepu.linked)
|
||||
return;
|
||||
if (cb)
|
||||
cb(callback->ctx, event, arg);
|
||||
}
|
||||
@@ -180,14 +186,63 @@ static void init_isp_infos(struct dvbm_ctx *ctx)
|
||||
{
|
||||
ctx->isp_frm_start = 0;
|
||||
ctx->isp_frm_end = 0;
|
||||
ctx->isp_frm_ns = 0;
|
||||
ctx->isp_frm_time = 0;
|
||||
}
|
||||
|
||||
static int rk_dvbm_setup_iobuf(struct dvbm_ctx *ctx, struct rk_dvbm_base *addr_base)
|
||||
static void rk_dvbm_show_time(struct dvbm_ctx *ctx)
|
||||
{
|
||||
u32 *data = (u32 *)addr_base;
|
||||
u32 i;
|
||||
ktime_t time = ktime_get();
|
||||
|
||||
if (ctx->isp_frm_time)
|
||||
dvbm_debug("isp frame start[%d : %d] times %lld us\n",
|
||||
ctx->isp_frm_start, ctx->isp_frm_end,
|
||||
ktime_us_delta(time, ctx->isp_frm_time));
|
||||
ctx->isp_frm_time = time;
|
||||
}
|
||||
|
||||
static void rk_dvbm_update_isp_frm_info(struct dvbm_ctx *ctx, u32 line_cnt)
|
||||
{
|
||||
struct dvbm_isp_frm_info *frm_info = &ctx->isp_frm_info;
|
||||
|
||||
/* wrap frame_cnt 0 - 255 */
|
||||
frm_info->frame_cnt = ctx->isp_frm_start % 256;
|
||||
frm_info->line_cnt = line_cnt;
|
||||
dvbm2enc_callback(ctx, DVBM_VEPU_NOTIFY_FRM_INFO, frm_info);
|
||||
|
||||
}
|
||||
|
||||
static int rk_dvbm_setup_iobuf(struct dvbm_ctx *ctx)
|
||||
{
|
||||
u32 *data;
|
||||
u32 i;
|
||||
struct rk_dvbm_base *addr_base = &ctx->regs.addr_base;
|
||||
struct dvbm_isp_cfg_t *cfg = &ctx->isp_cfg;
|
||||
|
||||
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;
|
||||
|
||||
ctx->isp_max_lcnt = cfg->ybuf_fstd / 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);
|
||||
|
||||
data = (u32 *)addr_base;
|
||||
for (i = 0; i < sizeof(struct rk_dvbm_base) / sizeof(u32); i++)
|
||||
rk_dvbm_set_reg(ctx, i * sizeof(u32) + DVBM_REG_OFFSET, data[i]);
|
||||
|
||||
@@ -287,6 +342,7 @@ int rk_dvbm_link(struct dvbm_port *port)
|
||||
reg->vepu_cnct.vepu_cnct = 1;
|
||||
rk_dvbm_set_reg(ctx, DVBM_VEPU_CNCT, 0x1);
|
||||
}
|
||||
port->linked = 1;
|
||||
dvbm_debug_dump("=== vepu link ===\n");
|
||||
rk_dvbm_dump_regs(ctx);
|
||||
dvbm_debug_dump("=== vepu link ===\n");
|
||||
@@ -318,6 +374,7 @@ int rk_dvbm_unlink(struct dvbm_port *port)
|
||||
rk_dvbm_set_reg(ctx, DVBM_ISP_CNCT, 0);
|
||||
} else if (dir == DVBM_VEPU_PORT) {
|
||||
reg->vepu_cnct.vepu_cnct = 0;
|
||||
port->linked = 0;
|
||||
rk_dvbm_set_reg(ctx, DVBM_VEPU_CNCT, 0);
|
||||
if (!ctx->regs.dvbm_cfg.auto_resyn) {
|
||||
u32 connect = 0;
|
||||
@@ -353,13 +410,27 @@ int rk_dvbm_set_cb(struct dvbm_port *port, struct dvbm_cb *cb)
|
||||
}
|
||||
EXPORT_SYMBOL(rk_dvbm_set_cb);
|
||||
|
||||
static void rk_dvbm_update_next_adr(struct dvbm_ctx *ctx)
|
||||
{
|
||||
u32 frame_cnt = ctx->isp_frm_info.frame_cnt;
|
||||
struct dvbm_isp_cfg_t *isp_cfg = &ctx->isp_cfg;
|
||||
struct dvbm_addr_cfg *vepu_cfg = &ctx->vepu_cfg;
|
||||
u32 y_wrap_size = isp_cfg->ybuf_top - isp_cfg->ybuf_bot;
|
||||
u32 c_wrap_size = isp_cfg->cbuf_top - isp_cfg->cbuf_bot;
|
||||
u32 s_off;
|
||||
|
||||
s_off = (frame_cnt * isp_cfg->ybuf_fstd) % y_wrap_size;
|
||||
vepu_cfg->ybuf_sadr = isp_cfg->dma_addr + isp_cfg->ybuf_bot + s_off;
|
||||
|
||||
s_off = (frame_cnt * isp_cfg->cbuf_fstd) % c_wrap_size;
|
||||
vepu_cfg->cbuf_sadr = isp_cfg->dma_addr + isp_cfg->cbuf_bot + s_off;
|
||||
}
|
||||
|
||||
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(!arg))
|
||||
return -EINVAL;
|
||||
if ((cmd < DVBM_ISP_CMD_BASE) || (cmd > DVBM_VEPU_CMD_BUTT)) {
|
||||
dvbm_err("%s input cmd invalid\n", __func__);
|
||||
return -EINVAL;
|
||||
@@ -371,52 +442,32 @@ int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg)
|
||||
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 = ®->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);
|
||||
rk_dvbm_setup_iobuf(ctx, addr_base);
|
||||
memcpy(&ctx->isp_cfg, cfg, sizeof(struct dvbm_isp_cfg_t));
|
||||
rk_dvbm_setup_iobuf(ctx);
|
||||
rk_dvbm_reg_init(ctx);
|
||||
init_isp_infos(ctx);
|
||||
} 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);
|
||||
ctx->isp_frm_quater_cnt = 0;
|
||||
rk_dvbm_update_isp_frm_info(ctx, 0);
|
||||
rk_dvbm_update_next_adr(ctx);
|
||||
rk_dvbm_show_time(ctx);
|
||||
} break;
|
||||
case DVBM_ISP_FRM_END: {
|
||||
u64 ns;
|
||||
u32 line_cnt = ALIGN(ctx->isp_max_lcnt, 32);
|
||||
|
||||
ns = ktime_get_ns();
|
||||
ctx->isp_frm_end = *(u32 *)arg;
|
||||
if (ctx->isp_frm_ns) {
|
||||
u64 interval = ns - ctx->isp_frm_ns;
|
||||
rk_dvbm_update_isp_frm_info(ctx, line_cnt);
|
||||
dvbm_debug("isp frame end[%d : %d]\n", ctx->isp_frm_start, ctx->isp_frm_end);
|
||||
} break;
|
||||
case DVBM_ISP_FRM_QUARTER: {
|
||||
u32 line_cnt;
|
||||
|
||||
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);
|
||||
ctx->isp_frm_quater_cnt++;
|
||||
line_cnt = ctx->isp_frm_quater_cnt * ctx->isp_max_lcnt / 4;
|
||||
rk_dvbm_update_isp_frm_info(ctx, line_cnt);
|
||||
} break;
|
||||
case DVBM_VEPU_GET_ADR: {
|
||||
struct dvbm_addr_cfg *dvbm_adr = (struct dvbm_addr_cfg *)arg;
|
||||
@@ -426,9 +477,14 @@ int rk_dvbm_ctrl(struct dvbm_port *port, enum dvbm_cmd cmd, void *arg)
|
||||
dvbm_adr->ybuf_bot = addr_base->ybuf_bot;
|
||||
dvbm_adr->cbuf_top = addr_base->cbuf_top;
|
||||
dvbm_adr->cbuf_bot = addr_base->cbuf_bot;
|
||||
dvbm_adr->cbuf_sadr = ctx->vepu_cfg.cbuf_sadr;
|
||||
dvbm_adr->ybuf_sadr = ctx->vepu_cfg.ybuf_sadr;
|
||||
dvbm_adr->overflow = ctx->isp_frm_quater_cnt > 2;
|
||||
dvbm_adr->frame_id = ctx->isp_frm_info.frame_cnt;
|
||||
dvbm_adr->line_cnt = ctx->isp_frm_info.line_cnt;
|
||||
} break;
|
||||
case DVBM_VEPU_GET_CUR_ID: {
|
||||
*(u32 *)arg = ctx->isp_frm_start;
|
||||
case DVBM_VEPU_GET_FRAME_INFO: {
|
||||
memcpy(arg, &ctx->isp_frm_info, sizeof(struct dvbm_isp_frm_info));
|
||||
} break;
|
||||
case DVBM_VEPU_SET_RESYNC: {
|
||||
reg->dvbm_cfg.auto_resyn = *(u32 *)arg;
|
||||
|
||||
@@ -189,15 +189,20 @@ struct dvbm_ctx {
|
||||
atomic_t vepu_ref;
|
||||
atomic_t vepu_link;
|
||||
struct dvbm_cb vepu_cb;
|
||||
struct dvbm_addr_cfg vepu_cfg;
|
||||
|
||||
/* isp infos */
|
||||
struct dvbm_port port_isp;
|
||||
struct dvbm_cb isp_cb;
|
||||
struct dvbm_isp_cfg_t isp_cfg;
|
||||
struct dvbm_isp_frm_info isp_frm_info;
|
||||
atomic_t isp_link;
|
||||
atomic_t isp_ref;
|
||||
u32 isp_max_lcnt;
|
||||
u32 isp_frm_start;
|
||||
u32 isp_frm_end;
|
||||
u64 isp_frm_ns;
|
||||
ktime_t isp_frm_time;
|
||||
u32 isp_frm_quater_cnt;
|
||||
|
||||
/* debug infos */
|
||||
u32 dump_s;
|
||||
|
||||
@@ -18,17 +18,26 @@ enum dvbm_cmd {
|
||||
DVBM_ISP_SET_CFG,
|
||||
DVBM_ISP_FRM_START,
|
||||
DVBM_ISP_FRM_END,
|
||||
DVBM_ISP_FRM_QUARTER,
|
||||
DVBM_ISP_CMD_BUTT,
|
||||
|
||||
DVBM_VEPU_CMD_BASE = 0x10,
|
||||
DVBM_VEPU_SET_RESYNC,
|
||||
DVBM_VEPU_SET_CFG,
|
||||
DVBM_VEPU_GET_ADR,
|
||||
DVBM_VEPU_GET_CUR_ID,
|
||||
DVBM_VEPU_GET_FRAME_INFO,
|
||||
DVBM_VEPU_DUMP_REGS,
|
||||
DVBM_VEPU_CMD_BUTT,
|
||||
};
|
||||
|
||||
enum isp_frame_status {
|
||||
ISP_FRAME_START,
|
||||
ISP_FRAME_ONE_QUARTER,
|
||||
ISP_FRAME_HALF,
|
||||
ISP_FRAME_THREE_QUARTERS,
|
||||
ISP_FRAME_FINISH,
|
||||
};
|
||||
|
||||
enum dvbm_cb_event {
|
||||
DVBM_ISP_EVENT_BASE = 0,
|
||||
DVBM_ISP_EVENT_BUTT,
|
||||
@@ -39,6 +48,7 @@ enum dvbm_cb_event {
|
||||
DVBM_VEPU_REQ_CONNECT,
|
||||
DVBM_VEPU_NOTIFY_FRM_STR,
|
||||
DVBM_VEPU_NOTIFY_FRM_END,
|
||||
DVBM_VEPU_NOTIFY_FRM_INFO,
|
||||
DVBM_VEPU_EVENT_BUTT,
|
||||
};
|
||||
|
||||
@@ -69,11 +79,21 @@ struct dvbm_isp_frm_cfg {
|
||||
u32 cbuf_start;
|
||||
};
|
||||
|
||||
struct dvbm_isp_frm_info {
|
||||
u32 frame_cnt;
|
||||
u32 line_cnt;
|
||||
};
|
||||
|
||||
struct dvbm_addr_cfg {
|
||||
u32 ybuf_top;
|
||||
u32 ybuf_bot;
|
||||
u32 ybuf_sadr;
|
||||
u32 cbuf_top;
|
||||
u32 cbuf_bot;
|
||||
u32 cbuf_sadr;
|
||||
u32 frame_id;
|
||||
u32 line_cnt;
|
||||
u32 overflow;
|
||||
};
|
||||
|
||||
struct dvbm_vepu_cfg {
|
||||
|
||||
Reference in New Issue
Block a user