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 <linux/matroxfb.h>
53 #include <asm/ioctl.h>
59 #include "ivtv-driver.h"
60 #include "ivtv-udma.h"
61 #include "ivtv-mailbox.h"
62 #include <media/ivtv-fb.h>
65 static int ivtv_fb_card_id = -1;
66 static int ivtv_fb_debug = 0;
68 static int osd_compat;
75 module_param(ivtv_fb_card_id, int, 0444);
76 module_param_named(debug,ivtv_fb_debug, int, 0644);
77 module_param(osd_laced, bool, 0444);
78 module_param(osd_compat, bool, 0444);
79 module_param(osd_depth, int, 0444);
80 module_param(osd_upper, int, 0444);
81 module_param(osd_left, int, 0444);
82 module_param(osd_yres, int, 0444);
83 module_param(osd_xres, int, 0444);
85 MODULE_PARM_DESC(ivtv_fb_card_id,
86 "Only use framebuffer of the specified ivtv card (0-31)\n"
87 "\t\t\tdefault -1: initialize all available framebuffers");
89 MODULE_PARM_DESC(debug,
90 "Debug level (bitmask). Default: errors only\n"
91 "\t\t\t(debug = 3 gives full debugging)");
93 MODULE_PARM_DESC(osd_compat,
94 "Compatibility mode - Display size is locked (use for old X drivers)\n"
99 /* Why upper, left, xres, yres, depth, laced ? To match terminology used
101 Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
103 MODULE_PARM_DESC(osd_laced,
107 "\t\t\tdefault off");
109 MODULE_PARM_DESC(osd_depth,
110 "Bits per pixel - 8, 16, 32\n"
113 MODULE_PARM_DESC(osd_upper,
114 "Vertical start position\n"
115 "\t\t\tdefault 0 (Centered)");
117 MODULE_PARM_DESC(osd_left,
118 "Horizontal start position\n"
119 "\t\t\tdefault 0 (Centered)");
121 MODULE_PARM_DESC(osd_yres,
123 "\t\t\tdefault 480 (PAL)\n"
124 "\t\t\t 400 (NTSC)");
126 MODULE_PARM_DESC(osd_xres,
128 "\t\t\tdefault 640");
130 MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
131 MODULE_LICENSE("GPL");
133 /* --------------------------------------------------------------------- */
135 #define IVTV_FB_DBGFLG_WARN (1 << 0)
136 #define IVTV_FB_DBGFLG_INFO (1 << 1)
138 #define IVTV_FB_DEBUG(x, type, fmt, args...) \
140 if ((x) & ivtv_fb_debug) \
141 printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \
143 #define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args)
144 #define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args)
146 /* Standard kernel messages */
147 #define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args)
148 #define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args)
149 #define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args)
151 /* --------------------------------------------------------------------- */
153 #define IVTV_OSD_MAX_WIDTH 720
154 #define IVTV_OSD_MAX_HEIGHT 576
156 #define IVTV_OSD_BPP_8 0x00
157 #define IVTV_OSD_BPP_16_444 0x03
158 #define IVTV_OSD_BPP_16_555 0x02
159 #define IVTV_OSD_BPP_16_565 0x01
160 #define IVTV_OSD_BPP_32 0x04
163 /* Physical base address */
164 unsigned long video_pbase;
165 /* Relative base address (relative to start of decoder memory) */
167 /* Mapped base address */
168 volatile char __iomem *video_vbase;
170 u32 video_buffer_size;
173 /* video_base rounded down as required by hardware MTRRs */
174 unsigned long fb_start_aligned_physaddr;
175 /* video_base rounded up as required by hardware MTRRs */
176 unsigned long fb_end_aligned_physaddr;
179 /* Current osd mode */
182 /* Store the buffer offset */
183 int set_osd_coords_x;
184 int set_osd_coords_y;
186 /* Current dimensions (NOT VISIBLE SIZE!) */
189 int display_byte_stride;
191 /* Current bits per pixel */
195 /* Frame buffer stuff */
196 struct fb_info ivtvfb_info;
197 struct fb_var_screeninfo ivtvfb_defined;
198 struct fb_fix_screeninfo ivtvfb_fix;
201 struct ivtv_osd_coords {
202 unsigned long offset;
203 unsigned long max_offset;
210 /* --------------------------------------------------------------------- */
212 /* ivtv API calls for framebuffer related support */
214 static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
217 u32 data[CX2341X_MBOX_MAX_DATA];
220 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
226 static int ivtv_fb_get_osd_coords(struct ivtv *itv,
227 struct ivtv_osd_coords *osd)
229 struct osd_info *oi = itv->osd_info;
230 u32 data[CX2341X_MBOX_MAX_DATA];
232 ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
234 osd->offset = data[0] - oi->video_rbase;
235 osd->max_offset = oi->display_width * oi->display_height * 4;
236 osd->pixel_stride = data[1];
237 osd->lines = data[2];
243 static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
245 struct osd_info *oi = itv->osd_info;
247 oi->display_width = osd->pixel_stride;
248 oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
249 oi->set_osd_coords_x += osd->x;
250 oi->set_osd_coords_y = osd->y;
252 return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
253 osd->offset + oi->video_rbase,
255 osd->lines, osd->x, osd->y);
258 static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
260 int osd_height_limit = itv->is_50hz ? 576 : 480;
262 /* Only fail if resolution too high, otherwise fudge the start coords. */
263 if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
266 /* Ensure we don't exceed display limits */
267 if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
268 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
269 ivtv_window->top, ivtv_window->height);
270 ivtv_window->top = osd_height_limit - ivtv_window->height;
273 if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
274 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
275 ivtv_window->left, ivtv_window->width);
276 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
279 /* Set the OSD origin */
280 write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
282 /* How much to display */
283 write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
285 /* Pass this info back the yuv handler */
286 itv->yuv_info.osd_vis_w = ivtv_window->width;
287 itv->yuv_info.osd_vis_h = ivtv_window->height;
288 itv->yuv_info.osd_x_offset = ivtv_window->left;
289 itv->yuv_info.osd_y_offset = ivtv_window->top;
294 static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv,
295 unsigned long ivtv_dest_addr, void __user *userbuf,
302 mutex_lock(&itv->udma.lock);
304 if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
305 mutex_unlock(&itv->udma.lock);
306 IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, "
307 "Error with get_user_pages: %d bytes, %d pages returned\n",
308 size_in_bytes, itv->udma.page_count);
310 /* get_user_pages must have failed completely */
314 IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
315 size_in_bytes, itv->udma.page_count);
317 ivtv_udma_prepare(itv);
318 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
319 /* if no UDMA is pending and no UDMA is in progress, then the DMA
321 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
322 /* don't interrupt if the DMA is in progress but break off
323 a still pending DMA. */
324 got_sig = signal_pending(current);
325 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
330 finish_wait(&itv->dma_waitq, &wait);
332 /* Unmap Last DMA Xfer */
333 ivtv_udma_unmap(itv);
334 mutex_unlock(&itv->udma.lock);
336 IVTV_DEBUG_INFO("User stopped OSD\n");
343 static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
344 unsigned long dest_offset, int count)
347 struct osd_info *oi = itv->osd_info;
351 IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n");
355 /* Check Total FB Size */
356 if ((dest_offset + count) > oi->video_buffer_size) {
357 IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
358 dest_offset + count, oi->video_buffer_size);
362 /* Not fatal, but will have undesirable results */
363 if ((unsigned long)source & 3)
364 IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
365 (unsigned long)source);
368 IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
371 IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count);
374 if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
375 IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n",
376 (unsigned long)source);
378 IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
379 dest_offset, (unsigned long)source,
384 /* OSD Address to send DMA to */
385 dest_offset += IVTV_DEC_MEM_START + oi->video_rbase;
388 return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count);
391 static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
394 struct ivtv *itv = (struct ivtv *)info->par;
398 case FBIOGET_VBLANK: {
399 struct fb_vblank vblank;
402 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
403 FB_VBLANK_HAVE_VSYNC;
404 trace = read_reg(0x028c0) >> 16;
405 if (itv->is_50hz && trace > 312) trace -= 312;
406 else if (itv->is_60hz && trace > 262) trace -= 262;
407 if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
408 vblank.count = itv->lastVsyncFrame;
409 vblank.vcount = trace;
411 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
416 case FBIO_WAITFORVSYNC:
417 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
418 if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
419 finish_wait(&itv->vsync_waitq, &wait);
422 case IVTVFB_IOC_DMA_FRAME: {
423 struct ivtvfb_dma_frame args;
425 IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
426 if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
429 return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
433 IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
439 /* Framebuffer device handling */
441 static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
443 struct osd_info *oi = itv->osd_info;
444 struct ivtv_osd_coords ivtv_osd;
445 struct v4l2_rect ivtv_window;
448 IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n");
450 /* Select color space */
451 if (var->nonstd) /* YUV */
452 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
454 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
456 /* Set the color mode */
457 switch (var->bits_per_pixel) {
459 osd_mode = IVTV_OSD_BPP_8;
462 osd_mode = IVTV_OSD_BPP_32;
465 switch (var->green.length) {
467 osd_mode = IVTV_OSD_BPP_16_444;
470 osd_mode = IVTV_OSD_BPP_16_555;
473 osd_mode = IVTV_OSD_BPP_16_565;
476 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
480 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
483 /* Change osd mode if needed.
484 Although rare, things can go wrong. The extra mode
485 change seems to help... */
486 if (osd_mode != -1 && osd_mode != oi->osd_mode) {
487 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
488 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
489 oi->osd_mode = osd_mode;
492 oi->bits_per_pixel = var->bits_per_pixel;
493 oi->bytes_per_pixel = var->bits_per_pixel / 8;
495 /* Set the flicker filter */
496 switch (var->vmode & FB_VMODE_MASK) {
497 case FB_VMODE_NONINTERLACED: /* Filter on */
498 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
500 case FB_VMODE_INTERLACED: /* Filter off */
501 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
504 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
507 /* Read the current osd info */
508 ivtv_fb_get_osd_coords(itv, &ivtv_osd);
510 /* Now set the OSD to the size we want */
511 ivtv_osd.pixel_stride = var->xres_virtual;
512 ivtv_osd.lines = var->yres_virtual;
515 ivtv_fb_set_osd_coords(itv, &ivtv_osd);
517 /* Can't seem to find the right API combo for this.
518 Use another function which does what we need through direct register access. */
519 ivtv_window.width = var->xres;
520 ivtv_window.height = var->yres;
522 /* Minimum margin cannot be 0, as X won't allow such a mode */
523 if (!var->upper_margin) var->upper_margin++;
524 if (!var->left_margin) var->left_margin++;
525 ivtv_window.top = var->upper_margin - 1;
526 ivtv_window.left = var->left_margin - 1;
528 ivtv_fb_set_display_window(itv, &ivtv_window);
530 /* Force update of yuv registers */
531 itv->yuv_info.yuv_forced_update = 1;
533 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
534 var->xres, var->yres,
535 var->xres_virtual, var->yres_virtual,
536 var->bits_per_pixel);
538 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
539 var->left_margin, var->upper_margin);
541 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
542 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
543 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
548 static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
550 struct osd_info *oi = itv->osd_info;
552 IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n");
553 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
554 strcpy(fix->id, "cx23415 TV out");
555 fix->smem_start = oi->video_pbase;
556 fix->smem_len = oi->video_buffer_size;
557 fix->type = FB_TYPE_PACKED_PIXELS;
558 fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
562 fix->line_length = oi->display_byte_stride;
563 fix->accel = FB_ACCEL_NONE;
567 /* Check the requested display mode, returning -EINVAL if we can't
570 static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
572 struct osd_info *oi = itv->osd_info;
573 int osd_height_limit;
574 u32 pixclock, hlimit, vlimit;
576 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
578 /* Set base references for mode calcs. */
583 osd_height_limit = 576;
589 osd_height_limit = 480;
592 /* Check the bits per pixel */
594 if (var->bits_per_pixel != 32) {
595 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
600 if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
601 var->transp.offset = 24;
602 var->transp.length = 8;
603 var->red.offset = 16;
605 var->green.offset = 8;
606 var->green.length = 8;
607 var->blue.offset = 0;
608 var->blue.length = 8;
610 else if (var->bits_per_pixel == 16) {
611 /* To find out the true mode, check green length */
612 switch (var->green.length) {
616 var->green.offset = 4;
617 var->green.length = 4;
618 var->blue.offset = 0;
619 var->blue.length = 4;
620 var->transp.offset = 12;
621 var->transp.length = 1;
624 var->red.offset = 10;
626 var->green.offset = 5;
627 var->green.length = 5;
628 var->blue.offset = 0;
629 var->blue.length = 5;
630 var->transp.offset = 15;
631 var->transp.length = 1;
634 var->red.offset = 11;
636 var->green.offset = 5;
637 var->green.length = 6;
638 var->blue.offset = 0;
639 var->blue.length = 5;
640 var->transp.offset = 0;
641 var->transp.length = 0;
646 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
650 /* Check the resolution */
652 if (var->xres != oi->ivtvfb_defined.xres ||
653 var->yres != oi->ivtvfb_defined.yres ||
654 var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
655 var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
656 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
657 var->xres, var->yres, var->xres_virtual, var->yres_virtual);
662 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
663 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n",
664 var->xres, var->yres);
668 /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
669 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
670 var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
671 var->xres_virtual < var->xres ||
672 var->yres_virtual < var->yres) {
673 IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
674 var->xres_virtual, var->yres_virtual);
679 /* Some extra checks if in 8 bit mode */
680 if (var->bits_per_pixel == 8) {
681 /* Width must be a multiple of 4 */
683 IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
686 if (var->xres_virtual & 3) {
687 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
691 else if (var->bits_per_pixel == 16) {
692 /* Width must be a multiple of 2 */
694 IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
697 if (var->xres_virtual & 1) {
698 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
703 /* Now check the offsets */
704 if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
705 IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
706 var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
710 /* Check pixel format */
711 if (var->nonstd > 1) {
712 IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
716 /* Check video mode */
717 if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
718 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
719 IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
723 /* Check the left & upper margins
724 If the margins are too large, just center the screen
725 (enforcing margins causes too many problems) */
727 if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
728 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
730 if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
731 var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
734 /* Maintain overall 'size' for a constant refresh rate */
735 var->right_margin = hlimit - var->left_margin - var->xres;
736 var->lower_margin = vlimit - var->upper_margin - var->yres;
738 /* Fixed sync times */
742 /* Non-interlaced / interlaced mode is used to switch the OSD filter
743 on or off. Adjust the clock timings to maintain a constant
744 vertical refresh rate. */
745 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
746 var->pixclock = pixclock / 2;
748 var->pixclock = pixclock;
750 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
751 var->xres, var->yres,
752 var->xres_virtual, var->yres_virtual,
753 var->bits_per_pixel);
755 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
756 var->left_margin, var->upper_margin);
758 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
759 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
760 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
764 static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
766 struct ivtv *itv = (struct ivtv *) info->par;
767 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
768 return _ivtvfb_check_var(var, itv);
771 static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
774 struct ivtv *itv = (struct ivtv *) info->par;
776 osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
777 write_reg(osd_pan_index, 0x02A0C);
779 /* Pass this info back the yuv handler */
780 itv->yuv_info.osd_x_pan = var->xoffset;
781 itv->yuv_info.osd_y_pan = var->yoffset;
782 /* Force update of yuv registers */
783 itv->yuv_info.yuv_forced_update = 1;
787 static int ivtvfb_set_par(struct fb_info *info)
790 struct ivtv *itv = (struct ivtv *) info->par;
792 IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n");
794 rc = ivtvfb_set_var(itv, &info->var);
795 ivtvfb_pan_display(&info->var, info);
796 ivtvfb_get_fix(itv, &info->fix);
800 static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
801 unsigned blue, unsigned transp,
802 struct fb_info *info)
805 struct ivtv *itv = (struct ivtv *)info->par;
807 if (regno >= info->cmap.len)
810 color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
811 if (info->var.bits_per_pixel <= 8) {
812 write_reg(regno, 0x02a30);
813 write_reg(color, 0x02a34);
819 palette = info->pseudo_palette;
820 if (info->var.bits_per_pixel == 16) {
821 switch (info->var.green.length) {
823 color = ((red & 0xf000) >> 4) |
824 ((green & 0xf000) >> 8) |
825 ((blue & 0xf000) >> 12);
828 color = ((red & 0xf800) >> 1) |
829 ((green & 0xf800) >> 6) |
830 ((blue & 0xf800) >> 11);
833 color = (red & 0xf800 ) |
834 ((green & 0xfc00) >> 5) |
835 ((blue & 0xf800) >> 11);
839 palette[regno] = color;
843 /* We don't really support blanking. All this does is enable or
845 static int ivtvfb_blank(int blank_mode, struct fb_info *info)
847 struct ivtv *itv = (struct ivtv *)info->par;
849 IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
850 switch (blank_mode) {
851 case FB_BLANK_UNBLANK:
852 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
854 case FB_BLANK_NORMAL:
855 case FB_BLANK_HSYNC_SUSPEND:
856 case FB_BLANK_VSYNC_SUSPEND:
857 case FB_BLANK_POWERDOWN:
858 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
864 static struct fb_ops ivtvfb_ops = {
865 .owner = THIS_MODULE,
866 .fb_check_var = ivtvfb_check_var,
867 .fb_set_par = ivtvfb_set_par,
868 .fb_setcolreg = ivtvfb_setcolreg,
869 .fb_fillrect = cfb_fillrect,
870 .fb_copyarea = cfb_copyarea,
871 .fb_imageblit = cfb_imageblit,
873 .fb_ioctl = ivtvfb_ioctl,
874 .fb_pan_display = ivtvfb_pan_display,
875 .fb_blank = ivtvfb_blank,
881 /* Setup our initial video mode */
882 static int ivtvfb_init_vidmode(struct ivtv *itv)
884 struct osd_info *oi = itv->osd_info;
885 struct v4l2_rect start_window;
890 if (osd_compat) osd_depth = 32;
891 if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
892 oi->bits_per_pixel = osd_depth;
893 oi->bytes_per_pixel = oi->bits_per_pixel / 8;
895 /* Invalidate current osd mode to force a mode switch later */
898 /* Horizontal size & position */
900 if (osd_xres > 720) osd_xres = 720;
902 /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
905 else if (osd_depth == 16)
909 start_window.width = osd_xres;
911 start_window.width = osd_compat ? 720: 640;
913 /* Check horizontal start (osd_left). */
914 if (osd_left && osd_left + start_window.width > 721) {
915 IVTV_FB_ERR("Invalid osd_left - assuming default\n");
919 /* Hardware coords start at 0, user coords start at 1. */
922 start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
924 oi->display_byte_stride =
925 start_window.width * oi->bytes_per_pixel;
927 /* Vertical size & position */
929 max_height = itv->is_50hz ? 576 : 480;
931 if (osd_yres > max_height)
932 osd_yres = max_height;
935 start_window.height = osd_yres;
937 start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
939 /* Check vertical start (osd_upper). */
940 if (osd_upper + start_window.height > max_height + 1) {
941 IVTV_FB_ERR("Invalid osd_upper - assuming default\n");
945 /* Hardware coords start at 0, user coords start at 1. */
948 start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
950 oi->display_width = start_window.width;
951 oi->display_height = start_window.height;
953 /* Generate a valid fb_var_screeninfo */
955 oi->ivtvfb_defined.xres = oi->display_width;
956 oi->ivtvfb_defined.yres = oi->display_height;
957 oi->ivtvfb_defined.xres_virtual = oi->display_width;
958 oi->ivtvfb_defined.yres_virtual = oi->display_height;
959 oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
960 oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
961 oi->ivtvfb_defined.left_margin = start_window.left + 1;
962 oi->ivtvfb_defined.upper_margin = start_window.top + 1;
963 oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
964 oi->ivtvfb_defined.nonstd = 0;
966 /* We've filled in the most data, let the usual mode check
967 routine fill in the rest. */
968 _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
970 /* Generate valid fb_fix_screeninfo */
972 ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
974 /* Generate valid fb_info */
976 oi->ivtvfb_info.node = -1;
977 oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
978 oi->ivtvfb_info.fbops = &ivtvfb_ops;
979 oi->ivtvfb_info.par = itv;
980 oi->ivtvfb_info.var = oi->ivtvfb_defined;
981 oi->ivtvfb_info.fix = oi->ivtvfb_fix;
982 oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
983 oi->ivtvfb_info.fbops = &ivtvfb_ops;
985 /* Supply some monitor specs. Bogus values will do for now */
986 oi->ivtvfb_info.monspecs.hfmin = 8000;
987 oi->ivtvfb_info.monspecs.hfmax = 70000;
988 oi->ivtvfb_info.monspecs.vfmin = 10;
989 oi->ivtvfb_info.monspecs.vfmax = 100;
991 /* Allocate color map */
992 if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
993 IVTV_FB_ERR("abort, unable to alloc cmap\n");
997 /* Allocate the pseudo palette */
998 oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
1000 if (!oi->ivtvfb_info.pseudo_palette) {
1001 IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n");
1008 /* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
1010 static int ivtvfb_init_io(struct ivtv *itv)
1012 struct osd_info *oi = itv->osd_info;
1014 if (ivtv_init_on_first_open(itv)) {
1015 IVTV_FB_ERR("Failed to initialize ivtv\n");
1019 ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
1021 /* The osd buffer size depends on the number of video buffers allocated
1022 on the PVR350 itself. For now we'll hardcode the smallest osd buffer
1023 size to prevent any overlap. */
1024 oi->video_buffer_size = 1704960;
1026 oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1027 oi->video_vbase = itv->dec_mem + oi->video_rbase;
1029 if (!oi->video_vbase) {
1030 IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1031 oi->video_buffer_size, oi->video_pbase);
1035 IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1036 oi->video_pbase, oi->video_vbase,
1037 oi->video_buffer_size / 1024);
1041 /* Find the largest power of two that maps the whole buffer */
1042 int size_shift = 31;
1044 while (!(oi->video_buffer_size & (1 << size_shift))) {
1048 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1049 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1050 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1051 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1052 if (mtrr_add(oi->fb_start_aligned_physaddr,
1053 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
1054 MTRR_TYPE_WRCOMB, 1) < 0) {
1055 IVTV_FB_WARN("cannot use mttr\n");
1056 oi->fb_start_aligned_physaddr = 0;
1057 oi->fb_end_aligned_physaddr = 0;
1062 /* Blank the entire osd. */
1063 memset_io(oi->video_vbase, 0, oi->video_buffer_size);
1068 /* Release any memory we've grabbed & remove mtrr entry */
1069 static void ivtvfb_release_buffers (struct ivtv *itv)
1071 struct osd_info *oi = itv->osd_info;
1074 if (oi->ivtvfb_info.cmap.len);
1075 fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
1077 /* Release pseudo palette */
1078 if (oi->ivtvfb_info.pseudo_palette)
1079 kfree(oi->ivtvfb_info.pseudo_palette);
1082 if (oi->fb_end_aligned_physaddr) {
1083 mtrr_del(-1, oi->fb_start_aligned_physaddr,
1084 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1089 itv->osd_info = NULL;
1092 /* Initialize the specified card */
1094 static int ivtvfb_init_card(struct ivtv *itv)
1098 if (itv->osd_info) {
1099 IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id);
1103 itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
1104 if (itv->osd_info == 0) {
1105 IVTV_FB_ERR("Failed to allocate memory for osd_info\n");
1109 /* Find & setup the OSD buffer */
1110 if ((rc = ivtvfb_init_io(itv)))
1113 /* Set the startup video mode information */
1114 if ((rc = ivtvfb_init_vidmode(itv))) {
1115 ivtvfb_release_buffers(itv);
1119 /* Register the framebuffer */
1120 if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1121 ivtvfb_release_buffers(itv);
1125 itv->osd_video_pbase = itv->osd_info->video_pbase;
1127 /* Set the card to the requested mode */
1128 ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1130 /* Set color 0 to black */
1131 write_reg(0, 0x02a30);
1132 write_reg(0, 0x02a34);
1134 /* Enable the osd */
1135 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1137 /* Note if we're running in compatibility mode */
1139 IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
1142 ivtv_udma_alloc(itv);
1147 static int __init ivtvfb_init(void)
1150 int i, registered = 0;
1152 if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) {
1153 printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n",
1154 IVTV_MAX_CARDS - 1);
1158 /* Locate & initialise all cards supporting an OSD. */
1159 for (i = 0; i < ivtv_cards_active; i++) {
1160 if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id)
1162 itv = ivtv_cards[i];
1163 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1164 if (ivtvfb_init_card(itv) == 0) {
1165 IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i);
1171 printk(KERN_ERR "ivtv-fb: no cards found");
1177 static void ivtvfb_cleanup(void)
1182 printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n");
1184 for (i = 0; i < ivtv_cards_active; i++) {
1185 itv = ivtv_cards[i];
1186 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
1187 IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i);
1188 ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
1189 unregister_framebuffer(&itv->osd_info->ivtvfb_info);
1190 ivtvfb_release_buffers(itv);
1191 itv->osd_video_pbase = 0;
1196 module_init(ivtvfb_init);
1197 module_exit(ivtvfb_cleanup);