📄 davincifb.c
字号:
#define WITHIN_LIMITS \
((_xp >= xp0) && (_yp >= yp0) && \
(_xp + _xl <= xp0 + xl0) && (_yp + _yl <= yp0 + yl0))
if (dm->osd0) {
get_win_position(dm->osd0, &_xp, &_yp, &_xl, &_yl);
if (!WITHIN_LIMITS)
RETURN(-EINVAL);
}
if (dm->osd1) {
get_win_position(dm->osd1, &_xp, &_yp, &_xl, &_yl);
if (!WITHIN_LIMITS)
RETURN(-EINVAL);
}
if (dm->vid1) {
get_win_position(dm->vid1, &_xp, &_yp, &_xl, &_yl);
if (!WITHIN_LIMITS)
RETURN(-EINVAL);
}
RETURN(0);
#undef WITHIN_LIMITS
}
/**
* davincifb_check_var - Validates a var passed in.
* @var: frame buffer variable screen structure
* @info: frame buffer structure that represents a single frame buffer
*
* Checks to see if the hardware supports the state requested by
* var passed in. This function does not alter the hardware state!!!
* This means the data stored in struct fb_info and struct xxx_par do
* not change. This includes the var inside of struct fb_info.
* Do NOT change these. This function can be called on its own if we
* intent to only test a mode and not actually set it.
* If the var passed in is slightly off by what the hardware can support
* then we alter the var PASSED in to what we can do.
*
* Returns negative errno on error, or zero on success.
*/
static int davincifb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
const struct dm_win_info *w = (const struct dm_win_info *)info->par;
struct fb_var_screeninfo v;
/* Rules:
* 1) Vid1, OSD0, OSD1 and Cursor must be fully contained inside of Vid0.
* 2) Vid0 and Vid1 are both set to accept YUV 4:2:2 (for now).
* 3) OSD window data is always packed into 32-bit words and left justified.
* 4) Each horizontal line of window data must be a multiple of 32 bytes.
* 32 bytes = 32 bytes / 2 bytes per pixel = 16 pixels.
* This implies that 'xres' must be a multiple of 32 bytes.
* 5) The offset registers hold the distance between the start of one line and
* the start of the next. This offset value must be a multiple of 32 bytes.
* This implies that 'xres_virtual' is also a multiple of 32 bytes. Note
* that 'xoffset' needn't be a multiple of 32 bytes.
* 6) OSD0 is set to accept RGB565.
* dispc_reg_merge(OSD_OSDWIN0ND, OSD_OSDWIN0ND_RGB0E, OSD_OSDWIN0ND_RGB0E)
* 7) OSD1 is set to be the attribute window.
* 8) Vid1 startX = Vid0 startX + N * 16 pixels (32 bytes)
* 9) Vid1 width = (16*N - 8) pixels
* 10) When one of the OSD windows is in RGB565, it cannot overlap with Vid1.
* 11) Vid1 start X position must be offset a multiple of 16 pixels from the
* left edge of Vid0.
*/
DBGENTER;
memcpy(&v, var, sizeof(v));
RETURN(0);
/* do board-specific checks on the var */
if (davincifb_venc_check_mode(w, &v))
RETURN(-EINVAL);
if (v.xres_virtual < v.xres || v.yres_virtual < v.yres)
RETURN(-EINVAL);
if (v.xoffset > v.xres_virtual - v.xres)
RETURN(-EINVAL);
if (v.yoffset > v.yres_virtual - v.yres)
RETURN(-EINVAL);
if ((v.xres * v.bits_per_pixel / 8) % 32 || (v.xres_virtual * v.bits_per_pixel / 8) % 32) /* Rules 4, 5 */
RETURN(-EINVAL);
if (v.xres_virtual * v.yres_virtual * v.bits_per_pixel / 8 > w->fb_size)
RETURN(-EINVAL);
if (!is_win(info->fix.id, VID0)) {
/* Rule 1 */
if (!within_vid0_limits(x_pos(w), y_pos(w), v.xres, v.yres))
RETURN(-EINVAL);
}
if (is_win(info->fix.id, OSD0)) {
/* Rule 10 */
if (window_overlap(w->dm->vid1,
x_pos(w), y_pos(w), v.xres, v.yres))
RETURN(-EINVAL);
/* Rule 5 */
v.bits_per_pixel = 16;
v.red.offset = 11;
v.green.offset = 5;
v.blue.offset = 0;
v.red.length = 5;
v.green.length = 6;
v.blue.length = 5;
v.transp.offset = v.transp.length = 0;
v.red.msb_right = v.green.msb_right = v.blue.msb_right
= v.transp.msb_right = 0;
v.nonstd = 0;
v.accel_flags = 0;
} else if (is_win(info->fix.id, OSD1)) {
v.bits_per_pixel = 4;
} else if (is_win(info->fix.id, VID0)) {
if (check_new_vid0_size(x_pos(w), y_pos(w), v.xres, v.yres))
RETURN(-EINVAL);
v.bits_per_pixel = 16;
} else if (is_win(info->fix.id, VID1)) {
/* Rule 11 */
if ((x_pos(w->dm->vid0) - x_pos(w)) % 16)
RETURN(-EINVAL);
/* Video1 may be in YUV or RGB888 format */
if ((v.bits_per_pixel != 16) && (v.bits_per_pixel != 32))
RETURN(-EINVAL);
} else
RETURN(-EINVAL);
memcpy(var, &v, sizeof(v));
RETURN(0);
}
/* Interlaced = Frame mode, Non-interlaced = Field mode */
static void set_interlaced(char *id, unsigned int on)
{
on = (on == 0) ? 0 : ~0;
DBGENTER;
if (is_win(id, VID0))
dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_VFF0);
else if (is_win(id, VID1))
dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_VFF1);
else if (is_win(id, OSD0))
dispc_reg_merge(OSD_OSDWIN0MD, on, OSD_OSDWIN0MD_OFF0);
else if (is_win(id, OSD1))
dispc_reg_merge(OSD_OSDWIN1MD, on, OSD_OSDWIN1MD_OFF1);
DBGEXIT;
}
/* For zooming, we just have to set the start of framebuffer, the zoom factors
* and the display size. The hardware will then read only
* (display size / zoom factor) area of the framebuffer and zoom and
* display it. In the following function, we assume that the start of
* framebuffer and the display size parameters are set already.
*/
static void set_zoom(int WinID, int h_factor, int v_factor)
{
DBGENTER;
switch (WinID) {
case 0: //VID0
dispc_reg_merge(OSD_VIDWINMD,
h_factor << OSD_VIDWINMD_VHZ0_SHIFT,
OSD_VIDWINMD_VHZ0);
dispc_reg_merge(OSD_VIDWINMD,
v_factor << OSD_VIDWINMD_VVZ0_SHIFT,
OSD_VIDWINMD_VVZ0);
break;
case 1: //VID1
dispc_reg_merge(OSD_VIDWINMD,
h_factor << OSD_VIDWINMD_VHZ1_SHIFT,
OSD_VIDWINMD_VHZ1);
dispc_reg_merge(OSD_VIDWINMD,
v_factor << OSD_VIDWINMD_VVZ1_SHIFT,
OSD_VIDWINMD_VVZ1);
break;
case 2: //OSD0
dispc_reg_merge(OSD_OSDWIN0MD,
h_factor << OSD_OSDWIN0MD_OHZ0_SHIFT,
OSD_OSDWIN0MD_OHZ0);
dispc_reg_merge(OSD_OSDWIN0MD,
v_factor << OSD_OSDWIN0MD_OVZ0_SHIFT,
OSD_OSDWIN0MD_OVZ0);
break;
case 3:
dispc_reg_merge(OSD_OSDWIN1MD,
h_factor << OSD_OSDWIN1MD_OHZ1_SHIFT,
OSD_OSDWIN1MD_OHZ1);
dispc_reg_merge(OSD_OSDWIN1MD,
v_factor << OSD_OSDWIN1MD_OVZ1_SHIFT,
OSD_OSDWIN1MD_OVZ1);
break;
}
DBGEXIT;
}
/* Logic Product Development
* Ryan Link
* DSP_Team
*/
/* Sets timing parameters for an lcd */
static void set_lcd_timings(int h_valid, int v_valid,
int h_int, int v_int,
int h_pulse, int v_pulse,
int h_start, int v_start,
int h_dly, int v_dly,
int hsync_pol,
int vsync_pol,
int oe_pol)// more for clocks?
{
DBGENTER;
if(hsync_pol){
if(vsync_pol){
// vsync active high, hsync active high
dispc_reg_merge(VENC_SYNCCTL, 0x03, 0xf);
}
else{
// vsync active low, hsync active high
dispc_reg_merge(VENC_SYNCCTL, 0x0b, 0xf);
}
}
else{
if(vsync_pol){
// vsync active high, hsync active low
dispc_reg_merge(VENC_SYNCCTL, 0x07, 0xf);
}
else{
// vsync active low, hsync active low
dispc_reg_merge(VENC_SYNCCTL, 0x0f, 0xf);
}
}
if(oe_pol){
dispc_reg_merge(VENC_LCDOUT, 0x01, 0x3);
}
else{
dispc_reg_merge(VENC_LCDOUT, 0x03, 0x3);
}
dispc_reg_out(VENC_HSPLS, h_pulse);
dispc_reg_out(VENC_VSPLS, v_pulse);
dispc_reg_out(VENC_HINT, h_int);
dispc_reg_out(VENC_VINT, v_int);
dispc_reg_out(VENC_HSTART, h_start);
dispc_reg_out(VENC_VSTART, v_start);
dispc_reg_out(VENC_HVALID, h_valid);
dispc_reg_out(VENC_VVALID, v_valid);
dispc_reg_out(VENC_HSDLY, h_dly);
dispc_reg_out(VENC_VSDLY, v_dly);
// more for clocks?
DBGEXIT;
}
/* Chooses the ROM CLUT for now. Can be extended later. */
static void set_bg_color(u8 clut, u8 color_offset)
{
clut = 0; /* 0 = ROM, 1 = RAM */
DBGENTER;
dispc_reg_merge(OSD_MODE, OSD_MODE_BCLUT & clut, OSD_MODE_BCLUT);
dispc_reg_merge(OSD_MODE, color_offset << OSD_MODE_CABG_SHIFT,
OSD_MODE_CABG);
DBGEXIT;
}
static void set_sdram_params(char *id, u32 addr, u32 line_length)
{
DBGENTER;
/* The parameters to be written to the registers should be in
* multiple of 32 bytes
*/
addr = addr; /* div by 32 */
line_length = line_length / 32;
if (is_win(id, VID0)) {
dispc_reg_out(OSD_VIDWIN0ADR, addr);
dispc_reg_out(OSD_VIDWIN0OFST, line_length);
} else if (is_win(id, VID1)) {
dispc_reg_out(OSD_VIDWIN1ADR, addr);
dispc_reg_out(OSD_VIDWIN1OFST, line_length);
} else if (is_win(id, OSD0)) {
dispc_reg_out(OSD_OSDWIN0ADR, addr);
dispc_reg_out(OSD_OSDWIN0OFST, line_length);
} else if (is_win(id, OSD1)) {
dispc_reg_out(OSD_OSDWIN1ADR, addr);
dispc_reg_out(OSD_OSDWIN1OFST, line_length);
}
DBGEXIT;
}
static void set_win_enable(char *id, unsigned int on)
{
on = (on == 0) ? 0 : ~0;
DBGENTER;
if (is_win(id, VID0))
/* Turning off VID0 use due to field inversion issue */
dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_ACT0);
else if (is_win(id, VID1))
dispc_reg_merge(OSD_VIDWINMD, on, OSD_VIDWINMD_ACT1);
else if (is_win(id, OSD0))
dispc_reg_merge(OSD_OSDWIN0MD, on, OSD_OSDWIN0MD_OACT0);
else if (is_win(id, OSD1)) {
/* The OACT1 bit is applicable only if OSD1 is not used as
* the attribute window
*/
if (!(dispc_reg_in(OSD_OSDWIN1MD) & OSD_OSDWIN1MD_OASW))
dispc_reg_merge(OSD_OSDWIN1MD, on, OSD_OSDWIN1MD_OACT1);
}
DBGEXIT;
}
static void set_win_mode(char *id)
{
DBGENTER;
if (is_win(id, VID0)) ;
else if (is_win(id, VID1)) {
if (dm->vid1->info.var.bits_per_pixel == 32)
dispc_reg_merge(OSD_MISCCT, ~0,
OSD_MISCCT_RGBWIN | OSD_MISCCT_RGBEN);
} else if (is_win(id, OSD0))
/* Set RGB565 mode */
dispc_reg_merge(OSD_OSDWIN0MD, OSD_OSDWIN0MD_RGB0E,
OSD_OSDWIN0MD_RGB0E);
else if (is_win(id, OSD1)) {
/* Set as attribute window */
dispc_reg_merge(OSD_OSDWIN1MD, OSD_OSDWIN1MD_OASW,
OSD_OSDWIN1MD_OASW);
}
DBGEXIT;
}
/**
* davincifb_set_par - Optional function. Alters the hardware state.
* @info: frame buffer structure that represents a single frame buffer
*
* Using the fb_var_screeninfo in fb_info we set the resolution of the
* this particular framebuffer. This function alters the par AND the
* fb_fix_screeninfo stored in fb_info. It doesn't not alter var in
* fb_info since we are using that data. This means we depend on the
* data in var inside fb_info to be supported by the hardware.
* davincifb_check_var is always called before dmfb_set_par to ensure this.
* Again if you can't can't the resolution you don't need this function.
*
*/
static int davincifb_set_par(struct fb_info *info)
{
struct dm_win_info *w = (struct dm_win_info *)info->par;
struct fb_var_screeninfo *v = &info->var;
u32 start = 0, offset = 0;
DBGENTER;
info->fix.line_length = v->xres_virtual * v->bits_per_pixel / 8;
offset = v->yoffset * info->fix.line_length +
v->xoffset * v->bits_per_pixel / 8;
start = (u32) w->fb_base_phys + offset;
set_sdram_params(info->fix.id, start, info->fix.line_length);
// Logic Product Development - Ryan Link - DSP_Team
if(dmparams.output == LCD && dmparams.format == RGB){
// non interlaced output
set_interlaced(info->fix.id, 0);
set_win_position(info->fix.id,
x_pos(w), y_pos(w), v->xres, v->yres);
}
else {
// interlaced output
set_interlaced(info->fix.id, 1);
set_win_position(info->fix.id,
x_pos(w), y_pos(w), v->xres, v->yres / 2);
}
//set_win_position(info->fix.id,
// x_pos(w), y_pos(w), v->xres, v->yres / 2);
//set_win_position(info->fix.id,
// x_pos(w), y_pos(w), v->xres, 480);
set_win_mode(info->fix.id);
set_win_enable(info->fix.id, 1);
RETURN(0);
}
/**
* davincifb_ioctl - handler for private ioctls.
*/
static int
davincifb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg, struct fb_info *info)
{
struct dm_win_info *w = (struct dm_win_info *)info->par;
void __user *argp = (void __user *)arg;
struct fb_fillrect rect;
struct zoom_params zoom;
struct lcd_timing_params lcd_timing;
long std = 0;
DBGENTER;
switch (cmd) {
case FBIO_WAITFORVSYNC:
/* This ioctl accepts an integer argument to specify a
* display. We only support one display, so we will
* simply ignore the argument.
*/
RETURN(davincifb_wait_for_vsync(w));
break;
case FBIO_SETATTRIBUTE:
if (copy_from_user(&rect, argp, sizeof(rect)))
return -EFAULT;
RETURN(davincifb_set_attr_blend(&rect));
break;
case FBIO_SETPOSX:
if (arg >= 0 && arg <= DISP_XRES) {
w->x = arg;
davincifb_check_var(&w->info.var, &w->info);
davincifb_set_par(&w->info);
return 0;
} else
return -EINVAL;
break;
case FBIO_SETPOSY:
if (arg >= 0 && arg <= DISP_YRES) {
w->y = arg;
davincifb_check_var(&w->info.var, &w->info);
davincifb_set_par(&w->info);
return 0;
} else
return -EINVAL;
break;
case FBIO_SETZOOM:
if (copy_from_user(&zoom, argp, sizeof(zoom)))
return -EFAULT;
if ((zoom.zoom_h == 2) || (zoom.zoom_h == 0)
|| (zoom.zoom_h == 1) || (zoom.zoom_v == 2)
|| (zoom.zoom_v == 0) || (zoom.zoom_v == 1)) {
set_zoom(zoom.window_id, zoom.zoom_h, zoom.zoom_v);
return 0;
} else {
return -EINVAL;
}
break;
case FBIO_GETSTD:
std = ((dmparams.output << 16) | (dmparams.format)); //(NTSC <<16) | (COPOSITE);
copy_to_user(argp, &std, sizeof(u_int32_t));
return 0;
break;
// Logic Product Development - Ryan Link - DSP_Team
case FBIO_SETLCDTIMEPARAMS:
if (copy_from_user(&lcd_timing, argp, sizeof(lcd_timing)))
return -EFAULT;
if (lcd_timing.h_valid > 0 && lcd_timing.v_valid > 0 &&
lcd_timing.h_interval > 0 && lcd_timing.v_interval > 0 &&
lcd_timing.h_pulse > 0 && lcd_timing.v_pulse > 0 &&
lcd_timing.h_start >= 0 && lcd_timing.v_start >= 0 &&
lcd_timing.h_delay >= 0 && lcd_timing.v_delay >= 0 &&
lcd_timing.h_valid < lcd_timing.h_interval &&
lcd_timing.v_valid < lcd_timing.v_interval ){ // more error checking?
set_lcd_timings(lcd_timing.h_valid, lcd_timing.v_valid,
lcd_timing.h_interval,lcd_timing.v_interval,
lcd_timing.h_pulse, lcd_timing.v_pulse,
lcd_timing.h_start, lcd_timing.v_start,
lcd_timing.h_delay, lcd_timing.v_delay,
lcd_timing.hsync_pol,
lcd_timing.vsync_pol,
lcd_timing.oe_pol);
return 0;
} else {
return -EINVAL;
}
break;
}
RETURN(-EINVAL);
}
/**
* davincifb_setcolreg - Optional function. Sets a color register.
* @regno: Which register in the CLUT we are programming
* @red: The red value which can be up to 16 bits wide
* @green: The green value which can be up to 16 bits wide
* @blue: The blue value which can be up to 16 bits wide.
* @transp: If supported the alpha value which can be up to 16 bits wide.
* @info: frame buffer info structure
*
* Set a single color register. The values supplied have a 16 bit
* magnitude which needs to be scaled in this function for the hardware.
* Things to take into consideration are how many color registers, if
* any, are supported with the current color visual. With truecolor mode
* no color palettes are supported. Here a psuedo palette is created
* which we store the value in pseudo_palette in struct fb_info. For
* pseudocolor mode we have a limited color palette. To deal with this
* we can program what color is displayed for a particular pixel value.
* DirectColor is similar in that we can program each color field. If
* we have a static colormap we don't need to implement this function.
*
* Returns negative errno on error, or zero on success.
*/
static int davincifb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
DBGENTER;
/* only pseudo-palette (16 bpp) allowed */
if (regno >= 16) /* maximum number of palette entries */
RETURN(1);
if (info->var.grayscale) {
/* grayscale = 0.30*R + 0.59*G + 0.11*B */
red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
}
/* Truecolor has hardware-independent 16-entry pseudo-palette */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -