📄 davincifb.c
字号:
RETURN(OVERLAP(xp, yp, xp + xl, yp + yl, _xp, _yp, _xp + _xl, _yp + _yl));#undef OVERLAP}/* Returns 1 if the window parameters are within VID0, 0 otherwise */static int within_vid0_limits(u32 xp, u32 yp, u32 xl, u32 yl){ u32 vid0_xp = 0, vid0_yp = 0, vid0_xl = 0, vid0_yl = 0; DBGENTER; if (!dm->vid0) RETURN(1); get_win_position(dm->vid0, &vid0_xp, &vid0_yp, &vid0_xl, &vid0_yl); if ((xp >= vid0_xp) && (yp >= vid0_yp) && (xp + xl <= vid0_xp + vid0_xl) && (yp + yl <= vid0_yp + vid0_yl)) RETURN(1); RETURN(0);}/* VID0 must be large enough to hold all other windows */static int check_new_vid0_size(u32 xp0, u32 yp0, u32 xl0, u32 yl0){ u32 _xp = 0, _yp = 0, _xl = 0, _yl = 0;#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;}/* 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, 0, 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); 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_mode(info->fix.id); set_win_enable(info->fix.id, 1); RETURN(0);}/** * davincifb_ioctl - handler for private ioctls. */static intdavincifb_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; 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; } 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 */ if (info->fix.visual == FB_VISUAL_TRUECOLOR) { u32 v; if (regno >= 16) RETURN(1); red >>= (16 - info->var.red.length); green >>= (16 - info->var.green.length); blue >>= (16 - info->var.blue.length); v = (red << info->var.red.offset) | (green << info->var.green.offset) | (blue << info->var.blue.offset); switch (info->var.bits_per_pixel) { case 16: ((u16 *) (info->pseudo_palette))[regno] = v; break; default: RETURN(1); } RETURN(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -