📄 atyfb_base.c
字号:
((h_sync_strt & 0x100)<<4) | (h_sync_wid<<16) | (h_sync_pol<<21); crtc->v_tot_disp = v_total | (v_disp<<16); crtc->v_sync_strt_wid = v_sync_strt | (v_sync_wid<<16) | (v_sync_pol<<21);#ifdef CONFIG_FB_ATY_GENERIC_LCD /* No hardware stretching please! */ crtc->h_stretching = 0; crtc->v_stretching = 0; } else { /* This is horror! When we simulate, say 640x480 on an 800x600 lcd monitor, the CRTC should be programmed 800x600 values for the non visible part, but 640x480 for the visible part. This code has been tested on a laptop with it's 800x600 lcd monitor and a conventional monitor both switched on. Tested modes: 640x400, 720x400, 800x600, 320x200-doublescan, 800x600-interlaced */ lcd_htotal = h_disp + info->lcd_hblank_width; lcd_hsync_start = h_disp + info->lcd_right; lcd_vtotal = v_disp + info->lcd_vblank_width; lcd_vsync_start = v_disp + info->lcd_lower; crtc->h_tot_disp = (lcd_htotal) | (h_disp<<16); crtc->h_sync_strt_wid = (lcd_hsync_start & 0xff) | (info->lcd_hsync_delay<<8) | ((lcd_hsync_start & 0x100)<<4) | (info->lcd_hsync_width<<16); crtc->v_tot_disp = lcd_vtotal | (v_disp<<16); crtc->v_sync_strt_wid = lcd_vsync_start | (info->lcd_vsync_width<<16); /* To simulate the requested video mode, we use the hardware stretcher, which zooms the image to the dimensions of the LCD screen. It has two modes; replication and blending. Replication duplicates some pixels, blending interpolates between pixels. We use blending. The formula for blending is: h_stretching=(source_with/dest_width)*4096 v_stretching=(source_lines/dest_lines)*1024 */ if (xres != info->lcd_width) crtc->h_stretching = (xres*4096)/info->lcd_width; else crtc->h_stretching = 0; if (ryres != info->lcd_height) crtc->v_stretching = (ryres*1024)/info->lcd_height; else crtc->v_stretching = 0; /* The prefered mode for the lcd is not interlaced, so disable it if it was enabled. For doublescan there is no problem, because we can compensate for it in the hardware stretching (we stretch half as much) */ crtc->gen_cntl&=~CRTC_INTERLACE_EN; }; crtc->monitors_enabled = *monitors_enabled;#endif if (M64_HAS(MAGIC_FIFO)) { /* Not VTB/GTB */ /* FIXME: magic FIFO values */ crtc->gen_cntl |= aty_ld_le32(CRTC_GEN_CNTL, info) & 0x000e0000; } crtc->dp_pix_width = dp_pix_width; crtc->dp_chain_mask = dp_chain_mask; return 0;}static int aty_crtc_to_var(const struct crtc *crtc, struct fb_var_screeninfo *var){ u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync; u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync; u32 pix_width; u32 double_scan, interlace; /* input */ h_total = crtc->h_tot_disp & 0x1ff; h_disp = (crtc->h_tot_disp>>16) & 0xff; h_sync_strt = (crtc->h_sync_strt_wid & 0xff) | ((crtc->h_sync_strt_wid>>4) & 0x100); h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7; h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f; h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1; v_total = crtc->v_tot_disp & 0x7ff; v_disp = (crtc->v_tot_disp>>16) & 0x7ff; v_sync_strt = crtc->v_sync_strt_wid & 0x7ff; v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f; v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1; c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0; pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK; double_scan = crtc->gen_cntl & CRTC_DBL_SCAN_EN; interlace = crtc->gen_cntl & CRTC_INTERLACE_EN; /* convert */ xres = (h_disp+1)*8; yres = v_disp+1; left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly; right = (h_sync_strt-h_disp)*8+h_sync_dly; hslen = h_sync_wid*8; upper = v_total-v_sync_strt-v_sync_wid; lower = v_sync_strt-v_disp; vslen = v_sync_wid; sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) | (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) | (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0); switch (pix_width) {#if 0 case CRTC_PIX_WIDTH_4BPP: bpp = 4; 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;#endif case CRTC_PIX_WIDTH_8BPP: bpp = 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 CRTC_PIX_WIDTH_15BPP: /* RGB 555 */ bpp = 16; var->red.offset = 10; var->red.length = 5; var->green.offset = 5; var->green.length = 5; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; break;#if 0 case CRTC_PIX_WIDTH_16BPP: /* RGB 565 */ bpp = 16; var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = 0; var->transp.length = 0; break;#endif case CRTC_PIX_WIDTH_24BPP: /* RGB 888 */ bpp = 24; 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.offset = 0; var->transp.length = 0; break; case CRTC_PIX_WIDTH_32BPP: /* ARGB 8888 */ bpp = 32; 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.offset = 24; var->transp.length = 8; break; default: FAIL("Invalid pixel width"); } /* output */ var->xres = xres; var->yres = yres; var->xres_virtual = crtc->vxres; var->yres_virtual = crtc->vyres; var->bits_per_pixel = bpp; var->xoffset = crtc->xoffset; var->yoffset = crtc->yoffset; var->left_margin = left; var->right_margin = right; var->upper_margin = upper; var->lower_margin = lower; var->hsync_len = hslen; var->vsync_len = vslen; var->sync = sync; var->vmode = FB_VMODE_NONINTERLACED; /* In double scan mode, the vertical parameters are doubled, so we need to half them to get the right values. In interlaced mode the values are already correct, so no correction is necessary. Code has been tested in 1024x768, 43 Hz interlaced and 640x480, 60 Hz doublesscan. */ if (interlace) var->vmode = FB_VMODE_INTERLACED; if (double_scan) { var->vmode = FB_VMODE_DOUBLE; var->yres>>=1; var->upper_margin>>=1; var->lower_margin>>=1; var->vsync_len>>=1; }; return 0;}/* ------------------------------------------------------------------------- */static void atyfb_set_par(const struct atyfb_par *par, struct fb_info_aty *info){ u32 i; int accelmode; u8 tmp; accelmode = par->accel_flags; /* hack */ info->current_par = *par; if (info->blitter_may_be_busy) wait_for_idle(info); tmp = aty_ld_8(CRTC_GEN_CNTL + 3, info); aty_set_crtc(info, &par->crtc);#if 0 aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info); /* better call aty_StrobeClock ?? */ aty_st_8(CLOCK_CNTL + info->clk_wr_offset, CLOCK_STROBE, info);#endif aty_st_8(CLOCK_CNTL, 0, info); aty_st_8(CLOCK_CNTL, CLOCK_STROBE | CLOCK_DIV, info); info->dac_ops->set_dac(info, &par->pll, par->crtc.bpp, accelmode); info->pll_ops->set_pll(info, &par->pll); if (!M64_HAS(INTEGRATED)) { /* Don't forget MEM_CNTL */ i = aty_ld_le32(MEM_CNTL, info) & 0xf0ffffff; switch (par->crtc.bpp) { case 8: i |= 0x02000000; break; case 16: i |= 0x03000000; break; case 32: i |= 0x06000000; break; } aty_st_le32(MEM_CNTL, i, info); } else { i = aty_ld_le32(MEM_CNTL, info) & 0xf00fffff; if (!M64_HAS(MAGIC_POSTDIV)) i |= info->mem_refresh_rate << 20; switch (par->crtc.bpp) { case 8: case 24: i |= 0x00000000; break; case 16: i |= 0x04000000; break; case 32: i |= 0x08000000; break; } if (M64_HAS(CT_BUS)) { aty_st_le32(DAC_CNTL, 0x87010184, info); aty_st_le32(BUS_CNTL, 0x680000f9, info); } else if (M64_HAS(VT_BUS)) { aty_st_le32(DAC_CNTL, 0x87010184, info); aty_st_le32(BUS_CNTL, 0x680000f9, info); } else if (M64_HAS(MOBIL_BUS)) { aty_st_le32(DAC_CNTL, 0x80010102, info); aty_st_le32(BUS_CNTL, 0x7b33a040, info); } else { /* GT */ aty_st_le32(DAC_CNTL, 0x86010102, info); aty_st_le32(BUS_CNTL, 0x7b23a040, info); aty_st_le32(EXT_MEM_CNTL, aty_ld_le32(EXT_MEM_CNTL, info) | 0x5000001, info); } aty_st_le32(MEM_CNTL, i, info); } aty_st_8(DAC_MASK, 0xff, info); /* Initialize the graphics engine */ if (par->accel_flags & FB_ACCELF_TEXT) aty_init_engine(par, info);#ifdef CONFIG_FB_COMPAT_XPMAC if (!console_fb_info || console_fb_info == &info->fb_info) { struct fb_var_screeninfo var; int vmode, cmode; display_info.height = ((par->crtc.v_tot_disp>>16) & 0x7ff)+1; display_info.width = (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8; display_info.depth = par->crtc.bpp; display_info.pitch = par->crtc.vxres*par->crtc.bpp/8; atyfb_encode_var(&var, par, info); if (mac_var_to_vmode(&var, &vmode, &cmode)) display_info.mode = 0; else display_info.mode = vmode; strcpy(display_info.name, atyfb_name); display_info.fb_address = info->frame_buffer_phys; display_info.cmap_adr_address = info->ati_regbase_phys+0xc0; display_info.cmap_data_address = info->ati_regbase_phys+0xc1; display_info.disp_reg_address = info->ati_regbase_phys; }#endif /* CONFIG_FB_COMPAT_XPMAC */#ifdef CONFIG_BOOTX_TEXT btext_update_display(info->frame_buffer_phys, (((par->crtc.h_tot_disp>>16) & 0xff)+1)*8, ((par->crtc.v_tot_disp>>16) & 0x7ff)+1, par->crtc.bpp, par->crtc.vxres*par->crtc.bpp/8);#endif /* CONFIG_BOOTX_TEXT */}static int atyfb_decode_var(const struct fb_var_screeninfo *var, struct atyfb_par *par, const struct fb_info_aty *info, u32 monitors_enabled){ int err; u32 pixclock,xres; err = aty_var_to_crtc(info, var, &par->crtc, &monitors_enabled); if (err == 0) { /* Alert! aty_var_to_crtc can modify monitors_enabled which is important for the pixclock decision */ pixclock = var->pixclock; xres = 0;#ifdef CONFIG_FB_ATY_GENERIC_LCD if ((info->lcd_table != 0) && ((monitors_enabled & LCD_ON) != 0)) { pixclock = info->lcd_pixclock; xres = var->xres; };#endif if (pixclock == 0) { FAIL("Invalid pixclock"); } else err = info->pll_ops->var_to_pll(info, pixclock, par->crtc.bpp, xres, &par->pll); }; if (err != 0) return err; if (var->accel_flags & FB_ACCELF_TEXT) par->accel_flags = FB_ACCELF_TEXT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -