2 On Screen Display cx23415 Framebuffer driver
4 This module presents the cx23415 OSD (onscreen display) framebuffer memory
5 as a standard Linux /dev/fb style framebuffer device. The framebuffer has
6 support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
7 mode, there is a choice of a three color depths (12, 15 or 16 bits), but no
8 local alpha. The colorspace is selectable between rgb & yuv.
9 Depending on the TV standard configured in the ivtv module at load time,
10 the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp.
11 Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL)
14 Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
16 Derived from drivers/video/vesafb.c
17 Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
20 Copyright (C) 2004 Matthias Badaire
22 Copyright (C) 2004 Chris Kennedy <c@groovy.org>
24 Copyright (C) 2006 Ian Armstrong <ian@iarmst.demon.co.uk>
26 This program is free software; you can redistribute it and/or modify
27 it under the terms of the GNU General Public License as published by
28 the Free Software Foundation; either version 2 of the License, or
29 (at your option) any later version.
31 This program is distributed in the hope that it will be useful,
32 but WITHOUT ANY WARRANTY; without even the implied warranty of
33 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
34 GNU General Public License for more details.
36 You should have received a copy of the GNU General Public License
37 along with this program; if not, write to the Free Software
38 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
41 #include <linux/module.h>
42 #include <linux/kernel.h>
43 #include <linux/string.h>
45 #include <linux/tty.h>
47 #include <linux/console.h>
48 #include <linux/bitops.h>
49 #include <linux/pagemap.h>
50 #include <media/ivtv-fb.h>
53 #include <asm/ioctl.h>
59 #include "ivtv-driver.h"
60 #include "ivtv-udma.h"
61 #include "ivtv-mailbox.h"
64 static int ivtv_fb_card_id = -1;
65 static int ivtv_fb_debug = 0;
67 static int osd_compat;
74 module_param(ivtv_fb_card_id, int, 0444);
75 module_param_named(debug,ivtv_fb_debug, int, 0644);
76 module_param(osd_laced, bool, 0444);
77 module_param(osd_compat, bool, 0444);
78 module_param(osd_depth, int, 0444);
79 module_param(osd_upper, int, 0444);
80 module_param(osd_left, int, 0444);
81 module_param(osd_yres, int, 0444);
82 module_param(osd_xres, int, 0444);
84 MODULE_PARM_DESC(ivtv_fb_card_id,
85 "Only use framebuffer of the specified ivtv card (0-31)\n"
86 "\t\t\tdefault -1: initialize all available framebuffers");
88 MODULE_PARM_DESC(debug,
89 "Debug level (bitmask). Default: errors only\n"
90 "\t\t\t(debug = 3 gives full debugging)");
92 MODULE_PARM_DESC(osd_compat,
93 "Compatibility mode - Display size is locked (use for old X drivers)\n"
98 /* Why upper, left, xres, yres, depth, laced ? To match terminology used
100 Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
102 MODULE_PARM_DESC(osd_laced,
106 "\t\t\tdefault off");
108 MODULE_PARM_DESC(osd_depth,
109 "Bits per pixel - 8, 16, 32\n"
112 MODULE_PARM_DESC(osd_upper,
113 "Vertical start position\n"
114 "\t\t\tdefault 0 (Centered)");
116 MODULE_PARM_DESC(osd_left,
117 "Horizontal start position\n"
118 "\t\t\tdefault 0 (Centered)");
120 MODULE_PARM_DESC(osd_yres,
122 "\t\t\tdefault 480 (PAL)\n"
123 "\t\t\t 400 (NTSC)");
125 MODULE_PARM_DESC(osd_xres,
127 "\t\t\tdefault 640");
129 MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
130 MODULE_LICENSE("GPL");
132 /* --------------------------------------------------------------------- */
134 #define IVTV_FB_DBGFLG_WARN (1 << 0)
135 #define IVTV_FB_DBGFLG_INFO (1 << 1)
137 #define IVTV_FB_DEBUG(x, type, fmt, args...) \
139 if ((x) & ivtv_fb_debug) \
140 printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \
142 #define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args)
143 #define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args)
145 /* Standard kernel messages */
146 #define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args)
147 #define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args)
148 #define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args)
150 /* --------------------------------------------------------------------- */
152 #define IVTV_OSD_MAX_WIDTH 720
153 #define IVTV_OSD_MAX_HEIGHT 576
155 #define IVTV_OSD_BPP_8 0x00
156 #define IVTV_OSD_BPP_16_444 0x03
157 #define IVTV_OSD_BPP_16_555 0x02
158 #define IVTV_OSD_BPP_16_565 0x01
159 #define IVTV_OSD_BPP_32 0x04
162 /* Physical base address */
163 unsigned long video_pbase;
164 /* Relative base address (relative to start of decoder memory) */
166 /* Mapped base address */
167 volatile char __iomem *video_vbase;
169 u32 video_buffer_size;
172 /* video_base rounded down as required by hardware MTRRs */
173 unsigned long fb_start_aligned_physaddr;
174 /* video_base rounded up as required by hardware MTRRs */
175 unsigned long fb_end_aligned_physaddr;
178 /* Current osd mode */
181 /* Store the buffer offset */
182 int set_osd_coords_x;
183 int set_osd_coords_y;
185 /* Current dimensions (NOT VISIBLE SIZE!) */
188 int display_byte_stride;
190 /* Current bits per pixel */
194 /* Frame buffer stuff */
195 struct fb_info ivtvfb_info;
196 struct fb_var_screeninfo ivtvfb_defined;
197 struct fb_fix_screeninfo ivtvfb_fix;
200 struct ivtv_osd_coords {
201 unsigned long offset;
202 unsigned long max_offset;
209 /* --------------------------------------------------------------------- */
211 /* ivtv API calls for framebuffer related support */
213 static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
216 u32 data[CX2341X_MBOX_MAX_DATA];
219 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
225 static int ivtv_fb_get_osd_coords(struct ivtv *itv,
226 struct ivtv_osd_coords *osd)
228 struct osd_info *oi = itv->osd_info;
229 u32 data[CX2341X_MBOX_MAX_DATA];
231 ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
233 osd->offset = data[0] - oi->video_rbase;
234 osd->max_offset = oi->display_width * oi->display_height * 4;
235 osd->pixel_stride = data[1];
236 osd->lines = data[2];
242 static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
244 struct osd_info *oi = itv->osd_info;
246 oi->display_width = osd->pixel_stride;
247 oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
248 oi->set_osd_coords_x += osd->x;
249 oi->set_osd_coords_y = osd->y;
251 return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
252 osd->offset + oi->video_rbase,
254 osd->lines, osd->x, osd->y);
257 static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
259 int osd_height_limit = itv->is_50hz ? 576 : 480;
261 /* Only fail if resolution too high, otherwise fudge the start coords. */
262 if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
265 /* Ensure we don't exceed display limits */
266 if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
267 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
268 ivtv_window->top, ivtv_window->height);
269 ivtv_window->top = osd_height_limit - ivtv_window->height;
272 if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
273 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
274 ivtv_window->left, ivtv_window->width);
275 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
278 /* Set the OSD origin */
279 write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
281 /* How much to display */
282 write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
284 /* Pass this info back the yuv handler */
285 itv->yuv_info.osd_vis_w = ivtv_window->width;
286 itv->yuv_info.osd_vis_h = ivtv_window->height;
287 itv->yuv_info.osd_x_offset = ivtv_window->left;
288 itv->yuv_info.osd_y_offset = ivtv_window->top;
293 static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv,
294 unsigned long ivtv_dest_addr, void __user *userbuf,
301 mutex_lock(&itv->udma.lock);
303 if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
304 mutex_unlock(&itv->udma.lock);
305 IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, "
306 "Error with get_user_pages: %d bytes, %d pages returned\n",
307 size_in_bytes, itv->udma.page_count);
309 /* get_user_pages must have failed completely */
313 IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
314 size_in_bytes, itv->udma.page_count);
316 ivtv_udma_prepare(itv);
317 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
318 /* if no UDMA is pending and no UDMA is in progress, then the DMA
320 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
321 /* don't interrupt if the DMA is in progress but break off
322 a still pending DMA. */
323 got_sig = signal_pending(current);
324 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
329 finish_wait(&itv->dma_waitq, &wait);
331 /* Unmap Last DMA Xfer */
332 ivtv_udma_unmap(itv);
333 mutex_unlock(&itv->udma.lock);
335 IVTV_DEBUG_INFO("User stopped OSD\n");
342 static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
343 unsigned long dest_offset, int count)
346 struct osd_info *oi = itv->osd_info;
350 IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n");
354 /* Check Total FB Size */
355 if ((dest_offset + count) > oi->video_buffer_size) {
356 IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
357 dest_offset + count, oi->video_buffer_size);
361 /* Not fatal, but will have undesirable results */
362 if ((unsigned long)source & 3)
363 IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
364 (unsigned long)source);
367 IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
370 IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count);
373 if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
374 IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n",
375 (unsigned long)source);
377 IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
378 dest_offset, (unsigned long)source,
383 /* OSD Address to send DMA to */
384 dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
387 return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count);
390 static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
393 struct ivtv *itv = (struct ivtv *)info->par;
397 case FBIOGET_VBLANK: {
398 struct fb_vblank vblank;
401 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
402 FB_VBLANK_HAVE_VSYNC;
403 trace = read_reg(0x028c0) >> 16;
404 if (itv->is_50hz && trace > 312) trace -= 312;
405 else if (itv->is_60hz && trace > 262) trace -= 262;
406 if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
407 vblank.count = itv->last_vsync_field;
408 vblank.vcount = trace;
410 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
415 case FBIO_WAITFORVSYNC:
416 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
417 if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
418 finish_wait(&itv->vsync_waitq, &wait);
421 case IVTVFB_IOC_DMA_FRAME: {
422 struct ivtvfb_dma_frame args;
424 IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
425 if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
428 return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
432 IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
438 /* Framebuffer device handling */
440 static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
442 struct osd_info *oi = itv->osd_info;
443 struct ivtv_osd_coords ivtv_osd;
444 struct v4l2_rect ivtv_window;
447 IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n");
449 /* Select color space */
450 if (var->nonstd) /* YUV */
451 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
453 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
455 /* Set the color mode */
456 switch (var->bits_per_pixel) {
458 osd_mode = IVTV_OSD_BPP_8;
461 osd_mode = IVTV_OSD_BPP_32;
464 switch (var->green.length) {
466 osd_mode = IVTV_OSD_BPP_16_444;
469 osd_mode = IVTV_OSD_BPP_16_555;
472 osd_mode = IVTV_OSD_BPP_16_565;
475 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
479 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
482 /* Change osd mode if needed.
483 Although rare, things can go wrong. The extra mode
484 change seems to help... */
485 if (osd_mode != -1 && osd_mode != oi->osd_mode) {
486 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
487 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
488 oi->osd_mode = osd_mode;
491 oi->bits_per_pixel = var->bits_per_pixel;
492 oi->bytes_per_pixel = var->bits_per_pixel / 8;
494 /* Set the flicker filter */
495 switch (var->vmode & FB_VMODE_MASK) {
496 case FB_VMODE_NONINTERLACED: /* Filter on */
497 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
499 case FB_VMODE_INTERLACED: /* Filter off */
500 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
503 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
506 /* Read the current osd info */
507 ivtv_fb_get_osd_coords(itv, &ivtv_osd);
509 /* Now set the OSD to the size we want */
510 ivtv_osd.pixel_stride = var->xres_virtual;
511 ivtv_osd.lines = var->yres_virtual;
514 ivtv_fb_set_osd_coords(itv, &ivtv_osd);
516 /* Can't seem to find the right API combo for this.
517 Use another function which does what we need through direct register access. */
518 ivtv_window.width = var->xres;
519 ivtv_window.height = var->yres;
521 /* Minimum margin cannot be 0, as X won't allow such a mode */
522 if (!var->upper_margin) var->upper_margin++;
523 if (!var->left_margin) var->left_margin++;
524 ivtv_window.top = var->upper_margin - 1;
525 ivtv_window.left = var->left_margin - 1;
527 ivtv_fb_set_display_window(itv, &ivtv_window);
529 /* Force update of yuv registers */
530 itv->yuv_info.yuv_forced_update = 1;
532 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
533 var->xres, var->yres,
534 var->xres_virtual, var->yres_virtual,
535 var->bits_per_pixel);
537 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
538 var->left_margin, var->upper_margin);
540 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
541 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
542 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
547 static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
549 struct osd_info *oi = itv->osd_info;
551 IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n");
552 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
553 strcpy(fix->id, "cx23415 TV out");
554 fix->smem_start = oi->video_pbase;
555 fix->smem_len = oi->video_buffer_size;
556 fix->type = FB_TYPE_PACKED_PIXELS;
557 fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
561 fix->line_length = oi->display_byte_stride;
562 fix->accel = FB_ACCEL_NONE;
566 /* Check the requested display mode, returning -EINVAL if we can't
569 static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
571 struct osd_info *oi = itv->osd_info;
572 int osd_height_limit;
573 u32 pixclock, hlimit, vlimit;
575 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
577 /* Set base references for mode calcs. */
582 osd_height_limit = 576;
588 osd_height_limit = 480;
591 /* Check the bits per pixel */
593 if (var->bits_per_pixel != 32) {
594 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
599 if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
600 var->transp.offset = 24;
601 var->transp.length = 8;
602 var->red.offset = 16;
604 var->green.offset = 8;
605 var->green.length = 8;
606 var->blue.offset = 0;
607 var->blue.length = 8;
609 else if (var->bits_per_pixel == 16) {
610 /* To find out the true mode, check green length */
611 switch (var->green.length) {
615 var->green.offset = 4;
616 var->green.length = 4;
617 var->blue.offset = 0;
618 var->blue.length = 4;
619 var->transp.offset = 12;
620 var->transp.length = 1;
623 var->red.offset = 10;
625 var->green.offset = 5;
626 var->green.length = 5;
627 var->blue.offset = 0;
628 var->blue.length = 5;
629 var->transp.offset = 15;
630 var->transp.length = 1;
633 var->red.offset = 11;
635 var->green.offset = 5;
636 var->green.length = 6;
637 var->blue.offset = 0;
638 var->blue.length = 5;
639 var->transp.offset = 0;
640 var->transp.length = 0;
645 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
649 /* Check the resolution */
651 if (var->xres != oi->ivtvfb_defined.xres ||
652 var->yres != oi->ivtvfb_defined.yres ||
653 var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
654 var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
655 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
656 var->xres, var->yres, var->xres_virtual, var->yres_virtual);
661 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
662 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n",
663 var->xres, var->yres);
667 /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
668 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
669 var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
670 var->xres_virtual < var->xres ||
671 var->yres_virtual < var->yres) {
672 IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
673 var->xres_virtual, var->yres_virtual);
678 /* Some extra checks if in 8 bit mode */
679 if (var->bits_per_pixel == 8) {
680 /* Width must be a multiple of 4 */
682 IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
685 if (var->xres_virtual & 3) {
686 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
690 else if (var->bits_per_pixel == 16) {
691 /* Width must be a multiple of 2 */
693 IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
696 if (var->xres_virtual & 1) {
697 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
702 /* Now check the offsets */
703 if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
704 IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
705 var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
709 /* Check pixel format */
710 if (var->nonstd > 1) {
711 IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
715 /* Check video mode */
716 if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
717 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
718 IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
722 /* Check the left & upper margins
723 If the margins are too large, just center the screen
724 (enforcing margins causes too many problems) */
726 if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
727 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
729 if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
730 var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
733 /* Maintain overall 'size' for a constant refresh rate */
734 var->right_margin = hlimit - var->left_margin - var->xres;
735 var->lower_margin = vlimit - var->upper_margin - var->yres;
737 /* Fixed sync times */
741 /* Non-interlaced / interlaced mode is used to switch the OSD filter
742 on or off. Adjust the clock timings to maintain a constant
743 vertical refresh rate. */
744 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
745 var->pixclock = pixclock / 2;
747 var->pixclock = pixclock;
749 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
750 var->xres, var->yres,
751 var->xres_virtual, var->yres_virtual,
752 var->bits_per_pixel);
754 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
755 var->left_margin, var->upper_margin);
757 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
758 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
759 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
763 static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
765 struct ivtv *itv = (struct ivtv *) info->par;
766 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
767 return _ivtvfb_check_var(var, itv);
770 static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
773 struct ivtv *itv = (struct ivtv *) info->par;
775 osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
776 write_reg(osd_pan_index, 0x02A0C);
778 /* Pass this info back the yuv handler */
779 itv->yuv_info.osd_x_pan = var->xoffset;
780 itv->yuv_info.osd_y_pan = var->yoffset;
781 /* Force update of yuv registers */
782 itv->yuv_info.yuv_forced_update = 1;
786 static int ivtvfb_set_par(struct fb_info *info)
789 struct ivtv *itv = (struct ivtv *) info->par;
791 IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n");
793 rc = ivtvfb_set_var(itv, &info->var);
794 ivtvfb_pan_display(&info->var, info);
795 ivtvfb_get_fix(itv, &info->fix);
799 static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
800 unsigned blue, unsigned transp,
801 struct fb_info *info)
804 struct ivtv *itv = (struct ivtv *)info->par;
806 if (regno >= info->cmap.len)
809 color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
810 if (info->var.bits_per_pixel <= 8) {
811 write_reg(regno, 0x02a30);
812 write_reg(color, 0x02a34);
818 palette = info->pseudo_palette;
819 if (info->var.bits_per_pixel == 16) {
820 switch (info->var.green.length) {
822 color = ((red & 0xf000) >> 4) |
823 ((green & 0xf000) >> 8) |
824 ((blue & 0xf000) >> 12);
827 color = ((red & 0xf800) >> 1) |
828 ((green & 0xf800) >> 6) |
829 ((blue & 0xf800) >> 11);
832 color = (red & 0xf800 ) |
833 ((green & 0xfc00) >> 5) |
834 ((blue & 0xf800) >> 11);
838 palette[regno] = color;
842 /* We don't really support blanking. All this does is enable or
844 static int ivtvfb_blank(int blank_mode, struct fb_info *info)
846 struct ivtv *itv = (struct ivtv *)info->par;
848 IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
849 switch (blank_mode) {
850 case FB_BLANK_UNBLANK:
851 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
853 case FB_BLANK_NORMAL:
854 case FB_BLANK_HSYNC_SUSPEND:
855 case FB_BLANK_VSYNC_SUSPEND:
856 case FB_BLANK_POWERDOWN:
857 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
863 static struct fb_ops ivtvfb_ops = {
864 .owner = THIS_MODULE,
865 .fb_check_var = ivtvfb_check_var,
866 .fb_set_par = ivtvfb_set_par,
867 .fb_setcolreg = ivtvfb_setcolreg,
868 .fb_fillrect = cfb_fillrect,
869 .fb_copyarea = cfb_copyarea,
870 .fb_imageblit = cfb_imageblit,
872 .fb_ioctl = ivtvfb_ioctl,
873 .fb_pan_display = ivtvfb_pan_display,
874 .fb_blank = ivtvfb_blank,
880 /* Setup our initial video mode */
881 static int ivtvfb_init_vidmode(struct ivtv *itv)
883 struct osd_info *oi = itv->osd_info;
884 struct v4l2_rect start_window;
889 if (osd_compat) osd_depth = 32;
890 if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
891 oi->bits_per_pixel = osd_depth;
892 oi->bytes_per_pixel = oi->bits_per_pixel / 8;
894 /* Invalidate current osd mode to force a mode switch later */
897 /* Horizontal size & position */
899 if (osd_xres > 720) osd_xres = 720;
901 /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
904 else if (osd_depth == 16)
908 start_window.width = osd_xres;
910 start_window.width = osd_compat ? 720: 640;
912 /* Check horizontal start (osd_left). */
913 if (osd_left && osd_left + start_window.width > 721) {
914 IVTV_FB_ERR("Invalid osd_left - assuming default\n");
918 /* Hardware coords start at 0, user coords start at 1. */
921 start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
923 oi->display_byte_stride =
924 start_window.width * oi->bytes_per_pixel;
926 /* Vertical size & position */
928 max_height = itv->is_50hz ? 576 : 480;
930 if (osd_yres > max_height)
931 osd_yres = max_height;
934 start_window.height = osd_yres;
936 start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
938 /* Check vertical start (osd_upper). */
939 if (osd_upper + start_window.height > max_height + 1) {
940 IVTV_FB_ERR("Invalid osd_upper - assuming default\n");
944 /* Hardware coords start at 0, user coords start at 1. */
947 start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
949 oi->display_width = start_window.width;
950 oi->display_height = start_window.height;
952 /* Generate a valid fb_var_screeninfo */
954 oi->ivtvfb_defined.xres = oi->display_width;
955 oi->ivtvfb_defined.yres = oi->display_height;
956 oi->ivtvfb_defined.xres_virtual = oi->display_width;
957 oi->ivtvfb_defined.yres_virtual = oi->display_height;
958 oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
959 oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
960 oi->ivtvfb_defined.left_margin = start_window.left + 1;
961 oi->ivtvfb_defined.upper_margin = start_window.top + 1;
962 oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
963 oi->ivtvfb_defined.nonstd = 0;
965 /* We've filled in the most data, let the usual mode check
966 routine fill in the rest. */
967 _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
969 /* Generate valid fb_fix_screeninfo */
971 ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
973 /* Generate valid fb_info */
975 oi->ivtvfb_info.node = -1;
976 oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
977 oi->ivtvfb_info.fbops = &ivtvfb_ops;
978 oi->ivtvfb_info.par = itv;
979 oi->ivtvfb_info.var = oi->ivtvfb_defined;
980 oi->ivtvfb_info.fix = oi->ivtvfb_fix;
981 oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
982 oi->ivtvfb_info.fbops = &ivtvfb_ops;
984 /* Supply some monitor specs. Bogus values will do for now */
985 oi->ivtvfb_info.monspecs.hfmin = 8000;
986 oi->ivtvfb_info.monspecs.hfmax = 70000;
987 oi->ivtvfb_info.monspecs.vfmin = 10;
988 oi->ivtvfb_info.monspecs.vfmax = 100;
990 /* Allocate color map */
991 if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
992 IVTV_FB_ERR("abort, unable to alloc cmap\n");
996 /* Allocate the pseudo palette */
997 oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
999 if (!oi->ivtvfb_info.pseudo_palette) {
1000 IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n");
1007 /* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
1009 static int ivtvfb_init_io(struct ivtv *itv)
1011 struct osd_info *oi = itv->osd_info;
1013 mutex_lock(&itv->serialize_lock);
1014 if (ivtv_init_on_first_open(itv)) {
1015 mutex_unlock(&itv->serialize_lock);
1016 IVTV_FB_ERR("Failed to initialize ivtv\n");
1019 mutex_unlock(&itv->serialize_lock);
1021 ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
1023 /* The osd buffer size depends on the number of video buffers allocated
1024 on the PVR350 itself. For now we'll hardcode the smallest osd buffer
1025 size to prevent any overlap. */
1026 oi->video_buffer_size = 1704960;
1028 oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1029 oi->video_vbase = itv->dec_mem + oi->video_rbase;
1031 if (!oi->video_vbase) {
1032 IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1033 oi->video_buffer_size, oi->video_pbase);
1037 IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1038 oi->video_pbase, oi->video_vbase,
1039 oi->video_buffer_size / 1024);
1043 /* Find the largest power of two that maps the whole buffer */
1044 int size_shift = 31;
1046 while (!(oi->video_buffer_size & (1 << size_shift))) {
1050 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1051 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1052 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1053 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1054 if (mtrr_add(oi->fb_start_aligned_physaddr,
1055 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
1056 MTRR_TYPE_WRCOMB, 1) < 0) {
1057 IVTV_FB_WARN("cannot use mttr\n");
1058 oi->fb_start_aligned_physaddr = 0;
1059 oi->fb_end_aligned_physaddr = 0;
1064 /* Blank the entire osd. */
1065 memset_io(oi->video_vbase, 0, oi->video_buffer_size);
1070 /* Release any memory we've grabbed & remove mtrr entry */
1071 static void ivtvfb_release_buffers (struct ivtv *itv)
1073 struct osd_info *oi = itv->osd_info;
1076 if (oi->ivtvfb_info.cmap.len);
1077 fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
1079 /* Release pseudo palette */
1080 if (oi->ivtvfb_info.pseudo_palette)
1081 kfree(oi->ivtvfb_info.pseudo_palette);
1084 if (oi->fb_end_aligned_physaddr) {
1085 mtrr_del(-1, oi->fb_start_aligned_physaddr,
1086 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1091 itv->osd_info = NULL;
1094 /* Initialize the specified card */
1096 static int ivtvfb_init_card(struct ivtv *itv)
1100 if (itv->osd_info) {
1101 IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id);
1105 itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
1106 if (itv->osd_info == 0) {
1107 IVTV_FB_ERR("Failed to allocate memory for osd_info\n");
1111 /* Find & setup the OSD buffer */
1112 if ((rc = ivtvfb_init_io(itv)))
1115 /* Set the startup video mode information */
1116 if ((rc = ivtvfb_init_vidmode(itv))) {
1117 ivtvfb_release_buffers(itv);
1121 /* Register the framebuffer */
1122 if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1123 ivtvfb_release_buffers(itv);
1127 itv->osd_video_pbase = itv->osd_info->video_pbase;
1129 /* Set the card to the requested mode */
1130 ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1132 /* Set color 0 to black */
1133 write_reg(0, 0x02a30);
1134 write_reg(0, 0x02a34);
1136 /* Enable the osd */
1137 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1139 /* Note if we're running in compatibility mode */
1141 IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
1144 ivtv_udma_alloc(itv);
1149 static int __init ivtvfb_init(void)
1152 int i, registered = 0;
1154 if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) {
1155 printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n",
1156 IVTV_MAX_CARDS - 1);
1160 /* Locate & initialise all cards supporting an OSD. */
1161 for (i = 0; i < ivtv_cards_active; i++) {
1162 if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id)
1164 itv = ivtv_cards[i];
1165 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1166 if (ivtvfb_init_card(itv) == 0) {
1167 IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i);
1173 printk(KERN_ERR "ivtv-fb: no cards found");
1179 static void ivtvfb_cleanup(void)
1184 printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n");
1186 for (i = 0; i < ivtv_cards_active; i++) {
1187 itv = ivtv_cards[i];
1188 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
1189 IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i);
1190 ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
1191 unregister_framebuffer(&itv->osd_info->ivtvfb_info);
1192 ivtvfb_release_buffers(itv);
1193 itv->osd_video_pbase = 0;
1198 module_init(ivtvfb_init);
1199 module_exit(ivtvfb_cleanup);