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

📄 radeon_monitor.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
					radeon_probe_i2c_connector(rinfo, ddc_vga,								   &rinfo->mon1_EDID);			if (rinfo->mon1_type == MT_NONE)				rinfo->mon1_type =					radeon_probe_i2c_connector(rinfo, ddc_crt2,								   &rinfo->mon1_EDID);	#endif /* CONFIG_FB_RADEON_I2C */			if (rinfo->mon1_type == MT_NONE)				rinfo->mon1_type = MT_CRT;			goto bail;		}		/*		 * Check for cards with reversed DACs or TMDS controllers using BIOS		 */		if (rinfo->bios_seg &&		    (tmp = BIOS_IN16(rinfo->fp_bios_start + 0x50))) {			for (i = 1; i < 4; i++) {				unsigned int tmp0;				if (!BIOS_IN8(tmp + i*2) && i > 1)					break;				tmp0 = BIOS_IN16(tmp + i*2);				if ((!(tmp0 & 0x01)) && (((tmp0 >> 8) & 0x0f) == ddc_dvi)) {					rinfo->reversed_DAC = 1;					printk(KERN_INFO "radeonfb: Reversed DACs detected\n");				}				if ((((tmp0 >> 8) & 0x0f) == ddc_dvi) && ((tmp0 >> 4) & 0x01)) {					rinfo->reversed_TMDS = 1;					printk(KERN_INFO "radeonfb: Reversed TMDS detected\n");				}			}		}		/*		 * Probe primary head (DVI or laptop internal panel)		 */#ifdef CONFIG_PPC_OF		if (rinfo->mon1_type == MT_NONE)			rinfo->mon1_type = radeon_probe_OF_head(rinfo, 0,								&rinfo->mon1_EDID);#endif /* CONFIG_PPC_OF */#ifdef CONFIG_FB_RADEON_I2C		if (rinfo->mon1_type == MT_NONE)			rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_dvi,								      &rinfo->mon1_EDID);		if (rinfo->mon1_type == MT_NONE) {			rinfo->mon1_type = radeon_probe_i2c_connector(rinfo, ddc_crt2,								      &rinfo->mon1_EDID);			if (rinfo->mon1_type != MT_NONE)				ddc_crt2_used = 1;		}#endif /* CONFIG_FB_RADEON_I2C */		if (rinfo->mon1_type == MT_NONE && rinfo->is_mobility &&		    ((rinfo->bios_seg && (INREG(BIOS_4_SCRATCH) & 4))		     || (INREG(LVDS_GEN_CNTL) & LVDS_ON))) {			rinfo->mon1_type = MT_LCD;			printk("Non-DDC laptop panel detected\n");		}		if (rinfo->mon1_type == MT_NONE)			rinfo->mon1_type = radeon_crt_is_connected(rinfo, rinfo->reversed_DAC);		/*		 * Probe secondary head (mostly VGA, can be DVI)		 */#ifdef CONFIG_PPC_OF		if (rinfo->mon2_type == MT_NONE)			rinfo->mon2_type = radeon_probe_OF_head(rinfo, 1,								&rinfo->mon2_EDID);#endif /* CONFIG_PPC_OF */#ifdef CONFIG_FB_RADEON_I2C		if (rinfo->mon2_type == MT_NONE)			rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_vga,								      &rinfo->mon2_EDID);		if (rinfo->mon2_type == MT_NONE && !ddc_crt2_used)			rinfo->mon2_type = radeon_probe_i2c_connector(rinfo, ddc_crt2,								      &rinfo->mon2_EDID);#endif /* CONFIG_FB_RADEON_I2C */		if (rinfo->mon2_type == MT_NONE)			rinfo->mon2_type = radeon_crt_is_connected(rinfo, !rinfo->reversed_DAC);		/*		 * If we only detected port 2, we swap them, if none detected,		 * assume CRT (maybe fallback to old BIOS_SCRATCH stuff ? or look		 * at FP registers ?)		 */		if (rinfo->mon1_type == MT_NONE) {			if (rinfo->mon2_type != MT_NONE) {				rinfo->mon1_type = rinfo->mon2_type;				rinfo->mon1_EDID = rinfo->mon2_EDID;			} else				rinfo->mon1_type = MT_CRT;			rinfo->mon2_type = MT_NONE;			rinfo->mon2_EDID = NULL;		}		/*		 * Deal with reversed TMDS		 */		if (rinfo->reversed_TMDS) {			/* Always keep internal TMDS as primary head */			if (rinfo->mon1_type == MT_DFP || rinfo->mon2_type == MT_DFP) {				int tmp_type = rinfo->mon1_type;				u8 *tmp_EDID = rinfo->mon1_EDID;				rinfo->mon1_type = rinfo->mon2_type;				rinfo->mon1_EDID = rinfo->mon2_EDID;				rinfo->mon2_type = tmp_type;				rinfo->mon2_EDID = tmp_EDID;				if (rinfo->mon1_type == MT_CRT || rinfo->mon2_type == MT_CRT)					rinfo->reversed_DAC ^= 1;			}		}	}	if (ignore_edid) {		kfree(rinfo->mon1_EDID);		rinfo->mon1_EDID = NULL;		kfree(rinfo->mon2_EDID);		rinfo->mon2_EDID = NULL;	} bail:	printk(KERN_INFO "radeonfb: Monitor 1 type %s found\n",	       radeon_get_mon_name(rinfo->mon1_type));	if (rinfo->mon1_EDID)		printk(KERN_INFO "radeonfb: EDID probed\n");	if (!rinfo->has_CRTC2)		return;	printk(KERN_INFO "radeonfb: Monitor 2 type %s found\n",	       radeon_get_mon_name(rinfo->mon2_type));	if (rinfo->mon2_EDID)		printk(KERN_INFO "radeonfb: EDID probed\n");}/* * This functions applyes any arch/model/machine specific fixups * to the panel info. It may eventually alter EDID block as * well or whatever is specific to a given model and not probed * properly by the default code */static void radeon_fixup_panel_info(struct radeonfb_info *rinfo){#ifdef CONFIG_PPC_OF	/*	 * LCD Flat panels should use fixed dividers, we enfore that on	 * PPC only for now...	 */	if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type == MT_LCD	    && rinfo->is_mobility) {		int ppll_div_sel;		u32 ppll_divn;		ppll_div_sel = INREG8(CLOCK_CNTL_INDEX + 1) & 0x3;		radeon_pll_errata_after_index(rinfo);		ppll_divn = INPLL(PPLL_DIV_0 + ppll_div_sel);		rinfo->panel_info.ref_divider = rinfo->pll.ref_div;		rinfo->panel_info.fbk_divider = ppll_divn & 0x7ff;		rinfo->panel_info.post_divider = (ppll_divn >> 16) & 0x7;		rinfo->panel_info.use_bios_dividers = 1;		printk(KERN_DEBUG "radeonfb: Using Firmware dividers 0x%08x "		       "from PPLL %d\n",		       rinfo->panel_info.fbk_divider |		       (rinfo->panel_info.post_divider << 16),		       ppll_div_sel);	}#endif /* CONFIG_PPC_OF */}/* * Fill up panel infos from a mode definition, either returned by the EDID * or from the default mode when we can't do any better */static void radeon_var_to_panel_info(struct radeonfb_info *rinfo, struct fb_var_screeninfo *var){	rinfo->panel_info.xres = var->xres;	rinfo->panel_info.yres = var->yres;	rinfo->panel_info.clock = 100000000 / var->pixclock;	rinfo->panel_info.hOver_plus = var->right_margin;	rinfo->panel_info.hSync_width = var->hsync_len;       	rinfo->panel_info.hblank = var->left_margin +		(var->right_margin + var->hsync_len);	rinfo->panel_info.vOver_plus = var->lower_margin;	rinfo->panel_info.vSync_width = var->vsync_len;       	rinfo->panel_info.vblank = var->upper_margin +		(var->lower_margin + var->vsync_len);	rinfo->panel_info.hAct_high =		(var->sync & FB_SYNC_HOR_HIGH_ACT) != 0;	rinfo->panel_info.vAct_high =		(var->sync & FB_SYNC_VERT_HIGH_ACT) != 0;	rinfo->panel_info.valid = 1;	/* We use a default of 200ms for the panel power delay, 	 * I need to have a real schedule() instead of mdelay's in the panel code.	 * we might be possible to figure out a better power delay either from	 * MacOS OF tree or from the EDID block (proprietary extensions ?)	 */	rinfo->panel_info.pwr_delay = 200;}static void radeon_videomode_to_var(struct fb_var_screeninfo *var,				    const struct fb_videomode *mode){	var->xres = mode->xres;	var->yres = mode->yres;	var->xres_virtual = mode->xres;	var->yres_virtual = mode->yres;	var->xoffset = 0;	var->yoffset = 0;	var->pixclock = mode->pixclock;	var->left_margin = mode->left_margin;	var->right_margin = mode->right_margin;	var->upper_margin = mode->upper_margin;	var->lower_margin = mode->lower_margin;	var->hsync_len = mode->hsync_len;	var->vsync_len = mode->vsync_len;	var->sync = mode->sync;	var->vmode = mode->vmode;}/* * Build the modedb for head 1 (head 2 will come later), check panel infos * from either BIOS or EDID, and pick up the default mode */void __devinit radeon_check_modes(struct radeonfb_info *rinfo, const char *mode_option){	struct fb_info * info = rinfo->info;	int has_default_mode = 0;	/*	 * Fill default var first	 */	info->var = radeonfb_default_var;	INIT_LIST_HEAD(&info->modelist);	/*	 * First check out what BIOS has to say	 */	if (rinfo->mon1_type == MT_LCD)		radeon_get_panel_info_BIOS(rinfo);	/*	 * Parse EDID detailed timings and deduce panel infos if any. Right now	 * we only deal with first entry returned by parse_EDID, we may do better	 * some day...	 */	if (!rinfo->panel_info.use_bios_dividers && rinfo->mon1_type != MT_CRT	    && rinfo->mon1_EDID) {		struct fb_var_screeninfo var;		RTRACE("Parsing EDID data for panel info\n");		if (fb_parse_edid(rinfo->mon1_EDID, &var) == 0) {			if (var.xres >= rinfo->panel_info.xres &&			    var.yres >= rinfo->panel_info.yres)				radeon_var_to_panel_info(rinfo, &var);		}	}	/*	 * Do any additional platform/arch fixups to the panel infos	 */	radeon_fixup_panel_info(rinfo);	/*	 * If we have some valid panel infos, we setup the default mode based on	 * those	 */	if (rinfo->mon1_type != MT_CRT && rinfo->panel_info.valid) {		struct fb_var_screeninfo *var = &info->var;		RTRACE("Setting up default mode based on panel info\n");		var->xres = rinfo->panel_info.xres;		var->yres = rinfo->panel_info.yres;		var->xres_virtual = rinfo->panel_info.xres;		var->yres_virtual = rinfo->panel_info.yres;		var->xoffset = var->yoffset = 0;		var->bits_per_pixel = 8;		var->pixclock = 100000000 / rinfo->panel_info.clock;		var->left_margin = (rinfo->panel_info.hblank - rinfo->panel_info.hOver_plus				    - rinfo->panel_info.hSync_width);		var->right_margin = rinfo->panel_info.hOver_plus;		var->upper_margin = (rinfo->panel_info.vblank - rinfo->panel_info.vOver_plus				     - rinfo->panel_info.vSync_width);		var->lower_margin = rinfo->panel_info.vOver_plus;		var->hsync_len = rinfo->panel_info.hSync_width;		var->vsync_len = rinfo->panel_info.vSync_width;		var->sync = 0;		if (rinfo->panel_info.hAct_high)			var->sync |= FB_SYNC_HOR_HIGH_ACT;		if (rinfo->panel_info.vAct_high)			var->sync |= FB_SYNC_VERT_HIGH_ACT;		var->vmode = 0;		has_default_mode = 1;	}	/*	 * Now build modedb from EDID	 */	if (rinfo->mon1_EDID) {		fb_edid_to_monspecs(rinfo->mon1_EDID, &info->monspecs);		fb_videomode_to_modelist(info->monspecs.modedb,					 info->monspecs.modedb_len,					 &info->modelist);		rinfo->mon1_modedb = info->monspecs.modedb;		rinfo->mon1_dbsize = info->monspecs.modedb_len;	}		/*	 * Finally, if we don't have panel infos we need to figure some (or	 * we try to read it from card), we try to pick a default mode	 * and create some panel infos. Whatever...	 */	if (rinfo->mon1_type != MT_CRT && !rinfo->panel_info.valid) {		struct fb_videomode	*modedb;		int			dbsize;		char			modename[32];		RTRACE("Guessing panel info...\n");		if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) {			u32 tmp = INREG(FP_HORZ_STRETCH) & HORZ_PANEL_SIZE;			rinfo->panel_info.xres = ((tmp >> HORZ_PANEL_SHIFT) + 1) * 8;			tmp = INREG(FP_VERT_STRETCH) & VERT_PANEL_SIZE;			rinfo->panel_info.yres = (tmp >> VERT_PANEL_SHIFT) + 1;		}		if (rinfo->panel_info.xres == 0 || rinfo->panel_info.yres == 0) {			printk(KERN_WARNING "radeonfb: Can't find panel size, going back to CRT\n");			rinfo->mon1_type = MT_CRT;			goto pickup_default;		}		printk(KERN_WARNING "radeonfb: Assuming panel size %dx%d\n",		       rinfo->panel_info.xres, rinfo->panel_info.yres);		modedb = rinfo->mon1_modedb;		dbsize = rinfo->mon1_dbsize;		snprintf(modename, 31, "%dx%d", rinfo->panel_info.xres, rinfo->panel_info.yres);		if (fb_find_mode(&info->var, info, modename,				 modedb, dbsize, NULL, 8) == 0) {			printk(KERN_WARNING "radeonfb: Can't find mode for panel size, going back to CRT\n");			rinfo->mon1_type = MT_CRT;			goto pickup_default;		}		has_default_mode = 1;		radeon_var_to_panel_info(rinfo, &info->var);	} pickup_default:	/*	 * Apply passed-in mode option if any	 */	if (mode_option) {		if (fb_find_mode(&info->var, info, mode_option,				 info->monspecs.modedb,				 info->monspecs.modedb_len, NULL, 8) != 0)			has_default_mode = 1; 	}	/*	 * Still no mode, let's pick up a default from the db	 */	if (!has_default_mode && info->monspecs.modedb != NULL) {		struct fb_monspecs *specs = &info->monspecs;		struct fb_videomode *modedb = NULL;		/* get preferred timing */		if (specs->misc & FB_MISC_1ST_DETAIL) {			int i;			for (i = 0; i < specs->modedb_len; i++) {				if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {					modedb = &specs->modedb[i];					break;				}			}		} else {			/* otherwise, get first mode in database */			modedb = &specs->modedb[0];		}		if (modedb != NULL) {			info->var.bits_per_pixel = 8;			radeon_videomode_to_var(&info->var, modedb);			has_default_mode = 1;		}	}	if (1) {		struct fb_videomode mode;		/* Make sure that whatever mode got selected is actually in the		 * modelist or the kernel may die		 */		fb_var_to_videomode(&mode, &info->var);		fb_add_videomode(&mode, &info->modelist);	}}/* * The code below is used to pick up a mode in check_var and * set_var. It should be made generic *//* * This is used when looking for modes. We assign a "distance" value * to a mode in the modedb depending how "close" it is from what we * are looking for. * Currently, we don't compare that much, we could do better but * the current fbcon doesn't quite mind ;) */static int radeon_compare_modes(const struct fb_var_screeninfo *var,				const struct fb_videomode *mode){	int distance = 0;	distance = mode->yres - var->yres;	distance += (mode->xres - var->xres)/2;	return distance;}/* * This function is called by check_var, it gets the passed in mode parameter, and * outputs a valid mode matching the passed-in one as closely as possible. * We need something better ultimately. Things like fbcon basically pass us out * current mode with xres/yres hacked, while things like XFree will actually * produce a full timing that we should respect as much as possible. * * This is why I added the FB_ACTIVATE_FIND that is used by fbcon. Without this, * we do a simple spec match, that's all. With it, we actually look for a mode in * either our monitor modedb or the vesa one if none * */int  radeon_match_mode(struct radeonfb_info *rinfo,		       struct fb_var_screeninfo *dest,		       const struct fb_var_screeninfo *src){	const struct fb_videomode	*db = vesa_modes;	int				i, dbsize = 34;	int				has_rmx, native_db = 0;	int				distance = INT_MAX;	const struct fb_videomode	*candidate = NULL;	/* Start with a copy of the requested mode */	memcpy(dest, src, sizeof(struct fb_var_screeninfo));	/* Check if we have a modedb built from EDID */	if (rinfo->mon1_modedb) {		db = rinfo->mon1_modedb;		dbsize = rinfo->mon1_dbsize;		native_db = 1;	}	/* Check if we have a scaler allowing any fancy mode */	has_rmx = rinfo->mon1_type == MT_LCD || rinfo->mon1_type == MT_DFP;	/* If we have a scaler and are passed FB_ACTIVATE_TEST or	 * FB_ACTIVATE_NOW, just do basic checking and return if the	 * mode match	 */	if ((src->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST ||	    (src->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {		/* We don't have an RMX, validate timings. If we don't have	 	 * monspecs, we should be paranoid and not let use go above		 * 640x480-60, but I assume userland knows what it's doing here		 * (though I may be proven wrong...)		 */		if (has_rmx == 0 && rinfo->mon1_modedb)			if (fb_validate_mode((struct fb_var_screeninfo *)src, rinfo->info))				return -EINVAL;		return 0;	}	/* Now look for a mode in the database */	while (db) {		for (i = 0; i < dbsize; i++) {			int d;			if (db[i].yres < src->yres)				continue;				if (db[i].xres < src->xres)				continue;			d = radeon_compare_modes(src, &db[i]);			/* If the new mode is at least as good as the previous one,			 * then it's our new candidate			 */			if (d < distance) {				candidate = &db[i];				distance = d;			}		}		db = NULL;		/* If we have a scaler, we allow any mode from the database */		if (native_db && has_rmx) {			db = vesa_modes;			dbsize = 34;			native_db = 0;		}	}	/* If we have found a match, return it */	if (candidate != NULL) {		radeon_videomode_to_var(dest, candidate);		return 0;	}	/* If we haven't and don't have a scaler, fail */	if (!has_rmx)		return -EINVAL;	return 0;}

⌨️ 快捷键说明

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