From 873e2b7d978ae964d974696ab22a3d6d411d0373 Mon Sep 17 00:00:00 2001 From: Maxime Jourdan Date: Thu, 7 Feb 2019 17:37:34 +0100 Subject: [PATCH 11/14] media: meson: vdec: add g12a platform Signed-off-by: Maxime Jourdan --- drivers/staging/media/meson/vdec/codec_hevc.c | 38 +++++-- .../media/meson/vdec/codec_hevc_common.c | 9 -- drivers/staging/media/meson/vdec/codec_vp9.c | 54 ++++++++-- drivers/staging/media/meson/vdec/hevc_regs.h | 1 + drivers/staging/media/meson/vdec/vdec.c | 13 ++- drivers/staging/media/meson/vdec/vdec.h | 1 + drivers/staging/media/meson/vdec/vdec_hevc.c | 9 ++ .../staging/media/meson/vdec/vdec_platform.c | 101 ++++++++++++++++++ .../staging/media/meson/vdec/vdec_platform.h | 2 + 9 files changed, 204 insertions(+), 24 deletions(-) diff --git a/drivers/staging/media/meson/vdec/codec_hevc.c b/drivers/staging/media/meson/vdec/codec_hevc.c index 03f00f969f02..e16e937d56e8 100644 --- a/drivers/staging/media/meson/vdec/codec_hevc.c +++ b/drivers/staging/media/meson/vdec/codec_hevc.c @@ -68,7 +68,8 @@ #define SWAP_BUF2_SIZE 0x800 #define SCALELUT_SIZE 0x8000 #define DBLK_PARA_SIZE 0x20000 -#define DBLK_DATA_SIZE 0x40000 +#define DBLK_DATA_SIZE 0x80000 +#define DBLK_DATA2_SIZE 0x80000 #define MMU_VBH_SIZE 0x5000 #define MPRED_ABV_SIZE 0x8000 #define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM) @@ -88,7 +89,8 @@ #define SCALELUT_OFFSET (SWAP_BUF2_OFFSET + SWAP_BUF2_SIZE) #define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) #define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) -#define MMU_VBH_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) +#define DBLK_DATA2_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) +#define MMU_VBH_OFFSET (DBLK_DATA2_OFFSET + DBLK_DATA2_SIZE) #define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) #define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE) @@ -523,6 +525,7 @@ codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc) amvdec_write_dos(core, HEVC_SCALELUT, wkaddr + SCALELUT_OFFSET); amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFGE, wkaddr + DBLK_DATA2_OFFSET); return 0; } @@ -547,6 +550,8 @@ static int codec_hevc_start(struct amvdec_session *sess) goto free_hevc; amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); + if (core->platform->revision == VDEC_REVISION_G12A) + amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, (0xf << 25)); val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff; val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | @@ -755,6 +760,25 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) (amvdec_get_output_size(sess) / 2)); if (frame->cur_slice_idx == 0) { + if (core->platform->revision >= VDEC_REVISION_G12A) { + val = 0x54 << 8; + + /* enable first, compressed write */ + if (codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) + val |= BIT(8); + + /* enable second, uncompressed write */ + if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) + val |= BIT(9); + + /* dblk pipeline mode=1 for performance */ + if (hevc->width >= 1280) + val |= BIT(4); + + amvdec_write_dos(core, HEVC_DBLK_CFGB, val); + amvdec_write_dos(core, HEVC_DBLK_STS1 + 4, BIT(28)); + } + amvdec_write_dos(core, HEVC_DBLK_CFG2, hevc->width | (hevc->height << 16)); @@ -770,10 +794,12 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame) val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ - if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) - val |= BIT(0); /* disable cm compression */ - else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) - val |= BIT(1); /* Disable double write */ + if (core->platform->revision < VDEC_REVISION_G12A) { + if (!codec_hevc_use_fbc(sess->pixfmt_cap, hevc->is_10bit)) + val |= BIT(0); /* disable cm compression */ + else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) + val |= BIT(1); /* Disable double write */ + } amvdec_write_dos(core, HEVC_SAO_CTRL1, val); diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.c b/drivers/staging/media/meson/vdec/codec_hevc_common.c index 2b296beb5d88..5c372a9b0f03 100644 --- a/drivers/staging/media/meson/vdec/codec_hevc_common.c +++ b/drivers/staging/media/meson/vdec/codec_hevc_common.c @@ -111,15 +111,6 @@ codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit) } } - /* Fill the remaining unused slots with the last buffer's Y addr */ - for (i = buf_num; i < MAX_REF_PIC_NUM; ++i) { - amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, - buf_y_paddr >> 5); - if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) - amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, - buf_uv_paddr >> 5); - } - amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 1); amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR, 1); for (i = 0; i < 32; ++i) diff --git a/drivers/staging/media/meson/vdec/codec_vp9.c b/drivers/staging/media/meson/vdec/codec_vp9.c index 731119b9ee17..39e8eb5937bf 100644 --- a/drivers/staging/media/meson/vdec/codec_vp9.c +++ b/drivers/staging/media/meson/vdec/codec_vp9.c @@ -90,8 +90,8 @@ enum FRAME_TYPE { #define DBLK_PARA_OFFSET (SCALELUT_OFFSET + SCALELUT_SIZE) #define DBLK_DATA_OFFSET (DBLK_PARA_OFFSET + DBLK_PARA_SIZE) #define SEG_MAP_OFFSET (DBLK_DATA_OFFSET + DBLK_DATA_SIZE) -#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) -#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) +#define PROB_OFFSET (SEG_MAP_OFFSET + SEG_MAP_SIZE) +#define COUNT_OFFSET (PROB_OFFSET + PROB_SIZE) #define MMU_VBH_OFFSET (COUNT_OFFSET + COUNT_SIZE) #define MPRED_ABV_OFFSET (MMU_VBH_OFFSET + MMU_VBH_SIZE) #define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE) @@ -326,7 +326,11 @@ vp9_loop_filter_init(struct amvdec_core *core, struct codec_vp9 *vp9) amvdec_write_dos(core, HEVC_DBLK_CFG9, thr); } - amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); + if (core->platform->revision == VDEC_REVISION_G12A) + /* VP9 video format */ + amvdec_write_dos(core, HEVC_DBLK_CFGB, (0x54 << 8) | BIT(0)); + else + amvdec_write_dos(core, HEVC_DBLK_CFGB, 0x40400001); } static void @@ -447,6 +451,13 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) return -ENOMEM; } + memset(vp9->workspace_vaddr + DBLK_PARA_OFFSET, 0, DBLK_PARA_SIZE); + memset(vp9->workspace_vaddr + COUNT_OFFSET, 0, COUNT_SIZE); + memset(vp9->workspace_vaddr + PROB_OFFSET, 0, PROB_SIZE); + + printk("Workspace: %08X-%08X\n", wkaddr, wkaddr + SIZE_WORKSPACE); + printk("DBLK_PARA: %08X\n", wkaddr + DBLK_PARA_OFFSET); + vp9->workspace_paddr = wkaddr; amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET); @@ -461,11 +472,17 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9) amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2, wkaddr + SWAP_BUF2_OFFSET); amvdec_write_dos(core, VP9_SCALELUT, wkaddr + SCALELUT_OFFSET); + + if (core->platform->revision == VDEC_REVISION_G12A) + amvdec_write_dos(core, HEVC_DBLK_CFGE, + wkaddr + DBLK_PARA_OFFSET); + amvdec_write_dos(core, HEVC_DBLK_CFG4, wkaddr + DBLK_PARA_OFFSET); amvdec_write_dos(core, HEVC_DBLK_CFG5, wkaddr + DBLK_DATA_OFFSET); amvdec_write_dos(core, VP9_SEG_MAP_BUFFER, wkaddr + SEG_MAP_OFFSET); amvdec_write_dos(core, VP9_PROB_SWAP_BUFFER, wkaddr + PROB_OFFSET); amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET); + amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET); return 0; } @@ -487,6 +504,9 @@ static int codec_vp9_start(struct amvdec_session *sess) goto free_vp9; amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0)); + // stream_fifo_hole + if (core->platform->revision == VDEC_REVISION_G12A) + amvdec_write_dos_bits(core, HEVC_STREAM_FIFO_CTL, BIT(29)); val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x7fffffff; val |= (3 << 29) | BIT(24) | BIT(22) | BIT(7) | BIT(4) | BIT(0); @@ -597,14 +617,34 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb amvdec_write_dos(core, HEVC_SAO_C_LENGTH, (amvdec_get_output_size(sess) / 2)); + if (core->platform->revision >= VDEC_REVISION_G12A) { + amvdec_clear_dos_bits(core, HEVC_DBLK_CFGB, BIT(4) | BIT(5) | BIT(8) | BIT(9)); + /* enable first, compressed write */ + if (codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) + amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(8)); + + /* enable second, uncompressed write */ + if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) + amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(9)); + + /* dblk pipeline mode=1 for performance */ + if (sess->width >= 1280) + amvdec_write_dos_bits(core, HEVC_DBLK_CFGB, BIT(4)); + + printk("HEVC_DBLK_CFGB: %08X\n", amvdec_read_dos(core, HEVC_DBLK_CFGB)); + } + val = amvdec_read_dos(core, HEVC_SAO_CTRL1) & ~0x3ff3; val |= 0xff0; /* Set endianness for 2-bytes swaps (nv12) */ - if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) - val |= BIT(0); /* disable cm compression */ - else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) - val |= BIT(1); /* Disable double write */ + if (core->platform->revision < VDEC_REVISION_G12A) { + if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) + val |= BIT(0); /* disable cm compression */ + else if (sess->pixfmt_cap == V4L2_PIX_FMT_AM21C) + val |= BIT(1); /* Disable double write */ + } amvdec_write_dos(core, HEVC_SAO_CTRL1, val); + printk("HEVC_SAO_CTRL1: %08X\n", val); if (!codec_hevc_use_fbc(sess->pixfmt_cap, vp9->is_10bit)) { /* no downscale for NV12 */ diff --git a/drivers/staging/media/meson/vdec/hevc_regs.h b/drivers/staging/media/meson/vdec/hevc_regs.h index c80479d7c9c3..dc2c2e085b05 100644 --- a/drivers/staging/media/meson/vdec/hevc_regs.h +++ b/drivers/staging/media/meson/vdec/hevc_regs.h @@ -170,6 +170,7 @@ #define HEVC_DBLK_STS0 0xd42c #define HEVC_DBLK_CFGB 0xd42c #define HEVC_DBLK_STS1 0xd430 +#define HEVC_DBLK_CFGE 0xd438 #define HEVC_SAO_VERSION 0xd800 #define HEVC_SAO_CTRL0 0xd804 diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index e466a9905c78..448d2366d6a0 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -967,6 +967,8 @@ static const struct of_device_id vdec_dt_match[] = { .data = &vdec_platform_gxm }, { .compatible = "amlogic,gxl-vdec", .data = &vdec_platform_gxl }, + { .compatible = "amlogic,g12a-vdec", + .data = &vdec_platform_g12a }, {} }; MODULE_DEVICE_TABLE(of, vdec_dt_match); @@ -1014,6 +1016,15 @@ static int vdec_probe(struct platform_device *pdev) if (IS_ERR(core->canvas)) return PTR_ERR(core->canvas); + of_id = of_match_node(vdec_dt_match, dev->of_node); + core->platform = of_id->data; + + if (core->platform->revision == VDEC_REVISION_G12A) { + core->vdec_hevcf_clk = devm_clk_get(dev, "vdec_hevcf"); + if (IS_ERR(core->vdec_hevcf_clk)) + return -EPROBE_DEFER; + } + core->dos_parser_clk = devm_clk_get(dev, "dos_parser"); if (IS_ERR(core->dos_parser_clk)) return -EPROBE_DEFER; @@ -1056,8 +1067,6 @@ static int vdec_probe(struct platform_device *pdev) goto err_vdev_release; } - of_id = of_match_node(vdec_dt_match, dev->of_node); - core->platform = of_id->data; core->vdev_dec = vdev; core->dev_dec = dev; mutex_init(&core->lock); diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h index 210ab4b755fe..95415212b282 100644 --- a/drivers/staging/media/meson/vdec/vdec.h +++ b/drivers/staging/media/meson/vdec/vdec.h @@ -76,6 +76,7 @@ struct amvdec_core { struct clk *dos_clk; struct clk *vdec_1_clk; struct clk *vdec_hevc_clk; + struct clk *vdec_hevcf_clk; struct reset_control *esparser_reset; diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c index b1406a5638da..730ecd771643 100644 --- a/drivers/staging/media/meson/vdec/vdec_hevc.c +++ b/drivers/staging/media/meson/vdec/vdec_hevc.c @@ -123,6 +123,8 @@ static int vdec_hevc_stop(struct amvdec_session *sess) regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); + if (core->platform->revision == VDEC_REVISION_G12A) + clk_disable_unprepare(core->vdec_hevcf_clk); clk_disable_unprepare(core->vdec_hevc_clk); return 0; @@ -139,6 +141,13 @@ static int vdec_hevc_start(struct amvdec_session *sess) if (ret) return ret; + if (core->platform->revision == VDEC_REVISION_G12A) { + clk_set_rate(core->vdec_hevcf_clk, 666666666); + ret = clk_prepare_enable(core->vdec_hevcf_clk); + if (ret) + return ret; + } + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, GEN_PWR_VDEC_HEVC, 0); udelay(10); diff --git a/drivers/staging/media/meson/vdec/vdec_platform.c b/drivers/staging/media/meson/vdec/vdec_platform.c index 3c51bf991a3b..a1812520421b 100644 --- a/drivers/staging/media/meson/vdec/vdec_platform.c +++ b/drivers/staging/media/meson/vdec/vdec_platform.c @@ -290,6 +290,101 @@ static const struct amvdec_format vdec_formats_gxm[] = { }, }; +static const struct amvdec_format vdec_formats_g12a[] = { + { + .pixfmt = V4L2_PIX_FMT_VP9, + .min_buffers = 4, + .max_buffers = 16, + .max_width = 3840, + .max_height = 2160, + .vdec_ops = &vdec_hevc_ops, + .codec_ops = &codec_vp9_ops, + .firmware_path = "meson/vdec/g12a_vp9.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, + }, + { + .pixfmt = V4L2_PIX_FMT_HEVC, + .min_buffers = 16, + .max_buffers = 24, + .max_width = 3840, + .max_height = 2160, + .vdec_ops = &vdec_hevc_ops, + .codec_ops = &codec_hevc_ops, + .firmware_path = "meson/vdec/g12a_hevc.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_AM21C, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_MJPEG, + .min_buffers = 4, + .max_buffers = 4, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mjpeg_ops, + .firmware_path = "meson/vdec/gxl_mjpeg.bin", + .pixfmts_cap = { V4L2_PIX_FMT_YUV420M, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_MPEG4, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg4_ops, + .firmware_path = "meson/vdec/gxl_mpeg4_5.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_H263, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg4_ops, + .firmware_path = "meson/vdec/gxl_h263.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_XVID, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg4_ops, + .firmware_path = "meson/vdec/gxl_mpeg4_5.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_H264, + .min_buffers = 2, + .max_buffers = 24, + .max_width = 3840, + .max_height = 2160, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_h264_ops, + .firmware_path = "meson/vdec/g12a_h264.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_MPEG1, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg12_ops, + .firmware_path = "meson/vdec/gxl_mpeg12.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, { + .pixfmt = V4L2_PIX_FMT_MPEG2, + .min_buffers = 8, + .max_buffers = 8, + .max_width = 1920, + .max_height = 1080, + .vdec_ops = &vdec_1_ops, + .codec_ops = &codec_mpeg12_ops, + .firmware_path = "meson/vdec/gxl_mpeg12.bin", + .pixfmts_cap = { V4L2_PIX_FMT_NV12M, V4L2_PIX_FMT_YUV420M, 0 }, + }, +}; + const struct vdec_platform vdec_platform_gxbb = { .formats = vdec_formats_gxbb, .num_formats = ARRAY_SIZE(vdec_formats_gxbb), @@ -307,3 +402,9 @@ const struct vdec_platform vdec_platform_gxm = { .num_formats = ARRAY_SIZE(vdec_formats_gxm), .revision = VDEC_REVISION_GXM, }; + +const struct vdec_platform vdec_platform_g12a = { + .formats = vdec_formats_g12a, + .num_formats = ARRAY_SIZE(vdec_formats_g12a), + .revision = VDEC_REVISION_G12A, +}; diff --git a/drivers/staging/media/meson/vdec/vdec_platform.h b/drivers/staging/media/meson/vdec/vdec_platform.h index f6025326db1d..7c61b941b39f 100644 --- a/drivers/staging/media/meson/vdec/vdec_platform.h +++ b/drivers/staging/media/meson/vdec/vdec_platform.h @@ -15,6 +15,7 @@ enum vdec_revision { VDEC_REVISION_GXBB, VDEC_REVISION_GXL, VDEC_REVISION_GXM, + VDEC_REVISION_G12A, }; struct vdec_platform { @@ -26,5 +27,6 @@ struct vdec_platform { extern const struct vdec_platform vdec_platform_gxbb; extern const struct vdec_platform vdec_platform_gxm; extern const struct vdec_platform vdec_platform_gxl; +extern const struct vdec_platform vdec_platform_g12a; #endif -- 2.20.1