Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 43a1ea1f authored by Arun Kumar K's avatar Arun Kumar K Committed by Mauro Carvalho Chehab
Browse files

[media] s5p-mfc: Update MFCv5 driver for callback based architecture



Modifies the driver to use a callback based architecture
for hardware dependent calls. This architecture is suitable
for supporting co-existence with newer versions of MFC hardware.

Signed-off-by: default avatarArun Kumar K <arun.kk@samsung.com>
Signed-off-by: default avatarNaveen Krishna Chatradhi <ch.naveen@samsung.com>
Acked-by: default avatarKamil Debski <k.debski@samsung.com>
Signed-off-by: default avatarSylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 77a788fc
Loading
Loading
Loading
Loading
+3 −2
Original line number Original line Diff line number Diff line
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o
s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr_v5.o
s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o
s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o
s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o
s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd_v5.o
s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o
s5p-mfc-y += s5p_mfc_pm.o
s5p-mfc-y += s5p_mfc_pm.o
s5p-mfc-y += s5p_mfc_opr_v5.o s5p_mfc_cmd_v5.o
+91 −61
Original line number Original line Diff line number Diff line
@@ -22,13 +22,14 @@
#include <media/v4l2-event.h>
#include <media/v4l2-event.h>
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-core.h>
#include "regs-mfc.h"
#include "s5p_mfc_common.h"
#include "s5p_mfc_ctrl.h"
#include "s5p_mfc_ctrl.h"
#include "s5p_mfc_debug.h"
#include "s5p_mfc_debug.h"
#include "s5p_mfc_dec.h"
#include "s5p_mfc_dec.h"
#include "s5p_mfc_enc.h"
#include "s5p_mfc_enc.h"
#include "s5p_mfc_intr.h"
#include "s5p_mfc_intr.h"
#include "s5p_mfc_opr_v5.h"
#include "s5p_mfc_opr.h"
#include "s5p_mfc_cmd.h"
#include "s5p_mfc_pm.h"
#include "s5p_mfc_pm.h"


#define S5P_MFC_NAME		"s5p-mfc"
#define S5P_MFC_NAME		"s5p-mfc"
@@ -148,10 +149,12 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work)
		if (!ctx)
		if (!ctx)
			continue;
			continue;
		ctx->state = MFCINST_ERROR;
		ctx->state = MFCINST_ERROR;
		s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
		s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
				&ctx->vq_dst);
		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
				&ctx->vq_src);
		clear_work_bit(ctx);
		clear_work_bit(ctx);
		wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0);
		wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0);
	}
	}
	clear_bit(0, &dev->hw_lock);
	clear_bit(0, &dev->hw_lock);
	spin_unlock_irqrestore(&dev->irqlock, flags);
	spin_unlock_irqrestore(&dev->irqlock, flags);
@@ -198,6 +201,7 @@ static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev)
static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
{
{
	struct s5p_mfc_buf *dst_buf;
	struct s5p_mfc_buf *dst_buf;
	struct s5p_mfc_dev *dev = ctx->dev;


	ctx->state = MFCINST_FINISHED;
	ctx->state = MFCINST_FINISHED;
	ctx->sequence++;
	ctx->sequence++;
@@ -212,8 +216,8 @@ static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx)
		ctx->dst_queue_cnt--;
		ctx->dst_queue_cnt--;
		dst_buf->b->v4l2_buf.sequence = (ctx->sequence++);
		dst_buf->b->v4l2_buf.sequence = (ctx->sequence++);


		if (s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP) ==
		if (s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_top, ctx) ==
			s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT))
			s5p_mfc_hw_call(dev->mfc_ops, get_pic_type_bot, ctx))
			dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
			dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
		else
		else
			dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED;
			dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED;
@@ -227,8 +231,11 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
{
{
	struct s5p_mfc_dev *dev = ctx->dev;
	struct s5p_mfc_dev *dev = ctx->dev;
	struct s5p_mfc_buf  *dst_buf, *src_buf;
	struct s5p_mfc_buf  *dst_buf, *src_buf;
	size_t dec_y_addr = s5p_mfc_get_dec_y_adr();
	size_t dec_y_addr;
	unsigned int frame_type = s5p_mfc_get_frame_type();
	unsigned int frame_type;

	dec_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev);
	frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev);


	/* Copy timestamp / timecode from decoded src to dst and set
	/* Copy timestamp / timecode from decoded src to dst and set
	   appropraite flags */
	   appropraite flags */
@@ -264,10 +271,13 @@ 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_dev *dev = ctx->dev;
	struct s5p_mfc_buf  *dst_buf;
	struct s5p_mfc_buf  *dst_buf;
	size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr();
	size_t dspl_y_addr;
	unsigned int frame_type = s5p_mfc_get_frame_type();
	unsigned int frame_type;
	unsigned int index;
	unsigned int index;


	dspl_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_y_adr, dev);
	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 is same as previous then skip and do not dequeue */
	if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
	if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) {
		if (!ctx->after_packed_pb)
		if (!ctx->after_packed_pb)
@@ -284,8 +294,10 @@ static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err)
			list_del(&dst_buf->list);
			list_del(&dst_buf->list);
			ctx->dst_queue_cnt--;
			ctx->dst_queue_cnt--;
			dst_buf->b->v4l2_buf.sequence = ctx->sequence;
			dst_buf->b->v4l2_buf.sequence = ctx->sequence;
			if (s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP) ==
			if (s5p_mfc_hw_call(dev->mfc_ops,
				s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT))
					get_pic_type_top, ctx) ==
				s5p_mfc_hw_call(dev->mfc_ops,
					get_pic_type_bot, ctx))
				dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
				dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE;
			else
			else
				dst_buf->b->v4l2_buf.field =
				dst_buf->b->v4l2_buf.field =
@@ -316,21 +328,21 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,


	unsigned int index;
	unsigned int index;


	dst_frame_status = s5p_mfc_get_dspl_status()
	dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev)
				& S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
				& S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
	res_change = s5p_mfc_get_dspl_status()
	res_change = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev)
				& S5P_FIMV_DEC_STATUS_RESOLUTION_MASK;
				& S5P_FIMV_DEC_STATUS_RESOLUTION_MASK;
	mfc_debug(2, "Frame Status: %x\n", dst_frame_status);
	mfc_debug(2, "Frame Status: %x\n", dst_frame_status);
	if (ctx->state == MFCINST_RES_CHANGE_INIT)
	if (ctx->state == MFCINST_RES_CHANGE_INIT)
		ctx->state = MFCINST_RES_CHANGE_FLUSH;
		ctx->state = MFCINST_RES_CHANGE_FLUSH;
	if (res_change) {
	if (res_change) {
		ctx->state = MFCINST_RES_CHANGE_INIT;
		ctx->state = MFCINST_RES_CHANGE_INIT;
		s5p_mfc_clear_int_flags(dev);
		s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
		wake_up_ctx(ctx, reason, err);
		wake_up_ctx(ctx, reason, err);
		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
			BUG();
			BUG();
		s5p_mfc_clock_off();
		s5p_mfc_clock_off();
		s5p_mfc_try_run(dev);
		s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
		return;
		return;
	}
	}
	if (ctx->dpb_flush_flag)
	if (ctx->dpb_flush_flag)
@@ -364,9 +376,12 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
		&& !list_empty(&ctx->src_queue)) {
		&& !list_empty(&ctx->src_queue)) {
		src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
		src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
								list);
								list);
		ctx->consumed_stream += s5p_mfc_get_consumed_stream();
		ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops,
		if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC &&
						get_consumed_stream, dev);
			s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME
		if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC &&
			s5p_mfc_hw_call(dev->mfc_ops,
				get_dec_frame_type, dev) ==
					S5P_FIMV_DECODE_FRAME_P_FRAME
					&& ctx->consumed_stream + STUFF_BYTE <
					&& ctx->consumed_stream + STUFF_BYTE <
					src_buf->b->v4l2_planes[0].bytesused) {
					src_buf->b->v4l2_planes[0].bytesused) {
			/* Run MFC again on the same buffer */
			/* Run MFC again on the same buffer */
@@ -378,7 +393,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
			ctx->consumed_stream = 0;
			ctx->consumed_stream = 0;
			list_del(&src_buf->list);
			list_del(&src_buf->list);
			ctx->src_queue_cnt--;
			ctx->src_queue_cnt--;
			if (s5p_mfc_err_dec(err) > 0)
			if (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) > 0)
				vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR);
				vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR);
			else
			else
				vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE);
				vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE);
@@ -389,12 +404,12 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
	if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
	if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
				    || ctx->dst_queue_cnt < ctx->dpb_count)
				    || ctx->dst_queue_cnt < ctx->dpb_count)
		clear_work_bit(ctx);
		clear_work_bit(ctx);
	s5p_mfc_clear_int_flags(dev);
	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
	wake_up_ctx(ctx, reason, err);
	wake_up_ctx(ctx, reason, err);
	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
		BUG();
		BUG();
	s5p_mfc_clock_off();
	s5p_mfc_clock_off();
	s5p_mfc_try_run(dev);
	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
}
}


/* Error handling for interrupt */
/* Error handling for interrupt */
@@ -411,7 +426,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,


	dev = ctx->dev;
	dev = ctx->dev;
	mfc_err("Interrupt Error: %08x\n", err);
	mfc_err("Interrupt Error: %08x\n", err);
	s5p_mfc_clear_int_flags(dev);
	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
	wake_up_dev(dev, reason, err);
	wake_up_dev(dev, reason, err);


	/* Error recovery is dependent on the state of context */
	/* Error recovery is dependent on the state of context */
@@ -440,9 +455,11 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx,
		ctx->state = MFCINST_ERROR;
		ctx->state = MFCINST_ERROR;
		/* Mark all dst buffers as having an error */
		/* Mark all dst buffers as having an error */
		spin_lock_irqsave(&dev->irqlock, flags);
		spin_lock_irqsave(&dev->irqlock, flags);
		s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue,
				&ctx->vq_dst);
		/* Mark all src buffers as having an error */
		/* Mark all src buffers as having an error */
		s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
		s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
				&ctx->vq_src);
		spin_unlock_irqrestore(&dev->irqlock, flags);
		spin_unlock_irqrestore(&dev->irqlock, flags);
		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
			BUG();
			BUG();
@@ -469,8 +486,10 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
		if (ctx->c_ops->post_seq_start(ctx))
		if (ctx->c_ops->post_seq_start(ctx))
			mfc_err("post_seq_start() failed\n");
			mfc_err("post_seq_start() failed\n");
	} else {
	} else {
		ctx->img_width = s5p_mfc_get_img_width();
		ctx->img_width = s5p_mfc_hw_call(dev->mfc_ops, get_img_width,
		ctx->img_height = s5p_mfc_get_img_height();
				dev);
		ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height,
				dev);


		ctx->buf_width = ALIGN(ctx->img_width,
		ctx->buf_width = ALIGN(ctx->img_width,
						S5P_FIMV_NV12MT_HALIGN);
						S5P_FIMV_NV12MT_HALIGN);
@@ -506,18 +525,19 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
				guard_height, S5P_FIMV_DEC_BUF_ALIGN);
				guard_height, S5P_FIMV_DEC_BUF_ALIGN);
			ctx->mv_size = 0;
			ctx->mv_size = 0;
		}
		}
		ctx->dpb_count = s5p_mfc_get_dpb_count();
		ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count,
				dev);
		if (ctx->img_width == 0 || ctx->img_height == 0)
		if (ctx->img_width == 0 || ctx->img_height == 0)
			ctx->state = MFCINST_ERROR;
			ctx->state = MFCINST_ERROR;
		else
		else
			ctx->state = MFCINST_HEAD_PARSED;
			ctx->state = MFCINST_HEAD_PARSED;
	}
	}
	s5p_mfc_clear_int_flags(dev);
	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
	clear_work_bit(ctx);
	clear_work_bit(ctx);
	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
	if (test_and_clear_bit(0, &dev->hw_lock) == 0)
		BUG();
		BUG();
	s5p_mfc_clock_off();
	s5p_mfc_clock_off();
	s5p_mfc_try_run(dev);
	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
	wake_up_ctx(ctx, reason, err);
	wake_up_ctx(ctx, reason, err);
}
}


@@ -532,7 +552,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
	if (ctx == NULL)
	if (ctx == NULL)
		return;
		return;
	dev = ctx->dev;
	dev = ctx->dev;
	s5p_mfc_clear_int_flags(dev);
	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
	ctx->int_type = reason;
	ctx->int_type = reason;
	ctx->int_err = err;
	ctx->int_err = err;
	ctx->int_cond = 1;
	ctx->int_cond = 1;
@@ -559,7 +579,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
		s5p_mfc_clock_off();
		s5p_mfc_clock_off();


		wake_up(&ctx->queue);
		wake_up(&ctx->queue);
		s5p_mfc_try_run(dev);
		s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
	} else {
	} else {
		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
		if (test_and_clear_bit(0, &dev->hw_lock) == 0)
			BUG();
			BUG();
@@ -601,7 +621,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx,


	s5p_mfc_clock_off();
	s5p_mfc_clock_off();
	wake_up(&ctx->queue);
	wake_up(&ctx->queue);
	s5p_mfc_try_run(dev);
	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
}
}


/* Interrupt processing */
/* Interrupt processing */
@@ -617,81 +637,83 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
	atomic_set(&dev->watchdog_cnt, 0);
	atomic_set(&dev->watchdog_cnt, 0);
	ctx = dev->ctx[dev->curr_ctx];
	ctx = dev->ctx[dev->curr_ctx];
	/* Get the reason of interrupt and the error code */
	/* Get the reason of interrupt and the error code */
	reason = s5p_mfc_get_int_reason();
	reason = s5p_mfc_hw_call(dev->mfc_ops, get_int_reason, dev);
	err = s5p_mfc_get_int_err();
	err = s5p_mfc_hw_call(dev->mfc_ops, get_int_err, dev);
	mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err);
	mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err);
	switch (reason) {
	switch (reason) {
	case S5P_FIMV_R2H_CMD_ERR_RET:
	case S5P_MFC_R2H_CMD_ERR_RET:
		/* An error has occured */
		/* An error has occured */
		if (ctx->state == MFCINST_RUNNING &&
		if (ctx->state == MFCINST_RUNNING &&
			s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START)
			s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >=
				dev->warn_start)
			s5p_mfc_handle_frame(ctx, reason, err);
			s5p_mfc_handle_frame(ctx, reason, err);
		else
		else
			s5p_mfc_handle_error(ctx, reason, err);
			s5p_mfc_handle_error(ctx, reason, err);
		clear_bit(0, &dev->enter_suspend);
		clear_bit(0, &dev->enter_suspend);
		break;
		break;


	case S5P_FIMV_R2H_CMD_SLICE_DONE_RET:
	case S5P_MFC_R2H_CMD_SLICE_DONE_RET:
	case S5P_FIMV_R2H_CMD_FRAME_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) {
			if (ctx->c_ops->post_frame_start(ctx))
			if (ctx->c_ops->post_frame_start(ctx))
				mfc_err("post_frame_start() failed\n");
				mfc_err("post_frame_start() failed\n");
			s5p_mfc_clear_int_flags(dev);
			s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
			wake_up_ctx(ctx, reason, err);
			wake_up_ctx(ctx, reason, err);
			if (test_and_clear_bit(0, &dev->hw_lock) == 0)
			if (test_and_clear_bit(0, &dev->hw_lock) == 0)
				BUG();
				BUG();
			s5p_mfc_clock_off();
			s5p_mfc_clock_off();
			s5p_mfc_try_run(dev);
			s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
		} else {
		} else {
			s5p_mfc_handle_frame(ctx, reason, err);
			s5p_mfc_handle_frame(ctx, reason, err);
		}
		}
		break;
		break;


	case S5P_FIMV_R2H_CMD_SEQ_DONE_RET:
	case S5P_MFC_R2H_CMD_SEQ_DONE_RET:
		s5p_mfc_handle_seq_done(ctx, reason, err);
		s5p_mfc_handle_seq_done(ctx, reason, err);
		break;
		break;


	case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET:
	case S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET:
		ctx->inst_no = s5p_mfc_get_inst_no();
		ctx->inst_no = s5p_mfc_hw_call(dev->mfc_ops, get_inst_no, dev);
		ctx->state = MFCINST_GOT_INST;
		ctx->state = MFCINST_GOT_INST;
		clear_work_bit(ctx);
		clear_work_bit(ctx);
		wake_up(&ctx->queue);
		wake_up(&ctx->queue);
		goto irq_cleanup_hw;
		goto irq_cleanup_hw;


	case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET:
	case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET:
		clear_work_bit(ctx);
		clear_work_bit(ctx);
		ctx->state = MFCINST_FREE;
		ctx->state = MFCINST_FREE;
		wake_up(&ctx->queue);
		wake_up(&ctx->queue);
		goto irq_cleanup_hw;
		goto irq_cleanup_hw;


	case S5P_FIMV_R2H_CMD_SYS_INIT_RET:
	case S5P_MFC_R2H_CMD_SYS_INIT_RET:
	case S5P_FIMV_R2H_CMD_FW_STATUS_RET:
	case S5P_MFC_R2H_CMD_FW_STATUS_RET:
	case S5P_FIMV_R2H_CMD_SLEEP_RET:
	case S5P_MFC_R2H_CMD_SLEEP_RET:
	case S5P_FIMV_R2H_CMD_WAKEUP_RET:
	case S5P_MFC_R2H_CMD_WAKEUP_RET:
		if (ctx)
		if (ctx)
			clear_work_bit(ctx);
			clear_work_bit(ctx);
		s5p_mfc_clear_int_flags(dev);
		s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
		wake_up_dev(dev, reason, err);
		wake_up_dev(dev, reason, err);
		clear_bit(0, &dev->hw_lock);
		clear_bit(0, &dev->hw_lock);
		clear_bit(0, &dev->enter_suspend);
		clear_bit(0, &dev->enter_suspend);
		break;
		break;


	case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET:
	case S5P_MFC_R2H_CMD_INIT_BUFFERS_RET:
		s5p_mfc_handle_init_buffers(ctx, reason, err);
		s5p_mfc_handle_init_buffers(ctx, reason, err);
		break;
		break;


	case S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET:
	case S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET:
		s5p_mfc_handle_stream_complete(ctx, reason, err);
		s5p_mfc_handle_stream_complete(ctx, reason, err);
		break;
		break;


	default:
	default:
		mfc_debug(2, "Unknown int reason\n");
		mfc_debug(2, "Unknown int reason\n");
		s5p_mfc_clear_int_flags(dev);
		s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
	}
	}
	mfc_debug_leave();
	mfc_debug_leave();
	return IRQ_HANDLED;
	return IRQ_HANDLED;
irq_cleanup_hw:
irq_cleanup_hw:
	s5p_mfc_clear_int_flags(dev);
	s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
	ctx->int_type = reason;
	ctx->int_type = reason;
	ctx->int_err = err;
	ctx->int_err = err;
	ctx->int_cond = 1;
	ctx->int_cond = 1;
@@ -700,7 +722,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)


	s5p_mfc_clock_off();
	s5p_mfc_clock_off();


	s5p_mfc_try_run(dev);
	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
	mfc_debug(2, "Exit via irq_cleanup_hw\n");
	mfc_debug(2, "Exit via irq_cleanup_hw\n");
	return IRQ_HANDLED;
	return IRQ_HANDLED;
}
}
@@ -748,6 +770,7 @@ static int s5p_mfc_open(struct file *file)
	if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
	if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
		ctx->type = MFCINST_DECODER;
		ctx->type = MFCINST_DECODER;
		ctx->c_ops = get_dec_codec_ops();
		ctx->c_ops = get_dec_codec_ops();
		s5p_mfc_dec_init(ctx);
		/* Setup ctrl handler */
		/* Setup ctrl handler */
		ret = s5p_mfc_dec_ctrls_setup(ctx);
		ret = s5p_mfc_dec_ctrls_setup(ctx);
		if (ret) {
		if (ret) {
@@ -760,6 +783,7 @@ static int s5p_mfc_open(struct file *file)
		/* only for encoder */
		/* only for encoder */
		INIT_LIST_HEAD(&ctx->ref_queue);
		INIT_LIST_HEAD(&ctx->ref_queue);
		ctx->ref_queue_cnt = 0;
		ctx->ref_queue_cnt = 0;
		s5p_mfc_enc_init(ctx);
		/* Setup ctrl handler */
		/* Setup ctrl handler */
		ret = s5p_mfc_enc_ctrls_setup(ctx);
		ret = s5p_mfc_enc_ctrls_setup(ctx);
		if (ret) {
		if (ret) {
@@ -885,19 +909,20 @@ static int s5p_mfc_release(struct file *file)
		ctx->state = MFCINST_RETURN_INST;
		ctx->state = MFCINST_RETURN_INST;
		set_work_bit_irqsave(ctx);
		set_work_bit_irqsave(ctx);
		s5p_mfc_clean_ctx_int_flags(ctx);
		s5p_mfc_clean_ctx_int_flags(ctx);
		s5p_mfc_try_run(dev);
		s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
		/* Wait until instance is returned or timeout occured */
		/* Wait until instance is returned or timeout occured */
		if (s5p_mfc_wait_for_done_ctx
		if (s5p_mfc_wait_for_done_ctx
		    (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) {
		    (ctx, S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)) {
			s5p_mfc_clock_off();
			s5p_mfc_clock_off();
			mfc_err("Err returning instance\n");
			mfc_err("Err returning instance\n");
		}
		}
		mfc_debug(2, "After free instance\n");
		mfc_debug(2, "After free instance\n");
		/* Free resources */
		/* Free resources */
		s5p_mfc_release_codec_buffers(ctx);
		s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
		s5p_mfc_release_instance_buffer(ctx);
		s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
		if (ctx->type == MFCINST_DECODER)
		if (ctx->type == MFCINST_DECODER)
			s5p_mfc_release_dec_desc_buffer(ctx);
			s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer,
					ctx);


		ctx->inst_no = MFC_NO_INSTANCE_SET;
		ctx->inst_no = MFC_NO_INSTANCE_SET;
	}
	}
@@ -909,6 +934,7 @@ static int s5p_mfc_release(struct file *file)
		mfc_debug(2, "Last instance - release firmware\n");
		mfc_debug(2, "Last instance - release firmware\n");
		/* reset <-> F/W release */
		/* reset <-> F/W release */
		s5p_mfc_reset(dev);
		s5p_mfc_reset(dev);
		s5p_mfc_deinit_hw(dev);
		s5p_mfc_release_firmware(dev);
		s5p_mfc_release_firmware(dev);
		del_timer_sync(&dev->watchdog_timer);
		del_timer_sync(&dev->watchdog_timer);
		if (s5p_mfc_power_off() < 0)
		if (s5p_mfc_power_off() < 0)
@@ -1159,6 +1185,10 @@ static int s5p_mfc_probe(struct platform_device *pdev)
	dev->watchdog_timer.data = (unsigned long)dev;
	dev->watchdog_timer.data = (unsigned long)dev;
	dev->watchdog_timer.function = s5p_mfc_watchdog;
	dev->watchdog_timer.function = s5p_mfc_watchdog;


	/* Initialize HW ops and commands based on MFC version */
	s5p_mfc_init_hw_ops(dev);
	s5p_mfc_init_hw_cmds(dev);

	pr_debug("%s--\n", __func__);
	pr_debug("%s--\n", __func__);
	return 0;
	return 0;


+24 −0
Original line number Original line Diff line number Diff line
/*
 * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.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_cmd.h"
#include "s5p_mfc_common.h"
#include "s5p_mfc_debug.h"
#include "s5p_mfc_cmd_v5.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();
	dev->mfc_cmds = s5p_mfc_cmds;
}
+35 −0
Original line number Original line Diff line number Diff line
/*
 * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h
 *
 * 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.
 */

#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_ */
+61 −15
Original line number Original line Diff line number Diff line
/*
/*
 * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c
 * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
 *
 *
 * Copyright (C) 2011 Samsung Electronics Co., Ltd.
 * Copyright (C) 2011 Samsung Electronics Co., Ltd.
 *		http://www.samsung.com/
 *		http://www.samsung.com/
@@ -11,12 +11,12 @@
 */
 */


#include "regs-mfc.h"
#include "regs-mfc.h"
#include "s5p_mfc_cmd_v5.h"
#include "s5p_mfc_cmd.h"
#include "s5p_mfc_common.h"
#include "s5p_mfc_common.h"
#include "s5p_mfc_debug.h"
#include "s5p_mfc_debug.h"


/* This function is used to send a command to the MFC */
/* This function is used to send a command to the MFC */
static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd,
int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd,
				struct s5p_mfc_cmd_args *args)
				struct s5p_mfc_cmd_args *args)
{
{
	int cur_cmd;
	int cur_cmd;
@@ -41,35 +41,37 @@ static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd,
}
}


/* Initialize the MFC */
/* Initialize the MFC */
int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev)
int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev)
{
{
	struct s5p_mfc_cmd_args h2r_args;
	struct s5p_mfc_cmd_args h2r_args;


	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	h2r_args.arg[0] = dev->fw_size;
	h2r_args.arg[0] = dev->fw_size;
	return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args);
	return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT,
			&h2r_args);
}
}


/* Suspend the MFC hardware */
/* Suspend the MFC hardware */
int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev)
int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev)
{
{
	struct s5p_mfc_cmd_args h2r_args;
	struct s5p_mfc_cmd_args h2r_args;


	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
	return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
}
}


/* Wake up the MFC hardware */
/* Wake up the MFC hardware */
int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev)
int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev)
{
{
	struct s5p_mfc_cmd_args h2r_args;
	struct s5p_mfc_cmd_args h2r_args;


	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args);
	return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_WAKEUP,
			&h2r_args);
}
}




int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
{
{
	struct s5p_mfc_dev *dev = ctx->dev;
	struct s5p_mfc_dev *dev = ctx->dev;
	struct s5p_mfc_cmd_args h2r_args;
	struct s5p_mfc_cmd_args h2r_args;
@@ -79,11 +81,41 @@ int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
	mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode);
	mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode);
	dev->curr_ctx = ctx->num;
	dev->curr_ctx = ctx->num;
	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	h2r_args.arg[0] = ctx->codec_mode;
	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[1] = 0; /* no crc & no pixelcache */
	h2r_args.arg[2] = ctx->ctx_ofs;
	h2r_args.arg[2] = ctx->ctx_ofs;
	h2r_args.arg[3] = ctx->ctx_size;
	h2r_args.arg[3] = ctx->ctx_size;
	ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE,
	ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE,
								&h2r_args);
								&h2r_args);
	if (ret) {
	if (ret) {
		mfc_err("Failed to create a new instance\n");
		mfc_err("Failed to create a new instance\n");
@@ -92,7 +124,7 @@ int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx)
	return ret;
	return ret;
}
}


int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
{
{
	struct s5p_mfc_dev *dev = ctx->dev;
	struct s5p_mfc_dev *dev = ctx->dev;
	struct s5p_mfc_cmd_args h2r_args;
	struct s5p_mfc_cmd_args h2r_args;
@@ -108,7 +140,7 @@ int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
	dev->curr_ctx = ctx->num;
	dev->curr_ctx = ctx->num;
	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
	h2r_args.arg[0] = ctx->inst_no;
	h2r_args.arg[0] = ctx->inst_no;
	ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
	ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
								&h2r_args);
								&h2r_args);
	if (ret) {
	if (ret) {
		mfc_err("Failed to return an instance\n");
		mfc_err("Failed to return an instance\n");
@@ -118,3 +150,17 @@ int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx)
	return 0;
	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;
}
Loading