diff options
author | Kamil Debski <k.debski@samsung.com> | 2011-06-21 09:51:26 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-07-27 16:56:00 -0400 |
commit | af935746781088f28904601469671d244d2f653b (patch) | |
tree | 0961dd7f98843d250abc5ff7ef3c4d37962b661f /drivers/media/video/s5p-mfc | |
parent | c53f9f00e5ddf72046698d6a378384e29fc9795f (diff) |
[media] MFC: Add MFC 5.1 V4L2 driver
Multi Format Codec 5.1 is a hardware video coding acceleration
module found in the S5PV210 and Exynos4 Samsung SoCs. It is
capable of handling a range of video codecs and this driver
provides a V4L2 interface for video decoding and encoding.
Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Jeongtae Park <jtp.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/s5p-mfc')
21 files changed, 7630 insertions, 0 deletions
diff --git a/drivers/media/video/s5p-mfc/Makefile b/drivers/media/video/s5p-mfc/Makefile new file mode 100644 index 000000000000..d0663409af00 --- /dev/null +++ b/drivers/media/video/s5p-mfc/Makefile | |||
@@ -0,0 +1,5 @@ | |||
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 | ||
3 | s5p-mfc-y += s5p_mfc_dec.o s5p_mfc_enc.o | ||
4 | s5p-mfc-y += s5p_mfc_ctrl.o s5p_mfc_cmd.o | ||
5 | s5p-mfc-y += s5p_mfc_pm.o s5p_mfc_shm.o | ||
diff --git a/drivers/media/video/s5p-mfc/regs-mfc.h b/drivers/media/video/s5p-mfc/regs-mfc.h new file mode 100644 index 000000000000..053a8a872fd7 --- /dev/null +++ b/drivers/media/video/s5p-mfc/regs-mfc.h | |||
@@ -0,0 +1,413 @@ | |||
1 | /* | ||
2 | * Register definition file for Samsung MFC V5.1 Interface (FIMV) driver | ||
3 | * | ||
4 | * Kamil Debski, Copyright (c) 2010 Samsung Electronics | ||
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 version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #ifndef _REGS_FIMV_H | ||
13 | #define _REGS_FIMV_H | ||
14 | |||
15 | #define S5P_FIMV_REG_SIZE (S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) | ||
16 | #define S5P_FIMV_REG_COUNT ((S5P_FIMV_END_ADDR - S5P_FIMV_START_ADDR) / 4) | ||
17 | |||
18 | /* Number of bits that the buffer address should be shifted for particular | ||
19 | * MFC buffers. */ | ||
20 | #define S5P_FIMV_START_ADDR 0x0000 | ||
21 | #define S5P_FIMV_END_ADDR 0xe008 | ||
22 | |||
23 | #define S5P_FIMV_SW_RESET 0x0000 | ||
24 | #define S5P_FIMV_RISC_HOST_INT 0x0008 | ||
25 | |||
26 | /* Command from HOST to RISC */ | ||
27 | #define S5P_FIMV_HOST2RISC_CMD 0x0030 | ||
28 | #define S5P_FIMV_HOST2RISC_ARG1 0x0034 | ||
29 | #define S5P_FIMV_HOST2RISC_ARG2 0x0038 | ||
30 | #define S5P_FIMV_HOST2RISC_ARG3 0x003c | ||
31 | #define S5P_FIMV_HOST2RISC_ARG4 0x0040 | ||
32 | |||
33 | /* Command from RISC to HOST */ | ||
34 | #define S5P_FIMV_RISC2HOST_CMD 0x0044 | ||
35 | #define S5P_FIMV_RISC2HOST_CMD_MASK 0x1FFFF | ||
36 | #define S5P_FIMV_RISC2HOST_ARG1 0x0048 | ||
37 | #define S5P_FIMV_RISC2HOST_ARG2 0x004c | ||
38 | #define S5P_FIMV_RISC2HOST_ARG3 0x0050 | ||
39 | #define S5P_FIMV_RISC2HOST_ARG4 0x0054 | ||
40 | |||
41 | #define S5P_FIMV_FW_VERSION 0x0058 | ||
42 | #define S5P_FIMV_SYS_MEM_SZ 0x005c | ||
43 | #define S5P_FIMV_FW_STATUS 0x0080 | ||
44 | |||
45 | /* Memory controller register */ | ||
46 | #define S5P_FIMV_MC_DRAMBASE_ADR_A 0x0508 | ||
47 | #define S5P_FIMV_MC_DRAMBASE_ADR_B 0x050c | ||
48 | #define S5P_FIMV_MC_STATUS 0x0510 | ||
49 | |||
50 | /* Common register */ | ||
51 | #define S5P_FIMV_COMMON_BASE_A 0x0600 | ||
52 | #define S5P_FIMV_COMMON_BASE_B 0x0700 | ||
53 | |||
54 | /* Decoder */ | ||
55 | #define S5P_FIMV_DEC_CHROMA_ADR (S5P_FIMV_COMMON_BASE_A) | ||
56 | #define S5P_FIMV_DEC_LUMA_ADR (S5P_FIMV_COMMON_BASE_B) | ||
57 | |||
58 | /* H.264 decoding */ | ||
59 | #define S5P_FIMV_H264_VERT_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) | ||
60 | /* vertical neighbor motion vector */ | ||
61 | #define S5P_FIMV_H264_NB_IP_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) | ||
62 | /* neighbor pixels for intra pred */ | ||
63 | #define S5P_FIMV_H264_MV_ADR (S5P_FIMV_COMMON_BASE_B + 0x80) | ||
64 | /* H264 motion vector */ | ||
65 | |||
66 | /* MPEG4 decoding */ | ||
67 | #define S5P_FIMV_MPEG4_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) | ||
68 | /* neighbor AC/DC coeff. */ | ||
69 | #define S5P_FIMV_MPEG4_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) | ||
70 | /* upper neighbor motion vector */ | ||
71 | #define S5P_FIMV_MPEG4_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) | ||
72 | /* subseq. anchor motion vector */ | ||
73 | #define S5P_FIMV_MPEG4_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) | ||
74 | /* overlap transform line */ | ||
75 | #define S5P_FIMV_MPEG4_SP_ADR (S5P_FIMV_COMMON_BASE_A + 0xa8) | ||
76 | /* syntax parser */ | ||
77 | |||
78 | /* H.263 decoding */ | ||
79 | #define S5P_FIMV_H263_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) | ||
80 | #define S5P_FIMV_H263_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) | ||
81 | #define S5P_FIMV_H263_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) | ||
82 | #define S5P_FIMV_H263_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) | ||
83 | |||
84 | /* VC-1 decoding */ | ||
85 | #define S5P_FIMV_VC1_NB_DCAC_ADR (S5P_FIMV_COMMON_BASE_A + 0x8c) | ||
86 | #define S5P_FIMV_VC1_UP_NB_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x90) | ||
87 | #define S5P_FIMV_VC1_SA_MV_ADR (S5P_FIMV_COMMON_BASE_A + 0x94) | ||
88 | #define S5P_FIMV_VC1_OT_LINE_ADR (S5P_FIMV_COMMON_BASE_A + 0x98) | ||
89 | #define S5P_FIMV_VC1_BITPLANE3_ADR (S5P_FIMV_COMMON_BASE_A + 0x9c) | ||
90 | /* bitplane3 */ | ||
91 | #define S5P_FIMV_VC1_BITPLANE2_ADR (S5P_FIMV_COMMON_BASE_A + 0xa0) | ||
92 | /* bitplane2 */ | ||
93 | #define S5P_FIMV_VC1_BITPLANE1_ADR (S5P_FIMV_COMMON_BASE_A + 0xa4) | ||
94 | /* bitplane1 */ | ||
95 | |||
96 | /* Encoder */ | ||
97 | #define S5P_FIMV_ENC_REF0_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x1c) | ||
98 | #define S5P_FIMV_ENC_REF1_LUMA_ADR (S5P_FIMV_COMMON_BASE_A + 0x20) | ||
99 | /* reconstructed luma */ | ||
100 | #define S5P_FIMV_ENC_REF0_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B) | ||
101 | #define S5P_FIMV_ENC_REF1_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x04) | ||
102 | /* reconstructed chroma */ | ||
103 | #define S5P_FIMV_ENC_REF2_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x10) | ||
104 | #define S5P_FIMV_ENC_REF2_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x08) | ||
105 | #define S5P_FIMV_ENC_REF3_LUMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x14) | ||
106 | #define S5P_FIMV_ENC_REF3_CHROMA_ADR (S5P_FIMV_COMMON_BASE_B + 0x0c) | ||
107 | |||
108 | /* H.264 encoding */ | ||
109 | #define S5P_FIMV_H264_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) | ||
110 | /* upper motion vector */ | ||
111 | #define S5P_FIMV_H264_NBOR_INFO_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) | ||
112 | /* entropy engine's neighbor info. */ | ||
113 | #define S5P_FIMV_H264_UP_INTRA_MD_ADR (S5P_FIMV_COMMON_BASE_A + 0x08) | ||
114 | /* upper intra MD */ | ||
115 | #define S5P_FIMV_H264_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) | ||
116 | /* direct cozero flag */ | ||
117 | #define S5P_FIMV_H264_UP_INTRA_PRED_ADR (S5P_FIMV_COMMON_BASE_B + 0x40) | ||
118 | /* upper intra PRED */ | ||
119 | |||
120 | /* H.263 encoding */ | ||
121 | #define S5P_FIMV_H263_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) | ||
122 | /* upper motion vector */ | ||
123 | #define S5P_FIMV_H263_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) | ||
124 | /* upper Q coeff. */ | ||
125 | |||
126 | /* MPEG4 encoding */ | ||
127 | #define S5P_FIMV_MPEG4_UP_MV_ADR (S5P_FIMV_COMMON_BASE_A) | ||
128 | /* upper motion vector */ | ||
129 | #define S5P_FIMV_MPEG4_ACDC_COEF_ADR (S5P_FIMV_COMMON_BASE_A + 0x04) | ||
130 | /* upper Q coeff. */ | ||
131 | #define S5P_FIMV_MPEG4_COZERO_FLAG_ADR (S5P_FIMV_COMMON_BASE_A + 0x10) | ||
132 | /* direct cozero flag */ | ||
133 | |||
134 | #define S5P_FIMV_ENC_REF_B_LUMA_ADR 0x062c /* ref B Luma addr */ | ||
135 | #define S5P_FIMV_ENC_REF_B_CHROMA_ADR 0x0630 /* ref B Chroma addr */ | ||
136 | |||
137 | #define S5P_FIMV_ENC_CUR_LUMA_ADR 0x0718 /* current Luma addr */ | ||
138 | #define S5P_FIMV_ENC_CUR_CHROMA_ADR 0x071C /* current Chroma addr */ | ||
139 | |||
140 | /* Codec common register */ | ||
141 | #define S5P_FIMV_ENC_HSIZE_PX 0x0818 /* frame width at encoder */ | ||
142 | #define S5P_FIMV_ENC_VSIZE_PX 0x081c /* frame height at encoder */ | ||
143 | #define S5P_FIMV_ENC_PROFILE 0x0830 /* profile register */ | ||
144 | #define S5P_FIMV_ENC_PROFILE_H264_MAIN 0 | ||
145 | #define S5P_FIMV_ENC_PROFILE_H264_HIGH 1 | ||
146 | #define S5P_FIMV_ENC_PROFILE_H264_BASELINE 2 | ||
147 | #define S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE 0 | ||
148 | #define S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE 1 | ||
149 | #define S5P_FIMV_ENC_PIC_STRUCT 0x083c /* picture field/frame flag */ | ||
150 | #define S5P_FIMV_ENC_LF_CTRL 0x0848 /* loop filter control */ | ||
151 | #define S5P_FIMV_ENC_ALPHA_OFF 0x084c /* loop filter alpha offset */ | ||
152 | #define S5P_FIMV_ENC_BETA_OFF 0x0850 /* loop filter beta offset */ | ||
153 | #define S5P_FIMV_MR_BUSIF_CTRL 0x0854 /* hidden, bus interface ctrl */ | ||
154 | #define S5P_FIMV_ENC_PXL_CACHE_CTRL 0x0a00 /* pixel cache control */ | ||
155 | |||
156 | /* Channel & stream interface register */ | ||
157 | #define S5P_FIMV_SI_RTN_CHID 0x2000 /* Return CH inst ID register */ | ||
158 | #define S5P_FIMV_SI_CH0_INST_ID 0x2040 /* codec instance ID */ | ||
159 | #define S5P_FIMV_SI_CH1_INST_ID 0x2080 /* codec instance ID */ | ||
160 | /* Decoder */ | ||
161 | #define S5P_FIMV_SI_VRESOL 0x2004 /* vertical res of decoder */ | ||
162 | #define S5P_FIMV_SI_HRESOL 0x2008 /* horizontal res of decoder */ | ||
163 | #define S5P_FIMV_SI_BUF_NUMBER 0x200c /* number of frames in the | ||
164 | decoded pic */ | ||
165 | #define S5P_FIMV_SI_DISPLAY_Y_ADR 0x2010 /* luma addr of displayed pic */ | ||
166 | #define S5P_FIMV_SI_DISPLAY_C_ADR 0x2014 /* chroma addrof displayed pic */ | ||
167 | #define S5P_FIMV_SI_CONSUMED_BYTES 0x2018 /* Consumed number of bytes to | ||
168 | decode a frame */ | ||
169 | #define S5P_FIMV_SI_DISPLAY_STATUS 0x201c /* status of decoded picture */ | ||
170 | |||
171 | #define S5P_FIMV_SI_CH0_SB_ST_ADR 0x2044 /* start addr of stream buf */ | ||
172 | #define S5P_FIMV_SI_CH0_SB_FRM_SIZE 0x2048 /* size of stream buf */ | ||
173 | #define S5P_FIMV_SI_CH0_DESC_ADR 0x204c /* addr of descriptor buf */ | ||
174 | #define S5P_FIMV_SI_CH0_CPB_SIZE 0x2058 /* max size of coded pic. buf */ | ||
175 | #define S5P_FIMV_SI_CH0_DESC_SIZE 0x205c /* max size of descriptor buf */ | ||
176 | |||
177 | #define S5P_FIMV_SI_CH1_SB_ST_ADR 0x2084 /* start addr of stream buf */ | ||
178 | #define S5P_FIMV_SI_CH1_SB_FRM_SIZE 0x2088 /* size of stream buf */ | ||
179 | #define S5P_FIMV_SI_CH1_DESC_ADR 0x208c /* addr of descriptor buf */ | ||
180 | #define S5P_FIMV_SI_CH1_CPB_SIZE 0x2098 /* max size of coded pic. buf */ | ||
181 | #define S5P_FIMV_SI_CH1_DESC_SIZE 0x209c /* max size of descriptor buf */ | ||
182 | |||
183 | #define S5P_FIMV_CRC_LUMA0 0x2030 /* luma crc data per frame | ||
184 | (top field) */ | ||
185 | #define S5P_FIMV_CRC_CHROMA0 0x2034 /* chroma crc data per frame | ||
186 | (top field) */ | ||
187 | #define S5P_FIMV_CRC_LUMA1 0x2038 /* luma crc data per bottom | ||
188 | field */ | ||
189 | #define S5P_FIMV_CRC_CHROMA1 0x203c /* chroma crc data per bottom | ||
190 | field */ | ||
191 | |||
192 | /* Display status */ | ||
193 | #define S5P_FIMV_DEC_STATUS_DECODING_ONLY 0 | ||
194 | #define S5P_FIMV_DEC_STATUS_DECODING_DISPLAY 1 | ||
195 | #define S5P_FIMV_DEC_STATUS_DISPLAY_ONLY 2 | ||
196 | #define S5P_FIMV_DEC_STATUS_DECODING_EMPTY 3 | ||
197 | #define S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK 7 | ||
198 | #define S5P_FIMV_DEC_STATUS_PROGRESSIVE (0<<3) | ||
199 | #define S5P_FIMV_DEC_STATUS_INTERLACE (1<<3) | ||
200 | #define S5P_FIMV_DEC_STATUS_INTERLACE_MASK (1<<3) | ||
201 | #define S5P_FIMV_DEC_STATUS_CRC_NUMBER_TWO (0<<4) | ||
202 | #define S5P_FIMV_DEC_STATUS_CRC_NUMBER_FOUR (1<<4) | ||
203 | #define S5P_FIMV_DEC_STATUS_CRC_NUMBER_MASK (1<<4) | ||
204 | #define S5P_FIMV_DEC_STATUS_CRC_GENERATED (1<<5) | ||
205 | #define S5P_FIMV_DEC_STATUS_CRC_NOT_GENERATED (0<<5) | ||
206 | #define S5P_FIMV_DEC_STATUS_CRC_MASK (1<<5) | ||
207 | |||
208 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_MASK (3<<4) | ||
209 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_INC (1<<4) | ||
210 | #define S5P_FIMV_DEC_STATUS_RESOLUTION_DEC (2<<4) | ||
211 | |||
212 | /* Decode frame address */ | ||
213 | #define S5P_FIMV_DECODE_Y_ADR 0x2024 | ||
214 | #define S5P_FIMV_DECODE_C_ADR 0x2028 | ||
215 | |||
216 | /* Decoded frame tpe */ | ||
217 | #define S5P_FIMV_DECODE_FRAME_TYPE 0x2020 | ||
218 | #define S5P_FIMV_DECODE_FRAME_MASK 7 | ||
219 | |||
220 | #define S5P_FIMV_DECODE_FRAME_SKIPPED 0 | ||
221 | #define S5P_FIMV_DECODE_FRAME_I_FRAME 1 | ||
222 | #define S5P_FIMV_DECODE_FRAME_P_FRAME 2 | ||
223 | #define S5P_FIMV_DECODE_FRAME_B_FRAME 3 | ||
224 | #define S5P_FIMV_DECODE_FRAME_OTHER_FRAME 4 | ||
225 | |||
226 | /* Sizes of buffers required for decoding */ | ||
227 | #define S5P_FIMV_DEC_NB_IP_SIZE (32 * 1024) | ||
228 | #define S5P_FIMV_DEC_VERT_NB_MV_SIZE (16 * 1024) | ||
229 | #define S5P_FIMV_DEC_NB_DCAC_SIZE (16 * 1024) | ||
230 | #define S5P_FIMV_DEC_UPNB_MV_SIZE (68 * 1024) | ||
231 | #define S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE (136 * 1024) | ||
232 | #define S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE (32 * 1024) | ||
233 | #define S5P_FIMV_DEC_VC1_BITPLANE_SIZE (2 * 1024) | ||
234 | #define S5P_FIMV_DEC_STX_PARSER_SIZE (68 * 1024) | ||
235 | |||
236 | #define S5P_FIMV_DEC_BUF_ALIGN (8 * 1024) | ||
237 | #define S5P_FIMV_ENC_BUF_ALIGN (8 * 1024) | ||
238 | #define S5P_FIMV_NV12M_HALIGN 16 | ||
239 | #define S5P_FIMV_NV12M_LVALIGN 16 | ||
240 | #define S5P_FIMV_NV12M_CVALIGN 8 | ||
241 | #define S5P_FIMV_NV12MT_HALIGN 128 | ||
242 | #define S5P_FIMV_NV12MT_VALIGN 32 | ||
243 | #define S5P_FIMV_NV12M_SALIGN 2048 | ||
244 | #define S5P_FIMV_NV12MT_SALIGN 8192 | ||
245 | |||
246 | /* Sizes of buffers required for encoding */ | ||
247 | #define S5P_FIMV_ENC_UPMV_SIZE 0x10000 | ||
248 | #define S5P_FIMV_ENC_COLFLG_SIZE 0x10000 | ||
249 | #define S5P_FIMV_ENC_INTRAMD_SIZE 0x10000 | ||
250 | #define S5P_FIMV_ENC_INTRAPRED_SIZE 0x4000 | ||
251 | #define S5P_FIMV_ENC_NBORINFO_SIZE 0x10000 | ||
252 | #define S5P_FIMV_ENC_ACDCCOEF_SIZE 0x10000 | ||
253 | |||
254 | /* Encoder */ | ||
255 | #define S5P_FIMV_ENC_SI_STRM_SIZE 0x2004 /* stream size */ | ||
256 | #define S5P_FIMV_ENC_SI_PIC_CNT 0x2008 /* picture count */ | ||
257 | #define S5P_FIMV_ENC_SI_WRITE_PTR 0x200c /* write pointer */ | ||
258 | #define S5P_FIMV_ENC_SI_SLICE_TYPE 0x2010 /* slice type(I/P/B/IDR) */ | ||
259 | #define S5P_FIMV_ENC_SI_SLICE_TYPE_NON_CODED 0 | ||
260 | #define S5P_FIMV_ENC_SI_SLICE_TYPE_I 1 | ||
261 | #define S5P_FIMV_ENC_SI_SLICE_TYPE_P 2 | ||
262 | #define S5P_FIMV_ENC_SI_SLICE_TYPE_B 3 | ||
263 | #define S5P_FIMV_ENC_SI_SLICE_TYPE_SKIPPED 4 | ||
264 | #define S5P_FIMV_ENC_SI_SLICE_TYPE_OTHERS 5 | ||
265 | #define S5P_FIMV_ENCODED_Y_ADDR 0x2014 /* the addr of the encoded | ||
266 | luma pic */ | ||
267 | #define S5P_FIMV_ENCODED_C_ADDR 0x2018 /* the addr of the encoded | ||
268 | chroma pic */ | ||
269 | |||
270 | #define S5P_FIMV_ENC_SI_CH0_SB_ADR 0x2044 /* addr of stream buf */ | ||
271 | #define S5P_FIMV_ENC_SI_CH0_SB_SIZE 0x204c /* size of stream buf */ | ||
272 | #define S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR 0x2050 /* current Luma addr */ | ||
273 | #define S5P_FIMV_ENC_SI_CH0_CUR_C_ADR 0x2054 /* current Chroma addr */ | ||
274 | #define S5P_FIMV_ENC_SI_CH0_FRAME_INS 0x2058 /* frame insertion */ | ||
275 | |||
276 | #define S5P_FIMV_ENC_SI_CH1_SB_ADR 0x2084 /* addr of stream buf */ | ||
277 | #define S5P_FIMV_ENC_SI_CH1_SB_SIZE 0x208c /* size of stream buf */ | ||
278 | #define S5P_FIMV_ENC_SI_CH1_CUR_Y_ADR 0x2090 /* current Luma addr */ | ||
279 | #define S5P_FIMV_ENC_SI_CH1_CUR_C_ADR 0x2094 /* current Chroma addr */ | ||
280 | #define S5P_FIMV_ENC_SI_CH1_FRAME_INS 0x2098 /* frame insertion */ | ||
281 | |||
282 | #define S5P_FIMV_ENC_PIC_TYPE_CTRL 0xc504 /* pic type level control */ | ||
283 | #define S5P_FIMV_ENC_B_RECON_WRITE_ON 0xc508 /* B frame recon write ctrl */ | ||
284 | #define S5P_FIMV_ENC_MSLICE_CTRL 0xc50c /* multi slice control */ | ||
285 | #define S5P_FIMV_ENC_MSLICE_MB 0xc510 /* MB number in the one slice */ | ||
286 | #define S5P_FIMV_ENC_MSLICE_BIT 0xc514 /* bit count for one slice */ | ||
287 | #define S5P_FIMV_ENC_CIR_CTRL 0xc518 /* number of intra refresh MB */ | ||
288 | #define S5P_FIMV_ENC_MAP_FOR_CUR 0xc51c /* linear or tiled mode */ | ||
289 | #define S5P_FIMV_ENC_PADDING_CTRL 0xc520 /* padding control */ | ||
290 | |||
291 | #define S5P_FIMV_ENC_RC_CONFIG 0xc5a0 /* RC config */ | ||
292 | #define S5P_FIMV_ENC_RC_BIT_RATE 0xc5a8 /* bit rate */ | ||
293 | #define S5P_FIMV_ENC_RC_QBOUND 0xc5ac /* max/min QP */ | ||
294 | #define S5P_FIMV_ENC_RC_RPARA 0xc5b0 /* rate control reaction coeff */ | ||
295 | #define S5P_FIMV_ENC_RC_MB_CTRL 0xc5b4 /* MB adaptive scaling */ | ||
296 | |||
297 | /* Encoder for H264 only */ | ||
298 | #define S5P_FIMV_ENC_H264_ENTROPY_MODE 0xd004 /* CAVLC or CABAC */ | ||
299 | #define S5P_FIMV_ENC_H264_ALPHA_OFF 0xd008 /* loop filter alpha offset */ | ||
300 | #define S5P_FIMV_ENC_H264_BETA_OFF 0xd00c /* loop filter beta offset */ | ||
301 | #define S5P_FIMV_ENC_H264_NUM_OF_REF 0xd010 /* number of reference for P/B */ | ||
302 | #define S5P_FIMV_ENC_H264_TRANS_FLAG 0xd034 /* 8x8 transform flag in PPS & | ||
303 | high profile */ | ||
304 | |||
305 | #define S5P_FIMV_ENC_RC_FRAME_RATE 0xd0d0 /* frame rate */ | ||
306 | |||
307 | /* Encoder for MPEG4 only */ | ||
308 | #define S5P_FIMV_ENC_MPEG4_QUART_PXL 0xe008 /* qpel interpolation ctrl */ | ||
309 | |||
310 | /* Additional */ | ||
311 | #define S5P_FIMV_SI_CH0_DPB_CONF_CTRL 0x2068 /* DPB Config Control Register */ | ||
312 | #define S5P_FIMV_SLICE_INT_MASK 1 | ||
313 | #define S5P_FIMV_SLICE_INT_SHIFT 31 | ||
314 | #define S5P_FIMV_DDELAY_ENA_SHIFT 30 | ||
315 | #define S5P_FIMV_DDELAY_VAL_MASK 0xff | ||
316 | #define S5P_FIMV_DDELAY_VAL_SHIFT 16 | ||
317 | #define S5P_FIMV_DPB_COUNT_MASK 0xffff | ||
318 | #define S5P_FIMV_DPB_FLUSH_MASK 1 | ||
319 | #define S5P_FIMV_DPB_FLUSH_SHIFT 14 | ||
320 | |||
321 | |||
322 | #define S5P_FIMV_SI_CH0_RELEASE_BUF 0x2060 /* DPB release buffer register */ | ||
323 | #define S5P_FIMV_SI_CH0_HOST_WR_ADR 0x2064 /* address of shared memory */ | ||
324 | |||
325 | /* Codec numbers */ | ||
326 | #define S5P_FIMV_CODEC_NONE -1 | ||
327 | |||
328 | #define S5P_FIMV_CODEC_H264_DEC 0 | ||
329 | #define S5P_FIMV_CODEC_VC1_DEC 1 | ||
330 | #define S5P_FIMV_CODEC_MPEG4_DEC 2 | ||
331 | #define S5P_FIMV_CODEC_MPEG2_DEC 3 | ||
332 | #define S5P_FIMV_CODEC_H263_DEC 4 | ||
333 | #define S5P_FIMV_CODEC_VC1RCV_DEC 5 | ||
334 | |||
335 | #define S5P_FIMV_CODEC_H264_ENC 16 | ||
336 | #define S5P_FIMV_CODEC_MPEG4_ENC 17 | ||
337 | #define S5P_FIMV_CODEC_H263_ENC 18 | ||
338 | |||
339 | /* Channel Control Register */ | ||
340 | #define S5P_FIMV_CH_SEQ_HEADER 1 | ||
341 | #define S5P_FIMV_CH_FRAME_START 2 | ||
342 | #define S5P_FIMV_CH_LAST_FRAME 3 | ||
343 | #define S5P_FIMV_CH_INIT_BUFS 4 | ||
344 | #define S5P_FIMV_CH_FRAME_START_REALLOC 5 | ||
345 | #define S5P_FIMV_CH_MASK 7 | ||
346 | #define S5P_FIMV_CH_SHIFT 16 | ||
347 | |||
348 | |||
349 | /* Host to RISC command */ | ||
350 | #define S5P_FIMV_H2R_CMD_EMPTY 0 | ||
351 | #define S5P_FIMV_H2R_CMD_OPEN_INSTANCE 1 | ||
352 | #define S5P_FIMV_H2R_CMD_CLOSE_INSTANCE 2 | ||
353 | #define S5P_FIMV_H2R_CMD_SYS_INIT 3 | ||
354 | #define S5P_FIMV_H2R_CMD_FLUSH 4 | ||
355 | #define S5P_FIMV_H2R_CMD_SLEEP 5 | ||
356 | #define S5P_FIMV_H2R_CMD_WAKEUP 6 | ||
357 | |||
358 | #define S5P_FIMV_R2H_CMD_EMPTY 0 | ||
359 | #define S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET 1 | ||
360 | #define S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET 2 | ||
361 | #define S5P_FIMV_R2H_CMD_RSV_RET 3 | ||
362 | #define S5P_FIMV_R2H_CMD_SEQ_DONE_RET 4 | ||
363 | #define S5P_FIMV_R2H_CMD_FRAME_DONE_RET 5 | ||
364 | #define S5P_FIMV_R2H_CMD_SLICE_DONE_RET 6 | ||
365 | #define S5P_FIMV_R2H_CMD_ENC_COMPLETE_RET 7 | ||
366 | #define S5P_FIMV_R2H_CMD_SYS_INIT_RET 8 | ||
367 | #define S5P_FIMV_R2H_CMD_FW_STATUS_RET 9 | ||
368 | #define S5P_FIMV_R2H_CMD_SLEEP_RET 10 | ||
369 | #define S5P_FIMV_R2H_CMD_WAKEUP_RET 11 | ||
370 | #define S5P_FIMV_R2H_CMD_FLUSH_RET 12 | ||
371 | #define S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET 15 | ||
372 | #define S5P_FIMV_R2H_CMD_EDFU_INIT_RET 16 | ||
373 | #define S5P_FIMV_R2H_CMD_ERR_RET 32 | ||
374 | |||
375 | /* Error handling defines */ | ||
376 | #define S5P_FIMV_ERR_WARNINGS_START 145 | ||
377 | #define S5P_FIMV_ERR_DEC_MASK 0xFFFF | ||
378 | #define S5P_FIMV_ERR_DEC_SHIFT 0 | ||
379 | #define S5P_FIMV_ERR_DSPL_MASK 0xFFFF0000 | ||
380 | #define S5P_FIMV_ERR_DSPL_SHIFT 16 | ||
381 | |||
382 | /* Shared memory registers' offsets */ | ||
383 | |||
384 | /* An offset of the start position in the stream when | ||
385 | * the start position is not aligned */ | ||
386 | #define S5P_FIMV_SHARED_CROP_INFO_H 0x0020 | ||
387 | #define S5P_FIMV_SHARED_CROP_LEFT_MASK 0xFFFF | ||
388 | #define S5P_FIMV_SHARED_CROP_LEFT_SHIFT 0 | ||
389 | #define S5P_FIMV_SHARED_CROP_RIGHT_MASK 0xFFFF0000 | ||
390 | #define S5P_FIMV_SHARED_CROP_RIGHT_SHIFT 16 | ||
391 | #define S5P_FIMV_SHARED_CROP_INFO_V 0x0024 | ||
392 | #define S5P_FIMV_SHARED_CROP_TOP_MASK 0xFFFF | ||
393 | #define S5P_FIMV_SHARED_CROP_TOP_SHIFT 0 | ||
394 | #define S5P_FIMV_SHARED_CROP_BOTTOM_MASK 0xFFFF0000 | ||
395 | #define S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT 16 | ||
396 | #define S5P_FIMV_SHARED_SET_FRAME_TAG 0x0004 | ||
397 | #define S5P_FIMV_SHARED_GET_FRAME_TAG_TOP 0x0008 | ||
398 | #define S5P_FIMV_SHARED_GET_FRAME_TAG_BOT 0x000C | ||
399 | #define S5P_FIMV_SHARED_START_BYTE_NUM 0x0018 | ||
400 | #define S5P_FIMV_SHARED_RC_VOP_TIMING 0x0030 | ||
401 | #define S5P_FIMV_SHARED_LUMA_DPB_SIZE 0x0064 | ||
402 | #define S5P_FIMV_SHARED_CHROMA_DPB_SIZE 0x0068 | ||
403 | #define S5P_FIMV_SHARED_MV_SIZE 0x006C | ||
404 | #define S5P_FIMV_SHARED_PIC_TIME_TOP 0x0010 | ||
405 | #define S5P_FIMV_SHARED_PIC_TIME_BOTTOM 0x0014 | ||
406 | #define S5P_FIMV_SHARED_EXT_ENC_CONTROL 0x0028 | ||
407 | #define S5P_FIMV_SHARED_P_B_FRAME_QP 0x0070 | ||
408 | #define S5P_FIMV_SHARED_ASPECT_RATIO_IDC 0x0074 | ||
409 | #define S5P_FIMV_SHARED_EXTENDED_SAR 0x0078 | ||
410 | #define S5P_FIMV_SHARED_H264_I_PERIOD 0x009C | ||
411 | #define S5P_FIMV_SHARED_RC_CONTROL_CONFIG 0x00A0 | ||
412 | |||
413 | #endif /* _REGS_FIMV_H */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc.c b/drivers/media/video/s5p-mfc/s5p_mfc.c new file mode 100644 index 000000000000..7dc7eab58b38 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc.c | |||
@@ -0,0 +1,1274 @@ | |||
1 | /* | ||
2 | * Samsung S5P Multi Format Codec v 5.1 | ||
3 | * | ||
4 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
5 | * Kamil Debski, <k.debski@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 <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/version.h> | ||
22 | #include <linux/videodev2.h> | ||
23 | #include <linux/workqueue.h> | ||
24 | #include <media/videobuf2-core.h> | ||
25 | #include "regs-mfc.h" | ||
26 | #include "s5p_mfc_ctrl.h" | ||
27 | #include "s5p_mfc_debug.h" | ||
28 | #include "s5p_mfc_dec.h" | ||
29 | #include "s5p_mfc_enc.h" | ||
30 | #include "s5p_mfc_intr.h" | ||
31 | #include "s5p_mfc_opr.h" | ||
32 | #include "s5p_mfc_pm.h" | ||
33 | #include "s5p_mfc_shm.h" | ||
34 | |||
35 | #define S5P_MFC_NAME "s5p-mfc" | ||
36 | #define S5P_MFC_DEC_NAME "s5p-mfc-dec" | ||
37 | #define S5P_MFC_ENC_NAME "s5p-mfc-enc" | ||
38 | |||
39 | int debug; | ||
40 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
41 | MODULE_PARM_DESC(debug, "Debug level - higher value produces more verbose messages"); | ||
42 | |||
43 | /* Helper functions for interrupt processing */ | ||
44 | /* Remove from hw execution round robin */ | ||
45 | static void clear_work_bit(struct s5p_mfc_ctx *ctx) | ||
46 | { | ||
47 | struct s5p_mfc_dev *dev = ctx->dev; | ||
48 | |||
49 | spin_lock(&dev->condlock); | ||
50 | clear_bit(ctx->num, &dev->ctx_work_bits); | ||
51 | spin_unlock(&dev->condlock); | ||
52 | } | ||
53 | |||
54 | /* Wake up context wait_queue */ | ||
55 | static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason, | ||
56 | unsigned int err) | ||
57 | { | ||
58 | ctx->int_cond = 1; | ||
59 | ctx->int_type = reason; | ||
60 | ctx->int_err = err; | ||
61 | wake_up(&ctx->queue); | ||
62 | } | ||
63 | |||
64 | /* Wake up device wait_queue */ | ||
65 | static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason, | ||
66 | unsigned int err) | ||
67 | { | ||
68 | dev->int_cond = 1; | ||
69 | dev->int_type = reason; | ||
70 | dev->int_err = err; | ||
71 | wake_up(&dev->queue); | ||
72 | } | ||
73 | |||
74 | void s5p_mfc_watchdog(unsigned long arg) | ||
75 | { | ||
76 | struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg; | ||
77 | |||
78 | if (test_bit(0, &dev->hw_lock)) | ||
79 | atomic_inc(&dev->watchdog_cnt); | ||
80 | if (atomic_read(&dev->watchdog_cnt) >= MFC_WATCHDOG_CNT) { | ||
81 | /* This means that hw is busy and no interrupts were | ||
82 | * generated by hw for the Nth time of running this | ||
83 | * watchdog timer. This usually means a serious hw | ||
84 | * error. Now it is time to kill all instances and | ||
85 | * reset the MFC. */ | ||
86 | mfc_err("Time out during waiting for HW\n"); | ||
87 | queue_work(dev->watchdog_workqueue, &dev->watchdog_work); | ||
88 | } | ||
89 | dev->watchdog_timer.expires = jiffies + | ||
90 | msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); | ||
91 | add_timer(&dev->watchdog_timer); | ||
92 | } | ||
93 | |||
94 | static void s5p_mfc_watchdog_worker(struct work_struct *work) | ||
95 | { | ||
96 | struct s5p_mfc_dev *dev; | ||
97 | struct s5p_mfc_ctx *ctx; | ||
98 | unsigned long flags; | ||
99 | int mutex_locked; | ||
100 | int i, ret; | ||
101 | |||
102 | dev = container_of(work, struct s5p_mfc_dev, watchdog_work); | ||
103 | |||
104 | mfc_err("Driver timeout error handling\n"); | ||
105 | /* Lock the mutex that protects open and release. | ||
106 | * This is necessary as they may load and unload firmware. */ | ||
107 | mutex_locked = mutex_trylock(&dev->mfc_mutex); | ||
108 | if (!mutex_locked) | ||
109 | mfc_err("Error: some instance may be closing/opening\n"); | ||
110 | spin_lock_irqsave(&dev->irqlock, flags); | ||
111 | |||
112 | s5p_mfc_clock_off(); | ||
113 | |||
114 | for (i = 0; i < MFC_NUM_CONTEXTS; i++) { | ||
115 | ctx = dev->ctx[i]; | ||
116 | if (!ctx) | ||
117 | continue; | ||
118 | ctx->state = MFCINST_ERROR; | ||
119 | s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); | ||
120 | s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); | ||
121 | clear_work_bit(ctx); | ||
122 | wake_up_ctx(ctx, S5P_FIMV_R2H_CMD_ERR_RET, 0); | ||
123 | } | ||
124 | clear_bit(0, &dev->hw_lock); | ||
125 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
126 | /* Double check if there is at least one instance running. | ||
127 | * If no instance is in memory than no firmware should be present */ | ||
128 | if (dev->num_inst > 0) { | ||
129 | ret = s5p_mfc_reload_firmware(dev); | ||
130 | if (ret) { | ||
131 | mfc_err("Failed to reload FW\n"); | ||
132 | goto unlock; | ||
133 | } | ||
134 | s5p_mfc_clock_on(); | ||
135 | ret = s5p_mfc_init_hw(dev); | ||
136 | if (ret) | ||
137 | mfc_err("Failed to reinit FW\n"); | ||
138 | } | ||
139 | unlock: | ||
140 | if (mutex_locked) | ||
141 | mutex_unlock(&dev->mfc_mutex); | ||
142 | } | ||
143 | |||
144 | static enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file) | ||
145 | { | ||
146 | struct video_device *vdev = video_devdata(file); | ||
147 | |||
148 | if (!vdev) { | ||
149 | mfc_err("failed to get video_device"); | ||
150 | return MFCNODE_INVALID; | ||
151 | } | ||
152 | if (vdev->index == 0) | ||
153 | return MFCNODE_DECODER; | ||
154 | else if (vdev->index == 1) | ||
155 | return MFCNODE_ENCODER; | ||
156 | return MFCNODE_INVALID; | ||
157 | } | ||
158 | |||
159 | static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev) | ||
160 | { | ||
161 | mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT); | ||
162 | mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); | ||
163 | mfc_write(dev, 0xffff, S5P_FIMV_SI_RTN_CHID); | ||
164 | } | ||
165 | |||
166 | static void s5p_mfc_handle_frame_all_extracted(struct s5p_mfc_ctx *ctx) | ||
167 | { | ||
168 | struct s5p_mfc_buf *dst_buf; | ||
169 | |||
170 | ctx->state = MFCINST_FINISHED; | ||
171 | ctx->sequence++; | ||
172 | while (!list_empty(&ctx->dst_queue)) { | ||
173 | dst_buf = list_entry(ctx->dst_queue.next, | ||
174 | struct s5p_mfc_buf, list); | ||
175 | mfc_debug(2, "Cleaning up buffer: %d\n", | ||
176 | dst_buf->b->v4l2_buf.index); | ||
177 | vb2_set_plane_payload(dst_buf->b, 0, 0); | ||
178 | vb2_set_plane_payload(dst_buf->b, 1, 0); | ||
179 | list_del(&dst_buf->list); | ||
180 | ctx->dst_queue_cnt--; | ||
181 | dst_buf->b->v4l2_buf.sequence = (ctx->sequence++); | ||
182 | |||
183 | if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == | ||
184 | s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) | ||
185 | dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; | ||
186 | else | ||
187 | dst_buf->b->v4l2_buf.field = V4L2_FIELD_INTERLACED; | ||
188 | |||
189 | ctx->dec_dst_flag &= ~(1 << dst_buf->b->v4l2_buf.index); | ||
190 | vb2_buffer_done(dst_buf->b, VB2_BUF_STATE_DONE); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx) | ||
195 | { | ||
196 | struct s5p_mfc_dev *dev = ctx->dev; | ||
197 | struct s5p_mfc_buf *dst_buf, *src_buf; | ||
198 | size_t dec_y_addr = s5p_mfc_get_dec_y_adr(); | ||
199 | unsigned int frame_type = s5p_mfc_get_frame_type(); | ||
200 | |||
201 | /* Copy timestamp / timecode from decoded src to dst and set | ||
202 | appropraite flags */ | ||
203 | src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
204 | list_for_each_entry(dst_buf, &ctx->dst_queue, list) { | ||
205 | if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dec_y_addr) { | ||
206 | memcpy(&dst_buf->b->v4l2_buf.timecode, | ||
207 | &src_buf->b->v4l2_buf.timecode, | ||
208 | sizeof(struct v4l2_timecode)); | ||
209 | memcpy(&dst_buf->b->v4l2_buf.timestamp, | ||
210 | &src_buf->b->v4l2_buf.timestamp, | ||
211 | sizeof(struct timeval)); | ||
212 | switch (frame_type) { | ||
213 | case S5P_FIMV_DECODE_FRAME_I_FRAME: | ||
214 | dst_buf->b->v4l2_buf.flags |= | ||
215 | V4L2_BUF_FLAG_KEYFRAME; | ||
216 | break; | ||
217 | case S5P_FIMV_DECODE_FRAME_P_FRAME: | ||
218 | dst_buf->b->v4l2_buf.flags |= | ||
219 | V4L2_BUF_FLAG_PFRAME; | ||
220 | break; | ||
221 | case S5P_FIMV_DECODE_FRAME_B_FRAME: | ||
222 | dst_buf->b->v4l2_buf.flags |= | ||
223 | V4L2_BUF_FLAG_BFRAME; | ||
224 | break; | ||
225 | } | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | |||
231 | static void s5p_mfc_handle_frame_new(struct s5p_mfc_ctx *ctx, unsigned int err) | ||
232 | { | ||
233 | struct s5p_mfc_dev *dev = ctx->dev; | ||
234 | struct s5p_mfc_buf *dst_buf; | ||
235 | size_t dspl_y_addr = s5p_mfc_get_dspl_y_adr(); | ||
236 | unsigned int frame_type = s5p_mfc_get_frame_type(); | ||
237 | unsigned int index; | ||
238 | |||
239 | /* If frame is same as previous then skip and do not dequeue */ | ||
240 | if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED) { | ||
241 | if (!ctx->after_packed_pb) | ||
242 | ctx->sequence++; | ||
243 | ctx->after_packed_pb = 0; | ||
244 | return; | ||
245 | } | ||
246 | ctx->sequence++; | ||
247 | /* The MFC returns address of the buffer, now we have to | ||
248 | * check which videobuf does it correspond to */ | ||
249 | list_for_each_entry(dst_buf, &ctx->dst_queue, list) { | ||
250 | /* Check if this is the buffer we're looking for */ | ||
251 | if (vb2_dma_contig_plane_paddr(dst_buf->b, 0) == dspl_y_addr) { | ||
252 | list_del(&dst_buf->list); | ||
253 | ctx->dst_queue_cnt--; | ||
254 | dst_buf->b->v4l2_buf.sequence = ctx->sequence; | ||
255 | if (s5p_mfc_read_shm(ctx, PIC_TIME_TOP) == | ||
256 | s5p_mfc_read_shm(ctx, PIC_TIME_BOT)) | ||
257 | dst_buf->b->v4l2_buf.field = V4L2_FIELD_NONE; | ||
258 | else | ||
259 | dst_buf->b->v4l2_buf.field = | ||
260 | V4L2_FIELD_INTERLACED; | ||
261 | vb2_set_plane_payload(dst_buf->b, 0, ctx->luma_size); | ||
262 | vb2_set_plane_payload(dst_buf->b, 1, ctx->chroma_size); | ||
263 | clear_bit(dst_buf->b->v4l2_buf.index, | ||
264 | &ctx->dec_dst_flag); | ||
265 | |||
266 | vb2_buffer_done(dst_buf->b, | ||
267 | err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); | ||
268 | |||
269 | index = dst_buf->b->v4l2_buf.index; | ||
270 | break; | ||
271 | } | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* Handle frame decoding interrupt */ | ||
276 | static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, | ||
277 | unsigned int reason, unsigned int err) | ||
278 | { | ||
279 | struct s5p_mfc_dev *dev = ctx->dev; | ||
280 | unsigned int dst_frame_status; | ||
281 | struct s5p_mfc_buf *src_buf; | ||
282 | unsigned long flags; | ||
283 | unsigned int res_change; | ||
284 | |||
285 | unsigned int index; | ||
286 | |||
287 | dst_frame_status = s5p_mfc_get_dspl_status() | ||
288 | & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK; | ||
289 | res_change = s5p_mfc_get_dspl_status() | ||
290 | & S5P_FIMV_DEC_STATUS_RESOLUTION_MASK; | ||
291 | mfc_debug(2, "Frame Status: %x\n", dst_frame_status); | ||
292 | if (ctx->state == MFCINST_RES_CHANGE_INIT) | ||
293 | ctx->state = MFCINST_RES_CHANGE_FLUSH; | ||
294 | if (res_change) { | ||
295 | ctx->state = MFCINST_RES_CHANGE_INIT; | ||
296 | s5p_mfc_clear_int_flags(dev); | ||
297 | wake_up_ctx(ctx, reason, err); | ||
298 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
299 | BUG(); | ||
300 | s5p_mfc_clock_off(); | ||
301 | s5p_mfc_try_run(dev); | ||
302 | return; | ||
303 | } | ||
304 | if (ctx->dpb_flush_flag) | ||
305 | ctx->dpb_flush_flag = 0; | ||
306 | |||
307 | spin_lock_irqsave(&dev->irqlock, flags); | ||
308 | /* All frames remaining in the buffer have been extracted */ | ||
309 | if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) { | ||
310 | if (ctx->state == MFCINST_RES_CHANGE_FLUSH) { | ||
311 | s5p_mfc_handle_frame_all_extracted(ctx); | ||
312 | ctx->state = MFCINST_RES_CHANGE_END; | ||
313 | goto leave_handle_frame; | ||
314 | } else { | ||
315 | s5p_mfc_handle_frame_all_extracted(ctx); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY || | ||
320 | dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY) | ||
321 | s5p_mfc_handle_frame_copy_time(ctx); | ||
322 | |||
323 | /* A frame has been decoded and is in the buffer */ | ||
324 | if (dst_frame_status == S5P_FIMV_DEC_STATUS_DISPLAY_ONLY || | ||
325 | dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY) { | ||
326 | s5p_mfc_handle_frame_new(ctx, err); | ||
327 | } else { | ||
328 | mfc_debug(2, "No frame decode\n"); | ||
329 | } | ||
330 | /* Mark source buffer as complete */ | ||
331 | if (dst_frame_status != S5P_FIMV_DEC_STATUS_DISPLAY_ONLY | ||
332 | && !list_empty(&ctx->src_queue)) { | ||
333 | src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, | ||
334 | list); | ||
335 | ctx->consumed_stream += s5p_mfc_get_consumed_stream(); | ||
336 | if (ctx->codec_mode != S5P_FIMV_CODEC_H264_DEC && | ||
337 | s5p_mfc_get_frame_type() == S5P_FIMV_DECODE_FRAME_P_FRAME | ||
338 | && ctx->consumed_stream + STUFF_BYTE < | ||
339 | src_buf->b->v4l2_planes[0].bytesused) { | ||
340 | /* Run MFC again on the same buffer */ | ||
341 | mfc_debug(2, "Running again the same buffer\n"); | ||
342 | ctx->after_packed_pb = 1; | ||
343 | } else { | ||
344 | index = src_buf->b->v4l2_buf.index; | ||
345 | mfc_debug(2, "MFC needs next buffer\n"); | ||
346 | ctx->consumed_stream = 0; | ||
347 | list_del(&src_buf->list); | ||
348 | ctx->src_queue_cnt--; | ||
349 | if (s5p_mfc_err_dec(err) > 0) | ||
350 | vb2_buffer_done(src_buf->b, VB2_BUF_STATE_ERROR); | ||
351 | else | ||
352 | vb2_buffer_done(src_buf->b, VB2_BUF_STATE_DONE); | ||
353 | } | ||
354 | } | ||
355 | leave_handle_frame: | ||
356 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
357 | if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING) | ||
358 | || ctx->dst_queue_cnt < ctx->dpb_count) | ||
359 | clear_work_bit(ctx); | ||
360 | s5p_mfc_clear_int_flags(dev); | ||
361 | wake_up_ctx(ctx, reason, err); | ||
362 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
363 | BUG(); | ||
364 | s5p_mfc_clock_off(); | ||
365 | s5p_mfc_try_run(dev); | ||
366 | } | ||
367 | |||
368 | /* Error handling for interrupt */ | ||
369 | static void s5p_mfc_handle_error(struct s5p_mfc_ctx *ctx, | ||
370 | unsigned int reason, unsigned int err) | ||
371 | { | ||
372 | struct s5p_mfc_dev *dev; | ||
373 | unsigned long flags; | ||
374 | |||
375 | /* If no context is available then all necessary | ||
376 | * processing has been done. */ | ||
377 | if (ctx == 0) | ||
378 | return; | ||
379 | |||
380 | dev = ctx->dev; | ||
381 | mfc_err("Interrupt Error: %08x\n", err); | ||
382 | s5p_mfc_clear_int_flags(dev); | ||
383 | wake_up_dev(dev, reason, err); | ||
384 | |||
385 | /* Error recovery is dependent on the state of context */ | ||
386 | switch (ctx->state) { | ||
387 | case MFCINST_INIT: | ||
388 | /* This error had to happen while acquireing instance */ | ||
389 | case MFCINST_GOT_INST: | ||
390 | /* This error had to happen while parsing the header */ | ||
391 | case MFCINST_HEAD_PARSED: | ||
392 | /* This error had to happen while setting dst buffers */ | ||
393 | case MFCINST_RETURN_INST: | ||
394 | /* This error had to happen while releasing instance */ | ||
395 | clear_work_bit(ctx); | ||
396 | wake_up_ctx(ctx, reason, err); | ||
397 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
398 | BUG(); | ||
399 | s5p_mfc_clock_off(); | ||
400 | ctx->state = MFCINST_ERROR; | ||
401 | break; | ||
402 | case MFCINST_FINISHING: | ||
403 | case MFCINST_FINISHED: | ||
404 | case MFCINST_RUNNING: | ||
405 | /* It is higly probable that an error occured | ||
406 | * while decoding a frame */ | ||
407 | clear_work_bit(ctx); | ||
408 | ctx->state = MFCINST_ERROR; | ||
409 | /* Mark all dst buffers as having an error */ | ||
410 | spin_lock_irqsave(&dev->irqlock, flags); | ||
411 | s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); | ||
412 | /* Mark all src buffers as having an error */ | ||
413 | s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); | ||
414 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
415 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
416 | BUG(); | ||
417 | s5p_mfc_clock_off(); | ||
418 | break; | ||
419 | default: | ||
420 | mfc_err("Encountered an error interrupt which had not been handled\n"); | ||
421 | break; | ||
422 | } | ||
423 | return; | ||
424 | } | ||
425 | |||
426 | /* Header parsing interrupt handling */ | ||
427 | static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, | ||
428 | unsigned int reason, unsigned int err) | ||
429 | { | ||
430 | struct s5p_mfc_dev *dev; | ||
431 | unsigned int guard_width, guard_height; | ||
432 | |||
433 | if (ctx == 0) | ||
434 | return; | ||
435 | dev = ctx->dev; | ||
436 | if (ctx->c_ops->post_seq_start) { | ||
437 | if (ctx->c_ops->post_seq_start(ctx)) | ||
438 | mfc_err("post_seq_start() failed\n"); | ||
439 | } else { | ||
440 | ctx->img_width = s5p_mfc_get_img_width(); | ||
441 | ctx->img_height = s5p_mfc_get_img_height(); | ||
442 | |||
443 | ctx->buf_width = ALIGN(ctx->img_width, | ||
444 | S5P_FIMV_NV12MT_HALIGN); | ||
445 | ctx->buf_height = ALIGN(ctx->img_height, | ||
446 | S5P_FIMV_NV12MT_VALIGN); | ||
447 | mfc_debug(2, "SEQ Done: Movie dimensions %dx%d, " | ||
448 | "buffer dimensions: %dx%d\n", ctx->img_width, | ||
449 | ctx->img_height, ctx->buf_width, | ||
450 | ctx->buf_height); | ||
451 | if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { | ||
452 | ctx->luma_size = ALIGN(ctx->buf_width * | ||
453 | ctx->buf_height, S5P_FIMV_DEC_BUF_ALIGN); | ||
454 | ctx->chroma_size = ALIGN(ctx->buf_width * | ||
455 | ALIGN((ctx->img_height >> 1), | ||
456 | S5P_FIMV_NV12MT_VALIGN), | ||
457 | S5P_FIMV_DEC_BUF_ALIGN); | ||
458 | ctx->mv_size = ALIGN(ctx->buf_width * | ||
459 | ALIGN((ctx->buf_height >> 2), | ||
460 | S5P_FIMV_NV12MT_VALIGN), | ||
461 | S5P_FIMV_DEC_BUF_ALIGN); | ||
462 | } else { | ||
463 | guard_width = ALIGN(ctx->img_width + 24, | ||
464 | S5P_FIMV_NV12MT_HALIGN); | ||
465 | guard_height = ALIGN(ctx->img_height + 16, | ||
466 | S5P_FIMV_NV12MT_VALIGN); | ||
467 | ctx->luma_size = ALIGN(guard_width * | ||
468 | guard_height, S5P_FIMV_DEC_BUF_ALIGN); | ||
469 | guard_width = ALIGN(ctx->img_width + 16, | ||
470 | S5P_FIMV_NV12MT_HALIGN); | ||
471 | guard_height = ALIGN((ctx->img_height >> 1) + 4, | ||
472 | S5P_FIMV_NV12MT_VALIGN); | ||
473 | ctx->chroma_size = ALIGN(guard_width * | ||
474 | guard_height, S5P_FIMV_DEC_BUF_ALIGN); | ||
475 | ctx->mv_size = 0; | ||
476 | } | ||
477 | ctx->dpb_count = s5p_mfc_get_dpb_count(); | ||
478 | if (ctx->img_width == 0 || ctx->img_width == 0) | ||
479 | ctx->state = MFCINST_ERROR; | ||
480 | else | ||
481 | ctx->state = MFCINST_HEAD_PARSED; | ||
482 | } | ||
483 | s5p_mfc_clear_int_flags(dev); | ||
484 | clear_work_bit(ctx); | ||
485 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
486 | BUG(); | ||
487 | s5p_mfc_clock_off(); | ||
488 | s5p_mfc_try_run(dev); | ||
489 | wake_up_ctx(ctx, reason, err); | ||
490 | } | ||
491 | |||
492 | /* Header parsing interrupt handling */ | ||
493 | static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, | ||
494 | unsigned int reason, unsigned int err) | ||
495 | { | ||
496 | struct s5p_mfc_buf *src_buf; | ||
497 | struct s5p_mfc_dev *dev; | ||
498 | unsigned long flags; | ||
499 | |||
500 | if (ctx == 0) | ||
501 | return; | ||
502 | dev = ctx->dev; | ||
503 | s5p_mfc_clear_int_flags(dev); | ||
504 | ctx->int_type = reason; | ||
505 | ctx->int_err = err; | ||
506 | ctx->int_cond = 1; | ||
507 | spin_lock(&dev->condlock); | ||
508 | clear_bit(ctx->num, &dev->ctx_work_bits); | ||
509 | spin_unlock(&dev->condlock); | ||
510 | if (err == 0) { | ||
511 | ctx->state = MFCINST_RUNNING; | ||
512 | if (!ctx->dpb_flush_flag) { | ||
513 | spin_lock_irqsave(&dev->irqlock, flags); | ||
514 | if (!list_empty(&ctx->src_queue)) { | ||
515 | src_buf = list_entry(ctx->src_queue.next, | ||
516 | struct s5p_mfc_buf, list); | ||
517 | list_del(&src_buf->list); | ||
518 | ctx->src_queue_cnt--; | ||
519 | vb2_buffer_done(src_buf->b, | ||
520 | VB2_BUF_STATE_DONE); | ||
521 | } | ||
522 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
523 | } else { | ||
524 | ctx->dpb_flush_flag = 0; | ||
525 | } | ||
526 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
527 | BUG(); | ||
528 | |||
529 | s5p_mfc_clock_off(); | ||
530 | |||
531 | wake_up(&ctx->queue); | ||
532 | s5p_mfc_try_run(dev); | ||
533 | } else { | ||
534 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
535 | BUG(); | ||
536 | |||
537 | s5p_mfc_clock_off(); | ||
538 | |||
539 | wake_up(&ctx->queue); | ||
540 | } | ||
541 | } | ||
542 | |||
543 | /* Interrupt processing */ | ||
544 | static irqreturn_t s5p_mfc_irq(int irq, void *priv) | ||
545 | { | ||
546 | struct s5p_mfc_dev *dev = priv; | ||
547 | struct s5p_mfc_ctx *ctx; | ||
548 | unsigned int reason; | ||
549 | unsigned int err; | ||
550 | |||
551 | mfc_debug_enter(); | ||
552 | /* Reset the timeout watchdog */ | ||
553 | atomic_set(&dev->watchdog_cnt, 0); | ||
554 | ctx = dev->ctx[dev->curr_ctx]; | ||
555 | /* Get the reason of interrupt and the error code */ | ||
556 | reason = s5p_mfc_get_int_reason(); | ||
557 | err = s5p_mfc_get_int_err(); | ||
558 | mfc_debug(1, "Int reason: %d (err: %08x)\n", reason, err); | ||
559 | switch (reason) { | ||
560 | case S5P_FIMV_R2H_CMD_ERR_RET: | ||
561 | /* An error has occured */ | ||
562 | if (ctx->state == MFCINST_RUNNING && | ||
563 | s5p_mfc_err_dec(err) >= S5P_FIMV_ERR_WARNINGS_START) | ||
564 | s5p_mfc_handle_frame(ctx, reason, err); | ||
565 | else | ||
566 | s5p_mfc_handle_error(ctx, reason, err); | ||
567 | clear_bit(0, &dev->enter_suspend); | ||
568 | break; | ||
569 | |||
570 | case S5P_FIMV_R2H_CMD_SLICE_DONE_RET: | ||
571 | case S5P_FIMV_R2H_CMD_FRAME_DONE_RET: | ||
572 | if (ctx->c_ops->post_frame_start) { | ||
573 | if (ctx->c_ops->post_frame_start(ctx)) | ||
574 | mfc_err("post_frame_start() failed\n"); | ||
575 | s5p_mfc_clear_int_flags(dev); | ||
576 | wake_up_ctx(ctx, reason, err); | ||
577 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
578 | BUG(); | ||
579 | s5p_mfc_clock_off(); | ||
580 | s5p_mfc_try_run(dev); | ||
581 | } else { | ||
582 | s5p_mfc_handle_frame(ctx, reason, err); | ||
583 | } | ||
584 | break; | ||
585 | |||
586 | case S5P_FIMV_R2H_CMD_SEQ_DONE_RET: | ||
587 | s5p_mfc_handle_seq_done(ctx, reason, err); | ||
588 | break; | ||
589 | |||
590 | case S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET: | ||
591 | ctx->inst_no = s5p_mfc_get_inst_no(); | ||
592 | ctx->state = MFCINST_GOT_INST; | ||
593 | clear_work_bit(ctx); | ||
594 | wake_up(&ctx->queue); | ||
595 | goto irq_cleanup_hw; | ||
596 | |||
597 | case S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET: | ||
598 | clear_work_bit(ctx); | ||
599 | ctx->state = MFCINST_FREE; | ||
600 | wake_up(&ctx->queue); | ||
601 | goto irq_cleanup_hw; | ||
602 | |||
603 | case S5P_FIMV_R2H_CMD_SYS_INIT_RET: | ||
604 | case S5P_FIMV_R2H_CMD_FW_STATUS_RET: | ||
605 | case S5P_FIMV_R2H_CMD_SLEEP_RET: | ||
606 | case S5P_FIMV_R2H_CMD_WAKEUP_RET: | ||
607 | if (ctx) | ||
608 | clear_work_bit(ctx); | ||
609 | s5p_mfc_clear_int_flags(dev); | ||
610 | wake_up_dev(dev, reason, err); | ||
611 | clear_bit(0, &dev->hw_lock); | ||
612 | clear_bit(0, &dev->enter_suspend); | ||
613 | break; | ||
614 | |||
615 | case S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET: | ||
616 | s5p_mfc_handle_init_buffers(ctx, reason, err); | ||
617 | break; | ||
618 | default: | ||
619 | mfc_debug(2, "Unknown int reason\n"); | ||
620 | s5p_mfc_clear_int_flags(dev); | ||
621 | } | ||
622 | mfc_debug_leave(); | ||
623 | return IRQ_HANDLED; | ||
624 | irq_cleanup_hw: | ||
625 | s5p_mfc_clear_int_flags(dev); | ||
626 | ctx->int_type = reason; | ||
627 | ctx->int_err = err; | ||
628 | ctx->int_cond = 1; | ||
629 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
630 | mfc_err("Failed to unlock hw\n"); | ||
631 | |||
632 | s5p_mfc_clock_off(); | ||
633 | |||
634 | s5p_mfc_try_run(dev); | ||
635 | mfc_debug(2, "Exit via irq_cleanup_hw\n"); | ||
636 | return IRQ_HANDLED; | ||
637 | } | ||
638 | |||
639 | /* Open an MFC node */ | ||
640 | static int s5p_mfc_open(struct file *file) | ||
641 | { | ||
642 | struct s5p_mfc_dev *dev = video_drvdata(file); | ||
643 | struct s5p_mfc_ctx *ctx = NULL; | ||
644 | struct vb2_queue *q; | ||
645 | unsigned long flags; | ||
646 | int ret = 0; | ||
647 | |||
648 | mfc_debug_enter(); | ||
649 | dev->num_inst++; /* It is guarded by mfc_mutex in vfd */ | ||
650 | /* Allocate memory for context */ | ||
651 | ctx = kzalloc(sizeof *ctx, GFP_KERNEL); | ||
652 | if (!ctx) { | ||
653 | mfc_err("Not enough memory\n"); | ||
654 | ret = -ENOMEM; | ||
655 | goto err_alloc; | ||
656 | } | ||
657 | v4l2_fh_init(&ctx->fh, video_devdata(file)); | ||
658 | file->private_data = &ctx->fh; | ||
659 | v4l2_fh_add(&ctx->fh); | ||
660 | ctx->dev = dev; | ||
661 | INIT_LIST_HEAD(&ctx->src_queue); | ||
662 | INIT_LIST_HEAD(&ctx->dst_queue); | ||
663 | ctx->src_queue_cnt = 0; | ||
664 | ctx->dst_queue_cnt = 0; | ||
665 | /* Get context number */ | ||
666 | ctx->num = 0; | ||
667 | while (dev->ctx[ctx->num]) { | ||
668 | ctx->num++; | ||
669 | if (ctx->num >= MFC_NUM_CONTEXTS) { | ||
670 | mfc_err("Too many open contexts\n"); | ||
671 | ret = -EBUSY; | ||
672 | goto err_no_ctx; | ||
673 | } | ||
674 | } | ||
675 | /* Mark context as idle */ | ||
676 | spin_lock_irqsave(&dev->condlock, flags); | ||
677 | clear_bit(ctx->num, &dev->ctx_work_bits); | ||
678 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
679 | dev->ctx[ctx->num] = ctx; | ||
680 | if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { | ||
681 | ctx->type = MFCINST_DECODER; | ||
682 | ctx->c_ops = get_dec_codec_ops(); | ||
683 | /* Setup ctrl handler */ | ||
684 | ret = s5p_mfc_dec_ctrls_setup(ctx); | ||
685 | if (ret) { | ||
686 | mfc_err("Failed to setup mfc controls\n"); | ||
687 | goto err_ctrls_setup; | ||
688 | } | ||
689 | } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { | ||
690 | ctx->type = MFCINST_ENCODER; | ||
691 | ctx->c_ops = get_enc_codec_ops(); | ||
692 | /* only for encoder */ | ||
693 | INIT_LIST_HEAD(&ctx->ref_queue); | ||
694 | ctx->ref_queue_cnt = 0; | ||
695 | /* Setup ctrl handler */ | ||
696 | ret = s5p_mfc_enc_ctrls_setup(ctx); | ||
697 | if (ret) { | ||
698 | mfc_err("Failed to setup mfc controls\n"); | ||
699 | goto err_ctrls_setup; | ||
700 | } | ||
701 | } else { | ||
702 | ret = -ENOENT; | ||
703 | goto err_bad_node; | ||
704 | } | ||
705 | ctx->fh.ctrl_handler = &ctx->ctrl_handler; | ||
706 | ctx->inst_no = -1; | ||
707 | /* Load firmware if this is the first instance */ | ||
708 | if (dev->num_inst == 1) { | ||
709 | dev->watchdog_timer.expires = jiffies + | ||
710 | msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); | ||
711 | add_timer(&dev->watchdog_timer); | ||
712 | ret = s5p_mfc_power_on(); | ||
713 | if (ret < 0) { | ||
714 | mfc_err("power on failed\n"); | ||
715 | goto err_pwr_enable; | ||
716 | } | ||
717 | s5p_mfc_clock_on(); | ||
718 | ret = s5p_mfc_alloc_and_load_firmware(dev); | ||
719 | if (ret) | ||
720 | goto err_alloc_fw; | ||
721 | /* Init the FW */ | ||
722 | ret = s5p_mfc_init_hw(dev); | ||
723 | if (ret) | ||
724 | goto err_init_hw; | ||
725 | s5p_mfc_clock_off(); | ||
726 | } | ||
727 | /* Init videobuf2 queue for CAPTURE */ | ||
728 | q = &ctx->vq_dst; | ||
729 | q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | ||
730 | q->drv_priv = &ctx->fh; | ||
731 | if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { | ||
732 | q->io_modes = VB2_MMAP; | ||
733 | q->ops = get_dec_queue_ops(); | ||
734 | } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { | ||
735 | q->io_modes = VB2_MMAP | VB2_USERPTR; | ||
736 | q->ops = get_enc_queue_ops(); | ||
737 | } else { | ||
738 | ret = -ENOENT; | ||
739 | goto err_queue_init; | ||
740 | } | ||
741 | q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; | ||
742 | ret = vb2_queue_init(q); | ||
743 | if (ret) { | ||
744 | mfc_err("Failed to initialize videobuf2 queue(capture)\n"); | ||
745 | goto err_queue_init; | ||
746 | } | ||
747 | /* Init videobuf2 queue for OUTPUT */ | ||
748 | q = &ctx->vq_src; | ||
749 | q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | ||
750 | q->io_modes = VB2_MMAP; | ||
751 | q->drv_priv = &ctx->fh; | ||
752 | if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) { | ||
753 | q->io_modes = VB2_MMAP; | ||
754 | q->ops = get_dec_queue_ops(); | ||
755 | } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) { | ||
756 | q->io_modes = VB2_MMAP | VB2_USERPTR; | ||
757 | q->ops = get_enc_queue_ops(); | ||
758 | } else { | ||
759 | ret = -ENOENT; | ||
760 | goto err_queue_init; | ||
761 | } | ||
762 | q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops; | ||
763 | ret = vb2_queue_init(q); | ||
764 | if (ret) { | ||
765 | mfc_err("Failed to initialize videobuf2 queue(output)\n"); | ||
766 | goto err_queue_init; | ||
767 | } | ||
768 | init_waitqueue_head(&ctx->queue); | ||
769 | mfc_debug_leave(); | ||
770 | return ret; | ||
771 | /* Deinit when failure occured */ | ||
772 | err_queue_init: | ||
773 | err_init_hw: | ||
774 | s5p_mfc_release_firmware(dev); | ||
775 | err_alloc_fw: | ||
776 | dev->ctx[ctx->num] = 0; | ||
777 | del_timer_sync(&dev->watchdog_timer); | ||
778 | s5p_mfc_clock_off(); | ||
779 | err_pwr_enable: | ||
780 | if (dev->num_inst == 1) { | ||
781 | if (s5p_mfc_power_off() < 0) | ||
782 | mfc_err("power off failed\n"); | ||
783 | s5p_mfc_release_firmware(dev); | ||
784 | } | ||
785 | err_ctrls_setup: | ||
786 | s5p_mfc_dec_ctrls_delete(ctx); | ||
787 | err_bad_node: | ||
788 | err_no_ctx: | ||
789 | v4l2_fh_del(&ctx->fh); | ||
790 | v4l2_fh_exit(&ctx->fh); | ||
791 | kfree(ctx); | ||
792 | err_alloc: | ||
793 | dev->num_inst--; | ||
794 | mfc_debug_leave(); | ||
795 | return ret; | ||
796 | } | ||
797 | |||
798 | /* Release MFC context */ | ||
799 | static int s5p_mfc_release(struct file *file) | ||
800 | { | ||
801 | struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); | ||
802 | struct s5p_mfc_dev *dev = ctx->dev; | ||
803 | unsigned long flags; | ||
804 | |||
805 | mfc_debug_enter(); | ||
806 | s5p_mfc_clock_on(); | ||
807 | vb2_queue_release(&ctx->vq_src); | ||
808 | vb2_queue_release(&ctx->vq_dst); | ||
809 | /* Mark context as idle */ | ||
810 | spin_lock_irqsave(&dev->condlock, flags); | ||
811 | clear_bit(ctx->num, &dev->ctx_work_bits); | ||
812 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
813 | /* If instance was initialised then | ||
814 | * return instance and free reosurces */ | ||
815 | if (ctx->inst_no != MFC_NO_INSTANCE_SET) { | ||
816 | mfc_debug(2, "Has to free instance\n"); | ||
817 | ctx->state = MFCINST_RETURN_INST; | ||
818 | spin_lock_irqsave(&dev->condlock, flags); | ||
819 | set_bit(ctx->num, &dev->ctx_work_bits); | ||
820 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
821 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
822 | s5p_mfc_try_run(dev); | ||
823 | /* Wait until instance is returned or timeout occured */ | ||
824 | if (s5p_mfc_wait_for_done_ctx | ||
825 | (ctx, S5P_FIMV_R2H_CMD_CLOSE_INSTANCE_RET, 0)) { | ||
826 | s5p_mfc_clock_off(); | ||
827 | mfc_err("Err returning instance\n"); | ||
828 | } | ||
829 | mfc_debug(2, "After free instance\n"); | ||
830 | /* Free resources */ | ||
831 | s5p_mfc_release_codec_buffers(ctx); | ||
832 | s5p_mfc_release_instance_buffer(ctx); | ||
833 | if (ctx->type == MFCINST_DECODER) | ||
834 | s5p_mfc_release_dec_desc_buffer(ctx); | ||
835 | |||
836 | ctx->inst_no = MFC_NO_INSTANCE_SET; | ||
837 | } | ||
838 | /* hardware locking scheme */ | ||
839 | if (dev->curr_ctx == ctx->num) | ||
840 | clear_bit(0, &dev->hw_lock); | ||
841 | dev->num_inst--; | ||
842 | if (dev->num_inst == 0) { | ||
843 | mfc_debug(2, "Last instance - release firmware\n"); | ||
844 | /* reset <-> F/W release */ | ||
845 | s5p_mfc_reset(dev); | ||
846 | s5p_mfc_release_firmware(dev); | ||
847 | del_timer_sync(&dev->watchdog_timer); | ||
848 | if (s5p_mfc_power_off() < 0) | ||
849 | mfc_err("Power off failed\n"); | ||
850 | } | ||
851 | mfc_debug(2, "Shutting down clock\n"); | ||
852 | s5p_mfc_clock_off(); | ||
853 | dev->ctx[ctx->num] = 0; | ||
854 | s5p_mfc_dec_ctrls_delete(ctx); | ||
855 | v4l2_fh_del(&ctx->fh); | ||
856 | v4l2_fh_exit(&ctx->fh); | ||
857 | kfree(ctx); | ||
858 | mfc_debug_leave(); | ||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | /* Poll */ | ||
863 | static unsigned int s5p_mfc_poll(struct file *file, | ||
864 | struct poll_table_struct *wait) | ||
865 | { | ||
866 | struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); | ||
867 | struct s5p_mfc_dev *dev = ctx->dev; | ||
868 | struct vb2_queue *src_q, *dst_q; | ||
869 | struct vb2_buffer *src_vb = NULL, *dst_vb = NULL; | ||
870 | unsigned int rc = 0; | ||
871 | unsigned long flags; | ||
872 | |||
873 | src_q = &ctx->vq_src; | ||
874 | dst_q = &ctx->vq_dst; | ||
875 | /* | ||
876 | * There has to be at least one buffer queued on each queued_list, which | ||
877 | * means either in driver already or waiting for driver to claim it | ||
878 | * and start processing. | ||
879 | */ | ||
880 | if ((!src_q->streaming || list_empty(&src_q->queued_list)) | ||
881 | && (!dst_q->streaming || list_empty(&dst_q->queued_list))) { | ||
882 | rc = POLLERR; | ||
883 | goto end; | ||
884 | } | ||
885 | mutex_unlock(&dev->mfc_mutex); | ||
886 | poll_wait(file, &src_q->done_wq, wait); | ||
887 | poll_wait(file, &dst_q->done_wq, wait); | ||
888 | mutex_lock(&dev->mfc_mutex); | ||
889 | spin_lock_irqsave(&src_q->done_lock, flags); | ||
890 | if (!list_empty(&src_q->done_list)) | ||
891 | src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer, | ||
892 | done_entry); | ||
893 | if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE | ||
894 | || src_vb->state == VB2_BUF_STATE_ERROR)) | ||
895 | rc |= POLLOUT | POLLWRNORM; | ||
896 | spin_unlock_irqrestore(&src_q->done_lock, flags); | ||
897 | spin_lock_irqsave(&dst_q->done_lock, flags); | ||
898 | if (!list_empty(&dst_q->done_list)) | ||
899 | dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer, | ||
900 | done_entry); | ||
901 | if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE | ||
902 | || dst_vb->state == VB2_BUF_STATE_ERROR)) | ||
903 | rc |= POLLIN | POLLRDNORM; | ||
904 | spin_unlock_irqrestore(&dst_q->done_lock, flags); | ||
905 | end: | ||
906 | return rc; | ||
907 | } | ||
908 | |||
909 | /* Mmap */ | ||
910 | static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) | ||
911 | { | ||
912 | struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); | ||
913 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | ||
914 | int ret; | ||
915 | if (offset < DST_QUEUE_OFF_BASE) { | ||
916 | mfc_debug(2, "mmaping source\n"); | ||
917 | ret = vb2_mmap(&ctx->vq_src, vma); | ||
918 | } else { /* capture */ | ||
919 | mfc_debug(2, "mmaping destination\n"); | ||
920 | vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); | ||
921 | ret = vb2_mmap(&ctx->vq_dst, vma); | ||
922 | } | ||
923 | return ret; | ||
924 | } | ||
925 | |||
926 | /* v4l2 ops */ | ||
927 | static const struct v4l2_file_operations s5p_mfc_fops = { | ||
928 | .owner = THIS_MODULE, | ||
929 | .open = s5p_mfc_open, | ||
930 | .release = s5p_mfc_release, | ||
931 | .poll = s5p_mfc_poll, | ||
932 | .unlocked_ioctl = video_ioctl2, | ||
933 | .mmap = s5p_mfc_mmap, | ||
934 | }; | ||
935 | |||
936 | static int match_child(struct device *dev, void *data) | ||
937 | { | ||
938 | if (!dev_name(dev)) | ||
939 | return 0; | ||
940 | return !strcmp(dev_name(dev), (char *)data); | ||
941 | } | ||
942 | |||
943 | |||
944 | /* MFC probe function */ | ||
945 | static int __devinit s5p_mfc_probe(struct platform_device *pdev) | ||
946 | { | ||
947 | struct s5p_mfc_dev *dev; | ||
948 | struct video_device *vfd; | ||
949 | struct resource *res; | ||
950 | int ret; | ||
951 | |||
952 | pr_debug("%s++\n", __func__); | ||
953 | dev = kzalloc(sizeof *dev, GFP_KERNEL); | ||
954 | if (!dev) { | ||
955 | dev_err(&pdev->dev, "Not enough memory for MFC device\n"); | ||
956 | return -ENOMEM; | ||
957 | } | ||
958 | |||
959 | spin_lock_init(&dev->irqlock); | ||
960 | spin_lock_init(&dev->condlock); | ||
961 | dev->plat_dev = pdev; | ||
962 | if (!dev->plat_dev) { | ||
963 | dev_err(&pdev->dev, "No platform data specified\n"); | ||
964 | ret = -ENODEV; | ||
965 | goto err_dev; | ||
966 | } | ||
967 | |||
968 | ret = s5p_mfc_init_pm(dev); | ||
969 | if (ret < 0) { | ||
970 | dev_err(&pdev->dev, "failed to get mfc clock source\n"); | ||
971 | goto err_clk; | ||
972 | } | ||
973 | |||
974 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
975 | if (res == NULL) { | ||
976 | dev_err(&pdev->dev, "failed to get memory region resource\n"); | ||
977 | ret = -ENOENT; | ||
978 | goto err_res; | ||
979 | } | ||
980 | |||
981 | dev->mfc_mem = request_mem_region(res->start, resource_size(res), | ||
982 | pdev->name); | ||
983 | if (dev->mfc_mem == NULL) { | ||
984 | dev_err(&pdev->dev, "failed to get memory region\n"); | ||
985 | ret = -ENOENT; | ||
986 | goto err_mem_reg; | ||
987 | } | ||
988 | dev->regs_base = ioremap(dev->mfc_mem->start, resource_size(dev->mfc_mem)); | ||
989 | if (dev->regs_base == NULL) { | ||
990 | dev_err(&pdev->dev, "failed to ioremap address region\n"); | ||
991 | ret = -ENOENT; | ||
992 | goto err_ioremap; | ||
993 | } | ||
994 | |||
995 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
996 | if (res == NULL) { | ||
997 | dev_err(&pdev->dev, "failed to get irq resource\n"); | ||
998 | ret = -ENOENT; | ||
999 | goto err_get_res; | ||
1000 | } | ||
1001 | dev->irq = res->start; | ||
1002 | ret = request_irq(dev->irq, s5p_mfc_irq, IRQF_DISABLED, pdev->name, | ||
1003 | dev); | ||
1004 | if (ret) { | ||
1005 | dev_err(&pdev->dev, "Failed to install irq (%d)\n", ret); | ||
1006 | goto err_req_irq; | ||
1007 | } | ||
1008 | |||
1009 | dev->mem_dev_l = device_find_child(&dev->plat_dev->dev, "s5p-mfc-l", | ||
1010 | match_child); | ||
1011 | if (!dev->mem_dev_l) { | ||
1012 | mfc_err("Mem child (L) device get failed\n"); | ||
1013 | ret = -ENODEV; | ||
1014 | goto err_find_child; | ||
1015 | } | ||
1016 | dev->mem_dev_r = device_find_child(&dev->plat_dev->dev, "s5p-mfc-r", | ||
1017 | match_child); | ||
1018 | if (!dev->mem_dev_r) { | ||
1019 | mfc_err("Mem child (R) device get failed\n"); | ||
1020 | ret = -ENODEV; | ||
1021 | goto err_find_child; | ||
1022 | } | ||
1023 | |||
1024 | dev->alloc_ctx[0] = vb2_dma_contig_init_ctx(dev->mem_dev_l); | ||
1025 | if (IS_ERR_OR_NULL(dev->alloc_ctx[0])) { | ||
1026 | ret = PTR_ERR(dev->alloc_ctx[0]); | ||
1027 | goto err_mem_init_ctx_0; | ||
1028 | } | ||
1029 | dev->alloc_ctx[1] = vb2_dma_contig_init_ctx(dev->mem_dev_r); | ||
1030 | if (IS_ERR_OR_NULL(dev->alloc_ctx[1])) { | ||
1031 | ret = PTR_ERR(dev->alloc_ctx[1]); | ||
1032 | goto err_mem_init_ctx_1; | ||
1033 | } | ||
1034 | |||
1035 | mutex_init(&dev->mfc_mutex); | ||
1036 | |||
1037 | ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); | ||
1038 | if (ret) | ||
1039 | goto err_v4l2_dev_reg; | ||
1040 | init_waitqueue_head(&dev->queue); | ||
1041 | |||
1042 | /* decoder */ | ||
1043 | vfd = video_device_alloc(); | ||
1044 | if (!vfd) { | ||
1045 | v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); | ||
1046 | ret = -ENOMEM; | ||
1047 | goto err_dec_alloc; | ||
1048 | } | ||
1049 | vfd->fops = &s5p_mfc_fops, | ||
1050 | vfd->ioctl_ops = get_dec_v4l2_ioctl_ops(); | ||
1051 | vfd->release = video_device_release, | ||
1052 | vfd->lock = &dev->mfc_mutex; | ||
1053 | vfd->v4l2_dev = &dev->v4l2_dev; | ||
1054 | snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME); | ||
1055 | dev->vfd_dec = vfd; | ||
1056 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | ||
1057 | if (ret) { | ||
1058 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | ||
1059 | video_device_release(vfd); | ||
1060 | goto err_dec_reg; | ||
1061 | } | ||
1062 | v4l2_info(&dev->v4l2_dev, | ||
1063 | "decoder registered as /dev/video%d\n", vfd->num); | ||
1064 | video_set_drvdata(vfd, dev); | ||
1065 | |||
1066 | /* encoder */ | ||
1067 | vfd = video_device_alloc(); | ||
1068 | if (!vfd) { | ||
1069 | v4l2_err(&dev->v4l2_dev, "Failed to allocate video device\n"); | ||
1070 | ret = -ENOMEM; | ||
1071 | goto err_enc_alloc; | ||
1072 | } | ||
1073 | vfd->fops = &s5p_mfc_fops, | ||
1074 | vfd->ioctl_ops = get_enc_v4l2_ioctl_ops(); | ||
1075 | vfd->release = video_device_release, | ||
1076 | vfd->lock = &dev->mfc_mutex; | ||
1077 | vfd->v4l2_dev = &dev->v4l2_dev; | ||
1078 | snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); | ||
1079 | dev->vfd_enc = vfd; | ||
1080 | ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); | ||
1081 | if (ret) { | ||
1082 | v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); | ||
1083 | video_device_release(vfd); | ||
1084 | goto err_enc_reg; | ||
1085 | } | ||
1086 | v4l2_info(&dev->v4l2_dev, | ||
1087 | "encoder registered as /dev/video%d\n", vfd->num); | ||
1088 | video_set_drvdata(vfd, dev); | ||
1089 | platform_set_drvdata(pdev, dev); | ||
1090 | |||
1091 | dev->hw_lock = 0; | ||
1092 | dev->watchdog_workqueue = create_singlethread_workqueue(S5P_MFC_NAME); | ||
1093 | INIT_WORK(&dev->watchdog_work, s5p_mfc_watchdog_worker); | ||
1094 | atomic_set(&dev->watchdog_cnt, 0); | ||
1095 | init_timer(&dev->watchdog_timer); | ||
1096 | dev->watchdog_timer.data = (unsigned long)dev; | ||
1097 | dev->watchdog_timer.function = s5p_mfc_watchdog; | ||
1098 | |||
1099 | pr_debug("%s--\n", __func__); | ||
1100 | return 0; | ||
1101 | |||
1102 | /* Deinit MFC if probe had failed */ | ||
1103 | err_enc_reg: | ||
1104 | video_device_release(dev->vfd_enc); | ||
1105 | err_enc_alloc: | ||
1106 | video_unregister_device(dev->vfd_dec); | ||
1107 | err_dec_reg: | ||
1108 | video_device_release(dev->vfd_dec); | ||
1109 | err_dec_alloc: | ||
1110 | v4l2_device_unregister(&dev->v4l2_dev); | ||
1111 | err_v4l2_dev_reg: | ||
1112 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]); | ||
1113 | err_mem_init_ctx_1: | ||
1114 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]); | ||
1115 | err_mem_init_ctx_0: | ||
1116 | err_find_child: | ||
1117 | free_irq(dev->irq, dev); | ||
1118 | err_req_irq: | ||
1119 | err_get_res: | ||
1120 | iounmap(dev->regs_base); | ||
1121 | dev->regs_base = NULL; | ||
1122 | err_ioremap: | ||
1123 | release_resource(dev->mfc_mem); | ||
1124 | kfree(dev->mfc_mem); | ||
1125 | err_mem_reg: | ||
1126 | err_res: | ||
1127 | s5p_mfc_final_pm(dev); | ||
1128 | err_clk: | ||
1129 | err_dev: | ||
1130 | kfree(dev); | ||
1131 | pr_debug("%s-- with error\n", __func__); | ||
1132 | return ret; | ||
1133 | |||
1134 | } | ||
1135 | |||
1136 | /* Remove the driver */ | ||
1137 | static int __devexit s5p_mfc_remove(struct platform_device *pdev) | ||
1138 | { | ||
1139 | struct s5p_mfc_dev *dev = platform_get_drvdata(pdev); | ||
1140 | |||
1141 | v4l2_info(&dev->v4l2_dev, "Removing %s\n", pdev->name); | ||
1142 | |||
1143 | del_timer_sync(&dev->watchdog_timer); | ||
1144 | flush_workqueue(dev->watchdog_workqueue); | ||
1145 | destroy_workqueue(dev->watchdog_workqueue); | ||
1146 | |||
1147 | video_unregister_device(dev->vfd_enc); | ||
1148 | video_unregister_device(dev->vfd_dec); | ||
1149 | v4l2_device_unregister(&dev->v4l2_dev); | ||
1150 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[0]); | ||
1151 | vb2_dma_contig_cleanup_ctx(dev->alloc_ctx[1]); | ||
1152 | |||
1153 | free_irq(dev->irq, dev); | ||
1154 | iounmap(dev->regs_base); | ||
1155 | if (dev->mfc_mem) { | ||
1156 | release_resource(dev->mfc_mem); | ||
1157 | kfree(dev->mfc_mem); | ||
1158 | dev->mfc_mem = NULL; | ||
1159 | } | ||
1160 | s5p_mfc_final_pm(dev); | ||
1161 | kfree(dev); | ||
1162 | return 0; | ||
1163 | } | ||
1164 | |||
1165 | #ifdef CONFIG_PM_SLEEP | ||
1166 | |||
1167 | static int s5p_mfc_suspend(struct device *dev) | ||
1168 | { | ||
1169 | struct platform_device *pdev = to_platform_device(dev); | ||
1170 | struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); | ||
1171 | int ret; | ||
1172 | |||
1173 | if (m_dev->num_inst == 0) | ||
1174 | return 0; | ||
1175 | return s5p_mfc_sleep(m_dev); | ||
1176 | if (test_and_set_bit(0, &m_dev->enter_suspend) != 0) { | ||
1177 | mfc_err("Error: going to suspend for a second time\n"); | ||
1178 | return -EIO; | ||
1179 | } | ||
1180 | |||
1181 | /* Check if we're processing then wait if it necessary. */ | ||
1182 | while (test_and_set_bit(0, &m_dev->hw_lock) != 0) { | ||
1183 | /* Try and lock the HW */ | ||
1184 | /* Wait on the interrupt waitqueue */ | ||
1185 | ret = wait_event_interruptible_timeout(m_dev->queue, | ||
1186 | m_dev->int_cond || m_dev->ctx[m_dev->curr_ctx]->int_cond, | ||
1187 | msecs_to_jiffies(MFC_INT_TIMEOUT)); | ||
1188 | |||
1189 | if (ret == 0) { | ||
1190 | mfc_err("Waiting for hardware to finish timed out\n"); | ||
1191 | return -EIO; | ||
1192 | } | ||
1193 | } | ||
1194 | return 0; | ||
1195 | } | ||
1196 | |||
1197 | static int s5p_mfc_resume(struct device *dev) | ||
1198 | { | ||
1199 | struct platform_device *pdev = to_platform_device(dev); | ||
1200 | struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); | ||
1201 | |||
1202 | if (m_dev->num_inst == 0) | ||
1203 | return 0; | ||
1204 | return s5p_mfc_wakeup(m_dev); | ||
1205 | } | ||
1206 | #endif | ||
1207 | |||
1208 | #ifdef CONFIG_PM_RUNTIME | ||
1209 | static int s5p_mfc_runtime_suspend(struct device *dev) | ||
1210 | { | ||
1211 | struct platform_device *pdev = to_platform_device(dev); | ||
1212 | struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); | ||
1213 | |||
1214 | atomic_set(&m_dev->pm.power, 0); | ||
1215 | return 0; | ||
1216 | } | ||
1217 | |||
1218 | static int s5p_mfc_runtime_resume(struct device *dev) | ||
1219 | { | ||
1220 | struct platform_device *pdev = to_platform_device(dev); | ||
1221 | struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); | ||
1222 | int pre_power; | ||
1223 | |||
1224 | if (!m_dev->alloc_ctx) | ||
1225 | return 0; | ||
1226 | pre_power = atomic_read(&m_dev->pm.power); | ||
1227 | atomic_set(&m_dev->pm.power, 1); | ||
1228 | return 0; | ||
1229 | } | ||
1230 | #endif | ||
1231 | |||
1232 | /* Power management */ | ||
1233 | static const struct dev_pm_ops s5p_mfc_pm_ops = { | ||
1234 | SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume) | ||
1235 | SET_RUNTIME_PM_OPS(s5p_mfc_runtime_suspend, s5p_mfc_runtime_resume, | ||
1236 | NULL) | ||
1237 | }; | ||
1238 | |||
1239 | static struct platform_driver s5p_mfc_pdrv = { | ||
1240 | .probe = s5p_mfc_probe, | ||
1241 | .remove = __devexit_p(s5p_mfc_remove), | ||
1242 | .driver = { | ||
1243 | .name = S5P_MFC_NAME, | ||
1244 | .owner = THIS_MODULE, | ||
1245 | .pm = &s5p_mfc_pm_ops | ||
1246 | }, | ||
1247 | }; | ||
1248 | |||
1249 | static char banner[] __initdata = | ||
1250 | "S5P MFC V4L2 Driver, (C) 2011 Samsung Electronics\n"; | ||
1251 | |||
1252 | static int __init s5p_mfc_init(void) | ||
1253 | { | ||
1254 | int ret; | ||
1255 | |||
1256 | pr_info("%s", banner); | ||
1257 | ret = platform_driver_register(&s5p_mfc_pdrv); | ||
1258 | if (ret) | ||
1259 | pr_err("Platform device registration failed.\n"); | ||
1260 | return ret; | ||
1261 | } | ||
1262 | |||
1263 | static void __devexit s5p_mfc_exit(void) | ||
1264 | { | ||
1265 | platform_driver_unregister(&s5p_mfc_pdrv); | ||
1266 | } | ||
1267 | |||
1268 | module_init(s5p_mfc_init); | ||
1269 | module_exit(s5p_mfc_exit); | ||
1270 | |||
1271 | MODULE_LICENSE("GPL"); | ||
1272 | MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>"); | ||
1273 | MODULE_DESCRIPTION("Samsung S5P Multi Format Codec V4L2 driver"); | ||
1274 | |||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c new file mode 100644 index 000000000000..f0665ed1a529 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_cmd.c | ||
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 | #include "regs-mfc.h" | ||
14 | #include "s5p_mfc_cmd.h" | ||
15 | #include "s5p_mfc_common.h" | ||
16 | #include "s5p_mfc_debug.h" | ||
17 | |||
18 | /* This function is used to send a command to the MFC */ | ||
19 | static int s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd, | ||
20 | struct s5p_mfc_cmd_args *args) | ||
21 | { | ||
22 | int cur_cmd; | ||
23 | unsigned long timeout; | ||
24 | |||
25 | timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); | ||
26 | /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ | ||
27 | do { | ||
28 | if (time_after(jiffies, timeout)) { | ||
29 | mfc_err("Timeout while waiting for hardware\n"); | ||
30 | return -EIO; | ||
31 | } | ||
32 | cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); | ||
33 | } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); | ||
34 | mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); | ||
35 | mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); | ||
36 | mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); | ||
37 | mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); | ||
38 | /* Issue the command */ | ||
39 | mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | /* Initialize the MFC */ | ||
44 | int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev) | ||
45 | { | ||
46 | struct s5p_mfc_cmd_args h2r_args; | ||
47 | |||
48 | memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); | ||
49 | h2r_args.arg[0] = dev->fw_size; | ||
50 | return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SYS_INIT, &h2r_args); | ||
51 | } | ||
52 | |||
53 | /* Suspend the MFC hardware */ | ||
54 | int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev) | ||
55 | { | ||
56 | struct s5p_mfc_cmd_args h2r_args; | ||
57 | |||
58 | memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); | ||
59 | return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); | ||
60 | } | ||
61 | |||
62 | /* Wake up the MFC hardware */ | ||
63 | int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev) | ||
64 | { | ||
65 | struct s5p_mfc_cmd_args h2r_args; | ||
66 | |||
67 | memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); | ||
68 | return s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_WAKEUP, &h2r_args); | ||
69 | } | ||
70 | |||
71 | |||
72 | int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx) | ||
73 | { | ||
74 | struct s5p_mfc_dev *dev = ctx->dev; | ||
75 | struct s5p_mfc_cmd_args h2r_args; | ||
76 | int ret; | ||
77 | |||
78 | /* Preparing decoding - getting instance number */ | ||
79 | mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); | ||
80 | dev->curr_ctx = ctx->num; | ||
81 | memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); | ||
82 | h2r_args.arg[0] = ctx->codec_mode; | ||
83 | h2r_args.arg[1] = 0; /* no crc & no pixelcache */ | ||
84 | h2r_args.arg[2] = ctx->ctx_ofs; | ||
85 | h2r_args.arg[3] = ctx->ctx_size; | ||
86 | ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, | ||
87 | &h2r_args); | ||
88 | if (ret) { | ||
89 | mfc_err("Failed to create a new instance\n"); | ||
90 | ctx->state = MFCINST_ERROR; | ||
91 | } | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx) | ||
96 | { | ||
97 | struct s5p_mfc_dev *dev = ctx->dev; | ||
98 | struct s5p_mfc_cmd_args h2r_args; | ||
99 | int ret; | ||
100 | |||
101 | if (ctx->state == MFCINST_FREE) { | ||
102 | mfc_err("Instance already returned\n"); | ||
103 | ctx->state = MFCINST_ERROR; | ||
104 | return -EINVAL; | ||
105 | } | ||
106 | /* Closing decoding instance */ | ||
107 | mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); | ||
108 | dev->curr_ctx = ctx->num; | ||
109 | memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); | ||
110 | h2r_args.arg[0] = ctx->inst_no; | ||
111 | ret = s5p_mfc_cmd_host2risc(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, | ||
112 | &h2r_args); | ||
113 | if (ret) { | ||
114 | mfc_err("Failed to return an instance\n"); | ||
115 | ctx->state = MFCINST_ERROR; | ||
116 | return -EINVAL; | ||
117 | } | ||
118 | return 0; | ||
119 | } | ||
120 | |||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h new file mode 100644 index 000000000000..5ceebfe6131a --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_cmd.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_cmd.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_H_ | ||
14 | #define S5P_MFC_CMD_H_ | ||
15 | |||
16 | #include "s5p_mfc_common.h" | ||
17 | |||
18 | #define MAX_H2R_ARG 4 | ||
19 | |||
20 | struct s5p_mfc_cmd_args { | ||
21 | unsigned int arg[MAX_H2R_ARG]; | ||
22 | }; | ||
23 | |||
24 | int s5p_mfc_sys_init_cmd(struct s5p_mfc_dev *dev); | ||
25 | int s5p_mfc_sleep_cmd(struct s5p_mfc_dev *dev); | ||
26 | int s5p_mfc_wakeup_cmd(struct s5p_mfc_dev *dev); | ||
27 | int s5p_mfc_open_inst_cmd(struct s5p_mfc_ctx *ctx); | ||
28 | int s5p_mfc_close_inst_cmd(struct s5p_mfc_ctx *ctx); | ||
29 | |||
30 | #endif /* S5P_MFC_CMD_H_ */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_common.h b/drivers/media/video/s5p-mfc/s5p_mfc_common.h new file mode 100644 index 000000000000..91146fa622e4 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_common.h | |||
@@ -0,0 +1,572 @@ | |||
1 | /* | ||
2 | * Samsung S5P Multi Format Codec v 5.0 | ||
3 | * | ||
4 | * This file contains definitions of enums and structs used by the codec | ||
5 | * driver. | ||
6 | * | ||
7 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
8 | * Kamil Debski, <k.debski@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 as published by the | ||
12 | * Free Software Foundation; either version 2 of the | ||
13 | * License, or (at your option) any later version | ||
14 | */ | ||
15 | |||
16 | #ifndef S5P_MFC_COMMON_H_ | ||
17 | #define S5P_MFC_COMMON_H_ | ||
18 | |||
19 | #include "regs-mfc.h" | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/videodev2.h> | ||
22 | #include <media/v4l2-ctrls.h> | ||
23 | #include <media/v4l2-device.h> | ||
24 | #include <media/v4l2-ioctl.h> | ||
25 | #include <media/videobuf2-core.h> | ||
26 | |||
27 | /* Definitions related to MFC memory */ | ||
28 | |||
29 | /* Offset base used to differentiate between CAPTURE and OUTPUT | ||
30 | * while mmaping */ | ||
31 | #define DST_QUEUE_OFF_BASE (TASK_SIZE / 2) | ||
32 | |||
33 | /* Offset used by the hardware to store addresses */ | ||
34 | #define MFC_OFFSET_SHIFT 11 | ||
35 | |||
36 | #define FIRMWARE_ALIGN 0x20000 /* 128KB */ | ||
37 | #define MFC_H264_CTX_BUF_SIZE 0x96000 /* 600KB per H264 instance */ | ||
38 | #define MFC_CTX_BUF_SIZE 0x2800 /* 10KB per instance */ | ||
39 | #define DESC_BUF_SIZE 0x20000 /* 128KB for DESC buffer */ | ||
40 | #define SHARED_BUF_SIZE 0x2000 /* 8KB for shared buffer */ | ||
41 | |||
42 | #define DEF_CPB_SIZE 0x40000 /* 512KB */ | ||
43 | |||
44 | #define MFC_BANK1_ALLOC_CTX 0 | ||
45 | #define MFC_BANK2_ALLOC_CTX 1 | ||
46 | |||
47 | #define MFC_BANK1_ALIGN_ORDER 13 | ||
48 | #define MFC_BANK2_ALIGN_ORDER 13 | ||
49 | #define MFC_BASE_ALIGN_ORDER 17 | ||
50 | |||
51 | #include <media/videobuf2-dma-contig.h> | ||
52 | |||
53 | static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b) | ||
54 | { | ||
55 | /* Same functionality as the vb2_dma_contig_plane_paddr */ | ||
56 | dma_addr_t *paddr = vb2_dma_contig_memops.cookie(b); | ||
57 | |||
58 | return *paddr; | ||
59 | } | ||
60 | |||
61 | /* MFC definitions */ | ||
62 | #define MFC_MAX_EXTRA_DPB 5 | ||
63 | #define MFC_MAX_BUFFERS 32 | ||
64 | #define MFC_NUM_CONTEXTS 4 | ||
65 | /* Interrupt timeout */ | ||
66 | #define MFC_INT_TIMEOUT 2000 | ||
67 | /* Busy wait timeout */ | ||
68 | #define MFC_BW_TIMEOUT 500 | ||
69 | /* Watchdog interval */ | ||
70 | #define MFC_WATCHDOG_INTERVAL 1000 | ||
71 | /* After how many executions watchdog should assume lock up */ | ||
72 | #define MFC_WATCHDOG_CNT 10 | ||
73 | #define MFC_NO_INSTANCE_SET -1 | ||
74 | #define MFC_ENC_CAP_PLANE_COUNT 1 | ||
75 | #define MFC_ENC_OUT_PLANE_COUNT 2 | ||
76 | #define STUFF_BYTE 4 | ||
77 | #define MFC_MAX_CTRLS 64 | ||
78 | |||
79 | #define mfc_read(dev, offset) readl(dev->regs_base + (offset)) | ||
80 | #define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ | ||
81 | (offset)) | ||
82 | |||
83 | /** | ||
84 | * enum s5p_mfc_fmt_type - type of the pixelformat | ||
85 | */ | ||
86 | enum s5p_mfc_fmt_type { | ||
87 | MFC_FMT_DEC, | ||
88 | MFC_FMT_ENC, | ||
89 | MFC_FMT_RAW, | ||
90 | }; | ||
91 | |||
92 | /** | ||
93 | * enum s5p_mfc_node_type - The type of an MFC device node. | ||
94 | */ | ||
95 | enum s5p_mfc_node_type { | ||
96 | MFCNODE_INVALID = -1, | ||
97 | MFCNODE_DECODER = 0, | ||
98 | MFCNODE_ENCODER = 1, | ||
99 | }; | ||
100 | |||
101 | /** | ||
102 | * enum s5p_mfc_inst_type - The type of an MFC instance. | ||
103 | */ | ||
104 | enum s5p_mfc_inst_type { | ||
105 | MFCINST_INVALID, | ||
106 | MFCINST_DECODER, | ||
107 | MFCINST_ENCODER, | ||
108 | }; | ||
109 | |||
110 | /** | ||
111 | * enum s5p_mfc_inst_state - The state of an MFC instance. | ||
112 | */ | ||
113 | enum s5p_mfc_inst_state { | ||
114 | MFCINST_FREE = 0, | ||
115 | MFCINST_INIT = 100, | ||
116 | MFCINST_GOT_INST, | ||
117 | MFCINST_HEAD_PARSED, | ||
118 | MFCINST_BUFS_SET, | ||
119 | MFCINST_RUNNING, | ||
120 | MFCINST_FINISHING, | ||
121 | MFCINST_FINISHED, | ||
122 | MFCINST_RETURN_INST, | ||
123 | MFCINST_ERROR, | ||
124 | MFCINST_ABORT, | ||
125 | MFCINST_RES_CHANGE_INIT, | ||
126 | MFCINST_RES_CHANGE_FLUSH, | ||
127 | MFCINST_RES_CHANGE_END, | ||
128 | }; | ||
129 | |||
130 | /** | ||
131 | * enum s5p_mfc_queue_state - The state of buffer queue. | ||
132 | */ | ||
133 | enum s5p_mfc_queue_state { | ||
134 | QUEUE_FREE, | ||
135 | QUEUE_BUFS_REQUESTED, | ||
136 | QUEUE_BUFS_QUERIED, | ||
137 | QUEUE_BUFS_MMAPED, | ||
138 | }; | ||
139 | |||
140 | /** | ||
141 | * enum s5p_mfc_decode_arg - type of frame decoding | ||
142 | */ | ||
143 | enum s5p_mfc_decode_arg { | ||
144 | MFC_DEC_FRAME, | ||
145 | MFC_DEC_LAST_FRAME, | ||
146 | MFC_DEC_RES_CHANGE, | ||
147 | }; | ||
148 | |||
149 | struct s5p_mfc_ctx; | ||
150 | |||
151 | /** | ||
152 | * struct s5p_mfc_buf - MFC buffer | ||
153 | */ | ||
154 | struct s5p_mfc_buf { | ||
155 | struct list_head list; | ||
156 | struct vb2_buffer *b; | ||
157 | union { | ||
158 | struct { | ||
159 | size_t luma; | ||
160 | size_t chroma; | ||
161 | } raw; | ||
162 | size_t stream; | ||
163 | } cookie; | ||
164 | int used; | ||
165 | }; | ||
166 | |||
167 | /** | ||
168 | * struct s5p_mfc_pm - power management data structure | ||
169 | */ | ||
170 | struct s5p_mfc_pm { | ||
171 | struct clk *clock; | ||
172 | struct clk *clock_gate; | ||
173 | atomic_t power; | ||
174 | struct device *device; | ||
175 | }; | ||
176 | |||
177 | /** | ||
178 | * struct s5p_mfc_dev - The struct containing driver internal parameters. | ||
179 | * | ||
180 | * @v4l2_dev: v4l2_device | ||
181 | * @vfd_dec: video device for decoding | ||
182 | * @vfd_enc: video device for encoding | ||
183 | * @plat_dev: platform device | ||
184 | * @mem_dev_l: child device of the left memory bank (0) | ||
185 | * @mem_dev_r: child device of the right memory bank (1) | ||
186 | * @regs_base: base address of the MFC hw registers | ||
187 | * @irq: irq resource | ||
188 | * @mfc_mem: MFC registers memory resource | ||
189 | * @dec_ctrl_handler: control framework handler for decoding | ||
190 | * @enc_ctrl_handler: control framework handler for encoding | ||
191 | * @pm: power management control | ||
192 | * @num_inst: couter of active MFC instances | ||
193 | * @irqlock: lock for operations on videobuf2 queues | ||
194 | * @condlock: lock for changing/checking if a context is ready to be | ||
195 | * processed | ||
196 | * @mfc_mutex: lock for video_device | ||
197 | * @int_cond: variable used by the waitqueue | ||
198 | * @int_type: type of last interrupt | ||
199 | * @int_err: error number for last interrupt | ||
200 | * @queue: waitqueue for waiting for completion of device commands | ||
201 | * @fw_size: size of firmware | ||
202 | * @bank1: address of the beggining of bank 1 memory | ||
203 | * @bank2: address of the beggining of bank 2 memory | ||
204 | * @hw_lock: used for hardware locking | ||
205 | * @ctx: array of driver contexts | ||
206 | * @curr_ctx: number of the currently running context | ||
207 | * @ctx_work_bits: used to mark which contexts are waiting for hardware | ||
208 | * @watchdog_cnt: counter for the watchdog | ||
209 | * @watchdog_workqueue: workqueue for the watchdog | ||
210 | * @watchdog_work: worker for the watchdog | ||
211 | * @alloc_ctx: videobuf2 allocator contexts for two memory banks | ||
212 | * @enter_suspend: flag set when entering suspend | ||
213 | * | ||
214 | */ | ||
215 | struct s5p_mfc_dev { | ||
216 | struct v4l2_device v4l2_dev; | ||
217 | struct video_device *vfd_dec; | ||
218 | struct video_device *vfd_enc; | ||
219 | struct platform_device *plat_dev; | ||
220 | struct device *mem_dev_l; | ||
221 | struct device *mem_dev_r; | ||
222 | void __iomem *regs_base; | ||
223 | int irq; | ||
224 | struct resource *mfc_mem; | ||
225 | struct v4l2_ctrl_handler dec_ctrl_handler; | ||
226 | struct v4l2_ctrl_handler enc_ctrl_handler; | ||
227 | struct s5p_mfc_pm pm; | ||
228 | int num_inst; | ||
229 | spinlock_t irqlock; /* lock when operating on videobuf2 queues */ | ||
230 | spinlock_t condlock; /* lock when changing/checking if a context is | ||
231 | ready to be processed */ | ||
232 | struct mutex mfc_mutex; /* video_device lock */ | ||
233 | int int_cond; | ||
234 | int int_type; | ||
235 | unsigned int int_err; | ||
236 | wait_queue_head_t queue; | ||
237 | size_t fw_size; | ||
238 | size_t bank1; | ||
239 | size_t bank2; | ||
240 | unsigned long hw_lock; | ||
241 | struct s5p_mfc_ctx *ctx[MFC_NUM_CONTEXTS]; | ||
242 | int curr_ctx; | ||
243 | unsigned long ctx_work_bits; | ||
244 | atomic_t watchdog_cnt; | ||
245 | struct timer_list watchdog_timer; | ||
246 | struct workqueue_struct *watchdog_workqueue; | ||
247 | struct work_struct watchdog_work; | ||
248 | void *alloc_ctx[2]; | ||
249 | unsigned long enter_suspend; | ||
250 | }; | ||
251 | |||
252 | /** | ||
253 | * struct s5p_mfc_h264_enc_params - encoding parameters for h264 | ||
254 | */ | ||
255 | struct s5p_mfc_h264_enc_params { | ||
256 | enum v4l2_mpeg_video_h264_profile profile; | ||
257 | enum v4l2_mpeg_video_h264_loop_filter_mode loop_filter_mode; | ||
258 | s8 loop_filter_alpha; | ||
259 | s8 loop_filter_beta; | ||
260 | enum v4l2_mpeg_video_h264_entropy_mode entropy_mode; | ||
261 | u8 max_ref_pic; | ||
262 | u8 num_ref_pic_4p; | ||
263 | int _8x8_transform; | ||
264 | int rc_mb; | ||
265 | int rc_mb_dark; | ||
266 | int rc_mb_smooth; | ||
267 | int rc_mb_static; | ||
268 | int rc_mb_activity; | ||
269 | int vui_sar; | ||
270 | u8 vui_sar_idc; | ||
271 | u16 vui_ext_sar_width; | ||
272 | u16 vui_ext_sar_height; | ||
273 | int open_gop; | ||
274 | u16 open_gop_size; | ||
275 | u8 rc_frame_qp; | ||
276 | u8 rc_min_qp; | ||
277 | u8 rc_max_qp; | ||
278 | u8 rc_p_frame_qp; | ||
279 | u8 rc_b_frame_qp; | ||
280 | enum v4l2_mpeg_video_h264_level level_v4l2; | ||
281 | int level; | ||
282 | u16 cpb_size; | ||
283 | }; | ||
284 | |||
285 | /** | ||
286 | * struct s5p_mfc_mpeg4_enc_params - encoding parameters for h263 and mpeg4 | ||
287 | */ | ||
288 | struct s5p_mfc_mpeg4_enc_params { | ||
289 | /* MPEG4 Only */ | ||
290 | enum v4l2_mpeg_video_mpeg4_profile profile; | ||
291 | int quarter_pixel; | ||
292 | /* Common for MPEG4, H263 */ | ||
293 | u16 vop_time_res; | ||
294 | u16 vop_frm_delta; | ||
295 | u8 rc_frame_qp; | ||
296 | u8 rc_min_qp; | ||
297 | u8 rc_max_qp; | ||
298 | u8 rc_p_frame_qp; | ||
299 | u8 rc_b_frame_qp; | ||
300 | enum v4l2_mpeg_video_mpeg4_level level_v4l2; | ||
301 | int level; | ||
302 | }; | ||
303 | |||
304 | /** | ||
305 | * struct s5p_mfc_enc_params - general encoding parameters | ||
306 | */ | ||
307 | struct s5p_mfc_enc_params { | ||
308 | u16 width; | ||
309 | u16 height; | ||
310 | |||
311 | u16 gop_size; | ||
312 | enum v4l2_mpeg_video_multi_slice_mode slice_mode; | ||
313 | u16 slice_mb; | ||
314 | u32 slice_bit; | ||
315 | u16 intra_refresh_mb; | ||
316 | int pad; | ||
317 | u8 pad_luma; | ||
318 | u8 pad_cb; | ||
319 | u8 pad_cr; | ||
320 | int rc_frame; | ||
321 | u32 rc_bitrate; | ||
322 | u16 rc_reaction_coeff; | ||
323 | u16 vbv_size; | ||
324 | |||
325 | enum v4l2_mpeg_video_header_mode seq_hdr_mode; | ||
326 | enum v4l2_mpeg_mfc51_video_frame_skip_mode frame_skip_mode; | ||
327 | int fixed_target_bit; | ||
328 | |||
329 | u8 num_b_frame; | ||
330 | u32 rc_framerate_num; | ||
331 | u32 rc_framerate_denom; | ||
332 | int interlace; | ||
333 | |||
334 | union { | ||
335 | struct s5p_mfc_h264_enc_params h264; | ||
336 | struct s5p_mfc_mpeg4_enc_params mpeg4; | ||
337 | } codec; | ||
338 | |||
339 | }; | ||
340 | |||
341 | /** | ||
342 | * struct s5p_mfc_codec_ops - codec ops, used by encoding | ||
343 | */ | ||
344 | struct s5p_mfc_codec_ops { | ||
345 | /* initialization routines */ | ||
346 | int (*pre_seq_start) (struct s5p_mfc_ctx *ctx); | ||
347 | int (*post_seq_start) (struct s5p_mfc_ctx *ctx); | ||
348 | /* execution routines */ | ||
349 | int (*pre_frame_start) (struct s5p_mfc_ctx *ctx); | ||
350 | int (*post_frame_start) (struct s5p_mfc_ctx *ctx); | ||
351 | }; | ||
352 | |||
353 | #define call_cop(c, op, args...) \ | ||
354 | (((c)->c_ops->op) ? \ | ||
355 | ((c)->c_ops->op(args)) : 0) | ||
356 | |||
357 | /** | ||
358 | * struct s5p_mfc_ctx - This struct contains the instance context | ||
359 | * | ||
360 | * @dev: pointer to the s5p_mfc_dev of the device | ||
361 | * @fh: struct v4l2_fh | ||
362 | * @num: number of the context that this structure describes | ||
363 | * @int_cond: variable used by the waitqueue | ||
364 | * @int_type: type of the last interrupt | ||
365 | * @int_err: error number received from MFC hw in the interrupt | ||
366 | * @queue: waitqueue that can be used to wait for this context to | ||
367 | * finish | ||
368 | * @src_fmt: source pixelformat information | ||
369 | * @dst_fmt: destination pixelformat information | ||
370 | * @vq_src: vb2 queue for source buffers | ||
371 | * @vq_dst: vb2 queue for destination buffers | ||
372 | * @src_queue: driver internal queue for source buffers | ||
373 | * @dst_queue: driver internal queue for destination buffers | ||
374 | * @src_queue_cnt: number of buffers queued on the source internal queue | ||
375 | * @dst_queue_cnt: number of buffers queued on the dest internal queue | ||
376 | * @type: type of the instance - decoder or encoder | ||
377 | * @state: state of the context | ||
378 | * @inst_no: number of hw instance associated with the context | ||
379 | * @img_width: width of the image that is decoded or encoded | ||
380 | * @img_height: height of the image that is decoded or encoded | ||
381 | * @buf_width: width of the buffer for processed image | ||
382 | * @buf_height: height of the buffer for processed image | ||
383 | * @luma_size: size of a luma plane | ||
384 | * @chroma_size: size of a chroma plane | ||
385 | * @mv_size: size of a motion vectors buffer | ||
386 | * @consumed_stream: number of bytes that have been used so far from the | ||
387 | * decoding buffer | ||
388 | * @dpb_flush_flag: flag used to indicate that a DPB buffers are being | ||
389 | * flushed | ||
390 | * @bank1_buf: handle to memory allocated for temporary buffers from | ||
391 | * memory bank 1 | ||
392 | * @bank1_phys: address of the temporary buffers from memory bank 1 | ||
393 | * @bank1_size: size of the memory allocated for temporary buffers from | ||
394 | * memory bank 1 | ||
395 | * @bank2_buf: handle to memory allocated for temporary buffers from | ||
396 | * memory bank 2 | ||
397 | * @bank2_phys: address of the temporary buffers from memory bank 2 | ||
398 | * @bank2_size: size of the memory allocated for temporary buffers from | ||
399 | * memory bank 2 | ||
400 | * @capture_state: state of the capture buffers queue | ||
401 | * @output_state: state of the output buffers queue | ||
402 | * @src_bufs: information on allocated source buffers | ||
403 | * @dst_bufs: information on allocated destination buffers | ||
404 | * @sequence: counter for the sequence number for v4l2 | ||
405 | * @dec_dst_flag: flags for buffers queued in the hardware | ||
406 | * @dec_src_buf_size: size of the buffer for source buffers in decoding | ||
407 | * @codec_mode: number of codec mode used by MFC hw | ||
408 | * @slice_interface: slice interface flag | ||
409 | * @loop_filter_mpeg4: loop filter for MPEG4 flag | ||
410 | * @display_delay: value of the display delay for H264 | ||
411 | * @display_delay_enable: display delay for H264 enable flag | ||
412 | * @after_packed_pb: flag used to track buffer when stream is in | ||
413 | * Packed PB format | ||
414 | * @dpb_count: count of the DPB buffers required by MFC hw | ||
415 | * @total_dpb_count: count of DPB buffers with additional buffers | ||
416 | * requested by the application | ||
417 | * @ctx_buf: handle to the memory associated with this context | ||
418 | * @ctx_phys: address of the memory associated with this context | ||
419 | * @ctx_size: size of the memory associated with this context | ||
420 | * @desc_buf: description buffer for decoding handle | ||
421 | * @desc_phys: description buffer for decoding address | ||
422 | * @shm_alloc: handle for the shared memory buffer | ||
423 | * @shm: virtual address for the shared memory buffer | ||
424 | * @shm_ofs: address offset for shared memory | ||
425 | * @enc_params: encoding parameters for MFC | ||
426 | * @enc_dst_buf_size: size of the buffers for encoder output | ||
427 | * @frame_type: used to force the type of the next encoded frame | ||
428 | * @ref_queue: list of the reference buffers for encoding | ||
429 | * @ref_queue_cnt: number of the buffers in the reference list | ||
430 | * @c_ops: ops for encoding | ||
431 | * @ctrls: array of controls, used when adding controls to the | ||
432 | * v4l2 control framework | ||
433 | * @ctrl_handler: handler for v4l2 framework | ||
434 | */ | ||
435 | struct s5p_mfc_ctx { | ||
436 | struct s5p_mfc_dev *dev; | ||
437 | struct v4l2_fh fh; | ||
438 | |||
439 | int num; | ||
440 | |||
441 | int int_cond; | ||
442 | int int_type; | ||
443 | unsigned int int_err; | ||
444 | wait_queue_head_t queue; | ||
445 | |||
446 | struct s5p_mfc_fmt *src_fmt; | ||
447 | struct s5p_mfc_fmt *dst_fmt; | ||
448 | |||
449 | struct vb2_queue vq_src; | ||
450 | struct vb2_queue vq_dst; | ||
451 | |||
452 | struct list_head src_queue; | ||
453 | struct list_head dst_queue; | ||
454 | |||
455 | unsigned int src_queue_cnt; | ||
456 | unsigned int dst_queue_cnt; | ||
457 | |||
458 | enum s5p_mfc_inst_type type; | ||
459 | enum s5p_mfc_inst_state state; | ||
460 | int inst_no; | ||
461 | |||
462 | /* Image parameters */ | ||
463 | int img_width; | ||
464 | int img_height; | ||
465 | int buf_width; | ||
466 | int buf_height; | ||
467 | |||
468 | int luma_size; | ||
469 | int chroma_size; | ||
470 | int mv_size; | ||
471 | |||
472 | unsigned long consumed_stream; | ||
473 | |||
474 | unsigned int dpb_flush_flag; | ||
475 | |||
476 | /* Buffers */ | ||
477 | void *bank1_buf; | ||
478 | size_t bank1_phys; | ||
479 | size_t bank1_size; | ||
480 | |||
481 | void *bank2_buf; | ||
482 | size_t bank2_phys; | ||
483 | size_t bank2_size; | ||
484 | |||
485 | enum s5p_mfc_queue_state capture_state; | ||
486 | enum s5p_mfc_queue_state output_state; | ||
487 | |||
488 | struct s5p_mfc_buf src_bufs[MFC_MAX_BUFFERS]; | ||
489 | int src_bufs_cnt; | ||
490 | struct s5p_mfc_buf dst_bufs[MFC_MAX_BUFFERS]; | ||
491 | int dst_bufs_cnt; | ||
492 | |||
493 | unsigned int sequence; | ||
494 | unsigned long dec_dst_flag; | ||
495 | size_t dec_src_buf_size; | ||
496 | |||
497 | /* Control values */ | ||
498 | int codec_mode; | ||
499 | int slice_interface; | ||
500 | int loop_filter_mpeg4; | ||
501 | int display_delay; | ||
502 | int display_delay_enable; | ||
503 | int after_packed_pb; | ||
504 | |||
505 | int dpb_count; | ||
506 | int total_dpb_count; | ||
507 | |||
508 | /* Buffers */ | ||
509 | void *ctx_buf; | ||
510 | size_t ctx_phys; | ||
511 | size_t ctx_ofs; | ||
512 | size_t ctx_size; | ||
513 | |||
514 | void *desc_buf; | ||
515 | size_t desc_phys; | ||
516 | |||
517 | |||
518 | void *shm_alloc; | ||
519 | void *shm; | ||
520 | size_t shm_ofs; | ||
521 | |||
522 | struct s5p_mfc_enc_params enc_params; | ||
523 | |||
524 | size_t enc_dst_buf_size; | ||
525 | |||
526 | enum v4l2_mpeg_mfc51_video_force_frame_type force_frame_type; | ||
527 | |||
528 | struct list_head ref_queue; | ||
529 | unsigned int ref_queue_cnt; | ||
530 | |||
531 | struct s5p_mfc_codec_ops *c_ops; | ||
532 | |||
533 | struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS]; | ||
534 | struct v4l2_ctrl_handler ctrl_handler; | ||
535 | }; | ||
536 | |||
537 | /* | ||
538 | * struct s5p_mfc_fmt - structure used to store information about pixelformats | ||
539 | * used by the MFC | ||
540 | */ | ||
541 | struct s5p_mfc_fmt { | ||
542 | char *name; | ||
543 | u32 fourcc; | ||
544 | u32 codec_mode; | ||
545 | enum s5p_mfc_fmt_type type; | ||
546 | u32 num_planes; | ||
547 | }; | ||
548 | |||
549 | /** | ||
550 | * struct mfc_control - structure used to store information about MFC controls | ||
551 | * it is used to initialize the control framework. | ||
552 | */ | ||
553 | struct mfc_control { | ||
554 | __u32 id; | ||
555 | enum v4l2_ctrl_type type; | ||
556 | __u8 name[32]; /* Whatever */ | ||
557 | __s32 minimum; /* Note signedness */ | ||
558 | __s32 maximum; | ||
559 | __s32 step; | ||
560 | __u32 menu_skip_mask; | ||
561 | __s32 default_value; | ||
562 | __u32 flags; | ||
563 | __u32 reserved[2]; | ||
564 | __u8 is_volatile; | ||
565 | }; | ||
566 | |||
567 | |||
568 | #define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh) | ||
569 | #define ctrl_to_ctx(__ctrl) \ | ||
570 | container_of((__ctrl)->handler, struct s5p_mfc_ctx, ctrl_handler) | ||
571 | |||
572 | #endif /* S5P_MFC_COMMON_H_ */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c new file mode 100644 index 000000000000..5f4da80051bb --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c | ||
3 | * | ||
4 | * Copyright (c) 2010 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 <linux/delay.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/firmware.h> | ||
16 | #include <linux/jiffies.h> | ||
17 | #include <linux/sched.h> | ||
18 | #include "regs-mfc.h" | ||
19 | #include "s5p_mfc_cmd.h" | ||
20 | #include "s5p_mfc_common.h" | ||
21 | #include "s5p_mfc_debug.h" | ||
22 | #include "s5p_mfc_intr.h" | ||
23 | #include "s5p_mfc_pm.h" | ||
24 | |||
25 | static void *s5p_mfc_bitproc_buf; | ||
26 | static size_t s5p_mfc_bitproc_phys; | ||
27 | static unsigned char *s5p_mfc_bitproc_virt; | ||
28 | |||
29 | /* Allocate and load firmware */ | ||
30 | int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) | ||
31 | { | ||
32 | struct firmware *fw_blob; | ||
33 | size_t bank2_base_phys; | ||
34 | void *b_base; | ||
35 | int err; | ||
36 | |||
37 | /* Firmare has to be present as a separate file or compiled | ||
38 | * into kernel. */ | ||
39 | mfc_debug_enter(); | ||
40 | err = request_firmware((const struct firmware **)&fw_blob, | ||
41 | "s5pc110-mfc.fw", dev->v4l2_dev.dev); | ||
42 | if (err != 0) { | ||
43 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); | ||
44 | return -EINVAL; | ||
45 | } | ||
46 | dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN); | ||
47 | if (s5p_mfc_bitproc_buf) { | ||
48 | mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); | ||
49 | release_firmware(fw_blob); | ||
50 | return -ENOMEM; | ||
51 | } | ||
52 | s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc( | ||
53 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size); | ||
54 | if (IS_ERR(s5p_mfc_bitproc_buf)) { | ||
55 | s5p_mfc_bitproc_buf = 0; | ||
56 | mfc_err("Allocating bitprocessor buffer failed\n"); | ||
57 | release_firmware(fw_blob); | ||
58 | return -ENOMEM; | ||
59 | } | ||
60 | s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie( | ||
61 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], s5p_mfc_bitproc_buf); | ||
62 | if (s5p_mfc_bitproc_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { | ||
63 | mfc_err("The base memory for bank 1 is not aligned to 128KB\n"); | ||
64 | vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); | ||
65 | s5p_mfc_bitproc_phys = 0; | ||
66 | s5p_mfc_bitproc_buf = 0; | ||
67 | release_firmware(fw_blob); | ||
68 | return -EIO; | ||
69 | } | ||
70 | s5p_mfc_bitproc_virt = vb2_dma_contig_memops.vaddr(s5p_mfc_bitproc_buf); | ||
71 | if (!s5p_mfc_bitproc_virt) { | ||
72 | mfc_err("Bitprocessor memory remap failed\n"); | ||
73 | vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); | ||
74 | s5p_mfc_bitproc_phys = 0; | ||
75 | s5p_mfc_bitproc_buf = 0; | ||
76 | release_firmware(fw_blob); | ||
77 | return -EIO; | ||
78 | } | ||
79 | dev->bank1 = s5p_mfc_bitproc_phys; | ||
80 | b_base = vb2_dma_contig_memops.alloc( | ||
81 | dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BANK2_ALIGN_ORDER); | ||
82 | if (IS_ERR(b_base)) { | ||
83 | vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); | ||
84 | s5p_mfc_bitproc_phys = 0; | ||
85 | s5p_mfc_bitproc_buf = 0; | ||
86 | mfc_err("Allocating bank2 base failed\n"); | ||
87 | release_firmware(fw_blob); | ||
88 | return -ENOMEM; | ||
89 | } | ||
90 | bank2_base_phys = s5p_mfc_mem_cookie( | ||
91 | dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); | ||
92 | vb2_dma_contig_memops.put(b_base); | ||
93 | if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { | ||
94 | mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); | ||
95 | vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); | ||
96 | s5p_mfc_bitproc_phys = 0; | ||
97 | s5p_mfc_bitproc_buf = 0; | ||
98 | release_firmware(fw_blob); | ||
99 | return -EIO; | ||
100 | } | ||
101 | dev->bank2 = bank2_base_phys; | ||
102 | memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); | ||
103 | wmb(); | ||
104 | release_firmware(fw_blob); | ||
105 | mfc_debug_leave(); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /* Reload firmware to MFC */ | ||
110 | int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) | ||
111 | { | ||
112 | struct firmware *fw_blob; | ||
113 | int err; | ||
114 | |||
115 | /* Firmare has to be present as a separate file or compiled | ||
116 | * into kernel. */ | ||
117 | mfc_debug_enter(); | ||
118 | err = request_firmware((const struct firmware **)&fw_blob, | ||
119 | "s5pc110-mfc.fw", dev->v4l2_dev.dev); | ||
120 | if (err != 0) { | ||
121 | mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); | ||
122 | return -EINVAL; | ||
123 | } | ||
124 | if (fw_blob->size > dev->fw_size) { | ||
125 | mfc_err("MFC firmware is too big to be loaded\n"); | ||
126 | release_firmware(fw_blob); | ||
127 | return -ENOMEM; | ||
128 | } | ||
129 | if (s5p_mfc_bitproc_buf == 0 || s5p_mfc_bitproc_phys == 0) { | ||
130 | mfc_err("MFC firmware is not allocated or was not mapped correctly\n"); | ||
131 | release_firmware(fw_blob); | ||
132 | return -EINVAL; | ||
133 | } | ||
134 | memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); | ||
135 | wmb(); | ||
136 | release_firmware(fw_blob); | ||
137 | mfc_debug_leave(); | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | /* Release firmware memory */ | ||
142 | int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) | ||
143 | { | ||
144 | /* Before calling this function one has to make sure | ||
145 | * that MFC is no longer processing */ | ||
146 | if (!s5p_mfc_bitproc_buf) | ||
147 | return -EINVAL; | ||
148 | vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); | ||
149 | s5p_mfc_bitproc_virt = 0; | ||
150 | s5p_mfc_bitproc_phys = 0; | ||
151 | s5p_mfc_bitproc_buf = 0; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /* Reset the device */ | ||
156 | int s5p_mfc_reset(struct s5p_mfc_dev *dev) | ||
157 | { | ||
158 | unsigned int mc_status; | ||
159 | unsigned long timeout; | ||
160 | |||
161 | mfc_debug_enter(); | ||
162 | /* Stop procedure */ | ||
163 | /* reset RISC */ | ||
164 | mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); | ||
165 | /* All reset except for MC */ | ||
166 | mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); | ||
167 | mdelay(10); | ||
168 | |||
169 | timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); | ||
170 | /* Check MC status */ | ||
171 | do { | ||
172 | if (time_after(jiffies, timeout)) { | ||
173 | mfc_err("Timeout while resetting MFC\n"); | ||
174 | return -EIO; | ||
175 | } | ||
176 | |||
177 | mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); | ||
178 | |||
179 | } while (mc_status & 0x3); | ||
180 | |||
181 | mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); | ||
182 | mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); | ||
183 | mfc_debug_leave(); | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) | ||
188 | { | ||
189 | mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); | ||
190 | mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); | ||
191 | mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2); | ||
192 | } | ||
193 | |||
194 | static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) | ||
195 | { | ||
196 | mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); | ||
197 | mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); | ||
198 | mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); | ||
199 | mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); | ||
200 | } | ||
201 | |||
202 | /* Initialize hardware */ | ||
203 | int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) | ||
204 | { | ||
205 | unsigned int ver; | ||
206 | int ret; | ||
207 | |||
208 | mfc_debug_enter(); | ||
209 | if (!s5p_mfc_bitproc_buf) | ||
210 | return -EINVAL; | ||
211 | |||
212 | /* 0. MFC reset */ | ||
213 | mfc_debug(2, "MFC reset..\n"); | ||
214 | s5p_mfc_clock_on(); | ||
215 | ret = s5p_mfc_reset(dev); | ||
216 | if (ret) { | ||
217 | mfc_err("Failed to reset MFC - timeout\n"); | ||
218 | return ret; | ||
219 | } | ||
220 | mfc_debug(2, "Done MFC reset..\n"); | ||
221 | /* 1. Set DRAM base Addr */ | ||
222 | s5p_mfc_init_memctrl(dev); | ||
223 | /* 2. Initialize registers of channel I/F */ | ||
224 | s5p_mfc_clear_cmds(dev); | ||
225 | /* 3. Release reset signal to the RISC */ | ||
226 | s5p_mfc_clean_dev_int_flags(dev); | ||
227 | mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); | ||
228 | mfc_debug(2, "Will now wait for completion of firmware transfer\n"); | ||
229 | if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) { | ||
230 | mfc_err("Failed to load firmware\n"); | ||
231 | s5p_mfc_reset(dev); | ||
232 | s5p_mfc_clock_off(); | ||
233 | return -EIO; | ||
234 | } | ||
235 | s5p_mfc_clean_dev_int_flags(dev); | ||
236 | /* 4. Initialize firmware */ | ||
237 | ret = s5p_mfc_sys_init_cmd(dev); | ||
238 | if (ret) { | ||
239 | mfc_err("Failed to send command to MFC - timeout\n"); | ||
240 | s5p_mfc_reset(dev); | ||
241 | s5p_mfc_clock_off(); | ||
242 | return ret; | ||
243 | } | ||
244 | mfc_debug(2, "Ok, now will write a command to init the system\n"); | ||
245 | if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) { | ||
246 | mfc_err("Failed to load firmware\n"); | ||
247 | s5p_mfc_reset(dev); | ||
248 | s5p_mfc_clock_off(); | ||
249 | return -EIO; | ||
250 | } | ||
251 | dev->int_cond = 0; | ||
252 | if (dev->int_err != 0 || dev->int_type != | ||
253 | S5P_FIMV_R2H_CMD_SYS_INIT_RET) { | ||
254 | /* Failure. */ | ||
255 | mfc_err("Failed to init firmware - error: %d int: %d\n", | ||
256 | dev->int_err, dev->int_type); | ||
257 | s5p_mfc_reset(dev); | ||
258 | s5p_mfc_clock_off(); | ||
259 | return -EIO; | ||
260 | } | ||
261 | ver = mfc_read(dev, S5P_FIMV_FW_VERSION); | ||
262 | mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", | ||
263 | (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); | ||
264 | s5p_mfc_clock_off(); | ||
265 | mfc_debug_leave(); | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | |||
270 | int s5p_mfc_sleep(struct s5p_mfc_dev *dev) | ||
271 | { | ||
272 | int ret; | ||
273 | |||
274 | mfc_debug_enter(); | ||
275 | s5p_mfc_clock_on(); | ||
276 | s5p_mfc_clean_dev_int_flags(dev); | ||
277 | ret = s5p_mfc_sleep_cmd(dev); | ||
278 | if (ret) { | ||
279 | mfc_err("Failed to send command to MFC - timeout\n"); | ||
280 | return ret; | ||
281 | } | ||
282 | if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) { | ||
283 | mfc_err("Failed to sleep\n"); | ||
284 | return -EIO; | ||
285 | } | ||
286 | s5p_mfc_clock_off(); | ||
287 | dev->int_cond = 0; | ||
288 | if (dev->int_err != 0 || dev->int_type != | ||
289 | S5P_FIMV_R2H_CMD_SLEEP_RET) { | ||
290 | /* Failure. */ | ||
291 | mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err, | ||
292 | dev->int_type); | ||
293 | return -EIO; | ||
294 | } | ||
295 | mfc_debug_leave(); | ||
296 | return ret; | ||
297 | } | ||
298 | |||
299 | int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) | ||
300 | { | ||
301 | int ret; | ||
302 | |||
303 | mfc_debug_enter(); | ||
304 | /* 0. MFC reset */ | ||
305 | mfc_debug(2, "MFC reset..\n"); | ||
306 | s5p_mfc_clock_on(); | ||
307 | ret = s5p_mfc_reset(dev); | ||
308 | if (ret) { | ||
309 | mfc_err("Failed to reset MFC - timeout\n"); | ||
310 | return ret; | ||
311 | } | ||
312 | mfc_debug(2, "Done MFC reset..\n"); | ||
313 | /* 1. Set DRAM base Addr */ | ||
314 | s5p_mfc_init_memctrl(dev); | ||
315 | /* 2. Initialize registers of channel I/F */ | ||
316 | s5p_mfc_clear_cmds(dev); | ||
317 | s5p_mfc_clean_dev_int_flags(dev); | ||
318 | /* 3. Initialize firmware */ | ||
319 | ret = s5p_mfc_wakeup_cmd(dev); | ||
320 | if (ret) { | ||
321 | mfc_err("Failed to send command to MFC - timeout\n"); | ||
322 | return ret; | ||
323 | } | ||
324 | /* 4. Release reset signal to the RISC */ | ||
325 | mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); | ||
326 | mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); | ||
327 | if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) { | ||
328 | mfc_err("Failed to load firmware\n"); | ||
329 | return -EIO; | ||
330 | } | ||
331 | s5p_mfc_clock_off(); | ||
332 | dev->int_cond = 0; | ||
333 | if (dev->int_err != 0 || dev->int_type != | ||
334 | S5P_FIMV_R2H_CMD_WAKEUP_RET) { | ||
335 | /* Failure. */ | ||
336 | mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err, | ||
337 | dev->int_type); | ||
338 | return -EIO; | ||
339 | } | ||
340 | mfc_debug_leave(); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h new file mode 100644 index 000000000000..61dc23b7ee5a --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.h | ||
3 | * | ||
4 | * Copyright (c) 2010 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_CTRL_H | ||
14 | #define S5P_MFC_CTRL_H | ||
15 | |||
16 | #include "s5p_mfc_common.h" | ||
17 | |||
18 | int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev); | ||
19 | int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev); | ||
20 | int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev); | ||
21 | |||
22 | int s5p_mfc_init_hw(struct s5p_mfc_dev *dev); | ||
23 | |||
24 | int s5p_mfc_sleep(struct s5p_mfc_dev *dev); | ||
25 | int s5p_mfc_wakeup(struct s5p_mfc_dev *dev); | ||
26 | |||
27 | int s5p_mfc_reset(struct s5p_mfc_dev *dev); | ||
28 | |||
29 | #endif /* S5P_MFC_CTRL_H */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_debug.h b/drivers/media/video/s5p-mfc/s5p_mfc_debug.h new file mode 100644 index 000000000000..ecb8616a492a --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_debug.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * drivers/media/video/samsung/mfc5/s5p_mfc_debug.h | ||
3 | * | ||
4 | * Header file for Samsung MFC (Multi Function Codec - FIMV) driver | ||
5 | * This file contains debug macros | ||
6 | * | ||
7 | * Kamil Debski, Copyright (c) 2011 Samsung Electronics | ||
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_DEBUG_H_ | ||
16 | #define S5P_MFC_DEBUG_H_ | ||
17 | |||
18 | #define DEBUG | ||
19 | |||
20 | #ifdef DEBUG | ||
21 | extern int debug; | ||
22 | |||
23 | #define mfc_debug(level, fmt, args...) \ | ||
24 | do { \ | ||
25 | if (debug >= level) \ | ||
26 | printk(KERN_DEBUG "%s:%d: " fmt, \ | ||
27 | __func__, __LINE__, ##args); \ | ||
28 | } while (0) | ||
29 | #else | ||
30 | #define mfc_debug(level, fmt, args...) | ||
31 | #endif | ||
32 | |||
33 | #define mfc_debug_enter() mfc_debug(5, "enter") | ||
34 | #define mfc_debug_leave() mfc_debug(5, "leave") | ||
35 | |||
36 | #define mfc_err(fmt, args...) \ | ||
37 | do { \ | ||
38 | printk(KERN_ERR "%s:%d: " fmt, \ | ||
39 | __func__, __LINE__, ##args); \ | ||
40 | } while (0) | ||
41 | |||
42 | #define mfc_info(fmt, args...) \ | ||
43 | do { \ | ||
44 | printk(KERN_INFO "%s:%d: " fmt, \ | ||
45 | __func__, __LINE__, ##args); \ | ||
46 | } while (0) | ||
47 | |||
48 | #endif /* S5P_MFC_DEBUG_H_ */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c new file mode 100644 index 000000000000..b2c5052a9c41 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c | |||
@@ -0,0 +1,1036 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_dec.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com/ | ||
6 | * Kamil Debski, <k.debski@samsung.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/version.h> | ||
22 | #include <linux/videodev2.h> | ||
23 | #include <linux/workqueue.h> | ||
24 | #include <media/v4l2-ctrls.h> | ||
25 | #include <media/videobuf2-core.h> | ||
26 | #include "regs-mfc.h" | ||
27 | #include "s5p_mfc_common.h" | ||
28 | #include "s5p_mfc_debug.h" | ||
29 | #include "s5p_mfc_dec.h" | ||
30 | #include "s5p_mfc_intr.h" | ||
31 | #include "s5p_mfc_opr.h" | ||
32 | #include "s5p_mfc_pm.h" | ||
33 | #include "s5p_mfc_shm.h" | ||
34 | |||
35 | static struct s5p_mfc_fmt formats[] = { | ||
36 | { | ||
37 | .name = "4:2:0 2 Planes 64x32 Tiles", | ||
38 | .fourcc = V4L2_PIX_FMT_NV12MT, | ||
39 | .codec_mode = S5P_FIMV_CODEC_NONE, | ||
40 | .type = MFC_FMT_RAW, | ||
41 | .num_planes = 2, | ||
42 | }, | ||
43 | { | ||
44 | .name = "4:2:0 2 Planes", | ||
45 | .fourcc = V4L2_PIX_FMT_NV12M, | ||
46 | .codec_mode = S5P_FIMV_CODEC_NONE, | ||
47 | .type = MFC_FMT_RAW, | ||
48 | .num_planes = 2, | ||
49 | }, | ||
50 | { | ||
51 | .name = "H264 Encoded Stream", | ||
52 | .fourcc = V4L2_PIX_FMT_H264, | ||
53 | .codec_mode = S5P_FIMV_CODEC_H264_DEC, | ||
54 | .type = MFC_FMT_DEC, | ||
55 | .num_planes = 1, | ||
56 | }, | ||
57 | { | ||
58 | .name = "H263 Encoded Stream", | ||
59 | .fourcc = V4L2_PIX_FMT_H263, | ||
60 | .codec_mode = S5P_FIMV_CODEC_H263_DEC, | ||
61 | .type = MFC_FMT_DEC, | ||
62 | .num_planes = 1, | ||
63 | }, | ||
64 | { | ||
65 | .name = "MPEG1 Encoded Stream", | ||
66 | .fourcc = V4L2_PIX_FMT_MPEG1, | ||
67 | .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, | ||
68 | .type = MFC_FMT_DEC, | ||
69 | .num_planes = 1, | ||
70 | }, | ||
71 | { | ||
72 | .name = "MPEG2 Encoded Stream", | ||
73 | .fourcc = V4L2_PIX_FMT_MPEG2, | ||
74 | .codec_mode = S5P_FIMV_CODEC_MPEG2_DEC, | ||
75 | .type = MFC_FMT_DEC, | ||
76 | .num_planes = 1, | ||
77 | }, | ||
78 | { | ||
79 | .name = "MPEG4 Encoded Stream", | ||
80 | .fourcc = V4L2_PIX_FMT_MPEG4, | ||
81 | .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, | ||
82 | .type = MFC_FMT_DEC, | ||
83 | .num_planes = 1, | ||
84 | }, | ||
85 | { | ||
86 | .name = "XviD Encoded Stream", | ||
87 | .fourcc = V4L2_PIX_FMT_XVID, | ||
88 | .codec_mode = S5P_FIMV_CODEC_MPEG4_DEC, | ||
89 | .type = MFC_FMT_DEC, | ||
90 | .num_planes = 1, | ||
91 | }, | ||
92 | { | ||
93 | .name = "VC1 Encoded Stream", | ||
94 | .fourcc = V4L2_PIX_FMT_VC1_ANNEX_G, | ||
95 | .codec_mode = S5P_FIMV_CODEC_VC1_DEC, | ||
96 | .type = MFC_FMT_DEC, | ||
97 | .num_planes = 1, | ||
98 | }, | ||
99 | { | ||
100 | .name = "VC1 RCV Encoded Stream", | ||
101 | .fourcc = V4L2_PIX_FMT_VC1_ANNEX_L, | ||
102 | .codec_mode = S5P_FIMV_CODEC_VC1RCV_DEC, | ||
103 | .type = MFC_FMT_DEC, | ||
104 | .num_planes = 1, | ||
105 | }, | ||
106 | }; | ||
107 | |||
108 | #define NUM_FORMATS ARRAY_SIZE(formats) | ||
109 | |||
110 | /* Find selected format description */ | ||
111 | static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) | ||
112 | { | ||
113 | unsigned int i; | ||
114 | |||
115 | for (i = 0; i < NUM_FORMATS; i++) { | ||
116 | if (formats[i].fourcc == f->fmt.pix_mp.pixelformat && | ||
117 | formats[i].type == t) | ||
118 | return &formats[i]; | ||
119 | } | ||
120 | return NULL; | ||
121 | } | ||
122 | |||
123 | static struct mfc_control controls[] = { | ||
124 | { | ||
125 | .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY, | ||
126 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
127 | .name = "H264 Display Delay", | ||
128 | .minimum = 0, | ||
129 | .maximum = 16383, | ||
130 | .step = 1, | ||
131 | .default_value = 0, | ||
132 | }, | ||
133 | { | ||
134 | .id = V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE, | ||
135 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
136 | .name = "H264 Display Delay Enable", | ||
137 | .minimum = 0, | ||
138 | .maximum = 1, | ||
139 | .step = 1, | ||
140 | .default_value = 0, | ||
141 | }, | ||
142 | { | ||
143 | .id = V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, | ||
144 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
145 | .name = "Mpeg4 Loop Filter Enable", | ||
146 | .minimum = 0, | ||
147 | .maximum = 1, | ||
148 | .step = 1, | ||
149 | .default_value = 0, | ||
150 | }, | ||
151 | { | ||
152 | .id = V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, | ||
153 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
154 | .name = "Slice Interface Enable", | ||
155 | .minimum = 0, | ||
156 | .maximum = 1, | ||
157 | .step = 1, | ||
158 | .default_value = 0, | ||
159 | }, | ||
160 | { | ||
161 | .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, | ||
162 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
163 | .name = "Minimum number of cap bufs", | ||
164 | .minimum = 1, | ||
165 | .maximum = 32, | ||
166 | .step = 1, | ||
167 | .default_value = 1, | ||
168 | .is_volatile = 1, | ||
169 | }, | ||
170 | }; | ||
171 | |||
172 | #define NUM_CTRLS ARRAY_SIZE(controls) | ||
173 | |||
174 | /* Check whether a context should be run on hardware */ | ||
175 | static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) | ||
176 | { | ||
177 | /* Context is to parse header */ | ||
178 | if (ctx->src_queue_cnt >= 1 && ctx->state == MFCINST_GOT_INST) | ||
179 | return 1; | ||
180 | /* Context is to decode a frame */ | ||
181 | if (ctx->src_queue_cnt >= 1 && | ||
182 | ctx->state == MFCINST_RUNNING && | ||
183 | ctx->dst_queue_cnt >= ctx->dpb_count) | ||
184 | return 1; | ||
185 | /* Context is to return last frame */ | ||
186 | if (ctx->state == MFCINST_FINISHING && | ||
187 | ctx->dst_queue_cnt >= ctx->dpb_count) | ||
188 | return 1; | ||
189 | /* Context is to set buffers */ | ||
190 | if (ctx->src_queue_cnt >= 1 && | ||
191 | ctx->state == MFCINST_HEAD_PARSED && | ||
192 | ctx->capture_state == QUEUE_BUFS_MMAPED) | ||
193 | return 1; | ||
194 | /* Resolution change */ | ||
195 | if ((ctx->state == MFCINST_RES_CHANGE_INIT || | ||
196 | ctx->state == MFCINST_RES_CHANGE_FLUSH) && | ||
197 | ctx->dst_queue_cnt >= ctx->dpb_count) | ||
198 | return 1; | ||
199 | if (ctx->state == MFCINST_RES_CHANGE_END && | ||
200 | ctx->src_queue_cnt >= 1) | ||
201 | return 1; | ||
202 | mfc_debug(2, "ctx is not ready\n"); | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static struct s5p_mfc_codec_ops decoder_codec_ops = { | ||
207 | .pre_seq_start = NULL, | ||
208 | .post_seq_start = NULL, | ||
209 | .pre_frame_start = NULL, | ||
210 | .post_frame_start = NULL, | ||
211 | }; | ||
212 | |||
213 | /* Query capabilities of the device */ | ||
214 | static int vidioc_querycap(struct file *file, void *priv, | ||
215 | struct v4l2_capability *cap) | ||
216 | { | ||
217 | struct s5p_mfc_dev *dev = video_drvdata(file); | ||
218 | |||
219 | strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1); | ||
220 | strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1); | ||
221 | cap->bus_info[0] = 0; | ||
222 | cap->version = KERNEL_VERSION(1, 0, 0); | ||
223 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | ||
224 | | V4L2_CAP_STREAMING; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | /* Enumerate format */ | ||
229 | static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out) | ||
230 | { | ||
231 | struct s5p_mfc_fmt *fmt; | ||
232 | int i, j = 0; | ||
233 | |||
234 | for (i = 0; i < ARRAY_SIZE(formats); ++i) { | ||
235 | if (mplane && formats[i].num_planes == 1) | ||
236 | continue; | ||
237 | else if (!mplane && formats[i].num_planes > 1) | ||
238 | continue; | ||
239 | if (out && formats[i].type != MFC_FMT_DEC) | ||
240 | continue; | ||
241 | else if (!out && formats[i].type != MFC_FMT_RAW) | ||
242 | continue; | ||
243 | |||
244 | if (j == f->index) | ||
245 | break; | ||
246 | ++j; | ||
247 | } | ||
248 | if (i == ARRAY_SIZE(formats)) | ||
249 | return -EINVAL; | ||
250 | fmt = &formats[i]; | ||
251 | strlcpy(f->description, fmt->name, sizeof(f->description)); | ||
252 | f->pixelformat = fmt->fourcc; | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, | ||
257 | struct v4l2_fmtdesc *f) | ||
258 | { | ||
259 | return vidioc_enum_fmt(f, false, false); | ||
260 | } | ||
261 | |||
262 | static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, | ||
263 | struct v4l2_fmtdesc *f) | ||
264 | { | ||
265 | return vidioc_enum_fmt(f, true, false); | ||
266 | } | ||
267 | |||
268 | static int vidioc_enum_fmt_vid_out(struct file *file, void *prov, | ||
269 | struct v4l2_fmtdesc *f) | ||
270 | { | ||
271 | return vidioc_enum_fmt(f, false, true); | ||
272 | } | ||
273 | |||
274 | static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, | ||
275 | struct v4l2_fmtdesc *f) | ||
276 | { | ||
277 | return vidioc_enum_fmt(f, true, true); | ||
278 | } | ||
279 | |||
280 | /* Get format */ | ||
281 | static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | ||
282 | { | ||
283 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
284 | struct v4l2_pix_format_mplane *pix_mp; | ||
285 | |||
286 | mfc_debug_enter(); | ||
287 | pix_mp = &f->fmt.pix_mp; | ||
288 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | ||
289 | (ctx->state == MFCINST_GOT_INST || ctx->state == | ||
290 | MFCINST_RES_CHANGE_END)) { | ||
291 | /* If the MFC is parsing the header, | ||
292 | * so wait until it is finished */ | ||
293 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
294 | s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_SEQ_DONE_RET, | ||
295 | 0); | ||
296 | } | ||
297 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && | ||
298 | ctx->state >= MFCINST_HEAD_PARSED && | ||
299 | ctx->state < MFCINST_ABORT) { | ||
300 | /* This is run on CAPTURE (decode output) */ | ||
301 | /* Width and height are set to the dimensions | ||
302 | of the movie, the buffer is bigger and | ||
303 | further processing stages should crop to this | ||
304 | rectangle. */ | ||
305 | pix_mp->width = ctx->buf_width; | ||
306 | pix_mp->height = ctx->buf_height; | ||
307 | pix_mp->field = V4L2_FIELD_NONE; | ||
308 | pix_mp->num_planes = 2; | ||
309 | /* Set pixelformat to the format in which MFC | ||
310 | outputs the decoded frame */ | ||
311 | pix_mp->pixelformat = V4L2_PIX_FMT_NV12MT; | ||
312 | pix_mp->plane_fmt[0].bytesperline = ctx->buf_width; | ||
313 | pix_mp->plane_fmt[0].sizeimage = ctx->luma_size; | ||
314 | pix_mp->plane_fmt[1].bytesperline = ctx->buf_width; | ||
315 | pix_mp->plane_fmt[1].sizeimage = ctx->chroma_size; | ||
316 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
317 | /* This is run on OUTPUT | ||
318 | The buffer contains compressed image | ||
319 | so width and height have no meaning */ | ||
320 | pix_mp->width = 0; | ||
321 | pix_mp->height = 0; | ||
322 | pix_mp->field = V4L2_FIELD_NONE; | ||
323 | pix_mp->plane_fmt[0].bytesperline = ctx->dec_src_buf_size; | ||
324 | pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size; | ||
325 | pix_mp->pixelformat = ctx->src_fmt->fourcc; | ||
326 | pix_mp->num_planes = ctx->src_fmt->num_planes; | ||
327 | } else { | ||
328 | mfc_err("Format could not be read\n"); | ||
329 | mfc_debug(2, "%s-- with error\n", __func__); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | mfc_debug_leave(); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | /* Try format */ | ||
337 | static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) | ||
338 | { | ||
339 | struct s5p_mfc_fmt *fmt; | ||
340 | |||
341 | if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
342 | mfc_err("This node supports decoding only\n"); | ||
343 | return -EINVAL; | ||
344 | } | ||
345 | fmt = find_format(f, MFC_FMT_DEC); | ||
346 | if (!fmt) { | ||
347 | mfc_err("Unsupported format\n"); | ||
348 | return -EINVAL; | ||
349 | } | ||
350 | if (fmt->type != MFC_FMT_DEC) { | ||
351 | mfc_err("\n"); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* Set format */ | ||
358 | static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | ||
359 | { | ||
360 | struct s5p_mfc_dev *dev = video_drvdata(file); | ||
361 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
362 | int ret = 0; | ||
363 | struct s5p_mfc_fmt *fmt; | ||
364 | struct v4l2_pix_format_mplane *pix_mp; | ||
365 | |||
366 | mfc_debug_enter(); | ||
367 | ret = vidioc_try_fmt(file, priv, f); | ||
368 | pix_mp = &f->fmt.pix_mp; | ||
369 | if (ret) | ||
370 | return ret; | ||
371 | if (ctx->vq_src.streaming || ctx->vq_dst.streaming) { | ||
372 | v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); | ||
373 | ret = -EBUSY; | ||
374 | goto out; | ||
375 | } | ||
376 | fmt = find_format(f, MFC_FMT_DEC); | ||
377 | if (!fmt || fmt->codec_mode == S5P_FIMV_CODEC_NONE) { | ||
378 | mfc_err("Unknown codec\n"); | ||
379 | ret = -EINVAL; | ||
380 | goto out; | ||
381 | } | ||
382 | if (fmt->type != MFC_FMT_DEC) { | ||
383 | mfc_err("Wrong format selected, you should choose " | ||
384 | "format for decoding\n"); | ||
385 | ret = -EINVAL; | ||
386 | goto out; | ||
387 | } | ||
388 | ctx->src_fmt = fmt; | ||
389 | ctx->codec_mode = fmt->codec_mode; | ||
390 | mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode); | ||
391 | pix_mp->height = 0; | ||
392 | pix_mp->width = 0; | ||
393 | if (pix_mp->plane_fmt[0].sizeimage) | ||
394 | ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage; | ||
395 | else | ||
396 | pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size = | ||
397 | DEF_CPB_SIZE; | ||
398 | pix_mp->plane_fmt[0].bytesperline = 0; | ||
399 | ctx->state = MFCINST_INIT; | ||
400 | out: | ||
401 | mfc_debug_leave(); | ||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | /* Reqeust buffers */ | ||
406 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
407 | struct v4l2_requestbuffers *reqbufs) | ||
408 | { | ||
409 | struct s5p_mfc_dev *dev = video_drvdata(file); | ||
410 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
411 | int ret = 0; | ||
412 | unsigned long flags; | ||
413 | |||
414 | if (reqbufs->memory != V4L2_MEMORY_MMAP) { | ||
415 | mfc_err("Only V4L2_MEMORY_MAP is supported\n"); | ||
416 | return -EINVAL; | ||
417 | } | ||
418 | if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
419 | /* Can only request buffers after an instance has been opened.*/ | ||
420 | if (ctx->state == MFCINST_INIT) { | ||
421 | ctx->src_bufs_cnt = 0; | ||
422 | if (reqbufs->count == 0) { | ||
423 | mfc_debug(2, "Freeing buffers\n"); | ||
424 | s5p_mfc_clock_on(); | ||
425 | ret = vb2_reqbufs(&ctx->vq_src, reqbufs); | ||
426 | s5p_mfc_clock_off(); | ||
427 | return ret; | ||
428 | } | ||
429 | /* Decoding */ | ||
430 | if (ctx->output_state != QUEUE_FREE) { | ||
431 | mfc_err("Bufs have already been requested\n"); | ||
432 | return -EINVAL; | ||
433 | } | ||
434 | s5p_mfc_clock_on(); | ||
435 | ret = vb2_reqbufs(&ctx->vq_src, reqbufs); | ||
436 | s5p_mfc_clock_off(); | ||
437 | if (ret) { | ||
438 | mfc_err("vb2_reqbufs on output failed\n"); | ||
439 | return ret; | ||
440 | } | ||
441 | mfc_debug(2, "vb2_reqbufs: %d\n", ret); | ||
442 | ctx->output_state = QUEUE_BUFS_REQUESTED; | ||
443 | } | ||
444 | } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
445 | ctx->dst_bufs_cnt = 0; | ||
446 | if (reqbufs->count == 0) { | ||
447 | mfc_debug(2, "Freeing buffers\n"); | ||
448 | s5p_mfc_clock_on(); | ||
449 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | ||
450 | s5p_mfc_clock_off(); | ||
451 | return ret; | ||
452 | } | ||
453 | if (ctx->capture_state != QUEUE_FREE) { | ||
454 | mfc_err("Bufs have already been requested\n"); | ||
455 | return -EINVAL; | ||
456 | } | ||
457 | ctx->capture_state = QUEUE_BUFS_REQUESTED; | ||
458 | s5p_mfc_clock_on(); | ||
459 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | ||
460 | s5p_mfc_clock_off(); | ||
461 | if (ret) { | ||
462 | mfc_err("vb2_reqbufs on capture failed\n"); | ||
463 | return ret; | ||
464 | } | ||
465 | if (reqbufs->count < ctx->dpb_count) { | ||
466 | mfc_err("Not enough buffers allocated\n"); | ||
467 | reqbufs->count = 0; | ||
468 | s5p_mfc_clock_on(); | ||
469 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | ||
470 | s5p_mfc_clock_off(); | ||
471 | return -ENOMEM; | ||
472 | } | ||
473 | ctx->total_dpb_count = reqbufs->count; | ||
474 | ret = s5p_mfc_alloc_codec_buffers(ctx); | ||
475 | if (ret) { | ||
476 | mfc_err("Failed to allocate decoding buffers\n"); | ||
477 | reqbufs->count = 0; | ||
478 | s5p_mfc_clock_on(); | ||
479 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | ||
480 | s5p_mfc_clock_off(); | ||
481 | return -ENOMEM; | ||
482 | } | ||
483 | if (ctx->dst_bufs_cnt == ctx->total_dpb_count) { | ||
484 | ctx->capture_state = QUEUE_BUFS_MMAPED; | ||
485 | } else { | ||
486 | mfc_err("Not all buffers passed to buf_init\n"); | ||
487 | reqbufs->count = 0; | ||
488 | s5p_mfc_clock_on(); | ||
489 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | ||
490 | s5p_mfc_release_codec_buffers(ctx); | ||
491 | s5p_mfc_clock_off(); | ||
492 | return -ENOMEM; | ||
493 | } | ||
494 | if (s5p_mfc_ctx_ready(ctx)) { | ||
495 | spin_lock_irqsave(&dev->condlock, flags); | ||
496 | set_bit(ctx->num, &dev->ctx_work_bits); | ||
497 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
498 | } | ||
499 | s5p_mfc_try_run(dev); | ||
500 | s5p_mfc_wait_for_done_ctx(ctx, | ||
501 | S5P_FIMV_R2H_CMD_INIT_BUFFERS_RET, 0); | ||
502 | } | ||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | /* Query buffer */ | ||
507 | static int vidioc_querybuf(struct file *file, void *priv, | ||
508 | struct v4l2_buffer *buf) | ||
509 | { | ||
510 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
511 | int ret; | ||
512 | int i; | ||
513 | |||
514 | if (buf->memory != V4L2_MEMORY_MMAP) { | ||
515 | mfc_err("Only mmaped buffers can be used\n"); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type); | ||
519 | if (ctx->state == MFCINST_INIT && | ||
520 | buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
521 | ret = vb2_querybuf(&ctx->vq_src, buf); | ||
522 | } else if (ctx->state == MFCINST_RUNNING && | ||
523 | buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
524 | ret = vb2_querybuf(&ctx->vq_dst, buf); | ||
525 | for (i = 0; i < buf->length; i++) | ||
526 | buf->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE; | ||
527 | } else { | ||
528 | mfc_err("vidioc_querybuf called in an inappropriate state\n"); | ||
529 | ret = -EINVAL; | ||
530 | } | ||
531 | mfc_debug_leave(); | ||
532 | return ret; | ||
533 | } | ||
534 | |||
535 | /* Queue a buffer */ | ||
536 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
537 | { | ||
538 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
539 | |||
540 | if (ctx->state == MFCINST_ERROR) { | ||
541 | mfc_err("Call on QBUF after unrecoverable error\n"); | ||
542 | return -EIO; | ||
543 | } | ||
544 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
545 | return vb2_qbuf(&ctx->vq_src, buf); | ||
546 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
547 | return vb2_qbuf(&ctx->vq_dst, buf); | ||
548 | return -EINVAL; | ||
549 | } | ||
550 | |||
551 | /* Dequeue a buffer */ | ||
552 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
553 | { | ||
554 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
555 | |||
556 | if (ctx->state == MFCINST_ERROR) { | ||
557 | mfc_err("Call on DQBUF after unrecoverable error\n"); | ||
558 | return -EIO; | ||
559 | } | ||
560 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
561 | return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); | ||
562 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
563 | return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); | ||
564 | return -EINVAL; | ||
565 | } | ||
566 | |||
567 | /* Stream on */ | ||
568 | static int vidioc_streamon(struct file *file, void *priv, | ||
569 | enum v4l2_buf_type type) | ||
570 | { | ||
571 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
572 | struct s5p_mfc_dev *dev = ctx->dev; | ||
573 | unsigned long flags; | ||
574 | int ret = -EINVAL; | ||
575 | |||
576 | mfc_debug_enter(); | ||
577 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
578 | |||
579 | if (ctx->state == MFCINST_INIT) { | ||
580 | ctx->dst_bufs_cnt = 0; | ||
581 | ctx->src_bufs_cnt = 0; | ||
582 | ctx->capture_state = QUEUE_FREE; | ||
583 | ctx->output_state = QUEUE_FREE; | ||
584 | s5p_mfc_alloc_instance_buffer(ctx); | ||
585 | s5p_mfc_alloc_dec_temp_buffers(ctx); | ||
586 | spin_lock_irqsave(&dev->condlock, flags); | ||
587 | set_bit(ctx->num, &dev->ctx_work_bits); | ||
588 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
589 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
590 | s5p_mfc_try_run(dev); | ||
591 | |||
592 | if (s5p_mfc_wait_for_done_ctx(ctx, | ||
593 | S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 0)) { | ||
594 | /* Error or timeout */ | ||
595 | mfc_err("Error getting instance from hardware\n"); | ||
596 | s5p_mfc_release_instance_buffer(ctx); | ||
597 | s5p_mfc_release_dec_desc_buffer(ctx); | ||
598 | return -EIO; | ||
599 | } | ||
600 | mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); | ||
601 | } | ||
602 | ret = vb2_streamon(&ctx->vq_src, type); | ||
603 | } | ||
604 | else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
605 | ret = vb2_streamon(&ctx->vq_dst, type); | ||
606 | mfc_debug_leave(); | ||
607 | return ret; | ||
608 | } | ||
609 | |||
610 | /* Stream off, which equals to a pause */ | ||
611 | static int vidioc_streamoff(struct file *file, void *priv, | ||
612 | enum v4l2_buf_type type) | ||
613 | { | ||
614 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
615 | |||
616 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
617 | return vb2_streamoff(&ctx->vq_src, type); | ||
618 | else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
619 | return vb2_streamoff(&ctx->vq_dst, type); | ||
620 | return -EINVAL; | ||
621 | } | ||
622 | |||
623 | /* Set controls - v4l2 control framework */ | ||
624 | static int s5p_mfc_dec_s_ctrl(struct v4l2_ctrl *ctrl) | ||
625 | { | ||
626 | struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); | ||
627 | |||
628 | switch (ctrl->id) { | ||
629 | case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY: | ||
630 | ctx->loop_filter_mpeg4 = ctrl->val; | ||
631 | break; | ||
632 | case V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE: | ||
633 | ctx->display_delay_enable = ctrl->val; | ||
634 | break; | ||
635 | case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: | ||
636 | ctx->display_delay = ctrl->val; | ||
637 | break; | ||
638 | case V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: | ||
639 | ctx->slice_interface = ctrl->val; | ||
640 | break; | ||
641 | default: | ||
642 | mfc_err("Invalid control 0x%08x\n", ctrl->id); | ||
643 | return -EINVAL; | ||
644 | } | ||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl) | ||
649 | { | ||
650 | struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); | ||
651 | struct s5p_mfc_dev *dev = ctx->dev; | ||
652 | |||
653 | switch (ctrl->id) { | ||
654 | case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: | ||
655 | if (ctx->state >= MFCINST_HEAD_PARSED && | ||
656 | ctx->state < MFCINST_ABORT) { | ||
657 | ctrl->val = ctx->dpb_count; | ||
658 | break; | ||
659 | } else if (ctx->state != MFCINST_INIT) { | ||
660 | v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); | ||
661 | return -EINVAL; | ||
662 | } | ||
663 | /* Should wait for the header to be parsed */ | ||
664 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
665 | s5p_mfc_wait_for_done_ctx(ctx, | ||
666 | S5P_FIMV_R2H_CMD_SEQ_DONE_RET, 0); | ||
667 | if (ctx->state >= MFCINST_HEAD_PARSED && | ||
668 | ctx->state < MFCINST_ABORT) { | ||
669 | ctrl->val = ctx->dpb_count; | ||
670 | } else { | ||
671 | v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n"); | ||
672 | return -EINVAL; | ||
673 | } | ||
674 | break; | ||
675 | } | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | |||
680 | static const struct v4l2_ctrl_ops s5p_mfc_dec_ctrl_ops = { | ||
681 | .s_ctrl = s5p_mfc_dec_s_ctrl, | ||
682 | .g_volatile_ctrl = s5p_mfc_dec_g_v_ctrl, | ||
683 | }; | ||
684 | |||
685 | /* Get cropping information */ | ||
686 | static int vidioc_g_crop(struct file *file, void *priv, | ||
687 | struct v4l2_crop *cr) | ||
688 | { | ||
689 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
690 | u32 left, right, top, bottom; | ||
691 | |||
692 | if (ctx->state != MFCINST_HEAD_PARSED && | ||
693 | ctx->state != MFCINST_RUNNING && ctx->state != MFCINST_FINISHING | ||
694 | && ctx->state != MFCINST_FINISHED) { | ||
695 | mfc_err("Cannont set crop\n"); | ||
696 | return -EINVAL; | ||
697 | } | ||
698 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_H264) { | ||
699 | left = s5p_mfc_read_shm(ctx, CROP_INFO_H); | ||
700 | right = left >> S5P_FIMV_SHARED_CROP_RIGHT_SHIFT; | ||
701 | left = left & S5P_FIMV_SHARED_CROP_LEFT_MASK; | ||
702 | top = s5p_mfc_read_shm(ctx, CROP_INFO_V); | ||
703 | bottom = top >> S5P_FIMV_SHARED_CROP_BOTTOM_SHIFT; | ||
704 | top = top & S5P_FIMV_SHARED_CROP_TOP_MASK; | ||
705 | cr->c.left = left; | ||
706 | cr->c.top = top; | ||
707 | cr->c.width = ctx->img_width - left - right; | ||
708 | cr->c.height = ctx->img_height - top - bottom; | ||
709 | mfc_debug(2, "Cropping info [h264]: l=%d t=%d " | ||
710 | "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top, | ||
711 | cr->c.width, cr->c.height, right, bottom, | ||
712 | ctx->buf_width, ctx->buf_height); | ||
713 | } else { | ||
714 | cr->c.left = 0; | ||
715 | cr->c.top = 0; | ||
716 | cr->c.width = ctx->img_width; | ||
717 | cr->c.height = ctx->img_height; | ||
718 | mfc_debug(2, "Cropping info: w=%d h=%d fw=%d " | ||
719 | "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width, | ||
720 | ctx->buf_height); | ||
721 | } | ||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | /* v4l2_ioctl_ops */ | ||
726 | static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { | ||
727 | .vidioc_querycap = vidioc_querycap, | ||
728 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
729 | .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, | ||
730 | .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, | ||
731 | .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, | ||
732 | .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, | ||
733 | .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, | ||
734 | .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, | ||
735 | .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, | ||
736 | .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, | ||
737 | .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, | ||
738 | .vidioc_reqbufs = vidioc_reqbufs, | ||
739 | .vidioc_querybuf = vidioc_querybuf, | ||
740 | .vidioc_qbuf = vidioc_qbuf, | ||
741 | .vidioc_dqbuf = vidioc_dqbuf, | ||
742 | .vidioc_streamon = vidioc_streamon, | ||
743 | .vidioc_streamoff = vidioc_streamoff, | ||
744 | .vidioc_g_crop = vidioc_g_crop, | ||
745 | }; | ||
746 | |||
747 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, unsigned int *buf_count, | ||
748 | unsigned int *plane_count, unsigned long psize[], | ||
749 | void *allocators[]) | ||
750 | { | ||
751 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | ||
752 | |||
753 | /* Video output for decoding (source) | ||
754 | * this can be set after getting an instance */ | ||
755 | if (ctx->state == MFCINST_INIT && | ||
756 | vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
757 | /* A single plane is required for input */ | ||
758 | *plane_count = 1; | ||
759 | if (*buf_count < 1) | ||
760 | *buf_count = 1; | ||
761 | if (*buf_count > MFC_MAX_BUFFERS) | ||
762 | *buf_count = MFC_MAX_BUFFERS; | ||
763 | /* Video capture for decoding (destination) | ||
764 | * this can be set after the header was parsed */ | ||
765 | } else if (ctx->state == MFCINST_HEAD_PARSED && | ||
766 | vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
767 | /* Output plane count is 2 - one for Y and one for CbCr */ | ||
768 | *plane_count = 2; | ||
769 | /* Setup buffer count */ | ||
770 | if (*buf_count < ctx->dpb_count) | ||
771 | *buf_count = ctx->dpb_count; | ||
772 | if (*buf_count > ctx->dpb_count + MFC_MAX_EXTRA_DPB) | ||
773 | *buf_count = ctx->dpb_count + MFC_MAX_EXTRA_DPB; | ||
774 | if (*buf_count > MFC_MAX_BUFFERS) | ||
775 | *buf_count = MFC_MAX_BUFFERS; | ||
776 | } else { | ||
777 | mfc_err("State seems invalid. State = %d, vq->type = %d\n", | ||
778 | ctx->state, vq->type); | ||
779 | return -EINVAL; | ||
780 | } | ||
781 | mfc_debug(2, "Buffer count=%d, plane count=%d\n", | ||
782 | *buf_count, *plane_count); | ||
783 | if (ctx->state == MFCINST_HEAD_PARSED && | ||
784 | vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
785 | psize[0] = ctx->luma_size; | ||
786 | psize[1] = ctx->chroma_size; | ||
787 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | ||
788 | allocators[1] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | ||
789 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && | ||
790 | ctx->state == MFCINST_INIT) { | ||
791 | psize[0] = ctx->dec_src_buf_size; | ||
792 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | ||
793 | } else { | ||
794 | mfc_err("This video node is dedicated to decoding. Decoding not initalised\n"); | ||
795 | return -EINVAL; | ||
796 | } | ||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | static void s5p_mfc_unlock(struct vb2_queue *q) | ||
801 | { | ||
802 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | ||
803 | struct s5p_mfc_dev *dev = ctx->dev; | ||
804 | |||
805 | mutex_unlock(&dev->mfc_mutex); | ||
806 | } | ||
807 | |||
808 | static void s5p_mfc_lock(struct vb2_queue *q) | ||
809 | { | ||
810 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | ||
811 | struct s5p_mfc_dev *dev = ctx->dev; | ||
812 | |||
813 | mutex_lock(&dev->mfc_mutex); | ||
814 | } | ||
815 | |||
816 | static int s5p_mfc_buf_init(struct vb2_buffer *vb) | ||
817 | { | ||
818 | struct vb2_queue *vq = vb->vb2_queue; | ||
819 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | ||
820 | unsigned int i; | ||
821 | |||
822 | if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
823 | if (ctx->capture_state == QUEUE_BUFS_MMAPED) | ||
824 | return 0; | ||
825 | for (i = 0; i <= ctx->src_fmt->num_planes ; i++) { | ||
826 | if (IS_ERR_OR_NULL(ERR_PTR( | ||
827 | vb2_dma_contig_plane_paddr(vb, i)))) { | ||
828 | mfc_err("Plane mem not allocated\n"); | ||
829 | return -EINVAL; | ||
830 | } | ||
831 | } | ||
832 | if (vb2_plane_size(vb, 0) < ctx->luma_size || | ||
833 | vb2_plane_size(vb, 1) < ctx->chroma_size) { | ||
834 | mfc_err("Plane buffer (CAPTURE) is too small\n"); | ||
835 | return -EINVAL; | ||
836 | } | ||
837 | i = vb->v4l2_buf.index; | ||
838 | ctx->dst_bufs[i].b = vb; | ||
839 | ctx->dst_bufs[i].cookie.raw.luma = | ||
840 | vb2_dma_contig_plane_paddr(vb, 0); | ||
841 | ctx->dst_bufs[i].cookie.raw.chroma = | ||
842 | vb2_dma_contig_plane_paddr(vb, 1); | ||
843 | ctx->dst_bufs_cnt++; | ||
844 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
845 | if (IS_ERR_OR_NULL(ERR_PTR( | ||
846 | vb2_dma_contig_plane_paddr(vb, 0)))) { | ||
847 | mfc_err("Plane memory not allocated\n"); | ||
848 | return -EINVAL; | ||
849 | } | ||
850 | if (vb2_plane_size(vb, 0) < ctx->dec_src_buf_size) { | ||
851 | mfc_err("Plane buffer (OUTPUT) is too small\n"); | ||
852 | return -EINVAL; | ||
853 | } | ||
854 | |||
855 | i = vb->v4l2_buf.index; | ||
856 | ctx->src_bufs[i].b = vb; | ||
857 | ctx->src_bufs[i].cookie.stream = | ||
858 | vb2_dma_contig_plane_paddr(vb, 0); | ||
859 | ctx->src_bufs_cnt++; | ||
860 | } else { | ||
861 | mfc_err("s5p_mfc_buf_init: unknown queue type\n"); | ||
862 | return -EINVAL; | ||
863 | } | ||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | static int s5p_mfc_start_streaming(struct vb2_queue *q) | ||
868 | { | ||
869 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | ||
870 | struct s5p_mfc_dev *dev = ctx->dev; | ||
871 | unsigned long flags; | ||
872 | |||
873 | v4l2_ctrl_handler_setup(&ctx->ctrl_handler); | ||
874 | if (ctx->state == MFCINST_FINISHING || | ||
875 | ctx->state == MFCINST_FINISHED) | ||
876 | ctx->state = MFCINST_RUNNING; | ||
877 | /* If context is ready then dev = work->data;schedule it to run */ | ||
878 | if (s5p_mfc_ctx_ready(ctx)) { | ||
879 | spin_lock_irqsave(&dev->condlock, flags); | ||
880 | set_bit(ctx->num, &dev->ctx_work_bits); | ||
881 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
882 | } | ||
883 | s5p_mfc_try_run(dev); | ||
884 | return 0; | ||
885 | } | ||
886 | |||
887 | static int s5p_mfc_stop_streaming(struct vb2_queue *q) | ||
888 | { | ||
889 | unsigned long flags; | ||
890 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | ||
891 | struct s5p_mfc_dev *dev = ctx->dev; | ||
892 | int aborted = 0; | ||
893 | |||
894 | if ((ctx->state == MFCINST_FINISHING || | ||
895 | ctx->state == MFCINST_RUNNING) && | ||
896 | dev->curr_ctx == ctx->num && dev->hw_lock) { | ||
897 | ctx->state = MFCINST_ABORT; | ||
898 | s5p_mfc_wait_for_done_ctx(ctx, | ||
899 | S5P_FIMV_R2H_CMD_FRAME_DONE_RET, 0); | ||
900 | aborted = 1; | ||
901 | } | ||
902 | spin_lock_irqsave(&dev->irqlock, flags); | ||
903 | if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
904 | s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); | ||
905 | INIT_LIST_HEAD(&ctx->dst_queue); | ||
906 | ctx->dst_queue_cnt = 0; | ||
907 | ctx->dpb_flush_flag = 1; | ||
908 | ctx->dec_dst_flag = 0; | ||
909 | } | ||
910 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
911 | s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); | ||
912 | INIT_LIST_HEAD(&ctx->src_queue); | ||
913 | ctx->src_queue_cnt = 0; | ||
914 | } | ||
915 | if (aborted) | ||
916 | ctx->state = MFCINST_RUNNING; | ||
917 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | |||
922 | static void s5p_mfc_buf_queue(struct vb2_buffer *vb) | ||
923 | { | ||
924 | struct vb2_queue *vq = vb->vb2_queue; | ||
925 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | ||
926 | struct s5p_mfc_dev *dev = ctx->dev; | ||
927 | unsigned long flags; | ||
928 | struct s5p_mfc_buf *mfc_buf; | ||
929 | |||
930 | if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
931 | mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index]; | ||
932 | mfc_buf->used = 0; | ||
933 | spin_lock_irqsave(&dev->irqlock, flags); | ||
934 | list_add_tail(&mfc_buf->list, &ctx->src_queue); | ||
935 | ctx->src_queue_cnt++; | ||
936 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
937 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
938 | mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index]; | ||
939 | mfc_buf->used = 0; | ||
940 | /* Mark destination as available for use by MFC */ | ||
941 | spin_lock_irqsave(&dev->irqlock, flags); | ||
942 | set_bit(vb->v4l2_buf.index, &ctx->dec_dst_flag); | ||
943 | list_add_tail(&mfc_buf->list, &ctx->dst_queue); | ||
944 | ctx->dst_queue_cnt++; | ||
945 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
946 | } else { | ||
947 | mfc_err("Unsupported buffer type (%d)\n", vq->type); | ||
948 | } | ||
949 | if (s5p_mfc_ctx_ready(ctx)) { | ||
950 | spin_lock_irqsave(&dev->condlock, flags); | ||
951 | set_bit(ctx->num, &dev->ctx_work_bits); | ||
952 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
953 | } | ||
954 | s5p_mfc_try_run(dev); | ||
955 | } | ||
956 | |||
957 | static struct vb2_ops s5p_mfc_dec_qops = { | ||
958 | .queue_setup = s5p_mfc_queue_setup, | ||
959 | .wait_prepare = s5p_mfc_unlock, | ||
960 | .wait_finish = s5p_mfc_lock, | ||
961 | .buf_init = s5p_mfc_buf_init, | ||
962 | .start_streaming = s5p_mfc_start_streaming, | ||
963 | .stop_streaming = s5p_mfc_stop_streaming, | ||
964 | .buf_queue = s5p_mfc_buf_queue, | ||
965 | }; | ||
966 | |||
967 | struct s5p_mfc_codec_ops *get_dec_codec_ops(void) | ||
968 | { | ||
969 | return &decoder_codec_ops; | ||
970 | } | ||
971 | |||
972 | struct vb2_ops *get_dec_queue_ops(void) | ||
973 | { | ||
974 | return &s5p_mfc_dec_qops; | ||
975 | } | ||
976 | |||
977 | const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void) | ||
978 | { | ||
979 | return &s5p_mfc_dec_ioctl_ops; | ||
980 | } | ||
981 | |||
982 | #define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \ | ||
983 | && V4L2_CTRL_DRIVER_PRIV(x)) | ||
984 | |||
985 | int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx) | ||
986 | { | ||
987 | struct v4l2_ctrl_config cfg; | ||
988 | int i; | ||
989 | |||
990 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS); | ||
991 | if (ctx->ctrl_handler.error) { | ||
992 | mfc_err("v4l2_ctrl_handler_init failed\n"); | ||
993 | return ctx->ctrl_handler.error; | ||
994 | } | ||
995 | |||
996 | for (i = 0; i < NUM_CTRLS; i++) { | ||
997 | if (IS_MFC51_PRIV(controls[i].id)) { | ||
998 | cfg.ops = &s5p_mfc_dec_ctrl_ops; | ||
999 | cfg.id = controls[i].id; | ||
1000 | cfg.min = controls[i].minimum; | ||
1001 | cfg.max = controls[i].maximum; | ||
1002 | cfg.def = controls[i].default_value; | ||
1003 | cfg.name = controls[i].name; | ||
1004 | cfg.type = controls[i].type; | ||
1005 | |||
1006 | cfg.step = controls[i].step; | ||
1007 | cfg.menu_skip_mask = 0; | ||
1008 | |||
1009 | ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler, | ||
1010 | &cfg, NULL); | ||
1011 | } else { | ||
1012 | ctx->ctrls[i] = v4l2_ctrl_new_std(&ctx->ctrl_handler, | ||
1013 | &s5p_mfc_dec_ctrl_ops, | ||
1014 | controls[i].id, controls[i].minimum, | ||
1015 | controls[i].maximum, controls[i].step, | ||
1016 | controls[i].default_value); | ||
1017 | } | ||
1018 | if (ctx->ctrl_handler.error) { | ||
1019 | mfc_err("Adding control (%d) failed\n", i); | ||
1020 | return ctx->ctrl_handler.error; | ||
1021 | } | ||
1022 | if (controls[i].is_volatile && ctx->ctrls[i]) | ||
1023 | ctx->ctrls[i]->is_volatile = 1; | ||
1024 | } | ||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx) | ||
1029 | { | ||
1030 | int i; | ||
1031 | |||
1032 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
1033 | for (i = 0; i < NUM_CTRLS; i++) | ||
1034 | ctx->ctrls[i] = NULL; | ||
1035 | } | ||
1036 | |||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.h b/drivers/media/video/s5p-mfc/s5p_mfc_dec.h new file mode 100644 index 000000000000..fb8b215db0e7 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_dec.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_DEC_H_ | ||
14 | #define S5P_MFC_DEC_H_ | ||
15 | |||
16 | struct s5p_mfc_codec_ops *get_dec_codec_ops(void); | ||
17 | struct vb2_ops *get_dec_queue_ops(void); | ||
18 | const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); | ||
19 | struct s5p_mfc_fmt *get_dec_def_fmt(bool src); | ||
20 | int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx); | ||
21 | void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx); | ||
22 | |||
23 | #endif /* S5P_MFC_DEC_H_ */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c new file mode 100644 index 000000000000..fee094a14f4c --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c | |||
@@ -0,0 +1,1829 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_enc.c | ||
3 | * | ||
4 | * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. | ||
5 | * http://www.samsung.com/ | ||
6 | * | ||
7 | * Jeongtae Park <jtp.park@samsung.com> | ||
8 | * Kamil Debski <k.debski@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 as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/clk.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/version.h> | ||
23 | #include <linux/videodev2.h> | ||
24 | #include <linux/workqueue.h> | ||
25 | #include <media/v4l2-ctrls.h> | ||
26 | #include <media/videobuf2-core.h> | ||
27 | #include "regs-mfc.h" | ||
28 | #include "s5p_mfc_common.h" | ||
29 | #include "s5p_mfc_debug.h" | ||
30 | #include "s5p_mfc_enc.h" | ||
31 | #include "s5p_mfc_intr.h" | ||
32 | #include "s5p_mfc_opr.h" | ||
33 | |||
34 | static struct s5p_mfc_fmt formats[] = { | ||
35 | { | ||
36 | .name = "4:2:0 2 Planes 64x32 Tiles", | ||
37 | .fourcc = V4L2_PIX_FMT_NV12MT, | ||
38 | .codec_mode = S5P_FIMV_CODEC_NONE, | ||
39 | .type = MFC_FMT_RAW, | ||
40 | .num_planes = 2, | ||
41 | }, | ||
42 | { | ||
43 | .name = "4:2:0 2 Planes", | ||
44 | .fourcc = V4L2_PIX_FMT_NV12M, | ||
45 | .codec_mode = S5P_FIMV_CODEC_NONE, | ||
46 | .type = MFC_FMT_RAW, | ||
47 | .num_planes = 2, | ||
48 | }, | ||
49 | { | ||
50 | .name = "H264 Encoded Stream", | ||
51 | .fourcc = V4L2_PIX_FMT_H264, | ||
52 | .codec_mode = S5P_FIMV_CODEC_H264_ENC, | ||
53 | .type = MFC_FMT_ENC, | ||
54 | .num_planes = 1, | ||
55 | }, | ||
56 | { | ||
57 | .name = "MPEG4 Encoded Stream", | ||
58 | .fourcc = V4L2_PIX_FMT_MPEG4, | ||
59 | .codec_mode = S5P_FIMV_CODEC_MPEG4_ENC, | ||
60 | .type = MFC_FMT_ENC, | ||
61 | .num_planes = 1, | ||
62 | }, | ||
63 | { | ||
64 | .name = "H264 Encoded Stream", | ||
65 | .fourcc = V4L2_PIX_FMT_H263, | ||
66 | .codec_mode = S5P_FIMV_CODEC_H263_ENC, | ||
67 | .type = MFC_FMT_ENC, | ||
68 | .num_planes = 1, | ||
69 | }, | ||
70 | }; | ||
71 | |||
72 | #define NUM_FORMATS ARRAY_SIZE(formats) | ||
73 | static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) | ||
74 | { | ||
75 | unsigned int i; | ||
76 | |||
77 | for (i = 0; i < NUM_FORMATS; i++) { | ||
78 | if (formats[i].fourcc == f->fmt.pix_mp.pixelformat && | ||
79 | formats[i].type == t) | ||
80 | return &formats[i]; | ||
81 | } | ||
82 | return NULL; | ||
83 | } | ||
84 | |||
85 | static struct mfc_control controls[] = { | ||
86 | { | ||
87 | .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, | ||
88 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
89 | .minimum = 0, | ||
90 | .maximum = (1 << 16) - 1, | ||
91 | .step = 1, | ||
92 | .default_value = 0, | ||
93 | }, | ||
94 | { | ||
95 | .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, | ||
96 | .type = V4L2_CTRL_TYPE_MENU, | ||
97 | .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, | ||
98 | .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, | ||
99 | .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, | ||
100 | .menu_skip_mask = 0, | ||
101 | }, | ||
102 | { | ||
103 | .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, | ||
104 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
105 | .minimum = 1, | ||
106 | .maximum = (1 << 16) - 1, | ||
107 | .step = 1, | ||
108 | .default_value = 1, | ||
109 | }, | ||
110 | { | ||
111 | .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, | ||
112 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
113 | .minimum = 1900, | ||
114 | .maximum = (1 << 30) - 1, | ||
115 | .step = 1, | ||
116 | .default_value = 1900, | ||
117 | }, | ||
118 | { | ||
119 | .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, | ||
120 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
121 | .minimum = 0, | ||
122 | .maximum = (1 << 16) - 1, | ||
123 | .step = 1, | ||
124 | .default_value = 0, | ||
125 | }, | ||
126 | { | ||
127 | .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING, | ||
128 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
129 | .name = "Padding Control Enable", | ||
130 | .minimum = 0, | ||
131 | .maximum = 1, | ||
132 | .step = 1, | ||
133 | .default_value = 0, | ||
134 | }, | ||
135 | { | ||
136 | .id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV, | ||
137 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
138 | .name = "Padding Color YUV Value", | ||
139 | .minimum = 0, | ||
140 | .maximum = (1 << 25) - 1, | ||
141 | .step = 1, | ||
142 | .default_value = 0, | ||
143 | }, | ||
144 | { | ||
145 | .id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, | ||
146 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
147 | .minimum = 0, | ||
148 | .maximum = 1, | ||
149 | .step = 1, | ||
150 | .default_value = 0, | ||
151 | }, | ||
152 | { | ||
153 | .id = V4L2_CID_MPEG_VIDEO_BITRATE, | ||
154 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
155 | .minimum = 1, | ||
156 | .maximum = (1 << 30) - 1, | ||
157 | .step = 1, | ||
158 | .default_value = 1, | ||
159 | }, | ||
160 | { | ||
161 | .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF, | ||
162 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
163 | .name = "Rate Control Reaction Coeff.", | ||
164 | .minimum = 1, | ||
165 | .maximum = (1 << 16) - 1, | ||
166 | .step = 1, | ||
167 | .default_value = 1, | ||
168 | }, | ||
169 | { | ||
170 | .id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE, | ||
171 | .type = V4L2_CTRL_TYPE_MENU, | ||
172 | .name = "Force frame type", | ||
173 | .minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED, | ||
174 | .maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED, | ||
175 | .default_value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED, | ||
176 | .menu_skip_mask = 0, | ||
177 | }, | ||
178 | { | ||
179 | .id = V4L2_CID_MPEG_VIDEO_VBV_SIZE, | ||
180 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
181 | .minimum = 0, | ||
182 | .maximum = (1 << 16) - 1, | ||
183 | .step = 1, | ||
184 | .default_value = 0, | ||
185 | }, | ||
186 | { | ||
187 | .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, | ||
188 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
189 | .minimum = 0, | ||
190 | .maximum = (1 << 16) - 1, | ||
191 | .step = 1, | ||
192 | .default_value = 0, | ||
193 | }, | ||
194 | { | ||
195 | .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE, | ||
196 | .type = V4L2_CTRL_TYPE_MENU, | ||
197 | .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, | ||
198 | .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, | ||
199 | .default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, | ||
200 | .menu_skip_mask = 0, | ||
201 | }, | ||
202 | { | ||
203 | .id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE, | ||
204 | .type = V4L2_CTRL_TYPE_MENU, | ||
205 | .name = "Frame Skip Enable", | ||
206 | .minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED, | ||
207 | .maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, | ||
208 | .menu_skip_mask = 0, | ||
209 | .default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED, | ||
210 | }, | ||
211 | { | ||
212 | .id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT, | ||
213 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
214 | .name = "Fixed Target Bit Enable", | ||
215 | .minimum = 0, | ||
216 | .maximum = 1, | ||
217 | .default_value = 0, | ||
218 | .menu_skip_mask = 0, | ||
219 | }, | ||
220 | { | ||
221 | .id = V4L2_CID_MPEG_VIDEO_B_FRAMES, | ||
222 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
223 | .minimum = 0, | ||
224 | .maximum = 2, | ||
225 | .step = 1, | ||
226 | .default_value = 0, | ||
227 | }, | ||
228 | { | ||
229 | .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, | ||
230 | .type = V4L2_CTRL_TYPE_MENU, | ||
231 | .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, | ||
232 | .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, | ||
233 | .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, | ||
234 | .menu_skip_mask = ~( | ||
235 | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | | ||
236 | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | | ||
237 | (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) | ||
238 | ), | ||
239 | }, | ||
240 | { | ||
241 | .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, | ||
242 | .type = V4L2_CTRL_TYPE_MENU, | ||
243 | .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, | ||
244 | .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0, | ||
245 | .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, | ||
246 | .menu_skip_mask = ~( | ||
247 | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | | ||
248 | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | | ||
249 | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | | ||
250 | (1 << V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | ||
251 | ), | ||
252 | }, | ||
253 | { | ||
254 | .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, | ||
255 | .type = V4L2_CTRL_TYPE_MENU, | ||
256 | .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, | ||
257 | .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, | ||
258 | .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, | ||
259 | .menu_skip_mask = 0, | ||
260 | }, | ||
261 | { | ||
262 | .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, | ||
263 | .type = V4L2_CTRL_TYPE_MENU, | ||
264 | .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, | ||
265 | .maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY, | ||
266 | .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, | ||
267 | .menu_skip_mask = 0, | ||
268 | }, | ||
269 | { | ||
270 | .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, | ||
271 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
272 | .minimum = -6, | ||
273 | .maximum = 6, | ||
274 | .step = 1, | ||
275 | .default_value = 0, | ||
276 | }, | ||
277 | { | ||
278 | .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, | ||
279 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
280 | .minimum = -6, | ||
281 | .maximum = 6, | ||
282 | .step = 1, | ||
283 | .default_value = 0, | ||
284 | }, | ||
285 | { | ||
286 | .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, | ||
287 | .type = V4L2_CTRL_TYPE_MENU, | ||
288 | .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, | ||
289 | .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, | ||
290 | .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, | ||
291 | .menu_skip_mask = 0, | ||
292 | }, | ||
293 | { | ||
294 | .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P, | ||
295 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
296 | .name = "The Number of Ref. Pic for P", | ||
297 | .minimum = 1, | ||
298 | .maximum = 2, | ||
299 | .step = 1, | ||
300 | .default_value = 1, | ||
301 | }, | ||
302 | { | ||
303 | .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, | ||
304 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
305 | .minimum = 0, | ||
306 | .maximum = 1, | ||
307 | .step = 1, | ||
308 | .default_value = 0, | ||
309 | }, | ||
310 | { | ||
311 | .id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, | ||
312 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
313 | .minimum = 0, | ||
314 | .maximum = 1, | ||
315 | .step = 1, | ||
316 | .default_value = 0, | ||
317 | }, | ||
318 | { | ||
319 | .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, | ||
320 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
321 | .minimum = 0, | ||
322 | .maximum = 51, | ||
323 | .step = 1, | ||
324 | .default_value = 1, | ||
325 | }, | ||
326 | { | ||
327 | .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP, | ||
328 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
329 | .minimum = 0, | ||
330 | .maximum = 51, | ||
331 | .step = 1, | ||
332 | .default_value = 1, | ||
333 | }, | ||
334 | { | ||
335 | .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP, | ||
336 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
337 | .minimum = 0, | ||
338 | .maximum = 51, | ||
339 | .step = 1, | ||
340 | .default_value = 1, | ||
341 | }, | ||
342 | { | ||
343 | .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, | ||
344 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
345 | .minimum = 0, | ||
346 | .maximum = 51, | ||
347 | .step = 1, | ||
348 | .default_value = 1, | ||
349 | }, | ||
350 | { | ||
351 | .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, | ||
352 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
353 | .minimum = 0, | ||
354 | .maximum = 51, | ||
355 | .step = 1, | ||
356 | .default_value = 1, | ||
357 | }, | ||
358 | { | ||
359 | .id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP, | ||
360 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
361 | .name = "H263 I-Frame QP value", | ||
362 | .minimum = 1, | ||
363 | .maximum = 31, | ||
364 | .step = 1, | ||
365 | .default_value = 1, | ||
366 | }, | ||
367 | { | ||
368 | .id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP, | ||
369 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
370 | .name = "H263 Minimum QP value", | ||
371 | .minimum = 1, | ||
372 | .maximum = 31, | ||
373 | .step = 1, | ||
374 | .default_value = 1, | ||
375 | }, | ||
376 | { | ||
377 | .id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP, | ||
378 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
379 | .name = "H263 Maximum QP value", | ||
380 | .minimum = 1, | ||
381 | .maximum = 31, | ||
382 | .step = 1, | ||
383 | .default_value = 1, | ||
384 | }, | ||
385 | { | ||
386 | .id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP, | ||
387 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
388 | .name = "H263 P frame QP value", | ||
389 | .minimum = 1, | ||
390 | .maximum = 31, | ||
391 | .step = 1, | ||
392 | .default_value = 1, | ||
393 | }, | ||
394 | { | ||
395 | .id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP, | ||
396 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
397 | .name = "H263 B frame QP value", | ||
398 | .minimum = 1, | ||
399 | .maximum = 31, | ||
400 | .step = 1, | ||
401 | .default_value = 1, | ||
402 | }, | ||
403 | { | ||
404 | .id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, | ||
405 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
406 | .name = "MPEG4 I-Frame QP value", | ||
407 | .minimum = 1, | ||
408 | .maximum = 31, | ||
409 | .step = 1, | ||
410 | .default_value = 1, | ||
411 | }, | ||
412 | { | ||
413 | .id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP, | ||
414 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
415 | .name = "MPEG4 Minimum QP value", | ||
416 | .minimum = 1, | ||
417 | .maximum = 31, | ||
418 | .step = 1, | ||
419 | .default_value = 1, | ||
420 | }, | ||
421 | { | ||
422 | .id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP, | ||
423 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
424 | .name = "MPEG4 Maximum QP value", | ||
425 | .minimum = 0, | ||
426 | .maximum = 51, | ||
427 | .step = 1, | ||
428 | .default_value = 1, | ||
429 | }, | ||
430 | { | ||
431 | .id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, | ||
432 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
433 | .name = "MPEG4 P frame QP value", | ||
434 | .minimum = 1, | ||
435 | .maximum = 31, | ||
436 | .step = 1, | ||
437 | .default_value = 1, | ||
438 | }, | ||
439 | { | ||
440 | .id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP, | ||
441 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
442 | .name = "MPEG4 B frame QP value", | ||
443 | .minimum = 1, | ||
444 | .maximum = 31, | ||
445 | .step = 1, | ||
446 | .default_value = 1, | ||
447 | }, | ||
448 | { | ||
449 | .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK, | ||
450 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
451 | .name = "H264 Dark Reg Adaptive RC", | ||
452 | .minimum = 0, | ||
453 | .maximum = 1, | ||
454 | .step = 1, | ||
455 | .default_value = 0, | ||
456 | }, | ||
457 | { | ||
458 | .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH, | ||
459 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
460 | .name = "H264 Smooth Reg Adaptive RC", | ||
461 | .minimum = 0, | ||
462 | .maximum = 1, | ||
463 | .step = 1, | ||
464 | .default_value = 0, | ||
465 | }, | ||
466 | { | ||
467 | .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC, | ||
468 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
469 | .name = "H264 Static Reg Adaptive RC", | ||
470 | .minimum = 0, | ||
471 | .maximum = 1, | ||
472 | .step = 1, | ||
473 | .default_value = 0, | ||
474 | }, | ||
475 | { | ||
476 | .id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY, | ||
477 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
478 | .name = "H264 Activity Reg Adaptive RC", | ||
479 | .minimum = 0, | ||
480 | .maximum = 1, | ||
481 | .step = 1, | ||
482 | .default_value = 0, | ||
483 | }, | ||
484 | { | ||
485 | .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, | ||
486 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
487 | .minimum = 0, | ||
488 | .maximum = 1, | ||
489 | .step = 1, | ||
490 | .default_value = 0, | ||
491 | }, | ||
492 | { | ||
493 | .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC, | ||
494 | .type = V4L2_CTRL_TYPE_MENU, | ||
495 | .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED, | ||
496 | .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED, | ||
497 | .default_value = 0, | ||
498 | .menu_skip_mask = 0, | ||
499 | }, | ||
500 | { | ||
501 | .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH, | ||
502 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
503 | .minimum = 0, | ||
504 | .maximum = (1 << 16) - 1, | ||
505 | .step = 1, | ||
506 | .default_value = 0, | ||
507 | }, | ||
508 | { | ||
509 | .id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT, | ||
510 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
511 | .minimum = 0, | ||
512 | .maximum = (1 << 16) - 1, | ||
513 | .step = 1, | ||
514 | .default_value = 0, | ||
515 | }, | ||
516 | { | ||
517 | .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, | ||
518 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
519 | .minimum = 0, | ||
520 | .maximum = 1, | ||
521 | .step = 1, | ||
522 | .default_value = 1, | ||
523 | }, | ||
524 | { | ||
525 | .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, | ||
526 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
527 | .minimum = 0, | ||
528 | .maximum = (1 << 16) - 1, | ||
529 | .step = 1, | ||
530 | .default_value = 0, | ||
531 | }, | ||
532 | { | ||
533 | .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, | ||
534 | .type = V4L2_CTRL_TYPE_MENU, | ||
535 | .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, | ||
536 | .maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE, | ||
537 | .default_value = 0, | ||
538 | .menu_skip_mask = 0, | ||
539 | }, | ||
540 | { | ||
541 | .id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL, | ||
542 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
543 | .minimum = 0, | ||
544 | .maximum = 1, | ||
545 | .step = 1, | ||
546 | .default_value = 0, | ||
547 | }, | ||
548 | }; | ||
549 | |||
550 | #define NUM_CTRLS ARRAY_SIZE(controls) | ||
551 | static const char * const *mfc51_get_menu(u32 id) | ||
552 | { | ||
553 | static const char * const mfc51_video_frame_skip[] = { | ||
554 | "Disabled", | ||
555 | "Level Limit", | ||
556 | "VBV/CPB Limit", | ||
557 | NULL, | ||
558 | }; | ||
559 | static const char * const mfc51_video_force_frame[] = { | ||
560 | "Disabled", | ||
561 | "I Frame", | ||
562 | "Not Coded", | ||
563 | NULL, | ||
564 | }; | ||
565 | switch (id) { | ||
566 | case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: | ||
567 | return mfc51_video_frame_skip; | ||
568 | case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE: | ||
569 | return mfc51_video_force_frame; | ||
570 | } | ||
571 | return NULL; | ||
572 | } | ||
573 | |||
574 | static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx) | ||
575 | { | ||
576 | mfc_debug(2, "src=%d, dst=%d, state=%d\n", | ||
577 | ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state); | ||
578 | /* context is ready to make header */ | ||
579 | if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1) | ||
580 | return 1; | ||
581 | /* context is ready to encode a frame */ | ||
582 | if (ctx->state == MFCINST_RUNNING && | ||
583 | ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) | ||
584 | return 1; | ||
585 | /* context is ready to encode remain frames */ | ||
586 | if (ctx->state == MFCINST_FINISHING && | ||
587 | ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) | ||
588 | return 1; | ||
589 | mfc_debug(2, "ctx is not ready\n"); | ||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx) | ||
594 | { | ||
595 | struct s5p_mfc_buf *mb_entry; | ||
596 | unsigned long mb_y_addr, mb_c_addr; | ||
597 | |||
598 | /* move buffers in ref queue to src queue */ | ||
599 | while (!list_empty(&ctx->ref_queue)) { | ||
600 | mb_entry = list_entry((&ctx->ref_queue)->next, | ||
601 | struct s5p_mfc_buf, list); | ||
602 | mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0); | ||
603 | mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1); | ||
604 | list_del(&mb_entry->list); | ||
605 | ctx->ref_queue_cnt--; | ||
606 | list_add_tail(&mb_entry->list, &ctx->src_queue); | ||
607 | ctx->src_queue_cnt++; | ||
608 | } | ||
609 | mfc_debug(2, "enc src count: %d, enc ref count: %d\n", | ||
610 | ctx->src_queue_cnt, ctx->ref_queue_cnt); | ||
611 | INIT_LIST_HEAD(&ctx->ref_queue); | ||
612 | ctx->ref_queue_cnt = 0; | ||
613 | } | ||
614 | |||
615 | static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx) | ||
616 | { | ||
617 | struct s5p_mfc_dev *dev = ctx->dev; | ||
618 | struct s5p_mfc_buf *dst_mb; | ||
619 | unsigned long dst_addr; | ||
620 | unsigned int dst_size; | ||
621 | unsigned long flags; | ||
622 | |||
623 | spin_lock_irqsave(&dev->irqlock, flags); | ||
624 | dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); | ||
625 | dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0); | ||
626 | dst_size = vb2_plane_size(dst_mb->b, 0); | ||
627 | s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); | ||
628 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static int enc_post_seq_start(struct s5p_mfc_ctx *ctx) | ||
633 | { | ||
634 | struct s5p_mfc_dev *dev = ctx->dev; | ||
635 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
636 | struct s5p_mfc_buf *dst_mb; | ||
637 | unsigned long flags; | ||
638 | |||
639 | if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) { | ||
640 | spin_lock_irqsave(&dev->irqlock, flags); | ||
641 | dst_mb = list_entry(ctx->dst_queue.next, | ||
642 | struct s5p_mfc_buf, list); | ||
643 | list_del(&dst_mb->list); | ||
644 | ctx->dst_queue_cnt--; | ||
645 | vb2_set_plane_payload(dst_mb->b, 0, | ||
646 | s5p_mfc_get_enc_strm_size()); | ||
647 | vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE); | ||
648 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
649 | } | ||
650 | ctx->state = MFCINST_RUNNING; | ||
651 | if (s5p_mfc_ctx_ready(ctx)) { | ||
652 | spin_lock_irqsave(&dev->condlock, flags); | ||
653 | set_bit(ctx->num, &dev->ctx_work_bits); | ||
654 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
655 | } | ||
656 | s5p_mfc_try_run(dev); | ||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx) | ||
661 | { | ||
662 | struct s5p_mfc_dev *dev = ctx->dev; | ||
663 | struct s5p_mfc_buf *dst_mb; | ||
664 | struct s5p_mfc_buf *src_mb; | ||
665 | unsigned long flags; | ||
666 | unsigned long src_y_addr, src_c_addr, dst_addr; | ||
667 | unsigned int dst_size; | ||
668 | |||
669 | spin_lock_irqsave(&dev->irqlock, flags); | ||
670 | src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
671 | src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0); | ||
672 | src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1); | ||
673 | s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr); | ||
674 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
675 | |||
676 | spin_lock_irqsave(&dev->irqlock, flags); | ||
677 | dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); | ||
678 | dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0); | ||
679 | dst_size = vb2_plane_size(dst_mb->b, 0); | ||
680 | s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); | ||
681 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
682 | |||
683 | return 0; | ||
684 | } | ||
685 | |||
686 | static int enc_post_frame_start(struct s5p_mfc_ctx *ctx) | ||
687 | { | ||
688 | struct s5p_mfc_dev *dev = ctx->dev; | ||
689 | struct s5p_mfc_buf *mb_entry; | ||
690 | unsigned long enc_y_addr, enc_c_addr; | ||
691 | unsigned long mb_y_addr, mb_c_addr; | ||
692 | int slice_type; | ||
693 | unsigned int strm_size; | ||
694 | unsigned long flags; | ||
695 | |||
696 | slice_type = s5p_mfc_get_enc_slice_type(); | ||
697 | strm_size = s5p_mfc_get_enc_strm_size(); | ||
698 | mfc_debug(2, "Encoded slice type: %d", slice_type); | ||
699 | mfc_debug(2, "Encoded stream size: %d", strm_size); | ||
700 | mfc_debug(2, "Display order: %d", | ||
701 | mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT)); | ||
702 | spin_lock_irqsave(&dev->irqlock, flags); | ||
703 | if (slice_type >= 0) { | ||
704 | s5p_mfc_get_enc_frame_buffer(ctx, &enc_y_addr, &enc_c_addr); | ||
705 | list_for_each_entry(mb_entry, &ctx->src_queue, list) { | ||
706 | mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0); | ||
707 | mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1); | ||
708 | if ((enc_y_addr == mb_y_addr) && | ||
709 | (enc_c_addr == mb_c_addr)) { | ||
710 | list_del(&mb_entry->list); | ||
711 | ctx->src_queue_cnt--; | ||
712 | vb2_buffer_done(mb_entry->b, | ||
713 | VB2_BUF_STATE_DONE); | ||
714 | break; | ||
715 | } | ||
716 | } | ||
717 | list_for_each_entry(mb_entry, &ctx->ref_queue, list) { | ||
718 | mb_y_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 0); | ||
719 | mb_c_addr = vb2_dma_contig_plane_paddr(mb_entry->b, 1); | ||
720 | if ((enc_y_addr == mb_y_addr) && | ||
721 | (enc_c_addr == mb_c_addr)) { | ||
722 | list_del(&mb_entry->list); | ||
723 | ctx->ref_queue_cnt--; | ||
724 | vb2_buffer_done(mb_entry->b, | ||
725 | VB2_BUF_STATE_DONE); | ||
726 | break; | ||
727 | } | ||
728 | } | ||
729 | } | ||
730 | if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) { | ||
731 | mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, | ||
732 | list); | ||
733 | if (mb_entry->used) { | ||
734 | list_del(&mb_entry->list); | ||
735 | ctx->src_queue_cnt--; | ||
736 | list_add_tail(&mb_entry->list, &ctx->ref_queue); | ||
737 | ctx->ref_queue_cnt++; | ||
738 | } | ||
739 | mfc_debug(2, "enc src count: %d, enc ref count: %d\n", | ||
740 | ctx->src_queue_cnt, ctx->ref_queue_cnt); | ||
741 | } | ||
742 | if (strm_size > 0) { | ||
743 | /* at least one more dest. buffers exist always */ | ||
744 | mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, | ||
745 | list); | ||
746 | list_del(&mb_entry->list); | ||
747 | ctx->dst_queue_cnt--; | ||
748 | switch (slice_type) { | ||
749 | case S5P_FIMV_ENC_SI_SLICE_TYPE_I: | ||
750 | mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME; | ||
751 | break; | ||
752 | case S5P_FIMV_ENC_SI_SLICE_TYPE_P: | ||
753 | mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME; | ||
754 | break; | ||
755 | case S5P_FIMV_ENC_SI_SLICE_TYPE_B: | ||
756 | mb_entry->b->v4l2_buf.flags |= V4L2_BUF_FLAG_BFRAME; | ||
757 | break; | ||
758 | } | ||
759 | vb2_set_plane_payload(mb_entry->b, 0, strm_size); | ||
760 | vb2_buffer_done(mb_entry->b, VB2_BUF_STATE_DONE); | ||
761 | } | ||
762 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
763 | if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0)) { | ||
764 | spin_lock(&dev->condlock); | ||
765 | clear_bit(ctx->num, &dev->ctx_work_bits); | ||
766 | spin_unlock(&dev->condlock); | ||
767 | } | ||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | static struct s5p_mfc_codec_ops encoder_codec_ops = { | ||
772 | .pre_seq_start = enc_pre_seq_start, | ||
773 | .post_seq_start = enc_post_seq_start, | ||
774 | .pre_frame_start = enc_pre_frame_start, | ||
775 | .post_frame_start = enc_post_frame_start, | ||
776 | }; | ||
777 | |||
778 | /* Query capabilities of the device */ | ||
779 | static int vidioc_querycap(struct file *file, void *priv, | ||
780 | struct v4l2_capability *cap) | ||
781 | { | ||
782 | struct s5p_mfc_dev *dev = video_drvdata(file); | ||
783 | |||
784 | strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1); | ||
785 | strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1); | ||
786 | cap->bus_info[0] = 0; | ||
787 | cap->version = KERNEL_VERSION(1, 0, 0); | ||
788 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | ||
789 | | V4L2_CAP_VIDEO_OUTPUT | ||
790 | | V4L2_CAP_STREAMING; | ||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out) | ||
795 | { | ||
796 | struct s5p_mfc_fmt *fmt; | ||
797 | int i, j = 0; | ||
798 | |||
799 | for (i = 0; i < ARRAY_SIZE(formats); ++i) { | ||
800 | if (mplane && formats[i].num_planes == 1) | ||
801 | continue; | ||
802 | else if (!mplane && formats[i].num_planes > 1) | ||
803 | continue; | ||
804 | if (out && formats[i].type != MFC_FMT_RAW) | ||
805 | continue; | ||
806 | else if (!out && formats[i].type != MFC_FMT_ENC) | ||
807 | continue; | ||
808 | if (j == f->index) { | ||
809 | fmt = &formats[i]; | ||
810 | strlcpy(f->description, fmt->name, | ||
811 | sizeof(f->description)); | ||
812 | f->pixelformat = fmt->fourcc; | ||
813 | return 0; | ||
814 | } | ||
815 | ++j; | ||
816 | } | ||
817 | return -EINVAL; | ||
818 | } | ||
819 | |||
820 | static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, | ||
821 | struct v4l2_fmtdesc *f) | ||
822 | { | ||
823 | return vidioc_enum_fmt(f, false, false); | ||
824 | } | ||
825 | |||
826 | static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, | ||
827 | struct v4l2_fmtdesc *f) | ||
828 | { | ||
829 | return vidioc_enum_fmt(f, true, false); | ||
830 | } | ||
831 | |||
832 | static int vidioc_enum_fmt_vid_out(struct file *file, void *prov, | ||
833 | struct v4l2_fmtdesc *f) | ||
834 | { | ||
835 | return vidioc_enum_fmt(f, false, true); | ||
836 | } | ||
837 | |||
838 | static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, | ||
839 | struct v4l2_fmtdesc *f) | ||
840 | { | ||
841 | return vidioc_enum_fmt(f, true, true); | ||
842 | } | ||
843 | |||
844 | static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | ||
845 | { | ||
846 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
847 | struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; | ||
848 | |||
849 | mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state); | ||
850 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
851 | /* This is run on output (encoder dest) */ | ||
852 | pix_fmt_mp->width = 0; | ||
853 | pix_fmt_mp->height = 0; | ||
854 | pix_fmt_mp->field = V4L2_FIELD_NONE; | ||
855 | pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc; | ||
856 | pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes; | ||
857 | |||
858 | pix_fmt_mp->plane_fmt[0].bytesperline = ctx->enc_dst_buf_size; | ||
859 | pix_fmt_mp->plane_fmt[0].sizeimage = ctx->enc_dst_buf_size; | ||
860 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
861 | /* This is run on capture (encoder src) */ | ||
862 | pix_fmt_mp->width = ctx->img_width; | ||
863 | pix_fmt_mp->height = ctx->img_height; | ||
864 | |||
865 | pix_fmt_mp->field = V4L2_FIELD_NONE; | ||
866 | pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc; | ||
867 | pix_fmt_mp->num_planes = ctx->src_fmt->num_planes; | ||
868 | |||
869 | pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; | ||
870 | pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; | ||
871 | pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; | ||
872 | pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; | ||
873 | } else { | ||
874 | mfc_err("invalid buf type\n"); | ||
875 | return -EINVAL; | ||
876 | } | ||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) | ||
881 | { | ||
882 | struct s5p_mfc_fmt *fmt; | ||
883 | struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; | ||
884 | |||
885 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
886 | fmt = find_format(f, MFC_FMT_ENC); | ||
887 | if (!fmt) { | ||
888 | mfc_err("failed to try output format\n"); | ||
889 | return -EINVAL; | ||
890 | } | ||
891 | |||
892 | if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { | ||
893 | mfc_err("must be set encoding output size\n"); | ||
894 | return -EINVAL; | ||
895 | } | ||
896 | |||
897 | pix_fmt_mp->plane_fmt[0].bytesperline = | ||
898 | pix_fmt_mp->plane_fmt[0].sizeimage; | ||
899 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
900 | fmt = find_format(f, MFC_FMT_RAW); | ||
901 | if (!fmt) { | ||
902 | mfc_err("failed to try output format\n"); | ||
903 | return -EINVAL; | ||
904 | } | ||
905 | |||
906 | if (fmt->num_planes != pix_fmt_mp->num_planes) { | ||
907 | mfc_err("failed to try output format\n"); | ||
908 | return -EINVAL; | ||
909 | } | ||
910 | } else { | ||
911 | mfc_err("invalid buf type\n"); | ||
912 | return -EINVAL; | ||
913 | } | ||
914 | return 0; | ||
915 | } | ||
916 | |||
917 | static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | ||
918 | { | ||
919 | struct s5p_mfc_dev *dev = video_drvdata(file); | ||
920 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
921 | struct s5p_mfc_fmt *fmt; | ||
922 | struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; | ||
923 | unsigned long flags; | ||
924 | int ret = 0; | ||
925 | |||
926 | ret = vidioc_try_fmt(file, priv, f); | ||
927 | if (ret) | ||
928 | return ret; | ||
929 | if (ctx->vq_src.streaming || ctx->vq_dst.streaming) { | ||
930 | v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__); | ||
931 | ret = -EBUSY; | ||
932 | goto out; | ||
933 | } | ||
934 | if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
935 | fmt = find_format(f, MFC_FMT_ENC); | ||
936 | if (!fmt) { | ||
937 | mfc_err("failed to set capture format\n"); | ||
938 | return -EINVAL; | ||
939 | } | ||
940 | ctx->state = MFCINST_INIT; | ||
941 | ctx->dst_fmt = fmt; | ||
942 | ctx->codec_mode = ctx->dst_fmt->codec_mode; | ||
943 | ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage; | ||
944 | pix_fmt_mp->plane_fmt[0].bytesperline = 0; | ||
945 | ctx->dst_bufs_cnt = 0; | ||
946 | ctx->capture_state = QUEUE_FREE; | ||
947 | s5p_mfc_alloc_instance_buffer(ctx); | ||
948 | spin_lock_irqsave(&dev->condlock, flags); | ||
949 | set_bit(ctx->num, &dev->ctx_work_bits); | ||
950 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
951 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
952 | s5p_mfc_try_run(dev); | ||
953 | if (s5p_mfc_wait_for_done_ctx(ctx, \ | ||
954 | S5P_FIMV_R2H_CMD_OPEN_INSTANCE_RET, 1)) { | ||
955 | /* Error or timeout */ | ||
956 | mfc_err("Error getting instance from hardware\n"); | ||
957 | s5p_mfc_release_instance_buffer(ctx); | ||
958 | ret = -EIO; | ||
959 | goto out; | ||
960 | } | ||
961 | mfc_debug(2, "Got instance number: %d\n", ctx->inst_no); | ||
962 | } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
963 | fmt = find_format(f, MFC_FMT_RAW); | ||
964 | if (!fmt) { | ||
965 | mfc_err("failed to set output format\n"); | ||
966 | return -EINVAL; | ||
967 | } | ||
968 | if (fmt->num_planes != pix_fmt_mp->num_planes) { | ||
969 | mfc_err("failed to set output format\n"); | ||
970 | ret = -EINVAL; | ||
971 | goto out; | ||
972 | } | ||
973 | ctx->src_fmt = fmt; | ||
974 | ctx->img_width = pix_fmt_mp->width; | ||
975 | ctx->img_height = pix_fmt_mp->height; | ||
976 | mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode); | ||
977 | mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n", | ||
978 | pix_fmt_mp->width, pix_fmt_mp->height, | ||
979 | ctx->img_width, ctx->img_height); | ||
980 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) { | ||
981 | ctx->buf_width = ALIGN(ctx->img_width, | ||
982 | S5P_FIMV_NV12M_HALIGN); | ||
983 | ctx->luma_size = ALIGN(ctx->img_width, | ||
984 | S5P_FIMV_NV12M_HALIGN) * ALIGN(ctx->img_height, | ||
985 | S5P_FIMV_NV12M_LVALIGN); | ||
986 | ctx->chroma_size = ALIGN(ctx->img_width, | ||
987 | S5P_FIMV_NV12M_HALIGN) * ALIGN((ctx->img_height | ||
988 | >> 1), S5P_FIMV_NV12M_CVALIGN); | ||
989 | |||
990 | ctx->luma_size = ALIGN(ctx->luma_size, | ||
991 | S5P_FIMV_NV12M_SALIGN); | ||
992 | ctx->chroma_size = ALIGN(ctx->chroma_size, | ||
993 | S5P_FIMV_NV12M_SALIGN); | ||
994 | |||
995 | pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; | ||
996 | pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; | ||
997 | pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; | ||
998 | pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; | ||
999 | |||
1000 | } else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) { | ||
1001 | ctx->buf_width = ALIGN(ctx->img_width, | ||
1002 | S5P_FIMV_NV12MT_HALIGN); | ||
1003 | ctx->luma_size = ALIGN(ctx->img_width, | ||
1004 | S5P_FIMV_NV12MT_HALIGN) * ALIGN(ctx->img_height, | ||
1005 | S5P_FIMV_NV12MT_VALIGN); | ||
1006 | ctx->chroma_size = ALIGN(ctx->img_width, | ||
1007 | S5P_FIMV_NV12MT_HALIGN) * ALIGN((ctx->img_height | ||
1008 | >> 1), S5P_FIMV_NV12MT_VALIGN); | ||
1009 | ctx->luma_size = ALIGN(ctx->luma_size, | ||
1010 | S5P_FIMV_NV12MT_SALIGN); | ||
1011 | ctx->chroma_size = ALIGN(ctx->chroma_size, | ||
1012 | S5P_FIMV_NV12MT_SALIGN); | ||
1013 | |||
1014 | pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size; | ||
1015 | pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width; | ||
1016 | pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size; | ||
1017 | pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width; | ||
1018 | } | ||
1019 | ctx->src_bufs_cnt = 0; | ||
1020 | ctx->output_state = QUEUE_FREE; | ||
1021 | } else { | ||
1022 | mfc_err("invalid buf type\n"); | ||
1023 | return -EINVAL; | ||
1024 | } | ||
1025 | out: | ||
1026 | mfc_debug_leave(); | ||
1027 | return ret; | ||
1028 | } | ||
1029 | |||
1030 | static int vidioc_reqbufs(struct file *file, void *priv, | ||
1031 | struct v4l2_requestbuffers *reqbufs) | ||
1032 | { | ||
1033 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
1034 | int ret = 0; | ||
1035 | |||
1036 | /* if memory is not mmp or userptr return error */ | ||
1037 | if ((reqbufs->memory != V4L2_MEMORY_MMAP) && | ||
1038 | (reqbufs->memory != V4L2_MEMORY_USERPTR)) | ||
1039 | return -EINVAL; | ||
1040 | if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
1041 | if (ctx->capture_state != QUEUE_FREE) { | ||
1042 | mfc_err("invalid capture state: %d\n", | ||
1043 | ctx->capture_state); | ||
1044 | return -EINVAL; | ||
1045 | } | ||
1046 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | ||
1047 | if (ret != 0) { | ||
1048 | mfc_err("error in vb2_reqbufs() for E(D)\n"); | ||
1049 | return ret; | ||
1050 | } | ||
1051 | ctx->capture_state = QUEUE_BUFS_REQUESTED; | ||
1052 | ret = s5p_mfc_alloc_codec_buffers(ctx); | ||
1053 | if (ret) { | ||
1054 | mfc_err("Failed to allocate encoding buffers\n"); | ||
1055 | reqbufs->count = 0; | ||
1056 | ret = vb2_reqbufs(&ctx->vq_dst, reqbufs); | ||
1057 | return -ENOMEM; | ||
1058 | } | ||
1059 | } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
1060 | if (ctx->output_state != QUEUE_FREE) { | ||
1061 | mfc_err("invalid output state: %d\n", | ||
1062 | ctx->output_state); | ||
1063 | return -EINVAL; | ||
1064 | } | ||
1065 | ret = vb2_reqbufs(&ctx->vq_src, reqbufs); | ||
1066 | if (ret != 0) { | ||
1067 | mfc_err("error in vb2_reqbufs() for E(S)\n"); | ||
1068 | return ret; | ||
1069 | } | ||
1070 | ctx->output_state = QUEUE_BUFS_REQUESTED; | ||
1071 | } else { | ||
1072 | mfc_err("invalid buf type\n"); | ||
1073 | return -EINVAL; | ||
1074 | } | ||
1075 | return ret; | ||
1076 | } | ||
1077 | |||
1078 | static int vidioc_querybuf(struct file *file, void *priv, | ||
1079 | struct v4l2_buffer *buf) | ||
1080 | { | ||
1081 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
1082 | int ret = 0; | ||
1083 | |||
1084 | /* if memory is not mmp or userptr return error */ | ||
1085 | if ((buf->memory != V4L2_MEMORY_MMAP) && | ||
1086 | (buf->memory != V4L2_MEMORY_USERPTR)) | ||
1087 | return -EINVAL; | ||
1088 | if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
1089 | if (ctx->state != MFCINST_GOT_INST) { | ||
1090 | mfc_err("invalid context state: %d\n", ctx->state); | ||
1091 | return -EINVAL; | ||
1092 | } | ||
1093 | ret = vb2_querybuf(&ctx->vq_dst, buf); | ||
1094 | if (ret != 0) { | ||
1095 | mfc_err("error in vb2_querybuf() for E(D)\n"); | ||
1096 | return ret; | ||
1097 | } | ||
1098 | buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE; | ||
1099 | } else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
1100 | ret = vb2_querybuf(&ctx->vq_src, buf); | ||
1101 | if (ret != 0) { | ||
1102 | mfc_err("error in vb2_querybuf() for E(S)\n"); | ||
1103 | return ret; | ||
1104 | } | ||
1105 | } else { | ||
1106 | mfc_err("invalid buf type\n"); | ||
1107 | return -EINVAL; | ||
1108 | } | ||
1109 | return ret; | ||
1110 | } | ||
1111 | |||
1112 | /* Queue a buffer */ | ||
1113 | static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
1114 | { | ||
1115 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
1116 | |||
1117 | if (ctx->state == MFCINST_ERROR) { | ||
1118 | mfc_err("Call on QBUF after unrecoverable error\n"); | ||
1119 | return -EIO; | ||
1120 | } | ||
1121 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
1122 | return vb2_qbuf(&ctx->vq_src, buf); | ||
1123 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
1124 | return vb2_qbuf(&ctx->vq_dst, buf); | ||
1125 | return -EINVAL; | ||
1126 | } | ||
1127 | |||
1128 | /* Dequeue a buffer */ | ||
1129 | static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) | ||
1130 | { | ||
1131 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
1132 | |||
1133 | if (ctx->state == MFCINST_ERROR) { | ||
1134 | mfc_err("Call on DQBUF after unrecoverable error\n"); | ||
1135 | return -EIO; | ||
1136 | } | ||
1137 | if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
1138 | return vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK); | ||
1139 | else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
1140 | return vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK); | ||
1141 | return -EINVAL; | ||
1142 | } | ||
1143 | |||
1144 | /* Stream on */ | ||
1145 | static int vidioc_streamon(struct file *file, void *priv, | ||
1146 | enum v4l2_buf_type type) | ||
1147 | { | ||
1148 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
1149 | |||
1150 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
1151 | return vb2_streamon(&ctx->vq_src, type); | ||
1152 | else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
1153 | return vb2_streamon(&ctx->vq_dst, type); | ||
1154 | return -EINVAL; | ||
1155 | } | ||
1156 | |||
1157 | /* Stream off, which equals to a pause */ | ||
1158 | static int vidioc_streamoff(struct file *file, void *priv, | ||
1159 | enum v4l2_buf_type type) | ||
1160 | { | ||
1161 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
1162 | |||
1163 | if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) | ||
1164 | return vb2_streamoff(&ctx->vq_src, type); | ||
1165 | else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) | ||
1166 | return vb2_streamoff(&ctx->vq_dst, type); | ||
1167 | return -EINVAL; | ||
1168 | } | ||
1169 | |||
1170 | static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl) | ||
1171 | { | ||
1172 | static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_0 + 1] = { | ||
1173 | /* V4L2_MPEG_VIDEO_H264_LEVEL_1_0 */ 10, | ||
1174 | /* V4L2_MPEG_VIDEO_H264_LEVEL_1B */ 9, | ||
1175 | /* V4L2_MPEG_VIDEO_H264_LEVEL_1_1 */ 11, | ||
1176 | /* V4L2_MPEG_VIDEO_H264_LEVEL_1_2 */ 12, | ||
1177 | /* V4L2_MPEG_VIDEO_H264_LEVEL_1_3 */ 13, | ||
1178 | /* V4L2_MPEG_VIDEO_H264_LEVEL_2_0 */ 20, | ||
1179 | /* V4L2_MPEG_VIDEO_H264_LEVEL_2_1 */ 21, | ||
1180 | /* V4L2_MPEG_VIDEO_H264_LEVEL_2_2 */ 22, | ||
1181 | /* V4L2_MPEG_VIDEO_H264_LEVEL_3_0 */ 30, | ||
1182 | /* V4L2_MPEG_VIDEO_H264_LEVEL_3_1 */ 31, | ||
1183 | /* V4L2_MPEG_VIDEO_H264_LEVEL_3_2 */ 32, | ||
1184 | /* V4L2_MPEG_VIDEO_H264_LEVEL_4_0 */ 40, | ||
1185 | }; | ||
1186 | return t[lvl]; | ||
1187 | } | ||
1188 | |||
1189 | static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl) | ||
1190 | { | ||
1191 | static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 + 1] = { | ||
1192 | /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 */ 0, | ||
1193 | /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B */ 9, | ||
1194 | /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 */ 1, | ||
1195 | /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 */ 2, | ||
1196 | /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 */ 3, | ||
1197 | /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B */ 7, | ||
1198 | /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 */ 4, | ||
1199 | /* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 */ 5, | ||
1200 | }; | ||
1201 | return t[lvl]; | ||
1202 | } | ||
1203 | |||
1204 | static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar) | ||
1205 | { | ||
1206 | static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = { | ||
1207 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED */ 0, | ||
1208 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 */ 1, | ||
1209 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 */ 2, | ||
1210 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 */ 3, | ||
1211 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 */ 4, | ||
1212 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 */ 5, | ||
1213 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 */ 6, | ||
1214 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 */ 7, | ||
1215 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 */ 8, | ||
1216 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 */ 9, | ||
1217 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 */ 10, | ||
1218 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 */ 11, | ||
1219 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 */ 12, | ||
1220 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 */ 13, | ||
1221 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 */ 14, | ||
1222 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 */ 15, | ||
1223 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 */ 16, | ||
1224 | /* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED */ 255, | ||
1225 | }; | ||
1226 | return t[sar]; | ||
1227 | } | ||
1228 | |||
1229 | static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1230 | { | ||
1231 | struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl); | ||
1232 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1233 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
1234 | int ret = 0; | ||
1235 | |||
1236 | switch (ctrl->id) { | ||
1237 | case V4L2_CID_MPEG_VIDEO_GOP_SIZE: | ||
1238 | p->gop_size = ctrl->val; | ||
1239 | break; | ||
1240 | case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: | ||
1241 | p->slice_mode = ctrl->val; | ||
1242 | break; | ||
1243 | case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: | ||
1244 | p->slice_mb = ctrl->val; | ||
1245 | break; | ||
1246 | case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: | ||
1247 | p->slice_bit = ctrl->val * 8; | ||
1248 | break; | ||
1249 | case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: | ||
1250 | p->intra_refresh_mb = ctrl->val; | ||
1251 | break; | ||
1252 | case V4L2_CID_MPEG_MFC51_VIDEO_PADDING: | ||
1253 | p->pad = ctrl->val; | ||
1254 | break; | ||
1255 | case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV: | ||
1256 | p->pad_luma = (ctrl->val >> 16) & 0xff; | ||
1257 | p->pad_cb = (ctrl->val >> 8) & 0xff; | ||
1258 | p->pad_cr = (ctrl->val >> 0) & 0xff; | ||
1259 | break; | ||
1260 | case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: | ||
1261 | p->rc_frame = ctrl->val; | ||
1262 | break; | ||
1263 | case V4L2_CID_MPEG_VIDEO_BITRATE: | ||
1264 | p->rc_bitrate = ctrl->val; | ||
1265 | break; | ||
1266 | case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF: | ||
1267 | p->rc_reaction_coeff = ctrl->val; | ||
1268 | break; | ||
1269 | case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE: | ||
1270 | ctx->force_frame_type = ctrl->val; | ||
1271 | break; | ||
1272 | case V4L2_CID_MPEG_VIDEO_VBV_SIZE: | ||
1273 | p->vbv_size = ctrl->val; | ||
1274 | break; | ||
1275 | case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: | ||
1276 | p->codec.h264.cpb_size = ctrl->val; | ||
1277 | break; | ||
1278 | case V4L2_CID_MPEG_VIDEO_HEADER_MODE: | ||
1279 | p->seq_hdr_mode = ctrl->val; | ||
1280 | break; | ||
1281 | case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: | ||
1282 | p->frame_skip_mode = ctrl->val; | ||
1283 | break; | ||
1284 | case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT: | ||
1285 | p->fixed_target_bit = ctrl->val; | ||
1286 | break; | ||
1287 | case V4L2_CID_MPEG_VIDEO_B_FRAMES: | ||
1288 | p->num_b_frame = ctrl->val; | ||
1289 | break; | ||
1290 | case V4L2_CID_MPEG_VIDEO_H264_PROFILE: | ||
1291 | switch (ctrl->val) { | ||
1292 | case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: | ||
1293 | p->codec.h264.profile = | ||
1294 | S5P_FIMV_ENC_PROFILE_H264_MAIN; | ||
1295 | break; | ||
1296 | case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: | ||
1297 | p->codec.h264.profile = | ||
1298 | S5P_FIMV_ENC_PROFILE_H264_HIGH; | ||
1299 | break; | ||
1300 | case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: | ||
1301 | p->codec.h264.profile = | ||
1302 | S5P_FIMV_ENC_PROFILE_H264_BASELINE; | ||
1303 | break; | ||
1304 | default: | ||
1305 | ret = -EINVAL; | ||
1306 | } | ||
1307 | break; | ||
1308 | case V4L2_CID_MPEG_VIDEO_H264_LEVEL: | ||
1309 | p->codec.h264.level_v4l2 = ctrl->val; | ||
1310 | p->codec.h264.level = h264_level(ctrl->val); | ||
1311 | if (p->codec.h264.level < 0) { | ||
1312 | mfc_err("Level number is wrong\n"); | ||
1313 | ret = p->codec.h264.level; | ||
1314 | } | ||
1315 | break; | ||
1316 | case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: | ||
1317 | p->codec.mpeg4.level_v4l2 = ctrl->val; | ||
1318 | p->codec.mpeg4.level = mpeg4_level(ctrl->val); | ||
1319 | if (p->codec.mpeg4.level < 0) { | ||
1320 | mfc_err("Level number is wrong\n"); | ||
1321 | ret = p->codec.mpeg4.level; | ||
1322 | } | ||
1323 | break; | ||
1324 | case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: | ||
1325 | p->codec.h264.loop_filter_mode = ctrl->val; | ||
1326 | break; | ||
1327 | case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: | ||
1328 | p->codec.h264.loop_filter_alpha = ctrl->val; | ||
1329 | break; | ||
1330 | case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: | ||
1331 | p->codec.h264.loop_filter_beta = ctrl->val; | ||
1332 | break; | ||
1333 | case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: | ||
1334 | p->codec.h264.entropy_mode = ctrl->val; | ||
1335 | break; | ||
1336 | case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P: | ||
1337 | p->codec.h264.num_ref_pic_4p = ctrl->val; | ||
1338 | break; | ||
1339 | case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: | ||
1340 | p->codec.h264._8x8_transform = ctrl->val; | ||
1341 | break; | ||
1342 | case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: | ||
1343 | p->codec.h264.rc_mb = ctrl->val; | ||
1344 | break; | ||
1345 | case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: | ||
1346 | p->codec.h264.rc_frame_qp = ctrl->val; | ||
1347 | break; | ||
1348 | case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: | ||
1349 | p->codec.h264.rc_min_qp = ctrl->val; | ||
1350 | break; | ||
1351 | case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: | ||
1352 | p->codec.h264.rc_max_qp = ctrl->val; | ||
1353 | break; | ||
1354 | case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: | ||
1355 | p->codec.h264.rc_p_frame_qp = ctrl->val; | ||
1356 | break; | ||
1357 | case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: | ||
1358 | p->codec.h264.rc_b_frame_qp = ctrl->val; | ||
1359 | break; | ||
1360 | case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: | ||
1361 | case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: | ||
1362 | p->codec.mpeg4.rc_frame_qp = ctrl->val; | ||
1363 | break; | ||
1364 | case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: | ||
1365 | case V4L2_CID_MPEG_VIDEO_H263_MIN_QP: | ||
1366 | p->codec.mpeg4.rc_min_qp = ctrl->val; | ||
1367 | break; | ||
1368 | case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: | ||
1369 | case V4L2_CID_MPEG_VIDEO_H263_MAX_QP: | ||
1370 | p->codec.mpeg4.rc_max_qp = ctrl->val; | ||
1371 | break; | ||
1372 | case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: | ||
1373 | case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: | ||
1374 | p->codec.mpeg4.rc_p_frame_qp = ctrl->val; | ||
1375 | break; | ||
1376 | case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: | ||
1377 | case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: | ||
1378 | p->codec.mpeg4.rc_b_frame_qp = ctrl->val; | ||
1379 | break; | ||
1380 | case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK: | ||
1381 | p->codec.h264.rc_mb_dark = ctrl->val; | ||
1382 | break; | ||
1383 | case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH: | ||
1384 | p->codec.h264.rc_mb_smooth = ctrl->val; | ||
1385 | break; | ||
1386 | case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC: | ||
1387 | p->codec.h264.rc_mb_static = ctrl->val; | ||
1388 | break; | ||
1389 | case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY: | ||
1390 | p->codec.h264.rc_mb_activity = ctrl->val; | ||
1391 | break; | ||
1392 | case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: | ||
1393 | p->codec.h264.vui_sar = ctrl->val; | ||
1394 | break; | ||
1395 | case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: | ||
1396 | p->codec.h264.vui_sar_idc = vui_sar_idc(ctrl->val); | ||
1397 | break; | ||
1398 | case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: | ||
1399 | p->codec.h264.vui_ext_sar_width = ctrl->val; | ||
1400 | break; | ||
1401 | case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: | ||
1402 | p->codec.h264.vui_ext_sar_height = ctrl->val; | ||
1403 | break; | ||
1404 | case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: | ||
1405 | p->codec.h264.open_gop = !ctrl->val; | ||
1406 | break; | ||
1407 | case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: | ||
1408 | p->codec.h264.open_gop_size = ctrl->val; | ||
1409 | break; | ||
1410 | case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: | ||
1411 | switch (ctrl->val) { | ||
1412 | case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: | ||
1413 | p->codec.mpeg4.profile = | ||
1414 | S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE; | ||
1415 | break; | ||
1416 | case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: | ||
1417 | p->codec.mpeg4.profile = | ||
1418 | S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE; | ||
1419 | break; | ||
1420 | default: | ||
1421 | ret = -EINVAL; | ||
1422 | } | ||
1423 | break; | ||
1424 | case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: | ||
1425 | p->codec.mpeg4.quarter_pixel = ctrl->val; | ||
1426 | break; | ||
1427 | default: | ||
1428 | v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", | ||
1429 | ctrl->id, ctrl->val); | ||
1430 | ret = -EINVAL; | ||
1431 | } | ||
1432 | return ret; | ||
1433 | } | ||
1434 | |||
1435 | static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = { | ||
1436 | .s_ctrl = s5p_mfc_enc_s_ctrl, | ||
1437 | }; | ||
1438 | |||
1439 | int vidioc_s_parm(struct file *file, void *priv, struct v4l2_streamparm *a) | ||
1440 | { | ||
1441 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
1442 | |||
1443 | if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
1444 | ctx->enc_params.rc_framerate_num = | ||
1445 | a->parm.output.timeperframe.denominator; | ||
1446 | ctx->enc_params.rc_framerate_denom = | ||
1447 | a->parm.output.timeperframe.numerator; | ||
1448 | } else { | ||
1449 | mfc_err("Setting FPS is only possible for the output queue\n"); | ||
1450 | return -EINVAL; | ||
1451 | } | ||
1452 | return 0; | ||
1453 | } | ||
1454 | |||
1455 | int vidioc_g_parm(struct file *file, void *priv, struct v4l2_streamparm *a) | ||
1456 | { | ||
1457 | struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); | ||
1458 | |||
1459 | if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
1460 | a->parm.output.timeperframe.denominator = | ||
1461 | ctx->enc_params.rc_framerate_num; | ||
1462 | a->parm.output.timeperframe.numerator = | ||
1463 | ctx->enc_params.rc_framerate_denom; | ||
1464 | } else { | ||
1465 | mfc_err("Setting FPS is only possible for the output queue\n"); | ||
1466 | return -EINVAL; | ||
1467 | } | ||
1468 | return 0; | ||
1469 | } | ||
1470 | |||
1471 | static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { | ||
1472 | .vidioc_querycap = vidioc_querycap, | ||
1473 | .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, | ||
1474 | .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, | ||
1475 | .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, | ||
1476 | .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, | ||
1477 | .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, | ||
1478 | .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, | ||
1479 | .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, | ||
1480 | .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, | ||
1481 | .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt, | ||
1482 | .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt, | ||
1483 | .vidioc_reqbufs = vidioc_reqbufs, | ||
1484 | .vidioc_querybuf = vidioc_querybuf, | ||
1485 | .vidioc_qbuf = vidioc_qbuf, | ||
1486 | .vidioc_dqbuf = vidioc_dqbuf, | ||
1487 | .vidioc_streamon = vidioc_streamon, | ||
1488 | .vidioc_streamoff = vidioc_streamoff, | ||
1489 | .vidioc_s_parm = vidioc_s_parm, | ||
1490 | .vidioc_g_parm = vidioc_g_parm, | ||
1491 | }; | ||
1492 | |||
1493 | static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) | ||
1494 | { | ||
1495 | int i; | ||
1496 | |||
1497 | if (!fmt) | ||
1498 | return -EINVAL; | ||
1499 | if (fmt->num_planes != vb->num_planes) { | ||
1500 | mfc_err("invalid plane number for the format\n"); | ||
1501 | return -EINVAL; | ||
1502 | } | ||
1503 | for (i = 0; i < fmt->num_planes; i++) { | ||
1504 | if (!vb2_dma_contig_plane_paddr(vb, i)) { | ||
1505 | mfc_err("failed to get plane cookie\n"); | ||
1506 | return -EINVAL; | ||
1507 | } | ||
1508 | mfc_debug(2, "index: %d, plane[%d] cookie: 0x%08zx", | ||
1509 | vb->v4l2_buf.index, i, | ||
1510 | vb2_dma_contig_plane_paddr(vb, i)); | ||
1511 | } | ||
1512 | return 0; | ||
1513 | } | ||
1514 | |||
1515 | static int s5p_mfc_queue_setup(struct vb2_queue *vq, | ||
1516 | unsigned int *buf_count, unsigned int *plane_count, | ||
1517 | unsigned long psize[], void *allocators[]) | ||
1518 | { | ||
1519 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | ||
1520 | |||
1521 | if (ctx->state != MFCINST_GOT_INST) { | ||
1522 | mfc_err("inavlid state: %d\n", ctx->state); | ||
1523 | return -EINVAL; | ||
1524 | } | ||
1525 | if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
1526 | if (ctx->dst_fmt) | ||
1527 | *plane_count = ctx->dst_fmt->num_planes; | ||
1528 | else | ||
1529 | *plane_count = MFC_ENC_CAP_PLANE_COUNT; | ||
1530 | if (*buf_count < 1) | ||
1531 | *buf_count = 1; | ||
1532 | if (*buf_count > MFC_MAX_BUFFERS) | ||
1533 | *buf_count = MFC_MAX_BUFFERS; | ||
1534 | psize[0] = ctx->enc_dst_buf_size; | ||
1535 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | ||
1536 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
1537 | if (ctx->src_fmt) | ||
1538 | *plane_count = ctx->src_fmt->num_planes; | ||
1539 | else | ||
1540 | *plane_count = MFC_ENC_OUT_PLANE_COUNT; | ||
1541 | |||
1542 | if (*buf_count < 1) | ||
1543 | *buf_count = 1; | ||
1544 | if (*buf_count > MFC_MAX_BUFFERS) | ||
1545 | *buf_count = MFC_MAX_BUFFERS; | ||
1546 | psize[0] = ctx->luma_size; | ||
1547 | psize[1] = ctx->chroma_size; | ||
1548 | allocators[0] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | ||
1549 | allocators[1] = ctx->dev->alloc_ctx[MFC_BANK2_ALLOC_CTX]; | ||
1550 | } else { | ||
1551 | mfc_err("inavlid queue type: %d\n", vq->type); | ||
1552 | return -EINVAL; | ||
1553 | } | ||
1554 | return 0; | ||
1555 | } | ||
1556 | |||
1557 | static void s5p_mfc_unlock(struct vb2_queue *q) | ||
1558 | { | ||
1559 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | ||
1560 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1561 | |||
1562 | mutex_unlock(&dev->mfc_mutex); | ||
1563 | } | ||
1564 | |||
1565 | static void s5p_mfc_lock(struct vb2_queue *q) | ||
1566 | { | ||
1567 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | ||
1568 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1569 | |||
1570 | mutex_lock(&dev->mfc_mutex); | ||
1571 | } | ||
1572 | |||
1573 | static int s5p_mfc_buf_init(struct vb2_buffer *vb) | ||
1574 | { | ||
1575 | struct vb2_queue *vq = vb->vb2_queue; | ||
1576 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | ||
1577 | unsigned int i; | ||
1578 | int ret; | ||
1579 | |||
1580 | if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
1581 | ret = check_vb_with_fmt(ctx->dst_fmt, vb); | ||
1582 | if (ret < 0) | ||
1583 | return ret; | ||
1584 | i = vb->v4l2_buf.index; | ||
1585 | ctx->dst_bufs[i].b = vb; | ||
1586 | ctx->dst_bufs[i].cookie.stream = | ||
1587 | vb2_dma_contig_plane_paddr(vb, 0); | ||
1588 | ctx->dst_bufs_cnt++; | ||
1589 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
1590 | ret = check_vb_with_fmt(ctx->src_fmt, vb); | ||
1591 | if (ret < 0) | ||
1592 | return ret; | ||
1593 | i = vb->v4l2_buf.index; | ||
1594 | ctx->src_bufs[i].b = vb; | ||
1595 | ctx->src_bufs[i].cookie.raw.luma = | ||
1596 | vb2_dma_contig_plane_paddr(vb, 0); | ||
1597 | ctx->src_bufs[i].cookie.raw.chroma = | ||
1598 | vb2_dma_contig_plane_paddr(vb, 1); | ||
1599 | ctx->src_bufs_cnt++; | ||
1600 | } else { | ||
1601 | mfc_err("inavlid queue type: %d\n", vq->type); | ||
1602 | return -EINVAL; | ||
1603 | } | ||
1604 | return 0; | ||
1605 | } | ||
1606 | |||
1607 | static int s5p_mfc_buf_prepare(struct vb2_buffer *vb) | ||
1608 | { | ||
1609 | struct vb2_queue *vq = vb->vb2_queue; | ||
1610 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | ||
1611 | int ret; | ||
1612 | |||
1613 | if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
1614 | ret = check_vb_with_fmt(ctx->dst_fmt, vb); | ||
1615 | if (ret < 0) | ||
1616 | return ret; | ||
1617 | mfc_debug(2, "plane size: %ld, dst size: %d\n", | ||
1618 | vb2_plane_size(vb, 0), ctx->enc_dst_buf_size); | ||
1619 | if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) { | ||
1620 | mfc_err("plane size is too small for capture\n"); | ||
1621 | return -EINVAL; | ||
1622 | } | ||
1623 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
1624 | ret = check_vb_with_fmt(ctx->src_fmt, vb); | ||
1625 | if (ret < 0) | ||
1626 | return ret; | ||
1627 | mfc_debug(2, "plane size: %ld, luma size: %d\n", | ||
1628 | vb2_plane_size(vb, 0), ctx->luma_size); | ||
1629 | mfc_debug(2, "plane size: %ld, chroma size: %d\n", | ||
1630 | vb2_plane_size(vb, 1), ctx->chroma_size); | ||
1631 | if (vb2_plane_size(vb, 0) < ctx->luma_size || | ||
1632 | vb2_plane_size(vb, 1) < ctx->chroma_size) { | ||
1633 | mfc_err("plane size is too small for output\n"); | ||
1634 | return -EINVAL; | ||
1635 | } | ||
1636 | } else { | ||
1637 | mfc_err("inavlid queue type: %d\n", vq->type); | ||
1638 | return -EINVAL; | ||
1639 | } | ||
1640 | return 0; | ||
1641 | } | ||
1642 | |||
1643 | static int s5p_mfc_start_streaming(struct vb2_queue *q) | ||
1644 | { | ||
1645 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | ||
1646 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1647 | unsigned long flags; | ||
1648 | |||
1649 | v4l2_ctrl_handler_setup(&ctx->ctrl_handler); | ||
1650 | /* If context is ready then dev = work->data;schedule it to run */ | ||
1651 | if (s5p_mfc_ctx_ready(ctx)) { | ||
1652 | spin_lock_irqsave(&dev->condlock, flags); | ||
1653 | set_bit(ctx->num, &dev->ctx_work_bits); | ||
1654 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
1655 | } | ||
1656 | s5p_mfc_try_run(dev); | ||
1657 | return 0; | ||
1658 | } | ||
1659 | |||
1660 | static int s5p_mfc_stop_streaming(struct vb2_queue *q) | ||
1661 | { | ||
1662 | unsigned long flags; | ||
1663 | struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv); | ||
1664 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1665 | |||
1666 | if ((ctx->state == MFCINST_FINISHING || | ||
1667 | ctx->state == MFCINST_RUNNING) && | ||
1668 | dev->curr_ctx == ctx->num && dev->hw_lock) { | ||
1669 | ctx->state = MFCINST_ABORT; | ||
1670 | s5p_mfc_wait_for_done_ctx(ctx, S5P_FIMV_R2H_CMD_FRAME_DONE_RET, | ||
1671 | 0); | ||
1672 | } | ||
1673 | ctx->state = MFCINST_FINISHED; | ||
1674 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1675 | if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
1676 | s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst); | ||
1677 | INIT_LIST_HEAD(&ctx->dst_queue); | ||
1678 | ctx->dst_queue_cnt = 0; | ||
1679 | } | ||
1680 | if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
1681 | cleanup_ref_queue(ctx); | ||
1682 | s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src); | ||
1683 | INIT_LIST_HEAD(&ctx->src_queue); | ||
1684 | ctx->src_queue_cnt = 0; | ||
1685 | } | ||
1686 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1687 | return 0; | ||
1688 | } | ||
1689 | |||
1690 | static void s5p_mfc_buf_queue(struct vb2_buffer *vb) | ||
1691 | { | ||
1692 | struct vb2_queue *vq = vb->vb2_queue; | ||
1693 | struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv); | ||
1694 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1695 | unsigned long flags; | ||
1696 | struct s5p_mfc_buf *mfc_buf; | ||
1697 | |||
1698 | if (ctx->state == MFCINST_ERROR) { | ||
1699 | vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); | ||
1700 | cleanup_ref_queue(ctx); | ||
1701 | return; | ||
1702 | } | ||
1703 | if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | ||
1704 | mfc_buf = &ctx->dst_bufs[vb->v4l2_buf.index]; | ||
1705 | mfc_buf->used = 0; | ||
1706 | /* Mark destination as available for use by MFC */ | ||
1707 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1708 | list_add_tail(&mfc_buf->list, &ctx->dst_queue); | ||
1709 | ctx->dst_queue_cnt++; | ||
1710 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1711 | } else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { | ||
1712 | mfc_buf = &ctx->src_bufs[vb->v4l2_buf.index]; | ||
1713 | mfc_buf->used = 0; | ||
1714 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1715 | if (vb->v4l2_planes[0].bytesused == 0) { | ||
1716 | mfc_debug(1, "change state to FINISHING\n"); | ||
1717 | ctx->state = MFCINST_FINISHING; | ||
1718 | vb2_buffer_done(vb, VB2_BUF_STATE_DONE); | ||
1719 | cleanup_ref_queue(ctx); | ||
1720 | } else { | ||
1721 | list_add_tail(&mfc_buf->list, &ctx->src_queue); | ||
1722 | ctx->src_queue_cnt++; | ||
1723 | } | ||
1724 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1725 | } else { | ||
1726 | mfc_err("unsupported buffer type (%d)\n", vq->type); | ||
1727 | } | ||
1728 | if (s5p_mfc_ctx_ready(ctx)) { | ||
1729 | spin_lock_irqsave(&dev->condlock, flags); | ||
1730 | set_bit(ctx->num, &dev->ctx_work_bits); | ||
1731 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
1732 | } | ||
1733 | s5p_mfc_try_run(dev); | ||
1734 | } | ||
1735 | |||
1736 | static struct vb2_ops s5p_mfc_enc_qops = { | ||
1737 | .queue_setup = s5p_mfc_queue_setup, | ||
1738 | .wait_prepare = s5p_mfc_unlock, | ||
1739 | .wait_finish = s5p_mfc_lock, | ||
1740 | .buf_init = s5p_mfc_buf_init, | ||
1741 | .buf_prepare = s5p_mfc_buf_prepare, | ||
1742 | .start_streaming = s5p_mfc_start_streaming, | ||
1743 | .stop_streaming = s5p_mfc_stop_streaming, | ||
1744 | .buf_queue = s5p_mfc_buf_queue, | ||
1745 | }; | ||
1746 | |||
1747 | struct s5p_mfc_codec_ops *get_enc_codec_ops(void) | ||
1748 | { | ||
1749 | return &encoder_codec_ops; | ||
1750 | } | ||
1751 | |||
1752 | struct vb2_ops *get_enc_queue_ops(void) | ||
1753 | { | ||
1754 | return &s5p_mfc_enc_qops; | ||
1755 | } | ||
1756 | |||
1757 | const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void) | ||
1758 | { | ||
1759 | return &s5p_mfc_enc_ioctl_ops; | ||
1760 | } | ||
1761 | |||
1762 | #define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \ | ||
1763 | && V4L2_CTRL_DRIVER_PRIV(x)) | ||
1764 | |||
1765 | int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx) | ||
1766 | { | ||
1767 | struct v4l2_ctrl_config cfg; | ||
1768 | int i; | ||
1769 | |||
1770 | v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS); | ||
1771 | if (ctx->ctrl_handler.error) { | ||
1772 | mfc_err("v4l2_ctrl_handler_init failed\n"); | ||
1773 | return ctx->ctrl_handler.error; | ||
1774 | } | ||
1775 | for (i = 0; i < NUM_CTRLS; i++) { | ||
1776 | if (IS_MFC51_PRIV(controls[i].id)) { | ||
1777 | cfg.ops = &s5p_mfc_enc_ctrl_ops; | ||
1778 | cfg.id = controls[i].id; | ||
1779 | cfg.min = controls[i].minimum; | ||
1780 | cfg.max = controls[i].maximum; | ||
1781 | cfg.def = controls[i].default_value; | ||
1782 | cfg.name = controls[i].name; | ||
1783 | cfg.type = controls[i].type; | ||
1784 | cfg.flags = 0; | ||
1785 | |||
1786 | if (cfg.type == V4L2_CTRL_TYPE_MENU) { | ||
1787 | cfg.step = 0; | ||
1788 | cfg.menu_skip_mask = cfg.menu_skip_mask; | ||
1789 | cfg.qmenu = mfc51_get_menu(cfg.id); | ||
1790 | } else { | ||
1791 | cfg.step = controls[i].step; | ||
1792 | cfg.menu_skip_mask = 0; | ||
1793 | } | ||
1794 | ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler, | ||
1795 | &cfg, NULL); | ||
1796 | } else { | ||
1797 | if (controls[i].type == V4L2_CTRL_TYPE_MENU) { | ||
1798 | ctx->ctrls[i] = v4l2_ctrl_new_std_menu( | ||
1799 | &ctx->ctrl_handler, | ||
1800 | &s5p_mfc_enc_ctrl_ops, controls[i].id, | ||
1801 | controls[i].maximum, 0, | ||
1802 | controls[i].default_value); | ||
1803 | } else { | ||
1804 | ctx->ctrls[i] = v4l2_ctrl_new_std( | ||
1805 | &ctx->ctrl_handler, | ||
1806 | &s5p_mfc_enc_ctrl_ops, controls[i].id, | ||
1807 | controls[i].minimum, | ||
1808 | controls[i].maximum, controls[i].step, | ||
1809 | controls[i].default_value); | ||
1810 | } | ||
1811 | } | ||
1812 | if (ctx->ctrl_handler.error) { | ||
1813 | mfc_err("Adding control (%d) failed\n", i); | ||
1814 | return ctx->ctrl_handler.error; | ||
1815 | } | ||
1816 | if (controls[i].is_volatile && ctx->ctrls[i]) | ||
1817 | ctx->ctrls[i]->is_volatile = 1; | ||
1818 | } | ||
1819 | return 0; | ||
1820 | } | ||
1821 | |||
1822 | void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx) | ||
1823 | { | ||
1824 | int i; | ||
1825 | |||
1826 | v4l2_ctrl_handler_free(&ctx->ctrl_handler); | ||
1827 | for (i = 0; i < NUM_CTRLS; i++) | ||
1828 | ctx->ctrls[i] = NULL; | ||
1829 | } | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.h b/drivers/media/video/s5p-mfc/s5p_mfc_enc.h new file mode 100644 index 000000000000..405bdd3ee083 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_enc.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_ENC_H_ | ||
14 | #define S5P_MFC_ENC_H_ | ||
15 | |||
16 | struct s5p_mfc_codec_ops *get_enc_codec_ops(void); | ||
17 | struct vb2_ops *get_enc_queue_ops(void); | ||
18 | const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); | ||
19 | struct s5p_mfc_fmt *get_enc_def_fmt(bool src); | ||
20 | int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx); | ||
21 | void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx); | ||
22 | |||
23 | #endif /* S5P_MFC_ENC_H_ */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_intr.c b/drivers/media/video/s5p-mfc/s5p_mfc_intr.c new file mode 100644 index 000000000000..8f2f8bf4da7f --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_intr.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * drivers/media/video/samsung/mfc5/s5p_mfc_intr.c | ||
3 | * | ||
4 | * C file for Samsung MFC (Multi Function Codec - FIMV) driver | ||
5 | * This file contains functions used to wait for command completion. | ||
6 | * | ||
7 | * Kamil Debski, Copyright (C) 2011 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 | #include <linux/delay.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include "regs-mfc.h" | ||
21 | #include "s5p_mfc_common.h" | ||
22 | #include "s5p_mfc_debug.h" | ||
23 | #include "s5p_mfc_intr.h" | ||
24 | |||
25 | int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) | ||
26 | { | ||
27 | int ret; | ||
28 | |||
29 | ret = wait_event_interruptible_timeout(dev->queue, | ||
30 | (dev->int_cond && (dev->int_type == command | ||
31 | || dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), | ||
32 | msecs_to_jiffies(MFC_INT_TIMEOUT)); | ||
33 | if (ret == 0) { | ||
34 | mfc_err("Interrupt (dev->int_type:%d, command:%d) timed out\n", | ||
35 | dev->int_type, command); | ||
36 | return 1; | ||
37 | } else if (ret == -ERESTARTSYS) { | ||
38 | mfc_err("Interrupted by a signal\n"); | ||
39 | return 1; | ||
40 | } | ||
41 | mfc_debug(1, "Finished waiting (dev->int_type:%d, command: %d)\n", | ||
42 | dev->int_type, command); | ||
43 | if (dev->int_type == S5P_FIMV_R2H_CMD_ERR_RET) | ||
44 | return 1; | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev) | ||
49 | { | ||
50 | dev->int_cond = 0; | ||
51 | dev->int_type = 0; | ||
52 | dev->int_err = 0; | ||
53 | } | ||
54 | |||
55 | int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, | ||
56 | int command, int interrupt) | ||
57 | { | ||
58 | int ret; | ||
59 | |||
60 | if (interrupt) { | ||
61 | ret = wait_event_interruptible_timeout(ctx->queue, | ||
62 | (ctx->int_cond && (ctx->int_type == command | ||
63 | || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), | ||
64 | msecs_to_jiffies(MFC_INT_TIMEOUT)); | ||
65 | } else { | ||
66 | ret = wait_event_timeout(ctx->queue, | ||
67 | (ctx->int_cond && (ctx->int_type == command | ||
68 | || ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET)), | ||
69 | msecs_to_jiffies(MFC_INT_TIMEOUT)); | ||
70 | } | ||
71 | if (ret == 0) { | ||
72 | mfc_err("Interrupt (ctx->int_type:%d, command:%d) timed out\n", | ||
73 | ctx->int_type, command); | ||
74 | return 1; | ||
75 | } else if (ret == -ERESTARTSYS) { | ||
76 | mfc_err("Interrupted by a signal\n"); | ||
77 | return 1; | ||
78 | } | ||
79 | mfc_debug(1, "Finished waiting (ctx->int_type:%d, command: %d)\n", | ||
80 | ctx->int_type, command); | ||
81 | if (ctx->int_type == S5P_FIMV_R2H_CMD_ERR_RET) | ||
82 | return 1; | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx) | ||
87 | { | ||
88 | ctx->int_cond = 0; | ||
89 | ctx->int_type = 0; | ||
90 | ctx->int_err = 0; | ||
91 | } | ||
92 | |||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_intr.h b/drivers/media/video/s5p-mfc/s5p_mfc_intr.h new file mode 100644 index 000000000000..122d7732f745 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_intr.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * drivers/media/video/samsung/mfc5/s5p_mfc_intr.h | ||
3 | * | ||
4 | * Header file for Samsung MFC (Multi Function Codec - FIMV) driver | ||
5 | * It contains waiting functions declarations. | ||
6 | * | ||
7 | * Kamil Debski, Copyright (C) 2011 Samsung Electronics | ||
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_INTR_H_ | ||
16 | #define S5P_MFC_INTR_H_ | ||
17 | |||
18 | #include "s5p_mfc_common.h" | ||
19 | |||
20 | int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, | ||
21 | int command, int interrupt); | ||
22 | int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command); | ||
23 | void s5p_mfc_clean_ctx_int_flags(struct s5p_mfc_ctx *ctx); | ||
24 | void s5p_mfc_clean_dev_int_flags(struct s5p_mfc_dev *dev); | ||
25 | |||
26 | #endif /* S5P_MFC_INTR_H_ */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.c b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c new file mode 100644 index 000000000000..7b239168c199 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_opr.c | |||
@@ -0,0 +1,1397 @@ | |||
1 | /* | ||
2 | * drivers/media/video/samsung/mfc5/s5p_mfc_opr.c | ||
3 | * | ||
4 | * Samsung MFC (Multi Function Codec - FIMV) driver | ||
5 | * This file contains hw related functions. | ||
6 | * | ||
7 | * Kamil Debski, Copyright (c) 2011 Samsung Electronics | ||
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 | #include "regs-mfc.h" | ||
16 | #include "s5p_mfc_cmd.h" | ||
17 | #include "s5p_mfc_common.h" | ||
18 | #include "s5p_mfc_ctrl.h" | ||
19 | #include "s5p_mfc_debug.h" | ||
20 | #include "s5p_mfc_intr.h" | ||
21 | #include "s5p_mfc_opr.h" | ||
22 | #include "s5p_mfc_pm.h" | ||
23 | #include "s5p_mfc_shm.h" | ||
24 | #include <asm/cacheflush.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/dma-mapping.h> | ||
27 | #include <linux/err.h> | ||
28 | #include <linux/firmware.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <linux/jiffies.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/sched.h> | ||
33 | |||
34 | #define OFFSETA(x) (((x) - dev->bank1) >> MFC_OFFSET_SHIFT) | ||
35 | #define OFFSETB(x) (((x) - dev->bank2) >> MFC_OFFSET_SHIFT) | ||
36 | |||
37 | /* Allocate temporary buffers for decoding */ | ||
38 | int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx) | ||
39 | { | ||
40 | void *desc_virt; | ||
41 | struct s5p_mfc_dev *dev = ctx->dev; | ||
42 | |||
43 | ctx->desc_buf = vb2_dma_contig_memops.alloc( | ||
44 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], DESC_BUF_SIZE); | ||
45 | if (IS_ERR_VALUE((int)ctx->desc_buf)) { | ||
46 | ctx->desc_buf = 0; | ||
47 | mfc_err("Allocating DESC buffer failed\n"); | ||
48 | return -ENOMEM; | ||
49 | } | ||
50 | ctx->desc_phys = s5p_mfc_mem_cookie( | ||
51 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->desc_buf); | ||
52 | BUG_ON(ctx->desc_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); | ||
53 | desc_virt = vb2_dma_contig_memops.vaddr(ctx->desc_buf); | ||
54 | if (desc_virt == NULL) { | ||
55 | vb2_dma_contig_memops.put(ctx->desc_buf); | ||
56 | ctx->desc_phys = 0; | ||
57 | ctx->desc_buf = 0; | ||
58 | mfc_err("Remapping DESC buffer failed\n"); | ||
59 | return -ENOMEM; | ||
60 | } | ||
61 | memset(desc_virt, 0, DESC_BUF_SIZE); | ||
62 | wmb(); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | /* Release temporary buffers for decoding */ | ||
67 | void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx) | ||
68 | { | ||
69 | if (ctx->desc_phys) { | ||
70 | vb2_dma_contig_memops.put(ctx->desc_buf); | ||
71 | ctx->desc_phys = 0; | ||
72 | ctx->desc_buf = 0; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | /* Allocate codec buffers */ | ||
77 | int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx) | ||
78 | { | ||
79 | struct s5p_mfc_dev *dev = ctx->dev; | ||
80 | unsigned int enc_ref_y_size = 0; | ||
81 | unsigned int enc_ref_c_size = 0; | ||
82 | unsigned int guard_width, guard_height; | ||
83 | |||
84 | if (ctx->type == MFCINST_DECODER) { | ||
85 | mfc_debug(2, "Luma size:%d Chroma size:%d MV size:%d\n", | ||
86 | ctx->luma_size, ctx->chroma_size, ctx->mv_size); | ||
87 | mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count); | ||
88 | } else if (ctx->type == MFCINST_ENCODER) { | ||
89 | enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) | ||
90 | * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); | ||
91 | enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); | ||
92 | |||
93 | if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { | ||
94 | enc_ref_c_size = ALIGN(ctx->img_width, | ||
95 | S5P_FIMV_NV12MT_HALIGN) | ||
96 | * ALIGN(ctx->img_height >> 1, | ||
97 | S5P_FIMV_NV12MT_VALIGN); | ||
98 | enc_ref_c_size = ALIGN(enc_ref_c_size, | ||
99 | S5P_FIMV_NV12MT_SALIGN); | ||
100 | } else { | ||
101 | guard_width = ALIGN(ctx->img_width + 16, | ||
102 | S5P_FIMV_NV12MT_HALIGN); | ||
103 | guard_height = ALIGN((ctx->img_height >> 1) + 4, | ||
104 | S5P_FIMV_NV12MT_VALIGN); | ||
105 | enc_ref_c_size = ALIGN(guard_width * guard_height, | ||
106 | S5P_FIMV_NV12MT_SALIGN); | ||
107 | } | ||
108 | mfc_debug(2, "recon luma size: %d chroma size: %d\n", | ||
109 | enc_ref_y_size, enc_ref_c_size); | ||
110 | } else { | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | /* Codecs have different memory requirements */ | ||
114 | switch (ctx->codec_mode) { | ||
115 | case S5P_FIMV_CODEC_H264_DEC: | ||
116 | ctx->bank1_size = | ||
117 | ALIGN(S5P_FIMV_DEC_NB_IP_SIZE + | ||
118 | S5P_FIMV_DEC_VERT_NB_MV_SIZE, | ||
119 | S5P_FIMV_DEC_BUF_ALIGN); | ||
120 | ctx->bank2_size = ctx->total_dpb_count * ctx->mv_size; | ||
121 | break; | ||
122 | case S5P_FIMV_CODEC_MPEG4_DEC: | ||
123 | ctx->bank1_size = | ||
124 | ALIGN(S5P_FIMV_DEC_NB_DCAC_SIZE + | ||
125 | S5P_FIMV_DEC_UPNB_MV_SIZE + | ||
126 | S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + | ||
127 | S5P_FIMV_DEC_STX_PARSER_SIZE + | ||
128 | S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE, | ||
129 | S5P_FIMV_DEC_BUF_ALIGN); | ||
130 | ctx->bank2_size = 0; | ||
131 | break; | ||
132 | case S5P_FIMV_CODEC_VC1RCV_DEC: | ||
133 | case S5P_FIMV_CODEC_VC1_DEC: | ||
134 | ctx->bank1_size = | ||
135 | ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + | ||
136 | S5P_FIMV_DEC_UPNB_MV_SIZE + | ||
137 | S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + | ||
138 | S5P_FIMV_DEC_NB_DCAC_SIZE + | ||
139 | 3 * S5P_FIMV_DEC_VC1_BITPLANE_SIZE, | ||
140 | S5P_FIMV_DEC_BUF_ALIGN); | ||
141 | ctx->bank2_size = 0; | ||
142 | break; | ||
143 | case S5P_FIMV_CODEC_MPEG2_DEC: | ||
144 | ctx->bank1_size = 0; | ||
145 | ctx->bank2_size = 0; | ||
146 | break; | ||
147 | case S5P_FIMV_CODEC_H263_DEC: | ||
148 | ctx->bank1_size = | ||
149 | ALIGN(S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE + | ||
150 | S5P_FIMV_DEC_UPNB_MV_SIZE + | ||
151 | S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE + | ||
152 | S5P_FIMV_DEC_NB_DCAC_SIZE, | ||
153 | S5P_FIMV_DEC_BUF_ALIGN); | ||
154 | ctx->bank2_size = 0; | ||
155 | break; | ||
156 | case S5P_FIMV_CODEC_H264_ENC: | ||
157 | ctx->bank1_size = (enc_ref_y_size * 2) + | ||
158 | S5P_FIMV_ENC_UPMV_SIZE + | ||
159 | S5P_FIMV_ENC_COLFLG_SIZE + | ||
160 | S5P_FIMV_ENC_INTRAMD_SIZE + | ||
161 | S5P_FIMV_ENC_NBORINFO_SIZE; | ||
162 | ctx->bank2_size = (enc_ref_y_size * 2) + | ||
163 | (enc_ref_c_size * 4) + | ||
164 | S5P_FIMV_ENC_INTRAPRED_SIZE; | ||
165 | break; | ||
166 | case S5P_FIMV_CODEC_MPEG4_ENC: | ||
167 | ctx->bank1_size = (enc_ref_y_size * 2) + | ||
168 | S5P_FIMV_ENC_UPMV_SIZE + | ||
169 | S5P_FIMV_ENC_COLFLG_SIZE + | ||
170 | S5P_FIMV_ENC_ACDCCOEF_SIZE; | ||
171 | ctx->bank2_size = (enc_ref_y_size * 2) + | ||
172 | (enc_ref_c_size * 4); | ||
173 | break; | ||
174 | case S5P_FIMV_CODEC_H263_ENC: | ||
175 | ctx->bank1_size = (enc_ref_y_size * 2) + | ||
176 | S5P_FIMV_ENC_UPMV_SIZE + | ||
177 | S5P_FIMV_ENC_ACDCCOEF_SIZE; | ||
178 | ctx->bank2_size = (enc_ref_y_size * 2) + | ||
179 | (enc_ref_c_size * 4); | ||
180 | break; | ||
181 | default: | ||
182 | break; | ||
183 | } | ||
184 | /* Allocate only if memory from bank 1 is necessary */ | ||
185 | if (ctx->bank1_size > 0) { | ||
186 | ctx->bank1_buf = vb2_dma_contig_memops.alloc( | ||
187 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_size); | ||
188 | if (IS_ERR(ctx->bank1_buf)) { | ||
189 | ctx->bank1_buf = 0; | ||
190 | printk(KERN_ERR | ||
191 | "Buf alloc for decoding failed (port A)\n"); | ||
192 | return -ENOMEM; | ||
193 | } | ||
194 | ctx->bank1_phys = s5p_mfc_mem_cookie( | ||
195 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->bank1_buf); | ||
196 | BUG_ON(ctx->bank1_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); | ||
197 | } | ||
198 | /* Allocate only if memory from bank 2 is necessary */ | ||
199 | if (ctx->bank2_size > 0) { | ||
200 | ctx->bank2_buf = vb2_dma_contig_memops.alloc( | ||
201 | dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_size); | ||
202 | if (IS_ERR(ctx->bank2_buf)) { | ||
203 | ctx->bank2_buf = 0; | ||
204 | mfc_err("Buf alloc for decoding failed (port B)\n"); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | ctx->bank2_phys = s5p_mfc_mem_cookie( | ||
208 | dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], ctx->bank2_buf); | ||
209 | BUG_ON(ctx->bank2_phys & ((1 << MFC_BANK2_ALIGN_ORDER) - 1)); | ||
210 | } | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | /* Release buffers allocated for codec */ | ||
215 | void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx) | ||
216 | { | ||
217 | if (ctx->bank1_buf) { | ||
218 | vb2_dma_contig_memops.put(ctx->bank1_buf); | ||
219 | ctx->bank1_buf = 0; | ||
220 | ctx->bank1_phys = 0; | ||
221 | ctx->bank1_size = 0; | ||
222 | } | ||
223 | if (ctx->bank2_buf) { | ||
224 | vb2_dma_contig_memops.put(ctx->bank2_buf); | ||
225 | ctx->bank2_buf = 0; | ||
226 | ctx->bank2_phys = 0; | ||
227 | ctx->bank2_size = 0; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /* Allocate memory for instance data buffer */ | ||
232 | int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx) | ||
233 | { | ||
234 | void *context_virt; | ||
235 | struct s5p_mfc_dev *dev = ctx->dev; | ||
236 | |||
237 | if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC || | ||
238 | ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) | ||
239 | ctx->ctx_size = MFC_H264_CTX_BUF_SIZE; | ||
240 | else | ||
241 | ctx->ctx_size = MFC_CTX_BUF_SIZE; | ||
242 | ctx->ctx_buf = vb2_dma_contig_memops.alloc( | ||
243 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_size); | ||
244 | if (IS_ERR(ctx->ctx_buf)) { | ||
245 | mfc_err("Allocating context buffer failed\n"); | ||
246 | ctx->ctx_phys = 0; | ||
247 | ctx->ctx_buf = 0; | ||
248 | return -ENOMEM; | ||
249 | } | ||
250 | ctx->ctx_phys = s5p_mfc_mem_cookie( | ||
251 | dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], ctx->ctx_buf); | ||
252 | BUG_ON(ctx->ctx_phys & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); | ||
253 | ctx->ctx_ofs = OFFSETA(ctx->ctx_phys); | ||
254 | context_virt = vb2_dma_contig_memops.vaddr(ctx->ctx_buf); | ||
255 | if (context_virt == NULL) { | ||
256 | mfc_err("Remapping instance buffer failed\n"); | ||
257 | vb2_dma_contig_memops.put(ctx->ctx_buf); | ||
258 | ctx->ctx_phys = 0; | ||
259 | ctx->ctx_buf = 0; | ||
260 | return -ENOMEM; | ||
261 | } | ||
262 | /* Zero content of the allocated memory */ | ||
263 | memset(context_virt, 0, ctx->ctx_size); | ||
264 | wmb(); | ||
265 | if (s5p_mfc_init_shm(ctx) < 0) { | ||
266 | vb2_dma_contig_memops.put(ctx->ctx_buf); | ||
267 | ctx->ctx_phys = 0; | ||
268 | ctx->ctx_buf = 0; | ||
269 | return -ENOMEM; | ||
270 | } | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | /* Release instance buffer */ | ||
275 | void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx) | ||
276 | { | ||
277 | if (ctx->ctx_buf) { | ||
278 | vb2_dma_contig_memops.put(ctx->ctx_buf); | ||
279 | ctx->ctx_phys = 0; | ||
280 | ctx->ctx_buf = 0; | ||
281 | } | ||
282 | if (ctx->shm_alloc) { | ||
283 | vb2_dma_contig_memops.put(ctx->shm_alloc); | ||
284 | ctx->shm_alloc = 0; | ||
285 | ctx->shm = 0; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /* Set registers for decoding temporary buffers */ | ||
290 | void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) | ||
291 | { | ||
292 | struct s5p_mfc_dev *dev = ctx->dev; | ||
293 | |||
294 | mfc_write(dev, OFFSETA(ctx->desc_phys), S5P_FIMV_SI_CH0_DESC_ADR); | ||
295 | mfc_write(dev, DESC_BUF_SIZE, S5P_FIMV_SI_CH0_DESC_SIZE); | ||
296 | } | ||
297 | |||
298 | /* Set registers for shared buffer */ | ||
299 | void s5p_mfc_set_shared_buffer(struct s5p_mfc_ctx *ctx) | ||
300 | { | ||
301 | struct s5p_mfc_dev *dev = ctx->dev; | ||
302 | mfc_write(dev, ctx->shm_ofs, S5P_FIMV_SI_CH0_HOST_WR_ADR); | ||
303 | } | ||
304 | |||
305 | /* Set registers for decoding stream buffer */ | ||
306 | int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, | ||
307 | unsigned int start_num_byte, unsigned int buf_size) | ||
308 | { | ||
309 | struct s5p_mfc_dev *dev = ctx->dev; | ||
310 | |||
311 | mfc_write(dev, OFFSETA(buf_addr), S5P_FIMV_SI_CH0_SB_ST_ADR); | ||
312 | mfc_write(dev, ctx->dec_src_buf_size, S5P_FIMV_SI_CH0_CPB_SIZE); | ||
313 | mfc_write(dev, buf_size, S5P_FIMV_SI_CH0_SB_FRM_SIZE); | ||
314 | s5p_mfc_write_shm(ctx, start_num_byte, START_BYTE_NUM); | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* Set decoding frame buffer */ | ||
319 | int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx) | ||
320 | { | ||
321 | unsigned int frame_size, i; | ||
322 | unsigned int frame_size_ch, frame_size_mv; | ||
323 | struct s5p_mfc_dev *dev = ctx->dev; | ||
324 | unsigned int dpb; | ||
325 | size_t buf_addr1, buf_addr2; | ||
326 | int buf_size1, buf_size2; | ||
327 | |||
328 | buf_addr1 = ctx->bank1_phys; | ||
329 | buf_size1 = ctx->bank1_size; | ||
330 | buf_addr2 = ctx->bank2_phys; | ||
331 | buf_size2 = ctx->bank2_size; | ||
332 | dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & | ||
333 | ~S5P_FIMV_DPB_COUNT_MASK; | ||
334 | mfc_write(dev, ctx->total_dpb_count | dpb, | ||
335 | S5P_FIMV_SI_CH0_DPB_CONF_CTRL); | ||
336 | s5p_mfc_set_shared_buffer(ctx); | ||
337 | switch (ctx->codec_mode) { | ||
338 | case S5P_FIMV_CODEC_H264_DEC: | ||
339 | mfc_write(dev, OFFSETA(buf_addr1), | ||
340 | S5P_FIMV_H264_VERT_NB_MV_ADR); | ||
341 | buf_addr1 += S5P_FIMV_DEC_VERT_NB_MV_SIZE; | ||
342 | buf_size1 -= S5P_FIMV_DEC_VERT_NB_MV_SIZE; | ||
343 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_NB_IP_ADR); | ||
344 | buf_addr1 += S5P_FIMV_DEC_NB_IP_SIZE; | ||
345 | buf_size1 -= S5P_FIMV_DEC_NB_IP_SIZE; | ||
346 | break; | ||
347 | case S5P_FIMV_CODEC_MPEG4_DEC: | ||
348 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_NB_DCAC_ADR); | ||
349 | buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; | ||
350 | buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; | ||
351 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_NB_MV_ADR); | ||
352 | buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; | ||
353 | buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; | ||
354 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SA_MV_ADR); | ||
355 | buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; | ||
356 | buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; | ||
357 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_SP_ADR); | ||
358 | buf_addr1 += S5P_FIMV_DEC_STX_PARSER_SIZE; | ||
359 | buf_size1 -= S5P_FIMV_DEC_STX_PARSER_SIZE; | ||
360 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_OT_LINE_ADR); | ||
361 | buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; | ||
362 | buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; | ||
363 | break; | ||
364 | case S5P_FIMV_CODEC_H263_DEC: | ||
365 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_OT_LINE_ADR); | ||
366 | buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; | ||
367 | buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; | ||
368 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_NB_MV_ADR); | ||
369 | buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; | ||
370 | buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; | ||
371 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_SA_MV_ADR); | ||
372 | buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; | ||
373 | buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; | ||
374 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_NB_DCAC_ADR); | ||
375 | buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; | ||
376 | buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; | ||
377 | break; | ||
378 | case S5P_FIMV_CODEC_VC1_DEC: | ||
379 | case S5P_FIMV_CODEC_VC1RCV_DEC: | ||
380 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_NB_DCAC_ADR); | ||
381 | buf_addr1 += S5P_FIMV_DEC_NB_DCAC_SIZE; | ||
382 | buf_size1 -= S5P_FIMV_DEC_NB_DCAC_SIZE; | ||
383 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_OT_LINE_ADR); | ||
384 | buf_addr1 += S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; | ||
385 | buf_size1 -= S5P_FIMV_DEC_OVERLAP_TRANSFORM_SIZE; | ||
386 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_UP_NB_MV_ADR); | ||
387 | buf_addr1 += S5P_FIMV_DEC_UPNB_MV_SIZE; | ||
388 | buf_size1 -= S5P_FIMV_DEC_UPNB_MV_SIZE; | ||
389 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_SA_MV_ADR); | ||
390 | buf_addr1 += S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; | ||
391 | buf_size1 -= S5P_FIMV_DEC_SUB_ANCHOR_MV_SIZE; | ||
392 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE3_ADR); | ||
393 | buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; | ||
394 | buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; | ||
395 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE2_ADR); | ||
396 | buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; | ||
397 | buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; | ||
398 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_VC1_BITPLANE1_ADR); | ||
399 | buf_addr1 += S5P_FIMV_DEC_VC1_BITPLANE_SIZE; | ||
400 | buf_size1 -= S5P_FIMV_DEC_VC1_BITPLANE_SIZE; | ||
401 | break; | ||
402 | case S5P_FIMV_CODEC_MPEG2_DEC: | ||
403 | break; | ||
404 | default: | ||
405 | mfc_err("Unknown codec for decoding (%x)\n", | ||
406 | ctx->codec_mode); | ||
407 | return -EINVAL; | ||
408 | break; | ||
409 | } | ||
410 | frame_size = ctx->luma_size; | ||
411 | frame_size_ch = ctx->chroma_size; | ||
412 | frame_size_mv = ctx->mv_size; | ||
413 | mfc_debug(2, "Frm size: %d ch: %d mv: %d\n", frame_size, frame_size_ch, | ||
414 | frame_size_mv); | ||
415 | for (i = 0; i < ctx->total_dpb_count; i++) { | ||
416 | /* Bank2 */ | ||
417 | mfc_debug(2, "Luma %d: %x\n", i, | ||
418 | ctx->dst_bufs[i].cookie.raw.luma); | ||
419 | mfc_write(dev, OFFSETB(ctx->dst_bufs[i].cookie.raw.luma), | ||
420 | S5P_FIMV_DEC_LUMA_ADR + i * 4); | ||
421 | mfc_debug(2, "\tChroma %d: %x\n", i, | ||
422 | ctx->dst_bufs[i].cookie.raw.chroma); | ||
423 | mfc_write(dev, OFFSETA(ctx->dst_bufs[i].cookie.raw.chroma), | ||
424 | S5P_FIMV_DEC_CHROMA_ADR + i * 4); | ||
425 | if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) { | ||
426 | mfc_debug(2, "\tBuf2: %x, size: %d\n", | ||
427 | buf_addr2, buf_size2); | ||
428 | mfc_write(dev, OFFSETB(buf_addr2), | ||
429 | S5P_FIMV_H264_MV_ADR + i * 4); | ||
430 | buf_addr2 += frame_size_mv; | ||
431 | buf_size2 -= frame_size_mv; | ||
432 | } | ||
433 | } | ||
434 | mfc_debug(2, "Buf1: %u, buf_size1: %d\n", buf_addr1, buf_size1); | ||
435 | mfc_debug(2, "Buf 1/2 size after: %d/%d (frames %d)\n", | ||
436 | buf_size1, buf_size2, ctx->total_dpb_count); | ||
437 | if (buf_size1 < 0 || buf_size2 < 0) { | ||
438 | mfc_debug(2, "Not enough memory has been allocated\n"); | ||
439 | return -ENOMEM; | ||
440 | } | ||
441 | s5p_mfc_write_shm(ctx, frame_size, ALLOC_LUMA_DPB_SIZE); | ||
442 | s5p_mfc_write_shm(ctx, frame_size_ch, ALLOC_CHROMA_DPB_SIZE); | ||
443 | if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC) | ||
444 | s5p_mfc_write_shm(ctx, frame_size_mv, ALLOC_MV_SIZE); | ||
445 | mfc_write(dev, ((S5P_FIMV_CH_INIT_BUFS & S5P_FIMV_CH_MASK) | ||
446 | << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), | ||
447 | S5P_FIMV_SI_CH0_INST_ID); | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | /* Set registers for encoding stream buffer */ | ||
452 | int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, | ||
453 | unsigned long addr, unsigned int size) | ||
454 | { | ||
455 | struct s5p_mfc_dev *dev = ctx->dev; | ||
456 | |||
457 | mfc_write(dev, OFFSETA(addr), S5P_FIMV_ENC_SI_CH0_SB_ADR); | ||
458 | mfc_write(dev, size, S5P_FIMV_ENC_SI_CH0_SB_SIZE); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, | ||
463 | unsigned long y_addr, unsigned long c_addr) | ||
464 | { | ||
465 | struct s5p_mfc_dev *dev = ctx->dev; | ||
466 | |||
467 | mfc_write(dev, OFFSETB(y_addr), S5P_FIMV_ENC_SI_CH0_CUR_Y_ADR); | ||
468 | mfc_write(dev, OFFSETB(c_addr), S5P_FIMV_ENC_SI_CH0_CUR_C_ADR); | ||
469 | } | ||
470 | |||
471 | void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, | ||
472 | unsigned long *y_addr, unsigned long *c_addr) | ||
473 | { | ||
474 | struct s5p_mfc_dev *dev = ctx->dev; | ||
475 | |||
476 | *y_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_Y_ADDR) | ||
477 | << MFC_OFFSET_SHIFT); | ||
478 | *c_addr = dev->bank2 + (mfc_read(dev, S5P_FIMV_ENCODED_C_ADDR) | ||
479 | << MFC_OFFSET_SHIFT); | ||
480 | } | ||
481 | |||
482 | /* Set encoding ref & codec buffer */ | ||
483 | int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *ctx) | ||
484 | { | ||
485 | struct s5p_mfc_dev *dev = ctx->dev; | ||
486 | size_t buf_addr1, buf_addr2; | ||
487 | size_t buf_size1, buf_size2; | ||
488 | unsigned int enc_ref_y_size, enc_ref_c_size; | ||
489 | unsigned int guard_width, guard_height; | ||
490 | int i; | ||
491 | |||
492 | buf_addr1 = ctx->bank1_phys; | ||
493 | buf_size1 = ctx->bank1_size; | ||
494 | buf_addr2 = ctx->bank2_phys; | ||
495 | buf_size2 = ctx->bank2_size; | ||
496 | enc_ref_y_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) | ||
497 | * ALIGN(ctx->img_height, S5P_FIMV_NV12MT_VALIGN); | ||
498 | enc_ref_y_size = ALIGN(enc_ref_y_size, S5P_FIMV_NV12MT_SALIGN); | ||
499 | if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) { | ||
500 | enc_ref_c_size = ALIGN(ctx->img_width, S5P_FIMV_NV12MT_HALIGN) | ||
501 | * ALIGN((ctx->img_height >> 1), S5P_FIMV_NV12MT_VALIGN); | ||
502 | enc_ref_c_size = ALIGN(enc_ref_c_size, S5P_FIMV_NV12MT_SALIGN); | ||
503 | } else { | ||
504 | guard_width = ALIGN(ctx->img_width + 16, | ||
505 | S5P_FIMV_NV12MT_HALIGN); | ||
506 | guard_height = ALIGN((ctx->img_height >> 1) + 4, | ||
507 | S5P_FIMV_NV12MT_VALIGN); | ||
508 | enc_ref_c_size = ALIGN(guard_width * guard_height, | ||
509 | S5P_FIMV_NV12MT_SALIGN); | ||
510 | } | ||
511 | mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", buf_size1, buf_size2); | ||
512 | switch (ctx->codec_mode) { | ||
513 | case S5P_FIMV_CODEC_H264_ENC: | ||
514 | for (i = 0; i < 2; i++) { | ||
515 | mfc_write(dev, OFFSETA(buf_addr1), | ||
516 | S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); | ||
517 | buf_addr1 += enc_ref_y_size; | ||
518 | buf_size1 -= enc_ref_y_size; | ||
519 | |||
520 | mfc_write(dev, OFFSETB(buf_addr2), | ||
521 | S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); | ||
522 | buf_addr2 += enc_ref_y_size; | ||
523 | buf_size2 -= enc_ref_y_size; | ||
524 | } | ||
525 | for (i = 0; i < 4; i++) { | ||
526 | mfc_write(dev, OFFSETB(buf_addr2), | ||
527 | S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); | ||
528 | buf_addr2 += enc_ref_c_size; | ||
529 | buf_size2 -= enc_ref_c_size; | ||
530 | } | ||
531 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H264_UP_MV_ADR); | ||
532 | buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; | ||
533 | buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; | ||
534 | mfc_write(dev, OFFSETA(buf_addr1), | ||
535 | S5P_FIMV_H264_COZERO_FLAG_ADR); | ||
536 | buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; | ||
537 | buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; | ||
538 | mfc_write(dev, OFFSETA(buf_addr1), | ||
539 | S5P_FIMV_H264_UP_INTRA_MD_ADR); | ||
540 | buf_addr1 += S5P_FIMV_ENC_INTRAMD_SIZE; | ||
541 | buf_size1 -= S5P_FIMV_ENC_INTRAMD_SIZE; | ||
542 | mfc_write(dev, OFFSETB(buf_addr2), | ||
543 | S5P_FIMV_H264_UP_INTRA_PRED_ADR); | ||
544 | buf_addr2 += S5P_FIMV_ENC_INTRAPRED_SIZE; | ||
545 | buf_size2 -= S5P_FIMV_ENC_INTRAPRED_SIZE; | ||
546 | mfc_write(dev, OFFSETA(buf_addr1), | ||
547 | S5P_FIMV_H264_NBOR_INFO_ADR); | ||
548 | buf_addr1 += S5P_FIMV_ENC_NBORINFO_SIZE; | ||
549 | buf_size1 -= S5P_FIMV_ENC_NBORINFO_SIZE; | ||
550 | mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", | ||
551 | buf_size1, buf_size2); | ||
552 | break; | ||
553 | case S5P_FIMV_CODEC_MPEG4_ENC: | ||
554 | for (i = 0; i < 2; i++) { | ||
555 | mfc_write(dev, OFFSETA(buf_addr1), | ||
556 | S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); | ||
557 | buf_addr1 += enc_ref_y_size; | ||
558 | buf_size1 -= enc_ref_y_size; | ||
559 | mfc_write(dev, OFFSETB(buf_addr2), | ||
560 | S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); | ||
561 | buf_addr2 += enc_ref_y_size; | ||
562 | buf_size2 -= enc_ref_y_size; | ||
563 | } | ||
564 | for (i = 0; i < 4; i++) { | ||
565 | mfc_write(dev, OFFSETB(buf_addr2), | ||
566 | S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); | ||
567 | buf_addr2 += enc_ref_c_size; | ||
568 | buf_size2 -= enc_ref_c_size; | ||
569 | } | ||
570 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_MPEG4_UP_MV_ADR); | ||
571 | buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; | ||
572 | buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; | ||
573 | mfc_write(dev, OFFSETA(buf_addr1), | ||
574 | S5P_FIMV_MPEG4_COZERO_FLAG_ADR); | ||
575 | buf_addr1 += S5P_FIMV_ENC_COLFLG_SIZE; | ||
576 | buf_size1 -= S5P_FIMV_ENC_COLFLG_SIZE; | ||
577 | mfc_write(dev, OFFSETA(buf_addr1), | ||
578 | S5P_FIMV_MPEG4_ACDC_COEF_ADR); | ||
579 | buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; | ||
580 | buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; | ||
581 | mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", | ||
582 | buf_size1, buf_size2); | ||
583 | break; | ||
584 | case S5P_FIMV_CODEC_H263_ENC: | ||
585 | for (i = 0; i < 2; i++) { | ||
586 | mfc_write(dev, OFFSETA(buf_addr1), | ||
587 | S5P_FIMV_ENC_REF0_LUMA_ADR + (4 * i)); | ||
588 | buf_addr1 += enc_ref_y_size; | ||
589 | buf_size1 -= enc_ref_y_size; | ||
590 | mfc_write(dev, OFFSETB(buf_addr2), | ||
591 | S5P_FIMV_ENC_REF2_LUMA_ADR + (4 * i)); | ||
592 | buf_addr2 += enc_ref_y_size; | ||
593 | buf_size2 -= enc_ref_y_size; | ||
594 | } | ||
595 | for (i = 0; i < 4; i++) { | ||
596 | mfc_write(dev, OFFSETB(buf_addr2), | ||
597 | S5P_FIMV_ENC_REF0_CHROMA_ADR + (4 * i)); | ||
598 | buf_addr2 += enc_ref_c_size; | ||
599 | buf_size2 -= enc_ref_c_size; | ||
600 | } | ||
601 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_UP_MV_ADR); | ||
602 | buf_addr1 += S5P_FIMV_ENC_UPMV_SIZE; | ||
603 | buf_size1 -= S5P_FIMV_ENC_UPMV_SIZE; | ||
604 | mfc_write(dev, OFFSETA(buf_addr1), S5P_FIMV_H263_ACDC_COEF_ADR); | ||
605 | buf_addr1 += S5P_FIMV_ENC_ACDCCOEF_SIZE; | ||
606 | buf_size1 -= S5P_FIMV_ENC_ACDCCOEF_SIZE; | ||
607 | mfc_debug(2, "buf_size1: %d, buf_size2: %d\n", | ||
608 | buf_size1, buf_size2); | ||
609 | break; | ||
610 | default: | ||
611 | mfc_err("Unknown codec set for encoding: %d\n", | ||
612 | ctx->codec_mode); | ||
613 | return -EINVAL; | ||
614 | } | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) | ||
619 | { | ||
620 | struct s5p_mfc_dev *dev = ctx->dev; | ||
621 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
622 | unsigned int reg; | ||
623 | unsigned int shm; | ||
624 | |||
625 | /* width */ | ||
626 | mfc_write(dev, ctx->img_width, S5P_FIMV_ENC_HSIZE_PX); | ||
627 | /* height */ | ||
628 | mfc_write(dev, ctx->img_height, S5P_FIMV_ENC_VSIZE_PX); | ||
629 | /* pictype : enable, IDR period */ | ||
630 | reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); | ||
631 | reg |= (1 << 18); | ||
632 | reg &= ~(0xFFFF); | ||
633 | reg |= p->gop_size; | ||
634 | mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); | ||
635 | mfc_write(dev, 0, S5P_FIMV_ENC_B_RECON_WRITE_ON); | ||
636 | /* multi-slice control */ | ||
637 | /* multi-slice MB number or bit size */ | ||
638 | mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); | ||
639 | if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { | ||
640 | mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); | ||
641 | } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { | ||
642 | mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); | ||
643 | } else { | ||
644 | mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); | ||
645 | mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_BIT); | ||
646 | } | ||
647 | /* cyclic intra refresh */ | ||
648 | mfc_write(dev, p->intra_refresh_mb, S5P_FIMV_ENC_CIR_CTRL); | ||
649 | /* memory structure cur. frame */ | ||
650 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) | ||
651 | mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); | ||
652 | else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) | ||
653 | mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); | ||
654 | /* padding control & value */ | ||
655 | reg = mfc_read(dev, S5P_FIMV_ENC_PADDING_CTRL); | ||
656 | if (p->pad) { | ||
657 | /** enable */ | ||
658 | reg |= (1 << 31); | ||
659 | /** cr value */ | ||
660 | reg &= ~(0xFF << 16); | ||
661 | reg |= (p->pad_cr << 16); | ||
662 | /** cb value */ | ||
663 | reg &= ~(0xFF << 8); | ||
664 | reg |= (p->pad_cb << 8); | ||
665 | /** y value */ | ||
666 | reg &= ~(0xFF); | ||
667 | reg |= (p->pad_luma); | ||
668 | } else { | ||
669 | /** disable & all value clear */ | ||
670 | reg = 0; | ||
671 | } | ||
672 | mfc_write(dev, reg, S5P_FIMV_ENC_PADDING_CTRL); | ||
673 | /* rate control config. */ | ||
674 | reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); | ||
675 | /** frame-level rate control */ | ||
676 | reg &= ~(0x1 << 9); | ||
677 | reg |= (p->rc_frame << 9); | ||
678 | mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); | ||
679 | /* bit rate */ | ||
680 | if (p->rc_frame) | ||
681 | mfc_write(dev, p->rc_bitrate, | ||
682 | S5P_FIMV_ENC_RC_BIT_RATE); | ||
683 | else | ||
684 | mfc_write(dev, 0, S5P_FIMV_ENC_RC_BIT_RATE); | ||
685 | /* reaction coefficient */ | ||
686 | if (p->rc_frame) | ||
687 | mfc_write(dev, p->rc_reaction_coeff, S5P_FIMV_ENC_RC_RPARA); | ||
688 | shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); | ||
689 | /* seq header ctrl */ | ||
690 | shm &= ~(0x1 << 3); | ||
691 | shm |= (p->seq_hdr_mode << 3); | ||
692 | /* frame skip mode */ | ||
693 | shm &= ~(0x3 << 1); | ||
694 | shm |= (p->frame_skip_mode << 1); | ||
695 | s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); | ||
696 | /* fixed target bit */ | ||
697 | s5p_mfc_write_shm(ctx, p->fixed_target_bit, RC_CONTROL_CONFIG); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) | ||
702 | { | ||
703 | struct s5p_mfc_dev *dev = ctx->dev; | ||
704 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
705 | struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; | ||
706 | unsigned int reg; | ||
707 | unsigned int shm; | ||
708 | |||
709 | s5p_mfc_set_enc_params(ctx); | ||
710 | /* pictype : number of B */ | ||
711 | reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); | ||
712 | /* num_b_frame - 0 ~ 2 */ | ||
713 | reg &= ~(0x3 << 16); | ||
714 | reg |= (p->num_b_frame << 16); | ||
715 | mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); | ||
716 | /* profile & level */ | ||
717 | reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); | ||
718 | /* level */ | ||
719 | reg &= ~(0xFF << 8); | ||
720 | reg |= (p_264->level << 8); | ||
721 | /* profile - 0 ~ 2 */ | ||
722 | reg &= ~(0x3F); | ||
723 | reg |= p_264->profile; | ||
724 | mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); | ||
725 | /* interlace */ | ||
726 | mfc_write(dev, p->interlace, S5P_FIMV_ENC_PIC_STRUCT); | ||
727 | /* height */ | ||
728 | if (p->interlace) | ||
729 | mfc_write(dev, ctx->img_height >> 1, S5P_FIMV_ENC_VSIZE_PX); | ||
730 | /* loopfilter ctrl */ | ||
731 | mfc_write(dev, p_264->loop_filter_mode, S5P_FIMV_ENC_LF_CTRL); | ||
732 | /* loopfilter alpha offset */ | ||
733 | if (p_264->loop_filter_alpha < 0) { | ||
734 | reg = 0x10; | ||
735 | reg |= (0xFF - p_264->loop_filter_alpha) + 1; | ||
736 | } else { | ||
737 | reg = 0x00; | ||
738 | reg |= (p_264->loop_filter_alpha & 0xF); | ||
739 | } | ||
740 | mfc_write(dev, reg, S5P_FIMV_ENC_ALPHA_OFF); | ||
741 | /* loopfilter beta offset */ | ||
742 | if (p_264->loop_filter_beta < 0) { | ||
743 | reg = 0x10; | ||
744 | reg |= (0xFF - p_264->loop_filter_beta) + 1; | ||
745 | } else { | ||
746 | reg = 0x00; | ||
747 | reg |= (p_264->loop_filter_beta & 0xF); | ||
748 | } | ||
749 | mfc_write(dev, reg, S5P_FIMV_ENC_BETA_OFF); | ||
750 | /* entropy coding mode */ | ||
751 | if (p_264->entropy_mode == V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) | ||
752 | mfc_write(dev, 1, S5P_FIMV_ENC_H264_ENTROPY_MODE); | ||
753 | else | ||
754 | mfc_write(dev, 0, S5P_FIMV_ENC_H264_ENTROPY_MODE); | ||
755 | /* number of ref. picture */ | ||
756 | reg = mfc_read(dev, S5P_FIMV_ENC_H264_NUM_OF_REF); | ||
757 | /* num of ref. pictures of P */ | ||
758 | reg &= ~(0x3 << 5); | ||
759 | reg |= (p_264->num_ref_pic_4p << 5); | ||
760 | /* max number of ref. pictures */ | ||
761 | reg &= ~(0x1F); | ||
762 | reg |= p_264->max_ref_pic; | ||
763 | mfc_write(dev, reg, S5P_FIMV_ENC_H264_NUM_OF_REF); | ||
764 | /* 8x8 transform enable */ | ||
765 | mfc_write(dev, p_264->_8x8_transform, S5P_FIMV_ENC_H264_TRANS_FLAG); | ||
766 | /* rate control config. */ | ||
767 | reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); | ||
768 | /* macroblock level rate control */ | ||
769 | reg &= ~(0x1 << 8); | ||
770 | reg |= (p_264->rc_mb << 8); | ||
771 | /* frame QP */ | ||
772 | reg &= ~(0x3F); | ||
773 | reg |= p_264->rc_frame_qp; | ||
774 | mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); | ||
775 | /* frame rate */ | ||
776 | if (p->rc_frame && p->rc_framerate_denom) | ||
777 | mfc_write(dev, p->rc_framerate_num * 1000 | ||
778 | / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); | ||
779 | else | ||
780 | mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); | ||
781 | /* max & min value of QP */ | ||
782 | reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); | ||
783 | /* max QP */ | ||
784 | reg &= ~(0x3F << 8); | ||
785 | reg |= (p_264->rc_max_qp << 8); | ||
786 | /* min QP */ | ||
787 | reg &= ~(0x3F); | ||
788 | reg |= p_264->rc_min_qp; | ||
789 | mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); | ||
790 | /* macroblock adaptive scaling features */ | ||
791 | if (p_264->rc_mb) { | ||
792 | reg = mfc_read(dev, S5P_FIMV_ENC_RC_MB_CTRL); | ||
793 | /* dark region */ | ||
794 | reg &= ~(0x1 << 3); | ||
795 | reg |= (p_264->rc_mb_dark << 3); | ||
796 | /* smooth region */ | ||
797 | reg &= ~(0x1 << 2); | ||
798 | reg |= (p_264->rc_mb_smooth << 2); | ||
799 | /* static region */ | ||
800 | reg &= ~(0x1 << 1); | ||
801 | reg |= (p_264->rc_mb_static << 1); | ||
802 | /* high activity region */ | ||
803 | reg &= ~(0x1); | ||
804 | reg |= p_264->rc_mb_activity; | ||
805 | mfc_write(dev, reg, S5P_FIMV_ENC_RC_MB_CTRL); | ||
806 | } | ||
807 | if (!p->rc_frame && | ||
808 | !p_264->rc_mb) { | ||
809 | shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); | ||
810 | shm &= ~(0xFFF); | ||
811 | shm |= ((p_264->rc_b_frame_qp & 0x3F) << 6); | ||
812 | shm |= (p_264->rc_p_frame_qp & 0x3F); | ||
813 | s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); | ||
814 | } | ||
815 | /* extended encoder ctrl */ | ||
816 | shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); | ||
817 | /* AR VUI control */ | ||
818 | shm &= ~(0x1 << 15); | ||
819 | shm |= (p_264->vui_sar << 1); | ||
820 | s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); | ||
821 | if (p_264->vui_sar) { | ||
822 | /* aspect ration IDC */ | ||
823 | shm = s5p_mfc_read_shm(ctx, SAMPLE_ASPECT_RATIO_IDC); | ||
824 | shm &= ~(0xFF); | ||
825 | shm |= p_264->vui_sar_idc; | ||
826 | s5p_mfc_write_shm(ctx, shm, SAMPLE_ASPECT_RATIO_IDC); | ||
827 | if (p_264->vui_sar_idc == 0xFF) { | ||
828 | /* sample AR info */ | ||
829 | shm = s5p_mfc_read_shm(ctx, EXTENDED_SAR); | ||
830 | shm &= ~(0xFFFFFFFF); | ||
831 | shm |= p_264->vui_ext_sar_width << 16; | ||
832 | shm |= p_264->vui_ext_sar_height; | ||
833 | s5p_mfc_write_shm(ctx, shm, EXTENDED_SAR); | ||
834 | } | ||
835 | } | ||
836 | /* intra picture period for H.264 */ | ||
837 | shm = s5p_mfc_read_shm(ctx, H264_I_PERIOD); | ||
838 | /* control */ | ||
839 | shm &= ~(0x1 << 16); | ||
840 | shm |= (p_264->open_gop << 16); | ||
841 | /* value */ | ||
842 | if (p_264->open_gop) { | ||
843 | shm &= ~(0xFFFF); | ||
844 | shm |= p_264->open_gop_size; | ||
845 | } | ||
846 | s5p_mfc_write_shm(ctx, shm, H264_I_PERIOD); | ||
847 | /* extended encoder ctrl */ | ||
848 | shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); | ||
849 | /* vbv buffer size */ | ||
850 | if (p->frame_skip_mode == | ||
851 | V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { | ||
852 | shm &= ~(0xFFFF << 16); | ||
853 | shm |= (p_264->cpb_size << 16); | ||
854 | } | ||
855 | s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); | ||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) | ||
860 | { | ||
861 | struct s5p_mfc_dev *dev = ctx->dev; | ||
862 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
863 | struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; | ||
864 | unsigned int reg; | ||
865 | unsigned int shm; | ||
866 | unsigned int framerate; | ||
867 | |||
868 | s5p_mfc_set_enc_params(ctx); | ||
869 | /* pictype : number of B */ | ||
870 | reg = mfc_read(dev, S5P_FIMV_ENC_PIC_TYPE_CTRL); | ||
871 | /* num_b_frame - 0 ~ 2 */ | ||
872 | reg &= ~(0x3 << 16); | ||
873 | reg |= (p->num_b_frame << 16); | ||
874 | mfc_write(dev, reg, S5P_FIMV_ENC_PIC_TYPE_CTRL); | ||
875 | /* profile & level */ | ||
876 | reg = mfc_read(dev, S5P_FIMV_ENC_PROFILE); | ||
877 | /* level */ | ||
878 | reg &= ~(0xFF << 8); | ||
879 | reg |= (p_mpeg4->level << 8); | ||
880 | /* profile - 0 ~ 2 */ | ||
881 | reg &= ~(0x3F); | ||
882 | reg |= p_mpeg4->profile; | ||
883 | mfc_write(dev, reg, S5P_FIMV_ENC_PROFILE); | ||
884 | /* quarter_pixel */ | ||
885 | mfc_write(dev, p_mpeg4->quarter_pixel, S5P_FIMV_ENC_MPEG4_QUART_PXL); | ||
886 | /* qp */ | ||
887 | if (!p->rc_frame) { | ||
888 | shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); | ||
889 | shm &= ~(0xFFF); | ||
890 | shm |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 6); | ||
891 | shm |= (p_mpeg4->rc_p_frame_qp & 0x3F); | ||
892 | s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); | ||
893 | } | ||
894 | /* frame rate */ | ||
895 | if (p->rc_frame) { | ||
896 | if (p->rc_framerate_denom > 0) { | ||
897 | framerate = p->rc_framerate_num * 1000 / | ||
898 | p->rc_framerate_denom; | ||
899 | mfc_write(dev, framerate, | ||
900 | S5P_FIMV_ENC_RC_FRAME_RATE); | ||
901 | shm = s5p_mfc_read_shm(ctx, RC_VOP_TIMING); | ||
902 | shm &= ~(0xFFFFFFFF); | ||
903 | shm |= (1 << 31); | ||
904 | shm |= ((p->rc_framerate_num & 0x7FFF) << 16); | ||
905 | shm |= (p->rc_framerate_denom & 0xFFFF); | ||
906 | s5p_mfc_write_shm(ctx, shm, RC_VOP_TIMING); | ||
907 | } | ||
908 | } else { | ||
909 | mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); | ||
910 | } | ||
911 | /* rate control config. */ | ||
912 | reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); | ||
913 | /* frame QP */ | ||
914 | reg &= ~(0x3F); | ||
915 | reg |= p_mpeg4->rc_frame_qp; | ||
916 | mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); | ||
917 | /* max & min value of QP */ | ||
918 | reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); | ||
919 | /* max QP */ | ||
920 | reg &= ~(0x3F << 8); | ||
921 | reg |= (p_mpeg4->rc_max_qp << 8); | ||
922 | /* min QP */ | ||
923 | reg &= ~(0x3F); | ||
924 | reg |= p_mpeg4->rc_min_qp; | ||
925 | mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); | ||
926 | /* extended encoder ctrl */ | ||
927 | shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); | ||
928 | /* vbv buffer size */ | ||
929 | if (p->frame_skip_mode == | ||
930 | V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { | ||
931 | shm &= ~(0xFFFF << 16); | ||
932 | shm |= (p->vbv_size << 16); | ||
933 | } | ||
934 | s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); | ||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) | ||
939 | { | ||
940 | struct s5p_mfc_dev *dev = ctx->dev; | ||
941 | struct s5p_mfc_enc_params *p = &ctx->enc_params; | ||
942 | struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; | ||
943 | unsigned int reg; | ||
944 | unsigned int shm; | ||
945 | |||
946 | s5p_mfc_set_enc_params(ctx); | ||
947 | /* qp */ | ||
948 | if (!p->rc_frame) { | ||
949 | shm = s5p_mfc_read_shm(ctx, P_B_FRAME_QP); | ||
950 | shm &= ~(0xFFF); | ||
951 | shm |= (p_h263->rc_p_frame_qp & 0x3F); | ||
952 | s5p_mfc_write_shm(ctx, shm, P_B_FRAME_QP); | ||
953 | } | ||
954 | /* frame rate */ | ||
955 | if (p->rc_frame && p->rc_framerate_denom) | ||
956 | mfc_write(dev, p->rc_framerate_num * 1000 | ||
957 | / p->rc_framerate_denom, S5P_FIMV_ENC_RC_FRAME_RATE); | ||
958 | else | ||
959 | mfc_write(dev, 0, S5P_FIMV_ENC_RC_FRAME_RATE); | ||
960 | /* rate control config. */ | ||
961 | reg = mfc_read(dev, S5P_FIMV_ENC_RC_CONFIG); | ||
962 | /* frame QP */ | ||
963 | reg &= ~(0x3F); | ||
964 | reg |= p_h263->rc_frame_qp; | ||
965 | mfc_write(dev, reg, S5P_FIMV_ENC_RC_CONFIG); | ||
966 | /* max & min value of QP */ | ||
967 | reg = mfc_read(dev, S5P_FIMV_ENC_RC_QBOUND); | ||
968 | /* max QP */ | ||
969 | reg &= ~(0x3F << 8); | ||
970 | reg |= (p_h263->rc_max_qp << 8); | ||
971 | /* min QP */ | ||
972 | reg &= ~(0x3F); | ||
973 | reg |= p_h263->rc_min_qp; | ||
974 | mfc_write(dev, reg, S5P_FIMV_ENC_RC_QBOUND); | ||
975 | /* extended encoder ctrl */ | ||
976 | shm = s5p_mfc_read_shm(ctx, EXT_ENC_CONTROL); | ||
977 | /* vbv buffer size */ | ||
978 | if (p->frame_skip_mode == | ||
979 | V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) { | ||
980 | shm &= ~(0xFFFF << 16); | ||
981 | shm |= (p->vbv_size << 16); | ||
982 | } | ||
983 | s5p_mfc_write_shm(ctx, shm, EXT_ENC_CONTROL); | ||
984 | return 0; | ||
985 | } | ||
986 | |||
987 | /* Initialize decoding */ | ||
988 | int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx) | ||
989 | { | ||
990 | struct s5p_mfc_dev *dev = ctx->dev; | ||
991 | |||
992 | s5p_mfc_set_shared_buffer(ctx); | ||
993 | /* Setup loop filter, for decoding this is only valid for MPEG4 */ | ||
994 | if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_DEC) | ||
995 | mfc_write(dev, ctx->loop_filter_mpeg4, S5P_FIMV_ENC_LF_CTRL); | ||
996 | else | ||
997 | mfc_write(dev, 0, S5P_FIMV_ENC_LF_CTRL); | ||
998 | mfc_write(dev, ((ctx->slice_interface & S5P_FIMV_SLICE_INT_MASK) << | ||
999 | S5P_FIMV_SLICE_INT_SHIFT) | (ctx->display_delay_enable << | ||
1000 | S5P_FIMV_DDELAY_ENA_SHIFT) | ((ctx->display_delay & | ||
1001 | S5P_FIMV_DDELAY_VAL_MASK) << S5P_FIMV_DDELAY_VAL_SHIFT), | ||
1002 | S5P_FIMV_SI_CH0_DPB_CONF_CTRL); | ||
1003 | mfc_write(dev, | ||
1004 | ((S5P_FIMV_CH_SEQ_HEADER & S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | ||
1005 | | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); | ||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | static void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush) | ||
1010 | { | ||
1011 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1012 | unsigned int dpb; | ||
1013 | |||
1014 | if (flush) | ||
1015 | dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) | ( | ||
1016 | S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); | ||
1017 | else | ||
1018 | dpb = mfc_read(dev, S5P_FIMV_SI_CH0_DPB_CONF_CTRL) & | ||
1019 | ~(S5P_FIMV_DPB_FLUSH_MASK << S5P_FIMV_DPB_FLUSH_SHIFT); | ||
1020 | mfc_write(dev, dpb, S5P_FIMV_SI_CH0_DPB_CONF_CTRL); | ||
1021 | } | ||
1022 | |||
1023 | /* Decode a single frame */ | ||
1024 | int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, | ||
1025 | enum s5p_mfc_decode_arg last_frame) | ||
1026 | { | ||
1027 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1028 | |||
1029 | mfc_write(dev, ctx->dec_dst_flag, S5P_FIMV_SI_CH0_RELEASE_BUF); | ||
1030 | s5p_mfc_set_shared_buffer(ctx); | ||
1031 | s5p_mfc_set_flush(ctx, ctx->dpb_flush_flag); | ||
1032 | /* Issue different commands to instance basing on whether it | ||
1033 | * is the last frame or not. */ | ||
1034 | switch (last_frame) { | ||
1035 | case MFC_DEC_FRAME: | ||
1036 | mfc_write(dev, ((S5P_FIMV_CH_FRAME_START & S5P_FIMV_CH_MASK) << | ||
1037 | S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); | ||
1038 | break; | ||
1039 | case MFC_DEC_LAST_FRAME: | ||
1040 | mfc_write(dev, ((S5P_FIMV_CH_LAST_FRAME & S5P_FIMV_CH_MASK) << | ||
1041 | S5P_FIMV_CH_SHIFT) | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); | ||
1042 | break; | ||
1043 | case MFC_DEC_RES_CHANGE: | ||
1044 | mfc_write(dev, ((S5P_FIMV_CH_FRAME_START_REALLOC & | ||
1045 | S5P_FIMV_CH_MASK) << S5P_FIMV_CH_SHIFT) | (ctx->inst_no), | ||
1046 | S5P_FIMV_SI_CH0_INST_ID); | ||
1047 | break; | ||
1048 | } | ||
1049 | mfc_debug(2, "Decoding a usual frame\n"); | ||
1050 | return 0; | ||
1051 | } | ||
1052 | |||
1053 | int s5p_mfc_init_encode(struct s5p_mfc_ctx *ctx) | ||
1054 | { | ||
1055 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1056 | |||
1057 | if (ctx->codec_mode == S5P_FIMV_CODEC_H264_ENC) | ||
1058 | s5p_mfc_set_enc_params_h264(ctx); | ||
1059 | else if (ctx->codec_mode == S5P_FIMV_CODEC_MPEG4_ENC) | ||
1060 | s5p_mfc_set_enc_params_mpeg4(ctx); | ||
1061 | else if (ctx->codec_mode == S5P_FIMV_CODEC_H263_ENC) | ||
1062 | s5p_mfc_set_enc_params_h263(ctx); | ||
1063 | else { | ||
1064 | mfc_err("Unknown codec for encoding (%x)\n", | ||
1065 | ctx->codec_mode); | ||
1066 | return -EINVAL; | ||
1067 | } | ||
1068 | s5p_mfc_set_shared_buffer(ctx); | ||
1069 | mfc_write(dev, ((S5P_FIMV_CH_SEQ_HEADER << 16) & 0x70000) | | ||
1070 | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); | ||
1071 | return 0; | ||
1072 | } | ||
1073 | |||
1074 | /* Encode a single frame */ | ||
1075 | int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *ctx) | ||
1076 | { | ||
1077 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1078 | /* memory structure cur. frame */ | ||
1079 | if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) | ||
1080 | mfc_write(dev, 0, S5P_FIMV_ENC_MAP_FOR_CUR); | ||
1081 | else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT) | ||
1082 | mfc_write(dev, 3, S5P_FIMV_ENC_MAP_FOR_CUR); | ||
1083 | s5p_mfc_set_shared_buffer(ctx); | ||
1084 | mfc_write(dev, (S5P_FIMV_CH_FRAME_START << 16 & 0x70000) | | ||
1085 | (ctx->inst_no), S5P_FIMV_SI_CH0_INST_ID); | ||
1086 | return 0; | ||
1087 | } | ||
1088 | |||
1089 | static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev) | ||
1090 | { | ||
1091 | unsigned long flags; | ||
1092 | int new_ctx; | ||
1093 | int cnt; | ||
1094 | |||
1095 | spin_lock_irqsave(&dev->condlock, flags); | ||
1096 | new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS; | ||
1097 | cnt = 0; | ||
1098 | while (!test_bit(new_ctx, &dev->ctx_work_bits)) { | ||
1099 | new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS; | ||
1100 | if (++cnt > MFC_NUM_CONTEXTS) { | ||
1101 | /* No contexts to run */ | ||
1102 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
1103 | return -EAGAIN; | ||
1104 | } | ||
1105 | } | ||
1106 | spin_unlock_irqrestore(&dev->condlock, flags); | ||
1107 | return new_ctx; | ||
1108 | } | ||
1109 | |||
1110 | static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx) | ||
1111 | { | ||
1112 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1113 | |||
1114 | s5p_mfc_set_dec_stream_buffer(ctx, 0, 0, 0); | ||
1115 | dev->curr_ctx = ctx->num; | ||
1116 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1117 | s5p_mfc_decode_one_frame(ctx, MFC_DEC_RES_CHANGE); | ||
1118 | } | ||
1119 | |||
1120 | static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame) | ||
1121 | { | ||
1122 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1123 | struct s5p_mfc_buf *temp_vb; | ||
1124 | unsigned long flags; | ||
1125 | unsigned int index; | ||
1126 | |||
1127 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1128 | /* Frames are being decoded */ | ||
1129 | if (list_empty(&ctx->src_queue)) { | ||
1130 | mfc_debug(2, "No src buffers\n"); | ||
1131 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1132 | return -EAGAIN; | ||
1133 | } | ||
1134 | /* Get the next source buffer */ | ||
1135 | temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
1136 | temp_vb->used = 1; | ||
1137 | s5p_mfc_set_dec_stream_buffer(ctx, | ||
1138 | vb2_dma_contig_plane_paddr(temp_vb->b, 0), ctx->consumed_stream, | ||
1139 | temp_vb->b->v4l2_planes[0].bytesused); | ||
1140 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1141 | index = temp_vb->b->v4l2_buf.index; | ||
1142 | dev->curr_ctx = ctx->num; | ||
1143 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1144 | if (temp_vb->b->v4l2_planes[0].bytesused == 0) { | ||
1145 | last_frame = MFC_DEC_LAST_FRAME; | ||
1146 | mfc_debug(2, "Setting ctx->state to FINISHING\n"); | ||
1147 | ctx->state = MFCINST_FINISHING; | ||
1148 | } | ||
1149 | s5p_mfc_decode_one_frame(ctx, last_frame); | ||
1150 | return 0; | ||
1151 | } | ||
1152 | |||
1153 | static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx) | ||
1154 | { | ||
1155 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1156 | unsigned long flags; | ||
1157 | struct s5p_mfc_buf *dst_mb; | ||
1158 | struct s5p_mfc_buf *src_mb; | ||
1159 | unsigned long src_y_addr, src_c_addr, dst_addr; | ||
1160 | unsigned int dst_size; | ||
1161 | |||
1162 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1163 | if (list_empty(&ctx->src_queue)) { | ||
1164 | mfc_debug(2, "no src buffers\n"); | ||
1165 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1166 | return -EAGAIN; | ||
1167 | } | ||
1168 | if (list_empty(&ctx->dst_queue)) { | ||
1169 | mfc_debug(2, "no dst buffers\n"); | ||
1170 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1171 | return -EAGAIN; | ||
1172 | } | ||
1173 | src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
1174 | src_mb->used = 1; | ||
1175 | src_y_addr = vb2_dma_contig_plane_paddr(src_mb->b, 0); | ||
1176 | src_c_addr = vb2_dma_contig_plane_paddr(src_mb->b, 1); | ||
1177 | s5p_mfc_set_enc_frame_buffer(ctx, src_y_addr, src_c_addr); | ||
1178 | dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); | ||
1179 | dst_mb->used = 1; | ||
1180 | dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0); | ||
1181 | dst_size = vb2_plane_size(dst_mb->b, 0); | ||
1182 | s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); | ||
1183 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1184 | dev->curr_ctx = ctx->num; | ||
1185 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1186 | s5p_mfc_encode_one_frame(ctx); | ||
1187 | return 0; | ||
1188 | } | ||
1189 | |||
1190 | static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx) | ||
1191 | { | ||
1192 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1193 | unsigned long flags; | ||
1194 | struct s5p_mfc_buf *temp_vb; | ||
1195 | |||
1196 | /* Initializing decoding - parsing header */ | ||
1197 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1198 | mfc_debug(2, "Preparing to init decoding\n"); | ||
1199 | temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
1200 | s5p_mfc_set_dec_desc_buffer(ctx); | ||
1201 | mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); | ||
1202 | s5p_mfc_set_dec_stream_buffer(ctx, | ||
1203 | vb2_dma_contig_plane_paddr(temp_vb->b, 0), | ||
1204 | 0, temp_vb->b->v4l2_planes[0].bytesused); | ||
1205 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1206 | dev->curr_ctx = ctx->num; | ||
1207 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1208 | s5p_mfc_init_decode(ctx); | ||
1209 | } | ||
1210 | |||
1211 | static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx) | ||
1212 | { | ||
1213 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1214 | unsigned long flags; | ||
1215 | struct s5p_mfc_buf *dst_mb; | ||
1216 | unsigned long dst_addr; | ||
1217 | unsigned int dst_size; | ||
1218 | |||
1219 | s5p_mfc_set_enc_ref_buffer(ctx); | ||
1220 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1221 | dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list); | ||
1222 | dst_addr = vb2_dma_contig_plane_paddr(dst_mb->b, 0); | ||
1223 | dst_size = vb2_plane_size(dst_mb->b, 0); | ||
1224 | s5p_mfc_set_enc_stream_buffer(ctx, dst_addr, dst_size); | ||
1225 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1226 | dev->curr_ctx = ctx->num; | ||
1227 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1228 | s5p_mfc_init_encode(ctx); | ||
1229 | } | ||
1230 | |||
1231 | static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) | ||
1232 | { | ||
1233 | struct s5p_mfc_dev *dev = ctx->dev; | ||
1234 | unsigned long flags; | ||
1235 | struct s5p_mfc_buf *temp_vb; | ||
1236 | int ret; | ||
1237 | |||
1238 | /* | ||
1239 | * Header was parsed now starting processing | ||
1240 | * First set the output frame buffers | ||
1241 | */ | ||
1242 | if (ctx->capture_state != QUEUE_BUFS_MMAPED) { | ||
1243 | mfc_err("It seems that not all destionation buffers were " | ||
1244 | "mmaped\nMFC requires that all destination are mmaped " | ||
1245 | "before starting processing\n"); | ||
1246 | return -EAGAIN; | ||
1247 | } | ||
1248 | spin_lock_irqsave(&dev->irqlock, flags); | ||
1249 | if (list_empty(&ctx->src_queue)) { | ||
1250 | mfc_err("Header has been deallocated in the middle of" | ||
1251 | " initialization\n"); | ||
1252 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1253 | return -EIO; | ||
1254 | } | ||
1255 | temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); | ||
1256 | mfc_debug(2, "Header size: %d\n", temp_vb->b->v4l2_planes[0].bytesused); | ||
1257 | s5p_mfc_set_dec_stream_buffer(ctx, | ||
1258 | vb2_dma_contig_plane_paddr(temp_vb->b, 0), | ||
1259 | 0, temp_vb->b->v4l2_planes[0].bytesused); | ||
1260 | spin_unlock_irqrestore(&dev->irqlock, flags); | ||
1261 | dev->curr_ctx = ctx->num; | ||
1262 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1263 | ret = s5p_mfc_set_dec_frame_buffer(ctx); | ||
1264 | if (ret) { | ||
1265 | mfc_err("Failed to alloc frame mem\n"); | ||
1266 | ctx->state = MFCINST_ERROR; | ||
1267 | } | ||
1268 | return ret; | ||
1269 | } | ||
1270 | |||
1271 | /* Try running an operation on hardware */ | ||
1272 | void s5p_mfc_try_run(struct s5p_mfc_dev *dev) | ||
1273 | { | ||
1274 | struct s5p_mfc_ctx *ctx; | ||
1275 | int new_ctx; | ||
1276 | unsigned int ret = 0; | ||
1277 | |||
1278 | if (test_bit(0, &dev->enter_suspend)) { | ||
1279 | mfc_debug(1, "Entering suspend so do not schedule any jobs\n"); | ||
1280 | return; | ||
1281 | } | ||
1282 | /* Check whether hardware is not running */ | ||
1283 | if (test_and_set_bit(0, &dev->hw_lock) != 0) { | ||
1284 | /* This is perfectly ok, the scheduled ctx should wait */ | ||
1285 | mfc_debug(1, "Couldn't lock HW\n"); | ||
1286 | return; | ||
1287 | } | ||
1288 | /* Choose the context to run */ | ||
1289 | new_ctx = s5p_mfc_get_new_ctx(dev); | ||
1290 | if (new_ctx < 0) { | ||
1291 | /* No contexts to run */ | ||
1292 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) { | ||
1293 | mfc_err("Failed to unlock hardware\n"); | ||
1294 | return; | ||
1295 | } | ||
1296 | mfc_debug(1, "No ctx is scheduled to be run\n"); | ||
1297 | return; | ||
1298 | } | ||
1299 | ctx = dev->ctx[new_ctx]; | ||
1300 | /* Got context to run in ctx */ | ||
1301 | /* | ||
1302 | * Last frame has already been sent to MFC. | ||
1303 | * Now obtaining frames from MFC buffer | ||
1304 | */ | ||
1305 | s5p_mfc_clock_on(); | ||
1306 | if (ctx->type == MFCINST_DECODER) { | ||
1307 | s5p_mfc_set_dec_desc_buffer(ctx); | ||
1308 | switch (ctx->state) { | ||
1309 | case MFCINST_FINISHING: | ||
1310 | s5p_mfc_run_dec_frame(ctx, MFC_DEC_LAST_FRAME); | ||
1311 | break; | ||
1312 | case MFCINST_RUNNING: | ||
1313 | ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); | ||
1314 | break; | ||
1315 | case MFCINST_INIT: | ||
1316 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1317 | ret = s5p_mfc_open_inst_cmd(ctx); | ||
1318 | break; | ||
1319 | case MFCINST_RETURN_INST: | ||
1320 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1321 | ret = s5p_mfc_close_inst_cmd(ctx); | ||
1322 | break; | ||
1323 | case MFCINST_GOT_INST: | ||
1324 | s5p_mfc_run_init_dec(ctx); | ||
1325 | break; | ||
1326 | case MFCINST_HEAD_PARSED: | ||
1327 | ret = s5p_mfc_run_init_dec_buffers(ctx); | ||
1328 | mfc_debug(1, "head parsed\n"); | ||
1329 | break; | ||
1330 | case MFCINST_RES_CHANGE_INIT: | ||
1331 | s5p_mfc_run_res_change(ctx); | ||
1332 | break; | ||
1333 | case MFCINST_RES_CHANGE_FLUSH: | ||
1334 | s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME); | ||
1335 | break; | ||
1336 | case MFCINST_RES_CHANGE_END: | ||
1337 | mfc_debug(2, "Finished remaining frames after resolution change\n"); | ||
1338 | ctx->capture_state = QUEUE_FREE; | ||
1339 | mfc_debug(2, "Will re-init the codec\n"); | ||
1340 | s5p_mfc_run_init_dec(ctx); | ||
1341 | break; | ||
1342 | default: | ||
1343 | ret = -EAGAIN; | ||
1344 | } | ||
1345 | } else if (ctx->type == MFCINST_ENCODER) { | ||
1346 | switch (ctx->state) { | ||
1347 | case MFCINST_FINISHING: | ||
1348 | case MFCINST_RUNNING: | ||
1349 | ret = s5p_mfc_run_enc_frame(ctx); | ||
1350 | break; | ||
1351 | case MFCINST_INIT: | ||
1352 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1353 | ret = s5p_mfc_open_inst_cmd(ctx); | ||
1354 | break; | ||
1355 | case MFCINST_RETURN_INST: | ||
1356 | s5p_mfc_clean_ctx_int_flags(ctx); | ||
1357 | ret = s5p_mfc_close_inst_cmd(ctx); | ||
1358 | break; | ||
1359 | case MFCINST_GOT_INST: | ||
1360 | s5p_mfc_run_init_enc(ctx); | ||
1361 | break; | ||
1362 | default: | ||
1363 | ret = -EAGAIN; | ||
1364 | } | ||
1365 | } else { | ||
1366 | mfc_err("Invalid context type: %d\n", ctx->type); | ||
1367 | ret = -EAGAIN; | ||
1368 | } | ||
1369 | |||
1370 | if (ret) { | ||
1371 | /* Free hardware lock */ | ||
1372 | if (test_and_clear_bit(0, &dev->hw_lock) == 0) | ||
1373 | mfc_err("Failed to unlock hardware\n"); | ||
1374 | |||
1375 | /* This is in deed imporant, as no operation has been | ||
1376 | * scheduled, reduce the clock count as no one will | ||
1377 | * ever do this, because no interrupt related to this try_run | ||
1378 | * will ever come from hardware. */ | ||
1379 | s5p_mfc_clock_off(); | ||
1380 | } | ||
1381 | } | ||
1382 | |||
1383 | |||
1384 | void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq) | ||
1385 | { | ||
1386 | struct s5p_mfc_buf *b; | ||
1387 | int i; | ||
1388 | |||
1389 | while (!list_empty(lh)) { | ||
1390 | b = list_entry(lh->next, struct s5p_mfc_buf, list); | ||
1391 | for (i = 0; i < b->b->num_planes; i++) | ||
1392 | vb2_set_plane_payload(b->b, i, 0); | ||
1393 | vb2_buffer_done(b->b, VB2_BUF_STATE_ERROR); | ||
1394 | list_del(&b->list); | ||
1395 | } | ||
1396 | } | ||
1397 | |||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_opr.h b/drivers/media/video/s5p-mfc/s5p_mfc_opr.h new file mode 100644 index 000000000000..db83836e6a9f --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_opr.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * drivers/media/video/samsung/mfc5/s5p_mfc_opr.h | ||
3 | * | ||
4 | * Header file for Samsung MFC (Multi Function Codec - FIMV) driver | ||
5 | * Contains declarations of hw related functions. | ||
6 | * | ||
7 | * Kamil Debski, Copyright (C) 2011 Samsung Electronics | ||
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_H_ | ||
16 | #define S5P_MFC_OPR_H_ | ||
17 | |||
18 | #include "s5p_mfc_common.h" | ||
19 | |||
20 | int s5p_mfc_init_decode(struct s5p_mfc_ctx *ctx); | ||
21 | int s5p_mfc_init_encode(struct s5p_mfc_ctx *mfc_ctx); | ||
22 | |||
23 | /* Decoding functions */ | ||
24 | int s5p_mfc_set_dec_frame_buffer(struct s5p_mfc_ctx *ctx); | ||
25 | int s5p_mfc_set_dec_stream_buffer(struct s5p_mfc_ctx *ctx, int buf_addr, | ||
26 | unsigned int start_num_byte, | ||
27 | unsigned int buf_size); | ||
28 | |||
29 | /* Encoding functions */ | ||
30 | void s5p_mfc_set_enc_frame_buffer(struct s5p_mfc_ctx *ctx, | ||
31 | unsigned long y_addr, unsigned long c_addr); | ||
32 | int s5p_mfc_set_enc_stream_buffer(struct s5p_mfc_ctx *ctx, | ||
33 | unsigned long addr, unsigned int size); | ||
34 | void s5p_mfc_get_enc_frame_buffer(struct s5p_mfc_ctx *ctx, | ||
35 | unsigned long *y_addr, unsigned long *c_addr); | ||
36 | int s5p_mfc_set_enc_ref_buffer(struct s5p_mfc_ctx *mfc_ctx); | ||
37 | |||
38 | int s5p_mfc_decode_one_frame(struct s5p_mfc_ctx *ctx, | ||
39 | enum s5p_mfc_decode_arg last_frame); | ||
40 | int s5p_mfc_encode_one_frame(struct s5p_mfc_ctx *mfc_ctx); | ||
41 | |||
42 | /* Memory allocation */ | ||
43 | int s5p_mfc_alloc_dec_temp_buffers(struct s5p_mfc_ctx *ctx); | ||
44 | void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx); | ||
45 | void s5p_mfc_release_dec_desc_buffer(struct s5p_mfc_ctx *ctx); | ||
46 | |||
47 | int s5p_mfc_alloc_codec_buffers(struct s5p_mfc_ctx *ctx); | ||
48 | void s5p_mfc_release_codec_buffers(struct s5p_mfc_ctx *ctx); | ||
49 | |||
50 | int s5p_mfc_alloc_instance_buffer(struct s5p_mfc_ctx *ctx); | ||
51 | void s5p_mfc_release_instance_buffer(struct s5p_mfc_ctx *ctx); | ||
52 | |||
53 | void s5p_mfc_try_run(struct s5p_mfc_dev *dev); | ||
54 | void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq); | ||
55 | |||
56 | #define s5p_mfc_get_dspl_y_adr() (readl(dev->regs_base + \ | ||
57 | S5P_FIMV_SI_DISPLAY_Y_ADR) << \ | ||
58 | MFC_OFFSET_SHIFT) | ||
59 | #define s5p_mfc_get_dec_y_adr() (readl(dev->regs_base + \ | ||
60 | S5P_FIMV_SI_DISPLAY_Y_ADR) << \ | ||
61 | MFC_OFFSET_SHIFT) | ||
62 | #define s5p_mfc_get_dspl_status() readl(dev->regs_base + \ | ||
63 | S5P_FIMV_SI_DISPLAY_STATUS) | ||
64 | #define s5p_mfc_get_frame_type() (readl(dev->regs_base + \ | ||
65 | S5P_FIMV_DECODE_FRAME_TYPE) \ | ||
66 | & S5P_FIMV_DECODE_FRAME_MASK) | ||
67 | #define s5p_mfc_get_consumed_stream() readl(dev->regs_base + \ | ||
68 | S5P_FIMV_SI_CONSUMED_BYTES) | ||
69 | #define s5p_mfc_get_int_reason() (readl(dev->regs_base + \ | ||
70 | S5P_FIMV_RISC2HOST_CMD) & \ | ||
71 | S5P_FIMV_RISC2HOST_CMD_MASK) | ||
72 | #define s5p_mfc_get_int_err() readl(dev->regs_base + \ | ||
73 | S5P_FIMV_RISC2HOST_ARG2) | ||
74 | #define s5p_mfc_err_dec(x) (((x) & S5P_FIMV_ERR_DEC_MASK) >> \ | ||
75 | S5P_FIMV_ERR_DEC_SHIFT) | ||
76 | #define s5p_mfc_err_dspl(x) (((x) & S5P_FIMV_ERR_DSPL_MASK) >> \ | ||
77 | S5P_FIMV_ERR_DSPL_SHIFT) | ||
78 | #define s5p_mfc_get_img_width() readl(dev->regs_base + \ | ||
79 | S5P_FIMV_SI_HRESOL) | ||
80 | #define s5p_mfc_get_img_height() readl(dev->regs_base + \ | ||
81 | S5P_FIMV_SI_VRESOL) | ||
82 | #define s5p_mfc_get_dpb_count() readl(dev->regs_base + \ | ||
83 | S5P_FIMV_SI_BUF_NUMBER) | ||
84 | #define s5p_mfc_get_inst_no() readl(dev->regs_base + \ | ||
85 | S5P_FIMV_RISC2HOST_ARG1) | ||
86 | #define s5p_mfc_get_enc_strm_size() readl(dev->regs_base + \ | ||
87 | S5P_FIMV_ENC_SI_STRM_SIZE) | ||
88 | #define s5p_mfc_get_enc_slice_type() readl(dev->regs_base + \ | ||
89 | S5P_FIMV_ENC_SI_SLICE_TYPE) | ||
90 | |||
91 | #endif /* S5P_MFC_OPR_H_ */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.c b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c new file mode 100644 index 000000000000..f6a3035c4fb7 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_pm.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_pm.c | ||
3 | * | ||
4 | * Copyright (c) 2010 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 <linux/clk.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #ifdef CONFIG_PM_RUNTIME | ||
17 | #include <linux/pm_runtime.h> | ||
18 | #endif | ||
19 | #include "s5p_mfc_common.h" | ||
20 | #include "s5p_mfc_debug.h" | ||
21 | #include "s5p_mfc_pm.h" | ||
22 | |||
23 | #define MFC_CLKNAME "sclk_mfc" | ||
24 | #define MFC_GATE_CLK_NAME "mfc" | ||
25 | |||
26 | #define CLK_DEBUG | ||
27 | |||
28 | static struct s5p_mfc_pm *pm; | ||
29 | static struct s5p_mfc_dev *p_dev; | ||
30 | |||
31 | #ifdef CLK_DEBUG | ||
32 | atomic_t clk_ref; | ||
33 | #endif | ||
34 | |||
35 | int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) | ||
36 | { | ||
37 | int ret = 0; | ||
38 | |||
39 | pm = &dev->pm; | ||
40 | p_dev = dev; | ||
41 | pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME); | ||
42 | if (IS_ERR(pm->clock_gate)) { | ||
43 | mfc_err("Failed to get clock-gating control\n"); | ||
44 | ret = -ENOENT; | ||
45 | goto err_g_ip_clk; | ||
46 | } | ||
47 | pm->clock = clk_get(&dev->plat_dev->dev, MFC_CLKNAME); | ||
48 | if (IS_ERR(pm->clock)) { | ||
49 | mfc_err("Failed to get MFC clock\n"); | ||
50 | ret = -ENOENT; | ||
51 | goto err_g_ip_clk_2; | ||
52 | } | ||
53 | atomic_set(&pm->power, 0); | ||
54 | #ifdef CONFIG_PM_RUNTIME | ||
55 | pm->device = &dev->plat_dev->dev; | ||
56 | pm_runtime_enable(pm->device); | ||
57 | #endif | ||
58 | #ifdef CLK_DEBUG | ||
59 | atomic_set(&clk_ref, 0); | ||
60 | #endif | ||
61 | return 0; | ||
62 | err_g_ip_clk_2: | ||
63 | clk_put(pm->clock_gate); | ||
64 | err_g_ip_clk: | ||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) | ||
69 | { | ||
70 | clk_put(pm->clock_gate); | ||
71 | clk_put(pm->clock); | ||
72 | #ifdef CONFIG_PM_RUNTIME | ||
73 | pm_runtime_disable(pm->device); | ||
74 | #endif | ||
75 | } | ||
76 | |||
77 | int s5p_mfc_clock_on(void) | ||
78 | { | ||
79 | int ret; | ||
80 | #ifdef CLK_DEBUG | ||
81 | atomic_inc(&clk_ref); | ||
82 | mfc_debug(3, "+ %d", atomic_read(&clk_ref)); | ||
83 | #endif | ||
84 | ret = clk_enable(pm->clock_gate); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | void s5p_mfc_clock_off(void) | ||
89 | { | ||
90 | #ifdef CLK_DEBUG | ||
91 | atomic_dec(&clk_ref); | ||
92 | mfc_debug(3, "- %d", atomic_read(&clk_ref)); | ||
93 | #endif | ||
94 | clk_disable(pm->clock_gate); | ||
95 | } | ||
96 | |||
97 | int s5p_mfc_power_on(void) | ||
98 | { | ||
99 | #ifdef CONFIG_PM_RUNTIME | ||
100 | return pm_runtime_get_sync(pm->device); | ||
101 | #else | ||
102 | atomic_set(&pm->power, 1); | ||
103 | return 0; | ||
104 | #endif | ||
105 | } | ||
106 | |||
107 | int s5p_mfc_power_off(void) | ||
108 | { | ||
109 | #ifdef CONFIG_PM_RUNTIME | ||
110 | return pm_runtime_put_sync(pm->device); | ||
111 | #else | ||
112 | atomic_set(&pm->power, 0); | ||
113 | return 0; | ||
114 | #endif | ||
115 | } | ||
116 | |||
117 | |||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_pm.h b/drivers/media/video/s5p-mfc/s5p_mfc_pm.h new file mode 100644 index 000000000000..5107914f27e4 --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_pm.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_pm.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_PM_H_ | ||
14 | #define S5P_MFC_PM_H_ | ||
15 | |||
16 | int s5p_mfc_init_pm(struct s5p_mfc_dev *dev); | ||
17 | void s5p_mfc_final_pm(struct s5p_mfc_dev *dev); | ||
18 | |||
19 | int s5p_mfc_clock_on(void); | ||
20 | void s5p_mfc_clock_off(void); | ||
21 | int s5p_mfc_power_on(void); | ||
22 | int s5p_mfc_power_off(void); | ||
23 | |||
24 | #endif /* S5P_MFC_PM_H_ */ | ||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_shm.c b/drivers/media/video/s5p-mfc/s5p_mfc_shm.c new file mode 100644 index 000000000000..91fdbac8c37a --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_shm.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_shm.c | ||
3 | * | ||
4 | * Copyright (c) 2010 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 | #ifdef CONFIG_ARCH_EXYNOS4 | ||
14 | #include <linux/dma-mapping.h> | ||
15 | #endif | ||
16 | #include <linux/io.h> | ||
17 | #include "s5p_mfc_common.h" | ||
18 | #include "s5p_mfc_debug.h" | ||
19 | |||
20 | int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx) | ||
21 | { | ||
22 | struct s5p_mfc_dev *dev = ctx->dev; | ||
23 | void *shm_alloc_ctx = dev->alloc_ctx[MFC_BANK1_ALLOC_CTX]; | ||
24 | |||
25 | ctx->shm_alloc = vb2_dma_contig_memops.alloc(shm_alloc_ctx, | ||
26 | SHARED_BUF_SIZE); | ||
27 | if (IS_ERR(ctx->shm_alloc)) { | ||
28 | mfc_err("failed to allocate shared memory\n"); | ||
29 | return PTR_ERR(ctx->shm_alloc); | ||
30 | } | ||
31 | /* shm_ofs only keeps the offset from base (port a) */ | ||
32 | ctx->shm_ofs = s5p_mfc_mem_cookie(shm_alloc_ctx, ctx->shm_alloc) | ||
33 | - dev->bank1; | ||
34 | BUG_ON(ctx->shm_ofs & ((1 << MFC_BANK1_ALIGN_ORDER) - 1)); | ||
35 | ctx->shm = vb2_dma_contig_memops.vaddr(ctx->shm_alloc); | ||
36 | if (!ctx->shm) { | ||
37 | vb2_dma_contig_memops.put(ctx->shm_alloc); | ||
38 | ctx->shm_ofs = 0; | ||
39 | ctx->shm_alloc = NULL; | ||
40 | mfc_err("failed to virt addr of shared memory\n"); | ||
41 | return -ENOMEM; | ||
42 | } | ||
43 | memset((void *)ctx->shm, 0, SHARED_BUF_SIZE); | ||
44 | wmb(); | ||
45 | return 0; | ||
46 | } | ||
47 | |||
diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_shm.h b/drivers/media/video/s5p-mfc/s5p_mfc_shm.h new file mode 100644 index 000000000000..764eac6bcc4c --- /dev/null +++ b/drivers/media/video/s5p-mfc/s5p_mfc_shm.h | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * linux/drivers/media/video/s5p-mfc/s5p_mfc_shm.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_SHM_H_ | ||
14 | #define S5P_MFC_SHM_H_ | ||
15 | |||
16 | enum MFC_SHM_OFS | ||
17 | { | ||
18 | EXTENEDED_DECODE_STATUS = 0x00, /* D */ | ||
19 | SET_FRAME_TAG = 0x04, /* D */ | ||
20 | GET_FRAME_TAG_TOP = 0x08, /* D */ | ||
21 | GET_FRAME_TAG_BOT = 0x0C, /* D */ | ||
22 | PIC_TIME_TOP = 0x10, /* D */ | ||
23 | PIC_TIME_BOT = 0x14, /* D */ | ||
24 | START_BYTE_NUM = 0x18, /* D */ | ||
25 | |||
26 | CROP_INFO_H = 0x20, /* D */ | ||
27 | CROP_INFO_V = 0x24, /* D */ | ||
28 | EXT_ENC_CONTROL = 0x28, /* E */ | ||
29 | ENC_PARAM_CHANGE = 0x2C, /* E */ | ||
30 | RC_VOP_TIMING = 0x30, /* E, MPEG4 */ | ||
31 | HEC_PERIOD = 0x34, /* E, MPEG4 */ | ||
32 | METADATA_ENABLE = 0x38, /* C */ | ||
33 | METADATA_STATUS = 0x3C, /* C */ | ||
34 | METADATA_DISPLAY_INDEX = 0x40, /* C */ | ||
35 | EXT_METADATA_START_ADDR = 0x44, /* C */ | ||
36 | PUT_EXTRADATA = 0x48, /* C */ | ||
37 | EXTRADATA_ADDR = 0x4C, /* C */ | ||
38 | |||
39 | ALLOC_LUMA_DPB_SIZE = 0x64, /* D */ | ||
40 | ALLOC_CHROMA_DPB_SIZE = 0x68, /* D */ | ||
41 | ALLOC_MV_SIZE = 0x6C, /* D */ | ||
42 | P_B_FRAME_QP = 0x70, /* E */ | ||
43 | SAMPLE_ASPECT_RATIO_IDC = 0x74, /* E, H.264, depend on | ||
44 | ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ | ||
45 | EXTENDED_SAR = 0x78, /* E, H.264, depned on | ||
46 | ASPECT_RATIO_VUI_ENABLE in EXT_ENC_CONTROL */ | ||
47 | DISP_PIC_PROFILE = 0x7C, /* D */ | ||
48 | FLUSH_CMD_TYPE = 0x80, /* C */ | ||
49 | FLUSH_CMD_INBUF1 = 0x84, /* C */ | ||
50 | FLUSH_CMD_INBUF2 = 0x88, /* C */ | ||
51 | FLUSH_CMD_OUTBUF = 0x8C, /* E */ | ||
52 | NEW_RC_BIT_RATE = 0x90, /* E, format as RC_BIT_RATE(0xC5A8) | ||
53 | depend on RC_BIT_RATE_CHANGE in ENC_PARAM_CHANGE */ | ||
54 | NEW_RC_FRAME_RATE = 0x94, /* E, format as RC_FRAME_RATE(0xD0D0) | ||
55 | depend on RC_FRAME_RATE_CHANGE in ENC_PARAM_CHANGE */ | ||
56 | NEW_I_PERIOD = 0x98, /* E, format as I_FRM_CTRL(0xC504) | ||
57 | depend on I_PERIOD_CHANGE in ENC_PARAM_CHANGE */ | ||
58 | H264_I_PERIOD = 0x9C, /* E, H.264, open GOP */ | ||
59 | RC_CONTROL_CONFIG = 0xA0, /* E */ | ||
60 | BATCH_INPUT_ADDR = 0xA4, /* E */ | ||
61 | BATCH_OUTPUT_ADDR = 0xA8, /* E */ | ||
62 | BATCH_OUTPUT_SIZE = 0xAC, /* E */ | ||
63 | MIN_LUMA_DPB_SIZE = 0xB0, /* D */ | ||
64 | DEVICE_FORMAT_ID = 0xB4, /* C */ | ||
65 | H264_POC_TYPE = 0xB8, /* D */ | ||
66 | MIN_CHROMA_DPB_SIZE = 0xBC, /* D */ | ||
67 | DISP_PIC_FRAME_TYPE = 0xC0, /* D */ | ||
68 | FREE_LUMA_DPB = 0xC4, /* D, VC1 MPEG4 */ | ||
69 | ASPECT_RATIO_INFO = 0xC8, /* D, MPEG4 */ | ||
70 | EXTENDED_PAR = 0xCC, /* D, MPEG4 */ | ||
71 | DBG_HISTORY_INPUT0 = 0xD0, /* C */ | ||
72 | DBG_HISTORY_INPUT1 = 0xD4, /* C */ | ||
73 | DBG_HISTORY_OUTPUT = 0xD8, /* C */ | ||
74 | HIERARCHICAL_P_QP = 0xE0, /* E, H.264 */ | ||
75 | }; | ||
76 | |||
77 | int s5p_mfc_init_shm(struct s5p_mfc_ctx *ctx); | ||
78 | |||
79 | #define s5p_mfc_write_shm(ctx, x, ofs) \ | ||
80 | do { \ | ||
81 | writel(x, (ctx->shm + ofs)); \ | ||
82 | wmb(); \ | ||
83 | } while (0) | ||
84 | |||
85 | static inline u32 s5p_mfc_read_shm(struct s5p_mfc_ctx *ctx, unsigned int ofs) | ||
86 | { | ||
87 | rmb(); | ||
88 | return readl(ctx->shm + ofs); | ||
89 | } | ||
90 | |||
91 | #endif /* S5P_MFC_SHM_H_ */ | ||