From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 23 May 2020 10:18:16 +0000 Subject: [PATCH] WIP: media: rkvdec: continue to gate clock when decoding finish Signed-off-by: Jonas Karlman --- drivers/staging/media/rkvdec/rkvdec.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index d068383aeea8..5c03fdbd45ec 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -986,7 +986,8 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv) state = (status & RKVDEC_RDY_STA) ? VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; - writel(0, rkvdec->regs + RKVDEC_REG_INTERRUPT); + writel(RKVDEC_CONFIG_DEC_CLK_GATE_E, + rkvdec->regs + RKVDEC_REG_INTERRUPT); if (cancel_delayed_work(&rkvdec->watchdog_work)) { struct rkvdec_ctx *ctx; @@ -1007,7 +1008,8 @@ static void rkvdec_watchdog_func(struct work_struct *work) ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); if (ctx) { dev_err(rkvdec->dev, "Frame processing timed out!\n"); - writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT); + writel(RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_IRQ_DIS, + rkvdec->regs + RKVDEC_REG_INTERRUPT); writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL); rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); } From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 23 May 2020 10:16:01 +0000 Subject: [PATCH] WIP: media: rkvdec: pm runtime dont use autosuspend before disable and cleanup Signed-off-by: Jonas Karlman --- drivers/staging/media/rkvdec/rkvdec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index 5c03fdbd45ec..ad5e02bbd8d0 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -1105,9 +1105,9 @@ static int rkvdec_remove(struct platform_device *pdev) { struct rkvdec_dev *rkvdec = platform_get_drvdata(pdev); - rkvdec_v4l2_cleanup(rkvdec); - pm_runtime_disable(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_disable(&pdev->dev); + rkvdec_v4l2_cleanup(rkvdec); return 0; } From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 23 May 2020 11:23:04 +0000 Subject: [PATCH] WIP: media: rkvdec: h264: return early when no reference pictures NOTE: also change from a switch statement to access reflists from a pointer array, should simplify once we add support for field reference list Signed-off-by: Jonas Karlman --- drivers/staging/media/rkvdec/rkvdec-h264.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c index c9a551dbd9bc..6ce11b736363 100644 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c @@ -734,6 +734,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, const struct v4l2_ctrl_h264_sps *sps = run->sps; struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; u32 max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); + u8 *reflists[3] = { h264_ctx->reflists.p, h264_ctx->reflists.b0, h264_ctx->reflists.b1 }; u32 *hw_rps = priv_tbl->rps; u32 i, j; @@ -741,6 +742,9 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, memset(hw_rps, 0, sizeof(priv_tbl->rps)); + if (!h264_ctx->reflists.num_valid) + return; + /* * Assign an invalid pic_num if DPB entry at that position is inactive. * If we assign 0 in that position hardware will treat that as a real @@ -763,19 +767,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { for (i = 0; i < h264_ctx->reflists.num_valid; i++) { u8 dpb_valid = 0; - u8 idx = 0; - - switch (j) { - case 0: - idx = h264_ctx->reflists.p[i]; - break; - case 1: - idx = h264_ctx->reflists.b0[i]; - break; - case 2: - idx = h264_ctx->reflists.b1[i]; - break; - } + u8 idx = reflists[j][i]; if (idx >= ARRAY_SIZE(dec_params->dpb)) continue; From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sat, 23 May 2020 14:42:27 +0000 Subject: [PATCH] WIP: media: rkvdec: h264: add field decoding support Signed-off-by: Jonas Karlman --- drivers/staging/media/rkvdec/rkvdec-h264.c | 79 ++++++++++++++++++---- 1 file changed, 64 insertions(+), 15 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c index 6ce11b736363..9c3f08c94800 100644 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c @@ -737,7 +737,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, u8 *reflists[3] = { h264_ctx->reflists.p, h264_ctx->reflists.b0, h264_ctx->reflists.b1 }; u32 *hw_rps = priv_tbl->rps; - u32 i, j; + u32 i, j, k; u16 *p = (u16 *)hw_rps; memset(hw_rps, 0, sizeof(priv_tbl->rps)); @@ -764,18 +764,71 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, p[i] = dpb[i].frame_num - max_frame_num; } - for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { - for (i = 0; i < h264_ctx->reflists.num_valid; i++) { - u8 dpb_valid = 0; - u8 idx = reflists[j][i]; + if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) { + for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { + for (i = 0; i < h264_ctx->reflists.num_valid; i++) { + u8 dpb_valid = 0; + u8 idx = reflists[j][i]; - if (idx >= ARRAY_SIZE(dec_params->dpb)) - continue; - dpb_valid = !!(dpb[idx].flags & - V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); + if (idx >= ARRAY_SIZE(dec_params->dpb)) + continue; + dpb_valid = !!(dpb[idx].flags & + V4L2_H264_DPB_ENTRY_FLAG_ACTIVE); - set_ps_field(hw_rps, DPB_INFO(i, j), - idx | dpb_valid << 4); + set_ps_field(hw_rps, DPB_INFO(i, j), + idx | dpb_valid << 4); + } + } + return; + } + + for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { + enum v4l2_h264_field_reference a_parity = + (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + ? V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF; + enum v4l2_h264_field_reference b_parity = + (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) + ? V4L2_H264_TOP_FIELD_REF : V4L2_H264_BOTTOM_FIELD_REF; + u32 flags = V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM; + i = 0; + + for (k = 0; k < 2; k++) { + u8 a = 0; + u8 b = 0; + u32 long_term = k ? V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM : 0; + + while (a < h264_ctx->reflists.num_valid || b < h264_ctx->reflists.num_valid) { + for (; a < h264_ctx->reflists.num_valid; a++) { + u8 idx = reflists[j][a]; + if (idx >= ARRAY_SIZE(dec_params->dpb)) + continue; + if ((dpb[idx].reference & a_parity) == a_parity && + (dpb[idx].flags & flags) == long_term) { + set_ps_field(hw_rps, DPB_INFO(i, j), + idx | (1 << 4)); + set_ps_field(hw_rps, BOTTOM_FLAG(i, j), + a_parity == V4L2_H264_BOTTOM_FIELD_REF); + i++; + a++; + break; + } + } + for (; b < h264_ctx->reflists.num_valid; b++) { + u8 idx = reflists[j][b]; + if (idx >= ARRAY_SIZE(dec_params->dpb)) + continue; + if ((dpb[idx].reference & b_parity) == b_parity && + (dpb[idx].flags & flags) == long_term) { + set_ps_field(hw_rps, DPB_INFO(i, j), + idx | (1 << 4)); + set_ps_field(hw_rps, BOTTOM_FLAG(i, j), + b_parity == V4L2_H264_BOTTOM_FIELD_REF); + i++; + b++; + break; + } + } + } } } } @@ -968,10 +1021,6 @@ static void config_registers(struct rkvdec_ctx *ctx, rkvdec->regs + RKVDEC_REG_H264_BASE_REFER15); } - /* - * Since support frame mode only - * top_field_order_cnt is the same as bottom_field_order_cnt - */ reg = RKVDEC_CUR_POC(dec_params->top_field_order_cnt); writel_relaxed(reg, rkvdec->regs + RKVDEC_REG_CUR_POC0); From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Tue, 29 Oct 2019 01:26:02 +0000 Subject: [PATCH] RFC: media: hantro: Fix H264 decoding of field encoded content This still need code cleanup and formatting Signed-off-by: Jonas Karlman --- drivers/staging/media/hantro/hantro_h264.c | 91 ++++++++++++++++------ 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c index 0b4d2491be3b..7b56a68c176c 100644 --- a/drivers/staging/media/hantro/hantro_h264.c +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -227,30 +227,67 @@ static void prepare_table(struct hantro_ctx *ctx) { const struct hantro_h264_dec_ctrls *ctrls = &ctx->h264_dec.ctrls; const struct v4l2_ctrl_h264_decode_params *dec_param = ctrls->decode; + const struct v4l2_ctrl_h264_sps *sps = ctrls->sps; struct hantro_h264_dec_priv_tbl *tbl = ctx->h264_dec.priv.cpu; const struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; u32 dpb_longterm = 0; u32 dpb_valid = 0; int i; - for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { - tbl->poc[i * 2] = dpb[i].top_field_order_cnt; - tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; + /* + * Set up bit maps of valid and long term DPBs. + * NOTE: The bits are reversed, i.e. MSb is DPB 0. + */ + if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { + for (i = 0; i < HANTRO_H264_DPB_SIZE * 2; ++i) { + // check for correct reference use + enum v4l2_h264_field_reference parity = (i & 0x1) ? + V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF; + if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE && + dpb[i / 2].reference & parity) + dpb_valid |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i); + + if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i); + } - /* - * Set up bit maps of valid and long term DPBs. - * NOTE: The bits are reversed, i.e. MSb is DPB 0. - */ - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) - dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + ctx->h264_dec.dpb_valid = dpb_valid; + ctx->h264_dec.dpb_longterm = dpb_longterm; + } else { + for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) + dpb_valid |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + dpb_longterm |= BIT(HANTRO_H264_DPB_SIZE - 1 - i); + } + + ctx->h264_dec.dpb_valid = dpb_valid << 16; + ctx->h264_dec.dpb_longterm = dpb_longterm << 16; } - ctx->h264_dec.dpb_valid = dpb_valid << 16; - ctx->h264_dec.dpb_longterm = dpb_longterm << 16; - tbl->poc[32] = dec_param->top_field_order_cnt; - tbl->poc[33] = dec_param->bottom_field_order_cnt; + for (i = 0; i < HANTRO_H264_DPB_SIZE; ++i) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) { + tbl->poc[i * 2] = dpb[i].top_field_order_cnt; + tbl->poc[i * 2 + 1] = dpb[i].bottom_field_order_cnt; + } else { + tbl->poc[i * 2] = 0; + tbl->poc[i * 2 + 1] = 0; + } + } + + if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || !(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { + if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC)) + tbl->poc[32] = (dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ? + dec_param->bottom_field_order_cnt : + dec_param->top_field_order_cnt; + else + tbl->poc[32] = min(dec_param->top_field_order_cnt, dec_param->bottom_field_order_cnt); + tbl->poc[33] = 0; + } else { + tbl->poc[32] = dec_param->top_field_order_cnt; + tbl->poc[33] = dec_param->bottom_field_order_cnt; + }; assemble_scaling_list(ctx); } @@ -258,8 +295,7 @@ static void prepare_table(struct hantro_ctx *ctx) static bool dpb_entry_match(const struct v4l2_h264_dpb_entry *a, const struct v4l2_h264_dpb_entry *b) { - return a->top_field_order_cnt == b->top_field_order_cnt && - a->bottom_field_order_cnt == b->bottom_field_order_cnt; + return a->reference_ts == b->reference_ts; } static void update_dpb(struct hantro_ctx *ctx) @@ -273,13 +309,13 @@ static void update_dpb(struct hantro_ctx *ctx) /* Disable all entries by default. */ for (i = 0; i < ARRAY_SIZE(ctx->h264_dec.dpb); i++) - ctx->h264_dec.dpb[i].flags &= ~V4L2_H264_DPB_ENTRY_FLAG_ACTIVE; + ctx->h264_dec.dpb[i].flags = 0; /* Try to match new DPB entries with existing ones by their POCs. */ for (i = 0; i < ARRAY_SIZE(dec_param->dpb); i++) { const struct v4l2_h264_dpb_entry *ndpb = &dec_param->dpb[i]; - if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + if (!(ndpb->flags & V4L2_H264_DPB_ENTRY_FLAG_VALID)) continue; /* @@ -290,8 +326,7 @@ static void update_dpb(struct hantro_ctx *ctx) struct v4l2_h264_dpb_entry *cdpb; cdpb = &ctx->h264_dec.dpb[j]; - if (cdpb->flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE || - !dpb_entry_match(cdpb, ndpb)) + if (!dpb_entry_match(cdpb, ndpb)) continue; *cdpb = *ndpb; @@ -327,7 +362,10 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, unsigned int dpb_idx) { struct v4l2_h264_dpb_entry *dpb = ctx->h264_dec.dpb; + const struct v4l2_ctrl_h264_decode_params *dec_param = ctx->h264_dec.ctrls.decode; dma_addr_t dma_addr = 0; + s32 cur_poc; + u32 flags; if (dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) dma_addr = hantro_get_ref(ctx, dpb[dpb_idx].reference_ts); @@ -345,7 +383,16 @@ dma_addr_t hantro_h264_get_ref_buf(struct hantro_ctx *ctx, dma_addr = hantro_get_dec_buf_addr(ctx, buf); } - return dma_addr; + cur_poc = dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD ? + dec_param->bottom_field_order_cnt : + dec_param->top_field_order_cnt; + flags = dpb[dpb_idx].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD ? 0x2 : 0; + flags |= abs(dpb[dpb_idx].top_field_order_cnt - cur_poc) < + abs(dpb[dpb_idx].bottom_field_order_cnt - cur_poc) ? + 0x1 : 0; + + return dma_addr | flags; + } u16 hantro_h264_get_ref_nbr(struct hantro_ctx *ctx, unsigned int dpb_idx) From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Wed, 14 Oct 2020 13:27:12 +0200 Subject: [PATCH] media: hantro: adapt to match 5.11 H.264 uapi changes Signed-off-by: Alex Bee --- drivers/staging/media/hantro/hantro_h264.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/hantro/hantro_h264.c b/drivers/staging/media/hantro/hantro_h264.c index 7b56a68c176c..befa69d5c855 100644 --- a/drivers/staging/media/hantro/hantro_h264.c +++ b/drivers/staging/media/hantro/hantro_h264.c @@ -241,10 +241,10 @@ static void prepare_table(struct hantro_ctx *ctx) if ((dec_param->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC) || (sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD)) { for (i = 0; i < HANTRO_H264_DPB_SIZE * 2; ++i) { // check for correct reference use - enum v4l2_h264_field_reference parity = (i & 0x1) ? + u8 parity = (i & 0x1) ? V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF; if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE && - dpb[i / 2].reference & parity) + dpb[i / 2].fields & parity) dpb_valid |= BIT(HANTRO_H264_DPB_SIZE * 2 - 1 - i); if (dpb[i / 2].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Wed, 14 Oct 2020 13:42:01 +0200 Subject: [PATCH] media: rkvdec: adapt to match 5.11 H.264 uapi changes Signed-off-by: Alex Bee --- drivers/staging/media/rkvdec/rkvdec-h264.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c index 9c3f08c94800..7238117b6cf4 100644 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c @@ -783,10 +783,10 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, } for (j = 0; j < RKVDEC_NUM_REFLIST; j++) { - enum v4l2_h264_field_reference a_parity = + u8 a_parity = (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ? V4L2_H264_BOTTOM_FIELD_REF : V4L2_H264_TOP_FIELD_REF; - enum v4l2_h264_field_reference b_parity = + u8 b_parity = (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD) ? V4L2_H264_TOP_FIELD_REF : V4L2_H264_BOTTOM_FIELD_REF; u32 flags = V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM; @@ -802,7 +802,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, u8 idx = reflists[j][a]; if (idx >= ARRAY_SIZE(dec_params->dpb)) continue; - if ((dpb[idx].reference & a_parity) == a_parity && + if ((dpb[idx].fields & a_parity) == a_parity && (dpb[idx].flags & flags) == long_term) { set_ps_field(hw_rps, DPB_INFO(i, j), idx | (1 << 4)); @@ -817,7 +817,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx, u8 idx = reflists[j][b]; if (idx >= ARRAY_SIZE(dec_params->dpb)) continue; - if ((dpb[idx].reference & b_parity) == b_parity && + if ((dpb[idx].fields & b_parity) == b_parity && (dpb[idx].flags & flags) == long_term) { set_ps_field(hw_rps, DPB_INFO(i, j), idx | (1 << 4)); From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Randy Li Date: Sun, 6 Jan 2019 01:48:37 +0800 Subject: [PATCH] soc: rockchip: power-domain: export idle request We need to put the power status of HEVC IP into IDLE unless we can't reset that IP or the SoC would crash down. rockchip_pmu_idle_request(dev, true)---> enter idle rockchip_pmu_idle_request(dev, false)---> exit idle Signed-off-by: Caesar Wang Signed-off-by: Jeffy Chen Signed-off-by: Randy Li --- drivers/soc/rockchip/pm_domains.c | 23 +++++++++++++++++++++++ include/linux/rockchip_pmu.h | 15 +++++++++++++++ include/soc/rockchip/pm_domains.h | 18 ++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 include/linux/rockchip_pmu.h create mode 100644 include/soc/rockchip/pm_domains.h diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 0868b7d406fb..fddb4022c376 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -204,6 +204,29 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, return 0; } +int rockchip_pmu_idle_request(struct device *dev, bool idle) +{ + struct generic_pm_domain *genpd; + struct rockchip_pm_domain *pd; + int ret; + + if (IS_ERR_OR_NULL(dev)) + return -EINVAL; + + if (IS_ERR_OR_NULL(dev->pm_domain)) + return -EINVAL; + + genpd = pd_to_genpd(dev->pm_domain); + pd = to_rockchip_pd(genpd); + + mutex_lock(&pd->pmu->mutex); + ret = rockchip_pmu_set_idle_request(pd, idle); + mutex_unlock(&pd->pmu->mutex); + + return ret; +} +EXPORT_SYMBOL(rockchip_pmu_idle_request); + static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) { int i; diff --git a/include/linux/rockchip_pmu.h b/include/linux/rockchip_pmu.h new file mode 100644 index 000000000000..720b3314e71a --- /dev/null +++ b/include/linux/rockchip_pmu.h @@ -0,0 +1,15 @@ +/* + * pm_domain.h - Definitions and headers related to device power domains. + * + * Copyright (C) 2017 Randy Li . + * + * This file is released under the GPLv2. + */ + +#ifndef _LINUX_ROCKCHIP_PM_H +#define _LINUX_ROCKCHIP_PM_H +#include + +int rockchip_pmu_idle_request(struct device *dev, bool idle); + +#endif /* _LINUX_ROCKCHIP_PM_H */ diff --git a/include/soc/rockchip/pm_domains.h b/include/soc/rockchip/pm_domains.h new file mode 100644 index 000000000000..690db6118636 --- /dev/null +++ b/include/soc/rockchip/pm_domains.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __SOC_ROCKCHIP_PM_DOMAINS_H +#define __SOC_ROCKCHIP_PM_DOMAINS_H + +#include + +struct device; + +#ifdef CONFIG_ROCKCHIP_PM_DOMAINS +int rockchip_pmu_idle_request(struct device *dev, bool idle); +#else +static inline int rockchip_pmu_idle_request(struct device *dev, bool idle) +{ + return -ENOTSUPP; +} +#endif + +#endif From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Wed, 20 May 2020 17:04:47 +0200 Subject: [PATCH] WIP: media: rkvdec: implement reset controls --- .../bindings/media/rockchip,vdec.yaml | 19 +++++++ drivers/staging/media/rkvdec/rkvdec-regs.h | 5 ++ drivers/staging/media/rkvdec/rkvdec.c | 53 +++++++++++++++++++ drivers/staging/media/rkvdec/rkvdec.h | 11 +++- 4 files changed, 87 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml index 089f11d21b25..3f4772c8d095 100644 --- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml +++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml @@ -51,6 +51,18 @@ properties: iommus: maxItems: 1 + resets: + maxItems: 6 + + reset-names: + items: + - const: video_h + - const: video_a + - const: video_core + - const: video_cabac + - const: niu_a + - const: niu_h + required: - compatible - reg @@ -58,6 +70,8 @@ required: - clocks - clock-names - power-domains + - resets + - reset-names additionalProperties: false @@ -76,6 +90,11 @@ examples: clock-names = "axi", "ahb", "cabac", "core"; power-domains = <&power RK3399_PD_VDU>; iommus = <&vdec_mmu>; + resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>, + <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>, + <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>; + reset-names = "video_h", "video_a", "video_core", "video_cabac", + "niu_a", "niu_h"; }; ... diff --git a/drivers/staging/media/rkvdec/rkvdec-regs.h b/drivers/staging/media/rkvdec/rkvdec-regs.h index 15b9bee92016..3acc914888f6 100644 --- a/drivers/staging/media/rkvdec/rkvdec-regs.h +++ b/drivers/staging/media/rkvdec/rkvdec-regs.h @@ -28,6 +28,11 @@ #define RKVDEC_SOFTRST_EN_P BIT(20) #define RKVDEC_FORCE_SOFTRESET_VALID BIT(21) #define RKVDEC_SOFTRESET_RDY BIT(22) +#define RKVDEC_ERR_MASK (RKVDEC_BUS_STA \ + | RKVDEC_ERR_STA \ + | RKVDEC_TIMEOUT_STA \ + | RKVDEC_BUF_EMPTY_STA \ + | RKVDEC_COLMV_REF_ERR_STA ) #define RKVDEC_REG_SYSCTRL 0x008 #define RKVDEC_IN_ENDIAN BIT(0) diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index ad5e02bbd8d0..6abce36eee7f 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -10,12 +10,15 @@ */ #include +#include #include #include #include #include #include #include +#include +#include #include #include #include @@ -687,6 +690,11 @@ static void rkvdec_job_finish(struct rkvdec_ctx *ctx, pm_runtime_mark_last_busy(rkvdec->dev); pm_runtime_put_autosuspend(rkvdec->dev); + + if (result == VB2_BUF_STATE_ERROR && + rkvdec->reset_mask == RESET_NONE) + rkvdec->reset_mask |= RESET_SOFT; + rkvdec_job_finish_no_pm(ctx, result); } @@ -724,6 +732,33 @@ static void rkvdec_device_run(void *priv) if (WARN_ON(!desc)) return; + if (rkvdec->reset_mask != RESET_NONE) { + + if (rkvdec->reset_mask & RESET_SOFT) { + writel(RKVDEC_SOFTRST_EN_P, + rkvdec->regs + RKVDEC_REG_INTERRUPT); + udelay(RKVDEC_RESET_DELAY); + if (readl(rkvdec->regs + RKVDEC_REG_INTERRUPT) + & RKVDEC_SOFTRESET_RDY) + dev_info_ratelimited(rkvdec->dev, + "softreset failed\n"); + } + + if (rkvdec->reset_mask & RESET_HARD) { + rockchip_pmu_idle_request(rkvdec->dev, true); + ret = reset_control_assert(rkvdec->rstc); + if (!ret) { + udelay(RKVDEC_RESET_DELAY); + ret = reset_control_deassert(rkvdec->rstc); + } + rockchip_pmu_idle_request(rkvdec->dev, false); + if (ret) + dev_notice_ratelimited(rkvdec->dev, + "hardreset failed\n"); + } + rkvdec->reset_mask = RESET_NONE; + pm_runtime_suspend(rkvdec->dev); + } ret = pm_runtime_resume_and_get(rkvdec->dev); if (ret < 0) { @@ -991,6 +1026,11 @@ static irqreturn_t rkvdec_irq_handler(int irq, void *priv) if (cancel_delayed_work(&rkvdec->watchdog_work)) { struct rkvdec_ctx *ctx; + if (state == VB2_BUF_STATE_ERROR) { + rkvdec->reset_mask |= (status & RKVDEC_ERR_MASK) ? + RESET_HARD : RESET_SOFT; + } + ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); rkvdec_job_finish(ctx, state); } @@ -1008,6 +1048,7 @@ static void rkvdec_watchdog_func(struct work_struct *work) ctx = v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); if (ctx) { dev_err(rkvdec->dev, "Frame processing timed out!\n"); + rkvdec->reset_mask |= RESET_HARD; writel(RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT); writel(0, rkvdec->regs + RKVDEC_REG_SYSCTRL); @@ -1085,6 +1126,18 @@ static int rkvdec_probe(struct platform_device *pdev) return ret; } + + rkvdec->rstc = devm_reset_control_array_get(&pdev->dev, false, true); + if (IS_ERR(rkvdec->rstc)) { + dev_err(&pdev->dev, + "get resets failed %ld\n", PTR_ERR(rkvdec->rstc)); + return PTR_ERR(rkvdec->rstc); + } else { + dev_dbg(&pdev->dev, + "requested %d resets\n", + reset_control_get_count(&pdev->dev)); + } + pm_runtime_set_autosuspend_delay(&pdev->dev, 100); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h index 7b6f44ee8a1a..fa24bcb6ff42 100644 --- a/drivers/staging/media/rkvdec/rkvdec.h +++ b/drivers/staging/media/rkvdec/rkvdec.h @@ -11,10 +11,11 @@ #ifndef RKVDEC_H_ #define RKVDEC_H_ +#include #include +#include #include #include -#include #include #include @@ -22,6 +23,12 @@ #include #include +#define RESET_NONE 0 +#define RESET_SOFT BIT(0) +#define RESET_HARD BIT(1) + +#define RKVDEC_RESET_DELAY 5 + struct rkvdec_ctx; struct rkvdec_ctrl_desc { @@ -90,6 +97,8 @@ struct rkvdec_dev { void __iomem *regs; struct mutex vdev_lock; /* serializes ioctls */ struct delayed_work watchdog_work; + struct reset_control *rstc; + u8 reset_mask; }; struct rkvdec_ctx { From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Tue, 18 Aug 2020 11:38:04 +0200 Subject: [PATCH] WIP: arm64: dts: add resets to vdec for RK3399 --- arch/arm64/boot/dts/rockchip/rk3399.dtsi | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 52a748053a97..2c7b263a82cd 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -993,7 +993,10 @@ power-domain@RK3399_PD_VCODEC { power-domain@RK3399_PD_VDU { reg = ; clocks = <&cru ACLK_VDU>, - <&cru HCLK_VDU>; + <&cru HCLK_VDU>, + <&cru SCLK_VDU_CA>, + <&cru SCLK_VDU_CORE>; + pm_qos = <&qos_video_m1_r>, <&qos_video_m1_w>; #power-domain-cells = <0>; @@ -1266,6 +1269,11 @@ vdec: video-codec@ff660000 { clock-names = "axi", "ahb", "cabac", "core"; iommus = <&vdec_mmu>; power-domains = <&power RK3399_PD_VDU>; + resets = <&cru SRST_H_VDU>, <&cru SRST_A_VDU>, + <&cru SRST_VDU_CORE>, <&cru SRST_VDU_CA>, + <&cru SRST_A_VDU_NOC>, <&cru SRST_H_VDU_NOC>; + reset-names = "video_h", "video_a", "video_core", "video_cabac", + "niu_a", "niu_h"; }; vdec_mmu: iommu@ff660480 { From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Fri, 1 Jan 2021 12:11:12 +0200 Subject: [PATCH] arm64: dts: rockchip: fix RK3399 vdec register witdh Signed-off-by: Alex Bee --- arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 2c7b263a82cd..ec3561d147d5 100644 --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi @@ -1262,7 +1262,7 @@ vpu_mmu: iommu@ff650800 { vdec: video-codec@ff660000 { compatible = "rockchip,rk3399-vdec"; - reg = <0x0 0xff660000 0x0 0x400>; + reg = <0x0 0xff660000 0x0 0x480>; interrupts = ; clocks = <&cru ACLK_VDU>, <&cru HCLK_VDU>, <&cru SCLK_VDU_CA>, <&cru SCLK_VDU_CORE>; From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Wed, 19 Aug 2020 21:12:54 +0200 Subject: [PATCH] arm64: dts: rockchip: add rkvdec node for RK3328 Signed-off-by: Alex Bee --- .../bindings/media/rockchip,vdec.yaml | 3 +++ arch/arm64/boot/dts/rockchip/rk3328.dtsi | 25 ++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml index 3f4772c8d095..21a78372dae6 100644 --- a/Documentation/devicetree/bindings/media/rockchip,vdec.yaml +++ b/Documentation/devicetree/bindings/media/rockchip,vdec.yaml @@ -20,6 +20,9 @@ properties: - items: - const: rockchip,rk3228-vdec - const: rockchip,rk3399-vdec + - items: + - const: rockchip,rk3328-vdec + - const: rockchip,rk3399-vdec reg: maxItems: 1 diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi b/arch/arm64/boot/dts/rockchip/rk3328.dtsi index 9c10b6e3b9bc..23021373e15b 100644 --- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi @@ -306,6 +306,10 @@ power-domain@RK3328_PD_HEVC { }; power-domain@RK3328_PD_VIDEO { reg = ; + clocks = <&cru ACLK_RKVDEC>, + <&cru HCLK_RKVDEC>, + <&cru SCLK_VDEC_CABAC>, + <&cru SCLK_VDEC_CORE>; #power-domain-cells = <0>; }; power-domain@RK3328_PD_VPU { @@ -660,6 +664,25 @@ vpu_mmu: iommu@ff350800 { power-domains = <&power RK3328_PD_VPU>; }; + rkvdec: video-codec@ff360000 { + compatible = "rockchip,rk3328-vdec", "rockchip,rk3399-vdec"; + reg = <0x0 0xff360000 0x0 0x480>; + interrupts = ; + assigned-clocks = <&cru ACLK_RKVDEC>, <&cru SCLK_VDEC_CABAC>, + <&cru SCLK_VDEC_CORE>; + assigned-clock-rates = <400000000>, <400000000>, <300000000>; + clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>, + <&cru SCLK_VDEC_CABAC>, <&cru SCLK_VDEC_CORE>; + clock-names = "axi", "ahb", "cabac", "core"; + iommus = <&rkvdec_mmu>; + power-domains = <&power RK3328_PD_VIDEO>; + resets = <&cru SRST_VDEC_H>, <&cru SRST_VDEC_A>, + <&cru SRST_VDEC_CORE>, <&cru SRST_VDEC_CABAC>, + <&cru SRST_VDEC_NIU_A>, <&cru SRST_VDEC_NIU_H>; + reset-names = "video_h", "video_a", "video_core", "video_cabac", + "niu_a", "niu_h"; + }; + rkvdec_mmu: iommu@ff360480 { compatible = "rockchip,iommu"; reg = <0x0 0xff360480 0x0 0x40>, <0x0 0xff3604c0 0x0 0x40>; @@ -667,7 +690,7 @@ rkvdec_mmu: iommu@ff360480 { clocks = <&cru ACLK_RKVDEC>, <&cru HCLK_RKVDEC>; clock-names = "aclk", "iface"; #iommu-cells = <0>; - status = "disabled"; + power-domains = <&power RK3328_PD_VIDEO>; }; vop: vop@ff370000 { From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sun, 3 May 2020 18:34:56 +0200 Subject: [PATCH] WIP: media/rkvdec: don't overclock IP Signed-off-by: Alex Bee --- drivers/staging/media/rkvdec/rkvdec.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index 6abce36eee7f..fbaf0303f7c2 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -1096,10 +1096,12 @@ static int rkvdec_probe(struct platform_device *pdev) return ret; /* - * Bump ACLK to max. possible freq. (500 MHz) to improve performance - * When 4k video playback. + * Don't bump ACLK to max. possible freq. (500 MHz) to improve performance, + * since it will lead to non-recoverable decoder lockups in case of decoding + * errors, instead put it to 400 MHz, which seems to have no drawbacks + * in decoding performance and doesn't result in those hangs. */ - clk_set_rate(rkvdec->clocks[0].clk, 500 * 1000 * 1000); + clk_set_rate(rkvdec->clocks[0].clk, 400 * 1000 * 1000); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rkvdec->regs = devm_ioremap_resource(&pdev->dev, res); From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Alex Bee Date: Sat, 21 Aug 2021 16:12:36 +0200 Subject: [PATCH] media: hantro: rockchip: Increase RK3288's max ACLK Required to proper decode H.264@4K Signed-off-by: Alex Bee --- drivers/staging/media/hantro/rockchip_vpu_hw.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/hantro/rockchip_vpu_hw.c b/drivers/staging/media/hantro/rockchip_vpu_hw.c index d4f52957cc53..3d98e2251ea5 100644 --- a/drivers/staging/media/hantro/rockchip_vpu_hw.c +++ b/drivers/staging/media/hantro/rockchip_vpu_hw.c @@ -15,7 +15,8 @@ #include "rockchip_vpu2_regs.h" #define RK3066_ACLK_MAX_FREQ (300 * 1000 * 1000) -#define RK3288_ACLK_MAX_FREQ (400 * 1000 * 1000) +#define RK3288_ACLK_MAX_FREQ (600 * 1000 * 1000) +#define RK3399_ACLK_MAX_FREQ (400 * 1000 * 1000) /* * Supported formats. @@ -272,13 +273,20 @@ static int rk3066_vpu_hw_init(struct hantro_dev *vpu) return 0; } -static int rockchip_vpu_hw_init(struct hantro_dev *vpu) +static int rk3288_vpu_hw_init(struct hantro_dev *vpu) { /* Bump ACLK to max. possible freq. to improve performance. */ clk_set_rate(vpu->clocks[0].clk, RK3288_ACLK_MAX_FREQ); return 0; } +static int rockchip_vpu_hw_init(struct hantro_dev *vpu) +{ + /* Bump ACLK to max. possible freq. to improve performance. */ + clk_set_rate(vpu->clocks[0].clk, RK3399_ACLK_MAX_FREQ); + return 0; +} + static void rk3066_vpu_dec_reset(struct hantro_ctx *ctx) { struct hantro_dev *vpu = ctx->dev; @@ -511,7 +519,7 @@ const struct hantro_variant rk3288_vpu_variant = { .codec_ops = rk3288_vpu_codec_ops, .irqs = rockchip_vpu1_irqs, .num_irqs = ARRAY_SIZE(rockchip_vpu1_irqs), - .init = rockchip_vpu_hw_init, + .init = rk3288_vpu_hw_init, .clk_names = rockchip_vpu_clk_names, .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names) };