]>
Commit | Line | Data |
---|---|---|
d2b4387f EJ |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | ||
3 | #include <linux/atomic.h> | |
4 | #include <linux/bitfield.h> | |
5 | #include <linux/clk.h> | |
6 | #include <linux/delay.h> | |
7 | #include <linux/device.h> | |
8 | #include <linux/dma-mapping.h> | |
9 | #include <linux/interrupt.h> | |
10 | #include <linux/jiffies.h> | |
11 | #include <linux/module.h> | |
12 | #include <linux/mutex.h> | |
13 | #include <linux/of.h> | |
14 | #include <linux/of_irq.h> | |
15 | #include <linux/of_reserved_mem.h> | |
16 | #include <linux/platform_device.h> | |
17 | #include <linux/reset.h> | |
18 | #include <linux/sched.h> | |
19 | #include <linux/spinlock.h> | |
20 | #include <linux/string.h> | |
21 | #include <linux/v4l2-controls.h> | |
22 | #include <linux/videodev2.h> | |
23 | #include <linux/wait.h> | |
24 | #include <linux/workqueue.h> | |
25 | #include <media/v4l2-ctrls.h> | |
26 | #include <media/v4l2-dev.h> | |
27 | #include <media/v4l2-device.h> | |
28 | #include <media/v4l2-dv-timings.h> | |
29 | #include <media/v4l2-event.h> | |
30 | #include <media/v4l2-ioctl.h> | |
31 | #include <media/videobuf2-dma-contig.h> | |
32 | ||
33 | #define DEVICE_NAME "aspeed-video" | |
34 | ||
35 | #define ASPEED_VIDEO_JPEG_NUM_QUALITIES 12 | |
36 | #define ASPEED_VIDEO_JPEG_HEADER_SIZE 10 | |
37 | #define ASPEED_VIDEO_JPEG_QUANT_SIZE 116 | |
38 | #define ASPEED_VIDEO_JPEG_DCT_SIZE 34 | |
39 | ||
40 | #define MAX_FRAME_RATE 60 | |
41 | #define MAX_HEIGHT 1200 | |
42 | #define MAX_WIDTH 1920 | |
43 | #define MIN_HEIGHT 480 | |
44 | #define MIN_WIDTH 640 | |
45 | ||
46 | #define NUM_POLARITY_CHECKS 10 | |
47 | #define INVALID_RESOLUTION_RETRIES 2 | |
48 | #define INVALID_RESOLUTION_DELAY msecs_to_jiffies(250) | |
49 | #define RESOLUTION_CHANGE_DELAY msecs_to_jiffies(500) | |
50 | #define MODE_DETECT_TIMEOUT msecs_to_jiffies(500) | |
51 | #define STOP_TIMEOUT msecs_to_jiffies(1000) | |
52 | #define DIRECT_FETCH_THRESHOLD 0x0c0000 /* 1024 * 768 */ | |
53 | ||
54 | #define VE_MAX_SRC_BUFFER_SIZE 0x8ca000 /* 1920 * 1200, 32bpp */ | |
55 | #define VE_JPEG_HEADER_SIZE 0x006000 /* 512 * 12 * 4 */ | |
56 | ||
57 | #define VE_PROTECTION_KEY 0x000 | |
58 | #define VE_PROTECTION_KEY_UNLOCK 0x1a038aa8 | |
59 | ||
60 | #define VE_SEQ_CTRL 0x004 | |
61 | #define VE_SEQ_CTRL_TRIG_MODE_DET BIT(0) | |
62 | #define VE_SEQ_CTRL_TRIG_CAPTURE BIT(1) | |
63 | #define VE_SEQ_CTRL_FORCE_IDLE BIT(2) | |
64 | #define VE_SEQ_CTRL_MULT_FRAME BIT(3) | |
65 | #define VE_SEQ_CTRL_TRIG_COMP BIT(4) | |
66 | #define VE_SEQ_CTRL_AUTO_COMP BIT(5) | |
67 | #define VE_SEQ_CTRL_EN_WATCHDOG BIT(7) | |
68 | #define VE_SEQ_CTRL_YUV420 BIT(10) | |
69 | #define VE_SEQ_CTRL_COMP_FMT GENMASK(11, 10) | |
70 | #define VE_SEQ_CTRL_HALT BIT(12) | |
71 | #define VE_SEQ_CTRL_EN_WATCHDOG_COMP BIT(14) | |
72 | #define VE_SEQ_CTRL_TRIG_JPG BIT(15) | |
73 | #define VE_SEQ_CTRL_CAP_BUSY BIT(16) | |
74 | #define VE_SEQ_CTRL_COMP_BUSY BIT(18) | |
75 | ||
76 | #ifdef CONFIG_MACH_ASPEED_G5 | |
77 | #define VE_SEQ_CTRL_JPEG_MODE BIT(13) /* AST2500 */ | |
78 | #else | |
79 | #define VE_SEQ_CTRL_JPEG_MODE BIT(8) /* AST2400 */ | |
80 | #endif /* CONFIG_MACH_ASPEED_G5 */ | |
81 | ||
82 | #define VE_CTRL 0x008 | |
83 | #define VE_CTRL_HSYNC_POL BIT(0) | |
84 | #define VE_CTRL_VSYNC_POL BIT(1) | |
85 | #define VE_CTRL_SOURCE BIT(2) | |
86 | #define VE_CTRL_INT_DE BIT(4) | |
87 | #define VE_CTRL_DIRECT_FETCH BIT(5) | |
88 | #define VE_CTRL_YUV BIT(6) | |
89 | #define VE_CTRL_RGB BIT(7) | |
90 | #define VE_CTRL_CAPTURE_FMT GENMASK(7, 6) | |
91 | #define VE_CTRL_AUTO_OR_CURSOR BIT(8) | |
92 | #define VE_CTRL_CLK_INVERSE BIT(11) | |
93 | #define VE_CTRL_CLK_DELAY GENMASK(11, 9) | |
94 | #define VE_CTRL_INTERLACE BIT(14) | |
95 | #define VE_CTRL_HSYNC_POL_CTRL BIT(15) | |
96 | #define VE_CTRL_FRC GENMASK(23, 16) | |
97 | ||
98 | #define VE_TGS_0 0x00c | |
99 | #define VE_TGS_1 0x010 | |
100 | #define VE_TGS_FIRST GENMASK(28, 16) | |
101 | #define VE_TGS_LAST GENMASK(12, 0) | |
102 | ||
103 | #define VE_SCALING_FACTOR 0x014 | |
104 | #define VE_SCALING_FILTER0 0x018 | |
105 | #define VE_SCALING_FILTER1 0x01c | |
106 | #define VE_SCALING_FILTER2 0x020 | |
107 | #define VE_SCALING_FILTER3 0x024 | |
108 | ||
109 | #define VE_CAP_WINDOW 0x030 | |
110 | #define VE_COMP_WINDOW 0x034 | |
111 | #define VE_COMP_PROC_OFFSET 0x038 | |
112 | #define VE_COMP_OFFSET 0x03c | |
113 | #define VE_JPEG_ADDR 0x040 | |
114 | #define VE_SRC0_ADDR 0x044 | |
115 | #define VE_SRC_SCANLINE_OFFSET 0x048 | |
116 | #define VE_SRC1_ADDR 0x04c | |
117 | #define VE_COMP_ADDR 0x054 | |
118 | ||
119 | #define VE_STREAM_BUF_SIZE 0x058 | |
120 | #define VE_STREAM_BUF_SIZE_N_PACKETS GENMASK(5, 3) | |
121 | #define VE_STREAM_BUF_SIZE_P_SIZE GENMASK(2, 0) | |
122 | ||
123 | #define VE_COMP_CTRL 0x060 | |
124 | #define VE_COMP_CTRL_VQ_DCT_ONLY BIT(0) | |
125 | #define VE_COMP_CTRL_VQ_4COLOR BIT(1) | |
126 | #define VE_COMP_CTRL_QUANTIZE BIT(2) | |
127 | #define VE_COMP_CTRL_EN_BQ BIT(4) | |
128 | #define VE_COMP_CTRL_EN_CRYPTO BIT(5) | |
129 | #define VE_COMP_CTRL_DCT_CHR GENMASK(10, 6) | |
130 | #define VE_COMP_CTRL_DCT_LUM GENMASK(15, 11) | |
131 | #define VE_COMP_CTRL_EN_HQ BIT(16) | |
132 | #define VE_COMP_CTRL_RSVD BIT(19) | |
133 | #define VE_COMP_CTRL_ENCODE GENMASK(21, 20) | |
134 | #define VE_COMP_CTRL_HQ_DCT_CHR GENMASK(26, 22) | |
135 | #define VE_COMP_CTRL_HQ_DCT_LUM GENMASK(31, 27) | |
136 | ||
137 | #define VE_OFFSET_COMP_STREAM 0x078 | |
138 | ||
139 | #define VE_SRC_LR_EDGE_DET 0x090 | |
140 | #define VE_SRC_LR_EDGE_DET_LEFT GENMASK(11, 0) | |
141 | #define VE_SRC_LR_EDGE_DET_NO_V BIT(12) | |
142 | #define VE_SRC_LR_EDGE_DET_NO_H BIT(13) | |
143 | #define VE_SRC_LR_EDGE_DET_NO_DISP BIT(14) | |
144 | #define VE_SRC_LR_EDGE_DET_NO_CLK BIT(15) | |
145 | #define VE_SRC_LR_EDGE_DET_RT_SHF 16 | |
146 | #define VE_SRC_LR_EDGE_DET_RT GENMASK(27, VE_SRC_LR_EDGE_DET_RT_SHF) | |
147 | #define VE_SRC_LR_EDGE_DET_INTERLACE BIT(31) | |
148 | ||
149 | #define VE_SRC_TB_EDGE_DET 0x094 | |
150 | #define VE_SRC_TB_EDGE_DET_TOP GENMASK(12, 0) | |
151 | #define VE_SRC_TB_EDGE_DET_BOT_SHF 16 | |
152 | #define VE_SRC_TB_EDGE_DET_BOT GENMASK(28, VE_SRC_TB_EDGE_DET_BOT_SHF) | |
153 | ||
154 | #define VE_MODE_DETECT_STATUS 0x098 | |
155 | #define VE_MODE_DETECT_H_PIXELS GENMASK(11, 0) | |
156 | #define VE_MODE_DETECT_V_LINES_SHF 16 | |
157 | #define VE_MODE_DETECT_V_LINES GENMASK(27, VE_MODE_DETECT_V_LINES_SHF) | |
158 | #define VE_MODE_DETECT_STATUS_VSYNC BIT(28) | |
159 | #define VE_MODE_DETECT_STATUS_HSYNC BIT(29) | |
160 | ||
161 | #define VE_SYNC_STATUS 0x09c | |
162 | #define VE_SYNC_STATUS_HSYNC GENMASK(11, 0) | |
163 | #define VE_SYNC_STATUS_VSYNC_SHF 16 | |
164 | #define VE_SYNC_STATUS_VSYNC GENMASK(27, VE_SYNC_STATUS_VSYNC_SHF) | |
165 | ||
166 | #define VE_INTERRUPT_CTRL 0x304 | |
167 | #define VE_INTERRUPT_STATUS 0x308 | |
168 | #define VE_INTERRUPT_MODE_DETECT_WD BIT(0) | |
169 | #define VE_INTERRUPT_CAPTURE_COMPLETE BIT(1) | |
170 | #define VE_INTERRUPT_COMP_READY BIT(2) | |
171 | #define VE_INTERRUPT_COMP_COMPLETE BIT(3) | |
172 | #define VE_INTERRUPT_MODE_DETECT BIT(4) | |
173 | #define VE_INTERRUPT_FRAME_COMPLETE BIT(5) | |
174 | #define VE_INTERRUPT_DECODE_ERR BIT(6) | |
175 | #define VE_INTERRUPT_HALT_READY BIT(8) | |
176 | #define VE_INTERRUPT_HANG_WD BIT(9) | |
177 | #define VE_INTERRUPT_STREAM_DESC BIT(10) | |
178 | #define VE_INTERRUPT_VSYNC_DESC BIT(11) | |
179 | ||
180 | #define VE_MODE_DETECT 0x30c | |
181 | #define VE_MEM_RESTRICT_START 0x310 | |
182 | #define VE_MEM_RESTRICT_END 0x314 | |
183 | ||
184 | enum { | |
185 | VIDEO_MODE_DETECT_DONE, | |
186 | VIDEO_RES_CHANGE, | |
187 | VIDEO_RES_DETECT, | |
188 | VIDEO_STREAMING, | |
189 | VIDEO_FRAME_INPRG, | |
190 | VIDEO_STOPPED, | |
191 | }; | |
192 | ||
193 | struct aspeed_video_addr { | |
194 | unsigned int size; | |
195 | dma_addr_t dma; | |
196 | void *virt; | |
197 | }; | |
198 | ||
199 | struct aspeed_video_buffer { | |
200 | struct vb2_v4l2_buffer vb; | |
201 | struct list_head link; | |
202 | }; | |
203 | ||
204 | #define to_aspeed_video_buffer(x) \ | |
205 | container_of((x), struct aspeed_video_buffer, vb) | |
206 | ||
207 | struct aspeed_video { | |
208 | void __iomem *base; | |
209 | struct clk *eclk; | |
210 | struct clk *vclk; | |
211 | struct reset_control *rst; | |
212 | ||
213 | struct device *dev; | |
214 | struct v4l2_ctrl_handler ctrl_handler; | |
215 | struct v4l2_device v4l2_dev; | |
216 | struct v4l2_pix_format pix_fmt; | |
217 | struct v4l2_bt_timings active_timings; | |
218 | struct v4l2_bt_timings detected_timings; | |
219 | u32 v4l2_input_status; | |
220 | struct vb2_queue queue; | |
221 | struct video_device vdev; | |
222 | struct mutex video_lock; /* v4l2 and videobuf2 lock */ | |
223 | ||
224 | wait_queue_head_t wait; | |
225 | spinlock_t lock; /* buffer list lock */ | |
226 | struct delayed_work res_work; | |
227 | struct list_head buffers; | |
228 | unsigned long flags; | |
229 | unsigned int sequence; | |
230 | ||
231 | unsigned int max_compressed_size; | |
232 | struct aspeed_video_addr srcs[2]; | |
233 | struct aspeed_video_addr jpeg; | |
234 | ||
235 | bool yuv420; | |
236 | unsigned int frame_rate; | |
237 | unsigned int jpeg_quality; | |
238 | ||
239 | unsigned int frame_bottom; | |
240 | unsigned int frame_left; | |
241 | unsigned int frame_right; | |
242 | unsigned int frame_top; | |
243 | }; | |
244 | ||
245 | #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev) | |
246 | ||
247 | static const u32 aspeed_video_jpeg_header[ASPEED_VIDEO_JPEG_HEADER_SIZE] = { | |
248 | 0xe0ffd8ff, 0x464a1000, 0x01004649, 0x60000101, 0x00006000, 0x0f00feff, | |
249 | 0x00002d05, 0x00000000, 0x00000000, 0x00dbff00 | |
250 | }; | |
251 | ||
252 | static const u32 aspeed_video_jpeg_quant[ASPEED_VIDEO_JPEG_QUANT_SIZE] = { | |
253 | 0x081100c0, 0x00000000, 0x00110103, 0x03011102, 0xc4ff0111, 0x00001f00, | |
254 | 0x01010501, 0x01010101, 0x00000000, 0x00000000, 0x04030201, 0x08070605, | |
255 | 0xff0b0a09, 0x10b500c4, 0x03010200, 0x03040203, 0x04040505, 0x7d010000, | |
256 | 0x00030201, 0x12051104, 0x06413121, 0x07615113, 0x32147122, 0x08a19181, | |
257 | 0xc1b14223, 0xf0d15215, 0x72623324, 0x160a0982, 0x1a191817, 0x28272625, | |
258 | 0x35342a29, 0x39383736, 0x4544433a, 0x49484746, 0x5554534a, 0x59585756, | |
259 | 0x6564635a, 0x69686766, 0x7574736a, 0x79787776, 0x8584837a, 0x89888786, | |
260 | 0x9493928a, 0x98979695, 0xa3a29a99, 0xa7a6a5a4, 0xb2aaa9a8, 0xb6b5b4b3, | |
261 | 0xbab9b8b7, 0xc5c4c3c2, 0xc9c8c7c6, 0xd4d3d2ca, 0xd8d7d6d5, 0xe2e1dad9, | |
262 | 0xe6e5e4e3, 0xeae9e8e7, 0xf4f3f2f1, 0xf8f7f6f5, 0xc4fffaf9, 0x00011f00, | |
263 | 0x01010103, 0x01010101, 0x00000101, 0x00000000, 0x04030201, 0x08070605, | |
264 | 0xff0b0a09, 0x11b500c4, 0x02010200, 0x04030404, 0x04040507, 0x77020100, | |
265 | 0x03020100, 0x21050411, 0x41120631, 0x71610751, 0x81322213, 0x91421408, | |
266 | 0x09c1b1a1, 0xf0523323, 0xd1726215, 0x3424160a, 0x17f125e1, 0x261a1918, | |
267 | 0x2a292827, 0x38373635, 0x44433a39, 0x48474645, 0x54534a49, 0x58575655, | |
268 | 0x64635a59, 0x68676665, 0x74736a69, 0x78777675, 0x83827a79, 0x87868584, | |
269 | 0x928a8988, 0x96959493, 0x9a999897, 0xa5a4a3a2, 0xa9a8a7a6, 0xb4b3b2aa, | |
270 | 0xb8b7b6b5, 0xc3c2bab9, 0xc7c6c5c4, 0xd2cac9c8, 0xd6d5d4d3, 0xdad9d8d7, | |
271 | 0xe5e4e3e2, 0xe9e8e7e6, 0xf4f3f2ea, 0xf8f7f6f5, 0xdafffaf9, 0x01030c00, | |
272 | 0x03110200, 0x003f0011 | |
273 | }; | |
274 | ||
275 | static const u32 aspeed_video_jpeg_dct[ASPEED_VIDEO_JPEG_NUM_QUALITIES] | |
276 | [ASPEED_VIDEO_JPEG_DCT_SIZE] = { | |
277 | { 0x0d140043, 0x0c0f110f, 0x11101114, 0x17141516, 0x1e20321e, | |
278 | 0x3d1e1b1b, 0x32242e2b, 0x4b4c3f48, 0x44463f47, 0x61735a50, | |
279 | 0x566c5550, 0x88644644, 0x7a766c65, 0x4d808280, 0x8c978d60, | |
280 | 0x7e73967d, 0xdbff7b80, 0x1f014300, 0x272d2121, 0x3030582d, | |
281 | 0x697bb958, 0xb8b9b97b, 0xb9b8a6a6, 0xb9b9b9b9, 0xb9b9b9b9, | |
282 | 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, | |
283 | 0xb9b9b9b9, 0xb9b9b9b9, 0xb9b9b9b9, 0xffb9b9b9 }, | |
284 | { 0x0c110043, 0x0a0d0f0d, 0x0f0e0f11, 0x14111213, 0x1a1c2b1a, | |
285 | 0x351a1818, 0x2b1f2826, 0x4142373f, 0x3c3d373e, 0x55644e46, | |
286 | 0x4b5f4a46, 0x77573d3c, 0x6b675f58, 0x43707170, 0x7a847b54, | |
287 | 0x6e64836d, 0xdbff6c70, 0x1b014300, 0x22271d1d, 0x2a2a4c27, | |
288 | 0x5b6ba04c, 0xa0a0a06b, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, | |
289 | 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, | |
290 | 0xa0a0a0a0, 0xa0a0a0a0, 0xa0a0a0a0, 0xffa0a0a0 }, | |
291 | { 0x090e0043, 0x090a0c0a, 0x0c0b0c0e, 0x110e0f10, 0x15172415, | |
292 | 0x2c151313, 0x241a211f, 0x36372e34, 0x31322e33, 0x4653413a, | |
293 | 0x3e4e3d3a, 0x62483231, 0x58564e49, 0x385d5e5d, 0x656d6645, | |
294 | 0x5b536c5a, 0xdbff595d, 0x16014300, 0x1c201818, 0x22223f20, | |
295 | 0x4b58853f, 0x85858558, 0x85858585, 0x85858585, 0x85858585, | |
296 | 0x85858585, 0x85858585, 0x85858585, 0x85858585, 0x85858585, | |
297 | 0x85858585, 0x85858585, 0x85858585, 0xff858585 }, | |
298 | { 0x070b0043, 0x07080a08, 0x0a090a0b, 0x0d0b0c0c, 0x11121c11, | |
299 | 0x23110f0f, 0x1c141a19, 0x2b2b2429, 0x27282428, 0x3842332e, | |
300 | 0x313e302e, 0x4e392827, 0x46443e3a, 0x2c4a4a4a, 0x50565137, | |
301 | 0x48425647, 0xdbff474a, 0x12014300, 0x161a1313, 0x1c1c331a, | |
302 | 0x3d486c33, 0x6c6c6c48, 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, | |
303 | 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, | |
304 | 0x6c6c6c6c, 0x6c6c6c6c, 0x6c6c6c6c, 0xff6c6c6c }, | |
305 | { 0x06090043, 0x05060706, 0x07070709, 0x0a09090a, 0x0d0e160d, | |
306 | 0x1b0d0c0c, 0x16101413, 0x21221c20, 0x1e1f1c20, 0x2b332824, | |
307 | 0x26302624, 0x3d2d1f1e, 0x3735302d, 0x22393a39, 0x3f443f2b, | |
308 | 0x38334338, 0xdbff3739, 0x0d014300, 0x11130e0e, 0x15152613, | |
309 | 0x2d355026, 0x50505035, 0x50505050, 0x50505050, 0x50505050, | |
310 | 0x50505050, 0x50505050, 0x50505050, 0x50505050, 0x50505050, | |
311 | 0x50505050, 0x50505050, 0x50505050, 0xff505050 }, | |
312 | { 0x04060043, 0x03040504, 0x05040506, 0x07060606, 0x09090f09, | |
313 | 0x12090808, 0x0f0a0d0d, 0x16161315, 0x14151315, 0x1d221b18, | |
314 | 0x19201918, 0x281e1514, 0x2423201e, 0x17262726, 0x2a2d2a1c, | |
315 | 0x25222d25, 0xdbff2526, 0x09014300, 0x0b0d0a0a, 0x0e0e1a0d, | |
316 | 0x1f25371a, 0x37373725, 0x37373737, 0x37373737, 0x37373737, | |
317 | 0x37373737, 0x37373737, 0x37373737, 0x37373737, 0x37373737, | |
318 | 0x37373737, 0x37373737, 0x37373737, 0xff373737 }, | |
319 | { 0x02030043, 0x01020202, 0x02020203, 0x03030303, 0x04040704, | |
320 | 0x09040404, 0x07050606, 0x0b0b090a, 0x0a0a090a, 0x0e110d0c, | |
321 | 0x0c100c0c, 0x140f0a0a, 0x1211100f, 0x0b131313, 0x1516150e, | |
322 | 0x12111612, 0xdbff1213, 0x04014300, 0x05060505, 0x07070d06, | |
323 | 0x0f121b0d, 0x1b1b1b12, 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, | |
324 | 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, | |
325 | 0x1b1b1b1b, 0x1b1b1b1b, 0x1b1b1b1b, 0xff1b1b1b }, | |
326 | { 0x01020043, 0x01010101, 0x01010102, 0x02020202, 0x03030503, | |
327 | 0x06030202, 0x05030404, 0x07070607, 0x06070607, 0x090b0908, | |
328 | 0x080a0808, 0x0d0a0706, 0x0c0b0a0a, 0x070c0d0c, 0x0e0f0e09, | |
329 | 0x0c0b0f0c, 0xdbff0c0c, 0x03014300, 0x03040303, 0x04040804, | |
330 | 0x0a0c1208, 0x1212120c, 0x12121212, 0x12121212, 0x12121212, | |
331 | 0x12121212, 0x12121212, 0x12121212, 0x12121212, 0x12121212, | |
332 | 0x12121212, 0x12121212, 0x12121212, 0xff121212 }, | |
333 | { 0x01020043, 0x01010101, 0x01010102, 0x02020202, 0x03030503, | |
334 | 0x06030202, 0x05030404, 0x07070607, 0x06070607, 0x090b0908, | |
335 | 0x080a0808, 0x0d0a0706, 0x0c0b0a0a, 0x070c0d0c, 0x0e0f0e09, | |
336 | 0x0c0b0f0c, 0xdbff0c0c, 0x02014300, 0x03030202, 0x04040703, | |
337 | 0x080a0f07, 0x0f0f0f0a, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, | |
338 | 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, | |
339 | 0x0f0f0f0f, 0x0f0f0f0f, 0x0f0f0f0f, 0xff0f0f0f }, | |
340 | { 0x01010043, 0x01010101, 0x01010101, 0x01010101, 0x02020302, | |
341 | 0x04020202, 0x03020303, 0x05050405, 0x05050405, 0x07080606, | |
342 | 0x06080606, 0x0a070505, 0x09080807, 0x05090909, 0x0a0b0a07, | |
343 | 0x09080b09, 0xdbff0909, 0x02014300, 0x02030202, 0x03030503, | |
344 | 0x07080c05, 0x0c0c0c08, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, | |
345 | 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, | |
346 | 0x0c0c0c0c, 0x0c0c0c0c, 0x0c0c0c0c, 0xff0c0c0c }, | |
347 | { 0x01010043, 0x01010101, 0x01010101, 0x01010101, 0x01010201, | |
348 | 0x03010101, 0x02010202, 0x03030303, 0x03030303, 0x04050404, | |
349 | 0x04050404, 0x06050303, 0x06050505, 0x03060606, 0x07070704, | |
350 | 0x06050706, 0xdbff0606, 0x01014300, 0x01020101, 0x02020402, | |
351 | 0x05060904, 0x09090906, 0x09090909, 0x09090909, 0x09090909, | |
352 | 0x09090909, 0x09090909, 0x09090909, 0x09090909, 0x09090909, | |
353 | 0x09090909, 0x09090909, 0x09090909, 0xff090909 }, | |
354 | { 0x01010043, 0x01010101, 0x01010101, 0x01010101, 0x01010101, | |
355 | 0x01010101, 0x01010101, 0x01010101, 0x01010101, 0x02020202, | |
356 | 0x02020202, 0x03020101, 0x03020202, 0x01030303, 0x03030302, | |
357 | 0x03020303, 0xdbff0403, 0x01014300, 0x01010101, 0x01010201, | |
358 | 0x03040602, 0x06060604, 0x06060606, 0x06060606, 0x06060606, | |
359 | 0x06060606, 0x06060606, 0x06060606, 0x06060606, 0x06060606, | |
360 | 0x06060606, 0x06060606, 0x06060606, 0xff060606 } | |
361 | }; | |
362 | ||
363 | static const struct v4l2_dv_timings_cap aspeed_video_timings_cap = { | |
364 | .type = V4L2_DV_BT_656_1120, | |
365 | .bt = { | |
366 | .min_width = MIN_WIDTH, | |
367 | .max_width = MAX_WIDTH, | |
368 | .min_height = MIN_HEIGHT, | |
369 | .max_height = MAX_HEIGHT, | |
370 | .min_pixelclock = 6574080, /* 640 x 480 x 24Hz */ | |
371 | .max_pixelclock = 138240000, /* 1920 x 1200 x 60Hz */ | |
372 | .standards = V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | | |
373 | V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, | |
374 | .capabilities = V4L2_DV_BT_CAP_PROGRESSIVE | | |
375 | V4L2_DV_BT_CAP_REDUCED_BLANKING | | |
376 | V4L2_DV_BT_CAP_CUSTOM, | |
377 | }, | |
378 | }; | |
379 | ||
380 | static void aspeed_video_init_jpeg_table(u32 *table, bool yuv420) | |
381 | { | |
382 | int i; | |
383 | unsigned int base; | |
384 | ||
385 | for (i = 0; i < ASPEED_VIDEO_JPEG_NUM_QUALITIES; i++) { | |
386 | base = 256 * i; /* AST HW requires this header spacing */ | |
387 | memcpy(&table[base], aspeed_video_jpeg_header, | |
388 | sizeof(aspeed_video_jpeg_header)); | |
389 | ||
390 | base += ASPEED_VIDEO_JPEG_HEADER_SIZE; | |
391 | memcpy(&table[base], aspeed_video_jpeg_dct[i], | |
392 | sizeof(aspeed_video_jpeg_dct[i])); | |
393 | ||
394 | base += ASPEED_VIDEO_JPEG_DCT_SIZE; | |
395 | memcpy(&table[base], aspeed_video_jpeg_quant, | |
396 | sizeof(aspeed_video_jpeg_quant)); | |
397 | ||
398 | if (yuv420) | |
399 | table[base + 2] = 0x00220103; | |
400 | } | |
401 | } | |
402 | ||
403 | static void aspeed_video_update(struct aspeed_video *video, u32 reg, u32 clear, | |
404 | u32 bits) | |
405 | { | |
406 | u32 t = readl(video->base + reg); | |
407 | u32 before = t; | |
408 | ||
409 | t &= ~clear; | |
410 | t |= bits; | |
411 | writel(t, video->base + reg); | |
412 | dev_dbg(video->dev, "update %03x[%08x -> %08x]\n", reg, before, | |
413 | readl(video->base + reg)); | |
414 | } | |
415 | ||
416 | static u32 aspeed_video_read(struct aspeed_video *video, u32 reg) | |
417 | { | |
418 | u32 t = readl(video->base + reg); | |
419 | ||
420 | dev_dbg(video->dev, "read %03x[%08x]\n", reg, t); | |
421 | return t; | |
422 | } | |
423 | ||
424 | static void aspeed_video_write(struct aspeed_video *video, u32 reg, u32 val) | |
425 | { | |
426 | writel(val, video->base + reg); | |
427 | dev_dbg(video->dev, "write %03x[%08x]\n", reg, | |
428 | readl(video->base + reg)); | |
429 | } | |
430 | ||
431 | static int aspeed_video_start_frame(struct aspeed_video *video) | |
432 | { | |
433 | dma_addr_t addr; | |
434 | unsigned long flags; | |
435 | struct aspeed_video_buffer *buf; | |
436 | u32 seq_ctrl = aspeed_video_read(video, VE_SEQ_CTRL); | |
437 | ||
438 | if (video->v4l2_input_status) { | |
439 | dev_dbg(video->dev, "No signal; don't start frame\n"); | |
440 | return 0; | |
441 | } | |
442 | ||
443 | if (!(seq_ctrl & VE_SEQ_CTRL_COMP_BUSY) || | |
444 | !(seq_ctrl & VE_SEQ_CTRL_CAP_BUSY)) { | |
445 | dev_err(video->dev, "Engine busy; don't start frame\n"); | |
446 | return -EBUSY; | |
447 | } | |
448 | ||
449 | spin_lock_irqsave(&video->lock, flags); | |
450 | buf = list_first_entry_or_null(&video->buffers, | |
451 | struct aspeed_video_buffer, link); | |
452 | if (!buf) { | |
453 | spin_unlock_irqrestore(&video->lock, flags); | |
454 | dev_dbg(video->dev, "No buffers; don't start frame\n"); | |
455 | return -EPROTO; | |
456 | } | |
457 | ||
458 | set_bit(VIDEO_FRAME_INPRG, &video->flags); | |
459 | addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); | |
460 | spin_unlock_irqrestore(&video->lock, flags); | |
461 | ||
462 | aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0); | |
463 | aspeed_video_write(video, VE_COMP_OFFSET, 0); | |
464 | aspeed_video_write(video, VE_COMP_ADDR, addr); | |
465 | ||
466 | aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, | |
467 | VE_INTERRUPT_COMP_COMPLETE | | |
468 | VE_INTERRUPT_CAPTURE_COMPLETE); | |
469 | ||
470 | aspeed_video_update(video, VE_SEQ_CTRL, 0, | |
471 | VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP); | |
472 | ||
473 | return 0; | |
474 | } | |
475 | ||
476 | static void aspeed_video_enable_mode_detect(struct aspeed_video *video) | |
477 | { | |
478 | /* Enable mode detect interrupts */ | |
479 | aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, | |
480 | VE_INTERRUPT_MODE_DETECT); | |
481 | ||
482 | /* Trigger mode detect */ | |
483 | aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_MODE_DET); | |
484 | } | |
485 | ||
486 | static void aspeed_video_reset(struct aspeed_video *video) | |
487 | { | |
488 | /* Reset the engine */ | |
489 | reset_control_assert(video->rst); | |
490 | ||
491 | /* Don't usleep here; function may be called in interrupt context */ | |
492 | udelay(100); | |
493 | reset_control_deassert(video->rst); | |
494 | } | |
495 | ||
496 | static void aspeed_video_off(struct aspeed_video *video) | |
497 | { | |
498 | aspeed_video_reset(video); | |
499 | ||
500 | /* Turn off the relevant clocks */ | |
501 | clk_disable_unprepare(video->vclk); | |
502 | clk_disable_unprepare(video->eclk); | |
503 | } | |
504 | ||
505 | static void aspeed_video_on(struct aspeed_video *video) | |
506 | { | |
507 | /* Turn on the relevant clocks */ | |
508 | clk_prepare_enable(video->eclk); | |
509 | clk_prepare_enable(video->vclk); | |
510 | ||
511 | aspeed_video_reset(video); | |
512 | } | |
513 | ||
514 | static void aspeed_video_bufs_done(struct aspeed_video *video, | |
515 | enum vb2_buffer_state state) | |
516 | { | |
517 | unsigned long flags; | |
518 | struct aspeed_video_buffer *buf; | |
519 | ||
520 | spin_lock_irqsave(&video->lock, flags); | |
521 | list_for_each_entry(buf, &video->buffers, link) | |
522 | vb2_buffer_done(&buf->vb.vb2_buf, state); | |
523 | INIT_LIST_HEAD(&video->buffers); | |
524 | spin_unlock_irqrestore(&video->lock, flags); | |
525 | } | |
526 | ||
527 | static void aspeed_video_irq_res_change(struct aspeed_video *video) | |
528 | { | |
529 | dev_dbg(video->dev, "Resolution changed; resetting\n"); | |
530 | ||
531 | set_bit(VIDEO_RES_CHANGE, &video->flags); | |
532 | clear_bit(VIDEO_FRAME_INPRG, &video->flags); | |
533 | ||
534 | aspeed_video_off(video); | |
535 | aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR); | |
536 | ||
537 | schedule_delayed_work(&video->res_work, RESOLUTION_CHANGE_DELAY); | |
538 | } | |
539 | ||
540 | static irqreturn_t aspeed_video_irq(int irq, void *arg) | |
541 | { | |
542 | struct aspeed_video *video = arg; | |
543 | u32 sts = aspeed_video_read(video, VE_INTERRUPT_STATUS); | |
544 | ||
545 | /* | |
546 | * Resolution changed or signal was lost; reset the engine and | |
547 | * re-initialize | |
548 | */ | |
549 | if (sts & VE_INTERRUPT_MODE_DETECT_WD) { | |
550 | aspeed_video_irq_res_change(video); | |
551 | return IRQ_HANDLED; | |
552 | } | |
553 | ||
554 | if (sts & VE_INTERRUPT_MODE_DETECT) { | |
555 | if (test_bit(VIDEO_RES_DETECT, &video->flags)) { | |
556 | aspeed_video_update(video, VE_INTERRUPT_CTRL, | |
557 | VE_INTERRUPT_MODE_DETECT, 0); | |
558 | aspeed_video_write(video, VE_INTERRUPT_STATUS, | |
559 | VE_INTERRUPT_MODE_DETECT); | |
560 | ||
561 | set_bit(VIDEO_MODE_DETECT_DONE, &video->flags); | |
562 | wake_up_interruptible_all(&video->wait); | |
563 | } else { | |
564 | /* | |
565 | * Signal acquired while NOT doing resolution | |
566 | * detection; reset the engine and re-initialize | |
567 | */ | |
568 | aspeed_video_irq_res_change(video); | |
569 | return IRQ_HANDLED; | |
570 | } | |
571 | } | |
572 | ||
573 | if ((sts & VE_INTERRUPT_COMP_COMPLETE) && | |
574 | (sts & VE_INTERRUPT_CAPTURE_COMPLETE)) { | |
575 | struct aspeed_video_buffer *buf; | |
576 | u32 frame_size = aspeed_video_read(video, | |
577 | VE_OFFSET_COMP_STREAM); | |
578 | ||
579 | spin_lock(&video->lock); | |
580 | clear_bit(VIDEO_FRAME_INPRG, &video->flags); | |
581 | buf = list_first_entry_or_null(&video->buffers, | |
582 | struct aspeed_video_buffer, | |
583 | link); | |
584 | if (buf) { | |
585 | vb2_set_plane_payload(&buf->vb.vb2_buf, 0, frame_size); | |
586 | ||
587 | if (!list_is_last(&buf->link, &video->buffers)) { | |
588 | buf->vb.vb2_buf.timestamp = ktime_get_ns(); | |
589 | buf->vb.sequence = video->sequence++; | |
590 | buf->vb.field = V4L2_FIELD_NONE; | |
591 | vb2_buffer_done(&buf->vb.vb2_buf, | |
592 | VB2_BUF_STATE_DONE); | |
593 | list_del(&buf->link); | |
594 | } | |
595 | } | |
596 | spin_unlock(&video->lock); | |
597 | ||
598 | aspeed_video_update(video, VE_SEQ_CTRL, | |
599 | VE_SEQ_CTRL_TRIG_CAPTURE | | |
600 | VE_SEQ_CTRL_FORCE_IDLE | | |
601 | VE_SEQ_CTRL_TRIG_COMP, 0); | |
602 | aspeed_video_update(video, VE_INTERRUPT_CTRL, | |
603 | VE_INTERRUPT_COMP_COMPLETE | | |
604 | VE_INTERRUPT_CAPTURE_COMPLETE, 0); | |
605 | aspeed_video_write(video, VE_INTERRUPT_STATUS, | |
606 | VE_INTERRUPT_COMP_COMPLETE | | |
607 | VE_INTERRUPT_CAPTURE_COMPLETE); | |
608 | ||
609 | if (test_bit(VIDEO_STREAMING, &video->flags) && buf) | |
610 | aspeed_video_start_frame(video); | |
611 | } | |
612 | ||
613 | return IRQ_HANDLED; | |
614 | } | |
615 | ||
616 | static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) | |
617 | { | |
618 | int i; | |
619 | int hsync_counter = 0; | |
620 | int vsync_counter = 0; | |
621 | u32 sts; | |
622 | ||
623 | for (i = 0; i < NUM_POLARITY_CHECKS; ++i) { | |
624 | sts = aspeed_video_read(video, VE_MODE_DETECT_STATUS); | |
625 | if (sts & VE_MODE_DETECT_STATUS_VSYNC) | |
626 | vsync_counter--; | |
627 | else | |
628 | vsync_counter++; | |
629 | ||
630 | if (sts & VE_MODE_DETECT_STATUS_HSYNC) | |
631 | hsync_counter--; | |
632 | else | |
633 | hsync_counter++; | |
634 | } | |
635 | ||
636 | if (hsync_counter < 0 || vsync_counter < 0) { | |
637 | u32 ctrl; | |
638 | ||
639 | if (hsync_counter < 0) { | |
640 | ctrl = VE_CTRL_HSYNC_POL; | |
641 | video->detected_timings.polarities &= | |
642 | ~V4L2_DV_HSYNC_POS_POL; | |
643 | } else { | |
644 | video->detected_timings.polarities |= | |
645 | V4L2_DV_HSYNC_POS_POL; | |
646 | } | |
647 | ||
648 | if (vsync_counter < 0) { | |
649 | ctrl = VE_CTRL_VSYNC_POL; | |
650 | video->detected_timings.polarities &= | |
651 | ~V4L2_DV_VSYNC_POS_POL; | |
652 | } else { | |
653 | video->detected_timings.polarities |= | |
654 | V4L2_DV_VSYNC_POS_POL; | |
655 | } | |
656 | ||
657 | aspeed_video_update(video, VE_CTRL, 0, ctrl); | |
658 | } | |
659 | } | |
660 | ||
661 | static bool aspeed_video_alloc_buf(struct aspeed_video *video, | |
662 | struct aspeed_video_addr *addr, | |
663 | unsigned int size) | |
664 | { | |
665 | addr->virt = dma_alloc_coherent(video->dev, size, &addr->dma, | |
666 | GFP_KERNEL); | |
667 | if (!addr->virt) | |
668 | return false; | |
669 | ||
670 | addr->size = size; | |
671 | return true; | |
672 | } | |
673 | ||
674 | static void aspeed_video_free_buf(struct aspeed_video *video, | |
675 | struct aspeed_video_addr *addr) | |
676 | { | |
677 | dma_free_coherent(video->dev, addr->size, addr->virt, addr->dma); | |
678 | addr->size = 0; | |
679 | addr->dma = 0ULL; | |
680 | addr->virt = NULL; | |
681 | } | |
682 | ||
683 | /* | |
684 | * Get the minimum HW-supported compression buffer size for the frame size. | |
685 | * Assume worst-case JPEG compression size is 1/8 raw size. This should be | |
686 | * plenty even for maximum quality; any worse and the engine will simply return | |
687 | * incomplete JPEGs. | |
688 | */ | |
689 | static void aspeed_video_calc_compressed_size(struct aspeed_video *video, | |
690 | unsigned int frame_size) | |
691 | { | |
692 | int i, j; | |
693 | u32 compression_buffer_size_reg = 0; | |
694 | unsigned int size; | |
695 | const unsigned int num_compression_packets = 4; | |
696 | const unsigned int compression_packet_size = 1024; | |
697 | const unsigned int max_compressed_size = frame_size / 2; /* 4bpp / 8 */ | |
698 | ||
699 | video->max_compressed_size = UINT_MAX; | |
700 | ||
701 | for (i = 0; i < 6; ++i) { | |
702 | for (j = 0; j < 8; ++j) { | |
703 | size = (num_compression_packets << i) * | |
704 | (compression_packet_size << j); | |
705 | if (size < max_compressed_size) | |
706 | continue; | |
707 | ||
708 | if (size < video->max_compressed_size) { | |
709 | compression_buffer_size_reg = (i << 3) | j; | |
710 | video->max_compressed_size = size; | |
711 | } | |
712 | } | |
713 | } | |
714 | ||
715 | aspeed_video_write(video, VE_STREAM_BUF_SIZE, | |
716 | compression_buffer_size_reg); | |
717 | ||
718 | dev_dbg(video->dev, "Max compressed size: %x\n", | |
719 | video->max_compressed_size); | |
720 | } | |
721 | ||
722 | #define res_check(v) test_and_clear_bit(VIDEO_MODE_DETECT_DONE, &(v)->flags) | |
723 | ||
724 | static void aspeed_video_get_resolution(struct aspeed_video *video) | |
725 | { | |
726 | bool invalid_resolution = true; | |
727 | int rc; | |
728 | int tries = 0; | |
729 | u32 mds; | |
730 | u32 src_lr_edge; | |
731 | u32 src_tb_edge; | |
732 | u32 sync; | |
733 | struct v4l2_bt_timings *det = &video->detected_timings; | |
734 | ||
735 | det->width = MIN_WIDTH; | |
736 | det->height = MIN_HEIGHT; | |
737 | video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; | |
738 | ||
739 | /* | |
740 | * Since we need max buffer size for detection, free the second source | |
741 | * buffer first. | |
742 | */ | |
743 | if (video->srcs[1].size) | |
744 | aspeed_video_free_buf(video, &video->srcs[1]); | |
745 | ||
746 | if (video->srcs[0].size < VE_MAX_SRC_BUFFER_SIZE) { | |
747 | if (video->srcs[0].size) | |
748 | aspeed_video_free_buf(video, &video->srcs[0]); | |
749 | ||
750 | if (!aspeed_video_alloc_buf(video, &video->srcs[0], | |
751 | VE_MAX_SRC_BUFFER_SIZE)) { | |
752 | dev_err(video->dev, | |
753 | "Failed to allocate source buffers\n"); | |
754 | return; | |
755 | } | |
756 | } | |
757 | ||
758 | aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma); | |
759 | ||
760 | do { | |
761 | if (tries) { | |
762 | set_current_state(TASK_INTERRUPTIBLE); | |
763 | if (schedule_timeout(INVALID_RESOLUTION_DELAY)) | |
764 | return; | |
765 | } | |
766 | ||
767 | set_bit(VIDEO_RES_DETECT, &video->flags); | |
768 | aspeed_video_enable_mode_detect(video); | |
769 | ||
770 | rc = wait_event_interruptible_timeout(video->wait, | |
771 | res_check(video), | |
772 | MODE_DETECT_TIMEOUT); | |
773 | if (!rc) { | |
774 | dev_err(video->dev, "Timed out; first mode detect\n"); | |
775 | clear_bit(VIDEO_RES_DETECT, &video->flags); | |
776 | return; | |
777 | } | |
778 | ||
779 | /* Disable mode detect in order to re-trigger */ | |
780 | aspeed_video_update(video, VE_SEQ_CTRL, | |
781 | VE_SEQ_CTRL_TRIG_MODE_DET, 0); | |
782 | ||
783 | aspeed_video_check_and_set_polarity(video); | |
784 | ||
785 | aspeed_video_enable_mode_detect(video); | |
786 | ||
787 | rc = wait_event_interruptible_timeout(video->wait, | |
788 | res_check(video), | |
789 | MODE_DETECT_TIMEOUT); | |
790 | clear_bit(VIDEO_RES_DETECT, &video->flags); | |
791 | if (!rc) { | |
792 | dev_err(video->dev, "Timed out; second mode detect\n"); | |
793 | return; | |
794 | } | |
795 | ||
796 | src_lr_edge = aspeed_video_read(video, VE_SRC_LR_EDGE_DET); | |
797 | src_tb_edge = aspeed_video_read(video, VE_SRC_TB_EDGE_DET); | |
798 | mds = aspeed_video_read(video, VE_MODE_DETECT_STATUS); | |
799 | sync = aspeed_video_read(video, VE_SYNC_STATUS); | |
800 | ||
801 | video->frame_bottom = (src_tb_edge & VE_SRC_TB_EDGE_DET_BOT) >> | |
802 | VE_SRC_TB_EDGE_DET_BOT_SHF; | |
803 | video->frame_top = src_tb_edge & VE_SRC_TB_EDGE_DET_TOP; | |
804 | det->vfrontporch = video->frame_top; | |
805 | det->vbackporch = ((mds & VE_MODE_DETECT_V_LINES) >> | |
806 | VE_MODE_DETECT_V_LINES_SHF) - video->frame_bottom; | |
807 | det->vsync = (sync & VE_SYNC_STATUS_VSYNC) >> | |
808 | VE_SYNC_STATUS_VSYNC_SHF; | |
809 | if (video->frame_top > video->frame_bottom) | |
810 | continue; | |
811 | ||
812 | video->frame_right = (src_lr_edge & VE_SRC_LR_EDGE_DET_RT) >> | |
813 | VE_SRC_LR_EDGE_DET_RT_SHF; | |
814 | video->frame_left = src_lr_edge & VE_SRC_LR_EDGE_DET_LEFT; | |
815 | det->hfrontporch = video->frame_left; | |
816 | det->hbackporch = (mds & VE_MODE_DETECT_H_PIXELS) - | |
817 | video->frame_right; | |
818 | det->hsync = sync & VE_SYNC_STATUS_HSYNC; | |
819 | if (video->frame_left > video->frame_right) | |
820 | continue; | |
821 | ||
822 | invalid_resolution = false; | |
823 | } while (invalid_resolution && (tries++ < INVALID_RESOLUTION_RETRIES)); | |
824 | ||
825 | if (invalid_resolution) { | |
826 | dev_err(video->dev, "Invalid resolution detected\n"); | |
827 | return; | |
828 | } | |
829 | ||
830 | det->height = (video->frame_bottom - video->frame_top) + 1; | |
831 | det->width = (video->frame_right - video->frame_left) + 1; | |
832 | video->v4l2_input_status = 0; | |
833 | ||
834 | /* | |
835 | * Enable mode-detect watchdog, resolution-change watchdog and | |
836 | * automatic compression after frame capture. | |
837 | */ | |
838 | aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, | |
839 | VE_INTERRUPT_MODE_DETECT_WD); | |
840 | aspeed_video_update(video, VE_SEQ_CTRL, 0, | |
841 | VE_SEQ_CTRL_AUTO_COMP | VE_SEQ_CTRL_EN_WATCHDOG); | |
842 | ||
843 | dev_dbg(video->dev, "Got resolution: %dx%d\n", det->width, | |
844 | det->height); | |
845 | } | |
846 | ||
847 | static void aspeed_video_set_resolution(struct aspeed_video *video) | |
848 | { | |
849 | struct v4l2_bt_timings *act = &video->active_timings; | |
850 | unsigned int size = act->width * act->height; | |
851 | ||
852 | aspeed_video_calc_compressed_size(video, size); | |
853 | ||
854 | /* Don't use direct mode below 1024 x 768 (irqs don't fire) */ | |
855 | if (size < DIRECT_FETCH_THRESHOLD) { | |
856 | aspeed_video_write(video, VE_TGS_0, | |
857 | FIELD_PREP(VE_TGS_FIRST, | |
858 | video->frame_left - 1) | | |
859 | FIELD_PREP(VE_TGS_LAST, | |
860 | video->frame_right)); | |
861 | aspeed_video_write(video, VE_TGS_1, | |
862 | FIELD_PREP(VE_TGS_FIRST, video->frame_top) | | |
863 | FIELD_PREP(VE_TGS_LAST, | |
864 | video->frame_bottom + 1)); | |
865 | aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_INT_DE); | |
866 | } else { | |
867 | aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH); | |
868 | } | |
869 | ||
870 | /* Set capture/compression frame sizes */ | |
871 | aspeed_video_write(video, VE_CAP_WINDOW, | |
872 | act->width << 16 | act->height); | |
873 | aspeed_video_write(video, VE_COMP_WINDOW, | |
874 | act->width << 16 | act->height); | |
875 | aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4); | |
876 | ||
877 | size *= 4; | |
878 | ||
879 | if (size == video->srcs[0].size / 2) { | |
880 | aspeed_video_write(video, VE_SRC1_ADDR, | |
881 | video->srcs[0].dma + size); | |
882 | } else if (size == video->srcs[0].size) { | |
883 | if (!aspeed_video_alloc_buf(video, &video->srcs[1], size)) | |
884 | goto err_mem; | |
885 | ||
886 | aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma); | |
887 | } else { | |
888 | aspeed_video_free_buf(video, &video->srcs[0]); | |
889 | ||
890 | if (!aspeed_video_alloc_buf(video, &video->srcs[0], size)) | |
891 | goto err_mem; | |
892 | ||
893 | if (!aspeed_video_alloc_buf(video, &video->srcs[1], size)) | |
894 | goto err_mem; | |
895 | ||
896 | aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma); | |
897 | aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma); | |
898 | } | |
899 | ||
900 | return; | |
901 | ||
902 | err_mem: | |
903 | dev_err(video->dev, "Failed to allocate source buffers\n"); | |
904 | ||
905 | if (video->srcs[0].size) | |
906 | aspeed_video_free_buf(video, &video->srcs[0]); | |
907 | } | |
908 | ||
909 | static void aspeed_video_init_regs(struct aspeed_video *video) | |
910 | { | |
911 | u32 comp_ctrl = VE_COMP_CTRL_RSVD | | |
912 | FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) | | |
913 | FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10); | |
914 | u32 ctrl = VE_CTRL_AUTO_OR_CURSOR; | |
915 | u32 seq_ctrl = VE_SEQ_CTRL_JPEG_MODE; | |
916 | ||
917 | if (video->frame_rate) | |
918 | ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate); | |
919 | ||
920 | if (video->yuv420) | |
921 | seq_ctrl |= VE_SEQ_CTRL_YUV420; | |
922 | ||
923 | /* Unlock VE registers */ | |
924 | aspeed_video_write(video, VE_PROTECTION_KEY, VE_PROTECTION_KEY_UNLOCK); | |
925 | ||
926 | /* Disable interrupts */ | |
927 | aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); | |
928 | aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); | |
929 | ||
930 | /* Clear the offset */ | |
931 | aspeed_video_write(video, VE_COMP_PROC_OFFSET, 0); | |
932 | aspeed_video_write(video, VE_COMP_OFFSET, 0); | |
933 | ||
934 | aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma); | |
935 | ||
936 | /* Set control registers */ | |
937 | aspeed_video_write(video, VE_SEQ_CTRL, seq_ctrl); | |
938 | aspeed_video_write(video, VE_CTRL, ctrl); | |
939 | aspeed_video_write(video, VE_COMP_CTRL, comp_ctrl); | |
940 | ||
941 | /* Don't downscale */ | |
942 | aspeed_video_write(video, VE_SCALING_FACTOR, 0x10001000); | |
943 | aspeed_video_write(video, VE_SCALING_FILTER0, 0x00200000); | |
944 | aspeed_video_write(video, VE_SCALING_FILTER1, 0x00200000); | |
945 | aspeed_video_write(video, VE_SCALING_FILTER2, 0x00200000); | |
946 | aspeed_video_write(video, VE_SCALING_FILTER3, 0x00200000); | |
947 | ||
948 | /* Set mode detection defaults */ | |
949 | aspeed_video_write(video, VE_MODE_DETECT, 0x22666500); | |
950 | } | |
951 | ||
952 | static void aspeed_video_start(struct aspeed_video *video) | |
953 | { | |
954 | aspeed_video_on(video); | |
955 | ||
956 | aspeed_video_init_regs(video); | |
957 | ||
958 | /* Resolution set to 640x480 if no signal found */ | |
959 | aspeed_video_get_resolution(video); | |
960 | ||
961 | /* Set timings since the device is being opened for the first time */ | |
962 | video->active_timings = video->detected_timings; | |
963 | aspeed_video_set_resolution(video); | |
964 | ||
965 | video->pix_fmt.width = video->active_timings.width; | |
966 | video->pix_fmt.height = video->active_timings.height; | |
967 | video->pix_fmt.sizeimage = video->max_compressed_size; | |
968 | } | |
969 | ||
970 | static void aspeed_video_stop(struct aspeed_video *video) | |
971 | { | |
972 | set_bit(VIDEO_STOPPED, &video->flags); | |
973 | cancel_delayed_work_sync(&video->res_work); | |
974 | ||
975 | aspeed_video_off(video); | |
976 | ||
977 | if (video->srcs[0].size) | |
978 | aspeed_video_free_buf(video, &video->srcs[0]); | |
979 | ||
980 | if (video->srcs[1].size) | |
981 | aspeed_video_free_buf(video, &video->srcs[1]); | |
982 | ||
983 | video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; | |
984 | video->flags = 0; | |
985 | } | |
986 | ||
987 | static int aspeed_video_querycap(struct file *file, void *fh, | |
988 | struct v4l2_capability *cap) | |
989 | { | |
990 | strscpy(cap->driver, DEVICE_NAME, sizeof(cap->driver)); | |
991 | strscpy(cap->card, "Aspeed Video Engine", sizeof(cap->card)); | |
992 | snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", | |
993 | DEVICE_NAME); | |
994 | ||
995 | return 0; | |
996 | } | |
997 | ||
998 | static int aspeed_video_enum_format(struct file *file, void *fh, | |
999 | struct v4l2_fmtdesc *f) | |
1000 | { | |
1001 | if (f->index) | |
1002 | return -EINVAL; | |
1003 | ||
1004 | f->pixelformat = V4L2_PIX_FMT_JPEG; | |
1005 | ||
1006 | return 0; | |
1007 | } | |
1008 | ||
1009 | static int aspeed_video_get_format(struct file *file, void *fh, | |
1010 | struct v4l2_format *f) | |
1011 | { | |
1012 | struct aspeed_video *video = video_drvdata(file); | |
1013 | ||
1014 | f->fmt.pix = video->pix_fmt; | |
1015 | ||
1016 | return 0; | |
1017 | } | |
1018 | ||
1019 | static int aspeed_video_enum_input(struct file *file, void *fh, | |
1020 | struct v4l2_input *inp) | |
1021 | { | |
1022 | struct aspeed_video *video = video_drvdata(file); | |
1023 | ||
1024 | if (inp->index) | |
1025 | return -EINVAL; | |
1026 | ||
1027 | strscpy(inp->name, "Host VGA capture", sizeof(inp->name)); | |
1028 | inp->type = V4L2_INPUT_TYPE_CAMERA; | |
1029 | inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; | |
1030 | inp->status = video->v4l2_input_status; | |
1031 | ||
1032 | return 0; | |
1033 | } | |
1034 | ||
1035 | static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i) | |
1036 | { | |
1037 | *i = 0; | |
1038 | ||
1039 | return 0; | |
1040 | } | |
1041 | ||
1042 | static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i) | |
1043 | { | |
1044 | if (i) | |
1045 | return -EINVAL; | |
1046 | ||
1047 | return 0; | |
1048 | } | |
1049 | ||
1050 | static int aspeed_video_get_parm(struct file *file, void *fh, | |
1051 | struct v4l2_streamparm *a) | |
1052 | { | |
1053 | struct aspeed_video *video = video_drvdata(file); | |
1054 | ||
1055 | a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; | |
1056 | a->parm.capture.readbuffers = 3; | |
1057 | a->parm.capture.timeperframe.numerator = 1; | |
1058 | if (!video->frame_rate) | |
1059 | a->parm.capture.timeperframe.denominator = MAX_FRAME_RATE; | |
1060 | else | |
1061 | a->parm.capture.timeperframe.denominator = video->frame_rate; | |
1062 | ||
1063 | return 0; | |
1064 | } | |
1065 | ||
1066 | static int aspeed_video_set_parm(struct file *file, void *fh, | |
1067 | struct v4l2_streamparm *a) | |
1068 | { | |
1069 | unsigned int frame_rate = 0; | |
1070 | struct aspeed_video *video = video_drvdata(file); | |
1071 | ||
1072 | a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; | |
1073 | a->parm.capture.readbuffers = 3; | |
1074 | ||
1075 | if (a->parm.capture.timeperframe.numerator) | |
1076 | frame_rate = a->parm.capture.timeperframe.denominator / | |
1077 | a->parm.capture.timeperframe.numerator; | |
1078 | ||
1079 | if (!frame_rate || frame_rate > MAX_FRAME_RATE) { | |
1080 | frame_rate = 0; | |
1081 | a->parm.capture.timeperframe.denominator = MAX_FRAME_RATE; | |
1082 | a->parm.capture.timeperframe.numerator = 1; | |
1083 | } | |
1084 | ||
1085 | if (video->frame_rate != frame_rate) { | |
1086 | video->frame_rate = frame_rate; | |
1087 | aspeed_video_update(video, VE_CTRL, VE_CTRL_FRC, | |
1088 | FIELD_PREP(VE_CTRL_FRC, frame_rate)); | |
1089 | } | |
1090 | ||
1091 | return 0; | |
1092 | } | |
1093 | ||
1094 | static int aspeed_video_enum_framesizes(struct file *file, void *fh, | |
1095 | struct v4l2_frmsizeenum *fsize) | |
1096 | { | |
1097 | struct aspeed_video *video = video_drvdata(file); | |
1098 | ||
1099 | if (fsize->index) | |
1100 | return -EINVAL; | |
1101 | ||
1102 | if (fsize->pixel_format != V4L2_PIX_FMT_JPEG) | |
1103 | return -EINVAL; | |
1104 | ||
1105 | fsize->discrete.width = video->pix_fmt.width; | |
1106 | fsize->discrete.height = video->pix_fmt.height; | |
1107 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | |
1108 | ||
1109 | return 0; | |
1110 | } | |
1111 | ||
1112 | static int aspeed_video_enum_frameintervals(struct file *file, void *fh, | |
1113 | struct v4l2_frmivalenum *fival) | |
1114 | { | |
1115 | struct aspeed_video *video = video_drvdata(file); | |
1116 | ||
1117 | if (fival->index) | |
1118 | return -EINVAL; | |
1119 | ||
1120 | if (fival->width != video->detected_timings.width || | |
1121 | fival->height != video->detected_timings.height) | |
1122 | return -EINVAL; | |
1123 | ||
1124 | if (fival->pixel_format != V4L2_PIX_FMT_JPEG) | |
1125 | return -EINVAL; | |
1126 | ||
1127 | fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS; | |
1128 | ||
1129 | fival->stepwise.min.denominator = MAX_FRAME_RATE; | |
1130 | fival->stepwise.min.numerator = 1; | |
1131 | fival->stepwise.max.denominator = 1; | |
1132 | fival->stepwise.max.numerator = 1; | |
1133 | fival->stepwise.step = fival->stepwise.max; | |
1134 | ||
1135 | return 0; | |
1136 | } | |
1137 | ||
1138 | static int aspeed_video_set_dv_timings(struct file *file, void *fh, | |
1139 | struct v4l2_dv_timings *timings) | |
1140 | { | |
1141 | struct aspeed_video *video = video_drvdata(file); | |
1142 | ||
1143 | if (timings->bt.width == video->active_timings.width && | |
1144 | timings->bt.height == video->active_timings.height) | |
1145 | return 0; | |
1146 | ||
1147 | if (vb2_is_busy(&video->queue)) | |
1148 | return -EBUSY; | |
1149 | ||
1150 | video->active_timings = timings->bt; | |
1151 | ||
1152 | aspeed_video_set_resolution(video); | |
1153 | ||
1154 | video->pix_fmt.width = timings->bt.width; | |
1155 | video->pix_fmt.height = timings->bt.height; | |
1156 | video->pix_fmt.sizeimage = video->max_compressed_size; | |
1157 | ||
1158 | timings->type = V4L2_DV_BT_656_1120; | |
1159 | ||
1160 | return 0; | |
1161 | } | |
1162 | ||
1163 | static int aspeed_video_get_dv_timings(struct file *file, void *fh, | |
1164 | struct v4l2_dv_timings *timings) | |
1165 | { | |
1166 | struct aspeed_video *video = video_drvdata(file); | |
1167 | ||
1168 | timings->type = V4L2_DV_BT_656_1120; | |
1169 | timings->bt = video->active_timings; | |
1170 | ||
1171 | return 0; | |
1172 | } | |
1173 | ||
1174 | static int aspeed_video_query_dv_timings(struct file *file, void *fh, | |
1175 | struct v4l2_dv_timings *timings) | |
1176 | { | |
1177 | int rc; | |
1178 | struct aspeed_video *video = video_drvdata(file); | |
1179 | ||
1180 | /* | |
1181 | * This blocks only if the driver is currently in the process of | |
1182 | * detecting a new resolution; in the event of no signal or timeout | |
1183 | * this function is woken up. | |
1184 | */ | |
1185 | if (file->f_flags & O_NONBLOCK) { | |
1186 | if (test_bit(VIDEO_RES_CHANGE, &video->flags)) | |
1187 | return -EAGAIN; | |
1188 | } else { | |
1189 | rc = wait_event_interruptible(video->wait, | |
1190 | !test_bit(VIDEO_RES_CHANGE, | |
1191 | &video->flags)); | |
1192 | if (rc) | |
1193 | return -EINTR; | |
1194 | } | |
1195 | ||
1196 | timings->type = V4L2_DV_BT_656_1120; | |
1197 | timings->bt = video->detected_timings; | |
1198 | ||
1199 | return video->v4l2_input_status ? -ENOLINK : 0; | |
1200 | } | |
1201 | ||
1202 | static int aspeed_video_enum_dv_timings(struct file *file, void *fh, | |
1203 | struct v4l2_enum_dv_timings *timings) | |
1204 | { | |
1205 | return v4l2_enum_dv_timings_cap(timings, &aspeed_video_timings_cap, | |
1206 | NULL, NULL); | |
1207 | } | |
1208 | ||
1209 | static int aspeed_video_dv_timings_cap(struct file *file, void *fh, | |
1210 | struct v4l2_dv_timings_cap *cap) | |
1211 | { | |
1212 | *cap = aspeed_video_timings_cap; | |
1213 | ||
1214 | return 0; | |
1215 | } | |
1216 | ||
1217 | static int aspeed_video_sub_event(struct v4l2_fh *fh, | |
1218 | const struct v4l2_event_subscription *sub) | |
1219 | { | |
1220 | switch (sub->type) { | |
1221 | case V4L2_EVENT_SOURCE_CHANGE: | |
1222 | return v4l2_src_change_event_subscribe(fh, sub); | |
1223 | } | |
1224 | ||
1225 | return v4l2_ctrl_subscribe_event(fh, sub); | |
1226 | } | |
1227 | ||
1228 | static const struct v4l2_ioctl_ops aspeed_video_ioctl_ops = { | |
1229 | .vidioc_querycap = aspeed_video_querycap, | |
1230 | ||
1231 | .vidioc_enum_fmt_vid_cap = aspeed_video_enum_format, | |
1232 | .vidioc_g_fmt_vid_cap = aspeed_video_get_format, | |
1233 | .vidioc_s_fmt_vid_cap = aspeed_video_get_format, | |
1234 | .vidioc_try_fmt_vid_cap = aspeed_video_get_format, | |
1235 | ||
1236 | .vidioc_reqbufs = vb2_ioctl_reqbufs, | |
1237 | .vidioc_querybuf = vb2_ioctl_querybuf, | |
1238 | .vidioc_qbuf = vb2_ioctl_qbuf, | |
1239 | .vidioc_expbuf = vb2_ioctl_expbuf, | |
1240 | .vidioc_dqbuf = vb2_ioctl_dqbuf, | |
1241 | .vidioc_create_bufs = vb2_ioctl_create_bufs, | |
1242 | .vidioc_prepare_buf = vb2_ioctl_prepare_buf, | |
1243 | .vidioc_streamon = vb2_ioctl_streamon, | |
1244 | .vidioc_streamoff = vb2_ioctl_streamoff, | |
1245 | ||
1246 | .vidioc_enum_input = aspeed_video_enum_input, | |
1247 | .vidioc_g_input = aspeed_video_get_input, | |
1248 | .vidioc_s_input = aspeed_video_set_input, | |
1249 | ||
1250 | .vidioc_g_parm = aspeed_video_get_parm, | |
1251 | .vidioc_s_parm = aspeed_video_set_parm, | |
1252 | .vidioc_enum_framesizes = aspeed_video_enum_framesizes, | |
1253 | .vidioc_enum_frameintervals = aspeed_video_enum_frameintervals, | |
1254 | ||
1255 | .vidioc_s_dv_timings = aspeed_video_set_dv_timings, | |
1256 | .vidioc_g_dv_timings = aspeed_video_get_dv_timings, | |
1257 | .vidioc_query_dv_timings = aspeed_video_query_dv_timings, | |
1258 | .vidioc_enum_dv_timings = aspeed_video_enum_dv_timings, | |
1259 | .vidioc_dv_timings_cap = aspeed_video_dv_timings_cap, | |
1260 | ||
1261 | .vidioc_subscribe_event = aspeed_video_sub_event, | |
1262 | .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | |
1263 | }; | |
1264 | ||
1265 | static void aspeed_video_update_jpeg_quality(struct aspeed_video *video) | |
1266 | { | |
1267 | u32 comp_ctrl = FIELD_PREP(VE_COMP_CTRL_DCT_LUM, video->jpeg_quality) | | |
1268 | FIELD_PREP(VE_COMP_CTRL_DCT_CHR, video->jpeg_quality | 0x10); | |
1269 | ||
1270 | aspeed_video_update(video, VE_COMP_CTRL, | |
1271 | VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR, | |
1272 | comp_ctrl); | |
1273 | } | |
1274 | ||
1275 | static void aspeed_video_update_subsampling(struct aspeed_video *video) | |
1276 | { | |
1277 | if (video->jpeg.virt) | |
1278 | aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); | |
1279 | ||
1280 | if (video->yuv420) | |
1281 | aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_YUV420); | |
1282 | else | |
1283 | aspeed_video_update(video, VE_SEQ_CTRL, VE_SEQ_CTRL_YUV420, 0); | |
1284 | } | |
1285 | ||
1286 | static int aspeed_video_set_ctrl(struct v4l2_ctrl *ctrl) | |
1287 | { | |
1288 | struct aspeed_video *video = container_of(ctrl->handler, | |
1289 | struct aspeed_video, | |
1290 | ctrl_handler); | |
1291 | ||
1292 | switch (ctrl->id) { | |
1293 | case V4L2_CID_JPEG_COMPRESSION_QUALITY: | |
1294 | video->jpeg_quality = ctrl->val; | |
1295 | aspeed_video_update_jpeg_quality(video); | |
1296 | break; | |
1297 | case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: | |
1298 | if (ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_420) { | |
1299 | video->yuv420 = true; | |
1300 | aspeed_video_update_subsampling(video); | |
1301 | } else { | |
1302 | video->yuv420 = false; | |
1303 | aspeed_video_update_subsampling(video); | |
1304 | } | |
1305 | break; | |
1306 | default: | |
1307 | return -EINVAL; | |
1308 | } | |
1309 | ||
1310 | return 0; | |
1311 | } | |
1312 | ||
1313 | static const struct v4l2_ctrl_ops aspeed_video_ctrl_ops = { | |
1314 | .s_ctrl = aspeed_video_set_ctrl, | |
1315 | }; | |
1316 | ||
1317 | static void aspeed_video_resolution_work(struct work_struct *work) | |
1318 | { | |
1319 | struct delayed_work *dwork = to_delayed_work(work); | |
1320 | struct aspeed_video *video = container_of(dwork, struct aspeed_video, | |
1321 | res_work); | |
1322 | u32 input_status = video->v4l2_input_status; | |
1323 | ||
1324 | aspeed_video_on(video); | |
1325 | ||
1326 | /* Exit early in case no clients remain */ | |
1327 | if (test_bit(VIDEO_STOPPED, &video->flags)) | |
1328 | goto done; | |
1329 | ||
1330 | aspeed_video_init_regs(video); | |
1331 | ||
1332 | aspeed_video_get_resolution(video); | |
1333 | ||
1334 | if (video->detected_timings.width != video->active_timings.width || | |
1335 | video->detected_timings.height != video->active_timings.height || | |
1336 | input_status != video->v4l2_input_status) { | |
1337 | static const struct v4l2_event ev = { | |
1338 | .type = V4L2_EVENT_SOURCE_CHANGE, | |
1339 | .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, | |
1340 | }; | |
1341 | ||
1342 | v4l2_event_queue(&video->vdev, &ev); | |
1343 | } else if (test_bit(VIDEO_STREAMING, &video->flags)) { | |
1344 | /* No resolution change so just restart streaming */ | |
1345 | aspeed_video_start_frame(video); | |
1346 | } | |
1347 | ||
1348 | done: | |
1349 | clear_bit(VIDEO_RES_CHANGE, &video->flags); | |
1350 | wake_up_interruptible_all(&video->wait); | |
1351 | } | |
1352 | ||
1353 | static int aspeed_video_open(struct file *file) | |
1354 | { | |
1355 | int rc; | |
1356 | struct aspeed_video *video = video_drvdata(file); | |
1357 | ||
1358 | mutex_lock(&video->video_lock); | |
1359 | ||
1360 | rc = v4l2_fh_open(file); | |
1361 | if (rc) { | |
1362 | mutex_unlock(&video->video_lock); | |
1363 | return rc; | |
1364 | } | |
1365 | ||
1366 | if (v4l2_fh_is_singular_file(file)) | |
1367 | aspeed_video_start(video); | |
1368 | ||
1369 | mutex_unlock(&video->video_lock); | |
1370 | ||
1371 | return 0; | |
1372 | } | |
1373 | ||
1374 | static int aspeed_video_release(struct file *file) | |
1375 | { | |
1376 | int rc; | |
1377 | struct aspeed_video *video = video_drvdata(file); | |
1378 | ||
1379 | mutex_lock(&video->video_lock); | |
1380 | ||
1381 | if (v4l2_fh_is_singular_file(file)) | |
1382 | aspeed_video_stop(video); | |
1383 | ||
1384 | rc = _vb2_fop_release(file, NULL); | |
1385 | ||
1386 | mutex_unlock(&video->video_lock); | |
1387 | ||
1388 | return rc; | |
1389 | } | |
1390 | ||
1391 | static const struct v4l2_file_operations aspeed_video_v4l2_fops = { | |
1392 | .owner = THIS_MODULE, | |
1393 | .read = vb2_fop_read, | |
1394 | .poll = vb2_fop_poll, | |
1395 | .unlocked_ioctl = video_ioctl2, | |
1396 | .mmap = vb2_fop_mmap, | |
1397 | .open = aspeed_video_open, | |
1398 | .release = aspeed_video_release, | |
1399 | }; | |
1400 | ||
1401 | static int aspeed_video_queue_setup(struct vb2_queue *q, | |
1402 | unsigned int *num_buffers, | |
1403 | unsigned int *num_planes, | |
1404 | unsigned int sizes[], | |
1405 | struct device *alloc_devs[]) | |
1406 | { | |
1407 | struct aspeed_video *video = vb2_get_drv_priv(q); | |
1408 | ||
1409 | if (*num_planes) { | |
1410 | if (sizes[0] < video->max_compressed_size) | |
1411 | return -EINVAL; | |
1412 | ||
1413 | return 0; | |
1414 | } | |
1415 | ||
1416 | *num_planes = 1; | |
1417 | sizes[0] = video->max_compressed_size; | |
1418 | ||
1419 | return 0; | |
1420 | } | |
1421 | ||
1422 | static int aspeed_video_buf_prepare(struct vb2_buffer *vb) | |
1423 | { | |
1424 | struct aspeed_video *video = vb2_get_drv_priv(vb->vb2_queue); | |
1425 | ||
1426 | if (vb2_plane_size(vb, 0) < video->max_compressed_size) | |
1427 | return -EINVAL; | |
1428 | ||
1429 | return 0; | |
1430 | } | |
1431 | ||
1432 | static int aspeed_video_start_streaming(struct vb2_queue *q, | |
1433 | unsigned int count) | |
1434 | { | |
1435 | int rc; | |
1436 | struct aspeed_video *video = vb2_get_drv_priv(q); | |
1437 | ||
1438 | video->sequence = 0; | |
1439 | ||
1440 | rc = aspeed_video_start_frame(video); | |
1441 | if (rc) { | |
1442 | aspeed_video_bufs_done(video, VB2_BUF_STATE_QUEUED); | |
1443 | return rc; | |
1444 | } | |
1445 | ||
1446 | set_bit(VIDEO_STREAMING, &video->flags); | |
1447 | return 0; | |
1448 | } | |
1449 | ||
1450 | static void aspeed_video_stop_streaming(struct vb2_queue *q) | |
1451 | { | |
1452 | int rc; | |
1453 | struct aspeed_video *video = vb2_get_drv_priv(q); | |
1454 | ||
1455 | clear_bit(VIDEO_STREAMING, &video->flags); | |
1456 | ||
1457 | rc = wait_event_timeout(video->wait, | |
1458 | !test_bit(VIDEO_FRAME_INPRG, &video->flags), | |
1459 | STOP_TIMEOUT); | |
1460 | if (!rc) { | |
1461 | dev_err(video->dev, "Timed out when stopping streaming\n"); | |
1462 | ||
1463 | /* | |
1464 | * Need to force stop any DMA and try and get HW into a good | |
1465 | * state for future calls to start streaming again. | |
1466 | */ | |
1467 | aspeed_video_reset(video); | |
1468 | aspeed_video_init_regs(video); | |
1469 | ||
1470 | aspeed_video_get_resolution(video); | |
1471 | } | |
1472 | ||
1473 | aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR); | |
1474 | } | |
1475 | ||
1476 | static void aspeed_video_buf_queue(struct vb2_buffer *vb) | |
1477 | { | |
1478 | bool empty; | |
1479 | struct aspeed_video *video = vb2_get_drv_priv(vb->vb2_queue); | |
1480 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
1481 | struct aspeed_video_buffer *avb = to_aspeed_video_buffer(vbuf); | |
1482 | unsigned long flags; | |
1483 | ||
1484 | spin_lock_irqsave(&video->lock, flags); | |
1485 | empty = list_empty(&video->buffers); | |
1486 | list_add_tail(&avb->link, &video->buffers); | |
1487 | spin_unlock_irqrestore(&video->lock, flags); | |
1488 | ||
1489 | if (test_bit(VIDEO_STREAMING, &video->flags) && | |
1490 | !test_bit(VIDEO_FRAME_INPRG, &video->flags) && empty) | |
1491 | aspeed_video_start_frame(video); | |
1492 | } | |
1493 | ||
1494 | static const struct vb2_ops aspeed_video_vb2_ops = { | |
1495 | .queue_setup = aspeed_video_queue_setup, | |
1496 | .wait_prepare = vb2_ops_wait_prepare, | |
1497 | .wait_finish = vb2_ops_wait_finish, | |
1498 | .buf_prepare = aspeed_video_buf_prepare, | |
1499 | .start_streaming = aspeed_video_start_streaming, | |
1500 | .stop_streaming = aspeed_video_stop_streaming, | |
1501 | .buf_queue = aspeed_video_buf_queue, | |
1502 | }; | |
1503 | ||
1504 | static int aspeed_video_setup_video(struct aspeed_video *video) | |
1505 | { | |
1506 | const u64 mask = ~(BIT(V4L2_JPEG_CHROMA_SUBSAMPLING_444) | | |
1507 | BIT(V4L2_JPEG_CHROMA_SUBSAMPLING_420)); | |
1508 | struct v4l2_device *v4l2_dev = &video->v4l2_dev; | |
1509 | struct vb2_queue *vbq = &video->queue; | |
1510 | struct video_device *vdev = &video->vdev; | |
1511 | int rc; | |
1512 | ||
1513 | video->pix_fmt.pixelformat = V4L2_PIX_FMT_JPEG; | |
1514 | video->pix_fmt.field = V4L2_FIELD_NONE; | |
1515 | video->pix_fmt.colorspace = V4L2_COLORSPACE_SRGB; | |
1516 | video->pix_fmt.quantization = V4L2_QUANTIZATION_FULL_RANGE; | |
1517 | video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; | |
1518 | ||
1519 | rc = v4l2_device_register(video->dev, v4l2_dev); | |
1520 | if (rc) { | |
1521 | dev_err(video->dev, "Failed to register v4l2 device\n"); | |
1522 | return rc; | |
1523 | } | |
1524 | ||
1525 | v4l2_ctrl_handler_init(&video->ctrl_handler, 2); | |
1526 | v4l2_ctrl_new_std(&video->ctrl_handler, &aspeed_video_ctrl_ops, | |
1527 | V4L2_CID_JPEG_COMPRESSION_QUALITY, 0, | |
1528 | ASPEED_VIDEO_JPEG_NUM_QUALITIES - 1, 1, 0); | |
1529 | v4l2_ctrl_new_std_menu(&video->ctrl_handler, &aspeed_video_ctrl_ops, | |
1530 | V4L2_CID_JPEG_CHROMA_SUBSAMPLING, | |
1531 | V4L2_JPEG_CHROMA_SUBSAMPLING_420, mask, | |
1532 | V4L2_JPEG_CHROMA_SUBSAMPLING_444); | |
1533 | ||
1534 | if (video->ctrl_handler.error) { | |
1535 | v4l2_ctrl_handler_free(&video->ctrl_handler); | |
1536 | v4l2_device_unregister(v4l2_dev); | |
1537 | ||
1538 | dev_err(video->dev, "Failed to init controls: %d\n", | |
1539 | video->ctrl_handler.error); | |
1540 | return rc; | |
1541 | } | |
1542 | ||
1543 | v4l2_dev->ctrl_handler = &video->ctrl_handler; | |
1544 | ||
1545 | vbq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1546 | vbq->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; | |
1547 | vbq->dev = v4l2_dev->dev; | |
1548 | vbq->lock = &video->video_lock; | |
1549 | vbq->ops = &aspeed_video_vb2_ops; | |
1550 | vbq->mem_ops = &vb2_dma_contig_memops; | |
1551 | vbq->drv_priv = video; | |
1552 | vbq->buf_struct_size = sizeof(struct aspeed_video_buffer); | |
1553 | vbq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; | |
1554 | vbq->min_buffers_needed = 3; | |
1555 | ||
1556 | rc = vb2_queue_init(vbq); | |
1557 | if (rc) { | |
1558 | v4l2_ctrl_handler_free(&video->ctrl_handler); | |
1559 | v4l2_device_unregister(v4l2_dev); | |
1560 | ||
1561 | dev_err(video->dev, "Failed to init vb2 queue\n"); | |
1562 | return rc; | |
1563 | } | |
1564 | ||
1565 | vdev->queue = vbq; | |
1566 | vdev->fops = &aspeed_video_v4l2_fops; | |
1567 | vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | | |
1568 | V4L2_CAP_STREAMING; | |
1569 | vdev->v4l2_dev = v4l2_dev; | |
1570 | strscpy(vdev->name, DEVICE_NAME, sizeof(vdev->name)); | |
1571 | vdev->vfl_type = VFL_TYPE_GRABBER; | |
1572 | vdev->vfl_dir = VFL_DIR_RX; | |
1573 | vdev->release = video_device_release_empty; | |
1574 | vdev->ioctl_ops = &aspeed_video_ioctl_ops; | |
1575 | vdev->lock = &video->video_lock; | |
1576 | ||
1577 | video_set_drvdata(vdev, video); | |
1578 | rc = video_register_device(vdev, VFL_TYPE_GRABBER, 0); | |
1579 | if (rc) { | |
1580 | vb2_queue_release(vbq); | |
1581 | v4l2_ctrl_handler_free(&video->ctrl_handler); | |
1582 | v4l2_device_unregister(v4l2_dev); | |
1583 | ||
1584 | dev_err(video->dev, "Failed to register video device\n"); | |
1585 | return rc; | |
1586 | } | |
1587 | ||
1588 | return 0; | |
1589 | } | |
1590 | ||
1591 | static int aspeed_video_init(struct aspeed_video *video) | |
1592 | { | |
1593 | int irq; | |
1594 | int rc; | |
1595 | struct device *dev = video->dev; | |
1596 | ||
1597 | irq = irq_of_parse_and_map(dev->of_node, 0); | |
1598 | if (!irq) { | |
1599 | dev_err(dev, "Unable to find IRQ\n"); | |
1600 | return -ENODEV; | |
1601 | } | |
1602 | ||
1603 | rc = devm_request_irq(dev, irq, aspeed_video_irq, IRQF_SHARED, | |
1604 | DEVICE_NAME, video); | |
1605 | if (rc < 0) { | |
1606 | dev_err(dev, "Unable to request IRQ %d\n", irq); | |
1607 | return rc; | |
1608 | } | |
1609 | ||
1610 | video->eclk = devm_clk_get(dev, "eclk"); | |
1611 | if (IS_ERR(video->eclk)) { | |
1612 | dev_err(dev, "Unable to get ECLK\n"); | |
1613 | return PTR_ERR(video->eclk); | |
1614 | } | |
1615 | ||
1616 | video->vclk = devm_clk_get(dev, "vclk"); | |
1617 | if (IS_ERR(video->vclk)) { | |
1618 | dev_err(dev, "Unable to get VCLK\n"); | |
1619 | return PTR_ERR(video->vclk); | |
1620 | } | |
1621 | ||
1622 | video->rst = devm_reset_control_get_exclusive(dev, NULL); | |
1623 | if (IS_ERR(video->rst)) { | |
1624 | dev_err(dev, "Unable to get VE reset\n"); | |
1625 | return PTR_ERR(video->rst); | |
1626 | } | |
1627 | ||
1628 | rc = of_reserved_mem_device_init(dev); | |
1629 | if (rc) { | |
1630 | dev_err(dev, "Unable to reserve memory\n"); | |
1631 | return rc; | |
1632 | } | |
1633 | ||
1634 | rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); | |
1635 | if (rc) { | |
1636 | dev_err(dev, "Failed to set DMA mask\n"); | |
1637 | of_reserved_mem_device_release(dev); | |
1638 | return rc; | |
1639 | } | |
1640 | ||
1641 | if (!aspeed_video_alloc_buf(video, &video->jpeg, | |
1642 | VE_JPEG_HEADER_SIZE)) { | |
1643 | dev_err(dev, "Failed to allocate DMA for JPEG header\n"); | |
1644 | of_reserved_mem_device_release(dev); | |
1645 | return rc; | |
1646 | } | |
1647 | ||
1648 | aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); | |
1649 | ||
1650 | return 0; | |
1651 | } | |
1652 | ||
1653 | static int aspeed_video_probe(struct platform_device *pdev) | |
1654 | { | |
1655 | int rc; | |
1656 | struct resource *res; | |
1657 | struct aspeed_video *video = kzalloc(sizeof(*video), GFP_KERNEL); | |
1658 | ||
1659 | if (!video) | |
1660 | return -ENOMEM; | |
1661 | ||
1662 | video->frame_rate = 30; | |
1663 | video->dev = &pdev->dev; | |
07758747 | 1664 | spin_lock_init(&video->lock); |
d2b4387f EJ |
1665 | mutex_init(&video->video_lock); |
1666 | init_waitqueue_head(&video->wait); | |
1667 | INIT_DELAYED_WORK(&video->res_work, aspeed_video_resolution_work); | |
1668 | INIT_LIST_HEAD(&video->buffers); | |
1669 | ||
1670 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
1671 | ||
1672 | video->base = devm_ioremap_resource(video->dev, res); | |
1673 | ||
1674 | if (IS_ERR(video->base)) | |
1675 | return PTR_ERR(video->base); | |
1676 | ||
1677 | rc = aspeed_video_init(video); | |
1678 | if (rc) | |
1679 | return rc; | |
1680 | ||
1681 | rc = aspeed_video_setup_video(video); | |
1682 | if (rc) | |
1683 | return rc; | |
1684 | ||
1685 | return 0; | |
1686 | } | |
1687 | ||
1688 | static int aspeed_video_remove(struct platform_device *pdev) | |
1689 | { | |
1690 | struct device *dev = &pdev->dev; | |
1691 | struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); | |
1692 | struct aspeed_video *video = to_aspeed_video(v4l2_dev); | |
1693 | ||
1694 | video_unregister_device(&video->vdev); | |
1695 | ||
1696 | vb2_queue_release(&video->queue); | |
1697 | ||
1698 | v4l2_ctrl_handler_free(&video->ctrl_handler); | |
1699 | ||
1700 | v4l2_device_unregister(v4l2_dev); | |
1701 | ||
1702 | dma_free_coherent(video->dev, VE_JPEG_HEADER_SIZE, video->jpeg.virt, | |
1703 | video->jpeg.dma); | |
1704 | ||
1705 | of_reserved_mem_device_release(dev); | |
1706 | ||
1707 | return 0; | |
1708 | } | |
1709 | ||
1710 | static const struct of_device_id aspeed_video_of_match[] = { | |
1711 | { .compatible = "aspeed,ast2400-video-engine" }, | |
1712 | { .compatible = "aspeed,ast2500-video-engine" }, | |
1713 | {} | |
1714 | }; | |
1715 | MODULE_DEVICE_TABLE(of, aspeed_video_of_match); | |
1716 | ||
1717 | static struct platform_driver aspeed_video_driver = { | |
1718 | .driver = { | |
1719 | .name = DEVICE_NAME, | |
1720 | .of_match_table = aspeed_video_of_match, | |
1721 | }, | |
1722 | .probe = aspeed_video_probe, | |
1723 | .remove = aspeed_video_remove, | |
1724 | }; | |
1725 | ||
1726 | module_platform_driver(aspeed_video_driver); | |
1727 | ||
1728 | MODULE_DESCRIPTION("ASPEED Video Engine Driver"); | |
1729 | MODULE_AUTHOR("Eddie James"); | |
1730 | MODULE_LICENSE("GPL v2"); |