📄 omap_fb.c
字号:
int output_dev = omap2_disp_get_output_dev(OMAP2_GRAPHICS); int count = 200; timeout = jiffies + timeout; while (!omap2_disp_reg_sync_done(output_dev) && time_before(jiffies, timeout) && count) { if (busy_wait || in_interrupt()) { udelay(100); count--; } else { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1); if (fb_suspend_data.suspended) return; } } if (!omap2_disp_reg_sync_done(output_dev)) { printk(KERN_WARNING "timeout waiting for display controller " "to save registers\n"); }}/** fbops functions*//* * omap24xxfb_check_var - Validates a var passed in. * @var: frame buffer variable screen structure * @info: frame buffer structure that represents a single frame buffer * * Returns negative errno on error, or zero on success. The var info on * exit may be different than the var info on entry. * * This function accepts any bits-per-pixel value in the range 0 to 32 * (0 to 8 for monochrome displays). If the specified number of * bits-per-pixel isn't supported, then the next greater number of * bits-per-pixel will be substituted. This function differentiates * between color depths of 12 and 16 (which both have 16 bits-per-pixel) * by checking to see if the sum of the lengths of the RGB fields is 12, * in which case the color depth is assumed to be 12. Except for * differentiating between 12-bit and 16-bit color depths, the values * passed in var->red, var->green, and var->blue are ignored and replaced * with the correct values for the specified color depth. * * The xres/yres variables in the var screeninfo specify the size of the * graphics window. The graphics window size must not be larger than the * physical display size nor larger than the size of the framebuffer. * The xres_virtual/yres_virtual values in the var screeninfo specify the * size of the framebuffer in memory. The framebuffer must not be smaller * than the size of the graphics window. The display must not be smaller * than the graphics window. The display size depends on whether the * framebuffer is displayed on LCD or a TV. The xoffset/yoffset variables * in the var screeninfo specify the offset of the graphics window within * the framebuffer. There is no means for the user to specify the offset * of the graphics window on the display, so that offset will always be * zero unless the board-specific mode changing function implements some * other behavior, such as centering. */static intomap24xxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info){ const struct omap24xxfb_info *oinfo = (const struct omap24xxfb_info *) info->par; struct fb_var_screeninfo v; u32 hbp, hfp, hsw, vbp, vfp, vsw; u32 display_xres, display_yres; int output_dev; omap2_disp_get_dss(); output_dev = omap2_disp_get_output_dev(OMAP2_GRAPHICS); DBGENTER; memcpy(&v, var, sizeof(v)); omap2_disp_put_dss(); return 0; /* do board-specific checks on the var */ if (omap24xxfb_check_mode(oinfo, &v)){ omap2_disp_put_dss(); return -EINVAL; } switch (v.bits_per_pixel) { case 0 ... 1: v.bits_per_pixel = 1; break; case 2: v.bits_per_pixel = 2; break; case 3 ... 4: v.bits_per_pixel = 4; break; case 5 ... 8: v.bits_per_pixel = 8; break; case 9 ... 16: if (v.grayscale) { omap2_disp_put_dss(); return -EINVAL; } v.bits_per_pixel = 16; break; case 17 ... 32: if (v.grayscale) { omap2_disp_put_dss(); return -EINVAL; } v.bits_per_pixel = 32; break; default: omap2_disp_put_dss(); return -EINVAL; } switch (var_to_depth(&v)) { case 1: v.red.offset = v.green.offset = v.blue.offset = 0; v.red.length = v.green.length = v.blue.length = 1; v.transp.offset = v.transp.length = 0; break; case 2: v.red.offset = v.green.offset = v.blue.offset = 0; v.red.length = v.green.length = v.blue.length = 2; v.transp.offset = v.transp.length = 0; break; case 4: v.red.offset = v.green.offset = v.blue.offset = 0; v.red.length = v.green.length = v.blue.length = 4; v.transp.offset = v.transp.length = 0; break; case 8: v.red.offset = v.green.offset = v.blue.offset = 0; v.red.length = v.green.length = v.blue.length = 8; v.transp.offset = v.transp.length = 0; break; case 12: v.red.offset = 8; v.green.offset = 4; v.blue.offset = 0; v.red.length = v.green.length = v.blue.length = 4; v.transp.offset = v.transp.length = 0; break; case 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; break; case 24: v.red.offset = 16; v.green.offset = 8; v.blue.offset = 0; v.red.length = v.blue.length = v.green.length = 8; v.transp.offset = v.transp.length = 0; break; case 32: v.red.offset = 24; v.green.offset = 16; v.blue.offset = 8; v.red.length = v.blue.length = v.green.length = 8; v.transp.offset = 0; v.transp.length = 8; break; default: omap2_disp_put_dss(); return -EINVAL; } omap2_disp_get_panel_size(output_dev, &display_xres, &display_yres); if (display_xres > MAX_PIXELS_PER_LINE || display_yres > MAX_LINES) { omap2_disp_put_dss(); return -EINVAL; } if (display_xres == 0 || display_yres == 0) { omap2_disp_put_dss(); return -EINVAL; } if (v.xres_virtual < v.xres || v.yres_virtual < v.yres) { omap2_disp_put_dss(); return -EINVAL; } if (!oinfo->rotation_support) { if (display_xres < v.xres || display_yres < v.yres) { omap2_disp_put_dss(); return -EINVAL; } } else { switch(v.rotate) { case 0: case 180: default: if (display_xres < v.xres || display_yres < v.yres) { omap2_disp_put_dss(); return -EINVAL; } break; case 90: case 270: if (display_xres < v.yres || display_yres < v.xres) { omap2_disp_put_dss(); return -EINVAL; } break; } } if (v.xoffset > v.xres_virtual - v.xres) { omap2_disp_put_dss(); return -EINVAL; } if (v.yoffset > v.yres_virtual - v.yres) { omap2_disp_put_dss(); return -EINVAL; } if ((v.bits_per_pixel < 8) && (((v.xres_virtual % 8) != 0) || ((v.xres % 8) != 0) || ((v.xoffset % 8) != 0))) { omap2_disp_put_dss(); return -EINVAL; } /* check if we have enough video memory to support this framebuffer */ if (((!oinfo->rotation_support) && (((v.xres_virtual*v.yres_virtual*v.bits_per_pixel)/8) > info->fix.smem_len)) || ((oinfo->rotation_support) && (((MAX_PIXELS_PER_LINE*v.yres_virtual*v.bits_per_pixel)/8) > info->fix.smem_len))) { omap2_disp_put_dss(); return -EINVAL; } /* calculate horizontal timing parameters in pixclocks */ hbp = (v.left_margin > 0) ? (v.left_margin - 1) : 0; if (hbp > 255) hbp = 255; hfp = (v.right_margin > 0) ? (v.right_margin - 1) : 0; if (hfp > 255) hfp = 255; hsw = (v.hsync_len > 0) ? (v.hsync_len - 1) : 0; if (hsw > 63) hsw = 63; v.left_margin = hbp + 1; v.right_margin = hfp + 1; v.hsync_len = hsw + 1; /* calculate vertical timing parameters in line clocks */ vbp = v.upper_margin; if (vbp > 255) vbp = 255; vfp = v.lower_margin; if (vfp > 255) vfp = 255; vsw = (v.vsync_len > 0) ? (v.vsync_len - 1) : v.vsync_len; if (vsw > 63) vsw = 63; v.upper_margin = vbp; v.lower_margin = vfp; v.vsync_len = vsw + 1; v.red.msb_right = v.green.msb_right = v.blue.msb_right = v.transp.msb_right = 0; v.nonstd = 0; v.accel_flags = 0; memcpy(var, &v, sizeof(v)); omap2_disp_put_dss(); DBGLEAVE; return 0;}/* Calculates the Graphics pipleline DMA parameters */static intomap24xxfb_set_dma_params(const struct fb_var_screeninfo *var, const struct fb_fix_screeninfo *fix, int rotation, int mirroring){ int context = 0; u32 view_address_base; u32 start, total_width, img_width; u32 row_inc, pix_inc; u32 xoffset, yoffset; if ((rotation > 0) && (rotation % 90 != 0)) return -EINVAL; if (!mirroring) { if (rotation < 0) { view_address_base = fix->smem_start; start = view_address_base + var->yoffset*fix->line_length + (var->xoffset*var->bits_per_pixel)/8; total_width = fix->line_length; img_width = (var->xres * var->bits_per_pixel)/8; } else { view_address_base = SMS_ROT_VIRT_BASE(context, 0); switch (rotation) { /* to the user, xres and yres are interchanged between 0/180 deg and 90/270 deg, but the DMA still has to use the panel's dimension and orientation. */ case 0: case 180: default: xoffset = var->xoffset; if (rotation == 180) xoffset += var->xres_virtual - var->xres; start = view_address_base + var->yoffset*fix->line_length + (xoffset*var->bits_per_pixel)/8; total_width = fix->line_length; img_width = (var->xres * var->bits_per_pixel)/8; break; case 90: case 270: yoffset = var->yoffset; if (rotation == 90) yoffset += var->yres_virtual - var->yres; start = view_address_base + var->xoffset*fix->line_length + (yoffset*var->bits_per_pixel)/8; total_width = fix->line_length; img_width = (var->yres * var->bits_per_pixel)/8; break; } } pix_inc = 1; row_inc = 1 + total_width - img_width; omap2_disp_set_dma_params(OMAP2_GRAPHICS, OMAP2_OUTPUT_LCD, start, start, row_inc, pix_inc); omap2_disp_set_dma_params(OMAP2_GRAPHICS, OMAP2_OUTPUT_TV, start, (start + total_width), (row_inc + total_width), pix_inc); } else { /* mirroring */ if (rotation < 0) { view_address_base = fix->smem_start; img_width = (var->xres * var->bits_per_pixel)/8; start = view_address_base + var->yoffset*fix->line_length + (var->xoffset*var->bits_per_pixel)/8 + (var->xres - 1) * var->bits_per_pixel/8; total_width = fix->line_length; pix_inc = - 2 * (var->bits_per_pixel/8) + 1; row_inc = total_width + (var->xres - 2) * var->bits_per_pixel/8 + 1; omap2_disp_set_dma_params(OMAP2_GRAPHICS, OMAP2_OUTPUT_LCD, start, start, row_inc, pix_inc); omap2_disp_set_dma_params(OMAP2_GRAPHICS, OMAP2_OUTPUT_TV, start, (start + total_width), (row_inc + total_width), pix_inc); } else { view_address_base = SMS_ROT_VIRT_BASE(context, 0); switch (rotation) { case 0: case 180: default: xoffset = var->xoffset; if (rotation == 0) { xoffset += var->xres_virtual - var->xres; } start = view_address_base + (var->yres - var->yoffset - 1) * fix->line_length - (xoffset*var->bits_per_pixel)/8; total_width = fix->line_length; img_width = (var->xres * var->bits_per_pixel)/8; break; case 90: case 270: yoffset = var->yoffset; if (rotation == 270) { yoffset += var->yres_virtual - var->yres; } start = view_address_base + (var->xres - var->xoffset - 1) * fix->line_length + (yoffset*var->bits_per_pixel)/8; total_width = fix->line_length; img_width = (var->yres * var->bits_per_pixel)/8; break; } pix_inc = 1; row_inc = - (total_width + img_width) + 1; omap2_disp_set_dma_params(OMAP2_GRAPHICS, OMAP2_OUTPUT_LCD, start, start, row_inc, pix_inc); omap2_disp_set_dma_params(OMAP2_GRAPHICS, OMAP2_OUTPUT_TV, start, (start - total_width), (row_inc - total_width), pix_inc); } } return 0;}/* * omap24xxfb_set_par - 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 * this particular framebuffer. This function alters the par AND the * fb_fix_screeninfo stored in fb_info. It does 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. * omap24xxfb_check_var is always called before omap24xxfb_set_par to * ensure this. * */static intomap24xxfb_set_par(struct fb_info *info){ struct omap24xxfb_info *oinfo = (struct omap24xxfb_info *) info->par; struct fb_var_screeninfo *var = &info->var; u32 clkdiv, hbp, hfp, hsw, vbp, vfp, vsw; int ret = 0; DBGENTER; if (oinfo->asleep) return 0; omap2_disp_get_dss(); /* update the fix screeninfo */ if (oinfo->rotation_support) { oinfo->rotation_deg = var->rotate; info->fix.line_length = MAX_PIXELS_PER_LINE * var->bits_per_pixel / 8; } else info->fix.line_length = (var->xres_virtual*var->bits_per_pixel)/8; info->fix.visual = ((var_to_depth(var) <= 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR); /* Graphics window parameters */ if ((oinfo->rotation_support) && ((oinfo->rotation_deg == 90) || (oinfo->rotation_deg == 270))) { omap2_disp_config_gfxlayer(var->yres, var->xres, var_to_depth(var)); } else { omap2_disp_config_gfxlayer(var->xres, var->yres, var_to_depth(var)); } omap2_disp_set_gfx_palette(oinfo->palette_phys); /* Rotation */ if (oinfo->rotation_support) { int width = 0, height = 0; if ((var->rotate == 90) || (var->rotate == 270)) { width = var->xres_virtual; height = var->yres_virtual; } else { width = var->yres_virtual; height = var->xres_virtual; } omap2_disp_set_vrfb(0, oinfo->fb_base_phys, width, height, var->bits_per_pixel/8); if(omap24xxfb_mirroring){ info->fix.smem_start = oinfo->sms_rot_phy[omap_rot_mirror_index(oinfo->rotation_deg)]; info->screen_base = (char *)(oinfo->sms_rot_virt[omap_rot_mirror_index(oinfo->rotation_deg)]); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -