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 + -
显示快捷键?