⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aty128fb.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
     * Functions to read from/write to the mmio registers     *	- endian conversions may possibly be avoided by     *    using the other register aperture. TODO.     */static inline u32 _aty_ld_le32(volatile unsigned int regindex, 			       const struct aty128fb_par *par){	return readl (par->regbase + regindex);}static inline void _aty_st_le32(volatile unsigned int regindex, u32 val, 				const struct aty128fb_par *par){	writel (val, par->regbase + regindex);}static inline u8 _aty_ld_8(unsigned int regindex,			   const struct aty128fb_par *par){	return readb (par->regbase + regindex);}static inline void _aty_st_8(unsigned int regindex, u8 val,			     const struct aty128fb_par *par){	writeb (val, par->regbase + regindex);}#define aty_ld_le32(regindex)		_aty_ld_le32(regindex, par)#define aty_st_le32(regindex, val)	_aty_st_le32(regindex, val, par)#define aty_ld_8(regindex)		_aty_ld_8(regindex, par)#define aty_st_8(regindex, val)		_aty_st_8(regindex, val, par)    /*     * Functions to read from/write to the pll registers     */#define aty_ld_pll(pll_index)		_aty_ld_pll(pll_index, par)#define aty_st_pll(pll_index, val)	_aty_st_pll(pll_index, val, par)static u32 _aty_ld_pll(unsigned int pll_index,		       const struct aty128fb_par *par){       	aty_st_8(CLOCK_CNTL_INDEX, pll_index & 0x3F);	return aty_ld_le32(CLOCK_CNTL_DATA);}    static void _aty_st_pll(unsigned int pll_index, u32 val,			const struct aty128fb_par *par){	aty_st_8(CLOCK_CNTL_INDEX, (pll_index & 0x3F) | PLL_WR_EN);	aty_st_le32(CLOCK_CNTL_DATA, val);}/* return true when the PLL has completed an atomic update */static int aty_pll_readupdate(const struct aty128fb_par *par){	return !(aty_ld_pll(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R);}static void aty_pll_wait_readupdate(const struct aty128fb_par *par){	unsigned long timeout = jiffies + HZ/100; // should be more than enough	int reset = 1;	while (time_before(jiffies, timeout))		if (aty_pll_readupdate(par)) {			reset = 0;			break;		}	if (reset)	/* reset engine?? */		printk(KERN_DEBUG "aty128fb: PLL write timeout!\n");}/* tell PLL to update */static void aty_pll_writeupdate(const struct aty128fb_par *par){	aty_pll_wait_readupdate(par);	aty_st_pll(PPLL_REF_DIV,		   aty_ld_pll(PPLL_REF_DIV) | PPLL_ATOMIC_UPDATE_W);}/* write to the scratch register to test r/w functionality */static int __init register_test(const struct aty128fb_par *par){	u32 val;	int flag = 0;	val = aty_ld_le32(BIOS_0_SCRATCH);	aty_st_le32(BIOS_0_SCRATCH, 0x55555555);	if (aty_ld_le32(BIOS_0_SCRATCH) == 0x55555555) {		aty_st_le32(BIOS_0_SCRATCH, 0xAAAAAAAA);		if (aty_ld_le32(BIOS_0_SCRATCH) == 0xAAAAAAAA)			flag = 1; 	}	aty_st_le32(BIOS_0_SCRATCH, val);	// restore value	return flag;}/* * Accelerator engine functions */static void do_wait_for_fifo(u16 entries, struct aty128fb_par *par){	int i;	for (;;) {		for (i = 0; i < 2000000; i++) {			par->fifo_slots = aty_ld_le32(GUI_STAT) & 0x0fff;			if (par->fifo_slots >= entries)				return;		}		aty128_reset_engine(par);	}}static void wait_for_idle(struct aty128fb_par *par){	int i;	do_wait_for_fifo(64, par);	for (;;) {		for (i = 0; i < 2000000; i++) {			if (!(aty_ld_le32(GUI_STAT) & (1 << 31))) {				aty128_flush_pixel_cache(par);				par->blitter_may_be_busy = 0;				return;			}		}		aty128_reset_engine(par);	}}static void wait_for_fifo(u16 entries, struct aty128fb_par *par){	if (par->fifo_slots < entries)		do_wait_for_fifo(64, par);	par->fifo_slots -= entries;}static void aty128_flush_pixel_cache(const struct aty128fb_par *par){	int i;	u32 tmp;	tmp = aty_ld_le32(PC_NGUI_CTLSTAT);	tmp &= ~(0x00ff);	tmp |= 0x00ff;	aty_st_le32(PC_NGUI_CTLSTAT, tmp);	for (i = 0; i < 2000000; i++)		if (!(aty_ld_le32(PC_NGUI_CTLSTAT) & PC_BUSY))			break;}static void aty128_reset_engine(const struct aty128fb_par *par){	u32 gen_reset_cntl, clock_cntl_index, mclk_cntl;	aty128_flush_pixel_cache(par);	clock_cntl_index = aty_ld_le32(CLOCK_CNTL_INDEX);	mclk_cntl = aty_ld_pll(MCLK_CNTL);	aty_st_pll(MCLK_CNTL, mclk_cntl | 0x00030000);	gen_reset_cntl = aty_ld_le32(GEN_RESET_CNTL);	aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl | SOFT_RESET_GUI);	aty_ld_le32(GEN_RESET_CNTL);	aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl & ~(SOFT_RESET_GUI));	aty_ld_le32(GEN_RESET_CNTL);	aty_st_pll(MCLK_CNTL, mclk_cntl);	aty_st_le32(CLOCK_CNTL_INDEX, clock_cntl_index);	aty_st_le32(GEN_RESET_CNTL, gen_reset_cntl);	/* use old pio mode */	aty_st_le32(PM4_BUFFER_CNTL, PM4_BUFFER_CNTL_NONPM4);	DBG("engine reset");}static void aty128_init_engine(struct aty128fb_par *par){	u32 pitch_value;	wait_for_idle(par);	/* 3D scaler not spoken here */	wait_for_fifo(1, par);	aty_st_le32(SCALE_3D_CNTL, 0x00000000);	aty128_reset_engine(par);	pitch_value = par->crtc.pitch;	if (par->crtc.bpp == 24) {		pitch_value = pitch_value * 3;	}	wait_for_fifo(4, par);	/* setup engine offset registers */	aty_st_le32(DEFAULT_OFFSET, 0x00000000);	/* setup engine pitch registers */	aty_st_le32(DEFAULT_PITCH, pitch_value);	/* set the default scissor register to max dimensions */	aty_st_le32(DEFAULT_SC_BOTTOM_RIGHT, (0x1FFF << 16) | 0x1FFF);	/* set the drawing controls registers */	aty_st_le32(DP_GUI_MASTER_CNTL,		    GMC_SRC_PITCH_OFFSET_DEFAULT		|		    GMC_DST_PITCH_OFFSET_DEFAULT		|		    GMC_SRC_CLIP_DEFAULT			|		    GMC_DST_CLIP_DEFAULT			|		    GMC_BRUSH_SOLIDCOLOR			|		    (depth_to_dst(par->crtc.depth) << 8)	|		    GMC_SRC_DSTCOLOR			|		    GMC_BYTE_ORDER_MSB_TO_LSB		|		    GMC_DP_CONVERSION_TEMP_6500		|		    ROP3_PATCOPY				|		    GMC_DP_SRC_RECT				|		    GMC_3D_FCN_EN_CLR			|		    GMC_DST_CLR_CMP_FCN_CLEAR		|		    GMC_AUX_CLIP_CLEAR			|		    GMC_WRITE_MASK_SET);	wait_for_fifo(8, par);	/* clear the line drawing registers */	aty_st_le32(DST_BRES_ERR, 0);	aty_st_le32(DST_BRES_INC, 0);	aty_st_le32(DST_BRES_DEC, 0);	/* set brush color registers */	aty_st_le32(DP_BRUSH_FRGD_CLR, 0xFFFFFFFF); /* white */	aty_st_le32(DP_BRUSH_BKGD_CLR, 0x00000000); /* black */	/* set source color registers */	aty_st_le32(DP_SRC_FRGD_CLR, 0xFFFFFFFF);   /* white */	aty_st_le32(DP_SRC_BKGD_CLR, 0x00000000);   /* black */	/* default write mask */	aty_st_le32(DP_WRITE_MASK, 0xFFFFFFFF);	/* Wait for all the writes to be completed before returning */	wait_for_idle(par);}/* convert depth values to their register representation */static u32 depth_to_dst(u32 depth){	if (depth <= 8)		return DST_8BPP;	else if (depth <= 15)		return DST_15BPP;	else if (depth == 16)		return DST_16BPP;	else if (depth <= 24)		return DST_24BPP;	else if (depth <= 32)		return DST_32BPP;	return -EINVAL;}/* * PLL informations retreival */#ifndef __sparc__static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev){	u16 dptr;	u8 rom_type;	void __iomem *bios;	size_t rom_size;    	/* Fix from ATI for problem with Rage128 hardware not leaving ROM enabled */    	unsigned int temp;	temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);	temp &= 0x00ffffffu;	temp |= 0x04 << 24;	aty_st_le32(RAGE128_MPP_TB_CONFIG, temp);	temp = aty_ld_le32(RAGE128_MPP_TB_CONFIG);	bios = pci_map_rom(dev, &rom_size);	if (!bios) {		printk(KERN_ERR "aty128fb: ROM failed to map\n");		return NULL;	}	/* Very simple test to make sure it appeared */	if (BIOS_IN16(0) != 0xaa55) {		printk(KERN_DEBUG "aty128fb: Invalid ROM signature %x should "			" be 0xaa55\n", BIOS_IN16(0));		goto failed;	}	/* Look for the PCI data to check the ROM type */	dptr = BIOS_IN16(0x18);	/* Check the PCI data signature. If it's wrong, we still assume a normal x86 ROM	 * for now, until I've verified this works everywhere. The goal here is more	 * to phase out Open Firmware images.	 *	 * Currently, we only look at the first PCI data, we could iteratre and deal with	 * them all, and we should use fb_bios_start relative to start of image and not	 * relative start of ROM, but so far, I never found a dual-image ATI card	 *	 * typedef struct {	 * 	u32	signature;	+ 0x00	 * 	u16	vendor;		+ 0x04	 * 	u16	device;		+ 0x06	 * 	u16	reserved_1;	+ 0x08	 * 	u16	dlen;		+ 0x0a	 * 	u8	drevision;	+ 0x0c	 * 	u8	class_hi;	+ 0x0d	 * 	u16	class_lo;	+ 0x0e	 * 	u16	ilen;		+ 0x10	 * 	u16	irevision;	+ 0x12	 * 	u8	type;		+ 0x14	 * 	u8	indicator;	+ 0x15	 * 	u16	reserved_2;	+ 0x16	 * } pci_data_t;	 */	if (BIOS_IN32(dptr) !=  (('R' << 24) | ('I' << 16) | ('C' << 8) | 'P')) {		printk(KERN_WARNING "aty128fb: PCI DATA signature in ROM incorrect: %08x\n",		       BIOS_IN32(dptr));		goto anyway;	}	rom_type = BIOS_IN8(dptr + 0x14);	switch(rom_type) {	case 0:		printk(KERN_INFO "aty128fb: Found Intel x86 BIOS ROM Image\n");		break;	case 1:		printk(KERN_INFO "aty128fb: Found Open Firmware ROM Image\n");		goto failed;	case 2:		printk(KERN_INFO "aty128fb: Found HP PA-RISC ROM Image\n");		goto failed;	default:		printk(KERN_INFO "aty128fb: Found unknown type %d ROM Image\n", rom_type);		goto failed;	} anyway:	return bios; failed:	pci_unmap_rom(dev, bios);	return NULL;}static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios){	unsigned int bios_hdr;	unsigned int bios_pll;	bios_hdr = BIOS_IN16(0x48);	bios_pll = BIOS_IN16(bios_hdr + 0x30);		par->constants.ppll_max = BIOS_IN32(bios_pll + 0x16);	par->constants.ppll_min = BIOS_IN32(bios_pll + 0x12);	par->constants.xclk = BIOS_IN16(bios_pll + 0x08);	par->constants.ref_divider = BIOS_IN16(bios_pll + 0x10);	par->constants.ref_clk = BIOS_IN16(bios_pll + 0x0e);	DBG("ppll_max %d ppll_min %d xclk %d ref_divider %d ref clock %d\n",			par->constants.ppll_max, par->constants.ppll_min,			par->constants.xclk, par->constants.ref_divider,			par->constants.ref_clk);}           #ifdef CONFIG_X86static void __iomem *  __devinit aty128_find_mem_vbios(struct aty128fb_par *par){	/* I simplified this code as we used to miss the signatures in	 * a lot of case. It's now closer to XFree, we just don't check	 * for signatures at all... Something better will have to be done	 * if we end up having conflicts	 */        u32  segstart;        unsigned char __iomem *rom_base = NULL;                                                        for (segstart=0x000c0000; segstart<0x000f0000; segstart+=0x00001000) {                rom_base = ioremap(segstart, 0x10000);		if (rom_base == NULL)			return NULL;		if (readb(rom_base) == 0x55 && readb(rom_base + 1) == 0xaa)	                break;                iounmap(rom_base);		rom_base = NULL;        }	return rom_base;}#endif#endif /* ndef(__sparc__) *//* fill in known card constants if pll_block is not available */static void __init aty128_timings(struct aty128fb_par *par){#ifdef CONFIG_PPC_OF	/* instead of a table lookup, assume OF has properly	 * setup the PLL registers and use their values	 * to set the XCLK values and reference divider values */	u32 x_mpll_ref_fb_div;	u32 xclk_cntl;	u32 Nx, M;	unsigned PostDivSet[] = { 0, 1, 2, 4, 8, 3, 6, 12 };#endif	if (!par->constants.ref_clk)		par->constants.ref_clk = 2950;#ifdef CONFIG_PPC_OF	x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV);	xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7;	Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8;	M  = x_mpll_ref_fb_div & 0x0000ff;	par->constants.xclk = round_div((2 * Nx * par->constants.ref_clk),					(M * PostDivSet[xclk_cntl]));	par->constants.ref_divider =		aty_ld_pll(PPLL_REF_DIV) & PPLL_REF_DIV_MASK;#endif	if (!par->constants.ref_divider) {		par->constants.ref_divider = 0x3b;		aty_st_pll(X_MPLL_REF_FB_DIV, 0x004c4c1e);		aty_pll_writeupdate(par);	}	aty_st_pll(PPLL_REF_DIV, par->constants.ref_divider);	aty_pll_writeupdate(par);	/* from documentation */	if (!par->constants.ppll_min)		par->constants.ppll_min = 12500;	if (!par->constants.ppll_max)		par->constants.ppll_max = 25000;    /* 23000 on some cards? */	if (!par->constants.xclk)		par->constants.xclk = 0x1d4d;	     /* same as mclk */	par->constants.fifo_width = 128;	par->constants.fifo_depth = 32;	switch (aty_ld_le32(MEM_CNTL) & 0x3) {	case 0:		par->mem = &sdr_128;		break;	case 1:		par->mem = &sdr_sgram;		break;	case 2:		par->mem = &ddr_sgram;		break;	default:		par->mem = &sdr_sgram;	}}/* * CRTC programming *//* Program the CRTC registers */static void aty128_set_crtc(const struct aty128_crtc *crtc,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -