diff options
author | Jeongtae Park <jtp.park@samsung.com> | 2012-10-03 21:19:11 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-10-05 22:08:31 -0400 |
commit | f96f3cfa0bb8f777fe877d7f881bf7ee58bd162a (patch) | |
tree | 52e3aacbc57281366ac0b823ba335fe1b394a86b /drivers/media/platform | |
parent | 5b781e171ec8f03e640d3b1de6a7ad6a5349e4bf (diff) |
[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>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r-- | drivers/media/platform/Kconfig | 4 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/Makefile | 8 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/regs-mfc.h | 21 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc.c | 64 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c | 7 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | 156 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h | 20 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 61 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | 162 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 193 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 134 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | 10 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 1956 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h | 50 | ||||
-rw-r--r-- | drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 3 |
15 files changed, 2679 insertions, 170 deletions
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index f588d6296c76..181c7686e412 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig | |||
@@ -165,12 +165,12 @@ config VIDEO_SAMSUNG_S5P_JPEG | |||
165 | This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec | 165 | This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec |
166 | 166 | ||
167 | config VIDEO_SAMSUNG_S5P_MFC | 167 | config VIDEO_SAMSUNG_S5P_MFC |
168 | tristate "Samsung S5P MFC 5.1 Video Codec" | 168 | tristate "Samsung S5P MFC Video Codec" |
169 | depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P | 169 | depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P |
170 | select VIDEOBUF2_DMA_CONTIG | 170 | select VIDEOBUF2_DMA_CONTIG |
171 | default n | 171 | default n |
172 | help | 172 | help |
173 | MFC 5.1 driver for V4L2. | 173 | MFC 5.1 and 6.x driver for V4L2 |
174 | 174 | ||
175 | config VIDEO_MX2_EMMAPRP | 175 | config VIDEO_MX2_EMMAPRP |
176 | tristate "MX2 eMMa-PrP support" | 176 | tristate "MX2 eMMa-PrP support" |
diff --git a/drivers/media/platform/s5p-mfc/Makefile b/drivers/media/platform/s5p-mfc/Makefile index cfb9ee9f543a..379008c6d09a 100644 --- a/drivers/media/platform/s5p-mfc/Makefile +++ b/drivers/media/platform/s5p-mfc/Makefile | |||
@@ -1,6 +1,6 @@ | |||
1 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o | 1 | obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) := s5p-mfc.o |
2 | s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o s5p_mfc_opr.o | 2 | s5p-mfc-y += s5p_mfc.o s5p_mfc_intr.o |
3 | s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o | 3 | s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o |
4 | s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o | 4 | s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_pm.o |
5 | s5p-mfc-y += s5p_mfc_pm.o | 5 | s5p-mfc-y += s5p_mfc_opr.o s5p_mfc_opr_v5.o s5p_mfc_opr_v6.o |
6 | s5p-mfc-y += s5p_mfc_opr_v5.o s5p_mfc_cmd_v5.o | 6 | s5p-mfc-y += s5p_mfc_cmd.o s5p_mfc_cmd_v5.o s5p_mfc_cmd_v6.o |
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h index f33c54d4df86..9319e93599ae 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc.h | |||
@@ -147,6 +147,7 @@ | |||
147 | #define S5P_FIMV_ENC_PROFILE_H264_MAIN 0 | 147 | #define S5P_FIMV_ENC_PROFILE_H264_MAIN 0 |
148 | #define S5P_FIMV_ENC_PROFILE_H264_HIGH 1 | 148 | #define S5P_FIMV_ENC_PROFILE_H264_HIGH 1 |
149 | #define S5P_FIMV_ENC_PROFILE_H264_BASELINE 2 | 149 | #define S5P_FIMV_ENC_PROFILE_H264_BASELINE 2 |
150 | #define S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE 3 | ||
150 | #define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0 | 151 | #define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0 |
151 | #define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1 | 152 | #define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1 |
152 | #define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */ | 153 | #define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */ |
@@ -216,6 +217,7 @@ | |||
216 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) | 217 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) |
217 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) | 218 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) |
218 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) | 219 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) |
220 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT 4 | ||
219 | 221 | ||
220 | /* Decode frame address */ | 222 | /* Decode frame address */ |
221 | #define S5P_FIMV_DECODE_Y_ADR 0x2024 | 223 | #define S5P_FIMV_DECODE_Y_ADR 0x2024 |
@@ -380,6 +382,16 @@ | |||
380 | #define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16 | 382 | #define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16 |
381 | #define S5P_FIMV_R2H_CMD_ERR_RET 32 | 383 | #define S5P_FIMV_R2H_CMD_ERR_RET 32 |
382 | 384 | ||
385 | /* Dummy definition for MFCv6 compatibilty */ | ||
386 | #define S5P_FIMV_CODEC_H264_MVC_DEC -1 | ||
387 | #define S5P_FIMV_R2H_CMD_FIELD_DONE_RET -1 | ||
388 | #define S5P_FIMV_MFC_RESET -1 | ||
389 | #define S5P_FIMV_RISC_ON -1 | ||
390 | #define S5P_FIMV_RISC_BASE_ADDRESS -1 | ||
391 | #define S5P_FIMV_CODEC_VP8_DEC -1 | ||
392 | #define S5P_FIMV_REG_CLEAR_BEGIN 0 | ||
393 | #define S5P_FIMV_REG_CLEAR_COUNT 0 | ||
394 | |||
383 | /* Error handling defines */ | 395 | /* Error handling defines */ |
384 | #define S5P_FIMV_ERR_WARNINGS_START 145 | 396 | #define S5P_FIMV_ERR_WARNINGS_START 145 |
385 | #define S5P_FIMV_ERR_DEC_MASK 0xFFFF | 397 | #define S5P_FIMV_ERR_DEC_MASK 0xFFFF |
@@ -435,4 +447,13 @@ | |||
435 | #define MFC_VERSION 0x51 | 447 | #define MFC_VERSION 0x51 |
436 | #define MFC_NUM_PORTS 2 | 448 | #define MFC_NUM_PORTS 2 |
437 | 449 | ||
450 | #define S5P_FIMV_SHARED_FRAME_PACK_SEI_AVAIL 0x16C | ||
451 | #define S5P_FIMV_SHARED_FRAME_PACK_ARRGMENT_ID 0x170 | ||
452 | #define S5P_FIMV_SHARED_FRAME_PACK_SEI_INFO 0x174 | ||
453 | #define S5P_FIMV_SHARED_FRAME_PACK_GRID_POS 0x178 | ||
454 | |||
455 | /* Values for resolution change in display status */ | ||
456 | #define S5P_FIMV_RES_INCREASE 1 | ||
457 | #define S5P_FIMV_RES_DECREASE 2 | ||
458 | |||
438 | #endif /* _REGS_FIMV_H */ | 459 | #endif /* _REGS_FIMV_H */ |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 7feae81db00b..aa551339cb41 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c | |||
@@ -330,12 +330,14 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, | |||
330 | 330 | ||
331 | dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) | 331 | dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) |
332 | & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; | 332 | & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; |
333 | res_change = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) | 333 | res_change = (s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev) |
334 | & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK; | 334 | & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK) |
335 | >> S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT; | ||
335 | mfc_debug(2, "Frame Status: %x\n", dst_frame_status); | 336 | mfc_debug(2, "Frame Status: %x\n", dst_frame_status); |
336 | if (ctx->state == MFCINST_RES_CHANGE_INIT) | 337 | if (ctx->state == MFCINST_RES_CHANGE_INIT) |
337 | ctx->state = MFCINST_RES_CHANGE_FLUSH; | 338 | ctx->state = MFCINST_RES_CHANGE_FLUSH; |
338 | if (res_change) { | 339 | if (res_change == S5P_FIMV_RES_INCREASE || |
340 | res_change == S5P_FIMV_RES_DECREASE) { | ||
339 | ctx->state = MFCINST_RES_CHANGE_INIT; | 341 | ctx->state = MFCINST_RES_CHANGE_INIT; |
340 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); | 342 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); |
341 | wake_up_ctx(ctx, reason, err); | 343 | wake_up_ctx(ctx, reason, err); |
@@ -494,10 +496,28 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, | |||
494 | 496 | ||
495 | ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, | 497 | ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count, |
496 | dev); | 498 | dev); |
499 | ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, | ||
500 | dev); | ||
497 | if (ctx->img_width == 0 || ctx->img_height == 0) | 501 | if (ctx->img_width == 0 || ctx->img_height == 0) |
498 | ctx->state = MFCINST_ERROR; | 502 | ctx->state = MFCINST_ERROR; |
499 | else | 503 | else |
500 | ctx->state = MFCINST_HEAD_PARSED; | 504 | ctx->state = MFCINST_HEAD_PARSED; |
505 | |||
506 | if ((ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || | ||
507 | ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) && | ||
508 | !list_empty(&ctx->src_queue)) { | ||
509 | struct s5p_mfc_buf *src_buf; | ||
510 | src_buf = list_entry(ctx->src_queue.next, | ||
511 | struct s5p_mfc_buf, list); | ||
512 | if (s5p_mfc_hw_call(dev->mfc_ops, get_consumed_stream, | ||
513 | dev) < | ||
514 | src_buf->b->v4l2_planes[0].bytesused) | ||
515 | ctx->head_processed = 0; | ||
516 | else | ||
517 | ctx->head_processed = 1; | ||
518 | } else { | ||
519 | ctx->head_processed = 1; | ||
520 | } | ||
501 | } | 521 | } |
502 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); | 522 | s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); |
503 | clear_work_bit(ctx); | 523 | clear_work_bit(ctx); |
@@ -526,7 +546,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, | |||
526 | clear_work_bit(ctx); | 546 | clear_work_bit(ctx); |
527 | if (err == 0) { | 547 | if (err == 0) { |
528 | ctx->state = MFCINST_RUNNING; | 548 | ctx->state = MFCINST_RUNNING; |
529 | if (!ctx->dpb_flush_flag) { | 549 | if (!ctx->dpb_flush_flag && ctx->head_processed) { |
530 | spin_lock_irqsave(&dev->irqlock, flags); | 550 | spin_lock_irqsave(&dev->irqlock, flags); |
531 | if (!list_empty(&ctx->src_queue)) { | 551 | if (!list_empty(&ctx->src_queue)) { |
532 | src_buf = list_entry(ctx->src_queue.next, | 552 | src_buf = list_entry(ctx->src_queue.next, |
@@ -1071,6 +1091,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) | |||
1071 | ret = -ENODEV; | 1091 | ret = -ENODEV; |
1072 | goto err_res; | 1092 | goto err_res; |
1073 | } | 1093 | } |
1094 | |||
1074 | dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r", | 1095 | dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r", |
1075 | match_child); | 1096 | match_child); |
1076 | if (!dev->mem_dev_r) { | 1097 | if (!dev->mem_dev_r) { |
@@ -1301,12 +1322,47 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { | |||
1301 | .port_num = MFC_NUM_PORTS, | 1322 | .port_num = MFC_NUM_PORTS, |
1302 | .buf_size = &buf_size_v5, | 1323 | .buf_size = &buf_size_v5, |
1303 | .buf_align = &mfc_buf_align_v5, | 1324 | .buf_align = &mfc_buf_align_v5, |
1325 | .mclk_name = "sclk_mfc", | ||
1326 | .fw_name = "s5p-mfc.fw", | ||
1327 | }; | ||
1328 | |||
1329 | struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { | ||
1330 | .dev_ctx = MFC_CTX_BUF_SIZE_V6, | ||
1331 | .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V6, | ||
1332 | .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V6, | ||
1333 | .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V6, | ||
1334 | .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V6, | ||
1335 | }; | ||
1336 | |||
1337 | struct s5p_mfc_buf_size buf_size_v6 = { | ||
1338 | .fw = MAX_FW_SIZE_V6, | ||
1339 | .cpb = MAX_CPB_SIZE_V6, | ||
1340 | .priv = &mfc_buf_size_v6, | ||
1341 | }; | ||
1342 | |||
1343 | struct s5p_mfc_buf_align mfc_buf_align_v6 = { | ||
1344 | .base = 0, | ||
1345 | }; | ||
1346 | |||
1347 | static struct s5p_mfc_variant mfc_drvdata_v6 = { | ||
1348 | .version = MFC_VERSION_V6, | ||
1349 | .port_num = MFC_NUM_PORTS_V6, | ||
1350 | .buf_size = &buf_size_v6, | ||
1351 | .buf_align = &mfc_buf_align_v6, | ||
1352 | .mclk_name = "aclk_333", | ||
1353 | .fw_name = "s5p-mfc-v6.fw", | ||
1304 | }; | 1354 | }; |
1305 | 1355 | ||
1306 | static struct platform_device_id mfc_driver_ids[] = { | 1356 | static struct platform_device_id mfc_driver_ids[] = { |
1307 | { | 1357 | { |
1308 | .name = "s5p-mfc", | 1358 | .name = "s5p-mfc", |
1309 | .driver_data = (unsigned long)&mfc_drvdata_v5, | 1359 | .driver_data = (unsigned long)&mfc_drvdata_v5, |
1360 | }, { | ||
1361 | .name = "s5p-mfc-v5", | ||
1362 | .driver_data = (unsigned long)&mfc_drvdata_v5, | ||
1363 | }, { | ||
1364 | .name = "s5p-mfc-v6", | ||
1365 | .driver_data = (unsigned long)&mfc_drvdata_v6, | ||
1310 | }, | 1366 | }, |
1311 | {}, | 1367 | {}, |
1312 | }; | 1368 | }; |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c index 8ea304be7e68..f0a41c95df84 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd.c | |||
@@ -14,11 +14,16 @@ | |||
14 | #include "s5p_mfc_common.h" | 14 | #include "s5p_mfc_common.h" |
15 | #include "s5p_mfc_debug.h" | 15 | #include "s5p_mfc_debug.h" |
16 | #include "s5p_mfc_cmd_v5.h" | 16 | #include "s5p_mfc_cmd_v5.h" |
17 | #include "s5p_mfc_cmd_v6.h" | ||
17 | 18 | ||
18 | static struct s5p_mfc_hw_cmds *s5p_mfc_cmds; | 19 | static struct s5p_mfc_hw_cmds *s5p_mfc_cmds; |
19 | 20 | ||
20 | void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev) | 21 | void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev) |
21 | { | 22 | { |
22 | s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); | 23 | if (IS_MFCV6(dev)) |
24 | s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v6(); | ||
25 | else | ||
26 | s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); | ||
27 | |||
23 | dev->mfc_cmds = s5p_mfc_cmds; | 28 | dev->mfc_cmds = s5p_mfc_cmds; |
24 | } | 29 | } |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c new file mode 100644 index 000000000000..754bfbcb1c43 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.c | ||
3 | * | ||
4 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com/ | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include "s5p_mfc_common.h" | ||
14 | |||
15 | #include "s5p_mfc_cmd.h" | ||
16 | #include "s5p_mfc_debug.h" | ||
17 | #include "s5p_mfc_intr.h" | ||
18 | #include "s5p_mfc_opr.h" | ||
19 | |||
20 | int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, | ||
21 | struct s5p_mfc_cmd_args *args) | ||
22 | { | ||
23 | mfc_debug(2, "Issue the command: %d\n", cmd); | ||
24 | |||
25 | /* Reset RISC2HOST command */ | ||
26 | mfc_write(dev, 0x0, S5P_FIMV_RISC2HOST_CMD_V6); | ||
27 | |||
28 | /* Issue the command */ | ||
29 | mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD_V6); | ||
30 | mfc_write(dev, 0x1, S5P_FIMV_HOST2RISC_INT_V6); | ||
31 | |||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) | ||
36 | { | ||
37 | struct s5p_mfc_cmd_args h2r_args; | ||
38 | struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; | ||
39 | |||
40 | s5p_mfc_hw_call(dev->mfc_ops, alloc_dev_context_buffer, dev); | ||
41 | mfc_write(dev, dev->ctx_buf.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); | ||
42 | mfc_write(dev, buf_size->dev_ctx, S5P_FIMV_CONTEXT_MEM_SIZE_V6); | ||
43 | return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SYS_INIT_V6, | ||
44 | &h2r_args); | ||
45 | } | ||
46 | |||
47 | int s5p_mfc_sleep_cmd_v6(struct s5p_mfc_dev *dev) | ||
48 | { | ||
49 | struct s5p_mfc_cmd_args h2r_args; | ||
50 | |||
51 | memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); | ||
52 | return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_SLEEP_V6, | ||
53 | &h2r_args); | ||
54 | } | ||
55 | |||
56 | int s5p_mfc_wakeup_cmd_v6(struct s5p_mfc_dev *dev) | ||
57 | { | ||
58 | struct s5p_mfc_cmd_args h2r_args; | ||
59 | |||
60 | memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); | ||
61 | return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_WAKEUP_V6, | ||
62 | &h2r_args); | ||
63 | } | ||
64 | |||
65 | /* Open a new instance and get its number */ | ||
66 | int s5p_mfc_open_inst_cmd_v6(struct s5p_mfc_ctx *ctx) | ||
67 | { | ||
68 | struct s5p_mfc_dev *dev = ctx->dev; | ||
69 | struct s5p_mfc_cmd_args h2r_args; | ||
70 | int codec_type; | ||
71 | |||
72 | mfc_debug(2, "Requested codec mode: %d\n", ctx->codec_mode); | ||
73 | dev->curr_ctx = ctx->num; | ||
74 | switch (ctx->codec_mode) { | ||
75 | case S5P_MFC_CODEC_H264_DEC: | ||
76 | codec_type = S5P_FIMV_CODEC_H264_DEC_V6; | ||
77 | break; | ||
78 | case S5P_MFC_CODEC_H264_MVC_DEC: | ||
79 | codec_type = S5P_FIMV_CODEC_H264_MVC_DEC_V6; | ||
80 | break; | ||
81 | case S5P_MFC_CODEC_VC1_DEC: | ||
82 | codec_type = S5P_FIMV_CODEC_VC1_DEC_V6; | ||
83 | break; | ||
84 | case S5P_MFC_CODEC_MPEG4_DEC: | ||
85 | codec_type = S5P_FIMV_CODEC_MPEG4_DEC_V6; | ||
86 | break; | ||
87 | case S5P_MFC_CODEC_MPEG2_DEC: | ||
88 | codec_type = S5P_FIMV_CODEC_MPEG2_DEC_V6; | ||
89 | break; | ||
90 | case S5P_MFC_CODEC_H263_DEC: | ||
91 | codec_type = S5P_FIMV_CODEC_H263_DEC_V6; | ||
92 | break; | ||
93 | case S5P_MFC_CODEC_VC1RCV_DEC: | ||
94 | codec_type = S5P_FIMV_CODEC_VC1RCV_DEC_V6; | ||
95 | break; | ||
96 | case S5P_MFC_CODEC_VP8_DEC: | ||
97 | codec_type = S5P_FIMV_CODEC_VP8_DEC_V6; | ||
98 | break; | ||
99 | case S5P_MFC_CODEC_H264_ENC: | ||
100 | codec_type = S5P_FIMV_CODEC_H264_ENC_V6; | ||
101 | break; | ||
102 | case S5P_MFC_CODEC_H264_MVC_ENC: | ||
103 | codec_type = S5P_FIMV_CODEC_H264_MVC_ENC_V6; | ||
104 | break; | ||
105 | case S5P_MFC_CODEC_MPEG4_ENC: | ||
106 | codec_type = S5P_FIMV_CODEC_MPEG4_ENC_V6; | ||
107 | break; | ||
108 | case S5P_MFC_CODEC_H263_ENC: | ||
109 | codec_type = S5P_FIMV_CODEC_H263_ENC_V6; | ||
110 | break; | ||
111 | default: | ||
112 | codec_type = S5P_FIMV_CODEC_NONE_V6; | ||
113 | }; | ||
114 | mfc_write(dev, codec_type, S5P_FIMV_CODEC_TYPE_V6); | ||
115 | mfc_write(dev, ctx->ctx.dma, S5P_FIMV_CONTEXT_MEM_ADDR_V6); | ||
116 | mfc_write(dev, ctx->ctx.size, S5P_FIMV_CONTEXT_MEM_SIZE_V6); | ||
117 | mfc_write(dev, 0, S5P_FIMV_D_CRC_CTRL_V6); /* no crc */ | ||
118 | |||
119 | return s5p_mfc_cmd_host2risc_v6(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE_V6, | ||
120 | &h2r_args); | ||
121 | } | ||
122 | |||
123 | /* Close instance */ | ||
124 | int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) | ||
125 | { | ||
126 | struct s5p_mfc_dev *dev = ctx->dev; | ||
127 | struct s5p_mfc_cmd_args h2r_args; | ||
128 | int ret = 0; | ||
129 | |||
130 | dev->curr_ctx = ctx->num; | ||
131 | if (ctx->state != MFCINST_FREE) { | ||
132 | mfc_write(dev, ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); | ||
133 | ret = s5p_mfc_cmd_host2risc_v6(dev, | ||
134 | S5P_FIMV_H2R_CMD_CLOSE_INSTANCE_V6, | ||
135 | &h2r_args); | ||
136 | } else { | ||
137 | ret = -EINVAL; | ||
138 | } | ||
139 | |||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | /* Initialize cmd function pointers for MFC v6 */ | ||
144 | static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { | ||
145 | .cmd_host2risc = s5p_mfc_cmd_host2risc_v6, | ||
146 | .sys_init_cmd = s5p_mfc_sys_init_cmd_v6, | ||
147 | .sleep_cmd = s5p_mfc_sleep_cmd_v6, | ||
148 | .wakeup_cmd = s5p_mfc_wakeup_cmd_v6, | ||
149 | .open_inst_cmd = s5p_mfc_open_inst_cmd_v6, | ||
150 | .close_inst_cmd = s5p_mfc_close_inst_cmd_v6, | ||
151 | }; | ||
152 | |||
153 | struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) | ||
154 | { | ||
155 | return &s5p_mfc_cmds_v6; | ||
156 | } | ||
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h new file mode 100644 index 000000000000..b7a8e57837b5 --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v6.h | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com/ | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef S5P_MFC_CMD_V6_H_ | ||
14 | #define S5P_MFC_CMD_V6_H_ | ||
15 | |||
16 | #include "s5p_mfc_common.h" | ||
17 | |||
18 | struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void); | ||
19 | |||
20 | #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 e495b13b2710..f02e0497ca98 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h | |||
@@ -16,13 +16,14 @@ | |||
16 | #ifndef S5P_MFC_COMMON_H_ | 16 | #ifndef S5P_MFC_COMMON_H_ |
17 | #define S5P_MFC_COMMON_H_ | 17 | #define S5P_MFC_COMMON_H_ |
18 | 18 | ||
19 | #include "regs-mfc.h" | ||
20 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
21 | #include <linux/videodev2.h> | 20 | #include <linux/videodev2.h> |
22 | #include <media/v4l2-ctrls.h> | 21 | #include <media/v4l2-ctrls.h> |
23 | #include <media/v4l2-device.h> | 22 | #include <media/v4l2-device.h> |
24 | #include <media/v4l2-ioctl.h> | 23 | #include <media/v4l2-ioctl.h> |
25 | #include <media/videobuf2-core.h> | 24 | #include <media/videobuf2-core.h> |
25 | #include "regs-mfc.h" | ||
26 | #include "regs-mfc-v6.h" | ||
26 | 27 | ||
27 | /* Definitions related to MFC memory */ | 28 | /* Definitions related to MFC memory */ |
28 | 29 | ||
@@ -206,6 +207,14 @@ struct s5p_mfc_buf_size_v5 { | |||
206 | unsigned int shm; | 207 | unsigned int shm; |
207 | }; | 208 | }; |
208 | 209 | ||
210 | struct s5p_mfc_buf_size_v6 { | ||
211 | unsigned int dev_ctx; | ||
212 | unsigned int h264_dec_ctx; | ||
213 | unsigned int other_dec_ctx; | ||
214 | unsigned int h264_enc_ctx; | ||
215 | unsigned int other_enc_ctx; | ||
216 | }; | ||
217 | |||
209 | struct s5p_mfc_buf_size { | 218 | struct s5p_mfc_buf_size { |
210 | unsigned int fw; | 219 | unsigned int fw; |
211 | unsigned int cpb; | 220 | unsigned int cpb; |
@@ -221,6 +230,8 @@ struct s5p_mfc_variant { | |||
221 | unsigned int port_num; | 230 | unsigned int port_num; |
222 | struct s5p_mfc_buf_size *buf_size; | 231 | struct s5p_mfc_buf_size *buf_size; |
223 | struct s5p_mfc_buf_align *buf_align; | 232 | struct s5p_mfc_buf_align *buf_align; |
233 | char *mclk_name; | ||
234 | char *fw_name; | ||
224 | }; | 235 | }; |
225 | 236 | ||
226 | /** | 237 | /** |
@@ -277,6 +288,7 @@ struct s5p_mfc_priv_buf { | |||
277 | * @watchdog_work: worker for the watchdog | 288 | * @watchdog_work: worker for the watchdog |
278 | * @alloc_ctx: videobuf2 allocator contexts for two memory banks | 289 | * @alloc_ctx: videobuf2 allocator contexts for two memory banks |
279 | * @enter_suspend: flag set when entering suspend | 290 | * @enter_suspend: flag set when entering suspend |
291 | * @ctx_buf: common context memory (MFCv6) | ||
280 | * @warn_start: hardware error code from which warnings start | 292 | * @warn_start: hardware error code from which warnings start |
281 | * @mfc_ops: ops structure holding HW operation function pointers | 293 | * @mfc_ops: ops structure holding HW operation function pointers |
282 | * @mfc_cmds: cmd structure holding HW commands function pointers | 294 | * @mfc_cmds: cmd structure holding HW commands function pointers |
@@ -318,6 +330,7 @@ struct s5p_mfc_dev { | |||
318 | void *alloc_ctx[2]; | 330 | void *alloc_ctx[2]; |
319 | unsigned long enter_suspend; | 331 | unsigned long enter_suspend; |
320 | 332 | ||
333 | struct s5p_mfc_priv_buf ctx_buf; | ||
321 | int warn_start; | 334 | int warn_start; |
322 | struct s5p_mfc_hw_ops *mfc_ops; | 335 | struct s5p_mfc_hw_ops *mfc_ops; |
323 | struct s5p_mfc_hw_cmds *mfc_cmds; | 336 | struct s5p_mfc_hw_cmds *mfc_cmds; |
@@ -354,6 +367,22 @@ struct s5p_mfc_h264_enc_params { | |||
354 | int level; | 367 | int level; |
355 | u16 cpb_size; | 368 | u16 cpb_size; |
356 | int interlace; | 369 | int interlace; |
370 | u8 hier_qp; | ||
371 | u8 hier_qp_type; | ||
372 | u8 hier_qp_layer; | ||
373 | u8 hier_qp_layer_qp[7]; | ||
374 | u8 sei_frame_packing; | ||
375 | u8 sei_fp_curr_frame_0; | ||
376 | u8 sei_fp_arrangement_type; | ||
377 | |||
378 | u8 fmo; | ||
379 | u8 fmo_map_type; | ||
380 | u8 fmo_slice_grp; | ||
381 | u8 fmo_chg_dir; | ||
382 | u32 fmo_chg_rate; | ||
383 | u32 fmo_run_len[4]; | ||
384 | u8 aso; | ||
385 | u32 aso_slice_order[8]; | ||
357 | }; | 386 | }; |
358 | 387 | ||
359 | /** | 388 | /** |
@@ -396,6 +425,7 @@ struct s5p_mfc_enc_params { | |||
396 | u32 rc_bitrate; | 425 | u32 rc_bitrate; |
397 | u16 rc_reaction_coeff; | 426 | u16 rc_reaction_coeff; |
398 | u16 vbv_size; | 427 | u16 vbv_size; |
428 | u32 vbv_delay; | ||
399 | 429 | ||
400 | enum v4l2_mpeg_video_header_mode seq_hdr_mode; | 430 | enum v4l2_mpeg_video_header_mode seq_hdr_mode; |
401 | enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode; | 431 | enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode; |
@@ -461,6 +491,8 @@ struct s5p_mfc_codec_ops { | |||
461 | * decoding buffer | 491 | * decoding buffer |
462 | * @dpb_flush_flag: flag used to indicate that a DPB buffers are being | 492 | * @dpb_flush_flag: flag used to indicate that a DPB buffers are being |
463 | * flushed | 493 | * flushed |
494 | * @head_processed: flag mentioning whether the header data is processed | ||
495 | * completely or not | ||
464 | * @bank1_buf: handle to memory allocated for temporary buffers from | 496 | * @bank1_buf: handle to memory allocated for temporary buffers from |
465 | * memory bank 1 | 497 | * memory bank 1 |
466 | * @bank1_phys: address of the temporary buffers from memory bank 1 | 498 | * @bank1_phys: address of the temporary buffers from memory bank 1 |
@@ -485,14 +517,20 @@ struct s5p_mfc_codec_ops { | |||
485 | * @display_delay_enable: display delay for H264 enable flag | 517 | * @display_delay_enable: display delay for H264 enable flag |
486 | * @after_packed_pb: flag used to track buffer when stream is in | 518 | * @after_packed_pb: flag used to track buffer when stream is in |
487 | * Packed PB format | 519 | * Packed PB format |
520 | * @sei_fp_parse: enable/disable parsing of frame packing SEI information | ||
488 | * @dpb_count: count of the DPB buffers required by MFC hw | 521 | * @dpb_count: count of the DPB buffers required by MFC hw |
489 | * @total_dpb_count: count of DPB buffers with additional buffers | 522 | * @total_dpb_count: count of DPB buffers with additional buffers |
490 | * requested by the application | 523 | * requested by the application |
491 | * @ctx: context buffer information | 524 | * @ctx: context buffer information |
492 | * @dsc: descriptor buffer information | 525 | * @dsc: descriptor buffer information |
493 | * @shm: shared memory buffer information | 526 | * @shm: shared memory buffer information |
527 | * @mv_count: number of MV buffers allocated for decoding | ||
494 | * @enc_params: encoding parameters for MFC | 528 | * @enc_params: encoding parameters for MFC |
495 | * @enc_dst_buf_size: size of the buffers for encoder output | 529 | * @enc_dst_buf_size: size of the buffers for encoder output |
530 | * @luma_dpb_size: dpb buffer size for luma | ||
531 | * @chroma_dpb_size: dpb buffer size for chroma | ||
532 | * @me_buffer_size: size of the motion estimation buffer | ||
533 | * @tmv_buffer_size: size of temporal predictor motion vector buffer | ||
496 | * @frame_type: used to force the type of the next encoded frame | 534 | * @frame_type: used to force the type of the next encoded frame |
497 | * @ref_queue: list of the reference buffers for encoding | 535 | * @ref_queue: list of the reference buffers for encoding |
498 | * @ref_queue_cnt: number of the buffers in the reference list | 536 | * @ref_queue_cnt: number of the buffers in the reference list |
@@ -541,6 +579,7 @@ struct s5p_mfc_ctx { | |||
541 | unsigned long consumed_stream; | 579 | unsigned long consumed_stream; |
542 | 580 | ||
543 | unsigned int dpb_flush_flag; | 581 | unsigned int dpb_flush_flag; |
582 | unsigned int head_processed; | ||
544 | 583 | ||
545 | /* Buffers */ | 584 | /* Buffers */ |
546 | void *bank1_buf; | 585 | void *bank1_buf; |
@@ -570,10 +609,11 @@ struct s5p_mfc_ctx { | |||
570 | int display_delay; | 609 | int display_delay; |
571 | int display_delay_enable; | 610 | int display_delay_enable; |
572 | int after_packed_pb; | 611 | int after_packed_pb; |
612 | int sei_fp_parse; | ||
573 | 613 | ||
574 | int dpb_count; | 614 | int dpb_count; |
575 | int total_dpb_count; | 615 | int total_dpb_count; |
576 | 616 | int mv_count; | |
577 | /* Buffers */ | 617 | /* Buffers */ |
578 | struct s5p_mfc_priv_buf ctx; | 618 | struct s5p_mfc_priv_buf ctx; |
579 | struct s5p_mfc_priv_buf dsc; | 619 | struct s5p_mfc_priv_buf dsc; |
@@ -582,16 +622,28 @@ struct s5p_mfc_ctx { | |||
582 | struct s5p_mfc_enc_params enc_params; | 622 | struct s5p_mfc_enc_params enc_params; |
583 | 623 | ||
584 | size_t enc_dst_buf_size; | 624 | size_t enc_dst_buf_size; |
625 | size_t luma_dpb_size; | ||
626 | size_t chroma_dpb_size; | ||
627 | size_t me_buffer_size; | ||
628 | size_t tmv_buffer_size; | ||
585 | 629 | ||
586 | enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type; | 630 | enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type; |
587 | 631 | ||
588 | struct list_head ref_queue; | 632 | struct list_head ref_queue; |
589 | unsigned int ref_queue_cnt; | 633 | unsigned int ref_queue_cnt; |
590 | 634 | ||
635 | enum v4l2_mpeg_video_multi_slice_mode slice_mode; | ||
636 | union { | ||
637 | unsigned int mb; | ||
638 | unsigned int bits; | ||
639 | } slice_size; | ||
640 | |||
591 | struct s5p_mfc_codec_ops *c_ops; | 641 | struct s5p_mfc_codec_ops *c_ops; |
592 | 642 | ||
593 | struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; | 643 | struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; |
594 | struct v4l2_ctrl_handler ctrl_handler; | 644 | struct v4l2_ctrl_handler ctrl_handler; |
645 | unsigned int frame_tag; | ||
646 | size_t scratch_buf_size; | ||
595 | }; | 647 | }; |
596 | 648 | ||
597 | /* | 649 | /* |
@@ -637,4 +689,9 @@ void set_work_bit(struct s5p_mfc_ctx *ctx); | |||
637 | void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx); | 689 | void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx); |
638 | void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx); | 690 | void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx); |
639 | 691 | ||
692 | #define HAS_PORTNUM(dev) (dev ? (dev->variant ? \ | ||
693 | (dev->variant->port_num ? 1 : 0) : 0) : 0) | ||
694 | #define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0) | ||
695 | #define IS_MFCV6(dev) (dev->variant->version >= 0x60 ? 1 : 0) | ||
696 | |||
640 | #endif /* S5P_MFC_COMMON_H_ */ | 697 | #endif /* S5P_MFC_COMMON_H_ */ |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c index 311ec90be621..585b7b0ed8ec 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c | |||
@@ -37,8 +37,9 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) | |||
37 | /* Firmare has to be present as a separate file or compiled | 37 | /* Firmare has to be present as a separate file or compiled |
38 | * into kernel. */ | 38 | * into kernel. */ |
39 | mfc_debug_enter(); | 39 | mfc_debug_enter(); |
40 | |||
40 | err = request_firmware((const struct firmware **)&fw_blob, | 41 | err = request_firmware((const struct firmware **)&fw_blob, |
41 | "s5p-mfc.fw", dev->v4l2_dev.dev); | 42 | dev->variant->fw_name, dev->v4l2_dev.dev); |
42 | if (err != 0) { | 43 | if (err != 0) { |
43 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); | 44 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); |
44 | return -EINVAL; | 45 | return -EINVAL; |
@@ -82,32 +83,37 @@ int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) | |||
82 | return -EIO; | 83 | return -EIO; |
83 | } | 84 | } |
84 | dev->bank1 = s5p_mfc_bitproc_phys; | 85 | dev->bank1 = s5p_mfc_bitproc_phys; |
85 | b_base = vb2_dma_contig_memops.alloc( | 86 | if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) { |
86 | dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BASE_ALIGN_ORDER); | 87 | b_base = vb2_dma_contig_memops.alloc( |
87 | if (IS_ERR(b_base)) { | 88 | dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], |
88 | vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); | 89 | 1 << MFC_BASE_ALIGN_ORDER); |
89 | s5p_mfc_bitproc_phys = 0; | 90 | if (IS_ERR(b_base)) { |
90 | s5p_mfc_bitproc_buf = NULL; | 91 | vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); |
91 | mfc_err("Allocating bank2 base failed\n"); | 92 | s5p_mfc_bitproc_phys = 0; |
92 | release_firmware(fw_blob); | 93 | s5p_mfc_bitproc_buf = NULL; |
93 | return -ENOMEM; | 94 | mfc_err("Allocating bank2 base failed\n"); |
94 | } | 95 | release_firmware(fw_blob); |
95 | bank2_base_phys = s5p_mfc_mem_cookie( | 96 | return -ENOMEM; |
96 | dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); | 97 | } |
97 | vb2_dma_contig_memops.put(b_base); | 98 | bank2_base_phys = s5p_mfc_mem_cookie( |
98 | if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { | 99 | dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); |
99 | mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); | 100 | vb2_dma_contig_memops.put(b_base); |
100 | vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); | 101 | if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { |
101 | s5p_mfc_bitproc_phys = 0; | 102 | mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); |
102 | s5p_mfc_bitproc_buf = NULL; | 103 | vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); |
103 | release_firmware(fw_blob); | 104 | s5p_mfc_bitproc_phys = 0; |
104 | return -EIO; | 105 | s5p_mfc_bitproc_buf = NULL; |
106 | release_firmware(fw_blob); | ||
107 | return -EIO; | ||
108 | } | ||
109 | /* Valid buffers passed to MFC encoder with LAST_FRAME command | ||
110 | * should not have address of bank2 - MFC will treat it as a null frame. | ||
111 | * To avoid such situation we set bank2 address below the pool address. | ||
112 | */ | ||
113 | dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER); | ||
114 | } else { | ||
115 | dev->bank2 = dev->bank1; | ||
105 | } | 116 | } |
106 | /* Valid buffers passed to MFC encoder with LAST_FRAME command | ||
107 | * should not have address of bank2 - MFC will treat it as a null frame. | ||
108 | * To avoid such situation we set bank2 address below the pool address. | ||
109 | */ | ||
110 | dev->bank2 = bank2_base_phys - (1 << MFC_BASE_ALIGN_ORDER); | ||
111 | memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); | 117 | memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); |
112 | wmb(); | 118 | wmb(); |
113 | release_firmware(fw_blob); | 119 | release_firmware(fw_blob); |
@@ -124,8 +130,9 @@ int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) | |||
124 | /* Firmare has to be present as a separate file or compiled | 130 | /* Firmare has to be present as a separate file or compiled |
125 | * into kernel. */ | 131 | * into kernel. */ |
126 | mfc_debug_enter(); | 132 | mfc_debug_enter(); |
133 | |||
127 | err = request_firmware((const struct firmware **)&fw_blob, | 134 | err = request_firmware((const struct firmware **)&fw_blob, |
128 | "s5p-mfc.fw", dev->v4l2_dev.dev); | 135 | dev->variant->fw_name, dev->v4l2_dev.dev); |
129 | if (err != 0) { | 136 | if (err != 0) { |
130 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); | 137 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); |
131 | return -EINVAL; | 138 | return -EINVAL; |
@@ -166,46 +173,81 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev) | |||
166 | { | 173 | { |
167 | unsigned int mc_status; | 174 | unsigned int mc_status; |
168 | unsigned long timeout; | 175 | unsigned long timeout; |
176 | int i; | ||
169 | 177 | ||
170 | mfc_debug_enter(); | 178 | mfc_debug_enter(); |
171 | /* Stop procedure */ | ||
172 | /* reset RISC */ | ||
173 | mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); | ||
174 | /* All reset except for MC */ | ||
175 | mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); | ||
176 | mdelay(10); | ||
177 | |||
178 | timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); | ||
179 | /* Check MC status */ | ||
180 | do { | ||
181 | if (time_after(jiffies, timeout)) { | ||
182 | mfc_err("Timeout while resetting MFC\n"); | ||
183 | return -EIO; | ||
184 | } | ||
185 | 179 | ||
186 | mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); | 180 | if (IS_MFCV6(dev)) { |
181 | /* Reset IP */ | ||
182 | /* except RISC, reset */ | ||
183 | mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6); | ||
184 | /* reset release */ | ||
185 | mfc_write(dev, 0x0, S5P_FIMV_MFC_RESET_V6); | ||
186 | |||
187 | /* Zero Initialization of MFC registers */ | ||
188 | mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); | ||
189 | mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6); | ||
190 | mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6); | ||
191 | |||
192 | for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++) | ||
193 | mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4)); | ||
194 | |||
195 | /* Reset */ | ||
196 | mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); | ||
197 | mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6); | ||
198 | mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6); | ||
199 | } else { | ||
200 | /* Stop procedure */ | ||
201 | /* reset RISC */ | ||
202 | mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); | ||
203 | /* All reset except for MC */ | ||
204 | mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); | ||
205 | mdelay(10); | ||
187 | 206 | ||
188 | } while (mc_status & 0x3); | 207 | timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); |
208 | /* Check MC status */ | ||
209 | do { | ||
210 | if (time_after(jiffies, timeout)) { | ||
211 | mfc_err("Timeout while resetting MFC\n"); | ||
212 | return -EIO; | ||
213 | } | ||
214 | |||
215 | mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); | ||
216 | |||
217 | } while (mc_status & 0x3); | ||
218 | |||
219 | mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); | ||
220 | mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); | ||
221 | } | ||
189 | 222 | ||
190 | mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); | ||
191 | mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); | ||
192 | mfc_debug_leave(); | 223 | mfc_debug_leave(); |
193 | return 0; | 224 | return 0; |
194 | } | 225 | } |
195 | 226 | ||
196 | static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) | 227 | static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) |
197 | { | 228 | { |
198 | mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); | 229 | if (IS_MFCV6(dev)) { |
199 | mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); | 230 | mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6); |
200 | mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2); | 231 | mfc_debug(2, "Base Address : %08x\n", dev->bank1); |
232 | } else { | ||
233 | mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); | ||
234 | mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); | ||
235 | mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", | ||
236 | dev->bank1, dev->bank2); | ||
237 | } | ||
201 | } | 238 | } |
202 | 239 | ||
203 | static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) | 240 | static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) |
204 | { | 241 | { |
205 | mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); | 242 | if (IS_MFCV6(dev)) { |
206 | mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); | 243 | /* Zero initialization should be done before RESET. |
207 | mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); | 244 | * Nothing to do here. */ |
208 | mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); | 245 | } else { |
246 | mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); | ||
247 | mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); | ||
248 | mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); | ||
249 | mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); | ||
250 | } | ||
209 | } | 251 | } |
210 | 252 | ||
211 | /* Initialize hardware */ | 253 | /* Initialize hardware */ |
@@ -233,7 +275,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) | |||
233 | s5p_mfc_clear_cmds(dev); | 275 | s5p_mfc_clear_cmds(dev); |
234 | /* 3. Release reset signal to the RISC */ | 276 | /* 3. Release reset signal to the RISC */ |
235 | s5p_mfc_clean_dev_int_flags(dev); | 277 | s5p_mfc_clean_dev_int_flags(dev); |
236 | mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); | 278 | if (IS_MFCV6(dev)) |
279 | mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); | ||
280 | else | ||
281 | mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); | ||
237 | mfc_debug(2, "Will now wait for completion of firmware transfer\n"); | 282 | mfc_debug(2, "Will now wait for completion of firmware transfer\n"); |
238 | if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { | 283 | if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { |
239 | mfc_err("Failed to load firmware\n"); | 284 | mfc_err("Failed to load firmware\n"); |
@@ -267,7 +312,11 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) | |||
267 | s5p_mfc_clock_off(); | 312 | s5p_mfc_clock_off(); |
268 | return -EIO; | 313 | return -EIO; |
269 | } | 314 | } |
270 | ver = mfc_read(dev, S5P_FIMV_FW_VERSION); | 315 | if (IS_MFCV6(dev)) |
316 | ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6); | ||
317 | else | ||
318 | ver = mfc_read(dev, S5P_FIMV_FW_VERSION); | ||
319 | |||
271 | mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", | 320 | mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", |
272 | (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); | 321 | (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); |
273 | s5p_mfc_clock_off(); | 322 | s5p_mfc_clock_off(); |
@@ -342,7 +391,10 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) | |||
342 | return ret; | 391 | return ret; |
343 | } | 392 | } |
344 | /* 4. Release reset signal to the RISC */ | 393 | /* 4. Release reset signal to the RISC */ |
345 | mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); | 394 | if (IS_MFCV6(dev)) |
395 | mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); | ||
396 | else | ||
397 | mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); | ||
346 | mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); | 398 | mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); |
347 | if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { | 399 | if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) { |
348 | mfc_err("Failed to load firmware\n"); | 400 | mfc_err("Failed to load firmware\n"); |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 107609c4e51a..eb6a70b0f821 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | |||
@@ -31,10 +31,17 @@ | |||
31 | #include "s5p_mfc_pm.h" | 31 | #include "s5p_mfc_pm.h" |
32 | 32 | ||
33 | #define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264 | 33 | #define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264 |
34 | #define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT | 34 | #define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT_16X16 |
35 | 35 | ||
36 | static struct s5p_mfc_fmt formats[] = { | 36 | static struct s5p_mfc_fmt formats[] = { |
37 | { | 37 | { |
38 | .name = "4:2:0 2 Planes 16x16 Tiles", | ||
39 | .fourcc = V4L2_PIX_FMT_NV12MT_16X16, | ||
40 | .codec_mode = S5P_MFC_CODEC_NONE, | ||
41 | .type = MFC_FMT_RAW, | ||
42 | .num_planes = 2, | ||
43 | }, | ||
44 | { | ||
38 | .name = "4:2:0 2 Planes 64x32 Tiles", | 45 | .name = "4:2:0 2 Planes 64x32 Tiles", |
39 | .fourcc = V4L2_PIX_FMT_NV12MT, | 46 | .fourcc = V4L2_PIX_FMT_NV12MT, |
40 | .codec_mode = S5P_MFC_CODEC_NONE, | 47 | .codec_mode = S5P_MFC_CODEC_NONE, |
@@ -42,67 +49,88 @@ static struct s5p_mfc_fmt formats[] = { | |||
42 | .num_planes = 2, | 49 | .num_planes = 2, |
43 | }, | 50 | }, |
44 | { | 51 | { |
45 | .name = "4:2:0 2 Planes", | 52 | .name = "4:2:0 2 Planes Y/CbCr", |
46 | .fourcc = V4L2_PIX_FMT_NV12M, | 53 | .fourcc = V4L2_PIX_FMT_NV12M, |
47 | .codec_mode = S5P_MFC_CODEC_NONE, | 54 | .codec_mode = S5P_MFC_CODEC_NONE, |
48 | .type = MFC_FMT_RAW, | 55 | .type = MFC_FMT_RAW, |
49 | .num_planes = 2, | 56 | .num_planes = 2, |
57 | }, | ||
58 | { | ||
59 | .name = "4:2:0 2 Planes Y/CrCb", | ||
60 | .fourcc = V4L2_PIX_FMT_NV21M, | ||
61 | .codec_mode = S5P_MFC_CODEC_NONE, | ||
62 | .type = MFC_FMT_RAW, | ||
63 | .num_planes = 2, | ||
64 | }, | ||
65 | { | ||
66 | .name = "H264 Encoded Stream", | ||
67 | .fourcc = V4L2_PIX_FMT_H264, | ||
68 | .codec_mode = S5P_MFC_CODEC_H264_DEC, | ||
69 | .type = MFC_FMT_DEC, | ||
70 | .num_planes = 1, | ||
50 | }, | 71 | }, |
51 | { | 72 | { |
52 | .name = "H264 Encoded Stream", | 73 | .name = "H264/MVC Encoded Stream", |
53 | .fourcc = V4L2_PIX_FMT_H264, | 74 | .fourcc = V4L2_PIX_FMT_H264_MVC, |
54 | .codec_mode = S5P_MFC_CODEC_H264_DEC, | 75 | .codec_mode = S5P_MFC_CODEC_H264_MVC_DEC, |
55 | .type = MFC_FMT_DEC, | 76 | .type = MFC_FMT_DEC, |
56 | .num_planes = 1, | 77 | .num_planes = 1, |
57 | }, | 78 | }, |
58 | { | 79 | { |
59 | .name = "H263 Encoded Stream", | 80 | .name = "H263 Encoded Stream", |
60 | .fourcc = V4L2_PIX_FMT_H263, | 81 | .fourcc = V4L2_PIX_FMT_H263, |
61 | .codec_mode = S5P_MFC_CODEC_H263_DEC, | 82 | .codec_mode = S5P_MFC_CODEC_H263_DEC, |
62 | .type = MFC_FMT_DEC, | 83 | .type = MFC_FMT_DEC, |
63 | .num_planes = 1, | 84 | .num_planes = 1, |
64 | }, | 85 | }, |
65 | { | 86 | { |
66 | .name = "MPEG1 Encoded Stream", | 87 | .name = "MPEG1 Encoded Stream", |
67 | .fourcc = V4L2_PIX_FMT_MPEG1, | 88 | .fourcc = V4L2_PIX_FMT_MPEG1, |
68 | .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, | 89 | .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, |
69 | .type = MFC_FMT_DEC, | 90 | .type = MFC_FMT_DEC, |
70 | .num_planes = 1, | 91 | .num_planes = 1, |
71 | }, | 92 | }, |
72 | { | 93 | { |
73 | .name = "MPEG2 Encoded Stream", | 94 | .name = "MPEG2 Encoded Stream", |
74 | .fourcc = V4L2_PIX_FMT_MPEG2, | 95 | .fourcc = V4L2_PIX_FMT_MPEG2, |
75 | .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, | 96 | .codec_mode = S5P_MFC_CODEC_MPEG2_DEC, |
76 | .type = MFC_FMT_DEC, | 97 | .type = MFC_FMT_DEC, |
77 | .num_planes = 1, | 98 | .num_planes = 1, |
78 | }, | 99 | }, |
79 | { | 100 | { |
80 | .name = "MPEG4 Encoded Stream", | 101 | .name = "MPEG4 Encoded Stream", |
81 | .fourcc = V4L2_PIX_FMT_MPEG4, | 102 | .fourcc = V4L2_PIX_FMT_MPEG4, |
82 | .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, | 103 | .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, |
83 | .type = MFC_FMT_DEC, | 104 | .type = MFC_FMT_DEC, |
84 | .num_planes = 1, | 105 | .num_planes = 1, |
85 | }, | 106 | }, |
86 | { | 107 | { |
87 | .name = "XviD Encoded Stream", | 108 | .name = "XviD Encoded Stream", |
88 | .fourcc = V4L2_PIX_FMT_XVID, | 109 | .fourcc = V4L2_PIX_FMT_XVID, |
89 | .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, | 110 | .codec_mode = S5P_MFC_CODEC_MPEG4_DEC, |
90 | .type = MFC_FMT_DEC, | 111 | .type = MFC_FMT_DEC, |
91 | .num_planes = 1, | 112 | .num_planes = 1, |
92 | }, | 113 | }, |
93 | { | 114 | { |
94 | .name = "VC1 Encoded Stream", | 115 | .name = "VC1 Encoded Stream", |
95 | .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, | 116 | .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, |
96 | .codec_mode = S5P_MFC_CODEC_VC1_DEC, | 117 | .codec_mode = S5P_MFC_CODEC_VC1_DEC, |
97 | .type = MFC_FMT_DEC, | 118 | .type = MFC_FMT_DEC, |
98 | .num_planes = 1, | 119 | .num_planes = 1, |
99 | }, | 120 | }, |
100 | { | 121 | { |
101 | .name = "VC1 RCV Encoded Stream", | 122 | .name = "VC1 RCV Encoded Stream", |
102 | .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, | 123 | .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, |
103 | .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, | 124 | .codec_mode = S5P_MFC_CODEC_VC1RCV_DEC, |
104 | .type = MFC_FMT_DEC, | 125 | .type = MFC_FMT_DEC, |
105 | .num_planes = 1, | 126 | .num_planes = 1, |
127 | }, | ||
128 | { | ||
129 | .name = "VP8 Encoded Stream", | ||
130 | .fourcc = V4L2_PIX_FMT_VP8, | ||
131 | .codec_mode = S5P_MFC_CODEC_VP8_DEC, | ||
132 | .type = MFC_FMT_DEC, | ||
133 | .num_planes = 1, | ||
106 | }, | 134 | }, |
107 | }; | 135 | }; |
108 | 136 | ||
@@ -343,21 +371,36 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
343 | /* Try format */ | 371 | /* Try format */ |
344 | static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) | 372 | static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) |
345 | { | 373 | { |
374 | struct s5p_mfc_dev *dev = video_drvdata(file); | ||
346 | struct s5p_mfc_fmt *fmt; | 375 | struct s5p_mfc_fmt *fmt; |
347 | 376 | ||
348 | if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | 377 | mfc_debug(2, "Type is %d\n", f->type); |
349 | mfc_err("This node supports decoding only\n"); | 378 | if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
350 | return -EINVAL; | 379 | fmt = find_format(f, MFC_FMT_DEC); |
351 | } | 380 | if (!fmt) { |
352 | fmt = find_format(f, MFC_FMT_DEC); | 381 | mfc_err("Unsupported format for source.\n"); |
353 | if (!fmt) { | 382 | return -EINVAL; |
354 | mfc_err("Unsupported format\n"); | 383 | } |
355 | return -EINVAL; | 384 | if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { |
356 | } | 385 | mfc_err("Not supported format.\n"); |
357 | if (fmt->type != MFC_FMT_DEC) { | 386 | return -EINVAL; |
358 | mfc_err("\n"); | 387 | } |
359 | return -EINVAL; | 388 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
389 | fmt = find_format(f, MFC_FMT_RAW); | ||
390 | if (!fmt) { | ||
391 | mfc_err("Unsupported format for destination.\n"); | ||
392 | return -EINVAL; | ||
393 | } | ||
394 | if (IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { | ||
395 | mfc_err("Not supported format.\n"); | ||
396 | return -EINVAL; | ||
397 | } else if (!IS_MFCV6(dev) && | ||
398 | (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { | ||
399 | mfc_err("Not supported format.\n"); | ||
400 | return -EINVAL; | ||
401 | } | ||
360 | } | 402 | } |
403 | |||
361 | return 0; | 404 | return 0; |
362 | } | 405 | } |
363 | 406 | ||
@@ -380,6 +423,27 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
380 | ret = -EBUSY; | 423 | ret = -EBUSY; |
381 | goto out; | 424 | goto out; |
382 | } | 425 | } |
426 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
427 | fmt = find_format(f, MFC_FMT_RAW); | ||
428 | if (!fmt) { | ||
429 | mfc_err("Unsupported format for source.\n"); | ||
430 | return -EINVAL; | ||
431 | } | ||
432 | if (!IS_MFCV6(dev) && (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) { | ||
433 | mfc_err("Not supported format.\n"); | ||
434 | return -EINVAL; | ||
435 | } else if (IS_MFCV6(dev) && | ||
436 | (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { | ||
437 | mfc_err("Not supported format.\n"); | ||
438 | return -EINVAL; | ||
439 | } | ||
440 | ctx->dst_fmt = fmt; | ||
441 | mfc_debug_leave(); | ||
442 | return ret; | ||
443 | } else if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
444 | mfc_err("Wrong type error for S_FMT : %d", f->type); | ||
445 | return -EINVAL; | ||
446 | } | ||
383 | fmt = find_format(f, MFC_FMT_DEC); | 447 | fmt = find_format(f, MFC_FMT_DEC); |
384 | if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) { | 448 | if (!fmt || fmt->codec_mode == S5P_MFC_CODEC_NONE) { |
385 | mfc_err("Unknown codec\n"); | 449 | mfc_err("Unknown codec\n"); |
@@ -392,6 +456,10 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
392 | ret = -EINVAL; | 456 | ret = -EINVAL; |
393 | goto out; | 457 | goto out; |
394 | } | 458 | } |
459 | if (!IS_MFCV6(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) { | ||
460 | mfc_err("Not supported format.\n"); | ||
461 | return -EINVAL; | ||
462 | } | ||
395 | ctx->src_fmt = fmt; | 463 | ctx->src_fmt = fmt; |
396 | ctx->codec_mode = fmt->codec_mode; | 464 | ctx->codec_mode = fmt->codec_mode; |
397 | mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); | 465 | 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, | |||
756 | void *allocators[]) | 824 | void *allocators[]) |
757 | { | 825 | { |
758 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | 826 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); |
827 | struct s5p_mfc_dev *dev = ctx->dev; | ||
759 | 828 | ||
760 | /* Video output for decoding (source) | 829 | /* Video output for decoding (source) |
761 | * this can be set after getting an instance */ | 830 | * this can be set after getting an instance */ |
@@ -791,7 +860,13 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, | |||
791 | vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | 860 | vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
792 | psize[0] = ctx->luma_size; | 861 | psize[0] = ctx->luma_size; |
793 | psize[1] = ctx->chroma_size; | 862 | psize[1] = ctx->chroma_size; |
794 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | 863 | |
864 | if (IS_MFCV6(dev)) | ||
865 | allocators[0] = | ||
866 | ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | ||
867 | else | ||
868 | allocators[0] = | ||
869 | ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | ||
795 | allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | 870 | allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; |
796 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | 871 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && |
797 | ctx->state == MFCINST_INIT) { | 872 | ctx->state == MFCINST_INIT) { |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index b0879f912db3..2af6d522f4ac 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | |||
@@ -36,39 +36,53 @@ | |||
36 | 36 | ||
37 | static struct s5p_mfc_fmt formats[] = { | 37 | static struct s5p_mfc_fmt formats[] = { |
38 | { | 38 | { |
39 | .name = "4:2:0 2 Planes 64x32 Tiles", | 39 | .name = "4:2:0 2 Planes 16x16 Tiles", |
40 | .fourcc = V4L2_PIX_FMT_NV12MT, | 40 | .fourcc = V4L2_PIX_FMT_NV12MT_16X16, |
41 | .codec_mode = S5P_MFC_CODEC_NONE, | 41 | .codec_mode = S5P_MFC_CODEC_NONE, |
42 | .type = MFC_FMT_RAW, | 42 | .type = MFC_FMT_RAW, |
43 | .num_planes = 2, | 43 | .num_planes = 2, |
44 | }, | 44 | }, |
45 | { | 45 | { |
46 | .name = "4:2:0 2 Planes", | 46 | .name = "4:2:0 2 Planes 64x32 Tiles", |
47 | .fourcc = V4L2_PIX_FMT_NV12M, | 47 | .fourcc = V4L2_PIX_FMT_NV12MT, |
48 | .codec_mode = S5P_MFC_CODEC_NONE, | 48 | .codec_mode = S5P_MFC_CODEC_NONE, |
49 | .type = MFC_FMT_RAW, | 49 | .type = MFC_FMT_RAW, |
50 | .num_planes = 2, | 50 | .num_planes = 2, |
51 | }, | 51 | }, |
52 | { | 52 | { |
53 | .name = "H264 Encoded Stream", | 53 | .name = "4:2:0 2 Planes Y/CbCr", |
54 | .fourcc = V4L2_PIX_FMT_H264, | 54 | .fourcc = V4L2_PIX_FMT_NV12M, |
55 | .codec_mode = S5P_MFC_CODEC_H264_ENC, | 55 | .codec_mode = S5P_MFC_CODEC_NONE, |
56 | .type = MFC_FMT_ENC, | 56 | .type = MFC_FMT_RAW, |
57 | .num_planes = 1, | 57 | .num_planes = 2, |
58 | }, | 58 | }, |
59 | { | 59 | { |
60 | .name = "MPEG4 Encoded Stream", | 60 | .name = "4:2:0 2 Planes Y/CrCb", |
61 | .fourcc = V4L2_PIX_FMT_MPEG4, | 61 | .fourcc = V4L2_PIX_FMT_NV21M, |
62 | .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, | 62 | .codec_mode = S5P_MFC_CODEC_NONE, |
63 | .type = MFC_FMT_ENC, | 63 | .type = MFC_FMT_RAW, |
64 | .num_planes = 1, | 64 | .num_planes = 2, |
65 | }, | 65 | }, |
66 | { | 66 | { |
67 | .name = "H263 Encoded Stream", | 67 | .name = "H264 Encoded Stream", |
68 | .fourcc = V4L2_PIX_FMT_H263, | 68 | .fourcc = V4L2_PIX_FMT_H264, |
69 | .codec_mode = S5P_MFC_CODEC_H263_ENC, | 69 | .codec_mode = S5P_MFC_CODEC_H264_ENC, |
70 | .type = MFC_FMT_ENC, | 70 | .type = MFC_FMT_ENC, |
71 | .num_planes = 1, | 71 | .num_planes = 1, |
72 | }, | ||
73 | { | ||
74 | .name = "MPEG4 Encoded Stream", | ||
75 | .fourcc = V4L2_PIX_FMT_MPEG4, | ||
76 | .codec_mode = S5P_MFC_CODEC_MPEG4_ENC, | ||
77 | .type = MFC_FMT_ENC, | ||
78 | .num_planes = 1, | ||
79 | }, | ||
80 | { | ||
81 | .name = "H263 Encoded Stream", | ||
82 | .fourcc = V4L2_PIX_FMT_H263, | ||
83 | .codec_mode = S5P_MFC_CODEC_H263_ENC, | ||
84 | .type = MFC_FMT_ENC, | ||
85 | .num_planes = 1, | ||
72 | }, | 86 | }, |
73 | }; | 87 | }; |
74 | 88 | ||
@@ -576,7 +590,8 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) | |||
576 | if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1) | 590 | if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1) |
577 | return 1; | 591 | return 1; |
578 | /* context is ready to encode a frame */ | 592 | /* context is ready to encode a frame */ |
579 | if (ctx->state == MFCINST_RUNNING && | 593 | if ((ctx->state == MFCINST_RUNNING || |
594 | ctx->state == MFCINST_HEAD_PARSED) && | ||
580 | ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) | 595 | ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) |
581 | return 1; | 596 | return 1; |
582 | /* context is ready to encode remaining frames */ | 597 | /* context is ready to encode remaining frames */ |
@@ -645,10 +660,19 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) | |||
645 | vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE); | 660 | vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE); |
646 | spin_unlock_irqrestore(&dev->irqlock, flags); | 661 | spin_unlock_irqrestore(&dev->irqlock, flags); |
647 | } | 662 | } |
648 | ctx->state = MFCINST_RUNNING; | 663 | if (IS_MFCV6(dev)) { |
649 | if (s5p_mfc_ctx_ready(ctx)) | 664 | ctx->state = MFCINST_HEAD_PARSED; /* for INIT_BUFFER cmd */ |
650 | set_work_bit_irqsave(ctx); | 665 | } else { |
651 | s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); | 666 | ctx->state = MFCINST_RUNNING; |
667 | if (s5p_mfc_ctx_ready(ctx)) | ||
668 | set_work_bit_irqsave(ctx); | ||
669 | s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); | ||
670 | } | ||
671 | |||
672 | if (IS_MFCV6(dev)) | ||
673 | ctx->dpb_count = s5p_mfc_hw_call(dev->mfc_ops, | ||
674 | get_enc_dpb_count, dev); | ||
675 | |||
652 | return 0; | 676 | return 0; |
653 | } | 677 | } |
654 | 678 | ||
@@ -965,6 +989,17 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | |||
965 | mfc_err("failed to set output format\n"); | 989 | mfc_err("failed to set output format\n"); |
966 | return -EINVAL; | 990 | return -EINVAL; |
967 | } | 991 | } |
992 | |||
993 | if (!IS_MFCV6(dev) && | ||
994 | (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)) { | ||
995 | mfc_err("Not supported format.\n"); | ||
996 | return -EINVAL; | ||
997 | } else if (IS_MFCV6(dev) && | ||
998 | (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) { | ||
999 | mfc_err("Not supported format.\n"); | ||
1000 | return -EINVAL; | ||
1001 | } | ||
1002 | |||
968 | if (fmt->num_planes != pix_fmt_mp->num_planes) { | 1003 | if (fmt->num_planes != pix_fmt_mp->num_planes) { |
969 | mfc_err("failed to set output format\n"); | 1004 | mfc_err("failed to set output format\n"); |
970 | ret = -EINVAL; | 1005 | ret = -EINVAL; |
@@ -998,6 +1033,7 @@ out: | |||
998 | static int vidioc_reqbufs(struct file *file, void *priv, | 1033 | static int vidioc_reqbufs(struct file *file, void *priv, |
999 | struct v4l2_requestbuffers *reqbufs) | 1034 | struct v4l2_requestbuffers *reqbufs) |
1000 | { | 1035 | { |
1036 | struct s5p_mfc_dev *dev = video_drvdata(file); | ||
1001 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | 1037 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); |
1002 | int ret = 0; | 1038 | int ret = 0; |
1003 | 1039 | ||
@@ -1017,13 +1053,16 @@ static int vidioc_reqbufs(struct file *file, void *priv, | |||
1017 | return ret; | 1053 | return ret; |
1018 | } | 1054 | } |
1019 | ctx->capture_state = QUEUE_BUFS_REQUESTED; | 1055 | ctx->capture_state = QUEUE_BUFS_REQUESTED; |
1020 | ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, alloc_codec_buffers, | 1056 | |
1021 | ctx); | 1057 | if (!IS_MFCV6(dev)) { |
1022 | if (ret) { | 1058 | ret = s5p_mfc_hw_call(ctx->dev->mfc_ops, |
1023 | mfc_err("Failed to allocate encoding buffers\n"); | 1059 | alloc_codec_buffers, ctx); |
1024 | reqbufs->count = 0; | 1060 | if (ret) { |
1025 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | 1061 | mfc_err("Failed to allocate encoding buffers\n"); |
1026 | return -ENOMEM; | 1062 | reqbufs->count = 0; |
1063 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | ||
1064 | return -ENOMEM; | ||
1065 | } | ||
1027 | } | 1066 | } |
1028 | } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | 1067 | } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { |
1029 | if (ctx->output_state != QUEUE_FREE) { | 1068 | if (ctx->output_state != QUEUE_FREE) { |
@@ -1286,6 +1325,13 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) | |||
1286 | p->codec.h264.profile = | 1325 | p->codec.h264.profile = |
1287 | S5P_FIMV_ENC_PROFILE_H264_BASELINE; | 1326 | S5P_FIMV_ENC_PROFILE_H264_BASELINE; |
1288 | break; | 1327 | break; |
1328 | case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: | ||
1329 | if (IS_MFCV6(dev)) | ||
1330 | p->codec.h264.profile = | ||
1331 | S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE; | ||
1332 | else | ||
1333 | ret = -EINVAL; | ||
1334 | break; | ||
1289 | default: | 1335 | default: |
1290 | ret = -EINVAL; | 1336 | ret = -EINVAL; |
1291 | } | 1337 | } |
@@ -1559,6 +1605,7 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, | |||
1559 | unsigned int psize[], void *allocators[]) | 1605 | unsigned int psize[], void *allocators[]) |
1560 | { | 1606 | { |
1561 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | 1607 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); |
1608 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1562 | 1609 | ||
1563 | if (ctx->state != MFCINST_GOT_INST) { | 1610 | if (ctx->state != MFCINST_GOT_INST) { |
1564 | mfc_err("inavlid state: %d\n", ctx->state); | 1611 | mfc_err("inavlid state: %d\n", ctx->state); |
@@ -1587,8 +1634,17 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq, | |||
1587 | *buf_count = MFC_MAX_BUFFERS; | 1634 | *buf_count = MFC_MAX_BUFFERS; |
1588 | psize[0] = ctx->luma_size; | 1635 | psize[0] = ctx->luma_size; |
1589 | psize[1] = ctx->chroma_size; | 1636 | psize[1] = ctx->chroma_size; |
1590 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | 1637 | if (IS_MFCV6(dev)) { |
1591 | allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | 1638 | allocators[0] = |
1639 | ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | ||
1640 | allocators[1] = | ||
1641 | ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | ||
1642 | } else { | ||
1643 | allocators[0] = | ||
1644 | ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | ||
1645 | allocators[1] = | ||
1646 | ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | ||
1647 | } | ||
1592 | } else { | 1648 | } else { |
1593 | mfc_err("inavlid queue type: %d\n", vq->type); | 1649 | mfc_err("inavlid queue type: %d\n", vq->type); |
1594 | return -EINVAL; | 1650 | return -EINVAL; |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index b6246b2ae759..6932e90d4065 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | |||
@@ -14,12 +14,18 @@ | |||
14 | 14 | ||
15 | #include "s5p_mfc_opr.h" | 15 | #include "s5p_mfc_opr.h" |
16 | #include "s5p_mfc_opr_v5.h" | 16 | #include "s5p_mfc_opr_v5.h" |
17 | #include "s5p_mfc_opr_v6.h" | ||
17 | 18 | ||
18 | static struct s5p_mfc_hw_ops *s5p_mfc_ops; | 19 | static struct s5p_mfc_hw_ops *s5p_mfc_ops; |
19 | 20 | ||
20 | void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev) | 21 | void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev) |
21 | { | 22 | { |
22 | s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); | 23 | if (IS_MFCV6(dev)) { |
23 | dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; | 24 | s5p_mfc_ops = s5p_mfc_init_hw_ops_v6(); |
25 | dev->warn_start = S5P_FIMV_ERR_WARNINGS_START_V6; | ||
26 | } else { | ||
27 | s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); | ||
28 | dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; | ||
29 | } | ||
24 | dev->mfc_ops = s5p_mfc_ops; | 30 | dev->mfc_ops = s5p_mfc_ops; |
25 | } | 31 | } |
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c new file mode 100644 index 000000000000..50b5bee3c44e --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | |||
@@ -0,0 +1,1956 @@ | |||
1 | /* | ||
2 | * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | ||
3 | * | ||
4 | * Samsung MFC (Multi Function Codec - FIMV) driver | ||
5 | * This file contains hw related functions. | ||
6 | * | ||
7 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
8 | * http://www.samsung.com/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #undef DEBUG | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/jiffies.h> | ||
21 | #include <linux/firmware.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/dma-mapping.h> | ||
25 | |||
26 | #include <asm/cacheflush.h> | ||
27 | |||
28 | #include "s5p_mfc_common.h" | ||
29 | #include "s5p_mfc_cmd.h" | ||
30 | #include "s5p_mfc_intr.h" | ||
31 | #include "s5p_mfc_pm.h" | ||
32 | #include "s5p_mfc_debug.h" | ||
33 | #include "s5p_mfc_opr.h" | ||
34 | #include "s5p_mfc_opr_v6.h" | ||
35 | |||
36 | /* #define S5P_MFC_DEBUG_REGWRITE */ | ||
37 | #ifdef S5P_MFC_DEBUG_REGWRITE | ||
38 | #undef writel | ||
39 | #define writel(v, r) \ | ||
40 | do { \ | ||
41 | pr_err("MFCWRITE(%p): %08x\n", r, (unsigned int)v); \ | ||
42 | __raw_writel(v, r); \ | ||
43 | } while (0) | ||
44 | #endif /* S5P_MFC_DEBUG_REGWRITE */ | ||
45 | |||
46 | #define READL(offset) readl(dev->regs_base + (offset)) | ||
47 | #define WRITEL(data, offset) writel((data), dev->regs_base + (offset)) | ||
48 | #define OFFSETA(x) (((x) - dev->port_a) >> S5P_FIMV_MEM_OFFSET) | ||
49 | #define OFFSETB(x) (((x) - dev->port_b) >> S5P_FIMV_MEM_OFFSET) | ||
50 | |||
51 | /* Allocate temporary buffers for decoding */ | ||
52 | int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx) | ||
53 | { | ||
54 | /* NOP */ | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | /* Release temproary buffers for decoding */ | ||
60 | void s5p_mfc_release_dec_desc_buffer_v6(struct s5p_mfc_ctx *ctx) | ||
61 | { | ||
62 | /* NOP */ | ||
63 | } | ||
64 | |||
65 | int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev) | ||
66 | { | ||
67 | /* NOP */ | ||
68 | return -1; | ||
69 | } | ||
70 | |||
71 | /* Allocate codec buffers */ | ||
72 | int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx) | ||
73 | { | ||
74 | struct s5p_mfc_dev *dev = ctx->dev; | ||
75 | unsigned int mb_width, mb_height; | ||
76 | |||
77 | mb_width = MB_WIDTH(ctx->img_width); | ||
78 | mb_height = MB_HEIGHT(ctx->img_height); | ||
79 | |||
80 | if (ctx->type == MFCINST_DECODER) { | ||
81 | mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", | ||
82 | ctx->luma_size, ctx->chroma_size, ctx->mv_size); | ||
83 | mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); | ||
84 | } else if (ctx->type == MFCINST_ENCODER) { | ||
85 | ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 * | ||
86 | ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height), | ||
87 | S5P_FIMV_TMV_BUFFER_ALIGN_V6); | ||
88 | ctx->luma_dpb_size = ALIGN((mb_width * mb_height) * | ||
89 | S5P_FIMV_LUMA_MB_TO_PIXEL_V6, | ||
90 | S5P_FIMV_LUMA_DPB_BUFFER_ALIGN_V6); | ||
91 | ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) * | ||
92 | S5P_FIMV_CHROMA_MB_TO_PIXEL_V6, | ||
93 | S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6); | ||
94 | ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6( | ||
95 | ctx->img_width, ctx->img_height, | ||
96 | mb_width, mb_height), | ||
97 | S5P_FIMV_ME_BUFFER_ALIGN_V6); | ||
98 | |||
99 | mfc_debug(2, "recon luma size: %d chroma size: %d\n", | ||
100 | ctx->luma_dpb_size, ctx->chroma_dpb_size); | ||
101 | } else { | ||
102 | return -EINVAL; | ||
103 | } | ||
104 | |||
105 | /* Codecs have different memory requirements */ | ||
106 | switch (ctx->codec_mode) { | ||
107 | case S5P_MFC_CODEC_H264_DEC: | ||
108 | case S5P_MFC_CODEC_H264_MVC_DEC: | ||
109 | ctx->scratch_buf_size = | ||
110 | S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6( | ||
111 | mb_width, | ||
112 | mb_height); | ||
113 | ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, | ||
114 | S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); | ||
115 | ctx->bank1_size = | ||
116 | ctx->scratch_buf_size + | ||
117 | (ctx->mv_count * ctx->mv_size); | ||
118 | break; | ||
119 | case S5P_MFC_CODEC_MPEG4_DEC: | ||
120 | ctx->scratch_buf_size = | ||
121 | S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6( | ||
122 | mb_width, | ||
123 | mb_height); | ||
124 | ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, | ||
125 | S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); | ||
126 | ctx->bank1_size = ctx->scratch_buf_size; | ||
127 | break; | ||
128 | case S5P_MFC_CODEC_VC1RCV_DEC: | ||
129 | case S5P_MFC_CODEC_VC1_DEC: | ||
130 | ctx->scratch_buf_size = | ||
131 | S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6( | ||
132 | mb_width, | ||
133 | mb_height); | ||
134 | ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, | ||
135 | S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); | ||
136 | ctx->bank1_size = ctx->scratch_buf_size; | ||
137 | break; | ||
138 | case S5P_MFC_CODEC_MPEG2_DEC: | ||
139 | ctx->bank1_size = 0; | ||
140 | ctx->bank2_size = 0; | ||
141 | break; | ||
142 | case S5P_MFC_CODEC_H263_DEC: | ||
143 | ctx->scratch_buf_size = | ||
144 | S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6( | ||
145 | mb_width, | ||
146 | mb_height); | ||
147 | ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, | ||
148 | S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); | ||
149 | ctx->bank1_size = ctx->scratch_buf_size; | ||
150 | break; | ||
151 | case S5P_MFC_CODEC_VP8_DEC: | ||
152 | ctx->scratch_buf_size = | ||
153 | S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6( | ||
154 | mb_width, | ||
155 | mb_height); | ||
156 | ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, | ||
157 | S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); | ||
158 | ctx->bank1_size = ctx->scratch_buf_size; | ||
159 | break; | ||
160 | case S5P_MFC_CODEC_H264_ENC: | ||
161 | ctx->scratch_buf_size = | ||
162 | S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6( | ||
163 | mb_width, | ||
164 | mb_height); | ||
165 | ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, | ||
166 | S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); | ||
167 | ctx->bank1_size = | ||
168 | ctx->scratch_buf_size + ctx->tmv_buffer_size + | ||
169 | (ctx->dpb_count * (ctx->luma_dpb_size + | ||
170 | ctx->chroma_dpb_size + ctx->me_buffer_size)); | ||
171 | ctx->bank2_size = 0; | ||
172 | break; | ||
173 | case S5P_MFC_CODEC_MPEG4_ENC: | ||
174 | case S5P_MFC_CODEC_H263_ENC: | ||
175 | ctx->scratch_buf_size = | ||
176 | S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_ENC_V6( | ||
177 | mb_width, | ||
178 | mb_height); | ||
179 | ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, | ||
180 | S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6); | ||
181 | ctx->bank1_size = | ||
182 | ctx->scratch_buf_size + ctx->tmv_buffer_size + | ||
183 | (ctx->dpb_count * (ctx->luma_dpb_size + | ||
184 | ctx->chroma_dpb_size + ctx->me_buffer_size)); | ||
185 | ctx->bank2_size = 0; | ||
186 | break; | ||
187 | default: | ||
188 | break; | ||
189 | } | ||
190 | |||
191 | /* Allocate only if memory from bank 1 is necessary */ | ||
192 | if (ctx->bank1_size > 0) { | ||
193 | ctx->bank1_buf = vb2_dma_contig_memops.alloc( | ||
194 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); | ||
195 | if (IS_ERR(ctx->bank1_buf)) { | ||
196 | ctx->bank1_buf = 0; | ||
197 | pr_err("Buf alloc for decoding failed (port A)\n"); | ||
198 | return -ENOMEM; | ||
199 | } | ||
200 | ctx->bank1_phys = s5p_mfc_mem_cookie( | ||
201 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); | ||
202 | BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* Release buffers allocated for codec */ | ||
209 | void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) | ||
210 | { | ||
211 | if (ctx->bank1_buf) { | ||
212 | vb2_dma_contig_memops.put(ctx->bank1_buf); | ||
213 | ctx->bank1_buf = 0; | ||
214 | ctx->bank1_phys = 0; | ||
215 | ctx->bank1_size = 0; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | /* Allocate memory for instance data buffer */ | ||
220 | int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) | ||
221 | { | ||
222 | struct s5p_mfc_dev *dev = ctx->dev; | ||
223 | struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; | ||
224 | |||
225 | mfc_debug_enter(); | ||
226 | |||
227 | switch (ctx->codec_mode) { | ||
228 | case S5P_MFC_CODEC_H264_DEC: | ||
229 | case S5P_MFC_CODEC_H264_MVC_DEC: | ||
230 | ctx->ctx.size = buf_size->h264_dec_ctx; | ||
231 | break; | ||
232 | case S5P_MFC_CODEC_MPEG4_DEC: | ||
233 | case S5P_MFC_CODEC_H263_DEC: | ||
234 | case S5P_MFC_CODEC_VC1RCV_DEC: | ||
235 | case S5P_MFC_CODEC_VC1_DEC: | ||
236 | case S5P_MFC_CODEC_MPEG2_DEC: | ||
237 | case S5P_MFC_CODEC_VP8_DEC: | ||
238 | ctx->ctx.size = buf_size->other_dec_ctx; | ||
239 | break; | ||
240 | case S5P_MFC_CODEC_H264_ENC: | ||
241 | ctx->ctx.size = buf_size->h264_enc_ctx; | ||
242 | break; | ||
243 | case S5P_MFC_CODEC_MPEG4_ENC: | ||
244 | case S5P_MFC_CODEC_H263_ENC: | ||
245 | ctx->ctx.size = buf_size->other_enc_ctx; | ||
246 | break; | ||
247 | default: | ||
248 | ctx->ctx.size = 0; | ||
249 | mfc_err("Codec type(%d) should be checked!\n", ctx->codec_mode); | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | ctx->ctx.alloc = vb2_dma_contig_memops.alloc( | ||
254 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.size); | ||
255 | if (IS_ERR(ctx->ctx.alloc)) { | ||
256 | mfc_err("Allocating context buffer failed.\n"); | ||
257 | return PTR_ERR(ctx->ctx.alloc); | ||
258 | } | ||
259 | |||
260 | ctx->ctx.dma = s5p_mfc_mem_cookie( | ||
261 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx.alloc); | ||
262 | |||
263 | ctx->ctx.virt = vb2_dma_contig_memops.vaddr(ctx->ctx.alloc); | ||
264 | if (!ctx->ctx.virt) { | ||
265 | vb2_dma_contig_memops.put(ctx->ctx.alloc); | ||
266 | ctx->ctx.alloc = NULL; | ||
267 | ctx->ctx.dma = 0; | ||
268 | ctx->ctx.virt = NULL; | ||
269 | |||
270 | mfc_err("Remapping context buffer failed.\n"); | ||
271 | return -ENOMEM; | ||
272 | } | ||
273 | |||
274 | memset(ctx->ctx.virt, 0, ctx->ctx.size); | ||
275 | wmb(); | ||
276 | |||
277 | mfc_debug_leave(); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | /* Release instance buffer */ | ||
283 | void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) | ||
284 | { | ||
285 | mfc_debug_enter(); | ||
286 | |||
287 | if (ctx->ctx.alloc) { | ||
288 | vb2_dma_contig_memops.put(ctx->ctx.alloc); | ||
289 | ctx->ctx.alloc = NULL; | ||
290 | ctx->ctx.dma = 0; | ||
291 | ctx->ctx.virt = NULL; | ||
292 | } | ||
293 | |||
294 | mfc_debug_leave(); | ||
295 | } | ||
296 | |||
297 | /* Allocate context buffers for SYS_INIT */ | ||
298 | int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) | ||
299 | { | ||
300 | struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; | ||
301 | |||
302 | mfc_debug_enter(); | ||
303 | |||
304 | dev->ctx_buf.alloc = vb2_dma_contig_memops.alloc( | ||
305 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], buf_size->dev_ctx); | ||
306 | if (IS_ERR(dev->ctx_buf.alloc)) { | ||
307 | mfc_err("Allocating DESC buffer failed.\n"); | ||
308 | return PTR_ERR(dev->ctx_buf.alloc); | ||
309 | } | ||
310 | |||
311 | dev->ctx_buf.dma = s5p_mfc_mem_cookie( | ||
312 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], | ||
313 | dev->ctx_buf.alloc); | ||
314 | |||
315 | dev->ctx_buf.virt = vb2_dma_contig_memops.vaddr(dev->ctx_buf.alloc); | ||
316 | if (!dev->ctx_buf.virt) { | ||
317 | vb2_dma_contig_memops.put(dev->ctx_buf.alloc); | ||
318 | dev->ctx_buf.alloc = NULL; | ||
319 | dev->ctx_buf.dma = 0; | ||
320 | |||
321 | mfc_err("Remapping DESC buffer failed.\n"); | ||
322 | return -ENOMEM; | ||
323 | } | ||
324 | |||
325 | memset(dev->ctx_buf.virt, 0, buf_size->dev_ctx); | ||
326 | wmb(); | ||
327 | |||
328 | mfc_debug_leave(); | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | /* Release context buffers for SYS_INIT */ | ||
334 | void s5p_mfc_release_dev_context_buffer_v6(struct s5p_mfc_dev *dev) | ||
335 | { | ||
336 | if (dev->ctx_buf.alloc) { | ||
337 | vb2_dma_contig_memops.put(dev->ctx_buf.alloc); | ||
338 | dev->ctx_buf.alloc = NULL; | ||
339 | dev->ctx_buf.dma = 0; | ||
340 | dev->ctx_buf.virt = NULL; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | static int calc_plane(int width, int height) | ||
345 | { | ||
346 | int mbX, mbY; | ||
347 | |||
348 | mbX = DIV_ROUND_UP(width, S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); | ||
349 | mbY = DIV_ROUND_UP(height, S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6); | ||
350 | |||
351 | if (width * height < S5P_FIMV_MAX_FRAME_SIZE_V6) | ||
352 | mbY = (mbY + 1) / 2 * 2; | ||
353 | |||
354 | return (mbX * S5P_FIMV_NUM_PIXELS_IN_MB_COL_V6) * | ||
355 | (mbY * S5P_FIMV_NUM_PIXELS_IN_MB_ROW_V6); | ||
356 | } | ||
357 | |||
358 | void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx) | ||
359 | { | ||
360 | ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN_V6); | ||
361 | ctx->buf_height = ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN_V6); | ||
362 | mfc_debug(2, "SEQ Done: Movie dimensions %dx%d,\n" | ||
363 | "buffer dimensions: %dx%d\n", ctx->img_width, | ||
364 | ctx->img_height, ctx->buf_width, ctx->buf_height); | ||
365 | |||
366 | ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height); | ||
367 | ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1)); | ||
368 | if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || | ||
369 | ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { | ||
370 | ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width, | ||
371 | ctx->img_height); | ||
372 | ctx->mv_size = ALIGN(ctx->mv_size, 16); | ||
373 | } else { | ||
374 | ctx->mv_size = 0; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx) | ||
379 | { | ||
380 | unsigned int mb_width, mb_height; | ||
381 | |||
382 | mb_width = MB_WIDTH(ctx->img_width); | ||
383 | mb_height = MB_HEIGHT(ctx->img_height); | ||
384 | |||
385 | ctx->buf_width = ALIGN(ctx->img_width, S5P_FIMV_NV12M_HALIGN_V6); | ||
386 | ctx->luma_size = ALIGN((mb_width * mb_height) * 256, 256); | ||
387 | ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256); | ||
388 | } | ||
389 | |||
390 | /* Set registers for decoding stream buffer */ | ||
391 | int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, int buf_addr, | ||
392 | unsigned int start_num_byte, unsigned int strm_size) | ||
393 | { | ||
394 | struct s5p_mfc_dev *dev = ctx->dev; | ||
395 | struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; | ||
396 | |||
397 | mfc_debug_enter(); | ||
398 | mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n" | ||
399 | "buf_size: 0x%08x (%d)\n", | ||
400 | ctx->inst_no, buf_addr, strm_size, strm_size); | ||
401 | WRITEL(strm_size, S5P_FIMV_D_STREAM_DATA_SIZE_V6); | ||
402 | WRITEL(buf_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V6); | ||
403 | WRITEL(buf_size->cpb, S5P_FIMV_D_CPB_BUFFER_SIZE_V6); | ||
404 | WRITEL(start_num_byte, S5P_FIMV_D_CPB_BUFFER_OFFSET_V6); | ||
405 | |||
406 | mfc_debug_leave(); | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | /* Set decoding frame buffer */ | ||
411 | int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx) | ||
412 | { | ||
413 | unsigned int frame_size, i; | ||
414 | unsigned int frame_size_ch, frame_size_mv; | ||
415 | struct s5p_mfc_dev *dev = ctx->dev; | ||
416 | size_t buf_addr1; | ||
417 | int buf_size1; | ||
418 | int align_gap; | ||
419 | |||
420 | buf_addr1 = ctx->bank1_phys; | ||
421 | buf_size1 = ctx->bank1_size; | ||
422 | |||
423 | mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); | ||
424 | mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count); | ||
425 | mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay); | ||
426 | |||
427 | WRITEL(ctx->total_dpb_count, S5P_FIMV_D_NUM_DPB_V6); | ||
428 | WRITEL(ctx->luma_size, S5P_FIMV_D_LUMA_DPB_SIZE_V6); | ||
429 | WRITEL(ctx->chroma_size, S5P_FIMV_D_CHROMA_DPB_SIZE_V6); | ||
430 | |||
431 | WRITEL(buf_addr1, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6); | ||
432 | WRITEL(ctx->scratch_buf_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6); | ||
433 | buf_addr1 += ctx->scratch_buf_size; | ||
434 | buf_size1 -= ctx->scratch_buf_size; | ||
435 | |||
436 | if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || | ||
437 | ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){ | ||
438 | WRITEL(ctx->mv_size, S5P_FIMV_D_MV_BUFFER_SIZE_V6); | ||
439 | WRITEL(ctx->mv_count, S5P_FIMV_D_NUM_MV_V6); | ||
440 | } | ||
441 | |||
442 | frame_size = ctx->luma_size; | ||
443 | frame_size_ch = ctx->chroma_size; | ||
444 | frame_size_mv = ctx->mv_size; | ||
445 | mfc_debug(2, "Frame size: %d ch: %d mv: %d\n", | ||
446 | frame_size, frame_size_ch, frame_size_mv); | ||
447 | |||
448 | for (i = 0; i < ctx->total_dpb_count; i++) { | ||
449 | /* Bank2 */ | ||
450 | mfc_debug(2, "Luma %d: %x\n", i, | ||
451 | ctx->dst_bufs[i].cookie.raw.luma); | ||
452 | WRITEL(ctx->dst_bufs[i].cookie.raw.luma, | ||
453 | S5P_FIMV_D_LUMA_DPB_V6 + i * 4); | ||
454 | mfc_debug(2, "\tChroma %d: %x\n", i, | ||
455 | ctx->dst_bufs[i].cookie.raw.chroma); | ||
456 | WRITEL(ctx->dst_bufs[i].cookie.raw.chroma, | ||
457 | S5P_FIMV_D_CHROMA_DPB_V6 + i * 4); | ||
458 | } | ||
459 | if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || | ||
460 | ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) { | ||
461 | for (i = 0; i < ctx->mv_count; i++) { | ||
462 | /* To test alignment */ | ||
463 | align_gap = buf_addr1; | ||
464 | buf_addr1 = ALIGN(buf_addr1, 16); | ||
465 | align_gap = buf_addr1 - align_gap; | ||
466 | buf_size1 -= align_gap; | ||
467 | |||
468 | mfc_debug(2, "\tBuf1: %x, size: %d\n", | ||
469 | buf_addr1, buf_size1); | ||
470 | WRITEL(buf_addr1, S5P_FIMV_D_MV_BUFFER_V6 + i * 4); | ||
471 | buf_addr1 += frame_size_mv; | ||
472 | buf_size1 -= frame_size_mv; | ||
473 | } | ||
474 | } | ||
475 | |||
476 | mfc_debug(2, "Buf1: %u, buf_size1: %d (frames %d)\n", | ||
477 | buf_addr1, buf_size1, ctx->total_dpb_count); | ||
478 | if (buf_size1 < 0) { | ||
479 | mfc_debug(2, "Not enough memory has been allocated.\n"); | ||
480 | return -ENOMEM; | ||
481 | } | ||
482 | |||
483 | WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); | ||
484 | s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, | ||
485 | S5P_FIMV_CH_INIT_BUFS_V6, NULL); | ||
486 | |||
487 | mfc_debug(2, "After setting buffers.\n"); | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | /* Set registers for encoding stream buffer */ | ||
492 | int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx, | ||
493 | unsigned long addr, unsigned int size) | ||
494 | { | ||
495 | struct s5p_mfc_dev *dev = ctx->dev; | ||
496 | |||
497 | WRITEL(addr, S5P_FIMV_E_STREAM_BUFFER_ADDR_V6); /* 16B align */ | ||
498 | WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE_V6); | ||
499 | |||
500 | mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d", | ||
501 | addr, size); | ||
502 | |||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, | ||
507 | unsigned long y_addr, unsigned long c_addr) | ||
508 | { | ||
509 | struct s5p_mfc_dev *dev = ctx->dev; | ||
510 | |||
511 | WRITEL(y_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6); /* 256B align */ | ||
512 | WRITEL(c_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6); | ||
513 | |||
514 | mfc_debug(2, "enc src y buf addr: 0x%08lx", y_addr); | ||
515 | mfc_debug(2, "enc src c buf addr: 0x%08lx", c_addr); | ||
516 | } | ||
517 | |||
518 | void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx, | ||
519 | unsigned long *y_addr, unsigned long *c_addr) | ||
520 | { | ||
521 | struct s5p_mfc_dev *dev = ctx->dev; | ||
522 | unsigned long enc_recon_y_addr, enc_recon_c_addr; | ||
523 | |||
524 | *y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6); | ||
525 | *c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6); | ||
526 | |||
527 | enc_recon_y_addr = READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6); | ||
528 | enc_recon_c_addr = READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6); | ||
529 | |||
530 | mfc_debug(2, "recon y addr: 0x%08lx", enc_recon_y_addr); | ||
531 | mfc_debug(2, "recon c addr: 0x%08lx", enc_recon_c_addr); | ||
532 | } | ||
533 | |||
534 | /* Set encoding ref & codec buffer */ | ||
535 | int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx) | ||
536 | { | ||
537 | struct s5p_mfc_dev *dev = ctx->dev; | ||
538 | size_t buf_addr1, buf_size1; | ||
539 | int i; | ||
540 | |||
541 | mfc_debug_enter(); | ||
542 | |||
543 | buf_addr1 = ctx->bank1_phys; | ||
544 | buf_size1 = ctx->bank1_size; | ||
545 | |||
546 | mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1); | ||
547 | |||
548 | for (i = 0; i < ctx->dpb_count; i++) { | ||
549 | WRITEL(buf_addr1, S5P_FIMV_E_LUMA_DPB_V6 + (4 * i)); | ||
550 | buf_addr1 += ctx->luma_dpb_size; | ||
551 | WRITEL(buf_addr1, S5P_FIMV_E_CHROMA_DPB_V6 + (4 * i)); | ||
552 | buf_addr1 += ctx->chroma_dpb_size; | ||
553 | WRITEL(buf_addr1, S5P_FIMV_E_ME_BUFFER_V6 + (4 * i)); | ||
554 | buf_addr1 += ctx->me_buffer_size; | ||
555 | buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size + | ||
556 | ctx->me_buffer_size); | ||
557 | } | ||
558 | |||
559 | WRITEL(buf_addr1, S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6); | ||
560 | WRITEL(ctx->scratch_buf_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6); | ||
561 | buf_addr1 += ctx->scratch_buf_size; | ||
562 | buf_size1 -= ctx->scratch_buf_size; | ||
563 | |||
564 | WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER0_V6); | ||
565 | buf_addr1 += ctx->tmv_buffer_size >> 1; | ||
566 | WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER1_V6); | ||
567 | buf_addr1 += ctx->tmv_buffer_size >> 1; | ||
568 | buf_size1 -= ctx->tmv_buffer_size; | ||
569 | |||
570 | mfc_debug(2, "Buf1: %u, buf_size1: %d (ref frames %d)\n", | ||
571 | buf_addr1, buf_size1, ctx->dpb_count); | ||
572 | if (buf_size1 < 0) { | ||
573 | mfc_debug(2, "Not enough memory has been allocated.\n"); | ||
574 | return -ENOMEM; | ||
575 | } | ||
576 | |||
577 | WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); | ||
578 | s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, | ||
579 | S5P_FIMV_CH_INIT_BUFS_V6, NULL); | ||
580 | |||
581 | mfc_debug_leave(); | ||
582 | |||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx) | ||
587 | { | ||
588 | struct s5p_mfc_dev *dev = ctx->dev; | ||
589 | |||
590 | /* multi-slice control */ | ||
591 | /* multi-slice MB number or bit size */ | ||
592 | WRITEL(ctx->slice_mode, S5P_FIMV_E_MSLICE_MODE_V6); | ||
593 | if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { | ||
594 | WRITEL(ctx->slice_size.mb, S5P_FIMV_E_MSLICE_SIZE_MB_V6); | ||
595 | } else if (ctx->slice_mode == | ||
596 | V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { | ||
597 | WRITEL(ctx->slice_size.bits, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); | ||
598 | } else { | ||
599 | WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_MB_V6); | ||
600 | WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_BITS_V6); | ||
601 | } | ||
602 | |||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) | ||
607 | { | ||
608 | struct s5p_mfc_dev *dev = ctx->dev; | ||
609 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
610 | unsigned int reg = 0; | ||
611 | |||
612 | mfc_debug_enter(); | ||
613 | |||
614 | /* width */ | ||
615 | WRITEL(ctx->img_width, S5P_FIMV_E_FRAME_WIDTH_V6); /* 16 align */ | ||
616 | /* height */ | ||
617 | WRITEL(ctx->img_height, S5P_FIMV_E_FRAME_HEIGHT_V6); /* 16 align */ | ||
618 | |||
619 | /* cropped width */ | ||
620 | WRITEL(ctx->img_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6); | ||
621 | /* cropped height */ | ||
622 | WRITEL(ctx->img_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); | ||
623 | /* cropped offset */ | ||
624 | WRITEL(0x0, S5P_FIMV_E_FRAME_CROP_OFFSET_V6); | ||
625 | |||
626 | /* pictype : IDR period */ | ||
627 | reg = 0; | ||
628 | reg |= p->gop_size & 0xFFFF; | ||
629 | WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); | ||
630 | |||
631 | /* multi-slice control */ | ||
632 | /* multi-slice MB number or bit size */ | ||
633 | ctx->slice_mode = p->slice_mode; | ||
634 | reg = 0; | ||
635 | if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { | ||
636 | reg |= (0x1 << 3); | ||
637 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
638 | ctx->slice_size.mb = p->slice_mb; | ||
639 | } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { | ||
640 | reg |= (0x1 << 3); | ||
641 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
642 | ctx->slice_size.bits = p->slice_bit; | ||
643 | } else { | ||
644 | reg &= ~(0x1 << 3); | ||
645 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
646 | } | ||
647 | |||
648 | s5p_mfc_set_slice_mode(ctx); | ||
649 | |||
650 | /* cyclic intra refresh */ | ||
651 | WRITEL(p->intra_refresh_mb, S5P_FIMV_E_IR_SIZE_V6); | ||
652 | reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); | ||
653 | if (p->intra_refresh_mb == 0) | ||
654 | reg &= ~(0x1 << 4); | ||
655 | else | ||
656 | reg |= (0x1 << 4); | ||
657 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
658 | |||
659 | /* 'NON_REFERENCE_STORE_ENABLE' for debugging */ | ||
660 | reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); | ||
661 | reg &= ~(0x1 << 9); | ||
662 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
663 | |||
664 | /* memory structure cur. frame */ | ||
665 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { | ||
666 | /* 0: Linear, 1: 2D tiled*/ | ||
667 | reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); | ||
668 | reg &= ~(0x1 << 7); | ||
669 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
670 | /* 0: NV12(CbCr), 1: NV21(CrCb) */ | ||
671 | WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); | ||
672 | } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) { | ||
673 | /* 0: Linear, 1: 2D tiled*/ | ||
674 | reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); | ||
675 | reg &= ~(0x1 << 7); | ||
676 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
677 | /* 0: NV12(CbCr), 1: NV21(CrCb) */ | ||
678 | WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6); | ||
679 | } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) { | ||
680 | /* 0: Linear, 1: 2D tiled*/ | ||
681 | reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); | ||
682 | reg |= (0x1 << 7); | ||
683 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
684 | /* 0: NV12(CbCr), 1: NV21(CrCb) */ | ||
685 | WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); | ||
686 | } | ||
687 | |||
688 | /* memory structure recon. frame */ | ||
689 | /* 0: Linear, 1: 2D tiled */ | ||
690 | reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); | ||
691 | reg |= (0x1 << 8); | ||
692 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
693 | |||
694 | /* padding control & value */ | ||
695 | WRITEL(0x0, S5P_FIMV_E_PADDING_CTRL_V6); | ||
696 | if (p->pad) { | ||
697 | reg = 0; | ||
698 | /** enable */ | ||
699 | reg |= (1 << 31); | ||
700 | /** cr value */ | ||
701 | reg |= ((p->pad_cr & 0xFF) << 16); | ||
702 | /** cb value */ | ||
703 | reg |= ((p->pad_cb & 0xFF) << 8); | ||
704 | /** y value */ | ||
705 | reg |= p->pad_luma & 0xFF; | ||
706 | WRITEL(reg, S5P_FIMV_E_PADDING_CTRL_V6); | ||
707 | } | ||
708 | |||
709 | /* rate control config. */ | ||
710 | reg = 0; | ||
711 | /* frame-level rate control */ | ||
712 | reg |= ((p->rc_frame & 0x1) << 9); | ||
713 | WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); | ||
714 | |||
715 | /* bit rate */ | ||
716 | if (p->rc_frame) | ||
717 | WRITEL(p->rc_bitrate, | ||
718 | S5P_FIMV_E_RC_BIT_RATE_V6); | ||
719 | else | ||
720 | WRITEL(1, S5P_FIMV_E_RC_BIT_RATE_V6); | ||
721 | |||
722 | /* reaction coefficient */ | ||
723 | if (p->rc_frame) { | ||
724 | if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */ | ||
725 | WRITEL(1, S5P_FIMV_E_RC_RPARAM_V6); | ||
726 | else /* loose CBR */ | ||
727 | WRITEL(2, S5P_FIMV_E_RC_RPARAM_V6); | ||
728 | } | ||
729 | |||
730 | /* seq header ctrl */ | ||
731 | reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6); | ||
732 | reg &= ~(0x1 << 2); | ||
733 | reg |= ((p->seq_hdr_mode & 0x1) << 2); | ||
734 | |||
735 | /* frame skip mode */ | ||
736 | reg &= ~(0x3); | ||
737 | reg |= (p->frame_skip_mode & 0x3); | ||
738 | WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6); | ||
739 | |||
740 | /* 'DROP_CONTROL_ENABLE', disable */ | ||
741 | reg = READL(S5P_FIMV_E_RC_CONFIG_V6); | ||
742 | reg &= ~(0x1 << 10); | ||
743 | WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); | ||
744 | |||
745 | /* setting for MV range [16, 256] */ | ||
746 | reg = 0; | ||
747 | reg &= ~(0x3FFF); | ||
748 | reg = 256; | ||
749 | WRITEL(reg, S5P_FIMV_E_MV_HOR_RANGE_V6); | ||
750 | |||
751 | reg = 0; | ||
752 | reg &= ~(0x3FFF); | ||
753 | reg = 256; | ||
754 | WRITEL(reg, S5P_FIMV_E_MV_VER_RANGE_V6); | ||
755 | |||
756 | WRITEL(0x0, S5P_FIMV_E_FRAME_INSERTION_V6); | ||
757 | WRITEL(0x0, S5P_FIMV_E_ROI_BUFFER_ADDR_V6); | ||
758 | WRITEL(0x0, S5P_FIMV_E_PARAM_CHANGE_V6); | ||
759 | WRITEL(0x0, S5P_FIMV_E_RC_ROI_CTRL_V6); | ||
760 | WRITEL(0x0, S5P_FIMV_E_PICTURE_TAG_V6); | ||
761 | |||
762 | WRITEL(0x0, S5P_FIMV_E_BIT_COUNT_ENABLE_V6); | ||
763 | WRITEL(0x0, S5P_FIMV_E_MAX_BIT_COUNT_V6); | ||
764 | WRITEL(0x0, S5P_FIMV_E_MIN_BIT_COUNT_V6); | ||
765 | |||
766 | WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_ADDR_V6); | ||
767 | WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_SIZE_V6); | ||
768 | |||
769 | mfc_debug_leave(); | ||
770 | |||
771 | return 0; | ||
772 | } | ||
773 | |||
774 | static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) | ||
775 | { | ||
776 | struct s5p_mfc_dev *dev = ctx->dev; | ||
777 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
778 | struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; | ||
779 | unsigned int reg = 0; | ||
780 | int i; | ||
781 | |||
782 | mfc_debug_enter(); | ||
783 | |||
784 | s5p_mfc_set_enc_params(ctx); | ||
785 | |||
786 | /* pictype : number of B */ | ||
787 | reg = READL(S5P_FIMV_E_GOP_CONFIG_V6); | ||
788 | reg &= ~(0x3 << 16); | ||
789 | reg |= ((p->num_b_frame & 0x3) << 16); | ||
790 | WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); | ||
791 | |||
792 | /* profile & level */ | ||
793 | reg = 0; | ||
794 | /** level */ | ||
795 | reg |= ((p_h264->level & 0xFF) << 8); | ||
796 | /** profile - 0 ~ 3 */ | ||
797 | reg |= p_h264->profile & 0x3F; | ||
798 | WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); | ||
799 | |||
800 | /* rate control config. */ | ||
801 | reg = READL(S5P_FIMV_E_RC_CONFIG_V6); | ||
802 | /** macroblock level rate control */ | ||
803 | reg &= ~(0x1 << 8); | ||
804 | reg |= ((p->rc_mb & 0x1) << 8); | ||
805 | WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); | ||
806 | /** frame QP */ | ||
807 | reg &= ~(0x3F); | ||
808 | reg |= p_h264->rc_frame_qp & 0x3F; | ||
809 | WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); | ||
810 | |||
811 | /* max & min value of QP */ | ||
812 | reg = 0; | ||
813 | /** max QP */ | ||
814 | reg |= ((p_h264->rc_max_qp & 0x3F) << 8); | ||
815 | /** min QP */ | ||
816 | reg |= p_h264->rc_min_qp & 0x3F; | ||
817 | WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); | ||
818 | |||
819 | /* other QPs */ | ||
820 | WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); | ||
821 | if (!p->rc_frame && !p->rc_mb) { | ||
822 | reg = 0; | ||
823 | reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16); | ||
824 | reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8); | ||
825 | reg |= p_h264->rc_frame_qp & 0x3F; | ||
826 | WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); | ||
827 | } | ||
828 | |||
829 | /* frame rate */ | ||
830 | if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { | ||
831 | reg = 0; | ||
832 | reg |= ((p->rc_framerate_num & 0xFFFF) << 16); | ||
833 | reg |= p->rc_framerate_denom & 0xFFFF; | ||
834 | WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); | ||
835 | } | ||
836 | |||
837 | /* vbv buffer size */ | ||
838 | if (p->frame_skip_mode == | ||
839 | V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { | ||
840 | WRITEL(p_h264->cpb_size & 0xFFFF, | ||
841 | S5P_FIMV_E_VBV_BUFFER_SIZE_V6); | ||
842 | |||
843 | if (p->rc_frame) | ||
844 | WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); | ||
845 | } | ||
846 | |||
847 | /* interlace */ | ||
848 | reg = 0; | ||
849 | reg |= ((p_h264->interlace & 0x1) << 3); | ||
850 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
851 | |||
852 | /* height */ | ||
853 | if (p_h264->interlace) { | ||
854 | WRITEL(ctx->img_height >> 1, | ||
855 | S5P_FIMV_E_FRAME_HEIGHT_V6); /* 32 align */ | ||
856 | /* cropped height */ | ||
857 | WRITEL(ctx->img_height >> 1, | ||
858 | S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6); | ||
859 | } | ||
860 | |||
861 | /* loop filter ctrl */ | ||
862 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
863 | reg &= ~(0x3 << 1); | ||
864 | reg |= ((p_h264->loop_filter_mode & 0x3) << 1); | ||
865 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
866 | |||
867 | /* loopfilter alpha offset */ | ||
868 | if (p_h264->loop_filter_alpha < 0) { | ||
869 | reg = 0x10; | ||
870 | reg |= (0xFF - p_h264->loop_filter_alpha) + 1; | ||
871 | } else { | ||
872 | reg = 0x00; | ||
873 | reg |= (p_h264->loop_filter_alpha & 0xF); | ||
874 | } | ||
875 | WRITEL(reg, S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6); | ||
876 | |||
877 | /* loopfilter beta offset */ | ||
878 | if (p_h264->loop_filter_beta < 0) { | ||
879 | reg = 0x10; | ||
880 | reg |= (0xFF - p_h264->loop_filter_beta) + 1; | ||
881 | } else { | ||
882 | reg = 0x00; | ||
883 | reg |= (p_h264->loop_filter_beta & 0xF); | ||
884 | } | ||
885 | WRITEL(reg, S5P_FIMV_E_H264_LF_BETA_OFFSET_V6); | ||
886 | |||
887 | /* entropy coding mode */ | ||
888 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
889 | reg &= ~(0x1); | ||
890 | reg |= p_h264->entropy_mode & 0x1; | ||
891 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
892 | |||
893 | /* number of ref. picture */ | ||
894 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
895 | reg &= ~(0x1 << 7); | ||
896 | reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7); | ||
897 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
898 | |||
899 | /* 8x8 transform enable */ | ||
900 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
901 | reg &= ~(0x3 << 12); | ||
902 | reg |= ((p_h264->_8x8_transform & 0x3) << 12); | ||
903 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
904 | |||
905 | /* macroblock adaptive scaling features */ | ||
906 | WRITEL(0x0, S5P_FIMV_E_MB_RC_CONFIG_V6); | ||
907 | if (p->rc_mb) { | ||
908 | reg = 0; | ||
909 | /** dark region */ | ||
910 | reg |= ((p_h264->rc_mb_dark & 0x1) << 3); | ||
911 | /** smooth region */ | ||
912 | reg |= ((p_h264->rc_mb_smooth & 0x1) << 2); | ||
913 | /** static region */ | ||
914 | reg |= ((p_h264->rc_mb_static & 0x1) << 1); | ||
915 | /** high activity region */ | ||
916 | reg |= p_h264->rc_mb_activity & 0x1; | ||
917 | WRITEL(reg, S5P_FIMV_E_MB_RC_CONFIG_V6); | ||
918 | } | ||
919 | |||
920 | /* aspect ratio VUI */ | ||
921 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
922 | reg &= ~(0x1 << 5); | ||
923 | reg |= ((p_h264->vui_sar & 0x1) << 5); | ||
924 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
925 | |||
926 | WRITEL(0x0, S5P_FIMV_E_ASPECT_RATIO_V6); | ||
927 | WRITEL(0x0, S5P_FIMV_E_EXTENDED_SAR_V6); | ||
928 | if (p_h264->vui_sar) { | ||
929 | /* aspect ration IDC */ | ||
930 | reg = 0; | ||
931 | reg |= p_h264->vui_sar_idc & 0xFF; | ||
932 | WRITEL(reg, S5P_FIMV_E_ASPECT_RATIO_V6); | ||
933 | if (p_h264->vui_sar_idc == 0xFF) { | ||
934 | /* extended SAR */ | ||
935 | reg = 0; | ||
936 | reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16; | ||
937 | reg |= p_h264->vui_ext_sar_height & 0xFFFF; | ||
938 | WRITEL(reg, S5P_FIMV_E_EXTENDED_SAR_V6); | ||
939 | } | ||
940 | } | ||
941 | |||
942 | /* intra picture period for H.264 open GOP */ | ||
943 | /* control */ | ||
944 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
945 | reg &= ~(0x1 << 4); | ||
946 | reg |= ((p_h264->open_gop & 0x1) << 4); | ||
947 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
948 | /* value */ | ||
949 | WRITEL(0x0, S5P_FIMV_E_H264_I_PERIOD_V6); | ||
950 | if (p_h264->open_gop) { | ||
951 | reg = 0; | ||
952 | reg |= p_h264->open_gop_size & 0xFFFF; | ||
953 | WRITEL(reg, S5P_FIMV_E_H264_I_PERIOD_V6); | ||
954 | } | ||
955 | |||
956 | /* 'WEIGHTED_BI_PREDICTION' for B is disable */ | ||
957 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
958 | reg &= ~(0x3 << 9); | ||
959 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
960 | |||
961 | /* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */ | ||
962 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
963 | reg &= ~(0x1 << 14); | ||
964 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
965 | |||
966 | /* ASO */ | ||
967 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
968 | reg &= ~(0x1 << 6); | ||
969 | reg |= ((p_h264->aso & 0x1) << 6); | ||
970 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
971 | |||
972 | /* hier qp enable */ | ||
973 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
974 | reg &= ~(0x1 << 8); | ||
975 | reg |= ((p_h264->open_gop & 0x1) << 8); | ||
976 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
977 | reg = 0; | ||
978 | if (p_h264->hier_qp && p_h264->hier_qp_layer) { | ||
979 | reg |= (p_h264->hier_qp_type & 0x1) << 0x3; | ||
980 | reg |= p_h264->hier_qp_layer & 0x7; | ||
981 | WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6); | ||
982 | /* QP value for each layer */ | ||
983 | for (i = 0; i < (p_h264->hier_qp_layer & 0x7); i++) | ||
984 | WRITEL(p_h264->hier_qp_layer_qp[i], | ||
985 | S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 + | ||
986 | i * 4); | ||
987 | } | ||
988 | /* number of coding layer should be zero when hierarchical is disable */ | ||
989 | WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6); | ||
990 | |||
991 | /* frame packing SEI generation */ | ||
992 | reg = READL(S5P_FIMV_E_H264_OPTIONS_V6); | ||
993 | reg &= ~(0x1 << 25); | ||
994 | reg |= ((p_h264->sei_frame_packing & 0x1) << 25); | ||
995 | WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6); | ||
996 | if (p_h264->sei_frame_packing) { | ||
997 | reg = 0; | ||
998 | /** current frame0 flag */ | ||
999 | reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2); | ||
1000 | /** arrangement type */ | ||
1001 | reg |= p_h264->sei_fp_arrangement_type & 0x3; | ||
1002 | WRITEL(reg, S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6); | ||
1003 | } | ||
1004 | |||
1005 | if (p_h264->fmo) { | ||
1006 | switch (p_h264->fmo_map_type) { | ||
1007 | case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES: | ||
1008 | if (p_h264->fmo_slice_grp > 4) | ||
1009 | p_h264->fmo_slice_grp = 4; | ||
1010 | for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++) | ||
1011 | WRITEL(p_h264->fmo_run_len[i] - 1, | ||
1012 | S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 + | ||
1013 | i * 4); | ||
1014 | break; | ||
1015 | case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES: | ||
1016 | if (p_h264->fmo_slice_grp > 4) | ||
1017 | p_h264->fmo_slice_grp = 4; | ||
1018 | break; | ||
1019 | case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN: | ||
1020 | case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN: | ||
1021 | if (p_h264->fmo_slice_grp > 2) | ||
1022 | p_h264->fmo_slice_grp = 2; | ||
1023 | WRITEL(p_h264->fmo_chg_dir & 0x1, | ||
1024 | S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6); | ||
1025 | /* the valid range is 0 ~ number of macroblocks -1 */ | ||
1026 | WRITEL(p_h264->fmo_chg_rate, | ||
1027 | S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6); | ||
1028 | break; | ||
1029 | default: | ||
1030 | mfc_err("Unsupported map type for FMO: %d\n", | ||
1031 | p_h264->fmo_map_type); | ||
1032 | p_h264->fmo_map_type = 0; | ||
1033 | p_h264->fmo_slice_grp = 1; | ||
1034 | break; | ||
1035 | } | ||
1036 | |||
1037 | WRITEL(p_h264->fmo_map_type, | ||
1038 | S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6); | ||
1039 | WRITEL(p_h264->fmo_slice_grp - 1, | ||
1040 | S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); | ||
1041 | } else { | ||
1042 | WRITEL(0, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6); | ||
1043 | } | ||
1044 | |||
1045 | mfc_debug_leave(); | ||
1046 | |||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
1050 | static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) | ||
1051 | { | ||
1052 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1053 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
1054 | struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; | ||
1055 | unsigned int reg = 0; | ||
1056 | |||
1057 | mfc_debug_enter(); | ||
1058 | |||
1059 | s5p_mfc_set_enc_params(ctx); | ||
1060 | |||
1061 | /* pictype : number of B */ | ||
1062 | reg = READL(S5P_FIMV_E_GOP_CONFIG_V6); | ||
1063 | reg &= ~(0x3 << 16); | ||
1064 | reg |= ((p->num_b_frame & 0x3) << 16); | ||
1065 | WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6); | ||
1066 | |||
1067 | /* profile & level */ | ||
1068 | reg = 0; | ||
1069 | /** level */ | ||
1070 | reg |= ((p_mpeg4->level & 0xFF) << 8); | ||
1071 | /** profile - 0 ~ 1 */ | ||
1072 | reg |= p_mpeg4->profile & 0x3F; | ||
1073 | WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); | ||
1074 | |||
1075 | /* rate control config. */ | ||
1076 | reg = READL(S5P_FIMV_E_RC_CONFIG_V6); | ||
1077 | /** macroblock level rate control */ | ||
1078 | reg &= ~(0x1 << 8); | ||
1079 | reg |= ((p->rc_mb & 0x1) << 8); | ||
1080 | WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); | ||
1081 | /** frame QP */ | ||
1082 | reg &= ~(0x3F); | ||
1083 | reg |= p_mpeg4->rc_frame_qp & 0x3F; | ||
1084 | WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); | ||
1085 | |||
1086 | /* max & min value of QP */ | ||
1087 | reg = 0; | ||
1088 | /** max QP */ | ||
1089 | reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8); | ||
1090 | /** min QP */ | ||
1091 | reg |= p_mpeg4->rc_min_qp & 0x3F; | ||
1092 | WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); | ||
1093 | |||
1094 | /* other QPs */ | ||
1095 | WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); | ||
1096 | if (!p->rc_frame && !p->rc_mb) { | ||
1097 | reg = 0; | ||
1098 | reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16); | ||
1099 | reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8); | ||
1100 | reg |= p_mpeg4->rc_frame_qp & 0x3F; | ||
1101 | WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); | ||
1102 | } | ||
1103 | |||
1104 | /* frame rate */ | ||
1105 | if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { | ||
1106 | reg = 0; | ||
1107 | reg |= ((p->rc_framerate_num & 0xFFFF) << 16); | ||
1108 | reg |= p->rc_framerate_denom & 0xFFFF; | ||
1109 | WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); | ||
1110 | } | ||
1111 | |||
1112 | /* vbv buffer size */ | ||
1113 | if (p->frame_skip_mode == | ||
1114 | V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { | ||
1115 | WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); | ||
1116 | |||
1117 | if (p->rc_frame) | ||
1118 | WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); | ||
1119 | } | ||
1120 | |||
1121 | /* Disable HEC */ | ||
1122 | WRITEL(0x0, S5P_FIMV_E_MPEG4_OPTIONS_V6); | ||
1123 | WRITEL(0x0, S5P_FIMV_E_MPEG4_HEC_PERIOD_V6); | ||
1124 | |||
1125 | mfc_debug_leave(); | ||
1126 | |||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) | ||
1131 | { | ||
1132 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1133 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
1134 | struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; | ||
1135 | unsigned int reg = 0; | ||
1136 | |||
1137 | mfc_debug_enter(); | ||
1138 | |||
1139 | s5p_mfc_set_enc_params(ctx); | ||
1140 | |||
1141 | /* profile & level */ | ||
1142 | reg = 0; | ||
1143 | /** profile */ | ||
1144 | reg |= (0x1 << 4); | ||
1145 | WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6); | ||
1146 | |||
1147 | /* rate control config. */ | ||
1148 | reg = READL(S5P_FIMV_E_RC_CONFIG_V6); | ||
1149 | /** macroblock level rate control */ | ||
1150 | reg &= ~(0x1 << 8); | ||
1151 | reg |= ((p->rc_mb & 0x1) << 8); | ||
1152 | WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); | ||
1153 | /** frame QP */ | ||
1154 | reg &= ~(0x3F); | ||
1155 | reg |= p_h263->rc_frame_qp & 0x3F; | ||
1156 | WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6); | ||
1157 | |||
1158 | /* max & min value of QP */ | ||
1159 | reg = 0; | ||
1160 | /** max QP */ | ||
1161 | reg |= ((p_h263->rc_max_qp & 0x3F) << 8); | ||
1162 | /** min QP */ | ||
1163 | reg |= p_h263->rc_min_qp & 0x3F; | ||
1164 | WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6); | ||
1165 | |||
1166 | /* other QPs */ | ||
1167 | WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6); | ||
1168 | if (!p->rc_frame && !p->rc_mb) { | ||
1169 | reg = 0; | ||
1170 | reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16); | ||
1171 | reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8); | ||
1172 | reg |= p_h263->rc_frame_qp & 0x3F; | ||
1173 | WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6); | ||
1174 | } | ||
1175 | |||
1176 | /* frame rate */ | ||
1177 | if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) { | ||
1178 | reg = 0; | ||
1179 | reg |= ((p->rc_framerate_num & 0xFFFF) << 16); | ||
1180 | reg |= p->rc_framerate_denom & 0xFFFF; | ||
1181 | WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6); | ||
1182 | } | ||
1183 | |||
1184 | /* vbv buffer size */ | ||
1185 | if (p->frame_skip_mode == | ||
1186 | V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { | ||
1187 | WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6); | ||
1188 | |||
1189 | if (p->rc_frame) | ||
1190 | WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6); | ||
1191 | } | ||
1192 | |||
1193 | mfc_debug_leave(); | ||
1194 | |||
1195 | return 0; | ||
1196 | } | ||
1197 | |||
1198 | /* Initialize decoding */ | ||
1199 | int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx) | ||
1200 | { | ||
1201 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1202 | unsigned int reg = 0; | ||
1203 | int fmo_aso_ctrl = 0; | ||
1204 | |||
1205 | mfc_debug_enter(); | ||
1206 | mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no, | ||
1207 | S5P_FIMV_CH_SEQ_HEADER_V6); | ||
1208 | mfc_debug(2, "BUFs: %08x %08x %08x\n", | ||
1209 | READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6), | ||
1210 | READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6), | ||
1211 | READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6)); | ||
1212 | |||
1213 | /* FMO_ASO_CTRL - 0: Enable, 1: Disable */ | ||
1214 | reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6); | ||
1215 | |||
1216 | /* When user sets desplay_delay to 0, | ||
1217 | * It works as "display_delay enable" and delay set to 0. | ||
1218 | * If user wants display_delay disable, It should be | ||
1219 | * set to negative value. */ | ||
1220 | if (ctx->display_delay >= 0) { | ||
1221 | reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6); | ||
1222 | WRITEL(ctx->display_delay, S5P_FIMV_D_DISPLAY_DELAY_V6); | ||
1223 | } | ||
1224 | /* Setup loop filter, for decoding this is only valid for MPEG4 */ | ||
1225 | if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_DEC) { | ||
1226 | mfc_debug(2, "Set loop filter to: %d\n", | ||
1227 | ctx->loop_filter_mpeg4); | ||
1228 | reg |= (ctx->loop_filter_mpeg4 << | ||
1229 | S5P_FIMV_D_OPT_LF_CTRL_SHIFT_V6); | ||
1230 | } | ||
1231 | if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) | ||
1232 | reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6); | ||
1233 | |||
1234 | WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS_V6); | ||
1235 | |||
1236 | /* 0: NV12(CbCr), 1: NV21(CrCb) */ | ||
1237 | if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M) | ||
1238 | WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6); | ||
1239 | else | ||
1240 | WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6); | ||
1241 | |||
1242 | /* sei parse */ | ||
1243 | WRITEL(ctx->sei_fp_parse & 0x1, S5P_FIMV_D_SEI_ENABLE_V6); | ||
1244 | |||
1245 | WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); | ||
1246 | s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, | ||
1247 | S5P_FIMV_CH_SEQ_HEADER_V6, NULL); | ||
1248 | |||
1249 | mfc_debug_leave(); | ||
1250 | return 0; | ||
1251 | } | ||
1252 | |||
1253 | static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) | ||
1254 | { | ||
1255 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1256 | unsigned int dpb; | ||
1257 | if (flush) | ||
1258 | dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | (1 << 14); | ||
1259 | else | ||
1260 | dpb = READL(S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & ~(1 << 14); | ||
1261 | WRITEL(dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); | ||
1262 | } | ||
1263 | |||
1264 | /* Decode a single frame */ | ||
1265 | int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx, | ||
1266 | enum s5p_mfc_decode_arg last_frame) | ||
1267 | { | ||
1268 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1269 | |||
1270 | WRITEL(ctx->dec_dst_flag, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6); | ||
1271 | WRITEL(ctx->slice_interface & 0x1, S5P_FIMV_D_SLICE_IF_ENABLE_V6); | ||
1272 | |||
1273 | WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); | ||
1274 | /* Issue different commands to instance basing on whether it | ||
1275 | * is the last frame or not. */ | ||
1276 | switch (last_frame) { | ||
1277 | case 0: | ||
1278 | s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, | ||
1279 | S5P_FIMV_CH_FRAME_START_V6, NULL); | ||
1280 | break; | ||
1281 | case 1: | ||
1282 | s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, | ||
1283 | S5P_FIMV_CH_LAST_FRAME_V6, NULL); | ||
1284 | break; | ||
1285 | default: | ||
1286 | mfc_err("Unsupported last frame arg.\n"); | ||
1287 | return -EINVAL; | ||
1288 | } | ||
1289 | |||
1290 | mfc_debug(2, "Decoding a usual frame.\n"); | ||
1291 | return 0; | ||
1292 | } | ||
1293 | |||
1294 | int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx) | ||
1295 | { | ||
1296 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1297 | |||
1298 | if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) | ||
1299 | s5p_mfc_set_enc_params_h264(ctx); | ||
1300 | else if (ctx->codec_mode == S5P_MFC_CODEC_MPEG4_ENC) | ||
1301 | s5p_mfc_set_enc_params_mpeg4(ctx); | ||
1302 | else if (ctx->codec_mode == S5P_MFC_CODEC_H263_ENC) | ||
1303 | s5p_mfc_set_enc_params_h263(ctx); | ||
1304 | else { | ||
1305 | mfc_err("Unknown codec for encoding (%x).\n", | ||
1306 | ctx->codec_mode); | ||
1307 | return -EINVAL; | ||
1308 | } | ||
1309 | |||
1310 | WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); | ||
1311 | s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, | ||
1312 | S5P_FIMV_CH_SEQ_HEADER_V6, NULL); | ||
1313 | |||
1314 | return 0; | ||
1315 | } | ||
1316 | |||
1317 | int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) | ||
1318 | { | ||
1319 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1320 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
1321 | struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; | ||
1322 | int i; | ||
1323 | |||
1324 | if (p_h264->aso) { | ||
1325 | for (i = 0; i < 8; i++) | ||
1326 | WRITEL(p_h264->aso_slice_order[i], | ||
1327 | S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 + i * 4); | ||
1328 | } | ||
1329 | return 0; | ||
1330 | } | ||
1331 | |||
1332 | /* Encode a single frame */ | ||
1333 | int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx) | ||
1334 | { | ||
1335 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1336 | |||
1337 | mfc_debug(2, "++\n"); | ||
1338 | |||
1339 | /* memory structure cur. frame */ | ||
1340 | |||
1341 | if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC) | ||
1342 | s5p_mfc_h264_set_aso_slice_order_v6(ctx); | ||
1343 | |||
1344 | s5p_mfc_set_slice_mode(ctx); | ||
1345 | |||
1346 | WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6); | ||
1347 | s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, | ||
1348 | S5P_FIMV_CH_FRAME_START_V6, NULL); | ||
1349 | |||
1350 | mfc_debug(2, "--\n"); | ||
1351 | |||
1352 | return 0; | ||
1353 | } | ||
1354 | |||
1355 | static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) | ||
1356 | { | ||
1357 | unsigned long flags; | ||
1358 | int new_ctx; | ||
1359 | int cnt; | ||
1360 | |||
1361 | spin_lock_irqsave(&dev->condlock, flags); | ||
1362 | mfc_debug(2, "Previos context: %d (bits %08lx)\n", dev->curr_ctx, | ||
1363 | dev->ctx_work_bits); | ||
1364 | new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; | ||
1365 | cnt = 0; | ||
1366 | while (!test_bit(new_ctx, &dev->ctx_work_bits)) { | ||
1367 | new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; | ||
1368 | cnt++; | ||
1369 | if (cnt > MFC_NUM_CONTEXTS) { | ||
1370 | /* No contexts to run */ | ||
1371 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
1372 | return -EAGAIN; | ||
1373 | } | ||
1374 | } | ||
1375 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
1376 | return new_ctx; | ||
1377 | } | ||
1378 | |||
1379 | static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx) | ||
1380 | { | ||
1381 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1382 | struct s5p_mfc_buf *temp_vb; | ||
1383 | unsigned long flags; | ||
1384 | |||
1385 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1386 | |||
1387 | /* Frames are being decoded */ | ||
1388 | if (list_empty(&ctx->src_queue)) { | ||
1389 | mfc_debug(2, "No src buffers.\n"); | ||
1390 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1391 | return; | ||
1392 | } | ||
1393 | /* Get the next source buffer */ | ||
1394 | temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
1395 | temp_vb->flags |= MFC_BUF_FLAG_USED; | ||
1396 | s5p_mfc_set_dec_stream_buffer_v6(ctx, | ||
1397 | vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, 0); | ||
1398 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1399 | |||
1400 | dev->curr_ctx = ctx->num; | ||
1401 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1402 | s5p_mfc_decode_one_frame_v6(ctx, 1); | ||
1403 | } | ||
1404 | |||
1405 | static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx) | ||
1406 | { | ||
1407 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1408 | struct s5p_mfc_buf *temp_vb; | ||
1409 | unsigned long flags; | ||
1410 | int last_frame = 0; | ||
1411 | unsigned int index; | ||
1412 | |||
1413 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1414 | |||
1415 | /* Frames are being decoded */ | ||
1416 | if (list_empty(&ctx->src_queue)) { | ||
1417 | mfc_debug(2, "No src buffers.\n"); | ||
1418 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1419 | return -EAGAIN; | ||
1420 | } | ||
1421 | /* Get the next source buffer */ | ||
1422 | temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
1423 | temp_vb->flags |= MFC_BUF_FLAG_USED; | ||
1424 | s5p_mfc_set_dec_stream_buffer_v6(ctx, | ||
1425 | vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), | ||
1426 | ctx->consumed_stream, | ||
1427 | temp_vb->b->v4l2_planes[0].bytesused); | ||
1428 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1429 | |||
1430 | index = temp_vb->b->v4l2_buf.index; | ||
1431 | |||
1432 | dev->curr_ctx = ctx->num; | ||
1433 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1434 | if (temp_vb->b->v4l2_planes[0].bytesused == 0) { | ||
1435 | last_frame = 1; | ||
1436 | mfc_debug(2, "Setting ctx->state to FINISHING\n"); | ||
1437 | ctx->state = MFCINST_FINISHING; | ||
1438 | } | ||
1439 | s5p_mfc_decode_one_frame_v6(ctx, last_frame); | ||
1440 | |||
1441 | return 0; | ||
1442 | } | ||
1443 | |||
1444 | static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) | ||
1445 | { | ||
1446 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1447 | unsigned long flags; | ||
1448 | struct s5p_mfc_buf *dst_mb; | ||
1449 | struct s5p_mfc_buf *src_mb; | ||
1450 | unsigned long src_y_addr, src_c_addr, dst_addr; | ||
1451 | /* | ||
1452 | unsigned int src_y_size, src_c_size; | ||
1453 | */ | ||
1454 | unsigned int dst_size; | ||
1455 | unsigned int index; | ||
1456 | |||
1457 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1458 | |||
1459 | if (list_empty(&ctx->src_queue)) { | ||
1460 | mfc_debug(2, "no src buffers.\n"); | ||
1461 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1462 | return -EAGAIN; | ||
1463 | } | ||
1464 | |||
1465 | if (list_empty(&ctx->dst_queue)) { | ||
1466 | mfc_debug(2, "no dst buffers.\n"); | ||
1467 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1468 | return -EAGAIN; | ||
1469 | } | ||
1470 | |||
1471 | src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
1472 | src_mb->flags |= MFC_BUF_FLAG_USED; | ||
1473 | src_y_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 0); | ||
1474 | src_c_addr = vb2_dma_contig_plane_dma_addr(src_mb->b, 1); | ||
1475 | |||
1476 | mfc_debug(2, "enc src y addr: 0x%08lx", src_y_addr); | ||
1477 | mfc_debug(2, "enc src c addr: 0x%08lx", src_c_addr); | ||
1478 | |||
1479 | s5p_mfc_set_enc_frame_buffer_v6(ctx, src_y_addr, src_c_addr); | ||
1480 | |||
1481 | dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); | ||
1482 | dst_mb->flags |= MFC_BUF_FLAG_USED; | ||
1483 | dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); | ||
1484 | dst_size = vb2_plane_size(dst_mb->b, 0); | ||
1485 | |||
1486 | s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); | ||
1487 | |||
1488 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1489 | |||
1490 | index = src_mb->b->v4l2_buf.index; | ||
1491 | |||
1492 | dev->curr_ctx = ctx->num; | ||
1493 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1494 | s5p_mfc_encode_one_frame_v6(ctx); | ||
1495 | |||
1496 | return 0; | ||
1497 | } | ||
1498 | |||
1499 | static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) | ||
1500 | { | ||
1501 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1502 | unsigned long flags; | ||
1503 | struct s5p_mfc_buf *temp_vb; | ||
1504 | |||
1505 | /* Initializing decoding - parsing header */ | ||
1506 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1507 | mfc_debug(2, "Preparing to init decoding.\n"); | ||
1508 | temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
1509 | mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); | ||
1510 | s5p_mfc_set_dec_stream_buffer_v6(ctx, | ||
1511 | vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, | ||
1512 | temp_vb->b->v4l2_planes[0].bytesused); | ||
1513 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1514 | dev->curr_ctx = ctx->num; | ||
1515 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1516 | s5p_mfc_init_decode_v6(ctx); | ||
1517 | } | ||
1518 | |||
1519 | static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) | ||
1520 | { | ||
1521 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1522 | unsigned long flags; | ||
1523 | struct s5p_mfc_buf *dst_mb; | ||
1524 | unsigned long dst_addr; | ||
1525 | unsigned int dst_size; | ||
1526 | |||
1527 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1528 | |||
1529 | dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); | ||
1530 | dst_addr = vb2_dma_contig_plane_dma_addr(dst_mb->b, 0); | ||
1531 | dst_size = vb2_plane_size(dst_mb->b, 0); | ||
1532 | s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size); | ||
1533 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1534 | dev->curr_ctx = ctx->num; | ||
1535 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1536 | s5p_mfc_init_encode_v6(ctx); | ||
1537 | } | ||
1538 | |||
1539 | static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) | ||
1540 | { | ||
1541 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1542 | int ret; | ||
1543 | /* Header was parsed now start processing | ||
1544 | * First set the output frame buffers | ||
1545 | * s5p_mfc_alloc_dec_buffers(ctx); */ | ||
1546 | |||
1547 | if (ctx->capture_state != QUEUE_BUFS_MMAPED) { | ||
1548 | mfc_err("It seems that not all destionation buffers were\n" | ||
1549 | "mmaped.MFC requires that all destination are mmaped\n" | ||
1550 | "before starting processing.\n"); | ||
1551 | return -EAGAIN; | ||
1552 | } | ||
1553 | |||
1554 | dev->curr_ctx = ctx->num; | ||
1555 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1556 | ret = s5p_mfc_set_dec_frame_buffer_v6(ctx); | ||
1557 | if (ret) { | ||
1558 | mfc_err("Failed to alloc frame mem.\n"); | ||
1559 | ctx->state = MFCINST_ERROR; | ||
1560 | } | ||
1561 | return ret; | ||
1562 | } | ||
1563 | |||
1564 | static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx) | ||
1565 | { | ||
1566 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1567 | int ret; | ||
1568 | |||
1569 | ret = s5p_mfc_alloc_codec_buffers_v6(ctx); | ||
1570 | if (ret) { | ||
1571 | mfc_err("Failed to allocate encoding buffers.\n"); | ||
1572 | return -ENOMEM; | ||
1573 | } | ||
1574 | |||
1575 | /* Header was generated now starting processing | ||
1576 | * First set the reference frame buffers | ||
1577 | */ | ||
1578 | if (ctx->capture_state != QUEUE_BUFS_REQUESTED) { | ||
1579 | mfc_err("It seems that destionation buffers were not\n" | ||
1580 | "requested.MFC requires that header should be generated\n" | ||
1581 | "before allocating codec buffer.\n"); | ||
1582 | return -EAGAIN; | ||
1583 | } | ||
1584 | |||
1585 | dev->curr_ctx = ctx->num; | ||
1586 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1587 | ret = s5p_mfc_set_enc_ref_buffer_v6(ctx); | ||
1588 | if (ret) { | ||
1589 | mfc_err("Failed to alloc frame mem.\n"); | ||
1590 | ctx->state = MFCINST_ERROR; | ||
1591 | } | ||
1592 | return ret; | ||
1593 | } | ||
1594 | |||
1595 | /* Try running an operation on hardware */ | ||
1596 | void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) | ||
1597 | { | ||
1598 | struct s5p_mfc_ctx *ctx; | ||
1599 | int new_ctx; | ||
1600 | unsigned int ret = 0; | ||
1601 | |||
1602 | mfc_debug(1, "Try run dev: %p\n", dev); | ||
1603 | |||
1604 | /* Check whether hardware is not running */ | ||
1605 | if (test_and_set_bit(0, &dev->hw_lock) != 0) { | ||
1606 | /* This is perfectly ok, the scheduled ctx should wait */ | ||
1607 | mfc_debug(1, "Couldn't lock HW.\n"); | ||
1608 | return; | ||
1609 | } | ||
1610 | |||
1611 | /* Choose the context to run */ | ||
1612 | new_ctx = s5p_mfc_get_new_ctx(dev); | ||
1613 | if (new_ctx < 0) { | ||
1614 | /* No contexts to run */ | ||
1615 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) { | ||
1616 | mfc_err("Failed to unlock hardware.\n"); | ||
1617 | return; | ||
1618 | } | ||
1619 | |||
1620 | mfc_debug(1, "No ctx is scheduled to be run.\n"); | ||
1621 | return; | ||
1622 | } | ||
1623 | |||
1624 | mfc_debug(1, "New context: %d\n", new_ctx); | ||
1625 | ctx = dev->ctx[new_ctx]; | ||
1626 | mfc_debug(1, "Seting new context to %p\n", ctx); | ||
1627 | /* Got context to run in ctx */ | ||
1628 | mfc_debug(1, "ctx->dst_queue_cnt=%d ctx->dpb_count=%d ctx->src_queue_cnt=%d\n", | ||
1629 | ctx->dst_queue_cnt, ctx->dpb_count, ctx->src_queue_cnt); | ||
1630 | mfc_debug(1, "ctx->state=%d\n", ctx->state); | ||
1631 | /* Last frame has already been sent to MFC | ||
1632 | * Now obtaining frames from MFC buffer */ | ||
1633 | |||
1634 | s5p_mfc_clock_on(); | ||
1635 | if (ctx->type == MFCINST_DECODER) { | ||
1636 | switch (ctx->state) { | ||
1637 | case MFCINST_FINISHING: | ||
1638 | s5p_mfc_run_dec_last_frames(ctx); | ||
1639 | break; | ||
1640 | case MFCINST_RUNNING: | ||
1641 | ret = s5p_mfc_run_dec_frame(ctx); | ||
1642 | break; | ||
1643 | case MFCINST_INIT: | ||
1644 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1645 | ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, | ||
1646 | ctx); | ||
1647 | break; | ||
1648 | case MFCINST_RETURN_INST: | ||
1649 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1650 | ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, | ||
1651 | ctx); | ||
1652 | break; | ||
1653 | case MFCINST_GOT_INST: | ||
1654 | s5p_mfc_run_init_dec(ctx); | ||
1655 | break; | ||
1656 | case MFCINST_HEAD_PARSED: | ||
1657 | ret = s5p_mfc_run_init_dec_buffers(ctx); | ||
1658 | break; | ||
1659 | case MFCINST_RES_CHANGE_INIT: | ||
1660 | s5p_mfc_run_dec_last_frames(ctx); | ||
1661 | break; | ||
1662 | case MFCINST_RES_CHANGE_FLUSH: | ||
1663 | s5p_mfc_run_dec_last_frames(ctx); | ||
1664 | break; | ||
1665 | case MFCINST_RES_CHANGE_END: | ||
1666 | mfc_debug(2, "Finished remaining frames after resolution change.\n"); | ||
1667 | ctx->capture_state = QUEUE_FREE; | ||
1668 | mfc_debug(2, "Will re-init the codec`.\n"); | ||
1669 | s5p_mfc_run_init_dec(ctx); | ||
1670 | break; | ||
1671 | default: | ||
1672 | ret = -EAGAIN; | ||
1673 | } | ||
1674 | } else if (ctx->type == MFCINST_ENCODER) { | ||
1675 | switch (ctx->state) { | ||
1676 | case MFCINST_FINISHING: | ||
1677 | case MFCINST_RUNNING: | ||
1678 | ret = s5p_mfc_run_enc_frame(ctx); | ||
1679 | break; | ||
1680 | case MFCINST_INIT: | ||
1681 | ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd, | ||
1682 | ctx); | ||
1683 | break; | ||
1684 | case MFCINST_RETURN_INST: | ||
1685 | ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd, | ||
1686 | ctx); | ||
1687 | break; | ||
1688 | case MFCINST_GOT_INST: | ||
1689 | s5p_mfc_run_init_enc(ctx); | ||
1690 | break; | ||
1691 | case MFCINST_HEAD_PARSED: /* Only for MFC6.x */ | ||
1692 | ret = s5p_mfc_run_init_enc_buffers(ctx); | ||
1693 | break; | ||
1694 | default: | ||
1695 | ret = -EAGAIN; | ||
1696 | } | ||
1697 | } else { | ||
1698 | mfc_err("invalid context type: %d\n", ctx->type); | ||
1699 | ret = -EAGAIN; | ||
1700 | } | ||
1701 | |||
1702 | if (ret) { | ||
1703 | /* Free hardware lock */ | ||
1704 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
1705 | mfc_err("Failed to unlock hardware.\n"); | ||
1706 | |||
1707 | /* This is in deed imporant, as no operation has been | ||
1708 | * scheduled, reduce the clock count as no one will | ||
1709 | * ever do this, because no interrupt related to this try_run | ||
1710 | * will ever come from hardware. */ | ||
1711 | s5p_mfc_clock_off(); | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | |||
1716 | void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq) | ||
1717 | { | ||
1718 | struct s5p_mfc_buf *b; | ||
1719 | int i; | ||
1720 | |||
1721 | while (!list_empty(lh)) { | ||
1722 | b = list_entry(lh->next, struct s5p_mfc_buf, list); | ||
1723 | for (i = 0; i < b->b->num_planes; i++) | ||
1724 | vb2_set_plane_payload(b->b, i, 0); | ||
1725 | vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); | ||
1726 | list_del(&b->list); | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev) | ||
1731 | { | ||
1732 | mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6); | ||
1733 | mfc_write(dev, 0, S5P_FIMV_RISC2HOST_INT_V6); | ||
1734 | } | ||
1735 | |||
1736 | void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data, | ||
1737 | unsigned int ofs) | ||
1738 | { | ||
1739 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1740 | |||
1741 | s5p_mfc_clock_on(); | ||
1742 | WRITEL(data, ofs); | ||
1743 | s5p_mfc_clock_off(); | ||
1744 | } | ||
1745 | |||
1746 | unsigned int s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs) | ||
1747 | { | ||
1748 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1749 | int ret; | ||
1750 | |||
1751 | s5p_mfc_clock_on(); | ||
1752 | ret = READL(ofs); | ||
1753 | s5p_mfc_clock_off(); | ||
1754 | |||
1755 | return ret; | ||
1756 | } | ||
1757 | |||
1758 | int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev) | ||
1759 | { | ||
1760 | return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); | ||
1761 | } | ||
1762 | |||
1763 | int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev) | ||
1764 | { | ||
1765 | return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6); | ||
1766 | } | ||
1767 | |||
1768 | int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev) | ||
1769 | { | ||
1770 | return mfc_read(dev, S5P_FIMV_D_DISPLAY_STATUS_V6); | ||
1771 | } | ||
1772 | |||
1773 | int s5p_mfc_get_decoded_status_v6(struct s5p_mfc_dev *dev) | ||
1774 | { | ||
1775 | return mfc_read(dev, S5P_FIMV_D_DECODED_STATUS_V6); | ||
1776 | } | ||
1777 | |||
1778 | int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev) | ||
1779 | { | ||
1780 | return mfc_read(dev, S5P_FIMV_D_DECODED_FRAME_TYPE_V6) & | ||
1781 | S5P_FIMV_DECODE_FRAME_MASK_V6; | ||
1782 | } | ||
1783 | |||
1784 | int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx) | ||
1785 | { | ||
1786 | return mfc_read(ctx->dev, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6) & | ||
1787 | S5P_FIMV_DECODE_FRAME_MASK_V6; | ||
1788 | } | ||
1789 | |||
1790 | int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev) | ||
1791 | { | ||
1792 | return mfc_read(dev, S5P_FIMV_D_DECODED_NAL_SIZE_V6); | ||
1793 | } | ||
1794 | |||
1795 | int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev) | ||
1796 | { | ||
1797 | return mfc_read(dev, S5P_FIMV_RISC2HOST_CMD_V6) & | ||
1798 | S5P_FIMV_RISC2HOST_CMD_MASK; | ||
1799 | } | ||
1800 | |||
1801 | int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev) | ||
1802 | { | ||
1803 | return mfc_read(dev, S5P_FIMV_ERROR_CODE_V6); | ||
1804 | } | ||
1805 | |||
1806 | int s5p_mfc_err_dec_v6(unsigned int err) | ||
1807 | { | ||
1808 | return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6; | ||
1809 | } | ||
1810 | |||
1811 | int s5p_mfc_err_dspl_v6(unsigned int err) | ||
1812 | { | ||
1813 | return (err & S5P_FIMV_ERR_DSPL_MASK_V6) >> S5P_FIMV_ERR_DSPL_SHIFT_V6; | ||
1814 | } | ||
1815 | |||
1816 | int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev) | ||
1817 | { | ||
1818 | return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6); | ||
1819 | } | ||
1820 | |||
1821 | int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev) | ||
1822 | { | ||
1823 | return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6); | ||
1824 | } | ||
1825 | |||
1826 | int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev) | ||
1827 | { | ||
1828 | return mfc_read(dev, S5P_FIMV_D_MIN_NUM_DPB_V6); | ||
1829 | } | ||
1830 | |||
1831 | int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev) | ||
1832 | { | ||
1833 | return mfc_read(dev, S5P_FIMV_D_MIN_NUM_MV_V6); | ||
1834 | } | ||
1835 | |||
1836 | int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev) | ||
1837 | { | ||
1838 | return mfc_read(dev, S5P_FIMV_RET_INSTANCE_ID_V6); | ||
1839 | } | ||
1840 | |||
1841 | int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev) | ||
1842 | { | ||
1843 | return mfc_read(dev, S5P_FIMV_E_NUM_DPB_V6); | ||
1844 | } | ||
1845 | |||
1846 | int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev) | ||
1847 | { | ||
1848 | return mfc_read(dev, S5P_FIMV_E_STREAM_SIZE_V6); | ||
1849 | } | ||
1850 | |||
1851 | int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev) | ||
1852 | { | ||
1853 | return mfc_read(dev, S5P_FIMV_E_SLICE_TYPE_V6); | ||
1854 | } | ||
1855 | |||
1856 | int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev) | ||
1857 | { | ||
1858 | return mfc_read(dev, S5P_FIMV_E_PICTURE_COUNT_V6); | ||
1859 | } | ||
1860 | |||
1861 | int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx) | ||
1862 | { | ||
1863 | return mfc_read(ctx->dev, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6); | ||
1864 | } | ||
1865 | |||
1866 | int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev) | ||
1867 | { | ||
1868 | return mfc_read(dev, S5P_FIMV_D_MVC_NUM_VIEWS_V6); | ||
1869 | } | ||
1870 | |||
1871 | int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev) | ||
1872 | { | ||
1873 | return mfc_read(dev, S5P_FIMV_D_MVC_VIEW_ID_V6); | ||
1874 | } | ||
1875 | |||
1876 | unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx) | ||
1877 | { | ||
1878 | return s5p_mfc_read_info_v6(ctx, PIC_TIME_TOP_V6); | ||
1879 | } | ||
1880 | |||
1881 | unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx) | ||
1882 | { | ||
1883 | return s5p_mfc_read_info_v6(ctx, PIC_TIME_BOT_V6); | ||
1884 | } | ||
1885 | |||
1886 | unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx) | ||
1887 | { | ||
1888 | return s5p_mfc_read_info_v6(ctx, CROP_INFO_H_V6); | ||
1889 | } | ||
1890 | |||
1891 | unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx) | ||
1892 | { | ||
1893 | return s5p_mfc_read_info_v6(ctx, CROP_INFO_V_V6); | ||
1894 | } | ||
1895 | |||
1896 | /* Initialize opr function pointers for MFC v6 */ | ||
1897 | static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { | ||
1898 | .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v6, | ||
1899 | .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v6, | ||
1900 | .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v6, | ||
1901 | .release_codec_buffers = s5p_mfc_release_codec_buffers_v6, | ||
1902 | .alloc_instance_buffer = s5p_mfc_alloc_instance_buffer_v6, | ||
1903 | .release_instance_buffer = s5p_mfc_release_instance_buffer_v6, | ||
1904 | .alloc_dev_context_buffer = | ||
1905 | s5p_mfc_alloc_dev_context_buffer_v6, | ||
1906 | .release_dev_context_buffer = | ||
1907 | s5p_mfc_release_dev_context_buffer_v6, | ||
1908 | .dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v6, | ||
1909 | .enc_calc_src_size = s5p_mfc_enc_calc_src_size_v6, | ||
1910 | .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v6, | ||
1911 | .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v6, | ||
1912 | .set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v6, | ||
1913 | .set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v6, | ||
1914 | .get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v6, | ||
1915 | .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v6, | ||
1916 | .init_decode = s5p_mfc_init_decode_v6, | ||
1917 | .init_encode = s5p_mfc_init_encode_v6, | ||
1918 | .encode_one_frame = s5p_mfc_encode_one_frame_v6, | ||
1919 | .try_run = s5p_mfc_try_run_v6, | ||
1920 | .cleanup_queue = s5p_mfc_cleanup_queue_v6, | ||
1921 | .clear_int_flags = s5p_mfc_clear_int_flags_v6, | ||
1922 | .write_info = s5p_mfc_write_info_v6, | ||
1923 | .read_info = s5p_mfc_read_info_v6, | ||
1924 | .get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v6, | ||
1925 | .get_dec_y_adr = s5p_mfc_get_dec_y_adr_v6, | ||
1926 | .get_dspl_status = s5p_mfc_get_dspl_status_v6, | ||
1927 | .get_dec_status = s5p_mfc_get_dec_status_v6, | ||
1928 | .get_dec_frame_type = s5p_mfc_get_dec_frame_type_v6, | ||
1929 | .get_disp_frame_type = s5p_mfc_get_disp_frame_type_v6, | ||
1930 | .get_consumed_stream = s5p_mfc_get_consumed_stream_v6, | ||
1931 | .get_int_reason = s5p_mfc_get_int_reason_v6, | ||
1932 | .get_int_err = s5p_mfc_get_int_err_v6, | ||
1933 | .err_dec = s5p_mfc_err_dec_v6, | ||
1934 | .err_dspl = s5p_mfc_err_dspl_v6, | ||
1935 | .get_img_width = s5p_mfc_get_img_width_v6, | ||
1936 | .get_img_height = s5p_mfc_get_img_height_v6, | ||
1937 | .get_dpb_count = s5p_mfc_get_dpb_count_v6, | ||
1938 | .get_mv_count = s5p_mfc_get_mv_count_v6, | ||
1939 | .get_inst_no = s5p_mfc_get_inst_no_v6, | ||
1940 | .get_enc_strm_size = s5p_mfc_get_enc_strm_size_v6, | ||
1941 | .get_enc_slice_type = s5p_mfc_get_enc_slice_type_v6, | ||
1942 | .get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v6, | ||
1943 | .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v6, | ||
1944 | .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v6, | ||
1945 | .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v6, | ||
1946 | .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v6, | ||
1947 | .get_pic_type_top = s5p_mfc_get_pic_type_top_v6, | ||
1948 | .get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6, | ||
1949 | .get_crop_info_h = s5p_mfc_get_crop_info_h_v6, | ||
1950 | .get_crop_info_v = s5p_mfc_get_crop_info_v_v6, | ||
1951 | }; | ||
1952 | |||
1953 | struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) | ||
1954 | { | ||
1955 | return &s5p_mfc_ops_v6; | ||
1956 | } | ||
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h new file mode 100644 index 000000000000..ab164efa127e --- /dev/null +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h | ||
3 | * | ||
4 | * Header file for Samsung MFC (Multi Function Codec - FIMV) driver | ||
5 | * Contains declarations of hw related functions. | ||
6 | * | ||
7 | * Copyright (c) 2012 Samsung Electronics Co., Ltd. | ||
8 | * http://www.samsung.com/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef S5P_MFC_OPR_V6_H_ | ||
16 | #define S5P_MFC_OPR_V6_H_ | ||
17 | |||
18 | #include "s5p_mfc_common.h" | ||
19 | #include "s5p_mfc_opr.h" | ||
20 | |||
21 | #define MFC_CTRL_MODE_CUSTOM MFC_CTRL_MODE_SFR | ||
22 | |||
23 | #define MB_WIDTH(x_size) DIV_ROUND_UP(x_size, 16) | ||
24 | #define MB_HEIGHT(y_size) DIV_ROUND_UP(y_size, 16) | ||
25 | #define S5P_MFC_DEC_MV_SIZE_V6(x, y) (MB_WIDTH(x) * \ | ||
26 | (((MB_HEIGHT(y)+1)/2)*2) * 64 + 128) | ||
27 | |||
28 | /* Definition */ | ||
29 | #define ENC_MULTI_SLICE_MB_MAX ((1 << 30) - 1) | ||
30 | #define ENC_MULTI_SLICE_BIT_MIN 2800 | ||
31 | #define ENC_INTRA_REFRESH_MB_MAX ((1 << 18) - 1) | ||
32 | #define ENC_VBV_BUF_SIZE_MAX ((1 << 30) - 1) | ||
33 | #define ENC_H264_LOOP_FILTER_AB_MIN -12 | ||
34 | #define ENC_H264_LOOP_FILTER_AB_MAX 12 | ||
35 | #define ENC_H264_RC_FRAME_RATE_MAX ((1 << 16) - 1) | ||
36 | #define ENC_H263_RC_FRAME_RATE_MAX ((1 << 16) - 1) | ||
37 | #define ENC_H264_PROFILE_MAX 3 | ||
38 | #define ENC_H264_LEVEL_MAX 42 | ||
39 | #define ENC_MPEG4_VOP_TIME_RES_MAX ((1 << 16) - 1) | ||
40 | #define FRAME_DELTA_H264_H263 1 | ||
41 | #define TIGHT_CBR_MAX 10 | ||
42 | |||
43 | /* Definitions for shared memory compatibility */ | ||
44 | #define PIC_TIME_TOP_V6 S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6 | ||
45 | #define PIC_TIME_BOT_V6 S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6 | ||
46 | #define CROP_INFO_H_V6 S5P_FIMV_D_DISPLAY_CROP_INFO1_V6 | ||
47 | #define CROP_INFO_V_V6 S5P_FIMV_D_DISPLAY_CROP_INFO2_V6 | ||
48 | |||
49 | struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); | ||
50 | #endif /* S5P_MFC_OPR_V6_H_ */ | ||
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 0503d14ac94e..367db7552289 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include "s5p_mfc_debug.h" | 20 | #include "s5p_mfc_debug.h" |
21 | #include "s5p_mfc_pm.h" | 21 | #include "s5p_mfc_pm.h" |
22 | 22 | ||
23 | #define MFC_CLKNAME "sclk_mfc" | ||
24 | #define MFC_GATE_CLK_NAME "mfc" | 23 | #define MFC_GATE_CLK_NAME "mfc" |
25 | 24 | ||
26 | #define CLK_DEBUG | 25 | #define CLK_DEBUG |
@@ -51,7 +50,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) | |||
51 | goto err_p_ip_clk; | 50 | goto err_p_ip_clk; |
52 | } | 51 | } |
53 | 52 | ||
54 | pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME); | 53 | pm->clock = clk_get(&dev->plat_dev->dev, dev->variant->mclk_name); |
55 | if (IS_ERR(pm->clock)) { | 54 | if (IS_ERR(pm->clock)) { |
56 | mfc_err("Failed to get MFC clock\n"); | 55 | mfc_err("Failed to get MFC clock\n"); |
57 | ret = PTR_ERR(pm->clock); | 56 | ret = PTR_ERR(pm->clock); |