📄 i810_main.c
字号:
static void i810_restore_vga_state(struct i810fb_par *par){ u8 __iomem *mmio = par->mmio_start_virtual; i810_screen_off(mmio, OFF); i810_protect_regs(mmio, OFF); i810_dram_off(mmio, OFF); i810_restore_pll(par); i810_restore_dac(par); i810_restore_vga(par); i810_restore_vgax(par); i810_restore_addr_map(par); i810_dram_off(mmio, ON); i810_restore_2d(par); i810_screen_off(mmio, ON); i810_protect_regs(mmio, ON);}/*********************************************************************** * VGA State Save * ***********************************************************************/static void i810_save_vgax(struct i810fb_par *par){ u8 i; u8 __iomem *mmio = par->mmio_start_virtual; for (i = 0; i < 4; i++) { i810_writeb(CR_INDEX_CGA, mmio, CR30 + i); *(&(par->hw_state.cr30) + i) = i810_readb(CR_DATA_CGA, mmio); } i810_writeb(CR_INDEX_CGA, mmio, CR35); par->hw_state.cr35 = i810_readb(CR_DATA_CGA, mmio); i810_writeb(CR_INDEX_CGA, mmio, CR39); par->hw_state.cr39 = i810_readb(CR_DATA_CGA, mmio); i810_writeb(CR_INDEX_CGA, mmio, CR41); par->hw_state.cr41 = i810_readb(CR_DATA_CGA, mmio); i810_writeb(CR_INDEX_CGA, mmio, CR70); par->hw_state.cr70 = i810_readb(CR_DATA_CGA, mmio); par->hw_state.msr = i810_readb(MSR_READ, mmio); i810_writeb(CR_INDEX_CGA, mmio, CR80); par->hw_state.cr80 = i810_readb(CR_DATA_CGA, mmio); i810_writeb(SR_INDEX, mmio, SR01); par->hw_state.sr01 = i810_readb(SR_DATA, mmio);}static void i810_save_vga(struct i810fb_par *par){ u8 i; u8 __iomem *mmio = par->mmio_start_virtual; for (i = 0; i < 10; i++) { i810_writeb(CR_INDEX_CGA, mmio, CR00 + i); *((&par->hw_state.cr00) + i) = i810_readb(CR_DATA_CGA, mmio); } for (i = 0; i < 8; i++) { i810_writeb(CR_INDEX_CGA, mmio, CR10 + i); *((&par->hw_state.cr10) + i) = i810_readb(CR_DATA_CGA, mmio); }}static void i810_save_2d(struct i810fb_par *par){ u8 __iomem *mmio = par->mmio_start_virtual; par->hw_state.dclk_2d = i810_readl(DCLK_2D, mmio); par->hw_state.dclk_1d = i810_readl(DCLK_1D, mmio); par->hw_state.dclk_0ds = i810_readl(DCLK_0DS, mmio); par->hw_state.pixconf = i810_readl(PIXCONF, mmio); par->hw_state.fw_blc = i810_readl(FW_BLC, mmio); par->hw_state.bltcntl = i810_readw(BLTCNTL, mmio); par->hw_state.hwstam = i810_readw(HWSTAM, mmio); par->hw_state.hws_pga = i810_readl(HWS_PGA, mmio); par->hw_state.ier = i810_readw(IER, mmio); par->hw_state.imr = i810_readw(IMR, mmio); par->hw_state.dplystas = i810_readl(DPLYSTAS, mmio);}static void i810_save_vga_state(struct i810fb_par *par){ i810_save_vga(par); i810_save_vgax(par); i810_save_2d(par);}/************************************************************ * Helpers * ************************************************************//** * get_line_length - calculates buffer pitch in bytes * @par: pointer to i810fb_par structure * @xres_virtual: virtual resolution of the frame * @bpp: bits per pixel * * DESCRIPTION: * Calculates buffer pitch in bytes. */static u32 get_line_length(struct i810fb_par *par, int xres_virtual, int bpp){ u32 length; length = xres_virtual*bpp; length = (length+31)&-32; length >>= 3; return length;}/** * i810_calc_dclk - calculates the P, M, and N values of a pixelclock value * @freq: target pixelclock in picoseconds * @m: where to write M register * @n: where to write N register * @p: where to write P register * * DESCRIPTION: * Based on the formula Freq_actual = (4*M*Freq_ref)/(N^P) * Repeatedly computes the Freq until the actual Freq is equal to * the target Freq or until the loop count is zero. In the latter * case, the actual frequency nearest the target will be used. */static void i810_calc_dclk(u32 freq, u32 *m, u32 *n, u32 *p){ u32 m_reg, n_reg, p_divisor, n_target_max; u32 m_target, n_target, p_target, n_best, m_best, mod; u32 f_out, target_freq, diff = 0, mod_min, diff_min; diff_min = mod_min = 0xFFFFFFFF; n_best = m_best = m_target = f_out = 0; target_freq = freq; n_target_max = 30; /* * find P such that target freq is 16x reference freq (Hz). */ p_divisor = 1; p_target = 0; while(!((1000000 * p_divisor)/(16 * 24 * target_freq)) && p_divisor <= 32) { p_divisor <<= 1; p_target++; } n_reg = m_reg = n_target = 3; while (diff_min && mod_min && (n_target < n_target_max)) { f_out = (p_divisor * n_reg * 1000000)/(4 * 24 * m_reg); mod = (p_divisor * n_reg * 1000000) % (4 * 24 * m_reg); m_target = m_reg; n_target = n_reg; if (f_out <= target_freq) { n_reg++; diff = target_freq - f_out; } else { m_reg++; diff = f_out - target_freq; } if (diff_min > diff) { diff_min = diff; n_best = n_target; m_best = m_target; } if (!diff && mod_min > mod) { mod_min = mod; n_best = n_target; m_best = m_target; } } if (m) *m = (m_best - 2) & 0x3FF; if (n) *n = (n_best - 2) & 0x3FF; if (p) *p = (p_target << 4);}/************************************************************* * Hardware Cursor Routines * *************************************************************//** * i810_enable_cursor - show or hide the hardware cursor * @mmio: address of register space * @mode: show (1) or hide (0) * * Description: * Shows or hides the hardware cursor */static void i810_enable_cursor(u8 __iomem *mmio, int mode){ u32 temp; temp = i810_readl(PIXCONF, mmio); temp = (mode == ON) ? temp | CURSOR_ENABLE_MASK : temp & ~CURSOR_ENABLE_MASK; i810_writel(PIXCONF, mmio, temp);}static void i810_reset_cursor_image(struct i810fb_par *par){ u8 __iomem *addr = par->cursor_heap.virtual; int i, j; for (i = 64; i--; ) { for (j = 0; j < 8; j++) { i810_writeb(j, addr, 0xff); i810_writeb(j+8, addr, 0x00); } addr +=16; }}static void i810_load_cursor_image(int width, int height, u8 *data, struct i810fb_par *par){ u8 __iomem *addr = par->cursor_heap.virtual; int i, j, w = width/8; int mod = width % 8, t_mask, d_mask; t_mask = 0xff >> mod; d_mask = ~(0xff >> mod); for (i = height; i--; ) { for (j = 0; j < w; j++) { i810_writeb(j+0, addr, 0x00); i810_writeb(j+8, addr, *data++); } if (mod) { i810_writeb(j+0, addr, t_mask); i810_writeb(j+8, addr, *data++ & d_mask); } addr += 16; }}static void i810_load_cursor_colors(int fg, int bg, struct fb_info *info){ struct i810fb_par *par = (struct i810fb_par *) info->par; u8 __iomem *mmio = par->mmio_start_virtual; u8 red, green, blue, trans, temp; i810fb_getcolreg(bg, &red, &green, &blue, &trans, info); temp = i810_readb(PIXCONF1, mmio); i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE); i810_write_dac(4, red, green, blue, mmio); i810_writeb(PIXCONF1, mmio, temp); i810fb_getcolreg(fg, &red, &green, &blue, &trans, info); temp = i810_readb(PIXCONF1, mmio); i810_writeb(PIXCONF1, mmio, temp | EXTENDED_PALETTE); i810_write_dac(5, red, green, blue, mmio); i810_writeb(PIXCONF1, mmio, temp);}/** * i810_init_cursor - initializes the cursor * @par: pointer to i810fb_par structure * * DESCRIPTION: * Initializes the cursor registers */static void i810_init_cursor(struct i810fb_par *par){ u8 __iomem *mmio = par->mmio_start_virtual; i810_enable_cursor(mmio, OFF); i810_writel(CURBASE, mmio, par->cursor_heap.physical); i810_writew(CURCNTR, mmio, COORD_ACTIVE | CURSOR_MODE_64_XOR);} /********************************************************************* * Framebuffer hook helpers * *********************************************************************//** * i810_round_off - Round off values to capability of hardware * @var: pointer to fb_var_screeninfo structure * * DESCRIPTION: * @var contains user-defined information for the mode to be set. * This will try modify those values to ones nearest the * capability of the hardware */static void i810_round_off(struct fb_var_screeninfo *var){ u32 xres, yres, vxres, vyres; /* * Presently supports only these configurations */ xres = var->xres; yres = var->yres; vxres = var->xres_virtual; vyres = var->yres_virtual; var->bits_per_pixel += 7; var->bits_per_pixel &= ~7; if (var->bits_per_pixel < 8) var->bits_per_pixel = 8; if (var->bits_per_pixel > 32) var->bits_per_pixel = 32; round_off_xres(&xres); if (xres < 40) xres = 40; if (xres > 2048) xres = 2048; xres = (xres + 7) & ~7; if (vxres < xres) vxres = xres; round_off_yres(&xres, &yres); if (yres < 1) yres = 1; if (yres >= 2048) yres = 2048; if (vyres < yres) vyres = yres; if (var->bits_per_pixel == 32) var->accel_flags = 0; /* round of horizontal timings to nearest 8 pixels */ var->left_margin = (var->left_margin + 4) & ~7; var->right_margin = (var->right_margin + 4) & ~7; var->hsync_len = (var->hsync_len + 4) & ~7; if (var->vmode & FB_VMODE_INTERLACED) { if (!((yres + var->upper_margin + var->vsync_len + var->lower_margin) & 1)) var->upper_margin++; } var->xres = xres; var->yres = yres; var->xres_virtual = vxres; var->yres_virtual = vyres;} /** * set_color_bitfields - sets rgba fields * @var: pointer to fb_var_screeninfo * * DESCRIPTION: * The length, offset and ordering for each color field * (red, green, blue) will be set as specified * by the hardware */ static void set_color_bitfields(struct fb_var_screeninfo *var){ switch (var->bits_per_pixel) { case 8: var->red.offset = 0; var->red.length = 8; var->green.offset = 0; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.offset = 0; var->transp.length = 0; break; case 16: var->green.length = (var->green.length == 5) ? 5 : 6; var->red.length = 5; var->blue.length = 5; var->transp.length = 6 - var->green.length; var->blue.offset = 0; var->green.offset = 5; var->red.offset = 5 + var->green.length; var->transp.offset = (5 + var->red.offset) & 15; break; case 24: /* RGB 888 */ case 32: /* RGBA 8888 */ var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; var->transp.length = var->bits_per_pixel - 24; var->transp.offset = (var->transp.length) ? 24 : 0; break; } var->red.msb_right = 0; var->green.msb_right = 0; var->blue.msb_right = 0; var->transp.msb_right = 0;}/** * i810_check_params - check if contents in var are valid * @var: pointer to fb_var_screeninfo * @info: pointer to fb_info * * DESCRIPTION: * This will check if the framebuffer size is sufficient * for the current mode and if the user's monitor has the * required specifications to display the current mode. */static int i810_check_params(struct fb_var_screeninfo *var, struct fb_info *info){ struct i810fb_par *par = (struct i810fb_par *) info->par; int line_length, vidmem, mode_valid = 0, retval = 0; u32 vyres = var->yres_virtual, vxres = var->xres_virtual; /* * Memory limit */ line_length = get_line_length(par, vxres, var->bits_per_pixel); vidmem = line_length*vyres; if (vidmem > par->fb.size) { vyres = par->fb.size/line_length; if (vyres < var->yres) { vyres = yres; vxres = par->fb.size/vyres; vxres /= var->bits_per_pixel >> 3; line_length = get_line_length(par, vxres, var->bits_per_pixel); vidmem = line_length * yres; if (vxres < var->xres) { printk("i810fb: required video memory, " "%d bytes, for %dx%d-%d (virtual) " "is out of range\n", vidmem, vxres, vyres, var->bits_per_pixel); return -ENOMEM; } } } var->xres_virtual = vxres; var->yres_virtual = vyres; /* * Monitor limit */ switch (var->bits_per_pixel) { case 8: info->monspecs.dclkmax = 234000000; break; case 16: info->monspecs.dclkmax = 229000000; break; case 24: case 32: info->monspecs.dclkmax = 204000000; break; } info->monspecs.dclkmin = 15000000; if (!fb_validate_mode(var, info)) mode_valid = 1;#ifdef CONFIG_FB_I810_I2C if (!mode_valid && info->monspecs.gtf && !fb_get_mode(FB_MAXTIMINGS, 0, var, info)) mode_valid = 1; if (!mode_valid && info->monspecs.modedb_len) { struct fb_videomode *mode; mode = fb_find_best_mode(var, &info->modelist); if (mode) { fb_videomode_to_var(var, mode); mode_valid = 1; } }#endif if (!mode_valid && info->monspecs.modedb_len == 0) { if (fb_get_mode(FB_MAXTIMINGS, 0, var, info)) { int default_sync = (info->monspecs.hfmin-HFMIN) |(info->monspecs.hfmax-HFMAX) |(info->monspecs.vfmin-VFMIN) |(info->monspecs.vfmax-VFMAX); printk("i810fb: invalid video mode%s\n", default_sync ? "" : ". Specifying " "vsyncN/hsyncN parameters may help"); retval = -EINVAL; } } return retval;} /** * encode_fix - fill up fb_fix_screeninfo structure * @fix: pointer to fb_fix_screeninfo * @info: pointer to fb_info * * DESCRIPTION: * This will set up parameters that are unmodifiable by the user. */static int encode_fix(struct fb_fix_screeninfo *fix, struct fb_info *info){ struct i810fb_par *par = (struct i810fb_par *) info->par; memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id, "I810"); fix->smem_start = par->fb.physical; fix->smem_len = par->fb.size; fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; fix->xpanstep = 8; fix->ypanstep = 1; switch (info->var.bits_per_pixel) { case 8: fix->visual = FB_VISUAL_PSEUDOCOLOR; break; case 16: case 24: case 32: if (info->var.nonstd) fix->visual = FB_VISUAL_DIRECTCOLOR; else fix->visual = FB_VISUAL_TRUECOLOR; break; default: return -EINVAL; } fix->ywrapstep = 0; fix->line_length = par->pitch; fix->mmio_start = par->mmio_start_phys; fix->mmio_len = MMIO_SIZE; fix->accel = FB_ACCEL_I810; return 0;}/** * decode_var - modify par according to contents of var * @var: pointer to fb_var_screeninfo * @par: pointer to i810fb_par *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -