diff options
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_atombios.c')
| -rw-r--r-- | drivers/gpu/drm/radeon/radeon_atombios.c | 450 | 
1 files changed, 246 insertions, 204 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 93783b15c81..9916d825401 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -69,52 +69,54 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev  	struct radeon_i2c_bus_rec i2c;  	int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);  	struct _ATOM_GPIO_I2C_INFO *i2c_info; -	uint16_t data_offset; -	int i; +	uint16_t data_offset, size; +	int i, num_indices;  	memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));  	i2c.valid = false; -	atom_parse_data_header(ctx, index, NULL, NULL, NULL, &data_offset); +	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { +		i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); -	i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); +		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / +			sizeof(ATOM_GPIO_I2C_ASSIGMENT); +		for (i = 0; i < num_indices; i++) { +			gpio = &i2c_info->asGPIO_Info[i]; -	for (i = 0; i < ATOM_MAX_SUPPORTED_DEVICE; i++) { -		gpio = &i2c_info->asGPIO_Info[i]; +			if (gpio->sucI2cId.ucAccess == id) { +				i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; +				i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; +				i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; +				i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4; +				i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4; +				i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4; +				i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4; +				i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4; +				i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift); +				i2c.mask_data_mask = (1 << gpio->ucDataMaskShift); +				i2c.en_clk_mask = (1 << gpio->ucClkEnShift); +				i2c.en_data_mask = (1 << gpio->ucDataEnShift); +				i2c.y_clk_mask = (1 << gpio->ucClkY_Shift); +				i2c.y_data_mask = (1 << gpio->ucDataY_Shift); +				i2c.a_clk_mask = (1 << gpio->ucClkA_Shift); +				i2c.a_data_mask = (1 << gpio->ucDataA_Shift); -		if (gpio->sucI2cId.ucAccess == id) { -			i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; -			i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; -			i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; -			i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4; -			i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4; -			i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4; -			i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4; -			i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4; -			i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift); -			i2c.mask_data_mask = (1 << gpio->ucDataMaskShift); -			i2c.en_clk_mask = (1 << gpio->ucClkEnShift); -			i2c.en_data_mask = (1 << gpio->ucDataEnShift); -			i2c.y_clk_mask = (1 << gpio->ucClkY_Shift); -			i2c.y_data_mask = (1 << gpio->ucDataY_Shift); -			i2c.a_clk_mask = (1 << gpio->ucClkA_Shift); -			i2c.a_data_mask = (1 << gpio->ucDataA_Shift); - -			if (gpio->sucI2cId.sbfAccess.bfHW_Capable) -				i2c.hw_capable = true; -			else -				i2c.hw_capable = false; +				if (gpio->sucI2cId.sbfAccess.bfHW_Capable) +					i2c.hw_capable = true; +				else +					i2c.hw_capable = false; -			if (gpio->sucI2cId.ucAccess == 0xa0) -				i2c.mm_i2c = true; -			else -				i2c.mm_i2c = false; +				if (gpio->sucI2cId.ucAccess == 0xa0) +					i2c.mm_i2c = true; +				else +					i2c.mm_i2c = false; -			i2c.i2c_id = gpio->sucI2cId.ucAccess; +				i2c.i2c_id = gpio->sucI2cId.ucAccess; -			i2c.valid = true; -			break; +				i2c.valid = true; +				break; +			}  		}  	} @@ -135,20 +137,21 @@ static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rd  	memset(&gpio, 0, sizeof(struct radeon_gpio_rec));  	gpio.valid = false; -	atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset); - -	gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset); +	if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { +		gpio_info = (struct _ATOM_GPIO_PIN_LUT *)(ctx->bios + data_offset); -	num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / sizeof(ATOM_GPIO_PIN_ASSIGNMENT); +		num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) / +			sizeof(ATOM_GPIO_PIN_ASSIGNMENT); -	for (i = 0; i < num_indices; i++) { -		pin = &gpio_info->asGPIO_Pin[i]; -		if (id == pin->ucGPIO_ID) { -			gpio.id = pin->ucGPIO_ID; -			gpio.reg = pin->usGpioPin_AIndex * 4; -			gpio.mask = (1 << pin->ucGpioPinBitShift); -			gpio.valid = true; -			break; +		for (i = 0; i < num_indices; i++) { +			pin = &gpio_info->asGPIO_Pin[i]; +			if (id == pin->ucGPIO_ID) { +				gpio.id = pin->ucGPIO_ID; +				gpio.reg = pin->usGpioPin_AIndex * 4; +				gpio.mask = (1 << pin->ucGpioPinBitShift); +				gpio.valid = true; +				break; +			}  		}  	} @@ -264,6 +267,8 @@ static bool radeon_atom_apply_quirks(struct drm_device *dev,  		if ((supported_device == ATOM_DEVICE_CRT1_SUPPORT) ||  		    (supported_device == ATOM_DEVICE_DFP2_SUPPORT))  			return false; +		if (supported_device == ATOM_DEVICE_CRT2_SUPPORT) +			*line_mux = 0x90;  	}  	/* ASUS HD 3600 XT board lists the DVI port as HDMI */ @@ -395,9 +400,7 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)  	struct radeon_gpio_rec gpio;  	struct radeon_hpd hpd; -	atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); - -	if (data_offset == 0) +	if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset))  		return false;  	if (crev < 2) @@ -449,37 +452,43 @@ bool radeon_get_atom_connector_info_from_object_table(struct drm_device *dev)  				    GetIndexIntoMasterTable(DATA,  							    IntegratedSystemInfo); -				atom_parse_data_header(ctx, index, &size, &frev, -						       &crev, &igp_offset); +				if (atom_parse_data_header(ctx, index, &size, &frev, +							   &crev, &igp_offset)) { -				if (crev >= 2) { -					igp_obj = -					    (ATOM_INTEGRATED_SYSTEM_INFO_V2 -					     *) (ctx->bios + igp_offset); +					if (crev >= 2) { +						igp_obj = +							(ATOM_INTEGRATED_SYSTEM_INFO_V2 +							 *) (ctx->bios + igp_offset); -					if (igp_obj) { -						uint32_t slot_config, ct; +						if (igp_obj) { +							uint32_t slot_config, ct; -						if (con_obj_num == 1) -							slot_config = -							    igp_obj-> -							    ulDDISlot1Config; -						else -							slot_config = -							    igp_obj-> -							    ulDDISlot2Config; +							if (con_obj_num == 1) +								slot_config = +									igp_obj-> +									ulDDISlot1Config; +							else +								slot_config = +									igp_obj-> +									ulDDISlot2Config; -						ct = (slot_config >> 16) & 0xff; -						connector_type = -						    object_connector_convert -						    [ct]; -						connector_object_id = ct; -						igp_lane_info = -						    slot_config & 0xffff; +							ct = (slot_config >> 16) & 0xff; +							connector_type = +								object_connector_convert +								[ct]; +							connector_object_id = ct; +							igp_lane_info = +								slot_config & 0xffff; +						} else +							continue;  					} else  						continue; -				} else -					continue; +				} else { +					igp_lane_info = 0; +					connector_type = +						object_connector_convert[con_obj_id]; +					connector_object_id = con_obj_id; +				}  			} else {  				igp_lane_info = 0;  				connector_type = @@ -627,20 +636,23 @@ static uint16_t atombios_get_connector_object_id(struct drm_device *dev,  		uint8_t frev, crev;  		ATOM_XTMDS_INFO *xtmds; -		atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); -		xtmds = (ATOM_XTMDS_INFO *)(ctx->bios + data_offset); +		if (atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) { +			xtmds = (ATOM_XTMDS_INFO *)(ctx->bios + data_offset); -		if (xtmds->ucSupportedLink & ATOM_XTMDS_SUPPORTED_DUALLINK) { -			if (connector_type == DRM_MODE_CONNECTOR_DVII) -				return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I; -			else -				return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D; -		} else { -			if (connector_type == DRM_MODE_CONNECTOR_DVII) -				return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I; -			else -				return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D; -		} +			if (xtmds->ucSupportedLink & ATOM_XTMDS_SUPPORTED_DUALLINK) { +				if (connector_type == DRM_MODE_CONNECTOR_DVII) +					return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I; +				else +					return CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D; +			} else { +				if (connector_type == DRM_MODE_CONNECTOR_DVII) +					return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I; +				else +					return CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D; +			} +		} else +			return supported_devices_connector_object_id_convert +				[connector_type];  	} else {  		return supported_devices_connector_object_id_convert  			[connector_type]; @@ -672,7 +684,8 @@ bool radeon_get_atom_connector_info_from_supported_devices_table(struct  	int i, j, max_device;  	struct bios_connector bios_connectors[ATOM_MAX_SUPPORTED_DEVICE]; -	atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset); +	if (!atom_parse_data_header(ctx, index, &size, &frev, &crev, &data_offset)) +		return false;  	supported_devices =  	    (union atom_supported_devices *)(ctx->bios + data_offset); @@ -865,14 +878,11 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)  	struct radeon_pll *mpll = &rdev->clock.mpll;  	uint16_t data_offset; -	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, -			       &crev, &data_offset); - -	firmware_info = -	    (union firmware_info *)(mode_info->atom_context->bios + -				    data_offset); - -	if (firmware_info) { +	if (atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) { +		firmware_info = +			(union firmware_info *)(mode_info->atom_context->bios + +						data_offset);  		/* pixel clocks */  		p1pll->reference_freq =  		    le16_to_cpu(firmware_info->info.usReferenceClock); @@ -887,6 +897,20 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)  		p1pll->pll_out_max =  		    le32_to_cpu(firmware_info->info.ulMaxPixelClockPLL_Output); +		if (crev >= 4) { +			p1pll->lcd_pll_out_min = +				le16_to_cpu(firmware_info->info_14.usLcdMinPixelClockPLL_Output) * 100; +			if (p1pll->lcd_pll_out_min == 0) +				p1pll->lcd_pll_out_min = p1pll->pll_out_min; +			p1pll->lcd_pll_out_max = +				le16_to_cpu(firmware_info->info_14.usLcdMaxPixelClockPLL_Output) * 100; +			if (p1pll->lcd_pll_out_max == 0) +				p1pll->lcd_pll_out_max = p1pll->pll_out_max; +		} else { +			p1pll->lcd_pll_out_min = p1pll->pll_out_min; +			p1pll->lcd_pll_out_max = p1pll->pll_out_max; +		} +  		if (p1pll->pll_out_min == 0) {  			if (ASIC_IS_AVIVO(rdev))  				p1pll->pll_out_min = 64800; @@ -992,13 +1016,10 @@ bool radeon_atombios_sideport_present(struct radeon_device *rdev)  	u8 frev, crev;  	u16 data_offset; -	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, -			       &crev, &data_offset); - -	igp_info = (union igp_info *)(mode_info->atom_context->bios + +	if (atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) { +		igp_info = (union igp_info *)(mode_info->atom_context->bios +  				      data_offset); - -	if (igp_info) {  		switch (crev) {  		case 1:  			if (igp_info->info.ucMemoryType & 0xf0) @@ -1029,14 +1050,12 @@ bool radeon_atombios_get_tmds_info(struct radeon_encoder *encoder,  	uint16_t maxfreq;  	int i; -	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, -			       &crev, &data_offset); - -	tmds_info = -	    (struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios + -				       data_offset); +	if (atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) { +		tmds_info = +			(struct _ATOM_TMDS_INFO *)(mode_info->atom_context->bios + +						   data_offset); -	if (tmds_info) {  		maxfreq = le16_to_cpu(tmds_info->usMaxFrequency);  		for (i = 0; i < 4; i++) {  			tmds->tmds_pll[i].freq = @@ -1085,13 +1104,11 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct  	if (id > ATOM_MAX_SS_ENTRY)  		return NULL; -	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, -			       &crev, &data_offset); +	if (atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) { +		ss_info = +			(struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset); -	ss_info = -	    (struct _ATOM_SPREAD_SPECTRUM_INFO *)(mode_info->atom_context->bios + data_offset); - -	if (ss_info) {  		ss =  		    kzalloc(sizeof(struct radeon_atom_ss), GFP_KERNEL); @@ -1114,30 +1131,6 @@ static struct radeon_atom_ss *radeon_atombios_get_ss_info(struct  	return ss;  } -static void radeon_atom_apply_lvds_quirks(struct drm_device *dev, -					  struct radeon_encoder_atom_dig *lvds) -{ - -	/* Toshiba A300-1BU laptop panel doesn't like new pll divider algo */ -	if ((dev->pdev->device == 0x95c4) && -	    (dev->pdev->subsystem_vendor == 0x1179) && -	    (dev->pdev->subsystem_device == 0xff50)) { -		if ((lvds->native_mode.hdisplay == 1280) && -		    (lvds->native_mode.vdisplay == 800)) -			lvds->pll_algo = PLL_ALGO_LEGACY; -	} - -	/* Dell Studio 15 laptop panel doesn't like new pll divider algo */ -	if ((dev->pdev->device == 0x95c4) && -	    (dev->pdev->subsystem_vendor == 0x1028) && -	    (dev->pdev->subsystem_device == 0x029f)) { -		if ((lvds->native_mode.hdisplay == 1280) && -		    (lvds->native_mode.vdisplay == 800)) -			lvds->pll_algo = PLL_ALGO_LEGACY; -	} - -} -  union lvds_info {  	struct _ATOM_LVDS_INFO info;  	struct _ATOM_LVDS_INFO_V12 info_12; @@ -1156,13 +1149,10 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct  	uint8_t frev, crev;  	struct radeon_encoder_atom_dig *lvds = NULL; -	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, -			       &crev, &data_offset); - -	lvds_info = -	    (union lvds_info *)(mode_info->atom_context->bios + data_offset); - -	if (lvds_info) { +	if (atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) { +		lvds_info = +			(union lvds_info *)(mode_info->atom_context->bios + data_offset);  		lvds =  		    kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); @@ -1220,9 +1210,6 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct  				lvds->pll_algo = PLL_ALGO_LEGACY;  		} -		/* LVDS quirks */ -		radeon_atom_apply_lvds_quirks(dev, lvds); -  		encoder->native_mode = lvds->native_mode;  	}  	return lvds; @@ -1241,11 +1228,11 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder)  	uint8_t bg, dac;  	struct radeon_encoder_primary_dac *p_dac = NULL; -	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); +	if (atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) { +		dac_info = (struct _COMPASSIONATE_DATA *) +			(mode_info->atom_context->bios + data_offset); -	dac_info = (struct _COMPASSIONATE_DATA *)(mode_info->atom_context->bios + data_offset); - -	if (dac_info) {  		p_dac = kzalloc(sizeof(struct radeon_encoder_primary_dac), GFP_KERNEL);  		if (!p_dac) @@ -1270,12 +1257,14 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,  	u8 frev, crev;  	u16 data_offset, misc; -	atom_parse_data_header(mode_info->atom_context, data_index, NULL, &frev, &crev, &data_offset); +	if (!atom_parse_data_header(mode_info->atom_context, data_index, NULL, +				    &frev, &crev, &data_offset)) +		return false;  	switch (crev) {  	case 1:  		tv_info = (ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset); -		if (index > MAX_SUPPORTED_TV_TIMING) +		if (index >= MAX_SUPPORTED_TV_TIMING)  			return false;  		mode->crtc_htotal = le16_to_cpu(tv_info->aModeTimings[index].usCRTC_H_Total); @@ -1313,7 +1302,7 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,  		break;  	case 2:  		tv_info_v1_2 = (ATOM_ANALOG_TV_INFO_V1_2 *)(mode_info->atom_context->bios + data_offset); -		if (index > MAX_SUPPORTED_TV_TIMING_V1_2) +		if (index >= MAX_SUPPORTED_TV_TIMING_V1_2)  			return false;  		dtd_timings = &tv_info_v1_2->aModeTimings[index]; @@ -1362,47 +1351,50 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev)  	struct _ATOM_ANALOG_TV_INFO *tv_info;  	enum radeon_tv_std tv_std = TV_STD_NTSC; -	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); +	if (atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) { -	tv_info = (struct _ATOM_ANALOG_TV_INFO *)(mode_info->atom_context->bios + data_offset); +		tv_info = (struct _ATOM_ANALOG_TV_INFO *) +			(mode_info->atom_context->bios + data_offset); -	switch (tv_info->ucTV_BootUpDefaultStandard) { -	case ATOM_TV_NTSC: -		tv_std = TV_STD_NTSC; -		DRM_INFO("Default TV standard: NTSC\n"); -		break; -	case ATOM_TV_NTSCJ: -		tv_std = TV_STD_NTSC_J; -		DRM_INFO("Default TV standard: NTSC-J\n"); -		break; -	case ATOM_TV_PAL: -		tv_std = TV_STD_PAL; -		DRM_INFO("Default TV standard: PAL\n"); -		break; -	case ATOM_TV_PALM: -		tv_std = TV_STD_PAL_M; -		DRM_INFO("Default TV standard: PAL-M\n"); -		break; -	case ATOM_TV_PALN: -		tv_std = TV_STD_PAL_N; -		DRM_INFO("Default TV standard: PAL-N\n"); -		break; -	case ATOM_TV_PALCN: -		tv_std = TV_STD_PAL_CN; -		DRM_INFO("Default TV standard: PAL-CN\n"); -		break; -	case ATOM_TV_PAL60: -		tv_std = TV_STD_PAL_60; -		DRM_INFO("Default TV standard: PAL-60\n"); -		break; -	case ATOM_TV_SECAM: -		tv_std = TV_STD_SECAM; -		DRM_INFO("Default TV standard: SECAM\n"); -		break; -	default: -		tv_std = TV_STD_NTSC; -		DRM_INFO("Unknown TV standard; defaulting to NTSC\n"); -		break; +		switch (tv_info->ucTV_BootUpDefaultStandard) { +		case ATOM_TV_NTSC: +			tv_std = TV_STD_NTSC; +			DRM_INFO("Default TV standard: NTSC\n"); +			break; +		case ATOM_TV_NTSCJ: +			tv_std = TV_STD_NTSC_J; +			DRM_INFO("Default TV standard: NTSC-J\n"); +			break; +		case ATOM_TV_PAL: +			tv_std = TV_STD_PAL; +			DRM_INFO("Default TV standard: PAL\n"); +			break; +		case ATOM_TV_PALM: +			tv_std = TV_STD_PAL_M; +			DRM_INFO("Default TV standard: PAL-M\n"); +			break; +		case ATOM_TV_PALN: +			tv_std = TV_STD_PAL_N; +			DRM_INFO("Default TV standard: PAL-N\n"); +			break; +		case ATOM_TV_PALCN: +			tv_std = TV_STD_PAL_CN; +			DRM_INFO("Default TV standard: PAL-CN\n"); +			break; +		case ATOM_TV_PAL60: +			tv_std = TV_STD_PAL_60; +			DRM_INFO("Default TV standard: PAL-60\n"); +			break; +		case ATOM_TV_SECAM: +			tv_std = TV_STD_SECAM; +			DRM_INFO("Default TV standard: SECAM\n"); +			break; +		default: +			tv_std = TV_STD_NTSC; +			DRM_INFO("Unknown TV standard; defaulting to NTSC\n"); +			break; +		}  	}  	return tv_std;  } @@ -1420,11 +1412,12 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)  	uint8_t bg, dac;  	struct radeon_encoder_tv_dac *tv_dac = NULL; -	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); +	if (atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) { -	dac_info = (struct _COMPASSIONATE_DATA *)(mode_info->atom_context->bios + data_offset); +		dac_info = (struct _COMPASSIONATE_DATA *) +			(mode_info->atom_context->bios + data_offset); -	if (dac_info) {  		tv_dac = kzalloc(sizeof(struct radeon_encoder_tv_dac), GFP_KERNEL);  		if (!tv_dac) @@ -1447,6 +1440,30 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder)  	return tv_dac;  } +static const char *thermal_controller_names[] = { +	"NONE", +	"LM63", +	"ADM1032", +	"ADM1030", +	"MUA6649", +	"LM64", +	"F75375", +	"ASC7512", +}; + +static const char *pp_lib_thermal_controller_names[] = { +	"NONE", +	"LM63", +	"ADM1032", +	"ADM1030", +	"MUA6649", +	"LM64", +	"F75375", +	"RV6xx", +	"RV770", +	"ADT7473", +}; +  union power_info {  	struct _ATOM_POWERPLAY_INFO info;  	struct _ATOM_POWERPLAY_INFO_V2 info_2; @@ -1466,15 +1483,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)  	struct _ATOM_PPLIB_STATE *power_state;  	int num_modes = 0, i, j;  	int state_index = 0, mode_index = 0; - -	atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); - -	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); +	struct radeon_i2c_bus_rec i2c_bus;  	rdev->pm.default_power_state = NULL; -	if (power_info) { +	if (atom_parse_data_header(mode_info->atom_context, index, NULL, +				   &frev, &crev, &data_offset)) { +		power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);  		if (frev < 4) { +			/* add the i2c bus for thermal/fan chip */ +			if (power_info->info.ucOverdriveThermalController > 0) { +				DRM_INFO("Possible %s thermal controller at 0x%02x\n", +					 thermal_controller_names[power_info->info.ucOverdriveThermalController], +					 power_info->info.ucOverdriveControllerAddress >> 1); +				i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); +				rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal"); +			}  			num_modes = power_info->info.ucNumOfPowerModeEntries;  			if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK)  				num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; @@ -1684,6 +1708,24 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)  				}  			}  		} else if (frev == 4) { +			/* add the i2c bus for thermal/fan chip */ +			/* no support for internal controller yet */ +			if (power_info->info_4.sThermalController.ucType > 0) { +				if ((power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) || +				    (power_info->info_4.sThermalController.ucType == ATOM_PP_THERMALCONTROLLER_RV770)) { +					DRM_INFO("Internal thermal controller %s fan control\n", +						 (power_info->info_4.sThermalController.ucFanParameters & +						  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); +				} else { +					DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", +						 pp_lib_thermal_controller_names[power_info->info_4.sThermalController.ucType], +						 power_info->info_4.sThermalController.ucI2cAddress >> 1, +						 (power_info->info_4.sThermalController.ucFanParameters & +						  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); +					i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info_4.sThermalController.ucI2cLine); +					rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal"); +				} +			}  			for (i = 0; i < power_info->info_4.ucNumStates; i++) {  				mode_index = 0;  				power_state = (struct _ATOM_PPLIB_STATE *)  |