Commit | Line | Data |
---|---|---|
9d200153 SM |
1 | /* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. |
2 | * | |
3 | * This program is free software; you can redistribute it and/or modify | |
4 | * it under the terms of the GNU General Public License version 2 and | |
5 | * only version 2 as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * GNU General Public License for more details. | |
11 | * | |
12 | * You should have received a copy of the GNU General Public License | |
13 | * along with this program; if not, write to the Free Software | |
14 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
15 | * 02110-1301, USA. | |
16 | */ | |
17 | ||
18 | #include <linux/module.h> | |
19 | #include <linux/kernel.h> | |
20 | #include <linux/sched.h> | |
21 | #include <linux/time.h> | |
22 | #include <linux/init.h> | |
23 | #include <linux/interrupt.h> | |
24 | #include <linux/spinlock.h> | |
25 | #include <linux/hrtimer.h> | |
26 | #include <linux/clk.h> | |
27 | #include <mach/hardware.h> | |
28 | #include <linux/io.h> | |
29 | #include <linux/debugfs.h> | |
30 | #include <linux/fb.h> | |
31 | #include <msm_mdp.h> | |
32 | #include <linux/file.h> | |
33 | #include "android_pmem.h" | |
34 | #include <linux/major.h> | |
35 | #include <asm/system.h> | |
36 | #include <asm/mach-types.h> | |
37 | #include <linux/semaphore.h> | |
38 | #include <linux/uaccess.h> | |
39 | #include <linux/mutex.h> | |
40 | ||
41 | #include "mdp.h" | |
42 | #include "msm_fb.h" | |
43 | #include "mdp4.h" | |
44 | ||
45 | ||
46 | struct mdp4_overlay_ctrl { | |
47 | struct mdp4_overlay_pipe plist[MDP4_MAX_OVERLAY_PIPE]; | |
48 | struct mdp4_overlay_pipe *stage[MDP4_MAX_MIXER][MDP4_MAX_STAGE]; | |
49 | } mdp4_overlay_db; | |
50 | ||
51 | static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db; | |
52 | ||
53 | ||
54 | void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc) | |
55 | { | |
56 | uint32 dma2_cfg_reg; | |
57 | ||
58 | dma2_cfg_reg = DMA_DITHER_EN; | |
59 | ||
60 | if (mfd->fb_imgType == MDP_BGR_565) | |
61 | dma2_cfg_reg |= DMA_PACK_PATTERN_BGR; | |
62 | else | |
63 | dma2_cfg_reg |= DMA_PACK_PATTERN_RGB; | |
64 | ||
65 | ||
66 | if (mfd->panel_info.bpp == 18) { | |
67 | dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */ | |
68 | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; | |
69 | } else if (mfd->panel_info.bpp == 16) { | |
70 | dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */ | |
71 | DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS; | |
72 | } else { | |
73 | dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */ | |
74 | DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS; | |
75 | } | |
76 | ||
77 | if (lcdc) | |
78 | dma2_cfg_reg |= DMA_PACK_ALIGN_MSB; | |
79 | ||
80 | /* dma2 config register */ | |
81 | MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg); | |
82 | ||
83 | } | |
84 | ||
85 | void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe) | |
86 | { | |
87 | ||
88 | /* dma_p source */ | |
89 | MDP_OUTP(MDP_BASE + 0x90004, | |
90 | (pipe->src_height << 16 | pipe->src_width)); | |
91 | MDP_OUTP(MDP_BASE + 0x90008, pipe->srcp0_addr); | |
92 | MDP_OUTP(MDP_BASE + 0x9000c, pipe->srcp0_ystride); | |
93 | ||
94 | /* dma_p dest */ | |
95 | MDP_OUTP(MDP_BASE + 0x90010, (pipe->dst_y << 16 | pipe->dst_x)); | |
96 | } | |
97 | ||
98 | #define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000 | |
99 | #define MDP4_VG_PHASE_STEP_SHIFT 29 | |
100 | ||
101 | static int mdp4_leading_0(uint32 num) | |
102 | { | |
103 | uint32 bit = 0x80000000; | |
104 | int i; | |
105 | ||
106 | for (i = 0; i < 32; i++) { | |
107 | if (bit & num) | |
108 | return i; | |
109 | bit >>= 1; | |
110 | } | |
111 | ||
112 | return i; | |
113 | } | |
114 | ||
115 | static uint32 mdp4_scale_phase_step(int f_num, uint32 src, uint32 dst) | |
116 | { | |
117 | uint32 val; | |
118 | int n; | |
119 | ||
120 | n = mdp4_leading_0(src); | |
121 | if (n > f_num) | |
122 | n = f_num; | |
123 | val = src << n; /* maximum to reduce lose of resolution */ | |
124 | val /= dst; | |
125 | if (n < f_num) { | |
126 | n = f_num - n; | |
127 | val <<= n; | |
128 | } | |
129 | ||
130 | return val; | |
131 | } | |
132 | ||
133 | static void mdp4_scale_setup(struct mdp4_overlay_pipe *pipe) | |
134 | { | |
135 | ||
136 | pipe->phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; | |
137 | pipe->phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; | |
138 | ||
139 | if (pipe->dst_h && pipe->src_h != pipe->dst_h) { | |
140 | if (pipe->dst_h >= pipe->src_h * 8) /* too much */ | |
141 | return; | |
142 | pipe->op_mode |= MDP4_OP_SCALEY_EN; | |
143 | ||
144 | if (pipe->pipe_type == OVERLAY_TYPE_VG) { | |
145 | if (pipe->dst_h <= (pipe->src_h / 4)) | |
146 | pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; | |
147 | else | |
148 | pipe->op_mode |= MDP4_OP_SCALEY_FIR; | |
149 | } | |
150 | ||
151 | pipe->phasey_step = mdp4_scale_phase_step(29, | |
152 | pipe->src_h, pipe->dst_h); | |
153 | } | |
154 | ||
155 | if (pipe->dst_w && pipe->src_w != pipe->dst_w) { | |
156 | if (pipe->dst_w >= pipe->src_w * 8) /* too much */ | |
157 | return; | |
158 | pipe->op_mode |= MDP4_OP_SCALEX_EN; | |
159 | ||
160 | if (pipe->pipe_type == OVERLAY_TYPE_VG) { | |
161 | if (pipe->dst_w <= (pipe->src_w / 4)) | |
162 | pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE; | |
163 | else | |
164 | pipe->op_mode |= MDP4_OP_SCALEY_FIR; | |
165 | } | |
166 | ||
167 | pipe->phasex_step = mdp4_scale_phase_step(29, | |
168 | pipe->src_w, pipe->dst_w); | |
169 | } | |
170 | } | |
171 | ||
172 | void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe) | |
173 | { | |
174 | char *rgb_base; | |
175 | uint32 src_size, src_xy, dst_size, dst_xy; | |
176 | uint32 format, pattern; | |
177 | ||
178 | rgb_base = MDP_BASE + MDP4_RGB_BASE; | |
179 | rgb_base += (MDP4_RGB_OFF * pipe->pipe_num); | |
180 | ||
181 | src_size = ((pipe->src_h << 16) | pipe->src_w); | |
182 | src_xy = ((pipe->src_y << 16) | pipe->src_x); | |
183 | dst_size = ((pipe->dst_h << 16) | pipe->dst_w); | |
184 | dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); | |
185 | ||
186 | format = mdp4_overlay_format(pipe); | |
187 | pattern = mdp4_overlay_unpack_pattern(pipe); | |
188 | ||
189 | pipe->op_mode |= MDP4_OP_IGC_LUT_EN; | |
190 | ||
191 | mdp4_scale_setup(pipe); | |
192 | ||
193 | outpdw(rgb_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ | |
194 | outpdw(rgb_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ | |
195 | outpdw(rgb_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ | |
196 | outpdw(rgb_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ | |
197 | ||
198 | outpdw(rgb_base + 0x0010, pipe->srcp0_addr); | |
199 | outpdw(rgb_base + 0x0040, pipe->srcp0_ystride); | |
200 | ||
201 | outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */ | |
202 | outpdw(rgb_base + 0x0054, pattern);/* MDP_RGB_SRC_UNPACK_PATTERN */ | |
203 | outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ | |
204 | outpdw(rgb_base + 0x005c, pipe->phasex_step); | |
205 | outpdw(rgb_base + 0x0060, pipe->phasey_step); | |
206 | ||
207 | /* 16 bytes-burst x 3 req <= 48 bytes */ | |
208 | outpdw(rgb_base + 0x1004, 0xc2); /* MDP_RGB_FETCH_CFG */ | |
209 | } | |
210 | ||
211 | void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe) | |
212 | { | |
213 | char *vg_base; | |
214 | uint32 frame_size, src_size, src_xy, dst_size, dst_xy; | |
215 | uint32 format, pattern; | |
216 | ||
217 | vg_base = MDP_BASE + MDP4_VIDEO_BASE; | |
218 | vg_base += (MDP4_VIDEO_OFF * pipe->pipe_num); | |
219 | ||
220 | frame_size = ((pipe->src_height << 16) | pipe->src_width); | |
221 | src_size = ((pipe->src_h << 16) | pipe->src_w); | |
222 | src_xy = ((pipe->src_y << 16) | pipe->src_x); | |
223 | dst_size = ((pipe->dst_h << 16) | pipe->dst_w); | |
224 | dst_xy = ((pipe->dst_y << 16) | pipe->dst_x); | |
225 | ||
226 | format = mdp4_overlay_format(pipe); | |
227 | pattern = mdp4_overlay_unpack_pattern(pipe); | |
228 | ||
229 | pipe->op_mode |= (MDP4_OP_CSC_EN | MDP4_OP_SRC_DATA_YCBCR | | |
230 | MDP4_OP_IGC_LUT_EN); | |
231 | ||
232 | mdp4_scale_setup(pipe); | |
233 | ||
234 | outpdw(vg_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */ | |
235 | outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */ | |
236 | outpdw(vg_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */ | |
237 | outpdw(vg_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */ | |
238 | outpdw(vg_base + 0x0048, frame_size); /* TILE frame size */ | |
239 | ||
240 | /* luma component plane */ | |
241 | outpdw(vg_base + 0x0010, pipe->srcp0_addr); | |
242 | ||
243 | /* chroma component plane */ | |
244 | outpdw(vg_base + 0x0014, pipe->srcp1_addr); | |
245 | ||
246 | outpdw(vg_base + 0x0040, | |
247 | pipe->srcp1_ystride << 16 | pipe->srcp0_ystride); | |
248 | ||
249 | outpdw(vg_base + 0x0050, format); /* MDP_RGB_SRC_FORMAT */ | |
250 | outpdw(vg_base + 0x0054, pattern); /* MDP_RGB_SRC_UNPACK_PATTERN */ | |
251 | outpdw(vg_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */ | |
252 | outpdw(vg_base + 0x005c, pipe->phasex_step); | |
253 | outpdw(vg_base + 0x0060, pipe->phasey_step); | |
254 | ||
255 | if (pipe->op_mode & MDP4_OP_DITHER_EN) { | |
256 | outpdw(vg_base + 0x0068, | |
257 | pipe->r_bit << 4 | pipe->b_bit << 2 | pipe->g_bit); | |
258 | } | |
259 | ||
260 | /* 16 bytes-burst x 3 req <= 48 bytes */ | |
261 | outpdw(vg_base + 0x1004, 0xc2); /* MDP_VG_FETCH_CFG */ | |
262 | } | |
263 | ||
264 | int mdp4_overlay_format2type(uint32 format) | |
265 | { | |
266 | switch (format) { | |
267 | case MDP_RGB_565: | |
268 | case MDP_RGB_888: | |
269 | case MDP_BGR_565: | |
270 | case MDP_ARGB_8888: | |
271 | case MDP_RGBA_8888: | |
272 | case MDP_BGRA_8888: | |
273 | return OVERLAY_TYPE_RGB; | |
274 | case MDP_YCRYCB_H2V1: | |
275 | case MDP_Y_CRCB_H2V1: | |
276 | case MDP_Y_CBCR_H2V1: | |
277 | case MDP_Y_CRCB_H2V2: | |
278 | case MDP_Y_CBCR_H2V2: | |
279 | case MDP_Y_CBCR_H2V2_TILE: | |
280 | case MDP_Y_CRCB_H2V2_TILE: | |
281 | return OVERLAY_TYPE_VG; | |
282 | default: | |
283 | return -ERANGE; | |
284 | } | |
285 | ||
286 | } | |
287 | ||
288 | #define C3_ALPHA 3 /* alpha */ | |
289 | #define C2_R_Cr 2 /* R/Cr */ | |
290 | #define C1_B_Cb 1 /* B/Cb */ | |
291 | #define C0_G_Y 0 /* G/luma */ | |
292 | ||
293 | int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe) | |
294 | { | |
295 | switch (pipe->src_format) { | |
296 | case MDP_RGB_565: | |
297 | pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; | |
298 | pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; | |
299 | pipe->a_bit = 0; | |
300 | pipe->r_bit = 1; /* R, 5 bits */ | |
301 | pipe->b_bit = 1; /* B, 5 bits */ | |
302 | pipe->g_bit = 2; /* G, 6 bits */ | |
303 | pipe->alpha_enable = 0; | |
304 | pipe->unpack_tight = 1; | |
305 | pipe->unpack_align_msb = 0; | |
306 | pipe->unpack_count = 2; | |
307 | pipe->element2 = C2_R_Cr; /* R */ | |
308 | pipe->element1 = C0_G_Y; /* G */ | |
309 | pipe->element0 = C1_B_Cb; /* B */ | |
310 | pipe->bpp = 2; /* 2 bpp */ | |
311 | break; | |
312 | case MDP_RGB_888: | |
313 | pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; | |
314 | pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; | |
315 | pipe->a_bit = 0; | |
316 | pipe->r_bit = 3; /* R, 8 bits */ | |
317 | pipe->b_bit = 3; /* B, 8 bits */ | |
318 | pipe->g_bit = 3; /* G, 8 bits */ | |
319 | pipe->alpha_enable = 0; | |
320 | pipe->unpack_tight = 1; | |
321 | pipe->unpack_align_msb = 0; | |
322 | pipe->unpack_count = 2; | |
323 | pipe->element2 = C2_R_Cr; /* R */ | |
324 | pipe->element1 = C0_G_Y; /* G */ | |
325 | pipe->element0 = C1_B_Cb; /* B */ | |
326 | pipe->bpp = 3; /* 3 bpp */ | |
327 | break; | |
328 | case MDP_BGR_565: | |
329 | pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; | |
330 | pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; | |
331 | pipe->a_bit = 0; | |
332 | pipe->r_bit = 1; /* R, 5 bits */ | |
333 | pipe->b_bit = 1; /* B, 5 bits */ | |
334 | pipe->g_bit = 2; /* G, 6 bits */ | |
335 | pipe->alpha_enable = 0; | |
336 | pipe->unpack_tight = 1; | |
337 | pipe->unpack_align_msb = 0; | |
338 | pipe->unpack_count = 2; | |
339 | pipe->element2 = C1_B_Cb; /* B */ | |
340 | pipe->element1 = C0_G_Y; /* G */ | |
341 | pipe->element0 = C2_R_Cr; /* R */ | |
342 | pipe->bpp = 2; /* 2 bpp */ | |
343 | break; | |
344 | case MDP_ARGB_8888: | |
345 | pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; | |
346 | pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; | |
347 | pipe->a_bit = 3; /* alpha, 4 bits */ | |
348 | pipe->r_bit = 3; /* R, 8 bits */ | |
349 | pipe->b_bit = 3; /* B, 8 bits */ | |
350 | pipe->g_bit = 3; /* G, 8 bits */ | |
351 | pipe->alpha_enable = 1; | |
352 | pipe->unpack_tight = 1; | |
353 | pipe->unpack_align_msb = 0; | |
354 | pipe->unpack_count = 3; | |
355 | pipe->element3 = C3_ALPHA; /* alpha */ | |
356 | pipe->element2 = C2_R_Cr; /* R */ | |
357 | pipe->element1 = C0_G_Y; /* G */ | |
358 | pipe->element0 = C1_B_Cb; /* B */ | |
359 | pipe->bpp = 4; /* 4 bpp */ | |
360 | break; | |
361 | case MDP_RGBA_8888: | |
362 | pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; | |
363 | pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; | |
364 | pipe->a_bit = 3; /* alpha, 4 bits */ | |
365 | pipe->r_bit = 3; /* R, 8 bits */ | |
366 | pipe->b_bit = 3; /* B, 8 bits */ | |
367 | pipe->g_bit = 3; /* G, 8 bits */ | |
368 | pipe->alpha_enable = 1; | |
369 | pipe->unpack_tight = 1; | |
370 | pipe->unpack_align_msb = 0; | |
371 | pipe->unpack_count = 3; | |
372 | pipe->element3 = C2_R_Cr; /* R */ | |
373 | pipe->element2 = C0_G_Y; /* G */ | |
374 | pipe->element1 = C1_B_Cb; /* B */ | |
375 | pipe->element0 = C3_ALPHA; /* alpha */ | |
376 | pipe->bpp = 4; /* 4 bpp */ | |
377 | break; | |
378 | case MDP_BGRA_8888: | |
379 | pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; | |
380 | pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; | |
381 | pipe->a_bit = 3; /* alpha, 4 bits */ | |
382 | pipe->r_bit = 3; /* R, 8 bits */ | |
383 | pipe->b_bit = 3; /* B, 8 bits */ | |
384 | pipe->g_bit = 3; /* G, 8 bits */ | |
385 | pipe->alpha_enable = 1; | |
386 | pipe->unpack_tight = 1; | |
387 | pipe->unpack_align_msb = 0; | |
388 | pipe->unpack_count = 3; | |
389 | pipe->element3 = C1_B_Cb; /* B */ | |
390 | pipe->element2 = C0_G_Y; /* G */ | |
391 | pipe->element1 = C2_R_Cr; /* R */ | |
392 | pipe->element0 = C3_ALPHA; /* alpha */ | |
393 | pipe->bpp = 4; /* 4 bpp */ | |
394 | break; | |
395 | case MDP_YCRYCB_H2V1: | |
396 | pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; | |
397 | pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED; | |
398 | pipe->a_bit = 0; /* alpha, 4 bits */ | |
399 | pipe->r_bit = 3; /* R, 8 bits */ | |
400 | pipe->b_bit = 3; /* B, 8 bits */ | |
401 | pipe->g_bit = 3; /* G, 8 bits */ | |
402 | pipe->alpha_enable = 0; | |
403 | pipe->unpack_tight = 1; | |
404 | pipe->unpack_align_msb = 0; | |
405 | pipe->unpack_count = 3; | |
406 | pipe->element3 = C0_G_Y; /* G */ | |
407 | pipe->element2 = C2_R_Cr; /* R */ | |
408 | pipe->element1 = C0_G_Y; /* G */ | |
409 | pipe->element0 = C1_B_Cb; /* B */ | |
410 | pipe->bpp = 2; /* 2 bpp */ | |
411 | pipe->chroma_sample = MDP4_CHROMA_H2V1; | |
412 | break; | |
413 | case MDP_Y_CRCB_H2V1: | |
414 | case MDP_Y_CBCR_H2V1: | |
415 | case MDP_Y_CRCB_H2V2: | |
416 | case MDP_Y_CBCR_H2V2: | |
417 | pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR; | |
418 | pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; | |
419 | pipe->a_bit = 0; | |
420 | pipe->r_bit = 3; /* R, 8 bits */ | |
421 | pipe->b_bit = 3; /* B, 8 bits */ | |
422 | pipe->g_bit = 3; /* G, 8 bits */ | |
423 | pipe->alpha_enable = 0; | |
424 | pipe->unpack_tight = 1; | |
425 | pipe->unpack_align_msb = 0; | |
426 | pipe->unpack_count = 1; /* 2 */ | |
427 | pipe->element3 = C0_G_Y; /* not used */ | |
428 | pipe->element2 = C0_G_Y; /* not used */ | |
429 | if (pipe->src_format == MDP_Y_CRCB_H2V1) { | |
430 | pipe->element1 = C2_R_Cr; /* R */ | |
431 | pipe->element0 = C1_B_Cb; /* B */ | |
432 | pipe->chroma_sample = MDP4_CHROMA_H2V1; | |
433 | } else if (pipe->src_format == MDP_Y_CBCR_H2V1) { | |
434 | pipe->element1 = C1_B_Cb; /* B */ | |
435 | pipe->element0 = C2_R_Cr; /* R */ | |
436 | pipe->chroma_sample = MDP4_CHROMA_H2V1; | |
437 | } else if (pipe->src_format == MDP_Y_CRCB_H2V2) { | |
438 | pipe->element1 = C2_R_Cr; /* R */ | |
439 | pipe->element0 = C1_B_Cb; /* B */ | |
440 | pipe->chroma_sample = MDP4_CHROMA_420; | |
441 | } else if (pipe->src_format == MDP_Y_CBCR_H2V2) { | |
442 | pipe->element1 = C1_B_Cb; /* B */ | |
443 | pipe->element0 = C2_R_Cr; /* R */ | |
444 | pipe->chroma_sample = MDP4_CHROMA_420; | |
445 | } | |
446 | pipe->bpp = 2; /* 2 bpp */ | |
447 | break; | |
448 | case MDP_Y_CBCR_H2V2_TILE: | |
449 | case MDP_Y_CRCB_H2V2_TILE: | |
450 | pipe->frame_format = MDP4_FRAME_FORMAT_VIDEO_SUPERTILE; | |
451 | pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR; | |
452 | pipe->a_bit = 0; | |
453 | pipe->r_bit = 3; /* R, 8 bits */ | |
454 | pipe->b_bit = 3; /* B, 8 bits */ | |
455 | pipe->g_bit = 3; /* G, 8 bits */ | |
456 | pipe->alpha_enable = 0; | |
457 | pipe->unpack_tight = 1; | |
458 | pipe->unpack_align_msb = 0; | |
459 | pipe->unpack_count = 1; /* 2 */ | |
460 | pipe->element3 = C0_G_Y; /* not used */ | |
461 | pipe->element2 = C0_G_Y; /* not used */ | |
462 | if (pipe->src_format == MDP_Y_CRCB_H2V2_TILE) { | |
463 | pipe->element1 = C2_R_Cr; /* R */ | |
464 | pipe->element0 = C1_B_Cb; /* B */ | |
465 | pipe->chroma_sample = MDP4_CHROMA_420; | |
466 | } else if (pipe->src_format == MDP_Y_CBCR_H2V2_TILE) { | |
467 | pipe->element1 = C1_B_Cb; /* B */ | |
468 | pipe->element0 = C2_R_Cr; /* R */ | |
469 | pipe->chroma_sample = MDP4_CHROMA_420; | |
470 | } | |
471 | pipe->bpp = 2; /* 2 bpp */ | |
472 | break; | |
473 | default: | |
474 | /* not likely */ | |
475 | return -ERANGE; | |
476 | } | |
477 | ||
478 | return 0; | |
479 | } | |
480 | ||
481 | /* | |
482 | * color_key_convert: output with 12 bits color key | |
483 | */ | |
484 | static uint32 color_key_convert(int start, int num, uint32 color) | |
485 | { | |
486 | ||
487 | uint32 data; | |
488 | ||
489 | data = (color >> start) & ((1 << num) - 1); | |
490 | ||
491 | if (num == 5) | |
492 | data = (data << 7) + (data << 2) + (data >> 3); | |
493 | else if (num == 6) | |
494 | data = (data << 6) + data; | |
495 | else /* 8 bits */ | |
496 | data = (data << 4) + (data >> 4); | |
497 | ||
498 | return data; | |
499 | ||
500 | } | |
501 | ||
502 | void transp_color_key(int format, uint32 transp, | |
503 | uint32 *c0, uint32 *c1, uint32 *c2) | |
504 | { | |
505 | int b_start, g_start, r_start; | |
506 | int b_num, g_num, r_num; | |
507 | ||
508 | switch (format) { | |
509 | case MDP_RGB_565: | |
510 | b_start = 0; | |
511 | g_start = 5; | |
512 | r_start = 11; | |
513 | r_num = 5; | |
514 | g_num = 6; | |
515 | b_num = 5; | |
516 | break; | |
517 | case MDP_RGB_888: | |
518 | case MDP_XRGB_8888: | |
519 | case MDP_ARGB_8888: | |
520 | b_start = 0; | |
521 | g_start = 8; | |
522 | r_start = 16; | |
523 | r_num = 8; | |
524 | g_num = 8; | |
525 | b_num = 8; | |
526 | break; | |
527 | case MDP_BGR_565: | |
528 | b_start = 11; | |
529 | g_start = 5; | |
530 | r_start = 0; | |
531 | r_num = 5; | |
532 | g_num = 6; | |
533 | b_num = 5; | |
534 | break; | |
535 | case MDP_Y_CBCR_H2V2: | |
536 | case MDP_Y_CBCR_H2V1: | |
537 | b_start = 8; | |
538 | g_start = 16; | |
539 | r_start = 0; | |
540 | r_num = 8; | |
541 | g_num = 8; | |
542 | b_num = 8; | |
543 | break; | |
544 | case MDP_Y_CRCB_H2V2: | |
545 | case MDP_Y_CRCB_H2V1: | |
546 | b_start = 0; | |
547 | g_start = 16; | |
548 | r_start = 8; | |
549 | r_num = 8; | |
550 | g_num = 8; | |
551 | b_num = 8; | |
552 | break; | |
553 | default: | |
554 | b_start = 0; | |
555 | g_start = 8; | |
556 | r_start = 16; | |
557 | r_num = 8; | |
558 | g_num = 8; | |
559 | b_num = 8; | |
560 | break; | |
561 | } | |
562 | ||
563 | *c0 = color_key_convert(g_start, g_num, transp); | |
564 | *c1 = color_key_convert(b_start, b_num, transp); | |
565 | *c2 = color_key_convert(r_start, r_num, transp); | |
566 | } | |
567 | ||
568 | uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe) | |
569 | { | |
570 | uint32 format; | |
571 | ||
572 | format = 0; | |
573 | ||
574 | if (pipe->solid_fill) | |
575 | format |= MDP4_FORMAT_SOLID_FILL; | |
576 | ||
577 | if (pipe->unpack_align_msb) | |
578 | format |= MDP4_FORMAT_UNPACK_ALIGN_MSB; | |
579 | ||
580 | if (pipe->unpack_tight) | |
581 | format |= MDP4_FORMAT_UNPACK_TIGHT; | |
582 | ||
583 | if (pipe->alpha_enable) | |
584 | format |= MDP4_FORMAT_ALPHA_ENABLE; | |
585 | ||
586 | format |= (pipe->unpack_count << 13); | |
587 | format |= ((pipe->bpp - 1) << 9); | |
588 | format |= (pipe->a_bit << 6); | |
589 | format |= (pipe->r_bit << 4); | |
590 | format |= (pipe->b_bit << 2); | |
591 | format |= pipe->g_bit; | |
592 | ||
593 | format |= (pipe->frame_format << 29); | |
594 | ||
595 | if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { | |
596 | /* video/graphic */ | |
597 | format |= (pipe->fetch_plane << 19); | |
598 | format |= (pipe->chroma_site << 28); | |
599 | format |= (pipe->chroma_sample << 26); | |
600 | } | |
601 | ||
602 | return format; | |
603 | } | |
604 | ||
605 | uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe) | |
606 | { | |
607 | return (pipe->element3 << 24) | (pipe->element2 << 16) | | |
608 | (pipe->element1 << 8) | pipe->element0; | |
609 | } | |
610 | ||
611 | void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe) | |
612 | { | |
613 | uint32 data; | |
614 | char *overlay_base; | |
615 | ||
616 | if (pipe->mixer_num == MDP4_MIXER1) | |
617 | overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ | |
618 | else | |
619 | overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ | |
620 | ||
621 | /* MDP_OVERLAYPROC_CFG */ | |
622 | outpdw(overlay_base + 0x0004, 0x01); /* directout */ | |
623 | data = pipe->src_height; | |
624 | data <<= 16; | |
625 | data |= pipe->src_width; | |
626 | outpdw(overlay_base + 0x0008, data); /* ROI, height + width */ | |
627 | outpdw(overlay_base + 0x000c, pipe->srcp0_addr); | |
628 | outpdw(overlay_base + 0x0010, pipe->srcp0_ystride); | |
629 | outpdw(overlay_base + 0x0014, 0x4); /* GC_LUT_EN, 888 */ | |
630 | } | |
631 | ||
632 | int mdp4_overlay_active(int mixer) | |
633 | { | |
634 | uint32 data, mask, i; | |
635 | int p1, p2; | |
636 | ||
637 | data = inpdw(MDP_BASE + 0x10100); | |
638 | p1 = 0; | |
639 | p2 = 0; | |
640 | for (i = 0; i < 8; i++) { | |
641 | mask = data & 0x0f; | |
642 | if (mask) { | |
643 | if (mask <= 4) | |
644 | p1++; | |
645 | else | |
646 | p2++; | |
647 | } | |
648 | data >>= 4; | |
649 | } | |
650 | ||
651 | if (mixer) | |
652 | return p2; | |
653 | else | |
654 | return p1; | |
655 | } | |
656 | ||
657 | void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe) | |
658 | { | |
659 | uint32 data, mask, snum, stage, mixer; | |
660 | ||
661 | stage = pipe->mixer_stage; | |
662 | mixer = pipe->mixer_num; | |
663 | ||
664 | /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */ | |
665 | data = inpdw(MDP_BASE + 0x10100); | |
666 | ||
667 | if (mixer == MDP4_MIXER1) | |
668 | stage += 8; | |
669 | ||
670 | if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */ | |
671 | snum = 0; | |
672 | snum += (4 * pipe->pipe_num); | |
673 | } else { | |
674 | snum = 8; | |
675 | snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */ | |
676 | } | |
677 | ||
678 | mask = 0x0f; | |
679 | mask <<= snum; | |
680 | stage <<= snum; | |
681 | data &= ~mask; /* clear old bits */ | |
682 | ||
683 | data |= stage; | |
684 | ||
685 | outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */ | |
686 | ||
687 | data = inpdw(MDP_BASE + 0x10100); | |
688 | ||
689 | ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = pipe; /* keep it */ | |
690 | } | |
691 | ||
692 | void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe) | |
693 | { | |
694 | uint32 data, mask, snum, stage, mixer; | |
695 | ||
696 | stage = pipe->mixer_stage; | |
697 | mixer = pipe->mixer_num; | |
698 | ||
25985edc | 699 | if (pipe != ctrl->stage[mixer][stage]) /* not running */ |
9d200153 SM |
700 | return; |
701 | ||
702 | /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */ | |
703 | data = inpdw(MDP_BASE + 0x10100); | |
704 | ||
705 | if (mixer == MDP4_MIXER1) | |
706 | stage += 8; | |
707 | ||
708 | if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */ | |
709 | snum = 0; | |
710 | snum += (4 * pipe->pipe_num); | |
711 | } else { | |
712 | snum = 8; | |
713 | snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */ | |
714 | } | |
715 | ||
716 | mask = 0x0f; | |
717 | mask <<= snum; | |
718 | data &= ~mask; /* clear old bits */ | |
719 | ||
720 | outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */ | |
721 | ||
722 | data = inpdw(MDP_BASE + 0x10100); | |
723 | ||
724 | ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL; /* clear it */ | |
725 | } | |
726 | ||
727 | void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe) | |
728 | { | |
729 | unsigned char *overlay_base; | |
730 | uint32 c0, c1, c2, blend_op; | |
731 | int off; | |
732 | ||
733 | if (pipe->mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */ | |
734 | overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */ | |
735 | else | |
736 | overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */ | |
737 | ||
738 | /* stage 0 to stage 2 */ | |
739 | off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0); | |
740 | ||
741 | blend_op = 0; | |
742 | if (pipe->alpha_enable) /* ARGB */ | |
743 | blend_op = MDP4_BLEND_FG_ALPHA_FG_PIXEL | | |
744 | MDP4_BLEND_BG_ALPHA_FG_PIXEL; | |
745 | else | |
746 | blend_op = (MDP4_BLEND_BG_ALPHA_BG_CONST | | |
747 | MDP4_BLEND_FG_ALPHA_FG_CONST); | |
748 | ||
749 | ||
750 | if (pipe->alpha_enable == 0) { /* not ARGB */ | |
751 | if (pipe->is_fg) { | |
752 | outpdw(overlay_base + off + 0x108, pipe->alpha); | |
753 | outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha); | |
754 | } else { | |
755 | outpdw(overlay_base + off + 0x108, 0xff - pipe->alpha); | |
756 | outpdw(overlay_base + off + 0x10c, pipe->alpha); | |
757 | } | |
758 | } | |
759 | ||
760 | if (pipe->transp != MDP_TRANSP_NOP) { | |
761 | transp_color_key(pipe->src_format, pipe->transp, &c0, &c1, &c2); | |
762 | if (pipe->is_fg) { | |
763 | blend_op |= MDP4_BLEND_FG_TRANSP_EN; /* Fg blocked */ | |
764 | /* lower limit */ | |
765 | if (c0 > 0x10) | |
766 | c0 -= 0x10; | |
767 | if (c1 > 0x10) | |
768 | c1 -= 0x10; | |
769 | if (c2 > 0x10) | |
770 | c2 -= 0x10; | |
771 | outpdw(overlay_base + off + 0x110, | |
772 | (c1 << 16 | c0));/* low */ | |
773 | outpdw(overlay_base + off + 0x114, c2);/* low */ | |
774 | /* upper limit */ | |
775 | if ((c0 + 0x20) < 0x0fff) | |
776 | c0 += 0x20; | |
777 | else | |
778 | c0 = 0x0fff; | |
779 | if ((c1 + 0x20) < 0x0fff) | |
780 | c1 += 0x20; | |
781 | else | |
782 | c1 = 0x0fff; | |
783 | if ((c2 + 0x20) < 0x0fff) | |
784 | c2 += 0x20; | |
785 | else | |
786 | c2 = 0x0fff; | |
787 | outpdw(overlay_base + off + 0x118, | |
788 | (c1 << 16 | c0));/* high */ | |
789 | outpdw(overlay_base + off + 0x11c, c2);/* high */ | |
790 | } else { | |
791 | blend_op |= MDP4_BLEND_BG_TRANSP_EN; /* bg blocked */ | |
792 | /* lower limit */ | |
793 | if (c0 > 0x10) | |
794 | c0 -= 0x10; | |
795 | if (c1 > 0x10) | |
796 | c1 -= 0x10; | |
797 | if (c2 > 0x10) | |
798 | c2 -= 0x10; | |
799 | outpdw(overlay_base + 0x180, | |
800 | (c1 << 16 | c0));/* low */ | |
801 | outpdw(overlay_base + 0x184, c2);/* low */ | |
802 | /* upper limit */ | |
803 | if ((c0 + 0x20) < 0x0fff) | |
804 | c0 += 0x20; | |
805 | else | |
806 | c0 = 0x0fff; | |
807 | if ((c1 + 0x20) < 0x0fff) | |
808 | c1 += 0x20; | |
809 | else | |
810 | c1 = 0x0fff; | |
811 | if ((c2 + 0x20) < 0x0fff) | |
812 | c2 += 0x20; | |
813 | else | |
814 | c2 = 0x0fff; | |
815 | outpdw(overlay_base + 0x188, | |
816 | (c1 << 16 | c0));/* high */ | |
817 | outpdw(overlay_base + 0x18c, c2);/* high */ | |
818 | } | |
819 | } | |
820 | outpdw(overlay_base + off + 0x104, blend_op); | |
821 | } | |
822 | ||
823 | void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all) | |
824 | { | |
825 | uint32 bits = 0; | |
826 | ||
827 | if (pipe->mixer_num == MDP4_MIXER1) | |
828 | bits |= 0x02; | |
829 | else | |
830 | bits |= 0x01; | |
831 | ||
832 | if (all) { | |
833 | if (pipe->pipe_type == OVERLAY_TYPE_RGB) { | |
834 | if (pipe->pipe_num == OVERLAY_PIPE_RGB2) | |
835 | bits |= 0x20; | |
836 | else | |
837 | bits |= 0x10; | |
838 | } else { | |
839 | if (pipe->pipe_num == OVERLAY_PIPE_VG2) | |
840 | bits |= 0x08; | |
841 | else | |
842 | bits |= 0x04; | |
843 | } | |
844 | } | |
845 | ||
846 | outpdw(MDP_BASE + 0x18000, bits); /* MDP_OVERLAY_REG_FLUSH */ | |
847 | ||
848 | while (inpdw(MDP_BASE + 0x18000) & bits) /* self clear when complete */ | |
849 | ; | |
850 | } | |
851 | ||
852 | struct mdp4_overlay_pipe *mdp4_overlay_ndx2pipe(int ndx) | |
853 | { | |
854 | struct mdp4_overlay_pipe *pipe; | |
855 | ||
856 | if (ndx == 0 || ndx >= MDP4_MAX_OVERLAY_PIPE) | |
857 | return NULL; | |
858 | ||
859 | pipe = &ctrl->plist[ndx - 1]; /* ndx start from 1 */ | |
860 | ||
861 | if (pipe->pipe_ndx == 0) | |
862 | return NULL; | |
863 | ||
864 | return pipe; | |
865 | } | |
866 | ||
867 | struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void) | |
868 | { | |
869 | int i; | |
870 | struct mdp4_overlay_pipe *pipe; | |
871 | ||
872 | pipe = &ctrl->plist[0]; | |
873 | for (i = 0; i < MDP4_MAX_OVERLAY_PIPE; i++) { | |
874 | if (pipe->pipe_ndx == 0) { | |
875 | pipe->pipe_ndx = i + 1; /* start from 1 */ | |
876 | init_completion(&pipe->comp); | |
fb5206d9 KV |
877 | printk(KERN_INFO "mdp4_overlay_pipe_alloc: pipe=%p ndx=%d\n", |
878 | pipe, pipe->pipe_ndx); | |
9d200153 SM |
879 | return pipe; |
880 | } | |
881 | pipe++; | |
882 | } | |
883 | ||
884 | return NULL; | |
885 | } | |
886 | ||
887 | ||
888 | void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe) | |
889 | { | |
fb5206d9 KV |
890 | printk(KERN_INFO "mdp4_overlay_pipe_free: pipe=%p ndx=%d\n", |
891 | pipe, pipe->pipe_ndx); | |
9d200153 SM |
892 | memset(pipe, 0, sizeof(*pipe)); |
893 | } | |
894 | ||
895 | static int get_pipe_num(int ptype, int stage) | |
896 | { | |
897 | if (ptype == OVERLAY_TYPE_RGB) { | |
898 | if (stage == MDP4_MIXER_STAGE_BASE) | |
899 | return OVERLAY_PIPE_RGB1; | |
900 | else | |
901 | return OVERLAY_PIPE_RGB2; | |
902 | } else { | |
903 | if (stage == MDP4_MIXER_STAGE0) | |
904 | return OVERLAY_PIPE_VG1; | |
905 | else | |
906 | return OVERLAY_PIPE_VG2; | |
907 | } | |
908 | } | |
909 | ||
910 | int mdp4_overlay_req_check(uint32 id, uint32 z_order, uint32 mixer) | |
911 | { | |
912 | struct mdp4_overlay_pipe *pipe; | |
913 | ||
914 | pipe = ctrl->stage[mixer][z_order]; | |
915 | ||
916 | if (pipe == NULL) | |
917 | return 0; | |
918 | ||
919 | if (pipe->pipe_ndx == id) /* same req, recycle */ | |
920 | return 0; | |
921 | ||
922 | return -EPERM; | |
923 | } | |
924 | ||
925 | static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer, | |
926 | struct mdp4_overlay_pipe **ppipe) | |
927 | { | |
928 | struct mdp4_overlay_pipe *pipe; | |
929 | int ret, ptype; | |
930 | ||
931 | if (mixer >= MDP4_MAX_MIXER) { | |
932 | printk(KERN_ERR "mpd_overlay_req2pipe: mixer out of range!\n"); | |
933 | return -ERANGE; | |
934 | } | |
935 | ||
936 | if (req->z_order < 0 || req->z_order > 2) { | |
937 | printk(KERN_ERR "mpd_overlay_req2pipe: z_order=%d out of range!\n", | |
938 | req->z_order); | |
939 | return -ERANGE; | |
940 | } | |
941 | ||
942 | if (req->src_rect.h == 0 || req->src_rect.w == 0) { | |
943 | printk(KERN_ERR "mpd_overlay_req2pipe: src img of zero size!\n"); | |
944 | return -EINVAL; | |
945 | } | |
946 | ||
947 | ret = mdp4_overlay_req_check(req->id, req->z_order, mixer); | |
948 | if (ret < 0) | |
949 | return ret; | |
950 | ||
951 | ptype = mdp4_overlay_format2type(req->src.format); | |
952 | if (ptype < 0) | |
953 | return ptype; | |
954 | ||
955 | if (req->id == MSMFB_NEW_REQUEST) /* new request */ | |
956 | pipe = mdp4_overlay_pipe_alloc(); | |
957 | else | |
958 | pipe = mdp4_overlay_ndx2pipe(req->id); | |
959 | ||
960 | if (pipe == NULL) | |
961 | return -ENOMEM; | |
962 | ||
963 | pipe->src_format = req->src.format; | |
964 | ret = mdp4_overlay_format2pipe(pipe); | |
965 | ||
966 | if (ret < 0) | |
967 | return ret; | |
968 | ||
969 | /* | |
970 | * base layer == 1, reserved for frame buffer | |
971 | * zorder 0 == stage 0 == 2 | |
972 | * zorder 1 == stage 1 == 3 | |
973 | * zorder 2 == stage 2 == 4 | |
974 | */ | |
975 | if (req->id == MSMFB_NEW_REQUEST) { /* new request */ | |
976 | pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0; | |
977 | pipe->pipe_type = ptype; | |
978 | pipe->pipe_num = get_pipe_num(ptype, pipe->mixer_stage); | |
979 | printk(KERN_INFO "mpd4_overlay_req2pipe: zorder=%d pipe_num=%d\n", | |
980 | req->z_order, pipe->pipe_num); | |
981 | } | |
982 | ||
983 | pipe->src_width = req->src.width & 0x07ff; /* source img width */ | |
984 | pipe->src_height = req->src.height & 0x07ff; /* source img height */ | |
985 | pipe->src_h = req->src_rect.h & 0x07ff; | |
986 | pipe->src_w = req->src_rect.w & 0x07ff; | |
987 | pipe->src_y = req->src_rect.y & 0x07ff; | |
988 | pipe->src_x = req->src_rect.x & 0x07ff; | |
989 | pipe->dst_h = req->dst_rect.h & 0x07ff; | |
990 | pipe->dst_w = req->dst_rect.w & 0x07ff; | |
991 | pipe->dst_y = req->dst_rect.y & 0x07ff; | |
992 | pipe->dst_x = req->dst_rect.x & 0x07ff; | |
993 | ||
994 | if (req->flags & MDP_FLIP_LR) | |
995 | pipe->op_mode |= MDP4_OP_FLIP_LR; | |
996 | ||
997 | if (req->flags & MDP_FLIP_UD) | |
998 | pipe->op_mode |= MDP4_OP_FLIP_UD; | |
999 | ||
1000 | if (req->flags & MDP_DITHER) | |
1001 | pipe->op_mode |= MDP4_OP_DITHER_EN; | |
1002 | ||
1003 | if (req->flags & MDP_DEINTERLACE) | |
1004 | pipe->op_mode |= MDP4_OP_DEINT_ODD_REF; | |
1005 | ||
1006 | pipe->is_fg = req->is_fg;/* control alpha and color key */ | |
1007 | ||
1008 | pipe->alpha = req->alpha & 0x0ff; | |
1009 | ||
1010 | pipe->transp = req->transp_mask; | |
1011 | ||
1012 | *ppipe = pipe; | |
1013 | ||
1014 | return 0; | |
1015 | } | |
1016 | ||
1017 | int get_img(struct msmfb_data *img, struct fb_info *info, | |
1018 | unsigned long *start, unsigned long *len, struct file **pp_file) | |
1019 | { | |
1020 | int put_needed, ret = 0; | |
1021 | struct file *file; | |
1022 | #ifdef CONFIG_ANDROID_PMEM | |
1023 | unsigned long vstart; | |
1024 | #endif | |
1025 | ||
1026 | #ifdef CONFIG_ANDROID_PMEM | |
1027 | if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file)) | |
1028 | return 0; | |
1029 | #endif | |
1030 | file = fget_light(img->memory_id, &put_needed); | |
1031 | if (file == NULL) | |
1032 | return -1; | |
1033 | ||
1034 | if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { | |
1035 | *start = info->fix.smem_start; | |
1036 | *len = info->fix.smem_len; | |
1037 | *pp_file = file; | |
1038 | } else { | |
1039 | ret = -1; | |
1040 | fput_light(file, put_needed); | |
1041 | } | |
1042 | return ret; | |
1043 | } | |
1044 | int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req) | |
1045 | { | |
1046 | struct mdp4_overlay_pipe *pipe; | |
1047 | ||
1048 | pipe = mdp4_overlay_ndx2pipe(req->id); | |
1049 | if (pipe == NULL) | |
1050 | return -ENODEV; | |
1051 | ||
1052 | *req = pipe->req_data; | |
1053 | ||
1054 | return 0; | |
1055 | } | |
1056 | ||
1057 | int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req) | |
1058 | { | |
1059 | struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; | |
1060 | int ret, mixer; | |
1061 | struct mdp4_overlay_pipe *pipe; | |
1062 | int lcdc; | |
1063 | ||
1064 | if (mfd == NULL) | |
1065 | return -ENODEV; | |
1066 | ||
1067 | if (req->src.format == MDP_FB_FORMAT) | |
1068 | req->src.format = mfd->fb_imgType; | |
1069 | ||
1070 | if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) | |
1071 | return -EINTR; | |
1072 | ||
1073 | mixer = info->node; /* minor number of char device */ | |
1074 | ||
1075 | ret = mdp4_overlay_req2pipe(req, mixer, &pipe); | |
1076 | if (ret < 0) { | |
1077 | mutex_unlock(&mfd->dma->ov_mutex); | |
1078 | return ret; | |
1079 | } | |
1080 | ||
1081 | lcdc = inpdw(MDP_BASE + 0xc0000); | |
1082 | ||
1083 | if (lcdc == 0) { /* mddi */ | |
1084 | /* MDP cmd block enable */ | |
1085 | mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE); | |
1086 | } | |
1087 | ||
1088 | /* return id back to user */ | |
1089 | req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */ | |
1090 | pipe->req_data = *req; /* keep original req */ | |
1091 | ||
1092 | mutex_unlock(&mfd->dma->ov_mutex); | |
1093 | ||
1094 | return 0; | |
1095 | } | |
1096 | ||
1097 | int mdp4_overlay_unset(struct fb_info *info, int ndx) | |
1098 | { | |
1099 | struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; | |
1100 | struct mdp4_overlay_pipe *pipe; | |
1101 | int lcdc; | |
1102 | ||
1103 | if (mfd == NULL) | |
1104 | return -ENODEV; | |
1105 | ||
1106 | if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) | |
1107 | return -EINTR; | |
1108 | ||
1109 | pipe = mdp4_overlay_ndx2pipe(ndx); | |
1110 | ||
1111 | if (pipe == NULL) { | |
1112 | mutex_unlock(&mfd->dma->ov_mutex); | |
1113 | return -ENODEV; | |
1114 | } | |
1115 | ||
1116 | lcdc = inpdw(MDP_BASE + 0xc0000); | |
1117 | ||
1118 | mdp4_mixer_stage_down(pipe); | |
1119 | ||
1120 | if (lcdc == 0) { /* mddi */ | |
1121 | /* MDP cmd block disable */ | |
1122 | mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE); | |
1123 | } | |
1124 | ||
1125 | if (lcdc) /* LCDC mode */ | |
1126 | mdp4_overlay_reg_flush(pipe, 0); | |
1127 | ||
1128 | mdp4_overlay_pipe_free(pipe); | |
1129 | ||
1130 | if (lcdc == 0) { /* mddi */ | |
1131 | mdp4_mddi_overlay_restore(); | |
1132 | } | |
1133 | ||
1134 | mutex_unlock(&mfd->dma->ov_mutex); | |
1135 | ||
1136 | return 0; | |
1137 | } | |
1138 | ||
1139 | struct tile_desc { | |
1140 | uint32 width; /* tile's width */ | |
1141 | uint32 height; /* tile's height */ | |
1142 | uint32 row_tile_w; /* tiles per row's width */ | |
1143 | uint32 row_tile_h; /* tiles per row's height */ | |
1144 | }; | |
1145 | ||
1146 | void tile_samsung(struct tile_desc *tp) | |
1147 | { | |
1148 | /* | |
1149 | * each row of samsung tile consists of two tiles in height | |
1150 | * and two tiles in width which means width should align to | |
1151 | * 64 x 2 bytes and height should align to 32 x 2 bytes. | |
1152 | * video decoder generate two tiles in width and one tile | |
1153 | * in height which ends up height align to 32 X 1 bytes. | |
1154 | */ | |
1155 | tp->width = 64; /* 64 bytes */ | |
1156 | tp->row_tile_w = 2; /* 2 tiles per row's width */ | |
1157 | tp->height = 32; /* 32 bytes */ | |
1158 | tp->row_tile_h = 1; /* 1 tiles per row's height */ | |
1159 | } | |
1160 | ||
1161 | uint32 tile_mem_size(struct mdp4_overlay_pipe *pipe, struct tile_desc *tp) | |
1162 | { | |
1163 | uint32 tile_w, tile_h; | |
1164 | uint32 row_num_w, row_num_h; | |
1165 | ||
1166 | ||
1167 | tile_w = tp->width * tp->row_tile_w; | |
1168 | tile_h = tp->height * tp->row_tile_h; | |
1169 | ||
1170 | row_num_w = (pipe->src_width + tile_w - 1) / tile_w; | |
1171 | row_num_h = (pipe->src_height + tile_h - 1) / tile_h; | |
1172 | ||
1173 | return row_num_w * row_num_h * tile_w * tile_h; | |
1174 | } | |
1175 | ||
1176 | int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req, | |
1177 | struct file **pp_src_file) | |
1178 | { | |
1179 | struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; | |
1180 | struct msmfb_data *img; | |
1181 | struct mdp4_overlay_pipe *pipe; | |
1182 | ulong start, addr; | |
1183 | ulong len = 0; | |
1184 | struct file *p_src_file = 0; | |
1185 | int lcdc; | |
1186 | ||
1187 | if (mfd == NULL) | |
1188 | return -ENODEV; | |
1189 | ||
1190 | pipe = mdp4_overlay_ndx2pipe(req->id); | |
1191 | if (pipe == NULL) | |
1192 | return -ENODEV; | |
1193 | ||
1194 | if (mutex_lock_interruptible(&mfd->dma->ov_mutex)) | |
1195 | return -EINTR; | |
1196 | ||
1197 | img = &req->data; | |
1198 | get_img(img, info, &start, &len, &p_src_file); | |
1199 | if (len == 0) { | |
1200 | mutex_unlock(&mfd->dma->ov_mutex); | |
1201 | printk(KERN_ERR "mdp_overlay_play: could not retrieve" | |
1202 | " image from memory\n"); | |
1203 | return -1; | |
1204 | } | |
1205 | *pp_src_file = p_src_file; | |
1206 | ||
1207 | addr = start + img->offset; | |
1208 | pipe->srcp0_addr = addr; | |
1209 | pipe->srcp0_ystride = pipe->src_width * pipe->bpp; | |
1210 | ||
1211 | if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) { | |
1212 | if (pipe->frame_format == MDP4_FRAME_FORMAT_VIDEO_SUPERTILE) { | |
1213 | struct tile_desc tile; | |
1214 | ||
1215 | tile_samsung(&tile); | |
1216 | pipe->srcp1_addr = addr + tile_mem_size(pipe, &tile); | |
1217 | } else | |
1218 | pipe->srcp1_addr = addr + | |
1219 | pipe->src_width * pipe->src_height; | |
1220 | ||
1221 | pipe->srcp0_ystride = pipe->src_width; | |
1222 | pipe->srcp1_ystride = pipe->src_width; | |
1223 | } | |
1224 | ||
1225 | lcdc = inpdw(MDP_BASE + 0xc0000); | |
1226 | lcdc &= 0x01; /* LCDC mode */ | |
1227 | ||
1228 | if (pipe->pipe_type == OVERLAY_TYPE_VG) | |
1229 | mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */ | |
1230 | else | |
1231 | mdp4_overlay_rgb_setup(pipe); /* rgb pipe */ | |
1232 | ||
1233 | mdp4_mixer_blend_setup(pipe); | |
1234 | mdp4_mixer_stage_up(pipe); | |
1235 | ||
1236 | if (lcdc) { /* LCDC mode */ | |
1237 | mdp4_overlay_reg_flush(pipe, 1); | |
1238 | } | |
1239 | ||
1240 | if (lcdc) { /* LCDC mode */ | |
1241 | if (pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { /* done */ | |
1242 | mutex_unlock(&mfd->dma->ov_mutex); | |
1243 | return 0; | |
1244 | } | |
1245 | } | |
1246 | ||
1247 | if (lcdc == 0) { /* MDDI mode */ | |
1248 | #ifdef MDP4_NONBLOCKING | |
1249 | if (mfd->panel_power_on) | |
1250 | #else | |
1251 | if (!mfd->dma->busy && mfd->panel_power_on) | |
1252 | #endif | |
1253 | mdp4_mddi_overlay_kickoff(mfd, pipe); | |
1254 | } | |
1255 | ||
1256 | mutex_unlock(&mfd->dma->ov_mutex); | |
1257 | ||
1258 | return 0; | |
1259 | } |