On 14/02/2020 16:07, Hans Verkuil wrote: > On 2/6/20 9:41 AM, Neil Armstrong wrote: >> From: Maxime Jourdan <mjourdan@xxxxxxxxxxxx> >> >> Add support for the HEVC & VP9 common decoder support, handling >> Amlogic GXBB, GXL, G12A and SM1 platforms. >> >> This handles the "HEVC" hw decoder used for HEVC and VP9, and will be >> using in the new H264 multi-instance decoder for G12A & SM1 platforms. >> >> Signed-off-by: Maxime Jourdan <mjourdan@xxxxxxxxxxxx> >> Signed-off-by: Neil Armstrong <narmstrong@xxxxxxxxxxxx> > > I'm getting some checkpatch warnings/checks: > > WARNING: Possible unnecessary 'out of memory' message > #219: FILE: drivers/staging/media/meson/vdec/codec_hevc_common.c:171: > + if (!vaddr) { > + dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); > > WARNING: Possible unnecessary 'out of memory' message > #273: FILE: drivers/staging/media/meson/vdec/codec_hevc_common.c:225: > + if (!vaddr) { > + dev_err(dev, "Couldn't allocate MMU header %u\n", idx); > > WARNING: Possible unnecessary 'out of memory' message > #692: FILE: drivers/staging/media/meson/vdec/vdec_hevc.c:52: > + if (!mc_addr) { > + dev_err(dev, "Failed allocating memory for firmware loading\n"); > > CHECK: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst > #819: FILE: drivers/staging/media/meson/vdec/vdec_hevc.c:179: > + udelay(10); > > CHECK: usleep_range is preferred over udelay; see Documentation/timers/timers-howto.rst > #857: FILE: drivers/staging/media/meson/vdec/vdec_hevc.c:217: > + udelay(10); > > Can you take a look? I'll fix all these. Neil > > Regards, > > Hans > >> --- >> drivers/staging/media/meson/vdec/Makefile | 4 +- >> .../media/meson/vdec/codec_hevc_common.c | 286 ++++++++++++++++++ >> .../media/meson/vdec/codec_hevc_common.h | 77 +++++ >> drivers/staging/media/meson/vdec/hevc_regs.h | 211 +++++++++++++ >> drivers/staging/media/meson/vdec/vdec_hevc.c | 231 ++++++++++++++ >> drivers/staging/media/meson/vdec/vdec_hevc.h | 13 + >> 6 files changed, 820 insertions(+), 2 deletions(-) >> create mode 100644 drivers/staging/media/meson/vdec/codec_hevc_common.c >> create mode 100644 drivers/staging/media/meson/vdec/codec_hevc_common.h >> create mode 100644 drivers/staging/media/meson/vdec/hevc_regs.h >> create mode 100644 drivers/staging/media/meson/vdec/vdec_hevc.c >> create mode 100644 drivers/staging/media/meson/vdec/vdec_hevc.h >> >> diff --git a/drivers/staging/media/meson/vdec/Makefile b/drivers/staging/media/meson/vdec/Makefile >> index 711d990c760e..f55b6e625034 100644 >> --- a/drivers/staging/media/meson/vdec/Makefile >> +++ b/drivers/staging/media/meson/vdec/Makefile >> @@ -2,7 +2,7 @@ >> # Makefile for Amlogic meson video decoder driver >> >> meson-vdec-objs = esparser.o vdec.o vdec_helpers.o vdec_platform.o >> -meson-vdec-objs += vdec_1.o >> -meson-vdec-objs += codec_mpeg12.o codec_h264.o >> +meson-vdec-objs += vdec_1.o vdec_hevc.o >> +meson-vdec-objs += codec_mpeg12.o codec_h264.o codec_hevc_common.o >> >> obj-$(CONFIG_VIDEO_MESON_VDEC) += meson-vdec.o >> diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.c b/drivers/staging/media/meson/vdec/codec_hevc_common.c >> new file mode 100644 >> index 000000000000..335bcba062ac >> --- /dev/null >> +++ b/drivers/staging/media/meson/vdec/codec_hevc_common.c >> @@ -0,0 +1,286 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Copyright (C) 2018 Maxime Jourdan <mjourdan@xxxxxxxxxxxx> >> + */ >> + >> +#include <media/v4l2-mem2mem.h> >> +#include <media/videobuf2-dma-contig.h> >> + >> +#include "codec_hevc_common.h" >> +#include "vdec_helpers.h" >> +#include "hevc_regs.h" >> + >> +#define MMU_COMPRESS_HEADER_SIZE 0x48000 >> +#define MMU_MAP_SIZE 0x4800 >> + >> +/* Configure decode head read mode */ >> +void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit) >> +{ >> + struct amvdec_core *core = sess->core; >> + u32 body_size = amvdec_am21c_body_size(sess->width, sess->height); >> + u32 head_size = amvdec_am21c_head_size(sess->width, sess->height); >> + >> + if (!codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { >> + /* Enable 2-plane reference read mode */ >> + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(31)); >> + return; >> + } >> + >> + if (codec_hevc_use_mmu(core->platform->revision, >> + sess->pixfmt_cap, is_10bit)) >> + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, BIT(4)); >> + else >> + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0); >> + >> + if (core->platform->revision < VDEC_REVISION_SM1) >> + amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL2, body_size / 32); >> + amvdec_write_dos(core, HEVC_CM_BODY_LENGTH, body_size); >> + amvdec_write_dos(core, HEVC_CM_HEADER_OFFSET, body_size); >> + amvdec_write_dos(core, HEVC_CM_HEADER_LENGTH, head_size); >> +} >> +EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head); >> + >> +static void codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, >> + struct codec_hevc_common *comm, >> + int is_10bit) >> +{ >> + struct amvdec_core *core = sess->core; >> + struct v4l2_m2m_buffer *buf; >> + u32 buf_num = v4l2_m2m_num_dst_bufs_ready(sess->m2m_ctx); >> + dma_addr_t buf_y_paddr = 0; >> + dma_addr_t buf_uv_paddr = 0; >> + u32 idx = 0; >> + u32 val; >> + int i; >> + >> + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0); >> + >> + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { >> + struct vb2_buffer *vb = &buf->vb.vb2_buf; >> + >> + idx = vb->index; >> + >> + if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) >> + buf_y_paddr = comm->fbc_buffer_paddr[idx]; >> + else >> + buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); >> + >> + if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) { >> + val = buf_y_paddr | (idx << 8) | 1; >> + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, >> + val); >> + } else { >> + buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); >> + val = buf_y_paddr | ((idx * 2) << 8) | 1; >> + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, >> + val); >> + val = buf_uv_paddr | ((idx * 2 + 1) << 8) | 1; >> + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR, >> + val); >> + } >> + } >> + >> + if (codec_hevc_use_fbc(sess->pixfmt_cap, is_10bit)) >> + val = buf_y_paddr | (idx << 8) | 1; >> + else >> + val = buf_y_paddr | ((idx * 2) << 8) | 1; >> + >> + /* 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_CMD_ADDR, val); >> + >> + 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) >> + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); >> +} >> + >> +static void codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, >> + struct codec_hevc_common *comm, >> + int is_10bit) >> +{ >> + struct amvdec_core *core = sess->core; >> + struct v4l2_m2m_buffer *buf; >> + u32 revision = core->platform->revision; >> + u32 pixfmt_cap = sess->pixfmt_cap; >> + int i; >> + >> + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, >> + BIT(2) | BIT(1)); >> + >> + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { >> + struct vb2_buffer *vb = &buf->vb.vb2_buf; >> + dma_addr_t buf_y_paddr = 0; >> + dma_addr_t buf_uv_paddr = 0; >> + u32 idx = vb->index; >> + >> + if (codec_hevc_use_mmu(revision, pixfmt_cap, is_10bit)) >> + buf_y_paddr = comm->mmu_header_paddr[idx]; >> + else if (codec_hevc_use_downsample(pixfmt_cap, is_10bit)) >> + buf_y_paddr = comm->fbc_buffer_paddr[idx]; >> + else >> + buf_y_paddr = vb2_dma_contig_plane_dma_addr(vb, 0); >> + >> + amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_DATA, >> + buf_y_paddr >> 5); >> + >> + if (!codec_hevc_use_fbc(pixfmt_cap, is_10bit)) { >> + buf_uv_paddr = vb2_dma_contig_plane_dma_addr(vb, 1); >> + 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) >> + amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0); >> +} >> + >> +void codec_hevc_free_fbc_buffers(struct amvdec_session *sess, >> + struct codec_hevc_common *comm) >> +{ >> + struct device *dev = sess->core->dev; >> + u32 am21_size = amvdec_am21c_size(sess->width, sess->height); >> + int i; >> + >> + for (i = 0; i < MAX_REF_PIC_NUM; ++i) { >> + if (comm->fbc_buffer_vaddr[i]) { >> + dma_free_coherent(dev, am21_size, >> + comm->fbc_buffer_vaddr[i], >> + comm->fbc_buffer_paddr[i]); >> + comm->fbc_buffer_vaddr[i] = NULL; >> + } >> + } >> +} >> +EXPORT_SYMBOL_GPL(codec_hevc_free_fbc_buffers); >> + >> +static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess, >> + struct codec_hevc_common *comm) >> +{ >> + struct device *dev = sess->core->dev; >> + struct v4l2_m2m_buffer *buf; >> + u32 am21_size = amvdec_am21c_size(sess->width, sess->height); >> + >> + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { >> + u32 idx = buf->vb.vb2_buf.index; >> + dma_addr_t paddr; >> + void *vaddr = dma_alloc_coherent(dev, am21_size, &paddr, >> + GFP_KERNEL); >> + if (!vaddr) { >> + dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx); >> + codec_hevc_free_fbc_buffers(sess, comm); >> + return -ENOMEM; >> + } >> + >> + comm->fbc_buffer_vaddr[idx] = vaddr; >> + comm->fbc_buffer_paddr[idx] = paddr; >> + } >> + >> + return 0; >> +} >> + >> +void codec_hevc_free_mmu_headers(struct amvdec_session *sess, >> + struct codec_hevc_common *comm) >> +{ >> + struct device *dev = sess->core->dev; >> + int i; >> + >> + for (i = 0; i < MAX_REF_PIC_NUM; ++i) { >> + if (comm->mmu_header_vaddr[i]) { >> + dma_free_coherent(dev, MMU_COMPRESS_HEADER_SIZE, >> + comm->mmu_header_vaddr[i], >> + comm->mmu_header_paddr[i]); >> + comm->mmu_header_vaddr[i] = NULL; >> + } >> + } >> + >> + if (comm->mmu_map_vaddr) { >> + dma_free_coherent(dev, MMU_MAP_SIZE, >> + comm->mmu_map_vaddr, >> + comm->mmu_map_paddr); >> + comm->mmu_map_vaddr = NULL; >> + } >> +} >> +EXPORT_SYMBOL_GPL(codec_hevc_free_mmu_headers); >> + >> +static int codec_hevc_alloc_mmu_headers(struct amvdec_session *sess, >> + struct codec_hevc_common *comm) >> +{ >> + struct device *dev = sess->core->dev; >> + struct v4l2_m2m_buffer *buf; >> + >> + comm->mmu_map_vaddr = dma_alloc_coherent(dev, MMU_MAP_SIZE, >> + &comm->mmu_map_paddr, >> + GFP_KERNEL); >> + if (!comm->mmu_map_vaddr) >> + return -ENOMEM; >> + >> + v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) { >> + u32 idx = buf->vb.vb2_buf.index; >> + dma_addr_t paddr; >> + void *vaddr = dma_alloc_coherent(dev, MMU_COMPRESS_HEADER_SIZE, >> + &paddr, GFP_KERNEL); >> + if (!vaddr) { >> + dev_err(dev, "Couldn't allocate MMU header %u\n", idx); >> + codec_hevc_free_mmu_headers(sess, comm); >> + return -ENOMEM; >> + } >> + >> + comm->mmu_header_vaddr[idx] = vaddr; >> + comm->mmu_header_paddr[idx] = paddr; >> + } >> + >> + return 0; >> +} >> + >> +int codec_hevc_setup_buffers(struct amvdec_session *sess, >> + struct codec_hevc_common *comm, >> + int is_10bit) >> +{ >> + struct amvdec_core *core = sess->core; >> + int ret; >> + >> + if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit)) { >> + ret = codec_hevc_alloc_fbc_buffers(sess, comm); >> + if (ret) >> + return ret; >> + } >> + >> + if (codec_hevc_use_mmu(core->platform->revision, >> + sess->pixfmt_cap, is_10bit)) { >> + ret = codec_hevc_alloc_mmu_headers(sess, comm); >> + if (ret) { >> + codec_hevc_free_fbc_buffers(sess, comm); >> + return ret; >> + } >> + } >> + >> + if (core->platform->revision == VDEC_REVISION_GXBB) >> + codec_hevc_setup_buffers_gxbb(sess, comm, is_10bit); >> + else >> + codec_hevc_setup_buffers_gxl(sess, comm, is_10bit); >> + >> + return 0; >> +} >> +EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers); >> + >> +void codec_hevc_fill_mmu_map(struct amvdec_session *sess, >> + struct codec_hevc_common *comm, >> + struct vb2_buffer *vb) >> +{ >> + u32 size = amvdec_am21c_size(sess->width, sess->height); >> + u32 nb_pages = size / PAGE_SIZE; >> + u32 *mmu_map = comm->mmu_map_vaddr; >> + u32 first_page; >> + u32 i; >> + >> + if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) >> + first_page = comm->fbc_buffer_paddr[vb->index] >> PAGE_SHIFT; >> + else >> + first_page = vb2_dma_contig_plane_dma_addr(vb, 0) >> PAGE_SHIFT; >> + >> + for (i = 0; i < nb_pages; ++i) >> + mmu_map[i] = first_page + i; >> +} >> +EXPORT_SYMBOL_GPL(codec_hevc_fill_mmu_map); >> diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.h b/drivers/staging/media/meson/vdec/codec_hevc_common.h >> new file mode 100644 >> index 000000000000..de16d2e43061 >> --- /dev/null >> +++ b/drivers/staging/media/meson/vdec/codec_hevc_common.h >> @@ -0,0 +1,77 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright (C) 2018 BayLibre, SAS >> + * Author: Maxime Jourdan <mjourdan@xxxxxxxxxxxx> >> + */ >> + >> +#ifndef __MESON_VDEC_HEVC_COMMON_H_ >> +#define __MESON_VDEC_HEVC_COMMON_H_ >> + >> +#include "vdec.h" >> + >> +#define PARSER_CMD_SKIP_CFG_0 0x0000090b >> +#define PARSER_CMD_SKIP_CFG_1 0x1b14140f >> +#define PARSER_CMD_SKIP_CFG_2 0x001b1910 >> +static const u16 vdec_hevc_parser_cmd[] = { >> + 0x0401, 0x8401, 0x0800, 0x0402, >> + 0x9002, 0x1423, 0x8CC3, 0x1423, >> + 0x8804, 0x9825, 0x0800, 0x04FE, >> + 0x8406, 0x8411, 0x1800, 0x8408, >> + 0x8409, 0x8C2A, 0x9C2B, 0x1C00, >> + 0x840F, 0x8407, 0x8000, 0x8408, >> + 0x2000, 0xA800, 0x8410, 0x04DE, >> + 0x840C, 0x840D, 0xAC00, 0xA000, >> + 0x08C0, 0x08E0, 0xA40E, 0xFC00, >> + 0x7C00 >> +}; >> + >> +#define MAX_REF_PIC_NUM 24 >> + >> +struct codec_hevc_common { >> + void *fbc_buffer_vaddr[MAX_REF_PIC_NUM]; >> + dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM]; >> + >> + void *mmu_header_vaddr[MAX_REF_PIC_NUM]; >> + dma_addr_t mmu_header_paddr[MAX_REF_PIC_NUM]; >> + >> + void *mmu_map_vaddr; >> + dma_addr_t mmu_map_paddr; >> +}; >> + >> +/* Returns 1 if we must use framebuffer compression */ >> +static inline int codec_hevc_use_fbc(u32 pixfmt, int is_10bit) >> +{ >> + /* TOFIX: Handle Amlogic Compressed buffer for 8bit also */ >> + return is_10bit; >> +} >> + >> +/* Returns 1 if we are decoding 10-bit but outputting 8-bit NV12 */ >> +static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit) >> +{ >> + return is_10bit; >> +} >> + >> +/* Returns 1 if we are decoding using the IOMMU */ >> +static inline int codec_hevc_use_mmu(u32 revision, u32 pixfmt, int is_10bit) >> +{ >> + return revision >= VDEC_REVISION_G12A && >> + codec_hevc_use_fbc(pixfmt, is_10bit); >> +} >> + >> +/** >> + * Configure decode head read mode >> + */ >> +void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit); >> + >> +void codec_hevc_free_fbc_buffers(struct amvdec_session *sess, >> + struct codec_hevc_common *comm); >> + >> +int codec_hevc_setup_buffers(struct amvdec_session *sess, >> + struct codec_hevc_common *comm, >> + int is_10bit); >> + >> +void codec_hevc_fill_mmu_map(struct amvdec_session *sess, >> + struct codec_hevc_common *comm, >> + struct vb2_buffer *vb); >> + >> +#endif >> diff --git a/drivers/staging/media/meson/vdec/hevc_regs.h b/drivers/staging/media/meson/vdec/hevc_regs.h >> new file mode 100644 >> index 000000000000..55c1a80b955a >> --- /dev/null >> +++ b/drivers/staging/media/meson/vdec/hevc_regs.h >> @@ -0,0 +1,211 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright (C) 2015 Amlogic, Inc. All rights reserved. >> + */ >> + >> +#ifndef __MESON_VDEC_HEVC_REGS_H_ >> +#define __MESON_VDEC_HEVC_REGS_H_ >> + >> +#define HEVC_ASSIST_MMU_MAP_ADDR 0xc024 >> + >> +#define HEVC_ASSIST_MBOX1_CLR_REG 0xc1d4 >> +#define HEVC_ASSIST_MBOX1_MASK 0xc1d8 >> + >> +#define HEVC_ASSIST_SCRATCH_0 0xc300 >> +#define HEVC_ASSIST_SCRATCH_1 0xc304 >> +#define HEVC_ASSIST_SCRATCH_2 0xc308 >> +#define HEVC_ASSIST_SCRATCH_3 0xc30c >> +#define HEVC_ASSIST_SCRATCH_4 0xc310 >> +#define HEVC_ASSIST_SCRATCH_5 0xc314 >> +#define HEVC_ASSIST_SCRATCH_6 0xc318 >> +#define HEVC_ASSIST_SCRATCH_7 0xc31c >> +#define HEVC_ASSIST_SCRATCH_8 0xc320 >> +#define HEVC_ASSIST_SCRATCH_9 0xc324 >> +#define HEVC_ASSIST_SCRATCH_A 0xc328 >> +#define HEVC_ASSIST_SCRATCH_B 0xc32c >> +#define HEVC_ASSIST_SCRATCH_C 0xc330 >> +#define HEVC_ASSIST_SCRATCH_D 0xc334 >> +#define HEVC_ASSIST_SCRATCH_E 0xc338 >> +#define HEVC_ASSIST_SCRATCH_F 0xc33c >> +#define HEVC_ASSIST_SCRATCH_G 0xc340 >> +#define HEVC_ASSIST_SCRATCH_H 0xc344 >> +#define HEVC_ASSIST_SCRATCH_I 0xc348 >> +#define HEVC_ASSIST_SCRATCH_J 0xc34c >> +#define HEVC_ASSIST_SCRATCH_K 0xc350 >> +#define HEVC_ASSIST_SCRATCH_L 0xc354 >> +#define HEVC_ASSIST_SCRATCH_M 0xc358 >> +#define HEVC_ASSIST_SCRATCH_N 0xc35c >> + >> +#define HEVC_PARSER_VERSION 0xc400 >> +#define HEVC_STREAM_CONTROL 0xc404 >> +#define HEVC_STREAM_START_ADDR 0xc408 >> +#define HEVC_STREAM_END_ADDR 0xc40c >> +#define HEVC_STREAM_WR_PTR 0xc410 >> +#define HEVC_STREAM_RD_PTR 0xc414 >> +#define HEVC_STREAM_LEVEL 0xc418 >> +#define HEVC_STREAM_FIFO_CTL 0xc41c >> +#define HEVC_SHIFT_CONTROL 0xc420 >> +#define HEVC_SHIFT_STARTCODE 0xc424 >> +#define HEVC_SHIFT_EMULATECODE 0xc428 >> +#define HEVC_SHIFT_STATUS 0xc42c >> +#define HEVC_SHIFTED_DATA 0xc430 >> +#define HEVC_SHIFT_BYTE_COUNT 0xc434 >> +#define HEVC_SHIFT_COMMAND 0xc438 >> +#define HEVC_ELEMENT_RESULT 0xc43c >> +#define HEVC_CABAC_CONTROL 0xc440 >> +#define HEVC_PARSER_SLICE_INFO 0xc444 >> +#define HEVC_PARSER_CMD_WRITE 0xc448 >> +#define HEVC_PARSER_CORE_CONTROL 0xc44c >> +#define HEVC_PARSER_CMD_FETCH 0xc450 >> +#define HEVC_PARSER_CMD_STATUS 0xc454 >> +#define HEVC_PARSER_LCU_INFO 0xc458 >> +#define HEVC_PARSER_HEADER_INFO 0xc45c >> +#define HEVC_PARSER_INT_CONTROL 0xc480 >> +#define HEVC_PARSER_INT_STATUS 0xc484 >> +#define HEVC_PARSER_IF_CONTROL 0xc488 >> +#define HEVC_PARSER_PICTURE_SIZE 0xc48c >> +#define HEVC_PARSER_LCU_START 0xc490 >> +#define HEVC_PARSER_HEADER_INFO2 0xc494 >> +#define HEVC_PARSER_QUANT_READ 0xc498 >> +#define HEVC_PARSER_RESERVED_27 0xc49c >> +#define HEVC_PARSER_CMD_SKIP_0 0xc4a0 >> +#define HEVC_PARSER_CMD_SKIP_1 0xc4a4 >> +#define HEVC_PARSER_CMD_SKIP_2 0xc4a8 >> +#define HEVC_SAO_IF_STATUS 0xc4c0 >> +#define HEVC_SAO_IF_DATA_Y 0xc4c4 >> +#define HEVC_SAO_IF_DATA_U 0xc4c8 >> +#define HEVC_SAO_IF_DATA_V 0xc4cc >> +#define HEVC_STREAM_SWAP_ADDR 0xc4d0 >> +#define HEVC_STREAM_SWAP_CTRL 0xc4d4 >> +#define HEVC_IQIT_IF_WAIT_CNT 0xc4d8 >> +#define HEVC_MPRED_IF_WAIT_CNT 0xc4dc >> +#define HEVC_SAO_IF_WAIT_CNT 0xc4e0 >> + >> +#define HEVC_MPRED_VERSION 0xc800 >> +#define HEVC_MPRED_CTRL0 0xc804 >> + #define MPRED_CTRL0_NEW_PIC BIT(2) >> + #define MPRED_CTRL0_NEW_TILE BIT(3) >> + #define MPRED_CTRL0_NEW_SLI_SEG BIT(4) >> + #define MPRED_CTRL0_TMVP BIT(5) >> + #define MPRED_CTRL0_LDC BIT(6) >> + #define MPRED_CTRL0_COL_FROM_L0 BIT(7) >> + #define MPRED_CTRL0_ABOVE_EN BIT(9) >> + #define MPRED_CTRL0_MV_WR_EN BIT(10) >> + #define MPRED_CTRL0_MV_RD_EN BIT(11) >> + #define MPRED_CTRL0_BUF_LINEAR BIT(13) >> +#define HEVC_MPRED_CTRL1 0xc808 >> +#define HEVC_MPRED_INT_EN 0xc80c >> +#define HEVC_MPRED_INT_STATUS 0xc810 >> +#define HEVC_MPRED_PIC_SIZE 0xc814 >> +#define HEVC_MPRED_PIC_SIZE_LCU 0xc818 >> +#define HEVC_MPRED_TILE_START 0xc81c >> +#define HEVC_MPRED_TILE_SIZE_LCU 0xc820 >> +#define HEVC_MPRED_REF_NUM 0xc824 >> +#define HEVC_MPRED_REF_EN_L0 0xc830 >> +#define HEVC_MPRED_REF_EN_L1 0xc834 >> +#define HEVC_MPRED_COLREF_EN_L0 0xc838 >> +#define HEVC_MPRED_COLREF_EN_L1 0xc83c >> +#define HEVC_MPRED_AXI_WCTRL 0xc840 >> +#define HEVC_MPRED_AXI_RCTRL 0xc844 >> +#define HEVC_MPRED_ABV_START_ADDR 0xc848 >> +#define HEVC_MPRED_MV_WR_START_ADDR 0xc84c >> +#define HEVC_MPRED_MV_RD_START_ADDR 0xc850 >> +#define HEVC_MPRED_MV_WPTR 0xc854 >> +#define HEVC_MPRED_MV_RPTR 0xc858 >> +#define HEVC_MPRED_MV_WR_ROW_JUMP 0xc85c >> +#define HEVC_MPRED_MV_RD_ROW_JUMP 0xc860 >> +#define HEVC_MPRED_CURR_LCU 0xc864 >> +#define HEVC_MPRED_ABV_WPTR 0xc868 >> +#define HEVC_MPRED_ABV_RPTR 0xc86c >> +#define HEVC_MPRED_CTRL2 0xc870 >> +#define HEVC_MPRED_CTRL3 0xc874 >> +#define HEVC_MPRED_L0_REF00_POC 0xc880 >> +#define HEVC_MPRED_L1_REF00_POC 0xc8c0 >> + >> +#define HEVC_MPRED_CUR_POC 0xc980 >> +#define HEVC_MPRED_COL_POC 0xc984 >> +#define HEVC_MPRED_MV_RD_END_ADDR 0xc988 >> + >> +#define HEVC_MSP 0xcc00 >> +#define HEVC_MPSR 0xcc04 >> +#define HEVC_MCPU_INTR_MSK 0xcc10 >> +#define HEVC_MCPU_INTR_REQ 0xcc14 >> +#define HEVC_CPSR 0xcc84 >> + >> +#define HEVC_IMEM_DMA_CTRL 0xcd00 >> +#define HEVC_IMEM_DMA_ADR 0xcd04 >> +#define HEVC_IMEM_DMA_COUNT 0xcd08 >> + >> +#define HEVCD_IPP_TOP_CNTL 0xd000 >> +#define HEVCD_IPP_LINEBUFF_BASE 0xd024 >> +#define HEVCD_IPP_AXIIF_CONFIG 0xd02c >> + >> +#define HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR 0xd180 >> +#define HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR 0xd184 >> +#define HEVCD_MPP_ANC2AXI_TBL_DATA 0xd190 >> + >> +#define HEVCD_MPP_ANC_CANVAS_ACCCONFIG_ADDR 0xd300 >> +#define HEVCD_MPP_ANC_CANVAS_DATA_ADDR 0xd304 >> +#define HEVCD_MPP_DECOMP_CTL1 0xd308 >> +#define HEVCD_MPP_DECOMP_CTL2 0xd30c >> +#define HEVCD_MCRCC_CTL1 0xd3c0 >> +#define HEVCD_MCRCC_CTL2 0xd3c4 >> +#define HEVCD_MCRCC_CTL3 0xd3c8 >> + >> +#define HEVC_DBLK_CFG0 0xd400 >> +#define HEVC_DBLK_CFG1 0xd404 >> +#define HEVC_DBLK_CFG2 0xd408 >> +#define HEVC_DBLK_CFG3 0xd40c >> +#define HEVC_DBLK_CFG4 0xd410 >> +#define HEVC_DBLK_CFG5 0xd414 >> +#define HEVC_DBLK_CFG6 0xd418 >> +#define HEVC_DBLK_CFG7 0xd41c >> +#define HEVC_DBLK_CFG8 0xd420 >> +#define HEVC_DBLK_CFG9 0xd424 >> +#define HEVC_DBLK_CFGA 0xd428 >> +#define HEVC_DBLK_STS0 0xd42c >> +#define HEVC_DBLK_STS1 0xd430 >> +#define HEVC_DBLK_CFGE 0xd438 >> + >> +#define HEVC_SAO_VERSION 0xd800 >> +#define HEVC_SAO_CTRL0 0xd804 >> +#define HEVC_SAO_CTRL1 0xd808 >> +#define HEVC_SAO_PIC_SIZE 0xd814 >> +#define HEVC_SAO_PIC_SIZE_LCU 0xd818 >> +#define HEVC_SAO_TILE_START 0xd81c >> +#define HEVC_SAO_TILE_SIZE_LCU 0xd820 >> +#define HEVC_SAO_Y_START_ADDR 0xd82c >> +#define HEVC_SAO_Y_LENGTH 0xd830 >> +#define HEVC_SAO_C_START_ADDR 0xd834 >> +#define HEVC_SAO_C_LENGTH 0xd838 >> +#define HEVC_SAO_Y_WPTR 0xd83c >> +#define HEVC_SAO_C_WPTR 0xd840 >> +#define HEVC_SAO_ABV_START_ADDR 0xd844 >> +#define HEVC_SAO_VB_WR_START_ADDR 0xd848 >> +#define HEVC_SAO_VB_RD_START_ADDR 0xd84c >> +#define HEVC_SAO_ABV_WPTR 0xd850 >> +#define HEVC_SAO_ABV_RPTR 0xd854 >> +#define HEVC_SAO_VB_WPTR 0xd858 >> +#define HEVC_SAO_VB_RPTR 0xd85c >> +#define HEVC_SAO_CTRL2 0xd880 >> +#define HEVC_SAO_CTRL3 0xd884 >> +#define HEVC_SAO_CTRL4 0xd888 >> +#define HEVC_SAO_CTRL5 0xd88c >> +#define HEVC_SAO_CTRL6 0xd890 >> +#define HEVC_SAO_CTRL7 0xd894 >> +#define HEVC_CM_BODY_START_ADDR 0xd898 >> +#define HEVC_CM_BODY_LENGTH 0xd89c >> +#define HEVC_CM_HEADER_START_ADDR 0xd8a0 >> +#define HEVC_CM_HEADER_LENGTH 0xd8a4 >> +#define HEVC_CM_HEADER_OFFSET 0xd8ac >> +#define HEVC_SAO_MMU_VH0_ADDR 0xd8e8 >> +#define HEVC_SAO_MMU_VH1_ADDR 0xd8ec >> + >> +#define HEVC_IQIT_CLK_RST_CTRL 0xdc00 >> +#define HEVC_IQIT_SCALELUT_WR_ADDR 0xdc08 >> +#define HEVC_IQIT_SCALELUT_RD_ADDR 0xdc0c >> +#define HEVC_IQIT_SCALELUT_DATA 0xdc10 >> + >> +#define HEVC_PSCALE_CTRL 0xe444 >> + >> +#endif >> diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c >> new file mode 100644 >> index 000000000000..af41215e106c >> --- /dev/null >> +++ b/drivers/staging/media/meson/vdec/vdec_hevc.c >> @@ -0,0 +1,231 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@xxxxxxxxxx> >> + * >> + * VDEC_HEVC is a video decoding block that allows decoding of >> + * HEVC, VP9 >> + */ >> + >> +#include <linux/firmware.h> >> +#include <linux/clk.h> >> + >> +#include "vdec_1.h" >> +#include "vdec_helpers.h" >> +#include "hevc_regs.h" >> +#include "dos_regs.h" >> + >> +/* AO Registers */ >> +#define AO_RTI_GEN_PWR_SLEEP0 0xe8 >> +#define AO_RTI_GEN_PWR_ISO0 0xec >> + #define GEN_PWR_VDEC_HEVC (BIT(7) | BIT(6)) >> + #define GEN_PWR_VDEC_HEVC_SM1 (BIT(2)) >> + >> +#define MC_SIZE (4096 * 4) >> + >> +static int vdec_hevc_load_firmware(struct amvdec_session *sess, >> + const char *fwname) >> +{ >> + struct amvdec_core *core = sess->core; >> + struct device *dev = core->dev_dec; >> + const struct firmware *fw; >> + static void *mc_addr; >> + static dma_addr_t mc_addr_map; >> + int ret; >> + u32 i = 100; >> + >> + ret = request_firmware(&fw, fwname, dev); >> + if (ret < 0) { >> + dev_err(dev, "Unable to request firmware %s\n", fwname); >> + return ret; >> + } >> + >> + if (fw->size < MC_SIZE) { >> + dev_err(dev, "Firmware size %zu is too small. Expected %u.\n", >> + fw->size, MC_SIZE); >> + ret = -EINVAL; >> + goto release_firmware; >> + } >> + >> + mc_addr = dma_alloc_coherent(core->dev, MC_SIZE, &mc_addr_map, >> + GFP_KERNEL); >> + if (!mc_addr) { >> + dev_err(dev, "Failed allocating memory for firmware loading\n"); >> + ret = -ENOMEM; >> + goto release_firmware; >> + } >> + >> + memcpy(mc_addr, fw->data, MC_SIZE); >> + >> + amvdec_write_dos(core, HEVC_MPSR, 0); >> + amvdec_write_dos(core, HEVC_CPSR, 0); >> + >> + amvdec_write_dos(core, HEVC_IMEM_DMA_ADR, mc_addr_map); >> + amvdec_write_dos(core, HEVC_IMEM_DMA_COUNT, MC_SIZE / 4); >> + amvdec_write_dos(core, HEVC_IMEM_DMA_CTRL, (0x8000 | (7 << 16))); >> + >> + while (i && (readl(core->dos_base + HEVC_IMEM_DMA_CTRL) & 0x8000)) >> + i--; >> + >> + if (i == 0) { >> + dev_err(dev, "Firmware load fail (DMA hang?)\n"); >> + ret = -ENODEV; >> + } >> + >> + dma_free_coherent(core->dev, MC_SIZE, mc_addr, mc_addr_map); >> +release_firmware: >> + release_firmware(fw); >> + return ret; >> +} >> + >> +static void vdec_hevc_stbuf_init(struct amvdec_session *sess) >> +{ >> + struct amvdec_core *core = sess->core; >> + >> + amvdec_write_dos(core, HEVC_STREAM_CONTROL, >> + amvdec_read_dos(core, HEVC_STREAM_CONTROL) & ~1); >> + amvdec_write_dos(core, HEVC_STREAM_START_ADDR, sess->vififo_paddr); >> + amvdec_write_dos(core, HEVC_STREAM_END_ADDR, >> + sess->vififo_paddr + sess->vififo_size); >> + amvdec_write_dos(core, HEVC_STREAM_RD_PTR, sess->vififo_paddr); >> + amvdec_write_dos(core, HEVC_STREAM_WR_PTR, sess->vififo_paddr); >> +} >> + >> +/* VDEC_HEVC specific ESPARSER configuration */ >> +static void vdec_hevc_conf_esparser(struct amvdec_session *sess) >> +{ >> + struct amvdec_core *core = sess->core; >> + >> + /* set vififo_vbuf_rp_sel=>vdec_hevc */ >> + amvdec_write_dos(core, DOS_GEN_CTRL0, 3 << 1); >> + amvdec_write_dos(core, HEVC_STREAM_CONTROL, >> + amvdec_read_dos(core, HEVC_STREAM_CONTROL) | BIT(3)); >> + amvdec_write_dos(core, HEVC_STREAM_CONTROL, >> + amvdec_read_dos(core, HEVC_STREAM_CONTROL) | 1); >> + amvdec_write_dos(core, HEVC_STREAM_FIFO_CTL, >> + amvdec_read_dos(core, HEVC_STREAM_FIFO_CTL) | BIT(29)); >> +} >> + >> +static u32 vdec_hevc_vififo_level(struct amvdec_session *sess) >> +{ >> + return readl_relaxed(sess->core->dos_base + HEVC_STREAM_LEVEL); >> +} >> + >> +static int vdec_hevc_stop(struct amvdec_session *sess) >> +{ >> + struct amvdec_core *core = sess->core; >> + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; >> + >> + /* Disable interrupt */ >> + amvdec_write_dos(core, HEVC_ASSIST_MBOX1_MASK, 0); >> + /* Disable firmware processor */ >> + amvdec_write_dos(core, HEVC_MPSR, 0); >> + >> + if (sess->priv) >> + codec_ops->stop(sess); >> + >> + /* Enable VDEC_HEVC Isolation */ >> + if (core->platform->revision == VDEC_REVISION_SM1) >> + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, >> + GEN_PWR_VDEC_HEVC_SM1, >> + GEN_PWR_VDEC_HEVC_SM1); >> + else >> + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, >> + 0xc00, 0xc00); >> + >> + /* VDEC_HEVC Memories */ >> + amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0xffffffffUL); >> + >> + if (core->platform->revision == VDEC_REVISION_SM1) >> + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, >> + GEN_PWR_VDEC_HEVC_SM1, >> + GEN_PWR_VDEC_HEVC_SM1); >> + else >> + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, >> + GEN_PWR_VDEC_HEVC, GEN_PWR_VDEC_HEVC); >> + >> + clk_disable_unprepare(core->vdec_hevc_clk); >> + if (core->platform->revision == VDEC_REVISION_G12A || >> + core->platform->revision == VDEC_REVISION_SM1) >> + clk_disable_unprepare(core->vdec_hevcf_clk); >> + >> + return 0; >> +} >> + >> +static int vdec_hevc_start(struct amvdec_session *sess) >> +{ >> + int ret; >> + struct amvdec_core *core = sess->core; >> + struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops; >> + >> + if (core->platform->revision == VDEC_REVISION_G12A || >> + core->platform->revision == VDEC_REVISION_SM1) { >> + clk_set_rate(core->vdec_hevcf_clk, 666666666); >> + ret = clk_prepare_enable(core->vdec_hevcf_clk); >> + if (ret) >> + return ret; >> + } >> + >> + clk_set_rate(core->vdec_hevc_clk, 666666666); >> + ret = clk_prepare_enable(core->vdec_hevc_clk); >> + if (ret) >> + return ret; >> + >> + if (core->platform->revision == VDEC_REVISION_SM1) >> + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, >> + GEN_PWR_VDEC_HEVC_SM1, 0); >> + else >> + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, >> + GEN_PWR_VDEC_HEVC, 0); >> + udelay(10); >> + >> + /* Reset VDEC_HEVC*/ >> + amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); >> + amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); >> + >> + amvdec_write_dos(core, DOS_GCLK_EN3, 0xffffffff); >> + >> + /* VDEC_HEVC Memories */ >> + amvdec_write_dos(core, DOS_MEM_PD_HEVC, 0x00000000); >> + >> + /* Remove VDEC_HEVC Isolation */ >> + if (core->platform->revision == VDEC_REVISION_SM1) >> + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, >> + GEN_PWR_VDEC_HEVC_SM1, 0); >> + else >> + regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_ISO0, >> + 0xc00, 0); >> + >> + amvdec_write_dos(core, DOS_SW_RESET3, 0xffffffff); >> + amvdec_write_dos(core, DOS_SW_RESET3, 0x00000000); >> + >> + vdec_hevc_stbuf_init(sess); >> + >> + ret = vdec_hevc_load_firmware(sess, sess->fmt_out->firmware_path); >> + if (ret) >> + goto stop; >> + >> + ret = codec_ops->start(sess); >> + if (ret) >> + goto stop; >> + >> + amvdec_write_dos(core, DOS_SW_RESET3, BIT(12) | BIT(11)); >> + amvdec_write_dos(core, DOS_SW_RESET3, 0); >> + amvdec_read_dos(core, DOS_SW_RESET3); >> + >> + amvdec_write_dos(core, HEVC_MPSR, 1); >> + /* Let the firmware settle */ >> + udelay(10); >> + >> + return 0; >> + >> +stop: >> + vdec_hevc_stop(sess); >> + return ret; >> +} >> + >> +struct amvdec_ops vdec_hevc_ops = { >> + .start = vdec_hevc_start, >> + .stop = vdec_hevc_stop, >> + .conf_esparser = vdec_hevc_conf_esparser, >> + .vififo_level = vdec_hevc_vififo_level, >> +}; >> diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.h b/drivers/staging/media/meson/vdec/vdec_hevc.h >> new file mode 100644 >> index 000000000000..cd576a73a966 >> --- /dev/null >> +++ b/drivers/staging/media/meson/vdec/vdec_hevc.h >> @@ -0,0 +1,13 @@ >> +/* SPDX-License-Identifier: GPL-2.0+ */ >> +/* >> + * Copyright (C) 2018 Maxime Jourdan <maxi.jourdan@xxxxxxxxxx> >> + */ >> + >> +#ifndef __MESON_VDEC_VDEC_HEVC_H_ >> +#define __MESON_VDEC_VDEC_HEVC_H_ >> + >> +#include "vdec.h" >> + >> +extern struct amvdec_ops vdec_hevc_ops; >> + >> +#endif >> >