Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(83)

Side by Side Diff: drivers/media/video/samsung/tv20/s5p_stda_grp.c

Issue 2036011: V4L/DVB : Add S5PV210 TV out driver support (Closed) Base URL: swsolcc@12.23.106.100:kernel-samsung.git
Patch Set: Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /* linux/drivers/media/video/samsung/tv20/s5p_stda_grp.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * S5PV210 - Graphic Layer ftn. file for Samsung TVOut driver
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/stddef.h>
16 #include <linux/ioctl.h>
17 #include <linux/dma-mapping.h>
18
19 #include <linux/io.h>
20 #include <linux/uaccess.h>
21
22 #include "s5p_tv.h"
23
24 #ifdef CONFIG_TVOUT_DBG
25 #define S5P_GRP_DEBUG 1
26 #endif
27
28 #ifdef S5P_GRP_DEBUG
29 #define GRPPRINTK(fmt, args...) \
30 printk(KERN_INFO "\t[STDA_GRP] %s: " fmt, __func__ , ## args)
31 #else
32 #define GRPPRINTK(fmt, args...)
33 #endif
34
35 bool tv_grp_start(enum s5p_tv_vmx_layer vm_layer)
36 {
37 enum s5p_tv_vmx_err merr;
38 struct s5p_tv_status *st = &s5ptv_status;
39
40 if (!(st->grp_layer_enable[0] || st->grp_layer_enable[1])) {
41
42 merr = tv_vm_init_status_reg(st->grp_burst,
43 st->grp_endian);
44
45 if (merr != VMIXER_NO_ERROR)
46 return false;
47 }
48
49 merr = tv_vm_init_layer(s5ptv_status.tvout_param.disp_mode,
50 vm_layer,
51 true,
52 s5ptv_overlay[vm_layer].win_blending,
53 s5ptv_overlay[vm_layer].win.global_alpha,
54 s5ptv_overlay[vm_layer].priority,
55 s5ptv_overlay[vm_layer].fb.fmt.pixelformat,
56 s5ptv_overlay[vm_layer].blank_change,
57 s5ptv_overlay[vm_layer].pixel_blending,
58 s5ptv_overlay[vm_layer].pre_mul,
59 s5ptv_overlay[vm_layer].blank_color,
60 s5ptv_overlay[vm_layer].base_addr,
61 s5ptv_overlay[vm_layer].fb.fmt.bytesperline,
62 s5ptv_overlay[vm_layer].win.w.width,
63 s5ptv_overlay[vm_layer].win.w.height,
64 s5ptv_overlay[vm_layer].win.w.left,
65 s5ptv_overlay[vm_layer].win.w.top,
66 s5ptv_overlay[vm_layer].dst_rect.left,
67 s5ptv_overlay[vm_layer].dst_rect.top,
68 s5ptv_overlay[vm_layer].dst_rect.width,
69 s5ptv_overlay[vm_layer].dst_rect.height);
70
71 if (merr != VMIXER_NO_ERROR) {
72 GRPPRINTK("can't initialize layer(%d)\n\r", merr);
73 return false;
74 }
75
76 tv_vm_start();
77
78
79 st->grp_layer_enable[vm_layer] = true;
80
81 GRPPRINTK("()\n\r");
82
83 return true;
84 }
85
86 bool tv_grp_stop(enum s5p_tv_vmx_layer vm_layer)
87 {
88 enum s5p_tv_vmx_err merr;
89 struct s5p_tv_status *st = &s5ptv_status;
90
91 GRPPRINTK("()\n\r");
92
93 merr = tv_vm_set_layer_show(vm_layer, false);
94
95 if (merr != VMIXER_NO_ERROR)
96 return false;
97
98 merr = tv_vm_set_layer_priority(vm_layer, 0);
99
100 if (merr != VMIXER_NO_ERROR)
101 return false;
102
103 tv_vm_start();
104
105
106 st->grp_layer_enable[vm_layer] = false;
107
108 GRPPRINTK("()\n\r");
109
110 return true;
111 }
112
113 int s5ptvfb_set_output(struct s5p_tv_status *ctrl) { return 0; }
114
115 int s5ptvfb_set_display_mode(struct s5p_tv_status *ctrl)
116 {
117 enum s5p_tv_vmx_layer layer = VM_GPR0_LAYER;
118 bool premul = false;
119 bool pixel_blending = false;
120 bool blank_change = false;
121 bool win_blending = false;
122 u32 blank_color = 0x0;
123 enum s5p_tv_vmx_color_fmt color;
124 u32 bpp;
125 u32 alpha = 0;
126
127 bpp = ((struct fb_var_screeninfo)(ctrl->fb->var)).bits_per_pixel;
128
129 if (bpp == 32)
130 color = VM_DIRECT_RGB8888;
131 else
132 color = VM_DIRECT_RGB565;
133
134 tv_vm_set_ctrl(layer, premul, pixel_blending, blank_change,
135 win_blending, color, alpha, blank_color);
136
137 return 0;
138 }
139
140 int s5ptvfb_display_on(struct s5p_tv_status *ctrl)
141 {
142 tv_vm_set_layer_priority(VM_GPR0_LAYER, 10);
143 tv_vm_set_layer_show(VM_GPR0_LAYER, true);
144
145 return 0;
146 }
147
148 int s5ptvfb_display_off(struct s5p_tv_status *ctrl)
149 {
150 tv_vm_set_layer_priority(VM_GPR0_LAYER, 10);
151 tv_vm_set_layer_show(VM_GPR0_LAYER, false);
152
153 return 0;
154 }
155
156 int s5ptvfb_frame_off(struct s5p_tv_status *ctrl) { return 0; }
157 int s5ptvfb_set_clock(struct s5p_tv_status *ctrl) { return 0; }
158 int s5ptvfb_set_polarity(struct s5p_tv_status *ctrl) { return 0; }
159 int s5ptvfb_set_timing(struct s5p_tv_status *ctrl) { return 0; }
160 int s5ptvfb_set_lcd_size(struct s5p_tv_status *ctrl) { return 0; }
161 int s5ptvfb_window_on(struct s5p_tv_status *ctrl, int id)
162 {
163 tv_vm_set_layer_show(VM_GPR0_LAYER, true);
164
165 return 0;
166 }
167
168 int s5ptvfb_window_off(struct s5p_tv_status *ctrl, int id)
169 {
170 tv_vm_set_layer_show(VM_GPR0_LAYER, false);
171 return 0;
172 }
173
174 int s5ptvfb_set_window_control(struct s5p_tv_status *ctrl, int id) { return 0; }
175 int s5ptvfb_set_alpha_blending(struct s5p_tv_status *ctrl, int id) { return 0; }
176 int s5ptvfb_set_window_position(struct s5p_tv_status *ctrl, int id)
177 {
178 u32 off_x, off_y;
179 u32 w_t, h_t;
180 u32 w, h;
181
182 struct fb_var_screeninfo *var = &ctrl->fb->var;
183 struct s5ptvfb_window *win = ctrl->fb->par;
184
185 off_x = (u32)win->x;
186 off_y = (u32)win->y;
187
188 w = var->xres;
189 h = var->yres;
190
191 /*
192 * When tvout resolution was overscanned, there is no
193 * adjust method in H/W. So, framebuffer should be resized.
194 * In this case - TV w/h is greater than FB w/h, grp layer's
195 * dst offset must be changed to fix tv screen.
196 */
197
198 switch (ctrl->tvout_param.disp_mode) {
199
200 case TVOUT_NTSC_M:
201 case TVOUT_480P_60_16_9:
202 case TVOUT_480P_60_4_3:
203 case TVOUT_480P_59:
204 w_t = 720;
205 h_t = 480;
206 break;
207
208 case TVOUT_576P_50_16_9:
209 case TVOUT_576P_50_4_3:
210 w_t = 720;
211 h_t = 576;
212 break;
213
214 case TVOUT_720P_60:
215 case TVOUT_720P_59:
216 case TVOUT_720P_50:
217 w_t = 1280;
218 h_t = 720;
219 break;
220
221 case TVOUT_1080I_60:
222 case TVOUT_1080I_59:
223 case TVOUT_1080I_50:
224 case TVOUT_1080P_60:
225 case TVOUT_1080P_59:
226 case TVOUT_1080P_50:
227 case TVOUT_1080P_30:
228 w_t = 1920;
229 h_t = 1080;
230 break;
231
232 default:
233 w_t = 0;
234 h_t = 0;
235 break;
236 }
237
238 if (w_t > w)
239 off_x = (w_t - w) / 2;
240
241 if (h_t > h)
242 off_y = (h_t - h) / 2;
243
244 tv_vm_set_grp_layer_position(VM_GPR0_LAYER, off_x, off_y);
245
246 return 0;
247 }
248
249 int s5ptvfb_set_window_size(struct s5p_tv_status *ctrl, int id)
250 {
251 struct fb_var_screeninfo *var = &ctrl->fb->var;
252 int w, h, xo, yo;
253
254 w = var->xres;
255 h = var->yres;
256 xo = var->xoffset;
257 yo = var->yoffset;
258
259 tv_vm_set_grp_layer_size(VM_GPR0_LAYER, w, w, h, xo, yo);
260
261
262 dev_dbg(ctrl->dev_fb, "[fb%d] resolution: %d x %d\n", id,
263 var->xres, var->yres);
264
265 return 0;
266 }
267
268 int s5ptvfb_set_buffer_address(struct s5p_tv_status *ctrl, int id)
269 {
270 struct fb_fix_screeninfo *fix = &ctrl->fb->fix;
271 struct fb_var_screeninfo *var = &ctrl->fb->var;
272 dma_addr_t start_addr = 0, end_addr = 0;
273
274 if (fix->smem_start) {
275 start_addr = fix->smem_start + (var->xres_virtual *
276 (var->bits_per_pixel / 8) * var->yoffset);
277
278 end_addr = start_addr + (var->xres_virtual *
279 (var->bits_per_pixel / 8) * var->yres);
280 }
281
282 tv_vm_set_grp_base_address(VM_GPR0_LAYER, start_addr);
283 return 0;
284 }
285
286 int s5ptvfb_set_buffer_size(struct s5p_tv_status *ctrl, int id) { return 0; }
287
288 int s5ptvfb_set_chroma_key(struct s5p_tv_status *ctrl, int id)
289 {
290 struct s5ptvfb_window *win = ctrl->fb->par;
291 struct s5ptvfb_chroma *chroma = &win->chroma;
292
293 enum s5p_tv_vmx_layer layer = VM_GPR0_LAYER;
294
295 bool blank_change = (chroma->enabled) ? true : false;
296 u32 blank_color = chroma->key;
297
298 bool win_blending = (chroma->blended) ? true : false;
299 bool alpha = chroma->alpha;
300
301 enum s5p_tv_vmx_color_fmt color = VM_DIRECT_RGB8888;
302
303 tv_vm_set_ctrl(layer, false, false, blank_change,
304 win_blending, color, alpha, blank_color);
305
306 return 0;
307 }
308
309 int s5ptvfb_wait_for_vsync(void)
310 {
311 sleep_on_timeout(&s5ptv_wq, HZ / 10);
312 return 0;
313 }
314
315 static inline unsigned int chan_to_field(unsigned int chan,
316 struct fb_bitfield bf)
317 {
318 chan &= 0xffff;
319 chan >>= 16 - bf.length;
320
321 return chan << bf.offset;
322 }
323
324 static int s5ptvfb_set_alpha_info(struct fb_var_screeninfo *var,
325 struct s5ptvfb_window *win)
326 {
327 if (var->transp.length > 0)
328 win->alpha.mode = PIXEL_BLENDING;
329 else {
330 win->alpha.mode = PLANE_BLENDING;
331 win->alpha.channel = 0;
332 win->alpha.value = S5PTVFB_AVALUE(0xf, 0xf, 0xf);
333 }
334
335 return 0;
336 }
337
338
339 static int s5ptvfb_enable_window(int id)
340 {
341 struct s5ptvfb_window *win = s5ptv_status.fb->par;
342
343 if (s5ptvfb_window_on(&s5ptv_status, id)) {
344 win->enabled = 0;
345 return -EFAULT;
346 } else {
347 win->enabled = 1;
348 return 0;
349 }
350 }
351
352
353 static int s5ptvfb_disable_window(int id)
354 {
355 struct s5ptvfb_window *win = s5ptv_status.fb->par;
356
357 if (s5ptvfb_window_off(&s5ptv_status, id)) {
358 win->enabled = 1;
359 return -EFAULT;
360 } else {
361 win->enabled = 0;
362 return 0;
363 }
364 }
365
366 int s5ptvfb_unmap_video_memory(struct fb_info *fb)
367 {
368 struct fb_fix_screeninfo *fix = &fb->fix;
369 struct s5ptvfb_window *win = fb->par;
370
371 if (fix->smem_start) {
372 dma_free_writecombine(s5ptv_status.dev_fb, fix->smem_len,
373 fb->screen_base, fix->smem_start);
374 fix->smem_start = 0;
375 fix->smem_len = 0;
376 dev_info(s5ptv_status.dev_fb,
377 "[fb%d] video memory released\n", win->id);
378 }
379
380 return 0;
381 }
382
383 static int s5ptvfb_release_window(struct fb_info *fb)
384 {
385 struct s5ptvfb_window *win = fb->par;
386
387 win->x = 0;
388 win->y = 0;
389
390 return 0;
391 }
392
393 int s5ptvfb_map_video_memory(struct fb_info *fb)
394 {
395 struct fb_fix_screeninfo *fix = &fb->fix;
396 struct s5ptvfb_window *win = fb->par;
397
398 if (win->path == DATA_PATH_FIFO)
399 return 0;
400
401 fb->screen_base = dma_alloc_writecombine(s5ptv_status.dev_fb,
402 PAGE_ALIGN(fix->smem_len),
403 (unsigned int *) &fix->smem_start, GFP_KERNEL);
404 if (!fb->screen_base)
405 return -ENOMEM;
406 else
407 dev_info(s5ptv_status.dev_fb,
408 "[fb%d] dma: 0x%08x, cpu: 0x%08x, "
409 "size: 0x%08x\n", win->id,
410 (unsigned int) fix->smem_start,
411 (unsigned int) fb->screen_base,
412 fix->smem_len);
413
414 memset(fb->screen_base, 0, fix->smem_len);
415
416 return 0;
417 }
418
419
420 static int s5ptvfb_set_bitfield(struct fb_var_screeninfo *var)
421 {
422 switch (var->bits_per_pixel) {
423 case 16:
424 if (var->transp.length == 1) {
425 var->red.offset = 10;
426 var->red.length = 5;
427 var->green.offset = 5;
428 var->green.length = 5;
429 var->blue.offset = 0;
430 var->blue.length = 5;
431 var->transp.offset = 15;
432 } else if (var->transp.length == 4) {
433 var->red.offset = 8;
434 var->red.length = 4;
435 var->green.offset = 4;
436 var->green.length = 4;
437 var->blue.offset = 0;
438 var->blue.length = 4;
439 var->transp.offset = 12;
440 } else {
441 var->red.offset = 11;
442 var->red.length = 5;
443 var->green.offset = 5;
444 var->green.length = 6;
445 var->blue.offset = 0;
446 var->blue.length = 5;
447 var->transp.offset = 0;
448 }
449 break;
450
451 case 24:
452 var->red.offset = 16;
453 var->red.length = 8;
454 var->green.offset = 8;
455 var->green.length = 8;
456 var->blue.offset = 0;
457 var->blue.length = 8;
458 var->transp.offset = 0;
459 var->transp.length = 0;
460 break;
461
462 case 32:
463 var->red.offset = 16;
464 var->red.length = 8;
465 var->green.offset = 8;
466 var->green.length = 8;
467 var->blue.offset = 0;
468 var->blue.length = 8;
469 var->transp.offset = 24;
470 break;
471 }
472
473 return 0;
474 }
475
476 static int s5ptvfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
477 {
478 /* nothing to do for removing cursor */
479 return 0;
480 }
481
482
483 static int s5ptvfb_setcolreg(unsigned int regno, unsigned int red,
484 unsigned int green, unsigned int blue,
485 unsigned int transp, struct fb_info *fb)
486 {
487 unsigned int *pal = (unsigned int *) fb->pseudo_palette;
488 unsigned int val = 0;
489
490 if (regno < 16) {
491 /* fake palette of 16 colors */
492 val |= chan_to_field(red, fb->var.red);
493 val |= chan_to_field(green, fb->var.green);
494 val |= chan_to_field(blue, fb->var.blue);
495 val |= chan_to_field(transp, fb->var.transp);
496
497 pal[regno] = val;
498 }
499
500 return 0;
501 }
502
503
504 static int s5ptvfb_pan_display(struct fb_var_screeninfo *var,
505 struct fb_info *fb)
506 {
507 struct s5ptvfb_window *win = fb->par;
508
509 if (var->yoffset + var->yres > var->yres_virtual) {
510 dev_err(s5ptv_status.dev_fb, "invalid yoffset value\n");
511 return -EINVAL;
512 }
513
514 fb->var.yoffset = var->yoffset;
515
516 dev_dbg(s5ptv_status.dev_fb,
517 "[fb%d] yoffset for pan display: %d\n", win->id,
518 var->yoffset);
519
520 s5ptvfb_set_buffer_address(&s5ptv_status, win->id);
521
522 return 0;
523 }
524
525
526 static int s5ptvfb_blank(int blank_mode, struct fb_info *fb)
527 {
528 struct s5ptvfb_window *win = fb->par;
529
530 dev_dbg(s5ptv_status.dev_fb, "change blank mode\n");
531
532 switch (blank_mode) {
533 case FB_BLANK_UNBLANK:
534 if (fb->fix.smem_start) {
535 s5ptvfb_display_on(&s5ptv_status);
536 s5ptvfb_enable_window(win->id);
537 } else
538 dev_info(s5ptv_status.dev_fb,
539 "[fb%d] no allocated memory for unblank\n",
540 win->id);
541
542 break;
543
544 case FB_BLANK_POWERDOWN:
545 s5ptvfb_display_off(&s5ptv_status);
546 s5ptvfb_disable_window(win->id);
547 break;
548
549 default:
550 dev_dbg(s5ptv_status.dev_fb, "unsupported blank mode\n");
551 break;
552 }
553
554 return 0;
555 }
556
557 int s5ptvfb_set_par(struct fb_info *fb)
558 {
559 struct s5ptvfb_window *win = fb->par;
560
561 dev_dbg(s5ptv_status.dev_fb, "[fb%d] set_par\n", win->id);
562
563 if (!fb->fix.smem_start) {
564 printk(KERN_ERR "[Warning]fb addr should be \
565 allocated before enabling HDMI\n");
566 }
567
568
569 /* For setting input color format */
570 ((struct fb_var_screeninfo) (s5ptv_status.fb->var)).bits_per_pixel =
571 ((struct fb_var_screeninfo) (fb->var)).bits_per_pixel;
572
573 s5ptvfb_set_display_mode(&s5ptv_status);
574
575 s5ptvfb_set_window_control(&s5ptv_status, win->id);
576 s5ptvfb_set_window_position(&s5ptv_status, win->id);
577 s5ptvfb_set_window_size(&s5ptv_status, win->id);
578 s5ptvfb_set_buffer_address(&s5ptv_status, win->id);
579 s5ptvfb_set_buffer_size(&s5ptv_status, win->id);
580
581 if (win->id > 0)
582 s5ptvfb_set_alpha_blending(&s5ptv_status, win->id);
583
584 return 0;
585 }
586
587 int s5ptvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb)
588 {
589 struct fb_fix_screeninfo *fix = &fb->fix;
590 struct s5ptvfb_window *win = fb->par;
591 struct s5ptvfb_lcd *lcd = s5ptv_status.lcd;
592
593 dev_dbg(s5ptv_status.dev_fb, "[fb%d] check_var\n", win->id);
594
595 if (var->bits_per_pixel != 16 && var->bits_per_pixel != 24 &&
596 var->bits_per_pixel != 32) {
597 dev_err(s5ptv_status.dev_fb, "invalid bits per pixel\n");
598 return -EINVAL;
599 }
600
601 if (var->xres > lcd->width)
602 var->xres = lcd->width;
603
604 if (var->yres > lcd->height)
605 var->yres = lcd->height;
606
607 if (var->xres_virtual != var->xres)
608 var->xres_virtual = var->xres;
609
610 if (var->yres_virtual > var->yres * (fb->fix.ypanstep + 1))
611 var->yres_virtual = var->yres * (fb->fix.ypanstep + 1);
612
613 if (var->xoffset != 0)
614 var->xoffset = 0;
615
616 if (var->yoffset + var->yres > var->yres_virtual)
617 var->yoffset = var->yres_virtual - var->yres;
618
619 if (win->x + var->xres > lcd->width)
620 win->x = lcd->width - var->xres;
621
622 if (win->y + var->yres > lcd->height)
623 win->y = lcd->height - var->yres;
624
625 /* modify the fix info */
626 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
627 fix->smem_len = fix->line_length * var->yres_virtual;
628
629
630 s5ptvfb_set_bitfield(var);
631 s5ptvfb_set_alpha_info(var, win);
632
633 return 0;
634 }
635
636 static int s5ptvfb_release(struct fb_info *fb, int user)
637 {
638 int ret;
639 struct s5ptvfb_window *win = fb->par;
640
641 s5ptv_status.hdcp_en = false;
642
643 s5ptvfb_release_window(fb);
644
645 tv_vlayer_stop();
646 tv_if_stop();
647
648 s5ptv_status.hdcp_en = false;
649
650 s5ptv_status.tvout_output_enable = false;
651
652 /*
653 * drv. release
654 * - just check drv. state reg. or not.
655 */
656
657 ret = s5p_tv_clk_gate(false);
658 if (ret < 0) {
659 printk(KERN_ERR "[Error]Cannot release\n");
660 return -1;
661 }
662 tv_phy_power(false);
663
664 mutex_lock(&s5ptv_status.fb_lock);
665 atomic_dec(&win->in_use);
666 mutex_unlock(&s5ptv_status.fb_lock);
667
668 return 0;
669 }
670
671 static int s5ptvfb_ioctl(struct fb_info *fb, unsigned int cmd,
672 unsigned long arg)
673 {
674 struct fb_var_screeninfo *var = &fb->var;
675 struct s5ptvfb_window *win = fb->par;
676 struct s5ptvfb_lcd *lcd = s5ptv_status.lcd;
677 int ret = 0;
678 void *argp = (void *) arg;
679
680 union {
681 struct s5ptvfb_user_window user_window;
682 struct s5ptvfb_user_plane_alpha user_alpha;
683 struct s5ptvfb_user_chroma user_chroma;
684 int vsync;
685 } p;
686
687 switch (cmd) {
688
689 case FBIO_ALLOC:
690 win->path = (enum s5ptvfb_data_path_t) argp;
691 break;
692
693 case FBIOGET_FSCREENINFO:
694 ret = memcpy(argp, &fb->fix, sizeof(fb->fix)) ? 0 : -EFAULT;
695 break;
696
697 case FBIOGET_VSCREENINFO:
698 ret = memcpy(argp, &fb->var, sizeof(fb->var)) ? 0 : -EFAULT;
699 break;
700
701 case FBIOPUT_VSCREENINFO:
702 ret = s5ptvfb_check_var((struct fb_var_screeninfo *) argp, fb);
703 if (ret) {
704 dev_err(s5ptv_status.dev_fb, "invalid vscreeninfo\n");
705 break;
706 }
707
708 ret = memcpy(&fb->var, (struct fb_var_screeninfo *) argp,
709 sizeof(fb->var)) ? 0 : -EFAULT;
710 if (ret) {
711 dev_err(s5ptv_status.dev_fb,
712 "failed to put new vscreeninfo\n");
713 break;
714 }
715
716 ret = s5ptvfb_set_par(fb);
717 break;
718
719 case S5PTVFB_WIN_POSITION:
720 if (copy_from_user(&p.user_window,
721 (struct s5ptvfb_user_window __user *) arg,
722 sizeof(p.user_window)))
723 ret = -EFAULT;
724 else {
725 if (p.user_window.x < 0)
726 p.user_window.x = 0;
727
728 if (p.user_window.y < 0)
729 p.user_window.y = 0;
730
731 if (p.user_window.x + var->xres > lcd->width)
732 win->x = lcd->width - var->xres;
733 else
734 win->x = p.user_window.x;
735
736 if (p.user_window.y + var->yres > lcd->height)
737 win->y = lcd->height - var->yres;
738 else
739 win->y = p.user_window.y;
740
741 s5ptvfb_set_window_position(&s5ptv_status, win->id);
742 }
743 break;
744
745 case S5PTVFB_WIN_SET_PLANE_ALPHA:
746 if (copy_from_user(&p.user_alpha,
747 (struct s5ptvfb_user_plane_alpha __user *) arg,
748 sizeof(p.user_alpha)))
749 ret = -EFAULT;
750 else {
751 win->alpha.mode = PLANE_BLENDING;
752 win->alpha.channel = p.user_alpha.channel;
753 win->alpha.value =
754 S5PTVFB_AVALUE(p.user_alpha.red,
755 p.user_alpha.green,
756 p.user_alpha.blue);
757
758 s5ptvfb_set_alpha_blending(&s5ptv_status, win->id);
759 }
760 break;
761
762 case S5PTVFB_WIN_SET_CHROMA:
763 if (copy_from_user(&p.user_chroma,
764 (struct s5ptvfb_user_chroma __user *) arg,
765 sizeof(p.user_chroma)))
766 ret = -EFAULT;
767 else {
768 win->chroma.enabled = p.user_chroma.enabled;
769 win->chroma.key = S5PTVFB_CHROMA(p.user_chroma.red,
770 p.user_chroma.green,
771 p.user_chroma.blue);
772
773 s5ptvfb_set_chroma_key(&s5ptv_status, win->id);
774 }
775 break;
776
777 case S5PTVFB_SET_VSYNC_INT:
778 tv_vm_set_vsync_interrupt((int)argp);
779 break;
780
781 case S5PTVFB_WAITFORVSYNC:
782 s5ptvfb_wait_for_vsync();
783 break;
784
785 case S5PTVFB_WIN_SET_ADDR:
786 fb->fix.smem_start = (unsigned long)argp;
787 s5ptvfb_set_buffer_address(&s5ptv_status, win->id);
788 break;
789
790 case S5PTVFB_SET_WIN_ON:
791 s5ptvfb_display_on(&s5ptv_status);
792 s5ptvfb_enable_window(0);
793 break;
794
795 case S5PTVFB_SET_WIN_OFF:
796 s5ptvfb_display_off(&s5ptv_status);
797 s5ptvfb_disable_window(0);
798 break;
799 }
800
801 return 0;
802 }
803
804 static int s5ptvfb_open(struct fb_info *fb, int user)
805 {
806 struct s5ptvfb_window *win = fb->par;
807 int ret = 0;
808
809 ret = s5p_tv_clk_gate(true);
810 if (ret < 0) {
811 printk(KERN_ERR "[Error]Cannot open it\n");
812 return -1;
813 }
814
815 tv_phy_power(true);
816
817 tv_if_init_param();
818
819 s5p_tv_v4l2_init_param();
820
821 s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_HDMI_RGB;
822
823 tv_if_set_disp();
824
825 mutex_lock(&s5ptv_status.fb_lock);
826
827 if (atomic_read(&win->in_use)) {
828
829 dev_dbg(s5ptv_status.dev_fb,
830 "do not allow multiple open "
831 "for window\n");
832 ret = -EBUSY;
833
834 } else
835 atomic_inc(&win->in_use);
836
837 mutex_unlock(&s5ptv_status.fb_lock);
838
839 return ret;
840
841 }
842
843
844 int s5p_tv_v_read(struct file *filp, char *buf, size_t count,
845 loff_t *f_pos)
846 {
847 return 0;
848 }
849
850 int s5p_tv_v_write(struct file *filp, const char *buf, size_t
851 count, loff_t *f_pos)
852 {
853 return 0;
854 }
855
856 struct fb_ops s5ptvfb_ops = {
857 .owner = THIS_MODULE,
858 .fb_fillrect = cfb_fillrect,
859 .fb_copyarea = cfb_copyarea,
860 .fb_imageblit = cfb_imageblit,
861 .fb_check_var = s5ptvfb_check_var,
862 .fb_set_par = s5ptvfb_set_par,
863 .fb_blank = s5ptvfb_blank,
864 .fb_pan_display = s5ptvfb_pan_display,
865 .fb_setcolreg = s5ptvfb_setcolreg,
866 .fb_cursor = s5ptvfb_cursor,
867 .fb_ioctl = s5ptvfb_ioctl,
868 .fb_open = s5ptvfb_open,
869 .fb_release = s5ptvfb_release,
870 };
871
872 int s5ptvfb_init_fbinfo(int id)
873 {
874 struct fb_info *fb = s5ptv_status.fb;
875 struct fb_fix_screeninfo *fix = &fb->fix;
876 struct fb_var_screeninfo *var = &fb->var;
877 struct s5ptvfb_window *win = fb->par;
878 struct s5ptvfb_alpha *alpha = &win->alpha;
879 struct s5ptvfb_lcd *lcd = s5ptv_status.lcd;
880 struct s5ptvfb_lcd_timing *timing = &lcd->timing;
881
882 memset(win, 0, sizeof(struct s5ptvfb_window));
883
884 platform_set_drvdata(to_platform_device(s5ptv_status.dev_fb), fb);
885
886 strcpy(fix->id, S5PTVFB_NAME);
887
888 /* fimd specific */
889 win->id = id;
890 win->path = DATA_PATH_DMA;
891 win->dma_burst = 16;
892 alpha->mode = PLANE_BLENDING;
893
894 /* fbinfo */
895 fb->fbops = &s5ptvfb_ops;
896 fb->flags = FBINFO_FLAG_DEFAULT;
897 fb->pseudo_palette = &win->pseudo_pal;
898 fix->xpanstep = 0;
899 fix->ypanstep = 0;
900 fix->type = FB_TYPE_PACKED_PIXELS;
901 fix->accel = FB_ACCEL_NONE;
902 fix->visual = FB_VISUAL_TRUECOLOR;
903 var->xres = lcd->width;
904 var->yres = lcd->height;
905 var->xres_virtual = var->xres;
906 var->yres_virtual = var->yres
907 + (var->yres * fix->ypanstep);
908 var->bits_per_pixel = 32;
909 var->xoffset = 0;
910 var->yoffset = 0;
911 var->width = 0;
912 var->height = 0;
913 var->transp.length = 0;
914 var->nonstd = 0;
915 var->activate = FB_ACTIVATE_NOW;
916 var->vmode = FB_VMODE_NONINTERLACED;
917 var->hsync_len = timing->h_sw;
918 var->vsync_len = timing->v_sw;
919 var->left_margin = timing->h_fp;
920 var->right_margin = timing->h_bp;
921 var->upper_margin = timing->v_fp;
922 var->lower_margin = timing->v_bp;
923
924 fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
925 fix->smem_len = fix->line_length * var->yres_virtual;
926
927 var->pixclock = lcd->freq * (var->left_margin + var->right_margin +
928 var->hsync_len + var->xres) *
929 (var->upper_margin + var->lower_margin +
930 var->vsync_len + var->yres);
931
932 dev_dbg(s5ptv_status.dev_fb, "pixclock: %d\n", var->pixclock);
933
934 s5ptvfb_set_bitfield(var);
935 s5ptvfb_set_alpha_info(var, win);
936
937 return 0;
938 }
939
940 static struct s5ptvfb_lcd max_tvfb = {
941 .width = 1920,
942 .height = 1080,
943 .bpp = 32,
944 .freq = 60,
945
946 .timing = {
947 .h_fp = 49,
948 .h_bp = 17,
949 .h_sw = 33,
950 .v_fp = 4,
951 .v_fpe = 1,
952 .v_bp = 15,
953 .v_bpe = 1,
954 .v_sw = 6,
955 },
956
957 .polarity = {
958 .rise_vclk = 0,
959 .inv_hsync = 1,
960 .inv_vsync = 1,
961 .inv_vden = 0,
962 },
963 };
964
965 void s5ptvfb_set_lcd_info(struct s5p_tv_status *ctrl)
966 {
967 ctrl->lcd = &max_tvfb;
968 }
969
970
971 int s5ptvfb_direct_ioctl(int id, unsigned int cmd, unsigned long arg)
972 {
973 struct fb_info *fb = s5ptv_status.fb;
974 struct fb_fix_screeninfo *fix = &fb->fix;
975 struct s5ptvfb_window *win = fb->par;
976 void *argp = (void *) arg;
977 int ret = 0;
978
979 switch (cmd) {
980
981 case FBIO_ALLOC:
982 win->path = (enum s5ptvfb_data_path_t) argp;
983 break;
984
985 case FBIOGET_FSCREENINFO:
986 ret = memcpy(argp, &fb->fix, sizeof(fb->fix)) ? 0 : -EFAULT;
987 break;
988
989 case FBIOGET_VSCREENINFO:
990 ret = memcpy(argp, &fb->var, sizeof(fb->var)) ? 0 : -EFAULT;
991 break;
992
993 case FBIOPUT_VSCREENINFO:
994 ret = s5ptvfb_check_var((struct fb_var_screeninfo *) argp, fb);
995 if (ret) {
996 dev_err(s5ptv_status.dev_fb, "invalid vscreeninfo\n");
997 break;
998 }
999
1000 ret = memcpy(&fb->var, (struct fb_var_screeninfo *) argp,
1001 sizeof(fb->var)) ? 0 : -EFAULT;
1002 if (ret) {
1003 dev_err(s5ptv_status.dev_fb,
1004 "failed to put new vscreeninfo\n");
1005 break;
1006 }
1007
1008 ret = s5ptvfb_set_par(fb);
1009 break;
1010
1011 case S5PTVFB_SET_WIN_ON:
1012 s5ptvfb_display_on(&s5ptv_status);
1013 s5ptvfb_enable_window(0);
1014 break;
1015
1016 case S5PTVFB_SET_WIN_OFF:
1017 s5ptvfb_display_off(&s5ptv_status);
1018 s5ptvfb_disable_window(0);
1019 break;
1020
1021 case S5PTVFB_POWER_ON:
1022 ret = s5p_tv_clk_gate(true);
1023 if (ret < 0) {
1024 printk(KERN_ERR "[Error]The power is not on\n");
1025 break;
1026 }
1027 tv_phy_power(true);
1028
1029 tv_if_init_param();
1030
1031 s5p_tv_v4l2_init_param();
1032
1033 s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_HDMI_RGB;
1034
1035 tv_if_set_disp();
1036
1037 break;
1038
1039 case S5PTVFB_POWER_OFF:
1040 tv_vlayer_stop();
1041 tv_if_stop();
1042
1043 ret = s5p_tv_clk_gate(false);
1044 if (ret < 0) {
1045 printk(KERN_ERR "[Error]The power is not off\n");
1046 break;
1047 }
1048 tv_phy_power(false);
1049 break;
1050
1051 case S5PTVFB_SET_VSYNC_INT:
1052 tv_vm_set_vsync_interrupt((int)argp);
1053 break;
1054
1055 case S5PTVFB_WAITFORVSYNC:
1056 s5ptvfb_wait_for_vsync();
1057 break;
1058
1059 case S5PTVFB_WIN_SET_ADDR:
1060 fix->smem_start = (unsigned long)argp;
1061 s5ptvfb_set_buffer_address(&s5ptv_status, win->id);
1062 break;
1063
1064 default:
1065 ret = s5ptvfb_ioctl(fb, cmd, arg);
1066 break;
1067 }
1068
1069 return ret;
1070 }
1071 EXPORT_SYMBOL(s5ptvfb_direct_ioctl);
OLDNEW
« no previous file with comments | « drivers/media/video/samsung/tv20/hpd.c ('k') | drivers/media/video/samsung/tv20/s5p_stda_tvout_if.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698