// SPDX-License-Identifier: GPL-2.0-or-later /* On Screen Display cx23415 Framebuffer driver
This module presents the cx23415 OSD (onscreen display) framebuffer memory as a standard Linux /dev/fb style framebuffer device. The framebuffer has support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp mode, there is a choice of a three color depths (12, 15 or 16 bits), but no local alpha. The colorspace is selectable between rgb & yuv. Depending on the TV standard configured in the ivtv module at load time, the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp. Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL) or 59.94 (NTSC)
Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
Derived from drivers/video/vesafb.c Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
MODULE_PARM_DESC(ivtvfb_card_id, "Only use framebuffer of the specified ivtv card (0-31)\n" "\t\t\tdefault -1: initialize all available framebuffers");
MODULE_PARM_DESC(force_pat, "Force initialization on x86 PAT-enabled systems (bool).\n");
/* Why upper, left, xres, yres, depth, laced ? To match terminology used by fbset.
Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
MODULE_DESCRIPTION("Conexant cx23415 framebuffer support");
MODULE_LICENSE("GPL");
struct osd_info { /* Physical base address */ unsignedlong video_pbase; /* Relative base address (relative to start of decoder memory) */
u32 video_rbase; /* Mapped base address */ volatilechar __iomem *video_vbase; /* Buffer size */
u32 video_buffer_size;
/* video_base rounded down as required by hardware MTRRs */ unsignedlong fb_start_aligned_physaddr; /* video_base rounded up as required by hardware MTRRs */ unsignedlong fb_end_aligned_physaddr; int wc_cookie;
/* Store the buffer offset */ int set_osd_coords_x; int set_osd_coords_y;
/* Current dimensions (NOT VISIBLE SIZE!) */ int display_width; int display_height; int display_byte_stride;
/* Current bits per pixel */ int bits_per_pixel; int bytes_per_pixel;
/* Only fail if resolution too high, otherwise fudge the start coords. */ if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH)) return -EINVAL;
ivtv_udma_prepare(itv);
prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); /* if no UDMA is pending and no UDMA is in progress, then the DMA
is finished */ while (test_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags) ||
test_bit(IVTV_F_I_UDMA, &itv->i_flags)) { /* don't interrupt if the DMA is in progress but break off
a still pending DMA. */
got_sig = signal_pending(current); if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags)) break;
got_sig = 0;
schedule();
}
finish_wait(&itv->dma_waitq, &wait);
/* Unmap Last DMA Xfer */
ivtv_udma_unmap(itv);
mutex_unlock(&itv->udma.lock); if (got_sig) {
IVTV_DEBUG_INFO("User stopped OSD\n"); return -EINTR;
}
return 0;
}
staticint ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source, unsignedlong dest_offset, int count)
{
DEFINE_WAIT(wait); struct osd_info *oi = itv->osd_info;
/* Nothing to do */ if (count == 0) {
IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n"); return -EINVAL;
}
/* Check Total FB Size */ if ((dest_offset + count) > oi->video_buffer_size) {
IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
dest_offset + count, oi->video_buffer_size); return -E2BIG;
}
/* Not fatal, but will have undesirable results */ if ((unsignedlong)source & 3)
IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (%p)\n",
source);
if (dest_offset & 3)
IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
if (count & 3)
IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
/* Select color space */ if (var->nonstd) /* YUV */
write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00); else/* RGB */
write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
/* Set the color mode */ switch (var->bits_per_pixel) { case 8:
osd_mode = IVTV_OSD_BPP_8; break; case 32:
osd_mode = IVTV_OSD_BPP_32; break; case 16: switch (var->green.length) { case 4:
osd_mode = IVTV_OSD_BPP_16_444; break; case 5:
osd_mode = IVTV_OSD_BPP_16_555; break; case 6:
osd_mode = IVTV_OSD_BPP_16_565; break; default:
IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
} break; default:
IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
}
/* Set video mode. Although rare, the display can become scrambled even
if we don't change mode. Always 'bounce' to osd_mode via mode 0 */ if (osd_mode != -1) {
ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
}
/* Set the flicker filter */ switch (var->vmode & FB_VMODE_MASK) { case FB_VMODE_NONINTERLACED: /* Filter on */
ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1); break; case FB_VMODE_INTERLACED: /* Filter off */
ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0); break; default:
IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
}
/* Read the current osd info */
ivtvfb_get_osd_coords(itv, &ivtv_osd);
/* Now set the OSD to the size we want */
ivtv_osd.pixel_stride = var->xres_virtual;
ivtv_osd.lines = var->yres_virtual;
ivtv_osd.x = 0;
ivtv_osd.y = 0;
ivtvfb_set_osd_coords(itv, &ivtv_osd);
/* Can't seem to find the right API combo for this.
Use another function which does what we need through direct register access. */
ivtv_window.width = var->xres;
ivtv_window.height = var->yres;
/* Minimum margin cannot be 0, as X won't allow such a mode */ if (!var->upper_margin)
var->upper_margin++; if (!var->left_margin)
var->left_margin++;
ivtv_window.top = var->upper_margin - 1;
ivtv_window.left = var->left_margin - 1;
ivtvfb_set_display_window(itv, &ivtv_window);
/* Pass screen size back to yuv handler */
itv->yuv_info.osd_full_w = ivtv_osd.pixel_stride;
itv->yuv_info.osd_full_h = ivtv_osd.lines;
/* Force update of yuv registers */
itv->yuv_info.yuv_forced_update = 1;
/* Keep a copy of these settings */
memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
/* Some extra checks if in 8 bit mode */ if (var->bits_per_pixel == 8) { /* Width must be a multiple of 4 */ if (var->xres & 3) {
IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres); return -EINVAL;
} if (var->xres_virtual & 3) {
IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual); return -EINVAL;
}
} elseif (var->bits_per_pixel == 16) { /* Width must be a multiple of 2 */ if (var->xres & 1) {
IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres); return -EINVAL;
} if (var->xres_virtual & 1) {
IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual); return -EINVAL;
}
}
/* Now check the offsets */ if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual); return -EINVAL;
}
/* Check pixel format */ if (var->nonstd > 1) {
IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd); return -EINVAL;
}
/* Check video mode */ if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK); return -EINVAL;
}
/* Check the left & upper margins If the margins are too large, just center the screen
(enforcing margins causes too many problems) */
/* Non-interlaced / interlaced mode is used to switch the OSD filter on or off. Adjust the clock timings to maintain a constant
vertical refresh rate. */ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
var->pixclock = pixclock / 2; else
var->pixclock = pixclock;
/* Pass this info back the yuv handler */
itv->yuv_info.osd_x_pan = var->xoffset;
itv->yuv_info.osd_y_pan = var->yoffset; /* Force update of yuv registers */
itv->yuv_info.yuv_forced_update = 1; /* Remember this value */
itv->osd_info->pan_cur = osd_pan_index; return 0;
}
/* We don't really support blanking. All this does is enable or
disable the OSD. */ staticint ivtvfb_blank(int blank_mode, struct fb_info *info)
{ struct ivtv *itv = (struct ivtv *)info->par;
/* Supply some monitor specs. Bogus values will do for now */
oi->ivtvfb_info.monspecs.hfmin = 8000;
oi->ivtvfb_info.monspecs.hfmax = 70000;
oi->ivtvfb_info.monspecs.vfmin = 10;
oi->ivtvfb_info.monspecs.vfmax = 100;
/* Allocate color map */ if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
IVTVFB_ERR("abort, unable to alloc cmap\n"); return -ENOMEM;
}
if (!oi->ivtvfb_info.pseudo_palette) {
IVTVFB_ERR("abort, unable to alloc pseudo palette\n"); return -ENOMEM;
}
return 0;
}
/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
staticint ivtvfb_init_io(struct ivtv *itv)
{ struct osd_info *oi = itv->osd_info; /* Find the largest power of two that maps the whole buffer */ int size_shift = 31;
mutex_lock(&itv->serialize_lock); if (ivtv_init_on_first_open(itv)) {
mutex_unlock(&itv->serialize_lock);
IVTVFB_ERR("Failed to initialize ivtv\n"); return -ENXIO;
}
mutex_unlock(&itv->serialize_lock);
if (ivtvfb_get_framebuffer(itv, &oi->video_rbase,
&oi->video_buffer_size) < 0) {
IVTVFB_ERR("Firmware failed to respond\n"); return -EIO;
}
/* The osd buffer size depends on the number of video buffers allocated on the PVR350 itself. For now we'll hardcode the smallest osd buffer
size to prevent any overlap. */
oi->video_buffer_size = 1704960;
staticint ivtvfb_init_card(struct ivtv *itv)
{ int rc;
#ifdefined(CONFIG_X86_64) && !defined(CONFIG_UML) if (pat_enabled()) { if (ivtvfb_force_pat) {
pr_info("PAT is enabled. Write-combined framebuffer caching will be disabled.\n");
pr_info("To enable caching, boot with nopat kernel parameter\n");
} else {
pr_warn("ivtvfb needs PAT disabled for write-combined framebuffer caching.\n");
pr_warn("Boot with nopat kernel parameter to use caching, or use the\n");
pr_warn("force_pat module parameter to run with caching disabled\n"); return -ENODEV;
}
} #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.