📄 atyfb_base.c
字号:
chip_id = aty_ld_le32(CNFG_CHIP_ID, par); type = chip_id & CFG_CHIP_TYPE; rev = (chip_id & CFG_CHIP_REV) >> 24; switch(par->pci_id) {#ifdef CONFIG_FB_ATY_GX case PCI_CHIP_MACH64GX: if(type != 0x00d7) return -ENODEV; break; case PCI_CHIP_MACH64CX: if(type != 0x0057) return -ENODEV; break;#endif#ifdef CONFIG_FB_ATY_CT case PCI_CHIP_MACH64VT: switch (rev & 0x07) { case 0x00: switch (rev & 0xc0) { case 0x00: name = "ATI264VT (A3) (Mach64 VT)"; par->pll_limits.pll_max = 170; par->pll_limits.mclk = 67; par->pll_limits.xclk = 67; par->pll_limits.ecp_max = 80; par->features = ATI_CHIP_264VT; break; case 0x40: name = "ATI264VT2 (A4) (Mach64 VT)"; par->pll_limits.pll_max = 200; par->pll_limits.mclk = 67; par->pll_limits.xclk = 67; par->pll_limits.ecp_max = 80; par->features = ATI_CHIP_264VT | M64F_MAGIC_POSTDIV; break; } break; case 0x01: name = "ATI264VT3 (B1) (Mach64 VT)"; par->pll_limits.pll_max = 200; par->pll_limits.mclk = 67; par->pll_limits.xclk = 67; par->pll_limits.ecp_max = 80; par->features = ATI_CHIP_264VTB; break; case 0x02: name = "ATI264VT3 (B2) (Mach64 VT)"; par->pll_limits.pll_max = 200; par->pll_limits.mclk = 67; par->pll_limits.xclk = 67; par->pll_limits.ecp_max = 80; par->features = ATI_CHIP_264VT3; break; } break; case PCI_CHIP_MACH64GT: switch (rev & 0x07) { case 0x01: name = "3D RAGE II (Mach64 GT)"; par->pll_limits.pll_max = 170; par->pll_limits.mclk = 67; par->pll_limits.xclk = 67; par->pll_limits.ecp_max = 80; par->features = ATI_CHIP_264GTB; break; case 0x02: name = "3D RAGE II+ (Mach64 GT)"; par->pll_limits.pll_max = 200; par->pll_limits.mclk = 67; par->pll_limits.xclk = 67; par->pll_limits.ecp_max = 100; par->features = ATI_CHIP_264GTB; break; } break;#endif } PRINTKI("%s [0x%04x rev 0x%02x]\n", name, type, rev); return 0;}static char ram_dram[] __devinitdata = "DRAM";static char ram_resv[] __devinitdata = "RESV";#ifdef CONFIG_FB_ATY_GXstatic char ram_vram[] __devinitdata = "VRAM";#endif /* CONFIG_FB_ATY_GX */#ifdef CONFIG_FB_ATY_CTstatic char ram_edo[] __devinitdata = "EDO";static char ram_sdram[] __devinitdata = "SDRAM (1:1)";static char ram_sgram[] __devinitdata = "SGRAM (1:1)";static char ram_sdram32[] __devinitdata = "SDRAM (2:1) (32-bit)";static char ram_off[] __devinitdata = "OFF";#endif /* CONFIG_FB_ATY_CT */#ifdef CONFIG_FB_ATY_GXstatic char *aty_gx_ram[8] __devinitdata = { ram_dram, ram_vram, ram_vram, ram_dram, ram_dram, ram_vram, ram_vram, ram_resv};#endif /* CONFIG_FB_ATY_GX */#ifdef CONFIG_FB_ATY_CTstatic char *aty_ct_ram[8] __devinitdata = { ram_off, ram_dram, ram_edo, ram_edo, ram_sdram, ram_sgram, ram_sdram32, ram_resv};#endif /* CONFIG_FB_ATY_CT */static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, struct atyfb_par *par){ u32 pixclock = var->pixclock;#ifdef CONFIG_FB_ATY_GENERIC_LCD u32 lcd_on_off; par->pll.ct.xres = 0; if (par->lcd_table != 0) { lcd_on_off = aty_ld_lcd(LCD_GEN_CNTL, par); if(lcd_on_off & LCD_ON) { par->pll.ct.xres = var->xres; pixclock = par->lcd_pixclock; } }#endif return pixclock;}#if defined(CONFIG_PPC)/* * Apple monitor sense */static int __devinit read_aty_sense(const struct atyfb_par *par){ int sense, i; aty_st_le32(GP_IO, 0x31003100, par); /* drive outputs high */ __delay(200); aty_st_le32(GP_IO, 0, par); /* turn off outputs */ __delay(2000); i = aty_ld_le32(GP_IO, par); /* get primary sense value */ sense = ((i & 0x3000) >> 3) | (i & 0x100); /* drive each sense line low in turn and collect the other 2 */ aty_st_le32(GP_IO, 0x20000000, par); /* drive A low */ __delay(2000); i = aty_ld_le32(GP_IO, par); sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4); aty_st_le32(GP_IO, 0x20002000, par); /* drive A high again */ __delay(200); aty_st_le32(GP_IO, 0x10000000, par); /* drive B low */ __delay(2000); i = aty_ld_le32(GP_IO, par); sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6); aty_st_le32(GP_IO, 0x10001000, par); /* drive B high again */ __delay(200); aty_st_le32(GP_IO, 0x01000000, par); /* drive C low */ __delay(2000); sense |= (aty_ld_le32(GP_IO, par) & 0x3000) >> 12; aty_st_le32(GP_IO, 0, par); /* turn off outputs */ return sense;}#endif /* defined(CONFIG_PPC) *//* ------------------------------------------------------------------------- *//* * CRTC programming */static void aty_get_crtc(const struct atyfb_par *par, struct crtc *crtc){#ifdef CONFIG_FB_ATY_GENERIC_LCD if (par->lcd_table != 0) { if(!M64_HAS(LT_LCD_REGS)) { crtc->lcd_index = aty_ld_le32(LCD_INDEX, par); aty_st_le32(LCD_INDEX, crtc->lcd_index, par); } crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par); crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par); /* switch to non shadow registers */ aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl & ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par); /* save stretching */ crtc->horz_stretching = aty_ld_lcd(HORZ_STRETCHING, par); crtc->vert_stretching = aty_ld_lcd(VERT_STRETCHING, par); if (!M64_HAS(LT_LCD_REGS)) crtc->ext_vert_stretch = aty_ld_lcd(EXT_VERT_STRETCH, par); }#endif crtc->h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par); crtc->h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); crtc->v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par); crtc->v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); crtc->vline_crnt_vline = aty_ld_le32(CRTC_VLINE_CRNT_VLINE, par); crtc->off_pitch = aty_ld_le32(CRTC_OFF_PITCH, par); crtc->gen_cntl = aty_ld_le32(CRTC_GEN_CNTL, par);#ifdef CONFIG_FB_ATY_GENERIC_LCD if (par->lcd_table != 0) { /* switch to shadow registers */ aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) | SHADOW_EN | SHADOW_RW_EN, par); crtc->shadow_h_tot_disp = aty_ld_le32(CRTC_H_TOTAL_DISP, par); crtc->shadow_h_sync_strt_wid = aty_ld_le32(CRTC_H_SYNC_STRT_WID, par); crtc->shadow_v_tot_disp = aty_ld_le32(CRTC_V_TOTAL_DISP, par); crtc->shadow_v_sync_strt_wid = aty_ld_le32(CRTC_V_SYNC_STRT_WID, par); aty_st_le32(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par); }#endif /* CONFIG_FB_ATY_GENERIC_LCD */}static void aty_set_crtc(const struct atyfb_par *par, const struct crtc *crtc){#ifdef CONFIG_FB_ATY_GENERIC_LCD if (par->lcd_table != 0) { /* stop CRTC */ aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~(CRTC_EXT_DISP_EN | CRTC_EN), par); /* update non-shadow registers first */ aty_st_lcd(CNFG_PANEL, crtc->lcd_config_panel, par); aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl & ~(CRTC_RW_SELECT | SHADOW_EN | SHADOW_RW_EN), par); /* temporarily disable stretching */ aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching & ~(HORZ_STRETCH_MODE | HORZ_STRETCH_EN), par); aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching & ~(VERT_STRETCH_RATIO1 | VERT_STRETCH_RATIO2 | VERT_STRETCH_USE0 | VERT_STRETCH_EN), par); }#endif /* turn off CRT */ aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl & ~CRTC_EN, par); DPRINTK("setting up CRTC\n"); DPRINTK("set primary CRT to %ix%i %c%c composite %c\n", ((((crtc->h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->v_tot_disp>>16) & 0x7ff) + 1), (crtc->h_sync_strt_wid & 0x200000)?'N':'P', (crtc->v_sync_strt_wid & 0x200000)?'N':'P', (crtc->gen_cntl & CRTC_CSYNC_EN)?'P':'N'); DPRINTK("CRTC_H_TOTAL_DISP: %x\n",crtc->h_tot_disp); DPRINTK("CRTC_H_SYNC_STRT_WID: %x\n",crtc->h_sync_strt_wid); DPRINTK("CRTC_V_TOTAL_DISP: %x\n",crtc->v_tot_disp); DPRINTK("CRTC_V_SYNC_STRT_WID: %x\n",crtc->v_sync_strt_wid); DPRINTK("CRTC_OFF_PITCH: %x\n", crtc->off_pitch); DPRINTK("CRTC_VLINE_CRNT_VLINE: %x\n", crtc->vline_crnt_vline); DPRINTK("CRTC_GEN_CNTL: %x\n",crtc->gen_cntl); aty_st_le32(CRTC_H_TOTAL_DISP, crtc->h_tot_disp, par); aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->h_sync_strt_wid, par); aty_st_le32(CRTC_V_TOTAL_DISP, crtc->v_tot_disp, par); aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->v_sync_strt_wid, par); aty_st_le32(CRTC_OFF_PITCH, crtc->off_pitch, par); aty_st_le32(CRTC_VLINE_CRNT_VLINE, crtc->vline_crnt_vline, par); aty_st_le32(CRTC_GEN_CNTL, crtc->gen_cntl, par);#if 0 FIXME if (par->accel_flags & FB_ACCELF_TEXT) aty_init_engine(par, info);#endif#ifdef CONFIG_FB_ATY_GENERIC_LCD /* after setting the CRTC registers we should set the LCD registers. */ if (par->lcd_table != 0) { /* switch to shadow registers */ aty_st_lcd(LCD_GEN_CNTL, (crtc->lcd_gen_cntl & ~CRTC_RW_SELECT) | (SHADOW_EN | SHADOW_RW_EN), par); DPRINTK("set shadow CRT to %ix%i %c%c\n", ((((crtc->shadow_h_tot_disp>>16) & 0xff) + 1)<<3), (((crtc->shadow_v_tot_disp>>16) & 0x7ff) + 1), (crtc->shadow_h_sync_strt_wid & 0x200000)?'N':'P', (crtc->shadow_v_sync_strt_wid & 0x200000)?'N':'P'); DPRINTK("SHADOW CRTC_H_TOTAL_DISP: %x\n", crtc->shadow_h_tot_disp); DPRINTK("SHADOW CRTC_H_SYNC_STRT_WID: %x\n", crtc->shadow_h_sync_strt_wid); DPRINTK("SHADOW CRTC_V_TOTAL_DISP: %x\n", crtc->shadow_v_tot_disp); DPRINTK("SHADOW CRTC_V_SYNC_STRT_WID: %x\n", crtc->shadow_v_sync_strt_wid); aty_st_le32(CRTC_H_TOTAL_DISP, crtc->shadow_h_tot_disp, par); aty_st_le32(CRTC_H_SYNC_STRT_WID, crtc->shadow_h_sync_strt_wid, par); aty_st_le32(CRTC_V_TOTAL_DISP, crtc->shadow_v_tot_disp, par); aty_st_le32(CRTC_V_SYNC_STRT_WID, crtc->shadow_v_sync_strt_wid, par); /* restore CRTC selection & shadow state and enable stretching */ DPRINTK("LCD_GEN_CNTL: %x\n", crtc->lcd_gen_cntl); DPRINTK("HORZ_STRETCHING: %x\n", crtc->horz_stretching); DPRINTK("VERT_STRETCHING: %x\n", crtc->vert_stretching); if(!M64_HAS(LT_LCD_REGS)) DPRINTK("EXT_VERT_STRETCH: %x\n", crtc->ext_vert_stretch); aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par); aty_st_lcd(HORZ_STRETCHING, crtc->horz_stretching, par); aty_st_lcd(VERT_STRETCHING, crtc->vert_stretching, par); if(!M64_HAS(LT_LCD_REGS)) { aty_st_lcd(EXT_VERT_STRETCH, crtc->ext_vert_stretch, par); aty_ld_le32(LCD_INDEX, par); aty_st_le32(LCD_INDEX, crtc->lcd_index, par); } }#endif /* CONFIG_FB_ATY_GENERIC_LCD */}static int aty_var_to_crtc(const struct fb_info *info, const struct fb_var_screeninfo *var, struct crtc *crtc){ struct atyfb_par *par = (struct atyfb_par *) info->par; u32 xres, yres, vxres, vyres, xoffset, yoffset, bpp; u32 sync, vmode, vdisplay; u32 h_total, h_disp, h_sync_strt, h_sync_end, h_sync_dly, h_sync_wid, h_sync_pol; u32 v_total, v_disp, v_sync_strt, v_sync_end, v_sync_wid, v_sync_pol, c_sync; u32 pix_width, dp_pix_width, dp_chain_mask; /* input */ xres = var->xres; yres = var->yres; vxres = var->xres_virtual; vyres = var->yres_virtual; xoffset = var->xoffset; yoffset = var->yoffset; bpp = var->bits_per_pixel; if (bpp == 16) bpp = (var->green.length == 5) ? 15 : 16; sync = var->sync; vmode = var->vmode; /* convert (and round up) and validate */ if (vxres < xres + xoffset) vxres = xres + xoffset; h_disp = xres; if (vyres < yres + yoffset) vyres = yres + yoffset; v_disp = yres; if (bpp <= 8) { bpp = 8; pix_width = CRTC_PIX_WIDTH_8BPP; dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; dp_chain_mask = DP_CHAIN_8BPP; } else if (bpp <= 15) { bpp = 16; pix_width = CRTC_PIX_WIDTH_15BPP; dp_pix_width = HOST_15BPP | SRC_15BPP | DST_15BPP | BYTE_ORDER_LSB_TO_MSB; dp_chain_mask = DP_CHAIN_15BPP; } else if (bpp <= 16) { bpp = 16; pix_width = CRTC_PIX_WIDTH_16BPP; dp_pix_width = HOST_16BPP | SRC_16BPP | DST_16BPP | BYTE_ORDER_LSB_TO_MSB; dp_chain_mask = DP_CHAIN_16BPP; } else if (bpp <= 24 && M64_HAS(INTEGRATED)) { bpp = 24; pix_width = CRTC_PIX_WIDTH_24BPP; dp_pix_width = HOST_8BPP | SRC_8BPP | DST_8BPP | BYTE_ORDER_LSB_TO_MSB; dp_chain_mask = DP_CHAIN_24BPP; } else if (bpp <= 32) { bpp = 32; pix_width = CRTC_PIX_WIDTH_32BPP; dp_pix_width = HOST_32BPP | SRC_32BPP | DST_32BPP | BYTE_ORDER_LSB_TO_MSB; dp_chain_mask = DP_CHAIN_32BPP; } else FAIL("invalid bpp"); if (vxres * vyres * bpp / 8 > info->fix.smem_len) FAIL("not enough video RAM"); h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; if((xres > 1600) || (yres > 1200)) { FAIL("MACH64 chips are designed for max 1600x1200\n" "select anoter resolution."); } h_sync_strt = h_disp + var->right_margin; h_sync_end = h_sync_strt + var->hsync_len; h_sync_dly = var->right_margin & 7; h_total = h_sync_end + h_sync_dly + var->left_margin; v_sync_strt = v_disp + var->lower_margin; v_sync_end = v_sync_strt + var->vsync_len; v_total = v_sync_end + var->upper_margin;#ifdef CONFIG_FB_ATY_GENERIC_LCD if (par->lcd_table != 0) { if(!M64_HAS(LT_LCD_REGS)) { u32 lcd_index = aty_ld_le32(LCD_INDEX, par); crtc->lcd_index = lcd_index & ~(LCD_INDEX_MASK | LCD_DISPLAY_DIS | LCD_SRC_SEL | CRTC2_DISPLAY_DIS); aty_st_le32(LCD_INDEX, lcd_index, par); } if (!M64_HAS(MOBIL_BUS)) crtc->lcd_index |= CRTC2_DISPLAY_DIS; crtc->lcd_config_panel = aty_ld_lcd(CNFG_PANEL, par) | 0x4000; crtc->lcd_gen_cntl = aty_ld_lcd(LCD_GEN_CNTL, par) & ~CRTC_RW_SELECT; crtc->lcd_gen_cntl &= ~(HORZ_DIVBY2_EN | DIS_HOR_CRT_DIVBY2 | TVCLK_PM_EN | /*VCLK_DAC_PM_EN | USE_SHADOWED_VEND |*/ USE_SHADOWED_ROWCUR | SHADOW_EN | SHADOW_RW_EN); crtc->lcd_gen_cntl |= DONT_SHADOW_VPAR | LOCK_8DOT; if((crtc->lcd_gen_cntl & LCD_ON) && ((xres > par->lcd_width) || (yres > par->lcd_height))) { /* We cannot display the mode on the LCD. If the CRT is enabled we can turn off the LCD. If the CRT is off, it isn't a good idea to switch it on; we don't know if one is connected. So it's better to fail then. */ if (crtc->lcd_gen_cntl & CRT_ON) { if (!(var->activate & FB_ACTIVATE_TEST)) PRINTKI("Disable LCD panel, because video mode does not fit.\n"); crtc->lcd_gen_cntl &= ~LCD_ON; /*aty_st_lcd(LCD_GEN_CNTL, crtc->lcd_gen_cntl, par);*/ } else { if (!(var->activate & FB_ACTIVATE_TEST)) PRINTKE("Video mode exceeds size of LCD panel.\nConnect this computer to a conventional monitor if you really need this mode.\n"); return -EINVAL; } } } if ((par->lcd_table != 0) && (crtc->lcd_gen_cntl & LCD_ON)) { int VScan = 1; /* bpp -> bytespp, 1,4 -> 0; 8 -> 2; 15,16 -> 1; 24 -> 6; 32 -> 5 const u8 DFP_h_sync_dly_LT[] = { 0, 2, 1, 6, 5 }; const u8 ADD_to_strt_wid_and_dly_LT_DAC[] = { 0, 5, 6, 9, 9, 12, 12 }; */ vmode &= ~(FB_VMODE_DOUBLE | FB_VMODE_INTERLACED);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -