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-queue.h"
61 #include "ivtv-udma.h"
63 #include "ivtv-fileops.h"
64 #include "ivtv-mailbox.h"
65 #include "ivtv-cards.h"
66 #include <media/ivtv-fb.h>
69 static int ivtv_fb_card_id = -1;
70 static int ivtv_fb_debug = 0;
72 static int osd_compat;
79 module_param(ivtv_fb_card_id, int, 0444);
80 module_param_named(debug,ivtv_fb_debug, int, 0644);
81 module_param(osd_laced, bool, 0444);
82 module_param(osd_compat, bool, 0444);
83 module_param(osd_depth, int, 0444);
84 module_param(osd_upper, int, 0444);
85 module_param(osd_left, int, 0444);
86 module_param(osd_yres, int, 0444);
87 module_param(osd_xres, int, 0444);
89 MODULE_PARM_DESC(ivtv_fb_card_id,
90 "Only use framebuffer of the specified ivtv card (0-31)\n"
91 "\t\t\tdefault -1: initialize all available framebuffers");
93 MODULE_PARM_DESC(debug,
94 "Debug level (bitmask). Default: errors only\n"
95 "\t\t\t(debug = 3 gives full debugging)");
97 MODULE_PARM_DESC(osd_compat,
98 "Compatibility mode - Display size is locked (use for old X drivers)\n"
101 "\t\t\tdefault off");
103 /* Why upper, left, xres, yres, depth, laced ? To match terminology used
105 Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
107 MODULE_PARM_DESC(osd_laced,
111 "\t\t\tdefault off");
113 MODULE_PARM_DESC(osd_depth,
114 "Bits per pixel - 8, 16, 32\n"
117 MODULE_PARM_DESC(osd_upper,
118 "Vertical start position\n"
119 "\t\t\tdefault 0 (Centered)");
121 MODULE_PARM_DESC(osd_left,
122 "Horizontal start position\n"
123 "\t\t\tdefault 0 (Centered)");
125 MODULE_PARM_DESC(osd_yres,
127 "\t\t\tdefault 480 (PAL)\n"
128 "\t\t\t 400 (NTSC)");
130 MODULE_PARM_DESC(osd_xres,
132 "\t\t\tdefault 640");
134 MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
135 MODULE_LICENSE("GPL");
137 /* --------------------------------------------------------------------- */
139 #define IVTV_FB_DBGFLG_WARN (1 << 0)
140 #define IVTV_FB_DBGFLG_INFO (1 << 1)
142 #define IVTV_FB_DEBUG(x, type, fmt, args...) \
144 if ((x) & ivtv_fb_debug) \
145 printk(KERN_INFO "ivtv-fb%d " type ": " fmt, itv->num , ## args); \
147 #define IVTV_FB_DEBUG_WARN(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_WARN, "warning", fmt , ## args)
148 #define IVTV_FB_DEBUG_INFO(fmt, args...) IVTV_FB_DEBUG(IVTV_FB_DBGFLG_INFO, "info", fmt , ## args)
150 /* Standard kernel messages */
151 #define IVTV_FB_ERR(fmt, args...) printk(KERN_ERR "ivtv-fb%d: " fmt, itv->num , ## args)
152 #define IVTV_FB_WARN(fmt, args...) printk(KERN_WARNING "ivtv-fb%d: " fmt, itv->num , ## args)
153 #define IVTV_FB_INFO(fmt, args...) printk(KERN_INFO "ivtv-fb%d: " fmt, itv->num , ## args)
155 /* --------------------------------------------------------------------- */
157 #define IVTV_OSD_MAX_WIDTH 720
158 #define IVTV_OSD_MAX_HEIGHT 576
160 #define IVTV_OSD_BPP_8 0x00
161 #define IVTV_OSD_BPP_16_444 0x03
162 #define IVTV_OSD_BPP_16_555 0x02
163 #define IVTV_OSD_BPP_16_565 0x01
164 #define IVTV_OSD_BPP_32 0x04
167 /* Timing info for modes */
172 /* Physical base address */
173 unsigned long video_pbase;
174 /* Relative base address (relative to start of decoder memory) */
176 /* Mapped base address */
177 volatile char __iomem *video_vbase;
179 u32 video_buffer_size;
182 /* video_base rounded down as required by hardware MTRRs */
183 unsigned long fb_start_aligned_physaddr;
184 /* video_base rounded up as required by hardware MTRRs */
185 unsigned long fb_end_aligned_physaddr;
188 /* Store the buffer offset */
189 int set_osd_coords_x;
190 int set_osd_coords_y;
192 /* Current dimensions (NOT VISIBLE SIZE!) */
195 int display_byte_stride;
197 /* Current bits per pixel */
201 /* Frame buffer stuff */
202 struct fb_info ivtvfb_info;
203 struct fb_var_screeninfo ivtvfb_defined;
204 struct fb_fix_screeninfo ivtvfb_fix;
207 struct ivtv_osd_coords {
208 unsigned long offset;
209 unsigned long max_offset;
216 /* --------------------------------------------------------------------- */
218 /* ivtv API calls for framebuffer related support */
220 static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
223 u32 data[CX2341X_MBOX_MAX_DATA];
226 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
232 static int ivtv_fb_get_osd_coords(struct ivtv *itv,
233 struct ivtv_osd_coords *osd)
235 struct osd_info *oi = itv->osd_info;
236 u32 data[CX2341X_MBOX_MAX_DATA];
238 ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
240 osd->offset = data[0] - oi->video_rbase;
241 osd->max_offset = oi->display_width * oi->display_height * 4;
242 osd->pixel_stride = data[1];
243 osd->lines = data[2];
249 static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
251 struct osd_info *oi = itv->osd_info;
253 oi->display_width = osd->pixel_stride;
254 oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
255 oi->set_osd_coords_x += osd->x;
256 oi->set_osd_coords_y = osd->y;
258 return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
259 osd->offset + oi->video_rbase,
261 osd->lines, osd->x, osd->y);
264 static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
266 int osd_height_limit = itv->is_50hz ? 576 : 480;
268 /* Only fail if resolution too high, otherwise fudge the start coords. */
269 if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
272 /* Ensure we don't exceed display limits */
273 if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
274 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
275 ivtv_window->top, ivtv_window->height);
276 ivtv_window->top = osd_height_limit - ivtv_window->height;
279 if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
280 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
281 ivtv_window->left, ivtv_window->width);
282 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
285 /* Set the OSD origin */
286 write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
288 /* How much to display */
289 write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
291 /* Pass this info back the yuv handler */
292 itv->yuv_info.osd_vis_w = ivtv_window->width;
293 itv->yuv_info.osd_vis_h = ivtv_window->height;
294 itv->yuv_info.osd_x_offset = ivtv_window->left;
295 itv->yuv_info.osd_y_offset = ivtv_window->top;
300 static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv,
301 unsigned long ivtv_dest_addr, void __user *userbuf,
308 mutex_lock(&itv->udma.lock);
310 if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
311 mutex_unlock(&itv->udma.lock);
312 IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, "
313 "Error with get_user_pages: %d bytes, %d pages returned\n",
314 size_in_bytes, itv->udma.page_count);
316 /* get_user_pages must have failed completely */
320 IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
321 size_in_bytes, itv->udma.page_count);
323 ivtv_udma_prepare(itv);
324 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
325 /* if no UDMA is pending and no UDMA is in progress, then the DMA
327 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
328 /* don't interrupt if the DMA is in progress but break off
329 a still pending DMA. */
330 got_sig = signal_pending(current);
331 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
336 finish_wait(&itv->dma_waitq, &wait);
338 /* Unmap Last DMA Xfer */
339 ivtv_udma_unmap(itv);
340 mutex_unlock(&itv->udma.lock);
342 IVTV_DEBUG_INFO("User stopped OSD\n");
349 static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
350 unsigned long dest_offset, int count)
356 IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n");
360 /* Check Total FB Size */
361 if ((dest_offset + count) > itv->osd_info->video_buffer_size) {
362 IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
363 dest_offset + count, itv->osd_info->video_buffer_size);
367 /* Not fatal, but will have undesirable results */
368 if ((unsigned long)source & 3)
369 IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
370 (unsigned long)source);
373 IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
376 IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count);
379 if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
380 IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n",
381 (unsigned long)source);
383 IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
384 dest_offset, (unsigned long)source,
389 /* OSD Address to send DMA to */
390 dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase;
393 return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count);
396 static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
399 struct ivtv *itv = (struct ivtv *)info->par;
403 case FBIOGET_VBLANK: {
404 struct fb_vblank vblank;
407 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
408 FB_VBLANK_HAVE_VSYNC;
409 trace = read_reg(0x028c0) >> 16;
410 if (itv->is_50hz && trace > 312) trace -= 312;
411 else if (itv->is_60hz && trace > 262) trace -= 262;
412 if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
413 vblank.count = itv->lastVsyncFrame;
414 vblank.vcount = trace;
416 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
421 case FBIO_WAITFORVSYNC:
422 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
423 if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
424 finish_wait(&itv->vsync_waitq, &wait);
427 case IVTVFB_IOC_DMA_FRAME: {
428 struct ivtvfb_dma_frame args;
430 IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
431 if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
434 return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
438 IVTV_FB_ERR("Unknown IOCTL %d\n", cmd);
444 /* Framebuffer device handling */
446 static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
448 struct ivtv_osd_coords ivtv_osd;
449 struct v4l2_rect ivtv_window;
451 IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n");
453 /* Select color space */
454 if (var->nonstd) /* YUV */
455 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
457 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
459 /* Set the color mode
460 Although rare, occasionally things go wrong. The extra mode
461 change seems to help... */
463 switch (var->bits_per_pixel) {
465 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
466 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8);
469 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
470 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32);
473 switch (var->green.length) {
475 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
476 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444);
479 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
480 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555);
483 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
484 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565);
487 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
491 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
494 itv->osd_info->bits_per_pixel = var->bits_per_pixel;
495 itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8;
497 /* Set the flicker filter */
498 switch (var->vmode & FB_VMODE_MASK) {
499 case FB_VMODE_NONINTERLACED: /* Filter on */
500 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
502 case FB_VMODE_INTERLACED: /* Filter off */
503 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
506 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
509 /* Read the current osd info */
510 ivtv_fb_get_osd_coords(itv, &ivtv_osd);
512 /* Now set the OSD to the size we want */
513 ivtv_osd.pixel_stride = var->xres_virtual;
514 ivtv_osd.lines = var->yres_virtual;
517 ivtv_fb_set_osd_coords(itv, &ivtv_osd);
519 /* Can't seem to find the right API combo for this.
520 Use another function which does what we need through direct register access. */
521 ivtv_window.width = var->xres;
522 ivtv_window.height = var->yres;
524 /* Minimum margin cannot be 0, as X won't allow such a mode */
525 if (!var->upper_margin) var->upper_margin++;
526 if (!var->left_margin) var->left_margin++;
527 ivtv_window.top = var->upper_margin - 1;
528 ivtv_window.left = var->left_margin - 1;
530 ivtv_fb_set_display_window(itv, &ivtv_window);
532 /* Force update of yuv registers */
533 itv->yuv_info.yuv_forced_update = 1;
535 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
536 var->xres, var->yres,
537 var->xres_virtual, var->yres_virtual,
538 var->bits_per_pixel);
540 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
541 var->left_margin, var->upper_margin);
543 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
544 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
545 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
550 static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
552 struct osd_info *oi = itv->osd_info;
554 IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n");
555 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
556 strcpy(fix->id, "cx23415 TV out");
557 fix->smem_start = oi->video_pbase;
558 fix->smem_len = oi->video_buffer_size;
559 fix->type = FB_TYPE_PACKED_PIXELS;
560 fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
564 fix->line_length = oi->display_byte_stride;
565 fix->accel = FB_ACCEL_NONE;
569 /* Check the requested display mode, returning -EINVAL if we can't
572 static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
574 struct osd_info *oi = itv->osd_info;
575 int osd_height_limit = itv->is_50hz ? 576 : 480;
577 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
579 /* Check the bits per pixel */
581 if (var->bits_per_pixel != 32) {
582 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
587 if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
588 var->transp.offset = 24;
589 var->transp.length = 8;
590 var->red.offset = 16;
592 var->green.offset = 8;
593 var->green.length = 8;
594 var->blue.offset = 0;
595 var->blue.length = 8;
597 else if (var->bits_per_pixel == 16) {
598 var->transp.offset = 0;
599 var->transp.length = 0;
601 /* To find out the true mode, check green length */
602 switch (var->green.length) {
606 var->green.offset = 4;
607 var->green.length = 4;
608 var->blue.offset = 0;
609 var->blue.length = 4;
612 var->red.offset = 10;
614 var->green.offset = 5;
615 var->green.length = 5;
616 var->blue.offset = 0;
617 var->blue.length = 5;
620 var->red.offset = 11;
622 var->green.offset = 5;
623 var->green.length = 6;
624 var->blue.offset = 0;
625 var->blue.length = 5;
630 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
634 /* Check the resolution */
636 if (var->xres != oi->ivtvfb_defined.xres ||
637 var->yres != oi->ivtvfb_defined.yres ||
638 var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
639 var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
640 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
641 var->xres, var->yres, var->xres_virtual, var->yres_virtual);
646 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
647 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n",
648 var->xres, var->yres);
652 /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
653 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
654 var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
655 var->xres_virtual < var->xres ||
656 var->yres_virtual < var->yres) {
657 IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
658 var->xres_virtual, var->yres_virtual);
663 /* Some extra checks if in 8 bit mode */
664 if (var->bits_per_pixel == 8) {
665 /* Width must be a multiple of 4 */
667 IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
670 if (var->xres_virtual & 3) {
671 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
675 else if (var->bits_per_pixel == 16) {
676 /* Width must be a multiple of 2 */
678 IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
681 if (var->xres_virtual & 1) {
682 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
687 /* Now check the offsets */
688 if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
689 IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
690 var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
694 /* Check pixel format */
695 if (var->nonstd > 1) {
696 IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
700 /* Check video mode */
701 if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
702 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
703 IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
707 /* Check the left & upper margins
708 If the margins are too large, just center the screen
709 (enforcing margins causes too many problems) */
711 if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
712 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
714 if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
715 var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
718 /* Maintain overall 'size' for a constant refresh rate */
719 var->right_margin = oi->hlimit - var->left_margin - var->xres;
720 var->lower_margin = oi->vlimit - var->upper_margin - var->yres;
722 /* Fixed sync times */
726 /* Non-interlaced / interlaced mode is used to switch the OSD filter
727 on or off. Adjust the clock timings to maintain a constant
728 vertical refresh rate. */
729 var->pixclock = oi->pixclock;
730 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
733 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
734 var->xres, var->yres,
735 var->xres_virtual, var->yres_virtual,
736 var->bits_per_pixel);
738 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
739 var->left_margin, var->upper_margin);
741 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
742 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
743 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
747 static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
749 struct ivtv *itv = (struct ivtv *) info->par;
750 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
751 return _ivtvfb_check_var(var, itv);
754 static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
757 struct ivtv *itv = (struct ivtv *) info->par;
759 osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
760 write_reg(osd_pan_index, 0x02A0C);
762 /* Pass this info back the yuv handler */
763 itv->yuv_info.osd_x_pan = var->xoffset;
764 itv->yuv_info.osd_y_pan = var->yoffset;
765 /* Force update of yuv registers */
766 itv->yuv_info.yuv_forced_update = 1;
770 static int ivtvfb_set_par(struct fb_info *info)
773 struct ivtv *itv = (struct ivtv *) info->par;
775 IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n");
777 rc = ivtvfb_set_var(itv, &info->var);
778 ivtvfb_pan_display(&info->var, info);
779 ivtvfb_get_fix(itv, &info->fix);
783 static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
784 unsigned blue, unsigned transp,
785 struct fb_info *info)
788 struct ivtv *itv = (struct ivtv *)info->par;
790 if (regno >= info->cmap.len)
793 color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
794 if (info->var.bits_per_pixel <= 8) {
795 write_reg(regno, 0x02a30);
796 write_reg(color, 0x02a34);
802 palette = info->pseudo_palette;
803 if (info->var.bits_per_pixel == 16) {
804 switch (info->var.green.length) {
806 color = ((red & 0xf000) >> 4) |
807 ((green & 0xf000) >> 8) |
808 ((blue & 0xf000) >> 12);
811 color = ((red & 0xf800) >> 1) |
812 ((green & 0xf800) >> 6) |
813 ((blue & 0xf800) >> 11);
816 color = (red & 0xf800 ) |
817 ((green & 0xfc00) >> 5) |
818 ((blue & 0xf800) >> 11);
822 palette[regno] = color;
826 /* We don't really support blanking. All this does is enable or
828 static int ivtvfb_blank(int blank_mode, struct fb_info *info)
830 struct ivtv *itv = (struct ivtv *)info->par;
832 IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
833 switch (blank_mode) {
834 case FB_BLANK_UNBLANK:
835 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
837 case FB_BLANK_NORMAL:
838 case FB_BLANK_HSYNC_SUSPEND:
839 case FB_BLANK_VSYNC_SUSPEND:
840 case FB_BLANK_POWERDOWN:
841 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
847 static struct fb_ops ivtvfb_ops = {
848 .owner = THIS_MODULE,
849 .fb_check_var = ivtvfb_check_var,
850 .fb_set_par = ivtvfb_set_par,
851 .fb_setcolreg = ivtvfb_setcolreg,
852 .fb_fillrect = cfb_fillrect,
853 .fb_copyarea = cfb_copyarea,
854 .fb_imageblit = cfb_imageblit,
856 .fb_ioctl = ivtvfb_ioctl,
857 .fb_pan_display = ivtvfb_pan_display,
858 .fb_blank = ivtvfb_blank,
864 /* Setup our initial video mode */
865 static int ivtvfb_init_vidmode(struct ivtv *itv)
867 struct osd_info *oi = itv->osd_info;
868 struct v4l2_rect start_window;
871 /* Set base references for mode calcs. */
873 oi->pixclock = 84316;
878 oi->pixclock = 83926;
885 if (osd_compat) osd_depth = 32;
886 if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
887 oi->bits_per_pixel = osd_depth;
888 oi->bytes_per_pixel = oi->bits_per_pixel / 8;
890 /* Horizontal size & position */
892 if (osd_xres > 720) osd_xres = 720;
894 /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
897 else if (osd_depth == 16)
901 start_window.width = osd_xres;
903 start_window.width = osd_compat ? 720: 640;
905 /* Check horizontal start (osd_left). */
906 if (osd_left && osd_left + start_window.width > 721) {
907 IVTV_FB_ERR("Invalid osd_left - assuming default\n");
911 /* Hardware coords start at 0, user coords start at 1. */
914 start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
916 oi->display_byte_stride =
917 start_window.width * oi->bytes_per_pixel;
919 /* Vertical size & position */
921 max_height = itv->is_50hz ? 576 : 480;
923 if (osd_yres > max_height)
924 osd_yres = max_height;
927 start_window.height = osd_yres;
929 start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
931 /* Check vertical start (osd_upper). */
932 if (osd_upper + start_window.height > max_height + 1) {
933 IVTV_FB_ERR("Invalid osd_upper - assuming default\n");
937 /* Hardware coords start at 0, user coords start at 1. */
940 start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
942 oi->display_width = start_window.width;
943 oi->display_height = start_window.height;
945 /* Generate a valid fb_var_screeninfo */
947 oi->ivtvfb_defined.xres = oi->display_width;
948 oi->ivtvfb_defined.yres = oi->display_height;
949 oi->ivtvfb_defined.xres_virtual = oi->display_width;
950 oi->ivtvfb_defined.yres_virtual = oi->display_height;
951 oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
952 oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
953 oi->ivtvfb_defined.left_margin = start_window.left + 1;
954 oi->ivtvfb_defined.upper_margin = start_window.top + 1;
955 oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
956 oi->ivtvfb_defined.nonstd = 0;
958 /* We've filled in the most data, let the usual mode check
959 routine fill in the rest. */
960 _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
962 /* Generate valid fb_fix_screeninfo */
964 ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
966 /* Generate valid fb_info */
968 oi->ivtvfb_info.node = -1;
969 oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
970 oi->ivtvfb_info.fbops = &ivtvfb_ops;
971 oi->ivtvfb_info.par = itv;
972 oi->ivtvfb_info.var = oi->ivtvfb_defined;
973 oi->ivtvfb_info.fix = oi->ivtvfb_fix;
974 oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
975 oi->ivtvfb_info.fbops = &ivtvfb_ops;
977 /* Supply some monitor specs. Bogus values will do for now */
978 oi->ivtvfb_info.monspecs.hfmin = 8000;
979 oi->ivtvfb_info.monspecs.hfmax = 70000;
980 oi->ivtvfb_info.monspecs.vfmin = 10;
981 oi->ivtvfb_info.monspecs.vfmax = 100;
983 /* Allocate color map */
984 if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
985 IVTV_FB_ERR("abort, unable to alloc cmap\n");
989 /* Allocate the pseudo palette */
990 oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
992 if (!oi->ivtvfb_info.pseudo_palette) {
993 IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n");
1000 /* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
1002 static int ivtvfb_init_io(struct ivtv *itv)
1004 struct osd_info *oi = itv->osd_info;
1006 ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
1008 /* The osd buffer size depends on the number of video buffers allocated
1009 on the PVR350 itself. For now we'll hardcode the smallest osd buffer
1010 size to prevent any overlap. */
1011 oi->video_buffer_size = 1704960;
1013 oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1014 oi->video_vbase = itv->dec_mem + oi->video_rbase;
1016 if (!oi->video_vbase) {
1017 IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1018 oi->video_buffer_size, oi->video_pbase);
1022 IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1023 oi->video_pbase, oi->video_vbase,
1024 oi->video_buffer_size / 1024);
1028 /* Find the largest power of two that maps the whole buffer */
1029 int size_shift = 31;
1031 while (!(oi->video_buffer_size & (1 << size_shift))) {
1035 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1036 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1037 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1038 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1039 if (mtrr_add(oi->fb_start_aligned_physaddr,
1040 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
1041 MTRR_TYPE_WRCOMB, 1) < 0) {
1042 IVTV_FB_WARN("cannot use mttr\n");
1043 oi->fb_start_aligned_physaddr = 0;
1044 oi->fb_end_aligned_physaddr = 0;
1049 /* Blank the entire osd. */
1050 memset_io(oi->video_vbase, 0, oi->video_buffer_size);
1055 /* Release any memory we've grabbed & remove mtrr entry */
1056 static void ivtvfb_release_buffers (struct ivtv *itv)
1058 struct osd_info *oi = itv->osd_info;
1061 if (oi->ivtvfb_info.cmap.len);
1062 fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
1064 /* Release pseudo palette */
1065 if (oi->ivtvfb_info.pseudo_palette)
1066 kfree(oi->ivtvfb_info.pseudo_palette);
1069 if (oi->fb_end_aligned_physaddr) {
1070 mtrr_del(-1, oi->fb_start_aligned_physaddr,
1071 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1076 itv->osd_info = NULL;
1079 /* Initialize the specified card */
1081 static int ivtvfb_init_card(struct ivtv *itv)
1085 if (itv->osd_info) {
1086 IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id);
1090 itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
1091 if (itv->osd_info == 0) {
1092 IVTV_FB_ERR("Failed to allocate memory for osd_info\n");
1096 /* Find & setup the OSD buffer */
1097 if ((rc = ivtvfb_init_io(itv)))
1100 /* Set the startup video mode information */
1101 if ((rc = ivtvfb_init_vidmode(itv))) {
1102 ivtvfb_release_buffers(itv);
1106 /* Register the framebuffer */
1107 if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1108 ivtvfb_release_buffers(itv);
1112 itv->osd_video_pbase = itv->osd_info->video_pbase;
1114 /* Set the card to the requested mode */
1115 ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1117 /* Set color 0 to black */
1118 write_reg(0, 0x02a30);
1119 write_reg(0, 0x02a34);
1121 /* Enable the osd */
1122 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1124 /* Note if we're running in compatibility mode */
1126 IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
1129 ivtv_udma_alloc(itv);
1134 static int __init ivtvfb_init(void)
1137 int i, registered = 0;
1139 if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) {
1140 printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n",
1141 IVTV_MAX_CARDS - 1);
1145 /* Locate & initialise all cards supporting an OSD. */
1146 for (i = 0; i < ivtv_cards_active; i++) {
1147 if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id)
1149 itv = ivtv_cards[i];
1150 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1151 if (ivtvfb_init_card(itv) == 0) {
1152 IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i);
1158 printk(KERN_ERR "ivtv-fb: no cards found");
1164 static void ivtvfb_cleanup(void)
1169 printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n");
1171 for (i = 0; i < ivtv_cards_active; i++) {
1172 itv = ivtv_cards[i];
1173 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
1174 IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i);
1175 ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
1176 unregister_framebuffer(&itv->osd_info->ivtvfb_info);
1177 ivtvfb_release_buffers(itv);
1178 itv->osd_video_pbase = 0;
1183 module_init(ivtvfb_init);
1184 module_exit(ivtvfb_cleanup);