From 43ecec16c4face9a59e81771e7cbff4671c62117 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Mar 2022 11:18:18 +0100 Subject: media: platform: rename s5p-mfc/ to samsung/s5p-mfc/ As the end goal is to have platform drivers split by vendor, rename s5p-mfc/ to samsung/s5p-mfc/. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- drivers/media/platform/Makefile | 2 +- drivers/media/platform/s5p-mfc/Kconfig | 9 - drivers/media/platform/s5p-mfc/Makefile | 7 - drivers/media/platform/s5p-mfc/regs-mfc-v10.h | 87 - drivers/media/platform/s5p-mfc/regs-mfc-v6.h | 408 --- drivers/media/platform/s5p-mfc/regs-mfc-v7.h | 57 - drivers/media/platform/s5p-mfc/regs-mfc-v8.h | 123 - drivers/media/platform/s5p-mfc/regs-mfc.h | 459 ---- drivers/media/platform/s5p-mfc/s5p_mfc.c | 1680 ------------ drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c | 25 - drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h | 31 - drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c | 163 -- drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h | 16 - drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | 169 -- drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h | 16 - drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 792 ------ drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 482 ---- drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h | 29 - drivers/media/platform/s5p-mfc/s5p_mfc_debug.h | 51 - drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 1218 --------- drivers/media/platform/s5p-mfc/s5p_mfc_dec.h | 20 - drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 2697 -------------------- drivers/media/platform/s5p-mfc/s5p_mfc_enc.h | 20 - drivers/media/platform/s5p-mfc/s5p_mfc_intr.c | 88 - drivers/media/platform/s5p-mfc/s5p_mfc_intr.h | 23 - drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h | 28 - drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | 124 - drivers/media/platform/s5p-mfc/s5p_mfc_opr.h | 339 --- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 1637 ------------ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h | 82 - drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 2534 ------------------ drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h | 57 - drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 119 - drivers/media/platform/s5p-mfc/s5p_mfc_pm.h | 20 - drivers/media/platform/samsung/s5p-mfc/Kconfig | 9 + drivers/media/platform/samsung/s5p-mfc/Makefile | 7 + .../media/platform/samsung/s5p-mfc/regs-mfc-v10.h | 87 + .../media/platform/samsung/s5p-mfc/regs-mfc-v6.h | 408 +++ .../media/platform/samsung/s5p-mfc/regs-mfc-v7.h | 57 + .../media/platform/samsung/s5p-mfc/regs-mfc-v8.h | 123 + drivers/media/platform/samsung/s5p-mfc/regs-mfc.h | 459 ++++ drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c | 1680 ++++++++++++ .../media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c | 25 + .../media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h | 31 + .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c | 163 ++ .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h | 16 + .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c | 169 ++ .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h | 16 + .../platform/samsung/s5p-mfc/s5p_mfc_common.h | 792 ++++++ .../media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c | 482 ++++ .../media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.h | 29 + .../media/platform/samsung/s5p-mfc/s5p_mfc_debug.h | 51 + .../media/platform/samsung/s5p-mfc/s5p_mfc_dec.c | 1218 +++++++++ .../media/platform/samsung/s5p-mfc/s5p_mfc_dec.h | 20 + .../media/platform/samsung/s5p-mfc/s5p_mfc_enc.c | 2697 ++++++++++++++++++++ .../media/platform/samsung/s5p-mfc/s5p_mfc_enc.h | 20 + .../media/platform/samsung/s5p-mfc/s5p_mfc_intr.c | 88 + .../media/platform/samsung/s5p-mfc/s5p_mfc_intr.h | 23 + .../media/platform/samsung/s5p-mfc/s5p_mfc_iommu.h | 28 + .../media/platform/samsung/s5p-mfc/s5p_mfc_opr.c | 124 + .../media/platform/samsung/s5p-mfc/s5p_mfc_opr.h | 339 +++ .../platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c | 1637 ++++++++++++ .../platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h | 82 + .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c | 2534 ++++++++++++++++++ .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h | 57 + .../media/platform/samsung/s5p-mfc/s5p_mfc_pm.c | 119 + .../media/platform/samsung/s5p-mfc/s5p_mfc_pm.h | 20 + 68 files changed, 13612 insertions(+), 13612 deletions(-) delete mode 100644 drivers/media/platform/s5p-mfc/Kconfig delete mode 100644 drivers/media/platform/s5p-mfc/Makefile delete mode 100644 drivers/media/platform/s5p-mfc/regs-mfc-v10.h delete mode 100644 drivers/media/platform/s5p-mfc/regs-mfc-v6.h delete mode 100644 drivers/media/platform/s5p-mfc/regs-mfc-v7.h delete mode 100644 drivers/media/platform/s5p-mfc/regs-mfc-v8.h delete mode 100644 drivers/media/platform/s5p-mfc/regs-mfc.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_common.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_debug.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_dec.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_dec.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_enc.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_enc.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_intr.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_intr.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_opr.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_opr.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_pm.c delete mode 100644 drivers/media/platform/s5p-mfc/s5p_mfc_pm.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/Kconfig create mode 100644 drivers/media/platform/samsung/s5p-mfc/Makefile create mode 100644 drivers/media/platform/samsung/s5p-mfc/regs-mfc-v10.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/regs-mfc-v6.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/regs-mfc.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_debug.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_intr.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_intr.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_iommu.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c create mode 100644 drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.h (limited to 'drivers/media') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 5f7a89e2af80..c95a8b283d2a 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -87,12 +87,12 @@ source "drivers/media/platform/omap3isp/Kconfig" source "drivers/media/platform/qcom/Kconfig" source "drivers/media/platform/renesas/Kconfig" source "drivers/media/platform/rockchip/Kconfig" -source "drivers/media/platform/s5p-mfc/Kconfig" source "drivers/media/platform/samsung/exynos-gsc/Kconfig" source "drivers/media/platform/samsung/exynos4-is/Kconfig" source "drivers/media/platform/samsung/s3c-camif/Kconfig" source "drivers/media/platform/samsung/s5p-g2d/Kconfig" source "drivers/media/platform/samsung/s5p-jpeg/Kconfig" +source "drivers/media/platform/samsung/s5p-mfc/Kconfig" source "drivers/media/platform/sti/Kconfig" source "drivers/media/platform/stm32/Kconfig" source "drivers/media/platform/sunxi/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 86f81e81dadc..65bc673587b1 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -29,12 +29,12 @@ obj-y += qcom/venus/ obj-y += renesas/ obj-y += rockchip/rga/ obj-y += rockchip/rkisp1/ -obj-y += s5p-mfc/ obj-y += samsung/exynos-gsc/ obj-y += samsung/exynos4-is/ obj-y += samsung/s3c-camif/ obj-y += samsung/s5p-g2d/ obj-y += samsung/s5p-jpeg/ +obj-y += samsung/s5p-mfc/ obj-y += sti/bdisp/ obj-y += sti/c8sectpfe/ obj-y += sti/delta/ diff --git a/drivers/media/platform/s5p-mfc/Kconfig b/drivers/media/platform/s5p-mfc/Kconfig deleted file mode 100644 index 34b52b0de304..000000000000 --- a/drivers/media/platform/s5p-mfc/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_SAMSUNG_S5P_MFC - tristate "Samsung S5P MFC Video Codec" - depends on V4L_MEM2MEM_DRIVERS - depends on VIDEO_DEV && VIDEO_V4L2 - depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - help - MFC 5.1 and 6.x driver for V4L2 diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile deleted file mode 100644 index 0b324af2ab00..000000000000 --- a/drivers/media/platform/s5p-mfc/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc.o -s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o -s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o -s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_pm.o -s5p-mfc-y += s5p_mfc_opr.o s5p_mfc_opr_v5.o s5p_mfc_opr_v6.o -s5p-mfc-y += s5p_mfc_cmd.o s5p_mfc_cmd_v5.o s5p_mfc_cmd_v6.o diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/s5p-mfc/regs-mfc-v10.h deleted file mode 100644 index fadd9139b489..000000000000 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v10.h +++ /dev/null @@ -1,87 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * - * Copyright (c) 2017 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * Register definition file for Samsung MFC V10.x Interface (FIMV) driver - * - */ - -#ifndef _REGS_MFC_V10_H -#define _REGS_MFC_V10_H - -#include -#include "regs-mfc-v8.h" - -/* MFCv10 register definitions*/ -#define S5P_FIMV_MFC_CLOCK_OFF_V10 0x7120 -#define S5P_FIMV_MFC_STATE_V10 0x7124 -#define S5P_FIMV_D_STATIC_BUFFER_ADDR_V10 0xF570 -#define S5P_FIMV_D_STATIC_BUFFER_SIZE_V10 0xF574 -#define S5P_FIMV_E_NUM_T_LAYER_V10 0xFBAC -#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10 0xFBB0 -#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER1_V10 0xFBB4 -#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER2_V10 0xFBB8 -#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER3_V10 0xFBBC -#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER4_V10 0xFBC0 -#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER5_V10 0xFBC4 -#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER6_V10 0xFBC8 -#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10 0xFD18 -#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER1_V10 0xFD1C -#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER2_V10 0xFD20 -#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER3_V10 0xFD24 -#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER4_V10 0xFD28 -#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER5_V10 0xFD2C -#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER6_V10 0xFD30 -#define S5P_FIMV_E_HEVC_OPTIONS_V10 0xFDD4 -#define S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10 0xFDD8 -#define S5P_FIMV_E_HEVC_CHROMA_QP_OFFSET_V10 0xFDDC -#define S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10 0xFDE0 -#define S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10 0xFDE4 -#define S5P_FIMV_E_HEVC_NAL_CONTROL_V10 0xFDE8 - -/* MFCv10 Context buffer sizes */ -#define MFC_CTX_BUF_SIZE_V10 (30 * SZ_1K) -#define MFC_H264_DEC_CTX_BUF_SIZE_V10 (2 * SZ_1M) -#define MFC_OTHER_DEC_CTX_BUF_SIZE_V10 (20 * SZ_1K) -#define MFC_H264_ENC_CTX_BUF_SIZE_V10 (100 * SZ_1K) -#define MFC_HEVC_ENC_CTX_BUF_SIZE_V10 (30 * SZ_1K) -#define MFC_OTHER_ENC_CTX_BUF_SIZE_V10 (15 * SZ_1K) - -/* MFCv10 variant defines */ -#define MAX_FW_SIZE_V10 (SZ_1M) -#define MAX_CPB_SIZE_V10 (3 * SZ_1M) -#define MFC_VERSION_V10 0xA0 -#define MFC_NUM_PORTS_V10 1 - -/* MFCv10 codec defines*/ -#define S5P_FIMV_CODEC_HEVC_DEC 17 -#define S5P_FIMV_CODEC_VP9_DEC 18 -#define S5P_FIMV_CODEC_HEVC_ENC 26 - -/* Decoder buffer size for MFC v10 */ -#define DEC_VP9_STATIC_BUFFER_SIZE 20480 - -/* Encoder buffer size for MFC v10.0 */ -#define ENC_V100_BASE_SIZE(x, y) \ - (((x + 3) * (y + 3) * 8) \ - + ((y * 64) + 1280) * DIV_ROUND_UP(x, 8)) - -#define ENC_V100_H264_ME_SIZE(x, y) \ - (ENC_V100_BASE_SIZE(x, y) \ - + (DIV_ROUND_UP(x * y, 64) * 32)) - -#define ENC_V100_MPEG4_ME_SIZE(x, y) \ - (ENC_V100_BASE_SIZE(x, y) \ - + (DIV_ROUND_UP(x * y, 128) * 16)) - -#define ENC_V100_VP8_ME_SIZE(x, y) \ - ENC_V100_BASE_SIZE(x, y) - -#define ENC_V100_HEVC_ME_SIZE(x, y) \ - (((x + 3) * (y + 3) * 32) \ - + ((y * 128) + 1280) * DIV_ROUND_UP(x, 4)) - -#endif /*_REGS_MFC_V10_H*/ - diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h deleted file mode 100644 index fa49fe580e1a..000000000000 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h +++ /dev/null @@ -1,408 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Register definition file for Samsung MFC V6.x Interface (FIMV) driver - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef _REGS_FIMV_V6_H -#define _REGS_FIMV_V6_H - -#include -#include - -#define S5P_FIMV_REG_SIZE_V6 (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) -#define S5P_FIMV_REG_COUNT_V6 ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) - -/* Number of bits that the buffer address should be shifted for particular - * MFC buffers. */ -#define S5P_FIMV_MEM_OFFSET_V6 0 - -#define S5P_FIMV_START_ADDR_V6 0x0000 -#define S5P_FIMV_END_ADDR_V6 0xfd80 - -#define S5P_FIMV_REG_CLEAR_BEGIN_V6 0xf000 -#define S5P_FIMV_REG_CLEAR_COUNT_V6 1024 - -/* Codec Common Registers */ -#define S5P_FIMV_RISC_ON_V6 0x0000 -#define S5P_FIMV_RISC2HOST_INT_V6 0x003C -#define S5P_FIMV_HOST2RISC_INT_V6 0x0044 -#define S5P_FIMV_RISC_BASE_ADDRESS_V6 0x0054 - -#define S5P_FIMV_MFC_RESET_V6 0x1070 - -#define S5P_FIMV_HOST2RISC_CMD_V6 0x1100 -#define S5P_FIMV_H2R_CMD_EMPTY_V6 0 -#define S5P_FIMV_H2R_CMD_SYS_INIT_V6 1 -#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6 2 -#define S5P_FIMV_CH_SEQ_HEADER_V6 3 -#define S5P_FIMV_CH_INIT_BUFS_V6 4 -#define S5P_FIMV_CH_FRAME_START_V6 5 -#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6 6 -#define S5P_FIMV_H2R_CMD_SLEEP_V6 7 -#define S5P_FIMV_H2R_CMD_WAKEUP_V6 8 -#define S5P_FIMV_CH_LAST_FRAME_V6 9 -#define S5P_FIMV_H2R_CMD_FLUSH_V6 10 -/* RMVME: REALLOC used? */ -#define S5P_FIMV_CH_FRAME_START_REALLOC_V6 5 - -#define S5P_FIMV_RISC2HOST_CMD_V6 0x1104 -#define S5P_FIMV_R2H_CMD_EMPTY_V6 0 -#define S5P_FIMV_R2H_CMD_SYS_INIT_RET_V6 1 -#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET_V6 2 -#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET_V6 3 -#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET_V6 4 - -#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET_V6 6 -#define S5P_FIMV_R2H_CMD_SLEEP_RET_V6 7 -#define S5P_FIMV_R2H_CMD_WAKEUP_RET_V6 8 -#define S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET_V6 9 -#define S5P_FIMV_R2H_CMD_DPB_FLUSH_RET_V6 10 -#define S5P_FIMV_R2H_CMD_NAL_ABORT_RET_V6 11 -#define S5P_FIMV_R2H_CMD_FW_STATUS_RET_V6 12 -#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET_V6 13 -#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET_V6 14 -#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET_V6 15 -#define S5P_FIMV_R2H_CMD_ENC_BUFFER_FUL_RET_V6 16 -#define S5P_FIMV_R2H_CMD_ERR_RET_V6 32 - -#define S5P_FIMV_MFC_BUS_RESET_CTRL 0x7110 -#define S5P_FIMV_FW_VERSION_V6 0xf000 - -#define S5P_FIMV_INSTANCE_ID_V6 0xf008 -#define S5P_FIMV_CODEC_TYPE_V6 0xf00c -#define S5P_FIMV_CONTEXT_MEM_ADDR_V6 0xf014 -#define S5P_FIMV_CONTEXT_MEM_SIZE_V6 0xf018 -#define S5P_FIMV_PIXEL_FORMAT_V6 0xf020 - -#define S5P_FIMV_METADATA_ENABLE_V6 0xf024 -#define S5P_FIMV_DBG_BUFFER_ADDR_V6 0xf030 -#define S5P_FIMV_DBG_BUFFER_SIZE_V6 0xf034 -#define S5P_FIMV_RET_INSTANCE_ID_V6 0xf070 - -#define S5P_FIMV_ERROR_CODE_V6 0xf074 -#define S5P_FIMV_ERR_WARNINGS_START_V6 160 -#define S5P_FIMV_ERR_DEC_MASK_V6 0xffff -#define S5P_FIMV_ERR_DEC_SHIFT_V6 0 -#define S5P_FIMV_ERR_DSPL_MASK_V6 0xffff0000 -#define S5P_FIMV_ERR_DSPL_SHIFT_V6 16 - -#define S5P_FIMV_DBG_BUFFER_OUTPUT_SIZE_V6 0xf078 -#define S5P_FIMV_METADATA_STATUS_V6 0xf07C -#define S5P_FIMV_METADATA_ADDR_MB_INFO_V6 0xf080 -#define S5P_FIMV_METADATA_SIZE_MB_INFO_V6 0xf084 - -/* Decoder Registers */ -#define S5P_FIMV_D_CRC_CTRL_V6 0xf0b0 -#define S5P_FIMV_D_DEC_OPTIONS_V6 0xf0b4 -#define S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6 4 -#define S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6 3 -#define S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6 1 -#define S5P_FIMV_D_OPT_LF_CTRL_MASK_V6 0x3 -#define S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6 0 - -#define S5P_FIMV_D_DISPLAY_DELAY_V6 0xf0b8 - -#define S5P_FIMV_D_SET_FRAME_WIDTH_V6 0xf0bc -#define S5P_FIMV_D_SET_FRAME_HEIGHT_V6 0xf0c0 - -#define S5P_FIMV_D_SEI_ENABLE_V6 0xf0c4 - -/* Buffer setting registers */ -#define S5P_FIMV_D_MIN_NUM_DPB_V6 0xf0f0 -#define S5P_FIMV_D_MIN_LUMA_DPB_SIZE_V6 0xf0f4 -#define S5P_FIMV_D_MIN_CHROMA_DPB_SIZE_V6 0xf0f8 -#define S5P_FIMV_D_MVC_NUM_VIEWS_V6 0xf0fc -#define S5P_FIMV_D_MIN_NUM_MV_V6 0xf100 -#define S5P_FIMV_D_NUM_DPB_V6 0xf130 -#define S5P_FIMV_D_LUMA_DPB_SIZE_V6 0xf134 -#define S5P_FIMV_D_CHROMA_DPB_SIZE_V6 0xf138 -#define S5P_FIMV_D_MV_BUFFER_SIZE_V6 0xf13c - -#define S5P_FIMV_D_LUMA_DPB_V6 0xf140 -#define S5P_FIMV_D_CHROMA_DPB_V6 0xf240 -#define S5P_FIMV_D_MV_BUFFER_V6 0xf340 - -#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6 0xf440 -#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6 0xf444 -#define S5P_FIMV_D_METADATA_BUFFER_ADDR_V6 0xf448 -#define S5P_FIMV_D_METADATA_BUFFER_SIZE_V6 0xf44c -#define S5P_FIMV_D_NUM_MV_V6 0xf478 -#define S5P_FIMV_D_CPB_BUFFER_ADDR_V6 0xf4b0 -#define S5P_FIMV_D_CPB_BUFFER_SIZE_V6 0xf4b4 - -#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER_V6 0xf4b8 -#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6 0xf4bc -#define S5P_FIMV_D_CPB_BUFFER_OFFSET_V6 0xf4c0 -#define S5P_FIMV_D_SLICE_IF_ENABLE_V6 0xf4c4 -#define S5P_FIMV_D_PICTURE_TAG_V6 0xf4c8 -#define S5P_FIMV_D_STREAM_DATA_SIZE_V6 0xf4d0 -#define S5P_FIMV_D_INIT_BUFFER_OPTIONS_V6 0xf47c - -/* Display information register */ -#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6 0xf500 -#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6 0xf504 - -/* Display status */ -#define S5P_FIMV_D_DISPLAY_STATUS_V6 0xf508 - -#define S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6 0xf50c -#define S5P_FIMV_D_DISPLAY_CHROMA_ADDR_V6 0xf510 - -#define S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6 0xf514 - -#define S5P_FIMV_D_DISPLAY_CROP_INFO1_V6 0xf518 -#define S5P_FIMV_D_DISPLAY_CROP_INFO2_V6 0xf51c -#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE_V6 0xf520 -#define S5P_FIMV_D_DISPLAY_LUMA_CRC_TOP_V6 0xf524 -#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_TOP_V6 0xf528 -#define S5P_FIMV_D_DISPLAY_LUMA_CRC_BOT_V6 0xf52c -#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_BOT_V6 0xf530 -#define S5P_FIMV_D_DISPLAY_ASPECT_RATIO_V6 0xf534 -#define S5P_FIMV_D_DISPLAY_EXTENDED_AR_V6 0xf538 - -/* Decoded picture information register */ -#define S5P_FIMV_D_DECODED_FRAME_WIDTH_V6 0xf53c -#define S5P_FIMV_D_DECODED_FRAME_HEIGHT_V6 0xf540 -#define S5P_FIMV_D_DECODED_STATUS_V6 0xf544 -#define S5P_FIMV_DEC_CRC_GEN_MASK_V6 0x1 -#define S5P_FIMV_DEC_CRC_GEN_SHIFT_V6 6 - -#define S5P_FIMV_D_DECODED_LUMA_ADDR_V6 0xf548 -#define S5P_FIMV_D_DECODED_CHROMA_ADDR_V6 0xf54c - -#define S5P_FIMV_D_DECODED_FRAME_TYPE_V6 0xf550 -#define S5P_FIMV_DECODE_FRAME_MASK_V6 7 - -#define S5P_FIMV_D_DECODED_CROP_INFO1_V6 0xf554 -#define S5P_FIMV_D_DECODED_CROP_INFO2_V6 0xf558 -#define S5P_FIMV_D_DECODED_PICTURE_PROFILE_V6 0xf55c -#define S5P_FIMV_D_DECODED_NAL_SIZE_V6 0xf560 -#define S5P_FIMV_D_DECODED_LUMA_CRC_TOP_V6 0xf564 -#define S5P_FIMV_D_DECODED_CHROMA_CRC_TOP_V6 0xf568 -#define S5P_FIMV_D_DECODED_LUMA_CRC_BOT_V6 0xf56c -#define S5P_FIMV_D_DECODED_CHROMA_CRC_BOT_V6 0xf570 - -/* Returned value register for specific setting */ -#define S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6 0xf574 -#define S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6 0xf578 -#define S5P_FIMV_D_RET_PICTURE_TIME_TOP_V6 0xf57c -#define S5P_FIMV_D_RET_PICTURE_TIME_BOT_V6 0xf580 -#define S5P_FIMV_D_CHROMA_FORMAT_V6 0xf588 -#define S5P_FIMV_D_MPEG4_INFO_V6 0xf58c -#define S5P_FIMV_D_H264_INFO_V6 0xf590 - -#define S5P_FIMV_D_METADATA_ADDR_CONCEALED_MB_V6 0xf594 -#define S5P_FIMV_D_METADATA_SIZE_CONCEALED_MB_V6 0xf598 -#define S5P_FIMV_D_METADATA_ADDR_VC1_PARAM_V6 0xf59c -#define S5P_FIMV_D_METADATA_SIZE_VC1_PARAM_V6 0xf5a0 -#define S5P_FIMV_D_METADATA_ADDR_SEI_NAL_V6 0xf5a4 -#define S5P_FIMV_D_METADATA_SIZE_SEI_NAL_V6 0xf5a8 -#define S5P_FIMV_D_METADATA_ADDR_VUI_V6 0xf5ac -#define S5P_FIMV_D_METADATA_SIZE_VUI_V6 0xf5b0 - -#define S5P_FIMV_D_MVC_VIEW_ID_V6 0xf5b4 - -/* SEI related information */ -#define S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6 0xf5f0 -#define S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID_V6 0xf5f4 -#define S5P_FIMV_D_FRAME_PACK_SEI_INFO_V6 0xf5f8 -#define S5P_FIMV_D_FRAME_PACK_GRID_POS_V6 0xf5fc - -/* Encoder Registers */ -#define S5P_FIMV_E_FRAME_WIDTH_V6 0xf770 -#define S5P_FIMV_E_FRAME_HEIGHT_V6 0xf774 -#define S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6 0xf778 -#define S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6 0xf77c -#define S5P_FIMV_E_FRAME_CROP_OFFSET_V6 0xf780 -#define S5P_FIMV_E_ENC_OPTIONS_V6 0xf784 -#define S5P_FIMV_E_PICTURE_PROFILE_V6 0xf788 -#define S5P_FIMV_E_FIXED_PICTURE_QP_V6 0xf790 - -#define S5P_FIMV_E_RC_CONFIG_V6 0xf794 -#define S5P_FIMV_E_RC_QP_BOUND_V6 0xf798 -#define S5P_FIMV_E_RC_RPARAM_V6 0xf79c -#define S5P_FIMV_E_MB_RC_CONFIG_V6 0xf7a0 -#define S5P_FIMV_E_PADDING_CTRL_V6 0xf7a4 -#define S5P_FIMV_E_MV_HOR_RANGE_V6 0xf7ac -#define S5P_FIMV_E_MV_VER_RANGE_V6 0xf7b0 -#define S5P_FIMV_E_MV_RANGE_V6_MASK 0x3fff - -#define S5P_FIMV_E_VBV_BUFFER_SIZE_V6 0xf84c -#define S5P_FIMV_E_VBV_INIT_DELAY_V6 0xf850 -#define S5P_FIMV_E_NUM_DPB_V6 0xf890 -#define S5P_FIMV_E_LUMA_DPB_V6 0xf8c0 -#define S5P_FIMV_E_CHROMA_DPB_V6 0xf904 -#define S5P_FIMV_E_ME_BUFFER_V6 0xf948 - -#define S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6 0xf98c -#define S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6 0xf990 -#define S5P_FIMV_E_TMV_BUFFER0_V6 0xf994 -#define S5P_FIMV_E_TMV_BUFFER1_V6 0xf998 -#define S5P_FIMV_E_SOURCE_LUMA_ADDR_V6 0xf9f0 -#define S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6 0xf9f4 -#define S5P_FIMV_E_STREAM_BUFFER_ADDR_V6 0xf9f8 -#define S5P_FIMV_E_STREAM_BUFFER_SIZE_V6 0xf9fc -#define S5P_FIMV_E_ROI_BUFFER_ADDR_V6 0xfA00 - -#define S5P_FIMV_E_PARAM_CHANGE_V6 0xfa04 -#define S5P_FIMV_E_IR_SIZE_V6 0xfa08 -#define S5P_FIMV_E_GOP_CONFIG_V6 0xfa0c -#define S5P_FIMV_E_MSLICE_MODE_V6 0xfa10 -#define S5P_FIMV_E_MSLICE_SIZE_MB_V6 0xfa14 -#define S5P_FIMV_E_MSLICE_SIZE_BITS_V6 0xfa18 -#define S5P_FIMV_E_FRAME_INSERTION_V6 0xfa1c - -#define S5P_FIMV_E_RC_FRAME_RATE_V6 0xfa20 -#define S5P_FIMV_E_RC_BIT_RATE_V6 0xfa24 -#define S5P_FIMV_E_RC_QP_OFFSET_V6 0xfa28 -#define S5P_FIMV_E_RC_ROI_CTRL_V6 0xfa2c -#define S5P_FIMV_E_PICTURE_TAG_V6 0xfa30 -#define S5P_FIMV_E_BIT_COUNT_ENABLE_V6 0xfa34 -#define S5P_FIMV_E_MAX_BIT_COUNT_V6 0xfa38 -#define S5P_FIMV_E_MIN_BIT_COUNT_V6 0xfa3c - -#define S5P_FIMV_E_METADATA_BUFFER_ADDR_V6 0xfa40 -#define S5P_FIMV_E_METADATA_BUFFER_SIZE_V6 0xfa44 -#define S5P_FIMV_E_STREAM_SIZE_V6 0xfa80 -#define S5P_FIMV_E_SLICE_TYPE_V6 0xfa84 -#define S5P_FIMV_E_PICTURE_COUNT_V6 0xfa88 -#define S5P_FIMV_E_RET_PICTURE_TAG_V6 0xfa8c -#define S5P_FIMV_E_STREAM_BUFFER_WRITE_POINTER_V6 0xfa90 - -#define S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6 0xfa94 -#define S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6 0xfa98 -#define S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6 0xfa9c -#define S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6 0xfaa0 -#define S5P_FIMV_E_METADATA_ADDR_ENC_SLICE_V6 0xfaa4 -#define S5P_FIMV_E_METADATA_SIZE_ENC_SLICE_V6 0xfaa8 - -#define S5P_FIMV_E_MPEG4_OPTIONS_V6 0xfb10 -#define S5P_FIMV_E_MPEG4_HEC_PERIOD_V6 0xfb14 -#define S5P_FIMV_E_ASPECT_RATIO_V6 0xfb50 -#define S5P_FIMV_E_EXTENDED_SAR_V6 0xfb54 - -#define S5P_FIMV_E_H264_OPTIONS_V6 0xfb58 -#define S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6 0xfb5c -#define S5P_FIMV_E_H264_LF_BETA_OFFSET_V6 0xfb60 -#define S5P_FIMV_E_H264_I_PERIOD_V6 0xfb64 - -#define S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6 0xfb68 -#define S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6 0xfb6c -#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6 0xfb70 -#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6 0xfb74 -#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 0xfb78 -#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_1_V6 0xfb7c -#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_2_V6 0xfb80 -#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_3_V6 0xfb84 - -#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 0xfb88 -#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_1_V6 0xfb8c -#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_2_V6 0xfb90 -#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_3_V6 0xfb94 -#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_4_V6 0xfb98 -#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_5_V6 0xfb9c -#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_6_V6 0xfba0 -#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_7_V6 0xfba4 - -#define S5P_FIMV_E_H264_CHROMA_QP_OFFSET_V6 0xfba8 -#define S5P_FIMV_E_H264_NUM_T_LAYER_V6 0xfbac - -#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 0xfbb0 -#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER1_V6 0xfbb4 -#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER2_V6 0xfbb8 -#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER3_V6 0xfbbc -#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER4_V6 0xfbc0 -#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER5_V6 0xfbc4 -#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER6_V6 0xfbc8 - -#define S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6 0xfc4c -#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE_V6 0 -#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TOP_BOTTOM_V6 1 -#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TEMPORAL_V6 2 - -#define S5P_FIMV_E_MVC_FRAME_QP_VIEW1_V6 0xfd40 -#define S5P_FIMV_E_MVC_RC_FRAME_RATE_VIEW1_V6 0xfd44 -#define S5P_FIMV_E_MVC_RC_BIT_RATE_VIEW1_V6 0xfd48 -#define S5P_FIMV_E_MVC_RC_QBOUND_VIEW1_V6 0xfd4c -#define S5P_FIMV_E_MVC_RC_RPARA_VIEW1_V6 0xfd50 -#define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON_V6 0xfd80 - -/* Codec numbers */ -#define S5P_FIMV_CODEC_NONE_V6 -1 - - -#define S5P_FIMV_CODEC_H264_DEC_V6 0 -#define S5P_FIMV_CODEC_H264_MVC_DEC_V6 1 - -#define S5P_FIMV_CODEC_MPEG4_DEC_V6 3 -#define S5P_FIMV_CODEC_FIMV1_DEC_V6 4 -#define S5P_FIMV_CODEC_FIMV2_DEC_V6 5 -#define S5P_FIMV_CODEC_FIMV3_DEC_V6 6 -#define S5P_FIMV_CODEC_FIMV4_DEC_V6 7 -#define S5P_FIMV_CODEC_H263_DEC_V6 8 -#define S5P_FIMV_CODEC_VC1RCV_DEC_V6 9 -#define S5P_FIMV_CODEC_VC1_DEC_V6 10 -/* FIXME: Add 11~12 */ -#define S5P_FIMV_CODEC_MPEG2_DEC_V6 13 -#define S5P_FIMV_CODEC_VP8_DEC_V6 14 -/* FIXME: Add 15~16 */ -#define S5P_FIMV_CODEC_H264_ENC_V6 20 -#define S5P_FIMV_CODEC_H264_MVC_ENC_V6 21 - -#define S5P_FIMV_CODEC_MPEG4_ENC_V6 23 -#define S5P_FIMV_CODEC_H263_ENC_V6 24 - -#define S5P_FIMV_NV12M_HALIGN_V6 16 -#define S5P_FIMV_NV12MT_HALIGN_V6 16 -#define S5P_FIMV_NV12MT_VALIGN_V6 16 - -#define S5P_FIMV_TMV_BUFFER_ALIGN_V6 16 -#define S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6 256 -#define S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6 256 -#define S5P_FIMV_ME_BUFFER_ALIGN_V6 256 -#define S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6 256 - -#define S5P_FIMV_LUMA_MB_TO_PIXEL_V6 256 -#define S5P_FIMV_CHROMA_MB_TO_PIXEL_V6 128 -#define S5P_FIMV_NUM_TMV_BUFFERS_V6 2 - -#define S5P_FIMV_MAX_FRAME_SIZE_V6 (2 * SZ_1M) -#define S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6 16 -#define S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6 16 - -/* Buffer size requirements defined by hardware */ -#define S5P_FIMV_TMV_BUFFER_SIZE_V6(w, h) (((w) + 1) * ((h) + 3) * 8) -#define S5P_FIMV_ME_BUFFER_SIZE_V6(imw, imh, mbw, mbh) \ - (((((imw + 127) / 64) * 16) * DIV_ROUND_UP(imh, 64) * 256) + \ - (DIV_ROUND_UP((mbw) * (mbh), 32) * 16)) -#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6(w, h) (((w) * 192) + 64) -#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) \ - ((w) * 144 + 8192 * (h) + 49216 + 1048576) -#define S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(w, h) \ - (2096 * ((w) + (h) + 1)) -#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) \ - S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) -#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6(w, h) \ - ((w) * 32 + (h) * 128 + (((w) + 1) / 2) * 64 + 2112) -#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6(w, h) \ - (((w) * 64) + (((w) + 1) * 16) + (4096 * 16)) -#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6(w, h) \ - (((w) * 16) + (((w) + 1) * 16)) - -/* MFC Context buffer sizes */ -#define MFC_CTX_BUF_SIZE_V6 (28 * SZ_1K) /* 28KB */ -#define MFC_H264_DEC_CTX_BUF_SIZE_V6 (2 * SZ_1M) /* 2MB */ -#define MFC_OTHER_DEC_CTX_BUF_SIZE_V6 (20 * SZ_1K) /* 20KB */ -#define MFC_H264_ENC_CTX_BUF_SIZE_V6 (100 * SZ_1K) /* 100KB */ -#define MFC_OTHER_ENC_CTX_BUF_SIZE_V6 (12 * SZ_1K) /* 12KB */ - -/* MFCv6 variant defines */ -#define MAX_FW_SIZE_V6 (SZ_512K) /* 512KB */ -#define MAX_CPB_SIZE_V6 (3 * SZ_1M) /* 3MB */ -#define MFC_VERSION_V6 0x61 -#define MFC_NUM_PORTS_V6 1 - -#endif /* _REGS_FIMV_V6_H */ diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h deleted file mode 100644 index 4a7adfdaa359..000000000000 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Register definition file for Samsung MFC V7.x Interface (FIMV) driver - * - * Copyright (c) 2013 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef _REGS_MFC_V7_H -#define _REGS_MFC_V7_H - -#include "regs-mfc-v6.h" - -/* Additional features of v7 */ -#define S5P_FIMV_CODEC_VP8_ENC_V7 25 - -/* Additional registers for v7 */ -#define S5P_FIMV_E_SOURCE_FIRST_ADDR_V7 0xf9e0 -#define S5P_FIMV_E_SOURCE_SECOND_ADDR_V7 0xf9e4 -#define S5P_FIMV_E_SOURCE_THIRD_ADDR_V7 0xf9e8 -#define S5P_FIMV_E_SOURCE_FIRST_STRIDE_V7 0xf9ec -#define S5P_FIMV_E_SOURCE_SECOND_STRIDE_V7 0xf9f0 -#define S5P_FIMV_E_SOURCE_THIRD_STRIDE_V7 0xf9f4 - -#define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7 0xfa70 -#define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7 0xfa74 - -#define S5P_FIMV_E_VP8_OPTIONS_V7 0xfdb0 -#define S5P_FIMV_E_VP8_FILTER_OPTIONS_V7 0xfdb4 -#define S5P_FIMV_E_VP8_GOLDEN_FRAME_OPTION_V7 0xfdb8 -#define S5P_FIMV_E_VP8_NUM_T_LAYER_V7 0xfdc4 - -/* MFCv7 variant defines */ -#define MAX_FW_SIZE_V7 (SZ_512K) /* 512KB */ -#define MAX_CPB_SIZE_V7 (3 * SZ_1M) /* 3MB */ -#define MFC_VERSION_V7 0x72 -#define MFC_NUM_PORTS_V7 1 - -#define MFC_LUMA_PAD_BYTES_V7 256 -#define MFC_CHROMA_PAD_BYTES_V7 128 - -/* MFCv7 Context buffer sizes */ -#define MFC_CTX_BUF_SIZE_V7 (30 * SZ_1K) /* 30KB */ -#define MFC_H264_DEC_CTX_BUF_SIZE_V7 (2 * SZ_1M) /* 2MB */ -#define MFC_OTHER_DEC_CTX_BUF_SIZE_V7 (20 * SZ_1K) /* 20KB */ -#define MFC_H264_ENC_CTX_BUF_SIZE_V7 (100 * SZ_1K) /* 100KB */ -#define MFC_OTHER_ENC_CTX_BUF_SIZE_V7 (10 * SZ_1K) /* 10KB */ - -/* Buffer size defines */ -#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7(w, h) \ - (SZ_1M + ((w) * 144) + (8192 * (h)) + 49216) - -#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V7(w, h) \ - (((w) * 48) + 8192 + ((((w) + 1) / 2) * 128) + 144 + \ - ((((((w) * 16) * ((h) * 16)) * 3) / 2) * 4)) - -#endif /*_REGS_MFC_V7_H*/ diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h deleted file mode 100644 index 162e3c7e920f..000000000000 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ /dev/null @@ -1,123 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Register definition file for Samsung MFC V8.x Interface (FIMV) driver - * - * Copyright (c) 2014 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef _REGS_MFC_V8_H -#define _REGS_MFC_V8_H - -#include -#include "regs-mfc-v7.h" - -/* Additional registers for v8 */ -#define S5P_FIMV_D_MVC_NUM_VIEWS_V8 0xf104 -#define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8 0xf108 -#define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8 0xf144 -#define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8 0xf148 -#define S5P_FIMV_D_MV_BUFFER_SIZE_V8 0xf150 - -#define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8 0xf138 -#define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8 0xf13c - -#define S5P_FIMV_D_FIRST_PLANE_DPB_V8 0xf160 -#define S5P_FIMV_D_SECOND_PLANE_DPB_V8 0xf260 -#define S5P_FIMV_D_MV_BUFFER_V8 0xf460 - -#define S5P_FIMV_D_NUM_MV_V8 0xf134 -#define S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8 0xf154 - -#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8 0xf560 -#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8 0xf564 - -#define S5P_FIMV_D_CPB_BUFFER_ADDR_V8 0xf5b0 -#define S5P_FIMV_D_CPB_BUFFER_SIZE_V8 0xf5b4 -#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8 0xf5bc -#define S5P_FIMV_D_CPB_BUFFER_OFFSET_V8 0xf5c0 -#define S5P_FIMV_D_SLICE_IF_ENABLE_V8 0xf5c4 -#define S5P_FIMV_D_STREAM_DATA_SIZE_V8 0xf5d0 - -/* Display information register */ -#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V8 0xf600 -#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V8 0xf604 - -/* Display status */ -#define S5P_FIMV_D_DISPLAY_STATUS_V8 0xf608 - -#define S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR_V8 0xf60c -#define S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR_V8 0xf610 - -#define S5P_FIMV_D_DISPLAY_FRAME_TYPE_V8 0xf618 -#define S5P_FIMV_D_DISPLAY_CROP_INFO1_V8 0xf61c -#define S5P_FIMV_D_DISPLAY_CROP_INFO2_V8 0xf620 -#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE_V8 0xf624 - -/* Decoded picture information register */ -#define S5P_FIMV_D_DECODED_STATUS_V8 0xf644 -#define S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR_V8 0xf648 -#define S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR_V8 0xf64c -#define S5P_FIMV_D_DECODED_THIRD_PLANE_ADDR_V8 0xf650 -#define S5P_FIMV_D_DECODED_FRAME_TYPE_V8 0xf654 -#define S5P_FIMV_D_DECODED_NAL_SIZE_V8 0xf664 - -/* Returned value register for specific setting */ -#define S5P_FIMV_D_RET_PICTURE_TAG_TOP_V8 0xf674 -#define S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8 0xf678 -#define S5P_FIMV_D_MVC_VIEW_ID_V8 0xf6d8 - -/* SEI related information */ -#define S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V8 0xf6dc - -/* Encoder Registers */ -#define S5P_FIMV_E_FIXED_PICTURE_QP_V8 0xf794 -#define S5P_FIMV_E_RC_CONFIG_V8 0xf798 -#define S5P_FIMV_E_RC_QP_BOUND_V8 0xf79c -#define S5P_FIMV_E_RC_RPARAM_V8 0xf7a4 -#define S5P_FIMV_E_MB_RC_CONFIG_V8 0xf7a8 -#define S5P_FIMV_E_PADDING_CTRL_V8 0xf7ac -#define S5P_FIMV_E_MV_HOR_RANGE_V8 0xf7b4 -#define S5P_FIMV_E_MV_VER_RANGE_V8 0xf7b8 - -#define S5P_FIMV_E_VBV_BUFFER_SIZE_V8 0xf78c -#define S5P_FIMV_E_VBV_INIT_DELAY_V8 0xf790 -#define S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8 0xf894 - -#define S5P_FIMV_E_ASPECT_RATIO_V8 0xfb4c -#define S5P_FIMV_E_EXTENDED_SAR_V8 0xfb50 -#define S5P_FIMV_E_H264_OPTIONS_V8 0xfb54 - -/* MFCv8 Context buffer sizes */ -#define MFC_CTX_BUF_SIZE_V8 (36 * SZ_1K) /* 36KB */ -#define MFC_H264_DEC_CTX_BUF_SIZE_V8 (2 * SZ_1M) /* 2MB */ -#define MFC_OTHER_DEC_CTX_BUF_SIZE_V8 (20 * SZ_1K) /* 20KB */ -#define MFC_H264_ENC_CTX_BUF_SIZE_V8 (100 * SZ_1K) /* 100KB */ -#define MFC_OTHER_ENC_CTX_BUF_SIZE_V8 (10 * SZ_1K) /* 10KB */ - -/* Buffer size defines */ -#define S5P_FIMV_TMV_BUFFER_SIZE_V8(w, h) (((w) + 1) * ((h) + 1) * 8) - -#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8(w, h) (((w) * 704) + 2176) -#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8(w, h) \ - (((w) * 576 + (h) * 128) + 4128) - -#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8(w, h) \ - (((w) * 592) + 2336) -#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8(w, h) \ - (((w) * 576) + 10512 + \ - ((((((w) * 16) * ((h) * 16)) * 3) / 2) * 4)) -#define S5P_FIMV_ME_BUFFER_SIZE_V8(imw, imh, mbw, mbh) \ - ((DIV_ROUND_UP((mbw * 16), 64) * DIV_ROUND_UP((mbh * 16), 64) * 256) \ - + (DIV_ROUND_UP((mbw) * (mbh), 32) * 16)) - -/* BUffer alignment defines */ -#define S5P_FIMV_D_ALIGN_PLANE_SIZE_V8 64 - -/* MFCv8 variant defines */ -#define MAX_FW_SIZE_V8 (SZ_512K) /* 512KB */ -#define MAX_CPB_SIZE_V8 (3 * SZ_1M) /* 3MB */ -#define MFC_VERSION_V8 0x80 -#define MFC_NUM_PORTS_V8 1 - -#endif /*_REGS_MFC_V8_H*/ diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h deleted file mode 100644 index 9171e8181c18..000000000000 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ /dev/null @@ -1,459 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Register definition file for Samsung MFC V5.1 Interface (FIMV) driver - * - * Kamil Debski, Copyright (c) 2010 Samsung Electronics - * http://www.samsung.com/ -*/ - -#ifndef _REGS_FIMV_H -#define _REGS_FIMV_H - -#include -#include - -#define S5P_FIMV_REG_SIZE (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) -#define S5P_FIMV_REG_COUNT ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) - -/* Number of bits that the buffer address should be shifted for particular - * MFC buffers. */ -#define S5P_FIMV_START_ADDR 0x0000 -#define S5P_FIMV_END_ADDR 0xe008 - -#define S5P_FIMV_SW_RESET 0x0000 -#define S5P_FIMV_RISC_HOST_INT 0x0008 - -/* Command from HOST to RISC */ -#define S5P_FIMV_HOST2RISC_CMD 0x0030 -#define S5P_FIMV_HOST2RISC_ARG1 0x0034 -#define S5P_FIMV_HOST2RISC_ARG2 0x0038 -#define S5P_FIMV_HOST2RISC_ARG3 0x003c -#define S5P_FIMV_HOST2RISC_ARG4 0x0040 - -/* Command from RISC to HOST */ -#define S5P_FIMV_RISC2HOST_CMD 0x0044 -#define S5P_FIMV_RISC2HOST_CMD_MASK 0x1FFFF -#define S5P_FIMV_RISC2HOST_ARG1 0x0048 -#define S5P_FIMV_RISC2HOST_ARG2 0x004c -#define S5P_FIMV_RISC2HOST_ARG3 0x0050 -#define S5P_FIMV_RISC2HOST_ARG4 0x0054 - -#define S5P_FIMV_FW_VERSION 0x0058 -#define S5P_FIMV_SYS_MEM_SZ 0x005c -#define S5P_FIMV_FW_STATUS 0x0080 - -/* Memory controller register */ -#define S5P_FIMV_MC_DRAMBASE_ADR_A 0x0508 -#define S5P_FIMV_MC_DRAMBASE_ADR_B 0x050c -#define S5P_FIMV_MC_STATUS 0x0510 - -/* Common register */ -#define S5P_FIMV_COMMON_BASE_A 0x0600 -#define S5P_FIMV_COMMON_BASE_B 0x0700 - -/* Decoder */ -#define S5P_FIMV_DEC_CHROMA_ADR (S5P_FIMV_COMMON_BASE_A) -#define S5P_FIMV_DEC_LUMA_ADR (S5P_FIMV_COMMON_BASE_B) - -/* H.264 decoding */ -#define S5P_FIMV_H264_VERT_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) - /* vertical neighbor motion vector */ -#define S5P_FIMV_H264_NB_IP_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) - /* neighbor pixels for intra pred */ -#define S5P_FIMV_H264_MV_ADR (S5P_FIMV_COMMON_BASE_B + 0x80) - /* H264 motion vector */ - -/* MPEG4 decoding */ -#define S5P_FIMV_MPEG4_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) - /* neighbor AC/DC coeff. */ -#define S5P_FIMV_MPEG4_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) - /* upper neighbor motion vector */ -#define S5P_FIMV_MPEG4_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) - /* subseq. anchor motion vector */ -#define S5P_FIMV_MPEG4_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) - /* overlap transform line */ -#define S5P_FIMV_MPEG4_SP_ADR (S5P_FIMV_COMMON_BASE_A + 0xa8) - /* syntax parser */ - -/* H.263 decoding */ -#define S5P_FIMV_H263_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) -#define S5P_FIMV_H263_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) -#define S5P_FIMV_H263_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) -#define S5P_FIMV_H263_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) - -/* VC-1 decoding */ -#define S5P_FIMV_VC1_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) -#define S5P_FIMV_VC1_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) -#define S5P_FIMV_VC1_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) -#define S5P_FIMV_VC1_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) -#define S5P_FIMV_VC1_BITPLANE3_ADR (S5P_FIMV_COMMON_BASE_A + 0x9c) - /* bitplane3 */ -#define S5P_FIMV_VC1_BITPLANE2_ADR (S5P_FIMV_COMMON_BASE_A + 0xa0) - /* bitplane2 */ -#define S5P_FIMV_VC1_BITPLANE1_ADR (S5P_FIMV_COMMON_BASE_A + 0xa4) - /* bitplane1 */ - -/* Encoder */ -#define S5P_FIMV_ENC_REF0_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x1c) -#define S5P_FIMV_ENC_REF1_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x20) - /* reconstructed luma */ -#define S5P_FIMV_ENC_REF0_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B) -#define S5P_FIMV_ENC_REF1_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x04) - /* reconstructed chroma */ -#define S5P_FIMV_ENC_REF2_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x10) -#define S5P_FIMV_ENC_REF2_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x08) -#define S5P_FIMV_ENC_REF3_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x14) -#define S5P_FIMV_ENC_REF3_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x0c) - -/* H.264 encoding */ -#define S5P_FIMV_H264_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) - /* upper motion vector */ -#define S5P_FIMV_H264_NBOR_INFO_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) - /* entropy engine's neighbor info. */ -#define S5P_FIMV_H264_UP_INTRA_MD_ADR (S5P_FIMV_COMMON_BASE_A + 0x08) - /* upper intra MD */ -#define S5P_FIMV_H264_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) - /* direct cozero flag */ -#define S5P_FIMV_H264_UP_INTRA_PRED_ADR (S5P_FIMV_COMMON_BASE_B + 0x40) - /* upper intra PRED */ - -/* H.263 encoding */ -#define S5P_FIMV_H263_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) - /* upper motion vector */ -#define S5P_FIMV_H263_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) - /* upper Q coeff. */ - -/* MPEG4 encoding */ -#define S5P_FIMV_MPEG4_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) - /* upper motion vector */ -#define S5P_FIMV_MPEG4_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) - /* upper Q coeff. */ -#define S5P_FIMV_MPEG4_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) - /* direct cozero flag */ - -#define S5P_FIMV_ENC_REF_B_LUMA_ADR 0x062c /* ref B Luma addr */ -#define S5P_FIMV_ENC_REF_B_CHROMA_ADR 0x0630 /* ref B Chroma addr */ - -#define S5P_FIMV_ENC_CUR_LUMA_ADR 0x0718 /* current Luma addr */ -#define S5P_FIMV_ENC_CUR_CHROMA_ADR 0x071C /* current Chroma addr */ - -/* Codec common register */ -#define S5P_FIMV_ENC_HSIZE_PX 0x0818 /* frame width at encoder */ -#define S5P_FIMV_ENC_VSIZE_PX 0x081c /* frame height at encoder */ -#define S5P_FIMV_ENC_PROFILE 0x0830 /* profile register */ -#define S5P_FIMV_ENC_PROFILE_H264_MAIN 0 -#define S5P_FIMV_ENC_PROFILE_H264_HIGH 1 -#define S5P_FIMV_ENC_PROFILE_H264_BASELINE 2 -#define S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE 3 -#define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0 -#define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1 -#define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */ -#define S5P_FIMV_ENC_LF_CTRL 0x0848 /* loop filter control */ -#define S5P_FIMV_ENC_ALPHA_OFF 0x084c /* loop filter alpha offset */ -#define S5P_FIMV_ENC_BETA_OFF 0x0850 /* loop filter beta offset */ -#define S5P_FIMV_MR_BUSIF_CTRL 0x0854 /* hidden, bus interface ctrl */ -#define S5P_FIMV_ENC_PXL_CACHE_CTRL 0x0a00 /* pixel cache control */ - -/* Channel & stream interface register */ -#define S5P_FIMV_SI_RTN_CHID 0x2000 /* Return CH inst ID register */ -#define S5P_FIMV_SI_CH0_INST_ID 0x2040 /* codec instance ID */ -#define S5P_FIMV_SI_CH1_INST_ID 0x2080 /* codec instance ID */ -/* Decoder */ -#define S5P_FIMV_SI_VRESOL 0x2004 /* vertical res of decoder */ -#define S5P_FIMV_SI_HRESOL 0x2008 /* horizontal res of decoder */ -#define S5P_FIMV_SI_BUF_NUMBER 0x200c /* number of frames in the - decoded pic */ -#define S5P_FIMV_SI_DISPLAY_Y_ADR 0x2010 /* luma addr of displayed pic */ -#define S5P_FIMV_SI_DISPLAY_C_ADR 0x2014 /* chroma addrof displayed pic */ - -#define S5P_FIMV_SI_CONSUMED_BYTES 0x2018 /* Consumed number of bytes to - decode a frame */ -#define S5P_FIMV_SI_DISPLAY_STATUS 0x201c /* status of decoded picture */ - -#define S5P_FIMV_SI_DECODE_Y_ADR 0x2024 /* luma addr of decoded pic */ -#define S5P_FIMV_SI_DECODE_C_ADR 0x2028 /* chroma addrof decoded pic */ -#define S5P_FIMV_SI_DECODE_STATUS 0x202c /* status of decoded picture */ - -#define S5P_FIMV_SI_CH0_SB_ST_ADR 0x2044 /* start addr of stream buf */ -#define S5P_FIMV_SI_CH0_SB_FRM_SIZE 0x2048 /* size of stream buf */ -#define S5P_FIMV_SI_CH0_DESC_ADR 0x204c /* addr of descriptor buf */ -#define S5P_FIMV_SI_CH0_CPB_SIZE 0x2058 /* max size of coded pic. buf */ -#define S5P_FIMV_SI_CH0_DESC_SIZE 0x205c /* max size of descriptor buf */ - -#define S5P_FIMV_SI_CH1_SB_ST_ADR 0x2084 /* start addr of stream buf */ -#define S5P_FIMV_SI_CH1_SB_FRM_SIZE 0x2088 /* size of stream buf */ -#define S5P_FIMV_SI_CH1_DESC_ADR 0x208c /* addr of descriptor buf */ -#define S5P_FIMV_SI_CH1_CPB_SIZE 0x2098 /* max size of coded pic. buf */ -#define S5P_FIMV_SI_CH1_DESC_SIZE 0x209c /* max size of descriptor buf */ - -#define S5P_FIMV_CRC_LUMA0 0x2030 /* luma crc data per frame - (top field) */ -#define S5P_FIMV_CRC_CHROMA0 0x2034 /* chroma crc data per frame - (top field) */ -#define S5P_FIMV_CRC_LUMA1 0x2038 /* luma crc data per bottom - field */ -#define S5P_FIMV_CRC_CHROMA1 0x203c /* chroma crc data per bottom - field */ - -/* Display status */ -#define S5P_FIMV_DEC_STATUS_DECODING_ONLY 0 -#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY 1 -#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY 2 -#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY 3 -#define S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK 7 -#define S5P_FIMV_DEC_STATUS_PROGRESSIVE (0<<3) -#define S5P_FIMV_DEC_STATUS_INTERLACE (1<<3) -#define S5P_FIMV_DEC_STATUS_INTERLACE_MASK (1<<3) -#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_TWO (0<<4) -#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_FOUR (1<<4) -#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_MASK (1<<4) -#define S5P_FIMV_DEC_STATUS_CRC_GENERATED (1<<5) -#define S5P_FIMV_DEC_STATUS_CRC_NOT_GENERATED (0<<5) -#define S5P_FIMV_DEC_STATUS_CRC_MASK (1<<5) - -#define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) -#define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) -#define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) -#define S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT 4 - -/* Decode frame address */ -#define S5P_FIMV_DECODE_Y_ADR 0x2024 -#define S5P_FIMV_DECODE_C_ADR 0x2028 - -/* Decoded frame tpe */ -#define S5P_FIMV_DECODE_FRAME_TYPE 0x2020 -#define S5P_FIMV_DECODE_FRAME_MASK 7 - -#define S5P_FIMV_DECODE_FRAME_SKIPPED 0 -#define S5P_FIMV_DECODE_FRAME_I_FRAME 1 -#define S5P_FIMV_DECODE_FRAME_P_FRAME 2 -#define S5P_FIMV_DECODE_FRAME_B_FRAME 3 -#define S5P_FIMV_DECODE_FRAME_OTHER_FRAME 4 - -/* Sizes of buffers required for decoding */ -#define S5P_FIMV_DEC_NB_IP_SIZE (32 * 1024) -#define S5P_FIMV_DEC_VERT_NB_MV_SIZE (16 * 1024) -#define S5P_FIMV_DEC_NB_DCAC_SIZE (16 * 1024) -#define S5P_FIMV_DEC_UPNB_MV_SIZE (68 * 1024) -#define S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE (136 * 1024) -#define S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE (32 * 1024) -#define S5P_FIMV_DEC_VC1_BITPLANE_SIZE (2 * 1024) -#define S5P_FIMV_DEC_STX_PARSER_SIZE (68 * 1024) - -#define S5P_FIMV_DEC_BUF_ALIGN (8 * 1024) -#define S5P_FIMV_ENC_BUF_ALIGN (8 * 1024) -#define S5P_FIMV_NV12M_HALIGN 16 -#define S5P_FIMV_NV12M_LVALIGN 16 -#define S5P_FIMV_NV12M_CVALIGN 8 -#define S5P_FIMV_NV12MT_HALIGN 128 -#define S5P_FIMV_NV12MT_VALIGN 32 -#define S5P_FIMV_NV12M_SALIGN 2048 -#define S5P_FIMV_NV12MT_SALIGN 8192 - -/* Sizes of buffers required for encoding */ -#define S5P_FIMV_ENC_UPMV_SIZE 0x10000 -#define S5P_FIMV_ENC_COLFLG_SIZE 0x10000 -#define S5P_FIMV_ENC_INTRAMD_SIZE 0x10000 -#define S5P_FIMV_ENC_INTRAPRED_SIZE 0x4000 -#define S5P_FIMV_ENC_NBORINFO_SIZE 0x10000 -#define S5P_FIMV_ENC_ACDCCOEF_SIZE 0x10000 - -/* Encoder */ -#define S5P_FIMV_ENC_SI_STRM_SIZE 0x2004 /* stream size */ -#define S5P_FIMV_ENC_SI_PIC_CNT 0x2008 /* picture count */ -#define S5P_FIMV_ENC_SI_WRITE_PTR 0x200c /* write pointer */ -#define S5P_FIMV_ENC_SI_SLICE_TYPE 0x2010 /* slice type(I/P/B/IDR) */ -#define S5P_FIMV_ENC_SI_SLICE_TYPE_NON_CODED 0 -#define S5P_FIMV_ENC_SI_SLICE_TYPE_I 1 -#define S5P_FIMV_ENC_SI_SLICE_TYPE_P 2 -#define S5P_FIMV_ENC_SI_SLICE_TYPE_B 3 -#define S5P_FIMV_ENC_SI_SLICE_TYPE_SKIPPED 4 -#define S5P_FIMV_ENC_SI_SLICE_TYPE_OTHERS 5 -#define S5P_FIMV_ENCODED_Y_ADDR 0x2014 /* the addr of the encoded - luma pic */ -#define S5P_FIMV_ENCODED_C_ADDR 0x2018 /* the addr of the encoded - chroma pic */ - -#define S5P_FIMV_ENC_SI_CH0_SB_ADR 0x2044 /* addr of stream buf */ -#define S5P_FIMV_ENC_SI_CH0_SB_SIZE 0x204c /* size of stream buf */ -#define S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR 0x2050 /* current Luma addr */ -#define S5P_FIMV_ENC_SI_CH0_CUR_C_ADR 0x2054 /* current Chroma addr */ -#define S5P_FIMV_ENC_SI_CH0_FRAME_INS 0x2058 /* frame insertion */ - -#define S5P_FIMV_ENC_SI_CH1_SB_ADR 0x2084 /* addr of stream buf */ -#define S5P_FIMV_ENC_SI_CH1_SB_SIZE 0x208c /* size of stream buf */ -#define S5P_FIMV_ENC_SI_CH1_CUR_Y_ADR 0x2090 /* current Luma addr */ -#define S5P_FIMV_ENC_SI_CH1_CUR_C_ADR 0x2094 /* current Chroma addr */ -#define S5P_FIMV_ENC_SI_CH1_FRAME_INS 0x2098 /* frame insertion */ - -#define S5P_FIMV_ENC_PIC_TYPE_CTRL 0xc504 /* pic type level control */ -#define S5P_FIMV_ENC_B_RECON_WRITE_ON 0xc508 /* B frame recon write ctrl */ -#define S5P_FIMV_ENC_MSLICE_CTRL 0xc50c /* multi slice control */ -#define S5P_FIMV_ENC_MSLICE_MB 0xc510 /* MB number in the one slice */ -#define S5P_FIMV_ENC_MSLICE_BIT 0xc514 /* bit count for one slice */ -#define S5P_FIMV_ENC_CIR_CTRL 0xc518 /* number of intra refresh MB */ -#define S5P_FIMV_ENC_MAP_FOR_CUR 0xc51c /* linear or tiled mode */ -#define S5P_FIMV_ENC_PADDING_CTRL 0xc520 /* padding control */ - -#define S5P_FIMV_ENC_RC_CONFIG 0xc5a0 /* RC config */ -#define S5P_FIMV_ENC_RC_BIT_RATE 0xc5a8 /* bit rate */ -#define S5P_FIMV_ENC_RC_QBOUND 0xc5ac /* max/min QP */ -#define S5P_FIMV_ENC_RC_RPARA 0xc5b0 /* rate control reaction coeff */ -#define S5P_FIMV_ENC_RC_MB_CTRL 0xc5b4 /* MB adaptive scaling */ - -/* Encoder for H264 only */ -#define S5P_FIMV_ENC_H264_ENTROPY_MODE 0xd004 /* CAVLC or CABAC */ -#define S5P_FIMV_ENC_H264_ALPHA_OFF 0xd008 /* loop filter alpha offset */ -#define S5P_FIMV_ENC_H264_BETA_OFF 0xd00c /* loop filter beta offset */ -#define S5P_FIMV_ENC_H264_NUM_OF_REF 0xd010 /* number of reference for P/B */ -#define S5P_FIMV_ENC_H264_TRANS_FLAG 0xd034 /* 8x8 transform flag in PPS & - high profile */ - -#define S5P_FIMV_ENC_RC_FRAME_RATE 0xd0d0 /* frame rate */ - -/* Encoder for MPEG4 only */ -#define S5P_FIMV_ENC_MPEG4_QUART_PXL 0xe008 /* qpel interpolation ctrl */ - -/* Additional */ -#define S5P_FIMV_SI_CH0_DPB_CONF_CTRL 0x2068 /* DPB Config Control Register */ -#define S5P_FIMV_SLICE_INT_MASK 1 -#define S5P_FIMV_SLICE_INT_SHIFT 31 -#define S5P_FIMV_DDELAY_ENA_SHIFT 30 -#define S5P_FIMV_DDELAY_VAL_MASK 0xff -#define S5P_FIMV_DDELAY_VAL_SHIFT 16 -#define S5P_FIMV_DPB_COUNT_MASK 0xffff -#define S5P_FIMV_DPB_FLUSH_MASK 1 -#define S5P_FIMV_DPB_FLUSH_SHIFT 14 - - -#define S5P_FIMV_SI_CH0_RELEASE_BUF 0x2060 /* DPB release buffer register */ -#define S5P_FIMV_SI_CH0_HOST_WR_ADR 0x2064 /* address of shared memory */ - -/* Codec numbers */ -#define S5P_FIMV_CODEC_NONE -1 - -#define S5P_FIMV_CODEC_H264_DEC 0 -#define S5P_FIMV_CODEC_VC1_DEC 1 -#define S5P_FIMV_CODEC_MPEG4_DEC 2 -#define S5P_FIMV_CODEC_MPEG2_DEC 3 -#define S5P_FIMV_CODEC_H263_DEC 4 -#define S5P_FIMV_CODEC_VC1RCV_DEC 5 - -#define S5P_FIMV_CODEC_H264_ENC 16 -#define S5P_FIMV_CODEC_MPEG4_ENC 17 -#define S5P_FIMV_CODEC_H263_ENC 18 - -/* Channel Control Register */ -#define S5P_FIMV_CH_SEQ_HEADER 1 -#define S5P_FIMV_CH_FRAME_START 2 -#define S5P_FIMV_CH_LAST_FRAME 3 -#define S5P_FIMV_CH_INIT_BUFS 4 -#define S5P_FIMV_CH_FRAME_START_REALLOC 5 -#define S5P_FIMV_CH_MASK 7 -#define S5P_FIMV_CH_SHIFT 16 - - -/* Host to RISC command */ -#define S5P_FIMV_H2R_CMD_EMPTY 0 -#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE 1 -#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE 2 -#define S5P_FIMV_H2R_CMD_SYS_INIT 3 -#define S5P_FIMV_H2R_CMD_FLUSH 4 -#define S5P_FIMV_H2R_CMD_SLEEP 5 -#define S5P_FIMV_H2R_CMD_WAKEUP 6 - -#define S5P_FIMV_R2H_CMD_EMPTY 0 -#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET 1 -#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET 2 -#define S5P_FIMV_R2H_CMD_RSV_RET 3 -#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET 4 -#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET 5 -#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET 6 -#define S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET 7 -#define S5P_FIMV_R2H_CMD_SYS_INIT_RET 8 -#define S5P_FIMV_R2H_CMD_FW_STATUS_RET 9 -#define S5P_FIMV_R2H_CMD_SLEEP_RET 10 -#define S5P_FIMV_R2H_CMD_WAKEUP_RET 11 -#define S5P_FIMV_R2H_CMD_FLUSH_RET 12 -#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET 15 -#define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16 -#define S5P_FIMV_R2H_CMD_ERR_RET 32 - -/* Dummy definition for MFCv6 compatibility */ -#define S5P_FIMV_CODEC_H264_MVC_DEC -1 -#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET -1 -#define S5P_FIMV_MFC_RESET -1 -#define S5P_FIMV_RISC_ON -1 -#define S5P_FIMV_RISC_BASE_ADDRESS -1 -#define S5P_FIMV_CODEC_VP8_DEC -1 -#define S5P_FIMV_REG_CLEAR_BEGIN 0 -#define S5P_FIMV_REG_CLEAR_COUNT 0 - -/* Error handling defines */ -#define S5P_FIMV_ERR_NO_VALID_SEQ_HDR 67 -#define S5P_FIMV_ERR_INCOMPLETE_FRAME 124 -#define S5P_FIMV_ERR_TIMEOUT 140 -#define S5P_FIMV_ERR_WARNINGS_START 145 -#define S5P_FIMV_ERR_DEC_MASK 0xFFFF -#define S5P_FIMV_ERR_DEC_SHIFT 0 -#define S5P_FIMV_ERR_DSPL_MASK 0xFFFF0000 -#define S5P_FIMV_ERR_DSPL_SHIFT 16 - -/* Shared memory registers' offsets */ - -/* An offset of the start position in the stream when - * the start position is not aligned */ -#define S5P_FIMV_SHARED_CROP_INFO_H 0x0020 -#define S5P_FIMV_SHARED_CROP_LEFT_MASK 0xFFFF -#define S5P_FIMV_SHARED_CROP_LEFT_SHIFT 0 -#define S5P_FIMV_SHARED_CROP_RIGHT_MASK 0xFFFF0000 -#define S5P_FIMV_SHARED_CROP_RIGHT_SHIFT 16 -#define S5P_FIMV_SHARED_CROP_INFO_V 0x0024 -#define S5P_FIMV_SHARED_CROP_TOP_MASK 0xFFFF -#define S5P_FIMV_SHARED_CROP_TOP_SHIFT 0 -#define S5P_FIMV_SHARED_CROP_BOTTOM_MASK 0xFFFF0000 -#define S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT 16 -#define S5P_FIMV_SHARED_SET_FRAME_TAG 0x0004 -#define S5P_FIMV_SHARED_GET_FRAME_TAG_TOP 0x0008 -#define S5P_FIMV_SHARED_GET_FRAME_TAG_BOT 0x000C -#define S5P_FIMV_SHARED_START_BYTE_NUM 0x0018 -#define S5P_FIMV_SHARED_RC_VOP_TIMING 0x0030 -#define S5P_FIMV_SHARED_LUMA_DPB_SIZE 0x0064 -#define S5P_FIMV_SHARED_CHROMA_DPB_SIZE 0x0068 -#define S5P_FIMV_SHARED_MV_SIZE 0x006C -#define S5P_FIMV_SHARED_PIC_TIME_TOP 0x0010 -#define S5P_FIMV_SHARED_PIC_TIME_BOTTOM 0x0014 -#define S5P_FIMV_SHARED_EXT_ENC_CONTROL 0x0028 -#define S5P_FIMV_SHARED_P_B_FRAME_QP 0x0070 -#define S5P_FIMV_SHARED_ASPECT_RATIO_IDC 0x0074 -#define S5P_FIMV_SHARED_EXTENDED_SAR 0x0078 -#define S5P_FIMV_SHARED_H264_I_PERIOD 0x009C -#define S5P_FIMV_SHARED_RC_CONTROL_CONFIG 0x00A0 -#define S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT 2 - -/* Offset used by the hardware to store addresses */ -#define MFC_OFFSET_SHIFT 11 - -#define FIRMWARE_ALIGN (128 * SZ_1K) /* 128KB */ -#define MFC_H264_CTX_BUF_SIZE (600 * SZ_1K) /* 600KB per H264 instance */ -#define MFC_CTX_BUF_SIZE (10 * SZ_1K) /* 10KB per instance */ -#define DESC_BUF_SIZE (128 * SZ_1K) /* 128KB for DESC buffer */ -#define SHARED_BUF_SIZE (8 * SZ_1K) /* 8KB for shared buffer */ - -#define DEF_CPB_SIZE (256 * SZ_1K) /* 256KB */ -#define MAX_CPB_SIZE (4 * SZ_1M) /* 4MB */ -#define MAX_FW_SIZE (384 * SZ_1K) - -#define MFC_VERSION 0x51 -#define MFC_NUM_PORTS 2 - -#define S5P_FIMV_SHARED_FRAME_PACK_SEI_AVAIL 0x16C -#define S5P_FIMV_SHARED_FRAME_PACK_ARRGMENT_ID 0x170 -#define S5P_FIMV_SHARED_FRAME_PACK_SEI_INFO 0x174 -#define S5P_FIMV_SHARED_FRAME_PACK_GRID_POS 0x178 - -/* Values for resolution change in display status */ -#define S5P_FIMV_RES_INCREASE 1 -#define S5P_FIMV_RES_DECREASE 2 - -#endif /* _REGS_FIMV_H */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c deleted file mode 100644 index 761341934925..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ /dev/null @@ -1,1680 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Samsung S5P Multi Format Codec v 5.1 - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * Kamil Debski, - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "s5p_mfc_common.h" -#include "s5p_mfc_ctrl.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_dec.h" -#include "s5p_mfc_enc.h" -#include "s5p_mfc_intr.h" -#include "s5p_mfc_iommu.h" -#include "s5p_mfc_opr.h" -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_pm.h" - -#define S5P_MFC_DEC_NAME "s5p-mfc-dec" -#define S5P_MFC_ENC_NAME "s5p-mfc-enc" - -int mfc_debug_level; -module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); - -static char *mfc_mem_size; -module_param_named(mem, mfc_mem_size, charp, 0644); -MODULE_PARM_DESC(mem, "Preallocated memory size for the firmware and context buffers"); - -/* Helper functions for interrupt processing */ - -/* Remove from hw execution round robin */ -void clear_work_bit(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - spin_lock(&dev->condlock); - __clear_bit(ctx->num, &dev->ctx_work_bits); - spin_unlock(&dev->condlock); -} - -/* Add to hw execution round robin */ -void set_work_bit(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - spin_lock(&dev->condlock); - __set_bit(ctx->num, &dev->ctx_work_bits); - spin_unlock(&dev->condlock); -} - -/* Remove from hw execution round robin */ -void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - - spin_lock_irqsave(&dev->condlock, flags); - __clear_bit(ctx->num, &dev->ctx_work_bits); - spin_unlock_irqrestore(&dev->condlock, flags); -} - -/* Add to hw execution round robin */ -void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - - spin_lock_irqsave(&dev->condlock, flags); - __set_bit(ctx->num, &dev->ctx_work_bits); - spin_unlock_irqrestore(&dev->condlock, flags); -} - -int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) -{ - unsigned long flags; - int ctx; - - spin_lock_irqsave(&dev->condlock, flags); - ctx = dev->curr_ctx; - do { - ctx = (ctx + 1) % MFC_NUM_CONTEXTS; - if (ctx == dev->curr_ctx) { - if (!test_bit(ctx, &dev->ctx_work_bits)) - ctx = -EAGAIN; - break; - } - } while (!test_bit(ctx, &dev->ctx_work_bits)); - spin_unlock_irqrestore(&dev->condlock, flags); - - return ctx; -} - -/* Wake up context wait_queue */ -static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason, - unsigned int err) -{ - ctx->int_cond = 1; - ctx->int_type = reason; - ctx->int_err = err; - wake_up(&ctx->queue); -} - -/* Wake up device wait_queue */ -static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason, - unsigned int err) -{ - dev->int_cond = 1; - dev->int_type = reason; - dev->int_err = err; - wake_up(&dev->queue); -} - -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) -{ - struct s5p_mfc_buf *b; - int i; - - while (!list_empty(lh)) { - b = list_entry(lh->next, struct s5p_mfc_buf, list); - for (i = 0; i < b->b->vb2_buf.num_planes; i++) - vb2_set_plane_payload(&b->b->vb2_buf, i, 0); - vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR); - list_del(&b->list); - } -} - -static void s5p_mfc_watchdog(struct timer_list *t) -{ - struct s5p_mfc_dev *dev = from_timer(dev, t, watchdog_timer); - - if (test_bit(0, &dev->hw_lock)) - atomic_inc(&dev->watchdog_cnt); - if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) { - /* This means that hw is busy and no interrupts were - * generated by hw for the Nth time of running this - * watchdog timer. This usually means a serious hw - * error. Now it is time to kill all instances and - * reset the MFC. */ - mfc_err("Time out during waiting for HW\n"); - schedule_work(&dev->watchdog_work); - } - dev->watchdog_timer.expires = jiffies + - msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); - add_timer(&dev->watchdog_timer); -} - -static void s5p_mfc_watchdog_worker(struct work_struct *work) -{ - struct s5p_mfc_dev *dev; - struct s5p_mfc_ctx *ctx; - unsigned long flags; - int mutex_locked; - int i, ret; - - dev = container_of(work, struct s5p_mfc_dev, watchdog_work); - - mfc_err("Driver timeout error handling\n"); - /* Lock the mutex that protects open and release. - * This is necessary as they may load and unload firmware. */ - mutex_locked = mutex_trylock(&dev->mfc_mutex); - if (!mutex_locked) - mfc_err("Error: some instance may be closing/opening\n"); - spin_lock_irqsave(&dev->irqlock, flags); - - s5p_mfc_clock_off(); - - for (i = 0; i < MFC_NUM_CONTEXTS; i++) { - ctx = dev->ctx[i]; - if (!ctx) - continue; - ctx->state = MFCINST_ERROR; - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); - clear_work_bit(ctx); - wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0); - } - clear_bit(0, &dev->hw_lock); - spin_unlock_irqrestore(&dev->irqlock, flags); - - /* De-init MFC */ - s5p_mfc_deinit_hw(dev); - - /* Double check if there is at least one instance running. - * If no instance is in memory than no firmware should be present */ - if (dev->num_inst > 0) { - ret = s5p_mfc_load_firmware(dev); - if (ret) { - mfc_err("Failed to reload FW\n"); - goto unlock; - } - s5p_mfc_clock_on(); - ret = s5p_mfc_init_hw(dev); - s5p_mfc_clock_off(); - if (ret) - mfc_err("Failed to reinit FW\n"); - } -unlock: - if (mutex_locked) - mutex_unlock(&dev->mfc_mutex); -} - -static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_buf *dst_buf; - struct s5p_mfc_dev *dev = ctx->dev; - - ctx->state = MFCINST_FINISHED; - ctx->sequence++; - while (!list_empty(&ctx->dst_queue)) { - dst_buf = list_entry(ctx->dst_queue.next, - struct s5p_mfc_buf, list); - mfc_debug(2, "Cleaning up buffer: %d\n", - dst_buf->b->vb2_buf.index); - vb2_set_plane_payload(&dst_buf->b->vb2_buf, 0, 0); - vb2_set_plane_payload(&dst_buf->b->vb2_buf, 1, 0); - list_del(&dst_buf->list); - dst_buf->flags |= MFC_BUF_FLAG_EOS; - ctx->dst_queue_cnt--; - dst_buf->b->sequence = (ctx->sequence++); - - if (s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_top, ctx) == - s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_bot, ctx)) - dst_buf->b->field = V4L2_FIELD_NONE; - else - dst_buf->b->field = V4L2_FIELD_INTERLACED; - dst_buf->b->flags |= V4L2_BUF_FLAG_LAST; - - ctx->dec_dst_flag &= ~(1 << dst_buf->b->vb2_buf.index); - vb2_buffer_done(&dst_buf->b->vb2_buf, VB2_BUF_STATE_DONE); - } -} - -static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *dst_buf, *src_buf; - u32 dec_y_addr; - unsigned int frame_type; - - /* Make sure we actually have a new frame before continuing. */ - frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); - if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) - return; - dec_y_addr = (u32)s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev); - - /* Copy timestamp / timecode from decoded src to dst and set - appropriate flags. */ - src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - list_for_each_entry(dst_buf, &ctx->dst_queue, list) { - u32 addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0); - - if (addr == dec_y_addr) { - dst_buf->b->timecode = src_buf->b->timecode; - dst_buf->b->vb2_buf.timestamp = - src_buf->b->vb2_buf.timestamp; - dst_buf->b->flags &= - ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->b->flags |= - src_buf->b->flags - & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - switch (frame_type) { - case S5P_FIMV_DECODE_FRAME_I_FRAME: - dst_buf->b->flags |= - V4L2_BUF_FLAG_KEYFRAME; - break; - case S5P_FIMV_DECODE_FRAME_P_FRAME: - dst_buf->b->flags |= - V4L2_BUF_FLAG_PFRAME; - break; - case S5P_FIMV_DECODE_FRAME_B_FRAME: - dst_buf->b->flags |= - V4L2_BUF_FLAG_BFRAME; - break; - default: - /* Don't know how to handle - S5P_FIMV_DECODE_FRAME_OTHER_FRAME. */ - mfc_debug(2, "Unexpected frame type: %d\n", - frame_type); - } - break; - } - } -} - -static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *dst_buf; - u32 dspl_y_addr; - unsigned int frame_type; - - dspl_y_addr = (u32)s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); - if (IS_MFCV6_PLUS(dev)) - frame_type = s5p_mfc_hw_call(dev->mfc_ops, - get_disp_frame_type, ctx); - else - frame_type = s5p_mfc_hw_call(dev->mfc_ops, - get_dec_frame_type, dev); - - /* If frame is same as previous then skip and do not dequeue */ - if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { - if (!ctx->after_packed_pb) - ctx->sequence++; - ctx->after_packed_pb = 0; - return; - } - ctx->sequence++; - /* The MFC returns address of the buffer, now we have to - * check which videobuf does it correspond to */ - list_for_each_entry(dst_buf, &ctx->dst_queue, list) { - u32 addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0); - - /* Check if this is the buffer we're looking for */ - if (addr == dspl_y_addr) { - list_del(&dst_buf->list); - ctx->dst_queue_cnt--; - dst_buf->b->sequence = ctx->sequence; - if (s5p_mfc_hw_call(dev->mfc_ops, - get_pic_type_top, ctx) == - s5p_mfc_hw_call(dev->mfc_ops, - get_pic_type_bot, ctx)) - dst_buf->b->field = V4L2_FIELD_NONE; - else - dst_buf->b->field = - V4L2_FIELD_INTERLACED; - vb2_set_plane_payload(&dst_buf->b->vb2_buf, 0, - ctx->luma_size); - vb2_set_plane_payload(&dst_buf->b->vb2_buf, 1, - ctx->chroma_size); - clear_bit(dst_buf->b->vb2_buf.index, - &ctx->dec_dst_flag); - - vb2_buffer_done(&dst_buf->b->vb2_buf, err ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - - break; - } - } -} - -/* Handle frame decoding interrupt */ -static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, - unsigned int reason, unsigned int err) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int dst_frame_status; - unsigned int dec_frame_status; - struct s5p_mfc_buf *src_buf; - unsigned int res_change; - - dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) - & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; - dec_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dec_status, dev) - & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; - res_change = (s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) - & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK) - >> S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT; - mfc_debug(2, "Frame Status: %x\n", dst_frame_status); - if (ctx->state == MFCINST_RES_CHANGE_INIT) - ctx->state = MFCINST_RES_CHANGE_FLUSH; - if (res_change == S5P_FIMV_RES_INCREASE || - res_change == S5P_FIMV_RES_DECREASE) { - ctx->state = MFCINST_RES_CHANGE_INIT; - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - wake_up_ctx(ctx, reason, err); - WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - return; - } - if (ctx->dpb_flush_flag) - ctx->dpb_flush_flag = 0; - - /* All frames remaining in the buffer have been extracted */ - if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) { - if (ctx->state == MFCINST_RES_CHANGE_FLUSH) { - static const struct v4l2_event ev_src_ch = { - .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = - V4L2_EVENT_SRC_CH_RESOLUTION, - }; - - s5p_mfc_handle_frame_all_extracted(ctx); - ctx->state = MFCINST_RES_CHANGE_END; - v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); - - goto leave_handle_frame; - } else { - s5p_mfc_handle_frame_all_extracted(ctx); - } - } - - if (dec_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) - s5p_mfc_handle_frame_copy_time(ctx); - - /* A frame has been decoded and is in the buffer */ - if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY || - dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) { - s5p_mfc_handle_frame_new(ctx, err); - } else { - mfc_debug(2, "No frame decode\n"); - } - /* Mark source buffer as complete */ - if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY - && !list_empty(&ctx->src_queue)) { - src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, - list); - ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops, - get_consumed_stream, dev); - if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC && - ctx->codec_mode != S5P_MFC_CODEC_VP8_DEC && - ctx->consumed_stream + STUFF_BYTE < - src_buf->b->vb2_buf.planes[0].bytesused) { - /* Run MFC again on the same buffer */ - mfc_debug(2, "Running again the same buffer\n"); - ctx->after_packed_pb = 1; - } else { - mfc_debug(2, "MFC needs next buffer\n"); - ctx->consumed_stream = 0; - if (src_buf->flags & MFC_BUF_FLAG_EOS) - ctx->state = MFCINST_FINISHING; - list_del(&src_buf->list); - ctx->src_queue_cnt--; - if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0) - vb2_buffer_done(&src_buf->b->vb2_buf, - VB2_BUF_STATE_ERROR); - else - vb2_buffer_done(&src_buf->b->vb2_buf, - VB2_BUF_STATE_DONE); - } - } -leave_handle_frame: - if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) - || ctx->dst_queue_cnt < ctx->pb_count) - clear_work_bit(ctx); - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - wake_up_ctx(ctx, reason, err); - WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); - /* if suspending, wake up device and do not try_run again*/ - if (test_bit(0, &dev->enter_suspend)) - wake_up_dev(dev, reason, err); - else - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); -} - -/* Error handling for interrupt */ -static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, - struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err) -{ - mfc_err("Interrupt Error: %08x\n", err); - - if (ctx) { - /* Error recovery is dependent on the state of context */ - switch (ctx->state) { - case MFCINST_RES_CHANGE_INIT: - case MFCINST_RES_CHANGE_FLUSH: - case MFCINST_RES_CHANGE_END: - case MFCINST_FINISHING: - case MFCINST_FINISHED: - case MFCINST_RUNNING: - /* It is highly probable that an error occurred - * while decoding a frame */ - clear_work_bit(ctx); - ctx->state = MFCINST_ERROR; - /* Mark all dst buffers as having an error */ - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); - /* Mark all src buffers as having an error */ - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); - wake_up_ctx(ctx, reason, err); - break; - default: - clear_work_bit(ctx); - ctx->state = MFCINST_ERROR; - wake_up_ctx(ctx, reason, err); - break; - } - } - WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - s5p_mfc_clock_off(); - wake_up_dev(dev, reason, err); -} - -/* Header parsing interrupt handling */ -static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, - unsigned int reason, unsigned int err) -{ - struct s5p_mfc_dev *dev; - - if (!ctx) - return; - dev = ctx->dev; - if (ctx->c_ops->post_seq_start) { - if (ctx->c_ops->post_seq_start(ctx)) - mfc_err("post_seq_start() failed\n"); - } else { - ctx->img_width = s5p_mfc_hw_call(dev->mfc_ops, get_img_width, - dev); - ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height, - dev); - - s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx); - - ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, - dev); - ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, - dev); - if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) - ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, - get_min_scratch_buf_size, dev); - if (ctx->img_width == 0 || ctx->img_height == 0) - ctx->state = MFCINST_ERROR; - else - ctx->state = MFCINST_HEAD_PARSED; - - if ((ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || - ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) && - !list_empty(&ctx->src_queue)) { - struct s5p_mfc_buf *src_buf; - src_buf = list_entry(ctx->src_queue.next, - struct s5p_mfc_buf, list); - if (s5p_mfc_hw_call(dev->mfc_ops, get_consumed_stream, - dev) < - src_buf->b->vb2_buf.planes[0].bytesused) - ctx->head_processed = 0; - else - ctx->head_processed = 1; - } else { - ctx->head_processed = 1; - } - } - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - clear_work_bit(ctx); - WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - wake_up_ctx(ctx, reason, err); -} - -/* Header parsing interrupt handling */ -static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, - unsigned int reason, unsigned int err) -{ - struct s5p_mfc_buf *src_buf; - struct s5p_mfc_dev *dev; - - if (!ctx) - return; - dev = ctx->dev; - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - ctx->int_type = reason; - ctx->int_err = err; - ctx->int_cond = 1; - clear_work_bit(ctx); - if (err == 0) { - ctx->state = MFCINST_RUNNING; - if (!ctx->dpb_flush_flag && ctx->head_processed) { - if (!list_empty(&ctx->src_queue)) { - src_buf = list_entry(ctx->src_queue.next, - struct s5p_mfc_buf, list); - list_del(&src_buf->list); - ctx->src_queue_cnt--; - vb2_buffer_done(&src_buf->b->vb2_buf, - VB2_BUF_STATE_DONE); - } - } else { - ctx->dpb_flush_flag = 0; - } - WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - - s5p_mfc_clock_off(); - - wake_up(&ctx->queue); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - } else { - WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - - s5p_mfc_clock_off(); - - wake_up(&ctx->queue); - } -} - -static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *mb_entry; - - mfc_debug(2, "Stream completed\n"); - - ctx->state = MFCINST_FINISHED; - - if (!list_empty(&ctx->dst_queue)) { - mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, - list); - list_del(&mb_entry->list); - ctx->dst_queue_cnt--; - vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, 0); - vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE); - } - - clear_work_bit(ctx); - - WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - - s5p_mfc_clock_off(); - wake_up(&ctx->queue); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); -} - -/* Interrupt processing */ -static irqreturn_t s5p_mfc_irq(int irq, void *priv) -{ - struct s5p_mfc_dev *dev = priv; - struct s5p_mfc_ctx *ctx; - unsigned int reason; - unsigned int err; - - mfc_debug_enter(); - /* Reset the timeout watchdog */ - atomic_set(&dev->watchdog_cnt, 0); - spin_lock(&dev->irqlock); - ctx = dev->ctx[dev->curr_ctx]; - /* Get the reason of interrupt and the error code */ - reason = s5p_mfc_hw_call(dev->mfc_ops, get_int_reason, dev); - err = s5p_mfc_hw_call(dev->mfc_ops, get_int_err, dev); - mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err); - switch (reason) { - case S5P_MFC_R2H_CMD_ERR_RET: - /* An error has occurred */ - if (ctx->state == MFCINST_RUNNING && - (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >= - dev->warn_start || - err == S5P_FIMV_ERR_NO_VALID_SEQ_HDR || - err == S5P_FIMV_ERR_INCOMPLETE_FRAME || - err == S5P_FIMV_ERR_TIMEOUT)) - s5p_mfc_handle_frame(ctx, reason, err); - else - s5p_mfc_handle_error(dev, ctx, reason, err); - clear_bit(0, &dev->enter_suspend); - break; - - case S5P_MFC_R2H_CMD_SLICE_DONE_RET: - case S5P_MFC_R2H_CMD_FIELD_DONE_RET: - case S5P_MFC_R2H_CMD_FRAME_DONE_RET: - if (ctx->c_ops->post_frame_start) { - if (ctx->c_ops->post_frame_start(ctx)) - mfc_err("post_frame_start() failed\n"); - - if (ctx->state == MFCINST_FINISHING && - list_empty(&ctx->ref_queue)) { - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - s5p_mfc_handle_stream_complete(ctx); - break; - } - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); - wake_up_ctx(ctx, reason, err); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - } else { - s5p_mfc_handle_frame(ctx, reason, err); - } - break; - - case S5P_MFC_R2H_CMD_SEQ_DONE_RET: - s5p_mfc_handle_seq_done(ctx, reason, err); - break; - - case S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET: - ctx->inst_no = s5p_mfc_hw_call(dev->mfc_ops, get_inst_no, dev); - ctx->state = MFCINST_GOT_INST; - goto irq_cleanup_hw; - - case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET: - ctx->inst_no = MFC_NO_INSTANCE_SET; - ctx->state = MFCINST_FREE; - goto irq_cleanup_hw; - - case S5P_MFC_R2H_CMD_SYS_INIT_RET: - case S5P_MFC_R2H_CMD_FW_STATUS_RET: - case S5P_MFC_R2H_CMD_SLEEP_RET: - case S5P_MFC_R2H_CMD_WAKEUP_RET: - if (ctx) - clear_work_bit(ctx); - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - clear_bit(0, &dev->hw_lock); - clear_bit(0, &dev->enter_suspend); - wake_up_dev(dev, reason, err); - break; - - case S5P_MFC_R2H_CMD_INIT_BUFFERS_RET: - s5p_mfc_handle_init_buffers(ctx, reason, err); - break; - - case S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET: - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - ctx->int_type = reason; - ctx->int_err = err; - s5p_mfc_handle_stream_complete(ctx); - break; - - case S5P_MFC_R2H_CMD_DPB_FLUSH_RET: - ctx->state = MFCINST_RUNNING; - goto irq_cleanup_hw; - - default: - mfc_debug(2, "Unknown int reason\n"); - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - } - spin_unlock(&dev->irqlock); - mfc_debug_leave(); - return IRQ_HANDLED; -irq_cleanup_hw: - s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - ctx->int_type = reason; - ctx->int_err = err; - ctx->int_cond = 1; - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - mfc_err("Failed to unlock hw\n"); - - s5p_mfc_clock_off(); - clear_work_bit(ctx); - wake_up(&ctx->queue); - - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - spin_unlock(&dev->irqlock); - mfc_debug(2, "Exit via irq_cleanup_hw\n"); - return IRQ_HANDLED; -} - -/* Open an MFC node */ -static int s5p_mfc_open(struct file *file) -{ - struct video_device *vdev = video_devdata(file); - struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = NULL; - struct vb2_queue *q; - int ret = 0; - - mfc_debug_enter(); - if (mutex_lock_interruptible(&dev->mfc_mutex)) - return -ERESTARTSYS; - dev->num_inst++; /* It is guarded by mfc_mutex in vfd */ - /* Allocate memory for context */ - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - ret = -ENOMEM; - goto err_alloc; - } - init_waitqueue_head(&ctx->queue); - v4l2_fh_init(&ctx->fh, vdev); - file->private_data = &ctx->fh; - v4l2_fh_add(&ctx->fh); - ctx->dev = dev; - INIT_LIST_HEAD(&ctx->src_queue); - INIT_LIST_HEAD(&ctx->dst_queue); - ctx->src_queue_cnt = 0; - ctx->dst_queue_cnt = 0; - /* Get context number */ - ctx->num = 0; - while (dev->ctx[ctx->num]) { - ctx->num++; - if (ctx->num >= MFC_NUM_CONTEXTS) { - mfc_debug(2, "Too many open contexts\n"); - ret = -EBUSY; - goto err_no_ctx; - } - } - /* Mark context as idle */ - clear_work_bit_irqsave(ctx); - dev->ctx[ctx->num] = ctx; - if (vdev == dev->vfd_dec) { - ctx->type = MFCINST_DECODER; - ctx->c_ops = get_dec_codec_ops(); - s5p_mfc_dec_init(ctx); - /* Setup ctrl handler */ - ret = s5p_mfc_dec_ctrls_setup(ctx); - if (ret) { - mfc_err("Failed to setup mfc controls\n"); - goto err_ctrls_setup; - } - } else if (vdev == dev->vfd_enc) { - ctx->type = MFCINST_ENCODER; - ctx->c_ops = get_enc_codec_ops(); - /* only for encoder */ - INIT_LIST_HEAD(&ctx->ref_queue); - ctx->ref_queue_cnt = 0; - s5p_mfc_enc_init(ctx); - /* Setup ctrl handler */ - ret = s5p_mfc_enc_ctrls_setup(ctx); - if (ret) { - mfc_err("Failed to setup mfc controls\n"); - goto err_ctrls_setup; - } - } else { - ret = -ENOENT; - goto err_bad_node; - } - ctx->fh.ctrl_handler = &ctx->ctrl_handler; - ctx->inst_no = MFC_NO_INSTANCE_SET; - /* Load firmware if this is the first instance */ - if (dev->num_inst == 1) { - dev->watchdog_timer.expires = jiffies + - msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); - add_timer(&dev->watchdog_timer); - ret = s5p_mfc_power_on(); - if (ret < 0) { - mfc_err("power on failed\n"); - goto err_pwr_enable; - } - s5p_mfc_clock_on(); - ret = s5p_mfc_load_firmware(dev); - if (ret) { - s5p_mfc_clock_off(); - goto err_load_fw; - } - /* Init the FW */ - ret = s5p_mfc_init_hw(dev); - s5p_mfc_clock_off(); - if (ret) - goto err_init_hw; - } - /* Init videobuf2 queue for CAPTURE */ - q = &ctx->vq_dst; - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->drv_priv = &ctx->fh; - q->lock = &dev->mfc_mutex; - if (vdev == dev->vfd_dec) { - q->io_modes = VB2_MMAP; - q->ops = get_dec_queue_ops(); - } else if (vdev == dev->vfd_enc) { - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->ops = get_enc_queue_ops(); - } else { - ret = -ENOENT; - goto err_queue_init; - } - /* - * We'll do mostly sequential access, so sacrifice TLB efficiency for - * faster allocation. - */ - q->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES; - q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - ret = vb2_queue_init(q); - if (ret) { - mfc_err("Failed to initialize videobuf2 queue(capture)\n"); - goto err_queue_init; - } - /* Init videobuf2 queue for OUTPUT */ - q = &ctx->vq_src; - q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - q->drv_priv = &ctx->fh; - q->lock = &dev->mfc_mutex; - if (vdev == dev->vfd_dec) { - q->io_modes = VB2_MMAP; - q->ops = get_dec_queue_ops(); - } else if (vdev == dev->vfd_enc) { - q->io_modes = VB2_MMAP | VB2_USERPTR; - q->ops = get_enc_queue_ops(); - } else { - ret = -ENOENT; - goto err_queue_init; - } - /* One way to indicate end-of-stream for MFC is to set the - * bytesused == 0. However by default videobuf2 handles bytesused - * equal to 0 as a special case and changes its value to the size - * of the buffer. Set the allow_zero_bytesused flag so that videobuf2 - * will keep the value of bytesused intact. - */ - q->allow_zero_bytesused = 1; - - /* - * We'll do mostly sequential access, so sacrifice TLB efficiency for - * faster allocation. - */ - q->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES; - q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - ret = vb2_queue_init(q); - if (ret) { - mfc_err("Failed to initialize videobuf2 queue(output)\n"); - goto err_queue_init; - } - mutex_unlock(&dev->mfc_mutex); - mfc_debug_leave(); - return ret; - /* Deinit when failure occurred */ -err_queue_init: - if (dev->num_inst == 1) - s5p_mfc_deinit_hw(dev); -err_init_hw: -err_load_fw: -err_pwr_enable: - if (dev->num_inst == 1) { - if (s5p_mfc_power_off() < 0) - mfc_err("power off failed\n"); - del_timer_sync(&dev->watchdog_timer); - } -err_ctrls_setup: - s5p_mfc_dec_ctrls_delete(ctx); -err_bad_node: - dev->ctx[ctx->num] = NULL; -err_no_ctx: - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - kfree(ctx); -err_alloc: - dev->num_inst--; - mutex_unlock(&dev->mfc_mutex); - mfc_debug_leave(); - return ret; -} - -/* Release MFC context */ -static int s5p_mfc_release(struct file *file) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); - struct s5p_mfc_dev *dev = ctx->dev; - - /* if dev is null, do cleanup that doesn't need dev */ - mfc_debug_enter(); - if (dev) - mutex_lock(&dev->mfc_mutex); - vb2_queue_release(&ctx->vq_src); - vb2_queue_release(&ctx->vq_dst); - if (dev) { - s5p_mfc_clock_on(); - - /* Mark context as idle */ - clear_work_bit_irqsave(ctx); - /* - * If instance was initialised and not yet freed, - * return instance and free resources - */ - if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) { - mfc_debug(2, "Has to free instance\n"); - s5p_mfc_close_mfc_inst(dev, ctx); - } - /* hardware locking scheme */ - if (dev->curr_ctx == ctx->num) - clear_bit(0, &dev->hw_lock); - dev->num_inst--; - if (dev->num_inst == 0) { - mfc_debug(2, "Last instance\n"); - s5p_mfc_deinit_hw(dev); - del_timer_sync(&dev->watchdog_timer); - s5p_mfc_clock_off(); - if (s5p_mfc_power_off() < 0) - mfc_err("Power off failed\n"); - } else { - mfc_debug(2, "Shutting down clock\n"); - s5p_mfc_clock_off(); - } - } - if (dev) - dev->ctx[ctx->num] = NULL; - s5p_mfc_dec_ctrls_delete(ctx); - v4l2_fh_del(&ctx->fh); - /* vdev is gone if dev is null */ - if (dev) - v4l2_fh_exit(&ctx->fh); - kfree(ctx); - mfc_debug_leave(); - if (dev) - mutex_unlock(&dev->mfc_mutex); - - return 0; -} - -/* Poll */ -static __poll_t s5p_mfc_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); - struct s5p_mfc_dev *dev = ctx->dev; - struct vb2_queue *src_q, *dst_q; - struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; - __poll_t rc = 0; - unsigned long flags; - - mutex_lock(&dev->mfc_mutex); - src_q = &ctx->vq_src; - dst_q = &ctx->vq_dst; - /* - * There has to be at least one buffer queued on each queued_list, which - * means either in driver already or waiting for driver to claim it - * and start processing. - */ - if ((!src_q->streaming || list_empty(&src_q->queued_list)) - && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { - rc = EPOLLERR; - goto end; - } - mutex_unlock(&dev->mfc_mutex); - poll_wait(file, &ctx->fh.wait, wait); - poll_wait(file, &src_q->done_wq, wait); - poll_wait(file, &dst_q->done_wq, wait); - mutex_lock(&dev->mfc_mutex); - if (v4l2_event_pending(&ctx->fh)) - rc |= EPOLLPRI; - spin_lock_irqsave(&src_q->done_lock, flags); - if (!list_empty(&src_q->done_list)) - src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, - done_entry); - if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE - || src_vb->state == VB2_BUF_STATE_ERROR)) - rc |= EPOLLOUT | EPOLLWRNORM; - spin_unlock_irqrestore(&src_q->done_lock, flags); - spin_lock_irqsave(&dst_q->done_lock, flags); - if (!list_empty(&dst_q->done_list)) - dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer, - done_entry); - if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE - || dst_vb->state == VB2_BUF_STATE_ERROR)) - rc |= EPOLLIN | EPOLLRDNORM; - spin_unlock_irqrestore(&dst_q->done_lock, flags); -end: - mutex_unlock(&dev->mfc_mutex); - return rc; -} - -/* Mmap */ -static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int ret; - - if (offset < DST_QUEUE_OFF_BASE) { - mfc_debug(2, "mmaping source\n"); - ret = vb2_mmap(&ctx->vq_src, vma); - } else { /* capture */ - mfc_debug(2, "mmaping destination\n"); - vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); - ret = vb2_mmap(&ctx->vq_dst, vma); - } - return ret; -} - -/* v4l2 ops */ -static const struct v4l2_file_operations s5p_mfc_fops = { - .owner = THIS_MODULE, - .open = s5p_mfc_open, - .release = s5p_mfc_release, - .poll = s5p_mfc_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = s5p_mfc_mmap, -}; - -/* DMA memory related helper functions */ -static void s5p_mfc_memdev_release(struct device *dev) -{ - of_reserved_mem_device_release(dev); -} - -static struct device *s5p_mfc_alloc_memdev(struct device *dev, - const char *name, unsigned int idx) -{ - struct device *child; - int ret; - - child = devm_kzalloc(dev, sizeof(*child), GFP_KERNEL); - if (!child) - return NULL; - - device_initialize(child); - dev_set_name(child, "%s:%s", dev_name(dev), name); - child->parent = dev; - child->coherent_dma_mask = dev->coherent_dma_mask; - child->dma_mask = dev->dma_mask; - child->release = s5p_mfc_memdev_release; - child->dma_parms = devm_kzalloc(dev, sizeof(*child->dma_parms), - GFP_KERNEL); - if (!child->dma_parms) - goto err; - - /* - * The memdevs are not proper OF platform devices, so in order for them - * to be treated as valid DMA masters we need a bit of a hack to force - * them to inherit the MFC node's DMA configuration. - */ - of_dma_configure(child, dev->of_node, true); - - if (device_add(child) == 0) { - ret = of_reserved_mem_device_init_by_idx(child, dev->of_node, - idx); - if (ret == 0) - return child; - device_del(child); - } -err: - put_device(child); - return NULL; -} - -static int s5p_mfc_configure_2port_memory(struct s5p_mfc_dev *mfc_dev) -{ - struct device *dev = &mfc_dev->plat_dev->dev; - void *bank2_virt; - dma_addr_t bank2_dma_addr; - unsigned long align_size = 1 << MFC_BASE_ALIGN_ORDER; - int ret; - - /* - * Create and initialize virtual devices for accessing - * reserved memory regions. - */ - mfc_dev->mem_dev[BANK_L_CTX] = s5p_mfc_alloc_memdev(dev, "left", - BANK_L_CTX); - if (!mfc_dev->mem_dev[BANK_L_CTX]) - return -ENODEV; - mfc_dev->mem_dev[BANK_R_CTX] = s5p_mfc_alloc_memdev(dev, "right", - BANK_R_CTX); - if (!mfc_dev->mem_dev[BANK_R_CTX]) { - device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); - return -ENODEV; - } - - /* Allocate memory for firmware and initialize both banks addresses */ - ret = s5p_mfc_alloc_firmware(mfc_dev); - if (ret) { - device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); - device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); - return ret; - } - - mfc_dev->dma_base[BANK_L_CTX] = mfc_dev->fw_buf.dma; - - bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK_R_CTX], - align_size, &bank2_dma_addr, GFP_KERNEL); - if (!bank2_virt) { - mfc_err("Allocating bank2 base failed\n"); - s5p_mfc_release_firmware(mfc_dev); - device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); - device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); - return -ENOMEM; - } - - /* Valid buffers passed to MFC encoder with LAST_FRAME command - * should not have address of bank2 - MFC will treat it as a null frame. - * To avoid such situation we set bank2 address below the pool address. - */ - mfc_dev->dma_base[BANK_R_CTX] = bank2_dma_addr - align_size; - - dma_free_coherent(mfc_dev->mem_dev[BANK_R_CTX], align_size, bank2_virt, - bank2_dma_addr); - - vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK_L_CTX], - DMA_BIT_MASK(32)); - vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK_R_CTX], - DMA_BIT_MASK(32)); - - return 0; -} - -static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) -{ - device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); - device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); - vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK_L_CTX]); - vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK_R_CTX]); -} - -static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) -{ - struct device *dev = &mfc_dev->plat_dev->dev; - unsigned long mem_size = SZ_4M; - - if (IS_ENABLED(CONFIG_DMA_CMA) || exynos_is_iommu_available(dev)) - mem_size = SZ_8M; - - if (mfc_mem_size) - mem_size = memparse(mfc_mem_size, NULL); - - mfc_dev->mem_bitmap = bitmap_zalloc(mem_size >> PAGE_SHIFT, GFP_KERNEL); - if (!mfc_dev->mem_bitmap) - return -ENOMEM; - - mfc_dev->mem_virt = dma_alloc_coherent(dev, mem_size, - &mfc_dev->mem_base, GFP_KERNEL); - if (!mfc_dev->mem_virt) { - bitmap_free(mfc_dev->mem_bitmap); - dev_err(dev, "failed to preallocate %ld MiB for the firmware and context buffers\n", - (mem_size / SZ_1M)); - return -ENOMEM; - } - mfc_dev->mem_size = mem_size; - mfc_dev->dma_base[BANK_L_CTX] = mfc_dev->mem_base; - mfc_dev->dma_base[BANK_R_CTX] = mfc_dev->mem_base; - - /* - * MFC hardware cannot handle 0 as a base address, so mark first 128K - * as used (to keep required base alignment) and adjust base address - */ - if (mfc_dev->mem_base == (dma_addr_t)0) { - unsigned int offset = 1 << MFC_BASE_ALIGN_ORDER; - - bitmap_set(mfc_dev->mem_bitmap, 0, offset >> PAGE_SHIFT); - mfc_dev->dma_base[BANK_L_CTX] += offset; - mfc_dev->dma_base[BANK_R_CTX] += offset; - } - - /* Firmware allocation cannot fail in this case */ - s5p_mfc_alloc_firmware(mfc_dev); - - mfc_dev->mem_dev[BANK_L_CTX] = mfc_dev->mem_dev[BANK_R_CTX] = dev; - vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); - - dev_info(dev, "preallocated %ld MiB buffer for the firmware and context buffers\n", - (mem_size / SZ_1M)); - - return 0; -} - -static void s5p_mfc_unconfigure_common_memory(struct s5p_mfc_dev *mfc_dev) -{ - struct device *dev = &mfc_dev->plat_dev->dev; - - dma_free_coherent(dev, mfc_dev->mem_size, mfc_dev->mem_virt, - mfc_dev->mem_base); - bitmap_free(mfc_dev->mem_bitmap); - vb2_dma_contig_clear_max_seg_size(dev); -} - -static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) -{ - struct device *dev = &mfc_dev->plat_dev->dev; - - if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) - return s5p_mfc_configure_common_memory(mfc_dev); - else - return s5p_mfc_configure_2port_memory(mfc_dev); -} - -static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) -{ - struct device *dev = &mfc_dev->plat_dev->dev; - - s5p_mfc_release_firmware(mfc_dev); - if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) - s5p_mfc_unconfigure_common_memory(mfc_dev); - else - s5p_mfc_unconfigure_2port_memory(mfc_dev); -} - -/* MFC probe function */ -static int s5p_mfc_probe(struct platform_device *pdev) -{ - struct s5p_mfc_dev *dev; - struct video_device *vfd; - int ret; - - pr_debug("%s++\n", __func__); - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - spin_lock_init(&dev->irqlock); - spin_lock_init(&dev->condlock); - dev->plat_dev = pdev; - if (!dev->plat_dev) { - mfc_err("No platform data specified\n"); - return -ENODEV; - } - - dev->variant = of_device_get_match_data(&pdev->dev); - if (!dev->variant) { - dev_err(&pdev->dev, "Failed to get device MFC hardware variant information\n"); - return -ENOENT; - } - - dev->regs_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(dev->regs_base)) - return PTR_ERR(dev->regs_base); - - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - dev->irq = ret; - ret = devm_request_irq(&pdev->dev, dev->irq, s5p_mfc_irq, - 0, pdev->name, dev); - if (ret) { - dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret); - return ret; - } - - ret = s5p_mfc_configure_dma_memory(dev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to configure DMA memory\n"); - return ret; - } - - ret = s5p_mfc_init_pm(dev); - if (ret < 0) { - dev_err(&pdev->dev, "failed to get mfc clock source\n"); - goto err_dma; - } - - /* - * Load fails if fs isn't mounted. Try loading anyway. - * _open() will load it, it it fails now. Ignore failure. - */ - s5p_mfc_load_firmware(dev); - - mutex_init(&dev->mfc_mutex); - init_waitqueue_head(&dev->queue); - dev->hw_lock = 0; - INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker); - atomic_set(&dev->watchdog_cnt, 0); - timer_setup(&dev->watchdog_timer, s5p_mfc_watchdog, 0); - - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); - if (ret) - goto err_v4l2_dev_reg; - - /* decoder */ - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); - ret = -ENOMEM; - goto err_dec_alloc; - } - vfd->fops = &s5p_mfc_fops; - vfd->ioctl_ops = get_dec_v4l2_ioctl_ops(); - vfd->release = video_device_release; - vfd->lock = &dev->mfc_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->vfl_dir = VFL_DIR_M2M; - vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); - snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME); - dev->vfd_dec = vfd; - video_set_drvdata(vfd, dev); - - /* encoder */ - vfd = video_device_alloc(); - if (!vfd) { - v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); - ret = -ENOMEM; - goto err_enc_alloc; - } - vfd->fops = &s5p_mfc_fops; - vfd->ioctl_ops = get_enc_v4l2_ioctl_ops(); - vfd->release = video_device_release; - vfd->lock = &dev->mfc_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->vfl_dir = VFL_DIR_M2M; - vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); - dev->vfd_enc = vfd; - video_set_drvdata(vfd, dev); - platform_set_drvdata(pdev, dev); - - /* Initialize HW ops and commands based on MFC version */ - s5p_mfc_init_hw_ops(dev); - s5p_mfc_init_hw_cmds(dev); - s5p_mfc_init_regs(dev); - - /* Register decoder and encoder */ - ret = video_register_device(dev->vfd_dec, VFL_TYPE_VIDEO, 0); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto err_dec_reg; - } - v4l2_info(&dev->v4l2_dev, - "decoder registered as /dev/video%d\n", dev->vfd_dec->num); - - ret = video_register_device(dev->vfd_enc, VFL_TYPE_VIDEO, 0); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto err_enc_reg; - } - v4l2_info(&dev->v4l2_dev, - "encoder registered as /dev/video%d\n", dev->vfd_enc->num); - - pr_debug("%s--\n", __func__); - return 0; - -/* Deinit MFC if probe had failed */ -err_enc_reg: - video_unregister_device(dev->vfd_dec); -err_dec_reg: - video_device_release(dev->vfd_enc); -err_enc_alloc: - video_device_release(dev->vfd_dec); -err_dec_alloc: - v4l2_device_unregister(&dev->v4l2_dev); -err_v4l2_dev_reg: - s5p_mfc_final_pm(dev); -err_dma: - s5p_mfc_unconfigure_dma_memory(dev); - - pr_debug("%s-- with error\n", __func__); - return ret; - -} - -/* Remove the driver */ -static int s5p_mfc_remove(struct platform_device *pdev) -{ - struct s5p_mfc_dev *dev = platform_get_drvdata(pdev); - struct s5p_mfc_ctx *ctx; - int i; - - v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name); - - /* - * Clear ctx dev pointer to avoid races between s5p_mfc_remove() - * and s5p_mfc_release() and s5p_mfc_release() accessing ctx->dev - * after s5p_mfc_remove() is run during unbind. - */ - mutex_lock(&dev->mfc_mutex); - for (i = 0; i < MFC_NUM_CONTEXTS; i++) { - ctx = dev->ctx[i]; - if (!ctx) - continue; - /* clear ctx->dev */ - ctx->dev = NULL; - } - mutex_unlock(&dev->mfc_mutex); - - del_timer_sync(&dev->watchdog_timer); - flush_work(&dev->watchdog_work); - - video_unregister_device(dev->vfd_enc); - video_unregister_device(dev->vfd_dec); - video_device_release(dev->vfd_enc); - video_device_release(dev->vfd_dec); - v4l2_device_unregister(&dev->v4l2_dev); - s5p_mfc_unconfigure_dma_memory(dev); - - s5p_mfc_final_pm(dev); - return 0; -} - -#ifdef CONFIG_PM_SLEEP - -static int s5p_mfc_suspend(struct device *dev) -{ - struct s5p_mfc_dev *m_dev = dev_get_drvdata(dev); - int ret; - - if (m_dev->num_inst == 0) - return 0; - - if (test_and_set_bit(0, &m_dev->enter_suspend) != 0) { - mfc_err("Error: going to suspend for a second time\n"); - return -EIO; - } - - /* Check if we're processing then wait if it necessary. */ - while (test_and_set_bit(0, &m_dev->hw_lock) != 0) { - /* Try and lock the HW */ - /* Wait on the interrupt waitqueue */ - ret = wait_event_interruptible_timeout(m_dev->queue, - m_dev->int_cond, msecs_to_jiffies(MFC_INT_TIMEOUT)); - if (ret == 0) { - mfc_err("Waiting for hardware to finish timed out\n"); - clear_bit(0, &m_dev->enter_suspend); - return -EIO; - } - } - - ret = s5p_mfc_sleep(m_dev); - if (ret) { - clear_bit(0, &m_dev->enter_suspend); - clear_bit(0, &m_dev->hw_lock); - } - return ret; -} - -static int s5p_mfc_resume(struct device *dev) -{ - struct s5p_mfc_dev *m_dev = dev_get_drvdata(dev); - - if (m_dev->num_inst == 0) - return 0; - return s5p_mfc_wakeup(m_dev); -} -#endif - -/* Power management */ -static const struct dev_pm_ops s5p_mfc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume) -}; - -static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { - .h264_ctx = MFC_H264_CTX_BUF_SIZE, - .non_h264_ctx = MFC_CTX_BUF_SIZE, - .dsc = DESC_BUF_SIZE, - .shm = SHARED_BUF_SIZE, -}; - -static struct s5p_mfc_buf_size buf_size_v5 = { - .fw = MAX_FW_SIZE, - .cpb = MAX_CPB_SIZE, - .priv = &mfc_buf_size_v5, -}; - -static struct s5p_mfc_variant mfc_drvdata_v5 = { - .version = MFC_VERSION, - .version_bit = MFC_V5_BIT, - .port_num = MFC_NUM_PORTS, - .buf_size = &buf_size_v5, - .fw_name[0] = "s5p-mfc.fw", - .clk_names = {"mfc", "sclk_mfc"}, - .num_clocks = 2, - .use_clock_gating = true, -}; - -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { - .dev_ctx = MFC_CTX_BUF_SIZE_V6, - .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V6, - .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V6, - .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V6, - .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V6, -}; - -static struct s5p_mfc_buf_size buf_size_v6 = { - .fw = MAX_FW_SIZE_V6, - .cpb = MAX_CPB_SIZE_V6, - .priv = &mfc_buf_size_v6, -}; - -static struct s5p_mfc_variant mfc_drvdata_v6 = { - .version = MFC_VERSION_V6, - .version_bit = MFC_V6_BIT, - .port_num = MFC_NUM_PORTS_V6, - .buf_size = &buf_size_v6, - .fw_name[0] = "s5p-mfc-v6.fw", - /* - * v6-v2 firmware contains bug fixes and interface change - * for init buffer command - */ - .fw_name[1] = "s5p-mfc-v6-v2.fw", - .clk_names = {"mfc"}, - .num_clocks = 1, -}; - -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { - .dev_ctx = MFC_CTX_BUF_SIZE_V7, - .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V7, - .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V7, - .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V7, - .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V7, -}; - -static struct s5p_mfc_buf_size buf_size_v7 = { - .fw = MAX_FW_SIZE_V7, - .cpb = MAX_CPB_SIZE_V7, - .priv = &mfc_buf_size_v7, -}; - -static struct s5p_mfc_variant mfc_drvdata_v7 = { - .version = MFC_VERSION_V7, - .version_bit = MFC_V7_BIT, - .port_num = MFC_NUM_PORTS_V7, - .buf_size = &buf_size_v7, - .fw_name[0] = "s5p-mfc-v7.fw", - .clk_names = {"mfc", "sclk_mfc"}, - .num_clocks = 2, -}; - -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { - .dev_ctx = MFC_CTX_BUF_SIZE_V8, - .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V8, - .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V8, - .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V8, - .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V8, -}; - -static struct s5p_mfc_buf_size buf_size_v8 = { - .fw = MAX_FW_SIZE_V8, - .cpb = MAX_CPB_SIZE_V8, - .priv = &mfc_buf_size_v8, -}; - -static struct s5p_mfc_variant mfc_drvdata_v8 = { - .version = MFC_VERSION_V8, - .version_bit = MFC_V8_BIT, - .port_num = MFC_NUM_PORTS_V8, - .buf_size = &buf_size_v8, - .fw_name[0] = "s5p-mfc-v8.fw", - .clk_names = {"mfc"}, - .num_clocks = 1, -}; - -static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { - .version = MFC_VERSION_V8, - .version_bit = MFC_V8_BIT, - .port_num = MFC_NUM_PORTS_V8, - .buf_size = &buf_size_v8, - .fw_name[0] = "s5p-mfc-v8.fw", - .clk_names = {"pclk", "aclk", "aclk_xiu"}, - .num_clocks = 3, -}; - -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { - .dev_ctx = MFC_CTX_BUF_SIZE_V10, - .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V10, - .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V10, - .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V10, - .hevc_enc_ctx = MFC_HEVC_ENC_CTX_BUF_SIZE_V10, - .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V10, -}; - -static struct s5p_mfc_buf_size buf_size_v10 = { - .fw = MAX_FW_SIZE_V10, - .cpb = MAX_CPB_SIZE_V10, - .priv = &mfc_buf_size_v10, -}; - -static struct s5p_mfc_variant mfc_drvdata_v10 = { - .version = MFC_VERSION_V10, - .version_bit = MFC_V10_BIT, - .port_num = MFC_NUM_PORTS_V10, - .buf_size = &buf_size_v10, - .fw_name[0] = "s5p-mfc-v10.fw", -}; - -static const struct of_device_id exynos_mfc_match[] = { - { - .compatible = "samsung,mfc-v5", - .data = &mfc_drvdata_v5, - }, { - .compatible = "samsung,mfc-v6", - .data = &mfc_drvdata_v6, - }, { - .compatible = "samsung,mfc-v7", - .data = &mfc_drvdata_v7, - }, { - .compatible = "samsung,mfc-v8", - .data = &mfc_drvdata_v8, - }, { - .compatible = "samsung,exynos5433-mfc", - .data = &mfc_drvdata_v8_5433, - }, { - .compatible = "samsung,mfc-v10", - .data = &mfc_drvdata_v10, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, exynos_mfc_match); - -static struct platform_driver s5p_mfc_driver = { - .probe = s5p_mfc_probe, - .remove = s5p_mfc_remove, - .driver = { - .name = S5P_MFC_NAME, - .pm = &s5p_mfc_pm_ops, - .of_match_table = exynos_mfc_match, - }, -}; - -module_platform_driver(s5p_mfc_driver); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kamil Debski "); -MODULE_DESCRIPTION("Samsung S5P Multi Format Codec V4L2 driver"); - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c deleted file mode 100644 index 0e88c28f4ad3..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c - * - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_common.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_cmd_v5.h" -#include "s5p_mfc_cmd_v6.h" - -static struct s5p_mfc_hw_cmds *s5p_mfc_cmds; - -void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev) -{ - if (IS_MFCV6_PLUS(dev)) - s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v6(); - else - s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); - - dev->mfc_cmds = s5p_mfc_cmds; -} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h deleted file mode 100644 index ed4e32a12552..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h - * - * Copyright (C) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_CMD_H_ -#define S5P_MFC_CMD_H_ - -#include "s5p_mfc_common.h" - -#define MAX_H2R_ARG 4 - -struct s5p_mfc_cmd_args { - unsigned int arg[MAX_H2R_ARG]; -}; - -struct s5p_mfc_hw_cmds { - int (*cmd_host2risc)(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args); - int (*sys_init_cmd)(struct s5p_mfc_dev *dev); - int (*sleep_cmd)(struct s5p_mfc_dev *dev); - int (*wakeup_cmd)(struct s5p_mfc_dev *dev); - int (*open_inst_cmd)(struct s5p_mfc_ctx *ctx); - int (*close_inst_cmd)(struct s5p_mfc_ctx *ctx); -}; - -void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev); -#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c deleted file mode 100644 index 1ea4eda9c8e0..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#include "regs-mfc.h" -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_common.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_cmd_v5.h" - -/* This function is used to send a command to the MFC */ -static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args) -{ - int cur_cmd; - unsigned long timeout; - - timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); - /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ - do { - if (time_after(jiffies, timeout)) { - mfc_err("Timeout while waiting for hardware\n"); - return -EIO; - } - cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); - } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); - mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); - mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); - mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); - mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); - /* Issue the command */ - mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); - return 0; -} - -/* Initialize the MFC */ -static int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = dev->fw_buf.size; - return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, - &h2r_args); -} - -/* Suspend the MFC hardware */ -static int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); -} - -/* Wake up the MFC hardware */ -static int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_WAKEUP, - &h2r_args); -} - - -static int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int ret; - - /* Preparing decoding - getting instance number */ - mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); - dev->curr_ctx = ctx->num; - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - switch (ctx->codec_mode) { - case S5P_MFC_CODEC_H264_DEC: - h2r_args.arg[0] = S5P_FIMV_CODEC_H264_DEC; - break; - case S5P_MFC_CODEC_VC1_DEC: - h2r_args.arg[0] = S5P_FIMV_CODEC_VC1_DEC; - break; - case S5P_MFC_CODEC_MPEG4_DEC: - h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_DEC; - break; - case S5P_MFC_CODEC_MPEG2_DEC: - h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG2_DEC; - break; - case S5P_MFC_CODEC_H263_DEC: - h2r_args.arg[0] = S5P_FIMV_CODEC_H263_DEC; - break; - case S5P_MFC_CODEC_VC1RCV_DEC: - h2r_args.arg[0] = S5P_FIMV_CODEC_VC1RCV_DEC; - break; - case S5P_MFC_CODEC_H264_ENC: - h2r_args.arg[0] = S5P_FIMV_CODEC_H264_ENC; - break; - case S5P_MFC_CODEC_MPEG4_ENC: - h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_ENC; - break; - case S5P_MFC_CODEC_H263_ENC: - h2r_args.arg[0] = S5P_FIMV_CODEC_H263_ENC; - break; - default: - h2r_args.arg[0] = S5P_FIMV_CODEC_NONE; - } - h2r_args.arg[1] = 0; /* no crc & no pixelcache */ - h2r_args.arg[2] = ctx->ctx.ofs; - h2r_args.arg[3] = ctx->ctx.size; - ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, - &h2r_args); - if (ret) { - mfc_err("Failed to create a new instance\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -static int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int ret; - - if (ctx->state == MFCINST_FREE) { - mfc_err("Instance already returned\n"); - ctx->state = MFCINST_ERROR; - return -EINVAL; - } - /* Closing decoding instance */ - mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); - dev->curr_ctx = ctx->num; - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - h2r_args.arg[0] = ctx->inst_no; - ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, - &h2r_args); - if (ret) { - mfc_err("Failed to return an instance\n"); - ctx->state = MFCINST_ERROR; - return -EINVAL; - } - return 0; -} - -/* Initialize cmd function pointers for MFC v5 */ -static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = { - .cmd_host2risc = s5p_mfc_cmd_host2risc_v5, - .sys_init_cmd = s5p_mfc_sys_init_cmd_v5, - .sleep_cmd = s5p_mfc_sleep_cmd_v5, - .wakeup_cmd = s5p_mfc_wakeup_cmd_v5, - .open_inst_cmd = s5p_mfc_open_inst_cmd_v5, - .close_inst_cmd = s5p_mfc_close_inst_cmd_v5, -}; - -struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) -{ - return &s5p_mfc_cmds_v5; -} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h deleted file mode 100644 index 917854bffe9f..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_CMD_V5_H_ -#define S5P_MFC_CMD_V5_H_ - -#include "s5p_mfc_common.h" - -struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void); - -#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c deleted file mode 100644 index 1f42130cc865..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c +++ /dev/null @@ -1,169 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#include "s5p_mfc_common.h" - -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_intr.h" -#include "s5p_mfc_opr.h" -#include "s5p_mfc_cmd_v6.h" - -static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args) -{ - mfc_debug(2, "Issue the command: %d\n", cmd); - - /* Reset RISC2HOST command */ - mfc_write(dev, 0x0, S5P_FIMV_RISC2HOST_CMD_V6); - - /* Issue the command */ - mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD_V6); - mfc_write(dev, 0x1, S5P_FIMV_HOST2RISC_INT_V6); - - return 0; -} - -static int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; - int ret; - - ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_dev_context_buffer, dev); - if (ret) - return ret; - - mfc_write(dev, dev->ctx_buf.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); - mfc_write(dev, buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE_V6); - return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SYS_INIT_V6, - &h2r_args); -} - -static int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SLEEP_V6, - &h2r_args); -} - -static int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_cmd_args h2r_args; - - memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); - return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_WAKEUP_V6, - &h2r_args); -} - -/* Open a new instance and get its number */ -static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int codec_type; - - mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); - dev->curr_ctx = ctx->num; - switch (ctx->codec_mode) { - case S5P_MFC_CODEC_H264_DEC: - codec_type = S5P_FIMV_CODEC_H264_DEC_V6; - break; - case S5P_MFC_CODEC_H264_MVC_DEC: - codec_type = S5P_FIMV_CODEC_H264_MVC_DEC_V6; - break; - case S5P_MFC_CODEC_VC1_DEC: - codec_type = S5P_FIMV_CODEC_VC1_DEC_V6; - break; - case S5P_MFC_CODEC_MPEG4_DEC: - codec_type = S5P_FIMV_CODEC_MPEG4_DEC_V6; - break; - case S5P_MFC_CODEC_MPEG2_DEC: - codec_type = S5P_FIMV_CODEC_MPEG2_DEC_V6; - break; - case S5P_MFC_CODEC_H263_DEC: - codec_type = S5P_FIMV_CODEC_H263_DEC_V6; - break; - case S5P_MFC_CODEC_VC1RCV_DEC: - codec_type = S5P_FIMV_CODEC_VC1RCV_DEC_V6; - break; - case S5P_MFC_CODEC_VP8_DEC: - codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; - break; - case S5P_MFC_CODEC_HEVC_DEC: - codec_type = S5P_FIMV_CODEC_HEVC_DEC; - break; - case S5P_MFC_CODEC_VP9_DEC: - codec_type = S5P_FIMV_CODEC_VP9_DEC; - break; - case S5P_MFC_CODEC_H264_ENC: - codec_type = S5P_FIMV_CODEC_H264_ENC_V6; - break; - case S5P_MFC_CODEC_H264_MVC_ENC: - codec_type = S5P_FIMV_CODEC_H264_MVC_ENC_V6; - break; - case S5P_MFC_CODEC_MPEG4_ENC: - codec_type = S5P_FIMV_CODEC_MPEG4_ENC_V6; - break; - case S5P_MFC_CODEC_H263_ENC: - codec_type = S5P_FIMV_CODEC_H263_ENC_V6; - break; - case S5P_MFC_CODEC_VP8_ENC: - codec_type = S5P_FIMV_CODEC_VP8_ENC_V7; - break; - case S5P_MFC_CODEC_HEVC_ENC: - codec_type = S5P_FIMV_CODEC_HEVC_ENC; - break; - default: - codec_type = S5P_FIMV_CODEC_NONE_V6; - } - mfc_write(dev, codec_type, S5P_FIMV_CODEC_TYPE_V6); - mfc_write(dev, ctx->ctx.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); - mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); - mfc_write(dev, 0, S5P_FIMV_D_CRC_CTRL_V6); /* no crc */ - - return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6, - &h2r_args); -} - -/* Close instance */ -static int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_cmd_args h2r_args; - int ret = 0; - - dev->curr_ctx = ctx->num; - if (ctx->state != MFCINST_FREE) { - mfc_write(dev, ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); - ret = s5p_mfc_cmd_host2risc_v6(dev, - S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6, - &h2r_args); - } else { - ret = -EINVAL; - } - - return ret; -} - -/* Initialize cmd function pointers for MFC v6 */ -static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { - .cmd_host2risc = s5p_mfc_cmd_host2risc_v6, - .sys_init_cmd = s5p_mfc_sys_init_cmd_v6, - .sleep_cmd = s5p_mfc_sleep_cmd_v6, - .wakeup_cmd = s5p_mfc_wakeup_cmd_v6, - .open_inst_cmd = s5p_mfc_open_inst_cmd_v6, - .close_inst_cmd = s5p_mfc_close_inst_cmd_v6, -}; - -struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) -{ - return &s5p_mfc_cmds_v6; -} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h deleted file mode 100644 index c19884ea2bfc..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_CMD_V6_H_ -#define S5P_MFC_CMD_V6_H_ - -#include "s5p_mfc_common.h" - -struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void); - -#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h deleted file mode 100644 index 5304f42c8c72..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ /dev/null @@ -1,792 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Samsung S5P Multi Format Codec v 5.0 - * - * This file contains definitions of enums and structs used by the codec - * driver. - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * Kamil Debski, - */ - -#ifndef S5P_MFC_COMMON_H_ -#define S5P_MFC_COMMON_H_ - -#include -#include -#include -#include -#include -#include -#include "regs-mfc.h" -#include "regs-mfc-v10.h" - -#define S5P_MFC_NAME "s5p-mfc" - -/* Definitions related to MFC memory */ - -/* Offset base used to differentiate between CAPTURE and OUTPUT -* while mmaping */ -#define DST_QUEUE_OFF_BASE (1 << 30) - -#define BANK_L_CTX 0 -#define BANK_R_CTX 1 -#define BANK_CTX_NUM 2 - -#define MFC_BANK1_ALIGN_ORDER 13 -#define MFC_BANK2_ALIGN_ORDER 13 -#define MFC_BASE_ALIGN_ORDER 17 - -#define MFC_FW_MAX_VERSIONS 2 - -#include - -/* MFC definitions */ -#define MFC_MAX_EXTRA_DPB 5 -#define MFC_MAX_BUFFERS 32 -#define MFC_NUM_CONTEXTS 4 -/* Interrupt timeout */ -#define MFC_INT_TIMEOUT 2000 -/* Busy wait timeout */ -#define MFC_BW_TIMEOUT 500 -/* Watchdog interval */ -#define MFC_WATCHDOG_INTERVAL 1000 -/* After how many executions watchdog should assume lock up */ -#define MFC_WATCHDOG_CNT 10 -#define MFC_NO_INSTANCE_SET -1 -#define MFC_ENC_CAP_PLANE_COUNT 1 -#define MFC_ENC_OUT_PLANE_COUNT 2 -#define STUFF_BYTE 4 -#define MFC_MAX_CTRLS 128 - -#define S5P_MFC_CODEC_NONE -1 -#define S5P_MFC_CODEC_H264_DEC 0 -#define S5P_MFC_CODEC_H264_MVC_DEC 1 -#define S5P_MFC_CODEC_VC1_DEC 2 -#define S5P_MFC_CODEC_MPEG4_DEC 3 -#define S5P_MFC_CODEC_MPEG2_DEC 4 -#define S5P_MFC_CODEC_H263_DEC 5 -#define S5P_MFC_CODEC_VC1RCV_DEC 6 -#define S5P_MFC_CODEC_VP8_DEC 7 -#define S5P_MFC_CODEC_HEVC_DEC 17 -#define S5P_MFC_CODEC_VP9_DEC 18 - -#define S5P_MFC_CODEC_H264_ENC 20 -#define S5P_MFC_CODEC_H264_MVC_ENC 21 -#define S5P_MFC_CODEC_MPEG4_ENC 22 -#define S5P_MFC_CODEC_H263_ENC 23 -#define S5P_MFC_CODEC_VP8_ENC 24 -#define S5P_MFC_CODEC_HEVC_ENC 26 - -#define S5P_MFC_R2H_CMD_EMPTY 0 -#define S5P_MFC_R2H_CMD_SYS_INIT_RET 1 -#define S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET 2 -#define S5P_MFC_R2H_CMD_SEQ_DONE_RET 3 -#define S5P_MFC_R2H_CMD_INIT_BUFFERS_RET 4 -#define S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET 6 -#define S5P_MFC_R2H_CMD_SLEEP_RET 7 -#define S5P_MFC_R2H_CMD_WAKEUP_RET 8 -#define S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET 9 -#define S5P_MFC_R2H_CMD_DPB_FLUSH_RET 10 -#define S5P_MFC_R2H_CMD_NAL_ABORT_RET 11 -#define S5P_MFC_R2H_CMD_FW_STATUS_RET 12 -#define S5P_MFC_R2H_CMD_FRAME_DONE_RET 13 -#define S5P_MFC_R2H_CMD_FIELD_DONE_RET 14 -#define S5P_MFC_R2H_CMD_SLICE_DONE_RET 15 -#define S5P_MFC_R2H_CMD_ENC_BUFFER_FUL_RET 16 -#define S5P_MFC_R2H_CMD_ERR_RET 32 - -#define MFC_MAX_CLOCKS 4 - -#define mfc_read(dev, offset) readl(dev->regs_base + (offset)) -#define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ - (offset)) - -/* - * enum s5p_mfc_fmt_type - type of the pixelformat - */ -enum s5p_mfc_fmt_type { - MFC_FMT_DEC, - MFC_FMT_ENC, - MFC_FMT_RAW, -}; - -/* - * enum s5p_mfc_inst_type - The type of an MFC instance. - */ -enum s5p_mfc_inst_type { - MFCINST_INVALID, - MFCINST_DECODER, - MFCINST_ENCODER, -}; - -/* - * enum s5p_mfc_inst_state - The state of an MFC instance. - */ -enum s5p_mfc_inst_state { - MFCINST_FREE = 0, - MFCINST_INIT = 100, - MFCINST_GOT_INST, - MFCINST_HEAD_PARSED, - MFCINST_HEAD_PRODUCED, - MFCINST_BUFS_SET, - MFCINST_RUNNING, - MFCINST_FINISHING, - MFCINST_FINISHED, - MFCINST_RETURN_INST, - MFCINST_ERROR, - MFCINST_ABORT, - MFCINST_FLUSH, - MFCINST_RES_CHANGE_INIT, - MFCINST_RES_CHANGE_FLUSH, - MFCINST_RES_CHANGE_END, -}; - -/* - * enum s5p_mfc_queue_state - The state of buffer queue. - */ -enum s5p_mfc_queue_state { - QUEUE_FREE, - QUEUE_BUFS_REQUESTED, - QUEUE_BUFS_QUERIED, - QUEUE_BUFS_MMAPED, -}; - -/* - * enum s5p_mfc_decode_arg - type of frame decoding - */ -enum s5p_mfc_decode_arg { - MFC_DEC_FRAME, - MFC_DEC_LAST_FRAME, - MFC_DEC_RES_CHANGE, -}; - -enum s5p_mfc_fw_ver { - MFC_FW_V1, - MFC_FW_V2, -}; - -#define MFC_BUF_FLAG_USED (1 << 0) -#define MFC_BUF_FLAG_EOS (1 << 1) - -struct s5p_mfc_ctx; - -/* - * struct s5p_mfc_buf - MFC buffer - */ -struct s5p_mfc_buf { - struct vb2_v4l2_buffer *b; - struct list_head list; - union { - struct { - size_t luma; - size_t chroma; - } raw; - size_t stream; - } cookie; - int flags; -}; - -/* - * struct s5p_mfc_pm - power management data structure - */ -struct s5p_mfc_pm { - struct clk *clock_gate; - const char * const *clk_names; - struct clk *clocks[MFC_MAX_CLOCKS]; - int num_clocks; - bool use_clock_gating; - - struct device *device; -}; - -struct s5p_mfc_buf_size_v5 { - unsigned int h264_ctx; - unsigned int non_h264_ctx; - unsigned int dsc; - unsigned int shm; -}; - -struct s5p_mfc_buf_size_v6 { - unsigned int dev_ctx; - unsigned int h264_dec_ctx; - unsigned int other_dec_ctx; - unsigned int h264_enc_ctx; - unsigned int hevc_enc_ctx; - unsigned int other_enc_ctx; -}; - -struct s5p_mfc_buf_size { - unsigned int fw; - unsigned int cpb; - void *priv; -}; - -struct s5p_mfc_variant { - unsigned int version; - unsigned int port_num; - u32 version_bit; - struct s5p_mfc_buf_size *buf_size; - char *fw_name[MFC_FW_MAX_VERSIONS]; - const char *clk_names[MFC_MAX_CLOCKS]; - int num_clocks; - bool use_clock_gating; -}; - -/** - * struct s5p_mfc_priv_buf - represents internal used buffer - * @ofs: offset of each buffer, will be used for MFC - * @virt: kernel virtual address, only valid when the - * buffer accessed by driver - * @dma: DMA address, only valid when kernel DMA API used - * @size: size of the buffer - * @ctx: memory context (bank) used for this allocation - */ -struct s5p_mfc_priv_buf { - unsigned long ofs; - void *virt; - dma_addr_t dma; - size_t size; - unsigned int ctx; -}; - -/** - * struct s5p_mfc_dev - The struct containing driver internal parameters. - * - * @v4l2_dev: v4l2_device - * @vfd_dec: video device for decoding - * @vfd_enc: video device for encoding - * @plat_dev: platform device - * @mem_dev: child devices of the memory banks - * @regs_base: base address of the MFC hw registers - * @irq: irq resource - * @dec_ctrl_handler: control framework handler for decoding - * @enc_ctrl_handler: control framework handler for encoding - * @pm: power management control - * @variant: MFC hardware variant information - * @num_inst: counter of active MFC instances - * @irqlock: lock for operations on videobuf2 queues - * @condlock: lock for changing/checking if a context is ready to be - * processed - * @mfc_mutex: lock for video_device - * @int_cond: variable used by the waitqueue - * @int_type: type of last interrupt - * @int_err: error number for last interrupt - * @queue: waitqueue for waiting for completion of device commands - * @fw_buf: the firmware buffer data structure - * @mem_size: size of the firmware operation memory - * @mem_base: base DMA address of the firmware operation memory - * @mem_bitmap: bitmap for managing MFC internal buffer allocations - * @mem_virt: virtual address of the firmware operation memory - * @dma_base: address of the beginning of memory banks - * @hw_lock: used for hardware locking - * @ctx: array of driver contexts - * @curr_ctx: number of the currently running context - * @ctx_work_bits: used to mark which contexts are waiting for hardware - * @watchdog_cnt: counter for the watchdog - * @watchdog_timer: timer for the watchdog - * @watchdog_workqueue: workqueue for the watchdog - * @watchdog_work: worker for the watchdog - * @enter_suspend: flag set when entering suspend - * @ctx_buf: common context memory (MFCv6) - * @warn_start: hardware error code from which warnings start - * @mfc_ops: ops structure holding HW operation function pointers - * @mfc_cmds: cmd structure holding HW commands function pointers - * @mfc_regs: structure holding MFC registers - * @fw_ver: loaded firmware sub-version - * @fw_get_done: flag set when request_firmware() is complete and - * copied into fw_buf - * @risc_on: flag indicates RISC is on or off - * - */ -struct s5p_mfc_dev { - struct v4l2_device v4l2_dev; - struct video_device *vfd_dec; - struct video_device *vfd_enc; - struct platform_device *plat_dev; - struct device *mem_dev[BANK_CTX_NUM]; - void __iomem *regs_base; - int irq; - struct v4l2_ctrl_handler dec_ctrl_handler; - struct v4l2_ctrl_handler enc_ctrl_handler; - struct s5p_mfc_pm pm; - const struct s5p_mfc_variant *variant; - int num_inst; - spinlock_t irqlock; /* lock when operating on context */ - spinlock_t condlock; /* lock when changing/checking if a context is - ready to be processed */ - struct mutex mfc_mutex; /* video_device lock */ - int int_cond; - int int_type; - unsigned int int_err; - wait_queue_head_t queue; - struct s5p_mfc_priv_buf fw_buf; - size_t mem_size; - dma_addr_t mem_base; - unsigned long *mem_bitmap; - void *mem_virt; - dma_addr_t dma_base[BANK_CTX_NUM]; - unsigned long hw_lock; - struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS]; - int curr_ctx; - unsigned long ctx_work_bits; - atomic_t watchdog_cnt; - struct timer_list watchdog_timer; - struct workqueue_struct *watchdog_workqueue; - struct work_struct watchdog_work; - unsigned long enter_suspend; - - struct s5p_mfc_priv_buf ctx_buf; - int warn_start; - struct s5p_mfc_hw_ops *mfc_ops; - struct s5p_mfc_hw_cmds *mfc_cmds; - const struct s5p_mfc_regs *mfc_regs; - enum s5p_mfc_fw_ver fw_ver; - bool fw_get_done; - bool risc_on; /* indicates if RISC is on or off */ -}; - -/* - * struct s5p_mfc_h264_enc_params - encoding parameters for h264 - */ -struct s5p_mfc_h264_enc_params { - enum v4l2_mpeg_video_h264_profile profile; - enum v4l2_mpeg_video_h264_loop_filter_mode loop_filter_mode; - s8 loop_filter_alpha; - s8 loop_filter_beta; - enum v4l2_mpeg_video_h264_entropy_mode entropy_mode; - u8 max_ref_pic; - u8 num_ref_pic_4p; - int _8x8_transform; - int rc_mb_dark; - int rc_mb_smooth; - int rc_mb_static; - int rc_mb_activity; - int vui_sar; - u8 vui_sar_idc; - u16 vui_ext_sar_width; - u16 vui_ext_sar_height; - int open_gop; - u16 open_gop_size; - u8 rc_frame_qp; - u8 rc_min_qp; - u8 rc_max_qp; - u8 rc_p_frame_qp; - u8 rc_b_frame_qp; - enum v4l2_mpeg_video_h264_level level_v4l2; - int level; - u16 cpb_size; - int interlace; - u8 hier_qp; - u8 hier_qp_type; - u8 hier_qp_layer; - u8 hier_qp_layer_qp[7]; - u8 sei_frame_packing; - u8 sei_fp_curr_frame_0; - u8 sei_fp_arrangement_type; - - u8 fmo; - u8 fmo_map_type; - u8 fmo_slice_grp; - u8 fmo_chg_dir; - u32 fmo_chg_rate; - u32 fmo_run_len[4]; - u8 aso; - u32 aso_slice_order[8]; -}; - -/* - * struct s5p_mfc_mpeg4_enc_params - encoding parameters for h263 and mpeg4 - */ -struct s5p_mfc_mpeg4_enc_params { - /* MPEG4 Only */ - enum v4l2_mpeg_video_mpeg4_profile profile; - int quarter_pixel; - /* Common for MPEG4, H263 */ - u16 vop_time_res; - u16 vop_frm_delta; - u8 rc_frame_qp; - u8 rc_min_qp; - u8 rc_max_qp; - u8 rc_p_frame_qp; - u8 rc_b_frame_qp; - enum v4l2_mpeg_video_mpeg4_level level_v4l2; - int level; -}; - -/* - * struct s5p_mfc_vp8_enc_params - encoding parameters for vp8 - */ -struct s5p_mfc_vp8_enc_params { - u8 imd_4x4; - enum v4l2_vp8_num_partitions num_partitions; - enum v4l2_vp8_num_ref_frames num_ref; - u8 filter_level; - u8 filter_sharpness; - u32 golden_frame_ref_period; - enum v4l2_vp8_golden_frame_sel golden_frame_sel; - u8 hier_layer; - u8 hier_layer_qp[3]; - u8 rc_min_qp; - u8 rc_max_qp; - u8 rc_frame_qp; - u8 rc_p_frame_qp; - u8 profile; -}; - -struct s5p_mfc_hevc_enc_params { - enum v4l2_mpeg_video_hevc_profile profile; - int level; - enum v4l2_mpeg_video_h264_level level_v4l2; - u8 tier; - u32 rc_framerate; - u8 rc_min_qp; - u8 rc_max_qp; - u8 rc_lcu_dark; - u8 rc_lcu_smooth; - u8 rc_lcu_static; - u8 rc_lcu_activity; - u8 rc_frame_qp; - u8 rc_p_frame_qp; - u8 rc_b_frame_qp; - u8 max_partition_depth; - u8 num_refs_for_p; - u8 refreshtype; - u16 refreshperiod; - s32 lf_beta_offset_div2; - s32 lf_tc_offset_div2; - u8 loopfilter; - u8 loopfilter_disable; - u8 loopfilter_across; - u8 nal_control_length_filed; - u8 nal_control_user_ref; - u8 nal_control_store_ref; - u8 const_intra_period_enable; - u8 lossless_cu_enable; - u8 wavefront_enable; - u8 enable_ltr; - u8 hier_qp_enable; - enum v4l2_mpeg_video_hevc_hier_coding_type hier_qp_type; - u8 num_hier_layer; - u8 hier_qp_layer[7]; - u32 hier_bit_layer[7]; - u8 sign_data_hiding; - u8 general_pb_enable; - u8 temporal_id_enable; - u8 strong_intra_smooth; - u8 intra_pu_split_disable; - u8 tmv_prediction_disable; - u8 max_num_merge_mv; - u8 eco_mode_enable; - u8 encoding_nostartcode_enable; - u8 size_of_length_field; - u8 prepend_sps_pps_to_idr; -}; - -/* - * struct s5p_mfc_enc_params - general encoding parameters - */ -struct s5p_mfc_enc_params { - u16 width; - u16 height; - u32 mv_h_range; - u32 mv_v_range; - - u16 gop_size; - enum v4l2_mpeg_video_multi_slice_mode slice_mode; - u16 slice_mb; - u32 slice_bit; - u16 intra_refresh_mb; - int pad; - u8 pad_luma; - u8 pad_cb; - u8 pad_cr; - int rc_frame; - int rc_mb; - u32 rc_bitrate; - u16 rc_reaction_coeff; - u16 vbv_size; - u32 vbv_delay; - - enum v4l2_mpeg_video_header_mode seq_hdr_mode; - enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode; - int fixed_target_bit; - - u8 num_b_frame; - u32 rc_framerate_num; - u32 rc_framerate_denom; - - struct { - struct s5p_mfc_h264_enc_params h264; - struct s5p_mfc_mpeg4_enc_params mpeg4; - struct s5p_mfc_vp8_enc_params vp8; - struct s5p_mfc_hevc_enc_params hevc; - } codec; - -}; - -/* - * struct s5p_mfc_codec_ops - codec ops, used by encoding - */ -struct s5p_mfc_codec_ops { - /* initialization routines */ - int (*pre_seq_start) (struct s5p_mfc_ctx *ctx); - int (*post_seq_start) (struct s5p_mfc_ctx *ctx); - /* execution routines */ - int (*pre_frame_start) (struct s5p_mfc_ctx *ctx); - int (*post_frame_start) (struct s5p_mfc_ctx *ctx); -}; - -#define call_cop(c, op, args...) \ - (((c)->c_ops->op) ? \ - ((c)->c_ops->op(args)) : 0) - -/** - * struct s5p_mfc_ctx - This struct contains the instance context - * - * @dev: pointer to the s5p_mfc_dev of the device - * @fh: struct v4l2_fh - * @num: number of the context that this structure describes - * @int_cond: variable used by the waitqueue - * @int_type: type of the last interrupt - * @int_err: error number received from MFC hw in the interrupt - * @queue: waitqueue that can be used to wait for this context to - * finish - * @src_fmt: source pixelformat information - * @dst_fmt: destination pixelformat information - * @vq_src: vb2 queue for source buffers - * @vq_dst: vb2 queue for destination buffers - * @src_queue: driver internal queue for source buffers - * @dst_queue: driver internal queue for destination buffers - * @src_queue_cnt: number of buffers queued on the source internal queue - * @dst_queue_cnt: number of buffers queued on the dest internal queue - * @type: type of the instance - decoder or encoder - * @state: state of the context - * @inst_no: number of hw instance associated with the context - * @img_width: width of the image that is decoded or encoded - * @img_height: height of the image that is decoded or encoded - * @buf_width: width of the buffer for processed image - * @buf_height: height of the buffer for processed image - * @luma_size: size of a luma plane - * @chroma_size: size of a chroma plane - * @mv_size: size of a motion vectors buffer - * @consumed_stream: number of bytes that have been used so far from the - * decoding buffer - * @dpb_flush_flag: flag used to indicate that a DPB buffers are being - * flushed - * @head_processed: flag mentioning whether the header data is processed - * completely or not - * @bank1: handle to memory allocated for temporary buffers from - * memory bank 1 - * @bank2: handle to memory allocated for temporary buffers from - * memory bank 2 - * @capture_state: state of the capture buffers queue - * @output_state: state of the output buffers queue - * @src_bufs: information on allocated source buffers - * @src_bufs_cnt: number of allocated source buffers - * @dst_bufs: information on allocated destination buffers - * @dst_bufs_cnt: number of allocated destination buffers - * @sequence: counter for the sequence number for v4l2 - * @dec_dst_flag: flags for buffers queued in the hardware - * @dec_src_buf_size: size of the buffer for source buffers in decoding - * @codec_mode: number of codec mode used by MFC hw - * @slice_interface: slice interface flag - * @loop_filter_mpeg4: loop filter for MPEG4 flag - * @display_delay: value of the display delay for H264 - * @display_delay_enable: display delay for H264 enable flag - * @after_packed_pb: flag used to track buffer when stream is in - * Packed PB format - * @sei_fp_parse: enable/disable parsing of frame packing SEI information - * @pb_count: count of the DPB buffers required by MFC hw - * @total_dpb_count: count of DPB buffers with additional buffers - * requested by the application - * @ctx: context buffer information - * @dsc: descriptor buffer information - * @shm: shared memory buffer information - * @mv_count: number of MV buffers allocated for decoding - * @enc_params: encoding parameters for MFC - * @enc_dst_buf_size: size of the buffers for encoder output - * @luma_dpb_size: dpb buffer size for luma - * @chroma_dpb_size: dpb buffer size for chroma - * @me_buffer_size: size of the motion estimation buffer - * @tmv_buffer_size: size of temporal predictor motion vector buffer - * @frame_type: used to force the type of the next encoded frame - * @ref_queue: list of the reference buffers for encoding - * @force_frame_type: encoder's frame type forcing control - * @ref_queue_cnt: number of the buffers in the reference list - * @slice_size: slice size - * @slice_mode: mode of dividing frames into slices - * @c_ops: ops for encoding - * @ctrls: array of controls, used when adding controls to the - * v4l2 control framework - * @ctrl_handler: handler for v4l2 framework - * @scratch_buf_size: scratch buffer size - */ -struct s5p_mfc_ctx { - struct s5p_mfc_dev *dev; - struct v4l2_fh fh; - - int num; - - int int_cond; - int int_type; - unsigned int int_err; - wait_queue_head_t queue; - - struct s5p_mfc_fmt *src_fmt; - struct s5p_mfc_fmt *dst_fmt; - - struct vb2_queue vq_src; - struct vb2_queue vq_dst; - - struct list_head src_queue; - struct list_head dst_queue; - - unsigned int src_queue_cnt; - unsigned int dst_queue_cnt; - - enum s5p_mfc_inst_type type; - enum s5p_mfc_inst_state state; - int inst_no; - - /* Image parameters */ - int img_width; - int img_height; - int buf_width; - int buf_height; - - int luma_size; - int chroma_size; - int mv_size; - - unsigned long consumed_stream; - - unsigned int dpb_flush_flag; - unsigned int head_processed; - - struct s5p_mfc_priv_buf bank1; - struct s5p_mfc_priv_buf bank2; - - enum s5p_mfc_queue_state capture_state; - enum s5p_mfc_queue_state output_state; - - struct s5p_mfc_buf src_bufs[MFC_MAX_BUFFERS]; - int src_bufs_cnt; - struct s5p_mfc_buf dst_bufs[MFC_MAX_BUFFERS]; - int dst_bufs_cnt; - - unsigned int sequence; - unsigned long dec_dst_flag; - size_t dec_src_buf_size; - - /* Control values */ - int codec_mode; - int slice_interface; - int loop_filter_mpeg4; - int display_delay; - int display_delay_enable; - int after_packed_pb; - int sei_fp_parse; - - int pb_count; - int total_dpb_count; - int mv_count; - /* Buffers */ - struct s5p_mfc_priv_buf ctx; - struct s5p_mfc_priv_buf dsc; - struct s5p_mfc_priv_buf shm; - - struct s5p_mfc_enc_params enc_params; - - size_t enc_dst_buf_size; - size_t luma_dpb_size; - size_t chroma_dpb_size; - size_t me_buffer_size; - size_t tmv_buffer_size; - - enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type; - - struct list_head ref_queue; - unsigned int ref_queue_cnt; - - enum v4l2_mpeg_video_multi_slice_mode slice_mode; - union { - unsigned int mb; - unsigned int bits; - } slice_size; - - const struct s5p_mfc_codec_ops *c_ops; - - struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; - struct v4l2_ctrl_handler ctrl_handler; - size_t scratch_buf_size; -}; - -/* - * struct s5p_mfc_fmt - structure used to store information about pixelformats - * used by the MFC - */ -struct s5p_mfc_fmt { - u32 fourcc; - u32 codec_mode; - enum s5p_mfc_fmt_type type; - u32 num_planes; - u32 versions; - u32 flags; -}; - -/* - * struct mfc_control - structure used to store information about MFC controls - * it is used to initialize the control framework. - */ -struct mfc_control { - __u32 id; - enum v4l2_ctrl_type type; - __u8 name[32]; /* Whatever */ - __s32 minimum; /* Note signedness */ - __s32 maximum; - __s32 step; - __u32 menu_skip_mask; - __s32 default_value; - __u32 flags; - __u32 reserved[2]; - __u8 is_volatile; -}; - -/* Macro for making hardware specific calls */ -#define s5p_mfc_hw_call(f, op, args...) \ - ((f && f->op) ? f->op(args) : (typeof(f->op(args)))(-ENODEV)) - -#define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) -#define ctrl_to_ctx(__ctrl) \ - container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler) - -void clear_work_bit(struct s5p_mfc_ctx *ctx); -void set_work_bit(struct s5p_mfc_ctx *ctx); -void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx); -void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx); -int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev); -void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); - -#define HAS_PORTNUM(dev) (dev ? (dev->variant ? \ - (dev->variant->port_num ? 1 : 0) : 0) : 0) -#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0) -#define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0) -#define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0) -#define IS_MFCV8_PLUS(dev) (dev->variant->version >= 0x80 ? 1 : 0) -#define IS_MFCV10(dev) (dev->variant->version >= 0xA0 ? 1 : 0) -#define FW_HAS_E_MIN_SCRATCH_BUF(dev) (IS_MFCV10(dev)) - -#define MFC_V5_BIT BIT(0) -#define MFC_V6_BIT BIT(1) -#define MFC_V7_BIT BIT(2) -#define MFC_V8_BIT BIT(3) -#define MFC_V10_BIT BIT(5) - -#define MFC_V5PLUS_BITS (MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | \ - MFC_V8_BIT | MFC_V10_BIT) -#define MFC_V6PLUS_BITS (MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT | \ - MFC_V10_BIT) -#define MFC_V7PLUS_BITS (MFC_V7_BIT | MFC_V8_BIT | MFC_V10_BIT) - -#endif /* S5P_MFC_COMMON_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c deleted file mode 100644 index da138c314963..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ /dev/null @@ -1,482 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#include -#include -#include -#include -#include -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_common.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_intr.h" -#include "s5p_mfc_opr.h" -#include "s5p_mfc_pm.h" -#include "s5p_mfc_ctrl.h" - -/* Allocate memory for firmware */ -int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_priv_buf *fw_buf = &dev->fw_buf; - int err; - - fw_buf->size = dev->variant->buf_size->fw; - - if (fw_buf->virt) { - mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); - return -ENOMEM; - } - - err = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &dev->fw_buf); - if (err) { - mfc_err("Allocating bitprocessor buffer failed\n"); - return err; - } - - return 0; -} - -/* Load firmware */ -int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) -{ - struct firmware *fw_blob; - int i, err = -EINVAL; - - /* Firmware has to be present as a separate file or compiled - * into kernel. */ - mfc_debug_enter(); - - if (dev->fw_get_done) - return 0; - - for (i = MFC_FW_MAX_VERSIONS - 1; i >= 0; i--) { - if (!dev->variant->fw_name[i]) - continue; - err = request_firmware((const struct firmware **)&fw_blob, - dev->variant->fw_name[i], &dev->plat_dev->dev); - if (!err) { - dev->fw_ver = (enum s5p_mfc_fw_ver) i; - break; - } - } - - if (err != 0) { - mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); - return -EINVAL; - } - if (fw_blob->size > dev->fw_buf.size) { - mfc_err("MFC firmware is too big to be loaded\n"); - release_firmware(fw_blob); - return -ENOMEM; - } - memcpy(dev->fw_buf.virt, fw_blob->data, fw_blob->size); - wmb(); - dev->fw_get_done = true; - release_firmware(fw_blob); - mfc_debug_leave(); - return 0; -} - -/* Release firmware memory */ -int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) -{ - /* Before calling this function one has to make sure - * that MFC is no longer processing */ - s5p_mfc_release_priv_buf(dev, &dev->fw_buf); - dev->fw_get_done = false; - return 0; -} - -static int s5p_mfc_bus_reset(struct s5p_mfc_dev *dev) -{ - unsigned int status; - unsigned long timeout; - - /* Reset */ - mfc_write(dev, 0x1, S5P_FIMV_MFC_BUS_RESET_CTRL); - timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); - /* Check bus status */ - do { - if (time_after(jiffies, timeout)) { - mfc_err("Timeout while resetting MFC.\n"); - return -EIO; - } - status = mfc_read(dev, S5P_FIMV_MFC_BUS_RESET_CTRL); - } while ((status & 0x2) == 0); - return 0; -} - -/* Reset the device */ -int s5p_mfc_reset(struct s5p_mfc_dev *dev) -{ - unsigned int mc_status; - unsigned long timeout; - int i; - - mfc_debug_enter(); - - if (IS_MFCV6_PLUS(dev)) { - /* Zero Initialization of MFC registers */ - mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); - mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); - mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6); - - for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) - mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); - - /* check bus reset control before reset */ - if (dev->risc_on) - if (s5p_mfc_bus_reset(dev)) - return -EIO; - /* Reset - * set RISC_ON to 0 during power_on & wake_up. - * V6 needs RISC_ON set to 0 during reset also. - */ - if ((!dev->risc_on) || (!IS_MFCV7_PLUS(dev))) - mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); - - mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); - mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); - } else { - /* Stop procedure */ - /* reset RISC */ - mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); - /* All reset except for MC */ - mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); - mdelay(10); - - timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); - /* Check MC status */ - do { - if (time_after(jiffies, timeout)) { - mfc_err("Timeout while resetting MFC\n"); - return -EIO; - } - - mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); - - } while (mc_status & 0x3); - - mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); - mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); - } - - mfc_debug_leave(); - return 0; -} - -static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) -{ - if (IS_MFCV6_PLUS(dev)) { - mfc_write(dev, dev->dma_base[BANK_L_CTX], - S5P_FIMV_RISC_BASE_ADDRESS_V6); - mfc_debug(2, "Base Address : %pad\n", - &dev->dma_base[BANK_L_CTX]); - } else { - mfc_write(dev, dev->dma_base[BANK_L_CTX], - S5P_FIMV_MC_DRAMBASE_ADR_A); - mfc_write(dev, dev->dma_base[BANK_R_CTX], - S5P_FIMV_MC_DRAMBASE_ADR_B); - mfc_debug(2, "Bank1: %pad, Bank2: %pad\n", - &dev->dma_base[BANK_L_CTX], - &dev->dma_base[BANK_R_CTX]); - } -} - -static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) -{ - if (IS_MFCV6_PLUS(dev)) { - /* Zero initialization should be done before RESET. - * Nothing to do here. */ - } else { - mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); - mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); - mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); - mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); - } -} - -/* Initialize hardware */ -int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) -{ - unsigned int ver; - int ret; - - mfc_debug_enter(); - if (!dev->fw_buf.virt) { - mfc_err("Firmware memory is not allocated.\n"); - return -EINVAL; - } - - /* 0. MFC reset */ - mfc_debug(2, "MFC reset..\n"); - s5p_mfc_clock_on(); - dev->risc_on = 0; - ret = s5p_mfc_reset(dev); - if (ret) { - mfc_err("Failed to reset MFC - timeout\n"); - return ret; - } - mfc_debug(2, "Done MFC reset..\n"); - /* 1. Set DRAM base Addr */ - s5p_mfc_init_memctrl(dev); - /* 2. Initialize registers of channel I/F */ - s5p_mfc_clear_cmds(dev); - /* 3. Release reset signal to the RISC */ - s5p_mfc_clean_dev_int_flags(dev); - if (IS_MFCV6_PLUS(dev)) { - dev->risc_on = 1; - mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); - } - else - mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); - - if (IS_MFCV10(dev)) - mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10); - - mfc_debug(2, "Will now wait for completion of firmware transfer\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { - mfc_err("Failed to load firmware\n"); - s5p_mfc_reset(dev); - s5p_mfc_clock_off(); - return -EIO; - } - s5p_mfc_clean_dev_int_flags(dev); - /* 4. Initialize firmware */ - ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev); - if (ret) { - mfc_err("Failed to send command to MFC - timeout\n"); - s5p_mfc_reset(dev); - s5p_mfc_clock_off(); - return ret; - } - mfc_debug(2, "Ok, now will wait for completion of hardware init\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { - mfc_err("Failed to init hardware\n"); - s5p_mfc_reset(dev); - s5p_mfc_clock_off(); - return -EIO; - } - dev->int_cond = 0; - if (dev->int_err != 0 || dev->int_type != - S5P_MFC_R2H_CMD_SYS_INIT_RET) { - /* Failure. */ - mfc_err("Failed to init firmware - error: %d int: %d\n", - dev->int_err, dev->int_type); - s5p_mfc_reset(dev); - s5p_mfc_clock_off(); - return -EIO; - } - if (IS_MFCV6_PLUS(dev)) - ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6); - else - ver = mfc_read(dev, S5P_FIMV_FW_VERSION); - - mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", - (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); - s5p_mfc_clock_off(); - mfc_debug_leave(); - return 0; -} - - -/* Deinitialize hardware */ -void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) -{ - s5p_mfc_clock_on(); - - s5p_mfc_reset(dev); - s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev); - - s5p_mfc_clock_off(); -} - -int s5p_mfc_sleep(struct s5p_mfc_dev *dev) -{ - int ret; - - mfc_debug_enter(); - s5p_mfc_clock_on(); - s5p_mfc_clean_dev_int_flags(dev); - ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev); - if (ret) { - mfc_err("Failed to send command to MFC - timeout\n"); - return ret; - } - if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) { - mfc_err("Failed to sleep\n"); - return -EIO; - } - s5p_mfc_clock_off(); - dev->int_cond = 0; - if (dev->int_err != 0 || dev->int_type != - S5P_MFC_R2H_CMD_SLEEP_RET) { - /* Failure. */ - mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err, - dev->int_type); - return -EIO; - } - mfc_debug_leave(); - return ret; -} - -static int s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev *dev) -{ - int ret; - - /* Release reset signal to the RISC */ - dev->risc_on = 1; - mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); - - if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { - mfc_err("Failed to reset MFCV8\n"); - return -EIO; - } - mfc_debug(2, "Write command to wakeup MFCV8\n"); - ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); - if (ret) { - mfc_err("Failed to send command to MFCV8 - timeout\n"); - return ret; - } - - if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { - mfc_err("Failed to wakeup MFC\n"); - return -EIO; - } - return ret; -} - -static int s5p_mfc_wait_wakeup(struct s5p_mfc_dev *dev) -{ - int ret; - - /* Send MFC wakeup command */ - ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); - if (ret) { - mfc_err("Failed to send command to MFC - timeout\n"); - return ret; - } - - /* Release reset signal to the RISC */ - if (IS_MFCV6_PLUS(dev)) { - dev->risc_on = 1; - mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); - } else { - mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); - } - - if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { - mfc_err("Failed to wakeup MFC\n"); - return -EIO; - } - return ret; -} - -int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) -{ - int ret; - - mfc_debug_enter(); - /* 0. MFC reset */ - mfc_debug(2, "MFC reset..\n"); - s5p_mfc_clock_on(); - dev->risc_on = 0; - ret = s5p_mfc_reset(dev); - if (ret) { - mfc_err("Failed to reset MFC - timeout\n"); - s5p_mfc_clock_off(); - return ret; - } - mfc_debug(2, "Done MFC reset..\n"); - /* 1. Set DRAM base Addr */ - s5p_mfc_init_memctrl(dev); - /* 2. Initialize registers of channel I/F */ - s5p_mfc_clear_cmds(dev); - s5p_mfc_clean_dev_int_flags(dev); - /* 3. Send MFC wakeup command and wait for completion*/ - if (IS_MFCV8_PLUS(dev)) - ret = s5p_mfc_v8_wait_wakeup(dev); - else - ret = s5p_mfc_wait_wakeup(dev); - - s5p_mfc_clock_off(); - if (ret) - return ret; - - dev->int_cond = 0; - if (dev->int_err != 0 || dev->int_type != - S5P_MFC_R2H_CMD_WAKEUP_RET) { - /* Failure. */ - mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err, - dev->int_type); - return -EIO; - } - mfc_debug_leave(); - return 0; -} - -int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) -{ - int ret = 0; - - ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx); - if (ret) { - mfc_err("Failed allocating instance buffer\n"); - goto err; - } - - if (ctx->type == MFCINST_DECODER) { - ret = s5p_mfc_hw_call(dev->mfc_ops, - alloc_dec_temp_buffers, ctx); - if (ret) { - mfc_err("Failed allocating temporary buffers\n"); - goto err_free_inst_buf; - } - } - - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - if (s5p_mfc_wait_for_done_ctx(ctx, - S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) { - /* Error or timeout */ - mfc_err("Error getting instance from hardware\n"); - ret = -EIO; - goto err_free_desc_buf; - } - - mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); - return ret; - -err_free_desc_buf: - if (ctx->type == MFCINST_DECODER) - s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); -err_free_inst_buf: - s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); -err: - return ret; -} - -void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) -{ - ctx->state = MFCINST_RETURN_INST; - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - /* Wait until instance is returned or timeout occurred */ - if (s5p_mfc_wait_for_done_ctx(ctx, - S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)) - mfc_err("Err returning instance\n"); - - /* Free resources */ - s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); - s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); - if (ctx->type == MFCINST_DECODER) - s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); - - ctx->inst_no = MFC_NO_INSTANCE_SET; - ctx->state = MFCINST_FREE; -} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h deleted file mode 100644 index 7f32ef8a6b61..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_CTRL_H -#define S5P_MFC_CTRL_H - -#include "s5p_mfc_common.h" - -int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev); -int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev); -int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev); - -int s5p_mfc_init_hw(struct s5p_mfc_dev *dev); -void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev); - -int s5p_mfc_sleep(struct s5p_mfc_dev *dev); -int s5p_mfc_wakeup(struct s5p_mfc_dev *dev); - -int s5p_mfc_reset(struct s5p_mfc_dev *dev); - -int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx); -void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx); - -#endif /* S5P_MFC_CTRL_H */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h deleted file mode 100644 index 752bbe4fe48e..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/platform/s5p-mfc/s5p_mfc_debug.h - * - * Header file for Samsung MFC (Multi Function Codec - FIMV) driver - * This file contains debug macros - * - * Kamil Debski, Copyright (c) 2011 Samsung Electronics - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_DEBUG_H_ -#define S5P_MFC_DEBUG_H_ - -#define DEBUG - -#ifdef DEBUG -extern int mfc_debug_level; - -#define mfc_debug(level, fmt, args...) \ - do { \ - if (mfc_debug_level >= level) \ - printk(KERN_DEBUG "%s:%d: " fmt, \ - __func__, __LINE__, ##args); \ - } while (0) -#else -#define mfc_debug(level, fmt, args...) -#endif - -#define mfc_debug_enter() mfc_debug(5, "enter\n") -#define mfc_debug_leave() mfc_debug(5, "leave\n") - -#define mfc_err(fmt, args...) \ - do { \ - printk(KERN_ERR "%s:%d: " fmt, \ - __func__, __LINE__, ##args); \ - } while (0) - -#define mfc_err_limited(fmt, args...) \ - do { \ - printk_ratelimited(KERN_ERR "%s:%d: " fmt, \ - __func__, __LINE__, ##args); \ - } while (0) - -#define mfc_info(fmt, args...) \ - do { \ - printk(KERN_INFO "%s:%d: " fmt, \ - __func__, __LINE__, ##args); \ - } while (0) - -#endif /* S5P_MFC_DEBUG_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c deleted file mode 100644 index c0798811755c..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ /dev/null @@ -1,1218 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * Kamil Debski, - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "s5p_mfc_common.h" -#include "s5p_mfc_ctrl.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_dec.h" -#include "s5p_mfc_intr.h" -#include "s5p_mfc_opr.h" -#include "s5p_mfc_pm.h" - -static struct s5p_mfc_fmt formats[] = { - { - .fourcc = V4L2_PIX_FMT_NV12MT_16X16, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT, - }, - { - .fourcc = V4L2_PIX_FMT_NV12MT, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, - .versions = MFC_V5_BIT, - }, - { - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, - .versions = MFC_V6PLUS_BITS, - }, - { - .fourcc = V4L2_PIX_FMT_NV21M, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, - .versions = MFC_V6PLUS_BITS, - }, - { - .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_MFC_CODEC_H264_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | - V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, - }, - { - .fourcc = V4L2_PIX_FMT_H264_MVC, - .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V6PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | - V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, - }, - { - .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_MFC_CODEC_H263_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_MPEG1, - .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | - V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, - }, - { - .fourcc = V4L2_PIX_FMT_MPEG2, - .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | - V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, - }, - { - .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | - V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, - }, - { - .fourcc = V4L2_PIX_FMT_XVID, - .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, - .codec_mode = S5P_MFC_CODEC_VC1_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, - .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .codec_mode = S5P_MFC_CODEC_VP8_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V6PLUS_BITS, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, - { - .fourcc = V4L2_PIX_FMT_HEVC, - .codec_mode = S5P_FIMV_CODEC_HEVC_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V10_BIT, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | - V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, - }, - { - .fourcc = V4L2_PIX_FMT_VP9, - .codec_mode = S5P_FIMV_CODEC_VP9_DEC, - .type = MFC_FMT_DEC, - .num_planes = 1, - .versions = MFC_V10_BIT, - .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, - }, -}; - -#define NUM_FORMATS ARRAY_SIZE(formats) - -/* Find selected format description */ -static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) -{ - unsigned int i; - - for (i = 0; i < NUM_FORMATS; i++) { - if (formats[i].fourcc == f->fmt.pix_mp.pixelformat && - formats[i].type == t) - return &formats[i]; - } - return NULL; -} - -static struct mfc_control controls[] = { - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "H264 Display Delay", - .minimum = 0, - .maximum = 16383, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 16383, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "H264 Display Delay Enable", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mpeg4 Loop Filter Enable", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Slice Interface Enable", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Minimum number of cap bufs", - .minimum = 1, - .maximum = 32, - .step = 1, - .default_value = 1, - .is_volatile = 1, - }, -}; - -#define NUM_CTRLS ARRAY_SIZE(controls) - -/* Check whether a context should be run on hardware */ -static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) -{ - /* Context is to parse header */ - if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST) - return 1; - /* Context is to decode a frame */ - if (ctx->src_queue_cnt >= 1 && - ctx->state == MFCINST_RUNNING && - ctx->dst_queue_cnt >= ctx->pb_count) - return 1; - /* Context is to return last frame */ - if (ctx->state == MFCINST_FINISHING && - ctx->dst_queue_cnt >= ctx->pb_count) - return 1; - /* Context is to set buffers */ - if (ctx->src_queue_cnt >= 1 && - ctx->state == MFCINST_HEAD_PARSED && - ctx->capture_state == QUEUE_BUFS_MMAPED) - return 1; - /* Resolution change */ - if ((ctx->state == MFCINST_RES_CHANGE_INIT || - ctx->state == MFCINST_RES_CHANGE_FLUSH) && - ctx->dst_queue_cnt >= ctx->pb_count) - return 1; - if (ctx->state == MFCINST_RES_CHANGE_END && - ctx->src_queue_cnt >= 1) - return 1; - mfc_debug(2, "ctx is not ready\n"); - return 0; -} - -static const struct s5p_mfc_codec_ops decoder_codec_ops = { - .pre_seq_start = NULL, - .post_seq_start = NULL, - .pre_frame_start = NULL, - .post_frame_start = NULL, -}; - -/* Query capabilities of the device */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - - strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver)); - strscpy(cap->card, dev->vfd_dec->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&dev->plat_dev->dev)); - return 0; -} - -/* Enumerate format */ -static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, - bool out) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - int i, j = 0; - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (out && formats[i].type != MFC_FMT_DEC) - continue; - else if (!out && formats[i].type != MFC_FMT_RAW) - continue; - else if ((dev->variant->version_bit & formats[i].versions) == 0) - continue; - - if (j == f->index) - break; - ++j; - } - if (i == ARRAY_SIZE(formats)) - return -EINVAL; - f->pixelformat = formats[i].fourcc; - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, f, false); -} - -static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, f, true); -} - -/* Get format */ -static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - struct v4l2_pix_format_mplane *pix_mp; - - mfc_debug_enter(); - pix_mp = &f->fmt.pix_mp; - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && - (ctx->state == MFCINST_GOT_INST || ctx->state == - MFCINST_RES_CHANGE_END)) { - /* If the MFC is parsing the header, - * so wait until it is finished */ - s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET, - 0); - } - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && - ctx->state >= MFCINST_HEAD_PARSED && - ctx->state < MFCINST_ABORT) { - /* This is run on CAPTURE (decode output) */ - /* Width and height are set to the dimensions - of the movie, the buffer is bigger and - further processing stages should crop to this - rectangle. */ - pix_mp->width = ctx->buf_width; - pix_mp->height = ctx->buf_height; - pix_mp->field = V4L2_FIELD_NONE; - pix_mp->num_planes = 2; - /* Set pixelformat to the format in which MFC - outputs the decoded frame */ - pix_mp->pixelformat = ctx->dst_fmt->fourcc; - pix_mp->plane_fmt[0].bytesperline = ctx->buf_width; - pix_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_mp->plane_fmt[1].bytesperline = ctx->buf_width; - pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - /* This is run on OUTPUT - The buffer contains compressed image - so width and height have no meaning */ - pix_mp->width = 0; - pix_mp->height = 0; - pix_mp->field = V4L2_FIELD_NONE; - pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size; - pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size; - pix_mp->pixelformat = ctx->src_fmt->fourcc; - pix_mp->num_planes = ctx->src_fmt->num_planes; - } else { - mfc_err("Format could not be read\n"); - mfc_debug(2, "%s-- with error\n", __func__); - return -EINVAL; - } - mfc_debug_leave(); - return 0; -} - -/* Try format */ -static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_fmt *fmt; - - mfc_debug(2, "Type is %d\n", f->type); - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - fmt = find_format(f, MFC_FMT_DEC); - if (!fmt) { - mfc_err("Unsupported format for source.\n"); - return -EINVAL; - } - if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) { - mfc_err("Unknown codec\n"); - return -EINVAL; - } - if ((dev->variant->version_bit & fmt->versions) == 0) { - mfc_err("Unsupported format by this MFC version.\n"); - return -EINVAL; - } - } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - fmt = find_format(f, MFC_FMT_RAW); - if (!fmt) { - mfc_err("Unsupported format for destination.\n"); - return -EINVAL; - } - if ((dev->variant->version_bit & fmt->versions) == 0) { - mfc_err("Unsupported format by this MFC version.\n"); - return -EINVAL; - } - } - - return 0; -} - -/* Set format */ -static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - int ret = 0; - struct v4l2_pix_format_mplane *pix_mp; - struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; - - mfc_debug_enter(); - ret = vidioc_try_fmt(file, priv, f); - pix_mp = &f->fmt.pix_mp; - if (ret) - return ret; - if (vb2_is_streaming(&ctx->vq_src) || vb2_is_streaming(&ctx->vq_dst)) { - v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); - ret = -EBUSY; - goto out; - } - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - /* dst_fmt is validated by call to vidioc_try_fmt */ - ctx->dst_fmt = find_format(f, MFC_FMT_RAW); - ret = 0; - goto out; - } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - /* src_fmt is validated by call to vidioc_try_fmt */ - ctx->src_fmt = find_format(f, MFC_FMT_DEC); - ctx->codec_mode = ctx->src_fmt->codec_mode; - mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); - pix_mp->height = 0; - pix_mp->width = 0; - if (pix_mp->plane_fmt[0].sizeimage == 0) - pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = - DEF_CPB_SIZE; - else if (pix_mp->plane_fmt[0].sizeimage > buf_size->cpb) - ctx->dec_src_buf_size = buf_size->cpb; - else - ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; - pix_mp->plane_fmt[0].bytesperline = 0; - ctx->state = MFCINST_INIT; - ret = 0; - goto out; - } else { - mfc_err("Wrong type error for S_FMT : %d", f->type); - ret = -EINVAL; - goto out; - } - -out: - mfc_debug_leave(); - return ret; -} - -static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, - struct v4l2_requestbuffers *reqbufs) -{ - int ret = 0; - - s5p_mfc_clock_on(); - - if (reqbufs->count == 0) { - mfc_debug(2, "Freeing buffers\n"); - ret = vb2_reqbufs(&ctx->vq_src, reqbufs); - if (ret) - goto out; - ctx->src_bufs_cnt = 0; - ctx->output_state = QUEUE_FREE; - } else if (ctx->output_state == QUEUE_FREE) { - /* Can only request buffers when we have a valid format set. */ - WARN_ON(ctx->src_bufs_cnt != 0); - if (ctx->state != MFCINST_INIT) { - mfc_err("Reqbufs called in an invalid state\n"); - ret = -EINVAL; - goto out; - } - - mfc_debug(2, "Allocating %d buffers for OUTPUT queue\n", - reqbufs->count); - ret = vb2_reqbufs(&ctx->vq_src, reqbufs); - if (ret) - goto out; - - ret = s5p_mfc_open_mfc_inst(dev, ctx); - if (ret) { - reqbufs->count = 0; - vb2_reqbufs(&ctx->vq_src, reqbufs); - goto out; - } - - ctx->output_state = QUEUE_BUFS_REQUESTED; - } else { - mfc_err("Buffers have already been requested\n"); - ret = -EINVAL; - } -out: - s5p_mfc_clock_off(); - if (ret) - mfc_err("Failed allocating buffers for OUTPUT queue\n"); - return ret; -} - -static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, - struct v4l2_requestbuffers *reqbufs) -{ - int ret = 0; - - s5p_mfc_clock_on(); - - if (reqbufs->count == 0) { - mfc_debug(2, "Freeing buffers\n"); - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - if (ret) - goto out; - s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); - ctx->dst_bufs_cnt = 0; - } else if (ctx->capture_state == QUEUE_FREE) { - WARN_ON(ctx->dst_bufs_cnt != 0); - mfc_debug(2, "Allocating %d buffers for CAPTURE queue\n", - reqbufs->count); - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - if (ret) - goto out; - - ctx->capture_state = QUEUE_BUFS_REQUESTED; - ctx->total_dpb_count = reqbufs->count; - - ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx); - if (ret) { - mfc_err("Failed to allocate decoding buffers\n"); - reqbufs->count = 0; - vb2_reqbufs(&ctx->vq_dst, reqbufs); - ret = -ENOMEM; - ctx->capture_state = QUEUE_FREE; - goto out; - } - - WARN_ON(ctx->dst_bufs_cnt != ctx->total_dpb_count); - ctx->capture_state = QUEUE_BUFS_MMAPED; - - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, - 0); - } else { - mfc_err("Buffers have already been requested\n"); - ret = -EINVAL; - } -out: - s5p_mfc_clock_off(); - if (ret) - mfc_err("Failed allocating buffers for CAPTURE queue\n"); - return ret; -} - -/* Request buffers */ -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (reqbufs->memory != V4L2_MEMORY_MMAP) { - mfc_debug(2, "Only V4L2_MEMORY_MMAP is supported\n"); - return -EINVAL; - } - - if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - return reqbufs_output(dev, ctx, reqbufs); - } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - return reqbufs_capture(dev, ctx, reqbufs); - } else { - mfc_err("Invalid type requested\n"); - return -EINVAL; - } -} - -/* Query buffer */ -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - int ret; - int i; - - if (buf->memory != V4L2_MEMORY_MMAP) { - mfc_err("Only mmapped buffers can be used\n"); - return -EINVAL; - } - mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type); - if (ctx->state == MFCINST_GOT_INST && - buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = vb2_querybuf(&ctx->vq_src, buf); - } else if (ctx->state == MFCINST_RUNNING && - buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - ret = vb2_querybuf(&ctx->vq_dst, buf); - for (i = 0; i < buf->length; i++) - buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE; - } else { - mfc_err("vidioc_querybuf called in an inappropriate state\n"); - ret = -EINVAL; - } - mfc_debug_leave(); - return ret; -} - -/* Queue a buffer */ -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (ctx->state == MFCINST_ERROR) { - mfc_err("Call on QBUF after unrecoverable error\n"); - return -EIO; - } - if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return vb2_qbuf(&ctx->vq_src, NULL, buf); - else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return vb2_qbuf(&ctx->vq_dst, NULL, buf); - return -EINVAL; -} - -/* Dequeue a buffer */ -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - const struct v4l2_event ev = { - .type = V4L2_EVENT_EOS - }; - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - int ret; - - if (ctx->state == MFCINST_ERROR) { - mfc_err_limited("Call on DQBUF after unrecoverable error\n"); - return -EIO; - } - - switch (buf->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); - if (ret) - return ret; - - if (ctx->state == MFCINST_FINISHED && - (ctx->dst_bufs[buf->index].flags & MFC_BUF_FLAG_EOS)) - v4l2_event_queue_fh(&ctx->fh, &ev); - return 0; - default: - return -EINVAL; - } -} - -/* Export DMA buffer */ -static int vidioc_expbuf(struct file *file, void *priv, - struct v4l2_exportbuffer *eb) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return vb2_expbuf(&ctx->vq_src, eb); - if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return vb2_expbuf(&ctx->vq_dst, eb); - return -EINVAL; -} - -/* Stream on */ -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - int ret = -EINVAL; - - mfc_debug_enter(); - if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - ret = vb2_streamon(&ctx->vq_src, type); - else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - ret = vb2_streamon(&ctx->vq_dst, type); - mfc_debug_leave(); - return ret; -} - -/* Stream off, which equals to a pause */ -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return vb2_streamoff(&ctx->vq_src, type); - else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return vb2_streamoff(&ctx->vq_dst, type); - return -EINVAL; -} - -/* Set controls - v4l2 control framework */ -static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); - - switch (ctrl->id) { - case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY: - case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: - ctx->display_delay = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE: - case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: - ctx->display_delay_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: - ctx->loop_filter_mpeg4 = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: - ctx->slice_interface = ctrl->val; - break; - default: - mfc_err("Invalid control 0x%08x\n", ctrl->id); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) -{ - struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); - struct s5p_mfc_dev *dev = ctx->dev; - - switch (ctrl->id) { - case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: - if (ctx->state >= MFCINST_HEAD_PARSED && - ctx->state < MFCINST_ABORT) { - ctrl->val = ctx->pb_count; - break; - } else if (ctx->state != MFCINST_INIT && - ctx->state != MFCINST_RES_CHANGE_END) { - v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); - return -EINVAL; - } - /* Should wait for the header to be parsed */ - s5p_mfc_wait_for_done_ctx(ctx, - S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); - if (ctx->state >= MFCINST_HEAD_PARSED && - ctx->state < MFCINST_ABORT) { - ctrl->val = ctx->pb_count; - } else { - v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); - return -EINVAL; - } - break; - } - return 0; -} - - -static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = { - .s_ctrl = s5p_mfc_dec_s_ctrl, - .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl, -}; - -/* Get compose information */ -static int vidioc_g_selection(struct file *file, void *priv, - struct v4l2_selection *s) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - struct s5p_mfc_dev *dev = ctx->dev; - u32 left, right, top, bottom; - u32 width, height; - - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (ctx->state != MFCINST_HEAD_PARSED && - ctx->state != MFCINST_RUNNING && - ctx->state != MFCINST_FINISHING && - ctx->state != MFCINST_FINISHED) { - mfc_err("Can not get compose information\n"); - return -EINVAL; - } - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { - left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx); - right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; - left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; - top = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_v, ctx); - bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; - top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; - width = ctx->img_width - left - right; - height = ctx->img_height - top - bottom; - mfc_debug(2, "Composing info [h264]: l=%d t=%d w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", - left, top, s->r.width, s->r.height, right, bottom, - ctx->buf_width, ctx->buf_height); - } else { - left = 0; - top = 0; - width = ctx->img_width; - height = ctx->img_height; - mfc_debug(2, "Composing info: w=%d h=%d fw=%d fh=%d\n", - s->r.width, s->r.height, ctx->buf_width, - ctx->buf_height); - } - - switch (s->target) { - case V4L2_SEL_TGT_COMPOSE: - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - s->r.left = left; - s->r.top = top; - s->r.width = width; - s->r.height = height; - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_decoder_cmd(struct file *file, void *priv, - struct v4l2_decoder_cmd *cmd) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *buf; - unsigned long flags; - - switch (cmd->cmd) { - case V4L2_DEC_CMD_STOP: - if (cmd->flags != 0) - return -EINVAL; - - if (!vb2_is_streaming(&ctx->vq_src)) - return -EINVAL; - - spin_lock_irqsave(&dev->irqlock, flags); - if (list_empty(&ctx->src_queue)) { - mfc_err("EOS: empty src queue, entering finishing state"); - ctx->state = MFCINST_FINISHING; - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - spin_unlock_irqrestore(&dev->irqlock, flags); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - } else { - mfc_err("EOS: marking last buffer of stream"); - buf = list_entry(ctx->src_queue.prev, - struct s5p_mfc_buf, list); - if (buf->flags & MFC_BUF_FLAG_USED) - ctx->state = MFCINST_FINISHING; - else - buf->flags |= MFC_BUF_FLAG_EOS; - spin_unlock_irqrestore(&dev->irqlock, flags); - } - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - switch (sub->type) { - case V4L2_EVENT_EOS: - return v4l2_event_subscribe(fh, sub, 2, NULL); - case V4L2_EVENT_SOURCE_CHANGE: - return v4l2_src_change_event_subscribe(fh, sub); - default: - return -EINVAL; - } -} - - -/* v4l2_ioctl_ops */ -static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, - .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, - .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, - .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, - .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, - .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_expbuf = vidioc_expbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_selection = vidioc_g_selection, - .vidioc_decoder_cmd = vidioc_decoder_cmd, - .vidioc_subscribe_event = vidioc_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static int s5p_mfc_queue_setup(struct vb2_queue *vq, - unsigned int *buf_count, - unsigned int *plane_count, unsigned int psize[], - struct device *alloc_devs[]) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - /* Video output for decoding (source) - * this can be set after getting an instance */ - if (ctx->state == MFCINST_INIT && - vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - /* A single plane is required for input */ - *plane_count = 1; - if (*buf_count < 1) - *buf_count = 1; - if (*buf_count > MFC_MAX_BUFFERS) - *buf_count = MFC_MAX_BUFFERS; - /* Video capture for decoding (destination) - * this can be set after the header was parsed */ - } else if (ctx->state == MFCINST_HEAD_PARSED && - vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - /* Output plane count is 2 - one for Y and one for CbCr */ - *plane_count = 2; - /* Setup buffer count */ - if (*buf_count < ctx->pb_count) - *buf_count = ctx->pb_count; - if (*buf_count > ctx->pb_count + MFC_MAX_EXTRA_DPB) - *buf_count = ctx->pb_count + MFC_MAX_EXTRA_DPB; - if (*buf_count > MFC_MAX_BUFFERS) - *buf_count = MFC_MAX_BUFFERS; - } else { - mfc_err("State seems invalid. State = %d, vq->type = %d\n", - ctx->state, vq->type); - return -EINVAL; - } - mfc_debug(2, "Buffer count=%d, plane count=%d\n", - *buf_count, *plane_count); - if (ctx->state == MFCINST_HEAD_PARSED && - vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - psize[0] = ctx->luma_size; - psize[1] = ctx->chroma_size; - - if (IS_MFCV6_PLUS(dev)) - alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; - else - alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX]; - alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX]; - } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && - ctx->state == MFCINST_INIT) { - psize[0] = ctx->dec_src_buf_size; - alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; - } else { - mfc_err("This video node is dedicated to decoding. Decoding not initialized\n"); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_buf_init(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); - unsigned int i; - - if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - if (ctx->capture_state == QUEUE_BUFS_MMAPED) - return 0; - for (i = 0; i < ctx->dst_fmt->num_planes; i++) { - if (IS_ERR_OR_NULL(ERR_PTR( - vb2_dma_contig_plane_dma_addr(vb, i)))) { - mfc_err("Plane mem not allocated\n"); - return -EINVAL; - } - } - if (vb2_plane_size(vb, 0) < ctx->luma_size || - vb2_plane_size(vb, 1) < ctx->chroma_size) { - mfc_err("Plane buffer (CAPTURE) is too small\n"); - return -EINVAL; - } - i = vb->index; - ctx->dst_bufs[i].b = vbuf; - ctx->dst_bufs[i].cookie.raw.luma = - vb2_dma_contig_plane_dma_addr(vb, 0); - ctx->dst_bufs[i].cookie.raw.chroma = - vb2_dma_contig_plane_dma_addr(vb, 1); - ctx->dst_bufs_cnt++; - } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (IS_ERR_OR_NULL(ERR_PTR( - vb2_dma_contig_plane_dma_addr(vb, 0)))) { - mfc_err("Plane memory not allocated\n"); - return -EINVAL; - } - if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) { - mfc_err("Plane buffer (OUTPUT) is too small\n"); - return -EINVAL; - } - - i = vb->index; - ctx->src_bufs[i].b = vbuf; - ctx->src_bufs[i].cookie.stream = - vb2_dma_contig_plane_dma_addr(vb, 0); - ctx->src_bufs_cnt++; - } else { - mfc_err("s5p_mfc_buf_init: unknown queue type\n"); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - v4l2_ctrl_handler_setup(&ctx->ctrl_handler); - if (ctx->state == MFCINST_FINISHING || - ctx->state == MFCINST_FINISHED) - ctx->state = MFCINST_RUNNING; - /* If context is ready then dev = work->data;schedule it to run */ - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - return 0; -} - -static void s5p_mfc_stop_streaming(struct vb2_queue *q) -{ - unsigned long flags; - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - int aborted = 0; - - spin_lock_irqsave(&dev->irqlock, flags); - if ((ctx->state == MFCINST_FINISHING || - ctx->state == MFCINST_RUNNING) && - dev->curr_ctx == ctx->num && dev->hw_lock) { - ctx->state = MFCINST_ABORT; - spin_unlock_irqrestore(&dev->irqlock, flags); - s5p_mfc_wait_for_done_ctx(ctx, - S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0); - aborted = 1; - spin_lock_irqsave(&dev->irqlock, flags); - } - if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); - INIT_LIST_HEAD(&ctx->dst_queue); - ctx->dst_queue_cnt = 0; - ctx->dpb_flush_flag = 1; - ctx->dec_dst_flag = 0; - if (IS_MFCV6_PLUS(dev) && (ctx->state == MFCINST_RUNNING)) { - ctx->state = MFCINST_FLUSH; - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - spin_unlock_irqrestore(&dev->irqlock, flags); - if (s5p_mfc_wait_for_done_ctx(ctx, - S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0)) - mfc_err("Err flushing buffers\n"); - spin_lock_irqsave(&dev->irqlock, flags); - } - } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); - INIT_LIST_HEAD(&ctx->src_queue); - ctx->src_queue_cnt = 0; - } - if (aborted) - ctx->state = MFCINST_RUNNING; - spin_unlock_irqrestore(&dev->irqlock, flags); -} - - -static void s5p_mfc_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *mfc_buf; - - if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - mfc_buf = &ctx->src_bufs[vb->index]; - mfc_buf->flags &= ~MFC_BUF_FLAG_USED; - spin_lock_irqsave(&dev->irqlock, flags); - list_add_tail(&mfc_buf->list, &ctx->src_queue); - ctx->src_queue_cnt++; - spin_unlock_irqrestore(&dev->irqlock, flags); - } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - mfc_buf = &ctx->dst_bufs[vb->index]; - mfc_buf->flags &= ~MFC_BUF_FLAG_USED; - /* Mark destination as available for use by MFC */ - spin_lock_irqsave(&dev->irqlock, flags); - set_bit(vb->index, &ctx->dec_dst_flag); - list_add_tail(&mfc_buf->list, &ctx->dst_queue); - ctx->dst_queue_cnt++; - spin_unlock_irqrestore(&dev->irqlock, flags); - } else { - mfc_err("Unsupported buffer type (%d)\n", vq->type); - } - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); -} - -static struct vb2_ops s5p_mfc_dec_qops = { - .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_init = s5p_mfc_buf_init, - .start_streaming = s5p_mfc_start_streaming, - .stop_streaming = s5p_mfc_stop_streaming, - .buf_queue = s5p_mfc_buf_queue, -}; - -const struct s5p_mfc_codec_ops *get_dec_codec_ops(void) -{ - return &decoder_codec_ops; -} - -struct vb2_ops *get_dec_queue_ops(void) -{ - return &s5p_mfc_dec_qops; -} - -const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void) -{ - return &s5p_mfc_dec_ioctl_ops; -} - -#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_CODEC) \ - && V4L2_CTRL_DRIVER_PRIV(x)) - -int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx) -{ - struct v4l2_ctrl_config cfg; - int i; - - v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS); - if (ctx->ctrl_handler.error) { - mfc_err("v4l2_ctrl_handler_init failed\n"); - return ctx->ctrl_handler.error; - } - - for (i = 0; i < NUM_CTRLS; i++) { - if (IS_MFC51_PRIV(controls[i].id)) { - memset(&cfg, 0, sizeof(struct v4l2_ctrl_config)); - cfg.ops = &s5p_mfc_dec_ctrl_ops; - cfg.id = controls[i].id; - cfg.min = controls[i].minimum; - cfg.max = controls[i].maximum; - cfg.def = controls[i].default_value; - cfg.name = controls[i].name; - cfg.type = controls[i].type; - - cfg.step = controls[i].step; - cfg.menu_skip_mask = 0; - - ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler, - &cfg, NULL); - } else { - ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler, - &s5p_mfc_dec_ctrl_ops, - controls[i].id, controls[i].minimum, - controls[i].maximum, controls[i].step, - controls[i].default_value); - } - if (ctx->ctrl_handler.error) { - mfc_err("Adding control (%d) failed\n", i); - return ctx->ctrl_handler.error; - } - if (controls[i].is_volatile && ctx->ctrls[i]) - ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; - } - return 0; -} - -void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx) -{ - int i; - - v4l2_ctrl_handler_free(&ctx->ctrl_handler); - for (i = 0; i < NUM_CTRLS; i++) - ctx->ctrls[i] = NULL; -} - -void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) -{ - struct v4l2_format f; - f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; - ctx->src_fmt = find_format(&f, MFC_FMT_DEC); - if (IS_MFCV8_PLUS(ctx->dev)) - f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; - else if (IS_MFCV6_PLUS(ctx->dev)) - f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16; - else - f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT; - ctx->dst_fmt = find_format(&f, MFC_FMT_RAW); - mfc_debug(2, "Default src_fmt is %p, dest_fmt is %p\n", - ctx->src_fmt, ctx->dst_fmt); -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h deleted file mode 100644 index 0e9a0e3bbbe7..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_DEC_H_ -#define S5P_MFC_DEC_H_ - -const struct s5p_mfc_codec_ops *get_dec_codec_ops(void); -struct vb2_ops *get_dec_queue_ops(void); -const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); -struct s5p_mfc_fmt *get_dec_def_fmt(bool src); -int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx); -void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx); -void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx); - -#endif /* S5P_MFC_DEC_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c deleted file mode 100644 index 1fad99edb091..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ /dev/null @@ -1,2697 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c - * - * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - * - * Jeongtae Park - * Kamil Debski - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "s5p_mfc_common.h" -#include "s5p_mfc_ctrl.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_enc.h" -#include "s5p_mfc_intr.h" -#include "s5p_mfc_opr.h" - -#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12M -#define DEF_DST_FMT_ENC V4L2_PIX_FMT_H264 - -static struct s5p_mfc_fmt formats[] = { - { - .fourcc = V4L2_PIX_FMT_NV12MT_16X16, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, - .versions = MFC_V6_BIT | MFC_V7_BIT, - }, - { - .fourcc = V4L2_PIX_FMT_NV12MT, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, - .versions = MFC_V5_BIT, - }, - { - .fourcc = V4L2_PIX_FMT_NV12M, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, - .versions = MFC_V5PLUS_BITS, - }, - { - .fourcc = V4L2_PIX_FMT_NV21M, - .codec_mode = S5P_MFC_CODEC_NONE, - .type = MFC_FMT_RAW, - .num_planes = 2, - .versions = MFC_V6PLUS_BITS, - }, - { - .fourcc = V4L2_PIX_FMT_H264, - .codec_mode = S5P_MFC_CODEC_H264_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - }, - { - .fourcc = V4L2_PIX_FMT_MPEG4, - .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - }, - { - .fourcc = V4L2_PIX_FMT_H263, - .codec_mode = S5P_MFC_CODEC_H263_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, - .versions = MFC_V5PLUS_BITS, - }, - { - .fourcc = V4L2_PIX_FMT_VP8, - .codec_mode = S5P_MFC_CODEC_VP8_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, - .versions = MFC_V7PLUS_BITS, - }, - { - .fourcc = V4L2_PIX_FMT_HEVC, - .codec_mode = S5P_FIMV_CODEC_HEVC_ENC, - .type = MFC_FMT_ENC, - .num_planes = 1, - .versions = MFC_V10_BIT, - }, -}; - -#define NUM_FORMATS ARRAY_SIZE(formats) -static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) -{ - unsigned int i; - - for (i = 0; i < NUM_FORMATS; i++) { - if (formats[i].fourcc == f->fmt.pix_mp.pixelformat && - formats[i].type == t) - return &formats[i]; - } - return NULL; -} - -static struct mfc_control controls[] = { - { - .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 12, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, - .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, - .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 1, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 1900, - .maximum = (1 << 30) - 1, - .step = 1, - .default_value = 1900, - }, - { - .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Padding Control Enable", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Padding Color YUV Value", - .minimum = 0, - .maximum = (1 << 25) - 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_BITRATE, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 1, - .maximum = (1 << 30) - 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Rate Control Reaction Coeff.", - .minimum = 1, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Force frame type", - .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED, - .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED, - .default_value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, - .type = V4L2_CTRL_TYPE_BUTTON, - .minimum = 0, - .maximum = 0, - .step = 0, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Horizontal MV Search Range", - .minimum = 16, - .maximum = 128, - .step = 16, - .default_value = 32, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Vertical MV Search Range", - .minimum = 16, - .maximum = 128, - .step = 16, - .default_value = 32, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, - .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, - .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Frame Skip Enable", - .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED, - .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, - .menu_skip_mask = 0, - .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED, - }, - { - .id = V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .maximum = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, - .default_value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Fixed Target Bit Enable", - .minimum = 0, - .maximum = 1, - .default_value = 0, - .step = 1, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 2, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, - .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, - .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, - .menu_skip_mask = ~( - (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | - (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | - (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) - ), - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, - .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0, - .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, - .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, - .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, - .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, - .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = -6, - .maximum = 6, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = -6, - .maximum = 6, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, - .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, - .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "The Number of Ref. Pic for P", - .minimum = 1, - .maximum = 2, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 51, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "H263 I-Frame QP value", - .minimum = 1, - .maximum = 31, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "H263 Minimum QP value", - .minimum = 1, - .maximum = 31, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "H263 Maximum QP value", - .minimum = 1, - .maximum = 31, - .step = 1, - .default_value = 31, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "H263 P frame QP value", - .minimum = 1, - .maximum = 31, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "H263 B frame QP value", - .minimum = 1, - .maximum = 31, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "MPEG4 I-Frame QP value", - .minimum = 1, - .maximum = 31, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "MPEG4 Minimum QP value", - .minimum = 1, - .maximum = 31, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "MPEG4 Maximum QP value", - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 51, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "MPEG4 P frame QP value", - .minimum = 1, - .maximum = 31, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "MPEG4 B frame QP value", - .minimum = 1, - .maximum = 31, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "H264 Dark Reg Adaptive RC", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "H264 Smooth Reg Adaptive RC", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "H264 Static Reg Adaptive RC", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "H264 Activity Reg Adaptive RC", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED, - .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED, - .default_value = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, - .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE, - .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS, - .type = V4L2_CTRL_TYPE_INTEGER_MENU, - .maximum = V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS, - .default_value = V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES, - .type = V4L2_CTRL_TYPE_INTEGER_MENU, - .maximum = V4L2_CID_MPEG_VIDEO_VPX_2_REF_FRAME, - .default_value = V4L2_CID_MPEG_VIDEO_VPX_1_REF_FRAME, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 7, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV, - .maximum = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD, - .default_value = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_MAX_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 127, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 11, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 10, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 127, - .step = 1, - .default_value = 10, - }, - { - .id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_VP8_PROFILE_0, - .maximum = V4L2_MPEG_VIDEO_VP8_PROFILE_3, - .default_value = V4L2_MPEG_VIDEO_VP8_PROFILE_0, - .menu_skip_mask = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "HEVC I Frame QP Value", - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "HEVC P Frame QP Value", - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, - .maximum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, - .step = 1, - .default_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, - .maximum = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, - .step = 1, - .default_value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_TIER, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, - .maximum = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, - .step = 1, - .default_value = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 1, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 1, - .maximum = 2, - .step = 1, - .default_value = 1, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, - .maximum = V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, - .step = 1, - .default_value = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, - .maximum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, - .step = 1, - .default_value = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, - .maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, - .step = 1, - .default_value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 6, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 51, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = INT_MIN, - .maximum = INT_MAX, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 4, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = (1 << 16) - 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = -6, - .maximum = 6, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = -6, - .maximum = 6, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, - .type = V4L2_CTRL_TYPE_MENU, - .minimum = V4L2_MPEG_VIDEO_HEVC_SIZE_0, - .maximum = V4L2_MPEG_VIDEO_HEVC_SIZE_4, - .step = 1, - .default_value = V4L2_MPEG_VIDEO_HEVC_SIZE_0, - }, - { - .id = V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, - .type = V4L2_CTRL_TYPE_INTEGER, - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - { - .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Minimum number of output bufs", - .minimum = 1, - .maximum = 32, - .step = 1, - .default_value = 1, - .is_volatile = 1, - }, -}; - -#define NUM_CTRLS ARRAY_SIZE(controls) -static const char * const *mfc51_get_menu(u32 id) -{ - static const char * const mfc51_video_frame_skip[] = { - "Disabled", - "Level Limit", - "VBV/CPB Limit", - NULL, - }; - static const char * const mfc51_video_force_frame[] = { - "Disabled", - "I Frame", - "Not Coded", - NULL, - }; - switch (id) { - case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: - return mfc51_video_frame_skip; - case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE: - return mfc51_video_force_frame; - } - return NULL; -} - -static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) -{ - mfc_debug(2, "src=%d, dst=%d, state=%d\n", - ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state); - /* context is ready to make header */ - if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1) - return 1; - /* context is ready to encode a frame */ - if ((ctx->state == MFCINST_RUNNING || - ctx->state == MFCINST_HEAD_PRODUCED) && - ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) - return 1; - /* context is ready to encode remaining frames */ - if (ctx->state == MFCINST_FINISHING && - ctx->dst_queue_cnt >= 1) - return 1; - mfc_debug(2, "ctx is not ready\n"); - return 0; -} - -static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_buf *mb_entry; - - /* move buffers in ref queue to src queue */ - while (!list_empty(&ctx->ref_queue)) { - mb_entry = list_entry((&ctx->ref_queue)->next, - struct s5p_mfc_buf, list); - list_del(&mb_entry->list); - ctx->ref_queue_cnt--; - list_add_tail(&mb_entry->list, &ctx->src_queue); - ctx->src_queue_cnt++; - } - mfc_debug(2, "enc src count: %d, enc ref count: %d\n", - ctx->src_queue_cnt, ctx->ref_queue_cnt); - INIT_LIST_HEAD(&ctx->ref_queue); - ctx->ref_queue_cnt = 0; -} - -static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *dst_mb; - unsigned long dst_addr; - unsigned int dst_size; - - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); - dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); - s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, - dst_size); - return 0; -} - -static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_buf *dst_mb; - unsigned int enc_pb_count; - - if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) { - if (!list_empty(&ctx->dst_queue)) { - dst_mb = list_entry(ctx->dst_queue.next, - struct s5p_mfc_buf, list); - list_del(&dst_mb->list); - ctx->dst_queue_cnt--; - vb2_set_plane_payload(&dst_mb->b->vb2_buf, 0, - s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, - dev)); - vb2_buffer_done(&dst_mb->b->vb2_buf, - VB2_BUF_STATE_DONE); - } - } - - if (!IS_MFCV6_PLUS(dev)) { - ctx->state = MFCINST_RUNNING; - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - } else { - enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops, - get_enc_dpb_count, dev); - if (ctx->pb_count < enc_pb_count) - ctx->pb_count = enc_pb_count; - if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) { - ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, - get_e_min_scratch_buf_size, dev); - ctx->bank1.size += ctx->scratch_buf_size; - } - ctx->state = MFCINST_HEAD_PRODUCED; - } - - return 0; -} - -static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *dst_mb; - struct s5p_mfc_buf *src_mb; - unsigned long src_y_addr, src_c_addr, dst_addr; - unsigned int dst_size; - - src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0); - src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1); - s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, - src_y_addr, src_c_addr); - - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); - dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); - s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, - dst_size); - - return 0; -} - -static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *mb_entry; - unsigned long enc_y_addr = 0, enc_c_addr = 0; - unsigned long mb_y_addr, mb_c_addr; - int slice_type; - unsigned int strm_size; - - slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev); - strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev); - mfc_debug(2, "Encoded slice type: %d\n", slice_type); - mfc_debug(2, "Encoded stream size: %d\n", strm_size); - mfc_debug(2, "Display order: %d\n", - mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); - if (slice_type >= 0) { - s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx, - &enc_y_addr, &enc_c_addr); - list_for_each_entry(mb_entry, &ctx->src_queue, list) { - mb_y_addr = vb2_dma_contig_plane_dma_addr( - &mb_entry->b->vb2_buf, 0); - mb_c_addr = vb2_dma_contig_plane_dma_addr( - &mb_entry->b->vb2_buf, 1); - if ((enc_y_addr == mb_y_addr) && - (enc_c_addr == mb_c_addr)) { - list_del(&mb_entry->list); - ctx->src_queue_cnt--; - vb2_buffer_done(&mb_entry->b->vb2_buf, - VB2_BUF_STATE_DONE); - break; - } - } - list_for_each_entry(mb_entry, &ctx->ref_queue, list) { - mb_y_addr = vb2_dma_contig_plane_dma_addr( - &mb_entry->b->vb2_buf, 0); - mb_c_addr = vb2_dma_contig_plane_dma_addr( - &mb_entry->b->vb2_buf, 1); - if ((enc_y_addr == mb_y_addr) && - (enc_c_addr == mb_c_addr)) { - list_del(&mb_entry->list); - ctx->ref_queue_cnt--; - vb2_buffer_done(&mb_entry->b->vb2_buf, - VB2_BUF_STATE_DONE); - break; - } - } - } - if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) { - mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, - list); - if (mb_entry->flags & MFC_BUF_FLAG_USED) { - list_del(&mb_entry->list); - ctx->src_queue_cnt--; - list_add_tail(&mb_entry->list, &ctx->ref_queue); - ctx->ref_queue_cnt++; - } - } - mfc_debug(2, "enc src count: %d, enc ref count: %d\n", - ctx->src_queue_cnt, ctx->ref_queue_cnt); - if ((ctx->dst_queue_cnt > 0) && (strm_size > 0)) { - mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, - list); - list_del(&mb_entry->list); - ctx->dst_queue_cnt--; - switch (slice_type) { - case S5P_FIMV_ENC_SI_SLICE_TYPE_I: - mb_entry->b->flags |= V4L2_BUF_FLAG_KEYFRAME; - break; - case S5P_FIMV_ENC_SI_SLICE_TYPE_P: - mb_entry->b->flags |= V4L2_BUF_FLAG_PFRAME; - break; - case S5P_FIMV_ENC_SI_SLICE_TYPE_B: - mb_entry->b->flags |= V4L2_BUF_FLAG_BFRAME; - break; - } - vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, strm_size); - vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE); - } - if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) - clear_work_bit(ctx); - - return 0; -} - -static const struct s5p_mfc_codec_ops encoder_codec_ops = { - .pre_seq_start = enc_pre_seq_start, - .post_seq_start = enc_post_seq_start, - .pre_frame_start = enc_pre_frame_start, - .post_frame_start = enc_post_frame_start, -}; - -/* Query capabilities of the device */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - - strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver)); - strscpy(cap->card, dev->vfd_enc->name, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - dev_name(&dev->plat_dev->dev)); - return 0; -} - -static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, - bool out) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - int i, j = 0; - - for (i = 0; i < ARRAY_SIZE(formats); ++i) { - if (out && formats[i].type != MFC_FMT_RAW) - continue; - else if (!out && formats[i].type != MFC_FMT_ENC) - continue; - else if ((dev->variant->version_bit & formats[i].versions) == 0) - continue; - - if (j == f->index) { - f->pixelformat = formats[i].fourcc; - return 0; - } - ++j; - } - return -EINVAL; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, f, false); -} - -static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return vidioc_enum_fmt(file, f, true); -} - -static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - - mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state); - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - /* This is run on output (encoder dest) */ - pix_fmt_mp->width = 0; - pix_fmt_mp->height = 0; - pix_fmt_mp->field = V4L2_FIELD_NONE; - pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc; - pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes; - - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->enc_dst_buf_size; - pix_fmt_mp->plane_fmt[0].sizeimage = ctx->enc_dst_buf_size; - } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - /* This is run on capture (encoder src) */ - pix_fmt_mp->width = ctx->img_width; - pix_fmt_mp->height = ctx->img_height; - - pix_fmt_mp->field = V4L2_FIELD_NONE; - pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc; - pix_fmt_mp->num_planes = ctx->src_fmt->num_planes; - - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; - pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; - pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - } else { - mfc_err("invalid buf type\n"); - return -EINVAL; - } - return 0; -} - -static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_fmt *fmt; - struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - fmt = find_format(f, MFC_FMT_ENC); - if (!fmt) { - mfc_err("failed to try output format\n"); - return -EINVAL; - } - if ((dev->variant->version_bit & fmt->versions) == 0) { - mfc_err("Unsupported format by this MFC version.\n"); - return -EINVAL; - } - - pix_fmt_mp->plane_fmt[0].bytesperline = - pix_fmt_mp->plane_fmt[0].sizeimage; - } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - fmt = find_format(f, MFC_FMT_RAW); - if (!fmt) { - mfc_err("failed to try output format\n"); - return -EINVAL; - } - if ((dev->variant->version_bit & fmt->versions) == 0) { - mfc_err("Unsupported format by this MFC version.\n"); - return -EINVAL; - } - - v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1, - &pix_fmt_mp->height, 4, 1080, 1, 0); - } else { - mfc_err("invalid buf type\n"); - return -EINVAL; - } - return 0; -} - -static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - int ret = 0; - - ret = vidioc_try_fmt(file, priv, f); - if (ret) - return ret; - if (ctx->vq_src.streaming || ctx->vq_dst.streaming) { - v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); - ret = -EBUSY; - goto out; - } - if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - /* dst_fmt is validated by call to vidioc_try_fmt */ - ctx->dst_fmt = find_format(f, MFC_FMT_ENC); - ctx->state = MFCINST_INIT; - ctx->codec_mode = ctx->dst_fmt->codec_mode; - ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage; - pix_fmt_mp->plane_fmt[0].bytesperline = 0; - ctx->dst_bufs_cnt = 0; - ctx->capture_state = QUEUE_FREE; - ret = s5p_mfc_open_mfc_inst(dev, ctx); - } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - /* src_fmt is validated by call to vidioc_try_fmt */ - ctx->src_fmt = find_format(f, MFC_FMT_RAW); - ctx->img_width = pix_fmt_mp->width; - ctx->img_height = pix_fmt_mp->height; - mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode); - mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n", - pix_fmt_mp->width, pix_fmt_mp->height, - ctx->img_width, ctx->img_height); - - s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx); - pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; - pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; - pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; - pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; - - ctx->src_bufs_cnt = 0; - ctx->output_state = QUEUE_FREE; - } else { - mfc_err("invalid buf type\n"); - ret = -EINVAL; - } -out: - mfc_debug_leave(); - return ret; -} - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *reqbufs) -{ - struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - int ret = 0; - - /* if memory is not mmp or userptr return error */ - if ((reqbufs->memory != V4L2_MEMORY_MMAP) && - (reqbufs->memory != V4L2_MEMORY_USERPTR)) - return -EINVAL; - if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - if (reqbufs->count == 0) { - mfc_debug(2, "Freeing buffers\n"); - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, - ctx); - ctx->capture_state = QUEUE_FREE; - return ret; - } - if (ctx->capture_state != QUEUE_FREE) { - mfc_err("invalid capture state: %d\n", - ctx->capture_state); - return -EINVAL; - } - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - if (ret != 0) { - mfc_err("error in vb2_reqbufs() for E(D)\n"); - return ret; - } - ctx->capture_state = QUEUE_BUFS_REQUESTED; - - ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, - alloc_codec_buffers, ctx); - if (ret) { - mfc_err("Failed to allocate encoding buffers\n"); - reqbufs->count = 0; - ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); - return -ENOMEM; - } - } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (reqbufs->count == 0) { - mfc_debug(2, "Freeing buffers\n"); - ret = vb2_reqbufs(&ctx->vq_src, reqbufs); - s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, - ctx); - ctx->output_state = QUEUE_FREE; - return ret; - } - if (ctx->output_state != QUEUE_FREE) { - mfc_err("invalid output state: %d\n", - ctx->output_state); - return -EINVAL; - } - - if (IS_MFCV6_PLUS(dev)) { - /* Check for min encoder buffers */ - if (ctx->pb_count && - (reqbufs->count < ctx->pb_count)) { - reqbufs->count = ctx->pb_count; - mfc_debug(2, "Minimum %d output buffers needed\n", - ctx->pb_count); - } else { - ctx->pb_count = reqbufs->count; - } - } - - ret = vb2_reqbufs(&ctx->vq_src, reqbufs); - if (ret != 0) { - mfc_err("error in vb2_reqbufs() for E(S)\n"); - return ret; - } - ctx->output_state = QUEUE_BUFS_REQUESTED; - } else { - mfc_err("invalid buf type\n"); - return -EINVAL; - } - return ret; -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *buf) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - int ret = 0; - - /* if memory is not mmp or userptr return error */ - if ((buf->memory != V4L2_MEMORY_MMAP) && - (buf->memory != V4L2_MEMORY_USERPTR)) - return -EINVAL; - if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - if (ctx->state != MFCINST_GOT_INST) { - mfc_err("invalid context state: %d\n", ctx->state); - return -EINVAL; - } - ret = vb2_querybuf(&ctx->vq_dst, buf); - if (ret != 0) { - mfc_err("error in vb2_querybuf() for E(D)\n"); - return ret; - } - buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE; - } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = vb2_querybuf(&ctx->vq_src, buf); - if (ret != 0) { - mfc_err("error in vb2_querybuf() for E(S)\n"); - return ret; - } - } else { - mfc_err("invalid buf type\n"); - return -EINVAL; - } - return ret; -} - -/* Queue a buffer */ -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (ctx->state == MFCINST_ERROR) { - mfc_err("Call on QBUF after unrecoverable error\n"); - return -EIO; - } - if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (ctx->state == MFCINST_FINISHING) { - mfc_err("Call on QBUF after EOS command\n"); - return -EIO; - } - return vb2_qbuf(&ctx->vq_src, NULL, buf); - } else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - return vb2_qbuf(&ctx->vq_dst, NULL, buf); - } - return -EINVAL; -} - -/* Dequeue a buffer */ -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) -{ - const struct v4l2_event ev = { - .type = V4L2_EVENT_EOS - }; - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - int ret; - - if (ctx->state == MFCINST_ERROR) { - mfc_err_limited("Call on DQBUF after unrecoverable error\n"); - return -EIO; - } - if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); - } else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); - if (ret == 0 && ctx->state == MFCINST_FINISHED - && list_empty(&ctx->vq_dst.done_list)) - v4l2_event_queue_fh(&ctx->fh, &ev); - } else { - ret = -EINVAL; - } - - return ret; -} - -/* Export DMA buffer */ -static int vidioc_expbuf(struct file *file, void *priv, - struct v4l2_exportbuffer *eb) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return vb2_expbuf(&ctx->vq_src, eb); - if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return vb2_expbuf(&ctx->vq_dst, eb); - return -EINVAL; -} - -/* Stream on */ -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return vb2_streamon(&ctx->vq_src, type); - else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return vb2_streamon(&ctx->vq_dst, type); - return -EINVAL; -} - -/* Stream off, which equals to a pause */ -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - return vb2_streamoff(&ctx->vq_src, type); - else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) - return vb2_streamoff(&ctx->vq_dst, type); - return -EINVAL; -} - -static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl) -{ - static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_0 + 1] = { - /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0 */ 10, - /* V4L2_MPEG_VIDEO_H264_LEVEL_1B */ 9, - /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1 */ 11, - /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2 */ 12, - /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3 */ 13, - /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0 */ 20, - /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1 */ 21, - /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2 */ 22, - /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0 */ 30, - /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1 */ 31, - /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2 */ 32, - /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0 */ 40, - }; - return t[lvl]; -} - -static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl) -{ - static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 + 1] = { - /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 */ 0, - /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B */ 9, - /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 */ 1, - /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 */ 2, - /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 */ 3, - /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B */ 7, - /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 */ 4, - /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 */ 5, - }; - return t[lvl]; -} - -static inline int hevc_level(enum v4l2_mpeg_video_hevc_level lvl) -{ - static unsigned int t[] = { - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_1 */ 10, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2 */ 20, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 */ 21, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3 */ 30, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 */ 31, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4 */ 40, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 */ 41, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5 */ 50, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 */ 51, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 */ 52, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6 */ 60, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 */ 61, - /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 */ 62, - }; - return t[lvl]; -} - -static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar) -{ - static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = { - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED */ 0, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 */ 1, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 */ 2, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 */ 3, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 */ 4, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 */ 5, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 */ 6, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 */ 7, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 */ 8, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 */ 9, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 */ 10, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 */ 11, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 */ 12, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 */ 13, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 */ 14, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 */ 15, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 */ 16, - /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED */ 255, - }; - return t[sar]; -} - -/* - * Update range of all HEVC quantization parameter controls that depend on the - * V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP controls. - */ -static void __enc_update_hevc_qp_ctrls_range(struct s5p_mfc_ctx *ctx, - int min, int max) -{ - static const int __hevc_qp_ctrls[] = { - V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, - V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, - V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, - V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, - V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, - V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, - V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, - V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, - V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, - V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, - }; - struct v4l2_ctrl *ctrl = NULL; - int i, j; - - for (i = 0; i < ARRAY_SIZE(__hevc_qp_ctrls); i++) { - for (j = 0; j < ARRAY_SIZE(ctx->ctrls); j++) { - if (ctx->ctrls[j]->id == __hevc_qp_ctrls[i]) { - ctrl = ctx->ctrls[j]; - break; - } - } - if (WARN_ON(!ctrl)) - break; - - __v4l2_ctrl_modify_range(ctrl, min, max, ctrl->step, min); - } -} - -static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - p->gop_size = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: - p->slice_mode = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: - p->slice_mb = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: - p->slice_bit = ctrl->val * 8; - break; - case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: - p->intra_refresh_mb = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_PADDING: - p->pad = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV: - p->pad_luma = (ctrl->val >> 16) & 0xff; - p->pad_cb = (ctrl->val >> 8) & 0xff; - p->pad_cr = (ctrl->val >> 0) & 0xff; - break; - case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: - p->rc_frame = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_BITRATE: - p->rc_bitrate = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF: - p->rc_reaction_coeff = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE: - ctx->force_frame_type = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: - ctx->force_frame_type = - V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME; - break; - case V4L2_CID_MPEG_VIDEO_VBV_SIZE: - p->vbv_size = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: - p->mv_h_range = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: - p->mv_v_range = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: - p->codec.h264.cpb_size = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEADER_MODE: - p->seq_hdr_mode = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: - case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: - p->frame_skip_mode = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT: - p->fixed_target_bit = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: - p->num_b_frame = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_PROFILE: - switch (ctrl->val) { - case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: - p->codec.h264.profile = - S5P_FIMV_ENC_PROFILE_H264_MAIN; - break; - case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: - p->codec.h264.profile = - S5P_FIMV_ENC_PROFILE_H264_HIGH; - break; - case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: - p->codec.h264.profile = - S5P_FIMV_ENC_PROFILE_H264_BASELINE; - break; - case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: - if (IS_MFCV6_PLUS(dev)) - p->codec.h264.profile = - S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE; - else - ret = -EINVAL; - break; - default: - ret = -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_H264_LEVEL: - p->codec.h264.level_v4l2 = ctrl->val; - p->codec.h264.level = h264_level(ctrl->val); - if (p->codec.h264.level < 0) { - mfc_err("Level number is wrong\n"); - ret = p->codec.h264.level; - } - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: - p->codec.mpeg4.level_v4l2 = ctrl->val; - p->codec.mpeg4.level = mpeg4_level(ctrl->val); - if (p->codec.mpeg4.level < 0) { - mfc_err("Level number is wrong\n"); - ret = p->codec.mpeg4.level; - } - break; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: - p->codec.h264.loop_filter_mode = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: - p->codec.h264.loop_filter_alpha = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: - p->codec.h264.loop_filter_beta = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: - p->codec.h264.entropy_mode = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P: - p->codec.h264.num_ref_pic_4p = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: - p->codec.h264._8x8_transform = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: - p->rc_mb = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: - p->codec.h264.rc_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: - p->codec.h264.rc_min_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: - p->codec.h264.rc_max_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: - p->codec.h264.rc_p_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: - p->codec.h264.rc_b_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: - case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: - p->codec.mpeg4.rc_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: - case V4L2_CID_MPEG_VIDEO_H263_MIN_QP: - p->codec.mpeg4.rc_min_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: - case V4L2_CID_MPEG_VIDEO_H263_MAX_QP: - p->codec.mpeg4.rc_max_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: - case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: - p->codec.mpeg4.rc_p_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: - case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: - p->codec.mpeg4.rc_b_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK: - p->codec.h264.rc_mb_dark = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH: - p->codec.h264.rc_mb_smooth = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC: - p->codec.h264.rc_mb_static = ctrl->val; - break; - case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY: - p->codec.h264.rc_mb_activity = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: - p->codec.h264.vui_sar = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: - p->codec.h264.vui_sar_idc = vui_sar_idc(ctrl->val); - break; - case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: - p->codec.h264.vui_ext_sar_width = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: - p->codec.h264.vui_ext_sar_height = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: - p->codec.h264.open_gop = !ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: - p->codec.h264.open_gop_size = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: - switch (ctrl->val) { - case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: - p->codec.mpeg4.profile = - S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE; - break; - case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: - p->codec.mpeg4.profile = - S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE; - break; - default: - ret = -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: - p->codec.mpeg4.quarter_pixel = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: - p->codec.vp8.num_partitions = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4: - p->codec.vp8.imd_4x4 = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: - p->codec.vp8.num_ref = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL: - p->codec.vp8.filter_level = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS: - p->codec.vp8.filter_sharpness = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD: - p->codec.vp8.golden_frame_ref_period = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: - p->codec.vp8.golden_frame_sel = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: - p->codec.vp8.rc_min_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: - p->codec.vp8.rc_max_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: - p->codec.vp8.rc_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: - p->codec.vp8.rc_p_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: - p->codec.vp8.profile = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: - p->codec.hevc.rc_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: - p->codec.hevc.rc_p_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: - p->codec.hevc.rc_b_frame_qp = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: - p->codec.hevc.rc_framerate = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: - p->codec.hevc.rc_min_qp = ctrl->val; - __enc_update_hevc_qp_ctrls_range(ctx, ctrl->val, - p->codec.hevc.rc_max_qp); - break; - case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: - p->codec.hevc.rc_max_qp = ctrl->val; - __enc_update_hevc_qp_ctrls_range(ctx, p->codec.hevc.rc_min_qp, - ctrl->val); - break; - case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: - p->codec.hevc.level_v4l2 = ctrl->val; - p->codec.hevc.level = hevc_level(ctrl->val); - break; - case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: - switch (ctrl->val) { - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: - p->codec.hevc.profile = - V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; - break; - case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: - p->codec.hevc.profile = - V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; - break; - default: - ret = -EINVAL; - } - break; - case V4L2_CID_MPEG_VIDEO_HEVC_TIER: - p->codec.hevc.tier = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: - p->codec.hevc.max_partition_depth = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: - p->codec.hevc.num_refs_for_p = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: - p->codec.hevc.refreshtype = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: - p->codec.hevc.const_intra_period_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: - p->codec.hevc.lossless_cu_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: - p->codec.hevc.wavefront_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: - p->codec.hevc.loopfilter = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: - p->codec.hevc.hier_qp_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: - p->codec.hevc.hier_qp_type = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: - p->codec.hevc.num_hier_layer = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: - p->codec.hevc.hier_qp_layer[0] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: - p->codec.hevc.hier_qp_layer[1] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: - p->codec.hevc.hier_qp_layer[2] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: - p->codec.hevc.hier_qp_layer[3] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: - p->codec.hevc.hier_qp_layer[4] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: - p->codec.hevc.hier_qp_layer[5] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: - p->codec.hevc.hier_qp_layer[6] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: - p->codec.hevc.hier_bit_layer[0] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: - p->codec.hevc.hier_bit_layer[1] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: - p->codec.hevc.hier_bit_layer[2] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: - p->codec.hevc.hier_bit_layer[3] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: - p->codec.hevc.hier_bit_layer[4] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: - p->codec.hevc.hier_bit_layer[5] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: - p->codec.hevc.hier_bit_layer[6] = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: - p->codec.hevc.general_pb_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: - p->codec.hevc.temporal_id_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: - p->codec.hevc.strong_intra_smooth = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: - p->codec.hevc.intra_pu_split_disable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: - p->codec.hevc.tmv_prediction_disable = !ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: - p->codec.hevc.max_num_merge_mv = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: - p->codec.hevc.encoding_nostartcode_enable = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: - p->codec.hevc.refreshperiod = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: - p->codec.hevc.lf_beta_offset_div2 = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: - p->codec.hevc.lf_tc_offset_div2 = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: - p->codec.hevc.size_of_length_field = ctrl->val; - break; - case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: - p->codec.hevc.prepend_sps_pps_to_idr = ctrl->val; - break; - default: - v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", - ctrl->id, ctrl->val); - ret = -EINVAL; - } - return ret; -} - -static int s5p_mfc_enc_g_v_ctrl(struct v4l2_ctrl *ctrl) -{ - struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); - struct s5p_mfc_dev *dev = ctx->dev; - - switch (ctrl->id) { - case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: - if (ctx->state >= MFCINST_HEAD_PARSED && - ctx->state < MFCINST_ABORT) { - ctrl->val = ctx->pb_count; - break; - } else if (ctx->state != MFCINST_INIT) { - v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n"); - return -EINVAL; - } - /* Should wait for the header to be produced */ - s5p_mfc_wait_for_done_ctx(ctx, - S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); - if (ctx->state >= MFCINST_HEAD_PARSED && - ctx->state < MFCINST_ABORT) { - ctrl->val = ctx->pb_count; - } else { - v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n"); - return -EINVAL; - } - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = { - .s_ctrl = s5p_mfc_enc_s_ctrl, - .g_volatile_ctrl = s5p_mfc_enc_g_v_ctrl, -}; - -static int vidioc_s_parm(struct file *file, void *priv, - struct v4l2_streamparm *a) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ctx->enc_params.rc_framerate_num = - a->parm.output.timeperframe.denominator; - ctx->enc_params.rc_framerate_denom = - a->parm.output.timeperframe.numerator; - } else { - mfc_err("Setting FPS is only possible for the output queue\n"); - return -EINVAL; - } - return 0; -} - -static int vidioc_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *a) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - - if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - a->parm.output.timeperframe.denominator = - ctx->enc_params.rc_framerate_num; - a->parm.output.timeperframe.numerator = - ctx->enc_params.rc_framerate_denom; - } else { - mfc_err("Setting FPS is only possible for the output queue\n"); - return -EINVAL; - } - return 0; -} - -static int vidioc_encoder_cmd(struct file *file, void *priv, - struct v4l2_encoder_cmd *cmd) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *buf; - unsigned long flags; - - switch (cmd->cmd) { - case V4L2_ENC_CMD_STOP: - if (cmd->flags != 0) - return -EINVAL; - - if (!ctx->vq_src.streaming) - return -EINVAL; - - spin_lock_irqsave(&dev->irqlock, flags); - if (list_empty(&ctx->src_queue)) { - mfc_debug(2, "EOS: empty src queue, entering finishing state\n"); - ctx->state = MFCINST_FINISHING; - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - spin_unlock_irqrestore(&dev->irqlock, flags); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - } else { - mfc_debug(2, "EOS: marking last buffer of stream\n"); - buf = list_entry(ctx->src_queue.prev, - struct s5p_mfc_buf, list); - if (buf->flags & MFC_BUF_FLAG_USED) - ctx->state = MFCINST_FINISHING; - else - buf->flags |= MFC_BUF_FLAG_EOS; - spin_unlock_irqrestore(&dev->irqlock, flags); - } - break; - default: - return -EINVAL; - - } - return 0; -} - -static int vidioc_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - switch (sub->type) { - case V4L2_EVENT_EOS: - return v4l2_event_subscribe(fh, sub, 2, NULL); - default: - return -EINVAL; - } -} - -static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, - .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, - .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, - .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, - .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, - .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_expbuf = vidioc_expbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_s_parm = vidioc_s_parm, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_encoder_cmd = vidioc_encoder_cmd, - .vidioc_subscribe_event = vidioc_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) -{ - int i; - - if (!fmt) - return -EINVAL; - if (fmt->num_planes != vb->num_planes) { - mfc_err("invalid plane number for the format\n"); - return -EINVAL; - } - for (i = 0; i < fmt->num_planes; i++) { - dma_addr_t dma = vb2_dma_contig_plane_dma_addr(vb, i); - if (!dma) { - mfc_err("failed to get plane cookie\n"); - return -EINVAL; - } - mfc_debug(2, "index: %d, plane[%d] cookie: %pad\n", - vb->index, i, &dma); - } - return 0; -} - -static int s5p_mfc_queue_setup(struct vb2_queue *vq, - unsigned int *buf_count, unsigned int *plane_count, - unsigned int psize[], struct device *alloc_devs[]) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - if (ctx->state != MFCINST_GOT_INST) { - mfc_err("invalid state: %d\n", ctx->state); - return -EINVAL; - } - - if (ctx->dst_fmt) - *plane_count = ctx->dst_fmt->num_planes; - else - *plane_count = MFC_ENC_CAP_PLANE_COUNT; - if (*buf_count < 1) - *buf_count = 1; - if (*buf_count > MFC_MAX_BUFFERS) - *buf_count = MFC_MAX_BUFFERS; - psize[0] = ctx->enc_dst_buf_size; - alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; - } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (ctx->src_fmt) - *plane_count = ctx->src_fmt->num_planes; - else - *plane_count = MFC_ENC_OUT_PLANE_COUNT; - - if (*buf_count < 1) - *buf_count = 1; - if (*buf_count > MFC_MAX_BUFFERS) - *buf_count = MFC_MAX_BUFFERS; - - psize[0] = ctx->luma_size; - psize[1] = ctx->chroma_size; - - if (IS_MFCV6_PLUS(dev)) { - alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; - alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX]; - } else { - alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX]; - alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX]; - } - } else { - mfc_err("invalid queue type: %d\n", vq->type); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_buf_init(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); - unsigned int i; - int ret; - - if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - ret = check_vb_with_fmt(ctx->dst_fmt, vb); - if (ret < 0) - return ret; - i = vb->index; - ctx->dst_bufs[i].b = vbuf; - ctx->dst_bufs[i].cookie.stream = - vb2_dma_contig_plane_dma_addr(vb, 0); - ctx->dst_bufs_cnt++; - } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = check_vb_with_fmt(ctx->src_fmt, vb); - if (ret < 0) - return ret; - i = vb->index; - ctx->src_bufs[i].b = vbuf; - ctx->src_bufs[i].cookie.raw.luma = - vb2_dma_contig_plane_dma_addr(vb, 0); - ctx->src_bufs[i].cookie.raw.chroma = - vb2_dma_contig_plane_dma_addr(vb, 1); - ctx->src_bufs_cnt++; - } else { - mfc_err("invalid queue type: %d\n", vq->type); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); - int ret; - - if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - ret = check_vb_with_fmt(ctx->dst_fmt, vb); - if (ret < 0) - return ret; - mfc_debug(2, "plane size: %ld, dst size: %zu\n", - vb2_plane_size(vb, 0), ctx->enc_dst_buf_size); - if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) { - mfc_err("plane size is too small for capture\n"); - return -EINVAL; - } - } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - ret = check_vb_with_fmt(ctx->src_fmt, vb); - if (ret < 0) - return ret; - mfc_debug(2, "plane size: %ld, luma size: %d\n", - vb2_plane_size(vb, 0), ctx->luma_size); - mfc_debug(2, "plane size: %ld, chroma size: %d\n", - vb2_plane_size(vb, 1), ctx->chroma_size); - if (vb2_plane_size(vb, 0) < ctx->luma_size || - vb2_plane_size(vb, 1) < ctx->chroma_size) { - mfc_err("plane size is too small for output\n"); - return -EINVAL; - } - } else { - mfc_err("invalid queue type: %d\n", vq->type); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - if (IS_MFCV6_PLUS(dev) && - (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) { - - if ((ctx->state == MFCINST_GOT_INST) && - (dev->curr_ctx == ctx->num) && dev->hw_lock) { - s5p_mfc_wait_for_done_ctx(ctx, - S5P_MFC_R2H_CMD_SEQ_DONE_RET, - 0); - } - - if (ctx->src_bufs_cnt < ctx->pb_count) { - mfc_err("Need minimum %d OUTPUT buffers\n", - ctx->pb_count); - return -ENOBUFS; - } - } - - /* If context is ready then dev = work->data;schedule it to run */ - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); - - return 0; -} - -static void s5p_mfc_stop_streaming(struct vb2_queue *q) -{ - unsigned long flags; - struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - - if ((ctx->state == MFCINST_FINISHING || - ctx->state == MFCINST_RUNNING) && - dev->curr_ctx == ctx->num && dev->hw_lock) { - ctx->state = MFCINST_ABORT; - s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_FRAME_DONE_RET, - 0); - } - ctx->state = MFCINST_FINISHED; - spin_lock_irqsave(&dev->irqlock, flags); - if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); - INIT_LIST_HEAD(&ctx->dst_queue); - ctx->dst_queue_cnt = 0; - } - if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - cleanup_ref_queue(ctx); - s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); - INIT_LIST_HEAD(&ctx->src_queue); - ctx->src_queue_cnt = 0; - } - spin_unlock_irqrestore(&dev->irqlock, flags); -} - -static void s5p_mfc_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_queue *vq = vb->vb2_queue; - struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); - struct s5p_mfc_dev *dev = ctx->dev; - unsigned long flags; - struct s5p_mfc_buf *mfc_buf; - - if (ctx->state == MFCINST_ERROR) { - vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); - cleanup_ref_queue(ctx); - return; - } - if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { - mfc_buf = &ctx->dst_bufs[vb->index]; - mfc_buf->flags &= ~MFC_BUF_FLAG_USED; - /* Mark destination as available for use by MFC */ - spin_lock_irqsave(&dev->irqlock, flags); - list_add_tail(&mfc_buf->list, &ctx->dst_queue); - ctx->dst_queue_cnt++; - spin_unlock_irqrestore(&dev->irqlock, flags); - } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - mfc_buf = &ctx->src_bufs[vb->index]; - mfc_buf->flags &= ~MFC_BUF_FLAG_USED; - spin_lock_irqsave(&dev->irqlock, flags); - list_add_tail(&mfc_buf->list, &ctx->src_queue); - ctx->src_queue_cnt++; - spin_unlock_irqrestore(&dev->irqlock, flags); - } else { - mfc_err("unsupported buffer type (%d)\n", vq->type); - } - if (s5p_mfc_ctx_ready(ctx)) - set_work_bit_irqsave(ctx); - s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); -} - -static struct vb2_ops s5p_mfc_enc_qops = { - .queue_setup = s5p_mfc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_init = s5p_mfc_buf_init, - .buf_prepare = s5p_mfc_buf_prepare, - .start_streaming = s5p_mfc_start_streaming, - .stop_streaming = s5p_mfc_stop_streaming, - .buf_queue = s5p_mfc_buf_queue, -}; - -const struct s5p_mfc_codec_ops *get_enc_codec_ops(void) -{ - return &encoder_codec_ops; -} - -struct vb2_ops *get_enc_queue_ops(void) -{ - return &s5p_mfc_enc_qops; -} - -const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void) -{ - return &s5p_mfc_enc_ioctl_ops; -} - -#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_CODEC) \ - && V4L2_CTRL_DRIVER_PRIV(x)) - -int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx) -{ - struct v4l2_ctrl_config cfg; - int i; - - v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS); - if (ctx->ctrl_handler.error) { - mfc_err("v4l2_ctrl_handler_init failed\n"); - return ctx->ctrl_handler.error; - } - for (i = 0; i < NUM_CTRLS; i++) { - if (IS_MFC51_PRIV(controls[i].id)) { - memset(&cfg, 0, sizeof(struct v4l2_ctrl_config)); - cfg.ops = &s5p_mfc_enc_ctrl_ops; - cfg.id = controls[i].id; - cfg.min = controls[i].minimum; - cfg.max = controls[i].maximum; - cfg.def = controls[i].default_value; - cfg.name = controls[i].name; - cfg.type = controls[i].type; - cfg.flags = 0; - - if (cfg.type == V4L2_CTRL_TYPE_MENU) { - cfg.step = 0; - cfg.menu_skip_mask = controls[i].menu_skip_mask; - cfg.qmenu = mfc51_get_menu(cfg.id); - } else { - cfg.step = controls[i].step; - cfg.menu_skip_mask = 0; - } - ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler, - &cfg, NULL); - } else { - if ((controls[i].type == V4L2_CTRL_TYPE_MENU) || - (controls[i].type == - V4L2_CTRL_TYPE_INTEGER_MENU)) { - ctx->ctrls[i] = v4l2_ctrl_new_std_menu( - &ctx->ctrl_handler, - &s5p_mfc_enc_ctrl_ops, controls[i].id, - controls[i].maximum, 0, - controls[i].default_value); - } else { - ctx->ctrls[i] = v4l2_ctrl_new_std( - &ctx->ctrl_handler, - &s5p_mfc_enc_ctrl_ops, controls[i].id, - controls[i].minimum, - controls[i].maximum, controls[i].step, - controls[i].default_value); - } - } - if (ctx->ctrl_handler.error) { - mfc_err("Adding control (%d) failed\n", i); - return ctx->ctrl_handler.error; - } - if (controls[i].is_volatile && ctx->ctrls[i]) - ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; - } - v4l2_ctrl_handler_setup(&ctx->ctrl_handler); - return 0; -} - -void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx) -{ - int i; - - v4l2_ctrl_handler_free(&ctx->ctrl_handler); - for (i = 0; i < NUM_CTRLS; i++) - ctx->ctrls[i] = NULL; -} - -void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx) -{ - struct v4l2_format f; - f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_ENC; - ctx->src_fmt = find_format(&f, MFC_FMT_RAW); - f.fmt.pix_mp.pixelformat = DEF_DST_FMT_ENC; - ctx->dst_fmt = find_format(&f, MFC_FMT_ENC); -} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h deleted file mode 100644 index cacd1ca43e19..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_ENC_H_ -#define S5P_MFC_ENC_H_ - -const struct s5p_mfc_codec_ops *get_enc_codec_ops(void); -struct vb2_ops *get_enc_queue_ops(void); -const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); -struct s5p_mfc_fmt *get_enc_def_fmt(bool src); -int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx); -void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx); -void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx); - -#endif /* S5P_MFC_ENC_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c deleted file mode 100644 index 0a38f6d70ee9..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.c +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.c - * - * C file for Samsung MFC (Multi Function Codec - FIMV) driver - * This file contains functions used to wait for command completion. - * - * Kamil Debski, Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#include -#include -#include -#include -#include -#include "s5p_mfc_common.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_intr.h" - -int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) -{ - int ret; - - ret = wait_event_interruptible_timeout(dev->queue, - (dev->int_cond && (dev->int_type == command - || dev->int_type == S5P_MFC_R2H_CMD_ERR_RET)), - msecs_to_jiffies(MFC_INT_TIMEOUT)); - if (ret == 0) { - mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n", - dev->int_type, command); - return 1; - } else if (ret == -ERESTARTSYS) { - mfc_err("Interrupted by a signal\n"); - return 1; - } - mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n", - dev->int_type, command); - if (dev->int_type == S5P_MFC_R2H_CMD_ERR_RET) - return 1; - return 0; -} - -void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev) -{ - dev->int_cond = 0; - dev->int_type = 0; - dev->int_err = 0; -} - -int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, - int command, int interrupt) -{ - int ret; - - if (interrupt) { - ret = wait_event_interruptible_timeout(ctx->queue, - (ctx->int_cond && (ctx->int_type == command - || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), - msecs_to_jiffies(MFC_INT_TIMEOUT)); - } else { - ret = wait_event_timeout(ctx->queue, - (ctx->int_cond && (ctx->int_type == command - || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), - msecs_to_jiffies(MFC_INT_TIMEOUT)); - } - if (ret == 0) { - mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n", - ctx->int_type, command); - return 1; - } else if (ret == -ERESTARTSYS) { - mfc_err("Interrupted by a signal\n"); - return 1; - } - mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n", - ctx->int_type, command); - if (ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET) - return 1; - return 0; -} - -void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx) -{ - ctx->int_cond = 0; - ctx->int_type = 0; - ctx->int_err = 0; -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h deleted file mode 100644 index d32860db17d2..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_intr.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.h - * - * Header file for Samsung MFC (Multi Function Codec - FIMV) driver - * It contains waiting functions declarations. - * - * Kamil Debski, Copyright (C) 2011 Samsung Electronics - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_INTR_H_ -#define S5P_MFC_INTR_H_ - -#include "s5p_mfc_common.h" - -int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, - int command, int interrupt); -int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command); -void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx); -void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev); - -#endif /* S5P_MFC_INTR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h b/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h deleted file mode 100644 index 1a32266b7ddc..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_iommu.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2015 Samsung Electronics Co.Ltd - * Authors: Marek Szyprowski - */ - -#ifndef S5P_MFC_IOMMU_H_ -#define S5P_MFC_IOMMU_H_ - -#if defined(CONFIG_EXYNOS_IOMMU) - -#include - -static inline bool exynos_is_iommu_available(struct device *dev) -{ - return dev_iommu_priv_get(dev) != NULL; -} - -#else - -static inline bool exynos_is_iommu_available(struct device *dev) -{ - return false; -} - -#endif - -#endif /* S5P_MFC_IOMMU_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c deleted file mode 100644 index bb65671eea91..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/platform/s5p-mfc/s5p_mfc_opr.c - * - * Samsung MFC (Multi Function Codec - FIMV) driver - * This file contains hw related functions. - * - * Kamil Debski, Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#include "s5p_mfc_debug.h" -#include "s5p_mfc_opr.h" -#include "s5p_mfc_opr_v5.h" -#include "s5p_mfc_opr_v6.h" - -static struct s5p_mfc_hw_ops *s5p_mfc_ops; - -void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev) -{ - if (IS_MFCV6_PLUS(dev)) { - s5p_mfc_ops = s5p_mfc_init_hw_ops_v6(); - dev->warn_start = S5P_FIMV_ERR_WARNINGS_START_V6; - } else { - s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); - dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; - } - dev->mfc_ops = s5p_mfc_ops; -} - -void s5p_mfc_init_regs(struct s5p_mfc_dev *dev) -{ - if (IS_MFCV6_PLUS(dev)) - dev->mfc_regs = s5p_mfc_init_regs_v6_plus(dev); -} - -int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, - struct s5p_mfc_priv_buf *b) -{ - unsigned int bits = dev->mem_size >> PAGE_SHIFT; - unsigned int count = b->size >> PAGE_SHIFT; - unsigned int align = (SZ_64K >> PAGE_SHIFT) - 1; - unsigned int start, offset; - - mfc_debug(3, "Allocating priv: %zu\n", b->size); - - if (dev->mem_virt) { - start = bitmap_find_next_zero_area(dev->mem_bitmap, bits, 0, count, align); - if (start > bits) - goto no_mem; - - bitmap_set(dev->mem_bitmap, start, count); - offset = start << PAGE_SHIFT; - b->virt = dev->mem_virt + offset; - b->dma = dev->mem_base + offset; - } else { - struct device *mem_dev = dev->mem_dev[mem_ctx]; - dma_addr_t base = dev->dma_base[mem_ctx]; - - b->ctx = mem_ctx; - b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL); - if (!b->virt) - goto no_mem; - if (b->dma < base) { - mfc_err("Invalid memory configuration - buffer (%pad) is below base memory address(%pad)\n", - &b->dma, &base); - dma_free_coherent(mem_dev, b->size, b->virt, b->dma); - return -ENOMEM; - } - } - - mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); - return 0; -no_mem: - mfc_err("Allocating private buffer of size %zu failed\n", b->size); - return -ENOMEM; -} - -int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, - struct s5p_mfc_priv_buf *b) -{ - struct device *mem_dev = dev->mem_dev[mem_ctx]; - - mfc_debug(3, "Allocating generic buf: %zu\n", b->size); - - b->ctx = mem_ctx; - b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL); - if (!b->virt) - goto no_mem; - - mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); - return 0; -no_mem: - mfc_err("Allocating generic buffer of size %zu failed\n", b->size); - return -ENOMEM; -} - -void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, - struct s5p_mfc_priv_buf *b) -{ - if (dev->mem_virt) { - unsigned int start = (b->dma - dev->mem_base) >> PAGE_SHIFT; - unsigned int count = b->size >> PAGE_SHIFT; - - bitmap_clear(dev->mem_bitmap, start, count); - } else { - struct device *mem_dev = dev->mem_dev[b->ctx]; - - dma_free_coherent(mem_dev, b->size, b->virt, b->dma); - } - b->virt = NULL; - b->dma = 0; - b->size = 0; -} - -void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, - struct s5p_mfc_priv_buf *b) -{ - struct device *mem_dev = dev->mem_dev[b->ctx]; - dma_free_coherent(mem_dev, b->size, b->virt, b->dma); - b->virt = NULL; - b->dma = 0; - b->size = 0; -} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h deleted file mode 100644 index 1c5d2d4c0543..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h +++ /dev/null @@ -1,339 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/platform/s5p-mfc/s5p_mfc_opr.h - * - * Header file for Samsung MFC (Multi Function Codec - FIMV) driver - * Contains declarations of hw related functions. - * - * Kamil Debski, Copyright (C) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_OPR_H_ -#define S5P_MFC_OPR_H_ - -#include "s5p_mfc_common.h" - -struct s5p_mfc_regs { - - /* codec common registers */ - void __iomem *risc_on; - void __iomem *risc2host_int; - void __iomem *host2risc_int; - void __iomem *risc_base_address; - void __iomem *mfc_reset; - void __iomem *host2risc_command; - void __iomem *risc2host_command; - void __iomem *mfc_bus_reset_ctrl; - void __iomem *firmware_version; - void __iomem *instance_id; - void __iomem *codec_type; - void __iomem *context_mem_addr; - void __iomem *context_mem_size; - void __iomem *pixel_format; - void __iomem *metadata_enable; - void __iomem *mfc_version; - void __iomem *dbg_info_enable; - void __iomem *dbg_buffer_addr; - void __iomem *dbg_buffer_size; - void __iomem *hed_control; - void __iomem *mfc_timeout_value; - void __iomem *hed_shared_mem_addr; - void __iomem *dis_shared_mem_addr;/* only v7 */ - void __iomem *ret_instance_id; - void __iomem *error_code; - void __iomem *dbg_buffer_output_size; - void __iomem *metadata_status; - void __iomem *metadata_addr_mb_info; - void __iomem *metadata_size_mb_info; - void __iomem *dbg_info_stage_counter; - - /* decoder registers */ - void __iomem *d_crc_ctrl; - void __iomem *d_dec_options; - void __iomem *d_display_delay; - void __iomem *d_set_frame_width; - void __iomem *d_set_frame_height; - void __iomem *d_sei_enable; - void __iomem *d_min_num_dpb; - void __iomem *d_min_first_plane_dpb_size; - void __iomem *d_min_second_plane_dpb_size; - void __iomem *d_min_third_plane_dpb_size;/* only v8 */ - void __iomem *d_min_num_mv; - void __iomem *d_mvc_num_views; - void __iomem *d_min_num_dis;/* only v7 */ - void __iomem *d_min_first_dis_size;/* only v7 */ - void __iomem *d_min_second_dis_size;/* only v7 */ - void __iomem *d_min_third_dis_size;/* only v7 */ - void __iomem *d_post_filter_luma_dpb0;/* v7 and v8 */ - void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */ - void __iomem *d_post_filter_luma_dpb2;/* only v7 */ - void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */ - void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */ - void __iomem *d_post_filter_chroma_dpb2;/* only v7 */ - void __iomem *d_num_dpb; - void __iomem *d_num_mv; - void __iomem *d_init_buffer_options; - void __iomem *d_first_plane_dpb_stride_size;/* only v8 */ - void __iomem *d_second_plane_dpb_stride_size;/* only v8 */ - void __iomem *d_third_plane_dpb_stride_size;/* only v8 */ - void __iomem *d_first_plane_dpb_size; - void __iomem *d_second_plane_dpb_size; - void __iomem *d_third_plane_dpb_size;/* only v8 */ - void __iomem *d_mv_buffer_size; - void __iomem *d_first_plane_dpb; - void __iomem *d_second_plane_dpb; - void __iomem *d_third_plane_dpb; - void __iomem *d_mv_buffer; - void __iomem *d_scratch_buffer_addr; - void __iomem *d_scratch_buffer_size; - void __iomem *d_metadata_buffer_addr; - void __iomem *d_metadata_buffer_size; - void __iomem *d_nal_start_options;/* v7 and v8 */ - void __iomem *d_cpb_buffer_addr; - void __iomem *d_cpb_buffer_size; - void __iomem *d_available_dpb_flag_upper; - void __iomem *d_available_dpb_flag_lower; - void __iomem *d_cpb_buffer_offset; - void __iomem *d_slice_if_enable; - void __iomem *d_picture_tag; - void __iomem *d_stream_data_size; - void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */ - void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */ - void __iomem *d_display_frame_width; - void __iomem *d_display_frame_height; - void __iomem *d_display_status; - void __iomem *d_display_first_plane_addr; - void __iomem *d_display_second_plane_addr; - void __iomem *d_display_third_plane_addr;/* only v8 */ - void __iomem *d_display_frame_type; - void __iomem *d_display_crop_info1; - void __iomem *d_display_crop_info2; - void __iomem *d_display_picture_profile; - void __iomem *d_display_luma_crc;/* v7 and v8 */ - void __iomem *d_display_chroma0_crc;/* v7 and v8 */ - void __iomem *d_display_chroma1_crc;/* only v8 */ - void __iomem *d_display_luma_crc_top;/* only v6 */ - void __iomem *d_display_chroma_crc_top;/* only v6 */ - void __iomem *d_display_luma_crc_bot;/* only v6 */ - void __iomem *d_display_chroma_crc_bot;/* only v6 */ - void __iomem *d_display_aspect_ratio; - void __iomem *d_display_extended_ar; - void __iomem *d_decoded_frame_width; - void __iomem *d_decoded_frame_height; - void __iomem *d_decoded_status; - void __iomem *d_decoded_first_plane_addr; - void __iomem *d_decoded_second_plane_addr; - void __iomem *d_decoded_third_plane_addr;/* only v8 */ - void __iomem *d_decoded_frame_type; - void __iomem *d_decoded_crop_info1; - void __iomem *d_decoded_crop_info2; - void __iomem *d_decoded_picture_profile; - void __iomem *d_decoded_nal_size; - void __iomem *d_decoded_luma_crc; - void __iomem *d_decoded_chroma0_crc; - void __iomem *d_decoded_chroma1_crc;/* only v8 */ - void __iomem *d_ret_picture_tag_top; - void __iomem *d_ret_picture_tag_bot; - void __iomem *d_ret_picture_time_top; - void __iomem *d_ret_picture_time_bot; - void __iomem *d_chroma_format; - void __iomem *d_vc1_info;/* v7 and v8 */ - void __iomem *d_mpeg4_info; - void __iomem *d_h264_info; - void __iomem *d_metadata_addr_concealed_mb; - void __iomem *d_metadata_size_concealed_mb; - void __iomem *d_metadata_addr_vc1_param; - void __iomem *d_metadata_size_vc1_param; - void __iomem *d_metadata_addr_sei_nal; - void __iomem *d_metadata_size_sei_nal; - void __iomem *d_metadata_addr_vui; - void __iomem *d_metadata_size_vui; - void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */ - void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */ - void __iomem *d_mvc_view_id; - void __iomem *d_frame_pack_sei_avail; - void __iomem *d_frame_pack_arrgment_id; - void __iomem *d_frame_pack_sei_info; - void __iomem *d_frame_pack_grid_pos; - void __iomem *d_display_recovery_sei_info;/* v7 and v8 */ - void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */ - void __iomem *d_display_first_addr;/* only v7 */ - void __iomem *d_display_second_addr;/* only v7 */ - void __iomem *d_display_third_addr;/* only v7 */ - void __iomem *d_decoded_first_addr;/* only v7 */ - void __iomem *d_decoded_second_addr;/* only v7 */ - void __iomem *d_decoded_third_addr;/* only v7 */ - void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */ - void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */ - void __iomem *d_min_scratch_buffer_size; /* v10 */ - void __iomem *d_static_buffer_addr; /* v10 */ - void __iomem *d_static_buffer_size; /* v10 */ - - /* encoder registers */ - void __iomem *e_frame_width; - void __iomem *e_frame_height; - void __iomem *e_cropped_frame_width; - void __iomem *e_cropped_frame_height; - void __iomem *e_frame_crop_offset; - void __iomem *e_enc_options; - void __iomem *e_picture_profile; - void __iomem *e_vbv_buffer_size; - void __iomem *e_vbv_init_delay; - void __iomem *e_fixed_picture_qp; - void __iomem *e_rc_config; - void __iomem *e_rc_qp_bound; - void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */ - void __iomem *e_rc_mode; - void __iomem *e_mb_rc_config; - void __iomem *e_padding_ctrl; - void __iomem *e_air_threshold; - void __iomem *e_mv_hor_range; - void __iomem *e_mv_ver_range; - void __iomem *e_num_dpb; - void __iomem *e_luma_dpb; - void __iomem *e_chroma_dpb; - void __iomem *e_me_buffer; - void __iomem *e_scratch_buffer_addr; - void __iomem *e_scratch_buffer_size; - void __iomem *e_tmv_buffer0; - void __iomem *e_tmv_buffer1; - void __iomem *e_ir_buffer_addr;/* v7 and v8 */ - void __iomem *e_source_first_plane_addr; - void __iomem *e_source_second_plane_addr; - void __iomem *e_source_third_plane_addr;/* v7 and v8 */ - void __iomem *e_source_first_plane_stride;/* v7 and v8 */ - void __iomem *e_source_second_plane_stride;/* v7 and v8 */ - void __iomem *e_source_third_plane_stride;/* v7 and v8 */ - void __iomem *e_stream_buffer_addr; - void __iomem *e_stream_buffer_size; - void __iomem *e_roi_buffer_addr; - void __iomem *e_param_change; - void __iomem *e_ir_size; - void __iomem *e_gop_config; - void __iomem *e_mslice_mode; - void __iomem *e_mslice_size_mb; - void __iomem *e_mslice_size_bits; - void __iomem *e_frame_insertion; - void __iomem *e_rc_frame_rate; - void __iomem *e_rc_bit_rate; - void __iomem *e_rc_roi_ctrl; - void __iomem *e_picture_tag; - void __iomem *e_bit_count_enable; - void __iomem *e_max_bit_count; - void __iomem *e_min_bit_count; - void __iomem *e_metadata_buffer_addr; - void __iomem *e_metadata_buffer_size; - void __iomem *e_encoded_source_first_plane_addr; - void __iomem *e_encoded_source_second_plane_addr; - void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */ - void __iomem *e_stream_size; - void __iomem *e_slice_type; - void __iomem *e_picture_count; - void __iomem *e_ret_picture_tag; - void __iomem *e_stream_buffer_write_pointer; /* only v6 */ - void __iomem *e_recon_luma_dpb_addr; - void __iomem *e_recon_chroma_dpb_addr; - void __iomem *e_metadata_addr_enc_slice; - void __iomem *e_metadata_size_enc_slice; - void __iomem *e_mpeg4_options; - void __iomem *e_mpeg4_hec_period; - void __iomem *e_aspect_ratio; - void __iomem *e_extended_sar; - void __iomem *e_h264_options; - void __iomem *e_h264_options_2;/* v7 and v8 */ - void __iomem *e_h264_lf_alpha_offset; - void __iomem *e_h264_lf_beta_offset; - void __iomem *e_h264_i_period; - void __iomem *e_h264_fmo_slice_grp_map_type; - void __iomem *e_h264_fmo_num_slice_grp_minus1; - void __iomem *e_h264_fmo_slice_grp_change_dir; - void __iomem *e_h264_fmo_slice_grp_change_rate_minus1; - void __iomem *e_h264_fmo_run_length_minus1_0; - void __iomem *e_h264_aso_slice_order_0; - void __iomem *e_h264_chroma_qp_offset; - void __iomem *e_h264_num_t_layer; - void __iomem *e_h264_hierarchical_qp_layer0; - void __iomem *e_h264_frame_packing_sei_info; - void __iomem *e_h264_nal_control;/* v7 and v8 */ - void __iomem *e_mvc_frame_qp_view1; - void __iomem *e_mvc_rc_bit_rate_view1; - void __iomem *e_mvc_rc_qbound_view1; - void __iomem *e_mvc_rc_mode_view1; - void __iomem *e_mvc_inter_view_prediction_on; - void __iomem *e_vp8_options;/* v7 and v8 */ - void __iomem *e_vp8_filter_options;/* v7 and v8 */ - void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */ - void __iomem *e_vp8_num_t_layer;/* v7 and v8 */ - void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */ - void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ - void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ - void __iomem *e_min_scratch_buffer_size; /* v10 */ - void __iomem *e_num_t_layer; /* v10 */ - void __iomem *e_hier_qp_layer0; /* v10 */ - void __iomem *e_hier_bit_rate_layer0; /* v10 */ - void __iomem *e_hevc_options; /* v10 */ - void __iomem *e_hevc_refresh_period; /* v10 */ - void __iomem *e_hevc_lf_beta_offset_div2; /* v10 */ - void __iomem *e_hevc_lf_tc_offset_div2; /* v10 */ - void __iomem *e_hevc_nal_control; /* v10 */ -}; - -struct s5p_mfc_hw_ops { - int (*alloc_dec_temp_buffers)(struct s5p_mfc_ctx *ctx); - void (*release_dec_desc_buffer)(struct s5p_mfc_ctx *ctx); - int (*alloc_codec_buffers)(struct s5p_mfc_ctx *ctx); - void (*release_codec_buffers)(struct s5p_mfc_ctx *ctx); - int (*alloc_instance_buffer)(struct s5p_mfc_ctx *ctx); - void (*release_instance_buffer)(struct s5p_mfc_ctx *ctx); - int (*alloc_dev_context_buffer)(struct s5p_mfc_dev *dev); - void (*release_dev_context_buffer)(struct s5p_mfc_dev *dev); - void (*dec_calc_dpb_size)(struct s5p_mfc_ctx *ctx); - void (*enc_calc_src_size)(struct s5p_mfc_ctx *ctx); - int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size); - void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr); - void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr); - void (*try_run)(struct s5p_mfc_dev *dev); - void (*clear_int_flags)(struct s5p_mfc_dev *dev); - int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev); - int (*get_dec_y_adr)(struct s5p_mfc_dev *dev); - int (*get_dspl_status)(struct s5p_mfc_dev *dev); - int (*get_dec_status)(struct s5p_mfc_dev *dev); - int (*get_dec_frame_type)(struct s5p_mfc_dev *dev); - int (*get_disp_frame_type)(struct s5p_mfc_ctx *ctx); - int (*get_consumed_stream)(struct s5p_mfc_dev *dev); - int (*get_int_reason)(struct s5p_mfc_dev *dev); - int (*get_int_err)(struct s5p_mfc_dev *dev); - int (*err_dec)(unsigned int err); - int (*get_img_width)(struct s5p_mfc_dev *dev); - int (*get_img_height)(struct s5p_mfc_dev *dev); - int (*get_dpb_count)(struct s5p_mfc_dev *dev); - int (*get_mv_count)(struct s5p_mfc_dev *dev); - int (*get_inst_no)(struct s5p_mfc_dev *dev); - int (*get_enc_strm_size)(struct s5p_mfc_dev *dev); - int (*get_enc_slice_type)(struct s5p_mfc_dev *dev); - int (*get_enc_dpb_count)(struct s5p_mfc_dev *dev); - unsigned int (*get_pic_type_top)(struct s5p_mfc_ctx *ctx); - unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx); - unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx); - unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx); - int (*get_min_scratch_buf_size)(struct s5p_mfc_dev *dev); - int (*get_e_min_scratch_buf_size)(struct s5p_mfc_dev *dev); -}; - -void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); -void s5p_mfc_init_regs(struct s5p_mfc_dev *dev); -int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, - struct s5p_mfc_priv_buf *b); -void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, - struct s5p_mfc_priv_buf *b); -int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, - struct s5p_mfc_priv_buf *b); -void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, - struct s5p_mfc_priv_buf *b); - - -#endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c deleted file mode 100644 index 28a06dc343fd..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ /dev/null @@ -1,1637 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.c - * - * Samsung MFC (Multi Function Codec - FIMV) driver - * This file contains hw related functions. - * - * Kamil Debski, Copyright (c) 2011 Samsung Electronics - * http://www.samsung.com/ - */ - -#include "s5p_mfc_common.h" -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_ctrl.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_intr.h" -#include "s5p_mfc_pm.h" -#include "s5p_mfc_opr.h" -#include "s5p_mfc_opr_v5.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define OFFSETA(x) (((x) - dev->dma_base[BANK_L_CTX]) >> MFC_OFFSET_SHIFT) -#define OFFSETB(x) (((x) - dev->dma_base[BANK_R_CTX]) >> MFC_OFFSET_SHIFT) - -/* Allocate temporary buffers for decoding */ -static int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; - int ret; - - ctx->dsc.size = buf_size->dsc; - ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->dsc); - if (ret) { - mfc_err("Failed to allocate temporary buffer\n"); - return ret; - } - - BUG_ON(ctx->dsc.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - memset(ctx->dsc.virt, 0, ctx->dsc.size); - wmb(); - return 0; -} - - -/* Release temporary buffers for decoding */ -static void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) -{ - s5p_mfc_release_priv_buf(ctx->dev, &ctx->dsc); -} - -/* Allocate codec buffers */ -static int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int enc_ref_y_size = 0; - unsigned int enc_ref_c_size = 0; - unsigned int guard_width, guard_height; - int ret; - - if (ctx->type == MFCINST_DECODER) { - mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", - ctx->luma_size, ctx->chroma_size, ctx->mv_size); - mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); - } else if (ctx->type == MFCINST_ENCODER) { - enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - - if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { - enc_ref_c_size = ALIGN(ctx->img_width, - S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height >> 1, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(enc_ref_c_size, - S5P_FIMV_NV12MT_SALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(guard_width * guard_height, - S5P_FIMV_NV12MT_SALIGN); - } - mfc_debug(2, "recon luma size: %d chroma size: %d\n", - enc_ref_y_size, enc_ref_c_size); - } else { - return -EINVAL; - } - /* Codecs have different memory requirements */ - switch (ctx->codec_mode) { - case S5P_MFC_CODEC_H264_DEC: - ctx->bank1.size = - ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + - S5P_FIMV_DEC_VERT_NB_MV_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2.size = ctx->total_dpb_count * ctx->mv_size; - break; - case S5P_MFC_CODEC_MPEG4_DEC: - ctx->bank1.size = - ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_STX_PARSER_SIZE + - S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2.size = 0; - break; - case S5P_MFC_CODEC_VC1RCV_DEC: - case S5P_MFC_CODEC_VC1_DEC: - ctx->bank1.size = - ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_NB_DCAC_SIZE + - 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2.size = 0; - break; - case S5P_MFC_CODEC_MPEG2_DEC: - ctx->bank1.size = 0; - ctx->bank2.size = 0; - break; - case S5P_MFC_CODEC_H263_DEC: - ctx->bank1.size = - ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + - S5P_FIMV_DEC_UPNB_MV_SIZE + - S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + - S5P_FIMV_DEC_NB_DCAC_SIZE, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->bank2.size = 0; - break; - case S5P_MFC_CODEC_H264_ENC: - ctx->bank1.size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_COLFLG_SIZE + - S5P_FIMV_ENC_INTRAMD_SIZE + - S5P_FIMV_ENC_NBORINFO_SIZE; - ctx->bank2.size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4) + - S5P_FIMV_ENC_INTRAPRED_SIZE; - break; - case S5P_MFC_CODEC_MPEG4_ENC: - ctx->bank1.size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_COLFLG_SIZE + - S5P_FIMV_ENC_ACDCCOEF_SIZE; - ctx->bank2.size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4); - break; - case S5P_MFC_CODEC_H263_ENC: - ctx->bank1.size = (enc_ref_y_size * 2) + - S5P_FIMV_ENC_UPMV_SIZE + - S5P_FIMV_ENC_ACDCCOEF_SIZE; - ctx->bank2.size = (enc_ref_y_size * 2) + - (enc_ref_c_size * 4); - break; - default: - break; - } - /* Allocate only if memory from bank 1 is necessary */ - if (ctx->bank1.size > 0) { - - ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->bank1); - if (ret) { - mfc_err("Failed to allocate Bank1 temporary buffer\n"); - return ret; - } - BUG_ON(ctx->bank1.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - } - /* Allocate only if memory from bank 2 is necessary */ - if (ctx->bank2.size > 0) { - ret = s5p_mfc_alloc_priv_buf(dev, BANK_R_CTX, &ctx->bank2); - if (ret) { - mfc_err("Failed to allocate Bank2 temporary buffer\n"); - s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank1); - return ret; - } - BUG_ON(ctx->bank2.dma & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); - } - return 0; -} - -/* Release buffers allocated for codec */ -static void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) -{ - s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank1); - s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank2); -} - -/* Allocate memory for instance data buffer */ -static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; - int ret; - - if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || - ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) - ctx->ctx.size = buf_size->h264_ctx; - else - ctx->ctx.size = buf_size->non_h264_ctx; - - ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->ctx); - if (ret) { - mfc_err("Failed to allocate instance buffer\n"); - return ret; - } - ctx->ctx.ofs = OFFSETA(ctx->ctx.dma); - - /* Zero content of the allocated memory */ - memset(ctx->ctx.virt, 0, ctx->ctx.size); - wmb(); - - /* Initialize shared memory */ - ctx->shm.size = buf_size->shm; - ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->shm); - if (ret) { - mfc_err("Failed to allocate shared memory buffer\n"); - s5p_mfc_release_priv_buf(dev, &ctx->ctx); - return ret; - } - - /* shared memory offset only keeps the offset from base (port a) */ - ctx->shm.ofs = ctx->shm.dma - dev->dma_base[BANK_L_CTX]; - BUG_ON(ctx->shm.ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - - memset(ctx->shm.virt, 0, buf_size->shm); - wmb(); - return 0; -} - -/* Release instance buffer */ -static void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) -{ - s5p_mfc_release_priv_buf(ctx->dev, &ctx->ctx); - s5p_mfc_release_priv_buf(ctx->dev, &ctx->shm); -} - -static int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev) -{ - /* NOP */ - - return 0; -} - -static void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) -{ - /* NOP */ -} - -static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, - unsigned int ofs) -{ - *(u32 *)(ctx->shm.virt + ofs) = data; - wmb(); -} - -static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, - unsigned long ofs) -{ - rmb(); - return *(u32 *)(ctx->shm.virt + ofs); -} - -static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) -{ - unsigned int guard_width, guard_height; - - ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); - ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - mfc_debug(2, - "SEQ Done: Movie dimensions %dx%d, buffer dimensions: %dx%d\n", - ctx->img_width, ctx->img_height, ctx->buf_width, - ctx->buf_height); - - if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { - ctx->luma_size = ALIGN(ctx->buf_width * ctx->buf_height, - S5P_FIMV_DEC_BUF_ALIGN); - ctx->chroma_size = ALIGN(ctx->buf_width * - ALIGN((ctx->img_height >> 1), - S5P_FIMV_NV12MT_VALIGN), - S5P_FIMV_DEC_BUF_ALIGN); - ctx->mv_size = ALIGN(ctx->buf_width * - ALIGN((ctx->buf_height >> 2), - S5P_FIMV_NV12MT_VALIGN), - S5P_FIMV_DEC_BUF_ALIGN); - } else { - guard_width = - ALIGN(ctx->img_width + 24, S5P_FIMV_NV12MT_HALIGN); - guard_height = - ALIGN(ctx->img_height + 16, S5P_FIMV_NV12MT_VALIGN); - ctx->luma_size = ALIGN(guard_width * guard_height, - S5P_FIMV_DEC_BUF_ALIGN); - - guard_width = - ALIGN(ctx->img_width + 16, S5P_FIMV_NV12MT_HALIGN); - guard_height = - ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - ctx->chroma_size = ALIGN(guard_width * guard_height, - S5P_FIMV_DEC_BUF_ALIGN); - - ctx->mv_size = 0; - } -} - -static void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx) -{ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { - ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN); - - ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12M_LVALIGN); - ctx->chroma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) - * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12M_CVALIGN); - - ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12M_SALIGN); - ctx->chroma_size = - ALIGN(ctx->chroma_size, S5P_FIMV_NV12M_SALIGN); - } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) { - ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); - - ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - ctx->chroma_size = - ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); - - ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12MT_SALIGN); - ctx->chroma_size = - ALIGN(ctx->chroma_size, S5P_FIMV_NV12MT_SALIGN); - } -} - -/* Set registers for decoding temporary buffers */ -static void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; - - mfc_write(dev, OFFSETA(ctx->dsc.dma), S5P_FIMV_SI_CH0_DESC_ADR); - mfc_write(dev, buf_size->dsc, S5P_FIMV_SI_CH0_DESC_SIZE); -} - -/* Set registers for shared buffer */ -static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - mfc_write(dev, ctx->shm.ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); -} - -/* Set registers for decoding stream buffer */ -static int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, - int buf_addr, unsigned int start_num_byte, - unsigned int buf_size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR); - mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE); - mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE); - s5p_mfc_write_info_v5(ctx, start_num_byte, START_BYTE_NUM); - return 0; -} - -/* Set decoding frame buffer */ -static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) -{ - unsigned int frame_size_lu, i; - unsigned int frame_size_ch, frame_size_mv; - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int dpb; - size_t buf_addr1, buf_addr2; - int buf_size1, buf_size2; - - buf_addr1 = ctx->bank1.dma; - buf_size1 = ctx->bank1.size; - buf_addr2 = ctx->bank2.dma; - buf_size2 = ctx->bank2.size; - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & - ~S5P_FIMV_DPB_COUNT_MASK; - mfc_write(dev, ctx->total_dpb_count | dpb, - S5P_FIMV_SI_CH0_DPB_CONF_CTRL); - s5p_mfc_set_shared_buffer(ctx); - switch (ctx->codec_mode) { - case S5P_MFC_CODEC_H264_DEC: - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_VERT_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; - break; - case S5P_MFC_CODEC_MPEG4_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR); - buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE; - buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - break; - case S5P_MFC_CODEC_H263_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - break; - case S5P_MFC_CODEC_VC1_DEC: - case S5P_MFC_CODEC_VC1RCV_DEC: - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); - buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; - buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR); - buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR); - buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR); - buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; - break; - case S5P_MFC_CODEC_MPEG2_DEC: - break; - default: - mfc_err("Unknown codec for decoding (%x)\n", - ctx->codec_mode); - return -EINVAL; - } - frame_size_lu = ctx->luma_size; - frame_size_ch = ctx->chroma_size; - frame_size_mv = ctx->mv_size; - mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size_lu, frame_size_ch, - frame_size_mv); - for (i = 0; i < ctx->total_dpb_count; i++) { - /* Bank2 */ - mfc_debug(2, "Luma %d: %zx\n", i, - ctx->dst_bufs[i].cookie.raw.luma); - mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), - S5P_FIMV_DEC_LUMA_ADR + i * 4); - mfc_debug(2, "\tChroma %d: %zx\n", i, - ctx->dst_bufs[i].cookie.raw.chroma); - mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), - S5P_FIMV_DEC_CHROMA_ADR + i * 4); - if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { - mfc_debug(2, "\tBuf2: %zx, size: %d\n", - buf_addr2, buf_size2); - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_H264_MV_ADR + i * 4); - buf_addr2 += frame_size_mv; - buf_size2 -= frame_size_mv; - } - } - mfc_debug(2, "Buf1: %zu, buf_size1: %d\n", buf_addr1, buf_size1); - mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", - buf_size1, buf_size2, ctx->total_dpb_count); - if (buf_size1 < 0 || buf_size2 < 0) { - mfc_debug(2, "Not enough memory has been allocated\n"); - return -ENOMEM; - } - s5p_mfc_write_info_v5(ctx, frame_size_lu, ALLOC_LUMA_DPB_SIZE); - s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); - if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) - s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE); - mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) - << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), - S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -/* Set registers for encoding stream buffer */ -static int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR); - mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE); - return 0; -} - -static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR); - mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); -} - -static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - *y_addr = dev->dma_base[BANK_R_CTX] + - (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) << MFC_OFFSET_SHIFT); - *c_addr = dev->dma_base[BANK_R_CTX] + - (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) << MFC_OFFSET_SHIFT); -} - -/* Set encoding ref & codec buffer */ -static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - size_t buf_addr1, buf_addr2; - size_t buf_size1, buf_size2; - unsigned int enc_ref_y_size, enc_ref_c_size; - unsigned int guard_width, guard_height; - int i; - - buf_addr1 = ctx->bank1.dma; - buf_size1 = ctx->bank1.size; - buf_addr2 = ctx->bank2.dma; - buf_size2 = ctx->bank2.size; - enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); - enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); - if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { - enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) - * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); - } else { - guard_width = ALIGN(ctx->img_width + 16, - S5P_FIMV_NV12MT_HALIGN); - guard_height = ALIGN((ctx->img_height >> 1) + 4, - S5P_FIMV_NV12MT_VALIGN); - enc_ref_c_size = ALIGN(guard_width * guard_height, - S5P_FIMV_NV12MT_SALIGN); - } - mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", buf_size1, buf_size2); - switch (ctx->codec_mode) { - case S5P_MFC_CODEC_H264_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_COZERO_FLAG_ADR); - buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; - buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_UP_INTRA_MD_ADR); - buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE; - buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_H264_UP_INTRA_PRED_ADR); - buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE; - buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_H264_NBOR_INFO_ADR); - buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; - buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; - mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", - buf_size1, buf_size2); - break; - case S5P_MFC_CODEC_MPEG4_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_MPEG4_COZERO_FLAG_ADR); - buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; - buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_MPEG4_ACDC_COEF_ADR); - buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; - buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", - buf_size1, buf_size2); - break; - case S5P_MFC_CODEC_H263_ENC: - for (i = 0; i < 2; i++) { - mfc_write(dev, OFFSETA(buf_addr1), - S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); - buf_addr1 += enc_ref_y_size; - buf_size1 -= enc_ref_y_size; - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); - buf_addr2 += enc_ref_y_size; - buf_size2 -= enc_ref_y_size; - } - for (i = 0; i < 4; i++) { - mfc_write(dev, OFFSETB(buf_addr2), - S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); - buf_addr2 += enc_ref_c_size; - buf_size2 -= enc_ref_c_size; - } - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR); - buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; - buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; - mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); - buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; - buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; - mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", - buf_size1, buf_size2); - break; - default: - mfc_err("Unknown codec set for encoding: %d\n", - ctx->codec_mode); - return -EINVAL; - } - return 0; -} - -static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - unsigned int reg; - unsigned int shm; - - /* width */ - mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX); - /* height */ - mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX); - /* pictype : enable, IDR period */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - reg |= (1 << 18); - reg &= ~(0xFFFF); - reg |= p->gop_size; - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON); - /* multi-slice control */ - /* multi-slice MB number or bit size */ - mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); - if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { - mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); - } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { - mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); - } else { - mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); - mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT); - } - /* cyclic intra refresh */ - mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL); - /* memory structure cur. frame */ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) - mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); - else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) - mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); - /* padding control & value */ - reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); - if (p->pad) { - /** enable */ - reg |= (1UL << 31); - /** cr value */ - reg &= ~(0xFF << 16); - reg |= (p->pad_cr << 16); - /** cb value */ - reg &= ~(0xFF << 8); - reg |= (p->pad_cb << 8); - /** y value */ - reg &= ~(0xFF); - reg |= (p->pad_luma); - } else { - /** disable & all value clear */ - reg = 0; - } - mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /** frame-level rate control */ - reg &= ~(0x1 << 9); - reg |= (p->rc_frame << 9); - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* bit rate */ - if (p->rc_frame) - mfc_write(dev, p->rc_bitrate, - S5P_FIMV_ENC_RC_BIT_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE); - /* reaction coefficient */ - if (p->rc_frame) - mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA); - shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); - /* seq header ctrl */ - shm &= ~(0x1 << 3); - shm |= (p->seq_hdr_mode << 3); - /* frame skip mode */ - shm &= ~(0x3 << 1); - shm |= (p->frame_skip_mode << 1); - s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); - /* fixed target bit */ - s5p_mfc_write_info_v5(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); - return 0; -} - -static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; - unsigned int reg; - unsigned int shm; - - s5p_mfc_set_enc_params(ctx); - /* pictype : number of B */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* num_b_frame - 0 ~ 2 */ - reg &= ~(0x3 << 16); - reg |= (p->num_b_frame << 16); - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* profile & level */ - reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); - /* level */ - reg &= ~(0xFF << 8); - reg |= (p_264->level << 8); - /* profile - 0 ~ 2 */ - reg &= ~(0x3F); - reg |= p_264->profile; - mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); - /* interlace */ - mfc_write(dev, p_264->interlace, S5P_FIMV_ENC_PIC_STRUCT); - /* height */ - if (p_264->interlace) - mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); - /* loopfilter ctrl */ - mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); - /* loopfilter alpha offset */ - if (p_264->loop_filter_alpha < 0) { - reg = 0x10; - reg |= (0xFF - p_264->loop_filter_alpha) + 1; - } else { - reg = 0x00; - reg |= (p_264->loop_filter_alpha & 0xF); - } - mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF); - /* loopfilter beta offset */ - if (p_264->loop_filter_beta < 0) { - reg = 0x10; - reg |= (0xFF - p_264->loop_filter_beta) + 1; - } else { - reg = 0x00; - reg |= (p_264->loop_filter_beta & 0xF); - } - mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF); - /* entropy coding mode */ - if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) - mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE); - /* number of ref. picture */ - reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF); - /* num of ref. pictures of P */ - reg &= ~(0x3 << 5); - reg |= (p_264->num_ref_pic_4p << 5); - /* max number of ref. pictures */ - reg &= ~(0x1F); - reg |= p_264->max_ref_pic; - mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF); - /* 8x8 transform enable */ - mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* macroblock level rate control */ - reg &= ~(0x1 << 8); - reg |= (p->rc_mb << 8); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_264->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* frame rate */ - if (p->rc_frame && p->rc_framerate_denom) - mfc_write(dev, p->rc_framerate_num * 1000 - / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_264->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_264->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* macroblock adaptive scaling features */ - if (p->rc_mb) { - reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); - /* dark region */ - reg &= ~(0x1 << 3); - reg |= (p_264->rc_mb_dark << 3); - /* smooth region */ - reg &= ~(0x1 << 2); - reg |= (p_264->rc_mb_smooth << 2); - /* static region */ - reg &= ~(0x1 << 1); - reg |= (p_264->rc_mb_static << 1); - /* high activity region */ - reg &= ~(0x1); - reg |= p_264->rc_mb_activity; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); - } - if (!p->rc_frame && !p->rc_mb) { - shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); - shm |= (p_264->rc_p_frame_qp & 0x3F); - s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); - } - /* extended encoder ctrl */ - shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); - /* AR VUI control */ - shm &= ~(0x1 << 15); - shm |= (p_264->vui_sar << 1); - s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); - if (p_264->vui_sar) { - /* aspect ration IDC */ - shm = s5p_mfc_read_info_v5(ctx, SAMPLE_ASPECT_RATIO_IDC); - shm &= ~(0xFF); - shm |= p_264->vui_sar_idc; - s5p_mfc_write_info_v5(ctx, shm, SAMPLE_ASPECT_RATIO_IDC); - if (p_264->vui_sar_idc == 0xFF) { - /* sample AR info */ - shm = s5p_mfc_read_info_v5(ctx, EXTENDED_SAR); - shm &= ~(0xFFFFFFFF); - shm |= p_264->vui_ext_sar_width << 16; - shm |= p_264->vui_ext_sar_height; - s5p_mfc_write_info_v5(ctx, shm, EXTENDED_SAR); - } - } - /* intra picture period for H.264 */ - shm = s5p_mfc_read_info_v5(ctx, H264_I_PERIOD); - /* control */ - shm &= ~(0x1 << 16); - shm |= (p_264->open_gop << 16); - /* value */ - if (p_264->open_gop) { - shm &= ~(0xFFFF); - shm |= p_264->open_gop_size; - } - s5p_mfc_write_info_v5(ctx, shm, H264_I_PERIOD); - /* extended encoder ctrl */ - shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p_264->cpb_size << 16); - } - s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; - unsigned int reg; - unsigned int shm; - unsigned int framerate; - - s5p_mfc_set_enc_params(ctx); - /* pictype : number of B */ - reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* num_b_frame - 0 ~ 2 */ - reg &= ~(0x3 << 16); - reg |= (p->num_b_frame << 16); - mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); - /* profile & level */ - reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); - /* level */ - reg &= ~(0xFF << 8); - reg |= (p_mpeg4->level << 8); - /* profile - 0 ~ 2 */ - reg &= ~(0x3F); - reg |= p_mpeg4->profile; - mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); - /* quarter_pixel */ - mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); - /* qp */ - if (!p->rc_frame) { - shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6); - shm |= (p_mpeg4->rc_p_frame_qp & 0x3F); - s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); - } - /* frame rate */ - if (p->rc_frame) { - if (p->rc_framerate_denom > 0) { - framerate = p->rc_framerate_num * 1000 / - p->rc_framerate_denom; - mfc_write(dev, framerate, - S5P_FIMV_ENC_RC_FRAME_RATE); - shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING); - shm &= ~(0xFFFFFFFF); - shm |= (1UL << 31); - shm |= ((p->rc_framerate_num & 0x7FFF) << 16); - shm |= (p->rc_framerate_denom & 0xFFFF); - s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING); - } - } else { - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - } - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_mpeg4->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_mpeg4->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_mpeg4->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* extended encoder ctrl */ - shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p->vbv_size << 16); - } - s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; - unsigned int reg; - unsigned int shm; - - s5p_mfc_set_enc_params(ctx); - /* qp */ - if (!p->rc_frame) { - shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); - shm &= ~(0xFFF); - shm |= (p_h263->rc_p_frame_qp & 0x3F); - s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); - } - /* frame rate */ - if (p->rc_frame && p->rc_framerate_denom) - mfc_write(dev, p->rc_framerate_num * 1000 - / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); - else - mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); - /* rate control config. */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); - /* frame QP */ - reg &= ~(0x3F); - reg |= p_h263->rc_frame_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); - /* max & min value of QP */ - reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); - /* max QP */ - reg &= ~(0x3F << 8); - reg |= (p_h263->rc_max_qp << 8); - /* min QP */ - reg &= ~(0x3F); - reg |= p_h263->rc_min_qp; - mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); - /* extended encoder ctrl */ - shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - shm &= ~(0xFFFF << 16); - shm |= (p->vbv_size << 16); - } - s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); - return 0; -} - -/* Initialize decoding */ -static int s5p_mfc_init_decode_v5(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - s5p_mfc_set_shared_buffer(ctx); - /* Setup loop filter, for decoding this is only valid for MPEG4 */ - if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) - mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); - else - mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); - mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) << - S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable << - S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay & - S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT), - S5P_FIMV_SI_CH0_DPB_CONF_CTRL); - mfc_write(dev, - ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) - | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int dpb; - - if (flush) - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | ( - S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); - else - dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & - ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); - mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); -} - -/* Decode a single frame */ -static int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx, - enum s5p_mfc_decode_arg last_frame) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF); - s5p_mfc_set_shared_buffer(ctx); - s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); - /* Issue different commands to instance basing on whether it - * is the last frame or not. */ - switch (last_frame) { - case MFC_DEC_FRAME: - mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) << - S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - break; - case MFC_DEC_LAST_FRAME: - mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) << - S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - break; - case MFC_DEC_RES_CHANGE: - mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC & - S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), - S5P_FIMV_SI_CH0_INST_ID); - break; - } - mfc_debug(2, "Decoding a usual frame\n"); - return 0; -} - -static int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) - s5p_mfc_set_enc_params_h264(ctx); - else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) - s5p_mfc_set_enc_params_mpeg4(ctx); - else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) - s5p_mfc_set_enc_params_h263(ctx); - else { - mfc_err("Unknown codec for encoding (%x)\n", - ctx->codec_mode); - return -EINVAL; - } - s5p_mfc_set_shared_buffer(ctx); - mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | - (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - return 0; -} - -/* Encode a single frame */ -static int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - int cmd; - /* memory structure cur. frame */ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) - mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); - else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) - mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); - s5p_mfc_set_shared_buffer(ctx); - - if (ctx->state == MFCINST_FINISHING) - cmd = S5P_FIMV_CH_LAST_FRAME; - else - cmd = S5P_FIMV_CH_FRAME_START; - mfc_write(dev, ((cmd & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) - | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); - - return 0; -} - -static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); - dev->curr_ctx = ctx->num; - s5p_mfc_decode_one_frame_v5(ctx, MFC_DEC_RES_CHANGE); -} - -static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *temp_vb; - - if (ctx->state == MFCINST_FINISHING) { - last_frame = MFC_DEC_LAST_FRAME; - s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); - dev->curr_ctx = ctx->num; - s5p_mfc_decode_one_frame_v5(ctx, last_frame); - return 0; - } - - /* Frames are being decoded */ - if (list_empty(&ctx->src_queue)) { - mfc_debug(2, "No src buffers\n"); - return -EAGAIN; - } - /* Get the next source buffer */ - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - temp_vb->flags |= MFC_BUF_FLAG_USED; - s5p_mfc_set_dec_stream_buffer_v5(ctx, - vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), - ctx->consumed_stream, temp_vb->b->vb2_buf.planes[0].bytesused); - dev->curr_ctx = ctx->num; - if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) { - last_frame = MFC_DEC_LAST_FRAME; - mfc_debug(2, "Setting ctx->state to FINISHING\n"); - ctx->state = MFCINST_FINISHING; - } - s5p_mfc_decode_one_frame_v5(ctx, last_frame); - return 0; -} - -static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *dst_mb; - struct s5p_mfc_buf *src_mb; - unsigned long src_y_addr, src_c_addr, dst_addr; - unsigned int dst_size; - - if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { - mfc_debug(2, "no src buffers\n"); - return -EAGAIN; - } - if (list_empty(&ctx->dst_queue)) { - mfc_debug(2, "no dst buffers\n"); - return -EAGAIN; - } - if (list_empty(&ctx->src_queue)) { - /* send null frame */ - s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->dma_base[BANK_R_CTX], - dev->dma_base[BANK_R_CTX]); - src_mb = NULL; - } else { - src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, - list); - src_mb->flags |= MFC_BUF_FLAG_USED; - if (src_mb->b->vb2_buf.planes[0].bytesused == 0) { - /* send null frame */ - s5p_mfc_set_enc_frame_buffer_v5(ctx, - dev->dma_base[BANK_R_CTX], - dev->dma_base[BANK_R_CTX]); - ctx->state = MFCINST_FINISHING; - } else { - src_y_addr = vb2_dma_contig_plane_dma_addr( - &src_mb->b->vb2_buf, 0); - src_c_addr = vb2_dma_contig_plane_dma_addr( - &src_mb->b->vb2_buf, 1); - s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr, - src_c_addr); - if (src_mb->flags & MFC_BUF_FLAG_EOS) - ctx->state = MFCINST_FINISHING; - } - } - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_mb->flags |= MFC_BUF_FLAG_USED; - dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); - dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); - s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); - dev->curr_ctx = ctx->num; - mfc_debug(2, "encoding buffer with index=%d state=%d\n", - src_mb ? src_mb->b->vb2_buf.index : -1, ctx->state); - s5p_mfc_encode_one_frame_v5(ctx); - return 0; -} - -static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *temp_vb; - - /* Initializing decoding - parsing header */ - mfc_debug(2, "Preparing to init decoding\n"); - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - s5p_mfc_set_dec_desc_buffer(ctx); - mfc_debug(2, "Header size: %d\n", - temp_vb->b->vb2_buf.planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer_v5(ctx, - vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), - 0, temp_vb->b->vb2_buf.planes[0].bytesused); - dev->curr_ctx = ctx->num; - s5p_mfc_init_decode_v5(ctx); -} - -static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *dst_mb; - unsigned long dst_addr; - unsigned int dst_size; - - s5p_mfc_set_enc_ref_buffer_v5(ctx); - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); - dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); - s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); - dev->curr_ctx = ctx->num; - s5p_mfc_init_encode_v5(ctx); -} - -static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *temp_vb; - int ret; - - /* - * Header was parsed now starting processing - * First set the output frame buffers - */ - if (ctx->capture_state != QUEUE_BUFS_MMAPED) { - mfc_err("It seems that not all destination buffers were mmapped\nMFC requires that all destination are mmapped before starting processing\n"); - return -EAGAIN; - } - if (list_empty(&ctx->src_queue)) { - mfc_err("Header has been deallocated in the middle of initialization\n"); - return -EIO; - } - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - mfc_debug(2, "Header size: %d\n", - temp_vb->b->vb2_buf.planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer_v5(ctx, - vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), - 0, temp_vb->b->vb2_buf.planes[0].bytesused); - dev->curr_ctx = ctx->num; - ret = s5p_mfc_set_dec_frame_buffer_v5(ctx); - if (ret) { - mfc_err("Failed to alloc frame mem\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -/* Try running an operation on hardware */ -static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_ctx *ctx; - int new_ctx; - unsigned int ret = 0; - - if (test_bit(0, &dev->enter_suspend)) { - mfc_debug(1, "Entering suspend so do not schedule any jobs\n"); - return; - } - /* Check whether hardware is not running */ - if (test_and_set_bit(0, &dev->hw_lock) != 0) { - /* This is perfectly ok, the scheduled ctx should wait */ - mfc_debug(1, "Couldn't lock HW\n"); - return; - } - /* Choose the context to run */ - new_ctx = s5p_mfc_get_new_ctx(dev); - if (new_ctx < 0) { - /* No contexts to run */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) { - mfc_err("Failed to unlock hardware\n"); - return; - } - mfc_debug(1, "No ctx is scheduled to be run\n"); - return; - } - ctx = dev->ctx[new_ctx]; - /* Got context to run in ctx */ - /* - * Last frame has already been sent to MFC. - * Now obtaining frames from MFC buffer - */ - s5p_mfc_clock_on(); - s5p_mfc_clean_ctx_int_flags(ctx); - - if (ctx->type == MFCINST_DECODER) { - s5p_mfc_set_dec_desc_buffer(ctx); - switch (ctx->state) { - case MFCINST_FINISHING: - s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME); - break; - case MFCINST_RUNNING: - ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); - break; - case MFCINST_INIT: - ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, - ctx); - break; - case MFCINST_RETURN_INST: - ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, - ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_dec(ctx); - break; - case MFCINST_HEAD_PARSED: - ret = s5p_mfc_run_init_dec_buffers(ctx); - mfc_debug(1, "head parsed\n"); - break; - case MFCINST_RES_CHANGE_INIT: - s5p_mfc_run_res_change(ctx); - break; - case MFCINST_RES_CHANGE_FLUSH: - s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); - break; - case MFCINST_RES_CHANGE_END: - mfc_debug(2, "Finished remaining frames after resolution change\n"); - ctx->capture_state = QUEUE_FREE; - mfc_debug(2, "Will re-init the codec\n"); - s5p_mfc_run_init_dec(ctx); - break; - default: - ret = -EAGAIN; - } - } else if (ctx->type == MFCINST_ENCODER) { - switch (ctx->state) { - case MFCINST_FINISHING: - case MFCINST_RUNNING: - ret = s5p_mfc_run_enc_frame(ctx); - break; - case MFCINST_INIT: - ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, - ctx); - break; - case MFCINST_RETURN_INST: - ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, - ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_enc(ctx); - break; - default: - ret = -EAGAIN; - } - } else { - mfc_err("Invalid context type: %d\n", ctx->type); - ret = -EAGAIN; - } - - if (ret) { - /* Free hardware lock */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - mfc_err("Failed to unlock hardware\n"); - - /* This is indeed important, as no operation has been - * scheduled, reduce the clock count as no one will - * ever do this, because no interrupt related to this try_run - * will ever come from hardware. */ - s5p_mfc_clock_off(); - } -} - -static void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev) -{ - mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); - mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); - mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID); -} - -static int s5p_mfc_get_dspl_y_adr_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_SI_DISPLAY_Y_ADR) << MFC_OFFSET_SHIFT; -} - -static int s5p_mfc_get_dec_y_adr_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_SI_DECODE_Y_ADR) << MFC_OFFSET_SHIFT; -} - -static int s5p_mfc_get_dspl_status_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_SI_DISPLAY_STATUS); -} - -static int s5p_mfc_get_dec_status_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_SI_DECODE_STATUS); -} - -static int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_DECODE_FRAME_TYPE) & - S5P_FIMV_DECODE_FRAME_MASK; -} - -static int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx) -{ - return (s5p_mfc_read_info_v5(ctx, DISP_PIC_FRAME_TYPE) >> - S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT) & - S5P_FIMV_DECODE_FRAME_MASK; -} - -static int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_SI_CONSUMED_BYTES); -} - -static int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev) -{ - int reason; - reason = mfc_read(dev, S5P_FIMV_RISC2HOST_CMD) & - S5P_FIMV_RISC2HOST_CMD_MASK; - switch (reason) { - case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: - reason = S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET; - break; - case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: - reason = S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET; - break; - case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: - reason = S5P_MFC_R2H_CMD_SEQ_DONE_RET; - break; - case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: - reason = S5P_MFC_R2H_CMD_FRAME_DONE_RET; - break; - case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: - reason = S5P_MFC_R2H_CMD_SLICE_DONE_RET; - break; - case S5P_FIMV_R2H_CMD_SYS_INIT_RET: - reason = S5P_MFC_R2H_CMD_SYS_INIT_RET; - break; - case S5P_FIMV_R2H_CMD_FW_STATUS_RET: - reason = S5P_MFC_R2H_CMD_FW_STATUS_RET; - break; - case S5P_FIMV_R2H_CMD_SLEEP_RET: - reason = S5P_MFC_R2H_CMD_SLEEP_RET; - break; - case S5P_FIMV_R2H_CMD_WAKEUP_RET: - reason = S5P_MFC_R2H_CMD_WAKEUP_RET; - break; - case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: - reason = S5P_MFC_R2H_CMD_INIT_BUFFERS_RET; - break; - case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET: - reason = S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET; - break; - case S5P_FIMV_R2H_CMD_ERR_RET: - reason = S5P_MFC_R2H_CMD_ERR_RET; - break; - default: - reason = S5P_MFC_R2H_CMD_EMPTY; - } - return reason; -} - -static int s5p_mfc_get_int_err_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG2); -} - -static int s5p_mfc_err_dec_v5(unsigned int err) -{ - return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT; -} - -static int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_SI_HRESOL); -} - -static int s5p_mfc_get_img_height_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_SI_VRESOL); -} - -static int s5p_mfc_get_dpb_count_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_SI_BUF_NUMBER); -} - -static int s5p_mfc_get_mv_count_v5(struct s5p_mfc_dev *dev) -{ - /* NOP */ - return -1; -} - -static int s5p_mfc_get_inst_no_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG1); -} - -static int s5p_mfc_get_enc_strm_size_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_ENC_SI_STRM_SIZE); -} - -static int s5p_mfc_get_enc_slice_type_v5(struct s5p_mfc_dev *dev) -{ - return mfc_read(dev, S5P_FIMV_ENC_SI_SLICE_TYPE); -} - -static int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev) -{ - return -1; -} - -static unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx) -{ - return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP); -} - -static unsigned int s5p_mfc_get_pic_type_bot_v5(struct s5p_mfc_ctx *ctx) -{ - return s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT); -} - -static unsigned int s5p_mfc_get_crop_info_h_v5(struct s5p_mfc_ctx *ctx) -{ - return s5p_mfc_read_info_v5(ctx, CROP_INFO_H); -} - -static unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx) -{ - return s5p_mfc_read_info_v5(ctx, CROP_INFO_V); -} - -/* Initialize opr function pointers for MFC v5 */ -static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { - .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v5, - .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v5, - .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v5, - .release_codec_buffers = s5p_mfc_release_codec_buffers_v5, - .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v5, - .release_instance_buffer = s5p_mfc_release_instance_buffer_v5, - .alloc_dev_context_buffer = s5p_mfc_alloc_dev_context_buffer_v5, - .release_dev_context_buffer = s5p_mfc_release_dev_context_buffer_v5, - .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v5, - .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v5, - .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v5, - .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v5, - .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v5, - .try_run = s5p_mfc_try_run_v5, - .clear_int_flags = s5p_mfc_clear_int_flags_v5, - .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v5, - .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v5, - .get_dspl_status = s5p_mfc_get_dspl_status_v5, - .get_dec_status = s5p_mfc_get_dec_status_v5, - .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v5, - .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v5, - .get_consumed_stream = s5p_mfc_get_consumed_stream_v5, - .get_int_reason = s5p_mfc_get_int_reason_v5, - .get_int_err = s5p_mfc_get_int_err_v5, - .err_dec = s5p_mfc_err_dec_v5, - .get_img_width = s5p_mfc_get_img_width_v5, - .get_img_height = s5p_mfc_get_img_height_v5, - .get_dpb_count = s5p_mfc_get_dpb_count_v5, - .get_mv_count = s5p_mfc_get_mv_count_v5, - .get_inst_no = s5p_mfc_get_inst_no_v5, - .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v5, - .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v5, - .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v5, - .get_pic_type_top = s5p_mfc_get_pic_type_top_v5, - .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v5, - .get_crop_info_h = s5p_mfc_get_crop_info_h_v5, - .get_crop_info_v = s5p_mfc_get_crop_info_v_v5, -}; - -struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void) -{ - return &s5p_mfc_ops_v5; -} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h deleted file mode 100644 index b53d376ead60..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.h +++ /dev/null @@ -1,82 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.h - * - * Header file for Samsung MFC (Multi Function Codec - FIMV) driver - * Contains declarations of hw related functions. - * - * Kamil Debski, Copyright (C) 2011 Samsung Electronics - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_OPR_V5_H_ -#define S5P_MFC_OPR_V5_H_ - -#include "s5p_mfc_common.h" -#include "s5p_mfc_opr.h" - -enum MFC_SHM_OFS { - EXTENEDED_DECODE_STATUS = 0x00, /* D */ - SET_FRAME_TAG = 0x04, /* D */ - GET_FRAME_TAG_TOP = 0x08, /* D */ - GET_FRAME_TAG_BOT = 0x0C, /* D */ - PIC_TIME_TOP = 0x10, /* D */ - PIC_TIME_BOT = 0x14, /* D */ - START_BYTE_NUM = 0x18, /* D */ - - CROP_INFO_H = 0x20, /* D */ - CROP_INFO_V = 0x24, /* D */ - EXT_ENC_CONTROL = 0x28, /* E */ - ENC_PARAM_CHANGE = 0x2C, /* E */ - RC_VOP_TIMING = 0x30, /* E, MPEG4 */ - HEC_PERIOD = 0x34, /* E, MPEG4 */ - METADATA_ENABLE = 0x38, /* C */ - METADATA_STATUS = 0x3C, /* C */ - METADATA_DISPLAY_INDEX = 0x40, /* C */ - EXT_METADATA_START_ADDR = 0x44, /* C */ - PUT_EXTRADATA = 0x48, /* C */ - EXTRADATA_ADDR = 0x4C, /* C */ - - ALLOC_LUMA_DPB_SIZE = 0x64, /* D */ - ALLOC_CHROMA_DPB_SIZE = 0x68, /* D */ - ALLOC_MV_SIZE = 0x6C, /* D */ - P_B_FRAME_QP = 0x70, /* E */ - SAMPLE_ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on - ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ - EXTENDED_SAR = 0x78, /* E, H.264, depned on - ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ - DISP_PIC_PROFILE = 0x7C, /* D */ - FLUSH_CMD_TYPE = 0x80, /* C */ - FLUSH_CMD_INBUF1 = 0x84, /* C */ - FLUSH_CMD_INBUF2 = 0x88, /* C */ - FLUSH_CMD_OUTBUF = 0x8C, /* E */ - NEW_RC_BIT_RATE = 0x90, /* E, format as RC_BIT_RATE(0xC5A8) - depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */ - NEW_RC_FRAME_RATE = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0) - depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */ - NEW_I_PERIOD = 0x98, /* E, format as I_FRM_CTRL(0xC504) - depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */ - H264_I_PERIOD = 0x9C, /* E, H.264, open GOP */ - RC_CONTROL_CONFIG = 0xA0, /* E */ - BATCH_INPUT_ADDR = 0xA4, /* E */ - BATCH_OUTPUT_ADDR = 0xA8, /* E */ - BATCH_OUTPUT_SIZE = 0xAC, /* E */ - MIN_LUMA_DPB_SIZE = 0xB0, /* D */ - DEVICE_FORMAT_ID = 0xB4, /* C */ - H264_POC_TYPE = 0xB8, /* D */ - MIN_CHROMA_DPB_SIZE = 0xBC, /* D */ - DISP_PIC_FRAME_TYPE = 0xC0, /* D */ - FREE_LUMA_DPB = 0xC4, /* D, VC1 MPEG4 */ - ASPECT_RATIO_INFO = 0xC8, /* D, MPEG4 */ - EXTENDED_PAR = 0xCC, /* D, MPEG4 */ - DBG_HISTORY_INPUT0 = 0xD0, /* C */ - DBG_HISTORY_INPUT1 = 0xD4, /* C */ - DBG_HISTORY_OUTPUT = 0xD8, /* C */ - HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */ - FRAME_PACK_SEI_ENABLE = 0x168, /* C */ - FRAME_PACK_SEI_AVAIL = 0x16c, /* D */ - FRAME_PACK_SEI_INFO = 0x17c, /* E */ -}; - -struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void); -#endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c deleted file mode 100644 index a1453053e31a..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ /dev/null @@ -1,2534 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c - * - * Samsung MFC (Multi Function Codec - FIMV) driver - * This file contains hw related functions. - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "s5p_mfc_common.h" -#include "s5p_mfc_cmd.h" -#include "s5p_mfc_intr.h" -#include "s5p_mfc_pm.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_opr.h" -#include "s5p_mfc_opr_v6.h" - -/* #define S5P_MFC_DEBUG_REGWRITE */ -#ifdef S5P_MFC_DEBUG_REGWRITE -#undef writel -#define writel(v, r) \ - do { \ - pr_err("MFCWRITE(%p): %08x\n", r, (unsigned int)v); \ - __raw_writel(v, r); \ - } while (0) -#endif /* S5P_MFC_DEBUG_REGWRITE */ - -#define IS_MFCV6_V2(dev) (!IS_MFCV7_PLUS(dev) && dev->fw_ver == MFC_FW_V2) - -/* Allocate temporary buffers for decoding */ -static int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) -{ - /* NOP */ - - return 0; -} - -/* Release temporary buffers for decoding */ -static void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) -{ - /* NOP */ -} - -/* Allocate codec buffers */ -static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - unsigned int mb_width, mb_height; - unsigned int lcu_width = 0, lcu_height = 0; - int ret; - - mb_width = MB_WIDTH(ctx->img_width); - mb_height = MB_HEIGHT(ctx->img_height); - - if (ctx->type == MFCINST_DECODER) { - mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", - ctx->luma_size, ctx->chroma_size, ctx->mv_size); - mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); - } else if (ctx->type == MFCINST_ENCODER) { - if (IS_MFCV10(dev)) { - ctx->tmv_buffer_size = 0; - } else if (IS_MFCV8_PLUS(dev)) - ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * - ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V8(mb_width, mb_height), - S5P_FIMV_TMV_BUFFER_ALIGN_V6); - else - ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * - ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), - S5P_FIMV_TMV_BUFFER_ALIGN_V6); - if (IS_MFCV10(dev)) { - lcu_width = S5P_MFC_LCU_WIDTH(ctx->img_width); - lcu_height = S5P_MFC_LCU_HEIGHT(ctx->img_height); - if (ctx->codec_mode != S5P_FIMV_CODEC_HEVC_ENC) { - ctx->luma_dpb_size = - ALIGN((mb_width * 16), 64) - * ALIGN((mb_height * 16), 32) - + 64; - ctx->chroma_dpb_size = - ALIGN((mb_width * 16), 64) - * (mb_height * 8) - + 64; - } else { - ctx->luma_dpb_size = - ALIGN((lcu_width * 32), 64) - * ALIGN((lcu_height * 32), 32) - + 64; - ctx->chroma_dpb_size = - ALIGN((lcu_width * 32), 64) - * (lcu_height * 16) - + 64; - } - } else { - ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * - S5P_FIMV_LUMA_MB_TO_PIXEL_V6, - S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); - ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * - S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, - S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); - } - if (IS_MFCV8_PLUS(dev)) - ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V8( - ctx->img_width, ctx->img_height, - mb_width, mb_height), - S5P_FIMV_ME_BUFFER_ALIGN_V6); - else - ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6( - ctx->img_width, ctx->img_height, - mb_width, mb_height), - S5P_FIMV_ME_BUFFER_ALIGN_V6); - - mfc_debug(2, "recon luma size: %zu chroma size: %zu\n", - ctx->luma_dpb_size, ctx->chroma_dpb_size); - } else { - return -EINVAL; - } - - /* Codecs have different memory requirements */ - switch (ctx->codec_mode) { - case S5P_MFC_CODEC_H264_DEC: - case S5P_MFC_CODEC_H264_MVC_DEC: - if (IS_MFCV10(dev)) - mfc_debug(2, "Use min scratch buffer size\n"); - else if (IS_MFCV8_PLUS(dev)) - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8( - mb_width, - mb_height); - else - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6( - mb_width, - mb_height); - ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, - S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); - ctx->bank1.size = - ctx->scratch_buf_size + - (ctx->mv_count * ctx->mv_size); - break; - case S5P_MFC_CODEC_MPEG4_DEC: - if (IS_MFCV10(dev)) - mfc_debug(2, "Use min scratch buffer size\n"); - else if (IS_MFCV7_PLUS(dev)) { - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7( - mb_width, - mb_height); - } else { - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6( - mb_width, - mb_height); - } - - ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, - S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); - ctx->bank1.size = ctx->scratch_buf_size; - break; - case S5P_MFC_CODEC_VC1RCV_DEC: - case S5P_MFC_CODEC_VC1_DEC: - if (IS_MFCV10(dev)) - mfc_debug(2, "Use min scratch buffer size\n"); - else - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( - mb_width, - mb_height); - - ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, - S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); - ctx->bank1.size = ctx->scratch_buf_size; - break; - case S5P_MFC_CODEC_MPEG2_DEC: - ctx->bank1.size = 0; - ctx->bank2.size = 0; - break; - case S5P_MFC_CODEC_H263_DEC: - if (IS_MFCV10(dev)) - mfc_debug(2, "Use min scratch buffer size\n"); - else - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( - mb_width, - mb_height); - ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, - S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); - ctx->bank1.size = ctx->scratch_buf_size; - break; - case S5P_MFC_CODEC_VP8_DEC: - if (IS_MFCV10(dev)) - mfc_debug(2, "Use min scratch buffer size\n"); - else if (IS_MFCV8_PLUS(dev)) - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8( - mb_width, - mb_height); - else - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6( - mb_width, - mb_height); - ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, - S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); - ctx->bank1.size = ctx->scratch_buf_size; - break; - case S5P_MFC_CODEC_HEVC_DEC: - mfc_debug(2, "Use min scratch buffer size\n"); - ctx->bank1.size = - ctx->scratch_buf_size + - (ctx->mv_count * ctx->mv_size); - break; - case S5P_MFC_CODEC_VP9_DEC: - mfc_debug(2, "Use min scratch buffer size\n"); - ctx->bank1.size = - ctx->scratch_buf_size + - DEC_VP9_STATIC_BUFFER_SIZE; - break; - case S5P_MFC_CODEC_H264_ENC: - if (IS_MFCV10(dev)) { - mfc_debug(2, "Use min scratch buffer size\n"); - ctx->me_buffer_size = - ALIGN(ENC_V100_H264_ME_SIZE(mb_width, mb_height), 16); - } else if (IS_MFCV8_PLUS(dev)) - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8( - mb_width, - mb_height); - else - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6( - mb_width, - mb_height); - ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, - S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); - ctx->bank1.size = - ctx->scratch_buf_size + ctx->tmv_buffer_size + - (ctx->pb_count * (ctx->luma_dpb_size + - ctx->chroma_dpb_size + ctx->me_buffer_size)); - ctx->bank2.size = 0; - break; - case S5P_MFC_CODEC_MPEG4_ENC: - case S5P_MFC_CODEC_H263_ENC: - if (IS_MFCV10(dev)) { - mfc_debug(2, "Use min scratch buffer size\n"); - ctx->me_buffer_size = - ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width, - mb_height), 16); - } else - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( - mb_width, - mb_height); - ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, - S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); - ctx->bank1.size = - ctx->scratch_buf_size + ctx->tmv_buffer_size + - (ctx->pb_count * (ctx->luma_dpb_size + - ctx->chroma_dpb_size + ctx->me_buffer_size)); - ctx->bank2.size = 0; - break; - case S5P_MFC_CODEC_VP8_ENC: - if (IS_MFCV10(dev)) { - mfc_debug(2, "Use min scratch buffer size\n"); - ctx->me_buffer_size = - ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height), - 16); - } else if (IS_MFCV8_PLUS(dev)) - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8( - mb_width, - mb_height); - else - ctx->scratch_buf_size = - S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V7( - mb_width, - mb_height); - ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, - S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); - ctx->bank1.size = - ctx->scratch_buf_size + ctx->tmv_buffer_size + - (ctx->pb_count * (ctx->luma_dpb_size + - ctx->chroma_dpb_size + ctx->me_buffer_size)); - ctx->bank2.size = 0; - break; - case S5P_MFC_CODEC_HEVC_ENC: - mfc_debug(2, "Use min scratch buffer size\n"); - ctx->me_buffer_size = - ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 16); - ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256); - ctx->bank1.size = - ctx->scratch_buf_size + ctx->tmv_buffer_size + - (ctx->pb_count * (ctx->luma_dpb_size + - ctx->chroma_dpb_size + ctx->me_buffer_size)); - ctx->bank2.size = 0; - break; - default: - break; - } - - /* Allocate only if memory from bank 1 is necessary */ - if (ctx->bank1.size > 0) { - ret = s5p_mfc_alloc_generic_buf(dev, BANK_L_CTX, &ctx->bank1); - if (ret) { - mfc_err("Failed to allocate Bank1 memory\n"); - return ret; - } - BUG_ON(ctx->bank1.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); - } - return 0; -} - -/* Release buffers allocated for codec */ -static void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) -{ - s5p_mfc_release_generic_buf(ctx->dev, &ctx->bank1); -} - -/* Allocate memory for instance data buffer */ -static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; - int ret; - - mfc_debug_enter(); - - switch (ctx->codec_mode) { - case S5P_MFC_CODEC_H264_DEC: - case S5P_MFC_CODEC_H264_MVC_DEC: - case S5P_MFC_CODEC_HEVC_DEC: - ctx->ctx.size = buf_size->h264_dec_ctx; - break; - case S5P_MFC_CODEC_MPEG4_DEC: - case S5P_MFC_CODEC_H263_DEC: - case S5P_MFC_CODEC_VC1RCV_DEC: - case S5P_MFC_CODEC_VC1_DEC: - case S5P_MFC_CODEC_MPEG2_DEC: - case S5P_MFC_CODEC_VP8_DEC: - case S5P_MFC_CODEC_VP9_DEC: - ctx->ctx.size = buf_size->other_dec_ctx; - break; - case S5P_MFC_CODEC_H264_ENC: - ctx->ctx.size = buf_size->h264_enc_ctx; - break; - case S5P_MFC_CODEC_HEVC_ENC: - ctx->ctx.size = buf_size->hevc_enc_ctx; - break; - case S5P_MFC_CODEC_MPEG4_ENC: - case S5P_MFC_CODEC_H263_ENC: - case S5P_MFC_CODEC_VP8_ENC: - ctx->ctx.size = buf_size->other_enc_ctx; - break; - default: - ctx->ctx.size = 0; - mfc_err("Codec type(%d) should be checked!\n", ctx->codec_mode); - break; - } - - ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->ctx); - if (ret) { - mfc_err("Failed to allocate instance buffer\n"); - return ret; - } - - memset(ctx->ctx.virt, 0, ctx->ctx.size); - wmb(); - - mfc_debug_leave(); - - return 0; -} - -/* Release instance buffer */ -static void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) -{ - s5p_mfc_release_priv_buf(ctx->dev, &ctx->ctx); -} - -/* Allocate context buffers for SYS_INIT */ -static int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; - int ret; - - mfc_debug_enter(); - - dev->ctx_buf.size = buf_size->dev_ctx; - ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &dev->ctx_buf); - if (ret) { - mfc_err("Failed to allocate device context buffer\n"); - return ret; - } - - memset(dev->ctx_buf.virt, 0, buf_size->dev_ctx); - wmb(); - - mfc_debug_leave(); - - return 0; -} - -/* Release context buffers for SYS_INIT */ -static void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) -{ - s5p_mfc_release_priv_buf(dev, &dev->ctx_buf); -} - -static int calc_plane(int width, int height) -{ - int mbX, mbY; - - mbX = DIV_ROUND_UP(width, S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); - mbY = DIV_ROUND_UP(height, S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6); - - if (width * height < S5P_FIMV_MAX_FRAME_SIZE_V6) - mbY = (mbY + 1) / 2 * 2; - - return (mbX * S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6) * - (mbY * S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); -} - -static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); - ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); - mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n" - "buffer dimensions: %dx%d\n", ctx->img_width, - ctx->img_height, ctx->buf_width, ctx->buf_height); - - ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height); - ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1)); - if (IS_MFCV8_PLUS(ctx->dev)) { - /* MFCv8 needs additional 64 bytes for luma,chroma dpb*/ - ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; - ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; - } - - if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || - ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { - if (IS_MFCV10(dev)) { - ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V10(ctx->img_width, - ctx->img_height); - } else { - ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, - ctx->img_height); - } - } else if (ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { - ctx->mv_size = s5p_mfc_dec_hevc_mv_size(ctx->img_width, - ctx->img_height); - ctx->mv_size = ALIGN(ctx->mv_size, 32); - } else { - ctx->mv_size = 0; - } -} - -static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx) -{ - unsigned int mb_width, mb_height; - - mb_width = MB_WIDTH(ctx->img_width); - mb_height = MB_HEIGHT(ctx->img_height); - - ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6); - ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256); - ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256); - - /* MFCv7 needs pad bytes for Luma and Chroma */ - if (IS_MFCV7_PLUS(ctx->dev)) { - ctx->luma_size += MFC_LUMA_PAD_BYTES_V7; - ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7; - } -} - -/* Set registers for decoding stream buffer */ -static int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, - int buf_addr, unsigned int start_num_byte, - unsigned int strm_size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; - - mfc_debug_enter(); - mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n" - "buf_size: 0x%08x (%d)\n", - ctx->inst_no, buf_addr, strm_size, strm_size); - writel(strm_size, mfc_regs->d_stream_data_size); - writel(buf_addr, mfc_regs->d_cpb_buffer_addr); - writel(buf_size->cpb, mfc_regs->d_cpb_buffer_size); - writel(start_num_byte, mfc_regs->d_cpb_buffer_offset); - - mfc_debug_leave(); - return 0; -} - -/* Set decoding frame buffer */ -static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) -{ - unsigned int frame_size, i; - unsigned int frame_size_ch, frame_size_mv; - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - size_t buf_addr1; - int buf_size1; - int align_gap; - - buf_addr1 = ctx->bank1.dma; - buf_size1 = ctx->bank1.size; - - mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); - mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count); - mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay); - - writel(ctx->total_dpb_count, mfc_regs->d_num_dpb); - writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size); - writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size); - - writel(buf_addr1, mfc_regs->d_scratch_buffer_addr); - writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size); - - if (IS_MFCV8_PLUS(dev)) { - writel(ctx->img_width, - mfc_regs->d_first_plane_dpb_stride_size); - writel(ctx->img_width, - mfc_regs->d_second_plane_dpb_stride_size); - } - - buf_addr1 += ctx->scratch_buf_size; - buf_size1 -= ctx->scratch_buf_size; - - if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC || - ctx->codec_mode == S5P_FIMV_CODEC_HEVC_DEC) { - writel(ctx->mv_size, mfc_regs->d_mv_buffer_size); - writel(ctx->mv_count, mfc_regs->d_num_mv); - } - - frame_size = ctx->luma_size; - frame_size_ch = ctx->chroma_size; - frame_size_mv = ctx->mv_size; - mfc_debug(2, "Frame size: %d ch: %d mv: %d\n", - frame_size, frame_size_ch, frame_size_mv); - - for (i = 0; i < ctx->total_dpb_count; i++) { - /* Bank2 */ - mfc_debug(2, "Luma %d: %zx\n", i, - ctx->dst_bufs[i].cookie.raw.luma); - writel(ctx->dst_bufs[i].cookie.raw.luma, - mfc_regs->d_first_plane_dpb + i * 4); - mfc_debug(2, "\tChroma %d: %zx\n", i, - ctx->dst_bufs[i].cookie.raw.chroma); - writel(ctx->dst_bufs[i].cookie.raw.chroma, - mfc_regs->d_second_plane_dpb + i * 4); - } - if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || - ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC || - ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { - for (i = 0; i < ctx->mv_count; i++) { - /* To test alignment */ - align_gap = buf_addr1; - buf_addr1 = ALIGN(buf_addr1, 16); - align_gap = buf_addr1 - align_gap; - buf_size1 -= align_gap; - - mfc_debug(2, "\tBuf1: %zx, size: %d\n", - buf_addr1, buf_size1); - writel(buf_addr1, mfc_regs->d_mv_buffer + i * 4); - buf_addr1 += frame_size_mv; - buf_size1 -= frame_size_mv; - } - } - if (ctx->codec_mode == S5P_FIMV_CODEC_VP9_DEC) { - writel(buf_addr1, mfc_regs->d_static_buffer_addr); - writel(DEC_VP9_STATIC_BUFFER_SIZE, - mfc_regs->d_static_buffer_size); - buf_addr1 += DEC_VP9_STATIC_BUFFER_SIZE; - buf_size1 -= DEC_VP9_STATIC_BUFFER_SIZE; - } - - mfc_debug(2, "Buf1: %zx, buf_size1: %d (frames %d)\n", - buf_addr1, buf_size1, ctx->total_dpb_count); - if (buf_size1 < 0) { - mfc_debug(2, "Not enough memory has been allocated.\n"); - return -ENOMEM; - } - - writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, - S5P_FIMV_CH_INIT_BUFS_V6, NULL); - - mfc_debug(2, "After setting buffers.\n"); - return 0; -} - -/* Set registers for encoding stream buffer */ -static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, - unsigned long addr, unsigned int size) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - - writel(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */ - writel(size, mfc_regs->e_stream_buffer_size); - - mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%x\n", - addr, size); - - return 0; -} - -static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, - unsigned long y_addr, unsigned long c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - - writel(y_addr, mfc_regs->e_source_first_plane_addr); - writel(c_addr, mfc_regs->e_source_second_plane_addr); - - mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr); - mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr); -} - -static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, - unsigned long *y_addr, unsigned long *c_addr) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - unsigned long enc_recon_y_addr, enc_recon_c_addr; - - *y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr); - *c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr); - - enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr); - enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr); - - mfc_debug(2, "recon y addr: 0x%08lx y_addr: 0x%08lx\n", enc_recon_y_addr, *y_addr); - mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr); -} - -/* Set encoding ref & codec buffer */ -static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - size_t buf_addr1; - int i, buf_size1; - - mfc_debug_enter(); - - buf_addr1 = ctx->bank1.dma; - buf_size1 = ctx->bank1.size; - - mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); - - if (IS_MFCV10(dev)) { - /* start address of per buffer is aligned */ - for (i = 0; i < ctx->pb_count; i++) { - writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); - buf_addr1 += ctx->luma_dpb_size; - buf_size1 -= ctx->luma_dpb_size; - } - for (i = 0; i < ctx->pb_count; i++) { - writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); - buf_addr1 += ctx->chroma_dpb_size; - buf_size1 -= ctx->chroma_dpb_size; - } - for (i = 0; i < ctx->pb_count; i++) { - writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); - buf_addr1 += ctx->me_buffer_size; - buf_size1 -= ctx->me_buffer_size; - } - } else { - for (i = 0; i < ctx->pb_count; i++) { - writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); - buf_addr1 += ctx->luma_dpb_size; - writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); - buf_addr1 += ctx->chroma_dpb_size; - writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); - buf_addr1 += ctx->me_buffer_size; - buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size - + ctx->me_buffer_size); - } - } - - writel(buf_addr1, mfc_regs->e_scratch_buffer_addr); - writel(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size); - buf_addr1 += ctx->scratch_buf_size; - buf_size1 -= ctx->scratch_buf_size; - - writel(buf_addr1, mfc_regs->e_tmv_buffer0); - buf_addr1 += ctx->tmv_buffer_size >> 1; - writel(buf_addr1, mfc_regs->e_tmv_buffer1); - buf_addr1 += ctx->tmv_buffer_size >> 1; - buf_size1 -= ctx->tmv_buffer_size; - - mfc_debug(2, "Buf1: %zu, buf_size1: %d (ref frames %d)\n", - buf_addr1, buf_size1, ctx->pb_count); - if (buf_size1 < 0) { - mfc_debug(2, "Not enough memory has been allocated.\n"); - return -ENOMEM; - } - - writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, - S5P_FIMV_CH_INIT_BUFS_V6, NULL); - - mfc_debug_leave(); - - return 0; -} - -static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - - /* multi-slice control */ - /* multi-slice MB number or bit size */ - writel(ctx->slice_mode, mfc_regs->e_mslice_mode); - if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { - writel(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb); - } else if (ctx->slice_mode == - V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { - writel(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits); - } else { - writel(0x0, mfc_regs->e_mslice_size_mb); - writel(0x0, mfc_regs->e_mslice_size_bits); - } - - return 0; -} - -static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - unsigned int reg = 0; - - mfc_debug_enter(); - - /* width */ - writel(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */ - /* height */ - writel(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */ - - /* cropped width */ - writel(ctx->img_width, mfc_regs->e_cropped_frame_width); - /* cropped height */ - writel(ctx->img_height, mfc_regs->e_cropped_frame_height); - /* cropped offset */ - writel(0x0, mfc_regs->e_frame_crop_offset); - - /* pictype : IDR period */ - reg = 0; - reg |= p->gop_size & 0xFFFF; - writel(reg, mfc_regs->e_gop_config); - - /* multi-slice control */ - /* multi-slice MB number or bit size */ - ctx->slice_mode = p->slice_mode; - reg = 0; - if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { - reg |= (0x1 << 3); - writel(reg, mfc_regs->e_enc_options); - ctx->slice_size.mb = p->slice_mb; - } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { - reg |= (0x1 << 3); - writel(reg, mfc_regs->e_enc_options); - ctx->slice_size.bits = p->slice_bit; - } else { - reg &= ~(0x1 << 3); - writel(reg, mfc_regs->e_enc_options); - } - - s5p_mfc_set_slice_mode(ctx); - - /* cyclic intra refresh */ - writel(p->intra_refresh_mb, mfc_regs->e_ir_size); - reg = readl(mfc_regs->e_enc_options); - if (p->intra_refresh_mb == 0) - reg &= ~(0x1 << 4); - else - reg |= (0x1 << 4); - writel(reg, mfc_regs->e_enc_options); - - /* 'NON_REFERENCE_STORE_ENABLE' for debugging */ - reg = readl(mfc_regs->e_enc_options); - reg &= ~(0x1 << 9); - writel(reg, mfc_regs->e_enc_options); - - /* memory structure cur. frame */ - if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { - /* 0: Linear, 1: 2D tiled*/ - reg = readl(mfc_regs->e_enc_options); - reg &= ~(0x1 << 7); - writel(reg, mfc_regs->e_enc_options); - /* 0: NV12(CbCr), 1: NV21(CrCb) */ - writel(0x0, mfc_regs->pixel_format); - } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) { - /* 0: Linear, 1: 2D tiled*/ - reg = readl(mfc_regs->e_enc_options); - reg &= ~(0x1 << 7); - writel(reg, mfc_regs->e_enc_options); - /* 0: NV12(CbCr), 1: NV21(CrCb) */ - writel(0x1, mfc_regs->pixel_format); - } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) { - /* 0: Linear, 1: 2D tiled*/ - reg = readl(mfc_regs->e_enc_options); - reg |= (0x1 << 7); - writel(reg, mfc_regs->e_enc_options); - /* 0: NV12(CbCr), 1: NV21(CrCb) */ - writel(0x0, mfc_regs->pixel_format); - } - - /* memory structure recon. frame */ - /* 0: Linear, 1: 2D tiled */ - reg = readl(mfc_regs->e_enc_options); - reg |= (0x1 << 8); - writel(reg, mfc_regs->e_enc_options); - - /* padding control & value */ - writel(0x0, mfc_regs->e_padding_ctrl); - if (p->pad) { - reg = 0; - /** enable */ - reg |= (1UL << 31); - /** cr value */ - reg |= ((p->pad_cr & 0xFF) << 16); - /** cb value */ - reg |= ((p->pad_cb & 0xFF) << 8); - /** y value */ - reg |= p->pad_luma & 0xFF; - writel(reg, mfc_regs->e_padding_ctrl); - } - - /* rate control config. */ - reg = 0; - /* frame-level rate control */ - reg |= ((p->rc_frame & 0x1) << 9); - writel(reg, mfc_regs->e_rc_config); - - /* bit rate */ - if (p->rc_frame) - writel(p->rc_bitrate, - mfc_regs->e_rc_bit_rate); - else - writel(1, mfc_regs->e_rc_bit_rate); - - /* reaction coefficient */ - if (p->rc_frame) { - if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */ - writel(1, mfc_regs->e_rc_mode); - else /* loose CBR */ - writel(2, mfc_regs->e_rc_mode); - } - - /* seq header ctrl */ - reg = readl(mfc_regs->e_enc_options); - reg &= ~(0x1 << 2); - reg |= ((p->seq_hdr_mode & 0x1) << 2); - - /* frame skip mode */ - reg &= ~(0x3); - reg |= (p->frame_skip_mode & 0x3); - writel(reg, mfc_regs->e_enc_options); - - /* 'DROP_CONTROL_ENABLE', disable */ - reg = readl(mfc_regs->e_rc_config); - reg &= ~(0x1 << 10); - writel(reg, mfc_regs->e_rc_config); - - /* setting for MV range [16, 256] */ - reg = (p->mv_h_range & S5P_FIMV_E_MV_RANGE_V6_MASK); - writel(reg, mfc_regs->e_mv_hor_range); - - reg = (p->mv_v_range & S5P_FIMV_E_MV_RANGE_V6_MASK); - writel(reg, mfc_regs->e_mv_ver_range); - - writel(0x0, mfc_regs->e_frame_insertion); - writel(0x0, mfc_regs->e_roi_buffer_addr); - writel(0x0, mfc_regs->e_param_change); - writel(0x0, mfc_regs->e_rc_roi_ctrl); - writel(0x0, mfc_regs->e_picture_tag); - - writel(0x0, mfc_regs->e_bit_count_enable); - writel(0x0, mfc_regs->e_max_bit_count); - writel(0x0, mfc_regs->e_min_bit_count); - - writel(0x0, mfc_regs->e_metadata_buffer_addr); - writel(0x0, mfc_regs->e_metadata_buffer_size); - - mfc_debug_leave(); - - return 0; -} - -static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; - unsigned int reg = 0; - int i; - - mfc_debug_enter(); - - s5p_mfc_set_enc_params(ctx); - - /* pictype : number of B */ - reg = readl(mfc_regs->e_gop_config); - reg &= ~(0x3 << 16); - reg |= ((p->num_b_frame & 0x3) << 16); - writel(reg, mfc_regs->e_gop_config); - - /* profile & level */ - reg = 0; - /** level */ - reg |= ((p_h264->level & 0xFF) << 8); - /** profile - 0 ~ 3 */ - reg |= p_h264->profile & 0x3F; - writel(reg, mfc_regs->e_picture_profile); - - /* rate control config. */ - reg = readl(mfc_regs->e_rc_config); - /** macroblock level rate control */ - reg &= ~(0x1 << 8); - reg |= ((p->rc_mb & 0x1) << 8); - writel(reg, mfc_regs->e_rc_config); - - /** frame QP */ - reg &= ~(0x3F); - reg |= p_h264->rc_frame_qp & 0x3F; - writel(reg, mfc_regs->e_rc_config); - - /* max & min value of QP */ - reg = 0; - /** max QP */ - reg |= ((p_h264->rc_max_qp & 0x3F) << 8); - /** min QP */ - reg |= p_h264->rc_min_qp & 0x3F; - writel(reg, mfc_regs->e_rc_qp_bound); - - /* other QPs */ - writel(0x0, mfc_regs->e_fixed_picture_qp); - if (!p->rc_frame && !p->rc_mb) { - reg = 0; - reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16); - reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8); - reg |= p_h264->rc_frame_qp & 0x3F; - writel(reg, mfc_regs->e_fixed_picture_qp); - } - - /* frame rate */ - if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { - reg = 0; - reg |= ((p->rc_framerate_num & 0xFFFF) << 16); - reg |= p->rc_framerate_denom & 0xFFFF; - writel(reg, mfc_regs->e_rc_frame_rate); - } - - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - writel(p_h264->cpb_size & 0xFFFF, - mfc_regs->e_vbv_buffer_size); - - if (p->rc_frame) - writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); - } - - /* interlace */ - reg = 0; - reg |= ((p_h264->interlace & 0x1) << 3); - writel(reg, mfc_regs->e_h264_options); - - /* height */ - if (p_h264->interlace) { - writel(ctx->img_height >> 1, - mfc_regs->e_frame_height); /* 32 align */ - /* cropped height */ - writel(ctx->img_height >> 1, - mfc_regs->e_cropped_frame_height); - } - - /* loop filter ctrl */ - reg = readl(mfc_regs->e_h264_options); - reg &= ~(0x3 << 1); - reg |= ((p_h264->loop_filter_mode & 0x3) << 1); - writel(reg, mfc_regs->e_h264_options); - - /* loopfilter alpha offset */ - if (p_h264->loop_filter_alpha < 0) { - reg = 0x10; - reg |= (0xFF - p_h264->loop_filter_alpha) + 1; - } else { - reg = 0x00; - reg |= (p_h264->loop_filter_alpha & 0xF); - } - writel(reg, mfc_regs->e_h264_lf_alpha_offset); - - /* loopfilter beta offset */ - if (p_h264->loop_filter_beta < 0) { - reg = 0x10; - reg |= (0xFF - p_h264->loop_filter_beta) + 1; - } else { - reg = 0x00; - reg |= (p_h264->loop_filter_beta & 0xF); - } - writel(reg, mfc_regs->e_h264_lf_beta_offset); - - /* entropy coding mode */ - reg = readl(mfc_regs->e_h264_options); - reg &= ~(0x1); - reg |= p_h264->entropy_mode & 0x1; - writel(reg, mfc_regs->e_h264_options); - - /* number of ref. picture */ - reg = readl(mfc_regs->e_h264_options); - reg &= ~(0x1 << 7); - reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7); - writel(reg, mfc_regs->e_h264_options); - - /* 8x8 transform enable */ - reg = readl(mfc_regs->e_h264_options); - reg &= ~(0x3 << 12); - reg |= ((p_h264->_8x8_transform & 0x3) << 12); - writel(reg, mfc_regs->e_h264_options); - - /* macroblock adaptive scaling features */ - writel(0x0, mfc_regs->e_mb_rc_config); - if (p->rc_mb) { - reg = 0; - /** dark region */ - reg |= ((p_h264->rc_mb_dark & 0x1) << 3); - /** smooth region */ - reg |= ((p_h264->rc_mb_smooth & 0x1) << 2); - /** static region */ - reg |= ((p_h264->rc_mb_static & 0x1) << 1); - /** high activity region */ - reg |= p_h264->rc_mb_activity & 0x1; - writel(reg, mfc_regs->e_mb_rc_config); - } - - /* aspect ratio VUI */ - readl(mfc_regs->e_h264_options); - reg &= ~(0x1 << 5); - reg |= ((p_h264->vui_sar & 0x1) << 5); - writel(reg, mfc_regs->e_h264_options); - - writel(0x0, mfc_regs->e_aspect_ratio); - writel(0x0, mfc_regs->e_extended_sar); - if (p_h264->vui_sar) { - /* aspect ration IDC */ - reg = 0; - reg |= p_h264->vui_sar_idc & 0xFF; - writel(reg, mfc_regs->e_aspect_ratio); - if (p_h264->vui_sar_idc == 0xFF) { - /* extended SAR */ - reg = 0; - reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16; - reg |= p_h264->vui_ext_sar_height & 0xFFFF; - writel(reg, mfc_regs->e_extended_sar); - } - } - - /* intra picture period for H.264 open GOP */ - /* control */ - readl(mfc_regs->e_h264_options); - reg &= ~(0x1 << 4); - reg |= ((p_h264->open_gop & 0x1) << 4); - writel(reg, mfc_regs->e_h264_options); - - /* value */ - writel(0x0, mfc_regs->e_h264_i_period); - if (p_h264->open_gop) { - reg = 0; - reg |= p_h264->open_gop_size & 0xFFFF; - writel(reg, mfc_regs->e_h264_i_period); - } - - /* 'WEIGHTED_BI_PREDICTION' for B is disable */ - readl(mfc_regs->e_h264_options); - reg &= ~(0x3 << 9); - writel(reg, mfc_regs->e_h264_options); - - /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */ - readl(mfc_regs->e_h264_options); - reg &= ~(0x1 << 14); - writel(reg, mfc_regs->e_h264_options); - - /* ASO */ - readl(mfc_regs->e_h264_options); - reg &= ~(0x1 << 6); - reg |= ((p_h264->aso & 0x1) << 6); - writel(reg, mfc_regs->e_h264_options); - - /* hier qp enable */ - readl(mfc_regs->e_h264_options); - reg &= ~(0x1 << 8); - reg |= ((p_h264->open_gop & 0x1) << 8); - writel(reg, mfc_regs->e_h264_options); - reg = 0; - if (p_h264->hier_qp && p_h264->hier_qp_layer) { - reg |= (p_h264->hier_qp_type & 0x1) << 0x3; - reg |= p_h264->hier_qp_layer & 0x7; - writel(reg, mfc_regs->e_h264_num_t_layer); - /* QP value for each layer */ - for (i = 0; i < p_h264->hier_qp_layer && - i < ARRAY_SIZE(p_h264->hier_qp_layer_qp); i++) { - writel(p_h264->hier_qp_layer_qp[i], - mfc_regs->e_h264_hierarchical_qp_layer0 - + i * 4); - } - } - /* number of coding layer should be zero when hierarchical is disable */ - writel(reg, mfc_regs->e_h264_num_t_layer); - - /* frame packing SEI generation */ - readl(mfc_regs->e_h264_options); - reg &= ~(0x1 << 25); - reg |= ((p_h264->sei_frame_packing & 0x1) << 25); - writel(reg, mfc_regs->e_h264_options); - if (p_h264->sei_frame_packing) { - reg = 0; - /** current frame0 flag */ - reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2); - /** arrangement type */ - reg |= p_h264->sei_fp_arrangement_type & 0x3; - writel(reg, mfc_regs->e_h264_frame_packing_sei_info); - } - - if (p_h264->fmo) { - switch (p_h264->fmo_map_type) { - case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES: - if (p_h264->fmo_slice_grp > 4) - p_h264->fmo_slice_grp = 4; - for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++) - writel(p_h264->fmo_run_len[i] - 1, - mfc_regs->e_h264_fmo_run_length_minus1_0 - + i * 4); - break; - case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES: - if (p_h264->fmo_slice_grp > 4) - p_h264->fmo_slice_grp = 4; - break; - case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN: - case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN: - if (p_h264->fmo_slice_grp > 2) - p_h264->fmo_slice_grp = 2; - writel(p_h264->fmo_chg_dir & 0x1, - mfc_regs->e_h264_fmo_slice_grp_change_dir); - /* the valid range is 0 ~ number of macroblocks -1 */ - writel(p_h264->fmo_chg_rate, - mfc_regs->e_h264_fmo_slice_grp_change_rate_minus1); - break; - default: - mfc_err("Unsupported map type for FMO: %d\n", - p_h264->fmo_map_type); - p_h264->fmo_map_type = 0; - p_h264->fmo_slice_grp = 1; - break; - } - - writel(p_h264->fmo_map_type, - mfc_regs->e_h264_fmo_slice_grp_map_type); - writel(p_h264->fmo_slice_grp - 1, - mfc_regs->e_h264_fmo_num_slice_grp_minus1); - } else { - writel(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1); - } - - mfc_debug_leave(); - - return 0; -} - -static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; - unsigned int reg = 0; - - mfc_debug_enter(); - - s5p_mfc_set_enc_params(ctx); - - /* pictype : number of B */ - reg = readl(mfc_regs->e_gop_config); - reg &= ~(0x3 << 16); - reg |= ((p->num_b_frame & 0x3) << 16); - writel(reg, mfc_regs->e_gop_config); - - /* profile & level */ - reg = 0; - /** level */ - reg |= ((p_mpeg4->level & 0xFF) << 8); - /** profile - 0 ~ 1 */ - reg |= p_mpeg4->profile & 0x3F; - writel(reg, mfc_regs->e_picture_profile); - - /* rate control config. */ - reg = readl(mfc_regs->e_rc_config); - /** macroblock level rate control */ - reg &= ~(0x1 << 8); - reg |= ((p->rc_mb & 0x1) << 8); - writel(reg, mfc_regs->e_rc_config); - - /** frame QP */ - reg &= ~(0x3F); - reg |= p_mpeg4->rc_frame_qp & 0x3F; - writel(reg, mfc_regs->e_rc_config); - - /* max & min value of QP */ - reg = 0; - /** max QP */ - reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8); - /** min QP */ - reg |= p_mpeg4->rc_min_qp & 0x3F; - writel(reg, mfc_regs->e_rc_qp_bound); - - /* other QPs */ - writel(0x0, mfc_regs->e_fixed_picture_qp); - if (!p->rc_frame && !p->rc_mb) { - reg = 0; - reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16); - reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8); - reg |= p_mpeg4->rc_frame_qp & 0x3F; - writel(reg, mfc_regs->e_fixed_picture_qp); - } - - /* frame rate */ - if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { - reg = 0; - reg |= ((p->rc_framerate_num & 0xFFFF) << 16); - reg |= p->rc_framerate_denom & 0xFFFF; - writel(reg, mfc_regs->e_rc_frame_rate); - } - - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); - - if (p->rc_frame) - writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); - } - - /* Disable HEC */ - writel(0x0, mfc_regs->e_mpeg4_options); - writel(0x0, mfc_regs->e_mpeg4_hec_period); - - mfc_debug_leave(); - - return 0; -} - -static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; - unsigned int reg = 0; - - mfc_debug_enter(); - - s5p_mfc_set_enc_params(ctx); - - /* profile & level */ - reg = 0; - /** profile */ - reg |= (0x1 << 4); - writel(reg, mfc_regs->e_picture_profile); - - /* rate control config. */ - reg = readl(mfc_regs->e_rc_config); - /** macroblock level rate control */ - reg &= ~(0x1 << 8); - reg |= ((p->rc_mb & 0x1) << 8); - writel(reg, mfc_regs->e_rc_config); - - /** frame QP */ - reg &= ~(0x3F); - reg |= p_h263->rc_frame_qp & 0x3F; - writel(reg, mfc_regs->e_rc_config); - - /* max & min value of QP */ - reg = 0; - /** max QP */ - reg |= ((p_h263->rc_max_qp & 0x3F) << 8); - /** min QP */ - reg |= p_h263->rc_min_qp & 0x3F; - writel(reg, mfc_regs->e_rc_qp_bound); - - /* other QPs */ - writel(0x0, mfc_regs->e_fixed_picture_qp); - if (!p->rc_frame && !p->rc_mb) { - reg = 0; - reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16); - reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8); - reg |= p_h263->rc_frame_qp & 0x3F; - writel(reg, mfc_regs->e_fixed_picture_qp); - } - - /* frame rate */ - if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { - reg = 0; - reg |= ((p->rc_framerate_num & 0xFFFF) << 16); - reg |= p->rc_framerate_denom & 0xFFFF; - writel(reg, mfc_regs->e_rc_frame_rate); - } - - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); - - if (p->rc_frame) - writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); - } - - mfc_debug_leave(); - - return 0; -} - -static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_vp8_enc_params *p_vp8 = &p->codec.vp8; - unsigned int reg = 0; - unsigned int val = 0; - - mfc_debug_enter(); - - s5p_mfc_set_enc_params(ctx); - - /* pictype : number of B */ - reg = readl(mfc_regs->e_gop_config); - reg &= ~(0x3 << 16); - reg |= ((p->num_b_frame & 0x3) << 16); - writel(reg, mfc_regs->e_gop_config); - - /* profile - 0 ~ 3 */ - reg = p_vp8->profile & 0x3; - writel(reg, mfc_regs->e_picture_profile); - - /* rate control config. */ - reg = readl(mfc_regs->e_rc_config); - /** macroblock level rate control */ - reg &= ~(0x1 << 8); - reg |= ((p->rc_mb & 0x1) << 8); - writel(reg, mfc_regs->e_rc_config); - - /* frame rate */ - if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { - reg = 0; - reg |= ((p->rc_framerate_num & 0xFFFF) << 16); - reg |= p->rc_framerate_denom & 0xFFFF; - writel(reg, mfc_regs->e_rc_frame_rate); - } - - /* frame QP */ - reg &= ~(0x7F); - reg |= p_vp8->rc_frame_qp & 0x7F; - writel(reg, mfc_regs->e_rc_config); - - /* other QPs */ - writel(0x0, mfc_regs->e_fixed_picture_qp); - if (!p->rc_frame && !p->rc_mb) { - reg = 0; - reg |= ((p_vp8->rc_p_frame_qp & 0x7F) << 8); - reg |= p_vp8->rc_frame_qp & 0x7F; - writel(reg, mfc_regs->e_fixed_picture_qp); - } - - /* max QP */ - reg = ((p_vp8->rc_max_qp & 0x7F) << 8); - /* min QP */ - reg |= p_vp8->rc_min_qp & 0x7F; - writel(reg, mfc_regs->e_rc_qp_bound); - - /* vbv buffer size */ - if (p->frame_skip_mode == - V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { - writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); - - if (p->rc_frame) - writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); - } - - /* VP8 specific params */ - reg = 0; - reg |= (p_vp8->imd_4x4 & 0x1) << 10; - switch (p_vp8->num_partitions) { - case V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION: - val = 0; - break; - case V4L2_CID_MPEG_VIDEO_VPX_2_PARTITIONS: - val = 2; - break; - case V4L2_CID_MPEG_VIDEO_VPX_4_PARTITIONS: - val = 4; - break; - case V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS: - val = 8; - break; - } - reg |= (val & 0xF) << 3; - reg |= (p_vp8->num_ref & 0x2); - writel(reg, mfc_regs->e_vp8_options); - - mfc_debug_leave(); - - return 0; -} - -static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_hevc_enc_params *p_hevc = &p->codec.hevc; - unsigned int reg = 0; - int i; - - mfc_debug_enter(); - - s5p_mfc_set_enc_params(ctx); - - /* pictype : number of B */ - reg = readl(mfc_regs->e_gop_config); - /* num_b_frame - 0 ~ 2 */ - reg &= ~(0x3 << 16); - reg |= (p->num_b_frame << 16); - writel(reg, mfc_regs->e_gop_config); - - /* UHD encoding case */ - if ((ctx->img_width == 3840) && (ctx->img_height == 2160)) { - p_hevc->level = 51; - p_hevc->tier = 0; - /* this tier can be changed */ - } - - /* tier & level */ - reg = 0; - /* profile */ - reg |= p_hevc->profile & 0x3; - /* level */ - reg &= ~(0xFF << 8); - reg |= (p_hevc->level << 8); - /* tier - 0 ~ 1 */ - reg |= (p_hevc->tier << 16); - writel(reg, mfc_regs->e_picture_profile); - - switch (p_hevc->loopfilter) { - case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: - p_hevc->loopfilter_disable = 1; - break; - case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: - p_hevc->loopfilter_disable = 0; - p_hevc->loopfilter_across = 1; - break; - case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: - p_hevc->loopfilter_disable = 0; - p_hevc->loopfilter_across = 0; - break; - } - - /* max partition depth */ - reg = 0; - reg |= (p_hevc->max_partition_depth & 0x1); - reg |= (p_hevc->num_refs_for_p-1) << 2; - reg |= (p_hevc->refreshtype & 0x3) << 3; - reg |= (p_hevc->const_intra_period_enable & 0x1) << 5; - reg |= (p_hevc->lossless_cu_enable & 0x1) << 6; - reg |= (p_hevc->wavefront_enable & 0x1) << 7; - reg |= (p_hevc->loopfilter_disable & 0x1) << 8; - reg |= (p_hevc->loopfilter_across & 0x1) << 9; - reg |= (p_hevc->enable_ltr & 0x1) << 10; - reg |= (p_hevc->hier_qp_enable & 0x1) << 11; - reg |= (p_hevc->general_pb_enable & 0x1) << 13; - reg |= (p_hevc->temporal_id_enable & 0x1) << 14; - reg |= (p_hevc->strong_intra_smooth & 0x1) << 15; - reg |= (p_hevc->intra_pu_split_disable & 0x1) << 16; - reg |= (p_hevc->tmv_prediction_disable & 0x1) << 17; - reg |= (p_hevc->max_num_merge_mv & 0x7) << 18; - reg |= (p_hevc->encoding_nostartcode_enable & 0x1) << 23; - reg |= (p_hevc->prepend_sps_pps_to_idr << 26); - - writel(reg, mfc_regs->e_hevc_options); - /* refresh period */ - if (p_hevc->refreshtype) { - reg = 0; - reg |= (p_hevc->refreshperiod & 0xFFFF); - writel(reg, mfc_regs->e_hevc_refresh_period); - } - /* loop filter setting */ - if (!(p_hevc->loopfilter_disable & 0x1)) { - reg = 0; - reg |= (p_hevc->lf_beta_offset_div2); - writel(reg, mfc_regs->e_hevc_lf_beta_offset_div2); - reg = 0; - reg |= (p_hevc->lf_tc_offset_div2); - writel(reg, mfc_regs->e_hevc_lf_tc_offset_div2); - } - /* hier qp enable */ - if (p_hevc->num_hier_layer) { - reg = 0; - reg |= (p_hevc->hier_qp_type & 0x1) << 0x3; - reg |= p_hevc->num_hier_layer & 0x7; - writel(reg, mfc_regs->e_num_t_layer); - /* QP value for each layer */ - if (p_hevc->hier_qp_enable) { - for (i = 0; i < 7; i++) - writel(p_hevc->hier_qp_layer[i], - mfc_regs->e_hier_qp_layer0 + i * 4); - } - if (p->rc_frame) { - for (i = 0; i < 7; i++) - writel(p_hevc->hier_bit_layer[i], - mfc_regs->e_hier_bit_rate_layer0 - + i * 4); - } - } - - /* rate control config. */ - reg = readl(mfc_regs->e_rc_config); - /* macroblock level rate control */ - reg &= ~(0x1 << 8); - reg |= (p->rc_mb << 8); - writel(reg, mfc_regs->e_rc_config); - /* frame QP */ - reg &= ~(0xFF); - reg |= p_hevc->rc_frame_qp; - writel(reg, mfc_regs->e_rc_config); - - /* frame rate */ - if (p->rc_frame) { - reg = 0; - reg &= ~(0xFFFF << 16); - reg |= ((p_hevc->rc_framerate) << 16); - reg &= ~(0xFFFF); - reg |= FRAME_DELTA_DEFAULT; - writel(reg, mfc_regs->e_rc_frame_rate); - } - - /* max & min value of QP */ - reg = 0; - /* max QP */ - reg &= ~(0xFF << 8); - reg |= (p_hevc->rc_max_qp << 8); - /* min QP */ - reg &= ~(0xFF); - reg |= p_hevc->rc_min_qp; - writel(reg, mfc_regs->e_rc_qp_bound); - - writel(0x0, mfc_regs->e_fixed_picture_qp); - if (!p->rc_frame && !p->rc_mb) { - reg = 0; - reg &= ~(0xFF << 16); - reg |= (p_hevc->rc_b_frame_qp << 16); - reg &= ~(0xFF << 8); - reg |= (p_hevc->rc_p_frame_qp << 8); - reg &= ~(0xFF); - reg |= p_hevc->rc_frame_qp; - writel(reg, mfc_regs->e_fixed_picture_qp); - } - mfc_debug_leave(); - - return 0; -} - -/* Initialize decoding */ -static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - unsigned int reg = 0; - int fmo_aso_ctrl = 0; - - mfc_debug_enter(); - mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, - S5P_FIMV_CH_SEQ_HEADER_V6); - mfc_debug(2, "BUFs: %08x %08x %08x\n", - readl(mfc_regs->d_cpb_buffer_addr), - readl(mfc_regs->d_cpb_buffer_addr), - readl(mfc_regs->d_cpb_buffer_addr)); - - /* FMO_ASO_CTRL - 0: Enable, 1: Disable */ - reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6); - - if (ctx->display_delay_enable) { - reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6); - writel(ctx->display_delay, mfc_regs->d_display_delay); - } - - if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) { - writel(reg, mfc_regs->d_dec_options); - reg = 0; - } - - /* Setup loop filter, for decoding this is only valid for MPEG4 */ - if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) { - mfc_debug(2, "Set loop filter to: %d\n", - ctx->loop_filter_mpeg4); - reg |= (ctx->loop_filter_mpeg4 << - S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6); - } - if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) - reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6); - - if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) - writel(reg, mfc_regs->d_init_buffer_options); - else - writel(reg, mfc_regs->d_dec_options); - - /* 0: NV12(CbCr), 1: NV21(CrCb) */ - if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M) - writel(0x1, mfc_regs->pixel_format); - else - writel(0x0, mfc_regs->pixel_format); - - - /* sei parse */ - writel(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable); - - writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, - S5P_FIMV_CH_SEQ_HEADER_V6, NULL); - - mfc_debug_leave(); - return 0; -} - -static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - - if (flush) { - dev->curr_ctx = ctx->num; - writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, - S5P_FIMV_H2R_CMD_FLUSH_V6, NULL); - } -} - -/* Decode a single frame */ -static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, - enum s5p_mfc_decode_arg last_frame) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - - writel(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower); - writel(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable); - - writel(ctx->inst_no, mfc_regs->instance_id); - /* Issue different commands to instance basing on whether it - * is the last frame or not. */ - switch (last_frame) { - case 0: - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, - S5P_FIMV_CH_FRAME_START_V6, NULL); - break; - case 1: - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, - S5P_FIMV_CH_LAST_FRAME_V6, NULL); - break; - default: - mfc_err("Unsupported last frame arg.\n"); - return -EINVAL; - } - - mfc_debug(2, "Decoding a usual frame.\n"); - return 0; -} - -static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - - if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) - s5p_mfc_set_enc_params_h264(ctx); - else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) - s5p_mfc_set_enc_params_mpeg4(ctx); - else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) - s5p_mfc_set_enc_params_h263(ctx); - else if (ctx->codec_mode == S5P_MFC_CODEC_VP8_ENC) - s5p_mfc_set_enc_params_vp8(ctx); - else if (ctx->codec_mode == S5P_FIMV_CODEC_HEVC_ENC) - s5p_mfc_set_enc_params_hevc(ctx); - else { - mfc_err("Unknown codec for encoding (%x).\n", - ctx->codec_mode); - return -EINVAL; - } - - /* Set stride lengths for v7 & above */ - if (IS_MFCV7_PLUS(dev)) { - writel(ctx->img_width, mfc_regs->e_source_first_plane_stride); - writel(ctx->img_width, mfc_regs->e_source_second_plane_stride); - } - - writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, - S5P_FIMV_CH_SEQ_HEADER_V6, NULL); - - return 0; -} - -static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; - int i; - - if (p_h264->aso) { - for (i = 0; i < ARRAY_SIZE(p_h264->aso_slice_order); i++) { - writel(p_h264->aso_slice_order[i], - mfc_regs->e_h264_aso_slice_order_0 + i * 4); - } - } - return 0; -} - -/* Encode a single frame */ -static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - int cmd; - - mfc_debug(2, "++\n"); - - /* memory structure cur. frame */ - - if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) - s5p_mfc_h264_set_aso_slice_order_v6(ctx); - - s5p_mfc_set_slice_mode(ctx); - - if (ctx->state != MFCINST_FINISHING) - cmd = S5P_FIMV_CH_FRAME_START_V6; - else - cmd = S5P_FIMV_CH_LAST_FRAME_V6; - - writel(ctx->inst_no, mfc_regs->instance_id); - s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, cmd, NULL); - - mfc_debug(2, "--\n"); - - return 0; -} - -static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - - s5p_mfc_set_dec_stream_buffer_v6(ctx, 0, 0, 0); - dev->curr_ctx = ctx->num; - s5p_mfc_decode_one_frame_v6(ctx, MFC_DEC_LAST_FRAME); -} - -static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *temp_vb; - int last_frame = 0; - - if (ctx->state == MFCINST_FINISHING) { - last_frame = MFC_DEC_LAST_FRAME; - s5p_mfc_set_dec_stream_buffer_v6(ctx, 0, 0, 0); - dev->curr_ctx = ctx->num; - s5p_mfc_clean_ctx_int_flags(ctx); - s5p_mfc_decode_one_frame_v6(ctx, last_frame); - return 0; - } - - /* Frames are being decoded */ - if (list_empty(&ctx->src_queue)) { - mfc_debug(2, "No src buffers.\n"); - return -EAGAIN; - } - /* Get the next source buffer */ - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - temp_vb->flags |= MFC_BUF_FLAG_USED; - s5p_mfc_set_dec_stream_buffer_v6(ctx, - vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), - ctx->consumed_stream, - temp_vb->b->vb2_buf.planes[0].bytesused); - - dev->curr_ctx = ctx->num; - if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) { - last_frame = 1; - mfc_debug(2, "Setting ctx->state to FINISHING\n"); - ctx->state = MFCINST_FINISHING; - } - s5p_mfc_decode_one_frame_v6(ctx, last_frame); - - return 0; -} - -static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *dst_mb; - struct s5p_mfc_buf *src_mb; - unsigned long src_y_addr, src_c_addr, dst_addr; - /* - unsigned int src_y_size, src_c_size; - */ - unsigned int dst_size; - - if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { - mfc_debug(2, "no src buffers.\n"); - return -EAGAIN; - } - - if (list_empty(&ctx->dst_queue)) { - mfc_debug(2, "no dst buffers.\n"); - return -EAGAIN; - } - - if (list_empty(&ctx->src_queue)) { - /* send null frame */ - s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0); - src_mb = NULL; - } else { - src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - src_mb->flags |= MFC_BUF_FLAG_USED; - if (src_mb->b->vb2_buf.planes[0].bytesused == 0) { - s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0); - ctx->state = MFCINST_FINISHING; - } else { - src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0); - src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1); - - mfc_debug(2, "enc src y addr: 0x%08lx\n", src_y_addr); - mfc_debug(2, "enc src c addr: 0x%08lx\n", src_c_addr); - - s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr); - if (src_mb->flags & MFC_BUF_FLAG_EOS) - ctx->state = MFCINST_FINISHING; - } - } - - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_mb->flags |= MFC_BUF_FLAG_USED; - dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); - dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); - - s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); - - dev->curr_ctx = ctx->num; - s5p_mfc_encode_one_frame_v6(ctx); - - return 0; -} - -static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *temp_vb; - - /* Initializing decoding - parsing header */ - mfc_debug(2, "Preparing to init decoding.\n"); - temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - mfc_debug(2, "Header size: %d\n", temp_vb->b->vb2_buf.planes[0].bytesused); - s5p_mfc_set_dec_stream_buffer_v6(ctx, - vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), 0, - temp_vb->b->vb2_buf.planes[0].bytesused); - dev->curr_ctx = ctx->num; - s5p_mfc_init_decode_v6(ctx); -} - -static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf *dst_mb; - unsigned long dst_addr; - unsigned int dst_size; - - dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); - dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); - dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); - s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); - dev->curr_ctx = ctx->num; - s5p_mfc_init_encode_v6(ctx); -} - -static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - int ret; - /* Header was parsed now start processing - * First set the output frame buffers - * s5p_mfc_alloc_dec_buffers(ctx); */ - - if (ctx->capture_state != QUEUE_BUFS_MMAPED) { - mfc_err("It seems that not all destination buffers were\n" - "mmapped.MFC requires that all destination are mmapped\n" - "before starting processing.\n"); - return -EAGAIN; - } - - dev->curr_ctx = ctx->num; - ret = s5p_mfc_set_dec_frame_buffer_v6(ctx); - if (ret) { - mfc_err("Failed to alloc frame mem.\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - int ret; - - dev->curr_ctx = ctx->num; - ret = s5p_mfc_set_enc_ref_buffer_v6(ctx); - if (ret) { - mfc_err("Failed to alloc frame mem.\n"); - ctx->state = MFCINST_ERROR; - } - return ret; -} - -/* Try running an operation on hardware */ -static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) -{ - struct s5p_mfc_ctx *ctx; - int new_ctx; - unsigned int ret = 0; - - mfc_debug(1, "Try run dev: %p\n", dev); - - /* Check whether hardware is not running */ - if (test_and_set_bit(0, &dev->hw_lock) != 0) { - /* This is perfectly ok, the scheduled ctx should wait */ - mfc_debug(1, "Couldn't lock HW.\n"); - return; - } - - /* Choose the context to run */ - new_ctx = s5p_mfc_get_new_ctx(dev); - if (new_ctx < 0) { - /* No contexts to run */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) { - mfc_err("Failed to unlock hardware.\n"); - return; - } - - mfc_debug(1, "No ctx is scheduled to be run.\n"); - return; - } - - mfc_debug(1, "New context: %d\n", new_ctx); - ctx = dev->ctx[new_ctx]; - mfc_debug(1, "Setting new context to %p\n", ctx); - /* Got context to run in ctx */ - mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n", - ctx->dst_queue_cnt, ctx->pb_count, ctx->src_queue_cnt); - mfc_debug(1, "ctx->state=%d\n", ctx->state); - /* Last frame has already been sent to MFC - * Now obtaining frames from MFC buffer */ - - s5p_mfc_clock_on(); - s5p_mfc_clean_ctx_int_flags(ctx); - - if (ctx->type == MFCINST_DECODER) { - switch (ctx->state) { - case MFCINST_FINISHING: - s5p_mfc_run_dec_last_frames(ctx); - break; - case MFCINST_RUNNING: - ret = s5p_mfc_run_dec_frame(ctx); - break; - case MFCINST_INIT: - ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, - ctx); - break; - case MFCINST_RETURN_INST: - ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, - ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_dec(ctx); - break; - case MFCINST_HEAD_PARSED: - ret = s5p_mfc_run_init_dec_buffers(ctx); - break; - case MFCINST_FLUSH: - s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); - break; - case MFCINST_RES_CHANGE_INIT: - s5p_mfc_run_dec_last_frames(ctx); - break; - case MFCINST_RES_CHANGE_FLUSH: - s5p_mfc_run_dec_last_frames(ctx); - break; - case MFCINST_RES_CHANGE_END: - mfc_debug(2, "Finished remaining frames after resolution change.\n"); - ctx->capture_state = QUEUE_FREE; - mfc_debug(2, "Will re-init the codec`.\n"); - s5p_mfc_run_init_dec(ctx); - break; - default: - ret = -EAGAIN; - } - } else if (ctx->type == MFCINST_ENCODER) { - switch (ctx->state) { - case MFCINST_FINISHING: - case MFCINST_RUNNING: - ret = s5p_mfc_run_enc_frame(ctx); - break; - case MFCINST_INIT: - ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, - ctx); - break; - case MFCINST_RETURN_INST: - ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, - ctx); - break; - case MFCINST_GOT_INST: - s5p_mfc_run_init_enc(ctx); - break; - case MFCINST_HEAD_PRODUCED: - ret = s5p_mfc_run_init_enc_buffers(ctx); - break; - default: - ret = -EAGAIN; - } - } else { - mfc_err("invalid context type: %d\n", ctx->type); - ret = -EAGAIN; - } - - if (ret) { - /* Free hardware lock */ - if (test_and_clear_bit(0, &dev->hw_lock) == 0) - mfc_err("Failed to unlock hardware.\n"); - - /* This is in deed imporant, as no operation has been - * scheduled, reduce the clock count as no one will - * ever do this, because no interrupt related to this try_run - * will ever come from hardware. */ - s5p_mfc_clock_off(); - } -} - -static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) -{ - const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - writel(0, mfc_regs->risc2host_command); - writel(0, mfc_regs->risc2host_int); -} - -static unsigned int -s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned long ofs) -{ - int ret; - - s5p_mfc_clock_on(); - ret = readl((void __iomem *)ofs); - s5p_mfc_clock_off(); - - return ret; -} - -static int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_display_first_plane_addr); -} - -static int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_decoded_first_plane_addr); -} - -static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_display_status); -} - -static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_decoded_status); -} - -static int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_decoded_frame_type) & - S5P_FIMV_DECODE_FRAME_MASK_V6; -} - -static int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx) -{ - struct s5p_mfc_dev *dev = ctx->dev; - return readl(dev->mfc_regs->d_display_frame_type) & - S5P_FIMV_DECODE_FRAME_MASK_V6; -} - -static int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_decoded_nal_size); -} - -static int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->risc2host_command) & - S5P_FIMV_RISC2HOST_CMD_MASK; -} - -static int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->error_code); -} - -static int s5p_mfc_err_dec_v6(unsigned int err) -{ - return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6; -} - -static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_display_frame_width); -} - -static int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_display_frame_height); -} - -static int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_min_num_dpb); -} - -static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_min_num_mv); -} - -static int s5p_mfc_get_min_scratch_buf_size(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->d_min_scratch_buffer_size); -} - -static int s5p_mfc_get_e_min_scratch_buf_size(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->e_min_scratch_buffer_size); -} - -static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->ret_instance_id); -} - -static int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->e_num_dpb); -} - -static int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->e_stream_size); -} - -static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) -{ - return readl(dev->mfc_regs->e_slice_type); -} - -static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) -{ - return s5p_mfc_read_info_v6(ctx, - (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_top); -} - -static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) -{ - return s5p_mfc_read_info_v6(ctx, - (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_bot); -} - -static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) -{ - return s5p_mfc_read_info_v6(ctx, - (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info1); -} - -static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) -{ - return s5p_mfc_read_info_v6(ctx, - (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info2); -} - -static struct s5p_mfc_regs mfc_regs; - -/* Initialize registers for MFC v6 onwards */ -const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) -{ - memset(&mfc_regs, 0, sizeof(mfc_regs)); - -#define S5P_MFC_REG_ADDR(dev, reg) ((dev)->regs_base + (reg)) -#define R(m, r) mfc_regs.m = S5P_MFC_REG_ADDR(dev, r) - /* codec common registers */ - R(risc_on, S5P_FIMV_RISC_ON_V6); - R(risc2host_int, S5P_FIMV_RISC2HOST_INT_V6); - R(host2risc_int, S5P_FIMV_HOST2RISC_INT_V6); - R(risc_base_address, S5P_FIMV_RISC_BASE_ADDRESS_V6); - R(mfc_reset, S5P_FIMV_MFC_RESET_V6); - R(host2risc_command, S5P_FIMV_HOST2RISC_CMD_V6); - R(risc2host_command, S5P_FIMV_RISC2HOST_CMD_V6); - R(firmware_version, S5P_FIMV_FW_VERSION_V6); - R(instance_id, S5P_FIMV_INSTANCE_ID_V6); - R(codec_type, S5P_FIMV_CODEC_TYPE_V6); - R(context_mem_addr, S5P_FIMV_CONTEXT_MEM_ADDR_V6); - R(context_mem_size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); - R(pixel_format, S5P_FIMV_PIXEL_FORMAT_V6); - R(ret_instance_id, S5P_FIMV_RET_INSTANCE_ID_V6); - R(error_code, S5P_FIMV_ERROR_CODE_V6); - - /* decoder registers */ - R(d_crc_ctrl, S5P_FIMV_D_CRC_CTRL_V6); - R(d_dec_options, S5P_FIMV_D_DEC_OPTIONS_V6); - R(d_display_delay, S5P_FIMV_D_DISPLAY_DELAY_V6); - R(d_sei_enable, S5P_FIMV_D_SEI_ENABLE_V6); - R(d_min_num_dpb, S5P_FIMV_D_MIN_NUM_DPB_V6); - R(d_min_num_mv, S5P_FIMV_D_MIN_NUM_MV_V6); - R(d_mvc_num_views, S5P_FIMV_D_MVC_NUM_VIEWS_V6); - R(d_num_dpb, S5P_FIMV_D_NUM_DPB_V6); - R(d_num_mv, S5P_FIMV_D_NUM_MV_V6); - R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V6); - R(d_first_plane_dpb_size, S5P_FIMV_D_LUMA_DPB_SIZE_V6); - R(d_second_plane_dpb_size, S5P_FIMV_D_CHROMA_DPB_SIZE_V6); - R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V6); - R(d_first_plane_dpb, S5P_FIMV_D_LUMA_DPB_V6); - R(d_second_plane_dpb, S5P_FIMV_D_CHROMA_DPB_V6); - R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V6); - R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6); - R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6); - R(d_cpb_buffer_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V6); - R(d_cpb_buffer_size, S5P_FIMV_D_CPB_BUFFER_SIZE_V6); - R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6); - R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V6); - R(d_slice_if_enable, S5P_FIMV_D_SLICE_IF_ENABLE_V6); - R(d_stream_data_size, S5P_FIMV_D_STREAM_DATA_SIZE_V6); - R(d_display_frame_width, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6); - R(d_display_frame_height, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6); - R(d_display_status, S5P_FIMV_D_DISPLAY_STATUS_V6); - R(d_display_first_plane_addr, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); - R(d_display_second_plane_addr, S5P_FIMV_D_DISPLAY_CHROMA_ADDR_V6); - R(d_display_frame_type, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6); - R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V6); - R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V6); - R(d_display_aspect_ratio, S5P_FIMV_D_DISPLAY_ASPECT_RATIO_V6); - R(d_display_extended_ar, S5P_FIMV_D_DISPLAY_EXTENDED_AR_V6); - R(d_decoded_status, S5P_FIMV_D_DECODED_STATUS_V6); - R(d_decoded_first_plane_addr, S5P_FIMV_D_DECODED_LUMA_ADDR_V6); - R(d_decoded_second_plane_addr, S5P_FIMV_D_DECODED_CHROMA_ADDR_V6); - R(d_decoded_frame_type, S5P_FIMV_D_DECODED_FRAME_TYPE_V6); - R(d_decoded_nal_size, S5P_FIMV_D_DECODED_NAL_SIZE_V6); - R(d_ret_picture_tag_top, S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6); - R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6); - R(d_h264_info, S5P_FIMV_D_H264_INFO_V6); - R(d_mvc_view_id, S5P_FIMV_D_MVC_VIEW_ID_V6); - R(d_frame_pack_sei_avail, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6); - - /* encoder registers */ - R(e_frame_width, S5P_FIMV_E_FRAME_WIDTH_V6); - R(e_frame_height, S5P_FIMV_E_FRAME_HEIGHT_V6); - R(e_cropped_frame_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6); - R(e_cropped_frame_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); - R(e_frame_crop_offset, S5P_FIMV_E_FRAME_CROP_OFFSET_V6); - R(e_enc_options, S5P_FIMV_E_ENC_OPTIONS_V6); - R(e_picture_profile, S5P_FIMV_E_PICTURE_PROFILE_V6); - R(e_vbv_buffer_size, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); - R(e_vbv_init_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); - R(e_fixed_picture_qp, S5P_FIMV_E_FIXED_PICTURE_QP_V6); - R(e_rc_config, S5P_FIMV_E_RC_CONFIG_V6); - R(e_rc_qp_bound, S5P_FIMV_E_RC_QP_BOUND_V6); - R(e_rc_mode, S5P_FIMV_E_RC_RPARAM_V6); - R(e_mb_rc_config, S5P_FIMV_E_MB_RC_CONFIG_V6); - R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V6); - R(e_mv_hor_range, S5P_FIMV_E_MV_HOR_RANGE_V6); - R(e_mv_ver_range, S5P_FIMV_E_MV_VER_RANGE_V6); - R(e_num_dpb, S5P_FIMV_E_NUM_DPB_V6); - R(e_luma_dpb, S5P_FIMV_E_LUMA_DPB_V6); - R(e_chroma_dpb, S5P_FIMV_E_CHROMA_DPB_V6); - R(e_me_buffer, S5P_FIMV_E_ME_BUFFER_V6); - R(e_scratch_buffer_addr, S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6); - R(e_scratch_buffer_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6); - R(e_tmv_buffer0, S5P_FIMV_E_TMV_BUFFER0_V6); - R(e_tmv_buffer1, S5P_FIMV_E_TMV_BUFFER1_V6); - R(e_source_first_plane_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6); - R(e_source_second_plane_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6); - R(e_stream_buffer_addr, S5P_FIMV_E_STREAM_BUFFER_ADDR_V6); - R(e_stream_buffer_size, S5P_FIMV_E_STREAM_BUFFER_SIZE_V6); - R(e_roi_buffer_addr, S5P_FIMV_E_ROI_BUFFER_ADDR_V6); - R(e_param_change, S5P_FIMV_E_PARAM_CHANGE_V6); - R(e_ir_size, S5P_FIMV_E_IR_SIZE_V6); - R(e_gop_config, S5P_FIMV_E_GOP_CONFIG_V6); - R(e_mslice_mode, S5P_FIMV_E_MSLICE_MODE_V6); - R(e_mslice_size_mb, S5P_FIMV_E_MSLICE_SIZE_MB_V6); - R(e_mslice_size_bits, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); - R(e_frame_insertion, S5P_FIMV_E_FRAME_INSERTION_V6); - R(e_rc_frame_rate, S5P_FIMV_E_RC_FRAME_RATE_V6); - R(e_rc_bit_rate, S5P_FIMV_E_RC_BIT_RATE_V6); - R(e_rc_roi_ctrl, S5P_FIMV_E_RC_ROI_CTRL_V6); - R(e_picture_tag, S5P_FIMV_E_PICTURE_TAG_V6); - R(e_bit_count_enable, S5P_FIMV_E_BIT_COUNT_ENABLE_V6); - R(e_max_bit_count, S5P_FIMV_E_MAX_BIT_COUNT_V6); - R(e_min_bit_count, S5P_FIMV_E_MIN_BIT_COUNT_V6); - R(e_metadata_buffer_addr, S5P_FIMV_E_METADATA_BUFFER_ADDR_V6); - R(e_metadata_buffer_size, S5P_FIMV_E_METADATA_BUFFER_SIZE_V6); - R(e_encoded_source_first_plane_addr, - S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6); - R(e_encoded_source_second_plane_addr, - S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6); - R(e_stream_size, S5P_FIMV_E_STREAM_SIZE_V6); - R(e_slice_type, S5P_FIMV_E_SLICE_TYPE_V6); - R(e_picture_count, S5P_FIMV_E_PICTURE_COUNT_V6); - R(e_ret_picture_tag, S5P_FIMV_E_RET_PICTURE_TAG_V6); - R(e_recon_luma_dpb_addr, S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6); - R(e_recon_chroma_dpb_addr, S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6); - R(e_mpeg4_options, S5P_FIMV_E_MPEG4_OPTIONS_V6); - R(e_mpeg4_hec_period, S5P_FIMV_E_MPEG4_HEC_PERIOD_V6); - R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V6); - R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V6); - R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V6); - R(e_h264_lf_alpha_offset, S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6); - R(e_h264_lf_beta_offset, S5P_FIMV_E_H264_LF_BETA_OFFSET_V6); - R(e_h264_i_period, S5P_FIMV_E_H264_I_PERIOD_V6); - R(e_h264_fmo_slice_grp_map_type, - S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6); - R(e_h264_fmo_num_slice_grp_minus1, - S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); - R(e_h264_fmo_slice_grp_change_dir, - S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6); - R(e_h264_fmo_slice_grp_change_rate_minus1, - S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6); - R(e_h264_fmo_run_length_minus1_0, - S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6); - R(e_h264_aso_slice_order_0, S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6); - R(e_h264_num_t_layer, S5P_FIMV_E_H264_NUM_T_LAYER_V6); - R(e_h264_hierarchical_qp_layer0, - S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6); - R(e_h264_frame_packing_sei_info, - S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6); - - if (!IS_MFCV7_PLUS(dev)) - goto done; - - /* Initialize registers used in MFC v7+ */ - R(e_source_first_plane_addr, S5P_FIMV_E_SOURCE_FIRST_ADDR_V7); - R(e_source_second_plane_addr, S5P_FIMV_E_SOURCE_SECOND_ADDR_V7); - R(e_source_third_plane_addr, S5P_FIMV_E_SOURCE_THIRD_ADDR_V7); - R(e_source_first_plane_stride, S5P_FIMV_E_SOURCE_FIRST_STRIDE_V7); - R(e_source_second_plane_stride, S5P_FIMV_E_SOURCE_SECOND_STRIDE_V7); - R(e_source_third_plane_stride, S5P_FIMV_E_SOURCE_THIRD_STRIDE_V7); - R(e_encoded_source_first_plane_addr, - S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7); - R(e_encoded_source_second_plane_addr, - S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7); - R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7); - - if (!IS_MFCV8_PLUS(dev)) - goto done; - - /* Initialize registers used in MFC v8 only. - * Also, over-write the registers which have - * a different offset for MFC v8. */ - R(d_stream_data_size, S5P_FIMV_D_STREAM_DATA_SIZE_V8); - R(d_cpb_buffer_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V8); - R(d_cpb_buffer_size, S5P_FIMV_D_CPB_BUFFER_SIZE_V8); - R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V8); - R(d_first_plane_dpb_size, S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8); - R(d_second_plane_dpb_size, S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8); - R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8); - R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8); - R(d_first_plane_dpb_stride_size, - S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8); - R(d_second_plane_dpb_stride_size, - S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8); - R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V8); - R(d_num_mv, S5P_FIMV_D_NUM_MV_V8); - R(d_first_plane_dpb, S5P_FIMV_D_FIRST_PLANE_DPB_V8); - R(d_second_plane_dpb, S5P_FIMV_D_SECOND_PLANE_DPB_V8); - R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V8); - R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8); - R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8); - R(d_slice_if_enable, S5P_FIMV_D_SLICE_IF_ENABLE_V8); - R(d_display_first_plane_addr, S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR_V8); - R(d_display_second_plane_addr, S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR_V8); - R(d_decoded_first_plane_addr, S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR_V8); - R(d_decoded_second_plane_addr, S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR_V8); - R(d_display_status, S5P_FIMV_D_DISPLAY_STATUS_V8); - R(d_decoded_status, S5P_FIMV_D_DECODED_STATUS_V8); - R(d_decoded_frame_type, S5P_FIMV_D_DECODED_FRAME_TYPE_V8); - R(d_display_frame_type, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V8); - R(d_decoded_nal_size, S5P_FIMV_D_DECODED_NAL_SIZE_V8); - R(d_display_frame_width, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V8); - R(d_display_frame_height, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V8); - R(d_frame_pack_sei_avail, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V8); - R(d_mvc_num_views, S5P_FIMV_D_MVC_NUM_VIEWS_V8); - R(d_mvc_view_id, S5P_FIMV_D_MVC_VIEW_ID_V8); - R(d_ret_picture_tag_top, S5P_FIMV_D_RET_PICTURE_TAG_TOP_V8); - R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8); - R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V8); - R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V8); - R(d_min_scratch_buffer_size, S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8); - - /* encoder registers */ - R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V8); - R(e_rc_config, S5P_FIMV_E_RC_CONFIG_V8); - R(e_rc_mode, S5P_FIMV_E_RC_RPARAM_V8); - R(e_mv_hor_range, S5P_FIMV_E_MV_HOR_RANGE_V8); - R(e_mv_ver_range, S5P_FIMV_E_MV_VER_RANGE_V8); - R(e_rc_qp_bound, S5P_FIMV_E_RC_QP_BOUND_V8); - R(e_fixed_picture_qp, S5P_FIMV_E_FIXED_PICTURE_QP_V8); - R(e_vbv_buffer_size, S5P_FIMV_E_VBV_BUFFER_SIZE_V8); - R(e_vbv_init_delay, S5P_FIMV_E_VBV_INIT_DELAY_V8); - R(e_mb_rc_config, S5P_FIMV_E_MB_RC_CONFIG_V8); - R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V8); - R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V8); - R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V8); - R(e_min_scratch_buffer_size, S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8); - - if (!IS_MFCV10(dev)) - goto done; - - /* Initialize registers used in MFC v10 only. - * Also, over-write the registers which have - * a different offset for MFC v10. - */ - - /* decoder registers */ - R(d_static_buffer_addr, S5P_FIMV_D_STATIC_BUFFER_ADDR_V10); - R(d_static_buffer_size, S5P_FIMV_D_STATIC_BUFFER_SIZE_V10); - - /* encoder registers */ - R(e_num_t_layer, S5P_FIMV_E_NUM_T_LAYER_V10); - R(e_hier_qp_layer0, S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10); - R(e_hier_bit_rate_layer0, S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10); - R(e_hevc_options, S5P_FIMV_E_HEVC_OPTIONS_V10); - R(e_hevc_refresh_period, S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10); - R(e_hevc_lf_beta_offset_div2, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10); - R(e_hevc_lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10); - R(e_hevc_nal_control, S5P_FIMV_E_HEVC_NAL_CONTROL_V10); - -done: - return &mfc_regs; -#undef S5P_MFC_REG_ADDR -#undef R -} - -/* Initialize opr function pointers for MFC v6 */ -static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { - .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v6, - .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v6, - .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v6, - .release_codec_buffers = s5p_mfc_release_codec_buffers_v6, - .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v6, - .release_instance_buffer = s5p_mfc_release_instance_buffer_v6, - .alloc_dev_context_buffer = - s5p_mfc_alloc_dev_context_buffer_v6, - .release_dev_context_buffer = - s5p_mfc_release_dev_context_buffer_v6, - .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v6, - .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v6, - .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v6, - .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v6, - .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v6, - .try_run = s5p_mfc_try_run_v6, - .clear_int_flags = s5p_mfc_clear_int_flags_v6, - .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v6, - .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v6, - .get_dspl_status = s5p_mfc_get_dspl_status_v6, - .get_dec_status = s5p_mfc_get_dec_status_v6, - .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v6, - .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v6, - .get_consumed_stream = s5p_mfc_get_consumed_stream_v6, - .get_int_reason = s5p_mfc_get_int_reason_v6, - .get_int_err = s5p_mfc_get_int_err_v6, - .err_dec = s5p_mfc_err_dec_v6, - .get_img_width = s5p_mfc_get_img_width_v6, - .get_img_height = s5p_mfc_get_img_height_v6, - .get_dpb_count = s5p_mfc_get_dpb_count_v6, - .get_mv_count = s5p_mfc_get_mv_count_v6, - .get_inst_no = s5p_mfc_get_inst_no_v6, - .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v6, - .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v6, - .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v6, - .get_pic_type_top = s5p_mfc_get_pic_type_top_v6, - .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, - .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, - .get_crop_info_v = s5p_mfc_get_crop_info_v_v6, - .get_min_scratch_buf_size = s5p_mfc_get_min_scratch_buf_size, - .get_e_min_scratch_buf_size = s5p_mfc_get_e_min_scratch_buf_size, -}; - -struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) -{ - return &s5p_mfc_ops_v6; -} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h deleted file mode 100644 index 8ca514bf5e37..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h +++ /dev/null @@ -1,57 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h - * - * Header file for Samsung MFC (Multi Function Codec - FIMV) driver - * Contains declarations of hw related functions. - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_OPR_V6_H_ -#define S5P_MFC_OPR_V6_H_ - -#include "s5p_mfc_common.h" -#include "s5p_mfc_opr.h" - -#define MFC_CTRL_MODE_CUSTOM MFC_CTRL_MODE_SFR - -#define MB_WIDTH(x_size) DIV_ROUND_UP(x_size, 16) -#define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16) -#define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \ - (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) -#define S5P_MFC_DEC_MV_SIZE_V10(x, y) (MB_WIDTH(x) * \ - (((MB_HEIGHT(y)+1)/2)*2) * 64 + 512) -#define S5P_MFC_LCU_WIDTH(x_size) DIV_ROUND_UP(x_size, 32) -#define S5P_MFC_LCU_HEIGHT(y_size) DIV_ROUND_UP(y_size, 32) - -#define s5p_mfc_dec_hevc_mv_size(x, y) \ - (DIV_ROUND_UP(x, 64) * DIV_ROUND_UP(y, 64) * 256 + 512) - -/* Definition */ -#define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) -#define ENC_MULTI_SLICE_BIT_MIN 2800 -#define ENC_INTRA_REFRESH_MB_MAX ((1 << 18) - 1) -#define ENC_VBV_BUF_SIZE_MAX ((1 << 30) - 1) -#define ENC_H264_LOOP_FILTER_AB_MIN -12 -#define ENC_H264_LOOP_FILTER_AB_MAX 12 -#define ENC_H264_RC_FRAME_RATE_MAX ((1 << 16) - 1) -#define ENC_H263_RC_FRAME_RATE_MAX ((1 << 16) - 1) -#define ENC_H264_PROFILE_MAX 3 -#define ENC_H264_LEVEL_MAX 42 -#define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1) -#define FRAME_DELTA_H264_H263 1 -#define TIGHT_CBR_MAX 10 -#define ENC_HEVC_RC_FRAME_RATE_MAX ((1 << 16) - 1) -#define ENC_HEVC_QP_INDEX_MIN -12 -#define ENC_HEVC_QP_INDEX_MAX 12 -#define ENC_HEVC_LOOP_FILTER_MIN -12 -#define ENC_HEVC_LOOP_FILTER_MAX 12 -#define ENC_HEVC_LEVEL_MAX 62 - -#define FRAME_DELTA_DEFAULT 1 - -struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); -const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev); -#endif /* S5P_MFC_OPR_V6_H_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c deleted file mode 100644 index 88b7d33c9197..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c - * - * Copyright (c) 2010 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#include -#include -#include -#include -#include "s5p_mfc_common.h" -#include "s5p_mfc_debug.h" -#include "s5p_mfc_pm.h" - -static struct s5p_mfc_pm *pm; -static struct s5p_mfc_dev *p_dev; -static atomic_t clk_ref; - -int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) -{ - int i; - - pm = &dev->pm; - p_dev = dev; - - pm->num_clocks = dev->variant->num_clocks; - pm->clk_names = dev->variant->clk_names; - pm->device = &dev->plat_dev->dev; - pm->clock_gate = NULL; - - /* clock control */ - for (i = 0; i < pm->num_clocks; i++) { - pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]); - if (IS_ERR(pm->clocks[i])) { - /* additional clocks are optional */ - if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) { - pm->clocks[i] = NULL; - continue; - } - mfc_err("Failed to get clock: %s\n", - pm->clk_names[i]); - return PTR_ERR(pm->clocks[i]); - } - } - - if (dev->variant->use_clock_gating) - pm->clock_gate = pm->clocks[0]; - - pm_runtime_enable(pm->device); - atomic_set(&clk_ref, 0); - return 0; -} - -void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) -{ - pm_runtime_disable(pm->device); -} - -int s5p_mfc_clock_on(void) -{ - atomic_inc(&clk_ref); - mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); - - return clk_enable(pm->clock_gate); -} - -void s5p_mfc_clock_off(void) -{ - atomic_dec(&clk_ref); - mfc_debug(3, "- %d\n", atomic_read(&clk_ref)); - - clk_disable(pm->clock_gate); -} - -int s5p_mfc_power_on(void) -{ - int i, ret = 0; - - ret = pm_runtime_resume_and_get(pm->device); - if (ret < 0) - return ret; - - /* clock control */ - for (i = 0; i < pm->num_clocks; i++) { - ret = clk_prepare_enable(pm->clocks[i]); - if (ret < 0) { - mfc_err("clock prepare failed for clock: %s\n", - pm->clk_names[i]); - i++; - goto err; - } - } - - /* prepare for software clock gating */ - clk_disable(pm->clock_gate); - - return 0; -err: - while (--i > 0) - clk_disable_unprepare(pm->clocks[i]); - pm_runtime_put(pm->device); - return ret; -} - -int s5p_mfc_power_off(void) -{ - int i; - - /* finish software clock gating */ - clk_enable(pm->clock_gate); - - for (i = 0; i < pm->num_clocks; i++) - clk_disable_unprepare(pm->clocks[i]); - - return pm_runtime_put_sync(pm->device); -} - diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h deleted file mode 100644 index 3d26443189a2..000000000000 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_pm.h - * - * Copyright (C) 2011 Samsung Electronics Co., Ltd. - * http://www.samsung.com/ - */ - -#ifndef S5P_MFC_PM_H_ -#define S5P_MFC_PM_H_ - -int s5p_mfc_init_pm(struct s5p_mfc_dev *dev); -void s5p_mfc_final_pm(struct s5p_mfc_dev *dev); - -int s5p_mfc_clock_on(void); -void s5p_mfc_clock_off(void); -int s5p_mfc_power_on(void); -int s5p_mfc_power_off(void); - -#endif /* S5P_MFC_PM_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/Kconfig b/drivers/media/platform/samsung/s5p-mfc/Kconfig new file mode 100644 index 000000000000..34b52b0de304 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/Kconfig @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_SAMSUNG_S5P_MFC + tristate "Samsung S5P MFC Video Codec" + depends on V4L_MEM2MEM_DRIVERS + depends on VIDEO_DEV && VIDEO_V4L2 + depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + help + MFC 5.1 and 6.x driver for V4L2 diff --git a/drivers/media/platform/samsung/s5p-mfc/Makefile b/drivers/media/platform/samsung/s5p-mfc/Makefile new file mode 100644 index 000000000000..0b324af2ab00 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc.o +s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o +s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o +s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_pm.o +s5p-mfc-y += s5p_mfc_opr.o s5p_mfc_opr_v5.o s5p_mfc_opr_v6.o +s5p-mfc-y += s5p_mfc_cmd.o s5p_mfc_cmd_v5.o s5p_mfc_cmd_v6.o diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v10.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v10.h new file mode 100644 index 000000000000..fadd9139b489 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v10.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Register definition file for Samsung MFC V10.x Interface (FIMV) driver + * + */ + +#ifndef _REGS_MFC_V10_H +#define _REGS_MFC_V10_H + +#include +#include "regs-mfc-v8.h" + +/* MFCv10 register definitions*/ +#define S5P_FIMV_MFC_CLOCK_OFF_V10 0x7120 +#define S5P_FIMV_MFC_STATE_V10 0x7124 +#define S5P_FIMV_D_STATIC_BUFFER_ADDR_V10 0xF570 +#define S5P_FIMV_D_STATIC_BUFFER_SIZE_V10 0xF574 +#define S5P_FIMV_E_NUM_T_LAYER_V10 0xFBAC +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10 0xFBB0 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER1_V10 0xFBB4 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER2_V10 0xFBB8 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER3_V10 0xFBBC +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER4_V10 0xFBC0 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER5_V10 0xFBC4 +#define S5P_FIMV_E_HIERARCHICAL_QP_LAYER6_V10 0xFBC8 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10 0xFD18 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER1_V10 0xFD1C +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER2_V10 0xFD20 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER3_V10 0xFD24 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER4_V10 0xFD28 +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER5_V10 0xFD2C +#define S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER6_V10 0xFD30 +#define S5P_FIMV_E_HEVC_OPTIONS_V10 0xFDD4 +#define S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10 0xFDD8 +#define S5P_FIMV_E_HEVC_CHROMA_QP_OFFSET_V10 0xFDDC +#define S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10 0xFDE0 +#define S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10 0xFDE4 +#define S5P_FIMV_E_HEVC_NAL_CONTROL_V10 0xFDE8 + +/* MFCv10 Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V10 (30 * SZ_1K) +#define MFC_H264_DEC_CTX_BUF_SIZE_V10 (2 * SZ_1M) +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V10 (20 * SZ_1K) +#define MFC_H264_ENC_CTX_BUF_SIZE_V10 (100 * SZ_1K) +#define MFC_HEVC_ENC_CTX_BUF_SIZE_V10 (30 * SZ_1K) +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V10 (15 * SZ_1K) + +/* MFCv10 variant defines */ +#define MAX_FW_SIZE_V10 (SZ_1M) +#define MAX_CPB_SIZE_V10 (3 * SZ_1M) +#define MFC_VERSION_V10 0xA0 +#define MFC_NUM_PORTS_V10 1 + +/* MFCv10 codec defines*/ +#define S5P_FIMV_CODEC_HEVC_DEC 17 +#define S5P_FIMV_CODEC_VP9_DEC 18 +#define S5P_FIMV_CODEC_HEVC_ENC 26 + +/* Decoder buffer size for MFC v10 */ +#define DEC_VP9_STATIC_BUFFER_SIZE 20480 + +/* Encoder buffer size for MFC v10.0 */ +#define ENC_V100_BASE_SIZE(x, y) \ + (((x + 3) * (y + 3) * 8) \ + + ((y * 64) + 1280) * DIV_ROUND_UP(x, 8)) + +#define ENC_V100_H264_ME_SIZE(x, y) \ + (ENC_V100_BASE_SIZE(x, y) \ + + (DIV_ROUND_UP(x * y, 64) * 32)) + +#define ENC_V100_MPEG4_ME_SIZE(x, y) \ + (ENC_V100_BASE_SIZE(x, y) \ + + (DIV_ROUND_UP(x * y, 128) * 16)) + +#define ENC_V100_VP8_ME_SIZE(x, y) \ + ENC_V100_BASE_SIZE(x, y) + +#define ENC_V100_HEVC_ME_SIZE(x, y) \ + (((x + 3) * (y + 3) * 32) \ + + ((y * 128) + 1280) * DIV_ROUND_UP(x, 4)) + +#endif /*_REGS_MFC_V10_H*/ + diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v6.h new file mode 100644 index 000000000000..fa49fe580e1a --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v6.h @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Register definition file for Samsung MFC V6.x Interface (FIMV) driver + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef _REGS_FIMV_V6_H +#define _REGS_FIMV_V6_H + +#include +#include + +#define S5P_FIMV_REG_SIZE_V6 (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) +#define S5P_FIMV_REG_COUNT_V6 ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) + +/* Number of bits that the buffer address should be shifted for particular + * MFC buffers. */ +#define S5P_FIMV_MEM_OFFSET_V6 0 + +#define S5P_FIMV_START_ADDR_V6 0x0000 +#define S5P_FIMV_END_ADDR_V6 0xfd80 + +#define S5P_FIMV_REG_CLEAR_BEGIN_V6 0xf000 +#define S5P_FIMV_REG_CLEAR_COUNT_V6 1024 + +/* Codec Common Registers */ +#define S5P_FIMV_RISC_ON_V6 0x0000 +#define S5P_FIMV_RISC2HOST_INT_V6 0x003C +#define S5P_FIMV_HOST2RISC_INT_V6 0x0044 +#define S5P_FIMV_RISC_BASE_ADDRESS_V6 0x0054 + +#define S5P_FIMV_MFC_RESET_V6 0x1070 + +#define S5P_FIMV_HOST2RISC_CMD_V6 0x1100 +#define S5P_FIMV_H2R_CMD_EMPTY_V6 0 +#define S5P_FIMV_H2R_CMD_SYS_INIT_V6 1 +#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6 2 +#define S5P_FIMV_CH_SEQ_HEADER_V6 3 +#define S5P_FIMV_CH_INIT_BUFS_V6 4 +#define S5P_FIMV_CH_FRAME_START_V6 5 +#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6 6 +#define S5P_FIMV_H2R_CMD_SLEEP_V6 7 +#define S5P_FIMV_H2R_CMD_WAKEUP_V6 8 +#define S5P_FIMV_CH_LAST_FRAME_V6 9 +#define S5P_FIMV_H2R_CMD_FLUSH_V6 10 +/* RMVME: REALLOC used? */ +#define S5P_FIMV_CH_FRAME_START_REALLOC_V6 5 + +#define S5P_FIMV_RISC2HOST_CMD_V6 0x1104 +#define S5P_FIMV_R2H_CMD_EMPTY_V6 0 +#define S5P_FIMV_R2H_CMD_SYS_INIT_RET_V6 1 +#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET_V6 2 +#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET_V6 3 +#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET_V6 4 + +#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET_V6 6 +#define S5P_FIMV_R2H_CMD_SLEEP_RET_V6 7 +#define S5P_FIMV_R2H_CMD_WAKEUP_RET_V6 8 +#define S5P_FIMV_R2H_CMD_COMPLETE_SEQ_RET_V6 9 +#define S5P_FIMV_R2H_CMD_DPB_FLUSH_RET_V6 10 +#define S5P_FIMV_R2H_CMD_NAL_ABORT_RET_V6 11 +#define S5P_FIMV_R2H_CMD_FW_STATUS_RET_V6 12 +#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET_V6 13 +#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET_V6 14 +#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET_V6 15 +#define S5P_FIMV_R2H_CMD_ENC_BUFFER_FUL_RET_V6 16 +#define S5P_FIMV_R2H_CMD_ERR_RET_V6 32 + +#define S5P_FIMV_MFC_BUS_RESET_CTRL 0x7110 +#define S5P_FIMV_FW_VERSION_V6 0xf000 + +#define S5P_FIMV_INSTANCE_ID_V6 0xf008 +#define S5P_FIMV_CODEC_TYPE_V6 0xf00c +#define S5P_FIMV_CONTEXT_MEM_ADDR_V6 0xf014 +#define S5P_FIMV_CONTEXT_MEM_SIZE_V6 0xf018 +#define S5P_FIMV_PIXEL_FORMAT_V6 0xf020 + +#define S5P_FIMV_METADATA_ENABLE_V6 0xf024 +#define S5P_FIMV_DBG_BUFFER_ADDR_V6 0xf030 +#define S5P_FIMV_DBG_BUFFER_SIZE_V6 0xf034 +#define S5P_FIMV_RET_INSTANCE_ID_V6 0xf070 + +#define S5P_FIMV_ERROR_CODE_V6 0xf074 +#define S5P_FIMV_ERR_WARNINGS_START_V6 160 +#define S5P_FIMV_ERR_DEC_MASK_V6 0xffff +#define S5P_FIMV_ERR_DEC_SHIFT_V6 0 +#define S5P_FIMV_ERR_DSPL_MASK_V6 0xffff0000 +#define S5P_FIMV_ERR_DSPL_SHIFT_V6 16 + +#define S5P_FIMV_DBG_BUFFER_OUTPUT_SIZE_V6 0xf078 +#define S5P_FIMV_METADATA_STATUS_V6 0xf07C +#define S5P_FIMV_METADATA_ADDR_MB_INFO_V6 0xf080 +#define S5P_FIMV_METADATA_SIZE_MB_INFO_V6 0xf084 + +/* Decoder Registers */ +#define S5P_FIMV_D_CRC_CTRL_V6 0xf0b0 +#define S5P_FIMV_D_DEC_OPTIONS_V6 0xf0b4 +#define S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6 4 +#define S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6 3 +#define S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6 1 +#define S5P_FIMV_D_OPT_LF_CTRL_MASK_V6 0x3 +#define S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6 0 + +#define S5P_FIMV_D_DISPLAY_DELAY_V6 0xf0b8 + +#define S5P_FIMV_D_SET_FRAME_WIDTH_V6 0xf0bc +#define S5P_FIMV_D_SET_FRAME_HEIGHT_V6 0xf0c0 + +#define S5P_FIMV_D_SEI_ENABLE_V6 0xf0c4 + +/* Buffer setting registers */ +#define S5P_FIMV_D_MIN_NUM_DPB_V6 0xf0f0 +#define S5P_FIMV_D_MIN_LUMA_DPB_SIZE_V6 0xf0f4 +#define S5P_FIMV_D_MIN_CHROMA_DPB_SIZE_V6 0xf0f8 +#define S5P_FIMV_D_MVC_NUM_VIEWS_V6 0xf0fc +#define S5P_FIMV_D_MIN_NUM_MV_V6 0xf100 +#define S5P_FIMV_D_NUM_DPB_V6 0xf130 +#define S5P_FIMV_D_LUMA_DPB_SIZE_V6 0xf134 +#define S5P_FIMV_D_CHROMA_DPB_SIZE_V6 0xf138 +#define S5P_FIMV_D_MV_BUFFER_SIZE_V6 0xf13c + +#define S5P_FIMV_D_LUMA_DPB_V6 0xf140 +#define S5P_FIMV_D_CHROMA_DPB_V6 0xf240 +#define S5P_FIMV_D_MV_BUFFER_V6 0xf340 + +#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6 0xf440 +#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6 0xf444 +#define S5P_FIMV_D_METADATA_BUFFER_ADDR_V6 0xf448 +#define S5P_FIMV_D_METADATA_BUFFER_SIZE_V6 0xf44c +#define S5P_FIMV_D_NUM_MV_V6 0xf478 +#define S5P_FIMV_D_CPB_BUFFER_ADDR_V6 0xf4b0 +#define S5P_FIMV_D_CPB_BUFFER_SIZE_V6 0xf4b4 + +#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_UPPER_V6 0xf4b8 +#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6 0xf4bc +#define S5P_FIMV_D_CPB_BUFFER_OFFSET_V6 0xf4c0 +#define S5P_FIMV_D_SLICE_IF_ENABLE_V6 0xf4c4 +#define S5P_FIMV_D_PICTURE_TAG_V6 0xf4c8 +#define S5P_FIMV_D_STREAM_DATA_SIZE_V6 0xf4d0 +#define S5P_FIMV_D_INIT_BUFFER_OPTIONS_V6 0xf47c + +/* Display information register */ +#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6 0xf500 +#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6 0xf504 + +/* Display status */ +#define S5P_FIMV_D_DISPLAY_STATUS_V6 0xf508 + +#define S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6 0xf50c +#define S5P_FIMV_D_DISPLAY_CHROMA_ADDR_V6 0xf510 + +#define S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6 0xf514 + +#define S5P_FIMV_D_DISPLAY_CROP_INFO1_V6 0xf518 +#define S5P_FIMV_D_DISPLAY_CROP_INFO2_V6 0xf51c +#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE_V6 0xf520 +#define S5P_FIMV_D_DISPLAY_LUMA_CRC_TOP_V6 0xf524 +#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_TOP_V6 0xf528 +#define S5P_FIMV_D_DISPLAY_LUMA_CRC_BOT_V6 0xf52c +#define S5P_FIMV_D_DISPLAY_CHROMA_CRC_BOT_V6 0xf530 +#define S5P_FIMV_D_DISPLAY_ASPECT_RATIO_V6 0xf534 +#define S5P_FIMV_D_DISPLAY_EXTENDED_AR_V6 0xf538 + +/* Decoded picture information register */ +#define S5P_FIMV_D_DECODED_FRAME_WIDTH_V6 0xf53c +#define S5P_FIMV_D_DECODED_FRAME_HEIGHT_V6 0xf540 +#define S5P_FIMV_D_DECODED_STATUS_V6 0xf544 +#define S5P_FIMV_DEC_CRC_GEN_MASK_V6 0x1 +#define S5P_FIMV_DEC_CRC_GEN_SHIFT_V6 6 + +#define S5P_FIMV_D_DECODED_LUMA_ADDR_V6 0xf548 +#define S5P_FIMV_D_DECODED_CHROMA_ADDR_V6 0xf54c + +#define S5P_FIMV_D_DECODED_FRAME_TYPE_V6 0xf550 +#define S5P_FIMV_DECODE_FRAME_MASK_V6 7 + +#define S5P_FIMV_D_DECODED_CROP_INFO1_V6 0xf554 +#define S5P_FIMV_D_DECODED_CROP_INFO2_V6 0xf558 +#define S5P_FIMV_D_DECODED_PICTURE_PROFILE_V6 0xf55c +#define S5P_FIMV_D_DECODED_NAL_SIZE_V6 0xf560 +#define S5P_FIMV_D_DECODED_LUMA_CRC_TOP_V6 0xf564 +#define S5P_FIMV_D_DECODED_CHROMA_CRC_TOP_V6 0xf568 +#define S5P_FIMV_D_DECODED_LUMA_CRC_BOT_V6 0xf56c +#define S5P_FIMV_D_DECODED_CHROMA_CRC_BOT_V6 0xf570 + +/* Returned value register for specific setting */ +#define S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6 0xf574 +#define S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6 0xf578 +#define S5P_FIMV_D_RET_PICTURE_TIME_TOP_V6 0xf57c +#define S5P_FIMV_D_RET_PICTURE_TIME_BOT_V6 0xf580 +#define S5P_FIMV_D_CHROMA_FORMAT_V6 0xf588 +#define S5P_FIMV_D_MPEG4_INFO_V6 0xf58c +#define S5P_FIMV_D_H264_INFO_V6 0xf590 + +#define S5P_FIMV_D_METADATA_ADDR_CONCEALED_MB_V6 0xf594 +#define S5P_FIMV_D_METADATA_SIZE_CONCEALED_MB_V6 0xf598 +#define S5P_FIMV_D_METADATA_ADDR_VC1_PARAM_V6 0xf59c +#define S5P_FIMV_D_METADATA_SIZE_VC1_PARAM_V6 0xf5a0 +#define S5P_FIMV_D_METADATA_ADDR_SEI_NAL_V6 0xf5a4 +#define S5P_FIMV_D_METADATA_SIZE_SEI_NAL_V6 0xf5a8 +#define S5P_FIMV_D_METADATA_ADDR_VUI_V6 0xf5ac +#define S5P_FIMV_D_METADATA_SIZE_VUI_V6 0xf5b0 + +#define S5P_FIMV_D_MVC_VIEW_ID_V6 0xf5b4 + +/* SEI related information */ +#define S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6 0xf5f0 +#define S5P_FIMV_D_FRAME_PACK_ARRGMENT_ID_V6 0xf5f4 +#define S5P_FIMV_D_FRAME_PACK_SEI_INFO_V6 0xf5f8 +#define S5P_FIMV_D_FRAME_PACK_GRID_POS_V6 0xf5fc + +/* Encoder Registers */ +#define S5P_FIMV_E_FRAME_WIDTH_V6 0xf770 +#define S5P_FIMV_E_FRAME_HEIGHT_V6 0xf774 +#define S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6 0xf778 +#define S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6 0xf77c +#define S5P_FIMV_E_FRAME_CROP_OFFSET_V6 0xf780 +#define S5P_FIMV_E_ENC_OPTIONS_V6 0xf784 +#define S5P_FIMV_E_PICTURE_PROFILE_V6 0xf788 +#define S5P_FIMV_E_FIXED_PICTURE_QP_V6 0xf790 + +#define S5P_FIMV_E_RC_CONFIG_V6 0xf794 +#define S5P_FIMV_E_RC_QP_BOUND_V6 0xf798 +#define S5P_FIMV_E_RC_RPARAM_V6 0xf79c +#define S5P_FIMV_E_MB_RC_CONFIG_V6 0xf7a0 +#define S5P_FIMV_E_PADDING_CTRL_V6 0xf7a4 +#define S5P_FIMV_E_MV_HOR_RANGE_V6 0xf7ac +#define S5P_FIMV_E_MV_VER_RANGE_V6 0xf7b0 +#define S5P_FIMV_E_MV_RANGE_V6_MASK 0x3fff + +#define S5P_FIMV_E_VBV_BUFFER_SIZE_V6 0xf84c +#define S5P_FIMV_E_VBV_INIT_DELAY_V6 0xf850 +#define S5P_FIMV_E_NUM_DPB_V6 0xf890 +#define S5P_FIMV_E_LUMA_DPB_V6 0xf8c0 +#define S5P_FIMV_E_CHROMA_DPB_V6 0xf904 +#define S5P_FIMV_E_ME_BUFFER_V6 0xf948 + +#define S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6 0xf98c +#define S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6 0xf990 +#define S5P_FIMV_E_TMV_BUFFER0_V6 0xf994 +#define S5P_FIMV_E_TMV_BUFFER1_V6 0xf998 +#define S5P_FIMV_E_SOURCE_LUMA_ADDR_V6 0xf9f0 +#define S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6 0xf9f4 +#define S5P_FIMV_E_STREAM_BUFFER_ADDR_V6 0xf9f8 +#define S5P_FIMV_E_STREAM_BUFFER_SIZE_V6 0xf9fc +#define S5P_FIMV_E_ROI_BUFFER_ADDR_V6 0xfA00 + +#define S5P_FIMV_E_PARAM_CHANGE_V6 0xfa04 +#define S5P_FIMV_E_IR_SIZE_V6 0xfa08 +#define S5P_FIMV_E_GOP_CONFIG_V6 0xfa0c +#define S5P_FIMV_E_MSLICE_MODE_V6 0xfa10 +#define S5P_FIMV_E_MSLICE_SIZE_MB_V6 0xfa14 +#define S5P_FIMV_E_MSLICE_SIZE_BITS_V6 0xfa18 +#define S5P_FIMV_E_FRAME_INSERTION_V6 0xfa1c + +#define S5P_FIMV_E_RC_FRAME_RATE_V6 0xfa20 +#define S5P_FIMV_E_RC_BIT_RATE_V6 0xfa24 +#define S5P_FIMV_E_RC_QP_OFFSET_V6 0xfa28 +#define S5P_FIMV_E_RC_ROI_CTRL_V6 0xfa2c +#define S5P_FIMV_E_PICTURE_TAG_V6 0xfa30 +#define S5P_FIMV_E_BIT_COUNT_ENABLE_V6 0xfa34 +#define S5P_FIMV_E_MAX_BIT_COUNT_V6 0xfa38 +#define S5P_FIMV_E_MIN_BIT_COUNT_V6 0xfa3c + +#define S5P_FIMV_E_METADATA_BUFFER_ADDR_V6 0xfa40 +#define S5P_FIMV_E_METADATA_BUFFER_SIZE_V6 0xfa44 +#define S5P_FIMV_E_STREAM_SIZE_V6 0xfa80 +#define S5P_FIMV_E_SLICE_TYPE_V6 0xfa84 +#define S5P_FIMV_E_PICTURE_COUNT_V6 0xfa88 +#define S5P_FIMV_E_RET_PICTURE_TAG_V6 0xfa8c +#define S5P_FIMV_E_STREAM_BUFFER_WRITE_POINTER_V6 0xfa90 + +#define S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6 0xfa94 +#define S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6 0xfa98 +#define S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6 0xfa9c +#define S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6 0xfaa0 +#define S5P_FIMV_E_METADATA_ADDR_ENC_SLICE_V6 0xfaa4 +#define S5P_FIMV_E_METADATA_SIZE_ENC_SLICE_V6 0xfaa8 + +#define S5P_FIMV_E_MPEG4_OPTIONS_V6 0xfb10 +#define S5P_FIMV_E_MPEG4_HEC_PERIOD_V6 0xfb14 +#define S5P_FIMV_E_ASPECT_RATIO_V6 0xfb50 +#define S5P_FIMV_E_EXTENDED_SAR_V6 0xfb54 + +#define S5P_FIMV_E_H264_OPTIONS_V6 0xfb58 +#define S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6 0xfb5c +#define S5P_FIMV_E_H264_LF_BETA_OFFSET_V6 0xfb60 +#define S5P_FIMV_E_H264_I_PERIOD_V6 0xfb64 + +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6 0xfb68 +#define S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6 0xfb6c +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6 0xfb70 +#define S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6 0xfb74 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 0xfb78 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_1_V6 0xfb7c +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_2_V6 0xfb80 +#define S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_3_V6 0xfb84 + +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 0xfb88 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_1_V6 0xfb8c +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_2_V6 0xfb90 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_3_V6 0xfb94 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_4_V6 0xfb98 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_5_V6 0xfb9c +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_6_V6 0xfba0 +#define S5P_FIMV_E_H264_ASO_SLICE_ORDER_7_V6 0xfba4 + +#define S5P_FIMV_E_H264_CHROMA_QP_OFFSET_V6 0xfba8 +#define S5P_FIMV_E_H264_NUM_T_LAYER_V6 0xfbac + +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 0xfbb0 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER1_V6 0xfbb4 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER2_V6 0xfbb8 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER3_V6 0xfbbc +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER4_V6 0xfbc0 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER5_V6 0xfbc4 +#define S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER6_V6 0xfbc8 + +#define S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6 0xfc4c +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE_V6 0 +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TOP_BOTTOM_V6 1 +#define S5P_FIMV_ENC_FP_ARRANGEMENT_TYPE_TEMPORAL_V6 2 + +#define S5P_FIMV_E_MVC_FRAME_QP_VIEW1_V6 0xfd40 +#define S5P_FIMV_E_MVC_RC_FRAME_RATE_VIEW1_V6 0xfd44 +#define S5P_FIMV_E_MVC_RC_BIT_RATE_VIEW1_V6 0xfd48 +#define S5P_FIMV_E_MVC_RC_QBOUND_VIEW1_V6 0xfd4c +#define S5P_FIMV_E_MVC_RC_RPARA_VIEW1_V6 0xfd50 +#define S5P_FIMV_E_MVC_INTER_VIEW_PREDICTION_ON_V6 0xfd80 + +/* Codec numbers */ +#define S5P_FIMV_CODEC_NONE_V6 -1 + + +#define S5P_FIMV_CODEC_H264_DEC_V6 0 +#define S5P_FIMV_CODEC_H264_MVC_DEC_V6 1 + +#define S5P_FIMV_CODEC_MPEG4_DEC_V6 3 +#define S5P_FIMV_CODEC_FIMV1_DEC_V6 4 +#define S5P_FIMV_CODEC_FIMV2_DEC_V6 5 +#define S5P_FIMV_CODEC_FIMV3_DEC_V6 6 +#define S5P_FIMV_CODEC_FIMV4_DEC_V6 7 +#define S5P_FIMV_CODEC_H263_DEC_V6 8 +#define S5P_FIMV_CODEC_VC1RCV_DEC_V6 9 +#define S5P_FIMV_CODEC_VC1_DEC_V6 10 +/* FIXME: Add 11~12 */ +#define S5P_FIMV_CODEC_MPEG2_DEC_V6 13 +#define S5P_FIMV_CODEC_VP8_DEC_V6 14 +/* FIXME: Add 15~16 */ +#define S5P_FIMV_CODEC_H264_ENC_V6 20 +#define S5P_FIMV_CODEC_H264_MVC_ENC_V6 21 + +#define S5P_FIMV_CODEC_MPEG4_ENC_V6 23 +#define S5P_FIMV_CODEC_H263_ENC_V6 24 + +#define S5P_FIMV_NV12M_HALIGN_V6 16 +#define S5P_FIMV_NV12MT_HALIGN_V6 16 +#define S5P_FIMV_NV12MT_VALIGN_V6 16 + +#define S5P_FIMV_TMV_BUFFER_ALIGN_V6 16 +#define S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_ME_BUFFER_ALIGN_V6 256 +#define S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6 256 + +#define S5P_FIMV_LUMA_MB_TO_PIXEL_V6 256 +#define S5P_FIMV_CHROMA_MB_TO_PIXEL_V6 128 +#define S5P_FIMV_NUM_TMV_BUFFERS_V6 2 + +#define S5P_FIMV_MAX_FRAME_SIZE_V6 (2 * SZ_1M) +#define S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6 16 +#define S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6 16 + +/* Buffer size requirements defined by hardware */ +#define S5P_FIMV_TMV_BUFFER_SIZE_V6(w, h) (((w) + 1) * ((h) + 3) * 8) +#define S5P_FIMV_ME_BUFFER_SIZE_V6(imw, imh, mbw, mbh) \ + (((((imw + 127) / 64) * 16) * DIV_ROUND_UP(imh, 64) * 256) + \ + (DIV_ROUND_UP((mbw) * (mbh), 32) * 16)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6(w, h) (((w) * 192) + 64) +#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) \ + ((w) * 144 + 8192 * (h) + 49216 + 1048576) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(w, h) \ + (2096 * ((w) + (h) + 1)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) \ + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6(w, h) \ + ((w) * 32 + (h) * 128 + (((w) + 1) / 2) * 64 + 2112) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6(w, h) \ + (((w) * 64) + (((w) + 1) * 16) + (4096 * 16)) +#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6(w, h) \ + (((w) * 16) + (((w) + 1) * 16)) + +/* MFC Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V6 (28 * SZ_1K) /* 28KB */ +#define MFC_H264_DEC_CTX_BUF_SIZE_V6 (2 * SZ_1M) /* 2MB */ +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V6 (20 * SZ_1K) /* 20KB */ +#define MFC_H264_ENC_CTX_BUF_SIZE_V6 (100 * SZ_1K) /* 100KB */ +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V6 (12 * SZ_1K) /* 12KB */ + +/* MFCv6 variant defines */ +#define MAX_FW_SIZE_V6 (SZ_512K) /* 512KB */ +#define MAX_CPB_SIZE_V6 (3 * SZ_1M) /* 3MB */ +#define MFC_VERSION_V6 0x61 +#define MFC_NUM_PORTS_V6 1 + +#endif /* _REGS_FIMV_V6_H */ diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h new file mode 100644 index 000000000000..4a7adfdaa359 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v7.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Register definition file for Samsung MFC V7.x Interface (FIMV) driver + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef _REGS_MFC_V7_H +#define _REGS_MFC_V7_H + +#include "regs-mfc-v6.h" + +/* Additional features of v7 */ +#define S5P_FIMV_CODEC_VP8_ENC_V7 25 + +/* Additional registers for v7 */ +#define S5P_FIMV_E_SOURCE_FIRST_ADDR_V7 0xf9e0 +#define S5P_FIMV_E_SOURCE_SECOND_ADDR_V7 0xf9e4 +#define S5P_FIMV_E_SOURCE_THIRD_ADDR_V7 0xf9e8 +#define S5P_FIMV_E_SOURCE_FIRST_STRIDE_V7 0xf9ec +#define S5P_FIMV_E_SOURCE_SECOND_STRIDE_V7 0xf9f0 +#define S5P_FIMV_E_SOURCE_THIRD_STRIDE_V7 0xf9f4 + +#define S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7 0xfa70 +#define S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7 0xfa74 + +#define S5P_FIMV_E_VP8_OPTIONS_V7 0xfdb0 +#define S5P_FIMV_E_VP8_FILTER_OPTIONS_V7 0xfdb4 +#define S5P_FIMV_E_VP8_GOLDEN_FRAME_OPTION_V7 0xfdb8 +#define S5P_FIMV_E_VP8_NUM_T_LAYER_V7 0xfdc4 + +/* MFCv7 variant defines */ +#define MAX_FW_SIZE_V7 (SZ_512K) /* 512KB */ +#define MAX_CPB_SIZE_V7 (3 * SZ_1M) /* 3MB */ +#define MFC_VERSION_V7 0x72 +#define MFC_NUM_PORTS_V7 1 + +#define MFC_LUMA_PAD_BYTES_V7 256 +#define MFC_CHROMA_PAD_BYTES_V7 128 + +/* MFCv7 Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V7 (30 * SZ_1K) /* 30KB */ +#define MFC_H264_DEC_CTX_BUF_SIZE_V7 (2 * SZ_1M) /* 2MB */ +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V7 (20 * SZ_1K) /* 20KB */ +#define MFC_H264_ENC_CTX_BUF_SIZE_V7 (100 * SZ_1K) /* 100KB */ +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V7 (10 * SZ_1K) /* 10KB */ + +/* Buffer size defines */ +#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7(w, h) \ + (SZ_1M + ((w) * 144) + (8192 * (h)) + 49216) + +#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V7(w, h) \ + (((w) * 48) + 8192 + ((((w) + 1) / 2) * 128) + 144 + \ + ((((((w) * 16) * ((h) * 16)) * 3) / 2) * 4)) + +#endif /*_REGS_MFC_V7_H*/ diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h new file mode 100644 index 000000000000..162e3c7e920f --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc-v8.h @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Register definition file for Samsung MFC V8.x Interface (FIMV) driver + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef _REGS_MFC_V8_H +#define _REGS_MFC_V8_H + +#include +#include "regs-mfc-v7.h" + +/* Additional registers for v8 */ +#define S5P_FIMV_D_MVC_NUM_VIEWS_V8 0xf104 +#define S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8 0xf108 +#define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8 0xf144 +#define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8 0xf148 +#define S5P_FIMV_D_MV_BUFFER_SIZE_V8 0xf150 + +#define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8 0xf138 +#define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8 0xf13c + +#define S5P_FIMV_D_FIRST_PLANE_DPB_V8 0xf160 +#define S5P_FIMV_D_SECOND_PLANE_DPB_V8 0xf260 +#define S5P_FIMV_D_MV_BUFFER_V8 0xf460 + +#define S5P_FIMV_D_NUM_MV_V8 0xf134 +#define S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8 0xf154 + +#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8 0xf560 +#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8 0xf564 + +#define S5P_FIMV_D_CPB_BUFFER_ADDR_V8 0xf5b0 +#define S5P_FIMV_D_CPB_BUFFER_SIZE_V8 0xf5b4 +#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8 0xf5bc +#define S5P_FIMV_D_CPB_BUFFER_OFFSET_V8 0xf5c0 +#define S5P_FIMV_D_SLICE_IF_ENABLE_V8 0xf5c4 +#define S5P_FIMV_D_STREAM_DATA_SIZE_V8 0xf5d0 + +/* Display information register */ +#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V8 0xf600 +#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V8 0xf604 + +/* Display status */ +#define S5P_FIMV_D_DISPLAY_STATUS_V8 0xf608 + +#define S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR_V8 0xf60c +#define S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR_V8 0xf610 + +#define S5P_FIMV_D_DISPLAY_FRAME_TYPE_V8 0xf618 +#define S5P_FIMV_D_DISPLAY_CROP_INFO1_V8 0xf61c +#define S5P_FIMV_D_DISPLAY_CROP_INFO2_V8 0xf620 +#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE_V8 0xf624 + +/* Decoded picture information register */ +#define S5P_FIMV_D_DECODED_STATUS_V8 0xf644 +#define S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR_V8 0xf648 +#define S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR_V8 0xf64c +#define S5P_FIMV_D_DECODED_THIRD_PLANE_ADDR_V8 0xf650 +#define S5P_FIMV_D_DECODED_FRAME_TYPE_V8 0xf654 +#define S5P_FIMV_D_DECODED_NAL_SIZE_V8 0xf664 + +/* Returned value register for specific setting */ +#define S5P_FIMV_D_RET_PICTURE_TAG_TOP_V8 0xf674 +#define S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8 0xf678 +#define S5P_FIMV_D_MVC_VIEW_ID_V8 0xf6d8 + +/* SEI related information */ +#define S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V8 0xf6dc + +/* Encoder Registers */ +#define S5P_FIMV_E_FIXED_PICTURE_QP_V8 0xf794 +#define S5P_FIMV_E_RC_CONFIG_V8 0xf798 +#define S5P_FIMV_E_RC_QP_BOUND_V8 0xf79c +#define S5P_FIMV_E_RC_RPARAM_V8 0xf7a4 +#define S5P_FIMV_E_MB_RC_CONFIG_V8 0xf7a8 +#define S5P_FIMV_E_PADDING_CTRL_V8 0xf7ac +#define S5P_FIMV_E_MV_HOR_RANGE_V8 0xf7b4 +#define S5P_FIMV_E_MV_VER_RANGE_V8 0xf7b8 + +#define S5P_FIMV_E_VBV_BUFFER_SIZE_V8 0xf78c +#define S5P_FIMV_E_VBV_INIT_DELAY_V8 0xf790 +#define S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8 0xf894 + +#define S5P_FIMV_E_ASPECT_RATIO_V8 0xfb4c +#define S5P_FIMV_E_EXTENDED_SAR_V8 0xfb50 +#define S5P_FIMV_E_H264_OPTIONS_V8 0xfb54 + +/* MFCv8 Context buffer sizes */ +#define MFC_CTX_BUF_SIZE_V8 (36 * SZ_1K) /* 36KB */ +#define MFC_H264_DEC_CTX_BUF_SIZE_V8 (2 * SZ_1M) /* 2MB */ +#define MFC_OTHER_DEC_CTX_BUF_SIZE_V8 (20 * SZ_1K) /* 20KB */ +#define MFC_H264_ENC_CTX_BUF_SIZE_V8 (100 * SZ_1K) /* 100KB */ +#define MFC_OTHER_ENC_CTX_BUF_SIZE_V8 (10 * SZ_1K) /* 10KB */ + +/* Buffer size defines */ +#define S5P_FIMV_TMV_BUFFER_SIZE_V8(w, h) (((w) + 1) * ((h) + 1) * 8) + +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8(w, h) (((w) * 704) + 2176) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8(w, h) \ + (((w) * 576 + (h) * 128) + 4128) + +#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8(w, h) \ + (((w) * 592) + 2336) +#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8(w, h) \ + (((w) * 576) + 10512 + \ + ((((((w) * 16) * ((h) * 16)) * 3) / 2) * 4)) +#define S5P_FIMV_ME_BUFFER_SIZE_V8(imw, imh, mbw, mbh) \ + ((DIV_ROUND_UP((mbw * 16), 64) * DIV_ROUND_UP((mbh * 16), 64) * 256) \ + + (DIV_ROUND_UP((mbw) * (mbh), 32) * 16)) + +/* BUffer alignment defines */ +#define S5P_FIMV_D_ALIGN_PLANE_SIZE_V8 64 + +/* MFCv8 variant defines */ +#define MAX_FW_SIZE_V8 (SZ_512K) /* 512KB */ +#define MAX_CPB_SIZE_V8 (3 * SZ_1M) /* 3MB */ +#define MFC_VERSION_V8 0x80 +#define MFC_NUM_PORTS_V8 1 + +#endif /*_REGS_MFC_V8_H*/ diff --git a/drivers/media/platform/samsung/s5p-mfc/regs-mfc.h b/drivers/media/platform/samsung/s5p-mfc/regs-mfc.h new file mode 100644 index 000000000000..9171e8181c18 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/regs-mfc.h @@ -0,0 +1,459 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Register definition file for Samsung MFC V5.1 Interface (FIMV) driver + * + * Kamil Debski, Copyright (c) 2010 Samsung Electronics + * http://www.samsung.com/ +*/ + +#ifndef _REGS_FIMV_H +#define _REGS_FIMV_H + +#include +#include + +#define S5P_FIMV_REG_SIZE (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) +#define S5P_FIMV_REG_COUNT ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) + +/* Number of bits that the buffer address should be shifted for particular + * MFC buffers. */ +#define S5P_FIMV_START_ADDR 0x0000 +#define S5P_FIMV_END_ADDR 0xe008 + +#define S5P_FIMV_SW_RESET 0x0000 +#define S5P_FIMV_RISC_HOST_INT 0x0008 + +/* Command from HOST to RISC */ +#define S5P_FIMV_HOST2RISC_CMD 0x0030 +#define S5P_FIMV_HOST2RISC_ARG1 0x0034 +#define S5P_FIMV_HOST2RISC_ARG2 0x0038 +#define S5P_FIMV_HOST2RISC_ARG3 0x003c +#define S5P_FIMV_HOST2RISC_ARG4 0x0040 + +/* Command from RISC to HOST */ +#define S5P_FIMV_RISC2HOST_CMD 0x0044 +#define S5P_FIMV_RISC2HOST_CMD_MASK 0x1FFFF +#define S5P_FIMV_RISC2HOST_ARG1 0x0048 +#define S5P_FIMV_RISC2HOST_ARG2 0x004c +#define S5P_FIMV_RISC2HOST_ARG3 0x0050 +#define S5P_FIMV_RISC2HOST_ARG4 0x0054 + +#define S5P_FIMV_FW_VERSION 0x0058 +#define S5P_FIMV_SYS_MEM_SZ 0x005c +#define S5P_FIMV_FW_STATUS 0x0080 + +/* Memory controller register */ +#define S5P_FIMV_MC_DRAMBASE_ADR_A 0x0508 +#define S5P_FIMV_MC_DRAMBASE_ADR_B 0x050c +#define S5P_FIMV_MC_STATUS 0x0510 + +/* Common register */ +#define S5P_FIMV_COMMON_BASE_A 0x0600 +#define S5P_FIMV_COMMON_BASE_B 0x0700 + +/* Decoder */ +#define S5P_FIMV_DEC_CHROMA_ADR (S5P_FIMV_COMMON_BASE_A) +#define S5P_FIMV_DEC_LUMA_ADR (S5P_FIMV_COMMON_BASE_B) + +/* H.264 decoding */ +#define S5P_FIMV_H264_VERT_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) + /* vertical neighbor motion vector */ +#define S5P_FIMV_H264_NB_IP_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) + /* neighbor pixels for intra pred */ +#define S5P_FIMV_H264_MV_ADR (S5P_FIMV_COMMON_BASE_B + 0x80) + /* H264 motion vector */ + +/* MPEG4 decoding */ +#define S5P_FIMV_MPEG4_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) + /* neighbor AC/DC coeff. */ +#define S5P_FIMV_MPEG4_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) + /* upper neighbor motion vector */ +#define S5P_FIMV_MPEG4_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) + /* subseq. anchor motion vector */ +#define S5P_FIMV_MPEG4_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) + /* overlap transform line */ +#define S5P_FIMV_MPEG4_SP_ADR (S5P_FIMV_COMMON_BASE_A + 0xa8) + /* syntax parser */ + +/* H.263 decoding */ +#define S5P_FIMV_H263_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) +#define S5P_FIMV_H263_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) +#define S5P_FIMV_H263_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) +#define S5P_FIMV_H263_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) + +/* VC-1 decoding */ +#define S5P_FIMV_VC1_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) +#define S5P_FIMV_VC1_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) +#define S5P_FIMV_VC1_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) +#define S5P_FIMV_VC1_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) +#define S5P_FIMV_VC1_BITPLANE3_ADR (S5P_FIMV_COMMON_BASE_A + 0x9c) + /* bitplane3 */ +#define S5P_FIMV_VC1_BITPLANE2_ADR (S5P_FIMV_COMMON_BASE_A + 0xa0) + /* bitplane2 */ +#define S5P_FIMV_VC1_BITPLANE1_ADR (S5P_FIMV_COMMON_BASE_A + 0xa4) + /* bitplane1 */ + +/* Encoder */ +#define S5P_FIMV_ENC_REF0_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x1c) +#define S5P_FIMV_ENC_REF1_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x20) + /* reconstructed luma */ +#define S5P_FIMV_ENC_REF0_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B) +#define S5P_FIMV_ENC_REF1_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x04) + /* reconstructed chroma */ +#define S5P_FIMV_ENC_REF2_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x10) +#define S5P_FIMV_ENC_REF2_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x08) +#define S5P_FIMV_ENC_REF3_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x14) +#define S5P_FIMV_ENC_REF3_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x0c) + +/* H.264 encoding */ +#define S5P_FIMV_H264_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) + /* upper motion vector */ +#define S5P_FIMV_H264_NBOR_INFO_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) + /* entropy engine's neighbor info. */ +#define S5P_FIMV_H264_UP_INTRA_MD_ADR (S5P_FIMV_COMMON_BASE_A + 0x08) + /* upper intra MD */ +#define S5P_FIMV_H264_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) + /* direct cozero flag */ +#define S5P_FIMV_H264_UP_INTRA_PRED_ADR (S5P_FIMV_COMMON_BASE_B + 0x40) + /* upper intra PRED */ + +/* H.263 encoding */ +#define S5P_FIMV_H263_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) + /* upper motion vector */ +#define S5P_FIMV_H263_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) + /* upper Q coeff. */ + +/* MPEG4 encoding */ +#define S5P_FIMV_MPEG4_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) + /* upper motion vector */ +#define S5P_FIMV_MPEG4_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) + /* upper Q coeff. */ +#define S5P_FIMV_MPEG4_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) + /* direct cozero flag */ + +#define S5P_FIMV_ENC_REF_B_LUMA_ADR 0x062c /* ref B Luma addr */ +#define S5P_FIMV_ENC_REF_B_CHROMA_ADR 0x0630 /* ref B Chroma addr */ + +#define S5P_FIMV_ENC_CUR_LUMA_ADR 0x0718 /* current Luma addr */ +#define S5P_FIMV_ENC_CUR_CHROMA_ADR 0x071C /* current Chroma addr */ + +/* Codec common register */ +#define S5P_FIMV_ENC_HSIZE_PX 0x0818 /* frame width at encoder */ +#define S5P_FIMV_ENC_VSIZE_PX 0x081c /* frame height at encoder */ +#define S5P_FIMV_ENC_PROFILE 0x0830 /* profile register */ +#define S5P_FIMV_ENC_PROFILE_H264_MAIN 0 +#define S5P_FIMV_ENC_PROFILE_H264_HIGH 1 +#define S5P_FIMV_ENC_PROFILE_H264_BASELINE 2 +#define S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE 3 +#define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0 +#define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1 +#define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */ +#define S5P_FIMV_ENC_LF_CTRL 0x0848 /* loop filter control */ +#define S5P_FIMV_ENC_ALPHA_OFF 0x084c /* loop filter alpha offset */ +#define S5P_FIMV_ENC_BETA_OFF 0x0850 /* loop filter beta offset */ +#define S5P_FIMV_MR_BUSIF_CTRL 0x0854 /* hidden, bus interface ctrl */ +#define S5P_FIMV_ENC_PXL_CACHE_CTRL 0x0a00 /* pixel cache control */ + +/* Channel & stream interface register */ +#define S5P_FIMV_SI_RTN_CHID 0x2000 /* Return CH inst ID register */ +#define S5P_FIMV_SI_CH0_INST_ID 0x2040 /* codec instance ID */ +#define S5P_FIMV_SI_CH1_INST_ID 0x2080 /* codec instance ID */ +/* Decoder */ +#define S5P_FIMV_SI_VRESOL 0x2004 /* vertical res of decoder */ +#define S5P_FIMV_SI_HRESOL 0x2008 /* horizontal res of decoder */ +#define S5P_FIMV_SI_BUF_NUMBER 0x200c /* number of frames in the + decoded pic */ +#define S5P_FIMV_SI_DISPLAY_Y_ADR 0x2010 /* luma addr of displayed pic */ +#define S5P_FIMV_SI_DISPLAY_C_ADR 0x2014 /* chroma addrof displayed pic */ + +#define S5P_FIMV_SI_CONSUMED_BYTES 0x2018 /* Consumed number of bytes to + decode a frame */ +#define S5P_FIMV_SI_DISPLAY_STATUS 0x201c /* status of decoded picture */ + +#define S5P_FIMV_SI_DECODE_Y_ADR 0x2024 /* luma addr of decoded pic */ +#define S5P_FIMV_SI_DECODE_C_ADR 0x2028 /* chroma addrof decoded pic */ +#define S5P_FIMV_SI_DECODE_STATUS 0x202c /* status of decoded picture */ + +#define S5P_FIMV_SI_CH0_SB_ST_ADR 0x2044 /* start addr of stream buf */ +#define S5P_FIMV_SI_CH0_SB_FRM_SIZE 0x2048 /* size of stream buf */ +#define S5P_FIMV_SI_CH0_DESC_ADR 0x204c /* addr of descriptor buf */ +#define S5P_FIMV_SI_CH0_CPB_SIZE 0x2058 /* max size of coded pic. buf */ +#define S5P_FIMV_SI_CH0_DESC_SIZE 0x205c /* max size of descriptor buf */ + +#define S5P_FIMV_SI_CH1_SB_ST_ADR 0x2084 /* start addr of stream buf */ +#define S5P_FIMV_SI_CH1_SB_FRM_SIZE 0x2088 /* size of stream buf */ +#define S5P_FIMV_SI_CH1_DESC_ADR 0x208c /* addr of descriptor buf */ +#define S5P_FIMV_SI_CH1_CPB_SIZE 0x2098 /* max size of coded pic. buf */ +#define S5P_FIMV_SI_CH1_DESC_SIZE 0x209c /* max size of descriptor buf */ + +#define S5P_FIMV_CRC_LUMA0 0x2030 /* luma crc data per frame + (top field) */ +#define S5P_FIMV_CRC_CHROMA0 0x2034 /* chroma crc data per frame + (top field) */ +#define S5P_FIMV_CRC_LUMA1 0x2038 /* luma crc data per bottom + field */ +#define S5P_FIMV_CRC_CHROMA1 0x203c /* chroma crc data per bottom + field */ + +/* Display status */ +#define S5P_FIMV_DEC_STATUS_DECODING_ONLY 0 +#define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY 1 +#define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY 2 +#define S5P_FIMV_DEC_STATUS_DECODING_EMPTY 3 +#define S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK 7 +#define S5P_FIMV_DEC_STATUS_PROGRESSIVE (0<<3) +#define S5P_FIMV_DEC_STATUS_INTERLACE (1<<3) +#define S5P_FIMV_DEC_STATUS_INTERLACE_MASK (1<<3) +#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_TWO (0<<4) +#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_FOUR (1<<4) +#define S5P_FIMV_DEC_STATUS_CRC_NUMBER_MASK (1<<4) +#define S5P_FIMV_DEC_STATUS_CRC_GENERATED (1<<5) +#define S5P_FIMV_DEC_STATUS_CRC_NOT_GENERATED (0<<5) +#define S5P_FIMV_DEC_STATUS_CRC_MASK (1<<5) + +#define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) +#define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) +#define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) +#define S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT 4 + +/* Decode frame address */ +#define S5P_FIMV_DECODE_Y_ADR 0x2024 +#define S5P_FIMV_DECODE_C_ADR 0x2028 + +/* Decoded frame tpe */ +#define S5P_FIMV_DECODE_FRAME_TYPE 0x2020 +#define S5P_FIMV_DECODE_FRAME_MASK 7 + +#define S5P_FIMV_DECODE_FRAME_SKIPPED 0 +#define S5P_FIMV_DECODE_FRAME_I_FRAME 1 +#define S5P_FIMV_DECODE_FRAME_P_FRAME 2 +#define S5P_FIMV_DECODE_FRAME_B_FRAME 3 +#define S5P_FIMV_DECODE_FRAME_OTHER_FRAME 4 + +/* Sizes of buffers required for decoding */ +#define S5P_FIMV_DEC_NB_IP_SIZE (32 * 1024) +#define S5P_FIMV_DEC_VERT_NB_MV_SIZE (16 * 1024) +#define S5P_FIMV_DEC_NB_DCAC_SIZE (16 * 1024) +#define S5P_FIMV_DEC_UPNB_MV_SIZE (68 * 1024) +#define S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE (136 * 1024) +#define S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE (32 * 1024) +#define S5P_FIMV_DEC_VC1_BITPLANE_SIZE (2 * 1024) +#define S5P_FIMV_DEC_STX_PARSER_SIZE (68 * 1024) + +#define S5P_FIMV_DEC_BUF_ALIGN (8 * 1024) +#define S5P_FIMV_ENC_BUF_ALIGN (8 * 1024) +#define S5P_FIMV_NV12M_HALIGN 16 +#define S5P_FIMV_NV12M_LVALIGN 16 +#define S5P_FIMV_NV12M_CVALIGN 8 +#define S5P_FIMV_NV12MT_HALIGN 128 +#define S5P_FIMV_NV12MT_VALIGN 32 +#define S5P_FIMV_NV12M_SALIGN 2048 +#define S5P_FIMV_NV12MT_SALIGN 8192 + +/* Sizes of buffers required for encoding */ +#define S5P_FIMV_ENC_UPMV_SIZE 0x10000 +#define S5P_FIMV_ENC_COLFLG_SIZE 0x10000 +#define S5P_FIMV_ENC_INTRAMD_SIZE 0x10000 +#define S5P_FIMV_ENC_INTRAPRED_SIZE 0x4000 +#define S5P_FIMV_ENC_NBORINFO_SIZE 0x10000 +#define S5P_FIMV_ENC_ACDCCOEF_SIZE 0x10000 + +/* Encoder */ +#define S5P_FIMV_ENC_SI_STRM_SIZE 0x2004 /* stream size */ +#define S5P_FIMV_ENC_SI_PIC_CNT 0x2008 /* picture count */ +#define S5P_FIMV_ENC_SI_WRITE_PTR 0x200c /* write pointer */ +#define S5P_FIMV_ENC_SI_SLICE_TYPE 0x2010 /* slice type(I/P/B/IDR) */ +#define S5P_FIMV_ENC_SI_SLICE_TYPE_NON_CODED 0 +#define S5P_FIMV_ENC_SI_SLICE_TYPE_I 1 +#define S5P_FIMV_ENC_SI_SLICE_TYPE_P 2 +#define S5P_FIMV_ENC_SI_SLICE_TYPE_B 3 +#define S5P_FIMV_ENC_SI_SLICE_TYPE_SKIPPED 4 +#define S5P_FIMV_ENC_SI_SLICE_TYPE_OTHERS 5 +#define S5P_FIMV_ENCODED_Y_ADDR 0x2014 /* the addr of the encoded + luma pic */ +#define S5P_FIMV_ENCODED_C_ADDR 0x2018 /* the addr of the encoded + chroma pic */ + +#define S5P_FIMV_ENC_SI_CH0_SB_ADR 0x2044 /* addr of stream buf */ +#define S5P_FIMV_ENC_SI_CH0_SB_SIZE 0x204c /* size of stream buf */ +#define S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR 0x2050 /* current Luma addr */ +#define S5P_FIMV_ENC_SI_CH0_CUR_C_ADR 0x2054 /* current Chroma addr */ +#define S5P_FIMV_ENC_SI_CH0_FRAME_INS 0x2058 /* frame insertion */ + +#define S5P_FIMV_ENC_SI_CH1_SB_ADR 0x2084 /* addr of stream buf */ +#define S5P_FIMV_ENC_SI_CH1_SB_SIZE 0x208c /* size of stream buf */ +#define S5P_FIMV_ENC_SI_CH1_CUR_Y_ADR 0x2090 /* current Luma addr */ +#define S5P_FIMV_ENC_SI_CH1_CUR_C_ADR 0x2094 /* current Chroma addr */ +#define S5P_FIMV_ENC_SI_CH1_FRAME_INS 0x2098 /* frame insertion */ + +#define S5P_FIMV_ENC_PIC_TYPE_CTRL 0xc504 /* pic type level control */ +#define S5P_FIMV_ENC_B_RECON_WRITE_ON 0xc508 /* B frame recon write ctrl */ +#define S5P_FIMV_ENC_MSLICE_CTRL 0xc50c /* multi slice control */ +#define S5P_FIMV_ENC_MSLICE_MB 0xc510 /* MB number in the one slice */ +#define S5P_FIMV_ENC_MSLICE_BIT 0xc514 /* bit count for one slice */ +#define S5P_FIMV_ENC_CIR_CTRL 0xc518 /* number of intra refresh MB */ +#define S5P_FIMV_ENC_MAP_FOR_CUR 0xc51c /* linear or tiled mode */ +#define S5P_FIMV_ENC_PADDING_CTRL 0xc520 /* padding control */ + +#define S5P_FIMV_ENC_RC_CONFIG 0xc5a0 /* RC config */ +#define S5P_FIMV_ENC_RC_BIT_RATE 0xc5a8 /* bit rate */ +#define S5P_FIMV_ENC_RC_QBOUND 0xc5ac /* max/min QP */ +#define S5P_FIMV_ENC_RC_RPARA 0xc5b0 /* rate control reaction coeff */ +#define S5P_FIMV_ENC_RC_MB_CTRL 0xc5b4 /* MB adaptive scaling */ + +/* Encoder for H264 only */ +#define S5P_FIMV_ENC_H264_ENTROPY_MODE 0xd004 /* CAVLC or CABAC */ +#define S5P_FIMV_ENC_H264_ALPHA_OFF 0xd008 /* loop filter alpha offset */ +#define S5P_FIMV_ENC_H264_BETA_OFF 0xd00c /* loop filter beta offset */ +#define S5P_FIMV_ENC_H264_NUM_OF_REF 0xd010 /* number of reference for P/B */ +#define S5P_FIMV_ENC_H264_TRANS_FLAG 0xd034 /* 8x8 transform flag in PPS & + high profile */ + +#define S5P_FIMV_ENC_RC_FRAME_RATE 0xd0d0 /* frame rate */ + +/* Encoder for MPEG4 only */ +#define S5P_FIMV_ENC_MPEG4_QUART_PXL 0xe008 /* qpel interpolation ctrl */ + +/* Additional */ +#define S5P_FIMV_SI_CH0_DPB_CONF_CTRL 0x2068 /* DPB Config Control Register */ +#define S5P_FIMV_SLICE_INT_MASK 1 +#define S5P_FIMV_SLICE_INT_SHIFT 31 +#define S5P_FIMV_DDELAY_ENA_SHIFT 30 +#define S5P_FIMV_DDELAY_VAL_MASK 0xff +#define S5P_FIMV_DDELAY_VAL_SHIFT 16 +#define S5P_FIMV_DPB_COUNT_MASK 0xffff +#define S5P_FIMV_DPB_FLUSH_MASK 1 +#define S5P_FIMV_DPB_FLUSH_SHIFT 14 + + +#define S5P_FIMV_SI_CH0_RELEASE_BUF 0x2060 /* DPB release buffer register */ +#define S5P_FIMV_SI_CH0_HOST_WR_ADR 0x2064 /* address of shared memory */ + +/* Codec numbers */ +#define S5P_FIMV_CODEC_NONE -1 + +#define S5P_FIMV_CODEC_H264_DEC 0 +#define S5P_FIMV_CODEC_VC1_DEC 1 +#define S5P_FIMV_CODEC_MPEG4_DEC 2 +#define S5P_FIMV_CODEC_MPEG2_DEC 3 +#define S5P_FIMV_CODEC_H263_DEC 4 +#define S5P_FIMV_CODEC_VC1RCV_DEC 5 + +#define S5P_FIMV_CODEC_H264_ENC 16 +#define S5P_FIMV_CODEC_MPEG4_ENC 17 +#define S5P_FIMV_CODEC_H263_ENC 18 + +/* Channel Control Register */ +#define S5P_FIMV_CH_SEQ_HEADER 1 +#define S5P_FIMV_CH_FRAME_START 2 +#define S5P_FIMV_CH_LAST_FRAME 3 +#define S5P_FIMV_CH_INIT_BUFS 4 +#define S5P_FIMV_CH_FRAME_START_REALLOC 5 +#define S5P_FIMV_CH_MASK 7 +#define S5P_FIMV_CH_SHIFT 16 + + +/* Host to RISC command */ +#define S5P_FIMV_H2R_CMD_EMPTY 0 +#define S5P_FIMV_H2R_CMD_OPEN_INSTANCE 1 +#define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE 2 +#define S5P_FIMV_H2R_CMD_SYS_INIT 3 +#define S5P_FIMV_H2R_CMD_FLUSH 4 +#define S5P_FIMV_H2R_CMD_SLEEP 5 +#define S5P_FIMV_H2R_CMD_WAKEUP 6 + +#define S5P_FIMV_R2H_CMD_EMPTY 0 +#define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET 1 +#define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET 2 +#define S5P_FIMV_R2H_CMD_RSV_RET 3 +#define S5P_FIMV_R2H_CMD_SEQ_DONE_RET 4 +#define S5P_FIMV_R2H_CMD_FRAME_DONE_RET 5 +#define S5P_FIMV_R2H_CMD_SLICE_DONE_RET 6 +#define S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET 7 +#define S5P_FIMV_R2H_CMD_SYS_INIT_RET 8 +#define S5P_FIMV_R2H_CMD_FW_STATUS_RET 9 +#define S5P_FIMV_R2H_CMD_SLEEP_RET 10 +#define S5P_FIMV_R2H_CMD_WAKEUP_RET 11 +#define S5P_FIMV_R2H_CMD_FLUSH_RET 12 +#define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET 15 +#define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16 +#define S5P_FIMV_R2H_CMD_ERR_RET 32 + +/* Dummy definition for MFCv6 compatibility */ +#define S5P_FIMV_CODEC_H264_MVC_DEC -1 +#define S5P_FIMV_R2H_CMD_FIELD_DONE_RET -1 +#define S5P_FIMV_MFC_RESET -1 +#define S5P_FIMV_RISC_ON -1 +#define S5P_FIMV_RISC_BASE_ADDRESS -1 +#define S5P_FIMV_CODEC_VP8_DEC -1 +#define S5P_FIMV_REG_CLEAR_BEGIN 0 +#define S5P_FIMV_REG_CLEAR_COUNT 0 + +/* Error handling defines */ +#define S5P_FIMV_ERR_NO_VALID_SEQ_HDR 67 +#define S5P_FIMV_ERR_INCOMPLETE_FRAME 124 +#define S5P_FIMV_ERR_TIMEOUT 140 +#define S5P_FIMV_ERR_WARNINGS_START 145 +#define S5P_FIMV_ERR_DEC_MASK 0xFFFF +#define S5P_FIMV_ERR_DEC_SHIFT 0 +#define S5P_FIMV_ERR_DSPL_MASK 0xFFFF0000 +#define S5P_FIMV_ERR_DSPL_SHIFT 16 + +/* Shared memory registers' offsets */ + +/* An offset of the start position in the stream when + * the start position is not aligned */ +#define S5P_FIMV_SHARED_CROP_INFO_H 0x0020 +#define S5P_FIMV_SHARED_CROP_LEFT_MASK 0xFFFF +#define S5P_FIMV_SHARED_CROP_LEFT_SHIFT 0 +#define S5P_FIMV_SHARED_CROP_RIGHT_MASK 0xFFFF0000 +#define S5P_FIMV_SHARED_CROP_RIGHT_SHIFT 16 +#define S5P_FIMV_SHARED_CROP_INFO_V 0x0024 +#define S5P_FIMV_SHARED_CROP_TOP_MASK 0xFFFF +#define S5P_FIMV_SHARED_CROP_TOP_SHIFT 0 +#define S5P_FIMV_SHARED_CROP_BOTTOM_MASK 0xFFFF0000 +#define S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT 16 +#define S5P_FIMV_SHARED_SET_FRAME_TAG 0x0004 +#define S5P_FIMV_SHARED_GET_FRAME_TAG_TOP 0x0008 +#define S5P_FIMV_SHARED_GET_FRAME_TAG_BOT 0x000C +#define S5P_FIMV_SHARED_START_BYTE_NUM 0x0018 +#define S5P_FIMV_SHARED_RC_VOP_TIMING 0x0030 +#define S5P_FIMV_SHARED_LUMA_DPB_SIZE 0x0064 +#define S5P_FIMV_SHARED_CHROMA_DPB_SIZE 0x0068 +#define S5P_FIMV_SHARED_MV_SIZE 0x006C +#define S5P_FIMV_SHARED_PIC_TIME_TOP 0x0010 +#define S5P_FIMV_SHARED_PIC_TIME_BOTTOM 0x0014 +#define S5P_FIMV_SHARED_EXT_ENC_CONTROL 0x0028 +#define S5P_FIMV_SHARED_P_B_FRAME_QP 0x0070 +#define S5P_FIMV_SHARED_ASPECT_RATIO_IDC 0x0074 +#define S5P_FIMV_SHARED_EXTENDED_SAR 0x0078 +#define S5P_FIMV_SHARED_H264_I_PERIOD 0x009C +#define S5P_FIMV_SHARED_RC_CONTROL_CONFIG 0x00A0 +#define S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT 2 + +/* Offset used by the hardware to store addresses */ +#define MFC_OFFSET_SHIFT 11 + +#define FIRMWARE_ALIGN (128 * SZ_1K) /* 128KB */ +#define MFC_H264_CTX_BUF_SIZE (600 * SZ_1K) /* 600KB per H264 instance */ +#define MFC_CTX_BUF_SIZE (10 * SZ_1K) /* 10KB per instance */ +#define DESC_BUF_SIZE (128 * SZ_1K) /* 128KB for DESC buffer */ +#define SHARED_BUF_SIZE (8 * SZ_1K) /* 8KB for shared buffer */ + +#define DEF_CPB_SIZE (256 * SZ_1K) /* 256KB */ +#define MAX_CPB_SIZE (4 * SZ_1M) /* 4MB */ +#define MAX_FW_SIZE (384 * SZ_1K) + +#define MFC_VERSION 0x51 +#define MFC_NUM_PORTS 2 + +#define S5P_FIMV_SHARED_FRAME_PACK_SEI_AVAIL 0x16C +#define S5P_FIMV_SHARED_FRAME_PACK_ARRGMENT_ID 0x170 +#define S5P_FIMV_SHARED_FRAME_PACK_SEI_INFO 0x174 +#define S5P_FIMV_SHARED_FRAME_PACK_GRID_POS 0x178 + +/* Values for resolution change in display status */ +#define S5P_FIMV_RES_INCREASE 1 +#define S5P_FIMV_RES_DECREASE 2 + +#endif /* _REGS_FIMV_H */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c new file mode 100644 index 000000000000..761341934925 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -0,0 +1,1680 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Samsung S5P Multi Format Codec v 5.1 + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "s5p_mfc_common.h" +#include "s5p_mfc_ctrl.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_dec.h" +#include "s5p_mfc_enc.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_iommu.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_pm.h" + +#define S5P_MFC_DEC_NAME "s5p-mfc-dec" +#define S5P_MFC_ENC_NAME "s5p-mfc-enc" + +int mfc_debug_level; +module_param_named(debug, mfc_debug_level, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); + +static char *mfc_mem_size; +module_param_named(mem, mfc_mem_size, charp, 0644); +MODULE_PARM_DESC(mem, "Preallocated memory size for the firmware and context buffers"); + +/* Helper functions for interrupt processing */ + +/* Remove from hw execution round robin */ +void clear_work_bit(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + spin_lock(&dev->condlock); + __clear_bit(ctx->num, &dev->ctx_work_bits); + spin_unlock(&dev->condlock); +} + +/* Add to hw execution round robin */ +void set_work_bit(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + spin_lock(&dev->condlock); + __set_bit(ctx->num, &dev->ctx_work_bits); + spin_unlock(&dev->condlock); +} + +/* Remove from hw execution round robin */ +void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->condlock, flags); + __clear_bit(ctx->num, &dev->ctx_work_bits); + spin_unlock_irqrestore(&dev->condlock, flags); +} + +/* Add to hw execution round robin */ +void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + + spin_lock_irqsave(&dev->condlock, flags); + __set_bit(ctx->num, &dev->ctx_work_bits); + spin_unlock_irqrestore(&dev->condlock, flags); +} + +int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) +{ + unsigned long flags; + int ctx; + + spin_lock_irqsave(&dev->condlock, flags); + ctx = dev->curr_ctx; + do { + ctx = (ctx + 1) % MFC_NUM_CONTEXTS; + if (ctx == dev->curr_ctx) { + if (!test_bit(ctx, &dev->ctx_work_bits)) + ctx = -EAGAIN; + break; + } + } while (!test_bit(ctx, &dev->ctx_work_bits)); + spin_unlock_irqrestore(&dev->condlock, flags); + + return ctx; +} + +/* Wake up context wait_queue */ +static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason, + unsigned int err) +{ + ctx->int_cond = 1; + ctx->int_type = reason; + ctx->int_err = err; + wake_up(&ctx->queue); +} + +/* Wake up device wait_queue */ +static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason, + unsigned int err) +{ + dev->int_cond = 1; + dev->int_type = reason; + dev->int_err = err; + wake_up(&dev->queue); +} + +void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) +{ + struct s5p_mfc_buf *b; + int i; + + while (!list_empty(lh)) { + b = list_entry(lh->next, struct s5p_mfc_buf, list); + for (i = 0; i < b->b->vb2_buf.num_planes; i++) + vb2_set_plane_payload(&b->b->vb2_buf, i, 0); + vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR); + list_del(&b->list); + } +} + +static void s5p_mfc_watchdog(struct timer_list *t) +{ + struct s5p_mfc_dev *dev = from_timer(dev, t, watchdog_timer); + + if (test_bit(0, &dev->hw_lock)) + atomic_inc(&dev->watchdog_cnt); + if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) { + /* This means that hw is busy and no interrupts were + * generated by hw for the Nth time of running this + * watchdog timer. This usually means a serious hw + * error. Now it is time to kill all instances and + * reset the MFC. */ + mfc_err("Time out during waiting for HW\n"); + schedule_work(&dev->watchdog_work); + } + dev->watchdog_timer.expires = jiffies + + msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); + add_timer(&dev->watchdog_timer); +} + +static void s5p_mfc_watchdog_worker(struct work_struct *work) +{ + struct s5p_mfc_dev *dev; + struct s5p_mfc_ctx *ctx; + unsigned long flags; + int mutex_locked; + int i, ret; + + dev = container_of(work, struct s5p_mfc_dev, watchdog_work); + + mfc_err("Driver timeout error handling\n"); + /* Lock the mutex that protects open and release. + * This is necessary as they may load and unload firmware. */ + mutex_locked = mutex_trylock(&dev->mfc_mutex); + if (!mutex_locked) + mfc_err("Error: some instance may be closing/opening\n"); + spin_lock_irqsave(&dev->irqlock, flags); + + s5p_mfc_clock_off(); + + for (i = 0; i < MFC_NUM_CONTEXTS; i++) { + ctx = dev->ctx[i]; + if (!ctx) + continue; + ctx->state = MFCINST_ERROR; + s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + clear_work_bit(ctx); + wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0); + } + clear_bit(0, &dev->hw_lock); + spin_unlock_irqrestore(&dev->irqlock, flags); + + /* De-init MFC */ + s5p_mfc_deinit_hw(dev); + + /* Double check if there is at least one instance running. + * If no instance is in memory than no firmware should be present */ + if (dev->num_inst > 0) { + ret = s5p_mfc_load_firmware(dev); + if (ret) { + mfc_err("Failed to reload FW\n"); + goto unlock; + } + s5p_mfc_clock_on(); + ret = s5p_mfc_init_hw(dev); + s5p_mfc_clock_off(); + if (ret) + mfc_err("Failed to reinit FW\n"); + } +unlock: + if (mutex_locked) + mutex_unlock(&dev->mfc_mutex); +} + +static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_buf *dst_buf; + struct s5p_mfc_dev *dev = ctx->dev; + + ctx->state = MFCINST_FINISHED; + ctx->sequence++; + while (!list_empty(&ctx->dst_queue)) { + dst_buf = list_entry(ctx->dst_queue.next, + struct s5p_mfc_buf, list); + mfc_debug(2, "Cleaning up buffer: %d\n", + dst_buf->b->vb2_buf.index); + vb2_set_plane_payload(&dst_buf->b->vb2_buf, 0, 0); + vb2_set_plane_payload(&dst_buf->b->vb2_buf, 1, 0); + list_del(&dst_buf->list); + dst_buf->flags |= MFC_BUF_FLAG_EOS; + ctx->dst_queue_cnt--; + dst_buf->b->sequence = (ctx->sequence++); + + if (s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_top, ctx) == + s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_bot, ctx)) + dst_buf->b->field = V4L2_FIELD_NONE; + else + dst_buf->b->field = V4L2_FIELD_INTERLACED; + dst_buf->b->flags |= V4L2_BUF_FLAG_LAST; + + ctx->dec_dst_flag &= ~(1 << dst_buf->b->vb2_buf.index); + vb2_buffer_done(&dst_buf->b->vb2_buf, VB2_BUF_STATE_DONE); + } +} + +static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *dst_buf, *src_buf; + u32 dec_y_addr; + unsigned int frame_type; + + /* Make sure we actually have a new frame before continuing. */ + frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev); + if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) + return; + dec_y_addr = (u32)s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev); + + /* Copy timestamp / timecode from decoded src to dst and set + appropriate flags. */ + src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + list_for_each_entry(dst_buf, &ctx->dst_queue, list) { + u32 addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0); + + if (addr == dec_y_addr) { + dst_buf->b->timecode = src_buf->b->timecode; + dst_buf->b->vb2_buf.timestamp = + src_buf->b->vb2_buf.timestamp; + dst_buf->b->flags &= + ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_buf->b->flags |= + src_buf->b->flags + & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + switch (frame_type) { + case S5P_FIMV_DECODE_FRAME_I_FRAME: + dst_buf->b->flags |= + V4L2_BUF_FLAG_KEYFRAME; + break; + case S5P_FIMV_DECODE_FRAME_P_FRAME: + dst_buf->b->flags |= + V4L2_BUF_FLAG_PFRAME; + break; + case S5P_FIMV_DECODE_FRAME_B_FRAME: + dst_buf->b->flags |= + V4L2_BUF_FLAG_BFRAME; + break; + default: + /* Don't know how to handle + S5P_FIMV_DECODE_FRAME_OTHER_FRAME. */ + mfc_debug(2, "Unexpected frame type: %d\n", + frame_type); + } + break; + } + } +} + +static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *dst_buf; + u32 dspl_y_addr; + unsigned int frame_type; + + dspl_y_addr = (u32)s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev); + if (IS_MFCV6_PLUS(dev)) + frame_type = s5p_mfc_hw_call(dev->mfc_ops, + get_disp_frame_type, ctx); + else + frame_type = s5p_mfc_hw_call(dev->mfc_ops, + get_dec_frame_type, dev); + + /* If frame is same as previous then skip and do not dequeue */ + if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { + if (!ctx->after_packed_pb) + ctx->sequence++; + ctx->after_packed_pb = 0; + return; + } + ctx->sequence++; + /* The MFC returns address of the buffer, now we have to + * check which videobuf does it correspond to */ + list_for_each_entry(dst_buf, &ctx->dst_queue, list) { + u32 addr = (u32)vb2_dma_contig_plane_dma_addr(&dst_buf->b->vb2_buf, 0); + + /* Check if this is the buffer we're looking for */ + if (addr == dspl_y_addr) { + list_del(&dst_buf->list); + ctx->dst_queue_cnt--; + dst_buf->b->sequence = ctx->sequence; + if (s5p_mfc_hw_call(dev->mfc_ops, + get_pic_type_top, ctx) == + s5p_mfc_hw_call(dev->mfc_ops, + get_pic_type_bot, ctx)) + dst_buf->b->field = V4L2_FIELD_NONE; + else + dst_buf->b->field = + V4L2_FIELD_INTERLACED; + vb2_set_plane_payload(&dst_buf->b->vb2_buf, 0, + ctx->luma_size); + vb2_set_plane_payload(&dst_buf->b->vb2_buf, 1, + ctx->chroma_size); + clear_bit(dst_buf->b->vb2_buf.index, + &ctx->dec_dst_flag); + + vb2_buffer_done(&dst_buf->b->vb2_buf, err ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + + break; + } + } +} + +/* Handle frame decoding interrupt */ +static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, + unsigned int reason, unsigned int err) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dst_frame_status; + unsigned int dec_frame_status; + struct s5p_mfc_buf *src_buf; + unsigned int res_change; + + dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) + & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; + dec_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dec_status, dev) + & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; + res_change = (s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) + & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK) + >> S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT; + mfc_debug(2, "Frame Status: %x\n", dst_frame_status); + if (ctx->state == MFCINST_RES_CHANGE_INIT) + ctx->state = MFCINST_RES_CHANGE_FLUSH; + if (res_change == S5P_FIMV_RES_INCREASE || + res_change == S5P_FIMV_RES_DECREASE) { + ctx->state = MFCINST_RES_CHANGE_INIT; + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + wake_up_ctx(ctx, reason, err); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); + s5p_mfc_clock_off(); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + return; + } + if (ctx->dpb_flush_flag) + ctx->dpb_flush_flag = 0; + + /* All frames remaining in the buffer have been extracted */ + if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) { + if (ctx->state == MFCINST_RES_CHANGE_FLUSH) { + static const struct v4l2_event ev_src_ch = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = + V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + s5p_mfc_handle_frame_all_extracted(ctx); + ctx->state = MFCINST_RES_CHANGE_END; + v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); + + goto leave_handle_frame; + } else { + s5p_mfc_handle_frame_all_extracted(ctx); + } + } + + if (dec_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) + s5p_mfc_handle_frame_copy_time(ctx); + + /* A frame has been decoded and is in the buffer */ + if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY || + dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) { + s5p_mfc_handle_frame_new(ctx, err); + } else { + mfc_debug(2, "No frame decode\n"); + } + /* Mark source buffer as complete */ + if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY + && !list_empty(&ctx->src_queue)) { + src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, + list); + ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops, + get_consumed_stream, dev); + if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC && + ctx->codec_mode != S5P_MFC_CODEC_VP8_DEC && + ctx->consumed_stream + STUFF_BYTE < + src_buf->b->vb2_buf.planes[0].bytesused) { + /* Run MFC again on the same buffer */ + mfc_debug(2, "Running again the same buffer\n"); + ctx->after_packed_pb = 1; + } else { + mfc_debug(2, "MFC needs next buffer\n"); + ctx->consumed_stream = 0; + if (src_buf->flags & MFC_BUF_FLAG_EOS) + ctx->state = MFCINST_FINISHING; + list_del(&src_buf->list); + ctx->src_queue_cnt--; + if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0) + vb2_buffer_done(&src_buf->b->vb2_buf, + VB2_BUF_STATE_ERROR); + else + vb2_buffer_done(&src_buf->b->vb2_buf, + VB2_BUF_STATE_DONE); + } + } +leave_handle_frame: + if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) + || ctx->dst_queue_cnt < ctx->pb_count) + clear_work_bit(ctx); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + wake_up_ctx(ctx, reason, err); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); + s5p_mfc_clock_off(); + /* if suspending, wake up device and do not try_run again*/ + if (test_bit(0, &dev->enter_suspend)) + wake_up_dev(dev, reason, err); + else + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); +} + +/* Error handling for interrupt */ +static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, + struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err) +{ + mfc_err("Interrupt Error: %08x\n", err); + + if (ctx) { + /* Error recovery is dependent on the state of context */ + switch (ctx->state) { + case MFCINST_RES_CHANGE_INIT: + case MFCINST_RES_CHANGE_FLUSH: + case MFCINST_RES_CHANGE_END: + case MFCINST_FINISHING: + case MFCINST_FINISHED: + case MFCINST_RUNNING: + /* It is highly probable that an error occurred + * while decoding a frame */ + clear_work_bit(ctx); + ctx->state = MFCINST_ERROR; + /* Mark all dst buffers as having an error */ + s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + /* Mark all src buffers as having an error */ + s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + wake_up_ctx(ctx, reason, err); + break; + default: + clear_work_bit(ctx); + ctx->state = MFCINST_ERROR; + wake_up_ctx(ctx, reason, err); + break; + } + } + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_clock_off(); + wake_up_dev(dev, reason, err); +} + +/* Header parsing interrupt handling */ +static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, + unsigned int reason, unsigned int err) +{ + struct s5p_mfc_dev *dev; + + if (!ctx) + return; + dev = ctx->dev; + if (ctx->c_ops->post_seq_start) { + if (ctx->c_ops->post_seq_start(ctx)) + mfc_err("post_seq_start() failed\n"); + } else { + ctx->img_width = s5p_mfc_hw_call(dev->mfc_ops, get_img_width, + dev); + ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height, + dev); + + s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx); + + ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, + dev); + ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, + dev); + if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + get_min_scratch_buf_size, dev); + if (ctx->img_width == 0 || ctx->img_height == 0) + ctx->state = MFCINST_ERROR; + else + ctx->state = MFCINST_HEAD_PARSED; + + if ((ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) && + !list_empty(&ctx->src_queue)) { + struct s5p_mfc_buf *src_buf; + src_buf = list_entry(ctx->src_queue.next, + struct s5p_mfc_buf, list); + if (s5p_mfc_hw_call(dev->mfc_ops, get_consumed_stream, + dev) < + src_buf->b->vb2_buf.planes[0].bytesused) + ctx->head_processed = 0; + else + ctx->head_processed = 1; + } else { + ctx->head_processed = 1; + } + } + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + clear_work_bit(ctx); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); + s5p_mfc_clock_off(); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + wake_up_ctx(ctx, reason, err); +} + +/* Header parsing interrupt handling */ +static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, + unsigned int reason, unsigned int err) +{ + struct s5p_mfc_buf *src_buf; + struct s5p_mfc_dev *dev; + + if (!ctx) + return; + dev = ctx->dev; + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + ctx->int_type = reason; + ctx->int_err = err; + ctx->int_cond = 1; + clear_work_bit(ctx); + if (err == 0) { + ctx->state = MFCINST_RUNNING; + if (!ctx->dpb_flush_flag && ctx->head_processed) { + if (!list_empty(&ctx->src_queue)) { + src_buf = list_entry(ctx->src_queue.next, + struct s5p_mfc_buf, list); + list_del(&src_buf->list); + ctx->src_queue_cnt--; + vb2_buffer_done(&src_buf->b->vb2_buf, + VB2_BUF_STATE_DONE); + } + } else { + ctx->dpb_flush_flag = 0; + } + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); + + s5p_mfc_clock_off(); + + wake_up(&ctx->queue); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + } else { + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); + + s5p_mfc_clock_off(); + + wake_up(&ctx->queue); + } +} + +static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *mb_entry; + + mfc_debug(2, "Stream completed\n"); + + ctx->state = MFCINST_FINISHED; + + if (!list_empty(&ctx->dst_queue)) { + mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, + list); + list_del(&mb_entry->list); + ctx->dst_queue_cnt--; + vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, 0); + vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE); + } + + clear_work_bit(ctx); + + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); + + s5p_mfc_clock_off(); + wake_up(&ctx->queue); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); +} + +/* Interrupt processing */ +static irqreturn_t s5p_mfc_irq(int irq, void *priv) +{ + struct s5p_mfc_dev *dev = priv; + struct s5p_mfc_ctx *ctx; + unsigned int reason; + unsigned int err; + + mfc_debug_enter(); + /* Reset the timeout watchdog */ + atomic_set(&dev->watchdog_cnt, 0); + spin_lock(&dev->irqlock); + ctx = dev->ctx[dev->curr_ctx]; + /* Get the reason of interrupt and the error code */ + reason = s5p_mfc_hw_call(dev->mfc_ops, get_int_reason, dev); + err = s5p_mfc_hw_call(dev->mfc_ops, get_int_err, dev); + mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err); + switch (reason) { + case S5P_MFC_R2H_CMD_ERR_RET: + /* An error has occurred */ + if (ctx->state == MFCINST_RUNNING && + (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >= + dev->warn_start || + err == S5P_FIMV_ERR_NO_VALID_SEQ_HDR || + err == S5P_FIMV_ERR_INCOMPLETE_FRAME || + err == S5P_FIMV_ERR_TIMEOUT)) + s5p_mfc_handle_frame(ctx, reason, err); + else + s5p_mfc_handle_error(dev, ctx, reason, err); + clear_bit(0, &dev->enter_suspend); + break; + + case S5P_MFC_R2H_CMD_SLICE_DONE_RET: + case S5P_MFC_R2H_CMD_FIELD_DONE_RET: + case S5P_MFC_R2H_CMD_FRAME_DONE_RET: + if (ctx->c_ops->post_frame_start) { + if (ctx->c_ops->post_frame_start(ctx)) + mfc_err("post_frame_start() failed\n"); + + if (ctx->state == MFCINST_FINISHING && + list_empty(&ctx->ref_queue)) { + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + s5p_mfc_handle_stream_complete(ctx); + break; + } + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); + s5p_mfc_clock_off(); + wake_up_ctx(ctx, reason, err); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + } else { + s5p_mfc_handle_frame(ctx, reason, err); + } + break; + + case S5P_MFC_R2H_CMD_SEQ_DONE_RET: + s5p_mfc_handle_seq_done(ctx, reason, err); + break; + + case S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET: + ctx->inst_no = s5p_mfc_hw_call(dev->mfc_ops, get_inst_no, dev); + ctx->state = MFCINST_GOT_INST; + goto irq_cleanup_hw; + + case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET: + ctx->inst_no = MFC_NO_INSTANCE_SET; + ctx->state = MFCINST_FREE; + goto irq_cleanup_hw; + + case S5P_MFC_R2H_CMD_SYS_INIT_RET: + case S5P_MFC_R2H_CMD_FW_STATUS_RET: + case S5P_MFC_R2H_CMD_SLEEP_RET: + case S5P_MFC_R2H_CMD_WAKEUP_RET: + if (ctx) + clear_work_bit(ctx); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + clear_bit(0, &dev->hw_lock); + clear_bit(0, &dev->enter_suspend); + wake_up_dev(dev, reason, err); + break; + + case S5P_MFC_R2H_CMD_INIT_BUFFERS_RET: + s5p_mfc_handle_init_buffers(ctx, reason, err); + break; + + case S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET: + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + ctx->int_type = reason; + ctx->int_err = err; + s5p_mfc_handle_stream_complete(ctx); + break; + + case S5P_MFC_R2H_CMD_DPB_FLUSH_RET: + ctx->state = MFCINST_RUNNING; + goto irq_cleanup_hw; + + default: + mfc_debug(2, "Unknown int reason\n"); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + } + spin_unlock(&dev->irqlock); + mfc_debug_leave(); + return IRQ_HANDLED; +irq_cleanup_hw: + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); + ctx->int_type = reason; + ctx->int_err = err; + ctx->int_cond = 1; + if (test_and_clear_bit(0, &dev->hw_lock) == 0) + mfc_err("Failed to unlock hw\n"); + + s5p_mfc_clock_off(); + clear_work_bit(ctx); + wake_up(&ctx->queue); + + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + spin_unlock(&dev->irqlock); + mfc_debug(2, "Exit via irq_cleanup_hw\n"); + return IRQ_HANDLED; +} + +/* Open an MFC node */ +static int s5p_mfc_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct s5p_mfc_dev *dev = video_drvdata(file); + struct s5p_mfc_ctx *ctx = NULL; + struct vb2_queue *q; + int ret = 0; + + mfc_debug_enter(); + if (mutex_lock_interruptible(&dev->mfc_mutex)) + return -ERESTARTSYS; + dev->num_inst++; /* It is guarded by mfc_mutex in vfd */ + /* Allocate memory for context */ + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + ret = -ENOMEM; + goto err_alloc; + } + init_waitqueue_head(&ctx->queue); + v4l2_fh_init(&ctx->fh, vdev); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + ctx->dev = dev; + INIT_LIST_HEAD(&ctx->src_queue); + INIT_LIST_HEAD(&ctx->dst_queue); + ctx->src_queue_cnt = 0; + ctx->dst_queue_cnt = 0; + /* Get context number */ + ctx->num = 0; + while (dev->ctx[ctx->num]) { + ctx->num++; + if (ctx->num >= MFC_NUM_CONTEXTS) { + mfc_debug(2, "Too many open contexts\n"); + ret = -EBUSY; + goto err_no_ctx; + } + } + /* Mark context as idle */ + clear_work_bit_irqsave(ctx); + dev->ctx[ctx->num] = ctx; + if (vdev == dev->vfd_dec) { + ctx->type = MFCINST_DECODER; + ctx->c_ops = get_dec_codec_ops(); + s5p_mfc_dec_init(ctx); + /* Setup ctrl handler */ + ret = s5p_mfc_dec_ctrls_setup(ctx); + if (ret) { + mfc_err("Failed to setup mfc controls\n"); + goto err_ctrls_setup; + } + } else if (vdev == dev->vfd_enc) { + ctx->type = MFCINST_ENCODER; + ctx->c_ops = get_enc_codec_ops(); + /* only for encoder */ + INIT_LIST_HEAD(&ctx->ref_queue); + ctx->ref_queue_cnt = 0; + s5p_mfc_enc_init(ctx); + /* Setup ctrl handler */ + ret = s5p_mfc_enc_ctrls_setup(ctx); + if (ret) { + mfc_err("Failed to setup mfc controls\n"); + goto err_ctrls_setup; + } + } else { + ret = -ENOENT; + goto err_bad_node; + } + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + ctx->inst_no = MFC_NO_INSTANCE_SET; + /* Load firmware if this is the first instance */ + if (dev->num_inst == 1) { + dev->watchdog_timer.expires = jiffies + + msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); + add_timer(&dev->watchdog_timer); + ret = s5p_mfc_power_on(); + if (ret < 0) { + mfc_err("power on failed\n"); + goto err_pwr_enable; + } + s5p_mfc_clock_on(); + ret = s5p_mfc_load_firmware(dev); + if (ret) { + s5p_mfc_clock_off(); + goto err_load_fw; + } + /* Init the FW */ + ret = s5p_mfc_init_hw(dev); + s5p_mfc_clock_off(); + if (ret) + goto err_init_hw; + } + /* Init videobuf2 queue for CAPTURE */ + q = &ctx->vq_dst; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->drv_priv = &ctx->fh; + q->lock = &dev->mfc_mutex; + if (vdev == dev->vfd_dec) { + q->io_modes = VB2_MMAP; + q->ops = get_dec_queue_ops(); + } else if (vdev == dev->vfd_enc) { + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->ops = get_enc_queue_ops(); + } else { + ret = -ENOENT; + goto err_queue_init; + } + /* + * We'll do mostly sequential access, so sacrifice TLB efficiency for + * faster allocation. + */ + q->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + ret = vb2_queue_init(q); + if (ret) { + mfc_err("Failed to initialize videobuf2 queue(capture)\n"); + goto err_queue_init; + } + /* Init videobuf2 queue for OUTPUT */ + q = &ctx->vq_src; + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + q->drv_priv = &ctx->fh; + q->lock = &dev->mfc_mutex; + if (vdev == dev->vfd_dec) { + q->io_modes = VB2_MMAP; + q->ops = get_dec_queue_ops(); + } else if (vdev == dev->vfd_enc) { + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->ops = get_enc_queue_ops(); + } else { + ret = -ENOENT; + goto err_queue_init; + } + /* One way to indicate end-of-stream for MFC is to set the + * bytesused == 0. However by default videobuf2 handles bytesused + * equal to 0 as a special case and changes its value to the size + * of the buffer. Set the allow_zero_bytesused flag so that videobuf2 + * will keep the value of bytesused intact. + */ + q->allow_zero_bytesused = 1; + + /* + * We'll do mostly sequential access, so sacrifice TLB efficiency for + * faster allocation. + */ + q->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + ret = vb2_queue_init(q); + if (ret) { + mfc_err("Failed to initialize videobuf2 queue(output)\n"); + goto err_queue_init; + } + mutex_unlock(&dev->mfc_mutex); + mfc_debug_leave(); + return ret; + /* Deinit when failure occurred */ +err_queue_init: + if (dev->num_inst == 1) + s5p_mfc_deinit_hw(dev); +err_init_hw: +err_load_fw: +err_pwr_enable: + if (dev->num_inst == 1) { + if (s5p_mfc_power_off() < 0) + mfc_err("power off failed\n"); + del_timer_sync(&dev->watchdog_timer); + } +err_ctrls_setup: + s5p_mfc_dec_ctrls_delete(ctx); +err_bad_node: + dev->ctx[ctx->num] = NULL; +err_no_ctx: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); +err_alloc: + dev->num_inst--; + mutex_unlock(&dev->mfc_mutex); + mfc_debug_leave(); + return ret; +} + +/* Release MFC context */ +static int s5p_mfc_release(struct file *file) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_dev *dev = ctx->dev; + + /* if dev is null, do cleanup that doesn't need dev */ + mfc_debug_enter(); + if (dev) + mutex_lock(&dev->mfc_mutex); + vb2_queue_release(&ctx->vq_src); + vb2_queue_release(&ctx->vq_dst); + if (dev) { + s5p_mfc_clock_on(); + + /* Mark context as idle */ + clear_work_bit_irqsave(ctx); + /* + * If instance was initialised and not yet freed, + * return instance and free resources + */ + if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) { + mfc_debug(2, "Has to free instance\n"); + s5p_mfc_close_mfc_inst(dev, ctx); + } + /* hardware locking scheme */ + if (dev->curr_ctx == ctx->num) + clear_bit(0, &dev->hw_lock); + dev->num_inst--; + if (dev->num_inst == 0) { + mfc_debug(2, "Last instance\n"); + s5p_mfc_deinit_hw(dev); + del_timer_sync(&dev->watchdog_timer); + s5p_mfc_clock_off(); + if (s5p_mfc_power_off() < 0) + mfc_err("Power off failed\n"); + } else { + mfc_debug(2, "Shutting down clock\n"); + s5p_mfc_clock_off(); + } + } + if (dev) + dev->ctx[ctx->num] = NULL; + s5p_mfc_dec_ctrls_delete(ctx); + v4l2_fh_del(&ctx->fh); + /* vdev is gone if dev is null */ + if (dev) + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + mfc_debug_leave(); + if (dev) + mutex_unlock(&dev->mfc_mutex); + + return 0; +} + +/* Poll */ +static __poll_t s5p_mfc_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + struct s5p_mfc_dev *dev = ctx->dev; + struct vb2_queue *src_q, *dst_q; + struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; + __poll_t rc = 0; + unsigned long flags; + + mutex_lock(&dev->mfc_mutex); + src_q = &ctx->vq_src; + dst_q = &ctx->vq_dst; + /* + * There has to be at least one buffer queued on each queued_list, which + * means either in driver already or waiting for driver to claim it + * and start processing. + */ + if ((!src_q->streaming || list_empty(&src_q->queued_list)) + && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { + rc = EPOLLERR; + goto end; + } + mutex_unlock(&dev->mfc_mutex); + poll_wait(file, &ctx->fh.wait, wait); + poll_wait(file, &src_q->done_wq, wait); + poll_wait(file, &dst_q->done_wq, wait); + mutex_lock(&dev->mfc_mutex); + if (v4l2_event_pending(&ctx->fh)) + rc |= EPOLLPRI; + spin_lock_irqsave(&src_q->done_lock, flags); + if (!list_empty(&src_q->done_list)) + src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, + done_entry); + if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE + || src_vb->state == VB2_BUF_STATE_ERROR)) + rc |= EPOLLOUT | EPOLLWRNORM; + spin_unlock_irqrestore(&src_q->done_lock, flags); + spin_lock_irqsave(&dst_q->done_lock, flags); + if (!list_empty(&dst_q->done_list)) + dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer, + done_entry); + if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE + || dst_vb->state == VB2_BUF_STATE_ERROR)) + rc |= EPOLLIN | EPOLLRDNORM; + spin_unlock_irqrestore(&dst_q->done_lock, flags); +end: + mutex_unlock(&dev->mfc_mutex); + return rc; +} + +/* Mmap */ +static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + int ret; + + if (offset < DST_QUEUE_OFF_BASE) { + mfc_debug(2, "mmaping source\n"); + ret = vb2_mmap(&ctx->vq_src, vma); + } else { /* capture */ + mfc_debug(2, "mmaping destination\n"); + vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); + ret = vb2_mmap(&ctx->vq_dst, vma); + } + return ret; +} + +/* v4l2 ops */ +static const struct v4l2_file_operations s5p_mfc_fops = { + .owner = THIS_MODULE, + .open = s5p_mfc_open, + .release = s5p_mfc_release, + .poll = s5p_mfc_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = s5p_mfc_mmap, +}; + +/* DMA memory related helper functions */ +static void s5p_mfc_memdev_release(struct device *dev) +{ + of_reserved_mem_device_release(dev); +} + +static struct device *s5p_mfc_alloc_memdev(struct device *dev, + const char *name, unsigned int idx) +{ + struct device *child; + int ret; + + child = devm_kzalloc(dev, sizeof(*child), GFP_KERNEL); + if (!child) + return NULL; + + device_initialize(child); + dev_set_name(child, "%s:%s", dev_name(dev), name); + child->parent = dev; + child->coherent_dma_mask = dev->coherent_dma_mask; + child->dma_mask = dev->dma_mask; + child->release = s5p_mfc_memdev_release; + child->dma_parms = devm_kzalloc(dev, sizeof(*child->dma_parms), + GFP_KERNEL); + if (!child->dma_parms) + goto err; + + /* + * The memdevs are not proper OF platform devices, so in order for them + * to be treated as valid DMA masters we need a bit of a hack to force + * them to inherit the MFC node's DMA configuration. + */ + of_dma_configure(child, dev->of_node, true); + + if (device_add(child) == 0) { + ret = of_reserved_mem_device_init_by_idx(child, dev->of_node, + idx); + if (ret == 0) + return child; + device_del(child); + } +err: + put_device(child); + return NULL; +} + +static int s5p_mfc_configure_2port_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = &mfc_dev->plat_dev->dev; + void *bank2_virt; + dma_addr_t bank2_dma_addr; + unsigned long align_size = 1 << MFC_BASE_ALIGN_ORDER; + int ret; + + /* + * Create and initialize virtual devices for accessing + * reserved memory regions. + */ + mfc_dev->mem_dev[BANK_L_CTX] = s5p_mfc_alloc_memdev(dev, "left", + BANK_L_CTX); + if (!mfc_dev->mem_dev[BANK_L_CTX]) + return -ENODEV; + mfc_dev->mem_dev[BANK_R_CTX] = s5p_mfc_alloc_memdev(dev, "right", + BANK_R_CTX); + if (!mfc_dev->mem_dev[BANK_R_CTX]) { + device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); + return -ENODEV; + } + + /* Allocate memory for firmware and initialize both banks addresses */ + ret = s5p_mfc_alloc_firmware(mfc_dev); + if (ret) { + device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); + device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); + return ret; + } + + mfc_dev->dma_base[BANK_L_CTX] = mfc_dev->fw_buf.dma; + + bank2_virt = dma_alloc_coherent(mfc_dev->mem_dev[BANK_R_CTX], + align_size, &bank2_dma_addr, GFP_KERNEL); + if (!bank2_virt) { + mfc_err("Allocating bank2 base failed\n"); + s5p_mfc_release_firmware(mfc_dev); + device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); + device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); + return -ENOMEM; + } + + /* Valid buffers passed to MFC encoder with LAST_FRAME command + * should not have address of bank2 - MFC will treat it as a null frame. + * To avoid such situation we set bank2 address below the pool address. + */ + mfc_dev->dma_base[BANK_R_CTX] = bank2_dma_addr - align_size; + + dma_free_coherent(mfc_dev->mem_dev[BANK_R_CTX], align_size, bank2_virt, + bank2_dma_addr); + + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK_L_CTX], + DMA_BIT_MASK(32)); + vb2_dma_contig_set_max_seg_size(mfc_dev->mem_dev[BANK_R_CTX], + DMA_BIT_MASK(32)); + + return 0; +} + +static void s5p_mfc_unconfigure_2port_memory(struct s5p_mfc_dev *mfc_dev) +{ + device_unregister(mfc_dev->mem_dev[BANK_L_CTX]); + device_unregister(mfc_dev->mem_dev[BANK_R_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK_L_CTX]); + vb2_dma_contig_clear_max_seg_size(mfc_dev->mem_dev[BANK_R_CTX]); +} + +static int s5p_mfc_configure_common_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = &mfc_dev->plat_dev->dev; + unsigned long mem_size = SZ_4M; + + if (IS_ENABLED(CONFIG_DMA_CMA) || exynos_is_iommu_available(dev)) + mem_size = SZ_8M; + + if (mfc_mem_size) + mem_size = memparse(mfc_mem_size, NULL); + + mfc_dev->mem_bitmap = bitmap_zalloc(mem_size >> PAGE_SHIFT, GFP_KERNEL); + if (!mfc_dev->mem_bitmap) + return -ENOMEM; + + mfc_dev->mem_virt = dma_alloc_coherent(dev, mem_size, + &mfc_dev->mem_base, GFP_KERNEL); + if (!mfc_dev->mem_virt) { + bitmap_free(mfc_dev->mem_bitmap); + dev_err(dev, "failed to preallocate %ld MiB for the firmware and context buffers\n", + (mem_size / SZ_1M)); + return -ENOMEM; + } + mfc_dev->mem_size = mem_size; + mfc_dev->dma_base[BANK_L_CTX] = mfc_dev->mem_base; + mfc_dev->dma_base[BANK_R_CTX] = mfc_dev->mem_base; + + /* + * MFC hardware cannot handle 0 as a base address, so mark first 128K + * as used (to keep required base alignment) and adjust base address + */ + if (mfc_dev->mem_base == (dma_addr_t)0) { + unsigned int offset = 1 << MFC_BASE_ALIGN_ORDER; + + bitmap_set(mfc_dev->mem_bitmap, 0, offset >> PAGE_SHIFT); + mfc_dev->dma_base[BANK_L_CTX] += offset; + mfc_dev->dma_base[BANK_R_CTX] += offset; + } + + /* Firmware allocation cannot fail in this case */ + s5p_mfc_alloc_firmware(mfc_dev); + + mfc_dev->mem_dev[BANK_L_CTX] = mfc_dev->mem_dev[BANK_R_CTX] = dev; + vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); + + dev_info(dev, "preallocated %ld MiB buffer for the firmware and context buffers\n", + (mem_size / SZ_1M)); + + return 0; +} + +static void s5p_mfc_unconfigure_common_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = &mfc_dev->plat_dev->dev; + + dma_free_coherent(dev, mfc_dev->mem_size, mfc_dev->mem_virt, + mfc_dev->mem_base); + bitmap_free(mfc_dev->mem_bitmap); + vb2_dma_contig_clear_max_seg_size(dev); +} + +static int s5p_mfc_configure_dma_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = &mfc_dev->plat_dev->dev; + + if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) + return s5p_mfc_configure_common_memory(mfc_dev); + else + return s5p_mfc_configure_2port_memory(mfc_dev); +} + +static void s5p_mfc_unconfigure_dma_memory(struct s5p_mfc_dev *mfc_dev) +{ + struct device *dev = &mfc_dev->plat_dev->dev; + + s5p_mfc_release_firmware(mfc_dev); + if (exynos_is_iommu_available(dev) || !IS_TWOPORT(mfc_dev)) + s5p_mfc_unconfigure_common_memory(mfc_dev); + else + s5p_mfc_unconfigure_2port_memory(mfc_dev); +} + +/* MFC probe function */ +static int s5p_mfc_probe(struct platform_device *pdev) +{ + struct s5p_mfc_dev *dev; + struct video_device *vfd; + int ret; + + pr_debug("%s++\n", __func__); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + spin_lock_init(&dev->irqlock); + spin_lock_init(&dev->condlock); + dev->plat_dev = pdev; + if (!dev->plat_dev) { + mfc_err("No platform data specified\n"); + return -ENODEV; + } + + dev->variant = of_device_get_match_data(&pdev->dev); + if (!dev->variant) { + dev_err(&pdev->dev, "Failed to get device MFC hardware variant information\n"); + return -ENOENT; + } + + dev->regs_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->regs_base)) + return PTR_ERR(dev->regs_base); + + ret = platform_get_irq(pdev, 0); + if (ret < 0) + return ret; + dev->irq = ret; + ret = devm_request_irq(&pdev->dev, dev->irq, s5p_mfc_irq, + 0, pdev->name, dev); + if (ret) { + dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret); + return ret; + } + + ret = s5p_mfc_configure_dma_memory(dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to configure DMA memory\n"); + return ret; + } + + ret = s5p_mfc_init_pm(dev); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get mfc clock source\n"); + goto err_dma; + } + + /* + * Load fails if fs isn't mounted. Try loading anyway. + * _open() will load it, it it fails now. Ignore failure. + */ + s5p_mfc_load_firmware(dev); + + mutex_init(&dev->mfc_mutex); + init_waitqueue_head(&dev->queue); + dev->hw_lock = 0; + INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker); + atomic_set(&dev->watchdog_cnt, 0); + timer_setup(&dev->watchdog_timer, s5p_mfc_watchdog, 0); + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + goto err_v4l2_dev_reg; + + /* decoder */ + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto err_dec_alloc; + } + vfd->fops = &s5p_mfc_fops; + vfd->ioctl_ops = get_dec_v4l2_ioctl_ops(); + vfd->release = video_device_release; + vfd->lock = &dev->mfc_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); + snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME); + dev->vfd_dec = vfd; + video_set_drvdata(vfd, dev); + + /* encoder */ + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto err_enc_alloc; + } + vfd->fops = &s5p_mfc_fops; + vfd->ioctl_ops = get_enc_v4l2_ioctl_ops(); + vfd->release = video_device_release; + vfd->lock = &dev->mfc_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); + dev->vfd_enc = vfd; + video_set_drvdata(vfd, dev); + platform_set_drvdata(pdev, dev); + + /* Initialize HW ops and commands based on MFC version */ + s5p_mfc_init_hw_ops(dev); + s5p_mfc_init_hw_cmds(dev); + s5p_mfc_init_regs(dev); + + /* Register decoder and encoder */ + ret = video_register_device(dev->vfd_dec, VFL_TYPE_VIDEO, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto err_dec_reg; + } + v4l2_info(&dev->v4l2_dev, + "decoder registered as /dev/video%d\n", dev->vfd_dec->num); + + ret = video_register_device(dev->vfd_enc, VFL_TYPE_VIDEO, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto err_enc_reg; + } + v4l2_info(&dev->v4l2_dev, + "encoder registered as /dev/video%d\n", dev->vfd_enc->num); + + pr_debug("%s--\n", __func__); + return 0; + +/* Deinit MFC if probe had failed */ +err_enc_reg: + video_unregister_device(dev->vfd_dec); +err_dec_reg: + video_device_release(dev->vfd_enc); +err_enc_alloc: + video_device_release(dev->vfd_dec); +err_dec_alloc: + v4l2_device_unregister(&dev->v4l2_dev); +err_v4l2_dev_reg: + s5p_mfc_final_pm(dev); +err_dma: + s5p_mfc_unconfigure_dma_memory(dev); + + pr_debug("%s-- with error\n", __func__); + return ret; + +} + +/* Remove the driver */ +static int s5p_mfc_remove(struct platform_device *pdev) +{ + struct s5p_mfc_dev *dev = platform_get_drvdata(pdev); + struct s5p_mfc_ctx *ctx; + int i; + + v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name); + + /* + * Clear ctx dev pointer to avoid races between s5p_mfc_remove() + * and s5p_mfc_release() and s5p_mfc_release() accessing ctx->dev + * after s5p_mfc_remove() is run during unbind. + */ + mutex_lock(&dev->mfc_mutex); + for (i = 0; i < MFC_NUM_CONTEXTS; i++) { + ctx = dev->ctx[i]; + if (!ctx) + continue; + /* clear ctx->dev */ + ctx->dev = NULL; + } + mutex_unlock(&dev->mfc_mutex); + + del_timer_sync(&dev->watchdog_timer); + flush_work(&dev->watchdog_work); + + video_unregister_device(dev->vfd_enc); + video_unregister_device(dev->vfd_dec); + video_device_release(dev->vfd_enc); + video_device_release(dev->vfd_dec); + v4l2_device_unregister(&dev->v4l2_dev); + s5p_mfc_unconfigure_dma_memory(dev); + + s5p_mfc_final_pm(dev); + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int s5p_mfc_suspend(struct device *dev) +{ + struct s5p_mfc_dev *m_dev = dev_get_drvdata(dev); + int ret; + + if (m_dev->num_inst == 0) + return 0; + + if (test_and_set_bit(0, &m_dev->enter_suspend) != 0) { + mfc_err("Error: going to suspend for a second time\n"); + return -EIO; + } + + /* Check if we're processing then wait if it necessary. */ + while (test_and_set_bit(0, &m_dev->hw_lock) != 0) { + /* Try and lock the HW */ + /* Wait on the interrupt waitqueue */ + ret = wait_event_interruptible_timeout(m_dev->queue, + m_dev->int_cond, msecs_to_jiffies(MFC_INT_TIMEOUT)); + if (ret == 0) { + mfc_err("Waiting for hardware to finish timed out\n"); + clear_bit(0, &m_dev->enter_suspend); + return -EIO; + } + } + + ret = s5p_mfc_sleep(m_dev); + if (ret) { + clear_bit(0, &m_dev->enter_suspend); + clear_bit(0, &m_dev->hw_lock); + } + return ret; +} + +static int s5p_mfc_resume(struct device *dev) +{ + struct s5p_mfc_dev *m_dev = dev_get_drvdata(dev); + + if (m_dev->num_inst == 0) + return 0; + return s5p_mfc_wakeup(m_dev); +} +#endif + +/* Power management */ +static const struct dev_pm_ops s5p_mfc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume) +}; + +static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { + .h264_ctx = MFC_H264_CTX_BUF_SIZE, + .non_h264_ctx = MFC_CTX_BUF_SIZE, + .dsc = DESC_BUF_SIZE, + .shm = SHARED_BUF_SIZE, +}; + +static struct s5p_mfc_buf_size buf_size_v5 = { + .fw = MAX_FW_SIZE, + .cpb = MAX_CPB_SIZE, + .priv = &mfc_buf_size_v5, +}; + +static struct s5p_mfc_variant mfc_drvdata_v5 = { + .version = MFC_VERSION, + .version_bit = MFC_V5_BIT, + .port_num = MFC_NUM_PORTS, + .buf_size = &buf_size_v5, + .fw_name[0] = "s5p-mfc.fw", + .clk_names = {"mfc", "sclk_mfc"}, + .num_clocks = 2, + .use_clock_gating = true, +}; + +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V6, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V6, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V6, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V6, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V6, +}; + +static struct s5p_mfc_buf_size buf_size_v6 = { + .fw = MAX_FW_SIZE_V6, + .cpb = MAX_CPB_SIZE_V6, + .priv = &mfc_buf_size_v6, +}; + +static struct s5p_mfc_variant mfc_drvdata_v6 = { + .version = MFC_VERSION_V6, + .version_bit = MFC_V6_BIT, + .port_num = MFC_NUM_PORTS_V6, + .buf_size = &buf_size_v6, + .fw_name[0] = "s5p-mfc-v6.fw", + /* + * v6-v2 firmware contains bug fixes and interface change + * for init buffer command + */ + .fw_name[1] = "s5p-mfc-v6-v2.fw", + .clk_names = {"mfc"}, + .num_clocks = 1, +}; + +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V7, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V7, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V7, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V7, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V7, +}; + +static struct s5p_mfc_buf_size buf_size_v7 = { + .fw = MAX_FW_SIZE_V7, + .cpb = MAX_CPB_SIZE_V7, + .priv = &mfc_buf_size_v7, +}; + +static struct s5p_mfc_variant mfc_drvdata_v7 = { + .version = MFC_VERSION_V7, + .version_bit = MFC_V7_BIT, + .port_num = MFC_NUM_PORTS_V7, + .buf_size = &buf_size_v7, + .fw_name[0] = "s5p-mfc-v7.fw", + .clk_names = {"mfc", "sclk_mfc"}, + .num_clocks = 2, +}; + +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V8, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V8, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V8, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V8, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V8, +}; + +static struct s5p_mfc_buf_size buf_size_v8 = { + .fw = MAX_FW_SIZE_V8, + .cpb = MAX_CPB_SIZE_V8, + .priv = &mfc_buf_size_v8, +}; + +static struct s5p_mfc_variant mfc_drvdata_v8 = { + .version = MFC_VERSION_V8, + .version_bit = MFC_V8_BIT, + .port_num = MFC_NUM_PORTS_V8, + .buf_size = &buf_size_v8, + .fw_name[0] = "s5p-mfc-v8.fw", + .clk_names = {"mfc"}, + .num_clocks = 1, +}; + +static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { + .version = MFC_VERSION_V8, + .version_bit = MFC_V8_BIT, + .port_num = MFC_NUM_PORTS_V8, + .buf_size = &buf_size_v8, + .fw_name[0] = "s5p-mfc-v8.fw", + .clk_names = {"pclk", "aclk", "aclk_xiu"}, + .num_clocks = 3, +}; + +static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { + .dev_ctx = MFC_CTX_BUF_SIZE_V10, + .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V10, + .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V10, + .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V10, + .hevc_enc_ctx = MFC_HEVC_ENC_CTX_BUF_SIZE_V10, + .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V10, +}; + +static struct s5p_mfc_buf_size buf_size_v10 = { + .fw = MAX_FW_SIZE_V10, + .cpb = MAX_CPB_SIZE_V10, + .priv = &mfc_buf_size_v10, +}; + +static struct s5p_mfc_variant mfc_drvdata_v10 = { + .version = MFC_VERSION_V10, + .version_bit = MFC_V10_BIT, + .port_num = MFC_NUM_PORTS_V10, + .buf_size = &buf_size_v10, + .fw_name[0] = "s5p-mfc-v10.fw", +}; + +static const struct of_device_id exynos_mfc_match[] = { + { + .compatible = "samsung,mfc-v5", + .data = &mfc_drvdata_v5, + }, { + .compatible = "samsung,mfc-v6", + .data = &mfc_drvdata_v6, + }, { + .compatible = "samsung,mfc-v7", + .data = &mfc_drvdata_v7, + }, { + .compatible = "samsung,mfc-v8", + .data = &mfc_drvdata_v8, + }, { + .compatible = "samsung,exynos5433-mfc", + .data = &mfc_drvdata_v8_5433, + }, { + .compatible = "samsung,mfc-v10", + .data = &mfc_drvdata_v10, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, exynos_mfc_match); + +static struct platform_driver s5p_mfc_driver = { + .probe = s5p_mfc_probe, + .remove = s5p_mfc_remove, + .driver = { + .name = S5P_MFC_NAME, + .pm = &s5p_mfc_pm_ops, + .of_match_table = exynos_mfc_match, + }, +}; + +module_platform_driver(s5p_mfc_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Kamil Debski "); +MODULE_DESCRIPTION("Samsung S5P Multi Format Codec V4L2 driver"); + diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c new file mode 100644 index 000000000000..774c573dc075 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c + * + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_common.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_cmd_v5.h" +#include "s5p_mfc_cmd_v6.h" + +static struct s5p_mfc_hw_cmds *s5p_mfc_cmds; + +void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev) +{ + if (IS_MFCV6_PLUS(dev)) + s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v6(); + else + s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); + + dev->mfc_cmds = s5p_mfc_cmds; +} diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h new file mode 100644 index 000000000000..945d12fdceb7 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h + * + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_CMD_H_ +#define S5P_MFC_CMD_H_ + +#include "s5p_mfc_common.h" + +#define MAX_H2R_ARG 4 + +struct s5p_mfc_cmd_args { + unsigned int arg[MAX_H2R_ARG]; +}; + +struct s5p_mfc_hw_cmds { + int (*cmd_host2risc)(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args); + int (*sys_init_cmd)(struct s5p_mfc_dev *dev); + int (*sleep_cmd)(struct s5p_mfc_dev *dev); + int (*wakeup_cmd)(struct s5p_mfc_dev *dev); + int (*open_inst_cmd)(struct s5p_mfc_ctx *ctx); + int (*close_inst_cmd)(struct s5p_mfc_ctx *ctx); +}; + +void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev); +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c new file mode 100644 index 000000000000..327e54e70611 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#include "regs-mfc.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_common.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_cmd_v5.h" + +/* This function is used to send a command to the MFC */ +static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args) +{ + int cur_cmd; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while waiting for hardware\n"); + return -EIO; + } + cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); + } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); + mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); + mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); + mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); + mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); + /* Issue the command */ + mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); + return 0; +} + +/* Initialize the MFC */ +static int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + h2r_args.arg[0] = dev->fw_buf.size; + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, + &h2r_args); +} + +/* Suspend the MFC hardware */ +static int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); +} + +/* Wake up the MFC hardware */ +static int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_WAKEUP, + &h2r_args); +} + + +static int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret; + + /* Preparing decoding - getting instance number */ + mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); + dev->curr_ctx = ctx->num; + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H264_DEC; + break; + case S5P_MFC_CODEC_VC1_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_VC1_DEC; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_DEC; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG2_DEC; + break; + case S5P_MFC_CODEC_H263_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H263_DEC; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + h2r_args.arg[0] = S5P_FIMV_CODEC_VC1RCV_DEC; + break; + case S5P_MFC_CODEC_H264_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H264_ENC; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_ENC; + break; + case S5P_MFC_CODEC_H263_ENC: + h2r_args.arg[0] = S5P_FIMV_CODEC_H263_ENC; + break; + default: + h2r_args.arg[0] = S5P_FIMV_CODEC_NONE; + } + h2r_args.arg[1] = 0; /* no crc & no pixelcache */ + h2r_args.arg[2] = ctx->ctx.ofs; + h2r_args.arg[3] = ctx->ctx.size; + ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, + &h2r_args); + if (ret) { + mfc_err("Failed to create a new instance\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +static int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret; + + if (ctx->state == MFCINST_FREE) { + mfc_err("Instance already returned\n"); + ctx->state = MFCINST_ERROR; + return -EINVAL; + } + /* Closing decoding instance */ + mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); + dev->curr_ctx = ctx->num; + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + h2r_args.arg[0] = ctx->inst_no; + ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, + &h2r_args); + if (ret) { + mfc_err("Failed to return an instance\n"); + ctx->state = MFCINST_ERROR; + return -EINVAL; + } + return 0; +} + +/* Initialize cmd function pointers for MFC v5 */ +static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = { + .cmd_host2risc = s5p_mfc_cmd_host2risc_v5, + .sys_init_cmd = s5p_mfc_sys_init_cmd_v5, + .sleep_cmd = s5p_mfc_sleep_cmd_v5, + .wakeup_cmd = s5p_mfc_wakeup_cmd_v5, + .open_inst_cmd = s5p_mfc_open_inst_cmd_v5, + .close_inst_cmd = s5p_mfc_close_inst_cmd_v5, +}; + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) +{ + return &s5p_mfc_cmds_v5; +} diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h new file mode 100644 index 000000000000..6eafa514aebc --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_CMD_V5_H_ +#define S5P_MFC_CMD_V5_H_ + +#include "s5p_mfc_common.h" + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void); + +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c new file mode 100644 index 000000000000..f8588e52dfc8 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#include "s5p_mfc_common.h" + +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_cmd_v6.h" + +static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, + struct s5p_mfc_cmd_args *args) +{ + mfc_debug(2, "Issue the command: %d\n", cmd); + + /* Reset RISC2HOST command */ + mfc_write(dev, 0x0, S5P_FIMV_RISC2HOST_CMD_V6); + + /* Issue the command */ + mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD_V6); + mfc_write(dev, 0x1, S5P_FIMV_HOST2RISC_INT_V6); + + return 0; +} + +static int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + int ret; + + ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_dev_context_buffer, dev); + if (ret) + return ret; + + mfc_write(dev, dev->ctx_buf.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); + mfc_write(dev, buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE_V6); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SYS_INIT_V6, + &h2r_args); +} + +static int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SLEEP_V6, + &h2r_args); +} + +static int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_cmd_args h2r_args; + + memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_WAKEUP_V6, + &h2r_args); +} + +/* Open a new instance and get its number */ +static int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int codec_type; + + mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); + dev->curr_ctx = ctx->num; + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + codec_type = S5P_FIMV_CODEC_H264_DEC_V6; + break; + case S5P_MFC_CODEC_H264_MVC_DEC: + codec_type = S5P_FIMV_CODEC_H264_MVC_DEC_V6; + break; + case S5P_MFC_CODEC_VC1_DEC: + codec_type = S5P_FIMV_CODEC_VC1_DEC_V6; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + codec_type = S5P_FIMV_CODEC_MPEG4_DEC_V6; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + codec_type = S5P_FIMV_CODEC_MPEG2_DEC_V6; + break; + case S5P_MFC_CODEC_H263_DEC: + codec_type = S5P_FIMV_CODEC_H263_DEC_V6; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + codec_type = S5P_FIMV_CODEC_VC1RCV_DEC_V6; + break; + case S5P_MFC_CODEC_VP8_DEC: + codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; + break; + case S5P_MFC_CODEC_HEVC_DEC: + codec_type = S5P_FIMV_CODEC_HEVC_DEC; + break; + case S5P_MFC_CODEC_VP9_DEC: + codec_type = S5P_FIMV_CODEC_VP9_DEC; + break; + case S5P_MFC_CODEC_H264_ENC: + codec_type = S5P_FIMV_CODEC_H264_ENC_V6; + break; + case S5P_MFC_CODEC_H264_MVC_ENC: + codec_type = S5P_FIMV_CODEC_H264_MVC_ENC_V6; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + codec_type = S5P_FIMV_CODEC_MPEG4_ENC_V6; + break; + case S5P_MFC_CODEC_H263_ENC: + codec_type = S5P_FIMV_CODEC_H263_ENC_V6; + break; + case S5P_MFC_CODEC_VP8_ENC: + codec_type = S5P_FIMV_CODEC_VP8_ENC_V7; + break; + case S5P_MFC_CODEC_HEVC_ENC: + codec_type = S5P_FIMV_CODEC_HEVC_ENC; + break; + default: + codec_type = S5P_FIMV_CODEC_NONE_V6; + } + mfc_write(dev, codec_type, S5P_FIMV_CODEC_TYPE_V6); + mfc_write(dev, ctx->ctx.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); + mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); + mfc_write(dev, 0, S5P_FIMV_D_CRC_CTRL_V6); /* no crc */ + + return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6, + &h2r_args); +} + +/* Close instance */ +static int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_cmd_args h2r_args; + int ret = 0; + + dev->curr_ctx = ctx->num; + if (ctx->state != MFCINST_FREE) { + mfc_write(dev, ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); + ret = s5p_mfc_cmd_host2risc_v6(dev, + S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6, + &h2r_args); + } else { + ret = -EINVAL; + } + + return ret; +} + +/* Initialize cmd function pointers for MFC v6 */ +static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { + .cmd_host2risc = s5p_mfc_cmd_host2risc_v6, + .sys_init_cmd = s5p_mfc_sys_init_cmd_v6, + .sleep_cmd = s5p_mfc_sleep_cmd_v6, + .wakeup_cmd = s5p_mfc_wakeup_cmd_v6, + .open_inst_cmd = s5p_mfc_open_inst_cmd_v6, + .close_inst_cmd = s5p_mfc_close_inst_cmd_v6, +}; + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) +{ + return &s5p_mfc_cmds_v6; +} diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h new file mode 100644 index 000000000000..9dc44460cc38 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_CMD_V6_H_ +#define S5P_MFC_CMD_V6_H_ + +#include "s5p_mfc_common.h" + +struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void); + +#endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h new file mode 100644 index 000000000000..5304f42c8c72 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h @@ -0,0 +1,792 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Samsung S5P Multi Format Codec v 5.0 + * + * This file contains definitions of enums and structs used by the codec + * driver. + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * Kamil Debski, + */ + +#ifndef S5P_MFC_COMMON_H_ +#define S5P_MFC_COMMON_H_ + +#include +#include +#include +#include +#include +#include +#include "regs-mfc.h" +#include "regs-mfc-v10.h" + +#define S5P_MFC_NAME "s5p-mfc" + +/* Definitions related to MFC memory */ + +/* Offset base used to differentiate between CAPTURE and OUTPUT +* while mmaping */ +#define DST_QUEUE_OFF_BASE (1 << 30) + +#define BANK_L_CTX 0 +#define BANK_R_CTX 1 +#define BANK_CTX_NUM 2 + +#define MFC_BANK1_ALIGN_ORDER 13 +#define MFC_BANK2_ALIGN_ORDER 13 +#define MFC_BASE_ALIGN_ORDER 17 + +#define MFC_FW_MAX_VERSIONS 2 + +#include + +/* MFC definitions */ +#define MFC_MAX_EXTRA_DPB 5 +#define MFC_MAX_BUFFERS 32 +#define MFC_NUM_CONTEXTS 4 +/* Interrupt timeout */ +#define MFC_INT_TIMEOUT 2000 +/* Busy wait timeout */ +#define MFC_BW_TIMEOUT 500 +/* Watchdog interval */ +#define MFC_WATCHDOG_INTERVAL 1000 +/* After how many executions watchdog should assume lock up */ +#define MFC_WATCHDOG_CNT 10 +#define MFC_NO_INSTANCE_SET -1 +#define MFC_ENC_CAP_PLANE_COUNT 1 +#define MFC_ENC_OUT_PLANE_COUNT 2 +#define STUFF_BYTE 4 +#define MFC_MAX_CTRLS 128 + +#define S5P_MFC_CODEC_NONE -1 +#define S5P_MFC_CODEC_H264_DEC 0 +#define S5P_MFC_CODEC_H264_MVC_DEC 1 +#define S5P_MFC_CODEC_VC1_DEC 2 +#define S5P_MFC_CODEC_MPEG4_DEC 3 +#define S5P_MFC_CODEC_MPEG2_DEC 4 +#define S5P_MFC_CODEC_H263_DEC 5 +#define S5P_MFC_CODEC_VC1RCV_DEC 6 +#define S5P_MFC_CODEC_VP8_DEC 7 +#define S5P_MFC_CODEC_HEVC_DEC 17 +#define S5P_MFC_CODEC_VP9_DEC 18 + +#define S5P_MFC_CODEC_H264_ENC 20 +#define S5P_MFC_CODEC_H264_MVC_ENC 21 +#define S5P_MFC_CODEC_MPEG4_ENC 22 +#define S5P_MFC_CODEC_H263_ENC 23 +#define S5P_MFC_CODEC_VP8_ENC 24 +#define S5P_MFC_CODEC_HEVC_ENC 26 + +#define S5P_MFC_R2H_CMD_EMPTY 0 +#define S5P_MFC_R2H_CMD_SYS_INIT_RET 1 +#define S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET 2 +#define S5P_MFC_R2H_CMD_SEQ_DONE_RET 3 +#define S5P_MFC_R2H_CMD_INIT_BUFFERS_RET 4 +#define S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET 6 +#define S5P_MFC_R2H_CMD_SLEEP_RET 7 +#define S5P_MFC_R2H_CMD_WAKEUP_RET 8 +#define S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET 9 +#define S5P_MFC_R2H_CMD_DPB_FLUSH_RET 10 +#define S5P_MFC_R2H_CMD_NAL_ABORT_RET 11 +#define S5P_MFC_R2H_CMD_FW_STATUS_RET 12 +#define S5P_MFC_R2H_CMD_FRAME_DONE_RET 13 +#define S5P_MFC_R2H_CMD_FIELD_DONE_RET 14 +#define S5P_MFC_R2H_CMD_SLICE_DONE_RET 15 +#define S5P_MFC_R2H_CMD_ENC_BUFFER_FUL_RET 16 +#define S5P_MFC_R2H_CMD_ERR_RET 32 + +#define MFC_MAX_CLOCKS 4 + +#define mfc_read(dev, offset) readl(dev->regs_base + (offset)) +#define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ + (offset)) + +/* + * enum s5p_mfc_fmt_type - type of the pixelformat + */ +enum s5p_mfc_fmt_type { + MFC_FMT_DEC, + MFC_FMT_ENC, + MFC_FMT_RAW, +}; + +/* + * enum s5p_mfc_inst_type - The type of an MFC instance. + */ +enum s5p_mfc_inst_type { + MFCINST_INVALID, + MFCINST_DECODER, + MFCINST_ENCODER, +}; + +/* + * enum s5p_mfc_inst_state - The state of an MFC instance. + */ +enum s5p_mfc_inst_state { + MFCINST_FREE = 0, + MFCINST_INIT = 100, + MFCINST_GOT_INST, + MFCINST_HEAD_PARSED, + MFCINST_HEAD_PRODUCED, + MFCINST_BUFS_SET, + MFCINST_RUNNING, + MFCINST_FINISHING, + MFCINST_FINISHED, + MFCINST_RETURN_INST, + MFCINST_ERROR, + MFCINST_ABORT, + MFCINST_FLUSH, + MFCINST_RES_CHANGE_INIT, + MFCINST_RES_CHANGE_FLUSH, + MFCINST_RES_CHANGE_END, +}; + +/* + * enum s5p_mfc_queue_state - The state of buffer queue. + */ +enum s5p_mfc_queue_state { + QUEUE_FREE, + QUEUE_BUFS_REQUESTED, + QUEUE_BUFS_QUERIED, + QUEUE_BUFS_MMAPED, +}; + +/* + * enum s5p_mfc_decode_arg - type of frame decoding + */ +enum s5p_mfc_decode_arg { + MFC_DEC_FRAME, + MFC_DEC_LAST_FRAME, + MFC_DEC_RES_CHANGE, +}; + +enum s5p_mfc_fw_ver { + MFC_FW_V1, + MFC_FW_V2, +}; + +#define MFC_BUF_FLAG_USED (1 << 0) +#define MFC_BUF_FLAG_EOS (1 << 1) + +struct s5p_mfc_ctx; + +/* + * struct s5p_mfc_buf - MFC buffer + */ +struct s5p_mfc_buf { + struct vb2_v4l2_buffer *b; + struct list_head list; + union { + struct { + size_t luma; + size_t chroma; + } raw; + size_t stream; + } cookie; + int flags; +}; + +/* + * struct s5p_mfc_pm - power management data structure + */ +struct s5p_mfc_pm { + struct clk *clock_gate; + const char * const *clk_names; + struct clk *clocks[MFC_MAX_CLOCKS]; + int num_clocks; + bool use_clock_gating; + + struct device *device; +}; + +struct s5p_mfc_buf_size_v5 { + unsigned int h264_ctx; + unsigned int non_h264_ctx; + unsigned int dsc; + unsigned int shm; +}; + +struct s5p_mfc_buf_size_v6 { + unsigned int dev_ctx; + unsigned int h264_dec_ctx; + unsigned int other_dec_ctx; + unsigned int h264_enc_ctx; + unsigned int hevc_enc_ctx; + unsigned int other_enc_ctx; +}; + +struct s5p_mfc_buf_size { + unsigned int fw; + unsigned int cpb; + void *priv; +}; + +struct s5p_mfc_variant { + unsigned int version; + unsigned int port_num; + u32 version_bit; + struct s5p_mfc_buf_size *buf_size; + char *fw_name[MFC_FW_MAX_VERSIONS]; + const char *clk_names[MFC_MAX_CLOCKS]; + int num_clocks; + bool use_clock_gating; +}; + +/** + * struct s5p_mfc_priv_buf - represents internal used buffer + * @ofs: offset of each buffer, will be used for MFC + * @virt: kernel virtual address, only valid when the + * buffer accessed by driver + * @dma: DMA address, only valid when kernel DMA API used + * @size: size of the buffer + * @ctx: memory context (bank) used for this allocation + */ +struct s5p_mfc_priv_buf { + unsigned long ofs; + void *virt; + dma_addr_t dma; + size_t size; + unsigned int ctx; +}; + +/** + * struct s5p_mfc_dev - The struct containing driver internal parameters. + * + * @v4l2_dev: v4l2_device + * @vfd_dec: video device for decoding + * @vfd_enc: video device for encoding + * @plat_dev: platform device + * @mem_dev: child devices of the memory banks + * @regs_base: base address of the MFC hw registers + * @irq: irq resource + * @dec_ctrl_handler: control framework handler for decoding + * @enc_ctrl_handler: control framework handler for encoding + * @pm: power management control + * @variant: MFC hardware variant information + * @num_inst: counter of active MFC instances + * @irqlock: lock for operations on videobuf2 queues + * @condlock: lock for changing/checking if a context is ready to be + * processed + * @mfc_mutex: lock for video_device + * @int_cond: variable used by the waitqueue + * @int_type: type of last interrupt + * @int_err: error number for last interrupt + * @queue: waitqueue for waiting for completion of device commands + * @fw_buf: the firmware buffer data structure + * @mem_size: size of the firmware operation memory + * @mem_base: base DMA address of the firmware operation memory + * @mem_bitmap: bitmap for managing MFC internal buffer allocations + * @mem_virt: virtual address of the firmware operation memory + * @dma_base: address of the beginning of memory banks + * @hw_lock: used for hardware locking + * @ctx: array of driver contexts + * @curr_ctx: number of the currently running context + * @ctx_work_bits: used to mark which contexts are waiting for hardware + * @watchdog_cnt: counter for the watchdog + * @watchdog_timer: timer for the watchdog + * @watchdog_workqueue: workqueue for the watchdog + * @watchdog_work: worker for the watchdog + * @enter_suspend: flag set when entering suspend + * @ctx_buf: common context memory (MFCv6) + * @warn_start: hardware error code from which warnings start + * @mfc_ops: ops structure holding HW operation function pointers + * @mfc_cmds: cmd structure holding HW commands function pointers + * @mfc_regs: structure holding MFC registers + * @fw_ver: loaded firmware sub-version + * @fw_get_done: flag set when request_firmware() is complete and + * copied into fw_buf + * @risc_on: flag indicates RISC is on or off + * + */ +struct s5p_mfc_dev { + struct v4l2_device v4l2_dev; + struct video_device *vfd_dec; + struct video_device *vfd_enc; + struct platform_device *plat_dev; + struct device *mem_dev[BANK_CTX_NUM]; + void __iomem *regs_base; + int irq; + struct v4l2_ctrl_handler dec_ctrl_handler; + struct v4l2_ctrl_handler enc_ctrl_handler; + struct s5p_mfc_pm pm; + const struct s5p_mfc_variant *variant; + int num_inst; + spinlock_t irqlock; /* lock when operating on context */ + spinlock_t condlock; /* lock when changing/checking if a context is + ready to be processed */ + struct mutex mfc_mutex; /* video_device lock */ + int int_cond; + int int_type; + unsigned int int_err; + wait_queue_head_t queue; + struct s5p_mfc_priv_buf fw_buf; + size_t mem_size; + dma_addr_t mem_base; + unsigned long *mem_bitmap; + void *mem_virt; + dma_addr_t dma_base[BANK_CTX_NUM]; + unsigned long hw_lock; + struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS]; + int curr_ctx; + unsigned long ctx_work_bits; + atomic_t watchdog_cnt; + struct timer_list watchdog_timer; + struct workqueue_struct *watchdog_workqueue; + struct work_struct watchdog_work; + unsigned long enter_suspend; + + struct s5p_mfc_priv_buf ctx_buf; + int warn_start; + struct s5p_mfc_hw_ops *mfc_ops; + struct s5p_mfc_hw_cmds *mfc_cmds; + const struct s5p_mfc_regs *mfc_regs; + enum s5p_mfc_fw_ver fw_ver; + bool fw_get_done; + bool risc_on; /* indicates if RISC is on or off */ +}; + +/* + * struct s5p_mfc_h264_enc_params - encoding parameters for h264 + */ +struct s5p_mfc_h264_enc_params { + enum v4l2_mpeg_video_h264_profile profile; + enum v4l2_mpeg_video_h264_loop_filter_mode loop_filter_mode; + s8 loop_filter_alpha; + s8 loop_filter_beta; + enum v4l2_mpeg_video_h264_entropy_mode entropy_mode; + u8 max_ref_pic; + u8 num_ref_pic_4p; + int _8x8_transform; + int rc_mb_dark; + int rc_mb_smooth; + int rc_mb_static; + int rc_mb_activity; + int vui_sar; + u8 vui_sar_idc; + u16 vui_ext_sar_width; + u16 vui_ext_sar_height; + int open_gop; + u16 open_gop_size; + u8 rc_frame_qp; + u8 rc_min_qp; + u8 rc_max_qp; + u8 rc_p_frame_qp; + u8 rc_b_frame_qp; + enum v4l2_mpeg_video_h264_level level_v4l2; + int level; + u16 cpb_size; + int interlace; + u8 hier_qp; + u8 hier_qp_type; + u8 hier_qp_layer; + u8 hier_qp_layer_qp[7]; + u8 sei_frame_packing; + u8 sei_fp_curr_frame_0; + u8 sei_fp_arrangement_type; + + u8 fmo; + u8 fmo_map_type; + u8 fmo_slice_grp; + u8 fmo_chg_dir; + u32 fmo_chg_rate; + u32 fmo_run_len[4]; + u8 aso; + u32 aso_slice_order[8]; +}; + +/* + * struct s5p_mfc_mpeg4_enc_params - encoding parameters for h263 and mpeg4 + */ +struct s5p_mfc_mpeg4_enc_params { + /* MPEG4 Only */ + enum v4l2_mpeg_video_mpeg4_profile profile; + int quarter_pixel; + /* Common for MPEG4, H263 */ + u16 vop_time_res; + u16 vop_frm_delta; + u8 rc_frame_qp; + u8 rc_min_qp; + u8 rc_max_qp; + u8 rc_p_frame_qp; + u8 rc_b_frame_qp; + enum v4l2_mpeg_video_mpeg4_level level_v4l2; + int level; +}; + +/* + * struct s5p_mfc_vp8_enc_params - encoding parameters for vp8 + */ +struct s5p_mfc_vp8_enc_params { + u8 imd_4x4; + enum v4l2_vp8_num_partitions num_partitions; + enum v4l2_vp8_num_ref_frames num_ref; + u8 filter_level; + u8 filter_sharpness; + u32 golden_frame_ref_period; + enum v4l2_vp8_golden_frame_sel golden_frame_sel; + u8 hier_layer; + u8 hier_layer_qp[3]; + u8 rc_min_qp; + u8 rc_max_qp; + u8 rc_frame_qp; + u8 rc_p_frame_qp; + u8 profile; +}; + +struct s5p_mfc_hevc_enc_params { + enum v4l2_mpeg_video_hevc_profile profile; + int level; + enum v4l2_mpeg_video_h264_level level_v4l2; + u8 tier; + u32 rc_framerate; + u8 rc_min_qp; + u8 rc_max_qp; + u8 rc_lcu_dark; + u8 rc_lcu_smooth; + u8 rc_lcu_static; + u8 rc_lcu_activity; + u8 rc_frame_qp; + u8 rc_p_frame_qp; + u8 rc_b_frame_qp; + u8 max_partition_depth; + u8 num_refs_for_p; + u8 refreshtype; + u16 refreshperiod; + s32 lf_beta_offset_div2; + s32 lf_tc_offset_div2; + u8 loopfilter; + u8 loopfilter_disable; + u8 loopfilter_across; + u8 nal_control_length_filed; + u8 nal_control_user_ref; + u8 nal_control_store_ref; + u8 const_intra_period_enable; + u8 lossless_cu_enable; + u8 wavefront_enable; + u8 enable_ltr; + u8 hier_qp_enable; + enum v4l2_mpeg_video_hevc_hier_coding_type hier_qp_type; + u8 num_hier_layer; + u8 hier_qp_layer[7]; + u32 hier_bit_layer[7]; + u8 sign_data_hiding; + u8 general_pb_enable; + u8 temporal_id_enable; + u8 strong_intra_smooth; + u8 intra_pu_split_disable; + u8 tmv_prediction_disable; + u8 max_num_merge_mv; + u8 eco_mode_enable; + u8 encoding_nostartcode_enable; + u8 size_of_length_field; + u8 prepend_sps_pps_to_idr; +}; + +/* + * struct s5p_mfc_enc_params - general encoding parameters + */ +struct s5p_mfc_enc_params { + u16 width; + u16 height; + u32 mv_h_range; + u32 mv_v_range; + + u16 gop_size; + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + u16 slice_mb; + u32 slice_bit; + u16 intra_refresh_mb; + int pad; + u8 pad_luma; + u8 pad_cb; + u8 pad_cr; + int rc_frame; + int rc_mb; + u32 rc_bitrate; + u16 rc_reaction_coeff; + u16 vbv_size; + u32 vbv_delay; + + enum v4l2_mpeg_video_header_mode seq_hdr_mode; + enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode; + int fixed_target_bit; + + u8 num_b_frame; + u32 rc_framerate_num; + u32 rc_framerate_denom; + + struct { + struct s5p_mfc_h264_enc_params h264; + struct s5p_mfc_mpeg4_enc_params mpeg4; + struct s5p_mfc_vp8_enc_params vp8; + struct s5p_mfc_hevc_enc_params hevc; + } codec; + +}; + +/* + * struct s5p_mfc_codec_ops - codec ops, used by encoding + */ +struct s5p_mfc_codec_ops { + /* initialization routines */ + int (*pre_seq_start) (struct s5p_mfc_ctx *ctx); + int (*post_seq_start) (struct s5p_mfc_ctx *ctx); + /* execution routines */ + int (*pre_frame_start) (struct s5p_mfc_ctx *ctx); + int (*post_frame_start) (struct s5p_mfc_ctx *ctx); +}; + +#define call_cop(c, op, args...) \ + (((c)->c_ops->op) ? \ + ((c)->c_ops->op(args)) : 0) + +/** + * struct s5p_mfc_ctx - This struct contains the instance context + * + * @dev: pointer to the s5p_mfc_dev of the device + * @fh: struct v4l2_fh + * @num: number of the context that this structure describes + * @int_cond: variable used by the waitqueue + * @int_type: type of the last interrupt + * @int_err: error number received from MFC hw in the interrupt + * @queue: waitqueue that can be used to wait for this context to + * finish + * @src_fmt: source pixelformat information + * @dst_fmt: destination pixelformat information + * @vq_src: vb2 queue for source buffers + * @vq_dst: vb2 queue for destination buffers + * @src_queue: driver internal queue for source buffers + * @dst_queue: driver internal queue for destination buffers + * @src_queue_cnt: number of buffers queued on the source internal queue + * @dst_queue_cnt: number of buffers queued on the dest internal queue + * @type: type of the instance - decoder or encoder + * @state: state of the context + * @inst_no: number of hw instance associated with the context + * @img_width: width of the image that is decoded or encoded + * @img_height: height of the image that is decoded or encoded + * @buf_width: width of the buffer for processed image + * @buf_height: height of the buffer for processed image + * @luma_size: size of a luma plane + * @chroma_size: size of a chroma plane + * @mv_size: size of a motion vectors buffer + * @consumed_stream: number of bytes that have been used so far from the + * decoding buffer + * @dpb_flush_flag: flag used to indicate that a DPB buffers are being + * flushed + * @head_processed: flag mentioning whether the header data is processed + * completely or not + * @bank1: handle to memory allocated for temporary buffers from + * memory bank 1 + * @bank2: handle to memory allocated for temporary buffers from + * memory bank 2 + * @capture_state: state of the capture buffers queue + * @output_state: state of the output buffers queue + * @src_bufs: information on allocated source buffers + * @src_bufs_cnt: number of allocated source buffers + * @dst_bufs: information on allocated destination buffers + * @dst_bufs_cnt: number of allocated destination buffers + * @sequence: counter for the sequence number for v4l2 + * @dec_dst_flag: flags for buffers queued in the hardware + * @dec_src_buf_size: size of the buffer for source buffers in decoding + * @codec_mode: number of codec mode used by MFC hw + * @slice_interface: slice interface flag + * @loop_filter_mpeg4: loop filter for MPEG4 flag + * @display_delay: value of the display delay for H264 + * @display_delay_enable: display delay for H264 enable flag + * @after_packed_pb: flag used to track buffer when stream is in + * Packed PB format + * @sei_fp_parse: enable/disable parsing of frame packing SEI information + * @pb_count: count of the DPB buffers required by MFC hw + * @total_dpb_count: count of DPB buffers with additional buffers + * requested by the application + * @ctx: context buffer information + * @dsc: descriptor buffer information + * @shm: shared memory buffer information + * @mv_count: number of MV buffers allocated for decoding + * @enc_params: encoding parameters for MFC + * @enc_dst_buf_size: size of the buffers for encoder output + * @luma_dpb_size: dpb buffer size for luma + * @chroma_dpb_size: dpb buffer size for chroma + * @me_buffer_size: size of the motion estimation buffer + * @tmv_buffer_size: size of temporal predictor motion vector buffer + * @frame_type: used to force the type of the next encoded frame + * @ref_queue: list of the reference buffers for encoding + * @force_frame_type: encoder's frame type forcing control + * @ref_queue_cnt: number of the buffers in the reference list + * @slice_size: slice size + * @slice_mode: mode of dividing frames into slices + * @c_ops: ops for encoding + * @ctrls: array of controls, used when adding controls to the + * v4l2 control framework + * @ctrl_handler: handler for v4l2 framework + * @scratch_buf_size: scratch buffer size + */ +struct s5p_mfc_ctx { + struct s5p_mfc_dev *dev; + struct v4l2_fh fh; + + int num; + + int int_cond; + int int_type; + unsigned int int_err; + wait_queue_head_t queue; + + struct s5p_mfc_fmt *src_fmt; + struct s5p_mfc_fmt *dst_fmt; + + struct vb2_queue vq_src; + struct vb2_queue vq_dst; + + struct list_head src_queue; + struct list_head dst_queue; + + unsigned int src_queue_cnt; + unsigned int dst_queue_cnt; + + enum s5p_mfc_inst_type type; + enum s5p_mfc_inst_state state; + int inst_no; + + /* Image parameters */ + int img_width; + int img_height; + int buf_width; + int buf_height; + + int luma_size; + int chroma_size; + int mv_size; + + unsigned long consumed_stream; + + unsigned int dpb_flush_flag; + unsigned int head_processed; + + struct s5p_mfc_priv_buf bank1; + struct s5p_mfc_priv_buf bank2; + + enum s5p_mfc_queue_state capture_state; + enum s5p_mfc_queue_state output_state; + + struct s5p_mfc_buf src_bufs[MFC_MAX_BUFFERS]; + int src_bufs_cnt; + struct s5p_mfc_buf dst_bufs[MFC_MAX_BUFFERS]; + int dst_bufs_cnt; + + unsigned int sequence; + unsigned long dec_dst_flag; + size_t dec_src_buf_size; + + /* Control values */ + int codec_mode; + int slice_interface; + int loop_filter_mpeg4; + int display_delay; + int display_delay_enable; + int after_packed_pb; + int sei_fp_parse; + + int pb_count; + int total_dpb_count; + int mv_count; + /* Buffers */ + struct s5p_mfc_priv_buf ctx; + struct s5p_mfc_priv_buf dsc; + struct s5p_mfc_priv_buf shm; + + struct s5p_mfc_enc_params enc_params; + + size_t enc_dst_buf_size; + size_t luma_dpb_size; + size_t chroma_dpb_size; + size_t me_buffer_size; + size_t tmv_buffer_size; + + enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type; + + struct list_head ref_queue; + unsigned int ref_queue_cnt; + + enum v4l2_mpeg_video_multi_slice_mode slice_mode; + union { + unsigned int mb; + unsigned int bits; + } slice_size; + + const struct s5p_mfc_codec_ops *c_ops; + + struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; + struct v4l2_ctrl_handler ctrl_handler; + size_t scratch_buf_size; +}; + +/* + * struct s5p_mfc_fmt - structure used to store information about pixelformats + * used by the MFC + */ +struct s5p_mfc_fmt { + u32 fourcc; + u32 codec_mode; + enum s5p_mfc_fmt_type type; + u32 num_planes; + u32 versions; + u32 flags; +}; + +/* + * struct mfc_control - structure used to store information about MFC controls + * it is used to initialize the control framework. + */ +struct mfc_control { + __u32 id; + enum v4l2_ctrl_type type; + __u8 name[32]; /* Whatever */ + __s32 minimum; /* Note signedness */ + __s32 maximum; + __s32 step; + __u32 menu_skip_mask; + __s32 default_value; + __u32 flags; + __u32 reserved[2]; + __u8 is_volatile; +}; + +/* Macro for making hardware specific calls */ +#define s5p_mfc_hw_call(f, op, args...) \ + ((f && f->op) ? f->op(args) : (typeof(f->op(args)))(-ENODEV)) + +#define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) +#define ctrl_to_ctx(__ctrl) \ + container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler) + +void clear_work_bit(struct s5p_mfc_ctx *ctx); +void set_work_bit(struct s5p_mfc_ctx *ctx); +void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx); +void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx); +int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev); +void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); + +#define HAS_PORTNUM(dev) (dev ? (dev->variant ? \ + (dev->variant->port_num ? 1 : 0) : 0) : 0) +#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0) +#define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0) +#define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0) +#define IS_MFCV8_PLUS(dev) (dev->variant->version >= 0x80 ? 1 : 0) +#define IS_MFCV10(dev) (dev->variant->version >= 0xA0 ? 1 : 0) +#define FW_HAS_E_MIN_SCRATCH_BUF(dev) (IS_MFCV10(dev)) + +#define MFC_V5_BIT BIT(0) +#define MFC_V6_BIT BIT(1) +#define MFC_V7_BIT BIT(2) +#define MFC_V8_BIT BIT(3) +#define MFC_V10_BIT BIT(5) + +#define MFC_V5PLUS_BITS (MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT | \ + MFC_V8_BIT | MFC_V10_BIT) +#define MFC_V6PLUS_BITS (MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT | \ + MFC_V10_BIT) +#define MFC_V7PLUS_BITS (MFC_V7_BIT | MFC_V8_BIT | MFC_V10_BIT) + +#endif /* S5P_MFC_COMMON_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c new file mode 100644 index 000000000000..72d70984e99a --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#include +#include +#include +#include +#include +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_common.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_pm.h" +#include "s5p_mfc_ctrl.h" + +/* Allocate memory for firmware */ +int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_priv_buf *fw_buf = &dev->fw_buf; + int err; + + fw_buf->size = dev->variant->buf_size->fw; + + if (fw_buf->virt) { + mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); + return -ENOMEM; + } + + err = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &dev->fw_buf); + if (err) { + mfc_err("Allocating bitprocessor buffer failed\n"); + return err; + } + + return 0; +} + +/* Load firmware */ +int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) +{ + struct firmware *fw_blob; + int i, err = -EINVAL; + + /* Firmware has to be present as a separate file or compiled + * into kernel. */ + mfc_debug_enter(); + + if (dev->fw_get_done) + return 0; + + for (i = MFC_FW_MAX_VERSIONS - 1; i >= 0; i--) { + if (!dev->variant->fw_name[i]) + continue; + err = request_firmware((const struct firmware **)&fw_blob, + dev->variant->fw_name[i], &dev->plat_dev->dev); + if (!err) { + dev->fw_ver = (enum s5p_mfc_fw_ver) i; + break; + } + } + + if (err != 0) { + mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); + return -EINVAL; + } + if (fw_blob->size > dev->fw_buf.size) { + mfc_err("MFC firmware is too big to be loaded\n"); + release_firmware(fw_blob); + return -ENOMEM; + } + memcpy(dev->fw_buf.virt, fw_blob->data, fw_blob->size); + wmb(); + dev->fw_get_done = true; + release_firmware(fw_blob); + mfc_debug_leave(); + return 0; +} + +/* Release firmware memory */ +int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) +{ + /* Before calling this function one has to make sure + * that MFC is no longer processing */ + s5p_mfc_release_priv_buf(dev, &dev->fw_buf); + dev->fw_get_done = false; + return 0; +} + +static int s5p_mfc_bus_reset(struct s5p_mfc_dev *dev) +{ + unsigned int status; + unsigned long timeout; + + /* Reset */ + mfc_write(dev, 0x1, S5P_FIMV_MFC_BUS_RESET_CTRL); + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* Check bus status */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while resetting MFC.\n"); + return -EIO; + } + status = mfc_read(dev, S5P_FIMV_MFC_BUS_RESET_CTRL); + } while ((status & 0x2) == 0); + return 0; +} + +/* Reset the device */ +int s5p_mfc_reset(struct s5p_mfc_dev *dev) +{ + unsigned int mc_status; + unsigned long timeout; + int i; + + mfc_debug_enter(); + + if (IS_MFCV6_PLUS(dev)) { + /* Zero Initialization of MFC registers */ + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); + mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6); + + for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) + mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); + + /* check bus reset control before reset */ + if (dev->risc_on) + if (s5p_mfc_bus_reset(dev)) + return -EIO; + /* Reset + * set RISC_ON to 0 during power_on & wake_up. + * V6 needs RISC_ON set to 0 during reset also. + */ + if ((!dev->risc_on) || (!IS_MFCV7_PLUS(dev))) + mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); + + mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); + mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); + } else { + /* Stop procedure */ + /* reset RISC */ + mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); + /* All reset except for MC */ + mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); + mdelay(10); + + timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); + /* Check MC status */ + do { + if (time_after(jiffies, timeout)) { + mfc_err("Timeout while resetting MFC\n"); + return -EIO; + } + + mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); + + } while (mc_status & 0x3); + + mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); + mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); + } + + mfc_debug_leave(); + return 0; +} + +static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) +{ + if (IS_MFCV6_PLUS(dev)) { + mfc_write(dev, dev->dma_base[BANK_L_CTX], + S5P_FIMV_RISC_BASE_ADDRESS_V6); + mfc_debug(2, "Base Address : %pad\n", + &dev->dma_base[BANK_L_CTX]); + } else { + mfc_write(dev, dev->dma_base[BANK_L_CTX], + S5P_FIMV_MC_DRAMBASE_ADR_A); + mfc_write(dev, dev->dma_base[BANK_R_CTX], + S5P_FIMV_MC_DRAMBASE_ADR_B); + mfc_debug(2, "Bank1: %pad, Bank2: %pad\n", + &dev->dma_base[BANK_L_CTX], + &dev->dma_base[BANK_R_CTX]); + } +} + +static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) +{ + if (IS_MFCV6_PLUS(dev)) { + /* Zero initialization should be done before RESET. + * Nothing to do here. */ + } else { + mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); + mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); + mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); + } +} + +/* Initialize hardware */ +int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) +{ + unsigned int ver; + int ret; + + mfc_debug_enter(); + if (!dev->fw_buf.virt) { + mfc_err("Firmware memory is not allocated.\n"); + return -EINVAL; + } + + /* 0. MFC reset */ + mfc_debug(2, "MFC reset..\n"); + s5p_mfc_clock_on(); + dev->risc_on = 0; + ret = s5p_mfc_reset(dev); + if (ret) { + mfc_err("Failed to reset MFC - timeout\n"); + return ret; + } + mfc_debug(2, "Done MFC reset..\n"); + /* 1. Set DRAM base Addr */ + s5p_mfc_init_memctrl(dev); + /* 2. Initialize registers of channel I/F */ + s5p_mfc_clear_cmds(dev); + /* 3. Release reset signal to the RISC */ + s5p_mfc_clean_dev_int_flags(dev); + if (IS_MFCV6_PLUS(dev)) { + dev->risc_on = 1; + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + } + else + mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + + if (IS_MFCV10(dev)) + mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10); + + mfc_debug(2, "Will now wait for completion of firmware transfer\n"); + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { + mfc_err("Failed to load firmware\n"); + s5p_mfc_reset(dev); + s5p_mfc_clock_off(); + return -EIO; + } + s5p_mfc_clean_dev_int_flags(dev); + /* 4. Initialize firmware */ + ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev); + if (ret) { + mfc_err("Failed to send command to MFC - timeout\n"); + s5p_mfc_reset(dev); + s5p_mfc_clock_off(); + return ret; + } + mfc_debug(2, "Ok, now will wait for completion of hardware init\n"); + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { + mfc_err("Failed to init hardware\n"); + s5p_mfc_reset(dev); + s5p_mfc_clock_off(); + return -EIO; + } + dev->int_cond = 0; + if (dev->int_err != 0 || dev->int_type != + S5P_MFC_R2H_CMD_SYS_INIT_RET) { + /* Failure. */ + mfc_err("Failed to init firmware - error: %d int: %d\n", + dev->int_err, dev->int_type); + s5p_mfc_reset(dev); + s5p_mfc_clock_off(); + return -EIO; + } + if (IS_MFCV6_PLUS(dev)) + ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6); + else + ver = mfc_read(dev, S5P_FIMV_FW_VERSION); + + mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", + (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); + s5p_mfc_clock_off(); + mfc_debug_leave(); + return 0; +} + + +/* Deinitialize hardware */ +void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) +{ + s5p_mfc_clock_on(); + + s5p_mfc_reset(dev); + s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev); + + s5p_mfc_clock_off(); +} + +int s5p_mfc_sleep(struct s5p_mfc_dev *dev) +{ + int ret; + + mfc_debug_enter(); + s5p_mfc_clock_on(); + s5p_mfc_clean_dev_int_flags(dev); + ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev); + if (ret) { + mfc_err("Failed to send command to MFC - timeout\n"); + return ret; + } + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) { + mfc_err("Failed to sleep\n"); + return -EIO; + } + s5p_mfc_clock_off(); + dev->int_cond = 0; + if (dev->int_err != 0 || dev->int_type != + S5P_MFC_R2H_CMD_SLEEP_RET) { + /* Failure. */ + mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err, + dev->int_type); + return -EIO; + } + mfc_debug_leave(); + return ret; +} + +static int s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev *dev) +{ + int ret; + + /* Release reset signal to the RISC */ + dev->risc_on = 1; + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { + mfc_err("Failed to reset MFCV8\n"); + return -EIO; + } + mfc_debug(2, "Write command to wakeup MFCV8\n"); + ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); + if (ret) { + mfc_err("Failed to send command to MFCV8 - timeout\n"); + return ret; + } + + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { + mfc_err("Failed to wakeup MFC\n"); + return -EIO; + } + return ret; +} + +static int s5p_mfc_wait_wakeup(struct s5p_mfc_dev *dev) +{ + int ret; + + /* Send MFC wakeup command */ + ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev); + if (ret) { + mfc_err("Failed to send command to MFC - timeout\n"); + return ret; + } + + /* Release reset signal to the RISC */ + if (IS_MFCV6_PLUS(dev)) { + dev->risc_on = 1; + mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); + } else { + mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); + } + + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { + mfc_err("Failed to wakeup MFC\n"); + return -EIO; + } + return ret; +} + +int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) +{ + int ret; + + mfc_debug_enter(); + /* 0. MFC reset */ + mfc_debug(2, "MFC reset..\n"); + s5p_mfc_clock_on(); + dev->risc_on = 0; + ret = s5p_mfc_reset(dev); + if (ret) { + mfc_err("Failed to reset MFC - timeout\n"); + s5p_mfc_clock_off(); + return ret; + } + mfc_debug(2, "Done MFC reset..\n"); + /* 1. Set DRAM base Addr */ + s5p_mfc_init_memctrl(dev); + /* 2. Initialize registers of channel I/F */ + s5p_mfc_clear_cmds(dev); + s5p_mfc_clean_dev_int_flags(dev); + /* 3. Send MFC wakeup command and wait for completion*/ + if (IS_MFCV8_PLUS(dev)) + ret = s5p_mfc_v8_wait_wakeup(dev); + else + ret = s5p_mfc_wait_wakeup(dev); + + s5p_mfc_clock_off(); + if (ret) + return ret; + + dev->int_cond = 0; + if (dev->int_err != 0 || dev->int_type != + S5P_MFC_R2H_CMD_WAKEUP_RET) { + /* Failure. */ + mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err, + dev->int_type); + return -EIO; + } + mfc_debug_leave(); + return 0; +} + +int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) +{ + int ret = 0; + + ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx); + if (ret) { + mfc_err("Failed allocating instance buffer\n"); + goto err; + } + + if (ctx->type == MFCINST_DECODER) { + ret = s5p_mfc_hw_call(dev->mfc_ops, + alloc_dec_temp_buffers, ctx); + if (ret) { + mfc_err("Failed allocating temporary buffers\n"); + goto err_free_inst_buf; + } + } + + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + if (s5p_mfc_wait_for_done_ctx(ctx, + S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) { + /* Error or timeout */ + mfc_err("Error getting instance from hardware\n"); + ret = -EIO; + goto err_free_desc_buf; + } + + mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); + return ret; + +err_free_desc_buf: + if (ctx->type == MFCINST_DECODER) + s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); +err_free_inst_buf: + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); +err: + return ret; +} + +void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx) +{ + ctx->state = MFCINST_RETURN_INST; + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + /* Wait until instance is returned or timeout occurred */ + if (s5p_mfc_wait_for_done_ctx(ctx, + S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)) + mfc_err("Err returning instance\n"); + + /* Free resources */ + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); + if (ctx->type == MFCINST_DECODER) + s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); + + ctx->inst_no = MFC_NO_INSTANCE_SET; + ctx->state = MFCINST_FREE; +} diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.h new file mode 100644 index 000000000000..653ba5f3d048 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.h + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_CTRL_H +#define S5P_MFC_CTRL_H + +#include "s5p_mfc_common.h" + +int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev); +int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev); +int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev); + +int s5p_mfc_init_hw(struct s5p_mfc_dev *dev); +void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev); + +int s5p_mfc_sleep(struct s5p_mfc_dev *dev); +int s5p_mfc_wakeup(struct s5p_mfc_dev *dev); + +int s5p_mfc_reset(struct s5p_mfc_dev *dev); + +int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx); +void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx); + +#endif /* S5P_MFC_CTRL_H */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_debug.h new file mode 100644 index 000000000000..bba5dad6dbff --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_debug.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/platform/samsung/s5p-mfc/s5p_mfc_debug.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains debug macros + * + * Kamil Debski, Copyright (c) 2011 Samsung Electronics + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_DEBUG_H_ +#define S5P_MFC_DEBUG_H_ + +#define DEBUG + +#ifdef DEBUG +extern int mfc_debug_level; + +#define mfc_debug(level, fmt, args...) \ + do { \ + if (mfc_debug_level >= level) \ + printk(KERN_DEBUG "%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) +#else +#define mfc_debug(level, fmt, args...) +#endif + +#define mfc_debug_enter() mfc_debug(5, "enter\n") +#define mfc_debug_leave() mfc_debug(5, "leave\n") + +#define mfc_err(fmt, args...) \ + do { \ + printk(KERN_ERR "%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) + +#define mfc_err_limited(fmt, args...) \ + do { \ + printk_ratelimited(KERN_ERR "%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) + +#define mfc_info(fmt, args...) \ + do { \ + printk(KERN_INFO "%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) + +#endif /* S5P_MFC_DEBUG_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c new file mode 100644 index 000000000000..4b89df8bfd18 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -0,0 +1,1218 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * Kamil Debski, + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "s5p_mfc_common.h" +#include "s5p_mfc_ctrl.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_dec.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_pm.h" + +static struct s5p_mfc_fmt formats[] = { + { + .fourcc = V4L2_PIX_FMT_NV12MT_16X16, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + .versions = MFC_V6_BIT | MFC_V7_BIT, + }, + { + .fourcc = V4L2_PIX_FMT_NV12MT, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + .versions = MFC_V5_BIT, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + .versions = MFC_V6PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + .versions = MFC_V6PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_H264, + .codec_mode = S5P_MFC_CODEC_H264_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | + V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, + }, + { + .fourcc = V4L2_PIX_FMT_H264_MVC, + .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V6PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | + V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, + }, + { + .fourcc = V4L2_PIX_FMT_H263, + .codec_mode = S5P_MFC_CODEC_H263_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG1, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | + V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG2, + .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | + V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG4, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | + V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, + }, + { + .fourcc = V4L2_PIX_FMT_XVID, + .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, + .codec_mode = S5P_MFC_CODEC_VC1_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, + .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_VP8, + .codec_mode = S5P_MFC_CODEC_VP8_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V6PLUS_BITS, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .codec_mode = S5P_FIMV_CODEC_HEVC_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V10_BIT, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION | + V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM, + }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .codec_mode = S5P_FIMV_CODEC_VP9_DEC, + .type = MFC_FMT_DEC, + .num_planes = 1, + .versions = MFC_V10_BIT, + .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(formats) + +/* Find selected format description */ +static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) +{ + unsigned int i; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].fourcc == f->fmt.pix_mp.pixelformat && + formats[i].type == t) + return &formats[i]; + } + return NULL; +} + +static struct mfc_control controls[] = { + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "H264 Display Delay", + .minimum = 0, + .maximum = 16383, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 16383, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "H264 Display Delay Enable", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mpeg4 Loop Filter Enable", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Slice Interface Enable", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Minimum number of cap bufs", + .minimum = 1, + .maximum = 32, + .step = 1, + .default_value = 1, + .is_volatile = 1, + }, +}; + +#define NUM_CTRLS ARRAY_SIZE(controls) + +/* Check whether a context should be run on hardware */ +static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) +{ + /* Context is to parse header */ + if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST) + return 1; + /* Context is to decode a frame */ + if (ctx->src_queue_cnt >= 1 && + ctx->state == MFCINST_RUNNING && + ctx->dst_queue_cnt >= ctx->pb_count) + return 1; + /* Context is to return last frame */ + if (ctx->state == MFCINST_FINISHING && + ctx->dst_queue_cnt >= ctx->pb_count) + return 1; + /* Context is to set buffers */ + if (ctx->src_queue_cnt >= 1 && + ctx->state == MFCINST_HEAD_PARSED && + ctx->capture_state == QUEUE_BUFS_MMAPED) + return 1; + /* Resolution change */ + if ((ctx->state == MFCINST_RES_CHANGE_INIT || + ctx->state == MFCINST_RES_CHANGE_FLUSH) && + ctx->dst_queue_cnt >= ctx->pb_count) + return 1; + if (ctx->state == MFCINST_RES_CHANGE_END && + ctx->src_queue_cnt >= 1) + return 1; + mfc_debug(2, "ctx is not ready\n"); + return 0; +} + +static const struct s5p_mfc_codec_ops decoder_codec_ops = { + .pre_seq_start = NULL, + .post_seq_start = NULL, + .pre_frame_start = NULL, + .post_frame_start = NULL, +}; + +/* Query capabilities of the device */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + + strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver)); + strscpy(cap->card, dev->vfd_dec->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(&dev->plat_dev->dev)); + return 0; +} + +/* Enumerate format */ +static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, + bool out) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + int i, j = 0; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (out && formats[i].type != MFC_FMT_DEC) + continue; + else if (!out && formats[i].type != MFC_FMT_RAW) + continue; + else if ((dev->variant->version_bit & formats[i].versions) == 0) + continue; + + if (j == f->index) + break; + ++j; + } + if (i == ARRAY_SIZE(formats)) + return -EINVAL; + f->pixelformat = formats[i].fourcc; + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(file, f, false); +} + +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(file, f, true); +} + +/* Get format */ +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *pix_mp; + + mfc_debug_enter(); + pix_mp = &f->fmt.pix_mp; + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + (ctx->state == MFCINST_GOT_INST || ctx->state == + MFCINST_RES_CHANGE_END)) { + /* If the MFC is parsing the header, + * so wait until it is finished */ + s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET, + 0); + } + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + ctx->state >= MFCINST_HEAD_PARSED && + ctx->state < MFCINST_ABORT) { + /* This is run on CAPTURE (decode output) */ + /* Width and height are set to the dimensions + of the movie, the buffer is bigger and + further processing stages should crop to this + rectangle. */ + pix_mp->width = ctx->buf_width; + pix_mp->height = ctx->buf_height; + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->num_planes = 2; + /* Set pixelformat to the format in which MFC + outputs the decoded frame */ + pix_mp->pixelformat = ctx->dst_fmt->fourcc; + pix_mp->plane_fmt[0].bytesperline = ctx->buf_width; + pix_mp->plane_fmt[0].sizeimage = ctx->luma_size; + pix_mp->plane_fmt[1].bytesperline = ctx->buf_width; + pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* This is run on OUTPUT + The buffer contains compressed image + so width and height have no meaning */ + pix_mp->width = 0; + pix_mp->height = 0; + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size; + pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size; + pix_mp->pixelformat = ctx->src_fmt->fourcc; + pix_mp->num_planes = ctx->src_fmt->num_planes; + } else { + mfc_err("Format could not be read\n"); + mfc_debug(2, "%s-- with error\n", __func__); + return -EINVAL; + } + mfc_debug_leave(); + return 0; +} + +/* Try format */ +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + struct s5p_mfc_fmt *fmt; + + mfc_debug(2, "Type is %d\n", f->type); + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fmt = find_format(f, MFC_FMT_DEC); + if (!fmt) { + mfc_err("Unsupported format for source.\n"); + return -EINVAL; + } + if (fmt->codec_mode == S5P_FIMV_CODEC_NONE) { + mfc_err("Unknown codec\n"); + return -EINVAL; + } + if ((dev->variant->version_bit & fmt->versions) == 0) { + mfc_err("Unsupported format by this MFC version.\n"); + return -EINVAL; + } + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = find_format(f, MFC_FMT_RAW); + if (!fmt) { + mfc_err("Unsupported format for destination.\n"); + return -EINVAL; + } + if ((dev->variant->version_bit & fmt->versions) == 0) { + mfc_err("Unsupported format by this MFC version.\n"); + return -EINVAL; + } + } + + return 0; +} + +/* Set format */ +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + int ret = 0; + struct v4l2_pix_format_mplane *pix_mp; + struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; + + mfc_debug_enter(); + ret = vidioc_try_fmt(file, priv, f); + pix_mp = &f->fmt.pix_mp; + if (ret) + return ret; + if (vb2_is_streaming(&ctx->vq_src) || vb2_is_streaming(&ctx->vq_dst)) { + v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); + ret = -EBUSY; + goto out; + } + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + /* dst_fmt is validated by call to vidioc_try_fmt */ + ctx->dst_fmt = find_format(f, MFC_FMT_RAW); + ret = 0; + goto out; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* src_fmt is validated by call to vidioc_try_fmt */ + ctx->src_fmt = find_format(f, MFC_FMT_DEC); + ctx->codec_mode = ctx->src_fmt->codec_mode; + mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); + pix_mp->height = 0; + pix_mp->width = 0; + if (pix_mp->plane_fmt[0].sizeimage == 0) + pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = + DEF_CPB_SIZE; + else if (pix_mp->plane_fmt[0].sizeimage > buf_size->cpb) + ctx->dec_src_buf_size = buf_size->cpb; + else + ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; + pix_mp->plane_fmt[0].bytesperline = 0; + ctx->state = MFCINST_INIT; + ret = 0; + goto out; + } else { + mfc_err("Wrong type error for S_FMT : %d", f->type); + ret = -EINVAL; + goto out; + } + +out: + mfc_debug_leave(); + return ret; +} + +static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, + struct v4l2_requestbuffers *reqbufs) +{ + int ret = 0; + + s5p_mfc_clock_on(); + + if (reqbufs->count == 0) { + mfc_debug(2, "Freeing buffers\n"); + ret = vb2_reqbufs(&ctx->vq_src, reqbufs); + if (ret) + goto out; + ctx->src_bufs_cnt = 0; + ctx->output_state = QUEUE_FREE; + } else if (ctx->output_state == QUEUE_FREE) { + /* Can only request buffers when we have a valid format set. */ + WARN_ON(ctx->src_bufs_cnt != 0); + if (ctx->state != MFCINST_INIT) { + mfc_err("Reqbufs called in an invalid state\n"); + ret = -EINVAL; + goto out; + } + + mfc_debug(2, "Allocating %d buffers for OUTPUT queue\n", + reqbufs->count); + ret = vb2_reqbufs(&ctx->vq_src, reqbufs); + if (ret) + goto out; + + ret = s5p_mfc_open_mfc_inst(dev, ctx); + if (ret) { + reqbufs->count = 0; + vb2_reqbufs(&ctx->vq_src, reqbufs); + goto out; + } + + ctx->output_state = QUEUE_BUFS_REQUESTED; + } else { + mfc_err("Buffers have already been requested\n"); + ret = -EINVAL; + } +out: + s5p_mfc_clock_off(); + if (ret) + mfc_err("Failed allocating buffers for OUTPUT queue\n"); + return ret; +} + +static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, + struct v4l2_requestbuffers *reqbufs) +{ + int ret = 0; + + s5p_mfc_clock_on(); + + if (reqbufs->count == 0) { + mfc_debug(2, "Freeing buffers\n"); + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + if (ret) + goto out; + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); + ctx->dst_bufs_cnt = 0; + } else if (ctx->capture_state == QUEUE_FREE) { + WARN_ON(ctx->dst_bufs_cnt != 0); + mfc_debug(2, "Allocating %d buffers for CAPTURE queue\n", + reqbufs->count); + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + if (ret) + goto out; + + ctx->capture_state = QUEUE_BUFS_REQUESTED; + ctx->total_dpb_count = reqbufs->count; + + ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx); + if (ret) { + mfc_err("Failed to allocate decoding buffers\n"); + reqbufs->count = 0; + vb2_reqbufs(&ctx->vq_dst, reqbufs); + ret = -ENOMEM; + ctx->capture_state = QUEUE_FREE; + goto out; + } + + WARN_ON(ctx->dst_bufs_cnt != ctx->total_dpb_count); + ctx->capture_state = QUEUE_BUFS_MMAPED; + + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, + 0); + } else { + mfc_err("Buffers have already been requested\n"); + ret = -EINVAL; + } +out: + s5p_mfc_clock_off(); + if (ret) + mfc_err("Failed allocating buffers for CAPTURE queue\n"); + return ret; +} + +/* Request buffers */ +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (reqbufs->memory != V4L2_MEMORY_MMAP) { + mfc_debug(2, "Only V4L2_MEMORY_MMAP is supported\n"); + return -EINVAL; + } + + if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + return reqbufs_output(dev, ctx, reqbufs); + } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + return reqbufs_capture(dev, ctx, reqbufs); + } else { + mfc_err("Invalid type requested\n"); + return -EINVAL; + } +} + +/* Query buffer */ +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + int ret; + int i; + + if (buf->memory != V4L2_MEMORY_MMAP) { + mfc_err("Only mmapped buffers can be used\n"); + return -EINVAL; + } + mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type); + if (ctx->state == MFCINST_GOT_INST && + buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = vb2_querybuf(&ctx->vq_src, buf); + } else if (ctx->state == MFCINST_RUNNING && + buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = vb2_querybuf(&ctx->vq_dst, buf); + for (i = 0; i < buf->length; i++) + buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE; + } else { + mfc_err("vidioc_querybuf called in an inappropriate state\n"); + ret = -EINVAL; + } + mfc_debug_leave(); + return ret; +} + +/* Queue a buffer */ +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (ctx->state == MFCINST_ERROR) { + mfc_err("Call on QBUF after unrecoverable error\n"); + return -EIO; + } + if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return vb2_qbuf(&ctx->vq_src, NULL, buf); + else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return vb2_qbuf(&ctx->vq_dst, NULL, buf); + return -EINVAL; +} + +/* Dequeue a buffer */ +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + const struct v4l2_event ev = { + .type = V4L2_EVENT_EOS + }; + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + int ret; + + if (ctx->state == MFCINST_ERROR) { + mfc_err_limited("Call on DQBUF after unrecoverable error\n"); + return -EIO; + } + + switch (buf->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); + if (ret) + return ret; + + if (ctx->state == MFCINST_FINISHED && + (ctx->dst_bufs[buf->index].flags & MFC_BUF_FLAG_EOS)) + v4l2_event_queue_fh(&ctx->fh, &ev); + return 0; + default: + return -EINVAL; + } +} + +/* Export DMA buffer */ +static int vidioc_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return vb2_expbuf(&ctx->vq_src, eb); + if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return vb2_expbuf(&ctx->vq_dst, eb); + return -EINVAL; +} + +/* Stream on */ +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + int ret = -EINVAL; + + mfc_debug_enter(); + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + ret = vb2_streamon(&ctx->vq_src, type); + else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + ret = vb2_streamon(&ctx->vq_dst, type); + mfc_debug_leave(); + return ret; +} + +/* Stream off, which equals to a pause */ +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return vb2_streamoff(&ctx->vq_src, type); + else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return vb2_streamoff(&ctx->vq_dst, type); + return -EINVAL; +} + +/* Set controls - v4l2 control framework */ +static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); + + switch (ctrl->id) { + case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY: + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: + ctx->display_delay = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE: + case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: + ctx->display_delay_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: + ctx->loop_filter_mpeg4 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: + ctx->slice_interface = ctrl->val; + break; + default: + mfc_err("Invalid control 0x%08x\n", ctrl->id); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) +{ + struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); + struct s5p_mfc_dev *dev = ctx->dev; + + switch (ctrl->id) { + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + if (ctx->state >= MFCINST_HEAD_PARSED && + ctx->state < MFCINST_ABORT) { + ctrl->val = ctx->pb_count; + break; + } else if (ctx->state != MFCINST_INIT && + ctx->state != MFCINST_RES_CHANGE_END) { + v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); + return -EINVAL; + } + /* Should wait for the header to be parsed */ + s5p_mfc_wait_for_done_ctx(ctx, + S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); + if (ctx->state >= MFCINST_HEAD_PARSED && + ctx->state < MFCINST_ABORT) { + ctrl->val = ctx->pb_count; + } else { + v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); + return -EINVAL; + } + break; + } + return 0; +} + + +static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = { + .s_ctrl = s5p_mfc_dec_s_ctrl, + .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl, +}; + +/* Get compose information */ +static int vidioc_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_dev *dev = ctx->dev; + u32 left, right, top, bottom; + u32 width, height; + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (ctx->state != MFCINST_HEAD_PARSED && + ctx->state != MFCINST_RUNNING && + ctx->state != MFCINST_FINISHING && + ctx->state != MFCINST_FINISHED) { + mfc_err("Can not get compose information\n"); + return -EINVAL; + } + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { + left = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_h, ctx); + right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; + left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; + top = s5p_mfc_hw_call(dev->mfc_ops, get_crop_info_v, ctx); + bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; + top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; + width = ctx->img_width - left - right; + height = ctx->img_height - top - bottom; + mfc_debug(2, "Composing info [h264]: l=%d t=%d w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", + left, top, s->r.width, s->r.height, right, bottom, + ctx->buf_width, ctx->buf_height); + } else { + left = 0; + top = 0; + width = ctx->img_width; + height = ctx->img_height; + mfc_debug(2, "Composing info: w=%d h=%d fw=%d fh=%d\n", + s->r.width, s->r.height, ctx->buf_width, + ctx->buf_height); + } + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + s->r.left = left; + s->r.top = top; + s->r.width = width; + s->r.height = height; + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_decoder_cmd(struct file *file, void *priv, + struct v4l2_decoder_cmd *cmd) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *buf; + unsigned long flags; + + switch (cmd->cmd) { + case V4L2_DEC_CMD_STOP: + if (cmd->flags != 0) + return -EINVAL; + + if (!vb2_is_streaming(&ctx->vq_src)) + return -EINVAL; + + spin_lock_irqsave(&dev->irqlock, flags); + if (list_empty(&ctx->src_queue)) { + mfc_err("EOS: empty src queue, entering finishing state"); + ctx->state = MFCINST_FINISHING; + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + spin_unlock_irqrestore(&dev->irqlock, flags); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + } else { + mfc_err("EOS: marking last buffer of stream"); + buf = list_entry(ctx->src_queue.prev, + struct s5p_mfc_buf, list); + if (buf->flags & MFC_BUF_FLAG_USED) + ctx->state = MFCINST_FINISHING; + else + buf->flags |= MFC_BUF_FLAG_EOS; + spin_unlock_irqrestore(&dev->irqlock, flags); + } + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + default: + return -EINVAL; + } +} + + +/* v4l2_ioctl_ops */ +static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_expbuf = vidioc_expbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_selection = vidioc_g_selection, + .vidioc_decoder_cmd = vidioc_decoder_cmd, + .vidioc_subscribe_event = vidioc_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int s5p_mfc_queue_setup(struct vb2_queue *vq, + unsigned int *buf_count, + unsigned int *plane_count, unsigned int psize[], + struct device *alloc_devs[]) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; + + /* Video output for decoding (source) + * this can be set after getting an instance */ + if (ctx->state == MFCINST_INIT && + vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* A single plane is required for input */ + *plane_count = 1; + if (*buf_count < 1) + *buf_count = 1; + if (*buf_count > MFC_MAX_BUFFERS) + *buf_count = MFC_MAX_BUFFERS; + /* Video capture for decoding (destination) + * this can be set after the header was parsed */ + } else if (ctx->state == MFCINST_HEAD_PARSED && + vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + /* Output plane count is 2 - one for Y and one for CbCr */ + *plane_count = 2; + /* Setup buffer count */ + if (*buf_count < ctx->pb_count) + *buf_count = ctx->pb_count; + if (*buf_count > ctx->pb_count + MFC_MAX_EXTRA_DPB) + *buf_count = ctx->pb_count + MFC_MAX_EXTRA_DPB; + if (*buf_count > MFC_MAX_BUFFERS) + *buf_count = MFC_MAX_BUFFERS; + } else { + mfc_err("State seems invalid. State = %d, vq->type = %d\n", + ctx->state, vq->type); + return -EINVAL; + } + mfc_debug(2, "Buffer count=%d, plane count=%d\n", + *buf_count, *plane_count); + if (ctx->state == MFCINST_HEAD_PARSED && + vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + psize[0] = ctx->luma_size; + psize[1] = ctx->chroma_size; + + if (IS_MFCV6_PLUS(dev)) + alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; + else + alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX]; + alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX]; + } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && + ctx->state == MFCINST_INIT) { + psize[0] = ctx->dec_src_buf_size; + alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; + } else { + mfc_err("This video node is dedicated to decoding. Decoding not initialized\n"); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vb2_queue *vq = vb->vb2_queue; + struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + unsigned int i; + + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (ctx->capture_state == QUEUE_BUFS_MMAPED) + return 0; + for (i = 0; i < ctx->dst_fmt->num_planes; i++) { + if (IS_ERR_OR_NULL(ERR_PTR( + vb2_dma_contig_plane_dma_addr(vb, i)))) { + mfc_err("Plane mem not allocated\n"); + return -EINVAL; + } + } + if (vb2_plane_size(vb, 0) < ctx->luma_size || + vb2_plane_size(vb, 1) < ctx->chroma_size) { + mfc_err("Plane buffer (CAPTURE) is too small\n"); + return -EINVAL; + } + i = vb->index; + ctx->dst_bufs[i].b = vbuf; + ctx->dst_bufs[i].cookie.raw.luma = + vb2_dma_contig_plane_dma_addr(vb, 0); + ctx->dst_bufs[i].cookie.raw.chroma = + vb2_dma_contig_plane_dma_addr(vb, 1); + ctx->dst_bufs_cnt++; + } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (IS_ERR_OR_NULL(ERR_PTR( + vb2_dma_contig_plane_dma_addr(vb, 0)))) { + mfc_err("Plane memory not allocated\n"); + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) { + mfc_err("Plane buffer (OUTPUT) is too small\n"); + return -EINVAL; + } + + i = vb->index; + ctx->src_bufs[i].b = vbuf; + ctx->src_bufs[i].cookie.stream = + vb2_dma_contig_plane_dma_addr(vb, 0); + ctx->src_bufs_cnt++; + } else { + mfc_err("s5p_mfc_buf_init: unknown queue type\n"); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; + + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + if (ctx->state == MFCINST_FINISHING || + ctx->state == MFCINST_FINISHED) + ctx->state = MFCINST_RUNNING; + /* If context is ready then dev = work->data;schedule it to run */ + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + return 0; +} + +static void s5p_mfc_stop_streaming(struct vb2_queue *q) +{ + unsigned long flags; + struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; + int aborted = 0; + + spin_lock_irqsave(&dev->irqlock, flags); + if ((ctx->state == MFCINST_FINISHING || + ctx->state == MFCINST_RUNNING) && + dev->curr_ctx == ctx->num && dev->hw_lock) { + ctx->state = MFCINST_ABORT; + spin_unlock_irqrestore(&dev->irqlock, flags); + s5p_mfc_wait_for_done_ctx(ctx, + S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0); + aborted = 1; + spin_lock_irqsave(&dev->irqlock, flags); + } + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + INIT_LIST_HEAD(&ctx->dst_queue); + ctx->dst_queue_cnt = 0; + ctx->dpb_flush_flag = 1; + ctx->dec_dst_flag = 0; + if (IS_MFCV6_PLUS(dev) && (ctx->state == MFCINST_RUNNING)) { + ctx->state = MFCINST_FLUSH; + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + spin_unlock_irqrestore(&dev->irqlock, flags); + if (s5p_mfc_wait_for_done_ctx(ctx, + S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0)) + mfc_err("Err flushing buffers\n"); + spin_lock_irqsave(&dev->irqlock, flags); + } + } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + INIT_LIST_HEAD(&ctx->src_queue); + ctx->src_queue_cnt = 0; + } + if (aborted) + ctx->state = MFCINST_RUNNING; + spin_unlock_irqrestore(&dev->irqlock, flags); +} + + +static void s5p_mfc_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *mfc_buf; + + if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_buf = &ctx->src_bufs[vb->index]; + mfc_buf->flags &= ~MFC_BUF_FLAG_USED; + spin_lock_irqsave(&dev->irqlock, flags); + list_add_tail(&mfc_buf->list, &ctx->src_queue); + ctx->src_queue_cnt++; + spin_unlock_irqrestore(&dev->irqlock, flags); + } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + mfc_buf = &ctx->dst_bufs[vb->index]; + mfc_buf->flags &= ~MFC_BUF_FLAG_USED; + /* Mark destination as available for use by MFC */ + spin_lock_irqsave(&dev->irqlock, flags); + set_bit(vb->index, &ctx->dec_dst_flag); + list_add_tail(&mfc_buf->list, &ctx->dst_queue); + ctx->dst_queue_cnt++; + spin_unlock_irqrestore(&dev->irqlock, flags); + } else { + mfc_err("Unsupported buffer type (%d)\n", vq->type); + } + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); +} + +static struct vb2_ops s5p_mfc_dec_qops = { + .queue_setup = s5p_mfc_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_init = s5p_mfc_buf_init, + .start_streaming = s5p_mfc_start_streaming, + .stop_streaming = s5p_mfc_stop_streaming, + .buf_queue = s5p_mfc_buf_queue, +}; + +const struct s5p_mfc_codec_ops *get_dec_codec_ops(void) +{ + return &decoder_codec_ops; +} + +struct vb2_ops *get_dec_queue_ops(void) +{ + return &s5p_mfc_dec_qops; +} + +const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void) +{ + return &s5p_mfc_dec_ioctl_ops; +} + +#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_CODEC) \ + && V4L2_CTRL_DRIVER_PRIV(x)) + +int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_ctrl_config cfg; + int i; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS); + if (ctx->ctrl_handler.error) { + mfc_err("v4l2_ctrl_handler_init failed\n"); + return ctx->ctrl_handler.error; + } + + for (i = 0; i < NUM_CTRLS; i++) { + if (IS_MFC51_PRIV(controls[i].id)) { + memset(&cfg, 0, sizeof(struct v4l2_ctrl_config)); + cfg.ops = &s5p_mfc_dec_ctrl_ops; + cfg.id = controls[i].id; + cfg.min = controls[i].minimum; + cfg.max = controls[i].maximum; + cfg.def = controls[i].default_value; + cfg.name = controls[i].name; + cfg.type = controls[i].type; + + cfg.step = controls[i].step; + cfg.menu_skip_mask = 0; + + ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler, + &cfg, NULL); + } else { + ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &s5p_mfc_dec_ctrl_ops, + controls[i].id, controls[i].minimum, + controls[i].maximum, controls[i].step, + controls[i].default_value); + } + if (ctx->ctrl_handler.error) { + mfc_err("Adding control (%d) failed\n", i); + return ctx->ctrl_handler.error; + } + if (controls[i].is_volatile && ctx->ctrls[i]) + ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; + } + return 0; +} + +void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx) +{ + int i; + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + for (i = 0; i < NUM_CTRLS; i++) + ctx->ctrls[i] = NULL; +} + +void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_format f; + f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; + ctx->src_fmt = find_format(&f, MFC_FMT_DEC); + if (IS_MFCV8_PLUS(ctx->dev)) + f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; + else if (IS_MFCV6_PLUS(ctx->dev)) + f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16; + else + f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT; + ctx->dst_fmt = find_format(&f, MFC_FMT_RAW); + mfc_debug(2, "Default src_fmt is %p, dest_fmt is %p\n", + ctx->src_fmt, ctx->dst_fmt); +} + diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.h new file mode 100644 index 000000000000..0c52ab46cff7 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_DEC_H_ +#define S5P_MFC_DEC_H_ + +const struct s5p_mfc_codec_ops *get_dec_codec_ops(void); +struct vb2_ops *get_dec_queue_ops(void); +const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); +struct s5p_mfc_fmt *get_dec_def_fmt(bool src); +int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx); +void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx); +void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx); + +#endif /* S5P_MFC_DEC_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c new file mode 100644 index 000000000000..a8877d805b29 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -0,0 +1,2697 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Jeongtae Park + * Kamil Debski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "s5p_mfc_common.h" +#include "s5p_mfc_ctrl.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_enc.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_opr.h" + +#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12M +#define DEF_DST_FMT_ENC V4L2_PIX_FMT_H264 + +static struct s5p_mfc_fmt formats[] = { + { + .fourcc = V4L2_PIX_FMT_NV12MT_16X16, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + .versions = MFC_V6_BIT | MFC_V7_BIT, + }, + { + .fourcc = V4L2_PIX_FMT_NV12MT, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + .versions = MFC_V5_BIT, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + .versions = MFC_V5PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .codec_mode = S5P_MFC_CODEC_NONE, + .type = MFC_FMT_RAW, + .num_planes = 2, + .versions = MFC_V6PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_H264, + .codec_mode = S5P_MFC_CODEC_H264_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_MPEG4, + .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_H263, + .codec_mode = S5P_MFC_CODEC_H263_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + .versions = MFC_V5PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_VP8, + .codec_mode = S5P_MFC_CODEC_VP8_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + .versions = MFC_V7PLUS_BITS, + }, + { + .fourcc = V4L2_PIX_FMT_HEVC, + .codec_mode = S5P_FIMV_CODEC_HEVC_ENC, + .type = MFC_FMT_ENC, + .num_planes = 1, + .versions = MFC_V10_BIT, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(formats) +static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) +{ + unsigned int i; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].fourcc == f->fmt.pix_mp.pixelformat && + formats[i].type == t) + return &formats[i]; + } + return NULL; +} + +static struct mfc_control controls[] = { + { + .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 12, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1900, + .maximum = (1 << 30) - 1, + .step = 1, + .default_value = 1900, + }, + { + .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Padding Control Enable", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Padding Color YUV Value", + .minimum = 0, + .maximum = (1 << 25) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_BITRATE, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = (1 << 30) - 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Rate Control Reaction Coeff.", + .minimum = 1, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Force frame type", + .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED, + .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED, + .default_value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 0, + .step = 0, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Horizontal MV Search Range", + .minimum = 16, + .maximum = 128, + .step = 16, + .default_value = 32, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Vertical MV Search Range", + .minimum = 16, + .maximum = 128, + .step = 16, + .default_value = 32, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Frame Skip Enable", + .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED, + .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .menu_skip_mask = 0, + .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED, + }, + { + .id = V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .maximum = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + .default_value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Fixed Target Bit Enable", + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 2, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, + .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) + ), + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0, + .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, + .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, + .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, + .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "The Number of Ref. Pic for P", + .minimum = 1, + .maximum = 2, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 51, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "H263 I-Frame QP value", + .minimum = 1, + .maximum = 31, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "H263 Minimum QP value", + .minimum = 1, + .maximum = 31, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "H263 Maximum QP value", + .minimum = 1, + .maximum = 31, + .step = 1, + .default_value = 31, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "H263 P frame QP value", + .minimum = 1, + .maximum = 31, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "H263 B frame QP value", + .minimum = 1, + .maximum = 31, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "MPEG4 I-Frame QP value", + .minimum = 1, + .maximum = 31, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "MPEG4 Minimum QP value", + .minimum = 1, + .maximum = 31, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "MPEG4 Maximum QP value", + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 51, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "MPEG4 P frame QP value", + .minimum = 1, + .maximum = 31, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "MPEG4 B frame QP value", + .minimum = 1, + .maximum = 31, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "H264 Dark Reg Adaptive RC", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "H264 Smooth Reg Adaptive RC", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "H264 Static Reg Adaptive RC", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "H264 Activity Reg Adaptive RC", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED, + .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED, + .default_value = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, + .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE, + .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS, + .type = V4L2_CTRL_TYPE_INTEGER_MENU, + .maximum = V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS, + .default_value = V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES, + .type = V4L2_CTRL_TYPE_INTEGER_MENU, + .maximum = V4L2_CID_MPEG_VIDEO_VPX_2_REF_FRAME, + .default_value = V4L2_CID_MPEG_VIDEO_VPX_1_REF_FRAME, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 63, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 7, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV, + .maximum = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD, + .default_value = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_MAX_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 127, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 11, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 10, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .step = 1, + .default_value = 10, + }, + { + .id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .maximum = V4L2_MPEG_VIDEO_VP8_PROFILE_3, + .default_value = V4L2_MPEG_VIDEO_VP8_PROFILE_0, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HEVC I Frame QP Value", + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "HEVC P Frame QP Value", + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + .maximum = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TIER, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + .maximum = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 2, + .step = 1, + .default_value = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, + .maximum = V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + .maximum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + .maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 51, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = INT_MIN, + .maximum = INT_MAX, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + .maximum = V4L2_MPEG_VIDEO_HEVC_SIZE_4, + .step = 1, + .default_value = V4L2_MPEG_VIDEO_HEVC_SIZE_0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Minimum number of output bufs", + .minimum = 1, + .maximum = 32, + .step = 1, + .default_value = 1, + .is_volatile = 1, + }, +}; + +#define NUM_CTRLS ARRAY_SIZE(controls) +static const char * const *mfc51_get_menu(u32 id) +{ + static const char * const mfc51_video_frame_skip[] = { + "Disabled", + "Level Limit", + "VBV/CPB Limit", + NULL, + }; + static const char * const mfc51_video_force_frame[] = { + "Disabled", + "I Frame", + "Not Coded", + NULL, + }; + switch (id) { + case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: + return mfc51_video_frame_skip; + case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE: + return mfc51_video_force_frame; + } + return NULL; +} + +static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) +{ + mfc_debug(2, "src=%d, dst=%d, state=%d\n", + ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state); + /* context is ready to make header */ + if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1) + return 1; + /* context is ready to encode a frame */ + if ((ctx->state == MFCINST_RUNNING || + ctx->state == MFCINST_HEAD_PRODUCED) && + ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) + return 1; + /* context is ready to encode remaining frames */ + if (ctx->state == MFCINST_FINISHING && + ctx->dst_queue_cnt >= 1) + return 1; + mfc_debug(2, "ctx is not ready\n"); + return 0; +} + +static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_buf *mb_entry; + + /* move buffers in ref queue to src queue */ + while (!list_empty(&ctx->ref_queue)) { + mb_entry = list_entry((&ctx->ref_queue)->next, + struct s5p_mfc_buf, list); + list_del(&mb_entry->list); + ctx->ref_queue_cnt--; + list_add_tail(&mb_entry->list, &ctx->src_queue); + ctx->src_queue_cnt++; + } + mfc_debug(2, "enc src count: %d, enc ref count: %d\n", + ctx->src_queue_cnt, ctx->ref_queue_cnt); + INIT_LIST_HEAD(&ctx->ref_queue); + ctx->ref_queue_cnt = 0; +} + +static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *dst_mb; + unsigned long dst_addr; + unsigned int dst_size; + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); + dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + dst_size); + return 0; +} + +static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_buf *dst_mb; + unsigned int enc_pb_count; + + if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) { + if (!list_empty(&ctx->dst_queue)) { + dst_mb = list_entry(ctx->dst_queue.next, + struct s5p_mfc_buf, list); + list_del(&dst_mb->list); + ctx->dst_queue_cnt--; + vb2_set_plane_payload(&dst_mb->b->vb2_buf, 0, + s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, + dev)); + vb2_buffer_done(&dst_mb->b->vb2_buf, + VB2_BUF_STATE_DONE); + } + } + + if (!IS_MFCV6_PLUS(dev)) { + ctx->state = MFCINST_RUNNING; + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + } else { + enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops, + get_enc_dpb_count, dev); + if (ctx->pb_count < enc_pb_count) + ctx->pb_count = enc_pb_count; + if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) { + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + get_e_min_scratch_buf_size, dev); + ctx->bank1.size += ctx->scratch_buf_size; + } + ctx->state = MFCINST_HEAD_PRODUCED; + } + + return 0; +} + +static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *dst_mb; + struct s5p_mfc_buf *src_mb; + unsigned long src_y_addr, src_c_addr, dst_addr; + unsigned int dst_size; + + src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx, + src_y_addr, src_c_addr); + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); + dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); + s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr, + dst_size); + + return 0; +} + +static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *mb_entry; + unsigned long enc_y_addr = 0, enc_c_addr = 0; + unsigned long mb_y_addr, mb_c_addr; + int slice_type; + unsigned int strm_size; + + slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev); + strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev); + mfc_debug(2, "Encoded slice type: %d\n", slice_type); + mfc_debug(2, "Encoded stream size: %d\n", strm_size); + mfc_debug(2, "Display order: %d\n", + mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); + if (slice_type >= 0) { + s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx, + &enc_y_addr, &enc_c_addr); + list_for_each_entry(mb_entry, &ctx->src_queue, list) { + mb_y_addr = vb2_dma_contig_plane_dma_addr( + &mb_entry->b->vb2_buf, 0); + mb_c_addr = vb2_dma_contig_plane_dma_addr( + &mb_entry->b->vb2_buf, 1); + if ((enc_y_addr == mb_y_addr) && + (enc_c_addr == mb_c_addr)) { + list_del(&mb_entry->list); + ctx->src_queue_cnt--; + vb2_buffer_done(&mb_entry->b->vb2_buf, + VB2_BUF_STATE_DONE); + break; + } + } + list_for_each_entry(mb_entry, &ctx->ref_queue, list) { + mb_y_addr = vb2_dma_contig_plane_dma_addr( + &mb_entry->b->vb2_buf, 0); + mb_c_addr = vb2_dma_contig_plane_dma_addr( + &mb_entry->b->vb2_buf, 1); + if ((enc_y_addr == mb_y_addr) && + (enc_c_addr == mb_c_addr)) { + list_del(&mb_entry->list); + ctx->ref_queue_cnt--; + vb2_buffer_done(&mb_entry->b->vb2_buf, + VB2_BUF_STATE_DONE); + break; + } + } + } + if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) { + mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, + list); + if (mb_entry->flags & MFC_BUF_FLAG_USED) { + list_del(&mb_entry->list); + ctx->src_queue_cnt--; + list_add_tail(&mb_entry->list, &ctx->ref_queue); + ctx->ref_queue_cnt++; + } + } + mfc_debug(2, "enc src count: %d, enc ref count: %d\n", + ctx->src_queue_cnt, ctx->ref_queue_cnt); + if ((ctx->dst_queue_cnt > 0) && (strm_size > 0)) { + mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, + list); + list_del(&mb_entry->list); + ctx->dst_queue_cnt--; + switch (slice_type) { + case S5P_FIMV_ENC_SI_SLICE_TYPE_I: + mb_entry->b->flags |= V4L2_BUF_FLAG_KEYFRAME; + break; + case S5P_FIMV_ENC_SI_SLICE_TYPE_P: + mb_entry->b->flags |= V4L2_BUF_FLAG_PFRAME; + break; + case S5P_FIMV_ENC_SI_SLICE_TYPE_B: + mb_entry->b->flags |= V4L2_BUF_FLAG_BFRAME; + break; + } + vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, strm_size); + vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE); + } + if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) + clear_work_bit(ctx); + + return 0; +} + +static const struct s5p_mfc_codec_ops encoder_codec_ops = { + .pre_seq_start = enc_pre_seq_start, + .post_seq_start = enc_post_seq_start, + .pre_frame_start = enc_pre_frame_start, + .post_frame_start = enc_post_frame_start, +}; + +/* Query capabilities of the device */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + + strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver)); + strscpy(cap->card, dev->vfd_enc->name, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(&dev->plat_dev->dev)); + return 0; +} + +static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, + bool out) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + int i, j = 0; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) { + if (out && formats[i].type != MFC_FMT_RAW) + continue; + else if (!out && formats[i].type != MFC_FMT_ENC) + continue; + else if ((dev->variant->version_bit & formats[i].versions) == 0) + continue; + + if (j == f->index) { + f->pixelformat = formats[i].fourcc; + return 0; + } + ++j; + } + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(file, f, false); +} + +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(file, f, true); +} + +static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + + mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state); + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + /* This is run on output (encoder dest) */ + pix_fmt_mp->width = 0; + pix_fmt_mp->height = 0; + pix_fmt_mp->field = V4L2_FIELD_NONE; + pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc; + pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes; + + pix_fmt_mp->plane_fmt[0].bytesperline = ctx->enc_dst_buf_size; + pix_fmt_mp->plane_fmt[0].sizeimage = ctx->enc_dst_buf_size; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* This is run on capture (encoder src) */ + pix_fmt_mp->width = ctx->img_width; + pix_fmt_mp->height = ctx->img_height; + + pix_fmt_mp->field = V4L2_FIELD_NONE; + pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc; + pix_fmt_mp->num_planes = ctx->src_fmt->num_planes; + + pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; + pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; + } else { + mfc_err("invalid buf type\n"); + return -EINVAL; + } + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + struct s5p_mfc_fmt *fmt; + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = find_format(f, MFC_FMT_ENC); + if (!fmt) { + mfc_err("failed to try output format\n"); + return -EINVAL; + } + if ((dev->variant->version_bit & fmt->versions) == 0) { + mfc_err("Unsupported format by this MFC version.\n"); + return -EINVAL; + } + + pix_fmt_mp->plane_fmt[0].bytesperline = + pix_fmt_mp->plane_fmt[0].sizeimage; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fmt = find_format(f, MFC_FMT_RAW); + if (!fmt) { + mfc_err("failed to try output format\n"); + return -EINVAL; + } + if ((dev->variant->version_bit & fmt->versions) == 0) { + mfc_err("Unsupported format by this MFC version.\n"); + return -EINVAL; + } + + v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1, + &pix_fmt_mp->height, 4, 1080, 1, 0); + } else { + mfc_err("invalid buf type\n"); + return -EINVAL; + } + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + int ret = 0; + + ret = vidioc_try_fmt(file, priv, f); + if (ret) + return ret; + if (ctx->vq_src.streaming || ctx->vq_dst.streaming) { + v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); + ret = -EBUSY; + goto out; + } + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + /* dst_fmt is validated by call to vidioc_try_fmt */ + ctx->dst_fmt = find_format(f, MFC_FMT_ENC); + ctx->state = MFCINST_INIT; + ctx->codec_mode = ctx->dst_fmt->codec_mode; + ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage; + pix_fmt_mp->plane_fmt[0].bytesperline = 0; + ctx->dst_bufs_cnt = 0; + ctx->capture_state = QUEUE_FREE; + ret = s5p_mfc_open_mfc_inst(dev, ctx); + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* src_fmt is validated by call to vidioc_try_fmt */ + ctx->src_fmt = find_format(f, MFC_FMT_RAW); + ctx->img_width = pix_fmt_mp->width; + ctx->img_height = pix_fmt_mp->height; + mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode); + mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n", + pix_fmt_mp->width, pix_fmt_mp->height, + ctx->img_width, ctx->img_height); + + s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx); + pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; + pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; + pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; + pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; + + ctx->src_bufs_cnt = 0; + ctx->output_state = QUEUE_FREE; + } else { + mfc_err("invalid buf type\n"); + ret = -EINVAL; + } +out: + mfc_debug_leave(); + return ret; +} + +static int vidioc_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *reqbufs) +{ + struct s5p_mfc_dev *dev = video_drvdata(file); + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + int ret = 0; + + /* if memory is not mmp or userptr return error */ + if ((reqbufs->memory != V4L2_MEMORY_MMAP) && + (reqbufs->memory != V4L2_MEMORY_USERPTR)) + return -EINVAL; + if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (reqbufs->count == 0) { + mfc_debug(2, "Freeing buffers\n"); + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, + ctx); + ctx->capture_state = QUEUE_FREE; + return ret; + } + if (ctx->capture_state != QUEUE_FREE) { + mfc_err("invalid capture state: %d\n", + ctx->capture_state); + return -EINVAL; + } + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + if (ret != 0) { + mfc_err("error in vb2_reqbufs() for E(D)\n"); + return ret; + } + ctx->capture_state = QUEUE_BUFS_REQUESTED; + + ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, + alloc_codec_buffers, ctx); + if (ret) { + mfc_err("Failed to allocate encoding buffers\n"); + reqbufs->count = 0; + ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); + return -ENOMEM; + } + } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (reqbufs->count == 0) { + mfc_debug(2, "Freeing buffers\n"); + ret = vb2_reqbufs(&ctx->vq_src, reqbufs); + s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, + ctx); + ctx->output_state = QUEUE_FREE; + return ret; + } + if (ctx->output_state != QUEUE_FREE) { + mfc_err("invalid output state: %d\n", + ctx->output_state); + return -EINVAL; + } + + if (IS_MFCV6_PLUS(dev)) { + /* Check for min encoder buffers */ + if (ctx->pb_count && + (reqbufs->count < ctx->pb_count)) { + reqbufs->count = ctx->pb_count; + mfc_debug(2, "Minimum %d output buffers needed\n", + ctx->pb_count); + } else { + ctx->pb_count = reqbufs->count; + } + } + + ret = vb2_reqbufs(&ctx->vq_src, reqbufs); + if (ret != 0) { + mfc_err("error in vb2_reqbufs() for E(S)\n"); + return ret; + } + ctx->output_state = QUEUE_BUFS_REQUESTED; + } else { + mfc_err("invalid buf type\n"); + return -EINVAL; + } + return ret; +} + +static int vidioc_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + int ret = 0; + + /* if memory is not mmp or userptr return error */ + if ((buf->memory != V4L2_MEMORY_MMAP) && + (buf->memory != V4L2_MEMORY_USERPTR)) + return -EINVAL; + if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (ctx->state != MFCINST_GOT_INST) { + mfc_err("invalid context state: %d\n", ctx->state); + return -EINVAL; + } + ret = vb2_querybuf(&ctx->vq_dst, buf); + if (ret != 0) { + mfc_err("error in vb2_querybuf() for E(D)\n"); + return ret; + } + buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE; + } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = vb2_querybuf(&ctx->vq_src, buf); + if (ret != 0) { + mfc_err("error in vb2_querybuf() for E(S)\n"); + return ret; + } + } else { + mfc_err("invalid buf type\n"); + return -EINVAL; + } + return ret; +} + +/* Queue a buffer */ +static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (ctx->state == MFCINST_ERROR) { + mfc_err("Call on QBUF after unrecoverable error\n"); + return -EIO; + } + if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (ctx->state == MFCINST_FINISHING) { + mfc_err("Call on QBUF after EOS command\n"); + return -EIO; + } + return vb2_qbuf(&ctx->vq_src, NULL, buf); + } else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + return vb2_qbuf(&ctx->vq_dst, NULL, buf); + } + return -EINVAL; +} + +/* Dequeue a buffer */ +static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + const struct v4l2_event ev = { + .type = V4L2_EVENT_EOS + }; + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + int ret; + + if (ctx->state == MFCINST_ERROR) { + mfc_err_limited("Call on DQBUF after unrecoverable error\n"); + return -EIO; + } + if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); + } else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); + if (ret == 0 && ctx->state == MFCINST_FINISHED + && list_empty(&ctx->vq_dst.done_list)) + v4l2_event_queue_fh(&ctx->fh, &ev); + } else { + ret = -EINVAL; + } + + return ret; +} + +/* Export DMA buffer */ +static int vidioc_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return vb2_expbuf(&ctx->vq_src, eb); + if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return vb2_expbuf(&ctx->vq_dst, eb); + return -EINVAL; +} + +/* Stream on */ +static int vidioc_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return vb2_streamon(&ctx->vq_src, type); + else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return vb2_streamon(&ctx->vq_dst, type); + return -EINVAL; +} + +/* Stream off, which equals to a pause */ +static int vidioc_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return vb2_streamoff(&ctx->vq_src, type); + else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return vb2_streamoff(&ctx->vq_dst, type); + return -EINVAL; +} + +static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl) +{ + static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_0 + 1] = { + /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0 */ 10, + /* V4L2_MPEG_VIDEO_H264_LEVEL_1B */ 9, + /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1 */ 11, + /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2 */ 12, + /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3 */ 13, + /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0 */ 20, + /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1 */ 21, + /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2 */ 22, + /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0 */ 30, + /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1 */ 31, + /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2 */ 32, + /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0 */ 40, + }; + return t[lvl]; +} + +static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl) +{ + static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 + 1] = { + /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 */ 0, + /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B */ 9, + /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 */ 1, + /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 */ 2, + /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 */ 3, + /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B */ 7, + /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 */ 4, + /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 */ 5, + }; + return t[lvl]; +} + +static inline int hevc_level(enum v4l2_mpeg_video_hevc_level lvl) +{ + static unsigned int t[] = { + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_1 */ 10, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2 */ 20, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 */ 21, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3 */ 30, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 */ 31, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4 */ 40, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 */ 41, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5 */ 50, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 */ 51, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 */ 52, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6 */ 60, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 */ 61, + /* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 */ 62, + }; + return t[lvl]; +} + +static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar) +{ + static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = { + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED */ 0, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 */ 1, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 */ 2, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 */ 3, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 */ 4, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 */ 5, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 */ 6, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 */ 7, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 */ 8, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 */ 9, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 */ 10, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 */ 11, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 */ 12, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 */ 13, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 */ 14, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 */ 15, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 */ 16, + /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED */ 255, + }; + return t[sar]; +} + +/* + * Update range of all HEVC quantization parameter controls that depend on the + * V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP controls. + */ +static void __enc_update_hevc_qp_ctrls_range(struct s5p_mfc_ctx *ctx, + int min, int max) +{ + static const int __hevc_qp_ctrls[] = { + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP, + }; + struct v4l2_ctrl *ctrl = NULL; + int i, j; + + for (i = 0; i < ARRAY_SIZE(__hevc_qp_ctrls); i++) { + for (j = 0; j < ARRAY_SIZE(ctx->ctrls); j++) { + if (ctx->ctrls[j]->id == __hevc_qp_ctrls[i]) { + ctrl = ctx->ctrls[j]; + break; + } + } + if (WARN_ON(!ctrl)) + break; + + __v4l2_ctrl_modify_range(ctrl, min, max, ctrl->step, min); + } +} + +static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + p->gop_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: + p->slice_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + p->slice_mb = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: + p->slice_bit = ctrl->val * 8; + break; + case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: + p->intra_refresh_mb = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_PADDING: + p->pad = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV: + p->pad_luma = (ctrl->val >> 16) & 0xff; + p->pad_cb = (ctrl->val >> 8) & 0xff; + p->pad_cr = (ctrl->val >> 0) & 0xff; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + p->rc_frame = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_BITRATE: + p->rc_bitrate = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF: + p->rc_reaction_coeff = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE: + ctx->force_frame_type = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: + ctx->force_frame_type = + V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME; + break; + case V4L2_CID_MPEG_VIDEO_VBV_SIZE: + p->vbv_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: + p->mv_h_range = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: + p->mv_v_range = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: + p->codec.h264.cpb_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + p->seq_hdr_mode = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: + case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: + p->frame_skip_mode = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT: + p->fixed_target_bit = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_B_FRAMES: + p->num_b_frame = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + p->codec.h264.profile = + S5P_FIMV_ENC_PROFILE_H264_MAIN; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + p->codec.h264.profile = + S5P_FIMV_ENC_PROFILE_H264_HIGH; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + p->codec.h264.profile = + S5P_FIMV_ENC_PROFILE_H264_BASELINE; + break; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + if (IS_MFCV6_PLUS(dev)) + p->codec.h264.profile = + S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE; + else + ret = -EINVAL; + break; + default: + ret = -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + p->codec.h264.level_v4l2 = ctrl->val; + p->codec.h264.level = h264_level(ctrl->val); + if (p->codec.h264.level < 0) { + mfc_err("Level number is wrong\n"); + ret = p->codec.h264.level; + } + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + p->codec.mpeg4.level_v4l2 = ctrl->val; + p->codec.mpeg4.level = mpeg4_level(ctrl->val); + if (p->codec.mpeg4.level < 0) { + mfc_err("Level number is wrong\n"); + ret = p->codec.mpeg4.level; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + p->codec.h264.loop_filter_mode = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: + p->codec.h264.loop_filter_alpha = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: + p->codec.h264.loop_filter_beta = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + p->codec.h264.entropy_mode = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P: + p->codec.h264.num_ref_pic_4p = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + p->codec.h264._8x8_transform = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: + p->rc_mb = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: + p->codec.h264.rc_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: + p->codec.h264.rc_min_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: + p->codec.h264.rc_max_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: + p->codec.h264.rc_p_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: + p->codec.h264.rc_b_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: + case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: + p->codec.mpeg4.rc_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: + case V4L2_CID_MPEG_VIDEO_H263_MIN_QP: + p->codec.mpeg4.rc_min_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: + case V4L2_CID_MPEG_VIDEO_H263_MAX_QP: + p->codec.mpeg4.rc_max_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: + case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: + p->codec.mpeg4.rc_p_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: + case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: + p->codec.mpeg4.rc_b_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK: + p->codec.h264.rc_mb_dark = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH: + p->codec.h264.rc_mb_smooth = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC: + p->codec.h264.rc_mb_static = ctrl->val; + break; + case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY: + p->codec.h264.rc_mb_activity = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: + p->codec.h264.vui_sar = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: + p->codec.h264.vui_sar_idc = vui_sar_idc(ctrl->val); + break; + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: + p->codec.h264.vui_ext_sar_width = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: + p->codec.h264.vui_ext_sar_height = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: + p->codec.h264.open_gop = !ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: + p->codec.h264.open_gop_size = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: + p->codec.mpeg4.profile = + S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE; + break; + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: + p->codec.mpeg4.profile = + S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE; + break; + default: + ret = -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: + p->codec.mpeg4.quarter_pixel = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: + p->codec.vp8.num_partitions = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4: + p->codec.vp8.imd_4x4 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: + p->codec.vp8.num_ref = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL: + p->codec.vp8.filter_level = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS: + p->codec.vp8.filter_sharpness = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD: + p->codec.vp8.golden_frame_ref_period = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: + p->codec.vp8.golden_frame_sel = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: + p->codec.vp8.rc_min_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: + p->codec.vp8.rc_max_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: + p->codec.vp8.rc_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: + p->codec.vp8.rc_p_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: + p->codec.vp8.profile = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: + p->codec.hevc.rc_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: + p->codec.hevc.rc_p_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: + p->codec.hevc.rc_b_frame_qp = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: + p->codec.hevc.rc_framerate = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: + p->codec.hevc.rc_min_qp = ctrl->val; + __enc_update_hevc_qp_ctrls_range(ctx, ctrl->val, + p->codec.hevc.rc_max_qp); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: + p->codec.hevc.rc_max_qp = ctrl->val; + __enc_update_hevc_qp_ctrls_range(ctx, p->codec.hevc.rc_min_qp, + ctrl->val); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + p->codec.hevc.level_v4l2 = ctrl->val; + p->codec.hevc.level = hevc_level(ctrl->val); + break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + p->codec.hevc.profile = + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; + break; + case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + p->codec.hevc.profile = + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; + break; + default: + ret = -EINVAL; + } + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TIER: + p->codec.hevc.tier = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: + p->codec.hevc.max_partition_depth = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: + p->codec.hevc.num_refs_for_p = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: + p->codec.hevc.refreshtype = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: + p->codec.hevc.const_intra_period_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: + p->codec.hevc.lossless_cu_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: + p->codec.hevc.wavefront_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: + p->codec.hevc.loopfilter = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: + p->codec.hevc.hier_qp_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: + p->codec.hevc.hier_qp_type = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: + p->codec.hevc.num_hier_layer = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: + p->codec.hevc.hier_qp_layer[0] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: + p->codec.hevc.hier_qp_layer[1] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: + p->codec.hevc.hier_qp_layer[2] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: + p->codec.hevc.hier_qp_layer[3] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: + p->codec.hevc.hier_qp_layer[4] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: + p->codec.hevc.hier_qp_layer[5] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: + p->codec.hevc.hier_qp_layer[6] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: + p->codec.hevc.hier_bit_layer[0] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: + p->codec.hevc.hier_bit_layer[1] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: + p->codec.hevc.hier_bit_layer[2] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: + p->codec.hevc.hier_bit_layer[3] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: + p->codec.hevc.hier_bit_layer[4] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: + p->codec.hevc.hier_bit_layer[5] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: + p->codec.hevc.hier_bit_layer[6] = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: + p->codec.hevc.general_pb_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: + p->codec.hevc.temporal_id_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: + p->codec.hevc.strong_intra_smooth = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: + p->codec.hevc.intra_pu_split_disable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: + p->codec.hevc.tmv_prediction_disable = !ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: + p->codec.hevc.max_num_merge_mv = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: + p->codec.hevc.encoding_nostartcode_enable = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: + p->codec.hevc.refreshperiod = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: + p->codec.hevc.lf_beta_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: + p->codec.hevc.lf_tc_offset_div2 = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: + p->codec.hevc.size_of_length_field = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: + p->codec.hevc.prepend_sps_pps_to_idr = ctrl->val; + break; + default: + v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", + ctrl->id, ctrl->val); + ret = -EINVAL; + } + return ret; +} + +static int s5p_mfc_enc_g_v_ctrl(struct v4l2_ctrl *ctrl) +{ + struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); + struct s5p_mfc_dev *dev = ctx->dev; + + switch (ctrl->id) { + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + if (ctx->state >= MFCINST_HEAD_PARSED && + ctx->state < MFCINST_ABORT) { + ctrl->val = ctx->pb_count; + break; + } else if (ctx->state != MFCINST_INIT) { + v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n"); + return -EINVAL; + } + /* Should wait for the header to be produced */ + s5p_mfc_wait_for_done_ctx(ctx, + S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0); + if (ctx->state >= MFCINST_HEAD_PARSED && + ctx->state < MFCINST_ABORT) { + ctrl->val = ctx->pb_count; + } else { + v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n"); + return -EINVAL; + } + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = { + .s_ctrl = s5p_mfc_enc_s_ctrl, + .g_volatile_ctrl = s5p_mfc_enc_g_v_ctrl, +}; + +static int vidioc_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *a) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ctx->enc_params.rc_framerate_num = + a->parm.output.timeperframe.denominator; + ctx->enc_params.rc_framerate_denom = + a->parm.output.timeperframe.numerator; + } else { + mfc_err("Setting FPS is only possible for the output queue\n"); + return -EINVAL; + } + return 0; +} + +static int vidioc_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *a) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + a->parm.output.timeperframe.denominator = + ctx->enc_params.rc_framerate_num; + a->parm.output.timeperframe.numerator = + ctx->enc_params.rc_framerate_denom; + } else { + mfc_err("Setting FPS is only possible for the output queue\n"); + return -EINVAL; + } + return 0; +} + +static int vidioc_encoder_cmd(struct file *file, void *priv, + struct v4l2_encoder_cmd *cmd) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *buf; + unsigned long flags; + + switch (cmd->cmd) { + case V4L2_ENC_CMD_STOP: + if (cmd->flags != 0) + return -EINVAL; + + if (!ctx->vq_src.streaming) + return -EINVAL; + + spin_lock_irqsave(&dev->irqlock, flags); + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "EOS: empty src queue, entering finishing state\n"); + ctx->state = MFCINST_FINISHING; + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + spin_unlock_irqrestore(&dev->irqlock, flags); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + } else { + mfc_debug(2, "EOS: marking last buffer of stream\n"); + buf = list_entry(ctx->src_queue.prev, + struct s5p_mfc_buf, list); + if (buf->flags & MFC_BUF_FLAG_USED) + ctx->state = MFCINST_FINISHING; + else + buf->flags |= MFC_BUF_FLAG_EOS; + spin_unlock_irqrestore(&dev->irqlock, flags); + } + break; + default: + return -EINVAL; + + } + return 0; +} + +static int vidioc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 2, NULL); + default: + return -EINVAL; + } +} + +static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_expbuf = vidioc_expbuf, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_s_parm = vidioc_s_parm, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_encoder_cmd = vidioc_encoder_cmd, + .vidioc_subscribe_event = vidioc_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) +{ + int i; + + if (!fmt) + return -EINVAL; + if (fmt->num_planes != vb->num_planes) { + mfc_err("invalid plane number for the format\n"); + return -EINVAL; + } + for (i = 0; i < fmt->num_planes; i++) { + dma_addr_t dma = vb2_dma_contig_plane_dma_addr(vb, i); + if (!dma) { + mfc_err("failed to get plane cookie\n"); + return -EINVAL; + } + mfc_debug(2, "index: %d, plane[%d] cookie: %pad\n", + vb->index, i, &dma); + } + return 0; +} + +static int s5p_mfc_queue_setup(struct vb2_queue *vq, + unsigned int *buf_count, unsigned int *plane_count, + unsigned int psize[], struct device *alloc_devs[]) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; + + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (ctx->state != MFCINST_GOT_INST) { + mfc_err("invalid state: %d\n", ctx->state); + return -EINVAL; + } + + if (ctx->dst_fmt) + *plane_count = ctx->dst_fmt->num_planes; + else + *plane_count = MFC_ENC_CAP_PLANE_COUNT; + if (*buf_count < 1) + *buf_count = 1; + if (*buf_count > MFC_MAX_BUFFERS) + *buf_count = MFC_MAX_BUFFERS; + psize[0] = ctx->enc_dst_buf_size; + alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; + } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (ctx->src_fmt) + *plane_count = ctx->src_fmt->num_planes; + else + *plane_count = MFC_ENC_OUT_PLANE_COUNT; + + if (*buf_count < 1) + *buf_count = 1; + if (*buf_count > MFC_MAX_BUFFERS) + *buf_count = MFC_MAX_BUFFERS; + + psize[0] = ctx->luma_size; + psize[1] = ctx->chroma_size; + + if (IS_MFCV6_PLUS(dev)) { + alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX]; + alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX]; + } else { + alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX]; + alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX]; + } + } else { + mfc_err("invalid queue type: %d\n", vq->type); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vb2_queue *vq = vb->vb2_queue; + struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + unsigned int i; + int ret; + + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = check_vb_with_fmt(ctx->dst_fmt, vb); + if (ret < 0) + return ret; + i = vb->index; + ctx->dst_bufs[i].b = vbuf; + ctx->dst_bufs[i].cookie.stream = + vb2_dma_contig_plane_dma_addr(vb, 0); + ctx->dst_bufs_cnt++; + } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = check_vb_with_fmt(ctx->src_fmt, vb); + if (ret < 0) + return ret; + i = vb->index; + ctx->src_bufs[i].b = vbuf; + ctx->src_bufs[i].cookie.raw.luma = + vb2_dma_contig_plane_dma_addr(vb, 0); + ctx->src_bufs[i].cookie.raw.chroma = + vb2_dma_contig_plane_dma_addr(vb, 1); + ctx->src_bufs_cnt++; + } else { + mfc_err("invalid queue type: %d\n", vq->type); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + int ret; + + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = check_vb_with_fmt(ctx->dst_fmt, vb); + if (ret < 0) + return ret; + mfc_debug(2, "plane size: %ld, dst size: %zu\n", + vb2_plane_size(vb, 0), ctx->enc_dst_buf_size); + if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) { + mfc_err("plane size is too small for capture\n"); + return -EINVAL; + } + } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + ret = check_vb_with_fmt(ctx->src_fmt, vb); + if (ret < 0) + return ret; + mfc_debug(2, "plane size: %ld, luma size: %d\n", + vb2_plane_size(vb, 0), ctx->luma_size); + mfc_debug(2, "plane size: %ld, chroma size: %d\n", + vb2_plane_size(vb, 1), ctx->chroma_size); + if (vb2_plane_size(vb, 0) < ctx->luma_size || + vb2_plane_size(vb, 1) < ctx->chroma_size) { + mfc_err("plane size is too small for output\n"); + return -EINVAL; + } + } else { + mfc_err("invalid queue type: %d\n", vq->type); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; + + if (IS_MFCV6_PLUS(dev) && + (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) { + + if ((ctx->state == MFCINST_GOT_INST) && + (dev->curr_ctx == ctx->num) && dev->hw_lock) { + s5p_mfc_wait_for_done_ctx(ctx, + S5P_MFC_R2H_CMD_SEQ_DONE_RET, + 0); + } + + if (ctx->src_bufs_cnt < ctx->pb_count) { + mfc_err("Need minimum %d OUTPUT buffers\n", + ctx->pb_count); + return -ENOBUFS; + } + } + + /* If context is ready then dev = work->data;schedule it to run */ + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); + + return 0; +} + +static void s5p_mfc_stop_streaming(struct vb2_queue *q) +{ + unsigned long flags; + struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; + + if ((ctx->state == MFCINST_FINISHING || + ctx->state == MFCINST_RUNNING) && + dev->curr_ctx == ctx->num && dev->hw_lock) { + ctx->state = MFCINST_ABORT; + s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_FRAME_DONE_RET, + 0); + } + ctx->state = MFCINST_FINISHED; + spin_lock_irqsave(&dev->irqlock, flags); + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); + INIT_LIST_HEAD(&ctx->dst_queue); + ctx->dst_queue_cnt = 0; + } + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + cleanup_ref_queue(ctx); + s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); + INIT_LIST_HEAD(&ctx->src_queue); + ctx->src_queue_cnt = 0; + } + spin_unlock_irqrestore(&dev->irqlock, flags); +} + +static void s5p_mfc_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_queue *vq = vb->vb2_queue; + struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); + struct s5p_mfc_dev *dev = ctx->dev; + unsigned long flags; + struct s5p_mfc_buf *mfc_buf; + + if (ctx->state == MFCINST_ERROR) { + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + cleanup_ref_queue(ctx); + return; + } + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + mfc_buf = &ctx->dst_bufs[vb->index]; + mfc_buf->flags &= ~MFC_BUF_FLAG_USED; + /* Mark destination as available for use by MFC */ + spin_lock_irqsave(&dev->irqlock, flags); + list_add_tail(&mfc_buf->list, &ctx->dst_queue); + ctx->dst_queue_cnt++; + spin_unlock_irqrestore(&dev->irqlock, flags); + } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_buf = &ctx->src_bufs[vb->index]; + mfc_buf->flags &= ~MFC_BUF_FLAG_USED; + spin_lock_irqsave(&dev->irqlock, flags); + list_add_tail(&mfc_buf->list, &ctx->src_queue); + ctx->src_queue_cnt++; + spin_unlock_irqrestore(&dev->irqlock, flags); + } else { + mfc_err("unsupported buffer type (%d)\n", vq->type); + } + if (s5p_mfc_ctx_ready(ctx)) + set_work_bit_irqsave(ctx); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); +} + +static struct vb2_ops s5p_mfc_enc_qops = { + .queue_setup = s5p_mfc_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_init = s5p_mfc_buf_init, + .buf_prepare = s5p_mfc_buf_prepare, + .start_streaming = s5p_mfc_start_streaming, + .stop_streaming = s5p_mfc_stop_streaming, + .buf_queue = s5p_mfc_buf_queue, +}; + +const struct s5p_mfc_codec_ops *get_enc_codec_ops(void) +{ + return &encoder_codec_ops; +} + +struct vb2_ops *get_enc_queue_ops(void) +{ + return &s5p_mfc_enc_qops; +} + +const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void) +{ + return &s5p_mfc_enc_ioctl_ops; +} + +#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_CODEC) \ + && V4L2_CTRL_DRIVER_PRIV(x)) + +int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_ctrl_config cfg; + int i; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS); + if (ctx->ctrl_handler.error) { + mfc_err("v4l2_ctrl_handler_init failed\n"); + return ctx->ctrl_handler.error; + } + for (i = 0; i < NUM_CTRLS; i++) { + if (IS_MFC51_PRIV(controls[i].id)) { + memset(&cfg, 0, sizeof(struct v4l2_ctrl_config)); + cfg.ops = &s5p_mfc_enc_ctrl_ops; + cfg.id = controls[i].id; + cfg.min = controls[i].minimum; + cfg.max = controls[i].maximum; + cfg.def = controls[i].default_value; + cfg.name = controls[i].name; + cfg.type = controls[i].type; + cfg.flags = 0; + + if (cfg.type == V4L2_CTRL_TYPE_MENU) { + cfg.step = 0; + cfg.menu_skip_mask = controls[i].menu_skip_mask; + cfg.qmenu = mfc51_get_menu(cfg.id); + } else { + cfg.step = controls[i].step; + cfg.menu_skip_mask = 0; + } + ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler, + &cfg, NULL); + } else { + if ((controls[i].type == V4L2_CTRL_TYPE_MENU) || + (controls[i].type == + V4L2_CTRL_TYPE_INTEGER_MENU)) { + ctx->ctrls[i] = v4l2_ctrl_new_std_menu( + &ctx->ctrl_handler, + &s5p_mfc_enc_ctrl_ops, controls[i].id, + controls[i].maximum, 0, + controls[i].default_value); + } else { + ctx->ctrls[i] = v4l2_ctrl_new_std( + &ctx->ctrl_handler, + &s5p_mfc_enc_ctrl_ops, controls[i].id, + controls[i].minimum, + controls[i].maximum, controls[i].step, + controls[i].default_value); + } + } + if (ctx->ctrl_handler.error) { + mfc_err("Adding control (%d) failed\n", i); + return ctx->ctrl_handler.error; + } + if (controls[i].is_volatile && ctx->ctrls[i]) + ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE; + } + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + return 0; +} + +void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx) +{ + int i; + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + for (i = 0; i < NUM_CTRLS; i++) + ctx->ctrls[i] = NULL; +} + +void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx) +{ + struct v4l2_format f; + f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_ENC; + ctx->src_fmt = find_format(&f, MFC_FMT_RAW); + f.fmt.pix_mp.pixelformat = DEF_DST_FMT_ENC; + ctx->dst_fmt = find_format(&f, MFC_FMT_ENC); +} diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.h new file mode 100644 index 000000000000..3f1b1a037a4f --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_ENC_H_ +#define S5P_MFC_ENC_H_ + +const struct s5p_mfc_codec_ops *get_enc_codec_ops(void); +struct vb2_ops *get_enc_queue_ops(void); +const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); +struct s5p_mfc_fmt *get_enc_def_fmt(bool src); +int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx); +void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx); +void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx); + +#endif /* S5P_MFC_ENC_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_intr.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_intr.c new file mode 100644 index 000000000000..0a38f6d70ee9 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_intr.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.c + * + * C file for Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains functions used to wait for command completion. + * + * Kamil Debski, Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#include +#include +#include +#include +#include +#include "s5p_mfc_common.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" + +int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) +{ + int ret; + + ret = wait_event_interruptible_timeout(dev->queue, + (dev->int_cond && (dev->int_type == command + || dev->int_type == S5P_MFC_R2H_CMD_ERR_RET)), + msecs_to_jiffies(MFC_INT_TIMEOUT)); + if (ret == 0) { + mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n", + dev->int_type, command); + return 1; + } else if (ret == -ERESTARTSYS) { + mfc_err("Interrupted by a signal\n"); + return 1; + } + mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n", + dev->int_type, command); + if (dev->int_type == S5P_MFC_R2H_CMD_ERR_RET) + return 1; + return 0; +} + +void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev) +{ + dev->int_cond = 0; + dev->int_type = 0; + dev->int_err = 0; +} + +int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, + int command, int interrupt) +{ + int ret; + + if (interrupt) { + ret = wait_event_interruptible_timeout(ctx->queue, + (ctx->int_cond && (ctx->int_type == command + || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), + msecs_to_jiffies(MFC_INT_TIMEOUT)); + } else { + ret = wait_event_timeout(ctx->queue, + (ctx->int_cond && (ctx->int_type == command + || ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET)), + msecs_to_jiffies(MFC_INT_TIMEOUT)); + } + if (ret == 0) { + mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n", + ctx->int_type, command); + return 1; + } else if (ret == -ERESTARTSYS) { + mfc_err("Interrupted by a signal\n"); + return 1; + } + mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n", + ctx->int_type, command); + if (ctx->int_type == S5P_MFC_R2H_CMD_ERR_RET) + return 1; + return 0; +} + +void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx) +{ + ctx->int_cond = 0; + ctx->int_type = 0; + ctx->int_err = 0; +} + diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_intr.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_intr.h new file mode 100644 index 000000000000..d32860db17d2 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_intr.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/platform/samsung/mfc5/s5p_mfc_intr.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * It contains waiting functions declarations. + * + * Kamil Debski, Copyright (C) 2011 Samsung Electronics + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_INTR_H_ +#define S5P_MFC_INTR_H_ + +#include "s5p_mfc_common.h" + +int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, + int command, int interrupt); +int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command); +void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx); +void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev); + +#endif /* S5P_MFC_INTR_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_iommu.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_iommu.h new file mode 100644 index 000000000000..1a32266b7ddc --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_iommu.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2015 Samsung Electronics Co.Ltd + * Authors: Marek Szyprowski + */ + +#ifndef S5P_MFC_IOMMU_H_ +#define S5P_MFC_IOMMU_H_ + +#if defined(CONFIG_EXYNOS_IOMMU) + +#include + +static inline bool exynos_is_iommu_available(struct device *dev) +{ + return dev_iommu_priv_get(dev) != NULL; +} + +#else + +static inline bool exynos_is_iommu_available(struct device *dev) +{ + return false; +} + +#endif + +#endif /* S5P_MFC_IOMMU_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.c new file mode 100644 index 000000000000..673962301173 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Kamil Debski, Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#include "s5p_mfc_debug.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v5.h" +#include "s5p_mfc_opr_v6.h" + +static struct s5p_mfc_hw_ops *s5p_mfc_ops; + +void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev) +{ + if (IS_MFCV6_PLUS(dev)) { + s5p_mfc_ops = s5p_mfc_init_hw_ops_v6(); + dev->warn_start = S5P_FIMV_ERR_WARNINGS_START_V6; + } else { + s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); + dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; + } + dev->mfc_ops = s5p_mfc_ops; +} + +void s5p_mfc_init_regs(struct s5p_mfc_dev *dev) +{ + if (IS_MFCV6_PLUS(dev)) + dev->mfc_regs = s5p_mfc_init_regs_v6_plus(dev); +} + +int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b) +{ + unsigned int bits = dev->mem_size >> PAGE_SHIFT; + unsigned int count = b->size >> PAGE_SHIFT; + unsigned int align = (SZ_64K >> PAGE_SHIFT) - 1; + unsigned int start, offset; + + mfc_debug(3, "Allocating priv: %zu\n", b->size); + + if (dev->mem_virt) { + start = bitmap_find_next_zero_area(dev->mem_bitmap, bits, 0, count, align); + if (start > bits) + goto no_mem; + + bitmap_set(dev->mem_bitmap, start, count); + offset = start << PAGE_SHIFT; + b->virt = dev->mem_virt + offset; + b->dma = dev->mem_base + offset; + } else { + struct device *mem_dev = dev->mem_dev[mem_ctx]; + dma_addr_t base = dev->dma_base[mem_ctx]; + + b->ctx = mem_ctx; + b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL); + if (!b->virt) + goto no_mem; + if (b->dma < base) { + mfc_err("Invalid memory configuration - buffer (%pad) is below base memory address(%pad)\n", + &b->dma, &base); + dma_free_coherent(mem_dev, b->size, b->virt, b->dma); + return -ENOMEM; + } + } + + mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); + return 0; +no_mem: + mfc_err("Allocating private buffer of size %zu failed\n", b->size); + return -ENOMEM; +} + +int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b) +{ + struct device *mem_dev = dev->mem_dev[mem_ctx]; + + mfc_debug(3, "Allocating generic buf: %zu\n", b->size); + + b->ctx = mem_ctx; + b->virt = dma_alloc_coherent(mem_dev, b->size, &b->dma, GFP_KERNEL); + if (!b->virt) + goto no_mem; + + mfc_debug(3, "Allocated addr %p %pad\n", b->virt, &b->dma); + return 0; +no_mem: + mfc_err("Allocating generic buffer of size %zu failed\n", b->size); + return -ENOMEM; +} + +void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b) +{ + if (dev->mem_virt) { + unsigned int start = (b->dma - dev->mem_base) >> PAGE_SHIFT; + unsigned int count = b->size >> PAGE_SHIFT; + + bitmap_clear(dev->mem_bitmap, start, count); + } else { + struct device *mem_dev = dev->mem_dev[b->ctx]; + + dma_free_coherent(mem_dev, b->size, b->virt, b->dma); + } + b->virt = NULL; + b->dma = 0; + b->size = 0; +} + +void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b) +{ + struct device *mem_dev = dev->mem_dev[b->ctx]; + dma_free_coherent(mem_dev, b->size, b->virt, b->dma); + b->virt = NULL; + b->dma = 0; + b->size = 0; +} diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h new file mode 100644 index 000000000000..b9831275f3ab --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Kamil Debski, Copyright (C) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_OPR_H_ +#define S5P_MFC_OPR_H_ + +#include "s5p_mfc_common.h" + +struct s5p_mfc_regs { + + /* codec common registers */ + void __iomem *risc_on; + void __iomem *risc2host_int; + void __iomem *host2risc_int; + void __iomem *risc_base_address; + void __iomem *mfc_reset; + void __iomem *host2risc_command; + void __iomem *risc2host_command; + void __iomem *mfc_bus_reset_ctrl; + void __iomem *firmware_version; + void __iomem *instance_id; + void __iomem *codec_type; + void __iomem *context_mem_addr; + void __iomem *context_mem_size; + void __iomem *pixel_format; + void __iomem *metadata_enable; + void __iomem *mfc_version; + void __iomem *dbg_info_enable; + void __iomem *dbg_buffer_addr; + void __iomem *dbg_buffer_size; + void __iomem *hed_control; + void __iomem *mfc_timeout_value; + void __iomem *hed_shared_mem_addr; + void __iomem *dis_shared_mem_addr;/* only v7 */ + void __iomem *ret_instance_id; + void __iomem *error_code; + void __iomem *dbg_buffer_output_size; + void __iomem *metadata_status; + void __iomem *metadata_addr_mb_info; + void __iomem *metadata_size_mb_info; + void __iomem *dbg_info_stage_counter; + + /* decoder registers */ + void __iomem *d_crc_ctrl; + void __iomem *d_dec_options; + void __iomem *d_display_delay; + void __iomem *d_set_frame_width; + void __iomem *d_set_frame_height; + void __iomem *d_sei_enable; + void __iomem *d_min_num_dpb; + void __iomem *d_min_first_plane_dpb_size; + void __iomem *d_min_second_plane_dpb_size; + void __iomem *d_min_third_plane_dpb_size;/* only v8 */ + void __iomem *d_min_num_mv; + void __iomem *d_mvc_num_views; + void __iomem *d_min_num_dis;/* only v7 */ + void __iomem *d_min_first_dis_size;/* only v7 */ + void __iomem *d_min_second_dis_size;/* only v7 */ + void __iomem *d_min_third_dis_size;/* only v7 */ + void __iomem *d_post_filter_luma_dpb0;/* v7 and v8 */ + void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */ + void __iomem *d_post_filter_luma_dpb2;/* only v7 */ + void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */ + void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */ + void __iomem *d_post_filter_chroma_dpb2;/* only v7 */ + void __iomem *d_num_dpb; + void __iomem *d_num_mv; + void __iomem *d_init_buffer_options; + void __iomem *d_first_plane_dpb_stride_size;/* only v8 */ + void __iomem *d_second_plane_dpb_stride_size;/* only v8 */ + void __iomem *d_third_plane_dpb_stride_size;/* only v8 */ + void __iomem *d_first_plane_dpb_size; + void __iomem *d_second_plane_dpb_size; + void __iomem *d_third_plane_dpb_size;/* only v8 */ + void __iomem *d_mv_buffer_size; + void __iomem *d_first_plane_dpb; + void __iomem *d_second_plane_dpb; + void __iomem *d_third_plane_dpb; + void __iomem *d_mv_buffer; + void __iomem *d_scratch_buffer_addr; + void __iomem *d_scratch_buffer_size; + void __iomem *d_metadata_buffer_addr; + void __iomem *d_metadata_buffer_size; + void __iomem *d_nal_start_options;/* v7 and v8 */ + void __iomem *d_cpb_buffer_addr; + void __iomem *d_cpb_buffer_size; + void __iomem *d_available_dpb_flag_upper; + void __iomem *d_available_dpb_flag_lower; + void __iomem *d_cpb_buffer_offset; + void __iomem *d_slice_if_enable; + void __iomem *d_picture_tag; + void __iomem *d_stream_data_size; + void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */ + void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */ + void __iomem *d_display_frame_width; + void __iomem *d_display_frame_height; + void __iomem *d_display_status; + void __iomem *d_display_first_plane_addr; + void __iomem *d_display_second_plane_addr; + void __iomem *d_display_third_plane_addr;/* only v8 */ + void __iomem *d_display_frame_type; + void __iomem *d_display_crop_info1; + void __iomem *d_display_crop_info2; + void __iomem *d_display_picture_profile; + void __iomem *d_display_luma_crc;/* v7 and v8 */ + void __iomem *d_display_chroma0_crc;/* v7 and v8 */ + void __iomem *d_display_chroma1_crc;/* only v8 */ + void __iomem *d_display_luma_crc_top;/* only v6 */ + void __iomem *d_display_chroma_crc_top;/* only v6 */ + void __iomem *d_display_luma_crc_bot;/* only v6 */ + void __iomem *d_display_chroma_crc_bot;/* only v6 */ + void __iomem *d_display_aspect_ratio; + void __iomem *d_display_extended_ar; + void __iomem *d_decoded_frame_width; + void __iomem *d_decoded_frame_height; + void __iomem *d_decoded_status; + void __iomem *d_decoded_first_plane_addr; + void __iomem *d_decoded_second_plane_addr; + void __iomem *d_decoded_third_plane_addr;/* only v8 */ + void __iomem *d_decoded_frame_type; + void __iomem *d_decoded_crop_info1; + void __iomem *d_decoded_crop_info2; + void __iomem *d_decoded_picture_profile; + void __iomem *d_decoded_nal_size; + void __iomem *d_decoded_luma_crc; + void __iomem *d_decoded_chroma0_crc; + void __iomem *d_decoded_chroma1_crc;/* only v8 */ + void __iomem *d_ret_picture_tag_top; + void __iomem *d_ret_picture_tag_bot; + void __iomem *d_ret_picture_time_top; + void __iomem *d_ret_picture_time_bot; + void __iomem *d_chroma_format; + void __iomem *d_vc1_info;/* v7 and v8 */ + void __iomem *d_mpeg4_info; + void __iomem *d_h264_info; + void __iomem *d_metadata_addr_concealed_mb; + void __iomem *d_metadata_size_concealed_mb; + void __iomem *d_metadata_addr_vc1_param; + void __iomem *d_metadata_size_vc1_param; + void __iomem *d_metadata_addr_sei_nal; + void __iomem *d_metadata_size_sei_nal; + void __iomem *d_metadata_addr_vui; + void __iomem *d_metadata_size_vui; + void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */ + void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */ + void __iomem *d_mvc_view_id; + void __iomem *d_frame_pack_sei_avail; + void __iomem *d_frame_pack_arrgment_id; + void __iomem *d_frame_pack_sei_info; + void __iomem *d_frame_pack_grid_pos; + void __iomem *d_display_recovery_sei_info;/* v7 and v8 */ + void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */ + void __iomem *d_display_first_addr;/* only v7 */ + void __iomem *d_display_second_addr;/* only v7 */ + void __iomem *d_display_third_addr;/* only v7 */ + void __iomem *d_decoded_first_addr;/* only v7 */ + void __iomem *d_decoded_second_addr;/* only v7 */ + void __iomem *d_decoded_third_addr;/* only v7 */ + void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */ + void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */ + void __iomem *d_min_scratch_buffer_size; /* v10 */ + void __iomem *d_static_buffer_addr; /* v10 */ + void __iomem *d_static_buffer_size; /* v10 */ + + /* encoder registers */ + void __iomem *e_frame_width; + void __iomem *e_frame_height; + void __iomem *e_cropped_frame_width; + void __iomem *e_cropped_frame_height; + void __iomem *e_frame_crop_offset; + void __iomem *e_enc_options; + void __iomem *e_picture_profile; + void __iomem *e_vbv_buffer_size; + void __iomem *e_vbv_init_delay; + void __iomem *e_fixed_picture_qp; + void __iomem *e_rc_config; + void __iomem *e_rc_qp_bound; + void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */ + void __iomem *e_rc_mode; + void __iomem *e_mb_rc_config; + void __iomem *e_padding_ctrl; + void __iomem *e_air_threshold; + void __iomem *e_mv_hor_range; + void __iomem *e_mv_ver_range; + void __iomem *e_num_dpb; + void __iomem *e_luma_dpb; + void __iomem *e_chroma_dpb; + void __iomem *e_me_buffer; + void __iomem *e_scratch_buffer_addr; + void __iomem *e_scratch_buffer_size; + void __iomem *e_tmv_buffer0; + void __iomem *e_tmv_buffer1; + void __iomem *e_ir_buffer_addr;/* v7 and v8 */ + void __iomem *e_source_first_plane_addr; + void __iomem *e_source_second_plane_addr; + void __iomem *e_source_third_plane_addr;/* v7 and v8 */ + void __iomem *e_source_first_plane_stride;/* v7 and v8 */ + void __iomem *e_source_second_plane_stride;/* v7 and v8 */ + void __iomem *e_source_third_plane_stride;/* v7 and v8 */ + void __iomem *e_stream_buffer_addr; + void __iomem *e_stream_buffer_size; + void __iomem *e_roi_buffer_addr; + void __iomem *e_param_change; + void __iomem *e_ir_size; + void __iomem *e_gop_config; + void __iomem *e_mslice_mode; + void __iomem *e_mslice_size_mb; + void __iomem *e_mslice_size_bits; + void __iomem *e_frame_insertion; + void __iomem *e_rc_frame_rate; + void __iomem *e_rc_bit_rate; + void __iomem *e_rc_roi_ctrl; + void __iomem *e_picture_tag; + void __iomem *e_bit_count_enable; + void __iomem *e_max_bit_count; + void __iomem *e_min_bit_count; + void __iomem *e_metadata_buffer_addr; + void __iomem *e_metadata_buffer_size; + void __iomem *e_encoded_source_first_plane_addr; + void __iomem *e_encoded_source_second_plane_addr; + void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */ + void __iomem *e_stream_size; + void __iomem *e_slice_type; + void __iomem *e_picture_count; + void __iomem *e_ret_picture_tag; + void __iomem *e_stream_buffer_write_pointer; /* only v6 */ + void __iomem *e_recon_luma_dpb_addr; + void __iomem *e_recon_chroma_dpb_addr; + void __iomem *e_metadata_addr_enc_slice; + void __iomem *e_metadata_size_enc_slice; + void __iomem *e_mpeg4_options; + void __iomem *e_mpeg4_hec_period; + void __iomem *e_aspect_ratio; + void __iomem *e_extended_sar; + void __iomem *e_h264_options; + void __iomem *e_h264_options_2;/* v7 and v8 */ + void __iomem *e_h264_lf_alpha_offset; + void __iomem *e_h264_lf_beta_offset; + void __iomem *e_h264_i_period; + void __iomem *e_h264_fmo_slice_grp_map_type; + void __iomem *e_h264_fmo_num_slice_grp_minus1; + void __iomem *e_h264_fmo_slice_grp_change_dir; + void __iomem *e_h264_fmo_slice_grp_change_rate_minus1; + void __iomem *e_h264_fmo_run_length_minus1_0; + void __iomem *e_h264_aso_slice_order_0; + void __iomem *e_h264_chroma_qp_offset; + void __iomem *e_h264_num_t_layer; + void __iomem *e_h264_hierarchical_qp_layer0; + void __iomem *e_h264_frame_packing_sei_info; + void __iomem *e_h264_nal_control;/* v7 and v8 */ + void __iomem *e_mvc_frame_qp_view1; + void __iomem *e_mvc_rc_bit_rate_view1; + void __iomem *e_mvc_rc_qbound_view1; + void __iomem *e_mvc_rc_mode_view1; + void __iomem *e_mvc_inter_view_prediction_on; + void __iomem *e_vp8_options;/* v7 and v8 */ + void __iomem *e_vp8_filter_options;/* v7 and v8 */ + void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */ + void __iomem *e_vp8_num_t_layer;/* v7 and v8 */ + void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */ + void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */ + void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */ + void __iomem *e_min_scratch_buffer_size; /* v10 */ + void __iomem *e_num_t_layer; /* v10 */ + void __iomem *e_hier_qp_layer0; /* v10 */ + void __iomem *e_hier_bit_rate_layer0; /* v10 */ + void __iomem *e_hevc_options; /* v10 */ + void __iomem *e_hevc_refresh_period; /* v10 */ + void __iomem *e_hevc_lf_beta_offset_div2; /* v10 */ + void __iomem *e_hevc_lf_tc_offset_div2; /* v10 */ + void __iomem *e_hevc_nal_control; /* v10 */ +}; + +struct s5p_mfc_hw_ops { + int (*alloc_dec_temp_buffers)(struct s5p_mfc_ctx *ctx); + void (*release_dec_desc_buffer)(struct s5p_mfc_ctx *ctx); + int (*alloc_codec_buffers)(struct s5p_mfc_ctx *ctx); + void (*release_codec_buffers)(struct s5p_mfc_ctx *ctx); + int (*alloc_instance_buffer)(struct s5p_mfc_ctx *ctx); + void (*release_instance_buffer)(struct s5p_mfc_ctx *ctx); + int (*alloc_dev_context_buffer)(struct s5p_mfc_dev *dev); + void (*release_dev_context_buffer)(struct s5p_mfc_dev *dev); + void (*dec_calc_dpb_size)(struct s5p_mfc_ctx *ctx); + void (*enc_calc_src_size)(struct s5p_mfc_ctx *ctx); + int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size); + void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr); + void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr); + void (*try_run)(struct s5p_mfc_dev *dev); + void (*clear_int_flags)(struct s5p_mfc_dev *dev); + int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev); + int (*get_dec_y_adr)(struct s5p_mfc_dev *dev); + int (*get_dspl_status)(struct s5p_mfc_dev *dev); + int (*get_dec_status)(struct s5p_mfc_dev *dev); + int (*get_dec_frame_type)(struct s5p_mfc_dev *dev); + int (*get_disp_frame_type)(struct s5p_mfc_ctx *ctx); + int (*get_consumed_stream)(struct s5p_mfc_dev *dev); + int (*get_int_reason)(struct s5p_mfc_dev *dev); + int (*get_int_err)(struct s5p_mfc_dev *dev); + int (*err_dec)(unsigned int err); + int (*get_img_width)(struct s5p_mfc_dev *dev); + int (*get_img_height)(struct s5p_mfc_dev *dev); + int (*get_dpb_count)(struct s5p_mfc_dev *dev); + int (*get_mv_count)(struct s5p_mfc_dev *dev); + int (*get_inst_no)(struct s5p_mfc_dev *dev); + int (*get_enc_strm_size)(struct s5p_mfc_dev *dev); + int (*get_enc_slice_type)(struct s5p_mfc_dev *dev); + int (*get_enc_dpb_count)(struct s5p_mfc_dev *dev); + unsigned int (*get_pic_type_top)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx); + unsigned int (*get_crop_info_v)(struct s5p_mfc_ctx *ctx); + int (*get_min_scratch_buf_size)(struct s5p_mfc_dev *dev); + int (*get_e_min_scratch_buf_size)(struct s5p_mfc_dev *dev); +}; + +void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev); +void s5p_mfc_init_regs(struct s5p_mfc_dev *dev); +int s5p_mfc_alloc_priv_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b); +void s5p_mfc_release_priv_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b); +int s5p_mfc_alloc_generic_buf(struct s5p_mfc_dev *dev, unsigned int mem_ctx, + struct s5p_mfc_priv_buf *b); +void s5p_mfc_release_generic_buf(struct s5p_mfc_dev *dev, + struct s5p_mfc_priv_buf *b); + + +#endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c new file mode 100644 index 000000000000..28a06dc343fd --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c @@ -0,0 +1,1637 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Kamil Debski, Copyright (c) 2011 Samsung Electronics + * http://www.samsung.com/ + */ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_ctrl.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_pm.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v5.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define OFFSETA(x) (((x) - dev->dma_base[BANK_L_CTX]) >> MFC_OFFSET_SHIFT) +#define OFFSETB(x) (((x) - dev->dma_base[BANK_R_CTX]) >> MFC_OFFSET_SHIFT) + +/* Allocate temporary buffers for decoding */ +static int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + int ret; + + ctx->dsc.size = buf_size->dsc; + ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->dsc); + if (ret) { + mfc_err("Failed to allocate temporary buffer\n"); + return ret; + } + + BUG_ON(ctx->dsc.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + memset(ctx->dsc.virt, 0, ctx->dsc.size); + wmb(); + return 0; +} + + +/* Release temporary buffers for decoding */ +static void s5p_mfc_release_dec_desc_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + s5p_mfc_release_priv_buf(ctx->dev, &ctx->dsc); +} + +/* Allocate codec buffers */ +static int s5p_mfc_alloc_codec_buffers_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int enc_ref_y_size = 0; + unsigned int enc_ref_c_size = 0; + unsigned int guard_width, guard_height; + int ret; + + if (ctx->type == MFCINST_DECODER) { + mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", + ctx->luma_size, ctx->chroma_size, ctx->mv_size); + mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); + } else if (ctx->type == MFCINST_ENCODER) { + enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { + enc_ref_c_size = ALIGN(ctx->img_width, + S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height >> 1, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(enc_ref_c_size, + S5P_FIMV_NV12MT_SALIGN); + } else { + guard_width = ALIGN(ctx->img_width + 16, + S5P_FIMV_NV12MT_HALIGN); + guard_height = ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(guard_width * guard_height, + S5P_FIMV_NV12MT_SALIGN); + } + mfc_debug(2, "recon luma size: %d chroma size: %d\n", + enc_ref_y_size, enc_ref_c_size); + } else { + return -EINVAL; + } + /* Codecs have different memory requirements */ + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + ctx->bank1.size = + ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + + S5P_FIMV_DEC_VERT_NB_MV_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2.size = ctx->total_dpb_count * ctx->mv_size; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + ctx->bank1.size = + ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_STX_PARSER_SIZE + + S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2.size = 0; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + ctx->bank1.size = + ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_NB_DCAC_SIZE + + 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2.size = 0; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + ctx->bank1.size = 0; + ctx->bank2.size = 0; + break; + case S5P_MFC_CODEC_H263_DEC: + ctx->bank1.size = + ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + + S5P_FIMV_DEC_UPNB_MV_SIZE + + S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + + S5P_FIMV_DEC_NB_DCAC_SIZE, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->bank2.size = 0; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->bank1.size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_COLFLG_SIZE + + S5P_FIMV_ENC_INTRAMD_SIZE + + S5P_FIMV_ENC_NBORINFO_SIZE; + ctx->bank2.size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4) + + S5P_FIMV_ENC_INTRAPRED_SIZE; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + ctx->bank1.size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_COLFLG_SIZE + + S5P_FIMV_ENC_ACDCCOEF_SIZE; + ctx->bank2.size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4); + break; + case S5P_MFC_CODEC_H263_ENC: + ctx->bank1.size = (enc_ref_y_size * 2) + + S5P_FIMV_ENC_UPMV_SIZE + + S5P_FIMV_ENC_ACDCCOEF_SIZE; + ctx->bank2.size = (enc_ref_y_size * 2) + + (enc_ref_c_size * 4); + break; + default: + break; + } + /* Allocate only if memory from bank 1 is necessary */ + if (ctx->bank1.size > 0) { + + ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->bank1); + if (ret) { + mfc_err("Failed to allocate Bank1 temporary buffer\n"); + return ret; + } + BUG_ON(ctx->bank1.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + } + /* Allocate only if memory from bank 2 is necessary */ + if (ctx->bank2.size > 0) { + ret = s5p_mfc_alloc_priv_buf(dev, BANK_R_CTX, &ctx->bank2); + if (ret) { + mfc_err("Failed to allocate Bank2 temporary buffer\n"); + s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank1); + return ret; + } + BUG_ON(ctx->bank2.dma & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); + } + return 0; +} + +/* Release buffers allocated for codec */ +static void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) +{ + s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank1); + s5p_mfc_release_priv_buf(ctx->dev, &ctx->bank2); +} + +/* Allocate memory for instance data buffer */ +static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + int ret; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + ctx->ctx.size = buf_size->h264_ctx; + else + ctx->ctx.size = buf_size->non_h264_ctx; + + ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->ctx); + if (ret) { + mfc_err("Failed to allocate instance buffer\n"); + return ret; + } + ctx->ctx.ofs = OFFSETA(ctx->ctx.dma); + + /* Zero content of the allocated memory */ + memset(ctx->ctx.virt, 0, ctx->ctx.size); + wmb(); + + /* Initialize shared memory */ + ctx->shm.size = buf_size->shm; + ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->shm); + if (ret) { + mfc_err("Failed to allocate shared memory buffer\n"); + s5p_mfc_release_priv_buf(dev, &ctx->ctx); + return ret; + } + + /* shared memory offset only keeps the offset from base (port a) */ + ctx->shm.ofs = ctx->shm.dma - dev->dma_base[BANK_L_CTX]; + BUG_ON(ctx->shm.ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + + memset(ctx->shm.virt, 0, buf_size->shm); + wmb(); + return 0; +} + +/* Release instance buffer */ +static void s5p_mfc_release_instance_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + s5p_mfc_release_priv_buf(ctx->dev, &ctx->ctx); + s5p_mfc_release_priv_buf(ctx->dev, &ctx->shm); +} + +static int s5p_mfc_alloc_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ + + return 0; +} + +static void s5p_mfc_release_dev_context_buffer_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ +} + +static void s5p_mfc_write_info_v5(struct s5p_mfc_ctx *ctx, unsigned int data, + unsigned int ofs) +{ + *(u32 *)(ctx->shm.virt + ofs) = data; + wmb(); +} + +static unsigned int s5p_mfc_read_info_v5(struct s5p_mfc_ctx *ctx, + unsigned long ofs) +{ + rmb(); + return *(u32 *)(ctx->shm.virt + ofs); +} + +static void s5p_mfc_dec_calc_dpb_size_v5(struct s5p_mfc_ctx *ctx) +{ + unsigned int guard_width, guard_height; + + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); + ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + mfc_debug(2, + "SEQ Done: Movie dimensions %dx%d, buffer dimensions: %dx%d\n", + ctx->img_width, ctx->img_height, ctx->buf_width, + ctx->buf_height); + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { + ctx->luma_size = ALIGN(ctx->buf_width * ctx->buf_height, + S5P_FIMV_DEC_BUF_ALIGN); + ctx->chroma_size = ALIGN(ctx->buf_width * + ALIGN((ctx->img_height >> 1), + S5P_FIMV_NV12MT_VALIGN), + S5P_FIMV_DEC_BUF_ALIGN); + ctx->mv_size = ALIGN(ctx->buf_width * + ALIGN((ctx->buf_height >> 2), + S5P_FIMV_NV12MT_VALIGN), + S5P_FIMV_DEC_BUF_ALIGN); + } else { + guard_width = + ALIGN(ctx->img_width + 24, S5P_FIMV_NV12MT_HALIGN); + guard_height = + ALIGN(ctx->img_height + 16, S5P_FIMV_NV12MT_VALIGN); + ctx->luma_size = ALIGN(guard_width * guard_height, + S5P_FIMV_DEC_BUF_ALIGN); + + guard_width = + ALIGN(ctx->img_width + 16, S5P_FIMV_NV12MT_HALIGN); + guard_height = + ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + ctx->chroma_size = ALIGN(guard_width * guard_height, + S5P_FIMV_DEC_BUF_ALIGN); + + ctx->mv_size = 0; + } +} + +static void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx) +{ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN); + + ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12M_LVALIGN); + ctx->chroma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12M_CVALIGN); + + ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12M_SALIGN); + ctx->chroma_size = + ALIGN(ctx->chroma_size, S5P_FIMV_NV12M_SALIGN); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) { + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN); + + ctx->luma_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + ctx->chroma_size = + ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); + + ctx->luma_size = ALIGN(ctx->luma_size, S5P_FIMV_NV12MT_SALIGN); + ctx->chroma_size = + ALIGN(ctx->chroma_size, S5P_FIMV_NV12MT_SALIGN); + } +} + +/* Set registers for decoding temporary buffers */ +static void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + + mfc_write(dev, OFFSETA(ctx->dsc.dma), S5P_FIMV_SI_CH0_DESC_ADR); + mfc_write(dev, buf_size->dsc, S5P_FIMV_SI_CH0_DESC_SIZE); +} + +/* Set registers for shared buffer */ +static void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + mfc_write(dev, ctx->shm.ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); +} + +/* Set registers for decoding stream buffer */ +static int s5p_mfc_set_dec_stream_buffer_v5(struct s5p_mfc_ctx *ctx, + int buf_addr, unsigned int start_num_byte, + unsigned int buf_size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR); + mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE); + mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE); + s5p_mfc_write_info_v5(ctx, start_num_byte, START_BYTE_NUM); + return 0; +} + +/* Set decoding frame buffer */ +static int s5p_mfc_set_dec_frame_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + unsigned int frame_size_lu, i; + unsigned int frame_size_ch, frame_size_mv; + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + size_t buf_addr1, buf_addr2; + int buf_size1, buf_size2; + + buf_addr1 = ctx->bank1.dma; + buf_size1 = ctx->bank1.size; + buf_addr2 = ctx->bank2.dma; + buf_size2 = ctx->bank2.size; + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & + ~S5P_FIMV_DPB_COUNT_MASK; + mfc_write(dev, ctx->total_dpb_count | dpb, + S5P_FIMV_SI_CH0_DPB_CONF_CTRL); + s5p_mfc_set_shared_buffer(ctx); + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_VERT_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR); + buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE; + buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + break; + case S5P_MFC_CODEC_H263_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + break; + case S5P_MFC_CODEC_VC1_DEC: + case S5P_MFC_CODEC_VC1RCV_DEC: + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); + buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; + buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR); + buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR); + buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR); + buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + break; + default: + mfc_err("Unknown codec for decoding (%x)\n", + ctx->codec_mode); + return -EINVAL; + } + frame_size_lu = ctx->luma_size; + frame_size_ch = ctx->chroma_size; + frame_size_mv = ctx->mv_size; + mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size_lu, frame_size_ch, + frame_size_mv); + for (i = 0; i < ctx->total_dpb_count; i++) { + /* Bank2 */ + mfc_debug(2, "Luma %d: %zx\n", i, + ctx->dst_bufs[i].cookie.raw.luma); + mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), + S5P_FIMV_DEC_LUMA_ADR + i * 4); + mfc_debug(2, "\tChroma %d: %zx\n", i, + ctx->dst_bufs[i].cookie.raw.chroma); + mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), + S5P_FIMV_DEC_CHROMA_ADR + i * 4); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) { + mfc_debug(2, "\tBuf2: %zx, size: %d\n", + buf_addr2, buf_size2); + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_H264_MV_ADR + i * 4); + buf_addr2 += frame_size_mv; + buf_size2 -= frame_size_mv; + } + } + mfc_debug(2, "Buf1: %zu, buf_size1: %d\n", buf_addr1, buf_size1); + mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", + buf_size1, buf_size2, ctx->total_dpb_count); + if (buf_size1 < 0 || buf_size2 < 0) { + mfc_debug(2, "Not enough memory has been allocated\n"); + return -ENOMEM; + } + s5p_mfc_write_info_v5(ctx, frame_size_lu, ALLOC_LUMA_DPB_SIZE); + s5p_mfc_write_info_v5(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC) + s5p_mfc_write_info_v5(ctx, frame_size_mv, ALLOC_MV_SIZE); + mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) + << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), + S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +/* Set registers for encoding stream buffer */ +static int s5p_mfc_set_enc_stream_buffer_v5(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR); + mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE); + return 0; +} + +static void s5p_mfc_set_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR); + mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); +} + +static void s5p_mfc_get_enc_frame_buffer_v5(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + *y_addr = dev->dma_base[BANK_R_CTX] + + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) << MFC_OFFSET_SHIFT); + *c_addr = dev->dma_base[BANK_R_CTX] + + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) << MFC_OFFSET_SHIFT); +} + +/* Set encoding ref & codec buffer */ +static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + size_t buf_addr1, buf_addr2; + size_t buf_size1, buf_size2; + unsigned int enc_ref_y_size, enc_ref_c_size; + unsigned int guard_width, guard_height; + int i; + + buf_addr1 = ctx->bank1.dma; + buf_size1 = ctx->bank1.size; + buf_addr2 = ctx->bank2.dma; + buf_size2 = ctx->bank2.size; + enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); + enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) { + enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) + * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); + } else { + guard_width = ALIGN(ctx->img_width + 16, + S5P_FIMV_NV12MT_HALIGN); + guard_height = ALIGN((ctx->img_height >> 1) + 4, + S5P_FIMV_NV12MT_VALIGN); + enc_ref_c_size = ALIGN(guard_width * guard_height, + S5P_FIMV_NV12MT_SALIGN); + } + mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", buf_size1, buf_size2); + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_COZERO_FLAG_ADR); + buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; + buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_UP_INTRA_MD_ADR); + buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE; + buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_H264_UP_INTRA_PRED_ADR); + buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE; + buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_H264_NBOR_INFO_ADR); + buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; + buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; + mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", + buf_size1, buf_size2); + break; + case S5P_MFC_CODEC_MPEG4_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_MPEG4_COZERO_FLAG_ADR); + buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; + buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_MPEG4_ACDC_COEF_ADR); + buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; + buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; + mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", + buf_size1, buf_size2); + break; + case S5P_MFC_CODEC_H263_ENC: + for (i = 0; i < 2; i++) { + mfc_write(dev, OFFSETA(buf_addr1), + S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); + buf_addr1 += enc_ref_y_size; + buf_size1 -= enc_ref_y_size; + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); + buf_addr2 += enc_ref_y_size; + buf_size2 -= enc_ref_y_size; + } + for (i = 0; i < 4; i++) { + mfc_write(dev, OFFSETB(buf_addr2), + S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); + buf_addr2 += enc_ref_c_size; + buf_size2 -= enc_ref_c_size; + } + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR); + buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; + buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; + mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); + buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; + buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; + mfc_debug(2, "buf_size1: %zu, buf_size2: %zu\n", + buf_size1, buf_size2); + break; + default: + mfc_err("Unknown codec set for encoding: %d\n", + ctx->codec_mode); + return -EINVAL; + } + return 0; +} + +static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + unsigned int reg; + unsigned int shm; + + /* width */ + mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX); + /* height */ + mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX); + /* pictype : enable, IDR period */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + reg |= (1 << 18); + reg &= ~(0xFFFF); + reg |= p->gop_size; + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON); + /* multi-slice control */ + /* multi-slice MB number or bit size */ + mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { + mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { + mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); + } else { + mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); + mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT); + } + /* cyclic intra refresh */ + mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL); + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) + mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); + else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) + mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); + /* padding control & value */ + reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); + if (p->pad) { + /** enable */ + reg |= (1UL << 31); + /** cr value */ + reg &= ~(0xFF << 16); + reg |= (p->pad_cr << 16); + /** cb value */ + reg &= ~(0xFF << 8); + reg |= (p->pad_cb << 8); + /** y value */ + reg &= ~(0xFF); + reg |= (p->pad_luma); + } else { + /** disable & all value clear */ + reg = 0; + } + mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /** frame-level rate control */ + reg &= ~(0x1 << 9); + reg |= (p->rc_frame << 9); + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* bit rate */ + if (p->rc_frame) + mfc_write(dev, p->rc_bitrate, + S5P_FIMV_ENC_RC_BIT_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE); + /* reaction coefficient */ + if (p->rc_frame) + mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA); + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* seq header ctrl */ + shm &= ~(0x1 << 3); + shm |= (p->seq_hdr_mode << 3); + /* frame skip mode */ + shm &= ~(0x3 << 1); + shm |= (p->frame_skip_mode << 1); + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + /* fixed target bit */ + s5p_mfc_write_info_v5(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); + return 0; +} + +static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; + unsigned int reg; + unsigned int shm; + + s5p_mfc_set_enc_params(ctx); + /* pictype : number of B */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* profile & level */ + reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_264->level << 8); + /* profile - 0 ~ 2 */ + reg &= ~(0x3F); + reg |= p_264->profile; + mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); + /* interlace */ + mfc_write(dev, p_264->interlace, S5P_FIMV_ENC_PIC_STRUCT); + /* height */ + if (p_264->interlace) + mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); + /* loopfilter ctrl */ + mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); + /* loopfilter alpha offset */ + if (p_264->loop_filter_alpha < 0) { + reg = 0x10; + reg |= (0xFF - p_264->loop_filter_alpha) + 1; + } else { + reg = 0x00; + reg |= (p_264->loop_filter_alpha & 0xF); + } + mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF); + /* loopfilter beta offset */ + if (p_264->loop_filter_beta < 0) { + reg = 0x10; + reg |= (0xFF - p_264->loop_filter_beta) + 1; + } else { + reg = 0x00; + reg |= (p_264->loop_filter_beta & 0xF); + } + mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF); + /* entropy coding mode */ + if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) + mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE); + /* number of ref. picture */ + reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF); + /* num of ref. pictures of P */ + reg &= ~(0x3 << 5); + reg |= (p_264->num_ref_pic_4p << 5); + /* max number of ref. pictures */ + reg &= ~(0x1F); + reg |= p_264->max_ref_pic; + mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF); + /* 8x8 transform enable */ + mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= (p->rc_mb << 8); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_264->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* frame rate */ + if (p->rc_frame && p->rc_framerate_denom) + mfc_write(dev, p->rc_framerate_num * 1000 + / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_264->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_264->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* macroblock adaptive scaling features */ + if (p->rc_mb) { + reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); + /* dark region */ + reg &= ~(0x1 << 3); + reg |= (p_264->rc_mb_dark << 3); + /* smooth region */ + reg &= ~(0x1 << 2); + reg |= (p_264->rc_mb_smooth << 2); + /* static region */ + reg &= ~(0x1 << 1); + reg |= (p_264->rc_mb_static << 1); + /* high activity region */ + reg &= ~(0x1); + reg |= p_264->rc_mb_activity; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); + } + if (!p->rc_frame && !p->rc_mb) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); + shm |= (p_264->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* AR VUI control */ + shm &= ~(0x1 << 15); + shm |= (p_264->vui_sar << 1); + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + if (p_264->vui_sar) { + /* aspect ration IDC */ + shm = s5p_mfc_read_info_v5(ctx, SAMPLE_ASPECT_RATIO_IDC); + shm &= ~(0xFF); + shm |= p_264->vui_sar_idc; + s5p_mfc_write_info_v5(ctx, shm, SAMPLE_ASPECT_RATIO_IDC); + if (p_264->vui_sar_idc == 0xFF) { + /* sample AR info */ + shm = s5p_mfc_read_info_v5(ctx, EXTENDED_SAR); + shm &= ~(0xFFFFFFFF); + shm |= p_264->vui_ext_sar_width << 16; + shm |= p_264->vui_ext_sar_height; + s5p_mfc_write_info_v5(ctx, shm, EXTENDED_SAR); + } + } + /* intra picture period for H.264 */ + shm = s5p_mfc_read_info_v5(ctx, H264_I_PERIOD); + /* control */ + shm &= ~(0x1 << 16); + shm |= (p_264->open_gop << 16); + /* value */ + if (p_264->open_gop) { + shm &= ~(0xFFFF); + shm |= p_264->open_gop_size; + } + s5p_mfc_write_info_v5(ctx, shm, H264_I_PERIOD); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p_264->cpb_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + unsigned int reg; + unsigned int shm; + unsigned int framerate; + + s5p_mfc_set_enc_params(ctx); + /* pictype : number of B */ + reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); + /* profile & level */ + reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_mpeg4->level << 8); + /* profile - 0 ~ 2 */ + reg &= ~(0x3F); + reg |= p_mpeg4->profile; + mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); + /* quarter_pixel */ + mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); + /* qp */ + if (!p->rc_frame) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6); + shm |= (p_mpeg4->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* frame rate */ + if (p->rc_frame) { + if (p->rc_framerate_denom > 0) { + framerate = p->rc_framerate_num * 1000 / + p->rc_framerate_denom; + mfc_write(dev, framerate, + S5P_FIMV_ENC_RC_FRAME_RATE); + shm = s5p_mfc_read_info_v5(ctx, RC_VOP_TIMING); + shm &= ~(0xFFFFFFFF); + shm |= (1UL << 31); + shm |= ((p->rc_framerate_num & 0x7FFF) << 16); + shm |= (p->rc_framerate_denom & 0xFFFF); + s5p_mfc_write_info_v5(ctx, shm, RC_VOP_TIMING); + } + } else { + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + } + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_mpeg4->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p->vbv_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + unsigned int reg; + unsigned int shm; + + s5p_mfc_set_enc_params(ctx); + /* qp */ + if (!p->rc_frame) { + shm = s5p_mfc_read_info_v5(ctx, P_B_FRAME_QP); + shm &= ~(0xFFF); + shm |= (p_h263->rc_p_frame_qp & 0x3F); + s5p_mfc_write_info_v5(ctx, shm, P_B_FRAME_QP); + } + /* frame rate */ + if (p->rc_frame && p->rc_framerate_denom) + mfc_write(dev, p->rc_framerate_num * 1000 + / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); + else + mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); + /* rate control config. */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); + /* frame QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_frame_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); + /* max & min value of QP */ + reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); + /* max QP */ + reg &= ~(0x3F << 8); + reg |= (p_h263->rc_max_qp << 8); + /* min QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_min_qp; + mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); + /* extended encoder ctrl */ + shm = s5p_mfc_read_info_v5(ctx, EXT_ENC_CONTROL); + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + shm &= ~(0xFFFF << 16); + shm |= (p->vbv_size << 16); + } + s5p_mfc_write_info_v5(ctx, shm, EXT_ENC_CONTROL); + return 0; +} + +/* Initialize decoding */ +static int s5p_mfc_init_decode_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_set_shared_buffer(ctx); + /* Setup loop filter, for decoding this is only valid for MPEG4 */ + if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) + mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); + else + mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); + mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) << + S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable << + S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay & + S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT), + S5P_FIMV_SI_CH0_DPB_CONF_CTRL); + mfc_write(dev, + ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) + | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int dpb; + + if (flush) + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | ( + S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); + else + dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & + ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); + mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); +} + +/* Decode a single frame */ +static int s5p_mfc_decode_one_frame_v5(struct s5p_mfc_ctx *ctx, + enum s5p_mfc_decode_arg last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF); + s5p_mfc_set_shared_buffer(ctx); + s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); + /* Issue different commands to instance basing on whether it + * is the last frame or not. */ + switch (last_frame) { + case MFC_DEC_FRAME: + mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) << + S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + break; + case MFC_DEC_LAST_FRAME: + mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) << + S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + break; + case MFC_DEC_RES_CHANGE: + mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC & + S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), + S5P_FIMV_SI_CH0_INST_ID); + break; + } + mfc_debug(2, "Decoding a usual frame\n"); + return 0; +} + +static int s5p_mfc_init_encode_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_set_enc_params_h264(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) + s5p_mfc_set_enc_params_mpeg4(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) + s5p_mfc_set_enc_params_h263(ctx); + else { + mfc_err("Unknown codec for encoding (%x)\n", + ctx->codec_mode); + return -EINVAL; + } + s5p_mfc_set_shared_buffer(ctx); + mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | + (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + return 0; +} + +/* Encode a single frame */ +static int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int cmd; + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) + mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); + else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) + mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); + s5p_mfc_set_shared_buffer(ctx); + + if (ctx->state == MFCINST_FINISHING) + cmd = S5P_FIMV_CH_LAST_FRAME; + else + cmd = S5P_FIMV_CH_FRAME_START; + mfc_write(dev, ((cmd & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) + | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); + + return 0; +} + +static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); + dev->curr_ctx = ctx->num; + s5p_mfc_decode_one_frame_v5(ctx, MFC_DEC_RES_CHANGE); +} + +static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + + if (ctx->state == MFCINST_FINISHING) { + last_frame = MFC_DEC_LAST_FRAME; + s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0); + dev->curr_ctx = ctx->num; + s5p_mfc_decode_one_frame_v5(ctx, last_frame); + return 0; + } + + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers\n"); + return -EAGAIN; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), + ctx->consumed_stream, temp_vb->b->vb2_buf.planes[0].bytesused); + dev->curr_ctx = ctx->num; + if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) { + last_frame = MFC_DEC_LAST_FRAME; + mfc_debug(2, "Setting ctx->state to FINISHING\n"); + ctx->state = MFCINST_FINISHING; + } + s5p_mfc_decode_one_frame_v5(ctx, last_frame); + return 0; +} + +static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *dst_mb; + struct s5p_mfc_buf *src_mb; + unsigned long src_y_addr, src_c_addr, dst_addr; + unsigned int dst_size; + + if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { + mfc_debug(2, "no src buffers\n"); + return -EAGAIN; + } + if (list_empty(&ctx->dst_queue)) { + mfc_debug(2, "no dst buffers\n"); + return -EAGAIN; + } + if (list_empty(&ctx->src_queue)) { + /* send null frame */ + s5p_mfc_set_enc_frame_buffer_v5(ctx, dev->dma_base[BANK_R_CTX], + dev->dma_base[BANK_R_CTX]); + src_mb = NULL; + } else { + src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, + list); + src_mb->flags |= MFC_BUF_FLAG_USED; + if (src_mb->b->vb2_buf.planes[0].bytesused == 0) { + /* send null frame */ + s5p_mfc_set_enc_frame_buffer_v5(ctx, + dev->dma_base[BANK_R_CTX], + dev->dma_base[BANK_R_CTX]); + ctx->state = MFCINST_FINISHING; + } else { + src_y_addr = vb2_dma_contig_plane_dma_addr( + &src_mb->b->vb2_buf, 0); + src_c_addr = vb2_dma_contig_plane_dma_addr( + &src_mb->b->vb2_buf, 1); + s5p_mfc_set_enc_frame_buffer_v5(ctx, src_y_addr, + src_c_addr); + if (src_mb->flags & MFC_BUF_FLAG_EOS) + ctx->state = MFCINST_FINISHING; + } + } + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_mb->flags |= MFC_BUF_FLAG_USED; + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); + dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); + s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); + dev->curr_ctx = ctx->num; + mfc_debug(2, "encoding buffer with index=%d state=%d\n", + src_mb ? src_mb->b->vb2_buf.index : -1, ctx->state); + s5p_mfc_encode_one_frame_v5(ctx); + return 0; +} + +static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + + /* Initializing decoding - parsing header */ + mfc_debug(2, "Preparing to init decoding\n"); + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + s5p_mfc_set_dec_desc_buffer(ctx); + mfc_debug(2, "Header size: %d\n", + temp_vb->b->vb2_buf.planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), + 0, temp_vb->b->vb2_buf.planes[0].bytesused); + dev->curr_ctx = ctx->num; + s5p_mfc_init_decode_v5(ctx); +} + +static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *dst_mb; + unsigned long dst_addr; + unsigned int dst_size; + + s5p_mfc_set_enc_ref_buffer_v5(ctx); + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); + dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); + s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size); + dev->curr_ctx = ctx->num; + s5p_mfc_init_encode_v5(ctx); +} + +static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + int ret; + + /* + * Header was parsed now starting processing + * First set the output frame buffers + */ + if (ctx->capture_state != QUEUE_BUFS_MMAPED) { + mfc_err("It seems that not all destination buffers were mmapped\nMFC requires that all destination are mmapped before starting processing\n"); + return -EAGAIN; + } + if (list_empty(&ctx->src_queue)) { + mfc_err("Header has been deallocated in the middle of initialization\n"); + return -EIO; + } + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + mfc_debug(2, "Header size: %d\n", + temp_vb->b->vb2_buf.planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v5(ctx, + vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), + 0, temp_vb->b->vb2_buf.planes[0].bytesused); + dev->curr_ctx = ctx->num; + ret = s5p_mfc_set_dec_frame_buffer_v5(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +/* Try running an operation on hardware */ +static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_ctx *ctx; + int new_ctx; + unsigned int ret = 0; + + if (test_bit(0, &dev->enter_suspend)) { + mfc_debug(1, "Entering suspend so do not schedule any jobs\n"); + return; + } + /* Check whether hardware is not running */ + if (test_and_set_bit(0, &dev->hw_lock) != 0) { + /* This is perfectly ok, the scheduled ctx should wait */ + mfc_debug(1, "Couldn't lock HW\n"); + return; + } + /* Choose the context to run */ + new_ctx = s5p_mfc_get_new_ctx(dev); + if (new_ctx < 0) { + /* No contexts to run */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) { + mfc_err("Failed to unlock hardware\n"); + return; + } + mfc_debug(1, "No ctx is scheduled to be run\n"); + return; + } + ctx = dev->ctx[new_ctx]; + /* Got context to run in ctx */ + /* + * Last frame has already been sent to MFC. + * Now obtaining frames from MFC buffer + */ + s5p_mfc_clock_on(); + s5p_mfc_clean_ctx_int_flags(ctx); + + if (ctx->type == MFCINST_DECODER) { + s5p_mfc_set_dec_desc_buffer(ctx); + switch (ctx->state) { + case MFCINST_FINISHING: + s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME); + break; + case MFCINST_RUNNING: + ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); + break; + case MFCINST_INIT: + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_dec(ctx); + break; + case MFCINST_HEAD_PARSED: + ret = s5p_mfc_run_init_dec_buffers(ctx); + mfc_debug(1, "head parsed\n"); + break; + case MFCINST_RES_CHANGE_INIT: + s5p_mfc_run_res_change(ctx); + break; + case MFCINST_RES_CHANGE_FLUSH: + s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); + break; + case MFCINST_RES_CHANGE_END: + mfc_debug(2, "Finished remaining frames after resolution change\n"); + ctx->capture_state = QUEUE_FREE; + mfc_debug(2, "Will re-init the codec\n"); + s5p_mfc_run_init_dec(ctx); + break; + default: + ret = -EAGAIN; + } + } else if (ctx->type == MFCINST_ENCODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + case MFCINST_RUNNING: + ret = s5p_mfc_run_enc_frame(ctx); + break; + case MFCINST_INIT: + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_enc(ctx); + break; + default: + ret = -EAGAIN; + } + } else { + mfc_err("Invalid context type: %d\n", ctx->type); + ret = -EAGAIN; + } + + if (ret) { + /* Free hardware lock */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) + mfc_err("Failed to unlock hardware\n"); + + /* This is indeed important, as no operation has been + * scheduled, reduce the clock count as no one will + * ever do this, because no interrupt related to this try_run + * will ever come from hardware. */ + s5p_mfc_clock_off(); + } +} + +static void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev) +{ + mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); + mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); + mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID); +} + +static int s5p_mfc_get_dspl_y_adr_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DISPLAY_Y_ADR) << MFC_OFFSET_SHIFT; +} + +static int s5p_mfc_get_dec_y_adr_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DECODE_Y_ADR) << MFC_OFFSET_SHIFT; +} + +static int s5p_mfc_get_dspl_status_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DISPLAY_STATUS); +} + +static int s5p_mfc_get_dec_status_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_DECODE_STATUS); +} + +static int s5p_mfc_get_dec_frame_type_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_DECODE_FRAME_TYPE) & + S5P_FIMV_DECODE_FRAME_MASK; +} + +static int s5p_mfc_get_disp_frame_type_v5(struct s5p_mfc_ctx *ctx) +{ + return (s5p_mfc_read_info_v5(ctx, DISP_PIC_FRAME_TYPE) >> + S5P_FIMV_SHARED_DISP_FRAME_TYPE_SHIFT) & + S5P_FIMV_DECODE_FRAME_MASK; +} + +static int s5p_mfc_get_consumed_stream_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_CONSUMED_BYTES); +} + +static int s5p_mfc_get_int_reason_v5(struct s5p_mfc_dev *dev) +{ + int reason; + reason = mfc_read(dev, S5P_FIMV_RISC2HOST_CMD) & + S5P_FIMV_RISC2HOST_CMD_MASK; + switch (reason) { + case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: + reason = S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET; + break; + case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: + reason = S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET; + break; + case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: + reason = S5P_MFC_R2H_CMD_SEQ_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: + reason = S5P_MFC_R2H_CMD_FRAME_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: + reason = S5P_MFC_R2H_CMD_SLICE_DONE_RET; + break; + case S5P_FIMV_R2H_CMD_SYS_INIT_RET: + reason = S5P_MFC_R2H_CMD_SYS_INIT_RET; + break; + case S5P_FIMV_R2H_CMD_FW_STATUS_RET: + reason = S5P_MFC_R2H_CMD_FW_STATUS_RET; + break; + case S5P_FIMV_R2H_CMD_SLEEP_RET: + reason = S5P_MFC_R2H_CMD_SLEEP_RET; + break; + case S5P_FIMV_R2H_CMD_WAKEUP_RET: + reason = S5P_MFC_R2H_CMD_WAKEUP_RET; + break; + case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: + reason = S5P_MFC_R2H_CMD_INIT_BUFFERS_RET; + break; + case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET: + reason = S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET; + break; + case S5P_FIMV_R2H_CMD_ERR_RET: + reason = S5P_MFC_R2H_CMD_ERR_RET; + break; + default: + reason = S5P_MFC_R2H_CMD_EMPTY; + } + return reason; +} + +static int s5p_mfc_get_int_err_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG2); +} + +static int s5p_mfc_err_dec_v5(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT; +} + +static int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_HRESOL); +} + +static int s5p_mfc_get_img_height_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_VRESOL); +} + +static int s5p_mfc_get_dpb_count_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_SI_BUF_NUMBER); +} + +static int s5p_mfc_get_mv_count_v5(struct s5p_mfc_dev *dev) +{ + /* NOP */ + return -1; +} + +static int s5p_mfc_get_inst_no_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_RISC2HOST_ARG1); +} + +static int s5p_mfc_get_enc_strm_size_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_STRM_SIZE); +} + +static int s5p_mfc_get_enc_slice_type_v5(struct s5p_mfc_dev *dev) +{ + return mfc_read(dev, S5P_FIMV_ENC_SI_SLICE_TYPE); +} + +static int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev) +{ + return -1; +} + +static unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP); +} + +static unsigned int s5p_mfc_get_pic_type_bot_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT); +} + +static unsigned int s5p_mfc_get_crop_info_h_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, CROP_INFO_H); +} + +static unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v5(ctx, CROP_INFO_V); +} + +/* Initialize opr function pointers for MFC v5 */ +static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { + .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v5, + .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v5, + .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v5, + .release_codec_buffers = s5p_mfc_release_codec_buffers_v5, + .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v5, + .release_instance_buffer = s5p_mfc_release_instance_buffer_v5, + .alloc_dev_context_buffer = s5p_mfc_alloc_dev_context_buffer_v5, + .release_dev_context_buffer = s5p_mfc_release_dev_context_buffer_v5, + .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v5, + .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v5, + .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v5, + .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v5, + .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v5, + .try_run = s5p_mfc_try_run_v5, + .clear_int_flags = s5p_mfc_clear_int_flags_v5, + .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v5, + .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v5, + .get_dspl_status = s5p_mfc_get_dspl_status_v5, + .get_dec_status = s5p_mfc_get_dec_status_v5, + .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v5, + .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v5, + .get_consumed_stream = s5p_mfc_get_consumed_stream_v5, + .get_int_reason = s5p_mfc_get_int_reason_v5, + .get_int_err = s5p_mfc_get_int_err_v5, + .err_dec = s5p_mfc_err_dec_v5, + .get_img_width = s5p_mfc_get_img_width_v5, + .get_img_height = s5p_mfc_get_img_height_v5, + .get_dpb_count = s5p_mfc_get_dpb_count_v5, + .get_mv_count = s5p_mfc_get_mv_count_v5, + .get_inst_no = s5p_mfc_get_inst_no_v5, + .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v5, + .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v5, + .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v5, + .get_pic_type_top = s5p_mfc_get_pic_type_top_v5, + .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v5, + .get_crop_info_h = s5p_mfc_get_crop_info_h_v5, + .get_crop_info_v = s5p_mfc_get_crop_info_v_v5, +}; + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void) +{ + return &s5p_mfc_ops_v5; +} diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h new file mode 100644 index 000000000000..b53d376ead60 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/platform/samsung/mfc5/s5p_mfc_opr_v5.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Kamil Debski, Copyright (C) 2011 Samsung Electronics + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_OPR_V5_H_ +#define S5P_MFC_OPR_V5_H_ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_opr.h" + +enum MFC_SHM_OFS { + EXTENEDED_DECODE_STATUS = 0x00, /* D */ + SET_FRAME_TAG = 0x04, /* D */ + GET_FRAME_TAG_TOP = 0x08, /* D */ + GET_FRAME_TAG_BOT = 0x0C, /* D */ + PIC_TIME_TOP = 0x10, /* D */ + PIC_TIME_BOT = 0x14, /* D */ + START_BYTE_NUM = 0x18, /* D */ + + CROP_INFO_H = 0x20, /* D */ + CROP_INFO_V = 0x24, /* D */ + EXT_ENC_CONTROL = 0x28, /* E */ + ENC_PARAM_CHANGE = 0x2C, /* E */ + RC_VOP_TIMING = 0x30, /* E, MPEG4 */ + HEC_PERIOD = 0x34, /* E, MPEG4 */ + METADATA_ENABLE = 0x38, /* C */ + METADATA_STATUS = 0x3C, /* C */ + METADATA_DISPLAY_INDEX = 0x40, /* C */ + EXT_METADATA_START_ADDR = 0x44, /* C */ + PUT_EXTRADATA = 0x48, /* C */ + EXTRADATA_ADDR = 0x4C, /* C */ + + ALLOC_LUMA_DPB_SIZE = 0x64, /* D */ + ALLOC_CHROMA_DPB_SIZE = 0x68, /* D */ + ALLOC_MV_SIZE = 0x6C, /* D */ + P_B_FRAME_QP = 0x70, /* E */ + SAMPLE_ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on + ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ + EXTENDED_SAR = 0x78, /* E, H.264, depned on + ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ + DISP_PIC_PROFILE = 0x7C, /* D */ + FLUSH_CMD_TYPE = 0x80, /* C */ + FLUSH_CMD_INBUF1 = 0x84, /* C */ + FLUSH_CMD_INBUF2 = 0x88, /* C */ + FLUSH_CMD_OUTBUF = 0x8C, /* E */ + NEW_RC_BIT_RATE = 0x90, /* E, format as RC_BIT_RATE(0xC5A8) + depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */ + NEW_RC_FRAME_RATE = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0) + depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */ + NEW_I_PERIOD = 0x98, /* E, format as I_FRM_CTRL(0xC504) + depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */ + H264_I_PERIOD = 0x9C, /* E, H.264, open GOP */ + RC_CONTROL_CONFIG = 0xA0, /* E */ + BATCH_INPUT_ADDR = 0xA4, /* E */ + BATCH_OUTPUT_ADDR = 0xA8, /* E */ + BATCH_OUTPUT_SIZE = 0xAC, /* E */ + MIN_LUMA_DPB_SIZE = 0xB0, /* D */ + DEVICE_FORMAT_ID = 0xB4, /* C */ + H264_POC_TYPE = 0xB8, /* D */ + MIN_CHROMA_DPB_SIZE = 0xBC, /* D */ + DISP_PIC_FRAME_TYPE = 0xC0, /* D */ + FREE_LUMA_DPB = 0xC4, /* D, VC1 MPEG4 */ + ASPECT_RATIO_INFO = 0xC8, /* D, MPEG4 */ + EXTENDED_PAR = 0xCC, /* D, MPEG4 */ + DBG_HISTORY_INPUT0 = 0xD0, /* C */ + DBG_HISTORY_INPUT1 = 0xD4, /* C */ + DBG_HISTORY_OUTPUT = 0xD8, /* C */ + HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */ + FRAME_PACK_SEI_ENABLE = 0x168, /* C */ + FRAME_PACK_SEI_AVAIL = 0x16c, /* D */ + FRAME_PACK_SEI_INFO = 0x17c, /* E */ +}; + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void); +#endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c new file mode 100644 index 000000000000..8227004f6746 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c @@ -0,0 +1,2534 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c + * + * Samsung MFC (Multi Function Codec - FIMV) driver + * This file contains hw related functions. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "s5p_mfc_common.h" +#include "s5p_mfc_cmd.h" +#include "s5p_mfc_intr.h" +#include "s5p_mfc_pm.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_opr_v6.h" + +/* #define S5P_MFC_DEBUG_REGWRITE */ +#ifdef S5P_MFC_DEBUG_REGWRITE +#undef writel +#define writel(v, r) \ + do { \ + pr_err("MFCWRITE(%p): %08x\n", r, (unsigned int)v); \ + __raw_writel(v, r); \ + } while (0) +#endif /* S5P_MFC_DEBUG_REGWRITE */ + +#define IS_MFCV6_V2(dev) (!IS_MFCV7_PLUS(dev) && dev->fw_ver == MFC_FW_V2) + +/* Allocate temporary buffers for decoding */ +static int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ + + return 0; +} + +/* Release temporary buffers for decoding */ +static void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + /* NOP */ +} + +/* Allocate codec buffers */ +static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + unsigned int mb_width, mb_height; + unsigned int lcu_width = 0, lcu_height = 0; + int ret; + + mb_width = MB_WIDTH(ctx->img_width); + mb_height = MB_HEIGHT(ctx->img_height); + + if (ctx->type == MFCINST_DECODER) { + mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", + ctx->luma_size, ctx->chroma_size, ctx->mv_size); + mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); + } else if (ctx->type == MFCINST_ENCODER) { + if (IS_MFCV10(dev)) { + ctx->tmv_buffer_size = 0; + } else if (IS_MFCV8_PLUS(dev)) + ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * + ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V8(mb_width, mb_height), + S5P_FIMV_TMV_BUFFER_ALIGN_V6); + else + ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * + ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), + S5P_FIMV_TMV_BUFFER_ALIGN_V6); + if (IS_MFCV10(dev)) { + lcu_width = S5P_MFC_LCU_WIDTH(ctx->img_width); + lcu_height = S5P_MFC_LCU_HEIGHT(ctx->img_height); + if (ctx->codec_mode != S5P_FIMV_CODEC_HEVC_ENC) { + ctx->luma_dpb_size = + ALIGN((mb_width * 16), 64) + * ALIGN((mb_height * 16), 32) + + 64; + ctx->chroma_dpb_size = + ALIGN((mb_width * 16), 64) + * (mb_height * 8) + + 64; + } else { + ctx->luma_dpb_size = + ALIGN((lcu_width * 32), 64) + * ALIGN((lcu_height * 32), 32) + + 64; + ctx->chroma_dpb_size = + ALIGN((lcu_width * 32), 64) + * (lcu_height * 16) + + 64; + } + } else { + ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_LUMA_MB_TO_PIXEL_V6, + S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); + ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * + S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, + S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); + } + if (IS_MFCV8_PLUS(dev)) + ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V8( + ctx->img_width, ctx->img_height, + mb_width, mb_height), + S5P_FIMV_ME_BUFFER_ALIGN_V6); + else + ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6( + ctx->img_width, ctx->img_height, + mb_width, mb_height), + S5P_FIMV_ME_BUFFER_ALIGN_V6); + + mfc_debug(2, "recon luma size: %zu chroma size: %zu\n", + ctx->luma_dpb_size, ctx->chroma_dpb_size); + } else { + return -EINVAL; + } + + /* Codecs have different memory requirements */ + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_MVC_DEC: + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV8_PLUS(dev)) + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8( + mb_width, + mb_height); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1.size = + ctx->scratch_buf_size + + (ctx->mv_count * ctx->mv_size); + break; + case S5P_MFC_CODEC_MPEG4_DEC: + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV7_PLUS(dev)) { + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7( + mb_width, + mb_height); + } else { + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6( + mb_width, + mb_height); + } + + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1.size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( + mb_width, + mb_height); + + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1.size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_MPEG2_DEC: + ctx->bank1.size = 0; + ctx->bank2.size = 0; + break; + case S5P_MFC_CODEC_H263_DEC: + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1.size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_VP8_DEC: + if (IS_MFCV10(dev)) + mfc_debug(2, "Use min scratch buffer size\n"); + else if (IS_MFCV8_PLUS(dev)) + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8( + mb_width, + mb_height); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1.size = ctx->scratch_buf_size; + break; + case S5P_MFC_CODEC_HEVC_DEC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->bank1.size = + ctx->scratch_buf_size + + (ctx->mv_count * ctx->mv_size); + break; + case S5P_MFC_CODEC_VP9_DEC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->bank1.size = + ctx->scratch_buf_size + + DEC_VP9_STATIC_BUFFER_SIZE; + break; + case S5P_MFC_CODEC_H264_ENC: + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_H264_ME_SIZE(mb_width, mb_height), 16); + } else if (IS_MFCV8_PLUS(dev)) + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8( + mb_width, + mb_height); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1.size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->pb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2.size = 0; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_H263_ENC: + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width, + mb_height), 16); + } else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1.size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->pb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2.size = 0; + break; + case S5P_MFC_CODEC_VP8_ENC: + if (IS_MFCV10(dev)) { + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height), + 16); + } else if (IS_MFCV8_PLUS(dev)) + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8( + mb_width, + mb_height); + else + ctx->scratch_buf_size = + S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V7( + mb_width, + mb_height); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, + S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); + ctx->bank1.size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->pb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2.size = 0; + break; + case S5P_MFC_CODEC_HEVC_ENC: + mfc_debug(2, "Use min scratch buffer size\n"); + ctx->me_buffer_size = + ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), 16); + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, 256); + ctx->bank1.size = + ctx->scratch_buf_size + ctx->tmv_buffer_size + + (ctx->pb_count * (ctx->luma_dpb_size + + ctx->chroma_dpb_size + ctx->me_buffer_size)); + ctx->bank2.size = 0; + break; + default: + break; + } + + /* Allocate only if memory from bank 1 is necessary */ + if (ctx->bank1.size > 0) { + ret = s5p_mfc_alloc_generic_buf(dev, BANK_L_CTX, &ctx->bank1); + if (ret) { + mfc_err("Failed to allocate Bank1 memory\n"); + return ret; + } + BUG_ON(ctx->bank1.dma & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); + } + return 0; +} + +/* Release buffers allocated for codec */ +static void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) +{ + s5p_mfc_release_generic_buf(ctx->dev, &ctx->bank1); +} + +/* Allocate memory for instance data buffer */ +static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + int ret; + + mfc_debug_enter(); + + switch (ctx->codec_mode) { + case S5P_MFC_CODEC_H264_DEC: + case S5P_MFC_CODEC_H264_MVC_DEC: + case S5P_MFC_CODEC_HEVC_DEC: + ctx->ctx.size = buf_size->h264_dec_ctx; + break; + case S5P_MFC_CODEC_MPEG4_DEC: + case S5P_MFC_CODEC_H263_DEC: + case S5P_MFC_CODEC_VC1RCV_DEC: + case S5P_MFC_CODEC_VC1_DEC: + case S5P_MFC_CODEC_MPEG2_DEC: + case S5P_MFC_CODEC_VP8_DEC: + case S5P_MFC_CODEC_VP9_DEC: + ctx->ctx.size = buf_size->other_dec_ctx; + break; + case S5P_MFC_CODEC_H264_ENC: + ctx->ctx.size = buf_size->h264_enc_ctx; + break; + case S5P_MFC_CODEC_HEVC_ENC: + ctx->ctx.size = buf_size->hevc_enc_ctx; + break; + case S5P_MFC_CODEC_MPEG4_ENC: + case S5P_MFC_CODEC_H263_ENC: + case S5P_MFC_CODEC_VP8_ENC: + ctx->ctx.size = buf_size->other_enc_ctx; + break; + default: + ctx->ctx.size = 0; + mfc_err("Codec type(%d) should be checked!\n", ctx->codec_mode); + break; + } + + ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &ctx->ctx); + if (ret) { + mfc_err("Failed to allocate instance buffer\n"); + return ret; + } + + memset(ctx->ctx.virt, 0, ctx->ctx.size); + wmb(); + + mfc_debug_leave(); + + return 0; +} + +/* Release instance buffer */ +static void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + s5p_mfc_release_priv_buf(ctx->dev, &ctx->ctx); +} + +/* Allocate context buffers for SYS_INIT */ +static int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + int ret; + + mfc_debug_enter(); + + dev->ctx_buf.size = buf_size->dev_ctx; + ret = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &dev->ctx_buf); + if (ret) { + mfc_err("Failed to allocate device context buffer\n"); + return ret; + } + + memset(dev->ctx_buf.virt, 0, buf_size->dev_ctx); + wmb(); + + mfc_debug_leave(); + + return 0; +} + +/* Release context buffers for SYS_INIT */ +static void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) +{ + s5p_mfc_release_priv_buf(dev, &dev->ctx_buf); +} + +static int calc_plane(int width, int height) +{ + int mbX, mbY; + + mbX = DIV_ROUND_UP(width, S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); + mbY = DIV_ROUND_UP(height, S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6); + + if (width * height < S5P_FIMV_MAX_FRAME_SIZE_V6) + mbY = (mbY + 1) / 2 * 2; + + return (mbX * S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6) * + (mbY * S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); +} + +static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); + ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); + mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n" + "buffer dimensions: %dx%d\n", ctx->img_width, + ctx->img_height, ctx->buf_width, ctx->buf_height); + + ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height); + ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1)); + if (IS_MFCV8_PLUS(ctx->dev)) { + /* MFCv8 needs additional 64 bytes for luma,chroma dpb*/ + ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; + ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8; + } + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { + if (IS_MFCV10(dev)) { + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V10(ctx->img_width, + ctx->img_height); + } else { + ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, + ctx->img_height); + } + } else if (ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { + ctx->mv_size = s5p_mfc_dec_hevc_mv_size(ctx->img_width, + ctx->img_height); + ctx->mv_size = ALIGN(ctx->mv_size, 32); + } else { + ctx->mv_size = 0; + } +} + +static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx) +{ + unsigned int mb_width, mb_height; + + mb_width = MB_WIDTH(ctx->img_width); + mb_height = MB_HEIGHT(ctx->img_height); + + ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6); + ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256); + ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256); + + /* MFCv7 needs pad bytes for Luma and Chroma */ + if (IS_MFCV7_PLUS(ctx->dev)) { + ctx->luma_size += MFC_LUMA_PAD_BYTES_V7; + ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7; + } +} + +/* Set registers for decoding stream buffer */ +static int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, + int buf_addr, unsigned int start_num_byte, + unsigned int strm_size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; + + mfc_debug_enter(); + mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n" + "buf_size: 0x%08x (%d)\n", + ctx->inst_no, buf_addr, strm_size, strm_size); + writel(strm_size, mfc_regs->d_stream_data_size); + writel(buf_addr, mfc_regs->d_cpb_buffer_addr); + writel(buf_size->cpb, mfc_regs->d_cpb_buffer_size); + writel(start_num_byte, mfc_regs->d_cpb_buffer_offset); + + mfc_debug_leave(); + return 0; +} + +/* Set decoding frame buffer */ +static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + unsigned int frame_size, i; + unsigned int frame_size_ch, frame_size_mv; + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + size_t buf_addr1; + int buf_size1; + int align_gap; + + buf_addr1 = ctx->bank1.dma; + buf_size1 = ctx->bank1.size; + + mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); + mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count); + mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay); + + writel(ctx->total_dpb_count, mfc_regs->d_num_dpb); + writel(ctx->luma_size, mfc_regs->d_first_plane_dpb_size); + writel(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size); + + writel(buf_addr1, mfc_regs->d_scratch_buffer_addr); + writel(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size); + + if (IS_MFCV8_PLUS(dev)) { + writel(ctx->img_width, + mfc_regs->d_first_plane_dpb_stride_size); + writel(ctx->img_width, + mfc_regs->d_second_plane_dpb_stride_size); + } + + buf_addr1 += ctx->scratch_buf_size; + buf_size1 -= ctx->scratch_buf_size; + + if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC || + ctx->codec_mode == S5P_FIMV_CODEC_HEVC_DEC) { + writel(ctx->mv_size, mfc_regs->d_mv_buffer_size); + writel(ctx->mv_count, mfc_regs->d_num_mv); + } + + frame_size = ctx->luma_size; + frame_size_ch = ctx->chroma_size; + frame_size_mv = ctx->mv_size; + mfc_debug(2, "Frame size: %d ch: %d mv: %d\n", + frame_size, frame_size_ch, frame_size_mv); + + for (i = 0; i < ctx->total_dpb_count; i++) { + /* Bank2 */ + mfc_debug(2, "Luma %d: %zx\n", i, + ctx->dst_bufs[i].cookie.raw.luma); + writel(ctx->dst_bufs[i].cookie.raw.luma, + mfc_regs->d_first_plane_dpb + i * 4); + mfc_debug(2, "\tChroma %d: %zx\n", i, + ctx->dst_bufs[i].cookie.raw.chroma); + writel(ctx->dst_bufs[i].cookie.raw.chroma, + mfc_regs->d_second_plane_dpb + i * 4); + } + if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || + ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC || + ctx->codec_mode == S5P_MFC_CODEC_HEVC_DEC) { + for (i = 0; i < ctx->mv_count; i++) { + /* To test alignment */ + align_gap = buf_addr1; + buf_addr1 = ALIGN(buf_addr1, 16); + align_gap = buf_addr1 - align_gap; + buf_size1 -= align_gap; + + mfc_debug(2, "\tBuf1: %zx, size: %d\n", + buf_addr1, buf_size1); + writel(buf_addr1, mfc_regs->d_mv_buffer + i * 4); + buf_addr1 += frame_size_mv; + buf_size1 -= frame_size_mv; + } + } + if (ctx->codec_mode == S5P_FIMV_CODEC_VP9_DEC) { + writel(buf_addr1, mfc_regs->d_static_buffer_addr); + writel(DEC_VP9_STATIC_BUFFER_SIZE, + mfc_regs->d_static_buffer_size); + buf_addr1 += DEC_VP9_STATIC_BUFFER_SIZE; + buf_size1 -= DEC_VP9_STATIC_BUFFER_SIZE; + } + + mfc_debug(2, "Buf1: %zx, buf_size1: %d (frames %d)\n", + buf_addr1, buf_size1, ctx->total_dpb_count); + if (buf_size1 < 0) { + mfc_debug(2, "Not enough memory has been allocated.\n"); + return -ENOMEM; + } + + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_INIT_BUFS_V6, NULL); + + mfc_debug(2, "After setting buffers.\n"); + return 0; +} + +/* Set registers for encoding stream buffer */ +static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long addr, unsigned int size) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + + writel(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */ + writel(size, mfc_regs->e_stream_buffer_size); + + mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%x\n", + addr, size); + + return 0; +} + +static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long y_addr, unsigned long c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + + writel(y_addr, mfc_regs->e_source_first_plane_addr); + writel(c_addr, mfc_regs->e_source_second_plane_addr); + + mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr); + mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr); +} + +static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, + unsigned long *y_addr, unsigned long *c_addr) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + unsigned long enc_recon_y_addr, enc_recon_c_addr; + + *y_addr = readl(mfc_regs->e_encoded_source_first_plane_addr); + *c_addr = readl(mfc_regs->e_encoded_source_second_plane_addr); + + enc_recon_y_addr = readl(mfc_regs->e_recon_luma_dpb_addr); + enc_recon_c_addr = readl(mfc_regs->e_recon_chroma_dpb_addr); + + mfc_debug(2, "recon y addr: 0x%08lx y_addr: 0x%08lx\n", enc_recon_y_addr, *y_addr); + mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr); +} + +/* Set encoding ref & codec buffer */ +static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + size_t buf_addr1; + int i, buf_size1; + + mfc_debug_enter(); + + buf_addr1 = ctx->bank1.dma; + buf_size1 = ctx->bank1.size; + + mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); + + if (IS_MFCV10(dev)) { + /* start address of per buffer is aligned */ + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + buf_size1 -= ctx->luma_dpb_size; + } + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + buf_size1 -= ctx->chroma_dpb_size; + } + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= ctx->me_buffer_size; + } + } else { + for (i = 0; i < ctx->pb_count; i++) { + writel(buf_addr1, mfc_regs->e_luma_dpb + (4 * i)); + buf_addr1 += ctx->luma_dpb_size; + writel(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i)); + buf_addr1 += ctx->chroma_dpb_size; + writel(buf_addr1, mfc_regs->e_me_buffer + (4 * i)); + buf_addr1 += ctx->me_buffer_size; + buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + + ctx->me_buffer_size); + } + } + + writel(buf_addr1, mfc_regs->e_scratch_buffer_addr); + writel(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size); + buf_addr1 += ctx->scratch_buf_size; + buf_size1 -= ctx->scratch_buf_size; + + writel(buf_addr1, mfc_regs->e_tmv_buffer0); + buf_addr1 += ctx->tmv_buffer_size >> 1; + writel(buf_addr1, mfc_regs->e_tmv_buffer1); + buf_addr1 += ctx->tmv_buffer_size >> 1; + buf_size1 -= ctx->tmv_buffer_size; + + mfc_debug(2, "Buf1: %zu, buf_size1: %d (ref frames %d)\n", + buf_addr1, buf_size1, ctx->pb_count); + if (buf_size1 < 0) { + mfc_debug(2, "Not enough memory has been allocated.\n"); + return -ENOMEM; + } + + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_INIT_BUFS_V6, NULL); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + + /* multi-slice control */ + /* multi-slice MB number or bit size */ + writel(ctx->slice_mode, mfc_regs->e_mslice_mode); + if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { + writel(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb); + } else if (ctx->slice_mode == + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { + writel(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits); + } else { + writel(0x0, mfc_regs->e_mslice_size_mb); + writel(0x0, mfc_regs->e_mslice_size_bits); + } + + return 0; +} + +static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + unsigned int reg = 0; + + mfc_debug_enter(); + + /* width */ + writel(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */ + /* height */ + writel(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */ + + /* cropped width */ + writel(ctx->img_width, mfc_regs->e_cropped_frame_width); + /* cropped height */ + writel(ctx->img_height, mfc_regs->e_cropped_frame_height); + /* cropped offset */ + writel(0x0, mfc_regs->e_frame_crop_offset); + + /* pictype : IDR period */ + reg = 0; + reg |= p->gop_size & 0xFFFF; + writel(reg, mfc_regs->e_gop_config); + + /* multi-slice control */ + /* multi-slice MB number or bit size */ + ctx->slice_mode = p->slice_mode; + reg = 0; + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { + reg |= (0x1 << 3); + writel(reg, mfc_regs->e_enc_options); + ctx->slice_size.mb = p->slice_mb; + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { + reg |= (0x1 << 3); + writel(reg, mfc_regs->e_enc_options); + ctx->slice_size.bits = p->slice_bit; + } else { + reg &= ~(0x1 << 3); + writel(reg, mfc_regs->e_enc_options); + } + + s5p_mfc_set_slice_mode(ctx); + + /* cyclic intra refresh */ + writel(p->intra_refresh_mb, mfc_regs->e_ir_size); + reg = readl(mfc_regs->e_enc_options); + if (p->intra_refresh_mb == 0) + reg &= ~(0x1 << 4); + else + reg |= (0x1 << 4); + writel(reg, mfc_regs->e_enc_options); + + /* 'NON_REFERENCE_STORE_ENABLE' for debugging */ + reg = readl(mfc_regs->e_enc_options); + reg &= ~(0x1 << 9); + writel(reg, mfc_regs->e_enc_options); + + /* memory structure cur. frame */ + if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { + /* 0: Linear, 1: 2D tiled*/ + reg = readl(mfc_regs->e_enc_options); + reg &= ~(0x1 << 7); + writel(reg, mfc_regs->e_enc_options); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + writel(0x0, mfc_regs->pixel_format); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) { + /* 0: Linear, 1: 2D tiled*/ + reg = readl(mfc_regs->e_enc_options); + reg &= ~(0x1 << 7); + writel(reg, mfc_regs->e_enc_options); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + writel(0x1, mfc_regs->pixel_format); + } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) { + /* 0: Linear, 1: 2D tiled*/ + reg = readl(mfc_regs->e_enc_options); + reg |= (0x1 << 7); + writel(reg, mfc_regs->e_enc_options); + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + writel(0x0, mfc_regs->pixel_format); + } + + /* memory structure recon. frame */ + /* 0: Linear, 1: 2D tiled */ + reg = readl(mfc_regs->e_enc_options); + reg |= (0x1 << 8); + writel(reg, mfc_regs->e_enc_options); + + /* padding control & value */ + writel(0x0, mfc_regs->e_padding_ctrl); + if (p->pad) { + reg = 0; + /** enable */ + reg |= (1UL << 31); + /** cr value */ + reg |= ((p->pad_cr & 0xFF) << 16); + /** cb value */ + reg |= ((p->pad_cb & 0xFF) << 8); + /** y value */ + reg |= p->pad_luma & 0xFF; + writel(reg, mfc_regs->e_padding_ctrl); + } + + /* rate control config. */ + reg = 0; + /* frame-level rate control */ + reg |= ((p->rc_frame & 0x1) << 9); + writel(reg, mfc_regs->e_rc_config); + + /* bit rate */ + if (p->rc_frame) + writel(p->rc_bitrate, + mfc_regs->e_rc_bit_rate); + else + writel(1, mfc_regs->e_rc_bit_rate); + + /* reaction coefficient */ + if (p->rc_frame) { + if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */ + writel(1, mfc_regs->e_rc_mode); + else /* loose CBR */ + writel(2, mfc_regs->e_rc_mode); + } + + /* seq header ctrl */ + reg = readl(mfc_regs->e_enc_options); + reg &= ~(0x1 << 2); + reg |= ((p->seq_hdr_mode & 0x1) << 2); + + /* frame skip mode */ + reg &= ~(0x3); + reg |= (p->frame_skip_mode & 0x3); + writel(reg, mfc_regs->e_enc_options); + + /* 'DROP_CONTROL_ENABLE', disable */ + reg = readl(mfc_regs->e_rc_config); + reg &= ~(0x1 << 10); + writel(reg, mfc_regs->e_rc_config); + + /* setting for MV range [16, 256] */ + reg = (p->mv_h_range & S5P_FIMV_E_MV_RANGE_V6_MASK); + writel(reg, mfc_regs->e_mv_hor_range); + + reg = (p->mv_v_range & S5P_FIMV_E_MV_RANGE_V6_MASK); + writel(reg, mfc_regs->e_mv_ver_range); + + writel(0x0, mfc_regs->e_frame_insertion); + writel(0x0, mfc_regs->e_roi_buffer_addr); + writel(0x0, mfc_regs->e_param_change); + writel(0x0, mfc_regs->e_rc_roi_ctrl); + writel(0x0, mfc_regs->e_picture_tag); + + writel(0x0, mfc_regs->e_bit_count_enable); + writel(0x0, mfc_regs->e_max_bit_count); + writel(0x0, mfc_regs->e_min_bit_count); + + writel(0x0, mfc_regs->e_metadata_buffer_addr); + writel(0x0, mfc_regs->e_metadata_buffer_size); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; + unsigned int reg = 0; + int i; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = readl(mfc_regs->e_gop_config); + reg &= ~(0x3 << 16); + reg |= ((p->num_b_frame & 0x3) << 16); + writel(reg, mfc_regs->e_gop_config); + + /* profile & level */ + reg = 0; + /** level */ + reg |= ((p_h264->level & 0xFF) << 8); + /** profile - 0 ~ 3 */ + reg |= p_h264->profile & 0x3F; + writel(reg, mfc_regs->e_picture_profile); + + /* rate control config. */ + reg = readl(mfc_regs->e_rc_config); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + writel(reg, mfc_regs->e_rc_config); + + /** frame QP */ + reg &= ~(0x3F); + reg |= p_h264->rc_frame_qp & 0x3F; + writel(reg, mfc_regs->e_rc_config); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_h264->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_h264->rc_min_qp & 0x3F; + writel(reg, mfc_regs->e_rc_qp_bound); + + /* other QPs */ + writel(0x0, mfc_regs->e_fixed_picture_qp); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8); + reg |= p_h264->rc_frame_qp & 0x3F; + writel(reg, mfc_regs->e_fixed_picture_qp); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + writel(reg, mfc_regs->e_rc_frame_rate); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + writel(p_h264->cpb_size & 0xFFFF, + mfc_regs->e_vbv_buffer_size); + + if (p->rc_frame) + writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); + } + + /* interlace */ + reg = 0; + reg |= ((p_h264->interlace & 0x1) << 3); + writel(reg, mfc_regs->e_h264_options); + + /* height */ + if (p_h264->interlace) { + writel(ctx->img_height >> 1, + mfc_regs->e_frame_height); /* 32 align */ + /* cropped height */ + writel(ctx->img_height >> 1, + mfc_regs->e_cropped_frame_height); + } + + /* loop filter ctrl */ + reg = readl(mfc_regs->e_h264_options); + reg &= ~(0x3 << 1); + reg |= ((p_h264->loop_filter_mode & 0x3) << 1); + writel(reg, mfc_regs->e_h264_options); + + /* loopfilter alpha offset */ + if (p_h264->loop_filter_alpha < 0) { + reg = 0x10; + reg |= (0xFF - p_h264->loop_filter_alpha) + 1; + } else { + reg = 0x00; + reg |= (p_h264->loop_filter_alpha & 0xF); + } + writel(reg, mfc_regs->e_h264_lf_alpha_offset); + + /* loopfilter beta offset */ + if (p_h264->loop_filter_beta < 0) { + reg = 0x10; + reg |= (0xFF - p_h264->loop_filter_beta) + 1; + } else { + reg = 0x00; + reg |= (p_h264->loop_filter_beta & 0xF); + } + writel(reg, mfc_regs->e_h264_lf_beta_offset); + + /* entropy coding mode */ + reg = readl(mfc_regs->e_h264_options); + reg &= ~(0x1); + reg |= p_h264->entropy_mode & 0x1; + writel(reg, mfc_regs->e_h264_options); + + /* number of ref. picture */ + reg = readl(mfc_regs->e_h264_options); + reg &= ~(0x1 << 7); + reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7); + writel(reg, mfc_regs->e_h264_options); + + /* 8x8 transform enable */ + reg = readl(mfc_regs->e_h264_options); + reg &= ~(0x3 << 12); + reg |= ((p_h264->_8x8_transform & 0x3) << 12); + writel(reg, mfc_regs->e_h264_options); + + /* macroblock adaptive scaling features */ + writel(0x0, mfc_regs->e_mb_rc_config); + if (p->rc_mb) { + reg = 0; + /** dark region */ + reg |= ((p_h264->rc_mb_dark & 0x1) << 3); + /** smooth region */ + reg |= ((p_h264->rc_mb_smooth & 0x1) << 2); + /** static region */ + reg |= ((p_h264->rc_mb_static & 0x1) << 1); + /** high activity region */ + reg |= p_h264->rc_mb_activity & 0x1; + writel(reg, mfc_regs->e_mb_rc_config); + } + + /* aspect ratio VUI */ + readl(mfc_regs->e_h264_options); + reg &= ~(0x1 << 5); + reg |= ((p_h264->vui_sar & 0x1) << 5); + writel(reg, mfc_regs->e_h264_options); + + writel(0x0, mfc_regs->e_aspect_ratio); + writel(0x0, mfc_regs->e_extended_sar); + if (p_h264->vui_sar) { + /* aspect ration IDC */ + reg = 0; + reg |= p_h264->vui_sar_idc & 0xFF; + writel(reg, mfc_regs->e_aspect_ratio); + if (p_h264->vui_sar_idc == 0xFF) { + /* extended SAR */ + reg = 0; + reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16; + reg |= p_h264->vui_ext_sar_height & 0xFFFF; + writel(reg, mfc_regs->e_extended_sar); + } + } + + /* intra picture period for H.264 open GOP */ + /* control */ + readl(mfc_regs->e_h264_options); + reg &= ~(0x1 << 4); + reg |= ((p_h264->open_gop & 0x1) << 4); + writel(reg, mfc_regs->e_h264_options); + + /* value */ + writel(0x0, mfc_regs->e_h264_i_period); + if (p_h264->open_gop) { + reg = 0; + reg |= p_h264->open_gop_size & 0xFFFF; + writel(reg, mfc_regs->e_h264_i_period); + } + + /* 'WEIGHTED_BI_PREDICTION' for B is disable */ + readl(mfc_regs->e_h264_options); + reg &= ~(0x3 << 9); + writel(reg, mfc_regs->e_h264_options); + + /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */ + readl(mfc_regs->e_h264_options); + reg &= ~(0x1 << 14); + writel(reg, mfc_regs->e_h264_options); + + /* ASO */ + readl(mfc_regs->e_h264_options); + reg &= ~(0x1 << 6); + reg |= ((p_h264->aso & 0x1) << 6); + writel(reg, mfc_regs->e_h264_options); + + /* hier qp enable */ + readl(mfc_regs->e_h264_options); + reg &= ~(0x1 << 8); + reg |= ((p_h264->open_gop & 0x1) << 8); + writel(reg, mfc_regs->e_h264_options); + reg = 0; + if (p_h264->hier_qp && p_h264->hier_qp_layer) { + reg |= (p_h264->hier_qp_type & 0x1) << 0x3; + reg |= p_h264->hier_qp_layer & 0x7; + writel(reg, mfc_regs->e_h264_num_t_layer); + /* QP value for each layer */ + for (i = 0; i < p_h264->hier_qp_layer && + i < ARRAY_SIZE(p_h264->hier_qp_layer_qp); i++) { + writel(p_h264->hier_qp_layer_qp[i], + mfc_regs->e_h264_hierarchical_qp_layer0 + + i * 4); + } + } + /* number of coding layer should be zero when hierarchical is disable */ + writel(reg, mfc_regs->e_h264_num_t_layer); + + /* frame packing SEI generation */ + readl(mfc_regs->e_h264_options); + reg &= ~(0x1 << 25); + reg |= ((p_h264->sei_frame_packing & 0x1) << 25); + writel(reg, mfc_regs->e_h264_options); + if (p_h264->sei_frame_packing) { + reg = 0; + /** current frame0 flag */ + reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2); + /** arrangement type */ + reg |= p_h264->sei_fp_arrangement_type & 0x3; + writel(reg, mfc_regs->e_h264_frame_packing_sei_info); + } + + if (p_h264->fmo) { + switch (p_h264->fmo_map_type) { + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES: + if (p_h264->fmo_slice_grp > 4) + p_h264->fmo_slice_grp = 4; + for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++) + writel(p_h264->fmo_run_len[i] - 1, + mfc_regs->e_h264_fmo_run_length_minus1_0 + + i * 4); + break; + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES: + if (p_h264->fmo_slice_grp > 4) + p_h264->fmo_slice_grp = 4; + break; + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN: + case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN: + if (p_h264->fmo_slice_grp > 2) + p_h264->fmo_slice_grp = 2; + writel(p_h264->fmo_chg_dir & 0x1, + mfc_regs->e_h264_fmo_slice_grp_change_dir); + /* the valid range is 0 ~ number of macroblocks -1 */ + writel(p_h264->fmo_chg_rate, + mfc_regs->e_h264_fmo_slice_grp_change_rate_minus1); + break; + default: + mfc_err("Unsupported map type for FMO: %d\n", + p_h264->fmo_map_type); + p_h264->fmo_map_type = 0; + p_h264->fmo_slice_grp = 1; + break; + } + + writel(p_h264->fmo_map_type, + mfc_regs->e_h264_fmo_slice_grp_map_type); + writel(p_h264->fmo_slice_grp - 1, + mfc_regs->e_h264_fmo_num_slice_grp_minus1); + } else { + writel(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1); + } + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + unsigned int reg = 0; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = readl(mfc_regs->e_gop_config); + reg &= ~(0x3 << 16); + reg |= ((p->num_b_frame & 0x3) << 16); + writel(reg, mfc_regs->e_gop_config); + + /* profile & level */ + reg = 0; + /** level */ + reg |= ((p_mpeg4->level & 0xFF) << 8); + /** profile - 0 ~ 1 */ + reg |= p_mpeg4->profile & 0x3F; + writel(reg, mfc_regs->e_picture_profile); + + /* rate control config. */ + reg = readl(mfc_regs->e_rc_config); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + writel(reg, mfc_regs->e_rc_config); + + /** frame QP */ + reg &= ~(0x3F); + reg |= p_mpeg4->rc_frame_qp & 0x3F; + writel(reg, mfc_regs->e_rc_config); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_mpeg4->rc_min_qp & 0x3F; + writel(reg, mfc_regs->e_rc_qp_bound); + + /* other QPs */ + writel(0x0, mfc_regs->e_fixed_picture_qp); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8); + reg |= p_mpeg4->rc_frame_qp & 0x3F; + writel(reg, mfc_regs->e_fixed_picture_qp); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + writel(reg, mfc_regs->e_rc_frame_rate); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); + + if (p->rc_frame) + writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); + } + + /* Disable HEC */ + writel(0x0, mfc_regs->e_mpeg4_options); + writel(0x0, mfc_regs->e_mpeg4_hec_period); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + unsigned int reg = 0; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* profile & level */ + reg = 0; + /** profile */ + reg |= (0x1 << 4); + writel(reg, mfc_regs->e_picture_profile); + + /* rate control config. */ + reg = readl(mfc_regs->e_rc_config); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + writel(reg, mfc_regs->e_rc_config); + + /** frame QP */ + reg &= ~(0x3F); + reg |= p_h263->rc_frame_qp & 0x3F; + writel(reg, mfc_regs->e_rc_config); + + /* max & min value of QP */ + reg = 0; + /** max QP */ + reg |= ((p_h263->rc_max_qp & 0x3F) << 8); + /** min QP */ + reg |= p_h263->rc_min_qp & 0x3F; + writel(reg, mfc_regs->e_rc_qp_bound); + + /* other QPs */ + writel(0x0, mfc_regs->e_fixed_picture_qp); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16); + reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8); + reg |= p_h263->rc_frame_qp & 0x3F; + writel(reg, mfc_regs->e_fixed_picture_qp); + } + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + writel(reg, mfc_regs->e_rc_frame_rate); + } + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); + + if (p->rc_frame) + writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); + } + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_vp8_enc_params *p_vp8 = &p->codec.vp8; + unsigned int reg = 0; + unsigned int val = 0; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = readl(mfc_regs->e_gop_config); + reg &= ~(0x3 << 16); + reg |= ((p->num_b_frame & 0x3) << 16); + writel(reg, mfc_regs->e_gop_config); + + /* profile - 0 ~ 3 */ + reg = p_vp8->profile & 0x3; + writel(reg, mfc_regs->e_picture_profile); + + /* rate control config. */ + reg = readl(mfc_regs->e_rc_config); + /** macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= ((p->rc_mb & 0x1) << 8); + writel(reg, mfc_regs->e_rc_config); + + /* frame rate */ + if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { + reg = 0; + reg |= ((p->rc_framerate_num & 0xFFFF) << 16); + reg |= p->rc_framerate_denom & 0xFFFF; + writel(reg, mfc_regs->e_rc_frame_rate); + } + + /* frame QP */ + reg &= ~(0x7F); + reg |= p_vp8->rc_frame_qp & 0x7F; + writel(reg, mfc_regs->e_rc_config); + + /* other QPs */ + writel(0x0, mfc_regs->e_fixed_picture_qp); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg |= ((p_vp8->rc_p_frame_qp & 0x7F) << 8); + reg |= p_vp8->rc_frame_qp & 0x7F; + writel(reg, mfc_regs->e_fixed_picture_qp); + } + + /* max QP */ + reg = ((p_vp8->rc_max_qp & 0x7F) << 8); + /* min QP */ + reg |= p_vp8->rc_min_qp & 0x7F; + writel(reg, mfc_regs->e_rc_qp_bound); + + /* vbv buffer size */ + if (p->frame_skip_mode == + V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { + writel(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size); + + if (p->rc_frame) + writel(p->vbv_delay, mfc_regs->e_vbv_init_delay); + } + + /* VP8 specific params */ + reg = 0; + reg |= (p_vp8->imd_4x4 & 0x1) << 10; + switch (p_vp8->num_partitions) { + case V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION: + val = 0; + break; + case V4L2_CID_MPEG_VIDEO_VPX_2_PARTITIONS: + val = 2; + break; + case V4L2_CID_MPEG_VIDEO_VPX_4_PARTITIONS: + val = 4; + break; + case V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS: + val = 8; + break; + } + reg |= (val & 0xF) << 3; + reg |= (p_vp8->num_ref & 0x2); + writel(reg, mfc_regs->e_vp8_options); + + mfc_debug_leave(); + + return 0; +} + +static int s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_hevc_enc_params *p_hevc = &p->codec.hevc; + unsigned int reg = 0; + int i; + + mfc_debug_enter(); + + s5p_mfc_set_enc_params(ctx); + + /* pictype : number of B */ + reg = readl(mfc_regs->e_gop_config); + /* num_b_frame - 0 ~ 2 */ + reg &= ~(0x3 << 16); + reg |= (p->num_b_frame << 16); + writel(reg, mfc_regs->e_gop_config); + + /* UHD encoding case */ + if ((ctx->img_width == 3840) && (ctx->img_height == 2160)) { + p_hevc->level = 51; + p_hevc->tier = 0; + /* this tier can be changed */ + } + + /* tier & level */ + reg = 0; + /* profile */ + reg |= p_hevc->profile & 0x3; + /* level */ + reg &= ~(0xFF << 8); + reg |= (p_hevc->level << 8); + /* tier - 0 ~ 1 */ + reg |= (p_hevc->tier << 16); + writel(reg, mfc_regs->e_picture_profile); + + switch (p_hevc->loopfilter) { + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: + p_hevc->loopfilter_disable = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: + p_hevc->loopfilter_disable = 0; + p_hevc->loopfilter_across = 1; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: + p_hevc->loopfilter_disable = 0; + p_hevc->loopfilter_across = 0; + break; + } + + /* max partition depth */ + reg = 0; + reg |= (p_hevc->max_partition_depth & 0x1); + reg |= (p_hevc->num_refs_for_p-1) << 2; + reg |= (p_hevc->refreshtype & 0x3) << 3; + reg |= (p_hevc->const_intra_period_enable & 0x1) << 5; + reg |= (p_hevc->lossless_cu_enable & 0x1) << 6; + reg |= (p_hevc->wavefront_enable & 0x1) << 7; + reg |= (p_hevc->loopfilter_disable & 0x1) << 8; + reg |= (p_hevc->loopfilter_across & 0x1) << 9; + reg |= (p_hevc->enable_ltr & 0x1) << 10; + reg |= (p_hevc->hier_qp_enable & 0x1) << 11; + reg |= (p_hevc->general_pb_enable & 0x1) << 13; + reg |= (p_hevc->temporal_id_enable & 0x1) << 14; + reg |= (p_hevc->strong_intra_smooth & 0x1) << 15; + reg |= (p_hevc->intra_pu_split_disable & 0x1) << 16; + reg |= (p_hevc->tmv_prediction_disable & 0x1) << 17; + reg |= (p_hevc->max_num_merge_mv & 0x7) << 18; + reg |= (p_hevc->encoding_nostartcode_enable & 0x1) << 23; + reg |= (p_hevc->prepend_sps_pps_to_idr << 26); + + writel(reg, mfc_regs->e_hevc_options); + /* refresh period */ + if (p_hevc->refreshtype) { + reg = 0; + reg |= (p_hevc->refreshperiod & 0xFFFF); + writel(reg, mfc_regs->e_hevc_refresh_period); + } + /* loop filter setting */ + if (!(p_hevc->loopfilter_disable & 0x1)) { + reg = 0; + reg |= (p_hevc->lf_beta_offset_div2); + writel(reg, mfc_regs->e_hevc_lf_beta_offset_div2); + reg = 0; + reg |= (p_hevc->lf_tc_offset_div2); + writel(reg, mfc_regs->e_hevc_lf_tc_offset_div2); + } + /* hier qp enable */ + if (p_hevc->num_hier_layer) { + reg = 0; + reg |= (p_hevc->hier_qp_type & 0x1) << 0x3; + reg |= p_hevc->num_hier_layer & 0x7; + writel(reg, mfc_regs->e_num_t_layer); + /* QP value for each layer */ + if (p_hevc->hier_qp_enable) { + for (i = 0; i < 7; i++) + writel(p_hevc->hier_qp_layer[i], + mfc_regs->e_hier_qp_layer0 + i * 4); + } + if (p->rc_frame) { + for (i = 0; i < 7; i++) + writel(p_hevc->hier_bit_layer[i], + mfc_regs->e_hier_bit_rate_layer0 + + i * 4); + } + } + + /* rate control config. */ + reg = readl(mfc_regs->e_rc_config); + /* macroblock level rate control */ + reg &= ~(0x1 << 8); + reg |= (p->rc_mb << 8); + writel(reg, mfc_regs->e_rc_config); + /* frame QP */ + reg &= ~(0xFF); + reg |= p_hevc->rc_frame_qp; + writel(reg, mfc_regs->e_rc_config); + + /* frame rate */ + if (p->rc_frame) { + reg = 0; + reg &= ~(0xFFFF << 16); + reg |= ((p_hevc->rc_framerate) << 16); + reg &= ~(0xFFFF); + reg |= FRAME_DELTA_DEFAULT; + writel(reg, mfc_regs->e_rc_frame_rate); + } + + /* max & min value of QP */ + reg = 0; + /* max QP */ + reg &= ~(0xFF << 8); + reg |= (p_hevc->rc_max_qp << 8); + /* min QP */ + reg &= ~(0xFF); + reg |= p_hevc->rc_min_qp; + writel(reg, mfc_regs->e_rc_qp_bound); + + writel(0x0, mfc_regs->e_fixed_picture_qp); + if (!p->rc_frame && !p->rc_mb) { + reg = 0; + reg &= ~(0xFF << 16); + reg |= (p_hevc->rc_b_frame_qp << 16); + reg &= ~(0xFF << 8); + reg |= (p_hevc->rc_p_frame_qp << 8); + reg &= ~(0xFF); + reg |= p_hevc->rc_frame_qp; + writel(reg, mfc_regs->e_fixed_picture_qp); + } + mfc_debug_leave(); + + return 0; +} + +/* Initialize decoding */ +static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + unsigned int reg = 0; + int fmo_aso_ctrl = 0; + + mfc_debug_enter(); + mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, + S5P_FIMV_CH_SEQ_HEADER_V6); + mfc_debug(2, "BUFs: %08x %08x %08x\n", + readl(mfc_regs->d_cpb_buffer_addr), + readl(mfc_regs->d_cpb_buffer_addr), + readl(mfc_regs->d_cpb_buffer_addr)); + + /* FMO_ASO_CTRL - 0: Enable, 1: Disable */ + reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6); + + if (ctx->display_delay_enable) { + reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6); + writel(ctx->display_delay, mfc_regs->d_display_delay); + } + + if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) { + writel(reg, mfc_regs->d_dec_options); + reg = 0; + } + + /* Setup loop filter, for decoding this is only valid for MPEG4 */ + if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) { + mfc_debug(2, "Set loop filter to: %d\n", + ctx->loop_filter_mpeg4); + reg |= (ctx->loop_filter_mpeg4 << + S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6); + } + if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) + reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6); + + if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) + writel(reg, mfc_regs->d_init_buffer_options); + else + writel(reg, mfc_regs->d_dec_options); + + /* 0: NV12(CbCr), 1: NV21(CrCb) */ + if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M) + writel(0x1, mfc_regs->pixel_format); + else + writel(0x0, mfc_regs->pixel_format); + + + /* sei parse */ + writel(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable); + + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_SEQ_HEADER_V6, NULL); + + mfc_debug_leave(); + return 0; +} + +static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + + if (flush) { + dev->curr_ctx = ctx->num; + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_H2R_CMD_FLUSH_V6, NULL); + } +} + +/* Decode a single frame */ +static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, + enum s5p_mfc_decode_arg last_frame) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + + writel(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower); + writel(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable); + + writel(ctx->inst_no, mfc_regs->instance_id); + /* Issue different commands to instance basing on whether it + * is the last frame or not. */ + switch (last_frame) { + case 0: + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_FRAME_START_V6, NULL); + break; + case 1: + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_LAST_FRAME_V6, NULL); + break; + default: + mfc_err("Unsupported last frame arg.\n"); + return -EINVAL; + } + + mfc_debug(2, "Decoding a usual frame.\n"); + return 0; +} + +static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_set_enc_params_h264(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) + s5p_mfc_set_enc_params_mpeg4(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) + s5p_mfc_set_enc_params_h263(ctx); + else if (ctx->codec_mode == S5P_MFC_CODEC_VP8_ENC) + s5p_mfc_set_enc_params_vp8(ctx); + else if (ctx->codec_mode == S5P_FIMV_CODEC_HEVC_ENC) + s5p_mfc_set_enc_params_hevc(ctx); + else { + mfc_err("Unknown codec for encoding (%x).\n", + ctx->codec_mode); + return -EINVAL; + } + + /* Set stride lengths for v7 & above */ + if (IS_MFCV7_PLUS(dev)) { + writel(ctx->img_width, mfc_regs->e_source_first_plane_stride); + writel(ctx->img_width, mfc_regs->e_source_second_plane_stride); + } + + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, + S5P_FIMV_CH_SEQ_HEADER_V6, NULL); + + return 0; +} + +static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + struct s5p_mfc_enc_params *p = &ctx->enc_params; + struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; + int i; + + if (p_h264->aso) { + for (i = 0; i < ARRAY_SIZE(p_h264->aso_slice_order); i++) { + writel(p_h264->aso_slice_order[i], + mfc_regs->e_h264_aso_slice_order_0 + i * 4); + } + } + return 0; +} + +/* Encode a single frame */ +static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + int cmd; + + mfc_debug(2, "++\n"); + + /* memory structure cur. frame */ + + if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) + s5p_mfc_h264_set_aso_slice_order_v6(ctx); + + s5p_mfc_set_slice_mode(ctx); + + if (ctx->state != MFCINST_FINISHING) + cmd = S5P_FIMV_CH_FRAME_START_V6; + else + cmd = S5P_FIMV_CH_LAST_FRAME_V6; + + writel(ctx->inst_no, mfc_regs->instance_id); + s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, cmd, NULL); + + mfc_debug(2, "--\n"); + + return 0; +} + +static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + + s5p_mfc_set_dec_stream_buffer_v6(ctx, 0, 0, 0); + dev->curr_ctx = ctx->num; + s5p_mfc_decode_one_frame_v6(ctx, MFC_DEC_LAST_FRAME); +} + +static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + int last_frame = 0; + + if (ctx->state == MFCINST_FINISHING) { + last_frame = MFC_DEC_LAST_FRAME; + s5p_mfc_set_dec_stream_buffer_v6(ctx, 0, 0, 0); + dev->curr_ctx = ctx->num; + s5p_mfc_clean_ctx_int_flags(ctx); + s5p_mfc_decode_one_frame_v6(ctx, last_frame); + return 0; + } + + /* Frames are being decoded */ + if (list_empty(&ctx->src_queue)) { + mfc_debug(2, "No src buffers.\n"); + return -EAGAIN; + } + /* Get the next source buffer */ + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + temp_vb->flags |= MFC_BUF_FLAG_USED; + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), + ctx->consumed_stream, + temp_vb->b->vb2_buf.planes[0].bytesused); + + dev->curr_ctx = ctx->num; + if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) { + last_frame = 1; + mfc_debug(2, "Setting ctx->state to FINISHING\n"); + ctx->state = MFCINST_FINISHING; + } + s5p_mfc_decode_one_frame_v6(ctx, last_frame); + + return 0; +} + +static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *dst_mb; + struct s5p_mfc_buf *src_mb; + unsigned long src_y_addr, src_c_addr, dst_addr; + /* + unsigned int src_y_size, src_c_size; + */ + unsigned int dst_size; + + if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) { + mfc_debug(2, "no src buffers.\n"); + return -EAGAIN; + } + + if (list_empty(&ctx->dst_queue)) { + mfc_debug(2, "no dst buffers.\n"); + return -EAGAIN; + } + + if (list_empty(&ctx->src_queue)) { + /* send null frame */ + s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0); + src_mb = NULL; + } else { + src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + src_mb->flags |= MFC_BUF_FLAG_USED; + if (src_mb->b->vb2_buf.planes[0].bytesused == 0) { + s5p_mfc_set_enc_frame_buffer_v6(ctx, 0, 0); + ctx->state = MFCINST_FINISHING; + } else { + src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0); + src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1); + + mfc_debug(2, "enc src y addr: 0x%08lx\n", src_y_addr); + mfc_debug(2, "enc src c addr: 0x%08lx\n", src_c_addr); + + s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr); + if (src_mb->flags & MFC_BUF_FLAG_EOS) + ctx->state = MFCINST_FINISHING; + } + } + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_mb->flags |= MFC_BUF_FLAG_USED; + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); + dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); + + s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); + + dev->curr_ctx = ctx->num; + s5p_mfc_encode_one_frame_v6(ctx); + + return 0; +} + +static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *temp_vb; + + /* Initializing decoding - parsing header */ + mfc_debug(2, "Preparing to init decoding.\n"); + temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); + mfc_debug(2, "Header size: %d\n", temp_vb->b->vb2_buf.planes[0].bytesused); + s5p_mfc_set_dec_stream_buffer_v6(ctx, + vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), 0, + temp_vb->b->vb2_buf.planes[0].bytesused); + dev->curr_ctx = ctx->num; + s5p_mfc_init_decode_v6(ctx); +} + +static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + struct s5p_mfc_buf *dst_mb; + unsigned long dst_addr; + unsigned int dst_size; + + dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); + dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0); + dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0); + s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); + dev->curr_ctx = ctx->num; + s5p_mfc_init_encode_v6(ctx); +} + +static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + /* Header was parsed now start processing + * First set the output frame buffers + * s5p_mfc_alloc_dec_buffers(ctx); */ + + if (ctx->capture_state != QUEUE_BUFS_MMAPED) { + mfc_err("It seems that not all destination buffers were\n" + "mmapped.MFC requires that all destination are mmapped\n" + "before starting processing.\n"); + return -EAGAIN; + } + + dev->curr_ctx = ctx->num; + ret = s5p_mfc_set_dec_frame_buffer_v6(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem.\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + int ret; + + dev->curr_ctx = ctx->num; + ret = s5p_mfc_set_enc_ref_buffer_v6(ctx); + if (ret) { + mfc_err("Failed to alloc frame mem.\n"); + ctx->state = MFCINST_ERROR; + } + return ret; +} + +/* Try running an operation on hardware */ +static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) +{ + struct s5p_mfc_ctx *ctx; + int new_ctx; + unsigned int ret = 0; + + mfc_debug(1, "Try run dev: %p\n", dev); + + /* Check whether hardware is not running */ + if (test_and_set_bit(0, &dev->hw_lock) != 0) { + /* This is perfectly ok, the scheduled ctx should wait */ + mfc_debug(1, "Couldn't lock HW.\n"); + return; + } + + /* Choose the context to run */ + new_ctx = s5p_mfc_get_new_ctx(dev); + if (new_ctx < 0) { + /* No contexts to run */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) { + mfc_err("Failed to unlock hardware.\n"); + return; + } + + mfc_debug(1, "No ctx is scheduled to be run.\n"); + return; + } + + mfc_debug(1, "New context: %d\n", new_ctx); + ctx = dev->ctx[new_ctx]; + mfc_debug(1, "Setting new context to %p\n", ctx); + /* Got context to run in ctx */ + mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n", + ctx->dst_queue_cnt, ctx->pb_count, ctx->src_queue_cnt); + mfc_debug(1, "ctx->state=%d\n", ctx->state); + /* Last frame has already been sent to MFC + * Now obtaining frames from MFC buffer */ + + s5p_mfc_clock_on(); + s5p_mfc_clean_ctx_int_flags(ctx); + + if (ctx->type == MFCINST_DECODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RUNNING: + ret = s5p_mfc_run_dec_frame(ctx); + break; + case MFCINST_INIT: + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_dec(ctx); + break; + case MFCINST_HEAD_PARSED: + ret = s5p_mfc_run_init_dec_buffers(ctx); + break; + case MFCINST_FLUSH: + s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); + break; + case MFCINST_RES_CHANGE_INIT: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RES_CHANGE_FLUSH: + s5p_mfc_run_dec_last_frames(ctx); + break; + case MFCINST_RES_CHANGE_END: + mfc_debug(2, "Finished remaining frames after resolution change.\n"); + ctx->capture_state = QUEUE_FREE; + mfc_debug(2, "Will re-init the codec`.\n"); + s5p_mfc_run_init_dec(ctx); + break; + default: + ret = -EAGAIN; + } + } else if (ctx->type == MFCINST_ENCODER) { + switch (ctx->state) { + case MFCINST_FINISHING: + case MFCINST_RUNNING: + ret = s5p_mfc_run_enc_frame(ctx); + break; + case MFCINST_INIT: + ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, + ctx); + break; + case MFCINST_RETURN_INST: + ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, + ctx); + break; + case MFCINST_GOT_INST: + s5p_mfc_run_init_enc(ctx); + break; + case MFCINST_HEAD_PRODUCED: + ret = s5p_mfc_run_init_enc_buffers(ctx); + break; + default: + ret = -EAGAIN; + } + } else { + mfc_err("invalid context type: %d\n", ctx->type); + ret = -EAGAIN; + } + + if (ret) { + /* Free hardware lock */ + if (test_and_clear_bit(0, &dev->hw_lock) == 0) + mfc_err("Failed to unlock hardware.\n"); + + /* This is in deed imporant, as no operation has been + * scheduled, reduce the clock count as no one will + * ever do this, because no interrupt related to this try_run + * will ever come from hardware. */ + s5p_mfc_clock_off(); + } +} + +static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) +{ + const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; + writel(0, mfc_regs->risc2host_command); + writel(0, mfc_regs->risc2host_int); +} + +static unsigned int +s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned long ofs) +{ + int ret; + + s5p_mfc_clock_on(); + ret = readl((void __iomem *)ofs); + s5p_mfc_clock_off(); + + return ret; +} + +static int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_display_first_plane_addr); +} + +static int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_decoded_first_plane_addr); +} + +static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_display_status); +} + +static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_decoded_status); +} + +static int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_decoded_frame_type) & + S5P_FIMV_DECODE_FRAME_MASK_V6; +} + +static int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx) +{ + struct s5p_mfc_dev *dev = ctx->dev; + return readl(dev->mfc_regs->d_display_frame_type) & + S5P_FIMV_DECODE_FRAME_MASK_V6; +} + +static int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_decoded_nal_size); +} + +static int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->risc2host_command) & + S5P_FIMV_RISC2HOST_CMD_MASK; +} + +static int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->error_code); +} + +static int s5p_mfc_err_dec_v6(unsigned int err) +{ + return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6; +} + +static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_display_frame_width); +} + +static int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_display_frame_height); +} + +static int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_min_num_dpb); +} + +static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_min_num_mv); +} + +static int s5p_mfc_get_min_scratch_buf_size(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->d_min_scratch_buffer_size); +} + +static int s5p_mfc_get_e_min_scratch_buf_size(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->e_min_scratch_buffer_size); +} + +static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->ret_instance_id); +} + +static int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->e_num_dpb); +} + +static int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->e_stream_size); +} + +static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) +{ + return readl(dev->mfc_regs->e_slice_type); +} + +static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, + (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_top); +} + +static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, + (__force unsigned long) ctx->dev->mfc_regs->d_ret_picture_tag_bot); +} + +static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, + (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info1); +} + +static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) +{ + return s5p_mfc_read_info_v6(ctx, + (__force unsigned long) ctx->dev->mfc_regs->d_display_crop_info2); +} + +static struct s5p_mfc_regs mfc_regs; + +/* Initialize registers for MFC v6 onwards */ +const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev) +{ + memset(&mfc_regs, 0, sizeof(mfc_regs)); + +#define S5P_MFC_REG_ADDR(dev, reg) ((dev)->regs_base + (reg)) +#define R(m, r) mfc_regs.m = S5P_MFC_REG_ADDR(dev, r) + /* codec common registers */ + R(risc_on, S5P_FIMV_RISC_ON_V6); + R(risc2host_int, S5P_FIMV_RISC2HOST_INT_V6); + R(host2risc_int, S5P_FIMV_HOST2RISC_INT_V6); + R(risc_base_address, S5P_FIMV_RISC_BASE_ADDRESS_V6); + R(mfc_reset, S5P_FIMV_MFC_RESET_V6); + R(host2risc_command, S5P_FIMV_HOST2RISC_CMD_V6); + R(risc2host_command, S5P_FIMV_RISC2HOST_CMD_V6); + R(firmware_version, S5P_FIMV_FW_VERSION_V6); + R(instance_id, S5P_FIMV_INSTANCE_ID_V6); + R(codec_type, S5P_FIMV_CODEC_TYPE_V6); + R(context_mem_addr, S5P_FIMV_CONTEXT_MEM_ADDR_V6); + R(context_mem_size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); + R(pixel_format, S5P_FIMV_PIXEL_FORMAT_V6); + R(ret_instance_id, S5P_FIMV_RET_INSTANCE_ID_V6); + R(error_code, S5P_FIMV_ERROR_CODE_V6); + + /* decoder registers */ + R(d_crc_ctrl, S5P_FIMV_D_CRC_CTRL_V6); + R(d_dec_options, S5P_FIMV_D_DEC_OPTIONS_V6); + R(d_display_delay, S5P_FIMV_D_DISPLAY_DELAY_V6); + R(d_sei_enable, S5P_FIMV_D_SEI_ENABLE_V6); + R(d_min_num_dpb, S5P_FIMV_D_MIN_NUM_DPB_V6); + R(d_min_num_mv, S5P_FIMV_D_MIN_NUM_MV_V6); + R(d_mvc_num_views, S5P_FIMV_D_MVC_NUM_VIEWS_V6); + R(d_num_dpb, S5P_FIMV_D_NUM_DPB_V6); + R(d_num_mv, S5P_FIMV_D_NUM_MV_V6); + R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V6); + R(d_first_plane_dpb_size, S5P_FIMV_D_LUMA_DPB_SIZE_V6); + R(d_second_plane_dpb_size, S5P_FIMV_D_CHROMA_DPB_SIZE_V6); + R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V6); + R(d_first_plane_dpb, S5P_FIMV_D_LUMA_DPB_V6); + R(d_second_plane_dpb, S5P_FIMV_D_CHROMA_DPB_V6); + R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V6); + R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6); + R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6); + R(d_cpb_buffer_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V6); + R(d_cpb_buffer_size, S5P_FIMV_D_CPB_BUFFER_SIZE_V6); + R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6); + R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V6); + R(d_slice_if_enable, S5P_FIMV_D_SLICE_IF_ENABLE_V6); + R(d_stream_data_size, S5P_FIMV_D_STREAM_DATA_SIZE_V6); + R(d_display_frame_width, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6); + R(d_display_frame_height, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6); + R(d_display_status, S5P_FIMV_D_DISPLAY_STATUS_V6); + R(d_display_first_plane_addr, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); + R(d_display_second_plane_addr, S5P_FIMV_D_DISPLAY_CHROMA_ADDR_V6); + R(d_display_frame_type, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6); + R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V6); + R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V6); + R(d_display_aspect_ratio, S5P_FIMV_D_DISPLAY_ASPECT_RATIO_V6); + R(d_display_extended_ar, S5P_FIMV_D_DISPLAY_EXTENDED_AR_V6); + R(d_decoded_status, S5P_FIMV_D_DECODED_STATUS_V6); + R(d_decoded_first_plane_addr, S5P_FIMV_D_DECODED_LUMA_ADDR_V6); + R(d_decoded_second_plane_addr, S5P_FIMV_D_DECODED_CHROMA_ADDR_V6); + R(d_decoded_frame_type, S5P_FIMV_D_DECODED_FRAME_TYPE_V6); + R(d_decoded_nal_size, S5P_FIMV_D_DECODED_NAL_SIZE_V6); + R(d_ret_picture_tag_top, S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6); + R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6); + R(d_h264_info, S5P_FIMV_D_H264_INFO_V6); + R(d_mvc_view_id, S5P_FIMV_D_MVC_VIEW_ID_V6); + R(d_frame_pack_sei_avail, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6); + + /* encoder registers */ + R(e_frame_width, S5P_FIMV_E_FRAME_WIDTH_V6); + R(e_frame_height, S5P_FIMV_E_FRAME_HEIGHT_V6); + R(e_cropped_frame_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6); + R(e_cropped_frame_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); + R(e_frame_crop_offset, S5P_FIMV_E_FRAME_CROP_OFFSET_V6); + R(e_enc_options, S5P_FIMV_E_ENC_OPTIONS_V6); + R(e_picture_profile, S5P_FIMV_E_PICTURE_PROFILE_V6); + R(e_vbv_buffer_size, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); + R(e_vbv_init_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); + R(e_fixed_picture_qp, S5P_FIMV_E_FIXED_PICTURE_QP_V6); + R(e_rc_config, S5P_FIMV_E_RC_CONFIG_V6); + R(e_rc_qp_bound, S5P_FIMV_E_RC_QP_BOUND_V6); + R(e_rc_mode, S5P_FIMV_E_RC_RPARAM_V6); + R(e_mb_rc_config, S5P_FIMV_E_MB_RC_CONFIG_V6); + R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V6); + R(e_mv_hor_range, S5P_FIMV_E_MV_HOR_RANGE_V6); + R(e_mv_ver_range, S5P_FIMV_E_MV_VER_RANGE_V6); + R(e_num_dpb, S5P_FIMV_E_NUM_DPB_V6); + R(e_luma_dpb, S5P_FIMV_E_LUMA_DPB_V6); + R(e_chroma_dpb, S5P_FIMV_E_CHROMA_DPB_V6); + R(e_me_buffer, S5P_FIMV_E_ME_BUFFER_V6); + R(e_scratch_buffer_addr, S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6); + R(e_scratch_buffer_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6); + R(e_tmv_buffer0, S5P_FIMV_E_TMV_BUFFER0_V6); + R(e_tmv_buffer1, S5P_FIMV_E_TMV_BUFFER1_V6); + R(e_source_first_plane_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6); + R(e_source_second_plane_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6); + R(e_stream_buffer_addr, S5P_FIMV_E_STREAM_BUFFER_ADDR_V6); + R(e_stream_buffer_size, S5P_FIMV_E_STREAM_BUFFER_SIZE_V6); + R(e_roi_buffer_addr, S5P_FIMV_E_ROI_BUFFER_ADDR_V6); + R(e_param_change, S5P_FIMV_E_PARAM_CHANGE_V6); + R(e_ir_size, S5P_FIMV_E_IR_SIZE_V6); + R(e_gop_config, S5P_FIMV_E_GOP_CONFIG_V6); + R(e_mslice_mode, S5P_FIMV_E_MSLICE_MODE_V6); + R(e_mslice_size_mb, S5P_FIMV_E_MSLICE_SIZE_MB_V6); + R(e_mslice_size_bits, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); + R(e_frame_insertion, S5P_FIMV_E_FRAME_INSERTION_V6); + R(e_rc_frame_rate, S5P_FIMV_E_RC_FRAME_RATE_V6); + R(e_rc_bit_rate, S5P_FIMV_E_RC_BIT_RATE_V6); + R(e_rc_roi_ctrl, S5P_FIMV_E_RC_ROI_CTRL_V6); + R(e_picture_tag, S5P_FIMV_E_PICTURE_TAG_V6); + R(e_bit_count_enable, S5P_FIMV_E_BIT_COUNT_ENABLE_V6); + R(e_max_bit_count, S5P_FIMV_E_MAX_BIT_COUNT_V6); + R(e_min_bit_count, S5P_FIMV_E_MIN_BIT_COUNT_V6); + R(e_metadata_buffer_addr, S5P_FIMV_E_METADATA_BUFFER_ADDR_V6); + R(e_metadata_buffer_size, S5P_FIMV_E_METADATA_BUFFER_SIZE_V6); + R(e_encoded_source_first_plane_addr, + S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6); + R(e_encoded_source_second_plane_addr, + S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6); + R(e_stream_size, S5P_FIMV_E_STREAM_SIZE_V6); + R(e_slice_type, S5P_FIMV_E_SLICE_TYPE_V6); + R(e_picture_count, S5P_FIMV_E_PICTURE_COUNT_V6); + R(e_ret_picture_tag, S5P_FIMV_E_RET_PICTURE_TAG_V6); + R(e_recon_luma_dpb_addr, S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6); + R(e_recon_chroma_dpb_addr, S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6); + R(e_mpeg4_options, S5P_FIMV_E_MPEG4_OPTIONS_V6); + R(e_mpeg4_hec_period, S5P_FIMV_E_MPEG4_HEC_PERIOD_V6); + R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V6); + R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V6); + R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V6); + R(e_h264_lf_alpha_offset, S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6); + R(e_h264_lf_beta_offset, S5P_FIMV_E_H264_LF_BETA_OFFSET_V6); + R(e_h264_i_period, S5P_FIMV_E_H264_I_PERIOD_V6); + R(e_h264_fmo_slice_grp_map_type, + S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6); + R(e_h264_fmo_num_slice_grp_minus1, + S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); + R(e_h264_fmo_slice_grp_change_dir, + S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6); + R(e_h264_fmo_slice_grp_change_rate_minus1, + S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6); + R(e_h264_fmo_run_length_minus1_0, + S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6); + R(e_h264_aso_slice_order_0, S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6); + R(e_h264_num_t_layer, S5P_FIMV_E_H264_NUM_T_LAYER_V6); + R(e_h264_hierarchical_qp_layer0, + S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6); + R(e_h264_frame_packing_sei_info, + S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6); + + if (!IS_MFCV7_PLUS(dev)) + goto done; + + /* Initialize registers used in MFC v7+ */ + R(e_source_first_plane_addr, S5P_FIMV_E_SOURCE_FIRST_ADDR_V7); + R(e_source_second_plane_addr, S5P_FIMV_E_SOURCE_SECOND_ADDR_V7); + R(e_source_third_plane_addr, S5P_FIMV_E_SOURCE_THIRD_ADDR_V7); + R(e_source_first_plane_stride, S5P_FIMV_E_SOURCE_FIRST_STRIDE_V7); + R(e_source_second_plane_stride, S5P_FIMV_E_SOURCE_SECOND_STRIDE_V7); + R(e_source_third_plane_stride, S5P_FIMV_E_SOURCE_THIRD_STRIDE_V7); + R(e_encoded_source_first_plane_addr, + S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7); + R(e_encoded_source_second_plane_addr, + S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7); + R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7); + + if (!IS_MFCV8_PLUS(dev)) + goto done; + + /* Initialize registers used in MFC v8 only. + * Also, over-write the registers which have + * a different offset for MFC v8. */ + R(d_stream_data_size, S5P_FIMV_D_STREAM_DATA_SIZE_V8); + R(d_cpb_buffer_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V8); + R(d_cpb_buffer_size, S5P_FIMV_D_CPB_BUFFER_SIZE_V8); + R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V8); + R(d_first_plane_dpb_size, S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8); + R(d_second_plane_dpb_size, S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8); + R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8); + R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8); + R(d_first_plane_dpb_stride_size, + S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8); + R(d_second_plane_dpb_stride_size, + S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8); + R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V8); + R(d_num_mv, S5P_FIMV_D_NUM_MV_V8); + R(d_first_plane_dpb, S5P_FIMV_D_FIRST_PLANE_DPB_V8); + R(d_second_plane_dpb, S5P_FIMV_D_SECOND_PLANE_DPB_V8); + R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V8); + R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8); + R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8); + R(d_slice_if_enable, S5P_FIMV_D_SLICE_IF_ENABLE_V8); + R(d_display_first_plane_addr, S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR_V8); + R(d_display_second_plane_addr, S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR_V8); + R(d_decoded_first_plane_addr, S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR_V8); + R(d_decoded_second_plane_addr, S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR_V8); + R(d_display_status, S5P_FIMV_D_DISPLAY_STATUS_V8); + R(d_decoded_status, S5P_FIMV_D_DECODED_STATUS_V8); + R(d_decoded_frame_type, S5P_FIMV_D_DECODED_FRAME_TYPE_V8); + R(d_display_frame_type, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V8); + R(d_decoded_nal_size, S5P_FIMV_D_DECODED_NAL_SIZE_V8); + R(d_display_frame_width, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V8); + R(d_display_frame_height, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V8); + R(d_frame_pack_sei_avail, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V8); + R(d_mvc_num_views, S5P_FIMV_D_MVC_NUM_VIEWS_V8); + R(d_mvc_view_id, S5P_FIMV_D_MVC_VIEW_ID_V8); + R(d_ret_picture_tag_top, S5P_FIMV_D_RET_PICTURE_TAG_TOP_V8); + R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8); + R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V8); + R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V8); + R(d_min_scratch_buffer_size, S5P_FIMV_D_MIN_SCRATCH_BUFFER_SIZE_V8); + + /* encoder registers */ + R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V8); + R(e_rc_config, S5P_FIMV_E_RC_CONFIG_V8); + R(e_rc_mode, S5P_FIMV_E_RC_RPARAM_V8); + R(e_mv_hor_range, S5P_FIMV_E_MV_HOR_RANGE_V8); + R(e_mv_ver_range, S5P_FIMV_E_MV_VER_RANGE_V8); + R(e_rc_qp_bound, S5P_FIMV_E_RC_QP_BOUND_V8); + R(e_fixed_picture_qp, S5P_FIMV_E_FIXED_PICTURE_QP_V8); + R(e_vbv_buffer_size, S5P_FIMV_E_VBV_BUFFER_SIZE_V8); + R(e_vbv_init_delay, S5P_FIMV_E_VBV_INIT_DELAY_V8); + R(e_mb_rc_config, S5P_FIMV_E_MB_RC_CONFIG_V8); + R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V8); + R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V8); + R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V8); + R(e_min_scratch_buffer_size, S5P_FIMV_E_MIN_SCRATCH_BUFFER_SIZE_V8); + + if (!IS_MFCV10(dev)) + goto done; + + /* Initialize registers used in MFC v10 only. + * Also, over-write the registers which have + * a different offset for MFC v10. + */ + + /* decoder registers */ + R(d_static_buffer_addr, S5P_FIMV_D_STATIC_BUFFER_ADDR_V10); + R(d_static_buffer_size, S5P_FIMV_D_STATIC_BUFFER_SIZE_V10); + + /* encoder registers */ + R(e_num_t_layer, S5P_FIMV_E_NUM_T_LAYER_V10); + R(e_hier_qp_layer0, S5P_FIMV_E_HIERARCHICAL_QP_LAYER0_V10); + R(e_hier_bit_rate_layer0, S5P_FIMV_E_HIERARCHICAL_BIT_RATE_LAYER0_V10); + R(e_hevc_options, S5P_FIMV_E_HEVC_OPTIONS_V10); + R(e_hevc_refresh_period, S5P_FIMV_E_HEVC_REFRESH_PERIOD_V10); + R(e_hevc_lf_beta_offset_div2, S5P_FIMV_E_HEVC_LF_BETA_OFFSET_DIV2_V10); + R(e_hevc_lf_tc_offset_div2, S5P_FIMV_E_HEVC_LF_TC_OFFSET_DIV2_V10); + R(e_hevc_nal_control, S5P_FIMV_E_HEVC_NAL_CONTROL_V10); + +done: + return &mfc_regs; +#undef S5P_MFC_REG_ADDR +#undef R +} + +/* Initialize opr function pointers for MFC v6 */ +static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { + .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v6, + .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v6, + .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v6, + .release_codec_buffers = s5p_mfc_release_codec_buffers_v6, + .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v6, + .release_instance_buffer = s5p_mfc_release_instance_buffer_v6, + .alloc_dev_context_buffer = + s5p_mfc_alloc_dev_context_buffer_v6, + .release_dev_context_buffer = + s5p_mfc_release_dev_context_buffer_v6, + .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v6, + .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v6, + .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v6, + .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v6, + .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v6, + .try_run = s5p_mfc_try_run_v6, + .clear_int_flags = s5p_mfc_clear_int_flags_v6, + .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v6, + .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v6, + .get_dspl_status = s5p_mfc_get_dspl_status_v6, + .get_dec_status = s5p_mfc_get_dec_status_v6, + .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v6, + .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v6, + .get_consumed_stream = s5p_mfc_get_consumed_stream_v6, + .get_int_reason = s5p_mfc_get_int_reason_v6, + .get_int_err = s5p_mfc_get_int_err_v6, + .err_dec = s5p_mfc_err_dec_v6, + .get_img_width = s5p_mfc_get_img_width_v6, + .get_img_height = s5p_mfc_get_img_height_v6, + .get_dpb_count = s5p_mfc_get_dpb_count_v6, + .get_mv_count = s5p_mfc_get_mv_count_v6, + .get_inst_no = s5p_mfc_get_inst_no_v6, + .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v6, + .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v6, + .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v6, + .get_pic_type_top = s5p_mfc_get_pic_type_top_v6, + .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, + .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, + .get_crop_info_v = s5p_mfc_get_crop_info_v_v6, + .get_min_scratch_buf_size = s5p_mfc_get_min_scratch_buf_size, + .get_e_min_scratch_buf_size = s5p_mfc_get_e_min_scratch_buf_size, +}; + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) +{ + return &s5p_mfc_ops_v6; +} diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h new file mode 100644 index 000000000000..e4dd03c5454c --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h + * + * Header file for Samsung MFC (Multi Function Codec - FIMV) driver + * Contains declarations of hw related functions. + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_OPR_V6_H_ +#define S5P_MFC_OPR_V6_H_ + +#include "s5p_mfc_common.h" +#include "s5p_mfc_opr.h" + +#define MFC_CTRL_MODE_CUSTOM MFC_CTRL_MODE_SFR + +#define MB_WIDTH(x_size) DIV_ROUND_UP(x_size, 16) +#define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16) +#define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \ + (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) +#define S5P_MFC_DEC_MV_SIZE_V10(x, y) (MB_WIDTH(x) * \ + (((MB_HEIGHT(y)+1)/2)*2) * 64 + 512) +#define S5P_MFC_LCU_WIDTH(x_size) DIV_ROUND_UP(x_size, 32) +#define S5P_MFC_LCU_HEIGHT(y_size) DIV_ROUND_UP(y_size, 32) + +#define s5p_mfc_dec_hevc_mv_size(x, y) \ + (DIV_ROUND_UP(x, 64) * DIV_ROUND_UP(y, 64) * 256 + 512) + +/* Definition */ +#define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) +#define ENC_MULTI_SLICE_BIT_MIN 2800 +#define ENC_INTRA_REFRESH_MB_MAX ((1 << 18) - 1) +#define ENC_VBV_BUF_SIZE_MAX ((1 << 30) - 1) +#define ENC_H264_LOOP_FILTER_AB_MIN -12 +#define ENC_H264_LOOP_FILTER_AB_MAX 12 +#define ENC_H264_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_H263_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_H264_PROFILE_MAX 3 +#define ENC_H264_LEVEL_MAX 42 +#define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1) +#define FRAME_DELTA_H264_H263 1 +#define TIGHT_CBR_MAX 10 +#define ENC_HEVC_RC_FRAME_RATE_MAX ((1 << 16) - 1) +#define ENC_HEVC_QP_INDEX_MIN -12 +#define ENC_HEVC_QP_INDEX_MAX 12 +#define ENC_HEVC_LOOP_FILTER_MIN -12 +#define ENC_HEVC_LOOP_FILTER_MAX 12 +#define ENC_HEVC_LEVEL_MAX 62 + +#define FRAME_DELTA_DEFAULT 1 + +struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); +const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev); +#endif /* S5P_MFC_OPR_V6_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c new file mode 100644 index 000000000000..72a901e99450 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#include +#include +#include +#include +#include "s5p_mfc_common.h" +#include "s5p_mfc_debug.h" +#include "s5p_mfc_pm.h" + +static struct s5p_mfc_pm *pm; +static struct s5p_mfc_dev *p_dev; +static atomic_t clk_ref; + +int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) +{ + int i; + + pm = &dev->pm; + p_dev = dev; + + pm->num_clocks = dev->variant->num_clocks; + pm->clk_names = dev->variant->clk_names; + pm->device = &dev->plat_dev->dev; + pm->clock_gate = NULL; + + /* clock control */ + for (i = 0; i < pm->num_clocks; i++) { + pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]); + if (IS_ERR(pm->clocks[i])) { + /* additional clocks are optional */ + if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) { + pm->clocks[i] = NULL; + continue; + } + mfc_err("Failed to get clock: %s\n", + pm->clk_names[i]); + return PTR_ERR(pm->clocks[i]); + } + } + + if (dev->variant->use_clock_gating) + pm->clock_gate = pm->clocks[0]; + + pm_runtime_enable(pm->device); + atomic_set(&clk_ref, 0); + return 0; +} + +void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) +{ + pm_runtime_disable(pm->device); +} + +int s5p_mfc_clock_on(void) +{ + atomic_inc(&clk_ref); + mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); + + return clk_enable(pm->clock_gate); +} + +void s5p_mfc_clock_off(void) +{ + atomic_dec(&clk_ref); + mfc_debug(3, "- %d\n", atomic_read(&clk_ref)); + + clk_disable(pm->clock_gate); +} + +int s5p_mfc_power_on(void) +{ + int i, ret = 0; + + ret = pm_runtime_resume_and_get(pm->device); + if (ret < 0) + return ret; + + /* clock control */ + for (i = 0; i < pm->num_clocks; i++) { + ret = clk_prepare_enable(pm->clocks[i]); + if (ret < 0) { + mfc_err("clock prepare failed for clock: %s\n", + pm->clk_names[i]); + i++; + goto err; + } + } + + /* prepare for software clock gating */ + clk_disable(pm->clock_gate); + + return 0; +err: + while (--i > 0) + clk_disable_unprepare(pm->clocks[i]); + pm_runtime_put(pm->device); + return ret; +} + +int s5p_mfc_power_off(void) +{ + int i; + + /* finish software clock gating */ + clk_enable(pm->clock_gate); + + for (i = 0; i < pm->num_clocks; i++) + clk_disable_unprepare(pm->clocks[i]); + + return pm_runtime_put_sync(pm->device); +} + diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.h new file mode 100644 index 000000000000..4159d2364e87 --- /dev/null +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.h + * + * Copyright (C) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + */ + +#ifndef S5P_MFC_PM_H_ +#define S5P_MFC_PM_H_ + +int s5p_mfc_init_pm(struct s5p_mfc_dev *dev); +void s5p_mfc_final_pm(struct s5p_mfc_dev *dev); + +int s5p_mfc_clock_on(void); +void s5p_mfc_clock_off(void); +int s5p_mfc_power_on(void); +int s5p_mfc_power_off(void); + +#endif /* S5P_MFC_PM_H_ */ -- cgit v1.2.3