atyfb.c
来自「讲述linux的初始化过程」· C语言 代码 · 共 2,436 行 · 第 1/5 页
C
2,436 行
static int currcon = 0;static struct fb_ops atyfb_ops = { owner: THIS_MODULE, fb_open: atyfb_open, fb_release: atyfb_release, fb_get_fix: atyfb_get_fix, fb_get_var: atyfb_get_var, fb_set_var: atyfb_set_var, fb_get_cmap: atyfb_get_cmap, fb_set_cmap: atyfb_set_cmap, fb_pan_display: atyfb_pan_display, fb_ioctl: atyfb_ioctl,#ifdef __sparc__ fb_mmap: atyfb_mmap,#endif fb_rasterimg: atyfb_rasterimg,};static char atyfb_name[16] = "ATY Mach64";static char fontname[40] __initdata = { 0 };static char curblink __initdata = 1;static char noaccel __initdata = 0;static u32 default_vram __initdata = 0;static int default_pll __initdata = 0;static int default_mclk __initdata = 0;#ifndef MODULEstatic const char *mode_option __initdata = NULL;#endif#ifdef CONFIG_PPC#ifdef CONFIG_NVRAM_NOT_DEFINEDstatic int default_vmode __initdata = VMODE_NVRAM;static int default_cmode __initdata = CMODE_NVRAM;#elsestatic int default_vmode __initdata = VMODE_CHOOSE;static int default_cmode __initdata = CMODE_CHOOSE;#endif#endif#ifdef CONFIG_ATARIstatic unsigned int mach64_count __initdata = 0;static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };static unsigned long phys_size[FB_MAX] __initdata = { 0, };static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };#endifstatic struct aty_features { u16 pci_id; u16 chip_type; const char *name;} aty_features[] __initdata = { /* mach64GX family */ { 0x4758, 0x00d7, "mach64GX (ATI888GX00)" }, { 0x4358, 0x0057, "mach64CX (ATI888CX00)" }, /* mach64CT family */ { 0x4354, 0x4354, "mach64CT (ATI264CT)" }, { 0x4554, 0x4554, "mach64ET (ATI264ET)" }, /* mach64CT family / mach64VT class */ { 0x5654, 0x5654, "mach64VT (ATI264VT)" }, { 0x5655, 0x5655, "mach64VTB (ATI264VTB)" }, { 0x5656, 0x5656, "mach64VT4 (ATI264VT4)" }, /* mach64CT family / mach64GT (3D RAGE) class */ { 0x4c42, 0x4c42, "3D RAGE LT PRO (AGP)" }, { 0x4c44, 0x4c44, "3D RAGE LT PRO" }, { 0x4c47, 0x4c47, "3D RAGE LT-G" }, { 0x4c49, 0x4c49, "3D RAGE LT PRO" }, { 0x4c50, 0x4c50, "3D RAGE LT PRO" }, { 0x4c54, 0x4c54, "3D RAGE LT" }, { 0x4754, 0x4754, "3D RAGE (GT)" }, { 0x4755, 0x4755, "3D RAGE II+ (GTB)" }, { 0x4756, 0x4756, "3D RAGE IIC (PCI)" }, { 0x4757, 0x4757, "3D RAGE IIC (AGP)" }, { 0x475a, 0x475a, "3D RAGE IIC (AGP)" }, { 0x4742, 0x4742, "3D RAGE PRO (BGA, AGP)" }, { 0x4744, 0x4744, "3D RAGE PRO (BGA, AGP, 1x only)" }, { 0x4749, 0x4749, "3D RAGE PRO (BGA, PCI)" }, { 0x4750, 0x4750, "3D RAGE PRO (PQFP, PCI)" }, { 0x4751, 0x4751, "3D RAGE PRO (PQFP, PCI, limited 3D)" }, { 0x4c4d, 0x4c4d, "3D RAGE Mobility (PCI)" }, { 0x4c4e, 0x4c4e, "3D RAGE Mobility (AGP)" },};static const char *aty_gx_ram[8] __initdata = { "DRAM", "VRAM", "VRAM", "DRAM", "DRAM", "VRAM", "VRAM", "RESV"};static const char *aty_ct_ram[8] __initdata = { "OFF", "DRAM", "EDO", "EDO", "SDRAM", "SGRAM", "WRAM", "RESV"};static inline u32 aty_ld_le32(int regindex, const struct fb_info_aty *info){ /* Hack for bloc 1, should be cleanly optimized by compiler */ if (regindex >= 0x400) regindex -= 0x800;#if defined(__mc68000__) return le32_to_cpu(*((volatile u32 *)(info->ati_regbase+regindex)));#else return readl (info->ati_regbase + regindex);#endif}static inline void aty_st_le32(int regindex, u32 val, const struct fb_info_aty *info){ /* Hack for bloc 1, should be cleanly optimized by compiler */ if (regindex >= 0x400) regindex -= 0x800;#if defined(__mc68000__) *((volatile u32 *)(info->ati_regbase+regindex)) = cpu_to_le32(val);#else writel (val, info->ati_regbase + regindex);#endif}static inline u8 aty_ld_8(int regindex, const struct fb_info_aty *info){ /* Hack for bloc 1, should be cleanly optimized by compiler */ if (regindex >= 0x400) regindex -= 0x800; return readb (info->ati_regbase + regindex);}static inline void aty_st_8(int regindex, u8 val, const struct fb_info_aty *info){ /* Hack for bloc 1, should be cleanly optimized by compiler */ if (regindex >= 0x400) regindex -= 0x800; writeb (val, info->ati_regbase + regindex);}#if defined(CONFIG_PPC) || defined(CONFIG_PMAC_PBOOK)static void aty_st_lcd(int index, u32 val, const struct fb_info_aty *info){ unsigned long temp; /* write addr byte */ temp = aty_ld_le32(LCD_INDEX, info); aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); /* write the register value */ aty_st_le32(LCD_DATA, val, info);}static u32 aty_ld_lcd(int index, const struct fb_info_aty *info){ unsigned long temp; /* write addr byte */ temp = aty_ld_le32(LCD_INDEX, info); aty_st_le32(LCD_INDEX, (temp & ~LCD_INDEX_MASK) | index, info); /* read the register value */ return aty_ld_le32(LCD_DATA, info);}#endif /* * Generic Mach64 routines */ /* * All writes to draw engine registers are automatically routed through a * 32-bit-wide, 16-entry-deep command FIFO ... * Register writes to registers with DWORD offsets less than 40h are not * FIFOed. * (from Chapter 5 of the Mach64 Programmer's Guide) */static inline void wait_for_fifo(u16 entries, const struct fb_info_aty *info){ while ((aty_ld_le32(FIFO_STAT, info) & 0xffff) > ((u32)(0x8000 >> entries)));}static inline void wait_for_idle(struct fb_info_aty *info){ wait_for_fifo(16, info); while ((aty_ld_le32(GUI_STAT, info) & 1)!= 0); info->blitter_may_be_busy = 0;}static void reset_engine(const struct fb_info_aty *info){ /* reset engine */ aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, info) & ~GUI_ENGINE_ENABLE, info); /* enable engine */ aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, info) | GUI_ENGINE_ENABLE, info); /* ensure engine is not locked up by clearing any FIFO or */ /* HOST errors */ aty_st_le32(BUS_CNTL, aty_ld_le32(BUS_CNTL, info) | BUS_HOST_ERR_ACK | BUS_FIFO_ERR_ACK, info);}static void reset_GTC_3D_engine(const struct fb_info_aty *info){ aty_st_le32(SCALE_3D_CNTL, 0xc0, info); mdelay(GTC_3D_RESET_DELAY); aty_st_le32(SETUP_CNTL, 0x00, info); mdelay(GTC_3D_RESET_DELAY); aty_st_le32(SCALE_3D_CNTL, 0x00, info); mdelay(GTC_3D_RESET_DELAY);}static void init_engine(const struct atyfb_par *par, struct fb_info_aty *info){ u32 pitch_value; /* determine modal information from global mode structure */ pitch_value = par->crtc.vxres; if (par->crtc.bpp == 24) { /* In 24 bpp, the engine is in 8 bpp - this requires that all */ /* horizontal coordinates and widths must be adjusted */ pitch_value = pitch_value * 3; } /* On GTC (RagePro), we need to reset the 3D engine before */ if (Gx == LB_CHIP_ID || Gx == LD_CHIP_ID || Gx == LI_CHIP_ID || Gx == LP_CHIP_ID || Gx == GB_CHIP_ID || Gx == GD_CHIP_ID || Gx == GI_CHIP_ID || Gx == GP_CHIP_ID || Gx == GQ_CHIP_ID || Gx == LM_CHIP_ID || Gx == LN_CHIP_ID) reset_GTC_3D_engine(info); /* Reset engine, enable, and clear any engine errors */ reset_engine(info); /* Ensure that vga page pointers are set to zero - the upper */ /* page pointers are set to 1 to handle overflows in the */ /* lower page */ aty_st_le32(MEM_VGA_WP_SEL, 0x00010000, info); aty_st_le32(MEM_VGA_RP_SEL, 0x00010000, info); /* ---- Setup standard engine context ---- */ /* All GUI registers here are FIFOed - therefore, wait for */ /* the appropriate number of empty FIFO entries */ wait_for_fifo(14, info); /* enable all registers to be loaded for context loads */ aty_st_le32(CONTEXT_MASK, 0xFFFFFFFF, info); /* set destination pitch to modal pitch, set offset to zero */ aty_st_le32(DST_OFF_PITCH, (pitch_value / 8) << 22, info); /* zero these registers (set them to a known state) */ aty_st_le32(DST_Y_X, 0, info); aty_st_le32(DST_HEIGHT, 0, info); aty_st_le32(DST_BRES_ERR, 0, info); aty_st_le32(DST_BRES_INC, 0, info); aty_st_le32(DST_BRES_DEC, 0, info); /* set destination drawing attributes */ aty_st_le32(DST_CNTL, DST_LAST_PEL | DST_Y_TOP_TO_BOTTOM | DST_X_LEFT_TO_RIGHT, info); /* set source pitch to modal pitch, set offset to zero */ aty_st_le32(SRC_OFF_PITCH, (pitch_value / 8) << 22, info); /* set these registers to a known state */ aty_st_le32(SRC_Y_X, 0, info); aty_st_le32(SRC_HEIGHT1_WIDTH1, 1, info); aty_st_le32(SRC_Y_X_START, 0, info); aty_st_le32(SRC_HEIGHT2_WIDTH2, 1, info); /* set source pixel retrieving attributes */ aty_st_le32(SRC_CNTL, SRC_LINE_X_LEFT_TO_RIGHT, info); /* set host attributes */ wait_for_fifo(13, info); aty_st_le32(HOST_CNTL, 0, info); /* set pattern attributes */ aty_st_le32(PAT_REG0, 0, info); aty_st_le32(PAT_REG1, 0, info); aty_st_le32(PAT_CNTL, 0, info); /* set scissors to modal size */ aty_st_le32(SC_LEFT, 0, info); aty_st_le32(SC_TOP, 0, info); aty_st_le32(SC_BOTTOM, par->crtc.vyres-1, info); aty_st_le32(SC_RIGHT, pitch_value-1, info); /* set background color to minimum value (usually BLACK) */ aty_st_le32(DP_BKGD_CLR, 0, info); /* set foreground color to maximum value (usually WHITE) */ aty_st_le32(DP_FRGD_CLR, 0xFFFFFFFF, info); /* set write mask to effect all pixel bits */ aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF, info); /* set foreground mix to overpaint and background mix to */ /* no-effect */ aty_st_le32(DP_MIX, FRGD_MIX_S | BKGD_MIX_D, info); /* set primary source pixel channel to foreground color */ /* register */ aty_st_le32(DP_SRC, FRGD_SRC_FRGD_CLR, info); /* set compare functionality to false (no-effect on */ /* destination) */ wait_for_fifo(3, info); aty_st_le32(CLR_CMP_CLR, 0, info); aty_st_le32(CLR_CMP_MASK, 0xFFFFFFFF, info); aty_st_le32(CLR_CMP_CNTL, 0, info); /* set pixel depth */ wait_for_fifo(2, info); aty_st_le32(DP_PIX_WIDTH, par->crtc.dp_pix_width, info); aty_st_le32(DP_CHAIN_MASK, par->crtc.dp_chain_mask, info); wait_for_fifo(5, info); aty_st_le32(SCALE_3D_CNTL, 0, info); aty_st_le32(Z_CNTL, 0, info); aty_st_le32(CRTC_INT_CNTL, aty_ld_le32(CRTC_INT_CNTL, info) & ~0x20, info); aty_st_le32(GUI_TRAJ_CNTL, 0x100023, info); /* insure engine is idle before leaving */ wait_for_idle(info);}static void aty_st_514(int offset, u8 val, const struct fb_info_aty *info){ aty_st_8(DAC_CNTL, 1, info); /* right addr byte */ aty_st_8(DAC_W_INDEX, offset & 0xff, info); /* left addr byte */ aty_st_8(DAC_DATA, (offset >> 8) & 0xff, info); aty_st_8(DAC_MASK, val, info); aty_st_8(DAC_CNTL, 0, info);}static void aty_st_pll(int offset, u8 val, const struct fb_info_aty *info){ /* write addr byte */ aty_st_8(CLOCK_CNTL + 1, (offset << 2) | PLL_WR_EN, info); /* write the register value */ aty_st_8(CLOCK_CNTL + 2, val, info); aty_st_8(CLOCK_CNTL + 1, (offset << 2) & ~PLL_WR_EN, info);}static u8 aty_ld_pll(int offset, const struct fb_info_aty *info){ u8 res; /* write addr byte */ aty_st_8(CLOCK_CNTL + 1, (offset << 2), info); /* read the register value */ res = aty_ld_8(CLOCK_CNTL + 2, info); return res;}#if defined(CONFIG_PPC) /* * Apple monitor sense */static int read_aty_sense(const struct fb_info_aty *info){ int sense, i; aty_st_le32(GP_IO, 0x31003100, info); /* drive outputs high */ __delay(200); aty_st_le32(GP_IO, 0, info); /* turn off outputs */ __delay(2000); i = aty_ld_le32(GP_IO, info); /* 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, info); /* drive A low */ __delay(2000); i = aty_ld_le32(GP_IO, info); sense |= ((i & 0x1000) >> 7) | ((i & 0x100) >> 4); aty_st_le32(GP_IO, 0x20002000, info); /* drive A high again */ __delay(200); aty_st_le32(GP_IO, 0x10000000, info); /* drive B low */ __delay(2000); i = aty_ld_le32(GP_IO, info); sense |= ((i & 0x2000) >> 10) | ((i & 0x100) >> 6); aty_st_le32(GP_IO, 0x10001000, info); /* drive B high again */ __delay(200); aty_st_le32(GP_IO, 0x01000000, info); /* drive C low */ __delay(2000); sense |= (aty_ld_le32(GP_IO, info) & 0x3000) >> 12; aty_st_le32(GP_IO, 0, info); /* turn off outputs */ return sense;}#endif /* defined(CONFIG_PPC) *//* ------------------------------------------------------------------------- */ /* * Hardware Cursor support. */static u8 cursor_pixel_map[2] = { 0, 15 };static u8 cursor_color_map[2] = { 0, 0xff };static u8 cursor_bits_lookup[16] ={ 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54, 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55};static u8 cursor_mask_lookup[16] ={ 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02, 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00};static voidaty_set_cursor_color(struct fb_info_aty *fb, u8 *pixel, u8 *red, u8 *green, u8 *blue){ struct aty_cursor *c = fb->cursor; int i; if (!c) return;#ifdef __sparc__ if (fb->mmaped && (!fb->fb_info.display_fg || fb->fb_info.display_fg->vc_num == fb->vtconsole)) return;#endif for (i = 0; i < 2; i++) { c->color[i] = (u32)red[i] << 24; c->color[i] |= (u32)green[i] << 16; c->color[i] |= (u32)blue[i] << 8; c->color[i] |= (u32)pixel[i]; } wait_for_fifo(2, fb); aty_st_le32(CUR_CLR0, c->color[0], fb); aty_st_le32(CUR_CLR1, c->color[1], fb);}static voidaty_set_cursor_shape(struct fb_info_aty *fb){ struct aty_cursor *c = fb->cursor; u8 *ram, m, b; int x, y; if (!c) return;#ifdef __sparc__ if (fb->mmaped && (!fb->fb_info.display_fg || fb->fb_info.display_fg->vc_num == fb->vtconsole)) return;#endif ram = c->ram; for (y = 0; y < c->size.y; y++) { for (x = 0; x < c->size.x >> 2; x++) { m = c->mask[x][y]; b = c->bits[x][y]; fb_writeb (cursor_mask_lookup[m >> 4] | cursor_bits_lookup[(b & m) >> 4], ram++); fb_writeb (cursor_mask_lookup[m & 0x0f] | cursor_bits_lookup[(b & m) & 0x0f], ram++); } for ( ; x < 8; x++) { fb_writeb (0xaa, ram++);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?