diff --git a/drivers/video/rockchip/dvbm/rockchip_dvbm.c b/drivers/video/rockchip/dvbm/rockchip_dvbm.c index 546a284afbfd..9074e12386a2 100644 --- a/drivers/video/rockchip/dvbm/rockchip_dvbm.c +++ b/drivers/video/rockchip/dvbm/rockchip_dvbm.c @@ -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; diff --git a/drivers/video/rockchip/dvbm/rockchip_dvbm.h b/drivers/video/rockchip/dvbm/rockchip_dvbm.h index 69cb5dbad63f..baf91d91c972 100644 --- a/drivers/video/rockchip/dvbm/rockchip_dvbm.h +++ b/drivers/video/rockchip/dvbm/rockchip_dvbm.h @@ -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; diff --git a/include/soc/rockchip/rockchip_dvbm.h b/include/soc/rockchip/rockchip_dvbm.h index d82ba0207a9b..f0e11f49ff86 100644 --- a/include/soc/rockchip/rockchip_dvbm.h +++ b/include/soc/rockchip/rockchip_dvbm.h @@ -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 {