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 /* Current osd mode */
191 /* Store the buffer offset */
192 int set_osd_coords_x;
193 int set_osd_coords_y;
195 /* Current dimensions (NOT VISIBLE SIZE!) */
198 int display_byte_stride;
200 /* Current bits per pixel */
204 /* Frame buffer stuff */
205 struct fb_info ivtvfb_info;
206 struct fb_var_screeninfo ivtvfb_defined;
207 struct fb_fix_screeninfo ivtvfb_fix;
210 struct ivtv_osd_coords {
211 unsigned long offset;
212 unsigned long max_offset;
219 /* --------------------------------------------------------------------- */
221 /* ivtv API calls for framebuffer related support */
223 static int ivtv_fb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
226 u32 data[CX2341X_MBOX_MAX_DATA];
229 rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
235 static int ivtv_fb_get_osd_coords(struct ivtv *itv,
236 struct ivtv_osd_coords *osd)
238 struct osd_info *oi = itv->osd_info;
239 u32 data[CX2341X_MBOX_MAX_DATA];
241 ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
243 osd->offset = data[0] - oi->video_rbase;
244 osd->max_offset = oi->display_width * oi->display_height * 4;
245 osd->pixel_stride = data[1];
246 osd->lines = data[2];
252 static int ivtv_fb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
254 struct osd_info *oi = itv->osd_info;
256 oi->display_width = osd->pixel_stride;
257 oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
258 oi->set_osd_coords_x += osd->x;
259 oi->set_osd_coords_y = osd->y;
261 return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
262 osd->offset + oi->video_rbase,
264 osd->lines, osd->x, osd->y);
267 static int ivtv_fb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
269 int osd_height_limit = itv->is_50hz ? 576 : 480;
271 /* Only fail if resolution too high, otherwise fudge the start coords. */
272 if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
275 /* Ensure we don't exceed display limits */
276 if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
277 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
278 ivtv_window->top, ivtv_window->height);
279 ivtv_window->top = osd_height_limit - ivtv_window->height;
282 if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
283 IVTV_FB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
284 ivtv_window->left, ivtv_window->width);
285 ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
288 /* Set the OSD origin */
289 write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
291 /* How much to display */
292 write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
294 /* Pass this info back the yuv handler */
295 itv->yuv_info.osd_vis_w = ivtv_window->width;
296 itv->yuv_info.osd_vis_h = ivtv_window->height;
297 itv->yuv_info.osd_x_offset = ivtv_window->left;
298 itv->yuv_info.osd_y_offset = ivtv_window->top;
303 static int ivtv_fb_prep_dec_dma_to_device(struct ivtv *itv,
304 unsigned long ivtv_dest_addr, void __user *userbuf,
311 mutex_lock(&itv->udma.lock);
313 if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
314 mutex_unlock(&itv->udma.lock);
315 IVTV_FB_WARN("ivtvfb_prep_dec_dma_to_device, "
316 "Error with get_user_pages: %d bytes, %d pages returned\n",
317 size_in_bytes, itv->udma.page_count);
319 /* get_user_pages must have failed completely */
323 IVTV_FB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
324 size_in_bytes, itv->udma.page_count);
326 ivtv_udma_prepare(itv);
327 prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
328 /* if no UDMA is pending and no UDMA is in progress, then the DMA
330 while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
331 /* don't interrupt if the DMA is in progress but break off
332 a still pending DMA. */
333 got_sig = signal_pending(current);
334 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
339 finish_wait(&itv->dma_waitq, &wait);
341 /* Unmap Last DMA Xfer */
342 ivtv_udma_unmap(itv);
343 mutex_unlock(&itv->udma.lock);
345 IVTV_DEBUG_INFO("User stopped OSD\n");
352 static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
353 unsigned long dest_offset, int count)
356 struct osd_info *oi = itv->osd_info;
360 IVTV_FB_DEBUG_WARN("ivtv_fb_prep_frame: Nothing to do. count = 0\n");
364 /* Check Total FB Size */
365 if ((dest_offset + count) > oi->video_buffer_size) {
366 IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
367 dest_offset + count, oi->video_buffer_size);
371 /* Not fatal, but will have undesirable results */
372 if ((unsigned long)source & 3)
373 IVTV_FB_WARN("ivtv_fb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
374 (unsigned long)source);
377 IVTV_FB_WARN("ivtv_fb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
380 IVTV_FB_WARN("ivtv_fb_prep_frame: Count not a multiple of 4 (%d)\n", count);
383 if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
384 IVTV_FB_WARN("Invalid userspace pointer 0x%08lx\n",
385 (unsigned long)source);
387 IVTV_FB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
388 dest_offset, (unsigned long)source,
393 /* OSD Address to send DMA to */
394 dest_offset += IVTV_DEC_MEM_START + oi->video_rbase;
397 return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count);
400 static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
403 struct ivtv *itv = (struct ivtv *)info->par;
407 case FBIOGET_VBLANK: {
408 struct fb_vblank vblank;
411 vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
412 FB_VBLANK_HAVE_VSYNC;
413 trace = read_reg(0x028c0) >> 16;
414 if (itv->is_50hz && trace > 312) trace -= 312;
415 else if (itv->is_60hz && trace > 262) trace -= 262;
416 if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
417 vblank.count = itv->lastVsyncFrame;
418 vblank.vcount = trace;
420 if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
425 case FBIO_WAITFORVSYNC:
426 prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
427 if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
428 finish_wait(&itv->vsync_waitq, &wait);
431 case IVTVFB_IOC_DMA_FRAME: {
432 struct ivtvfb_dma_frame args;
434 IVTV_FB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
435 if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
438 return ivtv_fb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
442 IVTV_FB_ERR("Unknown IOCTL %d\n", cmd);
448 /* Framebuffer device handling */
450 static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
452 struct osd_info *oi = itv->osd_info;
453 struct ivtv_osd_coords ivtv_osd;
454 struct v4l2_rect ivtv_window;
457 IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n");
459 /* Select color space */
460 if (var->nonstd) /* YUV */
461 write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
463 write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
465 /* Set the color mode */
466 switch (var->bits_per_pixel) {
468 osd_mode = IVTV_OSD_BPP_8;
471 osd_mode = IVTV_OSD_BPP_32;
474 switch (var->green.length) {
476 osd_mode = IVTV_OSD_BPP_16_444;
479 osd_mode = IVTV_OSD_BPP_16_555;
482 osd_mode = IVTV_OSD_BPP_16_565;
485 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
489 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
492 /* Change osd mode if needed.
493 Although rare, things can go wrong. The extra mode
494 change seems to help... */
495 if (osd_mode != -1 && osd_mode != oi->osd_mode) {
496 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
497 ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
498 oi->osd_mode = osd_mode;
501 oi->bits_per_pixel = var->bits_per_pixel;
502 oi->bytes_per_pixel = var->bits_per_pixel / 8;
504 /* Set the flicker filter */
505 switch (var->vmode & FB_VMODE_MASK) {
506 case FB_VMODE_NONINTERLACED: /* Filter on */
507 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
509 case FB_VMODE_INTERLACED: /* Filter off */
510 ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
513 IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
516 /* Read the current osd info */
517 ivtv_fb_get_osd_coords(itv, &ivtv_osd);
519 /* Now set the OSD to the size we want */
520 ivtv_osd.pixel_stride = var->xres_virtual;
521 ivtv_osd.lines = var->yres_virtual;
524 ivtv_fb_set_osd_coords(itv, &ivtv_osd);
526 /* Can't seem to find the right API combo for this.
527 Use another function which does what we need through direct register access. */
528 ivtv_window.width = var->xres;
529 ivtv_window.height = var->yres;
531 /* Minimum margin cannot be 0, as X won't allow such a mode */
532 if (!var->upper_margin) var->upper_margin++;
533 if (!var->left_margin) var->left_margin++;
534 ivtv_window.top = var->upper_margin - 1;
535 ivtv_window.left = var->left_margin - 1;
537 ivtv_fb_set_display_window(itv, &ivtv_window);
539 /* Force update of yuv registers */
540 itv->yuv_info.yuv_forced_update = 1;
542 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
543 var->xres, var->yres,
544 var->xres_virtual, var->yres_virtual,
545 var->bits_per_pixel);
547 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
548 var->left_margin, var->upper_margin);
550 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
551 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
552 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
557 static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
559 struct osd_info *oi = itv->osd_info;
561 IVTV_FB_DEBUG_INFO("ivtvfb_get_fix\n");
562 memset(fix, 0, sizeof(struct fb_fix_screeninfo));
563 strcpy(fix->id, "cx23415 TV out");
564 fix->smem_start = oi->video_pbase;
565 fix->smem_len = oi->video_buffer_size;
566 fix->type = FB_TYPE_PACKED_PIXELS;
567 fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
571 fix->line_length = oi->display_byte_stride;
572 fix->accel = FB_ACCEL_NONE;
576 /* Check the requested display mode, returning -EINVAL if we can't
579 static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
581 struct osd_info *oi = itv->osd_info;
582 int osd_height_limit = itv->is_50hz ? 576 : 480;
584 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
586 /* Check the bits per pixel */
588 if (var->bits_per_pixel != 32) {
589 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
594 if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
595 var->transp.offset = 24;
596 var->transp.length = 8;
597 var->red.offset = 16;
599 var->green.offset = 8;
600 var->green.length = 8;
601 var->blue.offset = 0;
602 var->blue.length = 8;
604 else if (var->bits_per_pixel == 16) {
605 var->transp.offset = 0;
606 var->transp.length = 0;
608 /* To find out the true mode, check green length */
609 switch (var->green.length) {
613 var->green.offset = 4;
614 var->green.length = 4;
615 var->blue.offset = 0;
616 var->blue.length = 4;
619 var->red.offset = 10;
621 var->green.offset = 5;
622 var->green.length = 5;
623 var->blue.offset = 0;
624 var->blue.length = 5;
627 var->red.offset = 11;
629 var->green.offset = 5;
630 var->green.length = 6;
631 var->blue.offset = 0;
632 var->blue.length = 5;
637 IVTV_FB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
641 /* Check the resolution */
643 if (var->xres != oi->ivtvfb_defined.xres ||
644 var->yres != oi->ivtvfb_defined.yres ||
645 var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
646 var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
647 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
648 var->xres, var->yres, var->xres_virtual, var->yres_virtual);
653 if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
654 IVTV_FB_DEBUG_WARN("Invalid resolution: %dx%d\n",
655 var->xres, var->yres);
659 /* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
660 if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
661 var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
662 var->xres_virtual < var->xres ||
663 var->yres_virtual < var->yres) {
664 IVTV_FB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
665 var->xres_virtual, var->yres_virtual);
670 /* Some extra checks if in 8 bit mode */
671 if (var->bits_per_pixel == 8) {
672 /* Width must be a multiple of 4 */
674 IVTV_FB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
677 if (var->xres_virtual & 3) {
678 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
682 else if (var->bits_per_pixel == 16) {
683 /* Width must be a multiple of 2 */
685 IVTV_FB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
688 if (var->xres_virtual & 1) {
689 IVTV_FB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
694 /* Now check the offsets */
695 if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
696 IVTV_FB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
697 var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
701 /* Check pixel format */
702 if (var->nonstd > 1) {
703 IVTV_FB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
707 /* Check video mode */
708 if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
709 ((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
710 IVTV_FB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
714 /* Check the left & upper margins
715 If the margins are too large, just center the screen
716 (enforcing margins causes too many problems) */
718 if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
719 var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
721 if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
722 var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
725 /* Maintain overall 'size' for a constant refresh rate */
726 var->right_margin = oi->hlimit - var->left_margin - var->xres;
727 var->lower_margin = oi->vlimit - var->upper_margin - var->yres;
729 /* Fixed sync times */
733 /* Non-interlaced / interlaced mode is used to switch the OSD filter
734 on or off. Adjust the clock timings to maintain a constant
735 vertical refresh rate. */
736 var->pixclock = oi->pixclock;
737 if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
740 IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
741 var->xres, var->yres,
742 var->xres_virtual, var->yres_virtual,
743 var->bits_per_pixel);
745 IVTV_FB_DEBUG_INFO("Display position: %d, %d\n",
746 var->left_margin, var->upper_margin);
748 IVTV_FB_DEBUG_INFO("Display filter: %s\n",
749 (var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
750 IVTV_FB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
754 static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
756 struct ivtv *itv = (struct ivtv *) info->par;
757 IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
758 return _ivtvfb_check_var(var, itv);
761 static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
764 struct ivtv *itv = (struct ivtv *) info->par;
766 osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
767 write_reg(osd_pan_index, 0x02A0C);
769 /* Pass this info back the yuv handler */
770 itv->yuv_info.osd_x_pan = var->xoffset;
771 itv->yuv_info.osd_y_pan = var->yoffset;
772 /* Force update of yuv registers */
773 itv->yuv_info.yuv_forced_update = 1;
777 static int ivtvfb_set_par(struct fb_info *info)
780 struct ivtv *itv = (struct ivtv *) info->par;
782 IVTV_FB_DEBUG_INFO("ivtvfb_set_par\n");
784 rc = ivtvfb_set_var(itv, &info->var);
785 ivtvfb_pan_display(&info->var, info);
786 ivtvfb_get_fix(itv, &info->fix);
790 static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
791 unsigned blue, unsigned transp,
792 struct fb_info *info)
795 struct ivtv *itv = (struct ivtv *)info->par;
797 if (regno >= info->cmap.len)
800 color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
801 if (info->var.bits_per_pixel <= 8) {
802 write_reg(regno, 0x02a30);
803 write_reg(color, 0x02a34);
809 palette = info->pseudo_palette;
810 if (info->var.bits_per_pixel == 16) {
811 switch (info->var.green.length) {
813 color = ((red & 0xf000) >> 4) |
814 ((green & 0xf000) >> 8) |
815 ((blue & 0xf000) >> 12);
818 color = ((red & 0xf800) >> 1) |
819 ((green & 0xf800) >> 6) |
820 ((blue & 0xf800) >> 11);
823 color = (red & 0xf800 ) |
824 ((green & 0xfc00) >> 5) |
825 ((blue & 0xf800) >> 11);
829 palette[regno] = color;
833 /* We don't really support blanking. All this does is enable or
835 static int ivtvfb_blank(int blank_mode, struct fb_info *info)
837 struct ivtv *itv = (struct ivtv *)info->par;
839 IVTV_FB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
840 switch (blank_mode) {
841 case FB_BLANK_UNBLANK:
842 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
844 case FB_BLANK_NORMAL:
845 case FB_BLANK_HSYNC_SUSPEND:
846 case FB_BLANK_VSYNC_SUSPEND:
847 case FB_BLANK_POWERDOWN:
848 ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
854 static struct fb_ops ivtvfb_ops = {
855 .owner = THIS_MODULE,
856 .fb_check_var = ivtvfb_check_var,
857 .fb_set_par = ivtvfb_set_par,
858 .fb_setcolreg = ivtvfb_setcolreg,
859 .fb_fillrect = cfb_fillrect,
860 .fb_copyarea = cfb_copyarea,
861 .fb_imageblit = cfb_imageblit,
863 .fb_ioctl = ivtvfb_ioctl,
864 .fb_pan_display = ivtvfb_pan_display,
865 .fb_blank = ivtvfb_blank,
871 /* Setup our initial video mode */
872 static int ivtvfb_init_vidmode(struct ivtv *itv)
874 struct osd_info *oi = itv->osd_info;
875 struct v4l2_rect start_window;
878 /* Set base references for mode calcs. */
880 oi->pixclock = 84316;
885 oi->pixclock = 83926;
892 if (osd_compat) osd_depth = 32;
893 if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
894 oi->bits_per_pixel = osd_depth;
895 oi->bytes_per_pixel = oi->bits_per_pixel / 8;
897 /* Invalidate current osd mode to force a mode switch later */
900 /* Horizontal size & position */
902 if (osd_xres > 720) osd_xres = 720;
904 /* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
907 else if (osd_depth == 16)
911 start_window.width = osd_xres;
913 start_window.width = osd_compat ? 720: 640;
915 /* Check horizontal start (osd_left). */
916 if (osd_left && osd_left + start_window.width > 721) {
917 IVTV_FB_ERR("Invalid osd_left - assuming default\n");
921 /* Hardware coords start at 0, user coords start at 1. */
924 start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
926 oi->display_byte_stride =
927 start_window.width * oi->bytes_per_pixel;
929 /* Vertical size & position */
931 max_height = itv->is_50hz ? 576 : 480;
933 if (osd_yres > max_height)
934 osd_yres = max_height;
937 start_window.height = osd_yres;
939 start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
941 /* Check vertical start (osd_upper). */
942 if (osd_upper + start_window.height > max_height + 1) {
943 IVTV_FB_ERR("Invalid osd_upper - assuming default\n");
947 /* Hardware coords start at 0, user coords start at 1. */
950 start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
952 oi->display_width = start_window.width;
953 oi->display_height = start_window.height;
955 /* Generate a valid fb_var_screeninfo */
957 oi->ivtvfb_defined.xres = oi->display_width;
958 oi->ivtvfb_defined.yres = oi->display_height;
959 oi->ivtvfb_defined.xres_virtual = oi->display_width;
960 oi->ivtvfb_defined.yres_virtual = oi->display_height;
961 oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
962 oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
963 oi->ivtvfb_defined.left_margin = start_window.left + 1;
964 oi->ivtvfb_defined.upper_margin = start_window.top + 1;
965 oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
966 oi->ivtvfb_defined.nonstd = 0;
968 /* We've filled in the most data, let the usual mode check
969 routine fill in the rest. */
970 _ivtvfb_check_var(&oi->ivtvfb_defined, itv);
972 /* Generate valid fb_fix_screeninfo */
974 ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
976 /* Generate valid fb_info */
978 oi->ivtvfb_info.node = -1;
979 oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
980 oi->ivtvfb_info.fbops = &ivtvfb_ops;
981 oi->ivtvfb_info.par = itv;
982 oi->ivtvfb_info.var = oi->ivtvfb_defined;
983 oi->ivtvfb_info.fix = oi->ivtvfb_fix;
984 oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
985 oi->ivtvfb_info.fbops = &ivtvfb_ops;
987 /* Supply some monitor specs. Bogus values will do for now */
988 oi->ivtvfb_info.monspecs.hfmin = 8000;
989 oi->ivtvfb_info.monspecs.hfmax = 70000;
990 oi->ivtvfb_info.monspecs.vfmin = 10;
991 oi->ivtvfb_info.monspecs.vfmax = 100;
993 /* Allocate color map */
994 if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
995 IVTV_FB_ERR("abort, unable to alloc cmap\n");
999 /* Allocate the pseudo palette */
1000 oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
1002 if (!oi->ivtvfb_info.pseudo_palette) {
1003 IVTV_FB_ERR("abort, unable to alloc pseudo pallete\n");
1010 /* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
1012 static int ivtvfb_init_io(struct ivtv *itv)
1014 struct osd_info *oi = itv->osd_info;
1016 ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
1018 /* The osd buffer size depends on the number of video buffers allocated
1019 on the PVR350 itself. For now we'll hardcode the smallest osd buffer
1020 size to prevent any overlap. */
1021 oi->video_buffer_size = 1704960;
1023 oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
1024 oi->video_vbase = itv->dec_mem + oi->video_rbase;
1026 if (!oi->video_vbase) {
1027 IVTV_FB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
1028 oi->video_buffer_size, oi->video_pbase);
1032 IVTV_FB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
1033 oi->video_pbase, oi->video_vbase,
1034 oi->video_buffer_size / 1024);
1038 /* Find the largest power of two that maps the whole buffer */
1039 int size_shift = 31;
1041 while (!(oi->video_buffer_size & (1 << size_shift))) {
1045 oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
1046 oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
1047 oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
1048 oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
1049 if (mtrr_add(oi->fb_start_aligned_physaddr,
1050 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
1051 MTRR_TYPE_WRCOMB, 1) < 0) {
1052 IVTV_FB_WARN("cannot use mttr\n");
1053 oi->fb_start_aligned_physaddr = 0;
1054 oi->fb_end_aligned_physaddr = 0;
1059 /* Blank the entire osd. */
1060 memset_io(oi->video_vbase, 0, oi->video_buffer_size);
1065 /* Release any memory we've grabbed & remove mtrr entry */
1066 static void ivtvfb_release_buffers (struct ivtv *itv)
1068 struct osd_info *oi = itv->osd_info;
1071 if (oi->ivtvfb_info.cmap.len);
1072 fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
1074 /* Release pseudo palette */
1075 if (oi->ivtvfb_info.pseudo_palette)
1076 kfree(oi->ivtvfb_info.pseudo_palette);
1079 if (oi->fb_end_aligned_physaddr) {
1080 mtrr_del(-1, oi->fb_start_aligned_physaddr,
1081 oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
1086 itv->osd_info = NULL;
1089 /* Initialize the specified card */
1091 static int ivtvfb_init_card(struct ivtv *itv)
1095 if (itv->osd_info) {
1096 IVTV_FB_ERR("Card %d already initialised\n", ivtv_fb_card_id);
1100 itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
1101 if (itv->osd_info == 0) {
1102 IVTV_FB_ERR("Failed to allocate memory for osd_info\n");
1106 /* Find & setup the OSD buffer */
1107 if ((rc = ivtvfb_init_io(itv)))
1110 /* Set the startup video mode information */
1111 if ((rc = ivtvfb_init_vidmode(itv))) {
1112 ivtvfb_release_buffers(itv);
1116 /* Register the framebuffer */
1117 if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
1118 ivtvfb_release_buffers(itv);
1122 itv->osd_video_pbase = itv->osd_info->video_pbase;
1124 /* Set the card to the requested mode */
1125 ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
1127 /* Set color 0 to black */
1128 write_reg(0, 0x02a30);
1129 write_reg(0, 0x02a34);
1131 /* Enable the osd */
1132 ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
1134 /* Note if we're running in compatibility mode */
1136 IVTV_FB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
1139 ivtv_udma_alloc(itv);
1144 static int __init ivtvfb_init(void)
1147 int i, registered = 0;
1149 if (ivtv_fb_card_id < -1 || ivtv_fb_card_id >= IVTV_MAX_CARDS) {
1150 printk(KERN_ERR "ivtv-fb: ivtv_fb_card_id parameter is out of range (valid range: -1 - %d)\n",
1151 IVTV_MAX_CARDS - 1);
1155 /* Locate & initialise all cards supporting an OSD. */
1156 for (i = 0; i < ivtv_cards_active; i++) {
1157 if (ivtv_fb_card_id != -1 && i != ivtv_fb_card_id)
1159 itv = ivtv_cards[i];
1160 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
1161 if (ivtvfb_init_card(itv) == 0) {
1162 IVTV_FB_INFO("Framebuffer registered on ivtv card id %d\n", i);
1168 printk(KERN_ERR "ivtv-fb: no cards found");
1174 static void ivtvfb_cleanup(void)
1179 printk(KERN_INFO "ivtv-fb: Unloading framebuffer module\n");
1181 for (i = 0; i < ivtv_cards_active; i++) {
1182 itv = ivtv_cards[i];
1183 if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
1184 IVTV_FB_DEBUG_INFO("Unregister framebuffer %d\n", i);
1185 ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
1186 unregister_framebuffer(&itv->osd_info->ivtvfb_info);
1187 ivtvfb_release_buffers(itv);
1188 itv->osd_video_pbase = 0;
1193 module_init(ivtvfb_init);
1194 module_exit(ivtvfb_cleanup);