armbian_build/patch/kernel/meson64-current/3-0012-media-meson-vp9-add-IOMMU-support.patch
Igor Pečovnik 150ac0c2af
Remove K<4, change branches, new features (#1586)
AR-1 - Adding support category for distributions
AR-4 - Remove Allwinner legacy
AR-5 - Drop Udoo family and move Udoo board into newly created imx6 family
AR-9 - Rename sunxi-next to sunxi-legacy
AR-10 - Rename sunxi-dev to sunxi-current
AR-11 - Adding Radxa Rockpi S support
AR-13 - Rename rockchip64-default to rockchip64-legacy
AR-14 - Add rockchip64-current as mainline source
AR-15 - Drop Rockchip 4.19.y NEXT, current become 5.3.y
AR-16 - Rename RK3399 default to legacy
AR-17 - Rename Odroid XU4 next and default to legacy 4.14.y, add DEV 5.4.y
AR-18 - Add Odroid N2 current mainline
AR-19 - Move Odroid C1 to meson family
AR-20 - Rename mvebu64-default to mvebu64-legacy
AR-21 - Rename mvebu-default to mvebu-legacy
AR-22 - Rename mvebu-next to mvebu-current
AR-23 - Drop meson64 default and next, current becomes former DEV 5.3.y
AR-24 - Drop cubox family and move Cubox/Hummingboard boards under imx6
AR-26 - Adjust motd
AR-27 - Enabling distribution release status
AR-28 - Added new GCC compilers
AR-29 - Implementing Ubuntu Eoan
AR-30 - Add desktop packages per board or family
AR-31 - Remove (Ubuntu/Debian) distribution name from image filename
AR-32 - Move arch configs from configuration.sh to separate arm64 and armhf config files
AR-33 - Revision numbers for beta builds changed to day_in_the_year
AR-34 - Patches support linked patches
AR-35 - Break meson64 family into gxbb and gxl
AR-36 - Add Nanopineo2 Black
AR-38 - Upgrade option from old branches to new one via armbian-config
AR-41 - Show full timezone info
AR-43 - Merge Odroid N2 to meson64
AR-44 - Enable FORCE_BOOTSCRIPT_UPDATE for all builds
2019-11-19 23:25:39 +01:00

774 lines
27 KiB
Diff

From 58cd69efd60bbf24e4795ac8635769e96eb3b079 Mon Sep 17 00:00:00 2001
From: Maxime Jourdan <mjourdan@baylibre.com>
Date: Fri, 1 Mar 2019 12:41:03 +0100
Subject: [PATCH 12/14] media: meson: vp9: add IOMMU support
Starting with GXL (S905X), the HEVC/VP9 decoder hardware supports an
IOMMU to access the decoded frames. This IOMMU is controlled by writing
the buffer's page IDs to the firmware, which then does the actual work.
This commit adds support for using the IOMMU with VP9/HEVC on G12A, the
first SoC on which it becomes mandatory.
Signed-off-by: Maxime Jourdan <mjourdan@baylibre.com>
---
drivers/staging/media/meson/vdec/codec_hevc.c | 35 ++--
.../media/meson/vdec/codec_hevc_common.c | 177 ++++++++++++++----
.../media/meson/vdec/codec_hevc_common.h | 31 ++-
drivers/staging/media/meson/vdec/codec_vp9.c | 71 ++++---
drivers/staging/media/meson/vdec/hevc_regs.h | 5 +
drivers/staging/media/meson/vdec/vdec.h | 5 -
drivers/staging/media/meson/vdec/vdec_hevc.c | 14 +-
7 files changed, 255 insertions(+), 83 deletions(-)
diff --git a/drivers/staging/media/meson/vdec/codec_hevc.c b/drivers/staging/media/meson/vdec/codec_hevc.c
index e16e937d56e8..65d2ad4d8345 100644
--- a/drivers/staging/media/meson/vdec/codec_hevc.c
+++ b/drivers/staging/media/meson/vdec/codec_hevc.c
@@ -75,6 +75,7 @@
#define MPRED_MV_SIZE (MPRED_MV_BUF_SIZE * MAX_REF_PIC_NUM)
#define RPM_BUF_SIZE 0x100
#define LMEM_SIZE 0xA00
+#define MMU_MAP_SIZE 0x4800
#define IPP_OFFSET 0x00
#define SAO_ABV_OFFSET (IPP_OFFSET + IPP_SIZE)
@@ -95,6 +96,7 @@
#define MPRED_MV_OFFSET (MPRED_ABV_OFFSET + MPRED_ABV_SIZE)
#define RPM_OFFSET (MPRED_MV_OFFSET + MPRED_MV_SIZE)
#define LMEM_OFFSET (RPM_OFFSET + RPM_BUF_SIZE)
+#define MMU_MAP_OFFSET (LMEM_OFFSET + LMEM_SIZE)
/* ISR decode status */
#define HEVC_DEC_IDLE 0x0
@@ -236,6 +238,9 @@ struct hevc_frame {
struct codec_hevc {
struct mutex lock;
+ /* Common part of the HEVC decoder */
+ struct codec_hevc_common common;
+
/* Buffer for the HEVC Workspace */
void *workspace_vaddr;
dma_addr_t workspace_paddr;
@@ -517,15 +522,20 @@ codec_hevc_setup_workspace(struct amvdec_core *core, struct codec_hevc *hevc)
amvdec_write_dos(core, HEVC_PPS_BUFFER, wkaddr + PPS_OFFSET);
amvdec_write_dos(core, HEVC_SAO_UP, wkaddr + SAO_UP_OFFSET);
+ if (core->platform->revision >= VDEC_REVISION_G12A)
+ amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR,
+ wkaddr + MMU_MAP_OFFSET);
+
/* No MMU */
- amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER,
+ /*amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER,
wkaddr + SWAP_BUF_OFFSET);
amvdec_write_dos(core, HEVC_STREAM_SWAP_BUFFER2,
- wkaddr + SWAP_BUF2_OFFSET);
+ wkaddr + SWAP_BUF2_OFFSET);*/
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);
+ amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET);
return 0;
}
@@ -549,9 +559,10 @@ static int codec_hevc_start(struct amvdec_session *sess)
if (ret)
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 = BIT(0); /* stream_fetch_enable */
+ if (core->platform->revision >= VDEC_REVISION_G12A)
+ val |= (0xf << 25); /* arwlen_axi_max */
+ amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, val);
val = amvdec_read_dos(core, HEVC_PARSER_INT_CONTROL) & 0x03ffffff;
val |= (3 << 29) | BIT(27) | BIT(24) | BIT(22) | BIT(7) | BIT(4) |
@@ -608,9 +619,9 @@ static int codec_hevc_start(struct amvdec_session *sess)
goto free_hevc;
}
- amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr);
+ /*amvdec_write_dos(core, HEVC_AUX_ADR, hevc->aux_paddr);
amvdec_write_dos(core, HEVC_AUX_DATA_SIZE,
- (((SIZE_AUX) >> 4) << 16) | 0);
+ (((SIZE_AUX) >> 4) << 16) | 0);*/
mutex_init(&hevc->lock);
sess->priv = hevc;
@@ -652,7 +663,7 @@ static int codec_hevc_stop(struct amvdec_session *sess)
dma_free_coherent(core->dev, SIZE_AUX,
hevc->aux_vaddr, hevc->aux_paddr);
- codec_hevc_free_fbc_buffers(sess);
+ codec_hevc_free_fbc_buffers(sess, &hevc->common);
mutex_unlock(&hevc->lock);
mutex_destroy(&hevc->lock);
@@ -732,7 +743,7 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame)
if (codec_hevc_use_downsample(sess->pixfmt_cap, hevc->is_10bit))
buf_y_paddr =
- sess->fbc_buffer_paddr[frame->vbuf->vb2_buf.index];
+ hevc->common.fbc_buffer_paddr[frame->vbuf->vb2_buf.index];
else
buf_y_paddr =
vb2_dma_contig_plane_dma_addr(&frame->vbuf->vb2_buf, 0);
@@ -776,7 +787,7 @@ codec_hevc_set_sao(struct amvdec_session *sess, struct hevc_frame *frame)
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_STS1 + 16, BIT(28));
}
amvdec_write_dos(core, HEVC_DBLK_CFG2,
@@ -1323,7 +1334,7 @@ static void codec_hevc_resume(struct amvdec_session *sess)
{
struct codec_hevc *hevc = sess->priv;
- if (codec_hevc_setup_buffers(sess, hevc->is_10bit)) {
+ if (codec_hevc_setup_buffers(sess, &hevc->common, hevc->is_10bit)) {
amvdec_abort(sess);
return;
}
@@ -1340,6 +1351,8 @@ static irqreturn_t codec_hevc_threaded_isr(struct amvdec_session *sess)
struct codec_hevc *hevc = sess->priv;
u32 dec_status = amvdec_read_dos(core, HEVC_DEC_STATUS_REG);
+ printk("ISR!\n");
+
if (!hevc)
return IRQ_HANDLED;
diff --git a/drivers/staging/media/meson/vdec/codec_hevc_common.c b/drivers/staging/media/meson/vdec/codec_hevc_common.c
index 5c372a9b0f03..de7eb6cfbe85 100644
--- a/drivers/staging/media/meson/vdec/codec_hevc_common.c
+++ b/drivers/staging/media/meson/vdec/codec_hevc_common.c
@@ -10,6 +10,9 @@
#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)
{
@@ -23,7 +26,12 @@ void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit)
return;
}
- amvdec_write_dos(core, HEVCD_MPP_DECOMP_CTL1, 0);
+ 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);
+
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);
@@ -31,8 +39,9 @@ void codec_hevc_setup_decode_head(struct amvdec_session *sess, int is_10bit)
}
EXPORT_SYMBOL_GPL(codec_hevc_setup_decode_head);
-static void
-codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit)
+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;
@@ -46,22 +55,26 @@ codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit)
amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CONF_ADDR, 0);
v4l2_m2m_for_each_dst_buf(sess->m2m_ctx, buf) {
- idx = buf->vb.vb2_buf.index;
+ struct vb2_buffer *vb = &buf->vb.vb2_buf;
+ idx = vb->index;
if (codec_hevc_use_downsample(sess->pixfmt_cap, is_10bit))
- buf_y_paddr = sess->fbc_buffer_paddr[idx];
+ buf_y_paddr = comm->fbc_buffer_paddr[idx];
else
- buf_y_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+ 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);
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ val);
} else {
- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1);
+ 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);
+ 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);
+ amvdec_write_dos(core, HEVCD_MPP_ANC2AXI_TBL_CMD_ADDR,
+ val);
}
}
@@ -80,32 +93,37 @@ codec_hevc_setup_buffers_gxbb(struct amvdec_session *sess, int is_10bit)
amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
}
-static void
-codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit)
+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 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 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) {
- u32 idx = buf->vb.vb2_buf.index;
+ 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_downsample(sess->pixfmt_cap, is_10bit))
- buf_y_paddr = sess->fbc_buffer_paddr[idx];
+ 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(&buf->vb.vb2_buf, 0);
+ 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(sess->pixfmt_cap, is_10bit)) {
- buf_uv_paddr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 1);
+
+ 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);
}
@@ -117,24 +135,26 @@ codec_hevc_setup_buffers_gxl(struct amvdec_session *sess, int is_10bit)
amvdec_write_dos(core, HEVCD_MPP_ANC_CANVAS_DATA_ADDR, 0);
}
-void codec_hevc_free_fbc_buffers(struct amvdec_session *sess)
+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 (sess->fbc_buffer_vaddr[i]) {
+ if (comm->fbc_buffer_vaddr[i]) {
dma_free_coherent(dev, am21_size,
- sess->fbc_buffer_vaddr[i],
- sess->fbc_buffer_paddr[i]);
- sess->fbc_buffer_vaddr[i] = NULL;
+ 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)
+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;
@@ -147,33 +167,118 @@ static int codec_hevc_alloc_fbc_buffers(struct amvdec_session *sess)
GFP_KERNEL);
if (!vaddr) {
dev_err(dev, "Couldn't allocate FBC buffer %u\n", idx);
- codec_hevc_free_fbc_buffers(sess);
+ 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;
}
- sess->fbc_buffer_vaddr[idx] = vaddr;
- sess->fbc_buffer_paddr[idx] = paddr;
+ comm->mmu_header_vaddr[idx] = vaddr;
+ comm->mmu_header_paddr[idx] = paddr;
}
return 0;
}
-int codec_hevc_setup_buffers(struct amvdec_session *sess, int is_10bit)
+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);
+ 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, is_10bit);
+ codec_hevc_setup_buffers_gxbb(sess, comm, is_10bit);
else
- codec_hevc_setup_buffers_gxl(sess, is_10bit);
+ codec_hevc_setup_buffers_gxl(sess, comm, is_10bit);
return 0;
}
-EXPORT_SYMBOL_GPL(codec_hevc_setup_buffers);
\ No newline at end of file
+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
index 7c8891529ac8..89c8b61f8a94 100644
--- a/drivers/staging/media/meson/vdec/codec_hevc_common.h
+++ b/drivers/staging/media/meson/vdec/codec_hevc_common.h
@@ -25,6 +25,19 @@ static const u16 vdec_hevc_parser_cmd[] = {
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)
{
@@ -37,13 +50,27 @@ static inline int codec_hevc_use_downsample(u32 pixfmt, int is_10bit)
return pixfmt == V4L2_PIX_FMT_NV12M && 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);
+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);
-int codec_hevc_setup_buffers(struct amvdec_session *sess, 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/codec_vp9.c b/drivers/staging/media/meson/vdec/codec_vp9.c
index 39e8eb5937bf..b1643cc01f68 100644
--- a/drivers/staging/media/meson/vdec/codec_vp9.c
+++ b/drivers/staging/media/meson/vdec/codec_vp9.c
@@ -219,6 +219,9 @@ struct vp9_frame {
struct codec_vp9 {
struct mutex lock;
+ /* Common part with the HEVC decoder */
+ struct codec_hevc_common common;
+
/* Buffer for the VP9 Workspace */
void *workspace_vaddr;
dma_addr_t workspace_paddr;
@@ -438,27 +441,26 @@ static u32 codec_vp9_num_pending_bufs(struct amvdec_session *sess)
return vp9->frames_num;
}
-static int
-codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9)
+static int codec_vp9_alloc_workspace(struct amvdec_core *core,
+ struct codec_vp9 *vp9)
{
- dma_addr_t wkaddr;
-
/* Allocate some memory for the VP9 decoder's state */
vp9->workspace_vaddr = dma_alloc_coherent(core->dev, SIZE_WORKSPACE,
- &wkaddr, GFP_KERNEL);
+ &vp9->workspace_paddr, GFP_KERNEL);
if (!vp9->workspace_vaddr) {
dev_err(core->dev, "Failed to allocate VP9 Workspace\n");
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);
+ return 0;
+}
- vp9->workspace_paddr = wkaddr;
+static void codec_vp9_setup_workspace(struct amvdec_session *sess,
+ struct codec_vp9 *vp9)
+{
+ struct amvdec_core *core = sess->core;
+ u32 revision = core->platform->revision;
+ dma_addr_t wkaddr = vp9->workspace_paddr;
amvdec_write_dos(core, HEVCD_IPP_LINEBUFF_BASE, wkaddr + IPP_OFFSET);
amvdec_write_dos(core, VP9_RPM_BUFFER, wkaddr + RPM_OFFSET);
@@ -466,7 +468,6 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9)
amvdec_write_dos(core, VP9_PPS_BUFFER, wkaddr + PPS_OFFSET);
amvdec_write_dos(core, VP9_SAO_UP, wkaddr + SAO_UP_OFFSET);
- /* No MMU */
amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER,
wkaddr + SWAP_BUF_OFFSET);
amvdec_write_dos(core, VP9_STREAM_SWAP_BUFFER2,
@@ -484,7 +485,19 @@ codec_vp9_setup_workspace(struct amvdec_core *core, struct codec_vp9 *vp9)
amvdec_write_dos(core, VP9_COUNT_SWAP_BUFFER, wkaddr + COUNT_OFFSET);
amvdec_write_dos(core, LMEM_DUMP_ADR, wkaddr + LMEM_OFFSET);
- return 0;
+ if (codec_hevc_use_mmu(revision, sess->pixfmt_cap, vp9->is_10bit)) {
+ amvdec_write_dos(core, HEVC_SAO_MMU_VH0_ADDR,
+ wkaddr + MMU_VBH_OFFSET);
+ amvdec_write_dos(core, HEVC_SAO_MMU_VH1_ADDR,
+ wkaddr + MMU_VBH_OFFSET + (MMU_VBH_SIZE / 2));
+
+ if (revision >= VDEC_REVISION_G12A)
+ amvdec_write_dos(core, HEVC_ASSIST_MMU_MAP_ADDR,
+ vp9->common.mmu_map_paddr);
+ else
+ amvdec_write_dos(core, VP9_MMU_MAP_BUFFER,
+ vp9->common.mmu_map_paddr);
+ }
}
static int codec_vp9_start(struct amvdec_session *sess)
@@ -499,10 +512,11 @@ static int codec_vp9_start(struct amvdec_session *sess)
if (!vp9)
return -ENOMEM;
- ret = codec_vp9_setup_workspace(core, vp9);
+ ret = codec_vp9_alloc_workspace(core, vp9);
if (ret)
goto free_vp9;
+ codec_vp9_setup_workspace(sess, vp9);
amvdec_write_dos_bits(core, HEVC_STREAM_CONTROL, BIT(0));
// stream_fifo_hole
if (core->platform->revision == VDEC_REVISION_G12A)
@@ -575,7 +589,7 @@ static int codec_vp9_stop(struct amvdec_session *sess)
vp9->workspace_vaddr,
vp9->workspace_paddr);
- codec_hevc_free_fbc_buffers(sess);
+ codec_hevc_free_fbc_buffers(sess, &vp9->common);
return 0;
}
@@ -590,7 +604,7 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb
if (codec_hevc_use_downsample(sess->pixfmt_cap, vp9->is_10bit))
buf_y_paddr =
- sess->fbc_buffer_paddr[vb->index];
+ vp9->common.fbc_buffer_paddr[vb->index];
else
buf_y_paddr =
vb2_dma_contig_plane_dma_addr(vb, 0);
@@ -601,6 +615,7 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb
amvdec_write_dos(core, HEVC_CM_BODY_START_ADDR, buf_y_paddr);
}
+
if (sess->pixfmt_cap == V4L2_PIX_FMT_NV12M) {
buf_y_paddr =
vb2_dma_contig_plane_dma_addr(vb, 0);
@@ -612,13 +627,22 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb
amvdec_write_dos(core, HEVC_SAO_C_WPTR, buf_u_v_paddr);
}
+ if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap,
+ vp9->is_10bit)) {
+ amvdec_write_dos(core, HEVC_CM_HEADER_START_ADDR,
+ vp9->common.mmu_header_paddr[vb->index]);
+ /* use HEVC_CM_HEADER_START_ADDR */
+ amvdec_write_dos_bits(core, HEVC_SAO_CTRL5, BIT(10));
+ }
+
amvdec_write_dos(core, HEVC_SAO_Y_LENGTH,
amvdec_get_output_size(sess));
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));
+ 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));
@@ -630,8 +654,6 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb
/* 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;
@@ -644,7 +666,6 @@ static void codec_vp9_set_sao(struct amvdec_session *sess, struct vb2_buffer *vb
}
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 */
@@ -919,6 +940,11 @@ static void codec_vp9_process_frame(struct amvdec_session *sess)
codec_vp9_update_next_ref(vp9);
codec_vp9_show_existing_frame(vp9);
+ if (codec_hevc_use_mmu(core->platform->revision, sess->pixfmt_cap,
+ vp9->is_10bit))
+ codec_hevc_fill_mmu_map(sess, &vp9->common,
+ &vp9->cur_frame->vbuf->vb2_buf);
+
intra_only = param->p.show_frame ? 0 : param->p.intra_only;
/* clear mpred (for keyframe only) */
if (param->p.frame_type != KEY_FRAME && !intra_only) {
@@ -971,11 +997,12 @@ static void codec_vp9_resume(struct amvdec_session *sess)
{
struct codec_vp9 *vp9 = sess->priv;
- if (codec_hevc_setup_buffers(sess, vp9->is_10bit)) {
+ if (codec_hevc_setup_buffers(sess, &vp9->common, vp9->is_10bit)) {
amvdec_abort(sess);
return;
}
+ codec_vp9_setup_workspace(sess, vp9);
codec_hevc_setup_decode_head(sess, vp9->is_10bit);
codec_vp9_process_lf(vp9);
codec_vp9_process_frame(sess);
diff --git a/drivers/staging/media/meson/vdec/hevc_regs.h b/drivers/staging/media/meson/vdec/hevc_regs.h
index dc2c2e085b05..0392f41a1eed 100644
--- a/drivers/staging/media/meson/vdec/hevc_regs.h
+++ b/drivers/staging/media/meson/vdec/hevc_regs.h
@@ -6,6 +6,8 @@
#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
@@ -200,8 +202,11 @@
#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
diff --git a/drivers/staging/media/meson/vdec/vdec.h b/drivers/staging/media/meson/vdec/vdec.h
index 95415212b282..95b4c5761a27 100644
--- a/drivers/staging/media/meson/vdec/vdec.h
+++ b/drivers/staging/media/meson/vdec/vdec.h
@@ -20,8 +20,6 @@
/* 32 buffers in 3-plane YUV420 */
#define MAX_CANVAS (32 * 3)
-#define MAX_REF_PIC_NUM 24
-
struct amvdec_buffer {
struct list_head list;
struct vb2_buffer *vb;
@@ -261,9 +259,6 @@ struct amvdec_session {
u32 wrap_count;
u32 fw_idx_to_vb2_idx[32];
- void *fbc_buffer_vaddr[MAX_REF_PIC_NUM];
- dma_addr_t fbc_buffer_paddr[MAX_REF_PIC_NUM];
-
enum amvdec_status status;
void *priv;
};
diff --git a/drivers/staging/media/meson/vdec/vdec_hevc.c b/drivers/staging/media/meson/vdec/vdec_hevc.c
index 730ecd771643..70db09c052c3 100644
--- a/drivers/staging/media/meson/vdec/vdec_hevc.c
+++ b/drivers/staging/media/meson/vdec/vdec_hevc.c
@@ -123,9 +123,9 @@ 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);
+ clk_disable_unprepare(core->vdec_hevc_clk);
if (core->platform->revision == VDEC_REVISION_G12A)
clk_disable_unprepare(core->vdec_hevcf_clk);
- clk_disable_unprepare(core->vdec_hevc_clk);
return 0;
}
@@ -136,11 +136,6 @@ static int vdec_hevc_start(struct amvdec_session *sess)
struct amvdec_core *core = sess->core;
struct amvdec_codec_ops *codec_ops = sess->fmt_out->codec_ops;
- 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_G12A) {
clk_set_rate(core->vdec_hevcf_clk, 666666666);
ret = clk_prepare_enable(core->vdec_hevcf_clk);
@@ -148,6 +143,11 @@ static int vdec_hevc_start(struct amvdec_session *sess)
return ret;
}
+ clk_set_rate(core->vdec_hevc_clk, 666666666);
+ ret = clk_prepare_enable(core->vdec_hevc_clk);
+ if (ret)
+ return ret;
+
regmap_update_bits(core->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
GEN_PWR_VDEC_HEVC, 0);
udelay(10);
@@ -177,7 +177,7 @@ static int vdec_hevc_start(struct amvdec_session *sess)
if (ret)
goto stop;
- amvdec_write_dos(core, DOS_SW_RESET3, BIT(12)|BIT(11));
+ 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);
--
2.20.1