radeon_base.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,181 行 · 第 1/5 页

C
2,181
字号
		 * TODO:  set mirror accordingly for non-Mobility chipsets with 2 CRTC's		 *        and do something better using 2nd CRTC instead of just hackish		 *        routing to second output		 */		case FBIO_RADEON_SET_MIRROR:			if (!rinfo->is_mobility)				return -EINVAL;			rc = get_user(value, (__u32 __user *)arg);			if (rc)				return rc;			radeon_fifo_wait(2);			if (value & 0x01) {				tmp = INREG(LVDS_GEN_CNTL);				tmp |= (LVDS_ON | LVDS_BLON);			} else {				tmp = INREG(LVDS_GEN_CNTL);				tmp &= ~(LVDS_ON | LVDS_BLON);			}			OUTREG(LVDS_GEN_CNTL, tmp);			if (value & 0x02) {				tmp = INREG(CRTC_EXT_CNTL);				tmp |= CRTC_CRT_ON;				mirror = 1;			} else {				tmp = INREG(CRTC_EXT_CNTL);				tmp &= ~CRTC_CRT_ON;				mirror = 0;			}			OUTREG(CRTC_EXT_CNTL, tmp);			break;		case FBIO_RADEON_GET_MIRROR:			if (!rinfo->is_mobility)				return -EINVAL;			tmp = INREG(LVDS_GEN_CNTL);			if ((LVDS_ON | LVDS_BLON) & tmp)				value |= 0x01;			tmp = INREG(CRTC_EXT_CNTL);			if (CRTC_CRT_ON & tmp)				value |= 0x02;			return put_user(value, (__u32 __user *)arg);		default:			return -EINVAL;	}	return -EINVAL;}static int radeon_screen_blank (struct radeonfb_info *rinfo, int blank){        u32 val = INREG(CRTC_EXT_CNTL);	u32 val2 = 0;	if (rinfo->mon1_type == MT_LCD)		val2 = INREG(LVDS_GEN_CNTL) & ~LVDS_DISPLAY_DIS;	        /* reset it */        val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |                 CRTC_VSYNC_DIS);        switch (blank) {                case VESA_NO_BLANKING:                        break;                case VESA_VSYNC_SUSPEND:                        val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS);                        break;                case VESA_HSYNC_SUSPEND:                        val |= (CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS);                        break;                case VESA_POWERDOWN:                        val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS |                                 CRTC_HSYNC_DIS);			val2 |= (LVDS_DISPLAY_DIS);                        break;        }	radeon_fifo_wait(1);	switch (rinfo->mon1_type) {		case MT_LCD:			OUTREG(LVDS_GEN_CNTL, val2);			break;		case MT_CRT:		default:		        OUTREG(CRTC_EXT_CNTL, val);			break;	}	return 0;}int radeonfb_blank (int blank, struct fb_info *info){        struct radeonfb_info *rinfo = info->par;	if (rinfo->asleep)		return 0;		#ifdef CONFIG_PMAC_BACKLIGHT	if (rinfo->mon1_type == MT_LCD && _machine == _MACH_Pmac && blank)		set_backlight_enable(0);#endif                        	radeon_screen_blank(rinfo, blank);#ifdef CONFIG_PMAC_BACKLIGHT	if (rinfo->mon1_type == MT_LCD && _machine == _MACH_Pmac && !blank)		set_backlight_enable(1);#endif	return 0;}static int radeonfb_setcolreg (unsigned regno, unsigned red, unsigned green,                             unsigned blue, unsigned transp, struct fb_info *info){        struct radeonfb_info *rinfo = info->par;	u32 pindex;	unsigned int i;		if (regno > 255)		return 1;	red >>= 8;	green >>= 8;	blue >>= 8;	rinfo->palette[regno].red = red;	rinfo->palette[regno].green = green;	rinfo->palette[regno].blue = blue;        /* default */        pindex = regno;        if (!rinfo->asleep) {        	u32 dac_cntl2, vclk_cntl = 0;        			radeon_fifo_wait(9);		if (rinfo->is_mobility) {			vclk_cntl = INPLL(VCLK_ECP_CNTL);			OUTPLL(VCLK_ECP_CNTL, vclk_cntl & ~PIXCLK_DAC_ALWAYS_ONb);		}		/* Make sure we are on first palette */		if (rinfo->has_CRTC2) {			dac_cntl2 = INREG(DAC_CNTL2);			dac_cntl2 &= ~DAC2_PALETTE_ACCESS_CNTL;			OUTREG(DAC_CNTL2, dac_cntl2);		}		if (rinfo->bpp == 16) {			pindex = regno * 8;			if (rinfo->depth == 16 && regno > 63)				return 1;			if (rinfo->depth == 15 && regno > 31)				return 1;			/* For 565, the green component is mixed one order below */			if (rinfo->depth == 16) {		                OUTREG(PALETTE_INDEX, pindex>>1);	       	         	OUTREG(PALETTE_DATA, (rinfo->palette[regno>>1].red << 16) |	                        	(green << 8) | (rinfo->palette[regno>>1].blue));	                	green = rinfo->palette[regno<<1].green;	        	}		}		if (rinfo->depth != 16 || regno < 32) {			OUTREG(PALETTE_INDEX, pindex);			OUTREG(PALETTE_DATA, (red << 16) | (green << 8) | blue);		}		if (rinfo->is_mobility)			OUTPLL(VCLK_ECP_CNTL, vclk_cntl);	} 	if (regno < 16) {		u32 *pal = info->pseudo_palette;        	switch (rinfo->depth) {		case 15:			pal[regno] = (regno << 10) | (regno << 5) | regno;			break;		case 16:			pal[regno] = (regno << 11) | (regno << 5) | regno;			break;		case 24:			pal[regno] = (regno << 16) | (regno << 8) | regno;			break;		case 32:			i = (regno << 8) | regno;			pal[regno] = (i << 16) | i;			break;		}        }	return 0;}static void radeon_save_state (struct radeonfb_info *rinfo, struct radeon_regs *save){	/* CRTC regs */	save->crtc_gen_cntl = INREG(CRTC_GEN_CNTL);	save->crtc_ext_cntl = INREG(CRTC_EXT_CNTL);	save->crtc_more_cntl = INREG(CRTC_MORE_CNTL);	save->dac_cntl = INREG(DAC_CNTL);        save->crtc_h_total_disp = INREG(CRTC_H_TOTAL_DISP);        save->crtc_h_sync_strt_wid = INREG(CRTC_H_SYNC_STRT_WID);        save->crtc_v_total_disp = INREG(CRTC_V_TOTAL_DISP);        save->crtc_v_sync_strt_wid = INREG(CRTC_V_SYNC_STRT_WID);	save->crtc_pitch = INREG(CRTC_PITCH);	save->surface_cntl = INREG(SURFACE_CNTL);	/* FP regs */	save->fp_crtc_h_total_disp = INREG(FP_CRTC_H_TOTAL_DISP);	save->fp_crtc_v_total_disp = INREG(FP_CRTC_V_TOTAL_DISP);	save->fp_gen_cntl = INREG(FP_GEN_CNTL);	save->fp_h_sync_strt_wid = INREG(FP_H_SYNC_STRT_WID);	save->fp_horz_stretch = INREG(FP_HORZ_STRETCH);	save->fp_v_sync_strt_wid = INREG(FP_V_SYNC_STRT_WID);	save->fp_vert_stretch = INREG(FP_VERT_STRETCH);	save->lvds_gen_cntl = INREG(LVDS_GEN_CNTL);	save->lvds_pll_cntl = INREG(LVDS_PLL_CNTL);	save->tmds_crc = INREG(TMDS_CRC);	save->tmds_transmitter_cntl = INREG(TMDS_TRANSMITTER_CNTL);	save->vclk_ecp_cntl = INPLL(VCLK_ECP_CNTL);}static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *mode){	int i;	radeon_fifo_wait(20);	/* Workaround from XFree */	if (rinfo->is_mobility) {	        /* A temporal workaround for the occational blanking on certain laptop panels. 	           This appears to related to the PLL divider registers (fail to lock?).  		   It occurs even when all dividers are the same with their old settings.  	           In this case we really don't need to fiddle with PLL registers. 	           By doing this we can avoid the blanking problem with some panels.	        */		if ((mode->ppll_ref_div == (INPLL(PPLL_REF_DIV) & PPLL_REF_DIV_MASK)) &&		    (mode->ppll_div_3 == (INPLL(PPLL_DIV_3) &					  (PPLL_POST3_DIV_MASK | PPLL_FB3_DIV_MASK)))) {			/* We still have to force a switch to PPLL div 3 thanks to			 * an XFree86 driver bug which will switch it away in some cases			 * even when using UseFDev */			OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, ~PPLL_DIV_SEL_MASK);            		return;		}	}	/* Swich VCKL clock input to CPUCLK so it stays fed while PPLL updates*/	OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_CPUCLK, ~VCLK_SRC_SEL_MASK);	/* Reset PPLL & enable atomic update */	OUTPLLP(PPLL_CNTL,		PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN,		~(PPLL_RESET | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));	/* Switch to PPLL div 3 */	OUTREGP(CLOCK_CNTL_INDEX, PPLL_DIV_SEL_MASK, ~PPLL_DIV_SEL_MASK);	/* Set PPLL ref. div */	if (rinfo->family == CHIP_FAMILY_R300 ||	    rinfo->family == CHIP_FAMILY_RS300 ||	    rinfo->family == CHIP_FAMILY_R350 ||	    rinfo->family == CHIP_FAMILY_RV350) {		if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {			/* When restoring console mode, use saved PPLL_REF_DIV			 * setting.			 */			OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, 0);		} else {			/* R300 uses ref_div_acc field as real ref divider */			OUTPLLP(PPLL_REF_DIV,				(mode->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT), 				~R300_PPLL_REF_DIV_ACC_MASK);		}	} else		OUTPLLP(PPLL_REF_DIV, mode->ppll_ref_div, ~PPLL_REF_DIV_MASK);	/* Set PPLL divider 3 & post divider*/	OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_FB3_DIV_MASK);	OUTPLLP(PPLL_DIV_3, mode->ppll_div_3, ~PPLL_POST3_DIV_MASK);	/* Write update */	while (INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R)		;	OUTPLLP(PPLL_REF_DIV, PPLL_ATOMIC_UPDATE_W, ~PPLL_ATOMIC_UPDATE_W);	/* Wait read update complete */	/* FIXME: Certain revisions of R300 can't recover here.  Not sure of	   the cause yet, but this workaround will mask the problem for now.	   Other chips usually will pass at the very first test, so the	   workaround shouldn't have any effect on them. */	for (i = 0; (i < 10000 && INPLL(PPLL_REF_DIV) & PPLL_ATOMIC_UPDATE_R); i++)		;		OUTPLL(HTOTAL_CNTL, 0);	/* Clear reset & atomic update */	OUTPLLP(PPLL_CNTL, 0,		~(PPLL_RESET | PPLL_SLEEP | PPLL_ATOMIC_UPDATE_EN | PPLL_VGA_ATOMIC_UPDATE_EN));	/* We may want some locking ... oh well */       	msleep(5);	/* Switch back VCLK source to PPLL */	OUTPLLP(VCLK_ECP_CNTL, VCLK_SRC_SEL_PPLLCLK, ~VCLK_SRC_SEL_MASK);}/* * Timer function for delayed LVDS panel power up/down */static void radeon_lvds_timer_func(unsigned long data){	struct radeonfb_info *rinfo = (struct radeonfb_info *)data;	radeon_fifo_wait(3);	OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl);	if (rinfo->pending_pixclks_cntl) {		OUTPLL(PIXCLKS_CNTL, rinfo->pending_pixclks_cntl);		rinfo->pending_pixclks_cntl = 0;	}}/* * Apply a video mode. This will apply the whole register set, including * the PLL registers, to the card */static void radeon_write_mode (struct radeonfb_info *rinfo,                               struct radeon_regs *mode){	int i;	int primary_mon = PRIMARY_MONITOR(rinfo);	if (nomodeset)		return;	del_timer_sync(&rinfo->lvds_timer);	radeon_screen_blank(rinfo, VESA_POWERDOWN);	radeon_fifo_wait(31);	for (i=0; i<10; i++)		OUTREG(common_regs[i].reg, common_regs[i].val);	/* Apply surface registers */	for (i=0; i<8; i++) {		OUTREG(SURFACE0_LOWER_BOUND + 0x10*i, mode->surf_lower_bound[i]);		OUTREG(SURFACE0_UPPER_BOUND + 0x10*i, mode->surf_upper_bound[i]);		OUTREG(SURFACE0_INFO + 0x10*i, mode->surf_info[i]);	}	OUTREG(CRTC_GEN_CNTL, mode->crtc_gen_cntl);	OUTREGP(CRTC_EXT_CNTL, mode->crtc_ext_cntl,		~(CRTC_HSYNC_DIS | CRTC_VSYNC_DIS | CRTC_DISPLAY_DIS));	OUTREG(CRTC_MORE_CNTL, mode->crtc_more_cntl);	OUTREGP(DAC_CNTL, mode->dac_cntl, DAC_RANGE_CNTL | DAC_BLANKING);	OUTREG(CRTC_H_TOTAL_DISP, mode->crtc_h_total_disp);	OUTREG(CRTC_H_SYNC_STRT_WID, mode->crtc_h_sync_strt_wid);	OUTREG(CRTC_V_TOTAL_DISP, mode->crtc_v_total_disp);	OUTREG(CRTC_V_SYNC_STRT_WID, mode->crtc_v_sync_strt_wid);	OUTREG(CRTC_OFFSET, 0);	OUTREG(CRTC_OFFSET_CNTL, 0);	OUTREG(CRTC_PITCH, mode->crtc_pitch);	OUTREG(SURFACE_CNTL, mode->surface_cntl);	radeon_write_pll_regs(rinfo, mode);	if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {		radeon_fifo_wait(10);		OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);		OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);		OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);		OUTREG(FP_V_SYNC_STRT_WID, mode->fp_v_sync_strt_wid);		OUTREG(FP_HORZ_STRETCH, mode->fp_horz_stretch);		OUTREG(FP_VERT_STRETCH, mode->fp_vert_stretch);		OUTREG(FP_GEN_CNTL, mode->fp_gen_cntl);		OUTREG(TMDS_CRC, mode->tmds_crc);		OUTREG(TMDS_TRANSMITTER_CNTL, mode->tmds_transmitter_cntl);		if (primary_mon == MT_LCD) {			unsigned int tmp = INREG(LVDS_GEN_CNTL);			/* HACK: The backlight control code may have modified init_state.lvds_gen_cntl,			 * so we update ourselves			 */			mode->lvds_gen_cntl &= ~LVDS_STATE_MASK;			mode->lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_STATE_MASK);			if ((tmp & (LVDS_ON | LVDS_BLON)) ==			    (mode->lvds_gen_cntl & (LVDS_ON | LVDS_BLON))) {				OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl);			} else {				rinfo->pending_pixclks_cntl = INPLL(PIXCLKS_CNTL);				if (rinfo->is_mobility || rinfo->is_IGP)					OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);				if (!(tmp & (LVDS_ON | LVDS_BLON)))					OUTREG(LVDS_GEN_CNTL, mode->lvds_gen_cntl | LVDS_BLON);				rinfo->pending_lvds_gen_cntl = mode->lvds_gen_cntl;				mod_timer(&rinfo->lvds_timer,					  jiffies + MS_TO_HZ(rinfo->panel_info.pwr_delay));			}		}	}	RTRACE("lvds_gen_cntl: %08x\n", INREG(LVDS_GEN_CNTL));	radeon_screen_blank(rinfo, VESA_NO_BLANKING);	radeon_fifo_wait(2);	OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);		return;}/* * Calculate the PLL values for a given mode */static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs *regs,				 unsigned long freq){	const struct {		int divider;

⌨️ 快捷键说明

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