[media] s5p-mfc: Update MFC v4l2 driver to support MFC6.x

Multi Format Codec 6.x is a hardware video coding acceleration
module present in new Exynos5 SoC series. It is capable of
handling several new video codecs for decoding and encoding.

Signed-off-by: Jeongtae Park <jtp.park@samsung.com>
Signed-off-by: Janghyuck Kim <janghyuck.kim@samsung.com>
Signed-off-by: Jaeryul Oh <jaeryul.oh@samsung.com>
Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com>
Signed-off-by: Arun Kumar K <arun.kk@samsung.com>
Acked-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Jeongtae Park 2012-10-03 22:19:11 -03:00 committed by Mauro Carvalho Chehab
parent 5b781e171e
commit f96f3cfa0b
15 changed files with 2678 additions and 169 deletions

View file

@ -165,12 +165,12 @@ config VIDEO_SAMSUNG_S5P_JPEG
This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec
config VIDEO_SAMSUNG_S5P_MFC
tristate "Samsung S5P MFC 5.1 Video Codec"
tristate "Samsung S5P MFC Video Codec"
depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
select VIDEOBUF2_DMA_CONTIG
default n
help
MFC 5.1 driver for V4L2.
MFC 5.1 and 6.x driver for V4L2
config VIDEO_MX2_EMMAPRP
tristate "MX2 eMMa-PrP support"

View file

@ -1,6 +1,6 @@
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o
s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.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_cmd.o
s5p-mfc-y += s5p_mfc_pm.o
s5p-mfc-y += s5p_mfc_opr_v5.o s5p_mfc_cmd_v5.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

View file

@ -147,6 +147,7 @@
#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 */
@ -216,6 +217,7 @@
#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
@ -380,6 +382,16 @@
#define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16
#define S5P_FIMV_R2H_CMD_ERR_RET 32
/* Dummy definition for MFCv6 compatibilty */
#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_WARNINGS_START 145
#define S5P_FIMV_ERR_DEC_MASK 0xFFFF
@ -435,4 +447,13 @@
#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 */

View file

@ -330,12 +330,14 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_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;
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) {
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);
@ -494,10 +496,28 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
ctx->dpb_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 (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->v4l2_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);
@ -526,7 +546,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
clear_work_bit(ctx);
if (err == 0) {
ctx->state = MFCINST_RUNNING;
if (!ctx->dpb_flush_flag) {
if (!ctx->dpb_flush_flag && ctx->head_processed) {
spin_lock_irqsave(&dev->irqlock, flags);
if (!list_empty(&ctx->src_queue)) {
src_buf = list_entry(ctx->src_queue.next,
@ -1071,6 +1091,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
ret = -ENODEV;
goto err_res;
}
dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r",
match_child);
if (!dev->mem_dev_r) {
@ -1301,12 +1322,47 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = {
.port_num = MFC_NUM_PORTS,
.buf_size = &buf_size_v5,
.buf_align = &mfc_buf_align_v5,
.mclk_name = "sclk_mfc",
.fw_name = "s5p-mfc.fw",
};
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,
};
struct s5p_mfc_buf_size buf_size_v6 = {
.fw = MAX_FW_SIZE_V6,
.cpb = MAX_CPB_SIZE_V6,
.priv = &mfc_buf_size_v6,
};
struct s5p_mfc_buf_align mfc_buf_align_v6 = {
.base = 0,
};
static struct s5p_mfc_variant mfc_drvdata_v6 = {
.version = MFC_VERSION_V6,
.port_num = MFC_NUM_PORTS_V6,
.buf_size = &buf_size_v6,
.buf_align = &mfc_buf_align_v6,
.mclk_name = "aclk_333",
.fw_name = "s5p-mfc-v6.fw",
};
static struct platform_device_id mfc_driver_ids[] = {
{
.name = "s5p-mfc",
.driver_data = (unsigned long)&mfc_drvdata_v5,
}, {
.name = "s5p-mfc-v5",
.driver_data = (unsigned long)&mfc_drvdata_v5,
}, {
.name = "s5p-mfc-v6",
.driver_data = (unsigned long)&mfc_drvdata_v6,
},
{},
};

View file

@ -14,11 +14,16 @@
#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)
{
s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5();
if (IS_MFCV6(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;
}

View file

@ -0,0 +1,156 @@
/*
* linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c
*
* Copyright (c) 2012 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#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"
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;
}
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;
s5p_mfc_hw_call(dev->mfc_ops, alloc_dev_context_buffer, dev);
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);
}
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);
}
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 */
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_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;
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 */
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;
}

View file

@ -0,0 +1,20 @@
/*
* linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h
*
* Copyright (C) 2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#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_ */

View file

@ -16,13 +16,14 @@
#ifndef S5P_MFC_COMMON_H_
#define S5P_MFC_COMMON_H_
#include "regs-mfc.h"
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
#include "regs-mfc.h"
#include "regs-mfc-v6.h"
/* Definitions related to MFC memory */
@ -206,6 +207,14 @@ struct s5p_mfc_buf_size_v5 {
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 other_enc_ctx;
};
struct s5p_mfc_buf_size {
unsigned int fw;
unsigned int cpb;
@ -221,6 +230,8 @@ struct s5p_mfc_variant {
unsigned int port_num;
struct s5p_mfc_buf_size *buf_size;
struct s5p_mfc_buf_align *buf_align;
char *mclk_name;
char *fw_name;
};
/**
@ -277,6 +288,7 @@ struct s5p_mfc_priv_buf {
* @watchdog_work: worker for the watchdog
* @alloc_ctx: videobuf2 allocator contexts for two memory banks
* @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
@ -318,6 +330,7 @@ struct s5p_mfc_dev {
void *alloc_ctx[2];
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;
@ -354,6 +367,22 @@ struct s5p_mfc_h264_enc_params {
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];
};
/**
@ -396,6 +425,7 @@ struct s5p_mfc_enc_params {
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;
@ -461,6 +491,8 @@ struct s5p_mfc_codec_ops {
* 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_buf: handle to memory allocated for temporary buffers from
* memory bank 1
* @bank1_phys: address of the temporary buffers from memory bank 1
@ -485,14 +517,20 @@ struct s5p_mfc_codec_ops {
* @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
* @dpb_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
* @ref_queue_cnt: number of the buffers in the reference list
@ -541,6 +579,7 @@ struct s5p_mfc_ctx {
unsigned long consumed_stream;
unsigned int dpb_flush_flag;
unsigned int head_processed;
/* Buffers */
void *bank1_buf;
@ -570,10 +609,11 @@ struct s5p_mfc_ctx {
int display_delay;
int display_delay_enable;
int after_packed_pb;
int sei_fp_parse;
int dpb_count;
int total_dpb_count;
int mv_count;
/* Buffers */
struct s5p_mfc_priv_buf ctx;
struct s5p_mfc_priv_buf dsc;
@ -582,16 +622,28 @@ struct s5p_mfc_ctx {
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;
struct s5p_mfc_codec_ops *c_ops;
struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS];
struct v4l2_ctrl_handler ctrl_handler;
unsigned int frame_tag;
size_t scratch_buf_size;
};
/*
@ -637,4 +689,9 @@ 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);
#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(dev) (dev->variant->version >= 0x60 ? 1 : 0)
#endif /* S5P_MFC_COMMON_H_ */

View file

@ -37,8 +37,9 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
/* Firmare has to be present as a separate file or compiled
* into kernel. */
mfc_debug_enter();
err = request_firmware((const struct firmware **)&fw_blob,
"s5p-mfc.fw", dev->v4l2_dev.dev);
dev->variant->fw_name, dev->v4l2_dev.dev);
if (err != 0) {
mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
return -EINVAL;
@ -82,32 +83,37 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev)
return -EIO;
}
dev->bank1 = s5p_mfc_bitproc_phys;
b_base = vb2_dma_contig_memops.alloc(
dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BASE_ALIGN_ORDER);
if (IS_ERR(b_base)) {
vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
s5p_mfc_bitproc_phys = 0;
s5p_mfc_bitproc_buf = NULL;
mfc_err("Allocating bank2 base failed\n");
release_firmware(fw_blob);
return -ENOMEM;
if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) {
b_base = vb2_dma_contig_memops.alloc(
dev->alloc_ctx[MFC_BANK2_ALLOC_CTX],
1 << MFC_BASE_ALIGN_ORDER);
if (IS_ERR(b_base)) {
vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
s5p_mfc_bitproc_phys = 0;
s5p_mfc_bitproc_buf = NULL;
mfc_err("Allocating bank2 base failed\n");
release_firmware(fw_blob);
return -ENOMEM;
}
bank2_base_phys = s5p_mfc_mem_cookie(
dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base);
vb2_dma_contig_memops.put(b_base);
if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
s5p_mfc_bitproc_phys = 0;
s5p_mfc_bitproc_buf = NULL;
release_firmware(fw_blob);
return -EIO;
}
/* 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.
*/
dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER);
} else {
dev->bank2 = dev->bank1;
}
bank2_base_phys = s5p_mfc_mem_cookie(
dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base);
vb2_dma_contig_memops.put(b_base);
if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) {
mfc_err("The base memory for bank 2 is not aligned to 128KB\n");
vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf);
s5p_mfc_bitproc_phys = 0;
s5p_mfc_bitproc_buf = NULL;
release_firmware(fw_blob);
return -EIO;
}
/* 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.
*/
dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER);
memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size);
wmb();
release_firmware(fw_blob);
@ -124,8 +130,9 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
/* Firmare has to be present as a separate file or compiled
* into kernel. */
mfc_debug_enter();
err = request_firmware((const struct firmware **)&fw_blob,
"s5p-mfc.fw", dev->v4l2_dev.dev);
dev->variant->fw_name, dev->v4l2_dev.dev);
if (err != 0) {
mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
return -EINVAL;
@ -166,46 +173,81 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev)
{
unsigned int mc_status;
unsigned long timeout;
int i;
mfc_debug_enter();
/* 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;
}
if (IS_MFCV6(dev)) {
/* Reset IP */
/* except RISC, reset */
mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6);
/* reset release */
mfc_write(dev, 0x0, S5P_FIMV_MFC_RESET_V6);
mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
/* 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);
} while (mc_status & 0x3);
for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++)
mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4));
/* Reset */
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_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)
{
mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2);
if (IS_MFCV6(dev)) {
mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6);
mfc_debug(2, "Base Address : %08x\n", dev->bank1);
} else {
mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
mfc_debug(2, "Bank1: %08x, Bank2: %08x\n",
dev->bank1, dev->bank2);
}
}
static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
{
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);
if (IS_MFCV6(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 */
@ -233,7 +275,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
s5p_mfc_clear_cmds(dev);
/* 3. Release reset signal to the RISC */
s5p_mfc_clean_dev_int_flags(dev);
mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
if (IS_MFCV6(dev))
mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
else
mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
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");
@ -267,7 +312,11 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
s5p_mfc_clock_off();
return -EIO;
}
ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
if (IS_MFCV6(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();
@ -342,7 +391,10 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
return ret;
}
/* 4. Release reset signal to the RISC */
mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
if (IS_MFCV6(dev))
mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
else
mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
mfc_err("Failed to load firmware\n");

View file

@ -31,9 +31,16 @@
#include "s5p_mfc_pm.h"
#define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264
#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT
#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT_16X16
static struct s5p_mfc_fmt formats[] = {
{
.name = "4:2:0 2 Planes 16x16 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT_16X16,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
},
{
.name = "4:2:0 2 Planes 64x32 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT,
@ -42,67 +49,88 @@ static struct s5p_mfc_fmt formats[] = {
.num_planes = 2,
},
{
.name = "4:2:0 2 Planes",
.fourcc = V4L2_PIX_FMT_NV12M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
.name = "4:2:0 2 Planes Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
},
{
.name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
.codec_mode = S5P_MFC_CODEC_H264_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
.name = "4:2:0 2 Planes Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV21M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
},
{
.name = "H263 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H263,
.codec_mode = S5P_MFC_CODEC_H263_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
.name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
.codec_mode = S5P_MFC_CODEC_H264_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
{
.name = "MPEG1 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG1,
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
.name = "H264/MVC Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264_MVC,
.codec_mode = S5P_MFC_CODEC_H264_MVC_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
{
.name = "MPEG2 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG2,
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
.name = "H263 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H263,
.codec_mode = S5P_MFC_CODEC_H263_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
{
.name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
.name = "MPEG1 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG1,
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
{
.name = "XviD Encoded Stream",
.fourcc = V4L2_PIX_FMT_XVID,
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
.name = "MPEG2 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG2,
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
{
.name = "VC1 Encoded Stream",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
.codec_mode = S5P_MFC_CODEC_VC1_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
.name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
{
.name = "VC1 RCV Encoded Stream",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
.codec_mode = S5P_MFC_CODEC_VC1RCV_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
.name = "XviD Encoded Stream",
.fourcc = V4L2_PIX_FMT_XVID,
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
{
.name = "VC1 Encoded Stream",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
.codec_mode = S5P_MFC_CODEC_VC1_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
{
.name = "VC1 RCV Encoded Stream",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
.codec_mode = S5P_MFC_CODEC_VC1RCV_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
{
.name = "VP8 Encoded Stream",
.fourcc = V4L2_PIX_FMT_VP8,
.codec_mode = S5P_MFC_CODEC_VP8_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
},
};
@ -343,21 +371,36 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
/* 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;
if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
mfc_err("This node supports decoding only\n");
return -EINVAL;
}
fmt = find_format(f, MFC_FMT_DEC);
if (!fmt) {
mfc_err("Unsupported format\n");
return -EINVAL;
}
if (fmt->type != MFC_FMT_DEC) {
mfc_err("\n");
return -EINVAL;
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 (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
mfc_err("Not supported format.\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 (IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
mfc_err("Not supported format.\n");
return -EINVAL;
} else if (!IS_MFCV6(dev) &&
(fmt->fourcc != V4L2_PIX_FMT_NV12MT)) {
mfc_err("Not supported format.\n");
return -EINVAL;
}
}
return 0;
}
@ -380,6 +423,27 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
ret = -EBUSY;
goto out;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
fmt = find_format(f, MFC_FMT_RAW);
if (!fmt) {
mfc_err("Unsupported format for source.\n");
return -EINVAL;
}
if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) {
mfc_err("Not supported format.\n");
return -EINVAL;
} else if (IS_MFCV6(dev) &&
(fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
mfc_err("Not supported format.\n");
return -EINVAL;
}
ctx->dst_fmt = fmt;
mfc_debug_leave();
return ret;
} else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
mfc_err("Wrong type error for S_FMT : %d", f->type);
return -EINVAL;
}
fmt = find_format(f, MFC_FMT_DEC);
if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) {
mfc_err("Unknown codec\n");
@ -392,6 +456,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
ret = -EINVAL;
goto out;
}
if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
mfc_err("Not supported format.\n");
return -EINVAL;
}
ctx->src_fmt = fmt;
ctx->codec_mode = fmt->codec_mode;
mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
@ -756,6 +824,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
void *allocators[])
{
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 */
@ -791,7 +860,13 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
psize[0] = ctx->luma_size;
psize[1] = ctx->chroma_size;
allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
if (IS_MFCV6(dev))
allocators[0] =
ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
else
allocators[0] =
ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
ctx->state == MFCINST_INIT) {

View file

@ -36,39 +36,53 @@
static struct s5p_mfc_fmt formats[] = {
{
.name = "4:2:0 2 Planes 64x32 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
.name = "4:2:0 2 Planes 16x16 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT_16X16,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
},
{
.name = "4:2:0 2 Planes",
.fourcc = V4L2_PIX_FMT_NV12M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
.name = "4:2:0 2 Planes 64x32 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
},
{
.name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
.codec_mode = S5P_MFC_CODEC_H264_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
.name = "4:2:0 2 Planes Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
},
{
.name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
.codec_mode = S5P_MFC_CODEC_MPEG4_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
.name = "4:2:0 2 Planes Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV21M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
},
{
.name = "H263 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H263,
.codec_mode = S5P_MFC_CODEC_H263_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
.name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
.codec_mode = S5P_MFC_CODEC_H264_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
},
{
.name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
.codec_mode = S5P_MFC_CODEC_MPEG4_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
},
{
.name = "H263 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H263,
.codec_mode = S5P_MFC_CODEC_H263_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
},
};
@ -576,7 +590,8 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
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 &&
if ((ctx->state == MFCINST_RUNNING ||
ctx->state == MFCINST_HEAD_PARSED) &&
ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
return 1;
/* context is ready to encode remaining frames */
@ -645,10 +660,19 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
spin_unlock_irqrestore(&dev->irqlock, flags);
}
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);
if (IS_MFCV6(dev)) {
ctx->state = MFCINST_HEAD_PARSED; /* for INIT_BUFFER cmd */
} else {
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);
}
if (IS_MFCV6(dev))
ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops,
get_enc_dpb_count, dev);
return 0;
}
@ -965,6 +989,17 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
mfc_err("failed to set output format\n");
return -EINVAL;
}
if (!IS_MFCV6(dev) &&
(fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)) {
mfc_err("Not supported format.\n");
return -EINVAL;
} else if (IS_MFCV6(dev) &&
(fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
mfc_err("Not supported format.\n");
return -EINVAL;
}
if (fmt->num_planes != pix_fmt_mp->num_planes) {
mfc_err("failed to set output format\n");
ret = -EINVAL;
@ -998,6 +1033,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
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;
@ -1017,13 +1053,16 @@ static int vidioc_reqbufs(struct file *file, void *priv,
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;
if (!IS_MFCV6(dev)) {
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 (ctx->output_state != QUEUE_FREE) {
@ -1286,6 +1325,13 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
p->codec.h264.profile =
S5P_FIMV_ENC_PROFILE_H264_BASELINE;
break;
case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
if (IS_MFCV6(dev))
p->codec.h264.profile =
S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE;
else
ret = -EINVAL;
break;
default:
ret = -EINVAL;
}
@ -1559,6 +1605,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
unsigned int psize[], void *allocators[])
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
struct s5p_mfc_dev *dev = ctx->dev;
if (ctx->state != MFCINST_GOT_INST) {
mfc_err("inavlid state: %d\n", ctx->state);
@ -1587,8 +1634,17 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
*buf_count = MFC_MAX_BUFFERS;
psize[0] = ctx->luma_size;
psize[1] = ctx->chroma_size;
allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
if (IS_MFCV6(dev)) {
allocators[0] =
ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
allocators[1] =
ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX];
} else {
allocators[0] =
ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
allocators[1] =
ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX];
}
} else {
mfc_err("inavlid queue type: %d\n", vq->type);
return -EINVAL;

View file

@ -14,12 +14,18 @@
#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)
{
s5p_mfc_ops = s5p_mfc_init_hw_ops_v5();
dev->warn_start = S5P_FIMV_ERR_WARNINGS_START;
if (IS_MFCV6(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;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,50 @@
/*
* 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/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#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)
/* 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
/* Definitions for shared memory compatibility */
#define PIC_TIME_TOP_V6 S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6
#define PIC_TIME_BOT_V6 S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6
#define CROP_INFO_H_V6 S5P_FIMV_D_DISPLAY_CROP_INFO1_V6
#define CROP_INFO_V_V6 S5P_FIMV_D_DISPLAY_CROP_INFO2_V6
struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void);
#endif /* S5P_MFC_OPR_V6_H_ */

View file

@ -20,7 +20,6 @@
#include "s5p_mfc_debug.h"
#include "s5p_mfc_pm.h"
#define MFC_CLKNAME "sclk_mfc"
#define MFC_GATE_CLK_NAME "mfc"
#define CLK_DEBUG
@ -51,7 +50,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
goto err_p_ip_clk;
}
pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME);
pm->clock = clk_get(&dev->plat_dev->dev, dev->variant->mclk_name);
if (IS_ERR(pm->clock)) {
mfc_err("Failed to get MFC clock\n");
ret = PTR_ERR(pm->clock);