diff options
author | Arun Kumar K <arun.kk@samsung.com> | 2012-10-03 22:19:08 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-10-05 22:53:37 -0300 |
commit | 43a1ea1f90382a6a8fcf5ed94835b8518ebdefc8 (patch) | |
tree | 69489808e3fdb9694540cb135f3d7aeaa0ad43f9 | |
parent | 77a788fc2d4089c64eb355a004f1f16b22eb3ab1 (diff) |
[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: Arun Kumar K <arun.kk@samsung.com>
Signed-off-by: Naveen Krishna Chatradhi <ch.naveen@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>
18 files changed, 852 insertions, 326 deletions
diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile index 39496b806b1..cfb9ee9f543 100644 --- a/drivers/media/platform/s5p-mfc/Makefile +++ b/drivers/media/platform/s5p-mfc/Makefile @@ -1,5 +1,6 @@ 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_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_opr_v5.o s5p_mfc_cmd_v5.o diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 74bb2848284..d711b0f7420 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -22,13 +22,14 @@ #include <media/v4l2-event.h> #include <linux/workqueue.h> #include <media/videobuf2-core.h> -#include "regs-mfc.h" +#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_opr_v5.h" +#include "s5p_mfc_opr.h" +#include "s5p_mfc_cmd.h" #include "s5p_mfc_pm.h" #define S5P_MFC_NAME "s5p-mfc" @@ -148,10 +149,12 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) 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); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->dst_queue, + &ctx->vq_dst); + s5p_mfc_hw_call(dev->mfc_ops, cleanup_queue, &ctx->src_queue, + &ctx->vq_src); 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); 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) { struct s5p_mfc_buf *dst_buf; + struct s5p_mfc_dev *dev = ctx->dev; ctx->state = MFCINST_FINISHED; ctx->sequence++; @@ -212,8 +216,8 @@ static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = (ctx->sequence++); - if (s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP) == - s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT)) + 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->v4l2_buf.field = V4L2_FIELD_NONE; else 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_buf *dst_buf, *src_buf; - size_t dec_y_addr = s5p_mfc_get_dec_y_adr(); - unsigned int frame_type = s5p_mfc_get_frame_type(); + size_t dec_y_addr; + 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 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_buf *dst_buf; - size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr(); - unsigned int frame_type = s5p_mfc_get_frame_type(); + size_t dspl_y_addr; + unsigned int frame_type; 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_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { 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); ctx->dst_queue_cnt--; dst_buf->b->v4l2_buf.sequence = ctx->sequence; - if (s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP) == - s5p_mfc_read_info_v5(ctx, PIC_TIME_BOT)) + 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->v4l2_buf.field = V4L2_FIELD_NONE; else dst_buf->b->v4l2_buf.field = @@ -316,21 +328,21 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, 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; - 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; 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) { 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); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return; } 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)) { src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); - ctx->consumed_stream += s5p_mfc_get_consumed_stream(); - if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC && - s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME + ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops, + get_consumed_stream, dev); + 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 < src_buf->b->v4l2_planes[0].bytesused) { /* 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; list_del(&src_buf->list); 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); else vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE); @@ -389,12 +404,12 @@ leave_handle_frame: if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) || ctx->dst_queue_cnt < ctx->dpb_count) 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); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Error handling for interrupt */ @@ -411,7 +426,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, dev = ctx->dev; 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); /* 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; /* Mark all dst buffers as having an error */ 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 */ - 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); if (test_and_clear_bit(0, &dev->hw_lock) == 0) 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)) mfc_err("post_seq_start() failed\n"); } else { - ctx->img_width = s5p_mfc_get_img_width(); - ctx->img_height = s5p_mfc_get_img_height(); + 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); ctx->buf_width = ALIGN(ctx->img_width, 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); 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) ctx->state = MFCINST_ERROR; else 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); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); 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); } @@ -532,7 +552,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, if (ctx == NULL) return; 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_err = err; ctx->int_cond = 1; @@ -559,7 +579,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); @@ -601,7 +621,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx, s5p_mfc_clock_off(); wake_up(&ctx->queue); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } /* Interrupt processing */ @@ -617,81 +637,83 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) atomic_set(&dev->watchdog_cnt, 0); ctx = dev->ctx[dev->curr_ctx]; /* Get the reason of interrupt and the error code */ - reason = s5p_mfc_get_int_reason(); - err = s5p_mfc_get_int_err(); + 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_FIMV_R2H_CMD_ERR_RET: + case S5P_MFC_R2H_CMD_ERR_RET: /* An error has occured */ 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); else s5p_mfc_handle_error(ctx, reason, err); clear_bit(0, &dev->enter_suspend); break; - case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: - case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: + 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"); - s5p_mfc_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); if (test_and_clear_bit(0, &dev->hw_lock) == 0) BUG(); s5p_mfc_clock_off(); - s5p_mfc_try_run(dev); + s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { s5p_mfc_handle_frame(ctx, reason, err); } 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); break; - case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: - ctx->inst_no = s5p_mfc_get_inst_no(); + 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; clear_work_bit(ctx); wake_up(&ctx->queue); goto irq_cleanup_hw; - case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: + case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET: clear_work_bit(ctx); ctx->state = MFCINST_FREE; wake_up(&ctx->queue); goto irq_cleanup_hw; - case S5P_FIMV_R2H_CMD_SYS_INIT_RET: - case S5P_FIMV_R2H_CMD_FW_STATUS_RET: - case S5P_FIMV_R2H_CMD_SLEEP_RET: - case S5P_FIMV_R2H_CMD_WAKEUP_RET: + 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_clear_int_flags(dev); + s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_dev(dev, reason, err); clear_bit(0, &dev->hw_lock); clear_bit(0, &dev->enter_suspend); 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); 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); break; default: 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(); return IRQ_HANDLED; 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_err = err; ctx->int_cond = 1; @@ -700,7 +722,7 @@ irq_cleanup_hw: 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"); return IRQ_HANDLED; } @@ -748,6 +770,7 @@ static int s5p_mfc_open(struct file *file) if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { 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) { @@ -760,6 +783,7 @@ static int s5p_mfc_open(struct file *file) /* 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) { @@ -885,19 +909,20 @@ static int s5p_mfc_release(struct file *file) ctx->state = MFCINST_RETURN_INST; set_work_bit_irqsave(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 */ 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(); mfc_err("Err returning instance\n"); } mfc_debug(2, "After free instance\n"); /* Free resources */ - s5p_mfc_release_codec_buffers(ctx); - s5p_mfc_release_instance_buffer(ctx); + 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_release_dec_desc_buffer(ctx); + s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, + ctx); 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"); /* reset <-> F/W release */ s5p_mfc_reset(dev); + s5p_mfc_deinit_hw(dev); s5p_mfc_release_firmware(dev); del_timer_sync(&dev->watchdog_timer); 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.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__); return 0; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c new file mode 100644 index 00000000000..8ea304be7e6 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c @@ -0,0 +1,24 @@ +/* + * 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; +} diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h new file mode 100644 index 00000000000..282e6c78070 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h @@ -0,0 +1,35 @@ +/* + * 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_ */ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c index cdd02b9295c..e4eb9569ba1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c @@ -1,5 +1,5 @@ /* - * 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. * http://www.samsung.com/ @@ -11,13 +11,13 @@ */ #include "regs-mfc.h" -#include "s5p_mfc_cmd_v5.h" +#include "s5p_mfc_cmd.h" #include "s5p_mfc_common.h" #include "s5p_mfc_debug.h" /* This function is used to send a command to the MFC */ -static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args) +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; @@ -41,35 +41,37 @@ static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd, } /* 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; memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); 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 */ -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; 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 */ -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; 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_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); dev->curr_ctx = ctx->num; 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[2] = ctx->ctx_ofs; 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); if (ret) { 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; } -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_cmd_args h2r_args; @@ -108,7 +140,7 @@ int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) 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(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, + 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"); @@ -118,3 +150,17 @@ int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) 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 index 8b090d3723e..6928a5514c1 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h @@ -1,5 +1,5 @@ /* - * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.h + * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.h * * Copyright (C) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com/ @@ -10,21 +10,11 @@ * (at your option) any later version. */ -#ifndef S5P_MFC_CMD_H_ -#define S5P_MFC_CMD_H_ +#ifndef S5P_MFC_CMD_V5_H_ +#define S5P_MFC_CMD_V5_H_ #include "s5p_mfc_common.h" -#define MAX_H2R_ARG 4 - -struct s5p_mfc_cmd_args { - unsigned int arg[MAX_H2R_ARG]; -}; - -int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev); -int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx); -int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx); +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_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 519b0d66d8d..82931d471d5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -74,7 +74,40 @@ static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b) #define MFC_ENC_CAP_PLANE_COUNT 1 #define MFC_ENC_OUT_PLANE_COUNT 2 #define STUFF_BYTE 4 -#define MFC_MAX_CTRLS 64 +#define MFC_MAX_CTRLS 70 + +#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_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_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_read(dev, offset) readl(dev->regs_base + (offset)) #define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ @@ -212,6 +245,9 @@ struct s5p_mfc_pm { * @watchdog_work: worker for the watchdog * @alloc_ctx: videobuf2 allocator contexts for two memory banks * @enter_suspend: flag set when entering suspend + * @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 * */ struct s5p_mfc_dev { @@ -248,6 +284,10 @@ struct s5p_mfc_dev { struct work_struct watchdog_work; void *alloc_ctx[2]; unsigned long enter_suspend; + + int warn_start; + struct s5p_mfc_hw_ops *mfc_ops; + struct s5p_mfc_hw_cmds *mfc_cmds; }; /** @@ -565,6 +605,9 @@ struct mfc_control { __u8 is_volatile; }; +/* Macro for making hardware specific calls */ +#define s5p_mfc_hw_call(f, op, args...) \ + ((f && f->op) ? f->op(args) : -ENODEV) #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) #define ctrl_to_ctx(__ctrl) \ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index f31bff981a5..7666e9445fb 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c @@ -15,11 +15,11 @@ #include <linux/firmware.h> #include <linux/jiffies.h> #include <linux/sched.h> -#include "regs-mfc.h" -#include "s5p_mfc_cmd_v5.h" +#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" static void *s5p_mfc_bitproc_buf; @@ -230,7 +230,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) s5p_mfc_clean_dev_int_flags(dev); 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_FIMV_R2H_CMD_FW_STATUS_RET)) { + 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(); @@ -238,7 +238,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } s5p_mfc_clean_dev_int_flags(dev); /* 4. Initialize firmware */ - ret = s5p_mfc_sys_init_cmd(dev); + 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); @@ -246,7 +246,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) return ret; } mfc_debug(2, "Ok, now will write a command to init the system\n"); - if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) { + if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { mfc_err("Failed to load firmware\n"); s5p_mfc_reset(dev); s5p_mfc_clock_off(); @@ -254,7 +254,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != - S5P_FIMV_R2H_CMD_SYS_INIT_RET) { + 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); @@ -271,6 +271,17 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) } +/* 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; @@ -278,19 +289,19 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) mfc_debug_enter(); s5p_mfc_clock_on(); s5p_mfc_clean_dev_int_flags(dev); - ret = s5p_mfc_sleep_cmd(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_FIMV_R2H_CMD_SLEEP_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->i |